Skip to content

Commit 14a6cac

Browse files
Do tryReplace using narrowedBounds instead of legalBound
In scala#20120, we reach constraints with equal bounds that are intersection types, they are formed from multiple successive calls to `addOneBound`. We miss the `replace` optimization in this case because the bounds only become equal progressively, and we are only checking for equality with the constraint being added. The second tryReplace after updateEntry and isSub does not address this specific issue but scala#19955.
1 parent 97ed37e commit 14a6cac

File tree

1 file changed

+23
-20
lines changed

1 file changed

+23
-20
lines changed

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

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ trait ConstraintHandling {
120120
*/
121121
private var myTrustBounds = true
122122

123-
inline def withUntrustedBounds(op: => Type): Type =
123+
transparent inline def withUntrustedBounds(op: => Type): Type =
124124
val saved = myTrustBounds
125125
myTrustBounds = false
126126
try op finally myTrustBounds = saved
@@ -301,40 +301,43 @@ trait ConstraintHandling {
301301
// so we shouldn't allow them as constraints either.
302302
false
303303
else
304-
val bound = legalBound(param, rawBound, isUpper)
305-
lazy val recBound = bound.existsPart(_ eq param, StopAt.Static)
304+
305+
val narrowedBounds: TypeBounds =
306+
val bound = legalBound(param, rawBound, isUpper)
307+
val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param)
308+
309+
val saved = homogenizeArgs
310+
homogenizeArgs = Config.alignArgsInAnd
311+
try
312+
withUntrustedBounds(
313+
if isUpper then oldBounds.derivedTypeBounds(lo, hi & bound)
314+
else oldBounds.derivedTypeBounds(lo | bound, hi))
315+
finally
316+
homogenizeArgs = saved
317+
end narrowedBounds
306318

307319
// If the narrowed bounds are equal and not recursive,
308320
// we can remove `param` from the constraint.
309-
def tryReplace: Boolean =
310-
val TypeBounds(lo, hi) = constraint.nonParamBounds(param)
311-
val equalBounds = (if isUpper then lo else hi) eq bound
312-
val canReplace = equalBounds && !recBound
313-
if canReplace then constraint = constraint.replace(param, bound)
321+
def tryReplace(newBounds: TypeBounds): Boolean =
322+
val TypeBounds(lo, hi) = newBounds
323+
val canReplace = (lo eq hi) && !newBounds.existsPart(_ eq param, StopAt.Static)
324+
if canReplace then constraint = constraint.replace(param, lo)
314325
canReplace
315326

316-
tryReplace || locally:
317-
val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param)
327+
tryReplace(narrowedBounds) || locally:
318328
// Narrow one of the bounds of type parameter `param`
319329
// If `isUpper` is true, ensure that `param <: `bound`, otherwise ensure
320330
// that `param >: bound`.
321-
val narrowedBounds =
322-
val saved = homogenizeArgs
323-
homogenizeArgs = Config.alignArgsInAnd
324-
try
325-
withUntrustedBounds(
326-
if isUpper then oldBounds.derivedTypeBounds(lo, hi & bound)
327-
else oldBounds.derivedTypeBounds(lo | bound, hi))
328-
finally
329-
homogenizeArgs = saved
330331
//println(i"narrow bounds for $param from $oldBounds to $narrowedBounds")
331332
val c1 = constraint.updateEntry(param, narrowedBounds)
332333
(c1 eq constraint)
333334
|| {
334335
constraint = c1
335336
val TypeBounds(lo, hi) = constraint.entry(param): @unchecked
336337
val isSat = isSub(lo, hi)
337-
if isSat then tryReplace // isSub may have introduced new constraints
338+
if isSat then
339+
// isSub may have narrowed the bounds further
340+
tryReplace(constraint.nonParamBounds(param))
338341
isSat
339342
}
340343
end addOneBound

0 commit comments

Comments
 (0)