diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 4cee0d0de721..7d418091f0d4 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -95,8 +95,9 @@ class Erasure extends Phase with DenotTransformer { thisTransformer => assertErased(tree) tree match { case res: tpd.This => - assert(!ExplicitOuter.referencesOuter(ctx.owner.lexicallyEnclosingClass, res), - i"Reference to $res from ${ctx.owner.showLocated}") + assert( + !ExplicitOuter.referencesOuter(ctx.owner.lexicallyEnclosingClass, res), + i"Reference to $res from ${ctx.owner} in ${ctx.owner.ownersIterator.toList}%, %") case ret: tpd.Return => // checked only after erasure, as checking before erasure is complicated // due presence of type params in returned types diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 7ad7fb348447..cd175e300ebe 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -257,7 +257,9 @@ object ExplicitOuter { case _ => false } tree match { - case _: This | _: Ident => isOuterRef(tree.tpe) + case _: This | _: Ident => + tree.symbol.is(InSuperCall) || // symbol in supercalls are lifted to the next outer class + isOuterRef(tree.tpe) case nw: New => val newCls = nw.tpe.classSymbol isOuterSym(newCls.owner.enclosingClass) || diff --git a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala index a729368d4978..8c0f3dba0050 100644 --- a/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala +++ b/compiler/src/dotty/tools/dotc/transform/LambdaLift.scala @@ -11,18 +11,17 @@ import core.Decorators._ import core.StdNames.nme import core.Names._ import core.NameOps._ +import core.NameKinds.ExpandPrefixName import core.Phases._ import ast.Trees._ import SymUtils._ import ExplicitOuter.outer import util.Attachment -import util.NameTransformer import util.Positions._ import collection.{ mutable, immutable } import collection.mutable.{ HashMap, HashSet, LinkedHashMap, LinkedHashSet, TreeSet } object LambdaLift { - private val NJ = NameTransformer.NAME_JOIN_STRING private class NoPath extends Exception } @@ -200,35 +199,44 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform * } * } */ - private def markFree(sym: Symbol, enclosure: Symbol)(implicit ctx: Context): Symbol = try { - if (!enclosure.exists) throw new NoPath - if (enclosure == sym.enclosure) NoSymbol - else { - ctx.debuglog(i"mark free: ${sym.showLocated} with owner ${sym.maybeOwner} marked free in $enclosure") - val intermediate = - if (enclosure.is(PackageClass)) enclosure - else markFree(sym, enclosure.enclosure) - narrowLiftedOwner(enclosure, intermediate orElse sym.enclosingClass) - if (!intermediate.isRealClass || enclosure.isConstructor) { - // Constructors and methods nested inside traits get the free variables - // of the enclosing trait or class. - // Conversely, local traits do not get free variables. - if (!enclosure.is(Trait)) - if (symSet(free, enclosure).add(sym)) { - changedFreeVars = true - ctx.log(i"$sym is free in $enclosure") + private def markFree(sym: Symbol, enclosure: Symbol)(implicit ctx: Context): Symbol = { + def recur(enclosure: Symbol, inSuper: Boolean): Symbol = try + if (!enclosure.exists) throw new NoPath + else if (enclosure == sym.enclosure) NoSymbol + else { + val intermediate = + if (enclosure.is(PackageClass)) enclosure + else { + val next = enclosure.enclosure + // Skip enclosing class if original enclosure appeared in a super call. + // The original enclosure will be moved out of the class, so cannot see + // any proxies in the class. + if (next.isClass && inSuper) recur(next.enclosure, false) + else recur(next, inSuper) } + narrowLiftedOwner(enclosure, intermediate orElse sym.enclosingClass) + if (!intermediate.isRealClass || enclosure.isConstructor) { + // Constructors and methods nested inside traits get the free variables + // of the enclosing trait or class. + // Conversely, local traits do not get free variables. + if (!enclosure.is(Trait)) + if (symSet(free, enclosure).add(sym)) { + changedFreeVars = true + ctx.log(i"$sym is free in $enclosure") + } + } + if (intermediate.isRealClass) intermediate + else if (enclosure.isRealClass) enclosure + else if (intermediate.isClass) intermediate + else if (enclosure.isClass) enclosure + else NoSymbol } - if (intermediate.isRealClass) intermediate - else if (enclosure.isRealClass) enclosure - else if (intermediate.isClass) intermediate - else if (enclosure.isClass) enclosure - else NoSymbol + catch { + case ex: NoPath => + println(i"error lambda lifting ${ctx.compilationUnit}: $sym is not visible from $enclosure") + throw ex } - } catch { - case ex: NoPath => - println(i"error lambda lifting ${ctx.compilationUnit}: $sym is not visible from $enclosure") - throw ex + recur(enclosure, enclosure.is(InSuperCall)) } private def markCalled(callee: Symbol, caller: Symbol)(implicit ctx: Context): Unit = { @@ -338,7 +346,9 @@ class LambdaLift extends MiniPhase with IdentityDenotTransformer { thisTransform private def newName(sym: Symbol)(implicit ctx: Context): Name = if (sym.isAnonymousFunction && sym.owner.is(Method, butNot = Label)) - (sym.name ++ NJ ++ sym.owner.name).freshened + sym.name.rewrite { + case name: SimpleTermName => ExpandPrefixName(sym.owner.name.asTermName, name) + }.freshened else sym.name.freshened private def generateProxies()(implicit ctx: Context): Unit = diff --git a/tests/pos/t0055.scala b/tests/pending/pos/t0055.scala similarity index 62% rename from tests/pos/t0055.scala rename to tests/pending/pos/t0055.scala index 0796294403a3..adab88a2c492 100644 --- a/tests/pos/t0055.scala +++ b/tests/pending/pos/t0055.scala @@ -4,3 +4,10 @@ class W { trait Y { def y = () } } class Z(r : Any) { def this() = this(null) } + +object Test { + def main(args: Array[String]) = { + val w = new W + } + +} diff --git a/tests/pos/lambdalift.scala b/tests/pos/lambdalift.scala index 33cc2c069e9b..ab50d9acf8ea 100644 --- a/tests/pos/lambdalift.scala +++ b/tests/pos/lambdalift.scala @@ -22,4 +22,19 @@ object test { fun("abc") } + + class D(f: Int => Int) { self => + assert(f(0) == 3) + + def g(xxx: Int) = { + + class E extends D(y => xxx + y) { + } + + new E + } + g(3) + } + + new D(y => 3) }