Refactor SsaBuilder.visitStaticSend and visitGetterSend.

BUG=
R=karlklose@google.com

Review URL: https://codereview.chromium.org//1112563002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@45449 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
johnniwinther@google.com 2015-04-29 11:44:05 +00:00
parent f59e077911
commit d9b0cc7da2
10 changed files with 580 additions and 201 deletions

View file

@ -794,6 +794,14 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive>
return irBuilder.buildSuperMethodGet(method);
}
@override
ir.Primitive visitUnresolvedGet(
ast.Send node,
Element element,
_) {
return giveup(node, 'visitUnresolvedGet');
}
@override
ir.Primitive visitUnresolvedSuperGet(
ast.Send node,
@ -1127,6 +1135,16 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive>
sourceInformation: sourceInformationBuilder.buildCall(node));
}
@override
ir.Primitive handleStaticFunctionIncompatibleInvoke(
ast.Send node,
MethodElement function,
ast.NodeList arguments,
CallStructure callStructure,
_) {
return giveup(node, 'handleStaticFunctionIncompatibleInvoke');
}
@override
ir.Primitive handleStaticGetterInvoke(
ast.Send node,
@ -1190,10 +1208,20 @@ abstract class IrBuilderVisitor extends ast.Visitor<ir.Primitive>
return giveup(node, 'visitSuperMethodIncompatibleInvoke');
}
@override
ir.Primitive visitUnresolvedInvoke(
ast.Send node,
Element element,
ast.NodeList arguments,
Selector selector,
_) {
return giveup(node, 'visitUnresolvedInvoke');
}
@override
ir.Primitive visitUnresolvedSuperInvoke(
ast.Send node,
MethodElement method,
Element element,
ast.NodeList arguments,
Selector selector,
_) {

View file

@ -737,6 +737,21 @@ abstract class SemanticSendVisitor<R, A> {
CallStructure callStructure,
A arg);
/// Invocation of the static [function] with incompatible [arguments].
///
/// For instance
/// class C {
/// static foo(a, b) {}
/// }
/// m() { C.foo(null); }
///
R visitStaticFunctionIncompatibleInvoke(
Send node,
MethodElement function,
NodeList arguments,
CallStructure callStructure,
A arg);
/// Assignment of [rhs] to the static [function].
///
/// For instance
@ -907,6 +922,21 @@ abstract class SemanticSendVisitor<R, A> {
CallStructure callStructure,
A arg);
/// Invocation of the top level [function] with incompatible [arguments].
///
/// For instance
/// class C {
/// static foo(a, b) {}
/// }
/// m() { C.foo(null); }
///
R visitTopLevelFunctionIncompatibleInvoke(
Send node,
MethodElement function,
NodeList arguments,
CallStructure callStructure,
A arg);
/// Assignment of [rhs] to the top level [function].
///
/// For instance
@ -2682,7 +2712,7 @@ abstract class SemanticSendVisitor<R, A> {
/// m7() => prefix.C.unresolved;
///
// TODO(johnniwinther): Split the cases in which a prefix is resolved.
R errorUnresolvedGet(
R visitUnresolvedGet(
Send node,
Element element,
A arg);
@ -2732,7 +2762,7 @@ abstract class SemanticSendVisitor<R, A> {
/// m7() => prefix.C.unresolved(null, 42);
///
// TODO(johnniwinther): Split the cases in which a prefix is resolved.
R errorUnresolvedInvoke(
R visitUnresolvedInvoke(
Send node,
Element element,
NodeList arguments,

View file

@ -464,24 +464,6 @@ abstract class ErrorBulkMixin<R, A>
return bulkHandleError(node, arg);
}
@override
R errorUnresolvedGet(
Send node,
Element element,
A arg) {
return bulkHandleError(node, arg);
}
@override
R errorUnresolvedInvoke(
Send node,
Element element,
NodeList arguments,
Selector selector,
A arg) {
return bulkHandleError(node, arg);
}
@override
R errorUnresolvedPostfix(
Send node,
@ -1237,6 +1219,16 @@ abstract class InvokeBulkMixin<R, A>
return bulkHandleInvoke(node, arg);
}
@override
R visitStaticFunctionIncompatibleInvoke(
Send node,
MethodElement function,
NodeList arguments,
CallStructure callStructure,
A arg) {
return bulkHandleInvoke(node, arg);
}
@override
R visitStaticGetterInvoke(
Send node,
@ -1325,6 +1317,16 @@ abstract class InvokeBulkMixin<R, A>
return bulkHandleInvoke(node, arg);
}
@override
R visitTopLevelFunctionIncompatibleInvoke(
Send node,
MethodElement function,
NodeList arguments,
CallStructure callStructure,
A arg) {
return bulkHandleInvoke(node, arg);
}
@override
R visitTopLevelGetterInvoke(
Send node,
@ -1365,6 +1367,16 @@ abstract class InvokeBulkMixin<R, A>
return bulkHandleInvoke(node, arg);
}
@override
R visitUnresolvedInvoke(
Send node,
Element element,
NodeList arguments,
Selector selector,
A arg) {
return bulkHandleInvoke(node, arg);
}
@override
R visitUnresolvedSuperInvoke(
Send node,
@ -1546,6 +1558,14 @@ abstract class GetBulkMixin<R, A>
return bulkHandleGet(node, arg);
}
@override
R visitUnresolvedGet(
Send node,
Element element,
A arg) {
return bulkHandleGet(node, arg);
}
@override
R visitUnresolvedSuperGet(
Send node,
@ -3769,6 +3789,17 @@ class TraversalSendMixin<R, A> implements SemanticSendVisitor<R, A> {
return null;
}
@override
R visitStaticFunctionIncompatibleInvoke(
Send node,
MethodElement function,
NodeList arguments,
CallStructure callStructure,
A arg) {
apply(arguments, arg);
return null;
}
@override
R visitStaticGetterGet(
Send node,
@ -4354,6 +4385,17 @@ class TraversalSendMixin<R, A> implements SemanticSendVisitor<R, A> {
return null;
}
@override
R visitTopLevelFunctionIncompatibleInvoke(
Send node,
MethodElement function,
NodeList arguments,
CallStructure callStructure,
A arg) {
apply(arguments, arg);
return null;
}
@override
R visitTopLevelGetterGet(
Send node,
@ -4565,7 +4607,7 @@ class TraversalSendMixin<R, A> implements SemanticSendVisitor<R, A> {
}
@override
R errorUnresolvedGet(
R visitUnresolvedGet(
Send node,
Element element,
A arg) {
@ -4573,7 +4615,7 @@ class TraversalSendMixin<R, A> implements SemanticSendVisitor<R, A> {
}
@override
R errorUnresolvedInvoke(
R visitUnresolvedInvoke(
Send node,
Element element,
NodeList arguments,
@ -5377,6 +5419,13 @@ abstract class BaseImplementationOfStaticsMixin<R, A>
CallStructure callStructure,
A arg);
R handleStaticFunctionIncompatibleInvoke(
Send node,
MethodElement function,
NodeList arguments,
CallStructure callStructure,
A arg);
R handleStaticGetterGet(
Send node,
FunctionElement getter,
@ -5503,6 +5552,17 @@ abstract class BaseImplementationOfStaticsMixin<R, A>
node, function, arguments, callStructure, arg);
}
@override
R visitStaticFunctionIncompatibleInvoke(
Send node,
MethodElement function,
NodeList arguments,
CallStructure callStructure,
A arg) {
return handleStaticFunctionIncompatibleInvoke(
node, function, arguments, callStructure, arg);
}
@override
R visitStaticGetterGet(
Send node,
@ -5675,6 +5735,17 @@ abstract class BaseImplementationOfStaticsMixin<R, A>
node, function, arguments, callStructure, arg);
}
@override
R visitTopLevelFunctionIncompatibleInvoke(
Send node,
MethodElement function,
NodeList arguments,
CallStructure callStructure,
A arg) {
return handleStaticFunctionIncompatibleInvoke(
node, function, arguments, callStructure, arg);
}
@override
R visitTopLevelGetterGet(
Send node,

View file

@ -234,12 +234,17 @@ abstract class SendResolverMixin {
case SendStructureKind.SET:
return new SetStructure(semantics, selector);
case SendStructureKind.INVOKE:
if (semantics.kind == AccessKind.SUPER_METHOD) {
// TODO(johnniwinther): Find all statically resolved case that should
// go here (top level, static, local, ...).
if (!selector.callStructure.signatureApplies(semantics.element)) {
return new IncompatibleInvokeStructure(semantics, selector);
}
switch (semantics.kind) {
case AccessKind.STATIC_METHOD:
case AccessKind.SUPER_METHOD:
case AccessKind.TOPLEVEL_METHOD:
// TODO(johnniwinther): Should local function also be handled here?
if (!selector.callStructure.signatureApplies(semantics.element)) {
return new IncompatibleInvokeStructure(semantics, selector);
}
break;
default:
break;
}
return new InvokeStructure(semantics, selector);
case SendStructureKind.UNARY:

View file

@ -333,7 +333,7 @@ class InvokeStructure<R, A> implements SendStructure<R, A> {
callStructure,
arg);
case AccessKind.UNRESOLVED:
return visitor.errorUnresolvedInvoke(
return visitor.visitUnresolvedInvoke(
node,
semantics.element,
node.argumentsNode,
@ -374,6 +374,13 @@ class IncompatibleInvokeStructure<R, A> implements SendStructure<R, A> {
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
case AccessKind.STATIC_METHOD:
return visitor.visitStaticFunctionIncompatibleInvoke(
node,
semantics.element,
node.argumentsNode,
callStructure,
arg);
case AccessKind.SUPER_METHOD:
return visitor.visitSuperMethodIncompatibleInvoke(
node,
@ -381,7 +388,14 @@ class IncompatibleInvokeStructure<R, A> implements SendStructure<R, A> {
node.argumentsNode,
callStructure,
arg);
default:
case AccessKind.TOPLEVEL_METHOD:
return visitor.visitTopLevelFunctionIncompatibleInvoke(
node,
semantics.element,
node.argumentsNode,
callStructure,
arg);
default:
// TODO(johnniwinther): Support more variants of this invoke structure.
break;
}
@ -522,7 +536,7 @@ class GetStructure<R, A> implements SendStructure<R, A> {
semantics.constant,
arg);
case AccessKind.UNRESOLVED:
return visitor.errorUnresolvedGet(
return visitor.visitUnresolvedGet(
node,
semantics.element,
arg);

View file

@ -481,7 +481,7 @@ class ResolvedSemanticDispatcher<R> extends Object
}
@override
R errorUnresolvedGet(
R visitUnresolvedGet(
Send node,
Element element,
ResolvedKindVisitor<R> visitor) {
@ -489,7 +489,7 @@ class ResolvedSemanticDispatcher<R> extends Object
}
@override
R errorUnresolvedInvoke(
R visitUnresolvedInvoke(
Send node,
Element element,
NodeList arguments,

View file

@ -1518,12 +1518,6 @@ class SsaBuilder extends NewResolvedVisitor {
return graph.addConstant(getConstantForNode(node), compiler);
}
bool isLazilyInitialized(VariableElement element) {
ConstantExpression initialValue =
backend.constants.getConstantForVariable(element);
return initialValue == null;
}
TypeMask cachedTypeOfThis;
TypeMask getTypeOfThis() {
@ -3245,94 +3239,121 @@ class SsaBuilder extends NewResolvedVisitor {
}
}
void generateGetter(ast.Send send, Element element) {
if (element != null && element.isForeign(backend)) {
visitForeignGetter(send);
} else if (Elements.isStaticOrTopLevelField(element)) {
ConstantExpression constant;
if (element.isField && !element.isAssignable) {
/// 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>());
} else {
// This happens when [element] has parse errors.
assert(invariant(node, element.isErroneous));
// TODO(ahe): Do something like the above, that is, emit a runtime
// error.
stack.add(graph.addConstantNull(compiler));
}
}
/// Read a static or top level [field] of constant value.
void generateStaticConstGet(
ast.Send node,
FieldElement field,
ConstantExpression constant) {
ConstantValue value = constant.value;
HConstant instruction;
// Constants that are referred via a deferred prefix should be referred
// by reference.
PrefixElement prefix = compiler.deferredLoadTask
.deferredPrefixElement(node, elements);
if (prefix != null) {
instruction = graph.addDeferredConstant(value, prefix, compiler);
} else {
instruction = graph.addConstant(value, compiler);
}
stack.add(instruction);
// The inferrer may have found a better type than the constant
// handler in the case of lists, because the constant handler
// does not look at elements in the list.
TypeMask type =
TypeMaskFactory.inferredTypeForElement(field, compiler);
if (!type.containsAll(compiler.world) &&
!instruction.isConstantNull()) {
// TODO(13429): The inferrer should know that an element
// cannot be null.
instruction.instructionType = type.nonNullable();
}
}
/// Read a static or top level [field].
void generateStaticFieldGet(ast.Send node, FieldElement field) {
generateIsDeferredLoadedCheckIfNeeded(node);
ConstantExpression constant =
backend.constants.getConstantForVariable(field);
if (constant != null) {
if (!field.isAssignable) {
// A static final or const. Get its constant value and inline it if
// the value can be compiled eagerly.
constant = backend.constants.getConstantForVariable(element);
}
if (constant != null) {
ConstantValue value = constant.value;
HConstant instruction;
// Constants that are referred via a deferred prefix should be referred
// by reference.
PrefixElement prefix = compiler.deferredLoadTask
.deferredPrefixElement(send, elements);
if (prefix != null) {
instruction = graph.addDeferredConstant(value, prefix, compiler);
} else {
instruction = graph.addConstant(value, compiler);
}
stack.add(instruction);
// The inferrer may have found a better type than the constant
// handler in the case of lists, because the constant handler
// does not look at elements in the list.
TypeMask type =
TypeMaskFactory.inferredTypeForElement(element, compiler);
if (!type.containsAll(compiler.world) &&
!instruction.isConstantNull()) {
// TODO(13429): The inferrer should know that an element
// cannot be null.
instruction.instructionType = type.nonNullable();
}
} else if (element.isField && isLazilyInitialized(element)) {
HInstruction instruction = new HLazyStatic(
element,
TypeMaskFactory.inferredTypeForElement(element, compiler));
generateStaticConstGet(node, field, constant);
} else {
// TODO(5346): Try to avoid the need for calling [declaration] before
// creating an [HStatic].
HInstruction instruction = new HStatic(
field.declaration,
TypeMaskFactory.inferredTypeForElement(field, compiler));
push(instruction);
} else {
if (element.isGetter) {
pushInvokeStatic(send, element, <HInstruction>[]);
} else {
// TODO(5346): Try to avoid the need for calling [declaration] before
// creating an [HStatic].
HInstruction instruction = new HStatic(
element.declaration,
TypeMaskFactory.inferredTypeForElement(element, compiler));
push(instruction);
}
}
} else if (Elements.isInstanceSend(send, elements)) {
HInstruction receiver = generateInstanceSendReceiver(send);
generateInstanceGetterWithCompiledReceiver(
send, elements.getSelector(send), receiver);
} else if (Elements.isStaticOrTopLevelFunction(element)) {
// TODO(5346): Try to avoid the need for calling [declaration] before
// creating an [HStatic].
push(new HStatic(element.declaration, backend.nonNullType));
// TODO(ahe): This should be registered in codegen.
registry.registerGetOfStaticFunction(element.declaration);
} else if (Elements.isErroneous(element)) {
if (element is ErroneousElement) {
// An erroneous element indicates an unresolved static getter.
generateThrowNoSuchMethod(
send,
noSuchMethodTargetSymbolString(element, 'get'),
argumentNodes: const Link<ast.Node>());
} else {
// TODO(ahe): Do something like the above, that is, emit a runtime
// error.
stack.add(graph.addConstantNull(compiler));
}
} else {
if (send.asSendSet() == null) {
internalError(send, "Unhandled local: $element");
}
// TODO(johnniwinther): Remove this when [generateGetter] is no longer
// called from [visitSendSet] (for compound assignments).
handleLocalGet(element);
HInstruction instruction = new HLazyStatic(
field,
TypeMaskFactory.inferredTypeForElement(field, compiler));
push(instruction);
}
}
/// Generate a getter invocation of the static or top level [getter].
void generateStaticGetterGet(ast.Send node, MethodElement getter) {
if (getter.isDeferredLoaderGetter) {
generateDeferredLoaderGet(node, getter);
} else {
generateIsDeferredLoadedCheckIfNeeded(node);
pushInvokeStatic(node, getter, <HInstruction>[]);
}
}
/// Generate a dynamic getter invocation.
void generateDynamicGet(ast.Send node) {
HInstruction receiver = generateInstanceSendReceiver(node);
generateInstanceGetterWithCompiledReceiver(
node, elements.getSelector(node), receiver);
}
/// Generate a closurization of the static or top level [function].
void generateStaticFunctionGet(ast.Send node, MethodElement function) {
generateIsDeferredLoadedCheckIfNeeded(node);
// TODO(5346): Try to avoid the need for calling [declaration] before
// creating an [HStatic].
push(new HStatic(function.declaration, backend.nonNullType));
// TODO(ahe): This should be registered in codegen.
registry.registerGetOfStaticFunction(function.declaration);
}
/// Read a local variable, function or parameter.
void handleLocalGet(LocalElement local) {
stack.add(localsHandler.readLocal(local));
}
@override
void visitDynamicPropertyGet(
ast.Send node,
ast.Node receiver,
Selector selector,
_) {
generateDynamicGet(node);
}
@override
void visitLocalVariableGet(ast.Send node, LocalVariableElement variable, _) {
handleLocalGet(variable);
@ -3348,6 +3369,62 @@ class SsaBuilder extends NewResolvedVisitor {
handleLocalGet(function);
}
@override
void visitStaticFieldGet(
ast.Send node,
FieldElement field,
_) {
generateStaticFieldGet(node, field);
}
@override
void visitStaticFunctionGet(
ast.Send node,
MethodElement function,
_) {
generateStaticFunctionGet(node, function);
}
@override
void visitStaticGetterGet(
ast.Send node,
FunctionElement getter,
_) {
generateStaticGetterGet(node, getter);
}
@override
void visitThisPropertyGet(
ast.Send node,
Selector selector,
_) {
generateDynamicGet(node);
}
@override
void visitTopLevelFieldGet(
ast.Send node,
FieldElement field,
_) {
generateStaticFieldGet(node, field);
}
@override
void visitTopLevelFunctionGet(
ast.Send node,
MethodElement function,
_) {
generateStaticFunctionGet(node, function);
}
@override
void visitTopLevelGetterGet(
ast.Send node,
FunctionElement getter,
_) {
generateStaticGetterGet(node, getter);
}
void generateInstanceSetterWithCompiledReceiver(ast.Send send,
HInstruction receiver,
HInstruction value,
@ -4014,9 +4091,8 @@ class SsaBuilder extends NewResolvedVisitor {
<HInstruction>[]));
}
visitForeignSend(ast.Send node) {
Selector selector = elements.getSelector(node);
String name = selector.name;
void handleForeignSend(ast.Send node, FunctionElement element) {
String name = element.name;
if (name == 'JS') {
handleForeignJs(node);
} else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') {
@ -4091,15 +4167,13 @@ class SsaBuilder extends NewResolvedVisitor {
} else if (name == 'JS_STRING_CONCAT') {
handleJsStringConcat(node);
} else {
throw "Unknown foreign: ${selector}";
throw "Unknown foreign: ${element}";
}
}
visitForeignGetter(ast.Send node) {
Element element = elements[node];
generateDeferredLoaderGet(ast.Send node, FunctionElement deferredLoader) {
// Until now we only handle these as getters.
invariant(node, element.isDeferredLoaderGetter);
FunctionElement deferredLoader = element;
invariant(node, deferredLoader.isDeferredLoaderGetter);
Element loadFunction = compiler.loadLibraryFunction;
PrefixElement prefixElement = deferredLoader.enclosingElement;
String loadId = compiler.deferredLoadTask
@ -4798,72 +4872,156 @@ class SsaBuilder extends NewResolvedVisitor {
}
assert(invariant(node, node.arguments.tail.isEmpty,
message: "Invalid assertion: $node"));
buildStaticFunctionInvoke(
generateStaticFunctionInvoke(
node, backend.assertMethod, CallStructure.ONE_ARG);
}
visitStaticSend(ast.Send node) {
CallStructure callStructure = elements.getSelector(node).callStructure;
Element element = elements[node];
if (elements.isAssert(node)) {
element = backend.assertMethod;
}
if (element.isForeign(backend) && element.isFunction) {
visitForeignSend(node);
return;
}
if (element.isErroneous) {
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);
} else {
// TODO(ahe): Do something like [generateWrongArgumentCountError].
stack.add(graph.addConstantNull(compiler));
}
return;
}
invariant(element, !element.isGenerativeConstructor);
generateIsDeferredLoadedCheckIfNeeded(node);
if (element.isFunction) {
// TODO(5347): Try to avoid the need for calling [implementation] before
// calling [makeStaticArgumentList].
if (!callStructure.signatureApplies(element.implementation)) {
generateWrongArgumentCountError(node, element, node.arguments);
return;
}
buildStaticFunctionInvoke(node, element, callStructure);
} else {
generateGetter(node, element);
List<HInstruction> inputs = <HInstruction>[pop()];
addDynamicSendArgumentsToList(node, inputs);
Selector closureSelector = callStructure.callSelector;
pushWithPosition(
new HInvokeClosure(closureSelector, inputs, backend.dynamicType),
node);
}
internalError(node, "Unexpected visitStaticSend");
}
void buildStaticFunctionInvoke(
/// Generate an invocation to the static or top level [function].
void generateStaticFunctionInvoke(
ast.Send node,
FunctionElement element,
FunctionElement function,
CallStructure callStructure) {
List<HInstruction> inputs = makeStaticArgumentList(
callStructure,
node.arguments,
element.implementation);
function.implementation);
if (element == compiler.identicalFunction) {
if (function == compiler.identicalFunction) {
pushWithPosition(
new HIdentity(inputs[0], inputs[1], null, backend.boolType), node);
return;
} else {
pushInvokeStatic(node, element, inputs);
pushInvokeStatic(node, function, inputs);
}
}
/// Generate an invocation to a static or top level function with the wrong
/// number of arguments.
void generateStaticFunctionIncompatibleInvoke(ast.Send node,
Element element) {
generateWrongArgumentCountError(node, element, node.arguments);
}
@override
void visitStaticFieldInvoke(
ast.Send node,
FieldElement field,
ast.NodeList arguments,
CallStructure callStructure,
_) {
generateStaticFieldGet(node, field);
generateCallInvoke(node, pop());
}
@override
void visitStaticFunctionInvoke(
ast.Send node,
MethodElement function,
ast.NodeList arguments,
CallStructure callStructure,
_) {
generateStaticFunctionInvoke(node, function, callStructure);
}
@override
void visitStaticFunctionIncompatibleInvoke(
ast.Send node,
MethodElement function,
ast.NodeList arguments,
CallStructure callStructure,
_) {
generateStaticFunctionIncompatibleInvoke(node, function);
}
@override
void visitStaticGetterInvoke(
ast.Send node,
FunctionElement getter,
ast.NodeList arguments,
CallStructure callStructure,
_) {
generateStaticGetterGet(node, getter);
generateCallInvoke(node, pop());
}
@override
void visitTopLevelFieldInvoke(
ast.Send node,
FieldElement field,
ast.NodeList arguments,
CallStructure callStructure,
_) {
generateStaticFieldGet(node, field);
generateCallInvoke(node, pop());
}
@override
void visitTopLevelFunctionInvoke(
ast.Send node,
MethodElement function,
ast.NodeList arguments,
CallStructure callStructure,
_) {
if (function.isForeign(backend)) {
handleForeignSend(node, function);
} else {
generateStaticFunctionInvoke(node, function, callStructure);
}
}
@override
void visitTopLevelFunctionIncompatibleInvoke(
ast.Send node,
MethodElement function,
ast.NodeList arguments,
CallStructure callStructure,
_) {
generateStaticFunctionIncompatibleInvoke(node, function);
}
@override
void visitTopLevelGetterInvoke(
ast.Send node,
FunctionElement getter,
ast.NodeList arguments,
CallStructure callStructure,
_) {
generateStaticGetterGet(node, getter);
generateCallInvoke(node, pop());
}
@override
void visitUnresolvedGet(
ast.Send node,
Element element,
_) {
generateStaticUnresolvedGet(node, element);
}
@override
void visitUnresolvedInvoke(
ast.Send node,
Element element,
ast.NodeList arguments,
Selector selector,
_) {
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);
} else {
// TODO(ahe): Do something like [generateWrongArgumentCountError].
stack.add(graph.addConstantNull(compiler));
}
return;
}
HConstant addConstantString(String string) {
ast.DartString dartString = new ast.DartString.literal(string);
ConstantValue constant = constantSystem.createString(dartString);
@ -4985,8 +5143,7 @@ class SsaBuilder extends NewResolvedVisitor {
}
visitGetterSend(ast.Send node) {
generateIsDeferredLoadedCheckIfNeeded(node);
generateGetter(node, elements[node]);
internalError(node, "Unexpected visitGetterSend");
}
// TODO(antonm): migrate rest of SsaFromAstMixin to internalError.
@ -5390,8 +5547,18 @@ class SsaBuilder extends NewResolvedVisitor {
receiver = generateInstanceSendReceiver(node);
generateInstanceGetterWithCompiledReceiver(
node, elements.getGetterSelectorInComplexSendSet(node), receiver);
} else if (getter.isErroneous) {
generateStaticUnresolvedGet(node, getter);
} else if (getter.isField) {
generateStaticFieldGet(node, getter);
} else if (getter.isGetter) {
generateStaticGetterGet(node, getter);
} else if (getter.isFunction) {
generateStaticFunctionGet(node, getter);
} else if (getter.isLocal) {
handleLocalGet(getter);
} else {
generateGetter(node, getter);
internalError(node, "Unexpected getter: $getter");
}
HInstruction getterInstruction = pop();
handleComplexOperatorSend(node, getterInstruction, node.arguments);

View file

@ -127,6 +127,7 @@ Future<String> compileAll(String code,
trustTypeAnnotations: trustTypeAnnotations,
expectedWarnings: expectedWarnings,
outputProvider: outputCollector);
compiler.diagnosticHandler = createHandler(compiler, code);
return compiler.runCompiler(uri).then((_) {
Expect.isFalse(compiler.compilationFailed,
'Unexpected compilation error(s): ${compiler.errors}');

View file

@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import "package:expect/expect.dart";
import "package:async_helper/async_helper.dart";
import 'compiler_helper.dart';
@ -235,27 +236,31 @@ void main() {
main() {
test(String code, Function f) {
asyncTest(() => compileAll(code, disableInlining: false).then((generated) {
Expect.isTrue(f(generated));
}));
test(String code, String expected) {
return () => compileAll(code, disableInlining: false).then((generated) {
Expect.isTrue(generated.contains(expected),
"Generated code didn't contain '$expected'.\n"
"Test:\n$code, Generated:\n$generated");
});
}
test(TEST_1, (generated) => generated.contains('return 42'));
test(TEST_2, (generated) => generated.contains('return 42'));
test(TEST_3, (generated) => generated.contains('return 84'));
test(TEST_4, (generated) => generated.contains('return t1 + t1'));
test(TEST_5, (generated) => generated.contains('return 84'));
test(TEST_6, (generated) => generated.contains('return 84'));
test(TEST_7, (generated) => generated.contains('return 32'));
test(TEST_8, (generated) => generated.contains('return a.a'));
test(TEST_9, (generated) => generated.contains('return a.a'));
test(TEST_10, (generated) => generated.contains('return 2'));
test(TEST_11, (generated) => generated.contains('return a.a'));
test(TEST_12, (generated) => generated.contains('return 6'));
test(TEST_13, (generated) => generated.contains('return 6'));
test(TEST_14, (generated) => generated.contains('return t1[0]'));
test(TEST_15, (generated) => generated.contains('return 42'));
test(TEST_16, (generated) => generated.contains('return \$.a'));
test(TEST_17, (generated) => generated.contains('return t1'));
test(TEST_18, (generated) => generated.contains('return t1'));
asyncTest(() => Future.forEach([
test(TEST_1, 'return 42'),
test(TEST_2, 'return 42'),
test(TEST_3, 'return 84'),
test(TEST_4, 'return t1 + t1'),
test(TEST_5, 'return 84'),
test(TEST_6, 'return 84'),
test(TEST_7, 'return 32'),
test(TEST_8, 'return a.a'),
test(TEST_9, 'return a.a'),
test(TEST_10, 'return 2'),
test(TEST_11, 'return a.a'),
test(TEST_12, 'return 6'),
test(TEST_13, 'return 6'),
test(TEST_14, 'return t1[0]'),
test(TEST_15, 'return 42'),
test(TEST_16, 'return \$.a'),
test(TEST_17, 'return t1'),
test(TEST_18, 'return t1'),
], (f) => f()));
}

View file

@ -505,6 +505,14 @@ const Map<String, List<Test>> SEND_TESTS = const {
const Visit(VisitKind.VISIT_STATIC_FUNCTION_INVOKE,
element: 'function(C#o)',
arguments: '(null,42)')),
const Test(
'''
class C { static o(a, b) {} }
m() => C.o(null);
''',
const Visit(VisitKind.VISIT_STATIC_FUNCTION_INCOMPATIBLE_INVOKE,
element: 'function(C#o)',
arguments: '(null)')),
],
'Top level fields': const [
// Top level fields
@ -554,6 +562,12 @@ const Map<String, List<Test>> SEND_TESTS = const {
const Visit(VisitKind.VISIT_TOP_LEVEL_FIELD_INVOKE,
element: 'field(o)',
arguments: '(null,42)')),
const Test(
'''
m() => o;
''',
const Visit(VisitKind.VISIT_UNRESOLVED_GET,
name: 'o')),
],
'Top level properties': const [
// Top level properties
@ -623,6 +637,14 @@ const Map<String, List<Test>> SEND_TESTS = const {
const Visit(VisitKind.VISIT_TOP_LEVEL_FUNCTION_INVOKE,
element: 'function(o)',
arguments: '(null,42)')),
const Test(
'''
o(a, b) {}
m() => o(null);
''',
const Visit(VisitKind.VISIT_TOP_LEVEL_FUNCTION_INCOMPATIBLE_INVOKE,
element: 'function(o)',
arguments: '(null)')),
const Test.prefix(
'''
o(a, b) {}
@ -631,6 +653,13 @@ const Map<String, List<Test>> SEND_TESTS = const {
const Visit(VisitKind.VISIT_TOP_LEVEL_FUNCTION_INVOKE,
element: 'function(o)',
arguments: '(null,42)')),
const Test(
'''
m() => o(null, 42);
''',
const Visit(VisitKind.VISIT_UNRESOLVED_INVOKE,
name: 'o',
arguments: '(null,42)')),
],
'Dynamic properties': const [
// Dynamic properties
@ -3640,6 +3669,18 @@ class SemanticSendTestVisitor extends SemanticTestVisitor {
apply(arguments, arg);
}
@override
visitStaticFunctionIncompatibleInvoke(
Send node,
MethodElement function,
NodeList arguments,
CallStructure callStructure,
arg) {
visits.add(new Visit(VisitKind.VISIT_STATIC_FUNCTION_INCOMPATIBLE_INVOKE,
element: function, arguments: arguments));
apply(arguments, arg);
}
@override
visitStaticGetterGet(
Send node,
@ -3828,6 +3869,18 @@ class SemanticSendTestVisitor extends SemanticTestVisitor {
apply(arguments, arg);
}
@override
visitTopLevelFunctionIncompatibleInvoke(
Send node,
MethodElement function,
NodeList arguments,
CallStructure callStructure,
arg) {
visits.add(new Visit(VisitKind.VISIT_TOP_LEVEL_FUNCTION_INCOMPATIBLE_INVOKE,
element: function, arguments: arguments));
apply(arguments, arg);
}
@override
visitTopLevelGetterGet(
Send node,
@ -5065,21 +5118,22 @@ class SemanticSendTestVisitor extends SemanticTestVisitor {
}
@override
errorUnresolvedGet(
visitUnresolvedGet(
Send node,
ErroneousElement element,
Element element,
arg) {
// TODO: implement errorUnresolvedGet
visits.add(new Visit(VisitKind.VISIT_UNRESOLVED_GET, name: element.name));
}
@override
errorUnresolvedInvoke(
visitUnresolvedInvoke(
Send node,
ErroneousElement element,
Element element,
NodeList arguments,
Selector selector,
arg) {
// TODO: implement errorUnresolvedInvoke
visits.add(new Visit(VisitKind.VISIT_UNRESOLVED_INVOKE,
name: element.name, arguments: arguments));
}
@override
@ -6036,6 +6090,7 @@ enum VisitKind {
VISIT_STATIC_FUNCTION_GET,
VISIT_STATIC_FUNCTION_INVOKE,
VISIT_STATIC_FUNCTION_INCOMPATIBLE_INVOKE,
VISIT_STATIC_FUNCTION_DECL,
VISIT_TOP_LEVEL_FIELD_GET,
@ -6058,6 +6113,7 @@ enum VisitKind {
VISIT_TOP_LEVEL_FUNCTION_GET,
VISIT_TOP_LEVEL_FUNCTION_INVOKE,
VISIT_TOP_LEVEL_FUNCTION_INCOMPATIBLE_INVOKE,
VISIT_TOP_LEVEL_FUNCTION_DECL,
VISIT_DYNAMIC_PROPERTY_GET,
@ -6101,6 +6157,8 @@ enum VisitKind {
VISIT_SUPER_METHOD_INVOKE,
VISIT_SUPER_METHOD_INCOMPATIBLE_INVOKE,
VISIT_UNRESOLVED_GET,
VISIT_UNRESOLVED_INVOKE,
VISIT_UNRESOLVED_SUPER_GET,
VISIT_UNRESOLVED_SUPER_INVOKE,