diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/ast/Trees.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Implicits.scala | 12 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Infer.scala | 11 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 14 | ||||
-rw-r--r-- | src/library/scala/Tuple2.scala | 110 |
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) + } + } } |