scala / scala3

The Scala 3 compiler, also known as Dotty.
https://dotty.epfl.ch
Apache License 2.0
5.84k stars 1.05k forks source link

Type mismatch after compiler rewrite for `A with B <:< C` #21398

Open WojciechMazur opened 1 month ago

WojciechMazur commented 1 month ago

Compiler version

All Scala versions since 3.4.0

Minimized code

sealed abstract class ZLayer[-RIn, +E, +ROut]
trait Tag[T]

trait GraphQLInterpreter[-R, +E]:
  final def provideSomeLayer[R0]: GraphQLInterpreter.ProvideSomeLayer[R0, R, E] = ???
object GraphQLInterpreter:
  final class ProvideSomeLayer[R0, -R, +E](private val self: GraphQLInterpreter[R, E]):
    def apply[E1 >: E, R1](layer: => ZLayer[R0, E1, R1])(implicit ev1: R0 with R1 <:< R, tagged: Tag[R1]): GraphQLInterpreter[R0, E1] = ???

final class UnsafeApi[R](interpreter: GraphQLInterpreter[R, Any]):
  def provideSomeLayer[R0](layer: ZLayer[R0, Any, R])(implicit tag: Tag[R]): UnsafeApi[R0] =
    new UnsafeApi(interpreter.provideSomeLayer(layer))

Output

Rewrites R0 with R1 <:< R to R0 & R1 <:< R. However it's interpreted differently: R0 with R1 <:< R === (R0 & R1) <:< R R0 & R1 <:< R === R0 & (R1 <:< R)

[error] ./src/main/scala/test.scala:12:54
[error] Cannot prove that R <:< R.
[error]     new UnsafeApi(interpreter.provideSomeLayer(layer))
[error]    

Expectation

The compiler should either treat the symbolic & in the same as the with symbol, or it should introduce parenthesis when rewriting symbols.

odersky commented 3 weeks ago

I think it's a corner case. We don't want to always add the parentheses, since that would clutter source and in 99.9% they are not needed. We could make it context dependent, at great expense. But I think it's actually a viable option to keep the current behavior and demand a manual fix afterwards.