This is an automated email from the ASF dual-hosted git repository.

tqchen 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 4290354c [CORE] Make concrete object references non-nullable (#840)
4290354c is described below

commit 4290354c8cdfbf1b354c423c41611465e9e25e16
Author: Tianqi Chen <[email protected]>
AuthorDate: Sun Oct 11 10:47:26 2026 -0400

    [CORE] Make concrete object references non-nullable (#840)
    
    Make concrete object-reference wrappers and containers explicitly
    non-nullable while preserving valid empty container defaults. Keep
    ObjectRef, Function, and Tensor nullable for compatibility, and use
    Optional to represent absence for concrete references.
    
    Store optional object references through pointer-sized composition
    instead of ObjectRef inheritance. Update ownership access, casting,
    reflection, and wrapper examples to make the distinction explicit.
---
 AGENTS.md                                   |  3 ++-
 docs/concepts/object_and_class.rst          |  2 +-
 docs/guides/cpp_lang_guide.md               | 10 +++++----
 docs/guides/python_lang_guide.md            |  2 +-
 include/tvm/ffi/cast.h                      | 10 +++++++--
 include/tvm/ffi/container/array.h           |  5 ++++-
 include/tvm/ffi/container/dict.h            |  5 ++++-
 include/tvm/ffi/container/list.h            |  5 ++++-
 include/tvm/ffi/container/map.h             |  5 ++++-
 include/tvm/ffi/container/tuple.h           |  1 +
 include/tvm/ffi/enum.h                      |  8 ++++----
 include/tvm/ffi/extra/structural_mutate.h   |  4 +++-
 include/tvm/ffi/extra/structural_visit.h    |  4 +++-
 include/tvm/ffi/extra/visit_error_context.h |  4 +++-
 include/tvm/ffi/optional.h                  | 30 +++++++++++++++++++--------
 include/tvm/ffi/reflection/access_path.h    | 12 +++++------
 include/tvm/ffi/reflection/enum_def.h       |  7 ++++---
 include/tvm/ffi/rvalue_ref.h                |  4 +++-
 pyproject.toml                              |  3 ++-
 src/ffi/testing/testing.cc                  | 32 +++++++++++++++++------------
 tests/cpp/extra/test_dataclass.cc           |  2 +-
 tests/cpp/extra/test_serialization.cc       | 10 ++++-----
 tests/cpp/extra/test_structural_mutate.cc   | 12 ++++++-----
 tests/cpp/test_example.cc                   |  2 +-
 tests/cpp/test_object.cc                    | 16 +++++++--------
 tests/cpp/test_reflection.cc                |  2 +-
 tests/cpp/testing_object.h                  | 32 ++++++++++++++---------------
 27 files changed, 141 insertions(+), 91 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md
index 9cf24519..5b2e143f 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -133,7 +133,8 @@ uv run --no-project --with "clang-tidy==21.1.1" \
 - Header guards: `#ifndef TVM_FFI_<PATH>_H_`.
 - Object pattern: `FooObj` (data) + `Foo` (ref wrapper extending `ObjectRef`).
   - `TVM_FFI_DECLARE_OBJECT_INFO("key", FooObj, ParentObj)` in the Obj class.
-  - `TVM_FFI_DEFINE_OBJECT_REF_METHODS(Foo, ParentRef, FooObj)` in the Ref 
class.
+  - `TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(Foo, ParentRef, FooObj)` in 
the Ref class.
+  - Use `Optional<Foo>` for absence; `ObjectRef`, `Function`, and `Tensor` 
retain nullable handles.
 - Errors: `TVM_FFI_THROW(ErrorType) << "message"`.
 - Doc comments: Doxygen (`/*! \brief ... */`).
 - Every file needs an Apache 2.0 license header.
diff --git a/docs/concepts/object_and_class.rst 
b/docs/concepts/object_and_class.rst
index 9a4fa8d6..e92163fd 100644
--- a/docs/concepts/object_and_class.rst
+++ b/docs/concepts/object_and_class.rst
@@ -111,7 +111,7 @@ creates the underlying object can wrap 
:cpp:func:`tvm::ffi::make_object`.
    Define a nullable reference class.
 
  :c:macro:`TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TypeName, ParentType, 
ObjectName) <TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE>`
-   Define a non-nullable reference class.
+   Define a non-nullable reference class. Use this for ordinary concrete 
wrappers.
 
 For example, a non-nullable reference class ``MyObject`` can be defined as 
follows:
 
diff --git a/docs/guides/cpp_lang_guide.md b/docs/guides/cpp_lang_guide.md
index fe88ea5c..203f1f00 100644
--- a/docs/guides/cpp_lang_guide.md
+++ b/docs/guides/cpp_lang_guide.md
@@ -167,7 +167,7 @@ class MyIntPair : public tvm::ffi::ObjectRef {
 
   // Required: define object reference methods
   // This macro provides the necessary methods for ObjectRef functionality
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(MyIntPair, tvm::ffi::ObjectRef, 
MyIntPairObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(MyIntPair, 
tvm::ffi::ObjectRef, MyIntPairObj);
 };
 
 void ExampleObjectRef() {
@@ -711,11 +711,13 @@ with copy-on-write semantics. Use `Dict<K, V>` when you 
need mutable in-place op
 ### Optional
 
 `Optional<T>` provides a safe way to handle values that may or may not exist.
-We specialize Optional for `ffi::String` and Object types to be more compact,
-using nullptr to indicate non-existence.
+For object references, `Optional<T>` owns one nullable object pointer without 
inheriting
+from `ObjectRef`. Access the contained reference explicitly with `value()` or 
`operator*`.
+A null `ObjectRef`, `Function`, or `Tensor` converts to an empty optional; 
ordinary
+concrete references and containers use `Optional<T>` to represent absence.
 
 ```cpp
-#include <tvm/ffi/container/optional.h>
+#include <tvm/ffi/optional.h>
 
 void ExampleOptional() {
   namespace ffi = tvm::ffi;
diff --git a/docs/guides/python_lang_guide.md b/docs/guides/python_lang_guide.md
index 1f98deb2..b98a45b8 100644
--- a/docs/guides/python_lang_guide.md
+++ b/docs/guides/python_lang_guide.md
@@ -386,7 +386,7 @@ public:
   }
 
   // Required: define object reference methods
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TestIntPair, tvm::ffi::ObjectRef, 
TestIntPairObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TestIntPair, 
tvm::ffi::ObjectRef, TestIntPairObj);
 };
 
 TVM_FFI_STATIC_INIT_BLOCK() {
diff --git a/include/tvm/ffi/cast.h b/include/tvm/ffi/cast.h
index 44228fe2..033ff549 100644
--- a/include/tvm/ffi/cast.h
+++ b/include/tvm/ffi/cast.h
@@ -46,8 +46,14 @@ namespace ffi {
  */
 template <typename RefType, typename ObjectType>
 inline RefType GetRef(const ObjectType* ptr) {
-  if constexpr (object_ref_contains_v<RefType, ObjectType>) {
-    if constexpr (is_optional_type_v<RefType> || RefType::_type_is_nullable) {
+  if constexpr (is_optional_type_v<RefType>) {
+    using ValueType = typename RefType::value_type;
+    static_assert(object_ref_contains_v<ValueType, ObjectType>,
+                  "GetRef requires the Optional value type to contain every 
ObjectType instance");
+    if (ptr == nullptr) return std::nullopt;
+    return RefType(GetRef<ValueType>(ptr));
+  } else if constexpr (object_ref_contains_v<RefType, ObjectType>) {
+    if constexpr (RefType::_type_is_nullable) {
       if (ptr == nullptr) {
         return details::ObjectUnsafe::ObjectRefFromObjectPtr<RefType>(nullptr);
       }
diff --git a/include/tvm/ffi/container/array.h 
b/include/tvm/ffi/container/array.h
index f5421df5..0680a741 100644
--- a/include/tvm/ffi/container/array.h
+++ b/include/tvm/ffi/container/array.h
@@ -276,7 +276,9 @@ class Array : public ObjectRef {
    * \brief Constructor from pointer
    * \param n the container pointer
    */
-  explicit Array(ObjectPtr<Object> n) : ObjectRef(std::move(n)) {}
+  explicit Array(ObjectPtr<Object> n) : ObjectRef(std::move(n)) {
+    TVM_FFI_ICHECK_NOTNULL(data_.get());
+  }
 
   /*!
    * \brief Constructor from iterator
@@ -655,6 +657,7 @@ class Array : public ObjectRef {
   /// \cond Doxygen_Suppress
   using ContainerType = ArrayObj;
   static constexpr bool _type_container_is_exact = false;
+  static constexpr bool _type_is_nullable = false;
   /// \endcond
 
   /*!
diff --git a/include/tvm/ffi/container/dict.h b/include/tvm/ffi/container/dict.h
index 32751a09..31325149 100644
--- a/include/tvm/ffi/container/dict.h
+++ b/include/tvm/ffi/container/dict.h
@@ -173,7 +173,9 @@ class Dict : public ObjectRef {
    * \brief constructor from pointer
    * \param n the container pointer
    */
-  explicit Dict(ObjectPtr<Object> n) : ObjectRef(n) {}
+  explicit Dict(ObjectPtr<Object> n) : ObjectRef(std::move(n)) {
+    TVM_FFI_ICHECK_NOTNULL(data_.get());
+  }
   /*!
    * \brief constructor from iterator
    * \param begin begin of iterator
@@ -274,6 +276,7 @@ class Dict : public ObjectRef {
   /// \cond Doxygen_Suppress
   using ContainerType = DictObj;
   static constexpr bool _type_container_is_exact = false;
+  static constexpr bool _type_is_nullable = false;
   /// \endcond
 
   /// \cond Doxygen_Suppress
diff --git a/include/tvm/ffi/container/list.h b/include/tvm/ffi/container/list.h
index bf865664..6bc0c2d4 100644
--- a/include/tvm/ffi/container/list.h
+++ b/include/tvm/ffi/container/list.h
@@ -212,7 +212,9 @@ class List : public ObjectRef {
   }
 
   /*! \brief Constructor from pointer */
-  explicit List(ObjectPtr<Object> n) : ObjectRef(std::move(n)) {}
+  explicit List(ObjectPtr<Object> n) : ObjectRef(std::move(n)) {
+    TVM_FFI_ICHECK_NOTNULL(data_.get());
+  }
 
   /*!
    * \brief Constructor from iterator
@@ -465,6 +467,7 @@ class List : public ObjectRef {
   /// \cond Doxygen_Suppress
   using ContainerType = ListObj;
   static constexpr bool _type_container_is_exact = false;
+  static constexpr bool _type_is_nullable = false;
   /// \endcond
 
  private:
diff --git a/include/tvm/ffi/container/map.h b/include/tvm/ffi/container/map.h
index 5c0807ca..542643f8 100644
--- a/include/tvm/ffi/container/map.h
+++ b/include/tvm/ffi/container/map.h
@@ -168,7 +168,9 @@ class Map : public ObjectRef {
    * \brief constructor from pointer
    * \param n the container pointer
    */
-  explicit Map(ObjectPtr<Object> n) : ObjectRef(n) {}
+  explicit Map(ObjectPtr<Object> n) : ObjectRef(std::move(n)) {
+    TVM_FFI_ICHECK_NOTNULL(data_.get());
+  }
   /*!
    * \brief constructor from iterator
    * \param begin begin of iterator
@@ -280,6 +282,7 @@ class Map : public ObjectRef {
   /// \cond Doxygen_Suppress
   using ContainerType = MapObj;
   static constexpr bool _type_container_is_exact = false;
+  static constexpr bool _type_is_nullable = false;
   /// \endcond
 
   /// \cond Doxygen_Suppress
diff --git a/include/tvm/ffi/container/tuple.h 
b/include/tvm/ffi/container/tuple.h
index 2d73f836..7353375c 100644
--- a/include/tvm/ffi/container/tuple.h
+++ b/include/tvm/ffi/container/tuple.h
@@ -193,6 +193,7 @@ class Tuple : public ObjectRef {
   /// \cond Doxygen_Suppress
   using ContainerType = ArrayObj;
   static constexpr bool _type_container_is_exact = false;
+  static constexpr bool _type_is_nullable = false;
   /// \endcond
 
  private:
diff --git a/include/tvm/ffi/enum.h b/include/tvm/ffi/enum.h
index d586a699..97d12442 100644
--- a/include/tvm/ffi/enum.h
+++ b/include/tvm/ffi/enum.h
@@ -63,7 +63,7 @@ class EnumStateObj : public Object {
 class EnumState : public ObjectRef {
  public:
   /// \cond Doxygen_Suppress
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(EnumState, ObjectRef, 
EnumStateObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(EnumState, ObjectRef, 
EnumStateObj);
   /// \endcond
 };
 
@@ -140,7 +140,7 @@ class EnumObj : public Object {
 class Enum : public ObjectRef {
  public:
   /// \cond Doxygen_Suppress
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(Enum, ObjectRef, EnumObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(Enum, ObjectRef, EnumObj);
   /// \endcond
 };
 
@@ -160,7 +160,7 @@ class IntEnumObj : public EnumObj {
 class IntEnum : public Enum {
  public:
   /// \cond Doxygen_Suppress
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(IntEnum, Enum, IntEnumObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(IntEnum, Enum, IntEnumObj);
   /// \endcond
 };
 
@@ -180,7 +180,7 @@ class StrEnumObj : public EnumObj {
 class StrEnum : public Enum {
  public:
   /// \cond Doxygen_Suppress
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(StrEnum, Enum, StrEnumObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(StrEnum, Enum, StrEnumObj);
   /// \endcond
 };
 
diff --git a/include/tvm/ffi/extra/structural_mutate.h 
b/include/tvm/ffi/extra/structural_mutate.h
index db543c39..b8db9197 100644
--- a/include/tvm/ffi/extra/structural_mutate.h
+++ b/include/tvm/ffi/extra/structural_mutate.h
@@ -766,7 +766,9 @@ class StructuralMutator : public ObjectRef {
    * \brief Construct from an existing mutator object pointer.
    * \param n The object pointer to wrap.
    */
-  explicit StructuralMutator(ObjectPtr<StructuralMutatorObj> n) : 
ObjectRef(std::move(n)) {}
+  explicit StructuralMutator(ObjectPtr<StructuralMutatorObj> n) : 
ObjectRef(std::move(n)) {
+    TVM_FFI_ICHECK_NOTNULL(data_.get());
+  }
 
   /// \cond Doxygen_Suppress
   TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(StructuralMutator, ObjectRef, 
StructuralMutatorObj);
diff --git a/include/tvm/ffi/extra/structural_visit.h 
b/include/tvm/ffi/extra/structural_visit.h
index 75df53d8..de3eba98 100644
--- a/include/tvm/ffi/extra/structural_visit.h
+++ b/include/tvm/ffi/extra/structural_visit.h
@@ -302,7 +302,9 @@ class StructuralVisitor : public ObjectRef {
    * \brief Construct from an existing object pointer.
    * \param n The object pointer to wrap.
    */
-  explicit StructuralVisitor(ObjectPtr<StructuralVisitorObj> n) : 
ObjectRef(std::move(n)) {}
+  explicit StructuralVisitor(ObjectPtr<StructuralVisitorObj> n) : 
ObjectRef(std::move(n)) {
+    TVM_FFI_ICHECK_NOTNULL(data_.get());
+  }
 
   /// \cond Doxygen_Suppress
   TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(StructuralVisitor, ObjectRef, 
StructuralVisitorObj);
diff --git a/include/tvm/ffi/extra/visit_error_context.h 
b/include/tvm/ffi/extra/visit_error_context.h
index 76c49375..4990fdc7 100644
--- a/include/tvm/ffi/extra/visit_error_context.h
+++ b/include/tvm/ffi/extra/visit_error_context.h
@@ -120,7 +120,9 @@ class VisitErrorContext : public ObjectRef {
       bool allow_prefix_match = false);
 
   /// \cond Doxygen_Suppress
-  explicit VisitErrorContext(ObjectPtr<VisitErrorContextObj> n) : 
ObjectRef(std::move(n)) {}
+  explicit VisitErrorContext(ObjectPtr<VisitErrorContextObj> n) : 
ObjectRef(std::move(n)) {
+    TVM_FFI_ICHECK_NOTNULL(data_.get());
+  }
   TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(VisitErrorContext, ObjectRef, 
VisitErrorContextObj);
   /// \endcond
 };
diff --git a/include/tvm/ffi/optional.h b/include/tvm/ffi/optional.h
index a089618b..7a14bc2a 100644
--- a/include/tvm/ffi/optional.h
+++ b/include/tvm/ffi/optional.h
@@ -368,15 +368,15 @@ class Optional<T,
 /*!
  * \brief Pointer-sized Optional specialization for ObjectRef types.
  *
- * ObjectRef already owns an ObjectPtr<Object>. Reusing that storage keeps the
- * long-standing nullable-pointer ABI: nullptr is nullopt, and an engaged value
- * is represented by the object's pointer with no TVMFFIAny wrapper.
+ * One ObjectPtr<Object> keeps the nullable-pointer ABI: nullptr is nullopt, 
and
+ * an engaged value is represented by the object's pointer with no TVMFFIAny
+ * wrapper. Optional is not an ObjectRef; access the contained reference 
explicitly.
  */
 template <typename T>
-class Optional<T, std::enable_if_t<use_object_ref_optional_v<T>>> : public 
ObjectRef {
+class Optional<T, std::enable_if_t<use_object_ref_optional_v<T>>> {
  public:
+  using value_type = T;
   using ContainerType = typename T::ContainerType;
-  static constexpr bool _type_container_is_exact = T::_type_container_is_exact;
 
   Optional() = default;
   // Special members are explicitly inlined to enable move cleanup 
optimizations
@@ -384,7 +384,7 @@ class Optional<T, 
std::enable_if_t<use_object_ref_optional_v<T>>> : public Objec
   // NOLINTBEGIN(google-explicit-constructor)
   TVM_FFI_INLINE Optional(const Optional&) = default;
   TVM_FFI_INLINE Optional(Optional&&) noexcept = default;
-  explicit Optional(UnsafeInit tag) : ObjectRef(tag) {}
+  explicit Optional(UnsafeInit) {}
   Optional(std::nullopt_t) {}
   Optional(std::nullptr_t) {}
   TVM_FFI_INLINE Optional(std::optional<T> other) {
@@ -392,17 +392,19 @@ class Optional<T, 
std::enable_if_t<use_object_ref_optional_v<T>>> : public Objec
       *this = *std::move(other);
     }
   }
-  TVM_FFI_INLINE Optional(T other) : ObjectRef(std::move(other)) {}
+  TVM_FFI_INLINE Optional(T other)
+      : 
data_(details::ObjectUnsafe::ObjectPtrFromObjectRef<Object>(std::move(other))) 
{}
   // NOLINTEND(google-explicit-constructor)
 
   TVM_FFI_INLINE Optional& operator=(const Optional&) = default;
   TVM_FFI_INLINE Optional& operator=(Optional&& other) noexcept {
-    ObjectRef::operator=(std::move(other));
+    data_ = std::move(other.data_);
+    other.data_ = nullptr;
     return *this;
   }
 
   TVM_FFI_INLINE Optional& operator=(T other) {
-    ObjectRef::operator=(std::move(other));
+    data_ = 
details::ObjectUnsafe::ObjectPtrFromObjectRef<Object>(std::move(other));
     return *this;
   }
 
@@ -489,7 +491,17 @@ class Optional<T, 
std::enable_if_t<use_object_ref_optional_v<T>>> : public Objec
     return static_cast<ContainerType*>(data_.get());
   }
 
+  TVM_FFI_INLINE const ContainerType* operator->() const { return get(); }
+  TVM_FFI_INLINE bool same_as(const Optional& other) const { return data_ == 
other.data_; }
+  TVM_FFI_INLINE bool same_as(const ObjectRef& other) const { return 
data_.get() == other.get(); }
+  TVM_FFI_INLINE bool unique() const { return data_.unique(); }
+  TVM_FFI_INLINE int use_count() const { return data_.use_count(); }
+
  private:
+  ObjectPtr<Object> data_;
+
+  friend struct details::ObjectUnsafe;
+
   template <typename U>
   TVM_FFI_INLINE auto EQToOptional(const U& other) const {
     using RetType = decltype(operator*() == *other);
diff --git a/include/tvm/ffi/reflection/access_path.h 
b/include/tvm/ffi/reflection/access_path.h
index 74d106ce..afaa0464 100644
--- a/include/tvm/ffi/reflection/access_path.h
+++ b/include/tvm/ffi/reflection/access_path.h
@@ -305,8 +305,8 @@ class AccessPathObj : public Object {
       if (!(*lhs->step)->StepEqual(*(rhs->step))) {
         return false;
       }
-      lhs = lhs->parent.as<AccessPathObj>();
-      rhs = rhs->parent.as<AccessPathObj>();
+      lhs = (*lhs->parent).as<AccessPathObj>();
+      rhs = (*rhs->parent).as<AccessPathObj>();
       // fast path for same pointer
       if (lhs == rhs) return true;
       TVM_FFI_ICHECK(lhs != nullptr);
@@ -373,8 +373,8 @@ class AccessPath : public ObjectRef {
 using AccessPathPair = Tuple<AccessPath, AccessPath>;
 
 inline Optional<AccessPath> AccessPathObj::GetParent() const {
-  if (auto opt_parent = this->parent.as<AccessPath>()) {
-    return opt_parent;
+  if (parent) {
+    return (*parent).as<AccessPath>();
   }
   return std::nullopt;
 }
@@ -415,7 +415,7 @@ inline Array<AccessStep> AccessPathObj::ToSteps() const {
   while (current->parent.has_value()) {
     TVM_FFI_ICHECK(current->step.has_value());
     reverse_steps.push_back(*(current->step));
-    current = current->parent.as<AccessPathObj>();
+    current = (*current->parent).as<AccessPathObj>();
     TVM_FFI_ICHECK(current != nullptr);
   }
   return Array<AccessStep>(reverse_steps.rbegin(), reverse_steps.rend());
@@ -432,7 +432,7 @@ inline bool AccessPathObj::IsPrefixOf(const AccessPath& 
other) const {
   const AccessPathObj* rhs_path = other.get();
   while (rhs_path->depth > this->depth) {
     TVM_FFI_ICHECK(rhs_path->parent.has_value());
-    rhs_path = rhs_path->parent.as<AccessPathObj>();
+    rhs_path = (*rhs_path->parent).as<AccessPathObj>();
   }
   return PathEqual(this, rhs_path);
 }
diff --git a/include/tvm/ffi/reflection/enum_def.h 
b/include/tvm/ffi/reflection/enum_def.h
index b32e876e..4b72fe3a 100644
--- a/include/tvm/ffi/reflection/enum_def.h
+++ b/include/tvm/ffi/reflection/enum_def.h
@@ -107,7 +107,7 @@ class EnumDef : public ReflectionDefBase {
     ::tvm::ffi::details::ObjectUnsafe::GetHeader(obj.get())->type_index = 
type_index_;
     obj->_int_index = int_index;
     obj->_str_index = std::move(str_index);
-    instance_ = Enum(ObjectPtr<EnumObj>(std::move(obj)));
+    instance_ = 
::tvm::ffi::details::ObjectUnsafe::ObjectRefFromObjectPtr<Enum>(std::move(obj));
     entries.push_back(instance_);
     indexes.Set(int_key, instance_);
     indexes.Set(str_key, instance_);
@@ -131,7 +131,8 @@ class EnumDef : public ReflectionDefBase {
     // GCC runs attribute constructors before dynamic initialization of inline 
type indices.
     // Set the header explicitly so the state is not packed as `None` during 
static init.
     ::tvm::ffi::details::ObjectUnsafe::GetHeader(state_obj.get())->type_index 
= state_type_index;
-    EnumState state(std::move(state_obj));
+    EnumState state =
+        
::tvm::ffi::details::ObjectUnsafe::ObjectRefFromObjectPtr<EnumState>(std::move(state_obj));
     constexpr TVMFFIByteArray name = AsByteArray(type_attr::kEnumState);
     TVMFFIAny value_any = AnyView(state).CopyToTVMFFIAny();
     TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeRegisterAttr(type_index_, &name, 
&value_any));
@@ -139,7 +140,7 @@ class EnumDef : public ReflectionDefBase {
   }
 
   int32_t type_index_;
-  Enum instance_;
+  Enum instance_{UnsafeInit{}};
 };
 
 }  // namespace reflection
diff --git a/include/tvm/ffi/rvalue_ref.h b/include/tvm/ffi/rvalue_ref.h
index c34a12e2..e55c41de 100644
--- a/include/tvm/ffi/rvalue_ref.h
+++ b/include/tvm/ffi/rvalue_ref.h
@@ -76,7 +76,9 @@ class RValueRef {
       : 
data_(details::ObjectUnsafe::ObjectPtrFromObjectRef<ContainerType>(std::move(data)))
 {}
 
   /*! \brief return the data as rvalue */
-  TObjRef operator*() && { return TObjRef(std::move(data_)); }
+  TObjRef operator*() && {
+    return 
details::ObjectUnsafe::ObjectRefFromObjectPtr<TObjRef>(std::move(data_));
+  }
 
  private:
   mutable ObjectPtr<ContainerType> data_;
diff --git a/pyproject.toml b/pyproject.toml
index 105953b2..dddadc2a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -111,7 +111,8 @@ tvm-ffi-stubgen = "tvm_ffi.stub.cli:__main__"
 # __dealloc__, and Cython 3.2.8 (2026-06-30) fixed the free-threaded object
 # keep-alive scheme for code executed there (cython#7769). Earlier Cython can
 # collect the wrapper mid-__dealloc__ on the 3.14t build.
-requires = ["scikit-build-core>=0.10.0", "cython>=3.2.8", "setuptools-scm"]
+# scikit-build-core 1.1.0 breaks free-threaded Development.Module discovery on 
CMake <4.1.2.
+requires = ["scikit-build-core>=0.10.0,!=1.1.0", "cython>=3.2.8", 
"setuptools-scm"]
 build-backend = "scikit_build_core.build"
 
 [tool.scikit-build]
diff --git a/src/ffi/testing/testing.cc b/src/ffi/testing/testing.cc
index cda1078e..319c8347 100644
--- a/src/ffi/testing/testing.cc
+++ b/src/ffi/testing/testing.cc
@@ -69,7 +69,7 @@ class TestIntPair : public tvm::ffi::ObjectRef {
   int64_t Sum() const { return get()->a + get()->b; }
 
   // Required: define object reference methods
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TestIntPair, tvm::ffi::ObjectRef, 
TestIntPairObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TestIntPair, 
tvm::ffi::ObjectRef, TestIntPairObj);
 };
 
 class TestFrozenCxxObj : public tvm::ffi::Object {
@@ -103,7 +103,8 @@ class TestEnumVariantObj : public tvm::ffi::EnumObj {
 
 class TestEnumVariant : public tvm::ffi::Enum {
  public:
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TestEnumVariant, tvm::ffi::Enum, 
TestEnumVariantObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TestEnumVariant, 
tvm::ffi::Enum,
+                                                TestEnumVariantObj);
 };
 
 TVM_FFI_STATIC_INIT_BLOCK() {
@@ -125,7 +126,8 @@ class TestCxxIntEnumObj : public tvm::ffi::IntEnumObj {
 
 class TestCxxIntEnum : public tvm::ffi::IntEnum {
  public:
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TestCxxIntEnum, 
tvm::ffi::IntEnum, TestCxxIntEnumObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TestCxxIntEnum, 
tvm::ffi::IntEnum,
+                                                TestCxxIntEnumObj);
 };
 
 class TestCxxStrEnumObj : public tvm::ffi::StrEnumObj {
@@ -137,7 +139,8 @@ class TestCxxStrEnumObj : public tvm::ffi::StrEnumObj {
 
 class TestCxxStrEnum : public tvm::ffi::StrEnum {
  public:
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TestCxxStrEnum, 
tvm::ffi::StrEnum, TestCxxStrEnumObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TestCxxStrEnum, 
tvm::ffi::StrEnum,
+                                                TestCxxStrEnumObj);
 };
 
 TVM_FFI_STATIC_INIT_BLOCK() {
@@ -278,6 +281,8 @@ class TestCxxEnumHolderObj : public Object {
   TestCxxIntEnum priority;
   TestCxxStrEnum opcode;
 
+  explicit TestCxxEnumHolderObj(UnsafeInit) : priority(UnsafeInit{}), 
opcode(UnsafeInit{}) {}
+
   static constexpr bool _type_mutable = true;
   TVM_FFI_DECLARE_OBJECT_INFO("testing.TestCxxEnumHolder", 
TestCxxEnumHolderObj, Object);
 };
@@ -436,7 +441,7 @@ class TestCompareObj : public Object {
 
 class TestCompare : public ObjectRef {
  public:
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TestCompare, ObjectRef, 
TestCompareObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TestCompare, ObjectRef, 
TestCompareObj);
 };
 
 class TestHashObj : public Object {
@@ -454,7 +459,7 @@ class TestHashObj : public Object {
 
 class TestHash : public ObjectRef {
  public:
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TestHash, ObjectRef, TestHashObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TestHash, ObjectRef, 
TestHashObj);
 };
 
 class TestCustomHashObj : public Object {
@@ -470,7 +475,7 @@ class TestCustomHashObj : public Object {
 
 class TestCustomHash : public ObjectRef {
  public:
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TestCustomHash, ObjectRef, 
TestCustomHashObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TestCustomHash, ObjectRef, 
TestCustomHashObj);
 };
 
 class TestCustomCompareObj : public Object {
@@ -486,7 +491,7 @@ class TestCustomCompareObj : public Object {
 
 class TestCustomCompare : public ObjectRef {
  public:
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TestCustomCompare, ObjectRef, 
TestCustomCompareObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TestCustomCompare, ObjectRef, 
TestCustomCompareObj);
 };
 
 // Test object with __ffi_eq__ but deliberately no __ffi_hash__.
@@ -504,7 +509,7 @@ class TestEqWithoutHashObj : public Object {
 
 class TestEqWithoutHash : public ObjectRef {
  public:
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TestEqWithoutHash, ObjectRef, 
TestEqWithoutHashObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TestEqWithoutHash, ObjectRef, 
TestEqWithoutHashObj);
 };
 
 // NOLINTNEXTLINE(performance-unnecessary-value-param)
@@ -922,7 +927,10 @@ class SchemaAllTypesObj : public Object {
 
 class SchemaAllTypes : public ObjectRef {
  public:
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(SchemaAllTypes, ObjectRef, 
SchemaAllTypesObj);
+  SchemaAllTypes(int64_t vi, double vf, String s)
+      : ObjectRef(make_object<SchemaAllTypesObj>(vi, vf, std::move(s))) {}
+
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(SchemaAllTypes, ObjectRef, 
SchemaAllTypesObj);
 };
 
 TVM_FFI_STATIC_INIT_BLOCK() {
@@ -959,9 +967,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
       // Register static creator (also a static method)
       .def_static(
           "make_with",
-          [](int64_t vi, double vf, String s) {
-            return SchemaAllTypes(make_object<SchemaAllTypesObj>(vi, vf, 
std::move(s)));
-          },
+          [](int64_t vi, double vf, String s) { return SchemaAllTypes(vi, vf, 
std::move(s)); },
           "Constructor with subset of fields");
 
   // Global typed functions to exercise RegisterFunc with various schemas
diff --git a/tests/cpp/extra/test_dataclass.cc 
b/tests/cpp/extra/test_dataclass.cc
index 4e7e21a4..f9a2c857 100644
--- a/tests/cpp/extra/test_dataclass.cc
+++ b/tests/cpp/extra/test_dataclass.cc
@@ -94,7 +94,7 @@ TEST(OstreamObjectRef, DerivedSlicing) {
 }
 
 TEST(OstreamObjectRef, NullObjectRef) {
-  TNumber n;  // default-constructed, null
+  ObjectRef n;  // default-constructed, null
   std::ostringstream os;
   os << n;
   EXPECT_EQ(os.str(), "None");
diff --git a/tests/cpp/extra/test_serialization.cc 
b/tests/cpp/extra/test_serialization.cc
index 7c30c7f3..4cf086ba 100644
--- a/tests/cpp/extra/test_serialization.cc
+++ b/tests/cpp/extra/test_serialization.cc
@@ -47,7 +47,7 @@ class SerializationEnumObj : public EnumObj {
 
 class SerializationEnum : public Enum {
  public:
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(SerializationEnum, Enum, 
SerializationEnumObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(SerializationEnum, Enum, 
SerializationEnumObj);
 };
 
 class SerializationIntEnumObj : public IntEnumObj {
@@ -58,8 +58,8 @@ class SerializationIntEnumObj : public IntEnumObj {
 
 class SerializationIntEnum : public IntEnum {
  public:
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(SerializationIntEnum, IntEnum,
-                                             SerializationIntEnumObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(SerializationIntEnum, IntEnum,
+                                                SerializationIntEnumObj);
 };
 
 class SerializationStrEnumObj : public StrEnumObj {
@@ -70,8 +70,8 @@ class SerializationStrEnumObj : public StrEnumObj {
 
 class SerializationStrEnum : public StrEnum {
  public:
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(SerializationStrEnum, StrEnum,
-                                             SerializationStrEnumObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(SerializationStrEnum, StrEnum,
+                                                SerializationStrEnumObj);
 };
 
 TVM_FFI_STATIC_INIT_BLOCK() {
diff --git a/tests/cpp/extra/test_structural_mutate.cc 
b/tests/cpp/extra/test_structural_mutate.cc
index 1cc31e75..348f94be 100644
--- a/tests/cpp/extra/test_structural_mutate.cc
+++ b/tests/cpp/extra/test_structural_mutate.cc
@@ -318,7 +318,7 @@ class TNestedMapHook : public ObjectRef {
     data_ = make_object<TNestedMapHookObj>(std::move(field));
   }
 
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TNestedMapHook, ObjectRef, 
TNestedMapHookObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TNestedMapHook, ObjectRef, 
TNestedMapHookObj);
 };
 
 TVM_FFI_STATIC_INIT_BLOCK() {
@@ -800,10 +800,12 @@ TEST(StructuralMap, 
RegisteredMutateHookUsesAssignOrReturn) {
 
   int nullable_var_callbacks = 0;
   nullable_mapped =
-      StructuralMap<WalkOrder::kPostOrder>(nullable, [&](const TVar& value) -> 
Expected<Any> {
-        ++nullable_var_callbacks;
-        return value.defined() ? Any(value) : Any(ObjectRef(nullptr));
-      }).cast<TMutatePair>();
+      StructuralMap<WalkOrder::kPostOrder>(nullable,
+                                           [&](const Optional<TVar>& value) -> 
Expected<Any> {
+                                             ++nullable_var_callbacks;
+                                             return Any(value);
+                                           })
+          .cast<TMutatePair>();
   EXPECT_EQ(nullable_var_callbacks, 2);
   EXPECT_FALSE(nullable_mapped->lhs.defined());
   EXPECT_TRUE(nullable_mapped->rhs.same_as(rhs));
diff --git a/tests/cpp/test_example.cc b/tests/cpp/test_example.cc
index 47b2d0fc..9a382958 100644
--- a/tests/cpp/test_example.cc
+++ b/tests/cpp/test_example.cc
@@ -255,7 +255,7 @@ class MyIntPair : public tvm::ffi::ObjectRef {
   explicit MyIntPair(int64_t a, int64_t b) { data_ = 
tvm::ffi::make_object<MyIntPairObj>(a, b); }
 
   // Required: define object reference methods
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(MyIntPair, tvm::ffi::ObjectRef, 
MyIntPairObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(MyIntPair, 
tvm::ffi::ObjectRef, MyIntPairObj);
 };
 
 void ExampleObjectPtr() {
diff --git a/tests/cpp/test_object.cc b/tests/cpp/test_object.cc
index 23c7cd38..5bd7762a 100644
--- a/tests/cpp/test_object.cc
+++ b/tests/cpp/test_object.cc
@@ -40,10 +40,9 @@ namespace testing {
 
 class TIntOrFloatRef : public ObjectRef {
  public:
-  TIntOrFloatRef() = default;
   explicit TIntOrFloatRef(UnsafeInit tag) : ObjectRef(tag) {}
 
-  static constexpr bool _type_is_nullable = true;
+  static constexpr bool _type_is_nullable = false;
   static constexpr bool _type_container_is_exact = false;
   using ContainerType = Object;
 };
@@ -97,9 +96,8 @@ inline constexpr bool object_ref_contains_is_enabled_v<
 static_assert(ObjectRef::_type_container_is_exact);
 static_assert(TNumber::_type_container_is_exact);
 static_assert(TInt::_type_container_is_exact);
-// ObjectRef optionals retain the original ObjectRef/ObjectPtr representation
-// and continue to participate in the ObjectRef container concept.
-static_assert(std::is_base_of_v<ObjectRef, Optional<TInt>>);
+// ObjectRef optionals retain pointer storage without inheriting ObjectRef.
+static_assert(!std::is_base_of_v<ObjectRef, Optional<TInt>>);
 static_assert(!TIntOrFloatRef::_type_container_is_exact);
 static_assert(!Array<TInt>::_type_container_is_exact);
 static_assert(!List<TInt>::_type_container_is_exact);
@@ -110,14 +108,14 @@ static_assert(!Variant<TInt, 
TFloat>::_type_container_is_exact);
 
 static_assert(object_ref_contains_v<TNumber, TIntObj>);
 static_assert(object_ref_contains_v<TInt, TIntObj>);
-static_assert(object_ref_contains_v<Optional<TInt>, TIntObj>);
+static_assert(object_ref_contains_v<Optional<TInt>::value_type, TIntObj>);
 static_assert(!object_ref_contains_v<TInt, TFloatObj>);
 static_assert(!object_ref_contains_v<Array<TInt>, ArrayObj>);
 static_assert(object_ref_contains_v<TIntOrFloatRef, TIntObj>);
 static_assert(object_ref_contains_v<TIntOrFloatRef, TFloatObj>);
 static_assert(!object_ref_contains_v<TIntOrFloatRef, TNumberObj>);
 static_assert(object_ref_contains_is_enabled_v<TInt, TIntObj>);
-static_assert(object_ref_contains_is_enabled_v<Optional<TInt>, TIntObj>);
+static_assert(!object_ref_contains_is_enabled_v<Optional<TInt>, TIntObj>);
 static_assert(object_ref_contains_is_enabled_v<TIntOrFloatRef, TIntObj>);
 static_assert(!object_ref_contains_is_enabled_v<int, TIntObj>);
 static_assert(!object_ref_contains_is_enabled_v<TIntObj, TIntObj>);
@@ -242,7 +240,7 @@ TEST(ObjectRef, as) {
   EXPECT_TRUE(c.as<TIntObj>() == nullptr);
   EXPECT_TRUE(c.as<TFloatObj>() == nullptr);
   EXPECT_TRUE(c.as<TNumberObj>() == nullptr);
-  auto null_number = c.as<TNumber>();
+  auto null_number = c.as<ObjectRef>();
   ASSERT_TRUE(null_number.has_value()) << "Expected nullable null ObjectRef 
cast to succeed";
   EXPECT_TRUE(!(*null_number).defined());  // 
NOLINT(bugprone-unchecked-optional-access)
   EXPECT_TRUE(!c.as<TInt>().has_value());
@@ -290,7 +288,7 @@ TEST(ObjectRef, AsOrThrow) {
   EXPECT_EQ(a.as<TIntObj>()->value, 10);
   EXPECT_EQ(a.as_or_throw<TInt>()->value, 10);
   EXPECT_EQ(b.as<TFloatObj>()->value, 20);
-  EXPECT_TRUE(!c.as_or_throw<TNumber>().defined());
+  EXPECT_TRUE(!c.as_or_throw<ObjectRef>().defined());
   auto const_as = const_a.as<TInt>();
   ASSERT_TRUE(const_as.has_value()) << "Expected const ObjectRef as<TInt>() to 
succeed";
   EXPECT_EQ((*const_as).get()->value, 30);  // 
NOLINT(bugprone-unchecked-optional-access)
diff --git a/tests/cpp/test_reflection.cc b/tests/cpp/test_reflection.cc
index 84a80b6a..2ea12f98 100644
--- a/tests/cpp/test_reflection.cc
+++ b/tests/cpp/test_reflection.cc
@@ -59,7 +59,7 @@ struct TestObjADerived : public TestObjA {
 };
 
 struct TestObjRefADerived : public ObjectRef {
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TestObjRefADerived, ObjectRef, 
TestObjADerived);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TestObjRefADerived, ObjectRef, 
TestObjADerived);
 };
 
 struct PrefixLookupObj : public Object {
diff --git a/tests/cpp/testing_object.h b/tests/cpp/testing_object.h
index 0b8881c3..3cd5474d 100644
--- a/tests/cpp/testing_object.h
+++ b/tests/cpp/testing_object.h
@@ -56,7 +56,7 @@ class TNumberObj : public BasePad, public Object {
 
 class TNumber : public ObjectRef {
  public:
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TNumber, ObjectRef, TNumberObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TNumber, ObjectRef, 
TNumberObj);
 };
 
 class TIntObj : public TNumberObj {
@@ -75,7 +75,7 @@ class TIntObj : public TNumberObj {
 
 class TInt : public TNumber {
  public:
-  explicit TInt(int64_t value) { data_ = make_object<TIntObj>(value); }
+  explicit TInt(int64_t value) : TNumber(UnsafeInit{}) { data_ = 
make_object<TIntObj>(value); }
 
   static TInt StaticAdd(TInt lhs, TInt rhs) { return TInt(lhs->value + 
rhs->value); }
 
@@ -127,7 +127,7 @@ class TFloatObj : public TNumberObj {
 
 class TFloat : public TNumber {
  public:
-  explicit TFloat(double value) { data_ = make_object<TFloatObj>(value); }
+  explicit TFloat(double value) : TNumber(UnsafeInit{}) { data_ = 
make_object<TFloatObj>(value); }
 
   static uint64_t CustomAnyHash(const Any& src) {
     double value = src.cast<TFloat>()->value;
@@ -138,7 +138,7 @@ class TFloat : public TNumber {
     return lhs.cast<TFloat>()->value == rhs.cast<TFloat>()->value;
   }
 
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TFloat, TNumber, TFloatObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TFloat, TNumber, TFloatObj);
 };
 
 inline void TFloatObj::RegisterReflection() {
@@ -181,7 +181,7 @@ class TPrimExpr : public ObjectRef {
     data_ = make_object<TPrimExprObj>(dtype, value);
   }
 
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TPrimExpr, ObjectRef, 
TPrimExprObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TPrimExpr, ObjectRef, 
TPrimExprObj);
 };
 
 class TVarObj : public Object {
@@ -206,7 +206,7 @@ class TVar : public ObjectRef {
  public:
   explicit TVar(std::string name) { data_ = make_object<TVarObj>(name); }
 
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TVar, ObjectRef, TVarObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TVar, ObjectRef, TVarObj);
 };
 
 class TPairObj : public Object {
@@ -232,7 +232,7 @@ class TPair : public ObjectRef {
     data_ = make_object<TPairObj>(std::move(lhs), std::move(rhs));
   }
 
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TPair, ObjectRef, TPairObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TPair, ObjectRef, TPairObj);
 };
 
 class TMutatePairObj : public Object {
@@ -288,7 +288,7 @@ class TMutatePair : public ObjectRef {
     data_ = make_object<TMutatePairObj>(std::move(lhs), std::move(rhs));
   }
 
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TMutatePair, ObjectRef, 
TMutatePairObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TMutatePair, ObjectRef, 
TMutatePairObj);
 };
 
 class TObjectPtrHolderObj : public Object {
@@ -323,7 +323,7 @@ class TObjectPtrHolder : public ObjectRef {
     data_ = make_object<TObjectPtrHolderObj>(std::move(value), 
std::move(optional_alias));
   }
 
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TObjectPtrHolder, ObjectRef, 
TObjectPtrHolderObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TObjectPtrHolder, ObjectRef, 
TObjectPtrHolderObj);
 };
 
 // FreeVar test object that has a sub-field referencing another FreeVar.
@@ -365,7 +365,7 @@ class TVarWithDep : public ObjectRef {
     data_ = make_object<TVarWithDepObj>(std::move(name), std::move(dep));
   }
 
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TVarWithDep, ObjectRef, 
TVarWithDepObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TVarWithDep, ObjectRef, 
TVarWithDepObj);
 };
 
 // Holder with one recursive-def field and one non-recursive-def field.
@@ -377,7 +377,7 @@ class TDefHolderObj : public Object {
 
   TDefHolderObj(TVarWithDep def_recursive, TVarWithDep def_non_recursive)
       : def_recursive(std::move(def_recursive)), 
def_non_recursive(std::move(def_non_recursive)) {}
-  explicit TDefHolderObj(UnsafeInit) {}
+  explicit TDefHolderObj(UnsafeInit tag) : def_recursive(tag), 
def_non_recursive(tag) {}
 
   static void RegisterReflection() {
     namespace refl = tvm::ffi::reflection;
@@ -398,7 +398,7 @@ class TDefHolder : public ObjectRef {
     data_ = make_object<TDefHolderObj>(std::move(def_recursive), 
std::move(def_non_recursive));
   }
 
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TDefHolder, ObjectRef, 
TDefHolderObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TDefHolder, ObjectRef, 
TDefHolderObj);
 };
 
 class TFuncObj : public Object {
@@ -444,7 +444,7 @@ class TFunc : public ObjectRef {
     data_ = make_object<TFuncObj>(params, body, comment);
   }
 
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TFunc, ObjectRef, TFuncObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TFunc, ObjectRef, TFuncObj);
 };
 
 class TCustomFuncObj : public Object {
@@ -495,7 +495,7 @@ class TCustomFunc : public ObjectRef {
     data_ = make_object<TCustomFuncObj>(params, body, comment);
   }
 
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TCustomFunc, ObjectRef, 
TCustomFuncObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TCustomFunc, ObjectRef, 
TCustomFuncObj);
 };
 
 // Test object with all POD field types to exercise serialization of every 
field kind.
@@ -552,7 +552,7 @@ class TAllFields : public ObjectRef {
                                        v_array, v_map);
   }
 
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TAllFields, ObjectRef, 
TAllFieldsObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TAllFields, ObjectRef, 
TAllFieldsObj);
 };
 
 // Test object with fields that have default values to test deserialization 
with missing fields
@@ -590,7 +590,7 @@ class TWithDefaults : public ObjectRef {
     data_ = make_object<TWithDefaultsObj>(required_val, default_int, 
default_str, default_bool);
   }
 
-  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NULLABLE(TWithDefaults, ObjectRef, 
TWithDefaultsObj);
+  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TWithDefaults, ObjectRef, 
TWithDefaultsObj);
 };
 
 }  // namespace testing

Reply via email to