Document things a bit more carefully, also account for coercion in check_expr_has_type_or_error
This commit is contained in:
parent
73d49f8c69
commit
515b93297f
@ -186,6 +186,7 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
|
|||||||
if self.coerce_never {
|
if self.coerce_never {
|
||||||
return success(simple(Adjust::NeverToAny)(b), b, vec![]);
|
return success(simple(Adjust::NeverToAny)(b), b, vec![]);
|
||||||
} else {
|
} else {
|
||||||
|
// Otherwise the only coercion we can do is unification.
|
||||||
return self.unify_and(a, b, identity);
|
return self.unify_and(a, b, identity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ pub(crate) fn check_expr_has_type_or_error(
|
|||||||
|
|
||||||
// While we don't allow *arbitrary* coercions here, we *do* allow
|
// While we don't allow *arbitrary* coercions here, we *do* allow
|
||||||
// coercions from ! to `expected`.
|
// 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) {
|
if let Some(_) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {
|
||||||
let reported = self.dcx().span_delayed_bug(
|
let reported = self.dcx().span_delayed_bug(
|
||||||
expr.span,
|
expr.span,
|
||||||
@ -260,6 +260,20 @@ pub(super) fn check_expr_with_expectation_and_args(
|
|||||||
ty
|
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 {
|
pub(super) fn expr_constitutes_read(&self, expr: &'tcx hir::Expr<'tcx>) -> bool {
|
||||||
// We only care about place exprs. Anything else returns an immediate
|
// We only care about place exprs. Anything else returns an immediate
|
||||||
// which would constitute a read. We don't care about distinguishing
|
// which would constitute a read. We don't care about distinguishing
|
||||||
|
@ -24,4 +24,3 @@ fn main() {
|
|||||||
let _ = *x;
|
let _ = *x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,14 +7,12 @@ LL | let c1 = || match x { };
|
|||||||
| ^ `x` used here but it isn't initialized
|
| ^ `x` used here but it isn't initialized
|
||||||
|
|
||||||
error[E0381]: used binding `x` 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: !;
|
LL | let x: !;
|
||||||
| - binding declared here but left uninitialized
|
| - binding declared here but left uninitialized
|
||||||
LL | let c2 = || match x { _ => () };
|
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
|
error[E0381]: used binding `variant` isn't initialized
|
||||||
--> $DIR/pattern-matching-should-fail.rs:27:13
|
--> $DIR/pattern-matching-should-fail.rs:27:13
|
||||||
|
Loading…
Reference in New Issue
Block a user