Skip to content

Commit 36c3084

Browse files
authored
Merge pull request #21305 from hvitved/rust/type-inference-speedup
Rust: Speedup `inferMethodCallTypeSelf`
2 parents 37af38e + 49f24ca commit 36c3084

File tree

2 files changed

+37
-28
lines changed

2 files changed

+37
-28
lines changed

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

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2477,10 +2477,10 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi
24772477
additional predicate decodeDerefChainBorrow(
24782478
string derefChainBorrow, DerefChain derefChain, BorrowKind borrow
24792479
) {
2480-
exists(string regexp |
2481-
regexp = "^(.*);(.*)$" and
2482-
derefChain = derefChainBorrow.regexpCapture(regexp, 1) and
2483-
borrow.toString() = derefChainBorrow.regexpCapture(regexp, 2)
2480+
exists(int i |
2481+
i = derefChainBorrow.indexOf(";") and
2482+
derefChain = derefChainBorrow.prefix(i) and
2483+
borrow.toString() = derefChainBorrow.suffix(i + 1)
24842484
)
24852485
}
24862486

@@ -2604,37 +2604,39 @@ private Type inferMethodCallTypeNonSelf(AstNode n, boolean isReturn, TypePath pa
26042604
}
26052605

26062606
/**
2607-
* Gets the type of `n` at `path` after applying `derefChain` and `borrow`,
2608-
* where `n` is the `self` argument of a method call.
2607+
* Gets the type of `n` at `path` after applying `derefChain`, where `n` is the
2608+
* `self` argument of a method call.
26092609
*
26102610
* The predicate recursively pops the head of `derefChain` until it becomes
26112611
* empty, at which point the inferred type can be applied back to `n`.
26122612
*/
26132613
pragma[nomagic]
2614-
private Type inferMethodCallTypeSelf(
2615-
AstNode n, DerefChain derefChain, BorrowKind borrow, TypePath path
2616-
) {
2617-
exists(MethodCallMatchingInput::AccessPosition apos, string derefChainBorrow |
2618-
result = inferMethodCallType0(_, apos, n, derefChainBorrow, path) and
2614+
private Type inferMethodCallTypeSelf(AstNode n, DerefChain derefChain, TypePath path) {
2615+
exists(
2616+
MethodCallMatchingInput::AccessPosition apos, string derefChainBorrow, BorrowKind borrow,
2617+
TypePath path0
2618+
|
2619+
result = inferMethodCallType0(_, apos, n, derefChainBorrow, path0) and
26192620
apos.isSelf() and
26202621
MethodCallMatchingInput::decodeDerefChainBorrow(derefChainBorrow, derefChain, borrow)
2621-
)
2622-
or
2623-
// adjust for implicit borrow
2624-
exists(TypePath path0, BorrowKind borrow0 |
2625-
result = inferMethodCallTypeSelf(n, derefChain, borrow0, path0) and
2626-
path0.isCons(borrow0.getRefType().getPositionalTypeParameter(0), path) and
2627-
borrow.isNoBorrow()
2622+
|
2623+
borrow.isNoBorrow() and
2624+
path = path0
2625+
or
2626+
// adjust for implicit borrow
2627+
exists(TypePath prefix |
2628+
prefix = TypePath::singleton(borrow.getRefType().getPositionalTypeParameter(0)) and
2629+
path0 = prefix.appendInverse(path)
2630+
)
26282631
)
26292632
or
26302633
// adjust for implicit deref
26312634
exists(
26322635
DerefChain derefChain0, Type t0, TypePath path0, DerefImplItemNode impl, Type selfParamType,
26332636
TypePath selfPath
26342637
|
2635-
t0 = inferMethodCallTypeSelf(n, derefChain0, borrow, path0) and
2638+
t0 = inferMethodCallTypeSelf(n, derefChain0, path0) and
26362639
derefChain0.isCons(impl, derefChain) and
2637-
borrow.isNoBorrow() and
26382640
selfParamType = impl.resolveSelfTypeAt(selfPath)
26392641
|
26402642
result = selfParamType and
@@ -2653,7 +2655,7 @@ private Type inferMethodCallTypeSelf(
26532655
private Type inferMethodCallTypePreCheck(AstNode n, boolean isReturn, TypePath path) {
26542656
result = inferMethodCallTypeNonSelf(n, isReturn, path)
26552657
or
2656-
result = inferMethodCallTypeSelf(n, DerefChain::nil(), TNoBorrowKind(), path) and
2658+
result = inferMethodCallTypeSelf(n, DerefChain::nil(), path) and
26572659
isReturn = false
26582660
}
26592661

shared/util/codeql/util/UnboundList.qll

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ module Make<LocationSig Location, InputSig<Location> Input> {
7878
/** Holds if this list is empty. */
7979
predicate isEmpty() { this = "" }
8080

81+
bindingset[this]
82+
private int stringLength() { result = super.length() }
83+
8184
/** Gets the length of this list. */
8285
bindingset[this]
8386
pragma[inline_late]
@@ -115,19 +118,23 @@ module Make<LocationSig Location, InputSig<Location> Input> {
115118
/** Holds if this list starts with `e`, followed by `suffix`. */
116119
bindingset[this]
117120
predicate isCons(Element e, UnboundList suffix) {
118-
exists(string regexp | regexp = "^([0-9]+)\\.(.*)$" |
119-
e = decode(this.regexpCapture(regexp, 1)) and
120-
suffix = this.regexpCapture(regexp, 2)
121+
exists(string elem |
122+
// it is more efficient to not create a capture group for the suffix, since
123+
// `regexpCapture` will then always join in both groups, only to afterwards filter
124+
// based on the requested group (the group number is not part of the binding set
125+
// of `regexpCapture`)
126+
elem = this.regexpCapture("^([0-9]+)\\..*$", 1) and
127+
e = decode(elem) and
128+
suffix = this.suffix(elem.length() + 1)
121129
)
122130
}
123131

124132
/** Holds if this list starts with `prefix`, followed by `e`. */
125133
bindingset[this]
126134
predicate isSnoc(UnboundList prefix, Element e) {
127-
exists(string regexp | regexp = "^(|.+\\.)([0-9]+)\\.$" |
128-
prefix = this.regexpCapture(regexp, 1) and
129-
e = decode(this.regexpCapture(regexp, 2))
130-
)
135+
// same remark as above about not using multiple capture groups
136+
prefix = this.regexpCapture("^(|.+\\.)[0-9]+\\.$", 1) and
137+
e = decode(this.substring(prefix.stringLength(), this.stringLength() - 1))
131138
}
132139

133140
/** Gets the head of this list, if any. */

0 commit comments

Comments
 (0)