Experimenting with Scala 3's metaprogramming capabilities, I found this issue with inline matching that I'm not able to satisfy myself with an explanation for.
Given a transparent inline method eitherTest
which takes an inlined Either[String, Int]
and then returns either the String
or the Int
directly using an inline match expression, things work perfectly fine if the input to eitherTest
is explicitly typed to a Left
or a Right
. However, the compiler appears to be unable to reduce the match expression if the input is explicitly typed to the supertype of Either
. What makes this more curious is that the argument to eitherTest
is itself typed as Either
.
Is this a compiler bug? Is this expected behavior? I'm struggling to understand why the compiler would not be able to resolve this.
Scastie link: https://scastie.scala-lang.org/CThqajauRVeJvxvW0uYy4w
Code:
@main def hello: Unit =
workingTest
failingTest
def workingTest: Unit =
val l: Left[String, Int] = Left("hello")
val r: Right[String, Int] = Right(22)
val tl: String = eitherTest(l)
val tr: Int = eitherTest(r)
println(s"$tl :: $tr")
def failingTest: Unit =
val l: Either[String, Int] = Left("hello")
val r: Either[String, Int] = Right(22)
val tl: String = eitherTest(l)
val tr: Int = eitherTest(r)
println(s"$tl :: $tr")
transparent inline def eitherTest(inline v: Either[String, Int]): Any =
inline v match
case Right(a) => a
case Left(b) => b
Error:
cannot reduce inline match with
scrutinee: l : (l : Either[String, Int])
patterns : case Right.unapply[String, Int](a @ _):Right[String, Int]
case Left.unapply[String, Int](b @ _):Left[String, Int]
CodePudding user response:
val l: Either[String, Int] = Left("hello")
val r: Either[String, Int] = Right(22)
This explicitly discards type information, leaving the compiler unable to infer what it needs. I believe the transparent
relies on type knowledge of passed arguments, rather than "dark type magic" around statically defined values. If you erase the type of the passed arguments, then it is fair to fail right?