@@ -9,7 +9,7 @@ use rustc_errors::{
99 ElidedLifetimeInPathSubdiag , EmissionGuarantee , LintDiagnostic , MultiSpan , SubdiagMessageOp ,
1010 Subdiagnostic , SuggestionStyle ,
1111} ;
12- use rustc_hir:: { def:: Namespace , def_id:: DefId } ;
12+ use rustc_hir:: { self as hir , def:: Namespace , def_id:: DefId } ;
1313use rustc_macros:: { LintDiagnostic , Subdiagnostic } ;
1414use rustc_middle:: ty:: {
1515 inhabitedness:: InhabitedPredicate , Clause , PolyExistentialTraitRef , Ty , TyCtxt ,
@@ -22,9 +22,7 @@ use rustc_span::{
2222 Span , Symbol ,
2323} ;
2424
25- use crate :: {
26- builtin:: InitError , builtin:: TypeAliasBounds , errors:: OverruledAttributeSub , LateContext ,
27- } ;
25+ use crate :: { builtin:: InitError , errors:: OverruledAttributeSub , LateContext } ;
2826
2927// array_into_iter.rs
3028#[ derive( LintDiagnostic ) ]
@@ -263,84 +261,104 @@ pub struct BuiltinUnreachablePub<'a> {
263261 pub help : Option < ( ) > ,
264262}
265263
266- pub struct SuggestChangingAssocTypes < ' a , ' b > {
267- pub ty : & ' a rustc_hir:: Ty < ' b > ,
264+ #[ derive( LintDiagnostic ) ]
265+ #[ diag( lint_macro_expr_fragment_specifier_2024_migration) ]
266+ pub struct MacroExprFragment2024 {
267+ #[ suggestion( code = "expr_2021" , applicability = "machine-applicable" ) ]
268+ pub suggestion : Span ,
269+ }
270+
271+ #[ derive( LintDiagnostic ) ]
272+ pub enum BuiltinTypeAliasBounds < ' a , ' hir > {
273+ #[ diag( lint_builtin_type_alias_bounds_where_clause) ]
274+ #[ note( lint_builtin_type_alias_bounds_limitation_note) ]
275+ WhereClause {
276+ #[ label( lint_builtin_type_alias_bounds_label) ]
277+ label : Span ,
278+ #[ help( lint_builtin_type_alias_bounds_enable_feat_help) ]
279+ enable_feat_help : Option < ( ) > ,
280+ #[ suggestion( code = "" ) ]
281+ suggestion : ( Span , Applicability ) ,
282+ #[ subdiagnostic]
283+ qualify_assoc_tys_sugg : Option < TypeAliasBoundsQualifyAssocTysSugg < ' a , ' hir > > ,
284+ } ,
285+ #[ diag( lint_builtin_type_alias_bounds_param_bounds) ]
286+ #[ note( lint_builtin_type_alias_bounds_limitation_note) ]
287+ ParamBounds {
288+ #[ label( lint_builtin_type_alias_bounds_label) ]
289+ label : Span ,
290+ #[ help( lint_builtin_type_alias_bounds_enable_feat_help) ]
291+ enable_feat_help : Option < ( ) > ,
292+ #[ subdiagnostic]
293+ suggestion : BuiltinTypeAliasParamBoundsSuggestion ,
294+ #[ subdiagnostic]
295+ qualify_assoc_tys_sugg : Option < TypeAliasBoundsQualifyAssocTysSugg < ' a , ' hir > > ,
296+ } ,
297+ }
298+
299+ pub struct BuiltinTypeAliasParamBoundsSuggestion {
300+ pub suggestions : Vec < ( Span , String ) > ,
301+ pub applicability : Applicability ,
268302}
269303
270- impl < ' a , ' b > Subdiagnostic for SuggestChangingAssocTypes < ' a , ' b > {
304+ impl Subdiagnostic for BuiltinTypeAliasParamBoundsSuggestion {
271305 fn add_to_diag_with < G : EmissionGuarantee , F : SubdiagMessageOp < G > > (
272306 self ,
273307 diag : & mut Diag < ' _ , G > ,
274308 _f : & F ,
275309 ) {
276- // Access to associates types should use `<T as Bound>::Assoc`, which does not need a
277- // bound. Let's see if this type does that.
278-
279- // We use a HIR visitor to walk the type.
280- use rustc_hir:: intravisit:: { self , Visitor } ;
281- struct WalkAssocTypes < ' a , ' b , G : EmissionGuarantee > {
282- err : & ' a mut Diag < ' b , G > ,
283- }
284- impl < ' a , ' b , G : EmissionGuarantee > Visitor < ' _ > for WalkAssocTypes < ' a , ' b , G > {
285- fn visit_qpath (
286- & mut self ,
287- qpath : & rustc_hir:: QPath < ' _ > ,
288- id : rustc_hir:: HirId ,
289- span : Span ,
290- ) {
291- if TypeAliasBounds :: is_type_variable_assoc ( qpath) {
292- self . err . span_help ( span, fluent:: lint_builtin_type_alias_bounds_help) ;
293- }
294- intravisit:: walk_qpath ( self , qpath, id)
295- }
296- }
297-
298- // Let's go for a walk!
299- let mut visitor = WalkAssocTypes { err : diag } ;
300- visitor. visit_ty ( self . ty ) ;
310+ diag. arg ( "count" , self . suggestions . len ( ) ) ;
311+ diag. multipart_suggestion ( fluent:: lint_suggestion, self . suggestions , self . applicability ) ;
301312 }
302313}
303314
304- #[ derive( LintDiagnostic ) ]
305- #[ diag( lint_builtin_type_alias_where_clause) ]
306- pub struct BuiltinTypeAliasWhereClause < ' a , ' b > {
307- #[ suggestion( code = "" , applicability = "machine-applicable" ) ]
308- pub suggestion : Span ,
309- #[ subdiagnostic]
310- pub sub : Option < SuggestChangingAssocTypes < ' a , ' b > > ,
311- }
312-
313- #[ derive( LintDiagnostic ) ]
314- #[ diag( lint_builtin_type_alias_generic_bounds) ]
315- pub struct BuiltinTypeAliasGenericBounds < ' a , ' b > {
316- #[ subdiagnostic]
317- pub suggestion : BuiltinTypeAliasGenericBoundsSuggestion ,
318- #[ subdiagnostic]
319- pub sub : Option < SuggestChangingAssocTypes < ' a , ' b > > ,
320- }
321-
322- #[ derive( LintDiagnostic ) ]
323- #[ diag( lint_macro_expr_fragment_specifier_2024_migration) ]
324- pub struct MacroExprFragment2024 {
325- #[ suggestion( code = "expr_2021" , applicability = "machine-applicable" ) ]
326- pub suggestion : Span ,
315+ pub struct TypeAliasBoundsQualifyAssocTysSugg < ' a , ' hir > {
316+ pub ty : & ' a hir:: Ty < ' hir > ,
327317}
328318
329- pub struct BuiltinTypeAliasGenericBoundsSuggestion {
330- pub suggestions : Vec < ( Span , String ) > ,
331- }
332-
333- impl Subdiagnostic for BuiltinTypeAliasGenericBoundsSuggestion {
319+ impl < ' a , ' hir > Subdiagnostic for TypeAliasBoundsQualifyAssocTysSugg < ' a , ' hir > {
334320 fn add_to_diag_with < G : EmissionGuarantee , F : SubdiagMessageOp < G > > (
335321 self ,
336322 diag : & mut Diag < ' _ , G > ,
337323 _f : & F ,
338324 ) {
339- diag. multipart_suggestion (
340- fluent:: lint_suggestion,
341- self . suggestions ,
342- Applicability :: MachineApplicable ,
343- ) ;
325+ // We perform the walk in here instead of in `<TypeAliasBounds as LateLintPass>` to
326+ // avoid doing throwaway work in case the lint ends up getting suppressed.
327+
328+ use hir:: intravisit:: Visitor ;
329+ struct ProbeShorthandAssocTys < ' a , ' b , G : EmissionGuarantee > {
330+ diag : & ' a mut Diag < ' b , G > ,
331+ }
332+ impl < ' a , ' b , G : EmissionGuarantee > Visitor < ' _ > for ProbeShorthandAssocTys < ' a , ' b , G > {
333+ fn visit_qpath ( & mut self , qpath : & hir:: QPath < ' _ > , id : hir:: HirId , _: Span ) {
334+ // Look for "type-parameter shorthand-associated-types". I.e., paths of the
335+ // form `T::Assoc` with `T` type param. These are reliant on trait bounds.
336+ // Suggest fully qualifying them via `<T as /* Trait */>::Assoc`.
337+ //
338+ // Instead of attempting to figure out the necessary trait ref, just use a
339+ // placeholder. Since we don't record type-dependent resolutions for non-body
340+ // items like type aliases, we can't simply deduce the corresp. trait from
341+ // the HIR path alone without rerunning parts of HIR ty lowering here
342+ // (namely `probe_single_ty_param_bound_for_assoc_ty`) which is infeasible.
343+ //
344+ // (We could employ some simple heuristics but that's likely not worth it).
345+ if let hir:: QPath :: TypeRelative ( qself, _) = qpath
346+ && let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) ) = qself. kind
347+ && let hir:: def:: Res :: Def ( hir:: def:: DefKind :: TyParam , _) = path. res
348+ {
349+ self . diag . multipart_suggestion (
350+ fluent:: lint_builtin_type_alias_bounds_qualify_assoc_tys_sugg,
351+ vec ! [
352+ ( qself. span. shrink_to_lo( ) , "<" . into( ) ) ,
353+ ( qself. span. shrink_to_hi( ) , " as /* Trait */>" . into( ) ) ,
354+ ] ,
355+ Applicability :: HasPlaceholders ,
356+ ) ;
357+ }
358+ hir:: intravisit:: walk_qpath ( self , qpath, id)
359+ }
360+ }
361+ ProbeShorthandAssocTys { diag } . visit_ty ( self . ty ) ;
344362 }
345363}
346364
0 commit comments