| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 /// This library defines the association between runtime objects and | |
| 6 /// runtime types. | |
| 7 part of dart._runtime; | |
| 8 | |
| 9 /// | |
| 10 /// Runtime type information. This module defines the mapping from | |
| 11 /// runtime objects to their runtime type information. See the types | |
| 12 /// module for the definition of how type information is represented. | |
| 13 /// | |
| 14 /// Runtime objects fall into four main categories: | |
| 15 /// | |
| 16 /// - Things represented by javascript primitives, such as | |
| 17 /// null, numbers, booleans, strings, and symbols. For these | |
| 18 /// we map directly from the javascript type (given by typeof) | |
| 19 /// to the appropriate class type from core, which serves as their | |
| 20 /// rtti. | |
| 21 /// | |
| 22 /// - Functions, which are represented by javascript functions. | |
| 23 /// Representations of Dart functions always have a | |
| 24 /// _runtimeType property attached to them with the appropriate | |
| 25 /// rtti. | |
| 26 /// | |
| 27 /// - Objects (instances) which are represented by instances of | |
| 28 /// javascript (ES6) classes. Their types are given by their | |
| 29 /// classes, and the rtti is accessed by projecting out their | |
| 30 /// constructor field. | |
| 31 /// | |
| 32 /// - Types objects, which are represented as described in the types | |
| 33 /// module. Types always have a _runtimeType property attached to | |
| 34 /// them with the appropriate rtti. The rtti for these is always | |
| 35 /// core.Type. TODO(leafp): consider the possibility that we can | |
| 36 /// reliably recognize type objects and map directly to core.Type | |
| 37 /// rather than attaching this property everywhere. | |
| 38 /// | |
| 39 /// | |
| 40 | |
| 41 /// | |
| 42 ///Tag a closure with a type, using one of three forms: | |
| 43 /// dart.fn(cls) marks cls has having no optional or named | |
| 44 /// parameters, with all argument and return types as dynamic | |
| 45 /// dart.fn(cls, func) marks cls with the lazily computed | |
| 46 /// runtime type as computed by func() | |
| 47 /// dart.fn(cls, rType, argsT, extras) marks cls as having the | |
| 48 /// runtime type dart.functionType(rType, argsT, extras) | |
| 49 /// | |
| 50 /// Note that since we are producing a type for a concrete function, | |
| 51 /// it is sound to use the definite arrow type. | |
| 52 /// | |
| 53 fn(closure, @rest args) => JS('', '''(() => { | |
| 54 // Closure and a lazy type constructor | |
| 55 if ($args.length == 1) { | |
| 56 $defineLazyProperty($closure, $_runtimeType, {get : $args[0]}); | |
| 57 return $closure; | |
| 58 } | |
| 59 let t; | |
| 60 if ($args.length == 0) { | |
| 61 // No type arguments, it's all dynamic | |
| 62 t = $definiteFunctionType( | |
| 63 $dynamicR, Array($closure.length).fill($dynamicR)); | |
| 64 } else { | |
| 65 // We're passed the piecewise components of the function type, | |
| 66 // construct it. | |
| 67 t = $definiteFunctionType.apply(null, $args); | |
| 68 } | |
| 69 tag($closure, t); | |
| 70 return $closure; | |
| 71 })()'''); | |
| 72 | |
| 73 // TODO(vsm): How should we encode the runtime type? | |
| 74 final _runtimeType = JS('', 'Symbol("_runtimeType")'); | |
| 75 | |
| 76 checkPrimitiveType(obj) => JS('', '''(() => { | |
| 77 switch (typeof $obj) { | |
| 78 case "undefined": | |
| 79 return $Null; | |
| 80 case "number": | |
| 81 return Math.floor($obj) == $obj ? $int : $double; | |
| 82 case "boolean": | |
| 83 return $bool; | |
| 84 case "string": | |
| 85 return $String; | |
| 86 case "symbol": | |
| 87 return Symbol; | |
| 88 } | |
| 89 // Undefined is handled above. For historical reasons, | |
| 90 // typeof null == "object" in JS. | |
| 91 if ($obj === null) return $Null; | |
| 92 return null; | |
| 93 })()'''); | |
| 94 | |
| 95 runtimeType(obj) => JS('', '''(() => { | |
| 96 // Lookup primitive (int/double/string) | |
| 97 let result = $checkPrimitiveType($obj); | |
| 98 if (result !== null) return result; | |
| 99 | |
| 100 // Lookup recorded type | |
| 101 result = $obj.runtimeType; | |
| 102 if (result) return result; | |
| 103 | |
| 104 return $_nonPrimitiveRuntimeType(obj); | |
| 105 })()'''); | |
| 106 | |
| 107 getFunctionType(obj) => JS('', '''(() => { | |
| 108 // TODO(vsm): Encode this properly on the function for Dart-generated code. | |
| 109 let args = Array($obj.length).fill($dynamicR); | |
| 110 return $definiteFunctionType($bottom, args); | |
| 111 })()'''); | |
| 112 | |
| 113 /// | |
| 114 /// Returns the runtime type of obj. This is the same as `obj.realRuntimeType` | |
| 115 /// but will not call an overridden getter. | |
| 116 /// | |
| 117 /// Currently this will return null for non-Dart objects. | |
| 118 /// | |
| 119 realRuntimeType(obj) => JS('', '''(() => { | |
| 120 // Lookup primitive type | |
| 121 let result = $checkPrimitiveType($obj); | |
| 122 if (result !== null) return result; | |
| 123 | |
| 124 return $_nonPrimitiveRuntimeType(obj); | |
| 125 })()'''); | |
| 126 | |
| 127 _nonPrimitiveRuntimeType(obj) => JS('', '''(() => { | |
| 128 // Lookup recorded *real* type (not user definable runtimeType) | |
| 129 // TODO(vsm): Should we treat Dart and JS objects differently here? | |
| 130 // E.g., we can check if obj instanceof core.Object to differentiate. | |
| 131 let result = $obj[$_runtimeType]; | |
| 132 if (result) return result; | |
| 133 | |
| 134 // Lookup extension type | |
| 135 result = $obj[$_extensionType]; | |
| 136 if (result) return result; | |
| 137 | |
| 138 // Fallback on constructor for class types | |
| 139 result = $obj.constructor; | |
| 140 if (result == Function) { | |
| 141 // An undecorated Function should have come from | |
| 142 // JavaScript. Treat as untyped. | |
| 143 return $jsobject; | |
| 144 } | |
| 145 return result; | |
| 146 })()'''); | |
| 147 | |
| 148 LazyTagged(infoFn) => JS('', '''(() => { | |
| 149 class _Tagged { | |
| 150 get [$_runtimeType]() {return $infoFn();} | |
| 151 } | |
| 152 return _Tagged; | |
| 153 })()'''); | |
| 154 | |
| 155 read(value) => JS('', '''(() => { | |
| 156 return $value[$_runtimeType]; | |
| 157 })()'''); | |
| 158 | |
| 159 tag(value, info) => JS('', '''(() => { | |
| 160 $value[$_runtimeType] = $info; | |
| 161 })()'''); | |
| 162 | |
| 163 tagComputed(value, compute) => JS('', '''(() => { | |
| 164 $defineProperty($value, $_runtimeType, { get: $compute }); | |
| 165 })()'''); | |
| 166 | |
| 167 tagMemoized(value, compute) => JS('', '''(() => { | |
| 168 let cache = null; | |
| 169 function getter() { | |
| 170 if ($compute == null) return cache; | |
| 171 cache = $compute(); | |
| 172 $compute = null; | |
| 173 return cache; | |
| 174 } | |
| 175 $tagComputed($value, getter); | |
| 176 })()'''); | |
| OLD | NEW |