Skip to content

Commit 087b8d4

Browse files
committed
Refactor IsFullyDefinedAccumulator for clarity
1 parent c252ffd commit 087b8d4

File tree

2 files changed

+44
-25
lines changed

2 files changed

+44
-25
lines changed

compiler/src/dotty/tools/dotc/core/TypeOps.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -555,17 +555,17 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
555555

556556
val childTp = if (child.isTerm) child.termRef else child.typeRef
557557

558-
instantiate(childTp, parent)(ctx.fresh.setNewTyperState()).dealias
558+
instantiateToSubType(childTp, parent)(ctx.fresh.setNewTyperState()).dealias
559559
}
560560

561561
/** Instantiate type `tp1` to be a subtype of `tp2`
562562
*
563-
* Return the instantiated type if type parameters and this type
563+
* Return the instantiated type if type parameters in this type
564564
* in `tp1` can be instantiated such that `tp1 <:< tp2`.
565565
*
566566
* Otherwise, return NoType.
567567
*/
568-
private def instantiate(tp1: NamedType, tp2: Type)(implicit ctx: Context): Type = {
568+
private def instantiateToSubType(tp1: NamedType, tp2: Type)(implicit ctx: Context): Type = {
569569
/** expose abstract type references to their bounds or tvars according to variance */
570570
class AbstractTypeMap(maximize: Boolean)(implicit ctx: Context) extends TypeMap {
571571
def expose(lo: Type, hi: Type): Type =
@@ -637,7 +637,6 @@ trait TypeOps { this: Context => // TODO: Make standalone object.
637637
tvar =>
638638
!(ctx.typerState.constraint.entry(tvar.origin) `eq` tvar.origin.underlying) ||
639639
(tvar `eq` removeThisType.prefixTVar),
640-
minimizeAll = false,
641640
allowBottom = false
642641
)
643642

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

Lines changed: 41 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,20 @@ object Inferencing {
4343
if (isFullyDefined(tp, ForceDegree.all)) tp
4444
else throw new Error(i"internal error: type of $what $tp is not fully defined, pos = $span") // !!! DEBUG
4545

46-
/** Instantiate selected type variables `tvars` in type `tp` */
46+
/** Instantiate selected type variables `tvars` in type `tp` in a special mode:
47+
* 1. If a type variable is constrained from below (i.e. constraint bound != given lower bound)
48+
* it is minimized.
49+
* 2. Otherwise, if the type variable is constrained from above, it is maximized.
50+
* 3. Otherwise, if the type variable has a lower bound != Nothing, it is minimized.
51+
* 4. Otherwise, if the type variable has an upper bound != Any, it is maximized.
52+
* If none of (1) - (4) applies, the type variable is left uninstantiated.
53+
* The method is called to instantiate type variables before an implicit search.
54+
*/
4755
def instantiateSelected(tp: Type, tvars: List[Type])(implicit ctx: Context): Unit =
4856
if (tvars.nonEmpty)
49-
new IsFullyDefinedAccumulator(new ForceDegree.Value(tvars.contains, minimizeAll = true, allowBottom = false)).process(tp)
57+
IsFullyDefinedAccumulator(
58+
ForceDegree.Value(tvars.contains, allowBottom = false), minimizeSelected = true
59+
).process(tp)
5060

5161
/** Instantiate any type variables in `tp` whose bounds contain a reference to
5262
* one of the parameters in `tparams` or `vparamss`.
@@ -78,19 +88,27 @@ object Inferencing {
7888
* 2. T is maximized if the constraint over T is only from above (i.e.
7989
* constrained upper bound != given upper bound and
8090
* constrained lower bound == given lower bound).
81-
* If (1) and (2) do not apply:
82-
* 3. T is minimized if forceDegree is minimizeAll.
83-
* 4. Otherwise, T is maximized if it appears only contravariantly in the given type,
84-
* or if forceDegree is `noBottom` and T's minimized value is a bottom type.
85-
* 5. Otherwise, T is minimized.
8691
*
87-
* The instantiation is done in two phases:
92+
* If (1) and (2) do not apply, and minimizeSelected is set:
93+
* 3. T is minimized if it has a lower bound (different from Nothing) in the
94+
* current constraint (the bound might come from T's declaration).
95+
* 4. Otherwise, T is maximized if it has an upper bound (different from Any)
96+
* in the currented constraint (the bound might come from T's declaration).
97+
* 5. Otherwise, T is not instantiated at all.
98+
99+
* If (1) and (2) do not apply, and minimizeSelected is not set:
100+
* 6: T is maximized if it appears only contravariantly in the given type,
101+
* or if forceDegree is `noBottom` and T has no lower bound different from Nothing.
102+
* 7. Otherwise, T is minimized.
103+
*
104+
* The instantiation for (6) and (7) is done in two phases:
88105
* 1st Phase: Try to instantiate minimizable type variables to
89106
* their lower bound. Record whether successful.
90107
* 2nd Phase: If first phase was successful, instantiate all remaining type variables
91108
* to their upper bound.
92109
*/
93-
private class IsFullyDefinedAccumulator(force: ForceDegree.Value)(implicit ctx: Context) extends TypeAccumulator[Boolean] {
110+
private class IsFullyDefinedAccumulator(force: ForceDegree.Value, minimizeSelected: Boolean = false)
111+
(implicit ctx: Context) extends TypeAccumulator[Boolean] {
94112

95113
private def instantiate(tvar: TypeVar, fromBelow: Boolean): Type = {
96114
val inst = tvar.instantiate(fromBelow)
@@ -108,14 +126,16 @@ object Inferencing {
108126
&& ctx.typerState.constraint.contains(tvar)
109127
&& {
110128
val direction = instDirection(tvar.origin)
111-
def preferMin =
112-
force.minimizeAll && (tvar.hasLowerBound || !tvar.hasUpperBound)
113-
|| variance >= 0 && (force.allowBottom || tvar.hasLowerBound)
114-
if (direction != 0) instantiate(tvar, direction < 0)
115-
else if (preferMin)
116-
if force.minimizeAll && !tvar.hasLowerBound then () // do nothing
117-
else instantiate(tvar, fromBelow = true)
118-
else toMaximize = tvar :: toMaximize
129+
if direction != 0 then
130+
instantiate(tvar, fromBelow = direction < 0)
131+
else if minimizeSelected then
132+
if tvar.hasLowerBound then instantiate(tvar, fromBelow = true)
133+
else if tvar.hasUpperBound then instantiate(tvar, fromBelow = false)
134+
else () // hold off instantiating unbounded unconstrained variables
135+
else if variance >= 0 && (force.allowBottom || tvar.hasLowerBound) then
136+
instantiate(tvar, fromBelow = true)
137+
else
138+
toMaximize = tvar :: toMaximize
119139
foldOver(x, tvar)
120140
}
121141
case tp =>
@@ -489,9 +509,9 @@ trait Inferencing { this: Typer =>
489509

490510
/** An enumeration controlling the degree of forcing in "is-dully-defined" checks. */
491511
@sharable object ForceDegree {
492-
class Value(val appliesTo: TypeVar => Boolean, val minimizeAll: Boolean, val allowBottom: Boolean = true)
493-
val none: Value = new Value(_ => false, minimizeAll = false)
494-
val all: Value = new Value(_ => true, minimizeAll = false)
495-
val noBottom: Value = new Value(_ => true, minimizeAll = false, allowBottom = false)
512+
class Value(val appliesTo: TypeVar => Boolean, val allowBottom: Boolean)
513+
val none: Value = new Value(_ => false, allowBottom = true)
514+
val all: Value = new Value(_ => true, allowBottom = true)
515+
val noBottom: Value = new Value(_ => true, allowBottom = false)
496516
}
497517

0 commit comments

Comments
 (0)