1+ //! A utility module to inspect currently ambiguous obligations in the current context.
2+ use crate :: rustc_middle:: ty:: TypeVisitableExt ;
13use crate :: FnCtxt ;
4+ use rustc_infer:: traits:: solve:: Goal ;
5+ use rustc_infer:: traits:: { self , ObligationCause } ;
26use rustc_middle:: ty:: { self , Ty } ;
3- use rustc_infer:: traits;
4- use rustc_data_structures:: captures:: Captures ;
7+ use rustc_span:: Span ;
8+ use rustc_trait_selection:: solve:: inspect:: ProofTreeInferCtxtExt ;
9+ use rustc_trait_selection:: solve:: inspect:: { InspectConfig , InspectGoal , ProofTreeVisitor } ;
510
611impl < ' a , ' tcx > FnCtxt < ' a , ' tcx > {
12+ /// Returns a list of all obligations whose self type has been unified
13+ /// with the unconstrained type `self_ty`.
714 #[ instrument( skip( self ) , level = "debug" ) ]
8- pub ( crate ) fn obligations_for_self_ty < ' b > (
9- & ' b self ,
15+ pub ( crate ) fn obligations_for_self_ty (
16+ & self ,
1017 self_ty : ty:: TyVid ,
11- ) -> impl DoubleEndedIterator < Item = traits:: PredicateObligation < ' tcx > > + Captures < ' tcx > + ' b
12- {
13- let ty_var_root = self . root_var ( self_ty) ;
14- trace ! ( "pending_obligations = {:#?}" , self . fulfillment_cx. borrow( ) . pending_obligations( ) ) ;
15-
16- self . fulfillment_cx . borrow ( ) . pending_obligations ( ) . into_iter ( ) . filter_map (
17- move |obligation| match & obligation. predicate . kind ( ) . skip_binder ( ) {
18- ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( data) )
19- if self . self_type_matches_expected_vid (
20- data. projection_ty . self_ty ( ) ,
21- ty_var_root,
22- ) =>
23- {
24- Some ( obligation)
25- }
26- ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( data) )
27- if self . self_type_matches_expected_vid ( data. self_ty ( ) , ty_var_root) =>
28- {
29- Some ( obligation)
30- }
18+ ) -> Vec < traits:: PredicateObligation < ' tcx > > {
19+ if self . next_trait_solver ( ) {
20+ self . obligations_for_self_ty_next ( self_ty)
21+ } else {
22+ let ty_var_root = self . root_var ( self_ty) ;
23+ let mut obligations = self . fulfillment_cx . borrow ( ) . pending_obligations ( ) ;
24+ trace ! ( "pending_obligations = {:#?}" , obligations) ;
25+ obligations
26+ . retain ( |obligation| self . predicate_has_self_ty ( obligation. predicate , ty_var_root) ) ;
27+ obligations
28+ }
29+ }
3130
32- ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( ..) )
33- | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( ..) )
34- | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstArgHasType ( ..) )
35- | ty:: PredicateKind :: Subtype ( ..)
36- | ty:: PredicateKind :: Coerce ( ..)
37- | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: RegionOutlives ( ..) )
38- | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: TypeOutlives ( ..) )
39- | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: WellFormed ( ..) )
40- | ty:: PredicateKind :: ObjectSafe ( ..)
41- | ty:: PredicateKind :: NormalizesTo ( ..)
42- | ty:: PredicateKind :: AliasRelate ( ..)
43- | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstEvaluatable ( ..) )
44- | ty:: PredicateKind :: ConstEquate ( ..)
45- | ty:: PredicateKind :: Ambiguous => None ,
46- } ,
47- )
31+ #[ instrument( level = "debug" , skip( self ) , ret) ]
32+ fn predicate_has_self_ty (
33+ & self ,
34+ predicate : ty:: Predicate < ' tcx > ,
35+ expected_vid : ty:: TyVid ,
36+ ) -> bool {
37+ match predicate. kind ( ) . skip_binder ( ) {
38+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( data) ) => {
39+ self . type_matches_expected_vid ( expected_vid, data. self_ty ( ) )
40+ }
41+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( data) ) => {
42+ self . type_matches_expected_vid ( expected_vid, data. projection_ty . self_ty ( ) )
43+ }
44+ ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstArgHasType ( ..) )
45+ | ty:: PredicateKind :: Subtype ( ..)
46+ | ty:: PredicateKind :: Coerce ( ..)
47+ | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: RegionOutlives ( ..) )
48+ | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: TypeOutlives ( ..) )
49+ | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: WellFormed ( ..) )
50+ | ty:: PredicateKind :: ObjectSafe ( ..)
51+ | ty:: PredicateKind :: NormalizesTo ( ..)
52+ | ty:: PredicateKind :: AliasRelate ( ..)
53+ | ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstEvaluatable ( ..) )
54+ | ty:: PredicateKind :: ConstEquate ( ..)
55+ | ty:: PredicateKind :: Ambiguous => false ,
56+ }
4857 }
4958
5059 #[ instrument( level = "debug" , skip( self ) , ret) ]
51- fn self_type_matches_expected_vid ( & self , self_ty : Ty < ' tcx > , expected_vid : ty:: TyVid ) -> bool {
52- let self_ty = self . shallow_resolve ( self_ty ) ;
53- debug ! ( ?self_ty ) ;
60+ fn type_matches_expected_vid ( & self , expected_vid : ty:: TyVid , ty : Ty < ' tcx > ) -> bool {
61+ let ty = self . shallow_resolve ( ty ) ;
62+ debug ! ( ?ty ) ;
5463
55- match * self_ty . kind ( ) {
64+ match * ty . kind ( ) {
5665 ty:: Infer ( ty:: TyVar ( found_vid) ) => {
57- let found_vid = self . root_var ( found_vid) ;
58- debug ! ( "self_type_matches_expected_vid - found_vid={:?}" , found_vid) ;
59- expected_vid == found_vid
66+ self . root_var ( expected_vid) == self . root_var ( found_vid)
6067 }
6168 _ => false ,
6269 }
6370 }
64- }
71+
72+ pub ( crate ) fn obligations_for_self_ty_next (
73+ & self ,
74+ self_ty : ty:: TyVid ,
75+ ) -> Vec < traits:: PredicateObligation < ' tcx > > {
76+ let obligations = self . fulfillment_cx . borrow ( ) . pending_obligations ( ) ;
77+ debug ! ( ?obligations) ;
78+ let mut obligations_for_self_ty = vec ! [ ] ;
79+ for obligation in obligations {
80+ let mut visitor = NestedObligationsForSelfTy {
81+ fcx : self ,
82+ self_ty,
83+ obligations_for_self_ty : & mut obligations_for_self_ty,
84+ root_cause : & obligation. cause ,
85+ } ;
86+
87+ let goal = Goal :: new ( self . tcx , obligation. param_env , obligation. predicate ) ;
88+ self . visit_proof_tree ( goal, & mut visitor) ;
89+ }
90+
91+ obligations_for_self_ty. retain_mut ( |obligation| {
92+ obligation. predicate = self . resolve_vars_if_possible ( obligation. predicate ) ;
93+ !obligation. predicate . has_placeholders ( )
94+ } ) ;
95+ obligations_for_self_ty
96+ }
97+ }
98+
99+ struct NestedObligationsForSelfTy < ' a , ' tcx > {
100+ fcx : & ' a FnCtxt < ' a , ' tcx > ,
101+ self_ty : ty:: TyVid ,
102+ root_cause : & ' a ObligationCause < ' tcx > ,
103+ obligations_for_self_ty : & ' a mut Vec < traits:: PredicateObligation < ' tcx > > ,
104+ }
105+
106+ impl < ' a , ' tcx > ProofTreeVisitor < ' tcx > for NestedObligationsForSelfTy < ' a , ' tcx > {
107+ type Result = ( ) ;
108+
109+ fn span ( & self ) -> Span {
110+ self . root_cause . span
111+ }
112+
113+ fn config ( & self ) -> InspectConfig {
114+ // Using an intentionally low depth to minimize the chance of future
115+ // breaking changes in case we adapt the approach later on. This also
116+ // avoids any hangs for exponentially growing proof trees.
117+ InspectConfig { max_depth : 5 }
118+ }
119+
120+ fn visit_goal ( & mut self , inspect_goal : & InspectGoal < ' _ , ' tcx > ) {
121+ let tcx = self . fcx . tcx ;
122+ let goal = inspect_goal. goal ( ) ;
123+ if self . fcx . predicate_has_self_ty ( goal. predicate , self . self_ty ) {
124+ self . obligations_for_self_ty . push ( traits:: Obligation :: new (
125+ tcx,
126+ self . root_cause . clone ( ) ,
127+ goal. param_env ,
128+ goal. predicate ,
129+ ) ) ;
130+ }
131+
132+ // If there's a unique way to prove a given goal, recurse into
133+ // that candidate. This means that for `impl<F: FnOnce(u32)> Trait<F> for () {}`
134+ // and a `(): Trait<?0>` goal we recurse into the impl and look at
135+ // the nested `?0: FnOnce(u32)` goal.
136+ if let Some ( candidate) = inspect_goal. unique_applicable_candidate ( ) {
137+ candidate. visit_nested_no_probe ( self )
138+ }
139+ }
140+ }
0 commit comments