| 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<T> { a: T } |
| |
| fn f<T>(_: &[T]) -> T { loop {} } |
| fn g<T>(_: S<&[T]>) -> T { loop {} } |
| |
| fn generate<T>() -> *mut [T; 2] { loop {} } |
| fn test1<U>() -> *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('?2, 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<T: ?Sized>(*const T); |
| struct B<T: ?Sized>(*const T); |
| struct C<T: ?Sized> { inner: *const T } |
| |
| impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} |
| impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<C<U>> for C<T> {} |
| |
| fn foo1<T>(x: A<[T]>) -> A<[T]> { x } |
| fn foo2<T>(x: B<[T]>) -> B<[T]> { x } |
| fn foo3<T>(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 if_coerce() { |
| check_no_mismatches( |
| r#" |
| //- minicore: coerce_unsized |
| fn foo<T>(x: &[T]) -> &[T] { x } |
| fn test() { |
| let x = if true { |
| foo(&[1]) |
| // ^^^^ adjustments: Deref(None), Borrow(Ref('?8, Not)), Pointer(Unsize) |
| } else { |
| &[1] |
| }; |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn if_else_coerce() { |
| check_no_mismatches( |
| r#" |
| //- minicore: coerce_unsized |
| fn foo<T>(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<T>(x: &[T]) -> &[T] { x } |
| fn test(i: i32) { |
| let x = match i { |
| 2 => foo(&[2]), |
| // ^^^^ adjustments: Deref(None), Borrow(Ref('?8, Not)), Pointer(Unsize) |
| 1 => &[1], |
| _ => &[3], |
| }; |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn match_second_coerce() { |
| check_no_mismatches( |
| r#" |
| //- minicore: coerce_unsized |
| fn foo<T>(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() { |
| cov_mark::check!(coerce_merge_fail_fallback); |
| |
| check( |
| r" |
| fn test() { |
| let t = &mut 1; |
| let x = match 1 { |
| 1 => t as *mut i32, |
| //^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer) |
| 2 => t as &i32, |
| //^^^^^^^^^ expected *mut i32, got &'? i32 |
| _ => t as *const i32, |
| }; |
| x; |
| //^ type: *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<T>(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('{error}, Not)) |
| } |
| "#, |
| ); |
| } |
| |
| #[test] |
| fn coerce_autoderef_implication_1() { |
| check_no_mismatches( |
| r" |
| //- minicore: deref |
| struct Foo<T>; |
| impl core::ops::Deref for Foo<u32> { type Target = (); } |
| |
| fn takes_ref_foo<T>(x: &Foo<T>) {} |
| fn test() { |
| let foo = Foo; |
| //^^^ type: Foo<{unknown}> |
| takes_ref_foo(&foo); |
| |
| let foo = Foo; |
| //^^^ type: Foo<u32> |
| let _: &() = &foo; |
| }", |
| ); |
| } |
| |
| #[test] |
| fn coerce_autoderef_implication_2() { |
| check( |
| r" |
| //- minicore: deref |
| struct Foo<T>; |
| impl core::ops::Deref for Foo<u32> { type Target = (); } |
| |
| fn takes_ref_foo<T>(x: &Foo<T>) {} |
| fn test() { |
| let foo = Foo; |
| //^^^ type: Foo<{unknown}> |
| let _: &u32 = &Foo; |
| //^^^^ 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() { |
| cov_mark::check!(coerce_fn_reification); |
| |
| 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: T } |
| impl<TT> S<TT> { |
| 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 |
| }"#, |
| ); |
| } |
| |
| #[test] |
| fn coerce_unsize_trait_object_simple() { |
| check_types( |
| r#" |
| //- minicore: coerce_unsized |
| trait Foo<T, U> {} |
| trait Bar<U, T, X>: Foo<T, U> {} |
| trait Baz<T, X>: Bar<usize, T, X> {} |
| |
| struct S<T, X>; |
| impl<T, X> Foo<T, usize> for S<T, X> {} |
| impl<T, X> Bar<usize, T, X> for S<T, X> {} |
| impl<T, X> Baz<T, X> for S<T, X> {} |
| |
| fn test() { |
| let obj: &dyn Baz<i8, i16> = &S; |
| //^ S<i8, i16> |
| let obj: &dyn Bar<_, i8, i16> = &S; |
| //^ S<i8, i16> |
| let obj: &dyn Foo<i8, _> = &S; |
| //^ S<i8, {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: T }; |
| struct Bar<T>(Foo<T>); |
| |
| fn test() { |
| let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] }; |
| //^^^^^^^^^^^^^^^^^^^^^ expected &'? Foo<[usize]>, got &'? Foo<[i32; 3]> |
| let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); |
| //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &'? Bar<[usize]>, got &'? Bar<[i32; 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, 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<T> { Ok(T), Err } |
| fn parse<T>() -> 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<T> { Ok(T), Err } |
| fn parse<T>() -> 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<T> InFile<T> { |
| fn with_value<U>(self, value: U) -> InFile<U> { InFile } |
| } |
| 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<T> { 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<T: ?Sized>(*const T); |
| impl<T: ?Sized> B<T> { |
| fn new(t: T) -> Self { B(&t) } |
| } |
| |
| impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<B<U>> for B<T> {} |
| |
| 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: 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: 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('{error}, Not)) |
| // ^^^^^^ adjustments: Borrow(Ref('{error}, 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('{error}, Mut)) |
| // ^^^^^^ 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('?8, Mut)) |
| } |
| ", |
| ); |
| check_no_mismatches( |
| r" |
| //- minicore: index |
| struct Struct; |
| impl core::ops::Index<usize> for Struct { |
| type Output = (); |
| |
| fn index(&self, index: usize) -> &Self::Output { &() } |
| } |
| struct StructMut; |
| |
| impl core::ops::Index<usize> 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('?2, Not)) |
| StructMut[0]; |
| // ^^^^^^^^^ adjustments: Borrow(Ref('?5, Not)) |
| &mut StructMut[0]; |
| // ^^^^^^^^^ adjustments: Borrow(Ref('?8, Mut)) |
| }", |
| ); |
| } |
| |
| #[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()]; |
| } |
| "#, |
| ); |
| } |