diff options
Diffstat (limited to 'compiler')
8 files changed, 73 insertions, 50 deletions
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 52ee7e2983c..ebca8bccefc 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2509,11 +2509,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { labeled_user_string ); let pred = format!("{}: {}", bound_kind, sub); - let suggestion = format!( - "{} {}", - generics.add_where_or_trailing_comma(), - pred, - ); + let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred,); err.span_suggestion( generics.tail_span_for_predicate_suggestion(), "consider adding a where clause", diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 6fbe6b8550c..020c5e0ce42 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -3,8 +3,8 @@ use std::ops::ControlFlow; use crate::ty::{ - fold::TypeFoldable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy, Ty, TyCtxt, - TypeVisitor, + fold::TypeFoldable, Const, ConstKind, DefIdTree, ExistentialPredicate, InferTy, + PolyTraitPredicate, Ty, TyCtxt, TypeSuperFoldable, TypeVisitor, }; use rustc_data_structures::fx::FxHashMap; @@ -73,31 +73,53 @@ impl<'tcx> Ty<'tcx> { _ => self.is_simple_ty(), } } +} + +pub trait IsSuggestable<'tcx> { + fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool; - /// Whether the type can be safely suggested during error recovery. - pub fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool { - self.visit_with(&mut IsSuggestableVisitor { tcx }).is_continue() + fn is_suggestable_modulo_impl_trait(self, tcx: TyCtxt<'tcx>, bound_str: &str) -> bool; +} + +impl<'tcx, T> IsSuggestable<'tcx> for T +where + T: TypeFoldable<'tcx>, +{ + fn is_suggestable(self, tcx: TyCtxt<'tcx>) -> bool { + self.visit_with(&mut IsSuggestableVisitor { tcx, bound_str: None }).is_continue() + } + + fn is_suggestable_modulo_impl_trait(self, tcx: TyCtxt<'tcx>, bound_str: &str) -> bool { + self.visit_with(&mut IsSuggestableVisitor { tcx, bound_str: Some(bound_str) }).is_continue() } } -pub fn suggest_arbitrary_trait_bound( +pub fn suggest_arbitrary_trait_bound<'tcx>( + tcx: TyCtxt<'tcx>, generics: &hir::Generics<'_>, err: &mut Diagnostic, - param_name: &str, - constraint: &str, + trait_pred: PolyTraitPredicate<'tcx>, ) -> bool { + if !trait_pred.is_suggestable(tcx) { + return false; + } + + let param_name = trait_pred.skip_binder().self_ty().to_string(); + let constraint = trait_pred.print_modifiers_and_trait_path().to_string(); let param = generics.params.iter().find(|p| p.name.ident().as_str() == param_name); - match (param, param_name) { - (Some(_), "Self") => return false, - _ => {} + + // Skip, there is a param named Self + if param.is_some() && param_name == "Self" { + return false; } + // Suggest a where clause bound for a non-type parameter. err.span_suggestion_verbose( generics.tail_span_for_predicate_suggestion(), &format!( "consider {} `where` clause, but there might be an alternative better way to express \ this requirement", - if generics.has_where_clause_token { "extending the" } else { "introducing a" }, + if generics.has_where_clause_token { "extending the" } else { "introducing a" }, ), format!("{} {}: {}", generics.add_where_or_trailing_comma(), param_name, constraint), Applicability::MaybeIncorrect, @@ -395,11 +417,12 @@ impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> { } } -pub struct IsSuggestableVisitor<'tcx> { +pub struct IsSuggestableVisitor<'tcx, 's> { tcx: TyCtxt<'tcx>, + bound_str: Option<&'s str>, } -impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { +impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx, '_> { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { @@ -438,6 +461,16 @@ impl<'tcx> TypeVisitor<'tcx> for IsSuggestableVisitor<'tcx> { } } + Param(param) => { + if let Some(found_bound_str) = + param.name.as_str().strip_prefix("impl ").map(|s| s.trim_start()) + { + if self.bound_str.map_or(true, |bound_str| bound_str != found_bound_str) { + return ControlFlow::Break(()); + } + } + } + _ => {} } 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 e58451cce82..fbdc7215856 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -21,11 +21,9 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node}; use rustc_middle::hir::map; use rustc_middle::ty::{ - self, - subst::{GenericArgKind, SubstsRef}, - suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree, - GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, ToPredicate, Ty, TyCtxt, - TypeFoldable, + self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, DefIdTree, + GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, IsSuggestable, + ToPredicate, Ty, TyCtxt, TypeFoldable, }; use rustc_middle::ty::{TypeAndMut, TypeckResults}; use rustc_session::Limit; @@ -358,11 +356,14 @@ fn suggest_restriction<'tcx>( ty::Param(param) => { // `fn foo(t: impl Trait)` // ^^^^^ get this string - param.name.as_str().strip_prefix("impl").map(|s| (s.trim_start().to_string(), sig)) + param.name.as_str().strip_prefix("impl ").map(|s| (s.trim_start().to_string(), sig)) } _ => None, }) { + if !trait_pred.is_suggestable_modulo_impl_trait(tcx, &bound_str) { + return; + } // We know we have an `impl Trait` that doesn't satisfy a required projection. // Find all of the occurrences of `impl Trait` for `Trait` in the function arguments' @@ -417,6 +418,9 @@ fn suggest_restriction<'tcx>( Applicability::MaybeIncorrect, ); } else { + if !trait_pred.is_suggestable(tcx) { + return; + } // Trivial case: `T` needs an extra bound: `T: Bound`. let (sp, suggestion) = match ( generics @@ -463,16 +467,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => (false, None), }; - let generic_args_have_impl_trait = |args: SubstsRef<'tcx>| -> bool { - args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Type(ty) => match ty.kind() { - ty::Param(param) => param.name.as_str().starts_with("impl"), - _ => false, - }, - _ => false, - }) - }; - // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we // don't suggest `T: Sized + ?Sized`. let mut hir_id = body_id; @@ -574,6 +568,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | hir::Node::ImplItem(hir::ImplItem { generics, .. }) if param_ty => { + if !trait_pred.skip_binder().trait_ref.substs[1..] + .iter() + .all(|g| g.is_suggestable(self.tcx)) + { + return; + } // Missing generic type parameter bound. let param_name = self_ty.to_string(); let constraint = with_no_trimmed_paths!( @@ -603,13 +603,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { | hir::ItemKind::TraitAlias(generics, _) | hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), .. - }) if !param_ty - && !generic_args_have_impl_trait(trait_pred.skip_binder().trait_ref.substs) => - { + }) if !param_ty => { // Missing generic type parameter bound. - let param_name = self_ty.to_string(); - let constraint = trait_pred.print_modifiers_and_trait_path().to_string(); - if suggest_arbitrary_trait_bound(generics, &mut err, ¶m_name, &constraint) { + if suggest_arbitrary_trait_bound(self.tcx, generics, &mut err, trait_pred) { return; } } diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index 3fe4b5b46e0..60682aa3435 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -13,7 +13,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::GenericArg; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::ty::{ - self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, Ty, TyCtxt, + self, subst, subst::SubstsRef, GenericParamDef, GenericParamDefKind, IsSuggestable, Ty, TyCtxt, }; use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS; use rustc_span::{symbol::kw, Span}; diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 26e954b0026..b5025b794bb 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -27,7 +27,9 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef}; use rustc_middle::ty::GenericParamDefKind; -use rustc_middle::ty::{self, Const, DefIdTree, EarlyBinder, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{ + self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeFoldable, +}; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS}; use rustc_span::edition::Edition; use rustc_span::lev_distance::find_best_match_for_name; diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index ca55a4299eb..99c766d54c8 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -15,7 +15,7 @@ use rustc_infer::infer::{self, TyCtxtInferExt}; use rustc_infer::traits; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, Binder, ToPredicate, Ty}; +use rustc_middle::ty::{self, Binder, IsSuggestable, ToPredicate, Ty}; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index b65b7458fc1..5f6ddc1e1c9 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -817,11 +817,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait bound{s}", s = pluralize!(obligations.len()) ), - format!( - "{} {}", - add_where_or_comma, - obligations.join(", ") - ), + format!("{} {}", add_where_or_comma, obligations.join(", ")), Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index de40126e724..5a70dc1e594 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -39,7 +39,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::util::Discr; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, IsSuggestable, Ty, TyCtxt}; use rustc_middle::ty::{ReprOptions, ToPredicate}; use rustc_session::lint; use rustc_session::parse::feature_err; |
