move hack to normalize_param_env_or_error

This commit is contained in:
Boxy 2023-05-31 02:13:47 +01:00
parent 9610dfe5a9
commit 1e9b69bf3f
2 changed files with 57 additions and 14 deletions

View File

@ -589,17 +589,6 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>(
debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b);
let tcx = relation.tcx();
// HACK(const_generics): We still need to eagerly evaluate consts when
// relating them because during `normalize_param_env_or_error`,
// we may relate an evaluated constant in a obligation against
// an unnormalized (i.e. unevaluated) const in the param-env.
// FIXME(generic_const_exprs): Once we always lazily unify unevaluated constants
// these `eval` calls can be removed.
if !tcx.features().generic_const_exprs {
a = a.eval(tcx, relation.param_env());
b = b.eval(tcx, relation.param_env());
}
if tcx.features().generic_const_exprs {
a = tcx.expand_abstract_consts(a);
b = tcx.expand_abstract_consts(b);

View File

@ -32,7 +32,7 @@
use rustc_middle::query::Providers;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFolder, TypeSuperVisitable};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_span::def_id::DefId;
use rustc_span::Span;
@ -272,8 +272,62 @@ pub fn normalize_param_env_or_error<'tcx>(
// parameter environments once for every fn as it goes,
// and errors will get reported then; so outside of type inference we
// can be sure that no errors should occur.
let mut predicates: Vec<_> =
util::elaborate(tcx, unnormalized_env.caller_bounds().into_iter()).collect();
let mut predicates: Vec<_> = util::elaborate(
tcx,
unnormalized_env.caller_bounds().into_iter().map(|predicate| {
if tcx.features().generic_const_exprs {
return predicate;
}
struct ConstNormalizer<'tcx>(TyCtxt<'tcx>);
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ConstNormalizer<'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
self.0
}
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
// While it is pretty sus to be evaluating things with an empty param env, it
// should actually be okay since without `feature(generic_const_exprs)` the only
// const arguments that have a non-empty param env are array repeat counts. These
// do not appear in the type system though.
c.eval(self.0, ty::ParamEnv::empty())
}
}
// This whole normalization step is a hack to work around the fact that
// `normalize_param_env_or_error` is fundamentally broken from using an
// unnormalized param env with a trait solver that expects the param env
// to be normalized.
//
// When normalizing the param env we can end up evaluating obligations
// that have been normalized but can only be proven via a where clause
// which is still in its unnormalized form. example:
//
// Attempting to prove `T: Trait<<u8 as Identity>::Assoc>` in a param env
// with a `T: Trait<<u8 as Identity>::Assoc>` where clause will fail because
// we first normalize obligations before proving them so we end up proving
// `T: Trait<u8>`. Since lazy normalization is not implemented equating `u8`
// with `<u8 as Identity>::Assoc` fails outright so we incorrectly believe that
// we cannot prove `T: Trait<u8>`.
//
// The same thing is true for const generics- attempting to prove
// `T: Trait<ConstKind::Unevaluated(...)>` with the same thing as a where clauses
// will fail. After normalization we may be attempting to prove `T: Trait<4>` with
// the unnormalized where clause `T: Trait<ConstKind::Unevaluated(...)>`. In order
// for the obligation to hold `4` must be equal to `ConstKind::Unevaluated(...)`
// but as we do not have lazy norm implemented, equating the two consts fails outright.
//
// Ideally we would not normalize consts here at all but it is required for backwards
// compatibility. Eventually when lazy norm is implemented this can just be removed.
// We do not normalize types here as there is no backwards compatibility requirement
// for us to do so.
//
// FIXME(-Ztrait-solver=next): remove this hack since we have deferred projection equality
predicate.fold_with(&mut ConstNormalizer(tcx))
}),
)
.collect();
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);