Rollup merge of #149345 - adwinwhite:next-166, r=lcnr

Deeply normalize param env in `compare_impl_item` if using the next solver

Fixes https://github.com/rust-lang/trait-system-refactor-initiative/issues/166.

Duplicated the `normalize_param_env_or_error` function to force deep normalization for `compare_impl_item`.

r? `@lcnr`
This commit is contained in:
Matthias Krüger 2025-11-27 15:59:14 +01:00 committed by GitHub
commit a8cf0c7080
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 134 additions and 2 deletions

View file

@ -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());

View file

@ -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*,

View file

@ -1,4 +1,6 @@
//@ check-pass
//@ revisions: old next
//@[next] compile-flags: -Znext-solver
struct Foo<'a> {
foo: &'a mut usize,

View file

@ -1,4 +1,6 @@
//@ check-pass
//@ revisions: old next
//@[next] compile-flags: -Znext-solver
pub trait BufferTrait<'buffer> {
type Subset<'channel>

View file

@ -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<T> {}
trait Entailment<T: Trait> {
fn method()
where
Self: for<'a> Bound<<T as Trait>::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() {}

View file

@ -1,3 +1,11 @@
error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc == _`
--> $DIR/normalize-param-env-2.rs:22:5
|
LL | / fn f()
LL | | where
LL | | Self::Assoc: A<T>,
| |__________________________^
error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: A<T>`
--> $DIR/normalize-param-env-2.rs:24:22
|
@ -46,6 +54,6 @@ LL | where
LL | Self::Assoc: A<T>,
| ^^^^ 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`.