diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/query')
3 files changed, 51 insertions, 23 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 449d7a7b4..40acabf62 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; @@ -48,10 +48,11 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { T: TypeFoldable<'tcx>, { debug!( - "normalize::<{}>(value={:?}, param_env={:?})", + "normalize::<{}>(value={:?}, param_env={:?}, cause={:?})", std::any::type_name::<T>(), value, self.param_env, + self.cause, ); if !needs_normalization(&value, self.param_env.reveal()) { return Ok(Normalized { value, obligations: vec![] }); @@ -266,7 +267,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { debug!("QueryNormalizer: result = {:#?}", result); debug!("QueryNormalizer: obligations = {:#?}", obligations); self.obligations.extend(obligations); - Ok(result.normalized_ty) + + let res = result.normalized_ty; + // `tcx.normalize_projection_ty` may normalize to a type that still has + // unevaluated consts, so keep normalizing here if that's the case. + if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { + Ok(res.try_super_fold_with(self)?) + } else { + Ok(res) + } } ty::Projection(data) => { @@ -275,11 +284,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(); @@ -305,18 +310,26 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { debug!("QueryNormalizer: result = {:#?}", result); debug!("QueryNormalizer: obligations = {:#?}", obligations); self.obligations.extend(obligations); - Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders( + let res = PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, mapped_types, mapped_consts, &self.universes, result.normalized_ty, - )) + ); + // `tcx.normalize_projection_ty` may normalize to a type that still has + // unevaluated consts, so keep normalizing here if that's the case. + if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { + Ok(res.try_super_fold_with(self)?) + } else { + Ok(res) + } } _ => ty.try_super_fold_with(self), })()?; + self.cache.insert(ty, res); Ok(res) } @@ -326,7 +339,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( @@ -348,7 +367,21 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { _ => mir::ConstantKind::Ty(const_folded), } } - mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(self)?, + mir::ConstantKind::Val(_, _) | mir::ConstantKind::Unevaluated(..) => { + constant.try_super_fold_with(self)? + } }) } + + #[inline] + fn try_fold_predicate( + &mut self, + p: ty::Predicate<'tcx>, + ) -> Result<ty::Predicate<'tcx>, Self::Error> { + if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { + p.try_super_fold_with(self) + } else { + Ok(p) + } + } } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index c99564936..18988861a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -1,11 +1,9 @@ use crate::infer::canonical::query_response; use crate::infer::{InferCtxt, InferOk}; -use crate::traits::engine::TraitEngineExt as _; +use crate::traits; use crate::traits::query::type_op::TypeOpOutput; use crate::traits::query::Fallible; -use crate::traits::TraitEngine; use rustc_infer::infer::region_constraints::RegionConstraintData; -use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::DUMMY_SP; use std::fmt; @@ -25,7 +23,7 @@ impl<F, G> CustomTypeOp<F, G> { } } -impl<'tcx, F, R, G> super::TypeOp<'tcx> for CustomTypeOp<F, G> +impl<'tcx, F, R: fmt::Debug, G> super::TypeOp<'tcx> for CustomTypeOp<F, G> where F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible<InferOk<'tcx, R>>, G: Fn() -> String, @@ -62,8 +60,6 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( infcx: &InferCtxt<'_, 'tcx>, op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>, ) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> { - let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx); - // During NLL, we expect that nobody will register region // obligations **except** as part of a custom type op (and, at the // end of each custom type op, we scrape out the region @@ -77,8 +73,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( ); let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; - fulfill_cx.register_predicate_obligations(infcx, obligations); - let errors = fulfill_cx.select_all_or_error(infcx); + let errors = traits::fully_solve_obligations(infcx, obligations); if !errors.is_empty() { infcx.tcx.sess.diagnostic().delay_span_bug( DUMMY_SP, @@ -94,8 +89,8 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( infcx.tcx, region_obligations .iter() - .map(|r_o| (r_o.sup_type, r_o.sub_region)) - .map(|(ty, r)| (infcx.resolve_vars_if_possible(ty), r)), + .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())) + .map(|(ty, r, cc)| (infcx.resolve_vars_if_possible(ty), r, cc)), ®ion_constraint_data, ); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 578e1d00c..8a7916570 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -26,7 +26,7 @@ pub use rustc_middle::traits::query::type_op::*; /// extract out the resulting region constraints (or an error if it /// cannot be completed). pub trait TypeOp<'tcx>: Sized + fmt::Debug { - type Output; + type Output: fmt::Debug; type ErrorInfo; /// Processes the operation and all resulting obligations, |