use super::{check, check_no_mismatches, check_types}; #[test] fn block_expr_type_mismatch() { check( r" fn test() { let a: i32 = { 1i64 }; // ^^^^ expected i32, got i64 } ", ); } #[test] fn coerce_places() { check_no_mismatches( r#" //- minicore: coerce_unsized struct S { a: T } fn f(_: &[T]) -> T { loop {} } fn g(_: S<&[T]>) -> T { loop {} } fn generate() -> *mut [T; 2] { loop {} } fn test1() -> *mut [U] { generate() } 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); } "#, ); } #[test] fn let_stmt_coerce() { check( r" //- minicore: coerce_unsized fn test() { let x: &[isize] = &[1]; // ^^^^ adjustments: Deref(None), Borrow(Ref(Not)), Pointer(Unsize) let x: *const [isize] = &[1]; // ^^^^ adjustments: Deref(None), Borrow(RawPtr(Not)), Pointer(Unsize) } ", ); } #[test] fn custom_coerce_unsized() { check( r#" //- minicore: coerce_unsized use core::{marker::Unsize, ops::CoerceUnsized}; 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); // ^ expected A<[{unknown}]>, got A<[u8; 2]> let e = foo2(b); // ^ type: B<[u8]> let f = foo3(c); // ^ type: C<[u8]> } "#, ); } #[test] fn unsized_from_keeps_type_info() { check_types( r#" //- minicore: coerce_unsized, from use core::{marker::Unsize, ops::CoerceUnsized}; struct MyBox { ptr: *const T, } impl, U: ?Sized> CoerceUnsized> for MyBox {} struct MyRc { ptr: *const T, } impl core::convert::From> for MyRc { fn from(_: MyBox) -> MyRc { loop {} } } fn make_box() -> MyBox<[i32; 2]> { loop {} } fn take(value: MyRc) -> MyRc { value } fn test() { let boxed: MyBox<[i32]> = make_box(); let rc = MyRc::from(boxed); //^^ MyRc<[i32]> let _: MyRc<[i32]> = take(rc); } "#, ); } #[test] fn if_coerce() { check_no_mismatches( r#" //- minicore: coerce_unsized fn foo(x: &[T]) -> &[T] { x } fn test() { let x = if true { foo(&[1]) // ^^^^ adjustments: Deref(None), Borrow(Ref(Not)), Pointer(Unsize) } else { &[1] }; } "#, ); } #[test] fn if_else_coerce() { check_no_mismatches( r#" //- minicore: coerce_unsized fn foo(x: &[T]) -> &[T] { x } fn test() { let x = if true { &[1] } else { foo(&[1]) }; } "#, ) } #[test] fn if_else_adjust_for_branches_discard_type_var() { check_no_mismatches( r#" fn test() { let f = || { if true { &"" } else { "" } }; } "#, ); } #[test] fn match_first_coerce() { check_no_mismatches( r#" //- minicore: coerce_unsized fn foo(x: &[T]) -> &[T] { x } fn test(i: i32) { let x = match i { 2 => foo(&[2]), // ^^^^ adjustments: Deref(None), Borrow(Ref(Not)), Pointer(Unsize) 1 => &[1], _ => &[3], }; } "#, ); } #[test] fn match_second_coerce() { check_no_mismatches( r#" //- minicore: coerce_unsized fn foo(x: &[T]) -> &[T] { loop {} } // ^^^^^^^ adjustments: NeverToAny fn test(i: i32) { let x = match i { 1 => &[1], 2 => foo(&[2]), _ => &[3], }; } "#, ); } #[test] fn coerce_merge_one_by_one1() { check( r" fn test() { let t = &mut 1; let x = match 1 { 1 => t as *mut i32, //^ adjustments: Deref(None), Borrow(RawPtr(Mut)) _ => t as *const i32, }; x; // ^ type: *const i32 let x = match 1 { 1 => t as *mut i32, 2 => t as &i32, //^^^^^^^^^ expected *mut i32, got &'? i32 _ => t as *const i32, }; } ", ); } #[test] fn match_adjust_for_branches_discard_type_var() { check_no_mismatches( r#" fn test() { let f = || { match 0i32 { 0i32 => &"", _ => "", } }; } "#, ); } #[test] fn return_coerce_unknown() { check_types( r" fn foo() -> u32 { return unknown; //^^^^^^^ u32 } ", ); } #[test] fn coerce_autoderef() { check_no_mismatches( r" struct Foo; fn takes_ref_foo(x: &Foo) {} fn test() { takes_ref_foo(&Foo); takes_ref_foo(&&Foo); takes_ref_foo(&&&Foo); }", ); } #[test] fn coerce_autoderef_generic() { check_no_mismatches( r#" struct Foo; fn takes_ref(x: &T) -> T { *x } fn test() { takes_ref(&Foo); takes_ref(&&Foo); takes_ref(&&&Foo); } "#, ); } #[test] fn coerce_autoderef_block() { check_no_mismatches( r#" //- minicore: deref struct String {} impl core::ops::Deref for String { type Target = str; } fn takes_ref_str(x: &str) {} fn returns_string() -> String { loop {} } fn test() { takes_ref_str(&{ returns_string() }); // ^^^^^^^^^^^^^^^^^^^^^ adjustments: Deref(None), Deref(Some(OverloadedDeref(Some(Not)))), Borrow(Ref(Not)) } "#, ); } #[test] fn coerce_autoderef_implication_1() { check_no_mismatches( r" //- minicore: deref, phantom_data use core::marker::PhantomData; struct Foo(PhantomData); impl core::ops::Deref for Foo { type Target = (); } fn takes_ref_foo(x: &Foo) {} fn test() { let foo = Foo(PhantomData); //^^^ type: Foo<{unknown}> takes_ref_foo(&foo); let foo = Foo(PhantomData); //^^^ type: Foo let _: &() = &foo; }", ); } #[test] fn coerce_autoderef_implication_2() { check( r" //- minicore: deref, phantom_data use core::marker::PhantomData; struct Foo(PhantomData); impl core::ops::Deref for Foo { type Target = (); } fn takes_ref_foo(x: &Foo) {} fn test() { let foo = Foo(PhantomData); //^^^ type: Foo<{unknown}> let _: &u32 = &Foo(PhantomData); //^^^^^^^^^^^^^^^^^ expected &'? u32, got &'? Foo<{unknown}> }", ); } #[test] fn closure_return_coerce() { check_no_mismatches( r" fn foo() { let x = || { if true { return &1u32; } &&1u32 }; }", ); } #[test] fn coroutine_yield_return_coerce() { check_no_mismatches( r#" fn test() { let g = || { yield &1u32; yield &&1u32; if true { return &1u32; } &&1u32 }; } "#, ); } #[test] fn assign_coerce() { check_no_mismatches( r" //- minicore: deref struct String; impl core::ops::Deref for String { type Target = str; } fn g(_text: &str) {} fn f(text: &str) { let mut text = text; let tmp = String; text = &tmp; g(text); } ", ); } #[test] fn destructuring_assign_coerce() { check_no_mismatches( r" //- minicore: deref struct String; impl core::ops::Deref for String { type Target = str; } fn g(_text: &str) {} fn f(text: &str) { let mut text = text; let tmp = String; [text, _] = [&tmp, &tmp]; g(text); } ", ); } #[test] fn coerce_fn_item_to_fn_ptr() { check_no_mismatches( r" fn foo(x: u32) -> isize { 1 } fn test() { let f: fn(u32) -> isize = foo; // ^^^ adjustments: Pointer(ReifyFnPointer) let f: unsafe fn(u32) -> isize = foo; // ^^^ adjustments: Pointer(ReifyFnPointer), Pointer(UnsafeFnPointer) }", ); } #[test] fn coerce_fn_item_to_fn_ptr_in_array() { check_no_mismatches( r" fn foo(x: u32) -> isize { 1 } fn bar(x: u32) -> isize { 1 } fn test() { let f = [foo, bar]; // ^^^ adjustments: Pointer(ReifyFnPointer) }", ); } #[test] fn coerce_fn_items_in_match_arms() { check_no_mismatches( r" fn foo1(x: u32) -> isize { 1 } fn foo2(x: u32) -> isize { 2 } fn foo3(x: u32) -> isize { 3 } fn test() { let x = match 1 { 1 => foo1, // ^^^^ adjustments: Pointer(ReifyFnPointer) 2 => foo2, // ^^^^ adjustments: Pointer(ReifyFnPointer) _ => foo3, // ^^^^ adjustments: Pointer(ReifyFnPointer) }; x; }", ); check_types( r" fn foo1(x: u32) -> isize { 1 } fn foo2(x: u32) -> isize { 2 } fn foo3(x: u32) -> isize { 3 } fn test() { let x = match 1 { 1 => foo1, 2 => foo2, _ => foo3, }; x; //^ fn(u32) -> isize }", ); } #[test] fn coerce_closure_to_fn_ptr() { check_no_mismatches( r" fn test() { let f: fn(u32) -> u32 = |x| x; // ^^^^^ adjustments: Pointer(ClosureFnPointer(Safe)) let f: unsafe fn(u32) -> u32 = |x| x; // ^^^^^ adjustments: Pointer(ClosureFnPointer(Unsafe)) }", ); } #[test] fn coerce_placeholder_ref() { // placeholders should unify, even behind references check_no_mismatches( r" struct S { t: T } impl S { fn get(&self) -> &TT { &self.t } }", ); } #[test] fn coerce_unsize_array() { check_types( r#" //- minicore: coerce_unsized fn test() { let f: &[usize] = &[1, 2, 3]; //^ usize }"#, ); } // FIXME(next-solver): We could learn more from the `&S` -> `&dyn Foo` coercion if we followed the rustc model // where unsized is successful if all unsizing trait goals are certain (and non-unsizing goals are delayed). #[test] fn coerce_unsize_trait_object_simple() { check_types( r#" //- minicore: coerce_unsized 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; //^ S let obj: &dyn Bar<_, i8, i16> = &S; //^ S //let obj: &dyn Foo = &S; // S<{unknown}, {unknown}> }"#, ); } #[test] fn coerce_unsize_super_trait_cycle() { check_no_mismatches( r#" //- minicore: coerce_unsized 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 = &S; } "#, ); } #[test] fn coerce_unsize_generic() { check( r#" //- minicore: coerce_unsized struct Foo { t: T }; struct Bar(Foo); fn test() { let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; //^^^^^^^^^^^^^^^^^^^^^ type: &'? Foo<[usize; 3]> let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); //^^^^^^^^^^^^^^^^^^^^^^^^^^ type: &'? Bar<[usize; 3]> } "#, ); } #[test] fn coerce_unsize_apit() { check( r#" //- minicore: coerce_unsized trait Foo {} fn test(f: impl Foo, g: &(impl Foo + ?Sized)) { let _: &dyn Foo = &f; let _: &dyn Foo = g; //^ expected &'? (dyn Foo + 'static), got &'? (impl Foo + ?Sized) } "#, ); } #[test] fn two_closures_lub() { check_types( r#" fn foo(c: i32) { let add = |a: i32, b: i32| a + b; //^^^^^^^^^^^^^^^^^^^^^^ impl Fn(i32, i32) -> i32 let sub = |a, b| a - b; //^^^^^^^^^^^^ impl Fn(i32, i32) -> i32 if c > 42 { add } else { sub }; //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fn(i32, i32) -> i32 } "#, ) } #[test] fn match_diverging_branch_1() { check_types( r#" enum Result { Ok(T), Err } fn parse() -> T { loop {} } fn test() -> i32 { let a = match parse() { Ok(val) => val, Err => return 0, }; a //^ i32 } "#, ) } #[test] fn match_diverging_branch_2() { // same as 1 except for order of branches check_types( r#" enum Result { Ok(T), Err } fn parse() -> T { loop {} } fn test() -> i32 { let a = match parse() { Err => return 0, Ok(val) => val, }; a //^ i32 } "#, ) } #[test] fn panic_macro() { check_no_mismatches( r#" mod panic { #[macro_export] pub macro panic_2015 { () => ( $crate::panicking::panic() ), } } mod panicking { pub fn panic() -> ! { loop {} } } #[rustc_builtin_macro = "core_panic"] macro_rules! panic { // Expands to either `$crate::panic::panic_2015` or `$crate::panic::panic_2021` // depending on the edition of the caller. ($($arg:tt)*) => { /* compiler built-in */ }; } fn main() { panic!() } "#, ); } #[test] fn coerce_unsize_expected_type_1() { check_no_mismatches( r#" //- minicore: coerce_unsized fn main() { let foo: &[u32] = &[1, 2]; let foo: &[u32] = match true { true => &[1, 2], false => &[1, 2, 3], }; let foo: &[u32] = if true { &[1, 2] } else { &[1, 2, 3] }; } "#, ); } #[test] fn coerce_unsize_expected_type_2() { check_no_mismatches( r#" //- minicore: coerce_unsized struct InFile(T); impl InFile { fn with_value(self, value: U) -> InFile { InFile(loop {}) } } struct RecordField; trait AstNode {} impl AstNode for RecordField {} fn takes_dyn(it: InFile<&dyn AstNode>) {} fn test() { let x: InFile<()> = InFile(()); let n = &RecordField; takes_dyn(x.with_value(n)); } "#, ); } #[test] fn coerce_unsize_expected_type_3() { check_no_mismatches( r#" //- minicore: coerce_unsized enum Option { Some(T), None } struct RecordField; trait AstNode {} impl AstNode for RecordField {} fn takes_dyn(it: Option<&dyn AstNode>) {} fn test() { let x: InFile<()> = InFile; let n = &RecordField; takes_dyn(Option::Some(n)); } "#, ); } #[test] fn coerce_unsize_expected_type_4() { check_no_mismatches( r#" //- minicore: coerce_unsized use core::{marker::Unsize, ops::CoerceUnsized}; struct B(*const T); impl B { fn new(t: T) -> Self { B(&t) } } impl, U: ?Sized> CoerceUnsized> for B {} fn test() { let _: B<[isize]> = B::new({ [1, 2, 3] }); } "#, ); } #[test] fn coerce_array_elems_lub() { check_no_mismatches( r#" fn f() {} fn g() {} fn test() { [f, g]; } "#, ); } #[test] fn coerce_type_var() { check_types( r#" //- minicore: from, coerce_unsized fn test() { let x = (); let _: &() = &x.into(); } //^^^^^^^^ () "#, ) } #[test] fn coerce_overloaded_binary_op_rhs() { check_types( r#" //- minicore: deref, add struct String {} impl core::ops::Deref for String { type Target = str; } impl core::ops::Add<&str> for String { type Output = String; } fn test() { let s1 = String {}; let s2 = String {}; s1 + &s2; //^^^^^^^^ String } "#, ); } #[test] fn assign_coerce_struct_fields() { check_no_mismatches( r#" //- minicore: coerce_unsized struct S; trait Tr {} impl Tr for S {} struct V { t: T } fn main() { let a: V<&dyn Tr>; a = V { t: &S }; let mut a: V<&dyn Tr> = V { t: &S }; a = V { t: &S }; } "#, ); } #[test] fn destructuring_assign_coerce_struct_fields() { check( r#" //- minicore: coerce_unsized struct S; trait Tr {} impl Tr for S {} struct V { t: T } fn main() { let a: V<&dyn Tr>; (a,) = V { t: &S }; //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,) let mut a: V<&dyn Tr> = V { t: &S }; (a,) = V { t: &S }; //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,) } "#, ); } #[test] fn adjust_comparison_arguments() { check_no_mismatches( r" //- minicore: eq struct Struct; impl core::cmp::PartialEq for Struct { fn eq(&self, other: &Self) -> bool { true } } fn test() { Struct == Struct; // ^^^^^^ adjustments: Borrow(Ref(Not)) // ^^^^^^ adjustments: Borrow(Ref(Not)) }", ); } #[test] fn adjust_assign_lhs() { check_no_mismatches( r" //- minicore: add struct Struct; impl core::ops::AddAssign for Struct { fn add_assign(&mut self, other: Self) {} } fn test() { Struct += Struct; // ^^^^^^ adjustments: Borrow(Ref(Mut { allow_two_phase_borrow: Yes })) // ^^^^^^ adjustments: }", ); } #[test] fn adjust_index() { check_no_mismatches( r" //- minicore: index, slice, coerce_unsized fn test() { let x = [1, 2, 3]; x[2] = 6; // ^ adjustments: Borrow(Ref(Mut { allow_two_phase_borrow: No })) } ", ); check_no_mismatches( r" //- minicore: index struct Struct; impl core::ops::Index for Struct { type Output = (); fn index(&self, index: usize) -> &Self::Output { &() } } struct StructMut; impl core::ops::Index for StructMut { type Output = (); fn index(&self, index: usize) -> &Self::Output { &() } } impl core::ops::IndexMut for StructMut { fn index_mut(&mut self, index: usize) -> &mut Self::Output { &mut () } } fn test() { Struct[0]; // ^^^^^^ adjustments: Borrow(Ref(Not)) StructMut[0]; // ^^^^^^^^^ adjustments: Borrow(Ref(Not)) &mut StructMut[0]; // ^^^^^^^^^ adjustments: Borrow(Ref(Mut { allow_two_phase_borrow: No })) }", ); } #[test] fn regression_14443_dyn_coercion_block_impls() { check_no_mismatches( r#" //- minicore: coerce_unsized trait T {} fn dyn_t(d: &dyn T) {} fn main() { struct A; impl T for A {} let a = A; let b = { struct B; impl T for B {} B }; dyn_t(&a); dyn_t(&b); } "#, ) } #[test] fn regression_18626() { check_no_mismatches( r#" fn f() { trait T { fn f() {} } impl T for i32 {} impl T for u32 {} &[i32::f, u32::f] as &[fn()]; } "#, ); }