Improve message when generating error ARGUMENT_TYPE_NOT_ASSIGNABLE for records.

Fixes BUG: #53580

Change-Id: I4c5a7b5147875ced2319ba36a396067a5ce1a657
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/330668
Commit-Queue: Keerti Parthasarathy <keertip@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
This commit is contained in:
Keerti Parthasarathy 2023-10-18 17:56:49 +00:00 committed by Commit Queue
parent 4f438f287d
commit c31be01bbe
6 changed files with 118 additions and 9 deletions

View file

@ -118,10 +118,12 @@ class CompileTimeErrorCode extends AnalyzerErrorCode {
/// Parameters:
/// 0: the name of the actual argument type
/// 1: the name of the expected type
/// 2: additional information, if any, when problem is associated with records
static const CompileTimeErrorCode ARGUMENT_TYPE_NOT_ASSIGNABLE =
CompileTimeErrorCode(
'ARGUMENT_TYPE_NOT_ASSIGNABLE',
"The argument type '{0}' can't be assigned to the parameter type '{1}'.",
"The argument type '{0}' can't be assigned to the parameter type '{1}'. "
"{2}",
hasPublishedDocs: true,
);

View file

@ -98,7 +98,44 @@ mixin ErrorDetectionHelpers {
return;
}
}
if (errorCode == CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE) {
var additionalInfo = <String>[];
if (expectedStaticType is RecordType &&
actualStaticType is RecordType) {
var actualPositionalFields = actualStaticType.positionalFields.length;
var expectedPositionalFields =
expectedStaticType.positionalFields.length;
if (expectedPositionalFields != 0 &&
actualPositionalFields != expectedPositionalFields) {
additionalInfo.add(
'Expected $expectedPositionalFields positional arguments, but got $actualPositionalFields instead.');
}
var actualNamedFieldsLength = actualStaticType.namedFields.length;
var expectedNamedFieldsLength = expectedStaticType.namedFields.length;
if (expectedNamedFieldsLength != 0 &&
actualNamedFieldsLength != expectedNamedFieldsLength) {
additionalInfo.add(
'Expected $expectedNamedFieldsLength named arguments, but got $actualNamedFieldsLength instead.');
}
var namedFields = expectedStaticType.namedFields;
if (namedFields.isNotEmpty) {
for (var field in actualStaticType.namedFields) {
if (!namedFields.any((element) =>
element.name == field.name && field.type == element.type)) {
additionalInfo.add(
'Unexpected named argument `${field.name}` with type `${field.type.getDisplayString(withNullability: true)}`.');
}
}
}
}
errorReporter.reportErrorForNode(
errorCode,
getErrorNode(expression),
[actualStaticType, expectedStaticType, additionalInfo.join(' ')],
computeWhyNotPromotedMessages(expression, whyNotPromoted?.call()),
);
return;
}
errorReporter.reportErrorForNode(
errorCode,
getErrorNode(expression),

View file

@ -644,12 +644,13 @@ CompileTimeErrorCode:
}
```
ARGUMENT_TYPE_NOT_ASSIGNABLE:
problemMessage: "The argument type '{0}' can't be assigned to the parameter type '{1}'."
problemMessage: "The argument type '{0}' can't be assigned to the parameter type '{1}'. {2}"
hasPublishedDocs: true
comment: |-
Parameters:
0: the name of the actual argument type
1: the name of the expected type
2: additional information, if any, when problem is associated with records
documentation: |-
#### Description

View file

@ -104,7 +104,7 @@ main() {
reporter.reportErrorForNode(
CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE,
findNode.simple('x'),
[firstType, secondType],
[firstType, secondType, ''],
);
var error = listener.errors[0];
@ -142,7 +142,7 @@ main() {
reporter.reportErrorForNode(
CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE,
findNode.simple('x'),
[firstType, secondType],
[firstType, secondType, ''],
);
var error = listener.errors[0];
@ -175,7 +175,7 @@ main() {
reporter.reportErrorForNode(
CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE,
findNode.simple('x'),
[fa.variables.type!.type!, fb.variables.type!.type!],
[fa.variables.type!.type!, fb.variables.type!.type!, ''],
);
var error = listener.errors[0];
@ -210,7 +210,7 @@ main() {
reporter.reportErrorForNode(
CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE,
findNode.simple('x'),
[ba.variables.type!.type!, bb.variables.type!.type!],
[ba.variables.type!.type!, bb.variables.type!.type!, ''],
);
var error = listener.errors[0];

View file

@ -225,7 +225,76 @@ void g() {
f((a: 1, b: 2));
}
''', [
error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 44, 12),
error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 44, 12,
messageContains: [
'Expected 2 positional arguments, but got 0 instead.'
]),
]);
}
void test_recordType_namedArguments() async {
await assertErrorsInCode('''
typedef A = ({
int b,
int c,
});
void f(A a){print(a);}
main() {
f((bb:2, c:3));
}
''', [
error(
CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE,
74,
11,
messageContains: ['Unexpected named argument `bb` with type `int`.'],
),
]);
}
void test_recordType_namedArguments_missing() async {
await assertErrorsInCode('''
typedef A = ({
int b,
int c,
});
void f(A a){print(a);}
main() {
f((b:2));
}
''', [
error(
CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE,
74,
5,
messageContains: [
'Expected 2 named arguments, but got 1 instead.',
],
),
]);
}
void test_recordType_positionalArguments() async {
await assertErrorsInCode('''
typedef A = (
int b,
int c,
);
void f(A a){print(a);}
main() {
f((3, 2, 1));
}
''', [
error(CompileTimeErrorCode.ARGUMENT_TYPE_NOT_ASSIGNABLE, 72, 9,
messageContains: [
'Expected 2 positional arguments, but got 3 instead.'
]),
]);
}
}

View file

@ -773,7 +773,7 @@ int Function(int) fromPointer(Pointer<NativeFunction<Int8 Function(Int8)>> p) {
### argument_type_not_assignable
_The argument type '{0}' can't be assigned to the parameter type '{1}'._
_The argument type '{0}' can't be assigned to the parameter type '{1}'. {2}_
#### Description