Implement record type resolution in RecordTypeAnnotationResolver, from ResolutionVisitor.

Change-Id: Ia3ab904c05d7800088ca6467d35151821130a523
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/256432
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/resolver/record_type_annotation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/record_type_annotation_resolver.dart
index 4bd6875..fbf4079 100644
--- a/pkg/analyzer/lib/src/dart/resolver/record_type_annotation_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/record_type_annotation_resolver.dart
@@ -3,25 +3,27 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/ast/extensions.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/diagnostic/diagnostic_factory.dart';
 import 'package:analyzer/src/error/codes.g.dart';
-import 'package:analyzer/src/generated/resolver.dart';
 
 /// Helper for resolving [RecordTypeAnnotation]s.
 class RecordTypeAnnotationResolver {
   /// A regular expression used to match positional field names.
   static final RegExp positionalFieldName = RegExp(r'^\$[0-9]+$');
 
-  final ResolverVisitor _resolver;
+  final TypeProviderImpl typeProvider;
+  final ErrorReporter errorReporter;
 
   RecordTypeAnnotationResolver({
-    required ResolverVisitor resolver,
-  }) : _resolver = resolver;
-
-  ErrorReporter get errorReporter => _resolver.errorReporter;
+    required this.typeProvider,
+    required this.errorReporter,
+  });
 
   /// Report any named fields in the record type [node] that use a previously
   /// defined name.
