1+ use crate :: rustc_middle:: ty:: TypeVisitableExt ;
12use crate :: FnCtxt ;
23use rustc_infer:: traits:: solve:: Goal ;
34use rustc_infer:: traits:: { self , ObligationCause } ;
@@ -31,10 +32,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
3132 ) -> bool {
3233 match predicate. kind ( ) . skip_binder ( ) {
3334 ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Trait ( data) ) => {
34- self . self_type_matches_expected_vid ( data. self_ty ( ) , expected_vid )
35+ self . type_matches_expected_vid ( expected_vid , data. self_ty ( ) )
3536 }
3637 ty:: PredicateKind :: Clause ( ty:: ClauseKind :: Projection ( data) ) => {
37- self . self_type_matches_expected_vid ( data. projection_ty . self_ty ( ) , expected_vid )
38+ self . type_matches_expected_vid ( expected_vid , data. projection_ty . self_ty ( ) )
3839 }
3940 ty:: PredicateKind :: Clause ( ty:: ClauseKind :: ConstArgHasType ( ..) )
4041 | ty:: PredicateKind :: Subtype ( ..)
@@ -52,11 +53,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
5253 }
5354
5455 #[ instrument( level = "debug" , skip( self ) , ret) ]
55- fn self_type_matches_expected_vid ( & self , self_ty : Ty < ' tcx > , expected_vid : ty:: TyVid ) -> bool {
56- let self_ty = self . shallow_resolve ( self_ty ) ;
57- debug ! ( ?self_ty ) ;
56+ fn type_matches_expected_vid ( & self , expected_vid : ty:: TyVid , ty : Ty < ' tcx > ) -> bool {
57+ let ty = self . shallow_resolve ( ty ) ;
58+ debug ! ( ?ty ) ;
5859
59- match * self_ty . kind ( ) {
60+ match * ty . kind ( ) {
6061 ty:: Infer ( ty:: TyVar ( found_vid) ) => expected_vid == self . root_var ( found_vid) ,
6162 _ => false ,
6263 }
@@ -67,6 +68,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
6768 self_ty : ty:: TyVid ,
6869 ) -> Vec < traits:: PredicateObligation < ' tcx > > {
6970 let obligations = self . fulfillment_cx . borrow ( ) . pending_obligations ( ) ;
71+ debug ! ( ?obligations) ;
7072 let mut obligations_for_self_ty = vec ! [ ] ;
7173 for obligation in obligations {
7274 let mut visitor = NestedObligationsForSelfTy {
@@ -79,6 +81,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7981 let goal = Goal :: new ( self . tcx , obligation. param_env , obligation. predicate ) ;
8082 self . visit_proof_tree ( goal, & mut visitor) ;
8183 }
84+
85+ obligations_for_self_ty. retain_mut ( |obligation| {
86+ obligation. predicate = self . resolve_vars_if_possible ( obligation. predicate ) ;
87+ !obligation. predicate . has_placeholders ( )
88+ } ) ;
8289 obligations_for_self_ty
8390 }
8491}
@@ -90,26 +97,65 @@ struct NestedObligationsForSelfTy<'a, 'tcx> {
9097 obligations_for_self_ty : & ' a mut Vec < traits:: PredicateObligation < ' tcx > > ,
9198}
9299
100+ impl < ' a , ' tcx > NestedObligationsForSelfTy < ' a , ' tcx > {
101+ fn consider_goal ( & mut self , goal : Goal < ' tcx , ty:: Predicate < ' tcx > > ) {
102+ if self . fcx . predicate_has_self_ty ( goal. predicate , self . ty_var_root ) {
103+ self . obligations_for_self_ty . push ( traits:: Obligation :: new (
104+ self . fcx . tcx ,
105+ self . root_cause . clone ( ) ,
106+ goal. param_env ,
107+ goal. predicate ,
108+ ) ) ;
109+ }
110+ }
111+ }
112+
93113impl < ' a , ' tcx > ProofTreeVisitor < ' tcx > for NestedObligationsForSelfTy < ' a , ' tcx > {
94114 type Result = ( ) ;
95115
96116 fn config ( & self ) -> InspectConfig {
97117 // Using an intentionally low depth to minimize the chance of future
98118 // breaking changes in case we adapt the approach later on. This also
99119 // avoids any hangs for exponentially growing proof trees.
100- InspectConfig { max_depth : 3 }
120+ InspectConfig { max_depth : 5 }
101121 }
102122
103123 fn visit_goal ( & mut self , inspect_goal : & InspectGoal < ' _ , ' tcx > ) {
104124 let tcx = self . fcx . tcx ;
105125 let goal = inspect_goal. goal ( ) ;
106- if self . fcx . predicate_has_self_ty ( goal. predicate , self . ty_var_root ) {
107- self . obligations_for_self_ty . push ( traits:: Obligation :: new (
108- tcx,
109- self . root_cause . clone ( ) ,
110- goal. param_env ,
111- goal. predicate ,
112- ) ) ;
126+ self . consider_goal ( goal) ;
127+
128+ // HACK: When proving `NormalizesTo(oapque; ?infer)` we don't emit the
129+ // item bounds of the opaque as nested goals, so they never get picked up here.
130+ // Manually add these as obligations instead.
131+ //
132+ // Alternatively, we could change the solver to always emit the item bounds
133+ // as nested goals, even if the hidden type is an infer var. However, given that
134+ // these nested goals would always just fail with ambiguity, that would be
135+ // useless for everything apart from this exact `ProofTreeVisitor`, so we
136+ // do it here.
137+ match goal. predicate . kind ( ) . no_bound_vars ( ) {
138+ Some ( ty:: PredicateKind :: NormalizesTo ( ty:: NormalizesTo { alias, term } ) ) => {
139+ if alias. is_opaque ( tcx) {
140+ let hidden_ty = term. ty ( ) . unwrap ( ) ;
141+ if self . fcx . type_matches_expected_vid ( self . ty_var_root , hidden_ty) {
142+ let mut obligations = vec ! [ ] ;
143+ self . fcx . add_item_bounds_for_hidden_type (
144+ alias. def_id ,
145+ alias. args ,
146+ self . root_cause . clone ( ) ,
147+ goal. param_env ,
148+ hidden_ty,
149+ & mut obligations,
150+ ) ;
151+ debug ! ( ?obligations) ;
152+ for obl in obligations {
153+ self . consider_goal ( obl. into ( ) ) ;
154+ }
155+ }
156+ }
157+ }
158+ Some ( _) | None => { }
113159 }
114160
115161 if let Some ( candidate) = inspect_goal. unique_applicable_candidate ( ) {
0 commit comments