Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |