Skip to content

Commit 7d0509b

Browse files
authored
Merge pull request #20282 from hvitved/rust/type-inference-method-call-resolution-rework
Rust: Rework call resolution and type inference for calls
2 parents 83f9fb1 + cf05414 commit 7d0509b

39 files changed

+7937
-6127
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: majorAnalysis
3+
---
4+
* Resolution of calls to functions has been improved in a number of ways, to make it more aligned with the behavior of the Rust compiler. This may impact queries that rely on call resolution, such as data flow queries.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ private import codeql.rust.elements.internal.ExprImpl::Impl as ExprImpl
1212
* the canonical path `path` and the method name `method`, and if it borrows its
1313
* first `borrows` arguments.
1414
*/
15-
private predicate isOverloaded(string op, int arity, string path, string method, int borrows) {
15+
predicate isOverloaded(string op, int arity, string path, string method, int borrows) {
1616
arity = 1 and
1717
(
1818
// Negation

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ module Impl {
4747
*/
4848
TypeBound getATypeBound() { result = this.getTypeBound(_) }
4949

50+
/** Holds if this type parameter has at least one type bound. */
51+
predicate hasTypeBound() { exists(this.getATypeBound()) }
52+
5053
override string toAbbreviatedString() { result = this.getName().getText() }
5154

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

rust/ql/lib/codeql/rust/frameworks/stdlib/Stdlib.qll

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,96 @@ class StringStruct extends Struct {
213213
pragma[nomagic]
214214
StringStruct() { this.getCanonicalPath() = "alloc::string::String" }
215215
}
216+
217+
/**
218+
* The [`Deref` trait][1].
219+
*
220+
* [1]: https://doc.rust-lang.org/core/ops/trait.Deref.html
221+
*/
222+
class DerefTrait extends Trait {
223+
pragma[nomagic]
224+
DerefTrait() { this.getCanonicalPath() = "core::ops::deref::Deref" }
225+
226+
/** Gets the `deref` function. */
227+
Function getDerefFunction() { result = this.(TraitItemNode).getAssocItem("deref") }
228+
229+
/** Gets the `Target` associated type. */
230+
pragma[nomagic]
231+
TypeAlias getTargetType() {
232+
result = this.getAssocItemList().getAnAssocItem() and
233+
result.getName().getText() = "Target"
234+
}
235+
}
236+
237+
/**
238+
* The [`Index` trait][1].
239+
*
240+
* [1]: https://doc.rust-lang.org/std/ops/trait.Index.html
241+
*/
242+
class IndexTrait extends Trait {
243+
pragma[nomagic]
244+
IndexTrait() { this.getCanonicalPath() = "core::ops::index::Index" }
245+
246+
/** Gets the `index` function. */
247+
Function getIndexFunction() { result = this.(TraitItemNode).getAssocItem("index") }
248+
249+
/** Gets the `Output` associated type. */
250+
pragma[nomagic]
251+
TypeAlias getOutputType() {
252+
result = this.getAssocItemList().getAnAssocItem() and
253+
result.getName().getText() = "Output"
254+
}
255+
}
256+
257+
/**
258+
* The [`Box` struct][1].
259+
*
260+
* [1]: https://doc.rust-lang.org/std/boxed/struct.Box.html
261+
*/
262+
class BoxStruct extends Struct {
263+
pragma[nomagic]
264+
BoxStruct() { this.getCanonicalPath() = "alloc::boxed::Box" }
265+
}
266+
267+
/**
268+
* The [`Rc` struct][1].
269+
*
270+
* [1]: https://doc.rust-lang.org/std/rc/struct.Rc.html
271+
*/
272+
class RcStruct extends Struct {
273+
pragma[nomagic]
274+
RcStruct() { this.getCanonicalPath() = "alloc::rc::Rc" }
275+
}
276+
277+
/**
278+
* The [`Arc` struct][1].
279+
*
280+
* [1]: https://doc.rust-lang.org/std/sync/struct.Arc.html
281+
*/
282+
class ArcStruct extends Struct {
283+
pragma[nomagic]
284+
ArcStruct() { this.getCanonicalPath() = "alloc::sync::Arc" }
285+
}
286+
287+
/**
288+
* The [`Pin` struct][1].
289+
*
290+
* [1]: https://doc.rust-lang.org/std/pin/struct.Pin.html
291+
*/
292+
class PinStruct extends Struct {
293+
pragma[nomagic]
294+
PinStruct() { this.getCanonicalPath() = "core::pin::Pin" }
295+
}
296+
297+
/**
298+
* The [`Vec` struct][1].
299+
*
300+
* [1]: https://doc.rust-lang.org/alloc/vec/struct.Vec.html
301+
*/
302+
class Vec extends Struct {
303+
pragma[nomagic]
304+
Vec() { this.getCanonicalPath() = "alloc::vec::Vec" }
305+
306+
/** Gets the type parameter representing the element type. */
307+
TypeParam getElementTypeParam() { result = this.getGenericParamList().getTypeParam(0) }
308+
}

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

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -840,7 +840,7 @@ final class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
840840
}
841841
}
842842

843-
final private class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
843+
final class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr {
844844
pragma[nomagic]
845845
Path getABoundPath() {
846846
result = super.getTypeBoundList().getABound().getTypeRepr().(PathTypeRepr).getPath()
@@ -963,7 +963,9 @@ final class TraitItemNode extends ImplOrTraitItemNode, TypeItemNode instanceof T
963963
Path getABoundPath() { result = super.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() }
964964

965965
pragma[nomagic]
966-
ItemNode resolveABound() { result = resolvePath(this.getABoundPath()) }
966+
ItemNode resolveBound(Path path) { path = this.getABoundPath() and result = resolvePath(path) }
967+
968+
ItemNode resolveABound() { result = this.resolveBound(_) }
967969

968970
override AssocItemNode getAnAssocItem() { result = this.getADescendant() }
969971

@@ -1643,25 +1645,55 @@ signature predicate relevantTraitVisibleSig(Element element, Trait trait);
16431645
* at a given element.
16441646
*/
16451647
module TraitIsVisible<relevantTraitVisibleSig/2 relevantTraitVisible> {
1646-
/** Holds if the trait might be looked up in `encl`. */
1647-
private predicate traitLookup(ItemNode encl, Element element, Trait trait) {
1648-
// lookup in immediately enclosing item
1649-
relevantTraitVisible(element, trait) and
1650-
encl.getADescendant() = element
1648+
private newtype TNode =
1649+
TTrait(Trait t) { relevantTraitVisible(_, t) } or
1650+
TItemNode(ItemNode i) or
1651+
TElement(Element e) { relevantTraitVisible(e, _) }
1652+
1653+
private predicate isTrait(TNode n) { n instanceof TTrait }
1654+
1655+
private predicate step(TNode n1, TNode n2) {
1656+
exists(Trait t1, ItemNode i2 |
1657+
n1 = TTrait(t1) and
1658+
n2 = TItemNode(i2) and
1659+
t1 = i2.getASuccessor(_, _, _)
1660+
)
16511661
or
1652-
// lookup in an outer scope, but only if the trait is not declared in inner scope
1653-
exists(ItemNode mid |
1654-
traitLookup(mid, element, trait) and
1655-
not trait = mid.getASuccessor(_, _, _) and
1656-
encl = getOuterScope(mid)
1662+
exists(ItemNode i1, ItemNode i2 |
1663+
n1 = TItemNode(i1) and
1664+
n2 = TItemNode(i2) and
1665+
i1 = getOuterScope(i2)
1666+
)
1667+
or
1668+
exists(ItemNode i1, Element e2 |
1669+
n1 = TItemNode(i1) and
1670+
n2 = TElement(e2) and
1671+
i1.getADescendant() = e2
1672+
)
1673+
}
1674+
1675+
private predicate isElement(TNode n) { n instanceof TElement }
1676+
1677+
private predicate traitIsVisibleTC(TNode trait, TNode element) =
1678+
doublyBoundedFastTC(step/2, isTrait/1, isElement/1)(trait, element)
1679+
1680+
pragma[nomagic]
1681+
private predicate relevantTraitVisibleLift(TNode trait, TElement element) {
1682+
exists(Trait t, Element e |
1683+
trait = TTrait(t) and
1684+
element = TElement(e) and
1685+
relevantTraitVisible(e, t)
16571686
)
16581687
}
16591688

16601689
/** Holds if the trait `trait` is visible at `element`. */
16611690
pragma[nomagic]
16621691
predicate traitIsVisible(Element element, Trait trait) {
1663-
exists(ItemNode encl |
1664-
traitLookup(encl, element, trait) and trait = encl.getASuccessor(_, _, _)
1692+
exists(TNode t, TNode e |
1693+
traitIsVisibleTC(t, e) and
1694+
relevantTraitVisibleLift(t, e) and
1695+
t = TTrait(trait) and
1696+
e = TElement(element)
16651697
)
16661698
}
16671699
}
@@ -2101,7 +2133,7 @@ private predicate builtin(string name, ItemNode i) {
21012133

21022134
/** Provides predicates for debugging the path resolution implementation. */
21032135
private module Debug {
2104-
private Locatable getRelevantLocatable() {
2136+
Locatable getRelevantLocatable() {
21052137
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
21062138
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
21072139
filepath.matches("%/main.rs") and

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ private import TypeMention
66
private import codeql.rust.internal.CachedStages
77
private import codeql.rust.elements.internal.generated.Raw
88
private import codeql.rust.elements.internal.generated.Synth
9+
private import codeql.rust.frameworks.stdlib.Stdlib
910

1011
/**
1112
* Holds if a dyn trait type should have a type parameter associated with `n`. A
@@ -624,3 +625,32 @@ final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeR
624625
implTraitTypeParam(this, _, result.(TypeParamTypeParameter).getTypeParam())
625626
}
626627
}
628+
629+
/**
630+
* Holds if `t` is a valid complex [`self` root type][1].
631+
*
632+
* [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html#r-items.associated.fn.method.self-ty
633+
*/
634+
pragma[nomagic]
635+
predicate validSelfType(Type t) {
636+
t instanceof RefType
637+
or
638+
exists(Struct s | t = TStruct(s) |
639+
s instanceof BoxStruct or
640+
s instanceof RcStruct or
641+
s instanceof ArcStruct or
642+
s instanceof PinStruct
643+
)
644+
}
645+
646+
/**
647+
* Holds if `root` is a valid complex [`self` root type][1], with type
648+
* parameter `tp`.
649+
*
650+
* [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html#r-items.associated.fn.method.self-ty
651+
*/
652+
pragma[nomagic]
653+
predicate complexSelfRoot(Type root, TypeParameter tp) {
654+
validSelfType(root) and
655+
tp = root.getPositionalTypeParameter(0)
656+
}

0 commit comments

Comments
 (0)