Augment. Report augmentationPositionalFormalParameterName.

PS1: rename the test file.

Change-Id: I0e38a25c9c6d2b573766eb9a088fadbc8a4fc5b4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/509202
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
Konstantin Shcheglov
2026-06-04 12:52:55 -07:00
parent 46bb00bfae
commit 4da9a9133e
7 changed files with 294 additions and 10 deletions
@@ -255,6 +255,8 @@ augmentation_of_mixin_application_class:
status: needsEvaluation
augmentation_optional_positional_formal_parameter_count:
status: needsEvaluation
augmentation_positional_formal_parameter_name:
status: needsEvaluation
augmentation_required_positional_formal_parameter_count:
status: needsEvaluation
augmentation_return_type_mismatch:
@@ -1073,6 +1073,27 @@ augmentationOptionalPositionalFormalParameterCount = DiagnosticWithArguments(
expectedTypes: [ExpectedType.int, ExpectedType.int],
);
/// Parameters:
/// String expectedName: the name from a preceding declaration.
/// String actualName: the name in the augmentation.
const DiagnosticWithArguments<
LocatableDiagnostic Function({
required String expectedName,
required String actualName,
})
>
augmentationPositionalFormalParameterName = DiagnosticWithArguments(
name: 'augmentation_positional_formal_parameter_name',
problemMessage:
"The parameter name '{1}' must either match the name '{0}' from a "
"preceding declaration or be '_'.",
correctionMessage: "Try changing the name to '{0}', or changing it to '_'.",
type: DiagnosticType.COMPILE_TIME_ERROR,
uniqueName: 'augmentation_positional_formal_parameter_name',
withArguments: _withArgumentsAugmentationPositionalFormalParameterName,
expectedTypes: [ExpectedType.string, ExpectedType.string],
);
/// Parameters:
/// int expectedCount: the number of required positional formal parameters in
/// the declaration.
@@ -18739,6 +18760,16 @@ _withArgumentsAugmentationOptionalPositionalFormalParameterCount({
);
}
LocatableDiagnostic _withArgumentsAugmentationPositionalFormalParameterName({
required String expectedName,
required String actualName,
}) {
return LocatableDiagnosticImpl(
diag.augmentationPositionalFormalParameterName,
[expectedName, actualName],
);
}
LocatableDiagnostic
_withArgumentsAugmentationRequiredPositionalFormalParameterCount({
required int expectedCount,
@@ -80,6 +80,7 @@ const List<DiagnosticCode> diagnosticCodeValues = [
diag.augmentationOfDifferentDeclarationKind,
diag.augmentationOfMixinApplicationClass,
diag.augmentationOptionalPositionalFormalParameterCount,
diag.augmentationPositionalFormalParameterName,
diag.augmentationRequiredPositionalFormalParameterCount,
diag.augmentationReturnTypeMismatch,
diag.augmentationTypeParameterBound,
@@ -2793,6 +2793,13 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
.where((parameter) => parameter.isRequiredPositional)
.length;
var firstOptionalPositionalCount = firstParameters
.where((parameter) => parameter.isOptionalPositional)
.length;
var currentOptionalPositionalCount = currentParameters
.where((parameter) => parameter.isOptionalPositional)
.length;
FormalParameter? formalParameterAtPositionalIndex(int index) {
return formalParameterList.parameters
.where((parameter) => parameter.isPositional)
@@ -2838,13 +2845,6 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
),
);
} else {
var firstOptionalPositionalCount = firstParameters
.where((parameter) => parameter.isOptionalPositional)
.length;
var currentOptionalPositionalCount = currentParameters
.where((parameter) => parameter.isOptionalPositional)
.length;
if (currentOptionalPositionalCount < firstOptionalPositionalCount) {
diagnosticReporter.report(
diag.augmentationOptionalPositionalFormalParameterCount
@@ -2883,6 +2883,57 @@ class ErrorVerifier extends RecursiveAstVisitor<void>
}
}
// Positional parameter names can be `_`, but every non-wildcard name must
// match all preceding non-wildcard declarations for the same parameter.
if (currentRequiredPositionalCount == firstRequiredPositionalCount &&
currentOptionalPositionalCount == firstOptionalPositionalCount) {
for (var formalParameter in formalParameterList.parameters) {
if (!formalParameter.isPositional) {
continue;
}
var currentParameter = formalParameter.declaredFragment;
if (currentParameter is! FormalParameterFragmentImpl ||
currentParameter.isOriginOtherFragmentOfEnclosing) {
continue;
}
var currentName = currentParameter.name;
if (currentName == null || currentName == '_') {
continue;
}
for (var precedingParameter in currentParameter.precedingFragments) {
if (precedingParameter.isOriginOtherFragmentOfEnclosing ||
precedingParameter.nameOffset == null) {
continue;
}
var precedingName = precedingParameter.name;
if (precedingName == null ||
precedingName == '_' ||
precedingName == currentName) {
continue;
}
diagnosticReporter.report(
diag.augmentationPositionalFormalParameterName
.withArguments(
expectedName: precedingName,
actualName: currentName,
)
.withContextMessages([
?precedingParameter.contextMessageAt(
'The preceding declaration is here.',
),
])
.at(formalParameterErrorEntity(formalParameter)),
);
break;
}
}
}
var firstNamedParametersByName = <String, FormalParameterFragmentImpl>{};
for (var parameter in firstParameters) {
var name = parameter.name;
+9
View File
@@ -1857,6 +1857,15 @@ CompileTimeErrorCode:
problemMessage: "The augmentation has #actualCount optional positional formal parameters, but the declaration has #expectedCount."
correctionMessage: Try changing the augmentation's formal parameters to match the declaration.
hasPublishedDocs: false
augmentationPositionalFormalParameterName:
type: compileTimeError
parameters:
String expectedName: the name from a preceding declaration.
String actualName: the name in the augmentation.
experiment: augmentations
problemMessage: "The parameter name '#actualName' must either match the name '#expectedName' from a preceding declaration or be '_'."
correctionMessage: "Try changing the name to '#expectedName', or changing it to '_'."
hasPublishedDocs: false
augmentationOfDifferentDeclarationKind:
type: compileTimeError
parameters:
@@ -9,11 +9,190 @@ import '../dart/resolution/node_text_expectations.dart';
main() {
defineReflectiveSuite(() {
defineReflectiveTests(AugmentationFormalParameterNameTest);
defineReflectiveTests(AugmentationFormalParameterShapeTest);
defineReflectiveTests(UpdateNodeTextExpectations);
});
}
@reflectiveTest
class AugmentationFormalParameterNameTest extends PubPackageResolutionTest {
test_class_constructor_fP1__rP2() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
final int p1;
A(this.p1);
// ^^
// [context 1] The preceding declaration is here.
augment A(int p2);
// ^^
// [diag.augmentationPositionalFormalParameterName][context 1] The parameter name 'p2' must either match the name 'p1' from a preceding declaration or be '_'.
}
''');
}
test_class_constructor_sp1__rp2() async {
await resolveTestCodeWithDiagnostics(r'''
class A {
A([int? p1]);
}
class B extends A {
B([super.p1]);
// ^^
// [context 1] The preceding declaration is here.
augment B([int? p2]);
// ^^
// [diag.augmentationPositionalFormalParameterName][context 1] The parameter name 'p2' must either match the name 'p1' from a preceding declaration or be '_'.
}
''');
}
test_class_instanceMethod_rP__x__y() async {
await resolveTestCodeWithDiagnostics(r'''
abstract class A {
void foo(int x);
// ^
// [context 1] The preceding declaration is here.
augment void foo(int y) {}
// ^
// [diag.augmentationPositionalFormalParameterName][context 1] The parameter name 'y' must either match the name 'x' from a preceding declaration or be '_'.
}
''');
}
test_topLevelFunction_rP__wildcard__x__wildcard() async {
await resolveTestCodeWithDiagnostics(r'''
void f(int _);
augment void f(int x);
augment void f(int _) {}
''');
}
test_topLevelFunction_rP__wildcard__x__y() async {
await resolveTestCodeWithDiagnostics(r'''
void f(int _);
augment void f(int x);
// ^
// [context 1] The preceding declaration is here.
augment void f(int y) {}
// ^
// [diag.augmentationPositionalFormalParameterName][context 1] The parameter name 'y' must either match the name 'x' from a preceding declaration or be '_'.
''');
}
test_topLevelFunction_rP__x__wildcard() async {
await resolveTestCodeWithDiagnostics(r'''
void f(int x);
augment void f(int _) {}
''');
}
test_topLevelFunction_rp__x__wildcard() async {
await resolveTestCodeWithDiagnostics(r'''
void f([int? x]);
augment void f([int? _]) {}
''');
}
test_topLevelFunction_rP__x__wildcard__x() async {
await resolveTestCodeWithDiagnostics(r'''
void f(int x);
augment void f(int _);
augment void f(int x) {}
''');
}
test_topLevelFunction_rP__x__wildcard__y() async {
await resolveTestCodeWithDiagnostics(r'''
void f(int x);
// ^
// [context 1] The preceding declaration is here.
augment void f(int _);
augment void f(int y) {}
// ^
// [diag.augmentationPositionalFormalParameterName][context 1] The parameter name 'y' must either match the name 'x' from a preceding declaration or be '_'.
''');
}
test_topLevelFunction_rP__x__y() async {
await resolveTestCodeWithDiagnostics(r'''
void f(int x);
// ^
// [context 1] The preceding declaration is here.
augment void f(int y) {}
// ^
// [diag.augmentationPositionalFormalParameterName][context 1] The parameter name 'y' must either match the name 'x' from a preceding declaration or be '_'.
''');
}
test_topLevelFunction_rp__x__y() async {
await resolveTestCodeWithDiagnostics(r'''
void f([int? x]);
// ^
// [context 1] The preceding declaration is here.
augment void f([int? y]) {}
// ^
// [diag.augmentationPositionalFormalParameterName][context 1] The parameter name 'y' must either match the name 'x' from a preceding declaration or be '_'.
''');
}
test_topLevelFunction_rP_rP__x_y__a_b() async {
await resolveTestCodeWithDiagnostics(r'''
void f(int x, int y);
// ^
// [context 1] The preceding declaration is here.
// ^
// [context 2] The preceding declaration is here.
augment void f(int a, int b) {}
// ^
// [diag.augmentationPositionalFormalParameterName][context 1] The parameter name 'a' must either match the name 'x' from a preceding declaration or be '_'.
// ^
// [diag.augmentationPositionalFormalParameterName][context 2] The parameter name 'b' must either match the name 'y' from a preceding declaration or be '_'.
''');
}
test_topLevelFunction_rP_rp__x_y__x_z() async {
await resolveTestCodeWithDiagnostics(r'''
void f(int x, [int? y]);
// ^
// [context 1] The preceding declaration is here.
augment void f(int x, [int? z]) {}
// ^
// [diag.augmentationPositionalFormalParameterName][context 1] The parameter name 'z' must either match the name 'y' from a preceding declaration or be '_'.
''');
}
test_topLevelSetter_rP__wildcard__x__y() async {
await resolveTestCodeWithDiagnostics(r'''
set foo(int _);
augment set foo(int x);
// ^
// [context 1] The preceding declaration is here.
augment set foo(int y) {}
// ^
// [diag.augmentationPositionalFormalParameterName][context 1] The parameter name 'y' must either match the name 'x' from a preceding declaration or be '_'.
''');
}
test_topLevelSetter_rP__x__wildcard() async {
await resolveTestCodeWithDiagnostics(r'''
set foo(int x);
augment set foo(int _) {}
''');
}
test_topLevelSetter_rP__x__y() async {
await resolveTestCodeWithDiagnostics(r'''
set foo(int x);
// ^
// [context 1] The preceding declaration is here.
augment set foo(int y) {}
// ^
// [diag.augmentationPositionalFormalParameterName][context 1] The parameter name 'y' must either match the name 'x' from a preceding declaration or be '_'.
''');
}
}
@reflectiveTest
class AugmentationFormalParameterShapeTest extends PubPackageResolutionTest {
test_class_constructor_rP1__rP1_rP2() async {
@@ -198,6 +377,17 @@ augment void f(int? p1, [int? p2, int? p3]) {}
''');
}
test_topLevelFunction_rP1__rP2_rP3_nameMismatch() async {
await resolveTestCodeWithDiagnostics(r'''
void f(int p1);
// ^
// [context 1] The declaration being augmented.
augment void f(int p2, int p3) {}
// ^^
// [diag.augmentationRequiredPositionalFormalParameterCount][context 1] The augmentation has 2 required positional formal parameters, but the declaration has 1.
''');
}
test_topLevelFunction_rP1_rn1__rP1() async {
await resolveTestCodeWithDiagnostics(r'''
void f(int? p1, {int? n1});
@@ -42,8 +42,8 @@ import 'async_keyword_used_as_identifier_test.dart'
as async_keyword_used_as_identifier;
import 'augmentation_extends_clause_already_present_test.dart'
as augmentation_extends_clause_already_present;
import 'augmentation_formal_parameter_shape_test.dart'
as augmentation_formal_parameter_shape;
import 'augmentation_formal_parameter_test.dart'
as augmentation_formal_parameter;
import 'augmentation_modifier_extra_test.dart' as augmentation_modifier_extra;
import 'augmentation_modifier_missing_test.dart'
as augmentation_modifier_missing;
@@ -993,7 +993,7 @@ main() {
async_for_in_wrong_context.main();
async_keyword_used_as_identifier.main();
augmentation_extends_clause_already_present.main();
augmentation_formal_parameter_shape.main();
augmentation_formal_parameter.main();
augmentation_modifier_extra.main();
augmentation_modifier_missing.main();
augmentation_of_different_declaration_kind.main();