Index: pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart |
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart |
index 0d7c066ce0b6a7dec44d17c2310d8ab34d15cff4..88faa4d5713549ae7a928e3771f306e1dacc4cf9 100644 |
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart |
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart |
@@ -32,19 +32,9 @@ class CheckCpsIntegrity extends RecursiveVisitor { |
Map<Definition, Set<Reference>> seenReferences = |
<Definition, Set<Reference>>{}; |
- Map<Definition, Node> bindings = <Definition, Node>{}; |
+ Set<Definition> inScope = new Set<Definition>(); |
Set<Continuation> insideContinuations = new Set<Continuation>(); |
- doInScope(Iterable<Definition> defs, Node binding, action()) { |
- for (Definition def in defs) { |
- bindings[def] = binding; |
- } |
- action(); |
- for (Definition def in defs) { |
- bindings.remove(def); |
- } |
- } |
- |
void markAsSeen(Definition def) { |
if (!seenDefinitions.add(def)) { |
error('Redeclared $def', def); |
@@ -52,70 +42,92 @@ class CheckCpsIntegrity extends RecursiveVisitor { |
seenReferences[def] = new Set<Reference>(); |
} |
- @override |
- visitLetCont(LetCont node) { |
- // Analyze each continuation separately without the others in scope. |
- for (Continuation continuation in node.continuations) { |
- // We always consider a continuation to be in scope of itself. |
- // The isRecursive flag is checked explicitly to give more useful |
- // error messages. |
- doInScope([continuation], node, () => visit(continuation)); |
- } |
- // Analyze the body with all continuations in scope. |
- doInScope(node.continuations, node, () => visit(node.body)); |
+ void enterScope(Iterable<Definition> definitions) { |
+ inScope.addAll(definitions); |
+ pushAction(() => inScope.removeAll(definitions)); |
+ } |
+ |
+ void enterContinuation(Continuation cont) { |
+ insideContinuations.add(cont); |
+ pushAction(() => insideContinuations.remove(cont)); |
+ } |
+ |
+ void check(FunctionDefinition node) { |
+ topLevelNode = node; |
+ visit(node); |
+ // Check for broken reference chains. We check this last, so out-of-scope |
+ // references are not classified as a broken reference chain. |
+ seenDefinitions.forEach(checkReferenceChain); |
} |
@override |
- visitContinuation(Continuation node) { |
- markAsSeen(node); |
- if (node.isReturnContinuation) { |
- error('Non-return continuation missing body', node); |
- } |
- node.parameters.forEach(markAsSeen); |
- insideContinuations.add(node); |
- doInScope(node.parameters, node, () => visit(node.body)); |
- insideContinuations.remove(node); |
+ Expression traverseLetCont(LetCont node) { |
+ node.continuations.forEach(markAsSeen); |
+ node.continuations.forEach(push); |
+ |
+ // Put all continuations in scope when visiting the body. |
+ enterScope(node.continuations); |
+ |
+ return node.body; |
} |
@override |
- visitLetPrim(LetPrim node) { |
+ Expression traverseLetPrim(LetPrim node) { |
markAsSeen(node.primitive); |
+ |
+ // Process references in the primitive. |
visit(node.primitive); |
- doInScope([node.primitive], node, () => visit(node.body)); |
+ |
+ // Put the primitive in scope when visiting the body. |
+ enterScope([node.primitive]); |
+ |
+ return node.body; |
} |
@override |
- visitLetMutable(LetMutable node) { |
+ Expression traverseLetMutable(LetMutable node) { |
markAsSeen(node.variable); |
processReference(node.value); |
- doInScope([node.variable], node, () => visit(node.body)); |
+ |
+ // Put the primitive in scope when visiting the body. |
+ enterScope([node.variable]); |
+ |
+ return node.body; |
+ } |
+ |
+ @override |
+ Expression traverseContinuation(Continuation cont) { |
+ if (cont.isReturnContinuation) { |
+ error('Non-return continuation missing body', cont); |
+ } |
+ cont.parameters.forEach(markAsSeen); |
+ enterScope(cont.parameters); |
+ // Put every continuation in scope at its own body. The isRecursive |
+ // flag is checked explicitly using [insideContinuations]. |
+ enterScope([cont]); |
+ enterContinuation(cont); |
+ return cont.body; |
} |
@override |
visitFunctionDefinition(FunctionDefinition node) { |
if (node.thisParameter != null) { |
markAsSeen(node.thisParameter); |
+ enterScope([node.thisParameter]); |
} |
node.parameters.forEach(markAsSeen); |
+ enterScope(node.parameters); |
markAsSeen(node.returnContinuation); |
+ enterScope([node.returnContinuation]); |
if (!node.returnContinuation.isReturnContinuation) { |
error('Return continuation with a body', node); |
} |
- doInOptionalScope(node.thisParameter, node, |
- () => doInScope(node.parameters, node, |
- () => doInScope([node.returnContinuation], node, |
- () => visit(node.body)))); |
- } |
- |
- doInOptionalScope(Parameter parameter, Node node, action) { |
- return (parameter == null) |
- ? action() |
- : doInScope([parameter], node, action); |
+ visit(node.body); |
} |
@override |
processReference(Reference reference) { |
- if (!bindings.containsKey(reference.definition)) { |
+ if (!inScope.contains(reference.definition)) { |
error('Referenced out of scope: ${reference.definition}', reference); |
} |
if (!seenReferences[reference.definition].add(reference)) { |
@@ -181,13 +193,4 @@ class CheckCpsIntegrity extends RecursiveVisitor { |
'$sexpr\n'; |
} |
- void check(FunctionDefinition node) { |
- topLevelNode = node; |
- visit(node); |
- |
- // Check this last, so out-of-scope references are not classified as |
- // a broken reference chain. |
- seenDefinitions.forEach(checkReferenceChain); |
- } |
- |
} |