Skip to content

Commit 8c6c28d

Browse files
committed
Rust: Add type inference tests for closures
1 parent 13d9d8a commit 8c6c28d

File tree

3 files changed

+147
-78
lines changed

3 files changed

+147
-78
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/// Tests for type inference for closures and higher-order functions.
2+
3+
mod simple_closures {
4+
pub fn test() {
5+
// A simple closure without type annotations or invocations.
6+
let my_closure = |a, b| a && b;
7+
8+
let x: i64 = 1i64; // $ type=x:i64
9+
let add_one = |n| n + 1i64; // $ MISSING: target=add
10+
let _y = add_one(x); // $ MISSING: type=y:i64
11+
12+
// The type of `x` is inferred from the closure's argument type.
13+
let x = Default::default(); // $ MISSING: type=x:i64 target=default
14+
let add_zero = |n: i64| n;
15+
let _y = add_zero(x); // $ MISSING: type=_y:i64
16+
17+
let _get_bool = || -> bool {
18+
// The return type annotation on the closure lets us infer the type of `b`.
19+
let b = Default::default(); // $ MISSING: type=b:bool target=default
20+
b
21+
};
22+
23+
// The parameter type of `id` is inferred from the argument.
24+
let id = |b| b; // $ MISSING: type=x:bool
25+
let _b = id(true); // $ MISSING: type=_b:bool
26+
27+
// The return type of `id2` is inferred from the type of the call expression.
28+
let id2 = |b| b;
29+
let arg = Default::default(); // $ MISSING: target=default type=arg:bool
30+
let _b2: bool = id2(arg); // $ MISSING: type=_b:bool
31+
}
32+
}
33+
34+
mod fn_once_trait {
35+
fn return_type<F: FnOnce(bool) -> i64>(f: F) {
36+
let _return = f(true); // $ MISSING: type=_return:i64
37+
}
38+
39+
fn argument_type<F: FnOnce(bool) -> i64>(f: F) {
40+
let arg = Default::default(); // $ MISSING: type=arg:bool target=default
41+
f(arg);
42+
}
43+
44+
fn apply<A, B, F: FnOnce(A) -> B>(f: F, a: A) -> B {
45+
f(a)
46+
}
47+
48+
fn apply_two(f: impl FnOnce(i64) -> i64) -> i64 {
49+
f(2)
50+
}
51+
52+
fn test() {
53+
let f = |x: bool| -> i64 {
54+
if x {
55+
1
56+
} else {
57+
0
58+
}
59+
};
60+
let _r = apply(f, true); // $ target=apply MISSING: type=_r:i64
61+
62+
let f = |x| x + 1; // $ MISSING: type=x:i64 target=add
63+
let _r2 = apply_two(f); // $ target=apply_two type=_r2:i64
64+
}
65+
}
66+
67+
mod dyn_fn_once {
68+
fn apply_boxed<A, B, F: FnOnce(A) -> B + ?Sized>(f: Box<F>, arg: A) -> B {
69+
f(arg)
70+
}
71+
72+
fn apply_boxed_dyn<A, B>(f: Box<dyn FnOnce(A) -> B>, arg: A) {
73+
let _r1 = apply_boxed(f, arg); // $ target=apply_boxed MISSING: type=_r1:B
74+
let _r2 = apply_boxed(Box::new(|_: i64| true), 3); // $ target=apply_boxed target=new MISSING: type=_r2:bool
75+
}
76+
}

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

Lines changed: 1 addition & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2459,46 +2459,7 @@ pub mod pattern_matching_experimental {
24592459
}
24602460
}
24612461

2462-
mod closures {
2463-
struct Row {
2464-
data: i64,
2465-
}
2466-
2467-
impl Row {
2468-
fn get(&self) -> i64 {
2469-
self.data // $ fieldof=Row
2470-
}
2471-
}
2472-
2473-
struct Table {
2474-
rows: Vec<Row>,
2475-
}
2476-
2477-
impl Table {
2478-
fn new() -> Self {
2479-
Table { rows: Vec::new() } // $ target=new
2480-
}
2481-
2482-
fn count_with(&self, property: impl Fn(Row) -> bool) -> i64 {
2483-
0 // (not implemented)
2484-
}
2485-
}
2486-
2487-
pub fn f() {
2488-
Some(1).map(|x| {
2489-
let x = x; // $ MISSING: type=x:i32
2490-
println!("{x}");
2491-
}); // $ target=map
2492-
2493-
let table = Table::new(); // $ target=new type=table:Table
2494-
let result = table.count_with(|row| // $ type=result:i64
2495-
{
2496-
let v = row.get(); // $ MISSING: target=get type=v:i64
2497-
v > 0 // $ MISSING: target=gt
2498-
}); // $ target=count_with
2499-
}
2500-
}
2501-
2462+
mod closure;
25022463
mod dereference;
25032464
mod dyn_type;
25042465

