Skip to content

Commit

Permalink
Do tryReplace using narrowedBounds instead of legalBound
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
EugeneFlesselle committed May 15, 2024
1 parent 97ed37e commit 14a6cac
Showing 1 changed file with 23 additions and 20 deletions.
43 changes: 23 additions & 20 deletions compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ trait ConstraintHandling {
*/
private var myTrustBounds = true

inline def withUntrustedBounds(op: => Type): Type =
transparent inline def withUntrustedBounds(op: => Type): Type =
val saved = myTrustBounds
myTrustBounds = false
try op finally myTrustBounds = saved
Expand Down Expand Up @@ -301,40 +301,43 @@ trait ConstraintHandling {
// so we shouldn't allow them as constraints either.
false
else
val bound = legalBound(param, rawBound, isUpper)
lazy val recBound = bound.existsPart(_ eq param, StopAt.Static)

val narrowedBounds: TypeBounds =
val bound = legalBound(param, rawBound, isUpper)
val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param)

val saved = homogenizeArgs
homogenizeArgs = Config.alignArgsInAnd
try
withUntrustedBounds(
if isUpper then oldBounds.derivedTypeBounds(lo, hi & bound)
else oldBounds.derivedTypeBounds(lo | bound, hi))
finally
homogenizeArgs = saved
end narrowedBounds

// If the narrowed bounds are equal and not recursive,
// we can remove `param` from the constraint.
def tryReplace: Boolean =
val TypeBounds(lo, hi) = constraint.nonParamBounds(param)
val equalBounds = (if isUpper then lo else hi) eq bound
val canReplace = equalBounds && !recBound
if canReplace then constraint = constraint.replace(param, bound)
def tryReplace(newBounds: TypeBounds): Boolean =
val TypeBounds(lo, hi) = newBounds
val canReplace = (lo eq hi) && !newBounds.existsPart(_ eq param, StopAt.Static)
if canReplace then constraint = constraint.replace(param, lo)
canReplace

tryReplace || locally:
val oldBounds @ TypeBounds(lo, hi) = constraint.nonParamBounds(param)
tryReplace(narrowedBounds) || locally:
// Narrow one of the bounds of type parameter `param`
// If `isUpper` is true, ensure that `param <: `bound`, otherwise ensure
// that `param >: bound`.
val narrowedBounds =
val saved = homogenizeArgs
homogenizeArgs = Config.alignArgsInAnd
try
withUntrustedBounds(
if isUpper then oldBounds.derivedTypeBounds(lo, hi & bound)
else oldBounds.derivedTypeBounds(lo | bound, hi))
finally
homogenizeArgs = saved
//println(i"narrow bounds for $param from $oldBounds to $narrowedBounds")
val c1 = constraint.updateEntry(param, narrowedBounds)
(c1 eq constraint)
|| {
constraint = c1
val TypeBounds(lo, hi) = constraint.entry(param): @unchecked
val isSat = isSub(lo, hi)
if isSat then tryReplace // isSub may have introduced new constraints
if isSat then
// isSub may have narrowed the bounds further
tryReplace(constraint.nonParamBounds(param))
isSat
}
end addOneBound
Expand Down

0 comments on commit 14a6cac

Please sign in to comment.