Skip to content

Commit 8e19b05

Browse files
authored
Merge pull request #21355 from hvitved/rust/type-inference-unify
Rust: Unify call resolution logic
2 parents 8ddfee9 + 1ac9e5a commit 8e19b05

File tree

18 files changed

+1692
-1503
lines changed

18 files changed

+1692
-1503
lines changed

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,11 @@ module Impl {
3333
result = "impl " + trait + this.getSelfTy().toAbbreviatedString() + " { ... }"
3434
)
3535
}
36+
37+
/**
38+
* Holds if this is an inherent `impl` block, that is, one that does not implement a trait.
39+
*/
40+
pragma[nomagic]
41+
predicate isInherent() { not this.hasTrait() }
3642
}
3743
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ module Impl {
66

77
private newtype TArgumentPosition =
88
TPositionalArgumentPosition(int i) {
9-
i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1]
9+
// For the type `FunctionPosition` used by type inference, we work with function-call syntax
10+
// adjusted positions, so a call like `x.m(a, b, c)` needs positions `0` through `3`; for this
11+
// reason, there is no `- 1` after `max(...)` below.
12+
i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()])]
1013
} or
1114
TSelfArgumentPosition() or
1215
TTypeQualifierArgumentPosition()

rust/ql/lib/codeql/rust/internal/typeinference/BlanketImplementation.qll

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,19 @@ private predicate hasFirstNonTrivialTraitBound(TypeParamItemNode tp, Trait trait
4141
*/
4242
pragma[nomagic]
4343
predicate isBlanketLike(ImplItemNode i, TypePath blanketSelfPath, TypeParam blanketTypeParam) {
44-
blanketTypeParam = i.getBlanketImplementationTypeParam() and
45-
blanketSelfPath.isEmpty()
46-
or
47-
exists(TypeMention tm, Type root, TypeParameter tp |
48-
tm = i.(Impl).getSelfTy() and
49-
complexSelfRoot(root, tp) and
50-
tm.getType() = root and
51-
tm.getTypeAt(blanketSelfPath) = TTypeParamTypeParameter(blanketTypeParam) and
52-
blanketSelfPath = TypePath::singleton(tp) and
53-
hasFirstNonTrivialTraitBound(blanketTypeParam, _)
44+
i.(Impl).hasTrait() and
45+
(
46+
blanketTypeParam = i.getBlanketImplementationTypeParam() and
47+
blanketSelfPath.isEmpty()
48+
or
49+
exists(TypeMention tm, Type root, TypeParameter tp |
50+
tm = i.(Impl).getSelfTy() and
51+
complexSelfRoot(root, tp) and
52+
tm.getType() = root and
53+
tm.getTypeAt(blanketSelfPath) = TTypeParamTypeParameter(blanketTypeParam) and
54+
blanketSelfPath = TypePath::singleton(tp) and
55+
hasFirstNonTrivialTraitBound(blanketTypeParam, _)
56+
)
5457
)
5558
}
5659

rust/ql/lib/codeql/rust/internal/typeinference/FunctionOverloading.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ private predicate functionResolutionDependsOnArgumentCand(
124124
implHasSibling(impl, trait) and
125125
traitTypeParameterOccurrence(trait, _, functionName, pos, path, traitTp) and
126126
f = impl.getASuccessor(functionName) and
127-
not pos.isSelfOrTypeQualifier()
127+
not pos.isTypeQualifier() and
128+
not (f instanceof Method and pos.asPosition() = 0)
128129
)
129130
}
130131

rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll

Lines changed: 35 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,23 @@ private import TypeMention
66
private import TypeInference
77

88
private newtype TFunctionPosition =
9-
TArgumentFunctionPosition(ArgumentPosition pos) or
9+
TArgumentFunctionPosition(ArgumentPosition pos) { not pos.isSelf() } or
1010
TReturnFunctionPosition()
1111

1212
/**
13-
* A position of a type related to a function.
13+
* A function-call adjusted position of a type related to a function.
1414
*
15-
* Either `self`, `return`, or a positional parameter index.
15+
* Either `return` or a positional parameter index, where `self` is translated
16+
* to position `0` and subsequent positional parameters at index `i` are
17+
* translated to position `i + 1`.
18+
*
19+
* Function-call adjusted positions are needed when resolving calls of the
20+
* form `Foo::f(x_1, ..., x_n)`, where we do not know up front whether `f` is a
21+
* method or a non-method, and hence we need to be able to match `x_1` against
22+
* both a potential `self` parameter and a potential first positional parameter
23+
* (and `x_2, ... x_n` against all subsequent positional parameters).
1624
*/
1725
class FunctionPosition extends TFunctionPosition {
18-
predicate isSelf() { this.asArgumentPosition().isSelf() }
19-
2026
int asPosition() { result = this.asArgumentPosition().asPosition() }
2127

2228
predicate isPosition() { exists(this.asPosition()) }
@@ -25,29 +31,18 @@ class FunctionPosition extends TFunctionPosition {
2531

2632
predicate isTypeQualifier() { this.asArgumentPosition().isTypeQualifier() }
2733

28-
predicate isSelfOrTypeQualifier() { this.isSelf() or this.isTypeQualifier() }
29-
3034
predicate isReturn() { this = TReturnFunctionPosition() }
3135

32-
/** Gets the corresponding position when `f` is invoked via a function call. */
33-
bindingset[f]
34-
FunctionPosition getFunctionCallAdjusted(Function f) {
35-
this.isReturn() and
36-
result = this
37-
or
38-
if f.hasSelfParam()
39-
then
40-
this.isSelf() and result.asPosition() = 0
41-
or
42-
result.asPosition() = this.asPosition() + 1
43-
else result = this
44-
}
45-
4636
TypeMention getTypeMention(Function f) {
47-
this.isSelf() and
48-
result = getSelfParamTypeMention(f.getSelfParam())
49-
or
50-
result = f.getParam(this.asPosition()).getTypeRepr()
37+
(
38+
if f instanceof Method
39+
then
40+
result = f.getParam(this.asPosition() - 1).getTypeRepr()
41+
or
42+
result = getSelfParamTypeMention(f.getSelfParam()) and
43+
this.asPosition() = 0
44+
else result = f.getParam(this.asPosition()).getTypeRepr()
45+
)
5146
or
5247
this.isReturn() and
5348
result = getReturnTypeMention(f)
@@ -197,8 +192,7 @@ class AssocFunctionType extends MkAssocFunctionType {
197192
exists(Function f, ImplOrTraitItemNode i, FunctionPosition pos | this.appliesTo(f, i, pos) |
198193
result = pos.getTypeMention(f)
199194
or
200-
pos.isSelf() and
201-
not f.hasSelfParam() and
195+
pos.isTypeQualifier() and
202196
result = [i.(Impl).getSelfTy().(AstNode), i.(Trait).getName()]
203197
)
204198
}
@@ -209,7 +203,7 @@ class AssocFunctionType extends MkAssocFunctionType {
209203
}
210204

211205
pragma[nomagic]
212-
private Trait getALookupTrait(Type t) {
206+
Trait getALookupTrait(Type t) {
213207
result = t.(TypeParamTypeParameter).getTypeParam().(TypeParamItemNode).resolveABound()
214208
or
215209
result = t.(SelfTypeParameter).getTrait()
@@ -310,10 +304,11 @@ signature module ArgsAreInstantiationsOfInputSig {
310304
* Holds if `f` inside `i` needs to have the type corresponding to type parameter
311305
* `tp` checked.
312306
*
313-
* If `i` is an inherent implementation, `tp` is a type parameter of the type being
314-
* implemented, otherwise `tp` is a type parameter of the trait (being implemented).
307+
* `tp` is a type parameter of the trait being implemented by `f` or the trait to which
308+
* `f` belongs.
315309
*
316-
* `pos` is one of the positions in `f` in which the relevant type occours.
310+
* `pos` is one of the function-call adjusted positions in `f` in which the relevant
311+
* type occurs.
317312
*/
318313
predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter tp, FunctionPosition pos);
319314

@@ -360,7 +355,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
360355
private newtype TCallAndPos =
361356
MkCallAndPos(Input::Call call, FunctionPosition pos) { exists(call.getArgType(pos, _)) }
362357

363-
/** A call tagged with a position. */
358+
/** A call tagged with a function-call adjusted position. */
364359
private class CallAndPos extends MkCallAndPos {
365360
Input::Call call;
366361
FunctionPosition pos;
@@ -413,20 +408,21 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
413408

414409
pragma[nomagic]
415410
private predicate argIsInstantiationOf(
416-
Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i, Function f, int rnk
411+
Input::Call call, ImplOrTraitItemNode i, Function f, int rnk
417412
) {
418-
ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and
419-
toCheckRanked(i, f, _, pos, rnk)
413+
exists(FunctionPosition pos |
414+
ArgIsInstantiationOfToIndex::argIsInstantiationOf(MkCallAndPos(call, pos), i, _) and
415+
toCheckRanked(i, f, _, pos, rnk)
416+
)
420417
}
421418

422419
pragma[nomagic]
423420
private predicate argsAreInstantiationsOfToIndex(
424421
Input::Call call, ImplOrTraitItemNode i, Function f, int rnk
425422
) {
426-
exists(FunctionPosition pos |
427-
argIsInstantiationOf(call, pos, i, f, rnk) and
428-
call.hasTargetCand(i, f)
429-
|
423+
argIsInstantiationOf(call, i, f, rnk) and
424+
call.hasTargetCand(i, f) and
425+
(
430426
rnk = 0
431427
or
432428
argsAreInstantiationsOfToIndex(call, i, f, rnk - 1)

0 commit comments

Comments
 (0)