| 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, add, builtin_impls | |
| fn test(x: &i32) { | |
| let y = x; | |
| let &z = x; | |
| let a = z; | |
| let (c, d) = (1, "hello"); | |
| for (e, f) in [(0, 1)] { | |
| let g = e; | |
| } | |
| if let [val] = [y] { | |
| 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..399 '{ ...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"': &'static str | |
| 101..150 'for (e... }': ! | |
| 101..150 'for (e... }': IntoIter<(i32, i32), 1> | |
| 101..150 'for (e... }': &'? mut IntoIter<(i32, i32), 1> | |
| 101..150 'for (e... }': fn next<IntoIter<(i32, i32), 1>>(&'? mut IntoIter<(i32, i32), 1>) -> Option<<IntoIter<(i32, i32), 1> as Iterator>::Item> | |
| 101..150 'for (e... }': Option<(i32, i32)> | |
| 101..150 'for (e... }': () | |
| 101..150 'for (e... }': () | |
| 101..150 'for (e... }': () | |
| 101..150 'for (e... }': () | |
| 105..111 '(e, f)': (i32, i32) | |
| 106..107 'e': i32 | |
| 109..110 'f': i32 | |
| 115..123 '[(0, 1)]': [(i32, i32); 1] | |
| 115..123 '[(0, 1)]': fn into_iter<[(i32, i32); 1]>([(i32, i32); 1]) -> <[(i32, i32); 1] as IntoIterator>::IntoIter | |
| 115..123 '[(0, 1)]': IntoIter<(i32, i32), 1> | |
| 116..122 '(0, 1)': (i32, i32) | |
| 117..118 '0': i32 | |
| 120..121 '1': i32 | |
| 124..150 '{ ... }': () | |
| 138..139 'g': i32 | |
| 142..143 'e': i32 | |
| 156..203 'if let... }': () | |
| 159..174 'let [val] = [y]': bool | |
| 163..168 '[val]': [&'? i32; 1] | |
| 164..167 'val': &'? i32 | |
| 171..174 '[y]': [&'? i32; 1] | |
| 172..173 'y': &'? i32 | |
| 175..203 '{ ... }': () | |
| 189..190 'h': &'? i32 | |
| 193..196 'val': &'? i32 | |
| 209..235 'if let...rue {}': () | |
| 212..232 'let x ... &true': bool | |
| 216..224 'x @ true': &'? bool | |
| 220..224 'true': bool | |
| 220..224 'true': bool | |
| 227..232 '&true': &'? bool | |
| 228..232 'true': bool | |
| 233..235 '{}': () | |
| 245..251 'lambda': impl Fn(u64, u64, i32) -> i32 | |
| 254..286 '|a: u6...b; c }': impl Fn(u64, u64, i32) -> i32 | |
| 255..256 'a': u64 | |
| 263..264 'b': u64 | |
| 266..267 'c': i32 | |
| 274..286 '{ a + b; c }': i32 | |
| 276..277 'a': u64 | |
| 276..281 'a + b': u64 | |
| 280..281 'b': u64 | |
| 283..284 'c': i32 | |
| 297..309 'ref ref_to_x': &'? &'? i32 | |
| 312..313 'x': &'? i32 | |
| 323..332 'mut mut_x': &'? i32 | |
| 335..336 'x': &'? i32 | |
| 346..366 'ref mu...f_to_x': &'? mut &'? i32 | |
| 369..370 'x': &'? i32 | |
| 380..381 'k': &'? mut &'? i32 | |
| 384..396 '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 1f16 = any() {} | |
| if let 1f32 = any() {} | |
| if let 1.0 = any() {} | |
| if let 1f128 = any() {} | |
| if let true = any() {} | |
| } | |
| "#, | |
| expect![[r#" | |
| 17..28 '{ loop {} }': T | |
| 19..26 'loop {}': ! | |
| 24..26 '{}': () | |
| 37..38 'x': &'? i32 | |
| 46..263 '{ ...) {} }': () | |
| 52..75 'if let...y() {}': () | |
| 55..72 'let "f... any()': bool | |
| 59..64 '"foo"': &'static str | |
| 59..64 '"foo"': &'static 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 '1f16': f16 | |
| 138..142 '1f16': f16 | |
| 145..148 'any': fn any<f16>() -> f16 | |
| 145..150 'any()': f16 | |
| 151..153 '{}': () | |
| 158..180 'if let...y() {}': () | |
| 161..177 'let 1f... any()': bool | |
| 165..169 '1f32': f32 | |
| 165..169 '1f32': f32 | |
| 172..175 'any': fn any<f32>() -> f32 | |
| 172..177 'any()': f32 | |
| 178..180 '{}': () | |
| 185..206 'if let...y() {}': () | |
| 188..203 'let 1.0 = any()': bool | |
| 192..195 '1.0': f64 | |
| 192..195 '1.0': f64 | |
| 198..201 'any': fn any<f64>() -> f64 | |
| 198..203 'any()': f64 | |
| 204..206 '{}': () | |
| 211..234 'if let...y() {}': () | |
| 214..231 'let 1f... any()': bool | |
| 218..223 '1f128': f128 | |
| 218..223 '1f128': f128 | |
| 226..229 'any': fn any<f128>() -> f128 | |
| 226..231 'any()': f128 | |
| 232..234 '{}': () | |
| 239..261 'if let...y() {}': () | |
| 242..258 'let tr... any()': bool | |
| 246..250 'true': bool | |
| 246..250 'true': bool | |
| 253..256 'any': fn any<bool>() -> bool | |
| 253..258 'any()': bool | |
| 259..261 '{}': () | |
| "#]], | |
| ); | |
| } | |
| #[test] | |
| fn infer_range_pattern() { | |
| check_infer_with_mismatches( | |
| r#" | |
| fn test() { | |
| if let 1..76 = 2u32 {} | |
| if let 1..=76 = 2u32 {} | |
| } | |
| "#, | |
| expect![[r#" | |
| 10..68 '{ ...2 {} }': () | |
| 16..38 'if let...u32 {}': () | |
| 19..35 'let 1....= 2u32': bool | |
| 23..24 '1': u32 | |
| 23..28 '1..76': u32 | |
| 26..28 '76': u32 | |
| 31..35 '2u32': u32 | |
| 36..38 '{}': () | |
| 43..66 'if let...u32 {}': () | |
| 46..63 'let 1....= 2u32': bool | |
| 50..51 '1': u32 | |
| 50..56 '1..=76': u32 | |
| 54..56 '76': u32 | |
| 59..63 '2u32': u32 | |
| 64..66 '{}': () | |
| "#]], | |
| ); | |
| check_no_mismatches( | |
| r#" | |
| //- minicore: range | |
| fn main() { | |
| let byte: u8 = 0u8; | |
| let b = match byte { | |
| b'0'..=b'9' => true, | |
| _ => false, | |
| }; | |
| } | |
| "#, | |
| ); | |
| } | |
| #[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': fn 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': fn A<i32>(i32) -> A<i32> | |
| 71..75 'A(1)': A<i32> | |
| 73..74 '1': i32 | |
| "#]], | |
| ); | |
| } | |
| #[test] | |
| fn infer_pattern_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#" | |
| //- minicore: fn | |
| 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"': &'static str | |
| 43..96 'match ... }': () | |
| 49..50 's': &'? str | |
| 61..68 '"hello"': &'static str | |
| 61..68 '"hello"': &'static str | |
| 72..74 '{}': () | |
| 83..84 '_': &'? str | |
| 88..90 '{}': () | |
| "#]], | |
| ); | |
| } | |
| #[test] | |
| fn infer_pattern_match_byte_string_literal() { | |
| check_infer_with_mismatches( | |
| r#" | |
| //- minicore: index, range | |
| 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': RangeFull | |
| 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"': &'static [u8] | |
| 216..222 'b"foo"': &'static [u8; 3] | |
| 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"': &'static [u8; 3] | |
| 245..251 'b"foo"': &'static [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"': &'static str | |
| 43..106 'match ... }': () | |
| 49..50 's': &'? str | |
| 61..68 '"hello"': &'static str | |
| 61..68 '"hello"': &'static str | |
| 61..78 '"hello...world"': &'? str | |
| 71..78 '"world"': &'static str | |
| 71..78 '"world"': &'static 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': fn 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': fn Foo(usize) -> Foo | |
| 105..112 'Foo(0,)': Foo | |
| 109..110 '0': usize | |
| 126..134 'Self(s,)': Foo | |
| 131..132 's': usize | |
| 137..140 'Foo': fn 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, Some(T) } | |
| 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"': &'static 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"': &'static 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#" | |
| #![feature(lang_items)] | |
| pub struct Global; | |
| #[lang = "owned_box"] | |
| pub struct Box<T, A = Global>(T); | |
| fn foo(params: Box<i32>) { | |
| match params { | |
| box integer => {} | |
| } | |
| } | |
| "#, | |
| expect![[r#" | |
| 108..114 'params': Box<i32, Global> | |
| 126..180 '{ ... } }': () | |
| 132..178 'match ... }': () | |
| 138..144 'params': Box<i32, Global> | |
| 155..166 'box integer': Box<i32, Global> | |
| 159..166 'integer': i32 | |
| 170..172 '{}': () | |
| "#]], | |
| ); | |
| check_infer( | |
| r#" | |
| #![feature(lang_items)] | |
| #[lang = "owned_box"] | |
| pub struct Box<T>(T); | |
| fn foo(params: Box<i32>) { | |
| match params { | |
| box integer => {} | |
| } | |
| } | |
| "#, | |
| expect![[r#" | |
| 77..83 'params': Box<i32> | |
| 95..149 '{ ... } }': () | |
| 101..147 'match ... }': () | |
| 107..113 'params': Box<i32> | |
| 124..135 'box integer': Box<i32> | |
| 128..135 'integer': i32 | |
| 139..141 '{}': () | |
| "#]], | |
| ); | |
| } | |
| #[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 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#" | |
| #![feature(lang_items)] | |
| #[lang = "va_list"] | |
| pub struct VaListImpl<'f>; | |
| fn my_fn(foo: ...) {} | |
| //^^^ VaListImpl<'?> | |
| fn my_fn2(bar: u32, foo: ...) {} | |
| //^^^ VaListImpl<'?> | |
| "#, | |
| ); | |
| } | |
| #[test] | |
| fn var_args_cond() { | |
| check_types( | |
| r#" | |
| #![feature(lang_items)] | |
| #[lang = "va_list"] | |
| pub struct VaListImpl<'f>; | |
| fn my_fn(bar: u32, #[cfg(FALSE)] foo: ..., #[cfg(not(FALSE))] foo: u32) { | |
| foo; | |
| //^^^ u32 | |
| } | |
| "#, | |
| ); | |
| } | |
| #[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 | |
| _ => (), | |
| } | |
| } | |
| "#, | |
| ); | |
| } | |
| #[test] | |
| fn destructuring_assign_ref() { | |
| check_no_mismatches( | |
| r#" | |
| struct Foo; | |
| fn foo() -> (&'static Foo, u32) { | |
| (&Foo, 0) | |
| } | |
| fn bar() { | |
| let ext: &Foo; | |
| let v; | |
| (ext, v) = foo(); | |
| } | |
| "#, | |
| ); | |
| } | |
| #[test] | |
| fn deref_pattern() { | |
| check_infer( | |
| r#" | |
| //- minicore: deref_pat | |
| use core::ops::{Deref, DerefPure}; | |
| #[lang = "owned_box"] | |
| pub struct Box<T>(T); | |
| impl<T> Deref for Box<T> { | |
| type Target = T; | |
| fn deref(&self) -> &Self::Target { | |
| loop {} | |
| } | |
| } | |
| impl<T> DerefPure for Box<T> {} | |
| pub struct Foo<T>(T); | |
| impl<T> Deref for Foo<T> { | |
| type Target = [T]; | |
| fn deref(&self) -> &Self::Target { | |
| loop {} | |
| } | |
| } | |
| impl<T> DerefPure for Foo<T> {} | |
| fn foo(v: &Box<Foo<i32>>) { | |
| match v { | |
| deref!(deref!(inner)) => {} | |
| _ => {} | |
| } | |
| } | |
| "#, | |
| expect![[r#" | |
| 142..146 'self': &'? Box<T> | |
| 165..188 '{ ... }': &'? T | |
| 175..182 'loop {}': ! | |
| 180..182 '{}': () | |
| 310..314 'self': &'? Foo<T> | |
| 333..356 '{ ... }': &'? [T] | |
| 343..350 'loop {}': ! | |
| 348..350 '{}': () | |
| !0..20 'builti...inner)': Foo<i32> | |
| !0..28 'builti...nner))': Box<Foo<i32>> | |
| !14..19 'inner': &'? [i32] | |
| 399..400 'v': &'? Box<Foo<i32>> | |
| 418..493 '{ ... } }': () | |
| 424..491 'match ... }': () | |
| 430..431 'v': &'? Box<Foo<i32>> | |
| 467..469 '{}': () | |
| 478..479 '_': &'? Box<Foo<i32>> | |
| 483..485 '{}': () | |
| "#]], | |
| ); | |
| } |