Skip to content

Commit cedd41b

Browse files
author
Adriaan Moors
committed
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
1 parent 7da30bf commit cedd41b

File tree

5 files changed

+99
-50
lines changed

5 files changed

+99
-50
lines changed

src/compiler/scala/tools/nsc/ast/Trees.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1708,7 +1708,7 @@ trait Trees {
17081708
}
17091709
}
17101710

1711-
class TreeTypeSubstituter(val from: List[Symbol], to: List[Type]) extends Traverser {
1711+
class TreeTypeSubstituter(val from: List[Symbol], val to: List[Type]) extends Traverser {
17121712
val typeSubst = new SubstTypeMap(from, to)
17131713
override def traverse(tree: Tree) {
17141714
if (tree.tpe ne null) tree.tpe = typeSubst(tree.tpe)

src/compiler/scala/tools/nsc/typechecker/Implicits.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -431,10 +431,16 @@ self: Analyzer =>
431431
val targs = solvedTypes(tvars, undetParams, undetParams map varianceInType(pt),
432432
false, lubDepth(List(itree2.tpe, pt)))
433433
checkBounds(itree2.pos, NoPrefix, NoSymbol, undetParams, targs, "inferred ") // #2421
434-
val subst = new TreeTypeSubstituter(undetParams, targs)
434+
435+
// filter out failures from type inference, don't want to remove them from undetParams!
436+
val uninstantiated = new ListBuffer[Symbol]
437+
val detargs = adjustTypeArgs(undetParams, targs, pt, uninstantiated)
438+
val (okParams, okArgs) = (undetParams zip detargs) filter {case (p, a) => !uninstantiated.contains(p)} unzip
439+
// TODO: optimise above line(s?) once `zipped filter` works (oh, the irony! this line is needed to get Zipped to type check...)
440+
441+
val subst = new TreeTypeSubstituter(okParams, okArgs)
435442
subst traverse itree2
436-
// todo: remove type params that have been instantiated to Nothing, similar
437-
// to methTypeArgs
443+
438444
val result = new SearchResult(itree2, subst)
439445
if (traceImplicits) println("RESULT = "+result)
440446
// println("RESULT = "+itree+"///"+itree1+"///"+itree2)//DEBUG

src/compiler/scala/tools/nsc/typechecker/Infer.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,9 +587,15 @@ trait Infer {
587587
* and treat them as uninstantiated parameters instead.
588588
* Map T* entries to Seq[T].
589589
*/
590-
def adjustTypeArgs(tparams: List[Symbol], targs: List[Type], restpe: Type, uninstantiated: ListBuffer[Symbol]): List[Type] =
590+
def adjustTypeArgs(tparams: List[Symbol], targs: List[Type], restpe: Type, uninstantiated: ListBuffer[Symbol]): List[Type] = {
591+
@inline def covariantOrNotContained(variance: Int) =
592+
((variance & COVARIANT) == 0) || // tparam occurred covariantly
593+
(variance == VARIANCES) // tparam did not occur
594+
591595
List.map2(tparams, targs) {(tparam, targ) =>
592-
if (targ.typeSymbol == NothingClass && (restpe == WildcardType || (varianceInType(restpe)(tparam) & COVARIANT) == 0)) {
596+
if (targ.typeSymbol == NothingClass &&
597+
( restpe == WildcardType
598+
|| covariantOrNotContained(varianceInType(restpe)(tparam)))) {
593599
uninstantiated += tparam
594600
tparam.tpeHK //@M tparam.tpe was wrong: we only want the type constructor,
595601
// not the type constructor applied to dummy arguments
@@ -602,6 +608,7 @@ trait Infer {
602608
targ.widen
603609
}
604610
}
611+
}
605612

606613
/** Return inferred type arguments, given type parameters, formal parameters,
607614
* argument types, result type and expected result type.

src/compiler/scala/tools/nsc/typechecker/Typers.scala

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,19 @@ trait Typers { self: Analyzer =>
172172
def applyImplicitArgs(fun: Tree): Tree = fun.tpe match {
173173
case MethodType(params, _) =>
174174
var positional = true
175-
val argResults = params map (p => inferImplicit(fun, p.tpe, true, false, context))
175+
val argResultsBuff = new ListBuffer[SearchResult]()
176+
177+
// apply the substitutions (undet type param -> type) that were determined
178+
// by implicit resolution of implicit arguments on the left of this argument
179+
for(param <- params) {
180+
var paramTp = param.tpe
181+
for(ar <- argResultsBuff)
182+
paramTp = paramTp.subst(ar.subst.from, ar.subst.to)
183+
184+
argResultsBuff += inferImplicit(fun, paramTp, true, false, context)
185+
}
186+
187+
val argResults = argResultsBuff.toList
176188
val args = argResults.zip(params) flatMap {
177189
case (arg, param) =>
178190
if (arg != SearchFailure) {

src/library/scala/Tuple2.scala

Lines changed: 67 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212

1313
package scala
1414

15-
import annotation.unchecked.uncheckedVariance
16-
import scala.collection.generic.GenericTraversableTemplate
17-
import scala.collection.mutable.Builder
15+
import scala.collection.{TraversableLike, Traversable, IterableLike}
16+
import scala.collection.generic.CanBuildFrom
1817

1918

2019
/** 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] {
3029
/** Swap the elements of the tuple */
3130
def swap: Tuple2[T2,T1] = Tuple2(_2, _1)
3231

33-
/*
34-
type Traverserable[CC[X] <: Traversable[X], X] = GenericTraversableTemplate[X, CC] with Iterable[X]
32+
def zipped[Repr1, El1, Repr2, El2](implicit w1: T1 <:< TraversableLike[El1, Repr1], w2: T2 <:< IterableLike[El2, Repr2]): Zipped[Repr1, El1, Repr2, El2]
33+
= new Zipped[Repr1, El1, Repr2, El2](_1, _2)
3534

36-
// TODO: benchmark factored version vs inlining forall2 everywhere (specialisation?)
37-
// factor further? (use fold2)
38-
// must use <:< instead of =>, otherwise bogus any2stringadd conversion is also eligible (in case of type errors)
35+
class Zipped[+Repr1, +El1, +Repr2, +El2](coll1: TraversableLike[El1, Repr1], coll2: IterableLike[El2, Repr2]) { // coll2: IterableLike for filter
36+
def it: (Repr1, Repr2) = (coll1.repr, coll2.repr) // TODO: do we want this? what should its name be?
3937

38+
def map[B, To](f: (El1, El2) => B)(implicit cbf: CanBuildFrom[Repr1, B, To]): To = {
39+
val b = cbf(coll1.repr)
40+
val elems2 = coll2.iterator
4041

41-
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 = {
42-
val it1 = _1.iterator
43-
val it2 = _2.iterator
44-
var res = true
45-
while (res && it1.hasNext && it2.hasNext)
46-
res = f(it1.next, it2.next)
47-
res
48-
}
42+
for(el1 <- coll1)
43+
if(elems2.hasNext)
44+
b += f(el1, elems2.next)
4945

50-
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 = {
51-
val it1 = _1.iterator
52-
val it2 = _2.iterator
53-
var res = false
54-
while (!res && it1.hasNext && it2.hasNext)
55-
res = f(it1.next, it2.next)
56-
res
57-
}
46+
b.result
47+
}
5848

59-
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
60-
= forall2[CC, A1, A2]{(x, y) => f(x, y); true} // XXX: remove type args and fix crash in type infer
49+
def flatMap[B, To](f: (El1, El2) => Traversable[B])(implicit cbf: CanBuildFrom[Repr1, B, To]): To = {
50+
val b = cbf(coll1.repr)
51+
val elems2 = coll2.iterator
6152

62-
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] = {
63-
val b = _1.genericBuilder[B]
64-
foreach2[CC, A1, A2, Unit](f(b)) // XXX: remove type args and fix crash in type infer
65-
b.result
66-
}
53+
for(el1 <- coll1)
54+
if(elems2.hasNext)
55+
b ++= f(el1, elems2.next)
6756

68-
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)]
69-
= build2[CC, A1, A2, (A1, A2)]{b => (x, y) => // XXX: remove type args and fix crash in type infer
70-
b += Tuple2(x, y)
71-
}
57+
b.result
58+
}
7259

73-
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]
74-
= build2[CC, A1, A2, B]{b => (x, y) => // XXX: remove type args and fix crash in type infer
75-
b += f(x, y)
76-
}
60+
def filter[To1, To2](f: (El1, El2) => Boolean)(implicit cbf1: CanBuildFrom[Repr1, El1, To1], cbf2: CanBuildFrom[Repr2, El2, To2]): (To1, To2) = {
61+
val b1 = cbf1(coll1.repr)
62+
val b2 = cbf2(coll2.repr)
63+
val elems2 = coll2.iterator
7764

78-
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]
79-
= build2[CC, A1, A2, B]{b => (x, y) => // XXX: remove type args and fix crash in type infer
80-
b ++= f(x, y)
65+
for(el1 <- coll1) {
66+
if(elems2.hasNext) {
67+
val el2 = elems2.next
68+
if(f(el1, el2)) {
69+
b1 += el1
70+
b2 += el2
71+
}
72+
}
8173
}
82-
*/
8374

75+
(b1.result, b2.result)
76+
}
77+
78+
def exists(f: (El1, El2) => Boolean): Boolean = {
79+
var acc = false
80+
val elems2 = coll2.iterator
81+
82+
for(el1 <- coll1)
83+
if(!acc && elems2.hasNext)
84+
acc = f(el1, elems2.next)
85+
86+
acc
87+
}
88+
89+
def forall(f: (El1, El2) => Boolean): Boolean = {
90+
var acc = true
91+
val elems2 = coll2.iterator
92+
93+
for(el1 <- coll1)
94+
if(acc && elems2.hasNext)
95+
acc = f(el1, elems2.next)
96+
97+
acc
98+
}
99+
100+
def foreach[U](f: (El1, El2) => U): Unit = {
101+
val elems2 = coll2.iterator
102+
103+
for(el1 <- coll1)
104+
if(elems2.hasNext)
105+
f(el1, elems2.next)
106+
}
107+
}
84108
}

0 commit comments

Comments
 (0)