 Chromium Code Reviews
 Chromium Code Reviews Issue 2623053004:
  Fix noSuchMethod handling of methods that are also extension methods. Fix noSuchMethod handling of …  (Closed)
    
  
    Issue 2623053004:
  Fix noSuchMethod handling of methods that are also extension methods. Fix noSuchMethod handling of …  (Closed) 
  | 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 d936333eb597ac7899138f4fad420911976adc1e..d7f787a597dbf80b5270e45bab5b23bab8e77c70 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 | 
| @@ -14,7 +14,7 @@ class InvocationImpl extends Invocation { | 
| final bool isGetter; | 
| final bool isSetter; | 
| - InvocationImpl(String memberName, this.positionalArguments, | 
| + InvocationImpl(memberName, this.positionalArguments, | 
| {namedArguments, | 
| this.isMethod: false, | 
| this.isGetter: false, | 
| @@ -29,12 +29,18 @@ class InvocationImpl extends Invocation { | 
| } | 
| } | 
| +// Warning: dload, dput, and dsend assume they are never called on methods | 
| +// implemented by the Object base class as those methods can always be | 
| +// statically resolved. | 
| dload(obj, field) { | 
| var f = _canonicalMember(obj, field); | 
| + | 
| _trackCall(obj); | 
| if (f != null) { | 
| - if (hasMethod(obj, f)) return bind(obj, f, JS('', 'void 0')); | 
| - return JS('', '#[#]', obj, f); | 
| + var type = getType(obj); | 
| + | 
| + if (hasField(type, f) || hasGetter(type, f)) return JS('', '#[#]', obj, f); | 
| + if (hasMethod(type, f)) return bind(obj, f, JS('', 'void 0')); | 
| } | 
| return noSuchMethod( | 
| obj, new InvocationImpl(field, JS('', '[]'), isGetter: true)); | 
| @@ -44,7 +50,25 @@ dput(obj, field, value) { | 
| var f = _canonicalMember(obj, field); | 
| _trackCall(obj); | 
| if (f != null) { | 
| - return JS('', '#[#] = #', obj, f, value); | 
| + var type = getType(obj); | 
| + var setter = getSetterType(type, f); | 
| 
Jennifer Messerly
2017/01/24 03:51:03
Possibly calling this setterType would be a bit mo
 
Jacob
2017/01/24 19:12:32
agreed. cleaned up.
 | 
| + if (JS('bool', '# != void 0', setter)) { | 
| + // TODO(jacobr): throw a type error instead of a NoSuchMethodError if | 
| + // the type of the setter doesn't match. | 
| + if (instanceOfOrNull(value, JS('', '#.args[0]', setter))) { | 
| + return JS('', '#[#] = #', obj, f, value); | 
| + } | 
| + } else { | 
| + var field = getFieldType(type, f); | 
| + // TODO(jacobr): propagate metadata tracking which fields are private. | 
| 
Jennifer Messerly
2017/01/24 03:51:03
What does this mean? It shouldn't be possible to g
 
Jacob
2017/01/24 19:12:32
Done.
It means I got distracted writing the commen
 | 
| + if (JS('bool', '# != void 0', field)) { | 
| + // TODO(jacobr): throw a type error instead of a NoSuchMethodError if | 
| + // the type of the field doesn't match. | 
| + if (instanceOfOrNull(value, field)) { | 
| + return JS('', '#[#] = #', obj, f, value); | 
| + } | 
| + } | 
| + } | 
| } | 
| return noSuchMethod( | 
| obj, new InvocationImpl(field, JS('', '[#]', value), isSetter: true)); | 
| @@ -89,8 +113,42 @@ _checkApply(type, actuals) => JS( | 
| return true; | 
| })()'''); | 
| -Symbol _dartSymbol(name) => | 
| - JS('', '#(#.new(#.toString()))', const_, Symbol, name); | 
| +_toSymbolName(symbol) => JS( | 
| + '', | 
| + '''(() => { | 
| + let str = $symbol.toString(); | 
| + // Strip leading 'Symbol(' and trailing ')' | 
| + return str.substring(7, str.length-1); | 
| + })()'''); | 
| + | 
| +_toDisplayName(name) => JS( | 
| + '', | 
| + '''(() => { | 
| + // Names starting with _ are escaped names used to disambiguate Dart and | 
| + // JS names. | 
| + if ($name[0] === '_') { | 
| + // Inverse of | 
| + switch($name) { | 
| + case '_get': | 
| + return '[]'; | 
| + case '_set': | 
| + return '[]='; | 
| + case '_negate': | 
| + return 'unary-'; | 
| + case '_constructor': | 
| + case '_prototype': | 
| + return $name.substring(1); | 
| + } | 
| + } | 
| + return $name; | 
| + })()'''); | 
| + | 
| +Symbol _dartSymbol(name) { | 
| + return (JS('bool', 'typeof # === "symbol"', name)) | 
| + ? JS('', '#(new #.es6(#, #))', const_, _internal.Symbol, | 
| + _toSymbolName(name), name) | 
| + : JS('', '#(#.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. | 
| @@ -121,7 +179,7 @@ _checkAndCall(f, ftype, obj, typeArgs, args, name) => JS( | 
| // We're not a function (and hence not a method either) | 
| // Grab the `call` method if it's not a function. | 
| if ($f != null) { | 
| - $ftype = $getMethodType($f, 'call'); | 
| + $ftype = $getMethodType($getType($f), 'call'); | 
| $f = $f.call; | 
| } | 
| if (!($f instanceof Function)) { | 
| @@ -303,7 +361,9 @@ _callMethod(obj, name, typeArgs, args, displayName) { | 
| obj, new InvocationImpl(displayName, args, isMethod: true)); | 
| } | 
| var f = obj != null ? JS('', '#[#]', obj, symbol) : null; | 
| - var ftype = getMethodType(obj, symbol); | 
| + var type = getType(obj); | 
| + var ftype = getMethodType(type, symbol); | 
| + // No such method if dart object and ftype is missing. | 
| return _checkAndCall(f, ftype, obj, typeArgs, args, displayName); | 
| } |