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 781 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
792 // TODO(jmesserly): if the type fails to resolve, should we generate code | 792 // TODO(jmesserly): if the type fails to resolve, should we generate code |
793 // that throws instead? | 793 // that throws instead? |
794 assert(options.unsafeForceCompile || options.replCompile); | 794 assert(options.unsafeForceCompile || options.replCompile); |
795 return _callHelper('dynamic'); | 795 return _callHelper('dynamic'); |
796 } | 796 } |
797 return _emitType(node.type); | 797 return _emitType(node.type); |
798 } | 798 } |
799 | 799 |
800 @override | 800 @override |
801 JS.Statement visitClassTypeAlias(ClassTypeAlias node) { | 801 JS.Statement visitClassTypeAlias(ClassTypeAlias node) { |
802 ClassElement element = node.element; | 802 ClassElement classElem = node.element; |
803 var supertype = element.supertype; | 803 var supertype = classElem.supertype; |
804 | 804 |
805 // Forward all generative constructors from the base class. | 805 var typeFormals = classElem.typeParameters; |
806 var methods = <JS.Method>[]; | 806 var isGeneric = typeFormals.isNotEmpty; |
807 if (!supertype.isObject) { | 807 |
808 for (var ctor in element.constructors) { | 808 // Special case where supertype is Object, and we mixin a single class. |
809 var parentCtor = supertype.lookUpConstructor(ctor.name, ctor.library); | 809 // The resulting 'class' is a mixable class in this case. |
810 // TODO(jmesserly): this avoids spread args for perf. Revisit. | 810 bool isMixinAlias = supertype.isObject && classElem.mixins.length == 1; |
811 var jsParams = <JS.Identifier>[]; | 811 |
812 for (var p in ctor.parameters) { | 812 var classExpr = isMixinAlias |
813 if (p.parameterKind != ParameterKind.NAMED) { | 813 ? _emitClassHeritage(classElem) |
814 jsParams.add(new JS.Identifier(p.name)); | 814 : _emitClassExpression(classElem, []); |
815 } else { | 815 var className = isGeneric |
816 jsParams.add(new JS.TemporaryId('namedArgs')); | 816 ? new JS.Identifier(classElem.name) |
817 break; | 817 : _emitTopLevelName(classElem); |
818 } | 818 var block = <JS.Statement>[]; |
819 } | 819 |
820 var fun = js.call('function(#) { super.#(#); }', | 820 if (isGeneric) { |
821 [jsParams, _constructorName(parentCtor), jsParams]) as JS.Fun; | 821 if (isMixinAlias) { |
822 methods.add(new JS.Method(_constructorName(ctor), fun)); | 822 block.add(js.statement('const # = #;', [className, classExpr])); |
| 823 } else { |
| 824 block.add(new JS.ClassDeclaration(classExpr)); |
823 } | 825 } |
| 826 } else { |
| 827 block.add(js.statement('# = #;', [className, classExpr])); |
824 } | 828 } |
825 | 829 |
826 var typeFormals = element.typeParameters; | 830 if (!isMixinAlias) _defineConstructors(classElem, className, [], block, []); |
827 var isGeneric = typeFormals.isNotEmpty; | 831 |
828 var className = isGeneric ? element.name : _emitTopLevelName(element); | 832 if (classElem.interfaces.isNotEmpty) { |
829 JS.Statement declareInterfaces(JS.Statement decl) { | 833 block.add(js.statement('#[#.implements] = () => #;', [ |
830 if (element.interfaces.isNotEmpty) { | 834 className, |
831 var body = [decl]..add(js.statement('#[#.implements] = () => #;', [ | 835 _runtimeModule, |
832 className, | 836 new JS.ArrayInitializer(classElem.interfaces.map(_emitType).toList()) |
833 _runtimeModule, | 837 ])); |
834 new JS.ArrayInitializer( | |
835 new List<JS.Expression>.from(element.interfaces.map(_emitType))) | |
836 ])); | |
837 decl = _statement(body); | |
838 } | |
839 return decl; | |
840 } | 838 } |
841 | 839 |
842 if (supertype.isObject && element.mixins.length == 1) { | 840 if (isGeneric) { |
843 // Special case where supertype is Object, and we mixin a single class. | 841 return _defineClassTypeArguments( |
844 // The resulting 'class' is a mixable class in this case. | 842 classElem, typeFormals, _statement(block)); |
845 var classExpr = _emitClassHeritage(element); | |
846 if (isGeneric) { | |
847 var classStmt = js.statement('const # = #;', [className, classExpr]); | |
848 return _defineClassTypeArguments( | |
849 element, typeFormals, declareInterfaces(classStmt)); | |
850 } else { | |
851 var classStmt = js.statement('# = #;', [className, classExpr]); | |
852 return declareInterfaces(classStmt); | |
853 } | |
854 } | 843 } |
855 | 844 return _statement(block); |
856 var classExpr = _emitClassExpression(element, methods); | |
857 if (isGeneric) { | |
858 var classStmt = new JS.ClassDeclaration(classExpr); | |
859 return _defineClassTypeArguments( | |
860 element, typeFormals, declareInterfaces(classStmt)); | |
861 } else { | |
862 var classStmt = js.statement('# = #;', [className, classExpr]); | |
863 return declareInterfaces(classStmt); | |
864 } | |
865 } | 845 } |
866 | 846 |
867 JS.Statement _emitJsType(Element e) { | 847 JS.Statement _emitJsType(Element e) { |
868 var jsTypeName = getAnnotationName(e, isJSAnnotation); | 848 var jsTypeName = getAnnotationName(e, isJSAnnotation); |
869 if (jsTypeName == null || jsTypeName == e.name) return null; | 849 if (jsTypeName == null || jsTypeName == e.name) return null; |
870 | 850 |
871 // We export the JS type as if it was a Dart type. For example this allows | 851 // We export the JS type as if it was a Dart type. For example this allows |
872 // `dom.InputElement` to actually be HTMLInputElement. | 852 // `dom.InputElement` to actually be HTMLInputElement. |
873 // TODO(jmesserly): if we had the JS name on the Element, we could just | 853 // TODO(jmesserly): if we had the JS name on the Element, we could just |
874 // generate it correctly when we refer to it. | 854 // generate it correctly when we refer to it. |
(...skipping 10 matching lines...) Expand all Loading... |
885 // If this is a JavaScript type, emit it now and then exit. | 865 // If this is a JavaScript type, emit it now and then exit. |
886 var jsTypeDef = _emitJsType(classElem); | 866 var jsTypeDef = _emitJsType(classElem); |
887 if (jsTypeDef != null) return jsTypeDef; | 867 if (jsTypeDef != null) return jsTypeDef; |
888 | 868 |
889 var ctors = <ConstructorDeclaration>[]; | 869 var ctors = <ConstructorDeclaration>[]; |
890 var allFields = <FieldDeclaration>[]; | 870 var allFields = <FieldDeclaration>[]; |
891 var fields = <FieldDeclaration>[]; | 871 var fields = <FieldDeclaration>[]; |
892 var staticFields = <FieldDeclaration>[]; | 872 var staticFields = <FieldDeclaration>[]; |
893 var methods = <MethodDeclaration>[]; | 873 var methods = <MethodDeclaration>[]; |
894 | 874 |
895 // True if a "call" method or getter exists directly on this class. | |
896 // If so, we need to install a Function prototype. | |
897 bool isCallable = false; | |
898 for (var member in node.members) { | 875 for (var member in node.members) { |
899 if (member is ConstructorDeclaration) { | 876 if (member is ConstructorDeclaration) { |
900 ctors.add(member); | 877 ctors.add(member); |
901 } else if (member is FieldDeclaration) { | 878 } else if (member is FieldDeclaration) { |
902 allFields.add(member); | 879 allFields.add(member); |
903 (member.isStatic ? staticFields : fields).add(member); | 880 (member.isStatic ? staticFields : fields).add(member); |
904 } else if (member is MethodDeclaration) { | 881 } else if (member is MethodDeclaration) { |
905 methods.add(member); | 882 methods.add(member); |
906 if (member.name.name == 'call' && !member.isSetter) { | |
907 // | |
908 // Make sure "call" has a statically known function type: | |
909 // | |
910 // - if it's a method, then it does because all methods do, | |
911 // - if it's a getter, check the return type. | |
912 // | |
913 // Other cases like a getter returning dynamic/Object/Function will be | |
914 // handled at runtime by the dynamic call mechanism. So we only | |
915 // concern ourselves with statically known function types. | |
916 // | |
917 // For the same reason, we can ignore "noSuchMethod". | |
918 // call-implemented-by-nSM will be dispatched by dcall at runtime. | |
919 // | |
920 isCallable = !member.isGetter || member.returnType is FunctionType; | |
921 } | |
922 } | 883 } |
923 } | 884 } |
924 | 885 |
925 // True if a "call" method or getter exists directly or indirectly on this | |
926 // class. If so, we need special constructor handling. | |
927 bool isCallableTransitive = | |
928 classElem.lookUpMethod('call', currentLibrary) != null; | |
929 if (!isCallableTransitive) { | |
930 var callGetter = classElem.lookUpGetter('call', currentLibrary); | |
931 isCallableTransitive = | |
932 callGetter != null && callGetter.returnType is FunctionType; | |
933 } | |
934 | |
935 JS.Expression className; | 886 JS.Expression className; |
936 if (classElem.typeParameters.isNotEmpty) { | 887 if (classElem.typeParameters.isNotEmpty) { |
937 // Generic classes will be defined inside a function that closes over the | 888 // Generic classes will be defined inside a function that closes over the |
938 // type parameter. So we can use their local variable name directly. | 889 // type parameter. So we can use their local variable name directly. |
939 className = new JS.Identifier(classElem.name); | 890 className = new JS.Identifier(classElem.name); |
940 } else { | 891 } else { |
941 className = _emitTopLevelName(classElem); | 892 className = _emitTopLevelName(classElem); |
942 } | 893 } |
943 | 894 |
944 var savedClassProperties = _classProperties; | 895 var savedClassProperties = _classProperties; |
945 _classProperties = | 896 _classProperties = |
946 new ClassPropertyModel.build(_extensionTypes, virtualFields, classElem); | 897 new ClassPropertyModel.build(_extensionTypes, virtualFields, classElem); |
947 | 898 |
948 var classExpr = _emitClassExpression( | 899 var classExpr = _emitClassExpression(classElem, _emitClassMethods(node), |
949 classElem, _emitClassMethods(node, ctors, fields), | |
950 fields: allFields); | 900 fields: allFields); |
951 | 901 |
952 var body = <JS.Statement>[]; | 902 var body = <JS.Statement>[]; |
953 _initExtensionSymbols(classElem, methods, fields, body); | 903 _initExtensionSymbols(classElem, methods, fields, body); |
954 _emitSuperHelperSymbols(_superHelperSymbols, body); | 904 _emitSuperHelperSymbols(_superHelperSymbols, body); |
955 | 905 |
956 // Emit the class, e.g. `core.Object = class Object { ... }` | 906 // Emit the class, e.g. `core.Object = class Object { ... }` |
957 _defineClass(classElem, className, classExpr, isCallable, body); | 907 _defineClass(classElem, className, classExpr, body); |
| 908 _defineConstructors(classElem, className, fields, body, ctors); |
958 | 909 |
959 // Emit things that come after the ES6 `class ... { ... }`. | 910 // Emit things that come after the ES6 `class ... { ... }`. |
960 var jsPeerNames = _getJSPeerNames(classElem); | 911 var jsPeerNames = _getJSPeerNames(classElem); |
961 JS.Statement deferredBaseClass = | 912 JS.Statement deferredBaseClass = |
962 _setBaseClass(classElem, className, jsPeerNames, body); | 913 _setBaseClass(classElem, className, jsPeerNames, body); |
963 | 914 |
964 _emitClassTypeTests(classElem, className, body); | 915 _emitClassTypeTests(classElem, className, body); |
965 | 916 |
966 _defineNamedConstructors(ctors, body, className, isCallableTransitive); | |
967 _emitVirtualFieldSymbols(classElem, body); | 917 _emitVirtualFieldSymbols(classElem, body); |
968 _emitClassSignature(methods, allFields, classElem, ctors, className, body); | 918 _emitClassSignature(methods, allFields, classElem, ctors, className, body); |
969 _defineExtensionMembers(className, body); | 919 _defineExtensionMembers(className, body); |
970 _emitClassMetadata(node.metadata, className, body); | 920 _emitClassMetadata(node.metadata, className, body); |
971 | 921 |
972 JS.Statement classDef = _statement(body); | 922 JS.Statement classDef = _statement(body); |
973 | 923 |
974 var typeFormals = classElem.typeParameters; | 924 var typeFormals = classElem.typeParameters; |
975 if (typeFormals.isNotEmpty) { | 925 if (typeFormals.isNotEmpty) { |
976 classDef = _defineClassTypeArguments( | 926 classDef = _defineClassTypeArguments( |
977 classElem, typeFormals, classDef, className, deferredBaseClass); | 927 classElem, typeFormals, classDef, className, deferredBaseClass); |
978 } | 928 } |
979 | 929 |
980 body = <JS.Statement>[classDef]; | 930 body = <JS.Statement>[classDef]; |
981 _emitStaticFields(staticFields, classElem, body); | 931 _emitStaticFields(staticFields, classElem, body); |
982 for (var peer in jsPeerNames) { | 932 for (var peer in jsPeerNames) { |
983 _registerExtensionType(classElem, peer, body); | 933 _registerExtensionType(classElem, peer, body); |
984 } | 934 } |
985 | 935 |
986 _classProperties = savedClassProperties; | 936 _classProperties = savedClassProperties; |
987 return _statement(body); | 937 return _statement(body); |
988 } | 938 } |
989 | 939 |
990 /// Emits code to support a class with a "call" method and an unnamed | |
991 /// constructor. | |
992 /// | |
993 /// This ensures instances created by the unnamed constructor are functions. | |
994 /// Named constructors are handled elsewhere, see [_defineNamedConstructors]. | |
995 JS.Expression _emitCallableClass( | |
996 JS.ClassExpression classExpr, ConstructorElement unnamedCtor) { | |
997 var ctor = new JS.NamedFunction( | |
998 classExpr.name, _emitCallableClassConstructor(unnamedCtor)); | |
999 | |
1000 // Name the constructor function the same as the class. | |
1001 return _callHelper('callableClass(#, #)', [ctor, classExpr]); | |
1002 } | |
1003 | |
1004 /// Emits a constructor that ensures instances of this class are callable as | |
1005 /// functions in JavaScript. | |
1006 JS.Fun _emitCallableClassConstructor(ConstructorElement ctor) { | |
1007 return js.call( | |
1008 r'''function (...args) { | |
1009 function call(...args) { | |
1010 return call.call.apply(call, args); | |
1011 } | |
1012 call.__proto__ = this.__proto__; | |
1013 call.#.apply(call, args); | |
1014 return call; | |
1015 }''', | |
1016 [_constructorName(ctor)]); | |
1017 } | |
1018 | |
1019 void _emitClassTypeTests(ClassElement classElem, JS.Expression className, | 940 void _emitClassTypeTests(ClassElement classElem, JS.Expression className, |
1020 List<JS.Statement> body) { | 941 List<JS.Statement> body) { |
1021 if (classElem == objectClass) { | 942 if (classElem == objectClass) { |
1022 // We rely on ES6 static inheritance. All types that are represented by | 943 // We rely on ES6 static inheritance. All types that are represented by |
1023 // class constructor functions will see these definitions, with [this] | 944 // class constructor functions will see these definitions, with [this] |
1024 // being bound to the class constructor. | 945 // being bound to the class constructor. |
1025 | 946 |
1026 // The 'instanceof' checks don't work for primitive types (which have fast | 947 // The 'instanceof' checks don't work for primitive types (which have fast |
1027 // definitions below) and don't work for native types. In those cases we | 948 // definitions below) and don't work for native types. In those cases we |
1028 // fall through to the general purpose checking code. | 949 // fall through to the general purpose checking code. |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1222 | 1143 |
1223 void _emitVirtualFieldSymbols( | 1144 void _emitVirtualFieldSymbols( |
1224 ClassElement classElement, List<JS.Statement> body) { | 1145 ClassElement classElement, List<JS.Statement> body) { |
1225 _classProperties.virtualFields.forEach((field, virtualField) { | 1146 _classProperties.virtualFields.forEach((field, virtualField) { |
1226 body.add(js.statement('const # = Symbol(#);', | 1147 body.add(js.statement('const # = Symbol(#);', |
1227 [virtualField, js.string('${classElement.name}.${field.name}')])); | 1148 [virtualField, js.string('${classElement.name}.${field.name}')])); |
1228 }); | 1149 }); |
1229 } | 1150 } |
1230 | 1151 |
1231 void _defineClass(ClassElement classElem, JS.Expression className, | 1152 void _defineClass(ClassElement classElem, JS.Expression className, |
1232 JS.ClassExpression classExpr, bool isCallable, List<JS.Statement> body) { | 1153 JS.ClassExpression classExpr, List<JS.Statement> body) { |
1233 JS.Expression callableClass; | |
1234 if (isCallable && classElem.unnamedConstructor != null) { | |
1235 callableClass = | |
1236 _emitCallableClass(classExpr, classElem.unnamedConstructor); | |
1237 } | |
1238 | |
1239 if (classElem.typeParameters.isNotEmpty) { | 1154 if (classElem.typeParameters.isNotEmpty) { |
1240 if (callableClass != null) { | 1155 body.add(new JS.ClassDeclaration(classExpr)); |
1241 body.add(js.statement('const # = #;', [classExpr.name, callableClass])); | |
1242 } else { | |
1243 body.add(new JS.ClassDeclaration(classExpr)); | |
1244 } | |
1245 } else { | 1156 } else { |
1246 body.add(js.statement('# = #;', [className, callableClass ?? classExpr])); | 1157 body.add(js.statement('# = #;', [className, classExpr])); |
1247 } | 1158 } |
1248 } | 1159 } |
1249 | 1160 |
1250 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) { | 1161 List<JS.Identifier> _emitTypeFormals(List<TypeParameterElement> typeFormals) { |
1251 return typeFormals | 1162 return typeFormals |
1252 .map((t) => new JS.Identifier(t.name)) | 1163 .map((t) => new JS.Identifier(t.name)) |
1253 .toList(growable: false); | 1164 .toList(growable: false); |
1254 } | 1165 } |
1255 | 1166 |
1256 /// Emits a field declaration for TypeScript & Closure's ES6_TYPED | 1167 /// Emits a field declaration for TypeScript & Closure's ES6_TYPED |
(...skipping 14 matching lines...) Expand all Loading... |
1271 } | 1182 } |
1272 | 1183 |
1273 @override | 1184 @override |
1274 JS.Statement visitEnumDeclaration(EnumDeclaration node) { | 1185 JS.Statement visitEnumDeclaration(EnumDeclaration node) { |
1275 var element = resolutionMap.elementDeclaredByEnumDeclaration(node); | 1186 var element = resolutionMap.elementDeclaredByEnumDeclaration(node); |
1276 var type = element.type; | 1187 var type = element.type; |
1277 | 1188 |
1278 // Generate a class per section 13 of the spec. | 1189 // Generate a class per section 13 of the spec. |
1279 // TODO(vsm): Generate any accompanying metadata | 1190 // TODO(vsm): Generate any accompanying metadata |
1280 | 1191 |
1281 // Create constructor and initialize index | 1192 var fields = element.fields.where((f) => f.type == type).toList(); |
1282 var constructor = new JS.Method(_propertyName('new'), | |
1283 js.call('function(index) { this.index = index; }') as JS.Fun); | |
1284 var fields = new List<FieldElement>.from( | |
1285 element.fields.where((f) => f.type == type)); | |
1286 | 1193 |
1287 // Create toString() method | 1194 // Create toString() method |
1288 var nameProperties = new List<JS.Property>(fields.length); | 1195 var nameProperties = new List<JS.Property>(fields.length); |
1289 for (var i = 0; i < fields.length; ++i) { | 1196 for (var i = 0; i < fields.length; ++i) { |
1290 nameProperties[i] = new JS.Property( | 1197 nameProperties[i] = new JS.Property( |
1291 js.number(i), js.string('${type.name}.${fields[i].name}')); | 1198 js.number(i), js.string('${type.name}.${fields[i].name}')); |
1292 } | 1199 } |
1293 var nameMap = new JS.ObjectInitializer(nameProperties, multiline: true); | 1200 var nameMap = new JS.ObjectInitializer(nameProperties, multiline: true); |
1294 var toStringF = new JS.Method(js.string('toString'), | 1201 var toStringF = new JS.Method(js.string('toString'), |
1295 js.call('function() { return #[this.index]; }', nameMap) as JS.Fun); | 1202 js.call('function() { return #[this.index]; }', nameMap) as JS.Fun); |
1296 | 1203 |
1297 // Create enum class | 1204 // Create enum class |
1298 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), | 1205 var classExpr = new JS.ClassExpression( |
1299 _emitClassHeritage(element), [constructor, toStringF]); | 1206 new JS.Identifier(type.name), _emitClassHeritage(element), [toStringF]); |
1300 var id = _emitTopLevelName(element); | 1207 var id = _emitTopLevelName(element); |
1301 | 1208 |
1302 // Emit metadata for synthetic enum index member. | 1209 // Emit metadata for synthetic enum index member. |
1303 // TODO(jacobr): make field readonly when that is supported. | 1210 // TODO(jacobr): make field readonly when that is supported. |
1304 var tInstanceFields = <JS.Property>[ | 1211 var tInstanceFields = <JS.Property>[ |
1305 new JS.Property( | 1212 new JS.Property( |
1306 _emitMemberName('index'), _emitFieldSignature(types.intType)) | 1213 _emitMemberName('index'), _emitFieldSignature(types.intType)) |
1307 ]; | 1214 ]; |
1308 var sigFields = <JS.Property>[]; | 1215 var sigFields = <JS.Property>[]; |
1309 _buildSignatureField(sigFields, 'fields', tInstanceFields); | 1216 _buildSignatureField(sigFields, 'fields', tInstanceFields); |
1310 var sig = new JS.ObjectInitializer(sigFields); | 1217 var sig = new JS.ObjectInitializer(sigFields); |
1311 | 1218 |
1312 var result = [ | 1219 var result = [ |
1313 js.statement('# = #', [id, classExpr]), | 1220 js.statement('# = #', [id, classExpr]), |
| 1221 js.statement( |
| 1222 '(#.new = function(x) { this.index = x; }).prototype = #.prototype;', |
| 1223 [id, id]), |
1314 _callHelperStatement('setSignature(#, #);', [id, sig]) | 1224 _callHelperStatement('setSignature(#, #);', [id, sig]) |
1315 ]; | 1225 ]; |
1316 | 1226 |
1317 // defineEnumValues internally depends on dart.constList which uses | 1227 // defineEnumValues internally depends on dart.constList which uses |
1318 // _interceptors.JSArray. | 1228 // _interceptors.JSArray. |
1319 _declareBeforeUse(_jsArray); | 1229 _declareBeforeUse(_jsArray); |
1320 | 1230 |
1321 // Create static fields for each enum value, and the "values" getter | 1231 // Create static fields for each enum value, and the "values" getter |
1322 result.add(_callHelperStatement('defineEnumValues(#, #);', [ | 1232 result.add(_callHelperStatement('defineEnumValues(#, #);', [ |
1323 id, | 1233 id, |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1444 [value], js.statement('{ this.# = #; }', [name, value])); | 1354 [value], js.statement('{ this.# = #; }', [name, value])); |
1445 method = new JS.Method(_declareMemberName(field.setter), fn, | 1355 method = new JS.Method(_declareMemberName(field.setter), fn, |
1446 isSetter: true); | 1356 isSetter: true); |
1447 jsMethods.add(method); | 1357 jsMethods.add(method); |
1448 } | 1358 } |
1449 } | 1359 } |
1450 } | 1360 } |
1451 return jsMethods; | 1361 return jsMethods; |
1452 } | 1362 } |
1453 | 1363 |
1454 List<JS.Method> _emitClassMethods(ClassDeclaration node, | 1364 List<JS.Method> _emitClassMethods(ClassDeclaration node) { |
1455 List<ConstructorDeclaration> ctors, List<FieldDeclaration> fields) { | |
1456 var element = resolutionMap.elementDeclaredByClassDeclaration(node); | 1365 var element = resolutionMap.elementDeclaredByClassDeclaration(node); |
1457 var type = element.type; | 1366 var type = element.type; |
1458 var isObject = type.isObject; | |
1459 var virtualFields = _classProperties.virtualFields; | 1367 var virtualFields = _classProperties.virtualFields; |
1460 | 1368 |
1461 // Iff no constructor is specified for a class C, it implicitly has a | |
1462 // default constructor `C() : super() {}`, unless C is class Object. | |
1463 var jsMethods = <JS.Method>[]; | 1369 var jsMethods = <JS.Method>[]; |
1464 if (isObject) { | 1370 bool hasJsPeer = findAnnotation(element, isJsPeerInterface) != null; |
1465 // Implements Dart constructor behavior. | 1371 bool hasIterator = false; |
1466 // | 1372 |
1467 // Because of ES6 constructor restrictions (`this` is not available until | 1373 if (type.isObject) { |
1468 // `super` is called), we cannot emit an actual ES6 `constructor` on our | 1374 // Dart does not use ES6 constructors. |
1469 // classes and preserve the Dart initialization order. | 1375 // Add an error to catch any invalid usage. |
1470 // | |
1471 // Instead we use the same trick as named constructors, and do them as | |
1472 // instance methods that perform initialization. | |
1473 // | |
1474 // Therefore, dart:core Object gets the one real `constructor` and | |
1475 // immediately bounces to the `new() { ... }` initializer, letting us | |
1476 // bypass the ES6 restrictions. | |
1477 // | |
1478 // TODO(jmesserly): we'll need to rethink this. | |
1479 // See https://github.com/dart-lang/sdk/issues/28322. | |
1480 // This level of indirection will hurt performance. | |
1481 jsMethods.add(new JS.Method( | 1376 jsMethods.add(new JS.Method( |
1482 _propertyName('constructor'), | 1377 _propertyName('constructor'), |
1483 js.call('function(...args) { return this.new.apply(this, args); }') | 1378 js.call( |
1484 as JS.Fun)); | 1379 r'''function() { |
1485 } else if (ctors.isEmpty) { | 1380 throw Error("use `new " + #.typeName(#.getReifiedType(this)) + |
1486 jsMethods.add(_emitImplicitConstructor(node, fields, virtualFields)); | 1381 ".new(...)` to create a Dart object"); |
| 1382 }''', |
| 1383 [_runtimeModule, _runtimeModule]))); |
1487 } | 1384 } |
1488 | |
1489 bool hasJsPeer = findAnnotation(element, isJsPeerInterface) != null; | |
1490 | |
1491 bool hasIterator = false; | |
1492 for (var m in node.members) { | 1385 for (var m in node.members) { |
1493 if (m is ConstructorDeclaration) { | 1386 if (m is ConstructorDeclaration) { |
1494 jsMethods | 1387 if (m.factoryKeyword != null && !_externalOrNative(m)) { |
1495 .add(_emitConstructor(m, type, fields, virtualFields, isObject)); | 1388 jsMethods.add(_emitFactoryConstructor(m)); |
| 1389 } |
1496 } else if (m is MethodDeclaration) { | 1390 } else if (m is MethodDeclaration) { |
1497 jsMethods.add(_emitMethodDeclaration(type, m)); | 1391 jsMethods.add(_emitMethodDeclaration(type, m)); |
1498 | 1392 |
1499 if (m.element is PropertyAccessorElement) { | 1393 if (m.element is PropertyAccessorElement) { |
1500 jsMethods.add(_emitSuperAccessorWrapper(m, type)); | 1394 jsMethods.add(_emitSuperAccessorWrapper(m, type)); |
1501 } | 1395 } |
1502 | 1396 |
1503 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { | 1397 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { |
1504 hasIterator = true; | 1398 hasIterator = true; |
1505 jsMethods.add(_emitIterable(type)); | 1399 jsMethods.add(_emitIterable(type)); |
(...skipping 27 matching lines...) Expand all Loading... |
1533 jsMethods.add(_emitIterable(type)); | 1427 jsMethods.add(_emitIterable(type)); |
1534 } | 1428 } |
1535 | 1429 |
1536 // Add all of the super helper methods | 1430 // Add all of the super helper methods |
1537 jsMethods.addAll(_superHelpers); | 1431 jsMethods.addAll(_superHelpers); |
1538 _superHelpers.clear(); | 1432 _superHelpers.clear(); |
1539 | 1433 |
1540 return jsMethods.where((m) => m != null).toList(growable: false); | 1434 return jsMethods.where((m) => m != null).toList(growable: false); |
1541 } | 1435 } |
1542 | 1436 |
| 1437 /// Emits a Dart factory constructor to a JS static method. |
| 1438 JS.Method _emitFactoryConstructor(ConstructorDeclaration node) { |
| 1439 var element = node.element; |
| 1440 var returnType = emitTypeRef(element.returnType); |
| 1441 var name = _constructorName(element); |
| 1442 JS.Fun fun; |
| 1443 |
| 1444 var redirect = node.redirectedConstructor; |
| 1445 if (redirect != null) { |
| 1446 // Wacky factory redirecting constructors: factory Foo.q(x, y) = Bar.baz; |
| 1447 |
| 1448 var newKeyword = redirect.staticElement.isFactory ? '' : 'new'; |
| 1449 // Pass along all arguments verbatim, and let the callee handle them. |
| 1450 // TODO(jmesserly): we'll need something different once we have |
| 1451 // rest/spread support, but this should work for now. |
| 1452 var params = |
| 1453 _emitFormalParameterList(node.parameters, destructure: false); |
| 1454 |
| 1455 fun = new JS.Fun( |
| 1456 params, |
| 1457 js.statement( |
| 1458 '{ return $newKeyword #(#); }', [_visit(redirect), params]), |
| 1459 returnType: returnType); |
| 1460 } else { |
| 1461 // Normal factory constructor |
| 1462 var body = <JS.Statement>[]; |
| 1463 var init = _emitArgumentInitializers(node, constructor: true); |
| 1464 if (init != null) body.add(init); |
| 1465 body.add(_visit(node.body)); |
| 1466 |
| 1467 var params = _emitFormalParameterList(node.parameters); |
| 1468 fun = new JS.Fun(params, new JS.Block(body), returnType: returnType); |
| 1469 } |
| 1470 |
| 1471 return annotate(new JS.Method(name, fun, isStatic: true), node, element); |
| 1472 } |
| 1473 |
1543 /// Given a class C that implements method M from interface I, but does not | 1474 /// Given a class C that implements method M from interface I, but does not |
1544 /// declare M, this will generate an implementation that forwards to | 1475 /// declare M, this will generate an implementation that forwards to |
1545 /// noSuchMethod. | 1476 /// noSuchMethod. |
1546 /// | 1477 /// |
1547 /// For example: | 1478 /// For example: |
1548 /// | 1479 /// |
1549 /// class Cat { | 1480 /// class Cat { |
1550 /// bool eatFood(String food) => true; | 1481 /// bool eatFood(String food) => true; |
1551 /// } | 1482 /// } |
1552 /// class MockCat implements Cat { | 1483 /// class MockCat implements Cat { |
1553 /// noSuchMethod(Invocation invocation) => 3; | 1484 /// noSuchMethod(Invocation invocation) => 3; |
1554 /// } | 1485 /// } |
1555 /// | 1486 /// |
1556 /// It will generate an `eatFood` that looks like: | 1487 /// It will generate an `eatFood` that looks like: |
1557 /// | 1488 /// |
1558 /// eatFood(...args) { | 1489 /// eatFood(...args) { |
1559 /// return core.bool.as(this.noSuchMethod( | 1490 /// return core.bool.as(this.noSuchMethod( |
1560 /// new dart.InvocationImpl('eatFood', args))); | 1491 /// new dart.InvocationImpl.new('eatFood', args))); |
1561 /// } | 1492 /// } |
1562 JS.Method _implementMockMember(ExecutableElement method, InterfaceType type) { | 1493 JS.Method _implementMockMember(ExecutableElement method, InterfaceType type) { |
1563 var invocationProps = <JS.Property>[]; | 1494 var invocationProps = <JS.Property>[]; |
1564 addProperty(String name, JS.Expression value) { | 1495 addProperty(String name, JS.Expression value) { |
1565 invocationProps.add(new JS.Property(js.string(name), value)); | 1496 invocationProps.add(new JS.Property(js.string(name), value)); |
1566 } | 1497 } |
1567 | 1498 |
1568 var args = new JS.TemporaryId('args'); | 1499 var args = new JS.TemporaryId('args'); |
1569 var fnArgs = <JS.Parameter>[]; | 1500 var fnArgs = <JS.Parameter>[]; |
1570 JS.Expression positionalArgs; | 1501 JS.Expression positionalArgs; |
(...skipping 14 matching lines...) Expand all Loading... |
1585 | 1516 |
1586 positionalArgs = new JS.ArrayInitializer([]); | 1517 positionalArgs = new JS.ArrayInitializer([]); |
1587 } else if (property.isSetter) { | 1518 } else if (property.isSetter) { |
1588 addProperty('isSetter', js.boolean(true)); | 1519 addProperty('isSetter', js.boolean(true)); |
1589 | 1520 |
1590 fnArgs.add(args); | 1521 fnArgs.add(args); |
1591 positionalArgs = new JS.ArrayInitializer([args]); | 1522 positionalArgs = new JS.ArrayInitializer([args]); |
1592 } | 1523 } |
1593 } | 1524 } |
1594 | 1525 |
1595 var fnBody = js.call('this.noSuchMethod(new #.InvocationImpl(#, #, #))', [ | 1526 var fnBody = |
| 1527 js.call('this.noSuchMethod(new #.InvocationImpl.new(#, #, #))', [ |
1596 _runtimeModule, | 1528 _runtimeModule, |
1597 _declareMemberName(method, useDisplayName: true), | 1529 _declareMemberName(method, useDisplayName: true), |
1598 positionalArgs, | 1530 positionalArgs, |
1599 new JS.ObjectInitializer(invocationProps) | 1531 new JS.ObjectInitializer(invocationProps) |
1600 ]); | 1532 ]); |
1601 | 1533 |
1602 if (!method.returnType.isDynamic) { | 1534 if (!method.returnType.isDynamic) { |
1603 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]); | 1535 fnBody = js.call('#._check(#)', [_emitType(method.returnType), fnBody]); |
1604 } | 1536 } |
1605 | 1537 |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1775 newBaseClass = _callHelper('mixin(#)', [mixins]); | 1707 newBaseClass = _callHelper('mixin(#)', [mixins]); |
1776 } | 1708 } |
1777 var deferredBaseClass = _callHelperStatement( | 1709 var deferredBaseClass = _callHelperStatement( |
1778 'setBaseClass(#, #);', [className, newBaseClass]); | 1710 'setBaseClass(#, #);', [className, newBaseClass]); |
1779 if (typeFormals.isNotEmpty) return deferredBaseClass; | 1711 if (typeFormals.isNotEmpty) return deferredBaseClass; |
1780 body.add(deferredBaseClass); | 1712 body.add(deferredBaseClass); |
1781 } | 1713 } |
1782 return null; | 1714 return null; |
1783 } | 1715 } |
1784 | 1716 |
1785 void _defineNamedConstructors(List<ConstructorDeclaration> ctors, | 1717 /// Defines all constructors for this class as ES5 constructors. |
1786 List<JS.Statement> body, JS.Expression className, bool isCallable) { | 1718 void _defineConstructors( |
1787 var code = isCallable | 1719 ClassElement classElem, |
1788 ? 'defineNamedConstructorCallable(#, #, #);' | 1720 JS.Expression className, |
1789 : 'defineNamedConstructor(#, #)'; | 1721 List<FieldDeclaration> fields, |
| 1722 List<JS.Statement> body, |
| 1723 List<ConstructorDeclaration> ctors) { |
| 1724 // See if we have a "call" with a statically known function type: |
| 1725 // |
| 1726 // - if it's a method, then it does because all methods do, |
| 1727 // - if it's a getter, check the return type. |
| 1728 // |
| 1729 // Other cases like a getter returning dynamic/Object/Function will be |
| 1730 // handled at runtime by the dynamic call mechanism. So we only |
| 1731 // concern ourselves with statically known function types. |
| 1732 // |
| 1733 // For the same reason, we can ignore "noSuchMethod". |
| 1734 // call-implemented-by-nSM will be dispatched by dcall at runtime. |
| 1735 bool isCallable = classElem.lookUpMethod('call', null) != null || |
| 1736 classElem.lookUpGetter('call', null)?.returnType is FunctionType; |
1790 | 1737 |
1791 for (ConstructorDeclaration member in ctors) { | 1738 void addConstructor(ConstructorElement element, JS.Expression jsCtor) { |
1792 if (member.name != null && member.factoryKeyword == null) { | 1739 var ctorName = _constructorName(element); |
1793 var args = [className, _constructorName(member.element)]; | 1740 if (JS.invalidStaticFieldName(element.name)) { |
1794 if (isCallable) { | 1741 jsCtor = |
1795 args.add(_emitCallableClassConstructor(member.element)); | 1742 _callHelper('defineValue(#, #, #)', [className, ctorName, jsCtor]); |
1796 } | 1743 } else { |
| 1744 jsCtor = js.call('#.# = #', [className, ctorName, jsCtor]); |
| 1745 } |
| 1746 body.add(js.statement('#.prototype = #.prototype;', [jsCtor, className])); |
| 1747 } |
1797 | 1748 |
1798 body.add(_callHelperStatement(code, args)); | 1749 if (classElem.isMixinApplication) { |
| 1750 var supertype = classElem.supertype; |
| 1751 for (var ctor in classElem.constructors) { |
| 1752 List<JS.Identifier> jsParams = _emitParametersForElement(ctor); |
| 1753 var superCtor = supertype.lookUpConstructor(ctor.name, ctor.library); |
| 1754 var superCall = |
| 1755 _superConstructorCall(classElem, className, superCtor, jsParams); |
| 1756 addConstructor( |
| 1757 ctor, |
| 1758 _finishConstructorFunction( |
| 1759 jsParams, |
| 1760 new JS.Block(superCall != null ? [superCall] : []), |
| 1761 isCallable)); |
1799 } | 1762 } |
| 1763 return; |
| 1764 } |
| 1765 |
| 1766 // Iff no constructor is specified for a class C, it implicitly has a |
| 1767 // default constructor `C() : super() {}`, unless C is class Object. |
| 1768 if (ctors.isEmpty) { |
| 1769 var superCall = _superConstructorCall(classElem, className); |
| 1770 List<JS.Statement> body = [_initializeFields(fields)]; |
| 1771 if (superCall != null) body.add(superCall); |
| 1772 |
| 1773 addConstructor(classElem.unnamedConstructor, |
| 1774 _finishConstructorFunction([], new JS.Block(body), isCallable)); |
| 1775 return; |
| 1776 } |
| 1777 |
| 1778 for (var ctor in ctors) { |
| 1779 var element = ctor.element; |
| 1780 if (element.isFactory || _externalOrNative(ctor)) continue; |
| 1781 |
| 1782 addConstructor( |
| 1783 element, _emitConstructor(ctor, fields, isCallable, className)); |
1800 } | 1784 } |
1801 } | 1785 } |
1802 | 1786 |
1803 /// Emits static fields for a class, and initialize them eagerly if possible, | 1787 /// Emits static fields for a class, and initialize them eagerly if possible, |
1804 /// otherwise define them as lazy properties. | 1788 /// otherwise define them as lazy properties. |
1805 void _emitStaticFields(List<FieldDeclaration> staticFields, | 1789 void _emitStaticFields(List<FieldDeclaration> staticFields, |
1806 ClassElement classElem, List<JS.Statement> body) { | 1790 ClassElement classElem, List<JS.Statement> body) { |
1807 var lazyStatics = staticFields.expand((f) => f.fields.variables).toList(); | 1791 var lazyStatics = staticFields.expand((f) => f.fields.variables).toList(); |
1808 if (lazyStatics.isNotEmpty) { | 1792 if (lazyStatics.isNotEmpty) { |
1809 body.add(_emitLazyFields(classElem, lazyStatics)); | 1793 body.add(_emitLazyFields(classElem, lazyStatics)); |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1968 var fieldSig = _emitFieldSignature(element.type, | 1952 var fieldSig = _emitFieldSignature(element.type, |
1969 metadata: node.metadata, isFinal: element.isFinal); | 1953 metadata: node.metadata, isFinal: element.isFinal); |
1970 fieldList.add(new JS.Property(memberName, fieldSig)); | 1954 fieldList.add(new JS.Property(memberName, fieldSig)); |
1971 } | 1955 } |
1972 } | 1956 } |
1973 } | 1957 } |
1974 | 1958 |
1975 var tCtors = <JS.Property>[]; | 1959 var tCtors = <JS.Property>[]; |
1976 if (options.emitMetadata) { | 1960 if (options.emitMetadata) { |
1977 for (ConstructorDeclaration node in ctors) { | 1961 for (ConstructorDeclaration node in ctors) { |
1978 var memberName = _constructorName(node.element); | 1962 var element = node.element; |
1979 var element = | 1963 var memberName = _constructorName(element); |
1980 resolutionMap.elementDeclaredByConstructorDeclaration(node); | |
1981 var type = _emitAnnotatedFunctionType(element.type, node.metadata, | 1964 var type = _emitAnnotatedFunctionType(element.type, node.metadata, |
1982 parameters: node.parameters.parameters, | 1965 parameters: node.parameters.parameters, |
1983 nameType: options.hoistSignatureTypes, | 1966 nameType: options.hoistSignatureTypes, |
1984 hoistType: options.hoistSignatureTypes, | 1967 hoistType: options.hoistSignatureTypes, |
1985 definite: true); | 1968 definite: true); |
1986 var property = new JS.Property(memberName, type); | 1969 var property = new JS.Property(memberName, type); |
1987 tCtors.add(property); | 1970 tCtors.add(property); |
1988 } | 1971 } |
1989 } | 1972 } |
1990 var sigFields = <JS.Property>[]; | 1973 var sigFields = <JS.Property>[]; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2045 } | 2028 } |
2046 } | 2029 } |
2047 } | 2030 } |
2048 if (dartxNames.isNotEmpty) { | 2031 if (dartxNames.isNotEmpty) { |
2049 body.add(_callHelperStatement('defineExtensionNames(#)', | 2032 body.add(_callHelperStatement('defineExtensionNames(#)', |
2050 [new JS.ArrayInitializer(dartxNames, multiline: true)])); | 2033 [new JS.ArrayInitializer(dartxNames, multiline: true)])); |
2051 } | 2034 } |
2052 } | 2035 } |
2053 } | 2036 } |
2054 | 2037 |
2055 /// Generates the implicit default constructor for class C of the form | 2038 JS.Expression _emitConstructor(ConstructorDeclaration node, |
2056 /// `C() : super() {}`. | 2039 List<FieldDeclaration> fields, bool isCallable, JS.Expression className) { |
2057 JS.Method _emitImplicitConstructor( | 2040 var params = _emitFormalParameterList(node.parameters); |
2058 ClassDeclaration node, | |
2059 List<FieldDeclaration> fields, | |
2060 Map<FieldElement, JS.TemporaryId> virtualFields) { | |
2061 // If we don't have a method body, skip this. | |
2062 var superCall = _superConstructorCall(node.element); | |
2063 if (fields.isEmpty && superCall == null) return null; | |
2064 | 2041 |
2065 var initFields = _initializeFields(node, fields, virtualFields); | 2042 var savedFunction = _currentFunction; |
2066 List<JS.Statement> body = [initFields]; | 2043 _currentFunction = node.body; |
2067 if (superCall != null) { | 2044 |
2068 body.add(superCall); | 2045 var savedSuperAllowed = _superAllowed; |
2069 } | 2046 _superAllowed = false; |
2070 var name = _constructorName(resolutionMap | 2047 var body = _emitConstructorBody(node, fields, className); |
2071 .elementDeclaredByClassDeclaration(node) | 2048 _superAllowed = savedSuperAllowed; |
2072 .unnamedConstructor); | 2049 _currentFunction = savedFunction; |
2073 return annotate( | 2050 |
2074 new JS.Method(name, js.call('function() { #; }', [body]) as JS.Fun), | 2051 return _finishConstructorFunction(params, body, isCallable); |
2075 node, | |
2076 node.element); | |
2077 } | 2052 } |
2078 | 2053 |
2079 JS.Method _emitConstructor( | 2054 JS.Expression _finishConstructorFunction( |
2080 ConstructorDeclaration node, | 2055 List<JS.Parameter> params, JS.Block body, isCallable) { |
2081 InterfaceType type, | 2056 // We consider a class callable if it inherits from anything with a `call` |
2082 List<FieldDeclaration> fields, | 2057 // method. As a result, we can know the callable JS function was created |
2083 Map<FieldElement, JS.TemporaryId> virtualFields, | 2058 // at the first constructor that was hit. |
2084 bool isObject) { | 2059 if (!isCallable) return new JS.Fun(params, body); |
2085 if (_externalOrNative(node)) return null; | 2060 return js.call( |
2086 | 2061 r'''function callableClass(#) { |
2087 var name = _constructorName(node.element); | 2062 if (typeof this !== "function") { |
2088 var returnType = emitTypeRef(resolutionMap | 2063 function self(...args) { |
2089 .elementDeclaredByConstructorDeclaration(node) | 2064 return self.call.apply(self, args); |
2090 .enclosingElement | 2065 } |
2091 .type); | 2066 self.__proto__ = this.__proto__; |
2092 | 2067 callableClass.call(self, #); |
2093 // Wacky factory redirecting constructors: factory Foo.q(x, y) = Bar.baz; | 2068 return self; |
2094 var redirect = node.redirectedConstructor; | 2069 } |
2095 if (redirect != null) { | 2070 # |
2096 var newKeyword = | 2071 }''', |
2097 resolutionMap.staticElementForConstructorReference(redirect).isFactory | 2072 [params, params, body]); |
2098 ? '' | |
2099 : 'new'; | |
2100 // Pass along all arguments verbatim, and let the callee handle them. | |
2101 // TODO(jmesserly): we'll need something different once we have | |
2102 // rest/spread support, but this should work for now. | |
2103 var params = | |
2104 _emitFormalParameterList(node.parameters, destructure: false); | |
2105 | |
2106 var fun = new JS.Fun( | |
2107 params, | |
2108 js.statement( | |
2109 '{ return $newKeyword #(#); }', [_visit(redirect), params]), | |
2110 returnType: returnType); | |
2111 return annotate( | |
2112 new JS.Method(name, fun, isStatic: true), node, node.element); | |
2113 } | |
2114 | |
2115 var params = _emitFormalParameterList(node.parameters); | |
2116 | |
2117 // Factory constructors are essentially static methods. | |
2118 if (node.factoryKeyword != null) { | |
2119 var body = <JS.Statement>[]; | |
2120 var init = _emitArgumentInitializers(node, constructor: true); | |
2121 if (init != null) body.add(init); | |
2122 body.add(_visit(node.body)); | |
2123 var fun = new JS.Fun(params, new JS.Block(body), returnType: returnType); | |
2124 return annotate( | |
2125 new JS.Method(name, fun, isStatic: true), node, node.element); | |
2126 } | |
2127 | |
2128 // Code generation for Object's constructor. | |
2129 var savedFunction = _currentFunction; | |
2130 _currentFunction = node.body; | |
2131 var body = _emitConstructorBody(node, fields, virtualFields); | |
2132 _currentFunction = savedFunction; | |
2133 | |
2134 // We generate constructors as initializer methods in the class; | |
2135 // this allows use of `super` for instance methods/properties. | |
2136 // It also avoids V8 restrictions on `super` in default constructors. | |
2137 return annotate( | |
2138 new JS.Method(name, new JS.Fun(params, body, returnType: returnType)), | |
2139 node, | |
2140 node.element); | |
2141 } | 2073 } |
2142 | 2074 |
2143 JS.Expression _constructorName(ConstructorElement ctor) { | 2075 JS.Expression _constructorName(ConstructorElement ctor) { |
2144 var name = ctor.name; | 2076 var name = ctor.name; |
2145 if (name == '') { | 2077 if (name == '') { |
2146 // Default constructors (factory or not) use `new` as their name. | 2078 // Default constructors (factory or not) use `new` as their name. |
2147 return _propertyName('new'); | 2079 return _propertyName('new'); |
2148 } | 2080 } |
2149 return _emitMemberName(name, isStatic: true); | 2081 return _emitMemberName(name, isStatic: true); |
2150 } | 2082 } |
2151 | 2083 |
2152 JS.Block _emitConstructorBody( | 2084 JS.Block _emitConstructorBody(ConstructorDeclaration node, |
2153 ConstructorDeclaration node, | 2085 List<FieldDeclaration> fields, JS.Expression className) { |
2154 List<FieldDeclaration> fields, | |
2155 Map<FieldElement, JS.TemporaryId> virtualFields) { | |
2156 var body = <JS.Statement>[]; | 2086 var body = <JS.Statement>[]; |
2157 ClassDeclaration cls = node.parent; | 2087 ClassDeclaration cls = node.parent; |
2158 | 2088 |
2159 // Generate optional/named argument value assignment. These can not have | 2089 // Generate optional/named argument value assignment. These can not have |
2160 // side effects, and may be used by the constructor's initializers, so it's | 2090 // side effects, and may be used by the constructor's initializers, so it's |
2161 // nice to do them first. | 2091 // nice to do them first. |
2162 // Also for const constructors we need to ensure default values are | 2092 // Also for const constructors we need to ensure default values are |
2163 // available for use by top-level constant initializers. | 2093 // available for use by top-level constant initializers. |
2164 var init = _emitArgumentInitializers(node, constructor: true); | 2094 var init = _emitArgumentInitializers(node, constructor: true); |
2165 if (init != null) body.add(init); | 2095 if (init != null) body.add(init); |
2166 | 2096 |
2167 // Redirecting constructors: these are not allowed to have initializers, | 2097 // Redirecting constructors: these are not allowed to have initializers, |
2168 // and the redirecting ctor invocation runs before field initializers. | 2098 // and the redirecting ctor invocation runs before field initializers. |
2169 var redirectCall = node.initializers.firstWhere( | 2099 var redirectCall = node.initializers.firstWhere( |
2170 (i) => i is RedirectingConstructorInvocation, | 2100 (i) => i is RedirectingConstructorInvocation, |
2171 orElse: () => null); | 2101 orElse: () => null); |
2172 | 2102 |
2173 if (redirectCall != null) { | 2103 if (redirectCall != null) { |
2174 body.add(_visit(redirectCall)); | 2104 body.add(_emitRedirectingConstructor(redirectCall, className)); |
2175 return new JS.Block(body); | 2105 return new JS.Block(body); |
2176 } | 2106 } |
2177 | 2107 |
2178 // Generate field initializers. | 2108 // Generate field initializers. |
2179 // These are expanded into each non-redirecting constructor. | 2109 // These are expanded into each non-redirecting constructor. |
2180 // In the future we may want to create an initializer function if we have | 2110 // In the future we may want to create an initializer function if we have |
2181 // multiple constructors, but it needs to be balanced against readability. | 2111 // multiple constructors, but it needs to be balanced against readability. |
2182 body.add(_initializeFields(cls, fields, virtualFields, node)); | 2112 body.add(_initializeFields(fields, node)); |
2183 | 2113 |
2184 var superCall = node.initializers.firstWhere( | 2114 var superCall = node.initializers.firstWhere( |
2185 (i) => i is SuperConstructorInvocation, | 2115 (i) => i is SuperConstructorInvocation, |
2186 orElse: () => null) as SuperConstructorInvocation; | 2116 orElse: () => null) as SuperConstructorInvocation; |
2187 | 2117 |
2188 // If no superinitializer is provided, an implicit superinitializer of the | 2118 // If no superinitializer is provided, an implicit superinitializer of the |
2189 // form `super()` is added at the end of the initializer list, unless the | 2119 // form `super()` is added at the end of the initializer list, unless the |
2190 // enclosing class is class Object. | 2120 // enclosing class is class Object. |
2191 var jsSuper = _superConstructorCall(cls.element, superCall); | 2121 var superCallArgs = |
2192 if (jsSuper != null) body.add(jsSuper); | 2122 superCall != null ? _emitArgumentList(superCall.argumentList) : null; |
| 2123 var jsSuper = _superConstructorCall( |
| 2124 cls.element, className, superCall?.staticElement, superCallArgs); |
| 2125 if (jsSuper != null) body.add(annotate(jsSuper, superCall)); |
2193 | 2126 |
2194 body.add(_visit(node.body)); | 2127 body.add(_visit(node.body)); |
2195 return new JS.Block(body)..sourceInformation = node; | 2128 return new JS.Block(body)..sourceInformation = node; |
2196 } | 2129 } |
2197 | 2130 |
2198 @override | 2131 JS.Statement _emitRedirectingConstructor( |
2199 JS.Statement visitRedirectingConstructorInvocation( | 2132 RedirectingConstructorInvocation node, JS.Expression className) { |
2200 RedirectingConstructorInvocation node) { | 2133 var ctor = node.staticElement; |
2201 var ctor = resolutionMap.staticElementForConstructorReference(node); | |
2202 var cls = ctor.enclosingElement; | |
2203 // We can't dispatch to the constructor with `this.new` as that might hit a | 2134 // We can't dispatch to the constructor with `this.new` as that might hit a |
2204 // derived class constructor with the same name. | 2135 // derived class constructor with the same name. |
2205 return js.statement('#.prototype.#.call(this, #);', [ | 2136 return js.statement('#.#.call(this, #);', [ |
2206 new JS.Identifier(cls.name), | 2137 className, |
2207 _constructorName(ctor), | 2138 _constructorName(ctor), |
2208 _emitArgumentList(node.argumentList) | 2139 _emitArgumentList(node.argumentList) |
2209 ]); | 2140 ]); |
2210 } | 2141 } |
2211 | 2142 |
2212 JS.Statement _superConstructorCall(ClassElement element, | 2143 JS.Statement _superConstructorCall( |
2213 [SuperConstructorInvocation node]) { | 2144 ClassElement element, JS.Expression className, |
2214 if (element.supertype == null) { | 2145 [ConstructorElement superCtor, List<JS.Expression> args]) { |
| 2146 // Get the supertype's unnamed constructor. |
| 2147 superCtor ??= element.supertype?.element?.unnamedConstructor; |
| 2148 if (superCtor == null) { |
2215 assert(element.type.isObject || options.unsafeForceCompile); | 2149 assert(element.type.isObject || options.unsafeForceCompile); |
2216 return null; | 2150 return null; |
2217 } | 2151 } |
2218 | 2152 |
2219 ConstructorElement superCtor; | 2153 // We can skip the super call if it's empty. Typically this happens for |
2220 if (node != null) { | 2154 // things that extend Object. |
2221 superCtor = node.staticElement; | |
2222 } else { | |
2223 // Get the supertype's unnamed constructor. | |
2224 superCtor = element.supertype.element.unnamedConstructor; | |
2225 } | |
2226 | |
2227 if (superCtor == null) { | |
2228 // This will only happen if the code has errors: | |
2229 // we're trying to generate an implicit constructor for a type where | |
2230 // we don't have a default constructor in the supertype. | |
2231 assert(options.unsafeForceCompile); | |
2232 return null; | |
2233 } | |
2234 | |
2235 if (superCtor.name == '' && !_hasUnnamedSuperConstructor(element)) { | 2155 if (superCtor.name == '' && !_hasUnnamedSuperConstructor(element)) { |
2236 return null; | 2156 return null; |
2237 } | 2157 } |
2238 | 2158 |
2239 var name = _constructorName(superCtor); | 2159 var name = _constructorName(superCtor); |
2240 var args = node != null ? _emitArgumentList(node.argumentList) : []; | 2160 return js.statement( |
2241 return annotate(js.statement('super.#(#);', [name, args]), node); | 2161 '#.__proto__.#.call(this, #);', [className, name, args ?? []]); |
2242 } | 2162 } |
2243 | 2163 |
2244 bool _hasUnnamedSuperConstructor(ClassElement e) { | 2164 bool _hasUnnamedSuperConstructor(ClassElement e) { |
2245 var supertype = e.supertype; | 2165 var supertype = e.supertype; |
2246 if (supertype == null) return false; | 2166 if (supertype == null) return false; |
2247 if (_hasUnnamedConstructor(supertype.element)) return true; | 2167 if (_hasUnnamedConstructor(supertype.element)) return true; |
2248 for (var mixin in e.mixins) { | 2168 for (var mixin in e.mixins) { |
2249 if (_hasUnnamedConstructor(mixin.element)) return true; | 2169 if (_hasUnnamedConstructor(mixin.element)) return true; |
2250 } | 2170 } |
2251 return false; | 2171 return false; |
2252 } | 2172 } |
2253 | 2173 |
2254 bool _hasUnnamedConstructor(ClassElement e) { | 2174 bool _hasUnnamedConstructor(ClassElement e) { |
2255 if (e.type.isObject) return false; | 2175 if (e.type.isObject) return false; |
2256 if (!e.unnamedConstructor.isSynthetic) return true; | 2176 if (!e.unnamedConstructor.isSynthetic) return true; |
2257 if (e.fields.any((f) => !f.isStatic && !f.isSynthetic)) return true; | 2177 if (e.fields.any((f) => !f.isStatic && !f.isSynthetic)) return true; |
2258 return _hasUnnamedSuperConstructor(e); | 2178 return _hasUnnamedSuperConstructor(e); |
2259 } | 2179 } |
2260 | 2180 |
2261 /// Initialize fields. They follow the sequence: | 2181 /// Initialize fields. They follow the sequence: |
2262 /// | 2182 /// |
2263 /// 1. field declaration initializer if non-const, | 2183 /// 1. field declaration initializer if non-const, |
2264 /// 2. field initializing parameters, | 2184 /// 2. field initializing parameters, |
2265 /// 3. constructor field initializers, | 2185 /// 3. constructor field initializers, |
2266 /// 4. initialize fields not covered in 1-3 | 2186 /// 4. initialize fields not covered in 1-3 |
2267 JS.Statement _initializeFields( | 2187 JS.Statement _initializeFields(List<FieldDeclaration> fieldDecls, |
2268 ClassDeclaration cls, | |
2269 List<FieldDeclaration> fieldDecls, | |
2270 Map<FieldElement, JS.TemporaryId> virtualFields, | |
2271 [ConstructorDeclaration ctor]) { | 2188 [ConstructorDeclaration ctor]) { |
2272 // Run field initializers if they can have side-effects. | 2189 // Run field initializers if they can have side-effects. |
2273 var fields = new Map<FieldElement, JS.Expression>(); | 2190 var fields = new Map<FieldElement, JS.Expression>(); |
2274 var unsetFields = new Map<FieldElement, VariableDeclaration>(); | 2191 var unsetFields = new Map<FieldElement, VariableDeclaration>(); |
2275 for (var declaration in fieldDecls) { | 2192 for (var declaration in fieldDecls) { |
2276 for (var fieldNode in declaration.fields.variables) { | 2193 for (var fieldNode in declaration.fields.variables) { |
2277 var element = fieldNode.element; | 2194 var element = fieldNode.element; |
2278 if (_constants.isFieldInitConstant(fieldNode)) { | 2195 if (_constants.isFieldInitConstant(fieldNode)) { |
2279 unsetFields[element as FieldElement] = fieldNode; | 2196 unsetFields[element as FieldElement] = fieldNode; |
2280 } else { | 2197 } else { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2313 if (fieldNode.initializer != null) { | 2230 if (fieldNode.initializer != null) { |
2314 value = _visit(fieldNode.initializer); | 2231 value = _visit(fieldNode.initializer); |
2315 } else { | 2232 } else { |
2316 value = new JS.LiteralNull(); | 2233 value = new JS.LiteralNull(); |
2317 } | 2234 } |
2318 fields[element] = value; | 2235 fields[element] = value; |
2319 }); | 2236 }); |
2320 | 2237 |
2321 var body = <JS.Statement>[]; | 2238 var body = <JS.Statement>[]; |
2322 fields.forEach((FieldElement e, JS.Expression initialValue) { | 2239 fields.forEach((FieldElement e, JS.Expression initialValue) { |
2323 JS.Expression access = virtualFields[e] ?? _declareMemberName(e.getter); | 2240 JS.Expression access = |
| 2241 _classProperties.virtualFields[e] ?? _declareMemberName(e.getter); |
2324 body.add(js.statement('this.# = #;', [access, initialValue])); | 2242 body.add(js.statement('this.# = #;', [access, initialValue])); |
2325 }); | 2243 }); |
2326 | 2244 |
2327 return _statement(body); | 2245 return _statement(body); |
2328 } | 2246 } |
2329 | 2247 |
2330 FormalParameterList _parametersOf(node) { | 2248 FormalParameterList _parametersOf(node) { |
2331 // TODO(jmesserly): clean this up. If we can model ES6 spread/rest args, we | 2249 // TODO(jmesserly): clean this up. If we can model ES6 spread/rest args, we |
2332 // could handle argument initializers more consistently in a separate | 2250 // could handle argument initializers more consistently in a separate |
2333 // lowering pass. | 2251 // lowering pass. |
(...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2795 } | 2713 } |
2796 return _callHelper('gbind(#, #)', [simpleId, typeArgs]); | 2714 return _callHelper('gbind(#, #)', [simpleId, typeArgs]); |
2797 } | 2715 } |
2798 | 2716 |
2799 /// Emits a simple identifier, handling implicit `this` as well as | 2717 /// Emits a simple identifier, handling implicit `this` as well as |
2800 /// going through the qualified library name if necessary, but *not* handling | 2718 /// going through the qualified library name if necessary, but *not* handling |
2801 /// inferred generic function instantiation. | 2719 /// inferred generic function instantiation. |
2802 JS.Expression _emitSimpleIdentifier(SimpleIdentifier node) { | 2720 JS.Expression _emitSimpleIdentifier(SimpleIdentifier node) { |
2803 var accessor = resolutionMap.staticElementForIdentifier(node); | 2721 var accessor = resolutionMap.staticElementForIdentifier(node); |
2804 if (accessor == null) { | 2722 if (accessor == null) { |
2805 return _callHelper('throw("compile error: unresolved identifier: " + #)', | 2723 return _callHelper( |
| 2724 'throw(Error("compile error: unresolved identifier: " + #))', |
2806 js.escapedString(node.name ?? '<null>')); | 2725 js.escapedString(node.name ?? '<null>')); |
2807 } | 2726 } |
2808 | 2727 |
2809 // Get the original declaring element. If we had a property accessor, this | 2728 // Get the original declaring element. If we had a property accessor, this |
2810 // indirects back to a (possibly synthetic) field. | 2729 // indirects back to a (possibly synthetic) field. |
2811 var element = accessor; | 2730 var element = accessor; |
2812 if (accessor is PropertyAccessorElement) element = accessor.variable; | 2731 if (accessor is PropertyAccessorElement) element = accessor.variable; |
2813 | 2732 |
2814 // type literal | 2733 // type literal |
2815 if (element is TypeDefiningElement) { | 2734 if (element is TypeDefiningElement) { |
(...skipping 984 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3800 return args; | 3719 return args; |
3801 } | 3720 } |
3802 | 3721 |
3803 @override | 3722 @override |
3804 JS.Property visitNamedExpression(NamedExpression node) { | 3723 JS.Property visitNamedExpression(NamedExpression node) { |
3805 assert(node.parent is ArgumentList); | 3724 assert(node.parent is ArgumentList); |
3806 return new JS.Property( | 3725 return new JS.Property( |
3807 _propertyName(node.name.label.name), _visit(node.expression)); | 3726 _propertyName(node.name.label.name), _visit(node.expression)); |
3808 } | 3727 } |
3809 | 3728 |
| 3729 List<JS.Parameter> _emitParametersForElement(ExecutableElement member) { |
| 3730 var jsParams = <JS.Identifier>[]; |
| 3731 for (var p in member.parameters) { |
| 3732 if (p.parameterKind != ParameterKind.NAMED) { |
| 3733 jsParams.add(new JS.Identifier(p.name)); |
| 3734 } else { |
| 3735 jsParams.add(new JS.TemporaryId('namedArgs')); |
| 3736 break; |
| 3737 } |
| 3738 } |
| 3739 return jsParams; |
| 3740 } |
| 3741 |
3810 List<JS.Parameter> _emitFormalParameterList(FormalParameterList node, | 3742 List<JS.Parameter> _emitFormalParameterList(FormalParameterList node, |
3811 {bool destructure: true}) { | 3743 {bool destructure: true}) { |
3812 if (node == null) return []; | 3744 if (node == null) return []; |
3813 | 3745 |
3814 destructure = destructure && options.destructureNamedParams; | 3746 destructure = destructure && options.destructureNamedParams; |
3815 | 3747 |
3816 var result = <JS.Parameter>[]; | 3748 var result = <JS.Parameter>[]; |
3817 var namedVars = <JS.DestructuredVariable>[]; | 3749 var namedVars = <JS.DestructuredVariable>[]; |
3818 var hasNamedArgsConflictingWithObjectProperties = false; | 3750 var hasNamedArgsConflictingWithObjectProperties = false; |
3819 var needsOpts = false; | 3751 var needsOpts = false; |
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4058 if (parent is ClassElement) { | 3990 if (parent is ClassElement) { |
4059 return getter | 3991 return getter |
4060 ? parent.getGetter(element.name) | 3992 ? parent.getGetter(element.name) |
4061 : parent.getSetter(element.name); | 3993 : parent.getSetter(element.name); |
4062 } | 3994 } |
4063 return null; | 3995 return null; |
4064 } | 3996 } |
4065 | 3997 |
4066 JS.Expression _emitConstructorName( | 3998 JS.Expression _emitConstructorName( |
4067 ConstructorElement element, DartType type, SimpleIdentifier name) { | 3999 ConstructorElement element, DartType type, SimpleIdentifier name) { |
4068 var classElem = element.enclosingElement; | 4000 return _emitJSInterop(type.element) ?? |
4069 var interop = _emitJSInterop(classElem); | 4001 new JS.PropertyAccess( |
4070 if (interop != null) return interop; | 4002 _emitConstructorAccess(type), _constructorName(element)); |
4071 var typeName = _emitConstructorAccess(type); | |
4072 if (name != null || element.isFactory) { | |
4073 var namedCtor = _constructorName(element); | |
4074 return new JS.PropertyAccess(typeName, namedCtor); | |
4075 } | |
4076 return typeName; | |
4077 } | 4003 } |
4078 | 4004 |
4079 @override | 4005 @override |
4080 visitConstructorName(ConstructorName node) { | 4006 visitConstructorName(ConstructorName node) { |
4081 return _emitConstructorName(node.staticElement, node.type.type, node.name); | 4007 return _emitConstructorName(node.staticElement, node.type.type, node.name); |
4082 } | 4008 } |
4083 | 4009 |
4084 JS.Expression _emitInstanceCreationExpression( | 4010 JS.Expression _emitInstanceCreationExpression( |
4085 ConstructorElement element, | 4011 ConstructorElement element, |
4086 DartType type, | 4012 DartType type, |
4087 SimpleIdentifier name, | 4013 SimpleIdentifier name, |
4088 ArgumentList argumentList, | 4014 ArgumentList argumentList, |
4089 bool isConst) { | 4015 bool isConst) { |
4090 JS.Expression emitNew() { | 4016 JS.Expression emitNew() { |
4091 JS.Expression ctor; | 4017 JS.Expression ctor; |
4092 bool isFactory = false; | 4018 bool isFactory = false; |
4093 bool isNative = false; | 4019 bool isNative = false; |
4094 if (element == null) { | 4020 if (element == null) { |
4095 ctor = _callHelper( | 4021 ctor = _callHelper( |
4096 'throw("compile error: unresolved constructor: " + # + "." + #)', [ | 4022 'throw(Error("compile error: unresolved constructor: " ' |
4097 js.escapedString(type?.name ?? '<null>'), | 4023 '+ # + "." + #))', |
4098 js.escapedString(name?.name ?? '<unnamed>') | 4024 [ |
4099 ]); | 4025 js.escapedString(type?.name ?? '<null>'), |
| 4026 js.escapedString(name?.name ?? '<unnamed>') |
| 4027 ]); |
4100 } else { | 4028 } else { |
4101 ctor = _emitConstructorName(element, type, name); | 4029 ctor = _emitConstructorName(element, type, name); |
4102 isFactory = element.isFactory; | 4030 isFactory = element.isFactory; |
4103 var classElem = element.enclosingElement; | 4031 var classElem = element.enclosingElement; |
4104 isNative = _isJSNative(classElem); | 4032 isNative = _isJSNative(classElem); |
4105 } | 4033 } |
4106 var args = _emitArgumentList(argumentList); | 4034 var args = _emitArgumentList(argumentList); |
4107 // Native factory constructors are JS constructors - use new here. | 4035 // Native factory constructors are JS constructors - use new here. |
4108 return isFactory && !isNative | 4036 return isFactory && !isNative |
4109 ? new JS.Call(ctor, args) | 4037 ? new JS.Call(ctor, args) |
(...skipping 1180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5290 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); | 5218 visitNullLiteral(NullLiteral node) => new JS.LiteralNull(); |
5291 | 5219 |
5292 @override | 5220 @override |
5293 visitSymbolLiteral(SymbolLiteral node) { | 5221 visitSymbolLiteral(SymbolLiteral node) { |
5294 JS.Expression emitSymbol() { | 5222 JS.Expression emitSymbol() { |
5295 // TODO(vsm): Handle qualified symbols correctly. | 5223 // TODO(vsm): Handle qualified symbols correctly. |
5296 var last = node.components.last.toString(); | 5224 var last = node.components.last.toString(); |
5297 var name = js.string(node.components.join('.'), "'"); | 5225 var name = js.string(node.components.join('.'), "'"); |
5298 if (last.startsWith('_')) { | 5226 if (last.startsWith('_')) { |
5299 var nativeSymbol = _emitPrivateNameSymbol(currentLibrary, last); | 5227 var nativeSymbol = _emitPrivateNameSymbol(currentLibrary, last); |
5300 return js.call('new #(#, #)', [ | 5228 return js.call('new #.new(#, #)', [ |
5301 _emitConstructorAccess(privateSymbolClass.type), | 5229 _emitConstructorAccess(privateSymbolClass.type), |
5302 name, | 5230 name, |
5303 nativeSymbol | 5231 nativeSymbol |
5304 ]); | 5232 ]); |
5305 } else { | 5233 } else { |
5306 return js | 5234 return js |
5307 .call('#.new(#)', [_emitConstructorAccess(types.symbolType), name]); | 5235 .call('#.new(#)', [_emitConstructorAccess(types.symbolType), name]); |
5308 } | 5236 } |
5309 } | 5237 } |
5310 | 5238 |
(...skipping 484 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5795 visitConfiguration(node) => _unreachable(node); | 5723 visitConfiguration(node) => _unreachable(node); |
5796 | 5724 |
5797 /// Unusued, see [_emitConstructor]. | 5725 /// Unusued, see [_emitConstructor]. |
5798 @override | 5726 @override |
5799 visitConstructorDeclaration(node) => _unreachable(node); | 5727 visitConstructorDeclaration(node) => _unreachable(node); |
5800 | 5728 |
5801 /// Unusued, see [_emitFieldInitializers]. | 5729 /// Unusued, see [_emitFieldInitializers]. |
5802 @override | 5730 @override |
5803 visitConstructorFieldInitializer(node) => _unreachable(node); | 5731 visitConstructorFieldInitializer(node) => _unreachable(node); |
5804 | 5732 |
| 5733 /// Unusued, see [_emitRedirectingConstructor]. |
| 5734 @override |
| 5735 visitRedirectingConstructorInvocation(node) => _unreachable(node); |
| 5736 |
5805 /// Unusued. Handled in [visitForEachStatement]. | 5737 /// Unusued. Handled in [visitForEachStatement]. |
5806 @override | 5738 @override |
5807 visitDeclaredIdentifier(node) => _unreachable(node); | 5739 visitDeclaredIdentifier(node) => _unreachable(node); |
5808 | 5740 |
5809 /// Unused, handled by imports/exports. | 5741 /// Unused, handled by imports/exports. |
5810 @override | 5742 @override |
5811 visitDottedName(node) => _unreachable(node); | 5743 visitDottedName(node) => _unreachable(node); |
5812 | 5744 |
5813 /// Unused, handled by [visitEnumDeclaration]. | 5745 /// Unused, handled by [visitEnumDeclaration]. |
5814 @override | 5746 @override |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5979 if (targetIdentifier.staticElement is! PrefixElement) return false; | 5911 if (targetIdentifier.staticElement is! PrefixElement) return false; |
5980 var prefix = targetIdentifier.staticElement as PrefixElement; | 5912 var prefix = targetIdentifier.staticElement as PrefixElement; |
5981 | 5913 |
5982 // The library the prefix is referring to must come from a deferred import. | 5914 // The library the prefix is referring to must come from a deferred import. |
5983 var containingLibrary = resolutionMap | 5915 var containingLibrary = resolutionMap |
5984 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) | 5916 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) |
5985 .library; | 5917 .library; |
5986 var imports = containingLibrary.getImportsWithPrefix(prefix); | 5918 var imports = containingLibrary.getImportsWithPrefix(prefix); |
5987 return imports.length == 1 && imports[0].isDeferred; | 5919 return imports.length == 1 && imports[0].isDeferred; |
5988 } | 5920 } |
OLD | NEW |