| Index: tool/input_sdk/private/classes.dart
|
| diff --git a/tool/input_sdk/private/classes.dart b/tool/input_sdk/private/classes.dart
|
| deleted file mode 100644
|
| index 4b27c394c23e3b3edc70caaf9a2b59c2f1120433..0000000000000000000000000000000000000000
|
| --- a/tool/input_sdk/private/classes.dart
|
| +++ /dev/null
|
| @@ -1,376 +0,0 @@
|
| -// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -/// This library defines the operations that define and manipulate Dart
|
| -/// classes. Included in this are:
|
| -/// - Generics
|
| -/// - Class metadata
|
| -/// - Extension methods
|
| -///
|
| -
|
| -// TODO(leafp): Consider splitting some of this out.
|
| -part of dart._runtime;
|
| -
|
| -///
|
| -/// Returns a new type that mixes members from base and all mixins.
|
| -///
|
| -/// Each mixin applies in sequence, with further to the right ones overriding
|
| -/// previous entries.
|
| -///
|
| -/// For each mixin, we only take its own properties, not anything from its
|
| -/// superclass (prototype).
|
| -///
|
| -mixin(base, @rest mixins) => JS('', '''(() => {
|
| - // Create an initializer for the mixin, so when derived constructor calls
|
| - // super, we can correctly initialize base and mixins.
|
| -
|
| - // Create a class that will hold all of the mixin methods.
|
| - class Mixin extends $base {
|
| - // Initializer method: run mixin initializers, then the base.
|
| - [$base.name](...args) {
|
| - // Run mixin initializers. They cannot have arguments.
|
| - // Run them backwards so most-derived mixin is initialized first.
|
| - for (let i = $mixins.length - 1; i >= 0; i--) {
|
| - let mixin = $mixins[i];
|
| - let init = mixin.prototype[mixin.name];
|
| - if (init) init.call(this);
|
| - }
|
| - // Run base initializer.
|
| - let init = $base.prototype[base.name];
|
| - if (init) init.apply(this, args);
|
| - }
|
| - }
|
| - // Copy each mixin's methods, with later ones overwriting earlier entries.
|
| - for (let m of $mixins) {
|
| - $copyProperties(Mixin.prototype, m.prototype);
|
| - }
|
| -
|
| - // Set the signature of the Mixin class to be the composition
|
| - // of the signatures of the mixins.
|
| - $setSignature(Mixin, {
|
| - methods: () => {
|
| - let s = {};
|
| - for (let m of $mixins) {
|
| - $copyProperties(s, m[$_methodSig]);
|
| - }
|
| - return s;
|
| - }
|
| - });
|
| -
|
| - // Save mixins for reflection
|
| - Mixin[$_mixins] = $mixins;
|
| - return Mixin;
|
| -})()''');
|
| -
|
| -getMixins(clazz) => JS('', '$clazz[$_mixins]');
|
| -
|
| -getImplements(clazz) => JS('', '$clazz[$implements_]');
|
| -
|
| -/// The Symbol for storing type arguments on a specialized generic type.
|
| -final _typeArguments = JS('', 'Symbol("typeArguments")');
|
| -final _originalDeclaration = JS('', 'Symbol("originalDeclaration")');
|
| -
|
| -/// Memoize a generic type constructor function.
|
| -generic(typeConstructor) => JS('', '''(() => {
|
| - let length = $typeConstructor.length;
|
| - if (length < 1) {
|
| - $throwInternalError('must have at least one generic type argument');
|
| - }
|
| - let resultMap = new Map();
|
| - function makeGenericType(...args) {
|
| - if (args.length != length && args.length != 0) {
|
| - $throwInternalError('requires ' + length + ' or 0 type arguments');
|
| - }
|
| - while (args.length < length) args.push($dynamicR);
|
| -
|
| - let value = resultMap;
|
| - for (let i = 0; i < length; i++) {
|
| - let arg = args[i];
|
| - if (arg == null) {
|
| - $throwInternalError('type arguments should not be null: '
|
| - + $typeConstructor);
|
| - }
|
| - let map = value;
|
| - value = map.get(arg);
|
| - if (value === void 0) {
|
| - if (i + 1 == length) {
|
| - value = $typeConstructor.apply(null, args);
|
| - // Save the type constructor and arguments for reflection.
|
| - if (value) {
|
| - value[$_typeArguments] = args;
|
| - value[$_originalDeclaration] = makeGenericType;
|
| - }
|
| - } else {
|
| - value = new Map();
|
| - }
|
| - map.set(arg, value);
|
| - }
|
| - }
|
| - return value;
|
| - }
|
| - return makeGenericType;
|
| -})()''');
|
| -
|
| -getGenericClass(type) =>
|
| - JS('', '$safeGetOwnProperty($type, $_originalDeclaration)');
|
| -
|
| -getGenericArgs(type) =>
|
| - JS('', '$safeGetOwnProperty($type, $_typeArguments)');
|
| -
|
| -final _constructorSig = JS('', 'Symbol("sigCtor")');
|
| -final _methodSig = JS('', 'Symbol("sig")');
|
| -final _staticSig = JS('', 'Symbol("sigStatic")');
|
| -
|
| -/// Get the type of a method using the stored signature
|
| -getMethodType(obj, name) => JS('', '''(() => {
|
| - if ($obj === void 0) return void 0;
|
| - if ($obj == null) return void 0;
|
| - let sigObj = $obj.__proto__.constructor[$_methodSig];
|
| - if (sigObj === void 0) return void 0;
|
| - let parts = sigObj[$name];
|
| - if (parts === void 0) return void 0;
|
| - return $definiteFunctionType.apply(null, parts);
|
| -})()''');
|
| -
|
| -/// Get the type of a constructor from a class using the stored signature
|
| -/// If name is undefined, returns the type of the default constructor
|
| -/// Returns undefined if the constructor is not found.
|
| -classGetConstructorType(cls, name) => JS('', '''(() => {
|
| - if(!$name) $name = $cls.name;
|
| - if ($cls === void 0) return void 0;
|
| - if ($cls == null) return void 0;
|
| - let sigCtor = $cls[$_constructorSig];
|
| - if (sigCtor === void 0) return void 0;
|
| - let parts = sigCtor[$name];
|
| - if (parts === void 0) return void 0;
|
| - return $definiteFunctionType.apply(null, parts);
|
| -})()''');
|
| -
|
| -/// Given an object and a method name, tear off the method.
|
| -/// Sets the runtime type of the torn off method appropriately,
|
| -/// and also binds the object.
|
| -///
|
| -/// If the optional `f` argument is passed in, it will be used as the method.
|
| -/// This supports cases like `super.foo` where we need to tear off the method
|
| -/// from the superclass, not from the `obj` directly.
|
| -/// TODO(leafp): Consider caching the tearoff on the object?
|
| -bind(obj, name, f) => JS('', '''(() => {
|
| - if ($f === void 0) $f = $obj[$name];
|
| - $f = $f.bind($obj);
|
| - // TODO(jmesserly): track the function's signature on the function, instead
|
| - // of having to go back to the class?
|
| - let sig = $getMethodType($obj, $name);
|
| - $assert_(sig);
|
| - $tag($f, sig);
|
| - return $f;
|
| -})()''');
|
| -
|
| -// Set up the method signature field on the constructor
|
| -_setMethodSignature(f, sigF) => JS('', '''(() => {
|
| - $defineMemoizedGetter($f, $_methodSig, () => {
|
| - let sigObj = $sigF();
|
| - sigObj.__proto__ = $f.__proto__[$_methodSig];
|
| - return sigObj;
|
| - });
|
| -})()''');
|
| -
|
| -// Set up the constructor signature field on the constructor
|
| -_setConstructorSignature(f, sigF) =>
|
| - JS('', '$defineMemoizedGetter($f, $_constructorSig, $sigF)');
|
| -
|
| -// Set up the static signature field on the constructor
|
| -_setStaticSignature(f, sigF) =>
|
| - JS('', '$defineMemoizedGetter($f, $_staticSig, $sigF)');
|
| -
|
| -// Set the lazily computed runtime type field on static methods
|
| -_setStaticTypes(f, names) => JS('', '''(() => {
|
| - for (let name of $names) {
|
| - // TODO(vsm): Need to generate static methods.
|
| - if (!$f[name]) continue;
|
| - $tagMemoized($f[name], function() {
|
| - let parts = $f[$_staticSig][name];
|
| - return $definiteFunctionType.apply(null, parts);
|
| - })
|
| - }
|
| -})()''');
|
| -
|
| -/// Set up the type signature of a class (constructor object)
|
| -/// f is a constructor object
|
| -/// signature is an object containing optional properties as follows:
|
| -/// methods: A function returning an object mapping method names
|
| -/// to method types. The function is evaluated lazily and cached.
|
| -/// statics: A function returning an object mapping static method
|
| -/// names to types. The function is evalutated lazily and cached.
|
| -/// names: An array of the names of the static methods. Used to
|
| -/// permit eagerly setting the runtimeType field on the methods
|
| -/// while still lazily computing the type descriptor object.
|
| -setSignature(f, signature) => JS('', '''(() => {
|
| - // TODO(ochafik): Deconstruct these when supported by Chrome.
|
| - let constructors =
|
| - ('constructors' in signature) ? signature.constructors : () => ({});
|
| - let methods =
|
| - ('methods' in signature) ? signature.methods : () => ({});
|
| - let statics =
|
| - ('statics' in signature) ? signature.statics : () => ({});
|
| - let names =
|
| - ('names' in signature) ? signature.names : [];
|
| - $_setConstructorSignature($f, constructors);
|
| - $_setMethodSignature($f, methods);
|
| - $_setStaticSignature($f, statics);
|
| - $_setStaticTypes($f, names);
|
| - $tagMemoized($f, () => $Type);
|
| -})()''');
|
| -
|
| -hasMethod(obj, name) => JS('', '$getMethodType($obj, $name) !== void 0');
|
| -
|
| -///
|
| -/// This is called whenever a derived class needs to introduce a new field,
|
| -/// shadowing a field or getter/setter pair on its parent.
|
| -///
|
| -/// This is important because otherwise, trying to read or write the field
|
| -/// would end up calling the getter or setter, and one of those might not even
|
| -/// exist, resulting in a runtime error. Even if they did exist, that's the
|
| -/// wrong behavior if a new field was declared.
|
| -///
|
| -virtualField(subclass, fieldName) => JS('', '''(() => {
|
| - // If the field is already overridden, do nothing.
|
| - let prop = $getOwnPropertyDescriptor($subclass.prototype, $fieldName);
|
| - if (prop) return;
|
| -
|
| - let symbol = Symbol($subclass.name + '.' + $fieldName.toString());
|
| - $defineProperty($subclass.prototype, $fieldName, {
|
| - get: function() { return this[symbol]; },
|
| - set: function(x) { this[symbol] = x; }
|
| - });
|
| -})()''');
|
| -
|
| -///
|
| -/// Given a class and an initializer method name, creates a constructor
|
| -/// function with the same name. For example `new SomeClass.name(args)`.
|
| -///
|
| -defineNamedConstructor(clazz, name) => JS('', '''(() => {
|
| - let proto = $clazz.prototype;
|
| - let initMethod = proto[$name];
|
| - let ctor = function() { return initMethod.apply(this, arguments); };
|
| - ctor.prototype = proto;
|
| - // Use defineProperty so we don't hit a property defined on Function,
|
| - // like `caller` and `arguments`.
|
| - $defineProperty($clazz, $name, { value: ctor, configurable: true });
|
| -})()''');
|
| -
|
| -final _extensionType = JS('', 'Symbol("extensionType")');
|
| -
|
| -getExtensionType(obj) => JS('', '$obj[$_extensionType]');
|
| -
|
| -final dartx = JS('', '{}');
|
| -
|
| -getExtensionSymbol(name) => JS('', '''(() => {
|
| - let sym = $dartx[$name];
|
| - if (!sym) $dartx[$name] = sym = Symbol('dartx.' + $name.toString());
|
| - return sym;
|
| -})()''');
|
| -
|
| -defineExtensionNames(names) => JS('', '$names.forEach($getExtensionSymbol)');
|
| -
|
| -// Install properties in prototype order. Properties / descriptors from
|
| -// more specific types should overwrite ones from less specific types.
|
| -_installProperties(jsProto, extProto) => JS('', '''(() => {
|
| - if (extProto !== $Object.prototype && extProto !== jsProto) {
|
| - $_installProperties(jsProto, extProto.__proto__);
|
| - }
|
| - $copyTheseProperties(jsProto, extProto, $getOwnPropertySymbols(extProto));
|
| -})()''');
|
| -
|
| -///
|
| -/// Copy symbols from the prototype of the source to destination.
|
| -/// These are the only properties safe to copy onto an existing public
|
| -/// JavaScript class.
|
| -///
|
| -registerExtension(jsType, dartExtType) => JS('', '''(() => {
|
| - // TODO(vsm): Not all registered js types are real.
|
| - if (!jsType) return;
|
| -
|
| - let extProto = $dartExtType.prototype;
|
| - let jsProto = $jsType.prototype;
|
| -
|
| - // Mark the JS type's instances so we can easily check for extensions.
|
| - jsProto[$_extensionType] = $dartExtType;
|
| - $_installProperties(jsProto, extProto);
|
| - let originalSigFn = $getOwnPropertyDescriptor($dartExtType, $_methodSig).get;
|
| - $assert_(originalSigFn);
|
| - $defineMemoizedGetter($jsType, $_methodSig, originalSigFn);
|
| -})()''');
|
| -
|
| -///
|
| -/// Mark a concrete type as implementing extension methods.
|
| -/// For example: `class MyIter implements Iterable`.
|
| -///
|
| -/// This takes a list of names, which are the extension methods implemented.
|
| -/// It will add a forwarder, so the extension method name redirects to the
|
| -/// normal Dart method name. For example:
|
| -///
|
| -/// defineExtensionMembers(MyType, ['add', 'remove']);
|
| -///
|
| -/// Results in:
|
| -///
|
| -/// MyType.prototype[dartx.add] = MyType.prototype.add;
|
| -/// MyType.prototype[dartx.remove] = MyType.prototype.remove;
|
| -///
|
| -// TODO(jmesserly): essentially this gives two names to the same method.
|
| -// This benefit is roughly equivalent call performance either way, but the
|
| -// cost is we need to call defineExtensionMembers any time a subclass
|
| -// overrides one of these methods.
|
| -defineExtensionMembers(type, methodNames) => JS('', '''(() => {
|
| - let proto = $type.prototype;
|
| - for (let name of $methodNames) {
|
| - let method = $getOwnPropertyDescriptor(proto, name);
|
| - // TODO(vsm): We should be able to generate code to avoid this case.
|
| - // The method may be null if this type implements a potentially native
|
| - // interface but isn't native itself. For a field on this type, we're not
|
| - // generating a corresponding getter/setter method - it's just a field.
|
| - if (!method) continue;
|
| - $defineProperty(proto, $getExtensionSymbol(name), method);
|
| - }
|
| - // Ensure the signature is available too.
|
| - // TODO(jmesserly): not sure if we can do this in a cleaner way. Essentially
|
| - // we need to copy the signature (and in the future, other data like
|
| - // annotations) any time we copy a method as part of our metaprogramming.
|
| - // It might be more friendly to JS metaprogramming if we include this info
|
| - // on the function.
|
| - let originalSigFn = $getOwnPropertyDescriptor($type, $_methodSig).get;
|
| - $defineMemoizedGetter(type, $_methodSig, function() {
|
| - let sig = originalSigFn();
|
| - for (let name of $methodNames) {
|
| - sig[$getExtensionSymbol(name)] = sig[name];
|
| - }
|
| - return sig;
|
| - });
|
| -})()''');
|
| -
|
| -canonicalMember(obj, name) => JS('', '''(() => {
|
| - if ($obj != null && $obj[$_extensionType]) return $dartx[$name];
|
| - // Check for certain names that we can't use in JS
|
| - if ($name == 'constructor' || $name == 'prototype') {
|
| - $name = '+' + $name;
|
| - }
|
| - return $name;
|
| -})()''');
|
| -
|
| -/// Sets the type of `obj` to be `type`
|
| -setType(obj, type) => JS('', '''(() => {
|
| - $obj.__proto__ = $type.prototype;
|
| - // TODO(vsm): This should be set in registerExtension, but that is only
|
| - // invoked on the generic type (e.g., JSArray<dynamic>, not JSArray<int>).
|
| - $obj.__proto__[$_extensionType] = $type;
|
| - return $obj;
|
| -})()''');
|
| -
|
| -/// Sets the element type of a list literal.
|
| -list(obj, elementType) =>
|
| - JS('', '$setType($obj, ${getGenericClass(JSArray)}($elementType))');
|
| -
|
| -setBaseClass(derived, base) => JS('', '''(() => {
|
| - // Link the extension to the type it's extending as a base class.
|
| - $derived.prototype.__proto__ = $base.prototype;
|
| -})()''');
|
|
|