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

`}

`