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

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: Address review comments. 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));
2495 } 2495 }
2496 } 2496 }
2497 push(expressions); 2497 push(expressions);
2498 push(labels); 2498 push(labels);
2499 enterLocalScope(); 2499 enterLocalScope();
2500 } 2500 }
2501 2501
2502 @override 2502 @override
2503 void handleSwitchCase( 2503 void handleSwitchCase(
2504 int labelCount, 2504 int labelCount,
2505 int expressionCount, 2505 int expressionCount,
2506 Token defaultKeyword, 2506 Token defaultKeyword,
2507 int statementCount, 2507 int statementCount,
2508 Token firstToken, 2508 Token firstToken,
2509 Token endToken) { 2509 Token endToken) {
2510 debugEvent("SwitchCase"); 2510 debugEvent("SwitchCase");
2511 // We always create a block here so that we later know that there's always
2512 // one synthetic block when we finish compiling the switch statement and
2513 // check this switch case to see if it falls through to the next case.
2511 Block block = popBlock(statementCount, firstToken); 2514 Block block = popBlock(statementCount, firstToken);
2512 exitLocalScope(); 2515 exitLocalScope();
2513 List<Label> labels = pop(); 2516 List<Label> labels = pop();
2514 List<Expression> expressions = pop(); 2517 List<Expression> expressions = pop();
2515 List<int> expressionOffsets = <int>[]; 2518 List<int> expressionOffsets = <int>[];
2516 for (Expression expression in expressions) { 2519 for (Expression expression in expressions) {
2517 expressionOffsets.add(expression.fileOffset); 2520 expressionOffsets.add(expression.fileOffset);
2518 } 2521 }
2519 push(new SwitchCase(expressions, expressionOffsets, block, 2522 push(new SwitchCase(expressions, expressionOffsets, block,
2520 isDefault: defaultKeyword != null) 2523 isDefault: defaultKeyword != null)
(...skipping 14 matching lines...) Expand all
2535 new List<SwitchCase>.filled(caseCount, null, growable: true); 2538 new List<SwitchCase>.filled(caseCount, null, growable: true);
2536 for (int i = caseCount - 1; i >= 0; i--) { 2539 for (int i = caseCount - 1; i >= 0; i--) {
2537 List<Label> labels = pop(); 2540 List<Label> labels = pop();
2538 SwitchCase current = cases[i] = pop(); 2541 SwitchCase current = cases[i] = pop();
2539 for (Label label in labels) { 2542 for (Label label in labels) {
2540 JumpTarget target = switchScope.lookupLabel(label.name); 2543 JumpTarget target = switchScope.lookupLabel(label.name);
2541 if (target != null) { 2544 if (target != null) {
2542 target.resolveGotos(current); 2545 target.resolveGotos(current);
2543 } 2546 }
2544 } 2547 }
2545 // TODO(ahe): Validate that there's only one default and it's last. 2548 }
2549 // Check all but the last case for the following:
2550 // 1. That it isn't a default case (which should be last).
2551 // 2. That it doesn't fall through to the next case.
2552 for (int i = 0; i < caseCount - 1; i++) {
2553 SwitchCase current = cases[i];
2554 if (current.isDefault) {
2555 addCompileTimeError(current.fileOffset,
2556 "'default' switch case should be the last case.");
2557 continue;
2558 }
2559 Block block = current.body;
2560 // [block] is a synthetic block that is added to handle variable
2561 // declarations in the switch case.
2562 TreeNode lastNode =
2563 block.statements.isEmpty ? null : block.statements.last;
2564 if (lastNode is Block) {
2565 // This is a non-synthetic block.
2566 Block block = lastNode;
2567 lastNode = block.statements.isEmpty ? null : block.statements.last;
2568 }
2569 if (lastNode is ExpressionStatement) {
2570 ExpressionStatement statement = lastNode;
2571 lastNode = statement.expression;
2572 }
2573 if (lastNode is! BreakStatement &&
2574 lastNode is! ContinueSwitchStatement &&
2575 lastNode is! Rethrow &&
2576 lastNode is! ReturnStatement &&
2577 lastNode is! Throw) {
2578 block.addStatement(
2579 new ExpressionStatement(buildFallThroughError(current.fileOffset)));
2580 }
2546 } 2581 }
2547 JumpTarget target = exitBreakTarget(); 2582 JumpTarget target = exitBreakTarget();
2548 exitSwitchScope(); 2583 exitSwitchScope();
2549 exitLocalScope(); 2584 exitLocalScope();
2550 Expression expression = popForValue(); 2585 Expression expression = popForValue();
2551 Statement result = new SwitchStatement(expression, cases); 2586 Statement result = new SwitchStatement(expression, cases);
2552 if (target.hasUsers) { 2587 if (target.hasUsers) {
2553 result = new LabeledStatement(result); 2588 result = new LabeledStatement(result);
2554 target.resolveBreaks(result); 2589 target.resolveBreaks(result);
2555 } 2590 }
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
2710 } 2745 }
2711 2746
2712 Expression wrapInCompileTimeError(Expression expression, String message) { 2747 Expression wrapInCompileTimeError(Expression expression, String message) {
2713 return new Let( 2748 return new Let(
2714 new VariableDeclaration.forValue(expression) 2749 new VariableDeclaration.forValue(expression)
2715 ..fileOffset = expression.fileOffset, 2750 ..fileOffset = expression.fileOffset,
2716 buildCompileTimeError(message, expression.fileOffset)) 2751 buildCompileTimeError(message, expression.fileOffset))
2717 ..fileOffset = expression.fileOffset; 2752 ..fileOffset = expression.fileOffset;
2718 } 2753 }
2719 2754
2755 Expression buildFallThroughError(int charOffset) {
2756 warningNotError("Switch case may fall through to next case.", charOffset);
2757 Builder constructor = library.loader.getFallThroughError();
2758 return new Throw(buildStaticInvocation(
2759 constructor.target, new Arguments.empty(),
2760 charOffset: charOffset));
2761 }
2762
2720 Expression buildAbstractClassInstantiationError(String className, 2763 Expression buildAbstractClassInstantiationError(String className,
2721 [int charOffset = -1]) { 2764 [int charOffset = -1]) {
2722 warning("The class '$className' is abstract and can't be instantiated.", 2765 warning("The class '$className' is abstract and can't be instantiated.",
2723 charOffset); 2766 charOffset);
2724 Builder constructor = library.loader.getAbstractClassInstantiationError(); 2767 Builder constructor = library.loader.getAbstractClassInstantiationError();
2725 return new Throw(buildStaticInvocation(constructor.target, 2768 return new Throw(buildStaticInvocation(constructor.target,
2726 new KernelArguments(<Expression>[new StringLiteral(className)]))); 2769 new KernelArguments(<Expression>[new StringLiteral(className)])));
2727 } 2770 }
2728 2771
2729 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) { 2772 Statement buildCompileTimeErrorStatement(error, [int charOffset = -1]) {
(...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after
3374 if (starToken == null) { 3417 if (starToken == null) {
3375 return AsyncMarker.Async; 3418 return AsyncMarker.Async;
3376 } else { 3419 } else {
3377 assert(identical(starToken.stringValue, "*")); 3420 assert(identical(starToken.stringValue, "*"));
3378 return AsyncMarker.AsyncStar; 3421 return AsyncMarker.AsyncStar;
3379 } 3422 }
3380 } else { 3423 } else {
3381 return internalError("Unknown async modifier: $asyncToken"); 3424 return internalError("Unknown async modifier: $asyncToken");
3382 } 3425 }
3383 } 3426 }
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