| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of _js_helper; | 5 part of _js_helper; |
| 6 | 6 |
| 7 setRuntimeTypeInfo(target, typeInfo) { | 7 setRuntimeTypeInfo(target, typeInfo) { |
| 8 assert(typeInfo == null || isJsArray(typeInfo)); | 8 assert(typeInfo == null || isJsArray(typeInfo)); |
| 9 // We have to check for null because factories may return null. | 9 // We have to check for null because factories may return null. |
| 10 if (target != null) JS('var', r'#.$builtinTypeInfo = #', target, typeInfo); | 10 if (target != null) JS('var', r'#.$builtinTypeInfo = #', target, typeInfo); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 * Parameters: | 112 * Parameters: |
| 113 * - [isField]: the name of the flag/function to check if the object | 113 * - [isField]: the name of the flag/function to check if the object |
| 114 * is of the correct class. | 114 * is of the correct class. |
| 115 * - [checks]: the (JavaScript) list of type representations for the | 115 * - [checks]: the (JavaScript) list of type representations for the |
| 116 * arguments to check against. | 116 * arguments to check against. |
| 117 * - [asField]: the name of the function that transforms the type | 117 * - [asField]: the name of the function that transforms the type |
| 118 * arguments of [objects] to an instance of the class that we check | 118 * arguments of [objects] to an instance of the class that we check |
| 119 * against. | 119 * against. |
| 120 */ | 120 */ |
| 121 bool checkSubtype(Object object, String isField, List checks, String asField) { | 121 bool checkSubtype(Object object, String isField, List checks, String asField) { |
| 122 if (object == null) return false; | 122 if (object == null) return true; |
| 123 var arguments = getRuntimeTypeInfo(object); | 123 var arguments = getRuntimeTypeInfo(object); |
| 124 // Interceptor is needed for JSArray and native classes. | 124 // Interceptor is needed for JSArray and native classes. |
| 125 // TODO(sra): It could be a more specialized interceptor since [object] is not | 125 // TODO(sra): It could be a more specialized interceptor since [object] is not |
| 126 // `null` or a primitive. | 126 // `null` or a primitive. |
| 127 // TODO(9586): Move type info for static functions onto an interceptor. | 127 // TODO(9586): Move type info for static functions onto an interceptor. |
| 128 var interceptor = isJsFunction(object) ? object : getInterceptor(object); | 128 var interceptor = getInterceptor(object); |
| 129 bool isSubclass = getField(interceptor, isField); | 129 bool isSubclass = getField(interceptor, isField); |
| 130 // When we read the field and it is not there, [isSubclass] will be [:null:]. | 130 // When we read the field and it is not there, [isSubclass] will be [:null:]. |
| 131 if (isSubclass == null || !isSubclass) return false; | 131 if (isSubclass == null || !isSubclass) return false; |
| 132 // Should the asField function be passed the receiver? | 132 // Should the asField function be passed the receiver? |
| 133 var substitution = getField(interceptor, asField); | 133 var substitution = getField(interceptor, asField); |
| 134 return checkArguments(substitution, arguments, checks); | 134 return checkArguments(substitution, arguments, checks); |
| 135 } | 135 } |
| 136 | 136 |
| 137 Object assertSubtype(Object object, String isField, List checks, |
| 138 String asField) { |
| 139 if (!checkSubtype(object, isField, checks, asField)) { |
| 140 // Shorten the field name to the class name and append the textual |
| 141 // representation of the type arguments. |
| 142 int prefixLength = JS_OPERATOR_IS_PREFIX().length; |
| 143 String typeName = '${isField.substring(prefixLength, isField.length)}' |
| 144 '${joinArguments(checks, 0)}'; |
| 145 throw new TypeErrorImplementation(object, typeName); |
| 146 } |
| 147 return object; |
| 148 } |
| 149 |
| 137 /** | 150 /** |
| 138 * Check that the types in the list [arguments] are subtypes of the types in | 151 * Check that the types in the list [arguments] are subtypes of the types in |
| 139 * list [checks] (at the respective positions), possibly applying [substitution] | 152 * list [checks] (at the respective positions), possibly applying [substitution] |
| 140 * to the arguments before the check. | 153 * to the arguments before the check. |
| 141 * | 154 * |
| 142 * See [:RuntimeTypes.getSubtypeSubstitution:] for a description of the possible | 155 * See [:RuntimeTypes.getSubtypeSubstitution:] for a description of the possible |
| 143 * values for [substitution]. | 156 * values for [substitution]. |
| 144 */ | 157 */ |
| 145 bool checkArguments(var substitution, var arguments, var checks) { | 158 bool checkArguments(var substitution, var arguments, var checks) { |
| 146 return areSubtypes(substitute(substitution, arguments), checks); | 159 return areSubtypes(substitute(substitution, arguments), checks); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 167 return isJsArray(type) ? JS('var', r'#.slice(1)', type) : null; | 180 return isJsArray(type) ? JS('var', r'#.slice(1)', type) : null; |
| 168 } | 181 } |
| 169 | 182 |
| 170 getField(var object, var name) => JS('var', r'#[#]', object, name); | 183 getField(var object, var name) => JS('var', r'#[#]', object, name); |
| 171 | 184 |
| 172 /** | 185 /** |
| 173 * Tests whether the Dart object [o] is a subtype of the runtime type | 186 * Tests whether the Dart object [o] is a subtype of the runtime type |
| 174 * representation [t], which is a type representation as described in the | 187 * representation [t], which is a type representation as described in the |
| 175 * comment on [isSubtype]. | 188 * comment on [isSubtype]. |
| 176 */ | 189 */ |
| 177 bool objectIsSubtype(Object o, var t) { | 190 bool checkSubtypeOfRuntimeType(Object o, var t) { |
| 178 if (JS('bool', '# == null', o) || JS('bool', '# == null', t)) return true; | 191 if (JS('bool', '# == null', o) || JS('bool', '# == null', t)) return true; |
| 179 // Get the runtime type information from the object here, because we may | 192 // Get the runtime type information from the object here, because we may |
| 180 // overwrite o with the interceptor below. | 193 // overwrite o with the interceptor below. |
| 181 var rti = getRuntimeTypeInfo(o); | 194 var rti = getRuntimeTypeInfo(o); |
| 182 // Check for native objects and use the interceptor instead of the object. | 195 // Check for native objects and use the interceptor instead of the object. |
| 183 // TODO(9586): Move type info for static functions onto an interceptor. | 196 // TODO(9586): Move type info for static functions onto an interceptor. |
| 184 o = isJsFunction(o) ? o : getInterceptor(o); | 197 o = isJsFunction(o) ? o : getInterceptor(o); |
| 185 // We can use the object as its own type representation because we install | 198 // We can use the object as its own type representation because we install |
| 186 // the subtype flags and the substitution on the prototype, so they are | 199 // the subtype flags and the substitution on the prototype, so they are |
| 187 // properties of the object in JS. | 200 // properties of the object in JS. |
| 188 var type; | 201 var type; |
| 189 if (JS('bool', '# != null', rti)) { | 202 if (JS('bool', '# != null', rti)) { |
| 190 // If the type has type variables (that is, [:rti != null:]), make a copy of | 203 // If the type has type variables (that is, [:rti != null:]), make a copy of |
| 191 // the type arguments and insert [o] in the first position to create a | 204 // the type arguments and insert [o] in the first position to create a |
| 192 // compound type representation. | 205 // compound type representation. |
| 193 type = JS('List', '#.slice()', rti); | 206 type = JS('List', '#.slice()', rti); |
| 194 JS('', '#.splice(0, 0, #)', type, o); | 207 JS('', '#.splice(0, 0, #)', type, o); |
| 195 } else { | 208 } else { |
| 196 // Use the object as representation of the raw type. | 209 // Use the object as representation of the raw type. |
| 197 type = o; | 210 type = o; |
| 198 } | 211 } |
| 199 return isSubtype(type, t); | 212 return isSubtype(type, t); |
| 200 } | 213 } |
| 201 | 214 |
| 215 Object assertSubtypeOfRuntimeType(Object object, var type) { |
| 216 if (!checkSubtypeOfRuntimeType(object, type)) { |
| 217 throw new TypeErrorImplementation(object, runtimeTypeToString(type)); |
| 218 } |
| 219 return object; |
| 220 } |
| 221 |
| 202 /** | 222 /** |
| 203 * Check whether the type represented by [s] is a subtype of the type | 223 * Check whether the type represented by [s] is a subtype of the type |
| 204 * represented by [t]. | 224 * represented by [t]. |
| 205 * | 225 * |
| 206 * Type representations can be: | 226 * Type representations can be: |
| 207 * 1) a JavaScript constructor for a class C: the represented type is the raw | 227 * 1) a JavaScript constructor for a class C: the represented type is the raw |
| 208 * type C. | 228 * type C. |
| 209 * 2) a Dart object: this is the interceptor instance for a native type. | 229 * 2) a Dart object: this is the interceptor instance for a native type. |
| 210 * 3) a JavaScript object: this represents a class for which there is no | 230 * 3) a JavaScript object: this represents a class for which there is no |
| 211 * JavaScript constructor, because it is only used in type arguments or it | 231 * JavaScript constructor, because it is only used in type arguments or it |
| 212 * is native. The represented type is the raw type of this class. | 232 * is native. The represented type is the raw type of this class. |
| 213 * 4) a JavaScript array: the first entry is of type 1, 2 or 3 and contains the | 233 * 4) a JavaScript array: the first entry is of type 1, 2 or 3 and contains the |
| 214 * subtyping flags and the substitution of the type and the rest of the | 234 * subtyping flags and the substitution of the type and the rest of the |
| 215 * array are the type arguments. | 235 * array are the type arguments. |
| 216 * 5) [:null:]: the dynamic type. | 236 * 5) [:null:]: the dynamic type. |
| 217 */ | 237 */ |
| 218 bool isSubtype(var s, var t) { | 238 bool isSubtype(var s, var t) { |
| 219 // If either type is dynamic, [s] is a subtype of [t]. | 239 // If either type is dynamic, [s] is a subtype of [t]. |
| 220 if (JS('bool', '# == null', s) || JS('bool', '# == null', t)) return true; | 240 if (JS('bool', '# == null', s) || JS('bool', '# == null', t)) return true; |
| 221 // Subtyping is reflexive. | 241 // Subtyping is reflexive. |
| 222 if (JS('bool', '# === #', s, t)) return true; | 242 if (JS('bool', '# === #', s, t)) return true; |
| 223 // Get the object describing the class and check for the subtyping flag | 243 // Get the object describing the class and check for the subtyping flag |
| 224 // constructed from the type of [t]. | 244 // constructed from the type of [t]. |
| 225 var typeOfS = isJsArray(s) ? s[0] : s; | 245 var typeOfS = isJsArray(s) ? s[0] : s; |
| 226 var typeOfT = isJsArray(t) ? t[0] : t; | 246 var typeOfT = isJsArray(t) ? t[0] : t; |
| 247 // TODO(johnniwinther): replace this with the real function subtype test. |
| 248 if (JS('bool', '#.func', s) == true || JS('bool', '#.func', t) == true ) { |
| 249 return true; |
| 250 } |
| 227 // Check for a subtyping flag. | 251 // Check for a subtyping flag. |
| 228 var test = '${JS_OPERATOR_IS_PREFIX()}${runtimeTypeToString(typeOfT)}'; | 252 var test = '${JS_OPERATOR_IS_PREFIX()}${runtimeTypeToString(typeOfT)}'; |
| 229 if (getField(typeOfS, test) == null) return false; | 253 if (getField(typeOfS, test) == null) return false; |
| 230 // Get the necessary substitution of the type arguments, if there is one. | 254 // Get the necessary substitution of the type arguments, if there is one. |
| 231 var substitution; | 255 var substitution; |
| 232 if (JS('bool', '# !== #', typeOfT, typeOfS)) { | 256 if (JS('bool', '# !== #', typeOfT, typeOfS)) { |
| 233 var field = '${JS_OPERATOR_AS_PREFIX()}${runtimeTypeToString(typeOfT)}'; | 257 var field = '${JS_OPERATOR_AS_PREFIX()}${runtimeTypeToString(typeOfT)}'; |
| 234 substitution = getField(typeOfS, field); | 258 substitution = getField(typeOfS, field); |
| 235 } | 259 } |
| 236 // The class of [s] is a subclass of the class of [t]. If [s] has no type | 260 // The class of [s] is a subclass of the class of [t]. If [s] has no type |
| 237 // arguments and no substitution, it is used as raw type. If [t] has no | 261 // arguments and no substitution, it is used as raw type. If [t] has no |
| 238 // type arguments, it used as a raw type. In both cases, [s] is a subtype | 262 // type arguments, it used as a raw type. In both cases, [s] is a subtype |
| 239 // of [t]. | 263 // of [t]. |
| 240 if ((!isJsArray(s) && JS('bool', '# == null', substitution)) || | 264 if ((!isJsArray(s) && JS('bool', '# == null', substitution)) || |
| 241 !isJsArray(t)) { | 265 !isJsArray(t)) { |
| 242 return true; | 266 return true; |
| 243 } | 267 } |
| 244 // Recursively check the type arguments. | 268 // Recursively check the type arguments. |
| 245 return checkArguments(substitution, getArguments(s), getArguments(t)); | 269 return checkArguments(substitution, getArguments(s), getArguments(t)); |
| 246 } | 270 } |
| 247 | 271 |
| 248 createRuntimeType(String name) => new TypeImpl(name); | 272 createRuntimeType(String name) => new TypeImpl(name); |
| OLD | NEW |