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

Seven-Streams 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 1a2e530f [FEAT][Rust] Let a static_init_block! end without Ok(()) 
(#883)
1a2e530f is described below

commit 1a2e530fa68f5a251e3dea8b24d2a7ba19614a14
Author: Linzhang Li <[email protected]>
AuthorDate: Tue Oct 27 20:33:20 2026 -0400

    [FEAT][Rust] Let a static_init_block! end without Ok(()) (#883)
    
    ## Summary
    
    The body of a `tvm_ffi::static_init_block!` (#882) was the body of a
    closure that returns
    `Result<()>`, so every block ended in an `Ok(())` that carried no
    information:
    
    ```rust
    tvm_ffi::static_init_block! {
        Function::register_global_typed("my_ext.add_one", add_one, "Add one to 
an integer.")?;
        Ok(())
    }
    ```
    
    This PR lets a block end without it, as C++ `TVM_FFI_STATIC_INIT_BLOCK`
    does:
    
    ```rust
    tvm_ffi::static_init_block! {
        Function::register_global_typed("my_ext.add_one", add_one, "Add one to 
an integer.")?;
    }
    ```
---
 rust/tvm-ffi/examples/static_init.rs   |  1 -
 rust/tvm-ffi/src/static_init.rs        | 61 +++++++++++++++++++++++++++++++---
 rust/tvm-ffi/tests/test_static_init.rs | 31 +++++++++++++++--
 3 files changed, 85 insertions(+), 8 deletions(-)

diff --git a/rust/tvm-ffi/examples/static_init.rs 
b/rust/tvm-ffi/examples/static_init.rs
index eb49faba..fbc46fbf 100644
--- a/rust/tvm-ffi/examples/static_init.rs
+++ b/rust/tvm-ffi/examples/static_init.rs
@@ -29,7 +29,6 @@ fn add_one(x: i64) -> Result<i64> {
 
 tvm_ffi::static_init_block! {
     Function::register_global_typed("static_init_example.add_one", add_one, 
"Add one to an integer.")?;
-    Ok(())
 }
 
 // The errors of the blocks that failed when the library loaded, which Python 
raises as
diff --git a/rust/tvm-ffi/src/static_init.rs b/rust/tvm-ffi/src/static_init.rs
index 323fad21..6b5a631a 100644
--- a/rust/tvm-ffi/src/static_init.rs
+++ b/rust/tvm-ffi/src/static_init.rs
@@ -36,8 +36,10 @@ use crate::{Any, Error, Function, Result, INTERNAL_ERROR};
 pub use linkme;
 
 /// Run code when the program or library that holds it loads, as a C++
-/// `TVM_FFI_STATIC_INIT_BLOCK` does. The body is a block that returns 
[`Result<()>`](crate::Result):
-/// it registers what the library defines, such as global functions, and stops 
at its first error.
+/// `TVM_FFI_STATIC_INIT_BLOCK` does. The body is the body of a function that 
returns
+/// [`Result<()>`](crate::Result): it registers what the library defines, such 
as global functions,
+/// and stops at its first error, which `?` returns. A body whose statements 
all end in `;` returns
+/// `Ok(())`; one that ends in an expression returns it, a `Result<()>`.
 ///
 /// ```
 /// use tvm_ffi::{Function, Result};
@@ -48,7 +50,6 @@ pub use linkme;
 ///
 /// tvm_ffi::static_init_block! {
 ///     Function::register_global_typed("my_ext.add_one", add_one, "Add one to 
an integer.")?;
-///     Ok(())
 /// }
 ///
 /// // Registered when the program loaded.
@@ -88,8 +89,14 @@ macro_rules! static_init_block {
                         None => "",
                     },
                     stringify!($($body)*),
-                    || -> $crate::Result<()> { $($body)* },
+                    __tvm_ffi_static_init_block_body,
                 );
+            // A function item rather than a closure, to carry the attribute: 
a body that diverges,
+            // such as one that panics, makes the conversion of its value 
unreachable.
+            #[allow(unreachable_code)]
+            fn __tvm_ffi_static_init_block_body() -> $crate::Result<()> {
+                
$crate::static_init::IntoStaticInitResult::into_static_init_result({ $($body)* 
})
+            }
             #[used]
             #[cfg_attr(target_os = "linux", link_section = ".init_array")]
             #[cfg_attr(target_os = "macos", link_section = 
"__DATA,__mod_init_func")]
@@ -99,6 +106,52 @@ macro_rules! static_init_block {
     };
 }
 
