Skip to content

Commit d15b00a

Browse files
committed
don't evaluate with escaping bound vars
1 parent 01adb7e commit d15b00a

File tree

4 files changed

+57
-19
lines changed

4 files changed

+57
-19
lines changed

compiler/rustc_infer/src/infer/combine.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -743,9 +743,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
743743
}
744744
}
745745
}
746-
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
747-
if self.tcx().lazy_normalization() =>
748-
{
746+
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
749747
assert_eq!(promoted, None);
750748
let substs = self.relate_with_variance(
751749
ty::Variance::Invariant,
@@ -967,9 +965,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
967965
}
968966
}
969967
}
970-
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
971-
if self.tcx().lazy_normalization() =>
972-
{
968+
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
973969
assert_eq!(promoted, None);
974970
let substs = self.relate_with_variance(
975971
ty::Variance::Invariant,

compiler/rustc_middle/src/ty/consts/kind.rs

+1
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ impl<'tcx> ConstKind<'tcx> {
180180
param_env: ParamEnv<'tcx>,
181181
eval_mode: EvalMode,
182182
) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
183+
assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}");
183184
if let ConstKind::Unevaluated(unevaluated) = self {
184185
use crate::mir::interpret::ErrorHandled;
185186

compiler/rustc_trait_selection/src/traits/project.rs

+44-4
Original file line numberDiff line numberDiff line change
@@ -635,13 +635,18 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
635635

636636
#[instrument(skip(self), level = "debug")]
637637
fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
638-
if self.selcx.tcx().lazy_normalization() {
638+
let tcx = self.selcx.tcx();
639+
if tcx.lazy_normalization() {
639640
constant
640641
} else {
641642
let constant = constant.super_fold_with(self);
642-
debug!(?constant);
643-
debug!("self.param_env: {:?}", self.param_env);
644-
constant.eval(self.selcx.tcx(), self.param_env)
643+
debug!(?constant, ?self.param_env);
644+
with_replaced_escaping_bound_vars(
645+
self.selcx.infcx(),
646+
&mut self.universes,
647+
constant,
648+
|constant| constant.eval(tcx, self.param_env),
649+
)
645650
}
646651
}
647652

@@ -671,6 +676,41 @@ pub struct BoundVarReplacer<'me, 'tcx> {
671676
universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>,
672677
}
673678

679+
/// Executes `f` on `value` after replacing all escaping bound variables with placeholders
680+
/// and then replaces these placeholders with the original bound variables in the result.
681+
///
682+
/// In most places, bound variables should be replaced right when entering a binder, making
683+
/// this function unnecessary. However, normalization currently does not do that, so we have
684+
/// to do this lazily.
685+
///
686+
/// You should not add any additional uses of this function, at least not without first
687+
/// discussing it with t-types.
688+
///
689+
/// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during
690+
/// normalization as well, at which point this function will be unnecessary and can be removed.
691+
pub fn with_replaced_escaping_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>, R: TypeFoldable<'tcx>>(
692+
infcx: &'a InferCtxt<'a, 'tcx>,
693+
universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>,
694+
value: T,
695+
f: impl FnOnce(T) -> R,
696+
) -> R {
697+
if value.has_escaping_bound_vars() {
698+
let (value, mapped_regions, mapped_types, mapped_consts) =
699+
BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value);
700+
let result = f(value);
701+
PlaceholderReplacer::replace_placeholders(
702+
infcx,
703+
mapped_regions,
704+
mapped_types,
705+
mapped_consts,
706+
universe_indices,
707+
result,
708+
)
709+
} else {
710+
f(value)
711+
}
712+
}
713+
674714
impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> {
675715
/// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that
676716
/// use a binding level above `universe_indices.len()`, we fail.

compiler/rustc_trait_selection/src/traits/query/normalize.rs

+10-9
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::infer::at::At;
66
use crate::infer::canonical::OriginalQueryValues;
77
use crate::infer::{InferCtxt, InferOk};
88
use crate::traits::error_reporting::InferCtxtExt;
9-
use crate::traits::project::needs_normalization;
9+
use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer};
1010
use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
1111
use rustc_data_structures::sso::SsoHashMap;
1212
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -283,11 +283,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
283283
let tcx = self.infcx.tcx;
284284
let infcx = self.infcx;
285285
let (data, mapped_regions, mapped_types, mapped_consts) =
286-
crate::traits::project::BoundVarReplacer::replace_bound_vars(
287-
infcx,
288-
&mut self.universes,
289-
data,
290-
);
286+
BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
291287
let data = data.try_fold_with(self)?;
292288

293289
let mut orig_values = OriginalQueryValues::default();
@@ -313,8 +309,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
313309
debug!("QueryNormalizer: result = {:#?}", result);
314310
debug!("QueryNormalizer: obligations = {:#?}", obligations);
315311
self.obligations.extend(obligations);
316-
317-
let res = crate::traits::project::PlaceholderReplacer::replace_placeholders(
312+
let res = PlaceholderReplacer::replace_placeholders(
318313
infcx,
319314
mapped_regions,
320315
mapped_types,
@@ -343,7 +338,13 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
343338
constant: ty::Const<'tcx>,
344339
) -> Result<ty::Const<'tcx>, Self::Error> {
345340
let constant = constant.try_super_fold_with(self)?;
346-
Ok(constant.eval(self.infcx.tcx, self.param_env))
341+
debug!(?constant, ?self.param_env);
342+
Ok(crate::traits::project::with_replaced_escaping_bound_vars(
343+
self.infcx,
344+
&mut self.universes,
345+
constant,
346+
|constant| constant.eval(self.infcx.tcx, self.param_env),
347+
))
347348
}
348349

349350
fn try_fold_mir_const(

0 commit comments

Comments
 (0)