| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 /// This library defines the representation of runtime types. | 5 /// This library defines the representation of runtime types. |
| 6 part of dart._runtime; | 6 part of dart._runtime; |
| 7 | 7 |
| 8 final metadata = JS('', 'Symbol("metadata")'); | 8 final metadata = JS('', 'Symbol("metadata")'); |
| 9 | 9 |
| 10 /// The symbol used to store the cached `Type` object associated with a class. | 10 /// The symbol used to store the cached `Type` object associated with a class. |
| (...skipping 642 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 653 } | 653 } |
| 654 } | 654 } |
| 655 | 655 |
| 656 // Check return type last, so that arity mismatched functions can be | 656 // Check return type last, so that arity mismatched functions can be |
| 657 // definitively rejected. | 657 // definitively rejected. |
| 658 | 658 |
| 659 // We allow any type to subtype a void return type, but not vice versa | 659 // We allow any type to subtype a void return type, but not vice versa |
| 660 if (ret2 === $_void) return true; | 660 if (ret2 === $_void) return true; |
| 661 // Dart allows void functions to subtype dynamic functions, but not | 661 // Dart allows void functions to subtype dynamic functions, but not |
| 662 // other functions. | 662 // other functions. |
| 663 if (ret1 === $_void) return (ret2 === $dynamic); | 663 // TODO(jmesserly): this check does not match our compile time subtype |
| 664 // implementation. Reconcile. |
| 665 if (ret1 === $_void) { |
| 666 return ret2 === $dynamic || ret2 === $FutureOr; |
| 667 } |
| 664 if (!$_isSubtype(ret1, ret2, $isCovariant)) return null; | 668 if (!$_isSubtype(ret1, ret2, $isCovariant)) return null; |
| 665 return true; | 669 return true; |
| 666 })()'''); | 670 })()'''); |
| 667 | 671 |
| 668 /// TODO(leafp): This duplicates code in operations.dart. | 672 /// TODO(leafp): This duplicates code in operations.dart. |
| 669 /// I haven't found a way to factor it out that makes the | 673 /// I haven't found a way to factor it out that makes the |
| 670 /// code generator happy though. | 674 /// code generator happy though. |
| 671 _subtypeMemo(f) => JS( | 675 _subtypeMemo(f) => JS( |
| 672 '', | 676 '', |
| 673 '''(() => { | 677 '''(() => { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 689 | 693 |
| 690 /// Returns true if [t1] <: [t2]. | 694 /// Returns true if [t1] <: [t2]. |
| 691 /// Returns false if [t1] </: [t2] in both spec and strong mode | 695 /// Returns false if [t1] </: [t2] in both spec and strong mode |
| 692 /// Returns undefined if [t1] </: [t2] in strong mode, but spec | 696 /// Returns undefined if [t1] </: [t2] in strong mode, but spec |
| 693 /// mode may differ | 697 /// mode may differ |
| 694 final isSubtype = JS( | 698 final isSubtype = JS( |
| 695 '', '$_subtypeMemo((t1, t2) => (t1 === t2) || $_isSubtype(t1, t2, true))'); | 699 '', '$_subtypeMemo((t1, t2) => (t1 === t2) || $_isSubtype(t1, t2, true))'); |
| 696 | 700 |
| 697 _isBottom(type) => JS('bool', '# == #', type, bottom); | 701 _isBottom(type) => JS('bool', '# == #', type, bottom); |
| 698 | 702 |
| 699 _isTop(type) => JS('bool', '# == # || # == #', type, Object, type, dynamic); | 703 _isTop(type) { |
| 704 if (JS('bool', '# === #', getGenericClass(type), getGenericClass(FutureOr))) { |
| 705 return _isTop(JS('', '#[0]', getGenericArgs(type))); |
| 706 } |
| 707 return JS('bool', '# == # || # == #', type, Object, type, dynamic); |
| 708 } |
| 700 | 709 |
| 701 _isSubtype(t1, t2, isCovariant) => JS( | 710 _isSubtype(t1, t2, isCovariant) => JS( |
| 702 '', | 711 '', |
| 703 '''(() => { | 712 '''(() => { |
| 704 if ($t1 === $t2) return true; | 713 if ($t1 === $t2) return true; |
| 705 | 714 |
| 706 // Trivially true. | 715 // Trivially true. |
| 707 if ($_isTop($t2) || $_isBottom($t1)) { | 716 if ($_isTop($t2) || $_isBottom($t1)) { |
| 708 return true; | 717 return true; |
| 709 } | 718 } |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 777 for (let i = 0; i < length; ++i) { | 786 for (let i = 0; i < length; ++i) { |
| 778 let result = | 787 let result = |
| 779 $_isSubtype(typeArguments1[i], typeArguments2[i], $isCovariant); | 788 $_isSubtype(typeArguments1[i], typeArguments2[i], $isCovariant); |
| 780 if (!result) { | 789 if (!result) { |
| 781 return result; | 790 return result; |
| 782 } | 791 } |
| 783 } | 792 } |
| 784 return true; | 793 return true; |
| 785 } | 794 } |
| 786 | 795 |
| 796 // Handle FutureOr<T>. |
| 797 // It's not really a class type, but it's convenient to handle here. |
| 798 if (raw1 === ${getGenericClass(FutureOr)}) { |
| 799 // given t1 is Future<A> | A, then: |
| 800 // (Future<A> | A) <: t2 iff Future<A> <: t2 and A <: t2. |
| 801 let t1TypeArg = $getGenericArgs($t1)[0]; |
| 802 let t1Future = ${getGenericClass(Future)}(t1TypeArg); |
| 803 return $isSubtype(t1Future, $t2) && $isSubtype(t1TypeArg, $t2); |
| 804 } else if (raw2 === ${getGenericClass(FutureOr)}) { |
| 805 // given t2 is Future<A> | A, then: |
| 806 // t1 <: (Future<A> | A) iff t1 <: Future<A> or t1 <: A |
| 807 let t2TypeArg = $getGenericArgs($t2)[0]; |
| 808 let t2Future = ${getGenericClass(Future)}(t2TypeArg); |
| 809 return $isSubtype($t1, t2Future) || $isSubtype($t1, t2TypeArg); |
| 810 } |
| 811 |
| 787 let indefinite = false; | 812 let indefinite = false; |
| 788 function definitive(t1, t2) { | 813 function definitive(t1, t2) { |
| 789 let result = $isClassSubType(t1, t2, $isCovariant); | 814 let result = $isClassSubType(t1, t2, $isCovariant); |
| 790 if (result == null) { | 815 if (result == null) { |
| 791 indefinite = true; | 816 indefinite = true; |
| 792 return false; | 817 return false; |
| 793 } | 818 } |
| 794 return result; | 819 return result; |
| 795 } | 820 } |
| 796 | 821 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 845 return true; | 870 return true; |
| 846 } | 871 } |
| 847 | 872 |
| 848 let typeArgs = $getGenericArgs($type); | 873 let typeArgs = $getGenericArgs($type); |
| 849 if (!typeArgs) return true; | 874 if (!typeArgs) return true; |
| 850 for (let t of typeArgs) { | 875 for (let t of typeArgs) { |
| 851 if (t != $Object && t != $dynamic) return false; | 876 if (t != $Object && t != $dynamic) return false; |
| 852 } | 877 } |
| 853 return true; | 878 return true; |
| 854 })()'''); | 879 })()'''); |
| OLD | NEW |