Skip to content

Commit ed3a33f

Browse files
authored
Merge pull request #20177 from hvitved/rust/type-inference-where
Rust: Improve handling of where clauses in type inference and path resolution
2 parents d215ea1 + b50a766 commit ed3a33f

File tree

10 files changed

+3901
-3744
lines changed

10 files changed

+3901
-3744
lines changed

rust/ql/lib/codeql/rust/elements/internal/TraitImpl.qll

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,36 @@ module Impl {
3636
not this.hasGenericParamList() and
3737
result = 0
3838
}
39+
40+
private int nrOfDirectTypeBounds() {
41+
result = this.getTypeBoundList().getNumberOfBounds()
42+
or
43+
not this.hasTypeBoundList() and
44+
result = 0
45+
}
46+
47+
/**
48+
* Gets the `index`th type bound of this trait, if any.
49+
*
50+
* This includes type bounds directly on the trait and bounds from any
51+
* `where` clauses for `Self`.
52+
*/
53+
TypeBound getTypeBound(int index) {
54+
result = this.getTypeBoundList().getBound(index)
55+
or
56+
exists(WherePred wp |
57+
wp = this.getWhereClause().getAPredicate() and
58+
wp.getTypeRepr().(PathTypeRepr).getPath().getText() = "Self" and
59+
result = wp.getTypeBoundList().getBound(index - this.nrOfDirectTypeBounds())
60+
)
61+
}
62+
63+
/**
64+
* Gets a type bound of this trait.
65+
*
66+
* This includes type bounds directly on the trait and bounds from any
67+
* `where` clauses for `Self`.
68+
*/
69+
TypeBound getATypeBound() { result = this.getTypeBound(_) }
3970
}
4071
}

