aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dotty/tools/dotc/TypeErasure.scala5
-rw-r--r--src/dotty/tools/dotc/transform/Erasure.scala4
-rw-r--r--src/dotty/tools/dotc/transform/OuterAccessors.scala35
-rw-r--r--tests/pos/explicitOuter.scala12
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 {}