Update resolution of arguments for named_arguments_anywhere.

Change-Id: I50fb95eba6c9345f452cdf7e38fa9c61c2b371ad
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/220123
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov
2021-11-12 23:27:32 +00:00
committed by commit-bot@chromium.org
parent 5de4830a4e
commit 0b395d26be
3 changed files with 89 additions and 80 deletions
+31 -34
View File
@@ -1045,20 +1045,16 @@ class ResolverVisitor extends ResolverBase with ErrorDetectionHelpers {
var callerType = InferenceContext.getContext(node);
NodeList<Expression> arguments = node.arguments;
if (callerType is FunctionType) {
Map<String, DartType> namedParameterTypes =
callerType.namedParameterTypes;
List<DartType> normalParameterTypes = callerType.normalParameterTypes;
List<DartType> optionalParameterTypes = callerType.optionalParameterTypes;
int normalCount = normalParameterTypes.length;
int optionalCount = optionalParameterTypes.length;
var parameters = callerType.parameters;
var namedParameters = <String, ParameterElement>{};
for (var i = 0; i < parameters.length; i++) {
var parameter = parameters[i];
if (parameter.isNamed) {
namedParameters[parameter.name] = parameter;
}
}
Iterable<Expression> positional =
arguments.takeWhile((l) => l is! NamedExpression);
Iterable<Expression> required = positional.take(normalCount);
Iterable<Expression> optional =
positional.skip(normalCount).take(optionalCount);
Iterable<Expression> named =
arguments.skipWhile((l) => l is! NamedExpression);
var parent = node.parent;
DartType? targetType;
Element? methodElement;
@@ -1072,28 +1068,29 @@ class ResolverVisitor extends ResolverBase with ErrorDetectionHelpers {
//TODO(leafp): Consider using the parameter elements here instead.
//TODO(leafp): Make sure that the parameter elements are getting
// setup correctly with inference.
int index = 0;
for (Expression argument in required) {
var parameterType = normalParameterTypes[index++];
if (targetType != null) {
InferenceContext.setType(
argument,
typeSystem.refineNumericInvocationContext(
targetType, methodElement, invocationContext, parameterType));
} else {
InferenceContext.setType(argument, parameterType);
}
}
index = 0;
for (Expression argument in optional) {
InferenceContext.setType(argument, optionalParameterTypes[index++]);
}
for (Expression argument in named) {
var positionalParameterIndex = 0;
for (var i = 0; i < arguments.length; i++) {
var argument = arguments[i];
ParameterElement? parameter;
if (argument is NamedExpression) {
var type = namedParameterTypes[argument.name.label.name];
if (type != null) {
InferenceContext.setType(argument, type);
parameter = namedParameters[argument.name.label.name];
} else {
while (positionalParameterIndex < parameters.length) {
parameter = parameters[positionalParameterIndex++];
if (!parameter.isNamed) {
break;
}
}
}
if (parameter != null) {
var parameterType = parameter.type;
if (targetType != null) {
InferenceContext.setType(
argument,
typeSystem.refineNumericInvocationContext(targetType,
methodElement, invocationContext, parameterType));
} else {
InferenceContext.setType(argument, parameterType);
}
}
}
@@ -305,42 +305,48 @@ main() {
test_namedArgument_anywhere() async {
await assertNoErrorsInCode('''
class A {
A(int a, double b, {bool? c, bool? d});
class A {}
class B {}
class C {}
class D {}
class X {
X(A a, B b, {C? c, D? d});
}
T g1<T>() => throw 0;
T g2<T>() => throw 0;
T g3<T>() => throw 0;
T g4<T>() => throw 0;
void f() {
A(0, c: true, 1.2, d: true);
X(g1(), c: g3(), g2(), d: g4());
}
''');
assertInstanceCreation(
findNode.instanceCreation('A(0'),
findElement.class_('A'),
'A',
findNode.instanceCreation('X(g'),
findElement.class_('X'),
'X',
);
assertParameterElement(
findNode.integerLiteral('0'),
findElement.parameter('a'),
);
var g1 = findNode.methodInvocation('g1()');
assertType(g1, 'A');
assertParameterElement(g1, findElement.parameter('a'));
assertParameterElement(
findNode.doubleLiteral('1.2'),
findElement.parameter('b'),
);
var g2 = findNode.methodInvocation('g2()');
assertType(g2, 'B');
assertParameterElement(g2, findElement.parameter('b'));
assertParameterElement(
findNode.namedExpression('c: true'),
findElement.parameter('c'),
);
assertNamedParameterRef('c: true', 'c');
var named_g3 = findNode.namedExpression('c: g3()');
assertType(named_g3.expression, 'C?');
assertParameterElement(named_g3, findElement.parameter('c'));
assertNamedParameterRef('c:', 'c');
assertParameterElement(
findNode.namedExpression('d: true'),
findElement.parameter('d'),
);
assertNamedParameterRef('d: true', 'd');
var named_g4 = findNode.namedExpression('d: g4()');
assertType(named_g4.expression, 'D?');
assertParameterElement(named_g4, findElement.parameter('d'));
assertNamedParameterRef('d:', 'd');
}
test_typeAlias_generic_class_generic_named_infer_all() async {
@@ -2865,40 +2865,46 @@ void f<T extends A, U extends B>(T a) {
test_namedArgument_anywhere() async {
await assertNoErrorsInCode('''
void foo(int a, double b, {bool? c, bool? d}) {}
class A {}
class B {}
class C {}
class D {}
void foo(A a, B b, {C? c, D? d}) {}
T g1<T>() => throw 0;
T g2<T>() => throw 0;
T g3<T>() => throw 0;
T g4<T>() => throw 0;
void f() {
foo(0, c: true, 1.2, d: true);
foo(g1(), c: g3(), g2(), d: g4());
}
''');
assertMethodInvocation(
findNode.methodInvocation('foo(0'),
findNode.methodInvocation('foo(g'),
findElement.topFunction('foo'),
'void Function(int, double, {bool? c, bool? d})',
'void Function(A, B, {C? c, D? d})',
);
assertParameterElement(
findNode.integerLiteral('0'),
findElement.parameter('a'),
);
var g1 = findNode.methodInvocation('g1()');
assertType(g1, 'A');
assertParameterElement(g1, findElement.parameter('a'));
assertParameterElement(
findNode.doubleLiteral('1.2'),
findElement.parameter('b'),
);
var g2 = findNode.methodInvocation('g2()');
assertType(g2, 'B');
assertParameterElement(g2, findElement.parameter('b'));
assertParameterElement(
findNode.namedExpression('c: true'),
findElement.parameter('c'),
);
assertNamedParameterRef('c: true', 'c');
var named_g3 = findNode.namedExpression('c: g3()');
assertType(named_g3.expression, 'C?');
assertParameterElement(named_g3, findElement.parameter('c'));
assertNamedParameterRef('c:', 'c');
assertParameterElement(
findNode.namedExpression('d: true'),
findElement.parameter('d'),
);
assertNamedParameterRef('d: true', 'd');
var named_g4 = findNode.namedExpression('d: g4()');
assertType(named_g4.expression, 'D?');
assertParameterElement(named_g4, findElement.parameter('d'));
assertNamedParameterRef('d:', 'd');
}
test_nullShorting_cascade_firstMethodInvocation() async {