Skip to content

Commit 746f50b

Browse files
committed
Record constraint against tvar parameters
Instead of using TypeVar#underlying, which uses Constraint#instType, relying only on TypeVar#inst. That way we can record constraints against the original parameter and _then_ maximise the type, which results in `Bar[String]` instead of `Bar[X]`, in both cases with `X := String` recorded in the GADT constraint.
1 parent fd38489 commit 746f50b

File tree

4 files changed

+14
-22
lines changed

4 files changed

+14
-22
lines changed

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

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,7 @@ trait ConstraintHandling {
252252
val bound = legalBound(param, rawBound, isUpper)
253253
val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param)
254254
val equalBounds = (if isUpper then lo else hi) eq bound
255-
val isGadt = ctx.mode.is(Mode.GadtConstraintInference)
256-
if equalBounds && !isGadt && !bound.existsPart(_ eq param, StopAt.Static) then
255+
if equalBounds && !bound.existsPart(_ eq param, StopAt.Static) then
257256
// The narrowed bounds are equal and not recursive,
258257
// so we can remove `param` from the constraint.
259258
constraint = constraint.replace(param, bound)
@@ -268,12 +267,8 @@ trait ConstraintHandling {
268267
homogenizeArgs = Config.alignArgsInAnd
269268
try
270269
trustBounds = false
271-
if isUpper then
272-
if isGadt && !hi.isAny && hi.isValueTypeOrWildcard && bound.isValueTypeOrWildcard then oldBounds.derivedTypeBounds(lo, AndType(hi, bound))
273-
else oldBounds.derivedTypeBounds(lo, hi & bound)
274-
else
275-
if isGadt && !lo.isNothingType && lo.isValueTypeOrWildcard && bound.isValueTypeOrWildcard then oldBounds.derivedTypeBounds(OrType(lo, bound, soft = true), hi)
276-
else oldBounds.derivedTypeBounds(lo | bound, hi)
270+
if isUpper then oldBounds.derivedTypeBounds(lo, hi & bound)
271+
else oldBounds.derivedTypeBounds(lo | bound, hi)
277272
finally
278273
homogenizeArgs = savedHomogenizeArgs
279274
trustBounds = savedTrustBounds

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

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,16 +162,13 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
162162

163163
def contains(pt: TypeLambda): Boolean = boundsMap(pt) != null
164164

165-
def contains(param: TypeParamRef): Boolean = {
166-
val entries = boundsMap(param.binder)
167-
entries != null && isBounds(entries(param.paramNum))
168-
}
165+
def contains(param: TypeParamRef): Boolean = boundsMap(param.binder) != null
169166

170167
def contains(tvar: TypeVar): Boolean = {
171168
val origin = tvar.origin
172169
val entries = boundsMap(origin.binder)
173170
val pnum = origin.paramNum
174-
entries != null && isBounds(entries(pnum)) && (typeVar(entries, pnum) eq tvar)
171+
entries != null && (typeVar(entries, pnum) eq tvar)
175172
}
176173

177174
// ---------- Dependency handling ----------------------------------------------
@@ -548,7 +545,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
548545

549546
def forallParams(p: TypeParamRef => Boolean): Boolean =
550547
boundsMap.forallBinding { (poly, entries) =>
551-
!0.until(paramCount(entries)).exists(i => isBounds(entries(i)) && !p(poly.paramRefs(i)))
548+
(0 until paramCount(entries)).forall(i => p(poly.paramRefs(i)))
552549
}
553550

554551
def foreachParam(p: (TypeLambda, Int) => Unit): Unit =

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
117117
protected def gadtAddLowerBound(sym: Symbol, b: Type): Boolean = ctx.gadt.addBound(sym, b, isUpper = false)
118118
protected def gadtAddUpperBound(sym: Symbol, b: Type): Boolean = ctx.gadt.addBound(sym, b, isUpper = true)
119119

120-
protected def typeVarInstance(tvar: TypeVar)(using Context): Type = tvar.underlying
120+
protected def typeVarInstance(tvar: TypeVar)(using Context): Type = tvar.inst.orElse(tvar.origin)
121121

122122
// Subtype testing `<:<`
123123

@@ -1201,7 +1201,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
12011201
def compareLower(tycon2bounds: TypeBounds, tyconIsTypeRef: Boolean): Boolean =
12021202
if ((tycon2bounds.lo `eq` tycon2bounds.hi) && !tycon2bounds.isInstanceOf[MatchAlias])
12031203
if (tyconIsTypeRef) recur(tp1, tp2.superTypeNormalized)
1204-
else recur(tp1, tycon2bounds.lo.applyIfParameterized(args2))
1204+
else isSubApproxHi(tp1, tycon2bounds.lo.applyIfParameterized(args2))
12051205
else
12061206
fallback(tycon2bounds.lo)
12071207

tests/pos/i15289.scala

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ class Test:
1818
// max: Bar[X]
1919

2020
// what's more correct?
21-
// * unapp arg tpe = Bar[X] gadt: X =:= String
22-
// * unapp arg tpe = Bar[String] gadt: X =:= String
21+
// * unapp arg tpe = Bar[X] gadt: X := String
22+
// * unapp arg tpe = Bar[String] gadt: X := String
2323

2424
// after fix:
2525
// ptc: Bar[C] aka Foo[C, C] vs Foo[X, String]
26-
// ptc: C >: X ~> cstr: C >: X
27-
// ptc: C <: X ~> cstr: C =:= X
28-
// ptc: C >: String ~> cstr: C >: X | String <: X gadt: X >: String
29-
// ptc: C <: String ~> cstr: C >: X | String <: X & String gadt: X =:= String
26+
// ptc: C >: X ~> cstr: C >: X
27+
// ptc: C <: X ~> cstr: C >: X <: X
28+
// ptc: C >: String ~> cstr: C >: X | String <: X gadt: X >: String
29+
// ptc: C <: String ~> cstr: C >: X | String <: String gadt: X := String
3030
// ptc: Bar[C]
3131
// max: Bar[String]

0 commit comments

Comments
 (0)