Repository navigation
fix(rust): a private item, or one another crate holds, no longer takes a name a file imports - #2692
Merged
Merged
Conversation
…s a name a file imports A Rust type alias declared without pub recorded no visibility in either engine, so name matching took dioxus's private type Result in src/build/patch.rs for the Result<...> a file means through use crate::Result. Type aliases now record it, as functions and structs already do, and a private module item is out of scope outside its own module ahead of the ranking. The pipeline's veto already rejected such a pick after the ranking, which left the reference unresolved: that is what kept tokio's timeout(...), split(...) and sleep(...) calls from linking, since a private namesake outranked the function they import. With the private items gone, a runner-up from an unrelated crate could win instead: tokio's tests' spawn(...) calls, under use tokio_test::task::spawn, went to the examples crate's pub fn spawn. So a name a use binds is now an item of the crate its path starts from, or of a project crate that one's [dependencies] name, in turn, which a facade's re-exports need: clap::Command is clap_builder's. crate::, self:: and super:: start from the file's own crate; a named root counts when the file's own manifest lists it. Dependencies are found by path (their own, or the workspace's for workspace = true), so renamed keys and crates outside the members land, and dotted keys such as helper.workspace = true are read. Dev and build dependencies are not re-exported, so they don't count: tokio's own use crate::spawn, whose spawn sits in a macro the index doesn't see, stays unresolved instead of going to tokio-test's. A file in no crate the manifests name, or a path from anything else, is matched as before. reference-target-kind's sibling-crate fixture re-exported pupil_core without depending on it, which Cargo rejects; it now declares it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 20, 2026
This was referenced Oct 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Follow-up from #2687, which kept
.rsout of thesrc/**/build/rule. Indexing dioxus'spackages/cli/src/build/moved 158Resulttype references off the crate's own alias. The cause is in Rust name matching, not in the build-folder rule:src/build/patch.rsdeclares a privatetype Result<T, E = PatchError>. The crate's own alias iserror.rs'spub(crate) type Result, which 21 files bring in withuse crate::Result.isRustNameInScopeaccepts anyResultonce a fileuses one (Resultis a prelude name), and the Rust extractors recorded no visibility for type aliases in either engine. Nothing said the private alias can't leavepatch.rs.#1731 already made
isVisibleAcrossFilesveto a private Rust item, but only after the ranking has picked it, and the veto leaves the reference unresolved. That is the second half of the bug: wherever a private namesake outranks the item a file imports, the import never links. tokio's tests'use tokio::time::timeoutcalls,split(…),try_exists(…)andsleep(…)were all unresolved this way.Fix
extractTypeAlias) and the kernel (extract_type_alias), private unlesspubin any form, as functions and structs already do.isRustItemVisibleFromapplies the Kotlin, Go, Rust: a private / unexported / non-pub definition is accepted as a cross-file name-match target #1731 veto's rule (its own module and the modules inside it, with amod.rs/lib.rs/main.rsowning its directory) to functions, structs, enums, unions, type aliases, traits, constants and statics. The crate's ownpub(crate) type Resultcan then win, instead of the reference going unresolved.usebinds is an item its path's crate can reach. Taking private items out ahead of the ranking let a runner-up from an unrelated crate win. tokio's tests'spawn(…)calls, underuse tokio_test::task::spawn, went to the examples crate'spub fn spawn, which nothing depends on. SorustUsesOfnow records the first segment of eachusepath that binds a name, andrustUseCanReachkeeps a candidate only when it is in the crate that path starts from, or in a project crate that crate's[dependencies]name, transitively. A facade's re-exports therefore resolve:clap::Commandis clap_builder's, and axum'sResponseis axum-core's.crate::,self::andsuper::start from the file's own crate. A named root counts when it is the file's own crate or a dependency its own manifest lists, under any kind.use crate::spawn(tokio'sspawnsits in acfg_rt!macro the index doesn't read) stays unresolved instead of going to tokio-test's, which tokio dev-depends on.rustCrateGraphfinds a dependency by itspath: its own, or the workspace's forworkspace = true. So renamed keys and crates outside the members land. It also reads every way Cargo writes a dependency: plain, inline table, dotted keys (helper.workspace = true) and[dependencies.foo]tables.Test change.
reference-target-kind.test.ts's sibling-crate fixture hadappre-exportpupil_core::portswithout depending on it, which Cargo rejects. The fixture now declares the dependency, and the test still covers what it was written for: a trait reached through a re-exported module with no file of its own.Related open PRs.
usepath, before name matching, and leaves names from another workspace crate as they were. Name matching is what this narrows, so the two complement each other.cargo-workspace.tsfor Rust paths. If both land, the dependency reading here could move there.Verification
__tests__/rust-private-item-scope.test.ts, 7 tests, on both engines.codegen/patch.rssorts beforeerror.rs, as dioxus'sbuild/does):use crate::Resultanduse crate::{Error, Result}reacherror.rs's alias;patch/jump.rs;fn checksumstays in its module;public/private.use helper::task::spawnreaches helper'sspawn, not the examples crate's, past a private namesake nearer the test. helper is a dev-dependency writtenhelper.workspace = true.use facade::Thingreaches theThingthe facade re-exports from a crate that it depends on under apackage = "shared-types"rename, and that isn't a workspace member.name-matcher.tsandtree-sitter.ts, 3 of the 7 fail: the visibility test,use crate::Result, and the helperspawn. Two mutants each fail thespawntest, which linksexamples/custom.rsexactly as tokio did: the crate rule switched off, and dotted keys not read.kernel-rustlang-paritypasses. The new tests pass withCODEGRAPH_KERNEL=0and with the kernel. With the kernel change reverted, the LF and CRLF torture parity tests fail (checked earlier on this branch).tsc --noEmitis clean.scripts/build-kernel.sh,CODEGRAPH_KERNEL_EXPECT=1,--maxWorkers=4 --minWorkers=1): 7,637 tests, 7,557 passed, 0 failed, 80 skipped. Rebased since onto 40987d7 (fix(objc): a macro alone on its line no longer hides the declaration below it #2691, Objective-C only):tscand the 15 Rust, Objective-C, resolution and framework test files (338 tests) pass.A/B on real repos
Arms: origin/main 6c202bc, and this branch on it. Each arm carries its own kernel. Each repo was indexed fresh with
codegraph init -y, dumped withscripts/dump-graph.mjs, and edges were paired by kind, source, line, column and name.Every changed edge was judged two ways:
usepath names. The script can't judge a root-level path such asuse crate::Matchorpub use anyhow::Error; those were checked by hand.No edge moved from a right target to a wrong one.
compiler-core)packages/cli)tokio:
spawn(…)calls underuse tokio_test::task::spawnnow link to tokio-test'sspawn. 44 more, which main sent to the examples crate'sspawn, move there.timeout, 10split, 10try_exists, 8 tokio-utilwrite_all_vectored, 6read, 5sleep, 3interval, 1writeand 1create_dir. All now reach the function the fileuses.Handle, 4Expiration, 2Builderand 1Elapsed. These are references in tokio's own crates that main sent to tokio-test's, tokio-util's or tokio-stream's namesakes, crates they don't depend on.Handle, 19Receiver, 9Sender, 6Wheeland 3Expiration. They went to a crate the file can't reach, and now go to a reachable namesake in the wrong module. For example, tokio-stream'suse tokio::sync::watch::Receiverwent to tokio-util's simplexReceiverand now goes to tokio'snet::unix::pipe::Receiver. The Rust framework rule takes the first in-scope namesake (see below).Errorrefs that went to tokio-util'scopy_to_bytes.rsimpl-associatedtype Error, and 1Outputthat went to another test file's.ripgrep:
use crate::error::{Error, ErrorKind}in grep-regex (14) and grep-pcre2 (7) went to globset'sError, a crate neither depends on; they now go to their ownerror.rs. 9Matchin ignore now go to ignore's ownenum Matchinstead of grep-matcher'sstruct Match.serde: serde_core's
impl SerializeSeq for Impossible<…>and its six siblings went to structs of those names in serde'sprivate/ser.rs; serde_core depends on serde only as a dev-dependency. They now reach serde_core's own traits. The 15 synthesized trait→impl edges move with them: they now start at the traits'endandserialize_*methods instead of the structs'.axum: 91
Responserefs move from an impl-associatedtype Responseto axum-core'spub type Response, which axum re-exports.Itemrefs tocookie/private.rs's iteratortype Item, and 1Clientin the mongodb example that went to the reverse-proxy example's private alias.axum/src/routing/move from one impl-associatedtype Responseto another (routing/mod.rs's), wrong before and after.clap:
impl Args for CliArgsunderuse clap::{…, Args, …}went to clap_bench'sstruct Args. It now reaches clap_builder'strait Args, and the trait→impl edges follow (the 2 new edges). 7Err(…)calls invalue_parser.rsno longer link tovalue_hint.rs'stype Errof aFromStrimpl.gleam:
TypeConstructor { … }constructions and 4 references now reachtype_.rs's pub struct; before,docs.rs's private one outranked it and was vetoed.bool()reachesprelude.rs's, throughuse crate::{type_::{…, bool}}.Err(…)calls that went todependency.rs'stype Errand 7Itemrefs toio.rs'stype Item, both impl-associated.dioxus: 8
Err(…)calls and 4Errorrefs no longer go toplatform.rs's andproxy_ws.rs's impl-associated aliases. The crate's ownErrorispub use anyhow::Error, from outside the project.Same target, new metadata: the same target, now a unique exact match (confidence 0.9) where the Rust framework rule took it (0.7) or a ranking picked it (0.4), because the private candidates no longer compete.
Byte-identical controls: gin, excalidraw, serilog, pypa/build.
Not in this PR
usepath names, within a crate. This PR checks the crate a path reaches, not the module. The Rust framework rule still takes the first in-scope namesake, souse tokio::sync::watch::Receivercan land on another tokioReceiver: tokio's 57 still-wrong moves.type Response = …;inside animpl) is never named bare; onlySelf::Responseor a path reaches it. It now recordsprivate, so other modules no longer match it, which is where most of the removed wrong links came from. Inside its own module it can still match a bare name: axum's 7routing/refs, or anErr(…)call in the same file as animpl FromStr { type Err = … }.src/**/build/rule (HAND_WRITTEN_SOURCE) comes next, re-measured on dioxus with this in place.🤖 Generated with Claude Code