@@ -487,31 +487,54 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
487487
488488 // If LHS is a hard union, constrain any type variables of the RHS with it as lower bound
489489 // 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
491491 // the two parts of the LHS separately to the constraint, the lower bound would become
492492 // a soft union.
493493 def constrainRHSVars (tp2 : Type ): Boolean = tp2.dealiasKeepRefiningAnnots match
494494 case tp2 : TypeParamRef if constraint contains tp2 => compareTypeParamRef(tp2)
495495 case AndType (tp21, tp22) => constrainRHSVars(tp21) && constrainRHSVars(tp22)
496496 case _ => true
497497
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
515538
516539 case CapturingType (parent1, refs1) =>
517540 if subCaptures(refs1, tp2.captureSet, frozenConstraint).isOK && sameBoxed(tp1, tp2, refs1)
@@ -2960,8 +2983,8 @@ object TypeComparer {
29602983 def subtypeCheckInProgress (using Context ): Boolean =
29612984 comparing(_.subtypeCheckInProgress)
29622985
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))
29652988
29662989 def approximation (param : TypeParamRef , fromBelow : Boolean , maxLevel : Int = Int .MaxValue )(using Context ): Type =
29672990 comparing(_.approximation(param, fromBelow, maxLevel))
@@ -2981,8 +3004,8 @@ object TypeComparer {
29813004 def addToConstraint (tl : TypeLambda , tvars : List [TypeVar ])(using Context ): Boolean =
29823005 comparing(_.addToConstraint(tl, tvars))
29833006
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 ))
29863009
29873010 def dropTransparentTraits (tp : Type , bound : Type )(using Context ): Type =
29883011 comparing(_.dropTransparentTraits(tp, bound))
0 commit comments