Skip to content

Commit

Permalink
A first attempt at level checking for classes
Browse files Browse the repository at this point in the history
Check that instantiated root variable of a method inside a class
is nested in the instance variable of the class.

For the moment I was not able to construct a counter example where this
makes a difference.
  • Loading branch information
odersky committed Oct 7, 2023
1 parent 7c34545 commit 2e1ed26
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 4 deletions.
16 changes: 13 additions & 3 deletions compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ class CheckCaptures extends Recheck, SymTransformer:
includeCallCaptures(tree.symbol, tree.srcPos)
else
markFree(tree.symbol, tree.srcPos)
instantiateLocalRoots(tree.symbol, NoPrefix, pt):
instantiateLocalRoots(tree.symbol, NoPrefix, pt, tree.srcPos):
super.recheckIdent(tree, pt)

/** A specialized implementation of the selection rule.
Expand Down Expand Up @@ -349,7 +349,7 @@ class CheckCaptures extends Recheck, SymTransformer:

val selType = recheckSelection(tree, qualType, name, disambiguate)
val selCs = selType.widen.captureSet
instantiateLocalRoots(tree.symbol, qualType, pt):
instantiateLocalRoots(tree.symbol, qualType, pt, tree.srcPos):
if selCs.isAlwaysEmpty || selType.widen.isBoxedCapturing || qualType.isBoxedCapturing then
selType
else
Expand All @@ -370,7 +370,7 @@ class CheckCaptures extends Recheck, SymTransformer:
* - `tp` is the type of a function that gets applied, either as a method
* or as a function value that gets applied.
*/
def instantiateLocalRoots(sym: Symbol, pre: Type, pt: Type)(tp: Type)(using Context): Type =
def instantiateLocalRoots(sym: Symbol, pre: Type, pt: Type, pos: SrcPos)(tp: Type)(using Context): Type =
def canInstantiate =
sym.is(Method, butNot = Accessor)
|| sym.isTerm && defn.isFunctionType(sym.info) && pt == AnySelectionProto
Expand All @@ -379,6 +379,16 @@ class CheckCaptures extends Recheck, SymTransformer:
var tp1 = tpw
val rootVar = CaptureRoot.Var(ctx.owner, sym)
if sym.isLevelOwner then
val outerOwner = sym.skipConstructor.owner.levelOwner
if outerOwner.isClass then
val outerRoot = outerOwner.localRoot.termRef
outerRoot.asSeenFrom(pre, sym.owner) match
case outerLimit: CaptureRoot if outerLimit ne outerRoot =>
capt.println(i"constraining $rootVar of $sym by $outerLimit")
if !outerLimit.encloses(rootVar) then
// Should this be an assertion failure instead?
report.error(em"outer instance $outerLimit does not enclose local root $rootVar", pos)
case _ =>
tp1 = mapRoots(sym.localRoot.termRef, rootVar)(tp1)
if tp1 ne tpw then
ccSetup.println(i"INST local $sym: $tp, ${sym.localRoot} = $tp1")
Expand Down
1 change: 0 additions & 1 deletion tests/pos-custom-args/captures/nested-classes-2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,5 @@ def test2(x1: (() => Unit), x2: (() => Unit) => Unit) =
def test3(y1: (() => Unit), y2: (() => Unit) => Unit) =
val cc1/*: C1^{cap[test3]}*/ = C1(y1, y2) // error (but should be OK)
val cc2 = cc1.c2(x1, x2) // error (but should be OK)
()
//val cc3: cc1.C2^{cap[test2]} = cc2

0 comments on commit 2e1ed26

Please sign in to comment.