feat(rust): infer let types from Self-returning associated constructors#242
Merged
Conversation
A `let x = Type::new(..)` already seeded the local type environment so a later selector call on x resolves against Type; extend that to the other conventional value constructors (from/default/with_capacity/with_config/ empty) idiomatic Rust reserves for returning the owning type itself. The inferred name must be a bare UpperCamelCase type, so a lowercase module function, `Self`, or a single-letter generic parameter is never seeded, and the resolver still refuses to bind unless that type genuinely owns the called method, so a misfit inference falls through to unresolved rather than to a wrong owner. Wrapper-returning constructors are deliberately excluded — from_str and open yield Result<Self> and builder a distinct struct, so the binding's real type is that wrapper, not the qualifier.
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.
What
Extends the Rust extractor's local type environment: a
let x = Type::new(..)already seededx's type so a laterx.method()selector call resolves againstType. This generalizes that seeding to the other conventional value constructors idiomatic Rust reserves for returning the owning type —from,default,with_capacity,with_config,empty— solet x = Matcher::from(cfg); x.find()bindsfindtoMatcher::find.Precision is preserved by two guards: (1) the inferred name must be a bare UpperCamelCase type, so a lowercase module function,
Self, or a single-letter generic parameter is never seeded; (2) the resolver still refuses to bind unless that type genuinely owns the called method, so a misfit inference falls through to unresolved rather than to a wrong owner. Wrapper-returning constructors are deliberately excluded —from_str/openyieldResult<Self>andbuildera distinct struct, so their binding's real type is the wrapper, not the qualifier (admitting them was a latent wrong-owner risk this PR also removes).Measured impact — honest
On ripgrep (native resolution, rust-analyzer off), this produces zero change in resolved-vs-unresolved edges: ripgrep's residual ambiguous method calls are dominated by common names (
push/len/map/is_empty) on standard-library receiver types (Vec/String/Option/&[u8]) whose owner types aren't graph nodes, so no amount of native qualifier/receiver inference can bind them — that is inherently language-server territory. This change is a correctness/completeness improvement to the extractor (it infers more local types, and fixes the wrapper-constructor precision hole) that helps codebases with richer internal polymorphism than ripgrep; it is not expected to move recall on std-heavy repos.Tests
Config::default()/Buf::with_capacity()/Matcher::from()seed the local type;thing::from(lowercase) andT::from(generic) do not.go build,go test -race ./internal/parser/... ./internal/resolver/...,golangci-lintall green.