Skip to content

Analyze the impl body a trait-dispatched call resolves to - #237

Draft
coord-e wants to merge 1 commit into
mainfrom
claude/issue-190-fix-4m1wjh
Draft

Analyze the impl body a trait-dispatched call resolves to#237
coord-e wants to merge 1 commit into
mainfrom
claude/issue-190-fix-4m1wjh

Conversation

@coord-e

@coord-e coord-e commented Aug 20, 2026

Copy link
Copy Markdown
Owner

Closes #190.

A generic impl of a trait method is registered as a deferred def, whose body is analyzed only when its type is asked for. A call dispatched through the trait takes its type from the trait method instead — that is where the spec is annotated — so nothing ever asked for the impl method's type: its body went unchecked while every caller assumed the trait's ensures, and an always-panicking program verified as safe.

Changes

  • src/analyze/basic_block.rs: when fn_def_ty answers from the registered callee type, also analyze the body the call resolves to (analyze_resolved_impl_body, a no-op unless resolution lands on a different def). The impl method's expected type is the trait's spec, so running its body against that type is the missing check.
  • src/analyze/local_def.rs: trait_item_ty instantiates the impl's trait ref with the instantiation being analyzed rather than the identity one, so the trait spec is translated at concrete types. Analyzer::new now defaults generic_args to the identity instantiation, which keeps that instantiation well-formed for a def whose generic arguments were never set.
  • tests/ui/{pass,fail}/trait_generic_impl.rs: a generic impl of a spec'd trait method, with the ensures satisfied and violated.

Verification

cargo test (328 UI tests), cargo fmt --all -- --check and cargo clippy -- -D warnings all pass, with Z3 5.0.0 and the CI-pinned COAR image.

Beyond the added test pair, checked by hand: the issue's reproduction and its assert!(false)-with-unused-result variant are both rejected; a satisfied body, a bounded impl<T: Base>, and two instantiations (W<i32> and W<bool>) all verify, and each is rejected once its body breaks the postcondition.


Generated by Claude Code

A generic impl of a trait method is registered as a deferred def, whose body
is analyzed only when its type is asked for. A call dispatched through the
trait takes its type from the trait method instead, where the spec is
annotated, so nothing ever asked for the impl method's type: its body went
unchecked while every caller assumed the trait's `ensures`.

Ask for it at the call site, and instantiate the trait ref in `trait_item_ty`
with the analyzed instantiation so the impl method's expected type is the
trait's spec for that instantiation rather than one carrying the impl's own
type parameters.

Closes #190

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PvA5f69BEE7xw9MR6SLeMX
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants