Skip to content

Commit

Permalink
Guard against recursive lower bounds in constraints
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
odersky committed Sep 13, 2024
1 parent d2bb85d commit d0ea3b0
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 d0ea3b0

Please sign in to comment.