@@ -437,12 +437,19 @@ object Inferencing {
437437
438438 type VarianceMap = SimpleIdentityMap [TypeVar , Integer ]
439439
440- /** All occurrences of type vars in this type that satisfy predicate
441- * `include` mapped to their variances (-1/0/1) in this type, where
440+ /** All occurrences of type vars in `tp` that satisfy predicate
441+ * `include` mapped to their variances (-1/0/1) in both `tp` and
442+ * `pt.finalResultType`, where
442443 * -1 means: only contravariant occurrences
443444 * +1 means: only covariant occurrences
444445 * 0 means: mixed or non-variant occurrences
445446 *
447+ * We need to take the occurences in `pt` into account because a type
448+ * variable created when typing the current tree might only appear in the
449+ * bounds of a type variable in the expected type, for example when
450+ * `ConstraintHandling#addOneBound` creates type variables when approximating
451+ * a bound.
452+ *
446453 * Note: We intentionally use a relaxed version of variance here,
447454 * where the variance does not change under a prefix of a named type
448455 * (the strict version makes prefixes invariant). This turns out to be
@@ -453,7 +460,7 @@ object Inferencing {
453460 *
454461 * we want to instantiate U to x.type right away. No need to wait further.
455462 */
456- private def variances (tp : Type )(using Context ): VarianceMap = {
463+ private def variances (tp : Type , pt : Type = WildcardType )(using Context ): VarianceMap = {
457464 Stats .record(" variances" )
458465 val constraint = ctx.typerState.constraint
459466
@@ -486,21 +493,21 @@ object Inferencing {
486493 def traverse (tp : Type ) = { vmap1 = accu(vmap1, tp) }
487494 vmap.foreachBinding { (tvar, v) =>
488495 val param = tvar.origin
489- val e = constraint.entry(param)
490- accu.setVariance(v)
491- if (v >= 0 ) {
492- traverse(e.bounds.lo)
493- constraint.lower(param).foreach(p => traverse(constraint.typeVarOfParam(p)) )
494- }
495- if ( v <= 0 ) {
496- traverse(e.bounds. hi)
497- constraint.upper(param).foreach(p => traverse(constraint.typeVarOfParam(p)))
498- }
496+ constraint.entry(param) match
497+ case TypeBounds (lo, hi) =>
498+ accu.setVariance(v)
499+ if v >= 0 then
500+ traverse(lo )
501+ constraint.lower(param).foreach(p => traverse(constraint.typeVarOfParam(p)))
502+ if v <= 0 then
503+ traverse(hi)
504+ constraint.upper(param).foreach(p => traverse(constraint.typeVarOfParam(p)))
505+ case _ =>
499506 }
500507 if (vmap1 eq vmap) vmap else propagate(vmap1)
501508 }
502509
503- propagate(accu(SimpleIdentityMap .empty, tp))
510+ propagate(accu(accu( SimpleIdentityMap .empty, tp), pt.finalResultType ))
504511 }
505512
506513 /** Run the transformation after dealiasing but return the original type if it was a no-op. */
@@ -546,8 +553,8 @@ trait Inferencing { this: Typer =>
546553 * @param locked the set of type variables of the current typer state that cannot be interpolated
547554 * at the present time
548555 * Eligible for interpolation are all type variables owned by the current typerstate
549- * that are not in locked. Type variables occurring co- (respectively, contra-) variantly in the type
550- * are minimized (respectvely, maximized). Non occurring type variables are minimized if they
556+ * that are not in locked. Type variables occurring co- (respectively, contra-) variantly in the tree type
557+ * or expected type are minimized (respectvely, maximized). Non occurring type variables are minimized if they
551558 * have a lower bound different from Nothing, maximized otherwise. Type variables appearing
552559 * non-variantly in the type are left untouched.
553560 *
@@ -572,15 +579,15 @@ trait Inferencing { this: Typer =>
572579 if ((ownedVars ne locked) && ! ownedVars.isEmpty) {
573580 val qualifying = ownedVars -- locked
574581 if (! qualifying.isEmpty) {
575- typr.println(i " interpolate $tree: ${tree.tpe.widen} in $state, owned vars = ${state.ownedVars.toList}%, %, qualifying = ${qualifying.toList}%, %, previous = ${locked.toList}%, % / ${state.constraint}" )
582+ typr.println(i " interpolate $tree: ${tree.tpe.widen} in $state, pt = $pt , owned vars = ${state.ownedVars.toList}%, %, qualifying = ${qualifying.toList}%, %, previous = ${locked.toList}%, % / ${state.constraint}" )
576583 val resultAlreadyConstrained =
577584 tree.isInstanceOf [Apply ] || tree.tpe.isInstanceOf [MethodOrPoly ]
578585 if (! resultAlreadyConstrained)
579586 constrainResult(tree.symbol, tree.tpe, pt)
580587 // This is needed because it could establish singleton type upper bounds. See i2998.scala.
581588
582589 val tp = tree.tpe.widen
583- val vs = variances(tp)
590+ val vs = variances(tp, pt )
584591
585592 // Avoid interpolating variables occurring in tree's type if typerstate has unreported errors.
586593 // Reason: The errors might reflect unsatisfiable constraints. In that
0 commit comments