1
Fork 0

Move outlives env computation into methods

This commit is contained in:
Michael Goulet 2025-01-25 04:26:32 +00:00
parent 2b8930c71c
commit 48b7e38c06
8 changed files with 71 additions and 49 deletions

View file

@ -1,6 +1,8 @@
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_hir::OpaqueTyOrigin;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _}; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _};
use rustc_macros::extension; use rustc_macros::extension;
use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::fold::fold_regions;
@ -10,6 +12,7 @@ use rustc_middle::ty::{
TypingMode, TypingMode,
}; };
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::regions::OutlivesEnvironmentBuildExt;
use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::ObligationCtxt;
use tracing::{debug, instrument}; use tracing::{debug, instrument};
@ -406,10 +409,6 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
} }
fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> { fn get_canonical_args(&self) -> ty::GenericArgsRef<'tcx> {
use rustc_hir as hir;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
if let Some(&canonical_args) = self.canonical_args.get() { if let Some(&canonical_args) = self.canonical_args.get() {
return canonical_args; return canonical_args;
} }
@ -417,9 +416,9 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
let &Self { tcx, def_id, .. } = self; let &Self { tcx, def_id, .. } = self;
let origin = tcx.local_opaque_ty_origin(def_id); let origin = tcx.local_opaque_ty_origin(def_id);
let parent = match origin { let parent = match origin {
hir::OpaqueTyOrigin::FnReturn { parent, .. } OpaqueTyOrigin::FnReturn { parent, .. }
| hir::OpaqueTyOrigin::AsyncFn { parent, .. } | OpaqueTyOrigin::AsyncFn { parent, .. }
| hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent, | OpaqueTyOrigin::TyAlias { parent, .. } => parent,
}; };
let param_env = tcx.param_env(parent); let param_env = tcx.param_env(parent);
let args = GenericArgs::identity_for_item(tcx, parent).extend_to( let args = GenericArgs::identity_for_item(tcx, parent).extend_to(
@ -439,8 +438,7 @@ impl<'tcx> LazyOpaqueTyEnv<'tcx> {
tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "error getting implied bounds"); tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "error getting implied bounds");
Default::default() Default::default()
}); });
let implied_bounds = infcx.implied_bounds_tys(parent, param_env, wf_tys); let outlives_env = OutlivesEnvironment::new(&infcx, parent, param_env, wf_tys);
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
let mut seen = vec![tcx.lifetimes.re_static]; let mut seen = vec![tcx.lifetimes.re_static];
let canonical_args = fold_regions(tcx, args, |r1, _| { let canonical_args = fold_regions(tcx, args, |r1, _| {

View file

@ -25,11 +25,10 @@ use rustc_middle::{bug, span_bug};
use rustc_session::parse::feature_err; use rustc_session::parse::feature_err;
use rustc_span::{DUMMY_SP, Ident, Span, sym}; use rustc_span::{DUMMY_SP, Ident, Span, sym};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::regions::{InferCtxtRegionExt, OutlivesEnvironmentBuildExt};
use rustc_trait_selection::traits::misc::{ use rustc_trait_selection::traits::misc::{
ConstParamTyImplementationError, type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError, type_allowed_to_implement_const_param_ty,
}; };
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{ use rustc_trait_selection::traits::{
self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt, self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
@ -128,13 +127,13 @@ where
let infcx_compat = infcx.fork(); let infcx_compat = infcx.fork();
// We specifically want to call the non-compat version of `implied_bounds_tys`; we do this always. // We specifically want to call the non-compat version of `implied_bounds_tys`; we do this always.
let implied_bounds = infcx.implied_bounds_tys_compat( let outlives_env = OutlivesEnvironment::new_with_implied_bounds_compat(
&infcx,
body_def_id, body_def_id,
param_env, param_env,
assumed_wf_types.iter().copied(), assumed_wf_types.iter().copied(),
false, false,
); );
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
lint_redundant_lifetimes(tcx, body_def_id, &outlives_env); lint_redundant_lifetimes(tcx, body_def_id, &outlives_env);
@ -176,9 +175,13 @@ where
// but that does result in slightly more work when this option is set and // but that does result in slightly more work when this option is set and
// just obscures what we mean here anyways. Let's just be explicit. // just obscures what we mean here anyways. Let's just be explicit.
if is_bevy && !infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat { if is_bevy && !infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat {
let implied_bounds = let outlives_env = OutlivesEnvironment::new_with_implied_bounds_compat(
infcx_compat.implied_bounds_tys_compat(body_def_id, param_env, assumed_wf_types, true); &infcx,
let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); body_def_id,
param_env,
assumed_wf_types,
true,
);
let errors_compat = infcx_compat.resolve_regions_with_outlives_env(&outlives_env); let errors_compat = infcx_compat.resolve_regions_with_outlives_env(&outlives_env);
if errors_compat.is_empty() { if errors_compat.is_empty() {
Ok(()) Ok(())

View file

@ -59,12 +59,6 @@ pub struct OutlivesEnvironment<'tcx> {
pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesPredicate<'tcx, GenericKind<'tcx>>>; pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesPredicate<'tcx, GenericKind<'tcx>>>;
impl<'tcx> OutlivesEnvironment<'tcx> { impl<'tcx> OutlivesEnvironment<'tcx> {
/// Create a new `OutlivesEnvironment` without extra outlives bounds.
#[inline]
pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
Self::with_bounds(param_env, vec![])
}
/// Create a new `OutlivesEnvironment` with extra outlives bounds. /// Create a new `OutlivesEnvironment` with extra outlives bounds.
pub fn with_bounds( pub fn with_bounds(
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,

View file

@ -25,8 +25,8 @@ use rustc_span::{Span, Symbol};
use rustc_trait_selection::errors::{ use rustc_trait_selection::errors::{
AddPreciseCapturingForOvercapture, impl_trait_overcapture_suggestion, AddPreciseCapturingForOvercapture, impl_trait_overcapture_suggestion,
}; };
use rustc_trait_selection::regions::OutlivesEnvironmentBuildExt;
use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::ObligationCtxt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt;
use crate::{LateContext, LateLintPass, fluent_generated as fluent}; use crate::{LateContext, LateLintPass, fluent_generated as fluent};
@ -190,9 +190,7 @@ fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) {
let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
let ocx = ObligationCtxt::new(&infcx); let ocx = ObligationCtxt::new(&infcx);
let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default(); let assumed_wf_tys = ocx.assumed_wf_types(param_env, parent_def_id).unwrap_or_default();
let implied_bounds = OutlivesEnvironment::new(&infcx, parent_def_id, param_env, assumed_wf_tys)
infcx.implied_bounds_tys_compat(parent_def_id, param_env, assumed_wf_tys, false);
OutlivesEnvironment::with_bounds(param_env, implied_bounds)
}), }),
}); });
} }

View file

@ -9,6 +9,46 @@ use rustc_middle::ty::{self, Ty};
use crate::traits::ScrubbedTraitError; use crate::traits::ScrubbedTraitError;
use crate::traits::outlives_bounds::InferCtxtExt; use crate::traits::outlives_bounds::InferCtxtExt;
#[extension(pub trait OutlivesEnvironmentBuildExt<'tcx>)]
impl<'tcx> OutlivesEnvironment<'tcx> {
fn new(
infcx: &InferCtxt<'tcx>,
body_id: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
) -> Self {
Self::new_with_implied_bounds_compat(
infcx,
body_id,
param_env,
assumed_wf_tys,
!infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat,
)
}
fn new_with_implied_bounds_compat(
infcx: &InferCtxt<'tcx>,
body_id: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
implied_bounds_compat: bool,
) -> Self {
// FIXME: This needs to be modified so that we normalize the known type
// outlives obligations then elaborate them into their region/type components.
// Otherwise, `<W<'a> as Mirror>::Assoc: 'b` will not imply `'a: 'b` even
// if we can normalize `'a`.
OutlivesEnvironment::with_bounds(
param_env,
infcx.implied_bounds_tys_with_compat(
body_id,
param_env,
assumed_wf_tys,
implied_bounds_compat,
),
)
}
}
#[extension(pub trait InferCtxtRegionExt<'tcx>)] #[extension(pub trait InferCtxtRegionExt<'tcx>)]
impl<'tcx> InferCtxt<'tcx> { impl<'tcx> InferCtxt<'tcx> {
/// Resolve regions, using the deep normalizer to normalize any type-outlives /// Resolve regions, using the deep normalizer to normalize any type-outlives
@ -23,9 +63,11 @@ impl<'tcx> InferCtxt<'tcx> {
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>, assumed_wf_tys: impl IntoIterator<Item = Ty<'tcx>>,
) -> Vec<RegionResolutionError<'tcx>> { ) -> Vec<RegionResolutionError<'tcx>> {
self.resolve_regions_with_outlives_env(&OutlivesEnvironment::with_bounds( self.resolve_regions_with_outlives_env(&OutlivesEnvironment::new(
self,
body_id,
param_env, param_env,
self.implied_bounds_tys(body_id, param_env, assumed_wf_tys), assumed_wf_tys,
)) ))
} }

View file

@ -6,6 +6,7 @@ use std::iter;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry};
use rustc_data_structures::unord::UnordSet; use rustc_data_structures::unord::UnordSet;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::DefineOpaqueTypes;
use rustc_middle::ty::{Region, RegionVid}; use rustc_middle::ty::{Region, RegionVid};
use tracing::debug; use tracing::debug;
@ -13,6 +14,7 @@ use tracing::debug;
use super::*; use super::*;
use crate::errors::UnableToConstructConstantValue; use crate::errors::UnableToConstructConstantValue;
use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::regions::OutlivesEnvironmentBuildExt;
use crate::traits::project::ProjectAndUnifyResult; use crate::traits::project::ProjectAndUnifyResult;
// FIXME(twk): this is obviously not nice to duplicate like that // FIXME(twk): this is obviously not nice to duplicate like that
@ -158,7 +160,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
panic!("Unable to fulfill trait {trait_did:?} for '{ty:?}': {errors:?}"); panic!("Unable to fulfill trait {trait_did:?} for '{ty:?}': {errors:?}");
} }
let outlives_env = OutlivesEnvironment::new(full_env); let outlives_env = OutlivesEnvironment::new(&infcx, CRATE_DEF_ID, full_env, []);
let _ = infcx.process_registered_region_obligations(&outlives_env, |ty, _| Ok(ty)); let _ = infcx.process_registered_region_obligations(&outlives_env, |ty, _| Ok(ty));
let region_data = infcx.inner.borrow_mut().unwrap_region_constraints().data().clone(); let region_data = infcx.inner.borrow_mut().unwrap_region_constraints().data().clone();

