1use std::mem;
2use std::rc::Rc;
34use rustc_abi::FieldIdx;
5use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
6use rustc_hir::def_id::LocalDefId;
7use rustc_middle::mir::ConstraintCategory;
8use rustc_middle::ty::{self, TyCtxt};
9use rustc_span::ErrorGuaranteed;
10use smallvec::SmallVec;
1112use crate::consumers::BorrowckConsumer;
13use crate::nll::compute_closure_requirements_modulo_opaques;
14use crate::region_infer::opaque_types::{
15apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
16compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types,
17};
18use crate::type_check::{Locations, constraint_conversion};
19use crate::{
20ClosureRegionRequirements, CollectRegionConstraintsResult, PropagatedBorrowCheckResults,
21borrowck_check_region_constraints, borrowck_collect_region_constraints,
22};
2324/// The shared context used by both the root as well as all its nested
25/// items.
26pub(super) struct BorrowCheckRootCtxt<'tcx> {
27pub tcx: TyCtxt<'tcx>,
28 root_def_id: LocalDefId,
29 hidden_types: FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
30/// The region constraints computed by [borrowck_collect_region_constraints]. This uses
31 /// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before
32 /// their parents.
33collect_region_constraints_results:
34FxIndexMap<LocalDefId, CollectRegionConstraintsResult<'tcx>>,
35 propagated_borrowck_results: FxHashMap<LocalDefId, PropagatedBorrowCheckResults<'tcx>>,
36 tainted_by_errors: Option<ErrorGuaranteed>,
37/// This should be `None` during normal compilation. See [`crate::consumers`] for more
38 /// information on how this is used.
39pub consumer: Option<BorrowckConsumer<'tcx>>,
40}
4142impl<'tcx> BorrowCheckRootCtxt<'tcx> {
43pub(super) fn new(
44 tcx: TyCtxt<'tcx>,
45 root_def_id: LocalDefId,
46 consumer: Option<BorrowckConsumer<'tcx>>,
47 ) -> BorrowCheckRootCtxt<'tcx> {
48BorrowCheckRootCtxt {
49tcx,
50root_def_id,
51 hidden_types: Default::default(),
52 collect_region_constraints_results: Default::default(),
53 propagated_borrowck_results: Default::default(),
54 tainted_by_errors: None,
55consumer,
56 }
57 }
5859pub(super) fn root_def_id(&self) -> LocalDefId {
60self.root_def_id
61 }
6263pub(super) fn set_tainted_by_errors(&mut self, guar: ErrorGuaranteed) {
64self.tainted_by_errors = Some(guar);
65 }
6667pub(super) fn used_mut_upvars(
68&mut self,
69 nested_body_def_id: LocalDefId,
70 ) -> &SmallVec<[FieldIdx; 8]> {
71&self.propagated_borrowck_results[&nested_body_def_id].used_mut_upvars
72 }
7374pub(super) fn finalize(
75self,
76 ) -> Result<&'tcx FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>, ErrorGuaranteed>
77 {
78if let Some(guar) = self.tainted_by_errors {
79Err(guar)
80 } else {
81Ok(self.tcx.arena.alloc(self.hidden_types))
82 }
83 }
8485fn handle_opaque_type_uses(&mut self) {
86let mut per_body_info = Vec::new();
87for input in self.collect_region_constraints_results.values_mut() {
88let (num_entries, opaque_types) = clone_and_resolve_opaque_types(
89&input.infcx,
90&input.universal_region_relations,
91&mut input.constraints,
92 );
93 input.deferred_opaque_type_errors = compute_definition_site_hidden_types(
94&input.infcx,
95&input.universal_region_relations,
96&input.constraints,
97 Rc::clone(&input.location_map),
98&mut self.hidden_types,
99&opaque_types,
100 );
101 per_body_info.push((num_entries, opaque_types));
102 }
103104for (input, (opaque_types_storage_num_entries, opaque_types)) in
105self.collect_region_constraints_results.values_mut().zip(per_body_info)
106 {
107if input.deferred_opaque_type_errors.is_empty() {
108 input.deferred_opaque_type_errors = apply_definition_site_hidden_types(
109&input.infcx,
110&input.body_owned,
111&input.universal_region_relations.universal_regions,
112&input.region_bound_pairs,
113&input.known_type_outlives_obligations,
114&mut input.constraints,
115&mut self.hidden_types,
116&opaque_types,
117 );
118 }
119120 detect_opaque_types_added_while_handling_opaque_types(
121&input.infcx,
122 opaque_types_storage_num_entries,
123 )
124 }
125 }
126127/// Computing defining uses of opaques may depend on the propagated region
128 /// requirements of nested bodies, while applying defining uses may introduce
129 /// additional region requirements we need to propagate.
130 ///
131 /// This results in cyclic dependency. To compute the defining uses in parent
132 /// bodies, we need the closure requirements of its nested bodies, but to check
133 /// non-defining uses in nested bodies, we may rely on the defining uses in the
134 /// parent.
135 ///
136 /// We handle this issue by applying closure requirements twice. Once using the
137 /// region constraints from before we've handled opaque types in the nested body
138 /// - which is used by the parent to handle its defining uses - and once after.
139 ///
140 /// As a performance optimization, we also eagerly finish borrowck for bodies
141 /// which don't depend on opaque types. In this case they get removed from
142 /// `collect_region_constraints_results` and the final result gets put into
143 /// `propagated_borrowck_results`.
144fn apply_closure_requirements_modulo_opaques(&mut self) {
145let mut closure_requirements_modulo_opaques = FxHashMap::default();
146// We need to `mem::take` both `self.collect_region_constraints_results` and
147 // `input.deferred_closure_requirements` as we otherwise can't iterate over
148 // them while mutably using the containing struct.
149let collect_region_constraints_results =
150 mem::take(&mut self.collect_region_constraints_results);
151// We iterate over all bodies here, visiting nested bodies before their parent.
152for (def_id, mut input) in collect_region_constraints_results {
153// A body depends on opaque types if it either has any opaque type uses itself,
154 // or it has a nested body which does.
155 //
156 // If the current body does not depend on any opaque types, we eagerly compute
157 // its final result and write it into `self.propagated_borrowck_results`. This
158 // avoids having to compute its closure requirements modulo regions, as they
159 // are just the same as its final closure requirements.
160let mut depends_on_opaques = input.infcx.has_opaque_types_in_storage();
161162// Iterate over all nested bodies of `input`. If that nested body depends on
163 // opaque types, we apply its closure requirements modulo opaques. Otherwise
164 // we use the closure requirements from its final borrowck result.
165 //
166 // In case we've only applied the closure requirements modulo opaques, we have
167 // to later apply its closure requirements considering opaques, so we put that
168 // nested body back into `deferred_closure_requirements`.
169for (def_id, args, locations) in mem::take(&mut input.deferred_closure_requirements) {
170let closure_requirements = match self.propagated_borrowck_results.get(&def_id) {
171None => {
172 depends_on_opaques = true;
173 input.deferred_closure_requirements.push((def_id, args, locations));
174&closure_requirements_modulo_opaques[&def_id]
175 }
176Some(result) => &result.closure_requirements,
177 };
178179Self::apply_closure_requirements(
180&mut input,
181 closure_requirements,
182 def_id,
183 args,
184 locations,
185 );
186 }
187188// In case the current body does depend on opaques and is a nested body,
189 // we need to compute its closure requirements modulo opaques so that
190 // we're able to use it when visiting its parent later in this function.
191 //
192 // If the current body does not depend on opaque types, we finish borrowck
193 // and write its result into `propagated_borrowck_results`.
194if depends_on_opaques {
195if def_id != self.root_def_id {
196let req = Self::compute_closure_requirements_modulo_opaques(&input);
197 closure_requirements_modulo_opaques.insert(def_id, req);
198 }
199self.collect_region_constraints_results.insert(def_id, input);
200 } else {
201if !input.deferred_closure_requirements.is_empty() {
::core::panicking::panic("assertion failed: input.deferred_closure_requirements.is_empty()")
};assert!(input.deferred_closure_requirements.is_empty());
202let result = borrowck_check_region_constraints(self, input);
203self.propagated_borrowck_results.insert(def_id, result);
204 }
205 }
206 }
207208fn compute_closure_requirements_modulo_opaques(
209 input: &CollectRegionConstraintsResult<'tcx>,
210 ) -> Option<ClosureRegionRequirements<'tcx>> {
211compute_closure_requirements_modulo_opaques(
212&input.infcx,
213&input.body_owned,
214Rc::clone(&input.location_map),
215&input.universal_region_relations,
216&input.constraints,
217 )
218 }
219220fn apply_closure_requirements(
221 input: &mut CollectRegionConstraintsResult<'tcx>,
222 closure_requirements: &Option<ClosureRegionRequirements<'tcx>>,
223 closure_def_id: LocalDefId,
224 args: ty::GenericArgsRef<'tcx>,
225 locations: Locations,
226 ) {
227if let Some(closure_requirements) = closure_requirements {
228 constraint_conversion::ConstraintConversion::new(
229&input.infcx,
230&input.universal_region_relations.universal_regions,
231&input.region_bound_pairs,
232&input.known_type_outlives_obligations,
233locations,
234input.body_owned.span, // irrelevant; will be overridden.
235ConstraintCategory::Boring, // same as above.
236&mut input.constraints,
237 )
238 .apply_closure_requirements(closure_requirements, closure_def_id, args);
239 }
240 }
241242pub(super) fn do_mir_borrowck(&mut self) {
243// The list of all bodies we need to borrowck. This first looks at
244 // nested bodies, and then their parents. This means accessing e.g.
245 // `used_mut_upvars` for a closure can assume that we've already
246 // checked that closure.
247let all_bodies = self248 .tcx
249 .nested_bodies_within(self.root_def_id)
250 .iter()
251 .chain(std::iter::once(self.root_def_id));
252for def_id in all_bodies {
253let result = borrowck_collect_region_constraints(self, def_id);
254self.collect_region_constraints_results.insert(def_id, result);
255 }
256257// We now apply the closure requirements of nested bodies modulo
258 // opaques. In case a body does not depend on opaque types, we
259 // eagerly check its region constraints and use the final closure
260 // requirements.
261 //
262 // We eagerly finish borrowck for bodies which don't depend on
263 // opaques.
264self.apply_closure_requirements_modulo_opaques();
265266// We handle opaque type uses for all bodies together.
267self.handle_opaque_type_uses();
268269// Now walk over all bodies which depend on opaque types and finish borrowck.
270 //
271 // We first apply the final closure requirements from nested bodies which also
272 // depend on opaque types and then finish borrow checking the parent. Bodies
273 // which don't depend on opaques have already been fully borrowchecked in
274 // `apply_closure_requirements_modulo_opaques` as an optimization.
275for (def_id, mut input) in mem::take(&mut self.collect_region_constraints_results) {
276for (def_id, args, locations) in mem::take(&mut input.deferred_closure_requirements) {
277// We visit nested bodies before their parent, so we're already
278 // done with nested bodies at this point.
279let closure_requirements =
280&self.propagated_borrowck_results[&def_id].closure_requirements;
281Self::apply_closure_requirements(
282&mut input,
283 closure_requirements,
284 def_id,
285 args,
286 locations,
287 );
288 }
289290let result = borrowck_check_region_constraints(self, input);
291self.propagated_borrowck_results.insert(def_id, result);
292 }
293 }
294}