diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 6d4bd981b7b42..7c40043743657 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -131,7 +131,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_with_expectation(expr, ExpectHasType(expected)) } - fn check_expr_with_expectation_and_needs( + pub(super) fn check_expr_with_expectation_and_needs( &self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index a02073f302549..ada671e3e48da 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1444,7 +1444,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // referent for the reference that results is *equal to* the // type of the place it is referencing, and not some // supertype thereof. - let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m)); + let mut init_ty = self.check_expr_with_expectation_and_needs( + init, + ExpectHasType(local_ty), + Needs::maybe_mut_place(m), + ); + // The one exception to the above rule - we permit coercions when the expression has type ! + // This allows `let Foo { ref my_field } = diverging_expr;`. The actual assignment is guaranteed + // to be unreachable, so the soundness concerns with 'ref mut' do not apply. + if init_ty.is_never() { + init_ty = self.demand_coerce(init, init_ty, local_ty, None, AllowTwoPhase::No); + }; + if let Some(mut diag) = self.demand_eqtype_diag(init.span, local_ty, init_ty) { self.emit_type_mismatch_suggestions( &mut diag, diff --git a/tests/ui/pattern/issue-118113-ref-pattern-never-type.rs b/tests/ui/pattern/issue-118113-ref-pattern-never-type.rs new file mode 100644 index 0000000000000..2a6e5620dc367 --- /dev/null +++ b/tests/ui/pattern/issue-118113-ref-pattern-never-type.rs @@ -0,0 +1,10 @@ +// check-pass + +pub struct Foo { + bar: u8 +} + +#[allow(unused_variables)] +fn main() { + let Foo { ref bar } = loop {}; +} diff --git a/tests/ui/pattern/ref-pattern-assoc-type.rs b/tests/ui/pattern/ref-pattern-assoc-type.rs new file mode 100644 index 0000000000000..936aa23565133 --- /dev/null +++ b/tests/ui/pattern/ref-pattern-assoc-type.rs @@ -0,0 +1,22 @@ +// check-pass + +trait Call { + type Out; + fn call(self) -> Self::Out; +} + +impl T, T> Call for F { + type Out = T; + fn call(self) -> T { (self)() } +} + +pub struct Foo { + bar: u8 +} + +fn diverge() -> ! { todo!() } + +#[allow(unused_variables)] +fn main() { + let Foo { ref bar } = diverge.call(); +}