summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_trait_selection/src/traits/query/normalize.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs99
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)
+ }
}
}