Skip to content

Commit 5cf33a6

Browse files
committed
let_chains: match check 'let' exprs
1 parent 6f02799 commit 5cf33a6

File tree

1 file changed

+47
-18
lines changed

1 file changed

+47
-18
lines changed

src/librustc_mir_build/hair/pattern/check_match.rs

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,10 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> {
5151

5252
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
5353
intravisit::walk_expr(self, ex);
54-
55-
// FIXME(let_chains): Deal with `::Let`.
56-
if let hir::ExprKind::Match(ref scrut, ref arms, source) = ex.kind {
57-
self.check_match(scrut, arms, source);
54+
match &ex.kind {
55+
hir::ExprKind::Match(scrut, arms, source) => self.check_match(scrut, arms, *source),
56+
hir::ExprKind::Let(pat, scrut) => self.check_let(pat, scrut),
57+
_ => {}
5858
}
5959
}
6060

@@ -145,6 +145,24 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
145145
MatchCheckCtxt::create_and_enter(self.tcx, self.param_env, module, |cx| f(cx));
146146
}
147147

148+
fn check_let(&mut self, pat: &'tcx hir::Pat<'tcx>, scrut: &hir::Expr<'_>) {
149+
self.check_patterns(false, pat);
150+
// FIXME(let_chains, Centril): Exhaustiveness of `let p = e` is unnecessary for soundness.
151+
// Consider dropping the checks here, at least the non-linting part for perf reasons.
152+
self.check_in_cx(scrut.hir_id, |ref mut cx| {
153+
let mut have_errors = false;
154+
let pattern = self.lower_pattern(cx, pat, &mut have_errors).0;
155+
if have_errors {
156+
return;
157+
}
158+
let wild = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(pattern.ty));
159+
wild.span = pattern.span;
160+
let arms = &[(pattern, pat.hir_id, false), (wild, pat.hir_id, false)];
161+
let desugar = hir::MatchSource::IfLetDesugar { contains_else_clause: true };
162+
self.check_union_irrefutable(cx, scrut, arms, desugar)
163+
});
164+
}
165+
148166
fn check_match(
149167
&mut self,
150168
scrut: &hir::Expr<'_>,
@@ -158,36 +176,47 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
158176

159177
self.check_in_cx(scrut.hir_id, |ref mut cx| {
160178
let mut have_errors = false;
161-
162179
let inlined_arms: Vec<_> = arms
163180
.iter()
164181
.map(|hir::Arm { pat, guard, .. }| {
165182
(self.lower_pattern(cx, pat, &mut have_errors).0, pat.hir_id, guard.is_some())
166183
})
167184
.collect();
168-
169-
// Bail out early if inlining failed.
170185
if have_errors {
186+
// Inlining failed, bail out early.
171187
return;
172188
}
173189

174-
// Fourth, check for unreachable arms.
175-
let matrix = check_arms(cx, &inlined_arms, source);
176-
177-
// Fifth, check if the match is exhaustive.
178-
let scrut_ty = self.tables.node_type(scrut.hir_id);
179-
// Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
180-
// since an empty matrix can occur when there are arms, if those arms all have guards.
181-
let is_empty_match = inlined_arms.is_empty();
182-
check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, is_empty_match);
190+
self.check_union_irrefutable(cx, scrut, &inlined_arms, source);
183191
})
184192
}
185193

194+
fn check_union_irrefutable<'p>(
195+
&self,
196+
cx: &mut MatchCheckCtxt<'p, 'tcx>,
197+
scrut: &hir::Expr<'_>,
198+
arms: &[(&'p super::Pat<'tcx>, HirId, bool)],
199+
source: hir::MatchSource,
200+
) {
201+
// Check for unreachable arms.
202+
let matrix = check_arms(cx, &arms, source);
203+
204+
// Check if the match is exhaustive.
205+
let scrut_ty = self.tables.node_type(scrut.hir_id);
206+
// Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
207+
// since an empty matrix can occur when there are arms, if those arms all have guards.
208+
check_exhaustive(cx, scrut_ty, scrut.span, &matrix, scrut.hir_id, arms.is_empty());
209+
}
210+
186211
fn check_irrefutable(&self, pat: &'tcx Pat<'tcx>, origin: &str, sp: Option<Span>) {
187212
self.check_in_cx(pat.hir_id, |ref mut cx| {
188-
let (pattern, pattern_ty) = self.lower_pattern(cx, pat, &mut false);
189-
let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect();
213+
let mut has_errors = false;
214+
let (pattern, pattern_ty) = self.lower_pattern(cx, pat, &mut has_errors);
215+
if has_errors {
216+
return;
217+
}
190218

219+
let pats: Matrix<'_, '_> = vec![PatStack::from_pattern(pattern)].into_iter().collect();
191220
let witnesses = match check_not_useful(cx, pattern_ty, &pats, pat.hir_id) {
192221
Ok(_) => return,
193222
Err(err) => err,

0 commit comments

Comments
 (0)