View file

@ -108,8 +108,9 @@ fn implied_outlives_bounds<'a, 'tcx>(
#[extension(pub trait InferCtxtExt<'tcx>)] #[extension(pub trait InferCtxtExt<'tcx>)]
impl<'tcx> InferCtxt<'tcx> { impl<'tcx> InferCtxt<'tcx> {
/// Do *NOT* call this directly. /// Do *NOT* call this directly. You probably want to construct a `OutlivesEnvironment`
fn implied_bounds_tys_compat<Tys: IntoIterator<Item = Ty<'tcx>>>( /// instead if you're interested in the implied bounds for a given signature.
fn implied_bounds_tys_with_compat<Tys: IntoIterator<Item = Ty<'tcx>>>(
&self, &self,
body_id: LocalDefId, body_id: LocalDefId,
param_env: ParamEnv<'tcx>, param_env: ParamEnv<'tcx>,
@ -119,20 +120,4 @@ impl<'tcx> InferCtxt<'tcx> {
tys.into_iter() tys.into_iter()
.flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, ty, compat)) .flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, ty, compat))
} }
/// If `-Z no-implied-bounds-compat` is set, calls `implied_bounds_tys_compat`
/// with `compat` set to `true`, otherwise `false`.
fn implied_bounds_tys(
&self,
body_id: LocalDefId,
param_env: ParamEnv<'tcx>,
tys: impl IntoIterator<Item = Ty<'tcx>>,
) -> impl Iterator<Item = OutlivesBound<'tcx>> {
self.implied_bounds_tys_compat(
body_id,
param_env,
tys,
!self.tcx.sess.opts.unstable_opts.no_implied_bounds_compat,
)
}
} }

