@@ -31,8 +31,8 @@ use rustc_middle::ty::print::{
3131} ;
3232use rustc_middle:: ty:: {
3333 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,
3636} ;
3737use rustc_middle:: { bug, span_bug} ;
3838use rustc_span:: def_id:: LocalDefId ;
@@ -262,6 +262,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
262262 _ => ( false , None ) ,
263263 } ;
264264
265+ let mut finder = ParamFinder { .. } ;
266+ finder. visit_binder ( & trait_pred) ;
267+
265268 // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we
266269 // don't suggest `T: Sized + ?Sized`.
267270 loop {
@@ -410,6 +413,26 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
410413 }
411414 }
412415
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+ }
413436 hir:: Node :: Item ( hir:: Item {
414437 kind :
415438 hir:: ItemKind :: Struct ( _, generics, _)
@@ -422,7 +445,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
422445 | hir:: ItemKind :: Const ( _, generics, _, _)
423446 | hir:: ItemKind :: TraitAlias ( _, generics, _) ,
424447 ..
425- } ) if !param_ty => {
448+ } ) if finder . can_suggest_bound ( generics ) => {
426449 // Missing generic type parameter bound.
427450 if suggest_arbitrary_trait_bound (
428451 self . tcx ,
@@ -5034,8 +5057,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
50345057 // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
50355058 // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
50365059 // 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 , .. } ;
50395061 visitor. visit_item ( item) ;
50405062 if visitor. invalid_spans . is_empty ( ) {
50415063 return false ;
@@ -5198,7 +5220,7 @@ fn hint_missing_borrow<'tcx>(
51985220/// Used to suggest replacing associated types with an explicit type in `where` clauses.
51995221#[ derive( Debug ) ]
52005222pub struct SelfVisitor < ' v > {
5201- pub paths : Vec < & ' v hir:: Ty < ' v > > ,
5223+ pub paths : Vec < & ' v hir:: Ty < ' v > > = Vec :: new ( ) ,
52025224 pub name : Option < Symbol > ,
52035225}
52045226
@@ -5568,7 +5590,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
55685590 ) ;
55695591 // Search for the associated type `Self::{name}`, get
55705592 // 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) , .. } ;
55725594 visitor. visit_trait_ref ( trait_ref) ;
55735595 for path in visitor. paths {
55745596 err. span_suggestion_verbose (
@@ -5579,7 +5601,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
55795601 ) ;
55805602 }
55815603 } else {
5582- let mut visitor = SelfVisitor { paths : vec ! [ ] , name : None } ;
5604+ let mut visitor = SelfVisitor { name : None , .. } ;
55835605 visitor. visit_trait_ref ( trait_ref) ;
55845606 let span: MultiSpan =
55855607 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>) {
56095631/// `param: ?Sized` would be a valid constraint.
56105632struct FindTypeParam {
56115633 param : rustc_span:: Symbol ,
5612- invalid_spans : Vec < Span > ,
5613- nested : bool ,
5634+ invalid_spans : Vec < Span > = Vec :: new ( ) ,
5635+ nested : bool = false ,
56145636}
56155637
56165638impl < ' v > Visitor < ' v > for FindTypeParam {
@@ -5648,3 +5670,38 @@ impl<'v> Visitor<'v> for FindTypeParam {
56485670 }
56495671 }
56505672}
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