Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 68291f3

Browse files
author
Dart CI
committed
Version 2.19.0-413.0.dev
Merge ae1ed9e into dev
2 parents 0c51d4b + ae1ed9e commit 68291f3

31 files changed

+664
-316
lines changed

DEPS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ vars = {
5151

5252
# co19 is a cipd package. Use update.sh in tests/co19[_2] to update these
5353
# hashes.
54-
"co19_rev": "19439c0d58a0df422c4acc4ae97a3deeb98d0f67",
54+
"co19_rev": "2a9309cd36effe3b083df6a2761fea6b7213c670",
5555
# This line prevents conflicts when both packages are rolled simultaneously.
5656
"co19_2_rev": "cdab7e4e26f3dd534bcb297ff3f9e9aa5c7a04fb",
5757

pkg/_fe_analyzer_shared/lib/src/type_inference/type_analyzer.dart

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -551,20 +551,33 @@ mixin TypeAnalyzer<
551551
Pattern node,
552552
{Type? elementType,
553553
required List<Node> elements}) {
554-
// Stack: ()
555-
Type? matchedElementType = typeOperations.matchListType(matchedType);
556-
if (matchedElementType == null) {
557-
if (typeOperations.isDynamic(matchedType)) {
558-
matchedElementType = dynamicType;
554+
Type valueType;
555+
if (elementType != null) {
556+
valueType = elementType;
557+
} else {
558+
Type? listElementType = typeOperations.matchListType(matchedType);
559+
if (listElementType != null) {
560+
valueType = listElementType;
561+
} else if (typeOperations.isDynamic(matchedType)) {
562+
valueType = dynamicType;
559563
} else {
560-
matchedElementType = objectQuestionType;
564+
valueType = objectQuestionType;
561565
}
562566
}
567+
// Stack: ()
563568
for (Node element in elements) {
564-
dispatchPattern(matchedElementType, context, element);
569+
if (isRestPatternElement(element)) {
570+
Pattern? subPattern = getRestPatternElementPattern(element);
571+
if (subPattern != null) {
572+
dispatchPattern(listType(valueType), context, subPattern);
573+
}
574+
handleRestPatternElement(node, element);
575+
} else {
576+
dispatchPattern(valueType, context, element);
577+
}
565578
}
566579
// Stack: (n * Pattern) where n = elements.length
567-
Type requiredType = listType(elementType ?? matchedElementType);
580+
Type requiredType = listType(valueType);
568581
Node? irrefutableContext = context.irrefutableContext;
569582
if (irrefutableContext != null &&
570583
!typeOperations.isAssignableTo(matchedType, requiredType)) {
@@ -582,19 +595,40 @@ mixin TypeAnalyzer<
582595
/// subpatterns.
583596
///
584597
/// Stack effect: none.
585-
Type analyzeListPatternSchema(
586-
{Type? elementType, required List<Node> elements}) {
587-
if (elementType == null) {
588-
if (elements.isEmpty) {
589-
return objectQuestionType;
598+
Type analyzeListPatternSchema({
599+
required Type? elementType,
600+
required List<Node> elements,
601+
}) {
602+
if (elementType != null) {
603+
return listType(elementType);
604+
}
605+
606+
if (elements.isEmpty) {
607+
return listType(unknownType);
608+
}
609+
610+
Type? currentGLB;
611+
for (Node element in elements) {
612+
Type? typeToAdd;
613+
if (isRestPatternElement(element)) {
614+
Pattern? subPattern = getRestPatternElementPattern(element);
615+
if (subPattern != null) {
616+
Type subPatternType = dispatchPatternSchema(subPattern);
617+
typeToAdd = typeOperations.matchIterableType(subPatternType);
618+
}
619+
} else {
620+
typeToAdd = dispatchPatternSchema(element);
590621
}
591-
elementType = dispatchPatternSchema(elements[0]);
592-
for (int i = 1; i < elements.length; i++) {
593-
elementType = typeOperations.glb(
594-
elementType!, dispatchPatternSchema(elements[i]));
622+
if (typeToAdd != null) {
623+
if (currentGLB == null) {
624+
currentGLB = typeToAdd;
625+
} else {
626+
currentGLB = typeOperations.glb(currentGLB, typeToAdd);
627+
}
595628
}
596629
}
597-
return listType(elementType!);
630+
currentGLB ??= unknownType;
631+
return listType(currentGLB);
598632
}
599633

600634
/// Analyzes a logical-or or logical-and pattern. [node] is the pattern
@@ -1213,6 +1247,9 @@ mixin TypeAnalyzer<
12131247

12141248
List<Variable>? getJoinedVariableComponents(Variable variable);
12151249

1250+
/// If [node] is [isRestPatternElement], returns its optional pattern.
1251+
Pattern? getRestPatternElementPattern(Node node);
1252+
12161253
/// Returns an [ExpressionCaseInfo] object describing the [index]th `case` or
12171254
/// `default` clause in the switch expression [node].
12181255
///
@@ -1331,6 +1368,11 @@ mixin TypeAnalyzer<
13311368
/// Stack effect: pushes (Statement).
13321369
void handleNoStatement(Statement node);
13331370

1371+
/// Called after visiting a rest element in a list or map pattern.
1372+
///
1373+
/// Stack effect: pushes (Pattern).
1374+
void handleRestPatternElement(Pattern container, Node restElement);
1375+
13341376
/// Called after visiting the scrutinee part of a switch statement or switch
13351377
/// expression. This is a hook to allow the client to start exhaustiveness
13361378
/// analysis.
@@ -1343,6 +1385,9 @@ mixin TypeAnalyzer<
13431385
/// Stack effect: none.
13441386
void handleSwitchScrutinee(Type type);
13451387

1388+
/// Returns whether [node] is a rest element in a list or map pattern.
1389+
bool isRestPatternElement(Node node);
1390+
13461391
/// Queries whether the switch statement or expression represented by [node]
13471392
/// was exhaustive. [expressionType] is the static type of the scrutinee.
13481393
///

pkg/_fe_analyzer_shared/lib/src/type_inference/type_operations.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ mixin TypeOperations<Type extends Object> {
7575
/// of [type] and `Null`.
7676
Type makeNullable(Type type);
7777

78+
/// If [type] is a subtype of the type `Iterable<T>` for some `T`, returns
79+
/// the type `T`. Otherwise returns `null`.
80+
Type? matchIterableType(Type type);
81+
7882
/// If [type] is a subtype of the type `List<T>` for some `T`, returns the
7983
/// type `T`. Otherwise returns `null`.
8084
Type? matchListType(Type type);

pkg/_fe_analyzer_shared/test/mini_ast.dart

Lines changed: 80 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -247,10 +247,13 @@ Expression intLiteral(int value, {bool? expectConversionToDouble}) =>
247247
expectConversionToDouble: expectConversionToDouble,
248248
location: computeLocation());
249249

250-
Pattern listPattern(List<Pattern> elements, {String? elementType}) =>
250+
Pattern listPattern(List<ListPatternElement> elements, {String? elementType}) =>
251251
_ListPattern(elementType == null ? null : Type(elementType), elements,
252252
location: computeLocation());
253253

254+
ListPatternElement listPatternRestElement([Pattern? pattern]) =>
255+
_RestPatternElement(pattern, location: computeLocation());
256+
254257
Statement localFunction(List<Statement> body) {
255258
var location = computeLocation();
256259
return _LocalFunction(_Block(body, location: location), location: location);
@@ -685,6 +688,12 @@ class Label extends Node {
685688
String toString() => _name;
686689
}
687690

691+
abstract class ListPatternElement implements Node {
692+
void preVisit(PreVisitor visitor, VariableBinder<Node, Var> variableBinder);
693+
694+
String _debugString({required bool needsKeywordOrType});
695+
}
696+
688697
/// Representation of an expression that can appear on the left hand side of an
689698
/// assignment (or as the target of `++` or `--`). Methods in this class may be
690699
/// used to create more complex expressions based on this one.
@@ -775,7 +784,13 @@ class MiniAstOperations
775784
'List <: int': false,
776785
'List <: Iterable': true,
777786
'List <: Object': true,
787+
'List<dynamic> <: Object': true,
788+
'List<Object?> <: Object': true,
789+
'List<int> <: dynamic': true,
790+
'List<int> <: Iterable<double>': false,
791+
'List<int> <: Iterable<int>': true,
778792
'List<int> <: List<num>': true,
793+
'List<int> <: String': false,
779794
'Never <: int': true,
780795
'Never <: int?': true,
781796
'Never <: Null': true,
@@ -847,6 +862,8 @@ class MiniAstOperations
847862
};
848863

849864
static final Map<String, Type> _coreGlbs = {
865+
'Object?, double': Type('double'),
866+
'Object?, int': Type('int'),
850867
'double, int': Type('Never'),
851868
'double?, int?': Type('Null'),
852869
'int?, num': Type('int'),
@@ -1029,12 +1046,22 @@ class MiniAstOperations
10291046
@override
10301047
Type makeNullable(Type type) => lub(type, Type('Null'));
10311048

1049+
@override
1050+
Type? matchIterableType(Type type) {
1051+
if (type is NonFunctionType &&
1052+
type.name == 'Iterable' &&
1053+
type.args.length == 1) {
1054+
return type.args[0];
1055+
}
1056+
return null;
1057+
}
1058+
10321059
@override
10331060
Type? matchListType(Type type) {
1034-
if (type is NonFunctionType) {
1035-
if (type.args.length == 1) {
1036-
return type.args[0];
1037-
}
1061+
if (type is NonFunctionType &&
1062+
type.name == 'List' &&
1063+
type.args.length == 1) {
1064+
return type.args[0];
10381065
}
10391066
return null;
10401067
}
@@ -1151,7 +1178,9 @@ class ObjectPatternRequiredType {
11511178
}
11521179
}
11531180

1154-
abstract class Pattern extends Node with PossiblyGuardedPattern {
1181+
abstract class Pattern extends Node
1182+
with PossiblyGuardedPattern
1183+
implements ListPatternElement {
11551184
Pattern._({required super.location}) : super._();
11561185

11571186
Pattern get nullAssert =>
@@ -1180,8 +1209,6 @@ abstract class Pattern extends Node with PossiblyGuardedPattern {
11801209
Pattern or(Pattern other) =>
11811210
_LogicalPattern(this, other, isAnd: false, location: computeLocation());
11821211

1183-
void preVisit(PreVisitor visitor, VariableBinder<Node, Var> variableBinder);
1184-
11851212
RecordPatternField recordField([String? name]) {
11861213
return RecordPatternField(
11871214
name: name,
@@ -1206,8 +1233,6 @@ abstract class Pattern extends Node with PossiblyGuardedPattern {
12061233
location: location,
12071234
);
12081235
}
1209-
1210-
String _debugString({required bool needsKeywordOrType});
12111236
}
12121237

12131238
class PatternVariableJoin extends Var {
@@ -2554,7 +2579,7 @@ class _LabeledStatement extends Statement {
25542579
class _ListPattern extends Pattern {
25552580
final Type? _elementType;
25562581

2557-
final List<Pattern> _elements;
2582+
final List<ListPatternElement> _elements;
25582583

25592584
_ListPattern(this._elementType, this._elements, {required super.location})
25602585
: super._();
@@ -3256,6 +3281,11 @@ class _MiniAstTypeAnalyzer
32563281
return null;
32573282
}
32583283

3284+
@override
3285+
Pattern? getRestPatternElementPattern(Node element) {
3286+
return element is _RestPatternElement ? element._pattern : null;
3287+
}
3288+
32593289
@override
32603290
SwitchExpressionMemberInfo<Node, Expression, Var>
32613291
getSwitchExpressionMemberInfo(
@@ -3400,6 +3430,19 @@ class _MiniAstTypeAnalyzer
34003430
_irBuilder.atom('noop', Kind.statement, location: node.location);
34013431
}
34023432

3433+
@override
3434+
void handleRestPatternElement(
3435+
Pattern container,
3436+
covariant _RestPatternElement restElement,
3437+
) {
3438+
if (restElement._pattern != null) {
3439+
_irBuilder.apply('...', [Kind.pattern], Kind.pattern,
3440+
location: restElement.location);
3441+
} else {
3442+
_irBuilder.atom('...', Kind.pattern, location: restElement.location);
3443+
}
3444+
}
3445+
34033446
@override
34043447
void handleSwitchScrutinee(Type type) {}
34053448

@@ -3418,6 +3461,11 @@ class _MiniAstTypeAnalyzer
34183461
}
34193462
}
34203463

3464+
@override
3465+
bool isRestPatternElement(Node element) {
3466+
return element is _RestPatternElement;
3467+
}
3468+
34213469
@override
34223470
bool isSwitchExhaustive(
34233471
covariant _SwitchStatement node, Type expressionType) {
@@ -3852,6 +3900,27 @@ class _RelationalPattern extends Pattern {
38523900
_debugString({required bool needsKeywordOrType}) => '$operator $operand';
38533901
}
38543902

3903+
class _RestPatternElement extends Node implements ListPatternElement {
3904+
final Pattern? _pattern;
3905+
3906+
_RestPatternElement(this._pattern, {required super.location}) : super._();
3907+
3908+
@override
3909+
void preVisit(PreVisitor visitor, VariableBinder<Node, Var> variableBinder) {
3910+
_pattern?.preVisit(visitor, variableBinder);
3911+
}
3912+
3913+
@override
3914+
String _debugString({required bool needsKeywordOrType}) {
3915+
var pattern = _pattern;
3916+
if (pattern == null) {
3917+
return '...';
3918+
} else {
3919+
return '...${pattern._debugString(needsKeywordOrType: false)}';
3920+
}
3921+
}
3922+
}
3923+
38553924
class _Return extends Statement {
38563925
_Return({required super.location});
38573926

0 commit comments

Comments
 (0)