Skip to content

Commit 4daa9b9

Browse files
Kevin Millikincommit-bot@chromium.org
Kevin Millikin
authored andcommitted
[cfe] Compile if elements in lists and sets
If elements are compiled to if statements. The type inference rules including insertion of runtime checks are not yet implemented. Change-Id: Iaa7ab709a7acacf952887b17ac1081a9fecd7cef Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97200 Commit-Queue: Kevin Millikin <[email protected]> Reviewed-by: Dmitry Stefantsov <[email protected]>
1 parent c9efa47 commit 4daa9b9

18 files changed

+386
-137
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3652,6 +3652,8 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
36523652
push(ifToken);
36533653
}
36543654

3655+
void handleElseControlFlow(Token elseToken) {}
3656+
36553657
@override
36563658
void endIfControlFlow(Token token) {
36573659
debugEvent("endIfControlFlow");

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,13 @@ import 'package:kernel/visitor.dart'
2828

2929
import '../problems.dart' show getFileUri, unsupported;
3030

31+
/// Mixin for spread and control-flow elements.
32+
///
3133
/// Spread and control-flow elements are not truly expressions and they cannot
3234
/// appear in arbitrary expression contexts in the Kernel program. They can
33-
/// only appear as elements in list or set literals.
34-
mixin _FakeExpressionMixin on Expression {
35+
/// only appear as elements in list or set literals. They are translated into
36+
/// a lower-level representation and never serialized to .dill files.
37+
mixin CollectionElement on Expression {
3538
/// Spread and contol-flow elements are not expressions and do not have a
3639
/// static type.
3740
@override
@@ -48,7 +51,7 @@ mixin _FakeExpressionMixin on Expression {
4851
}
4952

5053
/// A spread element in a list or set literal.
51-
class SpreadElement extends Expression with _FakeExpressionMixin {
54+
class SpreadElement extends Expression with CollectionElement {
5255
Expression expression;
5356
bool isNullAware;
5457

@@ -71,7 +74,7 @@ class SpreadElement extends Expression with _FakeExpressionMixin {
7174
}
7275

7376
/// An 'if' element in a list or set literal.
74-
class IfElement extends Expression with _FakeExpressionMixin {
77+
class IfElement extends Expression with CollectionElement {
7578
Expression condition;
7679
Expression then;
7780
Expression otherwise;
@@ -107,7 +110,7 @@ class IfElement extends Expression with _FakeExpressionMixin {
107110
}
108111

109112
/// A 'for' element in a list or set literal.
110-
class ForElement extends Expression with _FakeExpressionMixin {
113+
class ForElement extends Expression with CollectionElement {
111114
final List<VariableDeclaration> variables; // May be empty, but not null.
112115
Expression condition; // May be null.
113116
final List<Expression> updates; // May be empty, but not null.
@@ -144,7 +147,7 @@ class ForElement extends Expression with _FakeExpressionMixin {
144147
}
145148

146149
/// A 'for-in' element in a list or set literal.
147-
class ForInElement extends Expression with _FakeExpressionMixin {
150+
class ForInElement extends Expression with CollectionElement {
148151
VariableDeclaration variable; // Has no initializer.
149152
Expression iterable;
150153
Expression body;

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

Lines changed: 63 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
1111

1212
@override
1313
void defaultExpression(Expression node, DartType typeContext) {
14-
if (node is IfElement) {
15-
visitIfElement(node, typeContext);
16-
return;
17-
}
1814
unhandled("${node.runtimeType}", "InferenceVisitor", node.fileOffset,
1915
inferrer.helper.uri);
2016
}
@@ -25,11 +21,6 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
2521
inferrer.helper.uri);
2622
}
2723

28-
visitIfElement(IfElement node, DartType typeContext) {
29-
node.parent.replaceChild(node,
30-
new InvalidExpression('unhandled if element in collection literal'));
31-
}
32-
3324
@override
3425
void visitInvalidExpression(InvalidExpression node, DartType typeContext) {}
3526

@@ -665,6 +656,45 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
665656
return null;
666657
}
667658

659+
DartType inferElement(
660+
Expression element,
661+
int index,
662+
DartType inferredTypeArgument,
663+
List<DartType> spreadTypes,
664+
bool inferenceNeeded,
665+
bool typeChecksNeeded) {
666+
if (element is SpreadElement) {
667+
DartType spreadType = inferrer.inferExpression(
668+
element.expression,
669+
new InterfaceType(inferrer.coreTypes.iterableClass,
670+
<DartType>[inferredTypeArgument]),
671+
inferenceNeeded || typeChecksNeeded,
672+
isVoidAllowed: true);
673+
if (typeChecksNeeded) {
674+
spreadTypes[index] = spreadType;
675+
}
676+
// Use 'dynamic' for error recovery.
677+
return getSpreadElementType(spreadType, element.isNullAware) ??
678+
const DynamicType();
679+
} else if (element is IfElement) {
680+
inferrer.inferExpression(element.condition,
681+
inferrer.coreTypes.boolClass.rawType, typeChecksNeeded,
682+
isVoidAllowed: false);
683+
inferElement(element.then, index, inferredTypeArgument, spreadTypes,
684+
inferenceNeeded, typeChecksNeeded);
685+
if (element.otherwise != null) {
686+
inferElement(element.otherwise, index, inferredTypeArgument,
687+
spreadTypes, inferenceNeeded, typeChecksNeeded);
688+
}
689+
// TODO(kmillikin): Implement inference rules for if elements.
690+
return const DynamicType();
691+
} else {
692+
return inferrer.inferExpression(
693+
element, inferredTypeArgument, inferenceNeeded || typeChecksNeeded,
694+
isVoidAllowed: true);
695+
}
696+
}
697+
668698
void visitListLiteralJudgment(
669699
ListLiteralJudgment node, DartType typeContext) {
670700
var listClass = inferrer.coreTypes.listClass;
@@ -692,32 +722,16 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
692722
typeChecksNeeded ? new List<DartType>(node.expressions.length) : null;
693723
if (inferenceNeeded || typeChecksNeeded) {
694724
for (int i = 0; i < node.expressions.length; ++i) {
695-
Expression judgment = node.expressions[i];
696-
if (judgment is SpreadElement) {
697-
DartType spreadType = inferrer.inferExpression(
698-
judgment.expression,
699-
new InterfaceType(inferrer.coreTypes.iterableClass,
700-
<DartType>[inferredTypeArgument]),
701-
inferenceNeeded || typeChecksNeeded,
702-
isVoidAllowed: true);
703-
if (inferenceNeeded) {
704-
formalTypes.add(listType.typeArguments[0]);
705-
}
706-
if (typeChecksNeeded) {
707-
spreadTypes[i] = spreadType;
708-
}
709-
// Use 'dynamic' for error recovery.
710-
actualTypes.add(
711-
getSpreadElementType(spreadType, judgment.isNullAware) ??
712-
const DynamicType());
713-
} else {
714-
inferrer.inferExpression(judgment, inferredTypeArgument,
715-
inferenceNeeded || typeChecksNeeded,
716-
isVoidAllowed: true);
717-
if (inferenceNeeded) {
718-
formalTypes.add(listType.typeArguments[0]);
719-
}
720-
actualTypes.add(getInferredType(judgment, inferrer));
725+
DartType type = inferElement(
726+
node.expressions[i],
727+
i,
728+
inferredTypeArgument,
729+
spreadTypes,
730+
inferenceNeeded,
731+
typeChecksNeeded);
732+
actualTypes.add(type);
733+
if (inferenceNeeded) {
734+
formalTypes.add(listType.typeArguments[0]);
721735
}
722736
}
723737
}
@@ -777,6 +791,8 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
777791
1)));
778792
}
779793
}
794+
} else if (item is IfElement) {
795+
// TODO(kmillikin): Insert type checks on if elements.
780796
} else {
781797
inferrer.ensureAssignable(
782798
node.typeArgument, actualTypes[i], item, item.fileOffset,
@@ -1375,32 +1391,16 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
13751391
typeChecksNeeded ? new List<DartType>(node.expressions.length) : null;
13761392
if (inferenceNeeded || typeChecksNeeded) {
13771393
for (int i = 0; i < node.expressions.length; ++i) {
1378-
Expression judgment = node.expressions[i];
1379-
if (judgment is SpreadElement) {
1380-
DartType spreadType = inferrer.inferExpression(
1381-
judgment.expression,
1382-
new InterfaceType(inferrer.coreTypes.iterableClass,
1383-
<DartType>[inferredTypeArgument]),
1384-
inferenceNeeded || typeChecksNeeded,
1385-
isVoidAllowed: true);
1386-
if (inferenceNeeded) {
1387-
formalTypes.add(setType.typeArguments[0]);
1388-
}
1389-
if (typeChecksNeeded) {
1390-
spreadTypes[i] = spreadType;
1391-
}
1392-
// Use 'dynamic' for error recovery.
1393-
actualTypes.add(
1394-
getSpreadElementType(spreadType, judgment.isNullAware) ??
1395-
const DynamicType());
1396-
} else {
1397-
inferrer.inferExpression(judgment, inferredTypeArgument,
1398-
inferenceNeeded || typeChecksNeeded,
1399-
isVoidAllowed: true);
1400-
if (inferenceNeeded) {
1401-
formalTypes.add(setType.typeArguments[0]);
1402-
}
1403-
actualTypes.add(getInferredType(judgment, inferrer));
1394+
DartType type = inferElement(
1395+
node.expressions[i],
1396+
i,
1397+
inferredTypeArgument,
1398+
spreadTypes,
1399+
inferenceNeeded,
1400+
typeChecksNeeded);
1401+
actualTypes.add(type);
1402+
if (inferenceNeeded) {
1403+
formalTypes.add(setType.typeArguments[0]);
14041404
}
14051405
}
14061406
}
@@ -1460,6 +1460,8 @@ class InferenceVisitor extends BodyVisitor1<void, DartType> {
14601460
1)));
14611461
}
14621462
}
1463+
} else if (item is IfElement) {
1464+
// TODO(kmillikin): Insert type checks on if elements.
14631465
} else {
14641466
inferrer.ensureAssignable(node.typeArgument, actualTypes[i],
14651467
node.expressions[i], node.expressions[i].fileOffset,

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

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,11 @@ class InferredTypeVisitor
2828

2929
@override
3030
DartType defaultExpression(Expression node, TypeInferrerImpl inferrer) {
31-
if (node is IfElement) {
32-
return visitIfElement(node, inferrer);
33-
}
3431
unhandled("${node.runtimeType}", "getInferredType", node.fileOffset,
3532
inferrer.uri);
3633
return const InvalidType();
3734
}
3835

39-
DartType visitIfElement(IfElement node, TypeInferrerImpl inferrer) {
40-
return const BottomType();
41-
}
42-
4336
@override
4437
DartType visitIntLiteral(IntLiteral node, TypeInferrerImpl inferrer) {
4538
return inferrer.coreTypes.intClass.rawType;

0 commit comments

Comments
 (0)