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 |