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###" "### ); }