Skip to content

Rust: Type inference for .await expressions #19584

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 6 commits into from
Jun 10, 2025

Conversation

hvitved
Copy link
Contributor

@hvitved hvitved commented May 26, 2025

Adds type inference support for .await expressions. Since functions can be either implicitly asynchronous, using the async keyword, or explicitly using an impl Future<Output = ...> return type, this PR also add support for associated type argument (Output = ...) and impl Trait types.

DCA looks great: We increase Percentage of calls with call target by 1 percentage point, but this PR also fixes a performance issue resulting in a massive 61 % analysis time speedup.

@github-actions github-actions bot added the Rust Pull requests that update Rust code label May 26, 2025
@hvitved hvitved force-pushed the rust/type-inference-await branch 2 times, most recently from 92e4659 to 25b928d Compare May 27, 2025 11:59
@hvitved hvitved marked this pull request as ready for review May 28, 2025 06:32
@Copilot Copilot AI review requested due to automatic review settings May 28, 2025 06:32
@hvitved hvitved requested a review from a team as a code owner May 28, 2025 06:32
@hvitved hvitved requested a review from paldepind May 28, 2025 06:32
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 enhances the Rust type inference engine to support .await expressions, associated type arguments (Output = ...), and impl Trait types.

  • Add new async_ and impl_trait tests exercising .await and impl Trait inference.
  • Update expected outputs for type‐inference tests to include await and impl Trait cases.
  • Extend QL libraries (TypeMention.qll, TypeInference.qll, Type.qll, Stdlib.qll) to resolve associated types, impl Trait parameters, and infer await expressions.

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
rust/ql/test/library-tests/type-inference/main.rs Add async_ and impl_trait modules and invoke new test functions
rust/ql/test/library-tests/type-inference/type-inference.expected Update expected inference output to cover .await and impl Trait cases
rust/ql/lib/codeql/rust/internal/TypeMention.qll Support associated type arguments and impl Trait mentions in types
rust/ql/lib/codeql/rust/internal/TypeInference.qll Implement inferAwaitExprType, extend method resolution for impl Trait
rust/ql/lib/codeql/rust/internal/Type.qll Define TImplTraitType, TImplTraitTypeParameter, and related classes
rust/ql/lib/codeql/rust/frameworks/stdlib/Stdlib.qll Introduce FutureTrait with its Output associated type
Comments suppressed due to low confidence (2)

rust/ql/lib/codeql/rust/internal/TypeInference.qll:1195

  • [nitpick] This only resolves the first impl Trait bound. For multi-bound impl Trait types, consider iterating over all TImplTraitTypeParameter(_, _) parameters so methods on any bound are discovered.
result = getTraitMethod(mc.getTypeAt(TypePath::singleton(TImplTraitTypeParameter(_, _))), mc.getMethodName())

rust/ql/lib/codeql/rust/internal/TypeInference.qll:248

  • In the typeEquality predicate, matching n2 = any(BlockExpr be | ...) could match unrelated block expressions. It should constrain be to the actual n2 (e.g. be = n2.(BlockExpr)) to avoid spurious matches.
n2 =

@@ -77,6 +77,16 @@ private module Input1 implements InputSig1<Location> {
apos.asMethodTypeArgumentPosition() = ppos.asTypeParam().getPosition()
}

private int getImplTraitTypeParameterId(ImplTraitTypeParameter tp) {
Copy link
Preview

Copilot AI May 28, 2025

Choose a reason for hiding this comment

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

The getImplTraitTypeParameterId function uses rank[result] but never assigns result. To return the intended integer ID, add result = id after the rank expression or switch to rank[id].

Copilot uses AI. Check for mistakes.

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.

Since impl types implement traits we should have a case for them in conditionSatisfiesConstraint. It would also be great to have a test covering that. Something like the following should pass with impl added to conditionSatisfiesConstraint:

trait MyTrait<A> {
    fn get_a(&self) -> A;
}

impl MyTrait<S2> for S1 {
    fn get_a(&self) -> S2 {
        S2
    }
}

fn get_a_my_trait() -> impl MyTrait<S2> {
    S1
}

fn uses_my_trait<A, B: MyTrait<A>>(t: B) -> A {
    t.get_a() // $ method=MyTrait::get_a
}

fn test() {
    let a = get_a_my_trait();
    let b = uses_my_trait(a); // $ type=b:S2
}

@hvitved hvitved force-pushed the rust/type-inference-await branch from 25b928d to 80d91e2 Compare June 2, 2025 19:29
@hvitved hvitved added the no-change-note-required This PR does not need a change note label Jun 2, 2025
@hvitved hvitved force-pushed the rust/type-inference-await branch 2 times, most recently from 14b8af8 to 15ca62e Compare June 3, 2025 07:50
@hvitved hvitved requested a review from paldepind June 3, 2025 08:08
@hvitved
Copy link
Contributor Author

hvitved commented Jun 3, 2025

@paldepind : PR is ready for review again. I have rebased to resolve merge conflicts; only the last two commits need reviewing.

@hvitved hvitved force-pushed the rust/type-inference-await branch from 15ca62e to 2ebb619 Compare June 4, 2025 19:12
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 for addressing my comments.

PR looks really great and what a performance improvement 🤩

I've left a few minor review comments.

As a high-level remark it seems to me that the Matching module is a bit heavy-handed for something like .await. Going forward it might make sense to think about other abstractions that could handle something like .await with less boilerplate.

@hvitved hvitved requested a review from paldepind June 10, 2025 09:56
@hvitved hvitved force-pushed the rust/type-inference-await branch from 54f2945 to bf58b6c Compare June 10, 2025 10:39
class AssocTypeArg extends Generated::AssocTypeArg {
/** Gets the type representation for the associated type argument `name`. */
pragma[nomagic]
TypeRepr getTypeRepr(string name) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Might just be me, but this signature gives me the impression that an AssocTypeArg has several different TypeReprs for different names?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right; I have pushed a change that moves this into GenericArgList instead.

@hvitved hvitved force-pushed the rust/type-inference-await branch from bf58b6c to 3d395dd Compare June 10, 2025 11:39
@hvitved hvitved requested a review from paldepind June 10, 2025 11:53
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.

Seems like the CI is disagreeing about some versions, but otherwise LGTM!

@hvitved hvitved merged commit 791369d into github:main Jun 10, 2025
38 of 39 checks passed
@hvitved hvitved deleted the rust/type-inference-await branch June 10, 2025 12:56
@hvitved hvitved mentioned this pull request Jun 10, 2025
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