Skip to content

Commit 07588ab

Browse files
committed
Drop unnecessary ConstraintHandling#approximateWildcards
After improving Inferencing#variances to take the type variables appearing into the expected type into account, the special-casing based on necessaryConstraintsOnly provided by approximateWildcards turned out to be unnecessary. This change required tweaking the -Ytest-pickler logic to avoid a regression in tests/pos/i8802a.scala where a widened skolem in a prefix lead to a pretty-printing difference.
1 parent 362aaf2 commit 07588ab

File tree

4 files changed

+28
-34
lines changed

4 files changed

+28
-34
lines changed

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,6 @@ trait ConstraintHandling {
9797
def fullBounds(param: TypeParamRef)(using Context): TypeBounds =
9898
nonParamBounds(param).derivedTypeBounds(fullLowerBound(param), fullUpperBound(param))
9999

100-
/** If true, eliminate wildcards in bounds by avoidance, otherwise replace
101-
* them by fresh variables.
102-
*/
103-
protected def approximateWildcards: Boolean = true
104-
105100
protected def addOneBound(param: TypeParamRef, rawBound: Type, isUpper: Boolean)(using Context): Boolean =
106101
if !constraint.contains(param) then true
107102
else if !isUpper && param.occursIn(rawBound) then
@@ -116,7 +111,7 @@ trait ConstraintHandling {
116111
// flip the variance to under-approximate.
117112
if necessaryConstraintsOnly then variance = -variance
118113
override def mapWild(t: WildcardType) =
119-
if approximateWildcards then super.mapWild(t)
114+
if ctx.mode.is(Mode.TypevarsMissContext) then super.mapWild(t)
120115
else newTypeVar(apply(t.effectiveBounds).toBounds)
121116
val bound = dropWildcards(rawBound)
122117
val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param)

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

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,16 +137,6 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
137137
try topLevelSubType(tp1, tp2)
138138
finally myNecessaryConstraintsOnly = saved
139139

140-
/** Use avoidance to get rid of wildcards in constraint bounds if
141-
* we are doing a necessary comparison, or the mode is TypeVarsMissContext.
142-
* The idea is that under either of these conditions we are not interested
143-
* in creating a fresh type variable to replace the wildcard. I verified
144-
* that several tests break if one or the other part of the disjunction is dropped.
145-
* (for instance, i12677.scala demands `necessaryConstraintsOnly` in the condition)
146-
*/
147-
override protected def approximateWildcards: Boolean =
148-
necessaryConstraintsOnly || ctx.mode.is(Mode.TypevarsMissContext)
149-
150140
def testSubType(tp1: Type, tp2: Type): CompareResult =
151141
GADTused = false
152142
if !topLevelSubType(tp1, tp2) then CompareResult.Fail

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ class PlainPrinter(_ctx: Context) extends Printer {
6666
case tp @ AppliedType(tycon, args) =>
6767
if (defn.isCompiletimeAppliedType(tycon.typeSymbol)) tp.tryCompiletimeConstantFold
6868
else tycon.dealias.appliedTo(args)
69+
case tp: NamedType =>
70+
tp.reduceProjection
6971
case _ =>
7072
tp
7173
}

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

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)