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 6118c1fe [FEAT] Support optional structural visit early returns (#790)
6118c1fe is described below

commit 6118c1febc8eba8c486ce2f639d4c95e118e8bba
Author: Tianqi Chen <[email protected]>
AuthorDate: Mon Sep 14 19:54:47 2026 -0400

    [FEAT] Support optional structural visit early returns (#790)
    
    Allow exception-first structural visitors to use
    `TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN` with `Optional<VisitInterrupt>`.
    `VisitReturnHelper` forwards optional interrupts directly and preserves
    the existing Expected return proxy for typed helpers and raw hooks.
    
    Includes a focused regression for optional continuation and interrupt
    propagation.
---
 include/tvm/ffi/extra/structural_visit.h | 41 ++++++++++++++++++++++++--------
 tests/cpp/extra/test_structural_visit.cc | 20 ++++++++++++++++
 2 files changed, 51 insertions(+), 10 deletions(-)

diff --git a/include/tvm/ffi/extra/structural_visit.h 
b/include/tvm/ffi/extra/structural_visit.h
index a1f1d55a..d6d2ced7 100644
--- a/include/tvm/ffi/extra/structural_visit.h
+++ b/include/tvm/ffi/extra/structural_visit.h
@@ -306,6 +306,27 @@ class StructuralVisitor : public ObjectRef {
 
 namespace details {
 
+/*!
+ * \brief Return an optional visit result directly or wrap an Expected for 
return conversion.
+ */
+template <typename T>
+TVM_FFI_INLINE auto VisitReturnHelper(T&& result) {
+  if constexpr (std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>,
+                               Optional<VisitInterrupt>>) {
+    return std::forward<T>(result);
+  } else {
+    return ExpectedReturnHelper(std::forward<T>(result));
+  }
+}
+
+/*!
+ * \brief Return true when \p result carries a traversal-stopping interrupt.
+ */
+TVM_FFI_INLINE bool StructuralVisitNeedEarlyReturn(
+    const Optional<VisitInterrupt>& result) noexcept {
+  return result.has_value();
+}
+
 /*!
  * \brief Return true when \p result already carries a traversal-stopping 
state.
  * \tparam T The Expected success type.
@@ -501,9 +522,9 @@ namespace details {
  * \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.
+ * and otherwise falls through. An ``Optional<VisitInterrupt>`` result is 
returned
+ * directly. An ``Expected`` result uses an rvalue-only proxy to select the 
return
+ * representation for raw ``TVMFFIAny`` hooks or typed ``Expected`` helpers.
  *
  * 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
@@ -521,13 +542,13 @@ namespace details {
  *
  * \param Result An expression yielding the descent result to inspect.
  */
-#define TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN(Result)                             
    \
-  do {                                                                         
    \
-    auto&& tvm_ffi_res_ = (Result);                                            
    \
-    if (TVM_FFI_PREDICT_FALSE(                                                 
    \
-            
::tvm::ffi::details::StructuralVisitNeedEarlyReturn(tvm_ffi_res_))) {  \
-      return 
::tvm::ffi::details::ExpectedReturnHelper(::std::move(tvm_ffi_res_)); \
-    }                                                                          
    \
+#define TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN(Result)                             
   \
+  do {                                                                         
   \
+    auto&& tvm_ffi_res_ = (Result);                                            
   \
+    if (TVM_FFI_PREDICT_FALSE(                                                 
   \
+            
::tvm::ffi::details::StructuralVisitNeedEarlyReturn(tvm_ffi_res_))) { \
+      return 
::tvm::ffi::details::VisitReturnHelper(::std::move(tvm_ffi_res_));   \
+    }                                                                          
   \
   } while (0)
 
 }  // namespace details
diff --git a/tests/cpp/extra/test_structural_visit.cc 
b/tests/cpp/extra/test_structural_visit.cc
index 7c015053..b638c128 100644
--- a/tests/cpp/extra/test_structural_visit.cc
+++ b/tests/cpp/extra/test_structural_visit.cc
@@ -676,6 +676,26 @@ TEST(StructuralVisitor, WalkAnyFallback) {
 // StructuralVisit behavior.
 // ---------------------------------------------------------------------------
 
+TEST(StructuralVisit, OptionalEarlyReturn) {
+  bool continued = false;
+  auto visit = [&](Optional<VisitInterrupt> result) -> 
Optional<VisitInterrupt> {
+    TVM_FFI_S_VISIT_MAYBE_EARLY_RETURN(result);
+    continued = true;
+    return std::nullopt;
+  };
+
+  EXPECT_FALSE(visit(std::nullopt).has_value());
+  EXPECT_TRUE(continued);
+
+  continued = false;
+  VisitInterrupt interrupt(String("stop"));
+  Optional<VisitInterrupt> result = visit(interrupt);
+  ASSERT_TRUE(result.has_value());
+  EXPECT_TRUE(result.value().same_as(interrupt));
+  EXPECT_EQ(result.value()->value.cast<String>(), "stop");
+  EXPECT_FALSE(continued);
+}
+
 TEST(StructuralVisit, CallbackDrivenTraversal) {
   TVarWithDep lhs("lhs", TVarWithDep("pruned-dependency"));
   TVarWithDep stop("stop");

Reply via email to