Chromium Code Reviews| Index: pkg/dev_compiler/lib/src/compiler/code_generator.dart |
| diff --git a/pkg/dev_compiler/lib/src/compiler/code_generator.dart b/pkg/dev_compiler/lib/src/compiler/code_generator.dart |
| index cbbdd0b837ff2a6a55650f49afb68bae25883973..ef155dc3dde28936b1c3272ad905348299908445 100644 |
| --- a/pkg/dev_compiler/lib/src/compiler/code_generator.dart |
| +++ b/pkg/dev_compiler/lib/src/compiler/code_generator.dart |
| @@ -41,7 +41,6 @@ import '../js_ast/js_ast.dart' show js; |
| import 'ast_builder.dart' show AstBuilder; |
| import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile; |
| import 'element_helpers.dart'; |
| -import 'element_loader.dart' show ElementLoader; |
| import 'extension_types.dart' show ExtensionTypeSet; |
| import 'js_interop.dart'; |
| import 'js_metalet.dart' as JS; |
| @@ -72,6 +71,10 @@ class CodeGenerator extends GeneralizingAstVisitor |
| /// Imported libraries, and the temporaries used to refer to them. |
| final _imports = new Map<LibraryElement, JS.TemporaryId>(); |
| + /// The list of dart:_runtime SDK functions; these are assumed by other code |
| + /// in the SDK to be generated before anything else. |
| + final _internalSdkFunctions = <JS.ModuleItem>[]; |
| + |
| /// The list of output module items, in the order they need to be emitted in. |
| final _moduleItems = <JS.ModuleItem>[]; |
| @@ -105,8 +108,6 @@ class CodeGenerator extends GeneralizingAstVisitor |
| final _hasDeferredSupertype = new HashSet<ClassElement>(); |
| - final _eagerTopLevelFields = new HashSet<Element>.identity(); |
| - |
| /// The type provider from the current Analysis [context]. |
| final TypeProvider types; |
| @@ -134,9 +135,24 @@ class CodeGenerator extends GeneralizingAstVisitor |
| /// The current function body being compiled. |
| FunctionBody _currentFunction; |
| - /// Helper class for emitting elements in the proper order to allow |
| - /// JS to load the module. |
| - ElementLoader _loader; |
| + HashMap<TypeDefiningElement, AstNode> _declarationNodes; |
| + |
| + /// The stack of currently emitting elements, if generating top-level code |
| + /// for them. This is not used when inside method bodies, because order does |
| + /// not matter for those. |
| + final _topLevelElements = <TypeDefiningElement>[]; |
| + |
| + /// The current element being loaded. |
| + /// We can use this to determine if we're loading top-level code or not: |
| + /// |
| + /// _currentElements.last == _topLevelElements.last |
| + // |
| + // TODO(jmesserly): ideally we'd only track types here, in other words, |
| + // TypeDefiningElement. However we still rely on this for [currentLibrary] so |
| + // we need something to be pushed always. |
| + final _currentElements = <Element>[]; |
| + |
| + final _deferredProperties = new HashMap<PropertyAccessorElement, JS.Method>(); |
| BuildUnit _buildUnit; |
| @@ -182,7 +198,9 @@ class CodeGenerator extends GeneralizingAstVisitor |
| _getLibrary(c, 'dart:_internal').getType('PrivateSymbol'), |
| dartJSLibrary = _getLibrary(c, 'dart:js'); |
| - LibraryElement get currentLibrary => _loader.currentElement.library; |
| + Element get currentElement => _currentElements.last; |
| + |
| + LibraryElement get currentLibrary => currentElement.library; |
| /// The main entry point to JavaScript code generation. |
| /// |
| @@ -285,19 +303,17 @@ class CodeGenerator extends GeneralizingAstVisitor |
| } |
| } |
| - // Collect all Element -> Node mappings, in case we need to forward declare |
| - // any nodes. |
| - var nodes = new HashMap<Element, AstNode>.identity(); |
| - var sdkBootstrappingFns = new List<FunctionElement>(); |
| + // Collect all class/type Element -> Node mappings |
| + // in case we need to forward declare any classes. |
| + _declarationNodes = new HashMap<TypeDefiningElement, AstNode>.identity(); |
| for (var unit in compilationUnits) { |
| - if (isSdkInternalRuntime( |
| - resolutionMap.elementDeclaredByCompilationUnit(unit).library)) { |
| - sdkBootstrappingFns.addAll( |
| - resolutionMap.elementDeclaredByCompilationUnit(unit).functions); |
| + for (var declaration in unit.declarations) { |
| + var element = declaration.element; |
| + if (element is TypeDefiningElement) { |
| + _declarationNodes[element] = declaration; |
| + } |
| } |
| - _collectElements(unit, nodes); |
| } |
| - _loader = new ElementLoader(nodes); |
| if (compilationUnits.isNotEmpty) { |
| _constants = new ConstFieldVisitor(context, |
| dummySource: resolutionMap |
| @@ -308,15 +324,16 @@ class CodeGenerator extends GeneralizingAstVisitor |
| // Add implicit dart:core dependency so it is first. |
| emitLibraryName(dartCoreLibrary); |
| - // Emit SDK bootstrapping functions first, if any. |
| - sdkBootstrappingFns.forEach(_emitDeclaration); |
| - |
| // Visit each compilation unit and emit its code. |
| // |
| // NOTE: declarations are not necessarily emitted in this order. |
| // Order will be changed as needed so the resulting code can execute. |
| // This is done by forward declaring items. |
| - compilationUnits.forEach(_finishDeclarationsInUnit); |
| + compilationUnits.forEach(_emitCompilationUnit); |
| + assert(_deferredProperties.isEmpty); |
| + |
| + // Visit directives (for exports) |
| + compilationUnits.forEach(_emitExportDirectives); |
| // Declare imports |
| _finishImports(items); |
| @@ -324,6 +341,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| // Discharge the type table cache variables and |
| // hoisted definitions. |
| items.addAll(_typeTable.discharge()); |
| + items.addAll(_internalSdkFunctions); |
| // Track the module name for each library in the module. |
| // This data is only required for debugging. |
| @@ -432,7 +450,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| for (var item in items) { |
| if (item is JS.Block && !item.isScope) { |
| _copyAndFlattenBlocks(result, item.statements); |
| - } else { |
| + } else if (item != null) { |
| result.add(item); |
| } |
| } |
| @@ -485,21 +503,6 @@ class CodeGenerator extends GeneralizingAstVisitor |
| }); |
| } |
| - /// Collect toplevel elements and nodes we need to emit, and returns |
| - /// an ordered map of these. |
| - static void _collectElements( |
| - CompilationUnit unit, Map<Element, AstNode> map) { |
| - for (var declaration in unit.declarations) { |
| - if (declaration is TopLevelVariableDeclaration) { |
| - for (var field in declaration.variables.variables) { |
| - map[field.element] = field; |
| - } |
| - } else { |
| - map[declaration.element] = declaration; |
| - } |
| - } |
| - } |
| - |
| /// Called to emit all top-level declarations. |
| /// |
| /// During the course of emitting one item, we may emit another. For example |
| @@ -508,40 +511,112 @@ class CodeGenerator extends GeneralizingAstVisitor |
| /// |
| /// Because D depends on B, we'll emit B first if needed. However C is not |
| /// used by top-level JavaScript code, so we can ignore that dependency. |
| - void _emitDeclaration(Element e) { |
| - var item = _loader.emitDeclaration(e, (AstNode node) { |
| - // TODO(jmesserly): this is not really the right place for this. |
| - // Ideally we do this per function body. |
| - // |
| - // We'll need to be consistent about when we're generating functions, and |
| - // only run this on the outermost function, and not any closures. |
| - inferNullableTypes(node); |
| - return _visit(node) as JS.Node; |
| - }); |
| + void _emitTypeDeclaration(TypeDefiningElement e) { |
| + var node = _declarationNodes.remove(e); |
| + if (node == null) return null; // not from this module or already loaded. |
| + |
| + _currentElements.add(e); |
| + |
| + // TODO(jmesserly): this is not really the right place for this. |
| + // Ideally we do this per function body. |
| + // |
| + // We'll need to be consistent about when we're generating functions, and |
| + // only run this on the outermost function, and not any closures. |
| + inferNullableTypes(node); |
| + |
| + _moduleItems.add(_visit(node)); |
| - if (item != null) _moduleItems.add(item); |
| + var last = _currentElements.removeLast(); |
| + assert(identical(e, last)); |
| } |
| - void _declareBeforeUse(Element e) { |
| - _loader.declareBeforeUse(e, _emitDeclaration); |
| + /// Start generating top-level code for the element [e]. |
| + /// |
| + /// Subsequent [emitDeclaration] calls will cause those elements to be |
| + /// generated before this one, until [finishTopLevel] is called. |
| + void _startTopLevelCodeForClass(TypeDefiningElement e) { |
| + assert(identical(e, currentElement)); |
| + _topLevelElements.add(e); |
|
vsm
2017/04/04 22:58:43
Is it worth asserting that it's not there already?
Jennifer Messerly
2017/04/04 23:18:34
I think it's ~probably okay if we skip that assert
|
| + } |
| + |
| + /// Finishes the top-level code for the element [e]. |
| + void _finishTopLevelCodeForClass(TypeDefiningElement e) { |
| + var last = _topLevelElements.removeLast(); |
| + assert(identical(e, last)); |
| } |
| - void _finishDeclarationsInUnit(CompilationUnit unit) { |
| + /// To emit top-level module items, we sometimes need to reorder them. |
| + /// |
| + /// This function takes care of that, and also detects cases where reordering |
| + /// failed, and we need to resort to lazy loading, by marking the element as |
| + /// lazy. All elements need to be aware of this possibility and generate code |
| + /// accordingly. |
| + /// |
| + /// If we are not emitting top-level code, this does nothing, because all |
| + /// declarations are assumed to be available before we start execution. |
| + /// See [startTopLevel]. |
| + void _declareBeforeUse(TypeDefiningElement e) { |
| + if (e == null) return; |
| + |
| + var topLevel = _topLevelElements; |
| + if (topLevel.isNotEmpty && identical(currentElement, topLevel.last)) { |
| + // If the item is from our library, try to emit it now. |
| + _emitTypeDeclaration(e); |
| + } |
| + } |
| + |
| + void _emitCompilationUnit(CompilationUnit unit) { |
| // NOTE: this method isn't the right place to initialize |
| // per-compilation-unit state. Declarations can be visited out of order, |
| // this is only to catch things that haven't been emitted yet. |
| // |
| - // See _emitDeclaration. |
| + // See _emitTypeDeclaration. |
| + var library = unit.element.library; |
| + bool internalSdk = isSdkInternalRuntime(library); |
| + _currentElements.add(library); |
| + |
| + List<VariableDeclaration> fields; |
| for (var declaration in unit.declarations) { |
| + if (declaration is TopLevelVariableDeclaration) { |
| + inferNullableTypes(declaration); |
| + if (internalSdk && declaration.variables.isFinal) { |
| + _emitInternalSdkFields(declaration.variables.variables); |
| + } else { |
| + (fields ??= []).addAll(declaration.variables.variables); |
| + } |
| + continue; |
| + } |
| + |
| + if (fields != null) { |
| + _emitTopLevelFields(fields); |
| + fields = null; |
| + } |
| + |
| var element = declaration.element; |
| - if (element != null) { |
| - _emitDeclaration(element); |
| + if (element is TypeDefiningElement) { |
| + _emitTypeDeclaration(element); |
| + continue; |
| + } |
| + |
| + inferNullableTypes(declaration); |
| + var item = _visit(declaration); |
| + if (internalSdk && element is FunctionElement) { |
| + _internalSdkFunctions.add(item); |
| } else { |
| - declaration.accept(this); |
| + _moduleItems.add(item); |
| } |
| } |
| + |
| + if (fields != null) _emitTopLevelFields(fields); |
| + |
| + _currentElements.removeLast(); |
| + } |
| + |
| + void _emitExportDirectives(CompilationUnit unit) { |
| for (var directive in unit.directives) { |
| + _currentElements.add(directive.element); |
| directive.accept(this); |
| + _currentElements.removeLast(); |
| } |
| } |
| @@ -575,48 +650,21 @@ class CodeGenerator extends GeneralizingAstVisitor |
| var exportedNames = |
| new NamespaceBuilder().createExportNamespaceForDirective(element); |
| - var libraryName = emitLibraryName(currentLibrary); |
| - |
| - // TODO(jmesserly): we could collect all of the names for bulk re-export, |
| - // but this is easier to implement for now. |
| - void emitExport(Element export, {String suffix: ''}) { |
| - var name = _emitTopLevelName(export, suffix: suffix); |
| - |
| - if (export is TypeDefiningElement || |
| - export is FunctionElement || |
| - _eagerTopLevelFields.contains(export)) { |
| - // classes, typedefs, functions, and eager init fields can be assigned |
| - // directly. |
| - // TODO(jmesserly): we don't know about eager init fields from other |
| - // modules we import, so we will never go down this code path for them. |
| - _moduleItems |
| - .add(js.statement('#.# = #;', [libraryName, name.selector, name])); |
| - } |
| - } |
| - |
| - // We only need to export main as it is the only method party of the |
| + // We only need to export main as it is the only method part of the |
| // publicly exposed JS API for a library. |
| // TODO(jacobr): add a library level annotation indicating that all |
| // contents of a library need to be exposed to JS. |
| // https://github.com/dart-lang/sdk/issues/26368 |
| - |
| var export = exportedNames.get('main'); |
| - if (export == null) return; |
| - if (export is PropertyAccessorElement) { |
| - export = (export as PropertyAccessorElement).variable; |
| - } |
| - |
| - // Don't allow redefining names from this library. |
| - if (currentNames.containsKey(export.name)) return; |
| + if (export is FunctionElement) { |
| + // Don't allow redefining names from this library. |
| + if (currentNames.containsKey(export.name)) return; |
| - if (export.isSynthetic && export is PropertyInducingElement) { |
| - _emitDeclaration(export.getter); |
| - _emitDeclaration(export.setter); |
| - } else { |
| - _emitDeclaration(export); |
| + var name = _emitTopLevelName(export); |
| + _moduleItems.add(js.statement( |
| + '#.# = #;', [emitLibraryName(currentLibrary), name.selector, name])); |
| } |
| - emitExport(export); |
| } |
| @override |
| @@ -1313,7 +1361,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| var type = element.type; |
| if (type.isObject) return null; |
| - _loader.startTopLevel(element); |
| + _startTopLevelCodeForClass(element); |
| // List of "direct" supertypes (supertype + mixins) |
| var basetypes = [type.superclass]..addAll(type.mixins); |
| @@ -1336,7 +1384,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| ? baseclasses.first |
| : _callHelper('mixin(#)', [baseclasses]); |
| - _loader.finishTopLevel(element); |
| + _finishTopLevelCodeForClass(element); |
| return heritage; |
| } |
| @@ -1792,17 +1840,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| /// otherwise define them as lazy properties. |
| void _emitStaticFields(List<FieldDeclaration> staticFields, |
| ClassElement classElem, List<JS.Statement> body) { |
| - var lazyStatics = <VariableDeclaration>[]; |
| - for (FieldDeclaration member in staticFields) { |
| - for (VariableDeclaration field in member.fields.variables) { |
| - JS.Statement eagerField = _emitConstantStaticField(classElem, field); |
| - if (eagerField != null) { |
| - body.add(eagerField); |
| - } else { |
| - lazyStatics.add(field); |
| - } |
| - } |
| - } |
| + var lazyStatics = staticFields.expand((f) => f.fields.variables).toList(); |
| if (lazyStatics.isNotEmpty) { |
| body.add(_emitLazyFields(classElem, lazyStatics)); |
| } |
| @@ -2133,12 +2171,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| new JS.Method(name, fun, isStatic: true), node, node.element); |
| } |
| - // For const constructors we need to ensure default values are |
| - // available for use by top-level constant initializers. |
| - ClassDeclaration cls = node.parent; |
| - if (node.constKeyword != null) _loader.startTopLevel(cls.element); |
| var params = visitFormalParameterList(node.parameters); |
| - if (node.constKeyword != null) _loader.finishTopLevel(cls.element); |
| // Factory constructors are essentially static methods. |
| if (node.factoryKeyword != null) { |
| @@ -2187,9 +2220,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| // nice to do them first. |
| // Also for const constructors we need to ensure default values are |
| // available for use by top-level constant initializers. |
| - if (node.constKeyword != null) _loader.startTopLevel(cls.element); |
| var init = _emitArgumentInitializers(node, constructor: true); |
| - if (node.constKeyword != null) _loader.finishTopLevel(cls.element); |
| if (init != null) body.add(init); |
| // Redirecting constructors: these are not allowed to have initializers, |
| @@ -2297,9 +2328,6 @@ class CodeGenerator extends GeneralizingAstVisitor |
| List<FieldDeclaration> fieldDecls, |
| Map<FieldElement, JS.TemporaryId> virtualFields, |
| [ConstructorDeclaration ctor]) { |
| - bool isConst = ctor != null && ctor.constKeyword != null; |
| - if (isConst) _loader.startTopLevel(cls.element); |
| - |
| // Run field initializers if they can have side-effects. |
| var fields = new Map<FieldElement, JS.Expression>(); |
| var unsetFields = new Map<FieldElement, VariableDeclaration>(); |
| @@ -2351,7 +2379,6 @@ class CodeGenerator extends GeneralizingAstVisitor |
| body.add(js.statement('this.# = #;', [access, initialValue])); |
| }); |
| - if (isConst) _loader.finishTopLevel(cls.element); |
| return _statement(body); |
| } |
| @@ -2520,25 +2547,24 @@ class CodeGenerator extends GeneralizingAstVisitor |
| if (_externalOrNative(node)) return null; |
| - // If we have a getter/setter pair, they need to be defined together. |
| - if (node.isGetter) { |
| - PropertyAccessorElement element = node.element; |
| - var props = <JS.Method>[_emitTopLevelProperty(node)]; |
| - var setter = element.correspondingSetter; |
| - if (setter != null) { |
| - props.add(_loader.emitDeclaration( |
| - setter, (node) => _emitTopLevelProperty(node))); |
| - } |
| - return _callHelperStatement('copyProperties(#, { # });', |
| - [emitLibraryName(currentLibrary), props]); |
| - } |
| - if (node.isSetter) { |
| + if (node.isGetter || node.isSetter) { |
| PropertyAccessorElement element = node.element; |
| - var props = <JS.Method>[_emitTopLevelProperty(node)]; |
| - var getter = element.correspondingGetter; |
| - if (getter != null) { |
| - props.add(_loader.emitDeclaration( |
| - getter, (node) => _emitTopLevelProperty(node))); |
| + var pairAccessor = node.isGetter |
| + ? element.correspondingSetter |
| + : element.correspondingGetter; |
| + |
| + var jsCode = _emitTopLevelProperty(node); |
| + var props = <JS.Method>[jsCode]; |
| + if (pairAccessor != null) { |
| + // If we have a getter/setter pair, they need to be defined together. |
| + // If this is the first one, save the generated code for later. |
| + // If this is the second one, get the saved code and emit both. |
| + var pairCode = _deferredProperties.remove(pairAccessor); |
| + if (pairCode == null) { |
| + _deferredProperties[element] = jsCode; |
| + return null; |
| + } |
| + props.add(pairCode); |
| } |
| return _callHelperStatement('copyProperties(#, { # });', |
| [emitLibraryName(currentLibrary), props]); |
| @@ -2631,7 +2657,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| if (type is ParameterizedType && !type.typeArguments.every(_typeIsLoaded)) { |
| return false; |
| } |
| - return _loader.isLoaded(type.element); |
| + return !_declarationNodes.containsKey(type.element); |
| } |
| JS.Expression _emitFunctionTagged(JS.Expression fn, DartType type, |
| @@ -2852,10 +2878,10 @@ class CodeGenerator extends GeneralizingAstVisitor |
| var element = accessor; |
| if (accessor is PropertyAccessorElement) element = accessor.variable; |
| - _declareBeforeUse(element); |
| - |
| // type literal |
| if (element is TypeDefiningElement) { |
| + _declareBeforeUse(element); |
| + |
| var typeName = _emitType(fillDynamicTypeArgs(element.type)); |
| // If the type is a type literal expression in Dart code, wrap the raw |
| @@ -3157,7 +3183,9 @@ class CodeGenerator extends GeneralizingAstVisitor |
| } |
| var element = type.element; |
| - _declareBeforeUse(element); |
| + if (element is TypeDefiningElement) { |
| + _declareBeforeUse(element); |
| + } |
| var interop = _emitJSInterop(element); |
| // Type parameters don't matter as JS interop types cannot be reified. |
| @@ -3391,7 +3419,9 @@ class CodeGenerator extends GeneralizingAstVisitor |
| var element = accessor; |
| if (accessor is PropertyAccessorElement) element = accessor.variable; |
| - _declareBeforeUse(element); |
| + if (element is TypeDefiningElement) { |
| + _declareBeforeUse(element); |
| + } |
| if (element is LocalVariableElement || element is ParameterElement) { |
| return _emitSetLocal(node, element, rhs); |
| @@ -4010,11 +4040,11 @@ class CodeGenerator extends GeneralizingAstVisitor |
| return new JS.Yield(_visit(node.expression)); |
| } |
| + /// This is not used--we emit top-level fields as we are emitting the |
| + /// compilation unit, see [_emitCompilationUnit]. |
| @override |
| visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
| - for (var variable in node.variables.variables) { |
| - _emitDeclaration(variable.element); |
| - } |
| + assert(false); |
| } |
| /// This is not used--we emit fields as we are emitting the class, |
| @@ -4050,9 +4080,9 @@ class CodeGenerator extends GeneralizingAstVisitor |
| @override |
| visitVariableDeclaration(VariableDeclaration node) { |
| if (node.element is PropertyInducingElement) { |
| - // Static and instance fields are handled elsewhere. |
| - assert(node.element is TopLevelVariableElement); |
| - return _emitTopLevelField(node); |
| + // All fields are handled elsewhere. |
| + assert(false); |
| + return null; |
| } |
| var name = new JS.Identifier(node.name.name, |
| @@ -4061,87 +4091,21 @@ class CodeGenerator extends GeneralizingAstVisitor |
| return new JS.VariableInitialization(name, _visitInitializer(node)); |
| } |
| - /// Try to emit a constant static field. |
| - /// |
| - /// If the field's initializer does not cause side effects, and if all of |
| - /// dependencies are safe to refer to while we are initializing the class, |
| - /// then we can initialize it eagerly: |
| - /// |
| - /// // Baz must be const constructor, and the name "Baz" must be defined |
| - /// // by this point. |
| - /// Foo.bar = dart.const(new Baz(42)); |
| - /// |
| - /// Otherwise, we'll need to generate a lazy-static field. That ensures |
| - /// correct visible behavior, as well as avoiding referencing something that |
| - /// isn't defined yet (because it is defined later in the module). |
| - JS.Statement _emitConstantStaticField( |
| - ClassElement classElem, VariableDeclaration field) { |
|
vsm
2017/04/04 22:58:43
We could consider keeping this/below only for case
Jennifer Messerly
2017/04/04 23:05:17
yeah... thought about that. It'd certainly be a lo
|
| - PropertyInducingElement element = field.element; |
| - assert(element.isStatic); |
| - |
| - _loader.startCheckingReferences(); |
| - JS.Expression jsInit = _visitInitializer(field); |
| - bool isLoaded = _loader.finishCheckingReferences(); |
| - |
| - bool eagerInit = |
| - isLoaded && (field.isConst || _constants.isFieldInitConstant(field)); |
| - |
| - var fieldName = field.name.name; |
| - if (eagerInit && |
| - !JS.invalidStaticFieldName(fieldName) && |
| - !_classProperties.staticFieldOverrides.contains(element)) { |
| - return annotate( |
| - js.statement('#.# = #;', [ |
| - _emitTopLevelName(classElem), |
| - _emitMemberName(fieldName, isStatic: true), |
| - jsInit |
| - ]), |
| - field, |
| - field.element); |
| - } |
| - |
| - // This means it should be treated as a lazy field. |
| - // TODO(jmesserly): we're throwing away the initializer expression, |
| - // which will force us to regenerate it. |
| - return null; |
| + /// Emits a list of top-level field. |
| + void _emitTopLevelFields(List<VariableDeclaration> fields) { |
| + _moduleItems.add(_emitLazyFields(currentLibrary, fields)); |
| } |
| - /// Emits a top-level field. |
| - JS.ModuleItem _emitTopLevelField(VariableDeclaration field) { |
| - TopLevelVariableElement element = field.element; |
| - assert(element.isStatic); |
| - |
| - bool eagerInit; |
| - JS.Expression jsInit; |
| - if (field.isConst || _constants.isFieldInitConstant(field)) { |
| - // If the field is constant, try and generate it at the top level. |
| - _loader.startTopLevel(element); |
| - jsInit = _visitInitializer(field); |
| - _loader.finishTopLevel(element); |
| - eagerInit = _loader.isLoaded(element); |
| - } else { |
| - // TODO(jmesserly): we're visiting the initializer here, and again |
| - // later on when we emit lazy fields. That seems busted. |
| - jsInit = _visitInitializer(field); |
| - eagerInit = false; |
| - } |
| - |
| - // Treat dart:runtime stuff as safe to eagerly evaluate. |
| - // TODO(jmesserly): it'd be nice to avoid this special case. |
| - var isJSTopLevel = field.isFinal && isSdkInternalRuntime(element.library); |
| - if (eagerInit || isJSTopLevel) { |
| - // Remember that we emitted it this way, so re-export can take advantage |
| - // of this fact. |
| - _eagerTopLevelFields.add(element); |
| - |
| - return annotate( |
| - js.statement('# = #;', [_emitTopLevelName(element), jsInit]), |
| + /// Treat dart:_runtime fields as safe to eagerly evaluate. |
| + // TODO(jmesserly): it'd be nice to avoid this special case. |
| + void _emitInternalSdkFields(List<VariableDeclaration> fields) { |
| + for (var field in fields) { |
| + _moduleItems.add(annotate( |
| + js.statement('# = #;', |
| + [_emitTopLevelName(field.element), _visitInitializer(field)]), |
| field, |
| - element); |
| + field.element)); |
| } |
| - |
| - assert(element.library == currentLibrary); |
| - return _emitLazyFields(element.library, [field]); |
| } |
| JS.Expression _visitInitializer(VariableDeclaration node) { |
| @@ -4157,6 +4121,8 @@ class CodeGenerator extends GeneralizingAstVisitor |
| for (var node in fields) { |
| var name = node.name.name; |
| var element = node.element; |
| + assert(element.getAncestor((e) => identical(e, target)) != null, |
| + "target is $target but enclosing element is ${element.enclosingElement}"); |
| var access = _emitMemberName(name, isStatic: true); |
| methods.add(annotate( |
| new JS.Method( |
| @@ -5934,7 +5900,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| bool _inWhitelistCode(AstNode node, {isCall: false}) { |
| if (!options.useAngular2Whitelist) return false; |
| - var path = _loader.currentElement.source.fullName; |
| + var path = currentElement.source.fullName; |
| var filename = path.split("/").last; |
| if (_uncheckedWhitelist.containsKey(filename)) { |
| var whitelisted = _uncheckedWhitelist[filename]; |