From 9ab257b7321ea683665283d0dde81adfec2f0c23 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 29 Jan 2024 09:24:19 +0100 Subject: [PATCH 1/2] never normalize without eager inference replacement --- .../src/traits/fulfill.rs | 2 +- .../src/traits/project.rs | 88 ++----------------- .../src/traits/select/mod.rs | 3 +- 3 files changed, 11 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 0337672b3027e..a875534024e44 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -312,7 +312,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { if obligation.predicate.has_projections() { let mut obligations = Vec::new(); - let predicate = crate::traits::project::try_normalize_with_depth_to( + let predicate = crate::traits::project::normalize_with_depth_to( &mut self.selcx, obligation.param_env, obligation.cause.clone(), diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index abbc2066eac16..1edc6331ca094 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -383,32 +383,6 @@ where result } -#[instrument(level = "info", skip(selcx, param_env, cause, obligations))] -pub(crate) fn try_normalize_with_depth_to<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - value: T, - obligations: &mut Vec>, -) -> T -where - T: TypeFoldable>, -{ - debug!(obligations.len = obligations.len()); - let mut normalizer = AssocTypeNormalizer::new_without_eager_inference_replacement( - selcx, - param_env, - cause, - depth, - obligations, - ); - let result = ensure_sufficient_stack(|| normalizer.fold(value)); - debug!(?result, obligations.len = normalizer.obligations.len()); - debug!(?normalizer.obligations,); - result -} - pub(crate) fn needs_normalization<'tcx, T: TypeVisitable>>( value: &T, reveal: Reveal, @@ -435,10 +409,6 @@ struct AssocTypeNormalizer<'a, 'b, 'tcx> { obligations: &'a mut Vec>, depth: usize, universes: Vec>, - /// If true, when a projection is unable to be completed, an inference - /// variable will be created and an obligation registered to project to that - /// inference variable. Also, constants will be eagerly evaluated. - eager_inference_replacement: bool, } impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { @@ -450,33 +420,7 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { obligations: &'a mut Vec>, ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { debug_assert!(!selcx.infcx.next_trait_solver()); - AssocTypeNormalizer { - selcx, - param_env, - cause, - obligations, - depth, - universes: vec![], - eager_inference_replacement: true, - } - } - - fn new_without_eager_inference_replacement( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - obligations: &'a mut Vec>, - ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { - AssocTypeNormalizer { - selcx, - param_env, - cause, - obligations, - depth, - universes: vec![], - eager_inference_replacement: false, - } + AssocTypeNormalizer { selcx, param_env, cause, obligations, depth, universes: vec![] } } fn fold>>(&mut self, value: T) -> T { @@ -579,28 +523,14 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx // register an obligation to *later* project, since we know // there won't be bound vars there. let data = data.fold_with(self); - let normalized_ty = if self.eager_inference_replacement { - normalize_projection_type( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ) - } else { - opt_normalize_projection_type( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ) - .ok() - .flatten() - .unwrap_or_else(|| ty.super_fold_with(self).into()) - }; + let normalized_ty = normalize_projection_type( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + self.obligations, + ); debug!( ?self.depth, ?ty, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 6a6adcbb680ea..8eb805819ad5f 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -22,7 +22,6 @@ use super::{ use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt; use crate::traits::error_reporting::TypeErrCtxtExt; -use crate::traits::project::try_normalize_with_depth_to; use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectionCacheKeyExt; use crate::traits::ProjectionCacheKey; @@ -1069,7 +1068,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { && fresh_trait_pred.is_global() { let mut nested_obligations = Vec::new(); - let predicate = try_normalize_with_depth_to( + let predicate = normalize_with_depth_to( this, param_env, obligation.cause.clone(), From 2b3867ba585819143e28114b750be255df83dc30 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 29 Jan 2024 10:11:30 +0100 Subject: [PATCH 2/2] remove `pred_known_to_hold_modulo_regions` --- .../rustc_trait_selection/src/traits/mod.rs | 50 ++----------------- 1 file changed, 3 insertions(+), 47 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 080ad7bd549c8..f1871bf771868 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -118,9 +118,7 @@ pub fn predicates_for_generics<'tcx>( /// Determines whether the type `ty` is known to meet `bound` and /// returns true if so. Returns false if `ty` either does not meet -/// `bound` or is not known to meet bound (note that this is -/// conservative towards *no impl*, which is the opposite of the -/// `evaluate` methods). +/// `bound` or is not known to meet bound. pub fn type_known_to_meet_bound_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -128,50 +126,8 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( def_id: DefId, ) -> bool { let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]); - pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref) -} - -/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist? -/// -/// Ping me on zulip if you want to use this method and need help with finding -/// an appropriate replacement. -#[instrument(level = "debug", skip(infcx, param_env, pred), ret)] -fn pred_known_to_hold_modulo_regions<'tcx>( - infcx: &InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - pred: impl ToPredicate<'tcx>, -) -> bool { - let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred); - - let result = infcx.evaluate_obligation_no_overflow(&obligation); - debug!(?result); - - if result.must_apply_modulo_regions() { - true - } else if result.may_apply() { - // Sometimes obligations are ambiguous because the recursive evaluator - // is not smart enough, so we fall back to fulfillment when we're not certain - // that an obligation holds or not. Even still, we must make sure that - // the we do no inference in the process of checking this obligation. - let goal = infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); - infcx.probe(|_| { - let ocx = ObligationCtxt::new(infcx); - ocx.register_obligation(obligation); - - let errors = ocx.select_all_or_error(); - match errors.as_slice() { - // Only known to hold if we did no inference. - [] => infcx.shallow_resolve(goal) == goal, - - errors => { - debug!(?errors); - false - } - } - }) - } else { - false - } + let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, trait_ref); + infcx.predicate_must_hold_modulo_regions(&obligation) } #[instrument(level = "debug", skip(tcx, elaborated_env))]