| Index: lib/src/codegen/js_module_item_order.dart
|
| diff --git a/lib/src/codegen/js_module_item_order.dart b/lib/src/codegen/js_module_item_order.dart
|
| index a79e719de732cfd8b8e5da17c6e5f07ed268a605..d35b1d72f4aa25665b6608c8dbb2a20256e906f2 100644
|
| --- a/lib/src/codegen/js_module_item_order.dart
|
| +++ b/lib/src/codegen/js_module_item_order.dart
|
| @@ -41,6 +41,8 @@ class ModuleItemLoadOrder {
|
| /// Memoized results of [_inLibraryCycle].
|
| final _libraryCycleMemo = new HashMap<LibraryElement, bool>();
|
|
|
| + bool _checkReferences;
|
| +
|
| final ModuleItemEmitter _emitModuleItem;
|
|
|
| LibraryElement _currentLibrary;
|
| @@ -51,6 +53,9 @@ class ModuleItemLoadOrder {
|
| ? _loaded[e] == true
|
| : libraryIsLoaded(e.library);
|
|
|
| + /// True if the element is currently being loaded.
|
| + bool _isLoading(Element e) => _currentElements.contains(e);
|
| +
|
| /// Collect top-level elements and nodes we need to emit.
|
| void collectElements(
|
| LibraryElement library, Iterable<CompilationUnit> partsThenLibrary) {
|
| @@ -61,13 +66,7 @@ class ModuleItemLoadOrder {
|
| for (var decl in unit.declarations) {
|
| _declarationNodes[decl.element] = decl;
|
|
|
| - if (decl is ClassDeclaration) {
|
| - for (var member in decl.members) {
|
| - if (member is FieldDeclaration && member.isStatic) {
|
| - _collectElementsForVariable(member.fields);
|
| - }
|
| - }
|
| - } else if (decl is TopLevelVariableDeclaration) {
|
| + if (decl is TopLevelVariableDeclaration) {
|
| _collectElementsForVariable(decl.variables);
|
| }
|
| }
|
| @@ -85,8 +84,6 @@ class ModuleItemLoadOrder {
|
| /// before this one, until [finishElement] is called.
|
| void startTopLevel(Element e) {
|
| assert(isCurrentElement(e));
|
| - // Assume loading will succeed until proven otherwise.
|
| - _loaded[e] = true;
|
| _topLevelElements.add(e);
|
| }
|
|
|
| @@ -96,6 +93,26 @@ class ModuleItemLoadOrder {
|
| assert(identical(e, last));
|
| }
|
|
|
| + /// Starts recording calls to [declareBeforeUse], until
|
| + /// [finishCheckingReferences] is called.
|
| + void startCheckingReferences() {
|
| + // This function should not be reentrant, and we should not current be
|
| + // emitting top-level code.
|
| + assert(_checkReferences == null);
|
| + assert(
|
| + _topLevelElements.isEmpty || !isCurrentElement(_topLevelElements.last));
|
| + // Assume true until proven otherwise
|
| + _checkReferences = true;
|
| + }
|
| +
|
| + /// Finishes recording references, and returns `true` if all referenced
|
| + /// items were loaded (or if no items were referenced).
|
| + bool finishCheckingReferences() {
|
| + var result = _checkReferences;
|
| + _checkReferences = null;
|
| + return result;
|
| + }
|
| +
|
| // Starts generating code for the declaration element [e].
|
| //
|
| // Normally this is called implicitly by [loadDeclaration] and/or
|
| @@ -146,8 +163,17 @@ class ModuleItemLoadOrder {
|
| /// declarations are assumed to be available before we start execution.
|
| /// See [startTopLevel].
|
| void declareBeforeUse(Element e) {
|
| - if (e == null || _topLevelElements.isEmpty) return;
|
| - if (!isCurrentElement(_topLevelElements.last)) return;
|
| + if (e == null) return;
|
| +
|
| + if (_checkReferences != null) {
|
| + _checkReferences = _checkReferences && isLoaded(e) && !_isLoading(e);
|
| + return;
|
| + }
|
| +
|
| + if (_topLevelElements.isEmpty ||
|
| + !isCurrentElement(_topLevelElements.last)) {
|
| + return;
|
| + }
|
|
|
| // If the item is from our library, try to emit it now.
|
| bool loaded;
|
|
|