@@ -9,7 +9,9 @@ import 'package:kernel/ast.dart'
99 DynamicType,
1010 InterfaceType,
1111 Library,
12+ NamedType,
1213 Nullability,
14+ RecordType,
1315 TypeParameter;
1416import 'package:kernel/library_index.dart' show LibraryIndex;
1517
@@ -91,8 +93,8 @@ List<ParsedType> parseDefinitionTypes(List<String> definitionTypes) {
9193 int i = 0 ;
9294 List <ParsedType > argumentReceivers = [];
9395 while (i < definitionTypes.length) {
94- String uriOrNullString = definitionTypes[i];
95- if (uriOrNullString == "null" ) {
96+ String uriOrSpecialString = definitionTypes[i];
97+ if (uriOrSpecialString == "null" ) {
9698 if (argumentReceivers.isEmpty) {
9799 result.add (new ParsedType .nullType ());
98100 } else {
@@ -103,14 +105,39 @@ List<ParsedType> parseDefinitionTypes(List<String> definitionTypes) {
103105 }
104106 i++ ;
105107 continue ;
108+ } else if (uriOrSpecialString == "record" ) {
109+ // Record.
110+ // We expect at least 4 elements: "record", nullability, num fields,
111+ // num positional fields.
112+ if (i + 4 > definitionTypes.length) throw "invalid input" ;
113+ int nullability = int .parse (definitionTypes[i + 1 ]);
114+ int numFields = int .parse (definitionTypes[i + 2 ]);
115+ int numPositionalFields = int .parse (definitionTypes[i + 3 ]);
116+ i += 4 ;
117+
118+ List <String ?> fieldNames = new List <String ?>.filled (numFields, null );
119+ for (int j = numPositionalFields; j < numFields; j++ ) {
120+ fieldNames[j] = definitionTypes[i++ ];
121+ }
122+
123+ ParsedType type = new ParsedType .record (nullability, fieldNames);
124+ if (argumentReceivers.isEmpty) {
125+ result.add (type);
126+ } else {
127+ argumentReceivers.removeLast ().arguments! .add (type);
128+ }
129+ for (int j = 0 ; j < numFields; j++ ) {
130+ argumentReceivers.add (type);
131+ }
106132 } else {
107133 // We expect at least 4 elements: Uri, class name, nullability,
108134 // number of type arguments.
109135 if (i + 4 > definitionTypes.length) throw "invalid input" ;
110136 String className = definitionTypes[i + 1 ];
111137 int nullability = int .parse (definitionTypes[i + 2 ]);
112138 int typeArgumentsCount = int .parse (definitionTypes[i + 3 ]);
113- ParsedType type = new ParsedType (uriOrNullString, className, nullability);
139+ ParsedType type =
140+ new ParsedType .interface (uriOrSpecialString, className, nullability);
114141 if (argumentReceivers.isEmpty) {
115142 result.add (type);
116143 } else {
@@ -128,26 +155,44 @@ List<ParsedType> parseDefinitionTypes(List<String> definitionTypes) {
128155 return result;
129156}
130157
158+ enum ParsedTypeKind {
159+ Null ,
160+ Interface ,
161+ Record ,
162+ }
163+
131164// Coverage-ignore(suite): Not run.
132165class ParsedType {
166+ final ParsedTypeKind type;
133167 final String ? uri;
134168 final String ? className;
135169 final int ? nullability;
136170 final List <ParsedType >? arguments;
171+ final List <String ?>? recordFieldNames;
137172
138- bool get isNullType => uri == null ;
173+ ParsedType .interface (this .uri, this .className, this .nullability)
174+ : type = ParsedTypeKind .Interface ,
175+ arguments = [],
176+ recordFieldNames = null ;
139177
140- ParsedType (this .uri, this .className, this .nullability) : arguments = [];
178+ ParsedType .record (this .nullability, this .recordFieldNames)
179+ : type = ParsedTypeKind .Record ,
180+ uri = null ,
181+ className = null ,
182+ arguments = [];
141183
142184 ParsedType .nullType ()
143- : uri = null ,
185+ : type = ParsedTypeKind .Null ,
186+ uri = null ,
144187 className = null ,
145188 nullability = null ,
146- arguments = null ;
189+ arguments = null ,
190+ recordFieldNames = null ;
147191
148192 @override
149193 bool operator == (Object other) {
150194 if (other is ! ParsedType ) return false ;
195+ if (type != other.type) return false ;
151196 if (uri != other.uri) return false ;
152197 if (className != other.className) return false ;
153198 if (nullability != other.nullability) return false ;
@@ -157,42 +202,81 @@ class ParsedType {
157202 if (arguments! [i] != other.arguments! [i]) return false ;
158203 }
159204 }
205+ if (recordFieldNames? .length != other.recordFieldNames? .length) {
206+ return false ;
207+ }
208+ if (recordFieldNames != null ) {
209+ for (int i = 0 ; i < recordFieldNames! .length; i++ ) {
210+ if (recordFieldNames! [i] != other.recordFieldNames! [i]) return false ;
211+ }
212+ }
160213 return true ;
161214 }
162215
163216 @override
164217 int get hashCode {
165- if (isNullType ) return 0 ;
218+ if (type == ParsedTypeKind . Null ) return 0 ;
166219 int hash = 0x3fffffff & uri.hashCode;
167220 hash = 0x3fffffff & (hash * 31 + (hash ^ className.hashCode));
168221 hash = 0x3fffffff & (hash * 31 + (hash ^ nullability.hashCode));
169222 for (ParsedType argument in arguments! ) {
170223 hash = 0x3fffffff & (hash * 31 + (hash ^ argument.hashCode));
171224 }
225+ if (recordFieldNames != null ) {
226+ for (String ? name in recordFieldNames! ) {
227+ hash = 0x3fffffff & (hash * 31 + (hash ^ name.hashCode));
228+ }
229+ }
172230 return hash;
173231 }
174232
175233 @override
176234 String toString () {
177- if (isNullType) return "null-type" ;
178- return "$uri [$className ] ($nullability ) <$arguments >" ;
235+ switch (type) {
236+ case ParsedTypeKind .Null :
237+ return "null-type" ;
238+ case ParsedTypeKind .Interface :
239+ return "Record[$recordFieldNames ] ($nullability ) ($arguments )" ;
240+ case ParsedTypeKind .Record :
241+ if (arguments? .isEmpty ?? true ) {
242+ return "$uri [$className ] ($nullability )" ;
243+ }
244+ return "$uri [$className ] ($nullability ) <$arguments >" ;
245+ }
179246 }
180247
181248 DartType createDartType (LibraryIndex libraryIndex) {
182- if (isNullType) return new DynamicType ();
183- Class ? classNode = libraryIndex.tryGetClass (uri! , className! );
184- if (classNode == null ) return new DynamicType ();
185-
186- return new InterfaceType (
187- classNode,
188- _getDartNullability (),
189- arguments
190- ? .map ((e) => e.createDartType (libraryIndex))
191- .toList (growable: false ));
249+ switch (type) {
250+ case ParsedTypeKind .Null :
251+ return new DynamicType ();
252+ case ParsedTypeKind .Record :
253+ List <DartType > positional = [];
254+ List <NamedType > named = [];
255+ for (int i = 0 ; i < arguments! .length; i++ ) {
256+ String ? name = recordFieldNames! [i];
257+ DartType type = arguments! [i].createDartType (libraryIndex);
258+ if (name == null ) {
259+ positional.add (type);
260+ } else {
261+ named.add (new NamedType (name, type));
262+ }
263+ }
264+ return new RecordType (positional, named, _getDartNullability ());
265+ case ParsedTypeKind .Interface :
266+ Class ? classNode = libraryIndex.tryGetClass (uri! , className! );
267+ if (classNode == null ) return new DynamicType ();
268+
269+ return new InterfaceType (
270+ classNode,
271+ _getDartNullability (),
272+ arguments
273+ ? .map ((e) => e.createDartType (libraryIndex))
274+ .toList (growable: false ));
275+ }
192276 }
193277
194278 Nullability _getDartNullability () {
195- if (isNullType ) throw "No nullability on the null type" ;
279+ if (type == ParsedTypeKind . Null ) throw "No nullability on the null type" ;
196280 if (nullability == 0 ) return Nullability .nullable;
197281 if (nullability == 1 ) return Nullability .nonNullable;
198282 if (nullability == 2 ) return Nullability .legacy;
@@ -206,9 +290,14 @@ Set<String> collectParsedTypeUris(List<ParsedType> parsedTypes) {
206290 List <ParsedType > workList = new List .from (parsedTypes);
207291 while (workList.isNotEmpty) {
208292 ParsedType type = workList.removeLast ();
209- if (type.isNullType) continue ;
210- result.add (type.uri! );
211- workList.addAll (type.arguments! );
293+ if (type.arguments != null ) workList.addAll (type.arguments! );
294+ switch (type.type) {
295+ case ParsedTypeKind .Null :
296+ case ParsedTypeKind .Record :
297+ continue ;
298+ case ParsedTypeKind .Interface :
299+ result.add (type.uri! );
300+ }
212301 }
213302 return result;
214303}
0 commit comments