OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 | 2 |
3 // for details. All rights reserved. Use of this source code is governed by a | 3 // for details. All rights reserved. Use of this source code is governed by a |
4 // BSD-style license that can be found in the LICENSE file. | 4 // BSD-style license that can be found in the LICENSE file. |
5 | 5 |
6 import 'dart:collection' show HashMap, HashSet; | 6 import 'dart:collection' show HashMap, HashSet; |
7 import 'dart:math' show min, max; | 7 import 'dart:math' show min, max; |
8 | 8 |
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
10 import 'package:analyzer/dart/ast/ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
(...skipping 734 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
745 | 745 |
746 // If this is a JavaScript type, emit it now and then exit. | 746 // If this is a JavaScript type, emit it now and then exit. |
747 var jsTypeDef = _emitJsType(classElem); | 747 var jsTypeDef = _emitJsType(classElem); |
748 if (jsTypeDef != null) return jsTypeDef; | 748 if (jsTypeDef != null) return jsTypeDef; |
749 | 749 |
750 var ctors = <ConstructorDeclaration>[]; | 750 var ctors = <ConstructorDeclaration>[]; |
751 var fields = <FieldDeclaration>[]; | 751 var fields = <FieldDeclaration>[]; |
752 var staticFields = <FieldDeclaration>[]; | 752 var staticFields = <FieldDeclaration>[]; |
753 var methods = <MethodDeclaration>[]; | 753 var methods = <MethodDeclaration>[]; |
754 | 754 |
755 // True if a "call" method or getter exists. | 755 // True if a "call" method or getter exists directly on this class. |
| 756 // If so, we need to install a Function prototype. |
756 bool isCallable = false; | 757 bool isCallable = false; |
757 for (var member in node.members) { | 758 for (var member in node.members) { |
758 if (member is ConstructorDeclaration) { | 759 if (member is ConstructorDeclaration) { |
759 ctors.add(member); | 760 ctors.add(member); |
760 } else if (member is FieldDeclaration) { | 761 } else if (member is FieldDeclaration) { |
761 (member.isStatic ? staticFields : fields).add(member); | 762 (member.isStatic ? staticFields : fields).add(member); |
762 } else if (member is MethodDeclaration) { | 763 } else if (member is MethodDeclaration) { |
763 methods.add(member); | 764 methods.add(member); |
764 if (member.name.name == 'call' && !member.isSetter) { | 765 if (member.name.name == 'call' && !member.isSetter) { |
765 // | 766 // |
766 // Make sure "call" has a statically known function type: | 767 // Make sure "call" has a statically known function type: |
767 // | 768 // |
768 // - if it's a method, then it does because all methods do, | 769 // - if it's a method, then it does because all methods do, |
769 // - if it's a getter, check the return type. | 770 // - if it's a getter, check the return type. |
770 // | 771 // |
771 // Other cases like a getter returning dynamic/Object/Function will be | 772 // Other cases like a getter returning dynamic/Object/Function will be |
772 // handled at runtime by the dynamic call mechanism. So we only | 773 // handled at runtime by the dynamic call mechanism. So we only |
773 // concern ourselves with statically known function types. | 774 // concern ourselves with statically known function types. |
774 // | 775 // |
775 // For the same reason, we can ignore "noSuchMethod". | 776 // For the same reason, we can ignore "noSuchMethod". |
776 // call-implemented-by-nSM will be dispatched by dcall at runtime. | 777 // call-implemented-by-nSM will be dispatched by dcall at runtime. |
777 // | 778 // |
778 isCallable = !member.isGetter || member.returnType is FunctionType; | 779 isCallable = !member.isGetter || member.returnType is FunctionType; |
779 } | 780 } |
780 } | 781 } |
781 } | 782 } |
782 | 783 |
| 784 // True if a "call" method or getter exists directly or indirectly on this |
| 785 // class. If so, we need special constructor handling. |
| 786 bool isCallableTransitive = |
| 787 classElem.lookUpMethod('call', currentLibrary) != null; |
| 788 if (!isCallableTransitive) { |
| 789 var callGetter = classElem.lookUpGetter('call', currentLibrary); |
| 790 isCallableTransitive = |
| 791 callGetter != null && callGetter.returnType is FunctionType; |
| 792 } |
| 793 |
783 JS.Expression className; | 794 JS.Expression className; |
784 if (classElem.typeParameters.isNotEmpty) { | 795 if (classElem.typeParameters.isNotEmpty) { |
785 // Generic classes will be defined inside a function that closes over the | 796 // Generic classes will be defined inside a function that closes over the |
786 // type parameter. So we can use their local variable name directly. | 797 // type parameter. So we can use their local variable name directly. |
787 className = new JS.Identifier(classElem.name); | 798 className = new JS.Identifier(classElem.name); |
788 } else { | 799 } else { |
789 className = _emitTopLevelName(classElem); | 800 className = _emitTopLevelName(classElem); |
790 } | 801 } |
791 | 802 |
792 var allFields = fields.toList()..addAll(staticFields); | 803 var allFields = fields.toList()..addAll(staticFields); |
(...skipping 16 matching lines...) Expand all Loading... |
809 // Emit the class, e.g. `core.Object = class Object { ... }` | 820 // Emit the class, e.g. `core.Object = class Object { ... }` |
810 _defineClass(classElem, className, classExpr, isCallable, body); | 821 _defineClass(classElem, className, classExpr, isCallable, body); |
811 | 822 |
812 // Emit things that come after the ES6 `class ... { ... }`. | 823 // Emit things that come after the ES6 `class ... { ... }`. |
813 var jsPeerNames = _getJSPeerNames(classElem); | 824 var jsPeerNames = _getJSPeerNames(classElem); |
814 JS.Statement deferredBaseClass = | 825 JS.Statement deferredBaseClass = |
815 _setBaseClass(classElem, className, jsPeerNames, body); | 826 _setBaseClass(classElem, className, jsPeerNames, body); |
816 | 827 |
817 _emitClassTypeTests(classElem, className, body); | 828 _emitClassTypeTests(classElem, className, body); |
818 | 829 |
819 _defineNamedConstructors(ctors, body, className, isCallable); | 830 _defineNamedConstructors(ctors, body, className, isCallableTransitive); |
820 body.addAll(virtualFieldSymbols); | 831 body.addAll(virtualFieldSymbols); |
821 _emitClassSignature( | 832 _emitClassSignature( |
822 methods, allFields, classElem, ctors, extensions, className, body); | 833 methods, allFields, classElem, ctors, extensions, className, body); |
823 _defineExtensionMembers(extensions, className, body); | 834 _defineExtensionMembers(extensions, className, body); |
824 _emitClassMetadata(node.metadata, className, body); | 835 _emitClassMetadata(node.metadata, className, body); |
825 | 836 |
826 JS.Statement classDef = _statement(body); | 837 JS.Statement classDef = _statement(body); |
827 | 838 |
828 var typeFormals = classElem.typeParameters; | 839 var typeFormals = classElem.typeParameters; |
829 if (typeFormals.isNotEmpty) { | 840 if (typeFormals.isNotEmpty) { |
(...skipping 4969 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5799 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5810 if (targetIdentifier.staticElement is! PrefixElement) return false; |
5800 var prefix = targetIdentifier.staticElement as PrefixElement; | 5811 var prefix = targetIdentifier.staticElement as PrefixElement; |
5801 | 5812 |
5802 // The library the prefix is referring to must come from a deferred import. | 5813 // The library the prefix is referring to must come from a deferred import. |
5803 var containingLibrary = resolutionMap | 5814 var containingLibrary = resolutionMap |
5804 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 5815 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
5805 .library; | 5816 .library; |
5806 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5817 var imports = containingLibrary.getImportsWithPrefix(prefix); |
5807 return imports.length == 1 && imports[0].isDeferred; | 5818 return imports.length == 1 && imports[0].isDeferred; |
5808 } | 5819 } |
OLD | NEW |