@@ -487,31 +487,54 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
487
487
488
488
// If LHS is a hard union, constrain any type variables of the RHS with it as lower bound
489
489
// before splitting the LHS into its constituents. That way, the RHS variables are
490
- // constraint by the hard union and can be instantiated to it. If we just split and add
490
+ // constrained by the hard union and can be instantiated to it. If we just split and add
491
491
// the two parts of the LHS separately to the constraint, the lower bound would become
492
492
// a soft union.
493
493
def constrainRHSVars (tp2 : Type ): Boolean = tp2.dealiasKeepRefiningAnnots match
494
494
case tp2 : TypeParamRef if constraint contains tp2 => compareTypeParamRef(tp2)
495
495
case AndType (tp21, tp22) => constrainRHSVars(tp21) && constrainRHSVars(tp22)
496
496
case _ => true
497
497
498
- widenOK
499
- || joinOK
500
- || (tp1.isSoft || constrainRHSVars(tp2)) && recur(tp11, tp2) && recur(tp12, tp2)
501
- || containsAnd(tp1)
502
- && ! joined
503
- && {
504
- joined = true
505
- try inFrozenGadt(recur(tp1.join, tp2))
506
- finally joined = false
507
- }
508
- // An & on the left side loses information. We compensate by also trying the join.
509
- // This is less ad-hoc than it looks since we produce joins in type inference,
510
- // and then need to check that they are indeed supertypes of the original types
511
- // under -Ycheck. Test case is i7965.scala.
512
- // On the other hand, we could get a combinatorial explosion by applying such joins
513
- // recursively, so we do it only once. See i14870.scala as a test case, which would
514
- // loop for a very long time without the recursion brake.
498
+ /** Mark toplevel type vars in `tp2` as hard in the current typerState */
499
+ def hardenTypeVars (tp2 : Type ): Unit = tp2.dealiasKeepRefiningAnnots match
500
+ case tvar : TypeVar if constraint.contains(tvar.origin) =>
501
+ state.hardVars += tvar
502
+ case tp2 : TypeParamRef if constraint.contains(tp2) =>
503
+ hardenTypeVars(constraint.typeVarOfParam(tp2))
504
+ case tp2 : AndOrType =>
505
+ hardenTypeVars(tp2.tp1)
506
+ hardenTypeVars(tp2.tp2)
507
+ case _ =>
508
+
509
+ val res = widenOK
510
+ || joinOK
511
+ || (tp1.isSoft || constrainRHSVars(tp2)) && recur(tp11, tp2) && recur(tp12, tp2)
512
+ || containsAnd(tp1)
513
+ && ! joined
514
+ && {
515
+ joined = true
516
+ try inFrozenGadt(recur(tp1.join, tp2))
517
+ finally joined = false
518
+ }
519
+ // An & on the left side loses information. We compensate by also trying the join.
520
+ // This is less ad-hoc than it looks since we produce joins in type inference,
521
+ // and then need to check that they are indeed supertypes of the original types
522
+ // under -Ycheck. Test case is i7965.scala.
523
+ // On the other hand, we could get a combinatorial explosion by applying such joins
524
+ // recursively, so we do it only once. See i14870.scala as a test case, which would
525
+ // loop for a very long time without the recursion brake.
526
+
527
+ if res && ! tp1.isSoft then
528
+ // We use a heuristic here where every toplevel type variable on the right hand side
529
+ // is marked so that it converts all soft unions in its lower bound to hard unions
530
+ // before it is instantiated. The reason is that the union might have come from
531
+ // (decomposed and reconstituted) `tp1`. But of course there might be false positives
532
+ // where we also treat unions that come from elsewhere as hard unions. Or the constraint
533
+ // that created the union is ultimately thrown away, but the type variable will
534
+ // stay marked. So it is a coarse measure to take. But it works in the obvious cases.
535
+ hardenTypeVars(tp2)
536
+
537
+ res
515
538
516
539
case CapturingType (parent1, refs1) =>
517
540
if subCaptures(refs1, tp2.captureSet, frozenConstraint).isOK && sameBoxed(tp1, tp2, refs1)
@@ -2960,8 +2983,8 @@ object TypeComparer {
2960
2983
def subtypeCheckInProgress (using Context ): Boolean =
2961
2984
comparing(_.subtypeCheckInProgress)
2962
2985
2963
- def instanceType (param : TypeParamRef , fromBelow : Boolean , maxLevel : Int = Int .MaxValue )(using Context ): Type =
2964
- comparing(_.instanceType(param, fromBelow, maxLevel))
2986
+ def instanceType (param : TypeParamRef , fromBelow : Boolean , widenUnions : Boolean , maxLevel : Int = Int .MaxValue )(using Context ): Type =
2987
+ comparing(_.instanceType(param, fromBelow, widenUnions, maxLevel))
2965
2988
2966
2989
def approximation (param : TypeParamRef , fromBelow : Boolean , maxLevel : Int = Int .MaxValue )(using Context ): Type =
2967
2990
comparing(_.approximation(param, fromBelow, maxLevel))
@@ -2981,8 +3004,8 @@ object TypeComparer {
2981
3004
def addToConstraint (tl : TypeLambda , tvars : List [TypeVar ])(using Context ): Boolean =
2982
3005
comparing(_.addToConstraint(tl, tvars))
2983
3006
2984
- def widenInferred (inst : Type , bound : Type )(using Context ): Type =
2985
- comparing(_.widenInferred(inst, bound))
3007
+ def widenInferred (inst : Type , bound : Type , widenUnions : Boolean )(using Context ): Type =
3008
+ comparing(_.widenInferred(inst, bound, widenUnions ))
2986
3009
2987
3010
def dropTransparentTraits (tp : Type , bound : Type )(using Context ): Type =
2988
3011
comparing(_.dropTransparentTraits(tp, bound))
0 commit comments