diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs index 7841d59cacaf7..7afb44517a37b 100644 --- a/compiler/rustc_infer/src/infer/outlives/env.rs +++ b/compiler/rustc_infer/src/infer/outlives/env.rs @@ -52,12 +52,10 @@ pub struct OutlivesEnvironment<'tcx> { region_bound_pairs: RegionBoundPairs<'tcx>, } -/// Builder of OutlivesEnvironment. Use this structure if you need to add more outlives -/// bounds than `explicit_outlives_bounds(param_env)`. -pub struct OutlivesEnvironmentBuilder<'tcx> { - pub param_env: ty::ParamEnv<'tcx>, +/// Builder of OutlivesEnvironment. +struct OutlivesEnvironmentBuilder<'tcx> { + param_env: ty::ParamEnv<'tcx>, region_relation: TransitiveRelationBuilder>, - region_bound_pairs: RegionBoundPairs<'tcx>, } @@ -69,7 +67,7 @@ pub type RegionBoundPairs<'tcx> = impl<'tcx> OutlivesEnvironment<'tcx> { /// Create a builder using `ParamEnv` and add explicit outlives bounds into it. - pub fn builder(param_env: ty::ParamEnv<'tcx>) -> OutlivesEnvironmentBuilder<'tcx> { + fn builder(param_env: ty::ParamEnv<'tcx>) -> OutlivesEnvironmentBuilder<'tcx> { let mut builder = OutlivesEnvironmentBuilder { param_env, region_relation: Default::default(), @@ -87,6 +85,17 @@ impl<'tcx> OutlivesEnvironment<'tcx> { Self::builder(param_env).build() } + /// Create a new `OutlivesEnvironment` with extra outlives bounds. + pub fn with_bounds<'a>( + param_env: ty::ParamEnv<'tcx>, + infcx: Option<&InferCtxt<'a, 'tcx>>, + extra_bounds: impl IntoIterator>, + ) -> Self { + let mut builder = Self::builder(param_env); + builder.add_outlives_bounds(infcx, extra_bounds); + builder.build() + } + /// Borrows current value of the `free_region_map`. pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> { &self.free_region_map @@ -108,26 +117,14 @@ impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> { } } - // Record that `'sup:'sub`. Or, put another way, `'sub <= 'sup`. - // (with the exception that `'static: 'x` is not notable) - fn relate_regions(&mut self, sub: Region<'tcx>, sup: Region<'tcx>) { - debug!("relate_regions(sub={:?}, sup={:?})", sub, sup); - if sub.is_free_or_static() && sup.is_free() { - self.region_relation.add(sub, sup) - } - } - /// Processes outlives bounds that are known to hold, whether from implied or other sources. /// /// The `infcx` parameter is optional; if the implied bounds may /// contain inference variables, it must be supplied, in which /// case we will register "givens" on the inference context. (See /// `RegionConstraintData`.) - pub fn add_outlives_bounds( - &mut self, - infcx: Option<&InferCtxt<'a, 'tcx>>, - outlives_bounds: I, - ) where + fn add_outlives_bounds(&mut self, infcx: Option<&InferCtxt<'a, 'tcx>>, outlives_bounds: I) + where I: IntoIterator>, { // Record relationships such as `T:'x` that don't go into the @@ -159,7 +156,9 @@ impl<'a, 'tcx> OutlivesEnvironmentBuilder<'tcx> { // system to be more general and to make use // of *every* relationship that arises here, // but presently we do not.) - self.relate_regions(r_a, r_b); + if r_a.is_free_or_static() && r_b.is_free() { + self.region_relation.add(r_a, r_b) + } } } } diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index d645084375f98..5fde6f396e59d 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -1,6 +1,6 @@ use super::potentially_plural_count; -use crate::check::regionck::OutlivesEnvironmentExt; use crate::errors::LifetimesOrBoundsMismatchOnTrait; +use crate::outlives::outlives_bounds::InferCtxtExt as _; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed}; use rustc_hir as hir; @@ -401,9 +401,11 @@ fn compare_predicate_entailment<'tcx>( // Finally, resolve all regions. This catches wily misuses of // lifetime parameters. - let mut outlives_environment = OutlivesEnvironment::builder(param_env); - outlives_environment.add_implied_bounds(infcx, wf_tys, impl_m_hir_id); - let outlives_environment = outlives_environment.build(); + let outlives_environment = OutlivesEnvironment::with_bounds( + param_env, + Some(infcx), + infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys), + ); infcx.check_region_obligations_and_report_errors( impl_m.def_id.expect_local(), &outlives_environment, @@ -1517,6 +1519,7 @@ pub fn check_type_bounds<'tcx>( let mut outlives_environment = OutlivesEnvironment::builder(param_env); outlives_environment.add_implied_bounds(&infcx, assumed_wf_types, impl_ty_hir_id); let outlives_environment = outlives_environment.build(); + infcx.check_region_obligations_and_report_errors( impl_ty.def_id.expect_local(), &outlives_environment, diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index dfbef544b1d28..fb675212e3ffb 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -87,7 +87,6 @@ mod op; mod pat; mod place_op; mod region; -pub mod regionck; pub mod rvalue_scopes; mod upvar; pub mod wfcheck; diff --git a/compiler/rustc_typeck/src/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs deleted file mode 100644 index bcc1ea38c9d0f..0000000000000 --- a/compiler/rustc_typeck/src/check/regionck.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::outlives::outlives_bounds::InferCtxtExt as _; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; -use rustc_infer::infer::outlives::env::OutlivesEnvironmentBuilder; -use rustc_infer::infer::InferCtxt; -use rustc_middle::ty::Ty; - -pub(crate) trait OutlivesEnvironmentExt<'tcx> { - fn add_implied_bounds( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - fn_sig_tys: FxHashSet>, - body_id: hir::HirId, - ); -} - -impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironmentBuilder<'tcx> { - /// This method adds "implied bounds" into the outlives environment. - /// Implied bounds are outlives relationships that we can deduce - /// on the basis that certain types must be well-formed -- these are - /// either the types that appear in the function signature or else - /// the input types to an impl. For example, if you have a function - /// like - /// - /// ``` - /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { } - /// ``` - /// - /// we can assume in the caller's body that `'b: 'a` and that `T: - /// 'b` (and hence, transitively, that `T: 'a`). This method would - /// 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>, - fn_sig_tys: FxHashSet>, - body_id: hir::HirId, - ) { - for ty in fn_sig_tys { - let ty = infcx.resolve_vars_if_possible(ty); - let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty); - self.add_outlives_bounds(Some(infcx), implied_bounds) - } - } -} diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 4f080c0cdfa95..8396cb1ae0aab 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1,5 +1,5 @@ -use crate::check::regionck::OutlivesEnvironmentExt; use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; +use crate::outlives::outlives_bounds::InferCtxtExt as _; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; @@ -107,6 +107,7 @@ pub(super) fn enter_wf_checking_ctxt<'tcx, F>( let mut outlives_environment = OutlivesEnvironment::builder(param_env); outlives_environment.add_implied_bounds(infcx, assumed_wf_types, body_id); let outlives_environment = outlives_environment.build(); + infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment); }) } @@ -695,9 +696,11 @@ fn resolve_regions_with_wf_tys<'tcx>( // region constraints get added and solved there and we need to test each // call individually. tcx.infer_ctxt().enter(|infcx| { - let mut outlives_environment = OutlivesEnvironment::builder(param_env); - outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id); - let outlives_environment = outlives_environment.build(); + let outlives_environment = OutlivesEnvironment::with_bounds( + param_env, + Some(&infcx), + infcx.implied_bounds_tys(param_env, id, wf_tys.iter().map(|ty| *ty)), + ); let region_bound_pairs = outlives_environment.region_bound_pairs(); add_constraints(&infcx, region_bound_pairs); diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index e841d79d940e7..72af5d79e0915 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -65,9 +65,9 @@ //! cause use after frees with purely safe code in the same way as specializing //! on traits with methods can. -use crate::check::regionck::OutlivesEnvironmentExt; use crate::constrained_generic_params as cgp; use crate::errors::SubstsOnOverriddenImpl; +use crate::outlives::outlives_bounds::InferCtxtExt; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -147,10 +147,17 @@ fn get_impl_substs<'tcx>( let assumed_wf_types = ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id); - let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id()); + let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id.to_def_id()); let impl2_substs = translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node); + + + + + + + let errors = ocx.select_all_or_error(); if !errors.is_empty() { ocx.infcx.report_fulfillment_errors(&errors, None, false); diff --git a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs index 229a64650848c..769a3e7e11a83 100644 --- a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs +++ b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs @@ -1,5 +1,6 @@ use rustc_hir as hir; -use rustc_middle::ty::{self, Ty}; +use rustc_hir::HirId; +use rustc_middle::ty::{self, ParamEnv, Ty}; use rustc_trait_selection::infer::InferCtxt; use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput}; use rustc_trait_selection::traits::query::NoSolution; @@ -7,16 +8,23 @@ use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt pub use rustc_middle::traits::query::OutlivesBound; -pub trait InferCtxtExt<'tcx> { +pub trait InferCtxtExt<'a, 'tcx> { fn implied_outlives_bounds( &self, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, ty: Ty<'tcx>, ) -> Vec>; + + fn implied_bounds_tys( + &'a self, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + tys: impl IntoIterator> + 'a, + ) -> Box> + 'a>; } -impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { +impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> { /// Implied bounds are region relationships that we deduce /// automatically. The idea is that (e.g.) a caller must check that a /// function's argument types are well-formed immediately before @@ -87,4 +95,20 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> { output } + + fn implied_bounds_tys( + &'a self, + param_env: ParamEnv<'tcx>, + body_id: HirId, + tys: impl IntoIterator> + 'a, + ) -> Box> + 'a> { + Box::new( + tys.into_iter() + .map(move |ty| { + let ty = self.resolve_vars_if_possible(ty); + self.implied_outlives_bounds(param_env, body_id, ty) + }) + .flatten(), + ) + } }