Report a few errors for super-formal parameters in explicit super-constructor invocation.

Change-Id: I75cdc08ab26fba01fb44f387737ee44d6b09eaa8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/225980
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 77326fb..a3ae779 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -365,6 +365,8 @@
   CompileTimeErrorCode.PART_OF_DIFFERENT_LIBRARY,
   CompileTimeErrorCode.PART_OF_NON_PART,
   CompileTimeErrorCode.PART_OF_UNNAMED_LIBRARY,
+  CompileTimeErrorCode
+      .POSITIONAL_SUPER_FORMAL_PARAMETER_WITH_POSITIONAL_ARGUMENT,
   CompileTimeErrorCode.PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER,
   CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
   CompileTimeErrorCode.PREFIX_SHADOWED_BY_LOCAL_DECLARATION,
@@ -403,6 +405,8 @@
   CompileTimeErrorCode.SHARED_DEFERRED_PREFIX,
   CompileTimeErrorCode.SPREAD_EXPRESSION_FROM_DEFERRED_LIBRARY,
   CompileTimeErrorCode.STATIC_ACCESS_TO_INSTANCE_MEMBER,
+  CompileTimeErrorCode.SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_NAMED,
+  CompileTimeErrorCode.SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_POSITIONAL,
   CompileTimeErrorCode.SUPER_IN_EXTENSION,
   CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT,
   CompileTimeErrorCode.SUPER_IN_REDIRECTING_CONSTRUCTOR,
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 0a2341a..eabe7ee 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -5482,14 +5482,17 @@
       if (superConstructor != null) {
         var superParameters = superConstructor.parameters;
         if (isNamed) {
-          return superParameters.firstWhereOrNull((e) => e.name == name);
+          return superParameters
+              .firstWhereOrNull((e) => e.isNamed && e.name == name);
         } else {
+          var positionalSuperParameters =
+              superParameters.where((e) => e.isPositional).toList();
           var index = enclosingElement.parameters
               .whereType<SuperFormalParameterElementImpl>()
               .toList()
               .indexOf(this);
-          if (index >= 0 && index < superParameters.length) {
-            return superParameters[index];
+          if (index >= 0 && index < positionalSuperParameters.length) {
+            return positionalSuperParameters[index];
           }
         }
       }
diff --git a/pkg/analyzer/lib/src/error/codes.g.dart b/pkg/analyzer/lib/src/error/codes.g.dart
index 0f00d43..5f42ff2 100644
--- a/pkg/analyzer/lib/src/error/codes.g.dart
+++ b/pkg/analyzer/lib/src/error/codes.g.dart
@@ -11628,6 +11628,20 @@
   );
 
   /**
+   * No parameters.
+   */
+  static const CompileTimeErrorCode
+      POSITIONAL_SUPER_FORMAL_PARAMETER_WITH_POSITIONAL_ARGUMENT =
+      CompileTimeErrorCode(
+    'POSITIONAL_SUPER_FORMAL_PARAMETER_WITH_POSITIONAL_ARGUMENT',
+    "Positional super-formal parameters can't be used when the "
+        "super-constructor invocation has a positional argument.",
+    correctionMessage:
+        "Try removing the 'super' modifier, or changing the super-constructor "
+        "to use named parameters.",
+  );
+
+  /**
    * Parameters:
    * 0: the name of the prefix
    */
