Browse files

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.
  • Loading branch information...
1 parent eb4b065 commit f21b1ce7fda9022d6d805a708882c5a2ab241f41 @retronym retronym committed Dec 15, 2012
View
11 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)
View
9 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
}
View
3 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.
View
8 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()
View
29 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()
+ }
+}
+

0 comments on commit f21b1ce

Please sign in to comment.