@@ -9,7 +9,8 @@ import ProtoTypes.*
9
9
import NameKinds .UniqueName
10
10
import util .Spans .*
11
11
import util .{Stats , SimpleIdentityMap , SimpleIdentitySet , SrcPos }
12
- import Decorators .*
12
+ import transform .TypeUtils .isTransparent
13
+ import Decorators ._
13
14
import config .Printers .{gadts , typr }
14
15
import annotation .tailrec
15
16
import reporting .*
@@ -60,7 +61,9 @@ object Inferencing {
60
61
def instantiateSelected (tp : Type , tvars : List [Type ])(using Context ): Unit =
61
62
if (tvars.nonEmpty)
62
63
IsFullyDefinedAccumulator (
63
- ForceDegree .Value (tvars.contains, IfBottom .flip), minimizeSelected = true
64
+ new ForceDegree .Value (IfBottom .flip):
65
+ override def appliesTo (tvar : TypeVar ) = tvars.contains(tvar),
66
+ minimizeSelected = true
64
67
).process(tp)
65
68
66
69
/** Instantiate any type variables in `tp` whose bounds contain a reference to
@@ -154,15 +157,58 @@ object Inferencing {
154
157
* their lower bound. Record whether successful.
155
158
* 2nd Phase: If first phase was successful, instantiate all remaining type variables
156
159
* to their upper bound.
160
+ *
161
+ * Instance types can be improved by replacing covariant occurrences of Nothing
162
+ * with fresh type variables, if `force` allows this in its `canImprove` implementation.
157
163
*/
158
164
private class IsFullyDefinedAccumulator (force : ForceDegree .Value , minimizeSelected : Boolean = false )
159
165
(using Context ) extends TypeAccumulator [Boolean ] {
160
166
161
- private def instantiate (tvar : TypeVar , fromBelow : Boolean ): Type = {
167
+ /** Replace toplevel-covariant occurrences (i.e. covariant without double flips)
168
+ * of Nothing by fresh type variables.
169
+ * For singleton types and references to module classes: try to
170
+ * improve the widened type. For module classes, the widened type
171
+ * is the intersection of all its non-transparent parent types.
172
+ */
173
+ private def improve (tvar : TypeVar ) = new TypeMap :
174
+ def apply (t : Type ) = trace(i " improve $t" , show = true ):
175
+ def tryWidened (widened : Type ): Type =
176
+ val improved = apply(widened)
177
+ if improved ne widened then improved else mapOver(t)
178
+ if variance > 0 then
179
+ t match
180
+ case t : TypeRef =>
181
+ if t.symbol == defn.NothingClass then
182
+ newTypeVar(TypeBounds .empty, nestingLevel = tvar.nestingLevel)
183
+ else if t.symbol.is(ModuleClass ) then
184
+ tryWidened(t.parents.filter(! _.isTransparent())
185
+ .foldLeft(defn.AnyType : Type )(TypeComparer .andType(_, _)))
186
+ else
187
+ mapOver(t)
188
+ case t : TermRef =>
189
+ tryWidened(t.widen)
190
+ case _ =>
191
+ mapOver(t)
192
+ else t
193
+
194
+ /** Instantiate type variable with possibly improved computed instance type.
195
+ * @return true if variable was instantiated with improved type, which
196
+ * in this case should not be instantiated further, false otherwise.
197
+ */
198
+ private def instantiate (tvar : TypeVar , fromBelow : Boolean ): Boolean =
199
+ if fromBelow && force.canImprove(tvar) then
200
+ val inst = tvar.typeToInstantiateWith(fromBelow = true )
201
+ if apply(true , inst) then
202
+ // need to recursively check before improving, since improving adds type vars
203
+ // which should not be instantiated at this point
204
+ val better = improve(tvar)(inst)
205
+ if better <:< TypeComparer .fullUpperBound(tvar.origin) then
206
+ typr.println(i " forced instantiation of invariant ${tvar.origin} = $inst, improved to $better" )
207
+ tvar.instantiateWith(better)
208
+ return true
162
209
val inst = tvar.instantiate(fromBelow)
163
210
typr.println(i " forced instantiation of ${tvar.origin} = $inst" )
164
- inst
165
- }
211
+ false
166
212
167
213
private var toMaximize : List [TypeVar ] = Nil
168
214
@@ -178,26 +224,27 @@ object Inferencing {
178
224
&& ctx.typerState.constraint.contains(tvar)
179
225
&& {
180
226
var fail = false
227
+ var skip = false
181
228
val direction = instDirection(tvar.origin)
182
229
if minimizeSelected then
183
230
if direction <= 0 && tvar.hasLowerBound then
184
- instantiate(tvar, fromBelow = true )
231
+ skip = instantiate(tvar, fromBelow = true )
185
232
else if direction >= 0 && tvar.hasUpperBound then
186
- instantiate(tvar, fromBelow = false )
233
+ skip = instantiate(tvar, fromBelow = false )
187
234
// else hold off instantiating unbounded unconstrained variable
188
235
else if direction != 0 then
189
- instantiate(tvar, fromBelow = direction < 0 )
236
+ skip = instantiate(tvar, fromBelow = direction < 0 )
190
237
else if variance >= 0 && tvar.hasLowerBound then
191
- instantiate(tvar, fromBelow = true )
238
+ skip = instantiate(tvar, fromBelow = true )
192
239
else if (variance > 0 || variance == 0 && ! tvar.hasUpperBound)
193
240
&& force.ifBottom == IfBottom .ok
194
241
then // if variance == 0, prefer upper bound if one is given
195
- instantiate(tvar, fromBelow = true )
242
+ skip = instantiate(tvar, fromBelow = true )
196
243
else if variance >= 0 && force.ifBottom == IfBottom .fail then
197
244
fail = true
198
245
else
199
246
toMaximize = tvar :: toMaximize
200
- ! fail && foldOver(x, tvar)
247
+ ! fail && (skip || foldOver(x, tvar) )
201
248
}
202
249
case tp => foldOver(x, tp)
203
250
}
@@ -467,7 +514,7 @@ object Inferencing {
467
514
*
468
515
* we want to instantiate U to x.type right away. No need to wait further.
469
516
*/
470
- private def variances (tp : Type , pt : Type = WildcardType )(using Context ): VarianceMap [TypeVar ] = {
517
+ def variances (tp : Type , pt : Type = WildcardType )(using Context ): VarianceMap [TypeVar ] = {
471
518
Stats .record(" variances" )
472
519
val constraint = ctx.typerState.constraint
473
520
@@ -769,14 +816,30 @@ trait Inferencing { this: Typer =>
769
816
}
770
817
771
818
/** An enumeration controlling the degree of forcing in "is-fully-defined" checks. */
772
- @ sharable object ForceDegree {
773
- class Value (val appliesTo : TypeVar => Boolean , val ifBottom : IfBottom ):
774
- override def toString = s " ForceDegree.Value(.., $ifBottom) "
775
- val none : Value = new Value (_ => false , IfBottom .ok) { override def toString = " ForceDegree.none" }
776
- val all : Value = new Value (_ => true , IfBottom .ok) { override def toString = " ForceDegree.all" }
777
- val failBottom : Value = new Value (_ => true , IfBottom .fail) { override def toString = " ForceDegree.failBottom" }
778
- val flipBottom : Value = new Value (_ => true , IfBottom .flip) { override def toString = " ForceDegree.flipBottom" }
779
- }
819
+ @ sharable object ForceDegree :
820
+ class Value (val ifBottom : IfBottom ):
821
+
822
+ /** Does `tv` need to be instantiated? */
823
+ def appliesTo (tv : TypeVar ): Boolean = true
824
+
825
+ /** Should we try to improve the computed instance type by replacing bottom types
826
+ * with fresh type variables?
827
+ */
828
+ def canImprove (tv : TypeVar ): Boolean = false
829
+
830
+ override def toString = s " ForceDegree.Value( $ifBottom) "
831
+ end Value
832
+
833
+ val none : Value = new Value (IfBottom .ok):
834
+ override def appliesTo (tv : TypeVar ) = false
835
+ override def toString = " ForceDegree.none"
836
+ val all : Value = new Value (IfBottom .ok):
837
+ override def toString = " ForceDegree.all"
838
+ val failBottom : Value = new Value (IfBottom .fail):
839
+ override def toString = " ForceDegree.failBottom"
840
+ val flipBottom : Value = new Value (IfBottom .flip):
841
+ override def toString = " ForceDegree.flipBottom"
842
+ end ForceDegree
780
843
781
844
enum IfBottom :
782
845
case ok, fail, flip
0 commit comments