Rollup merge of #155276 - jdonszelmann:must-match-exhaustively-let-else, r=JonathanBrouwer

`#[rustc_must_match_exhaustively]` detect let else

Extension of https://github.com/rust-lang/rust/pull/155047, I forgor to lint on let-else :3
This commit is contained in:
Jonathan Brouwer
2026-04-14 16:29:36 +02:00
committed by GitHub
6 changed files with 68 additions and 12 deletions
+10 -3
View File
@@ -659,9 +659,16 @@ pub(crate) fn drain_stalled_coroutine_obligations(&self) {
// being stalled on a coroutine.
self.select_obligations_where_possible(|_| {});
let ty::TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
else {
bug!();
let defining_opaque_types_and_generators = match self.typing_mode() {
ty::TypingMode::Analysis { defining_opaque_types_and_generators } => {
defining_opaque_types_and_generators
}
ty::TypingMode::Coherence
| ty::TypingMode::Borrowck { .. }
| ty::TypingMode::PostBorrowckAnalysis { .. }
| ty::TypingMode::PostAnalysis => {
bug!()
}
};
if defining_opaque_types_and_generators
+12 -4
View File
@@ -1,8 +1,9 @@
use rustc_hir::def::DefKind;
use rustc_infer::traits::ObligationCause;
use rustc_middle::bug;
use rustc_middle::ty::{
self, DefiningScopeKind, DefinitionSiteHiddenType, OpaqueTypeKey, ProvisionalHiddenType,
TypeVisitableExt, TypingMode,
TypeVisitableExt,
};
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
use rustc_trait_selection::opaque_types::{
@@ -97,9 +98,16 @@ fn compute_definition_site_hidden_types(
debug!(?opaque_types);
let tcx = self.tcx;
let TypingMode::Analysis { defining_opaque_types_and_generators } = self.typing_mode()
else {
unreachable!();
let defining_opaque_types_and_generators = match self.typing_mode() {
ty::TypingMode::Analysis { defining_opaque_types_and_generators } => {
defining_opaque_types_and_generators
}
ty::TypingMode::Coherence
| ty::TypingMode::Borrowck { .. }
| ty::TypingMode::PostBorrowckAnalysis { .. }
| ty::TypingMode::PostAnalysis => {
bug!()
}
};
for def_id in defining_opaque_types_and_generators {
+24 -2
View File
@@ -783,7 +783,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
}
}
}
hir::ExprKind::If(expr, ..) if let ExprKind::Let(expr) = expr.kind => {
hir::ExprKind::Let(expr, ..) => {
if let Some(attr_span) = is_rustc_must_match_exhaustively(cx, expr.init.hir_id) {
cx.emit_span_lint(
RUSTC_MUST_MATCH_EXHAUSTIVELY,
@@ -791,7 +791,29 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
RustcMustMatchExhaustivelyNotExhaustive {
attr_span,
pat_span: expr.span,
message: "using if let only matches on one variant (try using `match`)",
message: "using `if let` only matches on one variant (try using `match`)",
},
);
}
}
_ => {}
}
}
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx rustc_hir::Stmt<'tcx>) {
match stmt.kind {
rustc_hir::StmtKind::Let(let_stmt) => {
if let_stmt.els.is_some()
&& let Some(attr_span) =
is_rustc_must_match_exhaustively(cx, let_stmt.pat.hir_id)
{
cx.emit_span_lint(
RUSTC_MUST_MATCH_EXHAUSTIVELY,
let_stmt.span,
RustcMustMatchExhaustivelyNotExhaustive {
attr_span,
pat_span: let_stmt.pat.span,
message: "using `let else` only matches on one variant (try using `match`)",
},
);
}
@@ -442,7 +442,7 @@ pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
// normalizing the self type as well, since type variables are not uniquified.
let goal = self.resolve_vars_if_possible(goal);
if let TypingMode::Coherence = self.typing_mode()
if self.typing_mode().is_coherence()
&& let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal)
{
candidates.push(candidate);
@@ -43,6 +43,9 @@ fn foo(f: Foo) {
if let Foo::A { .. } = f {}
//~^ ERROR match is not exhaustive
let Foo::A { .. } = f else { loop {} };
//~^ ERROR match is not exhaustive
}
fn main() {}
@@ -61,11 +61,27 @@ LL | if let Foo::A { .. } = f {}
| ^^^^^^^^^^^^^^^^^^^^^
|
= help: explicitly list all variants of the enum in a `match`
note: using if let only matches on one variant (try using `match`)
note: using `if let` only matches on one variant (try using `match`)
--> $DIR/must_match_exhaustively.rs:44:8
|
LL | if let Foo::A { .. } = f {}
| ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors
error: match is not exhaustive
--> $DIR/must_match_exhaustively.rs:47:5
|
LL | #[rustc_must_match_exhaustively]
| -------------------------------- required because of this attribute
...
LL | let Foo::A { .. } = f else { loop {} };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: explicitly list all variants of the enum in a `match`
note: using `let else` only matches on one variant (try using `match`)
--> $DIR/must_match_exhaustively.rs:47:9
|
LL | let Foo::A { .. } = f else { loop {} };
| ^^^^^^^^^^^^^
error: aborting due to 5 previous errors