| 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..880d0db1adcd1316285ab24d7a8407404a9c9d44 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,18 @@ 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() {
|
| return $noSuchMethod(originalTarget, new $InvocationImpl.new(
|
| - $name, $args,
|
| - {namedArguments: $extractNamedArgs($args), isMethod: true}));
|
| + $name, $args, {
|
| + namedArguments: $extractNamedArgs($args),
|
| + typeArguments: $typeArgs,
|
| + isMethod: true
|
| + }));
|
| }
|
| if (!($f instanceof Function)) {
|
| // We're not a function (and hence not a method either)
|
| @@ -349,9 +357,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 +437,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 +454,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 +488,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 +508,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 +608,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 +628,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 +642,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 +670,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 +783,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 +815,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 +862,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 +877,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 +896,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 +918,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 +937,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 +964,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 +973,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 +981,7 @@ String str(strings, @rest values) => JS(
|
| return s;
|
| })()''');
|
|
|
| -final JsIterator = JS(
|
| - '',
|
| - '''
|
| +final JsIterator = JS('', '''
|
| class JsIterator {
|
| constructor(dartIterator) {
|
| this.dartIterator = dartIterator;
|
|
|