1use std::mem;
2use std::rc::Rc;
3
4use 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;
11
12use crate::consumers::BorrowckConsumer;
13use crate::nll::compute_closure_requirements_modulo_opaques;
14use crate::region_infer::opaque_types::{
15 apply_computed_concrete_opaque_types, clone_and_resolve_opaque_types,
16 compute_concrete_opaque_types, detect_opaque_types_added_while_handling_opaque_types,
17};
18use crate::type_check::{Locations, constraint_conversion};
19use crate::{
20 ClosureRegionRequirements, CollectRegionConstraintsResult, ConcreteOpaqueTypes,
21 PropagatedBorrowCheckResults, borrowck_check_region_constraints,
22 borrowck_collect_region_constraints,
23};
24
25pub(super) struct BorrowCheckRootCtxt<'tcx> {
28 pub tcx: TyCtxt<'tcx>,
29 root_def_id: LocalDefId,
30 concrete_opaque_types: ConcreteOpaqueTypes<'tcx>,
31 collect_region_constraints_results:
35 FxIndexMap<LocalDefId, CollectRegionConstraintsResult<'tcx>>,
36 propagated_borrowck_results: FxHashMap<LocalDefId, PropagatedBorrowCheckResults<'tcx>>,
37 tainted_by_errors: Option<ErrorGuaranteed>,
38 pub consumer: Option<BorrowckConsumer<'tcx>>,
41}
42
43impl<'tcx> BorrowCheckRootCtxt<'tcx> {
44 pub(super) fn new(
45 tcx: TyCtxt<'tcx>,
46 root_def_id: LocalDefId,
47 consumer: Option<BorrowckConsumer<'tcx>>,
48 ) -> BorrowCheckRootCtxt<'tcx> {
49 BorrowCheckRootCtxt {
50 tcx,
51 root_def_id,
52 concrete_opaque_types: Default::default(),
53 collect_region_constraints_results: Default::default(),
54 propagated_borrowck_results: Default::default(),
55 tainted_by_errors: None,
56 consumer,
57 }
58 }
59
60 pub(super) fn root_def_id(&self) -> LocalDefId {
61 self.root_def_id
62 }
63
64 pub(super) fn set_tainted_by_errors(&mut self, guar: ErrorGuaranteed) {
65 self.tainted_by_errors = Some(guar);
66 }
67
68 pub(super) fn used_mut_upvars(
69 &mut self,
70 nested_body_def_id: LocalDefId,
71 ) -> &SmallVec<[FieldIdx; 8]> {
72 &self.propagated_borrowck_results[&nested_body_def_id].used_mut_upvars
73 }
74
75 pub(super) fn finalize(self) -> Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> {
76 if let Some(guar) = self.tainted_by_errors {
77 Err(guar)
78 } else {
79 Ok(self.tcx.arena.alloc(self.concrete_opaque_types))
80 }
81 }
82
83 fn handle_opaque_type_uses(&mut self) {
84 let mut per_body_info = Vec::new();
85 for input in self.collect_region_constraints_results.values_mut() {
86 let (num_entries, opaque_types) = clone_and_resolve_opaque_types(
87 &input.infcx,
88 &input.universal_region_relations,
89 &mut input.constraints,
90 );
91 input.deferred_opaque_type_errors = compute_concrete_opaque_types(
92 &input.infcx,
93 &input.universal_region_relations,
94 &input.constraints,
95 Rc::clone(&input.location_map),
96 &mut self.concrete_opaque_types,
97 &opaque_types,
98 );
99 per_body_info.push((num_entries, opaque_types));
100 }
101
102 for (input, (opaque_types_storage_num_entries, opaque_types)) in
103 self.collect_region_constraints_results.values_mut().zip(per_body_info)
104 {
105 if input.deferred_opaque_type_errors.is_empty() {
106 input.deferred_opaque_type_errors = apply_computed_concrete_opaque_types(
107 &input.infcx,
108 &input.body_owned,
109 &input.universal_region_relations.universal_regions,
110 &input.region_bound_pairs,
111 &input.known_type_outlives_obligations,
112 &mut input.constraints,
113 &mut self.concrete_opaque_types,
114 &opaque_types,
115 );
116 }
117
118 detect_opaque_types_added_while_handling_opaque_types(
119 &input.infcx,
120 opaque_types_storage_num_entries,
121 )
122 }
123 }
124
125 fn apply_closure_requirements_modulo_opaques(&mut self) {
143 let mut closure_requirements_modulo_opaques = FxHashMap::default();
144 let collect_region_constraints_results =
148 mem::take(&mut self.collect_region_constraints_results);
149 for (def_id, mut input) in collect_region_constraints_results {
151 let mut depends_on_opaques = input.infcx.has_opaque_types_in_storage();
159
160 for (def_id, args, locations) in mem::take(&mut input.deferred_closure_requirements) {
168 let closure_requirements = match self.propagated_borrowck_results.get(&def_id) {
169 None => {
170 depends_on_opaques = true;
171 input.deferred_closure_requirements.push((def_id, args, locations));
172 &closure_requirements_modulo_opaques[&def_id]
173 }
174 Some(result) => &result.closure_requirements,
175 };
176
177 Self::apply_closure_requirements(
178 &mut input,
179 closure_requirements,
180 def_id,
181 args,
182 locations,
183 );
184 }
185
186 if depends_on_opaques {
193 if def_id != self.root_def_id {
194 let req = Self::compute_closure_requirements_modulo_opaques(&input);
195 closure_requirements_modulo_opaques.insert(def_id, req);
196 }
197 self.collect_region_constraints_results.insert(def_id, input);
198 } else {
199 assert!(input.deferred_closure_requirements.is_empty());
200 let result = borrowck_check_region_constraints(self, input);
201 self.propagated_borrowck_results.insert(def_id, result);
202 }
203 }
204 }
205
206 fn compute_closure_requirements_modulo_opaques(
207 input: &CollectRegionConstraintsResult<'tcx>,
208 ) -> Option<ClosureRegionRequirements<'tcx>> {
209 compute_closure_requirements_modulo_opaques(
210 &input.infcx,
211 &input.body_owned,
212 Rc::clone(&input.location_map),
213 &input.universal_region_relations,
214 &input.constraints,
215 )
216 }
217
218 fn apply_closure_requirements(
219 input: &mut CollectRegionConstraintsResult<'tcx>,
220 closure_requirements: &Option<ClosureRegionRequirements<'tcx>>,
221 closure_def_id: LocalDefId,
222 args: ty::GenericArgsRef<'tcx>,
223 locations: Locations,
224 ) {
225 if let Some(closure_requirements) = closure_requirements {
226 constraint_conversion::ConstraintConversion::new(
227 &input.infcx,
228 &input.universal_region_relations.universal_regions,
229 &input.region_bound_pairs,
230 &input.known_type_outlives_obligations,
231 locations,
232 input.body_owned.span, ConstraintCategory::Boring, &mut input.constraints,
235 )
236 .apply_closure_requirements(closure_requirements, closure_def_id, args);
237 }
238 }
239
240 pub(super) fn do_mir_borrowck(&mut self) {
241 let all_bodies = self
246 .tcx
247 .nested_bodies_within(self.root_def_id)
248 .iter()
249 .chain(std::iter::once(self.root_def_id));
250 for def_id in all_bodies {
251 let result = borrowck_collect_region_constraints(self, def_id);
252 self.collect_region_constraints_results.insert(def_id, result);
253 }
254
255 self.apply_closure_requirements_modulo_opaques();
263
264 self.handle_opaque_type_uses();
266
267 for (def_id, mut input) in mem::take(&mut self.collect_region_constraints_results) {
274 for (def_id, args, locations) in mem::take(&mut input.deferred_closure_requirements) {
275 let closure_requirements =
278 &self.propagated_borrowck_results[&def_id].closure_requirements;
279 Self::apply_closure_requirements(
280 &mut input,
281 closure_requirements,
282 def_id,
283 args,
284 locations,
285 );
286 }
287
288 let result = borrowck_check_region_constraints(self, input);
289 self.propagated_borrowck_results.insert(def_id, result);
290 }
291 }
292}