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=58e002b3360818382bdc4363bf0d410fbbb8bc6b;hpb=94b1960535b79bc211a1a9c9967a972e8306e7ae;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 58e002b3360..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; @@ -58,7 +58,7 @@ fn suggest_dereferences( obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, - ); + ) -> bool; fn get_closure_name(&self, def_id: DefId, err: &mut Diagnostic, msg: &str) -> Option; @@ -67,7 +67,7 @@ fn suggest_fn_call( obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, - ); + ) -> bool; fn suggest_add_reference_to_arg( &self, @@ -82,7 +82,7 @@ fn suggest_remove_reference( obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, - ); + ) -> bool; fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic); @@ -99,7 +99,7 @@ fn suggest_semicolon_removal( err: &mut Diagnostic, span: Span, trait_pred: ty::PolyTraitPredicate<'tcx>, - ); + ) -> bool; fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option; @@ -128,7 +128,7 @@ fn report_closure_arg_mismatch( fn suggest_fully_qualified_path( &self, err: &mut Diagnostic, - def_id: DefId, + item_def_id: DefId, span: Span, trait_ref: DefId, ); @@ -494,54 +494,87 @@ fn suggest_dereferences( obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic, 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 { - return; + 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; - }; + 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, - ); + 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; + } } } } + false } /// Given a closure's `DefId`, return the given name of the closure. @@ -584,22 +617,22 @@ fn suggest_fn_call( obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, - ) { + ) -> bool { let Some(self_ty) = trait_pred.self_ty().no_bound_vars() else { - return; + return false; }; let (def_id, output_ty, callable) = match *self_ty.kind() { ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"), ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"), - _ => return, + _ => return false, }; let msg = format!("use parentheses to call the {}", callable); // `mk_trait_obligation_with_new_self_ty` only works for types with no escaping bound // variables, so bail out if we have any. let Some(output_ty) = output_ty.no_bound_vars() else { - return; + return false; }; let new_obligation = @@ -611,7 +644,7 @@ fn suggest_fn_call( | EvaluationResult::EvaluatedToOkModuloRegions | EvaluationResult::EvaluatedToAmbig, ) => {} - _ => return, + _ => return false, } let hir = self.tcx.hir(); // Get the name of the callable and the arguments to be used in the suggestion. @@ -622,7 +655,7 @@ fn suggest_fn_call( })) => { err.span_label(*span, "consider calling this closure"); let Some(name) = self.get_closure_name(def_id, err, &msg) else { - return; + return false; }; let args = decl.inputs.iter().map(|_| "_").collect::>().join(", "); let sugg = format!("({})", args); @@ -650,7 +683,7 @@ fn suggest_fn_call( let sugg = format!("({})", args); (format!("{}{}", ident, sugg), sugg) } - _ => return, + _ => return false, }; if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. }) { @@ -667,6 +700,7 @@ fn suggest_fn_call( } else { err.help(&format!("{}: `{}`", msg, snippet)); } + true } fn suggest_add_reference_to_arg( @@ -808,19 +842,20 @@ fn suggest_remove_reference( obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic, trait_pred: ty::PolyTraitPredicate<'tcx>, - ) { + ) -> bool { let span = obligation.cause.span; + let mut suggested = false; if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { let refs_number = snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count(); if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) { // Do not suggest removal of borrow from type arguments. - return; + return false; } let Some(mut suggested_ty) = trait_pred.self_ty().no_bound_vars() else { - return; + return false; }; for refs_remaining in 0..refs_number { @@ -856,10 +891,12 @@ fn suggest_remove_reference( String::new(), Applicability::MachineApplicable, ); + suggested = true; break; } } } + suggested } fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) { @@ -996,7 +1033,7 @@ fn suggest_semicolon_removal( err: &mut Diagnostic, span: Span, trait_pred: ty::PolyTraitPredicate<'tcx>, - ) { + ) -> bool { let hir = self.tcx.hir(); let parent_node = hir.get_parent_node(obligation.cause.body_id); let node = hir.find(parent_node); @@ -1015,7 +1052,9 @@ fn suggest_semicolon_removal( { let sp = self.tcx.sess.source_map().end_point(stmt.span); err.span_label(sp, "consider removing this semicolon"); + return true; } + false } fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option { @@ -1317,16 +1356,16 @@ fn report_closure_arg_mismatch( fn suggest_fully_qualified_path( &self, err: &mut Diagnostic, - def_id: DefId, + item_def_id: DefId, span: Span, trait_ref: DefId, ) { - if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) { + if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) { if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind { err.note(&format!( "{}s cannot be accessed directly on a `trait`, they can only be \ accessed through a specific `impl`", - assoc_item.kind.as_def_kind().descr(def_id) + assoc_item.kind.as_def_kind().descr(item_def_id) )); err.span_suggestion( span,