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:
committed by
commit-bot@chromium.org
parent
5de4830a4e
commit
0b395d26be
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user