diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/query')
4 files changed, 75 insertions, 57 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 32669e23d..c84f128dd 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -31,7 +31,7 @@ pub trait InferCtxtExt<'tcx> { ) -> EvaluationResult; } -impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { +impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { /// Evaluates whether the predicate can be satisfied (by any means) /// in the given `ParamEnv`. fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool { 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) + } } } 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..6bf3ed0d0 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; @@ -18,16 +16,16 @@ pub struct CustomTypeOp<F, G> { impl<F, G> CustomTypeOp<F, G> { pub fn new<'tcx, R>(closure: F, description: G) -> Self where - F: FnOnce(&InferCtxt<'_, 'tcx>) -> Fallible<InferOk<'tcx, R>>, + F: FnOnce(&InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>, G: Fn() -> String, { CustomTypeOp { closure, description } } } -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>>, + F: for<'a, 'cx> FnOnce(&'a InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>, G: Fn() -> String, { type Output = R; @@ -38,7 +36,7 @@ where /// Processes the operation and all resulting obligations, /// returning the final result along with any region constraints /// (they will be given over to the NLL region solver). - fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { + fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { if cfg!(debug_assertions) { info!("fully_perform({:?})", self); } @@ -59,11 +57,9 @@ where /// Executes `op` and then scrapes out all the "old style" region /// constraints that result, creating query-region-constraints. pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( - infcx: &InferCtxt<'_, 'tcx>, + 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..29ae8ae6b 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,13 +26,13 @@ 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, /// returning the final result along with any region constraints /// (they will be given over to the NLL region solver). - fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>>; + fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>>; } /// The output from performing a type op @@ -78,7 +78,7 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx { fn fully_perform_into( query_key: ParamEnvAnd<'tcx, Self>, - infcx: &InferCtxt<'_, 'tcx>, + infcx: &InferCtxt<'tcx>, output_query_region_constraints: &mut QueryRegionConstraints<'tcx>, ) -> Fallible<( Self::QueryResponse, @@ -120,7 +120,7 @@ where type Output = Q::QueryResponse; type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>; - fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { + fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> { let mut region_constraints = QueryRegionConstraints::default(); let (output, error_info, mut obligations, _) = Q::fully_perform_into(self, infcx, &mut region_constraints)?; |