Skip to content

Check borrowed inputs on the declared signature - #19

Merged
tanglearncode merged 1 commit into
mainfrom
fix/next-solver-signature-check
Sep 13, 2026
Merged

tanglearncode merged 1 commit into
mainfrom
fix/next-solver-signature-check

Conversation

@tanglearncode

@tanglearncode tanglearncode commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Fixes mock! and replace! on nightly Rust.

Since nightly-2026-08-22, signatures with borrowed inputs such as fn(&str) fail with "higher-ranked lifetime error". rust-lang/rust#160619 turned on the new trait solver, and the old check relied on lifetimes to pick a trait impl, which the new solver no longer does.

The check now looks at the declared signature: each borrowed input must accept a borrow of a local value. Stable and nightly behave the same.

One change for users: a function that only takes 'static borrows now needs unsafe fn(&'static str) instead of fn(&'static str).

Tested on stable, beta and nightly with both solvers: https://github.com/XTSoftwareLabs/shimforge/actions/runs/34768702371

Since nightly-2026-08-22, mock! and replace! no longer compile for safe
signatures with borrowed inputs, such as mock!(session, env::var_os::<&str>,
fn(&str) -> Option<OsString>). rustc reports "higher-ranked lifetime error"
from the probe traits in macros/src/signature.rs. cargo-bisect-rustc points at
rust-lang/rust#160619, which enables the next-generation trait solver by
default on nightly; stable 1.98 and beta 1.99 still compile the code, and
-Znext-solver=coherence restores it on nightly.

The probes asked whether the source function accepts any lifetime for an
input, and relied on that answer to pick a trait impl: if it did, the declared
signature had to accept any lifetime too, and otherwise a fallback impl
accepted a static-only source. The next solver ignores lifetimes when it picks
an impl, so it chose the strict impl for every source. Proving that impl then
fails for static-only sources, and for generic sources such as var_os::<&str>,
whose input lifetime is an inference variable that cannot satisfy a
higher-ranked bound.

The probes now inspect the declared function pointer instead. The impl is
chosen only by whether an input is a shared or mutable reference, and its
method then requires that input to accept any lifetime. No lifetime decides
which impl applies, so both solvers treat the code the same way, and the
declared pointer has no inference variables to trip over.

This is stricter than before: a safe signature can no longer declare a
'static borrowed input, even for a function that only accepts 'static borrows.
Such functions are declared with an unsafe fn signature, which is checked only
as a function pointer, as extern and unsafe signatures already are. The
static_length test now uses that form, and the mock! and replace! docs say so.
Declaring 'static for a source that accepts any lifetime stays rejected,
including through a type alias and for mutable borrows.
@tanglearncode
tanglearncode merged commit 4e4bd28 into main Sep 13, 2026
7 checks passed
@tanglearncode
tanglearncode deleted the fix/next-solver-signature-check branch September 14, 2026 03:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant