diff options
author | Martin Odersky <odersky@gmail.com> | 2014-08-25 13:05:38 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2014-08-25 13:05:43 +0200 |
commit | b41732c15682337c415355accb96224f452b9ff5 (patch) | |
tree | 25285be55a43bcd0858b286d4b91289e305b1568 /src/dotty/tools | |
parent | 15c4fec42148da760107baa0fb3e5fbb699c4c82 (diff) | |
download | dotty-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.
Diffstat (limited to 'src/dotty/tools')
-rw-r--r-- | src/dotty/tools/dotc/Compiler.scala | 3 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/AttachOuter.scala | 65 |
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 |