move ClosureRegionRequirements
to rustc_borrowck
This commit is contained in:
parent
f05a23be5c
commit
474ec7a3f4
7 changed files with 155 additions and 155 deletions
|
@ -36,7 +36,7 @@ use rustc_infer::infer::{
|
|||
};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
|
||||
use rustc_middle::ty::{self, ParamEnv, RegionVid, Ty, TyCtxt, TypingMode, fold_regions};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_mir_dataflow::impls::{
|
||||
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
|
||||
|
@ -140,6 +140,143 @@ struct PropagatedBorrowCheckResults<'tcx> {
|
|||
used_mut_upvars: SmallVec<[FieldIdx; 8]>,
|
||||
}
|
||||
|
||||
/// After we borrow check a closure, we are left with various
|
||||
/// requirements that we have inferred between the free regions that
|
||||
/// appear in the closure's signature or on its field types. These
|
||||
/// requirements are then verified and proved by the closure's
|
||||
/// creating function. This struct encodes those requirements.
|
||||
///
|
||||
/// The requirements are listed as being between various `RegionVid`. The 0th
|
||||
/// region refers to `'static`; subsequent region vids refer to the free
|
||||
/// regions that appear in the closure (or coroutine's) type, in order of
|
||||
/// appearance. (This numbering is actually defined by the `UniversalRegions`
|
||||
/// struct in the NLL region checker. See for example
|
||||
/// `UniversalRegions::closure_mapping`.) Note the free regions in the
|
||||
/// closure's signature and captures are erased.
|
||||
///
|
||||
/// Example: If type check produces a closure with the closure args:
|
||||
///
|
||||
/// ```text
|
||||
/// ClosureArgs = [
|
||||
/// 'a, // From the parent.
|
||||
/// 'b,
|
||||
/// i8, // the "closure kind"
|
||||
/// for<'x> fn(&'<erased> &'x u32) -> &'x u32, // the "closure signature"
|
||||
/// &'<erased> String, // some upvar
|
||||
/// ]
|
||||
/// ```
|
||||
///
|
||||
/// We would "renumber" each free region to a unique vid, as follows:
|
||||
///
|
||||
/// ```text
|
||||
/// ClosureArgs = [
|
||||
/// '1, // From the parent.
|
||||
/// '2,
|
||||
/// i8, // the "closure kind"
|
||||
/// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature"
|
||||
/// &'4 String, // some upvar
|
||||
/// ]
|
||||
/// ```
|
||||
///
|
||||
/// Now the code might impose a requirement like `'1: '2`. When an
|
||||
/// instance of the closure is created, the corresponding free regions
|
||||
/// can be extracted from its type and constrained to have the given
|
||||
/// outlives relationship.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ClosureRegionRequirements<'tcx> {
|
||||
/// The number of external regions defined on the closure. In our
|
||||
/// example above, it would be 3 -- one for `'static`, then `'1`
|
||||
/// and `'2`. This is just used for a sanity check later on, to
|
||||
/// make sure that the number of regions we see at the callsite
|
||||
/// matches.
|
||||
pub num_external_vids: usize,
|
||||
|
||||
/// Requirements between the various free regions defined in
|
||||
/// indices.
|
||||
pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
|
||||
}
|
||||
|
||||
/// Indicates an outlives-constraint between a type or between two
|
||||
/// free regions declared on the closure.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ClosureOutlivesRequirement<'tcx> {
|
||||
// This region or type ...
|
||||
pub subject: ClosureOutlivesSubject<'tcx>,
|
||||
|
||||
// ... must outlive this one.
|
||||
pub outlived_free_region: ty::RegionVid,
|
||||
|
||||
// If not, report an error here ...
|
||||
pub blame_span: Span,
|
||||
|
||||
// ... due to this reason.
|
||||
pub category: ConstraintCategory<'tcx>,
|
||||
}
|
||||
|
||||
// Make sure this enum doesn't unintentionally grow
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
|
||||
|
||||
/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
|
||||
/// that must outlive some region.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ClosureOutlivesSubject<'tcx> {
|
||||
/// Subject is a type, typically a type parameter, but could also
|
||||
/// be a projection. Indicates a requirement like `T: 'a` being
|
||||
/// passed to the caller, where the type here is `T`.
|
||||
Ty(ClosureOutlivesSubjectTy<'tcx>),
|
||||
|
||||
/// Subject is a free region from the closure. Indicates a requirement
|
||||
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
|
||||
Region(ty::RegionVid),
|
||||
}
|
||||
|
||||
/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
|
||||
///
|
||||
/// This abstraction is necessary because the type may include `ReVar` regions,
|
||||
/// which is what we use internally within NLL code, and they can't be used in
|
||||
/// a query response.
|
||||
///
|
||||
/// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
|
||||
/// type is not recognized as a binder for late-bound region.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ClosureOutlivesSubjectTy<'tcx> {
|
||||
inner: Ty<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
|
||||
/// All regions of `ty` must be of kind `ReVar` and must represent
|
||||
/// universal regions *external* to the closure.
|
||||
pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
|
||||
let inner = fold_regions(tcx, ty, |r, depth| match r.kind() {
|
||||
ty::ReVar(vid) => {
|
||||
let br = ty::BoundRegion {
|
||||
var: ty::BoundVar::from_usize(vid.index()),
|
||||
kind: ty::BoundRegionKind::Anon,
|
||||
};
|
||||
ty::Region::new_bound(tcx, depth, br)
|
||||
}
|
||||
_ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
|
||||
});
|
||||
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
pub fn instantiate(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
fold_regions(tcx, self.inner, |r, depth| match r.kind() {
|
||||
ty::ReBound(debruijn, br) => {
|
||||
debug_assert_eq!(debruijn, depth);
|
||||
map(ty::RegionVid::from_usize(br.var.index()))
|
||||
}
|
||||
_ => bug!("unexpected region {r:?}"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform the actual borrow checking.
|
||||
///
|
||||
/// Use `consumer_options: None` for the default behavior of returning
|
||||
|
|
|
@ -8,10 +8,7 @@ use std::str::FromStr;
|
|||
use polonius_engine::{Algorithm, Output};
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options};
|
||||
use rustc_middle::mir::{
|
||||
Body, ClosureOutlivesSubject, ClosureRegionRequirements, PassWhere, Promoted, create_dump_file,
|
||||
dump_enabled, dump_mir,
|
||||
};
|
||||
use rustc_middle::mir::{Body, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_mir_dataflow::ResultsCursor;
|
||||
|
@ -32,7 +29,10 @@ use crate::polonius::legacy::{
|
|||
use crate::region_infer::RegionInferenceContext;
|
||||
use crate::type_check::{self, MirTypeckResults};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt, polonius, renumber};
|
||||
use crate::{
|
||||
BorrowCheckRootCtxt, BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements,
|
||||
polonius, renumber,
|
||||
};
|
||||
|
||||
/// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any
|
||||
/// closure requirements to propagate, and any generated errors.
|
||||
|
|
|
@ -5,7 +5,7 @@ use rustc_index::IndexVec;
|
|||
use rustc_middle::mir::pretty::{
|
||||
PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer,
|
||||
};
|
||||
use rustc_middle::mir::{Body, ClosureRegionRequirements, Location};
|
||||
use rustc_middle::mir::{Body, Location};
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_mir_dataflow::points::PointIndex;
|
||||
use rustc_session::config::MirIncludeSpans;
|
||||
|
@ -17,7 +17,7 @@ use crate::polonius::{
|
|||
};
|
||||
use crate::region_infer::values::LivenessValues;
|
||||
use crate::type_check::Locations;
|
||||
use crate::{BorrowckInferCtxt, RegionInferenceContext};
|
||||
use crate::{BorrowckInferCtxt, ClosureRegionRequirements, RegionInferenceContext};
|
||||
|
||||
/// `-Zdump-mir=polonius` dumps MIR annotated with NLL and polonius specific information.
|
||||
pub(crate) fn dump_polonius_mir<'tcx>(
|
||||
|
|
|
@ -13,9 +13,8 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound,
|
|||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::{
|
||||
AnnotationSource, BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject,
|
||||
ClosureOutlivesSubjectTy, ClosureRegionRequirements, ConstraintCategory, Local, Location,
|
||||
ReturnConstraint, TerminatorKind,
|
||||
AnnotationSource, BasicBlock, Body, ConstraintCategory, Local, Location, ReturnConstraint,
|
||||
TerminatorKind,
|
||||
};
|
||||
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex, fold_regions};
|
||||
|
@ -24,7 +23,6 @@ use rustc_span::hygiene::DesugaringKind;
|
|||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::{Level, debug, enabled, instrument, trace};
|
||||
|
||||
use crate::BorrowckInferCtxt;
|
||||
use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
|
||||
use crate::constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet};
|
||||
use crate::dataflow::BorrowIndex;
|
||||
|
@ -37,6 +35,10 @@ use crate::region_infer::values::{LivenessValues, RegionElement, RegionValues, T
|
|||
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
||||
use crate::type_check::{Locations, MirTypeckRegionConstraints};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
use crate::{
|
||||
BorrowckInferCtxt, ClosureOutlivesRequirement, ClosureOutlivesSubject,
|
||||
ClosureOutlivesSubjectTy, ClosureRegionRequirements,
|
||||
};
|
||||
|
||||
mod dump_mir;
|
||||
mod graphviz;
|
||||
|
|
|
@ -2,12 +2,11 @@ use rustc_abi::FieldIdx;
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::{ClosureRegionRequirements, ConcreteOpaqueTypes};
|
||||
use rustc_middle::ty::{OpaqueHiddenType, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::PropagatedBorrowCheckResults;
|
||||
use crate::{ClosureRegionRequirements, ConcreteOpaqueTypes, PropagatedBorrowCheckResults};
|
||||
|
||||
/// The shared context used by both the root as well as all its nested
|
||||
/// items.
|
||||
|
|
|
@ -6,7 +6,6 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
|
|||
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
|
||||
use rustc_infer::traits::query::type_op::DeeplyNormalize;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions,
|
||||
};
|
||||
|
@ -18,6 +17,7 @@ use crate::constraints::OutlivesConstraint;
|
|||
use crate::region_infer::TypeTest;
|
||||
use crate::type_check::{Locations, MirTypeckRegionConstraints};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
use crate::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
|
||||
|
||||
pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
|
|
|
@ -6,13 +6,13 @@ use rustc_abi::{FieldIdx, VariantIdx};
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_index::bit_set::BitMatrix;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use super::{ConstValue, SourceInfo};
|
||||
use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt, fold_regions};
|
||||
use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty};
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
#[derive(HashStable)]
|
||||
|
@ -102,84 +102,6 @@ pub struct ConstQualifs {
|
|||
pub needs_non_const_drop: bool,
|
||||
pub tainted_by_errors: Option<ErrorGuaranteed>,
|
||||
}
|
||||
|
||||
/// After we borrow check a closure, we are left with various
|
||||
/// requirements that we have inferred between the free regions that
|
||||
/// appear in the closure's signature or on its field types. These
|
||||
/// requirements are then verified and proved by the closure's
|
||||
/// creating function. This struct encodes those requirements.
|
||||
///
|
||||
/// The requirements are listed as being between various `RegionVid`. The 0th
|
||||
/// region refers to `'static`; subsequent region vids refer to the free
|
||||
/// regions that appear in the closure (or coroutine's) type, in order of
|
||||
/// appearance. (This numbering is actually defined by the `UniversalRegions`
|
||||
/// struct in the NLL region checker. See for example
|
||||
/// `UniversalRegions::closure_mapping`.) Note the free regions in the
|
||||
/// closure's signature and captures are erased.
|
||||
///
|
||||
/// Example: If type check produces a closure with the closure args:
|
||||
///
|
||||
/// ```text
|
||||
/// ClosureArgs = [
|
||||
/// 'a, // From the parent.
|
||||
/// 'b,
|
||||
/// i8, // the "closure kind"
|
||||
/// for<'x> fn(&'<erased> &'x u32) -> &'x u32, // the "closure signature"
|
||||
/// &'<erased> String, // some upvar
|
||||
/// ]
|
||||
/// ```
|
||||
///
|
||||
/// We would "renumber" each free region to a unique vid, as follows:
|
||||
///
|
||||
/// ```text
|
||||
/// ClosureArgs = [
|
||||
/// '1, // From the parent.
|
||||
/// '2,
|
||||
/// i8, // the "closure kind"
|
||||
/// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature"
|
||||
/// &'4 String, // some upvar
|
||||
/// ]
|
||||
/// ```
|
||||
///
|
||||
/// Now the code might impose a requirement like `'1: '2`. When an
|
||||
/// instance of the closure is created, the corresponding free regions
|
||||
/// can be extracted from its type and constrained to have the given
|
||||
/// outlives relationship.
|
||||
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct ClosureRegionRequirements<'tcx> {
|
||||
/// The number of external regions defined on the closure. In our
|
||||
/// example above, it would be 3 -- one for `'static`, then `'1`
|
||||
/// and `'2`. This is just used for a sanity check later on, to
|
||||
/// make sure that the number of regions we see at the callsite
|
||||
/// matches.
|
||||
pub num_external_vids: usize,
|
||||
|
||||
/// Requirements between the various free regions defined in
|
||||
/// indices.
|
||||
pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
|
||||
}
|
||||
|
||||
/// Indicates an outlives-constraint between a type or between two
|
||||
/// free regions declared on the closure.
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct ClosureOutlivesRequirement<'tcx> {
|
||||
// This region or type ...
|
||||
pub subject: ClosureOutlivesSubject<'tcx>,
|
||||
|
||||
// ... must outlive this one.
|
||||
pub outlived_free_region: ty::RegionVid,
|
||||
|
||||
// If not, report an error here ...
|
||||
pub blame_span: Span,
|
||||
|
||||
// ... due to this reason.
|
||||
pub category: ConstraintCategory<'tcx>,
|
||||
}
|
||||
|
||||
// Make sure this enum doesn't unintentionally grow
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
|
||||
|
||||
/// Outlives-constraints can be categorized to determine whether and why they
|
||||
/// are interesting (for error reporting). Order of variants indicates sort
|
||||
/// order of the category, thereby influencing diagnostic output.
|
||||
|
@ -247,66 +169,6 @@ pub enum AnnotationSource {
|
|||
GenericArg,
|
||||
}
|
||||
|
||||
/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
|
||||
/// that must outlive some region.
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub enum ClosureOutlivesSubject<'tcx> {
|
||||
/// Subject is a type, typically a type parameter, but could also
|
||||
/// be a projection. Indicates a requirement like `T: 'a` being
|
||||
/// passed to the caller, where the type here is `T`.
|
||||
Ty(ClosureOutlivesSubjectTy<'tcx>),
|
||||
|
||||
/// Subject is a free region from the closure. Indicates a requirement
|
||||
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
|
||||
Region(ty::RegionVid),
|
||||
}
|
||||
|
||||
/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
|
||||
///
|
||||
/// This abstraction is necessary because the type may include `ReVar` regions,
|
||||
/// which is what we use internally within NLL code, and they can't be used in
|
||||
/// a query response.
|
||||
///
|
||||
/// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
|
||||
/// type is not recognized as a binder for late-bound region.
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct ClosureOutlivesSubjectTy<'tcx> {
|
||||
inner: Ty<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
|
||||
/// All regions of `ty` must be of kind `ReVar` and must represent
|
||||
/// universal regions *external* to the closure.
|
||||
pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
|
||||
let inner = fold_regions(tcx, ty, |r, depth| match r.kind() {
|
||||
ty::ReVar(vid) => {
|
||||
let br = ty::BoundRegion {
|
||||
var: ty::BoundVar::new(vid.index()),
|
||||
kind: ty::BoundRegionKind::Anon,
|
||||
};
|
||||
ty::Region::new_bound(tcx, depth, br)
|
||||
}
|
||||
_ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
|
||||
});
|
||||
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
pub fn instantiate(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
fold_regions(tcx, self.inner, |r, depth| match r.kind() {
|
||||
ty::ReBound(debruijn, br) => {
|
||||
debug_assert_eq!(debruijn, depth);
|
||||
map(ty::RegionVid::new(br.var.index()))
|
||||
}
|
||||
_ => bug!("unexpected region {r:?}"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// The constituent parts of a mir constant of kind ADT or array.
|
||||
#[derive(Copy, Clone, Debug, HashStable)]
|
||||
pub struct DestructuredConstant<'tcx> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue