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::{
15UnexpectedHiddenRegion, apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
16compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types,
17handle_unconstrained_hidden_type_errors,
18};
19use crate::type_check::{Locations, constraint_conversion};
20use crate::{
21ClosureRegionRequirements, CollectRegionConstraintsResult, PropagatedBorrowCheckResults,
22borrowck_check_region_constraints, borrowck_collect_region_constraints,
23};
2425/// The shared context used by both the root as well as all its nested
26/// items.
27pub(super) struct BorrowCheckRootCtxt<'tcx> {
28pub tcx: TyCtxt<'tcx>,
29 root_def_id: LocalDefId,
30/// This contains fully resolved hidden types or `ty::Error`.
31hidden_types: FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>,
32/// This contains unconstrained regions in hidden types.
33 /// Only used for deferred error reporting. See
34 /// [`crate::region_infer::opaque_types::handle_unconstrained_hidden_type_errors`]
35unconstrained_hidden_type_errors: Vec<UnexpectedHiddenRegion<'tcx>>,
36/// The region constraints computed by [borrowck_collect_region_constraints]. This uses
37 /// an [FxIndexMap] to guarantee that iterating over it visits nested bodies before
38 /// their parents.
39collect_region_constraints_results:
40FxIndexMap<LocalDefId, CollectRegionConstraintsResult<'tcx>>,
41 propagated_borrowck_results: FxHashMap<LocalDefId, PropagatedBorrowCheckResults<'tcx>>,
42 tainted_by_errors: Option<ErrorGuaranteed>,
43/// This should be `None` during normal compilation. See [`crate::consumers`] for more
44 /// information on how this is used.
45pub consumer: Option<BorrowckConsumer<'tcx>>,
46}
4748impl<'tcx> BorrowCheckRootCtxt<'tcx> {
49pub(super) fn new(
50 tcx: TyCtxt<'tcx>,
51 root_def_id: LocalDefId,
52 consumer: Option<BorrowckConsumer<'tcx>>,
53 ) -> BorrowCheckRootCtxt<'tcx> {
54BorrowCheckRootCtxt {
55tcx,
56root_def_id,
57 hidden_types: Default::default(),
58 unconstrained_hidden_type_errors: Default::default(),
59 collect_region_constraints_results: Default::default(),
60 propagated_borrowck_results: Default::default(),
61 tainted_by_errors: None,
62consumer,
63 }
64 }
6566pub(super) fn root_def_id(&self) -> LocalDefId {
67self.root_def_id
68 }
6970pub(super) fn set_tainted_by_errors(&mut self, guar: ErrorGuaranteed) {
71self.tainted_by_errors = Some(guar);
72 }
7374pub(super) fn used_mut_upvars(
75&mut self,
76 nested_body_def_id: LocalDefId,
77 ) -> &SmallVec<[FieldIdx; 8]> {
78&self.propagated_borrowck_results[&nested_body_def_id].used_mut_upvars
79 }
8081pub(super) fn finalize(
82self,
83 ) -> Result<&'tcx FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>, ErrorGuaranteed>
84 {
85if let Some(guar) = self.tainted_by_errors {
86Err(guar)
87 } else {
88Ok(self.tcx.arena.alloc(self.hidden_types))
89 }
90 }
9192fn handle_opaque_type_uses(&mut self) {
93let mut per_body_info = Vec::new();
94for (def_id, input) in &mut self.collect_region_constraints_results {
95let (num_entries, opaque_types) = clone_and_resolve_opaque_types(
96&input.infcx,
97&input.universal_region_relations,
98&mut input.constraints,
99 );
100 input.deferred_opaque_type_errors = compute_definition_site_hidden_types(
101*def_id,
102&input.infcx,
103&input.universal_region_relations,
104&input.constraints,
105 Rc::clone(&input.location_map),
106&mut self.hidden_types,
107&mut self.unconstrained_hidden_type_errors,
108&opaque_types,
109 );
110 per_body_info.push((num_entries, opaque_types));
111 }
112113handle_unconstrained_hidden_type_errors(
114self.tcx,
115&mut self.hidden_types,
116&mut self.unconstrained_hidden_type_errors,
117&mut self.collect_region_constraints_results,
118 );
119120for (input, (opaque_types_storage_num_entries, opaque_types)) in
121self.collect_region_constraints_results.values_mut().zip(per_body_info)
122 {
123if input.deferred_opaque_type_errors.is_empty() {
124 input.deferred_opaque_type_errors = apply_definition_site_hidden_types(
125&input.infcx,
126&input.body_owned,
127&input.universal_region_relations.universal_regions,
128&input.region_bound_pairs,
129&input.known_type_outlives_obligations,
130&mut input.constraints,
131&mut self.hidden_types,
132&opaque_types,
133 );
134 }
135136 detect_opaque_types_added_while_handling_opaque_types(
137&input.infcx,
138 opaque_types_storage_num_entries,
139 )
140 }
141 }
142143/// Computing defining uses of opaques may depend on the propagated region
144 /// requirements of nested bodies, while applying defining uses may introduce
145 /// additional region requirements we need to propagate.
146 ///
147 /// This results in cyclic dependency. To compute the defining uses in parent
148 /// bodies, we need the closure requirements of its nested bodies, but to check
149 /// non-defining uses in nested bodies, we may rely on the defining uses in the
150 /// parent.
151 ///
152 /// We handle this issue by applying closure requirements twice. Once using the
153 /// region constraints from before we've handled opaque types in the nested body
154 /// - which is used by the parent to handle its defining uses - and once after.
155 ///
156 /// As a performance optimization, we also eagerly finish borrowck for bodies
157 /// which don't depend on opaque types. In this case they get removed from
158 /// `collect_region_constraints_results` and the final result gets put into
159 /// `propagated_borrowck_results`.
160fn apply_closure_requirements_modulo_opaques(&mut self) {
161let mut closure_requirements_modulo_opaques = FxHashMap::default();
162// We need to `mem::take` both `self.collect_region_constraints_results` and
163 // `input.deferred_closure_requirements` as we otherwise can't iterate over
164 // them while mutably using the containing struct.
165let collect_region_constraints_results =
166 mem::take(&mut self.collect_region_constraints_results);
167// We iterate over all bodies here, visiting nested bodies before their parent.
168for (def_id, mut input) in collect_region_constraints_results {
169// A body depends on opaque types if it either has any opaque type uses itself,
170 // or it has a nested body which does.
171 //
172 // If the current body does not depend on any opaque types, we eagerly compute
173 // its final result and write it into `self.propagated_borrowck_results`. This
174 // avoids having to compute its closure requirements modulo regions, as they
175 // are just the same as its final closure requirements.
176let mut depends_on_opaques = input.infcx.has_opaque_types_in_storage();
177178// Iterate over all nested bodies of `input`. If that nested body depends on
179 // opaque types, we apply its closure requirements modulo opaques. Otherwise
180 // we use the closure requirements from its final borrowck result.
181 //
182 // In case we've only applied the closure requirements modulo opaques, we have
183 // to later apply its closure requirements considering opaques, so we put that
184 // nested body back into `deferred_closure_requirements`.
185for (def_id, args, locations) in mem::take(&mut input.deferred_closure_requirements) {
186let closure_requirements = match self.propagated_borrowck_results.get(&def_id) {
187None => {
188 depends_on_opaques = true;
189 input.deferred_closure_requirements.push((def_id, args, locations));
190&closure_requirements_modulo_opaques[&def_id]
191 }
192Some(result) => &result.closure_requirements,
193 };
194195Self::apply_closure_requirements(
196&mut input,
197 closure_requirements,
198 def_id,
199 args,
200 locations,
201 );
202 }
203204// In case the current body does depend on opaques and is a nested body,
205 // we need to compute its closure requirements modulo opaques so that
206 // we're able to use it when visiting its parent later in this function.
207 //
208 // If the current body does not depend on opaque types, we finish borrowck
209 // and write its result into `propagated_borrowck_results`.
210if depends_on_opaques {
211if def_id != self.root_def_id {
212let req = Self::compute_closure_requirements_modulo_opaques(&input);
213 closure_requirements_modulo_opaques.insert(def_id, req);
214 }
215self.collect_region_constraints_results.insert(def_id, input);
216 } else {
217if !input.deferred_closure_requirements.is_empty() {
::core::panicking::panic("assertion failed: input.deferred_closure_requirements.is_empty()")
};assert!(input.deferred_closure_requirements.is_empty());
218let result = borrowck_check_region_constraints(self, input);
219self.propagated_borrowck_results.insert(def_id, result);
220 }
221 }
222 }
223224fn compute_closure_requirements_modulo_opaques(
225 input: &CollectRegionConstraintsResult<'tcx>,
226 ) -> Option<ClosureRegionRequirements<'tcx>> {
227compute_closure_requirements_modulo_opaques(
228&input.infcx,
229&input.body_owned,
230Rc::clone(&input.location_map),
231&input.universal_region_relations,
232&input.constraints,
233 )
234 }
235236fn apply_closure_requirements(
237 input: &mut CollectRegionConstraintsResult<'tcx>,
238 closure_requirements: &Option<ClosureRegionRequirements<'tcx>>,
239 closure_def_id: LocalDefId,
240 args: ty::GenericArgsRef<'tcx>,
241 locations: Locations,
242 ) {
243if let Some(closure_requirements) = closure_requirements {
244 constraint_conversion::ConstraintConversion::new(
245&input.infcx,
246&input.universal_region_relations.universal_regions,
247&input.region_bound_pairs,
248&input.known_type_outlives_obligations,
249locations,
250input.body_owned.span, // irrelevant; will be overridden.
251ConstraintCategory::Boring, // same as above.
252&mut input.constraints,
253 )
254 .apply_closure_requirements(closure_requirements, closure_def_id, args);
255 }
256 }
257258pub(super) fn do_mir_borrowck(&mut self) {
259// The list of all bodies we need to borrowck. This first looks at
260 // nested bodies, and then their parents. This means accessing e.g.
261 // `used_mut_upvars` for a closure can assume that we've already
262 // checked that closure.
263let all_bodies = self264 .tcx
265 .nested_bodies_within(self.root_def_id)
266 .iter()
267 .chain(std::iter::once(self.root_def_id));
268for def_id in all_bodies {
269let result = borrowck_collect_region_constraints(self, def_id);
270self.collect_region_constraints_results.insert(def_id, result);
271 }
272273// We now apply the closure requirements of nested bodies modulo
274 // opaques. In case a body does not depend on opaque types, we
275 // eagerly check its region constraints and use the final closure
276 // requirements.
277 //
278 // We eagerly finish borrowck for bodies which don't depend on
279 // opaques.
280self.apply_closure_requirements_modulo_opaques();
281282// We handle opaque type uses for all bodies together.
283self.handle_opaque_type_uses();
284285// Now walk over all bodies which depend on opaque types and finish borrowck.
286 //
287 // We first apply the final closure requirements from nested bodies which also
288 // depend on opaque types and then finish borrow checking the parent. Bodies
289 // which don't depend on opaques have already been fully borrowchecked in
290 // `apply_closure_requirements_modulo_opaques` as an optimization.
291for (def_id, mut input) in mem::take(&mut self.collect_region_constraints_results) {
292for (def_id, args, locations) in mem::take(&mut input.deferred_closure_requirements) {
293// We visit nested bodies before their parent, so we're already
294 // done with nested bodies at this point.
295let closure_requirements =
296&self.propagated_borrowck_results[&def_id].closure_requirements;
297Self::apply_closure_requirements(
298&mut input,
299 closure_requirements,
300 def_id,
301 args,
302 locations,
303 );
304 }
305306let result = borrowck_check_region_constraints(self, input);
307self.propagated_borrowck_results.insert(def_id, result);
308 }
309 }
310}