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 d4f880f

Browse files
committedApr 8, 2025·
Auto merge of #138499 - lcnr:borrowck-typeck_root, r=oli-obk
borrowck typeck children together with their root This introduces new cycle errors, even with `feature(inline_const_pat)` removed, see the `non-structural-match-types-cycle-err.rs` test. The new cycle error happens as the layout of `async`-blocks relies on their `optimized_mir`. As that now depends on `mir_borrowck` of its typeck parent, computing the layout of an `async`-block during MIR building, e.g. when evaluating a named `const` pattern. I think there's currently no way to have a named const pattern whose type references an async block while being allowed? cc `@oli-obk` `@RalfJung` I cannot think of other cases where we currently rely on the MIR of a typeck children while borrowchecking their parent. The crater run came back without any breakage. My work here will prevent any future features which rely on this as we'll get locked into borrowchecking them together as I continue to work on rust-lang/types-team#129, cc `@rust-lang/types.` r? compiler-errors
2 parents f820b75 + d35ad8d commit d4f880f

File tree

22 files changed

+490
-368
lines changed

22 files changed

+490
-368
lines changed
 

‎compiler/rustc_borrowck/src/consumers.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub use super::polonius::legacy::{
1515
RichLocation, RustcFacts,
1616
};
1717
pub use super::region_infer::RegionInferenceContext;
18+
use crate::{BorrowCheckRootCtxt, do_mir_borrowck};
1819

1920
/// Options determining the output behavior of [`get_body_with_borrowck_facts`].
2021
///
@@ -97,8 +98,9 @@ pub struct BodyWithBorrowckFacts<'tcx> {
9798
/// * Polonius is highly unstable, so expect regular changes in its signature or other details.
9899
pub fn get_body_with_borrowck_facts(
99100
tcx: TyCtxt<'_>,
100-
def: LocalDefId,
101+
def_id: LocalDefId,
101102
options: ConsumerOptions,
102103
) -> BodyWithBorrowckFacts<'_> {
103-
*super::do_mir_borrowck(tcx, def, Some(options)).1.unwrap()
104+
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def_id);
105+
*do_mir_borrowck(&mut root_cx, def_id, Some(options)).1.unwrap()
104106
}

‎compiler/rustc_borrowck/src/lib.rs

Lines changed: 209 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#![feature(file_buffered)]
1010
#![feature(if_let_guard)]
1111
#![feature(let_chains)]
12+
#![feature(negative_impls)]
1213
#![feature(never_type)]
1314
#![feature(rustc_attrs)]
1415
#![feature(rustdoc_internals)]
@@ -21,6 +22,7 @@ use std::cell::RefCell;
2122
use std::marker::PhantomData;
2223
use std::ops::{ControlFlow, Deref};
2324

25+
use root_cx::BorrowCheckRootCtxt;
2426
use rustc_abi::FieldIdx;
2527
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
2628
use rustc_data_structures::graph::dominators::Dominators;
@@ -35,7 +37,9 @@ use rustc_infer::infer::{
3537
};
3638
use rustc_middle::mir::*;
3739
use rustc_middle::query::Providers;
38-
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
40+
use rustc_middle::ty::{
41+
self, ParamEnv, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypingMode, fold_regions,
42+
};
3943
use rustc_middle::{bug, span_bug};
4044
use rustc_mir_dataflow::impls::{
4145
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
@@ -45,7 +49,7 @@ use rustc_mir_dataflow::move_paths::{
4549
};
4650
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
4751
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
48-
use rustc_span::{Span, Symbol};
52+
use rustc_span::{ErrorGuaranteed, Span, Symbol};
4953
use smallvec::SmallVec;
5054
use tracing::{debug, instrument};
5155

@@ -73,14 +77,14 @@ mod def_use;
7377
mod diagnostics;
7478
mod member_constraints;
7579
mod nll;
76-
mod opaque_types;
7780
mod path_utils;
7881
mod place_ext;
7982
mod places_conflict;
8083
mod polonius;
8184
mod prefixes;
8285
mod region_infer;
8386
mod renumber;
87+
mod root_cx;
8488
mod session_diagnostics;
8589
mod type_check;
8690
mod universal_regions;
@@ -102,44 +106,202 @@ pub fn provide(providers: &mut Providers) {
102106
*providers = Providers { mir_borrowck, ..*providers };
103107
}
104108

105-
fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> {
109+
/// Provider for `query mir_borrowck`. Similar to `typeck`, this must
110+
/// only be called for typeck roots which will then borrowck all
111+
/// nested bodies as well.
112+
fn mir_borrowck(
113+
tcx: TyCtxt<'_>,
114+
def: LocalDefId,
115+
) -> Result<&ConcreteOpaqueTypes<'_>, ErrorGuaranteed> {
116+
assert!(!tcx.is_typeck_child(def.to_def_id()));
106117
let (input_body, _) = tcx.mir_promoted(def);
118+
debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
119+
107120
let input_body: &Body<'_> = &input_body.borrow();
108-
if input_body.should_skip() || input_body.tainted_by_errors.is_some() {
109-
debug!("Skipping borrowck because of injected body or tainted body");
110-
// Let's make up a borrowck result! Fun times!
111-
let result = BorrowCheckResult {
112-
concrete_opaque_types: FxIndexMap::default(),
113-
closure_requirements: None,
114-
used_mut_upvars: SmallVec::new(),
115-
tainted_by_errors: input_body.tainted_by_errors,
116-
};
117-
return tcx.arena.alloc(result);
121+
if let Some(guar) = input_body.tainted_by_errors {
122+
debug!("Skipping borrowck because of tainted body");
123+
Err(guar)
124+
} else if input_body.should_skip() {
125+
debug!("Skipping borrowck because of injected body");
126+
let opaque_types = ConcreteOpaqueTypes(Default::default());
127+
Ok(tcx.arena.alloc(opaque_types))
128+
} else {
129+
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def);
130+
let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
131+
do_mir_borrowck(&mut root_cx, def, None).0;
132+
debug_assert!(closure_requirements.is_none());
133+
debug_assert!(used_mut_upvars.is_empty());
134+
root_cx.finalize()
118135
}
136+
}
137+
138+
/// Data propagated to the typeck parent by nested items.
139+
/// This should always be empty for the typeck root.
140+
#[derive(Debug)]
141+
struct PropagatedBorrowCheckResults<'tcx> {
142+
closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
143+
used_mut_upvars: SmallVec<[FieldIdx; 8]>,
144+
}
145+
146+
/// After we borrow check a closure, we are left with various
147+
/// requirements that we have inferred between the free regions that
148+
/// appear in the closure's signature or on its field types. These
149+
/// requirements are then verified and proved by the closure's
150+
/// creating function. This struct encodes those requirements.
151+
///
152+
/// The requirements are listed as being between various `RegionVid`. The 0th
153+
/// region refers to `'static`; subsequent region vids refer to the free
154+
/// regions that appear in the closure (or coroutine's) type, in order of
155+
/// appearance. (This numbering is actually defined by the `UniversalRegions`
156+
/// struct in the NLL region checker. See for example
157+
/// `UniversalRegions::closure_mapping`.) Note the free regions in the
158+
/// closure's signature and captures are erased.
159+
///
160+
/// Example: If type check produces a closure with the closure args:
161+
///
162+
/// ```text
163+
/// ClosureArgs = [
164+
/// 'a, // From the parent.
165+
/// 'b,
166+
/// i8, // the "closure kind"
167+
/// for<'x> fn(&'<erased> &'x u32) -> &'x u32, // the "closure signature"
168+
/// &'<erased> String, // some upvar
169+
/// ]
170+
/// ```
171+
///
172+
/// We would "renumber" each free region to a unique vid, as follows:
173+
///
174+
/// ```text
175+
/// ClosureArgs = [
176+
/// '1, // From the parent.
177+
/// '2,
178+
/// i8, // the "closure kind"
179+
/// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature"
180+
/// &'4 String, // some upvar
181+
/// ]
182+
/// ```
183+
///
184+
/// Now the code might impose a requirement like `'1: '2`. When an
185+
/// instance of the closure is created, the corresponding free regions
186+
/// can be extracted from its type and constrained to have the given
187+
/// outlives relationship.
188+
#[derive(Clone, Debug)]
189+
pub struct ClosureRegionRequirements<'tcx> {
190+
/// The number of external regions defined on the closure. In our
191+
/// example above, it would be 3 -- one for `'static`, then `'1`
192+
/// and `'2`. This is just used for a sanity check later on, to
193+
/// make sure that the number of regions we see at the callsite
194+
/// matches.
195+
pub num_external_vids: usize,
196+
197+
/// Requirements between the various free regions defined in
198+
/// indices.
199+
pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
200+
}
119201

