| Index: pkg/front_end/lib/src/fasta/kernel/body_builder.dart
|
| diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
|
| index a82e842c13d025698d266f62733658a4bb160a1c..9702fad58f8d132c322842a6ae2cc667921e9283 100644
|
| --- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
|
| +++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
|
| @@ -2481,7 +2481,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| if (labelOrExpression is Label) {
|
| labels.add(labelOrExpression);
|
| } else {
|
| - expressions.add(toValue(labelOrExpression));
|
| + expressions.add(labelOrExpression);
|
| }
|
| }
|
| }
|
| @@ -2508,6 +2508,9 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| Token firstToken,
|
| Token endToken) {
|
| debugEvent("SwitchCase");
|
| + // We always create a block here so that we later know that there's always
|
| + // one synthetic block when we finish compiling the switch statement and
|
| + // check this switch case to see if it falls through to the next case.
|
| Block block = popBlock(statementCount, firstToken);
|
| exitLocalScope();
|
| List<Label> labels = pop();
|
| @@ -2542,7 +2545,39 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| target.resolveGotos(current);
|
| }
|
| }
|
| - // TODO(ahe): Validate that there's only one default and it's last.
|
| + }
|
| + // Check all but the last case for the following:
|
| + // 1. That it isn't a default case (which should be last).
|
| + // 2. That it doesn't fall through to the next case.
|
| + for (int i = 0; i < caseCount - 1; i++) {
|
| + SwitchCase current = cases[i];
|
| + if (current.isDefault) {
|
| + addCompileTimeError(current.fileOffset,
|
| + "'default' switch case should be the last case.");
|
| + continue;
|
| + }
|
| + Block block = current.body;
|
| + // [block] is a synthetic block that is added to handle variable
|
| + // declarations in the switch case.
|
| + TreeNode lastNode =
|
| + block.statements.isEmpty ? null : block.statements.last;
|
| + if (lastNode is Block) {
|
| + // This is a non-synthetic block.
|
| + Block block = lastNode;
|
| + lastNode = block.statements.isEmpty ? null : block.statements.last;
|
| + }
|
| + if (lastNode is ExpressionStatement) {
|
| + ExpressionStatement statement = lastNode;
|
| + lastNode = statement.expression;
|
| + }
|
| + if (lastNode is! BreakStatement &&
|
| + lastNode is! ContinueSwitchStatement &&
|
| + lastNode is! Rethrow &&
|
| + lastNode is! ReturnStatement &&
|
| + lastNode is! Throw) {
|
| + block.addStatement(
|
| + new ExpressionStatement(buildFallThroughError(current.fileOffset)));
|
| + }
|
| }
|
| JumpTarget target = exitBreakTarget();
|
| exitSwitchScope();
|
| @@ -2717,6 +2752,14 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
|
| ..fileOffset = expression.fileOffset;
|
| }
|
|
|
| + Expression buildFallThroughError(int charOffset) {
|
| + warningNotError("Switch case may fall through to next case.", charOffset);
|
| + Builder constructor = library.loader.getFallThroughError();
|
| + return new Throw(buildStaticInvocation(
|
| + constructor.target, new Arguments.empty(),
|
| + charOffset: charOffset));
|
| + }
|
| +
|
| Expression buildAbstractClassInstantiationError(String className,
|
| [int charOffset = -1]) {
|
| warning("The class '$className' is abstract and can't be instantiated.",
|
|
|