Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Rust: Type inference for tuples#20041

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
paldepind wants to merge8 commits intogithub:main
base:main
Choose a base branch
Loading
frompaldepind:rust/type-inference-tuples

Conversation

paldepind
Copy link
Contributor

@paldepindpaldepind commentedJul 14, 2025
edited
Loading

Implements type inference for tuples. More specifically tuple expressions (e.g.,(1,2)), tuple indexing (e.g.,tuple.1), and pattern matching on tuples.

Pattern matches with.. in them are not supported.

DCA shows a 1.12% point increase in resolved method calls, type inference inconsistencies is down, and performance seem unaffected.

@github-actionsgithub-actionsbot added the RustPull requests that update Rust code labelJul 14, 2025
Type parameters are required to belong to a single type only. Since we store the arity for tuple types, we need to store the arity in tuple type parameters as well such that we can associate them to the tuple type of the same arity.
@paldepindpaldepind marked this pull request as ready for reviewJuly 15, 2025 09:11
@CopilotCopilotAI review requested due to automatic review settingsJuly 15, 2025 09:11
@paldepindpaldepind requested a review froma team as acode ownerJuly 15, 2025 09:11
Copy link
Contributor

@CopilotCopilotAI 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 implements type inference for tuples in Rust, extending the type system to handle tuple expressions, tuple indexing, and pattern matching on tuples. The changes enable the type inference engine to correctly track type information through tuple creation, field access, and destructuring patterns.

  • Adds support for tuple types and tuple type parameters in the type system
  • Implements type inference for tuple expressions, indexing, and pattern matching
  • Updates type mentions to handle tuple type representations

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.

Show a summary per file
FileDescription
rust/ql/lib/codeql/rust/internal/Type.qllDefines tuple types and tuple type parameters
rust/ql/lib/codeql/rust/internal/TypeInference.qllImplements tuple type inference logic
rust/ql/lib/codeql/rust/internal/TypeMention.qllAdds tuple type representation mentions
rust/ql/test/library-tests/type-inference/type-inference.expectedTest file with .expected extension
rust/ql/test/library-tests/type-inference/pattern_matching.rsUpdates test expectations for tuple patterns
rust/ql/test/library-tests/type-inference/main.rsUpdates test expectations for tuple expressions
rust/ql/test/library-tests/dataflow/local/DataFlowStep.expectedTest file with .expected extension
rust/ql/test/library-tests/dataflow/local/CONSISTENCY/PathResolutionConsistency.expectedTest file with .expected extension
rust/ql/src/change-notes/2025-07-15-type-inference-tuples.mdChangelog entry

Copy link
Contributor

@aibaarsaibaars left a comment

Choose a reason for hiding this comment

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

Looks good to me overall. I have some questions and suggestions. Also could you add a test case like the following where the type information has to flow from a pattern match to other uses and the definition:

let pair =1.into();match pair{(0,0) =>print!("unexpected");}let x = pair.0;

TEnum(Enum e) or
TTrait(Trait t) or
TArrayType() or // todo: add size?
TRefType() or // todo: add mut?
TImplTraitType(ImplTraitTypeRepr impl) or
TSliceType() or
TTupleTypeParameter(int arity, int i) { exists(TTuple(arity)) and i in [0 .. arity - 1] } or
Copy link
Contributor

Choose a reason for hiding this comment

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

This way of definingarity would makeTType's definition recursive, right? Not sure if that is a problem, but we might want to avoid it.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Good question. No recursion markers show up in VScode, so Ithink what's happening is thatTTuple is materialized first and thenTTupleTypeParameter is materialized. SoTTupleTypeParameter depends onTTuple but there is no recursion. I'm just guessing though so maybe I'm wrong.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's fine with me,@hvitved once commented on a case where I defined a recursive type where it wasn't necessary. Not sure if it is a problem here though. In any case if it's easy to rewrite if it turns out to be a problem.

paldepind reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Agree. Let's keep it and change it if it's actually suboptimal.

