use expect_test::expect; use super::{check_infer, check_infer_with_mismatches, check_types}; #[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 { 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 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 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 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 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 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); fn test() { let A(n) = &A(1); let A(n) = &mut A(1); } "#, expect![[r#" 27..78 '{ ...(1); }': () 37..41 'A(n)': A 39..40 'n': &i32 44..49 '&A(1)': &A 45..46 'A': A(i32) -> A 45..49 'A(1)': A 47..48 '1': i32 59..63 'A(n)': A 61..62 'n': &mut i32 66..75 '&mut A(1)': &mut A 71..72 'A': A(i32) -> A 71..75 'A(1)': A 73..74 '1': i32 "#]], ); } #[test] fn infer_pattern_match_ergonomics_ref() { cov_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; 1] 37..42 '[0.0]': [f64; 1] 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; 2] 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 { x: T, } enum Option { Some(T), None, } fn test(a1: A, o: Option) { let A { x: x2 } = a1; let A:: { x: x3 } = A { x: 1 }; match o { Option::Some(t) => t, _ => 1, }; } "#, expect![[r#" 78..80 'a1': A 90..91 'o': Option 106..243 '{ ... }; }': () 116..127 'A { x: x2 }': A 123..125 'x2': u32 130..132 'a1': A 142..160 'A:: 156..158 'x3': i64 163..173 'A { x: 1 }': A 170..171 '1': i64 179..240 'match ... }': u64 185..186 'o': Option 197..212 'Option::Some(t)': Option 210..211 't': u64 216..217 't': u64 227..228 '_': Option 232..233 '1': u64 "#]], ); } #[test] fn infer_const_pattern() { check_infer_with_mismatches( r#" enum Option { None } use Option::None; struct Foo; const Bar: usize = 1; fn test() { let a: Option = None; let b: Option = 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 114..118 'None': Option 128..129 'b': Option 145..182 'match ... }': Option 151..152 'a': Option 163..167 'None': Option 171..175 'None': Option 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 { type Output; } fn foo 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#" pub struct Global; #[lang = "owned_box"] pub struct Box(T); fn foo(params: Box) { match params { box integer => {} } } "#, expect![[r#" 83..89 'params': Box 101..155 '{ ... } }': () 107..153 'match ... }': () 113..119 'params': Box 130..141 'box integer': Box 134..141 'integer': i32 145..147 '{}': () "#]], ); check_infer( r#" #[lang = "owned_box"] pub struct Box(T); fn foo(params: Box) { match params { box integer => {} } } "#, expect![[r#" 52..58 'params': Box 70..124 '{ ... } }': () 76..122 'match ... }': () 82..88 'params': Box 99..110 'box integer': Box 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) 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 '{}': () "#]], ); } #[test] fn const_block_pattern() { check_infer( r#" struct Foo(usize); fn foo(foo: Foo) { match foo { const { Foo(15 + 32) } => {}, _ => {} } }"#, expect![[r#" 26..29 'foo': Foo 36..115 '{ ... } }': () 42..113 'match ... }': () 48..51 'foo': Foo 62..84 'const ... 32) }': Foo 68..84 '{ Foo(... 32) }': Foo 70..73 'Foo': Foo(usize) -> Foo 70..82 'Foo(15 + 32)': Foo 74..76 '15': usize 74..81 '15 + 32': usize 79..81 '32': usize 88..90 '{}': () 100..101 '_': Foo 105..107 '{}': () "#]], ); } #[test] fn macro_pat() { check_types( r#" macro_rules! pat { ($name:ident) => { Enum::Variant1($name) } } enum Enum { Variant1(u8), Variant2, } fn f(e: Enum) { match e { pat!(bind) => { bind; //^^^^ u8 } Enum::Variant2 => {} } } "#, ) }