fix(resolver): Rust model cleanup: one-pass auto targets, in-scope own trait, IntoIterator items

Auto-discovered crate targets were matched per package, which was packages times files; they now take one pass after the package loop. A trait's own module always has it in scope. A project IntoIterator impl names its element in type Item, the same as Iterator. Separately, a field colliding with a method no longer marks the method as a signature twin, which had hidden about 120 genuine CALLS behind an unknown return type. Measured on meilisearch: CALLS 16,405 to 16,521, 3 lost, 119 gained.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
Martin Vogel committed 2026-11-01 16:09:44 +01:00
1 parent 4860aa1b74
commit 1a0f97b8f3
3 files changed
+16 -17

No files matched your search

+3 -5
View File
@@ -657,9 +657,8 @@ static rs_env_t rs_env_here(rs_walk_t *w) {
static bool rs_inst_binds_trait(rs_walk_t *w, rs_inst_t *inst, const rs_item_t *trait) {
const rs_mod_t *syn = inst->syn;
for (int i = 0; i < syn->nitems; i++)
if (syn->items[i] == trait)
return true;
if (trait->owner == syn)
return true;
for (const rs_use_t *use = syn->uses; use; use = use->next) {
if (!use->nseg || strcmp(use->segs[use->nseg - 1], trait->name) != 0)
continue;
@@ -2766,8 +2765,7 @@ static const rs_type_t *rs_element_of(rs_walk_t *w, const rs_type_t *iterable) {
} else if (type->kind == RT_ITEM) {
/* A project iterator names its element in `type Item = X`. */
for (const rs_impl_t *impl = type->item->impls; impl; impl = impl->next_self) {
if (!impl->trait_syn || impl->trait_syn->kind != RS_TS_PATH || !impl->trait_syn->nseg ||
strcmp(impl->trait_syn->segs[impl->trait_syn->nseg - 1], "Iterator") != 0)
if (!rs_iterator_trait_name(rs_tsyn_leaf(impl->trait_syn)))
continue;
for (int i = 0; i < impl->nassoc; i++) {
if (strcmp(impl->assoc_names[i], "Item") != 0)
+10 -3
View File
@@ -1561,10 +1561,15 @@ static void rs_package_crates(cbm_rust_project_t *project, rs_package_t *package
rs_join(arena, package->dir, package->build_path ? package->build_path : "build.rs");
if (build_rel)
(void)rs_crate_add(project, package, "build_script_build", build_rel, RS_CRATE_AUX);
}
/* src/bin, tests, benches and examples of whichever package owns each file. */
static void rs_auto_crates(cbm_rust_project_t *project) {
CBMArena *arena = &project->arena;
for (int i = 0; i < project->nfiles; i++) {
const char *rel = project->files[i]->rel, *rest = NULL;
if (rs_owning_package(project, rel) != package || !rs_under(rel, package->dir, &rest) ||
rs_target_listed(package, rel, arena))
rs_package_t *package = (rs_package_t *)rs_owning_package(project, rel);
if (!package || !package->name || !rs_under(rel, package->dir, &rest))
continue;
const char *name = NULL;
rs_crate_kind_t kind = RS_CRATE_AUX;
@@ -1574,7 +1579,8 @@ static void rs_package_crates(cbm_rust_project_t *project, rs_package_t *package
!(package->auto_benches && (name = rs_auto_target(arena, rest, "benches/"))) &&
!(package->auto_examples && (name = rs_auto_target(arena, rest, "examples/"))))
continue;
(void)rs_crate_add(project, package, rs_folded(arena, name), rel, kind);
if (!rs_target_listed(package, rel, arena))
(void)rs_crate_add(project, package, rs_folded(arena, name), rel, kind);
}
}
@@ -1686,6 +1692,7 @@ bool cbm_rust_project_seal(cbm_rust_project_t *project) {
if (package->has_package && package->name)
rs_package_crates(project, package);
}
rs_auto_crates(project);
if (!any_manifest) {
/* Without a manifest an entry file is an explicit rustc root. */
for (int i = 0; i < project->nfiles; i++) {
+3 -9
View File
@@ -503,15 +503,9 @@ TEST(javascript_import_table) {
}
/* ═══════════════════════════════════════════════════════════════════════════
* Rust — parse_rust_imports (text-based: strips "use "/";" from whole node).
*
* EXPECTED: basic and namespaced forms GREEN; grouped/braced forms may be RED
* because the whole `use std::io::{self, Write};` text becomes the module_path,
* so has_import("std::io") would still match as a substring — likely GREEN even
* for grouped. The alias form `use X as Y;` leaves "std::collections::HashMap as H"
* as module_path — has_import("std::collections::HashMap") would still match.
* So most forms should be GREEN at extraction. Graph-level zero edges are
* downstream.
* Rust — parse_rust_imports: one import per use-tree leaf, each with its whole
* path. `use std::io::{self, Write};` is "std::io" and "std::io::Write", and an
* alias changes the local name, never the path.
* ═══════════════════════════════════════════════════════════════════════════ */
static const import_case_t rust_cases[] = {