Repository navigation
fix(rust): a Self:: call is the function of the type whose impl it is in - #2700
Merged
Merged
Conversation
A Rust Self::x(...) call reached the resolver as a method call on a receiver named Self, which names no type. So it fell to a guess by the name alone, and linked only when nothing else in the project shared that name. clap's Self::new(...) calls in impl Error, ValueParser and the like stayed unresolved, and so did tokio's, axum's and serde's. dioxus's Self::current() stopped resolving once its Android tooling's AndroidTools::current was indexed. Self is now the type of the impl (or trait) the call is written in. The call reaches that type's function, or its variant for Self::Text(...), in the type's own file first, then the nearest. As in Rust, the type's inherent function comes first, with cfg twins standing for one another. A trait impl's function is taken only when it is the only one, and several trait impls of one name (From<A>, From<B>) are left unresolved. Inside a trait impl, a call to the function's own name hands on to the type's own function, so it never links to itself there. In the type's own impl such a call is a recursion and stays one. A trait's own method is the fallback only where nothing could shadow it. A type from outside the project, such as axum's impl Listener for tokio::net::TcpListener, has only the impls written beside the call. When the type has no such function, the call stays unresolved instead of going to another type's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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
Found in #2695's A/B: once dioxus's
build/android.rswas indexed,Self::current()insideimpl Workspacestopped linking toWorkspace::current. The new file addsAndroidTools::currentas a namesake.A Rust
Self::x(…)call reachesmatchMethodCallas a call on a receiver namedSelf. No type has that name, so it falls to the name-only guess (Strategy 3), which links only when nothing else shares the method's name.A census of every
Self::x(…)call across tokio, ripgrep, serde, axum, clap, gleam and dioxus found 0 wrong links. It did find many lost ones:xx(a trait default, std, a macro)compiler-core)packages/cli)The unresolved ones include
Self::new(…)insideimpl ErrorwhileError::newsits in the same file,Self::Text(…)insideimpl Message, andSelf::from_std(…).Fix
matchRustSelfPath(name-matcher), tried bymatchMethodCallfor a RustSelf::xcall before any guess:Selfis the type of theimpl(or trait) the call is written in (rustSelfType, reading the header with fix(rust): a call reaches a project impl on a std type only as Rust would pick it #2697'sparseRustImplHeader). The call reaches that type'sx: a function, a method, or a variant forSelf::Text(…), matching how an explicitMessage::Text(…)already resolves. The type's own file comes first, then the nearest.#[cfg]twins standing for one another;Self::from(…)amongOsStr's 13Fromimpls, or tokio'sSpawnLocation's two.fn local_addr(&self) { Self::local_addr(self) }hands the call on to the type's own function, so it never links to the method it is written in. In the type's own impl, that shape is a recursion and links to itself as before, as in gleam'sresolve_type_var_id.use, or a std type the project doesn't declare, like axum'simpl Listener for tokio::net::TcpListener.impl<T: Parser> Parser for Box<T>callsSelf::new, which isBox::new, not thenewof a struct also namedParser.x, the call stays unresolved instead of falling to a guess at another type's.Verification
__tests__/rust-self-path-calls.test.ts, 5 tests. Every name involved also has a namesake elsewhere, so a guess by name can't pick it:Self::newinimpl Errorand dioxus'sSelf::currentinimpl Workspace;Self::Text(…);Self::new()inimpl Store for Config, andSelf::open()in a trait's default method;Box<T>shape;TcpListenerthat must link nothing.name-matcher.ts, 4 of the 5 tests fail. The one that passes there is theBox<T>guard, which main also leaves unlinked.tsc --noEmitis clean.scripts/build-kernel.sh,CODEGRAPH_KERNEL_EXPECT=1,--maxWorkers=4 --minWorkers=1): 7,671 tests, 7,591 passed, 0 failed, 80 skipped.A/B on real repos
Arms: origin/main 60b2f1e (#2697 merged), and this change on it, with one kernel. Main has since gained only #2698, a C++ fix. 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.Self::calls newly linkedcompiler-core)packages/cli)Workspace::reload→Workspace::current)Self::link and no self-loop among the new edges. A sample read by hand:Error::argument_conflict→Error::new,BoolValueParser::default→BoolValueParser::new,StreamMap::from_iter→StreamMap::with_capacity,KeepAlive::default→KeepAlive::newandEventFlags::from_bits.qualified-name).Self::from(…)among severalFromimpls: clap 15 and tokio 1.🤖 Generated with Claude Code