blob: 30f66a53625d9a73e85ef0f75af659f0dfa3b336 [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 file.
import 'package:kernel/ast.dart' as ir;
import '../common.dart';
import '../compiler.dart';
import '../constants/expressions.dart';
import '../dart_types.dart';
import '../elements/elements.dart';
import '../js_backend/backend.dart' show JavaScriptBackend;
import '../kernel/kernel.dart';
import '../kernel/kernel_visitor.dart';
import '../resolution/registry.dart' show ResolutionWorldImpactBuilder;
import '../universe/feature.dart';
import '../universe/use.dart';
import 'kernel_ast_adapter.dart';
import '../common/resolution.dart';
/// Computes the [ResolutionImpact] for [resolvedAst] through kernel.
ResolutionImpact build(Compiler compiler, ResolvedAst resolvedAst) {
AstElement element = resolvedAst.element.implementation;
JavaScriptBackend backend = compiler.backend;
Kernel kernel = backend.kernelTask.kernel;
ir.Procedure function = kernel.functions[element];
if (function == null) {
print("FOUND NULL FUNCTION: $element");
print(kernel.functions);
}
KernelImpactBuilder builder =
new KernelImpactBuilder(function, element, resolvedAst, compiler, kernel);
return builder.build();
}
class KernelImpactBuilder extends ir.Visitor {
final ir.Procedure function;
final FunctionElement functionElement;
final ResolvedAst resolvedAst;
final Compiler compiler;
JavaScriptBackend get backend => compiler.backend;
ResolutionWorldImpactBuilder impactBuilder;
KernelAstAdapter astAdapter;
KernelImpactBuilder(this.function, this.functionElement, this.resolvedAst,
this.compiler, Kernel kernel) {
this.impactBuilder = new ResolutionWorldImpactBuilder('$functionElement');
this.astAdapter = new KernelAstAdapter(
compiler.backend,
resolvedAst,
kernel.nodeToAst,
kernel.nodeToElement,
kernel.functions,
kernel.classes,
kernel.libraries);
}
ResolutionImpact build() {
if (function.kind == ir.ProcedureKind.Method ||
function.kind == ir.ProcedureKind.Operator) {
buildMethod(function);
} else {
compiler.reporter.internalError(
functionElement,
"Unable to compute resolution impact for this kind of Kernel "
"procedure: ${function.kind}");
}
return impactBuilder;
}
/// Add a checked-mode type use of [type] if it is not `dynamic`.
DartType checkType(DartType type) {
if (!type.isDynamic) {
impactBuilder.registerTypeUse(new TypeUse.checkedModeCheck(type));
}
return type;
}
void buildMethod(ir.Procedure method) {
method.function.body.accept(this);
}
void visitNodes(Iterable<ir.Node> nodes) {
nodes.forEach((ir.Node node) => node.accept(this));
}
@override
void visitBlock(ir.Block block) => visitNodes(block.statements);
@override
void visitExpressionStatement(ir.ExpressionStatement exprStatement) {
exprStatement.expression.accept(this);
}
@override
void visitReturnStatement(ir.ReturnStatement returnStatement) {
returnStatement.expression?.accept(this);
}
@override
void visitIfStatement(ir.IfStatement ifStatement) {
ifStatement.condition.accept(this);
ifStatement.then.accept(this);
ifStatement.otherwise?.accept(this);
}
@override
void visitIntLiteral(ir.IntLiteral literal) {
impactBuilder
.registerConstantLiteral(new IntConstantExpression(literal.value));
}
@override
void visitDoubleLiteral(ir.DoubleLiteral literal) {
impactBuilder
.registerConstantLiteral(new DoubleConstantExpression(literal.value));
}
@override
void visitBoolLiteral(ir.BoolLiteral literal) {
impactBuilder
.registerConstantLiteral(new BoolConstantExpression(literal.value));
}
@override
void visitStringLiteral(ir.StringLiteral literal) {
impactBuilder
.registerConstantLiteral(new StringConstantExpression(literal.value));
}
@override
void visitSymbolLiteral(ir.SymbolLiteral literal) {
impactBuilder.registerConstSymbolName(literal.value);
}
@override
void visitNullLiteral(ir.NullLiteral literal) {
impactBuilder.registerConstantLiteral(new NullConstantExpression());
}
@override
void visitListLiteral(ir.ListLiteral literal) {
visitNodes(literal.expressions);
DartType elementType =
checkType(astAdapter.getDartType(literal.typeArgument));
impactBuilder.registerListLiteral(new ListLiteralUse(
compiler.coreTypes.listType(elementType),
isConstant: literal.isConst,
isEmpty: literal.expressions.isEmpty));
}
@override
void visitMapLiteral(ir.MapLiteral literal) {
visitNodes(literal.entries);
DartType keyType = checkType(astAdapter.getDartType(literal.keyType));
DartType valueType = checkType(astAdapter.getDartType(literal.valueType));
impactBuilder.registerMapLiteral(new MapLiteralUse(
compiler.coreTypes.mapType(keyType, valueType),
isConstant: literal.isConst,
isEmpty: literal.entries.isEmpty));
}
void visitMapEntry(ir.MapEntry entry) {
entry.key.accept(this);
entry.value.accept(this);
}
void _visitArguments(ir.Arguments arguments) {
for (ir.Expression argument in arguments.positional) {
argument.accept(this);
}
for (ir.NamedExpression argument in arguments.named) {
argument.value.accept(this);
}
}
@override
void visitStaticInvocation(ir.StaticInvocation invocation) {
_visitArguments(invocation.arguments);
Element target = astAdapter.getElement(invocation.target).declaration;
impactBuilder.registerStaticUse(new StaticUse.staticInvoke(
target, astAdapter.getCallStructure(invocation.arguments)));
}
@override
void visitMethodInvocation(ir.MethodInvocation invocation) {
invocation.receiver.accept(this);
_visitArguments(invocation.arguments);
impactBuilder.registerDynamicUse(
new DynamicUse(astAdapter.getSelector(invocation), null));
}
@override
void visitNot(ir.Not not) {
not.operand.accept(this);
}
}