@@ -4413,21 +4413,49 @@ class ListPattern extends Pattern {
4413
4413
greaterThanOrEqualsName,
4414
4414
fileOffset,
4415
4415
callSiteAccessKind: CallSiteAccessKind .operatorInvocation);
4416
+ ObjectAccessTarget equalsTarget = inferenceVisitor.findInterfaceMember (
4417
+ inferenceVisitor.coreTypes.intNonNullableRawType,
4418
+ equalsName,
4419
+ fileOffset,
4420
+ callSiteAccessKind: CallSiteAccessKind .operatorInvocation);
4416
4421
4417
- // greaterThanOrEqualsInvocation: `lengthGet` >= `patterns.length`
4418
- // ==> LVAR.length >= `patterns.length`
4419
- Expression greaterThanOrEqualsInvocation = new InstanceInvocation (
4420
- InstanceAccessKind .Instance ,
4421
- lengthGet,
4422
- greaterThanOrEqualsName,
4423
- inferenceVisitor.engine.forest.createArguments (fileOffset, [
4424
- inferenceVisitor.engine.forest
4425
- .createIntLiteral (fileOffset, patterns.length)
4426
- ]),
4427
- functionType:
4428
- greaterThanOrEqualsTarget.getFunctionType (inferenceVisitor),
4429
- interfaceTarget: greaterThanOrEqualsTarget.member as Procedure )
4430
- ..fileOffset = fileOffset;
4422
+ Expression lengthCheck;
4423
+ bool hasRestPattern = false ;
4424
+ for (Pattern pattern in patterns) {
4425
+ if (pattern is RestPattern ) {
4426
+ hasRestPattern = true ;
4427
+ break ;
4428
+ }
4429
+ }
4430
+ if (hasRestPattern) {
4431
+ // lengthCheck: `lengthGet` >= `patterns.length - 1`
4432
+ // ==> LVAR.length >= `patterns.length - 1`
4433
+ lengthCheck = new InstanceInvocation (
4434
+ InstanceAccessKind .Instance ,
4435
+ lengthGet,
4436
+ greaterThanOrEqualsName,
4437
+ inferenceVisitor.engine.forest.createArguments (fileOffset, [
4438
+ inferenceVisitor.engine.forest
4439
+ .createIntLiteral (fileOffset, patterns.length - 1 )
4440
+ ]),
4441
+ functionType:
4442
+ greaterThanOrEqualsTarget.getFunctionType (inferenceVisitor),
4443
+ interfaceTarget: greaterThanOrEqualsTarget.member as Procedure )
4444
+ ..fileOffset = fileOffset;
4445
+ } else {
4446
+ // lengthCheck: `lengthGet` == `patterns.length`
4447
+ lengthCheck = new InstanceInvocation (
4448
+ InstanceAccessKind .Instance ,
4449
+ lengthGet,
4450
+ equalsName,
4451
+ inferenceVisitor.engine.forest.createArguments (fileOffset, [
4452
+ inferenceVisitor.engine.forest
4453
+ .createIntLiteral (fileOffset, patterns.length)
4454
+ ]),
4455
+ functionType: equalsTarget.getFunctionType (inferenceVisitor),
4456
+ interfaceTarget: equalsTarget.member as Procedure )
4457
+ ..fileOffset = fileOffset;
4458
+ }
4431
4459
4432
4460
// typeAndLengthCheck: `listVariable` is `targetListType`
4433
4461
// && `greaterThanOrEqualsInvocation`
@@ -4445,11 +4473,15 @@ class ListPattern extends Pattern {
4445
4473
targetListType,
4446
4474
forNonNullableByDefault: false ),
4447
4475
doubleAmpersandName.text,
4448
- greaterThanOrEqualsInvocation );
4476
+ lengthCheck );
4449
4477
} else {
4450
- typeAndLengthCheck = greaterThanOrEqualsInvocation ;
4478
+ typeAndLengthCheck = lengthCheck ;
4451
4479
}
4452
4480
4481
+ ObjectAccessTarget intSubtraction = inferenceVisitor.findInterfaceMember (
4482
+ inferenceVisitor.coreTypes.intNonNullableRawType, minusName, fileOffset,
4483
+ callSiteAccessKind: CallSiteAccessKind .operatorInvocation);
4484
+
4453
4485
ObjectAccessTarget elementAccess = inferenceVisitor.findInterfaceMember (
4454
4486
targetListType, indexGetName, fileOffset,
4455
4487
callSiteAccessKind: CallSiteAccessKind .operatorInvocation);
@@ -4458,17 +4490,58 @@ class ListPattern extends Pattern {
4458
4490
PatternTransformationResult transformationResult =
4459
4491
new PatternTransformationResult ([]);
4460
4492
List <VariableDeclaration > elementAccessVariables = [];
4493
+ bool hasSeenRestPattern = false ;
4461
4494
for (int i = 0 ; i < patterns.length; i++ ) {
4462
- // listElement: `listVariable`[`i`]
4463
- // ==> LVAR[`i`]
4495
+ if (patterns[i] is RestPattern ) {
4496
+ hasSeenRestPattern = true ;
4497
+ continue ;
4498
+ }
4499
+
4500
+ Expression elementIndex;
4501
+ if (! hasSeenRestPattern) {
4502
+ // elementIndex: `i`
4503
+ elementIndex =
4504
+ inferenceVisitor.engine.forest.createIntLiteral (fileOffset, i);
4505
+ } else {
4506
+ // elementIndex: `listVariable`.length - `patterns.length - i`
4507
+ // ==> LVAR.length - `patterns.length - i`
4508
+
4509
+ // lengthGet: `listVariable`.length ==> LVAR.length
4510
+ Expression lengthGet = new InstanceGet (
4511
+ InstanceAccessKind .Instance ,
4512
+ inferenceVisitor.engine.forest
4513
+ .createVariableGet (fileOffset, listVariable)
4514
+ ..promotedType =
4515
+ typeCheckForTargetListNeeded ? targetListType : null ,
4516
+ lengthName,
4517
+ resultType: lengthTarget.getGetterType (inferenceVisitor),
4518
+ interfaceTarget: lengthTarget.member as Procedure )
4519
+ ..fileOffset = fileOffset;
4520
+
4521
+ // elementIndex: `lengthGet` - `patterns.length - i`
4522
+ // ==> LVAR.length - `patterns.length - i`
4523
+ elementIndex = new InstanceInvocation (
4524
+ InstanceAccessKind .Instance ,
4525
+ lengthGet,
4526
+ minusName,
4527
+ inferenceVisitor.engine.forest.createArguments (fileOffset, [
4528
+ inferenceVisitor.engine.forest
4529
+ .createIntLiteral (fileOffset, patterns.length - i)
4530
+ ]),
4531
+ interfaceTarget: intSubtraction.member as Procedure ,
4532
+ functionType: intSubtraction.getFunctionType (inferenceVisitor));
4533
+ }
4534
+
4535
+ // listElement: `listVariable`[`elementIndex`]
4536
+ // ==> LVAR[`elementIndex`]
4464
4537
Expression listElement = new InstanceInvocation (
4465
4538
InstanceAccessKind .Instance ,
4466
4539
inferenceVisitor.engine.forest
4467
4540
.createVariableGet (fileOffset, listVariable)
4468
4541
..promotedType = targetListType,
4469
4542
indexGetName,
4470
- inferenceVisitor.engine.forest. createArguments (fileOffset,
4471
- [inferenceVisitor.engine.forest. createIntLiteral (fileOffset, i) ]),
4543
+ inferenceVisitor.engine.forest
4544
+ . createArguments (fileOffset, [elementIndex ]),
4472
4545
functionType: elementAccessFunctionType,
4473
4546
interfaceTarget: elementAccess.member as Procedure );
4474
4547
@@ -5544,6 +5617,39 @@ class VariablePattern extends Pattern {
5544
5617
}
5545
5618
}
5546
5619
5620
+ class RestPattern extends Pattern {
5621
+ RestPattern (int fileOffset) : super (fileOffset);
5622
+
5623
+ @override
5624
+ PatternInferenceResult acceptInference (InferenceVisitorImpl visitor,
5625
+ {required SharedMatchContext context}) {
5626
+ return visitor.visitRestPattern (this , context: context);
5627
+ }
5628
+
5629
+ @override
5630
+ List <VariableDeclaration > get declaredVariables => const [];
5631
+
5632
+ @override
5633
+ void toTextInternal (AstPrinter printer) {
5634
+ printer.write ('...' );
5635
+ }
5636
+
5637
+ @override
5638
+ String toString () {
5639
+ return "RestPattern(${toStringInternal ()}" ;
5640
+ }
5641
+
5642
+ @override
5643
+ PatternTransformationResult transform (
5644
+ Expression matchedExpression,
5645
+ DartType matchedType,
5646
+ Expression variableInitializingContext,
5647
+ InferenceVisitorBase inferenceVisitor) {
5648
+ return unsupported (
5649
+ "RestPattern.transform" , fileOffset, inferenceVisitor.helper.uri);
5650
+ }
5651
+ }
5652
+
5547
5653
enum PatternTransformationElementKind {
5548
5654
regular,
5549
5655
logicalOrPatternLeftBegin,
0 commit comments