| Index: pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
|
| diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
|
| index edb056aa1c05493a0eba2dc2836c6cf28ab44511..63480fd29f492e335175ae27ea37441f4087f94b 100644
|
| --- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
|
| +++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
|
| @@ -182,56 +182,61 @@ class WrappedType extends Type {
|
| toString() => typeName(_wrappedType);
|
| }
|
|
|
| -final AbstractFunctionType = JS(
|
| - '',
|
| - '''
|
| - class AbstractFunctionType extends $TypeRep {
|
| - constructor() {
|
| - super();
|
| - this._stringValue = null;
|
| - }
|
| -
|
| - toString() { return this.name; }
|
| +abstract class AbstractFunctionType extends TypeRep {
|
| + String _stringValue = null;
|
| + get args;
|
| + get optionals;
|
| + get metadata;
|
| + get named;
|
| + get returnType;
|
| +
|
| + AbstractFunctionType() {}
|
| +
|
| + toString() {
|
| + return name;
|
| + }
|
|
|
| - get name() {
|
| - if (this._stringValue) return this._stringValue;
|
| + get name {
|
| + if (_stringValue != null) return _stringValue;
|
|
|
| - let buffer = '(';
|
| - for (let i = 0; i < this.args.length; ++i) {
|
| + var buffer = '(';
|
| + for (var i = 0; JS('bool', '# < #.length', i, args); ++i) {
|
| + if (i > 0) {
|
| + buffer += ', ';
|
| + }
|
| + buffer += typeName(JS('', '#[#]', args, i));
|
| + }
|
| + if (JS('bool', '#.length > 0', optionals)) {
|
| + if (JS('bool', '#.length > 0', args)) buffer += ', ';
|
| + buffer += '[';
|
| + for (var i = 0; JS('bool', '# < #.length', i, optionals); ++i) {
|
| if (i > 0) {
|
| buffer += ', ';
|
| }
|
| - buffer += $typeName(this.args[i]);
|
| + buffer += typeName(JS('', '#[#]', optionals, i));
|
| }
|
| - if (this.optionals.length > 0) {
|
| - if (this.args.length > 0) buffer += ', ';
|
| - buffer += '[';
|
| - for (let i = 0; i < this.optionals.length; ++i) {
|
| - if (i > 0) {
|
| - buffer += ', ';
|
| - }
|
| - buffer += $typeName(this.optionals[i]);
|
| - }
|
| - buffer += ']';
|
| - } else if (Object.keys(this.named).length > 0) {
|
| - if (this.args.length > 0) buffer += ', ';
|
| - buffer += '{';
|
| - let names = $getOwnPropertyNames(this.named).sort();
|
| - for (let i = 0; i < names.length; ++i) {
|
| - if (i > 0) {
|
| - buffer += ', ';
|
| - }
|
| - buffer += names[i] + ': ' + $typeName(this.named[names[i]]);
|
| + buffer += ']';
|
| + } else if (JS('bool', 'Object.keys(#).length > 0', named)) {
|
| + if (JS('bool', '#.length > 0', args)) buffer += ', ';
|
| + buffer += '{';
|
| + var names = getOwnPropertyNames(named);
|
| + JS('', '#.sort()', names);
|
| + for (var i = 0; JS('', '# < #.length', i, names); ++i) {
|
| + if (i > 0) {
|
| + buffer += ', ';
|
| }
|
| - buffer += '}';
|
| + var typeNameString = typeName(JS('', '#[#[#]]', named, names, i));
|
| + buffer += '${JS('', '#[#]', names, i)}: $typeNameString';
|
| }
|
| -
|
| - buffer += ') -> ' + $typeName(this.returnType);
|
| - this._stringValue = buffer;
|
| - return buffer;
|
| + buffer += '}';
|
| }
|
| +
|
| + var returnTypeName = typeName(returnType);
|
| + buffer += ') -> $returnTypeName';
|
| + _stringValue = buffer;
|
| + return buffer;
|
| }
|
| -''');
|
| +}
|
|
|
| /// Memo table for named argument groups. A named argument packet
|
| /// {name1 : type1, ..., namen : typen} corresponds to the path
|
| @@ -260,207 +265,215 @@ final _fnTypeTypeMap = JS('', 'new Map()');
|
| /// of required arguments yields a map which is indexed by the
|
| /// argument types themselves. The element reached via this
|
| /// index path (if present) is the canonical function type.
|
| -final _fnTypeSmallMap = JS('', '[new Map(), new Map(), new Map()]');
|
| +final List _fnTypeSmallMap = JS('', '[new Map(), new Map(), new Map()]');
|
|
|
| -final FunctionType = JS(
|
| +_memoizeArray(map, arr, create) => JS(
|
| '',
|
| - '''
|
| - class FunctionType extends $AbstractFunctionType {
|
| - static _memoizeArray(map, arr, create) {
|
| - let len = arr.length;
|
| - map = FunctionType._lookupNonTerminal(map, len);
|
| - for (var i = 0; i < len-1; ++i) {
|
| - map = FunctionType._lookupNonTerminal(map, arr[i]);
|
| - }
|
| - let result = map.get(arr[len-1]);
|
| - if (result !== void 0) return result;
|
| - map.set(arr[len-1], result = create());
|
| - return result;
|
| - }
|
| + '''(() => {
|
| + let len = $arr.length;
|
| + $map = $_lookupNonTerminal($map, len);
|
| + for (var i = 0; i < len-1; ++i) {
|
| + $map = $_lookupNonTerminal($map, $arr[i]);
|
| + }
|
| + let result = $map.get($arr[len-1]);
|
| + if (result !== void 0) return result;
|
| + $map.set($arr[len-1], result = $create());
|
| + return result;
|
| +})()''');
|
|
|
| - // Map dynamic to bottom. If meta-data is present,
|
| - // we slice off the remaining meta-data and make
|
| - // it the second element of a packet for processing
|
| - // later on in the constructor.
|
| - static _normalizeParameter(a) {
|
| - if (a instanceof Array) {
|
| - let result = [];
|
| - result.push((a[0] == $dynamic) ? $bottom : a[0]);
|
| - result.push(a.slice(1));
|
| - return result;
|
| - }
|
| - return (a == $dynamic) ? $bottom : a;
|
| - }
|
| +// Map dynamic to bottom. If meta-data is present,
|
| +// we slice off the remaining meta-data and make
|
| +// it the second element of a packet for processing
|
| +// later on in the constructor.
|
| +_normalizeParameter(a) => JS(
|
| + '',
|
| + '''(() => {
|
| + if ($a instanceof Array) {
|
| + let result = [];
|
| + result.push(($a[0] == $dynamic) ? $bottom : $a[0]);
|
| + result.push($a.slice(1));
|
| + return result;
|
| + }
|
| + return ($a == $dynamic) ? $bottom : $a;
|
| +})()''');
|
|
|
| - static _canonicalizeArray(definite, array, map) {
|
| - let arr = (definite)
|
| - ? array
|
| - : array.map(FunctionType._normalizeParameter);
|
| - return FunctionType._memoizeArray(map, arr, () => arr);
|
| - }
|
| +_canonicalizeArray(definite, array, map) => JS(
|
| + '',
|
| + '''(() => {
|
| + let arr = ($definite)
|
| + ? $array
|
| + : $array.map($_normalizeParameter);
|
| + return $_memoizeArray($map, arr, () => arr);
|
| +})()''');
|
|
|
| - // TODO(leafp): This only canonicalizes of the names are
|
| - // emitted in a consistent order.
|
| - static _canonicalizeNamed(definite, named, map) {
|
| - let key = [];
|
| - let names = $getOwnPropertyNames(named);
|
| - let r = {};
|
| - for (var i = 0; i < names.length; ++i) {
|
| - let name = names[i];
|
| - let type = named[name];
|
| - if (!definite) r[name] = type = FunctionType._normalizeParameter(type);
|
| - key.push(name);
|
| - key.push(type);
|
| - }
|
| - if (!definite) named = r;
|
| - return FunctionType._memoizeArray(map, key, () => named);
|
| - }
|
| +// TODO(leafp): This only canonicalizes of the names are
|
| +// emitted in a consistent order.
|
| +_canonicalizeNamed(definite, named, map) => JS(
|
| + '',
|
| + '''(() => {
|
| + let key = [];
|
| + let names = $getOwnPropertyNames($named);
|
| + let r = {};
|
| + for (var i = 0; i < names.length; ++i) {
|
| + let name = names[i];
|
| + let type = $named[name];
|
| + if (!definite) r[name] = type = $_normalizeParameter(type);
|
| + key.push(name);
|
| + key.push(type);
|
| + }
|
| + if (!$definite) $named = r;
|
| + return $_memoizeArray($map, key, () => $named);
|
| +})()''');
|
|
|
| - static _lookupNonTerminal(map, key) {
|
| - let result = map.get(key);
|
| - if (result !== void 0) return result;
|
| - map.set(key, result = new Map());
|
| - return result;
|
| - }
|
| +_lookupNonTerminal(map, key) => JS(
|
| + '',
|
| + '''(() => {
|
| + let result = $map.get($key);
|
| + if (result !== void 0) return result;
|
| + $map.set($key, result = new Map());
|
| + return result;
|
| +})()''');
|
| +
|
| +// TODO(leafp): This handles some low hanging fruit, but
|
| +// really we should make all of this faster, and also
|
| +// handle more cases here.
|
| +_createSmall(count, definite, returnType, required) => JS(
|
| + '',
|
| + '''(() => {
|
| + let map = $_fnTypeSmallMap[$count];
|
| + let args = ($definite) ? $required
|
| + : $required.map($_normalizeParameter);
|
| + for (var i = 0; i < $count; ++i) {
|
| + map = $_lookupNonTerminal(map, args[i]);
|
| + }
|
| + let result = map.get($returnType);
|
| + if (result !== void 0) return result;
|
| + result = new $FunctionType($returnType, args, [], {});
|
| + map.set($returnType, result);
|
| + return result;
|
| +})()''');
|
|
|
| - // TODO(leafp): This handles some low hanging fruit, but
|
| - // really we should make all of this faster, and also
|
| - // handle more cases here.
|
| - static _createSmall(count, definite, returnType, required) {
|
| - let map = $_fnTypeSmallMap[count];
|
| - let args = (definite) ? required
|
| - : required.map(FunctionType._normalizeParameter);
|
| - for (var i = 0; i < count; ++i) {
|
| - map = FunctionType._lookupNonTerminal(map, args[i]);
|
| - }
|
| - let result = map.get(returnType);
|
| - if (result !== void 0) return result;
|
| - result = new FunctionType(returnType, args, [], {});
|
| - map.set(returnType, result);
|
| - return result;
|
| +class FunctionType extends AbstractFunctionType {
|
| + final returnType;
|
| + dynamic args;
|
| + dynamic optionals;
|
| + final named;
|
| + dynamic metadata;
|
| +
|
| + /**
|
| + * Construct a function type. There are two arrow constructors,
|
| + * distinguished by the "definite" flag.
|
| + *
|
| + * The fuzzy arrow (definite is false) treats any arguments
|
| + * of type dynamic as having type bottom, and will always be
|
| + * called with a dynamic invoke.
|
| + *
|
| + * The definite arrow (definite is true) leaves arguments unchanged.
|
| + *
|
| + * We eagerly normalize the argument types to avoid having to deal with
|
| + * this logic in multiple places.
|
| + *
|
| + * This code does best effort canonicalization. It does not guarantee
|
| + * that all instances will share.
|
| + *
|
| + */
|
| + static create(definite, returnType, args, extra) {
|
| + // Note that if extra is ever passed as an empty array
|
| + // or an empty map, we can end up with semantically
|
| + // identical function types that don't canonicalize
|
| + // to the same object since we won't fall into this
|
| + // fast path.
|
| + if (JS('bool', '# === void 0', extra) && JS('', '#.length < 3', args)) {
|
| + return _createSmall(JS('', '#.length', args), definite, returnType, args);
|
| + }
|
| + args = _canonicalizeArray(definite, args, _fnTypeArrayArgMap);
|
| + var keys;
|
| + var create;
|
| + if (JS('bool', '# === void 0', extra)) {
|
| + keys = [returnType, args];
|
| + create = () => new FunctionType(returnType, args, [], JS('', '{}'));
|
| + } else if (JS('bool', '# instanceof Array', extra)) {
|
| + var optionals = _canonicalizeArray(definite, extra, _fnTypeArrayArgMap);
|
| + keys = [returnType, args, optionals];
|
| + create =
|
| + () => new FunctionType(returnType, args, optionals, JS('', '{}'));
|
| + } else {
|
| + var named = _canonicalizeNamed(definite, extra, _fnTypeNamedArgMap);
|
| + keys = [returnType, args, named];
|
| + create = () => new FunctionType(returnType, args, [], named);
|
| }
|
| - /**
|
| - * Construct a function type. There are two arrow constructors,
|
| - * distinguished by the "definite" flag.
|
| - *
|
| - * The fuzzy arrow (definite is false) treats any arguments
|
| - * of type dynamic as having type bottom, and will always be
|
| - * called with a dynamic invoke.
|
| - *
|
| - * The definite arrow (definite is true) leaves arguments unchanged.
|
| - *
|
| - * We eagerly normalize the argument types to avoid having to deal with
|
| - * this logic in multiple places.
|
| - *
|
| - * This code does best effort canonicalization. It does not guarantee
|
| - * that all instances will share.
|
| - *
|
| - */
|
| - static create(definite, returnType, args, extra) {
|
| - // Note that if extra is ever passed as an empty array
|
| - // or an empty map, we can end up with semantically
|
| - // identical function types that don't canonicalize
|
| - // to the same object since we won't fall into this
|
| - // fast path.
|
| - if (extra === void 0 && args.length < 3) {
|
| - return FunctionType._createSmall(
|
| - args.length, definite, returnType, args);
|
| - }
|
| - args = FunctionType._canonicalizeArray(
|
| - definite, args, $_fnTypeArrayArgMap);
|
| - let keys;
|
| - let create;
|
| - if (extra === void 0) {
|
| - keys = [returnType, args];
|
| - create = () => new FunctionType(returnType, args, [], {});
|
| - } else if (extra instanceof Array) {
|
| - let optionals =
|
| - FunctionType._canonicalizeArray(definite, extra, $_fnTypeArrayArgMap);
|
| - keys = [returnType, args, optionals];
|
| - create =
|
| - () => new FunctionType(returnType, args, optionals, {});
|
| + return _memoizeArray(_fnTypeTypeMap, keys, create);
|
| + }
|
| +
|
| + _process(array, metadata) {
|
| + var result = [];
|
| + for (var i = 0; JS('bool', '# < #.length', i, array); ++i) {
|
| + var arg = JS('', '#[#]', array, i);
|
| + if (JS('bool', '# instanceof Array', arg)) {
|
| + metadata.add(JS('', '#.slice(1)', arg));
|
| + result.add(JS('', '#[0]', arg));
|
| } else {
|
| - let named =
|
| - FunctionType._canonicalizeNamed(definite, extra, $_fnTypeNamedArgMap);
|
| - keys = [returnType, args, named];
|
| - create = () => new FunctionType(returnType, args, [], named);
|
| + JS('', '#.push([])', metadata);
|
| + JS('', '#.push(#)', result, arg);
|
| }
|
| - return FunctionType._memoizeArray($_fnTypeTypeMap, keys, create);
|
| }
|
| + return result;
|
| + }
|
|
|
| - constructor(returnType, args, optionals, named) {
|
| - super();
|
| - this.returnType = returnType;
|
| - this.args = args;
|
| - this.optionals = optionals;
|
| - this.named = named;
|
| -
|
| - // TODO(vsm): This is just parameter metadata for now.
|
| - this.metadata = [];
|
| - function process(array, metadata) {
|
| - var result = [];
|
| - for (var i = 0; i < array.length; ++i) {
|
| - var arg = array[i];
|
| - if (arg instanceof Array) {
|
| - metadata.push(arg.slice(1));
|
| - result.push(arg[0]);
|
| - } else {
|
| - metadata.push([]);
|
| - result.push(arg);
|
| - }
|
| - }
|
| - return result;
|
| - }
|
| - this.args = process(this.args, this.metadata);
|
| - this.optionals = process(this.optionals, this.metadata);
|
| - // TODO(vsm): Add named arguments.
|
| - }
|
| + FunctionType(this.returnType, this.args, this.optionals, this.named) {
|
| + // TODO(vsm): This is just parameter metadata for now.
|
| + metadata = [];
|
| + this.args = _process(this.args, metadata);
|
| + this.optionals = _process(this.optionals, metadata);
|
| + // TODO(vsm): Add named arguments.
|
| }
|
| -''');
|
| +}
|
|
|
| -final Typedef = JS(
|
| - '',
|
| - '''
|
| - class Typedef extends $AbstractFunctionType {
|
| - constructor(name, closure) {
|
| - super();
|
| - this._name = name;
|
| - this._closure = closure;
|
| - this._functionType = null;
|
| - }
|
| +// TODO(jacobr): we can't define this typedef due to execution order issues.
|
| +//typedef AbstractFunctionType FunctionTypeClosure();
|
|
|
| - get name() {
|
| - return this._name;
|
| - }
|
| +class Typedef extends AbstractFunctionType {
|
| + dynamic _name;
|
| + dynamic /*FunctionTypeClosure*/ _closure;
|
| + AbstractFunctionType _functionType;
|
|
|
| - get functionType() {
|
| - if (!this._functionType) {
|
| - this._functionType = this._closure();
|
| - }
|
| - return this._functionType;
|
| - }
|
| + Typedef(this._name, this._closure) {}
|
|
|
| - get returnType() {
|
| - return this.functionType.returnType;
|
| - }
|
| + get name {
|
| + return _name;
|
| + }
|
|
|
| - get args() {
|
| - return this.functionType.args;
|
| + AbstractFunctionType get functionType {
|
| + if (_functionType == null) {
|
| + _functionType = JS('', '#()', _closure);
|
| }
|
| + return _functionType;
|
| + }
|
|
|
| - get optionals() {
|
| - return this.functionType.optionals;
|
| - }
|
| + get returnType {
|
| + return functionType.returnType;
|
| + }
|
|
|
| - get named() {
|
| - return this.functionType.named;
|
| - }
|
| + List get args {
|
| + return functionType.args;
|
| + }
|
|
|
| - get metadata() {
|
| - return this.functionType.metadata;
|
| - }
|
| + List get optionals {
|
| + return functionType.optionals;
|
| + }
|
| +
|
| + get named {
|
| + return functionType.named;
|
| }
|
| -''');
|
| +
|
| + List get metadata {
|
| + return functionType.metadata;
|
| + }
|
| +}
|
| +
|
| +typedef(name, /*FunctionTypeClosure*/ closure) {
|
| + return new Typedef(name, closure);
|
| +}
|
|
|
| final _typeFormalCount = JS('', 'Symbol("_typeFormalCount")');
|
|
|
| @@ -500,9 +513,7 @@ functionType(returnType, args, extra) =>
|
| definiteFunctionType(returnType, args, extra) =>
|
| _functionType(true, returnType, args, extra);
|
|
|
| -typedef(name, closure) => JS('', 'new #(#, #)', Typedef, name, closure);
|
| -
|
| -typeName(type) => JS(
|
| +String typeName(type) => JS(
|
| '',
|
| '''(() => {
|
| if ($type === void 0) return "undefined type";
|
| @@ -554,7 +565,7 @@ typeName(type) => JS(
|
| /// for a class type.
|
| getImplicitFunctionType(type) {
|
| if (isFunctionType(type)) return type;
|
| - return getMethodTypeFromType(type, 'call');
|
| + return getMethodType(type, 'call');
|
| }
|
|
|
| bool isFunctionType(type) => JS('bool', '# instanceof # || # === #', type,
|
|
|