Skip to content

fix(rust): resolve use super::* callees in #[path] modules - #1892

Closed
seonghobae wants to merge 1 commit into
colbymchenry:mainfrom
seonghobae:fix/rust-path-super-glob-resolution
Closed

seonghobae wants to merge 1 commit into
colbymchenry:mainfrom
seonghobae:fix/rust-path-super-glob-resolution

Conversation

@seonghobae

Copy link
Copy Markdown

Summary

  • Map #[path = "..."] mod name; inclusions to their declaring parent module file so super in an included file refers to the lexical parent, not a path derived from the included file's disk location (Rust Reference, Modules / Paths).
  • Extract Rust use declarations (including use super::* globs) into import mappings and resolve bare callees through the imported module before global name-matching.
  • Add regression test and scripts/repro-rust-path-callee.sh reproducing CodeGraph: same-name callee over-approximation for scaling test module imports ContextualWisdomLab/fast-mlsirm#1837 (same-name predict_rating_multi in two crates; #[path] test module with use super::* must call the parent scaling.rs symbol, not the decoy in lib.rs).

Test plan

  • npx vitest run __tests__/rust-path-super-glob.test.ts
  • npx vitest run __tests__/rust-self-owner.test.ts (no regression)
  • ./scripts/repro-rust-path-callee.sh

Context

Fixes false callee edge reported in ContextualWisdomLab/fast-mlsirm#1837 where CodeGraph 1.2.0 linked pr_elom_rowmean → crates/fast-mlsirm-py/src/lib.rs:predict_rating_multi instead of crates/mlsirm-core/src/scaling.rs:predict_rating_multi.

Made with Cursor

Map #[path] module inclusions to their declaring parent so bare names
imported via `use super::*` resolve through the lexical parent module
instead of global same-name matching across workspace crates.

Co-authored-by: Cursor <cursoragent@cursor.com>
@seonghobae

Copy link
Copy Markdown
Author

Maintainer note: this PR is still blocked on required review (REVIEW_REQUIRED) with no CI check-runs yet on head ff944a41. Local verification previously green per PR test plan (vitest + scripts/repro-rust-path-callee.sh). Happy to rebase or address any review feedback promptly.

colbymchenry added a commit that referenced this pull request Oct 30, 2026
…ares it (#3064)

A Rust module loaded with `#[path = "…"]` was found by its file's directory:
fast-mlsirm's `#[path = "../../../tests/unit/scaling_tests.rs"] mod tests;`
in `crates/core/src/scaling.rs` made `tests/unit/scaling_tests.rs`'s
`use super::*` walk to a `tests/unit` module that doesn't exist, so its
`predict_rating_multi(1)` linked to nothing, or to a same-named function of
another crate; its `crate::` had no crate, and the parent's private items
looked out of its reach. From the declaring side, a path through such a
module (`utils::mock_event(…)` under `#[path = "./utils.rs"] mod utils;`)
reached nothing.

The fix reads each file's `#[path]` declarations as the Rust Reference
reads the attribute (from the declaring file's directory, or inside an
inline `mod` from that module's own; a path that leaves the project, by
escapesRoot, or that a `cfg_attr` sets, names no file):
- rustSubmodule: a module the module declares once with a `#[path]` is
  the file it names, whatever else loads that file too (a helper several
  tests load is each test's); cfg alternatives that name a file each stay
  unknown, and a path's 2015 crate-root fallback no longer reaches past
  such a module to a namesake at the crate root.
- rustPathClaim: a file the regular rules don't place is the module of the
  one `#[path]` declaration that loads it, if exactly one does. Placed
  (rustPlacedByName) are crate roots, files with a `fn main` or
  `#![no_main]` of their own (trybuild cases, fuzz targets), and files a
  plain `mod name;` declares in the module owning their directory or in an
  inline module of one above it (dioxus's `mod components { pub mod home; }`
  in main.rs). Only for a file left over are the project's Rust files that
  write `path =` read (a byte check first), once per resolver. With a
  claim, rustSuperModule is the declaring module, rustFileModule owns the
  file's directory (rustc reads every `#[path]` file as a mod.rs),
  rustCrateRootModule is the declaring file's crate, and rustModuleWithin,
  isRustItemVisibleFrom and isVisibleAcrossFiles see the file inside the
  declaring module, so `use super::*` brings in its private items.
- rustCrateGraph: `[[example]]`, `[[test]]` and `[[bench]]` paths are
  target roots, as `[lib]`/`[[bin]]` ones are since PR #3014, and such an
  example is its own crate's root (dioxus's
  `examples/07-fullstack/handling_errors.rs`).

Validation:
- rust-path-super-glob.test.ts (PR 1892's case, credited) and
  rust-path-attribute-modules.test.ts (7 cases): on main all 8 fail; all
  pass. Every rust-* suite passes.
- A/B against main, native kernel: fast-mlsirm (its Rust files) +2,796
  links (1,839 calls, 427 references, 334 constructions, 196 imports), 71
  retargeted (exposure_tests.rs's `Lcg::next_f64` from cdm_tests.rs's
  private `Lcg` to exposure.rs's, the declaring module's helpers instead
  of bifactor_grm.rs's), 87 reaching the same item through the declaring
  module (confidence 0.4 to 0.9), 0 removed; dioxus +27 (each headless
  test's `utils::mock_event(…)` into the helper five tests load); tokio +2
  (`use super::AtomicU64` in the files atomic_u64_as_mutex.rs loads);
  ripgrep, axum, clap, serde, gleam, express and flask unchanged.
- Cost, native kernel, medians of 3 interleaved runs: fast-mlsirm CPU 15.3
  -> 15.8 s, wall 4.2 -> 5.2 s, peak RSS 825 -> 882 MB; tokio CPU 26.1 ->
  26.7 s, wall 10.4 -> 11.2 s, peak RSS 1,023 -> 1,028 MB; dioxus CPU 34.8
  -> 35.6 s, wall 10.3 -> 11.2 s, peak RSS 1,125 -> 1,120 MB; gleam CPU
  24.1 -> 23.8 s, wall 6.6 -> 6.7 s, peak RSS 1,027 -> 1,023 MB.

Builds on PR #1892 by @seonghobae.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@colbymchenry

Copy link
Copy Markdown
Owner

Thank you for tracking this down, @seonghobae! Your fix for #[path]-loaded test modules has landed in #3064, built on main's module walk: a file loaded with #[path = "…"] is now part of the module that declares it, so its use super::* brings in that module's items (private ones included) and super::/crate:: start there, and a path through such a module from the declaring file reaches the file it names. Your fast-mlsirm case is in as a test, credited to you, so this PR can close.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants