-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inconsistent runtime type errors for certain dynamic generic function invocations. #37704
Comments
CFE behavior is correct to the best of my knowledge. Given the code like this:
If |
Agreeing with @mraleph about the issue, I think it's worth considering the example design as well. The examples fails at the evaluation of The basic issue is that covariant generics is an unsound rule for a class that contains members whose type is not covariant; the type of But you could use a different approach which won't create the situation where you get a caller-side check at all (this is just a manual emulation of the approach proposed in dart-lang/language#296): class Foo<T> {
Foo();
}
typedef Foo FooOperation<T>([T value]);
// Specify a common supertype of `FooOperation<T>` for all `T`. PS: Change `Null`
// to `Never` when we switch to non-nullable types.
typedef Foo FooBound([Null value]);
class FooOperator<T> {
FooBound op; // Use the common supertype.
// Specify the parameter type, such that we get the same type check as before
// when an instance of `FooOperator<T>` is created.
FooOperator(FooOperator<T> this.op);
}
Foo<String> start() {
var operation = FooOperator<String>(([_]) => Foo<String>());
return operation.op();
}
main() {
start();
} With this approach you avoid using a non-covariant type for The trade-off is that In the example it is actually not necessary, but it would be needed if you had chosen to pass an argument, e.g., Another approach that might actually be the most convenient in practice would be to make class Foo<T> {
Foo();
}
typedef Foo FooOperation<T>([T value]);
class FooOperator<T> {
FooOperation<T> _op;
FooOperator(this._op);
Foo op([T value]) => _op(value);
}
Foo<String> start() {
var operation = FooOperator<String>(([_]) => Foo<String>());
return operation.op();
}
main() {
start();
} The invocation In order to avoid the dynamic checks entirely you would need to specify some kind of invariance (or contravariance, if you're only using contravariant-typed members like |
@Markzipan - can you clarify - are you seeing different behavior with DDC and DDK? |
Yes - DDK emits the proper error here. So there might be a few areas in google3 to fix up. |
Thanks. Analyzer DDC should be injecting a check here as well, but marking p4. |
@Markzipan - shall we close this? |
Yep - issue resolved by fixing internal tests. |
The above snippet passes in DDC but fails in CFE with:
It seems that DDC is missing the function type check (i.e., dynamicToFooOfString._check()).
What's the expected behavior here? This pattern's being used quite a bit internally, so making this stricter will require some cleanup.
The text was updated successfully, but these errors were encountered: