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

Unified Diff: pkg/compiler/lib/src/resolution/members.dart

Issue 1157333003: Compute more SendStructures on ResolverVisitor. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Check for explicit this property access. Created 5 years, 7 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
Index: pkg/compiler/lib/src/resolution/members.dart
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 0ea0739f795f3a1c7bba31d4e7f171113fe11239..1bd64f232b073b3fa36cadc1d227bba1cb1d5521 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -187,6 +187,44 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return new ErroneousElementX(kind, arguments, name, enclosingElement);
}
+ /// Report a warning or error on an unresolved access in non-instance context.
+ ///
+ /// The [ErroneousElement] corresponding to the message is returned.
+ ErroneousElement reportCannotResolve(Node node, String name) {
+ assert(invariant(node, !inInstanceContext,
+ message: "ResolverVisitor.reportCannotResolve must not be called in "
+ "instance context."));
+
+ // We report an error within initializers because `this` is implicitly
+ // accessed when unqualified identifiers are not resolved. For
+ // details, see section 16.14.3 of the spec (2nd edition):
+ // An unqualified invocation `i` of the form `id(a1, ...)`
+ // ...
+ // If `i` does not occur inside a top level or static function, `i`
+ // is equivalent to `this.id(a1 , ...)`.
+ bool inInitializer =
+ enclosingElement.isGenerativeConstructor ||
+ (enclosingElement.isInstanceMember && enclosingElement.isField);
+ MessageKind kind;
+ Map arguments = {'name': name};
+ if (inInitializer) {
+ kind = MessageKind.CANNOT_RESOLVE_IN_INITIALIZER;
+ } else if (name == 'await') {
+ var functionName = enclosingElement.name;
+ if (functionName == '') {
+ kind = MessageKind.CANNOT_RESOLVE_AWAIT_IN_CLOSURE;
+ } else {
+ kind = MessageKind.CANNOT_RESOLVE_AWAIT;
+ arguments['functionName'] = functionName;
+ }
+ } else {
+ kind = MessageKind.CANNOT_RESOLVE;
+ }
+ registry.registerThrowNoSuchMethod();
+ return reportAndCreateErroneousElement(
+ node, name, kind, arguments, isError: inInitializer);
+ }
+
ResolutionResult visitIdentifier(Identifier node) {
if (node.isThis()) {
if (!inInstanceContext) {
@@ -211,36 +249,10 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// Set the type to be `dynamic` to mark that this is a type literal.
registry.setType(node, const DynamicType());
}
- element = reportLookupErrorIfAny(element, node, node.source);
+ element = reportLookupErrorIfAny(element, node, name);
if (element == null) {
if (!inInstanceContext) {
- // We report an error within initializers because `this` is implicitly
- // accessed when unqualified identifiers are not resolved. For
- // details, see section 16.14.3 of the spec (2nd edition):
- // An unqualified invocation `i` of the form `id(a1, ...)`
- // ...
- // If `i` does not occur inside a top level or static function, `i`
- // is equivalent to `this.id(a1 , ...)`.
- bool inInitializer = enclosingElement.isGenerativeConstructor ||
- (enclosingElement.isInstanceMember && enclosingElement.isField);
- MessageKind kind;
- Map arguments = {'name': name};
- if (inInitializer) {
- kind = MessageKind.CANNOT_RESOLVE_IN_INITIALIZER;
- } else if (name == 'await') {
- var functionName = enclosingElement.name;
- if (functionName == '') {
- kind = MessageKind.CANNOT_RESOLVE_AWAIT_IN_CLOSURE;
- } else {
- kind = MessageKind.CANNOT_RESOLVE_AWAIT;
- arguments['functionName'] = functionName;
- }
- } else {
- kind = MessageKind.CANNOT_RESOLVE;
- }
- element = reportAndCreateErroneousElement(node, name, kind,
- arguments, isError: inInitializer);
- registry.registerThrowNoSuchMethod();
+ element = reportCannotResolve(node, name);
}
} else if (element.isErroneous) {
// Use the erroneous element.
@@ -485,21 +497,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// If this send is of the form "assert(expr);", then
// this is an assertion.
if (selector.isAssert) {
- SendStructure sendStructure = const AssertStructure();
- if (selector.argumentCount != 1) {
- error(node.selector,
- MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT,
- {'argumentCount': selector.argumentCount});
- sendStructure = const InvalidAssertStructure();
- } else if (selector.namedArgumentCount != 0) {
- error(node.selector,
- MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS,
- {'argumentCount': selector.namedArgumentCount});
- sendStructure = const InvalidAssertStructure();
- }
- registry.registerAssert(node);
- registry.registerSendStructure(node, sendStructure);
- return const AssertResult();
+ internalError(node, "Unexpected assert: $node");
}
return node.selector.accept(this);
@@ -709,17 +707,20 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return selector;
}
- void resolveArguments(NodeList list) {
- if (list == null) return;
+ CallStructure resolveArguments(NodeList list) {
+ if (list == null) return null;
bool oldSendIsMemberAccess = sendIsMemberAccess;
sendIsMemberAccess = false;
Map<String, Node> seenNamedArguments = new Map<String, Node>();
+ int argumentCount = 0;
+ List<String> namedArguments = <String>[];
for (Link<Node> link = list.nodes; !link.isEmpty; link = link.tail) {
Expression argument = link.head;
visit(argument);
NamedArgument namedArgument = argument.asNamedArgument();
if (namedArgument != null) {
String source = namedArgument.name.source;
+ namedArguments.add(source);
if (seenNamedArguments.containsKey(source)) {
reportDuplicateDefinition(
source,
@@ -731,8 +732,10 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
} else if (!seenNamedArguments.isEmpty) {
error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED);
}
+ argumentCount++;
}
sendIsMemberAccess = oldSendIsMemberAccess;
+ return new CallStructure(argumentCount, namedArguments);
}
void registerTypeLiteralAccess(Send node, Element target) {
@@ -770,9 +773,14 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
/// Check that access to `super` is currently allowed.
- bool checkSuperAccess(Node node) {
+ bool checkSuperAccess(Send node) {
if (!inInstanceContext) {
- compiler.reportError(node, MessageKind.NO_SUPER_AVAILABLE);
+ compiler.reportError(node, MessageKind.NO_SUPER_IN_STATIC);
+ return false;
+ }
+ if (node.isConditional) {
+ // `super?.foo` is not allowed.
+ compiler.reportError(node, MessageKind.INVALID_USE_OF_SUPER);
return false;
}
if (currentClass.supertype == null) {
@@ -786,6 +794,20 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return true;
}
+ /// Check that access to `this` is currently allowed.
+ bool checkThisAccess(Send node) {
+ if (!inInstanceContext) {
+ compiler.reportError(node, MessageKind.NO_THIS_AVAILABLE);
+ return false;
+ }
+ if (node.isConditional) {
+ // `this?.foo` is not allowed.
+ compiler.reportError(node, MessageKind.INVALID_USE_OF_THIS);
+ return false;
+ }
+ return true;
+ }
+
/// Compute the [AccessSemantics] corresponding to a super access of [target].
AccessSemantics computeSuperAccess(Spannable node, Element target) {
if (target.isErroneous) {
@@ -803,6 +825,22 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
}
}
+ /// Compute the [AccessSemantics] for accessing the name of [selector] on the
+ /// super class.
+ ///
+ /// If no matching super member is found and error is reported and
+ /// `noSuchMethod` on `super` is registered. Furthermore, if [alternateName]
+ /// is provided, the [AccessSemantics] corresponding to the alternate name is
+ /// returned. For instance, the access of a super setter for an unresolved
+ /// getter:
+ ///
+ /// class Super {
+ /// set name(_) {}
+ /// }
+ /// class Sub extends Super {
+ /// foo => super.name; // Access to the setter.
+ /// }
+ ///
AccessSemantics computeSuperSemantics(Spannable node,
Selector selector,
{Name alternateName}) {
@@ -830,6 +868,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return computeSuperAccess(node, target);
}
+ /// Resolve [node] as subexpression that is _not_ the prefix of a member
+ /// access. For instance `a` in `a + b`, as opposed to `a` in `a.b`.
ResolutionResult visitExpression(Node node) {
bool oldSendIsMemberAccess = sendIsMemberAccess;
sendIsMemberAccess = false;
@@ -838,6 +878,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return result;
}
+ /// Handle a type test expression, like `a is T` and `a is! T`.
ResolutionResult handleIs(Send node) {
Node expression = node.receiver;
visitExpression(expression);
@@ -864,6 +905,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return null;
}
+ /// Handle a type cast expression, like `a as T`.
ResolutionResult handleAs(Send node) {
Node expression = node.receiver;
visitExpression(expression);
@@ -875,6 +917,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return null;
}
+ /// Handle the unary expression of an unresolved unary operator [text], like
+ /// the no longer supported `+a`.
ResolutionResult handleUnresolvedUnary(Send node, String text) {
Node expression = node.receiver;
if (node.isSuperCall) {
@@ -887,6 +931,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return null;
}
+ /// Handle the unary expression of a user definable unary [operator], like
+ /// `-a`, and `-super`.
ResolutionResult handleUserDefinableUnary(Send node, UnaryOperator operator) {
Node expression = node.receiver;
Selector selector = operator.selector;
@@ -921,6 +967,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return null;
}
+ /// Handle a not expression, like `!a`.
ResolutionResult handleNot(Send node, UnaryOperator operator) {
assert(invariant(node, operator.kind == UnaryOperatorKind.NOT));
@@ -931,6 +978,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return null;
}
+ /// Handle a logical and expression, like `a && b`.
ResolutionResult handleLogicalAnd(Send node) {
Node left = node.receiver;
Node right = node.arguments.head;
@@ -940,6 +988,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return null;
}
+ /// Handle a logical or expression, like `a || b`.
ResolutionResult handleLogicalOr(Send node) {
Node left = node.receiver;
Node right = node.arguments.head;
@@ -949,6 +998,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return null;
}
+ /// Handle an if-null expression, like `a ?? b`.
ResolutionResult handleIfNull(Send node) {
Node left = node.receiver;
Node right = node.arguments.head;
@@ -958,6 +1008,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return null;
}
+ /// Handle the binary expression of an unresolved binary operator [text], like
+ /// the no longer supported `a === b`.
ResolutionResult handleUnresolvedBinary(Send node, String text) {
Node left = node.receiver;
Node right = node.arguments.head;
@@ -971,6 +1023,8 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return null;
}
+ /// Handle the binary expression of a user definable binary [operator], like
+ /// `a + b`, `super + b`, `a == b` and `a != b`.
ResolutionResult handleUserDefinableBinary(Send node,
BinaryOperator operator) {
Node left = node.receiver;
@@ -997,7 +1051,6 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
// TODO(johnniwinther): Remove this when all information goes through
// the [SendStructure].
registry.useElement(node, semantics.element);
-
}
} else {
visitExpression(left);
@@ -1048,65 +1101,333 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
return null;
}
- ResolutionResult visitSend(Send node) {
- if (node.isOperator) {
- String operatorText = node.selector.asOperator().source;
- if (operatorText == 'is') {
- return handleIs(node);
- } else if (operatorText == 'as') {
- return handleAs(node);
- } else if (node.arguments.isEmpty) {
- UnaryOperator operator = UnaryOperator.parse(operatorText);
- if (operator == null) {
- return handleUnresolvedUnary(node, operatorText);
- } else {
- switch (operator.kind) {
- case UnaryOperatorKind.NOT:
- return handleNot(node, operator);
- case UnaryOperatorKind.COMPLEMENT:
- case UnaryOperatorKind.NEGATE:
- assert(invariant(node, operator.isUserDefinable,
- message: "Unexpected unary operator '${operator}'."));
- return handleUserDefinableUnary(node, operator);
- }
- return handleUserDefinableUnary(node, operator);
+ /// Handle an invocation of an expression, like `(){}()` or `(foo)()`.
+ ResolutionResult handleExpressionInvoke(Send node) {
+ assert(invariant(node, node.isCall,
+ message: "Unexpected expression: $node"));
+ Node expression = node.selector;
+ visitExpression(expression);
+ CallStructure callStructure = resolveArguments(node.argumentsNode);
+ Selector selector = callStructure.callSelector;
+ // TODO(johnniwinther): Remove this when all information goes through the
+ // [SendStructure].
+ registry.setSelector(node, selector);
+ registry.registerDynamicInvocation(selector);
+ registry.registerSendStructure(node,
+ new InvokeStructure(new AccessSemantics.expression(), selector));
+ return null;
+ }
+
+ /// Handle a, possibly invalid, assertion, like `assert(cond)` or `assert()`.
+ ResolutionResult handleAssert(Send node) {
+ assert(invariant(node, node.isCall,
+ message: "Unexpected assert: $node"));
+ // If this send is of the form "assert(expr);", then
+ // this is an assertion.
+
+ CallStructure callStructure = resolveArguments(node.argumentsNode);
+ SendStructure sendStructure = const AssertStructure();
+ if (callStructure.argumentCount != 1) {
+ compiler.reportError(
+ node.selector,
+ MessageKind.WRONG_NUMBER_OF_ARGUMENTS_FOR_ASSERT,
+ {'argumentCount': callStructure.argumentCount});
+ sendStructure = const InvalidAssertStructure();
+ } else if (callStructure.namedArgumentCount != 0) {
+ compiler.reportError(
+ node.selector,
+ MessageKind.ASSERT_IS_GIVEN_NAMED_ARGUMENTS,
+ {'argumentCount': callStructure.namedArgumentCount});
+ sendStructure = const InvalidAssertStructure();
+ }
+ registry.registerAssert(node);
+ registry.registerSendStructure(node, sendStructure);
+ return const AssertResult();
+ }
+
+ /// Handle access of a property of [name] on `this`, like `this.name` and
+ /// `this.name()`, or `name` and `name()` in instance context.
+ ResolutionResult handleThisPropertyAccess(Send node, Name name) {
+ AccessSemantics accessSemantics = new AccessSemantics.thisProperty();
+ SendStructure sendStructure;
+ Selector selector;
+ if (node.isCall) {
+ CallStructure callStructure = resolveArguments(node.argumentsNode);
+ selector = new Selector(SelectorKind.CALL, name, callStructure);
+ registry.registerDynamicInvocation(selector);
+ sendStructure = new InvokeStructure(accessSemantics, selector);
+ } else {
+ assert(invariant(node, node.isPropertyAccess));
+ selector = new Selector(
+ SelectorKind.GETTER, name, CallStructure.NO_ARGS);
+ registry.registerDynamicGetter(selector);
+ sendStructure = new GetStructure(accessSemantics, selector);
+ }
+ registry.registerSendStructure(node, sendStructure);
+ // TODO(johnniwinther): Remove this when all information goes through
+ // the [SendStructure].
+ registry.setSelector(node, selector);
+ return null;
+ }
+
+ /// Handle access on `this`, like `this()` and `this` when it is parsed as a
+ /// [Send] node.
+ ResolutionResult handleThisAccess(Send node) {
+ AccessSemantics accessSemantics = new AccessSemantics.thisAccess();
+ if (node.isCall) {
+ CallStructure callStructure = resolveArguments(node.argumentsNode);
+ Selector selector = callStructure.callSelector;
+ // TODO(johnniwinther): Handle invalid this access as an
+ // [AccessSemantics].
+ if (checkThisAccess(node)) {
+ registry.registerDynamicInvocation(selector);
+ registry.registerSendStructure(node,
+ new InvokeStructure(accessSemantics, selector));
+ }
+ // TODO(johnniwinther): Remove this when all information goes through
+ // the [SendStructure].
+ registry.setSelector(node, selector);
+ } else {
+ // TODO(johnniwinther): Handle get of `this` when it is a [Send] node.
+ internalError(node, "Unexpected node '$node'.");
+ }
+ return null;
+ }
+
+ /// Handle access of a super property, like `super.foo` and `super.foo()`.
+ ResolutionResult handleSuperPropertyAccess(Send node, Name name) {
+ Element target;
+ Selector selector;
+ CallStructure callStructure = CallStructure.NO_ARGS;
+ if (node.isCall) {
+ callStructure = resolveArguments(node.argumentsNode);
+ selector = new Selector(SelectorKind.CALL, name, callStructure);
+ } else {
+ selector = new Selector(SelectorKind.GETTER, name, callStructure);
+ }
+ if (checkSuperAccess(node)) {
+ AccessSemantics semantics = computeSuperSemantics(
+ node, selector, alternateName: name.setter);
+ if (node.isCall) {
+ bool isIncompatibleInvoke = false;
+ switch (semantics.kind) {
+ case AccessKind.SUPER_METHOD:
+ MethodElementX superMethod = semantics.element;
+ superMethod.computeSignature(compiler);
+ if (!callStructure.signatureApplies(superMethod)) {
+ registry.registerThrowNoSuchMethod();
+ registry.registerDynamicInvocation(selector);
+ registry.registerSuperNoSuchMethod();
+ isIncompatibleInvoke = true;
+ } else {
+ registry.registerStaticInvocation(semantics.element);
+ }
+ break;
+ case AccessKind.SUPER_FIELD:
+ case AccessKind.SUPER_GETTER:
+ registry.registerStaticUse(semantics.element);
+ selector = callStructure.callSelector;
+ registry.registerDynamicInvocation(selector);
+ break;
+ case AccessKind.SUPER_SETTER:
+ case AccessKind.UNRESOLVED_SUPER:
+ // NoSuchMethod registered in [computeSuperSemantics].
+ break;
+ default:
+ internalError(node, "Unexpected super property access $semantics.");
+ break;
}
+ registry.registerSendStructure(node,
+ isIncompatibleInvoke
+ ? new IncompatibleInvokeStructure(semantics, selector)
+ : new InvokeStructure(semantics, selector));
} else {
- BinaryOperator operator = BinaryOperator.parse(operatorText);
- if (operator == null) {
- return handleUnresolvedBinary(node, operatorText);
- } else {
- switch (operator.kind) {
- case BinaryOperatorKind.LOGICAL_AND:
- return handleLogicalAnd(node);
- case BinaryOperatorKind.LOGICAL_OR:
- return handleLogicalOr(node);
- case BinaryOperatorKind.IF_NULL:
- return handleIfNull(node);
- case BinaryOperatorKind.EQ:
- case BinaryOperatorKind.NOT_EQ:
- case BinaryOperatorKind.INDEX:
- case BinaryOperatorKind.ADD:
- case BinaryOperatorKind.SUB:
- case BinaryOperatorKind.MUL:
- case BinaryOperatorKind.DIV:
- case BinaryOperatorKind.IDIV:
- case BinaryOperatorKind.MOD:
- case BinaryOperatorKind.SHL:
- case BinaryOperatorKind.SHR:
- case BinaryOperatorKind.GTEQ:
- case BinaryOperatorKind.GT:
- case BinaryOperatorKind.LTEQ:
- case BinaryOperatorKind.LT:
- case BinaryOperatorKind.AND:
- case BinaryOperatorKind.OR:
- case BinaryOperatorKind.XOR:
- return handleUserDefinableBinary(node, operator);
- }
+ switch (semantics.kind) {
+ case AccessKind.SUPER_METHOD:
+ // TODO(johnniwinther): Method this should be registered as a
+ // closurization.
+ registry.registerStaticUse(semantics.element);
+ break;
+ case AccessKind.SUPER_FIELD:
+ case AccessKind.SUPER_GETTER:
+ registry.registerStaticUse(semantics.element);
+ break;
+ case AccessKind.SUPER_SETTER:
+ case AccessKind.UNRESOLVED_SUPER:
+ // NoSuchMethod registered in [computeSuperSemantics].
+ break;
+ default:
+ internalError(node, "Unexpected super property access $semantics.");
+ break;
}
+ registry.registerSendStructure(node,
+ new GetStructure(semantics, selector));
}
+ target = semantics.element;
}
+ // TODO(johnniwinther): Remove these when all information goes through
+ // the [SendStructure].
+ registry.useElement(node, target);
+ registry.setSelector(node, selector);
+ return null;
+ }
+
+ /// Handle a [Send] whose selector is an [Operator], like `a && b`, `a is T`,
+ /// `a + b`, and `~a`.
+ ResolutionResult handleOperatorSend(Send node) {
+ String operatorText = node.selector.asOperator().source;
+ if (operatorText == 'is') {
+ return handleIs(node);
+ } else if (operatorText == 'as') {
+ return handleAs(node);
+ } else if (node.arguments.isEmpty) {
+ UnaryOperator operator = UnaryOperator.parse(operatorText);
+ if (operator == null) {
+ return handleUnresolvedUnary(node, operatorText);
+ } else {
+ switch (operator.kind) {
+ case UnaryOperatorKind.NOT:
+ return handleNot(node, operator);
+ case UnaryOperatorKind.COMPLEMENT:
+ case UnaryOperatorKind.NEGATE:
+ assert(invariant(node, operator.isUserDefinable,
+ message: "Unexpected unary operator '${operator}'."));
+ return handleUserDefinableUnary(node, operator);
+ }
+ return handleUserDefinableUnary(node, operator);
+ }
+ } else {
+ BinaryOperator operator = BinaryOperator.parse(operatorText);
+ if (operator == null) {
+ return handleUnresolvedBinary(node, operatorText);
+ } else {
+ switch (operator.kind) {
+ case BinaryOperatorKind.LOGICAL_AND:
+ return handleLogicalAnd(node);
+ case BinaryOperatorKind.LOGICAL_OR:
+ return handleLogicalOr(node);
+ case BinaryOperatorKind.IF_NULL:
+ return handleIfNull(node);
+ case BinaryOperatorKind.EQ:
+ case BinaryOperatorKind.NOT_EQ:
+ case BinaryOperatorKind.INDEX:
+ case BinaryOperatorKind.ADD:
+ case BinaryOperatorKind.SUB:
+ case BinaryOperatorKind.MUL:
+ case BinaryOperatorKind.DIV:
+ case BinaryOperatorKind.IDIV:
+ case BinaryOperatorKind.MOD:
+ case BinaryOperatorKind.SHL:
+ case BinaryOperatorKind.SHR:
+ case BinaryOperatorKind.GTEQ:
+ case BinaryOperatorKind.GT:
+ case BinaryOperatorKind.LTEQ:
+ case BinaryOperatorKind.LT:
+ case BinaryOperatorKind.AND:
+ case BinaryOperatorKind.OR:
+ case BinaryOperatorKind.XOR:
+ return handleUserDefinableBinary(node, operator);
+ }
+ }
+ }
+ }
+
+ /// Handle a qualified [Send], that is where the receiver is non-null, like
+ /// `a.b`, `a.b()`, `this.a()` and `super.a()`.
+ ResolutionResult handleQualifiedSend(Send node) {
+ Identifier selector = node.selector.asIdentifier();
+ Name name = new Name(selector.source, enclosingElement.library);
+ if (node.isSuperCall) {
+ return handleSuperPropertyAccess(node, name);
+ } else if (node.receiver.isThis()) {
+ if (checkThisAccess(node)) {
+ return handleThisPropertyAccess(node, name);
+ }
+ // TODO(johnniwinther): Handle invalid this access as an
+ // [AccessSemantics].
+ return null;
+ }
+ // TODO(johnniwinther): Handle remaining qualified sends.
+ return oldVisitSend(node);
+ }
+
+ /// Handle access unresolved access to [name] in a non-instance context.
+ ResolutionResult handleUnresolvedAccess(
+ Send node, Name name, Element element) {
+ // TODO(johnniwinther): Support unresolved top level access as an
+ // [AccessSemantics].
+ AccessSemantics accessSemantics = new StaticAccess.unresolved(element);
+ SendStructure sendStructure;
+ Selector selector;
+ if (node.isCall) {
+ CallStructure callStructure = resolveArguments(node.argumentsNode);
+ selector = new Selector(SelectorKind.CALL, name, callStructure);
+ registry.registerDynamicInvocation(selector);
+ sendStructure = new InvokeStructure(accessSemantics, selector);
+ } else {
+ assert(invariant(node, node.isPropertyAccess));
+ selector = new Selector(
+ SelectorKind.GETTER, name, CallStructure.NO_ARGS);
+ registry.registerDynamicGetter(selector);
+ sendStructure = new GetStructure(accessSemantics, selector);
+ }
+ // TODO(johnniwinther): Remove this when all information goes through
+ // the [SendStructure].
+ registry.setSelector(node, selector);
+ registry.useElement(node, element);
+ registry.registerSendStructure(node, sendStructure);
+ return null;
+ }
+
+ /// Handle an unqualified [Send], that is where the `node.receiver` is null,
+ /// like `a`, `a()`, `this()`, `assert()`, and `(){}()`.
+ ResolutionResult handleUnqualifiedSend(Send node) {
+ Identifier selector = node.selector.asIdentifier();
+ if (selector == null) {
+ // `(){}()` and `(foo)()`.
+ return handleExpressionInvoke(node);
+ }
+ String text = selector.source;
+ if (text == 'assert') {
+ // `assert()`.
+ return handleAssert(node);
+ } else if (text == 'this') {
+ // `this()`.
+ return handleThisAccess(node);
+ } else if (text == 'dynamic') {
+ // `dynamic` || `dynamic()`.
+ // TODO(johnniwinther): Handle dynamic type literal access.
+ return oldVisitSend(node);
+ }
+ // `name` or `name()`
+ Name name = new Name(text, enclosingElement.library);
+ Element element = lookupInScope(compiler, node, scope, text);
+ if (element == null) {
+ if (inInstanceContext) {
+ // Implicitly `this.name`.
+ return handleThisPropertyAccess(node, name);
+ } else {
+ // Create [ErroneousElement] for unresolved access.
+ ErroneousElement error = reportCannotResolve(node, text);
+ return handleUnresolvedAccess(node, name, error);
+ }
+ }
+ return oldVisitSend(node);
+ }
+
+ ResolutionResult visitSend(Send node) {
+ if (node.isOperator) {
+ return handleOperatorSend(node);
+ } else if (node.receiver != null) {
+ return handleQualifiedSend(node);
+ } else {
+ return handleUnqualifiedSend(node);
+ }
+ return oldVisitSend(node);
+ }
+
+ ResolutionResult oldVisitSend(Send node) {
bool oldSendIsMemberAccess = sendIsMemberAccess;
sendIsMemberAccess = node.isPropertyAccess || node.isCall;
@@ -1190,12 +1511,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
if (!selector.applies(target, compiler.world)) {
registry.registerThrowNoSuchMethod();
if (node.isSuperCall) {
- // Similar to what we do when we can't find super via selector
- // in [resolveSend] above, we still need to register the invocation,
- // because we might call [:super.noSuchMethod:] which calls
- // [JSInvocationMirror._invokeOn].
- registry.registerDynamicInvocation(selector);
- registry.registerSuperNoSuchMethod();
+ internalError(node, "Unexpected super call $node");
}
}
}
@@ -1229,8 +1545,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
/// Callback for native enqueuer to parse a type. Returns [:null:] on error.
DartType resolveTypeFromString(Node node, String typeName) {
- Element element = lookupInScope(compiler, node,
- scope, typeName);
+ Element element = lookupInScope(compiler, node, scope, typeName);
if (element == null) return null;
if (element is! ClassElement) return null;
ClassElement cls = element;
« no previous file with comments | « pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart ('k') | pkg/compiler/lib/src/resolution/resolution.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698