| use expect_test::expect; |
| |
| use super::{check, check_infer, check_infer_with_mismatches, check_no_mismatches, check_types}; |
| |
| #[test] |
| fn infer_pattern() { |
| check_infer( |
| r#" |
| //- minicore: iterator |
| 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; |
| } |
| |
| if let x @ true = &true {} |
| |
| 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..400 '{ ...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... }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter |
| 101..151 'for (e... }': {unknown} |
| 101..151 'for (e... }': ! |
| 101..151 'for (e... }': {unknown} |
| 101..151 'for (e... }': &mut {unknown} |
| 101..151 'for (e... }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item> |
| 101..151 'for (e... }': Option<({unknown}, {unknown})> |
| 101..151 'for (e... }': () |
| 101..151 'for (e... }': () |
| 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... }': () |
| 160..175 'let [val] = opt': bool |
| 164..169 '[val]': [{unknown}] |
| 165..168 'val': {unknown} |
| 172..175 'opt': [{unknown}] |
| 176..204 '{ ... }': () |
| 190..191 'h': {unknown} |
| 194..197 'val': {unknown} |
| 210..236 'if let...rue {}': () |
| 213..233 'let x ... &true': bool |
| 217..225 'x @ true': &bool |
| 221..225 'true': bool |
| 221..225 'true': bool |
| 228..233 '&true': &bool |
| 229..233 'true': bool |
| 234..236 '{}': () |
| 246..252 'lambda': impl Fn(u64, u64, i32) -> i32 |
| 255..287 '|a: u6...b; c }': impl Fn(u64, u64, i32) -> i32 |
| 256..257 'a': u64 |
| 264..265 'b': u64 |
| 267..268 'c': i32 |
| 275..287 '{ a + b; c }': i32 |
| 277..278 'a': u64 |
| 277..282 'a + b': u64 |
| 281..282 'b': u64 |
| 284..285 'c': i32 |
| 298..310 'ref ref_to_x': &&i32 |
| 313..314 'x': &i32 |
| 324..333 'mut mut_x': &i32 |
| 336..337 'x': &i32 |
| 347..367 'ref mu...f_to_x': &mut &i32 |
| 370..371 'x': &i32 |
| 381..382 'k': &mut &i32 |
| 385..397 '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() {}': () |
| 55..72 'let "f... any()': bool |
| 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() {}': () |
| 83..96 'let 1 = any()': bool |
| 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() {}': () |
| 107..123 'let 1u... any()': bool |
| 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() {}': () |
| 134..150 'let 1f... any()': bool |
| 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() {}': () |
| 161..176 'let 1.0 = any()': bool |
| 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() {}': () |
| 187..203 'let tr... any()': bool |
| 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 {}': () |
| 26..42 'let 1....= 2u32': bool |
| 30..35 '1..76': u32 |
| 38..42 '2u32': u32 |
| 43..45 '{}': () |
| 50..73 'if let...u32 {}': () |
| 53..70 'let 1....= 2u32': bool |
| 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': extern "rust-call" 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': extern "rust-call" A<i32>(i32) -> A<i32> |
| 71..75 'A(1)': A<i32> |
| 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 ref_pat_with_inference_variable() { |
| check_no_mismatches( |
| r#" |
| enum E { A } |
| fn test() { |
| let f = |e| match e { |
| &E::A => {} |
| }; |
| f(&E::A); |
| } |
| "#, |
| ); |
| } |
| |
| #[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_byte_string_literal() { |
| check_infer_with_mismatches( |
| r#" |
| //- minicore: index |
| struct S; |
| impl<T, const N: usize> core::ops::Index<S> for [T; N] { |
| type Output = [u8]; |
| fn index(&self, index: core::ops::RangeFull) -> &Self::Output { |
| loop {} |
| } |
| } |
| fn test(v: [u8; 3]) { |
| if let b"foo" = &v[S] {} |
| if let b"foo" = &v {} |
| } |
| "#, |
| expect![[r#" |
| 105..109 'self': &[T; N] |
| 111..116 'index': {unknown} |
| 157..180 '{ ... }': &[u8] |
| 167..174 'loop {}': ! |
| 172..174 '{}': () |
| 191..192 'v': [u8; 3] |
| 203..261 '{ ...v {} }': () |
| 209..233 'if let...[S] {}': () |
| 212..230 'let b"... &v[S]': bool |
| 216..222 'b"foo"': &[u8] |
| 216..222 'b"foo"': &[u8] |
| 225..230 '&v[S]': &[u8] |
| 226..227 'v': [u8; 3] |
| 226..230 'v[S]': [u8] |
| 228..229 'S': S |
| 231..233 '{}': () |
| 238..259 'if let... &v {}': () |
| 241..256 'let b"foo" = &v': bool |
| 245..251 'b"foo"': &[u8; 3] |
| 245..251 'b"foo"': &[u8; 3] |
| 254..256 '&v': &[u8; 3] |
| 255..256 'v': [u8; 3] |
| 257..259 '{}': () |
| "#]], |
| ); |
| } |
| |
| #[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; 2] |
| 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; 2] |
| 72..80 '[1.0, a]': [f64; 2] |
| 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; 2] |
| 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 tuple_struct_destructured_with_self() { |
| check_infer( |
| r#" |
| struct Foo(usize,); |
| impl Foo { |
| fn f() { |
| let Self(s,) = &Foo(0,); |
| let Self(s,) = &mut Foo(0,); |
| let Self(s,) = Foo(0,); |
| } |
| } |
| "#, |
| expect![[r#" |
| 42..151 '{ ... }': () |
| 56..64 'Self(s,)': Foo |
| 61..62 's': &usize |
| 67..75 '&Foo(0,)': &Foo |
| 68..71 'Foo': extern "rust-call" Foo(usize) -> Foo |
| 68..75 'Foo(0,)': Foo |
| 72..73 '0': usize |
| 89..97 'Self(s,)': Foo |
| 94..95 's': &mut usize |
| 100..112 '&mut Foo(0,)': &mut Foo |
| 105..108 'Foo': extern "rust-call" Foo(usize) -> Foo |
| 105..112 'Foo(0,)': Foo |
| 109..110 '0': usize |
| 126..134 'Self(s,)': Foo |
| 131..132 's': usize |
| 137..140 'Foo': extern "rust-call" Foo(usize) -> Foo |
| 137..144 'Foo(0,)': Foo |
| 141..142 '0': usize |
| "#]], |
| ); |
| } |
| |
| #[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( |
| 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 => () }; |
| // ^^^ expected (), got Foo |
| let _: () = match () { Bar => () }; |
| // ^^^ 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#" |
| //- minicore: fn |
| 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#" |
| 32..33 't': T |
| 38..39 'f': F |
| 49..60 '{ loop {} }': U |
| 51..58 'loop {}': ! |
| 56..58 '{}': () |
| 72..171 '{ ... x); }': () |
| 78..81 'foo': fn foo<&(i32, &str), i32, impl FnOnce(&(i32, &str)) -> i32>(&(i32, &str), impl FnOnce(&(i32, &str)) -> i32) -> i32 |
| 78..105 'foo(&(...y)| x)': i32 |
| 82..91 '&(1, "a")': &(i32, &str) |
| 83..91 '(1, "a")': (i32, &str) |
| 84..85 '1': i32 |
| 87..90 '"a"': &str |
| 93..104 '|&(x, y)| x': impl FnOnce(&(i32, &str)) -> i32 |
| 94..101 '&(x, y)': &(i32, &str) |
| 95..101 '(x, y)': (i32, &str) |
| 96..97 'x': i32 |
| 99..100 'y': &str |
| 103..104 'x': i32 |
| 142..145 'foo': fn foo<&(i32, &str), &i32, impl FnOnce(&(i32, &str)) -> &i32>(&(i32, &str), impl FnOnce(&(i32, &str)) -> &i32) -> &i32 |
| 142..168 'foo(&(...y)| x)': &i32 |
| 146..155 '&(1, "a")': &(i32, &str) |
| 147..155 '(1, "a")': (i32, &str) |
| 148..149 '1': i32 |
| 151..154 '"a"': &str |
| 157..167 '|(x, y)| x': impl FnOnce(&(i32, &str)) -> &i32 |
| 158..164 '(x, y)': (i32, &str) |
| 159..160 'x': &i32 |
| 162..163 'y': &&str |
| 166..167 '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, A = Global>(T); |
| |
| fn foo(params: Box<i32>) { |
| match params { |
| box integer => {} |
| } |
| } |
| "#, |
| expect![[r#" |
| 83..89 'params': Box<i32, Global> |
| 101..155 '{ ... } }': () |
| 107..153 'match ... }': () |
| 113..119 'params': Box<i32, Global> |
| 130..141 'box integer': Box<i32, Global> |
| 134..141 'integer': i32 |
| 145..147 '{}': () |
| "#]], |
| ); |
| 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_with_mismatches( |
| 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 '{}': () |
| 136..142: expected (u8, i16, f32), got (u8, i16) |
| 170..182: expected (u8, i16, f32), got (u8, i16, f32, {unknown}) |
| "#]], |
| ); |
| } |
| |
| #[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': extern "rust-call" 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 => {} |
| } |
| } |
| "#, |
| ) |
| } |
| |
| #[test] |
| fn type_mismatch_in_or_pattern() { |
| check_infer_with_mismatches( |
| r#" |
| fn main() { |
| match (false,) { |
| (true | (),) => {} |
| (() | true,) => {} |
| (_ | (),) => {} |
| (() | _,) => {} |
| } |
| } |
| "#, |
| expect![[r#" |
| 10..142 '{ ... } }': () |
| 16..140 'match ... }': () |
| 22..30 '(false,)': (bool,) |
| 23..28 'false': bool |
| 41..53 '(true | (),)': (bool,) |
| 42..46 'true': bool |
| 42..46 'true': bool |
| 42..51 'true | ()': bool |
| 49..51 '()': () |
| 57..59 '{}': () |
| 68..80 '(() | true,)': (bool,) |
| 69..71 '()': () |
| 69..78 '() | true': bool |
| 74..78 'true': bool |
| 74..78 'true': bool |
| 84..86 '{}': () |
| 95..104 '(_ | (),)': (bool,) |
| 96..97 '_': bool |
| 96..102 '_ | ()': bool |
| 100..102 '()': () |
| 108..110 '{}': () |
| 119..128 '(() | _,)': (bool,) |
| 120..122 '()': () |
| 120..126 '() | _': bool |
| 125..126 '_': bool |
| 132..134 '{}': () |
| 49..51: expected bool, got () |
| 69..71: expected bool, got () |
| 100..102: expected bool, got () |
| 120..122: expected bool, got () |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn slice_pattern_correctly_handles_array_length() { |
| check_infer( |
| r#" |
| fn main() { |
| let [head, middle @ .., tail, tail2] = [1, 2, 3, 4, 5]; |
| } |
| "#, |
| expect![[r#" |
| 10..73 '{ ... 5]; }': () |
| 20..52 '[head,...tail2]': [i32; 5] |
| 21..25 'head': i32 |
| 27..38 'middle @ ..': [i32; 2] |
| 36..38 '..': [i32; 2] |
| 40..44 'tail': i32 |
| 46..51 'tail2': i32 |
| 55..70 '[1, 2, 3, 4, 5]': [i32; 5] |
| 56..57 '1': i32 |
| 59..60 '2': i32 |
| 62..63 '3': i32 |
| 65..66 '4': i32 |
| 68..69 '5': i32 |
| "#]], |
| ); |
| } |
| |
| #[test] |
| fn pattern_lookup_in_value_ns() { |
| check_types( |
| r#" |
| use self::Constructor::*; |
| struct IntRange { |
| range: (), |
| } |
| enum Constructor { |
| IntRange(IntRange), |
| } |
| fn main() { |
| match Constructor::IntRange(IntRange { range: () }) { |
| IntRange(x) => { |
| x; |
| //^ IntRange |
| } |
| Constructor::IntRange(x) => { |
| x; |
| //^ IntRange |
| } |
| } |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn if_let_guards() { |
| check_types( |
| r#" |
| fn main() { |
| match (0,) { |
| opt if let (x,) = opt => { |
| x; |
| //^ i32 |
| } |
| _ => {} |
| } |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn tuple_wildcard() { |
| check_types( |
| r#" |
| fn main() { |
| enum Option<T> {Some(T), None} |
| use Option::*; |
| |
| let mut x = None; |
| x; |
| //^ Option<(i32, i32)> |
| |
| if let Some((_, _a)) = x {} |
| |
| x = Some((1, 2)); |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn cfg_params() { |
| check_types( |
| r#" |
| fn my_fn(#[cfg(feature = "feature")] u8: u8, u32: u32) {} |
| //^^^ u32 |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn var_args() { |
| check_types( |
| r#" |
| #[lang = "va_list"] |
| pub struct VaListImpl<'f>; |
| fn my_fn(foo: ...) {} |
| //^^^ VaListImpl<'_> |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn ref_pat_mutability() { |
| check( |
| r#" |
| fn foo() { |
| let &() = &(); |
| let &mut () = &mut (); |
| let &mut () = &(); |
| //^^^^^^^ expected &(), got &mut () |
| let &() = &mut (); |
| //^^^ expected &mut (), got &() |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn generic_alias() { |
| check_types( |
| r#" |
| type Wrap<T> = T; |
| |
| enum X { |
| A { cool: u32, stuff: u32 }, |
| B, |
| } |
| |
| fn main() { |
| let wrapped = Wrap::<X>::A { |
| cool: 100, |
| stuff: 100, |
| }; |
| |
| if let Wrap::<X>::A { cool, ..} = &wrapped {} |
| //^^^^ &u32 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn generic_alias_with_qualified_path() { |
| check_types( |
| r#" |
| type Wrap<T> = T; |
| |
| struct S; |
| |
| trait Schematic { |
| type Props; |
| } |
| |
| impl Schematic for S { |
| type Props = X; |
| } |
| |
| enum X { |
| A { cool: u32, stuff: u32 }, |
| B, |
| } |
| |
| fn main() { |
| let wrapped = Wrap::<<S as Schematic>::Props>::A { |
| cool: 100, |
| stuff: 100, |
| }; |
| |
| if let Wrap::<<S as Schematic>::Props>::A { cool, ..} = &wrapped {} |
| //^^^^ &u32 |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn type_mismatch_pat_const_reference() { |
| check_no_mismatches( |
| r#" |
| const TEST_STR: &'static str = "abcd"; |
| |
| fn main() { |
| let s = "abcd"; |
| match s { |
| TEST_STR => (), |
| _ => (), |
| } |
| } |
| |
| "#, |
| ); |
| check( |
| r#" |
| struct Foo<T>(T); |
| |
| impl<T> Foo<T> { |
| const TEST_I32_REF: &'static i32 = &3; |
| const TEST_I32: i32 = 3; |
| } |
| |
| fn main() { |
| match &6 { |
| Foo::<i32>::TEST_I32_REF => (), |
| Foo::<i32>::TEST_I32 => (), |
| //^^^^^^^^^^^^^^^^^^^^ expected &i32, got i32 |
| _ => (), |
| } |
| } |
| |
| "#, |
| ); |
| } |