@@ -1089,7 +1089,7 @@ class CheckCaptures extends Recheck, SymTransformer:
10891089
10901090 if actualBoxed eq actual then
10911091 // Only `addOuterRefs` when there is no box adaptation
1092- expected1 = addOuterRefs(expected1, actual)
1092+ expected1 = addOuterRefs(expected1, actual, tree.srcPos )
10931093 if isCompatible(actualBoxed, expected1) then
10941094 if debugSuccesses then tree match
10951095 case Ident (_) =>
@@ -1130,8 +1130,12 @@ class CheckCaptures extends Recheck, SymTransformer:
11301130 * that are outside `Cls`. These are all accessed through `Cls.this`,
11311131 * so we can assume they are already accounted for by `Ce` and adding
11321132 * them explicitly to `Ce` changes nothing.
1133+ * - To make up for this, we also add these variables to the capture set of `Cls`,
1134+ * so that all instances of `Cls` will capture these outer references.
1135+ * So in a sense we use `{Cls.this}` as a placeholder for certain outer captures.
1136+ * that we needed to be subsumed by `Cls.this`.
11331137 */
1134- private def addOuterRefs (expected : Type , actual : Type )(using Context ): Type =
1138+ private def addOuterRefs (expected : Type , actual : Type , pos : SrcPos )(using Context ): Type =
11351139
11361140 def isPure (info : Type ): Boolean = info match
11371141 case info : PolyType => isPure(info.resType)
@@ -1144,19 +1148,40 @@ class CheckCaptures extends Recheck, SymTransformer:
11441148 else isPure(owner.info) && isPureContext(owner.owner, limit)
11451149
11461150 // Augment expeced capture set `erefs` by all references in actual capture
1147- // set `arefs` that are outside some `this.type` reference in `erefs`
1151+ // set `arefs` that are outside some `C.this.type` reference in `erefs` for an enclosing
1152+ // class `C`. If an added reference is not a ThisType itself, add it to the capture set
1153+ // (i.e. use set) of the `C`. This makes sure that any outer reference implicitly subsumed
1154+ // by `C.this` becomes a capture reference of every instance of `C`.
11481155 def augment (erefs : CaptureSet , arefs : CaptureSet ): CaptureSet =
11491156 (erefs /: erefs.elems): (erefs, eref) =>
11501157 eref match
11511158 case eref : ThisType if isPureContext(ctx.owner, eref.cls) =>
1152- def isOuterRef (aref : Type ): Boolean = aref match
1153- case aref : TermRef =>
1154- val owner = aref.symbol.owner
1155- if owner.isClass then isOuterRef(aref.prefix)
1156- else eref.cls.isProperlyContainedIn(owner)
1159+
1160+ def pathRoot (aref : Type ): Type = aref match
1161+ case aref : NamedType if aref.symbol.owner.isClass => pathRoot(aref.prefix)
1162+ case _ => aref
1163+
1164+ def isOuterRef (aref : Type ): Boolean = pathRoot(aref) match
1165+ case aref : NamedType => eref.cls.isProperlyContainedIn(aref.symbol.owner)
11571166 case aref : ThisType => eref.cls.isProperlyContainedIn(aref.cls)
11581167 case _ => false
1159- erefs ++ arefs.filter(isOuterRef)
1168+
1169+ val outerRefs = arefs.filter(isOuterRef)
1170+
1171+ // Include implicitly added outer references in the capture set of the class of `eref`.
1172+ for outerRef <- outerRefs.elems do
1173+ if ! erefs.elems.contains(outerRef)
1174+ && ! pathRoot(outerRef).isInstanceOf [ThisType ]
1175+ // we don't need to add outer ThisTypes as these are anyway added as path
1176+ // prefixes at the use site. And this exemption is required since capture sets
1177+ // of non-local classes are always empty, so we can't add an outer this to them.
1178+ then
1179+ def provenance =
1180+ i """ of the enclosing class ${eref.cls}.
1181+ |The reference was included since we tried to establish that $arefs <: $erefs"""
1182+ checkElem(outerRef, capturedVars(eref.cls), pos, provenance)
1183+
1184+ erefs ++ outerRefs
11601185 case _ =>
11611186 erefs
11621187
@@ -1341,7 +1366,7 @@ class CheckCaptures extends Recheck, SymTransformer:
13411366 * @param sym symbol of the field definition that is being checked
13421367 */
13431368 override def checkSubType (actual : Type , expected : Type )(using Context ): Boolean =
1344- val expected1 = alignDependentFunction(addOuterRefs(expected, actual), actual.stripCapturing)
1369+ val expected1 = alignDependentFunction(addOuterRefs(expected, actual, srcPos ), actual.stripCapturing)
13451370 val actual1 =
13461371 val saved = curEnv
13471372 try
0 commit comments