diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2023-01-01 18:43:47 -0800 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2023-01-11 21:38:54 +0000 |
| commit | 2024aa48b4e92894e6f780a13c03db7605e1a5f2 (patch) | |
| tree | 5dfeab33080b82ef4d5bc8baf2a5ff8588734ad4 /compiler/rustc_trait_selection/src | |
| parent | b22c152958eade17a71d899b29a2d39bcc77aa48 (diff) | |
| download | rust-2024aa48b4e92894e6f780a13c03db7605e1a5f2.tar.gz rust-2024aa48b4e92894e6f780a13c03db7605e1a5f2.zip | |
Make `&`-removal suggestion verbose
Diffstat (limited to 'compiler/rustc_trait_selection/src')
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs | 71 |
1 files changed, 47 insertions, 24 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 43985495827..553144078ee 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1358,26 +1358,41 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { - let span = obligation.cause.span; - + let mut span = obligation.cause.span; + while span.desugaring_kind().is_some() { + // Remove all the hir desugaring contexts while maintaining the macro contexts. + span.remove_mark(); + } let mut suggested = false; - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - let refs_number = - snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count(); - if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) { - // Do not suggest removal of borrow from type arguments. - return false; - } - // Skipping binder here, remapping below - let mut suggested_ty = trait_pred.self_ty().skip_binder(); + let mut expr_finder = super::FindExprBySpan { span, result: None }; + let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else { + return false; + }; + expr_finder.visit_expr(&body); + let mut count = 0; + let mut suggestions = vec![]; + let Some(mut expr) = expr_finder.result else { return false; }; + // Skipping binder here, remapping below + let mut suggested_ty = trait_pred.self_ty().skip_binder(); + + 'outer: loop { + while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind { + count += 1; + let span = if expr.span.eq_ctxt(borrowed.span) { + expr.span.until(borrowed.span) + } else { + expr.span.with_hi(expr.span.lo() + BytePos(1)) + }; + suggestions.push((span, String::new())); - for refs_remaining in 0..refs_number { let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else { break; }; suggested_ty = *inner_ty; + expr = borrowed; + // Remapping bound vars here let trait_pred_and_suggested_ty = trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty)); @@ -1388,25 +1403,33 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); if self.predicate_may_hold(&new_obligation) { - let sp = self - .tcx - .sess - .source_map() - .span_take_while(span, |c| c.is_whitespace() || *c == '&'); - - let remove_refs = refs_remaining + 1; - - let msg = if remove_refs == 1 { + let msg = if count == 1 { "consider removing the leading `&`-reference".to_string() } else { - format!("consider removing {} leading `&`-references", remove_refs) + format!("consider removing {count} leading `&`-references") }; - err.span_suggestion_short(sp, &msg, "", Applicability::MachineApplicable); + err.multipart_suggestion_verbose( + &msg, + suggestions, + Applicability::MachineApplicable, + ); suggested = true; - break; + break 'outer; } } + if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind + && let hir::def::Res::Local(hir_id) = path.res + && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id) + && let parent_hir_id = self.tcx.hir().get_parent_node(binding.hir_id) + && let Some(hir::Node::Local(local)) = self.tcx.hir().find(parent_hir_id) + && let None = local.ty + && let Some(binding_expr) = local.init + { + expr = binding_expr; + } else { + break 'outer; + } } suggested } |
