@@ -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,66 @@ 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. Double-flips are not covered to be
169+ * conservative and save a bit of time on traversals; we could probably
170+ * generalize that if we see use cases.
171+ * For singleton types and references to module classes: try to
172+ * improve the widened type. For module classes, the widened type
173+ * is the intersection of all its non-transparent parent types.
174+ */
175+ private def improve (tvar : TypeVar ) = new TypeMap :
176+ def apply (t : Type ) = trace(i " improve $t" , show = true ):
177+ def tryWidened (widened : Type ): Type =
178+ val improved = apply(widened)
179+ if improved ne widened then improved else mapOver(t)
180+ if variance > 0 then
181+ t match
182+ case t : TypeRef =>
183+ if t.symbol == defn.NothingClass then
184+ newTypeVar(TypeBounds .empty, nestingLevel = tvar.nestingLevel)
185+ else if t.symbol.is(ModuleClass ) then
186+ tryWidened(t.parents.filter(! _.isTransparent())
187+ .foldLeft(defn.AnyType : Type )(TypeComparer .andType(_, _)))
188+ else
189+ mapOver(t)
190+ case t : TermRef =>
191+ tryWidened(t.widen)
192+ case _ =>
193+ mapOver(t)
194+ else t
195+
196+ // Don't map Nothing arguments for higher-kinded types; we'd get the wrong kind */
197+ override def mapArg (arg : Type , tparam : ParamInfo ): Type =
198+ if tparam.paramInfo.isLambdaSub then arg
199+ else super .mapArg(arg, tparam)
200+ end improve
201+
202+ /** Instantiate type variable with possibly improved computed instance type.
203+ * @return true if variable was instantiated with improved type, which
204+ * in this case should not be instantiated further, false otherwise.
205+ */
206+ private def instantiate (tvar : TypeVar , fromBelow : Boolean ): Boolean =
207+ if fromBelow && force.canImprove(tvar) then
208+ val inst = tvar.typeToInstantiateWith(fromBelow = true )
209+ if apply(true , inst) then
210+ // need to recursively check before improving, since improving adds type vars
211+ // which should not be instantiated at this point
212+ val better = improve(tvar)(inst)
213+ if better <:< TypeComparer .fullUpperBound(tvar.origin) then
214+ typr.println(i " forced instantiation of invariant ${tvar.origin} = $inst, improved to $better" )
215+ tvar.instantiateWith(better)
216+ return true
162217 val inst = tvar.instantiate(fromBelow)
163218 typr.println(i " forced instantiation of ${tvar.origin} = $inst" )
164- inst
165- }
219+ false
166220
167221 private var toMaximize : List [TypeVar ] = Nil
168222
@@ -178,26 +232,27 @@ object Inferencing {
178232 && ctx.typerState.constraint.contains(tvar)
179233 && {
180234 var fail = false
235+ var skip = false
181236 val direction = instDirection(tvar.origin)
182237 if minimizeSelected then
183238 if direction <= 0 && tvar.hasLowerBound then
184- instantiate(tvar, fromBelow = true )
239+ skip = instantiate(tvar, fromBelow = true )
185240 else if direction >= 0 && tvar.hasUpperBound then
186- instantiate(tvar, fromBelow = false )
241+ skip = instantiate(tvar, fromBelow = false )
187242 // else hold off instantiating unbounded unconstrained variable
188243 else if direction != 0 then
189- instantiate(tvar, fromBelow = direction < 0 )
244+ skip = instantiate(tvar, fromBelow = direction < 0 )
190245 else if variance >= 0 && tvar.hasLowerBound then
191- instantiate(tvar, fromBelow = true )
246+ skip = instantiate(tvar, fromBelow = true )
192247 else if (variance > 0 || variance == 0 && ! tvar.hasUpperBound)
193248 && force.ifBottom == IfBottom .ok
194249 then // if variance == 0, prefer upper bound if one is given
195- instantiate(tvar, fromBelow = true )
250+ skip = instantiate(tvar, fromBelow = true )
196251 else if variance >= 0 && force.ifBottom == IfBottom .fail then
197252 fail = true
198253 else
199254 toMaximize = tvar :: toMaximize
200- ! fail && foldOver(x, tvar)
255+ ! fail && (skip || foldOver(x, tvar) )
201256 }
202257 case tp => foldOver(x, tp)
203258 }
@@ -467,7 +522,7 @@ object Inferencing {
467522 *
468523 * we want to instantiate U to x.type right away. No need to wait further.
469524 */
470- private def variances (tp : Type , pt : Type = WildcardType )(using Context ): VarianceMap [TypeVar ] = {
525+ def variances (tp : Type , pt : Type = WildcardType )(using Context ): VarianceMap [TypeVar ] = {
471526 Stats .record(" variances" )
472527 val constraint = ctx.typerState.constraint
473528
@@ -769,14 +824,30 @@ trait Inferencing { this: Typer =>
769824}
770825
771826/** 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- }
827+ @ sharable object ForceDegree :
828+ class Value (val ifBottom : IfBottom ):
829+
830+ /** Does `tv` need to be instantiated? */
831+ def appliesTo (tv : TypeVar ): Boolean = true
832+
833+ /** Should we try to improve the computed instance type by replacing bottom types
834+ * with fresh type variables?
835+ */
836+ def canImprove (tv : TypeVar ): Boolean = false
837+
838+ override def toString = s " ForceDegree.Value( $ifBottom) "
839+ end Value
840+
841+ val none : Value = new Value (IfBottom .ok):
842+ override def appliesTo (tv : TypeVar ) = false
843+ override def toString = " ForceDegree.none"
844+ val all : Value = new Value (IfBottom .ok):
845+ override def toString = " ForceDegree.all"
846+ val failBottom : Value = new Value (IfBottom .fail):
847+ override def toString = " ForceDegree.failBottom"
848+ val flipBottom : Value = new Value (IfBottom .flip):
849+ override def toString = " ForceDegree.flipBottom"
850+ end ForceDegree
780851
781852enum IfBottom :
782853 case ok, fail, flip
0 commit comments