Skip to content

Commit 3bcd6f8

Browse files
author
Adriaan Moors
committed
Merge pull request scala#975 from adriaanm/ticket-4881b
SI-4881 infer variance from formals, then result
2 parents 7b62eee + 5c5e8d4 commit 3bcd6f8

File tree

3 files changed

+45
-6
lines changed

3 files changed

+45
-6
lines changed

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ trait Infer {
445445
val tvars = tparams map freshVar
446446
if (isConservativelyCompatible(restpe.instantiateTypeParams(tparams, tvars), pt))
447447
map2(tparams, tvars)((tparam, tvar) =>
448-
instantiateToBound(tvar, varianceInTypes(formals)(tparam)))
448+
instantiateToBound(tvar, inferVariance(formals, restpe)(tparam)))
449449
else
450450
tvars map (tvar => WildcardType)
451451
}
@@ -575,13 +575,24 @@ trait Infer {
575575
"argument expression's type is not compatible with formal parameter type" + foundReqMsg(tp1, pt1))
576576
}
577577
}
578+
578579
val targs = solvedTypes(
579-
tvars, tparams, tparams map varianceInTypes(formals),
580+
tvars, tparams, tparams map inferVariance(formals, restpe),
580581
false, lubDepth(formals) max lubDepth(argtpes)
581582
)
582583
adjustTypeArgs(tparams, tvars, targs, restpe)
583584
}
584585

586+
/** Determine which variance to assume for the type paraneter. We first chose the variance
587+
* that minimizes any formal parameters. If that is still undetermined, because the type parameter
588+
* does not appear as a formal parameter type, then we pick the variance so that it minimizes the
589+
* method's result type instead.
590+
*/
591+
private def inferVariance(formals: List[Type], restpe: Type)(tparam: Symbol): Int = {
592+
val v = varianceInTypes(formals)(tparam)
593+
if (v != VarianceFlags) v else varianceInType(restpe)(tparam)
594+
}
595+
585596
private[typechecker] def followApply(tp: Type): Type = tp match {
586597
case NullaryMethodType(restp) =>
587598
val restp1 = followApply(restp)

test/files/neg/t5845.check

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
t5845.scala:9: error: value +++ is not a member of Int
2-
println(5 +++ 5)
3-
^
41
t5845.scala:15: error: value +++ is not a member of Int
52
println(5 +++ 5)
63
^
7-
two errors found
4+
one error found

test/files/pos/t4881.scala

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
class Contra[-T]
2+
trait A
3+
trait B extends A
4+
trait C extends B
5+
6+
// test improved variance inference: first try formals to see in which variance positions the type param appears;
7+
// only when that fails to determine variance, look at result type
8+
object Test {
9+
def contraLBUB[a >: C <: A](): Contra[a] = null
10+
def contraLB[a >: C](): Contra[a] = null
11+
12+
{
13+
val x = contraLBUB() //inferred Contra[C] instead of Contra[A]
14+
val x1: Contra[A] = x
15+
}
16+
17+
{
18+
val x = contraLB() //inferred Contra[C] instead of Contra[Any]
19+
val x1: Contra[Any] = x
20+
}
21+
22+
{
23+
val x = contraLBUB // make sure it does the same thing as its ()-less counterpart
24+
val x1: Contra[A] = x
25+
}
26+
27+
{
28+
val x = contraLB
29+
val x1: Contra[Any] = x
30+
}
31+
}

0 commit comments

Comments
 (0)