summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2013-09-30 12:11:49 -0700
committerPaul Phillips <paulp@improving.org>2013-10-01 20:26:54 -0700
commit95d5554b9a263e3eb060c181463234f3e79864ab (patch)
treeab5d0185f0096d723403c14209fe638d337463ec
parentbef9e52d7337dafcc1f507ff1d93241f12f7c6d9 (diff)
downloadscala-95d5554b9a263e3eb060c181463234f3e79864ab.tar.gz
scala-95d5554b9a263e3eb060c181463234f3e79864ab.tar.bz2
scala-95d5554b9a263e3eb060c181463234f3e79864ab.zip
SI-7886 unsoundness in pattern matcher.
I tracked down what was behind the issue described here: // TODO: fix the illegal type bound in pos/t602 -- type inference // messes up before we get here: /*override def equals(x$1: Any): Boolean = ... // Span[Any] --> Any is not a legal type argument for Span! val o5: Option[com.mosol.sl.Span[Any]] = */ ...which led straight to the unsoundness seen in neg/t7886. It is dangerous to have an expected type of "Any" because the type system will blithely ignore kind errors, since "Any" can absorb anything. The consequence in this instance was that inferring the case constructor for a type like Foo[T <: Bound] if done with expected type Any, this would come up with Foo[Any]. I altered it to use expected type Foo[T], which lets the dummy type parameter survive to carry the bound forward and restores sense to the inference. The before/after output for -Xprint:patmat on pos/t602.scala is: 15c15 < if (x1.isInstanceOf[com.mosol.sl.Span[Any]]) --- > if (x1.isInstanceOf[com.mosol.sl.Span[K]]) 17c17 < <synthetic> val x2: com.mosol.sl.Span[Any] = \ (x1.asInstanceOf[com.mosol.sl.Span[Any]]: com.mosol.sl.Span[Any]); --- > <synthetic> val x2: com.mosol.sl.Span[K] = \ (x1.asInstanceOf[com.mosol.sl.Span[K]]: com.mosol.sl.Span[K]); 19,20c19,20 < val low$0: Option[Any] = x2.low; < val high$0: Option[Any] = x2.high; --- > val low$0: Option[K] = x2.low; > val high$0: Option[K] = x2.high; A file in the library depended (needlessly) on the unsoundness. It was easy to fix but reminds us this may affect existing code.
-rw-r--r--src/actors/scala/actors/remote/Proxy.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala5
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala8
-rw-r--r--test/files/neg/t4818.check2
-rw-r--r--test/files/neg/t5189.check4
-rw-r--r--test/files/neg/t6829.check4
-rw-r--r--test/files/neg/t7886.check6
-rw-r--r--test/files/neg/t7886.scala22
8 files changed, 41 insertions, 12 deletions
diff --git a/src/actors/scala/actors/remote/Proxy.scala b/src/actors/scala/actors/remote/Proxy.scala
index 73af1edeec..43a43ac99c 100644
--- a/src/actors/scala/actors/remote/Proxy.scala
+++ b/src/actors/scala/actors/remote/Proxy.scala
@@ -118,7 +118,7 @@ private[remote] case class Apply0(rfun: Function2[AbstractActor, Proxy, Unit])
*/
private[remote] class DelegateActor(creator: Proxy, node: Node, name: Symbol, kernel: NetKernel) extends Actor {
var channelMap = new mutable.HashMap[Symbol, OutputChannel[Any]]
- var sessionMap = new mutable.HashMap[OutputChannel[Any], Symbol]
+ var sessionMap = new mutable.HashMap[OutputChannel[_], Symbol]
def act() {
Actor.loop {
diff --git a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
index ab19660da5..2be031a66f 100644
--- a/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
+++ b/src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala
@@ -500,11 +500,6 @@ trait MatchTranslation {
// U must have N members _1,..., _N -- the _i are type checked, call their type Ti,
// for now only used for case classes -- pretending there's an unapplyProd that's the identity (and don't call it)
class ExtractorCallProd(val fun: Tree, val args: List[Tree]) extends ExtractorCall {
- // TODO: fix the illegal type bound in pos/t602 -- type inference messes up before we get here:
- /*override def equals(x$1: Any): Boolean = ...
- val o5: Option[com.mosol.sl.Span[Any]] = // Span[Any] --> Any is not a legal type argument for Span!
- */
-
private def constructorTp = fun.tpe
def isTyped = fun.isTyped
diff --git a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
index 38a3f18bf8..df4dd3d777 100644
--- a/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala
@@ -322,7 +322,13 @@ trait PatternTypers {
*
* see test/files/../t5189*.scala
*/
- private def convertToCaseConstructor(tree: Tree, caseClass: Symbol, pt: Type): Tree = {
+ private def convertToCaseConstructor(tree: Tree, caseClass: Symbol, ptIn: Type): Tree = {
+ // Unsoundness looms for those who infer type parameters with pt=Any. See SI-7886.
+ val pt = (
+ if (ptIn =:= AnyTpe && caseClass.typeParams.nonEmpty)
+ devWarningResult(s"Evading kind-polymorphic expected type for case constructor of $caseClass")(caseClass.tpe_*)
+ else ptIn
+ )
val variantToSkolem = new VariantToSkolemMap
val caseConstructorType = tree.tpe.prefix memberType caseClass memberType caseClass.primaryConstructor
val tree1 = TypeTree(caseConstructorType) setOriginal tree
diff --git a/test/files/neg/t4818.check b/test/files/neg/t4818.check
index a5e15e456b..8a2c024b30 100644
--- a/test/files/neg/t4818.check
+++ b/test/files/neg/t4818.check
@@ -1,6 +1,6 @@
t4818.scala:4: error: type mismatch;
found : Int(5)
- required: Nothing
+ required: A
def f(x: Any) = x match { case Fn(f) => f(5) }
^
one error found
diff --git a/test/files/neg/t5189.check b/test/files/neg/t5189.check
index 7762f465dc..aecc1d11c4 100644
--- a/test/files/neg/t5189.check
+++ b/test/files/neg/t5189.check
@@ -1,6 +1,6 @@
t5189.scala:3: error: type mismatch;
- found : Nothing => Any
+ found : T => U
required: Any => Any
def f(x: Any): Any => Any = x match { case Foo(bar) => bar }
^
-one error found \ No newline at end of file
+one error found
diff --git a/test/files/neg/t6829.check b/test/files/neg/t6829.check
index 7c3c66e0f2..c7c641844e 100644
--- a/test/files/neg/t6829.check
+++ b/test/files/neg/t6829.check
@@ -16,12 +16,12 @@ t6829.scala:49: error: not found: value nextState
val (s,a,s2) = (state,actions(agent),nextState)
^
t6829.scala:50: error: type mismatch;
- found : s.type (with underlying type Any)
+ found : s.type (with underlying type T1)
required: _53.State where val _53: G
val r = rewards(agent).r(s,a,s2)
^
t6829.scala:51: error: type mismatch;
- found : s.type (with underlying type Any)
+ found : s.type (with underlying type T1)
required: _50.State
agent.learn(s,a,s2,r): G#Agent
^
diff --git a/test/files/neg/t7886.check b/test/files/neg/t7886.check
new file mode 100644
index 0000000000..338eee9708
--- /dev/null
+++ b/test/files/neg/t7886.check
@@ -0,0 +1,6 @@
+t7886.scala:10: error: type mismatch;
+ found : Contra[A]
+ required: Contra[Any]
+ case Unravel(m, msg) => g(m)
+ ^
+one error found
diff --git a/test/files/neg/t7886.scala b/test/files/neg/t7886.scala
new file mode 100644
index 0000000000..55d80a0a43
--- /dev/null
+++ b/test/files/neg/t7886.scala
@@ -0,0 +1,22 @@
+trait Covariant[+A]
+trait Contra[-A] { def accept(p: A): Unit }
+trait Invariant[A] extends Covariant[A] with Contra[A]
+
+case class Unravel[A](m: Contra[A], msg: A)
+
+object Test extends Covariant[Any] {
+ def g(m: Contra[Any]): Unit = m accept 5
+ def f(x: Any): Unit = x match {
+ case Unravel(m, msg) => g(m)
+ case _ =>
+ }
+ def main(args: Array[String]) {
+ f(Unravel[String](new Contra[String] { def accept(x: String) = x.length }, ""))
+ }
+}
+// java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
+// at Test$$anon$1.accept(a.scala:18)
+// at Test$.g(a.scala:13)
+// at Test$.f(a.scala:15)
+// at Test$.main(a.scala:18)
+// at Test.main(a.scala)