diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 6a07d2988fdfc..fa497cc21e40d 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -236,7 +236,26 @@ fn compare_method_predicate_entailment<'tcx>( let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_def_id); let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds)); - let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); + // FIXME(-Zhigher-ranked-assumptions): The `hybrid_preds` + // should be well-formed. However, using them may result in + // region errors as we currently don't track placeholder + // assumptions. + // + // To avoid being backwards incompatible with the old solver, + // we also eagerly normalize the where-bounds in the new solver + // here while ignoring region constraints. This means we can then + // use where-bounds whose normalization results in placeholder + // errors further down without getting any errors. + // + // It should be sound to do so as the only region errors here + // should be due to missing implied bounds. + // + // cc trait-system-refactor-initiative/issues/166. + let param_env = if tcx.next_trait_solver_globally() { + traits::deeply_normalize_param_env_ignoring_regions(tcx, param_env, normalize_cause) + } else { + traits::normalize_param_env_or_error(tcx, param_env, normalize_cause) + }; debug!(caller_bounds=?param_env.caller_bounds()); let infcx = &tcx.infer_ctxt().build(TypingMode::non_body_analysis()); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 6032bcacec6a4..c9f7237b123fb 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -477,6 +477,69 @@ pub fn normalize_param_env_or_error<'tcx>( ty::ParamEnv::new(tcx.mk_clauses(&predicates)) } +/// Deeply normalize the param env using the next solver ignoring +/// region errors. +/// +/// FIXME(-Zhigher-ranked-assumptions): this is a hack to work around +/// the fact that we don't support placeholder assumptions right now +/// and is necessary for `compare_method_predicate_entailment`, see the +/// use of this function for more info. We should remove this once we +/// have proper support for implied bounds on binders. +#[instrument(level = "debug", skip(tcx))] +pub fn deeply_normalize_param_env_ignoring_regions<'tcx>( + tcx: TyCtxt<'tcx>, + unnormalized_env: ty::ParamEnv<'tcx>, + cause: ObligationCause<'tcx>, +) -> ty::ParamEnv<'tcx> { + let predicates: Vec<_> = + util::elaborate(tcx, unnormalized_env.caller_bounds().into_iter()).collect(); + + debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); + + let elaborated_env = ty::ParamEnv::new(tcx.mk_clauses(&predicates)); + if !elaborated_env.has_aliases() { + return elaborated_env; + } + + let span = cause.span; + let infcx = tcx + .infer_ctxt() + .with_next_trait_solver(true) + .ignoring_regions() + .build(TypingMode::non_body_analysis()); + let predicates = match crate::solve::deeply_normalize::<_, FulfillmentError<'tcx>>( + infcx.at(&cause, elaborated_env), + predicates, + ) { + Ok(predicates) => predicates, + Err(errors) => { + infcx.err_ctxt().report_fulfillment_errors(errors); + // An unnormalized env is better than nothing. + debug!("normalize_param_env_or_error: errored resolving predicates"); + return elaborated_env; + } + }; + + debug!("do_normalize_predicates: normalized predicates = {:?}", predicates); + // FIXME(-Zhigher-ranked-assumptions): We're ignoring region errors for now. + // There're placeholder constraints `leaking` out. + // See the fixme in the enclosing function's docs for more. + let _errors = infcx.resolve_regions(cause.body_id, elaborated_env, []); + + let predicates = match infcx.fully_resolve(predicates) { + Ok(predicates) => predicates, + Err(fixup_err) => { + span_bug!( + span, + "inference variables in normalized parameter environment: {}", + fixup_err + ) + } + }; + debug!("normalize_param_env_or_error: final predicates={:?}", predicates); + ty::ParamEnv::new(tcx.mk_clauses(&predicates)) +} + #[derive(Debug)] pub enum EvaluateConstErr { /// The constant being evaluated was either a generic parameter or inference variable, *or*, diff --git a/tests/ui/higher-ranked/trait-bounds/issue-100689.rs b/tests/ui/higher-ranked/trait-bounds/issue-100689.rs index f405abfb2a2ef..6bfad56b93d29 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-100689.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-100689.rs @@ -1,4 +1,6 @@ //@ check-pass +//@ revisions: old next +//@[next] compile-flags: -Znext-solver struct Foo<'a> { foo: &'a mut usize, diff --git a/tests/ui/higher-ranked/trait-bounds/issue-102899.rs b/tests/ui/higher-ranked/trait-bounds/issue-102899.rs index b4ef75319e5c1..77d4d0179b1ba 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-102899.rs +++ b/tests/ui/higher-ranked/trait-bounds/issue-102899.rs @@ -1,4 +1,6 @@ //@ check-pass +//@ revisions: old next +//@[next] compile-flags: -Znext-solver pub trait BufferTrait<'buffer> { type Subset<'channel> diff --git a/tests/ui/traits/next-solver/normalize/deeply-normalize-env-in-compare-impl-item.rs b/tests/ui/traits/next-solver/normalize/deeply-normalize-env-in-compare-impl-item.rs new file mode 100644 index 0000000000000..e68f82da88af8 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/deeply-normalize-env-in-compare-impl-item.rs @@ -0,0 +1,38 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +// See trait-system-refactor-initiative/issues/166. +// The old solver doesn't check normalization constraints in `compare_impl_item`. +// The new solver performs lazy normalization so those region constraints may get postponed to +// an infcx that considers regions. +trait Trait { + type Assoc<'a> + where + Self: 'a; +} +impl<'b> Trait for &'b u32 { + type Assoc<'a> = &'a u32 + where + Self: 'a; +} + +trait Bound {} +trait Entailment { + fn method() + where + Self: for<'a> Bound<::Assoc<'a>>; +} + +impl<'b, T> Entailment<&'b u32> for T { + // Instantiates trait where-clauses with `&'b u32` and then normalizes + // `T: for<'a> Bound<<&'b u32 as Trait>::Assoc<'a>>` in a separate infcx + // without checking region constraints. + // + // It normalizes to `T: Bound<&'a u32>`, dropping the `&'b u32: 'a` constraint. + fn method() + where + Self: for<'a> Bound<&'a u32> + {} +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr index d179c80596238..82a5f33628e61 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr @@ -1,3 +1,11 @@ +error[E0275]: overflow evaluating the requirement `<() as A>::Assoc == _` + --> $DIR/normalize-param-env-2.rs:22:5 + | +LL | / fn f() +LL | | where +LL | | Self::Assoc: A, + | |__________________________^ + error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` --> $DIR/normalize-param-env-2.rs:24:22 | @@ -46,6 +54,6 @@ LL | where LL | Self::Assoc: A, | ^^^^ required by this bound in `A::f` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0275`.