Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Rust: Improve performance of type inference #19534

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 21, 2025

Conversation

hvitved
Copy link
Contributor

@hvitved hvitved commented May 20, 2025

This PR speeds up type inference by

  1. avoiding the strictcount aggregate,
  2. avoiding a run-time negation that can be done at compile-time, and
  3. avoiding checking for type path lengths when deconstructing existing type paths that have already been checked.

DCA shows an impressive 65 % analysis time speedup on rust-lang/rust.

@github-actions github-actions bot added the Rust Pull requests that update Rust code label May 20, 2025
@hvitved hvitved marked this pull request as ready for review May 20, 2025 13:02
@Copilot Copilot AI review requested due to automatic review settings May 20, 2025 13:02
@hvitved hvitved requested a review from a team as a code owner May 20, 2025 13:02
@hvitved hvitved requested a review from paldepind May 20, 2025 13:02
@hvitved hvitved added the no-change-note-required This PR does not need a change note label May 20, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR optimizes type inference by eliminating certain aggregates and runtime checks, replacing them with compile-time computations, and introduces inverse-append helpers to skip redundant path‐length validations.

  • Introduce length2() to compute type-path segment counts without strictcount
  • Replace append with bounds-checked logic and add appendInverse for deconstructing paths
  • Update all call sites to use appendInverse where appropriate

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
shared/typeinference/codeql/typeinference/internal/TypeInference.qll Replaced strictcount use with length2(), refactored length(), introduced appendInverse and updated call sites
rust/ql/lib/codeql/rust/internal/TypeInference.qll Added typeEqualityLeft/Right predicates, switched to consInverse in inference and replaced old prefix-based logic
Comments suppressed due to low confidence (2)

shared/typeinference/codeql/typeinference/internal/TypeInference.qll:187

  • [nitpick] The name length2 is not descriptive of its purpose (counting path segments). Consider renaming it to something like segmentCount or dotCountPlusOne for clarity.
private int length2() {

shared/typeinference/codeql/typeinference/internal/TypeInference.qll:191

  • Using regexpReplaceAll for every path may be costly on very long strings. After fixing the bug above, consider benchmarking or using a direct dot-counting approach if QL provides one to ensure this remains faster than strictcount.
result = this.regexpReplaceAll("[0-9]+", "").length() + 1

Comment on lines +225 to +228
* Gets the path obtained by appending `suffix` onto this path.
*
* Unlike `append`, this predicate has `result` in the binding set,
* so there is no need to check the length of `result`.
Copy link
Preview

Copilot AI May 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation for appendInverse is copied from append but this predicate actually deconstructs a full path into this and suffix. Please update the comment to describe the inverse operation.

Suggested change
* Gets the path obtained by appending `suffix` onto this path.
*
* Unlike `append`, this predicate has `result` in the binding set,
* so there is no need to check the length of `result`.
* Deconstructs a full path `result` into `this` and `suffix`.
*
* This predicate performs the inverse operation of `append`. It holds if
* `result` is a path that can be split into `this` as the prefix and
* `suffix` as the remainder. For example, if `result` is "a.b.c" and
* `this` is "a.b", then `suffix` would be "c".

Copilot uses AI. Check for mistakes.

Positive FeedbackNegative Feedback
rust/ql/lib/codeql/rust/internal/TypeInference.qll Outdated Show resolved Hide resolved
Copy link
Contributor

@paldepind paldepind left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow. Really impressive speedup!

* onto `suffix`.
*/
bindingset[result]
TypePath consInverse(TypeParameter tp, TypePath suffix) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consInverse is equivalent to isCons but with a different parameter order.

I find isCons easer to read as it's the result that is the output and since the name is easier to understand. Looking at the places where consInverse is used there's only one spot where it's not trivial to use isCons instead. Given that, I think it would make sense to remove consInverse and use isCons instead.

* so there is no need to check the length of `result`.
*/
bindingset[this, result]
TypePath appendInverse(TypePath suffix) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A variant of this where the result is the output could be:

    bindingset[this, prefix]
    TypePath stripPrefix(TypePath prefix) { this = prefix.appendInverse(result) }

Similar to my comment for consInverse I find that more natural. However, unlike for isCons this variant is less convenient in all the places where appendInverse is used. But perhaps we could introduce stripPrefix, define appendInverse in terms of stripPrefix, and use stripPrefix in the (few if any) cases where it's not inconvenient?

this.isEmpty() and result = 0
or
result = strictcount(this.indexOf(".")) + 1
if this.isEmpty()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps depth would actually be a better name than length?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't depth lead to the misconception that it is a tree instead of a list?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe? To me it feel natural to say that the depth of foo/bar/baz is 3, but let's just keep it as-if if you feel it's not as clear.

/** Gets the length of this path, assuming the length is at least 2. */
bindingset[this]
pragma[inline_late]
private int length2() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe depthFrom2?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or lengthFrom2.

@hvitved hvitved force-pushed the rust/type-inference-performance branch from 39423fd to 856021c Compare May 21, 2025 12:03
@hvitved hvitved force-pushed the rust/type-inference-performance branch from 856021c to 13861b8 Compare May 21, 2025 12:10
@hvitved hvitved requested a review from paldepind May 21, 2025 12:20
Copy link
Contributor

@paldepind paldepind left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! LGTM 🎉

@hvitved hvitved merged commit 41e4ada into github:main May 21, 2025
38 checks passed
@hvitved hvitved deleted the rust/type-inference-performance branch May 21, 2025 18:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
no-change-note-required This PR does not need a change note Rust Pull requests that update Rust code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.