From 340e708634e7cc560c04e27b91297ff04f897683 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 16 May 2022 14:23:15 +0000 Subject: [PATCH 1/4] Some tracing cleanups --- .../rustc_borrowck/src/type_check/free_region_relations.rs | 2 +- compiler/rustc_infer/src/infer/outlives/mod.rs | 2 +- compiler/rustc_typeck/src/check/regionck.rs | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index f08f2e1b12da6..aa17e27367982 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -334,8 +334,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { /// either the return type of the MIR or one of its arguments. At /// the same time, compute and add any implied bounds that come /// from this local. + #[instrument(level = "debug", skip(self))] fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option>> { - debug!("add_implied_bounds(ty={:?})", ty); let TypeOpOutput { output: bounds, constraints, .. } = self .param_env .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 03d6c45a65345..b9652e83e65be 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -8,10 +8,10 @@ pub mod verify; use rustc_middle::traits::query::OutlivesBound; use rustc_middle::ty; +#[instrument(level = "debug", skip(param_env))] pub fn explicit_outlives_bounds<'tcx>( param_env: ty::ParamEnv<'tcx>, ) -> impl Iterator> + 'tcx { - debug!("explicit_outlives_bounds()"); param_env .caller_bounds() .into_iter() diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs index 20456cc427c52..2ba8cb24f8b41 100644 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -130,6 +130,7 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> { /// add those assumptions into the outlives-environment. /// /// Tests: `src/test/ui/regions/regions-free-region-ordering-*.rs` + #[instrument(level = "debug", skip(self, infcx))] fn add_implied_bounds<'a>( &mut self, infcx: &InferCtxt<'a, 'tcx>, @@ -137,11 +138,8 @@ impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> { body_id: hir::HirId, span: Span, ) { - debug!("add_implied_bounds()"); - for ty in fn_sig_tys { let ty = infcx.resolve_vars_if_possible(ty); - debug!("add_implied_bounds: ty = {}", ty); let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); self.add_outlives_bounds(Some(infcx), implied_bounds) } From 14da30e3e68999021a42bab470865b044409fb68 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 16 May 2022 14:23:52 +0000 Subject: [PATCH 2/4] Split some logic from a loop into a separate function --- .../src/infer/canonical/query_response.rs | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 5671711397a2c..ec468f428528e 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -547,25 +547,34 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { ) -> impl Iterator> + 'a + Captures<'tcx> { unsubstituted_region_constraints.iter().map(move |&constraint| { let predicate = substitute_value(self.tcx, result_subst, constraint); - let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder(); + self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env) + }) + } - let atom = match k1.unpack() { - GenericArgKind::Lifetime(r1) => { - ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)) - } - GenericArgKind::Type(t1) => { - ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t1, r2)) - } - GenericArgKind::Const(..) => { - // Consts cannot outlive one another, so we don't expect to - // encounter this branch. - span_bug!(cause.span, "unexpected const outlives {:?}", constraint); - } - }; - let predicate = predicate.rebind(atom).to_predicate(self.tcx); + pub fn query_outlives_constraint_to_obligation( + &self, + predicate: QueryOutlivesConstraint<'tcx>, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Obligation<'tcx, ty::Predicate<'tcx>> { + let ty::OutlivesPredicate(k1, r2) = predicate.skip_binder(); - Obligation::new(cause.clone(), param_env, predicate) - }) + let atom = match k1.unpack() { + GenericArgKind::Lifetime(r1) => { + ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)) + } + GenericArgKind::Type(t1) => { + ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t1, r2)) + } + GenericArgKind::Const(..) => { + // Consts cannot outlive one another, so we don't expect to + // encounter this branch. + span_bug!(cause.span, "unexpected const outlives {:?}", predicate); + } + }; + let predicate = predicate.rebind(atom).to_predicate(self.tcx); + + Obligation::new(cause, param_env, predicate) } /// Given two sets of values for the same set of canonical variables, unify them. From b85ebefcc4ffe44f4ce6f1e8a690256369492d95 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 16 May 2022 14:24:41 +0000 Subject: [PATCH 3/4] Re-use the type op instead of calling the implied_outlives_bounds query directly --- .../src/outlives/outlives_bounds.rs | 63 ++++++++++--------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs index 87f844fafe67f..3bf697e768269 100644 --- a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs +++ b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs @@ -1,9 +1,8 @@ use rustc_hir as hir; -use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::{self, Ty}; use rustc_span::source_map::Span; -use rustc_trait_selection::infer::canonical::OriginalQueryValues; use rustc_trait_selection::infer::InferCtxt; +use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput}; use rustc_trait_selection::traits::query::NoSolution; use rustc_trait_selection::traits::{FulfillmentContext, ObligationCause, TraitEngine}; @@ -41,6 +40,7 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { /// - `ty`, the type that we are supposed to assume is WF. /// - `span`, a span to use when normalizing, hopefully not important, /// might be useful if a `bug!` occurs. + #[instrument(level = "debug", skip(self, param_env, body_id, span))] fn implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, @@ -48,11 +48,10 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { ty: Ty<'tcx>, span: Span, ) -> Vec> { - debug!("implied_outlives_bounds(ty = {:?})", ty); - - let mut orig_values = OriginalQueryValues::default(); - let key = self.canonicalize_query(param_env.and(ty), &mut orig_values); - let result = match self.tcx.implied_outlives_bounds(key) { + let result = param_env + .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) + .fully_perform(self); + let result = match result { Ok(r) => r, Err(NoSolution) => { self.tcx.sess.delay_span_bug( @@ -62,32 +61,34 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { return vec![]; } }; - assert!(result.value.is_proven()); - let result = self.instantiate_query_response_and_region_obligations( - &ObligationCause::misc(span, body_id), - param_env, - &orig_values, - result, - ); - debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result); - let Ok(result) = result else { - self.tcx.sess.delay_span_bug(span, "implied_outlives_bounds failed to instantiate"); - return vec![]; - }; + let TypeOpOutput { output, constraints, .. } = result; - // Instantiation may have produced new inference variables and constraints on those - // variables. Process these constraints. - let mut fulfill_cx = FulfillmentContext::new(); - fulfill_cx.register_predicate_obligations(self, result.obligations); - let errors = fulfill_cx.select_all_or_error(self); - if !errors.is_empty() { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve obligations from instantiation", - ); - } + if let Some(constraints) = constraints { + // Instantiation may have produced new inference variables and constraints on those + // variables. Process these constraints. + let mut fulfill_cx = FulfillmentContext::new(); + let cause = ObligationCause::misc(span, body_id); + for &constraint in &constraints.outlives { + let obligation = self.query_outlives_constraint_to_obligation( + constraint, + cause.clone(), + param_env, + ); + fulfill_cx.register_predicate_obligation(self, obligation); + } + if !constraints.member_constraints.is_empty() { + span_bug!(span, "{:#?}", constraints.member_constraints); + } + let errors = fulfill_cx.select_all_or_error(self); + if !errors.is_empty() { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to solve obligations from instantiation", + ); + } + }; - result.value + output } } From e7a1fbc486b459eb359039fbd9bf78626d60ee41 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 16 May 2022 14:37:43 +0000 Subject: [PATCH 4/4] Don't go into the query for things that can't possibly have lifetimes. --- .../traits/query/type_op/implied_outlives_bounds.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 04c382d439d4c..46d6e973d4cf9 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -1,7 +1,7 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; use crate::traits::query::Fallible; use rustc_infer::traits::query::OutlivesBound; -use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt}; +use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt}; #[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)] pub struct ImpliedOutlivesBounds<'tcx> { @@ -13,9 +13,16 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { fn try_fast_path( _tcx: TyCtxt<'tcx>, - _key: &ParamEnvAnd<'tcx, Self>, + key: &ParamEnvAnd<'tcx, Self>, ) -> Option { - None + // Don't go into the query for things that can't possibly have lifetimes. + match key.value.ty.kind() { + ty::Tuple(elems) if elems.is_empty() => Some(vec![]), + ty::Never | ty::Str | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { + Some(vec![]) + } + _ => None, + } } fn perform_query(