summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/Settings.scala1
-rw-r--r--src/compiler/scala/tools/nsc/ast/TreeGen.scala11
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala25
-rw-r--r--test/files/neg/bug997.check13
-rwxr-xr-xtest/files/neg/bug997.scala15
5 files changed, 53 insertions, 12 deletions
diff --git a/src/compiler/scala/tools/nsc/Settings.scala b/src/compiler/scala/tools/nsc/Settings.scala
index b984a97469..848fc8a8f1 100644
--- a/src/compiler/scala/tools/nsc/Settings.scala
+++ b/src/compiler/scala/tools/nsc/Settings.scala
@@ -86,6 +86,7 @@ class Settings(error: String => unit) {
val outdir = StringSetting ("-d", "directory", "Specify where to place generated class files", ".")
val encoding = new StringSetting ("-encoding", "encoding", "Specify character encoding used by source files", encodingDefault) { override def hiddenToIDE = false }
val target = ChoiceSetting ("-target", "Specify which backend to use", List("jvm-1.5", "jvm-1.4", "msil", "cldc"), "jvm-1.4")
+ val checknull = BooleanSetting("-checknull", "Emit warning on selection of nullable reference")
val migrate = BooleanSetting("-migrate", "Assist in migrating from Scala version 1.0")
val assemname = StringSetting ("-o", "file", "Name of the output assembly (only relevant with -target:msil)", "").dependsOn(target, "msil")
val assemrefs = StringSetting ("-r", "path", "List of assemblies referenced by the program (only relevant with -target:msil)", ".").dependsOn(target, "msil")
diff --git a/src/compiler/scala/tools/nsc/ast/TreeGen.scala b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
index 2baea3f4e2..5a2ffbf875 100644
--- a/src/compiler/scala/tools/nsc/ast/TreeGen.scala
+++ b/src/compiler/scala/tools/nsc/ast/TreeGen.scala
@@ -156,10 +156,15 @@ abstract class TreeGen {
def mkAsInstanceOf(value: Tree, tpe: Type): Tree =
mkAsInstanceOf(value, tpe, global.phase.erasedTypes)
- def mkCheckInit(tree: Tree): Tree =
- if (tree.hasSymbol && tree.symbol.tpe <:< NotNullClass.tpe && !tree.symbol.tpe.isNotNull)
+ def mkCheckInit(tree: Tree): Tree = {
+ var tpe = tree.tpe
+ if (tpe == null && tree.hasSymbol) tpe = tree.symbol.tpe
+ if (!global.phase.erasedTypes && settings.checknull.value &&
+ tpe <:< NotNullClass.tpe && !tpe.isNotNull)
mkRuntimeCall(nme.checkInitialized, List(tree))
- else tree
+ else
+ tree
+ }
/** Builds a list with given head and tail. */
def mkNewCons(head: Tree, tail: Tree): Tree =
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 6ef190be69..8044f2ce5d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2011,15 +2011,19 @@ trait Typers requires Analyzer {
case fun1: Tree =>
val fun2 = if (stableApplication) stabilizeFun(fun1, mode, pt) else fun1
if (util.Statistics.enabled) appcnt = appcnt + 1
- if (phase.id <= currentRun.typerPhase.id &&
- fun2.isInstanceOf[Select] &&
- !fun2.tpe.isInstanceOf[ImplicitMethodType] &&
- ((fun2.symbol eq null) || !fun2.symbol.isConstructor) &&
- (mode & (EXPRmode | SNDTRYmode)) == EXPRmode) {
- tryTypedApply(fun2, args)
- } else {
- doTypedApply(tree, fun2, args, mode, pt)
- }
+ val res =
+ if (phase.id <= currentRun.typerPhase.id &&
+ fun2.isInstanceOf[Select] &&
+ !fun2.tpe.isInstanceOf[ImplicitMethodType] &&
+ ((fun2.symbol eq null) || !fun2.symbol.isConstructor) &&
+ (mode & (EXPRmode | SNDTRYmode)) == EXPRmode) {
+ tryTypedApply(fun2, args)
+ } else {
+ doTypedApply(tree, fun2, args, mode, pt)
+ }
+ if (fun2.symbol == Array_apply) typed { atPos(tree.pos) { gen.mkCheckInit(res) } }
+ else res
+
case ex: TypeError =>
fun match {
case Select(qual, name)
@@ -2180,6 +2184,9 @@ trait Typers requires Analyzer {
}
val result = stabilize(checkAccessible(tree1, sym, qual.tpe, qual), qual.tpe, mode, pt)
if (sym.isCaseFactory && !phase.erasedTypes) checkStable(qual)
+ if (!global.phase.erasedTypes && settings.checknull.value &&
+ !(qual.tpe <:< NotNullClass.tpe) && !qual.tpe.isNotNull)
+ unit.warning(tree.pos, "potential null pointer dereference")
result
}
}
diff --git a/test/files/neg/bug997.check b/test/files/neg/bug997.check
new file mode 100644
index 0000000000..ba6dfd94bb
--- /dev/null
+++ b/test/files/neg/bug997.check
@@ -0,0 +1,13 @@
+bug997.scala:7: error: wrong number of arguments for object Foo of type Foo.type
+"x" match { case Foo(a) => Console.println(a) }
+ ^
+bug997.scala:7: error: not found: value a
+"x" match { case Foo(a) => Console.println(a) }
+ ^
+bug997.scala:13: error: wrong number of arguments for object Foo of type Foo.type
+"x" match { case Foo(a, b, c) => Console.println((a,b,c)) }
+ ^
+bug997.scala:13: error: not found: value a
+"x" match { case Foo(a, b, c) => Console.println((a,b,c)) }
+ ^
+four errors found
diff --git a/test/files/neg/bug997.scala b/test/files/neg/bug997.scala
new file mode 100755
index 0000000000..b6897e62df
--- /dev/null
+++ b/test/files/neg/bug997.scala
@@ -0,0 +1,15 @@
+// An extractor with 2 results
+object Foo { def unapply(x : String) = Some(Pair(x, x)) }
+
+object Test extends Application {
+
+// Prints 'x'; ought not to compile (or maybe a should be the Pair?).
+"x" match { case Foo(a) => Console.println(a) }
+
+// Prints '(x,x)' as expected.
+"x" match { case Foo(a, b) => Console.println((a,b)) }
+
+// Gives confusing error 'not found: value c'.
+"x" match { case Foo(a, b, c) => Console.println((a,b,c)) }
+
+}