Skip to content

Commit 8068ebb

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 8068ebb

File tree

4 files changed

+19
-32
lines changed

4 files changed

+19
-32
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: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ object Inferencing {
453453
*
454454
* we want to instantiate U to x.type right away. No need to wait further.
455455
*/
456-
private def variances(tp: Type)(using Context): VarianceMap = {
456+
private def variances(tp: Type, pt: Type = WildcardType)(using Context): VarianceMap = {
457457
Stats.record("variances")
458458
val constraint = ctx.typerState.constraint
459459

@@ -486,21 +486,21 @@ object Inferencing {
486486
def traverse(tp: Type) = { vmap1 = accu(vmap1, tp) }
487487
vmap.foreachBinding { (tvar, v) =>
488488
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-
}
489+
constraint.entry(param) match
490+
case TypeBounds(lo, hi) =>
491+
accu.setVariance(v)
492+
if v >= 0 then
493+
traverse(lo)
494+
constraint.lower(param).foreach(p => traverse(constraint.typeVarOfParam(p)))
495+
if v <= 0 then
496+
traverse(hi)
497+
constraint.upper(param).foreach(p => traverse(constraint.typeVarOfParam(p)))
498+
case _ =>
499499
}
500500
if (vmap1 eq vmap) vmap else propagate(vmap1)
501501
}
502502

503-
propagate(accu(SimpleIdentityMap.empty, tp))
503+
propagate(accu(accu(SimpleIdentityMap.empty, tp), pt.finalResultType))
504504
}
505505

506506
/** Run the transformation after dealiasing but return the original type if it was a no-op. */
@@ -546,8 +546,8 @@ trait Inferencing { this: Typer =>
546546
* @param locked the set of type variables of the current typer state that cannot be interpolated
547547
* at the present time
548548
* 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
549+
* that are not in locked. Type variables occurring co- (respectively, contra-) variantly in the tree type
550+
* or expected type are minimized (respectvely, maximized). Non occurring type variables are minimized if they
551551
* have a lower bound different from Nothing, maximized otherwise. Type variables appearing
552552
* non-variantly in the type are left untouched.
553553
*
@@ -572,15 +572,15 @@ trait Inferencing { this: Typer =>
572572
if ((ownedVars ne locked) && !ownedVars.isEmpty) {
573573
val qualifying = ownedVars -- locked
574574
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}")
575+
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}")
576576
val resultAlreadyConstrained =
577577
tree.isInstanceOf[Apply] || tree.tpe.isInstanceOf[MethodOrPoly]
578578
if (!resultAlreadyConstrained)
579579
constrainResult(tree.symbol, tree.tpe, pt)
580580
// This is needed because it could establish singleton type upper bounds. See i2998.scala.
581581

582582
val tp = tree.tpe.widen
583-
val vs = variances(tp)
583+
val vs = variances(tp, pt)
584584

585585
// Avoid interpolating variables occurring in tree's type if typerstate has unreported errors.
586586
// Reason: The errors might reflect unsatisfiable constraints. In that

0 commit comments

Comments
 (0)