Do not suggest borrowing enclosing calls for nested where-clause obligations

This commit is contained in:
nataliakokoromyti
2026-04-18 10:51:16 -07:00
parent 14196dbfa3
commit 9064d17405
5 changed files with 83 additions and 0 deletions
@@ -349,6 +349,7 @@ pub(super) fn maybe_report_ambiguity(
if impl_candidates.len() < 40 {
self.report_similar_impl_candidates(
impl_candidates.as_slice(),
obligation,
trait_pred,
obligation.cause.body_id,
&mut err,
@@ -2008,6 +2008,7 @@ pub(super) fn find_similar_impl_candidates(
pub(super) fn report_similar_impl_candidates(
&self,
impl_candidates: &[ImplCandidate<'tcx>],
obligation: &PredicateObligation<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
body_def_id: LocalDefId,
err: &mut Diag<'_>,
@@ -2072,6 +2073,20 @@ pub(super) fn report_similar_impl_candidates(
};
if let [single] = &impl_candidates {
let self_ty = trait_pred.skip_binder().self_ty();
if !self_ty.has_escaping_bound_vars() {
let self_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty());
if let ty::Ref(_, inner_ty, _) = self_ty.kind()
&& self.can_eq(param_env, single.trait_ref.self_ty(), *inner_ty)
&& !self.where_clause_expr_matches_failed_self_ty(obligation, self_ty)
{
// Avoid pointing at a nearby impl like `String: Borrow<str>` when the
// failing obligation comes from something nested inside an enclosing call
// expression such as `foo(&[String::from("a")])`.
return true;
}
}
// If we have a single implementation, try to unify it with the trait ref
// that failed. This should uncover a better hint for what *is* implemented.
if self.probe(|_| {
@@ -2491,6 +2506,7 @@ fn report_similar_impl_candidates_for_root_obligation(
let impl_candidates = self.find_similar_impl_candidates(trait_pred);
self.report_similar_impl_candidates(
&impl_candidates,
obligation,
trait_pred,
body_def_id,
err,
@@ -3165,6 +3181,7 @@ fn try_to_add_help_message(
let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
if !self.report_similar_impl_candidates(
&impl_candidates,
obligation,
trait_predicate,
body_def_id,
err,
@@ -1467,6 +1467,39 @@ pub fn extract_callable_info(
if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) }
}
pub(super) fn where_clause_expr_matches_failed_self_ty(
&self,
obligation: &PredicateObligation<'tcx>,
old_self_ty: Ty<'tcx>,
) -> bool {
let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code() else {
return true;
};
let (Some(typeck_results), Some(body)) = (
self.typeck_results.as_ref(),
self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id),
) else {
return true;
};
let mut expr_finder = FindExprBySpan::new(obligation.cause.span, self.tcx);
expr_finder.visit_expr(body.value);
let Some(expr) = expr_finder.result else {
return true;
};
let inner_old_self_ty = match old_self_ty.kind() {
ty::Ref(_, inner_ty, _) => Some(*inner_ty),
_ => None,
};
[typeck_results.expr_ty_adjusted_opt(expr)].into_iter().flatten().any(|expr_ty| {
self.can_eq(obligation.param_env, expr_ty, old_self_ty)
|| inner_old_self_ty
.is_some_and(|inner_ty| self.can_eq(obligation.param_env, expr_ty, inner_ty))
})
}
pub(super) fn suggest_add_reference_to_arg(
&self,
obligation: &PredicateObligation<'tcx>,
@@ -1740,6 +1773,15 @@ pub(super) fn suggest_add_reference_to_arg(
if let hir::ExprKind::AddrOf(_, _, _) = expr.kind {
return false;
}
let old_self_ty = old_pred.skip_binder().self_ty();
if !old_self_ty.has_escaping_bound_vars()
&& !self.where_clause_expr_matches_failed_self_ty(
obligation,
self.tcx.instantiate_bound_regions_with_erased(old_pred.self_ty()),
)
{
return false;
}
let needs_parens_post = expr_needs_parens(expr);
let needs_parens_pre = match self.tcx.parent_hir_node(expr.hir_id) {
Node::Expr(e)
@@ -0,0 +1,8 @@
use std::borrow::Borrow;
fn foo(_v: impl IntoIterator<Item = impl Borrow<str>>) {}
fn main() {
foo(&[String::from("a")]);
//~^ ERROR the trait bound `&String: Borrow<str>` is not satisfied
}
@@ -0,0 +1,15 @@
error[E0277]: the trait bound `&String: Borrow<str>` is not satisfied
--> $DIR/dont-suggest-borrow-whole-call-issue-155088.rs:6:5
|
LL | foo(&[String::from("a")]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Borrow<str>` is not implemented for `&String`
|
note: required by a bound in `foo`
--> $DIR/dont-suggest-borrow-whole-call-issue-155088.rs:3:42
|
LL | fn foo(_v: impl IntoIterator<Item = impl Borrow<str>>) {}
| ^^^^^^^^^^^ required by this bound in `foo`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.