From 50e3a7d92f4b7cc4cd922eb92c7ed8bf793b159c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 17 Sep 2015 12:01:29 +0200 Subject: New phase: ExplicitSelf Makes self types explicit, if this is needed to identify a member in a select. Fixes #789. --- src/dotty/tools/dotc/Compiler.scala | 1 + src/dotty/tools/dotc/core/Types.scala | 5 ++- src/dotty/tools/dotc/transform/ExplicitSelf.scala | 37 +++++++++++++++++++++++ tests/run/i789.check | 1 + tests/run/i789.scala | 20 ++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/dotty/tools/dotc/transform/ExplicitSelf.scala create mode 100644 tests/run/i789.check create mode 100644 tests/run/i789.scala diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index c537d8885..a36743b59 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -52,6 +52,7 @@ class Compiler { new ClassOf), List(new PatternMatcher, new ExplicitOuter, + new ExplicitSelf, new Splitter), List(new VCInlineMethods, new SeqLiterals, diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index d04da30c0..358720836 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -2530,7 +2530,7 @@ object Types { def selfType(implicit ctx: Context): Type = { if (selfTypeCache == null) selfTypeCache = { - def fullRef = fullyAppliedRef(cls.typeRef, cls.typeParams) + def fullRef = fullyAppliedRef val given = givenSelfType val raw = if (!given.exists) fullRef @@ -2561,6 +2561,9 @@ object Types { base } + /** The class type with all type parameters */ + def fullyAppliedRef(implicit ctx: Context): Type = fullyAppliedRef(cls.typeRef, cls.typeParams) + def rebase(tp: Type)(implicit ctx: Context): Type = if ((prefix eq cls.owner.thisType) || !cls.owner.isClass || ctx.erasedTypes) tp else tp.substThis(cls.owner.asClass, prefix) diff --git a/src/dotty/tools/dotc/transform/ExplicitSelf.scala b/src/dotty/tools/dotc/transform/ExplicitSelf.scala new file mode 100644 index 000000000..c6a218157 --- /dev/null +++ b/src/dotty/tools/dotc/transform/ExplicitSelf.scala @@ -0,0 +1,37 @@ +package dotty.tools.dotc +package transform + +import core._ +import Contexts.Context +import Types._ +import TreeTransforms._ +import Decorators._ +import ast.Trees._ +import Flags._ + +/** Transform references of the form + * + * C.this.m + * + * where `C` is a class with explicit self type and `C` is not a + * subclass of the owner of `m` to + * + * C.this.asInstanceOf[S].m + * + * where `S` is the self type of `C`. + */ +class ExplicitSelf extends MiniPhaseTransform { thisTransform => + import ast.tpd._ + + override def phaseName = "explicitSelf" + + override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo): Tree = tree match { + case Select(thiz: This, name) if name.isTermName => + val cls = thiz.symbol.asClass + val cinfo = cls.classInfo + if (cinfo.givenSelfType.exists && !cls.derivesFrom(tree.symbol.owner)) + cpy.Select(tree)(thiz.asInstance(cinfo.selfType), name) + else tree + case _ => tree + } +} diff --git a/tests/run/i789.check b/tests/run/i789.check new file mode 100644 index 000000000..d41f69423 --- /dev/null +++ b/tests/run/i789.check @@ -0,0 +1 @@ +atPhase: 2 diff --git a/tests/run/i789.scala b/tests/run/i789.scala new file mode 100644 index 000000000..99b081f0a --- /dev/null +++ b/tests/run/i789.scala @@ -0,0 +1,20 @@ + trait Periods { self: Context => + + def atPhase(id: Int): Unit = println(s"atPhase: $id") + + } + + class Phase(val id: Int) + + trait Phases { self: Context => + def atPhase(phase: Phase): Unit = self.atPhase(phase.id) + } + + trait Context extends Phases with Periods + + object Test extends Context { + + def main(args: Array[String]) = atPhase(new Phase(2)) + + } + -- cgit v1.2.3