| 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 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 * See the comment in the beginning of this file for a description of type | 383 * See the comment in the beginning of this file for a description of type |
| 384 * representations. | 384 * representations. |
| 385 */ | 385 */ |
| 386 bool checkSubtypeOfRuntimeType(o, t) { | 386 bool checkSubtypeOfRuntimeType(o, t) { |
| 387 if (o == null) return isSupertypeOfNull(t); | 387 if (o == null) return isSupertypeOfNull(t); |
| 388 if (t == null) return true; | 388 if (t == null) return true; |
| 389 // Get the runtime type information from the object here, because we may | 389 // Get the runtime type information from the object here, because we may |
| 390 // overwrite o with the interceptor below. | 390 // overwrite o with the interceptor below. |
| 391 var rti = getRuntimeTypeInfo(o); | 391 var rti = getRuntimeTypeInfo(o); |
| 392 o = getInterceptor(o); | 392 o = getInterceptor(o); |
| 393 var type = JS('', '#.constructor', o); | 393 // We can use the object as its own type representation because we install |
| 394 var type; |
| 394 if (rti != null) { | 395 if (rti != null) { |
| 395 // If the type has type variables (that is, `rti != null`), make a copy of | 396 // If the type has type variables (that is, `rti != null`), make a copy of |
| 396 // the type arguments and insert [o] in the first position to create a | 397 // the type arguments and insert [o] in the first position to create a |
| 397 // compound type representation. | 398 // compound type representation. |
| 398 rti = JS('JSExtendableArray', '#.slice()', rti); // Make a copy. | 399 type = JS('JSExtendableArray', '#.slice()', rti); |
| 399 JS('', '#.splice(0, 0, #)', rti, type); // Insert type at position 0. | 400 JS('', '#.splice(0, 0, #)', type, o); |
| 400 type = rti; | 401 } else { |
| 401 } else if (hasField(t, '${JS_FUNCTION_TYPE_TAG()}')) { | 402 // Use the object as representation of the raw type. |
| 402 // Functions are treated specially and have their type information stored | 403 type = o; |
| 403 // directly in the instance. | |
| 404 var signatureName = | |
| 405 '${JS_OPERATOR_IS_PREFIX()}_${getField(t, JS_FUNCTION_TYPE_TAG())}'; | |
| 406 if (hasField(o, signatureName)) return true; | |
| 407 var targetSignatureFunction = getField(o, '${JS_SIGNATURE_NAME()}'); | |
| 408 if (targetSignatureFunction == null) return false; | |
| 409 type = invokeOn(targetSignatureFunction, o, null); | |
| 410 return isFunctionSubtype(type, t); | |
| 411 } | 404 } |
| 412 return isSubtype(type, t); | 405 return isSubtype(type, t); |
| 413 } | 406 } |
| 414 | 407 |
| 415 Object subtypeOfRuntimeTypeCast(Object object, var type) { | 408 Object subtypeOfRuntimeTypeCast(Object object, var type) { |
| 416 if (object != null && !checkSubtypeOfRuntimeType(object, type)) { | 409 if (object != null && !checkSubtypeOfRuntimeType(object, type)) { |
| 417 String actualType = Primitives.objectTypeName(object); | 410 String actualType = Primitives.objectTypeName(object); |
| 418 throw new CastErrorImplementation(actualType, runtimeTypeToString(type)); | 411 throw new CastErrorImplementation(actualType, runtimeTypeToString(type)); |
| 419 } | 412 } |
| 420 return object; | 413 return object; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 434 getArguments(var type) { | 427 getArguments(var type) { |
| 435 return isJsArray(type) ? JS('var', r'#.slice(1)', type) : null; | 428 return isJsArray(type) ? JS('var', r'#.slice(1)', type) : null; |
| 436 } | 429 } |
| 437 | 430 |
| 438 /** | 431 /** |
| 439 * Checks whether the type represented by the type representation [s] is a | 432 * Checks whether the type represented by the type representation [s] is a |
| 440 * subtype of the type represented by the type representation [t]. | 433 * subtype of the type represented by the type representation [t]. |
| 441 * | 434 * |
| 442 * See the comment in the beginning of this file for a description of type | 435 * See the comment in the beginning of this file for a description of type |
| 443 * representations. | 436 * representations. |
| 444 * | |
| 445 * The arguments [s] and [t] must be types, usually represented by the | |
| 446 * constructor of the class, or an array (for generic types). | |
| 447 */ | 437 */ |
| 448 bool isSubtype(var s, var t) { | 438 bool isSubtype(var s, var t) { |
| 449 // Subtyping is reflexive. | 439 // Subtyping is reflexive. |
| 450 if (isIdentical(s, t)) return true; | 440 if (isIdentical(s, t)) return true; |
| 451 // If either type is dynamic, [s] is a subtype of [t]. | 441 // If either type is dynamic, [s] is a subtype of [t]. |
| 452 if (s == null || t == null) return true; | 442 if (s == null || t == null) return true; |
| 453 if (hasField(t, '${JS_FUNCTION_TYPE_TAG()}')) { | 443 if (hasField(t, '${JS_FUNCTION_TYPE_TAG()}')) { |
| 444 if (hasNoField(s, '${JS_FUNCTION_TYPE_TAG()}')) { |
| 445 var signatureName = |
| 446 '${JS_OPERATOR_IS_PREFIX()}_${getField(t, JS_FUNCTION_TYPE_TAG())}'; |
| 447 if (hasField(s, signatureName)) return true; |
| 448 var targetSignatureFunction = getField(s, '${JS_SIGNATURE_NAME()}'); |
| 449 if (targetSignatureFunction == null) return false; |
| 450 s = invokeOn(targetSignatureFunction, s, null); |
| 451 } |
| 454 return isFunctionSubtype(s, t); | 452 return isFunctionSubtype(s, t); |
| 455 } | 453 } |
| 456 // Check function types against the Function class. | 454 // Check function types against the Function class. |
| 457 if (hasField(s, '${JS_FUNCTION_TYPE_TAG()}')) { | 455 if (getConstructorName(t) == JS_FUNCTION_CLASS_NAME() && |
| 458 return getConstructorName(t) == JS_FUNCTION_CLASS_NAME(); | 456 hasField(s, '${JS_FUNCTION_TYPE_TAG()}')) { |
| 457 return true; |
| 459 } | 458 } |
| 460 | |
| 461 // Get the object describing the class and check for the subtyping flag | 459 // Get the object describing the class and check for the subtyping flag |
| 462 // constructed from the type of [t]. | 460 // constructed from the type of [t]. |
| 463 var typeOfS = isJsArray(s) ? getIndex(s, 0) : s; | 461 var typeOfS = isJsArray(s) ? getIndex(s, 0) : s; |
| 464 var typeOfT = isJsArray(t) ? getIndex(t, 0) : t; | 462 var typeOfT = isJsArray(t) ? getIndex(t, 0) : t; |
| 465 // Check for a subtyping flag. | 463 // Check for a subtyping flag. |
| 466 var name = runtimeTypeToString(typeOfT); | 464 var name = runtimeTypeToString(typeOfT); |
| 467 // Get the necessary substitution of the type arguments, if there is one. | 465 // Get the necessary substitution of the type arguments, if there is one. |
| 468 var substitution; | 466 var substitution; |
| 469 if (isNotIdentical(typeOfT, typeOfS)) { | 467 if (isNotIdentical(typeOfT, typeOfS)) { |
| 470 var test = '${JS_OPERATOR_IS_PREFIX()}${name}'; | 468 var test = '${JS_OPERATOR_IS_PREFIX()}${name}'; |
| 471 var typeOfSPrototype = JS('', '#.prototype', typeOfS); | 469 if (hasNoField(typeOfS, test)) return false; |
| 472 if (hasNoField(typeOfSPrototype, test)) return false; | |
| 473 var field = '${JS_OPERATOR_AS_PREFIX()}${runtimeTypeToString(typeOfT)}'; | 470 var field = '${JS_OPERATOR_AS_PREFIX()}${runtimeTypeToString(typeOfT)}'; |
| 474 substitution = getField(typeOfSPrototype, field); | 471 substitution = getField(typeOfS, field); |
| 475 } | 472 } |
| 476 // The class of [s] is a subclass of the class of [t]. If [s] has no type | 473 // The class of [s] is a subclass of the class of [t]. If [s] has no type |
| 477 // arguments and no substitution, it is used as raw type. If [t] has no | 474 // arguments and no substitution, it is used as raw type. If [t] has no |
| 478 // type arguments, it used as a raw type. In both cases, [s] is a subtype | 475 // type arguments, it used as a raw type. In both cases, [s] is a subtype |
| 479 // of [t]. | 476 // of [t]. |
| 480 if ((!isJsArray(s) && substitution == null) || !isJsArray(t)) { | 477 if ((!isJsArray(s) && substitution == null) || !isJsArray(t)) { |
| 481 return true; | 478 return true; |
| 482 } | 479 } |
| 483 // Recursively check the type arguments. | 480 // Recursively check the type arguments. |
| 484 return checkArguments(substitution, getArguments(s), getArguments(t)); | 481 return checkArguments(substitution, getArguments(s), getArguments(t)); |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 679 * `null` and `undefined` (which we can avoid). | 676 * `null` and `undefined` (which we can avoid). |
| 680 */ | 677 */ |
| 681 bool isIdentical(var s, var t) => JS('bool', '# === #', s, t); | 678 bool isIdentical(var s, var t) => JS('bool', '# === #', s, t); |
| 682 | 679 |
| 683 /** | 680 /** |
| 684 * Returns `true` if the JavaScript values [s] and [t] are not identical. We use | 681 * Returns `true` if the JavaScript values [s] and [t] are not identical. We use |
| 685 * this helper instead of [identical] because `identical` needs to merge | 682 * this helper instead of [identical] because `identical` needs to merge |
| 686 * `null` and `undefined` (which we can avoid). | 683 * `null` and `undefined` (which we can avoid). |
| 687 */ | 684 */ |
| 688 bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t); | 685 bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t); |
| OLD | NEW |