@@ -20,6 +20,7 @@ import ast.tpd.*
20
20
import Synthesizer .*
21
21
import sbt .ExtractDependencies .*
22
22
import xsbti .api .DependencyContext .*
23
+ import TypeComparer .{fullLowerBound , fullUpperBound }
23
24
24
25
/** Synthesize terms for special classes */
25
26
class Synthesizer (typer : Typer )(using @ constructorOnly c : Context ):
@@ -38,10 +39,32 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
38
39
// bounds are usually widened during instantiation.
39
40
instArg(tp.tp1)
40
41
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
41
57
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 )
45
68
case _ =>
46
69
tp
47
70
@@ -573,9 +596,8 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
573
596
resType <:< target
574
597
val tparams = poly.paramRefs
575
598
val variances = childClass.typeParams.map(_.paramVarianceSign)
576
- val instanceTypes = tparams.lazyZip(variances).map( (tparam, variance) =>
599
+ val instanceTypes = tparams.lazyZip(variances).map: (tparam, variance) =>
577
600
TypeComparer .instanceType(tparam, fromBelow = variance < 0 , Widen .Unions )
578
- )
579
601
val instanceType = resType.substParams(poly, instanceTypes)
580
602
// this is broken in tests/run/i13332intersection.scala,
581
603
// because type parameters are not correctly inferred.
0 commit comments