From 33b9b9530561ada2584c8a9239e6581fef216a2a Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 4 Oct 2021 15:57:39 -0500 Subject: [PATCH 1/3] Introduce get_diagnostic_name --- compiler/rustc_hir/src/diagnostic_items.rs | 17 ++++++++++ compiler/rustc_hir/src/lib.rs | 1 + compiler/rustc_metadata/src/rmeta/decoder.rs | 16 ++++++--- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 4 +-- compiler/rustc_middle/src/ty/context.rs | 9 +++-- compiler/rustc_passes/src/diagnostic_items.rs | 34 ++++++++----------- .../src/traits/error_reporting/suggestions.rs | 8 ++--- .../rustc_typeck/src/check/method/suggest.rs | 2 +- 9 files changed, 59 insertions(+), 34 deletions(-) create mode 100644 compiler/rustc_hir/src/diagnostic_items.rs diff --git a/compiler/rustc_hir/src/diagnostic_items.rs b/compiler/rustc_hir/src/diagnostic_items.rs new file mode 100644 index 0000000000000..243014b002703 --- /dev/null +++ b/compiler/rustc_hir/src/diagnostic_items.rs @@ -0,0 +1,17 @@ +use crate::def_id::DefId; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_span::Symbol; + +#[derive(Debug, Default)] +pub struct DiagnosticItems { + pub id_to_name: FxHashMap, + pub name_to_id: FxHashMap, +} + +impl HashStable for DiagnosticItems { + #[inline] + fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { + self.name_to_id.hash_stable(ctx, hasher); + } +} diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index ce36648d6df11..f5ea044e24865 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -18,6 +18,7 @@ mod arena; pub mod def; pub mod def_path_hash_map; pub mod definitions; +pub mod diagnostic_items; pub use rustc_span::def_id; mod hir; pub mod hir_id; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 08fc11f21d94e..c7d0f594f0117 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -18,6 +18,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; +use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::lang_items; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::hir::exports::Export; @@ -1052,16 +1053,23 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } /// Iterates over the diagnostic items in the given crate. - fn get_diagnostic_items(&self) -> FxHashMap { + fn get_diagnostic_items(&self) -> DiagnosticItems { if self.root.is_proc_macro_crate() { // Proc macro crates do not export any diagnostic-items to the target. Default::default() } else { - self.root + let mut id_to_name = FxHashMap::default(); + let name_to_id = self + .root .diagnostic_items .decode(self) - .map(|(name, def_index)| (name, self.local_def_id(def_index))) - .collect() + .map(|(name, def_index)| { + let id = self.local_def_id(def_index); + id_to_name.insert(id, name); + (name, id) + }) + .collect(); + DiagnosticItems { id_to_name, name_to_id } } } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 072398983afb9..dacb1e4029c20 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1750,7 +1750,7 @@ impl EncodeContext<'a, 'tcx> { fn encode_diagnostic_items(&mut self) -> Lazy<[(Symbol, DefIndex)]> { empty_proc_macro!(self); let tcx = self.tcx; - let diagnostic_items = tcx.diagnostic_items(LOCAL_CRATE); + let diagnostic_items = &tcx.diagnostic_items(LOCAL_CRATE).name_to_id; self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index))) } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index b4f7a9fa8e9d6..9b0b1377875d1 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1442,7 +1442,7 @@ rustc_queries! { } /// Returns all diagnostic items defined in all crates. - query all_diagnostic_items(_: ()) -> FxHashMap { + query all_diagnostic_items(_: ()) -> rustc_hir::diagnostic_items::DiagnosticItems { storage(ArenaCacheSelector<'tcx>) eval_always desc { "calculating the diagnostic items map" } @@ -1454,7 +1454,7 @@ rustc_queries! { } /// Returns the diagnostic items defined in a crate. - query diagnostic_items(_: CrateNum) -> FxHashMap { + query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems { storage(ArenaCacheSelector<'tcx>) desc { "calculating the diagnostic items map in a crate" } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 080e2fef203b8..6a6fb30dce837 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1232,12 +1232,17 @@ impl<'tcx> TyCtxt<'tcx> { /// Obtain the given diagnostic item's `DefId`. Use `is_diagnostic_item` if you just want to /// compare against another `DefId`, since `is_diagnostic_item` is cheaper. pub fn get_diagnostic_item(self, name: Symbol) -> Option { - self.all_diagnostic_items(()).get(&name).copied() + self.all_diagnostic_items(()).name_to_id.get(&name).copied() + } + + /// Obtain the diagnostic item's name + pub fn get_diagnostic_name(self, id: DefId) -> Option { + self.diagnostic_items(id.krate).id_to_name.get(&id).copied() } /// Check whether the diagnostic item with the given `name` has the given `DefId`. pub fn is_diagnostic_item(self, name: Symbol, did: DefId) -> bool { - self.diagnostic_items(did.krate).get(&name) == Some(&did) + self.diagnostic_items(did.krate).name_to_id.get(&name) == Some(&did) } pub fn stability(self) -> &'tcx stability::Index<'tcx> { diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index d35a1cc293ecf..30a0071f0f2e5 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -10,8 +10,8 @@ //! * Compiler internal types like `Ty` and `TyCtxt` use rustc_ast as ast; -use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; +use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; @@ -19,9 +19,8 @@ use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_span::symbol::{sym, Symbol}; struct DiagnosticItemCollector<'tcx> { - // items from this crate - items: FxHashMap, tcx: TyCtxt<'tcx>, + diagnostic_items: DiagnosticItems, } impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> { @@ -44,7 +43,7 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for DiagnosticItemCollector<'tcx> { impl<'tcx> DiagnosticItemCollector<'tcx> { fn new(tcx: TyCtxt<'tcx>) -> DiagnosticItemCollector<'tcx> { - DiagnosticItemCollector { tcx, items: Default::default() } + DiagnosticItemCollector { tcx, diagnostic_items: DiagnosticItems::default() } } fn observe_item(&mut self, def_id: LocalDefId) { @@ -52,19 +51,14 @@ impl<'tcx> DiagnosticItemCollector<'tcx> { let attrs = self.tcx.hir().attrs(hir_id); if let Some(name) = extract(attrs) { // insert into our table - collect_item(self.tcx, &mut self.items, name, def_id.to_def_id()); + collect_item(self.tcx, &mut self.diagnostic_items, name, def_id.to_def_id()); } } } -fn collect_item( - tcx: TyCtxt<'_>, - items: &mut FxHashMap, - name: Symbol, - item_def_id: DefId, -) { - // Check for duplicates. - if let Some(original_def_id) = items.insert(name, item_def_id) { +fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item_def_id: DefId) { + items.id_to_name.insert(item_def_id, name); + if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) { if original_def_id != item_def_id { let mut err = match tcx.hir().span_if_local(item_def_id) { Some(span) => tcx.sess.struct_span_err( @@ -98,7 +92,7 @@ fn extract(attrs: &[ast::Attribute]) -> Option { } /// Traverse and collect the diagnostic items in the current -fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> FxHashMap { +fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> DiagnosticItems { assert_eq!(cnum, LOCAL_CRATE); // Initialize the collector. @@ -107,22 +101,22 @@ fn diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, cnum: CrateNum) -> FxHashMap(tcx: TyCtxt<'tcx>, (): ()) -> FxHashMap { +fn all_diagnostic_items<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> DiagnosticItems { // Initialize the collector. - let mut collector = FxHashMap::default(); + let mut items = DiagnosticItems::default(); // Collect diagnostic items in other crates. for &cnum in tcx.crates(()).iter().chain(std::iter::once(&LOCAL_CRATE)) { - for (&name, &def_id) in tcx.diagnostic_items(cnum).iter() { - collect_item(tcx, &mut collector, name, def_id); + for (&name, &def_id) in &tcx.diagnostic_items(cnum).name_to_id { + collect_item(tcx, &mut items, name, def_id); } } - collector + items } pub fn provide(providers: &mut Providers) { 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 cd678b9644622..a73d2285d4576 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1636,12 +1636,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // Special case the primary error message when send or sync is the trait that was // not implemented. - let is_send = self.tcx.is_diagnostic_item(sym::Send, trait_ref.def_id); - let is_sync = self.tcx.is_diagnostic_item(sym::Sync, trait_ref.def_id); let hir = self.tcx.hir(); - let trait_explanation = if is_send || is_sync { + let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) = + self.tcx.get_diagnostic_name(trait_ref.def_id) + { let (trait_name, trait_verb) = - if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; + if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; err.clear_code(); err.set_primary_message(format!( diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 8c7ec2194644b..41281a6748f08 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1076,7 +1076,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if adt_def.did.is_local() { let diagnostic_items = self.tcx.diagnostic_items(trait_ref.def_id.krate); return derivables.iter().find_map(|trait_derivable| { - let item_def_id = diagnostic_items.get(trait_derivable)?; + let item_def_id = diagnostic_items.name_to_id.get(trait_derivable)?; if item_def_id == &trait_pred.trait_ref.def_id && !(adt_def.is_enum() && *trait_derivable == sym::Default) { From b6cab80c181e0212966017c0abe1c3e08b50f5d4 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 4 Oct 2021 16:11:22 -0500 Subject: [PATCH 2/3] Use get_diagnostic_name --- compiler/rustc_lint/src/builtin.rs | 28 +++-- compiler/rustc_lint/src/internal.rs | 31 ++--- compiler/rustc_lint/src/non_fmt_panic.rs | 7 +- compiler/rustc_lint/src/noop_method_call.rs | 7 +- compiler/rustc_lint/src/types.rs | 3 +- .../rustc_typeck/src/check/method/suggest.rs | 110 ++++++------------ 6 files changed, 73 insertions(+), 113 deletions(-) diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5656fff2fcb72..57c1c8f3ecb5c 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2478,14 +2478,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { // Find calls to `mem::{uninitialized,zeroed}` methods. if let hir::ExprKind::Path(ref qpath) = path_expr.kind { let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?; - - if cx.tcx.is_diagnostic_item(sym::mem_zeroed, def_id) { - return Some(InitKind::Zeroed); - } else if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, def_id) { - return Some(InitKind::Uninit); - } else if cx.tcx.is_diagnostic_item(sym::transmute, def_id) && is_zero(&args[0]) - { - return Some(InitKind::Zeroed); + match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::mem_zeroed) => return Some(InitKind::Zeroed), + Some(sym::mem_uninitialized) => return Some(InitKind::Uninit), + Some(sym::transmute) if is_zero(&args[0]) => return Some(InitKind::Zeroed), + _ => {} } } } else if let hir::ExprKind::MethodCall(_, _, ref args, _) = expr.kind { @@ -2497,11 +2494,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind { if let hir::ExprKind::Path(ref qpath) = path_expr.kind { let def_id = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id()?; - - if cx.tcx.is_diagnostic_item(sym::maybe_uninit_zeroed, def_id) { - return Some(InitKind::Zeroed); - } else if cx.tcx.is_diagnostic_item(sym::maybe_uninit_uninit, def_id) { - return Some(InitKind::Uninit); + match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::maybe_uninit_zeroed) => return Some(InitKind::Zeroed), + Some(sym::maybe_uninit_uninit) => return Some(InitKind::Uninit), + _ => {} } } } @@ -3091,8 +3087,10 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr { rustc_hir::ExprKind::Call(ref path, _) => { if let rustc_hir::ExprKind::Path(ref qpath) = path.kind { if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() { - return cx.tcx.is_diagnostic_item(sym::ptr_null, def_id) - || cx.tcx.is_diagnostic_item(sym::ptr_null_mut, def_id); + return matches!( + cx.tcx.get_diagnostic_name(def_id), + Some(sym::ptr_null | sym::ptr_null_mut) + ); } } } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index a4940e5aae7a7..50a0d211a366a 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -33,12 +33,10 @@ impl LateLintPass<'_> for DefaultHashTypes { // don't lint imports, only actual usages return; } - let replace = if cx.tcx.is_diagnostic_item(sym::HashMap, def_id) { - "FxHashMap" - } else if cx.tcx.is_diagnostic_item(sym::HashSet, def_id) { - "FxHashSet" - } else { - return; + let replace = match cx.tcx.get_diagnostic_name(def_id) { + Some(sym::HashMap) => "FxHashMap", + Some(sym::HashSet) => "FxHashSet", + _ => return, }; cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| { let msg = format!( @@ -174,26 +172,29 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option { if let TyKind::Path(qpath) = &ty.kind { if let QPath::Resolved(_, path) = qpath { match path.res { - Res::Def(_, did) => { - if cx.tcx.is_diagnostic_item(sym::Ty, did) { - return Some(format!("Ty{}", gen_args(path.segments.last().unwrap()))); - } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, did) { - return Some(format!("TyCtxt{}", gen_args(path.segments.last().unwrap()))); + Res::Def(_, def_id) => { + if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id) + { + return Some(format!( + "{}{}", + name, + gen_args(path.segments.last().unwrap()) + )); } } // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait. Res::SelfTy(None, Some((did, _))) => { if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() { - if cx.tcx.is_diagnostic_item(sym::Ty, adt.did) { + if let Some(name @ (sym::Ty | sym::TyCtxt)) = + cx.tcx.get_diagnostic_name(adt.did) + { // NOTE: This path is currently unreachable as `Ty<'tcx>` is // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>` // is not actually allowed. // // I(@lcnr) still kept this branch in so we don't miss this // if we ever change it in the future. - return Some(format!("Ty<{}>", substs[0])); - } else if cx.tcx.is_diagnostic_item(sym::TyCtxt, adt.did) { - return Some(format!("TyCtxt<{}>", substs[0])); + return Some(format!("{}<{}>", name, substs[0])); } } } diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index b945c764320e3..103555a67524f 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -54,9 +54,10 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt { || Some(def_id) == cx.tcx.lang_items().panic_str() { if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id { - if cx.tcx.is_diagnostic_item(sym::std_panic_2015_macro, id) - || cx.tcx.is_diagnostic_item(sym::core_panic_2015_macro, id) - { + if matches!( + cx.tcx.get_diagnostic_name(id), + Some(sym::core_panic_2015_macro | sym::std_panic_2015_macro) + ) { check_panic(cx, f, arg); } } diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index c14f16b6d11ba..d2c970468abc7 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -51,9 +51,10 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) { // Check that we're dealing with a trait method for one of the traits we care about. Some(trait_id) - if [sym::Clone, sym::Deref, sym::Borrow] - .iter() - .any(|s| cx.tcx.is_diagnostic_item(*s, trait_id)) => + if matches!( + cx.tcx.get_diagnostic_name(trait_id), + Some(sym::Borrow | sym::Clone | sym::Deref) + ) => { (trait_id, did) } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index ac4bffc239b03..708cd56e068b5 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1541,8 +1541,7 @@ impl InvalidAtomicOrdering { if let ExprKind::Call(ref func, ref args) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if cx.tcx.is_diagnostic_item(sym::fence, def_id) || - cx.tcx.is_diagnostic_item(sym::compiler_fence, def_id); + if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence)); if let ExprKind::Path(ref ordering_qpath) = &args[0].kind; if let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id(); if Self::matches_ordering(cx, ordering_def_id, &[sym::Relaxed]); diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 41281a6748f08..183ebc559ae42 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -1047,51 +1047,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err: &mut DiagnosticBuilder<'_>, unsatisfied_predicates: &Vec<(ty::Predicate<'tcx>, Option>)>, ) { - let derivables = [ - sym::Eq, - sym::PartialEq, - sym::Ord, - sym::PartialOrd, - sym::Clone, - sym::Copy, - sym::Hash, - sym::Default, - sym::Debug, - ]; - let mut derives = unsatisfied_predicates - .iter() - .filter_map(|(pred, _)| { - let trait_pred = - if let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder() { - trait_pred - } else { - return None; - }; - let trait_ref = trait_pred.trait_ref; - let adt_def = if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() { - adt_def - } else { - return None; - }; - if adt_def.did.is_local() { - let diagnostic_items = self.tcx.diagnostic_items(trait_ref.def_id.krate); - return derivables.iter().find_map(|trait_derivable| { - let item_def_id = diagnostic_items.name_to_id.get(trait_derivable)?; - if item_def_id == &trait_pred.trait_ref.def_id - && !(adt_def.is_enum() && *trait_derivable == sym::Default) - { - return Some(( - format!("{}", trait_ref.self_ty()), - self.tcx.def_span(adt_def.did), - format!("{}", trait_ref.print_only_trait_name()), - )); - } - None - }); - } - None - }) - .collect::>(); + let mut derives = Vec::<(String, Span, String)>::new(); + let mut traits = Vec::::new(); + for (pred, _) in unsatisfied_predicates { + let trait_pred = match pred.kind().skip_binder() { + ty::PredicateKind::Trait(trait_pred) => trait_pred, + _ => continue, + }; + let adt = match trait_pred.self_ty().ty_adt_def() { + Some(adt) if adt.did.is_local() => adt, + _ => continue, + }; + let can_derive = match self.tcx.get_diagnostic_name(trait_pred.def_id()) { + Some(sym::Default) => !adt.is_enum(), + Some( + sym::Eq + | sym::PartialEq + | sym::Ord + | sym::PartialOrd + | sym::Clone + | sym::Copy + | sym::Hash + | sym::Debug, + ) => true, + _ => false, + }; + if can_derive { + derives.push(( + format!("{}", trait_pred.self_ty()), + self.tcx.def_span(adt.did), + format!("{}", trait_pred.trait_ref.print_only_trait_name()), + )); + } else { + traits.push(self.tcx.def_span(trait_pred.def_id())); + } + } derives.sort(); let derives_grouped = derives.into_iter().fold( Vec::<(String, Span, String)>::new(), @@ -1106,36 +1096,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { acc }, ); - let mut traits: Vec<_> = unsatisfied_predicates - .iter() - .filter_map(|(pred, _)| { - let trait_pred = - if let ty::PredicateKind::Trait(trait_pred) = pred.kind().skip_binder() { - trait_pred - } else { - return None; - }; - if let ty::Adt(adt_def, _) = trait_pred.trait_ref.self_ty().kind() { - if !adt_def.did.is_local() { - return None; - } - } else { - return None; - }; - - let did = trait_pred.def_id(); - let diagnostic_items = self.tcx.diagnostic_items(did.krate); - - if !derivables - .iter() - .any(|trait_derivable| diagnostic_items.get(trait_derivable) == Some(&did)) - { - Some(self.tcx.def_span(did)) - } else { - None - } - }) - .collect(); traits.sort(); traits.dedup(); From a8d8bfd3763cfde5a27dc7babd6691f1b3d65840 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Wed, 6 Oct 2021 14:00:40 -0500 Subject: [PATCH 3/3] Bless tests --- .../suggestions/derive-trait-for-method-call.stderr | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/ui/suggestions/derive-trait-for-method-call.stderr b/src/test/ui/suggestions/derive-trait-for-method-call.stderr index 97fc1134a9477..2af3ba1d5bb9c 100644 --- a/src/test/ui/suggestions/derive-trait-for-method-call.stderr +++ b/src/test/ui/suggestions/derive-trait-for-method-call.stderr @@ -20,6 +20,17 @@ LL | let y = x.test(); `Enum: Clone` `Enum: Default` `CloneEnum: Default` +note: the following trait must be implemented + --> $SRC_DIR/core/src/default.rs:LL:COL + | +LL | / pub trait Default: Sized { +LL | | /// Returns the "default value" for a type. +LL | | /// +LL | | /// Default values are often some kind of initial value, identity value, or anything else that +... | +LL | | fn default() -> Self; +LL | | } + | |_^ help: consider annotating `Enum` with `#[derive(Clone)]` | LL | #[derive(Clone)]