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 d27d80a086ad1..0f556aea90d73 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -197,6 +197,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>; @@ -532,8 +533,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 2837b8565f603..0c17962b066ea 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 70c28421c57ea..adbfa394847ff 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 @@ -396,9 +396,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 651f073efb828..ad69c2dd164ab 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -121,6 +121,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 e8f94c8e7cc92..67cc82346941a 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -462,6 +462,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 c4293579aea8e..4a3789b2c2b02 100644 --- a/tests/ui/traits/const-traits/call-const-closure.rs +++ b/tests/ui/traits/const-traits/call-const-closure.rs @@ -15,7 +15,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 9a851a97f186a..47ff68005420e 100644 --- a/tests/ui/traits/const-traits/call-const-closure.stderr +++ b/tests/ui/traits/const-traits/call-const-closure.stderr @@ -9,6 +9,12 @@ help: make the `impl` of trait `Bar` `const` LL | impl const Bar for () { | +++++ -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`.