Skip to content

Commit 574e12d

Browse files
chloestefantsovaCommit Queue
authored and
Commit Queue
committed
[cfe] Support pattern entry-to-element conversion in type inference
Part of #49749 Change-Id: I5a227763225eda6a8154591fa35aa7cc66c0050a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/285320 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent c8f07e6 commit 574e12d

14 files changed

+890
-38
lines changed

pkg/front_end/lib/src/fasta/kernel/body_builder.dart

+30-12
Original file line numberDiff line numberDiff line change
@@ -6692,16 +6692,22 @@ class BodyBuilder extends StackListenerImpl
66926692
node = forest.createIfMapEntry(
66936693
offsetForToken(ifToken), condition.expression, entry);
66946694
} else {
6695-
node = forest.createIfCaseMapEntry(
6696-
offsetForToken(ifToken), condition.expression, patternGuard, entry);
6695+
node = forest.createIfCaseMapEntry(offsetForToken(ifToken),
6696+
prelude: [],
6697+
expression: condition.expression,
6698+
patternGuard: patternGuard,
6699+
then: entry);
66976700
}
66986701
} else {
66996702
if (patternGuard == null) {
67006703
node = forest.createIfElement(
67016704
offsetForToken(ifToken), condition.expression, toValue(entry));
67026705
} else {
67036706
node = forest.createIfCaseElement(offsetForToken(ifToken),
6704-
condition.expression, patternGuard, toValue(entry));
6707+
prelude: [],
6708+
expression: condition.expression,
6709+
patternGuard: patternGuard,
6710+
then: toValue(entry));
67056711
}
67066712
}
67076713
push(node);
@@ -6747,7 +6753,11 @@ class BodyBuilder extends StackListenerImpl
67476753
condition.expression, thenEntry, elseEntry);
67486754
} else {
67496755
node = forest.createIfCaseMapEntry(offsetForToken(ifToken),
6750-
condition.expression, patternGuard, thenEntry, elseEntry);
6756+
prelude: [],
6757+
expression: condition.expression,
6758+
patternGuard: patternGuard,
6759+
then: thenEntry,
6760+
otherwise: elseEntry);
67516761
}
67526762
} else if (elseEntry is ControlFlowElement) {
67536763
MapLiteralEntry? elseMapEntry = elseEntry
@@ -6758,7 +6768,11 @@ class BodyBuilder extends StackListenerImpl
67586768
condition.expression, thenEntry, elseMapEntry);
67596769
} else {
67606770
node = forest.createIfCaseMapEntry(offsetForToken(ifToken),
6761-
condition.expression, patternGuard, thenEntry, elseMapEntry);
6771+
prelude: [],
6772+
expression: condition.expression,
6773+
patternGuard: patternGuard,
6774+
then: thenEntry,
6775+
otherwise: elseMapEntry);
67626776
}
67636777
} else {
67646778
int offset = elseEntry.fileOffset;
@@ -6788,7 +6802,11 @@ class BodyBuilder extends StackListenerImpl
67886802
condition.expression, thenMapEntry, elseEntry);
67896803
} else {
67906804
node = forest.createIfCaseMapEntry(offsetForToken(ifToken),
6791-
condition.expression, patternGuard, thenMapEntry, elseEntry);
6805+
prelude: [],
6806+
expression: condition.expression,
6807+
patternGuard: patternGuard,
6808+
then: thenMapEntry,
6809+
otherwise: elseEntry);
67926810
}
67936811
} else {
67946812
int offset = thenEntry.fileOffset;
@@ -6813,12 +6831,12 @@ class BodyBuilder extends StackListenerImpl
68136831
node = forest.createIfElement(offsetForToken(ifToken),
68146832
condition.expression, toValue(thenEntry), toValue(elseEntry));
68156833
} else {
6816-
node = forest.createIfCaseElement(
6817-
offsetForToken(ifToken),
6818-
condition.expression,
6819-
condition.patternGuard!,
6820-
toValue(thenEntry),
6821-
toValue(elseEntry));
6834+
node = forest.createIfCaseElement(offsetForToken(ifToken),
6835+
prelude: [],
6836+
expression: condition.expression,
6837+
patternGuard: condition.patternGuard!,
6838+
then: toValue(thenEntry),
6839+
otherwise: toValue(elseEntry));
68226840
}
68236841
}
68246842
push(node);

pkg/front_end/lib/src/fasta/kernel/collections.dart

