Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(550)

Side by Side Diff: pkg/front_end/lib/src/fasta/kernel/body_builder.dart

Issue 2926533004: Semantic checks on switch cases and fall-through errors. (Closed)
Patch Set: Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/front_end/lib/src/fasta/parser/listener.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library fasta.body_builder; 5 library fasta.body_builder;
6 6
7 import '../fasta_codes.dart' 7 import '../fasta_codes.dart'
8 show FastaMessage, codeExpectedButGot, codeExpectedFunctionBody; 8 show FastaMessage, codeExpectedButGot, codeExpectedFunctionBody;
9 9
10 import '../parser/parser.dart' show FormalParameterType, MemberKind, optional; 10 import '../parser/parser.dart' show FormalParameterType, MemberKind, optional;
(...skipping 2463 matching lines...) Expand 10 before | Expand all | Expand 10 after
2474 void beginSwitchCase(int labelCount, int expressionCount, Token firstToken) { 2474 void beginSwitchCase(int labelCount, int expressionCount, Token firstToken) {
2475 debugEvent("beginSwitchCase"); 2475 debugEvent("beginSwitchCase");
2476 List labelsAndExpressions = popList(labelCount + expressionCount); 2476 List labelsAndExpressions = popList(labelCount + expressionCount);
2477 List<Label> labels = <Label>[]; 2477 List<Label> labels = <Label>[];
2478 List<Expression> expressions = <Expression>[]; 2478 List<Expression> expressions = <Expression>[];
2479 if (labelsAndExpressions != null) { 2479 if (labelsAndExpressions != null) {
2480 for (var labelOrExpression in labelsAndExpressions) { 2480 for (var labelOrExpression in labelsAndExpressions) {
2481 if (labelOrExpression is Label) { 2481 if (labelOrExpression is Label) {
2482 labels.add(labelOrExpression); 2482 labels.add(labelOrExpression);
2483 } else { 2483 } else {
2484 expressions.add(toValue(labelOrExpression)); 2484 expressions.add(labelOrExpression);
2485 } 2485 }
2486 } 2486 }
2487 } 2487 }
2488 assert(scope == switchScope); 2488 assert(scope == switchScope);
2489 for (Label label in labels) { 2489 for (Label label in labels) {
2490 if (scope.hasLocalLabel(label.name)) { 2490 if (scope.hasLocalLabel(label.name)) {
2491 // TODO(ahe): Should validate this is a goto target and not duplicated. 2491 // TODO(ahe): Should validate this is a goto target and not duplicated.
2492 scope.claimLabel(label.name); 2492 scope.claimLabel(label.name);
2493 } else { 2493 } else {
2494 scope.declareLabel(label.name, createGotoTarget(firstToken.charOffset)); 2494 scope.declareLabel(label.name, createGotoTarget(firstToken.charOffset));
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
2535 new List<SwitchCase>.filled(caseCount, null, growable: true); 2535 new List<SwitchCase>.filled(caseCount, null, growable: true);
2536 for (int i = caseCount - 1; i >= 0; i--) { 2536 for (int i = caseCount - 1; i >= 0; i--) {
2537 List<Label> labels = pop(); 2537 List<Label> labels = pop();
2538 SwitchCase current = cases[i] = pop(); 2538 SwitchCase current = cases[i] = pop();
2539 for (Label label in labels) { 2539 for (Label label in labels) {
2540 JumpTarget target = switchScope.lookupLabel(label.name); 2540 JumpTarget target = switchScope.lookupLabel(label.name);
2541 if (target != null) { 2541 if (target != null) {
2542 target.resolveGotos(current); 2542 target.resolveGotos(current);
2543 } 2543 }
2544 } 2544 }
2545 // TODO(ahe): Validate that there's only one default and it's last. 2545 }
2546 // Check all but the last case for the following:
2547 // 1. That it isn't a default case (which should be last).
2548 // 2. That it doesn't fall through to the next case.
2549 for (int i = 0; i < caseCount - 1; i++) {
2550 SwitchCase current = cases[i];
2551 if (current.isDefault) {
2552 addCompileTimeError(current.fileOffset,
2553 "'default' switch case should be the last case.");
2554 continue;
2555 }
2556 Block block = current.body;
2557 TreeNode lastNode = block;
2558 while (lastNode is Block || lastNode is LabeledStatement) {
Paul Berry 2017/06/06 18:32:26 This isn't consistent with the spec. The spec say
ahe 2017/06/06 18:40:05 Then I should replace lines 2558-2569 with lines 2
Paul Berry 2017/06/06 18:55:37 I think we still need the LabeledStatement logic.
ahe 2017/06/06 19:02:15 That's what I thought at first. However, that does
Paul Berry 2017/06/06 19:18:08 Fair enough. I've checked and analyzer's interpre
2559 if (lastNode is Block) {
2560 Block block = lastNode;
2561 if (block.statements.isEmpty) {
2562 lastNode = null;
2563 } else {
2564 lastNode = block.statements.last;
2565 }
2566 } else if (lastNode is LabeledStatement) {
2567 LabeledStatement statement = lastNode;
2568 lastNode = statement.body;
2569 }
2570 }
2571 if (lastNode is ExpressionStatement) {
2572 ExpressionStatement statement = lastNode;
2573 lastNode = statement.expression;
2574 }
2575 if (lastNode is! BreakStatement &&
2576 lastNode is! ContinueSwitchStatement &&
2577 lastNode is! Rethrow &&
2578 lastNode is! ReturnStatement &&
2579 lastNode is! Throw) {
2580 block.addStatement(
2581 new ExpressionStatement(buildFallThroughError(current.fileOffset)));
2582 }
2546 } 2583 }
2547 JumpTarget target = exitBreakTarget(); 2584 JumpTarget target = exitBreakTarget();
2548 exitSwitchScope(); 2585 exitSwitchScope();
2549 exitLocalScope(); 2586 exitLocalScope();
2550 Expression expression = popForValue(); 2587 Expression expression = popForValue();
2551 Statement result = new SwitchStatement(expression, cases); 2588 Statement result = new SwitchStatement(expression, cases);
2552 if (target.hasUsers) { 2589 if (target.hasUsers) {
2553 result = new LabeledStatement(result); 2590 result = new LabeledStatement(result);
2554 target.resolveBreaks(result); 2591 target.resolveBreaks(result);
2555 } 2592 }
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
2710 } 2747 }
2711 2748
2712 Expression wrapInCompileTimeError(Expression expression, String message) { 2749 Expression wrapInCompileTimeError(Expression expression, String message) {
2713 return new Let( 2750 return new Let(
2714 new VariableDeclaration.forValue(expression) 2751 new VariableDeclaration.forValue(expression)
2715 ..fileOffset = expression.fileOffset, 2752 ..fileOffset = expression.fileOffset,
2716 buildCompileTimeError(message, expression.fileOffset)) 2753 buildCompileTimeError(message, expression.fileOffset))
2717 ..fileOffset = expression.fileOffset; 2754 ..fileOffset = expression.fileOffset;
2718 } 2755 }
2719 2756
2757 Expression buildFallThroughError(int charOffset) {
2758 warningNotError("Switch case may fall through to next case.", charOffset);
2759 Builder constructor = library.loader.getFallThroughError();
2760 return new Throw(buildStaticInvocation(
2761 constructor.target, new Arguments.empty(),
2762 charOffset: charOffset));
2763 }
2764
2720 Expression buildAbstractClassInstantiationError(String className, 2765 Expression buildAbstractClassInstantiationError(String className,
2721 [int charOffset = -1]) { 2766 [int charOffset = -1]) {
2722 warning("The class '$className' is abstract and can't be instantiated.", 2767 warning("The class '$className' is abstract and can't be instantiated.",
2723 charOffset); 2768 charOffset);
2724 Builder constructor = library.loader.getAbstractClassInstantiationError(); 2769 Builder constructor = library.loader.getAbstractClassInstantiationError();
2725 return new Throw(buildStaticInvocation(constructor.target, 2770 return new Throw(buildStaticInvocation(constructor.target,
2726 new KernelArguments(<Expression>[new StringLiteral(className)]))); 2771 new KernelArguments(<Expression>[new StringLiteral(className)])));
2727 } 2772 }
2728 2773
2729 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) { 2774 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) {
(...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after
3374 if (starToken == null) { 3419 if (starToken == null) {
3375 return AsyncMarker.Async; 3420 return AsyncMarker.Async;
3376 } else { 3421 } else {
3377 assert(identical(starToken.stringValue, "*")); 3422 assert(identical(starToken.stringValue, "*"));
3378 return AsyncMarker.AsyncStar; 3423 return AsyncMarker.AsyncStar;
3379 } 3424 }
3380 } else { 3425 } else {
3381 return internalError("Unknown async modifier: $asyncToken"); 3426 return internalError("Unknown async modifier: $asyncToken");
3382 } 3427 }
3383 } 3428 }
OLDNEW
« no previous file with comments | « no previous file | pkg/front_end/lib/src/fasta/parser/listener.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698