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(
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)