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

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

Issue 1879373004: Implement modular compilation (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 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
« no previous file with comments | « lib/src/compiler/ast_builder.dart ('k') | lib/src/compiler/command.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; 5 import 'dart:collection' show HashMap, HashSet;
6 6
7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
8 import 'package:analyzer/dart/ast/token.dart'; 8 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
9 import 'package:analyzer/dart/element/element.dart'; 9 import 'package:analyzer/dart/element/element.dart';
10 import 'package:analyzer/dart/element/visitor.dart';
11 import 'package:analyzer/dart/element/type.dart'; 10 import 'package:analyzer/dart/element/type.dart';
12 import 'package:analyzer/dart/ast/ast.dart' hide ConstantEvaluator; 11 import 'package:analyzer/dart/ast/ast.dart' hide ConstantEvaluator;
13 import 'package:analyzer/src/generated/constant.dart'; 12
14 //TODO(leafp): Remove deprecated dependency 13 //TODO(leafp): Remove deprecated dependency
15 //ignore: DEPRECATED_MEMBER_USE 14 //ignore: DEPRECATED_MEMBER_USE
16 import 'package:analyzer/src/generated/element.dart' 15 import 'package:analyzer/src/generated/element.dart'
17 show DynamicElementImpl, DynamicTypeImpl, LocalVariableElementImpl; 16 show DynamicTypeImpl, LocalVariableElementImpl;
18 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext; 17 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
19 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; 18 import 'package:analyzer/src/generated/resolver.dart'
20 import 'package:analyzer/src/dart/ast/token.dart' 19 show TypeProvider, NamespaceBuilder;
21 show StringToken, Token, TokenType; 20 import 'package:analyzer/src/dart/ast/token.dart' show StringToken;
22 import 'package:analyzer/src/generated/type_system.dart' 21 import 'package:analyzer/src/generated/type_system.dart'
23 show StrongTypeSystemImpl; 22 show StrongTypeSystemImpl;
24 import 'package:analyzer/src/task/strong/info.dart'; 23 import 'package:analyzer/src/summary/summarize_elements.dart'
24 show PackageBundleAssembler;
25 import 'package:analyzer/src/task/strong/info.dart' show DynamicInvoke;
26
27 import '../js_ast/js_ast.dart' as JS;
28 import '../js_ast/js_ast.dart' show js;
29 import '../closure/closure_annotator.dart' show ClosureAnnotator;
25 30
26 import 'ast_builder.dart' show AstBuilder; 31 import 'ast_builder.dart' show AstBuilder;
27 import 'reify_coercions.dart' show CoercionReifier, Tuple2; 32 import 'compiler.dart'
28 33 show BuildUnit, CompilerOptions, JSModuleFile, ModuleFormat;
29 import '../js/js_ast.dart' as JS; 34 import 'element_helpers.dart';
30 import '../js/js_ast.dart' show js; 35 import 'element_loader.dart' show ElementLoader;
31 36 import 'extension_types.dart' show ExtensionTypeSet;
32 import '../closure/closure_annotator.dart' show ClosureAnnotator; 37 import 'js_field_storage.dart' show findFieldsNeedingStorage;
33 import '../compiler.dart'
34 show AbstractCompiler, corelibOrder, getCorelibModuleName;
35 import '../options.dart' show CodegenOptions;
36 import '../utils.dart';
37
38 import 'js_field_storage.dart';
39 import 'js_interop.dart'; 38 import 'js_interop.dart';
40 import 'js_names.dart' as JS; 39 import 'js_names.dart' as JS;
41 import 'js_metalet.dart' as JS; 40 import 'js_metalet.dart' as JS;
42 import 'js_module_item_order.dart'; 41 import 'js_typeref_codegen.dart' show JsTypeRefCodegen;
43 import 'js_names.dart'; 42 import 'module_builder.dart'
44 import 'js_printer.dart' show writeJsLibrary; 43 show LegacyModuleBuilder, NodeModuleBuilder, pathToJSIdentifier;
45 import 'js_typeref_codegen.dart'; 44 import 'nullable_type_inference.dart' show NullableTypeInference;
46 import 'module_builder.dart'; 45 import 'reify_coercions.dart' show CoercionReifier;
47 import 'nullable_type_inference.dart'; 46 import 'side_effect_analysis.dart' show ConstFieldVisitor, isStateless;
48 import 'side_effect_analysis.dart'; 47 import 'source_map_printer.dart' show SourceMapPrintingContext;
48 import 'package:source_maps/source_maps.dart';
49 49
50 // Various dynamic helpers we call. 50 class CodeGenerator extends GeneralizingAstVisitor
51 // If renaming these, make sure to check other places like the 51 with ClosureAnnotator, JsTypeRefCodegen, NullableTypeInference {
52 // _runtime.js file and comments. 52 final AnalysisContext context;
53 // TODO(jmesserly): ideally we'd have a "dynamic call" dart library we can 53 final CompilerOptions options;
54 // import and generate calls to, rather than dart_runtime.js 54 final rules = new StrongTypeSystemImpl();
55 const DPUT = 'dput';
56 const DLOAD = 'dload';
57 const DINDEX = 'dindex';
58 const DSETINDEX = 'dsetindex';
59 const DCALL = 'dcall';
60 const DSEND = 'dsend';
61 55
62 class JSCodegenVisitor extends GeneralizingAstVisitor 56 /// The set of libraries we are currently compiling, and the temporaries used
63 with ClosureAnnotator, JsTypeRefCodegen, NullableTypeInference { 57 /// to refer to them.
64 final AbstractCompiler compiler; 58 ///
65 final CodegenOptions options; 59 /// We sometimes special case codegen for a single library, as it simplifies
66 final LibraryElement currentLibrary; 60 /// name scoping requirements.
67 final StrongTypeSystemImpl rules; 61 final _libraries = new Map<LibraryElement, JS.Identifier>();
62
63 /// Imported libraries, and the temporaries used to refer to them.
64 final _imports = new Map<LibraryElement, JS.TemporaryId>();
65
66 /// The list of output module items, in the order they need to be emitted in.
67 final _moduleItems = <JS.ModuleItem>[];
68 68
69 /// The global extension type table. 69 /// The global extension type table.
70 final ExtensionTypeSet _extensionTypes; 70 final ExtensionTypeSet _extensionTypes;
71 71
72 /// Information that is precomputed for this library, indicates which fields 72 /// Information that is precomputed for this library, indicates which fields
73 /// need storage slots. 73 /// need storage slots.
74 final HashSet<FieldElement> _fieldsNeedingStorage; 74 HashSet<FieldElement> _fieldsNeedingStorage;
75 75
76 /// The variable for the target of the current `..` cascade expression. 76 /// The variable for the target of the current `..` cascade expression.
77 /// 77 ///
78 /// Usually a [SimpleIdentifier], but it can also be other expressions 78 /// Usually a [SimpleIdentifier], but it can also be other expressions
79 /// that are safe to evaluate multiple times, such as `this`. 79 /// that are safe to evaluate multiple times, such as `this`.
80 Expression _cascadeTarget; 80 Expression _cascadeTarget;
81 81
82 /// The variable for the current catch clause 82 /// The variable for the current catch clause
83 SimpleIdentifier _catchParameter; 83 SimpleIdentifier _catchParameter;
84 84
85 /// In an async* function, this represents the stream controller parameter. 85 /// In an async* function, this represents the stream controller parameter.
86 JS.TemporaryId _asyncStarController; 86 JS.TemporaryId _asyncStarController;
87 87
88 /// Imported libraries, and the temporaries used to refer to them. 88 final _privateNames =
89 final _imports = new Map<LibraryElement, JS.TemporaryId>(); 89 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>();
90 final _exports = <String, String>{};
91 final _properties = <FunctionDeclaration>[];
92 final _privateNames = new HashMap<String, JS.TemporaryId>();
93 final _moduleItems = <JS.Statement>[];
94 final _temps = new HashMap<Element, JS.TemporaryId>(); 90 final _temps = new HashMap<Element, JS.TemporaryId>();
95 final _qualifiedIds = new List<Tuple2<Element, JS.MaybeQualifiedId>>(); 91
96
97 /// The name for the library's exports inside itself.
98 /// `exports` was chosen as the most similar to ES module patterns.
99 final _dartxVar = new JS.Identifier('dartx'); 92 final _dartxVar = new JS.Identifier('dartx');
100 final _exportsVar = new JS.TemporaryId('exports');
101 final _runtimeLibVar = new JS.Identifier('dart'); 93 final _runtimeLibVar = new JS.Identifier('dart');
102 final namedArgumentTemp = new JS.TemporaryId('opts'); 94 final namedArgumentTemp = new JS.TemporaryId('opts');
103 95
104 final TypeProvider _types; 96 final _hasDeferredSupertype = new HashSet<ClassElement>();
97
98 /// The type provider from the current Analysis [context].
99 final TypeProvider types;
100
101 final LibraryElement dartCoreLibrary;
102 final LibraryElement dartJSLibrary;
103
104 /// The dart:async `StreamIterator<>` type.
105 final InterfaceType _asyncStreamIterator;
106
107 /// The dart:_interceptors JSArray element.
108 final ClassElement _jsArray;
105 109
106 ConstFieldVisitor _constField; 110 ConstFieldVisitor _constField;
107 111
108 ModuleItemLoadOrder _loader;
109
110 /// _interceptors.JSArray<E>, used for List literals.
111 ClassElement _jsArray;
112
113 /// The current function body being compiled. 112 /// The current function body being compiled.
114 FunctionBody _currentFunction; 113 FunctionBody _currentFunction;
115 114
116 /// The default value of the module object. See [visitLibraryDirective]. 115 /// Helper class for emitting elements in the proper order to allow
117 String _jsModuleValue; 116 /// JS to load the module.
118 117 ElementLoader _loader;
119 bool _isDartRuntime; 118
120 119 BuildUnit _buildUnit;
121 JSCodegenVisitor(AbstractCompiler compiler, this.rules, this.currentLibrary, 120
122 this._extensionTypes, this._fieldsNeedingStorage) 121 CodeGenerator(AnalysisContext c, this.options, this._extensionTypes)
123 : compiler = compiler, 122 : context = c,
124 options = compiler.options.codegenOptions, 123 types = c.typeProvider,
125 _types = compiler.context.typeProvider { 124 _asyncStreamIterator =
126 _loader = new ModuleItemLoadOrder(_emitModuleItem); 125 _getLibrary(c, 'dart:async').getType('StreamIterator').type,
127 126 _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'),
128 var context = compiler.context; 127 dartCoreLibrary = _getLibrary(c, 'dart:core'),
129 var src = context.sourceFactory.forUri('dart:_interceptors'); 128 dartJSLibrary = _getLibrary(c, 'dart:js');
130 var interceptors = context.computeLibraryElement(src); 129
131 _jsArray = interceptors.getType('JSArray'); 130 LibraryElement get currentLibrary => _loader.currentElement.library;
132 _isDartRuntime = currentLibrary.source.uri.toString() == 'dart:_runtime'; 131
133 } 132 /// The main entry point to JavaScript code generation.
134 133 ///
135 TypeProvider get types => _types; 134 /// Takes the metadata for the build unit, as well as resolved trees and
136 135 /// errors, and computes the output module code and optionally the source map.
137 JS.Program emitLibrary(List<CompilationUnit> units) { 136 JSModuleFile compile(BuildUnit unit, List<CompilationUnit> compilationUnits,
138 // Modify the AST to make coercions explicit. 137 List<String> errors) {
139 units = new CoercionReifier().reify(units); 138 _buildUnit = unit;
140 139
141 units.last.directives.forEach(_visit); 140 var jsTree = _emitModule(compilationUnits);
142 141 var codeAndSourceMap = _writeJSText(unit, jsTree);
143 // Rather than directly visit declarations, we instead use [_loader] to 142
144 // visit them. It has the ability to sort elements on demand, so 143 List<int> summary;
145 // dependencies between top level items are handled with a minimal 144 if (options.summarizeApi) {
146 // reordering of the user's input code. The loader will call back into 145 var assembler = new PackageBundleAssembler();
147 // this visitor via [_emitModuleItem] when it's ready to visit the item 146 compilationUnits
148 // for real. 147 .map((u) => u.element.library)
149 _loader.collectElements(currentLibrary, units); 148 .toSet()
150 149 .forEach(assembler.serializeLibraryElement);
150 summary = assembler.assemble().toBuffer();
151 }
152
153 return new JSModuleFile(
154 unit.name, errors, codeAndSourceMap.e0, codeAndSourceMap.e1, summary);
155 }
156
157 Tuple2<String, Map> _writeJSText(BuildUnit unit, JS.Program jsTree) {
158 var opts = new JS.JavaScriptPrintingOptions(
159 emitTypes: options.closure,
160 allowKeywordsInProperties: true,
161 allowSingleLineIfStatements: true);
162 JS.SimpleJavaScriptPrintingContext printer;
163 SourceMapBuilder sourceMap;
164 if (options.sourceMap) {
165 var sourceMapContext = new SourceMapPrintingContext();
166 sourceMap = sourceMapContext.sourceMap;
167 printer = sourceMapContext;
168 } else {
169 printer = new JS.SimpleJavaScriptPrintingContext();
170 }
171
172 jsTree.accept(new JS.Printer(opts, printer,
173 localNamer: new JS.TemporaryNamer(jsTree)));
174
175 if (options.sourceMap && options.sourceMapComment) {
176 printer.emit('\n//# sourceMappingURL=${unit.name}.js.map\n');
177 }
178
179 return new Tuple2(printer.getText(), sourceMap?.build(unit.name + '.js'));
180 }
181
182 JS.Program _emitModule(List<CompilationUnit> compilationUnits) {
183 if (_moduleItems.isNotEmpty) {
184 throw new StateError('Can only call emitModule once.');
185 }
186
187 _fieldsNeedingStorage = findFieldsNeedingStorage(
188 compilationUnits.map((u) => u.element), _extensionTypes);
189
190 // Transform the AST to make coercions explicit.
191 compilationUnits = CoercionReifier.reify(compilationUnits);
192
193 // Initialize our library variables.
194 var items = <JS.ModuleItem>[];
195 for (var unit in compilationUnits) {
196 var library = unit.element.library;
197 if (unit.element != library.definingCompilationUnit) continue;
198
199 var libraryTemp = _isDartRuntime(library)
200 ? _runtimeLibVar
201 : new JS.TemporaryId(jsLibraryName(library));
202 _libraries[library] = libraryTemp;
203 items.add(new JS.ExportDeclaration(
204 js.call('const # = Object.create(null)', [libraryTemp])));
205
206 // dart:_runtime has a magic module that holds extenstion method symbols.
207 // TODO(jmesserly): find a cleaner design for this.
208 if (_isDartRuntime(library)) {
209 items.add(new JS.ExportDeclaration(
210 js.call('const # = Object.create(null)', [_dartxVar])));
211 }
212 }
213
214 // Collect all Element -> Node mappings, in case we need to forward declare
215 // any nodes.
216 var nodes = new HashMap<Element, AstNode>.identity();
217 compilationUnits.map(_collectElements).forEach(nodes.addAll);
218 _loader = new ElementLoader(_emitModuleItem, nodes);
219
220 // Add implicit dart:core dependency so it is first.
221 emitLibraryName(dartCoreLibrary);
222
223 //
224 // Visit each compilation unit and emit its code.
225 //
226 // NOTE: declarations are not necessarily emitted in this order.
227 // Order will be changed as needed so the resulting code can execute.
228 // This is done by forward declaring items.
229 compilationUnits.forEach(visitCompilationUnit);
230
231 // Declare imports
232 _finishImports(items);
233
234 // Add the module's code (produced by visiting compilation units, above)
235 _copyAndFlattenBlocks(items, _moduleItems);
236
237 // Build the module.
238 var module = new JS.Program(items, name: _buildUnit.name);
239
240 // Optional: lower module format. Otherwise just return it.
241 switch (options.moduleFormat) {
242 case ModuleFormat.legacy:
243 return new LegacyModuleBuilder().build(module);
244 case ModuleFormat.node:
245 return new NodeModuleBuilder().build(module);
246 case ModuleFormat.es6:
247 return module;
248 }
249 }
250
251 /// Flattens blocks in [items] to a single list.
252 ///
253 /// This will not flatten blocks that are marked as being scopes.
254 void _copyAndFlattenBlocks(
255 List<JS.ModuleItem> result, Iterable<JS.ModuleItem> items) {
256 for (var item in items) {
257 if (item is JS.Block && !item.isScope) {
258 _copyAndFlattenBlocks(result, item.statements);
259 } else {
260 result.add(item);
261 }
262 }
263 }
264
265 String _libraryToModule(LibraryElement library) {
266 assert(!_libraries.containsKey(library));
267 var source = library.source;
268 // TODO(jmesserly): we need to split out HTML.
269 if (source.uri.scheme == 'dart') {
270 return 'dart_sdk';
271 }
272 var moduleName = _buildUnit.libraryToModule(source);
273 if (moduleName == null) {
274 throw new StateError('Could not find module containing "$library".');
275 }
276 return moduleName;
277 }
278
279 void _finishImports(List<JS.ModuleItem> items) {
280 var modules = new Map<String, List<LibraryElement>>();
281
282 for (var import in _imports.keys) {
283 modules.putIfAbsent(_libraryToModule(import), () => []).add(import);
284 }
285
286 String coreModuleName;
287 if (!_libraries.containsKey(dartCoreLibrary)) {
288 coreModuleName = _libraryToModule(dartCoreLibrary);
289 }
290 modules.forEach((module, libraries) {
291 // Generate import directives.
292 //
293 // Our import variables are temps and can get renamed. Since our renaming
294 // is integrated into js_ast, it is aware of this possibility and will
295 // generate an "as" if needed. For example:
296 //
297 // import {foo} from 'foo'; // if no rename needed
298 // import {foo as foo$} from 'foo'; // if rename was needed
299 //
300 var imports =
301 libraries.map((l) => new JS.NameSpecifier(_imports[l])).toList();
302 if (module == coreModuleName) {
303 imports.add(new JS.NameSpecifier(_runtimeLibVar));
304 imports.add(new JS.NameSpecifier(_dartxVar));
305 }
306 items.add(new JS.ImportDeclaration(
307 namedImports: imports, from: js.string(module, "'")));
308 });
309 }
310
311 /// Collect toplevel elements and nodes we need to emit, and returns
312 /// an ordered map of these.
313 static Map<Element, AstNode> _collectElements(CompilationUnit unit) {
314 var map = <Element, AstNode>{};
315 for (var declaration in unit.declarations) {
316 if (declaration is TopLevelVariableDeclaration) {
317 for (var field in declaration.variables.variables) {
318 map[field.element] = field;
319 }
320 } else {
321 map[declaration.element] = declaration;
322 }
323 }
324 return map;
325 }
326
327 void _emitModuleItem(AstNode node) {
151 // TODO(jmesserly): ideally we could do this at a smaller granularity. 328 // TODO(jmesserly): ideally we could do this at a smaller granularity.
152 // We'll need to be consistent about when we're generating functions, and 329 // We'll need to be consistent about when we're generating functions, and
153 // only run this on the outermost function. 330 // only run this on the outermost function.
154 inferNullableTypesInLibrary(units); 331 inferNullableTypes(node);
155
156 _constField = new ConstFieldVisitor(types, currentLibrary.source);
157
158 for (var unit in units) {
159 for (var decl in unit.declarations) {
160 if (decl is TopLevelVariableDeclaration) {
161 visitTopLevelVariableDeclaration(decl);
162 } else {
163 _loader.loadDeclaration(decl, decl.element);
164 }
165 }
166 }
167
168 // Flush any unwritten fields/properties.
169 _flushLibraryProperties(_moduleItems);
170
171 // Mark all qualified names as qualified or not, depending on if they need
172 // to be loaded lazily or not.
173 for (var elementIdPairs in _qualifiedIds) {
174 var element = elementIdPairs.e0;
175 var id = elementIdPairs.e1;
176 id.setQualified(!_loader.isLoaded(element));
177 }
178
179 var moduleBuilder = new ModuleBuilder(options.moduleFormat);
180
181 _exports.forEach(moduleBuilder.addExport);
182
183 var currentModuleName = compiler.getModuleName(currentLibrary.source.uri);
184 var items = <JS.ModuleItem>[];
185 if (!_isDartRuntime) {
186 if (currentLibrary.source.isInSystemLibrary) {
187 // Force the import order of runtime libs.
188 // TODO(ochafik): Reduce this to a minimum.
189 for (var libUri in corelibOrder.reversed) {
190 var moduleName = compiler.getModuleName(libUri);
191 if (moduleName == currentModuleName) continue;
192 moduleBuilder.addImport(moduleName, null);
193 }
194 }
195 moduleBuilder.addImport('dart/_runtime', _runtimeLibVar);
196
197 var dartxImport =
198 js.statement("let # = #.dartx;", [_dartxVar, _runtimeLibVar]);
199 items.add(dartxImport);
200 }
201 items.addAll(_moduleItems);
202
203 _imports.forEach((LibraryElement lib, JS.TemporaryId temp) {
204 moduleBuilder.addImport(compiler.getModuleName(lib.source.uri), temp,
205 isLazy: _isDartRuntime || !_loader.libraryIsLoaded(lib));
206 });
207
208 // TODO(jmesserly): scriptTag support.
209 // Enable this if we know we're targetting command line environment?
210 // It doesn't work in browser.
211 // var jsBin = compiler.options.runnerOptions.v8Binary;
212 // String scriptTag = null;
213 // if (library.library.scriptTag != null) scriptTag = '/usr/bin/env $jsBin';
214 return moduleBuilder.build(
215 currentModuleName, _jsModuleValue, _exportsVar, items);
216 }
217
218 void _emitModuleItem(AstNode node) {
219 // Attempt to group adjacent properties.
220 if (node is! FunctionDeclaration) _flushLibraryProperties(_moduleItems);
221 332
222 var code = _visit(node); 333 var code = _visit(node);
223 if (code != null) _moduleItems.add(code); 334 if (code != null) _moduleItems.add(code);
224 } 335 }
225 336
226 @override 337 @override
227 void visitLibraryDirective(LibraryDirective node) { 338 void visitCompilationUnit(CompilationUnit unit) {
228 assert(_jsModuleValue == null); 339 _constField = new ConstFieldVisitor(types, unit.element.source);
229 340
230 var jsName = findAnnotation(node.element, isJSAnnotation); 341 for (var declaration in unit.declarations) {
231 _jsModuleValue = 342 var element = declaration.element;
232 getConstantField(jsName, 'name', types.stringType)?.toStringValue(); 343 if (element != null) {
233 } 344 _loader.emitDeclaration(element);
345 } else {
346 declaration.accept(this);
347 }
348 }
349 for (var directive in unit.directives) {
350 directive.accept(this);
351 }
352 }
353
354 @override
355 void visitLibraryDirective(LibraryDirective node) {}
234 356
235 @override 357 @override
236 void visitImportDirective(ImportDirective node) { 358 void visitImportDirective(ImportDirective node) {
237 // Nothing to do yet, but we'll want to convert this to an ES6 import once 359 // We don't handle imports here.
238 // we have support for modules. 360 //
361 // Instead, we collect imports whenever we need to generate a reference
362 // to another library. This has the effect of collecting the actually used
363 // imports.
364 //
365 // TODO(jmesserly): if this is a prefixed import, consider adding the prefix
366 // as an alias?
239 } 367 }
240 368
241 @override 369 @override
242 void visitPartDirective(PartDirective node) {} 370 void visitPartDirective(PartDirective node) {}
371
243 @override 372 @override
244 void visitPartOfDirective(PartOfDirective node) {} 373 void visitPartOfDirective(PartOfDirective node) {}
245 374
246 @override 375 @override
247 void visitExportDirective(ExportDirective node) { 376 void visitExportDirective(ExportDirective node) {
248 var exportName = emitLibraryName(node.uriElement); 377 ExportElement element = node.element;
249 378 var currentLibrary = element.library;
250 var currentLibNames = currentLibrary.publicNamespace.definedNames; 379
251 380 var currentNames = currentLibrary.publicNamespace.definedNames;
252 var args = [_exportsVar, exportName]; 381 var exportedNames =
253 if (node.combinators.isNotEmpty) { 382 new NamespaceBuilder().createExportNamespaceForDirective(element);
254 var shownNames = <JS.Expression>[]; 383
255 var hiddenNames = <JS.Expression>[]; 384 // TODO(jmesserly): we could collect all of the names for bulk re-export,
256 385 // but this is easier to implement for now.
257 var show = node.combinators.firstWhere((c) => c is ShowCombinator, 386 void emitExport(Element export, {String suffix: ''}) {
258 orElse: () => null) as ShowCombinator; 387 var name = _emitTopLevelName(export, suffix: suffix);
259 var hide = node.combinators.firstWhere((c) => c is HideCombinator, 388 _moduleItems.add(js.statement(
260 orElse: () => null) as HideCombinator; 389 '#.# = #;', [emitLibraryName(currentLibrary), name.selector, name]));
261 if (show != null) { 390 }
262 shownNames.addAll(show.shownNames 391
263 .map((i) => i.name) 392 for (var export in exportedNames.definedNames.values) {
264 .where((s) => !currentLibNames.containsKey(s)) 393 // Don't allow redefining names from this library.
265 .map((s) => js.string(s, "'"))); 394 if (currentNames.containsKey(export.name)) continue;
266 } 395
267 if (hide != null) { 396 _loader.emitDeclaration(export);
268 hiddenNames.addAll(hide.hiddenNames.map((i) => js.string(i.name, "'"))); 397 if (export is ClassElement && export.typeParameters.isNotEmpty) {
269 } 398 // Export the generic name as well.
270 args.add(new JS.ArrayInitializer(shownNames)); 399 // TODO(jmesserly): revisit generic classes
271 args.add(new JS.ArrayInitializer(hiddenNames)); 400 emitExport(export, suffix: r'$');
272 } 401 }
273 402 emitExport(export);
274 _moduleItems.add(js.statement('dart.export(#);', [args])); 403 }
275 } 404 }
276
277 JS.Identifier _initSymbol(JS.Identifier id) {
278 var s =
279 js.statement('const # = $_SYMBOL(#);', [id, js.string(id.name, "'")]);
280 _moduleItems.add(s);
281 return id;
282 }
283
284 // TODO(jmesserly): this is a temporary workaround for `Symbol` in core,
285 // until we have better name tracking.
286 String get _SYMBOL {
287 var name = currentLibrary.name;
288 if (name == 'dart.core' || name == 'dart._internal') return 'dart.JsSymbol';
289 return 'Symbol';
290 }
291
292 bool isPublic(String name) => !name.startsWith('_');
293 405
294 @override 406 @override
295 visitAsExpression(AsExpression node) { 407 visitAsExpression(AsExpression node) {
296 var from = getStaticType(node.expression); 408 var from = getStaticType(node.expression);
297 var to = node.type.type; 409 var to = node.type.type;
298 410
299 var fromExpr = _visit(node.expression); 411 var fromExpr = _visit(node.expression);
300 412
301 // Skip the cast if it's not needed. 413 // Skip the cast if it's not needed.
302 if (rules.isSubtypeOf(from, to)) return fromExpr; 414 if (rules.isSubtypeOf(from, to)) return fromExpr;
303 415
304 // All Dart number types map to a JS double. 416 // All Dart number types map to a JS double.
305 if (_isNumberInJS(from) && _isNumberInJS(to)) { 417 if (_isNumberInJS(from) && _isNumberInJS(to)) {
306 // Make sure to check when converting to int. 418 // Make sure to check when converting to int.
307 if (from != _types.intType && to == _types.intType) { 419 if (from != types.intType && to == types.intType) {
308 return js.call('dart.asInt(#)', [fromExpr]); 420 return js.call('dart.asInt(#)', [fromExpr]);
309 } 421 }
310 422
311 // A no-op in JavaScript. 423 // A no-op in JavaScript.
312 return fromExpr; 424 return fromExpr;
313 } 425 }
314 426
315 return js.call('dart.as(#, #)', [fromExpr, _emitTypeName(to)]); 427 return js.call('dart.as(#, #)', [fromExpr, _emitTypeName(to)]);
316 } 428 }
317 429
(...skipping 12 matching lines...) Expand all
330 } 442 }
331 443
332 if (node.notOperator != null) { 444 if (node.notOperator != null) {
333 return js.call('!#', result); 445 return js.call('!#', result);
334 } 446 }
335 return result; 447 return result;
336 } 448 }
337 449
338 String _jsTypeofName(DartType t) { 450 String _jsTypeofName(DartType t) {
339 if (_isNumberInJS(t)) return 'number'; 451 if (_isNumberInJS(t)) return 'number';
340 if (t == _types.stringType) return 'string'; 452 if (t == types.stringType) return 'string';
341 if (t == _types.boolType) return 'boolean'; 453 if (t == types.boolType) return 'boolean';
342 return null; 454 return null;
343 } 455 }
344 456
345 @override 457 @override
346 visitFunctionTypeAlias(FunctionTypeAlias node) { 458 visitFunctionTypeAlias(FunctionTypeAlias node) {
347 var element = node.element; 459 FunctionTypeAliasElement element = node.element;
348 var type = element.type;
349 var name = element.name;
350 460
351 var fnType = annotate( 461 JS.Expression body = annotate(
352 js.statement('const # = dart.typedef(#, () => #);', [ 462 js.call('dart.typedef(#, () => #)', [
353 name, 463 js.string(element.name, "'"),
354 js.string(name, "'"), 464 _emitTypeName(element.type, lowerTypedef: true)
355 _emitTypeName(type, lowerTypedef: true)
356 ]), 465 ]),
357 node, 466 node,
358 node.element); 467 element);
359 468
360 return _finishClassDef(type, fnType); 469 var typeFormals = element.typeParameters;
470 if (typeFormals.isNotEmpty) {
471 return _defineClassTypeArguments(element, typeFormals,
472 js.statement('const # = #;', [element.name, body]));
473 } else {
474 return js.statement('# = #;', [_emitTopLevelName(element), body]);
475 }
361 } 476 }
362 477
363 @override 478 @override
364 JS.Expression visitTypeName(TypeName node) => _emitTypeName(node.type); 479 JS.Expression visitTypeName(TypeName node) => _emitTypeName(node.type);
365 480
366 @override 481 @override
367 JS.Statement visitClassTypeAlias(ClassTypeAlias node) { 482 JS.Statement visitClassTypeAlias(ClassTypeAlias node) {
368 var element = node.element; 483 ClassElement element = node.element;
369 484
370 // Forward all generative constructors from the base class. 485 // Forward all generative constructors from the base class.
371 var body = <JS.Method>[]; 486 var methods = <JS.Method>[];
372 487
373 var supertype = element.supertype; 488 var supertype = element.supertype;
374 if (!supertype.isObject) { 489 if (!supertype.isObject) {
375 for (var ctor in element.constructors) { 490 for (var ctor in element.constructors) {
376 var parentCtor = supertype.lookUpConstructor(ctor.name, ctor.library); 491 var parentCtor = supertype.lookUpConstructor(ctor.name, ctor.library);
377 var fun = js.call('function() { super.#(...arguments); }', 492 var fun = js.call('function() { super.#(...arguments); }',
378 [_constructorName(parentCtor)]) as JS.Fun; 493 [_constructorName(parentCtor)]) as JS.Fun;
379 body.add(new JS.Method(_constructorName(ctor), fun)); 494 methods.add(new JS.Method(_constructorName(ctor), fun));
380 } 495 }
381 } 496 }
382 497
383 var cls = _emitClassDeclaration(element, body); 498 var classExpr = _emitClassExpression(element, methods);
384 return _finishClassDef(element.type, cls); 499
500 var typeFormals = element.typeParameters;
501 if (typeFormals.isNotEmpty) {
502 return _defineClassTypeArguments(
503 element, typeFormals, new JS.ClassDeclaration(classExpr));
504 } else {
505 return js.statement('# = #;', [_emitTopLevelName(element), classExpr]);
506 }
385 } 507 }
386 508
387 JS.Statement _emitJsType(String dartClassName, DartObject jsName) { 509 JS.Statement _emitJsType(Element e) {
388 var jsTypeName = 510 var jsTypeName = getAnnotationName(e, isJSAnnotation);
389 getConstantField(jsName, 'name', types.stringType)?.toStringValue(); 511 if (jsTypeName == null || jsTypeName == e.name) return null;
390 512
391 if (jsTypeName != null && jsTypeName != dartClassName) { 513 // We export the JS type as if it was a Dart type. For example this allows
392 // We export the JS type as if it was a Dart type. For example this allows 514 // `dom.InputElement` to actually be HTMLInputElement.
393 // `dom.InputElement` to actually be HTMLInputElement. 515 // TODO(jmesserly): if we had the JS name on the Element, we could just
394 // TODO(jmesserly): if we had the JS name on the Element, we could just 516 // generate it correctly when we refer to it.
395 // generate it correctly when we refer to it. 517 return js.statement('# = #;', [_emitTopLevelName(e), jsTypeName]);
396 if (isPublic(dartClassName)) _addExport(dartClassName);
397 return js.statement('const # = #;', [dartClassName, jsTypeName]);
398 }
399 return null;
400 } 518 }
401 519
402 @override 520 @override
403 JS.Statement visitClassDeclaration(ClassDeclaration node) { 521 JS.Statement visitClassDeclaration(ClassDeclaration node) {
404 var classElem = node.element; 522 var classElem = node.element;
405 var type = classElem.type;
406 var jsName = findAnnotation(classElem, isJSAnnotation);
407 523
408 if (jsName != null) return _emitJsType(node.name.name, jsName); 524 // If this is a JavaScript type, emit it now and then exit.
525 var jsTypeDef = _emitJsType(classElem);
526 if (jsTypeDef != null) return jsTypeDef;
409 527
410 var ctors = <ConstructorDeclaration>[]; 528 var ctors = <ConstructorDeclaration>[];
411 var fields = <FieldDeclaration>[]; 529 var fields = <FieldDeclaration>[];
412 var staticFields = <FieldDeclaration>[]; 530 var staticFields = <FieldDeclaration>[];
413 var methods = <MethodDeclaration>[]; 531 var methods = <MethodDeclaration>[];
414 for (var member in node.members) { 532 for (var member in node.members) {
415 if (member is ConstructorDeclaration) { 533 if (member is ConstructorDeclaration) {
416 ctors.add(member); 534 ctors.add(member);
417 } else if (member is FieldDeclaration) { 535 } else if (member is FieldDeclaration) {
418 (member.isStatic ? staticFields : fields).add(member); 536 (member.isStatic ? staticFields : fields).add(member);
419 } else if (member is MethodDeclaration) { 537 } else if (member is MethodDeclaration) {
420 methods.add(member); 538 methods.add(member);
421 } 539 }
422 } 540 }
423 541
424 var allFields = new List.from(fields)..addAll(staticFields); 542 var allFields = new List.from(fields)..addAll(staticFields);
425 543 var classExpr = _emitClassExpression(
426 var classDecl = _emitClassDeclaration(
427 classElem, _emitClassMethods(node, ctors, fields), 544 classElem, _emitClassMethods(node, ctors, fields),
428 fields: allFields); 545 fields: allFields);
429 546
430 String jsPeerName; 547 var body = <JS.Statement>[];
431 var jsPeer = findAnnotation(classElem, isJsPeerInterface); 548 var extensions = _extensionsToImplement(classElem);
432 // Only look at "Native" annotations on registered extension types. 549 _initExtensionSymbols(classElem, methods, fields, body);
433 // E.g., we're current ignoring the ones in dart:html. 550
434 if (jsPeer == null && _extensionTypes.contains(classElem)) { 551 // Emit the class, e.g. `core.Object = class Object { ... }`
435 jsPeer = findAnnotation(classElem, isNativeAnnotation); 552 JS.Expression className = _defineClass(classElem, classExpr, body);
436 } 553
437 if (jsPeer != null) { 554 // Emit things that come after the ES6 `class ... { ... }`.
438 jsPeerName = 555 _setBaseClass(classElem, className, body);
439 getConstantField(jsPeer, 'name', types.stringType)?.toStringValue(); 556 _defineNamedConstructors(ctors, body, className);
440 if (jsPeerName.contains(',')) { 557 _emitVirtualFields(fields, className, body);
441 jsPeerName = jsPeerName.split(',')[0]; 558 _emitClassSignature(methods, classElem, ctors, extensions, className, body);
442 } 559 _defineExtensionMembers(extensions, className, body);
560 _emitClassMetadata(node.metadata, className, body);
561
562 JS.Statement classDef = _statement(body);
563 var typeFormals = classElem.typeParameters;
564 if (typeFormals.isNotEmpty) {
565 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef);
443 } 566 }
444 567
445 var body = _finishClassMembers(classElem, classDecl, ctors, fields, 568 body = <JS.Statement>[classDef];
446 staticFields, methods, node.metadata, jsPeerName); 569 _emitStaticFields(staticFields, classElem, body);
570 _registerExtensionType(classElem, body);
571 return _statement(body);
572 }
447 573
448 var result = _finishClassDef(type, body); 574 JS.Expression _defineClass(ClassElement classElem,
449 575 JS.ClassExpression classExpr, List<JS.Statement> body) {
450 if (jsPeerName != null) { 576 JS.Expression className;
451 // This class isn't allowed to be lazy, because we need to set up 577 if (classElem.typeParameters.isNotEmpty) {
452 // the native JS type eagerly at this point. 578 // Generic classes will be defined inside a function that closes over the
453 // If we wanted to support laziness, we could defer the hookup until 579 // type parameter. So we can use their local variable name directly.
454 // the end of the Dart library cycle load. 580 className = classExpr.name;
455 assert(_loader.isLoaded(classElem)); 581 body.add(new JS.ClassDeclaration(classExpr));
456 582 } else {
457 // TODO(jmesserly): this copies the dynamic members. 583 className = _emitTopLevelName(classElem);
458 // Probably fine for objects coming from JS, but not if we actually 584 body.add(js.statement('# = #;', [className, classExpr]));
459 // want to support construction of instances with generic types other
460 // than dynamic. See issue #154 for Array and List<E> related bug.
461 var copyMembers = js.statement(
462 'dart.registerExtension(dart.global.#, #);',
463 [_propertyName(jsPeerName), classElem.name]);
464 return _statement([result, copyMembers]);
465 } 585 }
466 return result; 586 return className;
467 } 587 }
468 588
469 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) { 589 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) {
470 return typeFormals 590 return typeFormals
471 .map((t) => new JS.Identifier(t.name)) 591 .map((t) => new JS.Identifier(t.name))
472 .toList(growable: false); 592 .toList(growable: false);
473 } 593 }
474 594
475 /// Emits a field declaration for TypeScript & Closure's ES6_TYPED 595 /// Emits a field declaration for TypeScript & Closure's ES6_TYPED
476 /// (e.g. `class Foo { i: string; }`) 596 /// (e.g. `class Foo { i: string; }`)
477 JS.VariableDeclarationList _emitTypeScriptField(FieldDeclaration field) { 597 JS.VariableDeclarationList _emitTypeScriptField(FieldDeclaration field) {
478 return new JS.VariableDeclarationList( 598 return new JS.VariableDeclarationList(
479 field.isStatic ? 'static' : null, 599 field.isStatic ? 'static' : null,
480 field.fields.variables 600 field.fields.variables
481 .map((decl) => new JS.VariableInitialization( 601 .map((decl) => new JS.VariableInitialization(
482 new JS.Identifier( 602 new JS.Identifier(
483 // TODO(ochafik): use a refactored _emitMemberName instead. 603 // TODO(ochafik): use a refactored _emitMemberName instead.
484 decl.name.name, 604 decl.name.name,
485 type: emitTypeRef(decl.element.type)), 605 type: emitTypeRef(decl.element.type)),
486 null)) 606 null))
487 .toList(growable: false)); 607 .toList(growable: false));
488 } 608 }
489 609
490 @override 610 @override
491 JS.Statement visitEnumDeclaration(EnumDeclaration node) { 611 JS.Statement visitEnumDeclaration(EnumDeclaration node) {
492 var element = node.element; 612 var element = node.element;
493 var type = element.type; 613 var type = element.type;
494 var name = js.string(type.name); 614 var name = js.string(type.name);
495 var id = new JS.Identifier(type.name);
496 615
497 // Generate a class per section 13 of the spec. 616 // Generate a class per section 13 of the spec.
498 // TODO(vsm): Generate any accompanying metadata 617 // TODO(vsm): Generate any accompanying metadata
499 618
500 // Create constructor and initialize index 619 // Create constructor and initialize index
501 var constructor = new JS.Method( 620 var constructor = new JS.Method(
502 name, js.call('function(index) { this.index = index; }') as JS.Fun); 621 name, js.call('function(index) { this.index = index; }') as JS.Fun);
503 var fields = new List<FieldElement>.from( 622 var fields = new List<FieldElement>.from(
504 element.fields.where((f) => f.type == type)); 623 element.fields.where((f) => f.type == type));
505 624
506 // Create toString() method 625 // Create toString() method
507 var properties = new List<JS.Property>(); 626 var properties = new List<JS.Property>();
508 for (var i = 0; i < fields.length; ++i) { 627 for (var i = 0; i < fields.length; ++i) {
509 properties.add(new JS.Property( 628 properties.add(new JS.Property(
510 js.number(i), js.string('${type.name}.${fields[i].name}'))); 629 js.number(i), js.string('${type.name}.${fields[i].name}')));
511 } 630 }
512 var nameMap = new JS.ObjectInitializer(properties, multiline: true); 631 var nameMap = new JS.ObjectInitializer(properties, multiline: true);
513 var toStringF = new JS.Method(js.string('toString'), 632 var toStringF = new JS.Method(js.string('toString'),
514 js.call('function() { return #[this.index]; }', nameMap) as JS.Fun); 633 js.call('function() { return #[this.index]; }', nameMap) as JS.Fun);
515 634
516 // Create enum class 635 // Create enum class
517 var classExpr = new JS.ClassExpression( 636 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name),
518 id, _emitClassHeritage(element), [constructor, toStringF]); 637 _emitClassHeritage(element), [constructor, toStringF]);
519 var result = <JS.Statement>[js.statement('#', classExpr)]; 638 var id = _emitTopLevelName(element);
639 var result = [
640 js.statement('# = #', [id, classExpr])
641 ];
520 642
521 // Create static fields for each enum value 643 // Create static fields for each enum value
522 for (var i = 0; i < fields.length; ++i) { 644 for (var i = 0; i < fields.length; ++i) {
523 result.add(js.statement('#.# = dart.const(new #(#));', 645 result.add(js.statement('#.# = dart.const(new #(#));',
524 [id, fields[i].name, id, js.number(i)])); 646 [id, fields[i].name, id, js.number(i)]));
525 } 647 }
526 648
527 // Create static values list 649 // Create static values list
528 var values = new JS.ArrayInitializer(new List<JS.Expression>.from( 650 var values = new JS.ArrayInitializer(new List<JS.Expression>.from(
529 fields.map((f) => js.call('#.#', [id, f.name])))); 651 fields.map((f) => js.call('#.#', [id, f.name]))));
530 result.add(js.statement('#.values = dart.const(dart.list(#, #));', 652 result.add(js.statement('#.values = dart.const(dart.list(#, #));',
531 [id, values, _emitTypeName(type)])); 653 [id, values, _emitTypeName(type)]));
532 654
533 if (isPublic(type.name)) _addExport(type.name);
534 return _statement(result); 655 return _statement(result);
535 } 656 }
536 657
537 /// Given a class element and body, complete the class declaration. 658 /// Wraps a possibly generic class in its type arguments.
538 /// This handles generic type parameters, laziness (in library-cycle cases), 659 JS.Statement _defineClassTypeArguments(TypeDefiningElement element,
539 /// and ensuring dependencies are loaded first. 660 List<TypeParameterElement> formals, JS.Statement body) {
540 JS.Statement _finishClassDef(ParameterizedType type, JS.Statement body) { 661 assert(formals.isNotEmpty);
541 var name = type.name; 662 var genericDef =
542 var genericName = '$name\$'; 663 js.statement('# = dart.generic((#) => { #; return #; });', [
664 _emitTopLevelName(element, suffix: r'$'),
665 _emitTypeFormals(formals),
666 body,
667 element.name
668 ]);
543 669
544 JS.Statement genericDef = null; 670 var dynType = fillDynamicTypeArgs(element.type);
545 if (_typeFormalsOf(type).isNotEmpty) { 671 var genericInst = _emitTypeName(dynType, lowerGeneric: true);
546 genericDef = _emitGenericClassDef(type, body); 672 return js.statement(
547 } 673 '{ #; # = #; }', [genericDef, _emitTopLevelName(element), genericInst]);
548 // The base class and all mixins must be declared before this class.
549 if (!_loader.isLoaded(type.element)) {
550 // TODO(jmesserly): the lazy class def is a simple solution for now.
551 // We may want to consider other options in the future.
552
553 if (genericDef != null) {
554 return js.statement(
555 '{ #; dart.defineLazyClassGeneric(#, #, { get: # }); }',
556 [genericDef, _exportsVar, _propertyName(name), genericName]);
557 }
558
559 return js.statement(
560 'dart.defineLazyClass(#, { get #() { #; return #; } });',
561 [_exportsVar, _propertyName(name), body, name]);
562 }
563
564 if (isPublic(name)) _addExport(name);
565
566 if (genericDef != null) {
567 var dynType = fillDynamicTypeArgs(type, types);
568 var genericInst = _emitTypeName(dynType, lowerGeneric: true);
569 return js.statement('{ #; let # = #; }', [genericDef, name, genericInst]);
570 }
571 return body;
572 } 674 }
573 675
574 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) {
575 var name = type.name;
576 var genericName = '$name\$';
577 var typeParams = _typeFormalsOf(type).map((p) => p.name);
578 if (isPublic(name)) _addExport(genericName);
579 return js.statement('const # = dart.generic(function(#) { #; return #; });',
580 [genericName, typeParams, body, name]);
581 }
582
583 final _hasDeferredSupertype = new HashSet<ClassElement>();
584
585 bool _deferIfNeeded(DartType type, ClassElement current) { 676 bool _deferIfNeeded(DartType type, ClassElement current) {
586 if (type is ParameterizedType) { 677 if (type is ParameterizedType) {
587 var typeArguments = type.typeArguments; 678 var typeArguments = type.typeArguments;
588 for (var typeArg in typeArguments) { 679 for (var typeArg in typeArguments) {
589 var typeElement = typeArg.element; 680 var typeElement = typeArg.element;
590 // FIXME(vsm): This does not track mutual recursive dependences. 681 // FIXME(vsm): This does not track mutual recursive dependences.
591 if (current == typeElement || _deferIfNeeded(typeArg, current)) { 682 if (current == typeElement || _deferIfNeeded(typeArg, current)) {
592 return true; 683 return true;
593 } 684 }
594 } 685 }
595 } 686 }
596 return false; 687 return false;
597 } 688 }
598 689
599 JS.Statement _emitClassDeclaration( 690 JS.ClassExpression _emitClassExpression(
600 ClassElement element, List<JS.Method> methods, 691 ClassElement element, List<JS.Method> methods,
601 {List<FieldDeclaration> fields}) { 692 {List<FieldDeclaration> fields}) {
602 String name = element.name; 693 String name = element.name;
603 var heritage = _emitClassHeritage(element); 694 var heritage = _emitClassHeritage(element);
604 var typeParams = _emitTypeFormals(element.typeParameters); 695 var typeParams = _emitTypeFormals(element.typeParameters);
605 var jsFields = fields?.map(_emitTypeScriptField)?.toList(); 696 var jsFields = fields?.map(_emitTypeScriptField)?.toList();
606 697
607 // Workaround for Closure: super classes must be qualified paths. 698 return new JS.ClassExpression(new JS.Identifier(name), heritage, methods,
608 // TODO(jmesserly): is there a bug filed? we need to get out of the business 699 typeParams: typeParams, fields: jsFields);
609 // of working around bugs in other transpilers...
610 JS.Statement workaroundSuper = null;
611 if (options.closure && heritage is JS.Call) {
612 var superVar = new JS.TemporaryId('$name\$super');
613 workaroundSuper = js.statement('const # = #;', [superVar, heritage]);
614 heritage = superVar;
615 }
616 var decl = new JS.ClassDeclaration(new JS.ClassExpression(
617 new JS.Identifier(name), heritage, methods,
618 typeParams: typeParams, fields: jsFields));
619 if (workaroundSuper != null) {
620 return new JS.Block([workaroundSuper, decl]);
621 }
622 return decl;
623 } 700 }
624 701
625 JS.Expression _emitClassHeritage(ClassElement element) { 702 JS.Expression _emitClassHeritage(ClassElement element) {
626 var type = element.type; 703 var type = element.type;
627 if (type.isObject) return null; 704 if (type.isObject) return null;
628 705
629 // Assume we can load eagerly, until proven otherwise.
630 _loader.startTopLevel(element); 706 _loader.startTopLevel(element);
631 707
632 // Find the super type 708 // Find the super type
633 JS.Expression heritage; 709 JS.Expression heritage;
634 var supertype = type.superclass; 710 var supertype = type.superclass;
635 if (_deferIfNeeded(supertype, element)) { 711 if (_deferIfNeeded(supertype, element)) {
636 // Fall back to raw type. 712 // Fall back to raw type.
637 supertype = fillDynamicTypeArgs(supertype.element.type, _types); 713 supertype = fillDynamicTypeArgs(supertype.element.type);
638 _hasDeferredSupertype.add(element); 714 _hasDeferredSupertype.add(element);
639 } 715 }
640 heritage = _emitTypeName(supertype); 716 heritage = _emitTypeName(supertype);
641 717
642 if (type.mixins.isNotEmpty) { 718 if (type.mixins.isNotEmpty) {
643 var mixins = type.mixins.map(_emitTypeName).toList(); 719 var mixins = type.mixins.map(_emitTypeName).toList();
644 mixins.insert(0, heritage); 720 mixins.insert(0, heritage);
645 heritage = js.call('dart.mixin(#)', [mixins]); 721 heritage = js.call('dart.mixin(#)', [mixins]);
646 } 722 }
647 723
648 _loader.finishTopLevel(element); 724 _loader.finishTopLevel(element);
725
649 return heritage; 726 return heritage;
650 } 727 }
651 728
652 /// Provide Dart getters and setters that forward to the underlying native 729 /// Provide Dart getters and setters that forward to the underlying native
653 /// field. Note that the Dart names are always symbolized to avoid 730 /// field. Note that the Dart names are always symbolized to avoid
654 /// conflicts. They will be installed as extension methods on the underlying 731 /// conflicts. They will be installed as extension methods on the underlying
655 /// native type. 732 /// native type.
656 List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) { 733 List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) {
657 // TODO(vsm): Can this by meta-programmed? 734 // TODO(vsm): Can this by meta-programmed?
658 // E.g., dart.nativeField(symbol, jsName) 735 // E.g., dart.nativeField(symbol, jsName)
659 // Alternatively, perhaps it could be meta-programmed directly in 736 // Alternatively, perhaps it could be meta-programmed directly in
660 // dart.registerExtensions? 737 // dart.registerExtensions?
661 var jsMethods = <JS.Method>[]; 738 var jsMethods = <JS.Method>[];
662 if (!node.isStatic) { 739 if (!node.isStatic) {
663 for (var decl in node.fields.variables) { 740 for (var decl in node.fields.variables) {
664 var field = decl.element; 741 var field = decl.element;
665 var name = decl.name.name; 742 var name = getAnnotationName(field, isJsName) ?? field.name;
666 var annotation = findAnnotation(field, isJsName);
667 if (annotation != null) {
668 name = getConstantField(annotation, 'name', types.stringType)
669 ?.toStringValue();
670 }
671 // Generate getter 743 // Generate getter
672 var fn = new JS.Fun([], js.statement('{ return this.#; }', [name])); 744 var fn = new JS.Fun([], js.statement('{ return this.#; }', [name]));
673 var method = 745 var method =
674 new JS.Method(_elementMemberName(field.getter), fn, isGetter: true); 746 new JS.Method(_elementMemberName(field.getter), fn, isGetter: true);
675 jsMethods.add(method); 747 jsMethods.add(method);
676 748
677 // Generate setter 749 // Generate setter
678 if (!decl.isFinal) { 750 if (!decl.isFinal) {
679 var value = new JS.TemporaryId('value'); 751 var value = new JS.TemporaryId('value');
680 fn = new JS.Fun( 752 fn = new JS.Fun(
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 // Iterable, we know the adapter is already there, so we can skip it as a 822 // Iterable, we know the adapter is already there, so we can skip it as a
751 // simple code size optimization. 823 // simple code size optimization.
752 var parent = t.lookUpGetterInSuperclass('iterator', t.element.library); 824 var parent = t.lookUpGetterInSuperclass('iterator', t.element.library);
753 if (parent != null) return null; 825 if (parent != null) return null;
754 var parentType = findSupertype(t, _implementsIterable); 826 var parentType = findSupertype(t, _implementsIterable);
755 if (parentType != null) return null; 827 if (parentType != null) return null;
756 828
757 // Otherwise, emit the adapter method, which wraps the Dart iterator in 829 // Otherwise, emit the adapter method, which wraps the Dart iterator in
758 // an ES6 iterator. 830 // an ES6 iterator.
759 return new JS.Method( 831 return new JS.Method(
760 js.call('$_SYMBOL.iterator'), 832 js.call('Symbol.iterator'),
761 js.call('function() { return new dart.JsIterator(this.#); }', 833 js.call('function() { return new dart.JsIterator(this.#); }',
762 [_emitMemberName('iterator', type: t)]) as JS.Fun); 834 [_emitMemberName('iterator', type: t)]) as JS.Fun);
763 } 835 }
764 836
765 JS.Expression _instantiateAnnotation(Annotation node) { 837 JS.Expression _instantiateAnnotation(Annotation node) {
766 var element = node.element; 838 var element = node.element;
767 if (element is ConstructorElement) { 839 if (element is ConstructorElement) {
768 return _emitInstanceCreationExpression(element, element.returnType, 840 return _emitInstanceCreationExpression(element, element.returnType,
769 node.constructorName, node.arguments, true); 841 node.constructorName, node.arguments, true);
770 } else { 842 } else {
771 return _visit(node.name); 843 return _visit(node.name);
772 } 844 }
773 } 845 }
774 846
775 /// Emit class members that need to come after the class declaration, such 847 /// Gets the JS peer for this Dart type if any, otherwise null.
776 /// as static fields. See [_emitClassMethods] for things that are emitted 848 ///
777 /// inside the ES6 `class { ... }` node. 849 /// For example for dart:_interceptors `JSArray` this will return "Array",
778 JS.Statement _finishClassMembers( 850 /// referring to the JavaScript built-in `Array` type.
779 ClassElement classElem, 851 String _getJSPeerName(ClassElement classElem) {
780 JS.Statement classDecl, 852 var jsPeerName = getAnnotationName(
781 List<ConstructorDeclaration> ctors, 853 classElem,
782 List<FieldDeclaration> fields, 854 (a) =>
783 List<FieldDeclaration> staticFields, 855 isJsPeerInterface(a) ||
784 List<MethodDeclaration> methods, 856 isNativeAnnotation(a) && _extensionTypes.contains(classElem));
785 List<Annotation> metadata, 857 if (jsPeerName != null && jsPeerName.contains(',')) {
786 String jsPeerName) { 858 jsPeerName = jsPeerName.split(',')[0];
787 var name = classElem.name; 859 }
788 var body = <JS.Statement>[]; 860 return jsPeerName;
861 }
789 862
790 if (_extensionTypes.contains(classElem)) { 863 void _registerExtensionType(ClassElement classElem, List<JS.Statement> body) {
791 var dartxNames = <JS.Expression>[]; 864 var jsPeerName = _getJSPeerName(classElem);
792 for (var m in methods) { 865 if (jsPeerName != null) {
793 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { 866 // TODO(jmesserly): this copies the dynamic members.
794 dartxNames.add(_elementMemberName(m.element, allowExtensions: false)); 867 // Probably fine for objects coming from JS, but not if we actually
868 // want to support construction of instances with generic types other
869 // than dynamic. See issue #154 for Array and List<E> related bug.
870 body.add(js.statement('dart.registerExtension(dart.global.#, #);',
871 [_propertyName(jsPeerName), _emitTopLevelName(classElem)]));
872 }
873 }
874
875 void _setBaseClass(ClassElement classElem, JS.Expression className,
876 List<JS.Statement> body) {
877 String jsPeerName = _getJSPeerName(classElem);
878 JS.Expression newBaseClass;
879 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) {
880 // TODO(jmesserly): we should really just extend Array in the first place.
881 newBaseClass = js.call('dart.global.#', [jsPeerName]);
882 } else if (_hasDeferredSupertype.contains(classElem)) {
883 newBaseClass = _emitTypeName(classElem.type.superclass);
884 }
885 if (newBaseClass != null) {
886 body.add(
887 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass]));
888 }
889 }
890
891 /// Emits instance fields, if they are virtual
892 /// (in other words, they override a getter/setter pair).
893 void _emitVirtualFields(List<FieldDeclaration> fields,
894 JS.Expression className, List<JS.Statement> body) {
895 for (FieldDeclaration member in fields) {
896 for (VariableDeclaration field in member.fields.variables) {
897 if (_fieldsNeedingStorage.contains(field.element)) {
898 body.add(_overrideField(className, field.element));
795 } 899 }
796 } 900 }
797 for (var f in fields) {
798 if (!f.isStatic) {
799 for (var d in f.fields.variables) {
800 if (d.element.isPublic) {
801 dartxNames.add(
802 _elementMemberName(d.element.getter, allowExtensions: false));
803 }
804 }
805 }
806 }
807 if (dartxNames.isNotEmpty) {
808 body.add(js.statement('dart.defineExtensionNames(#)',
809 [new JS.ArrayInitializer(dartxNames, multiline: true)]));
810 }
811 } 901 }
902 }
812 903
813 body.add(classDecl); 904 void _defineNamedConstructors(List<ConstructorDeclaration> ctors,
814 905 List<JS.Statement> body, JS.Expression className) {
815 // TODO(jmesserly): we should really just extend native Array.
816 if (jsPeerName != null && classElem.typeParameters.isNotEmpty) {
817 body.add(js.statement('dart.setBaseClass(#, dart.global.#);',
818 [classElem.name, _propertyName(jsPeerName)]));
819 }
820
821 // Deferred Superclass
822 if (_hasDeferredSupertype.contains(classElem)) {
823 body.add(js.statement('#.prototype.__proto__ = #.prototype;',
824 [name, _emitTypeName(classElem.type.superclass)]));
825 }
826
827 // Interfaces
828 if (classElem.interfaces.isNotEmpty) {
829 body.add(js.statement('#[dart.implements] = () => #;', [
830 name,
831 new JS.ArrayInitializer(new List<JS.Expression>.from(
832 classElem.interfaces.map(_emitTypeName)))
833 ]));
834 }
835
836 // Named constructors
837 for (ConstructorDeclaration member in ctors) { 906 for (ConstructorDeclaration member in ctors) {
838 if (member.name != null && member.factoryKeyword == null) { 907 if (member.name != null && member.factoryKeyword == null) {
839 body.add(js.statement('dart.defineNamedConstructor(#, #);', 908 body.add(js.statement('dart.defineNamedConstructor(#, #);',
840 [name, _emitMemberName(member.name.name, isStatic: true)])); 909 [className, _emitMemberName(member.name.name, isStatic: true)]));
841 } 910 }
842 } 911 }
912 }
843 913
844 // Emits instance fields, if they are virtual 914 /// Emits static fields for a class, and initialize them eagerly if possible,
845 // (in other words, they override a getter/setter pair). 915 /// otherwise define them as lazy properties.
846 for (FieldDeclaration member in fields) { 916 void _emitStaticFields(List<FieldDeclaration> staticFields,
917 ClassElement classElem, List<JS.Statement> body) {
918 var lazyStatics = <VariableDeclaration>[];
919 for (FieldDeclaration member in staticFields) {
847 for (VariableDeclaration field in member.fields.variables) { 920 for (VariableDeclaration field in member.fields.variables) {
848 if (_fieldsNeedingStorage.contains(field.element)) { 921 JS.Statement eagerField = _emitConstantStaticField(classElem, field);
849 body.add(_overrideField(field.element)); 922 if (eagerField != null) {
923 body.add(eagerField);
924 } else {
925 lazyStatics.add(field);
850 } 926 }
851 } 927 }
852 } 928 }
929 if (lazyStatics.isNotEmpty) {
930 body.add(_emitLazyFields(classElem, lazyStatics));
931 }
932 }
853 933
854 // Emit the signature on the class recording the runtime type information 934 void _emitClassMetadata(List<Annotation> metadata, JS.Expression className,
855 var extensions = _extensionsToImplement(classElem); 935 List<JS.Statement> body) {
856 { 936 // TODO(vsm): Make this optional per #268.
857 var tStatics = <JS.Property>[]; 937 // Metadata
858 var tMethods = <JS.Property>[]; 938 if (metadata.isNotEmpty) {
859 var sNames = <JS.Expression>[]; 939 body.add(js.statement('#[dart.metadata] = () => #;', [
860 for (MethodDeclaration node in methods) { 940 className,
861 if (!(node.isSetter || node.isGetter || node.isAbstract)) { 941 new JS.ArrayInitializer(
862 var name = node.name.name; 942 new List<JS.Expression>.from(metadata.map(_instantiateAnnotation)))
863 var element = node.element; 943 ]));
864 var inheritedElement = 944 }
865 classElem.lookUpInheritedConcreteMethod(name, currentLibrary); 945 }
866 if (inheritedElement != null &&
867 inheritedElement.type == element.type) {
868 continue;
869 }
870 var memberName = _elementMemberName(element);
871 var parts = _emitFunctionTypeParts(element.type);
872 var property =
873 new JS.Property(memberName, new JS.ArrayInitializer(parts));
874 if (node.isStatic) {
875 tStatics.add(property);
876 sNames.add(memberName);
877 } else {
878 tMethods.add(property);
879 }
880 }
881 }
882 946
883 var tCtors = <JS.Property>[]; 947 /// If a concrete class implements one of our extensions, we might need to
884 for (ConstructorDeclaration node in ctors) { 948 /// add forwarders.
885 var memberName = _constructorName(node.element); 949 void _defineExtensionMembers(List<ExecutableElement> extensions,
886 var element = node.element; 950 JS.Expression className, List<JS.Statement> body) {
887 var parts = _emitFunctionTypeParts(element.type, node.parameters);
888 var property =
889 new JS.Property(memberName, new JS.ArrayInitializer(parts));
890 tCtors.add(property);
891 }
892
893 JS.Property build(String name, List<JS.Property> elements) {
894 var o =
895 new JS.ObjectInitializer(elements, multiline: elements.length > 1);
896 var e = js.call('() => #', o);
897 return new JS.Property(_propertyName(name), e);
898 }
899 var sigFields = <JS.Property>[];
900 if (!tCtors.isEmpty) sigFields.add(build('constructors', tCtors));
901 if (!tMethods.isEmpty) sigFields.add(build('methods', tMethods));
902 if (!tStatics.isEmpty) {
903 assert(!sNames.isEmpty);
904 var aNames = new JS.Property(
905 _propertyName('names'), new JS.ArrayInitializer(sNames));
906 sigFields.add(build('statics', tStatics));
907 sigFields.add(aNames);
908 }
909 if (!sigFields.isEmpty || extensions.isNotEmpty) {
910 var sig = new JS.ObjectInitializer(sigFields);
911 var classExpr = new JS.Identifier(name);
912 body.add(js.statement('dart.setSignature(#, #);', [classExpr, sig]));
913 }
914 }
915
916 // If a concrete class implements one of our extensions, we might need to 951 // If a concrete class implements one of our extensions, we might need to
917 // add forwarders. 952 // add forwarders.
918 if (extensions.isNotEmpty) { 953 if (extensions.isNotEmpty) {
919 var methodNames = <JS.Expression>[]; 954 var methodNames = <JS.Expression>[];
920 for (var e in extensions) { 955 for (var e in extensions) {
921 methodNames.add(_elementMemberName(e)); 956 methodNames.add(_elementMemberName(e));
922 } 957 }
923 body.add(js.statement('dart.defineExtensionMembers(#, #);', [ 958 body.add(js.statement('dart.defineExtensionMembers(#, #);', [
924 name, 959 className,
925 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4) 960 new JS.ArrayInitializer(methodNames, multiline: methodNames.length > 4)
926 ])); 961 ]));
927 } 962 }
963 }
928 964
929 // TODO(vsm): Make this optional per #268. 965 /// Emit the signature on the class recording the runtime type information
930 // Metadata 966 void _emitClassSignature(
931 if (metadata.isNotEmpty) { 967 List<MethodDeclaration> methods,
932 body.add(js.statement('#[dart.metadata] = () => #;', [ 968 ClassElement classElem,
933 name, 969 List<ConstructorDeclaration> ctors,
934 new JS.ArrayInitializer( 970 List<ExecutableElement> extensions,
935 new List<JS.Expression>.from(metadata.map(_instantiateAnnotation))) 971 JS.Expression className,
972 List<JS.Statement> body) {
973 if (classElem.interfaces.isNotEmpty) {
974 body.add(js.statement('#[dart.implements] = () => #;', [
975 className,
976 new JS.ArrayInitializer(new List<JS.Expression>.from(
977 classElem.interfaces.map(_emitTypeName)))
936 ])); 978 ]));
937 } 979 }
938 980
939 // Emits static fields. These are eager initialized if possible, otherwise 981 var tStatics = <JS.Property>[];
940 // they are made lazy. 982 var tMethods = <JS.Property>[];
941 var lazyStatics = <VariableDeclaration>[]; 983 var sNames = <JS.Expression>[];
942 for (FieldDeclaration member in staticFields) { 984 for (MethodDeclaration node in methods) {
943 for (VariableDeclaration field in member.fields.variables) { 985 if (!(node.isSetter || node.isGetter || node.isAbstract)) {
944 JS.Statement eagerField = _emitConstantStaticField(classElem, field); 986 var name = node.name.name;
945 if (eagerField != null) { 987 var element = node.element;
946 body.add(eagerField); 988 var inheritedElement =
989 classElem.lookUpInheritedConcreteMethod(name, currentLibrary);
990 if (inheritedElement != null && inheritedElement.type == element.type) {
991 continue;
992 }
993 var memberName = _elementMemberName(element);
994 var parts = _emitFunctionTypeParts(element.type);
995 var property =
996 new JS.Property(memberName, new JS.ArrayInitializer(parts));
997 if (node.isStatic) {
998 tStatics.add(property);
999 sNames.add(memberName);
947 } else { 1000 } else {
948 lazyStatics.add(field); 1001 tMethods.add(property);
949 } 1002 }
950 } 1003 }
951 } 1004 }
952 if (lazyStatics.isNotEmpty) { 1005
953 body.add(_emitLazyFields(classElem, lazyStatics)); 1006 var tCtors = <JS.Property>[];
1007 for (ConstructorDeclaration node in ctors) {
1008 var memberName = _constructorName(node.element);
1009 var element = node.element;
1010 var parts = _emitFunctionTypeParts(element.type, node.parameters);
1011 var property =
1012 new JS.Property(memberName, new JS.ArrayInitializer(parts));
1013 tCtors.add(property);
954 } 1014 }
955 1015
956 return _statement(body); 1016 JS.Property build(String name, List<JS.Property> elements) {
1017 var o =
1018 new JS.ObjectInitializer(elements, multiline: elements.length > 1);
1019 var e = js.call('() => #', o);
1020 return new JS.Property(_propertyName(name), e);
1021 }
1022 var sigFields = <JS.Property>[];
1023 if (!tCtors.isEmpty) sigFields.add(build('constructors', tCtors));
1024 if (!tMethods.isEmpty) sigFields.add(build('methods', tMethods));
1025 if (!tStatics.isEmpty) {
1026 assert(!sNames.isEmpty);
1027 var aNames = new JS.Property(
1028 _propertyName('names'), new JS.ArrayInitializer(sNames));
1029 sigFields.add(build('statics', tStatics));
1030 sigFields.add(aNames);
1031 }
1032 if (!sigFields.isEmpty || extensions.isNotEmpty) {
1033 var sig = new JS.ObjectInitializer(sigFields);
1034 body.add(js.statement('dart.setSignature(#, #);', [className, sig]));
1035 }
1036 }
1037
1038 /// Ensure `dartx.` symbols we will use are present.
1039 void _initExtensionSymbols(
1040 ClassElement classElem,
1041 List<MethodDeclaration> methods,
1042 List<FieldDeclaration> fields,
1043 List<JS.Statement> body) {
1044 if (_extensionTypes.contains(classElem)) {
1045 var dartxNames = <JS.Expression>[];
1046 for (var m in methods) {
1047 if (!m.isAbstract && !m.isStatic && m.element.isPublic) {
1048 dartxNames.add(_elementMemberName(m.element, allowExtensions: false));
1049 }
1050 }
1051 for (var f in fields) {
1052 if (!f.isStatic) {
1053 for (var d in f.fields.variables) {
1054 if (d.element.isPublic) {
1055 dartxNames.add(
1056 _elementMemberName(d.element.getter, allowExtensions: false));
1057 }
1058 }
1059 }
1060 }
1061 if (dartxNames.isNotEmpty) {
1062 body.add(js.statement('dart.defineExtensionNames(#)',
1063 [new JS.ArrayInitializer(dartxNames, multiline: true)]));
1064 }
1065 }
957 } 1066 }
958 1067
959 List<ExecutableElement> _extensionsToImplement(ClassElement element) { 1068 List<ExecutableElement> _extensionsToImplement(ClassElement element) {
960 var members = <ExecutableElement>[]; 1069 var members = <ExecutableElement>[];
961 if (_extensionTypes.contains(element)) return members; 1070 if (_extensionTypes.contains(element)) return members;
962 1071
963 // Collect all extension types we implement. 1072 // Collect all extension types we implement.
964 var type = element.type; 1073 var type = element.type;
965 var types = new Set<ClassElement>(); 1074 var types = new Set<ClassElement>();
966 _collectExtensions(type, types); 1075 _collectExtensions(type, types);
(...skipping 24 matching lines...) Expand all
991 if (_extensionTypes.contains(element)) types.add(element); 1100 if (_extensionTypes.contains(element)) types.add(element);
992 for (var m in type.mixins.reversed) { 1101 for (var m in type.mixins.reversed) {
993 _collectExtensions(m, types); 1102 _collectExtensions(m, types);
994 } 1103 }
995 for (var i in type.interfaces) { 1104 for (var i in type.interfaces) {
996 _collectExtensions(i, types); 1105 _collectExtensions(i, types);
997 } 1106 }
998 _collectExtensions(type.superclass, types); 1107 _collectExtensions(type.superclass, types);
999 } 1108 }
1000 1109
1001 JS.Statement _overrideField(FieldElement e) { 1110 JS.Statement _overrideField(JS.Expression className, FieldElement e) {
1002 var cls = e.enclosingElement; 1111 var cls = e.enclosingElement;
1003 return js.statement('dart.virtualField(#, #)', 1112 return js.statement('dart.virtualField(#, #)',
1004 [cls.name, _emitMemberName(e.name, type: cls.type)]); 1113 [className, _emitMemberName(e.name, type: cls.type)]);
1005 } 1114 }
1006 1115
1007 /// Generates the implicit default constructor for class C of the form 1116 /// Generates the implicit default constructor for class C of the form
1008 /// `C() : super() {}`. 1117 /// `C() : super() {}`.
1009 JS.Method _emitImplicitConstructor( 1118 JS.Method _emitImplicitConstructor(
1010 ClassDeclaration node, List<FieldDeclaration> fields) { 1119 ClassDeclaration node, List<FieldDeclaration> fields) {
1011 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty); 1120 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty);
1012 1121
1013 // If we don't have a method body, skip this. 1122 // If we don't have a method body, skip this.
1014 var superCall = _superConstructorCall(node.element); 1123 var superCall = _superConstructorCall(node.element);
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
1122 // Other default constructors use the class name, as they aren't called 1231 // Other default constructors use the class name, as they aren't called
1123 // from call sites, but rather from Object's constructor. 1232 // from call sites, but rather from Object's constructor.
1124 // TODO(jmesserly): revisit in the context of Dart metaclasses, and cleaning 1233 // TODO(jmesserly): revisit in the context of Dart metaclasses, and cleaning
1125 // up constructors to integrate more closely with ES6. 1234 // up constructors to integrate more closely with ES6.
1126 return _propertyName(ctor.isFactory ? 'new' : ctor.enclosingElement.name); 1235 return _propertyName(ctor.isFactory ? 'new' : ctor.enclosingElement.name);
1127 } 1236 }
1128 1237
1129 JS.Block _emitConstructorBody( 1238 JS.Block _emitConstructorBody(
1130 ConstructorDeclaration node, List<FieldDeclaration> fields) { 1239 ConstructorDeclaration node, List<FieldDeclaration> fields) {
1131 var body = <JS.Statement>[]; 1240 var body = <JS.Statement>[];
1241 ClassDeclaration cls = node.parent;
1132 1242
1133 // Generate optional/named argument value assignment. These can not have 1243 // Generate optional/named argument value assignment. These can not have
1134 // side effects, and may be used by the constructor's initializers, so it's 1244 // side effects, and may be used by the constructor's initializers, so it's
1135 // nice to do them first. 1245 // nice to do them first.
1136 // Also for const constructors we need to ensure default values are 1246 // Also for const constructors we need to ensure default values are
1137 // available for use by top-level constant initializers. 1247 // available for use by top-level constant initializers.
1138 ClassDeclaration cls = node.parent;
1139 if (node.constKeyword != null) _loader.startTopLevel(cls.element); 1248 if (node.constKeyword != null) _loader.startTopLevel(cls.element);
1140 var init = _emitArgumentInitializers(node, constructor: true); 1249 var init = _emitArgumentInitializers(node, constructor: true);
1141 if (node.constKeyword != null) _loader.finishTopLevel(cls.element); 1250 if (node.constKeyword != null) _loader.finishTopLevel(cls.element);
1142 if (init != null) body.add(init); 1251 if (init != null) body.add(init);
1143 1252
1144 // Redirecting constructors: these are not allowed to have initializers, 1253 // Redirecting constructors: these are not allowed to have initializers,
1145 // and the redirecting ctor invocation runs before field initializers. 1254 // and the redirecting ctor invocation runs before field initializers.
1146 var redirectCall = node.initializers.firstWhere( 1255 var redirectCall = node.initializers.firstWhere(
1147 (i) => i is RedirectingConstructorInvocation, 1256 (i) => i is RedirectingConstructorInvocation,
1148 orElse: () => null); 1257 orElse: () => null);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1184 ConstructorElement superCtor; 1293 ConstructorElement superCtor;
1185 if (node != null) { 1294 if (node != null) {
1186 superCtor = node.staticElement; 1295 superCtor = node.staticElement;
1187 } else { 1296 } else {
1188 // Get the supertype's unnamed constructor. 1297 // Get the supertype's unnamed constructor.
1189 superCtor = element.supertype.element.unnamedConstructor; 1298 superCtor = element.supertype.element.unnamedConstructor;
1190 if (superCtor == null) { 1299 if (superCtor == null) {
1191 // This will only happen if the code has errors: 1300 // This will only happen if the code has errors:
1192 // we're trying to generate an implicit constructor for a type where 1301 // we're trying to generate an implicit constructor for a type where
1193 // we don't have a default constructor in the supertype. 1302 // we don't have a default constructor in the supertype.
1194 assert(options.forceCompile); 1303 assert(options.unsafeForceCompile);
1195 return null; 1304 return null;
1196 } 1305 }
1197 } 1306 }
1198 1307
1199 if (superCtor == null) { 1308 if (superCtor == null) {
1200 print('Error generating: ${element.displayName}'); 1309 print('Error generating: ${element.displayName}');
1201 } 1310 }
1202 if (superCtor.name == '' && !_shouldCallUnnamedSuperCtor(element)) { 1311 if (superCtor.name == '' && !_shouldCallUnnamedSuperCtor(element)) {
1203 return null; 1312 return null;
1204 } 1313 }
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
1363 } 1472 }
1364 } 1473 }
1365 1474
1366 JS.Fun _emitNativeFunctionBody(MethodDeclaration node) { 1475 JS.Fun _emitNativeFunctionBody(MethodDeclaration node) {
1367 if (node.isStatic) { 1476 if (node.isStatic) {
1368 // TODO(vsm): Do we need to handle this case? 1477 // TODO(vsm): Do we need to handle this case?
1369 return null; 1478 return null;
1370 } 1479 }
1371 1480
1372 var params = visitFormalParameterList(node.parameters, destructure: false); 1481 var params = visitFormalParameterList(node.parameters, destructure: false);
1373 String name = node.name.name; 1482 String name =
1374 var annotation = findAnnotation(node.element, isJsName); 1483 getAnnotationName(node.element, isJSAnnotation) ?? node.name.name;
1375 if (annotation != null) {
1376 name = getConstantField(annotation, 'name', types.stringType)
1377 ?.toStringValue();
1378 }
1379 if (node.isGetter) { 1484 if (node.isGetter) {
1380 return new JS.Fun(params, js.statement('{ return this.#; }', [name])); 1485 return new JS.Fun(params, js.statement('{ return this.#; }', [name]));
1381 } else if (node.isSetter) { 1486 } else if (node.isSetter) {
1382 return new JS.Fun( 1487 return new JS.Fun(
1383 params, js.statement('{ this.# = #; }', [name, params.last])); 1488 params, js.statement('{ this.# = #; }', [name, params.last]));
1384 } else { 1489 } else {
1385 return new JS.Fun( 1490 return new JS.Fun(
1386 params, js.statement('{ return this.#(#); }', [name, params])); 1491 params, js.statement('{ return this.#(#); }', [name, params]));
1387 } 1492 }
1388 } 1493 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1438 returnType: fn.returnType)..sourceInformation = fn.sourceInformation; 1543 returnType: fn.returnType)..sourceInformation = fn.sourceInformation;
1439 } 1544 }
1440 1545
1441 @override 1546 @override
1442 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) { 1547 JS.Statement visitFunctionDeclaration(FunctionDeclaration node) {
1443 assert(node.parent is CompilationUnit); 1548 assert(node.parent is CompilationUnit);
1444 1549
1445 if (_externalOrNative(node)) return null; 1550 if (_externalOrNative(node)) return null;
1446 1551
1447 if (node.isGetter || node.isSetter) { 1552 if (node.isGetter || node.isSetter) {
1448 // Add these later so we can use getter/setter syntax. 1553 // If we have a getter/setter pair, they need to be defined together.
1449 _properties.add(node); 1554 PropertyAccessorElement element = node.element;
1450 return null; 1555 var props = <JS.Method>[];
1556 var getter = element.variable.getter;
1557 if (getter != null) {
1558 props.add(_loader.customEmitDeclaration(getter, _emitTopLevelProperty));
1559 }
1560 var setter = element.variable.setter;
1561 if (setter != null) {
1562 props.add(_loader.customEmitDeclaration(setter, _emitTopLevelProperty));
1563 }
1564
1565 return js.statement('dart.copyProperties(#, { # });',
1566 [emitLibraryName(currentLibrary), props]);
1451 } 1567 }
1452 1568
1453 var body = <JS.Statement>[]; 1569 var body = <JS.Statement>[];
1454 _flushLibraryProperties(body);
1455
1456 var name = node.name.name;
1457 var fn = _emitFunction(node.functionExpression); 1570 var fn = _emitFunction(node.functionExpression);
1458 1571
1459 if (currentLibrary.source.isInSystemLibrary && 1572 if (currentLibrary.source.isInSystemLibrary &&
1460 _isInlineJSFunction(node.functionExpression)) { 1573 _isInlineJSFunction(node.functionExpression)) {
1461 fn = _simplifyPassThroughArrowFunCallBody(fn); 1574 fn = _simplifyPassThroughArrowFunCallBody(fn);
1462 } 1575 }
1463 1576
1464 var id = new JS.Identifier(name); 1577 var element = node.element;
1465 body.add(annotate(new JS.FunctionDeclaration(id, fn), node, node.element)); 1578 var nameExpr = _emitTopLevelName(element);
1466 if (!_isDartRuntime) { 1579 body.add(annotate(js.statement('# = #', [nameExpr, fn]), node, element));
1467 body.add(_emitFunctionTagged(id, node.element.type, topLevel: true) 1580 if (!_isDartRuntime(element.library)) {
1581 body.add(_emitFunctionTagged(nameExpr, element.type, topLevel: true)
1468 .toStatement()); 1582 .toStatement());
1469 } 1583 }
1470 1584
1471 if (isPublic(name)) {
1472 _addExport(name, getJSExportName(node.element, types) ?? name);
1473 }
1474 return _statement(body); 1585 return _statement(body);
1475 } 1586 }
1476 1587
1477 bool _isInlineJSFunction(FunctionExpression functionExpression) { 1588 bool _isInlineJSFunction(FunctionExpression functionExpression) {
1478 var body = functionExpression.body; 1589 var body = functionExpression.body;
1479 if (body is ExpressionFunctionBody) { 1590 if (body is ExpressionFunctionBody) {
1480 return _isJSInvocation(body.expression); 1591 return _isJSInvocation(body.expression);
1481 } else if (body is BlockFunctionBody) { 1592 } else if (body is BlockFunctionBody) {
1482 if (body.block.statements.length == 1) { 1593 var statements = body.block.statements;
1483 var stat = body.block.statements.single; 1594 if (statements.length == 1) {
1595 var stat = statements[0];
1484 if (stat is ReturnStatement) { 1596 if (stat is ReturnStatement) {
1485 return _isJSInvocation(stat.expression); 1597 return _isJSInvocation(stat.expression);
1486 } 1598 }
1487 } 1599 }
1488 } 1600 }
1489 return false; 1601 return false;
1490 } 1602 }
1491 1603
1492 bool _isJSInvocation(Expression expr) => 1604 bool _isJSInvocation(Expression expr) =>
1493 expr is MethodInvocation && isInlineJS(expr.methodName.staticElement); 1605 expr is MethodInvocation && isInlineJS(expr.methodName.staticElement);
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1549 var name = type.name; 1661 var name = type.name;
1550 var lazy = topLevel && !_typeIsLoaded(type); 1662 var lazy = topLevel && !_typeIsLoaded(type);
1551 1663
1552 if (type is FunctionType && (name == '' || name == null)) { 1664 if (type is FunctionType && (name == '' || name == null)) {
1553 if (type.returnType.isDynamic && 1665 if (type.returnType.isDynamic &&
1554 type.optionalParameterTypes.isEmpty && 1666 type.optionalParameterTypes.isEmpty &&
1555 type.namedParameterTypes.isEmpty && 1667 type.namedParameterTypes.isEmpty &&
1556 type.normalParameterTypes.every((t) => t.isDynamic)) { 1668 type.normalParameterTypes.every((t) => t.isDynamic)) {
1557 return js.call('dart.fn(#)', [fn]); 1669 return js.call('dart.fn(#)', [fn]);
1558 } 1670 }
1559 if (lazy) { 1671
1560 return js.call('dart.fn(#, () => #)', [fn, _emitFunctionRTTI(type)]); 1672 String code = lazy ? '() => dart.definiteFunctionType(#)' : '#';
1561 } 1673 return js.call('dart.fn(#, $code)', [fn, _emitFunctionTypeParts(type)]);
1562 return js.call('dart.fn(#, #)', [fn, _emitFunctionTypeParts(type)]);
1563 } 1674 }
1564 throw 'Function has non function type: $type'; 1675 throw 'Function has non function type: $type';
1565 } 1676 }
1566 1677
1567 /// Emits an arrow FunctionExpression node. 1678 /// Emits an arrow FunctionExpression node.
1568 /// 1679 ///
1569 /// This should be used for all places in Dart's AST where FunctionExpression 1680 /// This should be used for all places in Dart's AST where FunctionExpression
1570 /// appears and the function is actually in an Expression context. These 1681 /// appears and the function is actually in an Expression context. These
1571 /// correspond to arrow functions in Dart. 1682 /// correspond to arrow functions in Dart.
1572 /// 1683 ///
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
1729 1840
1730 // Get the original declaring element. If we had a property accessor, this 1841 // Get the original declaring element. If we had a property accessor, this
1731 // indirects back to a (possibly synthetic) field. 1842 // indirects back to a (possibly synthetic) field.
1732 var element = accessor; 1843 var element = accessor;
1733 if (accessor is PropertyAccessorElement) element = accessor.variable; 1844 if (accessor is PropertyAccessorElement) element = accessor.variable;
1734 1845
1735 _loader.declareBeforeUse(element); 1846 _loader.declareBeforeUse(element);
1736 1847
1737 // type literal 1848 // type literal
1738 if (element is TypeDefiningElement) { 1849 if (element is TypeDefiningElement) {
1739 return _emitTypeName( 1850 return _emitTypeName(fillDynamicTypeArgs(element.type));
1740 fillDynamicTypeArgs((element as dynamic).type, types));
1741 } 1851 }
1742 1852
1743 // library member 1853 // library member
1744 if (element.enclosingElement is CompilationUnitElement) { 1854 if (element.enclosingElement is CompilationUnitElement) {
1745 return _emitTopLevelName(element); 1855 return _emitTopLevelName(element);
1746 } 1856 }
1747 1857
1748 var name = element.name; 1858 var name = element.name;
1749 1859
1750 // Unqualified class member. This could mean implicit-this, or implicit 1860 // Unqualified class member. This could mean implicit-this, or implicit
1751 // call to a static from the same class. 1861 // call to a static from the same class.
1752 if (element is ClassMemberElement && element is! ConstructorElement) { 1862 if (element is ClassMemberElement && element is! ConstructorElement) {
1753 bool isStatic = element.isStatic; 1863 bool isStatic = element.isStatic;
1754 var type = element.enclosingElement.type; 1864 var type = element.enclosingElement.type;
1755 var member = _emitMemberName(name, isStatic: isStatic, type: type); 1865 var member = _emitMemberName(name, isStatic: isStatic, type: type);
1756 1866
1757 // For static methods, we add the raw type name, without generics or 1867 // For static methods, we add the raw type name, without generics or
1758 // library prefix. We don't need those because static calls can't use 1868 // library prefix. We don't need those because static calls can't use
1759 // the generic type. 1869 // the generic type.
1760 if (isStatic) { 1870 if (isStatic) {
1761 var dynType = _emitTypeName(fillDynamicTypeArgs(type, types)); 1871 var dynType = _emitTypeName(fillDynamicTypeArgs(type));
1762 return new JS.PropertyAccess(dynType, member); 1872 return new JS.PropertyAccess(dynType, member);
1763 } 1873 }
1764 1874
1765 // For instance members, we add implicit-this. 1875 // For instance members, we add implicit-this.
1766 // For method tear-offs, we ensure it's a bound method. 1876 // For method tear-offs, we ensure it's a bound method.
1767 var tearOff = element is MethodElement && !inInvocationContext(node); 1877 var tearOff = element is MethodElement && !inInvocationContext(node);
1768 var code = (tearOff) ? 'dart.bind(this, #)' : 'this.#'; 1878 var code = (tearOff) ? 'dart.bind(this, #)' : 'this.#';
1769 return js.call(code, member); 1879 return js.call(code, member);
1770 } 1880 }
1771 1881
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
1854 } 1964 }
1855 if (!optionalTypes.isEmpty) { 1965 if (!optionalTypes.isEmpty) {
1856 assert(namedTypes.isEmpty); 1966 assert(namedTypes.isEmpty);
1857 var oa = _emitTypeNames( 1967 var oa = _emitTypeNames(
1858 optionalTypes, parameters?.sublist(parameterTypes.length)); 1968 optionalTypes, parameters?.sublist(parameterTypes.length));
1859 return [rt, ra, oa]; 1969 return [rt, ra, oa];
1860 } 1970 }
1861 return [rt, ra]; 1971 return [rt, ra];
1862 } 1972 }
1863 1973
1864 JS.Expression _emitFunctionRTTI(FunctionType type) {
1865 var parts = _emitFunctionTypeParts(type);
1866 return js.call('dart.definiteFunctionType(#)', [parts]);
1867 }
1868
1869 /// Emits a Dart [type] into code. 1974 /// Emits a Dart [type] into code.
1870 /// 1975 ///
1871 /// If [lowerTypedef] is set, a typedef will be expanded as if it were a 1976 /// If [lowerTypedef] is set, a typedef will be expanded as if it were a
1872 /// function type. Similarly if [lowerGeneric] is set, the `List$()` form 1977 /// function type. Similarly if [lowerGeneric] is set, the `List$()` form
1873 /// will be used instead of `List`. These flags are used when generating 1978 /// will be used instead of `List`. These flags are used when generating
1874 /// the definitions for typedefs and generic types, respectively. 1979 /// the definitions for typedefs and generic types, respectively.
1875 JS.Expression _emitTypeName(DartType type, 1980 JS.Expression _emitTypeName(DartType type,
1876 {bool lowerTypedef: false, bool lowerGeneric: false}) { 1981 {bool lowerTypedef: false, bool lowerGeneric: false}) {
1877 // The void and dynamic types are not defined in core. 1982 // The void and dynamic types are not defined in core.
1878 if (type.isVoid) { 1983 if (type.isVoid) {
(...skipping 10 matching lines...) Expand all
1889 // methods? Similar issue with generic types. For all of these, we may want 1994 // methods? Similar issue with generic types. For all of these, we may want
1890 // to canonicalize them too, at least when inside the same library. 1995 // to canonicalize them too, at least when inside the same library.
1891 var name = type.name; 1996 var name = type.name;
1892 var element = type.element; 1997 var element = type.element;
1893 if (name == '' || name == null || lowerTypedef) { 1998 if (name == '' || name == null || lowerTypedef) {
1894 var parts = _emitFunctionTypeParts(type as FunctionType); 1999 var parts = _emitFunctionTypeParts(type as FunctionType);
1895 return js.call('dart.functionType(#)', [parts]); 2000 return js.call('dart.functionType(#)', [parts]);
1896 } 2001 }
1897 // For now, reify generic method parameters as dynamic 2002 // For now, reify generic method parameters as dynamic
1898 bool _isGenericTypeParameter(DartType type) => 2003 bool _isGenericTypeParameter(DartType type) =>
1899 (type is TypeParameterType) && 2004 type is TypeParameterType &&
1900 !(type.element.enclosingElement is ClassElement || 2005 type.element.enclosingElement is! TypeDefiningElement;
1901 type.element.enclosingElement is FunctionTypeAliasElement);
1902 2006
1903 if (_isGenericTypeParameter(type)) { 2007 if (_isGenericTypeParameter(type)) {
1904 return js.call('dart.dynamic'); 2008 return js.call('dart.dynamic');
1905 } 2009 }
1906 2010
1907 if (type is TypeParameterType) { 2011 if (type is TypeParameterType) {
1908 return new JS.Identifier(name); 2012 return new JS.Identifier(name);
1909 } 2013 }
1910 2014
1911 if (type is ParameterizedType) { 2015 if (type is ParameterizedType) {
1912 var args = type.typeArguments; 2016 var args = type.typeArguments;
1913 var isCurrentClass =
1914 args.isNotEmpty && _loader.isCurrentElement(type.element);
1915 Iterable jsArgs = null; 2017 Iterable jsArgs = null;
1916 if (args 2018 if (args.any((a) => !a.isDynamic && !_isGenericTypeParameter(a))) {
1917 .any((a) => a != types.dynamicType && !_isGenericTypeParameter(a))) {
1918 jsArgs = args.map(_emitTypeName); 2019 jsArgs = args.map(_emitTypeName);
1919 } else if (lowerGeneric || isCurrentClass) { 2020 } else if (lowerGeneric) {
1920 // When creating a `new S<dynamic>` we try and use the raw form
1921 // `new S()`, but this does not work if we're inside the same class,
1922 // because `S` refers to the current S<T> we are generating.
1923 jsArgs = []; 2021 jsArgs = [];
1924 } 2022 }
1925 if (jsArgs != null) { 2023 if (jsArgs != null) {
1926 var genericName = _emitTopLevelName(element, suffix: '\$'); 2024 var genericName = _emitTopLevelName(element, suffix: '\$');
1927 return js.call('#(#)', [genericName, jsArgs]); 2025 return js.call('#(#)', [genericName, jsArgs]);
1928 } 2026 }
1929 } 2027 }
1930 2028
1931 return _emitTopLevelName(element); 2029 return _emitTopLevelName(element);
1932 } 2030 }
1933 2031
1934 JS.Expression _emitTopLevelName(Element e, {String suffix: ''}) { 2032 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) {
1935 var libName = emitLibraryName(e.library); 2033 String name = getJSExportName(e) + suffix;
1936 2034 return new JS.PropertyAccess(
1937 // Always qualify: 2035 emitLibraryName(e.library), _propertyName(name));
1938 // * mutable top-level fields
1939 // * elements from other libraries
1940 bool mutableTopLevel = e is TopLevelVariableElement &&
1941 !e.isConst &&
1942 !_isFinalJSDecl(e.computeNode());
1943 bool fromAnotherLibrary = e.library != currentLibrary;
1944 var nameExpr;
1945 if (fromAnotherLibrary) {
1946 nameExpr = _propertyName((getJSExportName(e, types) ?? e.name) + suffix);
1947 } else {
1948 nameExpr = _propertyName(e.name + suffix);
1949 }
1950 if (mutableTopLevel || fromAnotherLibrary) {
1951 return new JS.PropertyAccess(libName, nameExpr);
1952 }
1953
1954 var id = new JS.MaybeQualifiedId(libName, nameExpr);
1955 _qualifiedIds.add(new Tuple2(e, id));
1956 return id;
1957 } 2036 }
1958 2037
1959 @override 2038 @override
1960 JS.Expression visitAssignmentExpression(AssignmentExpression node) { 2039 JS.Expression visitAssignmentExpression(AssignmentExpression node) {
1961 var left = node.leftHandSide; 2040 var left = node.leftHandSide;
1962 var right = node.rightHandSide; 2041 var right = node.rightHandSide;
1963 if (node.operator.type == TokenType.EQ) return _emitSet(left, right); 2042 if (node.operator.type == TokenType.EQ) return _emitSet(left, right);
1964 var op = node.operator.lexeme; 2043 var op = node.operator.lexeme;
1965 assert(op.endsWith('=')); 2044 assert(op.endsWith('='));
1966 op = op.substring(0, op.length - 1); // remove trailing '=' 2045 op = op.substring(0, op.length - 1); // remove trailing '='
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
2015 } 2094 }
2016 2095
2017 target = _getTarget(lhs); 2096 target = _getTarget(lhs);
2018 id = lhs.propertyName; 2097 id = lhs.propertyName;
2019 } else if (lhs is PrefixedIdentifier) { 2098 } else if (lhs is PrefixedIdentifier) {
2020 target = lhs.prefix; 2099 target = lhs.prefix;
2021 id = lhs.identifier; 2100 id = lhs.identifier;
2022 } 2101 }
2023 2102
2024 if (target != null && DynamicInvoke.get(target)) { 2103 if (target != null && DynamicInvoke.get(target)) {
2025 return js.call('dart.$DPUT(#, #, #)', 2104 return js.call('dart.dput(#, #, #)',
2026 [_visit(target), _emitMemberName(id.name), _visit(rhs)]); 2105 [_visit(target), _emitMemberName(id.name), _visit(rhs)]);
2027 } 2106 }
2028 2107
2029 return _visit(rhs).toAssignExpression(_visit(lhs)); 2108 return _visit(rhs).toAssignExpression(_visit(lhs));
2030 } 2109 }
2031 2110
2032 JS.Expression _emitNullSafeSet(PropertyAccess node, Expression right) { 2111 JS.Expression _emitNullSafeSet(PropertyAccess node, Expression right) {
2033 // Emit `obj?.prop = expr` as: 2112 // Emit `obj?.prop = expr` as:
2034 // 2113 //
2035 // (_ => _ == null ? null : _.prop = expr)(obj). 2114 // (_ => _ == null ? null : _.prop = expr)(obj).
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
2080 return _emitNullSafe(node); 2159 return _emitNullSafe(node);
2081 } 2160 }
2082 2161
2083 var target = _getTarget(node); 2162 var target = _getTarget(node);
2084 var result = _emitForeignJS(node); 2163 var result = _emitForeignJS(node);
2085 if (result != null) return result; 2164 if (result != null) return result;
2086 2165
2087 String code; 2166 String code;
2088 if (target == null || isLibraryPrefix(target)) { 2167 if (target == null || isLibraryPrefix(target)) {
2089 if (DynamicInvoke.get(node.methodName)) { 2168 if (DynamicInvoke.get(node.methodName)) {
2090 code = 'dart.$DCALL(#, #)'; 2169 code = 'dart.dcall(#, #)';
2091 } else { 2170 } else {
2092 code = '#(#)'; 2171 code = '#(#)';
2093 } 2172 }
2094 return js 2173 return js
2095 .call(code, [_visit(node.methodName), _visit(node.argumentList)]); 2174 .call(code, [_visit(node.methodName), _visit(node.argumentList)]);
2096 } 2175 }
2097 2176
2098 var type = getStaticType(target); 2177 var type = getStaticType(target);
2099 var name = node.methodName.name; 2178 var name = node.methodName.name;
2100 var element = node.methodName.staticElement; 2179 var element = node.methodName.staticElement;
2101 bool isStatic = element is ExecutableElement && element.isStatic; 2180 bool isStatic = element is ExecutableElement && element.isStatic;
2102 var memberName = _emitMemberName(name, type: type, isStatic: isStatic); 2181 var memberName = _emitMemberName(name, type: type, isStatic: isStatic);
2103 2182
2104 if (DynamicInvoke.get(target)) { 2183 if (DynamicInvoke.get(target)) {
2105 code = 'dart.$DSEND(#, #, #)'; 2184 code = 'dart.dsend(#, #, #)';
2106 } else if (DynamicInvoke.get(node.methodName)) { 2185 } else if (DynamicInvoke.get(node.methodName)) {
2107 // This is a dynamic call to a statically known target. For example: 2186 // This is a dynamic call to a statically known target. For example:
2108 // class Foo { Function bar; } 2187 // class Foo { Function bar; }
2109 // new Foo().bar(); // dynamic call 2188 // new Foo().bar(); // dynamic call
2110 code = 'dart.$DCALL(#.#, #)'; 2189 code = 'dart.dcall(#.#, #)';
2111 } else if (_requiresStaticDispatch(target, name)) { 2190 } else if (_requiresStaticDispatch(target, name)) {
2112 // Object methods require a helper for null checks. 2191 // Object methods require a helper for null checks.
2113 return js.call('dart.#(#, #)', 2192 return js.call('dart.#(#, #)',
2114 [memberName, _visit(target), _visit(node.argumentList)]); 2193 [memberName, _visit(target), _visit(node.argumentList)]);
2115 } else { 2194 } else {
2116 code = '#.#(#)'; 2195 code = '#.#(#)';
2117 } 2196 }
2118 2197
2119 return js 2198 return js
2120 .call(code, [_visit(target), memberName, _visit(node.argumentList)]); 2199 .call(code, [_visit(target), memberName, _visit(node.argumentList)]);
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2155 return result; 2234 return result;
2156 } 2235 }
2157 return null; 2236 return null;
2158 } 2237 }
2159 2238
2160 @override 2239 @override
2161 JS.Expression visitFunctionExpressionInvocation( 2240 JS.Expression visitFunctionExpressionInvocation(
2162 FunctionExpressionInvocation node) { 2241 FunctionExpressionInvocation node) {
2163 var code; 2242 var code;
2164 if (DynamicInvoke.get(node.function)) { 2243 if (DynamicInvoke.get(node.function)) {
2165 code = 'dart.$DCALL(#, #)'; 2244 code = 'dart.dcall(#, #)';
2166 } else { 2245 } else {
2167 code = '#(#)'; 2246 code = '#(#)';
2168 } 2247 }
2169 return js.call(code, [_visit(node.function), _visit(node.argumentList)]); 2248 return js.call(code, [_visit(node.function), _visit(node.argumentList)]);
2170 } 2249 }
2171 2250
2172 @override 2251 @override
2173 List<JS.Expression> visitArgumentList(ArgumentList node) { 2252 List<JS.Expression> visitArgumentList(ArgumentList node) {
2174 var args = <JS.Expression>[]; 2253 var args = <JS.Expression>[];
2175 var named = <JS.Property>[]; 2254 var named = <JS.Property>[];
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
2210 2289
2211 for (FormalParameter param in node.parameters) { 2290 for (FormalParameter param in node.parameters) {
2212 if (param.kind == ParameterKind.NAMED) { 2291 if (param.kind == ParameterKind.NAMED) {
2213 if (destructure) { 2292 if (destructure) {
2214 if (_jsObjectProperties.contains(param.identifier.name)) { 2293 if (_jsObjectProperties.contains(param.identifier.name)) {
2215 hasNamedArgsConflictingWithObjectProperties = true; 2294 hasNamedArgsConflictingWithObjectProperties = true;
2216 } 2295 }
2217 JS.Expression name; 2296 JS.Expression name;
2218 JS.SimpleBindingPattern structure = null; 2297 JS.SimpleBindingPattern structure = null;
2219 String paramName = param.identifier.name; 2298 String paramName = param.identifier.name;
2220 if (invalidVariableName(paramName)) { 2299 if (JS.invalidVariableName(paramName)) {
2221 name = js.string(paramName); 2300 name = js.string(paramName);
2222 structure = new JS.SimpleBindingPattern(_visit(param.identifier)); 2301 structure = new JS.SimpleBindingPattern(_visit(param.identifier));
2223 } else { 2302 } else {
2224 name = _visit(param.identifier); 2303 name = _visit(param.identifier);
2225 } 2304 }
2226 namedVars.add(new JS.DestructuredVariable( 2305 namedVars.add(new JS.DestructuredVariable(
2227 name: name, 2306 name: name,
2228 structure: structure, 2307 structure: structure,
2229 defaultValue: _defaultParamValue(param))); 2308 defaultValue: _defaultParamValue(param)));
2230 } else { 2309 } else {
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
2318 return jsExpr.toYieldStatement(star: star); 2397 return jsExpr.toYieldStatement(star: star);
2319 } 2398 }
2320 2399
2321 @override 2400 @override
2322 JS.Expression visitAwaitExpression(AwaitExpression node) { 2401 JS.Expression visitAwaitExpression(AwaitExpression node) {
2323 return new JS.Yield(_visit(node.expression)); 2402 return new JS.Yield(_visit(node.expression));
2324 } 2403 }
2325 2404
2326 @override 2405 @override
2327 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { 2406 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
2328 for (var v in node.variables.variables) { 2407 for (var variable in node.variables.variables) {
2329 _loader.loadDeclaration(v, v.element); 2408 _loader.emitDeclaration(variable.element);
2330 } 2409 }
2331 } 2410 }
2332 2411
2333 /// Emits static fields. 2412 /// This is not used--we emit fields as we are emitting the class,
2334 /// 2413 /// see [visitClassDeclaration].
2335 /// Instance fields are emitted in [_initializeFields].
2336 ///
2337 /// These are generally treated the same as top-level fields, see
2338 /// [visitTopLevelVariableDeclaration].
2339 @override 2414 @override
2340 visitFieldDeclaration(FieldDeclaration node) { 2415 visitFieldDeclaration(FieldDeclaration node) {
2341 if (!node.isStatic) return; 2416 assert(false);
2342
2343 node.fields.variables.forEach(_emitModuleItem);
2344 }
2345
2346 _addExport(String name, [String exportName]) {
2347 if (_exports.containsKey(name)) {
2348 throw 'Duplicate top level name found: $name';
2349 }
2350 _exports[name] = exportName ?? name;
2351 } 2417 }
2352 2418
2353 @override 2419 @override
2354 JS.Statement visitVariableDeclarationStatement( 2420 JS.Statement visitVariableDeclarationStatement(
2355 VariableDeclarationStatement node) { 2421 VariableDeclarationStatement node) {
2356 // Special case a single variable with an initializer. 2422 // Special case a single variable with an initializer.
2357 // This helps emit cleaner code for things like: 2423 // This helps emit cleaner code for things like:
2358 // var result = []..add(1)..add(2); 2424 // var result = []..add(1)..add(2);
2359 if (node.variables.variables.length == 1) { 2425 var variables = node.variables.variables;
2360 var v = node.variables.variables.single; 2426 if (variables.length == 1) {
2427 var v = variables[0];
2361 if (v.initializer != null) { 2428 if (v.initializer != null) {
2362 var name = new JS.Identifier(v.name.name); 2429 var name = new JS.Identifier(v.name.name);
2363 return _visit(v.initializer).toVariableDeclaration(name); 2430 return _visit(v.initializer).toVariableDeclaration(name);
2364 } 2431 }
2365 } 2432 }
2366 return _visit(node.variables).toStatement(); 2433 return _visit(node.variables).toStatement();
2367 } 2434 }
2368 2435
2369 @override 2436 @override
2370 visitVariableDeclarationList(VariableDeclarationList node) { 2437 visitVariableDeclarationList(VariableDeclarationList node) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
2412 JS.Expression jsInit = _visitInitializer(field); 2479 JS.Expression jsInit = _visitInitializer(field);
2413 bool isLoaded = _loader.finishCheckingReferences(); 2480 bool isLoaded = _loader.finishCheckingReferences();
2414 2481
2415 bool eagerInit = 2482 bool eagerInit =
2416 isLoaded && (field.isConst || _constField.isFieldInitConstant(field)); 2483 isLoaded && (field.isConst || _constField.isFieldInitConstant(field));
2417 2484
2418 var fieldName = field.name.name; 2485 var fieldName = field.name.name;
2419 if (eagerInit && !JS.invalidStaticFieldName(fieldName)) { 2486 if (eagerInit && !JS.invalidStaticFieldName(fieldName)) {
2420 return annotate( 2487 return annotate(
2421 js.statement('#.# = #;', [ 2488 js.statement('#.# = #;', [
2422 classElem.name, 2489 _emitTopLevelName(classElem),
2423 _emitMemberName(fieldName, isStatic: true), 2490 _emitMemberName(fieldName, isStatic: true),
2424 jsInit 2491 jsInit
2425 ]), 2492 ]),
2426 field, 2493 field,
2427 field.element); 2494 field.element);
2428 } 2495 }
2429 2496
2430 // This means it should be treated as a lazy field. 2497 // This means it should be treated as a lazy field.
2431 // TODO(jmesserly): we're throwing away the initializer expression, 2498 // TODO(jmesserly): we're throwing away the initializer expression,
2432 // which will force us to regenerate it. 2499 // which will force us to regenerate it.
2433 return null; 2500 return null;
2434 } 2501 }
2435 2502
2436 /// Emits a top-level field. 2503 /// Emits a top-level field.
2437 JS.Statement _emitTopLevelField(VariableDeclaration field) { 2504 JS.ModuleItem _emitTopLevelField(VariableDeclaration field) {
2438 TopLevelVariableElement element = field.element; 2505 TopLevelVariableElement element = field.element;
2439 assert(element.isStatic); 2506 assert(element.isStatic);
2440 2507
2441 bool eagerInit; 2508 bool eagerInit;
2442 JS.Expression jsInit; 2509 JS.Expression jsInit;
2443 if (field.isConst || _constField.isFieldInitConstant(field)) { 2510 if (field.isConst || _constField.isFieldInitConstant(field)) {
2444 // If the field is constant, try and generate it at the top level. 2511 // If the field is constant, try and generate it at the top level.
2445 _loader.startTopLevel(element); 2512 _loader.startTopLevel(element);
2446 jsInit = _visitInitializer(field); 2513 jsInit = _visitInitializer(field);
2447 _loader.finishTopLevel(element); 2514 _loader.finishTopLevel(element);
2448 eagerInit = _loader.isLoaded(element); 2515 eagerInit = _loader.isLoaded(element);
2449 } else { 2516 } else {
2450 // TODO(jmesserly): we're visiting the initializer here, and again 2517 // TODO(jmesserly): we're visiting the initializer here, and again
2451 // later on when we emit lazy fields. That seems busted. 2518 // later on when we emit lazy fields. That seems busted.
2452 jsInit = _visitInitializer(field); 2519 jsInit = _visitInitializer(field);
2453 eagerInit = false; 2520 eagerInit = false;
2454 } 2521 }
2455 2522
2456 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile 2523 // Treat `final x = JS('', '...')` as a const (non-lazy) to help compile
2457 // runtime helpers. 2524 // runtime helpers.
2525 // TODO(jmesserly): we don't track dependencies correctly for these.
2458 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field); 2526 var isJSTopLevel = field.isFinal && _isFinalJSDecl(field);
2459 if (isJSTopLevel) eagerInit = true; 2527 if (eagerInit || isJSTopLevel) {
2460 2528 return annotate(
2461 var fieldName = field.name.name; 2529 js.statement('# = #;', [_emitTopLevelName(element), jsInit]),
2462 var exportName = fieldName; 2530 field,
2463 if (element is TopLevelVariableElement) { 2531 element);
2464 exportName = getJSExportName(element, types) ?? fieldName;
2465 }
2466 if ((field.isConst && eagerInit && element is TopLevelVariableElement) ||
2467 isJSTopLevel) {
2468 // constant fields don't change, so we can generate them as `let`
2469 // but add them to the module's exports. However, make sure we generate
2470 // anything they depend on first.
2471
2472 if (isPublic(fieldName)) _addExport(fieldName, exportName);
2473 var declKeyword = field.isConst || field.isFinal ? 'const' : 'let';
2474 if (isJSTopLevel && jsInit is JS.ClassExpression) {
2475 return new JS.ClassDeclaration(jsInit);
2476 }
2477 return js.statement('#;', [
2478 annotate(
2479 new JS.VariableDeclarationList(declKeyword, [
2480 new JS.VariableInitialization(
2481 new JS.Identifier(fieldName,
2482 type: emitTypeRef(field.element.type)),
2483 jsInit)
2484 ]),
2485 field,
2486 field.element)
2487 ]);
2488 } 2532 }
2489 2533
2490 if (eagerInit && !JS.invalidStaticFieldName(fieldName)) { 2534 assert(element.library == currentLibrary);
2491 return annotate(js.statement('# = #;', [_visit(field.name), jsInit]), 2535 return _emitLazyFields(element.library, [field]);
2492 field, field.element);
2493 }
2494
2495 return _emitLazyFields(currentLibrary, [field]);
2496 } 2536 }
2497 2537
2498 JS.Expression _visitInitializer(VariableDeclaration node) { 2538 JS.Expression _visitInitializer(VariableDeclaration node) {
2499 var value = _visit(node.initializer); 2539 var value = _visit(node.initializer);
2500 // explicitly initialize to null, to avoid getting `undefined`. 2540 // explicitly initialize to null, to avoid getting `undefined`.
2501 // TODO(jmesserly): do this only for vars that aren't definitely assigned. 2541 // TODO(jmesserly): do this only for vars that aren't definitely assigned.
2502 return value ?? new JS.LiteralNull(); 2542 return value ?? new JS.LiteralNull();
2503 } 2543 }
2504 2544
2505 JS.Statement _emitLazyFields( 2545 JS.Statement _emitLazyFields(
(...skipping 17 matching lines...) Expand all
2523 methods.add(annotate( 2563 methods.add(annotate(
2524 new JS.Method(access, js.call('function(_) {}') as JS.Fun, 2564 new JS.Method(access, js.call('function(_) {}') as JS.Fun,
2525 isSetter: true), 2565 isSetter: true),
2526 node, 2566 node,
2527 _findAccessor(element, getter: false))); 2567 _findAccessor(element, getter: false)));
2528 } 2568 }
2529 } 2569 }
2530 2570
2531 JS.Expression objExpr; 2571 JS.Expression objExpr;
2532 if (target is ClassElement) { 2572 if (target is ClassElement) {
2533 objExpr = new JS.Identifier(target.type.name); 2573 objExpr = _emitTopLevelName(target);
2534 } else { 2574 } else {
2535 objExpr = emitLibraryName(target); 2575 objExpr = emitLibraryName(target);
2536 } 2576 }
2537 2577
2538 return js 2578 return js.statement('dart.defineLazy(#, { # });', [objExpr, methods]);
2539 .statement('dart.defineLazyProperties(#, { # });', [objExpr, methods]);
2540 } 2579 }
2541 2580
2542 PropertyAccessorElement _findAccessor(VariableElement element, 2581 PropertyAccessorElement _findAccessor(VariableElement element,
2543 {bool getter}) { 2582 {bool getter}) {
2544 var parent = element.enclosingElement; 2583 var parent = element.enclosingElement;
2545 if (parent is ClassElement) { 2584 if (parent is ClassElement) {
2546 return getter 2585 return getter
2547 ? parent.getGetter(element.name) 2586 ? parent.getGetter(element.name)
2548 : parent.getSetter(element.name); 2587 : parent.getSetter(element.name);
2549 } 2588 }
2550 return null; 2589 return null;
2551 } 2590 }
2552 2591
2553 void _flushLibraryProperties(List<JS.Statement> body) {
2554 if (_properties.isEmpty) return;
2555 body.add(js.statement('dart.copyProperties(#, { # });',
2556 [_exportsVar, _properties.map(_emitTopLevelProperty)]));
2557 _properties.clear();
2558 }
2559
2560 JS.Expression _emitConstructorName( 2592 JS.Expression _emitConstructorName(
2561 ConstructorElement element, DartType type, SimpleIdentifier name) { 2593 ConstructorElement element, DartType type, SimpleIdentifier name) {
2562 var typeName = _emitTypeName(type); 2594 var typeName = _emitTypeName(type);
2563 if (name != null || element.isFactory) { 2595 if (name != null || element.isFactory) {
2564 var namedCtor = _constructorName(element); 2596 var namedCtor = _constructorName(element);
2565 return new JS.PropertyAccess(typeName, namedCtor); 2597 return new JS.PropertyAccess(typeName, namedCtor);
2566 } 2598 }
2567 return typeName; 2599 return typeName;
2568 } 2600 }
2569 2601
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
2608 var type = constructor.type.type; 2640 var type = constructor.type.type;
2609 return _emitInstanceCreationExpression( 2641 return _emitInstanceCreationExpression(
2610 element, type, name, node.argumentList, node.isConst); 2642 element, type, name, node.argumentList, node.isConst);
2611 } 2643 }
2612 2644
2613 /// True if this type is built-in to JS, and we use the values unwrapped. 2645 /// True if this type is built-in to JS, and we use the values unwrapped.
2614 /// For these types we generate a calling convention via static 2646 /// For these types we generate a calling convention via static
2615 /// "extension methods". This allows types to be extended without adding 2647 /// "extension methods". This allows types to be extended without adding
2616 /// extensions directly on the prototype. 2648 /// extensions directly on the prototype.
2617 bool isPrimitiveType(DartType t) => 2649 bool isPrimitiveType(DartType t) =>
2618 typeIsPrimitiveInJS(t) || t == _types.stringType; 2650 typeIsPrimitiveInJS(t) || t == types.stringType;
2619 2651
2620 bool typeIsPrimitiveInJS(DartType t) => 2652 bool typeIsPrimitiveInJS(DartType t) =>
2621 _isNumberInJS(t) || t == _types.boolType; 2653 _isNumberInJS(t) || t == types.boolType;
2622 2654
2623 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) => 2655 bool binaryOperationIsPrimitive(DartType leftT, DartType rightT) =>
2624 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT); 2656 typeIsPrimitiveInJS(leftT) && typeIsPrimitiveInJS(rightT);
2625 2657
2626 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t); 2658 bool unaryOperationIsPrimitive(DartType t) => typeIsPrimitiveInJS(t);
2627 2659
2628 JS.Expression notNull(Expression expr) { 2660 JS.Expression notNull(Expression expr) {
2629 if (expr == null) return null; 2661 if (expr == null) return null;
2630 var jsExpr = _visit(expr); 2662 var jsExpr = _visit(expr);
2631 if (!isNullable(expr)) return jsExpr; 2663 if (!isNullable(expr)) return jsExpr;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2663 2695
2664 var vars = <String, JS.Expression>{}; 2696 var vars = <String, JS.Expression>{};
2665 // Desugar `l ?? r` as `l != null ? l : r` 2697 // Desugar `l ?? r` as `l != null ? l : r`
2666 var l = _visit(_bindValue(vars, 'l', left, context: left)); 2698 var l = _visit(_bindValue(vars, 'l', left, context: left));
2667 return new JS.MetaLet(vars, [ 2699 return new JS.MetaLet(vars, [
2668 js.call('# != null ? # : #', [l, l, _visit(right)]) 2700 js.call('# != null ? # : #', [l, l, _visit(right)])
2669 ]); 2701 ]);
2670 } 2702 }
2671 2703
2672 if (binaryOperationIsPrimitive(leftType, rightType) || 2704 if (binaryOperationIsPrimitive(leftType, rightType) ||
2673 leftType == _types.stringType && op.type == TokenType.PLUS) { 2705 leftType == types.stringType && op.type == TokenType.PLUS) {
2674 // special cases where we inline the operation 2706 // special cases where we inline the operation
2675 // these values are assumed to be non-null (determined by the checker) 2707 // these values are assumed to be non-null (determined by the checker)
2676 // TODO(jmesserly): it would be nice to just inline the method from core, 2708 // TODO(jmesserly): it would be nice to just inline the method from core,
2677 // instead of special cases here. 2709 // instead of special cases here.
2678 if (op.type == TokenType.TILDE_SLASH) { 2710 if (op.type == TokenType.TILDE_SLASH) {
2679 // `a ~/ b` is equivalent to `(a / b).truncate()` 2711 // `a ~/ b` is equivalent to `(a / b).truncate()`
2680 var div = AstBuilder.binaryExpression(left, '/', right) 2712 var div = AstBuilder.binaryExpression(left, '/', right)
2681 ..staticType = node.staticType; 2713 ..staticType = node.staticType;
2682 return _emitSend(div, 'truncate', []); 2714 return _emitSend(div, 'truncate', []);
2683 } else { 2715 } else {
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after
3012 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. 3044 /// Shared code for [PrefixedIdentifier] and [PropertyAccess].
3013 JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) { 3045 JS.Expression _emitGet(Expression target, SimpleIdentifier memberId) {
3014 var member = memberId.staticElement; 3046 var member = memberId.staticElement;
3015 if (member is PropertyAccessorElement) { 3047 if (member is PropertyAccessorElement) {
3016 member = (member as PropertyAccessorElement).variable; 3048 member = (member as PropertyAccessorElement).variable;
3017 } 3049 }
3018 bool isStatic = member is ClassMemberElement && member.isStatic; 3050 bool isStatic = member is ClassMemberElement && member.isStatic;
3019 var name = _emitMemberName(memberId.name, 3051 var name = _emitMemberName(memberId.name,
3020 type: getStaticType(target), isStatic: isStatic); 3052 type: getStaticType(target), isStatic: isStatic);
3021 if (DynamicInvoke.get(target)) { 3053 if (DynamicInvoke.get(target)) {
3022 return js.call('dart.$DLOAD(#, #)', [_visit(target), name]); 3054 return js.call('dart.dload(#, #)', [_visit(target), name]);
3023 } 3055 }
3024 3056
3025 String code; 3057 String code;
3026 if (member != null && member is MethodElement && !isStatic) { 3058 if (member != null && member is MethodElement && !isStatic) {
3027 // Tear-off methods: explicitly bind it. 3059 // Tear-off methods: explicitly bind it.
3028 if (target is SuperExpression) { 3060 if (target is SuperExpression) {
3029 return js.call('dart.bind(this, #, #.#)', [name, _visit(target), name]); 3061 return js.call('dart.bind(this, #, #.#)', [name, _visit(target), name]);
3030 } else if (_requiresStaticDispatch(target, memberId.name)) { 3062 } else if (_requiresStaticDispatch(target, memberId.name)) {
3031 var type = member.type; 3063 var type = member.type;
3032 var clos = js.call('dart.#.bind(#)', [name, _visit(target)]); 3064 var clos = js.call('dart.#.bind(#)', [name, _visit(target)]);
(...skipping 13 matching lines...) Expand all
3046 /// 3078 ///
3047 /// **Please note** this function does not support method invocation syntax 3079 /// **Please note** this function does not support method invocation syntax
3048 /// `obj.name(args)` because that could be a getter followed by a call. 3080 /// `obj.name(args)` because that could be a getter followed by a call.
3049 /// See [visitMethodInvocation]. 3081 /// See [visitMethodInvocation].
3050 JS.Expression _emitSend( 3082 JS.Expression _emitSend(
3051 Expression target, String name, List<Expression> args) { 3083 Expression target, String name, List<Expression> args) {
3052 var type = getStaticType(target); 3084 var type = getStaticType(target);
3053 var memberName = _emitMemberName(name, unary: args.isEmpty, type: type); 3085 var memberName = _emitMemberName(name, unary: args.isEmpty, type: type);
3054 if (DynamicInvoke.get(target)) { 3086 if (DynamicInvoke.get(target)) {
3055 // dynamic dispatch 3087 // dynamic dispatch
3056 var dynamicHelper = const {'[]': DINDEX, '[]=': DSETINDEX}[name]; 3088 var dynamicHelper = const {'[]': 'dindex', '[]=': 'dsetindex'}[name];
3057 if (dynamicHelper != null) { 3089 if (dynamicHelper != null) {
3058 return js.call( 3090 return js.call(
3059 'dart.$dynamicHelper(#, #)', [_visit(target), _visitList(args)]); 3091 'dart.$dynamicHelper(#, #)', [_visit(target), _visitList(args)]);
3060 } 3092 }
3061 return js.call('dart.$DSEND(#, #, #)', 3093 return js.call('dart.dsend(#, #, #)',
3062 [_visit(target), memberName, _visitList(args)]); 3094 [_visit(target), memberName, _visitList(args)]);
3063 } 3095 }
3064 3096
3065 // Generic dispatch to a statically known method. 3097 // Generic dispatch to a statically known method.
3066 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]); 3098 return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]);
3067 } 3099 }
3068 3100
3069 @override 3101 @override
3070 visitIndexExpression(IndexExpression node) { 3102 visitIndexExpression(IndexExpression node) {
3071 var target = _getTarget(node); 3103 var target = _getTarget(node);
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
3182 // } 3214 // }
3183 // } finally { 3215 // } finally {
3184 // await iter.cancel(); 3216 // await iter.cancel();
3185 // } 3217 // }
3186 // 3218 //
3187 // Like the Dart VM, we call cancel() always, as it's safe to call if the 3219 // Like the Dart VM, we call cancel() always, as it's safe to call if the
3188 // stream has already been cancelled. 3220 // stream has already been cancelled.
3189 // 3221 //
3190 // TODO(jmesserly): we may want a helper if these become common. For now the 3222 // TODO(jmesserly): we may want a helper if these become common. For now the
3191 // full desugaring seems okay. 3223 // full desugaring seems okay.
3192 var context = compiler.context; 3224 var streamIterator = rules.instantiateToBounds(_asyncStreamIterator);
3193 var dart_async = context
3194 .computeLibraryElement(context.sourceFactory.forUri('dart:async'));
3195 var _streamIteratorType =
3196 rules.instantiateToBounds(dart_async.getType('StreamIterator').type);
3197
3198 var createStreamIter = _emitInstanceCreationExpression( 3225 var createStreamIter = _emitInstanceCreationExpression(
3199 _streamIteratorType.element.unnamedConstructor, 3226 streamIterator.element.unnamedConstructor,
3200 _streamIteratorType, 3227 streamIterator,
3201 null, 3228 null,
3202 AstBuilder.argumentList([node.iterable]), 3229 AstBuilder.argumentList([node.iterable]),
3203 false); 3230 false);
3204 var iter = 3231 var iter = _visit(_createTemporary('it', streamIterator, nullable: false));
3205 _visit(_createTemporary('it', _streamIteratorType, nullable: false));
3206 3232
3207 var init = _visit(node.identifier); 3233 var init = _visit(node.identifier);
3208 if (init == null) { 3234 if (init == null) {
3209 init = js 3235 init = js
3210 .call('let # = #.current', [node.loopVariable.identifier.name, iter]); 3236 .call('let # = #.current', [node.loopVariable.identifier.name, iter]);
3211 } else { 3237 } else {
3212 init = js.call('# = #.current', [init, iter]); 3238 init = js.call('# = #.current', [init, iter]);
3213 } 3239 }
3214 return js.statement( 3240 return js.statement(
3215 '{' 3241 '{'
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
3493 return result; 3519 return result;
3494 } 3520 }
3495 3521
3496 /// Visits a list of expressions, creating a comma expression if needed in JS. 3522 /// Visits a list of expressions, creating a comma expression if needed in JS.
3497 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { 3523 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) {
3498 if (nodes == null || nodes.isEmpty) return null; 3524 if (nodes == null || nodes.isEmpty) return null;
3499 return new JS.Expression.binary( 3525 return new JS.Expression.binary(
3500 _visitList(nodes) as List<JS.Expression>, operator); 3526 _visitList(nodes) as List<JS.Expression>, operator);
3501 } 3527 }
3502 3528
3503 /// Return the bound type parameters for a ParameterizedType
3504 List<TypeParameterElement> _typeFormalsOf(ParameterizedType type) {
3505 return type is FunctionType ? type.typeFormals : type.typeParameters;
3506 }
3507
3508 /// Like [_emitMemberName], but for declaration sites. 3529 /// Like [_emitMemberName], but for declaration sites.
3509 /// 3530 ///
3510 /// Unlike call sites, we always have an element available, so we can use it 3531 /// Unlike call sites, we always have an element available, so we can use it
3511 /// directly rather than computing the relevant options for [_emitMemberName]. 3532 /// directly rather than computing the relevant options for [_emitMemberName].
3512 JS.Expression _elementMemberName(ExecutableElement e, 3533 JS.Expression _elementMemberName(ExecutableElement e,
3513 {bool allowExtensions: true}) { 3534 {bool allowExtensions: true}) {
3514 String name; 3535 String name;
3515 if (e is PropertyAccessorElement) { 3536 if (e is PropertyAccessorElement) {
3516 name = e.variable.name; 3537 name = e.variable.name;
3517 } else { 3538 } else {
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
3567 /// 3588 ///
3568 JS.Expression _emitMemberName(String name, 3589 JS.Expression _emitMemberName(String name,
3569 {DartType type, 3590 {DartType type,
3570 bool unary: false, 3591 bool unary: false,
3571 bool isStatic: false, 3592 bool isStatic: false,
3572 bool allowExtensions: true}) { 3593 bool allowExtensions: true}) {
3573 // Static members skip the rename steps. 3594 // Static members skip the rename steps.
3574 if (isStatic) return _propertyName(name); 3595 if (isStatic) return _propertyName(name);
3575 3596
3576 if (name.startsWith('_')) { 3597 if (name.startsWith('_')) {
3577 return _privateNames.putIfAbsent( 3598 return _emitPrivateNameSymbol(currentLibrary, name);
3578 name, () => _initSymbol(new JS.TemporaryId(name)) as JS.TemporaryId);
3579 } 3599 }
3580 3600
3581 if (name == '[]') { 3601 if (name == '[]') {
3582 name = 'get'; 3602 name = 'get';
3583 } else if (name == '[]=') { 3603 } else if (name == '[]=') {
3584 name = 'set'; 3604 name = 'set';
3585 } else if (name == '-' && unary) { 3605 } else if (name == '-' && unary) {
3586 name = 'unary-'; 3606 name = 'unary-';
3587 } else if (name == 'constructor' || name == 'prototype') { 3607 } else if (name == 'constructor' || name == 'prototype') {
3588 // This uses an illegal (in Dart) character for a member, avoiding the 3608 // This uses an illegal (in Dart) character for a member, avoiding the
3589 // conflict. We could use practically any character for this. 3609 // conflict. We could use practically any character for this.
3590 name = '+$name'; 3610 name = '+$name';
3591 } 3611 }
3592 3612
3593 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. 3613 // Dart "extension" methods. Used for JS Array, Boolean, Number, String.
3594 var baseType = type; 3614 var baseType = type;
3595 while (baseType is TypeParameterType) { 3615 while (baseType is TypeParameterType) {
3596 baseType = baseType.element.bound; 3616 baseType = baseType.element.bound;
3597 } 3617 }
3598 if (allowExtensions && 3618 if (allowExtensions &&
3599 baseType != null && 3619 baseType != null &&
3600 _extensionTypes.contains(baseType.element) && 3620 _extensionTypes.contains(baseType.element) &&
3601 !isObjectProperty(name)) { 3621 !isObjectProperty(name)) {
3602 return js.call('dartx.#', _propertyName(name)); 3622 return js.call('dartx.#', _propertyName(name));
3603 } 3623 }
3604 3624
3605 return _propertyName(name); 3625 return _propertyName(name);
3606 } 3626 }
3607 3627
3628 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) {
3629 return _privateNames
3630 .putIfAbsent(library, () => new HashMap())
3631 .putIfAbsent(name, () {
3632 var id = new JS.TemporaryId(name);
3633 _moduleItems.add(
3634 js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
3635 return id;
3636 });
3637 }
3638
3608 bool _externalOrNative(node) => 3639 bool _externalOrNative(node) =>
3609 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; 3640 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody;
3610 3641
3611 FunctionBody _functionBody(node) => 3642 FunctionBody _functionBody(node) =>
3612 node is FunctionDeclaration ? node.functionExpression.body : node.body; 3643 node is FunctionDeclaration ? node.functionExpression.body : node.body;
3613 3644
3614 /// Choose a canonical name from the library element. 3645 /// Returns the canonical name to refer to the Dart library.
3615 /// This never uses the library's name (the identifier in the `library`
3616 /// declaration) as it doesn't have any meaningful rules enforced.
3617 JS.Identifier emitLibraryName(LibraryElement library) { 3646 JS.Identifier emitLibraryName(LibraryElement library) {
3618 if (library == currentLibrary) return _exportsVar; 3647 // It's either one of the libraries in this module, or it's an import.
3619 if (library.name == 'dart._runtime') return _runtimeLibVar; 3648 return _libraries[library] ??
3620 return _imports.putIfAbsent( 3649 _imports.putIfAbsent(
3621 library, () => new JS.TemporaryId(jsLibraryName(library))); 3650 library, () => new JS.TemporaryId(jsLibraryName(library)));
3622 } 3651 }
3623 3652
3624 JS.Node annotate(JS.Node node, AstNode original, [Element element]) { 3653 JS.Node annotate(JS.Node node, AstNode original, [Element element]) {
3625 if (options.closure && element != null) { 3654 if (options.closure && element != null) {
3626 node = node.withClosureAnnotation(closureAnnotationFor( 3655 node = node.withClosureAnnotation(closureAnnotationFor(
3627 node, original, element, namedArgumentTemp.name)); 3656 node, original, element, namedArgumentTemp.name));
3628 } 3657 }
3629 return node..sourceInformation = original; 3658 return node..sourceInformation = original;
3630 } 3659 }
3631 3660
3632 /// Returns true if this is any kind of object represented by `Number` in JS. 3661 /// Returns true if this is any kind of object represented by `Number` in JS.
3633 /// 3662 ///
3634 /// In practice, this is 4 types: num, int, double, and JSNumber. 3663 /// In practice, this is 4 types: num, int, double, and JSNumber.
3635 /// 3664 ///
3636 /// JSNumber is the type that actually "implements" all numbers, hence it's 3665 /// JSNumber is the type that actually "implements" all numbers, hence it's
3637 /// a subtype of int and double (and num). It's in our "dart:_interceptors". 3666 /// a subtype of int and double (and num). It's in our "dart:_interceptors".
3638 bool _isNumberInJS(DartType t) => rules.isSubtypeOf(t, _types.numType); 3667 bool _isNumberInJS(DartType t) => rules.isSubtypeOf(t, types.numType);
3639 3668
3640 bool _isObjectGetter(String name) { 3669 bool _isObjectGetter(String name) {
3641 PropertyAccessorElement element = _types.objectType.element.getGetter(name); 3670 PropertyAccessorElement element = types.objectType.element.getGetter(name);
3642 return (element != null && !element.isStatic); 3671 return (element != null && !element.isStatic);
3643 } 3672 }
3644 3673
3645 bool _isObjectMethod(String name) { 3674 bool _isObjectMethod(String name) {
3646 MethodElement element = _types.objectType.element.getMethod(name); 3675 MethodElement element = types.objectType.element.getMethod(name);
3647 return (element != null && !element.isStatic); 3676 return (element != null && !element.isStatic);
3648 } 3677 }
3649 3678
3650 bool isObjectProperty(String name) { 3679 bool isObjectProperty(String name) {
3651 return _isObjectGetter(name) || _isObjectMethod(name); 3680 return _isObjectGetter(name) || _isObjectMethod(name);
3652 } 3681 }
3653 3682
3654 // TODO(leafp): Various analyzer pieces computed similar things. 3683 // TODO(leafp): Various analyzer pieces computed similar things.
3655 // Share this logic somewhere? 3684 // Share this logic somewhere?
3656 DartType _getExpectedReturnType(ExecutableElement element) { 3685 DartType _getExpectedReturnType(ExecutableElement element) {
3657 FunctionType functionType = element.type; 3686 FunctionType functionType = element.type;
3658 if (functionType == null) { 3687 if (functionType == null) {
3659 return DynamicTypeImpl.instance; 3688 return DynamicTypeImpl.instance;
3660 } 3689 }
3661 var type = functionType.returnType; 3690 var type = functionType.returnType;
3662 3691
3663 InterfaceType expectedType = null; 3692 InterfaceType expectedType = null;
3664 if (element.isAsynchronous) { 3693 if (element.isAsynchronous) {
3665 if (element.isGenerator) { 3694 if (element.isGenerator) {
3666 // Stream<T> -> T 3695 // Stream<T> -> T
3667 expectedType = _types.streamType; 3696 expectedType = types.streamType;
3668 } else { 3697 } else {
3669 // Future<T> -> T 3698 // Future<T> -> T
3670 // TODO(vsm): Revisit with issue #228. 3699 // TODO(vsm): Revisit with issue #228.
3671 expectedType = _types.futureType; 3700 expectedType = types.futureType;
3672 } 3701 }
3673 } else { 3702 } else {
3674 if (element.isGenerator) { 3703 if (element.isGenerator) {
3675 // Iterable<T> -> T 3704 // Iterable<T> -> T
3676 expectedType = _types.iterableType; 3705 expectedType = types.iterableType;
3677 } else { 3706 } else {
3678 // T -> T 3707 // T -> T
3679 return type; 3708 return type;
3680 } 3709 }
3681 } 3710 }
3682 if (type.isDynamic) { 3711 if (type.isDynamic) {
3683 return type; 3712 return type;
3684 } else if (type is InterfaceType && type.element == expectedType.element) { 3713 } else if (type is InterfaceType && type.element == expectedType.element) {
3685 return type.typeArguments[0]; 3714 return type.typeArguments[0];
3686 } else { 3715 } else {
3687 // TODO(leafp): The above only handles the case where the return type 3716 // TODO(leafp): The above only handles the case where the return type
3688 // is exactly Future/Stream/Iterable. Handle the subtype case. 3717 // is exactly Future/Stream/Iterable. Handle the subtype case.
3689 return DynamicTypeImpl.instance; 3718 return DynamicTypeImpl.instance;
3690 } 3719 }
3691 } 3720 }
3692 } 3721 }
3693 3722
3694 class ExtensionTypeSet extends GeneralizingElementVisitor {
3695 final AnalysisContext _context;
3696 final TypeProvider _types;
3697
3698 final _extensionTypes = new HashSet<ClassElement>();
3699 final _pendingLibraries = new HashSet<String>();
3700
3701 ExtensionTypeSet(AbstractCompiler compiler)
3702 : _context = compiler.context,
3703 _types = compiler.context.typeProvider;
3704
3705 visitClassElement(ClassElement element) {
3706 if (findAnnotation(element, isJsPeerInterface) != null ||
3707 findAnnotation(element, isNativeAnnotation) != null) {
3708 _addExtensionType(element.type);
3709 }
3710 }
3711
3712 void _addExtensionType(InterfaceType t) {
3713 if (t.isObject || !_extensionTypes.add(t.element)) return;
3714 t = fillDynamicTypeArgs(t, _types) as InterfaceType;
3715 t.interfaces.forEach(_addExtensionType);
3716 t.mixins.forEach(_addExtensionType);
3717 _addExtensionType(t.superclass);
3718 }
3719
3720 void _addExtensionTypesForLibrary(String libraryUri, List<String> typeNames) {
3721 var sourceFactory = _context.sourceFactory.forUri(libraryUri);
3722 var library = _context.computeLibraryElement(sourceFactory);
3723 for (var typeName in typeNames) {
3724 var element = library.getType(typeName);
3725 _addExtensionType(element.type);
3726 }
3727 }
3728
3729 void _addExtensionTypes(String libraryUri) {
3730 var sourceFactory = _context.sourceFactory.forUri(libraryUri);
3731 var library = _context.computeLibraryElement(sourceFactory);
3732 visitLibraryElement(library);
3733 }
3734
3735 void _addPendingExtensionTypes(String libraryUri) {
3736 _pendingLibraries.add(libraryUri);
3737 }
3738
3739 bool contains(Element element) {
3740 if (_extensionTypes.contains(element)) return true;
3741 if (_pendingLibraries.isEmpty) return false;
3742 if (element is ClassElement) {
3743 var uri = element.library.source.uri.toString();
3744 if (_pendingLibraries.contains(uri)) {
3745 // Load all pending libraries
3746 for (var libraryUri in _pendingLibraries) {
3747 _addExtensionTypes(libraryUri);
3748 }
3749 _pendingLibraries.clear();
3750 return _extensionTypes.contains(element);
3751 }
3752 }
3753 return false;
3754 }
3755 }
3756
3757 class JSGenerator {
3758 final AbstractCompiler compiler;
3759 final ExtensionTypeSet _extensionTypes;
3760 final TypeProvider _types;
3761
3762 JSGenerator(AbstractCompiler compiler)
3763 : compiler = compiler,
3764 _types = compiler.context.typeProvider,
3765 _extensionTypes = new ExtensionTypeSet(compiler) {
3766 // TODO(vsm): Eventually, we want to make this extensible - i.e., find
3767 // annotations in user code as well. It would need to be summarized in
3768 // the element model - not searched this way on every compile. To make this
3769 // a little more efficient now, we do this in two phases.
3770
3771 // First, core types:
3772 _extensionTypes._addExtensionTypes('dart:_interceptors');
3773 _extensionTypes._addExtensionTypes('dart:_native_typed_data');
3774 // TODO(vsm): If we're analyzing against the main SDK, those
3775 // types are not explicitly annotated.
3776 _extensionTypes._addExtensionType(_types.intType);
3777 _extensionTypes._addExtensionType(_types.doubleType);
3778 _extensionTypes._addExtensionType(_types.boolType);
3779 _extensionTypes._addExtensionType(_types.stringType);
3780 // These are used natively by dart:html but also not annotated.
3781 _extensionTypes
3782 ._addExtensionTypesForLibrary('dart:core', ['Comparable', 'Map']);
3783 _extensionTypes
3784 ._addExtensionTypesForLibrary('dart:collection', ['ListMixin']);
3785 _extensionTypes._addExtensionTypesForLibrary('dart:math', ['Rectangle']);
3786
3787 // Second, html types - these are only searched if we use dart:html, etc.:
3788 _extensionTypes._addPendingExtensionTypes('dart:html');
3789 _extensionTypes._addPendingExtensionTypes('dart:indexed_db');
3790 _extensionTypes._addPendingExtensionTypes('dart:svg');
3791 _extensionTypes._addPendingExtensionTypes('dart:web_audio');
3792 _extensionTypes._addPendingExtensionTypes('dart:web_gl');
3793 _extensionTypes._addPendingExtensionTypes('dart:web_sql');
3794 }
3795
3796 void generateLibrary(List<CompilationUnit> units) {
3797 var library = units.first.element.library;
3798 var fields =
3799 findFieldsNeedingStorage(units.map((c) => c.element), _extensionTypes);
3800 var rules = new StrongTypeSystemImpl();
3801 var codegen =
3802 new JSCodegenVisitor(compiler, rules, library, _extensionTypes, fields);
3803 var module = codegen.emitLibrary(units);
3804 var out = compiler.getOutputPath(library.source.uri);
3805 var options = compiler.options.codegenOptions;
3806 writeJsLibrary(module, out, compiler.inputBaseDir,
3807 emitTypes: options.closure,
3808 emitSourceMaps: options.emitSourceMaps,
3809 fileSystem: compiler.fileSystem);
3810 }
3811 }
3812
3813 /// Choose a canonical name from the library element. 3723 /// Choose a canonical name from the library element.
3814 /// This never uses the library's name (the identifier in the `library` 3724 /// This never uses the library's name (the identifier in the `library`
3815 /// declaration) as it doesn't have any meaningful rules enforced. 3725 /// declaration) as it doesn't have any meaningful rules enforced.
3816 String jsLibraryName(LibraryElement library) => canonicalLibraryName(library); 3726 String jsLibraryName(LibraryElement library) {
3727 return pathToJSIdentifier(library.source.uri.pathSegments.last);
3728 }
3817 3729
3818 /// Shorthand for identifier-like property names. 3730 /// Shorthand for identifier-like property names.
3819 /// For now, we emit them as strings and the printer restores them to 3731 /// For now, we emit them as strings and the printer restores them to
3820 /// identifiers if it can. 3732 /// identifiers if it can.
3821 // TODO(jmesserly): avoid the round tripping through quoted form. 3733 // TODO(jmesserly): avoid the round tripping through quoted form.
3822 JS.LiteralString _propertyName(String name) => js.string(name, "'"); 3734 JS.LiteralString _propertyName(String name) => js.string(name, "'");
3823 3735
3824 // TODO(jacobr): we would like to do something like the following 3736 // TODO(jacobr): we would like to do something like the following
3825 // but we don't have summary support yet. 3737 // but we don't have summary support yet.
3826 // bool _supportJsExtensionMethod(AnnotatedNode node) => 3738 // bool _supportJsExtensionMethod(AnnotatedNode node) =>
3827 // _getAnnotation(node, "SupportJsExtensionMethod") != null; 3739 // _getAnnotation(node, "SupportJsExtensionMethod") != null;
3828 3740
3829 /// A special kind of element created by the compiler, signifying a temporary 3741 /// A special kind of element created by the compiler, signifying a temporary
3830 /// variable. These objects use instance equality, and should be shared 3742 /// variable. These objects use instance equality, and should be shared
3831 /// everywhere in the tree where they are treated as the same variable. 3743 /// everywhere in the tree where they are treated as the same variable.
3832 class TemporaryVariableElement extends LocalVariableElementImpl { 3744 class TemporaryVariableElement extends LocalVariableElementImpl {
3833 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); 3745 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name);
3834 3746
3835 int get hashCode => identityHashCode(this); 3747 int get hashCode => identityHashCode(this);
3836 bool operator ==(Object other) => identical(this, other); 3748 bool operator ==(Object other) => identical(this, other);
3837 } 3749 }
3750
3751 bool isLibraryPrefix(Expression node) =>
3752 node is SimpleIdentifier && node.staticElement is PrefixElement;
3753
3754 LibraryElement _getLibrary(AnalysisContext c, String uri) =>
3755 c.computeLibraryElement(c.sourceFactory.forUri(uri));
3756
3757 bool _isDartRuntime(LibraryElement l) =>
3758 l.isInSdk && l.source.uri.toString() == 'dart:_runtime';
OLDNEW
« no previous file with comments | « lib/src/compiler/ast_builder.dart ('k') | lib/src/compiler/command.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698