Skip to content

Commit 6c489aa

Browse files
authored
Merge pull request #8953 from dotty-staging/fix-#8931
Fix #8931: Refinement of markFree in lambda lift
2 parents d1354f7 + ef9d827 commit 6c489aa

File tree

2 files changed

+69
-3
lines changed

2 files changed

+69
-3
lines changed

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,16 +151,21 @@ object LambdaLift {
151151
if (!enclosure.exists) throw new NoPath
152152
if (enclosure == sym.enclosure) NoSymbol
153153
else {
154+
def nestedInConstructor(sym: Symbol): Boolean =
155+
sym.isConstructor ||
156+
sym.isTerm && nestedInConstructor(sym.enclosure)
154157
ctx.debuglog(i"mark free: ${sym.showLocated} with owner ${sym.maybeOwner} marked free in $enclosure")
155158
val intermediate =
156159
if (enclosure.is(PackageClass)) enclosure
157160
else if (enclosure.isConstructor) markFree(sym, enclosure.owner.enclosure)
158161
else markFree(sym, enclosure.enclosure)
159162
if (intermediate.exists) narrowLiftedOwner(enclosure, intermediate)
160-
if (!intermediate.isRealClass || enclosure.isConstructor)
163+
if !intermediate.isRealClass || nestedInConstructor(enclosure) then
161164
// Constructors and methods nested inside traits get the free variables
162-
// of the enclosing trait or class.
165+
// of the enclosing trait or class.
163166
// Conversely, local traits do not get free variables.
167+
// Methods inside constructors also don't have intermediates,
168+
// need to get all their free variables passed directly.
164169
if (!enclosure.is(Trait))
165170
if (symSet(free, enclosure).add(sym)) {
166171
changedFreeVars = true
@@ -301,7 +306,7 @@ object LambdaLift {
301306
private def generateProxies()(implicit ctx: Context): Unit =
302307
for ((owner, freeValues) <- free.iterator) {
303308
val newFlags = Synthetic | (if (owner.isClass) ParamAccessor | Private else Param)
304-
ctx.debuglog(i"free var proxy: ${owner.showLocated}, ${freeValues.toList}%, %")
309+
ctx.debuglog(i"free var proxy of ${owner.showLocated}: ${freeValues.toList}%, %")
305310
proxyMap(owner) = {
306311
for (fv <- freeValues.toList) yield {
307312
val proxyName = newName(fv)

tests/run/i8931.scala

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
object test1:
2+
3+
trait Trait
4+
5+
trait Managed[T](x: T) {
6+
7+
def flatMap(f: T => Managed[T]): Managed[T] = new Managed[T](x) {
8+
9+
def make() = new Trait {
10+
val t: T = x
11+
val u =
12+
try {
13+
f(t)
14+
} catch {
15+
case e: Exception => ()
16+
}
17+
}
18+
}
19+
}
20+
21+
object test2:
22+
23+
trait Trait
24+
25+
trait Managed[T](x: T) {
26+
def xx = x
27+
28+
def flatMap(f: T => Managed[T]): Managed[T] = new Managed[T](x) {
29+
def make() = new Trait {
30+
val t: T = x
31+
val u = {
32+
def foo = f(t)
33+
assert(foo.xx == 22)
34+
foo
35+
}
36+
}
37+
make()
38+
}
39+
}
40+
41+
object test3:
42+
43+
trait Trait
44+
45+
trait Managed[T]:
46+
47+
def flatMap[U](f: T => Managed[U]) =
48+
class C:
49+
def make() =
50+
class D:
51+
def bar(): T = ???
52+
val t: T = ???
53+
val u =
54+
def foo = (f(t), f(bar()))
55+
foo
56+
new D().u
57+
()
58+
59+
@main def Test() =
60+
val m = new test2.Managed[Int](22) {}
61+
m.flatMap(x => new test2.Managed(x) {})

0 commit comments

Comments
 (0)