53219f95e6
This change introduces the dynamic_call test in pkg/dynamic_modules. TEST=pkg/dynamic_modules/test/data/dynamic_call Change-Id: I2425fd7925b2d7e66f919ceaaa102f4950e3a712 Bug: b/448095881 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/498301 Commit-Queue: Sigmund Cherem <sigmund@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
137 lines
3.6 KiB
Dart
137 lines
3.6 KiB
Dart
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
import 'package:expect/expect.dart';
|
|
import '../shared/lib.dart';
|
|
|
|
@pragma('dyn-module:entry-point')
|
|
Future<bool> dynamicModuleEntrypoint() async {
|
|
dynamic a1 = sharedA1;
|
|
|
|
// Dynamic method, getter, and setter calls.
|
|
Expect.equals(a1.m4(14), 4);
|
|
a1.m1();
|
|
a1.s3 = 'hello';
|
|
Expect.equals(a1.g2, 'hello');
|
|
Expect.equals(a1.m4(14), 4);
|
|
|
|
// Dynamic use of fields.
|
|
Expect.equals(a1.f1, null);
|
|
a1.f1 = 2;
|
|
Expect.equals(a1.f1, 2);
|
|
Expect.equals(a1.f2, 3);
|
|
|
|
if (const String.fromEnvironment('dynamic.modules.test.mode') == 'aot') {
|
|
// TODO(b/448095881): the tearoff operation currently fails in JIT
|
|
// Dynamic call via getter tearoff.
|
|
dynamic m4to = a1.m4;
|
|
Expect.equals(m4to(14), 4);
|
|
}
|
|
|
|
// Ensure we don't accidentally call the target without a dynamic forwarder,
|
|
// otherwise parameter checks are omitted accidentally.
|
|
Expect.throws(
|
|
() => a1.m4('str-value'),
|
|
(e) => e is ArgumentError || e is TypeError,
|
|
'missing error in dynamic call to host',
|
|
);
|
|
|
|
// Members defined in a dynamic module are dynamically-callable.
|
|
dynamic b = B();
|
|
Expect.equals(b.m4(14), 13);
|
|
Expect.equals(b.m5(14), 16);
|
|
|
|
// Members defined in a dynamic module also properly check their parameters.
|
|
Expect.throws(
|
|
() => b.m4('str-value'),
|
|
(e) => e is ArgumentError || e is TypeError,
|
|
'missing error in dynamic call within dynamic module',
|
|
);
|
|
Expect.throws(
|
|
() => b.m5('str-value'),
|
|
(e) => e is ArgumentError || e is TypeError,
|
|
'missing error in dynamic call within dynamic module',
|
|
);
|
|
|
|
// A1.m6 was not exposed, even though m6 is an allowed selector.
|
|
Expect.throws(
|
|
() => a1.m6(),
|
|
(e) => e is NoSuchMethodError,
|
|
'missing error in dynamic call to unexposed allowed method m6',
|
|
);
|
|
|
|
// A2.m1 was not exposed, but A1.m1 was, so the selector is allowed.
|
|
dynamic a2 = sharedA2;
|
|
Expect.throws(
|
|
() => a2.m1(),
|
|
(e) => e is NoSuchMethodError,
|
|
'missing error in dynamic call to unexposed class C.m1',
|
|
);
|
|
|
|
// A1.m7 is exposed in other ways, but not dynamically-callable.
|
|
Expect.throws(
|
|
() => a1.m7(),
|
|
(e) => e is NoSuchMethodError,
|
|
'missing error in dynamic call to callable but not dynamically-callable method m7',
|
|
);
|
|
|
|
dynamic a3 = sharedA4;
|
|
|
|
// Interface class A3, where A3.m9 is exposed, but A3.m6 is not.
|
|
Expect.equals(a3.m9(1), 11);
|
|
Expect.throws(
|
|
() => a3.m6(),
|
|
(e) => e is NoSuchMethodError,
|
|
'missing error in dynamic call to not dynamically-callable host method',
|
|
);
|
|
|
|
// Dynamic module class, base class only partially exposed.
|
|
dynamic b5 = B5();
|
|
Expect.throws(
|
|
() => b5.m10(), // target is unexposed host
|
|
(e) => e is NoSuchMethodError,
|
|
'missing error in dynamic call to not dynamically-callable host method',
|
|
);
|
|
Expect.equals(b5.m11(), 4); // target in dynamic module
|
|
Expect.equals(b5.m12(), 1); // target is exposed in host
|
|
Expect.equals(b5.m13(), 4); // target in dynamic module
|
|
|
|
sharedB6 = B6();
|
|
sharedB7 = B7();
|
|
|
|
return true;
|
|
}
|
|
|
|
class B {
|
|
// m4 matches an exposed selector name from the host.
|
|
int m4(int value) {
|
|
return value - 1;
|
|
}
|
|
|
|
// m5 matches a selector name in the allowlist flag.
|
|
int m5(int value) {
|
|
return value + 2;
|
|
}
|
|
}
|
|
|
|
class B5 extends A5 {
|
|
@override
|
|
int m11() => 4;
|
|
|
|
@override
|
|
int m13() => 4;
|
|
}
|
|
|
|
class B6 {
|
|
int m14() => 14;
|
|
}
|
|
|
|
class B7 extends A7 {
|
|
@override
|
|
int m16() => 4;
|
|
|
|
@override
|
|
int m18() => 4;
|
|
}
|