Index: pkg/compiler/lib/src/deferred_load.dart |
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart |
deleted file mode 100644 |
index ae262b7764f8f59e467b5ca0755d744d3678155e..0000000000000000000000000000000000000000 |
--- a/pkg/compiler/lib/src/deferred_load.dart |
+++ /dev/null |
@@ -1,767 +0,0 @@ |
-// 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 deferred_load; |
- |
-import 'constants/expressions.dart'; |
-import 'constants/values.dart' show |
- ConstantValue, |
- ConstructedConstantValue, |
- DeferredConstantValue, |
- StringConstantValue; |
- |
-import 'dart2jslib.dart' show |
- Backend, |
- Compiler, |
- CompilerTask, |
- invariant, |
- MessageKind; |
- |
-import 'dart_backend/dart_backend.dart' show |
- DartBackend; |
- |
-import 'js_backend/js_backend.dart' show |
- JavaScriptBackend; |
- |
-import 'elements/elements.dart' show |
- AstElement, |
- ClassElement, |
- Element, |
- ElementKind, |
- Elements, |
- FunctionElement, |
- LibraryElement, |
- MetadataAnnotation, |
- PrefixElement, |
- ScopeContainerElement, |
- TypedefElement, |
- VoidElement; |
- |
-import 'util/util.dart' show |
- Link, makeUnique; |
- |
-import 'util/setlet.dart' show |
- Setlet; |
- |
-import 'tree/tree.dart' show |
- Import, |
- LibraryTag, |
- LibraryDependency, |
- LiteralDartString, |
- LiteralString, |
- NewExpression, |
- Node; |
- |
-import 'tree/tree.dart' as ast; |
- |
-import 'resolution/resolution.dart' show |
- AnalyzableElementX, |
- TreeElements; |
- |
-/// A "hunk" of the program that will be loaded whenever one of its [imports] |
-/// are loaded. |
-/// |
-/// Elements that are only used in one deferred import, is in an OutputUnit with |
-/// the deferred import as single element in the [imports] set. |
-/// |
-/// Whenever a deferred Element is shared between several deferred imports it is |
-/// in an output unit with those imports in the [imports] Set. |
-/// |
-/// OutputUnits are equal if their [imports] are equal. |
-class OutputUnit { |
- /// The deferred imports that will load this output unit when one of them is |
- /// loaded. |
- final Setlet<Import> imports = new Setlet<Import>(); |
- |
- /// A unique name representing this [OutputUnit]. |
- /// Based on the set of [imports]. |
- String name; |
- |
- String toString() => "OutputUnit($name)"; |
- |
- bool operator==(OutputUnit other) { |
- return imports.length == other.imports.length && |
- imports.containsAll(other.imports); |
- } |
- |
- int get hashCode { |
- int sum = 0; |
- for (Import import in imports) { |
- sum = (sum + import.hashCode) & 0x3FFFFFFF; // Stay in 30 bit range. |
- } |
- return sum; |
- } |
-} |
- |
-/// For each deferred import, find elements and constants to be loaded when that |
-/// import is loaded. Elements that are used by several deferred imports are in |
-/// shared OutputUnits. |
-class DeferredLoadTask extends CompilerTask { |
- /// The name of this task. |
- String get name => 'Deferred Loading'; |
- |
- /// DeferredLibrary from dart:async |
- ClassElement get deferredLibraryClass => compiler.deferredLibraryClass; |
- |
- /// A synthetic [Import] representing the loading of the main |
- /// program. |
- final Import _fakeMainImport = new Import(null, new LiteralString(null, |
- new LiteralDartString("main")), null, null, null); |
- |
- /// The OutputUnit that will be loaded when the program starts. |
- final OutputUnit mainOutputUnit = new OutputUnit(); |
- |
- /// A set containing (eventually) all output units that will result from the |
- /// program. |
- final Set<OutputUnit> allOutputUnits = new Set<OutputUnit>(); |
- |
- /// Will be `true` if the program contains deferred libraries. |
- bool isProgramSplit = false; |
- |
- /// A mapping from the name of a defer import to all the output units it |
- /// depends on in a list of lists to be loaded in the order they appear. |
- /// |
- /// For example {"lib1": [[lib1_lib2_lib3], [lib1_lib2, lib1_lib3], |
- /// [lib1]]} would mean that in order to load "lib1" first the hunk |
- /// lib1_lib2_lib2 should be loaded, then the hunks lib1_lib2 and lib1_lib3 |
- /// can be loaded in parallel. And finally lib1 can be loaded. |
- final Map<String, List<OutputUnit>> hunksToLoad = |
- new Map<String, List<OutputUnit>>(); |
- final Map<Import, String> importDeferName = new Map<Import, String>(); |
- |
- /// A mapping from elements and constants to their output unit. Query this via |
- /// [outputUnitForElement] |
- final Map<Element, OutputUnit> _elementToOutputUnit = |
- new Map<Element, OutputUnit>(); |
- |
- /// A mapping from constants to their output unit. Query this via |
- /// [outputUnitForConstant] |
- final Map<ConstantValue, OutputUnit> _constantToOutputUnit = |
- new Map<ConstantValue, OutputUnit>(); |
- |
- /// All the imports with a [DeferredLibrary] annotation, mapped to the |
- /// [LibraryElement] they import. |
- /// The main library is included in this set for convenience. |
- final Map<Import, LibraryElement> _allDeferredImports = |
- new Map<Import, LibraryElement>(); |
- |
- // For each deferred import we want to know exactly what elements have to |
- // be loaded. |
- Map<Import, Set<Element>> _importedDeferredBy = null; |
- Map<Import, Set<ConstantValue>> _constantsDeferredBy = null; |
- |
- Set<Element> _mainElements = new Set<Element>(); |
- |
- DeferredLoadTask(Compiler compiler) : super(compiler) { |
- mainOutputUnit.imports.add(_fakeMainImport); |
- } |
- |
- Backend get backend => compiler.backend; |
- |
- /// Returns the [OutputUnit] where [element] belongs. |
- OutputUnit outputUnitForElement(Element element) { |
- if (!isProgramSplit) return mainOutputUnit; |
- |
- element = element.implementation; |
- while (!_elementToOutputUnit.containsKey(element)) { |
- // TODO(21051): workaround: it looks like we output annotation constants |
- // for classes that we don't include in the output. This seems to happen |
- // when we have reflection but can see that some classes are not needed. |
- // We still add the annotation but don't run through it below (where we |
- // assign every element to its output unit). |
- if (element.enclosingElement == null) { |
- _elementToOutputUnit[element] = mainOutputUnit; |
- break; |
- } |
- element = element.enclosingElement.implementation; |
- } |
- return _elementToOutputUnit[element]; |
- } |
- |
- /// Returns the [OutputUnit] where [constant] belongs. |
- OutputUnit outputUnitForConstant(ConstantValue constant) { |
- if (!isProgramSplit) return mainOutputUnit; |
- |
- return _constantToOutputUnit[constant]; |
- } |
- |
- bool isDeferred(Element element) { |
- return outputUnitForElement(element) != mainOutputUnit; |
- } |
- |
- /// Returns true if e1 and e2 are in the same output unit. |
- bool inSameOutputUnit(Element e1, Element e2) { |
- return outputUnitForElement(e1) == outputUnitForElement(e2); |
- } |
- |
- void registerConstantDeferredUse(DeferredConstantValue constant, |
- PrefixElement prefix) { |
- OutputUnit outputUnit = new OutputUnit(); |
- outputUnit.imports.add(prefix.deferredImport); |
- _constantToOutputUnit[constant] = outputUnit; |
- } |
- |
- /// Answers whether [element] is explicitly deferred when referred to from |
- /// [library]. |
- bool _isExplicitlyDeferred(Element element, LibraryElement library) { |
- Link<Import> imports = _getImports(element, library); |
- // If the element is not imported explicitly, it is implicitly imported |
- // not deferred. |
- if (imports.isEmpty) return false; |
- // An element could potentially be loaded by several imports. If all of them |
- // is explicitly deferred, we say the element is explicitly deferred. |
- // TODO(sigurdm): We might want to give a warning if the imports do not |
- // agree. |
- return imports.every((Import import) => import.isDeferred); |
- } |
- |
- /// Returns a [Link] of every [Import] that imports [element] into [library]. |
- Link<Import> _getImports(Element element, LibraryElement library) { |
- if (element.isClassMember) { |
- element = element.enclosingClass; |
- } |
- if (element.isAccessor) { |
- element = (element as FunctionElement).abstractField; |
- } |
- return library.getImportsFor(element); |
- } |
- |
- /// Finds all elements and constants that [element] depends directly on. |
- /// (not the transitive closure.) |
- /// |
- /// Adds the results to [elements] and [constants]. |
- void _collectAllElementsAndConstantsResolvedFrom( |
- Element element, |
- Set<Element> elements, |
- Set<ConstantValue> constants, |
- isMirrorUsage) { |
- |
- /// Recursively add the constant and its dependencies to [constants]. |
- void addConstants(ConstantValue constant) { |
- if (constants.contains(constant)) return; |
- constants.add(constant); |
- if (constant is ConstructedConstantValue) { |
- elements.add(constant.type.element); |
- } |
- constant.getDependencies().forEach(addConstants); |
- } |
- |
- /// Collects all direct dependencies of [element]. |
- /// |
- /// The collected dependent elements and constants are are added to |
- /// [elements] and [constants] respectively. |
- void collectDependencies(Element element) { |
- // TODO(johnniwinther): Remove this when [AbstractFieldElement] has been |
- // removed. |
- if (element is! AstElement) return; |
- AstElement astElement = element; |
- |
- // TODO(sigurdm): We want to be more specific about this - need a better |
- // way to query "liveness". |
- if (astElement is! TypedefElement && |
- !compiler.enqueuer.resolution.hasBeenResolved(astElement)) { |
- return; |
- } |
- |
- TreeElements treeElements = astElement.resolvedAst.elements; |
- |
- assert(treeElements != null); |
- |
- for (Element dependency in treeElements.allElements) { |
- if (dependency.isLocal && !dependency.isFunction) continue; |
- if (dependency.isErroneous) continue; |
- if (dependency.isTypeVariable) continue; |
- |
- elements.add(dependency); |
- } |
- treeElements.forEachConstantNode((Node node, _) { |
- // Explicitly depend on the backend constants. |
- addConstants( |
- backend.constants.getConstantForNode(node, treeElements).value); |
- }); |
- elements.addAll(treeElements.otherDependencies); |
- } |
- |
- // TODO(sigurdm): How is metadata on a patch-class handled? |
- for (MetadataAnnotation metadata in element.metadata) { |
- ConstantExpression constant = |
- backend.constants.getConstantForMetadata(metadata); |
- if (constant != null) { |
- addConstants(constant.value); |
- } |
- } |
- if (element.isClass) { |
- // If we see a class, add everything its live instance members refer |
- // to. Static members are not relevant, unless we are processing |
- // extra dependencies due to mirrors. |
- void addLiveInstanceMember(Element element) { |
- if (!compiler.enqueuer.resolution.hasBeenResolved(element)) return; |
- if (!isMirrorUsage && !element.isInstanceMember) return; |
- collectDependencies(element.implementation); |
- } |
- ClassElement cls = element.declaration; |
- cls.forEachLocalMember(addLiveInstanceMember); |
- if (cls.implementation != cls) { |
- // TODO(ahe): Why doesn't ClassElement.forEachLocalMember do this? |
- cls.implementation.forEachLocalMember(addLiveInstanceMember); |
- } |
- for (var type in cls.implementation.allSupertypes) { |
- elements.add(type.element.implementation); |
- } |
- elements.add(cls.implementation); |
- } else if (Elements.isStaticOrTopLevel(element) || |
- element.isConstructor) { |
- collectDependencies(element); |
- } |
- if (element.isGenerativeConstructor) { |
- // When instantiating a class, we record a reference to the |
- // constructor, not the class itself. We must add all the |
- // instance members of the constructor's class. |
- ClassElement implementation = |
- element.enclosingClass.implementation; |
- _collectAllElementsAndConstantsResolvedFrom( |
- implementation, elements, constants, isMirrorUsage); |
- } |
- |
- // Other elements, in particular instance members, are ignored as |
- // they are processed as part of the class. |
- } |
- |
- /// Returns the transitive closure of all libraries that are imported |
- /// from root without DeferredLibrary annotations. |
- Set<LibraryElement> _nonDeferredReachableLibraries(LibraryElement root) { |
- Set<LibraryElement> result = new Set<LibraryElement>(); |
- |
- void traverseLibrary(LibraryElement library) { |
- if (result.contains(library)) return; |
- result.add(library); |
- |
- iterateTags(LibraryElement library) { |
- // TODO(sigurdm): Make helper getLibraryDependencyTags when tags is |
- // changed to be a List instead of a Link. |
- for (LibraryTag tag in library.tags) { |
- if (tag is! LibraryDependency) continue; |
- LibraryDependency libraryDependency = tag; |
- if (!(libraryDependency is Import && libraryDependency.isDeferred)) { |
- LibraryElement importedLibrary = library.getLibraryFromTag(tag); |
- traverseLibrary(importedLibrary); |
- } |
- } |
- } |
- |
- iterateTags(library); |
- if (library.isPatched) { |
- iterateTags(library.implementation); |
- } |
- } |
- traverseLibrary(root); |
- result.add(compiler.coreLibrary); |
- return result; |
- } |
- |
- /// Recursively traverses the graph of dependencies from [element], mapping |
- /// deferred imports to each dependency it needs in the sets |
- /// [_importedDeferredBy] and [_constantsDeferredBy]. |
- void _mapDependencies(Element element, Import import, |
- {isMirrorUsage: false}) { |
- Set<Element> elements = _importedDeferredBy.putIfAbsent(import, |
- () => new Set<Element>()); |
- Set<ConstantValue> constants = _constantsDeferredBy.putIfAbsent(import, |
- () => new Set<ConstantValue>()); |
- |
- // Only process elements once, unless we are doing dependencies due to |
- // mirrors, which are added in additional traversals. |
- if (!isMirrorUsage && elements.contains(element)) return; |
- // Anything used directly by main will be loaded from the start |
- // We do not need to traverse it again. |
- if (import != _fakeMainImport && _mainElements.contains(element)) return; |
- |
- // Here we modify [_importedDeferredBy]. |
- elements.add(element); |
- |
- Set<Element> dependentElements = new Set<Element>(); |
- |
- // This call can modify [_importedDeferredBy] and [_constantsDeferredBy]. |
- _collectAllElementsAndConstantsResolvedFrom( |
- element, dependentElements, constants, isMirrorUsage); |
- |
- LibraryElement library = element.library; |
- for (Element dependency in dependentElements) { |
- if (_isExplicitlyDeferred(dependency, library)) { |
- for (Import deferredImport in _getImports(dependency, library)) { |
- _mapDependencies(dependency, deferredImport); |
- }; |
- } else { |
- _mapDependencies(dependency, import); |
- } |
- } |
- } |
- |
- /// Adds extra dependencies coming from mirror usage. |
- /// |
- /// The elements are added with [_mapDependencies]. |
- void _addMirrorElements() { |
- void mapDependenciesIfResolved(Element element, Import deferredImport) { |
- // If an element is the target of a MirrorsUsed annotation but never used |
- // It will not be resolved, and we should not call isNeededForReflection. |
- // TODO(sigurdm): Unresolved elements should just answer false when |
- // asked isNeededForReflection. Instead an internal error is triggered. |
- // So we have to filter them out here. |
- if (element is AnalyzableElementX && !element.hasTreeElements) return; |
- if (compiler.backend.isAccessibleByReflection(element)) { |
- _mapDependencies(element, deferredImport, isMirrorUsage: true); |
- } |
- } |
- |
- // For each deferred import we analyze all elements reachable from the |
- // imported library through non-deferred imports. |
- handleLibrary(LibraryElement library, Import deferredImport) { |
- library.implementation.forEachLocalMember((Element element) { |
- mapDependenciesIfResolved(element, deferredImport); |
- }); |
- |
- for (MetadataAnnotation metadata in library.metadata) { |
- ConstantExpression constant = |
- backend.constants.getConstantForMetadata(metadata); |
- if (constant != null) { |
- _mapDependencies(constant.value.computeType(compiler).element, |
- deferredImport); |
- } |
- } |
- for (LibraryTag tag in library.tags) { |
- for (MetadataAnnotation metadata in tag.metadata) { |
- ConstantExpression constant = |
- backend.constants.getConstantForMetadata(metadata); |
- if (constant != null) { |
- _mapDependencies(constant.value.computeType(compiler).element, |
- deferredImport); |
- } |
- } |
- } |
- } |
- |
- for (Import deferredImport in _allDeferredImports.keys) { |
- LibraryElement deferredLibrary = _allDeferredImports[deferredImport]; |
- for (LibraryElement library in |
- _nonDeferredReachableLibraries(deferredLibrary)) { |
- handleLibrary(library, deferredImport); |
- } |
- } |
- } |
- |
- /// Computes a unique string for the name field for each outputUnit. |
- /// |
- /// Also sets up the [hunksToLoad] mapping. |
- void _assignNamesToOutputUnits(Set<OutputUnit> allOutputUnits) { |
- Set<String> usedImportNames = new Set<String>(); |
- |
- // Finds the first argument to the [DeferredLibrary] annotation |
- void computeImportDeferName(Import import) { |
- String result; |
- if (import == _fakeMainImport) { |
- result = "main"; |
- } else if (import.isDeferred) { |
- result = import.prefix.toString(); |
- } else { |
- Link<MetadataAnnotation> metadatas = import.metadata; |
- assert(metadatas != null); |
- for (MetadataAnnotation metadata in metadatas) { |
- metadata.ensureResolved(compiler); |
- Element element = |
- metadata.constant.value.computeType(compiler).element; |
- if (element == deferredLibraryClass) { |
- ConstructedConstantValue constant = metadata.constant.value; |
- StringConstantValue s = constant.fields[0]; |
- result = s.primitiveValue.slowToString(); |
- break; |
- } |
- } |
- } |
- assert(result != null); |
- importDeferName[import] = makeUnique(result, usedImportNames);; |
- } |
- |
- int counter = 1; |
- |
- for (Import import in _allDeferredImports.keys) { |
- computeImportDeferName(import); |
- } |
- |
- for (OutputUnit outputUnit in allOutputUnits) { |
- if (outputUnit == mainOutputUnit) { |
- outputUnit.name = "main"; |
- } else { |
- outputUnit.name = "$counter"; |
- ++counter; |
- } |
- } |
- |
- List sortedOutputUnits = new List.from(allOutputUnits); |
- // Sort the output units in descending order of the number of imports they |
- // include. |
- |
- // The loading of the output units mut be ordered because a superclass needs |
- // to be initialized before its subclass. |
- // But a class can only depend on another class in an output unit shared by |
- // a strict superset of the imports: |
- // By contradiction: Assume a class C in output unit shared by imports in |
- // the set S1 = (lib1,.., lib_n) depends on a class D in an output unit |
- // shared by S2 such that S2 not a superset of S1. Let lib_s be a library in |
- // S1 not in S2. lib_s must depend on C, and then in turn on D therefore D |
- // is not in the right output unit. |
- sortedOutputUnits.sort((a, b) => b.imports.length - a.imports.length); |
- |
- // For each deferred import we find out which outputUnits to load. |
- for (Import import in _allDeferredImports.keys) { |
- if (import == _fakeMainImport) continue; |
- hunksToLoad[importDeferName[import]] = new List<OutputUnit>(); |
- for (OutputUnit outputUnit in sortedOutputUnits) { |
- if (outputUnit == mainOutputUnit) continue; |
- if (outputUnit.imports.contains(import)) { |
- hunksToLoad[importDeferName[import]].add(outputUnit); |
- } |
- } |
- } |
- } |
- |
- void onResolutionComplete(FunctionElement main) { |
- if (!isProgramSplit) { |
- allOutputUnits.add(mainOutputUnit); |
- return; |
- } |
- if (main == null) return; |
- LibraryElement mainLibrary = main.library; |
- _importedDeferredBy = new Map<Import, Set<Element>>(); |
- _constantsDeferredBy = new Map<Import, Set<ConstantValue>>(); |
- _importedDeferredBy[_fakeMainImport] = _mainElements; |
- |
- measureElement(mainLibrary, () { |
- |
- // Starting from main, traverse the program and find all dependencies. |
- _mapDependencies(compiler.mainFunction, _fakeMainImport); |
- |
- // Also add "global" dependencies to the main OutputUnit. These are |
- // things that the backend need but cannot associate with a particular |
- // element, for example, startRootIsolate. This set also contains |
- // elements for which we lack precise information. |
- for (Element element in compiler.globalDependencies.otherDependencies) { |
- _mapDependencies(element, _fakeMainImport); |
- } |
- |
- // Now check to see if we have to add more elements due to mirrors. |
- if (compiler.mirrorsLibrary != null) { |
- _addMirrorElements(); |
- } |
- |
- // Build the OutputUnits using these two maps. |
- Map<Element, OutputUnit> elementToOutputUnitBuilder = |
- new Map<Element, OutputUnit>(); |
- Map<ConstantValue, OutputUnit> constantToOutputUnitBuilder = |
- new Map<ConstantValue, OutputUnit>(); |
- |
- // Reverse the mappings. For each element record an OutputUnit collecting |
- // all deferred imports mapped to this element. Same for constants. |
- for (Import import in _importedDeferredBy.keys) { |
- for (Element element in _importedDeferredBy[import]) { |
- // Only one file should be loaded when the program starts, so make |
- // sure that only one OutputUnit is created for [fakeMainImport]. |
- if (import == _fakeMainImport) { |
- elementToOutputUnitBuilder[element] = mainOutputUnit; |
- } else { |
- elementToOutputUnitBuilder |
- .putIfAbsent(element, () => new OutputUnit()) |
- .imports.add(import); |
- } |
- } |
- for (ConstantValue constant in _constantsDeferredBy[import]) { |
- // Only one file should be loaded when the program starts, so make |
- // sure that only one OutputUnit is created for [fakeMainImport]. |
- if (import == _fakeMainImport) { |
- constantToOutputUnitBuilder[constant] = mainOutputUnit; |
- } else { |
- constantToOutputUnitBuilder |
- .putIfAbsent(constant, () => new OutputUnit()) |
- .imports.add(import); |
- } |
- } |
- } |
- |
- // Release maps; |
- _importedDeferredBy = null; |
- _constantsDeferredBy = null; |
- |
- // Find all the output units elements/constants have been mapped to, and |
- // canonicalize them. |
- elementToOutputUnitBuilder.forEach( |
- (Element element, OutputUnit outputUnit) { |
- OutputUnit representative = allOutputUnits.lookup(outputUnit); |
- if (representative == null) { |
- representative = outputUnit; |
- allOutputUnits.add(representative); |
- } |
- _elementToOutputUnit[element] = representative; |
- }); |
- constantToOutputUnitBuilder.forEach( |
- (ConstantValue constant, OutputUnit outputUnit) { |
- OutputUnit representative = allOutputUnits.lookup(outputUnit); |
- if (representative == null) { |
- representative = outputUnit; |
- allOutputUnits.add(representative); |
- } |
- _constantToOutputUnit[constant] = representative; |
- }); |
- |
- // Generate a unique name for each OutputUnit. |
- _assignNamesToOutputUnits(allOutputUnits); |
- }); |
- } |
- |
- void ensureMetadataResolved(Compiler compiler) { |
- if (compiler.mainApp == null) return; |
- _allDeferredImports[_fakeMainImport] = compiler.mainApp; |
- var lastDeferred; |
- // When detecting duplicate prefixes of deferred libraries there are 4 |
- // cases of duplicate prefixes: |
- // 1. |
- // import "lib.dart" deferred as a; |
- // import "lib2.dart" deferred as a; |
- // 2. |
- // import "lib.dart" deferred as a; |
- // import "lib2.dart" as a; |
- // 3. |
- // import "lib.dart" as a; |
- // import "lib2.dart" deferred as a; |
- // 4. |
- // import "lib.dart" as a; |
- // import "lib2.dart" as a; |
- // We must be able to signal error for case 1, 2, 3, but accept case 4. |
- |
- // The prefixes that have been used by any imports in this library. |
- Setlet<String> usedPrefixes = new Setlet<String>(); |
- // The last deferred import we saw with a given prefix (if any). |
- Map<String, Import> prefixDeferredImport = new Map<String, Import>(); |
- for (LibraryElement library in compiler.libraryLoader.libraries) { |
- compiler.withCurrentElement(library, () { |
- prefixDeferredImport.clear(); |
- usedPrefixes.clear(); |
- // TODO(sigurdm): Make helper getLibraryImportTags when tags is a List |
- // instead of a Link. |
- for (LibraryTag tag in library.tags) { |
- if (tag is! Import) continue; |
- Import import = tag; |
- |
- /// Give an error if the old annotation-based syntax has been used. |
- Link<MetadataAnnotation> metadataList = import.metadata; |
- if (metadataList != null) { |
- for (MetadataAnnotation metadata in metadataList) { |
- metadata.ensureResolved(compiler); |
- Element element = |
- metadata.constant.value.computeType(compiler).element; |
- if (element == deferredLibraryClass) { |
- compiler.reportFatalError( |
- import, MessageKind.DEFERRED_OLD_SYNTAX); |
- } |
- } |
- } |
- |
- String prefix = (import.prefix != null) |
- ? import.prefix.toString() |
- : null; |
- // The last import we saw with the same prefix. |
- Import previousDeferredImport = prefixDeferredImport[prefix]; |
- if (import.isDeferred) { |
- _allDeferredImports[import] = library.getLibraryFromTag(import); |
- |
- if (prefix == null) { |
- compiler.reportError(import, |
- MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX); |
- } else { |
- prefixDeferredImport[prefix] = import; |
- } |
- isProgramSplit = true; |
- lastDeferred = import; |
- } |
- if (prefix != null) { |
- if (previousDeferredImport != null || |
- (import.isDeferred && usedPrefixes.contains(prefix))) { |
- Import failingImport = (previousDeferredImport != null) |
- ? previousDeferredImport |
- : import; |
- compiler.reportError(failingImport.prefix, |
- MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX); |
- } |
- usedPrefixes.add(prefix); |
- } |
- } |
- }); |
- } |
- Backend backend = compiler.backend; |
- if (isProgramSplit && backend is JavaScriptBackend) { |
- backend.registerCheckDeferredIsLoaded(compiler.globalDependencies); |
- } |
- if (isProgramSplit && backend is DartBackend) { |
- // TODO(sigurdm): Implement deferred loading for dart2dart. |
- compiler.reportWarning( |
- lastDeferred, |
- MessageKind.DEFERRED_LIBRARY_DART_2_DART); |
- isProgramSplit = false; |
- } |
- } |
- |
- /// If [send] is a static send with a deferred element, returns the |
- /// [PrefixElement] that the first prefix of the send resolves to. |
- /// Otherwise returns null. |
- /// |
- /// Precondition: send must be static. |
- /// |
- /// Example: |
- /// |
- /// import "a.dart" deferred as a; |
- /// |
- /// main() { |
- /// print(a.loadLibrary.toString()); |
- /// a.loadLibrary().then((_) { |
- /// a.run(); |
- /// a.foo.method(); |
- /// }); |
- /// } |
- /// |
- /// Returns null for a.loadLibrary() (the special |
- /// function loadLibrary is not deferred). And returns the PrefixElement for |
- /// a.run() and a.foo. |
- /// a.loadLibrary.toString() and a.foo.method() are dynamic sends - and |
- /// this functions should not be called on them. |
- PrefixElement deferredPrefixElement(ast.Send send, TreeElements elements) { |
- Element element = elements[send]; |
- // The DeferredLoaderGetter is not deferred, therefore we do not return the |
- // prefix. |
- if (element != null && element.isDeferredLoaderGetter) return null; |
- |
- ast.Node firstNode(ast.Node node) { |
- if (node is! ast.Send) { |
- return node; |
- } else { |
- ast.Send send = node; |
- ast.Node receiver = send.receiver; |
- ast.Node receiverFirst = firstNode(receiver); |
- if (receiverFirst != null) { |
- return receiverFirst; |
- } else { |
- return firstNode(send.selector); |
- } |
- } |
- } |
- ast.Node first = firstNode(send); |
- ast.Node identifier = first.asIdentifier(); |
- if (identifier == null) return null; |
- Element maybePrefix = elements[identifier]; |
- if (maybePrefix != null && maybePrefix.isPrefix) { |
- PrefixElement prefixElement = maybePrefix; |
- if (prefixElement.isDeferred) { |
- return prefixElement; |
- } |
- } |
- return null; |
- } |
-} |