Skip to content

Commit 95914bb

Browse files
Retain panic-only error enums in spec shaking v2 (#1852)
### What Add a `SpecShakingMarker` bound to `Env::panic_with_error` under `experimental_spec_shaking_v2` and call `I::spec_shaking_marker()` before erasing the user's type via `.into()`. Share the body with the non-feature build via a private `panic_with_error_inner` that takes the already-converted `internal::Error`. Add tests in `tests/spec_shaking_v2/`: - `with_panic_error` + `UsedPanicErrorEnum` — error enum used only via `panic_with_error!`; asserts the spec entry is retained. - `with_assert_error` + `UsedAssertErrorEnum` — same, via `assert_with_error!`. - `with_panic_raw_error` — passes a raw `soroban_sdk::Error` to `panic_with_error!`; regression check that the new bound does not break callers using the un-typed error. - `UnusedPubError` — a `#[contracterror]` enum referenced nowhere; asserts it is correctly shaken out of filtered entries. ### Why Closes #1817. Spec shaking v2 keeps a type's `contractspecv0` entry only if its `SpecShakingMarker::spec_shaking_marker()` survives DCE, and the only paths that call the marker are the v2 blanket impls of `IntoValForContractFn` (return values) and `TryFromValForContractFn` (parameters). A contract that defined a `#[contracterror]` enum and used it only via `panic_with_error!` or `assert_with_error!` — without ever appearing in a `Result<_, E>` return type — had no live caller for the marker, so the marker function was eliminated and the spec entry stripped from the WASM, even though the enum is part of the contract's observable error interface.
1 parent 4c4831e commit 95914bb

7 files changed

Lines changed: 3388 additions & 83 deletions

File tree

soroban-sdk/src/env.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,29 @@ impl Env {
290290
///
291291
/// Equivalent to `panic!`, but with an error value instead of a string.
292292
#[doc(hidden)]
293+
#[cfg(feature = "experimental_spec_shaking_v2")]
294+
#[inline(always)]
295+
pub fn panic_with_error<I>(&self, error: I) -> !
296+
where
297+
I: Into<internal::Error> + crate::SpecShakingMarker,
298+
{
299+
I::spec_shaking_marker();
300+
self.panic_with_error_inner(error.into())
301+
}
302+
303+
/// Panic with the given error.
304+
///
305+
/// Equivalent to `panic!`, but with an error value instead of a string.
306+
#[doc(hidden)]
307+
#[cfg(not(feature = "experimental_spec_shaking_v2"))]
293308
#[inline(always)]
294309
pub fn panic_with_error(&self, error: impl Into<internal::Error>) -> ! {
295-
_ = internal::Env::fail_with_error(self, error.into());
310+
self.panic_with_error_inner(error.into())
311+
}
312+
313+
#[inline(always)]
314+
fn panic_with_error_inner(&self, error: internal::Error) -> ! {
315+
_ = internal::Env::fail_with_error(self, error);
296316
#[cfg(target_family = "wasm")]
297317
core::arch::wasm32::unreachable();
298318
#[cfg(not(target_family = "wasm"))]

0 commit comments

Comments
 (0)