120-
let borrowck_result = do_mir_borrowck(tcx, def, None).0;
121-
debug!("mir_borrowck done");
202+
/// Indicates an outlives-constraint between a type or between two
203+
/// free regions declared on the closure.
204+
#[derive(Copy, Clone, Debug)]
205+
pub struct ClosureOutlivesRequirement<'tcx> {
206+
// This region or type ...
207+
pub subject: ClosureOutlivesSubject<'tcx>,
122208

123-
tcx.arena.alloc(borrowck_result)
209+
// ... must outlive this one.
210+
pub outlived_free_region: ty::RegionVid,
211+
212+
// If not, report an error here ...
213+
pub blame_span: Span,
214+
215+
// ... due to this reason.
216+
pub category: ConstraintCategory<'tcx>,
217+
}
218+
219+
// Make sure this enum doesn't unintentionally grow
220+
#[cfg(target_pointer_width = "64")]
221+
rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
222+
223+
/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
224+
/// that must outlive some region.
225+
#[derive(Copy, Clone, Debug)]
226+
pub enum ClosureOutlivesSubject<'tcx> {
227+
/// Subject is a type, typically a type parameter, but could also
228+
/// be a projection. Indicates a requirement like `T: 'a` being
229+
/// passed to the caller, where the type here is `T`.
230+
Ty(ClosureOutlivesSubjectTy<'tcx>),
231+
232+
/// Subject is a free region from the closure. Indicates a requirement
233+
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
234+
Region(ty::RegionVid),
235+
}
236+
237+
/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
238+
///
239+
/// This abstraction is necessary because the type may include `ReVar` regions,
240+
/// which is what we use internally within NLL code, and they can't be used in
241+
/// a query response.
242+
#[derive(Copy, Clone, Debug)]
243+
pub struct ClosureOutlivesSubjectTy<'tcx> {
244+
inner: Ty<'tcx>,
245+
}
246+
// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
247+
// type is not recognized as a binder for late-bound region.
248+
impl<'tcx, I> !TypeVisitable<I> for ClosureOutlivesSubjectTy<'tcx> {}
249+
impl<'tcx, I> !TypeFoldable<I> for ClosureOutlivesSubjectTy<'tcx> {}
250+
251+
impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
252+
/// All regions of `ty` must be of kind `ReVar` and must represent
253+
/// universal regions *external* to the closure.
254+
pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
255+
let inner = fold_regions(tcx, ty, |r, depth| match r.kind() {
256+
ty::ReVar(vid) => {
257+
let br = ty::BoundRegion {
258+
var: ty::BoundVar::from_usize(vid.index()),
259+
kind: ty::BoundRegionKind::Anon,
260+
};
261+
ty::Region::new_bound(tcx, depth, br)
262+
}
263+
_ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
264+
});
265+
266+
Self { inner }
267+
}
268+
269+
pub fn instantiate(
270+
self,
271+
tcx: TyCtxt<'tcx>,
272+
mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
273+
) -> Ty<'tcx> {
274+
fold_regions(tcx, self.inner, |r, depth| match r.kind() {
275+
ty::ReBound(debruijn, br) => {
276+
debug_assert_eq!(debruijn, depth);
277+
map(ty::RegionVid::from_usize(br.var.index()))
278+
}
279+
_ => bug!("unexpected region {r:?}"),
280+
})
281+
}
124282
}
125283

