11use rustc_hir as hir;
2- use rustc_infer:: infer:: { BoundRegionConversionTime , DefineOpaqueTypes , InferCtxt } ;
2+ use rustc_infer:: infer:: { BoundRegionConversionTime , DefineOpaqueTypes } ;
33use rustc_infer:: traits:: { ImplSource , Obligation , PredicateObligation } ;
44use rustc_middle:: span_bug;
55use rustc_middle:: ty:: fast_reject:: DeepRejectCtxt ;
66use rustc_middle:: ty:: { self , TypingMode } ;
7+ use rustc_type_ir:: elaborate:: elaborate;
78use rustc_type_ir:: solve:: NoSolution ;
8- use thin_vec:: ThinVec ;
9+ use thin_vec:: { ThinVec , thin_vec } ;
910
1011use super :: SelectionContext ;
12+ use super :: normalize:: normalize_with_depth_to;
1113
1214pub type HostEffectObligation < ' tcx > = Obligation < ' tcx , ty:: HostEffectPredicate < ' tcx > > ;
1315
@@ -38,6 +40,12 @@ pub fn evaluate_host_effect_obligation<'tcx>(
3840 Err ( EvaluationFailure :: NoSolution ) => { }
3941 }
4042
43+ match evaluate_host_effect_from_item_bounds ( selcx, obligation) {
44+ Ok ( result) => return Ok ( result) ,
45+ Err ( EvaluationFailure :: Ambiguous ) => return Err ( EvaluationFailure :: Ambiguous ) ,
46+ Err ( EvaluationFailure :: NoSolution ) => { }
47+ }
48+
4149 match evaluate_host_effect_from_selection_candiate ( selcx, obligation) {
4250 Ok ( result) => return Ok ( result) ,
4351 Err ( EvaluationFailure :: Ambiguous ) => return Err ( EvaluationFailure :: Ambiguous ) ,
@@ -48,24 +56,45 @@ pub fn evaluate_host_effect_obligation<'tcx>(
4856}
4957
5058fn match_candidate < ' tcx > (
51- infcx : & InferCtxt < ' tcx > ,
59+ selcx : & mut SelectionContext < ' _ , ' tcx > ,
5260 obligation : & HostEffectObligation < ' tcx > ,
5361 candidate : ty:: Binder < ' tcx , ty:: HostEffectPredicate < ' tcx > > ,
62+ candidate_is_unnormalized : bool ,
63+ more_nested : impl FnOnce ( & mut SelectionContext < ' _ , ' tcx > , & mut ThinVec < PredicateObligation < ' tcx > > ) ,
5464) -> Result < ThinVec < PredicateObligation < ' tcx > > , NoSolution > {
5565 if !candidate. skip_binder ( ) . constness . satisfies ( obligation. predicate . constness ) {
5666 return Err ( NoSolution ) ;
5767 }
5868
59- let candidate = infcx. instantiate_binder_with_fresh_vars (
69+ let mut candidate = selcx . infcx . instantiate_binder_with_fresh_vars (
6070 obligation. cause . span ,
6171 BoundRegionConversionTime :: HigherRankedType ,
6272 candidate,
6373 ) ;
6474
65- let mut nested = infcx
66- . at ( & obligation. cause , obligation. param_env )
67- . eq ( DefineOpaqueTypes :: Yes , obligation. predicate . trait_ref , candidate. trait_ref ) ?
68- . into_obligations ( ) ;
75+ let mut nested = thin_vec ! [ ] ;
76+
77+ // Unlike param-env bounds, item bounds may not be normalized.
78+ if candidate_is_unnormalized {
79+ candidate = normalize_with_depth_to (
80+ selcx,
81+ obligation. param_env ,
82+ obligation. cause . clone ( ) ,
83+ obligation. recursion_depth ,
84+ candidate,
85+ & mut nested,
86+ ) ;
87+ }
88+
89+ nested. extend (
90+ selcx
91+ . infcx
92+ . at ( & obligation. cause , obligation. param_env )
93+ . eq ( DefineOpaqueTypes :: Yes , obligation. predicate . trait_ref , candidate. trait_ref ) ?
94+ . into_obligations ( ) ,
95+ ) ;
96+
97+ more_nested ( selcx, & mut nested) ;
6998
7099 for nested in & mut nested {
71100 nested. set_depth_from_parent ( obligation. recursion_depth ) ;
@@ -82,10 +111,70 @@ fn evaluate_host_effect_from_bounds<'tcx>(
82111 let drcx = DeepRejectCtxt :: relate_rigid_rigid ( selcx. tcx ( ) ) ;
83112 let mut candidate = None ;
84113
85- for predicate in obligation. param_env . caller_bounds ( ) {
86- let bound_predicate = predicate. kind ( ) ;
87- if let ty:: ClauseKind :: HostEffect ( data) = predicate. kind ( ) . skip_binder ( ) {
88- let data = bound_predicate. rebind ( data) ;
114+ for clause in obligation. param_env . caller_bounds ( ) {
115+ let bound_clause = clause. kind ( ) ;
116+ let ty:: ClauseKind :: HostEffect ( data) = bound_clause. skip_binder ( ) else {
117+ continue ;
118+ } ;
119+ let data = bound_clause. rebind ( data) ;
120+ if data. skip_binder ( ) . trait_ref . def_id != obligation. predicate . trait_ref . def_id {
121+ continue ;
122+ }
123+
124+ if !drcx
125+ . args_may_unify ( obligation. predicate . trait_ref . args , data. skip_binder ( ) . trait_ref . args )
126+ {
127+ continue ;
128+ }
129+
130+ let is_match =
131+ infcx. probe ( |_| match_candidate ( selcx, obligation, data, false , |_, _| { } ) . is_ok ( ) ) ;
132+
133+ if is_match {
134+ if candidate. is_some ( ) {
135+ return Err ( EvaluationFailure :: Ambiguous ) ;
136+ } else {
137+ candidate = Some ( data) ;
138+ }
139+ }
140+ }
141+
142+ if let Some ( data) = candidate {
143+ Ok ( match_candidate ( selcx, obligation, data, false , |_, _| { } )
144+ . expect ( "candidate matched before, so it should match again" ) )
145+ } else {
146+ Err ( EvaluationFailure :: NoSolution )
147+ }
148+ }
149+
150+ fn evaluate_host_effect_from_item_bounds < ' tcx > (
151+ selcx : & mut SelectionContext < ' _ , ' tcx > ,
152+ obligation : & HostEffectObligation < ' tcx > ,
153+ ) -> Result < ThinVec < PredicateObligation < ' tcx > > , EvaluationFailure > {
154+ let infcx = selcx. infcx ;
155+ let tcx = infcx. tcx ;
156+ let drcx = DeepRejectCtxt :: relate_rigid_rigid ( selcx. tcx ( ) ) ;
157+ let mut candidate = None ;
158+
159+ let mut consider_ty = obligation. predicate . self_ty ( ) ;
160+ while let ty:: Alias ( kind @ ( ty:: Projection | ty:: Opaque ) , alias_ty) = * consider_ty. kind ( ) {
161+ if kind != ty:: Projection {
162+ break ;
163+ }
164+
165+ for clause in elaborate (
166+ tcx,
167+ tcx. explicit_implied_const_bounds ( alias_ty. def_id )
168+ . iter_instantiated_copied ( tcx, alias_ty. args )
169+ . map ( |( trait_ref, _) | {
170+ trait_ref. to_host_effect_clause ( tcx, obligation. predicate . constness )
171+ } ) ,
172+ ) {
173+ let bound_clause = clause. kind ( ) ;
174+ let ty:: ClauseKind :: HostEffect ( data) = bound_clause. skip_binder ( ) else {
175+ unreachable ! ( "should not elaborate non-HostEffect from HostEffect" )
176+ } ;
177+ let data = bound_clause. rebind ( data) ;
89178 if data. skip_binder ( ) . trait_ref . def_id != obligation. predicate . trait_ref . def_id {
90179 continue ;
91180 }
@@ -97,21 +186,39 @@ fn evaluate_host_effect_from_bounds<'tcx>(
97186 continue ;
98187 }
99188
100- let is_match = infcx. probe ( |_| match_candidate ( infcx, obligation, data) . is_ok ( ) ) ;
189+ let is_match =
190+ infcx. probe ( |_| match_candidate ( selcx, obligation, data, true , |_, _| { } ) . is_ok ( ) ) ;
101191
102192 if is_match {
103193 if candidate. is_some ( ) {
104194 return Err ( EvaluationFailure :: Ambiguous ) ;
105195 } else {
106- candidate = Some ( data) ;
196+ candidate = Some ( ( data, alias_ty ) ) ;
107197 }
108198 }
109199 }
200+
201+ consider_ty = alias_ty. self_ty ( ) ;
110202 }
111203
112- if let Some ( data) = candidate {
113- Ok ( match_candidate ( infcx, obligation, data)
114- . expect ( "candidate matched before, so it should match again" ) )
204+ if let Some ( ( data, alias_ty) ) = candidate {
205+ Ok ( match_candidate ( selcx, obligation, data, true , |selcx, nested| {
206+ // An alias bound only holds if we also check the const conditions
207+ // of the alias, so we need to register those, too.
208+ let const_conditions = normalize_with_depth_to (
209+ selcx,
210+ obligation. param_env ,
211+ obligation. cause . clone ( ) ,
212+ obligation. recursion_depth ,
213+ tcx. const_conditions ( alias_ty. def_id ) . instantiate ( tcx, alias_ty. args ) ,
214+ nested,
215+ ) ;
216+ nested. extend ( const_conditions. into_iter ( ) . map ( |( trait_ref, _) | {
217+ obligation
218+ . with ( tcx, trait_ref. to_host_effect_clause ( tcx, obligation. predicate . constness ) )
219+ } ) ) ;
220+ } )
221+ . expect ( "candidate matched before, so it should match again" ) )
115222 } else {
116223 Err ( EvaluationFailure :: NoSolution )
117224 }
0 commit comments