-
Notifications
You must be signed in to change notification settings - Fork 213
Inference should use generic bounds to infer argument types #1761
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
Comments
Related to #1194 . |
Am I missing something? The following compiles just fine, and I think Dart won't infer void something<T extends Object>(void Function(T) c) { }
void main() {
something<Object>((Object arg) {});
something((Object arg) {});
} |
So, we don't have a downward inference hint for If I change the declaration to void something<T extends num>(void Function(T) c) {
print("T = $T, c: ${c.runtimeType}");
}
void main() {
something<int>((arg) {}); // T = int, c: (int) => void
something((arg) {}); // T = num, c: (Object?) => void
} I'm not sure what would happen if we used the bound type as the type of |
The motivating example is trying to write the equivalent of a It must be written as .onError<Object>((error, stackTrace) {
// some cleanup
throw error;
}); Without specifying the |
Here's another issue that seems to call for a similar feature: #3567. |
I filed an issue with a description of the changes to the meta-theory that I believe would be required to improves this here. |
Possibly related: It would be helpful if function argument types could be inferred when the context is a type parameter with a function bound: void main() {
final func = wrap((x, [String? y]) {}); // type omitted on x; would ideally be `int` but is `dynamic`
func(1, "a");
print(func.runtimeType); // (dynamic, [String?]) => Null
func("x", "y"); // no error :(
}
T wrap<T extends void Function(int)>(T t) => t; The equivalent code works fine in TypeScript FWIW: function main() {
const func = wrap((x, y?: string) => {}); // x inferred to be `number`
func(1, "a");
func("x", "y"); // error: string is not assignable to number
}
function wrap<T extends (n: number) => void>(t: T): T {
return t;
} The motivation is not having to specify types over and over for defining a set of related functions (e.g. factories with slightly different sets of arguments); it would be nice if this gave suitable types to T wrap<T extends void Function(int, String, bool)>(T t) => t;
final func1 = wrap((a, b, c, [int? d]) { /* ... */ });
final func2 = wrap((a, b, c, {String? e}) { /* ... */ });
// ... Slightly off topic, but the TypeScript "satisfies" keyword that can be used for a similar purpose (namely, influencing inference of function argument types without setting the context type): type MyFunction = (a: number, b: string, c: boolean) => void;
const func1 = ((a, b, c, d?: number) => { /*...*/ }) satisfies MyFunction;
const func2 = ((a, b, c, e?: string) => { /*...*/ }) satisfies MyFunction; |
I suspect that the inferred types of formal parameters of a function literal are handled in a slightly different way. I created #3695 to discuss a possible improvement in this area. |
I generally don't expect that specifying a generic which exactly matches what would be inferred should impact behavior, but it changes how arguments are inferred.
For example
In both cases the generic
T
takes the valueObject
, however in the latter case thearg
has an inferred type ofObject?
instead ofObject
.cc @leafpetersen
The text was updated successfully, but these errors were encountered: