@@ -9,7 +9,8 @@ import ProtoTypes.*
99import NameKinds .UniqueName
1010import util .Spans .*
1111import util .{Stats , SimpleIdentityMap , SimpleIdentitySet , SrcPos }
12- import Decorators .*
12+ import transform .TypeUtils .isTransparent
13+ import Decorators ._
1314import config .Printers .{gadts , typr }
1415import annotation .tailrec
1516import reporting .*
@@ -60,7 +61,9 @@ object Inferencing {
6061 def instantiateSelected (tp : Type , tvars : List [Type ])(using Context ): Unit =
6162 if (tvars.nonEmpty)
6263 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
6467 ).process(tp)
6568
6669 /** Instantiate any type variables in `tp` whose bounds contain a reference to
@@ -154,15 +157,58 @@ object Inferencing {
154157 * their lower bound. Record whether successful.
155158 * 2nd Phase: If first phase was successful, instantiate all remaining type variables
156159 * 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.
157163 */
158164 private class IsFullyDefinedAccumulator (force : ForceDegree .Value , minimizeSelected : Boolean = false )
159165 (using Context ) extends TypeAccumulator [Boolean ] {
160166
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
162209 val inst = tvar.instantiate(fromBelow)
163210 typr.println(i " forced instantiation of ${tvar.origin} = $inst" )
164- inst
165- }
211+ false
166212
167213 private var toMaximize : List [TypeVar ] = Nil
168214
@@ -178,26 +224,27 @@ object Inferencing {
178224 && ctx.typerState.constraint.contains(tvar)
179225 && {
180226 var fail = false
227+ var skip = false
181228 val direction = instDirection(tvar.origin)
182229 if minimizeSelected then
183230 if direction <= 0 && tvar.hasLowerBound then
184- instantiate(tvar, fromBelow = true )
231+ skip = instantiate(tvar, fromBelow = true )
185232 else if direction >= 0 && tvar.hasUpperBound then
186- instantiate(tvar, fromBelow = false )
233+ skip = instantiate(tvar, fromBelow = false )
187234 // else hold off instantiating unbounded unconstrained variable
188235 else if direction != 0 then
189- instantiate(tvar, fromBelow = direction < 0 )
236+ skip = instantiate(tvar, fromBelow = direction < 0 )
190237 else if variance >= 0 && tvar.hasLowerBound then
191- instantiate(tvar, fromBelow = true )
238+ skip = instantiate(tvar, fromBelow = true )
192239 else if (variance > 0 || variance == 0 && ! tvar.hasUpperBound)
193240 && force.ifBottom == IfBottom .ok
194241 then // if variance == 0, prefer upper bound if one is given
195- instantiate(tvar, fromBelow = true )
242+ skip = instantiate(tvar, fromBelow = true )
196243 else if variance >= 0 && force.ifBottom == IfBottom .fail then
197244 fail = true
198245 else
199246 toMaximize = tvar :: toMaximize
200- ! fail && foldOver(x, tvar)
247+ ! fail && (skip || foldOver(x, tvar) )
201248 }
202249 case tp => foldOver(x, tp)
203250 }
@@ -467,7 +514,7 @@ object Inferencing {
467514 *
468515 * we want to instantiate U to x.type right away. No need to wait further.
469516 */
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 ] = {
471518 Stats .record(" variances" )
472519 val constraint = ctx.typerState.constraint
473520
@@ -769,14 +816,30 @@ trait Inferencing { this: Typer =>
769816}
770817
771818/** 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
780843
781844enum IfBottom :
782845 case ok, fail, flip
0 commit comments