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 import 'dart:collection' show HashMap, HashSet; | 5 import 'dart:collection' show HashMap, HashSet; |
6 import 'dart:math' show min, max; | 6 import 'dart:math' show min, max; |
7 | 7 |
8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
(...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
248 // any nodes. | 248 // any nodes. |
249 var nodes = new HashMap<Element, AstNode>.identity(); | 249 var nodes = new HashMap<Element, AstNode>.identity(); |
250 var sdkBootstrappingFns = new List<FunctionElement>(); | 250 var sdkBootstrappingFns = new List<FunctionElement>(); |
251 for (var unit in compilationUnits) { | 251 for (var unit in compilationUnits) { |
252 if (_isDartRuntime(unit.element.library)) { | 252 if (_isDartRuntime(unit.element.library)) { |
253 sdkBootstrappingFns.addAll(unit.element.functions); | 253 sdkBootstrappingFns.addAll(unit.element.functions); |
254 } | 254 } |
255 _collectElements(unit, nodes); | 255 _collectElements(unit, nodes); |
256 } | 256 } |
257 _loader = new ElementLoader(nodes); | 257 _loader = new ElementLoader(nodes); |
258 if (compilationUnits.isNotEmpty) { | |
259 _constField = new ConstFieldVisitor(types, | |
260 dummySource: compilationUnits.first.element.source); | |
261 } | |
258 | 262 |
259 // Add implicit dart:core dependency so it is first. | 263 // Add implicit dart:core dependency so it is first. |
260 emitLibraryName(dartCoreLibrary); | 264 emitLibraryName(dartCoreLibrary); |
261 | 265 |
262 // Emit SDK bootstrapping functions first, if any. | 266 // Emit SDK bootstrapping functions first, if any. |
263 sdkBootstrappingFns.forEach(_emitDeclaration); | 267 sdkBootstrappingFns.forEach(_emitDeclaration); |
264 | 268 |
265 // Visit each compilation unit and emit its code. | 269 // Visit each compilation unit and emit its code. |
266 // | 270 // |
267 // NOTE: declarations are not necessarily emitted in this order. | 271 // NOTE: declarations are not necessarily emitted in this order. |
268 // Order will be changed as needed so the resulting code can execute. | 272 // Order will be changed as needed so the resulting code can execute. |
269 // This is done by forward declaring items. | 273 // This is done by forward declaring items. |
270 compilationUnits.forEach(visitCompilationUnit); | 274 compilationUnits.forEach(_finishDeclarationsInUnit); |
271 | 275 |
272 // Declare imports | 276 // Declare imports |
273 _finishImports(items); | 277 _finishImports(items); |
274 | 278 |
275 // Discharge the type table cache variables and | 279 // Discharge the type table cache variables and |
276 // hoisted definitions. | 280 // hoisted definitions. |
277 items.addAll(_typeTable.discharge()); | 281 items.addAll(_typeTable.discharge()); |
278 | 282 |
279 // Add the module's code (produced by visiting compilation units, above) | 283 // Add the module's code (produced by visiting compilation units, above) |
280 _copyAndFlattenBlocks(items, _moduleItems); | 284 _copyAndFlattenBlocks(items, _moduleItems); |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
432 return _visit(node); | 436 return _visit(node); |
433 }); | 437 }); |
434 | 438 |
435 if (item != null) _moduleItems.add(item); | 439 if (item != null) _moduleItems.add(item); |
436 } | 440 } |
437 | 441 |
438 void _declareBeforeUse(Element e) { | 442 void _declareBeforeUse(Element e) { |
439 _loader.declareBeforeUse(e, _emitDeclaration); | 443 _loader.declareBeforeUse(e, _emitDeclaration); |
440 } | 444 } |
441 | 445 |
442 @override | 446 void _finishDeclarationsInUnit(CompilationUnit unit) { |
443 void visitCompilationUnit(CompilationUnit unit) { | 447 // NOTE: this method isn't the right place to initialize |
444 _constField = new ConstFieldVisitor(types, unit.element.source); | 448 // per-compilation-unit state. Declarations can be visited out of order, |
445 | 449 // this is only to catch things that haven't been emitted yet. |
450 // | |
451 // See _emitDeclaration. | |
446 for (var declaration in unit.declarations) { | 452 for (var declaration in unit.declarations) { |
447 var element = declaration.element; | 453 var element = declaration.element; |
448 if (element != null) { | 454 if (element != null) { |
449 _emitDeclaration(element); | 455 _emitDeclaration(element); |
450 } else { | 456 } else { |
451 declaration.accept(this); | 457 declaration.accept(this); |
452 } | 458 } |
453 } | 459 } |
454 for (var directive in unit.directives) { | 460 for (var directive in unit.directives) { |
455 directive.accept(this); | 461 directive.accept(this); |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
695 | 701 |
696 // If this is a JavaScript type, emit it now and then exit. | 702 // If this is a JavaScript type, emit it now and then exit. |
697 var jsTypeDef = _emitJsType(classElem); | 703 var jsTypeDef = _emitJsType(classElem); |
698 if (jsTypeDef != null) return jsTypeDef; | 704 if (jsTypeDef != null) return jsTypeDef; |
699 | 705 |
700 var ctors = <ConstructorDeclaration>[]; | 706 var ctors = <ConstructorDeclaration>[]; |
701 var fields = <FieldDeclaration>[]; | 707 var fields = <FieldDeclaration>[]; |
702 var staticFields = <FieldDeclaration>[]; | 708 var staticFields = <FieldDeclaration>[]; |
703 var methods = <MethodDeclaration>[]; | 709 var methods = <MethodDeclaration>[]; |
704 | 710 |
705 // True if a "call" method or getter exists. This can also be | 711 // True if a "call" method or getter exists. |
706 // "noSuchMethod" method, because nSM could implement "call". | |
707 bool isCallable = false; | 712 bool isCallable = false; |
708 for (var member in node.members) { | 713 for (var member in node.members) { |
709 if (member is ConstructorDeclaration) { | 714 if (member is ConstructorDeclaration) { |
710 ctors.add(member); | 715 ctors.add(member); |
711 } else if (member is FieldDeclaration) { | 716 } else if (member is FieldDeclaration) { |
712 (member.isStatic ? staticFields : fields).add(member); | 717 (member.isStatic ? staticFields : fields).add(member); |
713 } else if (member is MethodDeclaration) { | 718 } else if (member is MethodDeclaration) { |
714 methods.add(member); | 719 methods.add(member); |
715 var name = member.name.name; | 720 if (member.name.name == 'call' && !member.isSetter) { |
Jennifer Messerly
2016/06/21 20:21:46
When I merged, I had to fix how recently implement
| |
716 if (name == 'call' && !member.isSetter) { | 721 // |
717 isCallable = true; | 722 // Make sure "call" has a statically known function type: |
718 } else if (name == 'noSuchMethod' && | 723 // |
719 !member.isGetter && | 724 // - if it's a method, then it does because all methods do, |
720 !member.isSetter && | 725 // - if it's a getter, check the return type. |
721 // Exclude SDK because we know they don't use nSM to implement call. | 726 // |
722 !classElem.library.source.isInSystemLibrary) { | 727 // Other cases like a getter returning dynamic/Object/Function will be |
723 isCallable = true; | 728 // handled at runtime by the dynamic call mechanism. So we only |
729 // concern ourselves with statically known function types. | |
730 // | |
731 // For the same reason, we can ignore "noSuchMethod". | |
732 // call-implemented-by-nSM will be dispatched by dcall at runtime. | |
733 // | |
734 isCallable = !member.isGetter || member.returnType is FunctionType; | |
724 } | 735 } |
725 } | 736 } |
726 } | 737 } |
727 | 738 |
728 JS.Expression className; | 739 JS.Expression className; |
729 if (classElem.typeParameters.isNotEmpty) { | 740 if (classElem.typeParameters.isNotEmpty) { |
730 // Generic classes will be defined inside a function that closes over the | 741 // Generic classes will be defined inside a function that closes over the |
731 // type parameter. So we can use their local variable name directly. | 742 // type parameter. So we can use their local variable name directly. |
732 className = new JS.Identifier(classElem.name); | 743 className = new JS.Identifier(classElem.name); |
733 } else { | 744 } else { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
785 /// Named constructors are handled elsewhere, see [_defineNamedConstructors]. | 796 /// Named constructors are handled elsewhere, see [_defineNamedConstructors]. |
786 JS.Expression _emitCallableClass(JS.ClassExpression classExpr, | 797 JS.Expression _emitCallableClass(JS.ClassExpression classExpr, |
787 ConstructorElement unnamedCtor) { | 798 ConstructorElement unnamedCtor) { |
788 var ctor = new JS.NamedFunction( | 799 var ctor = new JS.NamedFunction( |
789 classExpr.name, _emitCallableClassConstructor(unnamedCtor)); | 800 classExpr.name, _emitCallableClassConstructor(unnamedCtor)); |
790 | 801 |
791 // Name the constructor function the same as the class. | 802 // Name the constructor function the same as the class. |
792 return js.call('dart.callableClass(#, #)', [ctor, classExpr]); | 803 return js.call('dart.callableClass(#, #)', [ctor, classExpr]); |
793 } | 804 } |
794 | 805 |
795 JS.Fun _emitCallableClassConstructor( | 806 /// Emits a constructor that ensures instances of this class are callable as |
796 ConstructorElement ctor) { | 807 /// functions in JavaScript. |
808 JS.Fun _emitCallableClassConstructor(ConstructorElement ctor) { | |
797 | 809 |
798 return js.call( | 810 return js.call( |
799 r'''function (...args) { | 811 r'''function (...args) { |
800 const self = this; | 812 const self = this; |
801 function call(...args) { | 813 function call(...args) { |
802 return self.call.apply(self, args); | 814 return self.call.apply(self, args); |
803 } | 815 } |
804 call.__proto__ = this.__proto__; | 816 call.__proto__ = this.__proto__; |
805 call.#.apply(call, args); | 817 call.#.apply(call, args); |
806 return call; | 818 return call; |
(...skipping 3497 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4304 /// For example `null.toString()` is legal in Dart, so we need to generate | 4316 /// For example `null.toString()` is legal in Dart, so we need to generate |
4305 /// that as `dart.toString(obj)`. | 4317 /// that as `dart.toString(obj)`. |
4306 bool _isObjectMemberCall(Expression target, String memberName) { | 4318 bool _isObjectMemberCall(Expression target, String memberName) { |
4307 if (!isObjectMember(memberName)) { | 4319 if (!isObjectMember(memberName)) { |
4308 return false; | 4320 return false; |
4309 } | 4321 } |
4310 | 4322 |
4311 // Check if the target could be `null`, is dynamic, or may be an extension | 4323 // Check if the target could be `null`, is dynamic, or may be an extension |
4312 // native type. In all of those cases we need defensive code generation. | 4324 // native type. In all of those cases we need defensive code generation. |
4313 var type = getStaticType(target); | 4325 var type = getStaticType(target); |
4326 | |
4314 return isNullable(target) || | 4327 return isNullable(target) || |
4328 type is FunctionType || | |
4315 type.isDynamic || | 4329 type.isDynamic || |
4316 (_extensionTypes.hasNativeSubtype(type) && target is! SuperExpression); | 4330 (_extensionTypes.hasNativeSubtype(type) && target is! SuperExpression); |
4317 } | 4331 } |
4318 | 4332 |
4319 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. | 4333 /// Shared code for [PrefixedIdentifier] and [PropertyAccess]. |
4320 JS.Expression _emitAccess( | 4334 JS.Expression _emitAccess( |
4321 Expression target, SimpleIdentifier memberId, DartType resultType) { | 4335 Expression target, SimpleIdentifier memberId, DartType resultType) { |
4322 Element member = memberId.staticElement; | 4336 Element member = memberId.staticElement; |
4323 if (member is PropertyAccessorElement) { | 4337 if (member is PropertyAccessorElement) { |
4324 member = (member as PropertyAccessorElement).variable; | 4338 member = (member as PropertyAccessorElement).variable; |
(...skipping 877 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5202 } | 5216 } |
5203 | 5217 |
5204 bool isLibraryPrefix(Expression node) => | 5218 bool isLibraryPrefix(Expression node) => |
5205 node is SimpleIdentifier && node.staticElement is PrefixElement; | 5219 node is SimpleIdentifier && node.staticElement is PrefixElement; |
5206 | 5220 |
5207 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 5221 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
5208 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 5222 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
5209 | 5223 |
5210 bool _isDartRuntime(LibraryElement l) => | 5224 bool _isDartRuntime(LibraryElement l) => |
5211 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 5225 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
OLD | NEW |