@@ -13078,6 +13092,30 @@
   );
 
   /**
+   * No parameters.
+   */
+  static const CompileTimeErrorCode
+      SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_NAMED = CompileTimeErrorCode(
+    'SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_NAMED',
+    "No associated named super-constructor parameter.",
+    correctionMessage: "Try changing the name to the name of an existing named "
+        "super-constructor parameter, or creating such named parameter.",
+  );
+
+  /**
+   * No parameters.
+   */
+  static const CompileTimeErrorCode
+      SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_POSITIONAL =
+      CompileTimeErrorCode(
+    'SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_POSITIONAL',
+    "No associated positional super-constructor parameter.",
+    correctionMessage:
+        "Try using named parameters instead, or adding more positional "
+        "parameters to the super-constructor.",
+  );
+
+  /**
    * 7.6.1 Generative Constructors: Let <i>k</i> be a generative constructor. It
    * is a compile-time error if a generative constructor of class Object
    * includes a superinitializer.
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index c430007..344c5e7 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -406,7 +406,11 @@
       return;
     }
     var argumentList = node.argumentList;
-    var parameters = _resolveArgumentsToFunction(argumentList, element);
+    var parameters = _resolveArgumentsToFunction(
+      argumentList,
+      element,
+      enclosingConstructor: node.thisOrAncestorOfType<ConstructorDeclaration>(),
+    );
     if (parameters != null) {
       argumentList.correspondingStaticParameters = parameters;
     }
@@ -446,12 +450,19 @@
   /// cannot be matched to a parameter. Return the parameters that correspond to
   /// the arguments, or `null` if no correspondence could be computed.
   List<ParameterElement?>? _resolveArgumentsToFunction(
-      ArgumentList argumentList, ExecutableElement? executableElement) {
+    ArgumentList argumentList,
+    ExecutableElement? executableElement, {
+    ConstructorDeclaration? enclosingConstructor,
+  }) {
     if (executableElement == null) {
       return null;
     }
     List<ParameterElement> parameters = executableElement.parameters;
-    return _resolveArgumentsToParameters(argumentList, parameters);
+    return _resolveArgumentsToParameters(
+      argumentList,
+      parameters,
+      enclosingConstructor: enclosingConstructor,
+    );
   }
 
   /// Given an [argumentList] and the [parameters] related to the element that
@@ -460,9 +471,16 @@
   /// the arguments cannot be matched to a parameter. Return the parameters that
   /// correspond to the arguments.
   List<ParameterElement?> _resolveArgumentsToParameters(
-      ArgumentList argumentList, List<ParameterElement> parameters) {
+    ArgumentList argumentList,
+    List<ParameterElement> parameters, {
+    ConstructorDeclaration? enclosingConstructor,
+  }) {
     return ResolverVisitor.resolveArgumentsToParameters(
-        argumentList, parameters, _errorReporter.reportErrorForNode);
+      argumentList,
+      parameters,
+      _errorReporter.reportErrorForNode,
+      enclosingConstructor: enclosingConstructor,
+    );
   }
 
   /// Resolve the names in the given [combinators] in the scope of the given
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index ddcbc07..ad495d9 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -2331,11 +2331,12 @@
   /// Returns the parameters that correspond to the arguments. If no parameter
   /// matched an argument, that position will be `null` in the list.
   static List<ParameterElement?> resolveArgumentsToParameters(
-      ArgumentList argumentList,
-      List<ParameterElement> parameters,
-      void Function(ErrorCode errorCode, AstNode node,
-              [List<Object> arguments])?
-          onError) {
+    ArgumentList argumentList,
+    List<ParameterElement> parameters,
+    void Function(ErrorCode errorCode, AstNode node, [List<Object> arguments])?
+        onError, {
+    ConstructorDeclaration? enclosingConstructor,
+  }) {
     if (parameters.isEmpty && argumentList.arguments.isEmpty) {
       return const <ParameterElement>[];
     }
@@ -2401,6 +2402,45 @@
         }
       }
     }
+
+    if (enclosingConstructor != null) {
+      var hasExplicitPositionalArguments = positionalArgumentCount != 0;
+      for (var formalParameter in enclosingConstructor.parameters.parameters) {
+        formalParameter = formalParameter.notDefault;
+        if (formalParameter is SuperFormalParameter) {
+          var element = formalParameter.declaredElement
+              as SuperFormalParameterElementImpl;
+          if (formalParameter.isNamed) {
+            if (onError != null && element.superConstructorParameter == null) {
+              onError(
+                CompileTimeErrorCode
+                    .SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_NAMED,
+                formalParameter.identifier,
+              );
+            }
+          } else {
+            positionalArgumentCount++;
+            if (onError != null) {
+              if (hasExplicitPositionalArguments) {
+                onError(
+                  CompileTimeErrorCode
+                      .POSITIONAL_SUPER_FORMAL_PARAMETER_WITH_POSITIONAL_ARGUMENT,
+                  formalParameter.identifier,
+                );
+              }
+              if (element.superConstructorParameter == null) {
+                onError(
+                  CompileTimeErrorCode
+                      .SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_POSITIONAL,
+                  formalParameter.identifier,
+                );
+              }
+            }
+          }
+        }
+      }
+    }
+
     if (positionalArgumentCount < requiredParameterCount && noBlankArguments) {
       if (onError != null) {
         onError(CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS,
@@ -2417,8 +2457,8 @@
       } else {
         errorCode = CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS;
       }
-      if (onError != null) {
-        onError(errorCode, firstUnresolvedArgument!,
+      if (onError != null && firstUnresolvedArgument != null) {
+        onError(errorCode, firstUnresolvedArgument,
             [unnamedParameterCount, positionalArgumentCount]);
       }
     }
diff --git a/pkg/analyzer/messages.yaml b/pkg/analyzer/messages.yaml
index fc0b1e9..0f6e2fe 100644
--- a/pkg/analyzer/messages.yaml
+++ b/pkg/analyzer/messages.yaml
@@ -9866,6 +9866,10 @@
       ```dart
       part of 'test.dart';
       ```
+  POSITIONAL_SUPER_FORMAL_PARAMETER_WITH_POSITIONAL_ARGUMENT:
+    problemMessage: Positional super-formal parameters can't be used when the super-constructor invocation has a positional argument.
+    comment: No parameters.
+    correctionMessage: Try removing the 'super' modifier, or changing the super-constructor to use named parameters.
   PREFIX_COLLIDES_WITH_TOP_LEVEL_MEMBER:
     problemMessage: "The name '{0}' is already used as an import prefix and can't be used to name a top-level element."
     correctionMessage: Try renaming either the top-level element or the prefix.
@@ -11098,6 +11102,14 @@
 
       int f(C c) => c.b;
       ```
+  SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_NAMED:
+    problemMessage: No associated named super-constructor parameter.
+    comment: No parameters.
+    correctionMessage: Try changing the name to the name of an existing named super-constructor parameter, or creating such named parameter.
+  SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_POSITIONAL:
+    problemMessage: No associated positional super-constructor parameter.
+    comment: No parameters.
+    correctionMessage: Try using named parameters instead, or adding more positional parameters to the super-constructor.
   IMPLEMENTS_DEFERRED_CLASS:
     sharedName: SUBTYPE_OF_DEFERRED_CLASS
     problemMessage: "Classes and mixins can't implement deferred classes."
diff --git a/pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart b/pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart
index e8e1418..dcb8a8f 100644
--- a/pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/not_enough_positional_arguments_test.dart
@@ -86,4 +86,28 @@
       error(CompileTimeErrorCode.NOT_ENOUGH_POSITIONAL_ARGUMENTS, 65, 2),
     ]);
   }
+
+  test_superParameter_optional() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  A(int? a);
+}
+
+class B extends A {
+  B([super.a]) : super();
+}
+''');
+  }
+
+  test_superParameter_required() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  A(int a);
+}
+
+class B extends A {
+  B(super.a) : super();
+}
+''');
+  }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/positional_super_formal_parameter_with_positional_argument_test.dart b/pkg/analyzer/test/src/diagnostics/positional_super_formal_parameter_with_positional_argument_test.dart
new file mode 100644
index 0000000..ddde7c2
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/positional_super_formal_parameter_with_positional_argument_test.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(
+        PositionalSuperFormalParameterWithPositionalArgumentTest);
+  });
+}
+
+@reflectiveTest
+class PositionalSuperFormalParameterWithPositionalArgumentTest
+    extends PubPackageResolutionTest {
+  test_notReported() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  A(int a);
+}
+
+class B extends A {
+  B(super.a) : super();
+}
+''');
+  }
+
+  test_reported() async {
+    await assertErrorsInCode(r'''
+class A {
+  A(int a, int b);
+}
+
+class B extends A {
+  B(super.b) : super(0);
+}
+''', [
+      error(
+          CompileTimeErrorCode
+              .POSITIONAL_SUPER_FORMAL_PARAMETER_WITH_POSITIONAL_ARGUMENT,
+          62,
+          1)
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/super_formal_parameter_without_associated_named_test.dart b/pkg/analyzer/test/src/diagnostics/super_formal_parameter_without_associated_named_test.dart
new file mode 100644
index 0000000..049858a
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/super_formal_parameter_without_associated_named_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(SuperFormalParameterWithoutAssociatedNamedTest);
+  });
+}
+
+@reflectiveTest
+class SuperFormalParameterWithoutAssociatedNamedTest
+    extends PubPackageResolutionTest {
+  test_optional() async {
+    await assertErrorsInCode(r'''
+class A {
+  A([int? a]);
+}
+
+class B extends A {
+  B({super.a}) : super();
+}
+''', [
+      error(
+          CompileTimeErrorCode.SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_NAMED,
+          59,
+          1)
+    ]);
+  }
+
+  test_required() async {
+    await assertErrorsInCode(r'''
+class A {
+  A([int? a]);
+}
+
+class B extends A {
+  B({required super.a}) : super();
+}
+''', [
+      error(
+          CompileTimeErrorCode.SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_NAMED,
+          68,
+          1)
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/super_formal_parameter_without_associated_positional_test.dart b/pkg/analyzer/test/src/diagnostics/super_formal_parameter_without_associated_positional_test.dart
new file mode 100644
index 0000000..47d5cde
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/super_formal_parameter_without_associated_positional_test.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(SuperFormalParameterWithoutAssociatedPositionalTest);
+  });
+}
+
+@reflectiveTest
+class SuperFormalParameterWithoutAssociatedPositionalTest
+    extends PubPackageResolutionTest {
+  test_optional() async {
+    await assertErrorsInCode(r'''
+class A {
+  A({int? a});
+}
+
+class B extends A {
+  B([super.a]) : super();
+}
+''', [
+      error(
+          CompileTimeErrorCode
+              .SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_POSITIONAL,
+          59,
+          1)
+    ]);
+  }
+
+  test_required() async {
+    await assertErrorsInCode(r'''
+class A {
+  A({int? a});
+}
+
+class B extends A {
+  B(super.a) : super();
+}
+''', [
+      error(
+          CompileTimeErrorCode
+              .SUPER_FORMAL_PARAMETER_WITHOUT_ASSOCIATED_POSITIONAL,
+          58,
+          1)
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 8bed89d..445a54b 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -546,6 +546,8 @@
 import 'packed_nesting_non_packed_test.dart' as packed_nesting_non_packed;
 import 'part_of_different_library_test.dart' as part_of_different_library;
 import 'part_of_non_part_test.dart' as part_of_non_part;
+import 'positional_super_formal_parameter_with_positional_argument_test.dart'
+    as positional_super_formal_parameter_with_positional_argument;
 import 'prefix_collides_with_top_level_member_test.dart'
     as prefix_collides_with_top_level_member;
 import 'prefix_identifier_not_followed_by_dot_test.dart'
@@ -626,6 +628,10 @@
 import 'subtype_of_ffi_class_test.dart' as subtype_of_ffi_class;
 import 'subtype_of_sealed_class_test.dart' as subtype_of_sealed_class;
 import 'subtype_of_struct_class_test.dart' as subtype_of_struct_class;
+import 'super_formal_parameter_without_associated_named_test.dart'
+    as super_formal_parameter_without_associated_named;
+import 'super_formal_parameter_without_associated_positional_test.dart'
+    as super_formal_parameter_without_associated_positional;
 import 'super_in_extension_test.dart' as super_in_extension;
 import 'super_in_invalid_context_test.dart' as super_in_invalid_context;
 import 'super_in_redirecting_constructor_test.dart'
@@ -1089,6 +1095,7 @@
     packed_nesting_non_packed.main();
     part_of_different_library.main();
     part_of_non_part.main();
+    positional_super_formal_parameter_with_positional_argument.main();
     prefix_collides_with_top_level_member.main();
     prefix_identifier_not_followed_by_dot.main();
     prefix_shadowed_by_local_declaration.main();
@@ -1139,6 +1146,8 @@
     subtype_of_ffi_class.main();
     subtype_of_sealed_class.main();
     subtype_of_struct_class.main();
+    super_formal_parameter_without_associated_named.main();
+    super_formal_parameter_without_associated_positional.main();
     super_in_extension.main();
     super_in_invalid_context.main();
     super_in_redirecting_constructor.main();
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 9ab1bc5..b5fdd89 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -1615,6 +1615,38 @@
 ''');
   }
 
+  test_class_constructor_parameters_super_optionalNamed_unresolved2() async {
+    var library = await checkLibrary('''
+class A {
+  A(int a);
+}
+
+class B extends A {
+  B({super.a});
+}
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @6
+        constructors
+          @12
+            parameters
+              requiredPositional a @18
+                type: int
+      class B @31
+        supertype: A
+        constructors
+          @47
+            parameters
+              optionalNamed final super.a @56
+                type: dynamic
+                superConstructorParameter: <null>
+            superConstructor: self::@class::A::@constructor::•
+''');
+  }
+
   test_class_constructor_parameters_super_optionalPositional() async {
     var library = await checkLibrary('''
 class A {
@@ -1770,6 +1802,38 @@
 ''');
   }
 
+  test_class_constructor_parameters_super_requiredPositional_unresolved2() async {
+    var library = await checkLibrary('''
+class A {
+  A({required int a})
+}
+
+class B extends A {
+  B(super.a);
+}
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @6
+        constructors
+          @12
+            parameters
+              requiredNamed a @28
+                type: int
+      class B @41
+        supertype: A
+        constructors
+          @57
+            parameters
+              requiredPositional final super.a @65
+                type: dynamic
+                superConstructorParameter: <null>
+            superConstructor: self::@class::A::@constructor::•
+''');
+  }
+
   test_class_constructor_params() async {
     var library = await checkLibrary('class C { C(x, int y); }');
     checkElementText(library, r'''