summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2012-05-03 23:11:05 -0700
committerPaul Phillips <paulp@improving.org>2012-05-04 01:22:23 -0700
commit01f6ed8e22d02811fe62b9183d9f84bdda5ede4b (patch)
tree6cc9b5a4847ba7940ddd8313a1a906b06024b5bf
parentaad6deae7204a7fc95b59ede61b188bb62f51188 (diff)
downloadscala-01f6ed8e22d02811fe62b9183d9f84bdda5ede4b.tar.gz
scala-01f6ed8e22d02811fe62b9183d9f84bdda5ede4b.tar.bz2
scala-01f6ed8e22d02811fe62b9183d9f84bdda5ede4b.zip
Fix for one of the oldest open soundness bugs.
Closes SI-963, since it was one of my random 30 it won the prize. The trick after adding the stability check (which has been sitting there commented out for 3+ years) was that implicit search depended on the wrongness, because memberWildcardType would create scopes with members of the form ?{ val name: tp } And since a def shouldn't match that, fixing it broke everything until I flipped it around: memberWildcardType should be seeking ?{ def name: tp } It could also search for a mutable value: the relevant quality is that it not be stable so it doesn't have a tighter type than the members it hopes to match.
-rw-r--r--src/compiler/scala/reflect/internal/Types.scala17
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala4
-rw-r--r--test/files/buildmanager/t2556_3/t2556_3.check4
-rw-r--r--test/files/neg/logImplicits.check8
-rw-r--r--test/files/neg/t963.check12
-rw-r--r--test/files/neg/t963.scala18
6 files changed, 47 insertions, 16 deletions
diff --git a/src/compiler/scala/reflect/internal/Types.scala b/src/compiler/scala/reflect/internal/Types.scala
index 66657c4412..09e7303b90 100644
--- a/src/compiler/scala/reflect/internal/Types.scala
+++ b/src/compiler/scala/reflect/internal/Types.scala
@@ -5719,14 +5719,15 @@ trait Types extends api.Types { self: SymbolTable =>
val info1 = tp1.memberInfo(sym1)
val info2 = tp2.memberInfo(sym2).substThis(tp2.typeSymbol, tp1)
//System.out.println("specializes "+tp1+"."+sym1+":"+info1+sym1.locationString+" AND "+tp2+"."+sym2+":"+info2)//DEBUG
- sym2.isTerm && (info1 <:< info2) /*&& (!sym2.isStable || sym1.isStable) */ ||
- sym2.isAbstractType && {
- val memberTp1 = tp1.memberType(sym1)
- // println("kinds conform? "+(memberTp1, tp1, sym2, kindsConform(List(sym2), List(memberTp1), tp2, sym2.owner)))
- info2.bounds.containsType(memberTp1) &&
- kindsConform(List(sym2), List(memberTp1), tp1, sym1.owner)
- } ||
- sym2.isAliasType && tp2.memberType(sym2).substThis(tp2.typeSymbol, tp1) =:= tp1.memberType(sym1) //@MAT ok
+ ( sym2.isTerm && (info1 <:< info2) && (!sym2.isStable || sym1.isStable)
+ || sym2.isAbstractType && {
+ val memberTp1 = tp1.memberType(sym1)
+ // println("kinds conform? "+(memberTp1, tp1, sym2, kindsConform(List(sym2), List(memberTp1), tp2, sym2.owner)))
+ info2.bounds.containsType(memberTp1) &&
+ kindsConform(List(sym2), List(memberTp1), tp1, sym1.owner)
+ }
+ || sym2.isAliasType && tp2.memberType(sym2).substThis(tp2.typeSymbol, tp1) =:= tp1.memberType(sym1) //@MAT ok
+ )
}
/** A function implementing `tp1` matches `tp2`. */
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 0d7ef71193..787d7af136 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -214,13 +214,13 @@ trait Implicits {
override def hashCode = 1
}
- /** A constructor for types ?{ name: tp }, used in infer view to member
+ /** A constructor for types ?{ def/type name: tp }, used in infer view to member
* searches.
*/
def memberWildcardType(name: Name, tp: Type) = {
val result = refinedType(List(WildcardType), NoSymbol)
name match {
- case x: TermName => result.typeSymbol.newValue(x) setInfoAndEnter tp
+ case x: TermName => result.typeSymbol.newMethod(x) setInfoAndEnter tp
case x: TypeName => result.typeSymbol.newAbstractType(x) setInfoAndEnter tp
}
result
diff --git a/test/files/buildmanager/t2556_3/t2556_3.check b/test/files/buildmanager/t2556_3/t2556_3.check
index 37808d2b31..34f90f7f9b 100644
--- a/test/files/buildmanager/t2556_3/t2556_3.check
+++ b/test/files/buildmanager/t2556_3/t2556_3.check
@@ -9,10 +9,10 @@ invalidate B.scala because it references invalid (no longer inherited) definitio
compiling Set(B.scala, C.scala)
B.scala:3: error: type mismatch;
found : C
- required: ?{val x: ?}
+ required: ?{def x: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method any2Ensuring in object Predef of type [A](x: A)Ensuring[A]
and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]
- are possible conversion functions from C to ?{val x: ?}
+ are possible conversion functions from C to ?{def x: ?}
println( (new C).x )
^
diff --git a/test/files/neg/logImplicits.check b/test/files/neg/logImplicits.check
index d98422dacb..54afc6f86d 100644
--- a/test/files/neg/logImplicits.check
+++ b/test/files/neg/logImplicits.check
@@ -1,16 +1,16 @@
-logImplicits.scala:2: applied implicit conversion from xs.type to ?{val size: ?} = implicit def byteArrayOps(xs: Array[Byte]): scala.collection.mutable.ArrayOps[Byte]
+logImplicits.scala:2: applied implicit conversion from xs.type to ?{def size: ?} = implicit def byteArrayOps(xs: Array[Byte]): scala.collection.mutable.ArrayOps[Byte]
def f(xs: Array[Byte]) = xs.size
^
-logImplicits.scala:7: applied implicit conversion from String("abc") to ?{val map: ?} = implicit def augmentString(x: String): scala.collection.immutable.StringOps
+logImplicits.scala:7: applied implicit conversion from String("abc") to ?{def map: ?} = implicit def augmentString(x: String): scala.collection.immutable.StringOps
def f = "abc" map (_ + 1)
^
logImplicits.scala:15: inferred view from String("abc") to Int = C.this.convert:(p: String("abc"))Int
math.max(122, x: Int)
^
-logImplicits.scala:19: applied implicit conversion from Int(1) to ?{val ->: ?} = implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A]
+logImplicits.scala:19: applied implicit conversion from Int(1) to ?{def ->: ?} = implicit def any2ArrowAssoc[A](x: A): ArrowAssoc[A]
def f = (1 -> 2) + "c"
^
-logImplicits.scala:19: applied implicit conversion from (Int, Int) to ?{val +: ?} = implicit def any2stringadd(x: Any): scala.runtime.StringAdd
+logImplicits.scala:19: applied implicit conversion from (Int, Int) to ?{def +: ?} = implicit def any2stringadd(x: Any): scala.runtime.StringAdd
def f = (1 -> 2) + "c"
^
logImplicits.scala:22: error: class Un needs to be abstract, since method unimplemented is not defined
diff --git a/test/files/neg/t963.check b/test/files/neg/t963.check
new file mode 100644
index 0000000000..1f2d0687b3
--- /dev/null
+++ b/test/files/neg/t963.check
@@ -0,0 +1,12 @@
+t963.scala:14: error: stable identifier required, but Test.this.y3.x found.
+ val w3 : y3.x.type = y3.x
+ ^
+t963.scala:17: error: stable identifier required, but Test.this.y4.x found.
+ val w4 : y4.x.type = y4.x
+ ^
+t963.scala:10: error: type mismatch;
+ found : Object{def x: Integer}
+ required: AnyRef{val x: Integer}
+ val y2 : { val x : java.lang.Integer } = new { def x = new java.lang.Integer(r.nextInt) }
+ ^
+three errors found
diff --git a/test/files/neg/t963.scala b/test/files/neg/t963.scala
new file mode 100644
index 0000000000..0cc2034299
--- /dev/null
+++ b/test/files/neg/t963.scala
@@ -0,0 +1,18 @@
+import scala.util.Random
+
+// Only y1 (val/val) should actually compile.
+object Test {
+ val r = new Random()
+
+ val y1 : { val x : java.lang.Integer } = new { val x = new java.lang.Integer(r.nextInt) }
+ val w1 : y1.x.type = y1.x
+
+ val y2 : { val x : java.lang.Integer } = new { def x = new java.lang.Integer(r.nextInt) }
+ val w2 : y2.x.type = y2.x
+
+ val y3 : { def x : java.lang.Integer } = new { val x = new java.lang.Integer(r.nextInt) }
+ val w3 : y3.x.type = y3.x
+
+ val y4 : { def x : java.lang.Integer } = new { def x = new java.lang.Integer(r.nextInt) }
+ val w4 : y4.x.type = y4.x
+}