diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 156dfc4fc1e69..0ca31272fdfec 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -1526,7 +1526,7 @@ where ) -> QueryResultOrRerunNonErased { self.inspect.make_canonical_response(shallow_certainty); - let goals_certainty = self.try_evaluate_added_goals()?; + let added_goals_certainty = self.try_evaluate_added_goals()?; assert_eq!( self.tainted, Ok(()), @@ -1534,11 +1534,8 @@ where previous call to `try_evaluate_added_goals!`" ); - let goals_certainty = match self.delegate.cx().assumptions_on_binders() { - true => { - let certainty = self.eagerly_handle_placeholders()?; - certainty.and(goals_certainty) - } + let placeholder_certainty = match self.delegate.cx().assumptions_on_binders() { + true => self.eagerly_handle_placeholders()?, false => { // We only check for leaks from universes which were entered inside // of the query. @@ -1547,9 +1544,10 @@ where NoSolution })?; - goals_certainty + Certainty::Yes } }; + let goals_certainty = placeholder_certainty.and(added_goals_certainty); let (certainty, normalization_nested_goals) = match (self.current_goal_kind, shallow_certainty) { @@ -1563,12 +1561,13 @@ where (CurrentGoalKind::ProjectionComputeAssocTermCandidate, Certainty::Yes) => { let goals = std::mem::take(&mut self.nested_goals); // As we return all ambiguous nested goals, we can ignore the certainty - // returned by `self.try_evaluate_added_goals()`. + // returned by `self.try_evaluate_added_goals()`. However, placeholder + // handling may independently be ambiguous, so preserve its certainty. if goals.is_empty() { - assert!(matches!(goals_certainty, Certainty::Yes)); + assert!(matches!(added_goals_certainty, Certainty::Yes)); } ( - Certainty::Yes, + placeholder_certainty, NestedNormalizationGoals( goals.into_iter().map(|(s, g, _)| (s, g)).collect(), ), diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index c63b7773739d0..4242f475c5a9e 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -5,9 +5,11 @@ use rustc_infer::infer::{ InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt, TypeOutlivesConstraint, }; use rustc_macros::extension; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, elaborate}; +use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode, Unnormalized, elaborate}; use rustc_span::DUMMY_SP; +use crate::traits::ScrubbedTraitError; use crate::traits::outlives_bounds::InferCtxtExt; #[extension(pub trait OutlivesEnvironmentBuildExt<'tcx>)] @@ -31,8 +33,19 @@ impl<'tcx> OutlivesEnvironment<'tcx> { let mut bounds = vec![]; for bound in param_env.caller_bounds() { - if let Some(type_outlives) = bound.as_type_outlives_clause() { - debug_assert!(!infcx.next_trait_solver() || !type_outlives.has_non_rigid_aliases()); + if let Some(mut type_outlives) = bound.as_type_outlives_clause() { + if infcx.next_trait_solver() { + match crate::solve::deeply_normalize::<_, ScrubbedTraitError<'tcx>>( + infcx.at(&ObligationCause::dummy(), param_env), + Unnormalized::new_wip(type_outlives), + ) { + Ok(normalized) => type_outlives = normalized, + Err(_) => { + infcx.dcx().delayed_bug(format!("could not normalize `{bound}`")); + } + } + } + bounds.push(type_outlives); } } diff --git a/tests/ui/assumptions_on_binders/ambiguous-placeholder-certainty-issue-159896.rs b/tests/ui/assumptions_on_binders/ambiguous-placeholder-certainty-issue-159896.rs new file mode 100644 index 0000000000000..afe7b1808a96b --- /dev/null +++ b/tests/ui/assumptions_on_binders/ambiguous-placeholder-certainty-issue-159896.rs @@ -0,0 +1,28 @@ +// Regression test for issue #159896. +// +// An ambiguous result from eagerly handling placeholders must be preserved +// when returning nested normalization goals, instead of causing an ICE. + +//@ check-fail +//@ dont-check-compiler-stderr +//@ dont-require-annotations: ERROR +//@ compile-flags: -Znext-solver=globally -Zassumptions-on-binders +//@ edition: 2021 + +#![feature(type_alias_impl_trait)] + +type FooArg<'a> = &'a impl Iterator; +type FooRet = impl Iterator; +type FooItem = Box FooRet>; + +struct Bar; + +impl Iterator for Bar { + type Item = FooItem; + + fn next(&mut self) -> Option { + todo!() + } +} + +fn main() {}