Skip to content

Commit

Permalink
SI-4859 Don't elide qualifiers when selecting nested modules.
Browse files Browse the repository at this point in the history
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
retronym committed Jan 26, 2013
1 parent eb4b065 commit f21b1ce
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 5 deletions.
11 changes: 8 additions & 3 deletions src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
Expand Up @@ -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)
Expand Down
9 changes: 8 additions & 1 deletion src/compiler/scala/tools/nsc/transform/Flatten.scala
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
Expand Up @@ -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.
Expand Down
8 changes: 8 additions & 0 deletions 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()
29 changes: 29 additions & 0 deletions 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.