diff options
| author | León Orell Valerian Liehr <me@fmease.dev> | 2024-06-15 21:34:44 +0200 |
|---|---|---|
| committer | León Orell Valerian Liehr <me@fmease.dev> | 2024-07-23 01:48:03 +0200 |
| commit | fdf8f024ad71c6e9c46867fb31b74df0fcaaf3f2 (patch) | |
| tree | 4734f3cd875a36318edf34f613728dfe1c99fe4d /compiler/rustc_lint/src/lints.rs | |
| parent | a8b3dfd25336dc12f17da23a0ed7004a4ebee234 (diff) | |
| download | rust-fdf8f024ad71c6e9c46867fb31b74df0fcaaf3f2.tar.gz rust-fdf8f024ad71c6e9c46867fb31b74df0fcaaf3f2.zip | |
Improve the impl and diag output of lint type_alias_bounds
Diffstat (limited to 'compiler/rustc_lint/src/lints.rs')
| -rw-r--r-- | compiler/rustc_lint/src/lints.rs | 148 |
1 files changed, 83 insertions, 65 deletions
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 6c5f366727f..6cf8b9330fc 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -9,7 +9,7 @@ use rustc_errors::{ ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, }; -use rustc_hir::{def::Namespace, def_id::DefId}; +use rustc_hir::{self as hir, def::Namespace, def_id::DefId}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{ inhabitedness::InhabitedPredicate, Clause, PolyExistentialTraitRef, Ty, TyCtxt, @@ -22,9 +22,7 @@ use rustc_span::{ Span, Symbol, }; -use crate::{ - builtin::InitError, builtin::TypeAliasBounds, errors::OverruledAttributeSub, LateContext, -}; +use crate::{builtin::InitError, errors::OverruledAttributeSub, LateContext}; // array_into_iter.rs #[derive(LintDiagnostic)] @@ -263,84 +261,104 @@ pub struct BuiltinUnreachablePub<'a> { pub help: Option<()>, } -pub struct SuggestChangingAssocTypes<'a, 'b> { - pub ty: &'a rustc_hir::Ty<'b>, +#[derive(LintDiagnostic)] +#[diag(lint_macro_expr_fragment_specifier_2024_migration)] +pub struct MacroExprFragment2024 { + #[suggestion(code = "expr_2021", applicability = "machine-applicable")] + pub suggestion: Span, +} + +#[derive(LintDiagnostic)] +pub enum BuiltinTypeAliasBounds<'a, 'hir> { + #[diag(lint_builtin_type_alias_bounds_where_clause)] + #[note(lint_builtin_type_alias_bounds_limitation_note)] + WhereClause { + #[label(lint_builtin_type_alias_bounds_label)] + label: Span, + #[help(lint_builtin_type_alias_bounds_enable_feat_help)] + enable_feat_help: Option<()>, + #[suggestion(code = "")] + suggestion: (Span, Applicability), + #[subdiagnostic] + qualify_assoc_tys_sugg: Option<TypeAliasBoundsQualifyAssocTysSugg<'a, 'hir>>, + }, + #[diag(lint_builtin_type_alias_bounds_param_bounds)] + #[note(lint_builtin_type_alias_bounds_limitation_note)] + ParamBounds { + #[label(lint_builtin_type_alias_bounds_label)] + label: Span, + #[help(lint_builtin_type_alias_bounds_enable_feat_help)] + enable_feat_help: Option<()>, + #[subdiagnostic] + suggestion: BuiltinTypeAliasParamBoundsSuggestion, + #[subdiagnostic] + qualify_assoc_tys_sugg: Option<TypeAliasBoundsQualifyAssocTysSugg<'a, 'hir>>, + }, +} + +pub struct BuiltinTypeAliasParamBoundsSuggestion { + pub suggestions: Vec<(Span, String)>, + pub applicability: Applicability, } -impl<'a, 'b> Subdiagnostic for SuggestChangingAssocTypes<'a, 'b> { +impl Subdiagnostic for BuiltinTypeAliasParamBoundsSuggestion { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, _f: &F, ) { - // Access to associates types should use `<T as Bound>::Assoc`, which does not need a - // bound. Let's see if this type does that. - - // We use a HIR visitor to walk the type. - use rustc_hir::intravisit::{self, Visitor}; - struct WalkAssocTypes<'a, 'b, G: EmissionGuarantee> { - err: &'a mut Diag<'b, G>, - } - impl<'a, 'b, G: EmissionGuarantee> Visitor<'_> for WalkAssocTypes<'a, 'b, G> { - fn visit_qpath( - &mut self, - qpath: &rustc_hir::QPath<'_>, - id: rustc_hir::HirId, - span: Span, - ) { - if TypeAliasBounds::is_type_variable_assoc(qpath) { - self.err.span_help(span, fluent::lint_builtin_type_alias_bounds_help); - } - intravisit::walk_qpath(self, qpath, id) - } - } - - // Let's go for a walk! - let mut visitor = WalkAssocTypes { err: diag }; - visitor.visit_ty(self.ty); + diag.arg("count", self.suggestions.len()); + diag.multipart_suggestion(fluent::lint_suggestion, self.suggestions, self.applicability); } } -#[derive(LintDiagnostic)] -#[diag(lint_builtin_type_alias_where_clause)] -pub struct BuiltinTypeAliasWhereClause<'a, 'b> { - #[suggestion(code = "", applicability = "machine-applicable")] - pub suggestion: Span, - #[subdiagnostic] - pub sub: Option<SuggestChangingAssocTypes<'a, 'b>>, -} - -#[derive(LintDiagnostic)] -#[diag(lint_builtin_type_alias_generic_bounds)] -pub struct BuiltinTypeAliasGenericBounds<'a, 'b> { - #[subdiagnostic] - pub suggestion: BuiltinTypeAliasGenericBoundsSuggestion, - #[subdiagnostic] - pub sub: Option<SuggestChangingAssocTypes<'a, 'b>>, -} - -#[derive(LintDiagnostic)] -#[diag(lint_macro_expr_fragment_specifier_2024_migration)] -pub struct MacroExprFragment2024 { - #[suggestion(code = "expr_2021", applicability = "machine-applicable")] - pub suggestion: Span, +pub struct TypeAliasBoundsQualifyAssocTysSugg<'a, 'hir> { + pub ty: &'a hir::Ty<'hir>, } -pub struct BuiltinTypeAliasGenericBoundsSuggestion { - pub suggestions: Vec<(Span, String)>, -} - -impl Subdiagnostic for BuiltinTypeAliasGenericBoundsSuggestion { +impl<'a, 'hir> Subdiagnostic for TypeAliasBoundsQualifyAssocTysSugg<'a, 'hir> { fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( self, diag: &mut Diag<'_, G>, _f: &F, ) { - diag.multipart_suggestion( - fluent::lint_suggestion, - self.suggestions, - Applicability::MachineApplicable, - ); + // We perform the walk in here instead of in `<TypeAliasBounds as LateLintPass>` to + // avoid doing throwaway work in case the lint ends up getting suppressed. + + use hir::intravisit::Visitor; + struct ProbeShorthandAssocTys<'a, 'b, G: EmissionGuarantee> { + diag: &'a mut Diag<'b, G>, + } + impl<'a, 'b, G: EmissionGuarantee> Visitor<'_> for ProbeShorthandAssocTys<'a, 'b, G> { + fn visit_qpath(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, _: Span) { + // Look for "type-parameter shorthand-associated-types". I.e., paths of the + // form `T::Assoc` with `T` type param. These are reliant on trait bounds. + // Suggest fully qualifying them via `<T as /* Trait */>::Assoc`. + // + // Instead of attempting to figure out the necessary trait ref, just use a + // placeholder. Since we don't record type-dependent resolutions for non-body + // items like type aliases, we can't simply deduce the corresp. trait from + // the HIR path alone without rerunning parts of HIR ty lowering here + // (namely `probe_single_ty_param_bound_for_assoc_ty`) which is infeasible. + // + // (We could employ some simple heuristics but that's likely not worth it). + if let hir::QPath::TypeRelative(qself, _) = qpath + && let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = qself.kind + && let hir::def::Res::Def(hir::def::DefKind::TyParam, _) = path.res + { + self.diag.multipart_suggestion( + fluent::lint_builtin_type_alias_bounds_qualify_assoc_tys_sugg, + vec![ + (qself.span.shrink_to_lo(), "<".into()), + (qself.span.shrink_to_hi(), " as /* Trait */>".into()), + ], + Applicability::HasPlaceholders, + ); + } + hir::intravisit::walk_qpath(self, qpath, id) + } + } + ProbeShorthandAssocTys { diag }.visit_ty(self.ty); } } |