@@ -2532,6 +2493,5 @@ fn main() {
25322493
dereference::test(); // $ target=test
25332494
pattern_matching::test_all_patterns(); // $ target=test_all_patterns
25342495
pattern_matching_experimental::box_patterns(); // $ target=box_patterns
2535-
closures::f(); // $ target=f
25362496
dyn_type::test(); // $ target=test
25372497
}

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

Lines changed: 70 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,69 @@
11
inferType
2+
| closure.rs:6:27:6:27 | a | | {EXTERNAL LOCATION} | bool |
3+
| closure.rs:6:30:6:30 | b | | {EXTERNAL LOCATION} | bool |
4+
| closure.rs:6:33:6:33 | a | | {EXTERNAL LOCATION} | bool |
5+
| closure.rs:6:33:6:38 | ... && ... | | {EXTERNAL LOCATION} | bool |
6+
| closure.rs:6:38:6:38 | b | | {EXTERNAL LOCATION} | bool |
7+
| closure.rs:8:13:8:13 | x | | {EXTERNAL LOCATION} | i64 |
8+
| closure.rs:8:22:8:25 | 1i64 | | {EXTERNAL LOCATION} | i64 |
9+
| closure.rs:9:31:9:34 | 1i64 | | {EXTERNAL LOCATION} | i64 |
10+
| closure.rs:10:26:10:26 | x | | {EXTERNAL LOCATION} | i64 |
11+
| closure.rs:14:25:14:25 | n | | {EXTERNAL LOCATION} | i64 |
12+
| closure.rs:14:33:14:33 | n | | {EXTERNAL LOCATION} | i64 |
13+
| closure.rs:25:21:25:24 | true | | {EXTERNAL LOCATION} | bool |
14+
| closure.rs:30:13:30:15 | _b2 | | {EXTERNAL LOCATION} | bool |
15+
| closure.rs:30:25:30:32 | id2(...) | | {EXTERNAL LOCATION} | bool |
16+
| closure.rs:35:44:35:44 | f | | closure.rs:35:20:35:41 | F |
17+
| closure.rs:36:23:36:23 | f | | closure.rs:35:20:35:41 | F |
18+
| closure.rs:36:25:36:28 | true | | {EXTERNAL LOCATION} | bool |
19+
| closure.rs:39:46:39:46 | f | | closure.rs:39:22:39:43 | F |
20+
| closure.rs:41:9:41:9 | f | | closure.rs:39:22:39:43 | F |
21+
| closure.rs:44:39:44:39 | f | | closure.rs:44:20:44:36 | F |
22+
| closure.rs:44:45:44:45 | a | | closure.rs:44:14:44:14 | A |
23+
| closure.rs:44:56:46:5 | { ... } | | closure.rs:44:17:44:17 | B |
24+
| closure.rs:45:9:45:9 | f | | closure.rs:44:20:44:36 | F |
25+
| closure.rs:45:9:45:12 | f(...) | | closure.rs:44:17:44:17 | B |
26+
| closure.rs:45:11:45:11 | a | | closure.rs:44:14:44:14 | A |
27+
| closure.rs:48:18:48:18 | f | | closure.rs:48:21:48:43 | ImplTraitTypeRepr |
28+
| closure.rs:48:53:50:5 | { ... } | | {EXTERNAL LOCATION} | i64 |
29+
| closure.rs:49:9:49:9 | f | | closure.rs:48:21:48:43 | ImplTraitTypeRepr |
30+
| closure.rs:49:9:49:12 | f(...) | | {EXTERNAL LOCATION} | i64 |
31+
| closure.rs:49:11:49:11 | 2 | | {EXTERNAL LOCATION} | i32 |
32+
| closure.rs:53:18:53:18 | x | | {EXTERNAL LOCATION} | bool |
33+
| closure.rs:53:34:59:9 | { ... } | | {EXTERNAL LOCATION} | i32 |
34+
| closure.rs:54:13:58:13 | if x {...} else {...} | | {EXTERNAL LOCATION} | i32 |
35+
| closure.rs:54:16:54:16 | x | | {EXTERNAL LOCATION} | bool |
36+
| closure.rs:54:18:56:13 | { ... } | | {EXTERNAL LOCATION} | i32 |
37+
| closure.rs:55:17:55:17 | 1 | | {EXTERNAL LOCATION} | i32 |
38+
| closure.rs:56:20:58:13 | { ... } | | {EXTERNAL LOCATION} | i32 |
39+
| closure.rs:57:17:57:17 | 0 | | {EXTERNAL LOCATION} | i32 |
40+
| closure.rs:60:27:60:30 | true | | {EXTERNAL LOCATION} | bool |
41+
| closure.rs:62:25:62:25 | 1 | | {EXTERNAL LOCATION} | i32 |
42+
| closure.rs:63:13:63:15 | _r2 | | {EXTERNAL LOCATION} | i64 |
43+
| closure.rs:63:19:63:30 | apply_two(...) | | {EXTERNAL LOCATION} | i64 |
44+
| closure.rs:68:54:68:54 | f | | {EXTERNAL LOCATION} | Box |
45+
| closure.rs:68:54:68:54 | f | A | {EXTERNAL LOCATION} | Global |
46+
| closure.rs:68:54:68:54 | f | T | closure.rs:68:26:68:51 | F |
47+
| closure.rs:68:65:68:67 | arg | | closure.rs:68:20:68:20 | A |
48+
| closure.rs:68:78:70:5 | { ... } | | closure.rs:68:23:68:23 | B |
49+
| closure.rs:69:9:69:9 | f | | {EXTERNAL LOCATION} | Box |
50+
| closure.rs:69:9:69:9 | f | A | {EXTERNAL LOCATION} | Global |
51+
| closure.rs:69:9:69:9 | f | T | closure.rs:68:26:68:51 | F |
52+
| closure.rs:69:9:69:14 | f(...) | | closure.rs:68:23:68:23 | B |
53+
| closure.rs:69:11:69:13 | arg | | closure.rs:68:20:68:20 | A |
54+
| closure.rs:72:30:72:30 | f | | {EXTERNAL LOCATION} | Box |
55+
| closure.rs:72:30:72:30 | f | A | {EXTERNAL LOCATION} | Global |
56+
| closure.rs:72:30:72:30 | f | T | {EXTERNAL LOCATION} | dyn FnOnce |
57+
| closure.rs:72:58:72:60 | arg | | closure.rs:72:24:72:24 | A |
58+
| closure.rs:73:31:73:31 | f | | {EXTERNAL LOCATION} | Box |
59+
| closure.rs:73:31:73:31 | f | A | {EXTERNAL LOCATION} | Global |
60+
| closure.rs:73:31:73:31 | f | T | {EXTERNAL LOCATION} | dyn FnOnce |
61+
| closure.rs:73:34:73:36 | arg | | closure.rs:72:24:72:24 | A |
62+
| closure.rs:74:31:74:53 | ...::new(...) | | {EXTERNAL LOCATION} | Box |
63+
| closure.rs:74:31:74:53 | ...::new(...) | A | {EXTERNAL LOCATION} | Global |
64+
| closure.rs:74:41:74:41 | _ | | {EXTERNAL LOCATION} | i64 |
65+
| closure.rs:74:49:74:52 | true | | {EXTERNAL LOCATION} | bool |
66+
| closure.rs:74:56:74:56 | 3 | | {EXTERNAL LOCATION} | i32 |
267
| dereference.rs:12:14:12:18 | SelfParam | | file://:0:0:0:0 | & |
368
| dereference.rs:12:14:12:18 | SelfParam | &T | dereference.rs:4:1:6:1 | MyIntPointer |
469
| dereference.rs:12:29:14:5 | { ... } | | file://:0:0:0:0 | & |
@@ -4528,43 +4593,11 @@ inferType
45284593
| main.rs:2456:26:2456:43 | "Nested boxed: {}\\n" | &T | {EXTERNAL LOCATION} | str |
45294594
| main.rs:2456:26:2456:59 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
45304595
| main.rs:2456:26:2456:59 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
4531-
| main.rs:2468:16:2468:20 | SelfParam | | file://:0:0:0:0 | & |
4532-
| main.rs:2468:16:2468:20 | SelfParam | &T | main.rs:2463:5:2465:5 | Row |
4533-
| main.rs:2468:30:2470:9 | { ... } | | {EXTERNAL LOCATION} | i64 |
4534-
| main.rs:2469:13:2469:16 | self | | file://:0:0:0:0 | & |
4535-
| main.rs:2469:13:2469:16 | self | &T | main.rs:2463:5:2465:5 | Row |
4536-
| main.rs:2469:13:2469:21 | self.data | | {EXTERNAL LOCATION} | i64 |
4537-
| main.rs:2478:26:2480:9 | { ... } | | main.rs:2473:5:2475:5 | Table |
4538-
| main.rs:2479:13:2479:38 | Table {...} | | main.rs:2473:5:2475:5 | Table |
4539-
| main.rs:2479:27:2479:36 | ...::new(...) | | {EXTERNAL LOCATION} | Vec |
4540-
| main.rs:2479:27:2479:36 | ...::new(...) | A | {EXTERNAL LOCATION} | Global |
4541-
| main.rs:2479:27:2479:36 | ...::new(...) | T | main.rs:2463:5:2465:5 | Row |
4542-
| main.rs:2482:23:2482:27 | SelfParam | | file://:0:0:0:0 | & |
4543-
| main.rs:2482:23:2482:27 | SelfParam | &T | main.rs:2473:5:2475:5 | Table |
4544-
| main.rs:2482:30:2482:37 | property | | main.rs:2482:40:2482:59 | ImplTraitTypeRepr |
4545-
| main.rs:2482:69:2484:9 | { ... } | | {EXTERNAL LOCATION} | i32 |
4546-
| main.rs:2482:69:2484:9 | { ... } | | {EXTERNAL LOCATION} | i64 |
4547-
| main.rs:2483:13:2483:13 | 0 | | {EXTERNAL LOCATION} | i32 |
4548-
| main.rs:2483:13:2483:13 | 0 | | {EXTERNAL LOCATION} | i64 |
4549-
| main.rs:2488:9:2488:15 | Some(...) | | {EXTERNAL LOCATION} | Option |
4550-
| main.rs:2488:9:2488:15 | Some(...) | T | {EXTERNAL LOCATION} | i32 |
4551-
| main.rs:2488:9:2491:10 | ... .map(...) | | {EXTERNAL LOCATION} | Option |
4552-
| main.rs:2488:14:2488:14 | 1 | | {EXTERNAL LOCATION} | i32 |
4553-
| main.rs:2490:22:2490:26 | "{x}\\n" | | file://:0:0:0:0 | & |
4554-
| main.rs:2490:22:2490:26 | "{x}\\n" | &T | {EXTERNAL LOCATION} | str |
4555-
| main.rs:2490:22:2490:26 | FormatArgsExpr | | {EXTERNAL LOCATION} | Arguments |
4556-
| main.rs:2490:22:2490:26 | MacroExpr | | {EXTERNAL LOCATION} | Arguments |
4557-
| main.rs:2493:13:2493:17 | table | | main.rs:2473:5:2475:5 | Table |
4558-
| main.rs:2493:21:2493:32 | ...::new(...) | | main.rs:2473:5:2475:5 | Table |
4559-
| main.rs:2494:13:2494:18 | result | | {EXTERNAL LOCATION} | i64 |
4560-
| main.rs:2494:22:2494:26 | table | | main.rs:2473:5:2475:5 | Table |
4561-
| main.rs:2494:22:2498:14 | table.count_with(...) | | {EXTERNAL LOCATION} | i64 |
4562-
| main.rs:2497:21:2497:21 | 0 | | {EXTERNAL LOCATION} | i32 |
4563-
| main.rs:2507:5:2507:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo |
4564-
| main.rs:2508:5:2508:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo |
4565-
| main.rs:2508:20:2508:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
4566-
| main.rs:2508:41:2508:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
4567-
| main.rs:2524:5:2524:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future |
4596+
| main.rs:2468:5:2468:20 | ...::f(...) | | main.rs:72:5:72:21 | Foo |
4597+
| main.rs:2469:5:2469:60 | ...::g(...) | | main.rs:72:5:72:21 | Foo |
4598+
| main.rs:2469:20:2469:38 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
4599+
| main.rs:2469:41:2469:59 | ...::Foo {...} | | main.rs:72:5:72:21 | Foo |
4600+
| main.rs:2485:5:2485:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future |
45684601
| pattern_matching.rs:13:26:133:1 | { ... } | | {EXTERNAL LOCATION} | Option |
45694602
| pattern_matching.rs:13:26:133:1 | { ... } | T | file://:0:0:0:0 | () |
45704603
| pattern_matching.rs:14:9:14:13 | value | | {EXTERNAL LOCATION} | Option |

0 commit comments

Comments
 (0)