Files
Martin Vogel 793e0b6127 fix(rust): never let a std-typed receiver bind a same-named project method (#2053)
The Rust LSP types `root: &Path` and dispatches `root.join(..)` to
std.path.Path.join, a registered seed method with no graph node. Both
call resolvers treated "LSP row without a gbuf target" like "no LSP row"
and fell back to the textual registry, which bound the call to the only
project method named `join` (EvidenceTier::join via unique_name). Every
std/seeded-crate call whose leaf name a project method shares was
fabricated this way.

cbm_pipeline_rust_external_target() (lsp_resolve.h) recognises a Rust row
whose strategy emits a registered target (method/trait/deref/bound
dispatch, direct, ufcs, constructor) and whose QN lies outside the
project prefix. Project defs are registered under project-prefixed QNs, so
such a target is a std/core/alloc or seeded-crate symbol by construction.
pass_calls.c and pass_parallel.c skip the registry fallback for those rows
(in lockstep), and the parallel route-method fallback no longer turns a
skipped `map.get(k)` into a source->source self-call. Project-prefixed
rows, unknown-receiver rows and every other language are unchanged.

The call-expression receiver (`root.to_path_buf().join(..)`) needed type
facts: Path::join/to_path_buf/with_extension/with_file_name now return
PathBuf, PathBuf::as_path returns Path, and PathBuf derefs to Path.

Measured on BurntSushi/ripgrep @ 3fce3b5 (fresh index, two runs each,
byte-identical): CALLS 5371 -> 5014; 357 removed (307 suffix_match,
45 unique_name, 5 field_type_hint), 0 added, no lsp_* edge touched.
Removed samples are all std receivers (String::new -> State.new,
msg.contains -> ByteSet.contains, alts.push on a Vec -> TSeq.push).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-25 18:37:16 +02:00
..