@@ -31,8 +31,8 @@ use rustc_middle::ty::print::{
31
31
} ;
32
32
use rustc_middle:: ty:: {
33
33
self , AdtKind , GenericArgs , InferTy , IsSuggestable , Ty , TyCtxt , TypeFoldable , TypeFolder ,
34
- TypeSuperFoldable , TypeVisitableExt , TypeckResults , Upcast , suggest_arbitrary_trait_bound ,
35
- suggest_constraining_type_param,
34
+ TypeSuperFoldable , TypeSuperVisitable , TypeVisitableExt , TypeVisitor , TypeckResults , Upcast ,
35
+ suggest_arbitrary_trait_bound , suggest_constraining_type_param,
36
36
} ;
37
37
use rustc_middle:: { bug, span_bug} ;
38
38
use rustc_span:: def_id:: LocalDefId ;
@@ -262,6 +262,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
262
262
_ => ( false , None ) ,
263
263
} ;
264
264
265
+ let mut finder = ParamFinder { .. } ;
266
+ finder. visit_binder ( & trait_pred) ;
267
+
265
268
// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
266
269
// don't suggest `T: Sized + ?Sized`.
267
270
loop {
@@ -410,6 +413,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
410
413
}
411
414
}
412
415
416
+ hir:: Node :: TraitItem ( hir:: TraitItem {
417
+ generics,
418
+ kind : hir:: TraitItemKind :: Fn ( ..) ,
419
+ ..
420
+ } )
421
+ | hir:: Node :: ImplItem ( hir:: ImplItem {
422
+ generics,
423
+ trait_item_def_id : None ,
424
+ kind : hir:: ImplItemKind :: Fn ( ..) ,
425
+ ..
426
+ } ) if finder. can_suggest_bound ( generics) => {
427
+ // Missing generic type parameter bound.
428
+ suggest_arbitrary_trait_bound (
429
+ self . tcx ,
430
+ generics,
431
+ err,
432
+ trait_pred,
433
+ associated_ty,
434
+ ) ;
435
+ }
413
436
hir:: Node :: Item ( hir:: Item {
414
437
kind :
415
438
hir:: ItemKind :: Struct ( _, generics, _)
@@ -422,7 +445,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
422
445
| hir:: ItemKind :: Const ( _, generics, _, _)
423
446
| hir:: ItemKind :: TraitAlias ( _, generics, _) ,
424
447
..
425
- } ) if !param_ty => {
448
+ } ) if finder . can_suggest_bound ( generics ) => {
426
449
// Missing generic type parameter bound.
427
450
if suggest_arbitrary_trait_bound (
428
451
self . tcx ,
@@ -5034,8 +5057,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
5034
5057
// Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
5035
5058
// borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
5036
5059
// is not. Look for invalid "bare" parameter uses, and suggest using indirection.
5037
- let mut visitor =
5038
- FindTypeParam { param : param. name . ident ( ) . name , invalid_spans : vec ! [ ] , nested : false } ;
5060
+ let mut visitor = FindTypeParam { param : param. name . ident ( ) . name , .. } ;
5039
5061
visitor. visit_item ( item) ;
5040
5062
if visitor. invalid_spans . is_empty ( ) {
5041
5063
return false ;
@@ -5198,7 +5220,7 @@ fn hint_missing_borrow<'tcx>(
5198
5220
/// Used to suggest replacing associated types with an explicit type in `where` clauses.
5199
5221
#[ derive( Debug ) ]
5200
5222
pub struct SelfVisitor < ' v > {
5201
- pub paths : Vec < & ' v hir:: Ty < ' v > > ,
5223
+ pub paths : Vec < & ' v hir:: Ty < ' v > > = Vec :: new ( ) ,
5202
5224
pub name : Option < Symbol > ,
5203
5225
}
5204
5226
@@ -5568,7 +5590,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
5568
5590
) ;
5569
5591
// Search for the associated type `Self::{name}`, get
5570
5592
// its type and suggest replacing the bound with it.
5571
- let mut visitor = SelfVisitor { paths : vec ! [ ] , name : Some ( name) } ;
5593
+ let mut visitor = SelfVisitor { name : Some ( name) , .. } ;
5572
5594
visitor. visit_trait_ref ( trait_ref) ;
5573
5595
for path in visitor. paths {
5574
5596
err. span_suggestion_verbose (
@@ -5579,7 +5601,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
5579
5601
) ;
5580
5602
}
5581
5603
} else {
5582
- let mut visitor = SelfVisitor { paths : vec ! [ ] , name : None } ;
5604
+ let mut visitor = SelfVisitor { name : None , .. } ;
5583
5605
visitor. visit_trait_ref ( trait_ref) ;
5584
5606
let span: MultiSpan =
5585
5607
visitor. paths . iter ( ) . map ( |p| p. span ) . collect :: < Vec < Span > > ( ) . into ( ) ;
@@ -5609,8 +5631,8 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
5609
5631
/// `param: ?Sized` would be a valid constraint.
5610
5632
struct FindTypeParam {
5611
5633
param : rustc_span:: Symbol ,
5612
- invalid_spans : Vec < Span > ,
5613
- nested : bool ,
5634
+ invalid_spans : Vec < Span > = Vec :: new ( ) ,
5635
+ nested : bool = false ,
5614
5636
}
5615
5637
5616
5638
impl < ' v > Visitor < ' v > for FindTypeParam {
@@ -5648,3 +5670,38 @@ impl<'v> Visitor<'v> for FindTypeParam {
5648
5670
}
5649
5671
}
5650
5672
}
5673
+
5674
+ /// Look for type parameters in predicates. We use this to identify whether a bound is suitable in
5675
+ /// on a given item.
5676
+ struct ParamFinder {
5677
+ params : Vec < Symbol > = Vec :: new ( ) ,
5678
+ }
5679
+
5680
+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for ParamFinder {
5681
+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> Self :: Result {
5682
+ match t. kind ( ) {
5683
+ ty:: Param ( p) => self . params . push ( p. name ) ,
5684
+ _ => { }
5685
+ }
5686
+ t. super_visit_with ( self )
5687
+ }
5688
+ }
5689
+
5690
+ impl ParamFinder {
5691
+ /// Whether the `hir::Generics` of the current item can suggest the evaluated bound because its
5692
+ /// references to type parameters are present in the generics.
5693
+ fn can_suggest_bound ( & self , generics : & hir:: Generics < ' _ > ) -> bool {
5694
+ if self . params . is_empty ( ) {
5695
+ // There are no references to type parameters at all, so suggesting the bound
5696
+ // would be reasonable.
5697
+ return true ;
5698
+ }
5699
+ generics. params . iter ( ) . any ( |p| match p. name {
5700
+ hir:: ParamName :: Plain ( p_name) => {
5701
+ // All of the parameters in the bound can be referenced in the current item.
5702
+ self . params . iter ( ) . any ( |p| * p == p_name. name || * p == kw:: SelfUpper )
5703
+ }
5704
+ _ => true ,
5705
+ } )
5706
+ }
5707
+ }
0 commit comments