@@ -9,7 +9,7 @@ use rustc_errors::{
9
9
ElidedLifetimeInPathSubdiag , EmissionGuarantee , LintDiagnostic , MultiSpan , SubdiagMessageOp ,
10
10
Subdiagnostic , SuggestionStyle ,
11
11
} ;
12
- use rustc_hir:: { def:: Namespace , def_id:: DefId } ;
12
+ use rustc_hir:: { self as hir , def:: Namespace , def_id:: DefId } ;
13
13
use rustc_macros:: { LintDiagnostic , Subdiagnostic } ;
14
14
use rustc_middle:: ty:: {
15
15
inhabitedness:: InhabitedPredicate , Clause , PolyExistentialTraitRef , Ty , TyCtxt ,
@@ -22,9 +22,7 @@ use rustc_span::{
22
22
Span , Symbol ,
23
23
} ;
24
24
25
- use crate :: {
26
- builtin:: InitError , builtin:: TypeAliasBounds , errors:: OverruledAttributeSub , LateContext ,
27
- } ;
25
+ use crate :: { builtin:: InitError , errors:: OverruledAttributeSub , LateContext } ;
28
26
29
27
// array_into_iter.rs
30
28
#[ derive( LintDiagnostic ) ]
@@ -263,84 +261,104 @@ pub struct BuiltinUnreachablePub<'a> {
263
261
pub help : Option < ( ) > ,
264
262
}
265
263
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 ,
268
302
}
269
303
270
- impl < ' a , ' b > Subdiagnostic for SuggestChangingAssocTypes < ' a , ' b > {
304
+ impl Subdiagnostic for BuiltinTypeAliasParamBoundsSuggestion {
271
305
fn add_to_diag_with < G : EmissionGuarantee , F : SubdiagMessageOp < G > > (
272
306
self ,
273
307
diag : & mut Diag < ' _ , G > ,
274
308
_f : & F ,
275
309
) {
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 ) ;
301
312
}
302
313
}
303
314
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 > ,
327
317
}
328
318
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 > {
334
320
fn add_to_diag_with < G : EmissionGuarantee , F : SubdiagMessageOp < G > > (
335
321
self ,
336
322
diag : & mut Diag < ' _ , G > ,
337
323
_f : & F ,
338
324
) {
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 ) ;
344
362
}
345
363
}
346
364
0 commit comments