blob: f9d46c35715f31032d79f5910e703a76997bdafb [file] [log] [blame]
// Copyright (c) 2014, 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 kernel.deferred_load_data;
import 'package:kernel/ast.dart' as ir;
import '../compiler.dart' show Compiler;
import '../common_elements.dart';
import '../constants/values.dart' show ConstantValue;
import '../deferred_load.dart';
import '../elements/entities.dart';
import 'element_map.dart';
class KernelDeferredLoadTask extends DeferredLoadTask {
KernelToElementMapForImpact _elementMap;
Map<ir.Library, Set<ir.NamedNode>> _additionalExportsSets =
<ir.Library, Set<ir.NamedNode>>{};
KernelDeferredLoadTask(Compiler compiler, this._elementMap) : super(compiler);
@override
Iterable<ImportEntity> importsTo(Entity element, LibraryEntity library) {
ir.NamedNode node;
String nodeName;
ir.Library enclosingLibrary;
if (element is ClassEntity) {
ClassDefinition definition = _elementMap.getClassDefinition(element);
if (definition.kind != ClassKind.regular) {
// You can't import closures.
return const <ImportEntity>[];
}
ir.Class _node = definition.node;
nodeName = _node.name;
enclosingLibrary = _node.enclosingLibrary;
node = _node;
} else if (element is MemberEntity) {
ir.Member _node = _elementMap.getMemberDefinition(element).node;
nodeName = _node.name.name;
enclosingLibrary = _node.enclosingLibrary;
node = _node;
} else if (element is Local ||
element is LibraryEntity ||
element is TypeVariableEntity) {
return const <ImportEntity>[];
} else if (element is TypedefEntity) {
throw new UnimplementedError("KernelDeferredLoadTask.importsTo typedef");
} else {
throw new UnsupportedError(
"KernelDeferredLoadTask.importsTo unexpected entity type: "
"${element.runtimeType}");
}
List<ImportEntity> imports = [];
ir.Library source = _elementMap.getLibraryNode(library);
for (ir.LibraryDependency dependency in source.dependencies) {
if (dependency.isExport) continue;
if (!_isVisible(dependency.combinators, nodeName)) continue;
if (enclosingLibrary == dependency.targetLibrary ||
additionalExports(dependency.targetLibrary).contains(node)) {
imports.add(_elementMap.getImport(dependency));
}
}
return imports;
}
@override
void checkForDeferredErrorCases(LibraryEntity library) {
// Nothing to do. The FE checks for error cases upfront.
}
@override
void collectConstantsFromMetadata(
Entity element, Set<ConstantValue> constants) {
// Nothing to do. Kernel-pipeline doesn't support mirrors, so we don't need
// to track any constants from meta-data.
}
@override
void collectConstantsInBody(
covariant MemberEntity element, Set<ConstantValue> constants) {
ir.Member node = _elementMap.getMemberDefinition(element).node;
// Fetch the internal node in order to skip annotations on the member.
// TODO(sigmund): replace this pattern when the kernel-ast provides a better
// way to skip annotations (issue 31565).
var visitor = new ConstantCollector(_elementMap, constants);
if (node is ir.Field) {
node.initializer?.accept(visitor);
return;
}
if (node is ir.Constructor) {
node.initializers.forEach((i) => i.accept(visitor));
}
node.function?.accept(visitor);
}
/// Adds extra dependencies coming from mirror usage.
@override
void addDeferredMirrorElements(WorkQueue queue) {
throw new UnsupportedError(
"KernelDeferredLoadTask.addDeferredMirrorElements");
}
/// Add extra dependencies coming from mirror usage in [root] marking it with
/// [newSet].
@override
void addMirrorElementsForLibrary(
WorkQueue queue, LibraryEntity root, ImportSet newSet) {
throw new UnsupportedError(
"KernelDeferredLoadTask.addMirrorElementsForLibrary");
}
Set<ir.NamedNode> additionalExports(ir.Library library) {
return _additionalExportsSets[library] ??= new Set<ir.NamedNode>.from(
library.additionalExports.map((ir.Reference ref) => ref.node));
}
@override
void cleanup() {
_additionalExportsSets = null;
}
}
/// Returns whether [name] would be visible according to the given list of
/// show/hide [combinators].
bool _isVisible(List<ir.Combinator> combinators, String name) {
for (var c in combinators) {
if (c.isShow && !c.names.contains(name)) return false;
if (c.isHide && c.names.contains(name)) return false;
}
return true;
}
class ConstantCollector extends ir.RecursiveVisitor {
final KernelToElementMapForImpact elementMap;
final Set<ConstantValue> constants;
ConstantCollector(this.elementMap, this.constants);
CommonElements get commonElements => elementMap.commonElements;
void add(ir.Expression node) =>
constants.add(elementMap.getConstantValue(node));
@override
void visitIntLiteral(ir.IntLiteral literal) {}
@override
void visitDoubleLiteral(ir.DoubleLiteral literal) {}
@override
void visitBoolLiteral(ir.BoolLiteral literal) {}
@override
void visitStringLiteral(ir.StringLiteral literal) {}
@override
void visitSymbolLiteral(ir.SymbolLiteral literal) => add(literal);
@override
void visitNullLiteral(ir.NullLiteral literal) {}
@override
void visitListLiteral(ir.ListLiteral literal) {
if (literal.isConst) {
add(literal);
} else {
super.visitListLiteral(literal);
}
}
@override
void visitMapLiteral(ir.MapLiteral literal) {
if (literal.isConst) {
add(literal);
} else {
super.visitMapLiteral(literal);
}
}
@override
void visitConstructorInvocation(ir.ConstructorInvocation node) {
if (node.isConst) {
add(node);
} else {
super.visitConstructorInvocation(node);
}
}
@override
void visitFunctionDeclaration(ir.FunctionDeclaration node) {
// Do not recurse - closures are visited separately.
}
@override
void visitFunctionExpression(ir.FunctionExpression node) {
// Do not recurse - closures are visited separately.
}
@override
void visitTypeLiteral(ir.TypeLiteral node) {
if (node.type is! ir.TypeParameterType) add(node);
}
}