Skip to content

Commit 7a97e86

Browse files
committed
Change algorithm that computes instantiation direction
Change algorithm that determines whether type variables are minimized or maximized. We used to look only at the variance type variable in the containing type. We now also look with higher precedence at the direction from which the type variable was constrained. This is closer to what scalac does.
1 parent 3a8f708 commit 7a97e86

File tree

2 files changed

+45
-9
lines changed

2 files changed

+45
-9
lines changed

src/dotty/tools/dotc/core/ConstraintHandling.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ trait ConstraintHandling {
104104
up.forall(addOneBound(_, lo, isUpper = false))
105105
}
106106

107-
protected final def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
107+
final def isSubTypeWhenFrozen(tp1: Type, tp2: Type): Boolean = {
108108
val saved = frozenConstraint
109109
frozenConstraint = true
110110
try isSubType(tp1, tp2)

src/dotty/tools/dotc/typer/Inferencing.scala

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,20 @@ trait Inferencing { this: Checking =>
4444
else throw new Error(i"internal error: type of $what $tp is not fully defined, pos = $pos") // !!! DEBUG
4545

4646
/** The accumulator which forces type variables using the policy encoded in `force`
47-
* and returns whether the type is fully defined. Two phases:
48-
* 1st Phase: Try to instantiate covariant and non-variant type variables to
47+
* and returns whether the type is fully defined. The direction in which
48+
* a type variable is instantiated is determined as follows:
49+
* 1. T is minimized if the constraint over T is only from below (i.e.
50+
* constrained lower bound != given lower bound and
51+
* constrained upper bound == given upper bound).
52+
* 2. T is maximized if the constraint over T is only from above (i.e.
53+
* constrained upper bound != given upper bound and
54+
* constrained lower bound == given lower bound).
55+
* If (1) and (2) do not apply:
56+
* 3. T is maximized if it appears only contravariantly in the given type.
57+
* 4. T is minimized in all other cases.
58+
*
59+
* The instantiation is done in two phases:
60+
* 1st Phase: Try to instantiate minimizable type variables to
4961
* their lower bound. Record whether successful.
5062
* 2nd Phase: If first phase was successful, instantiate all remaining type variables
5163
* to their upper bound.
@@ -63,12 +75,19 @@ trait Inferencing { this: Checking =>
6375
case tvar: TypeVar if !tvar.isInstantiated =>
6476
if (force == ForceDegree.none) false
6577
else {
66-
val minimize =
67-
variance >= 0 && !(
68-
force == ForceDegree.noBottom &&
69-
isBottomType(ctx.typeComparer.approximation(tvar.origin, fromBelow = true)))
70-
if (minimize) instantiate(tvar, fromBelow = true)
71-
else toMaximize = true
78+
val direction = instDirection(tvar.origin)
79+
if (direction != 0) {
80+
if (direction > 0) println(s"inst $tvar dir = up")
81+
instantiate(tvar, direction < 0)
82+
}
83+
else {
84+
val minimize =
85+
variance >= 0 && !(
86+
force == ForceDegree.noBottom &&
87+
isBottomType(ctx.typeComparer.approximation(tvar.origin, fromBelow = true)))
88+
if (minimize) instantiate(tvar, fromBelow = true)
89+
else toMaximize = true
90+
}
7291
foldOver(x, tvar)
7392
}
7493
case tp =>
@@ -93,6 +112,23 @@ trait Inferencing { this: Checking =>
93112
}
94113
}
95114

115+
/** The instantiation direction for given poly param computed
116+
* from the constraint:
117+
* @return 1 (maximize) if constraint is uniformly from above,
118+
* -1 (minimize) if constraint is uniformly from below,
119+
* 0 if unconstrained, or constraint is from below and above.
120+
*/
121+
private def instDirection(param: PolyParam)(implicit ctx: Context): Int = {
122+
val constrained = ctx.typerState.constraint.fullBounds(param)
123+
val original = param.binder.paramBounds(param.paramNum)
124+
val cmp = ctx.typeComparer
125+
val approxBelow =
126+
if (!cmp.isSubTypeWhenFrozen(constrained.lo, original.lo)) 1 else 0
127+
val approxAbove =
128+
if (!cmp.isSubTypeWhenFrozen(original.hi, constrained.hi)) 1 else 0
129+
approxAbove - approxBelow
130+
}
131+
96132
def isBottomType(tp: Type)(implicit ctx: Context) =
97133
tp == defn.NothingType || tp == defn.NullType
98134

0 commit comments

Comments
 (0)