Skip to content

Commit 5eb0716

Browse files
committed
More careful ClassTag instantiation
We now use a blend of the new scheme and backwards compatible special case if type variables as ClassTag arguments are constrained by further type variables. Fixes #23611
1 parent e5e19c8 commit 5eb0716

File tree

2 files changed

+30
-4
lines changed

2 files changed

+30
-4
lines changed

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5116,11 +5116,17 @@ object Types extends TypeUtils {
51165116
*/
51175117
private def currentEntry(using Context): Type = ctx.typerState.constraint.entry(origin)
51185118

5119+
/** For uninstantiated type variables: the lower bound */
5120+
def lowerBound(using Context): Type = currentEntry.loBound
5121+
5122+
/** For uninstantiated type variables: the upper bound */
5123+
def upperBound(using Context): Type = currentEntry.hiBound
5124+
51195125
/** For uninstantiated type variables: Is the lower bound different from Nothing? */
5120-
def hasLowerBound(using Context): Boolean = !currentEntry.loBound.isExactlyNothing
5126+
def hasLowerBound(using Context): Boolean = !lowerBound.isExactlyNothing
51215127

51225128
/** For uninstantiated type variables: Is the upper bound different from Any? */
5123-
def hasUpperBound(using Context): Boolean = !currentEntry.hiBound.isTopOfSomeKind
5129+
def hasUpperBound(using Context): Boolean = !upperBound.isTopOfSomeKind
51245130

51255131
/** Unwrap to instance (if instantiated) or origin (if not), until result
51265132
* is no longer a TypeVar

compiler/src/dotty/tools/dotc/typer/Synthesizer.scala

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,29 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
3838
// bounds are usually widened during instantiation.
3939
instArg(tp.tp1)
4040
case tvar: TypeVar if ctx.typerState.constraint.contains(tvar) =>
41+
// If tvar has a lower or upper bound:
42+
// 1. If the bound is not another type variable, use this as approximation.
43+
// 2. Otherwise, if the type can be forced to be fully defined, use that type
44+
// as approximation.
45+
// 3. Otherwise leave argument uninstantiated.
46+
// The reason for (2) is that we observed complicated constraints in i23611.scala
47+
// that get better types if a fully defined type is computed than if several type
48+
// variables are approximated incrementally. This is a minimization of some ZIP code.
49+
// So in order to keep backwards compatibility (where before we _only_ did 2) we
50+
// add that special case.
51+
def isGroundConstr(tp: Type): Boolean = tp.dealias match
52+
case tvar: TypeVar if ctx.typerState.constraint.contains(tvar) => false
53+
case tp: AndOrType => isGroundConstr(tp.tp1) && isGroundConstr(tp.tp2)
54+
case _ => true
4155
instArg(
42-
if tvar.hasLowerBound then tvar.instantiate(fromBelow = true)
43-
else if tvar.hasUpperBound then tvar.instantiate(fromBelow = false)
56+
if tvar.hasLowerBound then
57+
if isGroundConstr(tvar.lowerBound) then tvar.instantiate(fromBelow = true)
58+
else if isFullyDefined(tp, ForceDegree.all) then tp
59+
else NoType
60+
else if tvar.hasUpperBound then
61+
if isGroundConstr(tvar.upperBound) then tvar.instantiate(fromBelow = false)
62+
else if isFullyDefined(tp, ForceDegree.all) then tp
63+
else NoType
4464
else NoType)
4565
case _ =>
4666
tp

0 commit comments

Comments
 (0)