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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy