summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdriaan Moors <adriaan.moors@epfl.ch>2009-11-09 20:10:22 +0000
committerAdriaan Moors <adriaan.moors@epfl.ch>2009-11-09 20:10:22 +0000
commitcedd41ba4a14f7f1595057edfeca5437ef674bc3 (patch)
treea1e00f4a9a9c375d65688521f5d00396dc47b0f4 /src
parent7da30bf2d5195d1e7a156680b50167707f7a3d0a (diff)
downloadscala-cedd41ba4a14f7f1595057edfeca5437ef674bc3.tar.gz
scala-cedd41ba4a14f7f1595057edfeca5437ef674bc3.tar.bz2
scala-cedd41ba4a14f7f1595057edfeca5437ef674bc3.zip
fixed bug in implicit resolution that only mani...
fixed bug in implicit resolution that only manifested itself when multiple implicit arguments needed to be resolved and they were intended to instantiate type parameters two problems: - type parameters that could not be inferred where removed from undetparams erroneously - the successfully inferred parameters were not propagated to the the implicit arguments on the right (implicit resolution searches for implicit arguments from left to right, fixing type parameters in the process) this should give the green light for the addition of Zipped to TupleN
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/ast/Trees.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Implicits.scala12
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Infer.scala11
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala14
-rw-r--r--src/library/scala/Tuple2.scala110
5 files changed, 99 insertions, 50 deletions
diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala
index f8f6ee2c55..bff4bd51c3 100644
--- a/src/compiler/scala/tools/nsc/ast/Trees.scala
+++ b/src/compiler/scala/tools/nsc/ast/Trees.scala
@@ -1708,7 +1708,7 @@ trait Trees {
}
}
- class TreeTypeSubstituter(val from: List[Symbol], to: List[Type]) extends Traverser {
+ class TreeTypeSubstituter(val from: List[Symbol], val to: List[Type]) extends Traverser {
val typeSubst = new SubstTypeMap(from, to)
override def traverse(tree: Tree) {
if (tree.tpe ne null) tree.tpe = typeSubst(tree.tpe)
diff --git a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
index 75a6796be6..18831600b7 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Implicits.scala
@@ -431,10 +431,16 @@ self: Analyzer =>
val targs = solvedTypes(tvars, undetParams, undetParams map varianceInType(pt),
false, lubDepth(List(itree2.tpe, pt)))
checkBounds(itree2.pos, NoPrefix, NoSymbol, undetParams, targs, "inferred ") // #2421
- val subst = new TreeTypeSubstituter(undetParams, targs)
+
+ // filter out failures from type inference, don't want to remove them from undetParams!
+ val uninstantiated = new ListBuffer[Symbol]
+ val detargs = adjustTypeArgs(undetParams, targs, pt, uninstantiated)
+ val (okParams, okArgs) = (undetParams zip detargs) filter {case (p, a) => !uninstantiated.contains(p)} unzip
+ // TODO: optimise above line(s?) once `zipped filter` works (oh, the irony! this line is needed to get Zipped to type check...)
+
+ val subst = new TreeTypeSubstituter(okParams, okArgs)
subst traverse itree2
- // todo: remove type params that have been instantiated to Nothing, similar
- // to methTypeArgs
+
val result = new SearchResult(itree2, subst)
if (traceImplicits) println("RESULT = "+result)
// println("RESULT = "+itree+"///"+itree1+"///"+itree2)//DEBUG
diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
index 3e83ecf272..8b600bfd90 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala
@@ -587,9 +587,15 @@ trait Infer {
* and treat them as uninstantiated parameters instead.
* Map T* entries to Seq[T].
*/
- def adjustTypeArgs(tparams: List[Symbol], targs: List[Type], restpe: Type, uninstantiated: ListBuffer[Symbol]): List[Type] =
+ def adjustTypeArgs(tparams: List[Symbol], targs: List[Type], restpe: Type, uninstantiated: ListBuffer[Symbol]): List[Type] = {
+ @inline def covariantOrNotContained(variance: Int) =
+ ((variance & COVARIANT) == 0) || // tparam occurred covariantly
+ (variance == VARIANCES) // tparam did not occur
+
List.map2(tparams, targs) {(tparam, targ) =>
- if (targ.typeSymbol == NothingClass && (restpe == WildcardType || (varianceInType(restpe)(tparam) & COVARIANT) == 0)) {
+ if (targ.typeSymbol == NothingClass &&
+ ( restpe == WildcardType
+ || covariantOrNotContained(varianceInType(restpe)(tparam)))) {
uninstantiated += tparam
tparam.tpeHK //@M tparam.tpe was wrong: we only want the type constructor,
// not the type constructor applied to dummy arguments
@@ -602,6 +608,7 @@ trait Infer {
targ.widen
}
}
+ }
/** Return inferred type arguments, given type parameters, formal parameters,
* argument types, result type and expected result type.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 619f5324be..50627268c8 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -172,7 +172,19 @@ trait Typers { self: Analyzer =>
def applyImplicitArgs(fun: Tree): Tree = fun.tpe match {
case MethodType(params, _) =>
var positional = true
- val argResults = params map (p => inferImplicit(fun, p.tpe, true, false, context))
+ val argResultsBuff = new ListBuffer[SearchResult]()
+
+ // apply the substitutions (undet type param -> type) that were determined
+ // by implicit resolution of implicit arguments on the left of this argument
+ for(param <- params) {
+ var paramTp = param.tpe
+ for(ar <- argResultsBuff)
+ paramTp = paramTp.subst(ar.subst.from, ar.subst.to)
+
+ argResultsBuff += inferImplicit(fun, paramTp, true, false, context)
+ }
+
+ val argResults = argResultsBuff.toList
val args = argResults.zip(params) flatMap {
case (arg, param) =>
if (arg != SearchFailure) {
diff --git a/src/library/scala/Tuple2.scala b/src/library/scala/Tuple2.scala
index a7519bef77..9835e8505d 100644
--- a/src/library/scala/Tuple2.scala
+++ b/src/library/scala/Tuple2.scala
@@ -12,9 +12,8 @@
package scala
-import annotation.unchecked.uncheckedVariance
-import scala.collection.generic.GenericTraversableTemplate
-import scala.collection.mutable.Builder
+import scala.collection.{TraversableLike, Traversable, IterableLike}
+import scala.collection.generic.CanBuildFrom
/** Tuple2 is the canonical representation of a @see Product2
@@ -30,55 +29,80 @@ case class Tuple2[+T1, +T2](_1:T1, _2:T2) extends Product2[T1, T2] {
/** Swap the elements of the tuple */
def swap: Tuple2[T2,T1] = Tuple2(_2, _1)
-/*
- type Traverserable[CC[X] <: Traversable[X], X] = GenericTraversableTemplate[X, CC] with Iterable[X]
+ def zipped[Repr1, El1, Repr2, El2](implicit w1: T1 <:< TraversableLike[El1, Repr1], w2: T2 <:< IterableLike[El2, Repr2]): Zipped[Repr1, El1, Repr2, El2]
+ = new Zipped[Repr1, El1, Repr2, El2](_1, _2)
- // TODO: benchmark factored version vs inlining forall2 everywhere (specialisation?)
- // factor further? (use fold2)
- // must use <:< instead of =>, otherwise bogus any2stringadd conversion is also eligible (in case of type errors)
+ class Zipped[+Repr1, +El1, +Repr2, +El2](coll1: TraversableLike[El1, Repr1], coll2: IterableLike[El2, Repr2]) { // coll2: IterableLike for filter
+ def it: (Repr1, Repr2) = (coll1.repr, coll2.repr) // TODO: do we want this? what should its name be?
+ def map[B, To](f: (El1, El2) => B)(implicit cbf: CanBuildFrom[Repr1, B, To]): To = {
+ val b = cbf(coll1.repr)
+ val elems2 = coll2.iterator
- def forall2[CC[X] <: Traverserable[CC, X], A1, A2](f: (A1, A2) => Boolean)(implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): Boolean = {
- val it1 = _1.iterator
- val it2 = _2.iterator
- var res = true
- while (res && it1.hasNext && it2.hasNext)
- res = f(it1.next, it2.next)
- res
- }
+ for(el1 <- coll1)
+ if(elems2.hasNext)
+ b += f(el1, elems2.next)
- def exists2[CC[X] <: Traverserable[CC, X], A1, A2](f: (A1, A2) => Boolean)(implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): Boolean = {
- val it1 = _1.iterator
- val it2 = _2.iterator
- var res = false
- while (!res && it1.hasNext && it2.hasNext)
- res = f(it1.next, it2.next)
- res
- }
+ b.result
+ }
- def foreach2[CC[X] <: Traverserable[CC, X], A1, A2, U](f: (A1, A2) => U)(implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): Unit
- = forall2[CC, A1, A2]{(x, y) => f(x, y); true} // XXX: remove type args and fix crash in type infer
+ def flatMap[B, To](f: (El1, El2) => Traversable[B])(implicit cbf: CanBuildFrom[Repr1, B, To]): To = {
+ val b = cbf(coll1.repr)
+ val elems2 = coll2.iterator
- def build2[CC[X] <: Traverserable[CC, X], A1, A2, B](f: Builder[B, CC[B]] => (A1, A2) => Unit)(implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): CC[B] = {
- val b = _1.genericBuilder[B]
- foreach2[CC, A1, A2, Unit](f(b)) // XXX: remove type args and fix crash in type infer
- b.result
- }
+ for(el1 <- coll1)
+ if(elems2.hasNext)
+ b ++= f(el1, elems2.next)
- def zip2[CC[X] <: Traverserable[CC, X], A1, A2](implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): CC[(A1, A2)]
- = build2[CC, A1, A2, (A1, A2)]{b => (x, y) => // XXX: remove type args and fix crash in type infer
- b += Tuple2(x, y)
- }
+ b.result
+ }
- def map2[CC[X] <: Traverserable[CC, X], A1, A2, B](f: (A1, A2) => B)(implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): CC[B]
- = build2[CC, A1, A2, B]{b => (x, y) => // XXX: remove type args and fix crash in type infer
- b += f(x, y)
- }
+ def filter[To1, To2](f: (El1, El2) => Boolean)(implicit cbf1: CanBuildFrom[Repr1, El1, To1], cbf2: CanBuildFrom[Repr2, El2, To2]): (To1, To2) = {
+ val b1 = cbf1(coll1.repr)
+ val b2 = cbf2(coll2.repr)
+ val elems2 = coll2.iterator
- def flatMap2[CC[X] <: Traverserable[CC, X], A1, A2, B](f: (A1, A2) => CC[B])(implicit fst: T1 <:< CC[A1], snd: T2 <:< Traverserable[Iterable, A2]/*CC[A2] does not work*/): CC[B]
- = build2[CC, A1, A2, B]{b => (x, y) => // XXX: remove type args and fix crash in type infer
- b ++= f(x, y)
+ for(el1 <- coll1) {
+ if(elems2.hasNext) {
+ val el2 = elems2.next
+ if(f(el1, el2)) {
+ b1 += el1
+ b2 += el2
+ }
+ }
}
-*/
+ (b1.result, b2.result)
+ }
+
+ def exists(f: (El1, El2) => Boolean): Boolean = {
+ var acc = false
+ val elems2 = coll2.iterator
+
+ for(el1 <- coll1)
+ if(!acc && elems2.hasNext)
+ acc = f(el1, elems2.next)
+
+ acc
+ }
+
+ def forall(f: (El1, El2) => Boolean): Boolean = {
+ var acc = true
+ val elems2 = coll2.iterator
+
+ for(el1 <- coll1)
+ if(acc && elems2.hasNext)
+ acc = f(el1, elems2.next)
+
+ acc
+ }
+
+ def foreach[U](f: (El1, El2) => U): Unit = {
+ val elems2 = coll2.iterator
+
+ for(el1 <- coll1)
+ if(elems2.hasNext)
+ f(el1, elems2.next)
+ }
+ }
}