Skip to content
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

Rust: Adjustments to type inference #19081

Merged
merged 3 commits into from
Mar 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ module Impl {
*/
class FieldExpr extends Generated::FieldExpr {
/** Gets the record field that this access references, if any. */
StructField getStructField() { result = TypeInference::resolveRecordFieldExpr(this) }
StructField getStructField() { result = TypeInference::resolveStructFieldExpr(this) }

/** Gets the tuple field that this access references, if any. */
TupleField getTupleField() { result = TypeInference::resolveTupleFieldExpr(this) }
Expand Down
2 changes: 1 addition & 1 deletion rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ module Impl {
* Empty structs are considered to use record fields.
*/
pragma[nomagic]
predicate isRecord() { not this.isTuple() }
predicate isStruct() { not this.isTuple() }
}
}
6 changes: 3 additions & 3 deletions rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ module Impl {
predicate isTuple() { this.getFieldList() instanceof TupleFieldList }

/**
* Holds if this variant uses record fields.
* Holds if this variant uses struct fields.
*
* Empty variants are considered to use record fields.
* Empty variants are considered to use struct fields.
*/
pragma[nomagic]
predicate isRecord() { not this.isTuple() }
predicate isStruct() { not this.isTuple() }

/** Gets the enum that this variant belongs to. */
Enum getEnum() { this = result.getVariantList().getAVariant() }
Expand Down
2 changes: 1 addition & 1 deletion rust/ql/lib/codeql/rust/internal/Type.qll
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ abstract class Type extends TType {
pragma[nomagic]
abstract Function getMethod(string name);

/** Gets the record field `name` belonging to this type, if any. */
/** Gets the struct field `name` belonging to this type, if any. */
pragma[nomagic]
abstract StructField getStructField(string name);

Expand Down
38 changes: 19 additions & 19 deletions rust/ql/lib/codeql/rust/internal/TypeInference.qll
Original file line number Diff line number Diff line change
Expand Up @@ -248,24 +248,24 @@ private TypeMention getExplicitTypeArgMention(Path path, TypeParam tp) {
}

/**
* A matching configuration for resolving types of record expressions
* A matching configuration for resolving types of struct expressions
* like `Foo { bar = baz }`.
*/
private module StructExprMatchingInput implements MatchingInputSig {
private newtype TPos =
TFieldPos(string name) { exists(any(Declaration decl).getField(name)) } or
TRecordPos()
TStructPos()

class DeclarationPosition extends TPos {
string asFieldPos() { this = TFieldPos(result) }

predicate isRecordPos() { this = TRecordPos() }
predicate isStructPos() { this = TStructPos() }

string toString() {
result = this.asFieldPos()
or
this.isRecordPos() and
result = "(record)"
this.isStructPos() and
result = "(struct)"
}
}

Expand All @@ -286,15 +286,15 @@ private module StructExprMatchingInput implements MatchingInputSig {
result = tp.resolveTypeAt(path)
)
or
// type parameter of the record itself
dpos.isRecordPos() and
// type parameter of the struct itself
dpos.isStructPos() and
result = this.getTypeParameter(_) and
path = TypePath::singleton(result)
}
}

private class RecordStructDecl extends Declaration, Struct {
RecordStructDecl() { this.isRecord() }
private class StructDecl extends Declaration, Struct {
StructDecl() { this.isStruct() }

override TypeParam getATypeParam() { result = this.getGenericParamList().getATypeParam() }

Expand All @@ -304,14 +304,14 @@ private module StructExprMatchingInput implements MatchingInputSig {
result = super.getDeclaredType(dpos, path)
or
// type of the struct itself
dpos.isRecordPos() and
dpos.isStructPos() and
path.isEmpty() and
result = TStruct(this)
}
}

private class RecordVariantDecl extends Declaration, Variant {
RecordVariantDecl() { this.isRecord() }
private class StructVariantDecl extends Declaration, Variant {
StructVariantDecl() { this.isStruct() }

Enum getEnum() { result.getVariantList().getAVariant() = this }

Expand All @@ -325,7 +325,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
result = super.getDeclaredType(dpos, path)
or
// type of the enum itself
dpos.isRecordPos() and
dpos.isStructPos() and
path.isEmpty() and
result = TEnum(this.getEnum())
}
Expand All @@ -342,7 +342,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
result = this.getFieldExpr(apos.asFieldPos()).getExpr()
or
result = this and
apos.isRecordPos()
apos.isStructPos()
}

Type getInferredType(AccessPosition apos, TypePath path) {
Expand All @@ -360,8 +360,8 @@ private module StructExprMatchingInput implements MatchingInputSig {
private module StructExprMatching = Matching<StructExprMatchingInput>;

/**
* Gets the type of `n` at `path`, where `n` is either a record expression or
* a field expression of a record expression.
* Gets the type of `n` at `path`, where `n` is either a struct expression or
* a field expression of a struct expression.
*/
pragma[nomagic]
private Type inferStructExprType(AstNode n, TypePath path) {
Expand Down Expand Up @@ -777,7 +777,7 @@ private module FieldExprMatchingInput implements MatchingInputSig {

Declaration getTarget() {
// mutual recursion; resolving fields requires resolving types and vice versa
result = [resolveRecordFieldExpr(this).(AstNode), resolveTupleFieldExpr(this)]
result = [resolveStructFieldExpr(this).(AstNode), resolveTupleFieldExpr(this)]
}
}

Expand Down Expand Up @@ -921,10 +921,10 @@ private module Cached {
}

/**
* Gets the record field that the field expression `fe` resolves to, if any.
* Gets the struct field that the field expression `fe` resolves to, if any.
*/
cached
StructField resolveRecordFieldExpr(FieldExpr fe) {
StructField resolveStructFieldExpr(FieldExpr fe) {
exists(string name | result = getFieldExprLookupType(fe, name).getStructField(name))
}

Expand Down
16 changes: 8 additions & 8 deletions rust/ql/test/library-tests/type-inference/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,8 @@ mod type_parameter_bounds {

mod function_trait_bounds {
#[derive(Debug)]
struct MyThing<A> {
a: A,
struct MyThing<T> {
a: T,
}

#[derive(Debug)]
Expand Down Expand Up @@ -387,12 +387,12 @@ mod method_supertraits {
#[derive(Debug)]
struct S2;

trait MyTrait1<A> {
fn m1(self) -> A;
trait MyTrait1<Tr1> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The expected file contained some duplicated lines, making it a bit hard to se what was what. So this renames some generics s.t. fewer names are identical.

fn m1(self) -> Tr1;
}

trait MyTrait2<A>: MyTrait1<A> {
fn m2(self) -> A
trait MyTrait2<Tr2>: MyTrait1<Tr2> {
fn m2(self) -> Tr2
where
Self: Sized,
{
Expand All @@ -404,8 +404,8 @@ mod method_supertraits {
}
}

trait MyTrait3<A>: MyTrait2<MyThing<A>> {
fn m3(self) -> A
trait MyTrait3<Tr3>: MyTrait2<MyThing<Tr3>> {
fn m3(self) -> Tr3
where
Self: Sized,
{
Expand Down
Loading
Loading