diagnostics: fix borrowck suggestions for if/while let conditionals · rust-lang/rust@ecb2d5c (original) (raw)
`@@ -248,7 +248,98 @@ impl<'tcx> BorrowExplanation<'tcx> {
`
248
248
`);
`
249
249
` err.span_label(body.source_info(drop_loc).span, message);
`
250
250
``
251
``
`-
if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
`
``
251
`+
struct FindLetExpr<'hir> {
`
``
252
`+
span: Span,
`
``
253
`+
result: Option<(Span, &'hir hir::Pat<'hir>, &'hir hir::Expr<'hir>)>,
`
``
254
`+
tcx: TyCtxt<'hir>,
`
``
255
`+
}
`
``
256
+
``
257
`+
impl<'hir> rustc_hir::intravisit::Visitor<'hir> for FindLetExpr<'hir> {
`
``
258
`+
type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
`
``
259
`+
fn nested_visit_map(&mut self) -> Self::Map {
`
``
260
`+
self.tcx.hir()
`
``
261
`+
}
`
``
262
`+
fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
`
``
263
`+
if let hir::ExprKind::If(cond, _conseq, _alt)
`
``
264
`+
| hir::ExprKind::Loop(
`
``
265
`+
hir::Block {
`
``
266
`+
expr:
`
``
267
`+
Some(&hir::Expr {
`
``
268
`+
kind: hir::ExprKind::If(cond, _conseq, _alt),
`
``
269
`+
..
`
``
270
`+
}),
`
``
271
`+
..
`
``
272
`+
},
`
``
273
`+
_,
`
``
274
`+
hir::LoopSource::While,
`
``
275
`+
_,
`
``
276
`+
) = expr.kind
`
``
277
`+
&& let hir::ExprKind::Let(hir::LetExpr {
`
``
278
`+
init: let_expr_init,
`
``
279
`+
span: let_expr_span,
`
``
280
`+
pat: let_expr_pat,
`
``
281
`+
..
`
``
282
`+
}) = cond.kind
`
``
283
`+
&& let_expr_init.span.contains(self.span)
`
``
284
`+
{
`
``
285
`+
self.result =
`
``
286
`+
Some((*let_expr_span, let_expr_pat, let_expr_init))
`
``
287
`+
} else {
`
``
288
`+
hir::intravisit::walk_expr(self, expr);
`
``
289
`+
}
`
``
290
`+
}
`
``
291
`+
}
`
``
292
+
``
293
`+
if let &LocalInfo::IfThenRescopeTemp { if_then } = local_decl.local_info()
`
``
294
`+
&& let hir::Node::Expr(expr) = tcx.hir_node(if_then)
`
``
295
`+
&& let hir::ExprKind::If(cond, conseq, alt) = expr.kind
`
``
296
`+
&& let hir::ExprKind::Let(&hir::LetExpr {
`
``
297
`+
span: _,
`
``
298
`+
pat,
`
``
299
`+
init,
`
``
300
`+
// FIXME(#101728): enable rewrite when type ascription is
`
``
301
`+
// stabilized again.
`
``
302
`+
ty: None,
`
``
303
`+
recovered: _,
`
``
304
`+
}) = cond.kind
`
``
305
`+
&& pat.span.can_be_used_for_suggestions()
`
``
306
`+
&& let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
`
``
307
`+
{
`
``
308
`+
suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err);
`
``
309
`+
} else if let Some((old, new)) = multiple_borrow_span
`
``
310
`+
&& let def_id = body.source.def_id()
`
``
311
`+
&& let Some(node) = tcx.hir().get_if_local(def_id)
`
``
312
`+
&& let Some(body_id) = node.body_id()
`
``
313
`+
&& let hir_body = tcx.hir().body(body_id)
`
``
314
`+
&& let mut expr_finder = (FindLetExpr { span: old, result: None, tcx })
`
``
315
`+
&& let Some((let_expr_span, let_expr_pat, let_expr_init)) = {
`
``
316
`+
expr_finder.visit_expr(hir_body.value);
`
``
317
`+
expr_finder.result
`
``
318
`+
}
`
``
319
`+
&& !let_expr_span.contains(new)
`
``
320
`+
{
`
``
321
`` +
// #133941: The old
expression is at the conditional part of an
``
``
322
`+
// if/while let expression. Adding a semicolon won't work.
`
``
323
`` +
// Instead, try suggesting the matches!
macro or a temporary.
``
``
324
`+
if let_expr_pat
`
``
325
`+
.walk_short(|pat| !matches!(pat.kind, hir::PatKind::Binding(..)))
`
``
326
`+
{
`
``
327
`+
if let Ok(pat_snippet) =
`
``
328
`+
tcx.sess.source_map().span_to_snippet(let_expr_pat.span)
`
``
329
`+
&& let Ok(init_snippet) =
`
``
330
`+
tcx.sess.source_map().span_to_snippet(let_expr_init.span)
`
``
331
`+
{
`
``
332
`+
err.span_suggestion_verbose(
`
``
333
`+
let_expr_span,
`
``
334
`` +
"consider using the matches!
macro",
``
``
335
`+
format!("matches!({init_snippet}, {pat_snippet})"),
`
``
336
`+
Applicability::MaybeIncorrect,
`
``
337
`+
);
`
``
338
`+
} else {
`
``
339
`` +
err.note("consider using the matches!
macro");
``
``
340
`+
}
`
``
341
`+
}
`
``
342
`+
} else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
`
252
343
`if info.tail_result_is_ignored {
`
253
344
`// #85581: If the first mutable borrow's scope contains
`
254
345
`// the second borrow, this suggestion isn't helpful.
`
`@@ -281,23 +372,6 @@ impl<'tcx> BorrowExplanation<'tcx> {
`
281
372
`Applicability::MaybeIncorrect,
`
282
373
`);
`
283
374
`};
`
284
``
`-
} else if let &LocalInfo::IfThenRescopeTemp { if_then } =
`
285
``
`-
local_decl.local_info()
`
286
``
`-
&& let hir::Node::Expr(expr) = tcx.hir_node(if_then)
`
287
``
`-
&& let hir::ExprKind::If(cond, conseq, alt) = expr.kind
`
288
``
`-
&& let hir::ExprKind::Let(&hir::LetExpr {
`
289
``
`-
span: _,
`
290
``
`-
pat,
`
291
``
`-
init,
`
292
``
`-
// FIXME(#101728): enable rewrite when type ascription is
`
293
``
`-
// stabilized again.
`
294
``
`-
ty: None,
`
295
``
`-
recovered: _,
`
296
``
`-
}) = cond.kind
`
297
``
`-
&& pat.span.can_be_used_for_suggestions()
`
298
``
`-
&& let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span)
`
299
``
`-
{
`
300
``
`-
suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err);
`
301
375
`}
`
302
376
`}
`
303
377
`}
`