1
Fork 0

fix the issue of shorthand in suggest_cloning

This commit is contained in:
yukang 2023-07-13 18:55:45 +08:00
parent 3ddf6f7c17
commit bdd04a62f9
6 changed files with 53 additions and 46 deletions

View file

@ -452,7 +452,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} = move_spans { } = move_spans {
// We already suggest cloning for these cases in `explain_captures`. // We already suggest cloning for these cases in `explain_captures`.
} else { } else {
self.suggest_cloning(err, ty, move_span); self.suggest_cloning(err, ty, expr, move_span);
} }
} }
} }
@ -727,9 +727,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
true true
} }
fn suggest_cloning(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) { fn suggest_cloning(
&self,
err: &mut Diagnostic,
ty: Ty<'tcx>,
expr: &hir::Expr<'_>,
span: Span,
) {
let tcx = self.infcx.tcx; let tcx = self.infcx.tcx;
// Try to find predicates on *generic params* that would allow copying `ty` // Try to find predicates on *generic params* that would allow copying `ty`
let suggestion =
if let Some(symbol) = tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
format!(": {}.clone()", symbol)
} else {
".clone()".to_owned()
};
if let Some(clone_trait_def) = tcx.lang_items().clone_trait() if let Some(clone_trait_def) = tcx.lang_items().clone_trait()
&& self.infcx && self.infcx
.type_implements_trait( .type_implements_trait(
@ -742,7 +754,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_suggestion_verbose( err.span_suggestion_verbose(
span.shrink_to_hi(), span.shrink_to_hi(),
"consider cloning the value if the performance cost is acceptable", "consider cloning the value if the performance cost is acceptable",
".clone()", suggestion,
Applicability::MachineApplicable, Applicability::MachineApplicable,
); );
} }

View file

@ -15,7 +15,7 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeFoldable}; use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeFoldable};
use rustc_span::symbol::{sym, Symbol}; use rustc_span::symbol::sym;
use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_span::{BytePos, Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::ObligationCause; use rustc_trait_selection::traits::ObligationCause;
@ -997,7 +997,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.collect(); .collect();
let suggestions_for = |variant: &_, ctor_kind, field_name| { let suggestions_for = |variant: &_, ctor_kind, field_name| {
let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!("{ident}: "), Some(ident) => format!("{ident}: "),
None => String::new(), None => String::new(),
}; };
@ -1240,39 +1240,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
pub(crate) fn maybe_get_struct_pattern_shorthand_field(
&self,
expr: &hir::Expr<'_>,
) -> Option<Symbol> {
let hir = self.tcx.hir();
let local = match expr {
hir::Expr {
kind:
hir::ExprKind::Path(hir::QPath::Resolved(
None,
hir::Path {
res: hir::def::Res::Local(_),
segments: [hir::PathSegment { ident, .. }],
..
},
)),
..
} => Some(ident),
_ => None,
}?;
match hir.find_parent(expr.hir_id)? {
Node::ExprField(field) => {
if field.ident.name == local.name && field.is_shorthand {
return Some(local.name);
}
}
_ => {}
}
None
}
/// If the given `HirId` corresponds to a block with a trailing expression, return that expression /// If the given `HirId` corresponds to a block with a trailing expression, return that expression
pub(crate) fn maybe_get_block_expr( pub(crate) fn maybe_get_block_expr(
&self, &self,
@ -1467,7 +1434,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)); ));
} }
let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!("{ident}: "), Some(ident) => format!("{ident}: "),
None => String::new(), None => String::new(),
}; };
@ -1661,7 +1628,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) )
}; };
let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { let prefix = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!("{ident}: "), Some(ident) => format!("{ident}: "),
None => String::new(), None => String::new(),
}; };

View file

@ -395,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))] vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))]
}; };
let struct_pat_shorthand_field = let struct_pat_shorthand_field =
self.maybe_get_struct_pattern_shorthand_field(expr); self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr);
if let Some(name) = struct_pat_shorthand_field { if let Some(name) = struct_pat_shorthand_field {
sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name))); sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name)));
} }
@ -1069,7 +1069,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) )
.must_apply_modulo_regions() .must_apply_modulo_regions()
{ {
let suggestion = match self.maybe_get_struct_pattern_shorthand_field(expr) { let suggestion = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!(": {}.clone()", ident), Some(ident) => format!(": {}.clone()", ident),
None => ".clone()".to_string() None => ".clone()".to_string()
}; };
@ -1247,7 +1247,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return false; return false;
} }
let suggestion = match self.maybe_get_struct_pattern_shorthand_field(expr) { let suggestion = match self.tcx.hir().maybe_get_struct_pattern_shorthand_field(expr) {
Some(ident) => format!(": {}.is_some()", ident), Some(ident) => format!(": {}.is_some()", ident),
None => ".is_some()".to_string(), None => ".is_some()".to_string(),
}; };

View file

@ -1103,6 +1103,33 @@ impl<'hir> Map<'hir> {
_ => None, _ => None,
} }
} }
pub fn maybe_get_struct_pattern_shorthand_field(&self, expr: &Expr<'_>) -> Option<Symbol> {
let local = match expr {
Expr {
kind:
ExprKind::Path(QPath::Resolved(
None,
Path {
res: def::Res::Local(_), segments: [PathSegment { ident, .. }], ..
},
)),
..
} => Some(ident),
_ => None,
}?;
match self.find_parent(expr.hir_id)? {
Node::ExprField(field) => {
if field.ident.name == local.name && field.is_shorthand {
return Some(local.name);
}
}
_ => {}
}
None
}
} }
impl<'hir> intravisit::Map<'hir> for Map<'hir> { impl<'hir> intravisit::Map<'hir> for Map<'hir> {

View file

@ -1,3 +1,4 @@
//@run-rustfix
pub struct DataStruct(); pub struct DataStruct();
pub struct HelperStruct<'n> { pub struct HelperStruct<'n> {

View file

@ -1,5 +1,5 @@
error[E0382]: borrow of moved value: `helpers` error[E0382]: borrow of moved value: `helpers`
--> $DIR/copy-suggestion-region-vid.rs:12:43 --> $DIR/copy-suggestion-region-vid.rs:13:43
| |
LL | let helpers = [vec![], vec![]]; LL | let helpers = [vec![], vec![]];
| ------- move occurs because `helpers` has type `[Vec<&i64>; 2]`, which does not implement the `Copy` trait | ------- move occurs because `helpers` has type `[Vec<&i64>; 2]`, which does not implement the `Copy` trait
@ -11,8 +11,8 @@ LL | HelperStruct { helpers, is_empty: helpers[0].is_empty() }
| |
help: consider cloning the value if the performance cost is acceptable help: consider cloning the value if the performance cost is acceptable
| |
LL | HelperStruct { helpers.clone(), is_empty: helpers[0].is_empty() } LL | HelperStruct { helpers: helpers.clone(), is_empty: helpers[0].is_empty() }
| ++++++++ | +++++++++++++++++
error: aborting due to previous error error: aborting due to previous error