From: lcnr Date: Mon, 4 Jul 2022 16:38:35 +0000 (+0200) Subject: don't evaluate with escaping bound vars X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=d15b00af487c356a426d08b333e64155ff386694;p=rust.git don't evaluate with escaping bound vars --- 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 @@ fn consts( } } } - 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 @@ fn consts( } } } - 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 @@ fn try_eval_inner( param_env: ParamEnv<'tcx>, eval_mode: EvalMode, ) -> Option, 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 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'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>, } +/// 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>, + 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::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 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result, Self::Error> { 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 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result, Self::Error> { 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 @@ fn try_fold_const( constant: ty::Const<'tcx>, ) -> Result, 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(