Экспериментируя с возможностями метапрограммирования Scala 3, я обнаружил эту проблему со встроенным сопоставлением, объяснение которой я не могу удовлетворить.
Учитывая прозрачный встроенный метод eitherTest
, который принимает встроенный Either[String, Int]
, а затем возвращает либо String
, либо Int
напрямую, используя встроенное выражение соответствия, все работает отлично, если входные данные для eitherTest
явно вводятся в Left
или Right
. Однако компилятор, по-видимому, не может сократить выражение соответствия, если входные данные явно введены в супертип Either
. Что делает это более любопытным, так это то, что аргумент eitherTest
сам по себе имеет тип Either
.
Это ошибка компилятора? Это ожидаемое поведение? Я изо всех сил пытаюсь понять, почему компилятор не сможет решить эту проблему.
Ссылка на касти: https://scastie.scala-lang.org/CThqajauRVeJvxvW0uYy4w
Код:
@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
Ошибка:
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]
val l: Either[String, Int] = Left("hello")
val r: Either[String, Int] = Right(22)
Это явно отбрасывает информацию о типе, в результате чего компилятор не может сделать вывод о том, что ему нужно. Я считаю, что transparent
полагается на знание типа переданных аргументов, а не на «магию темного типа» вокруг статически определенных значений. Если вы сотрете тип переданных аргументов, то будет справедливо потерпеть неудачу, верно?
Соглашаться. Если во время компиляции что-то известно только как
Either
— а это то, что делает повышающее приведение — ни один из этих случаев не применим. И если ни один из этих случаев не применим, компилятор имеет право жаловаться; нет ничего, что он может разумно сделать