| Index: pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
|
| diff --git a/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart b/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
|
| index 4131146bf82a0f6d21ab6d99f2932731ec78073d..06052a966b77d58284faec0019c4913f1c3cab72 100644
|
| --- a/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
|
| +++ b/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
|
| @@ -142,6 +142,25 @@ class BuilderContext<T> {
|
| return name;
|
| }
|
|
|
| + /// Adds declarations for all variables that are still undeclared.
|
| + void declareRemainingVariables() {
|
| + // These variables can be referenced from other variable initializers if
|
| + // they are set by an assignment expression, so we declare variables before
|
| + // those with initializers.
|
| + List<VariableDeclaration> declarations = <VariableDeclaration>[];
|
| + for (tree.Variable variable in variableNames.keys) {
|
| + if (!declaredVariables.contains(variable)) {
|
| + String name = getVariableName(variable);
|
| + VariableDeclaration decl = new VariableDeclaration(name);
|
| + decl.element = variable.element;
|
| + declarations.add(decl);
|
| + declaredVariables.add(variable);
|
| + }
|
| + }
|
| + // Prepend all variables at once to avoid quadratic blowup.
|
| + variables.insertAll(0, declarations);
|
| + }
|
| +
|
| String getConstantName(VariableElement element) {
|
| assert(element.kind == ElementKind.VARIABLE);
|
| if (element.enclosingElement != currentElement) {
|
| @@ -301,11 +320,7 @@ class ASTEmitter
|
| // Some of the variable declarations have already been added
|
| // if their first assignment could be pulled into the initializer.
|
| // Add the remaining variable declarations now.
|
| - for (tree.Variable variable in context.variableNames.keys) {
|
| - if (!context.declaredVariables.contains(variable)) {
|
| - context.addDeclaration(variable);
|
| - }
|
| - }
|
| + context.declareRemainingVariables();
|
|
|
| // Add constant declarations.
|
| List<VariableDeclaration> constants = <VariableDeclaration>[];
|
| @@ -370,12 +385,7 @@ class ASTEmitter
|
| // Some of the variable declarations have already been added
|
| // if their first assignment could be pulled into the initializer.
|
| // Add the remaining variable declarations now.
|
| - for (tree.Variable variable in context.variableNames.keys) {
|
| - if (!context.declaredVariables.contains(variable) &&
|
| - !context.handlerVariables.contains(variable)) {
|
| - context.addDeclaration(variable);
|
| - }
|
| - }
|
| + context.declareRemainingVariables();
|
|
|
| // Add constant declarations.
|
| List<VariableDeclaration> constants = <VariableDeclaration>[];
|
| @@ -498,13 +508,28 @@ class ASTEmitter
|
| @override
|
| void visitExpressionStatement(tree.ExpressionStatement stmt,
|
| BuilderContext<Statement> context) {
|
| + if (stmt.expression is tree.Assign) {
|
| + emitAssignStatement(stmt.expression, stmt, context);
|
| + return;
|
| + }
|
| Expression e = visitExpression(stmt.expression, context);
|
| context.addStatement(new ExpressionStatement(e));
|
| -
|
| visitStatement(stmt.next, context);
|
| }
|
|
|
| @override
|
| + void visitVariableDeclaration(tree.VariableDeclaration node,
|
| + BuilderContext<Statement> context) {
|
| + Expression value = visitExpression(node.value, context);
|
| + String name = context.getVariableName(node.variable);
|
| + VariableDeclaration decl = new VariableDeclaration(name, value)
|
| + ..element = node.variable.element;
|
| + context.declaredVariables.add(node.variable);
|
| + context.addStatement(new VariableDeclarations([decl]));
|
| + visitStatement(node.next, context);
|
| + }
|
| +
|
| + @override
|
| void visitLabeledStatement(tree.LabeledStatement stmt,
|
| BuilderContext<Statement> context) {
|
| Block block = visitInSubContext(stmt.body, context, fallthrough: stmt.next);
|
| @@ -515,58 +540,45 @@ class ASTEmitter
|
|
|
| bool isNullLiteral(Expression exp) => exp is Literal && exp.value.isNull;
|
|
|
| - @override
|
| - void visitAssign(tree.Assign stmt,
|
| - BuilderContext<Statement> context) {
|
| + void emitAssignStatement(tree.Assign assign,
|
| + tree.Statement statement,
|
| + BuilderContext<Statement> context) {
|
| // Try to emit a local function declaration. This is useful for functions
|
| // that may occur in expression context, but could not be inlined anywhere.
|
| - if (stmt.variable.element is FunctionElement &&
|
| - stmt.value is tree.FunctionExpression &&
|
| - !context.declaredVariables.contains(stmt.variable) &&
|
| - stmt.variable.writeCount == 1) {
|
| - tree.FunctionExpression functionExp = stmt.value;
|
| + if (assign.variable.element is FunctionElement &&
|
| + assign.value is tree.FunctionExpression &&
|
| + !context.declaredVariables.contains(assign.variable) &&
|
| + assign.variable.writeCount == 1) {
|
| + tree.FunctionExpression functionExp = assign.value;
|
| FunctionExpression function =
|
| makeSubFunction(functionExp.definition, context);
|
| FunctionDeclaration decl = new FunctionDeclaration(function);
|
| context.addStatement(decl);
|
| - context.declaredVariables.add(stmt.variable);
|
| + context.declaredVariables.add(assign.variable);
|
|
|
| - visitStatement(stmt.next, context);
|
| + visitStatement(statement.next, context);
|
| return;
|
| }
|
|
|
| - bool isFirstOccurrence = (context.variableNames[stmt.variable] == null);
|
| - bool isDeclaredHere = stmt.variable.host == context.currentElement;
|
| - String name = context.getVariableName(stmt.variable);
|
| - Expression definition = visitExpression(stmt.value, context);
|
| + Expression definition = visitExpression(assign.value, context);
|
| + bool isFirstOccurrence = (context.variableNames[assign.variable] == null);
|
| + bool isDeclaredHere = assign.variable.host == context.currentElement;
|
| + bool isFirstStatement = context.firstStatement == statement;
|
| + String name = context.getVariableName(assign.variable);
|
|
|
| // Try to pull into initializer.
|
| - if (context.firstStatement == stmt && isFirstOccurrence && isDeclaredHere) {
|
| + if (isFirstStatement && isFirstOccurrence && isDeclaredHere) {
|
| if (isNullLiteral(definition)) definition = null;
|
| - context.addDeclaration(stmt.variable, definition);
|
| - context.firstStatement = stmt.next;
|
| - visitStatement(stmt.next, context);
|
| - return;
|
| - }
|
| -
|
| - // Emit a variable declaration if we are required to do so.
|
| - // For captured variables, this ensures that a fresh variable is created.
|
| - if (stmt.isDeclaration) {
|
| - assert(isFirstOccurrence);
|
| - assert(isDeclaredHere);
|
| - if (isNullLiteral(definition)) definition = null;
|
| - VariableDeclaration decl = new VariableDeclaration(name, definition)
|
| - ..element = stmt.variable.element;
|
| - context.declaredVariables.add(stmt.variable);
|
| - context.addStatement(new VariableDeclarations([decl]));
|
| - visitStatement(stmt.next, context);
|
| + context.addDeclaration(assign.variable, definition);
|
| + context.firstStatement = statement.next;
|
| + visitStatement(statement.next, context);
|
| return;
|
| }
|
|
|
| context.addStatement(new ExpressionStatement(makeAssignment(
|
| - context.makeVariableAccess(stmt.variable),
|
| + context.makeVariableAccess(assign.variable),
|
| definition)));
|
| - visitStatement(stmt.next, context);
|
| + visitStatement(statement.next, context);
|
| }
|
|
|
| @override
|
| @@ -653,6 +665,7 @@ class ASTEmitter
|
| VariableDeclaration exceptionParameter =
|
| new VariableDeclaration(context.getVariableName(exceptionVariable));
|
| exceptionParameter.element = exceptionVariable.element;
|
| + stmt.catchParameters.forEach(context.declaredVariables.add);
|
| if (stmt.catchParameters.length == 2) {
|
| tree.Variable stackTraceVariable = stmt.catchParameters[1];
|
| context.handlerVariables.add(stackTraceVariable);
|
| @@ -878,6 +891,14 @@ class ASTEmitter
|
| return context.makeVariableAccess(exp.variable);
|
| }
|
|
|
| + @override
|
| + Expression visitAssign(tree.Assign node, BuilderContext<Statement> context) {
|
| + // This is called only when an assignment occurs in expression context.
|
| + return makeAssignment(
|
| + context.makeVariableAccess(node.variable),
|
| + visitExpression(node.value, context));
|
| + }
|
| +
|
| FunctionExpression makeSubFunction(tree.FunctionDefinition function,
|
| BuilderContext<Statement> context) {
|
| return visitFunctionDefinition(function,
|
| @@ -904,13 +925,15 @@ class ASTEmitter
|
| }
|
|
|
| List<Statement> buildInInitializerContext(tree.Statement root,
|
| - BuilderContext context) {
|
| + BuilderContext context) {
|
| BuilderContext inner = new BuilderContext<Statement>.initializer(context);
|
| inner.currentElement = context.currentElement;
|
| + inner.firstStatement = root;
|
| visitStatement(root, inner);
|
| List<Statement> bodyParts;
|
| for (tree.Variable variable in inner.variableNames.keys) {
|
| - if (!context.declaredVariables.contains(variable)) {
|
| + if (!context.declaredVariables.contains(variable) &&
|
| + !inner.declaredVariables.contains(variable)) {
|
| inner.addDeclaration(variable);
|
| }
|
| }
|
| @@ -1290,7 +1313,10 @@ class UnshadowParameters extends tree.RecursiveVisitor {
|
| param.element);
|
| definition.parameters[i] = newParam;
|
| definition.replaceEachBody((tree.Statement body) {
|
| - return new tree.Assign(param, new tree.VariableUse(newParam), body);
|
| + return tree.Assign.makeStatement(
|
| + param,
|
| + new tree.VariableUse(newParam),
|
| + body);
|
| });
|
| newParam.writeCount = 1; // Being a parameter counts as a write.
|
| param.writeCount--; // Not a parameter anymore.
|
|
|