Проблема преобразования захвата в Java, согласование WRT JLS и фактическое поведение JDK

Учитывая следующие два определения класса:

class C1<T extends C1<T>> {}

class C2<U> extends C1<C2<U>> {}

Рассмотрим следующее объявление типа:

C1<? extends C2<String>> c;

Это компилируется в JDK-8u45, но если мы рассмотрим спецификацию для преобразования захвата, мне кажется (что) это объявление должно привести к времени компиляции ошибка.

В частности, верхняя граница захвата переменной типа T#1 задается как glb(Bi, Ui[A1:=S1,...,An:=Sn]), где в этом случае Bi разрешает привязку подстановочного символа C2<String> и Ui[A1:=S1,...,An:=Sn] разрешается до C1<T#1>.

Из этого, glb(C2<?>, C1<T#1>) разрешается тип пересечения C2<String> & C1<T#1>, что является недопустимым, поскольку C2<String> и C1<T#1> - оба типа классов, а не типы интерфейсов, но ни один из них не является подтипом другого.

Это (очевидное) нарушение правила, возможно, более ясно описано в определении самого типа пересечения.

Я уверен, что это не ошибка, и я просто делаю некоторые простые ошибки где-то... Если это ошибка, я надеюсь, что это можно считать ошибкой в ​​JLS, а не JDK, чтобы я мог надеяться на безопасное подражание поведению...

Спасибо за любую помощь!

Изменить: Вчера, после разговора с Radiodef, я убедился, что проблема (или один из способов взглянуть на нее по крайней мере) заключается в том, что C2<String> можно эффективно рассматривать как подтип C1<T#1>, так как T # 1 может удовлетворяться только C2<String> и поэтому может считаться равным ему, но правила сдерживания и подтипирования не имеют понимания этого отношения как написано, и поэтому JLS не будет распознавать подтип и должен не в состоянии...

Если вы делаете несколько более сложный случай C1<? extends C2<?>> d;, тем не менее, это более сложно. Проблема аналогична, но тип пересечения, который образует верхнюю границу захвата, выражается как C2<?> & C1<T#2>, где, похоже, решение не может быть получено теми же рассуждениями, что и выше.

Ответы

Ответ 1

На этот вопрос лучше ответить ответ Maurizio на компилятор-dev.

(TL; DR javac действительно не согласуется с спецификацией здесь, и оптимальное решение, вероятно, лежит где-то между двумя подходами)

Связанная ошибка можно найти здесь.

Большое спасибо всем, кто внес свой вклад в этот ответ.