rust/ql/lib/codeql/rust/elements/internal/TypeParamImpl.qll

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ private import codeql.rust.elements.internal.generated.TypeParam
1212
*/
1313
module Impl {
1414
private import rust
15+
private import codeql.rust.internal.PathResolution
1516

1617
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1718
/**
@@ -27,6 +28,41 @@ module Impl {
2728
/** Gets the position of this type parameter. */
2829
int getPosition() { this = any(GenericParamList l).getTypeParam(result) }
2930

31+
private TypeBound getTypeBoundAt(int i, int j) {
32+
exists(TypeBoundList tbl | result = tbl.getBound(j) |
33+
tbl = this.getTypeBoundList() and i = 0
34+
or
35+
exists(WherePred wp |
36+
wp = this.(TypeParamItemNode).getAWherePred() and
37+
tbl = wp.getTypeBoundList() and
38+
wp = any(WhereClause wc).getPredicate(i)
39+
)
40+
)
41+
}
42+
43+
/**
44+
* Gets the `index`th type bound of this type parameter, if any.
45+
*
46+
* This includes type bounds directly on this type parameter and bounds from
47+
* any `where` clauses for this type parameter.
48+
*/
49+
TypeBound getTypeBound(int index) {
50+
result = rank[index + 1](int i, int j | | this.getTypeBoundAt(i, j) order by i, j)
51+
}
52+
53+
/**
54+
* Gets a type bound of this type parameter.
55+
*
56+
* This includes type bounds directly on this type parameter and bounds from
57+
* any `where` clauses for this type parameter.
58+
*/
59+
TypeBound getATypeBound() {
60+
// NOTE: This predicate is used in path resolution, so it can not be
61+
// defined using `getTypeBound` as that would cause non-monotonic
62+
// recursion due to the `rank`.
63+
result = this.getTypeBoundAt(_, _)
64+
}
65+
3066
override string toAbbreviatedString() { result = this.getName().getText() }
3167

3268
override string toStringImpl() { result = this.getName().getText() }

rust/ql/lib/codeql/rust/internal/PathResolution.qll

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -791,9 +791,7 @@ private class StructItemNode extends TypeItemNode instanceof Struct {
791791

792792
class TraitItemNode extends ImplOrTraitItemNode, TypeItemNode instanceof Trait {
793793
pragma[nomagic]
794-
Path getABoundPath() {
795-
result = super.getTypeBoundList().getABound().getTypeRepr().(PathTypeRepr).getPath()
796-
}
794+
Path getABoundPath() { result = super.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() }
797795

798796
pragma[nomagic]
799797
ItemNode resolveABound() { result = resolvePath(this.getABoundPath()) }
@@ -924,7 +922,8 @@ private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
924922
}
925923

926924
class TypeParamItemNode extends TypeItemNode instanceof TypeParam {
927-
private WherePred getAWherePred() {
925+
/** Gets a where predicate for this type parameter, if any */
926+
WherePred getAWherePred() {
928927
exists(ItemNode declaringItem |
929928
this = resolveTypeParamPathTypeRepr(result.getTypeRepr()) and
930929
result = declaringItem.getADescendant() and
@@ -933,13 +932,7 @@ class TypeParamItemNode extends TypeItemNode instanceof TypeParam {
933932
}
934933

935934
pragma[nomagic]
936-
Path getABoundPath() {
937-
exists(TypeBoundList tbl | result = tbl.getABound().getTypeRepr().(PathTypeRepr).getPath() |
938-
tbl = super.getTypeBoundList()
939-
or
940-
tbl = this.getAWherePred().getTypeBoundList()
941-
)
942-
}
935+
Path getABoundPath() { result = super.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() }
943936

944937
pragma[nomagic]
945938
ItemNode resolveABound() { result = resolvePath(this.getABoundPath()) }
@@ -956,12 +949,7 @@ class TypeParamItemNode extends TypeItemNode instanceof TypeParam {
956949
* ```
957950
*/
958951
cached
959-
predicate hasTraitBound() {
960-
Stages::PathResolutionStage::ref() and
961-
exists(this.getABoundPath())
962-
or
963-
exists(this.getAWherePred())
964-
}
952+
predicate hasTraitBound() { Stages::PathResolutionStage::ref() and exists(this.getABoundPath()) }
965953

966954
/**
967955
* Holds if this type parameter has no trait bound. Examples:

rust/ql/lib/codeql/rust/internal/TypeInference.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ private module Input2 implements InputSig2 {
151151
TypeMention getABaseTypeMention(Type t) { none() }
152152

153153
TypeMention getATypeParameterConstraint(TypeParameter tp) {
154-
result = tp.(TypeParamTypeParameter).getTypeParam().getTypeBoundList().getABound().getTypeRepr()
154+
result = tp.(TypeParamTypeParameter).getTypeParam().getATypeBound().getTypeRepr()
155155
or
156156
result = tp.(SelfTypeParameter).getTrait()
157157
or
@@ -184,12 +184,12 @@ private module Input2 implements InputSig2 {
184184
exists(Trait trait |
185185
abs = trait and
186186
condition = trait and
187-
constraint = trait.getTypeBoundList().getABound().getTypeRepr()
187+
constraint = trait.getATypeBound().getTypeRepr()
188188
)
189189
or
190190
// trait bounds on type parameters
191191
exists(TypeParam param |
192-
abs = param.getTypeBoundList().getABound() and
192+
abs = param.getATypeBound() and
193193
condition = param and
194194
constraint = abs.(TypeBound).getTypeRepr()
195195
)

rust/ql/test/library-tests/path-resolution/CONSISTENCY/PathResolutionConsistency.expected

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@ multipleCallTargets
22
| main.rs:118:9:118:11 | f(...) |
33
| proc_macro.rs:9:5:11:5 | ...::new(...) |
44
multiplePathResolutions
5-
| main.rs:626:3:626:12 | proc_macro |
6-
| main.rs:632:7:632:16 | proc_macro |
7-
| main.rs:635:7:635:16 | proc_macro |
5+
| main.rs:641:3:641:12 | proc_macro |
6+
| main.rs:647:7:647:16 | proc_macro |
7+
| main.rs:650:7:650:16 | proc_macro |

rust/ql/test/library-tests/path-resolution/main.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,21 @@ mod m15 {
312312
}
313313
} // I82
314314

315+
#[rustfmt::skip]
316+
trait Trait3<
317+
TT // ITT
318+
>
319+
where
320+
Self: Trait1, // $ item=ITrait3 item=I79
321+
TT: Trait1, // $ item=ITT item=I79
322+
{
323+
fn f(&self, tt: TT) { // $ item=ITT
324+
Self::g(self); // $ item=I80
325+
TT::g(&tt); // $ item=I80
326+
self.g(); // $ item=I80
327+
}
328+
} // ITrait3
329+
315330
struct S; // I81
316331

317332
#[rustfmt::skip]

0 commit comments

Comments
 (0)