Dart2JS编译器无法编译代码.这是错误、功能还是限制



我使用Dart2JS编译器1.0.0_r30798版(STABLE)。

示例代码(仅用于引入问题):

这里的真实代码(现在针对dart2js行为进行了更正):https://github.com/mezoni/queries/blob/master/lib/src/queries/lookup.dart

这是Dart语言的可查询集合。

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编译器的以下错误:

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编译器无法编译此代码。

所以,我无法理解:"这是bug、功能还是限制?"。

首先,dart2js不是Dart VM编译器,语言规范适用于它。因为Dart VM和Javascript是不同的语言,所以在非常抽象的情况下可能会发生不同的行为或限制。他们不应该,但他们确实。

话虽如此,我不明白为什么这段代码能够在虚拟机中运行。根据我在Dart中对继承和混合的了解,您对Lookup的定义应该是这样的:

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

因为否则,正如错误消息所说,您将使用不同的类型参数继承HasIterator两次,这当然有点问题——如果您最终将方法添加到HasIterater中,那么应该调用这两个方法中的哪一个?method1(dynamic)还是method1(IGrouping<TKey, TElement>)

飞镖队的回答非常好。

"VM的行为是正确的,dart2js还没有实现它。">

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

还有吉拉德·布拉查的回答。

"FWIW,规范没有这样的限制"(RE:class实现了一个具有两个不同类型参数的接口)。

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

也很好地提到:

"不幸的是,目前这是dart2js中的一个有意限制。用不同类型的参数实现同一个接口从未真正奏效,所以让人们依赖于坏的行为,我们感到非常不舒服。">

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

这个答案完全符合原始问题中的示例代码是正确的,并且目前无法通过dart2js进行编译。

p.S.

我的想法(我的跳投):

我认为这个问题可以在Dart2JS编译器中通过更好的类型兼容性测试来解决,而不仅仅是通过测试类的相等性。

我认为在这种情况下,HasIterator<dynamic>HasIterator<IGrouping<TKey, TElement>>不是相同的类型(即使它们是相同的类),因为它们都只是隐式地指定了HasIterator<TElement>TElement参数的下界和上界。

在实践中,这更为复杂,我可以在这里解释,但我可以添加以下内容。

它们不是相同的类型,因为这个表达式是真的:

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

它们不冲突(但隐式指定下限和上限),因为以下表达式中的一个为true。

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将更彻底地测试超类型,它可以绕过这个问题。

我不想在这里给出这个例子,但我认为开发人员知道如何解决这个问题。

相关内容

  • 没有找到相关文章

最新更新