Skip to content

Commit

Permalink
Fix regression in cyclic constraint handling (#16514)
Browse files Browse the repository at this point in the history
This regressed in 50eb0e9 when
`current.ensureNonCyclic` was incorrectly replaced by `validBoundsFor`
which operates on `this`, not `current`.

This isn't the first time we make this error (cf
a8641c5), maybe we should refactor
OrderingConstraint so that operations on `current` are done in the
companion object where `this` isn't accessible.

Fixes #16471. Note that the test case from this issue couldn't be added
because it fails `-Ycheck:typer`, but this was also the case before the
regression. This is now tracked by #16524.
  • Loading branch information
odersky authored Dec 14, 2022
2 parents 2e409c6 + c1f77a5 commit 1e6a747
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -693,7 +693,7 @@ class OrderingConstraint(private val boundsMap: ParamBounds,
def replaceParamIn(other: TypeParamRef) =
val oldEntry = current.entry(other)
val newEntry = oldEntry.substParam(param, replacement) match
case tp: TypeBounds => validBoundsFor(other, tp)
case tp: TypeBounds => current.validBoundsFor(other, tp)
case tp => tp
current = boundsLens.update(this, current, other, newEntry)
var oldDepEntry = oldEntry
Expand Down
14 changes: 14 additions & 0 deletions compiler/test/dotty/tools/dotc/core/ConstraintsTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,17 @@ class ConstraintsTest:
assert(lo =:= defn.NothingType, i"Unexpected lower bound $lo for $t: ${ctx.typerState.constraint}")
assert(hi =:= (defn.StringType | defn.IntType), i"Unexpected upper bound $hi for $t: ${ctx.typerState.constraint}")
}

@Test def validBoundsReplace: Unit = inCompilerContext(
TestConfiguration.basicClasspath,
scalaSources = "trait X; trait A { def foo[S <: U | X, T, U]: Any }") {
val tvarTrees = constrained(requiredClass("A").typeRef.select("foo".toTermName).info.asInstanceOf[TypeLambda], EmptyTree, alwaysAddTypeVars = true)._2
val tvars @ List(s, t, u) = tvarTrees.tpes.asInstanceOf[List[TypeVar]]
s =:= t
t =:= u

for tvar <- tvars do
val entry = ctx.typerState.constraint.entry(tvar.origin)
assert(!ctx.typerState.constraint.occursAtToplevel(tvar.origin, entry),
i"cyclic bound for ${tvar.origin}: ${entry} in ${ctx.typerState.constraint}")
}

0 comments on commit 1e6a747

Please sign in to comment.