diff options
author | Martin Odersky <odersky@gmail.com> | 2016-09-05 11:51:14 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2016-10-02 16:11:21 +0200 |
commit | 1d932642eaed2ec9829be951f3272d32b4393a39 (patch) | |
tree | 6e7263cc14896b604d0522f01c73644f6d54ea54 /src | |
parent | 0bd955e7780c95d41a0b6c4b7ca221f00e3cfd92 (diff) | |
download | dotty-1d932642eaed2ec9829be951f3272d32b4393a39.tar.gz dotty-1d932642eaed2ec9829be951f3272d32b4393a39.tar.bz2 dotty-1d932642eaed2ec9829be951f3272d32b4393a39.zip |
Handle outer this in Inliner
Also, do some refactorings and fix some bugs in Inliner.
Diffstat (limited to 'src')
-rw-r--r-- | src/dotty/tools/dotc/core/NameOps.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/StdNames.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/ExplicitOuter.scala | 6 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/FirstTransform.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/PatternMatcher.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/transform/SuperAccessors.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/typer/Inliner.scala | 58 |
7 files changed, 40 insertions, 34 deletions
diff --git a/src/dotty/tools/dotc/core/NameOps.scala b/src/dotty/tools/dotc/core/NameOps.scala index ea255e5b3..ddb0421bb 100644 --- a/src/dotty/tools/dotc/core/NameOps.scala +++ b/src/dotty/tools/dotc/core/NameOps.scala @@ -84,6 +84,7 @@ object NameOps { name.stripAnonNumberSuffix endsWith MODULE_VAR_SUFFIX def isSelectorName = name.startsWith(" ") && name.tail.forall(_.isDigit) def isLazyLocal = name.endsWith(nme.LAZY_LOCAL) + def isOuterSelect = name.endsWith(nme.OUTER_SELECT) /** Is name a variable name? */ def isVariableName: Boolean = name.length > 0 && { diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index f47ab1744..fc26e0536 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -252,7 +252,7 @@ object StdNames { val MODULE_INSTANCE_FIELD: N = NameTransformer.MODULE_INSTANCE_NAME // "MODULE$" val OUTER: N = "$outer" val OUTER_LOCAL: N = "$outer " - val OUTER_SYNTH: N = "<outer>" // emitted by virtual pattern matcher, replaced by outer accessor in explicitouter + val OUTER_SELECT: N = "_<outer>" // emitted by inliner, replaced by outer path in explicitouter val REFINE_CLASS: N = "<refinement>" val ROOTPKG: N = "_root_" val SELECTOR_DUMMY: N = "<unapply-selector>" diff --git a/src/dotty/tools/dotc/transform/ExplicitOuter.scala b/src/dotty/tools/dotc/transform/ExplicitOuter.scala index 60ef1b306..3f235dca7 100644 --- a/src/dotty/tools/dotc/transform/ExplicitOuter.scala +++ b/src/dotty/tools/dotc/transform/ExplicitOuter.scala @@ -57,6 +57,12 @@ class ExplicitOuter extends MiniPhaseTransform with InfoTransformer { thisTransf override def mayChange(sym: Symbol)(implicit ctx: Context): Boolean = sym.isClass + /** 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) + else tree + /** First, add outer accessors if a class does not have them yet and it references an outer this. * If the class has outer accessors, implement them. * Furthermore, if a parent trait might have an outer accessor, diff --git a/src/dotty/tools/dotc/transform/FirstTransform.scala b/src/dotty/tools/dotc/transform/FirstTransform.scala index 6e1fed607..74dc9b9d6 100644 --- a/src/dotty/tools/dotc/transform/FirstTransform.scala +++ b/src/dotty/tools/dotc/transform/FirstTransform.scala @@ -72,8 +72,8 @@ class FirstTransform extends MiniPhaseTransform with InfoTransformer with Annota override def checkPostCondition(tree: Tree)(implicit ctx: Context): Unit = { tree match { - case Select(qual, _) if tree.symbol.exists => - assert(qual.tpe derivesFrom tree.symbol.owner, i"non member selection of ${tree.symbol.showLocated} from ${qual.tpe}") + case Select(qual, name) if !name.isOuterSelect && tree.symbol.exists => + assert(qual.tpe derivesFrom tree.symbol.owner, i"non member selection of ${tree.symbol.showLocated} from ${qual.tpe} in $tree") case _: TypeTree => case _: Import | _: NamedArg | _: TypTree => assert(false, i"illegal tree: $tree") diff --git a/src/dotty/tools/dotc/transform/PatternMatcher.scala b/src/dotty/tools/dotc/transform/PatternMatcher.scala index 490feb7d0..49c0eabec 100644 --- a/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -782,6 +782,7 @@ class PatternMatcher extends MiniPhaseTransform with DenotTransformer { val expectedClass = expectedTp.dealias.classSymbol.asClass val test = codegen._asInstanceOf(testedBinder, expectedTp) + // TODO: Use nme.OUTER_SELECT, like the Inliner does? val outerAccessorTested = ctx.atPhase(ctx.explicitOuterPhase.next) { implicit ctx => ExplicitOuter.ensureOuterAccessors(expectedClass) test.select(ExplicitOuter.outerAccessor(expectedClass)).select(defn.Object_eq).appliedTo(expectedOuter) diff --git a/src/dotty/tools/dotc/transform/SuperAccessors.scala b/src/dotty/tools/dotc/transform/SuperAccessors.scala index 6af991f27..10be6db65 100644 --- a/src/dotty/tools/dotc/transform/SuperAccessors.scala +++ b/src/dotty/tools/dotc/transform/SuperAccessors.scala @@ -148,7 +148,7 @@ class SuperAccessors(thisTransformer: DenotTransformer) { */ private def ensureProtectedAccessOK(sel: Select, targs: List[Tree])(implicit ctx: Context) = { val sym = sel.symbol - if (sym.exists && needsProtectedAccessor(sym, sel.pos)) { + if (sym.isTerm && !sel.name.isOuterSelect && needsProtectedAccessor(sym, sel.pos)) { ctx.debuglog("Adding protected accessor for " + sel) protectedAccessorCall(sel, targs) } else sel diff --git a/src/dotty/tools/dotc/typer/Inliner.scala b/src/dotty/tools/dotc/typer/Inliner.scala index fbb847e9d..970d31e47 100644 --- a/src/dotty/tools/dotc/typer/Inliner.scala +++ b/src/dotty/tools/dotc/typer/Inliner.scala @@ -40,7 +40,7 @@ object Inliner { sym.getAnnotation(defn.InlineAnnot).get.tree .attachment(InlinedBody).body - private class Typer extends ReTyper { + private object InlineTyper extends ReTyper { override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = { val acc = tree.symbol super.typedSelect(tree, pt) match { @@ -117,12 +117,12 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { private val (methPart, targs, argss) = decomposeCall(call) private val meth = methPart.symbol - private lazy val prefix = methPart match { + private val prefix = methPart match { case Select(qual, _) => qual case _ => tpd.This(ctx.owner.enclosingClass.asClass) } - private val thisProxy = new mutable.HashMap[Type, NamedType] + private val thisProxy = new mutable.HashMap[Type, TermRef] private val paramProxy = new mutable.HashMap[Type, Type] private val paramBinding = new mutable.HashMap[Name, Type] val bindingsBuf = new mutable.ListBuffer[MemberDef] @@ -167,20 +167,20 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { } private def registerType(tpe: Type): Unit = tpe match { - case tpe: ThisType if !thisProxy.contains(tpe) => - if (!ctx.owner.isContainedIn(tpe.cls) && !tpe.cls.is(Package)) - if (tpe.cls.isStaticOwner) - thisProxy(tpe) = tpe.cls.sourceModule.termRef - else { - def outerDistance(cls: Symbol): Int = { - assert(cls.exists, i"not encl: ${meth.owner.enclosingClass} ${tpe.cls}") - if (tpe.cls eq cls) 0 - else outerDistance(cls.owner.enclosingClass) + 1 - } - val n = outerDistance(meth.owner) - thisProxy(tpe) = newSym(nme.SELF ++ n.toString, EmptyFlags, tpe.widen).termRef - } - case tpe: NamedType if tpe.symbol.is(Param) && tpe.symbol.owner == meth && !paramProxy.contains(tpe) => + case tpe: ThisType + if !ctx.owner.isContainedIn(tpe.cls) && !tpe.cls.is(Package) && + !thisProxy.contains(tpe) => + if (tpe.cls.isStaticOwner) + thisProxy(tpe) = tpe.cls.sourceModule.termRef + else { + val proxyName = s"${tpe.cls.name}_this".toTermName + val proxyType = tpe.asSeenFrom(prefix.tpe, meth.owner) + thisProxy(tpe) = newSym(proxyName, EmptyFlags, proxyType).termRef + registerType(meth.owner.thisType) // make sure we have a base from which to outer-select + } + case tpe: NamedType + if tpe.symbol.is(Param) && tpe.symbol.owner == meth && + !paramProxy.contains(tpe) => paramProxy(tpe) = paramBinding(tpe.name) case _ => } @@ -190,25 +190,23 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { case _ => } - private def outerLevel(sym: Symbol) = sym.name.drop(nme.SELF.length).toString.toInt - def inlined(pt: Type) = { + if (!isIdempotentExpr(prefix)) registerType(meth.owner.thisType) // make sure prefix is computed rhs.foreachSubTree(registerLeaf) - val accessedSelfSyms = - (for ((tp: ThisType, ref) <- thisProxy) yield ref.symbol.asTerm).toSeq.sortBy(outerLevel) + def classOf(sym: Symbol) = sym.info.widen.classSymbol + def outerSelector(sym: Symbol) = classOf(sym).name.toTermName ++ nme.OUTER_SELECT + def outerLevel(sym: Symbol) = classOf(sym).ownersIterator.length + val accessedSelfSyms = thisProxy.values.toList.map(_.symbol).sortBy(-outerLevel(_)) var lastSelf: Symbol = NoSymbol for (selfSym <- accessedSelfSyms) { val rhs = - if (!lastSelf.exists) prefix - else { - val outerDelta = outerLevel(selfSym) - outerLevel(lastSelf) - def outerSelect(ref: Tree, dummy: Int): Tree = ??? - //ref.select(ExplicitOuter.outerAccessorTBD(ref.tpe.widen.classSymbol.asClass)) - (ref(lastSelf) /: (0 until outerDelta))(outerSelect) - } - bindingsBuf += ValDef(selfSym, rhs.ensureConforms(selfSym.info)) + if (!lastSelf.exists) + prefix + else + untpd.Select(ref(lastSelf), outerSelector(selfSym)).withType(selfSym.info) + bindingsBuf += ValDef(selfSym.asTerm, rhs) lastSelf = selfSym } @@ -239,7 +237,7 @@ class Inliner(call: tpd.Tree, rhs: tpd.Tree)(implicit ctx: Context) { val bindings = bindingsBuf.toList.map(_.withPos(call.pos)) val expansion = inliner(rhs.withPos(call.pos)) - val expansion1 = new Typer().typed(expansion, pt)(inlineContext(call)) + val expansion1 = InlineTyper.typed(expansion, pt)(inlineContext(call)) val result = tpd.Inlined(call, bindings, expansion1) inlining.println(i"inlining $call\n --> \n$result") |