| 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 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 .substring(1, end) | 480 .substring(1, end) |
| 481 .split(',') | 481 .split(',') |
| 482 .map((n) => new TypeVariable(n.trim())) | 482 .map((n) => new TypeVariable(n.trim())) |
| 483 .toList(); | 483 .toList(); |
| 484 } else { | 484 } else { |
| 485 _typeFormals = [new TypeVariable(str.substring(0, end).trim())]; | 485 _typeFormals = [new TypeVariable(str.substring(0, end).trim())]; |
| 486 } | 486 } |
| 487 return _typeFormals; | 487 return _typeFormals; |
| 488 } | 488 } |
| 489 | 489 |
| 490 checkBounds(List typeArgs) { |
| 491 var bounds = instantiateTypeBounds(typeArgs); |
| 492 var typeFormals = this.typeFormals; |
| 493 for (var i = 0; i < typeArgs.length; i++) { |
| 494 var type = typeArgs[i]; |
| 495 var bound = bounds[i]; |
| 496 if (!JS('bool', '#', isSubtype(type, bound))) { |
| 497 throwStrongModeError('type `$type` does not extend `$bound`' |
| 498 ' of `${typeFormals[i]}`.'); |
| 499 } |
| 500 } |
| 501 } |
| 502 |
| 490 instantiate(typeArgs) { | 503 instantiate(typeArgs) { |
| 491 var parts = JS('', '#.apply(null, #)', _instantiateTypeParts, typeArgs); | 504 var parts = JS('', '#.apply(null, #)', _instantiateTypeParts, typeArgs); |
| 492 return JS('', '#.create(#, #[0], #[1], #[2])', FunctionType, definite, | 505 return JS('', '#.create(#, #[0], #[1], #[2])', FunctionType, definite, |
| 493 parts, parts, parts); | 506 parts, parts, parts); |
| 494 } | 507 } |
| 495 | 508 |
| 496 List instantiateTypeBounds(List typeArgs) { | 509 List instantiateTypeBounds(List typeArgs) { |
| 497 var boundsFn = _instantiateTypeBounds; | 510 var boundsFn = _instantiateTypeBounds; |
| 498 if (boundsFn == null) { | 511 if (boundsFn == null) { |
| 499 // The Dart 1 spec says omitted type parameters have an upper bound of | 512 // The Dart 1 spec says omitted type parameters have an upper bound of |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 781 // Check return type last, so that arity mismatched functions can be | 794 // Check return type last, so that arity mismatched functions can be |
| 782 // definitively rejected. | 795 // definitively rejected. |
| 783 | 796 |
| 784 // For `void` we will give the same answer as the VM, so don't return null. | 797 // For `void` we will give the same answer as the VM, so don't return null. |
| 785 if (ret1 === $_void) return $_isTop(ret2); | 798 if (ret1 === $_void) return $_isTop(ret2); |
| 786 | 799 |
| 787 if (!$_isSubtype(ret1, ret2, $isCovariant)) return null; | 800 if (!$_isSubtype(ret1, ret2, $isCovariant)) return null; |
| 788 return true; | 801 return true; |
| 789 })()'''); | 802 })()'''); |
| 790 | 803 |
| 791 /// TODO(leafp): This duplicates code in operations.dart. | |
| 792 /// I haven't found a way to factor it out that makes the | |
| 793 /// code generator happy though. | |
| 794 _subtypeMemo(f) => JS( | |
| 795 '', | |
| 796 '''(() => { | |
| 797 let memo = new Map(); | |
| 798 return (t1, t2) => { | |
| 799 let map = memo.get(t1); | |
| 800 let result; | |
| 801 if (map) { | |
| 802 result = map.get(t2); | |
| 803 if (result !== void 0) return result; | |
| 804 } else { | |
| 805 memo.set(t1, map = new Map()); | |
| 806 } | |
| 807 result = $f(t1, t2); | |
| 808 map.set(t2, result); | |
| 809 return result; | |
| 810 }; | |
| 811 })()'''); | |
| 812 | |
| 813 /// Returns true if [t1] <: [t2]. | 804 /// Returns true if [t1] <: [t2]. |
| 814 /// Returns false if [t1] </: [t2] in both spec and strong mode | 805 /// Returns false if [t1] </: [t2] in both spec and strong mode |
| 815 /// Returns undefined if [t1] </: [t2] in strong mode, but spec | 806 /// Returns undefined if [t1] </: [t2] in strong mode, but spec |
| 816 /// mode may differ | 807 /// mode may differ |
| 817 final isSubtype = JS( | 808 bool isSubtype(t1, t2) { |
| 818 '', '$_subtypeMemo((t1, t2) => (t1 === t2) || $_isSubtype(t1, t2, true))'); | 809 // TODO(leafp): This duplicates code in operations.dart. |
| 810 // I haven't found a way to factor it out that makes the |
| 811 // code generator happy though. |
| 812 var map = JS('', '#.get(#)', _memo, t1); |
| 813 bool result; |
| 814 if (JS('bool', '# !== void 0', map)) { |
| 815 result = JS('bool', '#.get(#)', map, t2); |
| 816 if (JS('bool', '# !== void 0', result)) return result; |
| 817 } else { |
| 818 JS('', '#.set(#, # = new Map())', _memo, t1, map); |
| 819 } |
| 820 result = JS('', '# === # || #(#, #, true)', t1, t2, _isSubtype, t1, t2); |
| 821 JS('', '#.set(#, #)', map, t2, result); |
| 822 return result; |
| 823 } |
| 824 |
| 825 final _memo = JS('', 'new Map()'); |
| 819 | 826 |
| 820 _isBottom(type) => JS('bool', '# == # || # == #', type, bottom, type, Null); | 827 _isBottom(type) => JS('bool', '# == # || # == #', type, bottom, type, Null); |
| 821 | 828 |
| 822 _isTop(type) { | 829 _isTop(type) { |
| 823 if (_isFutureOr(type)) { | 830 if (_isFutureOr(type)) { |
| 824 return _isTop(JS('', '#[0]', getGenericArgs(type))); | 831 return _isTop(JS('', '#[0]', getGenericArgs(type))); |
| 825 } | 832 } |
| 826 return JS('bool', '# == # || # == # || # == #', type, Object, type, dynamic, | 833 return JS('bool', '# == # || # == # || # == #', type, Object, type, dynamic, |
| 827 type, _void); | 834 type, _void); |
| 828 } | 835 } |
| 829 | 836 |
| 830 bool _isFutureOr(type) => | 837 bool _isFutureOr(type) => |
| 831 JS('bool', '# === #', getGenericClass(type), getGenericClass(FutureOr)); | 838 JS('bool', '# === #', getGenericClass(type), getGenericClass(FutureOr)); |
| 832 | 839 |
| 833 _isSubtype(t1, t2, isCovariant) => JS( | 840 bool _isSubtype(t1, t2, isCovariant) => JS( |
| 834 '', | 841 '', |
| 835 '''(() => { | 842 '''(() => { |
| 836 if ($t1 === $t2) return true; | 843 if ($t1 === $t2) return true; |
| 837 | 844 |
| 838 // Trivially true. | 845 // Trivially true. |
| 839 if ($_isTop($t2) || $_isBottom($t1)) { | 846 if ($_isTop($t2) || $_isBottom($t1)) { |
| 840 return true; | 847 return true; |
| 841 } | 848 } |
| 842 | 849 |
| 843 // Trivially false. | 850 // Trivially false. |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1057 return true; | 1064 return true; |
| 1058 } | 1065 } |
| 1059 | 1066 |
| 1060 let typeArgs = $getGenericArgs($type); | 1067 let typeArgs = $getGenericArgs($type); |
| 1061 if (!typeArgs) return true; | 1068 if (!typeArgs) return true; |
| 1062 for (let t of typeArgs) { | 1069 for (let t of typeArgs) { |
| 1063 if (t != $Object && t != $dynamic) return false; | 1070 if (t != $Object && t != $dynamic) return false; |
| 1064 } | 1071 } |
| 1065 return true; | 1072 return true; |
| 1066 })()'''); | 1073 })()'''); |
| OLD | NEW |