Skip to content

Commit a1d36c0

Browse files
committed
Rust: Implement support for inference of type aliases
1 parent e7027f0 commit a1d36c0

File tree

3 files changed

+85
-12
lines changed

3 files changed

+85
-12
lines changed

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

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,25 @@ class TypeReprMention extends TypeMention, TypeRepr {
5353
or
5454
result = this.(PathTypeRepr).getPath().(PathMention).resolveType()
5555
}
56+
57+
override Type resolveTypeAt(TypePath path) {
58+
result = this.(PathTypeRepr).getPath().(PathMention).resolveTypeAt(path)
59+
or
60+
not exists(this.(PathTypeRepr).getPath()) and
61+
result = super.resolveTypeAt(path)
62+
}
63+
}
64+
65+
/** Holds if `path` resolves the type alias `alias` with the definition `rhs`. */
66+
private predicate resolvePathAlias(Path path, TypeAlias alias, TypeReprMention rhs) {
67+
alias = resolvePath(path) and rhs = alias.getTypeRepr()
5668
}
5769

58-
class PathMention extends TypeMention, Path {
70+
abstract class PathMention extends TypeMention, Path { }
71+
72+
class NonAliasPathMention extends PathMention {
73+
NonAliasPathMention() { not resolvePathAlias(this, _, _) }
74+
5975
override TypeMention getTypeArgument(int i) {
6076
result = this.getSegment().getGenericArgList().getTypeArg(i)
6177
or
@@ -98,6 +114,37 @@ class PathMention extends TypeMention, Path {
98114
}
99115
}
100116

117+
class AliasPathMention extends PathMention {
118+
TypeAlias alias;
119+
TypeReprMention rhs;
120+
121+
AliasPathMention() { resolvePathAlias(this, alias, rhs) }
122+
123+
override TypeMention getTypeArgument(int i) {
124+
result = this.getSegment().getGenericArgList().getTypeArg(i)
125+
}
126+
127+
/** Get the `i`th type parameter of the alias itself. */
128+
private TypeParameter getTypeParameter(int i) {
129+
result = TTypeParamTypeParameter(alias.getGenericParamList().getTypeParam(i))
130+
}
131+
132+
override Type resolveType() { result = rhs.resolveType() }
133+
134+
override Type resolveTypeAt(TypePath path) {
135+
result = rhs.resolveTypeAt(path) and
136+
not result = this.getTypeParameter(_)
137+
or
138+
exists(TypeParameter tp, TypeMention arg, TypePath prefix, TypePath suffix, int i |
139+
tp = rhs.resolveTypeAt(prefix) and
140+
tp = this.getTypeParameter(i) and
141+
arg = this.getTypeArgument(i) and
142+
result = arg.resolveTypeAt(suffix) and
143+
path = prefix.append(suffix)
144+
)
145+
}
146+
}
147+
101148
// Used to represent implicit `Self` type arguments in traits and `impl` blocks,
102149
// see `PathMention` for details.
103150
class TypeParamMention extends TypeMention, TypeParam {

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -569,11 +569,11 @@ mod type_aliases {
569569
// Alias to another alias
570570
type AliasToAlias<A4> = AnotherPair<A4>;
571571

572-
// Alias that appears nested withing another alias
572+
// Alias that appears nested within another alias
573573
type NestedAlias<A5> = AnotherPair<AliasToAlias<A5>>;
574574

575575
fn g(t: NestedAlias<S3>) {
576-
let x = t.unwrapSnd().unwrapSnd(); // $ method=unwrapSnd MISSING: type=x:S3
576+
let x = t.unwrapSnd().unwrapSnd(); // $ method=unwrapSnd type=x:S3
577577
println!("{:?}", x);
578578
}
579579

@@ -583,15 +583,15 @@ mod type_aliases {
583583
println!("{:?}", p1);
584584

585585
// Type can be only inferred from the type alias
586-
let p2: MyPair = PairOption::PairNone(); // $ MISSING: type=p2:Fst.S1 MISSING: type=p2:Snd.S2
586+
let p2: MyPair = PairOption::PairNone(); // $ type=p2:Fst.S1 type=p2:Snd.S2
587587
println!("{:?}", p2);
588588

589589
// First type from alias, second from constructor
590-
let p3: AnotherPair<_> = PairOption::PairSnd(S3); // $ MISSING: type=p3:Fst.S2
590+
let p3: AnotherPair<_> = PairOption::PairSnd(S3); // $ type=p3:Fst.S2
591591
println!("{:?}", p3);
592592

593593
// First type from alias definition, second from argument to alias
594-
let p3: AnotherPair<S3> = PairOption::PairNone(); // $ SPURIOUS: type=p3:Fst.S3 MISSING: type=p3:Snd.S3
594+
let p3: AnotherPair<S3> = PairOption::PairNone(); // $ type=p3:Fst.S2 type=p3:Snd.S3
595595
println!("{:?}", p3);
596596

597597
g(PairOption::PairSnd(PairOption::PairSnd(S3)));

rust/ql/test/library-tests/type-inference/type-inference.expected

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -510,9 +510,21 @@ inferType
510510
| main.rs:549:41:549:43 | snd | | main.rs:543:15:543:17 | Snd |
511511
| main.rs:549:49:549:51 | snd | | main.rs:543:15:543:17 | Snd |
512512
| main.rs:575:10:575:10 | t | | main.rs:535:5:541:5 | PairOption |
513-
| main.rs:575:10:575:10 | t | Fst | main.rs:560:5:561:14 | S3 |
513+
| main.rs:575:10:575:10 | t | Fst | main.rs:557:5:558:14 | S2 |
514+
| main.rs:575:10:575:10 | t | Snd | main.rs:535:5:541:5 | PairOption |
515+
| main.rs:575:10:575:10 | t | Snd.Fst | main.rs:557:5:558:14 | S2 |
516+
| main.rs:575:10:575:10 | t | Snd.Snd | main.rs:560:5:561:14 | S3 |
517+
| main.rs:576:13:576:13 | x | | main.rs:560:5:561:14 | S3 |
514518
| main.rs:576:17:576:17 | t | | main.rs:535:5:541:5 | PairOption |
515-
| main.rs:576:17:576:17 | t | Fst | main.rs:560:5:561:14 | S3 |
519+
| main.rs:576:17:576:17 | t | Fst | main.rs:557:5:558:14 | S2 |
520+
| main.rs:576:17:576:17 | t | Snd | main.rs:535:5:541:5 | PairOption |
521+
| main.rs:576:17:576:17 | t | Snd.Fst | main.rs:557:5:558:14 | S2 |
522+
| main.rs:576:17:576:17 | t | Snd.Snd | main.rs:560:5:561:14 | S3 |
523+
| main.rs:576:17:576:29 | t.unwrapSnd() | | main.rs:535:5:541:5 | PairOption |
524+
| main.rs:576:17:576:29 | t.unwrapSnd() | Fst | main.rs:557:5:558:14 | S2 |
525+
| main.rs:576:17:576:29 | t.unwrapSnd() | Snd | main.rs:560:5:561:14 | S3 |
526+
| main.rs:576:17:576:41 | ... .unwrapSnd() | | main.rs:560:5:561:14 | S3 |
527+
| main.rs:577:26:577:26 | x | | main.rs:560:5:561:14 | S3 |
516528
| main.rs:582:13:582:14 | p1 | | main.rs:535:5:541:5 | PairOption |
517529
| main.rs:582:13:582:14 | p1 | Fst | main.rs:554:5:555:14 | S1 |
518530
| main.rs:582:13:582:14 | p1 | Snd | main.rs:557:5:558:14 | S2 |
@@ -525,26 +537,40 @@ inferType
525537
| main.rs:583:26:583:27 | p1 | Fst | main.rs:554:5:555:14 | S1 |
526538
| main.rs:583:26:583:27 | p1 | Snd | main.rs:557:5:558:14 | S2 |
527539
| main.rs:586:13:586:14 | p2 | | main.rs:535:5:541:5 | PairOption |
540+
| main.rs:586:13:586:14 | p2 | Fst | main.rs:554:5:555:14 | S1 |
541+
| main.rs:586:13:586:14 | p2 | Snd | main.rs:557:5:558:14 | S2 |
528542
| main.rs:586:26:586:47 | ...::PairNone(...) | | main.rs:535:5:541:5 | PairOption |
543+
| main.rs:586:26:586:47 | ...::PairNone(...) | Fst | main.rs:554:5:555:14 | S1 |
544+
| main.rs:586:26:586:47 | ...::PairNone(...) | Snd | main.rs:557:5:558:14 | S2 |
529545
| main.rs:587:26:587:27 | p2 | | main.rs:535:5:541:5 | PairOption |
546+
| main.rs:587:26:587:27 | p2 | Fst | main.rs:554:5:555:14 | S1 |
547+
| main.rs:587:26:587:27 | p2 | Snd | main.rs:557:5:558:14 | S2 |
530548
| main.rs:590:13:590:14 | p3 | | main.rs:535:5:541:5 | PairOption |
549+
| main.rs:590:13:590:14 | p3 | Fst | main.rs:557:5:558:14 | S2 |
531550
| main.rs:590:13:590:14 | p3 | Snd | main.rs:560:5:561:14 | S3 |
532551
| main.rs:590:34:590:56 | ...::PairSnd(...) | | main.rs:535:5:541:5 | PairOption |
552+
| main.rs:590:34:590:56 | ...::PairSnd(...) | Fst | main.rs:557:5:558:14 | S2 |
533553
| main.rs:590:34:590:56 | ...::PairSnd(...) | Snd | main.rs:560:5:561:14 | S3 |
534554
| main.rs:590:54:590:55 | S3 | | main.rs:560:5:561:14 | S3 |
535555
| main.rs:591:26:591:27 | p3 | | main.rs:535:5:541:5 | PairOption |
556+
| main.rs:591:26:591:27 | p3 | Fst | main.rs:557:5:558:14 | S2 |
536557
| main.rs:591:26:591:27 | p3 | Snd | main.rs:560:5:561:14 | S3 |
537558
| main.rs:594:13:594:14 | p3 | | main.rs:535:5:541:5 | PairOption |
538-
| main.rs:594:13:594:14 | p3 | Fst | main.rs:560:5:561:14 | S3 |
559+
| main.rs:594:13:594:14 | p3 | Fst | main.rs:557:5:558:14 | S2 |
560+
| main.rs:594:13:594:14 | p3 | Snd | main.rs:560:5:561:14 | S3 |
539561
| main.rs:594:35:594:56 | ...::PairNone(...) | | main.rs:535:5:541:5 | PairOption |
540-
| main.rs:594:35:594:56 | ...::PairNone(...) | Fst | main.rs:560:5:561:14 | S3 |
562+
| main.rs:594:35:594:56 | ...::PairNone(...) | Fst | main.rs:557:5:558:14 | S2 |
563+
| main.rs:594:35:594:56 | ...::PairNone(...) | Snd | main.rs:560:5:561:14 | S3 |
541564
| main.rs:595:26:595:27 | p3 | | main.rs:535:5:541:5 | PairOption |
542-
| main.rs:595:26:595:27 | p3 | Fst | main.rs:560:5:561:14 | S3 |
565+
| main.rs:595:26:595:27 | p3 | Fst | main.rs:557:5:558:14 | S2 |
566+
| main.rs:595:26:595:27 | p3 | Snd | main.rs:560:5:561:14 | S3 |
543567
| main.rs:597:11:597:54 | ...::PairSnd(...) | | main.rs:535:5:541:5 | PairOption |
544-
| main.rs:597:11:597:54 | ...::PairSnd(...) | Fst | main.rs:560:5:561:14 | S3 |
568+
| main.rs:597:11:597:54 | ...::PairSnd(...) | Fst | main.rs:557:5:558:14 | S2 |
545569
| main.rs:597:11:597:54 | ...::PairSnd(...) | Snd | main.rs:535:5:541:5 | PairOption |
570+
| main.rs:597:11:597:54 | ...::PairSnd(...) | Snd.Fst | main.rs:557:5:558:14 | S2 |
546571
| main.rs:597:11:597:54 | ...::PairSnd(...) | Snd.Snd | main.rs:560:5:561:14 | S3 |
547572
| main.rs:597:31:597:53 | ...::PairSnd(...) | | main.rs:535:5:541:5 | PairOption |
573+
| main.rs:597:31:597:53 | ...::PairSnd(...) | Fst | main.rs:557:5:558:14 | S2 |
548574
| main.rs:597:31:597:53 | ...::PairSnd(...) | Snd | main.rs:560:5:561:14 | S3 |
549575
| main.rs:597:51:597:52 | S3 | | main.rs:560:5:561:14 | S3 |
550576
| main.rs:610:16:610:24 | SelfParam | | file://:0:0:0:0 | & |

0 commit comments

Comments
 (0)