| Index: lib/runtime/dart/_classes.js
|
| diff --git a/lib/runtime/dart/_classes.js b/lib/runtime/dart/_classes.js
|
| index 36590277167f0688edaf12a95e590f5ccd14dbd8..c66f75fd24b9d13f5d2fc0747bacab134f11237c 100644
|
| --- a/lib/runtime/dart/_classes.js
|
| +++ b/lib/runtime/dart/_classes.js
|
| @@ -1,79 +1,39 @@
|
| -// 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.
|
| dart_library.library('dart/_classes', null, /* Imports */[
|
| -], /* Lazy Imports */[
|
| - 'dart/_utils',
|
| - 'dart/core',
|
| - 'dart/_interceptors',
|
| + 'dart/_utils'
|
| +], /* Lazy imports */[
|
| 'dart/_types',
|
| 'dart/_rtti',
|
| -], function(exports, dart_utils, core, _interceptors, types, rtti) {
|
| + 'dart/core',
|
| + 'dart/_interceptors'
|
| +], function(exports, utils, _types, rtti, core, _interceptors) {
|
| 'use strict';
|
| -
|
| - const assert = dart_utils.assert_;
|
| - const copyProperties = dart_utils.copyProperties;
|
| - const copyTheseProperties = dart_utils.copyTheseProperties;
|
| - const defineMemoizedGetter = dart_utils.defineMemoizedGetter;
|
| - const safeGetOwnProperty = dart_utils.safeGetOwnProperty;
|
| - const throwInternalError = dart_utils.throwInternalError;
|
| -
|
| + const assert = utils.assert;
|
| + const copyProperties = utils.copyProperties;
|
| + const copyTheseProperties = utils.copyTheseProperties;
|
| + const defineMemoizedGetter = utils.defineMemoizedGetter;
|
| + const safeGetOwnProperty = utils.safeGetOwnProperty;
|
| + const throwInternalError = utils.throwInternalError;
|
| const defineProperty = Object.defineProperty;
|
| const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
| const getOwnPropertySymbols = Object.getOwnPropertySymbols;
|
| -
|
| - /** The Symbol for storing type arguments on a specialized generic type. */
|
| - const _mixins = Symbol('mixins');
|
| - const _implements = Symbol('implements');
|
| - exports.implements = _implements;
|
| - const _metadata = Symbol('metadata');
|
| - exports.metadata = _metadata;
|
| -
|
| - /**
|
| - * 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).
|
| - */
|
| + const _mixins = Symbol("mixins");
|
| + const implements$ = Symbol("implements");
|
| + const metadata = Symbol("metadata");
|
| function mixin(base, ...mixins) {
|
| - // 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 = {};
|
| @@ -83,28 +43,17 @@ dart_library.library('dart/_classes', null, /* Imports */[
|
| return s;
|
| }
|
| });
|
| -
|
| - // Save mixins for reflection
|
| Mixin[_mixins] = mixins;
|
| return Mixin;
|
| }
|
| - exports.mixin = mixin;
|
| -
|
| - function getMixins (clazz) {
|
| + function getMixins(clazz) {
|
| return clazz[_mixins];
|
| }
|
| - exports.getMixins = getMixins;
|
| -
|
| - function getImplements (clazz) {
|
| - return clazz[_implements];
|
| + function getImplements(clazz) {
|
| + return clazz[implements$];
|
| }
|
| - exports.getImplements = getImplements;
|
| -
|
| - /** The Symbol for storing type arguments on a specialized generic type. */
|
| - let _typeArguments = Symbol('typeArguments');
|
| - let _originalDeclaration = Symbol('originalDeclaration');
|
| -
|
| - /** Memoize a generic type constructor function. */
|
| + const _typeArguments = Symbol("typeArguments");
|
| + const _originalDeclaration = Symbol("originalDeclaration");
|
| function generic(typeConstructor) {
|
| let length = typeConstructor.length;
|
| if (length < 1) {
|
| @@ -115,21 +64,19 @@ dart_library.library('dart/_classes', null, /* Imports */[
|
| if (args.length != length && args.length != 0) {
|
| throwInternalError('requires ' + length + ' or 0 type arguments');
|
| }
|
| - while (args.length < length) args.push(types.dynamic);
|
| -
|
| + while (args.length < length)
|
| + args.push(_types.dynamic);
|
| 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);
|
| + 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;
|
| @@ -144,69 +91,42 @@ dart_library.library('dart/_classes', null, /* Imports */[
|
| }
|
| return makeGenericType;
|
| }
|
| - exports.generic = generic;
|
| -
|
| function getGenericClass(type) {
|
| return safeGetOwnProperty(type, _originalDeclaration);
|
| - };
|
| - exports.getGenericClass = getGenericClass;
|
| -
|
| + }
|
| function getGenericArgs(type) {
|
| return safeGetOwnProperty(type, _typeArguments);
|
| - };
|
| - exports.getGenericArgs = getGenericArgs;
|
| -
|
| - let _constructorSig = Symbol('sigCtor');
|
| - let _methodSig = Symbol("sig");
|
| - let _staticSig = Symbol("sigStatic");
|
| -
|
| - /// Get the type of a method using the stored signature
|
| - function _getMethodType(obj, name) {
|
| + }
|
| + const _constructorSig = Symbol("sigCtor");
|
| + const _methodSig = Symbol("sig");
|
| + const _staticSig = Symbol("sigStatic");
|
| + function getMethodType(obj, name) {
|
| 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 types.definiteFunctionType.apply(null, parts);
|
| + return _types.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.
|
| - function _getConstructorType(cls, name) {
|
| - if(!name) name = cls.name;
|
| + function classGetConstructorType(cls, name) {
|
| + 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 types.definiteFunctionType.apply(null, parts);
|
| + return _types.definiteFunctionType.apply(null, parts);
|
| }
|
| - exports.classGetConstructorType = _getConstructorType;
|
| -
|
| - /// 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?
|
| function bind(obj, name, f) {
|
| 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);
|
| + let sig = getMethodType(obj, name);
|
| assert(sig);
|
| rtti.tag(f, sig);
|
| return f;
|
| }
|
| - exports.bind = bind;
|
| -
|
| - // Set up the method signature field on the constructor
|
| function _setMethodSignature(f, sigF) {
|
| defineMemoizedGetter(f, _methodSig, () => {
|
| let sigObj = sigF();
|
| @@ -214,127 +134,71 @@ dart_library.library('dart/_classes', null, /* Imports */[
|
| return sigObj;
|
| });
|
| }
|
| -
|
| - // Set up the constructor signature field on the constructor
|
| function _setConstructorSignature(f, sigF) {
|
| defineMemoizedGetter(f, _constructorSig, sigF);
|
| }
|
| -
|
| - // Set up the static signature field on the constructor
|
| function _setStaticSignature(f, sigF) {
|
| defineMemoizedGetter(f, _staticSig, sigF);
|
| }
|
| -
|
| - // Set the lazily computed runtime type field on static methods
|
| function _setStaticTypes(f, names) {
|
| for (let name of names) {
|
| rtti.tagMemoized(f[name], function() {
|
| let parts = f[_staticSig][name];
|
| - return types.definiteFunctionType.apply(null, parts);
|
| - })
|
| + return _types.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.
|
| function setSignature(f, signature) {
|
| - 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 : [];
|
| + 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);
|
| rtti.tagMemoized(f, () => core.Type);
|
| }
|
| - exports.setSignature = setSignature;
|
| -
|
| function hasMethod(obj, name) {
|
| - return _getMethodType(obj, name) !== void 0;
|
| + return getMethodType(obj, name) !== void 0;
|
| }
|
| - exports.hasMethod = hasMethod;
|
| -
|
| - exports.getMethodType = _getMethodType;
|
| -
|
| - /**
|
| - * 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.
|
| - */
|
| function virtualField(subclass, fieldName) {
|
| - // If the field is already overridden, do nothing.
|
| let prop = getOwnPropertyDescriptor(subclass.prototype, fieldName);
|
| if (prop) return;
|
| -
|
| let symbol = Symbol(subclass.name + '.' + fieldName);
|
| defineProperty(subclass.prototype, fieldName, {
|
| - get: function() { return this[symbol]; },
|
| - set: function(x) { this[symbol] = x; }
|
| + get: function() {
|
| + return this[symbol];
|
| + },
|
| + set: function(x) {
|
| + this[symbol] = x;
|
| + }
|
| });
|
| }
|
| - exports.virtualField = virtualField;
|
| -
|
| - /**
|
| - * Given a class and an initializer method name, creates a constructor
|
| - * function with the same name. For example `new SomeClass.name(args)`.
|
| - */
|
| function defineNamedConstructor(clazz, name) {
|
| let proto = clazz.prototype;
|
| let initMethod = proto[name];
|
| - let ctor = function() { return initMethod.apply(this, arguments); };
|
| + 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 });
|
| + defineProperty(clazz, name, {value: ctor, configurable: true});
|
| }
|
| - exports.defineNamedConstructor = defineNamedConstructor;
|
| -
|
| - let _extensionType = Symbol('extensionType');
|
| -
|
| - let dartx = {};
|
| - exports.dartx = dartx;
|
| -
|
| + const _extensionType = Symbol("extensionType");
|
| + const dartx = {};
|
| function getExtensionSymbol(name) {
|
| let sym = dartx[name];
|
| if (!sym) dartx[name] = sym = Symbol('dartx.' + name);
|
| return sym;
|
| }
|
| -
|
| function defineExtensionNames(names) {
|
| names.forEach(getExtensionSymbol);
|
| }
|
| - exports.defineExtensionNames = defineExtensionNames;
|
| -
|
| - /**
|
| - * Copy symbols from the prototype of the source to destination.
|
| - * These are the only properties safe to copy onto an existing public
|
| - * JavaScript class.
|
| - */
|
| function registerExtension(jsType, dartExtType) {
|
| let extProto = dartExtType.prototype;
|
| let jsProto = jsType.prototype;
|
| -
|
| - // Mark the JS type's instances so we can easily check for extensions.
|
| assert(jsProto[_extensionType] === void 0);
|
| jsProto[_extensionType] = extProto;
|
| -
|
| let dartObjProto = core.Object.prototype;
|
| while (extProto !== dartObjProto && extProto !== jsProto) {
|
| copyTheseProperties(jsProto, extProto, getOwnPropertySymbols(extProto));
|
| @@ -344,39 +208,12 @@ dart_library.library('dart/_classes', null, /* Imports */[
|
| assert(originalSigFn);
|
| defineMemoizedGetter(jsType, _methodSig, originalSigFn);
|
| }
|
| - exports.registerExtension = registerExtension;
|
| -
|
| - /**
|
| - * 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.
|
| function defineExtensionMembers(type, methodNames) {
|
| let proto = type.prototype;
|
| for (let name of methodNames) {
|
| let method = getOwnPropertyDescriptor(proto, name);
|
| 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();
|
| @@ -386,34 +223,55 @@ dart_library.library('dart/_classes', null, /* Imports */[
|
| return sig;
|
| });
|
| }
|
| - exports.defineExtensionMembers = defineExtensionMembers;
|
| -
|
| function canonicalMember(obj, name) {
|
| 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;
|
| }
|
| - exports.canonicalMember = canonicalMember;
|
| -
|
| - /** Sets the type of `obj` to be `type` */
|
| function setType(obj, type) {
|
| obj.__proto__ = type.prototype;
|
| return obj;
|
| }
|
| -
|
| - /** Sets the element type of a list literal. */
|
| function list(obj, elementType) {
|
| return setType(obj, _interceptors.JSArray$(elementType));
|
| }
|
| - exports.list = list;
|
| -
|
| function setBaseClass(derived, base) {
|
| - // Link the extension to the type it's extending as a base class.
|
| derived.prototype.__proto__ = base.prototype;
|
| }
|
| + // Exports:
|
| + exports.assert = assert;
|
| + exports.copyProperties = copyProperties;
|
| + exports.copyTheseProperties = copyTheseProperties;
|
| + exports.defineMemoizedGetter = defineMemoizedGetter;
|
| + exports.safeGetOwnProperty = safeGetOwnProperty;
|
| + exports.throwInternalError = throwInternalError;
|
| + exports.defineProperty = defineProperty;
|
| + exports.getOwnPropertyDescriptor = getOwnPropertyDescriptor;
|
| + exports.getOwnPropertySymbols = getOwnPropertySymbols;
|
| + exports.implements = implements$;
|
| + exports.metadata = metadata;
|
| + exports.mixin = mixin;
|
| + exports.getMixins = getMixins;
|
| + exports.getImplements = getImplements;
|
| + exports.generic = generic;
|
| + exports.getGenericClass = getGenericClass;
|
| + exports.getGenericArgs = getGenericArgs;
|
| + exports.getMethodType = getMethodType;
|
| + exports.classGetConstructorType = classGetConstructorType;
|
| + exports.bind = bind;
|
| + exports.setSignature = setSignature;
|
| + exports.hasMethod = hasMethod;
|
| + exports.virtualField = virtualField;
|
| + exports.defineNamedConstructor = defineNamedConstructor;
|
| + exports.dartx = dartx;
|
| + exports.getExtensionSymbol = getExtensionSymbol;
|
| + exports.defineExtensionNames = defineExtensionNames;
|
| + exports.registerExtension = registerExtension;
|
| + exports.defineExtensionMembers = defineExtensionMembers;
|
| + exports.canonicalMember = canonicalMember;
|
| + exports.setType = setType;
|
| + exports.list = list;
|
| exports.setBaseClass = setBaseClass;
|
| -
|
| });
|
|
|