summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2011-11-01 17:16:51 +0000
committerMartin Odersky <odersky@gmail.com>2011-11-01 17:16:51 +0000
commitb7b81ca286b1f426cd19befd50fbc513bb82282f (patch)
tree1008c7594c42995b7758b2bb09f87134ac98b2d1
parent69b3cd50923b3f495f1e421e8a4ac505044f3c40 (diff)
downloadscala-b7b81ca286b1f426cd19befd50fbc513bb82282f.tar.gz
scala-b7b81ca286b1f426cd19befd50fbc513bb82282f.tar.bz2
scala-b7b81ca286b1f426cd19befd50fbc513bb82282f.zip
Fixed type unsoundness problem in t5120 and als...
Fixed type unsoundness problem in t5120 and also discovered by roman.kalukiewicz@gmail.com. Fix should be refined further, as I am not convinced we are quite done yet. Review by moors.
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala15
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala2
-rw-r--r--test/files/neg/t3015.check6
-rw-r--r--test/files/neg/t5120.check12
-rw-r--r--test/files/neg/t5120.scala29
5 files changed, 57 insertions, 7 deletions
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index bc739e58a9..c542c818c1 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -560,11 +560,19 @@ trait Types extends api.Types { self: SymbolTable =>
def asSeenFrom(pre: Type, clazz: Symbol): Type =
if (isTrivial || phase.erasedTypes && pre.typeSymbol != ArrayClass) this
else {
+// scala.tools.nsc.util.trace.when(pre.isInstanceOf[ExistentialType])("X "+this+".asSeenfrom("+pre+","+clazz+" = ") {
incCounter(asSeenFromCount)
val start = startTimer(asSeenFromNanos)
val m = new AsSeenFromMap(pre.normalize, clazz)
val tp = m apply this
- val result = existentialAbstraction(m.capturedParams, tp)
+ val tp1 = existentialAbstraction(m.capturedParams, tp)
+ val result: Type =
+ if (m.capturedSkolems.isEmpty) tp1
+ else {
+ val captured = cloneSymbols(m.capturedSkolems)
+ captured foreach (_ setFlag CAPTURED)
+ tp1.substSym(m.capturedSkolems, captured)
+ }
stopTimer(asSeenFromNanos, start)
result
}
@@ -3606,6 +3614,7 @@ A type's typeSymbol should never be inspected directly.
/** A map to compute the asSeenFrom method */
class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap with KeepOnlyTypeConstraints {
+ var capturedSkolems: List[Symbol] = List()
var capturedParams: List[Symbol] = List()
override def mapOver(tree: Tree, giveup: ()=>Nothing): Tree = {
@@ -3679,7 +3688,7 @@ A type's typeSymbol should never be inspected directly.
pre1
}
} else {
- toPrefix(base(pre, clazz).prefix, clazz.owner);
+ toPrefix(base(pre, clazz).prefix, clazz.owner)
}
toPrefix(pre, clazz)
case SingleType(pre, sym) =>
@@ -3752,7 +3761,7 @@ A type's typeSymbol should never be inspected directly.
" gets applied to arguments "+baseargs.mkString("[",",","]")+", phase = "+phase)
}
case ExistentialType(tparams, qtpe) =>
- capturedParams = capturedParams union tparams
+ capturedSkolems = capturedSkolems union tparams
toInstance(qtpe, clazz)
case t =>
throwError
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 976fcc8f7c..32ea3eb3b3 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2841,7 +2841,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
def isLocal(sym: Symbol): Boolean =
if (sym == NoSymbol || sym.isRefinementClass || sym.isLocalDummy) false
else if (owner == NoSymbol) tree exists (defines(_, sym))
- else containsDef(owner, sym) || isRawParameter(sym)
+ else containsDef(owner, sym) || isRawParameter(sym) || ((sym hasFlag EXISTENTIAL) && (sym hasFlag CAPTURED)) // todo refine this
def containsLocal(tp: Type): Boolean =
tp exists (t => isLocal(t.typeSymbol) || isLocal(t.termSymbol))
val normalizeLocals = new TypeMap {
diff --git a/test/files/neg/t3015.check b/test/files/neg/t3015.check
index 6095efc6a7..0b394e23d6 100644
--- a/test/files/neg/t3015.check
+++ b/test/files/neg/t3015.check
@@ -1,11 +1,11 @@
t3015.scala:7: error: scrutinee is incompatible with pattern type;
- found : _$1 where type _$1
+ found : _$1 where type +_$1
required: String
val b(foo) = "foo"
^
t3015.scala:7: error: type mismatch;
- found : _$1(in value foo) where type _$1(in value foo) <: String
- required: (some other)_$1(in value foo) where type (some other)_$1(in value foo)
+ found : String with _$1(in object Test) where type +_$1(in object Test)
+ required: (some other)_$1(in object Test) where type +(some other)_$1(in object Test)
val b(foo) = "foo"
^
two errors found
diff --git a/test/files/neg/t5120.check b/test/files/neg/t5120.check
new file mode 100644
index 0000000000..34d4ebde31
--- /dev/null
+++ b/test/files/neg/t5120.check
@@ -0,0 +1,12 @@
+t5120.scala:11: error: type mismatch;
+ found : Object
+ required: _1
+ List(str, other) foreach (_.x1 = new AnyRef)
+ ^
+t5120.scala:25: error: type mismatch;
+ found : Thread
+ required: h.T
+ (which expands to) _2
+ List(str, num).foreach(h => h.f1 = new Thread())
+ ^
+two errors found
diff --git a/test/files/neg/t5120.scala b/test/files/neg/t5120.scala
new file mode 100644
index 0000000000..f28b2cfb4f
--- /dev/null
+++ b/test/files/neg/t5120.scala
@@ -0,0 +1,29 @@
+class Cell[T](x0: T) {
+ type U = T
+ var x1: U = x0
+}
+
+object Test {
+ val str: Cell[String] = new Cell("a")
+ val other: Cell[Int] = new Cell(0)
+
+ def main(args: Array[String]): Unit = {
+ List(str, other) foreach (_.x1 = new AnyRef)
+ str.x1.length
+ }
+}
+// another way demonstrating the same underlying problem, as reported by roman kalukiewicz
+
+class Holder[_T](_f1 : _T, _f2 : _T) {
+ type T = _T
+ var f1 : T = _f1
+ var f2 : T = _f2
+}
+object Test2 {
+ val str = new Holder("t1", "t2")
+ val num = new Holder(1, 2)
+ List(str, num).foreach(h => h.f1 = new Thread())
+ def main(args: Array[String]) {
+ println(str.f1)
+ }
+}