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 fb8e1024 [REFACTOR] Type default structural mutation results as 
UnchangedOr<Any> (#773)
fb8e1024 is described below

commit fb8e102418e8219ca351e3213904f22721e91f69
Author: Tianqi Chen <[email protected]>
AuthorDate: Thu Sep 10 11:34:48 2026 -0400

    [REFACTOR] Type default structural mutation results as UnchangedOr<Any> 
(#773)
    
    Type the default structural mutation helpers as
    Expected<UnchangedOr<Any>>, matching the protocol already exposed by the
    public mutation entry points.
    
    The raw TVMFFIAny hook and vtable ABI remain unchanged. The registered
    wrapper now returns the strong unchanged-or-replacement type directly,
    with focused compile-time and runtime coverage.
    
    Validation:
    - 20 focused UnchangedOr/StructuralMutate/StructuralMap tests
    - 497 enabled CTest tests
    - formatting and repository lint checks
    - identical normalized hot/cold instruction and relocation listings for
    both default helpers under GCC 11.4.0 at -O3 before and after the change
---
 include/tvm/ffi/extra/structural_mutate.h | 17 ++++++++++-------
 src/ffi/extra/structural_mutate.cc        |  3 +--
 tests/cpp/extra/test_structural_mutate.cc | 12 ++++++++++--
 3 files changed, 21 insertions(+), 11 deletions(-)

diff --git a/include/tvm/ffi/extra/structural_mutate.h 
b/include/tvm/ffi/extra/structural_mutate.h
index 3186d035..cf980088 100644
--- a/include/tvm/ffi/extra/structural_mutate.h
+++ b/include/tvm/ffi/extra/structural_mutate.h
@@ -430,31 +430,34 @@ class StructuralMutatorObj : public Object {
    * \brief Apply the default structural mutation with copy-on-write behavior.
    *
    * \param value The value to mutate.
-   * \return The mutated value, or an Error if hook dispatch, copying, or 
field mutation failed.
+   * \return The replacement or unchanged marker, or an Error if hook 
dispatch, copying, or field
+   *         mutation failed.
    *
    * \note A registered ``__s_mutate__`` hook is dispatched before the 
reflected fallback. A
    *       FreeVar hook owns the definition-only remap policy for that type; 
the reflected fallback
    *       applies the same policy automatically.
    */
 
-  TVM_FFI_INLINE Expected<Any> DefaultMutateExpected(AnyView value) noexcept {
-    return 
details::ExpectedUnsafe::MoveFromTVMFFIAny<Any>(DefaultMutateRaw(value));
+  TVM_FFI_INLINE Expected<UnchangedOr<Any>> DefaultMutateExpected(AnyView 
value) noexcept {
+    return 
details::ExpectedUnsafe::MoveFromTVMFFIAny<UnchangedOr<Any>>(DefaultMutateRaw(value));
   }
 
   /*!
    * \brief Apply custom maybe-in-place mutation, or fall back to non-in-place 
mutation.
    *
    * \param value The borrowed value to mutate.
-   * \return The mutated owning value, or an Error if mutation failed. 
In-place changes
-   *         completed before an Error are not rolled back.
+   * \return The replacement or unchanged marker, or an Error if mutation 
failed. In-place
+   *         changes completed before an Error are not rolled back.
    *
    * \note In-place mutation is explicitly opt-in. A registered
    *       ``__s_maybe_inplace_mutate__`` hook may rely on its input being 
safe to mutate and owns
    *       any variable-remap handling. When the hook is absent, this method 
calls
    *       \ref DefaultMutateExpected.
    */
-  TVM_FFI_INLINE Expected<Any> DefaultMaybeInplaceMutateExpected(AnyView 
value) noexcept {
-    return 
details::ExpectedUnsafe::MoveFromTVMFFIAny<Any>(DefaultMaybeInplaceMutateRaw(value));
+  TVM_FFI_INLINE Expected<UnchangedOr<Any>> DefaultMaybeInplaceMutateExpected(
+      AnyView value) noexcept {
+    return details::ExpectedUnsafe::MoveFromTVMFFIAny<UnchangedOr<Any>>(
+        DefaultMaybeInplaceMutateRaw(value));
   }
 
   /*!
diff --git a/src/ffi/extra/structural_mutate.cc 
b/src/ffi/extra/structural_mutate.cc
index 9dff14f7..33bb72a6 100644
--- a/src/ffi/extra/structural_mutate.cc
+++ b/src/ffi/extra/structural_mutate.cc
@@ -381,8 +381,7 @@ TVM_FFI_STATIC_INIT_BLOCK() {
       .def_method("ffi.StructuralMutatorDefaultMutate",
                   [](const StructuralMutator& mutator, AnyView value) -> Any {
                     UnchangedOr<Any> result =
-                        
details::AnyUnsafe::MoveFromAnyAfterCheck<UnchangedOr<Any>>(
-                            
std::move(mutator->DefaultMutateExpected(value)).value());
+                        
std::move(mutator->DefaultMutateExpected(value)).value();
                     return std::move(result).ValueOrUnchanged(value);
                   })
       .def_method("ffi.StructuralMutatorVarRemapGet",
diff --git a/tests/cpp/extra/test_structural_mutate.cc 
b/tests/cpp/extra/test_structural_mutate.cc
index 78256cf5..f4c80a72 100644
--- a/tests/cpp/extra/test_structural_mutate.cc
+++ b/tests/cpp/extra/test_structural_mutate.cc
@@ -40,6 +40,14 @@ using namespace tvm::ffi::testing;
 using AnyArray = Array<Any>;
 using StringMap = Map<String, Any>;
 
+static_assert(std::is_same_v<decltype(std::declval<StructuralMutatorObj&>().DefaultMutateExpected(
+                                 std::declval<AnyView>())),
+                             Expected<UnchangedOr<Any>>>);
+static_assert(
+    
std::is_same_v<decltype(std::declval<StructuralMutatorObj&>().DefaultMaybeInplaceMutateExpected(
+                       std::declval<AnyView>())),
+                   Expected<UnchangedOr<Any>>>);
+
 // ---------------------------------------------------------------------------
 // Unchanged result protocol.
 // ---------------------------------------------------------------------------
@@ -272,13 +280,13 @@ class StructuralMapWithMutateCount : public 
StructuralMapEngineBase {
 
   const MutateCount& count() const { return count_; }
 
-  Expected<Any> DefaultMutateExpected(AnyView value) noexcept {
+  Expected<UnchangedOr<Any>> DefaultMutateExpected(AnyView value) noexcept {
     ++count_.value;
     ++count_.mutate_expected;
     return StructuralMapEngineBase::DefaultMutateExpected(value);
   }
 
-  Expected<Any> DefaultMaybeInplaceMutateExpected(AnyView value) noexcept {
+  Expected<UnchangedOr<Any>> DefaultMaybeInplaceMutateExpected(AnyView value) 
noexcept {
     ++count_.value;
     ++count_.maybe_inplace_expected;
     return StructuralMapEngineBase::DefaultMaybeInplaceMutateExpected(value);

Reply via email to