Skip to content

Commit 9d9f599

Browse files
Kevin Millikincommit-bot@chromium.org
authored andcommitted
[cfe] Compile spread in sets
Compile spread in sets analogously with lists. Change-Id: Ieb3e139064a1174f7bb1c33aa82b21ca47fe768f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/95620 Reviewed-by: Dmitry Stefantsov <dmitryas@google.com> Commit-Queue: Kevin Millikin <kmillikin@google.com>
1 parent b5a1f6c commit 9d9f599

7 files changed

+209
-106
lines changed

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

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
2626
}
2727

2828
void visitSpreadElement(SpreadElement node, DartType typeContext) {
29-
if (node.parent is ListLiteral) {
29+
if (node.parent is ListLiteral || node.parent is SetLiteral) {
3030
inferrer.inferExpression(node.expression, const DynamicType(), true);
3131
return;
3232
}
@@ -1221,10 +1221,6 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
12211221
for (int i = 0; i < node.expressions.length; i++) {
12221222
Expression item = node.expressions[i];
12231223
if (item is SpreadElement) {
1224-
// TODO(dmitrayas): Remove this flag and all related uses of it
1225-
// when the desugaring is implemented.
1226-
bool replaced = false;
1227-
12281224
DartType spreadType = spreadTypes[i];
12291225
DartType spreadElementType = getSpreadElementType(spreadType);
12301226
if (spreadElementType == null) {
@@ -1235,7 +1231,6 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
12351231
templateSpreadTypeMismatch.withArguments(spreadType),
12361232
item.expression.fileOffset,
12371233
1)));
1238-
replaced = true;
12391234
} else if (spreadType is DynamicType) {
12401235
inferrer.ensureAssignable(inferrer.coreTypes.iterableClass.rawType,
12411236
spreadType, item.expression, item.expression.fileOffset);
@@ -1254,17 +1249,9 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
12541249
spreadElementType, node.typeArgument),
12551250
item.expression.fileOffset,
12561251
1)));
1257-
replaced = true;
12581252
}
12591253
}
12601254
}
1261-
1262-
if (!replaced) {
1263-
node.replaceChild(
1264-
node.expressions[i],
1265-
new InvalidExpression('unimplemented spread element')
1266-
..fileOffset = node.expressions[i].fileOffset);
1267-
}
12681255
} else {
12691256
inferrer.ensureAssignable(node.typeArgument, actualTypes[i],
12701257
node.expressions[i], node.expressions[i].fileOffset,

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

Lines changed: 75 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:kernel/ast.dart'
99
Arguments,
1010
Block,
1111
BlockExpression,
12+
DartType,
1213
Expression,
1314
ExpressionStatement,
1415
ForInStatement,
@@ -18,7 +19,9 @@ import 'package:kernel/ast.dart'
1819
MethodInvocation,
1920
Name,
2021
Procedure,
22+
SetLiteral,
2123
Statement,
24+
StaticInvocation,
2225
TreeNode,
2326
VariableDeclaration,
2427
VariableGet;
@@ -31,72 +34,113 @@ import 'collections.dart' show SpreadElement;
3134

3235
import '../source/source_loader.dart' show SourceLoader;
3336

37+
import 'redirecting_factory_body.dart' show RedirectingFactoryBody;
38+
3439
class CollectionTransformer extends Transformer {
3540
final CoreTypes coreTypes;
3641
final Procedure listAdd;
42+
final Procedure setFactory;
43+
final Procedure setAdd;
44+
45+
static Procedure _findSetFactory(CoreTypes coreTypes) {
46+
Procedure factory = coreTypes.index.getMember('dart:core', 'Set', '');
47+
RedirectingFactoryBody body = factory?.function?.body;
48+
return body?.target;
49+
}
3750

3851
CollectionTransformer(SourceLoader loader)
3952
: coreTypes = loader.coreTypes,
40-
listAdd = loader.coreTypes.index.getMember('dart:core', 'List', 'add');
53+
listAdd = loader.coreTypes.index.getMember('dart:core', 'List', 'add'),
54+
setFactory = _findSetFactory(loader.coreTypes),
55+
setAdd = loader.coreTypes.index.getMember('dart:core', 'Set', 'add');
4156

42-
@override
43-
TreeNode visitListLiteral(ListLiteral node) {
57+
TreeNode _translateListOrSet(
58+
Expression node, DartType elementType, List<Expression> elements,
59+
{bool isSet: false, bool isConst: false}) {
60+
// Translate elements in place up to the first spread if any.
4461
int i = 0;
45-
for (; i < node.expressions.length; ++i) {
46-
if (node.expressions[i] is SpreadElement) break;
47-
node.expressions[i] = node.expressions[i].accept(this)..parent = node;
62+
for (; i < elements.length; ++i) {
63+
if (elements[i] is SpreadElement) break;
64+
elements[i] = elements[i].accept(this)..parent = node;
4865
}
4966

50-
if (i == node.expressions.length) return node;
67+
// If there was no spread, we are done.
68+
if (i == elements.length) return node;
5169

52-
if (node.isConst) {
70+
if (isConst) {
5371
// We don't desugar const lists here. Remove spread for now so that they
5472
// don't leak out.
55-
for (; i < node.expressions.length; ++i) {
56-
Expression element = node.expressions[i];
73+
for (; i < elements.length; ++i) {
74+
Expression element = elements[i];
5775
if (element is SpreadElement) {
58-
element.parent.replaceChild(
59-
element,
60-
InvalidExpression('unimplemented spread element')
61-
..fileOffset = element.fileOffset);
76+
elements[i] = InvalidExpression('unimplemented spread element')
77+
..fileOffset = element.fileOffset
78+
..parent = node;
79+
} else {
80+
elements[i] = element.accept(this)..parent = node;
6281
}
6382
}
83+
return node;
6484
}
6585

66-
VariableDeclaration list = new VariableDeclaration.forValue(
67-
new ListLiteral([], typeArgument: node.typeArgument),
68-
type: new InterfaceType(coreTypes.listClass, [node.typeArgument]),
69-
isFinal: true);
70-
List<Statement> body = [list];
86+
// Build a block expression and create an empty list.
87+
VariableDeclaration result;
88+
if (isSet) {
89+
result = new VariableDeclaration.forValue(
90+
new StaticInvocation(
91+
setFactory, new Arguments([], types: [elementType])),
92+
type: new InterfaceType(coreTypes.setClass, [elementType]),
93+
isFinal: true);
94+
} else {
95+
result = new VariableDeclaration.forValue(
96+
new ListLiteral([], typeArgument: elementType),
97+
type: new InterfaceType(coreTypes.listClass, [elementType]),
98+
isFinal: true);
99+
}
100+
List<Statement> body = [result];
101+
// Add the elements up to the first spread.
71102
for (int j = 0; j < i; ++j) {
72103
body.add(new ExpressionStatement(new MethodInvocation(
73-
new VariableGet(list),
104+
new VariableGet(result),
74105
new Name('add'),
75-
new Arguments([node.expressions[j]]),
76-
listAdd)));
106+
new Arguments([elements[j]]),
107+
isSet ? setAdd : listAdd)));
77108
}
78-
for (; i < node.expressions.length; ++i) {
79-
Expression element = node.expressions[i];
109+
// Translate the elements starting with the first spread.
110+
for (; i < elements.length; ++i) {
111+
Expression element = elements[i];
80112
if (element is SpreadElement) {
81-
VariableDeclaration elt = new VariableDeclaration(null,
82-
type: node.typeArgument, isFinal: true);
113+
VariableDeclaration elt =
114+
new VariableDeclaration(null, type: elementType, isFinal: true);
83115
body.add(new ForInStatement(
84116
elt,
85117
element.expression.accept(this),
86118
new ExpressionStatement(new MethodInvocation(
87-
new VariableGet(list),
119+
new VariableGet(result),
88120
new Name('add'),
89121
new Arguments([new VariableGet(elt)]),
90-
listAdd))));
122+
isSet ? setAdd : listAdd))));
91123
} else {
92124
body.add(new ExpressionStatement(new MethodInvocation(
93-
new VariableGet(list),
125+
new VariableGet(result),
94126
new Name('add'),
95127
new Arguments([element.accept(this)]),
96-
listAdd)));
128+
isSet ? setAdd : listAdd)));
97129
}
98130
}
99131