126284
/// Perform the actual borrow checking.
127285
///
128286
/// Use `consumer_options: None` for the default behavior of returning
129-
/// [`BorrowCheckResult`] only. Otherwise, return [`BodyWithBorrowckFacts`] according
130-
/// to the given [`ConsumerOptions`].
131-
#[instrument(skip(tcx), level = "debug")]
287+
/// [`PropagatedBorrowCheckResults`] only. Otherwise, return [`BodyWithBorrowckFacts`]
288+
/// according to the given [`ConsumerOptions`].
289+
///
290+
/// For nested bodies this should only be called through `root_cx.get_or_insert_nested`.
291+
#[instrument(skip(root_cx), level = "debug")]
132292
fn do_mir_borrowck<'tcx>(
133-
tcx: TyCtxt<'tcx>,
293+
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
134294
def: LocalDefId,
135295
consumer_options: Option<ConsumerOptions>,
136-
) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
296+
) -> (PropagatedBorrowCheckResults<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
297+
let tcx = root_cx.tcx;
137298
let infcx = BorrowckInferCtxt::new(tcx, def);
138299
let (input_body, promoted) = tcx.mir_promoted(def);
139300
let input_body: &Body<'_> = &input_body.borrow();
140301
let input_promoted: &IndexSlice<_, _> = &promoted.borrow();
141302
if let Some(e) = input_body.tainted_by_errors {
142303
infcx.set_tainted_by_errors(e);
304+
root_cx.set_tainted_by_errors(e);
143305
}
144306

145307
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
@@ -185,13 +347,13 @@ fn do_mir_borrowck<'tcx>(
185347
// Compute non-lexical lifetimes.
186348
let nll::NllOutput {
187349
regioncx,
188-
concrete_opaque_types,
189350
polonius_input,
190351
polonius_output,
191352
opt_closure_req,
192353
nll_errors,
193354
polonius_diagnostics,
194355
} = nll::compute_regions(
356+
root_cx,
195357
&infcx,
196358
free_regions,
197359
body,
@@ -210,26 +372,19 @@ fn do_mir_borrowck<'tcx>(
210372
// We also have a `#[rustc_regions]` annotation that causes us to dump
211373
// information.
212374
let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
213-
nll::dump_annotation(
214-
&infcx,
215-
body,
216-
&regioncx,
217-
&opt_closure_req,
218-
&concrete_opaque_types,
219-
diags_buffer,
220-
);
375+
nll::dump_annotation(&infcx, body, &regioncx, &opt_closure_req, diags_buffer);
221376

222377
let movable_coroutine =
223-
// The first argument is the coroutine type passed by value
224-
if let Some(local) = body.local_decls.raw.get(1)
225-
// Get the interior types and args which typeck computed
226-
&& let ty::Coroutine(def_id, _) = *local.ty.kind()
227-
&& tcx.coroutine_movability(def_id) == hir::Movability::Movable
228-
{
229-
true
230-
} else {
231-
false
232-
};
378+
// The first argument is the coroutine type passed by value
379+
if let Some(local) = body.local_decls.raw.get(1)
380+
// Get the interior types and args which typeck computed
381+
&& let ty::Coroutine(def_id, _) = *local.ty.kind()
382+
&& tcx.coroutine_movability(def_id) == hir::Movability::Movable
383+
{
384+
true
385+
} else {
386+
false
387+
};
233388

234389
// While promoteds should mostly be correct by construction, we need to check them for
235390
// invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
@@ -240,6 +395,7 @@ fn do_mir_borrowck<'tcx>(
240395
// this check out of `MirBorrowckCtxt`, actually doing so is far from trivial.
241396
let move_data = MoveData::gather_moves(promoted_body, tcx, |_| true);
242397
let mut promoted_mbcx = MirBorrowckCtxt {
398+
root_cx,
243399
infcx: &infcx,
244400
body: promoted_body,
245401
move_data: &move_data,
@@ -280,6 +436,7 @@ fn do_mir_borrowck<'tcx>(
280436
}
281437

282438
let mut mbcx = MirBorrowckCtxt {
439+
root_cx,
283440
infcx: &infcx,
284441
body,
285442
move_data: &move_data,
@@ -347,13 +504,13 @@ fn do_mir_borrowck<'tcx>(
347504

348505
debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
349506
mbcx.lint_unused_mut();
350-
let tainted_by_errors = mbcx.emit_errors();
507+
if let Some(guar) = mbcx.emit_errors() {
508+
mbcx.root_cx.set_tainted_by_errors(guar);
509+
}
351510

352-
let result = BorrowCheckResult {
353-
concrete_opaque_types: concrete_opaque_types.into_inner(),
511+
let result = PropagatedBorrowCheckResults {
354512
closure_requirements: opt_closure_req,
355513
used_mut_upvars: mbcx.used_mut_upvars,
356-
tainted_by_errors,
357514
};
358515

359516
let body_with_facts = if consumer_options.is_some() {
@@ -488,6 +645,7 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
488645
}
489646

490647
struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
648+
root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
491649
infcx: &'infcx BorrowckInferCtxt<'tcx>,
492650
body: &'a Body<'tcx>,
493651
move_data: &'a MoveData<'tcx>,
@@ -1361,11 +1519,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
13611519
| AggregateKind::CoroutineClosure(def_id, _)
13621520
| AggregateKind::Coroutine(def_id, _) => {
13631521
let def_id = def_id.expect_local();
1364-
let BorrowCheckResult { used_mut_upvars, .. } =
1365-
self.infcx.tcx.mir_borrowck(def_id);
1522+
let used_mut_upvars = self.root_cx.used_mut_upvars(def_id);
13661523
debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
1367-
for field in used_mut_upvars {
1368-
self.propagate_closure_used_mut_upvar(&operands[*field]);
1524+
// FIXME: We're cloning the `SmallVec` here to avoid borrowing `root_cx`
1525+
// when calling `propagate_closure_used_mut_upvar`. This should ideally
1526+
// be unnecessary.
1527+
for field in used_mut_upvars.clone() {
1528+
self.propagate_closure_used_mut_upvar(&operands[field]);
13691529
}
13701530
}
13711531
AggregateKind::Adt(..)

‎compiler/rustc_borrowck/src/nll.rs

Lines changed: 10 additions & 17 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;
@@ -25,21 +22,22 @@ use tracing::{debug, instrument};
2522
use crate::borrow_set::BorrowSet;
2623
use crate::consumers::ConsumerOptions;
2724
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
28-
use crate::opaque_types::ConcreteOpaqueTypes;
2925
use crate::polonius::PoloniusDiagnosticsContext;
3026
use crate::polonius::legacy::{
3127
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
3228
};
3329
use crate::region_infer::RegionInferenceContext;
3430
use crate::type_check::{self, MirTypeckResults};
3531
use crate::universal_regions::UniversalRegions;
36-
use crate::{BorrowckInferCtxt, polonius, renumber};
32+
use crate::{
33+
BorrowCheckRootCtxt, BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements,
34+
polonius, renumber,
35+
};
3736

3837
/// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any
3938
/// closure requirements to propagate, and any generated errors.
4039
pub(crate) struct NllOutput<'tcx> {
4140
pub regioncx: RegionInferenceContext<'tcx>,
42-
pub concrete_opaque_types: ConcreteOpaqueTypes<'tcx>,
4341
pub polonius_input: Option<Box<PoloniusFacts>>,
4442
pub polonius_output: Option<Box<PoloniusOutput>>,
4543
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
@@ -78,6 +76,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
7876
///
7977
/// This may result in errors being reported.
8078
pub(crate) fn compute_regions<'a, 'tcx>(
79+
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
8180
infcx: &BorrowckInferCtxt<'tcx>,
8281
universal_regions: UniversalRegions<'tcx>,
8382
body: &Body<'tcx>,
@@ -98,15 +97,14 @@ pub(crate) fn compute_regions<'a, 'tcx>(
9897

9998
let location_map = Rc::new(DenseLocationMap::new(body));
10099

101-
let mut concrete_opaque_types = ConcreteOpaqueTypes::default();
102-
103100
// Run the MIR type-checker.
104101
let MirTypeckResults {
105102
constraints,
106103
universal_region_relations,
107104
opaque_type_values,
108105
polonius_context,
109106
} = type_check::type_check(
107+
root_cx,
110108
infcx,
111109
body,
112110
promoted,
@@ -117,7 +115,6 @@ pub(crate) fn compute_regions<'a, 'tcx>(
117115
flow_inits,
118116
move_data,
119117
Rc::clone(&location_map),
120-
&mut concrete_opaque_types,
121118
);
122119

123120
// Create the region inference context, taking ownership of the
@@ -181,11 +178,10 @@ pub(crate) fn compute_regions<'a, 'tcx>(
181178
infcx.set_tainted_by_errors(guar);
182179
}
183180

184-
regioncx.infer_opaque_types(infcx, opaque_type_values, &mut concrete_opaque_types);
181+
regioncx.infer_opaque_types(root_cx, infcx, opaque_type_values);
185182

186183
NllOutput {
187184
regioncx,
188-
concrete_opaque_types,
189185
polonius_input: polonius_facts.map(Box::new),
190186
polonius_output,
191187
opt_closure_req: closure_region_requirements,
@@ -301,7 +297,6 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
301297
body: &Body<'tcx>,
302298
regioncx: &RegionInferenceContext<'tcx>,
303299
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
304-
concrete_opaque_types: &ConcreteOpaqueTypes<'tcx>,
305300
diagnostics_buffer: &mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
306301
) {
307302
let tcx = infcx.tcx;
@@ -318,7 +313,7 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
318313
// better.
319314

320315
let def_span = tcx.def_span(body.source.def_id());
321-
let mut err = if let Some(closure_region_requirements) = closure_region_requirements {
316+
let err = if let Some(closure_region_requirements) = closure_region_requirements {
322317
let mut err = infcx.dcx().struct_span_note(def_span, "external requirements");
323318

324319
regioncx.annotate(tcx, &mut err);
@@ -344,9 +339,7 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
344339
err
345340
};
346341

347-
if !concrete_opaque_types.is_empty() {
348-
err.note(format!("Inferred opaque type values:\n{concrete_opaque_types:#?}"));
349-
}
342+
// FIXME(@lcnr): We currently don't dump the inferred hidden types here.
350343

351344
diagnostics_buffer.buffer_non_error(err);
352345
}

‎compiler/rustc_borrowck/src/opaque_types.rs

Lines changed: 0 additions & 55 deletions
This file was deleted.

‎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::{Level, debug, enabled, 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/region_infer/opaque_types.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid;
1010
use tracing::{debug, instrument};
1111

1212
use super::RegionInferenceContext;
13-
use crate::opaque_types::ConcreteOpaqueTypes;
13+
use crate::BorrowCheckRootCtxt;
1414
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
1515
use crate::universal_regions::RegionClassification;
1616

@@ -58,12 +58,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
5858
///
5959
/// [rustc-dev-guide chapter]:
6060
/// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html
61-
#[instrument(level = "debug", skip(self, infcx), ret)]
61+
#[instrument(level = "debug", skip(self, root_cx, infcx), ret)]
6262
pub(crate) fn infer_opaque_types(
6363
&self,
64+
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
6465
infcx: &InferCtxt<'tcx>,
6566
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
66-
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
6767
) {
6868
let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
6969
FxIndexMap::default();
@@ -140,11 +140,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
140140
}
141141
}
142142

143-
concrete_opaque_types.insert(
144-
infcx.tcx,
143+
root_cx.add_concrete_opaque_type(
145144
opaque_type_key.def_id,
146-
OpaqueHiddenType { ty, span: concrete_type.span },
145+
OpaqueHiddenType { span: concrete_type.span, ty },
147146
);
147+
148148
// Check that all opaque types have the same region parameters if they have the same
149149
// non-region parameters. This is necessary because within the new solver we perform
150150
// various query operations modulo regions, and thus could unsoundly select some impls
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use rustc_abi::FieldIdx;
2+
use rustc_data_structures::fx::FxHashMap;
3+
use rustc_hir::def_id::LocalDefId;
4+
use rustc_middle::bug;
5+
use rustc_middle::ty::{OpaqueHiddenType, Ty, TyCtxt, TypeVisitableExt};
6+
use rustc_span::ErrorGuaranteed;
7+
use smallvec::SmallVec;
8+
9+
use crate::{ClosureRegionRequirements, ConcreteOpaqueTypes, PropagatedBorrowCheckResults};
10+
11+
/// The shared context used by both the root as well as all its nested
12+
/// items.
13+
pub(super) struct BorrowCheckRootCtxt<'tcx> {
14+
pub tcx: TyCtxt<'tcx>,
15+
root_def_id: LocalDefId,
16+
concrete_opaque_types: ConcreteOpaqueTypes<'tcx>,
17+
nested_bodies: FxHashMap<LocalDefId, PropagatedBorrowCheckResults<'tcx>>,
18+
tainted_by_errors: Option<ErrorGuaranteed>,
19+
}
20+
21+
impl<'tcx> BorrowCheckRootCtxt<'tcx> {
22+
pub(super) fn new(tcx: TyCtxt<'tcx>, root_def_id: LocalDefId) -> BorrowCheckRootCtxt<'tcx> {
23+
BorrowCheckRootCtxt {
24+
tcx,
25+
root_def_id,
26+
concrete_opaque_types: Default::default(),
27+
nested_bodies: Default::default(),
28+
tainted_by_errors: None,
29+
}
30+
}
31+
32+
/// Collect all defining uses of opaque types inside of this typeck root. This
33+
/// expects the hidden type to be mapped to the definition parameters of the opaque
34+
/// and errors if we end up with distinct hidden types.
35+
pub(super) fn add_concrete_opaque_type(
36+
&mut self,
37+
def_id: LocalDefId,
38+
hidden_ty: OpaqueHiddenType<'tcx>,
39+
) {
40+
// Sometimes two opaque types are the same only after we remap the generic parameters
41+
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to
42+
// `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we
43+
// only know that once we convert the generic parameters to those of the opaque type.
44+
if let Some(prev) = self.concrete_opaque_types.0.get_mut(&def_id) {
45+
if prev.ty != hidden_ty.ty {
46+
let guar = hidden_ty.ty.error_reported().err().unwrap_or_else(|| {
47+
let (Ok(e) | Err(e)) =
48+
prev.build_mismatch_error(&hidden_ty, self.tcx).map(|d| d.emit());
49+
e
50+
});
51+
prev.ty = Ty::new_error(self.tcx, guar);
52+
}
53+
// Pick a better span if there is one.
54+
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
55+
prev.span = prev.span.substitute_dummy(hidden_ty.span);
56+
} else {
57+
self.concrete_opaque_types.0.insert(def_id, hidden_ty);
58+
}
59+
}
60+
61+
pub(super) fn set_tainted_by_errors(&mut self, guar: ErrorGuaranteed) {
62+
self.tainted_by_errors = Some(guar);
63+
}
64+
65+
fn get_or_insert_nested(&mut self, def_id: LocalDefId) -> &PropagatedBorrowCheckResults<'tcx> {
66+
debug_assert_eq!(
67+
self.tcx.typeck_root_def_id(def_id.to_def_id()),
68+
self.root_def_id.to_def_id()
69+
);
70+
if !self.nested_bodies.contains_key(&def_id) {
71+
let result = super::do_mir_borrowck(self, def_id, None).0;
72+
if let Some(prev) = self.nested_bodies.insert(def_id, result) {
73+
bug!("unexpected previous nested body: {prev:?}");
74+
}
75+
}
76+
77+
self.nested_bodies.get(&def_id).unwrap()
78+
}
79+
80+
pub(super) fn closure_requirements(
81+
&mut self,
82+
nested_body_def_id: LocalDefId,
83+
) -> &Option<ClosureRegionRequirements<'tcx>> {
84+
&self.get_or_insert_nested(nested_body_def_id).closure_requirements
85+
}
86+
87+
pub(super) fn used_mut_upvars(
88+
&mut self,
89+
nested_body_def_id: LocalDefId,
90+
) -> &SmallVec<[FieldIdx; 8]> {
91+
&self.get_or_insert_nested(nested_body_def_id).used_mut_upvars
92+
}
93+
94+
pub(super) fn finalize(self) -> Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> {
95+
if let Some(guar) = self.tainted_by_errors {
96+
Err(guar)
97+
} else {
98+
Ok(self.tcx.arena.alloc(self.concrete_opaque_types))
99+
}
100+
}
101+
}

‎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_borrowck/src/type_check/mod.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,14 @@ use crate::borrow_set::BorrowSet;
4545
use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet};
4646
use crate::diagnostics::UniverseInfo;
4747
use crate::member_constraints::MemberConstraintSet;
48-
use crate::opaque_types::ConcreteOpaqueTypes;
4948
use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable};
5049
use crate::polonius::{PoloniusContext, PoloniusLivenessContext};
5150
use crate::region_infer::TypeTest;
5251
use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices};
5352
use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
5453
use crate::type_check::free_region_relations::{CreateResult, UniversalRegionRelations};
5554
use crate::universal_regions::{DefiningTy, UniversalRegions};
56-
use crate::{BorrowckInferCtxt, path_utils};
55+
use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt, path_utils};
5756

5857
macro_rules! span_mirbug {
5958
($context:expr, $elem:expr, $($message:tt)*) => ({
@@ -102,6 +101,7 @@ mod relate_tys;
102101
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
103102
/// - `location_map` -- map between MIR `Location` and `PointIndex`
104103
pub(crate) fn type_check<'a, 'tcx>(
104+
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
105105
infcx: &BorrowckInferCtxt<'tcx>,
106106
body: &Body<'tcx>,
107107
promoted: &IndexSlice<Promoted, Body<'tcx>>,
@@ -112,7 +112,6 @@ pub(crate) fn type_check<'a, 'tcx>(
112112
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
113113
move_data: &MoveData<'tcx>,
114114
location_map: Rc<DenseLocationMap>,
115-
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
116115
) -> MirTypeckResults<'tcx> {
117116
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
118117
let mut constraints = MirTypeckRegionConstraints {
@@ -153,6 +152,7 @@ pub(crate) fn type_check<'a, 'tcx>(
153152
};
154153

155154
let mut typeck = TypeChecker {
155+
root_cx,
156156
infcx,
157157
last_span: body.span,
158158
body,
@@ -167,7 +167,6 @@ pub(crate) fn type_check<'a, 'tcx>(
167167
polonius_facts,
168168
borrow_set,
169169
constraints: &mut constraints,
170-
concrete_opaque_types,
171170
polonius_liveness,
172171
};
173172

@@ -215,6 +214,7 @@ enum FieldAccessError {
215214
/// way, it accrues region constraints -- these can later be used by
216215
/// NLL region checking.
217216
struct TypeChecker<'a, 'tcx> {
217+
root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
218218
infcx: &'a BorrowckInferCtxt<'tcx>,
219219
last_span: Span,
220220
body: &'a Body<'tcx>,
@@ -233,7 +233,6 @@ struct TypeChecker<'a, 'tcx> {
233233
polonius_facts: &'a mut Option<PoloniusFacts>,
234234
borrow_set: &'a BorrowSet<'tcx>,
235235
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
236-
concrete_opaque_types: &'a mut ConcreteOpaqueTypes<'tcx>,
237236
/// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints.
238237
polonius_liveness: Option<PoloniusLivenessContext>,
239238
}
@@ -2503,11 +2502,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
25032502
args: GenericArgsRef<'tcx>,
25042503
locations: Locations,
25052504
) -> ty::InstantiatedPredicates<'tcx> {
2506-
let closure_borrowck_results = tcx.mir_borrowck(def_id);
2507-
self.concrete_opaque_types
2508-
.extend_from_nested_body(tcx, &closure_borrowck_results.concrete_opaque_types);
2509-
2510-
if let Some(closure_requirements) = &closure_borrowck_results.closure_requirements {
2505+
if let Some(closure_requirements) = &self.root_cx.closure_requirements(def_id) {
25112506
constraint_conversion::ConstraintConversion::new(
25122507
self.infcx,
25132508
self.universal_regions,

‎compiler/rustc_hir_analysis/src/check/check.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,11 @@ fn best_definition_site_of_opaque<'tcx>(
397397
return ControlFlow::Continue(());
398398
}
399399

400-
if let Some(hidden_ty) =
401-
self.tcx.mir_borrowck(item_def_id).concrete_opaque_types.get(&self.opaque_def_id)
400+
if let Some(hidden_ty) = self
401+
.tcx
402+
.mir_borrowck(item_def_id)
403+
.ok()
404+
.and_then(|opaque_types| opaque_types.0.get(&self.opaque_def_id))
402405
{
403406
ControlFlow::Break((hidden_ty.span, item_def_id))
404407
} else {
@@ -413,9 +416,6 @@ fn best_definition_site_of_opaque<'tcx>(
413416
self.tcx
414417
}
415418
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result {
416-
if let hir::ExprKind::Closure(closure) = ex.kind {
417-
self.check(closure.def_id)?;
418-
}
419419
intravisit::walk_expr(self, ex)
420420
}
421421
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) -> Self::Result {

‎compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -183,25 +183,23 @@ impl<'tcx> TaitConstraintLocator<'tcx> {
183183
self.non_defining_use_in_defining_scope(item_def_id);
184184
}
185185
}
186-
DefiningScopeKind::MirBorrowck => {
187-
let borrowck_result = tcx.mir_borrowck(item_def_id);
188-
if let Some(guar) = borrowck_result.tainted_by_errors {
189-
self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar));
190-
} else if let Some(&hidden_type) =
191-
borrowck_result.concrete_opaque_types.get(&self.def_id)
192-
{
193-
debug!(?hidden_type, "found constraint");
194-
self.insert_found(hidden_type);
195-
} else if let Err(guar) = tcx
196-
.type_of_opaque_hir_typeck(self.def_id)
197-
.instantiate_identity()
198-
.error_reported()
199-
{
200-
self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar));
201-
} else {
202-
self.non_defining_use_in_defining_scope(item_def_id);
186+
DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(item_def_id) {
187+
Err(guar) => self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar)),
188+
Ok(concrete_opaque_types) => {
189+
if let Some(&hidden_type) = concrete_opaque_types.0.get(&self.def_id) {
190+
debug!(?hidden_type, "found constraint");
191+
self.insert_found(hidden_type);
192+
} else if let Err(guar) = tcx
193+
.type_of_opaque_hir_typeck(self.def_id)
194+
.instantiate_identity()
195+
.error_reported()
196+
{
197+
self.insert_found(ty::OpaqueHiddenType::new_error(tcx, guar));
198+
} else {
199+
self.non_defining_use_in_defining_scope(item_def_id);
200+
}
203201
}
204-
}
202+
},
205203
}
206204
}
207205
}
@@ -264,20 +262,20 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>(
264262
Ty::new_diverging_default(tcx)
265263
}
266264
}
267-
DefiningScopeKind::MirBorrowck => {
268-
let borrowck_result = tcx.mir_borrowck(owner_def_id);
269-
if let Some(guar) = borrowck_result.tainted_by_errors {
270-
Ty::new_error(tcx, guar)
271-
} else if let Some(hidden_ty) = borrowck_result.concrete_opaque_types.get(&def_id) {
272-
hidden_ty.ty
273-
} else {
274-
let hir_ty = tcx.type_of_opaque_hir_typeck(def_id).instantiate_identity();
275-
if let Err(guar) = hir_ty.error_reported() {
276-
Ty::new_error(tcx, guar)
265+
DefiningScopeKind::MirBorrowck => match tcx.mir_borrowck(owner_def_id) {
266+
Ok(concrete_opaque_types) => {
267+
if let Some(hidden_ty) = concrete_opaque_types.0.get(&def_id) {
268+
hidden_ty.ty
277269
} else {
278-
hir_ty
270+
let hir_ty = tcx.type_of_opaque_hir_typeck(def_id).instantiate_identity();
271+
if let Err(guar) = hir_ty.error_reported() {
272+
Ty::new_error(tcx, guar)
273+
} else {
274+
hir_ty
275+
}
279276
}
280277
}
281-
}
278+
Err(guar) => Ty::new_error(tcx, guar),
279+
},
282280
}
283281
}

‎compiler/rustc_interface/src/passes.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
955955
// Run unsafety check because it's responsible for stealing and
956956
// deallocating THIR.
957957
tcx.ensure_ok().check_unsafety(def_id);
958-
tcx.ensure_ok().mir_borrowck(def_id)
958+
if !tcx.is_typeck_child(def_id.to_def_id()) {
959+
tcx.ensure_ok().mir_borrowck(def_id)
960+
}
959961
});
960962
});
961963
sess.time("MIR_effect_checking", || {

‎compiler/rustc_middle/src/arena.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ macro_rules! arena_types {
2828
rustc_middle::mir::Body<'tcx>
2929
>,
3030
[decode] typeck_results: rustc_middle::ty::TypeckResults<'tcx>,
31-
[decode] borrowck_result: rustc_middle::mir::BorrowCheckResult<'tcx>,
31+
[decode] borrowck_result: rustc_middle::mir::ConcreteOpaqueTypes<'tcx>,
3232
[] resolver: rustc_data_structures::steal::Steal<(
3333
rustc_middle::ty::ResolverAstLowering,
3434
std::sync::Arc<rustc_ast::Crate>,

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

Lines changed: 7 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +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};
13-
use smallvec::SmallVec;
1413

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

1817
rustc_index::newtype_index! {
1918
#[derive(HashStable)]
@@ -85,16 +84,11 @@ impl Debug for CoroutineLayout<'_> {
8584
}
8685
}
8786

88-
#[derive(Debug, TyEncodable, TyDecodable, HashStable)]
89-
pub struct BorrowCheckResult<'tcx> {
90-
/// All the opaque types that are restricted to concrete types
91-
/// by this function. Unlike the value in `TypeckResults`, this has
92-
/// unerased regions.
93-
pub concrete_opaque_types: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
94-
pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
95-
pub used_mut_upvars: SmallVec<[FieldIdx; 8]>,
96-
pub tainted_by_errors: Option<ErrorGuaranteed>,
97-
}
87+
/// All the opaque types that are restricted to concrete types
88+
/// by this function. Unlike the value in `TypeckResults`, this has
89+
/// unerased regions.
90+
#[derive(Default, Debug, TyEncodable, TyDecodable, HashStable)]
91+
pub struct ConcreteOpaqueTypes<'tcx>(pub FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>);
9892

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

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

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,11 +1153,10 @@ rustc_queries! {
11531153
return_result_from_ensure_ok
11541154
}
11551155

1156-
/// Borrow-checks the function body. If this is a closure, returns
1157-
/// additional requirements that the closure's creator must verify.
1158-
query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
1156+
/// Borrow-checks the given typeck root, e.g. functions, const/static items,
1157+
/// and its children, e.g. closures, inline consts.
1158+
query mir_borrowck(key: LocalDefId) -> Result<&'tcx mir::ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> {
11591159
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) }
1160-
cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
11611160
}
11621161

