Skip to content

Commit 874a662

Browse files
author
Dart CI
committed
Version 2.19.0-380.0.dev
Merge 7043c88 into dev
2 parents 0466e37 + 7043c88 commit 874a662

File tree

32 files changed

+1256
-211
lines changed

32 files changed

+1256
-211
lines changed

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

Lines changed: 94 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,17 @@ class NamedType<Type extends Object> {
2929
NamedType(this.name, this.type);
3030
}
3131

32-
class RecordPatternField<Pattern extends Object> {
32+
class RecordPatternField<Node extends Object, Pattern extends Object> {
33+
/// The client specific node from which this object was created. It can be
34+
/// used for error reporting.
35+
final Node node;
36+
3337
/// If not `null` then the field is named, otherwise it is positional.
3438
final String? name;
3539
final Pattern pattern;
3640

3741
RecordPatternField({
42+
required this.node,
3843
required this.name,
3944
required this.pattern,
4045
});
@@ -341,6 +346,33 @@ mixin TypeAnalyzer<
341346
_analyzeIfCommon(node, ifTrue, ifFalse);
342347
}
343348

349+
/// Analyzes a collection element of the form `if (condition) ifTrue` or
350+
/// `if (condition) ifTrue else ifFalse`.
351+
///
352+
/// [node] should be the AST node for the entire element, [condition] for
353+
/// the condition expression, [ifTrue] for the "then" branch, and [ifFalse]
354+
/// for the "else" branch (if present).
355+
///
356+
/// Stack effect: pushes (Expression condition, CollectionElement ifTrue,
357+
/// CollectionElement ifFalse). Note that if there is no `else` clause, the
358+
/// representation for `ifFalse` will be pushed by
359+
/// [handleNoCollectionElement].
360+
void analyzeIfElement({
361+
required Node node,
362+
required Expression condition,
363+
required Node ifTrue,
364+
required Node? ifFalse,
365+
required Object? context,
366+
}) {
367+
// Stack: ()
368+
flow?.ifStatement_conditionBegin();
369+
analyzeExpression(condition, boolType);
370+
handle_ifElement_conditionEnd(node);
371+
// Stack: (Expression condition)
372+
flow?.ifStatement_thenBegin(condition, node);
373+
_analyzeIfElementCommon(node, ifTrue, ifFalse, context);
374+
}
375+
344376
/// Analyzes a statement of the form `if (condition) ifTrue` or
345377
/// `if (condition) ifTrue else ifFalse`.
346378
///
@@ -587,7 +619,7 @@ mixin TypeAnalyzer<
587619
MatchContext<Node, Expression> context,
588620
Pattern node, {
589621
required Type? requiredType,
590-
required List<RecordPatternField<Pattern>> fields,
622+
required List<RecordPatternField<Node, Pattern>> fields,
591623
}) {
592624
requiredType ??= downwardInferObjectPatternRequiredType(
593625
matchedType: matchedType,
@@ -606,7 +638,7 @@ mixin TypeAnalyzer<
606638
}
607639

608640
// Stack: ()
609-
for (RecordPatternField<Pattern> field in fields) {
641+
for (RecordPatternField<Node, Pattern> field in fields) {
610642
Type propertyType = resolveObjectPatternPropertyGet(
611643
receiverType: requiredType,
612644
field: field,
@@ -638,9 +670,12 @@ mixin TypeAnalyzer<
638670
Map<Variable, VariableTypeInfo<Pattern, Type>> typeInfos,
639671
MatchContext<Node, Expression> context,
640672
Pattern node, {
641-
required List<RecordPatternField<Pattern>> fields,
673+
required List<RecordPatternField<Node, Pattern>> fields,
642674
}) {
643-
void dispatchField(RecordPatternField<Pattern> field, Type matchedType) {
675+
void dispatchField(
676+
RecordPatternField<Node, Pattern> field,
677+
Type matchedType,
678+
) {
644679
dispatchPattern(matchedType, typeInfos, context, field.pattern);
645680
}
646681

@@ -653,7 +688,7 @@ mixin TypeAnalyzer<
653688
// Build the required type.
654689
int requiredTypePositionalCount = 0;
655690
List<NamedType<Type>> requiredTypeNamedTypes = [];
656-
for (RecordPatternField<Pattern> field in fields) {
691+
for (RecordPatternField<Node, Pattern> field in fields) {
657692
String? name = field.name;
658693
if (name == null) {
659694
requiredTypePositionalCount++;
@@ -709,11 +744,11 @@ mixin TypeAnalyzer<
709744
///
710745
/// Stack effect: none.
711746
Type analyzeRecordPatternSchema({
712-
required List<RecordPatternField<Pattern>> fields,
747+
required List<RecordPatternField<Node, Pattern>> fields,
713748
}) {
714749
List<Type> positional = [];
715750
List<NamedType<Type>> named = [];
716-
for (RecordPatternField<Pattern> field in fields) {
751+
for (RecordPatternField<Node, Pattern> field in fields) {
717752
Type fieldType = dispatchPatternSchema(field.pattern);
718753
String? name = field.name;
719754
if (name != null) {
@@ -1036,6 +1071,15 @@ mixin TypeAnalyzer<
10361071
/// If [type] is a record type, returns it.
10371072
RecordType<Type>? asRecordType(Type type);
10381073

1074+
/// Calls the appropriate `analyze` method according to the form of
1075+
/// collection [element], and then adjusts the stack as needed to combine
1076+
/// any sub-structures into a single collection element.
1077+
///
1078+
/// For example, if [element] is an `if` element, calls [analyzeIfElement].
1079+
///
1080+
/// Stack effect: pushes (CollectionElement).
1081+
void dispatchCollectionElement(Node element, Object? context);
1082+
10391083
/// Calls the appropriate `analyze` method according to the form of
10401084
/// [expression], and then adjusts the stack as needed to combine any
10411085
/// sub-structures into a single expression.
@@ -1121,6 +1165,15 @@ mixin TypeAnalyzer<
11211165
SwitchStatementMemberInfo<Node, Statement, Expression>
11221166
getSwitchStatementMemberInfo(Statement node, int caseIndex);
11231167

1168+
/// Called after visiting the expression of an `if` element.
1169+
void handle_ifElement_conditionEnd(Node node) {}
1170+
1171+
/// Called after visiting the `else` element of an `if` element.
1172+
void handle_ifElement_elseEnd(Node node, Node ifFalse) {}
1173+
1174+
/// Called after visiting the `then` element of an `if` element.
1175+
void handle_ifElement_thenEnd(Node node, Node ifTrue) {}
1176+
11241177
/// Called after visiting the expression of an `if` statement.
11251178
void handle_ifStatement_conditionEnd(Statement node) {}
11261179

@@ -1170,6 +1223,13 @@ mixin TypeAnalyzer<
11701223
required int executionPathIndex,
11711224
required int numStatements});
11721225

1226+
/// Called when visiting a syntactic construct where there is an implicit
1227+
/// no-op collection element. For example, this is called in place of the
1228+
/// missing `else` part of an `if` element that lacks an `else` clause.
1229+
///
1230+
/// Stack effect: pushes (CollectionElement).
1231+
void handleNoCollectionElement(Node node);
1232+
11731233
/// Called when visiting a `case` that lacks a guard clause. Since the lack
11741234
/// of a guard clause is semantically equivalent to `when true`, this method
11751235
/// should behave similarly to visiting the boolean literal `true`.
@@ -1220,7 +1280,7 @@ mixin TypeAnalyzer<
12201280
/// should report an error, and return `dynamic` for recovery.
12211281
Type resolveObjectPatternPropertyGet({
12221282
required Type receiverType,
1223-
required RecordPatternField<Pattern> field,
1283+
required RecordPatternField<Node, Pattern> field,
12241284
});
12251285

12261286
/// Records that type inference has assigned a [type] to a [variable]. This
@@ -1253,6 +1313,29 @@ mixin TypeAnalyzer<
12531313
// Stack: (Statement ifTrue, Statement ifFalse)
12541314
}
12551315

1316+
/// Common functionality shared by [analyzeIfElement] and
1317+
/// [analyzeIfCaseElement].
1318+
///
1319+
/// Stack effect: pushes (CollectionElement ifTrue,
1320+
/// CollectionElement ifFalse).
1321+
void _analyzeIfElementCommon(
1322+
Node node, Node ifTrue, Node? ifFalse, Object? context) {
1323+
// Stack: ()
1324+
dispatchCollectionElement(ifTrue, context);
1325+
handle_ifElement_thenEnd(node, ifTrue);
1326+
// Stack: (CollectionElement ifTrue)
1327+
if (ifFalse == null) {
1328+
handleNoCollectionElement(node);
1329+
flow?.ifStatement_end(false);
1330+
} else {
1331+
flow?.ifStatement_elseBegin();
1332+
dispatchCollectionElement(ifFalse, context);
1333+
flow?.ifStatement_end(true);
1334+
handle_ifElement_elseEnd(node, ifFalse);
1335+
}
1336+
// Stack: (CollectionElement ifTrue, CollectionElement ifFalse)
1337+
}
1338+
12561339
void _checkGuardType(Expression expression, Type type) {
12571340
// TODO(paulberry): harmonize this with analyzer's checkForNonBoolExpression
12581341
// TODO(paulberry): spec says the type must be `bool` or `dynamic`. This
@@ -1267,7 +1350,7 @@ mixin TypeAnalyzer<
12671350
/// [matchedType], returns matched types for each field in [fields].
12681351
/// Otherwise returns `null`.
12691352
List<Type>? _matchRecordTypeShape(
1270-
List<RecordPatternField<Pattern>> fields,
1353+
List<RecordPatternField<Node, Pattern>> fields,
12711354
RecordType<Type> matchedType,
12721355
) {
12731356
Map<String, Type> matchedTypeNamed = {};
@@ -1278,7 +1361,7 @@ mixin TypeAnalyzer<
12781361
List<Type> result = [];
12791362
int positionalIndex = 0;
12801363
int namedCount = 0;
1281-
for (RecordPatternField<Pattern> field in fields) {
1364+
for (RecordPatternField<Node, Pattern> field in fields) {
12821365
Type? fieldType;
12831366
String? name = field.name;
12841367
if (name != null) {

0 commit comments

Comments
 (0)