use super::infer_with_mismatches; use insta::assert_snapshot; use test_utils::covers; // Infer with some common definitions and impls. fn infer(source: &str) -> String { let defs = r#" #[lang = "sized"] pub trait Sized {} #[lang = "unsize"] pub trait Unsize {} #[lang = "coerce_unsized"] pub trait CoerceUnsized {} impl<'a, 'b: 'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} "#; // Append to the end to keep positions unchanged. super::infer(&format!("{}{}", source, defs)) } #[test] fn infer_block_expr_type_mismatch() { assert_snapshot!( infer(r#" fn test() { let a: i32 = { 1i64 }; } "#), @r###" 11..41 '{ ...4 }; }': () 21..22 'a': i32 30..38 '{ 1i64 }': i64 32..36 '1i64': i64 "###); } #[test] fn coerce_places() { assert_snapshot!( infer(r#" struct S { a: T } fn f(_: &[T]) -> T { loop {} } fn g(_: S<&[T]>) -> T { loop {} } fn gen() -> *mut [T; 2] { loop {} } fn test1() -> *mut [U] { gen() } fn test2() { let arr: &[u8; 1] = &[1]; let a: &[_] = arr; let b = f(arr); let c: &[_] = { arr }; let d = g(S { a: arr }); let e: [&[_]; 1] = [arr]; let f: [&[_]; 2] = [arr; 2]; let g: (&[_], &[_]) = (arr, arr); } "#), @r###" 31..32 '_': &[T] 45..56 '{ loop {} }': T 47..54 'loop {}': ! 52..54 '{}': () 65..66 '_': S<&[T]> 82..93 '{ loop {} }': T 84..91 'loop {}': ! 89..91 '{}': () 122..133 '{ loop {} }': *mut [T; _] 124..131 'loop {}': ! 129..131 '{}': () 160..173 '{ gen() }': *mut [U] 166..169 'gen': fn gen() -> *mut [U; _] 166..171 'gen()': *mut [U; _] 186..420 '{ ...rr); }': () 196..199 'arr': &[u8; _] 212..216 '&[1]': &[u8; _] 213..216 '[1]': [u8; _] 214..215 '1': u8 227..228 'a': &[u8] 237..240 'arr': &[u8; _] 250..251 'b': u8 254..255 'f': fn f(&[u8]) -> u8 254..260 'f(arr)': u8 256..259 'arr': &[u8; _] 270..271 'c': &[u8] 280..287 '{ arr }': &[u8] 282..285 'arr': &[u8; _] 297..298 'd': u8 301..302 'g': fn g(S<&[u8]>) -> u8 301..316 'g(S { a: arr })': u8 303..315 'S { a: arr }': S<&[u8]> 310..313 'arr': &[u8; _] 326..327 'e': [&[u8]; _] 341..346 '[arr]': [&[u8]; _] 342..345 'arr': &[u8; _] 356..357 'f': [&[u8]; _] 371..379 '[arr; 2]': [&[u8]; _] 372..375 'arr': &[u8; _] 377..378 '2': usize 389..390 'g': (&[u8], &[u8]) 407..417 '(arr, arr)': (&[u8], &[u8]) 408..411 'arr': &[u8; _] 413..416 'arr': &[u8; _] "### ); } #[test] fn infer_let_stmt_coerce() { assert_snapshot!( infer(r#" fn test() { let x: &[i32] = &[1]; } "#), @r###" 11..40 '{ ...[1]; }': () 21..22 'x': &[i32] 33..37 '&[1]': &[i32; _] 34..37 '[1]': [i32; _] 35..36 '1': i32 "###); } #[test] fn infer_custom_coerce_unsized() { assert_snapshot!( infer(r#" struct A(*const T); struct B(*const T); struct C { inner: *const T } impl, U: ?Sized> CoerceUnsized> for B {} impl, U: ?Sized> CoerceUnsized> for C {} fn foo1(x: A<[T]>) -> A<[T]> { x } fn foo2(x: B<[T]>) -> B<[T]> { x } fn foo3(x: C<[T]>) -> C<[T]> { x } fn test(a: A<[u8; 2]>, b: B<[u8; 2]>, c: C<[u8; 2]>) { let d = foo1(a); let e = foo2(b); let f = foo3(c); } "#), @r###" 258..259 'x': A<[T]> 279..284 '{ x }': A<[T]> 281..282 'x': A<[T]> 296..297 'x': B<[T]> 317..322 '{ x }': B<[T]> 319..320 'x': B<[T]> 334..335 'x': C<[T]> 355..360 '{ x }': C<[T]> 357..358 'x': C<[T]> 370..371 'a': A<[u8; _]> 385..386 'b': B<[u8; _]> 400..401 'c': C<[u8; _]> 415..481 '{ ...(c); }': () 425..426 'd': A<[{unknown}]> 429..433 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> 429..436 'foo1(a)': A<[{unknown}]> 434..435 'a': A<[u8; _]> 446..447 'e': B<[u8]> 450..454 'foo2': fn foo2(B<[u8]>) -> B<[u8]> 450..457 'foo2(b)': B<[u8]> 455..456 'b': B<[u8; _]> 467..468 'f': C<[u8]> 471..475 'foo3': fn foo3(C<[u8]>) -> C<[u8]> 471..478 'foo3(c)': C<[u8]> 476..477 'c': C<[u8; _]> "### ); } #[test] fn infer_if_coerce() { assert_snapshot!( infer(r#" fn foo(x: &[T]) -> &[T] { loop {} } fn test() { let x = if true { foo(&[1]) } else { &[1] }; } "#), @r###" 11..12 'x': &[T] 28..39 '{ loop {} }': &[T] 30..37 'loop {}': ! 35..37 '{}': () 50..126 '{ ... }; }': () 60..61 'x': &[i32] 64..123 'if tru... }': &[i32] 67..71 'true': bool 72..97 '{ ... }': &[i32] 82..85 'foo': fn foo(&[i32]) -> &[i32] 82..91 'foo(&[1])': &[i32] 86..90 '&[1]': &[i32; _] 87..90 '[1]': [i32; _] 88..89 '1': i32 103..123 '{ ... }': &[i32; _] 113..117 '&[1]': &[i32; _] 114..117 '[1]': [i32; _] 115..116 '1': i32 "### ); } #[test] fn infer_if_else_coerce() { assert_snapshot!( infer(r#" fn foo(x: &[T]) -> &[T] { loop {} } fn test() { let x = if true { &[1] } else { foo(&[1]) }; } "#), @r###" 11..12 'x': &[T] 28..39 '{ loop {} }': &[T] 30..37 'loop {}': ! 35..37 '{}': () 50..126 '{ ... }; }': () 60..61 'x': &[i32] 64..123 'if tru... }': &[i32] 67..71 'true': bool 72..92 '{ ... }': &[i32; _] 82..86 '&[1]': &[i32; _] 83..86 '[1]': [i32; _] 84..85 '1': i32 98..123 '{ ... }': &[i32] 108..111 'foo': fn foo(&[i32]) -> &[i32] 108..117 'foo(&[1])': &[i32] 112..116 '&[1]': &[i32; _] 113..116 '[1]': [i32; _] 114..115 '1': i32 "### ); } #[test] fn infer_match_first_coerce() { assert_snapshot!( infer(r#" fn foo(x: &[T]) -> &[T] { loop {} } fn test(i: i32) { let x = match i { 2 => foo(&[2]), 1 => &[1], _ => &[3], }; } "#), @r###" 11..12 'x': &[T] 28..39 '{ loop {} }': &[T] 30..37 'loop {}': ! 35..37 '{}': () 48..49 'i': i32 56..150 '{ ... }; }': () 66..67 'x': &[i32] 70..147 'match ... }': &[i32] 76..77 'i': i32 88..89 '2': i32 88..89 '2': i32 93..96 'foo': fn foo(&[i32]) -> &[i32] 93..102 'foo(&[2])': &[i32] 97..101 '&[2]': &[i32; _] 98..101 '[2]': [i32; _] 99..100 '2': i32 112..113 '1': i32 112..113 '1': i32 117..121 '&[1]': &[i32; _] 118..121 '[1]': [i32; _] 119..120 '1': i32 131..132 '_': i32 136..140 '&[3]': &[i32; _] 137..140 '[3]': [i32; _] 138..139 '3': i32 "### ); } #[test] fn infer_match_second_coerce() { assert_snapshot!( infer(r#" fn foo(x: &[T]) -> &[T] { loop {} } fn test(i: i32) { let x = match i { 1 => &[1], 2 => foo(&[2]), _ => &[3], }; } "#), @r###" 11..12 'x': &[T] 28..39 '{ loop {} }': &[T] 30..37 'loop {}': ! 35..37 '{}': () 48..49 'i': i32 56..150 '{ ... }; }': () 66..67 'x': &[i32] 70..147 'match ... }': &[i32] 76..77 'i': i32 88..89 '1': i32 88..89 '1': i32 93..97 '&[1]': &[i32; _] 94..97 '[1]': [i32; _] 95..96 '1': i32 107..108 '2': i32 107..108 '2': i32 112..115 'foo': fn foo(&[i32]) -> &[i32] 112..121 'foo(&[2])': &[i32] 116..120 '&[2]': &[i32; _] 117..120 '[2]': [i32; _] 118..119 '2': i32 131..132 '_': i32 136..140 '&[3]': &[i32; _] 137..140 '[3]': [i32; _] 138..139 '3': i32 "### ); } #[test] fn coerce_merge_one_by_one1() { covers!(coerce_merge_fail_fallback); assert_snapshot!( infer(r#" fn test() { let t = &mut 1; let x = match 1 { 1 => t as *mut i32, 2 => t as &i32, _ => t as *const i32, }; } "#), @r###" 11..145 '{ ... }; }': () 21..22 't': &mut i32 25..31 '&mut 1': &mut i32 30..31 '1': i32 41..42 'x': *const i32 45..142 'match ... }': *const i32 51..52 '1': i32 63..64 '1': i32 63..64 '1': i32 68..69 't': &mut i32 68..81 't as *mut i32': *mut i32 91..92 '2': i32 91..92 '2': i32 96..97 't': &mut i32 96..105 't as &i32': &i32 115..116 '_': i32 120..121 't': &mut i32 120..135 't as *const i32': *const i32 "### ); } #[test] fn return_coerce_unknown() { assert_snapshot!( infer_with_mismatches(r#" fn foo() -> u32 { return unknown; } "#, true), @r###" 17..40 '{ ...own; }': ! 23..37 'return unknown': ! 30..37 'unknown': u32 "### ); } #[test] fn coerce_autoderef() { assert_snapshot!( infer_with_mismatches(r#" struct Foo; fn takes_ref_foo(x: &Foo) {} fn test() { takes_ref_foo(&Foo); takes_ref_foo(&&Foo); takes_ref_foo(&&&Foo); } "#, true), @r###" 30..31 'x': &Foo 39..41 '{}': () 52..133 '{ ...oo); }': () 58..71 'takes_ref_foo': fn takes_ref_foo(&Foo) 58..77 'takes_...(&Foo)': () 72..76 '&Foo': &Foo 73..76 'Foo': Foo 83..96 'takes_ref_foo': fn takes_ref_foo(&Foo) 83..103 'takes_...&&Foo)': () 97..102 '&&Foo': &&Foo 98..102 '&Foo': &Foo 99..102 'Foo': Foo 109..122 'takes_ref_foo': fn takes_ref_foo(&Foo) 109..130 'takes_...&&Foo)': () 123..129 '&&&Foo': &&&Foo 124..129 '&&Foo': &&Foo 125..129 '&Foo': &Foo 126..129 'Foo': Foo "### ); } #[test] fn coerce_autoderef_generic() { assert_snapshot!( infer_with_mismatches(r#" struct Foo; fn takes_ref(x: &T) -> T { *x } fn test() { takes_ref(&Foo); takes_ref(&&Foo); takes_ref(&&&Foo); } "#, true), @r###" 29..30 'x': &T 41..47 '{ *x }': T 43..45 '*x': T 44..45 'x': &T 58..127 '{ ...oo); }': () 64..73 'takes_ref': fn takes_ref(&Foo) -> Foo 64..79 'takes_ref(&Foo)': Foo 74..78 '&Foo': &Foo 75..78 'Foo': Foo 85..94 'takes_ref': fn takes_ref<&Foo>(&&Foo) -> &Foo 85..101 'takes_...&&Foo)': &Foo 95..100 '&&Foo': &&Foo 96..100 '&Foo': &Foo 97..100 'Foo': Foo 107..116 'takes_ref': fn takes_ref<&&Foo>(&&&Foo) -> &&Foo 107..124 'takes_...&&Foo)': &&Foo 117..123 '&&&Foo': &&&Foo 118..123 '&&Foo': &&Foo 119..123 '&Foo': &Foo 120..123 'Foo': Foo "### ); } #[test] fn coerce_autoderef_block() { assert_snapshot!( infer_with_mismatches(r#" struct String {} #[lang = "deref"] trait Deref { type Target; } impl Deref for String { type Target = str; } fn takes_ref_str(x: &str) {} fn returns_string() -> String { loop {} } fn test() { takes_ref_str(&{ returns_string() }); } "#, true), @r###" 127..128 'x': &str 136..138 '{}': () 169..180 '{ loop {} }': String 171..178 'loop {}': ! 176..178 '{}': () 191..236 '{ ... }); }': () 197..210 'takes_ref_str': fn takes_ref_str(&str) 197..233 'takes_...g() })': () 211..232 '&{ ret...ng() }': &String 212..232 '{ retu...ng() }': String 214..228 'returns_string': fn returns_string() -> String 214..230 'return...ring()': String "### ); } #[test] fn closure_return_coerce() { assert_snapshot!( infer_with_mismatches(r#" fn foo() { let x = || { if true { return &1u32; } &&1u32 }; } "#, true), @r###" 10..106 '{ ... }; }': () 20..21 'x': || -> &u32 24..103 '|| { ... }': || -> &u32 27..103 '{ ... }': &u32 37..82 'if tru... }': () 40..44 'true': bool 45..82 '{ ... }': ! 59..71 'return &1u32': ! 66..71 '&1u32': &u32 67..71 '1u32': u32 91..97 '&&1u32': &&u32 92..97 '&1u32': &u32 93..97 '1u32': u32 "### ); } #[test] fn coerce_fn_item_to_fn_ptr() { assert_snapshot!( infer_with_mismatches(r#" fn foo(x: u32) -> isize { 1 } fn test() { let f: fn(u32) -> isize = foo; } "#, true), @r###" 8..9 'x': u32 25..30 '{ 1 }': isize 27..28 '1': isize 41..79 '{ ...foo; }': () 51..52 'f': fn(u32) -> isize 73..76 'foo': fn foo(u32) -> isize "### ); } #[test] fn coerce_closure_to_fn_ptr() { assert_snapshot!( infer_with_mismatches(r#" fn test() { let f: fn(u32) -> isize = |x| { 1 }; } "#, true), @r###" 11..55 '{ ...1 }; }': () 21..22 'f': fn(u32) -> isize 43..52 '|x| { 1 }': |u32| -> isize 44..45 'x': u32 47..52 '{ 1 }': isize 49..50 '1': isize "### ); } #[test] fn coerce_placeholder_ref() { // placeholders should unify, even behind references assert_snapshot!( infer_with_mismatches(r#" struct S { t: T } impl S { fn get(&self) -> &TT { &self.t } } "#, true), @r###" 51..55 'self': &S 64..87 '{ ... }': &TT 74..81 '&self.t': &TT 75..79 'self': &S 75..81 'self.t': TT "### ); } #[test] fn coerce_unsize_array() { assert_snapshot!( infer_with_mismatches(r#" #[lang = "unsize"] pub trait Unsize {} #[lang = "coerce_unsized"] pub trait CoerceUnsized {} impl, U> CoerceUnsized<&U> for &T {} fn test() { let f: &[usize] = &[1, 2, 3]; } "#, true), @r###" 162..199 '{ ... 3]; }': () 172..173 'f': &[usize] 186..196 '&[1, 2, 3]': &[usize; _] 187..196 '[1, 2, 3]': [usize; _] 188..189 '1': usize 191..192 '2': usize 194..195 '3': usize "### ); } #[test] fn coerce_unsize_trait_object() { assert_snapshot!( infer_with_mismatches(r#" #[lang = "unsize"] pub trait Unsize {} #[lang = "coerce_unsized"] pub trait CoerceUnsized {} impl, U> CoerceUnsized<&U> for &T {} trait Foo {} trait Bar: Foo {} trait Baz: Bar {} struct S; impl Foo for S {} impl Bar for S {} impl Baz for S {} fn test() { let obj: &dyn Baz = &S; let obj: &dyn Bar<_, _, _> = obj; let obj: &dyn Foo<_, _> = obj; let obj2: &dyn Baz = &S; let _: &dyn Foo<_, _> = obj2; } "#, true), @r###" 388..573 '{ ...bj2; }': () 398..401 'obj': &dyn Baz 423..425 '&S': &S 424..425 'S': S 435..438 'obj': &dyn Bar 460..463 'obj': &dyn Baz 473..476 'obj': &dyn Foo 495..498 'obj': &dyn Bar 508..512 'obj2': &dyn Baz 534..536 '&S': &S 535..536 'S': S 546..547 '_': &dyn Foo 566..570 'obj2': &dyn Baz "### ); } #[test] fn coerce_unsize_super_trait_cycle() { assert_snapshot!( infer_with_mismatches(r#" #[lang = "unsize"] pub trait Unsize {} #[lang = "coerce_unsized"] pub trait CoerceUnsized {} impl, U> CoerceUnsized<&U> for &T {} trait A {} trait B: C + A {} trait C: B {} trait D: C struct S; impl A for S {} impl B for S {} impl C for S {} impl D for S {} fn test() { let obj: &dyn D = &S; let obj: &dyn A = obj; } "#, true), @r###" 292..348 '{ ...obj; }': () 302..305 'obj': &dyn D 316..318 '&S': &S 317..318 'S': S 328..331 'obj': &dyn A 342..345 'obj': &dyn D "### ); } #[ignore] #[test] fn coerce_unsize_generic() { // FIXME: Implement this // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions assert_snapshot!( infer_with_mismatches(r#" #[lang = "unsize"] pub trait Unsize {} #[lang = "coerce_unsized"] pub trait CoerceUnsized {} impl, U> CoerceUnsized<&U> for &T {} struct Foo { t: T }; struct Bar(Foo); fn test() { let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); } "#, true), @r###" "### ); }