Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e60daca

Browse files
committedApr 2, 2025·
move ClosureRegionRequirements to rustc_borrowck
1 parent 6396e1f commit e60daca

File tree

7 files changed

+155
-155
lines changed

7 files changed

+155
-155
lines changed
 

‎compiler/rustc_borrowck/src/lib.rs

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use rustc_infer::infer::{
3636
};
3737
use rustc_middle::mir::*;
3838
use rustc_middle::query::Providers;
39-
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode, fold_regions};
39+
use rustc_middle::ty::{self, ParamEnv, RegionVid, Ty, TyCtxt, TypingMode, fold_regions};
4040
use rustc_middle::{bug, span_bug};
4141
use rustc_mir_dataflow::impls::{
4242
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
@@ -135,6 +135,143 @@ struct BorrowCheckResult<'tcx> {
135135
used_mut_upvars: SmallVec<[FieldIdx; 8]>,
136136
}
137137

138+
/// After we borrow check a closure, we are left with various
139+
/// requirements that we have inferred between the free regions that
140+
/// appear in the closure's signature or on its field types. These
141+
/// requirements are then verified and proved by the closure's
142+
/// creating function. This struct encodes those requirements.
143+
///
144+
/// The requirements are listed as being between various `RegionVid`. The 0th
145+
/// region refers to `'static`; subsequent region vids refer to the free
146+
/// regions that appear in the closure (or coroutine's) type, in order of
147+
/// appearance. (This numbering is actually defined by the `UniversalRegions`
148+
/// struct in the NLL region checker. See for example
149+
/// `UniversalRegions::closure_mapping`.) Note the free regions in the
150+
/// closure's signature and captures are erased.
151+
///
152+
/// Example: If type check produces a closure with the closure args:
153+
///
154+
/// ```text
155+
/// ClosureArgs = [
156+
/// 'a, // From the parent.
157+
/// 'b,
158+
/// i8, // the "closure kind"
159+
/// for<'x> fn(&'<erased> &'x u32) -> &'x u32, // the "closure signature"
160+
/// &'<erased> String, // some upvar
161+
/// ]
162+
/// ```
163+
///
164+
/// We would "renumber" each free region to a unique vid, as follows:
165+
///
166+
/// ```text
167+
/// ClosureArgs = [
168+
/// '1, // From the parent.
169+
/// '2,
170+
/// i8, // the "closure kind"
171+
/// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature"
172+
/// &'4 String, // some upvar
173+
/// ]
174+
/// ```
175+
///
176+
/// Now the code might impose a requirement like `'1: '2`. When an
177+
/// instance of the closure is created, the corresponding free regions
178+
/// can be extracted from its type and constrained to have the given
179+
/// outlives relationship.
180+
#[derive(Clone, Debug)]
181+
pub struct ClosureRegionRequirements<'tcx> {
182+
/// The number of external regions defined on the closure. In our
183+
/// example above, it would be 3 -- one for `'static`, then `'1`
184+
/// and `'2`. This is just used for a sanity check later on, to
185+
/// make sure that the number of regions we see at the callsite
186+
/// matches.
187+
pub num_external_vids: usize,
188+
189+
/// Requirements between the various free regions defined in
190+
/// indices.
191+
pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
192+
}
193+
194+
/// Indicates an outlives-constraint between a type or between two
195+
/// free regions declared on the closure.
196+
#[derive(Copy, Clone, Debug)]
197+
pub struct ClosureOutlivesRequirement<'tcx> {
198+
// This region or type ...
199+
pub subject: ClosureOutlivesSubject<'tcx>,
200+
201+
// ... must outlive this one.
202+
pub outlived_free_region: ty::RegionVid,
203+
204+
// If not, report an error here ...
205+
pub blame_span: Span,
206+
207+
// ... due to this reason.
208+
pub category: ConstraintCategory<'tcx>,
209+
}
210+
211+
// Make sure this enum doesn't unintentionally grow
212+
#[cfg(target_pointer_width = "64")]
213+
rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
214+
215+
/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
216+
/// that must outlive some region.
217+
#[derive(Copy, Clone, Debug)]
218+
pub enum ClosureOutlivesSubject<'tcx> {
219+
/// Subject is a type, typically a type parameter, but could also
220+
/// be a projection. Indicates a requirement like `T: 'a` being
221+
/// passed to the caller, where the type here is `T`.
222+
Ty(ClosureOutlivesSubjectTy<'tcx>),
223+
224+
/// Subject is a free region from the closure. Indicates a requirement
225+
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
226+
Region(ty::RegionVid),
227+
}
228+
229+
/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
230+
///
231+
/// This abstraction is necessary because the type may include `ReVar` regions,
232+
/// which is what we use internally within NLL code, and they can't be used in
233+
/// a query response.
234+
///
235+
/// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
236+
/// type is not recognized as a binder for late-bound region.
237+
#[derive(Copy, Clone, Debug)]
238+
pub struct ClosureOutlivesSubjectTy<'tcx> {
239+
inner: Ty<'tcx>,
240+
}
241+
242+
impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
243+
/// All regions of `ty` must be of kind `ReVar` and must represent
244+
/// universal regions *external* to the closure.
245+
pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
246+
let inner = fold_regions(tcx, ty, |r, depth| match r.kind() {
247+
ty::ReVar(vid) => {
248+
let br = ty::BoundRegion {
249+
var: ty::BoundVar::from_usize(vid.index()),
250+
kind: ty::BoundRegionKind::Anon,
251+
};
252+
ty::Region::new_bound(tcx, depth, br)
253+
}
254+
_ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
255+
});
256+
257+
Self { inner }
258+
}
259+
260+
pub fn instantiate(
261+
self,
262+
tcx: TyCtxt<'tcx>,
263+
mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
264+
) -> Ty<'tcx> {
265+
fold_regions(tcx, self.inner, |r, depth| match r.kind() {
266+
ty::ReBound(debruijn, br) => {
267+
debug_assert_eq!(debruijn, depth);
268+
map(ty::RegionVid::from_usize(br.var.index()))
269+
}
270+
_ => bug!("unexpected region {r:?}"),
271+
})
272+
}
273+
}
274+
138275
/// Perform the actual borrow checking.
139276
///
140277
/// Use `consumer_options: None` for the default behavior of returning

