@@ -164,6 +164,7 @@ where
164
164
ecx : & mut EvalCtxt < ' _ , D > ,
165
165
goal : Goal < I , Self > ,
166
166
) -> Result < Candidate < I > , NoSolution > {
167
+ let cx = ecx. cx ( ) ;
167
168
if goal. predicate . polarity != ty:: PredicatePolarity :: Positive {
168
169
return Err ( NoSolution ) ;
169
170
}
@@ -174,20 +175,37 @@ where
174
175
175
176
// Only consider auto impls of unsafe traits when there are no unsafe
176
177
// fields.
177
- if ecx . cx ( ) . trait_is_unsafe ( goal. predicate . def_id ( ) )
178
+ if cx . trait_is_unsafe ( goal. predicate . def_id ( ) )
178
179
&& goal. predicate . self_ty ( ) . has_unsafe_fields ( )
179
180
{
180
181
return Err ( NoSolution ) ;
181
182
}
182
183
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.
189
199
if let ty:: Alias ( ty:: Opaque , opaque_ty) = goal. predicate . self_ty ( ) . kind ( ) {
190
200
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
+ }
191
209
}
192
210
193
211
ecx. probe_and_evaluate_goal_for_constituent_tys (
0 commit comments