From d7b1e4681b3018d7c50d80431d0c60784dd59e3b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 15 Sep 2025 12:51:57 -0400 Subject: [PATCH] Dont bail in error predicate unless self ty is error --- .../src/solve/assembly/mod.rs | 5 +++-- .../src/solve/effect_goals.rs | 1 + .../src/solve/normalizes_to/mod.rs | 12 ++++++++++-- .../rustc_next_trait_solver/src/solve/trait_goals.rs | 1 + compiler/rustc_type_ir/src/ty_kind/closure.rs | 9 +++++++++ tests/ui/traits/const-traits/call-const-closure.rs | 2 +- .../ui/traits/const-traits/call-const-closure.stderr | 8 +++++++- 7 files changed, 32 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index fb777496e31eb..7543bcb09bcc4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -199,6 +199,7 @@ where /// but prevents incorrect normalization while hiding any trait errors. fn consider_error_guaranteed_candidate( ecx: &mut EvalCtxt<'_, D>, + goal: Goal, guar: I::ErrorGuaranteed, ) -> Result, NoSolution>; @@ -522,8 +523,8 @@ where // Instead of adding the logic here, it's a better idea to add it in // `EvalCtxt::disqualify_auto_trait_candidate_due_to_possible_impl` in // `solve::trait_goals` instead. - let result = if let Err(guar) = goal.predicate.error_reported() { - G::consider_error_guaranteed_candidate(self, guar) + let result = if let ty::Error(guar) = goal.predicate.self_ty().kind() { + G::consider_error_guaranteed_candidate(self, goal, guar) } else if cx.trait_is_auto(trait_def_id) { G::consider_auto_trait_candidate(self, goal) } else if cx.trait_is_alias(trait_def_id) { diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index cb72c1cd92b84..42a55f29f4a0c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -182,6 +182,7 @@ where fn consider_error_guaranteed_candidate( ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, _guar: I::ErrorGuaranteed, ) -> Result, NoSolution> { ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 54b92ebac1ded..5bbeeca5f998d 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -391,9 +391,17 @@ where /// Fail to normalize if the predicate contains an error, alternatively, we could normalize to `ty::Error` /// and succeed. Can experiment with this to figure out what results in better error messages. fn consider_error_guaranteed_candidate( - _ecx: &mut EvalCtxt<'_, D>, - _guar: I::ErrorGuaranteed, + ecx: &mut EvalCtxt<'_, D>, + goal: Goal, + guar: I::ErrorGuaranteed, ) -> Result, NoSolution> { + let cx = ecx.cx(); + let error_term = match goal.predicate.alias.kind(cx) { + ty::AliasTermKind::ProjectionTy => Ty::new_error(cx, guar).into(), + ty::AliasTermKind::ProjectionConst => Const::new_error(cx, guar).into(), + kind => panic!("expected projection, found {kind:?}"), + }; + ecx.instantiate_normalizes_to_term(goal, error_term); Err(NoSolution) } diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index a69e867289cee..609e4a4b2c60a 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -119,6 +119,7 @@ where fn consider_error_guaranteed_candidate( ecx: &mut EvalCtxt<'_, D>, + _goal: Goal, _guar: I::ErrorGuaranteed, ) -> Result, NoSolution> { ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index 3a6d1acfa8d93..e9691bfa11d83 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -459,6 +459,15 @@ impl CoroutineClosureSignature { coroutine_captures_by_ref_ty: I::Ty, env_region: I::Region, ) -> I::Ty { + // If either of the tupled capture types are constrained to error + // (e.g. during typeck when the infcx is tainted), then just return + // the error type directly. + if let ty::Error(_) = tupled_inputs_ty.kind() { + return tupled_inputs_ty; + } else if let ty::Error(_) = coroutine_captures_by_ref_ty.kind() { + return coroutine_captures_by_ref_ty; + } + match kind { ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { let ty::FnPtr(sig_tys, _) = coroutine_captures_by_ref_ty.kind() else { diff --git a/tests/ui/traits/const-traits/call-const-closure.rs b/tests/ui/traits/const-traits/call-const-closure.rs index 70dfaf724c9bd..167992e4668a2 100644 --- a/tests/ui/traits/const-traits/call-const-closure.rs +++ b/tests/ui/traits/const-traits/call-const-closure.rs @@ -16,7 +16,7 @@ impl Bar for () { const FOO: () = { (const || ().foo())(); //~^ ERROR the trait bound `(): [const] Bar` is not satisfied - // FIXME(const_trait_impl): The constness environment for const closures is wrong. + //~| ERROR [const] Fn()` is not satisfied }; fn main() {} diff --git a/tests/ui/traits/const-traits/call-const-closure.stderr b/tests/ui/traits/const-traits/call-const-closure.stderr index 4bb8b2e9777e6..782aa4bb4d8d2 100644 --- a/tests/ui/traits/const-traits/call-const-closure.stderr +++ b/tests/ui/traits/const-traits/call-const-closure.stderr @@ -4,6 +4,12 @@ error[E0277]: the trait bound `(): [const] Bar` is not satisfied LL | (const || ().foo())(); | ^^^ -error: aborting due to 1 previous error +error[E0277]: the trait bound `{closure@$DIR/call-const-closure.rs:17:6: 17:14}: [const] Fn()` is not satisfied + --> $DIR/call-const-closure.rs:17:5 + | +LL | (const || ().foo())(); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`.