@@ -44,8 +46,7 @@
 
   /// Report any fields in the record type [node] that use an invalid name.
   void reportInvalidFieldNames(RecordTypeAnnotationImpl node) {
-    var fields = node.fields;
-    for (var field in fields) {
+    for (var field in node.fields) {
       var nameToken = field.name;
       if (nameToken != null) {
         var name = nameToken.lexeme;
@@ -56,7 +57,7 @@
           errorReporter.reportErrorForToken(
               CompileTimeErrorCode.INVALID_FIELD_NAME_POSITIONAL, nameToken);
         } else {
-          var objectElement = _resolver.typeProvider.objectElement;
+          var objectElement = typeProvider.objectElement;
           if (objectElement.getGetter(name) != null ||
               objectElement.getMethod(name) != null) {
             errorReporter.reportErrorForToken(
@@ -67,16 +68,32 @@
     }
   }
 
-  void resolve(RecordTypeAnnotationImpl node,
-      {required DartType? contextType}) {
-    // TODO(brianwilkerson) Move resolution from the `visitRecordTypeAnnotation`
-    //  methods of `ResolverVisitor` and `StaticTypeAnalyzer` to this class.
+  void resolve(RecordTypeAnnotationImpl node) {
+    _buildType(node);
+    reportDuplicateFieldDefinitions(node);
+    reportInvalidFieldNames(node);
   }
-}
 
-extension on RecordTypeAnnotation {
-  List<RecordTypeAnnotationField> get fields => [
-        ...positionalFields,
-        ...?namedFields?.fields,
-      ];
+  void _buildType(RecordTypeAnnotationImpl node) {
+    final positionalFields = node.positionalFields.map((field) {
+      return RecordTypePositionalFieldImpl(
+        type: field.type.typeOrThrow,
+      );
+    }).toList();
+
+    final namedFields = node.namedFields?.fields.map((field) {
+      return RecordTypeNamedFieldImpl(
+        name: field.name.lexeme,
+        type: field.type.typeOrThrow,
+      );
+    }).toList();
+
+    node.type = RecordTypeImpl(
+      positionalFields: positionalFields,
+      namedFields: namedFields ?? const [],
+      nullabilitySuffix: node.question != null
+          ? NullabilitySuffix.question
+          : NullabilitySuffix.none,
+    );
+  }
 }
diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
index 3e94ae7..4818b5d 100644
--- a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
@@ -19,11 +19,11 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/resolver/ast_rewrite.dart';
 import 'package:analyzer/src/dart/resolver/named_type_resolver.dart';
+import 'package:analyzer/src/dart/resolver/record_type_annotation_resolver.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/element_walker.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
-import 'package:analyzer/src/summary2/record_type_builder.dart';
 
 class ElementHolder {
   final ElementImpl _element;
@@ -65,6 +65,7 @@
   final ErrorReporter _errorReporter;
   final AstRewriter _astRewriter;
   final NamedTypeResolver _namedTypeResolver;
+  final RecordTypeAnnotationResolver _recordTypeResolver;
 
   /// This index is incremented every time we visit a [LibraryDirective].
   /// There is just one [LibraryElement], so we can support only one node.
@@ -111,6 +112,11 @@
       errorReporter,
     );
 
+    final recordTypeResolver = RecordTypeAnnotationResolver(
+      typeProvider: typeProvider,
+      errorReporter: errorReporter,
+    );
+
     return ResolutionVisitor._(
       libraryElement,
       typeProvider,
@@ -119,6 +125,7 @@
       errorReporter,
       AstRewriter(errorReporter, typeProvider),
       namedTypeResolver,
+      recordTypeResolver,
       nameScope,
       elementWalker,
       ElementHolder(unitElement),
@@ -133,6 +140,7 @@
     this._errorReporter,
     this._astRewriter,
     this._namedTypeResolver,
+    this._recordTypeResolver,
     this._nameScope,
     this._elementWalker,
     this._elementHolder,
@@ -971,7 +979,7 @@
   @override
   void visitRecordTypeAnnotation(covariant RecordTypeAnnotationImpl node) {
     node.visitChildren(this);
-    RecordTypeBuilder.buildType(node);
+    _recordTypeResolver.resolve(node);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 8dd3bc7..a09991b 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -51,7 +51,6 @@
 import 'package:analyzer/src/dart/resolver/prefixed_identifier_resolver.dart';
 import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
 import 'package:analyzer/src/dart/resolver/record_literal_resolver.dart';
-import 'package:analyzer/src/dart/resolver/record_type_annotation_resolver.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
 import 'package:analyzer/src/dart/resolver/simple_identifier_resolver.dart';
 import 'package:analyzer/src/dart/resolver/this_lookup.dart';
@@ -253,9 +252,6 @@
   late final RecordLiteralResolver _recordLiteralResolver =
       RecordLiteralResolver(resolver: this);
 
-  late final RecordTypeAnnotationResolver _recordTypeAnnotationResolver =
-      RecordTypeAnnotationResolver(resolver: this);
-
   late final AnnotationResolver _annotationResolver = AnnotationResolver(this);
 
   final bool genericMetadataIsEnabled;
@@ -2235,10 +2231,11 @@
 
   @override
   void visitRecordTypeAnnotation(covariant RecordTypeAnnotationImpl node) {
+    // All RecordTypeAnnotation(s) are already resolved, so we don't resolve
+    // it here. But there might be types with Expression(s), such as default
+    // values for formal parameters of GenericFunctionType(s). These are
+    // invalid, but if they exist, they should be resolved.
     node.visitChildren(this);
-    _recordTypeAnnotationResolver
-      ..reportDuplicateFieldDefinitions(node)
-      ..reportInvalidFieldNames(node);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/summary2/record_type_builder.dart b/pkg/analyzer/lib/src/summary2/record_type_builder.dart
index 7d17359..59530b6 100644
--- a/pkg/analyzer/lib/src/summary2/record_type_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/record_type_builder.dart
@@ -123,30 +123,6 @@
     );
   }
 
-  /// TODO(scheglov) Move to [RecordTypeAnnotationResolver].
-  static RecordTypeImpl buildType(RecordTypeAnnotationImpl node) {
-    final positionalFields = node.positionalFields.map((field) {
-      return RecordTypePositionalFieldImpl(
-        type: field.type.typeOrThrow,
-      );
-    }).toList();
-
-    final namedFields = node.namedFields?.fields.map((field) {
-      return RecordTypeNamedFieldImpl(
-        name: field.name.lexeme,
-        type: field.type.typeOrThrow,
-      );
-    }).toList();
-
-    return node.type = RecordTypeImpl(
-      positionalFields: positionalFields,
-      namedFields: namedFields ?? const [],
-      nullabilitySuffix: node.question != null
-          ? NullabilitySuffix.question
-          : NullabilitySuffix.none,
-    );
-  }
-
   /// If the [type] is a [TypeBuilder], build it; otherwise return as is.
   static DartType _buildType(DartType type) {
     if (type is TypeBuilder) {