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

Unified Diff: gen.dart

Issue 8343037: Throw FallThroughError when we fall through a case in a switch statement. Fixes (Closed) Base URL: http://dart.googlecode.com/svn/experimental/frog/
Patch Set: '' Created 9 years, 2 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « frogsh ('k') | lib/corelib.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: gen.dart
===================================================================
--- gen.dart (revision 917)
+++ gen.dart (working copy)
@@ -163,7 +163,7 @@
Member standardConstructor = type.constructors[''];
if (standardConstructor == null ||
standardConstructor.generator == null) {
- if (!type.isNativeType) {
+ if (!type.isNativeType) {
writer.writeln('function ${type.jsname}() {}');
}
} else {
@@ -865,7 +865,7 @@
}
/** Visits [body] without creating a new block for a [BlockStatement]. */
- void visitStatementsInBlock(Statement body) {
+ bool visitStatementsInBlock(Statement body) {
if (body is BlockStatement) {
for (var stmt in body.body) {
stmt.visit(this);
@@ -873,6 +873,7 @@
} else {
if (body != null) body.visit(this);
}
+ return false;
}
_pushBlock([bool reentrant = false]) {
@@ -922,12 +923,13 @@
// ******************* Statements *******************
- void visitDietStatement(DietStatement node) {
+ bool visitDietStatement(DietStatement node) {
var parser = new Parser(node.span.file, /*diet:*/false, node.span.start);
visitStatementsInBlock(parser.block());
+ return false;
}
- void visitVariableDefinition(VariableDefinition node) {
+ bool visitVariableDefinition(VariableDefinition node) {
var isFinal = false;
// TODO(jimhug): Clean this up and share modifier parsing somewhere.
if (node.modifiers != null && node.modifiers[0].kind == TokenKind.FINAL) {
@@ -960,9 +962,11 @@
}
}
writer.writeln(';');
+ return false;
+
}
- void visitFunctionDefinition(FunctionDefinition node) {
+ bool visitFunctionDefinition(FunctionDefinition node) {
var name = world.toJsIdentifier(node.name.name);
var meth = _makeLambdaMethod(name, node);
@@ -970,9 +974,14 @@
// TODO(jimhug): Pass js name into writeDefinition?
var funcValue = _scope.create(name, meth.functionType, method.definition);
meth.generator.writeDefinition(writer, null);
+ return false;
}
- void visitReturnStatement(ReturnStatement node) {
+ /**
+ * Returns true indicating that normal control-flow is interrupted by
+ * this statement. (This could be a return, break, throw, or continue.)
+ */
+ bool visitReturnStatement(ReturnStatement node) {
if (node.value == null) {
writer.writeln('return;');
} else {
@@ -981,9 +990,10 @@
}
writer.writeln('return ${visitValue(node.value).code};');
}
+ return true;
}
- void visitThrowStatement(ThrowStatement node) {
+ bool visitThrowStatement(ThrowStatement node) {
// Dart allows throwing anything, just like JS
if (node.value != null) {
var value = visitValue(node.value);
@@ -999,9 +1009,10 @@
writer.writeln('throw ${rethrow.code};');
}
}
+ return true;
}
- void visitAssertStatement(AssertStatement node) {
+ bool visitAssertStatement(AssertStatement node) {
// be sure to walk test for static checking even is asserts disabled
var test = visitValue(node.test); // TODO(jimhug): check bool or callable.
if (options.enableAsserts) {
@@ -1016,53 +1027,61 @@
writer.writeln('\$assert(${test.code}, "${_escapeString(span.text)}",' +
' "${span.file.filename}", ${line + 1}, ${column + 1});');
}
+ return false;
}
- void visitBreakStatement(BreakStatement node) {
+ bool visitBreakStatement(BreakStatement node) {
// TODO(jimhug): Lots of flow error checking here and below.
if (node.label == null) {
writer.writeln('break;');
} else {
writer.writeln('break ${node.label.name};');
}
+ return true;
}
- void visitContinueStatement(ContinueStatement node) {
+ bool visitContinueStatement(ContinueStatement node) {
if (node.label == null) {
writer.writeln('continue;');
} else {
writer.writeln('continue ${node.label.name};');
}
+ return true;
}
- void visitIfStatement(IfStatement node) {
+ bool visitIfStatement(IfStatement node) {
var test = visitBool(node.test);
writer.write('if (${test.code}) ');
- node.trueBranch.visit(this);
+ var exit1 = node.trueBranch.visit(this);
if (node.falseBranch != null) {
writer.write('else ');
- node.falseBranch.visit(this);
+ if (node.falseBranch.visit(this) && exit1) {
+ return true;
+ }
}
+ return false;
}
- void visitWhileStatement(WhileStatement node) {
+ bool visitWhileStatement(WhileStatement node) {
var test = visitBool(node.test);
writer.write('while (${test.code}) ');
_pushBlock(/*reentrant:*/true);
node.body.visit(this);
_popBlock();
+ return false;
}
- void visitDoStatement(DoStatement node) {
+ bool visitDoStatement(DoStatement node) {
writer.write('do ');
_pushBlock(/*reentrant:*/true);
node.body.visit(this);
_popBlock();
var test = visitBool(node.test);
writer.writeln('while (${test.code})');
+ return false;
}
- void visitForStatement(ForStatement node) {
+ bool visitForStatement(ForStatement node) {
_pushBlock();
writer.write('for (');
if (node.init != null) node.init.visit(this);
@@ -1086,9 +1105,10 @@
node.body.visit(this);
_popBlock();
_popBlock();
+ return false;
}
- void visitForInStatement(ForInStatement node) {
+ bool visitForInStatement(ForInStatement node) {
// TODO(jimhug): visitValue and other cleanups here.
var itemType = method.resolveType(node.item.type);
var itemName = node.item.name.name;
@@ -1132,9 +1152,10 @@
visitStatementsInBlock(node.body);
writer.exitBlock('}');
_popBlock();
+ return false;
}
- void visitTryStatement(TryStatement node) {
+ bool visitTryStatement(TryStatement node) {
writer.enterBlock('try {');
_pushBlock();
visitStatementsInBlock(node.body);
@@ -1229,9 +1250,14 @@
// Close the try-catch-finally
writer.exitBlock('}');
+ // TODO(efortuna): This could be more precise by combining all the different
+ // paths here. -i.e. if there is a finally block with a return at the end
+ // then this can return true, similarly if all blocks have a return at the
+ // end then the same holds.
+ return false;
}
- void visitSwitchStatement(SwitchStatement node) {
+ bool visitSwitchStatement(SwitchStatement node) {
// TODO(jimhug): Lots of negative tests to check for.
var test = visitValue(node.test);
writer.enterBlock('switch (${test.code}) {');
@@ -1254,34 +1280,56 @@
}
}
writer.enterBlock('');
- for (var stmt in case_.statements) {
- stmt.visit(this);
- }
- if (case_ != node.cases[node.cases.length - 1]) {
+ bool caseExits = _visitAllStatements(case_.statements, false);
+
+ if (case_ != node.cases[node.cases.length - 1] && !caseExits) {
var span = case_.statements[case_.statements.length - 1].span;
+ //TODO(efortuna): This error message isn't 100% correct because
+ // constructors are not being built correctly. Check back for correct
+ // output when constructors are fixed.
+ writer.writeln('\$throw(new FallThroughError("${span.file.filename}",' +
+ ' ${span.file.getLine(span.start)}))');
}
writer.exitBlock('');
_popBlock();
}
writer.exitBlock('}');
+ // TODO(efortuna): When we are passing more information back about
+ // control flow by returning something other than bool, return true for the
+ // cases where every branch of the switch statement ends with a return
+ // statement.
+ return false;
}
+
+ bool _visitAllStatements(statementList, exits) {
+ for (int i = 0; i < statementList.length; i++) {
+ var stmt = statementList[i];
+ exits = stmt.visit(this);
+ //TODO(efortuna): fix this so you only get one error if you have "return;
+ //a; b; c;"
+ if (stmt != statementList[statementList.length - 1] && exits) {
+ world.warning('unreachable code', statementList[i + 1].span);
+ }
+ }
+ return exits;
+ }
- void visitBlockStatement(BlockStatement node) {
+ bool visitBlockStatement(BlockStatement node) {
_pushBlock();
writer.enterBlock('{');
- for (var stmt in node.body) {
- stmt.visit(this);
- }
+ var exits = _visitAllStatements(node.body, false);
writer.exitBlock('}');
_popBlock();
+ return exits;
}
- void visitLabeledStatement(LabeledStatement node) {
+ bool visitLabeledStatement(LabeledStatement node) {
writer.writeln('${node.name.name}:');
node.body.visit(this);
+ return false;
}
- void visitExpressionStatement(ExpressionStatement node) {
+ bool visitExpressionStatement(ExpressionStatement node) {
if (node.body is VarExpression || node.body is ThisExpression) {
// TODO(jmesserly): this is a "warning" but not a "type warning",
// Is that okay? We have a similar issue around unreachable code warnings.
@@ -1289,10 +1337,12 @@
}
var value = visitVoid(node.body);
writer.writeln('${value.code};');
+ return false;
}
- void visitEmptyStatement(EmptyStatement node) {
+ bool visitEmptyStatement(EmptyStatement node) {
writer.writeln(';');
+ return false;
}
_checkNonStatic(Node node) {
@@ -1783,7 +1833,7 @@
return m.invoke(parent, node, null, _makeArgs(node.arguments));
}
- void visitListExpression(ListExpression node) {
+ visitListExpression(ListExpression node) {
// TODO(jimhug): Use node.type or other type inference here.
var argsCode = [];
var argValues = [];
@@ -1811,7 +1861,7 @@
return new Value(world.listType, code);
}
- void visitMapExpression(MapExpression node) {
+ visitMapExpression(MapExpression node) {
// Ensure that Map factory is intialized - pseudo-call needed members.
var mapImplType = parent.useMapFactory();
« no previous file with comments | « frogsh ('k') | lib/corelib.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698