aboutsummaryrefslogtreecommitdiff
path: root/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2017-02-19 21:58:50 +0100
committerMartin Odersky <odersky@gmail.com>2017-02-19 21:59:01 +0100
commitbd80a187c3792a4891bec72e0b27b858a5a992ab (patch)
treeb031c9ecf7f29d23375067eee82cf473eaef9cca /compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
parentc54e942ef6275fc0c61c051539a1b37f4e12123c (diff)
downloaddotty-bd80a187c3792a4891bec72e0b27b858a5a992ab.tar.gz
dotty-bd80a187c3792a4891bec72e0b27b858a5a992ab.tar.bz2
dotty-bd80a187c3792a4891bec72e0b27b858a5a992ab.zip
Harden outer proxy computation of inlined code
It turns out that we simply cannot do reliable outer path computation that fills in the right hand sides of this-proxies from the types of these proxies. As-seen-from logic can mangle the types of proxies enough to scramble the necessary information. What we now do instead is simply count: We record the number of outer accesses to an outer this in inlineable code, and do the same number of outer accesses when computing the proxy.
Diffstat (limited to 'compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala')
-rw-r--r--compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala32
1 files changed, 17 insertions, 15 deletions
diff --git a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
index 3cfbdf454..d75c32fcc 100644
--- a/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
+++ b/compiler/src/dotty/tools/dotc/transform/ExplicitOuter.scala
@@ -60,7 +60,8 @@ 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, outOfContext = true).ensureConforms(tree.tpe)
+ outer.path(start = tree.qualifier, count = tree.name.outerSelectHops)
+ .ensureConforms(tree.tpe)
else tree
/** First, add outer accessors if a class does not have them yet and it references an outer this.
@@ -354,31 +355,32 @@ object ExplicitOuter {
} else Nil
}
- /** The path of outer accessors that references `toCls.this` starting from
- * 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.
+ /** A path of outer accessors starting from node `start`. `start` defaults to the
+ * context owner's this node. There are two alternative conditions that determine
+ * where the path ends:
+ *
+ * - if the initial `count` parameter is non-negative: where the number of
+ * outer accessors reaches count.
+ * - if the initial `count` parameter is negative: where the class symbol of
+ * the type of the reached tree matches `toCls`.
*/
- def path(toCls: Symbol,
- start: Tree = This(ctx.owner.lexicallyEnclosingClass.asClass),
- outOfContext: Boolean = false): Tree = try {
- def loop(tree: Tree): Tree = {
+ def path(start: Tree = This(ctx.owner.lexicallyEnclosingClass.asClass),
+ toCls: Symbol = NoSymbol,
+ count: Int = -1): Tree = try {
+ def loop(tree: Tree, count: Int): 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 || outOfContext && toCls.derivesFrom(treeCls)) tree
+ if (count == 0 || count < 0 && treeCls == toCls) tree
else {
val acc = outerAccessor(treeCls.asClass)(outerAccessorCtx)
assert(acc.exists,
i"failure to construct path from ${ctx.owner.ownersIterator.toList}%/% to `this` of ${toCls.showLocated};\n${treeCls.showLocated} does not have an outer accessor")
- loop(tree.select(acc).ensureApplied)
+ loop(tree.select(acc).ensureApplied, count - 1)
}
}
ctx.log(i"computing outerpath to $toCls from ${ctx.outersIterator.map(_.owner).toList}")
- loop(start)
+ loop(start, count)
} catch {
case ex: ClassCastException =>
throw new ClassCastException(i"no path exists from ${ctx.owner.enclosingClass} to $toCls")