Index: lib/compiler/implementation/resolver.dart |
diff --git a/lib/compiler/implementation/resolver.dart b/lib/compiler/implementation/resolver.dart |
index 13b6dd37e105e09a7127a838f7b5ce34f2e45b08..387f0e3dd5365fb1775731ce247807e380477f12 100644 |
--- a/lib/compiler/implementation/resolver.dart |
+++ b/lib/compiler/implementation/resolver.dart |
@@ -955,6 +955,7 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
bool inCheckContext; |
Scope scope; |
ClassElement currentClass; |
+ ExpressionStatement currentExpressionStatement; |
bool typeRequired = false; |
StatementScope statementScope; |
int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION; |
@@ -1163,7 +1164,10 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
visitEmptyStatement(EmptyStatement node) { } |
visitExpressionStatement(ExpressionStatement node) { |
+ ExpressionStatement oldExpressionStatement = currentExpressionStatement; |
+ currentExpressionStatement = node; |
visit(node.expression); |
+ currentExpressionStatement = oldExpressionStatement; |
} |
visitFor(For node) { |
@@ -1217,10 +1221,35 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
return (str === '&&' || str == '||' || str == '!'); |
} |
+ /** |
+ * Check the lexical scope chain for a declaration with the name "assert". |
+ * |
+ * This is used to detect whether "assert(x)" is actually an assertion or |
+ * just a call expression. |
+ * It does not check fields inherited from a superclass. |
+ */ |
+ bool isAssertInLexicalScope() { |
+ return scope.lexicalLookup(const SourceString("assert")) !== null; |
+ } |
+ |
+ /** Check if [node] is the expression of the current expression statement. */ |
+ bool isExpressionStatementExpression(Node node) { |
+ return currentExpressionStatement !== null && |
+ currentExpressionStatement.expression === node; |
+ } |
+ |
Element resolveSend(Send node) { |
Selector selector = resolveSelector(node); |
if (node.receiver === null) { |
+ // If this send is the expression of an expression statement, and is on |
+ // the form "assert(expr);", and there is no declaration with name |
+ // "assert" in the lexical scope, then this is actually an assertion. |
+ if (isExpressionStatementExpression(node) && |
+ selector.isAssertSyntax() && |
+ !isAssertInLexicalScope()) { |
+ return compiler.assertMethod; |
+ } |
return node.selector.accept(this); |
} |
@@ -1408,16 +1437,6 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
world.registerDynamicInvocation(call.name, call); |
} |
- // TODO(ngeoffray): We should do the check in |
- // visitExpressionStatement instead. |
- if (target === compiler.assertMethod && !node.isCall) { |
- // We can only use assert by calling it. |
- if (!inInstanceContext) { |
- error(node, MessageKind.MISSING_ARGUMENTS_TO_ASSERT, [node]); |
- } |
- target = null; |
- } |
- |
// TODO(ngeoffray): Warn if target is null and the send is |
// unqualified. |
useElement(node, target); |
@@ -1917,7 +1936,7 @@ class ResolverVisitor extends CommonResolverVisitor<Element> { |
} |
Scope blockScope = new BlockScope(scope); |
- doInCheckContext(() => visitIn(node.type, blockScope)); |
+ doInCheckContext(() => visitIn(node.type, blockScope)); |
visitIn(node.formals, blockScope); |
visitIn(node.block, blockScope); |
} |
@@ -2593,7 +2612,20 @@ class Scope { |
Scope(this.parent, this.element); |
abstract Element add(Element element); |
- abstract Element lookup(SourceString name); |
+ |
+ Element lookup(SourceString name) { |
+ Element result = localLookup(name); |
+ if (result != null) return result; |
+ return parent.lookup(name); |
+ } |
+ |
+ Element lexicalLookup(SourceString name) { |
+ Element result = localLookup(name); |
+ if (result != null) return result; |
+ return parent.lexicalLookup(name); |
+ } |
+ |
+ abstract Element localLookup(SourceString name); |
} |
class VariableScope extends Scope { |
@@ -2627,7 +2659,7 @@ class TypeDeclarationScope extends Scope { |
throw "Cannot add element to TypeDeclarationScope"; |
} |
- Element lookup(SourceString name) { |
+ Element localLookup(SourceString name) { |
Link<DartType> typeVariableLink = element.typeVariables; |
while (!typeVariableLink.isEmpty()) { |
TypeVariableType typeVariable = typeVariableLink.head; |
@@ -2636,8 +2668,7 @@ class TypeDeclarationScope extends Scope { |
} |
typeVariableLink = typeVariableLink.tail; |
} |
- |
- return parent.lookup(name); |
+ return null; |
} |
String toString() => |
@@ -2653,11 +2684,7 @@ class MethodScope extends Scope { |
assert(parent !== null); |
} |
- Element lookup(SourceString name) { |
- Element found = elements[name]; |
- if (found !== null) return found; |
- return parent.lookup(name); |
- } |
+ Element localLookup(SourceString name) => elements[name]; |
Element add(Element newElement) { |
if (elements.containsKey(newElement.name)) { |
@@ -2687,7 +2714,7 @@ class ClassScope extends TypeDeclarationScope { |
ClassScope(Scope parentScope, ClassElement element) |
: super(parentScope, element); |
- Element lookup(SourceString name) { |
+ Element localLookup(SourceString name) { |
ClassElement cls = element; |
Element result = cls.lookupLocalMember(name); |
if (result !== null) return result; |
@@ -2695,11 +2722,15 @@ class ClassScope extends TypeDeclarationScope { |
// If not in a static context, we can lookup in the |
// TypeDeclaration scope, which contains the type variables of |
// the class. |
- result = super.lookup(name); |
- } else { |
- result = parent.lookup(name); |
+ return super.localLookup(name); |
} |
- if (result != null) return result; |
+ return null; |
+ } |
+ |
+ Element lookup(SourceString name) { |
+ Element result = super.lookup(name); |
+ if (result !== null) return result; |
+ ClassElement cls = element; |
return cls.lookupSuperMember(name); |
} |
@@ -2714,9 +2745,10 @@ class TopScope extends Scope { |
LibraryElement get library => element; |
TopScope(LibraryElement library) : super(null, library); |
- Element lookup(SourceString name) { |
- return library.find(name); |
- } |
+ |
+ Element localLookup(SourceString name) => library.find(name); |
+ Element lookup(SourceString name) => localLookup(name); |
+ Element lexicalLookup(SourceString name) => localLookup(name); |
Element add(Element newElement) { |
throw "Cannot add an element in the top scope"; |