|| self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
|| self.suggest_block_to_brackets_peeling_refs(err, expr, expr_ty, expected)
|| self.suggest_copied_or_cloned(err, expr, expr_ty, expected)
+ || self.suggest_clone_for_ref(err, expr, expr_ty, expected)
|| self.suggest_into(err, expr, expr_ty, expected)
|| self.suggest_floating_point_literal(err, expr, expected);
if !suggested {
}
}
+ pub(crate) fn suggest_clone_for_ref(
+ &self,
+ diag: &mut Diagnostic,
+ expr: &hir::Expr<'_>,
+ expr_ty: Ty<'tcx>,
+ expected_ty: Ty<'tcx>,
+ ) -> bool {
+ if let ty::Ref(_, inner_ty, hir::Mutability::Not) = expr_ty.kind() &&
+ let Some(clone_trait_def) = self.tcx.lang_items().clone_trait() &&
+ expected_ty == *inner_ty &&
+ self
+ .infcx
+ .type_implements_trait(
+ clone_trait_def,
+ [self.tcx.erase_regions(expected_ty)],
+ self.param_env
+ )
+ .must_apply_modulo_regions() {
+ diag.span_suggestion_verbose(
+ expr.span.shrink_to_hi(),
+ "consider using clone here",
+ ".clone()",
+ Applicability::MachineApplicable,
+ );
+ return true;
+ }
+ false
+ }
+
pub(crate) fn suggest_copied_or_cloned(
&self,
diag: &mut Diagnostic,
);
}
+ if self.suggest_add_clone_to_arg(&obligation, &mut err, trait_predicate) {
+ err.emit();
+ return;
+ }
+
if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) {
err.emit();
return;
use crate::traits::{NormalizeExt, ObligationCtxt};
use hir::def::CtorOf;
-use hir::HirId;
+use hir::{Expr, HirId};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{
trait_pred: ty::PolyTraitPredicate<'tcx>,
);
- fn suggest_add_reference_to_arg(
+ fn suggest_add_clone_to_arg(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut Diagnostic,
trait_pred: ty::PolyTraitPredicate<'tcx>,
+ );
+
+ fn suggest_add_reference_to_arg(
+ err: &mut Diagnostic,
has_custom_message: bool,
) -> bool;
}
}
+ fn suggest_add_clone_to_arg(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ err: &mut Diagnostic,
+ trait_pred: ty::PolyTraitPredicate<'tcx>,
+ ) -> bool {
+ let span = obligation.cause.span;
+ let body_id = obligation.cause.body_id;
+ let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
+ let ty = self.tcx.erase_late_bound_regions(self_ty);
+ let owner = self.tcx.hir().get_parent_item(body_id);
+ if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = obligation.cause.code() &&
+ let arg_node = self.tcx.hir().get(*arg_hir_id) &&
+ let Node::Expr(Expr { kind: hir::ExprKind::Path(_), ..}) = arg_node &&
+ let Some(generics) = self.tcx.hir().get_generics(owner.def_id) &&
+ let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() &&
+ let ty::Param(param) = inner_ty.kind() &&
+ let Some(generic_param) =
+ generics.params.iter().find(|p| p.name.ident().as_str() == param.name.as_str())
+ {
+ let clone_trait = self.tcx.require_lang_item(LangItem::Clone, None);
+ let has_clone = self
+ .type_implements_trait(clone_trait, [ty], obligation.param_env)
+ .must_apply_modulo_regions();
+
+ let trait_pred_and_suggested_ty =
+ trait_pred.map_bound(|trait_pred| (trait_pred, *inner_ty));
+ let new_obligation = self.mk_trait_obligation_with_new_self_ty(
+ obligation.param_env,
+ trait_pred_and_suggested_ty,
+ );
+
+ if has_clone && self.predicate_may_hold(&new_obligation) {
+ let clone_bound = generics.bounds_for_param(generic_param.def_id)
+ .flat_map(|bp| bp.bounds)
+ .any(|bound| {
+ if let hir::GenericBound::Trait( hir::PolyTraitRef { trait_ref, ..}, ..) = bound {
+ Some(clone_trait) == trait_ref.trait_def_id()
+ } else {
+ false
+ }
+ });
+ if !clone_bound {
+ suggest_constraining_type_param(
+ self.tcx,
+ generics,
+ err,
+ param.name.as_str(),
+ "Clone",
+ Some(clone_trait)
+ );
+ }
+ err.span_suggestion_verbose(
+ span.shrink_to_hi(),
+ "consider using clone here",
+ ".clone()".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ return true;
+ }
+ }
+ false
+ }
+
fn suggest_add_reference_to_arg(
&self,
obligation: &PredicateObligation<'tcx>,
--- /dev/null
+#[derive(Clone)]
+struct S;
+
+// without Clone
+struct T;
+
+fn foo(_: S) {}
+
+fn test1() {
+ let s = &S;
+ foo(s); //~ ERROR mismatched types
+}
+
+fn bar(_: T) {}
+fn test2() {
+ let t = &T;
+ bar(t); //~ ERROR mismatched types
+}
+
+fn main() {
+ test1();
+ test2();
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-106443-sugg-clone-for-arg.rs:11:9
+ |
+LL | foo(s);
+ | --- ^ expected struct `S`, found `&S`
+ | |
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/issue-106443-sugg-clone-for-arg.rs:7:4
+ |
+LL | fn foo(_: S) {}
+ | ^^^ ----
+help: consider using clone here
+ |
+LL | foo(s.clone());
+ | ++++++++
+
+error[E0308]: mismatched types
+ --> $DIR/issue-106443-sugg-clone-for-arg.rs:17:9
+ |
+LL | bar(t);
+ | --- ^ expected struct `T`, found `&T`
+ | |
+ | arguments to this function are incorrect
+ |
+note: function defined here
+ --> $DIR/issue-106443-sugg-clone-for-arg.rs:14:4
+ |
+LL | fn bar(_: T) {}
+ | ^^^ ----
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#[derive(Clone)]
+struct S;
+
+trait X {}
+
+impl X for S {}
+
+fn foo<T: X>(_: T) {}
+fn bar<T: X>(s: &T) {
+ foo(s); //~ ERROR the trait bound `&T: X` is not satisfied
+}
+
+fn bar_with_clone<T: X + Clone>(s: &T) {
+ foo(s); //~ ERROR the trait bound `&T: X` is not satisfied
+}
+
+fn main() {
+ let s = &S;
+ bar(s);
+}
--- /dev/null
+error[E0277]: the trait bound `&T: X` is not satisfied
+ --> $DIR/issue-106443-sugg-clone-for-bound.rs:10:9
+ |
+LL | foo(s);
+ | ^ the trait `X` is not implemented for `&T`
+ |
+help: consider further restricting this bound
+ |
+LL | fn bar<T: X + Clone>(s: &T) {
+ | +++++++
+help: consider using clone here
+ |
+LL | foo(s.clone());
+ | ++++++++
+
+error[E0277]: the trait bound `&T: X` is not satisfied
+ --> $DIR/issue-106443-sugg-clone-for-bound.rs:14:9
+ |
+LL | foo(s);
+ | ^ the trait `X` is not implemented for `&T`
+ |
+help: consider using clone here
+ |
+LL | foo(s.clone());
+ | ++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.