Enforce diverging let...else
This commit is contained in:
parent
cb4439a315
commit
2f4e86b9ef
4 changed files with 33 additions and 5 deletions
|
@ -781,6 +781,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ObligationCauseCode::LetElse => {
|
||||||
|
err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
|
||||||
|
err.help("...or use `match` instead of `let...else`");
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2592,6 +2596,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
|
||||||
}
|
}
|
||||||
IfExpression { .. } => Error0308("`if` and `else` have incompatible types"),
|
IfExpression { .. } => Error0308("`if` and `else` have incompatible types"),
|
||||||
IfExpressionWithNoElse => Error0317("`if` may be missing an `else` clause"),
|
IfExpressionWithNoElse => Error0317("`if` may be missing an `else` clause"),
|
||||||
|
LetElse => Error0308("`else` clause of `let...else` does not diverge"),
|
||||||
MainFunctionType => Error0580("`main` function has wrong type"),
|
MainFunctionType => Error0580("`main` function has wrong type"),
|
||||||
StartFunctionType => Error0308("`#[start]` function has wrong type"),
|
StartFunctionType => Error0308("`#[start]` function has wrong type"),
|
||||||
IntrinsicType => Error0308("intrinsic has wrong type"),
|
IntrinsicType => Error0308("intrinsic has wrong type"),
|
||||||
|
|
|
@ -305,6 +305,9 @@ pub enum ObligationCauseCode<'tcx> {
|
||||||
/// Intrinsic has wrong type
|
/// Intrinsic has wrong type
|
||||||
IntrinsicType,
|
IntrinsicType,
|
||||||
|
|
||||||
|
/// A let else block does not diverge
|
||||||
|
LetElse,
|
||||||
|
|
||||||
/// Method receiver
|
/// Method receiver
|
||||||
MethodReceiver,
|
MethodReceiver,
|
||||||
|
|
||||||
|
|
|
@ -1928,7 +1928,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
| ObligationCauseCode::OpaqueType
|
| ObligationCauseCode::OpaqueType
|
||||||
| ObligationCauseCode::MiscObligation
|
| ObligationCauseCode::MiscObligation
|
||||||
| ObligationCauseCode::WellFormed(..)
|
| ObligationCauseCode::WellFormed(..)
|
||||||
| ObligationCauseCode::MatchImpl(..) => {}
|
| ObligationCauseCode::MatchImpl(..)
|
||||||
|
| ObligationCauseCode::ReturnType
|
||||||
|
| ObligationCauseCode::ReturnValue(_)
|
||||||
|
| ObligationCauseCode::BlockTailExpression(_)
|
||||||
|
| ObligationCauseCode::LetElse => {}
|
||||||
ObligationCauseCode::SliceOrArrayElem => {
|
ObligationCauseCode::SliceOrArrayElem => {
|
||||||
err.note("slice and array elements must have `Sized` type");
|
err.note("slice and array elements must have `Sized` type");
|
||||||
}
|
}
|
||||||
|
@ -2338,9 +2342,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
predicate
|
predicate
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
ObligationCauseCode::ReturnType
|
|
||||||
| ObligationCauseCode::ReturnValue(_)
|
|
||||||
| ObligationCauseCode::BlockTailExpression(_) => (),
|
|
||||||
ObligationCauseCode::TrivialBound => {
|
ObligationCauseCode::TrivialBound => {
|
||||||
err.help("see issue #48214");
|
err.help("see issue #48214");
|
||||||
if tcx.sess.opts.unstable_features.is_nightly_build() {
|
if tcx.sess.opts.unstable_features.is_nightly_build() {
|
||||||
|
|
|
@ -849,7 +849,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
coerce.coerce(self, &self.misc(sp), then_expr, then_ty);
|
coerce.coerce(self, &self.misc(sp), then_expr, then_ty);
|
||||||
|
|
||||||
if let Some(else_expr) = opt_else_expr {
|
if let Some(else_expr) = opt_else_expr {
|
||||||
let else_ty = self.check_expr_with_expectation(else_expr, expected);
|
let else_ty = if sp.desugaring_kind() == Some(DesugaringKind::LetElse) {
|
||||||
|
// todo introduce `check_expr_with_expectation(.., Expectation::LetElse)`
|
||||||
|
// for errors that point to the offending expression rather than the entire block.
|
||||||
|
// We could use `check_expr_eq_type(.., tcx.types.never)`, but then there is no
|
||||||
|
// way to detect that the expected type originated from let-else and provide
|
||||||
|
// a customized error.
|
||||||
|
let else_ty = self.check_expr(else_expr);
|
||||||
|
let cause = self.cause(else_expr.span, ObligationCauseCode::LetElse);
|
||||||
|
|
||||||
|
if let Some(mut err) =
|
||||||
|
self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty)
|
||||||
|
{
|
||||||
|
err.emit();
|
||||||
|
self.tcx.ty_error()
|
||||||
|
} else {
|
||||||
|
else_ty
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.check_expr_with_expectation(else_expr, expected)
|
||||||
|
};
|
||||||
let else_diverges = self.diverges.get();
|
let else_diverges = self.diverges.get();
|
||||||
|
|
||||||
let opt_suggest_box_span =
|
let opt_suggest_box_span =
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue