diff options
author | Adriaan Moors <adriaan.moors@epfl.ch> | 2012-03-06 15:58:58 +0100 |
---|---|---|
committer | Adriaan Moors <adriaan.moors@epfl.ch> | 2012-03-09 09:10:38 +0100 |
commit | 29bcadefb451bbf546e6f763027dac16f5b6f51b (patch) | |
tree | ba825b7dd0d3a1c8ed286a3275bcc1c17ff77cb9 /src/library | |
parent | 0cffdf38d9e2d88e66d8649d317f8815716b2748 (diff) | |
download | scala-29bcadefb451bbf546e6f763027dac16f5b6f51b.tar.gz scala-29bcadefb451bbf546e6f763027dac16f5b6f51b.tar.bz2 scala-29bcadefb451bbf546e6f763027dac16f5b6f51b.zip |
SI-5189 fixed: safe type infer for constr pattern
several fixes to the standard library due to
- the safer type checker this fix gives us (thus, some casts had to be inserted)
- SI-5548
- type inference gets a bit more complicated, it needs help (chainl1 in combinator.Parsers)
To deal with the type slack between actual (run-time) types and statically known
types, for each abstract type T, reflect its variance as a skolem that is
upper-bounded by T (covariant position), or lower-bounded by T (contravariant).
Consider the following example:
class AbsWrapperCov[+A]
case class Wrapper[B](x: Wrapped[B]) extends AbsWrapperCov[B]
def unwrap[T](x: AbsWrapperCov[T]): Wrapped[T] = x match {
case Wrapper(wrapped) =>
// Wrapper's type parameter must not be assumed to be equal to T,
// it's *upper-bounded* by it
wrapped // : Wrapped[_ <: T]
}
this method should type check if and only if Wrapped is covariant in its type
parameter
before inferring Wrapper's type parameter B from x's type AbsWrapperCov[T], we must
take into account that x's actual type is:
AbsWrapperCov[Tactual] forSome {type Tactual <: T}
since AbsWrapperCov is covariant in A -- in other words, we must not assume we know
T exactly, all we know is its upper bound
since method application is the only way to generate this slack between run-time and
compile-time types (TODO: right!?), we can simply replace skolems that represent
method type parameters as seen from the method's body by other skolems that are
(upper/lower)-bounded by that type-parameter skolem (depending on the variance
position of the skolem in the statically assumed type of the scrutinee, pt)
this type slack is introduced by adaptConstrPattern: before it calls
inferConstructorInstance, it creates a new context that holds the new existential
skolems
the context created by adaptConstrPattern must not be a CaseDef, since that
confuses instantiateTypeVar and the whole pushTypeBounds/restoreTypeBounds dance
(CaseDef contexts remember the bounds of the type params that we clobbered
during GADT typing)
typedCase deskolemizes the existential skolems back to the method skolems,
since they don't serve any further purpose (except confusing the old pattern
matcher)
typedCase is now better at finding that context (using nextEnclosing)
Diffstat (limited to 'src/library')
4 files changed, 16 insertions, 17 deletions
diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala index d5011fc6aa..50919e506a 100644 --- a/src/library/scala/collection/JavaConversions.scala +++ b/src/library/scala/collection/JavaConversions.scala @@ -69,7 +69,7 @@ object JavaConversions { * @return A Java Iterator view of the argument. */ implicit def asJavaIterator[A](it: Iterator[A]): ju.Iterator[A] = it match { - case JIteratorWrapper(wrapped) => wrapped + case JIteratorWrapper(wrapped) => wrapped.asInstanceOf[ju.Iterator[A]] case _ => IteratorWrapper(it) } @@ -87,7 +87,7 @@ object JavaConversions { * @return A Java Enumeration view of the argument. */ implicit def asJavaEnumeration[A](it: Iterator[A]): ju.Enumeration[A] = it match { - case JEnumerationWrapper(wrapped) => wrapped + case JEnumerationWrapper(wrapped) => wrapped.asInstanceOf[ju.Enumeration[A]] case _ => IteratorWrapper(it) } @@ -105,7 +105,7 @@ object JavaConversions { * @return A Java Iterable view of the argument. */ implicit def asJavaIterable[A](i: Iterable[A]): jl.Iterable[A] = i match { - case JIterableWrapper(wrapped) => wrapped + case JIterableWrapper(wrapped) => wrapped.asInstanceOf[jl.Iterable[A]] case _ => IterableWrapper(i) } @@ -121,7 +121,7 @@ object JavaConversions { * @return A Java Collection view of the argument. */ implicit def asJavaCollection[A](it: Iterable[A]): ju.Collection[A] = it match { - case JCollectionWrapper(wrapped) => wrapped + case JCollectionWrapper(wrapped) => wrapped.asInstanceOf[ju.Collection[A]] case _ => new IterableWrapper(it) } @@ -179,7 +179,7 @@ object JavaConversions { * @return A Java List view of the argument. */ implicit def seqAsJavaList[A](seq: Seq[A]): ju.List[A] = seq match { - case JListWrapper(wrapped) => wrapped + case JListWrapper(wrapped) => wrapped.asInstanceOf[ju.List[A]] case _ => new SeqWrapper(seq) } @@ -286,7 +286,7 @@ object JavaConversions { */ implicit def mapAsJavaMap[A, B](m: Map[A, B]): ju.Map[A, B] = m match { //case JConcurrentMapWrapper(wrapped) => wrapped - case JMapWrapper(wrapped) => wrapped + case JMapWrapper(wrapped) => wrapped.asInstanceOf[ju.Map[A, B]] case _ => new MapWrapper(m) } diff --git a/src/library/scala/collection/immutable/IntMap.scala b/src/library/scala/collection/immutable/IntMap.scala index dd6b066878..3c9c0c2f24 100644 --- a/src/library/scala/collection/immutable/IntMap.scala +++ b/src/library/scala/collection/immutable/IntMap.scala @@ -353,19 +353,19 @@ extends AbstractMap[Int, T] def unionWith[S >: T](that : IntMap[S], f : (Int, S, S) => S) : IntMap[S] = (this, that) match{ case (IntMap.Bin(p1, m1, l1, r1), that@(IntMap.Bin(p2, m2, l2, r2))) => if (shorter(m1, m2)) { - if (!hasMatch(p2, p1, m1)) join(p1, this, p2, that); + if (!hasMatch(p2, p1, m1)) join[S](p1, this, p2, that); // TODO: remove [S] when SI-5548 is fixed else if (zero(p2, m1)) IntMap.Bin(p1, m1, l1.unionWith(that, f), r1); else IntMap.Bin(p1, m1, l1, r1.unionWith(that, f)); } else if (shorter(m2, m1)){ - if (!hasMatch(p1, p2, m2)) join(p1, this, p2, that); + if (!hasMatch(p1, p2, m2)) join[S](p1, this, p2, that); // TODO: remove [S] when SI-5548 is fixed else if (zero(p1, m2)) IntMap.Bin(p2, m2, this.unionWith(l2, f), r2); else IntMap.Bin(p2, m2, l2, this.unionWith(r2, f)); } else { if (p1 == p2) IntMap.Bin(p1, m1, l1.unionWith(l2,f), r1.unionWith(r2, f)); - else join(p1, this, p2, that); + else join[S](p1, this, p2, that); // TODO: remove [S] when SI-5548 is fixed } - case (IntMap.Tip(key, value), x) => x.updateWith(key, value, (x, y) => f(key, y, x)); + case (IntMap.Tip(key, value), x) => x.updateWith[S](key, value, (x, y) => f(key, y, x)); case (x, IntMap.Tip(key, value)) => x.updateWith[S](key, value, (x, y) => f(key, x, y)); case (IntMap.Nil, x) => x; case (x, IntMap.Nil) => x; diff --git a/src/library/scala/collection/immutable/LongMap.scala b/src/library/scala/collection/immutable/LongMap.scala index 963ddac762..11b5d1e311 100644 --- a/src/library/scala/collection/immutable/LongMap.scala +++ b/src/library/scala/collection/immutable/LongMap.scala @@ -349,19 +349,19 @@ extends AbstractMap[Long, T] def unionWith[S >: T](that : LongMap[S], f : (Long, S, S) => S) : LongMap[S] = (this, that) match{ case (LongMap.Bin(p1, m1, l1, r1), that@(LongMap.Bin(p2, m2, l2, r2))) => if (shorter(m1, m2)) { - if (!hasMatch(p2, p1, m1)) join(p1, this, p2, that); + if (!hasMatch(p2, p1, m1)) join[S](p1, this, p2, that); // TODO: remove [S] when SI-5548 is fixed else if (zero(p2, m1)) LongMap.Bin(p1, m1, l1.unionWith(that, f), r1); else LongMap.Bin(p1, m1, l1, r1.unionWith(that, f)); } else if (shorter(m2, m1)){ - if (!hasMatch(p1, p2, m2)) join(p1, this, p2, that); + if (!hasMatch(p1, p2, m2)) join[S](p1, this, p2, that); // TODO: remove [S] when SI-5548 is fixed else if (zero(p1, m2)) LongMap.Bin(p2, m2, this.unionWith(l2, f), r2); else LongMap.Bin(p2, m2, l2, this.unionWith(r2, f)); } else { if (p1 == p2) LongMap.Bin(p1, m1, l1.unionWith(l2,f), r1.unionWith(r2, f)); - else join(p1, this, p2, that); + else join[S](p1, this, p2, that); // TODO: remove [S] when SI-5548 is fixed } - case (LongMap.Tip(key, value), x) => x.updateWith(key, value, (x, y) => f(key, y, x)); + case (LongMap.Tip(key, value), x) => x.updateWith[S](key, value, (x, y) => f(key, y, x)); // TODO: remove [S] when SI-5548 is fixed case (x, LongMap.Tip(key, value)) => x.updateWith[S](key, value, (x, y) => f(key, x, y)); case (LongMap.Nil, x) => x; case (x, LongMap.Nil) => x; diff --git a/src/library/scala/util/parsing/combinator/Parsers.scala b/src/library/scala/util/parsing/combinator/Parsers.scala index 27e9112fce..9aaf0aeb54 100644 --- a/src/library/scala/util/parsing/combinator/Parsers.scala +++ b/src/library/scala/util/parsing/combinator/Parsers.scala @@ -794,7 +794,7 @@ trait Parsers { */ def chainl1[T, U](first: => Parser[T], p: => Parser[U], q: => Parser[(T, U) => T]): Parser[T] = first ~ rep(q ~ p) ^^ { - case x ~ xs => xs.foldLeft(x){(_, _) match {case (a, f ~ b) => f(a, b)}} + case x ~ xs => xs.foldLeft(x: T){case (a, f ~ b) => f(a, b)} // x's type annotation is needed to deal with changed type inference due to SI-5189 } /** A parser generator that generalises the `rep1sep` generator so that `q`, @@ -812,8 +812,7 @@ trait Parsers { */ def chainr1[T, U](p: => Parser[T], q: => Parser[(T, U) => U], combine: (T, U) => U, first: U): Parser[U] = p ~ rep(q ~ p) ^^ { - case x ~ xs => (new ~(combine, x) :: xs). - foldRight(first){(_, _) match {case (f ~ a, b) => f(a, b)}} + case x ~ xs => (new ~(combine, x) :: xs).foldRight(first){case (f ~ a, b) => f(a, b)} } /** A parser generator for optional sub-phrases. |