From ef95be936d83c013a5ff75182ab1147e7fe74b75 Mon Sep 17 00:00:00 2001 From: tqchen Date: Sun, 6 Sep 2026 13:47:09 +0000 Subject: [PATCH] [REFACTOR][EXTRA] Add TVM_FFI_S_VISIT_RETURN_NONE for visit hook tails A visit hook ends by returning "no interrupt", which every hook spells out by hand as MoveToTVMFFIAny(Expected>(std::nullopt)). That puts the Expected storage representation in every hook body, including downstream ones outside this repository. Add the terminal counterpart to TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN, going through the same MaybeReturnHelper proxy so it works from a raw TVMFFIAny hook and a typed helper alike. Adopt it in the container hooks, and document both visit macros with the canonical hook shape, matching how TVM_FFI_S_MUTATE_ASSIGN_OR_RETURN is already documented. --- include/tvm/ffi/extra/structural_visit.h | 41 +++++++++++++++++++++--- src/ffi/extra/structural_visit.cc | 4 +-- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/include/tvm/ffi/extra/structural_visit.h b/include/tvm/ffi/extra/structural_visit.h index b8d419485..f2f7e830b 100644 --- a/include/tvm/ffi/extra/structural_visit.h +++ b/include/tvm/ffi/extra/structural_visit.h @@ -487,9 +487,31 @@ enum class WalkOrder : int32_t { namespace details { -/// \cond Doxygen_Suppress -// Return from the current raw or same-T Expected visit function if Result stops traversal. -// The rvalue-only proxy lets the enclosing return type select the representation. +/*! + * \brief Return from a visit hook if \p Result stops traversal. + * + * Propagates an ``Error`` or a ``VisitInterrupt`` out of the enclosing function + * and otherwise falls through. Works from a raw ``TVMFFIAny`` hook and from a + * typed ``Expected`` helper alike; the rvalue-only proxy lets the return type + * select the representation. + * + * A registered ``__s_visit__`` hook is one line per traversed field followed by + * the terminal return. A field skipped on purpose is guarded by a condition and + * carries a ``// skips:`` note saying why. + * + * \code{.cpp} + * TVMFFIAny FooVisit(StructuralVisitorObj* visitor, AnyView value) noexcept { + * const FooNode* self = + * details::AnyUnsafe::RawObjectPtrFromAnyViewAfterCheck(value); + * TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN(visitor->VisitExpected(self->a)); + * TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN(visitor->VisitExpected(self->b)); + * TVM_FFI_S_VISIT_RETURN_NONE(); + * } + * \endcode + * + * \param Result An expression yielding the descent result to inspect. + * \sa TVM_FFI_S_VISIT_RETURN_NONE + */ #define TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN(Result) \ do { \ auto&& tvm_ffi_res_ = (Result); \ @@ -498,7 +520,18 @@ namespace details { return ::tvm::ffi::details::MaybeReturnHelper(::std::move(tvm_ffi_res_)); \ } \ } while (0) -/// \endcond + +/*! + * \brief Return the completed result -- no interrupt -- from a visit hook. + * + * Terminal statement of a hook that traversed every field it intends to. Works + * from a raw ``TVMFFIAny`` hook and a typed ``Expected`` helper alike. + * + * \sa TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN + */ +#define TVM_FFI_S_VISIT_RETURN_NONE() \ + return ::tvm::ffi::details::MaybeReturnHelper( \ + ::tvm::ffi::Expected<::tvm::ffi::Optional<::tvm::ffi::VisitInterrupt>>(::std::nullopt)) } // namespace details diff --git a/src/ffi/extra/structural_visit.cc b/src/ffi/extra/structural_visit.cc index e1f73a5f4..2549b670f 100644 --- a/src/ffi/extra/structural_visit.cc +++ b/src/ffi/extra/structural_visit.cc @@ -115,7 +115,7 @@ TVMFFIAny VisitSeqContainer(StructuralVisitorObj* visitor, const SeqBaseObj* sel for (const Any& item : *self) { TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN(visitor->VisitExpected(item)); } - return ExpectedUnsafe::MoveToTVMFFIAny(Expected>(std::nullopt)); + TVM_FFI_S_VISIT_RETURN_NONE(); } /*! \brief Visit values in a map container while treating keys as structural anchors. */ @@ -123,7 +123,7 @@ TVMFFIAny VisitMapContainer(StructuralVisitorObj* visitor, const MapBaseObj* sel for (const auto& kv : *self) { TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN(visitor->VisitExpected(kv.second)); } - return ExpectedUnsafe::MoveToTVMFFIAny(Expected>(std::nullopt)); + TVM_FFI_S_VISIT_RETURN_NONE(); } /*! \brief Structural visit hook for ArrayObj. */