-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Rust: Implement type inference for associated types for concrete types #21188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
eca7559 to
8a465bd
Compare
8a465bd to
7e74844
Compare
| typePath = TypePath::singleton(TSelfTypeParameter(this)) and | ||
| result = TSelfTypeParameter(this) | ||
| or | ||
| exists(TypeAlias alias | |
Check warning
Code scanning / CodeQL
Omittable 'exists' variable Warning
in this argument
4dcb7c1 to
9d10607
Compare
9d10607 to
daeed4e
Compare
daeed4e to
ddd5b63
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements type inference for associated types on concrete types in Rust. It handles paths like <Foo as Trait>::Assoc and Self::Assoc in impl blocks by using a two-phase instantiation approach to avoid non-monotonic recursion. The key innovation is parameterizing TypeMention with a predicate for resolving additional path types, creating PreTypeMention first (with empty predicate) for building the type hierarchy, then the full TypeMention (with trait implementation knowledge) for complete type resolution.
Changes:
- Two-phase type mention instantiation to resolve non-monotonic recursion between type mentions and the type hierarchy
- Path resolution improvements for
Self::Assocpaths in impl blocks to correctly resolve to the trait's associated type - New test cases demonstrating associated type resolution for concrete types like
<Odd<i32> as GetSet>::Output = booland<Odd<bool> as GetSet>::Output = char
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| rust/ql/test/library-tests/type-inference/type-inference.expected | Updated test expectations with additional type inferences for concrete associated types |
| rust/ql/test/library-tests/type-inference/associated_types.rs | Added comprehensive test cases for concrete type associated type access |
| rust/ql/test/library-tests/type-inference/CONSISTENCY/TypeInferenceConsistency.expected | Documents expected non-unique certain type inconsistency |
| rust/ql/test/library-tests/path-resolution/path-resolution.expected | Updated path resolution expectations for improved Self path handling |
| rust/ql/test/library-tests/path-resolution/main.rs | Added test for Self path resolution within impl blocks |
| rust/ql/lib/codeql/rust/internal/typeinference/TypeMention.qll | Core implementation of two-phase type mention instantiation |
| rust/ql/lib/codeql/rust/internal/typeinference/TypeInferenceConsistency.qll | Updated consistency checks to filter source-only inconsistencies |
| rust/ql/lib/codeql/rust/internal/typeinference/TypeInference.qll | Changed to use PreTypeMention for type hierarchy construction |
| rust/ql/lib/codeql/rust/internal/typeinference/Type.qll | Updated type parameter default handling |
| rust/ql/lib/codeql/rust/internal/PathResolution.qll | Significant refactoring of Self path and associated type resolution logic |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| or | ||
| // Items available on the implementing type are available on `Self`. We only | ||
| // add these edges when they are relevant. If a type has `n` impl blocks with | ||
| // `m` functions each, we would otherwise end up always constructing somethong |
Copilot
AI
Jan 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a typo in the comment: "somethong" should be "something".
| // `m` functions each, we would otherwise end up always constructing somethong | |
| // `m` functions each, we would otherwise end up always constructing something |
| } | ||
|
|
||
| TypeItemNode getResolved() { result = resolved } | ||
| class AdditionalPathTypeMention extends PathTypeMention { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately the indentation change caused from making this a module shows a very annoying diff 😢. This is the only spot where there are actual changes.
The goal of this PR is to handle paths that access an associated type on a concrete type (concrete meaning not a type parameter) in
TypeMention.These paths fall into one of two cases:
<Foo as Trait>::AssocwhereFoocan be an arbitrarily complex type.Self::Associnside animplblock. For animplblock of the formimpl Trait for Foosuch a path is basically sugar for the above.A key point is that resolving the associated type relies on how the concrete type implements the trait that the associated type is from. For instance, the added tests have examples where
<Odd<i32> as GetSet>::Outputis equal toboolbut<Odd<bool> as GetSet>::Outputis equal tochar.Changes to path resolution
Today case 2 is somewhat handled inside path resolution. But path resolution doesn't understand how types implement traits: For a
Self::Assocpath we find all associated types with the nameAssocacross all traits thatSelfimplement. This leads to spurious path resolutions as seen in the tests.To address this, the PR tweaks path resolution such that a
Self::Assocpath resolves to the associated type in the trait whereAssocis from (except whenAssocis defined directly in theimplblock thatSelfbelongs to). This does not depend on type information, so it can be done correctly in path resolution.Changes to type inference
After that we use the
SatisfiesConstraintmodule inTypeMentionto find the correct trait implementations and read the associated types off of those. When implementing this I ran into non-monotonic recursion. The problem as well as the workaround is documented in the comment for theMkTypeMentionmodule.Non-unique certain type inconsistency
The last commit adds an example of a non-unique certain type inconsistency introduced by the PR caused by a type mention that resolves to two paths.
In this case the two types obviously can't both be "certain", but they still represent certain information in the sense that any other types would certainly be incorrect. Hence it's still beneficial to include those types as certain, even though it breaks the inconsistency rule.
I tried to come up with an exclusion to the rule, but it's not trivial as the certain types originate in a type mention and can propagate many places from there.
DCA
The DCA report shows more types and a 0.2% point increase in resolved calls.
There is a small slowdown. I'm not seeing any bad joins, so I think it's from now constructing two instances of
TypeMention. If that is indeed the cause it might be possible to limit the impact in follow up work by restrictingPreTypeMentionto the (small) subset of type mentions that are actually used to construct the type hierarchy (those used inconditionSatisfiesConstraint).