class TupleType extends Type, TTuple {
private int arity;

TupleType() { this = TTuple(arity) and arity > 0 }
Copy link
Contributor

Choose a reason for hiding this comment

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

Why the restriction that arity must be non-zero? Isn't() just a 0-arity tuple? See also:https://doc.rust-lang.org/reference/types/tuple.html

Suggested change
TupleType(){this=TTuple(arity)andarity>0}
TupleType(){this=TTuple(arity)}

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, lets do that! I wanted to have a classUnitType since I think it's useful to have that concept named, but making it a subclass of tuple still accomplices that and is nicer 👍

@@ -56,8 +60,8 @@ abstract class Type extends TType {
}

/** The unit type `()`. */
class UnitType extends Type, TUnit {
UnitType() { this = TUnit() }
class UnitType extends Type, TTuple {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
classUnitTypeextendsType,TTuple{
classUnitTypeextendsTupleType,TTuple{

Comment on lines 374 to 375
/** Gets the arity of this tuple type parameter. */
int getArity() { result = arity }
Copy link
Contributor

Choose a reason for hiding this comment

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

TypeParameters don't really have an arity, right? Do we need this method for anything? Perhaps it should be replaced by

TypeTypegetTupleType(){result=TTuple(arity)}

Comment on lines 12 to 15
TTuple(int arity) {
arity = any(TupleTypeRepr t).getNumberOfFields() and
Stages::TypeInferenceStage::ref()
} or
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we also include tuple patterns and tuple expression in addition to tuple type reprs?

Suggested change
TTuple(intarity){
arity=any(TupleTypeReprt).getNumberOfFields() and
Stages::TypeInferenceStage::ref()
}or
TTuple(intarity){
(
arity=any(TupleTypeReprt).getNumberOfFields() or
arity=any(TupleExpre).getNumberOfFields() or
arity=any(TuplePatp).getNumberOfFields()
)and
Stages::TypeInferenceStage::ref()
}or

* their positional index.
*/
class TupleTypeParameter extends TypeParameter, TTupleTypeParameter {
private int arity;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it really necessary to havearity as a field? Is it important to distinguish the first element of a pair from the first element of a triple?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Unintuitively the answer is yes. Before7c04c9f arity was not inTupleTypeParameter. But the type inference library relies on the assumption that every type parameter corresponds to exactly one type, so not having the arity caused problems.

I've noted this in the QLdoc forTupleTypeParameter now.

aibaars reacted with thumbs up emoji
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks, I was wondering this as well.


/** Infers the type of `t` in `t.n` when `t` is a tuple. */
private Type inferTupleContainerExprType(Expr e, TypePath path) {
// NOTE: For a field expression `t.n` where `n` is a number `t` might both be
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really understand this comment. I think the following is perfectly fine in rust

structPair(i32,u64);let x =(Pair(1,2)).1;

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Yes, that is the problem :) Inlet i: i64 = foo.1 we cannot say from looking at this syntactically thatfoo hasi64 as it's second tuple element, exactly because it could also be a tuple struct. But iffoois a tuple then we want to make that conclusion.

I've expanded on the comment. Let me know if it is still not clear enough.

@@ -1055,6 +1079,31 @@ private Type inferFieldExprType(AstNode n, TypePath path) {
)
}

pragma[nomagic]
private Type inferTupleIndexExprType(FieldExpr fe, TypePath path) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks fine to me, although I had expected something more similar toinferFieldExprType (or even integrated into that predicate). Or do things really work differently for named fields compared to numeric fields?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I looked into that, butinferFieldExprType uses theMatching module which is about propagating type info from declarations. Tuple types need not correspond to any declaration, so they're different enough that I don't see a clear way to handle them ininferFieldExprType.

@paldepind
Copy link
ContributorAuthor

Thanks for the review. I think I've addressed the suggestions and questions.

Also could you add a test case like the following where the type information has to flow from a pattern match to other uses and the definition:

Done. This also uncovered a gap in the implementation. We never inferred the root tuple type itself from a tuple pattern, only the type of the elements.

Copy link
Contributor

@geoffw0geoffw0 left a comment

Choose a reason for hiding this comment

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

Looks great, I'll have a look at the DCA results as well when that's done...

* their positional index.
*/
class TupleTypeParameter extends TypeParameter, TTupleTypeParameter {
private int arity;
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks, I was wondering this as well.

Co-authored-by: Arthur Baars <aibaars@github.com>
@paldepind
Copy link
ContributorAuthor

The status of this PR is that it's currently blocked as it causes analysis ondatabend to explode. I'm investigating the performance issue which is either caused or exposed by this PR.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@aibaarsaibaarsaibaars left review comments

@geoffw0geoffw0geoffw0 left review comments

Copilot code reviewCopilotCopilot left review comments

At least 1 approving review is required to merge this pull request.

Assignees
No one assigned
Labels
documentationRustPull requests that update Rust code
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

3 participants
@paldepind@aibaars@geoffw0

[8]ページ先頭

©2009-2025 Movatter.jp