@@ -17,6 +17,7 @@ import Decorators._
17
17
import Uniques ._
18
18
import ErrorReporting .{errorType , DiagnosticString }
19
19
import config .Printers ._
20
+ import annotation .tailrec
20
21
import collection .mutable
21
22
22
23
trait Inferencing { this : Checking =>
@@ -43,9 +44,26 @@ trait Inferencing { this: Checking =>
43
44
if (isFullyDefined(tp, ForceDegree .all)) tp
44
45
else throw new Error (i " internal error: type of $what $tp is not fully defined, pos = $pos" ) // !!! DEBUG
45
46
47
+
48
+ /** Instantiate selected type variables `tvars` in type `tp` */
49
+ def instantiateSelected (tp : Type , tvars : List [Type ])(implicit ctx : Context ): Unit =
50
+ new IsFullyDefinedAccumulator (new ForceDegree .Value (tvars.contains)).process(tp)
51
+
46
52
/** 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
53
+ * and returns whether the type is fully defined. The direction in which
54
+ * a type variable is instantiated is determined as follows:
55
+ * 1. T is minimized if the constraint over T is only from below (i.e.
56
+ * constrained lower bound != given lower bound and
57
+ * constrained upper bound == given upper bound).
58
+ * 2. T is maximized if the constraint over T is only from above (i.e.
59
+ * constrained upper bound != given upper bound and
60
+ * constrained lower bound == given lower bound).
61
+ * If (1) and (2) do not apply:
62
+ * 3. T is maximized if it appears only contravariantly in the given type.
63
+ * 4. T is minimized in all other cases.
64
+ *
65
+ * The instantiation is done in two phases:
66
+ * 1st Phase: Try to instantiate minimizable type variables to
49
67
* their lower bound. Record whether successful.
50
68
* 2nd Phase: If first phase was successful, instantiate all remaining type variables
51
69
* to their upper bound.
@@ -61,14 +79,20 @@ trait Inferencing { this: Checking =>
61
79
case _ : WildcardType | _ : ProtoType =>
62
80
false
63
81
case tvar : TypeVar if ! tvar.isInstantiated =>
64
- if (force == ForceDegree .none) false
65
- 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
82
+ force.appliesTo(tvar) && {
83
+ val direction = instDirection(tvar.origin)
84
+ if (direction != 0 ) {
85
+ if (direction > 0 ) println(s " inst $tvar dir = up " )
86
+ instantiate(tvar, direction < 0 )
87
+ }
88
+ else {
89
+ val minimize =
90
+ variance >= 0 && ! (
91
+ force == ForceDegree .noBottom &&
92
+ isBottomType(ctx.typeComparer.approximation(tvar.origin, fromBelow = true )))
93
+ if (minimize) instantiate(tvar, fromBelow = true )
94
+ else toMaximize = true
95
+ }
72
96
foldOver(x, tvar)
73
97
}
74
98
case tp =>
@@ -93,6 +117,62 @@ trait Inferencing { this: Checking =>
93
117
}
94
118
}
95
119
120
+ /** The list of uninstantiated type variables bound by some prefix of type `T` which
121
+ * occur in at least one formal parameter type of a prefix application.
122
+ * Considered prefixes are:
123
+ * - The function `f` of an application node `f(e1, .., en)`
124
+ * - The function `f` of a type application node `f[T1, ..., Tn]`
125
+ * - The prefix `p` of a selection `p.f`.
126
+ * - The result expression `e` of a block `{s1; .. sn; e}`.
127
+ */
128
+ def tvarsInParams (tree : Tree )(implicit ctx : Context ): List [TypeVar ] = {
129
+ @ tailrec def boundVars (tree : Tree , acc : List [TypeVar ]): List [TypeVar ] = tree match {
130
+ case Apply (fn, _) => boundVars(fn, acc)
131
+ case TypeApply (fn, targs) =>
132
+ val tvars = targs.tpes.collect {
133
+ case tvar : TypeVar if ! tvar.isInstantiated => tvar
134
+ }
135
+ boundVars(fn, acc ::: tvars)
136
+ case Select (pre, _) => boundVars(pre, acc)
137
+ case Block (_, expr) => boundVars(expr, acc)
138
+ case _ => acc
139
+ }
140
+ @ tailrec def occurring (tree : Tree , toTest : List [TypeVar ], acc : List [TypeVar ]): List [TypeVar ] =
141
+ if (toTest.isEmpty) acc
142
+ else tree match {
143
+ case Apply (fn, _) =>
144
+ fn.tpe match {
145
+ case mtp : MethodType =>
146
+ val (occ, nocc) = toTest.partition(tvar => mtp.paramTypes.exists(tvar.occursIn))
147
+ occurring(fn, nocc, occ ::: acc)
148
+ case _ =>
149
+ occurring(fn, toTest, acc)
150
+ }
151
+ case TypeApply (fn, targs) => occurring(fn, toTest, acc)
152
+ case Select (pre, _) => occurring(pre, toTest, acc)
153
+ case Block (_, expr) => occurring(expr, toTest, acc)
154
+ case _ => acc
155
+ }
156
+ occurring(tree, boundVars(tree, Nil ), Nil )
157
+ }
158
+
159
+ /** The instantiation direction for given poly param computed
160
+ * from the constraint:
161
+ * @return 1 (maximize) if constraint is uniformly from above,
162
+ * -1 (minimize) if constraint is uniformly from below,
163
+ * 0 if unconstrained, or constraint is from below and above.
164
+ */
165
+ private def instDirection (param : PolyParam )(implicit ctx : Context ): Int = {
166
+ val constrained = ctx.typerState.constraint.fullBounds(param)
167
+ val original = param.binder.paramBounds(param.paramNum)
168
+ val cmp = ctx.typeComparer
169
+ val approxBelow =
170
+ if (! cmp.isSubTypeWhenFrozen(constrained.lo, original.lo)) 1 else 0
171
+ val approxAbove =
172
+ if (! cmp.isSubTypeWhenFrozen(original.hi, constrained.hi)) 1 else 0
173
+ approxAbove - approxBelow
174
+ }
175
+
96
176
def isBottomType (tp : Type )(implicit ctx : Context ) =
97
177
tp == defn.NothingType || tp == defn.NullType
98
178
@@ -257,9 +337,10 @@ trait Inferencing { this: Checking =>
257
337
}
258
338
259
339
/** An enumeration controlling the degree of forcing in "is-dully-defined" checks. */
260
- @ sharable object ForceDegree extends Enumeration {
261
- val none, // don' t force type variables
262
- noBottom, // force type variables, fail if forced to Nothing or Null
263
- all = Value // force type variables, don't fail
340
+ @ sharable object ForceDegree {
341
+ class Value (val appliesTo : TypeVar => Boolean )
342
+ val none = new Value (_ => false )
343
+ val all = new Value (_ => true )
344
+ val noBottom = new Value (_ => true )
264
345
}
265
346
0 commit comments