@@ -6251,6 +6251,7 @@ class NamedPattern extends Pattern {
6251
6251
6252
6252
class RecordPattern extends Pattern {
6253
6253
final List <Pattern > patterns;
6254
+ late final RecordType type;
6254
6255
6255
6256
@override
6256
6257
List <VariableDeclaration > get declaredVariables =>
@@ -6293,12 +6294,114 @@ class RecordPattern extends Pattern {
6293
6294
DartType matchedType,
6294
6295
Expression variableInitializingContext,
6295
6296
InferenceVisitorBase inferenceVisitor) {
6296
- return new PatternTransformationResult ([
6297
- new PatternTransformationElement (
6298
- condition:
6299
- new InvalidExpression ("Unimplemented RecordPattern.transform" ),
6300
- variableInitializers: [])
6301
- ]);
6297
+ bool typeCheckNeeded = ! inferenceVisitor.isAssignable (type, matchedType) ||
6298
+ matchedType is DynamicType ;
6299
+
6300
+ // recordVariable: `matchedType` RVAR = `matchedExpression`
6301
+ VariableDeclaration recordVariable = inferenceVisitor.engine.forest
6302
+ .createVariableDeclarationForValue (matchedExpression,
6303
+ type: matchedType);
6304
+
6305
+ PatternTransformationResult transformationResult =
6306
+ new PatternTransformationResult ([]);
6307
+ int recordFieldIndex = 0 ;
6308
+ List <VariableDeclaration > fieldAccessVariables = [];
6309
+ for (Pattern fieldPattern in patterns) {
6310
+ Expression recordField;
6311
+ DartType fieldType;
6312
+ Pattern subpattern;
6313
+ if (fieldPattern is NamedPattern ) {
6314
+ // recordField: `recordVariable`[`fieldPattern.name`]
6315
+ // ==> RVAR[`fieldPattern.name`]
6316
+ recordField = new RecordNameGet (
6317
+ inferenceVisitor.engine.forest
6318
+ .createVariableGet (fileOffset, recordVariable)
6319
+ ..promotedType = typeCheckNeeded ? type : null ,
6320
+ type,
6321
+ fieldPattern.name);
6322
+
6323
+ // [type] is computed by the CFE, so the absence of the named field is
6324
+ // an internal error, and we check the condition with an assert rather
6325
+ // than reporting a compile-time error.
6326
+ assert (type.named.any ((named) => named.name == fieldPattern.name));
6327
+ fieldType = type.named
6328
+ .firstWhere ((named) => named.name == fieldPattern.name)
6329
+ .type;
6330
+
6331
+ subpattern = fieldPattern.pattern;
6332
+ } else {
6333
+ // recordField: `recordVariable`[`recordFieldIndex`]
6334
+ // ==> RVAR[`recordFieldIndex`]
6335
+ recordField = new RecordIndexGet (
6336
+ inferenceVisitor.engine.forest
6337
+ .createVariableGet (fileOffset, recordVariable)
6338
+ ..promotedType = typeCheckNeeded ? type : null ,
6339
+ type,
6340
+ recordFieldIndex);
6341
+
6342
+ // [type] is computed by the CFE, so the field index out of range is an
6343
+ // internal error, and we check the condition with an assert rather than
6344
+ // reporting a compile-time error.
6345
+ assert (recordFieldIndex < type.positional.length);
6346
+ fieldType = type.positional[recordFieldIndex];
6347
+
6348
+ subpattern = fieldPattern;
6349
+ recordFieldIndex++ ;
6350
+ }
6351
+
6352
+ // recordFieldIndex: `fieldType` FVAR = `recordField`
6353
+ VariableDeclaration recordFieldVariable = inferenceVisitor.engine.forest
6354
+ .createVariableDeclarationForValue (recordField, type: fieldType);
6355
+
6356
+ PatternTransformationResult subpatternTransformationResult =
6357
+ subpattern.transform (
6358
+ inferenceVisitor.engine.forest
6359
+ .createVariableGet (fileOffset, recordFieldVariable),
6360
+ fieldType,
6361
+ inferenceVisitor.engine.forest
6362
+ .createVariableGet (fileOffset, recordFieldVariable),
6363
+ inferenceVisitor);
6364
+
6365
+ // If the sub-pattern transformation doesn't declare captured variables
6366
+ // and consists of a single empty element, it means that it simply
6367
+ // doesn't have a place where it could refer to the element expression.
6368
+ // In that case we can avoid creating the intermediary variable for the
6369
+ // element expression.
6370
+ //
6371
+ // An example of such sub-pattern is in the following:
6372
+ //
6373
+ // if (x case (var _,)) { /* ... */ }
6374
+ if (subpattern.declaredVariables.isNotEmpty ||
6375
+ ! (subpatternTransformationResult.elements.length == 1 &&
6376
+ subpatternTransformationResult.elements.single.isEmpty)) {
6377
+ fieldAccessVariables.add (recordFieldVariable);
6378
+ transformationResult = transformationResult.combine (
6379
+ subpatternTransformationResult, inferenceVisitor);
6380
+ }
6381
+ }
6382
+
6383
+ // condition: [`recordVariable` is `type`]?
6384
+ // ==> [RVAR is `type`]?
6385
+ transformationResult = transformationResult.prependElement (
6386
+ new PatternTransformationElement (
6387
+ condition: ! typeCheckNeeded
6388
+ ? null
6389
+ : inferenceVisitor.engine.forest.createIsExpression (
6390
+ fileOffset,
6391
+ inferenceVisitor.engine.forest
6392
+ .createVariableGet (fileOffset, recordVariable),
6393
+ type,
6394
+ forNonNullableByDefault:
6395
+ inferenceVisitor.isNonNullableByDefault),
6396
+ variableInitializers: fieldAccessVariables),
6397
+ inferenceVisitor);
6398
+
6399
+ transformationResult = transformationResult.prependElement (
6400
+ new PatternTransformationElement (
6401
+ condition: null , variableInitializers: [recordVariable]),
6402
+ inferenceVisitor);
6403
+
6404
+ return transformationResult;
6302
6405
}
6303
6406
}
6304
6407
0 commit comments