Skip to content

Commit

Permalink
Allow coercions from never-type when ref binding is involved
Browse files Browse the repository at this point in the history
When we type-check a binding that uses ref patterns, we do not
perform coercions between the expression type and the pattern type.

However, this has the unfortunate result of disallow code like:
`let Foo { ref my_field } = diverging_expr();`. This code is accepted
without the `ref` keyword.

We now explicitly allow coercions when the expression type is !
In all other cases, we still avoid performing coersions.
This avoids causing broader changes in type-checking (with potential
soundness implications for 'ref mut'),
  • Loading branch information
Aaron1011 committed Nov 24, 2023
1 parent 42ae1a7 commit 36404ce
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 2 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/expr.rs
Expand Up @@ -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>,
Expand Down
13 changes: 12 additions & 1 deletion compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Expand Up @@ -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,
Expand Down
10 changes: 10 additions & 0 deletions 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 {};
}

0 comments on commit 36404ce

Please sign in to comment.