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);