Chromium Code Reviews| 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 (isNull(o)) return isSupertypeOfNull(t); | 387 if (isNull(o)) return isSupertypeOfNull(t); |
| 388 if (isNull(t)) return true; | 388 if (isNull(t)) 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 // We can use the object as its own type representation because we install | 393 var type = JS('', '#.constructor', o); |
| 394 // the subtype flags and the substitution on the prototype, so they are | |
| 395 // properties of the object in JS. | |
| 396 var type; | |
| 397 if (isNotNull(rti)) { | 394 if (isNotNull(rti)) { |
| 398 // If the type has type variables (that is, [:rti != null:]), make a copy of | 395 // If the type has type variables (that is, [:rti != null:]), make a copy of |
| 399 // the type arguments and insert [o] in the first position to create a | 396 // the type arguments and insert [o] in the first position to create a |
| 400 // compound type representation. | 397 // compound type representation. |
| 401 type = JS('JSExtendableArray', '#.slice()', rti); | 398 rti = JS('JSExtendableArray', '#.slice()', rti); // Make a copy. |
| 402 JS('', '#.splice(0, 0, #)', type, o); | 399 JS('', '#.splice(0, 0, #)', rti, type); // Insert type at position 0. |
| 403 } else { | 400 type = rti; |
| 404 // Use the object as representation of the raw type. | 401 } else if (hasField(t, '${JS_FUNCTION_TYPE_TAG()}') || |
|
karlklose
2014/12/15 13:12:21
One of them should be 'hasField(o, ...'.
floitsch
2014/12/15 16:04:35
argh.
In fact o can never have a function-type-tag
| |
| 402 hasField(t, '${JS_FUNCTION_TYPE_TAG()}')) { | |
| 403 // Functions are treated specially. If either `o` is a function or if t is | |
| 404 // a function type, take o as the type-object. If o isn't a function the | |
| 405 // test will fail, because `o` doesn't have the necessary fields. | |
| 405 type = o; | 406 type = o; |
| 406 } | 407 } |
| 407 return isSubtype(type, t); | 408 return isSubtype(type, t); |
| 408 } | 409 } |
| 409 | 410 |
| 410 Object subtypeOfRuntimeTypeCast(Object object, var type) { | 411 Object subtypeOfRuntimeTypeCast(Object object, var type) { |
| 411 if (object != null && !checkSubtypeOfRuntimeType(object, type)) { | 412 if (object != null && !checkSubtypeOfRuntimeType(object, type)) { |
| 412 String actualType = Primitives.objectTypeName(object); | 413 String actualType = Primitives.objectTypeName(object); |
| 413 throw new CastErrorImplementation(actualType, runtimeTypeToString(type)); | 414 throw new CastErrorImplementation(actualType, runtimeTypeToString(type)); |
| 414 } | 415 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 429 getArguments(var type) { | 430 getArguments(var type) { |
| 430 return isJsArray(type) ? JS('var', r'#.slice(1)', type) : null; | 431 return isJsArray(type) ? JS('var', r'#.slice(1)', type) : null; |
| 431 } | 432 } |
| 432 | 433 |
| 433 /** | 434 /** |
| 434 * Checks whether the type represented by the type representation [s] is a | 435 * Checks whether the type represented by the type representation [s] is a |
| 435 * subtype of the type represented by the type representation [t]. | 436 * subtype of the type represented by the type representation [t]. |
| 436 * | 437 * |
| 437 * See the comment in the beginning of this file for a description of type | 438 * See the comment in the beginning of this file for a description of type |
| 438 * representations. | 439 * representations. |
| 440 * | |
| 441 * [t] must be a type, usually represented by the constructor of the class, or | |
| 442 * an array (for generic types). | |
| 443 * | |
| 444 * If [t] is a function type, then [s] may be any object (and the test will | |
| 445 * look for closure properties on the object). if [t] is not a function type | |
|
karlklose
2014/12/15 13:12:21
'closure properties' -> 'function type tag'?
floitsch
2014/12/15 16:04:34
Changed.
Not true anymore.
| |
| 446 * [s] must be a type too. | |
| 439 */ | 447 */ |
| 440 bool isSubtype(var s, var t) { | 448 bool isSubtype(var s, var t) { |
| 441 // Subtyping is reflexive. | 449 // Subtyping is reflexive. |
| 442 if (isIdentical(s, t)) return true; | 450 if (isIdentical(s, t)) return true; |
| 443 // If either type is dynamic, [s] is a subtype of [t]. | 451 // If either type is dynamic, [s] is a subtype of [t]. |
| 444 if (isNull(s) || isNull(t)) return true; | 452 if (isNull(s) || isNull(t)) return true; |
| 445 if (hasField(t, '${JS_FUNCTION_TYPE_TAG()}')) { | 453 if (hasField(t, '${JS_FUNCTION_TYPE_TAG()}')) { |
| 446 if (hasNoField(s, '${JS_FUNCTION_TYPE_TAG()}')) { | 454 if (hasNoField(s, '${JS_FUNCTION_TYPE_TAG()}')) { |
| 447 var signatureName = | 455 var signatureName = |
| 448 '${JS_OPERATOR_IS_PREFIX()}_${getField(t, JS_FUNCTION_TYPE_TAG())}'; | 456 '${JS_OPERATOR_IS_PREFIX()}_${getField(t, JS_FUNCTION_TYPE_TAG())}'; |
| 449 if (hasField(s, signatureName)) return true; | 457 if (hasField(s, signatureName)) return true; |
| 450 var targetSignatureFunction = getField(s, '${JS_SIGNATURE_NAME()}'); | 458 var targetSignatureFunction = getField(s, '${JS_SIGNATURE_NAME()}'); |
| 451 if (isNull(targetSignatureFunction)) return false; | 459 if (isNull(targetSignatureFunction)) return false; |
| 452 s = invokeOn(targetSignatureFunction, s, null); | 460 s = invokeOn(targetSignatureFunction, s, null); |
| 453 } | 461 } |
| 454 return isFunctionSubtype(s, t); | 462 return isFunctionSubtype(s, t); |
| 455 } | 463 } |
| 456 // Check function types against the Function class. | 464 // Check function types against the Function class. |
| 457 if (getConstructorName(t) == JS_FUNCTION_CLASS_NAME() && | 465 if (hasField(s, '${JS_FUNCTION_TYPE_TAG()}')) { |
| 458 hasField(s, '${JS_FUNCTION_TYPE_TAG()}')) { | 466 return getConstructorName(t) == JS_FUNCTION_CLASS_NAME(); |
| 459 return true; | |
| 460 } | 467 } |
| 468 | |
| 461 // Get the object describing the class and check for the subtyping flag | 469 // Get the object describing the class and check for the subtyping flag |
| 462 // constructed from the type of [t]. | 470 // constructed from the type of [t]. |
| 463 var typeOfS = isJsArray(s) ? getIndex(s, 0) : s; | 471 var typeOfS = isJsArray(s) ? getIndex(s, 0) : s; |
| 464 var typeOfT = isJsArray(t) ? getIndex(t, 0) : t; | 472 var typeOfT = isJsArray(t) ? getIndex(t, 0) : t; |
| 465 // Check for a subtyping flag. | 473 // Check for a subtyping flag. |
| 466 var name = runtimeTypeToString(typeOfT); | 474 var name = runtimeTypeToString(typeOfT); |
| 467 // Get the necessary substitution of the type arguments, if there is one. | 475 // Get the necessary substitution of the type arguments, if there is one. |
| 468 var substitution; | 476 var substitution; |
| 469 if (isNotIdentical(typeOfT, typeOfS)) { | 477 if (isNotIdentical(typeOfT, typeOfS)) { |
| 470 var test = '${JS_OPERATOR_IS_PREFIX()}${name}'; | 478 var test = '${JS_OPERATOR_IS_PREFIX()}${name}'; |
| 471 if (hasNoField(typeOfS, test)) return false; | 479 var typeOfSPrototype = JS('', '#.prototype', typeOfS); |
| 480 if (hasNoField(typeOfSPrototype, test)) return false; | |
| 472 var field = '${JS_OPERATOR_AS_PREFIX()}${runtimeTypeToString(typeOfT)}'; | 481 var field = '${JS_OPERATOR_AS_PREFIX()}${runtimeTypeToString(typeOfT)}'; |
| 473 substitution = getField(typeOfS, field); | 482 substitution = getField(typeOfSPrototype, field); |
| 474 } | 483 } |
| 475 // The class of [s] is a subclass of the class of [t]. If [s] has no type | 484 // The class of [s] is a subclass of the class of [t]. If [s] has no type |
| 476 // arguments and no substitution, it is used as raw type. If [t] has no | 485 // arguments and no substitution, it is used as raw type. If [t] has no |
| 477 // type arguments, it used as a raw type. In both cases, [s] is a subtype | 486 // type arguments, it used as a raw type. In both cases, [s] is a subtype |
| 478 // of [t]. | 487 // of [t]. |
| 479 if ((!isJsArray(s) && isNull(substitution)) || !isJsArray(t)) { | 488 if ((!isJsArray(s) && isNull(substitution)) || !isJsArray(t)) { |
| 480 return true; | 489 return true; |
| 481 } | 490 } |
| 482 // Recursively check the type arguments. | 491 // Recursively check the type arguments. |
| 483 return checkArguments(substitution, getArguments(s), getArguments(t)); | 492 return checkArguments(substitution, getArguments(s), getArguments(t)); |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 694 * and [t] are Dart values. | 703 * and [t] are Dart values. |
| 695 */ | 704 */ |
| 696 bool isIdentical(var s, var t) => JS('bool', '# === #', s, t); | 705 bool isIdentical(var s, var t) => JS('bool', '# === #', s, t); |
| 697 | 706 |
| 698 /** | 707 /** |
| 699 * Returns [:true:] if the JavaScript values [s] and [t] are not identical. We | 708 * Returns [:true:] if the JavaScript values [s] and [t] are not identical. We |
| 700 * use this helper to avoid generating code under the invalid assumption that | 709 * use this helper to avoid generating code under the invalid assumption that |
| 701 * [s] and [t] are Dart values. | 710 * [s] and [t] are Dart values. |
| 702 */ | 711 */ |
| 703 bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t); | 712 bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t); |
| OLD | NEW |