diff options
author | Paul Phillips <paulp@improving.org> | 2013-09-30 12:11:49 -0700 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2013-10-01 20:26:54 -0700 |
commit | 95d5554b9a263e3eb060c181463234f3e79864ab (patch) | |
tree | ab5d0185f0096d723403c14209fe638d337463ec /src/compiler | |
parent | bef9e52d7337dafcc1f507ff1d93241f12f7c6d9 (diff) | |
download | scala-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.
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/patmat/MatchTranslation.scala | 5 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/PatternTypers.scala | 8 |
2 files changed, 7 insertions, 6 deletions
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 |