diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_trait_selection/src/traits/query/normalize.rs | 99 |
1 files changed, 61 insertions, 38 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..58e4597b7 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -5,17 +5,16 @@ 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::error_reporting::TypeErrCtxtExt; +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; use rustc_infer::traits::Normalized; -use rustc_middle::mir; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; -use rustc_middle::ty::subst::Subst; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; +use rustc_span::DUMMY_SP; use std::ops::ControlFlow; @@ -48,10 +47,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![] }); @@ -154,7 +154,7 @@ impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { } struct QueryNormalizer<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, + infcx: &'cx InferCtxt<'tcx>, cause: &'cx ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, obligations: Vec<PredicateObligation<'tcx>>, @@ -213,7 +213,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { self.param_env, ty, ); - self.infcx.report_overflow_error(&obligation, true); + self.infcx.err_ctxt().report_overflow_error(&obligation, true); } let generic_ty = self.tcx().bound_type_of(def_id); @@ -254,7 +254,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let result = tcx.normalize_projection_ty(c_data)?; // We don't expect ambiguity. if result.is_ambiguous() { - bug!("unexpected ambiguity: {:?} {:?}", c_data, result); + // Rustdoc normalizes possibly not well-formed types, so only + // treat this as a bug if we're not in rustdoc. + if !tcx.sess.opts.actually_rustdoc { + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("unexpected ambiguity: {:?} {:?}", c_data, result), + ); + } + return Err(NoSolution); } let InferOk { value: result, obligations } = self.infcx.instantiate_query_response_and_region_obligations( @@ -266,7 +274,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 +291,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(); @@ -293,7 +305,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { let result = tcx.normalize_projection_ty(c_data)?; // We don't expect ambiguity. if result.is_ambiguous() { - bug!("unexpected ambiguity: {:?} {:?}", c_data, result); + // Rustdoc normalizes possibly not well-formed types, so only + // treat this as a bug if we're not in rustdoc. + if !tcx.sess.opts.actually_rustdoc { + tcx.sess.delay_span_bug( + DUMMY_SP, + format!("unexpected ambiguity: {:?} {:?}", c_data, result), + ); + } + return Err(NoSolution); } let InferOk { value: result, obligations } = self.infcx.instantiate_query_response_and_region_obligations( @@ -305,18 +325,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,29 +354,24 @@ 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( + #[inline] + fn try_fold_predicate( &mut self, - constant: mir::ConstantKind<'tcx>, - ) -> Result<mir::ConstantKind<'tcx>, Self::Error> { - Ok(match constant { - mir::ConstantKind::Ty(c) => { - let const_folded = c.try_super_fold_with(self)?; - match const_folded.kind() { - ty::ConstKind::Value(valtree) => { - let tcx = self.infcx.tcx; - let ty = const_folded.ty(); - let const_val = tcx.valtree_to_const_val((ty, valtree)); - debug!(?ty, ?valtree, ?const_val); - - mir::ConstantKind::Val(const_val, ty) - } - _ => mir::ConstantKind::Ty(const_folded), - } - } - mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(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) + } } } |