Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 42d7174

Browse files
committed
Extract suggestion logic to its own method
1 parent 14a3d57 commit 42d7174

File tree

1 file changed

+156
-140
lines changed

1 file changed

+156
-140
lines changed

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

Lines changed: 156 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -192,146 +192,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
192192
is_loop_move = true;
193193
}
194194

195-
struct ExpressionFinder<'hir> {
196-
expr_span: Span,
197-
expr: Option<&'hir hir::Expr<'hir>>,
198-
pat: Option<&'hir hir::Pat<'hir>>,
199-
}
200-
impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
201-
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
202-
if e.span == self.expr_span {
203-
self.expr = Some(e);
204-
}
205-
hir::intravisit::walk_expr(self, e);
206-
}
207-
fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {
208-
if p.span == self.expr_span {
209-
self.pat = Some(p);
210-
}
211-
if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, _) = p.kind
212-
&& i.span == self.expr_span
213-
{
214-
self.pat = Some(p);
215-
}
216-
hir::intravisit::walk_pat(self, p);
217-
}
218-
}
219-
220-
let hir = self.infcx.tcx.hir();
221-
if let Some(hir::Node::Item(hir::Item {
222-
kind: hir::ItemKind::Fn(_, _, body_id),
223-
..
224-
})) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id()))
225-
&& let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
226-
{
227-
let place = &self.move_data.move_paths[mpi].place;
228-
let span = place.as_local()
229-
.map(|local| self.body.local_decls[local].source_info.span);
230-
let mut finder = ExpressionFinder {
231-
expr_span: move_span,
232-
expr: None,
233-
pat: None,
234-
};
235-
finder.visit_expr(expr);
236-
if let Some(span) = span && let Some(expr) = finder.expr {
237-
for (_, expr) in hir.parent_iter(expr.hir_id) {
238-
if let hir::Node::Expr(expr) = expr {
239-
if expr.span.contains(span) {
240-
// If the let binding occurs within the same loop, then that
241-
// loop isn't relevant, like in the following, the outermost `loop`
242-
// doesn't play into `x` being moved.
243-
// ```
244-
// loop {
245-
// let x = String::new();
246-
// loop {
247-
// foo(x);
248-
// }
249-
// }
250-
// ```
251-
break;
252-
}
253-
if let hir::ExprKind::Loop(.., loop_span) = expr.kind {
254-
err.span_label(loop_span, "inside of this loop");
255-
}
256-
}
257-
}
258-
let typeck = self.infcx.tcx.typeck(self.mir_def_id());
259-
let hir_id = hir.get_parent_node(expr.hir_id);
260-
if let Some(parent) = hir.find(hir_id) {
261-
if let hir::Node::Expr(parent_expr) = parent
262-
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
263-
&& let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id)
264-
&& let Some(def_id) = def_id.as_local()
265-
&& let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id))
266-
&& let Some(fn_sig) = node.fn_sig()
267-
&& let Some(ident) = node.ident()
268-
&& let Some(pos) = args.iter()
269-
.position(|arg| arg.hir_id == expr.hir_id)
270-
&& let Some(arg) = fn_sig.decl.inputs.get(pos + 1)
271-
{
272-
let mut span: MultiSpan = arg.span.into();
273-
span.push_span_label(
274-
arg.span,
275-
"this type parameter takes ownership of the value".to_string(),
276-
);
277-
span.push_span_label(
278-
ident.span,
279-
"in this method".to_string(),
280-
);
281-
err.span_note(
282-
span,
283-
format!(
284-
"consider changing this parameter type in `{}` to borrow \
285-
instead if ownering the value isn't necessary",
286-
ident,
287-
),
288-
);
289-
}
290-
if let hir::Node::Expr(parent_expr) = parent
291-
&& let hir::ExprKind::Call(call, args) = parent_expr.kind
292-
&& let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
293-
&& let Some(def_id) = def_id.as_local()
294-
&& let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id))
295-
&& let Some(fn_sig) = node.fn_sig()
296-
&& let Some(ident) = node.ident()
297-
&& let Some(pos) = args.iter()
298-
.position(|arg| arg.hir_id == expr.hir_id)
299-
&& let Some(arg) = fn_sig.decl.inputs.get(pos)
300-
{
301-
let mut span: MultiSpan = arg.span.into();
302-
span.push_span_label(
303-
arg.span,
304-
"this type parameter takes ownership of the value".to_string(),
305-
);
306-
span.push_span_label(
307-
ident.span,
308-
"in this function".to_string(),
309-
);
310-
err.span_note(
311-
span,
312-
format!(
313-
"consider changing this parameter type in `{}` to borrow \
314-
instead if ownering the value isn't necessary",
315-
ident,
316-
),
317-
);
318-
}
319-
let place = &self.move_data.move_paths[mpi].place;
320-
let ty = place.ty(self.body, self.infcx.tcx).ty;
321-
self.suggest_cloning(&mut err, ty, move_span);
322-
}
323-
}
324-
if let Some(pat) = finder.pat && !seen_spans.contains(&pat.span) {
325-
in_pattern = true;
326-
err.span_suggestion_verbose(
327-
pat.span.shrink_to_lo(),
328-
"borrow this binding in the pattern to avoid moving the value",
329-
"ref ".to_string(),
330-
Applicability::MachineApplicable,
331-
);
332-
seen_spans.insert(pat.span);
333-
}
334-
}
195+
self.suggest_ref_or_clone(
196+
mpi,
197+
move_span,
198+
&mut err,
199+
&mut seen_spans,
200+
&mut in_pattern,
201+
);
335202

