Skip to content

Commit 2f4e86b

Browse files
committed
Enforce diverging let...else
1 parent cb4439a commit 2f4e86b

File tree

4 files changed

+33
-5
lines changed
  • compiler

4 files changed

+33
-5
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
781781
);
782782
}
783783
}
784+
ObligationCauseCode::LetElse => {
785+
err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
786+
err.help("...or use `match` instead of `let...else`");
787+
}
784788
_ => (),
785789
}
786790
}
@@ -2592,6 +2596,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
25922596
}
25932597
IfExpression { .. } => Error0308("`if` and `else` have incompatible types"),
25942598
IfExpressionWithNoElse => Error0317("`if` may be missing an `else` clause"),
2599+
LetElse => Error0308("`else` clause of `let...else` does not diverge"),
25952600
MainFunctionType => Error0580("`main` function has wrong type"),
25962601
StartFunctionType => Error0308("`#[start]` function has wrong type"),
25972602
IntrinsicType => Error0308("intrinsic has wrong type"),

compiler/rustc_middle/src/traits/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,9 @@ pub enum ObligationCauseCode<'tcx> {
305305
/// Intrinsic has wrong type
306306
IntrinsicType,
307307

308+
/// A let else block does not diverge
309+
LetElse,
310+
308311
/// Method receiver
309312
MethodReceiver,
310313

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1928,7 +1928,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
19281928
| ObligationCauseCode::OpaqueType
19291929
| ObligationCauseCode::MiscObligation
19301930
| ObligationCauseCode::WellFormed(..)
1931-
| ObligationCauseCode::MatchImpl(..) => {}
1931+
| ObligationCauseCode::MatchImpl(..)
1932+
| ObligationCauseCode::ReturnType
1933+
| ObligationCauseCode::ReturnValue(_)
1934+
| ObligationCauseCode::BlockTailExpression(_)
1935+
| ObligationCauseCode::LetElse => {}
19321936
ObligationCauseCode::SliceOrArrayElem => {
19331937
err.note("slice and array elements must have `Sized` type");
19341938
}
@@ -2338,9 +2342,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
23382342
predicate
23392343
));
23402344
}
2341-
ObligationCauseCode::ReturnType
2342-
| ObligationCauseCode::ReturnValue(_)
2343-
| ObligationCauseCode::BlockTailExpression(_) => (),
23442345
ObligationCauseCode::TrivialBound => {
23452346
err.help("see issue #48214");
23462347
if tcx.sess.opts.unstable_features.is_nightly_build() {

compiler/rustc_typeck/src/check/expr.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -849,7 +849,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
849849
coerce.coerce(self, &self.misc(sp), then_expr, then_ty);
850850

851851
if let Some(else_expr) = opt_else_expr {
852-
let else_ty = self.check_expr_with_expectation(else_expr, expected);
852+
let else_ty = if sp.desugaring_kind() == Some(DesugaringKind::LetElse) {
853+
// todo introduce `check_expr_with_expectation(.., Expectation::LetElse)`
854+
// for errors that point to the offending expression rather than the entire block.
855+
// We could use `check_expr_eq_type(.., tcx.types.never)`, but then there is no
856+
// way to detect that the expected type originated from let-else and provide
857+
// a customized error.
858+
let else_ty = self.check_expr(else_expr);
859+
let cause = self.cause(else_expr.span, ObligationCauseCode::LetElse);
860+
861+
if let Some(mut err) =
862+
self.demand_eqtype_with_origin(&cause, self.tcx.types.never, else_ty)
863+
{
864+
err.emit();
865+
self.tcx.ty_error()
866+
} else {
867+
else_ty
868+
}
869+
} else {
870+
self.check_expr_with_expectation(else_expr, expected)
871+
};
853872
let else_diverges = self.diverges.get();
854873

855874
let opt_suggest_box_span =

0 commit comments

Comments
 (0)