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 | 6 |
7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 7 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
8 import 'package:analyzer/dart/ast/ast.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/dart/ast/ast.dart' hide ConstantEvaluator; |
9 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 9 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
10 import 'package:analyzer/dart/element/element.dart'; | 10 import 'package:analyzer/dart/element/element.dart'; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 Expression _cascadeTarget; | 74 Expression _cascadeTarget; |
75 | 75 |
76 /// The variable for the current catch clause | 76 /// The variable for the current catch clause |
77 SimpleIdentifier _catchParameter; | 77 SimpleIdentifier _catchParameter; |
78 | 78 |
79 /// In an async* function, this represents the stream controller parameter. | 79 /// In an async* function, this represents the stream controller parameter. |
80 JS.TemporaryId _asyncStarController; | 80 JS.TemporaryId _asyncStarController; |
81 | 81 |
82 final _privateNames = | 82 final _privateNames = |
83 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); | 83 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); |
84 final _virtualFields = new HashMap<VariableDeclaration, JS.TemporaryId>(); | |
Jennifer Messerly
2016/04/25 22:47:04
Generally we don't use AST nodes as hash keys. Sho
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
85 final _virtualFieldSymbols = new HashMap<ClassElement, List<JS.Statement>>(); | |
Jennifer Messerly
2016/04/25 22:47:04
do we need this map? could we simply keep a List<J
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
84 final _initializingFormalTemps = | 86 final _initializingFormalTemps = |
85 new HashMap<ParameterElement, JS.TemporaryId>(); | 87 new HashMap<ParameterElement, JS.TemporaryId>(); |
86 | 88 |
87 final _dartxVar = new JS.Identifier('dartx'); | 89 final _dartxVar = new JS.Identifier('dartx'); |
88 final _runtimeLibVar = new JS.Identifier('dart'); | 90 final _runtimeLibVar = new JS.Identifier('dart'); |
89 final namedArgumentTemp = new JS.TemporaryId('opts'); | 91 final namedArgumentTemp = new JS.TemporaryId('opts'); |
90 | 92 |
91 final _hasDeferredSupertype = new HashSet<ClassElement>(); | 93 final _hasDeferredSupertype = new HashSet<ClassElement>(); |
92 | 94 |
93 /// The type provider from the current Analysis [context]. | 95 /// The type provider from the current Analysis [context]. |
(...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
524 for (var member in node.members) { | 526 for (var member in node.members) { |
525 if (member is ConstructorDeclaration) { | 527 if (member is ConstructorDeclaration) { |
526 ctors.add(member); | 528 ctors.add(member); |
527 } else if (member is FieldDeclaration) { | 529 } else if (member is FieldDeclaration) { |
528 (member.isStatic ? staticFields : fields).add(member); | 530 (member.isStatic ? staticFields : fields).add(member); |
529 } else if (member is MethodDeclaration) { | 531 } else if (member is MethodDeclaration) { |
530 methods.add(member); | 532 methods.add(member); |
531 } | 533 } |
532 } | 534 } |
533 | 535 |
536 JS.Expression className; | |
537 if (classElem.typeParameters.isNotEmpty) { | |
538 className = new JS.Identifier(classElem.name); | |
Jennifer Messerly
2016/04/25 22:47:04
there was a comment below:
"// Generic classes wil
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
539 } else { | |
540 className = _emitTopLevelName(classElem); | |
541 } | |
542 | |
534 var allFields = new List.from(fields)..addAll(staticFields); | 543 var allFields = new List.from(fields)..addAll(staticFields); |
535 var classExpr = _emitClassExpression( | 544 var classExpr = _emitClassExpression( |
536 classElem, _emitClassMethods(node, ctors, fields), | 545 classElem, _emitClassMethods(node, ctors, fields, className, classElem), |
537 fields: allFields); | 546 fields: allFields); |
538 | 547 |
539 var body = <JS.Statement>[]; | 548 var body = <JS.Statement>[]; |
540 var extensions = _extensionsToImplement(classElem); | 549 var extensions = _extensionsToImplement(classElem); |
541 _initExtensionSymbols(classElem, methods, fields, body); | 550 _initExtensionSymbols(classElem, methods, fields, body); |
542 | 551 |
543 // Emit the class, e.g. `core.Object = class Object { ... }` | 552 // Emit the class, e.g. `core.Object = class Object { ... }` |
544 JS.Expression className = _defineClass(classElem, classExpr, body); | 553 _defineClass(classElem, className, classExpr, body); |
545 | 554 |
546 // Emit things that come after the ES6 `class ... { ... }`. | 555 // Emit things that come after the ES6 `class ... { ... }`. |
547 _setBaseClass(classElem, className, body); | 556 _setBaseClass(classElem, className, body); |
548 _defineNamedConstructors(ctors, body, className); | 557 _defineNamedConstructors(ctors, body, className); |
549 _emitVirtualFields(classElem, fields, className, body); | 558 _emitVirtualFieldSymbols(classElem, body); |
550 _emitClassSignature(methods, classElem, ctors, extensions, className, body); | 559 _emitClassSignature(methods, classElem, ctors, extensions, className, body); |
551 _defineExtensionMembers(extensions, className, body); | 560 _defineExtensionMembers(extensions, className, body); |
552 _emitClassMetadata(node.metadata, className, body); | 561 _emitClassMetadata(node.metadata, className, body); |
553 | 562 |
554 JS.Statement classDef = _statement(body); | 563 JS.Statement classDef = _statement(body); |
555 var typeFormals = classElem.typeParameters; | 564 var typeFormals = classElem.typeParameters; |
556 if (typeFormals.isNotEmpty) { | 565 if (typeFormals.isNotEmpty) { |
557 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef); | 566 classDef = _defineClassTypeArguments(classElem, typeFormals, classDef); |
558 } | 567 } |
559 | 568 |
560 body = <JS.Statement>[classDef]; | 569 body = <JS.Statement>[classDef]; |
561 _emitStaticFields(staticFields, classElem, body); | 570 _emitStaticFields(staticFields, classElem, body); |
562 _registerExtensionType(classElem, body); | 571 _registerExtensionType(classElem, body); |
563 return _statement(body); | 572 return _statement(body); |
564 } | 573 } |
565 | 574 |
566 JS.Expression _defineClass(ClassElement classElem, | 575 void _defineClass(ClassElement classElem, JS.Expression className, |
567 JS.ClassExpression classExpr, List<JS.Statement> body) { | 576 JS.ClassExpression classExpr, List<JS.Statement> body) { |
568 JS.Expression className; | |
569 if (classElem.typeParameters.isNotEmpty) { | 577 if (classElem.typeParameters.isNotEmpty) { |
570 // Generic classes will be defined inside a function that closes over the | 578 // Generic classes will be defined inside a function that closes over the |
571 // type parameter. So we can use their local variable name directly. | 579 // type parameter. So we can use their local variable name directly. |
572 className = classExpr.name; | |
573 body.add(new JS.ClassDeclaration(classExpr)); | 580 body.add(new JS.ClassDeclaration(classExpr)); |
574 } else { | 581 } else { |
575 className = _emitTopLevelName(classElem); | |
576 body.add(js.statement('# = #;', [className, classExpr])); | 582 body.add(js.statement('# = #;', [className, classExpr])); |
577 } | 583 } |
578 return className; | 584 } |
585 | |
586 void _emitVirtualFieldSymbols(ClassElement elem, List<JS.Statement> body) { | |
587 if (_virtualFieldSymbols[elem] == null) return; | |
588 body.addAll(_virtualFieldSymbols[elem]); | |
579 } | 589 } |
580 | 590 |
581 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) { | 591 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) { |
582 return typeFormals | 592 return typeFormals |
583 .map((t) => new JS.Identifier(t.name)) | 593 .map((t) => new JS.Identifier(t.name)) |
584 .toList(growable: false); | 594 .toList(growable: false); |
585 } | 595 } |
586 | 596 |
587 /// Emits a field declaration for TypeScript & Closure's ES6_TYPED | 597 /// Emits a field declaration for TypeScript & Closure's ES6_TYPED |
588 /// (e.g. `class Foo { i: string; }`) | 598 /// (e.g. `class Foo { i: string; }`) |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
745 [value], js.statement('{ this.# = #; }', [name, value])); | 755 [value], js.statement('{ this.# = #; }', [name, value])); |
746 method = new JS.Method(_elementMemberName(field.setter), fn, | 756 method = new JS.Method(_elementMemberName(field.setter), fn, |
747 isSetter: true); | 757 isSetter: true); |
748 jsMethods.add(method); | 758 jsMethods.add(method); |
749 } | 759 } |
750 } | 760 } |
751 } | 761 } |
752 return jsMethods; | 762 return jsMethods; |
753 } | 763 } |
754 | 764 |
755 List<JS.Method> _emitClassMethods(ClassDeclaration node, | 765 List<JS.Method> _emitClassMethods( |
756 List<ConstructorDeclaration> ctors, List<FieldDeclaration> fields) { | 766 ClassDeclaration node, |
767 List<ConstructorDeclaration> ctors, | |
768 List<FieldDeclaration> fields, | |
769 JS.Expression className, | |
770 ClassElement classElem) { | |
Jennifer Messerly
2016/04/25 22:47:04
This parameter isn't needed.
See the very next li
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
757 var element = node.element; | 771 var element = node.element; |
758 var type = element.type; | 772 var type = element.type; |
759 var isObject = type.isObject; | 773 var isObject = type.isObject; |
760 | 774 |
761 // Iff no constructor is specified for a class C, it implicitly has a | 775 // Iff no constructor is specified for a class C, it implicitly has a |
762 // default constructor `C() : super() {}`, unless C is class Object. | 776 // default constructor `C() : super() {}`, unless C is class Object. |
763 var jsMethods = <JS.Method>[]; | 777 var jsMethods = <JS.Method>[]; |
764 if (ctors.isEmpty && !isObject) { | 778 if (ctors.isEmpty && !isObject) { |
765 jsMethods.add(_emitImplicitConstructor(node, fields)); | 779 jsMethods.add(_emitImplicitConstructor(node, fields)); |
766 } | 780 } |
767 | 781 |
768 bool hasJsPeer = findAnnotation(element, isJsPeerInterface) != null; | 782 bool hasJsPeer = findAnnotation(element, isJsPeerInterface) != null; |
769 var superclasses = getSuperclasses(element); | 783 var superclasses = getSuperclasses(element); |
770 | 784 |
771 bool hasIterator = false; | 785 bool hasIterator = false; |
772 for (var m in node.members) { | 786 for (var m in node.members) { |
773 if (m is ConstructorDeclaration) { | 787 if (m is ConstructorDeclaration) { |
774 jsMethods.add(_emitConstructor(m, type, fields, isObject)); | 788 jsMethods.add(_emitConstructor(m, type, fields, isObject)); |
775 } else if (m is MethodDeclaration) { | 789 } else if (m is MethodDeclaration) { |
776 jsMethods.add(_emitMethodDeclaration(type, m)); | 790 jsMethods.add(_emitMethodDeclaration(type, m)); |
777 | 791 |
778 if (m.element is PropertyAccessorElement) { | 792 if (m.element is PropertyAccessorElement) { |
779 jsMethods.add(_emitSuperAccessorWrapper(m, type, superclasses)); | 793 jsMethods.add(_emitSuperAccessorWrapper(m, type, superclasses)); |
780 } | 794 } |
781 | 795 |
782 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { | 796 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { |
783 hasIterator = true; | 797 hasIterator = true; |
784 jsMethods.add(_emitIterable(type)); | 798 jsMethods.add(_emitIterable(type)); |
785 } | 799 } |
786 } else if (m is FieldDeclaration && _extensionTypes.contains(element)) { | 800 } else if (m is FieldDeclaration) { |
787 jsMethods.addAll(_emitNativeFieldAccessors(m)); | 801 if (_extensionTypes.contains(element)) { |
802 jsMethods.addAll(_emitNativeFieldAccessors(m)); | |
803 continue; | |
804 } | |
805 if (m.isStatic) continue; | |
806 for (VariableDeclaration field in m.fields.variables) { | |
807 var propertyOverrideResult = checkForPropertyOverride( | |
808 field.element, superclasses, _extensionTypes); | |
809 if (propertyOverrideResult.foundGetter || | |
Jennifer Messerly
2016/04/25 22:47:04
consider: a shorter name here.
"overrideInfo" or
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
810 propertyOverrideResult.foundSetter) { | |
811 jsMethods.addAll( | |
812 _emitVirtualFieldAccessor(field, type, className, classElem)); | |
Jennifer Messerly
2016/04/25 22:47:04
fyi -- you probably don't need to pass classElem o
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
813 } | |
814 } | |
788 } | 815 } |
789 } | 816 } |
790 | 817 |
791 // If the type doesn't have an `iterator`, but claims to implement Iterable, | 818 // If the type doesn't have an `iterator`, but claims to implement Iterable, |
792 // we inject the adaptor method here, as it's less code size to put the | 819 // we inject the adaptor method here, as it's less code size to put the |
793 // helper on a parent class. This pattern is common in the core libraries | 820 // helper on a parent class. This pattern is common in the core libraries |
794 // (e.g. IterableMixin<E> and IterableBase<E>). | 821 // (e.g. IterableMixin<E> and IterableBase<E>). |
795 // | 822 // |
796 // (We could do this same optimization for any interface with an `iterator` | 823 // (We could do this same optimization for any interface with an `iterator` |
797 // method, but that's more expensive to check for, so it doesn't seem worth | 824 // method, but that's more expensive to check for, so it doesn't seem worth |
798 // it. The above case for an explicit `iterator` method will catch those.) | 825 // it. The above case for an explicit `iterator` method will catch those.) |
799 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { | 826 if (!hasJsPeer && !hasIterator && _implementsIterable(type)) { |
800 jsMethods.add(_emitIterable(type)); | 827 jsMethods.add(_emitIterable(type)); |
801 } | 828 } |
802 | 829 |
803 return jsMethods.where((m) => m != null).toList(growable: false); | 830 return jsMethods.where((m) => m != null).toList(growable: false); |
804 } | 831 } |
805 | 832 |
833 /// This is called whenever a derived class needs to introduce a new field, | |
834 /// shadowing a field or getter/setter pair on its parent. | |
835 /// | |
836 /// This is important because otherwise, trying to read or write the field | |
837 /// would end up calling the getter or setter, and one of those might not even | |
838 /// exist, resulting in a runtime error. Even if they did exist, that's the | |
839 /// wrong behavior if a new field was declared. | |
840 List<JS.Method> _emitVirtualFieldAccessor(VariableDeclaration field, | |
841 InterfaceType type, JS.Expression className, ClassElement classElem) { | |
842 var virtualField = _emitVirtualFieldSymbol(field, className, classElem); | |
843 var result = <JS.Method>[]; | |
844 var name = _emitMemberName(field.element.name, type: type); | |
845 var getter = js.call('function() { return this[#]; }', [virtualField]); | |
846 result.add(new JS.Method(name, getter, isGetter: true)); | |
847 | |
848 if (field.isFinal) { | |
849 var setter = js.call( | |
850 'function(value) {' | |
Jennifer Messerly
2016/04/25 22:47:04
style comment: triple quote style is nicer for the
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
851 ' var f = this[#];' | |
852 ' if (f === undefined) {' | |
Jennifer Messerly
2016/04/25 22:47:04
Hmmmm, I'm a little confused about what's going on
Harry Terkelsen
2016/04/26 18:29:27
Done.
| |
853 ' this[#] = value;' | |
854 ' } else {' | |
855 ' super[#] = value;' | |
856 ' }' | |
857 '}', | |
858 [virtualField, virtualField, name]); | |
859 result.add(new JS.Method(name, setter, isSetter: true)); | |
860 } else { | |
861 var setter = | |
862 js.call('function(value) { this[#] = value; }', [virtualField]); | |
863 result.add(new JS.Method(name, setter, isSetter: true)); | |
864 } | |
865 | |
866 return result; | |
867 } | |
868 | |
869 /// Emit a getter or setter that simply forwards to the superclass getter or | |
870 /// setter. This is needed because in ES6, if you only override a getter | |
871 /// (alternatively, a setter), then there is an implicit override of the | |
872 /// setter (alternatively, the getter) that does nothing. | |
806 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method, | 873 JS.Method _emitSuperAccessorWrapper(MethodDeclaration method, |
807 InterfaceType type, List<ClassElement> superclasses) { | 874 InterfaceType type, List<ClassElement> superclasses) { |
808 var methodElement = method.element as PropertyAccessorElement; | 875 var methodElement = method.element as PropertyAccessorElement; |
809 var field = methodElement.variable; | 876 var field = methodElement.variable; |
810 if (!field.isSynthetic) return null; | 877 if (!field.isSynthetic) return null; |
811 var propertyOverrideResult = checkForPropertyOverride( | 878 var propertyOverrideResult = checkForPropertyOverride( |
812 methodElement.variable, superclasses, _extensionTypes); | 879 methodElement.variable, superclasses, _extensionTypes); |
813 | 880 |
814 // Generate a corresponding virtual getter / setter. | 881 // Generate a corresponding virtual getter / setter. |
815 var name = _elementMemberName(methodElement, | 882 var name = _elementMemberName(methodElement, |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
904 newBaseClass = js.call('dart.global.#', [jsPeerName]); | 971 newBaseClass = js.call('dart.global.#', [jsPeerName]); |
905 } else if (_hasDeferredSupertype.contains(classElem)) { | 972 } else if (_hasDeferredSupertype.contains(classElem)) { |
906 newBaseClass = _emitTypeName(classElem.type.superclass); | 973 newBaseClass = _emitTypeName(classElem.type.superclass); |
907 } | 974 } |
908 if (newBaseClass != null) { | 975 if (newBaseClass != null) { |
909 body.add( | 976 body.add( |
910 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass])); | 977 js.statement('dart.setBaseClass(#, #);', [className, newBaseClass])); |
911 } | 978 } |
912 } | 979 } |
913 | 980 |
914 /// Emits instance fields, if they are virtual | |
915 /// (in other words, they override a getter/setter pair). | |
916 void _emitVirtualFields( | |
917 ClassElement classElement, | |
918 List<FieldDeclaration> fields, | |
919 JS.Expression className, | |
920 List<JS.Statement> body) { | |
921 List<ClassElement> superclasses = getSuperclasses(classElement); | |
922 for (FieldDeclaration member in fields) { | |
923 for (VariableDeclaration field in member.fields.variables) { | |
924 var propertyOverrideResult = checkForPropertyOverride( | |
925 field.element, superclasses, _extensionTypes); | |
926 if (propertyOverrideResult.foundGetter || | |
927 propertyOverrideResult.foundSetter) { | |
928 body.add(_overrideField(className, field.element)); | |
929 } | |
930 } | |
931 } | |
932 } | |
933 | |
934 void _defineNamedConstructors(List<ConstructorDeclaration> ctors, | 981 void _defineNamedConstructors(List<ConstructorDeclaration> ctors, |
935 List<JS.Statement> body, JS.Expression className) { | 982 List<JS.Statement> body, JS.Expression className) { |
936 for (ConstructorDeclaration member in ctors) { | 983 for (ConstructorDeclaration member in ctors) { |
937 if (member.name != null && member.factoryKeyword == null) { | 984 if (member.name != null && member.factoryKeyword == null) { |
938 body.add(js.statement('dart.defineNamedConstructor(#, #);', | 985 body.add(js.statement('dart.defineNamedConstructor(#, #);', |
939 [className, _emitMemberName(member.name.name, isStatic: true)])); | 986 [className, _emitMemberName(member.name.name, isStatic: true)])); |
940 } | 987 } |
941 } | 988 } |
942 } | 989 } |
943 | 990 |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1130 if (_extensionTypes.contains(element)) types.add(element); | 1177 if (_extensionTypes.contains(element)) types.add(element); |
1131 for (var m in type.mixins.reversed) { | 1178 for (var m in type.mixins.reversed) { |
1132 _collectExtensions(m, types); | 1179 _collectExtensions(m, types); |
1133 } | 1180 } |
1134 for (var i in type.interfaces) { | 1181 for (var i in type.interfaces) { |
1135 _collectExtensions(i, types); | 1182 _collectExtensions(i, types); |
1136 } | 1183 } |
1137 _collectExtensions(type.superclass, types); | 1184 _collectExtensions(type.superclass, types); |
1138 } | 1185 } |
1139 | 1186 |
1140 JS.Statement _overrideField(JS.Expression className, FieldElement e) { | |
1141 var cls = e.enclosingElement; | |
1142 return js.statement('dart.virtualField(#, #)', | |
1143 [className, _emitMemberName(e.name, type: cls.type)]); | |
1144 } | |
1145 | |
1146 /// Generates the implicit default constructor for class C of the form | 1187 /// Generates the implicit default constructor for class C of the form |
1147 /// `C() : super() {}`. | 1188 /// `C() : super() {}`. |
1148 JS.Method _emitImplicitConstructor( | 1189 JS.Method _emitImplicitConstructor( |
1149 ClassDeclaration node, List<FieldDeclaration> fields) { | 1190 ClassDeclaration node, List<FieldDeclaration> fields) { |
1150 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty); | 1191 assert(_hasUnnamedConstructor(node.element) == fields.isNotEmpty); |
1151 | 1192 |
1152 // If we don't have a method body, skip this. | 1193 // If we don't have a method body, skip this. |
1153 var superCall = _superConstructorCall(node.element); | 1194 var superCall = _superConstructorCall(node.element); |
1154 if (fields.isEmpty && superCall == null) return null; | 1195 if (fields.isEmpty && superCall == null) return null; |
1155 | 1196 |
(...skipping 2510 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3666 return _privateNames | 3707 return _privateNames |
3667 .putIfAbsent(library, () => new HashMap()) | 3708 .putIfAbsent(library, () => new HashMap()) |
3668 .putIfAbsent(name, () { | 3709 .putIfAbsent(name, () { |
3669 var id = new JS.TemporaryId(name); | 3710 var id = new JS.TemporaryId(name); |
3670 _moduleItems.add( | 3711 _moduleItems.add( |
3671 js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")])); | 3712 js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")])); |
3672 return id; | 3713 return id; |
3673 }); | 3714 }); |
3674 } | 3715 } |
3675 | 3716 |
3717 JS.TemporaryId _emitVirtualFieldSymbol(VariableDeclaration field, | |
3718 JS.Expression className, ClassElement classElem) { | |
3719 return _virtualFields.putIfAbsent(field, () { | |
3720 var fieldName = _emitMemberName(field.element.name, | |
3721 type: (field.element.enclosingElement as ClassElement).type); | |
3722 var id = new JS.TemporaryId(field.name.name); | |
3723 _virtualFieldSymbols.putIfAbsent(classElem, () => <JS.Statement>[]).add(js | |
3724 .statement('const # = Symbol(#.name + "." + #.toString());', | |
3725 [id, className, fieldName])); | |
3726 return id; | |
3727 }); | |
3728 } | |
3729 | |
3676 bool _externalOrNative(node) => | 3730 bool _externalOrNative(node) => |
3677 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; | 3731 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; |
3678 | 3732 |
3679 FunctionBody _functionBody(node) => | 3733 FunctionBody _functionBody(node) => |
3680 node is FunctionDeclaration ? node.functionExpression.body : node.body; | 3734 node is FunctionDeclaration ? node.functionExpression.body : node.body; |
3681 | 3735 |
3682 /// Returns the canonical name to refer to the Dart library. | 3736 /// Returns the canonical name to refer to the Dart library. |
3683 JS.Identifier emitLibraryName(LibraryElement library) { | 3737 JS.Identifier emitLibraryName(LibraryElement library) { |
3684 // It's either one of the libraries in this module, or it's an import. | 3738 // It's either one of the libraries in this module, or it's an import. |
3685 return _libraries[library] ?? | 3739 return _libraries[library] ?? |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3788 } | 3842 } |
3789 | 3843 |
3790 bool isLibraryPrefix(Expression node) => | 3844 bool isLibraryPrefix(Expression node) => |
3791 node is SimpleIdentifier && node.staticElement is PrefixElement; | 3845 node is SimpleIdentifier && node.staticElement is PrefixElement; |
3792 | 3846 |
3793 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 3847 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
3794 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 3848 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
3795 | 3849 |
3796 bool _isDartRuntime(LibraryElement l) => | 3850 bool _isDartRuntime(LibraryElement l) => |
3797 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 3851 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
OLD | NEW |