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 association between runtime objects and | 5 /// This library defines the association between runtime objects and |
6 /// runtime types. | 6 /// runtime types. |
7 part of dart._runtime; | 7 part of dart._runtime; |
8 | 8 |
9 /// | |
10 /// Runtime type information. This module defines the mapping from | 9 /// Runtime type information. This module defines the mapping from |
11 /// runtime objects to their runtime type information. See the types | 10 /// runtime objects to their runtime type information. See the types |
12 /// module for the definition of how type information is represented. | 11 /// module for the definition of how type information is represented. |
13 /// | 12 /// |
14 /// Runtime objects fall into four main categories: | 13 /// There are two kinds of objects that represent "types" at runtime. A |
| 14 /// "runtime type" contains all of the data needed to implement the runtime |
| 15 /// type checking inserted by the compiler. These objects fall into four |
| 16 /// categories: |
15 /// | 17 /// |
16 /// - Things represented by javascript primitives, such as | 18 /// - Things represented by javascript primitives, such as |
17 /// null, numbers, booleans, strings, and symbols. For these | 19 /// null, numbers, booleans, strings, and symbols. For these |
18 /// we map directly from the javascript type (given by typeof) | 20 /// we map directly from the javascript type (given by typeof) |
19 /// to the appropriate class type from core, which serves as their | 21 /// to the appropriate class type from core, which serves as their |
20 /// rtti. | 22 /// rtti. |
21 /// | 23 /// |
22 /// - Functions, which are represented by javascript functions. | 24 /// - Functions, which are represented by javascript functions. |
23 /// Representations of Dart functions always have a | 25 /// Representations of Dart functions always have a |
24 /// _runtimeType property attached to them with the appropriate | 26 /// _runtimeType property attached to them with the appropriate |
25 /// rtti. | 27 /// rtti. |
26 /// | 28 /// |
27 /// - Objects (instances) which are represented by instances of | 29 /// - Objects (instances) which are represented by instances of |
28 /// javascript (ES6) classes. Their types are given by their | 30 /// javascript (ES6) classes. Their types are given by their |
29 /// classes, and the rtti is accessed by projecting out their | 31 /// classes, and the rtti is accessed by projecting out their |
30 /// constructor field. | 32 /// constructor field. |
31 /// | 33 /// |
32 /// - Types objects, which are represented as described in the types | 34 /// - Types objects, which are represented as described in the types |
33 /// module. Types always have a _runtimeType property attached to | 35 /// module. Types always have a _runtimeType property attached to |
34 /// them with the appropriate rtti. The rtti for these is always | 36 /// them with the appropriate rtti. The rtti for these is always |
35 /// core.Type. TODO(leafp): consider the possibility that we can | 37 /// core.Type. TODO(leafp): consider the possibility that we can |
36 /// reliably recognize type objects and map directly to core.Type | 38 /// reliably recognize type objects and map directly to core.Type |
37 /// rather than attaching this property everywhere. | 39 /// rather than attaching this property everywhere. |
38 /// | 40 /// |
39 /// | 41 /// The other kind of object representing a "type" is the instances of the |
| 42 /// dart:core Type class. These are the user visible objects you get by calling |
| 43 /// "runtimeType" on an object or using a class literal expression. These are |
| 44 /// different from the above objects, and are created by calling `wrapType()` |
| 45 /// on a runtime type. |
| 46 |
40 /// Tag a closure with a type, using one of two forms: | 47 /// Tag a closure with a type, using one of two forms: |
41 /// | 48 /// |
42 /// `dart.fn(cls)` marks cls has having no optional or named | 49 /// `dart.fn(cls)` marks cls has having no optional or named |
43 /// parameters, with all argument and return types as dynamic. | 50 /// parameters, with all argument and return types as dynamic. |
44 /// | 51 /// |
45 /// `dart.fn(cls, rType, argsT, extras)` marks cls as having the | 52 /// `dart.fn(cls, rType, argsT, extras)` marks cls as having the |
46 /// runtime type dart.functionType(rType, argsT, extras). | 53 /// runtime type dart.functionType(rType, argsT, extras). |
47 /// | 54 /// |
48 /// Note that since we are producing a type for a concrete function, | 55 /// Note that since we are producing a type for a concrete function, |
49 /// it is sound to use the definite arrow type. | 56 /// it is sound to use the definite arrow type. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
89 case "symbol": | 96 case "symbol": |
90 return Symbol; | 97 return Symbol; |
91 } | 98 } |
92 // Undefined is handled above. For historical reasons, | 99 // Undefined is handled above. For historical reasons, |
93 // typeof null == "object" in JS. | 100 // typeof null == "object" in JS. |
94 if ($obj === null) return $Null; | 101 if ($obj === null) return $Null; |
95 return null; | 102 return null; |
96 })()'''); | 103 })()'''); |
97 | 104 |
98 runtimeType(obj) => JS('', '''(() => { | 105 runtimeType(obj) => JS('', '''(() => { |
99 // Lookup primitive (int/double/string) | 106 // Handle primitives where the method isn't on the object. |
100 let result = $checkPrimitiveType($obj); | 107 let result = $checkPrimitiveType($obj); |
101 if (result !== null) return result; | 108 if (result !== null) return $wrapType(result); |
102 | 109 |
103 // Lookup recorded type | 110 // Delegate to the actual method on the object. |
104 result = $obj.runtimeType; | 111 return $obj.runtimeType; |
105 if (result) return result; | |
106 | |
107 return $_nonPrimitiveRuntimeType(obj); | |
108 })()'''); | 112 })()'''); |
109 | 113 |
110 getFunctionType(obj) => JS('', '''(() => { | 114 getFunctionType(obj) => JS('', '''(() => { |
111 // TODO(vsm): Encode this properly on the function for Dart-generated code. | 115 // TODO(vsm): Encode this properly on the function for Dart-generated code. |
112 let args = Array($obj.length).fill($dynamicR); | 116 let args = Array($obj.length).fill($dynamicR); |
113 return $definiteFunctionType($bottom, args); | 117 return $definiteFunctionType($bottom, args); |
114 })()'''); | 118 })()'''); |
115 | 119 |
| 120 /// The base implementation of Object.runtimeType. |
| 121 objectRuntimeType(obj) => wrapType(getReifiedType(obj)); |
| 122 |
| 123 /// Returns an the runtime representation of the type of obj. |
116 /// | 124 /// |
117 /// Returns the runtime type of obj. This is the same as `obj.realRuntimeType` | 125 /// The resulting object is used internally for runtime type checking. This is |
118 /// but will not call an overridden getter. | 126 /// different from the user-visible Type object returned by calling |
119 /// | 127 /// `runtimeType` on some Dart object. |
120 /// Currently this will return null for non-Dart objects. | 128 getReifiedType(obj) { |
121 /// | 129 var result = checkPrimitiveType(obj); |
122 realRuntimeType(obj) => JS('', '''(() => { | 130 if (result != null) return result; |
123 // Lookup primitive type | 131 return _nonPrimitiveRuntimeType(obj); |
124 let result = $checkPrimitiveType($obj); | 132 } |
125 if (result !== null) return result; | |
126 | |
127 return $_nonPrimitiveRuntimeType(obj); | |
128 })()'''); | |
129 | 133 |
130 _nonPrimitiveRuntimeType(obj) => JS('', '''(() => { | 134 _nonPrimitiveRuntimeType(obj) => JS('', '''(() => { |
131 // Lookup recorded *real* type (not user definable runtimeType) | 135 // Lookup recorded *real* type (not user definable runtimeType) |
132 // TODO(vsm): Should we treat Dart and JS objects differently here? | 136 // TODO(vsm): Should we treat Dart and JS objects differently here? |
133 // E.g., we can check if obj instanceof core.Object to differentiate. | 137 // E.g., we can check if obj instanceof core.Object to differentiate. |
134 let result = $obj[$_runtimeType]; | 138 let result = $obj[$_runtimeType]; |
135 if (result) return result; | 139 if (result) return result; |
136 | 140 |
137 // Lookup extension type | 141 // Lookup extension type |
138 result = $obj[$_extensionType]; | 142 result = $obj[$_extensionType]; |
139 if (result) return result; | 143 if (result) return result; |
140 | 144 |
141 // Fallback on constructor for class types | 145 // Fallback on constructor for class types |
142 result = $obj.constructor; | 146 result = $obj.constructor; |
143 if (result == Function) { | 147 if (result == Function) { |
144 // An undecorated Function should have come from | 148 // An undecorated Function should have come from |
145 // JavaScript. Treat as untyped. | 149 // JavaScript. Treat as untyped. |
146 return $jsobject; | 150 return $jsobject; |
147 } | 151 } |
148 return result; | 152 return result; |
149 })()'''); | 153 })()'''); |
150 | 154 |
| 155 /// Given an internal runtime type object, wraps it in a `WrappedType` object |
| 156 /// that implements the dart:core Type interface. |
| 157 wrapType(type) { |
| 158 // If we've already wrapped this type once, use the previous wrapper. This |
| 159 // way, multiple references to the same type return an identical Type. |
| 160 if (JS('bool', '#.hasOwnProperty(#)', type, _typeObject)) { |
| 161 return JS('', '#[#]', type, _typeObject); |
| 162 } |
| 163 return JS('', '#[#] = new #(#)', type, _typeObject, WrappedType, type); |
| 164 } |
| 165 |
151 _getRuntimeType(value) => JS('', '#[#]', value, _runtimeType); | 166 _getRuntimeType(value) => JS('', '#[#]', value, _runtimeType); |
152 | 167 |
153 /// Tag the runtime type of [value] to be type [t]. | 168 /// Tag the runtime type of [value] to be type [t]. |
154 void tag(value, t) { | 169 void tag(value, t) { |
155 JS('', '#[#] = #', value, _runtimeType, t); | 170 JS('', '#[#] = #', value, _runtimeType, t); |
156 } | 171 } |
157 | 172 |
158 void tagComputed(value, compute) { | 173 void tagComputed(value, compute) { |
159 JS('', '#(#, #, { get: # })', defineProperty, value, _runtimeType, compute); | 174 JS('', '#(#, #, { get: # })', defineProperty, value, _runtimeType, compute); |
160 } | 175 } |
161 | 176 |
162 void tagLazy(value, compute) { | 177 void tagLazy(value, compute) { |
163 JS('', '#(#, #, { get: # })', | 178 JS('', '#(#, #, { get: # })', |
164 defineLazyProperty, value, _runtimeType, compute); | 179 defineLazyProperty, value, _runtimeType, compute); |
165 } | 180 } |
OLD | NEW |