@@ -39,11 +39,13 @@ use std::sync::Arc;
39
39
use chalk_ir:: {
40
40
fold:: { Shift , TypeFoldable } ,
41
41
interner:: HasInterner ,
42
- NoSolution ,
42
+ visit:: { TypeSuperVisitable , TypeVisitable , TypeVisitor } ,
43
+ NoSolution , TyData ,
43
44
} ;
44
45
use hir_def:: { expr:: ExprId , type_ref:: Rawness , TypeOrConstParamId } ;
45
46
use hir_expand:: name;
46
47
use itertools:: Either ;
48
+ use rustc_hash:: FxHashSet ;
47
49
use traits:: FnTrait ;
48
50
use utils:: Generics ;
49
51
@@ -562,3 +564,68 @@ pub fn callable_sig_from_fnonce(
562
564
563
565
Some ( CallableSig :: from_params_and_return ( params, ret_ty, false , Safety :: Safe ) )
564
566
}
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