@@ -39,11 +39,13 @@ use std::sync::Arc;
3939use chalk_ir:: {
4040 fold:: { Shift , TypeFoldable } ,
4141 interner:: HasInterner ,
42- NoSolution ,
42+ visit:: { TypeSuperVisitable , TypeVisitable , TypeVisitor } ,
43+ NoSolution , TyData ,
4344} ;
4445use hir_def:: { expr:: ExprId , type_ref:: Rawness , TypeOrConstParamId } ;
4546use hir_expand:: name;
4647use itertools:: Either ;
48+ use rustc_hash:: FxHashSet ;
4749use traits:: FnTrait ;
4850use utils:: Generics ;
4951
@@ -562,3 +564,68 @@ pub fn callable_sig_from_fnonce(
562564
563565 Some ( CallableSig :: from_params_and_return ( params, ret_ty, false , Safety :: Safe ) )
564566}
567+
568+ struct PlaceholderCollector < ' db > {
569+ db : & ' db dyn HirDatabase ,
570+ placeholders : FxHashSet < TypeOrConstParamId > ,
571+ }
572+
573+ impl PlaceholderCollector < ' _ > {
574+ fn collect ( & mut self , idx : PlaceholderIndex ) {
575+ let id = from_placeholder_idx ( self . db , idx) ;
576+ self . placeholders . insert ( id) ;
577+ }
578+ }
579+
580+ impl TypeVisitor < Interner > for PlaceholderCollector < ' _ > {
581+ type BreakTy = ( ) ;
582+
583+ fn as_dyn ( & mut self ) -> & mut dyn TypeVisitor < Interner , BreakTy = Self :: BreakTy > {
584+ self
585+ }
586+
587+ fn interner ( & self ) -> Interner {
588+ Interner
589+ }
590+
591+ fn visit_ty (
592+ & mut self ,
593+ ty : & Ty ,
594+ outer_binder : DebruijnIndex ,
595+ ) -> std:: ops:: ControlFlow < Self :: BreakTy > {
596+ let has_placeholder_bits = TypeFlags :: HAS_TY_PLACEHOLDER | TypeFlags :: HAS_CT_PLACEHOLDER ;
597+ let TyData { kind, flags } = ty. data ( Interner ) ;
598+
599+ if let TyKind :: Placeholder ( idx) = kind {
600+ self . collect ( * idx) ;
601+ } else if flags. intersects ( has_placeholder_bits) {
602+ return ty. super_visit_with ( self , outer_binder) ;
603+ } else {
604+ // Fast path: don't visit inner types (e.g. generic arguments) when `flags` indicate
605+ // that there are no placeholders.
606+ }
607+
608+ std:: ops:: ControlFlow :: Continue ( ( ) )
609+ }
610+
611+ fn visit_const (
612+ & mut self ,
613+ constant : & chalk_ir:: Const < Interner > ,
614+ _outer_binder : DebruijnIndex ,
615+ ) -> std:: ops:: ControlFlow < Self :: BreakTy > {
616+ if let chalk_ir:: ConstValue :: Placeholder ( idx) = constant. data ( Interner ) . value {
617+ self . collect ( idx) ;
618+ }
619+ std:: ops:: ControlFlow :: Continue ( ( ) )
620+ }
621+ }
622+
623+ /// Returns unique placeholders for types and consts contained in `value`.
624+ pub fn collect_placeholders < T > ( value : & T , db : & dyn HirDatabase ) -> Vec < TypeOrConstParamId >
625+ where
626+ T : ?Sized + TypeVisitable < Interner > ,
627+ {
628+ let mut collector = PlaceholderCollector { db, placeholders : FxHashSet :: default ( ) } ;
629+ value. visit_with ( & mut collector, DebruijnIndex :: INNERMOST ) ;
630+ collector. placeholders . into_iter ( ) . collect ( )
631+ }
0 commit comments