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 /// Runtime type information. This module defines the mapping from | 9 /// Runtime type information. This module defines the mapping from |
10 /// runtime objects to their runtime type information. See the types | 10 /// runtime objects to their runtime type information. See the types |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
53 /// runtime type dart.functionType(rType, argsT, extras). | 53 /// runtime type dart.functionType(rType, argsT, extras). |
54 /// | 54 /// |
55 /// 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, |
56 /// it is sound to use the definite arrow type. | 56 /// it is sound to use the definite arrow type. |
57 /// | 57 /// |
58 fn(closure, rType, argsT, extras) { | 58 fn(closure, rType, argsT, extras) { |
59 var t; | 59 var t; |
60 if (rType == null) { | 60 if (rType == null) { |
61 // No type arguments, it's all dynamic | 61 // No type arguments, it's all dynamic |
62 t = definiteFunctionType( | 62 t = definiteFunctionType( |
63 dynamicR, | 63 JS('', '#', dynamic), |
64 JS('', 'Array(#.length).fill(#)', closure, dynamicR), | 64 JS('', 'Array(#.length).fill(#)', closure, dynamic), |
65 JS('', 'void 0')); | 65 JS('', 'void 0')); |
66 } else { | 66 } else { |
67 // We're passed the piecewise components of the function type, | 67 // We're passed the piecewise components of the function type, |
68 // construct it. | 68 // construct it. |
69 t = definiteFunctionType(rType, argsT, extras); | 69 t = definiteFunctionType(rType, argsT, extras); |
70 } | 70 } |
71 tag(closure, t); | 71 tag(closure, t); |
72 return closure; | 72 return closure; |
73 } | 73 } |
74 | 74 |
75 lazyFn(closure, computeTypeParts) { | 75 lazyFn(closure, computeTypeParts) { |
76 tagLazy(closure, JS('', '''() => { | 76 tagLazy(closure, JS('', '''() => { |
77 let parts = #(); | 77 let parts = #(); |
78 return #(parts[0], parts[1], parts[2]); | 78 return #(parts[0], parts[1], parts[2]); |
79 }''', computeTypeParts, definiteFunctionType)); | 79 }''', computeTypeParts, definiteFunctionType)); |
80 return closure; | 80 return closure; |
81 } | 81 } |
82 | 82 |
83 // TODO(vsm): How should we encode the runtime type? | 83 // TODO(vsm): How should we encode the runtime type? |
84 final _runtimeType = JS('', 'Symbol("_runtimeType")'); | 84 final _runtimeType = JS('', 'Symbol("_runtimeType")'); |
85 | 85 |
86 checkPrimitiveType(obj) => JS('', '''(() => { | 86 _checkPrimitiveType(obj) { |
87 switch (typeof $obj) { | 87 // TODO(jmesserly): JS is used to prevent type literal wrapping. |
88 case "undefined": | 88 // Is there a better way we can handle this? |
89 return $Null; | 89 |
| 90 // Check for null and undefined |
| 91 if (obj == null) return JS('', '#', Null); |
| 92 switch (JS('String', 'typeof #', obj)) { |
90 case "number": | 93 case "number": |
91 return Math.floor($obj) == $obj ? $int : $double; | 94 return JS('bool', 'Math.floor(#) == # ? # : #', obj, obj, int, double); |
92 case "boolean": | 95 case "boolean": |
93 return $bool; | 96 return JS('', '#', bool); |
94 case "string": | 97 case "string": |
95 return $String; | 98 return JS('', '#', String); |
96 case "symbol": | 99 case "symbol": |
97 return Symbol; | 100 // Note: this is a JS Symbol, not a Dart one. |
| 101 return JS('', '#', jsobject); |
98 } | 102 } |
99 // Undefined is handled above. For historical reasons, | |
100 // typeof null == "object" in JS. | |
101 if ($obj === null) return $Null; | |
102 return null; | 103 return null; |
103 })()'''); | 104 } |
104 | 105 |
105 runtimeType(obj) => JS('', '''(() => { | 106 getFunctionType(obj) { |
106 // Handle primitives where the method isn't on the object. | |
107 let result = $checkPrimitiveType($obj); | |
108 if (result !== null) return $wrapType(result); | |
109 | |
110 // Delegate to the actual method on the object. | |
111 return $obj.runtimeType; | |
112 })()'''); | |
113 | |
114 getFunctionType(obj) => JS('', '''(() => { | |
115 // TODO(vsm): Encode this properly on the function for Dart-generated code. | 107 // TODO(vsm): Encode this properly on the function for Dart-generated code. |
116 let args = Array($obj.length).fill($dynamicR); | 108 var args = JS('', 'Array(#.length).fill(#)', obj, dynamic); |
117 return $definiteFunctionType($bottom, args); | 109 return definiteFunctionType(bottom, args, JS('', 'void 0')); |
118 })()'''); | 110 } |
119 | |
120 /// The base implementation of Object.runtimeType. | |
121 objectRuntimeType(obj) => wrapType(getReifiedType(obj)); | |
122 | 111 |
123 /// Returns an the runtime representation of the type of obj. | 112 /// Returns an the runtime representation of the type of obj. |
124 /// | 113 /// |
125 /// The resulting object is used internally for runtime type checking. This is | 114 /// The resulting object is used internally for runtime type checking. This is |
126 /// different from the user-visible Type object returned by calling | 115 /// different from the user-visible Type object returned by calling |
127 /// `runtimeType` on some Dart object. | 116 /// `runtimeType` on some Dart object. |
128 getReifiedType(obj) { | 117 getReifiedType(obj) { |
129 var result = checkPrimitiveType(obj); | 118 var result = _checkPrimitiveType(obj); |
130 if (result != null) return result; | 119 if (result != null) return result; |
131 return _nonPrimitiveRuntimeType(obj); | 120 return _nonPrimitiveRuntimeType(obj); |
132 } | 121 } |
133 | 122 |
134 _nonPrimitiveRuntimeType(obj) => JS('', '''(() => { | 123 _nonPrimitiveRuntimeType(obj) { |
135 // Lookup recorded *real* type (not user definable runtimeType) | 124 // Lookup recorded *real* type (not user definable runtimeType) |
136 // TODO(vsm): Should we treat Dart and JS objects differently here? | 125 // TODO(vsm): Should we treat Dart and JS objects differently here? |
137 // E.g., we can check if obj instanceof core.Object to differentiate. | 126 // E.g., we can check if obj instanceof core.Object to differentiate. |
138 let result = $obj[$_runtimeType]; | 127 var result = _getRuntimeType(obj); |
139 if (result) return result; | 128 if (result != null) return result; |
140 | 129 |
141 // Lookup extension type | 130 // Lookup extension type |
142 result = $obj[$_extensionType]; | 131 result = getExtensionType(obj); |
143 if (result) return result; | 132 if (result != null) return result; |
144 | 133 |
145 // Fallback on constructor for class types | 134 // Fallback on constructor for class types |
146 result = $obj.constructor; | 135 result = JS('', '#.constructor', obj); |
147 if (result == Function) { | 136 if (JS('bool', '# === Function', result)) { |
148 // An undecorated Function should have come from | 137 // An undecorated Function should have come from JavaScript. |
149 // JavaScript. Treat as untyped. | 138 // Treat as untyped. |
150 return $jsobject; | 139 return JS('', '#', jsobject); |
151 } | 140 } |
152 return result; | 141 return result; |
153 })()'''); | 142 } |
154 | 143 |
155 /// Given an internal runtime type object, wraps it in a `WrappedType` object | 144 /// Given an internal runtime type object, wraps it in a `WrappedType` object |
156 /// that implements the dart:core Type interface. | 145 /// that implements the dart:core Type interface. |
157 wrapType(type) { | 146 wrapType(type) { |
158 // If we've already wrapped this type once, use the previous wrapper. This | 147 // 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. | 148 // way, multiple references to the same type return an identical Type. |
160 if (JS('bool', '#.hasOwnProperty(#)', type, _typeObject)) { | 149 if (JS('bool', '#.hasOwnProperty(#)', type, _typeObject)) { |
161 return JS('', '#[#]', type, _typeObject); | 150 return JS('', '#[#]', type, _typeObject); |
162 } | 151 } |
163 return JS('', '#[#] = new #(#)', type, _typeObject, WrappedType, type); | 152 return JS('', '#[#] = new #(#)', type, _typeObject, WrappedType, type); |
164 } | 153 } |
165 | 154 |
166 _getRuntimeType(value) => JS('', '#[#]', value, _runtimeType); | 155 _getRuntimeType(value) => JS('', '#[#]', value, _runtimeType); |
167 | 156 |
168 /// Tag the runtime type of [value] to be type [t]. | 157 /// Tag the runtime type of [value] to be type [t]. |
169 void tag(value, t) { | 158 void tag(value, t) { |
170 JS('', '#[#] = #', value, _runtimeType, t); | 159 JS('', '#[#] = #', value, _runtimeType, t); |
171 } | 160 } |
172 | 161 |
173 void tagComputed(value, compute) { | 162 void tagComputed(value, compute) { |
174 JS('', '#(#, #, { get: # })', defineProperty, value, _runtimeType, compute); | 163 JS('', '#(#, #, { get: # })', defineProperty, value, _runtimeType, compute); |
175 } | 164 } |
176 | 165 |
177 void tagLazy(value, compute) { | 166 void tagLazy(value, compute) { |
178 JS('', '#(#, #, { get: # })', | 167 JS('', '#(#, #, { get: # })', |
179 defineLazyProperty, value, _runtimeType, compute); | 168 defineLazyProperty, value, _runtimeType, compute); |
180 } | 169 } |
OLD | NEW |