| 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 683 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 694 if (findAnnotation(classElem, isPublicJSAnnotation) != null) return null; | 694 if (findAnnotation(classElem, isPublicJSAnnotation) != null) return null; |
| 695 | 695 |
| 696 // If this is a JavaScript type, emit it now and then exit. | 696 // If this is a JavaScript type, emit it now and then exit. |
| 697 var jsTypeDef = _emitJsType(classElem); | 697 var jsTypeDef = _emitJsType(classElem); |
| 698 if (jsTypeDef != null) return jsTypeDef; | 698 if (jsTypeDef != null) return jsTypeDef; |
| 699 | 699 |
| 700 var ctors = <ConstructorDeclaration>[]; | 700 var ctors = <ConstructorDeclaration>[]; |
| 701 var fields = <FieldDeclaration>[]; | 701 var fields = <FieldDeclaration>[]; |
| 702 var staticFields = <FieldDeclaration>[]; | 702 var staticFields = <FieldDeclaration>[]; |
| 703 var methods = <MethodDeclaration>[]; | 703 var methods = <MethodDeclaration>[]; |
| 704 |
| 705 // True if a "call" method or getter exists. This can also be |
| 706 // "noSuchMethod" method, because nSM could implement "call". |
| 707 bool isCallable = false; |
| 704 for (var member in node.members) { | 708 for (var member in node.members) { |
| 705 if (member is ConstructorDeclaration) { | 709 if (member is ConstructorDeclaration) { |
| 706 ctors.add(member); | 710 ctors.add(member); |
| 707 } else if (member is FieldDeclaration) { | 711 } else if (member is FieldDeclaration) { |
| 708 (member.isStatic ? staticFields : fields).add(member); | 712 (member.isStatic ? staticFields : fields).add(member); |
| 709 } else if (member is MethodDeclaration) { | 713 } else if (member is MethodDeclaration) { |
| 710 methods.add(member); | 714 methods.add(member); |
| 715 var name = member.name.name; |
| 716 if (name == 'call' && !member.isSetter) { |
| 717 isCallable = true; |
| 718 } else if (name == 'noSuchMethod' && |
| 719 !member.isGetter && |
| 720 !member.isSetter && |
| 721 // Exclude SDK because we know they don't use nSM to implement call. |
| 722 !classElem.library.source.isInSystemLibrary) { |
| 723 isCallable = true; |
| 724 } |
| 711 } | 725 } |
| 712 } | 726 } |
| 713 | 727 |
| 714 JS.Expression className; | 728 JS.Expression className; |
| 715 if (classElem.typeParameters.isNotEmpty) { | 729 if (classElem.typeParameters.isNotEmpty) { |
| 716 // Generic classes will be defined inside a function that closes over the | 730 // Generic classes will be defined inside a function that closes over the |
| 717 // type parameter. So we can use their local variable name directly. | 731 // type parameter. So we can use their local variable name directly. |
| 718 className = new JS.Identifier(classElem.name); | 732 className = new JS.Identifier(classElem.name); |
| 719 } else { | 733 } else { |
| 720 className = _emitTopLevelName(classElem); | 734 className = _emitTopLevelName(classElem); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 731 var classExpr = _emitClassExpression(classElem, | 745 var classExpr = _emitClassExpression(classElem, |
| 732 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), | 746 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), |
| 733 fields: allFields); | 747 fields: allFields); |
| 734 | 748 |
| 735 var body = <JS.Statement>[]; | 749 var body = <JS.Statement>[]; |
| 736 var extensions = _extensionsToImplement(classElem); | 750 var extensions = _extensionsToImplement(classElem); |
| 737 _initExtensionSymbols(classElem, methods, fields, body); | 751 _initExtensionSymbols(classElem, methods, fields, body); |
| 738 _emitSuperHelperSymbols(_superHelperSymbols, body); | 752 _emitSuperHelperSymbols(_superHelperSymbols, body); |
| 739 | 753 |
| 740 // Emit the class, e.g. `core.Object = class Object { ... }` | 754 // Emit the class, e.g. `core.Object = class Object { ... }` |
| 741 _defineClass(classElem, className, classExpr, body); | 755 _defineClass(classElem, className, classExpr, isCallable, body); |
| 742 | 756 |
| 743 // Emit things that come after the ES6 `class ... { ... }`. | 757 // Emit things that come after the ES6 `class ... { ... }`. |
| 744 var jsPeerName = _getJSPeerName(classElem); | 758 var jsPeerName = _getJSPeerName(classElem); |
| 745 _setBaseClass(classElem, className, jsPeerName, body); | 759 _setBaseClass(classElem, className, jsPeerName, body); |
| 746 | 760 |
| 747 _emitClassTypeTests(classElem, className, body); | 761 _emitClassTypeTests(classElem, className, body); |
| 748 | 762 |
| 749 _defineNamedConstructors(ctors, body, className); | 763 _defineNamedConstructors(ctors, body, className, isCallable); |
| 750 _emitVirtualFieldSymbols(virtualFieldSymbols, body); | 764 _emitVirtualFieldSymbols(virtualFieldSymbols, body); |
| 751 _emitClassSignature(methods, classElem, ctors, extensions, className, body); | 765 _emitClassSignature(methods, classElem, ctors, extensions, className, body); |
| 752 _defineExtensionMembers(extensions, className, body); | 766 _defineExtensionMembers(extensions, className, body); |
| 753 _emitClassMetadata(node.metadata, className, body); | 767 _emitClassMetadata(node.metadata, className, body); |
| 754 | 768 |
| 755 JS.Statement classDef = _statement(body); | 769 JS.Statement classDef = _statement(body); |
| 756 var typeFormals = classElem.typeParameters; | 770 var typeFormals = classElem.typeParameters; |
| 757 if (typeFormals.isNotEmpty) { | 771 if (typeFormals.isNotEmpty) { |
| 758 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef); | 772 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef); |
| 759 } | 773 } |
| 760 | 774 |
| 761 body = <JS.Statement>[classDef]; | 775 body = <JS.Statement>[classDef]; |
| 762 _emitStaticFields(staticFields, staticFieldOverrides, classElem, body); | 776 _emitStaticFields(staticFields, staticFieldOverrides, classElem, body); |
| 763 _registerExtensionType(classElem, jsPeerName, body); | 777 _registerExtensionType(classElem, jsPeerName, body); |
| 764 return _statement(body); | 778 return _statement(body); |
| 765 } | 779 } |
| 766 | 780 |
| 781 /// Emits code to support a class with a "call" method and an unnamed |
| 782 /// constructor. |
| 783 /// |
| 784 /// This ensures instances created by the unnamed constructor are functions. |
| 785 /// Named constructors are handled elsewhere, see [_defineNamedConstructors]. |
| 786 JS.Expression _emitCallableClass(JS.ClassExpression classExpr, |
| 787 ConstructorElement unnamedCtor) { |
| 788 var ctor = new JS.NamedFunction( |
| 789 classExpr.name, _emitCallableClassConstructor(unnamedCtor)); |
| 790 |
| 791 // Name the constructor function the same as the class. |
| 792 return js.call('dart.callableClass(#, #)', [ctor, classExpr]); |
| 793 } |
| 794 |
| 795 JS.Fun _emitCallableClassConstructor( |
| 796 ConstructorElement ctor) { |
| 797 |
| 798 return js.call( |
| 799 r'''function (...args) { |
| 800 const self = this; |
| 801 function call(...args) { |
| 802 return self.call.apply(self, args); |
| 803 } |
| 804 call.__proto__ = this.__proto__; |
| 805 call.#.apply(call, args); |
| 806 return call; |
| 807 }''', |
| 808 [_constructorName(ctor)]); |
| 809 } |
| 810 |
| 767 void _emitClassTypeTests(ClassElement classElem, JS.Expression className, | 811 void _emitClassTypeTests(ClassElement classElem, JS.Expression className, |
| 768 List<JS.Statement> body) { | 812 List<JS.Statement> body) { |
| 769 if (classElem == objectClass) { | 813 if (classElem == objectClass) { |
| 770 // We rely on ES6 static inheritance. All types that are represented by | 814 // We rely on ES6 static inheritance. All types that are represented by |
| 771 // class constructor functions will see these definitions, with [this] | 815 // class constructor functions will see these definitions, with [this] |
| 772 // being bound to the class constructor. | 816 // being bound to the class constructor. |
| 773 | 817 |
| 774 // The 'instanceof' checks don't work for primitive types (which have fast | 818 // The 'instanceof' checks don't work for primitive types (which have fast |
| 775 // definitions below) and don't work for native types. In those cases we | 819 // definitions below) and don't work for native types. In those cases we |
| 776 // fall through to the general purpose checking code. | 820 // fall through to the general purpose checking code. |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 971 virtualFields[field.element] = virtualField; | 1015 virtualFields[field.element] = virtualField; |
| 972 virtualFieldSymbols.add(js.statement( | 1016 virtualFieldSymbols.add(js.statement( |
| 973 'const # = Symbol(#.name + "." + #.toString());', | 1017 'const # = Symbol(#.name + "." + #.toString());', |
| 974 [virtualField, className, fieldName])); | 1018 [virtualField, className, fieldName])); |
| 975 } | 1019 } |
| 976 } | 1020 } |
| 977 } | 1021 } |
| 978 } | 1022 } |
| 979 } | 1023 } |
| 980 | 1024 |
| 981 void _defineClass(ClassElement classElem, JS.Expression className, | 1025 void _defineClass( |
| 982 JS.ClassExpression classExpr, List<JS.Statement> body) { | 1026 ClassElement classElem, |
| 1027 JS.Expression className, |
| 1028 JS.ClassExpression classExpr, |
| 1029 bool isCallable, |
| 1030 List<JS.Statement> body) { |
| 1031 JS.Expression callableClass; |
| 1032 if (isCallable && classElem.unnamedConstructor != null) { |
| 1033 callableClass = _emitCallableClass( |
| 1034 classExpr, classElem.unnamedConstructor); |
| 1035 } |
| 1036 |
| 983 if (classElem.typeParameters.isNotEmpty) { | 1037 if (classElem.typeParameters.isNotEmpty) { |
| 984 body.add(new JS.ClassDeclaration(classExpr)); | 1038 if (callableClass != null) { |
| 1039 body.add(js.statement('const # = #;', [classExpr.name, callableClass])); |
| 1040 } else { |
| 1041 body.add(new JS.ClassDeclaration(classExpr)); |
| 1042 } |
| 985 } else { | 1043 } else { |
| 986 body.add(js.statement('# = #;', [className, classExpr])); | 1044 body.add(js.statement('# = #;', [className, callableClass ?? classExpr])); |
| 987 } | 1045 } |
| 988 } | 1046 } |
| 989 | 1047 |
| 990 void _emitVirtualFieldSymbols( | 1048 void _emitVirtualFieldSymbols( |
| 991 List<JS.Statement> virtualFields, List<JS.Statement> body) { | 1049 List<JS.Statement> virtualFields, List<JS.Statement> body) { |
| 992 body.addAll(virtualFields); | 1050 body.addAll(virtualFields); |
| 993 } | 1051 } |
| 994 | 1052 |
| 995 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) { | 1053 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) { |
| 996 return typeFormals | 1054 return typeFormals |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1393 body.add(js.statement( | 1451 body.add(js.statement( |
| 1394 'dart.setExtensionBaseClass(#, #);', [className, newBaseClass])); | 1452 'dart.setExtensionBaseClass(#, #);', [className, newBaseClass])); |
| 1395 } else if (_hasDeferredSupertype.contains(classElem)) { | 1453 } else if (_hasDeferredSupertype.contains(classElem)) { |
| 1396 var newBaseClass = _emitType(classElem.type.superclass, | 1454 var newBaseClass = _emitType(classElem.type.superclass, |
| 1397 nameType: false, subClass: classElem, className: className); | 1455 nameType: false, subClass: classElem, className: className); |
| 1398 body.add( | 1456 body.add( |
| 1399 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass])); | 1457 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass])); |
| 1400 } | 1458 } |
| 1401 } | 1459 } |
| 1402 | 1460 |
| 1403 void _defineNamedConstructors(List<ConstructorDeclaration> ctors, | 1461 void _defineNamedConstructors( |
| 1404 List<JS.Statement> body, JS.Expression className) { | 1462 List<ConstructorDeclaration> ctors, |
| 1463 List<JS.Statement> body, |
| 1464 JS.Expression className, |
| 1465 bool isCallable) { |
| 1466 var code = isCallable |
| 1467 ? 'dart.defineNamedConstructorCallable(#, #, #);' |
| 1468 : 'dart.defineNamedConstructor(#, #)'; |
| 1469 |
| 1405 for (ConstructorDeclaration member in ctors) { | 1470 for (ConstructorDeclaration member in ctors) { |
| 1406 if (member.name != null && member.factoryKeyword == null) { | 1471 if (member.name != null && member.factoryKeyword == null) { |
| 1407 body.add(js.statement('dart.defineNamedConstructor(#, #);', | 1472 var args = [className, _constructorName(member.element)]; |
| 1408 [className, _constructorName(member.element)])); | 1473 if (isCallable) { |
| 1474 args.add(_emitCallableClassConstructor(member.element)); |
| 1475 } |
| 1476 |
| 1477 body.add(js.statement(code, args)); |
| 1409 } | 1478 } |
| 1410 } | 1479 } |
| 1411 } | 1480 } |
| 1412 | 1481 |
| 1413 /// Emits static fields for a class, and initialize them eagerly if possible, | 1482 /// Emits static fields for a class, and initialize them eagerly if possible, |
| 1414 /// otherwise define them as lazy properties. | 1483 /// otherwise define them as lazy properties. |
| 1415 void _emitStaticFields( | 1484 void _emitStaticFields( |
| 1416 List<FieldDeclaration> staticFields, | 1485 List<FieldDeclaration> staticFields, |
| 1417 Set<FieldElement> staticFieldOverrides, | 1486 Set<FieldElement> staticFieldOverrides, |
| 1418 ClassElement classElem, | 1487 ClassElement classElem, |
| (...skipping 3714 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5133 } | 5202 } |
| 5134 | 5203 |
| 5135 bool isLibraryPrefix(Expression node) => | 5204 bool isLibraryPrefix(Expression node) => |
| 5136 node is SimpleIdentifier && node.staticElement is PrefixElement; | 5205 node is SimpleIdentifier && node.staticElement is PrefixElement; |
| 5137 | 5206 |
| 5138 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 5207 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
| 5139 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 5208 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
| 5140 | 5209 |
| 5141 bool _isDartRuntime(LibraryElement l) => | 5210 bool _isDartRuntime(LibraryElement l) => |
| 5142 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 5211 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
| OLD | NEW |