Conversation
… traits
visit_item_trait_mut() unconditionally called visit_trait_items_prefilter(),
which clones every trait method into a shadow VERUS_SPEC__<name> item (used
to carry requires/ensures separately from the body for verification). This
ran even for #[verifier::external] traits, which are never verified and
whose items are entirely ignored by VIR construction anyway.
Beyond being wasted work, the generated clone always gets a default body
({ ::builtin::no_method_body() }), unlike the original declaration. For a
method shaped like `fn f() -> Self;` (no receiver, Self-typed return, no
body), that's a real behavioral difference: a bodyless trait method with an
unsized return type compiles fine in real Rust, but the same signature WITH
a body requires an explicit `Self: Sized` bound (confirmed directly against
plain rustc). split_trait_method() already has a special case adding that
bound for a by-value `self` receiver, but not for this shape, so external
traits with this pattern failed to compile with a spurious E0277 even
though the user's own declaration was fine as written.
Fix: skip the trait-item prefilter/split entirely when the trait itself is
marked #[verifier::external] (mirrors the existing is_external() guard used
for unerased-proxy generation in unerased_proxies.rs).
Verified:
- new regression test issue_783_no_verus_spec_split_for_external_trait in
rust_verify_test/tests/external_traits.rs (external trait with
`fn f() -> Self;`); confirmed it fails with E0277 without the fix
(git stash) and passes with it
- vstd still verifies fully (2045 verified, 0 errors), unchanged
- full external_traits.rs suite passes (39/39)
- full traits.rs suite passes (214 passed, 0 failed, 2 ignored, matching
the pre-existing baseline)
Fixes verus-lang#783.
Assisted-by: Claude Code:claude-sonnet-5
Chris-Hawblitzel
self-requested a review
September 3, 2026 18:21
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #783.
visit_item_trait_mut()unconditionally calledvisit_trait_items_prefilter(), which clones every trait method into a shadowVERUS_SPEC__<name>item (used to carry requires/ensures separately from the body for verification). This even applies to#[verifier::external]traits, which are never verified and whose items are entirely ignored by VIR construction anyway.The generated clone always gets a default body (
{ ::builtin::no_method_body() }), unlike the original declaration. For a method shaped likefn f() -> Self;(no receiver, Self-typed return, no body), that's a real behavioral difference: a bodyless trait method with an unsized return type compiles fine in real Rust, but the same signature WITH a body requires an explicitSelf: Sizedbound (confirmed directly against plain rustc).split_trait_method()already has a special case that adds that bound for a by-valueselfreceiver, but not for this shape, so external traits with this pattern failed to compile with a spurious E0277, even though the user's own declaration was fine as written.Fix: skip the trait-item prefilter/split entirely when the trait itself is marked
#[verifier::external](mirrors the existingis_external()guard used for unerased-proxy generation inunerased_proxies.rs).Verified:
issue_783_no_verus_spec_split_for_external_traitinrust_verify_test/tests/external_traits.rs(external trait withfn f() -> Self;); confirmed it fails with E0277 without the fix and passes with itexternal_traits.rssuite passes (39/39)traits.rssuite passes (214 passed, 0 failed, 2 ignored, matching the pre-existing baseline)Assisted-by: Claude Code:claude-sonnet-5
By submitting this pull request, I confirm that my contribution is made under the terms of the MIT license.