Chromium Code Reviews| 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 4d402db12c117e7ed6b633ca64e7a420543b7322..78baebf8dc69b6369ebd8352a63a56dfc805cb5e 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 { |
|
Jacob
2017/01/21 01:11:30
Switched these to be first class Dart types as DDC
|
| + 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, |