diff options
-rw-r--r-- | src/dotty/tools/dotc/TypeErasure.scala | 5 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/Erasure.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/OuterAccessors.scala | 35 | ||||
-rw-r--r-- | tests/pos/explicitOuter.scala | 12 |
4 files changed, 47 insertions, 9 deletions
diff --git a/src/dotty/tools/dotc/TypeErasure.scala b/src/dotty/tools/dotc/TypeErasure.scala index d2b241e71..a5dbd5731 100644 --- a/src/dotty/tools/dotc/TypeErasure.scala +++ b/src/dotty/tools/dotc/TypeErasure.scala @@ -1,7 +1,9 @@ -package dotty.tools.dotc +package dotty.tools +package dotc package core import Symbols._, Types._, Contexts._, Flags._, Names._, StdNames._, Decorators._, Flags.JavaDefined +import dotc.transform.OuterAccessors._ import util.DotClass /** Erased types are: @@ -110,6 +112,7 @@ object TypeErasure { if ((sym eq defn.Any_asInstanceOf) || (sym eq defn.Any_isInstanceOf)) eraseParamBounds(sym.info.asInstanceOf[PolyType]) else if (sym.isAbstractType) TypeAlias(WildcardType) + else if (sym.isConstructor) addOuterParam(sym.owner.asClass, erase(tp)) else erase(tp) } diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index 7100e4528..6e82f050a 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -24,6 +24,7 @@ import scala.collection.mutable.ListBuffer import dotty.tools.dotc.core.Flags import ValueClasses._ import TypeUtils._ +import OuterAccessors._ import typer.Mode class Erasure extends Phase with DenotTransformer { thisTransformer => @@ -304,7 +305,8 @@ object Erasure { case fun1 => fun1.tpe.widen match { case mt: MethodType => - val args1 = (args ++ protoArgs(pt)).zipWithConserve(mt.paramTypes)(typedExpr) + val outers = outerArgs(fun1) map untpd.TypedSplice + val args1 = (outers ::: args ++ protoArgs(pt)).zipWithConserve(mt.paramTypes)(typedExpr) untpd.cpy.Apply(tree)(fun1, args1) withType mt.resultType case _ => throw new MatchError(i"tree $tree has unexpected type of function ${fun1.tpe.widen}, was ${fun.typeOpt.widen}") diff --git a/src/dotty/tools/dotc/transform/OuterAccessors.scala b/src/dotty/tools/dotc/transform/OuterAccessors.scala index 5e6257e7f..2cad74cf3 100644 --- a/src/dotty/tools/dotc/transform/OuterAccessors.scala +++ b/src/dotty/tools/dotc/transform/OuterAccessors.scala @@ -80,7 +80,7 @@ class OuterAccessors extends MiniPhaseTransform with InfoTransformer { thisTrans if (isTrait) newDefs += DefDef(outerAcc, EmptyTree) else { - val outerParamAcc = cls.info.decl(nme.OUTER).symbol.asTerm + val outerParamAcc = outerParamAccessor(cls).asTerm newDefs += ValDef(outerParamAcc, EmptyTree) newDefs += DefDef(outerAcc, ref(outerParamAcc)) } @@ -132,6 +132,10 @@ object OuterAccessors { def hasLocalInstantiation(cls: ClassSymbol)(implicit ctx: Context): Boolean = cls.owner.isTerm || cls.is(LocalInstantiationSite) + /** The outer parameter accessor of cass `cls` */ + def outerParamAccessor(cls: ClassSymbol)(implicit ctx: Context) = + cls.info.decl(nme.OUTER).symbol + /** Class has outer accessor. Can be called only after phase OuterAccessors. */ def hasOuter(cls: ClassSymbol)(implicit ctx: Context): Boolean = cls.info.decl(cls.outerAccName).exists @@ -161,4 +165,33 @@ object OuterAccessors { case tpe: TypeProxy => outerPrefix(tpe.underlying) } + + /** If `cls` has an outer parameter add one to the method type `tp`. */ + def addOuterParam(cls: ClassSymbol, tp: Type)(implicit ctx: Context): Type = + if (hasOuter(cls)) { + val mt @ MethodType(pnames, ptypes) = tp + mt.derivedMethodType( + nme.OUTER :: pnames, cls.owner.enclosingClass.typeRef :: ptypes, mt.resultType) + } + else tp + + /** If function in an apply node is a constructor that needs to be passed an + * outer argument, the singleton list with the argument, otherwise Nil. + */ + def outerArgs(fun: Tree)(implicit ctx: Context): List[Tree] = { + if (fun.symbol.isConstructor) { + val cls = fun.symbol.owner.asClass + def outerArg(receiver: Tree): Tree = receiver match { + case New(tpt) => TypeTree(outerPrefix(tpt.tpe)).withPos(tpt.pos) + case This(_) => ref(outerParamAccessor(cls)) + case TypeApply(Select(r, nme.asInstanceOf_), args) => outerArg(r) // cast was inserted, skip + } + if (hasOuter(cls)) + methPart(fun) match { + case Select(receiver, _) => outerArg(receiver) :: Nil + } + else Nil + } + else Nil + } }
\ No newline at end of file diff --git a/tests/pos/explicitOuter.scala b/tests/pos/explicitOuter.scala index 747f07e8f..a5fb1dd70 100644 --- a/tests/pos/explicitOuter.scala +++ b/tests/pos/explicitOuter.scala @@ -4,8 +4,8 @@ class Outer(elem: Int, val next: Outer) { def foo = elem } - class InnerClass extends next.InnerTrait { - def bar = elem + class InnerClass(x: Int) extends next.InnerTrait { + def bar = elem + x } class EmptyInnerClass { @@ -17,15 +17,15 @@ class Outer(elem: Int, val next: Outer) { def foo = elem } - class InnerClass extends next.InnerTrait { - def bar = elem + class InnerClass(x: Int) extends next.InnerTrait { + def bar = elem + x } class EmptyInnerClass { def foo = 1 // does not need outer } - val ic = new InnerClass + val ic = new InnerClass(1) println(ic.bar) println(ic.foo) val it = new InnerTrait {} @@ -38,7 +38,7 @@ class Outer(elem: Int, val next: Outer) { object Test extends App { val o = new Outer(1, new Outer(2, null)) - val ic = new o.InnerClass + val ic = new o.InnerClass(1) println(ic.bar) println(ic.foo) val it = new o.InnerTrait {} |