mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 02:37:53 +00:00
Refactoring resolution of local access and unqualified access of statics
BUG= R=karlklose@google.com Review URL: https://codereview.chromium.org//1149403009
This commit is contained in:
parent
6cc3bd1124
commit
58896b74ce
|
@ -546,7 +546,8 @@ abstract class Enqueuer {
|
|||
*/
|
||||
void registerStaticUse(Element element) {
|
||||
if (element == null) return;
|
||||
assert(invariant(element, element.isDeclaration));
|
||||
assert(invariant(element, element.isDeclaration,
|
||||
message: "Element ${element} is not the declaration."));
|
||||
if (Elements.isStaticOrTopLevel(element) && element.isField) {
|
||||
universe.registerStaticFieldUse(element);
|
||||
}
|
||||
|
|
|
@ -53,6 +53,12 @@ void _trace(String message, {bool condition(String stackTrace), int limit,
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a function to use as an `condition` argument in [trace] that filters
|
||||
/// stack traces that contains any of the [exceptions].
|
||||
traceExceptions(List<String> exceptions) {
|
||||
return (String stackTrace) => !exceptions.any(stackTrace.contains);
|
||||
}
|
||||
|
||||
/// Function signature of [traceAndReport].
|
||||
typedef void TraceAndReport(Compiler compiler, Spannable node, String message,
|
||||
{bool condition(String stackTrace), int limit,
|
||||
|
|
|
@ -1695,6 +1695,26 @@ class SimpleTypeInferrerVisitor<T>
|
|||
return handleStaticFieldOrGetterInvoke(node, getter);
|
||||
}
|
||||
|
||||
@override
|
||||
T visitStaticSetterInvoke(
|
||||
ast.Send node,
|
||||
MethodElement setter,
|
||||
ast.NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
_) {
|
||||
return handleInvalidStaticInvoke(node);
|
||||
}
|
||||
|
||||
@override
|
||||
T visitTopLevelSetterInvoke(
|
||||
ast.Send node,
|
||||
MethodElement setter,
|
||||
ast.NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
_) {
|
||||
return handleInvalidStaticInvoke(node);
|
||||
}
|
||||
|
||||
@override
|
||||
T visitUnresolvedInvoke(
|
||||
ast.Send node,
|
||||
|
@ -1870,6 +1890,22 @@ class SimpleTypeInferrerVisitor<T>
|
|||
return handleStaticGetterGet(node, getter);
|
||||
}
|
||||
|
||||
@override
|
||||
T visitStaticSetterGet(
|
||||
ast.Send node,
|
||||
MethodElement setter,
|
||||
_) {
|
||||
return types.dynamicType;
|
||||
}
|
||||
|
||||
@override
|
||||
T visitTopLevelSetterGet(
|
||||
ast.Send node,
|
||||
MethodElement setter,
|
||||
_) {
|
||||
return types.dynamicType;
|
||||
}
|
||||
|
||||
@override
|
||||
T visitUnresolvedGet(
|
||||
ast.Send node,
|
||||
|
|
|
@ -804,7 +804,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
}
|
||||
|
||||
/// Compute the [AccessSemantics] corresponding to a super access of [target].
|
||||
AccessSemantics computeSuperAccess(Spannable node, Element target) {
|
||||
AccessSemantics computeSuperAccessSemantics(Spannable node, Element target) {
|
||||
if (target.isErroneous) {
|
||||
return new StaticAccess.unresolvedSuper(target);
|
||||
} else if (target.isGetter) {
|
||||
|
@ -812,7 +812,11 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
} else if (target.isSetter) {
|
||||
return new StaticAccess.superSetter(target);
|
||||
} else if (target.isField) {
|
||||
return new StaticAccess.superField(target);
|
||||
if (target.isFinal) {
|
||||
return new StaticAccess.superFinalField(target);
|
||||
} else {
|
||||
return new StaticAccess.superField(target);
|
||||
}
|
||||
} else {
|
||||
assert(invariant(node, target.isFunction,
|
||||
message: "Unexpected super target '$target'."));
|
||||
|
@ -820,6 +824,78 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Compute the [AccessSemantics] corresponding to a local access of [target].
|
||||
AccessSemantics computeLocalAccessSemantics(Spannable node,
|
||||
LocalElement target) {
|
||||
if (target.isParameter) {
|
||||
if (target.isFinal || target.isConst) {
|
||||
return new StaticAccess.finalParameter(target);
|
||||
} else {
|
||||
return new StaticAccess.parameter(target);
|
||||
}
|
||||
} else if (target.isVariable) {
|
||||
if (target.isFinal || target.isConst) {
|
||||
return new StaticAccess.finalLocalVariable(target);
|
||||
} else {
|
||||
return new StaticAccess.localVariable(target);
|
||||
}
|
||||
} else {
|
||||
assert(invariant(node, target.isFunction,
|
||||
message: "Unexpected local target '$target'."));
|
||||
return new StaticAccess.localFunction(target);
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the [AccessSemantics] corresponding to a static or toplevel access
|
||||
/// of [target].
|
||||
AccessSemantics computeStaticOrTopLevelAccessSemantics(
|
||||
Spannable node,
|
||||
Element target) {
|
||||
|
||||
target = target.declaration;
|
||||
if (target.isErroneous) {
|
||||
// This handles elements with parser errors.
|
||||
// TODO(johnniwinther): Elements with parse error should not set
|
||||
// [isErroneous] to `true`.
|
||||
return new StaticAccess.unresolved(target);
|
||||
}
|
||||
if (target.isStatic) {
|
||||
if (target.isGetter) {
|
||||
return new StaticAccess.staticGetter(target);
|
||||
} else if (target.isSetter) {
|
||||
return new StaticAccess.staticSetter(target);
|
||||
} else if (target.isField) {
|
||||
if (target.isFinal || target.isConst) {
|
||||
return new StaticAccess.finalStaticField(target);
|
||||
} else {
|
||||
return new StaticAccess.staticField(target);
|
||||
}
|
||||
} else {
|
||||
assert(invariant(node, target.isFunction,
|
||||
message: "Unexpected static target '$target'."));
|
||||
return new StaticAccess.staticMethod(target);
|
||||
}
|
||||
} else {
|
||||
assert(invariant(node, target.isTopLevel,
|
||||
message: "Unexpected statically resolved target '$target'."));
|
||||
if (target.isGetter) {
|
||||
return new StaticAccess.topLevelGetter(target);
|
||||
} else if (target.isSetter) {
|
||||
return new StaticAccess.topLevelSetter(target);
|
||||
} else if (target.isField) {
|
||||
if (target.isFinal) {
|
||||
return new StaticAccess.finalTopLevelField(target);
|
||||
} else {
|
||||
return new StaticAccess.topLevelField(target);
|
||||
}
|
||||
} else {
|
||||
assert(invariant(node, target.isFunction,
|
||||
message: "Unexpected top level target '$target'."));
|
||||
return new StaticAccess.topLevelMethod(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the [AccessSemantics] for accessing the name of [selector] on the
|
||||
/// super class.
|
||||
///
|
||||
|
@ -836,9 +912,11 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
/// foo => super.name; // Access to the setter.
|
||||
/// }
|
||||
///
|
||||
AccessSemantics computeSuperSemantics(Spannable node,
|
||||
Selector selector,
|
||||
{Name alternateName}) {
|
||||
AccessSemantics computeSuperAccessSemanticsForSelector(
|
||||
Spannable node,
|
||||
Selector selector,
|
||||
{Name alternateName}) {
|
||||
|
||||
Name name = selector.memberName;
|
||||
// TODO(johnniwinther): Ensure correct behavior if currentClass is a
|
||||
// patch.
|
||||
|
@ -860,7 +938,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
registry.registerDynamicInvocation(selector);
|
||||
registry.registerSuperNoSuchMethod();
|
||||
}
|
||||
return computeSuperAccess(node, target);
|
||||
return computeSuperAccessSemantics(node, target);
|
||||
}
|
||||
|
||||
/// Resolve [node] as subexpression that is _not_ the prefix of a member
|
||||
|
@ -938,7 +1016,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
AccessSemantics semantics;
|
||||
if (node.isSuperCall) {
|
||||
if (checkSuperAccess(node)) {
|
||||
semantics = computeSuperSemantics(node, selector);
|
||||
semantics = computeSuperAccessSemanticsForSelector(node, selector);
|
||||
// TODO(johnniwinther): Add information to [AccessSemantics] about
|
||||
// whether it is erroneous.
|
||||
if (semantics.kind == AccessKind.SUPER_METHOD) {
|
||||
|
@ -1037,7 +1115,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
|
||||
if (node.isSuperCall) {
|
||||
if (checkSuperAccess(node)) {
|
||||
semantics = computeSuperSemantics(node, selector);
|
||||
semantics = computeSuperAccessSemanticsForSelector(node, selector);
|
||||
// TODO(johnniwinther): Add information to [AccessSemantics] about
|
||||
// whether it is erroneous.
|
||||
if (semantics.kind == AccessKind.SUPER_METHOD) {
|
||||
|
@ -1201,7 +1279,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
selector = new Selector(SelectorKind.GETTER, name, callStructure);
|
||||
}
|
||||
if (checkSuperAccess(node)) {
|
||||
AccessSemantics semantics = computeSuperSemantics(
|
||||
AccessSemantics semantics = computeSuperAccessSemanticsForSelector(
|
||||
node, selector, alternateName: name.setter);
|
||||
if (node.isCall) {
|
||||
bool isIncompatibleInvoke = false;
|
||||
|
@ -1219,6 +1297,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
}
|
||||
break;
|
||||
case AccessKind.SUPER_FIELD:
|
||||
case AccessKind.SUPER_FINAL_FIELD:
|
||||
case AccessKind.SUPER_GETTER:
|
||||
registry.registerStaticUse(semantics.element);
|
||||
selector = callStructure.callSelector;
|
||||
|
@ -1244,6 +1323,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
registry.registerStaticUse(semantics.element);
|
||||
break;
|
||||
case AccessKind.SUPER_FIELD:
|
||||
case AccessKind.SUPER_FINAL_FIELD:
|
||||
case AccessKind.SUPER_GETTER:
|
||||
registry.registerStaticUse(semantics.element);
|
||||
break;
|
||||
|
@ -1353,6 +1433,12 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
// TODO(johnniwinther): Support unresolved top level access as an
|
||||
// [AccessSemantics].
|
||||
AccessSemantics accessSemantics = new StaticAccess.unresolved(element);
|
||||
return handleErroneousAccess(node, name, element, accessSemantics);
|
||||
}
|
||||
|
||||
/// Handle erroneous access of [element] of the given [accessSemantics].
|
||||
ResolutionResult handleErroneousAccess(
|
||||
Send node, Name name, Element element, AccessSemantics accessSemantics) {
|
||||
SendStructure sendStructure;
|
||||
Selector selector;
|
||||
if (node.isCall) {
|
||||
|
@ -1375,6 +1461,242 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
return null;
|
||||
}
|
||||
|
||||
/// Handle access to an ambiguous element, that is, a name imported twice.
|
||||
ResolutionResult handleAmbiguousSend(
|
||||
Send node,
|
||||
Name name,
|
||||
AmbiguousElement element) {
|
||||
|
||||
compiler.reportError(
|
||||
node, element.messageKind, element.messageArguments);
|
||||
element.diagnose(enclosingElement, compiler);
|
||||
|
||||
ErroneousElement error = new ErroneousElementX(
|
||||
element.messageKind,
|
||||
element.messageArguments,
|
||||
name.text,
|
||||
enclosingElement);
|
||||
|
||||
// TODO(johnniwinther): Support ambiguous access as an [AccessSemantics].
|
||||
AccessSemantics accessSemantics = new StaticAccess.unresolved(error);
|
||||
return handleErroneousAccess(node, name, error, accessSemantics);
|
||||
}
|
||||
|
||||
/// Handle access of an instance [member] from a non-instance context.
|
||||
ResolutionResult handleStaticInstanceSend(
|
||||
Send node, Name name, MemberElement member) {
|
||||
compiler.reportError(
|
||||
node, MessageKind.NO_INSTANCE_AVAILABLE, {'name': member.name});
|
||||
ErroneousElement error = new ErroneousElementX(
|
||||
MessageKind.NO_INSTANCE_AVAILABLE,
|
||||
{'name': name},
|
||||
name.text,
|
||||
enclosingElement);
|
||||
|
||||
// TODO(johnniwinther): Support static instance access as an
|
||||
// [AccessSemantics].
|
||||
AccessSemantics accessSemantics = new StaticAccess.unresolved(error);
|
||||
return handleErroneousAccess(node, name, error, accessSemantics);
|
||||
}
|
||||
|
||||
/// Handle access of a parameter, local variable or local function.
|
||||
ResolutionResult handleLocalAccess(Send node, Name name, Element element) {
|
||||
AccessSemantics semantics = computeLocalAccessSemantics(node, element);
|
||||
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 (node.isCall) {
|
||||
bool isIncompatibleInvoke = false;
|
||||
switch (semantics.kind) {
|
||||
case AccessKind.LOCAL_FUNCTION:
|
||||
LocalFunctionElementX function = semantics.element;
|
||||
function.computeSignature(compiler);
|
||||
if (!callStructure.signatureApplies(function)) {
|
||||
registry.registerThrowNoSuchMethod();
|
||||
registry.registerDynamicInvocation(selector);
|
||||
isIncompatibleInvoke = true;
|
||||
}
|
||||
break;
|
||||
case AccessKind.PARAMETER:
|
||||
case AccessKind.FINAL_PARAMETER:
|
||||
case AccessKind.LOCAL_VARIABLE:
|
||||
case AccessKind.FINAL_LOCAL_VARIABLE:
|
||||
selector = callStructure.callSelector;
|
||||
registry.registerDynamicInvocation(selector);
|
||||
break;
|
||||
default:
|
||||
internalError(node,
|
||||
"Unexpected local access $semantics.");
|
||||
break;
|
||||
}
|
||||
registry.registerSendStructure(node,
|
||||
isIncompatibleInvoke
|
||||
? new IncompatibleInvokeStructure(semantics, selector)
|
||||
: new InvokeStructure(semantics, selector));
|
||||
} else {
|
||||
registry.registerSendStructure(node,
|
||||
new GetStructure(semantics, selector));
|
||||
}
|
||||
|
||||
// TODO(johnniwinther): Remove these when all information goes through
|
||||
// the [SendStructure].
|
||||
registry.useElement(node, element);
|
||||
registry.setSelector(node, selector);
|
||||
|
||||
registerPotentialAccessInClosure(node, element);
|
||||
|
||||
return node.isPropertyAccess ? new ElementResult(element) : null;
|
||||
}
|
||||
|
||||
/// Handle access of a static or top level [element].
|
||||
ResolutionResult handleStaticOrTopLevelAccess(
|
||||
Send node, Name name, Element element) {
|
||||
|
||||
if (element.isAbstractField) {
|
||||
AbstractFieldElement abstractField = element;
|
||||
if (abstractField.getter != null) {
|
||||
element = abstractField.getter;
|
||||
} else {
|
||||
element = abstractField.setter;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
AccessSemantics semantics =
|
||||
computeStaticOrTopLevelAccessSemantics(node, element);
|
||||
if (node.isCall) {
|
||||
bool isIncompatibleInvoke = false;
|
||||
switch (semantics.kind) {
|
||||
case AccessKind.STATIC_METHOD:
|
||||
case AccessKind.TOPLEVEL_METHOD:
|
||||
MethodElementX method = semantics.element;
|
||||
method.computeSignature(compiler);
|
||||
if (!callStructure.signatureApplies(method)) {
|
||||
registry.registerThrowNoSuchMethod();
|
||||
registry.registerDynamicInvocation(selector);
|
||||
isIncompatibleInvoke = true;
|
||||
} else {
|
||||
registry.registerStaticUse(semantics.element);
|
||||
handleForeignCall(node, semantics.element, selector);
|
||||
}
|
||||
break;
|
||||
case AccessKind.STATIC_FIELD:
|
||||
case AccessKind.FINAL_STATIC_FIELD:
|
||||
case AccessKind.STATIC_GETTER:
|
||||
case AccessKind.TOPLEVEL_FIELD:
|
||||
case AccessKind.FINAL_TOPLEVEL_FIELD:
|
||||
case AccessKind.TOPLEVEL_GETTER:
|
||||
registry.registerStaticUse(semantics.element);
|
||||
selector = callStructure.callSelector;
|
||||
registry.registerDynamicInvocation(selector);
|
||||
break;
|
||||
case AccessKind.STATIC_SETTER:
|
||||
case AccessKind.TOPLEVEL_SETTER:
|
||||
case AccessKind.UNRESOLVED:
|
||||
registry.registerThrowNoSuchMethod();
|
||||
element = reportAndCreateErroneousElement(
|
||||
node.selector, name.text,
|
||||
MessageKind.CANNOT_RESOLVE_GETTER, const {});
|
||||
break;
|
||||
default:
|
||||
internalError(node,
|
||||
"Unexpected statically resolved access $semantics.");
|
||||
break;
|
||||
}
|
||||
registry.registerSendStructure(node,
|
||||
isIncompatibleInvoke
|
||||
? new IncompatibleInvokeStructure(semantics, selector)
|
||||
: new InvokeStructure(semantics, selector));
|
||||
} else {
|
||||
switch (semantics.kind) {
|
||||
case AccessKind.STATIC_METHOD:
|
||||
case AccessKind.TOPLEVEL_METHOD:
|
||||
// TODO(johnniwinther): Method this should be registered as a
|
||||
// closurization.
|
||||
registry.registerStaticUse(semantics.element);
|
||||
registry.registerGetOfStaticFunction(semantics.element);
|
||||
break;
|
||||
case AccessKind.STATIC_FIELD:
|
||||
case AccessKind.FINAL_STATIC_FIELD:
|
||||
case AccessKind.STATIC_GETTER:
|
||||
case AccessKind.TOPLEVEL_FIELD:
|
||||
case AccessKind.FINAL_TOPLEVEL_FIELD:
|
||||
case AccessKind.TOPLEVEL_GETTER:
|
||||
registry.registerStaticUse(semantics.element);
|
||||
break;
|
||||
case AccessKind.STATIC_SETTER:
|
||||
case AccessKind.TOPLEVEL_SETTER:
|
||||
case AccessKind.UNRESOLVED:
|
||||
registry.registerThrowNoSuchMethod();
|
||||
element = reportAndCreateErroneousElement(
|
||||
node.selector, name.text,
|
||||
MessageKind.CANNOT_RESOLVE_GETTER, const {});
|
||||
break;
|
||||
default:
|
||||
internalError(node,
|
||||
"Unexpected statically resolved access $semantics.");
|
||||
break;
|
||||
}
|
||||
registry.registerSendStructure(node,
|
||||
new GetStructure(semantics, selector));
|
||||
}
|
||||
|
||||
// TODO(johnniwinther): Remove these when all information goes through
|
||||
// the [SendStructure].
|
||||
registry.useElement(node, element);
|
||||
registry.setSelector(node, selector);
|
||||
|
||||
return node.isPropertyAccess ? new ElementResult(element) : null;
|
||||
}
|
||||
|
||||
/// Handle access to resolved [element].
|
||||
ResolutionResult handleResolvedSend(Send node, Name name, Element element) {
|
||||
if (element.isAmbiguous) {
|
||||
return handleAmbiguousSend(node, name, element);
|
||||
}
|
||||
if (element.isErroneous) {
|
||||
// This handles elements with parser errors.
|
||||
// TODO(johnniwinther): Elements with parse error should not set
|
||||
// [isErroneous] to `true`.
|
||||
assert(invariant(node, element is! ErroneousElement,
|
||||
message: "Unexpected erroneous element $element."));
|
||||
return handleErroneousAccess(node, name, element,
|
||||
new StaticAccess.unresolved(element));
|
||||
}
|
||||
if (element.isInstanceMember) {
|
||||
if (inInstanceContext) {
|
||||
// TODO(johnniwinther): Maybe use the found [element].
|
||||
return handleThisPropertyAccess(node, name);
|
||||
} else {
|
||||
return handleStaticInstanceSend(node, name, element);
|
||||
}
|
||||
}
|
||||
if (element.isClass || element.isTypedef) {
|
||||
return oldVisitSend(node);
|
||||
} else if (element.isTypeVariable) {
|
||||
return oldVisitSend(node);
|
||||
} else if (element.isPrefix) {
|
||||
return oldVisitSend(node);
|
||||
} else if (element.isLocal) {
|
||||
return handleLocalAccess(node, name, element);
|
||||
} else if (element.isStatic || element.isTopLevel) {
|
||||
return handleStaticOrTopLevelAccess(node, name, element);
|
||||
}
|
||||
return internalError(node, "Unexpected resolved send: $element");
|
||||
}
|
||||
|
||||
/// Handle an unqualified [Send], that is where the `node.receiver` is null,
|
||||
/// like `a`, `a()`, `this()`, `assert()`, and `(){}()`.
|
||||
ResolutionResult handleUnqualifiedSend(Send node) {
|
||||
|
@ -1407,19 +1729,33 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
ErroneousElement error = reportCannotResolve(node, text);
|
||||
return handleUnresolvedAccess(node, name, error);
|
||||
}
|
||||
} else {
|
||||
return handleResolvedSend(node, name, element);
|
||||
}
|
||||
return oldVisitSend(node);
|
||||
}
|
||||
|
||||
ResolutionResult visitSend(Send node) {
|
||||
if (node.isOperator) {
|
||||
// `a && b`, `a + b`, `-a`, or `a is T`.
|
||||
return handleOperatorSend(node);
|
||||
} else if (node.receiver != null) {
|
||||
// `a.b`.
|
||||
return handleQualifiedSend(node);
|
||||
} else {
|
||||
// `a`.
|
||||
return handleUnqualifiedSend(node);
|
||||
}
|
||||
return oldVisitSend(node);
|
||||
}
|
||||
|
||||
/// Regigster read access of [target] inside a closure.
|
||||
void registerPotentialAccessInClosure(Send node, Element target) {
|
||||
if (isPotentiallyMutableTarget(target)) {
|
||||
if (enclosingElement != target.enclosingElement) {
|
||||
for (Node scope in promotionScope) {
|
||||
registry.setAccessedByClosureIn(scope, target, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ResolutionResult oldVisitSend(Send node) {
|
||||
|
@ -1467,13 +1803,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
} else if (target.impliesType && (!sendIsMemberAccess || node.isCall)) {
|
||||
registerTypeLiteralAccess(node, target);
|
||||
}
|
||||
if (isPotentiallyMutableTarget(target)) {
|
||||
if (enclosingElement != target.enclosingElement) {
|
||||
for (Node scope in promotionScope) {
|
||||
registry.setAccessedByClosureIn(scope, target, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
registerPotentialAccessInClosure(node, target);
|
||||
}
|
||||
|
||||
bool resolvedArguments = false;
|
||||
|
@ -1511,23 +1841,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
}
|
||||
}
|
||||
|
||||
if (target != null && compiler.backend.isForeign(target)) {
|
||||
if (selector.name == 'JS') {
|
||||
registry.registerJsCall(node, this);
|
||||
} else if (selector.name == 'JS_EMBEDDED_GLOBAL') {
|
||||
registry.registerJsEmbeddedGlobalCall(node, this);
|
||||
} else if (selector.name == 'JS_BUILTIN') {
|
||||
registry.registerJsBuiltinCall(node, this);
|
||||
} else if (selector.name == 'JS_INTERCEPTOR_CONSTANT') {
|
||||
if (!node.argumentsNode.isEmpty) {
|
||||
Node argument = node.argumentsNode.nodes.head;
|
||||
if (argumentsToJsInterceptorConstant == null) {
|
||||
argumentsToJsInterceptorConstant = new Set<Node>();
|
||||
}
|
||||
argumentsToJsInterceptorConstant.add(argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
handleForeignCall(node, target, selector);
|
||||
}
|
||||
|
||||
registry.useElement(node, target);
|
||||
|
@ -1538,6 +1852,27 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
|
|||
return node.isPropertyAccess ? new ElementResult(target) : null;
|
||||
}
|
||||
|
||||
// TODO(johnniwinther): Move this to the backend resolution callbacks.
|
||||
void handleForeignCall(Send node, Element target, Selector selector) {
|
||||
if (target != null && compiler.backend.isForeign(target)) {
|
||||
if (selector.name == 'JS') {
|
||||
registry.registerJsCall(node, this);
|
||||
} else if (selector.name == 'JS_EMBEDDED_GLOBAL') {
|
||||
registry.registerJsEmbeddedGlobalCall(node, this);
|
||||
} else if (selector.name == 'JS_BUILTIN') {
|
||||
registry.registerJsBuiltinCall(node, this);
|
||||
} else if (selector.name == 'JS_INTERCEPTOR_CONSTANT') {
|
||||
if (!node.argumentsNode.isEmpty) {
|
||||
Node argument = node.argumentsNode.nodes.head;
|
||||
if (argumentsToJsInterceptorConstant == null) {
|
||||
argumentsToJsInterceptorConstant = new Set<Node>();
|
||||
}
|
||||
argumentsToJsInterceptorConstant.add(argument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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);
|
||||
|
|
|
@ -983,7 +983,7 @@ class CommonResolverVisitor<R> extends Visitor<R> {
|
|||
compiler.reportWarning(node, kind, arguments);
|
||||
}
|
||||
|
||||
void internalError(Spannable node, message) {
|
||||
internalError(Spannable node, message) {
|
||||
compiler.internalError(node, message);
|
||||
}
|
||||
|
||||
|
|
|
@ -1322,9 +1322,12 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
bool meetsHardConstraints() {
|
||||
if (compiler.disableInlining) return false;
|
||||
|
||||
assert(selector != null
|
||||
|| Elements.isStaticOrTopLevel(element)
|
||||
|| element.isGenerativeConstructorBody);
|
||||
assert(invariant(
|
||||
currentNode != null ? currentNode : element,
|
||||
selector != null ||
|
||||
Elements.isStaticOrTopLevel(element) ||
|
||||
element.isGenerativeConstructorBody,
|
||||
message: "Missing selector for inlining of $element."));
|
||||
if (selector != null && !selector.applies(function, compiler.world)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -3246,8 +3249,7 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
return pop();
|
||||
}
|
||||
|
||||
String noSuchMethodTargetSymbolString(ErroneousElement error,
|
||||
[String prefix]) {
|
||||
String noSuchMethodTargetSymbolString(Element error, [String prefix]) {
|
||||
String result = error.name;
|
||||
if (prefix == "set") return "$result=";
|
||||
return result;
|
||||
|
@ -3288,14 +3290,18 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
node);
|
||||
}
|
||||
|
||||
void handleInvalidStaticGet(ast.Send node, Element element) {
|
||||
generateThrowNoSuchMethod(
|
||||
node,
|
||||
noSuchMethodTargetSymbolString(element, 'get'),
|
||||
argumentNodes: const Link<ast.Node>());
|
||||
}
|
||||
|
||||
/// Generate read access of an unresolved static or top level entity.
|
||||
void generateStaticUnresolvedGet(ast.Send node, Element element) {
|
||||
if (element is ErroneousElement) {
|
||||
// An erroneous element indicates an unresolved static getter.
|
||||
generateThrowNoSuchMethod(
|
||||
node,
|
||||
noSuchMethodTargetSymbolString(element, 'get'),
|
||||
argumentNodes: const Link<ast.Node>());
|
||||
handleInvalidStaticGet(node, element);
|
||||
} else {
|
||||
// This happens when [element] has parse errors.
|
||||
assert(invariant(node, element == null || element.isErroneous));
|
||||
|
@ -5146,6 +5152,22 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
generateCallInvoke(node, pop());
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTopLevelSetterGet(
|
||||
ast.Send node,
|
||||
MethodElement setter,
|
||||
_) {
|
||||
handleInvalidStaticGet(node, setter);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitStaticSetterGet(
|
||||
ast.Send node,
|
||||
MethodElement setter,
|
||||
_) {
|
||||
handleInvalidStaticGet(node, setter);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitUnresolvedGet(
|
||||
ast.Send node,
|
||||
|
@ -5154,6 +5176,32 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
generateStaticUnresolvedGet(node, element);
|
||||
}
|
||||
|
||||
void handleInvalidStaticInvoke(ast.Send node, Element element) {
|
||||
generateThrowNoSuchMethod(node,
|
||||
noSuchMethodTargetSymbolString(element),
|
||||
argumentNodes: node.arguments);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitStaticSetterInvoke(
|
||||
ast.Send node,
|
||||
MethodElement setter,
|
||||
ast.NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
_) {
|
||||
handleInvalidStaticInvoke(node, setter);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitTopLevelSetterInvoke(
|
||||
ast.Send node,
|
||||
MethodElement setter,
|
||||
ast.NodeList arguments,
|
||||
CallStructure callStructure,
|
||||
_) {
|
||||
handleInvalidStaticInvoke(node, setter);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitUnresolvedInvoke(
|
||||
ast.Send node,
|
||||
|
@ -5164,9 +5212,7 @@ class SsaBuilder extends NewResolvedVisitor {
|
|||
if (element is ErroneousElement) {
|
||||
// An erroneous element indicates that the funciton could not be
|
||||
// resolved (a warning has been issued).
|
||||
generateThrowNoSuchMethod(node,
|
||||
noSuchMethodTargetSymbolString(element),
|
||||
argumentNodes: node.arguments);
|
||||
handleInvalidStaticInvoke(node, element);
|
||||
} else {
|
||||
// TODO(ahe): Do something like [generateWrongArgumentCountError].
|
||||
stack.add(graph.addConstantNull(compiler));
|
||||
|
|
|
@ -38,7 +38,7 @@ main() {
|
|||
"memory:library.dart:41:45:'hest' is defined here.:info",
|
||||
"memory:main.dart:0:22:'hest' is imported here.:info",
|
||||
"memory:main.dart:23:46:'hest' is imported here.:info",
|
||||
"memory:main.dart:86:90:Duplicate import of 'hest'.:error"
|
||||
"memory:main.dart:86:92:Duplicate import of 'hest'.:error"
|
||||
];
|
||||
Expect.listEquals(expected, diagnostics);
|
||||
Expect.isTrue(compiler.compilationFailed);
|
||||
|
|
|
@ -337,7 +337,7 @@ Future testLocalsThree() {
|
|||
Expect.equals(null, element);
|
||||
MethodScope scope = visitor.scope;
|
||||
Expect.equals(0, scope.elements.length);
|
||||
Expect.equals(3, map(visitor).length);
|
||||
Expect.equals(2, map(visitor).length);
|
||||
List<Element> elements = map(visitor).values.toList();
|
||||
Expect.equals(elements[0], elements[1]);
|
||||
});
|
||||
|
@ -366,7 +366,7 @@ Future testLocalsFive() {
|
|||
Expect.equals(null, element);
|
||||
MethodScope scope = visitor.scope;
|
||||
Expect.equals(0, scope.elements.length);
|
||||
Expect.equals(6, map(visitor).length);
|
||||
Expect.equals(4, map(visitor).length);
|
||||
|
||||
Block thenPart = tree.thenPart;
|
||||
List statements1 = thenPart.statements.nodes.toList();
|
||||
|
@ -419,7 +419,7 @@ Future testFor() {
|
|||
|
||||
MethodScope scope = visitor.scope;
|
||||
Expect.equals(0, scope.elements.length);
|
||||
Expect.equals(9, map(visitor).length);
|
||||
Expect.equals(7, map(visitor).length);
|
||||
|
||||
VariableDefinitions initializer = tree.initializer;
|
||||
Node iNode = initializer.definitions.nodes.head;
|
||||
|
@ -437,35 +437,27 @@ Future testFor() {
|
|||
|
||||
// for (int i = 0; i < 10; i = i + 1) { i = 5; };
|
||||
// ^
|
||||
checkIdentifier(iElement, nodes[1], elements[1]);
|
||||
|
||||
// for (int i = 0; i < 10; i = i + 1) { i = 5; };
|
||||
// ^
|
||||
checkSend(iElement, nodes[2], elements[2]);
|
||||
checkSend(iElement, nodes[1], elements[1]);
|
||||
|
||||
// for (int i = 0; i < 10; i = i + 1) { i = 5; };
|
||||
// ^
|
||||
checkIdentifier(iElement, nodes[3], elements[3]);
|
||||
checkIdentifier(iElement, nodes[2], elements[2]);
|
||||
|
||||
// for (int i = 0; i < 10; i = i + 1) { i = 5; };
|
||||
// ^
|
||||
checkIdentifier(iElement, nodes[4], elements[4]);
|
||||
|
||||
// for (int i = 0; i < 10; i = i + 1) { i = 5; };
|
||||
// ^
|
||||
checkSend(iElement, nodes[5], elements[5]);
|
||||
checkSend(iElement, nodes[3], elements[3]);
|
||||
|
||||
// for (int i = 0; i < 10; i = i + 1) { i = 5; };
|
||||
// ^^^^^^^^^
|
||||
checkSendSet(iElement, nodes[6], elements[6]);
|
||||
checkSendSet(iElement, nodes[4], elements[4]);
|
||||
|
||||
// for (int i = 0; i < 10; i = i + 1) { i = 5; };
|
||||
// ^
|
||||
checkIdentifier(iElement, nodes[7], elements[7]);
|
||||
checkIdentifier(iElement, nodes[5], elements[5]);
|
||||
|
||||
// for (int i = 0; i < 10; i = i + 1) { i = 5; };
|
||||
// ^^^^^
|
||||
checkSendSet(iElement, nodes[8], elements[8]);
|
||||
checkSendSet(iElement, nodes[6], elements[6]);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -927,7 +919,7 @@ Future testInitializers() {
|
|||
int bar;
|
||||
A() : this.foo = bar;
|
||||
}""";
|
||||
return resolveConstructor(script, "A a = new A();", "A", "", 3,
|
||||
return resolveConstructor(script, "A a = new A();", "A", "", 2,
|
||||
expectedWarnings: [],
|
||||
expectedErrors: [MessageKind.NO_INSTANCE_AVAILABLE]);
|
||||
},
|
||||
|
|
|
@ -184,11 +184,6 @@ const List<VisitKind> UNTESTABLE_KINDS = const <VisitKind>[
|
|||
VisitKind.VISIT_SUPER_METHOD_SETTER_COMPOUND,
|
||||
VisitKind.VISIT_SUPER_METHOD_SETTER_PREFIX,
|
||||
VisitKind.VISIT_SUPER_METHOD_SETTER_POSTFIX,
|
||||
// Invalid use of setters is currently reported through an erroneous element.
|
||||
VisitKind.VISIT_STATIC_SETTER_INVOKE,
|
||||
VisitKind.VISIT_STATIC_SETTER_GET,
|
||||
VisitKind.VISIT_TOP_LEVEL_SETTER_GET,
|
||||
VisitKind.VISIT_TOP_LEVEL_SETTER_INVOKE,
|
||||
// The constant expressions of assignment to constant type literals cannot be
|
||||
// handled the compile constant evaluator.
|
||||
VisitKind.VISIT_CLASS_TYPE_LITERAL_SET,
|
||||
|
|
|
@ -350,8 +350,9 @@ const Map<String, List<Test>> SEND_TESTS = const {
|
|||
m() => o;
|
||||
}
|
||||
''',
|
||||
const Visit(VisitKind.VISIT_UNRESOLVED_GET,
|
||||
name: 'o')),
|
||||
const Visit(VisitKind.VISIT_STATIC_SETTER_GET,
|
||||
element: 'setter(C#o)')),
|
||||
|
||||
const Test.clazz(
|
||||
'''
|
||||
class C {
|
||||
|
@ -462,8 +463,8 @@ const Map<String, List<Test>> SEND_TESTS = const {
|
|||
m() { o(null, 42); }
|
||||
}
|
||||
''',
|
||||
const Visit(VisitKind.VISIT_UNRESOLVED_INVOKE,
|
||||
name: 'o',
|
||||
const Visit(VisitKind.VISIT_STATIC_SETTER_INVOKE,
|
||||
element: 'setter(C#o)',
|
||||
arguments: '(null,42)')),
|
||||
const Test.clazz(
|
||||
'''
|
||||
|
@ -720,8 +721,8 @@ const Map<String, List<Test>> SEND_TESTS = const {
|
|||
set o(_) {}
|
||||
m() => o;
|
||||
''',
|
||||
const Visit(VisitKind.VISIT_UNRESOLVED_GET,
|
||||
name: 'o')),
|
||||
const Visit(VisitKind.VISIT_TOP_LEVEL_SETTER_GET,
|
||||
element: 'setter(o)')),
|
||||
const Test.prefix(
|
||||
'''
|
||||
set o(_) {}
|
||||
|
@ -786,8 +787,8 @@ const Map<String, List<Test>> SEND_TESTS = const {
|
|||
set o(_) {}
|
||||
m() => o(null, 42);
|
||||
''',
|
||||
const Visit(VisitKind.VISIT_UNRESOLVED_INVOKE,
|
||||
name: 'o',
|
||||
const Visit(VisitKind.VISIT_TOP_LEVEL_SETTER_INVOKE,
|
||||
element: 'setter(o)',
|
||||
arguments: '(null,42)')),
|
||||
const Test.prefix(
|
||||
'''
|
||||
|
|
|
@ -618,7 +618,7 @@ main() {
|
|||
returnNum1(true);
|
||||
returnNum2(true);
|
||||
returnInt1(true);
|
||||
returnInt2(true);
|
||||
returnInt2();
|
||||
returnInt3(true);
|
||||
returnInt4();
|
||||
returnDouble(true);
|
||||
|
@ -667,7 +667,7 @@ main() {
|
|||
returnAsTypedef();
|
||||
returnTopLevelGetter();
|
||||
testDeadCode();
|
||||
testLabeledIf();
|
||||
testLabeledIf(true);
|
||||
testSwitch1();
|
||||
testSwitch2();
|
||||
testSwitch3();
|
||||
|
@ -727,6 +727,7 @@ main() {
|
|||
void main() {
|
||||
Uri uri = new Uri(scheme: 'source');
|
||||
var compiler = compilerFor(TEST, uri);
|
||||
compiler.diagnosticHandler = createHandler(compiler, TEST);
|
||||
asyncTest(() => compiler.runCompiler(uri).then((_) {
|
||||
var typesTask = compiler.typesTask;
|
||||
var typesInferrer = typesTask.typesInferrer;
|
||||
|
|
Loading…
Reference in a new issue