Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // 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, HashMap; | 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; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 61 ConstantEvaluator _constEvaluator; | 61 ConstantEvaluator _constEvaluator; |
| 62 | 62 |
| 63 final _exports = <String>[]; | 63 final _exports = <String>[]; |
| 64 final _lazyFields = <VariableDeclaration>[]; | 64 final _lazyFields = <VariableDeclaration>[]; |
| 65 final _properties = <FunctionDeclaration>[]; | 65 final _properties = <FunctionDeclaration>[]; |
| 66 final _privateNames = new HashSet<String>(); | 66 final _privateNames = new HashSet<String>(); |
| 67 final _pendingPrivateNames = <String>[]; | 67 final _pendingPrivateNames = <String>[]; |
| 68 | 68 |
| 69 /// Classes we have not emitted yet. Values can be [ClassDeclaration] or | 69 /// Classes we have not emitted yet. Values can be [ClassDeclaration] or |
| 70 /// [ClassTypeAlias]. | 70 /// [ClassTypeAlias]. |
| 71 final _pendingClasses = new HashMap<ClassElement, CompilationUnitMember>(); | 71 final _pendingClasses = new HashMap<Element, CompilationUnitMember>(); |
| 72 | 72 |
| 73 /// Memoized results of [_lazyClass]. | 73 /// Memoized results of [_lazyClass]. |
| 74 final _lazyClassMemo = new HashMap<ClassElement, bool>(); | 74 final _lazyClassMemo = new HashMap<Element, bool>(); |
| 75 | 75 |
| 76 /// Memoized results of [_inLibraryCycle]. | 76 /// Memoized results of [_inLibraryCycle]. |
| 77 final _libraryCycleMemo = new HashMap<LibraryElement, bool>(); | 77 final _libraryCycleMemo = new HashMap<LibraryElement, bool>(); |
| 78 | 78 |
| 79 JSCodegenVisitor(this.libraryInfo, this.rules, this._checkerReporter); | 79 JSCodegenVisitor(this.libraryInfo, this.rules, this._checkerReporter); |
| 80 | 80 |
| 81 LibraryElement get currentLibrary => libraryInfo.library; | 81 LibraryElement get currentLibrary => libraryInfo.library; |
| 82 | 82 |
| 83 /// The name for the library's exports inside itself. | 83 /// The name for the library's exports inside itself. |
| 84 /// This much be a constant because we interpolate it into template strings, | 84 /// This much be a constant because we interpolate it into template strings, |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 101 } | 101 } |
| 102 } | 102 } |
| 103 } | 103 } |
| 104 var body = <JS.Statement>[]; | 104 var body = <JS.Statement>[]; |
| 105 | 105 |
| 106 // Collect classes we need to emit, used for: | 106 // Collect classes we need to emit, used for: |
| 107 // * tracks what we've emitted so we don't emit twice | 107 // * tracks what we've emitted so we don't emit twice |
| 108 // * provides a mapping from ClassElement back to the ClassDeclaration. | 108 // * provides a mapping from ClassElement back to the ClassDeclaration. |
| 109 for (var unit in library.partsThenLibrary) { | 109 for (var unit in library.partsThenLibrary) { |
| 110 for (var decl in unit.declarations) { | 110 for (var decl in unit.declarations) { |
| 111 if (decl is ClassDeclaration || decl is ClassTypeAlias) { | 111 if (decl is ClassDeclaration || |
| 112 decl is ClassTypeAlias || | |
| 113 decl is FunctionTypeAlias) { | |
| 112 _pendingClasses[decl.element] = decl; | 114 _pendingClasses[decl.element] = decl; |
| 113 } | 115 } |
| 114 } | 116 } |
| 115 } | 117 } |
| 116 | 118 |
| 117 for (var unit in library.partsThenLibrary) body.add(_visit(unit)); | 119 for (var unit in library.partsThenLibrary) body.add(_visit(unit)); |
| 118 | 120 |
| 119 assert(_pendingClasses.isEmpty); | 121 assert(_pendingClasses.isEmpty); |
| 120 | 122 |
| 121 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); | 123 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 253 | 255 |
| 254 String _jsTypeofName(DartType t) { | 256 String _jsTypeofName(DartType t) { |
| 255 if (rules.isIntType(t) || rules.isDoubleType(t)) return 'number'; | 257 if (rules.isIntType(t) || rules.isDoubleType(t)) return 'number'; |
| 256 if (rules.isStringType(t)) return 'string'; | 258 if (rules.isStringType(t)) return 'string'; |
| 257 if (rules.isBoolType(t)) return 'boolean'; | 259 if (rules.isBoolType(t)) return 'boolean'; |
| 258 return null; | 260 return null; |
| 259 } | 261 } |
| 260 | 262 |
| 261 @override | 263 @override |
| 262 visitFunctionTypeAlias(FunctionTypeAlias node) { | 264 visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 263 // TODO(vsm): Do we need to record type info the generated code for a | 265 // If we've already emitted this class, skip it. |
|
Jennifer Messerly
2015/04/01 22:31:31
all of these changes were because we do a type che
| |
| 264 // typedef? | 266 var type = node.element.type; |
| 267 if (_pendingClasses.remove(node.element) == null) return null; | |
| 268 | |
| 269 var classDecl = new JS.ClassDeclaration(new JS.ClassExpression( | |
|
Jennifer Messerly
2015/04/01 22:31:31
not sure if class is really what we want long term
vsm
2015/04/01 23:04:57
We might want this to be some sort of type object.
Jennifer Messerly
2015/04/01 23:22:56
yeah, something that is an instance of Type. Right
| |
| 270 new JS.Identifier(type.name), | |
| 271 _emitTypeName(rules.provider.functionType), [])); | |
| 272 | |
| 273 return _finishClassDef(type, classDecl); | |
| 265 } | 274 } |
| 266 | 275 |
| 267 @override | 276 @override |
| 268 JS.Expression visitTypeName(TypeName node) => _emitTypeName(node.type); | 277 JS.Expression visitTypeName(TypeName node) => _emitTypeName(node.type); |
| 269 | 278 |
| 270 @override | 279 @override |
| 271 JS.Statement visitClassTypeAlias(ClassTypeAlias node) { | 280 JS.Statement visitClassTypeAlias(ClassTypeAlias node) { |
| 272 // If we've already emitted this class, skip it. | 281 // If we've already emitted this class, skip it. |
| 273 var classElem = node.element; | 282 var type = node.element.type; |
| 274 if (_pendingClasses.remove(classElem) == null) return null; | 283 if (_pendingClasses.remove(node.element) == null) return null; |
| 275 | 284 |
| 276 var name = node.name.name; | 285 var name = node.name.name; |
| 277 var heritage = | 286 var heritage = |
| 278 js.call('dart.mixin(#)', [_visitList(node.withClause.mixinTypes)]); | 287 js.call('dart.mixin(#)', [_visitList(node.withClause.mixinTypes)]); |
| 279 var classDecl = new JS.ClassDeclaration( | 288 var classDecl = new JS.ClassDeclaration( |
| 280 new JS.ClassExpression(new JS.Identifier(name), heritage, [])); | 289 new JS.ClassExpression(new JS.Identifier(name), heritage, [])); |
| 281 | 290 |
| 282 return _finishClassDef(classElem, classDecl); | 291 return _finishClassDef(type, classDecl); |
| 283 } | 292 } |
| 284 | 293 |
| 285 @override | 294 @override |
| 286 JS.Statement visitClassDeclaration(ClassDeclaration node) { | 295 JS.Statement visitClassDeclaration(ClassDeclaration node) { |
| 287 // If we've already emitted this class, skip it. | 296 // If we've already emitted this class, skip it. |
| 288 var classElem = node.element; | 297 var type = node.element.type; |
| 289 if (_pendingClasses.remove(classElem) == null) return null; | 298 if (_pendingClasses.remove(node.element) == null) return null; |
| 290 if (_getJsNameAnnotation(node) != null) return null; | 299 if (_getJsNameAnnotation(node) != null) return null; |
| 291 | 300 |
| 292 currentClass = node; | 301 currentClass = node; |
| 293 | 302 |
| 294 var ctors = <ConstructorDeclaration>[]; | 303 var ctors = <ConstructorDeclaration>[]; |
| 295 var fields = <FieldDeclaration>[]; | 304 var fields = <FieldDeclaration>[]; |
| 296 var staticFields = <FieldDeclaration>[]; | 305 var staticFields = <FieldDeclaration>[]; |
| 297 for (var member in node.members) { | 306 for (var member in node.members) { |
| 298 if (member is ConstructorDeclaration) { | 307 if (member is ConstructorDeclaration) { |
| 299 ctors.add(member); | 308 ctors.add(member); |
| 300 } else if (member is FieldDeclaration) { | 309 } else if (member is FieldDeclaration) { |
| 301 (member.isStatic ? staticFields : fields).add(member); | 310 (member.isStatic ? staticFields : fields).add(member); |
| 302 } | 311 } |
| 303 } | 312 } |
| 304 | 313 |
| 305 var classExpr = new JS.ClassExpression(new JS.Identifier(classElem.name), | 314 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), |
| 306 _classHeritage(node), _emitClassMethods(node, ctors, fields)); | 315 _classHeritage(node), _emitClassMethods(node, ctors, fields)); |
| 307 | 316 |
| 308 var body = _finishClassMembers(classElem, classExpr, ctors, staticFields); | 317 var body = |
| 318 _finishClassMembers(node.element, classExpr, ctors, staticFields); | |
| 309 currentClass = null; | 319 currentClass = null; |
| 310 | 320 |
| 311 return _finishClassDef(classElem, body); | 321 return _finishClassDef(type, body); |
| 312 } | 322 } |
| 313 | 323 |
| 314 @override | 324 @override |
| 315 JS.Statement visitEnumDeclaration(EnumDeclaration node) => | 325 JS.Statement visitEnumDeclaration(EnumDeclaration node) => |
| 316 _unimplementedCall("Unimplemented enum: $node").toStatement(); | 326 _unimplementedCall("Unimplemented enum: $node").toStatement(); |
| 317 | 327 |
| 318 /// Given a class element and body, complete the class declaration. | 328 /// Given a class element and body, complete the class declaration. |
| 319 /// This handles generic type parameters, laziness (in library-cycle cases), | 329 /// This handles generic type parameters, laziness (in library-cycle cases), |
| 320 /// and ensuring dependencies are loaded first. | 330 /// and ensuring dependencies are loaded first. |
| 321 JS.Statement _finishClassDef(ClassElement classElem, JS.Statement body) { | 331 JS.Statement _finishClassDef(ParameterizedType type, JS.Statement body) { |
| 322 var name = classElem.name; | 332 var name = type.name; |
| 323 var genericName = '$name\$'; | 333 var genericName = '$name\$'; |
| 324 | 334 |
| 325 JS.Statement genericDef; | 335 JS.Statement genericDef; |
| 326 JS.Expression genericInst; | 336 JS.Expression genericInst; |
| 327 if (classElem.typeParameters.isNotEmpty) { | 337 if (type.typeParameters.isNotEmpty) { |
| 328 genericDef = _emitGenericClassDef(classElem, body); | 338 genericDef = _emitGenericClassDef(type, body); |
| 329 var dynamicArgs = new List.filled( | |
| 330 classElem.typeParameters.length, js.call('dart.dynamic')); | |
|
vsm
2015/04/01 23:04:57
Shouldn't we fill in with core.Object?
Jennifer Messerly
2015/04/01 23:22:56
It's handled in dart_runtime by the generic functi
vsm
2015/04/01 23:34:47
If we have x is T somewhere in the body of the cla
Jennifer Messerly
2015/04/02 16:11:08
yes, like I said it happens in dart_runtime :)
htt
vsm
2015/04/02 16:30:54
Aha! :-)
| |
| 331 | |
| 332 var target = genericName; | 339 var target = genericName; |
| 333 if (_needQualifiedName(classElem)) { | 340 if (_needQualifiedName(type.element)) { |
| 334 target = js.call('#.#', [_exportsVar, genericName]); | 341 target = js.call('#.#', [_exportsVar, genericName]); |
| 335 } | 342 } |
| 336 genericInst = js.call('#(#)', [target, dynamicArgs]); | 343 genericInst = js.call('#()', [target]); |
| 337 } | 344 } |
| 338 | 345 |
| 339 // The base class and all mixins must be declared before this class. | 346 // The base class and all mixins must be declared before this class. |
| 340 if (_lazyClass(classElem)) { | 347 if (_lazyClass(type)) { |
| 341 // TODO(jmesserly): the lazy class def is a simple solution for now. | 348 // TODO(jmesserly): the lazy class def is a simple solution for now. |
| 342 // We may want to consider other options in the future. | 349 // We may want to consider other options in the future. |
| 343 | 350 |
| 344 if (genericDef != null) { | 351 if (genericDef != null) { |
| 345 return js.statement( | 352 return js.statement( |
| 346 '{ #; dart.defineLazyClassGeneric(#, #, { get: # }); }', [ | 353 '{ #; dart.defineLazyClassGeneric(#, #, { get: # }); }', [ |
| 347 genericDef, | 354 genericDef, |
| 348 _exportsVar, | 355 _exportsVar, |
| 349 js.string(name, "'"), | 356 js.string(name, "'"), |
| 350 genericName | 357 genericName |
| 351 ]); | 358 ]); |
| 352 } | 359 } |
| 353 | 360 |
| 354 return js.statement( | 361 return js.statement( |
| 355 'dart.defineLazyClass(#, { get #() { #; return #; } });', [ | 362 'dart.defineLazyClass(#, { get #() { #; return #; } });', [ |
| 356 _exportsVar, | 363 _exportsVar, |
| 357 _propertyName(name), | 364 _propertyName(name), |
| 358 body, | 365 body, |
| 359 name | 366 name |
| 360 ]); | 367 ]); |
| 361 } | 368 } |
| 362 | 369 |
| 363 if (isPublic(name)) _exports.add(name); | 370 if (isPublic(name)) _exports.add(name); |
| 364 | 371 |
| 365 if (genericDef != null) { | 372 if (genericDef != null) { |
| 366 body = js.statement('{ #; let # = #; }', [genericDef, name, genericInst]); | 373 body = js.statement('{ #; let # = #; }', [genericDef, name, genericInst]); |
| 367 if (isPublic(name)) _exports.add(genericName); | |
| 368 } | 374 } |
| 369 | 375 |
| 370 if (classElem.type.isObject) return body; | 376 if (type.isObject) return body; |
| 371 | 377 |
| 372 // If we're not lazy, we still need to ensure our dependencies are | 378 // If we're not lazy, we still need to ensure our dependencies are |
| 373 // generated first. | 379 // generated first. |
| 374 var classDefs = <JS.Statement>[]; | 380 var classDefs = <JS.Statement>[]; |
| 375 _emitClassIfNeeded(classDefs, classElem.supertype.element); | 381 if (type is InterfaceType) { |
| 376 for (var m in classElem.mixins) { | 382 _emitClassIfNeeded(classDefs, type.superclass); |
| 377 _emitClassIfNeeded(classDefs, m.element); | 383 for (var m in type.element.mixins) { |
| 384 _emitClassIfNeeded(classDefs, m); | |
| 385 } | |
| 386 } else if (type is FunctionType) { | |
| 387 _emitClassIfNeeded(classDefs, rules.provider.functionType); | |
| 378 } | 388 } |
| 379 classDefs.add(body); | 389 classDefs.add(body); |
| 380 return _statement(classDefs); | 390 return _statement(classDefs); |
| 381 } | 391 } |
| 382 | 392 |
| 383 void _emitClassIfNeeded(List<JS.Statement> defs, ClassElement base) { | 393 void _emitClassIfNeeded(List<JS.Statement> defs, DartType base) { |
| 384 // We can only emit classes from this library. | 394 // We can only emit classes from this library. |
| 385 if (base.library != currentLibrary) return; | 395 if (base.element.library != currentLibrary) return; |
| 386 | 396 |
| 387 var baseNode = _pendingClasses[base]; | 397 var baseNode = _pendingClasses[base.element]; |
| 388 if (baseNode != null) defs.add(visitClassDeclaration(baseNode)); | 398 if (baseNode != null) defs.add(visitClassDeclaration(baseNode)); |
| 389 } | 399 } |
| 390 | 400 |
| 391 /// Returns true if the supertype or mixins aren't loaded. | 401 /// Returns true if the supertype or mixins aren't loaded. |
| 392 /// If that is the case, we'll emit a lazy class definition. | 402 /// If that is the case, we'll emit a lazy class definition. |
| 393 bool _lazyClass(ClassElement cls) { | 403 bool _lazyClass(DartType type) { |
| 394 if (cls.type.isObject) return false; | 404 if (type.isObject) return false; |
| 395 | 405 |
| 396 assert(cls.library == currentLibrary); | 406 // Use the element as the key, as those are unique whereas generic types |
| 397 var result = _lazyClassMemo[cls]; | 407 // can have their arguments substituted. |
| 408 assert(type.element.library == currentLibrary); | |
| 409 var result = _lazyClassMemo[type.element]; | |
| 398 if (result != null) return result; | 410 if (result != null) return result; |
| 399 | 411 |
| 400 result = _classMightNotBeLoaded(cls.supertype.element); | 412 if (type is InterfaceType) { |
| 401 for (var mixin in cls.mixins) { | 413 result = _typeMightNotBeLoaded(type.superclass) || |
| 402 if (result) break; | 414 type.mixins.any(_typeMightNotBeLoaded); |
| 403 result = _classMightNotBeLoaded(mixin.element); | 415 } else if (type is FunctionType) { |
| 416 result = _typeMightNotBeLoaded(rules.provider.functionType); | |
| 404 } | 417 } |
| 405 return _lazyClassMemo[cls] = result; | 418 return _lazyClassMemo[type.element] = result; |
| 406 } | 419 } |
| 407 | 420 |
| 408 /// Curated order to minimize lazy classes needed by dart:core and its | 421 /// Curated order to minimize lazy classes needed by dart:core and its |
| 409 /// transitive SDK imports. | 422 /// transitive SDK imports. |
| 410 static const CORELIB_ORDER = const [ | 423 static const CORELIB_ORDER = const [ |
| 411 'dart.core', | 424 'dart.core', |
| 412 'dart.collection', | 425 'dart.collection', |
| 413 'dart._internal' | 426 'dart._internal' |
| 414 ]; | 427 ]; |
| 415 | 428 |
| 416 /// Returns true if the class might not be loaded. | 429 /// Returns true if the class might not be loaded. |
| 417 /// | 430 /// |
| 418 /// If the class is from our library, this can happen because it's lazy. | 431 /// If the class is from our library, this can happen because it's lazy. |
| 419 /// | 432 /// |
| 420 /// If the class is from a different library, it could happen if we're in | 433 /// If the class is from a different library, it could happen if we're in |
| 421 /// a library cycle. In other words, if that different library depends back | 434 /// a library cycle. In other words, if that different library depends back |
| 422 /// on this library via some transitive import path. | 435 /// on this library via some transitive import path. |
| 423 /// | 436 /// |
| 424 /// If we could control the global import ordering, we could eliminate some | 437 /// If we could control the global import ordering, we could eliminate some |
| 425 /// of these cases, by ordering the imports of the cyclic libraries in an | 438 /// of these cases, by ordering the imports of the cyclic libraries in an |
| 426 /// optimal way. For example, we could order the libraries in a cycle to | 439 /// optimal way. For example, we could order the libraries in a cycle to |
| 427 /// minimize laziness. However, we currently assume we cannot control the | 440 /// minimize laziness. However, we currently assume we cannot control the |
| 428 /// order that the cycle of libraries will be loaded in. | 441 /// order that the cycle of libraries will be loaded in. |
| 429 bool _classMightNotBeLoaded(ClassElement cls) { | 442 bool _typeMightNotBeLoaded(DartType type) { |
| 430 if (cls.library == currentLibrary) return _lazyClass(cls); | 443 var library = type.element.library; |
| 444 if (library == currentLibrary) return _lazyClass(type); | |
| 431 | 445 |
| 432 // The SDK is a special case: we optimize the order to prevent laziness. | 446 // The SDK is a special case: we optimize the order to prevent laziness. |
| 433 if (cls.library.isInSdk) { | 447 if (library.isInSdk) { |
| 434 // SDK is loaded before non-SDK libraies | 448 // SDK is loaded before non-SDK libraies |
| 435 if (!currentLibrary.isInSdk) return false; | 449 if (!currentLibrary.isInSdk) return false; |
| 436 | 450 |
| 437 // Compute the order of both SDK libraries. If unknown, assume it's after. | 451 // Compute the order of both SDK libraries. If unknown, assume it's after. |
| 438 var classOrder = CORELIB_ORDER.indexOf(cls.library.name); | 452 var classOrder = CORELIB_ORDER.indexOf(library.name); |
| 439 if (classOrder == -1) classOrder = CORELIB_ORDER.length; | 453 if (classOrder == -1) classOrder = CORELIB_ORDER.length; |
| 440 | 454 |
| 441 var currentOrder = CORELIB_ORDER.indexOf(currentLibrary.name); | 455 var currentOrder = CORELIB_ORDER.indexOf(currentLibrary.name); |
| 442 if (currentOrder == -1) currentOrder = CORELIB_ORDER.length; | 456 if (currentOrder == -1) currentOrder = CORELIB_ORDER.length; |
| 443 | 457 |
| 444 // If the dart:* library we are currently compiling is loaded after the | 458 // If the dart:* library we are currently compiling is loaded after the |
| 445 // class's library, then we know the class is available. | 459 // class's library, then we know the class is available. |
| 446 if (classOrder != currentOrder) return currentOrder < classOrder; | 460 if (classOrder != currentOrder) return currentOrder < classOrder; |
| 447 | 461 |
| 448 // If we don't know the order of the class's library or the current | 462 // If we don't know the order of the class's library or the current |
| 449 // library, do the normal cycle check. (Not all SDK libs are cycles.) | 463 // library, do the normal cycle check. (Not all SDK libs are cycles.) |
| 450 } | 464 } |
| 451 | 465 |
| 452 return _inLibraryCycle(cls.library); | 466 return _inLibraryCycle(library); |
| 453 } | 467 } |
| 454 | 468 |
| 455 /// Returns true if [library] depends on the [currentLibrary] via some | 469 /// Returns true if [library] depends on the [currentLibrary] via some |
| 456 /// transitive import. | 470 /// transitive import. |
| 457 bool _inLibraryCycle(LibraryElement library) { | 471 bool _inLibraryCycle(LibraryElement library) { |
| 458 // SDK libs don't depend on things outside the SDK. | 472 // SDK libs don't depend on things outside the SDK. |
| 459 // (We can reach this via the recursive call below.) | 473 // (We can reach this via the recursive call below.) |
| 460 if (library.isInSdk && !currentLibrary.isInSdk) return false; | 474 if (library.isInSdk && !currentLibrary.isInSdk) return false; |
| 461 | 475 |
| 462 var result = _libraryCycleMemo[library]; | 476 var result = _libraryCycleMemo[library]; |
| 463 if (result != null) return result; | 477 if (result != null) return result; |
| 464 | 478 |
| 465 result = library == currentLibrary; | 479 result = library == currentLibrary; |
| 466 _libraryCycleMemo[library] = result; | 480 _libraryCycleMemo[library] = result; |
| 467 for (var e in library.imports) { | 481 for (var e in library.imports) { |
| 468 if (result) break; | 482 if (result) break; |
| 469 result = _inLibraryCycle(e.importedLibrary); | 483 result = _inLibraryCycle(e.importedLibrary); |
| 470 } | 484 } |
| 471 for (var e in library.exports) { | 485 for (var e in library.exports) { |
| 472 if (result) break; | 486 if (result) break; |
| 473 result = _inLibraryCycle(e.exportedLibrary); | 487 result = _inLibraryCycle(e.exportedLibrary); |
| 474 } | 488 } |
| 475 return _libraryCycleMemo[library] = result; | 489 return _libraryCycleMemo[library] = result; |
| 476 } | 490 } |
| 477 | 491 |
| 478 JS.Statement _emitGenericClassDef(ClassElement cls, JS.Statement body) { | 492 JS.Statement _emitGenericClassDef(ParameterizedType type, JS.Statement body) { |
| 479 var name = cls.name; | 493 var name = type.name; |
| 480 var genericName = '$name\$'; | 494 var genericName = '$name\$'; |
| 481 var typeParams = cls.typeParameters.map((p) => p.name); | 495 var typeParams = type.typeParameters.map((p) => p.name); |
| 496 if (isPublic(name)) _exports.add(genericName); | |
| 482 return js.statement('let # = dart.generic(function(#) { #; return #; });', [ | 497 return js.statement('let # = dart.generic(function(#) { #; return #; });', [ |
| 483 genericName, | 498 genericName, |
| 484 typeParams, | 499 typeParams, |
| 485 body, | 500 body, |
| 486 name | 501 name |
| 487 ]); | 502 ]); |
| 488 } | 503 } |
| 489 | 504 |
| 490 JS.Expression _classHeritage(ClassDeclaration node) { | 505 JS.Expression _classHeritage(ClassDeclaration node) { |
| 491 if (node.element.type.isObject) return null; | 506 if (node.element.type.isObject) return null; |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 628 // Instead we use the same trick as named constructors, and do them as | 643 // Instead we use the same trick as named constructors, and do them as |
| 629 // instance methods that perform initialization. | 644 // instance methods that perform initialization. |
| 630 // TODO(jmesserly): we'll need to rethink this once the ES6 spec and V8 | 645 // TODO(jmesserly): we'll need to rethink this once the ES6 spec and V8 |
| 631 // settles. See <https://github.com/dart-lang/dev_compiler/issues/51>. | 646 // settles. See <https://github.com/dart-lang/dev_compiler/issues/51>. |
| 632 // Performance of this pattern is likely to be bad. | 647 // Performance of this pattern is likely to be bad. |
| 633 name = js.string('constructor', "'"); | 648 name = js.string('constructor', "'"); |
| 634 // Mark the parameter as no-rename. | 649 // Mark the parameter as no-rename. |
| 635 var args = new JS.Identifier('arguments', allowRename: false); | 650 var args = new JS.Identifier('arguments', allowRename: false); |
| 636 body = js.statement('''{ | 651 body = js.statement('''{ |
| 637 // Get the class name for this instance. | 652 // Get the class name for this instance. |
| 638 var name = this.constructor.name; | 653 let name = this.constructor.name; |
| 639 // Call the default constructor. | 654 // Call the default constructor. |
| 640 var init = this[name]; | 655 let init = this[name]; |
| 641 var result = void 0; | 656 let result = void 0; |
| 642 if (init) result = init.apply(this, #); | 657 if (init) result = init.apply(this, #); |
| 643 return result === void 0 ? this : result; | 658 return result === void 0 ? this : result; |
| 644 }''', args); | 659 }''', args); |
| 645 } else { | 660 } else { |
| 646 body = _emitConstructorBody(node, fields); | 661 body = _emitConstructorBody(node, fields); |
| 647 } | 662 } |
| 648 | 663 |
| 649 // We generate constructors as initializer methods in the class; | 664 // We generate constructors as initializer methods in the class; |
| 650 // this allows use of `super` for instance methods/properties. | 665 // this allows use of `super` for instance methods/properties. |
| 651 // It also avoids V8 restrictions on `super` in default constructors. | 666 // It also avoids V8 restrictions on `super` in default constructors. |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1019 } | 1034 } |
| 1020 | 1035 |
| 1021 if (typeArgs != null) { | 1036 if (typeArgs != null) { |
| 1022 result = js.call('#(#)', [result, typeArgs]); | 1037 result = js.call('#(#)', [result, typeArgs]); |
| 1023 } | 1038 } |
| 1024 return result; | 1039 return result; |
| 1025 } | 1040 } |
| 1026 | 1041 |
| 1027 bool _needQualifiedName(Element element) { | 1042 bool _needQualifiedName(Element element) { |
| 1028 var lib = element.library; | 1043 var lib = element.library; |
| 1029 | 1044 if (lib == null) return false; |
| 1030 return lib != null && | 1045 if (lib != currentLibrary) return true; |
| 1031 (lib != currentLibrary || | 1046 if (element is ClassElement) return _lazyClass(element.type); |
| 1032 element is ClassElement && _lazyClass(element)); | 1047 if (element is FunctionTypeAliasElement) return _lazyClass(element.type); |
| 1048 return false; | |
| 1033 } | 1049 } |
| 1034 | 1050 |
| 1035 JS.Node _emitDPutIfDynamic( | 1051 JS.Node _emitDPutIfDynamic( |
| 1036 Expression target, SimpleIdentifier id, Expression rhs) { | 1052 Expression target, SimpleIdentifier id, Expression rhs) { |
| 1037 if (rules.isDynamicTarget(target)) { | 1053 if (rules.isDynamicTarget(target)) { |
| 1038 return js.call('dart.dput(#, #, #)', [ | 1054 return js.call('dart.dput(#, #, #)', [ |
| 1039 _visit(target), | 1055 _visit(target), |
| 1040 js.string(id.name, "'"), | 1056 js.string(id.name, "'"), |
| 1041 _visit(rhs) | 1057 _visit(rhs) |
| 1042 ]); | 1058 ]); |
| (...skipping 1341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2384 | 2400 |
| 2385 // TODO(jmesserly): in many cases marking the end will be unncessary. | 2401 // TODO(jmesserly): in many cases marking the end will be unncessary. |
| 2386 printer.mark(_location(node.end)); | 2402 printer.mark(_location(node.end)); |
| 2387 } | 2403 } |
| 2388 | 2404 |
| 2389 String _getIdentifier(AstNode node) { | 2405 String _getIdentifier(AstNode node) { |
| 2390 if (node is SimpleIdentifier) return node.name; | 2406 if (node is SimpleIdentifier) return node.name; |
| 2391 return null; | 2407 return null; |
| 2392 } | 2408 } |
| 2393 } | 2409 } |
| OLD | NEW |