‎compiler/rustc_borrowck/src/nll.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@ use std::str::FromStr;
88
use polonius_engine::{Algorithm, Output};
99
use rustc_index::IndexSlice;
1010
use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options};
11-
use rustc_middle::mir::{
12-
Body, ClosureOutlivesSubject, ClosureRegionRequirements, PassWhere, Promoted, create_dump_file,
13-
dump_enabled, dump_mir,
14-
};
11+
use rustc_middle::mir::{Body, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir};
1512
use rustc_middle::ty::print::with_no_trimmed_paths;
1613
use rustc_middle::ty::{self, TyCtxt};
1714
use rustc_mir_dataflow::ResultsCursor;
@@ -32,7 +29,10 @@ use crate::polonius::legacy::{
3229
use crate::region_infer::RegionInferenceContext;
3330
use crate::type_check::{self, MirTypeckResults};
3431
use crate::universal_regions::UniversalRegions;
35-
use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt, polonius, renumber};
32+
use crate::{
33+
BorrowCheckRootCtxt, BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements,
34+
polonius, renumber,
35+
};
3636

3737
/// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any
3838
/// closure requirements to propagate, and any generated errors.

‎compiler/rustc_borrowck/src/polonius/dump.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_index::IndexVec;
55
use rustc_middle::mir::pretty::{
66
PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer,
77
};
8-
use rustc_middle::mir::{Body, ClosureRegionRequirements, Location};
8+
use rustc_middle::mir::{Body, Location};
99
use rustc_middle::ty::{RegionVid, TyCtxt};
1010
use rustc_mir_dataflow::points::PointIndex;
1111
use rustc_session::config::MirIncludeSpans;
@@ -17,7 +17,7 @@ use crate::polonius::{
1717
};
1818
use crate::region_infer::values::LivenessValues;
1919
use crate::type_check::Locations;
20-
use crate::{BorrowckInferCtxt, RegionInferenceContext};
20+
use crate::{BorrowckInferCtxt, ClosureRegionRequirements, RegionInferenceContext};
2121

2222
/// `-Zdump-mir=polonius` dumps MIR annotated with NLL and polonius specific information.
2323
pub(crate) fn dump_polonius_mir<'tcx>(

‎compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,8 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound,
1313
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
1414
use rustc_middle::bug;
1515
use rustc_middle::mir::{
16-
AnnotationSource, BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject,
17-
ClosureOutlivesSubjectTy, ClosureRegionRequirements, ConstraintCategory, Local, Location,
18-
ReturnConstraint, TerminatorKind,
16+
AnnotationSource, BasicBlock, Body, ConstraintCategory, Local, Location, ReturnConstraint,
17+
TerminatorKind,
1918
};
2019
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
2120
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex, fold_regions};
@@ -24,7 +23,6 @@ use rustc_span::hygiene::DesugaringKind;
2423
use rustc_span::{DUMMY_SP, Span};
2524
use tracing::{debug, instrument, trace};
2625

