rust-analyzer/crates/hir_ty/src/tests/patterns.rs

776 lines
20 KiB
Rust

use expect_test::expect;
use test_utils::mark;
use super::{check_infer, check_infer_with_mismatches};
#[test]
fn infer_pattern() {
check_infer(
r#"
fn test(x: &i32) {
let y = x;
let &z = x;
let a = z;
let (c, d) = (1, "hello");
for (e, f) in some_iter {
let g = e;
}
if let [val] = opt {
let h = val;
}
let lambda = |a: u64, b, c: i32| { a + b; c };
let ref ref_to_x = x;
let mut mut_x = x;
let ref mut mut_ref_to_x = x;
let k = mut_ref_to_x;
}
"#,
expect![[r#"
8..9 'x': &i32
17..368 '{ ...o_x; }': ()
27..28 'y': &i32
31..32 'x': &i32
42..44 '&z': &i32
43..44 'z': i32
47..48 'x': &i32
58..59 'a': i32
62..63 'z': i32
73..79 '(c, d)': (i32, &str)
74..75 'c': i32
77..78 'd': &str
82..94 '(1, "hello")': (i32, &str)
83..84 '1': i32
86..93 '"hello"': &str
101..151 'for (e... }': ()
105..111 '(e, f)': ({unknown}, {unknown})
106..107 'e': {unknown}
109..110 'f': {unknown}
115..124 'some_iter': {unknown}
125..151 '{ ... }': ()
139..140 'g': {unknown}
143..144 'e': {unknown}
157..204 'if let... }': ()
164..169 '[val]': [{unknown}]
165..168 'val': {unknown}
172..175 'opt': [{unknown}]
176..204 '{ ... }': ()
190..191 'h': {unknown}
194..197 'val': {unknown}
214..220 'lambda': |u64, u64, i32| -> i32
223..255 '|a: u6...b; c }': |u64, u64, i32| -> i32
224..225 'a': u64
232..233 'b': u64
235..236 'c': i32
243..255 '{ a + b; c }': i32
245..246 'a': u64
245..250 'a + b': u64
249..250 'b': u64
252..253 'c': i32
266..278 'ref ref_to_x': &&i32
281..282 'x': &i32
292..301 'mut mut_x': &i32
304..305 'x': &i32
315..335 'ref mu...f_to_x': &mut &i32
338..339 'x': &i32
349..350 'k': &mut &i32
353..365 'mut_ref_to_x': &mut &i32
"#]],
);
}
#[test]
fn infer_literal_pattern() {
check_infer_with_mismatches(
r#"
fn any<T>() -> T { loop {} }
fn test(x: &i32) {
if let "foo" = any() {}
if let 1 = any() {}
if let 1u32 = any() {}
if let 1f32 = any() {}
if let 1.0 = any() {}
if let true = any() {}
}
"#,
expect![[r#"
17..28 '{ loop {} }': T
19..26 'loop {}': !
24..26 '{}': ()
37..38 'x': &i32
46..208 '{ ...) {} }': ()
52..75 'if let...y() {}': ()
59..64 '"foo"': &str
59..64 '"foo"': &str
67..70 'any': fn any<&str>() -> &str
67..72 'any()': &str
73..75 '{}': ()
80..99 'if let...y() {}': ()
87..88 '1': i32
87..88 '1': i32
91..94 'any': fn any<i32>() -> i32
91..96 'any()': i32
97..99 '{}': ()
104..126 'if let...y() {}': ()
111..115 '1u32': u32
111..115 '1u32': u32
118..121 'any': fn any<u32>() -> u32
118..123 'any()': u32
124..126 '{}': ()
131..153 'if let...y() {}': ()
138..142 '1f32': f32
138..142 '1f32': f32
145..148 'any': fn any<f32>() -> f32
145..150 'any()': f32
151..153 '{}': ()
158..179 'if let...y() {}': ()
165..168 '1.0': f64
165..168 '1.0': f64
171..174 'any': fn any<f64>() -> f64
171..176 'any()': f64
177..179 '{}': ()
184..206 'if let...y() {}': ()
191..195 'true': bool
191..195 'true': bool
198..201 'any': fn any<bool>() -> bool
198..203 'any()': bool
204..206 '{}': ()
"#]],
);
}
#[test]
fn infer_range_pattern() {
check_infer_with_mismatches(
r#"
fn test(x: &i32) {
if let 1..76 = 2u32 {}
if let 1..=76 = 2u32 {}
}
"#,
expect![[r#"
8..9 'x': &i32
17..75 '{ ...2 {} }': ()
23..45 'if let...u32 {}': ()
30..35 '1..76': u32
38..42 '2u32': u32
43..45 '{}': ()
50..73 'if let...u32 {}': ()
57..63 '1..=76': u32
66..70 '2u32': u32
71..73 '{}': ()
"#]],
);
}
#[test]
fn infer_pattern_match_ergonomics() {
check_infer(
r#"
struct A<T>(T);
fn test() {
let A(n) = &A(1);
let A(n) = &mut A(1);
}
"#,
expect![[r#"
27..78 '{ ...(1); }': ()
37..41 'A(n)': A<i32>
39..40 'n': &i32
44..49 '&A(1)': &A<i32>
45..46 'A': A<i32>(i32) -> A<i32>
45..49 'A(1)': A<i32>
47..48 '1': i32
59..63 'A(n)': A<i32>
61..62 'n': &mut i32
66..75 '&mut A(1)': &mut A<i32>
71..72 'A': A<i32>(i32) -> A<i32>
71..75 'A(1)': A<i32>
73..74 '1': i32
"#]],
);
}
#[test]
fn infer_pattern_match_ergonomics_ref() {
mark::check!(match_ergonomics_ref);
check_infer(
r#"
fn test() {
let v = &(1, &2);
let (_, &w) = v;
}
"#,
expect![[r#"
10..56 '{ ...= v; }': ()
20..21 'v': &(i32, &i32)
24..32 '&(1, &2)': &(i32, &i32)
25..32 '(1, &2)': (i32, &i32)
26..27 '1': i32
29..31 '&2': &i32
30..31 '2': i32
42..49 '(_, &w)': (i32, &i32)
43..44 '_': i32
46..48 '&w': &i32
47..48 'w': i32
52..53 'v': &(i32, &i32)
"#]],
);
}
#[test]
fn infer_pattern_match_slice() {
check_infer(
r#"
fn test() {
let slice: &[f64] = &[0.0];
match slice {
&[] => {},
&[a] => {
a;
},
&[b, c] => {
b;
c;
}
_ => {}
}
}
"#,
expect![[r#"
10..209 '{ ... } }': ()
20..25 'slice': &[f64]
36..42 '&[0.0]': &[f64; _]
37..42 '[0.0]': [f64; _]
38..41 '0.0': f64
48..207 'match ... }': ()
54..59 'slice': &[f64]
70..73 '&[]': &[f64]
71..73 '[]': [f64]
77..79 '{}': ()
89..93 '&[a]': &[f64]
90..93 '[a]': [f64]
91..92 'a': f64
97..123 '{ ... }': ()
111..112 'a': f64
133..140 '&[b, c]': &[f64]
134..140 '[b, c]': [f64]
135..136 'b': f64
138..139 'c': f64
144..185 '{ ... }': ()
158..159 'b': f64
173..174 'c': f64
194..195 '_': &[f64]
199..201 '{}': ()
"#]],
);
}
#[test]
fn infer_pattern_match_string_literal() {
check_infer_with_mismatches(
r#"
fn test() {
let s: &str = "hello";
match s {
"hello" => {}
_ => {}
}
}
"#,
expect![[r#"
10..98 '{ ... } }': ()
20..21 's': &str
30..37 '"hello"': &str
43..96 'match ... }': ()
49..50 's': &str
61..68 '"hello"': &str
61..68 '"hello"': &str
72..74 '{}': ()
83..84 '_': &str
88..90 '{}': ()
"#]],
);
}
#[test]
fn infer_pattern_match_or() {
check_infer_with_mismatches(
r#"
fn test() {
let s: &str = "hello";
match s {
"hello" | "world" => {}
_ => {}
}
}
"#,
expect![[r#"
10..108 '{ ... } }': ()
20..21 's': &str
30..37 '"hello"': &str
43..106 'match ... }': ()
49..50 's': &str
61..68 '"hello"': &str
61..68 '"hello"': &str
61..78 '"hello...world"': &str
71..78 '"world"': &str
71..78 '"world"': &str
82..84 '{}': ()
93..94 '_': &str
98..100 '{}': ()
"#]],
);
}
#[test]
fn infer_pattern_match_arr() {
check_infer(
r#"
fn test() {
let arr: [f64; 2] = [0.0, 1.0];
match arr {
[1.0, a] => {
a;
},
[b, c] => {
b;
c;
}
}
}
"#,
expect![[r#"
10..179 '{ ... } }': ()
20..23 'arr': [f64; _]
36..46 '[0.0, 1.0]': [f64; _]
37..40 '0.0': f64
42..45 '1.0': f64
52..177 'match ... }': ()
58..61 'arr': [f64; _]
72..80 '[1.0, a]': [f64; _]
73..76 '1.0': f64
73..76 '1.0': f64
78..79 'a': f64
84..110 '{ ... }': ()
98..99 'a': f64
120..126 '[b, c]': [f64; _]
121..122 'b': f64
124..125 'c': f64
130..171 '{ ... }': ()
144..145 'b': f64
159..160 'c': f64
"#]],
);
}
#[test]
fn infer_adt_pattern() {
check_infer(
r#"
enum E {
A { x: usize },
B
}
struct S(u32, E);
fn test() {
let e = E::A { x: 3 };
let S(y, z) = foo;
let E::A { x: new_var } = e;
match e {
E::A { x } => x,
E::B if foo => 1,
E::B => 10,
};
let ref d @ E::A { .. } = e;
d;
}
"#,
expect![[r#"
67..288 '{ ... d; }': ()
77..78 'e': E
81..94 'E::A { x: 3 }': E
91..92 '3': usize
105..112 'S(y, z)': S
107..108 'y': u32
110..111 'z': E
115..118 'foo': S
128..147 'E::A {..._var }': E
138..145 'new_var': usize
150..151 'e': E
158..244 'match ... }': usize
164..165 'e': E
176..186 'E::A { x }': E
183..184 'x': usize
190..191 'x': usize
201..205 'E::B': E
209..212 'foo': bool
216..217 '1': usize
227..231 'E::B': E
235..237 '10': usize
255..274 'ref d ...{ .. }': &E
263..274 'E::A { .. }': E
277..278 'e': E
284..285 'd': &E
"#]],
);
}
#[test]
fn enum_variant_through_self_in_pattern() {
check_infer(
r#"
enum E {
A { x: usize },
B(usize),
C
}
impl E {
fn test() {
match (loop {}) {
Self::A { x } => { x; },
Self::B(x) => { x; },
Self::C => {},
};
}
}
"#,
expect![[r#"
75..217 '{ ... }': ()
85..210 'match ... }': ()
92..99 'loop {}': !
97..99 '{}': ()
115..128 'Self::A { x }': E
125..126 'x': usize
132..138 '{ x; }': ()
134..135 'x': usize
152..162 'Self::B(x)': E
160..161 'x': usize
166..172 '{ x; }': ()
168..169 'x': usize
186..193 'Self::C': E
197..199 '{}': ()
"#]],
);
}
#[test]
fn infer_generics_in_patterns() {
check_infer(
r#"
struct A<T> {
x: T,
}
enum Option<T> {
Some(T),
None,
}
fn test(a1: A<u32>, o: Option<u64>) {
let A { x: x2 } = a1;
let A::<i64> { x: x3 } = A { x: 1 };
match o {
Option::Some(t) => t,
_ => 1,
};
}
"#,
expect![[r#"
78..80 'a1': A<u32>
90..91 'o': Option<u64>
106..243 '{ ... }; }': ()
116..127 'A { x: x2 }': A<u32>
123..125 'x2': u32
130..132 'a1': A<u32>
142..160 'A::<i6...: x3 }': A<i64>
156..158 'x3': i64
163..173 'A { x: 1 }': A<i64>
170..171 '1': i64
179..240 'match ... }': u64
185..186 'o': Option<u64>
197..212 'Option::Some(t)': Option<u64>
210..211 't': u64
216..217 't': u64
227..228 '_': Option<u64>
232..233 '1': u64
"#]],
);
}
#[test]
fn infer_const_pattern() {
check_infer_with_mismatches(
r#"
enum Option<T> { None }
use Option::None;
struct Foo;
const Bar: usize = 1;
fn test() {
let a: Option<u32> = None;
let b: Option<i64> = match a {
None => None,
};
let _: () = match () { Foo => Foo }; // Expected mismatch
let _: () = match () { Bar => Bar }; // Expected mismatch
}
"#,
expect![[r#"
73..74 '1': usize
87..309 '{ ...atch }': ()
97..98 'a': Option<u32>
114..118 'None': Option<u32>
128..129 'b': Option<i64>
145..182 'match ... }': Option<i64>
151..152 'a': Option<u32>
163..167 'None': Option<u32>
171..175 'None': Option<i64>
192..193 '_': ()
200..223 'match ... Foo }': Foo
206..208 '()': ()
211..214 'Foo': Foo
218..221 'Foo': Foo
254..255 '_': ()
262..285 'match ... Bar }': usize
268..270 '()': ()
273..276 'Bar': usize
280..283 'Bar': usize
200..223: expected (), got Foo
262..285: expected (), got usize
"#]],
);
}
#[test]
fn infer_guard() {
check_infer(
r#"
struct S;
impl S { fn foo(&self) -> bool { false } }
fn main() {
match S {
s if s.foo() => (),
}
}
"#,
expect![[r#"
27..31 'self': &S
41..50 '{ false }': bool
43..48 'false': bool
64..115 '{ ... } }': ()
70..113 'match ... }': ()
76..77 'S': S
88..89 's': S
93..94 's': S
93..100 's.foo()': bool
104..106 '()': ()
"#]],
)
}
#[test]
fn match_ergonomics_in_closure_params() {
check_infer(
r#"
#[lang = "fn_once"]
trait FnOnce<Args> {
type Output;
}
fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} }
fn test() {
foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics
foo(&(1, "a"), |(x, y)| x);
}
"#,
expect![[r#"
93..94 't': T
99..100 'f': F
110..121 '{ loop {} }': U
112..119 'loop {}': !
117..119 '{}': ()
133..232 '{ ... x); }': ()
139..142 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32
139..166 'foo(&(...y)| x)': i32
143..152 '&(1, "a")': &(i32, &str)
144..152 '(1, "a")': (i32, &str)
145..146 '1': i32
148..151 '"a"': &str
154..165 '|&(x, y)| x': |&(i32, &str)| -> i32
155..162 '&(x, y)': &(i32, &str)
156..162 '(x, y)': (i32, &str)
157..158 'x': i32
160..161 'y': &str
164..165 'x': i32
203..206 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32
203..229 'foo(&(...y)| x)': &i32
207..216 '&(1, "a")': &(i32, &str)
208..216 '(1, "a")': (i32, &str)
209..210 '1': i32
212..215 '"a"': &str
218..228 '|(x, y)| x': |&(i32, &str)| -> &i32
219..225 '(x, y)': (i32, &str)
220..221 'x': &i32
223..224 'y': &&str
227..228 'x': &i32
"#]],
);
}
#[test]
fn slice_tail_pattern() {
check_infer(
r#"
fn foo(params: &[i32]) {
match params {
[head, tail @ ..] => {
}
}
}
"#,
expect![[r#"
7..13 'params': &[i32]
23..92 '{ ... } }': ()
29..90 'match ... }': ()
35..41 'params': &[i32]
52..69 '[head,... @ ..]': [i32]
53..57 'head': &i32
59..68 'tail @ ..': &[i32]
66..68 '..': [i32]
73..84 '{ }': ()
"#]],
);
}
#[test]
fn box_pattern() {
check_infer(
r#"
#[lang = "owned_box"]
pub struct Box<T>(T);
fn foo(params: Box<i32>) {
match params {
box integer => {}
}
}
"#,
expect![[r#"
52..58 'params': Box<i32>
70..124 '{ ... } }': ()
76..122 'match ... }': ()
82..88 'params': Box<i32>
99..110 'box integer': Box<i32>
103..110 'integer': i32
114..116 '{}': ()
"#]],
);
}
#[test]
fn tuple_ellipsis_pattern() {
check_infer(
r#"
fn foo(tuple: (u8, i16, f32)) {
match tuple {
(.., b, c) => {},
(a, .., c) => {},
(a, b, ..) => {},
(a, b) => {/*too short*/}
(a, b, c, d) => {/*too long*/}
_ => {}
}
}"#,
expect![[r#"
7..12 'tuple': (u8, i16, f32)
30..224 '{ ... } }': ()
36..222 'match ... }': ()
42..47 'tuple': (u8, i16, f32)
58..68 '(.., b, c)': (u8, i16, f32)
63..64 'b': i16
66..67 'c': f32
72..74 '{}': ()
84..94 '(a, .., c)': (u8, i16, f32)
85..86 'a': u8
92..93 'c': f32
98..100 '{}': ()
110..120 '(a, b, ..)': (u8, i16, f32)
111..112 'a': u8
114..115 'b': i16
124..126 '{}': ()
136..142 '(a, b)': (u8, i16, f32)
137..138 'a': u8
140..141 'b': i16
146..161 '{/*too short*/}': ()
170..182 '(a, b, c, d)': (u8, i16, f32, {unknown})
171..172 'a': u8
174..175 'b': i16
177..178 'c': f32
180..181 'd': {unknown}
186..200 '{/*too long*/}': ()
209..210 '_': (u8, i16, f32)
214..216 '{}': ()
"#]],
);
}
#[test]
fn tuple_struct_ellipsis_pattern() {
check_infer(
r#"
struct Tuple(u8, i16, f32);
fn foo(tuple: Tuple) {
match tuple {
Tuple(.., b, c) => {},
Tuple(a, .., c) => {},
Tuple(a, b, ..) => {},
Tuple(a, b) => {/*too short*/}
Tuple(a, b, c, d) => {/*too long*/}
_ => {}
}
}"#,
expect![[r#"
35..40 'tuple': Tuple
49..268 '{ ... } }': ()
55..266 'match ... }': ()
61..66 'tuple': Tuple
77..92 'Tuple(.., b, c)': Tuple
87..88 'b': i16
90..91 'c': f32
96..98 '{}': ()
108..123 'Tuple(a, .., c)': Tuple
114..115 'a': u8
121..122 'c': f32
127..129 '{}': ()
139..154 'Tuple(a, b, ..)': Tuple
145..146 'a': u8
148..149 'b': i16
158..160 '{}': ()
170..181 'Tuple(a, b)': Tuple
176..177 'a': u8
179..180 'b': i16
185..200 '{/*too short*/}': ()
209..226 'Tuple(... c, d)': Tuple
215..216 'a': u8
218..219 'b': i16
221..222 'c': f32
224..225 'd': {unknown}
230..244 '{/*too long*/}': ()
253..254 '_': Tuple
258..260 '{}': ()
"#]],
);
}