Write / read RecordType into summaries.

Change-Id: I90665fbb3bdc4307270a17d9cefa896d5f931f3e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/255762
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 7eb930f..961f677 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -85,7 +85,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 238;
+  static const int DATA_VERSION = 239;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart b/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart
index 95d41a9..772fba3 100644
--- a/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_binary_tag.dart
@@ -125,8 +125,9 @@
   static const int InterfaceType_noTypeArguments_none = 7;
   static const int InterfaceType_noTypeArguments_question = 8;
   static const int InterfaceType_noTypeArguments_star = 9;
-  static const int TypeParameterType = 10;
-  static const int VoidType = 11;
+  static const int RecordType = 10;
+  static const int TypeParameterType = 11;
+  static const int VoidType = 12;
 }
 
 enum TypeParameterVarianceTag {
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index d24417e..16fcc24 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -1728,6 +1728,9 @@
       var nullability = _readNullability();
       var type = NeverTypeImpl.instance.withNullability(nullability);
       return _readAliasElementArguments(type);
+    } else if (tag == Tag.RecordType) {
+      final type = _readRecordType();
+      return _readAliasElementArguments(type);
     } else if (tag == Tag.TypeParameterType) {
       var element = readElement() as TypeParameterElement;
       var nullability = _readNullability();
@@ -1980,6 +1983,31 @@
     return _elementFactory.elementOfReference(reference);
   }
 
+  RecordTypeImpl _readRecordType() {
+    final positionalFields = readTypedList(() {
+      return RecordPositionalFieldElementImpl(
+        name: _reader.readOptionalStringReference(),
+        nameOffset: -1,
+        type: readRequiredType(),
+      );
+    });
+
+    final namedFields = readTypedList(() {
+      return RecordNamedFieldElementImpl(
+        name: _reader.readStringReference(),
+        nameOffset: -1,
+        type: readRequiredType(),
+      );
+    });
+
+    final nullabilitySuffix = _readNullability();
+
+    return RecordElementImpl(
+      positionalFields: positionalFields,
+      namedFields: namedFields,
+    ).instantiate(nullabilitySuffix: nullabilitySuffix);
+  }
+
   AstNode _readRequiredNode() {
     var astReader = AstBinaryReader(reader: this);
     return astReader.readNode();
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index 72a2d7a..b0a75f3 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -12,6 +12,7 @@
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/dart/resolver/variance.dart';
 import 'package:analyzer/src/summary2/ast_binary_tag.dart';
@@ -674,6 +675,9 @@
       writeByte(Tag.NeverType);
       _writeNullabilitySuffix(type.nullabilitySuffix);
       _writeTypeAliasElementArguments(type);
+    } else if (type is RecordTypeImpl) {
+      _writeRecordType(type);
+      _writeTypeAliasElementArguments(type);
     } else if (type is TypeParameterType) {
       writeByte(Tag.TypeParameterType);
       writeElement(type.element2);
@@ -803,6 +807,22 @@
     }
   }
 
+  void _writeRecordType(RecordTypeImpl type) {
+    writeByte(Tag.RecordType);
+
+    writeList<RecordTypePositionalField>(type.positionalFields, (field) {
+      _writeOptionalStringReference(field.element.name);
+      writeType(field.type);
+    });
+
+    writeList<RecordTypeNamedField>(type.namedFields, (field) {
+      _writeStringReference(field.element.name);
+      writeType(field.type);
+    });
+
+    _writeNullabilitySuffix(type.nullabilitySuffix);
+  }
+
   void _writeTypeAliasElementArguments(DartType type) {
     var alias = type.alias;
     _writeElement(alias?.element);
diff --git a/pkg/analyzer/test/src/summary/elements_test.dart b/pkg/analyzer/test/src/summary/elements_test.dart
index f1c3ab8..677765c 100644
--- a/pkg/analyzer/test/src/summary/elements_test.dart
+++ b/pkg/analyzer/test/src/summary/elements_test.dart
@@ -34752,6 +34752,44 @@
 ''');
   }
 
+  test_recordType_classField_fromLiteral() async {
+    var library = await buildLibrary('''
+class A {
+  final x = (0, true);
+}
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+    classes
+      class A @6
+        fields
+          final x @18
+            type: (int, bool)
+        constructors
+          synthetic @-1
+        accessors
+          synthetic get x @-1
+            returnType: (int, bool)
+''');
+  }
+
+  test_recordType_topVariable_fromLiteral() async {
+    var library = await buildLibrary('''
+final x = (0, true);
+''');
+    checkElementText(library, r'''
+library
+  definingUnit
+    topLevelVariables
+      static final x @6
+        type: (int, bool)
+    accessors
+      synthetic static get x @-1
+        returnType: (int, bool)
+''');
+  }
+
   test_setter_documented() async {
     var library = await buildLibrary('''
 // Extra comment so doc comment offset != 0