Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(725)

Side by Side Diff: pkg/dev_compiler/lib/src/compiler/code_generator.dart

Issue 3003613002: improve DDC's type checks (Closed)
Patch Set: format Created 3 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 final InterfaceType _asyncStreamIterator; 133 final InterfaceType _asyncStreamIterator;
134 134
135 /// The dart:core `identical` element. 135 /// The dart:core `identical` element.
136 final FunctionElement _coreIdentical; 136 final FunctionElement _coreIdentical;
137 137
138 /// The dart:_interceptors JSArray element. 138 /// The dart:_interceptors JSArray element.
139 final ClassElement _jsArray; 139 final ClassElement _jsArray;
140 140
141 final ClassElement boolClass; 141 final ClassElement boolClass;
142 final ClassElement intClass; 142 final ClassElement intClass;
143 final ClassElement doubleClass;
143 final ClassElement interceptorClass; 144 final ClassElement interceptorClass;
144 final ClassElement nullClass; 145 final ClassElement nullClass;
145 final ClassElement numClass; 146 final ClassElement numClass;
146 final ClassElement objectClass; 147 final ClassElement objectClass;
147 final ClassElement stringClass; 148 final ClassElement stringClass;
148 final ClassElement functionClass; 149 final ClassElement functionClass;
149 final ClassElement privateSymbolClass; 150 final ClassElement privateSymbolClass;
150 151
151 ConstFieldVisitor _constants; 152 ConstFieldVisitor _constants;
152 153
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 _asyncStreamIterator = 204 _asyncStreamIterator =
204 _getLibrary(c, 'dart:async').getType('StreamIterator').type, 205 _getLibrary(c, 'dart:async').getType('StreamIterator').type,
205 _coreIdentical = 206 _coreIdentical =
206 _getLibrary(c, 'dart:core').publicNamespace.get('identical'), 207 _getLibrary(c, 'dart:core').publicNamespace.get('identical'),
207 _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'), 208 _jsArray = _getLibrary(c, 'dart:_interceptors').getType('JSArray'),
208 interceptorClass = 209 interceptorClass =
209 _getLibrary(c, 'dart:_interceptors').getType('Interceptor'), 210 _getLibrary(c, 'dart:_interceptors').getType('Interceptor'),
210 dartCoreLibrary = _getLibrary(c, 'dart:core'), 211 dartCoreLibrary = _getLibrary(c, 'dart:core'),
211 boolClass = _getLibrary(c, 'dart:core').getType('bool'), 212 boolClass = _getLibrary(c, 'dart:core').getType('bool'),
212 intClass = _getLibrary(c, 'dart:core').getType('int'), 213 intClass = _getLibrary(c, 'dart:core').getType('int'),
214 doubleClass = _getLibrary(c, 'dart:core').getType('double'),
213 numClass = _getLibrary(c, 'dart:core').getType('num'), 215 numClass = _getLibrary(c, 'dart:core').getType('num'),
214 nullClass = _getLibrary(c, 'dart:core').getType('Null'), 216 nullClass = _getLibrary(c, 'dart:core').getType('Null'),
215 objectClass = _getLibrary(c, 'dart:core').getType('Object'), 217 objectClass = _getLibrary(c, 'dart:core').getType('Object'),
216 stringClass = _getLibrary(c, 'dart:core').getType('String'), 218 stringClass = _getLibrary(c, 'dart:core').getType('String'),
217 functionClass = _getLibrary(c, 'dart:core').getType('Function'), 219 functionClass = _getLibrary(c, 'dart:core').getType('Function'),
218 privateSymbolClass = 220 privateSymbolClass =
219 _getLibrary(c, 'dart:_internal').getType('PrivateSymbol'), 221 _getLibrary(c, 'dart:_internal').getType('PrivateSymbol'),
220 dartJSLibrary = _getLibrary(c, 'dart:js') { 222 dartJSLibrary = _getLibrary(c, 'dart:js') {
221 typeRep = new JSTypeRep(rules, types); 223 typeRep = new JSTypeRep(rules, types);
222 } 224 }
(...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after
833 if (isGeneric) { 835 if (isGeneric) {
834 if (isMixinAlias) { 836 if (isMixinAlias) {
835 block.add(js.statement('const # = #;', [className, classExpr])); 837 block.add(js.statement('const # = #;', [className, classExpr]));
836 } else { 838 } else {
837 block.add(new JS.ClassDeclaration(classExpr)); 839 block.add(new JS.ClassDeclaration(classExpr));
838 } 840 }
839 } else { 841 } else {
840 block.add(js.statement('# = #;', [className, classExpr])); 842 block.add(js.statement('# = #;', [className, classExpr]));
841 } 843 }
842 844
845 JS.Statement finishGenericTypeTest;
846
843 if (!isMixinAlias) { 847 if (!isMixinAlias) {
844 block.addAll(_defineConstructors(classElem, className, [], [])); 848 block.addAll(_defineConstructors(classElem, className, [], []));
849 finishGenericTypeTest = _emitClassTypeTests(classElem, className, block);
845 } 850 }
846 851
847 if (classElem.interfaces.isNotEmpty) { 852 if (classElem.interfaces.isNotEmpty) {
848 block.add(js.statement('#[#.implements] = () => #;', [ 853 block.add(js.statement('#[#.implements] = () => #;', [
849 className, 854 className,
850 _runtimeModule, 855 _runtimeModule,
851 new JS.ArrayInitializer(classElem.interfaces.map(_emitType).toList()) 856 new JS.ArrayInitializer(classElem.interfaces.map(_emitType).toList())
852 ])); 857 ]));
853 } 858 }
854 859
855 if (isGeneric) { 860 if (isGeneric) {
856 return _defineClassTypeArguments( 861 var classDef =
857 classElem, typeFormals, _statement(block)); 862 _defineClassTypeArguments(classElem, typeFormals, _statement(block));
863 if (finishGenericTypeTest == null) return classDef;
864 block = [classDef, finishGenericTypeTest];
858 } 865 }
859 return _statement(block); 866 return _statement(block);
860 } 867 }
861 868
862 JS.Statement _emitJSType(Element e) { 869 JS.Statement _emitJSType(Element e) {
863 var jsTypeName = getAnnotationName(e, isJSAnnotation); 870 var jsTypeName = getAnnotationName(e, isJSAnnotation);
864 if (jsTypeName == null || jsTypeName == e.name) return null; 871 if (jsTypeName == null || jsTypeName == e.name) return null;
865 872
866 // We export the JS type as if it was a Dart type. For example this allows 873 // We export the JS type as if it was a Dart type. For example this allows
867 // `dom.InputElement` to actually be HTMLInputElement. 874 // `dom.InputElement` to actually be HTMLInputElement.
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
925 932
926 // Emit the class, e.g. `core.Object = class Object { ... }` 933 // Emit the class, e.g. `core.Object = class Object { ... }`
927 _defineClass(classElem, className, classExpr, body); 934 _defineClass(classElem, className, classExpr, body);
928 body.addAll(jsCtors); 935 body.addAll(jsCtors);
929 936
930 // Emit things that come after the ES6 `class ... { ... }`. 937 // Emit things that come after the ES6 `class ... { ... }`.
931 var jsPeerNames = _getJSPeerNames(classElem); 938 var jsPeerNames = _getJSPeerNames(classElem);
932 JS.Statement deferredBaseClass = 939 JS.Statement deferredBaseClass =
933 _setBaseClass(classElem, className, jsPeerNames, body); 940 _setBaseClass(classElem, className, jsPeerNames, body);
934 941
935 _emitClassTypeTests(classElem, className, body); 942 var finishGenericTypeTest = _emitClassTypeTests(classElem, className, body);
936 943
937 _emitVirtualFieldSymbols(classElem, body); 944 _emitVirtualFieldSymbols(classElem, body);
938 _emitClassSignature(methods, allFields, classElem, ctors, className, body); 945 _emitClassSignature(methods, allFields, classElem, ctors, className, body);
939 _defineExtensionMembers(className, body); 946 _defineExtensionMembers(className, body);
940 _emitClassMetadata(node.metadata, className, body); 947 _emitClassMetadata(node.metadata, className, body);
941 948
942 JS.Statement classDef = _statement(body); 949 JS.Statement classDef = _statement(body);
943 950
944 var typeFormals = classElem.typeParameters; 951 var typeFormals = classElem.typeParameters;
945 if (typeFormals.isNotEmpty) { 952 if (typeFormals.isNotEmpty) {
946 classDef = _defineClassTypeArguments( 953 classDef = _defineClassTypeArguments(
947 classElem, typeFormals, classDef, className, deferredBaseClass); 954 classElem, typeFormals, classDef, className, deferredBaseClass);
948 } 955 }
949 956
950 body = <JS.Statement>[classDef]; 957 body = <JS.Statement>[classDef];
951 _emitStaticFields(staticFields, classElem, body); 958 _emitStaticFields(staticFields, classElem, body);
959 if (finishGenericTypeTest != null) body.add(finishGenericTypeTest);
952 for (var peer in jsPeerNames) { 960 for (var peer in jsPeerNames) {
953 _registerExtensionType(classElem, peer, body); 961 _registerExtensionType(classElem, peer, body);
954 } 962 }
955 963
956 _classProperties = savedClassProperties; 964 _classProperties = savedClassProperties;
957 return _statement(body); 965 return _statement(body);
958 } 966 }
959 967
960 void _emitClassTypeTests(ClassElement classElem, JS.Expression className, 968 JS.Statement _emitClassTypeTests(ClassElement classElem,
961 List<JS.Statement> body) { 969 JS.Expression className, List<JS.Statement> body) {
962 if (classElem == objectClass) { 970 JS.Expression getInterfaceSymbol(ClassElement c) {
963 // We rely on ES6 static inheritance. All types that are represented by 971 var library = c.library;
964 // class constructor functions will see these definitions, with [this] 972 if (library.isDartCore || library.isDartAsync) {
965 // being bound to the class constructor. 973 switch (c.name) {
966 974 case 'List':
967 // The 'instanceof' checks don't work for primitive types (which have fast 975 case 'Map':
968 // definitions below) and don't work for native types. In those cases we 976 case 'Iterable':
969 // fall through to the general purpose checking code. 977 case 'Future':
970 body.add(js.statement( 978 case 'Stream':
971 '#.is = function is_Object(o) {' 979 case 'StreamSubscription':
972 ' if (o instanceof this) return true;' 980 return _callHelper('is' + c.name);
973 ' return #.is(o, this);'
974 '}',
975 [className, _runtimeModule]));
976 body.add(js.statement(
977 '#.as = function as_Object(o) {'
978 ' if (o == null || o instanceof this) return o;'
979 ' return #.as(o, this);'
980 '}',
981 [className, _runtimeModule]));
982 body.add(js.statement(
983 '#._check = function check_Object(o) {'
984 ' if (o == null || o instanceof this) return o;'
985 ' return #.check(o, this);'
986 '}',
987 [className, _runtimeModule]));
988 return;
989 }
990 if (classElem == stringClass) {
991 body.add(js.statement(
992 '#.is = function is_String(o) { return typeof o == "string"; }',
993 className));
994 body.add(js.statement(
995 '#.as = function as_String(o) {'
996 ' if (typeof o == "string" || o == null) return o;'
997 ' return #.as(o, #);'
998 '}',
999 [className, _runtimeModule, className]));
1000 body.add(js.statement(
1001 '#._check = function check_String(o) {'
1002 ' if (typeof o == "string" || o == null) return o;'
1003 ' return #.check(o, #);'
1004 '}',
1005 [className, _runtimeModule, className]));
1006 return;
1007 }
1008 if (classElem == functionClass) {
1009 body.add(js.statement(
1010 '#.is = function is_Function(o) { return typeof o == "function"; }',
1011 className));
1012 body.add(js.statement(
1013 '#.as = function as_Function(o) {'
1014 ' if (typeof o == "function" || o == null) return o;'
1015 ' return #.as(o, #);'
1016 '}',
1017 [className, _runtimeModule, className]));
1018 body.add(js.statement(
1019 '#._check = function check_String(o) {'
1020 ' if (typeof o == "function" || o == null) return o;'
1021 ' return #.check(o, #);'
1022 '}',
1023 [className, _runtimeModule, className]));
1024 return;
1025 }
1026
1027 if (classElem == intClass) {
1028 body.add(js.statement(
1029 '#.is = function is_int(o) {'
1030 ' return typeof o == "number" && Math.floor(o) == o;'
1031 '}',
1032 className));
1033 body.add(js.statement(
1034 '#.as = function as_int(o) {'
1035 ' if ((typeof o == "number" && Math.floor(o) == o) || o == null)'
1036 ' return o;'
1037 ' return #.as(o, #);'
1038 '}',
1039 [className, _runtimeModule, className]));
1040 body.add(js.statement(
1041 '#._check = function check_int(o) {'
1042 ' if ((typeof o == "number" && Math.floor(o) == o) || o == null)'
1043 ' return o;'
1044 ' return #.check(o, #);'
1045 '}',
1046 [className, _runtimeModule, className]));
1047 return;
1048 }
1049 if (classElem == nullClass) {
1050 body.add(js.statement(
1051 '#.is = function is_Null(o) { return o == null; }', className));
1052 body.add(js.statement(
1053 '#.as = function as_Null(o) {'
1054 ' if (o == null) return o;'
1055 ' return #.as(o, #);'
1056 '}',
1057 [className, _runtimeModule, className]));
1058 body.add(js.statement(
1059 '#._check = function check_Null(o) {'
1060 ' if (o == null) return o;'
1061 ' return #.check(o, #);'
1062 '}',
1063 [className, _runtimeModule, className]));
1064 return;
1065 }
1066 if (classElem == numClass) {
1067 body.add(js.statement(
1068 '#.is = function is_num(o) { return typeof o == "number"; }',
1069 className));
1070 body.add(js.statement(
1071 '#.as = function as_num(o) {'
1072 ' if (typeof o == "number" || o == null) return o;'
1073 ' return #.as(o, #);'
1074 '}',
1075 [className, _runtimeModule, className]));
1076 body.add(js.statement(
1077 '#._check = function check_num(o) {'
1078 ' if (typeof o == "number" || o == null) return o;'
1079 ' return #.check(o, #);'
1080 '}',
1081 [className, _runtimeModule, className]));
1082 return;
1083 }
1084 if (classElem == boolClass) {
1085 body.add(js.statement(
1086 '#.is = function is_bool(o) { return o === true || o === false; }',
1087 className));
1088 body.add(js.statement(
1089 '#.as = function as_bool(o) {'
1090 ' if (o === true || o === false || o == null) return o;'
1091 ' return #.as(o, #);'
1092 '}',
1093 [className, _runtimeModule, className]));
1094 body.add(js.statement(
1095 '#._check = function check_bool(o) {'
1096 ' if (o === true || o === false || o == null) return o;'
1097 ' return #.check(o, #);'
1098 '}',
1099 [className, _runtimeModule, className]));
1100 return;
1101 }
1102 // TODO(sra): Add special cases for hot tests like `x is html.Element`.
1103
1104 // `instanceof` check is futile for classes that are Interceptor classes.
1105 ClassElement parent = classElem;
1106 while (parent != objectClass) {
1107 if (parent == interceptorClass) {
1108 if (classElem == interceptorClass) {
1109 // Place non-instanceof version of checks on Interceptor. All
1110 // interceptor classes will inherit the methods via ES6 class static
1111 // inheritance.
1112 body.add(_callHelperStatement('addTypeTests(#);', className));
1113
1114 // TODO(sra): We could place on the extension type a pointer to the
1115 // peer constructor and use that for the `instanceof` check, e.g.
1116 //
1117 // if (o instanceof this[_peerConstructor]) return o;
1118 //
1119 } 981 }
1120 return; 982 }
1121 } 983 return null;
1122 parent = parent.type.superclass.element; 984 }
1123 } 985
1124 986 void markSubtypeOf(JS.Expression testSymbol) {
1125 // Choose between 'simple' checks, which are often accelerated by 987 body.add(js.statement('#.prototype[#] = true', [className, testSymbol]));
1126 // `instanceof`, and other checks, which are slowed down by taking time to 988 }
1127 // do an `instanceof` check that is futile or likely futile. 989
1128 // 990 for (var iface in classElem.interfaces) {
1129 // The `instanceof` check is futile for (1) a class that is only used as a 991 var prop = getInterfaceSymbol(iface.element);
1130 // mixin, or (2) is only used as an interface in an `implements` clause, and 992 if (prop != null) markSubtypeOf(prop);
1131 // is likely futile (3) if the class has type parameters, since `Foo` aka 993 }
1132 // `Foo<dynamic>` is not a superclass of `Foo<int>`. The first two are 994
1133 // whole-program properites, but we can check for the last case. 995 if (classElem.library.isDartCore) {
1134 996 if (classElem == objectClass) {
Leaf 2017/08/24 17:19:39 Is there a reason we attach these here instead of
Jennifer Messerly 2017/08/24 18:26:37 Yeah I'm not sure why the existing code does that.
1135 // Since ES6 classes have inheritance of static properties, we need only 997 // Everything is an Object.
1136 // install checks that differ from the parent. 998 body.add(js.statement(
1137 999 '#.is = function is_Object(o) { return true; }', [className]));
1138 bool isSimple(ClassElement classElement) { 1000 body.add(js.statement(
1139 if (classElement.typeParameters.isNotEmpty) return false; 1001 '#.as = function as_Object(o) { return o; }', [className]));
1140 return true; 1002 body.add(js.statement(
1141 } 1003 '#._check = function check_Object(o) { return o; }', [className]));
1142 1004 return null;
1143 assert(classElem != objectClass); 1005 }
1144 bool thisIsSimple = isSimple(classElem); 1006 if (classElem == stringClass) {
1145 bool superIsSimple = isSimple(classElem.type.superclass.element); 1007 body.add(js.statement(
1146 1008 '#.is = function is_String(o) { return typeof o == "string"; }',
1147 if (thisIsSimple == superIsSimple) return; 1009 className));
1148 1010 body.add(js.statement(
1149 if (thisIsSimple) { 1011 '#.as = function as_String(o) {'
1150 body.add(_callHelperStatement('addSimpleTypeTests(#);', className)); 1012 ' if (typeof o == "string" || o == null) return o;'
1151 } else { 1013 ' return #.as(o, #, false);'
1152 body.add(_callHelperStatement('addTypeTests(#);', className)); 1014 '}',
1153 } 1015 [className, _runtimeModule, className]));
1016 body.add(js.statement(
1017 '#._check = function check_String(o) {'
1018 ' if (typeof o == "string" || o == null) return o;'
1019 ' return #.as(o, #, true);'
1020 '}',
1021 [className, _runtimeModule, className]));
1022 return null;
1023 }
1024 if (classElem == functionClass) {
1025 body.add(js.statement(
1026 '#.is = function is_Function(o) { return typeof o == "function"; }',
Leaf 2017/08/24 17:19:39 Does this handle call methods?
Jennifer Messerly 2017/08/24 18:26:37 yup. Callable classes are reified as JS functions
1027 className));
1028 body.add(js.statement(
1029 '#.as = function as_Function(o) {'
1030 ' if (typeof o == "function" || o == null) return o;'
1031 ' return #.as(o, #, false);'
1032 '}',
1033 [className, _runtimeModule, className]));
1034 body.add(js.statement(
1035 '#._check = function check_String(o) {'
1036 ' if (typeof o == "function" || o == null) return o;'
1037 ' return #.as(o, #, true);'
1038 '}',
1039 [className, _runtimeModule, className]));
1040 return null;
1041 }
1042 if (classElem == intClass) {
1043 body.add(js.statement(
1044 '#.is = function is_int(o) {'
1045 ' return typeof o == "number" && Math.floor(o) == o;'
1046 '}',
1047 className));
1048 body.add(js.statement(
1049 '#.as = function as_int(o) {'
1050 ' if ((typeof o == "number" && Math.floor(o) == o) || o == null)'
1051 ' return o;'
1052 ' return #.as(o, #, false);'
1053 '}',
1054 [className, _runtimeModule, className]));
1055 body.add(js.statement(
1056 '#._check = function check_int(o) {'
1057 ' if ((typeof o == "number" && Math.floor(o) == o) || o == null)'
1058 ' return o;'
1059 ' return #.as(o, #, true);'
1060 '}',
1061 [className, _runtimeModule, className]));
1062 return null;
1063 }
1064 if (classElem == nullClass) {
1065 body.add(js.statement(
1066 '#.is = function is_Null(o) { return o == null; }', className));
1067 body.add(js.statement(
1068 '#.as = function as_Null(o) {'
1069 ' if (o == null) return o;'
1070 ' return #.as(o, #, false);'
1071 '}',
1072 [className, _runtimeModule, className]));
1073 body.add(js.statement(
1074 '#._check = function check_Null(o) {'
1075 ' if (o == null) return o;'
1076 ' return #.as(o, #, true);'
1077 '}',
1078 [className, _runtimeModule, className]));
1079 return null;
1080 }
1081 if (classElem == numClass || classElem == doubleClass) {
1082 body.add(js.statement(
1083 '#.is = function is_num(o) { return typeof o == "number"; }',
1084 className));
1085 body.add(js.statement(
1086 '#.as = function as_num(o) {'
1087 ' if (typeof o == "number" || o == null) return o;'
1088 ' return #.as(o, #, false);'
1089 '}',
1090 [className, _runtimeModule, className]));
1091 body.add(js.statement(
1092 '#._check = function check_num(o) {'
1093 ' if (typeof o == "number" || o == null) return o;'
1094 ' return #.as(o, #, true);'
1095 '}',
1096 [className, _runtimeModule, className]));
1097 return null;
1098 }
1099 if (classElem == boolClass) {
1100 body.add(js.statement(
1101 '#.is = function is_bool(o) { return o === true || o === false; }',
1102 className));
1103 body.add(js.statement(
1104 '#.as = function as_bool(o) {'
1105 ' if (o === true || o === false || o == null) return o;'
1106 ' return #.as(o, #, false);'
1107 '}',
1108 [className, _runtimeModule, className]));
1109 body.add(js.statement(
1110 '#._check = function check_bool(o) {'
1111 ' if (o === true || o === false || o == null) return o;'
1112 ' return #.as(o, #, true);'
1113 '}',
1114 [className, _runtimeModule, className]));
1115 return null;
1116 }
1117 }
1118 if (classElem.library.isDartAsync) {
1119 if (classElem == types.futureOrType.element) {
1120 var typeParamT = classElem.typeParameters[0].type;
1121 var tOrFutureOfT = js.call('#.is(o) || #.is(o)', [
1122 _emitType(typeParamT),
1123 _emitType(types.futureType.instantiate([typeParamT]))
1124 ]);
1125 body.add(js.statement('''
1126 #.is = function is_FutureOr(o) {
1127 return #;
1128 }
1129 ''', [className, tOrFutureOfT]));
1130 body.add(js.statement('''
1131 #.as = function as_FutureOr(o) {
1132 if (o == null || #) return o;
1133 return #.castError(o, this, false);
1134 }
1135 ''', [className, tOrFutureOfT, _runtimeModule]));
1136 body.add(js.statement('''
1137 #._check = function check_FutureOr(o) {
1138 if (o == null || #) return o;
1139 return #.castError(o, this, true);
Leaf 2017/08/24 17:19:39 Is there a reason the other cases above go through
Jennifer Messerly 2017/08/24 18:26:37 yeah, I'm trying to simplify things and have the c
1140 }
1141 ''', [className, tOrFutureOfT, _runtimeModule]));
1142 return null;
1143 }
1144 }
1145
1146 body.add(_callHelperStatement('addTypeTests(#);', [className]));
1147
1148 if (classElem.typeParameters.isEmpty) return null;
1149
1150 // For generics, testing against the default instantiation is common,
1151 // so optimize that.
1152 var isClassSymbol = getInterfaceSymbol(classElem);
1153 if (isClassSymbol == null) {
1154 // TODO(jmesserly): we could export these symbols, if we want to mark
1155 // implemented interfaces for user-defined classes.
1156 var id = new JS.TemporaryId("_is_${classElem.name}_default");
1157 _moduleItems.add(
1158 js.statement('const # = Symbol(#);', [id, js.string(id.name, "'")]));
1159 isClassSymbol = id;
1160 }
1161 // Marking every generic type instantiation as a subtype of its default
1162 // instantiation.
1163 markSubtypeOf(isClassSymbol);
1164
1165 // Define the type tests on the default instantiation to check for that
1166 // marker.
1167 var defaultInst = _emitTopLevelName(classElem);
1168
1169 // Return this `addTypeTests` call so we can emit it outside of the generic
1170 // type parameter scope.
1171 return _callHelperStatement(
1172 'addTypeTests(#, #);', [defaultInst, isClassSymbol]);
1154 } 1173 }
1155 1174
1156 void _emitSuperHelperSymbols(List<JS.Statement> body) { 1175 void _emitSuperHelperSymbols(List<JS.Statement> body) {
1157 for (var id in _superHelpers.values.map((m) => m.name as JS.TemporaryId)) { 1176 for (var id in _superHelpers.values.map((m) => m.name as JS.TemporaryId)) {
1158 body.add(js.statement('const # = Symbol(#)', [id, js.string(id.name)])); 1177 body.add(js.statement('const # = Symbol(#)', [id, js.string(id.name)]));
1159 } 1178 }
1160 _superHelpers.clear(); 1179 _superHelpers.clear();
1161 } 1180 }
1162 1181
1163 void _emitVirtualFieldSymbols( 1182 void _emitVirtualFieldSymbols(
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
1275 } 1294 }
1276 1295
1277 var genericCall = _callHelper('generic(#)', [genericArgs]); 1296 var genericCall = _callHelper('generic(#)', [genericArgs]);
1278 1297
1279 if (element.library.isDartAsync && 1298 if (element.library.isDartAsync &&
1280 (element.name == "Future" || element.name == "_Future")) { 1299 (element.name == "Future" || element.name == "_Future")) {
1281 genericCall = _callHelper('flattenFutures(#)', [genericCall]); 1300 genericCall = _callHelper('flattenFutures(#)', [genericCall]);
1282 } 1301 }
1283 var genericDef = js.statement( 1302 var genericDef = js.statement(
1284 '# = #;', [_emitTopLevelName(element, suffix: r'$'), genericCall]); 1303 '# = #;', [_emitTopLevelName(element, suffix: r'$'), genericCall]);
1304 // TODO(jmesserly): this should be instantiate to bounds
1285 var dynType = fillDynamicTypeArgs(element.type); 1305 var dynType = fillDynamicTypeArgs(element.type);
1286 var genericInst = _emitType(dynType, lowerGeneric: true); 1306 var genericInst = _emitType(dynType, lowerGeneric: true);
1287 return js.statement( 1307 return js.statement(
1288 '{ #; # = #; }', [genericDef, _emitTopLevelName(element), genericInst]); 1308 '{ #; # = #; }', [genericDef, _emitTopLevelName(element), genericInst]);
1289 } 1309 }
1290 1310
1291 bool _deferIfNeeded(DartType type, ClassElement current) { 1311 bool _deferIfNeeded(DartType type, ClassElement current) {
1292 if (type is ParameterizedType) { 1312 if (type is ParameterizedType) {
1293 var typeArguments = type.typeArguments; 1313 var typeArguments = type.typeArguments;
1294 for (var typeArg in typeArguments) { 1314 for (var typeArg in typeArguments) {
(...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after
1833 // We can ignore `noSuchMethod` because: 1853 // We can ignore `noSuchMethod` because:
1834 // * `dynamic d; d();` without a declared `call` method is handled by dcall. 1854 // * `dynamic d; d();` without a declared `call` method is handled by dcall.
1835 // * for `class C implements Callable { noSuchMethod(i) { ... } }` we find 1855 // * for `class C implements Callable { noSuchMethod(i) { ... } }` we find
1836 // the `call` method on the `Callable` interface. 1856 // the `call` method on the `Callable` interface.
1837 var callMethod = classElem.type.lookUpInheritedGetterOrMethod('call'); 1857 var callMethod = classElem.type.lookUpInheritedGetterOrMethod('call');
1838 bool isCallable = callMethod is PropertyAccessorElement 1858 bool isCallable = callMethod is PropertyAccessorElement
1839 ? callMethod.returnType is FunctionType 1859 ? callMethod.returnType is FunctionType
1840 : callMethod != null; 1860 : callMethod != null;
1841 1861
1842 var body = <JS.Statement>[]; 1862 var body = <JS.Statement>[];
1863 if (isCallable) {
1864 // Our class instances will have JS `typeof this == "function"`,
1865 // so make sure to attach the runtime type information the same way
1866 // we would do it for function types.
1867 body.add(js.statement('#.prototype[#] = #;',
1868 [className, _callHelper('_runtimeType'), className]));
1869 }
1870
1843 void addConstructor(ConstructorElement element, JS.Expression jsCtor) { 1871 void addConstructor(ConstructorElement element, JS.Expression jsCtor) {
1844 var ctorName = _constructorName(element); 1872 var ctorName = _constructorName(element);
1845 if (JS.invalidStaticFieldName(element.name)) { 1873 if (JS.invalidStaticFieldName(element.name)) {
1846 jsCtor = 1874 jsCtor =
1847 _callHelper('defineValue(#, #, #)', [className, ctorName, jsCtor]); 1875 _callHelper('defineValue(#, #, #)', [className, ctorName, jsCtor]);
1848 } else { 1876 } else {
1849 jsCtor = js.call('#.# = #', [className, ctorName, jsCtor]); 1877 jsCtor = js.call('#.# = #', [className, ctorName, jsCtor]);
1850 } 1878 }
1851 body.add(js.statement('#.prototype = #.prototype;', [jsCtor, className])); 1879 body.add(js.statement('#.prototype = #.prototype;', [jsCtor, className]));
1852 } 1880 }
(...skipping 4139 matching lines...) Expand 10 before | Expand all | Expand 10 after
5992 if (targetIdentifier.staticElement is! PrefixElement) return false; 6020 if (targetIdentifier.staticElement is! PrefixElement) return false;
5993 var prefix = targetIdentifier.staticElement as PrefixElement; 6021 var prefix = targetIdentifier.staticElement as PrefixElement;
5994 6022
5995 // The library the prefix is referring to must come from a deferred import. 6023 // The library the prefix is referring to must come from a deferred import.
5996 var containingLibrary = resolutionMap 6024 var containingLibrary = resolutionMap
5997 .elementDeclaredByCompilationUnit(target.root as CompilationUnit) 6025 .elementDeclaredByCompilationUnit(target.root as CompilationUnit)
5998 .library; 6026 .library;
5999 var imports = containingLibrary.getImportsWithPrefix(prefix); 6027 var imports = containingLibrary.getImportsWithPrefix(prefix);
6000 return imports.length == 1 && imports[0].isDeferred; 6028 return imports.length == 1 && imports[0].isDeferred;
6001 } 6029 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698