Document things a bit more carefully, also account for coercion in check_expr_has_type_or_error

This commit is contained in:
Michael Goulet 2024-09-05 07:53:49 -04:00
parent 73d49f8c69
commit 515b93297f
4 changed files with 18 additions and 6 deletions

View File

@ -186,6 +186,7 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
if self.coerce_never {
return success(simple(Adjust::NeverToAny)(b), b, vec![]);
} else {
// Otherwise the only coercion we can do is unification.
return self.unify_and(a, b, identity);
}
}

View File

@ -62,7 +62,7 @@ pub(crate) fn check_expr_has_type_or_error(
// While we don't allow *arbitrary* coercions here, we *do* allow
// coercions from ! to `expected`.
if ty.is_never() {
if ty.is_never() && self.expr_constitutes_read(expr) {
if let Some(_) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {
let reported = self.dcx().span_delayed_bug(
expr.span,
@ -260,6 +260,20 @@ pub(super) fn check_expr_with_expectation_and_args(
ty
}
/// Whether this expression constitutes a read of value of the type that
/// it evaluates to.
///
/// This is used to determine if we should consider the block to diverge
/// if the expression evaluates to `!`, and if we should insert a `NeverToAny`
/// coercion for values of type `!`.
///
/// This function generally returns `false` if the expression is a place
/// expression and the *parent* expression is the scrutinee of a match or
/// the pointee of an `&` addr-of expression, since both of those parent
/// expressions take a *place* and not a value.
///
/// This function is unfortunately a bit heuristical, though it is certainly
/// far sounder than the prior status quo: <https://github.com/rust-lang/rust/issues/117288>.
pub(super) fn expr_constitutes_read(&self, expr: &'tcx hir::Expr<'tcx>) -> bool {
// We only care about place exprs. Anything else returns an immediate
// which would constitute a read. We don't care about distinguishing

View File

@ -24,4 +24,3 @@ fn main() {
let _ = *x;
}
}

View File

@ -7,14 +7,12 @@ LL | let c1 = || match x { };
| ^ `x` used here but it isn't initialized
error[E0381]: used binding `x` isn't initialized
--> $DIR/pattern-matching-should-fail.rs:15:14
--> $DIR/pattern-matching-should-fail.rs:15:23
|
LL | let x: !;
| - binding declared here but left uninitialized
LL | let c2 = || match x { _ => () };
| ^^ - borrow occurs due to use in closure
| |
| `x` used here but it isn't initialized
| ^ `x` used here but it isn't initialized
error[E0381]: used binding `variant` isn't initialized
--> $DIR/pattern-matching-should-fail.rs:27:13