100-
return new BlockExpression(new Block(body), new VariableGet(list));
132+
return new BlockExpression(new Block(body), new VariableGet(result));
133+
}
134+
135+
@override
136+
TreeNode visitListLiteral(ListLiteral node) {
137+
return _translateListOrSet(node, node.typeArgument, node.expressions,
138+
isConst: node.isConst, isSet: false);
139+
}
140+
141+
@override
142+
TreeNode visitSetLiteral(SetLiteral node) {
143+
return _translateListOrSet(node, node.typeArgument, node.expressions,
144+
isConst: node.isConst, isSet: true);
101145
}
102146
}

pkg/front_end/lib/src/fasta/source/source_loader.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,12 +1016,12 @@ class SourceLoader extends Loader<Library> {
10161016

10171017
void transformPostInference(
10181018
TreeNode node, bool transformSetLiterals, bool transformCollections) {
1019-
if (transformSetLiterals) {
1020-
node.accept(setLiteralTransformer ??= new SetLiteralTransformer(this));
1021-
}
10221019
if (transformCollections) {
10231020
node.accept(collectionTransformer ??= new CollectionTransformer(this));
10241021
}
1022+
if (transformSetLiterals) {
1023+
node.accept(setLiteralTransformer ??= new SetLiteralTransformer(this));
1024+
}
10251025
}
10261026

10271027
void transformListPostInference(List<TreeNode> list,

pkg/front_end/testcases/spread_collection.dart.strong.expect

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ static method main() → dynamic {
1313
#t1.{core::List::add}(#t3);
1414
} =>#t1;
1515
final core::Map<core::int, core::int> aMap = <core::int, core::int>{1: 1, invalid-expression "unimplemented spread entry": null, invalid-expression "unimplemented spread entry": null};
16-
final core::Set<core::int> aSet = let final core::Set<core::int> #t4 = col::LinkedHashSet::•<core::int>() in let final dynamic #t5 = #t4.{core::Set::add}(1) in let final dynamic #t6 = #t4.{core::Set::add}(invalid-expression "unimplemented spread element") in let final dynamic #t7 = #t4.{core::Set::add}(invalid-expression "unimplemented spread element") in #t4;
16+
final core::Set<core::int> aSet = block {
17+
final core::Set<core::int> #t4 = col::LinkedHashSet::•<core::int>();
18+
#t4.{core::Set::add}(1);
19+
for (final core::int #t5 in <core::int>[2])
20+
#t4.{core::Set::add}(#t5);
21+
for (final core::int #t6 in <core::int>[3])
22+
#t4.{core::Set::add}(#t6);
23+
} =>#t4;
1724
final core::Map<dynamic, dynamic> aSetOrMap = <dynamic, dynamic>{invalid-expression "unimplemented spread entry": null};
1825
core::print(aList);
1926
core::print(aSet);

pkg/front_end/testcases/spread_collection.dart.strong.transformed.expect

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ static method main() → dynamic {
1313
#t1.{core::List::add}(#t3);
1414
} =>#t1;
1515
final core::Map<core::int, core::int> aMap = <core::int, core::int>{1: 1, invalid-expression "unimplemented spread entry": null, invalid-expression "unimplemented spread entry": null};
16-
final core::Set<core::int> aSet = let final core::Set<core::int> #t4 = col::LinkedHashSet::•<core::int>() in let final core::bool #t5 = #t4.{core::Set::add}(1) in let final core::bool #t6 = #t4.{core::Set::add}(invalid-expression "unimplemented spread element") in let final core::bool #t7 = #t4.{core::Set::add}(invalid-expression "unimplemented spread element") in #t4;
16+
final core::Set<core::int> aSet = block {
17+
final core::Set<core::int> #t4 = col::LinkedHashSet::•<core::int>();
18+
#t4.{core::Set::add}(1);
19+
for (final core::int #t5 in <core::int>[2])
20+
#t4.{core::Set::add}(#t5);
21+
for (final core::int #t6 in <core::int>[3])
22+
#t4.{core::Set::add}(#t6);
23+
} =>#t4;
1724
final core::Map<dynamic, dynamic> aSetOrMap = <dynamic, dynamic>{invalid-expression "unimplemented spread entry": null};
1825
core::print(aList);
1926
core::print(aSet);

0 commit comments

Comments
 (0)