11631162
/// Gets a complete map from all types to their inherent impls.

‎compiler/rustc_middle/src/ty/codec.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ impl_decodable_via_ref! {
501501
&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
502502
&'tcx traits::ImplSource<'tcx, ()>,
503503
&'tcx mir::Body<'tcx>,
504-
&'tcx mir::BorrowCheckResult<'tcx>,
504+
&'tcx mir::ConcreteOpaqueTypes<'tcx>,
505505
&'tcx ty::List<ty::BoundVariableKind>,
506506
&'tcx ty::ListWithCachedTypeInfo<ty::Clause<'tcx>>,
507507
&'tcx ty::List<FieldIdx>,

‎compiler/rustc_mir_transform/src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -498,8 +498,11 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
498498
}
499499

500500
// We only need to borrowck non-synthetic MIR.
501-
let tainted_by_errors =
502-
if !tcx.is_synthetic_mir(def) { tcx.mir_borrowck(def).tainted_by_errors } else { None };
501+
let tainted_by_errors = if !tcx.is_synthetic_mir(def) {
502+
tcx.mir_borrowck(tcx.typeck_root_def_id(def.to_def_id()).expect_local()).err()
503+
} else {
504+
None
505+
};
503506

504507
let is_fn_like = tcx.def_kind(def).is_fn_like();
505508
if is_fn_like {
@@ -795,7 +798,7 @@ fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec<Promoted, Body<'_
795798
}
796799

