diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2012-12-15 14:22:14 +0100 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2013-01-26 15:41:07 +0100 |
commit | f21b1ce7fda9022d6d805a708882c5a2ab241f41 (patch) | |
tree | 8b8de4a28a0dcc6e4118e2986708074c55a42055 | |
parent | eb4b06544a4362231357686c39beef9dbe00d932 (diff) | |
download | scala-f21b1ce7fda9022d6d805a708882c5a2ab241f41.tar.gz scala-f21b1ce7fda9022d6d805a708882c5a2ab241f41.tar.bz2 scala-f21b1ce7fda9022d6d805a708882c5a2ab241f41.zip |
SI-4859 Don't elide qualifiers when selecting nested modules.
Otherwise we fail to throw in:
{???; Predef}.DummyImplicit.dummyImplicit
We still elide the initialization of `Outer` in `Outer.Inner.foo`
as before, although that seems a little dubious to me.
In total, we had to change RefChecks, Flatten, and GenICode
to effect this change. A recently fixed bug in tail call elimination
was also due to assuming that the the qualifier of a Select node
wasn't worthy of traversal. Let's keep a close eye out for more
instances of this problem.
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/GenICode.scala | 11 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Flatten.scala | 9 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 3 | ||||
-rw-r--r-- | test/files/run/t4859.check | 8 | ||||
-rw-r--r-- | test/files/run/t4859.scala | 29 |
5 files changed, 55 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala index 2ea26ddaa9..91a0ca4ff0 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala @@ -835,13 +835,18 @@ abstract class GenICode extends SubComponent { generatedType = toTypeKind(sym.info) val hostClass = findHostClass(qualifier.tpe, sym) log(s"Host class of $sym with qual $qualifier (${qualifier.tpe}) is $hostClass") + val qualSafeToInline = treeInfo isExprSafeToInline qualifier + + def genLoadQualUnlessInlinable: Context = + if (qualSafeToInline) ctx else genLoadQualifier(tree, ctx) if (sym.isModule) { - genLoadModule(ctx, tree) + genLoadModule(genLoadQualUnlessInlinable, tree) } else if (sym.isStaticMember) { - ctx.bb.emit(LOAD_FIELD(sym, true) setHostClass hostClass, tree.pos) - ctx + val ctx1 = genLoadQualUnlessInlinable + ctx1.bb.emit(LOAD_FIELD(sym, true) setHostClass hostClass, tree.pos) + ctx1 } else { val ctx1 = genLoadQualifier(tree, ctx) ctx1.bb.emit(LOAD_FIELD(sym, false) setHostClass hostClass, tree.pos) diff --git a/src/compiler/scala/tools/nsc/transform/Flatten.scala b/src/compiler/scala/tools/nsc/transform/Flatten.scala index 7fe3a5da5c..85516f1995 100644 --- a/src/compiler/scala/tools/nsc/transform/Flatten.scala +++ b/src/compiler/scala/tools/nsc/transform/Flatten.scala @@ -12,6 +12,7 @@ import scala.collection.mutable.ListBuffer abstract class Flatten extends InfoTransform { import global._ + import treeInfo.isExprSafeToInline /** the following two members override abstract members in Transform */ val phaseName: String = "flatten" @@ -117,7 +118,13 @@ abstract class Flatten extends InfoTransform { liftedDefs(sym.enclosingTopLevelClass.owner) += tree EmptyTree case Select(qual, name) if sym.isStaticModule && !sym.isTopLevel => - exitingFlatten(atPos(tree.pos)(gen.mkAttributedRef(sym))) + exitingFlatten { + atPos(tree.pos) { + val ref = gen.mkAttributedRef(sym) + if (isExprSafeToInline(qual)) ref + else Block(List(qual), ref).setType(tree.tpe) // need to execute the qualifier but refer directly to the lifted module. + } + } case _ => tree } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index c316955a02..b820d8a386 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1389,7 +1389,8 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans case TypeApply(fun, targs) => isClassTypeAccessible(fun) case Select(module, apply) => - ( // SI-4859 `CaseClass1().InnerCaseClass2()` must not be rewritten to `new InnerCaseClass2()` + ( // SI-4859 `CaseClass1().InnerCaseClass2()` must not be rewritten to `new InnerCaseClass2()`; + // {expr; Outer}.Inner() must not be rewritten to `new Outer.Inner()`. treeInfo.isExprSafeToInline(module) && // SI-5626 Classes in refinement types cannot be constructed with `new`. In this case, // the companion class is actually not a ClassSymbol, but a reference to an abstract type. diff --git a/test/files/run/t4859.check b/test/files/run/t4859.check new file mode 100644 index 0000000000..d329744ca0 --- /dev/null +++ b/test/files/run/t4859.check @@ -0,0 +1,8 @@ +Inner +Inner.i +About to reference Inner.i +Outer +Inner.i +About to reference O.N +About to reference O.N +About to reference O.N.apply() diff --git a/test/files/run/t4859.scala b/test/files/run/t4859.scala new file mode 100644 index 0000000000..6d223f2179 --- /dev/null +++ b/test/files/run/t4859.scala @@ -0,0 +1,29 @@ +object O { + case class N() + object P +} + +object Outer { + println("Outer") + object Inner { + println("Inner") + def i { + println("Inner.i") + } + } +} + +object Test { + def main(args: Array[String]) { + Outer.Inner.i // we still don't initiialize Outer here (but should we?) + + {println("About to reference Inner.i"); Outer}.Inner.i // Outer will be initialized. + + {println("About to reference O.N" ); O}.N + + {println("About to reference O.N" ); O}.N + + {println("About to reference O.N.apply()"); O}.N.apply() + } +} + |