From 4df4e531760c8f8124491ba956a10062471be564 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 11 May 2020 19:52:19 +0200 Subject: [PATCH 1/2] Fix #8931: Refinement of markFree in lambda lift --- .../dotty/tools/dotc/transform/LambdaLift.scala | 11 ++++++++--- tests/pos/i8931.scala | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 tests/pos/i8931.scala diff --git a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala index 46ffb195faa5..b0e236db6d1a 100644 --- a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -151,16 +151,21 @@ object LambdaLift { if (!enclosure.exists) throw new NoPath if (enclosure == sym.enclosure) NoSymbol else { + def nestedInConstructor(sym: Symbol): Boolean = + sym.isConstructor || + sym.isTerm && nestedInConstructor(sym.enclosure) ctx.debuglog(i"mark free: ${sym.showLocated} with owner ${sym.maybeOwner} marked free in $enclosure") val intermediate = if (enclosure.is(PackageClass)) enclosure else if (enclosure.isConstructor) markFree(sym, enclosure.owner.enclosure) else markFree(sym, enclosure.enclosure) if (intermediate.exists) narrowLiftedOwner(enclosure, intermediate) - if (!intermediate.isRealClass || enclosure.isConstructor) + if !intermediate.isRealClass || nestedInConstructor(enclosure) then // Constructors and methods nested inside traits get the free variables - // of the enclosing trait or class. + // of the enclosing trait or class. // Conversely, local traits do not get free variables. + // Methods inside constructors also don't have intermediates, + // need to get all their free variables passed directly. if (!enclosure.is(Trait)) if (symSet(free, enclosure).add(sym)) { changedFreeVars = true @@ -301,7 +306,7 @@ object LambdaLift { private def generateProxies()(implicit ctx: Context): Unit = for ((owner, freeValues) <- free.iterator) { val newFlags = Synthetic | (if (owner.isClass) ParamAccessor | Private else Param) - ctx.debuglog(i"free var proxy: ${owner.showLocated}, ${freeValues.toList}%, %") + ctx.debuglog(i"free var proxy of ${owner.showLocated}: ${freeValues.toList}%, %") proxyMap(owner) = { for (fv <- freeValues.toList) yield { val proxyName = newName(fv) diff --git a/tests/pos/i8931.scala b/tests/pos/i8931.scala new file mode 100644 index 000000000000..2f0d4affa376 --- /dev/null +++ b/tests/pos/i8931.scala @@ -0,0 +1,15 @@ +trait Trait + +trait Managed[T]: + + def flatMap[U](f: T => Managed[U]) = + class C: + def make() = + class D: + def bar(): T = ??? + val t: T = ??? + val u = + def foo = (f(t), f(bar())) + foo + new D().u + () From ef9d827eca5c34af7e69ad8b497bf86faae6b5c8 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 11 May 2020 20:46:19 +0200 Subject: [PATCH 2/2] Turn test into a run test --- tests/pos/i8931.scala | 15 ----------- tests/run/i8931.scala | 61 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 15 deletions(-) delete mode 100644 tests/pos/i8931.scala create mode 100644 tests/run/i8931.scala diff --git a/tests/pos/i8931.scala b/tests/pos/i8931.scala deleted file mode 100644 index 2f0d4affa376..000000000000 --- a/tests/pos/i8931.scala +++ /dev/null @@ -1,15 +0,0 @@ -trait Trait - -trait Managed[T]: - - def flatMap[U](f: T => Managed[U]) = - class C: - def make() = - class D: - def bar(): T = ??? - val t: T = ??? - val u = - def foo = (f(t), f(bar())) - foo - new D().u - () diff --git a/tests/run/i8931.scala b/tests/run/i8931.scala new file mode 100644 index 000000000000..555d15d0121d --- /dev/null +++ b/tests/run/i8931.scala @@ -0,0 +1,61 @@ +object test1: + + trait Trait + + trait Managed[T](x: T) { + + def flatMap(f: T => Managed[T]): Managed[T] = new Managed[T](x) { + + def make() = new Trait { + val t: T = x + val u = + try { + f(t) + } catch { + case e: Exception => () + } + } + } + } + +object test2: + + trait Trait + + trait Managed[T](x: T) { + def xx = x + + def flatMap(f: T => Managed[T]): Managed[T] = new Managed[T](x) { + def make() = new Trait { + val t: T = x + val u = { + def foo = f(t) + assert(foo.xx == 22) + foo + } + } + make() + } + } + +object test3: + + trait Trait + + trait Managed[T]: + + def flatMap[U](f: T => Managed[U]) = + class C: + def make() = + class D: + def bar(): T = ??? + val t: T = ??? + val u = + def foo = (f(t), f(bar())) + foo + new D().u + () + +@main def Test() = + val m = new test2.Managed[Int](22) {} + m.flatMap(x => new test2.Managed(x) {})