@@ -28,6 +28,7 @@ import NameKinds.{DefaultGetterName, WildcardParamName, UniqueNameKind}
2828import reporting .{trace , Message , OverrideError }
2929import Annotations .Annotation
3030import Capabilities .*
31+ import Mutability .*
3132import util .common .alwaysTrue
3233import scala .annotation .constructorOnly
3334
@@ -689,11 +690,7 @@ class CheckCaptures extends Recheck, SymTransformer:
689690 // read-only-use.scala, where the error on r3 goes unreported.
690691 markPathFree(sel, pt.pt, pt.select)
691692 case _ =>
692- if ref.derivesFromMutable then
693- if pt.isValueType && ! pt.isMutableType || ref.exclusivityInContext != Exclusivity .OK
694- then markFree(ref.readOnly, tree)
695- else markFree(ref, tree)
696- else markFree(ref, tree)
693+ markFree(ref.adjustReadOnly(pt), tree)
697694
698695 /** The expected type for the qualifier of a selection. If the selection
699696 * could be part of a capability path or is a a read-only method, we return
@@ -773,12 +770,6 @@ class CheckCaptures extends Recheck, SymTransformer:
773770 selType
774771 }// .showing(i"recheck sel $tree, $qualType = $result")
775772
776- def checkUpdate (qualType : Type , pos : SrcPos )(msg : => String )(using Context ): Unit =
777- qualType.exclusivityInContext match
778- case Exclusivity .OK =>
779- case err =>
780- report.error(em " $msg\n since ${err.description(qualType)}. " , pos)
781-
782773 /** Recheck applications, with special handling of unsafeAssumePure.
783774 * More work is done in `recheckApplication`, `recheckArg` and `instantiate` below.
784775 */
@@ -1773,101 +1764,6 @@ class CheckCaptures extends Recheck, SymTransformer:
17731764 case _ => widened
17741765 case _ => widened
17751766
1776- /** If actual is a capturing type T^C extending Mutable, and expected is an
1777- * unboxed non-singleton value type not extending mutable, narrow the capture
1778- * set `C` to `ro(C)`.
1779- * The unboxed condition ensures that the expected type is not a type variable
1780- * that's upper bounded by a read-only type. In this case it would not be sound
1781- * to narrow to the read-only set, since that set can be propagated
1782- * by the type variable instantiation.
1783- */
1784- private def improveReadOnly (actual : Type , expected : Type )(using Context ): Type = reporting.trace(i " improv ro $actual vs $expected" ):
1785- actual.dealiasKeepAnnots match
1786- case actual @ CapturingType (parent, refs) =>
1787- val parent1 = improveReadOnly(parent, expected)
1788- val refs1 =
1789- if parent1.derivesFrom(defn.Caps_Mutable )
1790- && expected.isValueType
1791- && (! expected.derivesFromMutable || expected.captureSet.isAlwaysReadOnly)
1792- && ! expected.isSingleton
1793- && actual.isBoxedCapturing == expected.isBoxedCapturing
1794- then refs.readOnly
1795- else refs
1796- actual.derivedCapturingType(parent1, refs1)
1797- case actual @ FunctionOrMethod (aargs, ares) =>
1798- expected.dealias.stripCapturing match
1799- case FunctionOrMethod (eargs, eres) =>
1800- actual.derivedFunctionOrMethod(aargs, improveReadOnly(ares, eres))
1801- case _ =>
1802- actual
1803- case actual @ AppliedType (atycon, aargs) =>
1804- def improveArgs (aargs : List [Type ], eargs : List [Type ], formals : List [ParamInfo ]): List [Type ] =
1805- aargs match
1806- case aargs @ (aarg :: aargs1) =>
1807- val aarg1 =
1808- if formals.head.paramVariance.is(Covariant )
1809- then improveReadOnly(aarg, eargs.head)
1810- else aarg
1811- aargs.derivedCons(aarg1, improveArgs(aargs1, eargs.tail, formals.tail))
1812- case Nil =>
1813- aargs
1814- val expected1 = expected.dealias.stripCapturing
1815- val esym = expected1.typeSymbol
1816- expected1 match
1817- case AppliedType (etycon, eargs) =>
1818- if atycon.typeSymbol == esym then
1819- actual.derivedAppliedType(atycon,
1820- improveArgs(aargs, eargs, etycon.typeParams))
1821- else if esym.isClass then
1822- // This case is tricky: Try to lift actual to the base type with class `esym`,
1823- // improve the resulting arguments, and figure out if anything can be
1824- // deduced from that for the original arguments.
1825- actual.baseType(esym) match
1826- case base @ AppliedType (_, bargs) =>
1827- // If any of the base type arguments can be improved, check
1828- // whether they are the same as an original argument, and in this
1829- // case improve the original argument.
1830- val iargs = improveArgs(bargs, eargs, etycon.typeParams)
1831- if iargs ne bargs then
1832- val updates =
1833- for
1834- (barg, iarg) <- bargs.lazyZip(iargs)
1835- if barg ne iarg
1836- aarg <- aargs.find(_ eq barg)
1837- yield (aarg, iarg)
1838- if updates.nonEmpty then AppliedType (atycon, aargs.map(updates.toMap))
1839- else actual
1840- else actual
1841- case _ => actual
1842- else actual
1843- case _ =>
1844- actual
1845- case actual @ RefinedType (aparent, aname, ainfo) =>
1846- expected.dealias.stripCapturing match
1847- case RefinedType (eparent, ename, einfo) if aname == ename =>
1848- actual.derivedRefinedType(
1849- improveReadOnly(aparent, eparent),
1850- aname,
1851- improveReadOnly(ainfo, einfo))
1852- case _ =>
1853- actual
1854- case actual @ AnnotatedType (parent, ann) =>
1855- actual.derivedAnnotatedType(improveReadOnly(parent, expected), ann)
1856- case _ =>
1857- actual
1858- end improveReadOnly
1859-
1860- def adaptReadOnly (improved : Type , original : Type , expected : Type , tree : Tree )(using Context ): Type = improved match
1861- case improved @ CapturingType (parent, refs)
1862- if parent.derivesFrom(defn.Caps_Mutable )
1863- && expected.isValueType
1864- && refs.isExclusive
1865- && ! original.exclusivityInContext.isOK =>
1866- improved.derivedCapturingType(parent, refs.readOnly)
1867- .showing(i " Adapted readonly $improved for $tree with original = $original in ${ctx.owner} --> $result" , capt)
1868- case _ =>
1869- improved
1870-
18711767 /* Currently not needed since it forms part of `adapt`
18721768 private def improve(actual: Type, prefix: Type)(using Context): Type =
18731769 val widened = actual.widen.dealiasKeepAnnots
@@ -1904,12 +1800,11 @@ class CheckCaptures extends Recheck, SymTransformer:
19041800 // since they obscures the capturing type.
19051801 val widened = actual.widen.dealiasKeepAnnots.dropUseAndConsumeAnnots
19061802 val improvedVAR = improveCaptures(widened, actual)
1907- val improved = improveReadOnly(improvedVAR, expected)
1908- val adaptedReadOnly = adaptReadOnly(improved, actual, expected, tree)
1803+ val adaptedReadOnly = adaptReadOnly(improvedVAR, actual, expected, tree)
19091804 val adapted = adaptBoxed(
19101805 adaptedReadOnly.withReachCaptures(actual), expected, tree,
19111806 covariant = true , alwaysConst = false )
1912- if adapted eq improvedVAR // no .rd improvement or adaptation , no box-adaptation
1807+ if adapted eq improvedVAR // no read-only-adaptation, no reaches added , no box-adaptation
19131808 then actual // might as well use actual instead of improved widened
19141809 else adapted.showing(i " adapt $actual vs $expected = $adapted" , capt)
19151810 end adapt
0 commit comments