This is an automated email from the ASF dual-hosted git repository.
junrushao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git
The following commit(s) were added to refs/heads/main by this push:
new 38914fa fix: TypeStr support for Any type in reflection Init (#393)
38914fa is described below
commit 38914fa7a13fce9eb32462d649b0d2f1d11553d1
Author: Guan-Ming (Wesley) Chiu <[email protected]>
AuthorDate: Sat Jan 10 16:59:01 2026 +0800
fix: TypeStr support for Any type in reflection Init (#393)
## Why
- Using refl::init<Any>() to define a constructor that takes Any fails
to compile
- The reflection system converts Any to Any&& internally
- No Type2Str<Any&&> specialization existed to handle this case
## How
- Added Type2Str<Any&&> specialization in any.h
- Added forward declaration of Any in type_traits.h
---
include/tvm/ffi/any.h | 10 ++++++++
include/tvm/ffi/type_traits.h | 2 ++
tests/cpp/test_reflection.cc | 56 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 68 insertions(+)
diff --git a/include/tvm/ffi/any.h b/include/tvm/ffi/any.h
index 4ff5db0..9adbd84 100644
--- a/include/tvm/ffi/any.h
+++ b/include/tvm/ffi/any.h
@@ -516,6 +516,11 @@ struct Type2Str<const Any&> {
static std::string v() { return "Any"; }
};
+template <>
+struct Type2Str<Any&&> {
+ static std::string v() { return "Any"; }
+};
+
template <>
struct Type2Str<AnyView> {
static std::string v() { return "AnyView"; }
@@ -526,6 +531,11 @@ struct Type2Str<const AnyView&> {
static std::string v() { return "AnyView"; }
};
+template <>
+struct Type2Str<AnyView&&> {
+ static std::string v() { return "AnyView"; }
+};
+
template <>
struct Type2Str<void> {
static std::string v() { return "void"; }
diff --git a/include/tvm/ffi/type_traits.h b/include/tvm/ffi/type_traits.h
index 1fd1304..dc7f982 100644
--- a/include/tvm/ffi/type_traits.h
+++ b/include/tvm/ffi/type_traits.h
@@ -36,6 +36,8 @@
namespace tvm {
namespace ffi {
+class Any;
+
/*!
* \brief TypeTraits that specifies the conversion behavior from/to FFI Any.
*
diff --git a/tests/cpp/test_reflection.cc b/tests/cpp/test_reflection.cc
index 8fe6a18..82d73a2 100644
--- a/tests/cpp/test_reflection.cc
+++ b/tests/cpp/test_reflection.cc
@@ -294,4 +294,60 @@ TEST(Reflection, AccessPath) {
auto root_parent = root->GetParent();
EXPECT_FALSE(root_parent.has_value());
}
+
+struct TestObjWithAny : public Object {
+ Any value;
+ explicit TestObjWithAny(Any value) : value(std::move(value)) {}
+ [[maybe_unused]] static constexpr bool _type_mutable = true;
+ TVM_FFI_DECLARE_OBJECT_INFO_FINAL("test.TestObjWithAny", TestObjWithAny,
Object);
+};
+
+TVM_FFI_STATIC_INIT_BLOCK() {
+ namespace refl = tvm::ffi::reflection;
+ refl::ObjectDef<TestObjWithAny>().def(refl::init<Any>()).def_ro("value",
&TestObjWithAny::value);
+}
+
+struct TestObjWithAnyView : public Object {
+ Any value;
+ explicit TestObjWithAnyView(AnyView value) : value(value) {}
+ [[maybe_unused]] static constexpr bool _type_mutable = true;
+ TVM_FFI_DECLARE_OBJECT_INFO_FINAL("test.TestObjWithAnyView",
TestObjWithAnyView, Object);
+};
+
+TVM_FFI_STATIC_INIT_BLOCK() {
+ namespace refl = tvm::ffi::reflection;
+ refl::ObjectDef<TestObjWithAnyView>()
+ .def(refl::init<AnyView>())
+ .def_ro("value", &TestObjWithAnyView::value);
+}
+
+TEST(Reflection, InitWithAny) {
+ Function init = reflection::GetMethod("test.TestObjWithAny", "__ffi_init__");
+ Any obj1 = init(42);
+ ASSERT_TRUE(obj1.as<TestObjWithAny>() != nullptr);
+ EXPECT_EQ(obj1.as<TestObjWithAny>()->value.cast<int>(), 42);
+
+ Any obj2 = init(3.14);
+ ASSERT_TRUE(obj2.as<TestObjWithAny>() != nullptr);
+ EXPECT_EQ(obj2.as<TestObjWithAny>()->value.cast<double>(), 3.14);
+
+ Any obj3 = init(String("hello"));
+ ASSERT_TRUE(obj3.as<TestObjWithAny>() != nullptr);
+ EXPECT_EQ(obj3.as<TestObjWithAny>()->value.cast<String>(), "hello");
+}
+
+TEST(Reflection, InitWithAnyView) {
+ Function init = reflection::GetMethod("test.TestObjWithAnyView",
"__ffi_init__");
+ Any obj1 = init(42);
+ ASSERT_TRUE(obj1.as<TestObjWithAnyView>() != nullptr);
+ EXPECT_EQ(obj1.as<TestObjWithAnyView>()->value.cast<int>(), 42);
+
+ Any obj2 = init(3.14);
+ ASSERT_TRUE(obj2.as<TestObjWithAnyView>() != nullptr);
+ EXPECT_EQ(obj2.as<TestObjWithAnyView>()->value.cast<double>(), 3.14);
+
+ Any obj3 = init(String("hello"));
+ ASSERT_TRUE(obj3.as<TestObjWithAnyView>() != nullptr);
+ EXPECT_EQ(obj3.as<TestObjWithAnyView>()->value.cast<String>(), "hello");
+}
} // namespace