add with_bounds
to OutlivesEnvironment
and implied_bounds_tys
to outlives_bounds::InferCtxtExt
This commit is contained in:
parent
5d9e4d07fc
commit
d037f1843e
7 changed files with 70 additions and 82 deletions
|
@ -52,12 +52,10 @@ pub struct OutlivesEnvironment<'tcx> {
|
||||||
region_bound_pairs: RegionBoundPairs<'tcx>,
|
region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builder of OutlivesEnvironment. Use this structure if you need to add more outlives
|
/// Builder of OutlivesEnvironment.
|
||||||
/// bounds than `explicit_outlives_bounds(param_env)`.
|
struct OutlivesEnvironmentBuilder<'tcx> {
|
||||||
pub struct OutlivesEnvironmentBuilder<'tcx> {
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
pub param_env: ty::ParamEnv<'tcx>,
|
|
||||||
region_relation: TransitiveRelationBuilder<Region<'tcx>>,
|
region_relation: TransitiveRelationBuilder<Region<'tcx>>,
|
||||||
|
|
||||||
region_bound_pairs: RegionBoundPairs<'tcx>,
|
region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +67,7 @@ pub type RegionBoundPairs<'tcx> =
|
||||||
|
|
||||||
impl<'tcx> OutlivesEnvironment<'tcx> {
|
impl<'tcx> OutlivesEnvironment<'tcx> {
|
||||||
/// Create a builder using `ParamEnv` and add explicit outlives bounds into it.
|
/// 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 {
|
let mut builder = OutlivesEnvironmentBuilder {
|
||||||
param_env,
|
param_env,
|
||||||
region_relation: Default::default(),
|
region_relation: Default::default(),
|
||||||
|
@ -87,6 +85,17 @@ impl<'tcx> OutlivesEnvironment<'tcx> {
|
||||||
Self::builder(param_env).build()
|
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<Item = OutlivesBound<'tcx>>,
|
||||||
|
) -> 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`.
|
/// Borrows current value of the `free_region_map`.
|
||||||
pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> {
|
pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> {
|
||||||
&self.free_region_map
|
&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.
|
/// Processes outlives bounds that are known to hold, whether from implied or other sources.
|
||||||
///
|
///
|
||||||
/// The `infcx` parameter is optional; if the implied bounds may
|
/// The `infcx` parameter is optional; if the implied bounds may
|
||||||
/// contain inference variables, it must be supplied, in which
|
/// contain inference variables, it must be supplied, in which
|
||||||
/// case we will register "givens" on the inference context. (See
|
/// case we will register "givens" on the inference context. (See
|
||||||
/// `RegionConstraintData`.)
|
/// `RegionConstraintData`.)
|
||||||
pub fn add_outlives_bounds<I>(
|
fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'a, 'tcx>>, outlives_bounds: I)
|
||||||
&mut self,
|
where
|
||||||
infcx: Option<&InferCtxt<'a, 'tcx>>,
|
|
||||||
outlives_bounds: I,
|
|
||||||
) where
|
|
||||||
I: IntoIterator<Item = OutlivesBound<'tcx>>,
|
I: IntoIterator<Item = OutlivesBound<'tcx>>,
|
||||||
{
|
{
|
||||||
// Record relationships such as `T:'x` that don't go into the
|
// 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
|
// system to be more general and to make use
|
||||||
// of *every* relationship that arises here,
|
// of *every* relationship that arises here,
|
||||||
// but presently we do not.)
|
// 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::potentially_plural_count;
|
use super::potentially_plural_count;
|
||||||
use crate::check::regionck::OutlivesEnvironmentExt;
|
|
||||||
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
|
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
|
||||||
|
use crate::outlives::outlives_bounds::InferCtxtExt as _;
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
|
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
@ -401,9 +401,11 @@ fn compare_predicate_entailment<'tcx>(
|
||||||
|
|
||||||
// Finally, resolve all regions. This catches wily misuses of
|
// Finally, resolve all regions. This catches wily misuses of
|
||||||
// lifetime parameters.
|
// lifetime parameters.
|
||||||
let mut outlives_environment = OutlivesEnvironment::builder(param_env);
|
let outlives_environment = OutlivesEnvironment::with_bounds(
|
||||||
outlives_environment.add_implied_bounds(infcx, wf_tys, impl_m_hir_id);
|
param_env,
|
||||||
let outlives_environment = outlives_environment.build();
|
Some(infcx),
|
||||||
|
infcx.implied_bounds_tys(param_env, impl_m_hir_id, wf_tys),
|
||||||
|
);
|
||||||
infcx.check_region_obligations_and_report_errors(
|
infcx.check_region_obligations_and_report_errors(
|
||||||
impl_m.def_id.expect_local(),
|
impl_m.def_id.expect_local(),
|
||||||
&outlives_environment,
|
&outlives_environment,
|
||||||
|
@ -1517,6 +1519,7 @@ pub fn check_type_bounds<'tcx>(
|
||||||
let mut outlives_environment = OutlivesEnvironment::builder(param_env);
|
let mut outlives_environment = OutlivesEnvironment::builder(param_env);
|
||||||
outlives_environment.add_implied_bounds(&infcx, assumed_wf_types, impl_ty_hir_id);
|
outlives_environment.add_implied_bounds(&infcx, assumed_wf_types, impl_ty_hir_id);
|
||||||
let outlives_environment = outlives_environment.build();
|
let outlives_environment = outlives_environment.build();
|
||||||
|
|
||||||
infcx.check_region_obligations_and_report_errors(
|
infcx.check_region_obligations_and_report_errors(
|
||||||
impl_ty.def_id.expect_local(),
|
impl_ty.def_id.expect_local(),
|
||||||
&outlives_environment,
|
&outlives_environment,
|
||||||
|
|
|
@ -87,7 +87,6 @@ mod op;
|
||||||
mod pat;
|
mod pat;
|
||||||
mod place_op;
|
mod place_op;
|
||||||
mod region;
|
mod region;
|
||||||
pub mod regionck;
|
|
||||||
pub mod rvalue_scopes;
|
pub mod rvalue_scopes;
|
||||||
mod upvar;
|
mod upvar;
|
||||||
pub mod wfcheck;
|
pub mod wfcheck;
|
||||||
|
|
|
@ -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<Ty<'tcx>>,
|
|
||||||
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<Ty<'tcx>>,
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::check::regionck::OutlivesEnvironmentExt;
|
|
||||||
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
|
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
|
||||||
|
use crate::outlives::outlives_bounds::InferCtxtExt as _;
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
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);
|
let mut outlives_environment = OutlivesEnvironment::builder(param_env);
|
||||||
outlives_environment.add_implied_bounds(infcx, assumed_wf_types, body_id);
|
outlives_environment.add_implied_bounds(infcx, assumed_wf_types, body_id);
|
||||||
let outlives_environment = outlives_environment.build();
|
let outlives_environment = outlives_environment.build();
|
||||||
|
|
||||||
infcx.check_region_obligations_and_report_errors(body_def_id, &outlives_environment);
|
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
|
// region constraints get added and solved there and we need to test each
|
||||||
// call individually.
|
// call individually.
|
||||||
tcx.infer_ctxt().enter(|infcx| {
|
tcx.infer_ctxt().enter(|infcx| {
|
||||||
let mut outlives_environment = OutlivesEnvironment::builder(param_env);
|
let outlives_environment = OutlivesEnvironment::with_bounds(
|
||||||
outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id);
|
param_env,
|
||||||
let outlives_environment = outlives_environment.build();
|
Some(&infcx),
|
||||||
|
infcx.implied_bounds_tys(param_env, id, wf_tys.iter().map(|ty| *ty)),
|
||||||
|
);
|
||||||
let region_bound_pairs = outlives_environment.region_bound_pairs();
|
let region_bound_pairs = outlives_environment.region_bound_pairs();
|
||||||
|
|
||||||
add_constraints(&infcx, region_bound_pairs);
|
add_constraints(&infcx, region_bound_pairs);
|
||||||
|
|
|
@ -65,9 +65,9 @@
|
||||||
//! cause use after frees with purely safe code in the same way as specializing
|
//! cause use after frees with purely safe code in the same way as specializing
|
||||||
//! on traits with methods can.
|
//! on traits with methods can.
|
||||||
|
|
||||||
use crate::check::regionck::OutlivesEnvironmentExt;
|
|
||||||
use crate::constrained_generic_params as cgp;
|
use crate::constrained_generic_params as cgp;
|
||||||
use crate::errors::SubstsOnOverriddenImpl;
|
use crate::errors::SubstsOnOverriddenImpl;
|
||||||
|
use crate::outlives::outlives_bounds::InferCtxtExt;
|
||||||
|
|
||||||
use rustc_data_structures::fx::FxHashSet;
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||||
|
@ -147,10 +147,17 @@ fn get_impl_substs<'tcx>(
|
||||||
let assumed_wf_types =
|
let assumed_wf_types =
|
||||||
ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
|
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 =
|
let impl2_substs =
|
||||||
translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
|
translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let errors = ocx.select_all_or_error();
|
let errors = ocx.select_all_or_error();
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
ocx.infcx.report_fulfillment_errors(&errors, None, false);
|
ocx.infcx.report_fulfillment_errors(&errors, None, false);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use rustc_hir as hir;
|
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::infer::InferCtxt;
|
||||||
use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput};
|
use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput};
|
||||||
use rustc_trait_selection::traits::query::NoSolution;
|
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 use rustc_middle::traits::query::OutlivesBound;
|
||||||
|
|
||||||
pub trait InferCtxtExt<'tcx> {
|
pub trait InferCtxtExt<'a, 'tcx> {
|
||||||
fn implied_outlives_bounds(
|
fn implied_outlives_bounds(
|
||||||
&self,
|
&self,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
body_id: hir::HirId,
|
body_id: hir::HirId,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Vec<OutlivesBound<'tcx>>;
|
) -> Vec<OutlivesBound<'tcx>>;
|
||||||
|
|
||||||
|
fn implied_bounds_tys(
|
||||||
|
&'a self,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
body_id: hir::HirId,
|
||||||
|
tys: impl IntoIterator<Item = Ty<'tcx>> + 'a,
|
||||||
|
) -> Box<dyn Iterator<Item = OutlivesBound<'tcx>> + '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
|
/// Implied bounds are region relationships that we deduce
|
||||||
/// automatically. The idea is that (e.g.) a caller must check that a
|
/// automatically. The idea is that (e.g.) a caller must check that a
|
||||||
/// function's argument types are well-formed immediately before
|
/// function's argument types are well-formed immediately before
|
||||||
|
@ -87,4 +95,20 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||||
|
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn implied_bounds_tys(
|
||||||
|
&'a self,
|
||||||
|
param_env: ParamEnv<'tcx>,
|
||||||
|
body_id: HirId,
|
||||||
|
tys: impl IntoIterator<Item = Ty<'tcx>> + 'a,
|
||||||
|
) -> Box<dyn Iterator<Item = OutlivesBound<'tcx>> + '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(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue