summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)
+ }
+ }
}