Discard parens before deciding whether an invocation argument is a function literal.

This extends the fix for
https://github.com/dart-lang/language/issues/731 (improved inference
for fold etc.) to cover situations where the function literal passed
to an invocation is enclosed in (unnecessary) parentheses.

Change-Id: I5eb40cf73336612e241a930122f8ae7b1c25bb2a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/241021
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Paul Berry <paulberry@google.com>
This commit is contained in:
Paul Berry 2022-04-12 16:25:22 +00:00 committed by Commit Bot
parent 03fd724529
commit 30f0e0f4d5
4 changed files with 113 additions and 0 deletions

View file

@ -528,6 +528,7 @@ class InvocationInferrer<Node extends AstNodeImpl> {
value = argument;
parameterKey = unnamedArgumentIndex++;
}
value = value.unParenthesized;
parameter = parameterMap[parameterKey];
if (resolver.isInferenceUpdate1Enabled &&
value is FunctionExpressionImpl) {

View file

@ -205,6 +205,58 @@ test() => f(t: 0, g: (x) {});
_isEnabled ? 'int' : 'Object?');
}
test_horizontal_inference_simple_parenthesized() async {
await assertNoErrorsInCode('''
void f<T>(T t, void Function(T) g) {}
test() => f(0, ((x) {}));
''');
assertType(
findNode.methodInvocation('f(').typeArgumentTypes!.single, 'int');
assertType(findNode.methodInvocation('f(').staticInvokeType,
'void Function(int, void Function(int))');
assertType(findNode.simpleParameter('x').declaredElement!.type,
_isEnabled ? 'int' : 'Object?');
}
test_horizontal_inference_simple_parenthesized_named() async {
await assertNoErrorsInCode('''
void f<T>({required T t, required void Function(T) g}) {}
test() => f(t: 0, g: ((x) {}));
''');
assertType(
findNode.methodInvocation('f(').typeArgumentTypes!.single, 'int');
assertType(findNode.methodInvocation('f(').staticInvokeType,
'void Function({required void Function(int) g, required int t})');
assertType(findNode.simpleParameter('x').declaredElement!.type,
_isEnabled ? 'int' : 'Object?');
}
test_horizontal_inference_simple_parenthesized_twice() async {
await assertNoErrorsInCode('''
void f<T>(T t, void Function(T) g) {}
test() => f(0, (((x) {})));
''');
assertType(
findNode.methodInvocation('f(').typeArgumentTypes!.single, 'int');
assertType(findNode.methodInvocation('f(').staticInvokeType,
'void Function(int, void Function(int))');
assertType(findNode.simpleParameter('x').declaredElement!.type,
_isEnabled ? 'int' : 'Object?');
}
test_horizontal_inference_simple_parenthesized_twice_named() async {
await assertNoErrorsInCode('''
void f<T>({required T t, required void Function(T) g}) {}
test() => f(t: 0, g: (((x) {})));
''');
assertType(
findNode.methodInvocation('f(').typeArgumentTypes!.single, 'int');
assertType(findNode.methodInvocation('f(').staticInvokeType,
'void Function({required void Function(int) g, required int t})');
assertType(findNode.simpleParameter('x').declaredElement!.type,
_isEnabled ? 'int' : 'Object?');
}
test_horizontal_inference_unnecessary_due_to_explicit_parameter_type() async {
// In this example, there is no need for horizontal type inference because
// the type of `x` is explicit.

View file

@ -59,4 +59,34 @@ testUnnecessaryDueToExplicitParameterTypeNamed(
a.expectStaticType<Exactly<int?>>();
}
testParenthesized(void Function<T>(T, void Function(T)) f) {
f(0, ((x) {
x.expectStaticType<Exactly<Object?>>();
}));
}
testParenthesizedNamed(
void Function<T>({required T a, required void Function(T) b}) f) {
f(
a: 0,
b: ((x) {
x.expectStaticType<Exactly<Object?>>();
}));
}
testParenthesizedTwice(void Function<T>(T, void Function(T)) f) {
f(0, (((x) {
x.expectStaticType<Exactly<Object?>>();
})));
}
testParenthesizedTwiceNamed(
void Function<T>({required T a, required void Function(T) b}) f) {
f(
a: 0,
b: (((x) {
x.expectStaticType<Exactly<Object?>>();
})));
}
main() {}

View file

@ -122,4 +122,34 @@ testUnnecessaryDueToExplicitParameterTypeNamed(
a.expectStaticType<Exactly<int?>>();
}
testParenthesized(void Function<T>(T, void Function(T)) f) {
f(0, ((x) {
x.expectStaticType<Exactly<int>>();
}));
}
testParenthesizedNamed(
void Function<T>({required T a, required void Function(T) b}) f) {
f(
a: 0,
b: ((x) {
x.expectStaticType<Exactly<int>>();
}));
}
testParenthesizedTwice(void Function<T>(T, void Function(T)) f) {
f(0, (((x) {
x.expectStaticType<Exactly<int>>();
})));
}
testParenthesizedTwiceNamed(
void Function<T>({required T a, required void Function(T) b}) f) {
f(
a: 0,
b: (((x) {
x.expectStaticType<Exactly<int>>();
})));
}
main() {}