| 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 16 matching lines...) Expand all Loading... |
| 124 value[$_originalDeclaration] = makeGenericType; | 129 value[$_originalDeclaration] = makeGenericType; |
| 125 } | 130 } |
| 126 } else { | 131 } else { |
| 127 value = new Map(); | 132 value = new Map(); |
| 128 } | 133 } |
| 129 map.set(arg, value); | 134 map.set(arg, value); |
| 130 } | 135 } |
| 131 } | 136 } |
| 132 return value; | 137 return value; |
| 133 } | 138 } |
| 139 makeGenericType[$_genericTypeCtor] = $typeConstructor; |
| 134 return makeGenericType; | 140 return makeGenericType; |
| 135 })()'''); | 141 })()'''); |
| 136 | 142 |
| 137 getGenericClass(type) => | 143 getGenericClass(type) => |
| 138 JS('', '$safeGetOwnProperty($type, $_originalDeclaration)'); | 144 JS('', '$safeGetOwnProperty($type, $_originalDeclaration)'); |
| 139 | 145 |
| 140 getGenericArgs(type) => | 146 getGenericArgs(type) => JS('', '$safeGetOwnProperty($type, $_typeArguments)'); |
| 141 JS('', '$safeGetOwnProperty($type, $_typeArguments)'); | |
| 142 | 147 |
| 143 final _constructorSig = JS('', 'Symbol("sigCtor")'); | 148 final _constructorSig = JS('', 'Symbol("sigCtor")'); |
| 144 final _methodSig = JS('', 'Symbol("sig")'); | 149 final _methodSig = JS('', 'Symbol("sig")'); |
| 145 final _staticSig = JS('', 'Symbol("sigStatic")'); | 150 final _staticSig = JS('', 'Symbol("sigStatic")'); |
| 151 final _genericTypeCtor = JS('', 'Symbol("genericType")'); |
| 152 |
| 153 getMethodSig(value) => JS('', '#[#]', value, _methodSig); |
| 154 getGenericTypeCtor(value) => JS('', '#[#]', value, _genericTypeCtor); |
| 146 | 155 |
| 147 /// Get the type of a method from an object using the stored signature | 156 /// Get the type of a method from an object using the stored signature |
| 148 getMethodType(obj, name) => JS('', '''(() => { | 157 getMethodType(obj, name) => JS( |
| 158 '', |
| 159 '''(() => { |
| 149 let type = $obj == null ? $Object : $obj.__proto__.constructor; | 160 let type = $obj == null ? $Object : $obj.__proto__.constructor; |
| 150 return $getMethodTypeFromType(type, $name); | 161 return $getMethodTypeFromType(type, $name); |
| 151 })()'''); | 162 })()'''); |
| 152 | 163 |
| 153 /// Get the type of a method from a type using the stored signature | 164 /// Get the type of a method from a type using the stored signature |
| 154 getMethodTypeFromType(type, name) => JS('', '''(() => { | 165 getMethodTypeFromType(type, name) => JS( |
| 166 '', |
| 167 '''(() => { |
| 155 let sigObj = $type[$_methodSig]; | 168 let sigObj = $type[$_methodSig]; |
| 156 if (sigObj === void 0) return void 0; | 169 if (sigObj === void 0) return void 0; |
| 157 return sigObj[$name]; | 170 return sigObj[$name]; |
| 158 })()'''); | 171 })()'''); |
| 159 | 172 |
| 160 /// Get the type of a constructor from a class using the stored signature | 173 /// 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 | 174 /// If name is undefined, returns the type of the default constructor |
| 162 /// Returns undefined if the constructor is not found. | 175 /// Returns undefined if the constructor is not found. |
| 163 classGetConstructorType(cls, name) => JS('', '''(() => { | 176 classGetConstructorType(cls, name) => JS( |
| 177 '', |
| 178 '''(() => { |
| 164 if(!$name) $name = $cls.name; | 179 if(!$name) $name = $cls.name; |
| 165 if ($cls === void 0) return void 0; | 180 if ($cls === void 0) return void 0; |
| 166 if ($cls == null) return void 0; | 181 if ($cls == null) return void 0; |
| 167 let sigCtor = $cls[$_constructorSig]; | 182 let sigCtor = $cls[$_constructorSig]; |
| 168 if (sigCtor === void 0) return void 0; | 183 if (sigCtor === void 0) return void 0; |
| 169 return sigCtor[$name]; | 184 return sigCtor[$name]; |
| 170 })()'''); | 185 })()'''); |
| 171 | 186 |
| 172 /// Given an object and a method name, tear off the method. | 187 /// Given an object and a method name, tear off the method. |
| 173 /// Sets the runtime type of the torn off method appropriately, | 188 /// Sets the runtime type of the torn off method appropriately, |
| 174 /// and also binds the object. | 189 /// and also binds the object. |
| 175 /// | 190 /// |
| 176 /// If the optional `f` argument is passed in, it will be used as the method. | 191 /// 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 | 192 /// This supports cases like `super.foo` where we need to tear off the method |
| 178 /// from the superclass, not from the `obj` directly. | 193 /// from the superclass, not from the `obj` directly. |
| 179 /// TODO(leafp): Consider caching the tearoff on the object? | 194 /// TODO(leafp): Consider caching the tearoff on the object? |
| 180 bind(obj, name, f) => JS('', '''(() => { | 195 bind(obj, name, f) => JS( |
| 196 '', |
| 197 '''(() => { |
| 181 if ($f === void 0) $f = $obj[$name]; | 198 if ($f === void 0) $f = $obj[$name]; |
| 182 $f = $f.bind($obj); | 199 $f = $f.bind($obj); |
| 183 // TODO(jmesserly): track the function's signature on the function, instead | 200 // TODO(jmesserly): track the function's signature on the function, instead |
| 184 // of having to go back to the class? | 201 // of having to go back to the class? |
| 185 let sig = $getMethodType($obj, $name); | 202 let sig = $getMethodType($obj, $name); |
| 186 $assert_(sig); | 203 $assert_(sig); |
| 187 $tag($f, sig); | 204 $tag($f, sig); |
| 188 return $f; | 205 return $f; |
| 189 })()'''); | 206 })()'''); |
| 190 | 207 |
| 191 /// Instantiate a generic method. | 208 /// Instantiate a generic method. |
| 192 /// | 209 /// |
| 193 /// We need to apply the type arguments both to the function, as well as its | 210 /// We need to apply the type arguments both to the function, as well as its |
| 194 /// associated function type. | 211 /// associated function type. |
| 195 gbind(f, @rest typeArgs) { | 212 gbind(f, @rest typeArgs) { |
| 196 var result = JS('', '#.apply(null, #)', f, typeArgs); | 213 var result = JS('', '#.apply(null, #)', f, typeArgs); |
| 197 var sig = JS('', '#.apply(null, #)', _getRuntimeType(f), typeArgs); | 214 var sig = JS('', '#.apply(null, #)', _getRuntimeType(f), typeArgs); |
| 198 tag(result, sig); | 215 tag(result, sig); |
| 199 return result; | 216 return result; |
| 200 } | 217 } |
| 201 | 218 |
| 202 // Set up the method signature field on the constructor | 219 // Set up the method signature field on the constructor |
| 203 _setMethodSignature(f, sigF) => JS('', '''(() => { | 220 _setMethodSignature(f, sigF) => JS( |
| 221 '', |
| 222 '''(() => { |
| 204 $defineMemoizedGetter($f, $_methodSig, () => { | 223 $defineMemoizedGetter($f, $_methodSig, () => { |
| 205 let sigObj = $sigF(); | 224 let sigObj = $sigF(); |
| 206 sigObj.__proto__ = $f.__proto__[$_methodSig]; | 225 sigObj.__proto__ = $f.__proto__[$_methodSig]; |
| 207 return sigObj; | 226 return sigObj; |
| 208 }); | 227 }); |
| 209 })()'''); | 228 })()'''); |
| 210 | 229 |
| 211 // Set up the constructor signature field on the constructor | 230 // Set up the constructor signature field on the constructor |
| 212 _setConstructorSignature(f, sigF) => | 231 _setConstructorSignature(f, sigF) => |
| 213 JS('', '$defineMemoizedGetter($f, $_constructorSig, $sigF)'); | 232 JS('', '$defineMemoizedGetter($f, $_constructorSig, $sigF)'); |
| 214 | 233 |
| 215 // Set up the static signature field on the constructor | 234 // Set up the static signature field on the constructor |
| 216 _setStaticSignature(f, sigF) => | 235 _setStaticSignature(f, sigF) => |
| 217 JS('', '$defineMemoizedGetter($f, $_staticSig, $sigF)'); | 236 JS('', '$defineMemoizedGetter($f, $_staticSig, $sigF)'); |
| 218 | 237 |
| 219 // Set the lazily computed runtime type field on static methods | 238 // Set the lazily computed runtime type field on static methods |
| 220 _setStaticTypes(f, names) => JS('', '''(() => { | 239 _setStaticTypes(f, names) => JS( |
| 240 '', |
| 241 '''(() => { |
| 221 for (let name of $names) { | 242 for (let name of $names) { |
| 222 // TODO(vsm): Need to generate static methods. | 243 // TODO(vsm): Need to generate static methods. |
| 223 if (!$f[name]) continue; | 244 if (!$f[name]) continue; |
| 224 $tagLazy($f[name], function() { | 245 $tagLazy($f[name], function() { |
| 225 return $f[$_staticSig][name]; | 246 return $f[$_staticSig][name]; |
| 226 }) | 247 }) |
| 227 } | 248 } |
| 228 })()'''); | 249 })()'''); |
| 229 | 250 |
| 230 /// Set up the type signature of a class (constructor object) | 251 /// Set up the type signature of a class (constructor object) |
| 231 /// f is a constructor object | 252 /// f is a constructor object |
| 232 /// signature is an object containing optional properties as follows: | 253 /// signature is an object containing optional properties as follows: |
| 233 /// methods: A function returning an object mapping method names | 254 /// methods: A function returning an object mapping method names |
| 234 /// to method types. The function is evaluated lazily and cached. | 255 /// to method types. The function is evaluated lazily and cached. |
| 235 /// statics: A function returning an object mapping static method | 256 /// statics: A function returning an object mapping static method |
| 236 /// names to types. The function is evalutated lazily and cached. | 257 /// names to types. The function is evalutated lazily and cached. |
| 237 /// names: An array of the names of the static methods. Used to | 258 /// names: An array of the names of the static methods. Used to |
| 238 /// permit eagerly setting the runtimeType field on the methods | 259 /// permit eagerly setting the runtimeType field on the methods |
| 239 /// while still lazily computing the type descriptor object. | 260 /// while still lazily computing the type descriptor object. |
| 240 setSignature(f, signature) => JS('', '''(() => { | 261 setSignature(f, signature) => JS( |
| 262 '', |
| 263 '''(() => { |
| 241 // TODO(ochafik): Deconstruct these when supported by Chrome. | 264 // TODO(ochafik): Deconstruct these when supported by Chrome. |
| 242 let constructors = | 265 let constructors = |
| 243 ('constructors' in signature) ? signature.constructors : () => ({}); | 266 ('constructors' in signature) ? signature.constructors : () => ({}); |
| 244 let methods = | 267 let methods = |
| 245 ('methods' in signature) ? signature.methods : () => ({}); | 268 ('methods' in signature) ? signature.methods : () => ({}); |
| 246 let statics = | 269 let statics = |
| 247 ('statics' in signature) ? signature.statics : () => ({}); | 270 ('statics' in signature) ? signature.statics : () => ({}); |
| 248 let names = | 271 let names = |
| 249 ('names' in signature) ? signature.names : []; | 272 ('names' in signature) ? signature.names : []; |
| 250 $_setConstructorSignature($f, constructors); | 273 $_setConstructorSignature($f, constructors); |
| 251 $_setMethodSignature($f, methods); | 274 $_setMethodSignature($f, methods); |
| 252 $_setStaticSignature($f, statics); | 275 $_setStaticSignature($f, statics); |
| 253 $_setStaticTypes($f, names); | 276 $_setStaticTypes($f, names); |
| 254 })()'''); | 277 })()'''); |
| 255 | 278 |
| 256 hasMethod(obj, name) => JS('', '$getMethodType($obj, $name) !== void 0'); | 279 hasMethod(obj, name) => JS('', '$getMethodType($obj, $name) !== void 0'); |
| 257 | 280 |
| 258 /// Given a class and an initializer method name, creates a constructor | 281 /// Given a class and an initializer method name, creates a constructor |
| 259 /// function with the same name. | 282 /// function with the same name. |
| 260 /// | 283 /// |
| 261 /// After we define the named constructor, the class can be constructed with | 284 /// After we define the named constructor, the class can be constructed with |
| 262 /// `new SomeClass.name(args)`. | 285 /// `new SomeClass.name(args)`. |
| 263 defineNamedConstructor(clazz, name) => JS('', '''(() => { | 286 defineNamedConstructor(clazz, name) => JS( |
| 287 '', |
| 288 '''(() => { |
| 264 let proto = $clazz.prototype; | 289 let proto = $clazz.prototype; |
| 265 let initMethod = proto[$name]; | 290 let initMethod = proto[$name]; |
| 266 let ctor = function(...args) { initMethod.apply(this, args); }; | 291 let ctor = function(...args) { initMethod.apply(this, args); }; |
| 292 ctor[$isNamedConstructor] = true; |
| 267 ctor.prototype = proto; | 293 ctor.prototype = proto; |
| 268 // Use defineProperty so we don't hit a property defined on Function, | 294 // Use defineProperty so we don't hit a property defined on Function, |
| 269 // like `caller` and `arguments`. | 295 // like `caller` and `arguments`. |
| 270 $defineProperty($clazz, $name, { value: ctor, configurable: true }); | 296 $defineProperty($clazz, $name, { value: ctor, configurable: true }); |
| 271 })()'''); | 297 })()'''); |
| 272 | 298 |
| 273 | |
| 274 final _extensionType = JS('', 'Symbol("extensionType")'); | 299 final _extensionType = JS('', 'Symbol("extensionType")'); |
| 275 | 300 |
| 276 getExtensionType(obj) => JS('', '#[#]', obj, _extensionType); | 301 getExtensionType(obj) => JS('', '#[#]', obj, _extensionType); |
| 277 | 302 |
| 278 final dartx = JS('', 'dartx'); | 303 final dartx = JS('', 'dartx'); |
| 279 | 304 |
| 280 getExtensionSymbol(name) { | 305 getExtensionSymbol(name) { |
| 281 var sym = JS('', 'dartx[#]', name); | 306 var sym = JS('', 'dartx[#]', name); |
| 282 if (sym == null) { | 307 if (sym == null) { |
| 283 sym = JS('', 'Symbol("dartx." + #.toString())', name); | 308 sym = JS('', 'Symbol("dartx." + #.toString())', name); |
| 284 JS('', 'dartx[#] = #', name, sym); | 309 JS('', 'dartx[#] = #', name, sym); |
| 285 } | 310 } |
| 286 return sym; | 311 return sym; |
| 287 } | 312 } |
| 288 | 313 |
| 289 defineExtensionNames(names) => | 314 defineExtensionNames(names) => |
| 290 JS('', '#.forEach(#)', names, getExtensionSymbol); | 315 JS('', '#.forEach(#)', names, getExtensionSymbol); |
| 291 | 316 |
| 292 | |
| 293 /// Install properties in prototype-first order. Properties / descriptors from | 317 /// Install properties in prototype-first order. Properties / descriptors from |
| 294 /// more specific types should overwrite ones from less specific types. | 318 /// more specific types should overwrite ones from less specific types. |
| 295 void _installProperties(jsProto, extProto) { | 319 void _installProperties(jsProto, extProto) { |
| 296 | |
| 297 // This relies on the Dart type literal evaluating to the JavaScript | 320 // This relies on the Dart type literal evaluating to the JavaScript |
| 298 // constructor. | 321 // constructor. |
| 299 var coreObjProto = JS('', '#.prototype', Object); | 322 var coreObjProto = JS('', '#.prototype', Object); |
| 300 | 323 |
| 301 var parentsExtension = | 324 var parentsExtension = JS('', '(#.__proto__)[#]', jsProto, _extensionType); |
| 302 JS('', '(#.__proto__)[#]', jsProto, _extensionType); | |
| 303 var installedParent = | 325 var installedParent = |
| 304 JS('', '# && #.prototype', parentsExtension, parentsExtension); | 326 JS('', '# && #.prototype', parentsExtension, parentsExtension); |
| 305 | 327 |
| 306 _installProperties2(jsProto, extProto, coreObjProto, installedParent); | 328 _installProperties2(jsProto, extProto, coreObjProto, installedParent); |
| 307 } | 329 } |
| 308 | 330 |
| 309 void _installProperties2(jsProto, extProto, coreObjProto, installedParent) { | 331 void _installProperties2(jsProto, extProto, coreObjProto, installedParent) { |
| 310 if (JS('bool', '# === #', extProto, coreObjProto)) { | 332 if (JS('bool', '# === #', extProto, coreObjProto)) { |
| 311 _installPropertiesForObject(jsProto, coreObjProto); | 333 _installPropertiesForObject(jsProto, coreObjProto); |
| 312 return; | 334 return; |
| 313 } | 335 } |
| 314 if (JS('bool', '# !== #', jsProto, extProto)) { | 336 if (JS('bool', '# !== #', jsProto, extProto)) { |
| 315 var extParent = JS('', '#.__proto__', extProto); | 337 var extParent = JS('', '#.__proto__', extProto); |
| 316 | 338 |
| 317 // If the extension methods of the parent have been installed on the parent | 339 // If the extension methods of the parent have been installed on the parent |
| 318 // of [jsProto], the methods will be available via prototype inheritance. | 340 // of [jsProto], the methods will be available via prototype inheritance. |
| 319 | 341 |
| 320 if(JS('bool', '# !== #', installedParent, extParent)) { | 342 if (JS('bool', '# !== #', installedParent, extParent)) { |
| 321 _installProperties2(jsProto, extParent, coreObjProto, installedParent); | 343 _installProperties2(jsProto, extParent, coreObjProto, installedParent); |
| 322 } | 344 } |
| 323 } | 345 } |
| 324 copyTheseProperties(jsProto, extProto, getOwnPropertySymbols(extProto)); | 346 copyTheseProperties(jsProto, extProto, getOwnPropertySymbols(extProto)); |
| 325 } | 347 } |
| 326 | 348 |
| 327 void _installPropertiesForObject(jsProto, coreObjProto) { | 349 void _installPropertiesForObject(jsProto, coreObjProto) { |
| 328 // core.Object members need to be copied from the non-symbol name to the | 350 // core.Object members need to be copied from the non-symbol name to the |
| 329 // symbol name. | 351 // symbol name. |
| 330 var names = getOwnPropertyNames(coreObjProto); | 352 var names = getOwnPropertyNames(coreObjProto); |
| 331 for (int i = 0; i < JS('int', '#.length', names); ++i) { | 353 for (int i = 0; i < JS('int', '#.length', names); ++i) { |
| 332 var name = JS('', '#[#]', names, i); | 354 var name = JS('', '#[#]', names, i); |
| 333 var desc = getOwnPropertyDescriptor(coreObjProto, name); | 355 var desc = getOwnPropertyDescriptor(coreObjProto, name); |
| 334 defineProperty(jsProto, getExtensionSymbol(name), desc); | 356 defineProperty(jsProto, getExtensionSymbol(name), desc); |
| 335 } | 357 } |
| 336 return; | 358 return; |
| 337 } | 359 } |
| 338 | 360 |
| 339 /// Copy symbols from the prototype of the source to destination. | 361 /// Copy symbols from the prototype of the source to destination. |
| 340 /// These are the only properties safe to copy onto an existing public | 362 /// These are the only properties safe to copy onto an existing public |
| 341 /// JavaScript class. | 363 /// JavaScript class. |
| 342 registerExtension(jsType, dartExtType) => JS('', '''(() => { | 364 registerExtension(jsType, dartExtType) => JS( |
| 365 '', |
| 366 '''(() => { |
| 343 // TODO(vsm): Not all registered js types are real. | 367 // TODO(vsm): Not all registered js types are real. |
| 344 if (!jsType) return; | 368 if (!jsType) return; |
| 345 | 369 |
| 346 let extProto = $dartExtType.prototype; | 370 let extProto = $dartExtType.prototype; |
| 347 let jsProto = $jsType.prototype; | 371 let jsProto = $jsType.prototype; |
| 348 | 372 |
| 349 // Mark the JS type's instances so we can easily check for extensions. | 373 // Mark the JS type's instances so we can easily check for extensions. |
| 350 jsProto[$_extensionType] = $dartExtType; | 374 jsProto[$_extensionType] = $dartExtType; |
| 351 $_installProperties(jsProto, extProto); | 375 $_installProperties(jsProto, extProto); |
| 352 let originalSigFn = $getOwnPropertyDescriptor($dartExtType, $_methodSig).get; | 376 let originalSigFn = $getOwnPropertyDescriptor($dartExtType, $_methodSig).get; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 366 /// | 390 /// |
| 367 /// Results in: | 391 /// Results in: |
| 368 /// | 392 /// |
| 369 /// MyType.prototype[dartx.add] = MyType.prototype.add; | 393 /// MyType.prototype[dartx.add] = MyType.prototype.add; |
| 370 /// MyType.prototype[dartx.remove] = MyType.prototype.remove; | 394 /// MyType.prototype[dartx.remove] = MyType.prototype.remove; |
| 371 /// | 395 /// |
| 372 // TODO(jmesserly): essentially this gives two names to the same method. | 396 // TODO(jmesserly): essentially this gives two names to the same method. |
| 373 // This benefit is roughly equivalent call performance either way, but the | 397 // This benefit is roughly equivalent call performance either way, but the |
| 374 // cost is we need to call defineExtensionMembers any time a subclass | 398 // cost is we need to call defineExtensionMembers any time a subclass |
| 375 // overrides one of these methods. | 399 // overrides one of these methods. |
| 376 defineExtensionMembers(type, methodNames) => JS('', '''(() => { | 400 defineExtensionMembers(type, methodNames) => JS( |
| 401 '', |
| 402 '''(() => { |
| 377 let proto = $type.prototype; | 403 let proto = $type.prototype; |
| 378 for (let name of $methodNames) { | 404 for (let name of $methodNames) { |
| 379 let method = $getOwnPropertyDescriptor(proto, name); | 405 let method = $getOwnPropertyDescriptor(proto, name); |
| 380 // TODO(vsm): We should be able to generate code to avoid this case. | 406 // 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 | 407 // 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 | 408 // 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. | 409 // generating a corresponding getter/setter method - it's just a field. |
| 384 if (!method) continue; | 410 if (!method) continue; |
| 385 $defineProperty(proto, $getExtensionSymbol(name), method); | 411 $defineProperty(proto, $getExtensionSymbol(name), method); |
| 386 } | 412 } |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 JS('', '#.__proto__ = #.__proto__', callableCtor, classExpr); | 471 JS('', '#.__proto__ = #.__proto__', callableCtor, classExpr); |
| 446 return callableCtor; | 472 return callableCtor; |
| 447 } | 473 } |
| 448 | 474 |
| 449 /// Given a class and an initializer method name and a call method, creates a | 475 /// Given a class and an initializer method name and a call method, creates a |
| 450 /// constructor function with the same name. | 476 /// constructor function with the same name. |
| 451 /// | 477 /// |
| 452 /// For example it can be called with `new SomeClass.name(args)`. | 478 /// For example it can be called with `new SomeClass.name(args)`. |
| 453 /// | 479 /// |
| 454 /// The constructor | 480 /// The constructor |
| 455 defineNamedConstructorCallable(clazz, name, ctor) => JS('', '''(() => { | 481 defineNamedConstructorCallable(clazz, name, ctor) => JS( |
| 482 '', |
| 483 '''(() => { |
| 456 ctor.prototype = $clazz.prototype; | 484 ctor.prototype = $clazz.prototype; |
| 457 // Use defineProperty so we don't hit a property defined on Function, | 485 // Use defineProperty so we don't hit a property defined on Function, |
| 458 // like `caller` and `arguments`. | 486 // like `caller` and `arguments`. |
| 459 $defineProperty($clazz, $name, { value: ctor, configurable: true }); | 487 $defineProperty($clazz, $name, { value: ctor, configurable: true }); |
| 460 })()'''); | 488 })()'''); |
| OLD | NEW |