336203
self.explain_captures(
337204
&mut err,
@@ -440,6 +307,155 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
440307
}
441308
}
442309

310+
fn suggest_ref_or_clone(
311+
&mut self,
312+
mpi: MovePathIndex,
313+
move_span: Span,
314+
err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
315+
seen_spans: &mut FxHashSet<Span>,
316+
in_pattern: &mut bool,
317+
) {
318+
struct ExpressionFinder<'hir> {
319+
expr_span: Span,
320+
expr: Option<&'hir hir::Expr<'hir>>,
321+
pat: Option<&'hir hir::Pat<'hir>>,
322+
}
323+
impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
324+
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
325+
if e.span == self.expr_span {
326+
self.expr = Some(e);
327+
}
328+
hir::intravisit::walk_expr(self, e);
329+
}
330+
fn visit_pat(&mut self, p: &'hir hir::Pat<'hir>) {
331+
if p.span == self.expr_span {
332+
self.pat = Some(p);
333+
}
334+
if let hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, i, _) = p.kind
335+
&& i.span == self.expr_span
336+
{
337+
self.pat = Some(p);
338+
}
339+
hir::intravisit::walk_pat(self, p);
340+
}
341+
}
342+
let hir = self.infcx.tcx.hir();
343+
if let Some(hir::Node::Item(hir::Item {
344+
kind: hir::ItemKind::Fn(_, _, body_id),
345+
..
346+
})) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id()))
347+
&& let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
348+
{
349+
let place = &self.move_data.move_paths[mpi].place;
350+
let span = place.as_local()
351+
.map(|local| self.body.local_decls[local].source_info.span);
352+
let mut finder = ExpressionFinder {
353+
expr_span: move_span,
354+
expr: None,
355+
pat: None,
356+
};
357+
finder.visit_expr(expr);
358+
if let Some(span) = span && let Some(expr) = finder.expr {
359+
for (_, expr) in hir.parent_iter(expr.hir_id) {
360+
if let hir::Node::Expr(expr) = expr {
361+
if expr.span.contains(span) {
362+
// If the let binding occurs within the same loop, then that
363+
// loop isn't relevant, like in the following, the outermost `loop`
364+
// doesn't play into `x` being moved.
365+
// ```
366+
// loop {
367+
// let x = String::new();
368+
// loop {
369+
// foo(x);
370+
// }
371+
// }
372+
// ```
373+
break;
374+
}
375+
if let hir::ExprKind::Loop(.., loop_span) = expr.kind {
376+
err.span_label(loop_span, "inside of this loop");
377+
}
378+
}
379+
}
380+
let typeck = self.infcx.tcx.typeck(self.mir_def_id());
381+
let hir_id = hir.get_parent_node(expr.hir_id);
382+
if let Some(parent) = hir.find(hir_id) {
383+
if let hir::Node::Expr(parent_expr) = parent
384+
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
385+
&& let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id)
386+
&& let Some(def_id) = def_id.as_local()
387+
&& let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id))
388+
&& let Some(fn_sig) = node.fn_sig()
389+
&& let Some(ident) = node.ident()
390+
&& let Some(pos) = args.iter()
391+
.position(|arg| arg.hir_id == expr.hir_id)
392+
&& let Some(arg) = fn_sig.decl.inputs.get(pos + 1)
393+
{
394+
let mut span: MultiSpan = arg.span.into();
395+
span.push_span_label(
396+
arg.span,
397+
"this type parameter takes ownership of the value".to_string(),
398+
);
399+
span.push_span_label(
400+
ident.span,
401+
"in this method".to_string(),
402+
);
403+
err.span_note(
404+
span,
405+
format!(
406+
"consider changing this parameter type in `{}` to borrow instead \
407+
if ownering the value isn't necessary",
408+
ident,
409+
),
410+
);
411+
}
412+
if let hir::Node::Expr(parent_expr) = parent
413+
&& let hir::ExprKind::Call(call, args) = parent_expr.kind
414+
&& let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
415+
&& let Some(def_id) = def_id.as_local()
416+
&& let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id))
417+
&& let Some(fn_sig) = node.fn_sig()
418+
&& let Some(ident) = node.ident()
419+
&& let Some(pos) = args.iter()
420+
.position(|arg| arg.hir_id == expr.hir_id)
421+
&& let Some(arg) = fn_sig.decl.inputs.get(pos)
422+
{
423+
let mut span: MultiSpan = arg.span.into();
424+
span.push_span_label(
425+
arg.span,
426+
"this type parameter takes ownership of the value".to_string(),
427+
);
428+
span.push_span_label(
429+
ident.span,
430+
"in this function".to_string(),
431+
);
432+
err.span_note(
433+
span,
434+
format!(
435+
"consider changing this parameter type in `{}` to borrow instead \
436+
if ownering the value isn't necessary",
437+
ident,
438+
),
439+
);
440+
}
441+
let place = &self.move_data.move_paths[mpi].place;
442+
let ty = place.ty(self.body, self.infcx.tcx).ty;
443+
self.suggest_cloning(err, ty, move_span);
444+
}
445+
}
446+
if let Some(pat) = finder.pat && !seen_spans.contains(&pat.span) {
447+
*in_pattern = true;
448+
err.span_suggestion_verbose(
449+
pat.span.shrink_to_lo(),
450+
"borrow this binding in the pattern to avoid moving the value",
451+
"ref ".to_string(),
452+
Applicability::MachineApplicable,
453+
);
454+
seen_spans.insert(pat.span);
455+
}
456+
}
457+
}
458+
443459
fn report_use_of_uninitialized(
444460
&self,
445461
mpi: MovePathIndex,

0 commit comments

Comments
 (0)