Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if impl_candidates.len() < 40 {
self.report_similar_impl_candidates(
impl_candidates.as_slice(),
obligation,
trait_pred,
obligation.cause.body_id,
&mut err,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2008,6 +2008,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
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<'_>,
Expand Down Expand Up @@ -2072,6 +2073,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
};

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(|_| {
Expand Down Expand Up @@ -2491,6 +2506,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let impl_candidates = self.find_similar_impl_candidates(trait_pred);
self.report_similar_impl_candidates(
&impl_candidates,
obligation,
trait_pred,
body_def_id,
err,
Expand Down Expand Up @@ -3165,6 +3181,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1467,6 +1467,39 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
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>,
Expand Down Expand Up @@ -1740,6 +1773,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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`.
Loading