Компилятор Dart2JS не может скомпилировать код. Это ошибка, функция или ограничение?

Я использую компилятор Dart2JS версии 1.0.0_r30798 (STABLE).

Пример кода (только для ознакомления с проблемой):

Настоящий код здесь (теперь исправлено поведение dart2js): https://github.com/mezoni/queries/blob/master/lib/src/queries/lookup.dart

Это часть коллекции Queryable для языка дартс.

class ILookup<TKey, TElement> implements IEnumerable<IGrouping<TKey, TElement>> {
}

class Lookup<TKey, TElement> extends Object with Enumerable implements ILookup<TKey, TElement> {
}

class IEnumerable<T> implements HasIterator<T> {
}

class HasIterator<T> {
}

class IGrouping<TKey, TElement> implements IEnumerable<TKey> {
}

class Enumerable<T> implements IEnumerable<T> {
}

void main() {
  var obj = new Lookup();
  print(obj);
}

Этот код генерирует следующую ошибку Google Dart dart2js Compiler:

 Internal Error: Inheritance of the same class with different type arguments is not
 supported: Both HasIterator<dynamic> and HasIterator<IGrouping<TKey, TElement>> are
 supertypes of Lookup<TKey, TElement>.
 class Lookup<TKey, TElement> extends Object with Enumerable implements ILookup<TKey,
 TElement> {

 ^^^^^
 Error: Compilation failed.

Это dart2js Компилятор не может скомпилировать этот код.

Итак, я не могу понять: "Это ошибка, функция или ограничение?".

2 ответа

Решение

Ответ от Dart Team очень хороший.

"Поведение виртуальной машины правильное, и dart2js пока не реализует ее".

https://code.google.com/p/dart/issues/detail?id=16047

Также ответ от Гилада Брача.

"FWIW, спецификация не имеет такого ограничения" (RE: класс реализует интерфейс с двумя различными параметрами типа).

https://code.google.com/p/dart/issues/detail?id=14729

Также очень хорошо упомянуто:

"К сожалению, на данный момент это намеренное ограничение в dart2js. Реализация одного и того же интерфейса с аргументами разных типов никогда не работала, поэтому мы чувствовали себя очень неловко, когда люди зависели от нарушенного поведения".

https://code.google.com/p/dart/issues/detail?id=14729

Этот ответ полностью соответствует тому, что пример кода в оригинальном вопросе верен, и в настоящее время его нельзя скомпилировать с помощью dart2js.

PS

Мои мысли (мои прыгуны):

Я думаю, что эта проблема может быть решена в компиляторе Dart2JS с помощью лучшего тестирования совместимости типов, но не только путем проверки равенства классов.

Я думаю, что в этом случае HasIterator<dynamic> а также HasIterator<IGrouping<TKey, TElement>> это не одни и те же типы (даже те же классы), потому что они оба неявно задают нижнюю и верхнюю границы TElement параметр HasIterator<TElement>,

На практике это более сложно, что я могу объяснить здесь, но я могу добавить следующее.

Они не одного типа, потому что это выражение верно:

HasIterator<dynamic> != HasIterator<IGrouping<TKey, TElement>>

Они не конфликтуют (но неявно задают нижнюю и верхнюю границы), поскольку одно из следующих выражений является истинным.

HasIterator<dynamic> is HasIterator<IGrouping<TKey, TElement>>
HasIterator<IGrouping<TKey, TElement>> is HasIterator<dynamic>

Является ли наш случай (неявный) нижней границей dynamic и (неявный) верхний bound является <IGrouping<TKey, TElement>,

implicit термин означает только resolved at compile time,

Это означает, что один из них является подтипом другого, и компилятор должен разрешить их обоих в объявлении. А в аннотациях типов компилятор должен тестировать параметры на совместимость с ними обоими (включая другие суперинтерфейсы).

Если Dart2JS будет тестировать супертипы более тщательно, это может обойти эту проблему.

Я не хочу здесь приводить пример, как это возможно, но я думаю, что разработчики знают, как решить эту проблему.

Во-первых, dart2js НЕ является компилятором Dart VM, к которому применима языковая спецификация. Поскольку Dart VM и Javascript - это разные языки, в очень абстрактных угловых случаях может быть разное поведение или ограничения. Они не должны, но они делают.

При этом я не понимаю, почему этот код в первую очередь может работать на ВМ. Согласно всему, что я знаю о наследовании и миксинах в Dart, ваше определение Lookup должен выглядеть так:

class Lookup<TKey, TElement> extends Object with Enumerable<IGrouping<TKey, TElement>> implements ILookup<TKey, TElement>`

Потому что в противном случае, как говорится в сообщении об ошибке, вы бы наследовали HasIterator два раза с разными параметрами типа, что, конечно, является небольшой проблемой - если вы наконец добавите методы в HasIterator, какой из этих двух должен быть вызван? method1(dynamic) или же method1(IGrouping<TKey, TElement>)?

Другие вопросы по тегам