Skip to content

Commit 8118fca

Browse files
authored
Rollup merge of #139789 - lcnr:opaques-auto-trait-leakage, r=compiler-errors
do not unnecessarily leak auto traits in item bounds fixes rust-lang/trait-system-refactor-initiative#158 Not a fix for rust-lang/trait-system-refactor-initiative#173 as you may have realized/tried yourself, cc #139788. However, fixing this feels desirable regardless and I don't see any reason not to. r? ```@compiler-errors```
2 parents 5a9455f + 836ea25 commit 8118fca

16 files changed

+285
-7
lines changed

compiler/rustc_next_trait_solver/src/solve/trait_goals.rs

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)