27-
use crate::BorrowckInferCtxt;
2826
use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
2927
use crate::constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet};
3028
use crate::dataflow::BorrowIndex;
@@ -37,6 +35,10 @@ use crate::region_infer::values::{LivenessValues, RegionElement, RegionValues, T
3735
use crate::type_check::free_region_relations::UniversalRegionRelations;
3836
use crate::type_check::{Locations, MirTypeckRegionConstraints};
3937
use crate::universal_regions::UniversalRegions;
38+
use crate::{
39+
BorrowckInferCtxt, ClosureOutlivesRequirement, ClosureOutlivesSubject,
40+
ClosureOutlivesSubjectTy, ClosureRegionRequirements,
41+
};
4042

4143
mod dump_mir;
4244
mod graphviz;

‎compiler/rustc_borrowck/src/root_cx.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ use rustc_abi::FieldIdx;
22
use rustc_data_structures::fx::FxHashMap;
33
use rustc_hir::def_id::LocalDefId;
44
use rustc_middle::bug;
5-
use rustc_middle::mir::{ClosureRegionRequirements, ConcreteOpaqueTypes};
65
use rustc_middle::ty::{OpaqueHiddenType, Ty, TyCtxt, TypeVisitableExt};
76
use rustc_span::ErrorGuaranteed;
87
use smallvec::SmallVec;
98

10-
use crate::BorrowCheckResult;
9+
use crate::{BorrowCheckResult, ClosureRegionRequirements, ConcreteOpaqueTypes};
1110

1211
/// The shared context used by both the root as well as all its nested
1312
/// items.

‎compiler/rustc_borrowck/src/type_check/constraint_conversion.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
66
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
77
use rustc_infer::traits::query::type_op::DeeplyNormalize;
88
use rustc_middle::bug;
9-
use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
109
use rustc_middle::ty::{
1110
self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions,
1211
};
@@ -18,6 +17,7 @@ use crate::constraints::OutlivesConstraint;
1817
use crate::region_infer::TypeTest;
1918
use crate::type_check::{Locations, MirTypeckRegionConstraints};
2019
use crate::universal_regions::UniversalRegions;
20+
use crate::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
2121

2222
pub(crate) struct ConstraintConversion<'a, 'tcx> {
2323
infcx: &'a InferCtxt<'tcx>,

‎compiler/rustc_middle/src/mir/query.rs

Lines changed: 2 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ use rustc_abi::{FieldIdx, VariantIdx};
66
use rustc_data_structures::fx::FxIndexMap;
77
use rustc_errors::ErrorGuaranteed;
88
use rustc_hir::def_id::LocalDefId;
9+
use rustc_index::IndexVec;
910
use rustc_index::bit_set::BitMatrix;
10-
use rustc_index::{Idx, IndexVec};
1111
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
1212
use rustc_span::{Span, Symbol};
1313

1414
use super::{ConstValue, SourceInfo};
15-
use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt, fold_regions};
15+
use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty};
1616

