1use std::cell::Cell;
2use std::mem;
3use std::rc::Rc;
45use rustc_abi::FieldIdx;
6use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
7use rustc_errors::DiagCtxtHandle;
8use rustc_hir::def_id::LocalDefId;
9use rustc_middle::mir::ConstraintCategory;
10use rustc_middle::ty::{self, TyCtxt};
11use rustc_span::ErrorGuaranteed;
12use smallvec::SmallVec;
1314use crate::consumers::BorrowckConsumer;
15use crate::diagnostics::BorrowckDiagnosticsBuffer;
16use crate::nll::compute_closure_requirements_modulo_opaques;
17use crate::region_infer::opaque_types::{
18UnexpectedHiddenRegion, apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
19compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types,
20handle_unconstrained_hidden_type_errors,
21};
22use crate::type_check::{Locations, constraint_conversion};
23use crate::{
24ClosureRegionRequirements, CollectRegionConstraintsResult, PropagatedBorrowCheckResults,
25borrowck_check_region_constraints, borrowck_collect_region_constraints,
26};
2728/// The shared context used by both the root as well as all its nested
29/// items.
30pub(super) struct BorrowCheckRootCtxt<'diag, 'tcx: 'diag> {
31pub tcx: TyCtxt<'tcx>,
32 root_def_id: LocalDefId,
33/// This contains fully resolved hidden types or `ty::Error`.
34hidden_types: FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
35/// This contains unconstrained regions in hidden types.
36 /// Only used for deferred error reporting. See
37 /// [`crate::region_infer::opaque_types::handle_unconstrained_hidden_type_errors`]
38unconstrained_hidden_type_errors: Vec<UnexpectedHiddenRegion<'tcx>>,
39/// The region constraints computed by [borrowck_collect_region_constraints]. This uses
40 /// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before
41 /// their parents.
42collect_region_constraints_results:
43FxIndexMap<LocalDefId, CollectRegionConstraintsResult<'tcx>>,
44 propagated_borrowck_results: FxHashMap<LocalDefId, PropagatedBorrowCheckResults<'tcx>>,
45 tainted_by_errors: &'diag Cell<Option<ErrorGuaranteed>>,
46/// This should be `None` during normal compilation. See [`crate::consumers`] for more
47 /// information on how this is used.
48pub consumer: Option<BorrowckConsumer<'tcx>>,
49}
5051impl<'diag, 'tcx> BorrowCheckRootCtxt<'diag, 'tcx> {
52pub(super) fn new(
53 tcx: TyCtxt<'tcx>,
54 root_def_id: LocalDefId,
55 consumer: Option<BorrowckConsumer<'tcx>>,
56 tainted_by_errors: &'diag Cell<Option<ErrorGuaranteed>>,
57 ) -> BorrowCheckRootCtxt<'diag, 'tcx> {
58BorrowCheckRootCtxt {
59tcx,
60root_def_id,
61 hidden_types: Default::default(),
62 unconstrained_hidden_type_errors: Default::default(),
63 collect_region_constraints_results: Default::default(),
64 propagated_borrowck_results: Default::default(),
65tainted_by_errors,
66consumer,
67 }
68 }
6970pub(super) fn root_def_id(&self) -> LocalDefId {
71self.root_def_id
72 }
7374pub(super) fn set_tainted_by_errors(&self, guar: ErrorGuaranteed) {
75self.tainted_by_errors.set(Some(guar));
76 }
7778pub(super) fn dcx(&self) -> DiagCtxtHandle<'diag> {
79self.tcx.dcx().taintable_handle(&self.tainted_by_errors)
80 }
8182pub(super) fn used_mut_upvars(
83&self,
84 nested_body_def_id: LocalDefId,
85 ) -> &SmallVec<[FieldIdx; 8]> {
86&self.propagated_borrowck_results[&nested_body_def_id].used_mut_upvars
87 }
8889pub(super) fn finalize(
90self,
91 ) -> Result<&'tcx FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>, ErrorGuaranteed>
92 {
93if let Some(guar) = self.tainted_by_errors.get() {
94Err(guar)
95 } else {
96Ok(self.tcx.arena.alloc(self.hidden_types))
97 }
98 }
99100fn handle_opaque_type_uses(&mut self) {
101let mut per_body_info = Vec::new();
102for (def_id, input) in &mut self.collect_region_constraints_results {
103let (num_entries, opaque_types) = clone_and_resolve_opaque_types(
104&input.infcx,
105&input.universal_region_relations,
106&mut input.constraints,
107 );
108 input.deferred_opaque_type_errors = compute_definition_site_hidden_types(
109*def_id,
110&input.infcx,
111&input.universal_region_relations,
112&input.constraints,
113 Rc::clone(&input.location_map),
114&mut self.hidden_types,
115&mut self.unconstrained_hidden_type_errors,
116&opaque_types,
117 );
118 per_body_info.push((num_entries, opaque_types));
119 }
120121handle_unconstrained_hidden_type_errors(
122self.tcx,
123&mut self.hidden_types,
124&mut self.unconstrained_hidden_type_errors,
125&mut self.collect_region_constraints_results,
126 );
127128for (input, (opaque_types_storage_num_entries, opaque_types)) in
129self.collect_region_constraints_results.values_mut().zip(per_body_info)
130 {
131if input.deferred_opaque_type_errors.is_empty() {
132 input.deferred_opaque_type_errors = apply_definition_site_hidden_types(
133&input.infcx,
134&input.body_owned,
135&input.universal_region_relations.universal_regions,
136&input.region_bound_pairs,
137&input.known_type_outlives_obligations,
138&mut input.constraints,
139&mut self.hidden_types,
140&opaque_types,
141 );
142 }
143144 detect_opaque_types_added_while_handling_opaque_types(
145&input.infcx,
146 opaque_types_storage_num_entries,
147 )
148 }
149 }
150151/// Computing defining uses of opaques may depend on the propagated region
152 /// requirements of nested bodies, while applying defining uses may introduce
153 /// additional region requirements we need to propagate.
154 ///
155 /// This results in cyclic dependency. To compute the defining uses in parent
156 /// bodies, we need the closure requirements of its nested bodies, but to check
157 /// non-defining uses in nested bodies, we may rely on the defining uses in the
158 /// parent.
159 ///
160 /// We handle this issue by applying closure requirements twice. Once using the
161 /// region constraints from before we've handled opaque types in the nested body
162 /// - which is used by the parent to handle its defining uses - and once after.
163 ///
164 /// As a performance optimization, we also eagerly finish borrowck for bodies
165 /// which don't depend on opaque types. In this case they get removed from
166 /// `collect_region_constraints_results` and the final result gets put into
167 /// `propagated_borrowck_results`.
168fn apply_closure_requirements_modulo_opaques(
169&mut self,
170 diags_buffer: &mut BorrowckDiagnosticsBuffer<'diag, 'tcx>,
171 ) {
172let mut closure_requirements_modulo_opaques = FxHashMap::default();
173// We need to `mem::take` both `self.collect_region_constraints_results` and
174 // `input.deferred_closure_requirements` as we otherwise can't iterate over
175 // them while mutably using the containing struct.
176let collect_region_constraints_results =
177 mem::take(&mut self.collect_region_constraints_results);
178// We iterate over all bodies here, visiting nested bodies before their parent.
179for (def_id, mut input) in collect_region_constraints_results {
180// A body depends on opaque types if it either has any opaque type uses itself,
181 // or it has a nested body which does.
182 //
183 // If the current body does not depend on any opaque types, we eagerly compute
184 // its final result and write it into `self.propagated_borrowck_results`. This
185 // avoids having to compute its closure requirements modulo regions, as they
186 // are just the same as its final closure requirements.
187let mut depends_on_opaques = input.infcx.has_opaque_types_in_storage();
188189// Iterate over all nested bodies of `input`. If that nested body depends on
190 // opaque types, we apply its closure requirements modulo opaques. Otherwise
191 // we use the closure requirements from its final borrowck result.
192 //
193 // In case we've only applied the closure requirements modulo opaques, we have
194 // to later apply its closure requirements considering opaques, so we put that
195 // nested body back into `deferred_closure_requirements`.
196for (def_id, args, locations) in mem::take(&mut input.deferred_closure_requirements) {
197let closure_requirements = match self.propagated_borrowck_results.get(&def_id) {
198None => {
199 depends_on_opaques = true;
200 input.deferred_closure_requirements.push((def_id, args, locations));
201&closure_requirements_modulo_opaques[&def_id]
202 }
203Some(result) => &result.closure_requirements,
204 };
205206Self::apply_closure_requirements(
207&mut input,
208 closure_requirements,
209 def_id,
210 args,
211 locations,
212 );
213 }
214215// In case the current body does depend on opaques and is a nested body,
216 // we need to compute its closure requirements modulo opaques so that
217 // we're able to use it when visiting its parent later in this function.
218 //
219 // If the current body does not depend on opaque types, we finish borrowck
220 // and write its result into `propagated_borrowck_results`.
221if depends_on_opaques {
222if def_id != self.root_def_id {
223let req = Self::compute_closure_requirements_modulo_opaques(&input);
224 closure_requirements_modulo_opaques.insert(def_id, req);
225 }
226self.collect_region_constraints_results.insert(def_id, input);
227 } else {
228if !input.deferred_closure_requirements.is_empty() {
::core::panicking::panic("assertion failed: input.deferred_closure_requirements.is_empty()")
};assert!(input.deferred_closure_requirements.is_empty());
229let result = borrowck_check_region_constraints(self, diags_buffer, input);
230self.propagated_borrowck_results.insert(def_id, result);
231 }
232 }
233 }
234235fn compute_closure_requirements_modulo_opaques(
236 input: &CollectRegionConstraintsResult<'tcx>,
237 ) -> Option<ClosureRegionRequirements<'tcx>> {
238compute_closure_requirements_modulo_opaques(
239&input.infcx,
240&input.body_owned,
241Rc::clone(&input.location_map),
242&input.universal_region_relations,
243&input.constraints,
244 )
245 }
246247fn apply_closure_requirements(
248 input: &mut CollectRegionConstraintsResult<'tcx>,
249 closure_requirements: &Option<ClosureRegionRequirements<'tcx>>,
250 closure_def_id: LocalDefId,
251 args: ty::GenericArgsRef<'tcx>,
252 locations: Locations,
253 ) {
254if let Some(closure_requirements) = closure_requirements {
255 constraint_conversion::ConstraintConversion::new(
256&input.infcx,
257&input.universal_region_relations.universal_regions,
258&input.region_bound_pairs,
259&input.known_type_outlives_obligations,
260locations,
261input.body_owned.span, // irrelevant; will be overridden.
262ConstraintCategory::Boring, // same as above.
263&mut input.constraints,
264 )
265 .apply_closure_requirements(closure_requirements, closure_def_id, args);
266 }
267 }
268269pub(super) fn do_mir_borrowck(&mut self) {
270// The list of all bodies we need to borrowck. This first looks at
271 // nested bodies, and then their parents. This means accessing e.g.
272 // `used_mut_upvars` for a closure can assume that we've already
273 // checked that closure.
274let all_bodies = self275 .tcx
276 .nested_bodies_within(self.root_def_id)
277 .iter()
278 .chain(std::iter::once(self.root_def_id));
279for def_id in all_bodies {
280let result = borrowck_collect_region_constraints(self, def_id);
281self.collect_region_constraints_results.insert(def_id, result);
282 }
283284let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
285286// We now apply the closure requirements of nested bodies modulo
287 // opaques. In case a body does not depend on opaque types, we
288 // eagerly check its region constraints and use the final closure
289 // requirements.
290 //
291 // We eagerly finish borrowck for bodies which don't depend on
292 // opaques.
293self.apply_closure_requirements_modulo_opaques(diags_buffer);
294295// We handle opaque type uses for all bodies together.
296self.handle_opaque_type_uses();
297298// Now walk over all bodies which depend on opaque types and finish borrowck.
299 //
300 // We first apply the final closure requirements from nested bodies which also
301 // depend on opaque types and then finish borrow checking the parent. Bodies
302 // which don't depend on opaques have already been fully borrowchecked in
303 // `apply_closure_requirements_modulo_opaques` as an optimization.
304for (def_id, mut input) in mem::take(&mut self.collect_region_constraints_results) {
305for (def_id, args, locations) in mem::take(&mut input.deferred_closure_requirements) {
306// We visit nested bodies before their parent, so we're already
307 // done with nested bodies at this point.
308let closure_requirements =
309&self.propagated_borrowck_results[&def_id].closure_requirements;
310Self::apply_closure_requirements(
311&mut input,
312 closure_requirements,
313 def_id,
314 args,
315 locations,
316 );
317 }
318319let result = borrowck_check_region_constraints(self, diags_buffer, input);
320self.propagated_borrowck_results.insert(def_id, result);
321 }
322diags_buffer.emit_errors();
323 }
324}