Skip to content

Commit 1e9b69b

Browse files
committed
move hack to normalize_param_env_or_error
1 parent 9610dfe commit 1e9b69b

File tree

2 files changed

+57
-14
lines changed

2 files changed

+57
-14
lines changed

Diff for: compiler/rustc_middle/src/ty/relate.rs

-11
Original file line numberDiff line numberDiff line change
@@ -589,17 +589,6 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>(
589589
debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b);
590590
let tcx = relation.tcx();
591591

592-
// HACK(const_generics): We still need to eagerly evaluate consts when
593-
// relating them because during `normalize_param_env_or_error`,
594-
// we may relate an evaluated constant in a obligation against
595-
// an unnormalized (i.e. unevaluated) const in the param-env.
596-
// FIXME(generic_const_exprs): Once we always lazily unify unevaluated constants
597-
// these `eval` calls can be removed.
598-
if !tcx.features().generic_const_exprs {
599-
a = a.eval(tcx, relation.param_env());
600-
b = b.eval(tcx, relation.param_env());
601-
}
602-
603592
if tcx.features().generic_const_exprs {
604593
a = tcx.expand_abstract_consts(a);
605594
b = tcx.expand_abstract_consts(b);

Diff for: compiler/rustc_trait_selection/src/traits/mod.rs

+57-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use rustc_errors::ErrorGuaranteed;
3232
use rustc_middle::query::Providers;
3333
use rustc_middle::ty::fold::TypeFoldable;
3434
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
35-
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
35+
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFolder, TypeSuperVisitable};
3636
use rustc_middle::ty::{InternalSubsts, SubstsRef};
3737
use rustc_span::def_id::DefId;
3838
use rustc_span::Span;
@@ -272,8 +272,62 @@ pub fn normalize_param_env_or_error<'tcx>(
272272
// parameter environments once for every fn as it goes,
273273
// and errors will get reported then; so outside of type inference we
274274
// can be sure that no errors should occur.
275-
let mut predicates: Vec<_> =
276-
util::elaborate(tcx, unnormalized_env.caller_bounds().into_iter()).collect();
275+
let mut predicates: Vec<_> = util::elaborate(
276+
tcx,
277+
unnormalized_env.caller_bounds().into_iter().map(|predicate| {
278+
if tcx.features().generic_const_exprs {
279+
return predicate;
280+
}
281+
282+
struct ConstNormalizer<'tcx>(TyCtxt<'tcx>);
283+
284+
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ConstNormalizer<'tcx> {
285+
fn interner(&self) -> TyCtxt<'tcx> {
286+
self.0
287+
}
288+
289+
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
290+
// While it is pretty sus to be evaluating things with an empty param env, it
291+
// should actually be okay since without `feature(generic_const_exprs)` the only
292+
// const arguments that have a non-empty param env are array repeat counts. These
293+
// do not appear in the type system though.
294+
c.eval(self.0, ty::ParamEnv::empty())
295+
}
296+
}
297+
298+
// This whole normalization step is a hack to work around the fact that
299+
// `normalize_param_env_or_error` is fundamentally broken from using an
300+
// unnormalized param env with a trait solver that expects the param env
301+
// to be normalized.
302+
//
303+
// When normalizing the param env we can end up evaluating obligations
304+
// that have been normalized but can only be proven via a where clause
305+
// which is still in its unnormalized form. example:
306+
//
307+
// Attempting to prove `T: Trait<<u8 as Identity>::Assoc>` in a param env
308+
// with a `T: Trait<<u8 as Identity>::Assoc>` where clause will fail because
309+
// we first normalize obligations before proving them so we end up proving
310+
// `T: Trait<u8>`. Since lazy normalization is not implemented equating `u8`
311+
// with `<u8 as Identity>::Assoc` fails outright so we incorrectly believe that
312+
// we cannot prove `T: Trait<u8>`.
313+
//
314+
// The same thing is true for const generics- attempting to prove
315+
// `T: Trait<ConstKind::Unevaluated(...)>` with the same thing as a where clauses
316+
// will fail. After normalization we may be attempting to prove `T: Trait<4>` with
317+
// the unnormalized where clause `T: Trait<ConstKind::Unevaluated(...)>`. In order
318+
// for the obligation to hold `4` must be equal to `ConstKind::Unevaluated(...)`
319+
// but as we do not have lazy norm implemented, equating the two consts fails outright.
320+
//
321+
// Ideally we would not normalize consts here at all but it is required for backwards
322+
// compatibility. Eventually when lazy norm is implemented this can just be removed.
323+
// We do not normalize types here as there is no backwards compatibility requirement
324+
// for us to do so.
325+
//
326+
// FIXME(-Ztrait-solver=next): remove this hack since we have deferred projection equality
327+
predicate.fold_with(&mut ConstNormalizer(tcx))
328+
}),
329+
)
330+
.collect();
277331

278332
debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates);
279333

0 commit comments

Comments
 (0)