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 /** | 5 /** |
6 * This part contains helpers for supporting runtime type information. | 6 * This part contains helpers for supporting runtime type information. |
7 * | 7 * |
8 * The helper use a mixture of Dart and JavaScript objects. To indicate which is | 8 * The helper use a mixture of Dart and JavaScript objects. To indicate which is |
9 * used where we adopt the scheme of using explicit type annotation for Dart | 9 * used where we adopt the scheme of using explicit type annotation for Dart |
10 * objects and 'var' or omitted return type for JavaScript objects. | 10 * objects and 'var' or omitted return type for JavaScript objects. |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
154 return 'dynamic'; | 154 return 'dynamic'; |
155 } else if (isJsArray(type)) { | 155 } else if (isJsArray(type)) { |
156 // A list representing a type with arguments. | 156 // A list representing a type with arguments. |
157 return getRuntimeTypeAsString(type); | 157 return getRuntimeTypeAsString(type); |
158 } else if (isJsFunction(type)) { | 158 } else if (isJsFunction(type)) { |
159 // A reference to the constructor. | 159 // A reference to the constructor. |
160 return getConstructorName(type); | 160 return getConstructorName(type); |
161 } else if (type is int) { | 161 } else if (type is int) { |
162 return type.toString(); | 162 return type.toString(); |
163 } else { | 163 } else { |
| 164 // TODO(ahe): Handle function types, and be sure to always return a string. |
164 return null; | 165 return null; |
165 } | 166 } |
166 } | 167 } |
167 | 168 |
168 /** | 169 /** |
169 * Creates a comma-separated string of human-readable representations of the | 170 * Creates a comma-separated string of human-readable representations of the |
170 * type representations in the JavaScript array [types] starting at index | 171 * type representations in the JavaScript array [types] starting at index |
171 * [startIndex]. | 172 * [startIndex]. |
172 */ | 173 */ |
173 String joinArguments(var types, int startIndex) { | 174 String joinArguments(var types, int startIndex) { |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 | 320 |
320 int len = getLength(s); | 321 int len = getLength(s); |
321 for (int i = 0; i < len; i++) { | 322 for (int i = 0; i < len; i++) { |
322 if (!isSubtype(getIndex(s, i), getIndex(t, i))) { | 323 if (!isSubtype(getIndex(s, i), getIndex(t, i))) { |
323 return false; | 324 return false; |
324 } | 325 } |
325 } | 326 } |
326 return true; | 327 return true; |
327 } | 328 } |
328 | 329 |
| 330 // TODO(ahe): Remove this. |
329 Object functionSubtypeCast(Object object, String signatureName, | 331 Object functionSubtypeCast(Object object, String signatureName, |
330 String contextName, var context, | 332 String contextName, var context, |
331 var typeArguments) { | 333 var typeArguments) { |
332 if (!checkFunctionSubtype(object, signatureName, | 334 if (!checkFunctionSubtype(object, signatureName, |
333 contextName, context, typeArguments)) { | 335 contextName, context, typeArguments)) { |
334 String actualType = Primitives.objectTypeName(object); | 336 String actualType = Primitives.objectTypeName(object); |
335 // TODO(johnniwinther): Provide better function type naming. | 337 // TODO(johnniwinther): Provide better function type naming. |
336 String typeName = signatureName; | 338 String typeName = signatureName; |
337 throw new CastErrorImplementation(actualType, typeName); | 339 throw new CastErrorImplementation(actualType, typeName); |
338 } | 340 } |
339 return object; | 341 return object; |
340 } | 342 } |
341 | 343 |
| 344 // TODO(ahe): Remove this. |
342 Object assertFunctionSubtype(Object object, String signatureName, | 345 Object assertFunctionSubtype(Object object, String signatureName, |
343 String contextName, var context, | 346 String contextName, var context, |
344 var typeArguments) { | 347 var typeArguments) { |
345 if (!checkFunctionSubtype(object, signatureName, | 348 if (!checkFunctionSubtype(object, signatureName, |
346 contextName, context, typeArguments)) { | 349 contextName, context, typeArguments)) { |
347 // TODO(johnniwinther): Provide better function type naming. | 350 // TODO(johnniwinther): Provide better function type naming. |
348 String typeName = signatureName; | 351 String typeName = signatureName; |
349 throw new TypeErrorImplementation(object, typeName); | 352 throw new TypeErrorImplementation(object, typeName); |
350 } | 353 } |
351 return object; | 354 return object; |
352 } | 355 } |
353 | 356 |
354 /** | 357 /** |
355 * Checks that the type of [target] is a subtype of the function type denoted by | 358 * Checks that the type of [target] is a subtype of the function type denoted by |
356 * [signatureName]. If the type contains type variables, [contextName] holds the | 359 * [signatureName]. If the type contains type variables, [contextName] holds the |
357 * name of the class where these were declared and either [context] holds the | 360 * name of the class where these were declared and either [context] holds the |
358 * object in which the runtime values of these can be found or [typeArguments] | 361 * object in which the runtime values of these can be found or [typeArguments] |
359 * contains these values as a list of runtime type information. | 362 * contains these values as a list of runtime type information. |
360 */ | 363 */ |
| 364 // TODO(ahe): Remove this. |
361 bool checkFunctionSubtype(var target, String signatureName, | 365 bool checkFunctionSubtype(var target, String signatureName, |
362 String contextName, var context, | 366 String contextName, var context, |
363 var typeArguments) { | 367 var typeArguments) { |
364 if (isNull(target)) return true; | 368 if (isNull(target)) return true; |
365 var interceptor = getInterceptor(target); | 369 var interceptor = getInterceptor(target); |
366 if (hasField(interceptor, '${JS_OPERATOR_IS_PREFIX()}_$signatureName')) { | 370 if (hasField(interceptor, '${JS_OPERATOR_IS_PREFIX()}_$signatureName')) { |
367 return true; | 371 return true; |
368 } | 372 } |
369 var signatureLocation = JS_CURRENT_ISOLATE(); | 373 var signatureLocation = JS_CURRENT_ISOLATE(); |
370 if (isNotNull(contextName)) { | 374 if (isNotNull(contextName)) { |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 if (getConstructorName(t) == JS_FUNCTION_CLASS_NAME() && | 497 if (getConstructorName(t) == JS_FUNCTION_CLASS_NAME() && |
494 hasField(s, '${JS_FUNCTION_TYPE_TAG()}')) { | 498 hasField(s, '${JS_FUNCTION_TYPE_TAG()}')) { |
495 return true; | 499 return true; |
496 } | 500 } |
497 // Get the object describing the class and check for the subtyping flag | 501 // Get the object describing the class and check for the subtyping flag |
498 // constructed from the type of [t]. | 502 // constructed from the type of [t]. |
499 var typeOfS = isJsArray(s) ? getIndex(s, 0) : s; | 503 var typeOfS = isJsArray(s) ? getIndex(s, 0) : s; |
500 var typeOfT = isJsArray(t) ? getIndex(t, 0) : t; | 504 var typeOfT = isJsArray(t) ? getIndex(t, 0) : t; |
501 // Check for a subtyping flag. | 505 // Check for a subtyping flag. |
502 var name = runtimeTypeToString(typeOfT); | 506 var name = runtimeTypeToString(typeOfT); |
503 var test = '${JS_OPERATOR_IS_PREFIX()}${name}'; | |
504 if (hasNoField(typeOfS, test)) return false; | |
505 // Get the necessary substitution of the type arguments, if there is one. | 507 // Get the necessary substitution of the type arguments, if there is one. |
506 var substitution; | 508 var substitution; |
507 if (isNotIdentical(typeOfT, typeOfS)) { | 509 if (isNotIdentical(typeOfT, typeOfS)) { |
| 510 var test = '${JS_OPERATOR_IS_PREFIX()}${name}'; |
| 511 if (hasNoField(typeOfS, test)) return false; |
508 var field = '${JS_OPERATOR_AS_PREFIX()}${runtimeTypeToString(typeOfT)}'; | 512 var field = '${JS_OPERATOR_AS_PREFIX()}${runtimeTypeToString(typeOfT)}'; |
509 substitution = getField(typeOfS, field); | 513 substitution = getField(typeOfS, field); |
510 } | 514 } |
511 // The class of [s] is a subclass of the class of [t]. If [s] has no type | 515 // The class of [s] is a subclass of the class of [t]. If [s] has no type |
512 // arguments and no substitution, it is used as raw type. If [t] has no | 516 // arguments and no substitution, it is used as raw type. If [t] has no |
513 // type arguments, it used as a raw type. In both cases, [s] is a subtype | 517 // type arguments, it used as a raw type. In both cases, [s] is a subtype |
514 // of [t]. | 518 // of [t]. |
515 if ((!isJsArray(s) && isNull(substitution)) || !isJsArray(t)) { | 519 if ((!isJsArray(s) && isNull(substitution)) || !isJsArray(t)) { |
516 return true; | 520 return true; |
517 } | 521 } |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
733 * and [t] are Dart values. | 737 * and [t] are Dart values. |
734 */ | 738 */ |
735 bool isIdentical(var s, var t) => JS('bool', '# === #', s, t); | 739 bool isIdentical(var s, var t) => JS('bool', '# === #', s, t); |
736 | 740 |
737 /** | 741 /** |
738 * Returns [:true:] if the JavaScript values [s] and [t] are not identical. We | 742 * Returns [:true:] if the JavaScript values [s] and [t] are not identical. We |
739 * use this helper to avoid generating code under the invalid assumption that | 743 * use this helper to avoid generating code under the invalid assumption that |
740 * [s] and [t] are Dart values. | 744 * [s] and [t] are Dart values. |
741 */ | 745 */ |
742 bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t); | 746 bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t); |
OLD | NEW |