| // 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 '../common_elements.dart'; |
| import '../compiler.dart' show Compiler; |
| 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, {bool required: true}) { |
| ConstantValue constant = |
| elementMap.getConstantValue(node, requireConstant: required); |
| if (constant != null) { |
| constants.add(constant); |
| } |
| } |
| |
| @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 visitTypeLiteral(ir.TypeLiteral node) { |
| if (node.type is! ir.TypeParameterType) add(node); |
| } |
| |
| @override |
| void visitInstantiation(ir.Instantiation node) { |
| // TODO(johnniwinther): The CFE should mark constant instantiations as |
| // constant. |
| add(node, required: false); |
| } |
| } |