aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/transform
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2017-02-18 12:54:36 +0100
committerMartin Odersky <odersky@gmail.com>2017-02-18 12:55:08 +0100
commite9fecd393a3c355a68207da4bb1fa9fcf47eafc9 (patch)
tree15d01361ddacc0cfafd05a7b780677c331c762c3 /compiler/src/dotty/tools/dotc/transform
parent6df672c7e7be65d7be1cd6524c610aed4f35178c (diff)
downloaddotty-e9fecd393a3c355a68207da4bb1fa9fcf47eafc9.tar.gz
dotty-e9fecd393a3c355a68207da4bb1fa9fcf47eafc9.tar.bz2
dotty-e9fecd393a3c355a68207da4bb1fa9fcf47eafc9.zip
Fix #1990: Handle case where inlining changes class of outer
The new situation in the test was that outer of the inlined method was `A` but it's as seen from type is a subtype `B`. We need two fixes: - Ignore outerSelects in TreeChecker. These are treated as having fixed symbols. - Adapt the outer-path logic to deal with code that's moved to another context.
Diffstat (limited to 'compiler/src/dotty/tools/dotc/transform')
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala15
-rw-r--r--compiler/src/dotty/tools/dotc/transform/TreeChecker.scala6
2 files changed, 16 insertions, 5 deletions
diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
index c2aacf826..cb74f601f 100644
--- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
@@ -60,7 +60,7 @@ class ExplicitOuter extends MiniPhaseTransform with InfoTransformer { thisTransf
/** Convert a selection of the form `qual.C_<OUTER>` to an outer path from `qual` to `C` */
override def transformSelect(tree: Select)(implicit ctx: Context, info: TransformerInfo) =
if (tree.name.isOuterSelect)
- outer.path(tree.tpe.widen.classSymbol, tree.qualifier).ensureConforms(tree.tpe)
+ outer.path(tree.tpe.widen.classSymbol, tree.qualifier, outOfContext = true).ensureConforms(tree.tpe)
else tree
/** First, add outer accessors if a class does not have them yet and it references an outer this.
@@ -355,14 +355,21 @@ object ExplicitOuter {
}
/** The path of outer accessors that references `toCls.this` starting from
- * the context owner's this node.
+ * node `start`, which defaults to the context owner's this node.
+ * @param outOfContext When true, we take the `path` in code that has been inlined
+ * from somewhere else. In that case, we need to stop not
+ * just when `toCls` is reached exactly, but also in any superclass
+ * of `treeCls`. This compensates the `asSeenFrom` logic
+ * used to compute this-proxies in Inliner.
*/
- def path(toCls: Symbol, start: Tree = This(ctx.owner.lexicallyEnclosingClass.asClass)): Tree = try {
+ def path(toCls: Symbol,
+ start: Tree = This(ctx.owner.lexicallyEnclosingClass.asClass),
+ outOfContext: Boolean = true): Tree = try {
def loop(tree: Tree): Tree = {
val treeCls = tree.tpe.widen.classSymbol
val outerAccessorCtx = ctx.withPhaseNoLater(ctx.lambdaLiftPhase) // lambdalift mangles local class names, which means we cannot reliably find outer acessors anymore
ctx.log(i"outer to $toCls of $tree: ${tree.tpe}, looking for ${outerAccName(treeCls.asClass)(outerAccessorCtx)} in $treeCls")
- if (treeCls == toCls) tree
+ if (treeCls == toCls || outOfContext && toCls.derivesFrom(treeCls)) tree
else {
val acc = outerAccessor(treeCls.asClass)(outerAccessorCtx)
assert(acc.exists,
diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
index b2b99160b..7a4af647f 100644
--- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
+++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
@@ -12,6 +12,7 @@ import core.Types._
import core.Flags._
import core.Constants._
import core.StdNames._
+import core.NameOps._
import core.Decorators._
import core.TypeErasure.isErasedType
import core.Phases.Phase
@@ -336,7 +337,10 @@ class TreeChecker extends Phase with SymTransformer {
assert(tree.isTerm || !ctx.isAfterTyper, tree.show + " at " + ctx.phase)
val tpe = tree.typeOpt
val sym = tree.symbol
- if (!tpe.isInstanceOf[WithFixedSym] && sym.exists && !sym.is(Private)) {
+ if (!tpe.isInstanceOf[WithFixedSym] &&
+ sym.exists && !sym.is(Private) &&
+ !tree.name.isOuterSelect // outer selects have effectively fixed symbols
+ ) {
val qualTpe = tree.qualifier.typeOpt
val member =
if (sym.is(Private)) qualTpe.member(tree.name)