Skip to content

Conversation

@paldepind
Copy link
Contributor

@paldepind paldepind commented Oct 28, 2025

This PR fixes two issues in how we handle Self type parameters. They're separate but related issues, so I've bunched them into one PR. Together these fixes should address https://github.com/github/codeql/pull/20682/files#r2464739113.

1/ Self in a default for a trait type parameter

If we have a default like this:

trait TraitWithSelfTp<A = Option<Self>> { ... }

Then, when TraitWithSelfTp is used as a trait bound, the meaning of the Self depends where that trait bound occurs. For instance, T : TraitWithSelfTp is the same as T : TraitWithSelfTp<T> and not T : TraitWithSelfTp<Self_TraitWithSelfTp>

The type mention Self in the default refers to the the Self type parameter for TraitWithSelfTp, but this needs to be translated at trait bounds.

2/ Self in supertraits

When Self occurs in the trait hierarchy

trait Sub: Super<Self> { ... }
trait SubSub : Sub { ... }

then those Self occurrences need to be instantiated such that the shared conditionSatisfiesConstraintTypeAt machinery calculates the correct trait hierarchy. Above, we should have that SubSub implements Super<Self_SubSub> and not some other Self parameter. To this end, the type mention for supertraits must instantiate the supertrait's Self type parameter.

@github-actions github-actions bot added the Rust Pull requests that update Rust code label Oct 28, 2025
@paldepind paldepind changed the title Rust: Improve handling of Self type parameter Rust: Improve handling of Self type parameter Oct 29, 2025
@paldepind paldepind marked this pull request as ready for review October 29, 2025 09:40
@paldepind paldepind requested a review from a team as a code owner October 29, 2025 09:40
Copilot AI review requested due to automatic review settings October 29, 2025 09:40
@paldepind paldepind added the no-change-note-required This PR does not need a change note label Oct 29, 2025
Copy link
Contributor

Copilot AI left a 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 adds support for handling trait type parameters with defaults that contain the implicit Self type parameter. The main enhancement allows the CodeQL type inference system to correctly resolve type defaults like trait TraitWithSelfTp<A = Option<Self>> by substituting Self with the concrete implementing type.

Key changes:

  • Added logic to detect and substitute Self type parameters in trait type parameter defaults
  • Added support for resolving Self type parameters from trait bounds, impl blocks, and type parameter bounds
  • Added comprehensive test cases covering various scenarios where Self appears in type parameter defaults

Reviewed Changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 2 comments.

File Description
rust/ql/lib/codeql/rust/internal/TypeMention.qll Implements core logic for detecting and resolving Self type parameters in trait defaults across different contexts
rust/ql/test/library-tests/type-inference/main.rs Adds test module trait_default_self_type_parameter with various test cases and corresponding call in main function
rust/ql/test/library-tests/type-inference/CONSISTENCY/PathResolutionConsistency.expected Updates expected line numbers in consistency test results (shifted by test additions)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 158 to 167
private TypeMention getSelfTypeParameter() {
exists(ImplItemNode impl | this = impl.getTraitPath() and result = impl.(Impl).getSelfTy())
or
exists(Trait subTrait |
this = subTrait.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() and
result.(SelfTypeParameterMention).getTrait() = subTrait
)
or
exists(TypeParamItemNode tp | this = tp.getABoundPath() and result = tp)
}
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getSelfTypeParameter method lacks documentation explaining its purpose and the three distinct contexts where Self type parameters can be resolved. Consider adding a comment block explaining: (1) impl blocks, (2) trait supertraits, and (3) type parameter bounds.

Copilot uses AI. Check for mistakes.
Comment on lines 183 to 191
if not ty = TSelfTypeParameter(resolved)
then result = ty and path = prefix
else
// When a default contains an implicit `Self` type parameter, it should
// be substituted for the type that implements the trait.
exists(TypePath suffix |
path = prefix.append(suffix) and
result = this.getSelfTypeParameter().resolveTypeAt(suffix)
)
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The comment on lines 186-187 could be more specific. It would be clearer to state that when a default type parameter is the Self type parameter (e.g., A = Option<Self>), it must be substituted with the concrete type from the trait implementation context.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@hvitved hvitved left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice work; some trivial comments.


mod trait_default_self_type_parameter {
// A trait with a type parameter that defaults to `Self`.
// trait TraitWithSelfTp<A = Self> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove

* Gets the type mention that instantiates the implicit `Self` type parameter
* for this path, if it occurs in the position of a trait bound.
*/
private TypeMention getSelfTypeParameter() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getSelfTraitBoundArg?

result = this.getDefaultPositionalTypeArgument(i, path)
}

private Type getDefaultPositionalTypeArgument(int i, TypePath path) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move this up before SelfTypeParameterMention.

@paldepind
Copy link
Contributor Author

Thanks for the review. I've addressed the comments.

The DCA report shows a small slowdown on average. When I evaluate locally I'm not seeing anything that sticks out (bad joins, etc.), so it might be noise or unavoidable.

@hvitved hvitved merged commit e5f1238 into github:main Oct 29, 2025
19 checks passed
@paldepind paldepind deleted the rust/ti-self-trait branch October 29, 2025 12:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-change-note-required This PR does not need a change note Rust Pull requests that update Rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants