У меня нет 100% полного ответа, но у меня есть указатель, который может быть достаточным для вас.
Scala компилятор работает с GADT (Generalized Algebrai c Types) в очень особенный способ. Некоторые случаи решаются с особой обработкой, некоторые случаи не решены. Дотти пытается заполнить большую часть дыр, и она уже решила множество связанных проблем, однако есть еще немало открытых .
Типичный пример специальной обработки GADT в компиляторе Scala 2 очень связан с вашим вариантом использования. Если мы посмотрим на:
def method[A](arg: Base[A]) = {
arg match {
case Derived(_) => 42
}
}
и мы явно объявим тип возвращаемого значения A
:
def method[A](arg: Base[A]): A
, он будет скомпилирован очень хорошо. Ваша IDE может жаловаться, но компилятор пропустит это. Метод говорит, что возвращает A
, но случай сопоставления с образцом оценивается в Int
, который теоретически не должен компилироваться. Тем не менее, специальная обработка GADT в компиляторе говорит, что это нормально, потому что в этой конкретной ветке сопоставления с шаблоном A
был «зафиксирован», чтобы быть Int
(потому что мы соответствовали Derived
, что Base[Int]
). Параметр типа
Generi c для GADT (в нашем случае A
) должен быть где-то объявлен. И вот интересная часть - специальная обработка компилятора работает только тогда, когда она объявлена как параметр типа метода включения . Если это происходит от члена типа или параметра типа включающей черты / класса, он не компилируется, как вы сами убедились.
Вот почему я сказал, что это не 100% полный ответ - я не могу указать конкретное место (например, официальную спецификацию), которое документирует это должным образом. Источники обработки GADT в Scala сводятся к паре из blogposts , которые, кстати, хороши, но если вы хотите большего, вы придется копаться в коде компилятора самостоятельно. Я попытался сделать именно это, и я думаю, что это сводится к этому методу , но если вы действительно хотите go глубже, вы можете захотеть пропинговать кого-то более опытного с Scala базой кода компилятора.