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

Side by Side Diff: lib/src/codegen/js_codegen.dart

Issue 1016003003: sort classes in dependency order, or load lazily if needed, fixes #78 (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // 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 library dev_compiler.src.codegen.js_codegen; 5 library dev_compiler.src.codegen.js_codegen;
6 6
7 import 'dart:collection' show HashSet; 7 import 'dart:collection' show HashSet, HashMap;
8 import 'dart:io' show Directory, File; 8 import 'dart:io' show Directory, File;
9 9
10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
11 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; 11 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator;
12 import 'package:analyzer/src/generated/constant.dart'; 12 import 'package:analyzer/src/generated/constant.dart';
13 import 'package:analyzer/src/generated/element.dart'; 13 import 'package:analyzer/src/generated/element.dart';
14 import 'package:analyzer/src/generated/scanner.dart' 14 import 'package:analyzer/src/generated/scanner.dart'
15 show StringToken, Token, TokenType; 15 show StringToken, Token, TokenType;
16 import 'package:source_maps/source_maps.dart' as srcmaps show Printer; 16 import 'package:source_maps/source_maps.dart' as srcmaps show Printer;
17 import 'package:source_maps/source_maps.dart' show SourceMapSpan; 17 import 'package:source_maps/source_maps.dart' show SourceMapSpan;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 60
61 ClassDeclaration currentClass; 61 ClassDeclaration currentClass;
62 ConstantEvaluator _constEvaluator; 62 ConstantEvaluator _constEvaluator;
63 63
64 final _exports = <String>[]; 64 final _exports = <String>[];
65 final _lazyFields = <VariableDeclaration>[]; 65 final _lazyFields = <VariableDeclaration>[];
66 final _properties = <FunctionDeclaration>[]; 66 final _properties = <FunctionDeclaration>[];
67 final _privateNames = new HashSet<String>(); 67 final _privateNames = new HashSet<String>();
68 final _pendingPrivateNames = <String>[]; 68 final _pendingPrivateNames = <String>[];
69 69
70 /// Classes we have not emitted yet. Values can be [ClassDeclaration] or
71 /// [ClassTypeAlias].
72 final _pendingClasses = new HashMap<ClassElement, CompilationUnitMember>();
73
74 /// Memoized results of [_lazyClass].
75 final _lazyClassMemo = new HashMap<ClassElement, bool>();
76
77 /// Memoized results of [_inLibraryCycle].
78 final _libraryCycleMemo = new HashMap<LibraryElement, bool>();
79
70 JSCodegenVisitor(this.libraryInfo, this.rules, this._checkerReporter); 80 JSCodegenVisitor(this.libraryInfo, this.rules, this._checkerReporter);
71 81
72 Element get currentLibrary => libraryInfo.library; 82 LibraryElement get currentLibrary => libraryInfo.library;
73 83
74 JS.Program emitLibrary(LibraryUnit library) { 84 JS.Program emitLibrary(LibraryUnit library) {
75 var jsDefaultValue = '{}'; 85 var jsDefaultValue = '{}';
76 var unit = library.library; 86 var unit = library.library;
77 if (unit.directives.isNotEmpty) { 87 if (unit.directives.isNotEmpty) {
78 var annotation = _getJsNameAnnotation(unit.directives.first); 88 var annotation = _getJsNameAnnotation(unit.directives.first);
79 if (annotation != null) { 89 if (annotation != null) {
80 var arguments = annotation.arguments.arguments; 90 var arguments = annotation.arguments.arguments;
81 if (!arguments.isEmpty) { 91 if (!arguments.isEmpty) {
82 var namedExpression = arguments.first as NamedExpression; 92 var namedExpression = arguments.first as NamedExpression;
83 var literal = namedExpression.expression as SimpleStringLiteral; 93 var literal = namedExpression.expression as SimpleStringLiteral;
84 jsDefaultValue = literal.stringValue; 94 jsDefaultValue = literal.stringValue;
85 } 95 }
86 } 96 }
87 } 97 }
88 var body = <JS.Statement>[]; 98 var body = <JS.Statement>[];
89 99
90 // Visit parts first, since the "part" declarations come before code 100 // Collect classes we need to emit, used for:
91 // in the main library's compilation unit. 101 // * tracks what we've emitted so we don't emit twice
92 for (var unit in library.parts) { 102 // * provides a mapping from ClassElement back to the ClassDeclaration.
93 body.add(_visit(unit)); 103 for (var unit in library.partsThenLibrary) {
104 for (var decl in unit.declarations) {
105 if (decl is ClassDeclaration || decl is ClassTypeAlias) {
106 _pendingClasses[decl.element] = decl;
107 }
108 }
94 } 109 }
95 110
96 // Visit main library 111 for (var unit in library.partsThenLibrary) body.add(_visit(unit));
97 body.add(_visit(library.library)); 112
113 assert(_pendingClasses.isEmpty);
98 114
99 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); 115 if (_exports.isNotEmpty) body.add(js.comment('Exports:'));
100 116
101 // TODO(jmesserly): make these immutable in JS? 117 // TODO(jmesserly): make these immutable in JS?
102 for (var name in _exports) { 118 for (var name in _exports) {
103 body.add(js.statement('$_EXPORTS.# = #;', [name, name])); 119 body.add(js.statement('$_EXPORTS.# = #;', [name, name]));
104 } 120 }
105 121
106 var name = jsLibraryName(libraryInfo.library); 122 var name = jsLibraryName(libraryInfo.library);
107 123
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 visitFunctionTypeAlias(FunctionTypeAlias node) { 233 visitFunctionTypeAlias(FunctionTypeAlias node) {
218 // TODO(vsm): Do we need to record type info the generated code for a 234 // TODO(vsm): Do we need to record type info the generated code for a
219 // typedef? 235 // typedef?
220 } 236 }
221 237
222 @override 238 @override
223 JS.Expression visitTypeName(TypeName node) => _emitTypeName(node.type); 239 JS.Expression visitTypeName(TypeName node) => _emitTypeName(node.type);
224 240
225 @override 241 @override
226 JS.Statement visitClassTypeAlias(ClassTypeAlias node) { 242 JS.Statement visitClassTypeAlias(ClassTypeAlias node) {
243 // If we've already emitted this class, skip it.
244 var classElem = node.element;
245 if (_pendingClasses.remove(classElem) == null) return null;
246
227 var name = node.name.name; 247 var name = node.name.name;
228 var heritage = 248 var heritage =
229 js.call('dart.mixin(#)', [_visitList(node.withClause.mixinTypes)]); 249 js.call('dart.mixin(#)', [_visitList(node.withClause.mixinTypes)]);
230 var classDecl = new JS.ClassDeclaration( 250 var classDecl = new JS.ClassDeclaration(
231 new JS.ClassExpression(new JS.VariableDeclaration(name), heritage, [])); 251 new JS.ClassExpression(new JS.VariableDeclaration(name), heritage, []));
232 if (isPublic(name)) _exports.add(name); 252 if (isPublic(name)) _exports.add(name);
233 return _addTypeParameters(node.typeParameters, name, classDecl);
234 }
235 253
236 @override 254 return _finishClassDef(classElem, classDecl);
237 visitTypeParameter(TypeParameter node) => new JS.Parameter(node.name.name);
238
239 JS.Statement _addTypeParameters(
240 TypeParameterList node, String name, JS.Statement clazz) {
241 if (node == null) return clazz;
242
243 var genericName = '$name\$';
244 var genericDef = js.statement(
245 'let # = dart.generic(function(#) { #; return #; });', [
246 genericName,
247 _visitList(node.typeParameters),
248 clazz,
249 name
250 ]);
251
252 // TODO(jmesserly): we may not want this to be `dynamic` if the generic
253 // has a lower bound, e.g. `<T extends SomeType>`.
254 // https://github.com/dart-lang/dart-dev-compiler/issues/38
255 var typeArgs =
256 new List.filled(node.typeParameters.length, js.call('dart.dynamic'));
257
258 var dynInst = js.statement('let # = #(#);', [name, genericName, typeArgs]);
259
260 // TODO(jmesserly): is it worth exporting both names? Alternatively we could
261 // put the generic type constructor on the <dynamic> instance.
262 if (isPublic(name)) _exports.add('${name}\$');
263 return new JS.Block([genericDef, dynInst]);
264 } 255 }
265 256
266 @override 257 @override
267 JS.Statement visitClassDeclaration(ClassDeclaration node) { 258 JS.Statement visitClassDeclaration(ClassDeclaration node) {
259 // If we've already emitted this class, skip it.
260 var classElem = node.element;
261 if (_pendingClasses.remove(classElem) == null) return null;
268 if (_getJsNameAnnotation(node) != null) return null; 262 if (_getJsNameAnnotation(node) != null) return null;
269 263
270 currentClass = node; 264 currentClass = node;
271 265
272 // dart:core Object is a bit special. 266 var name = classElem.name;
273 var isObject = node.element.type.isObject; 267 if (isPublic(name)) _exports.add(name);
274 268
275 var body = <JS.Statement>[];
276
277 var name = node.name.name;
278 var ctors = <ConstructorDeclaration>[]; 269 var ctors = <ConstructorDeclaration>[];
279 var fields = <FieldDeclaration>[]; 270 var fields = <FieldDeclaration>[];
280 var staticFields = <FieldDeclaration>[]; 271 var staticFields = <FieldDeclaration>[];
281 for (var member in node.members) { 272 for (var member in node.members) {
282 if (member is ConstructorDeclaration) { 273 if (member is ConstructorDeclaration) {
283 ctors.add(member); 274 ctors.add(member);
284 } else if (member is FieldDeclaration) { 275 } else if (member is FieldDeclaration) {
285 (member.isStatic ? staticFields : fields).add(member); 276 (member.isStatic ? staticFields : fields).add(member);
286 } 277 }
287 } 278 }
288 279
280 var classExpr = new JS.ClassExpression(new JS.VariableDeclaration(name),
281 _classHeritage(node), _emitClassMethods(node, ctors, fields));
282
283 var body = _finishClassMembers(name, classExpr, ctors, staticFields);
284 currentClass = null;
285
286 return _finishClassDef(classElem, body);
287 }
288
289 /// Given a class element and body, complete the class declaration.
290 /// This handles generic type parameters, laziness (in library-cycle cases),
291 /// and ensuring dependencies are loaded first.
292 JS.Statement _finishClassDef(ClassElement classElem, JS.Statement body) {
293 var name = classElem.name;
294 var genericName = '$name\$';
295
296 JS.Statement genericDef;
297 JS.Expression genericInst;
298 if (classElem.typeParameters.isNotEmpty) {
299 genericDef = _emitGenericClassDef(classElem, body);
300 var dynamicArgs = new List.filled(
301 classElem.typeParameters.length, js.call('dart.dynamic'));
302
303 var target = genericName;
304 if (_needQualifiedName(classElem)) {
305 target = js.call('#.#', [_EXPORTS, genericName]);
306 }
307 genericInst = js.call('#(#)', [target, dynamicArgs]);
308 }
309
310 // The base class and all mixins must be declared before this class.
311 if (_lazyClass(classElem)) {
312 // TODO(jmesserly): the lazy class def is a simple solution for now.
313 // We may want to consider other options in the future.
314
315 if (genericDef != null) {
316 return js.statement(
317 '{ #; dart.defineLazyClassGeneric(#, #, { get: # }); }', [
318 genericDef,
319 _EXPORTS,
320 js.string(name, "'"),
321 genericName
322 ]);
323 }
324
325 if (body is JS.ClassDeclaration) {
326 body = new JS.Return((body as JS.ClassDeclaration).classExpr);
327 } else {
328 body = js.statement('{ #; return #; }', [body, name]);
329 }
330
331 return js.statement('dart.defineLazyClass(#, { get #() { #; } });', [
332 _EXPORTS,
333 name,
334 body
335 ]);
336 }
337
338 if (genericDef != null) {
339 body = js.statement('{ #; let # = #; }', [genericDef, name, genericInst]);
340 }
341
342 if (classElem.type.isObject) return body;
343
344 // If we're not lazy, we still need to ensure our dependencies are
345 // generated first.
346 var classDefs = <JS.Statement>[];
347 _emitClassIfNeeded(classDefs, classElem.supertype.element);
348 for (var m in classElem.mixins) {
349 _emitClassIfNeeded(classDefs, m.element);
350 }
351 classDefs.add(body);
352 return _statement(classDefs);
353 }
354
355 void _emitClassIfNeeded(List<JS.Statement> defs, ClassElement base) {
356 // We can only emit classes from this library.
357 if (base.library != currentLibrary) return;
358
359 var baseNode = _pendingClasses[base];
360 if (baseNode != null) defs.add(visitClassDeclaration(baseNode));
361 }
362
363 /// Returns true if the supertype or mixins aren't loaded.
364 /// If that is the case, we'll emit a lazy class definition.
365 bool _lazyClass(ClassElement cls) {
366 if (cls.type.isObject) return false;
367
368 assert(cls.library == currentLibrary);
369 var result = _lazyClassMemo[cls];
370 if (result != null) return result;
371
372 result = _classMightNotBeLoaded(cls.supertype.element);
373 for (var mixin in cls.mixins) {
374 if (result) break;
375 result = _classMightNotBeLoaded(mixin.element);
376 }
377 return _lazyClassMemo[cls] = result;
378 }
379
380 /// Curated order to minimize lazy classes needed by dart:core and its
381 /// transitive SDK imports.
382 static const CORELIB_ORDER = const [
383 'dart.core',
384 'dart.collection',
385 'dart._internal'
386 ];
387
388 /// Returns true if the class might not be loaded.
389 ///
390 /// If the class is from our library, this can happen because it's lazy.
391 ///
392 /// If the class is from a different library, it could happen if we're in
393 /// a library cycle. In other words, if that different library depends back
394 /// on this library via some transitive import path.
395 ///
396 /// If we could control the global import ordering, we could eliminate some
397 /// of these cases, by ordering the imports of the cyclic libraries in an
398 /// optimal way. For example, we could order the libraries in a cycle to
399 /// minimize laziness. However, we currently assume we cannot control the
400 /// order that the cycle of libraries will be loaded in.
401 bool _classMightNotBeLoaded(ClassElement cls) {
402 if (cls.library == currentLibrary) return _lazyClass(cls);
403
404 // The SDK is a special case: we optimize the order to prevent laziness.
405 if (cls.library.isInSdk) {
406 if (!currentLibrary.isInSdk) return false;
407
408 var order = CORELIB_ORDER.indexOf(cls.library.name);
409 if (order != -1) {
410 // If the dart:* library we are currently compiling is loaded after the
411 // class's library, then we know the class is available.
412 var currentOrder = CORELIB_ORDER.indexOf(currentLibrary.name);
413 return currentOrder == -1 ? false : (currentOrder < order);
414 }
415 }
416
417 return _inLibraryCycle(cls.library);
418 }
419
420 /// Returns true if [library] depends on the [currentLibrary] via some
421 /// transitive import.
422 bool _inLibraryCycle(LibraryElement library) {
423 // SDK libs don't depend on things outside the SDK.
424 if (library.isInSdk && !currentLibrary.isInSdk) return false;
Siggi Cherem (dart-lang) 2015/03/18 23:54:55 maybe move the second condition to be an assertion
Jennifer Messerly 2015/03/19 16:03:29 I think it actually can be called via recursive pa
425
426 var result = _libraryCycleMemo[library];
427 if (result != null) return result;
428
429 result = library == currentLibrary;
430 _libraryCycleMemo[library] = result;
431 for (var e in library.imports) {
432 if (result) break;
433 result = _inLibraryCycle(e.importedLibrary);
434 }
435 for (var e in library.exports) {
436 if (result) break;
437 result = _inLibraryCycle(e.exportedLibrary);
438 }
439 return _libraryCycleMemo[library] = result;
440 }
441
442 JS.Statement _emitGenericClassDef(ClassElement cls, JS.Statement body) {
443 var name = cls.name;
444 var genericName = '$name\$';
445 var typeParams = cls.typeParameters.map((p) => new JS.Parameter(p.name));
446 // TODO(jmesserly): is it worth exporting both names? Alternatively we could
447 // put the generic type constructor on the <dynamic> instance.
448 if (isPublic(name)) _exports.add(genericName);
449 return js.statement('let # = dart.generic(function(#) { #; return #; });', [
450 genericName,
451 typeParams,
452 body,
453 name
454 ]);
455 }
456
457 JS.Expression _classHeritage(ClassDeclaration node) {
458 if (node.element.type.isObject) return null;
459
460 JS.Expression heritage = null;
461 if (node.extendsClause != null) {
462 heritage = _visit(node.extendsClause.superclass);
463 } else {
464 heritage = _emitTypeName(rules.provider.objectType);
465 }
466 if (node.withClause != null) {
467 var mixins = _visitList(node.withClause.mixinTypes);
468 mixins.insert(0, heritage);
469 heritage = js.call('dart.mixin(#)', [mixins]);
470 }
471 return heritage;
472 }
473
474 /// Emit class members that can be generated as methods.
475 /// Anything not handled here will be addressed in [_finishClassMembers].
476 List<JS.Method> _emitClassMethods(ClassDeclaration node,
477 List<ConstructorDeclaration> ctors, List<FieldDeclaration> fields) {
478 var element = node.element;
479 var isObject = element.type.isObject;
480 var name = node.name.name;
481
289 var jsMethods = <JS.Method>[]; 482 var jsMethods = <JS.Method>[];
290 // Iff no constructor is specified for a class C, it implicitly has a 483 // Iff no constructor is specified for a class C, it implicitly has a
291 // default constructor `C() : super() {}`, unless C is class Object. 484 // default constructor `C() : super() {}`, unless C is class Object.
292 if (ctors.isEmpty && !isObject) { 485 if (ctors.isEmpty && !isObject) {
293 jsMethods.add(_emitImplicitConstructor(node, name, fields)); 486 jsMethods.add(_emitImplicitConstructor(node, name, fields));
294 } 487 }
295 488
296 for (var member in node.members) { 489 for (var member in node.members) {
297 if (member is ConstructorDeclaration) { 490 if (member is ConstructorDeclaration) {
298 jsMethods.add(_emitConstructor(member, name, fields, isObject)); 491 jsMethods.add(_emitConstructor(member, name, fields, isObject));
299 } else if (member is MethodDeclaration) { 492 } else if (member is MethodDeclaration) {
300 jsMethods.add(_visit(member)); 493 jsMethods.add(_visit(member));
301 } 494 }
302 } 495 }
303 496
304 // Support for adapting dart:core Iterator/Iterable to ES6 versions. 497 // Support for adapting dart:core Iterator/Iterable to ES6 versions.
305 // This lets them use for-of loops transparently. 498 // This lets them use for-of loops transparently.
306 // https://github.com/lukehoban/es6features#iterators--forof 499 // https://github.com/lukehoban/es6features#iterators--forof
307 if (node.element.library.isDartCore && node.element.name == 'Iterable') { 500 if (element.library.isDartCore && element.name == 'Iterable') {
308 JS.Fun body = js.call('''function() { 501 JS.Fun body = js.call('''function() {
309 var iterator = this.iterator; 502 var iterator = this.iterator;
310 return { 503 return {
311 next() { 504 next() {
312 var done = iterator.moveNext(); 505 var done = iterator.moveNext();
313 return { done: done, current: done ? void 0 : iterator.current }; 506 return { done: done, current: done ? void 0 : iterator.current };
314 } 507 }
315 }; 508 };
316 }'''); 509 }''');
317 jsMethods.add(new JS.Method(js.call('Symbol.iterator'), body)); 510 jsMethods.add(new JS.Method(js.call('Symbol.iterator'), body));
318 } 511 }
512 return jsMethods.where((m) => m != null).toList(growable: false);
513 }
319 514
320 JS.Expression heritage = null; 515 /// Emit class members that need to come after the class declaration, such
321 if (node.extendsClause != null) { 516 /// as static fields. See [_emitClassMethods] for things that are emitted
322 heritage = _visit(node.extendsClause.superclass); 517 /// insite the ES6 `class { ... }` node.
323 } else if (!isObject) { 518 JS.Statement _finishClassMembers(String name, JS.ClassExpression cls,
324 heritage = _emitTypeName(rules.provider.objectType); 519 List<ConstructorDeclaration> ctors, List<FieldDeclaration> staticFields) {
325 } 520 var body = <JS.Statement>[];
326 if (node.withClause != null) { 521 body.add(new JS.ClassDeclaration(cls));
327 var mixins = _visitList(node.withClause.mixinTypes);
328 mixins.insert(0, heritage);
329 heritage = js.call('dart.mixin(#)', [mixins]);
330 }
331 body.add(new JS.ClassDeclaration(new JS.ClassExpression(
332 new JS.VariableDeclaration(name), heritage,
333 jsMethods.where((m) => m != null).toList(growable: false))));
334
335 if (isPublic(name)) _exports.add(name);
336 522
337 // Named constructors 523 // Named constructors
338 for (ConstructorDeclaration member in ctors) { 524 for (ConstructorDeclaration member in ctors) {
339 if (member.name != null) { 525 if (member.name != null) {
340 body.add(js.statement('dart.defineNamedConstructor(#, #);', [ 526 body.add(js.statement('dart.defineNamedConstructor(#, #);', [
341 name, 527 name,
342 js.string(member.name.name, "'") 528 js.string(member.name.name, "'")
343 ])); 529 ]));
344 } 530 }
345 } 531 }
346 532
347 // Static fields 533 // Static fields
348 var lazyStatics = <VariableDeclaration>[]; 534 var lazyStatics = <VariableDeclaration>[];
349 for (FieldDeclaration member in staticFields) { 535 for (FieldDeclaration member in staticFields) {
350 for (VariableDeclaration field in member.fields.variables) { 536 for (VariableDeclaration field in member.fields.variables) {
351 var fieldName = field.name.name; 537 var fieldName = field.name.name;
352 if (field.isConst || _isFieldInitConstant(field)) { 538 if (field.isConst || _isFieldInitConstant(field)) {
353 var init = _visit(field.initializer); 539 var init = _visit(field.initializer);
354 if (init == null) init = new JS.LiteralNull(); 540 if (init == null) init = new JS.LiteralNull();
355 body.add(js.statement('#.# = #;', [name, fieldName, init])); 541 body.add(js.statement('#.# = #;', [name, fieldName, init]));
356 } else { 542 } else {
357 lazyStatics.add(field); 543 lazyStatics.add(field);
358 } 544 }
359 } 545 }
360 } 546 }
361 var lazy = _emitLazyFields(name, lazyStatics); 547 var lazy = _emitLazyFields(name, lazyStatics);
362 if (lazy != null) body.add(lazy); 548 if (lazy != null) body.add(lazy);
363 549 return _statement(body);
364 currentClass = null;
365 return _addTypeParameters(node.typeParameters, name, _statement(body));
366 } 550 }
367 551
368 /// Generates the implicit default constructor for class C of the form 552 /// Generates the implicit default constructor for class C of the form
369 /// `C() : super() {}`. 553 /// `C() : super() {}`.
370 JS.Method _emitImplicitConstructor( 554 JS.Method _emitImplicitConstructor(
371 ClassDeclaration node, String name, List<FieldDeclaration> fields) { 555 ClassDeclaration node, String name, List<FieldDeclaration> fields) {
372 // If we don't have a method body, skip this. 556 // If we don't have a method body, skip this.
373 if (fields.isEmpty) return null; 557 if (fields.isEmpty) return null;
374 558
375 dynamic body = _initializeFields(fields); 559 dynamic body = _initializeFields(fields);
(...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after
735 var className = (variable.enclosingElement as ClassElement).name; 919 var className = (variable.enclosingElement as ClassElement).name;
736 return js.call('#.#', [className, name]); 920 return js.call('#.#', [className, name]);
737 } else if (e is ParameterElement && e.isInitializingFormal) { 921 } else if (e is ParameterElement && e.isInitializingFormal) {
738 name = _fieldParameterName(name); 922 name = _fieldParameterName(name);
739 } 923 }
740 return new JS.VariableUse(name); 924 return new JS.VariableUse(name);
741 } 925 }
742 926
743 JS.Expression _emitTypeName(DartType type) { 927 JS.Expression _emitTypeName(DartType type) {
744 var name = type.name; 928 var name = type.name;
745 var lib = type.element.library; 929 var element = type.element;
746 if (name == '') { 930 if (name == '') {
747 // TODO(jmesserly): remove when we're using coercion reifier. 931 // TODO(jmesserly): remove when we're using coercion reifier.
748 return _unimplementedCall('Unimplemented type $type'); 932 return _unimplementedCall('Unimplemented type $type');
749 } 933 }
750 934
751 var typeArgs = null; 935 var typeArgs = null;
752 if (type is ParameterizedType) { 936 if (type is ParameterizedType) {
753 // TODO(jmesserly): this is a workaround for an analyzer bug, see: 937 // TODO(jmesserly): this is a workaround for an analyzer bug, see:
754 // https://github.com/dart-lang/dart-dev-compiler/commit/a212d59ad046085a6 26dd8d16881cdb8e8b9c3fa 938 // https://github.com/dart-lang/dev_compiler/commit/a212d59ad046085a626dd8 d16881cdb8e8b9c3fa
755 if (type is! FunctionType || type.element is FunctionTypeAlias) { 939 if (type is! FunctionType || element is FunctionTypeAlias) {
756 var args = type.typeArguments; 940 var args = type.typeArguments;
757 if (args.any((a) => a != rules.provider.dynamicType)) { 941 if (args.any((a) => a != rules.provider.dynamicType)) {
758 name = '$name\$'; 942 name = '$name\$';
759 typeArgs = args.map(_emitTypeName); 943 typeArgs = args.map(_emitTypeName);
760 } 944 }
761 } 945 }
762 } 946 }
763 947
764 JS.Expression result; 948 JS.Expression result;
765 if (lib != currentLibrary && lib != null) { 949 if (_needQualifiedName(element)) {
766 result = js.call('#.#', [_libraryName(lib), name]); 950 result = js.call('#.#', [_libraryName(element.library), name]);
767 } else { 951 } else {
768 result = new JS.VariableUse(name); 952 result = new JS.VariableUse(name);
769 } 953 }
770 954
771 if (typeArgs != null) { 955 if (typeArgs != null) {
772 result = js.call('#(#)', [result, typeArgs]); 956 result = js.call('#(#)', [result, typeArgs]);
773 } 957 }
774 return result; 958 return result;
775 } 959 }
776 960
961 bool _needQualifiedName(Element element) {
962 var lib = element.library;
963
964 return lib != null &&
965 (lib != currentLibrary ||
966 element is ClassElement && _lazyClass(element));
967 }
968
777 JS.Node _emitDPutIfDynamic( 969 JS.Node _emitDPutIfDynamic(
778 Expression target, SimpleIdentifier id, Expression rhs) { 970 Expression target, SimpleIdentifier id, Expression rhs) {
779 if (rules.isDynamicTarget(target)) { 971 if (rules.isDynamicTarget(target)) {
780 return js.call('dart.dput(#, #, #)', [ 972 return js.call('dart.dput(#, #, #)', [
781 _visit(target), 973 _visit(target),
782 js.string(id.name, "'"), 974 js.string(id.name, "'"),
783 _visit(rhs) 975 _visit(rhs)
784 ]); 976 ]);
785 } else { 977 } else {
786 return null; 978 return null;
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
1078 1270
1079 // TODO(jmesserly): use a dummy setter to indicate writable. 1271 // TODO(jmesserly): use a dummy setter to indicate writable.
1080 if (!node.isFinal) { 1272 if (!node.isFinal) {
1081 methods.add(new JS.Method( 1273 methods.add(new JS.Method(
1082 new JS.PropertyName(name), js.call('function(_) {}'), 1274 new JS.PropertyName(name), js.call('function(_) {}'),
1083 isSetter: true)); 1275 isSetter: true));
1084 } 1276 }
1085 } 1277 }
1086 1278
1087 return js.statement( 1279 return js.statement(
1088 'dart.defineLazyProperties(#, { # })', [objExpr, methods]); 1280 'dart.defineLazyProperties(#, { # });', [objExpr, methods]);
1089 } 1281 }
1090 1282
1091 void _flushLibraryProperties(List<JS.Statement> body) { 1283 void _flushLibraryProperties(List<JS.Statement> body) {
1092 if (_properties.isEmpty) return; 1284 if (_properties.isEmpty) return;
1093 body.add(js.statement('dart.copyProperties($_EXPORTS, { # });', 1285 body.add(js.statement('dart.copyProperties($_EXPORTS, { # });',
1094 [_properties.map(_emitTopLevelProperty)])); 1286 [_properties.map(_emitTopLevelProperty)]));
1095 _properties.clear(); 1287 _properties.clear();
1096 } 1288 }
1097 1289
1098 @override 1290 @override
(...skipping 996 matching lines...) Expand 10 before | Expand all | Expand 10 after
2095 2287
2096 // TODO(jmesserly): in many cases marking the end will be unncessary. 2288 // TODO(jmesserly): in many cases marking the end will be unncessary.
2097 printer.mark(_location(node.end)); 2289 printer.mark(_location(node.end));
2098 } 2290 }
2099 2291
2100 String _getIdentifier(AstNode node) { 2292 String _getIdentifier(AstNode node) {
2101 if (node is SimpleIdentifier) return node.name; 2293 if (node is SimpleIdentifier) return node.name;
2102 return null; 2294 return null;
2103 } 2295 }
2104 } 2296 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698