Type argument does not conform to upper bound

Is this behavior correct? I couldn’t find anything wrong with it.

scala> trait X[T <: X[T, U], U <: Z[T, U]]
     | trait Y[T <: X[T, U], U <: Z[T, U]]
     | trait Z[T <: X[T, U], U <: Z[T, U]] extends Y[T, U]
-- [E057] Type Mismatch Error: -------------------------------------------------
3 |trait Z[T <: X[T, U], U <: Z[T, U]] extends Y[T, U]
  |                                                 ^
  |                   Type argument U does not conform to upper bound Z[T, U]
  |
  | longer explanation available when compiling with `-explain`
1 error found

Thanks

First, notice the circular F‑bound” in the definitions/

X is parameterized by T and U, with the constraints

  1. T⊆X[T,U]
  2. U⊆Z[T,U]
    Y is parameterized by the same pair (T,U)( but again requires
  3. T⊆X[T,U]
  4. U⊆Z[T,U]
    Z also uses the same pair (T,U) and itself requires
  5. T⊆X[T,U]
  6. U⊆Z[T,U] and extends Y[T,U].

When we write trait Z[T <: X[T, U], U <: Z[T, U]] extends Y[T, U]

we are telling the compiler that inside Z, the second type parameter U must itself be a subtype of Z[T, U] (the same trait we are defining). But at the same time, Z must extend Y[T, U], which also requires that this very same U be a subtype of Z[T, U].

Put differently, the compiler sees for Z[T, U] to extend Y[T, U], the second type parameter U must satisfy the upper bound required by Y, i.e. U⊆Z[T,U] and U ⊆ Z[T, U].

But U is the type parameter in Z[T, U] that is still being resolved. Scala 3’s type checker is stricter about such forward references or “F‑bound” cycles. Even though it looks consistent (“U should be a subtype of Z[T, U]” is exactly what you wrote), the compiler does not accept that U already “proves” it is a subtype of Z[T, U] merely by being used in the Z header itself.

In simpler terms you are defining trait Z, saying “U is a subtype of Z[T, U].” But you also do extends Y[T, U], so Y sees that “U must be a subtype of Z[T, U]” already. Scala 3 cannot confirm that requirement at the point where the trait is still being defined. It treats this as a circular, self-referential bound and fails with the message “type argument U does not conform to upper bound Z[T, U]”

This is precisely the F‑bounded polymorphism pitfall: you are “F‑bounding” over the same parameters in multiple traits (X, Y, Z) in a way that ends up circular from the compiler’s point of view. In Scala 2, certain self-referential or F‑bounded patterns were accepted more readily, sometimes in ways that weren’t fully safe. Scala 3 tightened the rules and disallows this direct cycle, thus producing the error.

2 Likes

Ok, then I tried an intersection type and it helps.

scala> trait X[T <: X[T, U], U <: Z[T, U]]
     | trait Y[T <: X[T, U], U <: Z[T, U] & Y[T, U]]
     | trait Z[T <: X[T, U], U <: Z[T, U]] extends Y[T, U]
// defined trait X
// defined trait Y
// defined trait Z