diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 25a82b22707cc..97b8557b95ef6 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -384,7 +384,6 @@ pub enum StashKey { /// FRU syntax MaybeFruTypo, CallAssocMethod, - AssociatedTypeSuggestion, UndeterminedMacroResolution, /// Used by `Parser::maybe_recover_trailing_expr` ExprInPat, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index a3cba8ce15fda..9123afd5986f5 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -2,10 +2,7 @@ use rustc_ast::TraitObjectSyntax; use rustc_attr_ir::lang_items::LangItem; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; -use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, Diagnostic, Level, StashKey, Suggestions, - struct_span_code_err, -}; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level, struct_span_code_err}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, HirId}; @@ -17,6 +14,7 @@ use rustc_middle::ty::{ }; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{ErrorGuaranteed, Span}; +use rustc_trait_selection::diagnostics::AssocTypeWithSameName; use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; use rustc_trait_selection::traits; @@ -655,15 +653,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { poly_trait_ref.trait_ref.trait_def_id(), &mut diag, ); - // In case there is an associated type with the same name - // Add the suggestion to this error - if let Some(mut sugg) = - self.dcx().steal_non_err(span, StashKey::AssociatedTypeSuggestion) - && let Suggestions::Enabled(ref mut s1) = diag.suggestions - && let Suggestions::Enabled(ref mut s2) = sugg.suggestions + // If there is an associated type with the same name, add the suggestion to this error. + if self + .tcx() + .resolutions(()) + .paths_matching_assoc_types + .contains(&span.with_parent(None)) { - s1.append(s2); - sugg.cancel(); + diag.subdiagnostic(AssocTypeWithSameName { span: span.shrink_to_lo() }); } Some(diag.emit_err()) } else { diff --git a/compiler/rustc_middle/src/middle/resolve.rs b/compiler/rustc_middle/src/middle/resolve.rs index 8267cde89ad27..491fec97db6c1 100644 --- a/compiler/rustc_middle/src/middle/resolve.rs +++ b/compiler/rustc_middle/src/middle/resolve.rs @@ -180,6 +180,9 @@ pub struct ResolverGlobalCtxt { /// A list of proc macro LocalDefIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. pub proc_macros: Vec, + /// Path spans where the ident matches an associated type for an enclosing trait. Used to + /// improve certain error messages. + pub paths_matching_assoc_types: UnordSet, /// Mapping from ident span to path span for paths that don't exist as written, but that /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. pub confused_type_with_std_module: FxIndexMap, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 8c4a9babe2213..cb6642a696504 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -22,7 +22,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, Diagnostic, ErrorGuaranteed, IntoDiagArg, MultiSpan, - StashKey, Suggestions, elided_lifetime_in_path_suggestion, pluralize, + Suggestions, elided_lifetime_in_path_suggestion, pluralize, }; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{CtorKind, DefKind, NonMacroAttrKind, PerNS}; @@ -4823,7 +4823,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { source, ) { Ok(Some(partial_res)) if let Some(res) = partial_res.full_res() => { - // if we also have an associated type that matches the ident, stash a suggestion + // If we also have an associated type that matches the ident, record that. if let Some(items) = self.diag_metadata.current_trait_assoc_items && let [Segment { ident, .. }] = path && items.iter().any(|item| { @@ -4836,14 +4836,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } }) { - let mut diag = self.r.tcx.dcx().struct_allow(""); - diag.span_suggestion_verbose( - path_span.shrink_to_lo(), - "there is an associated type with the same name", - "Self::", - Applicability::MaybeIncorrect, - ); - diag.stash(path_span, StashKey::AssociatedTypeSuggestion); + self.r.paths_matching_assoc_types.insert(path_span.with_parent(None)); } if source.is_expected(res) || res == Res::Err { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 7c80a892fa131..a913149733614 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1529,6 +1529,7 @@ pub struct Resolver<'ra, 'tcx> { /// A list of proc macro LocalDefIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. proc_macros: Vec = Vec::new(), + paths_matching_assoc_types: UnordSet, confused_type_with_std_module: FxIndexMap, /// Names of items that were stripped out via cfg with their corresponding cfg meta item. @@ -1892,6 +1893,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { invocation_parents, trait_impls: Default::default(), confused_type_with_std_module: Default::default(), + paths_matching_assoc_types: Default::default(), stripped_cfg_items: Default::default(), effective_visibilities: Default::default(), macro_reachable_adts: Default::default(), @@ -1970,6 +1972,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let glob_map = self.glob_map; let main_def = self.main_def; let confused_type_with_std_module = self.confused_type_with_std_module; + let paths_matching_assoc_types = self.paths_matching_assoc_types; let effective_visibilities = self.effective_visibilities; let stripped_cfg_items = self @@ -2000,6 +2003,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { trait_impls: self.trait_impls, proc_macros, confused_type_with_std_module, + paths_matching_assoc_types, doc_link_resolutions: self.doc_link_resolutions, doc_link_traits_in_scope: self.doc_link_traits_in_scope, all_macro_rules: self.all_macro_rules, diff --git a/compiler/rustc_trait_selection/src/diagnostics.rs b/compiler/rustc_trait_selection/src/diagnostics.rs index 4b7be976cdb30..80ffbba041ccd 100644 --- a/compiler/rustc_trait_selection/src/diagnostics.rs +++ b/compiler/rustc_trait_selection/src/diagnostics.rs @@ -2083,3 +2083,15 @@ pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> { }")] pub param_span: Span, } + +#[derive(Subdiagnostic)] +#[suggestion( + "there is an associated type with the same name", + style = "verbose", + code = "Self::", + applicability = "maybe-incorrect" +)] +pub struct AssocTypeWithSameName { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 4cb5465b5bbee..062b087413e4f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -13,8 +13,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, StringPart, Sublevel, Suggestions, - msg, pluralize, struct_span_code_err, + Applicability, Diag, ErrorGuaranteed, MultiSpan, StringPart, Sublevel, msg, pluralize, + struct_span_code_err, }; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::intravisit::Visitor; @@ -42,7 +42,8 @@ use tracing::{debug, instrument}; use super::suggestions::get_explanation_based_on_obligation; use super::{ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate}; use crate::diagnostics::{ - ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, CoroClosureNotFn, + AssocTypeWithSameName, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, + CoroClosureNotFn, }; use crate::error_reporting::TypeErrCtxt; use crate::error_reporting::infer::TyCategory; @@ -3107,13 +3108,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); self.suggest_unsized_bound_if_applicable(err, obligation); if let Some(span) = err.span.primary_span() - && let Some(mut diag) = - self.dcx().steal_non_err(span, StashKey::AssociatedTypeSuggestion) - && let Suggestions::Enabled(ref mut s1) = err.suggestions - && let Suggestions::Enabled(ref mut s2) = diag.suggestions + && self + .tcx + .resolutions(()) + .paths_matching_assoc_types + .contains(&span.with_parent(None)) { - s1.append(s2); - diag.cancel() + err.subdiagnostic(AssocTypeWithSameName { span: span.shrink_to_lo() }); } } }