-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
21c030f
03a9a16
7c04c9f
97e7794
8858f21
a508089
bbd7ed5
7f8829a
6b366d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -9,14 +9,17 @@ private import codeql.rust.elements.internal.generated.Synth | |||||
|
||||||
cached | ||||||
newtype TType = | ||||||
TUnit() or | ||||||
TStruct(Struct s) { Stages::TypeInferenceStage::ref() } or | ||||||
TTuple(int arity) { | ||||||
exists(any(TupleTypeRepr t).getField(arity)) and Stages::TypeInferenceStage::ref() | ||||||
} or | ||||||
TStruct(Struct s) or | ||||||
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 i) { exists(TTuple(i)) } or | ||||||
TTypeParamTypeParameter(TypeParam t) or | ||||||
TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or | ||||||
TArrayTypeParameter() or | ||||||
|
@@ -56,8 +59,8 @@ abstract class Type extends TType { | |||||
} | ||||||
|
||||||
/** The unit type `()`. */ | ||||||
class UnitType extends Type, TUnit { | ||||||
UnitType() { this = TUnit() } | ||||||
class UnitType extends Type, TTuple { | ||||||
UnitType() { this = TTuple(0) } | ||||||
|
||||||
override StructField getStructField(string name) { none() } | ||||||
|
||||||
|
@@ -70,6 +73,25 @@ class UnitType extends Type, TUnit { | |||||
override Location getLocation() { result instanceof EmptyLocation } | ||||||
} | ||||||
|
||||||
/** A tuple type `(T, ...)`. */ | ||||||
class TupleType extends Type, TTuple { | ||||||
private int arity; | ||||||
|
||||||
TupleType() { this = TTuple(arity) and arity > 0 } | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the restriction that arity must be non-zero? Isn't
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, lets do that! I wanted to have a class |
||||||
|
||||||
override StructField getStructField(string name) { none() } | ||||||
|
||||||
override TupleField getTupleField(int i) { none() } | ||||||
|
||||||
override TypeParameter getTypeParameter(int i) { result = TTupleTypeParameter(i) and i < arity } | ||||||
|
||||||
int getArity() { result = arity } | ||||||
|
||||||
override string toString() { result = "(T_" + arity + ")" } | ||||||
|
||||||
override Location getLocation() { result instanceof EmptyLocation } | ||||||
} | ||||||
|
||||||
abstract private class StructOrEnumType extends Type { | ||||||
abstract ItemNode asItemNode(); | ||||||
} | ||||||
|
@@ -329,6 +351,21 @@ class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypePara | |||||
override Location getLocation() { result = typeAlias.getLocation() } | ||||||
} | ||||||
|
||||||
/** | ||||||
* A tuple type parameter. For instance the `T` in `(T, U)`. | ||||||
* | ||||||
* Since tuples are structural their parameters can be represented simply as | ||||||
* their positional index. | ||||||
*/ | ||||||
class TupleTypeParameter extends TypeParameter, TTupleTypeParameter { | ||||||
override string toString() { result = this.getIndex().toString() } | ||||||
|
||||||
override Location getLocation() { result instanceof EmptyLocation } | ||||||
|
||||||
/** Gets the index of this tuple type parameter. */ | ||||||
int getIndex() { this = TTupleTypeParameter(result) } | ||||||
} | ||||||
|
||||||
/** An implicit array type parameter. */ | ||||||
class ArrayTypeParameter extends TypeParameter, TArrayTypeParameter { | ||||||
override string toString() { result = "[T;...]" } | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -103,6 +103,9 @@ private module Input1 implements InputSig1<Location> { | |
node = tp0.(SelfTypeParameter).getTrait() or | ||
node = tp0.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr() | ||
) | ||
or | ||
kind = 2 and | ||
id = tp0.(TupleTypeParameter).getIndex() | ||
| | ||
tp0 order by kind, id | ||
) | ||
|
@@ -229,7 +232,7 @@ private Type inferLogicalOperationType(AstNode n, TypePath path) { | |
private Type inferAssignmentOperationType(AstNode n, TypePath path) { | ||
n instanceof AssignmentOperation and | ||
path.isEmpty() and | ||
result = TUnit() | ||
result instanceof UnitType | ||
} | ||
|
||
pragma[nomagic] | ||
|
@@ -321,6 +324,14 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat | |
prefix1.isEmpty() and | ||
prefix2 = TypePath::singleton(TRefTypeParameter()) | ||
or | ||
exists(int i | | ||
prefix1.isEmpty() and | ||
prefix2 = TypePath::singleton(TTupleTypeParameter(i)) | ||
| | ||
n1 = n2.(TupleExpr).getField(i) or | ||
n1 = n2.(TuplePat).getField(i) | ||
) | ||
or | ||
exists(BlockExpr be | | ||
n1 = be and | ||
n2 = be.getStmtList().getTailExpr() and | ||
|
@@ -534,6 +545,12 @@ private Type inferStructExprType(AstNode n, TypePath path) { | |
) | ||
} | ||
|
||
pragma[nomagic] | ||
private Type inferTupleExprRootType(TupleExpr te) { | ||
// `typeEquality` handles the non-root case | ||
result = TTuple(te.getNumberOfFields()) | ||
} | ||
|
||
pragma[nomagic] | ||
private Type inferPathExprType(PathExpr pe, TypePath path) { | ||
// nullary struct/variant constructors | ||
|
@@ -1055,6 +1072,31 @@ private Type inferFieldExprType(AstNode n, TypePath path) { | |
) | ||
} | ||
|
||
pragma[nomagic] | ||
private Type inferTupleIndexExprType(FieldExpr fe, TypePath path) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks fine to me, although I had expected something more similar to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I looked into that, but |
||
exists(int i, TypePath path0 | | ||
fe.getIdentifier().getText() = i.toString() and | ||
result = inferType(fe.getContainer(), path0) and | ||
path0.isCons(TTupleTypeParameter(i), path) and | ||
fe.getIdentifier().getText() = i.toString() | ||
) | ||
} | ||
|
||
/** 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 struct Pair (i32, u64) ;
let x = (Pair (1,2)).1; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that is the problem :) In I've expanded on the comment. Let me know if it is still not clear enough. |
||
// a tuple struct or a tuple. It is only correct to let type information flow | ||
// from `t.n` to tuple type parameters of `t` in the latter case. Hence we | ||
// include the condition that the root type of `t` must be a tuple type. | ||
exists(int i, TypePath path0, FieldExpr fe | | ||
e = fe.getContainer() and | ||
fe.getIdentifier().getText() = i.toString() and | ||
inferType(fe.getContainer()) instanceof TupleType and | ||
result = inferType(fe, path0) and | ||
path = TypePath::cons(TTupleTypeParameter(i), path0) | ||
) | ||
} | ||
|
||
/** Gets the root type of the reference node `ref`. */ | ||
pragma[nomagic] | ||
private Type inferRefNodeType(AstNode ref) { | ||
|
@@ -1943,12 +1985,19 @@ private module Cached { | |
or | ||
result = inferStructExprType(n, path) | ||
or | ||
result = inferTupleExprRootType(n) and | ||
path.isEmpty() | ||
or | ||
result = inferPathExprType(n, path) | ||
or | ||
result = inferCallExprBaseType(n, path) | ||
or | ||
result = inferFieldExprType(n, path) | ||
or | ||
result = inferTupleIndexExprType(n, path) | ||
or | ||
result = inferTupleContainerExprType(n, path) | ||
or | ||
result = inferRefNodeType(n) and | ||
path.isEmpty() | ||
or | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.