-
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
pkg/meta: using a function with a @required parameter as tear-off does not warn about missing required parameter #34491
Comments
My guess (?) is this is WAI (working-as-intended), since For example, what about the following cases:
class X1 {
void doThing({@required String name}) {}
}
class Y1 extends X1 {
// Ok? Lint?
void doThing({String name)} {}
}
class X2 {
void doThing({String name}) {}
}
class X2 extends Y2 {
// OK? Lint?
void doThing({@required String name}) {}
} One silly idea to move forward is to introduce a lint, i.e. |
Yeah, this is a good example of why relying on metadata annotations for features like this doesn't give as nice of an experience as baking the feature fully into the language. Because |
What bad situations? |
Here is one: import 'package:meta/meta.dart';
class A {
void doThing() => print('doThing()');
}
class B implements A {
void doThing({@required String name}) => print('doThing($name)');
}
void main() {
B b = B();
A a = b;
// Required not linted... resulting in:
// Runtime error: `name` is null.
a.doThing();
} |
The grammar does not currently allow metadata on the parameter types in a "new style" function type like However, it may be somewhat tricky to support that with an analysis which is an enhanced version of the one we have currently to use this kind of information on function types. We would flag certain casts as violations of "requiredness preservation": void foo1({int i}) {}
void foo2({@required int i}) {}
void Function({@required int i}) f1;
void Function({int i}) f2;
void Function() f3;
main() {
f1 = foo1; // OK, requiredness can be overestimated, no problem.
f2 = foo1; // OK, extended type unchanged.
f3 = foo1; // OK, regular function type upcast.
f1 = foo2; // OK, extended type unchanged.
f2 = foo2; // Flagged as bad, forgets requiredness.
f3 = foo2; // Flagged as bad, forgets required parameter.
} It may be surprising that we are flagging otherwise always-ok transitions like upcasts as bad, and there may be some tricky corners around type variables: Y foo<X extends Y, Y>(X x) => x;
main() {
Function() f = foo(({@required int i}) => i); // Bad!
} It is surprising that the invocation of We can't see at the call site that the execution of There may be an easy and elegant solution, but it hasn't dawned upon me yet. ;-) PS: I don't think this difficulty has anything to do with being part of the language or not, there's nothing stopping the linter from knowing all the things that the type checker knows, and then some, and there's nothing (other than convention) stopping the type checker from seeing metadata. |
Ah, I forgot this: The relationship between |
I was using the meta package for the first time so I was surprised not to see a warning. But after completely reading the dartdoc of
But I am not sure, whether I would have immediately realized that no feedback will be provided by the analyzer when passing methods or functions with At least for my current use case I can just use an |
@matanlurey I assume B extends A? I don't understand why that's a runtime error caused by |
The restriction to only warn for invocations is more accidental than intentional. There isn't any reason, for example, that we couldn't check for cases where a function with a required parameter (such as
Yes, there will always be ways to get around the type system ( |
|
I just tested with |
Dart VM version: 2.1.0-dev.4.0 (Fri Sep 7 16:44:38 2018 +0200) on "windows_x64"
The text was updated successfully, but these errors were encountered: