blob: d53d4ec3ba7e5769622a82a46c94611f6f714bf0 [file] [log] [blame]
// Copyright (c) 2015, 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 file.
library dart2js.semantics_visitor.resolver;
import '../common.dart';
import '../constants/expressions.dart';
import '../dart_types.dart';
import '../elements/elements.dart';
import '../tree/tree.dart';
import 'semantic_visitor.dart';
import 'send_structure.dart';
import 'tree_elements.dart';
abstract class DeclStructure<R, A> {
final FunctionElement element;
DeclStructure(this.element);
/// Calls the matching visit method on [visitor] with [node] and [arg].
R dispatch(
SemanticDeclarationVisitor<R, A> visitor, FunctionExpression node, A arg);
}
enum ConstructorKind {
GENERATIVE,
REDIRECTING_GENERATIVE,
FACTORY,
REDIRECTING_FACTORY,
}
class ConstructorDeclStructure<R, A> extends DeclStructure<R, A> {
final ConstructorKind kind;
ConstructorDeclStructure(this.kind, ConstructorElement constructor)
: super(constructor);
R dispatch(SemanticDeclarationVisitor<R, A> visitor, FunctionExpression node,
A arg) {
switch (kind) {
case ConstructorKind.GENERATIVE:
return visitor.visitGenerativeConstructorDeclaration(
node, element, node.parameters, node.initializers, node.body, arg);
case ConstructorKind.REDIRECTING_GENERATIVE:
return visitor.visitRedirectingGenerativeConstructorDeclaration(
node, element, node.parameters, node.initializers, arg);
case ConstructorKind.FACTORY:
return visitor.visitFactoryConstructorDeclaration(
node, element, node.parameters, node.body, arg);
default:
break;
}
throw new SpannableAssertionFailure(
node, "Unhandled constructor declaration kind: ${kind}");
}
}
class RedirectingFactoryConstructorDeclStructure<R, A>
extends DeclStructure<R, A> {
InterfaceType redirectionTargetType;
ConstructorElement redirectionTarget;
RedirectingFactoryConstructorDeclStructure(ConstructorElement constructor,
this.redirectionTargetType, this.redirectionTarget)
: super(constructor);
R dispatch(SemanticDeclarationVisitor<R, A> visitor, FunctionExpression node,
A arg) {
return visitor.visitRedirectingFactoryConstructorDeclaration(node, element,
node.parameters, redirectionTargetType, redirectionTarget, arg);
}
}
enum FunctionKind {
TOP_LEVEL_GETTER,
TOP_LEVEL_SETTER,
TOP_LEVEL_FUNCTION,
STATIC_GETTER,
STATIC_SETTER,
STATIC_FUNCTION,
ABSTRACT_GETTER,
ABSTRACT_SETTER,
ABSTRACT_METHOD,
INSTANCE_GETTER,
INSTANCE_SETTER,
INSTANCE_METHOD,
LOCAL_FUNCTION,
CLOSURE,
}
class FunctionDeclStructure<R, A> extends DeclStructure<R, A> {
final FunctionKind kind;
FunctionDeclStructure(this.kind, FunctionElement function) : super(function);
R dispatch(SemanticDeclarationVisitor<R, A> visitor, FunctionExpression node,
A arg) {
switch (kind) {
case FunctionKind.TOP_LEVEL_GETTER:
return visitor.visitTopLevelGetterDeclaration(
node, element, node.body, arg);
case FunctionKind.TOP_LEVEL_SETTER:
return visitor.visitTopLevelSetterDeclaration(
node, element, node.parameters, node.body, arg);
case FunctionKind.TOP_LEVEL_FUNCTION:
return visitor.visitTopLevelFunctionDeclaration(
node, element, node.parameters, node.body, arg);
case FunctionKind.STATIC_GETTER:
return visitor.visitStaticGetterDeclaration(
node, element, node.body, arg);
case FunctionKind.STATIC_SETTER:
return visitor.visitStaticSetterDeclaration(
node, element, node.parameters, node.body, arg);
case FunctionKind.STATIC_FUNCTION:
return visitor.visitStaticFunctionDeclaration(
node, element, node.parameters, node.body, arg);
case FunctionKind.ABSTRACT_GETTER:
return visitor.visitAbstractGetterDeclaration(node, element, arg);
case FunctionKind.ABSTRACT_SETTER:
return visitor.visitAbstractSetterDeclaration(
node, element, node.parameters, arg);
case FunctionKind.ABSTRACT_METHOD:
return visitor.visitAbstractMethodDeclaration(
node, element, node.parameters, arg);
case FunctionKind.INSTANCE_GETTER:
return visitor.visitInstanceGetterDeclaration(
node, element, node.body, arg);
case FunctionKind.INSTANCE_SETTER:
return visitor.visitInstanceSetterDeclaration(
node, element, node.parameters, node.body, arg);
case FunctionKind.INSTANCE_METHOD:
return visitor.visitInstanceMethodDeclaration(
node, element, node.parameters, node.body, arg);
case FunctionKind.LOCAL_FUNCTION:
return visitor.visitLocalFunctionDeclaration(
node, element, node.parameters, node.body, arg);
case FunctionKind.CLOSURE:
return visitor.visitClosureDeclaration(
node, element, node.parameters, node.body, arg);
}
}
}
abstract class DeclarationResolverMixin {
TreeElements get elements;
internalError(Spannable spannable, String message);
ConstructorKind computeConstructorKind(ConstructorElement constructor) {
if (constructor.isRedirectingFactory) {
return ConstructorKind.REDIRECTING_FACTORY;
} else if (constructor.isFactoryConstructor) {
return ConstructorKind.FACTORY;
} else if (constructor.isRedirectingGenerative) {
return ConstructorKind.REDIRECTING_GENERATIVE;
} else {
return ConstructorKind.GENERATIVE;
}
}
DeclStructure computeFunctionStructure(FunctionExpression node) {
FunctionElement element = elements.getFunctionDefinition(node);
if (element.isConstructor) {
ConstructorElement constructor = element;
ConstructorKind kind = computeConstructorKind(constructor);
if (kind == ConstructorKind.REDIRECTING_FACTORY) {
return new RedirectingFactoryConstructorDeclStructure(
constructor,
elements.getType(node.body),
constructor.immediateRedirectionTarget);
} else {
return new ConstructorDeclStructure(kind, element);
}
} else {
FunctionKind kind;
if (element.isLocal) {
if (element.name.isEmpty) {
kind = FunctionKind.CLOSURE;
} else {
kind = FunctionKind.LOCAL_FUNCTION;
}
} else if (element.isInstanceMember) {
if (element.isGetter) {
kind = element.isAbstract
? FunctionKind.ABSTRACT_GETTER
: FunctionKind.INSTANCE_GETTER;
} else if (element.isSetter) {
kind = element.isAbstract
? FunctionKind.ABSTRACT_SETTER
: FunctionKind.INSTANCE_SETTER;
} else {
kind = element.isAbstract
? FunctionKind.ABSTRACT_METHOD
: FunctionKind.INSTANCE_METHOD;
}
} else if (element.isStatic) {
if (element.isGetter) {
kind = FunctionKind.STATIC_GETTER;
} else if (element.isSetter) {
kind = FunctionKind.STATIC_SETTER;
} else {
kind = FunctionKind.STATIC_FUNCTION;
}
} else if (element.isTopLevel) {
if (element.isGetter) {
kind = FunctionKind.TOP_LEVEL_GETTER;
} else if (element.isSetter) {
kind = FunctionKind.TOP_LEVEL_SETTER;
} else {
kind = FunctionKind.TOP_LEVEL_FUNCTION;
}
} else {
return internalError(node, "Unhandled function expression.");
}
return new FunctionDeclStructure(kind, element);
}
}
InitializersStructure computeInitializersStructure(FunctionExpression node) {
List<InitializerStructure> initializers = <InitializerStructure>[];
NodeList list = node.initializers;
bool constructorInvocationSeen = false;
if (list != null) {
for (Node initializer in list) {
InitializerStructure structure =
computeInitializerStructure(initializer);
if (structure.isConstructorInvoke) {
constructorInvocationSeen = true;
}
initializers.add(structure);
}
}
if (!constructorInvocationSeen) {
ConstructorElement currentConstructor = elements[node];
ClassElement currentClass = currentConstructor.enclosingClass;
InterfaceType supertype = currentClass.supertype;
if (supertype != null) {
ClassElement superclass = supertype.element;
ConstructorElement superConstructor =
superclass.lookupDefaultConstructor();
initializers.add(new ImplicitSuperConstructorInvokeStructure(
node, superConstructor, supertype));
}
}
return new InitializersStructure(initializers);
}
InitializerStructure computeInitializerStructure(Send node) {
Element element = elements[node];
if (node.asSendSet() != null) {
return new FieldInitializerStructure(node, element);
} else if (Initializers.isConstructorRedirect(node)) {
return new ThisConstructorInvokeStructure(
node, element, elements.getSelector(node).callStructure);
} else if (Initializers.isSuperConstructorCall(node)) {
return new SuperConstructorInvokeStructure(
node,
element,
elements.analyzedElement.enclosingClass.supertype,
elements.getSelector(node).callStructure);
}
return internalError(node, "Unhandled initializer.");
}
List<ParameterStructure> computeParameterStructures(NodeList parameters) {
List<ParameterStructure> list = <ParameterStructure>[];
int index = 0;
for (Node node in parameters) {
NodeList optionalParameters = node.asNodeList();
if (optionalParameters != null) {
bool isNamed = optionalParameters.beginToken.stringValue == '{';
for (Node node in optionalParameters) {
list.add(computeParameterStructure(node, index++,
isRequired: false, isNamed: isNamed));
}
} else {
list.add(computeParameterStructure(node, index++));
}
}
return list;
}
ParameterStructure computeParameterStructure(
VariableDefinitions definitions, int index,
{bool isRequired: true, bool isNamed: false}) {
Node node = definitions.definitions.nodes.single;
ParameterElement element = elements[node];
if (element == null) {
throw new SpannableAssertionFailure(
node, "No parameter structure for $node.");
}
if (isRequired) {
return new RequiredParameterStructure(definitions, node, element, index);
} else {
// TODO(johnniwinther): Should we differentiate between implicit (null)
// and explicit values? What about optional parameters on redirecting
// factories?
if (isNamed) {
return new NamedParameterStructure(
definitions, node, element, element.constant);
} else {
return new OptionalParameterStructure(
definitions, node, element, element.constant, index);
}
}
}
void computeVariableStructures(VariableDefinitions definitions,
void callback(Node node, VariableStructure structure)) {
for (Node node in definitions.definitions) {
callback(definitions, computeVariableStructure(node));
}
}
VariableStructure computeVariableStructure(Node node) {
VariableElement element = elements[node];
VariableKind kind;
if (element.isLocal) {
kind = VariableKind.LOCAL_VARIABLE;
} else if (element.isInstanceMember) {
kind = VariableKind.INSTANCE_FIELD;
} else if (element.isStatic) {
kind = VariableKind.STATIC_FIELD;
} else if (element.isTopLevel) {
kind = VariableKind.TOP_LEVEL_FIELD;
} else {
return internalError(node, "Unexpected variable $element.");
}
if (element.isConst) {
ConstantExpression constant = elements.getConstant(element.initializer);
return new ConstantVariableStructure(kind, node, element, constant);
} else {
return new NonConstantVariableStructure(kind, node, element);
}
}
}