Nie mam w 100% pełnej odpowiedzi, ale mam wskaźnik, który może być dla Ciebie wystarczający.
Kompilator Scala zajmuje się GADT (uogólnionymi typami danych algebraicznych) w bardzo szczególny sposób. Niektóre sprawy są rozwiązywane za pomocą specjalnej obsługi, niektóre sprawy są nierozwiązane. Dotty próbuje wypełnić większość dziur i już rozwiązało wiele powiązanych problemów, jednak wciąż istnieje wiele otwartych problemów .
Typowy przykład specjalnej obsługi GADT w kompilatorze Scala 2 jest bardzo związany z twoim przypadkiem użycia. Jeśli spojrzymy na:
def method[A](arg: Base[A]) = {
arg match {
case Derived(_) => 42
}
}
i wyraźnie deklarujemy, że typem zwrotu jest A
:
def method[A](arg: Base[A]): A
skompiluje się dobrze. Twoje IDE może narzekać, ale kompilator to przepuści. Metoda mówi, że zwraca an A
, ale wielkość pasująca do wzorca zmienia się w Int
, która teoretycznie nie powinna się kompilować. Jednak specjalna obsługa GADT w kompilatorze mówi, że jest w porządku, ponieważ w tym konkretnym odgałęzieniu dopasowywania wzorca A
została „ustalona” na Int
(ponieważ dopasowaliśmy, na Derived
którym jest a Base[Int]
).
Ogólny parametr typu GADT (w naszym przypadku A
) musi być gdzieś zadeklarowany. A oto interesująca część - specjalna obsługa kompilatora działa tylko wtedy, gdy jest zadeklarowana jako parametr typu metody zamykającej . Jeśli pochodzi od elementu typu lub parametru typu obejmującej cechy / klasy, nie kompiluje się, jak sam to widziałeś.
Dlatego powiedziałem, że nie jest to w 100% kompletna odpowiedź - nie mogę wskazać konkretnego miejsca (takiego jak oficjalna specyfikacja), które odpowiednio to dokumentuje. Źródła na manipulacyjny GADTs w Scala sprowadzają się do kilku z blogposts , które są świetne na drodze, ale jeśli chcesz więcej niż trzeba będzie kopać w kodzie kompilatora samodzielnie. Próbowałem zrobić dokładnie to i myślę, że sprowadza się to do tej metody , ale jeśli naprawdę chcesz zejść głębiej, możesz pingować kogoś bardziej doświadczonego z bazą kodową kompilatora Scala.