797800
if !tcx.is_synthetic_mir(def) {
798-
tcx.ensure_done().mir_borrowck(def);
801+
tcx.ensure_done().mir_borrowck(tcx.typeck_root_def_id(def.to_def_id()).expect_local());
799802
}
800803
let mut promoted = tcx.mir_promoted(def).1.steal();
801804

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//@ edition:2021
2+
3+
struct AnyOption<T>(T);
4+
impl<T> AnyOption<T> {
5+
const NONE: Option<T> = None;
6+
}
7+
8+
// This is an unfortunate side-effect of borrowchecking nested items
9+
// together with their parent. Evaluating the `AnyOption::<_>::NONE`
10+
// pattern for exhaustiveness checking relies on the layout of the
11+
// async block. This layout relies on `optimized_mir` of the nested
12+
// item which is now borrowck'd together with its parent. As
13+
// borrowck of the parent requires us to have already lowered the match,
14+
// this is a query cycle.
15+
16+
fn uwu() {}
17+
fn defines() {
18+
match Some(async {}) {
19+
AnyOption::<_>::NONE => {}
20+
//~^ ERROR cycle detected when building THIR for `defines`
21+
_ => {}
22+
}
23+
}
24+
fn main() {}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
error[E0391]: cycle detected when building THIR for `defines`
2+
--> $DIR/non-structural-match-types-cycle-err.rs:19:9
3+
|
4+
LL | AnyOption::<_>::NONE => {}
5+
| ^^^^^^^^^^^^^^^^^^^^
6+
|
7+
note: ...which requires evaluating type-level constant...
8+
--> $DIR/non-structural-match-types-cycle-err.rs:5:5
9+
|
10+
LL | const NONE: Option<T> = None;
11+
| ^^^^^^^^^^^^^^^^^^^^^
12+
note: ...which requires const-evaluating + checking `<impl at $DIR/non-structural-match-types-cycle-err.rs:4:1: 4:21>::NONE`...
13+
--> $DIR/non-structural-match-types-cycle-err.rs:5:5
14+
|
15+
LL | const NONE: Option<T> = None;
16+
| ^^^^^^^^^^^^^^^^^^^^^
17+
= note: ...which requires computing layout of `core::option::Option<{async block@$DIR/non-structural-match-types-cycle-err.rs:18:16: 18:21}>`...
18+
= note: ...which requires computing layout of `{async block@$DIR/non-structural-match-types-cycle-err.rs:18:16: 18:21}`...
19+
note: ...which requires optimizing MIR for `defines::{closure#0}`...
20+
--> $DIR/non-structural-match-types-cycle-err.rs:18:16
21+
|
22+
LL | match Some(async {}) {
23+
| ^^^^^
24+
note: ...which requires elaborating drops for `defines::{closure#0}`...
25+
--> $DIR/non-structural-match-types-cycle-err.rs:18:16
26+
|
27+
LL | match Some(async {}) {
28+
| ^^^^^
29+
note: ...which requires borrow-checking `defines`...
30+
--> $DIR/non-structural-match-types-cycle-err.rs:17:1
31+
|
32+
LL | fn defines() {
33+
| ^^^^^^^^^^^^
34+
note: ...which requires promoting constants in MIR for `defines`...
35+
--> $DIR/non-structural-match-types-cycle-err.rs:17:1
36+
|
37+
LL | fn defines() {
38+
| ^^^^^^^^^^^^
39+
note: ...which requires checking if `defines` contains FFI-unwind calls...
40+
--> $DIR/non-structural-match-types-cycle-err.rs:17:1
41+
|
42+
LL | fn defines() {
43+
| ^^^^^^^^^^^^
44+
note: ...which requires building MIR for `defines`...
45+
--> $DIR/non-structural-match-types-cycle-err.rs:17:1
46+
|
47+
LL | fn defines() {
48+
| ^^^^^^^^^^^^
49+
note: ...which requires match-checking `defines`...
50+
--> $DIR/non-structural-match-types-cycle-err.rs:17:1
51+
|
52+
LL | fn defines() {
53+
| ^^^^^^^^^^^^
54+
= note: ...which again requires building THIR for `defines`, completing the cycle
55+
note: cycle used when unsafety-checking `defines`
56+
--> $DIR/non-structural-match-types-cycle-err.rs:17:1
57+
|
58+
LL | fn defines() {
59+
| ^^^^^^^^^^^^
60+
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
61+
62+
error: aborting due to 1 previous error
63+
64+
For more information about this error, try `rustc --explain E0391`.

‎tests/ui/pattern/non-structural-match-types.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
//@ edition:2021
2-
#![feature(const_async_blocks)]
3-
42
struct AnyOption<T>(T);
53
impl<T> AnyOption<T> {
64
const NONE: Option<T> = None;
@@ -19,11 +17,5 @@ fn defines() {
1917
//~^ ERROR constant of non-structural type
2018
_ => {}
2119
}
22-
23-
match Some(async {}) {
24-
AnyOption::<_>::NONE => {}
25-
//~^ ERROR constant of non-structural type
26-
_ => {}
27-
}
2820
}
2921
fn main() {}
Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: constant of non-structural type `Option<fn() {uwu}>` in a pattern
2-
--> $DIR/non-structural-match-types.rs:12:9
2+
--> $DIR/non-structural-match-types.rs:10:9
33
|
44
LL | impl<T> AnyOption<T> {
55
| --------------------
@@ -11,8 +11,8 @@ LL | AnyOption::<_>::NONE => {}
1111
|
1212
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
1313

14-
error: constant of non-structural type `Option<{closure@$DIR/non-structural-match-types.rs:17:16: 17:18}>` in a pattern
15-
--> $DIR/non-structural-match-types.rs:18:9
14+
error: constant of non-structural type `Option<{closure@$DIR/non-structural-match-types.rs:15:16: 15:18}>` in a pattern
15+
--> $DIR/non-structural-match-types.rs:16:9
1616
|
1717
LL | impl<T> AnyOption<T> {
1818
| --------------------
@@ -24,19 +24,5 @@ LL | AnyOption::<_>::NONE => {}
2424
|
2525
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
2626

27-
error: constant of non-structural type `Option<{async block@$DIR/non-structural-match-types.rs:23:16: 23:21}>` in a pattern
28-
--> $DIR/non-structural-match-types.rs:24:9
29-
|
30-
LL | impl<T> AnyOption<T> {
31-
| --------------------
32-
LL | const NONE: Option<T> = None;
33-
| --------------------- constant defined here
34-
...
35-
LL | AnyOption::<_>::NONE => {}
36-
| ^^^^^^^^^^^^^^^^^^^^ constant of non-structural type
37-
|
38-
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
39-
= note: `ResumeTy` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
40-
41-
error: aborting due to 3 previous errors
27+
error: aborting due to 2 previous errors
4228

0 commit comments

Comments
 (0)
Please sign in to comment.