@@ -164,6 +164,7 @@ where
164164 ecx : & mut EvalCtxt < ' _ , D > ,
165165 goal : Goal < I , Self > ,
166166 ) -> Result < Candidate < I > , NoSolution > {
167+ let cx = ecx. cx ( ) ;
167168 if goal. predicate . polarity != ty:: PredicatePolarity :: Positive {
168169 return Err ( NoSolution ) ;
169170 }
@@ -174,20 +175,37 @@ where
174175
175176 // Only consider auto impls of unsafe traits when there are no unsafe
176177 // fields.
177- if ecx . cx ( ) . trait_is_unsafe ( goal. predicate . def_id ( ) )
178+ if cx . trait_is_unsafe ( goal. predicate . def_id ( ) )
178179 && goal. predicate . self_ty ( ) . has_unsafe_fields ( )
179180 {
180181 return Err ( NoSolution ) ;
181182 }
182183
183- // We only look into opaque types during analysis for opaque types
184- // outside of their defining scope. Doing so for opaques in the
185- // defining scope may require calling `typeck` on the same item we're
186- // currently type checking, which will result in a fatal cycle that
187- // ideally we want to avoid, since we can make progress on this goal
188- // via an alias bound or a locally-inferred hidden type instead.
184+ // We leak the implemented auto traits of opaques outside of their defining scope.
185+ // This depends on `typeck` of the defining scope of that opaque, which may result in
186+ // fatal query cycles.
187+ //
188+ // We only get to this point if we're outside of the defining scope as we'd otherwise
189+ // be able to normalize the opaque type. We may also cycle in case `typeck` of a defining
190+ // scope relies on the current context, e.g. either because it also leaks auto trait
191+ // bounds of opaques defined in the current context or by evaluating the current item.
192+ //
193+ // To avoid this we don't try to leak auto trait bounds if they can also be proven via
194+ // item bounds of the opaque. These bounds are always applicable as auto traits must not
195+ // have any generic parameters. They would also get preferred over the impl candidate
196+ // when merging candidates anyways.
197+ //
198+ // See tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs.
189199 if let ty:: Alias ( ty:: Opaque , opaque_ty) = goal. predicate . self_ty ( ) . kind ( ) {
190200 debug_assert ! ( ecx. opaque_type_is_rigid( opaque_ty. def_id) ) ;
201+ for item_bound in cx. item_self_bounds ( opaque_ty. def_id ) . skip_binder ( ) {
202+ if item_bound
203+ . as_trait_clause ( )
204+ . is_some_and ( |b| b. def_id ( ) == goal. predicate . def_id ( ) )
205+ {
206+ return Err ( NoSolution ) ;
207+ }
208+ }
191209 }
192210
193211 ecx. probe_and_evaluate_goal_for_constituent_tys (
0 commit comments