-
Notifications
You must be signed in to change notification settings - Fork 213
IIFE type inference #2820
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
Here is another instance of this issue that is closer to a useful real world example: void main() {
R match_example<R>(
final int t,
final R Function() zero,
final R Function() one,
final R Function() other,
) {
if (t == 0) {
return zero();
} else if (t == 1) {
return one();
} else {
return other();
}
}
List<String> a() {
const value = 7;
return [
"a",
"b",
"c",
...match_example(
value,
() => ["d"],
() => ["e"],
() => [],
),
];
}
List<String> a_with_iife() {
return [
"a",
"b",
"c",
// The element type 'dynamic' can't be assigned to the list type 'String'.
...() {
const value = 7;
return [
...match_example(
value,
() => ["d"],
() => ["e"],
() => [],
),
];
}(),
];
}
a();
a_with_iife();
} The type of the IIFE in Note (related to the support of IIFEs as a language feature): Unfortunately, an analyzer provided refactoring |
@munificent It looks to me like eventually you would like to support the following once records have landed: Foo(
...(
a: ...,
b: ...,
),
) I couldn't find the issue for that feature. I think the inference issue presented here is also related to that feature because being able to do: Foo(
...() {
// Other statements.
return (
a: ...,
b: ...,
);
}(),
) without any type inference issues seems like it would be very useful. I hope you will consider supporting ergonomic IIFEs in your design. |
I think I may have encountered the same issue when I was experimenting with pattern matching. dart-lang/sdk#51395 (comment) |
One thing you could do is to abstract away the immediate invocation: // Use this one to "immediately invoke" your function literals.
X iife<X>(X Function() f) => f();
// This one is just needed in order to see the context type.
X whatever<X>() {
print(X);
return <Never>[] as X;
}
void main() {
// With an actual immediate invocation the returned expression is inferred with context type `dynamic`.
List<int?> xs = (){ return whatever(); }(); // Prints 'dynamic'.
// When using `iife`, the context type is carried over.
List<int?> ys = iife(() => whatever()); // Prints 'List<int?>'.
List<int?> zs = iife(() { return whatever(); }); // Ditto.
} The typing doesn't depend on the choice of |
We don't have the ability to have a context type of "Function which returns X, but I don't know the argument shape". |
I don't think we need to abstract over the shape of the parameter list. The 'IIFE' acronym refers to a function literal which is immediately invoked, that is, X iife<X>(X Function() f) => f();
class Foo<T> {
Foo();
}
void main() {
<Foo<int>>[Foo(), iife(() => Foo())]; // No errors.
} The longer example is similar (omitting X iife<X>(X Function() f) => f();
void main() {
R match_example<R>(
final int t,
final R Function() zero,
final R Function() one,
final R Function() other,
) {
if (t == 0) {
return zero();
} else if (t == 1) {
return one();
} else {
return other();
}
}
List<String> a_with_iife() {
return [
"a",
"b",
"c",
...iife(() { // No errors.
const value = 7;
return [
...match_example(
value,
() => ["d"],
() => ["e"],
() => [],
),
];
}),
];
}
a_with_iife();
} The syntactic cost is obvious, but small (except that |
I agree that the iife function can be used to simulate IIFEs and that it solves the type inference issue that I was referring to, but it can't be used to solve one issue that I forgot to mention. Consider the following: void main() {
inlined();
literal();
function();
}
int inlined() {
int? b;
b = 0;
return b;
}
int literal() {
int? b;
() {
b = 0;
}();
return b;
}
int function() {
int? b;
iife(() {
b = 0;
});
return b;
}
R iife<R>(
final R Function() fn,
) {
return fn();
} The function-expression-based IIFE, and the iife-function-based IIFE fail to compile because the data flow analysis that allows This data flow analysis related issue (in addition to the type inference one) prevents refactoring tools from adding support for wrapping expressions/statements in |
Right, the error about But I'd say that this is a completely different topic, so maybe it belongs in an issue which is specifically about issues with, or improvements of, flow analysis and promotion? |
I agree. I initially did not intend for this issue to include usability improvements related to
Yes, I agree. I will open a separate issue for that example. |
Consider the following program that does not compile because type inference fails to infer
Foo<int>
as the type of the immediately invoked function expression (IIFE):I find IIFEs to be very useful because they allow me to not pollute scopes with names that don't need to be there. I regularly experience type inference issues related to IIFEs. I think it would be great if Dart could have better support for IIFE type inference.
Edit:
See also: #2820 (comment)
Edit: I think that this issue applies to all function literals (i.e.
() {}
,() sync* {}
,() async {}
and() async* {}
because it doesn't look like the type checker needs to depend on their evaluation strategy.The text was updated successfully, but these errors were encountered: