mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
Do not suggest borrowing enclosing calls for nested where-clause obligations
This commit is contained in:
@@ -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`.
|
||||
Reference in New Issue
Block a user