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