diff options
| -rw-r--r-- | compiler/rustc_infer/src/infer/combine.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/consts/kind.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/project.rs | 48 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/query/normalize.rs | 19 |
4 files changed, 57 insertions, 19 deletions
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 644c92ed0e5..c1fb59009d3 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -743,9 +743,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) - if self.tcx().lazy_normalization() => - { + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { assert_eq!(promoted, None); let substs = self.relate_with_variance( ty::Variance::Invariant, @@ -967,9 +965,7 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) - if self.tcx().lazy_normalization() => - { + ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { assert_eq!(promoted, None); let substs = self.relate_with_variance( ty::Variance::Invariant, diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 3840e79cebd..ff20da65c01 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -180,6 +180,7 @@ impl<'tcx> ConstKind<'tcx> { param_env: ParamEnv<'tcx>, eval_mode: EvalMode, ) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> { + assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); if let ConstKind::Unevaluated(unevaluated) = self { use crate::mir::interpret::ErrorHandled; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 1d9468a96b6..8a093bf4281 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -635,13 +635,18 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { #[instrument(skip(self), level = "debug")] fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { - if self.selcx.tcx().lazy_normalization() { + let tcx = self.selcx.tcx(); + if tcx.lazy_normalization() { constant } else { let constant = constant.super_fold_with(self); - debug!(?constant); - debug!("self.param_env: {:?}", self.param_env); - constant.eval(self.selcx.tcx(), self.param_env) + debug!(?constant, ?self.param_env); + with_replaced_escaping_bound_vars( + self.selcx.infcx(), + &mut self.universes, + constant, + |constant| constant.eval(tcx, self.param_env), + ) } } @@ -671,6 +676,41 @@ pub struct BoundVarReplacer<'me, 'tcx> { universe_indices: &'me mut Vec<Option<ty::UniverseIndex>>, } +/// Executes `f` on `value` after replacing all escaping bound variables with placeholders +/// and then replaces these placeholders with the original bound variables in the result. +/// +/// In most places, bound variables should be replaced right when entering a binder, making +/// this function unnecessary. However, normalization currently does not do that, so we have +/// to do this lazily. +/// +/// You should not add any additional uses of this function, at least not without first +/// discussing it with t-types. +/// +/// FIXME(@lcnr): We may even consider experimenting with eagerly replacing bound vars during +/// normalization as well, at which point this function will be unnecessary and can be removed. +pub fn with_replaced_escaping_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>, R: TypeFoldable<'tcx>>( + infcx: &'a InferCtxt<'a, 'tcx>, + universe_indices: &'a mut Vec<Option<ty::UniverseIndex>>, + value: T, + f: impl FnOnce(T) -> R, +) -> R { + if value.has_escaping_bound_vars() { + let (value, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, universe_indices, value); + let result = f(value); + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + universe_indices, + result, + ) + } else { + f(value) + } +} + impl<'me, 'tcx> BoundVarReplacer<'me, 'tcx> { /// Returns `Some` if we *were* able to replace bound vars. If there are any bound vars that /// use a binding level above `universe_indices.len()`, we fail. diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 61c556b726d..f65fc5bad0d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -6,7 +6,7 @@ use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::InferCtxtExt; -use crate::traits::project::needs_normalization; +use crate::traits::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -283,11 +283,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let tcx = self.infcx.tcx; let infcx = self.infcx; let (data, mapped_regions, mapped_types, mapped_consts) = - crate::traits::project::BoundVarReplacer::replace_bound_vars( - infcx, - &mut self.universes, - data, - ); + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); let data = data.try_fold_with(self)?; let mut orig_values = OriginalQueryValues::default(); @@ -313,8 +309,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { debug!("QueryNormalizer: result = {:#?}", result); debug!("QueryNormalizer: obligations = {:#?}", obligations); self.obligations.extend(obligations); - - let res = crate::traits::project::PlaceholderReplacer::replace_placeholders( + let res = PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, mapped_types, @@ -343,7 +338,13 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { constant: ty::Const<'tcx>, ) -> Result<ty::Const<'tcx>, Self::Error> { let constant = constant.try_super_fold_with(self)?; - Ok(constant.eval(self.infcx.tcx, self.param_env)) + debug!(?constant, ?self.param_env); + Ok(crate::traits::project::with_replaced_escaping_bound_vars( + self.infcx, + &mut self.universes, + constant, + |constant| constant.eval(self.infcx.tcx, self.param_env), + )) } fn try_fold_mir_const( |
