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 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 */ | 98 */ |
99 getRuntimeTypeInfo(Object target) { | 99 getRuntimeTypeInfo(Object target) { |
100 if (target == null) return null; | 100 if (target == null) return null; |
101 return JS('var', r'#.$builtinTypeInfo', target); | 101 return JS('var', r'#.$builtinTypeInfo', target); |
102 } | 102 } |
103 | 103 |
104 /** | 104 /** |
105 * Returns the type arguments of [target] as an instance of [substitutionName]. | 105 * Returns the type arguments of [target] as an instance of [substitutionName]. |
106 */ | 106 */ |
107 getRuntimeTypeArguments(target, substitutionName) { | 107 getRuntimeTypeArguments(target, substitutionName) { |
108 var substitution = | 108 var substitution = getField(target, |
109 getField(target, '${JS_GET_NAME(JsGetName.OPERATOR_AS_PREFIX)}$substitutio
nName'); | 109 '${JS_GET_NAME(JsGetName.OPERATOR_AS_PREFIX)}$substitutionName'); |
110 return substitute(substitution, getRuntimeTypeInfo(target)); | 110 return substitute(substitution, getRuntimeTypeInfo(target)); |
111 } | 111 } |
112 | 112 |
113 /** | 113 /** |
114 * Returns the [index]th type argument of [target] as an instance of | 114 * Returns the [index]th type argument of [target] as an instance of |
115 * [substitutionName]. | 115 * [substitutionName]. |
116 */ | 116 */ |
117 @NoThrows() @NoSideEffects() @NoInline() | 117 @NoThrows() @NoSideEffects() @NoInline() |
118 getRuntimeTypeArgument(Object target, String substitutionName, int index) { | 118 getRuntimeTypeArgument(Object target, String substitutionName, int index) { |
119 var arguments = getRuntimeTypeArguments(target, substitutionName); | 119 var arguments = getRuntimeTypeArguments(target, substitutionName); |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 if (rti != null) { | 385 if (rti != null) { |
386 // If the type has type variables (that is, `rti != null`), make a copy of | 386 // If the type has type variables (that is, `rti != null`), make a copy of |
387 // the type arguments and insert [o] in the first position to create a | 387 // the type arguments and insert [o] in the first position to create a |
388 // compound type representation. | 388 // compound type representation. |
389 rti = JS('JSExtendableArray', '#.slice()', rti); // Make a copy. | 389 rti = JS('JSExtendableArray', '#.slice()', rti); // Make a copy. |
390 JS('', '#.splice(0, 0, #)', rti, type); // Insert type at position 0. | 390 JS('', '#.splice(0, 0, #)', rti, type); // Insert type at position 0. |
391 type = rti; | 391 type = rti; |
392 } else if (isDartFunctionType(t)) { | 392 } else if (isDartFunctionType(t)) { |
393 // Functions are treated specially and have their type information stored | 393 // Functions are treated specially and have their type information stored |
394 // directly in the instance. | 394 // directly in the instance. |
395 var targetSignatureFunction = getField(o, '${JS_GET_NAME(JsGetName.SIGNATURE
_NAME)}'); | 395 var targetSignatureFunction = |
| 396 getField(o, '${JS_GET_NAME(JsGetName.SIGNATURE_NAME)}'); |
396 if (targetSignatureFunction == null) return false; | 397 if (targetSignatureFunction == null) return false; |
397 type = invokeOn(targetSignatureFunction, o, null); | 398 type = invokeOn(targetSignatureFunction, o, null); |
398 return isFunctionSubtype(type, t); | 399 return isFunctionSubtype(type, t); |
399 } | 400 } |
400 return isSubtype(type, t); | 401 return isSubtype(type, t); |
401 } | 402 } |
402 | 403 |
403 Object subtypeOfRuntimeTypeCast(Object object, var type) { | 404 Object subtypeOfRuntimeTypeCast(Object object, var type) { |
404 if (object != null && !checkSubtypeOfRuntimeType(object, type)) { | 405 if (object != null && !checkSubtypeOfRuntimeType(object, type)) { |
405 String actualType = Primitives.objectTypeName(object); | 406 String actualType = Primitives.objectTypeName(object); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
452 var typeOfT = isJsArray(t) ? getIndex(t, 0) : t; | 453 var typeOfT = isJsArray(t) ? getIndex(t, 0) : t; |
453 | 454 |
454 // Check for a subtyping flag. | 455 // Check for a subtyping flag. |
455 // Get the necessary substitution of the type arguments, if there is one. | 456 // Get the necessary substitution of the type arguments, if there is one. |
456 var substitution; | 457 var substitution; |
457 if (isNotIdentical(typeOfT, typeOfS)) { | 458 if (isNotIdentical(typeOfT, typeOfS)) { |
458 if (!builtinIsSubtype(typeOfS, runtimeTypeToString(typeOfT))) { | 459 if (!builtinIsSubtype(typeOfS, runtimeTypeToString(typeOfT))) { |
459 return false; | 460 return false; |
460 } | 461 } |
461 var typeOfSPrototype = JS('', '#.prototype', typeOfS); | 462 var typeOfSPrototype = JS('', '#.prototype', typeOfS); |
462 var field = '${JS_GET_NAME(JsGetName.OPERATOR_AS_PREFIX)}${runtimeTypeToStri
ng(typeOfT)}'; | 463 var field = '${JS_GET_NAME(JsGetName.OPERATOR_AS_PREFIX)}' |
| 464 '${runtimeTypeToString(typeOfT)}'; |
463 substitution = getField(typeOfSPrototype, field); | 465 substitution = getField(typeOfSPrototype, field); |
464 } | 466 } |
465 // The class of [s] is a subclass of the class of [t]. If [s] has no type | 467 // The class of [s] is a subclass of the class of [t]. If [s] has no type |
466 // arguments and no substitution, it is used as raw type. If [t] has no | 468 // arguments and no substitution, it is used as raw type. If [t] has no |
467 // type arguments, it used as a raw type. In both cases, [s] is a subtype | 469 // type arguments, it used as a raw type. In both cases, [s] is a subtype |
468 // of [t]. | 470 // of [t]. |
469 if ((!isJsArray(s) && substitution == null) || !isJsArray(t)) { | 471 if ((!isJsArray(s) && substitution == null) || !isJsArray(t)) { |
470 return true; | 472 return true; |
471 } | 473 } |
472 // Recursively check the type arguments. | 474 // Recursively check the type arguments. |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
524 var tType = JS('', '#[#]', t, name); | 526 var tType = JS('', '#[#]', t, name); |
525 var sType = JS('', '#[#]', s, name); | 527 var sType = JS('', '#[#]', s, name); |
526 if (!isAssignable(tType, sType)) return false; | 528 if (!isAssignable(tType, sType)) return false; |
527 } | 529 } |
528 return true; | 530 return true; |
529 } | 531 } |
530 | 532 |
531 bool isFunctionSubtype(var s, var t) { | 533 bool isFunctionSubtype(var s, var t) { |
532 assert(isDartFunctionType(t)); | 534 assert(isDartFunctionType(t)); |
533 if (!isDartFunctionType(s)) return false; | 535 if (!isDartFunctionType(s)) return false; |
534 if (hasField(s, '${JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG)}')) { | 536 var voidReturnTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG); |
535 if (hasNoField(t, '${JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG)}')
&& | 537 var returnTypeTag = JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG); |
536 hasField(t, '${JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG)}'))
{ | 538 if (hasField(s, voidReturnTag)) { |
| 539 if (hasNoField(t, voidReturnTag) && hasField(t, returnTypeTag)) { |
537 return false; | 540 return false; |
538 } | 541 } |
539 } else if (hasNoField(t, '${JS_GET_NAME(JsGetName.FUNCTION_TYPE_VOID_RETURN_TA
G)}')) { | 542 } else if (hasNoField(t, voidReturnTag)) { |
540 var sReturnType = getField(s, '${JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_
TYPE_TAG)}'); | 543 var sReturnType = getField(s, returnTypeTag); |
541 var tReturnType = getField(t, '${JS_GET_NAME(JsGetName.FUNCTION_TYPE_RETURN_
TYPE_TAG)}'); | 544 var tReturnType = getField(t, returnTypeTag); |
542 if (!isAssignable(sReturnType, tReturnType)) return false; | 545 if (!isAssignable(sReturnType, tReturnType)) return false; |
543 } | 546 } |
544 var sParameterTypes = | 547 var requiredParametersTag = |
545 getField(s, '${JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG
)}'); | 548 JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG); |
546 var tParameterTypes = | 549 var sParameterTypes = getField(s, requiredParametersTag); |
547 getField(t, '${JS_GET_NAME(JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG
)}'); | 550 var tParameterTypes = getField(t, requiredParametersTag); |
548 | 551 |
549 var sOptionalParameterTypes = | 552 var optionalParametersTag = |
550 getField(s, '${JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG
)}'); | 553 JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG); |
551 var tOptionalParameterTypes = | 554 var sOptionalParameterTypes = getField(s, optionalParametersTag); |
552 getField(t, '${JS_GET_NAME(JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG
)}'); | 555 var tOptionalParameterTypes = getField(t, optionalParametersTag); |
553 | 556 |
554 int sParametersLen = sParameterTypes != null ? getLength(sParameterTypes) : 0; | 557 int sParametersLen = sParameterTypes != null ? getLength(sParameterTypes) : 0; |
555 int tParametersLen = tParameterTypes != null ? getLength(tParameterTypes) : 0; | 558 int tParametersLen = tParameterTypes != null ? getLength(tParameterTypes) : 0; |
556 | 559 |
557 int sOptionalParametersLen = | 560 int sOptionalParametersLen = |
558 sOptionalParameterTypes != null ? getLength(sOptionalParameterTypes) : 0; | 561 sOptionalParameterTypes != null ? getLength(sOptionalParameterTypes) : 0; |
559 int tOptionalParametersLen = | 562 int tOptionalParametersLen = |
560 tOptionalParameterTypes != null ? getLength(tOptionalParameterTypes) : 0; | 563 tOptionalParameterTypes != null ? getLength(tOptionalParameterTypes) : 0; |
561 | 564 |
562 if (sParametersLen > tParametersLen) { | 565 if (sParametersLen > tParametersLen) { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
599 // Check the optional parameters of [t] with the remaining optional | 602 // Check the optional parameters of [t] with the remaining optional |
600 // parameters of [s]: | 603 // parameters of [s]: |
601 for (; tPos < tOptionalParametersLen ; sPos++, tPos++) { | 604 for (; tPos < tOptionalParametersLen ; sPos++, tPos++) { |
602 if (!isAssignable(getIndex(sOptionalParameterTypes, sPos), | 605 if (!isAssignable(getIndex(sOptionalParameterTypes, sPos), |
603 getIndex(tOptionalParameterTypes, tPos))) { | 606 getIndex(tOptionalParameterTypes, tPos))) { |
604 return false; | 607 return false; |
605 } | 608 } |
606 } | 609 } |
607 } | 610 } |
608 | 611 |
609 var sNamedParameters = | 612 var namedParametersTag = |
610 getField(s, '${JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG)}'
); | 613 JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG); |
611 var tNamedParameters = | 614 var sNamedParameters = getField(s, namedParametersTag); |
612 getField(t, '${JS_GET_NAME(JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG)}'
); | 615 var tNamedParameters = getField(t, namedParametersTag); |
613 return areAssignableMaps(sNamedParameters, tNamedParameters); | 616 return areAssignableMaps(sNamedParameters, tNamedParameters); |
614 } | 617 } |
615 | 618 |
616 /** | 619 /** |
617 * Calls the JavaScript [function] with the [arguments] with the global scope | 620 * Calls the JavaScript [function] with the [arguments] with the global scope |
618 * as the `this` context. | 621 * as the `this` context. |
619 */ | 622 */ |
620 invoke(var function, var arguments) => invokeOn(function, null, arguments); | 623 invoke(var function, var arguments) => invokeOn(function, null, arguments); |
621 | 624 |
622 /** | 625 /** |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
668 * `null` and `undefined` (which we can avoid). | 671 * `null` and `undefined` (which we can avoid). |
669 */ | 672 */ |
670 bool isIdentical(var s, var t) => JS('bool', '# === #', s, t); | 673 bool isIdentical(var s, var t) => JS('bool', '# === #', s, t); |
671 | 674 |
672 /** | 675 /** |
673 * Returns `true` if the JavaScript values [s] and [t] are not identical. We use | 676 * Returns `true` if the JavaScript values [s] and [t] are not identical. We use |
674 * this helper instead of [identical] because `identical` needs to merge | 677 * this helper instead of [identical] because `identical` needs to merge |
675 * `null` and `undefined` (which we can avoid). | 678 * `null` and `undefined` (which we can avoid). |
676 */ | 679 */ |
677 bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t); | 680 bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t); |
OLD | NEW |