@@ -32,8 +32,8 @@ use rustc_middle::ty::print::{
32
32
} ;
33
33
use rustc_middle:: ty:: {
34
34
self , AdtKind , GenericArgs , InferTy , IsSuggestable , Ty , TyCtxt , TypeFoldable , TypeFolder ,
35
- TypeSuperFoldable , TypeVisitableExt , TypeckResults , Upcast , suggest_arbitrary_trait_bound ,
36
- suggest_constraining_type_param,
35
+ TypeSuperFoldable , TypeSuperVisitable , TypeVisitableExt , TypeVisitor , TypeckResults , Upcast ,
36
+ suggest_arbitrary_trait_bound , suggest_constraining_type_param,
37
37
} ;
38
38
use rustc_middle:: { bug, span_bug} ;
39
39
use rustc_span:: def_id:: LocalDefId ;
@@ -263,6 +263,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
263
263
_ => ( false , None ) ,
264
264
} ;
265
265
266
+ let mut finder = ParamFinder { .. } ;
267
+ finder. visit_binder ( & trait_pred) ;
268
+
266
269
// FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
267
270
// don't suggest `T: Sized + ?Sized`.
268
271
loop {
@@ -411,6 +414,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
411
414
}
412
415
}
413
416
417
+ hir:: Node :: TraitItem ( hir:: TraitItem {
418
+ generics,
419
+ kind : hir:: TraitItemKind :: Fn ( ..) ,
420
+ ..
421
+ } )
422
+ | hir:: Node :: ImplItem ( hir:: ImplItem {
423
+ generics,
424
+ trait_item_def_id : None ,
425
+ kind : hir:: ImplItemKind :: Fn ( ..) ,
426
+ ..
427
+ } ) if finder. can_suggest_bound ( generics) => {
428
+ // Missing generic type parameter bound.
429
+ suggest_arbitrary_trait_bound (
430
+ self . tcx ,
431
+ generics,
432
+ err,
433
+ trait_pred,
434
+ associated_ty,
435
+ ) ;
436
+ }
414
437
hir:: Node :: Item ( hir:: Item {
415
438
kind :
416
439
hir:: ItemKind :: Struct ( _, generics, _)
@@ -423,7 +446,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
423
446
| hir:: ItemKind :: Const ( _, generics, _, _)
424
447
| hir:: ItemKind :: TraitAlias ( _, generics, _) ,
425
448
..
426
- } ) if !param_ty => {
449
+ } ) if finder . can_suggest_bound ( generics ) => {
427
450
// Missing generic type parameter bound.
428
451
if suggest_arbitrary_trait_bound (
429
452
self . tcx ,
@@ -5068,8 +5091,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
5068
5091
// Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
5069
5092
// borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
5070
5093
// is not. Look for invalid "bare" parameter uses, and suggest using indirection.
5071
- let mut visitor =
5072
- FindTypeParam { param : param. name . ident ( ) . name , invalid_spans : vec ! [ ] , nested : false } ;
5094
+ let mut visitor = FindTypeParam { param : param. name . ident ( ) . name , .. } ;
5073
5095
visitor. visit_item ( item) ;
5074
5096
if visitor. invalid_spans . is_empty ( ) {
5075
5097
return false ;
@@ -5228,7 +5250,7 @@ fn hint_missing_borrow<'tcx>(
5228
5250
/// Used to suggest replacing associated types with an explicit type in `where` clauses.
5229
5251
#[ derive( Debug ) ]
5230
5252
pub struct SelfVisitor < ' v > {
5231
- pub paths : Vec < & ' v hir:: Ty < ' v > > ,
5253
+ pub paths : Vec < & ' v hir:: Ty < ' v > > = Vec :: new ( ) ,
5232
5254
pub name : Option < Symbol > ,
5233
5255
}
5234
5256
@@ -5599,7 +5621,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
5599
5621
) ;
5600
5622
// Search for the associated type `Self::{name}`, get
5601
5623
// its type and suggest replacing the bound with it.
5602
- let mut visitor = SelfVisitor { paths : vec ! [ ] , name : Some ( name) } ;
5624
+ let mut visitor = SelfVisitor { name : Some ( name) , .. } ;
5603
5625
visitor. visit_trait_ref ( trait_ref) ;
5604
5626
for path in visitor. paths {
5605
5627
err. span_suggestion_verbose (
@@ -5610,7 +5632,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
5610
5632
) ;
5611
5633
}
5612
5634
} else {
5613
- let mut visitor = SelfVisitor { paths : vec ! [ ] , name : None } ;
5635
+ let mut visitor = SelfVisitor { name : None , .. } ;
5614
5636
visitor. visit_trait_ref ( trait_ref) ;
5615
5637
let span: MultiSpan =
5616
5638
visitor. paths . iter ( ) . map ( |p| p. span ) . collect :: < Vec < Span > > ( ) . into ( ) ;
@@ -5640,8 +5662,8 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
5640
5662
/// `param: ?Sized` would be a valid constraint.
5641
5663
struct FindTypeParam {
5642
5664
param : rustc_span:: Symbol ,
5643
- invalid_spans : Vec < Span > ,
5644
- nested : bool ,
5665
+ invalid_spans : Vec < Span > = Vec :: new ( ) ,
5666
+ nested : bool = false ,
5645
5667
}
5646
5668
5647
5669
impl < ' v > Visitor < ' v > for FindTypeParam {
@@ -5679,3 +5701,38 @@ impl<'v> Visitor<'v> for FindTypeParam {
5679
5701
}
5680
5702
}
5681
5703
}
5704
+
5705
+ /// Look for type parameters in predicates. We use this to identify whether a bound is suitable in
5706
+ /// on a given item.
5707
+ struct ParamFinder {
5708
+ params : Vec < Symbol > = Vec :: new ( ) ,
5709
+ }
5710
+
5711
+ impl < ' tcx > TypeVisitor < TyCtxt < ' tcx > > for ParamFinder {
5712
+ fn visit_ty ( & mut self , t : Ty < ' tcx > ) -> Self :: Result {
5713
+ match t. kind ( ) {
5714
+ ty:: Param ( p) => self . params . push ( p. name ) ,
5715
+ _ => { }
5716
+ }
5717
+ t. super_visit_with ( self )
5718
+ }
5719
+ }
5720
+
5721
+ impl ParamFinder {
5722
+ /// Whether the `hir::Generics` of the current item can suggest the evaluated bound because its
5723
+ /// references to type parameters are present in the generics.
5724
+ fn can_suggest_bound ( & self , generics : & hir:: Generics < ' _ > ) -> bool {
5725
+ if self . params . is_empty ( ) {
5726
+ // There are no references to type parameters at all, so suggesting the bound
5727
+ // would be reasonable.
5728
+ return true ;
5729
+ }
5730
+ generics. params . iter ( ) . any ( |p| match p. name {
5731
+ hir:: ParamName :: Plain ( p_name) => {
5732
+ // All of the parameters in the bound can be referenced in the current item.
5733
+ self . params . iter ( ) . any ( |p| * p == p_name. name || * p == kw:: SelfUpper )
5734
+ }
5735
+ _ => true ,
5736
+ } )
5737
+ }
5738
+ }
0 commit comments