+/// The value of the body of a 
[`static_init_block!`](crate::static_init_block), converted to the
+/// outcome of the block: `()`, of a body whose statements all end in `;`, is 
`Ok(())`, a
+/// [`Result<()>`](crate::Result) is itself, and a body that diverges, as one 
that panics or ends
+/// in `return`, has no value to convert.
+#[doc(hidden)]
+#[diagnostic::on_unimplemented(
+    message = "a static init block returns `Result<()>`, not `{Self}`",
+    label = "the value of the block",
+    note = "end the last statement of the block with `;`, or return a 
`Result<()>`"
+)]
+pub trait IntoStaticInitResult {
+    fn into_static_init_result(self) -> Result<()>;
+}
+
+impl IntoStaticInitResult for () {
+    fn into_static_init_result(self) -> Result<()> {
+        Ok(())
+    }
+}
+
+impl IntoStaticInitResult for Result<()> {
+    fn into_static_init_result(self) -> Result<()> {
+        self
+    }
+}
+
+/// The never type `!`, which stable Rust names only as the return type of a 
function pointer.
+/// The value of a body that diverges is `!`, or `()` where an edition before 
2024 falls back to it.
+#[doc(hidden)]
+pub trait FnOutput {
+    type Output;
+}
+
+impl<T> FnOutput for fn() -> T {
+    type Output = T;
+}
+
+#[doc(hidden)]
+pub type Never = <fn() -> ! as FnOutput>::Output;
+
+impl IntoStaticInitResult for Never {
+    fn into_static_init_result(self) -> Result<()> {
+        self
+    }
+}
+
 /// A [`static_init_block!`](crate::static_init_block), gathered at link time.
 #[doc(hidden)]
 pub struct StaticInitBlock {
diff --git a/rust/tvm-ffi/tests/test_static_init.rs 
b/rust/tvm-ffi/tests/test_static_init.rs
index ec0122e8..f1e4d460 100644
--- a/rust/tvm-ffi/tests/test_static_init.rs
+++ b/rust/tvm-ffi/tests/test_static_init.rs
@@ -31,9 +31,9 @@ fn add_one(x: i64) -> Result<i64> {
 
 tvm_ffi::static_init_block! {
     Function::register_global_typed("test_static_init.add_one", add_one, "Add 
one.")?;
-    Ok(())
 }
 
+// A block may also end in the `Result<()>` it returns.
 mod elsewhere {
     use super::*;
 
@@ -43,6 +43,28 @@ mod elsewhere {
     }
 }
 
+// A block that returns early, and one that ends in `return`, which `!` types.
+mod returning {
+    use super::*;
+
+    fn body() -> Result<i64> {
+        Ok(8)
+    }
+
+    tvm_ffi::static_init_block! {
+        Function::register_global_typed("test_static_init.returning", body, 
"")?;
+        if Function::get_global("test_static_init.returning").is_ok() {
+            return Ok(());
+        }
+        Function::register_global_typed("test_static_init.not_reached", body, 
"")?;
+    }
+
+    tvm_ffi::static_init_block! {
+        Function::register_global_typed("test_static_init.returned", body, 
"")?;
+        return Ok(())
+    }
+}
+
 // Blocks that fail, which `run_static_init_blocks` reports together while it 
runs the others: a
 // block stops at its first error, and a panic is an error.
 mod failing {
@@ -52,7 +74,6 @@ mod failing {
         Function::register_global_typed("test_static_init.twice", add_one, 
"")?;
         Function::register_global_typed("test_static_init.twice", add_one, 
"")?;
         Function::register_global_typed("test_static_init.after_broken", 
add_one, "")?;
-        Ok(())
     }
 
     tvm_ffi::static_init_block! {
@@ -76,6 +97,10 @@ fn blocks_run_when_the_program_loads() {
         2
     );
     assert_eq!(call_i64("test_static_init.elsewhere").unwrap(), 7);
+    // A block's own items are in scope, not shadowed by those of the macro.
+    assert_eq!(call_i64("test_static_init.returning").unwrap(), 8);
+    assert_eq!(call_i64("test_static_init.returned").unwrap(), 8);
+    assert!(Function::get_global("test_static_init.not_reached").is_err());
 
     // The block that failed registered what came before its error, and 
stopped there.
     assert!(Function::get_global("test_static_init.twice").is_ok());
@@ -86,7 +111,7 @@ fn blocks_run_when_the_program_loads() {
         .iter()
         .filter(|block| block.identity().starts_with("test_static_init"))
         .count();
-    assert_eq!(blocks, 5);
+    assert_eq!(blocks, 7);
 }
 
 #[test]

Reply via email to