X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=compiler%2Frustc_trait_selection%2Fsrc%2Ftraits%2Ferror_reporting%2Fsuggestions.rs;h=16ecca254c7b0163de33a9a401c30b2f86ee7652;hb=ef91519b45d2bbf0ce8c0180118160562eaaa0ca;hp=5bf9be87b57ae2dde9fb82699c9b92896b33d066;hpb=3aac307ca62f6d6c5b3612d3dfe80b6eeae8ba15;p=rust.git diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 5bf9be87b57..16ecca254c7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1,6 +1,6 @@ use super::{ - EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, - SelectionContext, + DerivedObligationCause, EvaluationResult, ImplDerivedObligationCause, Obligation, + ObligationCause, ObligationCauseCode, PredicateObligation, SelectionContext, }; use crate::autoderef::Autoderef; @@ -496,50 +496,81 @@ fn suggest_dereferences( trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { // It only make sense when suggesting dereferences for arguments - let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } = - obligation.cause.code() - { - parent_code.clone() - } else { + let ObligationCauseCode::FunctionArgumentObligation { .. } = obligation.cause.code() else { return false; }; let param_env = obligation.param_env; let body_id = obligation.cause.body_id; let span = obligation.cause.span; - let real_trait_pred = match &*code { - ObligationCauseCode::ImplDerivedObligation(cause) => cause.derived.parent_trait_pred, - ObligationCauseCode::DerivedObligation(cause) - | ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_pred, - _ => trait_pred, - }; - let Some(real_ty) = real_trait_pred.self_ty().no_bound_vars() else { - return false; - }; + let mut real_trait_pred = trait_pred; + let mut code = obligation.cause.code(); + loop { + match &code { + ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => { + code = &parent_code; + } + ObligationCauseCode::ImplDerivedObligation(box ImplDerivedObligationCause { + derived: DerivedObligationCause { parent_code, parent_trait_pred }, + .. + }) + | ObligationCauseCode::BuiltinDerivedObligation(DerivedObligationCause { + parent_code, + parent_trait_pred, + }) + | ObligationCauseCode::DerivedObligation(DerivedObligationCause { + parent_code, + parent_trait_pred, + }) => { + code = &parent_code; + real_trait_pred = *parent_trait_pred; + } + _ => break, + }; + let Some(real_ty) = real_trait_pred.self_ty().no_bound_vars() else { + continue; + }; - if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() { - let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span); - if let Some(steps) = autoderef.find_map(|(ty, steps)| { - // Re-add the `&` - let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); - let obligation = - self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, ty); - Some(steps).filter(|_| self.predicate_may_hold(&obligation)) - }) { - if steps > 0 { - if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) { - // Don't care about `&mut` because `DerefMut` is used less - // often and user will not expect autoderef happens. - if src.starts_with('&') && !src.starts_with("&mut ") { - let derefs = "*".repeat(steps); - err.span_suggestion( - span, - "consider adding dereference here", - format!("&{}{}", derefs, &src[1..]), - Applicability::MachineApplicable, - ); - return true; + if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() { + let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span); + if let Some(steps) = autoderef.find_map(|(ty, steps)| { + // Re-add the `&` + let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); + let obligation = + self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, ty); + Some(steps).filter(|_| self.predicate_may_hold(&obligation)) + }) { + if steps > 0 { + if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) { + // Don't care about `&mut` because `DerefMut` is used less + // often and user will not expect autoderef happens. + if src.starts_with('&') && !src.starts_with("&mut ") { + let derefs = "*".repeat(steps); + err.span_suggestion( + span, + "consider dereferencing here", + format!("&{}{}", derefs, &src[1..]), + Applicability::MachineApplicable, + ); + return true; + } } } + } else if real_trait_pred != trait_pred { + // This branch addresses #87437. + let obligation = self.mk_trait_obligation_with_new_self_ty( + param_env, + real_trait_pred, + base_ty, + ); + if self.predicate_may_hold(&obligation) { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider dereferencing here", + "*".to_string(), + Applicability::MachineApplicable, + ); + return true; + } } } }