Skip to content

Commit 7c04c9f

Browse files
committed
Rust: Store arity in tuple type parameters
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.
1 parent 03a9a16 commit 7c04c9f

File tree

6 files changed

+253
-262
lines changed

6 files changed

+253
-262
lines changed

rust/ql/lib/codeql/rust/internal/Type.qll

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ private import codeql.rust.elements.internal.generated.Synth
1010
cached
1111
newtype TType =
1212
TTuple(int arity) {
13-
exists(any(TupleTypeRepr t).getField(arity)) and Stages::TypeInferenceStage::ref()
13+
arity = any(TupleTypeRepr t).getNumberOfFields() and
14+
Stages::TypeInferenceStage::ref()
1415
} or
1516
TStruct(Struct s) or
1617
TEnum(Enum e) or
@@ -19,7 +20,7 @@ newtype TType =
1920
TRefType() or // todo: add mut?
2021
TImplTraitType(ImplTraitTypeRepr impl) or
2122
TSliceType() or
22-
TTupleTypeParameter(int i) { exists(TTuple(i)) } or
23+
TTupleTypeParameter(int arity, int i) { exists(TTuple(arity)) and i in [0 .. arity - 1] } or
2324
TTypeParamTypeParameter(TypeParam t) or
2425
TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or
2526
TArrayTypeParameter() or
@@ -83,7 +84,7 @@ class TupleType extends Type, TTuple {
8384

8485
override TupleField getTupleField(int i) { none() }
8586

86-
override TypeParameter getTypeParameter(int i) { result = TTupleTypeParameter(i) and i < arity }
87+
override TypeParameter getTypeParameter(int i) { result = TTupleTypeParameter(arity, i) }
8788

8889
int getArity() { result = arity }
8990

@@ -358,12 +359,20 @@ class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypePara
358359
* their positional index.
359360
*/
360361
class TupleTypeParameter extends TypeParameter, TTupleTypeParameter {
361-
override string toString() { result = this.getIndex().toString() }
362+
private int arity;
363+
private int index;
364+
365+
TupleTypeParameter() { this = TTupleTypeParameter(arity, index) }
366+
367+
override string toString() { result = index.toString() + "(" + arity + ")" }
362368

363369
override Location getLocation() { result instanceof EmptyLocation }
364370

365371
/** Gets the index of this tuple type parameter. */
366-
int getIndex() { this = TTupleTypeParameter(result) }
372+
int getIndex() { result = index }
373+
374+
/** Gets the arity of this tuple type parameter. */
375+
int getArity() { result = arity }
367376
}
368377

369378
/** An implicit array type parameter. */

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

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,12 @@ private module Input1 implements InputSig1<Location> {
104104
node = tp0.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr()
105105
)
106106
or
107-
kind = 2 and
108-
id = tp0.(TupleTypeParameter).getIndex()
107+
exists(TupleTypeParameter ttp, int maxArity |
108+
maxArity = max(int i | i = any(TupleType tt).getArity()) and
109+
tp0 = ttp and
110+
kind = 2 and
111+
id = ttp.getArity() * maxArity + ttp.getIndex()
112+
)
109113
|
110114
tp0 order by kind, id
111115
)
@@ -324,11 +328,14 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat
324328
prefix1.isEmpty() and
325329
prefix2 = TypePath::singleton(TRefTypeParameter())
326330
or
327-
exists(int i |
331+
exists(int i, int arity |
328332
prefix1.isEmpty() and
329-
prefix2 = TypePath::singleton(TTupleTypeParameter(i))
333+
prefix2 = TypePath::singleton(TTupleTypeParameter(arity, i))
330334
|
331-
n1 = n2.(TupleExpr).getField(i) or
335+
arity = n2.(TupleExpr).getNumberOfFields() and
336+
n1 = n2.(TupleExpr).getField(i)
337+
or
338+
arity = n2.(TuplePat).getNumberOfFields() and
332339
n1 = n2.(TuplePat).getField(i)
333340
)
334341
or
@@ -1077,7 +1084,7 @@ private Type inferTupleIndexExprType(FieldExpr fe, TypePath path) {
10771084
exists(int i, TypePath path0 |
10781085
fe.getIdentifier().getText() = i.toString() and
10791086
result = inferType(fe.getContainer(), path0) and
1080-
path0.isCons(TTupleTypeParameter(i), path) and
1087+
path0.isCons(TTupleTypeParameter(_, i), path) and
10811088
fe.getIdentifier().getText() = i.toString()
10821089
)
10831090
}
@@ -1088,12 +1095,12 @@ private Type inferTupleContainerExprType(Expr e, TypePath path) {
10881095
// a tuple struct or a tuple. It is only correct to let type information flow
10891096
// from `t.n` to tuple type parameters of `t` in the latter case. Hence we
10901097
// include the condition that the root type of `t` must be a tuple type.
1091-
exists(int i, TypePath path0, FieldExpr fe |
1098+
exists(int i, TypePath path0, FieldExpr fe, int arity |
10921099
e = fe.getContainer() and
10931100
fe.getIdentifier().getText() = i.toString() and
1094-
inferType(fe.getContainer()) instanceof TupleType and
1101+
arity = inferType(fe.getContainer()).(TupleType).getArity() and
10951102
result = inferType(fe, path0) and
1096-
path = TypePath::cons(TTupleTypeParameter(i), path0)
1103+
path = TypePath::cons(TTupleTypeParameter(arity, i), path0) // FIXME:
10971104
)
10981105
}
10991106

rust/ql/lib/codeql/rust/internal/TypeMention.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class TupleTypeReprMention extends TypeMention instanceof TupleTypeRepr {
2121
or
2222
exists(TypePath suffix, int i |
2323
result = super.getField(i).(TypeMention).resolveTypeAt(suffix) and
24-
path = TypePath::cons(TTupleTypeParameter(i), suffix)
24+
path = TypePath::cons(TTupleTypeParameter(super.getNumberOfFields(), i), suffix)
2525
)
2626
}
2727
}

rust/ql/test/library-tests/type-inference/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2354,7 +2354,7 @@ mod tuples {
23542354
// `a` and `b` to be inferred.
23552355
let a = Default::default(); // $ target=default type=a:i64
23562356
let b = Default::default(); // $ target=default type=b:bool
2357-
let pair = (a, b); // $ type=pair:0.i64 type=pair:1.bool
2357+
let pair = (a, b); // $ type=pair:0(2).i64 type=pair:1(2).bool
23582358
let i: i64 = pair.0;
23592359
let j: bool = pair.1;
23602360
}

rust/ql/test/library-tests/type-inference/pattern_matching.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ pub fn tuple_patterns() {
460460
// With rest pattern
461461
match tuple {
462462
(first, ..) => {
463-
let tuple_first = first; // $ type=tuple_first:i32
463+
let tuple_first = first; // $ MISSING: type=tuple_first:i32
464464
println!("First element: {}", tuple_first);
465465
}
466466
}
@@ -630,7 +630,7 @@ pub fn rest_patterns() {
630630
// RestPat - Rest patterns (..)
631631
match tuple {
632632
(first, ..) => {
633-
let rest_first = first; // $ type=rest_first:i32
633+
let rest_first = first; // $ MISSING: type=rest_first:i32
634634
println!("First with rest: {}", rest_first);
635635
}
636636
}
@@ -644,7 +644,7 @@ pub fn rest_patterns() {
644644

645645
match tuple {
646646
(first, .., last) => {
647-
let rest_start = first; // $ type=rest_start:i32
647+
let rest_start = first; // $ MISSING: type=rest_start:i32
648648
let rest_end = last; // $ MISSING: type=rest_end:u8
649649
println!("First and last: {}, {}", rest_start, rest_end);
650650
}
@@ -772,7 +772,7 @@ pub fn patterns_in_function_parameters() {
772772
let red = extract_color(color); // $ target=extract_color type=red:u8
773773

774774
let tuple = (42i32, 3.14f64, true);
775-
let tuple_extracted = extract_tuple(tuple); // $ target=extract_tuple type=tuple_extracted:0.i32 type=tuple_extracted:1.bool
775+
let tuple_extracted = extract_tuple(tuple); // $ target=extract_tuple type=tuple_extracted:0(2).i32 type=tuple_extracted:1(2).bool
776776
}
777777

778778
#[rustfmt::skip]

0 commit comments

Comments
 (0)