Skip to content

Commit

Permalink
Guard against recursive lower bounds in constraints (#21587)
Browse files Browse the repository at this point in the history
We could get an indirect recursion going through a singleton type
before.

Fixes #21535
  • Loading branch information
smarter authored Sep 13, 2024
2 parents a4b162d + d0ea3b0 commit e5be3a1
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 4 deletions.
21 changes: 17 additions & 4 deletions compiler/src/dotty/tools/dotc/core/ConstraintHandling.scala
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,24 @@ trait ConstraintHandling {
end legalBound

protected def addOneBound(param: TypeParamRef, rawBound: Type, isUpper: Boolean)(using Context): Boolean =

// Replace top-level occurrences of `param` in `bound` by `Nothing`
def sanitize(bound: Type): Type =
if bound.stripped eq param then defn.NothingType
else bound match
case bound: AndOrType =>
bound.derivedAndOrType(sanitize(bound.tp1), sanitize(bound.tp2))
case _ =>
bound

if !constraint.contains(param) then true
else if !isUpper && param.occursIn(rawBound) then
// We don't allow recursive lower bounds when defining a type,
// so we shouldn't allow them as constraints either.
false
else if !isUpper && param.occursIn(rawBound.widen) then
val rawBound1 = sanitize(rawBound.widenDealias)
if param.occursIn(rawBound1) then
// We don't allow recursive lower bounds when defining a type,
// so we shouldn't allow them as constraints either.
false
else addOneBound(param, rawBound1, isUpper)
else

// Narrow one of the bounds of type parameter `param`
Expand Down
11 changes: 11 additions & 0 deletions tests/neg/i21535.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
-- [E007] Type Mismatch Error: tests/neg/i21535.scala:7:4 --------------------------------------------------------------
3 | (if (true) then
4 | new A(66)
5 | else
6 | m1()
7 | ).m2(p1 = p); // error
| ^
| Found: (Int | Short) @uncheckedVariance
| Required: Int & Short
|
| longer explanation available when compiling with `-explain`
16 changes: 16 additions & 0 deletions tests/neg/i21535.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
def test() = {
val p = 10.toShort
(if (true) then
new A(66)
else
m1()
).m2(p1 = p); // error

}

def m1(): A[Short] = new A(10)

class A[D](var f: D) {

def m2(p1: D = f, p2: D = f): Unit = {}
}

0 comments on commit e5be3a1

Please sign in to comment.