summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala11
-rw-r--r--src/compiler/scala/tools/nsc/transform/Flatten.scala9
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala3
-rw-r--r--test/files/run/t4859.check8
-rw-r--r--test/files/run/t4859.scala29
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()
+ }
+}
+