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

Reply via email to