Skip to content

Code Analysis Rust Trait Impls

Tu Shaokun edited this page Nov 8, 2026 · 5 revisions

Rust trait impl call evidence

Validated in Draft, not Labs: #1286, final head 7d228fb5c849c370b09ae2d1a2d315b1c9e01ee4, targets the #1283 source branch codex/code-analysis-labs-integration-review-20261108. No merge, approval, release, installation or labs/code-analysis update. Validation commit 38f82efd2 passed run 42467009838 in full. Final head 7d228fb5c (target-column scoring) passed run 42469411573 on attempt 1 with 19 successful jobs; only the two deploy jobs were skipped.

Question

A maintainer changed one method inside impl Trait for Type. Which calls definitely point to that implementation, which only prove use of the trait method, and which remain unknown?

Model

Rust rust-source-direct-v5 / adapter revision 5 captures local trait declarations and impl-method edges.

  • <Type as Trait>::method(...) and unambiguous concrete receivers resolve to the unique captured impl (rust-trait-impl).
  • T: Trait, dyn Trait, Trait::method and generic paths resolve to the trait method declaration only (rust-trait-method-candidate).
  • Change questions add traitCandidates with runtimeTarget: "not-determined", separate from direct knownReferences.
  • A concrete receiver implementing several same-named traits stays unresolved rather than choosing by name; an inherent method with the same name blocks trait selection.

Fixed source answer

Expectations were frozen in benchmarks/code-analysis-rust-trait-change/source-first.json before either CLI ran. Profile: rustc/cargo 1.89.0, aarch64-apple-darwin, default features, tests excluded, root module only. Call columns are derived from the frozen source text.

The bytes count is reported under both scopes:

Project Change Definite in call inventory Definite in source answer Trait-only candidate Wrong
tokio-rs/bytes d38faf7→c08f876 BytesMut::put body 2/2 2/3 0 0
rust-lang/log 761461a→db14597 both KVs::into_kvs impls 0/0 0/0 1/1 0

The source-answer miss is src/buf/buf_impl.rs:2374, a definite call inside a Buf default-method body that the current call inventory does not scan. It is a retained product gap, not a wrong target or a trait-resolution miss.

Each returned result is graded on call range, target declaration file:line:column, owning trait and, when determined, implementation type:

Result Call range Target declaration Owning trait Impl type Status
bytes ret.put(&mut self.a) src/buf/chain.rs:184:13-184:33 src/bytes_mut.rs:1300:5 BufMut BytesMut correct
bytes ret.put((&mut self.b).take(...)) src/buf/chain.rs:185:13-185:53 src/bytes_mut.rs:1300:5 BufMut BytesMut correct
log kvs.into_kvs() src/__private_api.rs:101:9-101:23 src/__private_api.rs:17:12 KVs unverified correct

Per-call CLI targets expose no end position, so target-end stays unverified for all three rather than being inferred from another record. Baseline 0c81af0e reports 0 known references and no candidate coverage. The log result proves KVs::into_kvs use but not the runtime impl, so its implementation type stays unverified.

Example: BytesMut::put at src/bytes_mut.rs:1300 changed; ret.put(&mut self.a) at src/buf/chain.rs:184 reaches that impl because ret is a local crate::BytesMut.

The log reference-self impl (src/__private_api.rs:25) is head-only because its qualname embeds the changed Key token text; its head traitCandidates still contain src/__private_api.rs:101.

Controls and independent comparison

  • Fixture: two traits with the same method, two types implementing one trait, explicit qualification, T: Trait, &dyn Trait, and an ambiguous concrete receiver.
  • Fixture negative control swaps <A as Left>::act to Right::act; scoring must fail on declaration range. The runner exits nonzero otherwise.
  • Real-result same-named wrong target: replace src/buf/chain.rs:184's target with src/buf/buf_mut.rs:202 (BufMut::put). The scorer rejects it with declaration-range and implementation-type.
  • Real-result same-line different call: replace src/buf/chain.rs:185's range with the nested .take(...) call at 185:21-185:52, keeping the target. The scorer rejects it with call-range only.
  • Real-result target column only: change src/buf/chain.rs:184's target column from 5 to 6, keeping call range, target file, line, trait and implementation type fixed. The scorer rejects it with declaration-range only.
  • rust-analyzer 1.89.0 Go to Definition: both bytes calls go to src/bytes_mut.rs:1300; the log generic call goes to the trait declaration src/__private_api.rs:17, not an impl.
  • Unpacked archify.zip SHA256 5c9687d0fb0fe1ade96defa923e6f7d1c7eb2822d29b12b647b8d9b1d31e35e1 reproduces the source run exactly. Rebuilding at 38f82efd2 with Node 22.23.3 produced the identical hash.

CI record

Run 42465518271 at 3a1ac77a first failed in full-regression (2) because the self-bootstrap test's spawnSync hit its 20 s limit (ETIMEDOUT, assertion null !== 0); no byte or schema comparison ran. The same commit passed on rerun, including the downstream test (22) gate. Validation commit 38f82efd2 passed run 42467009838 in full. Intermediate report commit 0e1fe6f4c passed run 42467648337 on attempt 2 after one browser layout flake. Final head 7d228fb5c passed run 42469411573 on attempt 1 with 19 successful jobs. The module-suite timeout cause and the intermediate browser first-attempt cause remain unknown. The failure excerpt is in benchmarks/code-analysis-rust-trait-change/evidence/ci-full-regression-2-attempt1.txt.

Limits

Local captured traits only; external, macro-generated, blanket and supertrait impls remain unknown. Receiver typing covers parameters, local let initializers and literal/constructor paths; fields, chained calls and reassigned locals remain unknown. Trait default bodies are outside the call inventory, including src/buf/buf_impl.rs:2374. Same-type same-method impls in different traits share a qualname slot (duplicate-slot) while their head candidates stay inspectable. Source navigation is not compiler, runtime or complete-impact proof.

Reproduction: benchmarks/code-analysis-rust-trait-change/run.py with both pinned sample pairs, the baseline checkout and the source or unpacked ZIP CLI; it reports per-item results, dual bytes scopes and real-result controls. audit.py reproduces the language-server rows. evidence/ holds the normalized run, ZIP, CI and audit summaries.

Decision input: keep improving the built-in Rust source model. Explicit and uniquely typed concrete calls can be separated from trait-only candidates without adopting rust-analyzer as a product dependency.

Clone this wiki locally