[dartdevc] fix #36293, call nSM on callable objects if the lookup fails
Given `obj.foo(1, 2, 3)`, if `obj.foo` succeeds but `call()` on the
resulting object fails, DDC should call `noSuchMethod()` on the result
of `obj.foo`, not on `obj`. This CL also adds a few more test cases that
DDC was failing on.
Change-Id: I76c3cc73e4cc81791f961c6b2a55cbfea7a5240b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97701
Reviewed-by: Mark Zhou <markzipan@google.com>
Commit-Queue: Jenny Messerly <jmesserly@google.com>
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 b3865c1..6f67aa9 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
@@ -254,6 +254,10 @@
// We're not a function (and hence not a method either)
// Grab the `call` method if it's not a function.
if ($f != null) {
+ // Getting the member succeeded, so update the originalTarget.
+ // (we're now trying `call()` on `f`, so we want to call its nSM rather
+ // than the original target's nSM).
+ originalTarget = f;
$f = ${bindCall(f, _canonicalMember(f, 'call'))};
$ftype = null;
}
diff --git a/tests/language_2/regress_36084_test.dart b/tests/language_2/regress_36084_test.dart
index 1d56eb5..d16706e 100644
--- a/tests/language_2/regress_36084_test.dart
+++ b/tests/language_2/regress_36084_test.dart
@@ -15,11 +15,27 @@
}
}
+class A2 {
+ // Same as A1 but without a call method.
+ int noSuchMethod(Invocation invocation) {
+ return 42;
+ }
+}
+
class B {
dynamic foo;
dynamic get bar => foo;
}
+class B1 {
+ dynamic foo;
+ dynamic get bar => foo;
+
+ int noSuchMethod(Invocation invocation) {
+ Expect.fail('B1.noSuchMethod should not be called.');
+ }
+}
+
main() {
B b = new B();
b.foo = new A();
@@ -28,4 +44,19 @@
b.foo = new A1();
Expect.equals(42, b.foo(1, 2, 3));
Expect.equals(42, b.bar(1, 2, 3));
+ b.foo = new A2();
+ Expect.equals(42, b.foo(1, 2, 3));
+ Expect.equals(42, b.bar(1, 2, 3));
+
+ // Same test but with B1, which has its own `noSuchMethod()` handler.
+ B1 b1 = new B1();
+ b1.foo = new A();
+ Expect.throwsNoSuchMethodError(() => b1.foo(1, 2, 3));
+ Expect.throwsNoSuchMethodError(() => b1.bar(1, 2, 3));
+ b1.foo = new A1();
+ Expect.equals(42, b1.foo(1, 2, 3));
+ Expect.equals(42, b1.bar(1, 2, 3));
+ b1.foo = new A2();
+ Expect.equals(42, b1.foo(1, 2, 3));
+ Expect.equals(42, b1.bar(1, 2, 3));
}