Chromium Code Reviews| Index: pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart |
| diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart |
| index d8014d99ed6feb7339dd88c153a6a3d89553b003..a289167783da4d99c977b497d9590c95b2c076d8 100644 |
| --- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart |
| +++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart |
| @@ -10,17 +10,23 @@ class InvocationImpl extends Invocation { |
| final Symbol memberName; |
| final List positionalArguments; |
| final Map<Symbol, dynamic> namedArguments; |
| + final List<Type> typeArguments; |
| final bool isMethod; |
| final bool isGetter; |
| final bool isSetter; |
| InvocationImpl(memberName, this.positionalArguments, |
| {namedArguments, |
| + List typeArguments, |
| this.isMethod: false, |
| this.isGetter: false, |
| this.isSetter: false}) |
| - : memberName = _dartSymbol(memberName), |
| - namedArguments = _namedArgsToSymbols(namedArguments); |
| + : memberName = |
| + isSetter ? _setterSymbol(memberName) : _dartSymbol(memberName), |
| + namedArguments = _namedArgsToSymbols(namedArguments), |
| + typeArguments = typeArguments == null |
| + ? const [] |
| + : typeArguments.map(wrapType).toList(); |
| static Map<Symbol, dynamic> _namedArgsToSymbols(namedArgs) { |
| if (namedArgs == null) return {}; |
| @@ -174,9 +180,7 @@ dput(obj, field, value) { |
| /// Check that a function of a given type can be applied to |
| /// actuals. |
| -_checkApply(type, actuals) => JS( |
| - '', |
| - '''(() => { |
| +_checkApply(type, actuals) => JS('', '''(() => { |
| // TODO(vsm): Remove when we no longer need mirrors metadata. |
| // An array is used to encode annotations attached to the type. |
| if ($type instanceof Array) { |
| @@ -216,17 +220,13 @@ _checkApply(type, actuals) => JS( |
| return true; |
| })()'''); |
| -_toSymbolName(symbol) => JS( |
| - '', |
| - '''(() => { |
| +_toSymbolName(symbol) => JS('', '''(() => { |
| let str = $symbol.toString(); |
| // Strip leading 'Symbol(' and trailing ')' |
| return str.substring(7, str.length-1); |
| })()'''); |
| -_toDisplayName(name) => JS( |
| - '', |
| - '''(() => { |
| +_toDisplayName(name) => JS('', '''(() => { |
| // Names starting with _ are escaped names used to disambiguate Dart and |
| // JS names. |
| if ($name[0] === '_') { |
| @@ -253,6 +253,13 @@ Symbol _dartSymbol(name) { |
| : JS('Symbol', '#(#.new(#))', const_, Symbol, _toDisplayName(name)); |
| } |
| +Symbol _setterSymbol(name) { |
| + return (JS('bool', 'typeof # === "symbol"', name)) |
| + ? JS('Symbol', '#(new #.new(# + "=", #))', const_, |
| + _internal.PrivateSymbol, _toSymbolName(name), name) |
| + : JS('Symbol', '#(#.new(# + "="))', const_, Symbol, _toDisplayName(name)); |
| +} |
| + |
| /// Extracts the named argument array from a list of arguments, and returns it. |
| // TODO(jmesserly): we need to handle named arguments better. |
| extractNamedArgs(args) { |
| @@ -266,17 +273,19 @@ extractNamedArgs(args) { |
| return null; |
| } |
| -_checkAndCall(f, ftype, obj, typeArgs, args, name) => JS( |
| - '', |
| - '''(() => { |
| +_checkAndCall(f, ftype, obj, typeArgs, args, name) => JS('', '''(() => { |
| $_trackCall($obj); |
| let originalTarget = obj === void 0 ? f : obj; |
| function callNSM() { |
| + let opts = { }; |
| return $noSuchMethod(originalTarget, new $InvocationImpl.new( |
| - $name, $args, |
| - {namedArguments: $extractNamedArgs($args), isMethod: true})); |
| + $name, $args, opts, { |
|
vsm
2017/07/20 15:07:12
What is opts here? I only see two pos args on the
Jennifer Messerly
2017/07/20 19:14:57
oh gosh! I didn't upload after fixing this. oops.
|
| + namedArguments: $extractNamedArgs($args), |
| + typeArguments: $typeArgs, |
| + isMethod: true |
| + })); |
| } |
| if (!($f instanceof Function)) { |
| // We're not a function (and hence not a method either) |
| @@ -349,9 +358,7 @@ dgcall(f, typeArgs, @rest args) => _checkAndCall( |
| /// Helper for REPL dynamic invocation variants that make a best effort to |
| /// enable accessing private members across library boundaries. |
| -_dhelperRepl(object, field, callback) => JS( |
| - '', |
| - '''(() => { |
| +_dhelperRepl(object, field, callback) => JS('', '''(() => { |
| let rawField = $field; |
| if (typeof(field) == 'symbol') { |
| // test if the specified field exists in which case it is safe to use it. |
| @@ -431,9 +438,7 @@ dsetindex(obj, index, value) => |
| /// TODO(leafp): This duplicates code in types.dart. |
| /// I haven't found a way to factor it out that makes the |
| /// code generator happy though. |
| -_ignoreMemo(f) => JS( |
| - '', |
| - '''(() => { |
| +_ignoreMemo(f) => JS('', '''(() => { |
| let memo = new Map(); |
| return (t1, t2) => { |
| let map = memo.get(t1); |
| @@ -450,9 +455,7 @@ _ignoreMemo(f) => JS( |
| }; |
| })()'''); |
| -final _ignoreTypeFailure = JS( |
| - '', |
| - '''(() => { |
| +final _ignoreTypeFailure = JS('', '''(() => { |
| return $_ignoreMemo((actual, type) => { |
| // TODO(vsm): Remove this hack ... |
| // This is primarily due to the lack of generic methods, |
| @@ -486,9 +489,7 @@ final _ignoreTypeFailure = JS( |
| /// and strong mode |
| /// Returns null if [obj] is not an instance of [type] in strong mode |
| /// but might be in spec mode |
| -bool strongInstanceOf(obj, type, ignoreFromWhiteList) => JS( |
| - '', |
| - '''(() => { |
| +bool strongInstanceOf(obj, type, ignoreFromWhiteList) => JS('', '''(() => { |
| let actual = $getReifiedType($obj); |
| let result = $isSubtype(actual, $type); |
| if (result || (actual == $int && $isSubtype($double, $type))) return true; |
| @@ -508,18 +509,14 @@ bool strongInstanceOf(obj, type, ignoreFromWhiteList) => JS( |
| /// Returns true if [obj] is null or an instance of [type] |
| /// Returns false if [obj] is non-null and not an instance of [type] |
| /// in strong mode |
| -instanceOfOrNull(obj, type) => JS( |
| - '', |
| - '''(() => { |
| +instanceOfOrNull(obj, type) => JS('', '''(() => { |
| // If strongInstanceOf returns null, convert to false here. |
| if (($obj == null) || $strongInstanceOf($obj, $type, true)) return true; |
| return false; |
| })()'''); |
| @JSExportName('is') |
| -bool instanceOf(obj, type) => JS( |
| - '', |
| - '''(() => { |
| +bool instanceOf(obj, type) => JS('', '''(() => { |
| if ($obj == null) { |
| return $type == $Null || $_isTop($type); |
| } |
| @@ -612,9 +609,7 @@ asInt(obj) { |
| /// Adds type type test predicates to a constructor for a non-parameterized |
| /// type. Non-parameterized types can use `instanceof` for subclass checks and |
| /// fall through to a helper for subtype tests. |
| -addSimpleTypeTests(ctor) => JS( |
| - '', |
| - '''(() => { |
| +addSimpleTypeTests(ctor) => JS('', '''(() => { |
| $ctor.is = function is_C(object) { |
| // This is incorrect for classes [Null] and [Object], so we do not use |
| // [addSimpleTypeTests] for these classes. |
| @@ -634,9 +629,7 @@ addSimpleTypeTests(ctor) => JS( |
| /// Adds type type test predicates to a constructor. Used for parmeterized |
| /// types. We avoid `instanceof` for, e.g. `x is ListQueue` since there is |
| /// no common class for `ListQueue<int>` and `ListQueue<String>`. |
| -addTypeTests(ctor) => JS( |
| - '', |
| - '''(() => { |
| +addTypeTests(ctor) => JS('', '''(() => { |
| $ctor.as = function as_G(object) { |
| return dart.as(object, this); |
| }; |
| @@ -650,9 +643,7 @@ addTypeTests(ctor) => JS( |
| // TODO(vsm): Consider optimizing this. We may be able to statically |
| // determine which == operation to invoke given the static types. |
| -equals(x, y) => JS( |
| - '', |
| - '''(() => { |
| +equals(x, y) => JS('', '''(() => { |
| if ($x == null || $y == null) return $x == $y; |
| let eq = $x[dartx['==']] || $x['==']; |
| return eq ? eq.call($x, $y) : $x === $y; |
| @@ -680,9 +671,7 @@ notNull(x) { |
| // TODO(jmesserly): this could be faster |
| // TODO(jmesserly): we can use default values `= dynamic` once #417 is fixed. |
| // TODO(jmesserly): move this to classes for consistency with list literals? |
| -map(values, [K, V]) => JS( |
| - '', |
| - '''(() => { |
| +map(values, [K, V]) => JS('', '''(() => { |
| if ($K == null) $K = $dynamic; |
| if ($V == null) $V = $dynamic; |
| let map = ${getGenericClass(LinkedHashMap)}($K, $V).new(); |
| @@ -795,9 +784,7 @@ final _value = JS('', 'Symbol("_value")'); |
| /// |
| /// { 1: { 2: { 'hi ': { 'there ': 'world' } } } } |
| /// |
| -multiKeyPutIfAbsent(map, keys, valueFn) => JS( |
| - '', |
| - '''(() => { |
| +multiKeyPutIfAbsent(map, keys, valueFn) => JS('', '''(() => { |
| for (let k of $keys) { |
| let value = $map.get(k); |
| if (!value) { |
| @@ -829,9 +816,7 @@ final constants = JS('', 'new Map()'); |
| /// - nested values of the object are themselves already canonicalized. |
| /// |
| @JSExportName('const') |
| -const_(obj) => JS( |
| - '', |
| - '''(() => { |
| +const_(obj) => JS('', '''(() => { |
| // TODO(leafp): This table gets quite large in apps. |
| // Keeping the paths is probably expensive. It would probably |
| // be more space efficient to just use a direct hash table with |
| @@ -878,12 +863,8 @@ const_(obj) => JS( |
| /// type and contains the canonical version of the list. |
| final constantLists = JS('', 'new Map()'); |
| -/// |
| /// Canonicalize a constant list |
| -/// |
| -constList(elements, elementType) => JS( |
| - '', |
| - '''(() => { |
| +constList(elements, elementType) => JS('', '''(() => { |
| function lookupNonTerminal(map, key) { |
| let result = map.get(key); |
| if (result !== void 0) return result; |
| @@ -897,7 +878,8 @@ constList(elements, elementType) => JS( |
| } |
| let value = map.get($elementType); |
| if (value) return value; |
| - value = $list($elements, $elementType); |
| + |
| + value = $setType($elements, ${getGenericClass(JSArray)}($elementType)); |
| map.set($elementType, value); |
| return value; |
| })()'''); |
| @@ -915,9 +897,11 @@ hashCode(obj) { |
| // From JSBool.hashCode, see comment there. |
| return JS('', '# ? (2 * 3 * 23 * 3761) : (269 * 811)', obj); |
| case "function": |
| - var hashFn = JS('', '#[#]', obj, _tearoffHashcode); |
| - if (hashFn != null) return JS('int', '#()', hashFn); |
| - return Primitives.objectHashCode(obj); |
| + if (JS('bool', '# instanceof Function', obj)) { |
| + var hashFn = JS('', '#[#]', obj, _tearoffHashcode); |
| + if (hashFn != null) return JS('int', '#()', hashFn); |
| + return Primitives.objectHashCode(obj); |
| + } |
| } |
| var extension = getExtensionType(obj); |
| @@ -935,7 +919,7 @@ String _toString(obj) { |
| if (extension != null) { |
| return JS('String', '#[dartx.toString]()', obj); |
| } |
| - if (JS('bool', 'typeof # == "function"', obj)) { |
| + if (JS('bool', 'typeof # == "function" && # instanceof Function', obj, obj)) { |
| // If the function is a Type object, we should just display the type name. |
| // Regular Dart code should typically get wrapped type objects instead of |
| // raw type (aka JS constructor) objects however raw type objects can be |
| @@ -954,7 +938,8 @@ String _toString(obj) { |
| // TODO(jmesserly): is the argument type verified statically? |
| noSuchMethod(obj, Invocation invocation) { |
| - if (obj == null || JS('bool', 'typeof # == "function"', obj)) { |
| + if (obj == null || |
| + JS('bool', 'typeof # == "function" && # instanceof Function', obj, obj)) { |
| throwNoSuchMethodError(obj, invocation.memberName, |
| invocation.positionalArguments, invocation.namedArguments); |
| } |
| @@ -980,7 +965,7 @@ runtimeType(obj) { |
| // If extension doesn't override runtimeType, return the extension type. |
| return result ?? wrapType(extension); |
| } |
| - if (JS('bool', 'typeof # == "function"', obj)) { |
| + if (JS('bool', 'typeof # == "function" && # instanceof Function', obj, obj)) { |
| return wrapType(getReifiedType(obj)); |
| } |
| return JS('', '#.runtimeType', obj); |
| @@ -989,9 +974,7 @@ runtimeType(obj) { |
| /// Implements Dart's interpolated strings as ES2015 tagged template literals. |
| /// |
| /// For example: dart.str`hello ${name}` |
| -String str(strings, @rest values) => JS( |
| - '', |
| - '''(() => { |
| +String str(strings, @rest values) => JS('', '''(() => { |
| let s = $strings[0]; |
| for (let i = 0, len = $values.length; i < len; ) { |
| s += $notNull($_toString($values[i])) + $strings[++i]; |
| @@ -999,9 +982,7 @@ String str(strings, @rest values) => JS( |
| return s; |
| })()'''); |
| -final JsIterator = JS( |
| - '', |
| - ''' |
| +final JsIterator = JS('', ''' |
| class JsIterator { |
| constructor(dartIterator) { |
| this.dartIterator = dartIterator; |