From e9fecd393a3c355a68207da4bb1fa9fcf47eafc9 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 18 Feb 2017 12:54:36 +0100 Subject: 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. --- .../src/dotty/tools/dotc/transform/ExplicitOuter.scala | 15 +++++++++++---- compiler/src/dotty/tools/dotc/transform/TreeChecker.scala | 6 +++++- tests/pos/i1990.scala | 12 ++++++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 tests/pos/i1990.scala 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_` 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) diff --git a/tests/pos/i1990.scala b/tests/pos/i1990.scala new file mode 100644 index 000000000..77cea0af7 --- /dev/null +++ b/tests/pos/i1990.scala @@ -0,0 +1,12 @@ +class A { + class Foo { + inline def inlineMeth: Unit = { + new Bar + } + } + class Bar +} + +class B extends A { + (new Foo).inlineMeth +} -- cgit v1.2.3