Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: pkg/dev_compiler/lib/src/compiler/code_generator.dart

Issue 2797443007: fix #29182, generate top level const fields lazily (Closed)
Patch Set: fix Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 2
3 // for details. All rights reserved. Use of this source code is governed by a 3 // for details. All rights reserved. Use of this source code is governed by a
4 // BSD-style license that can be found in the LICENSE file. 4 // BSD-style license that can be found in the LICENSE file.
5 5
6 import 'dart:collection' show HashMap, HashSet; 6 import 'dart:collection' show HashMap, HashSet;
7 import 'dart:math' show min, max; 7 import 'dart:math' show min, max;
8 8
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
10 import 'package:analyzer/dart/ast/ast.dart'; 10 import 'package:analyzer/dart/ast/ast.dart';
(...skipping 23 matching lines...) Expand all
34 import 'package:analyzer/src/task/strong/ast_properties.dart' 34 import 'package:analyzer/src/task/strong/ast_properties.dart'
35 show isDynamicInvoke, setIsDynamicInvoke, getImplicitAssignmentCast; 35 show isDynamicInvoke, setIsDynamicInvoke, getImplicitAssignmentCast;
36 import 'package:path/path.dart' show separator; 36 import 'package:path/path.dart' show separator;
37 37
38 import '../closure/closure_annotator.dart' show ClosureAnnotator; 38 import '../closure/closure_annotator.dart' show ClosureAnnotator;
39 import '../js_ast/js_ast.dart' as JS; 39 import '../js_ast/js_ast.dart' as JS;
40 import '../js_ast/js_ast.dart' show js; 40 import '../js_ast/js_ast.dart' show js;
41 import 'ast_builder.dart' show AstBuilder; 41 import 'ast_builder.dart' show AstBuilder;
42 import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile; 42 import 'compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile;
43 import 'element_helpers.dart'; 43 import 'element_helpers.dart';
44 import 'element_loader.dart' show ElementLoader;
45 import 'extension_types.dart' show ExtensionTypeSet; 44 import 'extension_types.dart' show ExtensionTypeSet;
46 import 'js_interop.dart'; 45 import 'js_interop.dart';
47 import 'js_metalet.dart' as JS; 46 import 'js_metalet.dart' as JS;
48 import 'js_names.dart' as JS; 47 import 'js_names.dart' as JS;
49 import 'js_typeref_codegen.dart' show JsTypeRefCodegen; 48 import 'js_typeref_codegen.dart' show JsTypeRefCodegen;
50 import 'module_builder.dart' show pathToJSIdentifier; 49 import 'module_builder.dart' show pathToJSIdentifier;
51 import 'nullable_type_inference.dart' show NullableTypeInference; 50 import 'nullable_type_inference.dart' show NullableTypeInference;
52 import 'property_model.dart'; 51 import 'property_model.dart';
53 import 'reify_coercions.dart' show CoercionReifier; 52 import 'reify_coercions.dart' show CoercionReifier;
54 import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless; 53 import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless;
(...skipping 10 matching lines...) Expand all
65 /// The set of libraries we are currently compiling, and the temporaries used 64 /// The set of libraries we are currently compiling, and the temporaries used
66 /// to refer to them. 65 /// to refer to them.
67 /// 66 ///
68 /// We sometimes special case codegen for a single library, as it simplifies 67 /// We sometimes special case codegen for a single library, as it simplifies
69 /// name scoping requirements. 68 /// name scoping requirements.
70 final _libraries = new Map<LibraryElement, JS.Identifier>(); 69 final _libraries = new Map<LibraryElement, JS.Identifier>();
71 70
72 /// Imported libraries, and the temporaries used to refer to them. 71 /// Imported libraries, and the temporaries used to refer to them.
73 final _imports = new Map<LibraryElement, JS.TemporaryId>(); 72 final _imports = new Map<LibraryElement, JS.TemporaryId>();
74 73
74 /// The list of dart:_runtime SDK functions; these are assumed by other code
75 /// in the SDK to be generated before anything else.
76 final _internalSdkFunctions = <JS.ModuleItem>[];
77
75 /// The list of output module items, in the order they need to be emitted in. 78 /// The list of output module items, in the order they need to be emitted in.
76 final _moduleItems = <JS.ModuleItem>[]; 79 final _moduleItems = <JS.ModuleItem>[];
77 80
78 /// Table of named and possibly hoisted types. 81 /// Table of named and possibly hoisted types.
79 TypeTable _typeTable; 82 TypeTable _typeTable;
80 83
81 /// The global extension type table. 84 /// The global extension type table.
82 final ExtensionTypeSet _extensionTypes; 85 final ExtensionTypeSet _extensionTypes;
83 86
84 /// The variable for the target of the current `..` cascade expression. 87 /// The variable for the target of the current `..` cascade expression.
(...skipping 13 matching lines...) Expand all
98 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); 101 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>();
99 final _initializingFormalTemps = 102 final _initializingFormalTemps =
100 new HashMap<ParameterElement, JS.TemporaryId>(); 103 new HashMap<ParameterElement, JS.TemporaryId>();
101 104
102 JS.Identifier _extensionSymbolsModule; 105 JS.Identifier _extensionSymbolsModule;
103 JS.Identifier _runtimeModule; 106 JS.Identifier _runtimeModule;
104 final namedArgumentTemp = new JS.TemporaryId('opts'); 107 final namedArgumentTemp = new JS.TemporaryId('opts');
105 108
106 final _hasDeferredSupertype = new HashSet<ClassElement>(); 109 final _hasDeferredSupertype = new HashSet<ClassElement>();
107 110
108 final _eagerTopLevelFields = new HashSet<Element>.identity();
109
110 /// The type provider from the current Analysis [context]. 111 /// The type provider from the current Analysis [context].
111 final TypeProvider types; 112 final TypeProvider types;
112 113
113 final LibraryElement dartCoreLibrary; 114 final LibraryElement dartCoreLibrary;
114 final LibraryElement dartJSLibrary; 115 final LibraryElement dartJSLibrary;
115 116
116 /// The dart:async `StreamIterator<>` type. 117 /// The dart:async `StreamIterator<>` type.
117 final InterfaceType _asyncStreamIterator; 118 final InterfaceType _asyncStreamIterator;
118 119
119 /// The dart:_interceptors JSArray element. 120 /// The dart:_interceptors JSArray element.
120 final ClassElement _jsArray; 121 final ClassElement _jsArray;
121 122
122 final ClassElement boolClass; 123 final ClassElement boolClass;
123 final ClassElement intClass; 124 final ClassElement intClass;
124 final ClassElement interceptorClass; 125 final ClassElement interceptorClass;
125 final ClassElement nullClass; 126 final ClassElement nullClass;
126 final ClassElement numClass; 127 final ClassElement numClass;
127 final ClassElement objectClass; 128 final ClassElement objectClass;
128 final ClassElement stringClass; 129 final ClassElement stringClass;
129 final ClassElement functionClass; 130 final ClassElement functionClass;
130 final ClassElement privateSymbolClass; 131 final ClassElement privateSymbolClass;
131 132
132 ConstFieldVisitor _constants; 133 ConstFieldVisitor _constants;
133 134
134 /// The current function body being compiled. 135 /// The current function body being compiled.
135 FunctionBody _currentFunction; 136 FunctionBody _currentFunction;
136 137
137 /// Helper class for emitting elements in the proper order to allow 138 HashMap<TypeDefiningElement, AstNode> _declarationNodes;
138 /// JS to load the module. 139
139 ElementLoader _loader; 140 /// The stack of currently emitting elements, if generating top-level code
141 /// for them. This is not used when inside method bodies, because order does
142 /// not matter for those.
143 final _topLevelElements = <TypeDefiningElement>[];
144
145 /// The current element being loaded.
146 /// We can use this to determine if we're loading top-level code or not:
147 ///
148 /// _currentElements.last == _topLevelElements.last
149 //
150 // TODO(jmesserly): ideally we'd only track types here, in other words,
151 // TypeDefiningElement. However we still rely on this for [currentLibrary] so
152 // we need something to be pushed always.
153 final _currentElements = <Element>[];
154
155 final _deferredProperties = new HashMap<PropertyAccessorElement, JS.Method>();
140 156
141 BuildUnit _buildUnit; 157 BuildUnit _buildUnit;
142 158
143 String _libraryRoot; 159 String _libraryRoot;
144 160
145 bool _superAllowed = true; 161 bool _superAllowed = true;
146 162
147 List<JS.TemporaryId> _superHelperSymbols = <JS.TemporaryId>[]; 163 List<JS.TemporaryId> _superHelperSymbols = <JS.TemporaryId>[];
148 List<JS.Method> _superHelpers = <JS.Method>[]; 164 List<JS.Method> _superHelpers = <JS.Method>[];
149 165
(...skipping 25 matching lines...) Expand all
175 intClass = _getLibrary(c, 'dart:core').getType('int'), 191 intClass = _getLibrary(c, 'dart:core').getType('int'),
176 numClass = _getLibrary(c, 'dart:core').getType('num'), 192 numClass = _getLibrary(c, 'dart:core').getType('num'),
177 nullClass = _getLibrary(c, 'dart:core').getType('Null'), 193 nullClass = _getLibrary(c, 'dart:core').getType('Null'),
178 objectClass = _getLibrary(c, 'dart:core').getType('Object'), 194 objectClass = _getLibrary(c, 'dart:core').getType('Object'),
179 stringClass = _getLibrary(c, 'dart:core').getType('String'), 195 stringClass = _getLibrary(c, 'dart:core').getType('String'),
180 functionClass = _getLibrary(c, 'dart:core').getType('Function'), 196 functionClass = _getLibrary(c, 'dart:core').getType('Function'),
181 privateSymbolClass = 197 privateSymbolClass =
182 _getLibrary(c, 'dart:_internal').getType('PrivateSymbol'), 198 _getLibrary(c, 'dart:_internal').getType('PrivateSymbol'),
183 dartJSLibrary = _getLibrary(c, 'dart:js'); 199 dartJSLibrary = _getLibrary(c, 'dart:js');
184 200
185 LibraryElement get currentLibrary => _loader.currentElement.library; 201 Element get currentElement => _currentElements.last;
202
203 LibraryElement get currentLibrary => currentElement.library;
186 204
187 /// The main entry point to JavaScript code generation. 205 /// The main entry point to JavaScript code generation.
188 /// 206 ///
189 /// Takes the metadata for the build unit, as well as resolved trees and 207 /// Takes the metadata for the build unit, as well as resolved trees and
190 /// errors, and computes the output module code and optionally the source map. 208 /// errors, and computes the output module code and optionally the source map.
191 JSModuleFile compile(BuildUnit unit, List<CompilationUnit> compilationUnits, 209 JSModuleFile compile(BuildUnit unit, List<CompilationUnit> compilationUnits,
192 List<String> errors) { 210 List<String> errors) {
193 _buildUnit = unit; 211 _buildUnit = unit;
194 _libraryRoot = _buildUnit.libraryRoot; 212 _libraryRoot = _buildUnit.libraryRoot;
195 if (!_libraryRoot.endsWith(separator)) { 213 if (!_libraryRoot.endsWith(separator)) {
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 js.call('const # = Object.create(null)', [libraryTemp]))); 296 js.call('const # = Object.create(null)', [libraryTemp])));
279 297
280 // dart:_runtime has a magic module that holds extension method symbols. 298 // dart:_runtime has a magic module that holds extension method symbols.
281 // TODO(jmesserly): find a cleaner design for this. 299 // TODO(jmesserly): find a cleaner design for this.
282 if (isSdkInternalRuntime(library)) { 300 if (isSdkInternalRuntime(library)) {
283 items.add(new JS.ExportDeclaration(js 301 items.add(new JS.ExportDeclaration(js
284 .call('const # = Object.create(null)', [_extensionSymbolsModule]))); 302 .call('const # = Object.create(null)', [_extensionSymbolsModule])));
285 } 303 }
286 } 304 }
287 305
288 // Collect all Element -> Node mappings, in case we need to forward declare 306 // Collect all class/type Element -> Node mappings
289 // any nodes. 307 // in case we need to forward declare any classes.
290 var nodes = new HashMap<Element, AstNode>.identity(); 308 _declarationNodes = new HashMap<TypeDefiningElement, AstNode>.identity();
291 var sdkBootstrappingFns = new List<FunctionElement>();
292 for (var unit in compilationUnits) { 309 for (var unit in compilationUnits) {
293 if (isSdkInternalRuntime( 310 for (var declaration in unit.declarations) {
294 resolutionMap.elementDeclaredByCompilationUnit(unit).library)) { 311 var element = declaration.element;
295 sdkBootstrappingFns.addAll( 312 if (element is TypeDefiningElement) {
296 resolutionMap.elementDeclaredByCompilationUnit(unit).functions); 313 _declarationNodes[element] = declaration;
314 }
297 } 315 }
298 _collectElements(unit, nodes);
299 } 316 }
300 _loader = new ElementLoader(nodes);
301 if (compilationUnits.isNotEmpty) { 317 if (compilationUnits.isNotEmpty) {
302 _constants = new ConstFieldVisitor(context, 318 _constants = new ConstFieldVisitor(context,
303 dummySource: resolutionMap 319 dummySource: resolutionMap
304 .elementDeclaredByCompilationUnit(compilationUnits.first) 320 .elementDeclaredByCompilationUnit(compilationUnits.first)
305 .source); 321 .source);
306 } 322 }
307 323
308 // Add implicit dart:core dependency so it is first. 324 // Add implicit dart:core dependency so it is first.
309 emitLibraryName(dartCoreLibrary); 325 emitLibraryName(dartCoreLibrary);
310 326
311 // Emit SDK bootstrapping functions first, if any.
312 sdkBootstrappingFns.forEach(_emitDeclaration);
313
314 // Visit each compilation unit and emit its code. 327 // Visit each compilation unit and emit its code.
315 // 328 //
316 // NOTE: declarations are not necessarily emitted in this order. 329 // NOTE: declarations are not necessarily emitted in this order.
317 // Order will be changed as needed so the resulting code can execute. 330 // Order will be changed as needed so the resulting code can execute.
318 // This is done by forward declaring items. 331 // This is done by forward declaring items.
319 compilationUnits.forEach(_finishDeclarationsInUnit); 332 compilationUnits.forEach(_emitCompilationUnit);
333 assert(_deferredProperties.isEmpty);
334
335 // Visit directives (for exports)
336 compilationUnits.forEach(_emitExportDirectives);
320 337
321 // Declare imports 338 // Declare imports
322 _finishImports(items); 339 _finishImports(items);
323 340
324 // Discharge the type table cache variables and 341 // Discharge the type table cache variables and
325 // hoisted definitions. 342 // hoisted definitions.
326 items.addAll(_typeTable.discharge()); 343 items.addAll(_typeTable.discharge());
344 items.addAll(_internalSdkFunctions);
327 345
328 // Track the module name for each library in the module. 346 // Track the module name for each library in the module.
329 // This data is only required for debugging. 347 // This data is only required for debugging.
330 _moduleItems.add(js.statement( 348 _moduleItems.add(js.statement(
331 '#.trackLibraries(#, #, ${JSModuleFile.sourceMapHoleID});', 349 '#.trackLibraries(#, #, ${JSModuleFile.sourceMapHoleID});',
332 [_runtimeModule, js.string(name), _librariesDebuggerObject()])); 350 [_runtimeModule, js.string(name), _librariesDebuggerObject()]));
333 351
334 // Add the module's code (produced by visiting compilation units, above) 352 // Add the module's code (produced by visiting compilation units, above)
335 _copyAndFlattenBlocks(items, _moduleItems); 353 _copyAndFlattenBlocks(items, _moduleItems);
336 354
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
425 } 443 }
426 444
427 /// Flattens blocks in [items] to a single list. 445 /// Flattens blocks in [items] to a single list.
428 /// 446 ///
429 /// This will not flatten blocks that are marked as being scopes. 447 /// This will not flatten blocks that are marked as being scopes.
430 void _copyAndFlattenBlocks( 448 void _copyAndFlattenBlocks(
431 List<JS.ModuleItem> result, Iterable<JS.ModuleItem> items) { 449 List<JS.ModuleItem> result, Iterable<JS.ModuleItem> items) {
432 for (var item in items) { 450 for (var item in items) {
433 if (item is JS.Block && !item.isScope) { 451 if (item is JS.Block && !item.isScope) {
434 _copyAndFlattenBlocks(result, item.statements); 452 _copyAndFlattenBlocks(result, item.statements);
435 } else { 453 } else if (item != null) {
436 result.add(item); 454 result.add(item);
437 } 455 }
438 } 456 }
439 } 457 }
440 458
441 String _libraryToModule(LibraryElement library) { 459 String _libraryToModule(LibraryElement library) {
442 assert(!_libraries.containsKey(library)); 460 assert(!_libraries.containsKey(library));
443 var source = library.source; 461 var source = library.source;
444 // TODO(jmesserly): we need to split out HTML. 462 // TODO(jmesserly): we need to split out HTML.
445 if (source.uri.scheme == 'dart') { 463 if (source.uri.scheme == 'dart') {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 if (module == coreModuleName) { 496 if (module == coreModuleName) {
479 imports.add(new JS.NameSpecifier(_runtimeModule)); 497 imports.add(new JS.NameSpecifier(_runtimeModule));
480 imports.add(new JS.NameSpecifier(_extensionSymbolsModule)); 498 imports.add(new JS.NameSpecifier(_extensionSymbolsModule));
481 } 499 }
482 500
483 items.add(new JS.ImportDeclaration( 501 items.add(new JS.ImportDeclaration(
484 namedImports: imports, from: js.string(module, "'"))); 502 namedImports: imports, from: js.string(module, "'")));
485 }); 503 });
486 } 504 }
487 505
488 /// Collect toplevel elements and nodes we need to emit, and returns
489 /// an ordered map of these.
490 static void _collectElements(
491 CompilationUnit unit, Map<Element, AstNode> map) {
492 for (var declaration in unit.declarations) {
493 if (declaration is TopLevelVariableDeclaration) {
494 for (var field in declaration.variables.variables) {
495 map[field.element] = field;
496 }
497 } else {
498 map[declaration.element] = declaration;
499 }
500 }
501 }
502
503 /// Called to emit all top-level declarations. 506 /// Called to emit all top-level declarations.
504 /// 507 ///
505 /// During the course of emitting one item, we may emit another. For example 508 /// During the course of emitting one item, we may emit another. For example
506 /// 509 ///
507 /// class D extends B { C m() { ... } } 510 /// class D extends B { C m() { ... } }
508 /// 511 ///
509 /// Because D depends on B, we'll emit B first if needed. However C is not 512 /// Because D depends on B, we'll emit B first if needed. However C is not
510 /// used by top-level JavaScript code, so we can ignore that dependency. 513 /// used by top-level JavaScript code, so we can ignore that dependency.
511 void _emitDeclaration(Element e) { 514 void _emitTypeDeclaration(TypeDefiningElement e) {
512 var item = _loader.emitDeclaration(e, (AstNode node) { 515 var node = _declarationNodes.remove(e);
513 // TODO(jmesserly): this is not really the right place for this. 516 if (node == null) return null; // not from this module or already loaded.
514 // Ideally we do this per function body.
515 //
516 // We'll need to be consistent about when we're generating functions, and
517 // only run this on the outermost function, and not any closures.
518 inferNullableTypes(node);
519 return _visit(node) as JS.Node;
520 });
521 517
522 if (item != null) _moduleItems.add(item); 518 _currentElements.add(e);
519
520 // TODO(jmesserly): this is not really the right place for this.
521 // Ideally we do this per function body.
522 //
523 // We'll need to be consistent about when we're generating functions, and
524 // only run this on the outermost function, and not any closures.
525 inferNullableTypes(node);
526
527 _moduleItems.add(_visit(node));
528
529 var last = _currentElements.removeLast();
530 assert(identical(e, last));
523 } 531 }
524 532
525 void _declareBeforeUse(Element e) { 533 /// Start generating top-level code for the element [e].
526 _loader.declareBeforeUse(e, _emitDeclaration); 534 ///
535 /// Subsequent [emitDeclaration] calls will cause those elements to be
536 /// generated before this one, until [finishTopLevel] is called.
537 void _startTopLevelCodeForClass(TypeDefiningElement e) {
538 assert(identical(e, currentElement));
539 _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
527 } 540 }
528 541
529 void _finishDeclarationsInUnit(CompilationUnit unit) { 542 /// Finishes the top-level code for the element [e].
543 void _finishTopLevelCodeForClass(TypeDefiningElement e) {
544 var last = _topLevelElements.removeLast();
545 assert(identical(e, last));
546 }
547
548 /// To emit top-level module items, we sometimes need to reorder them.
549 ///
550 /// This function takes care of that, and also detects cases where reordering
551 /// failed, and we need to resort to lazy loading, by marking the element as
552 /// lazy. All elements need to be aware of this possibility and generate code
553 /// accordingly.
554 ///
555 /// If we are not emitting top-level code, this does nothing, because all
556 /// declarations are assumed to be available before we start execution.
557 /// See [startTopLevel].
558 void _declareBeforeUse(TypeDefiningElement e) {
559 if (e == null) return;
560
561 var topLevel = _topLevelElements;
562 if (topLevel.isNotEmpty && identical(currentElement, topLevel.last)) {
563 // If the item is from our library, try to emit it now.
564 _emitTypeDeclaration(e);
565 }
566 }
567
568 void _emitCompilationUnit(CompilationUnit unit) {
530 // NOTE: this method isn't the right place to initialize 569 // NOTE: this method isn't the right place to initialize
531 // per-compilation-unit state. Declarations can be visited out of order, 570 // per-compilation-unit state. Declarations can be visited out of order,
532 // this is only to catch things that haven't been emitted yet. 571 // this is only to catch things that haven't been emitted yet.
533 // 572 //
534 // See _emitDeclaration. 573 // See _emitTypeDeclaration.
574 var library = unit.element.library;
575 bool internalSdk = isSdkInternalRuntime(library);
576 _currentElements.add(library);
577
578 List<VariableDeclaration> fields;
535 for (var declaration in unit.declarations) { 579 for (var declaration in unit.declarations) {
580 if (declaration is TopLevelVariableDeclaration) {
581 inferNullableTypes(declaration);
582 if (internalSdk && declaration.variables.isFinal) {
583 _emitInternalSdkFields(declaration.variables.variables);
584 } else {
585 (fields ??= []).addAll(declaration.variables.variables);
586 }
587 continue;
588 }
589
590 if (fields != null) {
591 _emitTopLevelFields(fields);
592 fields = null;
593 }
594
536 var element = declaration.element; 595 var element = declaration.element;
537 if (element != null) { 596 if (element is TypeDefiningElement) {
538 _emitDeclaration(element); 597 _emitTypeDeclaration(element);
598 continue;
599 }
600
601 inferNullableTypes(declaration);
602 var item = _visit(declaration);
603 if (internalSdk && element is FunctionElement) {
604 _internalSdkFunctions.add(item);
539 } else { 605 } else {
540 declaration.accept(this); 606 _moduleItems.add(item);
541 } 607 }
542 } 608 }
609
610 if (fields != null) _emitTopLevelFields(fields);
611
612 _currentElements.removeLast();
613 }
614
615 void _emitExportDirectives(CompilationUnit unit) {
543 for (var directive in unit.directives) { 616 for (var directive in unit.directives) {
617 _currentElements.add(directive.element);
544 directive.accept(this); 618 directive.accept(this);
619 _currentElements.removeLast();
545 } 620 }
546 } 621 }
547 622
548 @override 623 @override
549 void visitLibraryDirective(LibraryDirective node) {} 624 void visitLibraryDirective(LibraryDirective node) {}
550 625
551 @override 626 @override
552 void visitImportDirective(ImportDirective node) { 627 void visitImportDirective(ImportDirective node) {
553 // We don't handle imports here. 628 // We don't handle imports here.
554 // 629 //
(...skipping 13 matching lines...) Expand all
568 643
569 @override 644 @override
570 void visitExportDirective(ExportDirective node) { 645 void visitExportDirective(ExportDirective node) {
571 ExportElement element = node.element; 646 ExportElement element = node.element;
572 var currentLibrary = element.library; 647 var currentLibrary = element.library;
573 648
574 var currentNames = currentLibrary.publicNamespace.definedNames; 649 var currentNames = currentLibrary.publicNamespace.definedNames;
575 var exportedNames = 650 var exportedNames =
576 new NamespaceBuilder().createExportNamespaceForDirective(element); 651 new NamespaceBuilder().createExportNamespaceForDirective(element);
577 652
578 var libraryName = emitLibraryName(currentLibrary); 653 // We only need to export main as it is the only method part of the
579
580 // TODO(jmesserly): we could collect all of the names for bulk re-export,
581 // but this is easier to implement for now.
582 void emitExport(Element export, {String suffix: ''}) {
583 var name = _emitTopLevelName(export, suffix: suffix);
584
585 if (export is TypeDefiningElement ||
586 export is FunctionElement ||
587 _eagerTopLevelFields.contains(export)) {
588 // classes, typedefs, functions, and eager init fields can be assigned
589 // directly.
590 // TODO(jmesserly): we don't know about eager init fields from other
591 // modules we import, so we will never go down this code path for them.
592 _moduleItems
593 .add(js.statement('#.# = #;', [libraryName, name.selector, name]));
594 }
595 }
596
597 // We only need to export main as it is the only method party of the
598 // publicly exposed JS API for a library. 654 // publicly exposed JS API for a library.
599 // TODO(jacobr): add a library level annotation indicating that all 655 // TODO(jacobr): add a library level annotation indicating that all
600 // contents of a library need to be exposed to JS. 656 // contents of a library need to be exposed to JS.
601 // https://github.com/dart-lang/sdk/issues/26368 657 // https://github.com/dart-lang/sdk/issues/26368
602
603 var export = exportedNames.get('main'); 658 var export = exportedNames.get('main');
604 659
605 if (export == null) return; 660 if (export is FunctionElement) {
606 if (export is PropertyAccessorElement) { 661 // Don't allow redefining names from this library.
607 export = (export as PropertyAccessorElement).variable; 662 if (currentNames.containsKey(export.name)) return;
663
664 var name = _emitTopLevelName(export);
665 _moduleItems.add(js.statement(
666 '#.# = #;', [emitLibraryName(currentLibrary), name.selector, name]));
608 } 667 }
609
610 // Don't allow redefining names from this library.
611 if (currentNames.containsKey(export.name)) return;
612
613 if (export.isSynthetic && export is PropertyInducingElement) {
614 _emitDeclaration(export.getter);
615 _emitDeclaration(export.setter);
616 } else {
617 _emitDeclaration(export);
618 }
619 emitExport(export);
620 } 668 }
621 669
622 @override 670 @override
623 visitAsExpression(AsExpression node) { 671 visitAsExpression(AsExpression node) {
624 Expression fromExpr = node.expression; 672 Expression fromExpr = node.expression;
625 var from = getStaticType(fromExpr); 673 var from = getStaticType(fromExpr);
626 var to = node.type.type; 674 var to = node.type.type;
627 675
628 JS.Expression jsFrom = _visit(fromExpr); 676 JS.Expression jsFrom = _visit(fromExpr);
629 if (_inWhitelistCode(node)) return jsFrom; 677 if (_inWhitelistCode(node)) return jsFrom;
(...skipping 676 matching lines...) Expand 10 before | Expand all | Expand 10 after
1306 var jsFields = fields?.map(_emitTypeScriptField)?.toList(); 1354 var jsFields = fields?.map(_emitTypeScriptField)?.toList();
1307 1355
1308 return new JS.ClassExpression(new JS.Identifier(name), heritage, methods, 1356 return new JS.ClassExpression(new JS.Identifier(name), heritage, methods,
1309 typeParams: typeParams, fields: jsFields); 1357 typeParams: typeParams, fields: jsFields);
1310 } 1358 }
1311 1359
1312 JS.Expression _emitClassHeritage(ClassElement element) { 1360 JS.Expression _emitClassHeritage(ClassElement element) {
1313 var type = element.type; 1361 var type = element.type;
1314 if (type.isObject) return null; 1362 if (type.isObject) return null;
1315 1363
1316 _loader.startTopLevel(element); 1364 _startTopLevelCodeForClass(element);
1317 1365
1318 // List of "direct" supertypes (supertype + mixins) 1366 // List of "direct" supertypes (supertype + mixins)
1319 var basetypes = [type.superclass]..addAll(type.mixins); 1367 var basetypes = [type.superclass]..addAll(type.mixins);
1320 1368
1321 // If any of these are recursive (via type parameter), defer setting 1369 // If any of these are recursive (via type parameter), defer setting
1322 // the real superclass. 1370 // the real superclass.
1323 if (basetypes.any((t) => _deferIfNeeded(t, element))) { 1371 if (basetypes.any((t) => _deferIfNeeded(t, element))) {
1324 // Fall back to raw type 1372 // Fall back to raw type
1325 basetypes = 1373 basetypes =
1326 basetypes.map((t) => fillDynamicTypeArgs(t.element.type)).toList(); 1374 basetypes.map((t) => fillDynamicTypeArgs(t.element.type)).toList();
1327 _hasDeferredSupertype.add(element); 1375 _hasDeferredSupertype.add(element);
1328 } 1376 }
1329 1377
1330 // List of "direct" JS superclasses 1378 // List of "direct" JS superclasses
1331 var baseclasses = basetypes 1379 var baseclasses = basetypes
1332 .map((t) => _emitConstructorAccess(t, nameType: false)) 1380 .map((t) => _emitConstructorAccess(t, nameType: false))
1333 .toList(); 1381 .toList();
1334 assert(baseclasses.isNotEmpty); 1382 assert(baseclasses.isNotEmpty);
1335 var heritage = (baseclasses.length == 1) 1383 var heritage = (baseclasses.length == 1)
1336 ? baseclasses.first 1384 ? baseclasses.first
1337 : _callHelper('mixin(#)', [baseclasses]); 1385 : _callHelper('mixin(#)', [baseclasses]);
1338 1386
1339 _loader.finishTopLevel(element); 1387 _finishTopLevelCodeForClass(element);
1340 1388
1341 return heritage; 1389 return heritage;
1342 } 1390 }
1343 1391
1344 /// Provide Dart getters and setters that forward to the underlying native 1392 /// Provide Dart getters and setters that forward to the underlying native
1345 /// field. Note that the Dart names are always symbolized to avoid 1393 /// field. Note that the Dart names are always symbolized to avoid
1346 /// conflicts. They will be installed as extension methods on the underlying 1394 /// conflicts. They will be installed as extension methods on the underlying
1347 /// native type. 1395 /// native type.
1348 List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) { 1396 List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) {
1349 // TODO(vsm): Can this by meta-programmed? 1397 // TODO(vsm): Can this by meta-programmed?
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after
1785 1833
1786 body.add(_callHelperStatement(code, args)); 1834 body.add(_callHelperStatement(code, args));
1787 } 1835 }
1788 } 1836 }
1789 } 1837 }
1790 1838
1791 /// Emits static fields for a class, and initialize them eagerly if possible, 1839 /// Emits static fields for a class, and initialize them eagerly if possible,
1792 /// otherwise define them as lazy properties. 1840 /// otherwise define them as lazy properties.
1793 void _emitStaticFields(List<FieldDeclaration> staticFields, 1841 void _emitStaticFields(List<FieldDeclaration> staticFields,
1794 ClassElement classElem, List<JS.Statement> body) { 1842 ClassElement classElem, List<JS.Statement> body) {
1795 var lazyStatics = <VariableDeclaration>[]; 1843 var lazyStatics = staticFields.expand((f) => f.fields.variables).toList();
1796 for (FieldDeclaration member in staticFields) {
1797 for (VariableDeclaration field in member.fields.variables) {
1798 JS.Statement eagerField = _emitConstantStaticField(classElem, field);
1799 if (eagerField != null) {
1800 body.add(eagerField);
1801 } else {
1802 lazyStatics.add(field);
1803 }
1804 }
1805 }
1806 if (lazyStatics.isNotEmpty) { 1844 if (lazyStatics.isNotEmpty) {
1807 body.add(_emitLazyFields(classElem, lazyStatics)); 1845 body.add(_emitLazyFields(classElem, lazyStatics));
1808 } 1846 }
1809 } 1847 }
1810 1848
1811 void _emitClassMetadata(List<Annotation> metadata, JS.Expression className, 1849 void _emitClassMetadata(List<Annotation> metadata, JS.Expression className,
1812 List<JS.Statement> body) { 1850 List<JS.Statement> body) {
1813 // Metadata 1851 // Metadata
1814 if (options.emitMetadata && metadata.isNotEmpty) { 1852 if (options.emitMetadata && metadata.isNotEmpty) {
1815 body.add(js.statement('#[#.metadata] = () => #;', [ 1853 body.add(js.statement('#[#.metadata] = () => #;', [
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after
2126 2164
2127 var fun = new JS.Fun( 2165 var fun = new JS.Fun(
2128 params, 2166 params,
2129 js.statement('{ return $newKeyword #(#); }', 2167 js.statement('{ return $newKeyword #(#); }',
2130 [_visit(redirect) as JS.Node, params]), 2168 [_visit(redirect) as JS.Node, params]),
2131 returnType: returnType); 2169 returnType: returnType);
2132 return annotate( 2170 return annotate(
2133 new JS.Method(name, fun, isStatic: true), node, node.element); 2171 new JS.Method(name, fun, isStatic: true), node, node.element);
2134 } 2172 }
2135 2173
2136 // For const constructors we need to ensure default values are
2137 // available for use by top-level constant initializers.
2138 ClassDeclaration cls = node.parent;
2139 if (node.constKeyword != null) _loader.startTopLevel(cls.element);
2140 var params = visitFormalParameterList(node.parameters); 2174 var params = visitFormalParameterList(node.parameters);
2141 if (node.constKeyword != null) _loader.finishTopLevel(cls.element);
2142 2175
2143 // Factory constructors are essentially static methods. 2176 // Factory constructors are essentially static methods.
2144 if (node.factoryKeyword != null) { 2177 if (node.factoryKeyword != null) {
2145 var body = <JS.Statement>[]; 2178 var body = <JS.Statement>[];
2146 var init = _emitArgumentInitializers(node, constructor: true); 2179 var init = _emitArgumentInitializers(node, constructor: true);
2147 if (init != null) body.add(init); 2180 if (init != null) body.add(init);
2148 body.add(_visit(node.body)); 2181 body.add(_visit(node.body));
2149 var fun = new JS.Fun(params, new JS.Block(body), returnType: returnType); 2182 var fun = new JS.Fun(params, new JS.Block(body), returnType: returnType);
2150 return annotate( 2183 return annotate(
2151 new JS.Method(name, fun, isStatic: true), node, node.element); 2184 new JS.Method(name, fun, isStatic: true), node, node.element);
(...skipping 28 matching lines...) Expand all
2180 List<FieldDeclaration> fields, 2213 List<FieldDeclaration> fields,
2181 Map<FieldElement, JS.TemporaryId> virtualFields) { 2214 Map<FieldElement, JS.TemporaryId> virtualFields) {
2182 var body = <JS.Statement>[]; 2215 var body = <JS.Statement>[];
2183 ClassDeclaration cls = node.parent; 2216 ClassDeclaration cls = node.parent;
2184 2217
2185 // Generate optional/named argument value assignment. These can not have 2218 // Generate optional/named argument value assignment. These can not have
2186 // side effects, and may be used by the constructor's initializers, so it's 2219 // side effects, and may be used by the constructor's initializers, so it's
2187 // nice to do them first. 2220 // nice to do them first.
2188 // Also for const constructors we need to ensure default values are 2221 // Also for const constructors we need to ensure default values are
2189 // available for use by top-level constant initializers. 2222 // available for use by top-level constant initializers.
2190 if (node.constKeyword != null) _loader.startTopLevel(cls.element);
2191 var init = _emitArgumentInitializers(node, constructor: true); 2223 var init = _emitArgumentInitializers(node, constructor: true);
2192 if (node.constKeyword != null) _loader.finishTopLevel(cls.element);
2193 if (init != null) body.add(init); 2224 if (init != null) body.add(init);
2194 2225
2195 // Redirecting constructors: these are not allowed to have initializers, 2226 // Redirecting constructors: these are not allowed to have initializers,
2196 // and the redirecting ctor invocation runs before field initializers. 2227 // and the redirecting ctor invocation runs before field initializers.
2197 var redirectCall = node.initializers.firstWhere( 2228 var redirectCall = node.initializers.firstWhere(
2198 (i) => i is RedirectingConstructorInvocation, 2229 (i) => i is RedirectingConstructorInvocation,
2199 orElse: () => null); 2230 orElse: () => null);
2200 2231
2201 if (redirectCall != null) { 2232 if (redirectCall != null) {
2202 body.add(_visit(redirectCall)); 2233 body.add(_visit(redirectCall));
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
2290 /// 2321 ///
2291 /// 1. field declaration initializer if non-const, 2322 /// 1. field declaration initializer if non-const,
2292 /// 2. field initializing parameters, 2323 /// 2. field initializing parameters,
2293 /// 3. constructor field initializers, 2324 /// 3. constructor field initializers,
2294 /// 4. initialize fields not covered in 1-3 2325 /// 4. initialize fields not covered in 1-3
2295 JS.Statement _initializeFields( 2326 JS.Statement _initializeFields(
2296 ClassDeclaration cls, 2327 ClassDeclaration cls,
2297 List<FieldDeclaration> fieldDecls, 2328 List<FieldDeclaration> fieldDecls,
2298 Map<FieldElement, JS.TemporaryId> virtualFields, 2329 Map<FieldElement, JS.TemporaryId> virtualFields,
2299 [ConstructorDeclaration ctor]) { 2330 [ConstructorDeclaration ctor]) {
2300 bool isConst = ctor != null && ctor.constKeyword != null;
2301 if (isConst) _loader.startTopLevel(cls.element);
2302
2303 // Run field initializers if they can have side-effects. 2331 // Run field initializers if they can have side-effects.
2304 var fields = new Map<FieldElement, JS.Expression>(); 2332 var fields = new Map<FieldElement, JS.Expression>();
2305 var unsetFields = new Map<FieldElement, VariableDeclaration>(); 2333 var unsetFields = new Map<FieldElement, VariableDeclaration>();
2306 for (var declaration in fieldDecls) { 2334 for (var declaration in fieldDecls) {
2307 for (var fieldNode in declaration.fields.variables) { 2335 for (var fieldNode in declaration.fields.variables) {
2308 var element = fieldNode.element; 2336 var element = fieldNode.element;
2309 if (_constants.isFieldInitConstant(fieldNode)) { 2337 if (_constants.isFieldInitConstant(fieldNode)) {
2310 unsetFields[element as FieldElement] = fieldNode; 2338 unsetFields[element as FieldElement] = fieldNode;
2311 } else { 2339 } else {
2312 fields[element as FieldElement] = _visitInitializer(fieldNode); 2340 fields[element as FieldElement] = _visitInitializer(fieldNode);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2344 } 2372 }
2345 fields[element] = value; 2373 fields[element] = value;
2346 }); 2374 });
2347 2375
2348 var body = <JS.Statement>[]; 2376 var body = <JS.Statement>[];
2349 fields.forEach((FieldElement e, JS.Expression initialValue) { 2377 fields.forEach((FieldElement e, JS.Expression initialValue) {
2350 JS.Expression access = virtualFields[e] ?? _declareMemberName(e.getter); 2378 JS.Expression access = virtualFields[e] ?? _declareMemberName(e.getter);
2351 body.add(js.statement('this.# = #;', [access, initialValue])); 2379 body.add(js.statement('this.# = #;', [access, initialValue]));
2352 }); 2380 });
2353 2381
2354 if (isConst) _loader.finishTopLevel(cls.element);
2355 return _statement(body); 2382 return _statement(body);
2356 } 2383 }
2357 2384
2358 FormalParameterList _parametersOf(node) { 2385 FormalParameterList _parametersOf(node) {
2359 // TODO(jmesserly): clean this up. If we can model ES6 spread/rest args, we 2386 // TODO(jmesserly): clean this up. If we can model ES6 spread/rest args, we
2360 // could handle argument initializers more consistently in a separate 2387 // could handle argument initializers more consistently in a separate
2361 // lowering pass. 2388 // lowering pass.
2362 if (node is ConstructorDeclaration) return node.parameters; 2389 if (node is ConstructorDeclaration) return node.parameters;
2363 if (node is MethodDeclaration) return node.parameters; 2390 if (node is MethodDeclaration) return node.parameters;
2364 if (node is FunctionDeclaration) node = node.functionExpression; 2391 if (node is FunctionDeclaration) node = node.functionExpression;
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
2513 typeParams: fn.typeParams, 2540 typeParams: fn.typeParams,
2514 returnType: fn.returnType)..sourceInformation = fn.sourceInformation; 2541 returnType: fn.returnType)..sourceInformation = fn.sourceInformation;
2515 } 2542 }
2516 2543
2517 @override 2544 @override
2518 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { 2545 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) {
2519 assert(node.parent is CompilationUnit); 2546 assert(node.parent is CompilationUnit);
2520 2547
2521 if (_externalOrNative(node)) return null; 2548 if (_externalOrNative(node)) return null;
2522 2549
2523 // If we have a getter/setter pair, they need to be defined together. 2550 if (node.isGetter || node.isSetter) {
2524 if (node.isGetter) {
2525 PropertyAccessorElement element = node.element; 2551 PropertyAccessorElement element = node.element;
2526 var props = <JS.Method>[_emitTopLevelProperty(node)]; 2552 var pairAccessor = node.isGetter
2527 var setter = element.correspondingSetter; 2553 ? element.correspondingSetter
2528 if (setter != null) { 2554 : element.correspondingGetter;
2529 props.add(_loader.emitDeclaration( 2555
2530 setter, (node) => _emitTopLevelProperty(node))); 2556 var jsCode = _emitTopLevelProperty(node);
2557 var props = <JS.Method>[jsCode];
2558 if (pairAccessor != null) {
2559 // If we have a getter/setter pair, they need to be defined together.
2560 // If this is the first one, save the generated code for later.
2561 // If this is the second one, get the saved code and emit both.
2562 var pairCode = _deferredProperties.remove(pairAccessor);
2563 if (pairCode == null) {
2564 _deferredProperties[element] = jsCode;
2565 return null;
2566 }
2567 props.add(pairCode);
2531 } 2568 }
2532 return _callHelperStatement('copyProperties(#, { # });', 2569 return _callHelperStatement('copyProperties(#, { # });',
2533 [emitLibraryName(currentLibrary), props]); 2570 [emitLibraryName(currentLibrary), props]);
2534 }
2535 if (node.isSetter) {
2536 PropertyAccessorElement element = node.element;
2537 var props = <JS.Method>[_emitTopLevelProperty(node)];
2538 var getter = element.correspondingGetter;
2539 if (getter != null) {
2540 props.add(_loader.emitDeclaration(
2541 getter, (node) => _emitTopLevelProperty(node)));
2542 }
2543 return _callHelperStatement('copyProperties(#, { # });',
2544 [emitLibraryName(currentLibrary), props]);
2545 } 2571 }
2546 2572
2547 var body = <JS.Statement>[]; 2573 var body = <JS.Statement>[];
2548 var fn = _emitFunction(node.functionExpression); 2574 var fn = _emitFunction(node.functionExpression);
2549 2575
2550 if (currentLibrary.source.isInSystemLibrary && 2576 if (currentLibrary.source.isInSystemLibrary &&
2551 _isInlineJSFunction(node.functionExpression)) { 2577 _isInlineJSFunction(node.functionExpression)) {
2552 fn = _simplifyPassThroughArrowFunCallBody(fn); 2578 fn = _simplifyPassThroughArrowFunCallBody(fn);
2553 } 2579 }
2554 2580
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
2624 if (type is FunctionType && (type.name == '' || type.name == null)) { 2650 if (type is FunctionType && (type.name == '' || type.name == null)) {
2625 return (_typeIsLoaded(type.returnType) && 2651 return (_typeIsLoaded(type.returnType) &&
2626 type.optionalParameterTypes.every(_typeIsLoaded) && 2652 type.optionalParameterTypes.every(_typeIsLoaded) &&
2627 type.namedParameterTypes.values.every(_typeIsLoaded) && 2653 type.namedParameterTypes.values.every(_typeIsLoaded) &&
2628 type.normalParameterTypes.every(_typeIsLoaded)); 2654 type.normalParameterTypes.every(_typeIsLoaded));
2629 } 2655 }
2630 if (type.isDynamic || type.isVoid || type.isBottom) return true; 2656 if (type.isDynamic || type.isVoid || type.isBottom) return true;
2631 if (type is ParameterizedType && !type.typeArguments.every(_typeIsLoaded)) { 2657 if (type is ParameterizedType && !type.typeArguments.every(_typeIsLoaded)) {
2632 return false; 2658 return false;
2633 } 2659 }
2634 return _loader.isLoaded(type.element); 2660 return !_declarationNodes.containsKey(type.element);
2635 } 2661 }
2636 2662
2637 JS.Expression _emitFunctionTagged(JS.Expression fn, DartType type, 2663 JS.Expression _emitFunctionTagged(JS.Expression fn, DartType type,
2638 {topLevel: false}) { 2664 {topLevel: false}) {
2639 var lazy = topLevel && !_typeIsLoaded(type); 2665 var lazy = topLevel && !_typeIsLoaded(type);
2640 var typeRep = _emitFunctionType(type, definite: true); 2666 var typeRep = _emitFunctionType(type, definite: true);
2641 if (lazy) { 2667 if (lazy) {
2642 return _callHelper('lazyFn(#, () => #)', [fn, typeRep]); 2668 return _callHelper('lazyFn(#, () => #)', [fn, typeRep]);
2643 } else { 2669 } else {
2644 return _callHelper('fn(#, #)', [fn, typeRep]); 2670 return _callHelper('fn(#, #)', [fn, typeRep]);
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after
2845 if (accessor == null) { 2871 if (accessor == null) {
2846 return js.commentExpression( 2872 return js.commentExpression(
2847 'Unimplemented unknown name', new JS.Identifier(node.name)); 2873 'Unimplemented unknown name', new JS.Identifier(node.name));
2848 } 2874 }
2849 2875
2850 // Get the original declaring element. If we had a property accessor, this 2876 // Get the original declaring element. If we had a property accessor, this
2851 // indirects back to a (possibly synthetic) field. 2877 // indirects back to a (possibly synthetic) field.
2852 var element = accessor; 2878 var element = accessor;
2853 if (accessor is PropertyAccessorElement) element = accessor.variable; 2879 if (accessor is PropertyAccessorElement) element = accessor.variable;
2854 2880
2855 _declareBeforeUse(element);
2856
2857 // type literal 2881 // type literal
2858 if (element is TypeDefiningElement) { 2882 if (element is TypeDefiningElement) {
2883 _declareBeforeUse(element);
2884
2859 var typeName = _emitType(fillDynamicTypeArgs(element.type)); 2885 var typeName = _emitType(fillDynamicTypeArgs(element.type));
2860 2886
2861 // If the type is a type literal expression in Dart code, wrap the raw 2887 // If the type is a type literal expression in Dart code, wrap the raw
2862 // runtime type in a "Type" instance. 2888 // runtime type in a "Type" instance.
2863 if (!_isInForeignJS && _isTypeLiteral(node)) { 2889 if (!_isInForeignJS && _isTypeLiteral(node)) {
2864 typeName = _callHelper('wrapType(#)', typeName); 2890 typeName = _callHelper('wrapType(#)', typeName);
2865 } 2891 }
2866 2892
2867 return typeName; 2893 return typeName;
2868 } 2894 }
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after
3150 // The void and dynamic types are not defined in core. 3176 // The void and dynamic types are not defined in core.
3151 if (type.isVoid) { 3177 if (type.isVoid) {
3152 return _callHelper('void'); 3178 return _callHelper('void');
3153 } else if (type.isDynamic) { 3179 } else if (type.isDynamic) {
3154 return _callHelper('dynamic'); 3180 return _callHelper('dynamic');
3155 } else if (type.isBottom) { 3181 } else if (type.isBottom) {
3156 return _callHelper('bottom'); 3182 return _callHelper('bottom');
3157 } 3183 }
3158 3184
3159 var element = type.element; 3185 var element = type.element;
3160 _declareBeforeUse(element); 3186 if (element is TypeDefiningElement) {
3187 _declareBeforeUse(element);
3188 }
3161 3189
3162 var interop = _emitJSInterop(element); 3190 var interop = _emitJSInterop(element);
3163 // Type parameters don't matter as JS interop types cannot be reified. 3191 // Type parameters don't matter as JS interop types cannot be reified.
3164 // We have to use lazy JS types because until we have proper module 3192 // We have to use lazy JS types because until we have proper module
3165 // loading for JS libraries bundled with Dart libraries, we will sometimes 3193 // loading for JS libraries bundled with Dart libraries, we will sometimes
3166 // need to load Dart libraries before the corresponding JS libraries are 3194 // need to load Dart libraries before the corresponding JS libraries are
3167 // actually loaded. 3195 // actually loaded.
3168 // Given a JS type such as: 3196 // Given a JS type such as:
3169 // @JS('google.maps.Location') 3197 // @JS('google.maps.Location')
3170 // class Location { ... } 3198 // class Location { ... }
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
3384 } 3412 }
3385 3413
3386 var accessor = resolutionMap.staticElementForIdentifier(node); 3414 var accessor = resolutionMap.staticElementForIdentifier(node);
3387 if (accessor == null) return unimplemented(); 3415 if (accessor == null) return unimplemented();
3388 3416
3389 // Get the original declaring element. If we had a property accessor, this 3417 // Get the original declaring element. If we had a property accessor, this
3390 // indirects back to a (possibly synthetic) field. 3418 // indirects back to a (possibly synthetic) field.
3391 var element = accessor; 3419 var element = accessor;
3392 if (accessor is PropertyAccessorElement) element = accessor.variable; 3420 if (accessor is PropertyAccessorElement) element = accessor.variable;
3393 3421
3394 _declareBeforeUse(element); 3422 if (element is TypeDefiningElement) {
3423 _declareBeforeUse(element);
3424 }
3395 3425
3396 if (element is LocalVariableElement || element is ParameterElement) { 3426 if (element is LocalVariableElement || element is ParameterElement) {
3397 return _emitSetLocal(node, element, rhs); 3427 return _emitSetLocal(node, element, rhs);
3398 } 3428 }
3399 3429
3400 if (element.enclosingElement is CompilationUnitElement) { 3430 if (element.enclosingElement is CompilationUnitElement) {
3401 // Top level library member. 3431 // Top level library member.
3402 return _emitSetTopLevel(node, element, rhs); 3432 return _emitSetTopLevel(node, element, rhs);
3403 } 3433 }
3404 3434
(...skipping 598 matching lines...) Expand 10 before | Expand all | Expand 10 after
4003 } 4033 }
4004 // A normal yield in a sync* 4034 // A normal yield in a sync*
4005 return jsExpr.toYieldStatement(star: star); 4035 return jsExpr.toYieldStatement(star: star);
4006 } 4036 }
4007 4037
4008 @override 4038 @override
4009 JS.Expression visitAwaitExpression(AwaitExpression node) { 4039 JS.Expression visitAwaitExpression(AwaitExpression node) {
4010 return new JS.Yield(_visit(node.expression)); 4040 return new JS.Yield(_visit(node.expression));
4011 } 4041 }
4012 4042
4043 /// This is not used--we emit top-level fields as we are emitting the
4044 /// compilation unit, see [_emitCompilationUnit].
4013 @override 4045 @override
4014 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { 4046 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
4015 for (var variable in node.variables.variables) { 4047 assert(false);
4016 _emitDeclaration(variable.element);
4017 }
4018 } 4048 }
4019 4049
4020 /// This is not used--we emit fields as we are emitting the class, 4050 /// This is not used--we emit fields as we are emitting the class,
4021 /// see [visitClassDeclaration]. 4051 /// see [visitClassDeclaration].
4022 @override 4052 @override
4023 visitFieldDeclaration(FieldDeclaration node) { 4053 visitFieldDeclaration(FieldDeclaration node) {
4024 assert(false); 4054 assert(false);
4025 } 4055 }
4026 4056
4027 @override 4057 @override
(...skipping 15 matching lines...) Expand all
4043 4073
4044 @override 4074 @override
4045 visitVariableDeclarationList(VariableDeclarationList node) { 4075 visitVariableDeclarationList(VariableDeclarationList node) {
4046 return new JS.VariableDeclarationList( 4076 return new JS.VariableDeclarationList(
4047 'let', _visitList(node.variables) as List<JS.VariableInitialization>); 4077 'let', _visitList(node.variables) as List<JS.VariableInitialization>);
4048 } 4078 }
4049 4079
4050 @override 4080 @override
4051 visitVariableDeclaration(VariableDeclaration node) { 4081 visitVariableDeclaration(VariableDeclaration node) {
4052 if (node.element is PropertyInducingElement) { 4082 if (node.element is PropertyInducingElement) {
4053 // Static and instance fields are handled elsewhere. 4083 // All fields are handled elsewhere.
4054 assert(node.element is TopLevelVariableElement); 4084 assert(false);
4055 return _emitTopLevelField(node); 4085 return null;
4056 } 4086 }
4057 4087
4058 var name = new JS.Identifier(node.name.name, 4088 var name = new JS.Identifier(node.name.name,
4059 type: emitTypeRef( 4089 type: emitTypeRef(
4060 resolutionMap.elementDeclaredByVariableDeclaration(node).type)); 4090 resolutionMap.elementDeclaredByVariableDeclaration(node).type));
4061 return new JS.VariableInitialization(name, _visitInitializer(node)); 4091 return new JS.VariableInitialization(name, _visitInitializer(node));
4062 } 4092 }
4063 4093
4064 /// Try to emit a constant static field. 4094 /// Emits a list of top-level field.
4065 /// 4095 void _emitTopLevelFields(List<VariableDeclaration> fields) {
4066 /// If the field's initializer does not cause side effects, and if all of 4096 _moduleItems.add(_emitLazyFields(currentLibrary, fields));
4067 /// dependencies are safe to refer to while we are initializing the class,
4068 /// then we can initialize it eagerly:
4069 ///
4070 /// // Baz must be const constructor, and the name "Baz" must be defined
4071 /// // by this point.
4072 /// Foo.bar = dart.const(new Baz(42));
4073 ///
4074 /// Otherwise, we'll need to generate a lazy-static field. That ensures
4075 /// correct visible behavior, as well as avoiding referencing something that
4076 /// isn't defined yet (because it is defined later in the module).
4077 JS.Statement _emitConstantStaticField(
4078 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
4079 PropertyInducingElement element = field.element;
4080 assert(element.isStatic);
4081
4082 _loader.startCheckingReferences();
4083 JS.Expression jsInit = _visitInitializer(field);
4084 bool isLoaded = _loader.finishCheckingReferences();
4085
4086 bool eagerInit =
4087 isLoaded && (field.isConst || _constants.isFieldInitConstant(field));
4088
4089 var fieldName = field.name.name;
4090 if (eagerInit &&
4091 !JS.invalidStaticFieldName(fieldName) &&
4092 !_classProperties.staticFieldOverrides.contains(element)) {
4093 return annotate(
4094 js.statement('#.# = #;', [
4095 _emitTopLevelName(classElem),
4096 _emitMemberName(fieldName, isStatic: true),
4097 jsInit
4098 ]),
4099 field,
4100 field.element);
4101 }
4102
4103 // This means it should be treated as a lazy field.
4104 // TODO(jmesserly): we're throwing away the initializer expression,
4105 // which will force us to regenerate it.
4106 return null;
4107 } 4097 }
4108 4098
4109 /// Emits a top-level field. 4099 /// Treat dart:_runtime fields as safe to eagerly evaluate.
4110 JS.ModuleItem _emitTopLevelField(VariableDeclaration field) { 4100 // TODO(jmesserly): it'd be nice to avoid this special case.
4111 TopLevelVariableElement element = field.element; 4101 void _emitInternalSdkFields(List<VariableDeclaration> fields) {
4112 assert(element.isStatic); 4102 for (var field in fields) {
4113 4103 _moduleItems.add(annotate(
4114 bool eagerInit; 4104 js.statement('# = #;',
4115 JS.Expression jsInit; 4105 [_emitTopLevelName(field.element), _visitInitializer(field)]),
4116 if (field.isConst || _constants.isFieldInitConstant(field)) { 4106 field,
4117 // If the field is constant, try and generate it at the top level. 4107 field.element));
4118 _loader.startTopLevel(element);
4119 jsInit = _visitInitializer(field);
4120 _loader.finishTopLevel(element);
4121 eagerInit = _loader.isLoaded(element);
4122 } else {
4123 // TODO(jmesserly): we're visiting the initializer here, and again
4124 // later on when we emit lazy fields. That seems busted.
4125 jsInit = _visitInitializer(field);
4126 eagerInit = false;
4127 } 4108 }
4128
4129 // Treat dart:runtime stuff as safe to eagerly evaluate.
4130 // TODO(jmesserly): it'd be nice to avoid this special case.
4131 var isJSTopLevel = field.isFinal && isSdkInternalRuntime(element.library);
4132 if (eagerInit || isJSTopLevel) {
4133 // Remember that we emitted it this way, so re-export can take advantage
4134 // of this fact.
4135 _eagerTopLevelFields.add(element);
4136
4137 return annotate(
4138 js.statement('# = #;', [_emitTopLevelName(element), jsInit]),
4139 field,
4140 element);
4141 }
4142
4143 assert(element.library == currentLibrary);
4144 return _emitLazyFields(element.library, [field]);
4145 } 4109 }
4146 4110
4147 JS.Expression _visitInitializer(VariableDeclaration node) { 4111 JS.Expression _visitInitializer(VariableDeclaration node) {
4148 var value = _visit(node.initializer); 4112 var value = _visit(node.initializer);
4149 // explicitly initialize to null, to avoid getting `undefined`. 4113 // explicitly initialize to null, to avoid getting `undefined`.
4150 // TODO(jmesserly): do this only for vars that aren't definitely assigned. 4114 // TODO(jmesserly): do this only for vars that aren't definitely assigned.
4151 return value ?? new JS.LiteralNull(); 4115 return value ?? new JS.LiteralNull();
4152 } 4116 }
4153 4117
4154 JS.Statement _emitLazyFields( 4118 JS.Statement _emitLazyFields(
4155 Element target, List<VariableDeclaration> fields) { 4119 Element target, List<VariableDeclaration> fields) {
4156 var methods = []; 4120 var methods = [];
4157 for (var node in fields) { 4121 for (var node in fields) {
4158 var name = node.name.name; 4122 var name = node.name.name;
4159 var element = node.element; 4123 var element = node.element;
4124 assert(element.getAncestor((e) => identical(e, target)) != null,
4125 "target is $target but enclosing element is ${element.enclosingElement }");
4160 var access = _emitMemberName(name, isStatic: true); 4126 var access = _emitMemberName(name, isStatic: true);
4161 methods.add(annotate( 4127 methods.add(annotate(
4162 new JS.Method( 4128 new JS.Method(
4163 access, 4129 access,
4164 js.call('function() { return #; }', _visitInitializer(node)) 4130 js.call('function() { return #; }', _visitInitializer(node))
4165 as JS.Fun, 4131 as JS.Fun,
4166 isGetter: true), 4132 isGetter: true),
4167 node, 4133 node,
4168 _findAccessor(element, getter: true))); 4134 _findAccessor(element, getter: true)));
4169 4135
(...skipping 1757 matching lines...) Expand 10 before | Expand all | Expand 10 after
5927 }; 5893 };
5928 5894
5929 static Set<String> _uncheckedWhitelistCalls = new Set() 5895 static Set<String> _uncheckedWhitelistCalls = new Set()
5930 ..add('ng_zone_impl.dart') 5896 ..add('ng_zone_impl.dart')
5931 ..add('stack_zone_specification.dart') 5897 ..add('stack_zone_specification.dart')
5932 ..add('view_manager.dart') 5898 ..add('view_manager.dart')
5933 ..add('view.dart'); 5899 ..add('view.dart');
5934 5900
5935 bool _inWhitelistCode(AstNode node, {isCall: false}) { 5901 bool _inWhitelistCode(AstNode node, {isCall: false}) {
5936 if (!options.useAngular2Whitelist) return false; 5902 if (!options.useAngular2Whitelist) return false;
5937 var path = _loader.currentElement.source.fullName; 5903 var path = currentElement.source.fullName;
5938 var filename = path.split("/").last; 5904 var filename = path.split("/").last;
5939 if (_uncheckedWhitelist.containsKey(filename)) { 5905 if (_uncheckedWhitelist.containsKey(filename)) {
5940 var whitelisted = _uncheckedWhitelist[filename]; 5906 var whitelisted = _uncheckedWhitelist[filename];
5941 if (whitelisted == null) return true; 5907 if (whitelisted == null) return true;
5942 var enclosing = node; 5908 var enclosing = node;
5943 while (enclosing != null && 5909 while (enclosing != null &&
5944 !(enclosing is ClassMember || enclosing is FunctionDeclaration)) { 5910 !(enclosing is ClassMember || enclosing is FunctionDeclaration)) {
5945 enclosing = enclosing.parent; 5911 enclosing = enclosing.parent;
5946 } 5912 }
5947 String name = (enclosing as dynamic)?.element?.name; 5913 String name = (enclosing as dynamic)?.element?.name;
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
6069 if (targetIdentifier.staticElement is! PrefixElement) return false; 6035 if (targetIdentifier.staticElement is! PrefixElement) return false;
6070 var prefix = targetIdentifier.staticElement as PrefixElement; 6036 var prefix = targetIdentifier.staticElement as PrefixElement;
6071 6037
6072 // The library the prefix is referring to must come from a deferred import. 6038 // The library the prefix is referring to must come from a deferred import.
6073 var containingLibrary = resolutionMap 6039 var containingLibrary = resolutionMap
6074 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) 6040 .elementDeclaredByCompilationUnit(target.root as CompilationUnit)
6075 .library; 6041 .library;
6076 var imports = containingLibrary.getImportsWithPrefix(prefix); 6042 var imports = containingLibrary.getImportsWithPrefix(prefix);
6077 return imports.length == 1 && imports[0].isDeferred; 6043 return imports.length == 1 && imports[0].isDeferred;
6078 } 6044 }
OLDNEW
« no previous file with comments | « pkg/dev_compiler/lib/sdk/ddc_sdk.sum ('k') | pkg/dev_compiler/lib/src/compiler/element_loader.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698