| 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 operations that define and manipulate Dart | 5 /// This library defines the operations that define and manipulate Dart |
| 6 /// classes. Included in this are: | 6 /// classes. Included in this are: |
| 7 /// - Generics | 7 /// - Generics |
| 8 /// - Class metadata | 8 /// - Class metadata |
| 9 /// - Extension methods | 9 /// - Extension methods |
| 10 /// | 10 /// |
| 11 | 11 |
| 12 // TODO(leafp): Consider splitting some of this out. | 12 // TODO(leafp): Consider splitting some of this out. |
| 13 part of dart._runtime; | 13 part of dart._runtime; |
| 14 | 14 |
| 15 /// | 15 /// |
| 16 /// Returns a new type that mixes members from base and all mixins. | 16 /// Returns a new type that mixes members from base and all mixins. |
| 17 /// | 17 /// |
| 18 /// Each mixin applies in sequence, with further to the right ones overriding | 18 /// Each mixin applies in sequence, with further to the right ones overriding |
| 19 /// previous entries. | 19 /// previous entries. |
| 20 /// | 20 /// |
| 21 /// For each mixin, we only take its own properties, not anything from its | 21 /// For each mixin, we only take its own properties, not anything from its |
| 22 /// superclass (prototype). | 22 /// superclass (prototype). |
| 23 /// | 23 /// |
| 24 mixin(base, @rest mixins) => JS('', '''(() => { | 24 mixin(base, @rest mixins) => JS( |
| 25 '', |
| 26 '''(() => { |
| 25 // Create an initializer for the mixin, so when derived constructor calls | 27 // Create an initializer for the mixin, so when derived constructor calls |
| 26 // super, we can correctly initialize base and mixins. | 28 // super, we can correctly initialize base and mixins. |
| 27 | 29 |
| 28 // Create a class that will hold all of the mixin methods. | 30 // Create a class that will hold all of the mixin methods. |
| 29 class Mixin extends $base {} | 31 class Mixin extends $base {} |
| 30 // Copy each mixin's methods, with later ones overwriting earlier entries. | 32 // Copy each mixin's methods, with later ones overwriting earlier entries. |
| 31 for (let m of $mixins) { | 33 for (let m of $mixins) { |
| 32 $copyProperties(Mixin.prototype, m.prototype); | 34 $copyProperties(Mixin.prototype, m.prototype); |
| 33 } | 35 } |
| 34 // Initializer method: run mixin initializers, then the base. | 36 // Initializer method: run mixin initializers, then the base. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 52 } | 54 } |
| 53 return s; | 55 return s; |
| 54 } | 56 } |
| 55 }); | 57 }); |
| 56 | 58 |
| 57 // Save mixins for reflection | 59 // Save mixins for reflection |
| 58 Mixin[$_mixins] = $mixins; | 60 Mixin[$_mixins] = $mixins; |
| 59 return Mixin; | 61 return Mixin; |
| 60 })()'''); | 62 })()'''); |
| 61 | 63 |
| 62 | |
| 63 /// The Symbol for storing type arguments on a specialized generic type. | 64 /// The Symbol for storing type arguments on a specialized generic type. |
| 64 final _mixins = JS('', 'Symbol("mixins")'); | 65 final _mixins = JS('', 'Symbol("mixins")'); |
| 65 | 66 |
| 66 getMixins(clazz) => JS('', '$clazz[$_mixins]'); | 67 getMixins(clazz) => JS('', '$clazz[$_mixins]'); |
| 67 | 68 |
| 68 @JSExportName('implements') | 69 @JSExportName('implements') |
| 69 final _implements = JS('', 'Symbol("implements")'); | 70 final _implements = JS('', 'Symbol("implements")'); |
| 70 | 71 |
| 71 getImplements(clazz) => JS('', '#[#]', clazz, _implements); | 72 getImplements(clazz) => JS('', '#[#]', clazz, _implements); |
| 72 | 73 |
| 73 /// The Symbol for storing type arguments on a specialized generic type. | 74 /// The Symbol for storing type arguments on a specialized generic type. |
| 74 final _typeArguments = JS('', 'Symbol("typeArguments")'); | 75 final _typeArguments = JS('', 'Symbol("typeArguments")'); |
| 75 | 76 |
| 76 final _originalDeclaration = JS('', 'Symbol("originalDeclaration")'); | 77 final _originalDeclaration = JS('', 'Symbol("originalDeclaration")'); |
| 77 | 78 |
| 78 /// Wrap a generic class builder function with future flattening. | 79 /// Wrap a generic class builder function with future flattening. |
| 79 flattenFutures(builder) => JS('', '''(() => { | 80 flattenFutures(builder) => JS( |
| 81 '', |
| 82 '''(() => { |
| 80 function flatten(T) { | 83 function flatten(T) { |
| 81 if (!T) return $builder($dynamic); | 84 if (!T) return $builder($dynamic); |
| 82 let futureClass = $getGenericClass($Future); | 85 let futureClass = $getGenericClass($Future); |
| 83 //TODO(leafp): This only handles the direct flattening case. | 86 //TODO(leafp): This only handles the direct flattening case. |
| 84 // It would probably be good to at least search up the class | 87 // It would probably be good to at least search up the class |
| 85 // hierarchy. If we keep doing flattening long term, we may | 88 // hierarchy. If we keep doing flattening long term, we may |
| 86 // want to implement the full future flattening per spec. | 89 // want to implement the full future flattening per spec. |
| 87 if ($getGenericClass(T) == futureClass) { | 90 if ($getGenericClass(T) == futureClass) { |
| 88 let args = $getGenericArgs(T); | 91 let args = $getGenericArgs(T); |
| 89 if (args) return $builder(args[0]); | 92 if (args) return $builder(args[0]); |
| 90 } | 93 } |
| 91 return $builder(T); | 94 return $builder(T); |
| 92 } | 95 } |
| 93 return flatten; | 96 return flatten; |
| 94 })()'''); | 97 })()'''); |
| 95 | 98 |
| 96 /// Memoize a generic type constructor function. | 99 /// Memoize a generic type constructor function. |
| 97 generic(typeConstructor) => JS('', '''(() => { | 100 generic(typeConstructor) => JS( |
| 101 '', |
| 102 '''(() => { |
| 98 let length = $typeConstructor.length; | 103 let length = $typeConstructor.length; |
| 99 if (length < 1) { | 104 if (length < 1) { |
| 100 $throwInternalError('must have at least one generic type argument'); | 105 $throwInternalError('must have at least one generic type argument'); |
| 101 } | 106 } |
| 102 let resultMap = new Map(); | 107 let resultMap = new Map(); |
| 103 function makeGenericType(...args) { | 108 function makeGenericType(...args) { |
| 104 if (args.length != length && args.length != 0) { | 109 if (args.length != length && args.length != 0) { |
| 105 $throwInternalError('requires ' + length + ' or 0 type arguments'); | 110 $throwInternalError('requires ' + length + ' or 0 type arguments'); |
| 106 } | 111 } |
| 107 while (args.length < length) args.push($dynamic); | 112 while (args.length < length) args.push($dynamic); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 130 } | 135 } |
| 131 } | 136 } |
| 132 return value; | 137 return value; |
| 133 } | 138 } |
| 134 return makeGenericType; | 139 return makeGenericType; |
| 135 })()'''); | 140 })()'''); |
| 136 | 141 |
| 137 getGenericClass(type) => | 142 getGenericClass(type) => |
| 138 JS('', '$safeGetOwnProperty($type, $_originalDeclaration)'); | 143 JS('', '$safeGetOwnProperty($type, $_originalDeclaration)'); |
| 139 | 144 |
| 140 getGenericArgs(type) => | 145 getGenericArgs(type) => JS('', '$safeGetOwnProperty($type, $_typeArguments)'); |
| 141 JS('', '$safeGetOwnProperty($type, $_typeArguments)'); | |
| 142 | 146 |
| 143 final _constructorSig = JS('', 'Symbol("sigCtor")'); | 147 final _constructorSig = JS('', 'Symbol("sigCtor")'); |
| 144 final _methodSig = JS('', 'Symbol("sig")'); | 148 final _methodSig = JS('', 'Symbol("sig")'); |
| 145 final _staticSig = JS('', 'Symbol("sigStatic")'); | 149 final _staticSig = JS('', 'Symbol("sigStatic")'); |
| 146 | 150 |
| 147 /// Get the type of a method from an object using the stored signature | 151 /// Get the type of a method from an object using the stored signature |
| 148 getMethodType(obj, name) => JS('', '''(() => { | 152 getMethodType(obj, name) => JS( |
| 153 '', |
| 154 '''(() => { |
| 149 let type = $obj == null ? $Object : $obj.__proto__.constructor; | 155 let type = $obj == null ? $Object : $obj.__proto__.constructor; |
| 150 return $getMethodTypeFromType(type, $name); | 156 return $getMethodTypeFromType(type, $name); |
| 151 })()'''); | 157 })()'''); |
| 152 | 158 |
| 153 /// Get the type of a method from a type using the stored signature | 159 /// Get the type of a method from a type using the stored signature |
| 154 getMethodTypeFromType(type, name) => JS('', '''(() => { | 160 getMethodTypeFromType(type, name) => JS( |
| 161 '', |
| 162 '''(() => { |
| 155 let sigObj = $type[$_methodSig]; | 163 let sigObj = $type[$_methodSig]; |
| 156 if (sigObj === void 0) return void 0; | 164 if (sigObj === void 0) return void 0; |
| 157 return sigObj[$name]; | 165 return sigObj[$name]; |
| 158 })()'''); | 166 })()'''); |
| 159 | 167 |
| 160 /// Get the type of a constructor from a class using the stored signature | 168 /// Get the type of a constructor from a class using the stored signature |
| 161 /// If name is undefined, returns the type of the default constructor | 169 /// If name is undefined, returns the type of the default constructor |
| 162 /// Returns undefined if the constructor is not found. | 170 /// Returns undefined if the constructor is not found. |
| 163 classGetConstructorType(cls, name) => JS('', '''(() => { | 171 classGetConstructorType(cls, name) => JS( |
| 172 '', |
| 173 '''(() => { |
| 164 if(!$name) $name = $cls.name; | 174 if(!$name) $name = $cls.name; |
| 165 if ($cls === void 0) return void 0; | 175 if ($cls === void 0) return void 0; |
| 166 if ($cls == null) return void 0; | 176 if ($cls == null) return void 0; |
| 167 let sigCtor = $cls[$_constructorSig]; | 177 let sigCtor = $cls[$_constructorSig]; |
| 168 if (sigCtor === void 0) return void 0; | 178 if (sigCtor === void 0) return void 0; |
| 169 return sigCtor[$name]; | 179 return sigCtor[$name]; |
| 170 })()'''); | 180 })()'''); |
| 171 | 181 |
| 172 /// Given an object and a method name, tear off the method. | 182 /// Given an object and a method name, tear off the method. |
| 173 /// Sets the runtime type of the torn off method appropriately, | 183 /// Sets the runtime type of the torn off method appropriately, |
| 174 /// and also binds the object. | 184 /// and also binds the object. |
| 175 /// | 185 /// |
| 176 /// If the optional `f` argument is passed in, it will be used as the method. | 186 /// If the optional `f` argument is passed in, it will be used as the method. |
| 177 /// This supports cases like `super.foo` where we need to tear off the method | 187 /// This supports cases like `super.foo` where we need to tear off the method |
| 178 /// from the superclass, not from the `obj` directly. | 188 /// from the superclass, not from the `obj` directly. |
| 179 /// TODO(leafp): Consider caching the tearoff on the object? | 189 /// TODO(leafp): Consider caching the tearoff on the object? |
| 180 bind(obj, name, f) => JS('', '''(() => { | 190 bind(obj, name, f) => JS( |
| 191 '', |
| 192 '''(() => { |
| 181 if ($f === void 0) $f = $obj[$name]; | 193 if ($f === void 0) $f = $obj[$name]; |
| 182 $f = $f.bind($obj); | 194 $f = $f.bind($obj); |
| 183 // TODO(jmesserly): track the function's signature on the function, instead | 195 // TODO(jmesserly): track the function's signature on the function, instead |
| 184 // of having to go back to the class? | 196 // of having to go back to the class? |
| 185 let sig = $getMethodType($obj, $name); | 197 let sig = $getMethodType($obj, $name); |
| 186 $assert_(sig); | 198 $assert_(sig); |
| 187 $tag($f, sig); | 199 $tag($f, sig); |
| 188 return $f; | 200 return $f; |
| 189 })()'''); | 201 })()'''); |
| 190 | 202 |
| 191 /// Instantiate a generic method. | 203 /// Instantiate a generic method. |
| 192 /// | 204 /// |
| 193 /// We need to apply the type arguments both to the function, as well as its | 205 /// We need to apply the type arguments both to the function, as well as its |
| 194 /// associated function type. | 206 /// associated function type. |
| 195 gbind(f, @rest typeArgs) { | 207 gbind(f, @rest typeArgs) { |
| 196 var result = JS('', '#.apply(null, #)', f, typeArgs); | 208 var result = JS('', '#.apply(null, #)', f, typeArgs); |
| 197 var sig = JS('', '#.apply(null, #)', _getRuntimeType(f), typeArgs); | 209 var sig = JS('', '#.apply(null, #)', _getRuntimeType(f), typeArgs); |
| 198 tag(result, sig); | 210 tag(result, sig); |
| 199 return result; | 211 return result; |
| 200 } | 212 } |
| 201 | 213 |
| 202 // Set up the method signature field on the constructor | 214 // Set up the method signature field on the constructor |
| 203 _setMethodSignature(f, sigF) => JS('', '''(() => { | 215 _setMethodSignature(f, sigF) => JS( |
| 216 '', |
| 217 '''(() => { |
| 204 $defineMemoizedGetter($f, $_methodSig, () => { | 218 $defineMemoizedGetter($f, $_methodSig, () => { |
| 205 let sigObj = $sigF(); | 219 let sigObj = $sigF(); |
| 206 sigObj.__proto__ = $f.__proto__[$_methodSig]; | 220 sigObj.__proto__ = $f.__proto__[$_methodSig]; |
| 207 return sigObj; | 221 return sigObj; |
| 208 }); | 222 }); |
| 209 })()'''); | 223 })()'''); |
| 210 | 224 |
| 211 // Set up the constructor signature field on the constructor | 225 // Set up the constructor signature field on the constructor |
| 212 _setConstructorSignature(f, sigF) => | 226 _setConstructorSignature(f, sigF) => |
| 213 JS('', '$defineMemoizedGetter($f, $_constructorSig, $sigF)'); | 227 JS('', '$defineMemoizedGetter($f, $_constructorSig, $sigF)'); |
| 214 | 228 |
| 215 // Set up the static signature field on the constructor | 229 // Set up the static signature field on the constructor |
| 216 _setStaticSignature(f, sigF) => | 230 _setStaticSignature(f, sigF) => |
| 217 JS('', '$defineMemoizedGetter($f, $_staticSig, $sigF)'); | 231 JS('', '$defineMemoizedGetter($f, $_staticSig, $sigF)'); |
| 218 | 232 |
| 219 // Set the lazily computed runtime type field on static methods | 233 // Set the lazily computed runtime type field on static methods |
| 220 _setStaticTypes(f, names) => JS('', '''(() => { | 234 _setStaticTypes(f, names) => JS( |
| 235 '', |
| 236 '''(() => { |
| 221 for (let name of $names) { | 237 for (let name of $names) { |
| 222 // TODO(vsm): Need to generate static methods. | 238 // TODO(vsm): Need to generate static methods. |
| 223 if (!$f[name]) continue; | 239 if (!$f[name]) continue; |
| 224 $tagLazy($f[name], function() { | 240 $tagLazy($f[name], function() { |
| 225 return $f[$_staticSig][name]; | 241 return $f[$_staticSig][name]; |
| 226 }) | 242 }) |
| 227 } | 243 } |
| 228 })()'''); | 244 })()'''); |
| 229 | 245 |
| 230 /// Set up the type signature of a class (constructor object) | 246 /// Set up the type signature of a class (constructor object) |
| 231 /// f is a constructor object | 247 /// f is a constructor object |
| 232 /// signature is an object containing optional properties as follows: | 248 /// signature is an object containing optional properties as follows: |
| 233 /// methods: A function returning an object mapping method names | 249 /// methods: A function returning an object mapping method names |
| 234 /// to method types. The function is evaluated lazily and cached. | 250 /// to method types. The function is evaluated lazily and cached. |
| 235 /// statics: A function returning an object mapping static method | 251 /// statics: A function returning an object mapping static method |
| 236 /// names to types. The function is evalutated lazily and cached. | 252 /// names to types. The function is evalutated lazily and cached. |
| 237 /// names: An array of the names of the static methods. Used to | 253 /// names: An array of the names of the static methods. Used to |
| 238 /// permit eagerly setting the runtimeType field on the methods | 254 /// permit eagerly setting the runtimeType field on the methods |
| 239 /// while still lazily computing the type descriptor object. | 255 /// while still lazily computing the type descriptor object. |
| 240 setSignature(f, signature) => JS('', '''(() => { | 256 setSignature(f, signature) => JS( |
| 257 '', |
| 258 '''(() => { |
| 241 // TODO(ochafik): Deconstruct these when supported by Chrome. | 259 // TODO(ochafik): Deconstruct these when supported by Chrome. |
| 242 let constructors = | 260 let constructors = |
| 243 ('constructors' in signature) ? signature.constructors : () => ({}); | 261 ('constructors' in signature) ? signature.constructors : () => ({}); |
| 244 let methods = | 262 let methods = |
| 245 ('methods' in signature) ? signature.methods : () => ({}); | 263 ('methods' in signature) ? signature.methods : () => ({}); |
| 246 let statics = | 264 let statics = |
| 247 ('statics' in signature) ? signature.statics : () => ({}); | 265 ('statics' in signature) ? signature.statics : () => ({}); |
| 248 let names = | 266 let names = |
| 249 ('names' in signature) ? signature.names : []; | 267 ('names' in signature) ? signature.names : []; |
| 250 $_setConstructorSignature($f, constructors); | 268 $_setConstructorSignature($f, constructors); |
| 251 $_setMethodSignature($f, methods); | 269 $_setMethodSignature($f, methods); |
| 252 $_setStaticSignature($f, statics); | 270 $_setStaticSignature($f, statics); |
| 253 $_setStaticTypes($f, names); | 271 $_setStaticTypes($f, names); |
| 254 })()'''); | 272 })()'''); |
| 255 | 273 |
| 256 hasMethod(obj, name) => JS('', '$getMethodType($obj, $name) !== void 0'); | 274 hasMethod(obj, name) => JS('', '$getMethodType($obj, $name) !== void 0'); |
| 257 | 275 |
| 258 /// Given a class and an initializer method name, creates a constructor | 276 /// Given a class and an initializer method name, creates a constructor |
| 259 /// function with the same name. | 277 /// function with the same name. |
| 260 /// | 278 /// |
| 261 /// After we define the named constructor, the class can be constructed with | 279 /// After we define the named constructor, the class can be constructed with |
| 262 /// `new SomeClass.name(args)`. | 280 /// `new SomeClass.name(args)`. |
| 263 defineNamedConstructor(clazz, name) => JS('', '''(() => { | 281 defineNamedConstructor(clazz, name) => JS( |
| 282 '', |
| 283 '''(() => { |
| 264 let proto = $clazz.prototype; | 284 let proto = $clazz.prototype; |
| 265 let initMethod = proto[$name]; | 285 let initMethod = proto[$name]; |
| 266 let ctor = function(...args) { initMethod.apply(this, args); }; | 286 let ctor = function(...args) { initMethod.apply(this, args); }; |
| 287 ctor[$isNamedConstructor] = true; |
| 267 ctor.prototype = proto; | 288 ctor.prototype = proto; |
| 268 // Use defineProperty so we don't hit a property defined on Function, | 289 // Use defineProperty so we don't hit a property defined on Function, |
| 269 // like `caller` and `arguments`. | 290 // like `caller` and `arguments`. |
| 270 $defineProperty($clazz, $name, { value: ctor, configurable: true }); | 291 $defineProperty($clazz, $name, { value: ctor, configurable: true }); |
| 271 })()'''); | 292 })()'''); |
| 272 | 293 |
| 273 | |
| 274 final _extensionType = JS('', 'Symbol("extensionType")'); | 294 final _extensionType = JS('', 'Symbol("extensionType")'); |
| 275 | 295 |
| 276 getExtensionType(obj) => JS('', '#[#]', obj, _extensionType); | 296 getExtensionType(obj) => JS('', '#[#]', obj, _extensionType); |
| 277 | 297 |
| 278 final dartx = JS('', 'dartx'); | 298 final dartx = JS('', 'dartx'); |
| 279 | 299 |
| 280 getExtensionSymbol(name) { | 300 getExtensionSymbol(name) { |
| 281 var sym = JS('', 'dartx[#]', name); | 301 var sym = JS('', 'dartx[#]', name); |
| 282 if (sym == null) { | 302 if (sym == null) { |
| 283 sym = JS('', 'Symbol("dartx." + #.toString())', name); | 303 sym = JS('', 'Symbol("dartx." + #.toString())', name); |
| 284 JS('', 'dartx[#] = #', name, sym); | 304 JS('', 'dartx[#] = #', name, sym); |
| 285 } | 305 } |
| 286 return sym; | 306 return sym; |
| 287 } | 307 } |
| 288 | 308 |
| 289 defineExtensionNames(names) => | 309 defineExtensionNames(names) => |
| 290 JS('', '#.forEach(#)', names, getExtensionSymbol); | 310 JS('', '#.forEach(#)', names, getExtensionSymbol); |
| 291 | 311 |
| 292 | |
| 293 /// Install properties in prototype-first order. Properties / descriptors from | 312 /// Install properties in prototype-first order. Properties / descriptors from |
| 294 /// more specific types should overwrite ones from less specific types. | 313 /// more specific types should overwrite ones from less specific types. |
| 295 void _installProperties(jsProto, extProto) { | 314 void _installProperties(jsProto, extProto) { |
| 296 | |
| 297 // This relies on the Dart type literal evaluating to the JavaScript | 315 // This relies on the Dart type literal evaluating to the JavaScript |
| 298 // constructor. | 316 // constructor. |
| 299 var coreObjProto = JS('', '#.prototype', Object); | 317 var coreObjProto = JS('', '#.prototype', Object); |
| 300 | 318 |
| 301 var parentsExtension = | 319 var parentsExtension = JS('', '(#.__proto__)[#]', jsProto, _extensionType); |
| 302 JS('', '(#.__proto__)[#]', jsProto, _extensionType); | |
| 303 var installedParent = | 320 var installedParent = |
| 304 JS('', '# && #.prototype', parentsExtension, parentsExtension); | 321 JS('', '# && #.prototype', parentsExtension, parentsExtension); |
| 305 | 322 |
| 306 _installProperties2(jsProto, extProto, coreObjProto, installedParent); | 323 _installProperties2(jsProto, extProto, coreObjProto, installedParent); |
| 307 } | 324 } |
| 308 | 325 |
| 309 void _installProperties2(jsProto, extProto, coreObjProto, installedParent) { | 326 void _installProperties2(jsProto, extProto, coreObjProto, installedParent) { |
| 310 if (JS('bool', '# === #', extProto, coreObjProto)) { | 327 if (JS('bool', '# === #', extProto, coreObjProto)) { |
| 311 _installPropertiesForObject(jsProto, coreObjProto); | 328 _installPropertiesForObject(jsProto, coreObjProto); |
| 312 return; | 329 return; |
| 313 } | 330 } |
| 314 if (JS('bool', '# !== #', jsProto, extProto)) { | 331 if (JS('bool', '# !== #', jsProto, extProto)) { |
| 315 var extParent = JS('', '#.__proto__', extProto); | 332 var extParent = JS('', '#.__proto__', extProto); |
| 316 | 333 |
| 317 // If the extension methods of the parent have been installed on the parent | 334 // If the extension methods of the parent have been installed on the parent |
| 318 // of [jsProto], the methods will be available via prototype inheritance. | 335 // of [jsProto], the methods will be available via prototype inheritance. |
| 319 | 336 |
| 320 if(JS('bool', '# !== #', installedParent, extParent)) { | 337 if (JS('bool', '# !== #', installedParent, extParent)) { |
| 321 _installProperties2(jsProto, extParent, coreObjProto, installedParent); | 338 _installProperties2(jsProto, extParent, coreObjProto, installedParent); |
| 322 } | 339 } |
| 323 } | 340 } |
| 324 copyTheseProperties(jsProto, extProto, getOwnPropertySymbols(extProto)); | 341 copyTheseProperties(jsProto, extProto, getOwnPropertySymbols(extProto)); |
| 325 } | 342 } |
| 326 | 343 |
| 327 void _installPropertiesForObject(jsProto, coreObjProto) { | 344 void _installPropertiesForObject(jsProto, coreObjProto) { |
| 328 // core.Object members need to be copied from the non-symbol name to the | 345 // core.Object members need to be copied from the non-symbol name to the |
| 329 // symbol name. | 346 // symbol name. |
| 330 var names = getOwnPropertyNames(coreObjProto); | 347 var names = getOwnPropertyNames(coreObjProto); |
| 331 for (int i = 0; i < JS('int', '#.length', names); ++i) { | 348 for (int i = 0; i < JS('int', '#.length', names); ++i) { |
| 332 var name = JS('', '#[#]', names, i); | 349 var name = JS('', '#[#]', names, i); |
| 333 var desc = getOwnPropertyDescriptor(coreObjProto, name); | 350 var desc = getOwnPropertyDescriptor(coreObjProto, name); |
| 334 defineProperty(jsProto, getExtensionSymbol(name), desc); | 351 defineProperty(jsProto, getExtensionSymbol(name), desc); |
| 335 } | 352 } |
| 336 return; | 353 return; |
| 337 } | 354 } |
| 338 | 355 |
| 339 /// Copy symbols from the prototype of the source to destination. | 356 /// Copy symbols from the prototype of the source to destination. |
| 340 /// These are the only properties safe to copy onto an existing public | 357 /// These are the only properties safe to copy onto an existing public |
| 341 /// JavaScript class. | 358 /// JavaScript class. |
| 342 registerExtension(jsType, dartExtType) => JS('', '''(() => { | 359 registerExtension(jsType, dartExtType) => JS( |
| 360 '', |
| 361 '''(() => { |
| 343 // TODO(vsm): Not all registered js types are real. | 362 // TODO(vsm): Not all registered js types are real. |
| 344 if (!jsType) return; | 363 if (!jsType) return; |
| 345 | 364 |
| 346 let extProto = $dartExtType.prototype; | 365 let extProto = $dartExtType.prototype; |
| 347 let jsProto = $jsType.prototype; | 366 let jsProto = $jsType.prototype; |
| 348 | 367 |
| 349 // Mark the JS type's instances so we can easily check for extensions. | 368 // Mark the JS type's instances so we can easily check for extensions. |
| 350 jsProto[$_extensionType] = $dartExtType; | 369 jsProto[$_extensionType] = $dartExtType; |
| 351 $_installProperties(jsProto, extProto); | 370 $_installProperties(jsProto, extProto); |
| 352 let originalSigFn = $getOwnPropertyDescriptor($dartExtType, $_methodSig).get; | 371 let originalSigFn = $getOwnPropertyDescriptor($dartExtType, $_methodSig).get; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 366 /// | 385 /// |
| 367 /// Results in: | 386 /// Results in: |
| 368 /// | 387 /// |
| 369 /// MyType.prototype[dartx.add] = MyType.prototype.add; | 388 /// MyType.prototype[dartx.add] = MyType.prototype.add; |
| 370 /// MyType.prototype[dartx.remove] = MyType.prototype.remove; | 389 /// MyType.prototype[dartx.remove] = MyType.prototype.remove; |
| 371 /// | 390 /// |
| 372 // TODO(jmesserly): essentially this gives two names to the same method. | 391 // TODO(jmesserly): essentially this gives two names to the same method. |
| 373 // This benefit is roughly equivalent call performance either way, but the | 392 // This benefit is roughly equivalent call performance either way, but the |
| 374 // cost is we need to call defineExtensionMembers any time a subclass | 393 // cost is we need to call defineExtensionMembers any time a subclass |
| 375 // overrides one of these methods. | 394 // overrides one of these methods. |
| 376 defineExtensionMembers(type, methodNames) => JS('', '''(() => { | 395 defineExtensionMembers(type, methodNames) => JS( |
| 396 '', |
| 397 '''(() => { |
| 377 let proto = $type.prototype; | 398 let proto = $type.prototype; |
| 378 for (let name of $methodNames) { | 399 for (let name of $methodNames) { |
| 379 let method = $getOwnPropertyDescriptor(proto, name); | 400 let method = $getOwnPropertyDescriptor(proto, name); |
| 380 // TODO(vsm): We should be able to generate code to avoid this case. | 401 // TODO(vsm): We should be able to generate code to avoid this case. |
| 381 // The method may be null if this type implements a potentially native | 402 // The method may be null if this type implements a potentially native |
| 382 // interface but isn't native itself. For a field on this type, we're not | 403 // interface but isn't native itself. For a field on this type, we're not |
| 383 // generating a corresponding getter/setter method - it's just a field. | 404 // generating a corresponding getter/setter method - it's just a field. |
| 384 if (!method) continue; | 405 if (!method) continue; |
| 385 $defineProperty(proto, $getExtensionSymbol(name), method); | 406 $defineProperty(proto, $getExtensionSymbol(name), method); |
| 386 } | 407 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 JS('', '#.__proto__ = #.__proto__', callableCtor, classExpr); | 466 JS('', '#.__proto__ = #.__proto__', callableCtor, classExpr); |
| 446 return callableCtor; | 467 return callableCtor; |
| 447 } | 468 } |
| 448 | 469 |
| 449 /// Given a class and an initializer method name and a call method, creates a | 470 /// Given a class and an initializer method name and a call method, creates a |
| 450 /// constructor function with the same name. | 471 /// constructor function with the same name. |
| 451 /// | 472 /// |
| 452 /// For example it can be called with `new SomeClass.name(args)`. | 473 /// For example it can be called with `new SomeClass.name(args)`. |
| 453 /// | 474 /// |
| 454 /// The constructor | 475 /// The constructor |
| 455 defineNamedConstructorCallable(clazz, name, ctor) => JS('', '''(() => { | 476 defineNamedConstructorCallable(clazz, name, ctor) => JS( |
| 477 '', |
| 478 '''(() => { |
| 456 ctor.prototype = $clazz.prototype; | 479 ctor.prototype = $clazz.prototype; |
| 457 // Use defineProperty so we don't hit a property defined on Function, | 480 // Use defineProperty so we don't hit a property defined on Function, |
| 458 // like `caller` and `arguments`. | 481 // like `caller` and `arguments`. |
| 459 $defineProperty($clazz, $name, { value: ctor, configurable: true }); | 482 $defineProperty($clazz, $name, { value: ctor, configurable: true }); |
| 460 })()'''); | 483 })()'''); |
| OLD | NEW |