summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala46
-rw-r--r--test/files/neg/virtpatmat_unreach_select.check4
-rw-r--r--test/files/neg/virtpatmat_unreach_select.flags1
-rw-r--r--test/files/neg/virtpatmat_unreach_select.scala12
-rw-r--r--test/files/pos/t5738.scala8
-rw-r--r--test/files/pos/t5742.scala8
-rw-r--r--test/files/run/t5816.check1
-rw-r--r--test/files/run/t5816.scala17
-rw-r--r--test/files/run/t5840.scala7
-rw-r--r--test/files/run/t5881.check2
-rw-r--r--test/files/run/t5881.scala6
11 files changed, 100 insertions, 12 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
index 68522c727f..4e8f416b16 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternMatching.scala
@@ -1429,6 +1429,12 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// (Select(codegen._asInstanceOf(testedBinder, expectedTp), outer)) OBJ_EQ expectedOuter
// }
+ // TODO: improve, e.g., for constants
+ def sameValue(a: Tree, b: Tree): Boolean = (a eq b) || ((a, b) match {
+ case (_ : Ident, _ : Ident) => a.symbol eq b.symbol
+ case _ => false
+ })
+
// returns (tree, tests), where `tree` will be used to refer to `root` in `tests`
abstract class TreeMakersToConds(val root: Symbol) {
@@ -1476,13 +1482,6 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// patmatDebug("accumSubst: "+ accumSubst)
}
-
- // TODO: improve, e.g., for constants
- def sameValue(a: Tree, b: Tree): Boolean = (a eq b) || ((a, b) match {
- case (_ : Ident, _ : Ident) => a.symbol eq b.symbol
- case _ => false
- })
-
// hashconsing trees (modulo value-equality)
def unique(t: Tree, tpOverride: Type = NoType): Tree =
trees find (a => a.correspondsStructure(t)(sameValue)) match {
@@ -2075,7 +2074,7 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
// a literal constant becomes ConstantType(Constant(v)) when the type allows it (roughly, anyval + string + null)
// equality between variables: SingleType(x) (note that pattern variables cannot relate to each other -- it's always patternVar == nonPatternVar)
object Const {
- def resetUniques() = {_nextTypeId = 0; _nextValueId = 0; uniques.clear()} // patmatDebug("RESET")
+ def resetUniques() = {_nextTypeId = 0; _nextValueId = 0; uniques.clear() ; trees.clear() } // patmatDebug("RESET")
private var _nextTypeId = 0
def nextTypeId = {_nextTypeId += 1; _nextTypeId}
@@ -2093,6 +2092,27 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
uniques(tp) = fresh
fresh
})
+
+ private val trees = collection.mutable.HashSet.empty[Tree]
+
+ // hashconsing trees (modulo value-equality)
+ private[SymbolicMatchAnalysis] def uniqueTpForTree(t: Tree): Type =
+ // a new type for every unstable symbol -- only stable value are uniqued
+ // technically, an unreachable value may change between cases
+ // thus, the failure of a case that matches on a mutable value does not exclude the next case succeeding
+ // (and thuuuuus, the latter case must be considered reachable)
+ if (!t.symbol.isStable) t.tpe.narrow
+ else trees find (a => a.correspondsStructure(t)(sameValue)) match {
+ case Some(orig) =>
+ // patmatDebug("unique: "+ (orig, orig.tpe))
+ orig.tpe
+ case _ =>
+ // duplicate, don't mutate old tree (TODO: use a map tree -> type instead?)
+ val treeWithNarrowedType = t.duplicate setType t.tpe.narrow
+ // patmatDebug("uniqued: "+ (t, t.tpe, treeWithNarrowedType.tpe))
+ trees += treeWithNarrowedType
+ treeWithNarrowedType.tpe
+ }
}
sealed abstract class Const extends AbsConst {
@@ -2181,11 +2201,13 @@ trait PatternMatching extends Transform with TypingTransformers with ast.TreeDSL
case Literal(c) =>
if (c.tpe.typeSymbol == UnitClass) c.tpe
else ConstantType(c)
- case p if p.symbol.isStable =>
+ case Ident(_) if p.symbol.isStable =>
+ // for Idents, can encode uniqueness of symbol as uniqueness of the corresponding singleton type
+ // for Selects, which are handled by the next case, the prefix of the select varies independently of the symbol (see pos/virtpatmat_unreach_select.scala)
singleType(tp.prefix, p.symbol)
- case x =>
- // TODO: better type
- x.tpe.narrow
+ case _ =>
+ // patmatDebug("unique type for "+(p, Const.uniqueTpForTree(p)))
+ Const.uniqueTpForTree(p)
}
val toString =
diff --git a/test/files/neg/virtpatmat_unreach_select.check b/test/files/neg/virtpatmat_unreach_select.check
new file mode 100644
index 0000000000..3771971020
--- /dev/null
+++ b/test/files/neg/virtpatmat_unreach_select.check
@@ -0,0 +1,4 @@
+virtpatmat_unreach_select.scala:10: error: unreachable code
+ case WARNING.id => // unreachable
+ ^
+one error found
diff --git a/test/files/neg/virtpatmat_unreach_select.flags b/test/files/neg/virtpatmat_unreach_select.flags
new file mode 100644
index 0000000000..85d8eb2ba2
--- /dev/null
+++ b/test/files/neg/virtpatmat_unreach_select.flags
@@ -0,0 +1 @@
+-Xfatal-warnings
diff --git a/test/files/neg/virtpatmat_unreach_select.scala b/test/files/neg/virtpatmat_unreach_select.scala
new file mode 100644
index 0000000000..c46ff15453
--- /dev/null
+++ b/test/files/neg/virtpatmat_unreach_select.scala
@@ -0,0 +1,12 @@
+class Test {
+ object severity extends Enumeration
+ class Severity(val id: Int) extends severity.Value
+ val INFO = new Severity(0)
+ val WARNING = new Severity(1)
+
+ (0: Int) match {
+ case WARNING.id =>
+ case INFO.id => // reachable
+ case WARNING.id => // unreachable
+ }
+}
diff --git a/test/files/pos/t5738.scala b/test/files/pos/t5738.scala
new file mode 100644
index 0000000000..b8755ed66e
--- /dev/null
+++ b/test/files/pos/t5738.scala
@@ -0,0 +1,8 @@
+import scala.reflect.runtime.universe._
+
+object Test extends App {
+ def f[T](a: T, b: T) = {
+ reify(a.toString + b)
+ reify(a + b.toString)
+ }
+} \ No newline at end of file
diff --git a/test/files/pos/t5742.scala b/test/files/pos/t5742.scala
new file mode 100644
index 0000000000..3d3125b5d3
--- /dev/null
+++ b/test/files/pos/t5742.scala
@@ -0,0 +1,8 @@
+import scala.reflect.runtime.universe._
+
+object Test extends App {
+ def foo[T](a: T) = reify {
+ val x1 = a
+ val x2 = reify(a)
+ }
+} \ No newline at end of file
diff --git a/test/files/run/t5816.check b/test/files/run/t5816.check
new file mode 100644
index 0000000000..920b64a50d
--- /dev/null
+++ b/test/files/run/t5816.check
@@ -0,0 +1 @@
+5.+(Test.this.y)
diff --git a/test/files/run/t5816.scala b/test/files/run/t5816.scala
new file mode 100644
index 0000000000..f0279e5703
--- /dev/null
+++ b/test/files/run/t5816.scala
@@ -0,0 +1,17 @@
+import scala.reflect.runtime.universe._
+import scala.reflect.runtime.{currentMirror => cm}
+import scala.tools.reflect.ToolBox
+
+object Test extends App {
+ val toolbox = cm.mkToolBox()
+
+ def printSource[T](expr: Expr[T]) {
+ val ttree = toolbox typeCheck expr.tree
+ println(ttree.toString)
+ }
+
+ var y = 3
+ printSource(reify {
+ 5 + y
+ })
+} \ No newline at end of file
diff --git a/test/files/run/t5840.scala b/test/files/run/t5840.scala
new file mode 100644
index 0000000000..da036d5122
--- /dev/null
+++ b/test/files/run/t5840.scala
@@ -0,0 +1,7 @@
+import scala.reflect.runtime.universe._
+
+object Test extends App {
+ reify {
+ class C[T <: String with Singleton]
+ }
+} \ No newline at end of file
diff --git a/test/files/run/t5881.check b/test/files/run/t5881.check
new file mode 100644
index 0000000000..477fb935a8
--- /dev/null
+++ b/test/files/run/t5881.check
@@ -0,0 +1,2 @@
+ClassTag[class scala.collection.immutable.List]
+ClassTag[class scala.collection.immutable.List]
diff --git a/test/files/run/t5881.scala b/test/files/run/t5881.scala
new file mode 100644
index 0000000000..01bee29181
--- /dev/null
+++ b/test/files/run/t5881.scala
@@ -0,0 +1,6 @@
+import scala.reflect.ClassTag
+
+object Test extends App {
+ println(implicitly[ClassTag[List[T forSome {type T <: List[T]}]]])
+ println(implicitly[ClassTag[List[Any]]])
+} \ No newline at end of file