Skip to content

Commit de49a9f

Browse files
Rollup merge of #112825 - compiler-errors:tait-defining-cycle, r=lcnr
Don't call `type_of` on TAIT in defining scope in new solver It's *never* productive to call `consider_auto_trait_candidate` on a TAIT in the defining scope, since it will always lead to a query cycle since we call `type_of` on the TAIT. So let's just don't. I've reserved this behavior just to `SolverMode::Normal` just to avoid any future problems, since this is *technically* incomplete since we're discarding a candidate that could *theoretically* apply. But given such candidate assembly *always* leads to a query cycle, I think it's relatively low risk, and I could be convinced otherwise and make this apply to both solver mode. I assume it's far less likely to be encountered in coherence, though. This is much more likely to encounter in the new solver, though it can also be encountered in the old solver too, so I'm happy to discuss whether this new behavior we even want in the first place... I encountered this in a couple of failing UI tests: * `tests/ui/type-alias-impl-trait/issue-62000-associate-impl-trait-lifetimes.rs` * `tests/ui/type-alias-impl-trait/issue-93411.rs` r? `@lcnr`
2 parents 75febc6 + 388c230 commit de49a9f

File tree

6 files changed

+67
-101
lines changed

6 files changed

+67
-101
lines changed

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -837,7 +837,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
837837
}
838838
}
839839

840-
pub(super) fn can_define_opaque_ty(&mut self, def_id: LocalDefId) -> bool {
840+
pub(super) fn can_define_opaque_ty(&self, def_id: LocalDefId) -> bool {
841841
self.infcx.opaque_type_origin(def_id).is_some()
842842
}
843843

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+27
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_hir::{LangItem, Movability};
77
use rustc_infer::traits::query::NoSolution;
88
use rustc_infer::traits::util::supertraits;
99
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, QueryResult};
10+
use rustc_middle::traits::Reveal;
1011
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
1112
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
1213
use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
@@ -118,6 +119,32 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
118119
return result;
119120
}
120121

122+
// Don't call `type_of` on a local TAIT that's in the defining scope,
123+
// since that may require calling `typeck` on the same item we're
124+
// currently type checking, which will result in a fatal cycle that
125+
// ideally we want to avoid, since we can make progress on this goal
126+
// via an alias bound or a locally-inferred hidden type instead.
127+
//
128+
// Also, don't call `type_of` on a TAIT in `Reveal::All` mode, since
129+
// we already normalize the self type in
130+
// `assemble_candidates_after_normalizing_self_ty`, and we'd
131+
// just be registering an identical candidate here.
132+
//
133+
// Returning `Err(NoSolution)` here is ok in `SolverMode::Coherence`
134+
// since we'll always be registering an ambiguous candidate in
135+
// `assemble_candidates_after_normalizing_self_ty` due to normalizing
136+
// the TAIT.
137+
if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
138+
if matches!(goal.param_env.reveal(), Reveal::All)
139+
|| opaque_ty
140+
.def_id
141+
.as_local()
142+
.is_some_and(|def_id| ecx.can_define_opaque_ty(def_id))
143+
{
144+
return Err(NoSolution);
145+
}
146+
}
147+
121148
ecx.probe_and_evaluate_goal_for_constituent_tys(
122149
goal,
123150
structural_traits::instantiate_constituent_tys_for_auto_trait,

tests/ui/traits/new-solver/dont-remap-tait-substs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// compile-flags: -Ztrait-solver=next
2-
// known-bug: #112825
2+
// check-pass
33

44
// Makes sure we don't prepopulate the MIR typeck of `define`
55
// with `Foo<T, U> = T`, but instead, `Foo<B, A> = B`, so that

tests/ui/traits/new-solver/dont-remap-tait-substs.stderr

-99
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0283]: type annotations needed: cannot satisfy `Foo: Send`
2+
--> $DIR/dont-type_of-tait-in-defining-scope.rs:16:5
3+
|
4+
LL | needs_send::<Foo>();
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: cannot satisfy `Foo: Send`
8+
note: required by a bound in `needs_send`
9+
--> $DIR/dont-type_of-tait-in-defining-scope.rs:13:18
10+
|
11+
LL | fn needs_send<T: Send>() {}
12+
| ^^^^ required by this bound in `needs_send`
13+
14+
error: aborting due to previous error
15+
16+
For more information about this error, try `rustc --explain E0283`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// revisions: is_send not_send
2+
// compile-flags: -Ztrait-solver=next
3+
//[is_send] check-pass
4+
5+
#![feature(type_alias_impl_trait)]
6+
7+
#[cfg(is_send)]
8+
type Foo = impl Send;
9+
10+
#[cfg(not_send)]
11+
type Foo = impl Sized;
12+
13+
fn needs_send<T: Send>() {}
14+
15+
fn test() {
16+
needs_send::<Foo>();
17+
//[not_send]~^ ERROR type annotations needed: cannot satisfy `Foo: Send`
18+
}
19+
20+
fn main() {
21+
let _: Foo = ();
22+
}

0 commit comments

Comments
 (0)