diff options
| author | Cameron Steffen <cam.steffen94@gmail.com> | 2021-07-30 11:30:12 -0500 |
|---|---|---|
| committer | Cameron Steffen <cam.steffen94@gmail.com> | 2021-08-30 20:18:42 -0500 |
| commit | 2f4e86b9ef457ff7b465e73e3aaabfcaa1d9d8e1 (patch) | |
| tree | 0a3ddf2ab5a4753d2b99b64742019c5fde1b5c7f | |
| parent | cb4439a3150308490a00773aa4f2a5ef23586a42 (diff) | |
| download | rust-2f4e86b9ef457ff7b465e73e3aaabfcaa1d9d8e1.tar.gz rust-2f4e86b9ef457ff7b465e73e3aaabfcaa1d9d8e1.zip | |
Enforce diverging let...else
4 files changed, 33 insertions, 5 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 299dcf5f17a..d54933841fd 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -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"), 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"), StartFunctionType => Error0308("`#[start]` function has wrong type"), IntrinsicType => Error0308("intrinsic has wrong type"), diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 676cb7fe41d..74edb17fe32 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -305,6 +305,9 @@ pub enum ObligationCauseCode<'tcx> { /// Intrinsic has wrong type IntrinsicType, + /// A let else block does not diverge + LetElse, + /// Method receiver MethodReceiver, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 40841a6e32d..db3432b0142 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1928,7 +1928,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | ObligationCauseCode::OpaqueType | ObligationCauseCode::MiscObligation | ObligationCauseCode::WellFormed(..) - | ObligationCauseCode::MatchImpl(..) => {} + | ObligationCauseCode::MatchImpl(..) + | ObligationCauseCode::ReturnType + | ObligationCauseCode::ReturnValue(_) + | ObligationCauseCode::BlockTailExpression(_) + | ObligationCauseCode::LetElse => {} ObligationCauseCode::SliceOrArrayElem => { err.note("slice and array elements must have `Sized` type"); } @@ -2338,9 +2342,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { predicate )); } - ObligationCauseCode::ReturnType - | ObligationCauseCode::ReturnValue(_) - | ObligationCauseCode::BlockTailExpression(_) => (), ObligationCauseCode::TrivialBound => { err.help("see issue #48214"); if tcx.sess.opts.unstable_features.is_nightly_build() { diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 51c646e500c..10f5b000aca 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -849,7 +849,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { coerce.coerce(self, &self.misc(sp), then_expr, then_ty); 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 opt_suggest_box_span = |
