@@ -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