blob: 8a984ed822bb5ef5d10b58bea89a327839930758 [file] [log] [blame]
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE.md file.
import 'package:kernel/ast.dart' as ir;
import "../elements/resolution_types.dart"
show ResolutionDartType, ResolutionInterfaceType;
import "../elements/elements.dart"
show
AstElement,
ConstructorElement,
Element,
ErroneousElement,
FunctionElement,
MethodElement;
import "../resolution/operators.dart"
show AssignmentOperator, BinaryOperator, IncDecOperator, UnaryOperator;
import "../tree/tree.dart" show Expression, NewExpression, Node, NodeList, Send;
import "../universe/call_structure.dart" show CallStructure;
import "../universe/selector.dart" show Selector;
import 'accessors.dart';
import "kernel.dart" show Kernel;
abstract class UnresolvedVisitor {
Kernel get kernel;
// Implemented in KernelVisitor
AstElement get currentElement;
bool get isVoidContext;
ir.Arguments buildArguments(NodeList arguments);
ir.TreeNode visitForValue(Expression node);
void associateCompoundComponents(Accessor accessor, Node node);
// TODO(ahe): Delete this method.
ir.InvalidExpression handleUnresolved(Node node);
/// Similar to [Kernel.functionToIr] but returns null if [function] is a
/// synthetic function created for error recovery.
ir.Member possiblyErroneousFunctionToIr(FunctionElement function) {
return kernel.isSyntheticError(function)
? null
: kernel.functionToIr(function);
}
/// Throws a [NoSuchMethodError] corresponding to a call to
/// [receiver].[memberName] with the arguments [callArguments].
///
/// The exception object is built by calling [exceptionBuilder]. This should
/// take the same arguments as the default constructor to [NoSuchMethodError],
/// but the method itself may encode additional details about the call than
/// is possible through the public interface of NoSuchMethodError.
///
/// Note that [callArguments] are the arguments as they occur in the attempted
/// call in user code -- they are not the arguments to [exceptionBuilder].
///
/// If [candidateTarget] is given, it will provide the expected parameter
/// names.
ir.Expression buildThrowNoSuchMethodError(ir.Procedure exceptionBuilder,
ir.Expression receiver, String memberName, ir.Arguments callArguments,
[Element candidateTarget]) {
ir.Expression memberNameArg =
markSynthetic(new ir.SymbolLiteral(memberName));
ir.Expression positional =
markSynthetic(new ir.ListLiteral(callArguments.positional));
ir.Expression named =
markSynthetic(new ir.MapLiteral(callArguments.named.map((e) {
return new ir.MapEntry(
markSynthetic(new ir.SymbolLiteral(e.name)), e.value);
}).toList()));
if (candidateTarget is FunctionElement) {
// Ensure [candidateTarget] has been resolved.
possiblyErroneousFunctionToIr(candidateTarget);
}
ir.Expression existingArguments;
if (candidateTarget is FunctionElement &&
!kernel.isSyntheticError(candidateTarget) &&
candidateTarget.hasFunctionSignature) {
List<ir.Expression> existingArgumentsList = <ir.Expression>[];
candidateTarget.functionSignature.forEachParameter((param) {
existingArgumentsList
.add(markSynthetic(new ir.StringLiteral(param.name)));
});
existingArguments =
markSynthetic(new ir.ListLiteral(existingArgumentsList));
} else {
existingArguments = new ir.NullLiteral();
}
ir.Expression construction = markSynthetic(new ir.StaticInvocation(
exceptionBuilder,
new ir.Arguments(<ir.Expression>[
receiver,
memberNameArg,
positional,
named,
existingArguments
])));
return new ir.Throw(construction);
}
ir.Expression markSynthetic(ir.Expression expression) {
kernel.syntheticNodes.add(expression);
return expression;
}
/// Throws a NoSuchMethodError for an unresolved getter named [name].
ir.Expression buildThrowUnresolvedGetter(String name,
[ir.Procedure exceptionBuilder]) {
// TODO(asgerf): We should remove this fallback, but in some cases we do
// not get sufficient information to determine exactly what kind of
// getter it is.
exceptionBuilder ??= kernel.getGenericNoSuchMethodBuilder();
return buildThrowNoSuchMethodError(
exceptionBuilder, new ir.NullLiteral(), name, new ir.Arguments.empty());
}
ir.Expression buildThrowUnresolvedSetter(String name, ir.Expression argument,
[ir.Procedure exceptionBuilder]) {
// TODO(asgerf): We should remove this fallback, but in some cases we do
// not get sufficient information to determine exactly what kind of
// setter it is.
exceptionBuilder ??= kernel.getGenericNoSuchMethodBuilder();
return buildThrowNoSuchMethodError(exceptionBuilder, new ir.NullLiteral(),
name, new ir.Arguments(<ir.Expression>[argument]));
}
ir.Expression buildThrowUnresolvedSuperGetter(String name) {
// TODO(sra): This is incorrect when the superclass defines noSuchMethod.
return buildThrowNoSuchMethodError(kernel.getUnresolvedSuperGetterBuilder(),
new ir.ThisExpression(), name, new ir.Arguments.empty());
}
ir.Expression buildThrowUnresolvedSuperSetter(
String name, ir.Expression argument) {
return buildThrowNoSuchMethodError(
kernel.getUnresolvedSuperSetterBuilder(),
new ir.ThisExpression(),
name,
new ir.Arguments(<ir.Expression>[argument]));
}
ir.Expression buildThrowSingleArgumentError(
ir.Procedure exceptionBuilder, String errorMessage) {
return new ir.Throw(new ir.StaticInvocation(exceptionBuilder,
new ir.Arguments(<ir.Expression>[new ir.StringLiteral(errorMessage)])));
}
SuperIndexAccessor buildUnresolvedSuperIndexAccessor(
Node index, Element element) {
ir.Member member = possiblyErroneousFunctionToIr(element);
return new SuperIndexAccessor(this, visitForValue(index), member, member);
}
SuperPropertyAccessor buildUnresolvedSuperPropertyAccessor(
String name, Element getter) {
return new SuperPropertyAccessor(this, kernel.irName(name, currentElement),
getter == null ? null : possiblyErroneousFunctionToIr(getter), null);
}
ir.Expression visitUnresolvedClassConstructorInvoke(
NewExpression node,
ErroneousElement element,
ResolutionDartType type,
NodeList arguments,
Selector selector,
_) {
// TODO(asgerf): The VM includes source information as part of the error
// message. We could do the same when we add source maps.
return buildThrowSingleArgumentError(
kernel.getMalformedTypeErrorBuilder(), element.message);
}
ir.Expression visitUnresolvedConstructorInvoke(
NewExpression node,
Element constructor,
ResolutionDartType type,
NodeList arguments,
Selector selector,
_) {
ir.Expression receiver = new ir.TypeLiteral(kernel.interfaceTypeToIr(type));
String methodName =
node.send.selector != null ? '${node.send.selector}' : type.name;
return buildThrowNoSuchMethodError(kernel.getUnresolvedConstructorBuilder(),
receiver, methodName, buildArguments(arguments), constructor);
}
ir.Expression visitUnresolvedCompound(
Send node, Element element, AssignmentOperator operator, Node rhs, _) {
return buildThrowUnresolvedGetter('${node.selector}');
}
ir.Expression visitUnresolvedGet(Send node, Element element, _) {
return buildThrowUnresolvedGetter('${node.selector}');
}
ir.Expression visitUnresolvedInvoke(
Send node, Element element, NodeList arguments, Selector selector, _) {
// TODO(asgerf): Should we use a type literal as receiver for unresolved
// static invocations?
return buildThrowNoSuchMethodError(kernel.getGenericNoSuchMethodBuilder(),
new ir.NullLiteral(), element.name, buildArguments(arguments), element);
}
ir.Expression visitUnresolvedPostfix(
Send node, Element element, IncDecOperator operator, _) {
return buildThrowUnresolvedGetter('${node.selector}');
}
ir.Expression visitUnresolvedPrefix(
Send node, Element element, IncDecOperator operator, _) {
return buildThrowUnresolvedGetter('${node.selector}');
}
ir.Expression visitUnresolvedRedirectingFactoryConstructorInvoke(
NewExpression node,
ConstructorElement constructor,
ResolutionInterfaceType type,
NodeList arguments,
CallStructure callStructure,
_) {
// The body of the factory will throw an error.
return new ir.StaticInvocation(
possiblyErroneousFunctionToIr(constructor), buildArguments(arguments));
}
ir.Expression visitUnresolvedSet(Send node, Element element, Node rhs, _) {
return buildThrowUnresolvedSetter('${node.selector}', visitForValue(rhs));
}
ir.Expression visitUnresolvedSetIfNull(
Send node, Element element, Node rhs, _) {
return buildThrowUnresolvedGetter('${node.selector}');
}
ir.Expression visitUnresolvedStaticGetterCompound(Send node, Element element,
MethodElement setter, AssignmentOperator operator, Node rhs, _) {
return buildThrowUnresolvedGetter(
'${node.selector}', kernel.getUnresolvedStaticGetterBuilder());
}
ir.Expression visitUnresolvedStaticGetterPostfix(Send node, Element element,
MethodElement setter, IncDecOperator operator, _) {
return buildThrowUnresolvedGetter(
'${node.selector}', kernel.getUnresolvedStaticGetterBuilder());
}
ir.Expression visitUnresolvedStaticGetterPrefix(Send node, Element element,
MethodElement setter, IncDecOperator operator, _) {
return buildThrowUnresolvedGetter(
'${node.selector}', kernel.getUnresolvedStaticGetterBuilder());
}
ir.Expression visitUnresolvedStaticGetterSetIfNull(
Send node, Element element, MethodElement setter, Node rhs, _) {
return buildThrowUnresolvedGetter(
'${node.selector}', kernel.getUnresolvedStaticGetterBuilder());
}
ir.Expression visitUnresolvedStaticSetterCompound(
Send node,
MethodElement getter,
Element element,
AssignmentOperator operator,
Node rhs,
_) {
return buildThrowUnresolvedSetter('${node.selector}', visitForValue(rhs),
kernel.getUnresolvedStaticSetterBuilder());
}
ir.Expression visitUnresolvedStaticSetterPostfix(Send node,
MethodElement getter, Element element, IncDecOperator operator, _) {
var accessor = new ClassStaticAccessor(
this, getter.name, possiblyErroneousFunctionToIr(getter), null);
var result = accessor.buildPostfixIncrement(
new ir.Name(operator.selectorName),
voidContext: isVoidContext);
associateCompoundComponents(accessor, node);
return result;
}
ir.Expression visitUnresolvedStaticSetterPrefix(Send node,
MethodElement getter, Element element, IncDecOperator operator, _) {
var accessor = new ClassStaticAccessor(
this, getter.name, possiblyErroneousFunctionToIr(getter), null);
var result = accessor.buildPrefixIncrement(
new ir.Name(operator.selectorName),
voidContext: isVoidContext);
associateCompoundComponents(accessor, node);
return result;
}
ir.Expression visitUnresolvedStaticSetterSetIfNull(
Send node, MethodElement getter, Element element, Node rhs, _) {
var accessor = new ClassStaticAccessor(
this, getter.name, possiblyErroneousFunctionToIr(getter), null);
return accessor.buildNullAwareAssignment(visitForValue(rhs), null,
voidContext: isVoidContext);
}
ir.Expression visitUnresolvedSuperBinary(
Send node, Element element, BinaryOperator operator, Node argument, _) {
// TODO(sra): This is incorrect when the superclass defines noSuchMethod.
return buildThrowNoSuchMethodError(
kernel.getUnresolvedSuperMethodBuilder(),
new ir.ThisExpression(),
operator.selectorName,
new ir.Arguments(<ir.Expression>[visitForValue(argument)]));
}
ir.Expression visitUnresolvedSuperCompound(
Send node, Element element, AssignmentOperator operator, Node rhs, _) {
return buildThrowUnresolvedSuperGetter('${node.selector}');
}
ir.Expression visitUnresolvedSuperCompoundIndexSet(Send node, Element element,
Node index, AssignmentOperator operator, Node rhs, _) {
return buildUnresolvedSuperIndexAccessor(index, element)
.buildCompoundAssignment(
new ir.Name(operator.selectorName), visitForValue(rhs));
}
ir.Expression visitUnresolvedSuperGet(Send node, Element element, _) {
return buildThrowUnresolvedSuperGetter('${node.selector}');
}
ir.Expression visitUnresolvedSuperGetterCompound(Send node, Element element,
MethodElement setter, AssignmentOperator operator, Node rhs, _) {
return buildThrowUnresolvedSuperGetter('${node.selector}');
}
ir.Expression visitUnresolvedSuperGetterCompoundIndexSet(
Send node,
Element element,
MethodElement setter,
Node index,
AssignmentOperator operator,
Node rhs,
_) {
return buildThrowUnresolvedSuperGetter('${node.selector}');
}
ir.Expression visitUnresolvedSuperGetterIndexPostfix(
Send node,
Element element,
MethodElement setter,
Node index,
IncDecOperator operator,
_) {
return buildThrowUnresolvedSuperGetter('${node.selector}');
}
ir.Expression visitUnresolvedSuperGetterIndexPrefix(
Send node,
Element element,
MethodElement setter,
Node index,
IncDecOperator operator,
_) {
return buildThrowUnresolvedSuperGetter('${node.selector}');
}
ir.Expression visitUnresolvedSuperGetterPostfix(Send node, Element element,
MethodElement setter, IncDecOperator operator, _) {
return buildThrowUnresolvedSuperGetter('${node.selector}');
}
ir.Expression visitUnresolvedSuperGetterPrefix(Send node, Element element,
MethodElement setter, IncDecOperator operator, _) {
return buildThrowUnresolvedSuperGetter('${node.selector}');
}
ir.Expression visitUnresolvedSuperGetterSetIfNull(
Send node, Element element, MethodElement setter, Node rhs, _) {
return buildThrowUnresolvedSuperGetter('${node.selector}');
}
ir.Expression visitUnresolvedSuperIndex(
Send node, Element element, Node index, _) {
return buildUnresolvedSuperIndexAccessor(index, element).buildSimpleRead();
}
ir.Expression visitUnresolvedSuperIndexPostfix(
Send node, Element element, Node index, IncDecOperator operator, _) {
return buildUnresolvedSuperIndexAccessor(index, element).buildSimpleRead();
}
ir.Expression visitUnresolvedSuperIndexPrefix(
Send node, Element element, Node index, IncDecOperator operator, _) {
return buildUnresolvedSuperIndexAccessor(index, element).buildSimpleRead();
}
ir.Expression visitUnresolvedSuperIndexSet(
Send node, Element element, Node index, Node rhs, _) {
return buildUnresolvedSuperIndexAccessor(index, element)
.buildAssignment(visitForValue(rhs));
}
ir.Expression visitUnresolvedSuperInvoke(
Send node, Element element, NodeList arguments, Selector selector, _) {
// TODO(asgerf): Should really invoke 'super.noSuchMethod'.
return buildThrowNoSuchMethodError(kernel.getUnresolvedSuperMethodBuilder(),
new ir.ThisExpression(), '${node.selector}', buildArguments(arguments));
}
ir.Expression visitUnresolvedSuperPostfix(
Send node, Element element, IncDecOperator operator, _) {
return buildThrowUnresolvedSuperGetter('${node.selector}');
}
ir.Expression visitUnresolvedSuperPrefix(
Send node, Element element, IncDecOperator operator, _) {
return buildThrowUnresolvedSuperGetter('${node.selector}');
}
ir.Expression visitUnresolvedSuperSetIfNull(
Send node, Element element, Node rhs, _) {
return buildThrowUnresolvedSuperGetter('${node.selector}');
}
ir.Expression visitUnresolvedSuperSetterCompound(
Send node,
MethodElement getter,
Element element,
AssignmentOperator operator,
Node rhs,
_) {
return buildUnresolvedSuperPropertyAccessor('${node.selector}', getter)
.buildCompoundAssignment(
new ir.Name(operator.selectorName), visitForValue(rhs));
}
ir.Expression visitUnresolvedSuperSetterCompoundIndexSet(
Send node,
MethodElement getter,
Element element,
Node index,
AssignmentOperator operator,
Node rhs,
_) {
return buildUnresolvedSuperIndexAccessor(index, element)
.buildCompoundAssignment(
new ir.Name(operator.selectorName), visitForValue(rhs));
}
ir.Expression visitUnresolvedSuperSetterIndexPostfix(
Send node,
MethodElement indexFunction,
Element element,
Node index,
IncDecOperator operator,
_) {
return buildUnresolvedSuperIndexAccessor(index, element)
.buildPostfixIncrement(new ir.Name(operator.selectorName));
}
ir.Expression visitUnresolvedSuperSetterIndexPrefix(
Send node,
MethodElement indexFunction,
Element element,
Node index,
IncDecOperator operator,
_) {
return buildUnresolvedSuperIndexAccessor(index, element)
.buildPrefixIncrement(new ir.Name(operator.selectorName));
}
ir.Expression visitUnresolvedSuperSetterPostfix(Send node,
MethodElement getter, Element element, IncDecOperator operator, _) {
return buildUnresolvedSuperPropertyAccessor('${node.selector}', getter)
.buildPostfixIncrement(new ir.Name(operator.selectorName));
}
ir.Expression visitUnresolvedSuperSetterPrefix(Send node,
MethodElement getter, Element element, IncDecOperator operator, _) {
return buildUnresolvedSuperPropertyAccessor('${node.selector}', getter)
.buildPrefixIncrement(new ir.Name(operator.selectorName));
}
ir.Expression visitUnresolvedSuperSetterSetIfNull(
Send node, MethodElement getter, Element element, Node rhs, _) {
return buildUnresolvedSuperPropertyAccessor('${node.selector}', getter)
.buildNullAwareAssignment(visitForValue(rhs), null);
}
ir.Expression visitUnresolvedSuperUnary(
Send node, UnaryOperator operator, Element element, _) {
// TODO(asgerf): Should really call 'super.noSuchMethod'.
return buildThrowNoSuchMethodError(
kernel.getUnresolvedSuperMethodBuilder(),
new ir.ThisExpression(),
operator.selectorName,
new ir.Arguments.empty());
}
ir.Expression visitUnresolvedTopLevelGetterCompound(
Send node,
Element element,
MethodElement setter,
AssignmentOperator operator,
Node rhs,
_) {
return buildThrowUnresolvedGetter(
'${node.selector}', kernel.getUnresolvedTopLevelGetterBuilder());
}
ir.Expression visitUnresolvedTopLevelGetterPostfix(Send node, Element element,
MethodElement setter, IncDecOperator operator, _) {
return buildThrowUnresolvedGetter(
'${node.selector}', kernel.getUnresolvedTopLevelGetterBuilder());
}
ir.Expression visitUnresolvedTopLevelGetterPrefix(Send node, Element element,
MethodElement setter, IncDecOperator operator, _) {
return buildThrowUnresolvedGetter(
'${node.selector}', kernel.getUnresolvedTopLevelGetterBuilder());
}
ir.Expression visitUnresolvedTopLevelGetterSetIfNull(
Send node, Element element, MethodElement setter, Node rhs, _) {
return buildThrowUnresolvedGetter(
'${node.selector}', kernel.getUnresolvedTopLevelGetterBuilder());
}
ir.Expression visitUnresolvedTopLevelSetterCompound(
Send node,
MethodElement getter,
Element element,
AssignmentOperator operator,
Node rhs,
_) {
var accessor = new TopLevelStaticAccessor(
this, getter.name, possiblyErroneousFunctionToIr(getter), null);
var result = accessor.buildCompoundAssignment(
new ir.Name(operator.selectorName), visitForValue(rhs),
voidContext: isVoidContext);
associateCompoundComponents(accessor, node);
return result;
}
ir.Expression visitUnresolvedTopLevelSetterPostfix(Send node,
MethodElement getter, Element element, IncDecOperator operator, _) {
var accessor = new TopLevelStaticAccessor(
this, getter.name, possiblyErroneousFunctionToIr(getter), null);
var result = accessor.buildPostfixIncrement(
new ir.Name(operator.selectorName),
voidContext: isVoidContext);
associateCompoundComponents(accessor, node);
return result;
}
ir.Expression visitUnresolvedTopLevelSetterPrefix(Send node,
MethodElement getter, Element element, IncDecOperator operator, _) {
var accessor = new TopLevelStaticAccessor(
this, getter.name, possiblyErroneousFunctionToIr(getter), null);
var result = accessor.buildPrefixIncrement(
new ir.Name(operator.selectorName),
voidContext: isVoidContext);
associateCompoundComponents(accessor, node);
return result;
}
ir.Expression visitUnresolvedTopLevelSetterSetIfNull(
Send node, MethodElement getter, Element element, Node rhs, _) {
var accessor = new TopLevelStaticAccessor(
this, getter.name, possiblyErroneousFunctionToIr(getter), null);
return accessor.buildNullAwareAssignment(visitForValue(rhs), null,
voidContext: isVoidContext);
}
ir.Expression visitUnresolvedSuperGetterIndexSetIfNull(Send node,
Element element, MethodElement setter, Node index, Node rhs, _) {
return buildUnresolvedSuperIndexAccessor(index, element)
.buildNullAwareAssignment(visitForValue(rhs), null);
}
ir.Expression visitUnresolvedSuperSetterIndexSetIfNull(Send node,
MethodElement getter, Element element, Node index, Node rhs, _) {
return buildUnresolvedSuperIndexAccessor(index, element)
.buildNullAwareAssignment(visitForValue(rhs), null);
}
ir.Expression visitUnresolvedSuperIndexSetIfNull(
Send node, Element element, Node index, Node rhs, _) {
return buildUnresolvedSuperIndexAccessor(index, element)
.buildNullAwareAssignment(visitForValue(rhs), null);
}
ir.Expression visitUnresolvedSuperSet(
Send node, Element element, Node rhs, _) {
return buildThrowUnresolvedSuperSetter(
'${node.selector}', visitForValue(rhs));
}
}