+37-7
Original file line numberDiff line numberDiff line change
@@ -837,13 +837,42 @@ Expression convertToElement(
837837
onConvertMapEntry(entry, result);
838838
return result;
839839
}
840-
if (entry is ForMapEntry) {
841-
ForElement result = new ForElement(entry.variables, entry.condition,
842-
entry.updates, convertToElement(entry.body, helper, onConvertMapEntry))
840+
if (entry is IfCaseMapEntry) {
841+
IfCaseElement result = new IfCaseElement(
842+
prelude: entry.prelude,
843+
expression: entry.expression,
844+
patternGuard: entry.patternGuard,
845+
then: convertToElement(entry.then, helper, onConvertMapEntry),
846+
otherwise: entry.otherwise == null
847+
? null
848+
: convertToElement(entry.otherwise!, helper, onConvertMapEntry))
843849
..fileOffset = entry.fileOffset;
844850
onConvertMapEntry(entry, result);
845851
return result;
846852
}
853+
if (entry is ForMapEntry) {
854+
if (entry is PatternForMapEntry) {
855+
PatternForElement result = new PatternForElement(
856+
patternVariableDeclaration: entry.patternVariableDeclaration,
857+
prelude: entry.prelude,
858+
variables: entry.variables,
859+
condition: entry.condition,
860+
updates: entry.updates,
861+
body: convertToElement(entry.body, helper, onConvertMapEntry))
862+
..fileOffset = entry.fileOffset;
863+
onConvertMapEntry(entry, result);
864+
return result;
865+
} else {
866+
ForElement result = new ForElement(
867+
entry.variables,
868+
entry.condition,
869+
entry.updates,
870+
convertToElement(entry.body, helper, onConvertMapEntry))
871+
..fileOffset = entry.fileOffset;
872+
onConvertMapEntry(entry, result);
873+
return result;
874+
}
875+
}
847876
if (entry is ForInMapEntry) {
848877
ForInElement result = new ForInElement(
849878
entry.variable,
@@ -925,10 +954,11 @@ MapLiteralEntry convertToMapEntry(Expression element, InferenceHelper helper,
925954
}
926955
if (element is IfCaseElement) {
927956
IfCaseMapEntry result = new IfCaseMapEntry(
928-
element.expression,
929-
element.patternGuard,
930-
convertToMapEntry(element.then, helper, onConvertElement),
931-
element.otherwise == null
957+
prelude: [],
958+
expression: element.expression,
959+
patternGuard: element.patternGuard,
960+
then: convertToMapEntry(element.then, helper, onConvertElement),
961+
otherwise: element.otherwise == null
932962
? null
933963
: convertToMapEntry(element.otherwise!, helper, onConvertElement))
934964
..fileOffset = element.fileOffset;

pkg/front_end/lib/src/fasta/kernel/forest.dart

+24-8
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,20 @@ class Forest {
272272
return new IfElement(condition, then, otherwise)..fileOffset = fileOffset;
273273
}
274274

275-
Expression createIfCaseElement(int fileOffset, Expression expression,
276-
PatternGuard patternGuard, Expression then,
277-
[Expression? otherwise]) {
275+
Expression createIfCaseElement(int fileOffset,
276+
{required List<Statement> prelude,
277+
required Expression expression,
278+
required PatternGuard patternGuard,
279+
required Expression then,
280+
Expression? otherwise}) {
278281
// ignore: unnecessary_null_comparison
279282
assert(fileOffset != null);
280-
return new IfCaseElement(expression, patternGuard, then, otherwise)
283+
return new IfCaseElement(
284+
prelude: prelude,
285+
expression: expression,
286+
patternGuard: patternGuard,
287+
then: then,
288+
otherwise: otherwise)
281289
..fileOffset = fileOffset;
282290
}
283291

@@ -289,12 +297,20 @@ class Forest {
289297
return new IfMapEntry(condition, then, otherwise)..fileOffset = fileOffset;
290298
}
291299

292-
MapLiteralEntry createIfCaseMapEntry(int fileOffset, Expression expression,
293-
PatternGuard patternGuard, MapLiteralEntry then,
294-
[MapLiteralEntry? otherwise]) {
300+
MapLiteralEntry createIfCaseMapEntry(int fileOffset,
301+
{required List<Statement> prelude,
302+
required Expression expression,
303+
required PatternGuard patternGuard,
304+
required MapLiteralEntry then,
305+
MapLiteralEntry? otherwise}) {
295306
// ignore: unnecessary_null_comparison
296307
assert(fileOffset != null);
297-
return new IfCaseMapEntry(expression, patternGuard, then, otherwise)
308+
return new IfCaseMapEntry(
309+
prelude: prelude,
310+
expression: expression,
311+
patternGuard: patternGuard,
312+
then: then,
313+
otherwise: otherwise)
298314
..fileOffset = fileOffset;
299315
}
300316

pkg/front_end/lib/src/fasta/kernel/internal_ast.dart

+21-7
Original file line numberDiff line numberDiff line change
@@ -4813,9 +4813,15 @@ class IfCaseElement extends InternalExpression with ControlFlowElement {
48134813
PatternGuard patternGuard;
48144814
Expression then;
48154815
Expression? otherwise;
4816-
late List<Statement> replacement;
4816+
List<Statement> prelude;
48174817

4818-
IfCaseElement(this.expression, this.patternGuard, this.then, this.otherwise) {
4818+
IfCaseElement(
4819+
{required this.prelude,
4820+
required this.expression,
4821+
required this.patternGuard,
4822+
required this.then,
4823+
this.otherwise}) {
4824+
setParents(prelude, this);
48194825
expression.parent = this;
48204826
patternGuard.parent = this;
48214827
then.parent = this;
@@ -4861,9 +4867,13 @@ class IfCaseElement extends InternalExpression with ControlFlowElement {
48614867
}
48624868
if (otherwiseEntry == null) return null;
48634869
}
4864-
IfCaseMapEntry result =
4865-
new IfCaseMapEntry(expression, patternGuard, thenEntry, otherwiseEntry)
4866-
..fileOffset = fileOffset;
4870+
IfCaseMapEntry result = new IfCaseMapEntry(
4871+
prelude: prelude,
4872+
expression: expression,
4873+
patternGuard: patternGuard,
4874+
then: thenEntry,
4875+
otherwise: otherwiseEntry)
4876+
..fileOffset = fileOffset;
48674877
onConvertElement(this, result);
48684878
return result;
48694879
}
@@ -4880,10 +4890,14 @@ class IfCaseMapEntry extends TreeNode
48804890
PatternGuard patternGuard;
48814891
MapLiteralEntry then;
48824892
MapLiteralEntry? otherwise;
4883-
late List<Statement> replacement;
4893+
List<Statement> prelude;
48844894

48854895
IfCaseMapEntry(
4886-
this.expression, this.patternGuard, this.then, this.otherwise) {
4896+
{required this.prelude,
4897+
required this.expression,
4898+
required this.patternGuard,
4899+
required this.then,
4900+
this.otherwise}) {
48874901
expression.parent = this;
48884902
patternGuard.parent = this;
48894903
then.parent = this;

pkg/front_end/lib/src/fasta/type_inference/inference_visitor.dart

+4-4
Original file line numberDiff line numberDiff line change
@@ -2273,7 +2273,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
22732273
createAndExpression(condition, guard, fileOffset: guard.fileOffset);
22742274
}
22752275
element.expression = condition;
2276-
element.replacement = [
2276+
element.prelude = [
22772277
...element.patternGuard.pattern.declaredVariables,
22782278
...matchingCache.declarations,
22792279
];
@@ -2829,7 +2829,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
28292829
IfStatement ifStatement =
28302830
_createIf(element.fileOffset, element.expression, thenBody, elseBody);
28312831
libraryBuilder.loader.dataForTesting?.registerAlias(element, ifStatement);
2832-
body.addAll(element.replacement);
2832+
body.addAll(element.prelude);
28332833
body.add(ifStatement);
28342834
}
28352835

@@ -3165,7 +3165,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
31653165
IfStatement ifStatement = _createIf(
31663166
entry.fileOffset, entry.expression, thenStatement, elseStatement);
31673167
libraryBuilder.loader.dataForTesting?.registerAlias(entry, ifStatement);
3168-
body.addAll(entry.replacement);
3168+
body.addAll(entry.prelude);
31693169
body.add(ifStatement);
31703170
}
31713171

@@ -4181,7 +4181,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
41814181
createAndExpression(condition, guard, fileOffset: guard.fileOffset);
41824182
}
41834183
entry.expression = condition;
4184-
entry.replacement = [
4184+
entry.prelude = [
41854185
...entry.patternGuard.pattern.declaredVariables,
41864186
...matchingCache.declarations,
41874187
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
Iterable<dynamic> test1(dynamic x, dynamic another) {
6+
return {for (var [int i, int n] = x; i < n; i++) ...another};
7+
}
8+
9+
Iterable<dynamic> test2(dynamic x, dynamic another) {
10+
return {if (x case String _) ...another};
11+
}
12+
13+
Iterable<dynamic> test3(dynamic x, dynamic another) {
14+
return {for (var [int _] in x) ...another};
15+
}
16+
17+
main() {
18+
expectSetEquals(
19+
test1([0, 2], {1, 2, 3}) as Set,
20+
{1, 2, 3},
21+
);
22+
expectSetEquals(
23+
test2([0, 0], {1, 2, 3}) as Set,
24+
{},
25+
);
26+
expectThrows(() => test1([], {}));
27+
28+
expectSetEquals(
29+
test2("foo", {1, 2, 3}) as Set,
30+
{1, 2, 3},
31+
);
32+
expectSetEquals(
33+
test2(false, {1, 2, 3}) as Set,
34+
{},
35+
);
36+
37+
expectSetEquals(
38+
test3([[0], [1]], {1, 2, 3}) as Set,
39+
{1, 2, 3},
40+
);
41+
expectThrows(() => test3([null], {}));
42+
}
43+
44+
expectSetEquals(Set x, Set y) {
45+
if (!x.containsAll(y) || !y.containsAll(x)) {
46+
throw "Expected sets '${x}' and '${y}' to be equal.";
47+
}
48+
}
49+
50+
expectThrows(void Function() f) {
51+
bool hasThrown = true;
52+
try {
53+
f();
54+
hasThrown = false;
55+
} catch (e) {}
56+
if (!hasThrown) {
57+
throw "Expected the function to throw.";
58+
}
59+
}

0 commit comments

Comments
 (0)