Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 61 additions & 12 deletions rust/ql/lib/codeql/rust/internal/TypeMention.qll
Original file line number Diff line number Diff line change
Expand Up @@ -151,25 +151,61 @@ class NonAliasPathTypeMention extends PathTypeMention {
result = this.getQualifier().getSegment().getGenericArgList().getTypeArg(i)
}

private TypeMention getPositionalTypeArgument(int i) {
result = this.getPositionalTypeArgument0(i)
/**
* 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?

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.

private Type getPositionalTypeArgument(int i, TypePath path) {
result = this.getPositionalTypeArgument0(i).resolveTypeAt(path)
or
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.

// If a type argument is not given in the path, then we use the default for
// the type parameter if one exists for the type.
not exists(this.getPositionalTypeArgument0(i)) and
result = this.resolveRootType().getTypeParameterDefault(i) and
// Defaults only apply to type mentions in type annotations
this = any(PathTypeRepr ptp).getPath().getQualifier*()
this = any(PathTypeRepr ptp).getPath().getQualifier*() and
exists(Type ty, TypePath prefix |
ty = this.resolveRootType().getTypeParameterDefault(i).resolveTypeAt(prefix) and
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)
)
Comment on lines 181 to 189
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.
)
}

/** Gets the type mention in this path for the type parameter `tp`, if any. */
pragma[nomagic]
private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) {
/**
* Gets the type for this path for the type parameter `tp` at `path`, when the
* type parameter does not correspond directly to a type mention.
*/
private Type getTypeForTypeParameterAt(TypeParameter tp, TypePath path) {
exists(int i |
result = this.getPositionalTypeArgument(pragma[only_bind_into](i)) and
result = this.getPositionalTypeArgument(pragma[only_bind_into](i), path) and
tp = this.resolveRootType().getPositionalTypeParameter(pragma[only_bind_into](i))
)
or
}

/** Gets the type mention in this path for the type parameter `tp`, if any. */
pragma[nomagic]
private TypeMention getTypeMentionForTypeParameter(TypeParameter tp) {
exists(TypeAlias alias |
result = this.getAnAssocTypeArgument(alias) and
tp = TAssociatedTypeTypeParameter(alias)
Expand Down Expand Up @@ -237,9 +273,17 @@ class NonAliasPathTypeMention extends PathTypeMention {
typePath.isEmpty() and
result = this.resolveRootType()
or
exists(TypeParameter tp, TypePath suffix |
result = this.getTypeMentionForTypeParameter(tp).resolveTypeAt(suffix) and
typePath = TypePath::cons(tp, suffix)
exists(TypeParameter tp, TypePath suffix | typePath = TypePath::cons(tp, suffix) |
result = this.getTypeForTypeParameterAt(tp, suffix)
or
result = this.getTypeMentionForTypeParameter(tp).resolveTypeAt(suffix)
)
or
// When the path refers to a trait, then the implicit `Self` type parameter
// should be instantiated from the context.
exists(TypePath suffix |
result = this.getSelfTypeParameter().resolveTypeAt(suffix) and
typePath = TypePath::cons(TSelfTypeParameter(resolved), suffix)
)
}
}
Expand Down Expand Up @@ -296,6 +340,11 @@ class TraitMention extends TypeMention instanceof TraitItemNode {
typePath.isEmpty() and
result = TTrait(this)
or
// The implicit `Self` type parameter occurs at the `Self` type parameter
// position.
typePath = TypePath::singleton(TSelfTypeParameter(this)) and
result = TSelfTypeParameter(this)
or
exists(TypeAlias alias |
alias = super.getAnAssocItem() and
typePath = TypePath::singleton(result) and
Expand Down
6 changes: 3 additions & 3 deletions rust/ql/test/library-tests/type-inference/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,7 @@ mod trait_default_self_type_parameter {

// The trait bound on `T` uses the default for `A` which contains `Self`
fn tp_uses_default<S: TraitWithSelfTp>(thing: S) -> i64 {
let _ms = thing.get_a(); // $ target=TraitWithSelfTp::get_a MISSING: type=_ms:T.S
let _ms = thing.get_a(); // $ target=TraitWithSelfTp::get_a type=_ms:T.S
0
}

Expand All @@ -675,7 +675,7 @@ mod trait_default_self_type_parameter {

fn get_a_through_tp<S: SubTraitOfTraitWithSelfTp>(thing: &S) {
// `thing` is a `TraitWithSelfTp` through the trait hierarchy
let _ms = get_a(thing); // $ target=get_a MISSING: type=_ms:T.S
let _ms = get_a(thing); // $ target=get_a type=_ms:T.S
}

struct MyStruct {
Expand All @@ -693,7 +693,7 @@ mod trait_default_self_type_parameter {

pub fn test() {
let s = MyStruct { value: 0 };
let _ms = get_a(&s); // $ target=get_a MISSING: type=_ms:T.MyStruct
let _ms = get_a(&s); // $ target=get_a type=_ms:T.MyStruct
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2013,18 +2013,18 @@ inferType
| main.rs:668:44:668:48 | thing | | main.rs:668:24:668:41 | S |
| main.rs:668:61:671:5 | { ... } | | {EXTERNAL LOCATION} | i64 |
| main.rs:669:13:669:15 | _ms | | {EXTERNAL LOCATION} | Option |
| main.rs:669:13:669:15 | _ms | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
| main.rs:669:13:669:15 | _ms | T | main.rs:668:24:668:41 | S |
| main.rs:669:19:669:23 | thing | | main.rs:668:24:668:41 | S |
| main.rs:669:19:669:31 | thing.get_a() | | {EXTERNAL LOCATION} | Option |
| main.rs:669:19:669:31 | thing.get_a() | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
| main.rs:669:19:669:31 | thing.get_a() | T | main.rs:668:24:668:41 | S |
| main.rs:670:9:670:9 | 0 | | {EXTERNAL LOCATION} | i32 |
| main.rs:670:9:670:9 | 0 | | {EXTERNAL LOCATION} | i64 |
| main.rs:676:55:676:59 | thing | | file://:0:0:0:0 | & |
| main.rs:676:55:676:59 | thing | &T | main.rs:676:25:676:52 | S |
| main.rs:678:13:678:15 | _ms | | {EXTERNAL LOCATION} | Option |
| main.rs:678:13:678:15 | _ms | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
| main.rs:678:13:678:15 | _ms | T | main.rs:676:25:676:52 | S |
| main.rs:678:19:678:30 | get_a(...) | | {EXTERNAL LOCATION} | Option |
| main.rs:678:19:678:30 | get_a(...) | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
| main.rs:678:19:678:30 | get_a(...) | T | main.rs:676:25:676:52 | S |
| main.rs:678:25:678:29 | thing | | file://:0:0:0:0 | & |
| main.rs:678:25:678:29 | thing | &T | main.rs:676:25:676:52 | S |
| main.rs:687:18:687:22 | SelfParam | | file://:0:0:0:0 | & |
Expand All @@ -2041,9 +2041,9 @@ inferType
| main.rs:695:17:695:37 | MyStruct {...} | | main.rs:681:5:683:5 | MyStruct |
| main.rs:695:35:695:35 | 0 | | {EXTERNAL LOCATION} | i32 |
| main.rs:696:13:696:15 | _ms | | {EXTERNAL LOCATION} | Option |
| main.rs:696:13:696:15 | _ms | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
| main.rs:696:13:696:15 | _ms | T | main.rs:681:5:683:5 | MyStruct |
| main.rs:696:19:696:27 | get_a(...) | | {EXTERNAL LOCATION} | Option |
| main.rs:696:19:696:27 | get_a(...) | T | main.rs:656:5:661:5 | Self [trait TraitWithSelfTp] |
| main.rs:696:19:696:27 | get_a(...) | T | main.rs:681:5:683:5 | MyStruct |
| main.rs:696:25:696:26 | &s | | file://:0:0:0:0 | & |
| main.rs:696:25:696:26 | &s | &T | main.rs:681:5:683:5 | MyStruct |
| main.rs:696:26:696:26 | s | | main.rs:681:5:683:5 | MyStruct |
Expand Down Expand Up @@ -4776,7 +4776,6 @@ inferType
| main.rs:2312:16:2312:21 | self.0 | | main.rs:2307:10:2307:17 | T |
| main.rs:2312:31:2312:35 | other | | main.rs:2305:5:2305:19 | S |
| main.rs:2312:31:2312:35 | other | T | main.rs:2307:10:2307:17 | T |
| main.rs:2312:31:2312:37 | other.0 | | main.rs:2267:5:2272:5 | Self [trait MyAdd] |
| main.rs:2312:31:2312:37 | other.0 | | main.rs:2307:10:2307:17 | T |
| main.rs:2320:19:2320:22 | SelfParam | | main.rs:2305:5:2305:19 | S |
| main.rs:2320:19:2320:22 | SelfParam | T | main.rs:2316:10:2316:17 | T |
Expand Down
Loading