View file

@ -40,7 +40,7 @@ requirements of impls and functions as explicit predicates.
### using implicit implied bounds as assumptions ### using implicit implied bounds as assumptions
These bounds are not added to the `ParamEnv` of the affected item itself. For lexical These bounds are not added to the `ParamEnv` of the affected item itself. For lexical
region resolution they are added using [`fn OutlivesEnvironment::with_bounds`]. region resolution they are added using [`fn OutlivesEnvironment::new`].
Similarly, during MIR borrowck we add them using Similarly, during MIR borrowck we add them using
[`fn UniversalRegionRelationsBuilder::add_implied_bounds`]. [`fn UniversalRegionRelationsBuilder::add_implied_bounds`].
@ -55,7 +55,7 @@ The assumed outlives constraints for implicit bounds are computed using the
MIR borrowck adds the outlives constraints for both the normalized and unnormalized types, MIR borrowck adds the outlives constraints for both the normalized and unnormalized types,
lexical region resolution [only uses the unnormalized types][notnorm]. lexical region resolution [only uses the unnormalized types][notnorm].
[`fn OutlivesEnvironment::with_bounds`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_infer/src/infer/outlives/env.rs#L90-L97 [`fn OutlivesEnvironment::new`]: TODO
[`fn UniversalRegionRelationsBuilder::add_implied_bounds`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs#L316 [`fn UniversalRegionRelationsBuilder::add_implied_bounds`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs#L316
[mir]: https://github.com/rust-lang/rust/blob/91cae1dcdcf1a31bd8a92e4a63793d65cfe289bb/compiler/rustc_borrowck/src/type_check/free_region_relations.rs#L258-L332 [mir]: https://github.com/rust-lang/rust/blob/91cae1dcdcf1a31bd8a92e4a63793d65cfe289bb/compiler/rustc_borrowck/src/type_check/free_region_relations.rs#L258-L332
[`fn assumed_wf_types`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_ty_utils/src/implied_bounds.rs#L21 [`fn assumed_wf_types`]: https://github.com/rust-lang/rust/blob/5b8bc568d28b2e922290c9a966b3231d0ce9398b/compiler/rustc_ty_utils/src/implied_bounds.rs#L21