Skip to content

Commit e0a0c39

Browse files
committed
Fix #480 in LambdaLift
Fix two errors, where the first masked the second: 1) Variables defined in a method are not free variables of that method. This was mispredicated before and caused liftedOwner to be updated to the class enclosing the method, thereby preventing any method that refers to a local parameter or symbol to be hoisted. Once this was fixed, methods were hoisted too far out. Test case in #480a, which takes code from Definitions. This was fixed by 2) markFree is updated to do an additional narrowLiftedOwner so that, if a free variable gets a proxy in an enclosing class, any inner classes and methods are kept within that class.
1 parent 85b48de commit e0a0c39

File tree

1 file changed

+17
-10
lines changed

1 file changed

+17
-10
lines changed

src/dotty/tools/dotc/transform/LambdaLift.scala

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,10 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
102102

103103
/** Mark symbol `sym` as being free in `enclosure`, unless `sym`
104104
* is defined in `enclosure` or there is a class between `enclosure`s owner
105-
* and the owner of `sym`.
106-
* Return `true` if there is no class between `enclosure` and
107-
* the owner of sym.
105+
* and the owner of `sym`. Also, update lifted owner of `enclosure` so
106+
* that `enclosure` can access `sym`, or its proxy in an intermediate class.
107+
* Return the closest enclosing intermediate class between `enclosure` and
108+
* the owner of sym, or NoSymbol is none exists.
108109
* pre: sym.owner.isTerm, (enclosure.isMethod || enclosure.isClass)
109110
*
110111
* The idea of `markFree` is illustrated with an example:
@@ -130,22 +131,28 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform
130131
* }
131132
* }
132133
*/
133-
private def markFree(sym: Symbol, enclosure: Symbol)(implicit ctx: Context): Boolean = try {
134+
private def markFree(sym: Symbol, enclosure: Symbol)(implicit ctx: Context): Symbol = try {
134135
if (!enclosure.exists) throw new NoPath
135-
ctx.log(i"mark free: ${sym.showLocated} with owner ${sym.maybeOwner} marked free in $enclosure")
136-
narrowLiftedOwner(enclosure, sym.enclosingClass)
137-
(enclosure == sym.enclosure) || {
136+
if (enclosure == sym.enclosure) NoSymbol
137+
else {
138+
ctx.log(i"mark free: ${sym.showLocated} with owner ${sym.maybeOwner} marked free in $enclosure")
138139
ctx.debuglog(i"$enclosure != ${sym.enclosure}")
139-
if (enclosure.is(PackageClass) ||
140-
!markFree(sym, enclosure.skipConstructor.enclosure)) false
140+
val intermediate =
141+
if (enclosure.is(PackageClass)) enclosure
142+
else markFree(sym, enclosure.skipConstructor.enclosure)
143+
if (intermediate.exists) {
144+
narrowLiftedOwner(enclosure, intermediate)
145+
intermediate
146+
}
141147
else {
148+
narrowLiftedOwner(enclosure, sym.enclosingClass)
142149
val ss = symSet(free, enclosure)
143150
if (!ss(sym)) {
144151
ss += sym
145152
changedFreeVars = true
146153
ctx.debuglog(i"$sym is free in $enclosure")
147154
}
148-
!enclosure.isClass
155+
if (enclosure.isClass) enclosure else NoSymbol
149156
}
150157
}
151158
} catch {

0 commit comments

Comments
 (0)