aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-08-25 13:05:38 +0200
committerMartin Odersky <odersky@gmail.com>2014-08-25 13:05:43 +0200
commitb41732c15682337c415355accb96224f452b9ff5 (patch)
tree25285be55a43bcd0858b286d4b91289e305b1568
parent15c4fec42148da760107baa0fb3e5fbb699c4c82 (diff)
downloaddotty-b41732c15682337c415355accb96224f452b9ff5.tar.gz
dotty-b41732c15682337c415355accb96224f452b9ff5.tar.bz2
dotty-b41732c15682337c415355accb96224f452b9ff5.zip
New minipahse: AttachOuter
This keeps type info needed for explicit outer in attachments so that it survives erasure. ExplicitOuter should run after erasure, for several reasons. (1) Java generic signatures do not include the outer parameter (2) Pre-erasure typings become incorrect after erasure. In particular, if we have a class class C { type T class Inner { type U = C.this.T } val inner: Inner } after explicit outer the equality of T and inner.U is no longer provable.
-rw-r--r--src/dotty/tools/dotc/Compiler.scala3
-rw-r--r--src/dotty/tools/dotc/transform/AttachOuter.scala65
2 files changed, 67 insertions, 1 deletions
diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala
index 3355ce1f2..ac2e91cec 100644
--- a/src/dotty/tools/dotc/Compiler.scala
+++ b/src/dotty/tools/dotc/Compiler.scala
@@ -61,7 +61,8 @@ class Compiler {
List(new ElimByName,
new TypeTestsCasts,
new InterceptedMethods,
- new Literalize),
+ new Literalize,
+ new AttachOuter),
List(new Erasure)
)
diff --git a/src/dotty/tools/dotc/transform/AttachOuter.scala b/src/dotty/tools/dotc/transform/AttachOuter.scala
new file mode 100644
index 000000000..9d2b0574d
--- /dev/null
+++ b/src/dotty/tools/dotc/transform/AttachOuter.scala
@@ -0,0 +1,65 @@
+package dotty.tools.dotc
+package transform
+
+import TreeTransforms._
+import core.DenotTransformers._
+import core.Symbols._
+import core.Contexts._
+import core.Types._
+import core.Flags._
+import core.Decorators._
+import core.StdNames.nme
+import ast.Trees._
+import util.Attachment
+
+/** This phase decorates News and parent constructors of non-static inner classes
+ * with an attachment indicating the outer reference as a tree. This is necessary because
+ * outer prefixes are erased, and explicit outer runs only after erasure.
+ */
+class AttachOuter extends MiniPhaseTransform {
+ import ast.tpd._
+
+ val Outer = new Attachment.Key[Tree]
+
+ override def phaseName: String = "attachOuter"
+
+ private def outerPrefix(tpe: Type)(implicit ctx: Context): Type = tpe match {
+ case tpe: TypeRef =>
+ tpe.symbol match {
+ case cls: ClassSymbol =>
+ if (cls.owner.isStaticOwner || cls.is(Interface)) NoPrefix
+ else if (tpe.prefix eq NoPrefix) cls.owner.enclosingClass.thisType
+ else tpe.prefix
+ case _ =>
+ outerPrefix(tpe.underlying)
+ }
+ case tpe: TypeProxy =>
+ outerPrefix(tpe.underlying)
+ }
+
+ override def transformNew(tree: New)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ val pre = outerPrefix(tree.tpt.tpe)
+ pre match {
+ case pre: SingletonType =>
+ tree.putAttachment(Outer, singleton(pre)) match {
+ case Some(outer) => assert(outer.tpe =:= pre)
+ case none =>
+ }
+ case NoPrefix =>
+ }
+ tree
+ }
+
+ override def transformTemplate(tree: Template)(implicit ctx: Context, info: TransformerInfo): Tree = {
+ def transformParent(tree: Tree): Tree = tree match {
+ case tree: TypeTree if outerPrefix(tree.tpe) != NoPrefix =>
+ val constr = New(tree.tpe, Nil).withPos(tree.pos)
+ val Select(nu: New, _) = methPart(constr)
+ transformNew(nu)
+ constr
+ case _ =>
+ tree
+ }
+ cpy.Template(tree)(parents = tree.parents mapconserve transformParent)
+ }
+} \ No newline at end of file