@@ -20,6 +20,7 @@ import ast.tpd.*
2020import Synthesizer .*
2121import sbt .ExtractDependencies .*
2222import xsbti .api .DependencyContext .*
23+ import TypeComparer .{fullLowerBound , fullUpperBound }
2324
2425/** Synthesize terms for special classes */
2526class Synthesizer (typer : Typer )(using @ constructorOnly c : Context ):
@@ -38,10 +39,32 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
3839 // bounds are usually widened during instantiation.
3940 instArg(tp.tp1)
4041 case tvar : TypeVar if ctx.typerState.constraint.contains(tvar) =>
42+ // If tvar has a lower or upper bound:
43+ // 1. If the bound is not another type variable, use this as approximation.
44+ // 2. Otherwise, if the type can be forced to be fully defined, use that type
45+ // as approximation.
46+ // 3. Otherwise leave argument uninstantiated.
47+ // The reason for (2) is that we observed complicated constraints in i23611.scala
48+ // that get better types if a fully defined type is computed than if several type
49+ // variables are approximated incrementally. This is a minimization of some ZIO code.
50+ // So in order to keep backwards compatibility (where before we _only_ did 2) we
51+ // add that special case.
52+ def isGroundConstr (tp : Type ): Boolean = tp.dealias match
53+ case tvar : TypeVar if ctx.typerState.constraint.contains(tvar) => false
54+ case pref : TypeParamRef if ctx.typerState.constraint.contains(pref) => false
55+ case tp : AndOrType => isGroundConstr(tp.tp1) && isGroundConstr(tp.tp2)
56+ case _ => true
4157 instArg(
42- if tvar.hasLowerBound then tvar.instantiate(fromBelow = true )
43- else if tvar.hasUpperBound then tvar.instantiate(fromBelow = false )
44- else NoType )
58+ if tvar.hasLowerBound then
59+ if isGroundConstr(fullLowerBound(tvar.origin)) then tvar.instantiate(fromBelow = true )
60+ else if isFullyDefined(tp, ForceDegree .all) then tp
61+ else NoType
62+ else if tvar.hasUpperBound then
63+ if isGroundConstr(fullUpperBound(tvar.origin)) then tvar.instantiate(fromBelow = false )
64+ else if isFullyDefined(tp, ForceDegree .all) then tp
65+ else NoType
66+ else
67+ NoType )
4568 case _ =>
4669 tp
4770
@@ -573,9 +596,8 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
573596 resType <:< target
574597 val tparams = poly.paramRefs
575598 val variances = childClass.typeParams.map(_.paramVarianceSign)
576- val instanceTypes = tparams.lazyZip(variances).map( (tparam, variance) =>
599+ val instanceTypes = tparams.lazyZip(variances).map: (tparam, variance) =>
577600 TypeComparer .instanceType(tparam, fromBelow = variance < 0 , Widen .Unions )
578- )
579601 val instanceType = resType.substParams(poly, instanceTypes)
580602 // this is broken in tests/run/i13332intersection.scala,
581603 // because type parameters are not correctly inferred.
0 commit comments