1717
rustc_index::newtype_index! {
1818
#[derive(HashStable)]
@@ -102,84 +102,6 @@ pub struct ConstQualifs {
102102
pub needs_non_const_drop: bool,
103103
pub tainted_by_errors: Option<ErrorGuaranteed>,
104104
}
105-
106-
/// After we borrow check a closure, we are left with various
107-
/// requirements that we have inferred between the free regions that
108-
/// appear in the closure's signature or on its field types. These
109-
/// requirements are then verified and proved by the closure's
110-
/// creating function. This struct encodes those requirements.
111-
///
112-
/// The requirements are listed as being between various `RegionVid`. The 0th
113-
/// region refers to `'static`; subsequent region vids refer to the free
114-
/// regions that appear in the closure (or coroutine's) type, in order of
115-
/// appearance. (This numbering is actually defined by the `UniversalRegions`
116-
/// struct in the NLL region checker. See for example
117-
/// `UniversalRegions::closure_mapping`.) Note the free regions in the
118-
/// closure's signature and captures are erased.
119-
///
120-
/// Example: If type check produces a closure with the closure args:
121-
///
122-
/// ```text
123-
/// ClosureArgs = [
124-
/// 'a, // From the parent.
125-
/// 'b,
126-
/// i8, // the "closure kind"
127-
/// for<'x> fn(&'<erased> &'x u32) -> &'x u32, // the "closure signature"
128-
/// &'<erased> String, // some upvar
129-
/// ]
130-
/// ```
131-
///
132-
/// We would "renumber" each free region to a unique vid, as follows:
133-
///
134-
/// ```text
135-
/// ClosureArgs = [
136-
/// '1, // From the parent.
137-
/// '2,
138-
/// i8, // the "closure kind"
139-
/// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature"
140-
/// &'4 String, // some upvar
141-
/// ]
142-
/// ```
143-
///
144-
/// Now the code might impose a requirement like `'1: '2`. When an
145-
/// instance of the closure is created, the corresponding free regions
146-
/// can be extracted from its type and constrained to have the given
147-
/// outlives relationship.
148-
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
149-
pub struct ClosureRegionRequirements<'tcx> {
150-
/// The number of external regions defined on the closure. In our
151-
/// example above, it would be 3 -- one for `'static`, then `'1`
152-
/// and `'2`. This is just used for a sanity check later on, to
153-
/// make sure that the number of regions we see at the callsite
154-
/// matches.
155-
pub num_external_vids: usize,
156-
157-
/// Requirements between the various free regions defined in
158-
/// indices.
159-
pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
160-
}
161-
162-
/// Indicates an outlives-constraint between a type or between two
163-
/// free regions declared on the closure.
164-
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
165-
pub struct ClosureOutlivesRequirement<'tcx> {
166-
// This region or type ...
167-
pub subject: ClosureOutlivesSubject<'tcx>,
168-
169-
// ... must outlive this one.
170-
pub outlived_free_region: ty::RegionVid,
171-
172-
// If not, report an error here ...
173-
pub blame_span: Span,
174-
175-
// ... due to this reason.
176-
pub category: ConstraintCategory<'tcx>,
177-
}
178-
179-
// Make sure this enum doesn't unintentionally grow
180-
#[cfg(target_pointer_width = "64")]
181-
rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
182-
183105
/// Outlives-constraints can be categorized to determine whether and why they
184106
/// are interesting (for error reporting). Order of variants indicates sort
185107
/// order of the category, thereby influencing diagnostic output.
@@ -247,66 +169,6 @@ pub enum AnnotationSource {
247169
GenericArg,
248170
}
249171

250-
/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
251-
/// that must outlive some region.
252-
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
253-
pub enum ClosureOutlivesSubject<'tcx> {
254-
/// Subject is a type, typically a type parameter, but could also
255-
/// be a projection. Indicates a requirement like `T: 'a` being
256-
/// passed to the caller, where the type here is `T`.
257-
Ty(ClosureOutlivesSubjectTy<'tcx>),
258-
259-
/// Subject is a free region from the closure. Indicates a requirement
260-
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
261-
Region(ty::RegionVid),
262-
}
263-
264-
/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
265-
///
266-
/// This abstraction is necessary because the type may include `ReVar` regions,
267-
/// which is what we use internally within NLL code, and they can't be used in
268-
/// a query response.
269-
///
270-
/// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
271-
/// type is not recognized as a binder for late-bound region.
272-
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
273-
pub struct ClosureOutlivesSubjectTy<'tcx> {
274-
inner: Ty<'tcx>,
275-
}
276-
277-
impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
278-
/// All regions of `ty` must be of kind `ReVar` and must represent
279-
/// universal regions *external* to the closure.
280-
pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
281-
let inner = fold_regions(tcx, ty, |r, depth| match r.kind() {
282-
ty::ReVar(vid) => {
283-
let br = ty::BoundRegion {
284-
var: ty::BoundVar::new(vid.index()),
285-
kind: ty::BoundRegionKind::Anon,
286-
};
287-
ty::Region::new_bound(tcx, depth, br)
288-
}
289-
_ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
290-
});
291-
292-
Self { inner }
293-
}
294-
295-
pub fn instantiate(
296-
self,
297-
tcx: TyCtxt<'tcx>,
298-
mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
299-
) -> Ty<'tcx> {
300-
fold_regions(tcx, self.inner, |r, depth| match r.kind() {
301-
ty::ReBound(debruijn, br) => {
302-
debug_assert_eq!(debruijn, depth);
303-
map(ty::RegionVid::new(br.var.index()))
304-
}
305-
_ => bug!("unexpected region {r:?}"),
306-
})
307-
}
308-
}
309-
310172
/// The constituent parts of a mir constant of kind ADT or array.
311173
#[derive(Copy, Clone, Debug, HashStable)]
312174
pub struct DestructuredConstant<'tcx> {

0 commit comments

Comments
 (0)
Please sign in to comment.