summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-04-30 05:12:47 -0700
committerPaul Phillips <paulp@improving.org>2013-04-30 05:12:47 -0700
commit1fd4b7d2f435cf440f874ce99056bd1feeafa333 (patch)
tree9f81c799b6f413c2e09d6f7f80332dac351a19dd
parent3da1abe3a2e2752588ca8e2c7e889a321dae2037 (diff)
parentd3aa9a7639c3c26b42a8faa9566d0d43a998b723 (diff)
downloadscala-1fd4b7d2f435cf440f874ce99056bd1feeafa333.tar.gz
scala-1fd4b7d2f435cf440f874ce99056bd1feeafa333.tar.bz2
scala-1fd4b7d2f435cf440f874ce99056bd1feeafa333.zip
Merge pull request #2432 from retronym/ticket/delayed-init-ref
Warn on selection of vals from DelayedInit subclasses.
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala11
-rw-r--r--test/files/neg/delayed-init-ref.check10
-rw-r--r--test/files/neg/delayed-init-ref.flags1
-rw-r--r--test/files/neg/delayed-init-ref.scala42
4 files changed, 64 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
index 7f8aeceeec..4933b8e0cb 100644
--- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
@@ -1411,6 +1411,16 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
}
}
+ private def checkDelayedInitSelect(qual: Tree, sym: Symbol, pos: Position) = {
+ def isLikelyUninitialized = (
+ (sym.owner isSubClass DelayedInitClass)
+ && !qual.tpe.isInstanceOf[ThisType]
+ && sym.accessedOrSelf.isVal
+ )
+ if (settings.lint.value && isLikelyUninitialized)
+ unit.warning(pos, s"Selecting ${sym} from ${sym.owner}, which extends scala.DelayedInit, is likely to yield an uninitialized value")
+ }
+
private def lessAccessible(otherSym: Symbol, memberSym: Symbol): Boolean = (
(otherSym != NoSymbol)
&& !otherSym.isProtected
@@ -1610,6 +1620,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans
if(settings.Xmigration.value != NoScalaVersion)
checkMigration(sym, tree.pos)
checkCompileTimeOnly(sym, tree.pos)
+ checkDelayedInitSelect(qual, sym, tree.pos)
if (sym eq NoSymbol) {
unit.warning(tree.pos, "Select node has NoSymbol! " + tree + " / " + tree.tpe)
diff --git a/test/files/neg/delayed-init-ref.check b/test/files/neg/delayed-init-ref.check
new file mode 100644
index 0000000000..42ccabed1b
--- /dev/null
+++ b/test/files/neg/delayed-init-ref.check
@@ -0,0 +1,10 @@
+delayed-init-ref.scala:17: error: Selecting value vall from object O, which extends scala.DelayedInit, is likely to yield an uninitialized value
+ println(O.vall) // warn
+ ^
+delayed-init-ref.scala:19: error: Selecting value vall from object O, which extends scala.DelayedInit, is likely to yield an uninitialized value
+ println(vall) // warn
+ ^
+delayed-init-ref.scala:40: error: Selecting value foo from trait UserContext, which extends scala.DelayedInit, is likely to yield an uninitialized value
+ println({locally(()); this}.foo) // warn (spurious, but we can't discriminate)
+ ^
+three errors found
diff --git a/test/files/neg/delayed-init-ref.flags b/test/files/neg/delayed-init-ref.flags
new file mode 100644
index 0000000000..7949c2afa2
--- /dev/null
+++ b/test/files/neg/delayed-init-ref.flags
@@ -0,0 +1 @@
+-Xlint -Xfatal-warnings
diff --git a/test/files/neg/delayed-init-ref.scala b/test/files/neg/delayed-init-ref.scala
new file mode 100644
index 0000000000..f2aa804e28
--- /dev/null
+++ b/test/files/neg/delayed-init-ref.scala
@@ -0,0 +1,42 @@
+trait T {
+ val traitVal = ""
+}
+
+object O extends App with T {
+ val vall = ""
+ lazy val lazyy = ""
+ def deff = ""
+
+ println(vall) // no warn
+ new {
+ println(vall) // no warn
+ }
+}
+
+object Client {
+ println(O.vall) // warn
+ import O.vall
+ println(vall) // warn
+
+ println(O.lazyy) // no warn
+ println(O.deff) // no warn
+ println(O.traitVal) // no warn
+}
+
+// Delayed init usage pattern from Specs2
+// See: https://groups.google.com/d/msg/scala-sips/wP6dL8nIAQs/ogjoPE-MSVAJ
+trait Before extends DelayedInit {
+ def before()
+ override def delayedInit(x: => Unit): Unit = { before; x }
+}
+object Spec {
+ trait UserContext extends Before {
+ def before() = ()
+ val foo = "foo"
+ }
+ new UserContext {
+ println(foo) // no warn
+ println(this.foo) // no warn
+ println({locally(()); this}.foo) // warn (spurious, but we can't discriminate)
+ }
+}