Answer from Dart Team is very well.
"The VM behavior is correct, and dart2js isn't implementing it yet."
https://code.google.com/p/dart/issues/detail?id=16047#c5
Also answer from Gilad Bracha.
"FWIW, the spec does not have such a restriction" (RE: class implements an interface with two different type parameters).
https://code.google.com/p/dart/issues/detail?id=14729#c2
Also very well mentioned:
"Unfortunately this is an intentional restriction in dart2js for now. Implementing the same interface with different type arguments has never really worked, so we felt very uncomfortable having people depend on the broken behavior."
https://code.google.com/p/dart/issues/detail?id=14729#c3
This answer fully fits in that the sample code in original question correct and it cannot be compiled currently via dart2js.
P.S.
My thoughts (my jumpers):
I think this problem can be solved in the Dart2JS compiler via better testing of type compatibility but not only via testing the equality of classes.
I think that in this case HasIterator<dynamic>
and HasIterator<IGrouping<TKey, TElement>>
is not the same types (even they the same classes) because they both just implicitly specifies lower and upper bounds of TElement
parameter of HasIterator<TElement>
.
In practice this is more complex that I can explain here but I can add the following.
They not the same types because this expression is true:
HasIterator<dynamic> != HasIterator<IGrouping<TKey, TElement>>
They not conflicts (but implicitly specifies lower and upper bounds) because one from the following expressions is true.
HasIterator<dynamic> is HasIterator<IGrouping<TKey, TElement>>
HasIterator<IGrouping<TKey, TElement>> is HasIterator<dynamic>
Is our case (implicit) lower bound is dynamic
and (implicit) upper bound
is <IGrouping<TKey, TElement>
.
The implicit
term means only resolved at compile time
.
This means that one from them is a subtype of another and compiler must allow both of them in declaration. And in type annotations the compiler must tests parameters on compatibility with both of them (including other super interfaces).
If Dart2JS will test supertypes more thoroughly it can bypass around this problem.
I not want here give sample how this is possible but I think developers know how to solve this problem.