-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Anonymous trait mixin breaks inline match + erasedValue + summonInline #17222
Comments
If the last couple of lines are replaced with this, it works: trait D[X] extends B[X] with C
val d = new D[Int] {}
summon[Reader[(d.type, d.type), (Int, Int)]] // works |
this issue is incorrectly titled, in fact the mirror synthesis works fine (can be observed with //> using scala "3.3.0-RC3"
import scala.compiletime.*
trait Reader[-In, Out]
trait A:
type T
type F[X]
type Q = F[T]
object Reader:
given [X]: Reader[A { type Q = X }, X] with {}
object Test:
trait B[X] extends A:
type T = X
trait C extends A:
type F[X] = X
trait D[X] extends B[X] with C
val d = new D[Int] {}
val bc = new B[Int] with C
summonAll[(Reader[d.type, Int], Reader[d.type, Int])] // works
summonAll[(Reader[bc.type, Int], Reader[bc.type, Int])] // error
summonInline[Reader[d.type, Int]] // works
summonInline[Reader[bc.type, Int]] // works?? so it appears the problem is |
If I reimplement object Test:
// ...
case class Box[T]()
/** compiletime.summonAll, but with one case */
inline def summonOne[T <: Box[?]]: T =
val res =
inline erasedValue[T] match
case _: Box[t] => summonInline[t]
end match
Box(res).asInstanceOf[T]
end summonOne
summonOne[Box[Reader[d.type, Int]]] // works
summonOne[Box[Reader[bc.type, Int]]] // errors |
Here is a complete minimized example. There are many ways to make it compile, but only one way to make it fail: //> using scala 3.3.3
import scala.compiletime.*
trait Reader[-In, Out]
trait A:
type T
type F[X]
type Q = F[T]
given [X]: Reader[A { type Q = X }, X] with {}
case class Box[T](x: T)
/** compiletime.summonAll, but with one case */
inline def summonOne[T]: T =
val res =
inline erasedValue[T] match
case _: Box[t] => summonInline[t]
end match
Box(res).asInstanceOf[T]
end summonOne
@main def main =
trait B[X] extends A:
type T = X
trait C extends A:
type F[X] = X
val bc = new B[Int] with C
summonOne[Box[Reader[bc.type, Int]]] // errors
val bc2: A { type Q = Int } = new B[Int] with C
summonOne[Box[Reader[bc2.type, Int]]] // works
object BC extends B[Int] with C
summonOne[Box[Reader[BC.type, Int]]] // works
val a = new A:
type T = Int
type F[X] = X
summonOne[Box[Reader[a.type, Int]]] // works
val b = new B[Int]:
type F[X] = X
summonOne[Box[Reader[b.type, Int]]] // works
val ac = new A with C:
type T = Int
summonOne[Box[Reader[ac.type, Int]]] // works
trait D[X] extends B[X] with C
val d = new D[Int] {}
summonOne[Box[Reader[d.type, Int]]] // works |
Spent some time investigating this, further minimization: //> using scala 3.3.3
import scala.compiletime.*
trait Reader[-In, Out]
trait A:
type T
type F[X]
type Q = F[T]
given [X]: Reader[A { type Q = X }, X] with {}
case class Box[T](x: T)
inline def summonOne[T]: T =
summonInline[T]
end summonOne
@main def main =
trait B[X] extends A:
type T = X
trait C extends A:
type F[X] = X
val bc = new B[Int] with C
summonInline[Reader[bc.type, Int]] // (I) Works
summonOne[Reader[bc.type, Int]] // (II) Errors Looks like the only difference between the working call (I) and the erroring call (II) is that the failing call has a slightly different Context, the type argument is unchanged after the inlining of the enclosing method. In the failing call (II) the compiler is able to correctly identify the implicit method, however a later This is where it gets difficult, in both calls the TypeComparer tries to check the subtyping of
I have no idea why the things differ here. In the failing check this causes the |
Hi @noti0na1, |
I took a quick look, and it appears that the two
I tried modifying the I know that the TypeComparer behaves differently before and after the typer phase, but I haven't look into details why the type variable can't be instantiated in the second case. |
Further minimized to: import scala.compiletime.*
trait Reader[-In, Out]
trait A:
type F
type Q = F
given [X]: Reader[A { type Q = X }, X] with {}
def main =
// type BC = A { type F = Int } & A // ok
type BC = A & A { type F = Int } // fail, also ok when manually de-aliased
inline def summonOne: Unit = summonInline[Reader[BC, Int]]
summonInline[Reader[BC, Int]] // ok
summonOne // error It is from |
@noti0na1 @EugeneFlesselle Thank you for all of the help! The different behavior is indeed caused by the current phase. With that knowledge I tried digging a little further, and where it starts to differ is where it tries to return the denotation for A#Q. In |
We had also noticed the issue is avoided by disabling the optimizations in |
Compiler version
3.2.2, 3.3.0-RC3
Minimized code
Output
Expectation
Successful compilation
The text was updated successfully, but these errors were encountered: