blob: 6e8e11b81c59eda864aacb73d98e049e3fa281ab [file] [log] [blame]
// Copyright (c) 2017, 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.
import '../common.dart';
import '../common/names.dart';
import '../compiler.dart';
import '../constants/expressions.dart';
import '../constants/values.dart';
import '../elements/elements.dart';
import '../elements/entities.dart';
import '../resolution/tree_elements.dart';
import '../tree/nodes.dart' as ast;
import '../types/types.dart';
import '../world.dart';
import 'builder.dart';
import 'inferrer_engine.dart';
import 'type_graph_nodes.dart';
import 'type_system.dart';
class AstInferrerEngine extends InferrerEngineImpl<ast.Node> {
final Compiler compiler;
AstInferrerEngine(this.compiler, ClosedWorld closedWorld,
ClosedWorldRefiner closedWorldRefiner, FunctionEntity mainElement)
: super(
compiler.options,
compiler.progress,
compiler.reporter,
compiler.outputProvider,
compiler.backend.optimizerHints,
closedWorld,
closedWorldRefiner,
compiler.backend.mirrorsData,
compiler.backend.noSuchMethodRegistry,
mainElement,
const TypeSystemStrategyImpl());
GlobalTypeInferenceElementData<ast.Node> createElementData() =>
new AstGlobalTypeInferenceElementData();
int computeMemberSize(MemberEntity member) => resolveAstApproxSize(member);
ast.Node computeMemberBody(covariant MemberElement member) {
ResolvedAst resolvedAst = member.resolvedAst;
ast.Node body;
if (resolvedAst.kind == ResolvedAstKind.PARSED) {
body = resolvedAst.body;
}
return body;
}
FunctionEntity lookupCallMethod(covariant ClassElement cls) {
MethodElement callMethod = cls.lookupMember(Identifiers.call);
if (callMethod == null) {
callMethod = cls.lookupMember(Identifiers.noSuchMethod_);
}
return callMethod;
}
TypeInformation computeMemberTypeInformation(
MemberEntity member, ast.Node body) {
ElementGraphBuilder visitor =
new ElementGraphBuilder(member, compiler, this);
return visitor.run();
}
bool isFieldInitializerPotentiallyNull(
FieldEntity field, ast.Node initializer) {
dynamic argument = initializer;
// TODO(13429): We could do better here by using the
// constant handler to figure out if it's a lazy field or not.
return argument.asSend() != null ||
(argument.asNewExpression() != null && !argument.isConst);
}
ConstantValue getFieldConstant(covariant FieldElement field) {
ConstantExpression constant = field.constant;
if (constant != null) {
ConstantValue value =
compiler.backend.constants.getConstantValue(constant);
if (value == null) {
assert(
field.isInstanceMember ||
constant.isImplicit ||
constant.isPotential,
failedAt(
field,
"Constant expression without value: "
"${constant.toStructuredText()}."));
}
return value;
}
return null;
}
/// Computes a 'size' of [_element] based on the number of selectors in the
/// associated [TreeElements]. This is used for sorting member for the type
/// inference work-queue.
// TODO(johnniwinther): This is brittle and cannot be translated in the
// kernel based inference. Find a more stable a reproducable size measure.
static int resolveAstApproxSize(_element) {
MemberElement element = _element;
ResolvedAst resolvedAst = element.resolvedAst;
element = element.implementation;
if (resolvedAst.kind == ResolvedAstKind.PARSED) {
TreeElementMapping mapping = resolvedAst.elements;
return mapping.getSelectorCount();
}
return 0;
}
}
class TypeSystemStrategyImpl implements TypeSystemStrategy<ast.Node> {
const TypeSystemStrategyImpl();
@override
MemberTypeInformation createMemberTypeInformation(
covariant MemberElement member) {
assert(member.isDeclaration, failedAt(member));
if (member.isField) {
FieldElement field = member;
return new FieldTypeInformation(field, field.type);
} else if (member.isGetter) {
GetterElement getter = member;
return new GetterTypeInformation(getter, getter.type);
} else if (member.isSetter) {
SetterElement setter = member;
return new SetterTypeInformation(setter);
} else if (member.isFunction) {
MethodElement method = member;
return new MethodTypeInformation(method, method.type);
} else {
ConstructorElement constructor = member;
if (constructor.isFactoryConstructor) {
return new FactoryConstructorTypeInformation(
constructor, constructor.type);
} else {
return new GenerativeConstructorTypeInformation(constructor);
}
}
}
@override
ParameterTypeInformation createParameterTypeInformation(
covariant ParameterElement parameter, TypeSystem<ast.Node> types) {
assert(parameter.isImplementation, failedAt(parameter));
FunctionTypedElement function = parameter.functionDeclaration.declaration;
if (function.isLocal) {
LocalFunctionElement localFunction = function;
MethodElement callMethod = localFunction.callMethod;
return new ParameterTypeInformation.localFunction(
types.getInferredTypeOfMember(callMethod),
parameter,
parameter.type,
callMethod);
} else if (function.isInstanceMember) {
MethodElement method = function;
return new ParameterTypeInformation.instanceMember(
types.getInferredTypeOfMember(method),
parameter,
parameter.type,
method,
new ParameterAssignments());
} else {
MethodElement method = function;
return new ParameterTypeInformation.static(
types.getInferredTypeOfMember(method),
parameter,
parameter.type,
method,
// TODO(johnniwinther): Is this still valid now that initializing
// formals also introduce locals?
isInitializingFormal: parameter.isInitializingFormal);
}
}
@override
void forEachParameter(
covariant MethodElement function, void f(Local parameter)) {
MethodElement impl = function.implementation;
FunctionSignature signature = impl.functionSignature;
signature.forEachParameter((FormalElement _parameter) {
ParameterElement parameter = _parameter;
f(parameter);
});
}
@override
bool checkMapNode(ast.Node node) {
return node is ast.LiteralMap;
}
@override
bool checkListNode(ast.Node node) {
return node is ast.LiteralList || node is ast.Send;
}
@override
bool checkLoopPhiNode(ast.Node node) {
return node is ast.Loop || node is ast.SwitchStatement;
}
@override
bool checkPhiNode(ast.Node node) {
return true;
}
@override
bool checkClassEntity(covariant ClassElement cls) {
return cls.isDeclaration;
}
}