diff --git a/src/dotty/tools/dotc/ast/TreeTypeMap.scala b/src/dotty/tools/dotc/ast/TreeTypeMap.scala index d714a3d21f40..a35fe2e8ffe8 100644 --- a/src/dotty/tools/dotc/ast/TreeTypeMap.scala +++ b/src/dotty/tools/dotc/ast/TreeTypeMap.scala @@ -82,7 +82,8 @@ final class TreeTypeMap( constr = tmap.transformSub(constr), parents = parents mapconserve transform, self = tmap.transformSub(self), - body = impl.body mapconserve tmap.transform + body = impl.body mapconserve + (tmap.transform(_)(ctx.withOwner(mapOwner(impl.symbol.owner)))) ).withType(tmap.mapType(impl.tpe)) case tree1 => tree1.withType(mapType(tree1.tpe)) match { diff --git a/src/dotty/tools/dotc/transform/Constructors.scala b/src/dotty/tools/dotc/transform/Constructors.scala index b6ebd7d90393..44638ce4892e 100644 --- a/src/dotty/tools/dotc/transform/Constructors.scala +++ b/src/dotty/tools/dotc/transform/Constructors.scala @@ -26,7 +26,7 @@ import collection.mutable * - also moves private fields that are accessed only from constructor * into the constructor if possible. */ -class Constructors extends MiniPhaseTransform with SymTransformer { thisTransform => +class Constructors extends MiniPhaseTransform with IdentityDenotTransformer { thisTransform => import tpd._ override def phaseName: String = "constructors" @@ -99,18 +99,6 @@ class Constructors extends MiniPhaseTransform with SymTransformer { thisTransfor } } - /** Symbols that are owned by either or a class field move into the - * primary constructor. - */ - override def transformSym(sym: SymDenotation)(implicit ctx: Context): SymDenotation = { - def ownerBecomesConstructor(owner: Symbol): Boolean = - (owner.isLocalDummy || owner.isTerm && !owner.is(MethodOrLazy)) && - owner.owner.isClass - if (ownerBecomesConstructor(sym.owner)) - sym.copySymDenotation(owner = sym.owner.enclosingClass.primaryConstructor) - else sym - } - /** @return true if after ExplicitOuter, all references from this tree go via an * outer link, so no parameter accessors need to be rewired to parameters */ diff --git a/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 4cf076c45d3f..9170cd277c22 100644 --- a/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -212,27 +212,34 @@ object ExplicitOuter { /** Tree references an outer class of `cls` which is not a static owner. */ def referencesOuter(cls: Symbol, tree: Tree)(implicit ctx: Context): Boolean = { - def isOuter(sym: Symbol) = + def isOuterSym(sym: Symbol) = !sym.isStaticOwner && cls.isProperlyContainedIn(sym) + def isOuterRef(ref: Type): Boolean = ref match { + case ref: ThisType => + isOuterSym(ref.cls) + case ref: TermRef => + if (ref.prefix ne NoPrefix) + !ref.symbol.isStatic && isOuterRef(ref.prefix) + else if (ref.symbol is Hoistable) + // ref.symbol will be placed in enclosing class scope by LambdaLift, so it might need + // an outer path then. + isOuterSym(ref.symbol.owner.enclosingClass) + else + // ref.symbol will get a proxy in immediately enclosing class. If this properly + // contains the current class, it needs an outer path. + ctx.owner.enclosingClass.owner.enclosingClass.isContainedIn(ref.symbol.owner) + case _ => false + } + def hasOuterPrefix(tp: Type) = tp match { + case TypeRef(prefix, _) => isOuterRef(prefix) + case _ => false + } tree match { - case thisTree @ This(_) => - isOuter(thisTree.symbol) - case id: Ident => - id.tpe match { - case ref @ TermRef(NoPrefix, _) => - if (ref.symbol is Hoistable) - // ref.symbol will be placed in enclosing class scope by LambdaLift, so it might need - // an outer path then. - isOuter(ref.symbol.owner.enclosingClass) - else - // ref.symbol will get a proxy in immediately enclosing class. If this properly - // contains the current class, it needs an outer path. - ctx.owner.enclosingClass.owner.enclosingClass.isContainedIn(ref.symbol.owner) - case _ => false - } + case _: This | _: Ident => isOuterRef(tree.tpe) case nw: New => val newCls = nw.tpe.classSymbol - isOuter(newCls.owner.enclosingClass) || + isOuterSym(newCls.owner.enclosingClass) || + hasOuterPrefix(nw.tpe) || newCls.owner.isTerm && cls.isProperlyContainedIn(newCls) // newCls might get proxies for free variables. If current class is // properly contained in newCls, it needs an outer path to newCls access the diff --git a/src/dotty/tools/dotc/transform/Mixin.scala b/src/dotty/tools/dotc/transform/Mixin.scala index 32b268fc75f9..d9e0c74769b0 100644 --- a/src/dotty/tools/dotc/transform/Mixin.scala +++ b/src/dotty/tools/dotc/transform/Mixin.scala @@ -134,8 +134,8 @@ class Mixin extends MiniPhaseTransform with SymTransformer { thisTransform => val vsym = stat.symbol val isym = initializer(vsym) val rhs = Block( - initBuf.toList.map(_.changeOwner(impl.symbol, isym)), - stat.rhs.changeOwner(vsym, isym).wildcardToDefault) + initBuf.toList.map(_.changeOwnerAfter(impl.symbol, isym, thisTransform)), + stat.rhs.changeOwnerAfter(vsym, isym, thisTransform).wildcardToDefault) initBuf.clear() cpy.DefDef(stat)(rhs = EmptyTree) :: DefDef(isym, rhs) :: Nil case stat: DefDef if stat.symbol.isSetter => diff --git a/tests/pos/i1131.scala b/tests/pos/i1131.scala new file mode 100644 index 000000000000..42c2a685c9b0 --- /dev/null +++ b/tests/pos/i1131.scala @@ -0,0 +1,14 @@ +class Outer { + class Inner +} + +trait MustBeATrait { + val o = new Outer + val inner = { + class C { + new o.Inner + } + new C + } + val inner2 = new o.Inner {} +}