Skip to main content

rustc_borrowck/
root_cx.rs

1use std::cell::Cell;
2use std::mem;
3use std::rc::Rc;
4
5use 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;
13
14use crate::consumers::BorrowckConsumer;
15use crate::diagnostics::BorrowckDiagnosticsBuffer;
16use crate::nll::compute_closure_requirements_modulo_opaques;
17use crate::region_infer::opaque_types::{
18    UnexpectedHiddenRegion, apply_definition_site_hidden_types, clone_and_resolve_opaque_types,
19    compute_definition_site_hidden_types, detect_opaque_types_added_while_handling_opaque_types,
20    handle_unconstrained_hidden_type_errors,
21};
22use crate::type_check::{Locations, constraint_conversion};
23use crate::{
24    ClosureRegionRequirements, CollectRegionConstraintsResult, PropagatedBorrowCheckResults,
25    borrowck_check_region_constraints, borrowck_collect_region_constraints,
26};
27
28/// The shared context used by both the root as well as all its nested
29/// items.
30pub(super) struct BorrowCheckRootCtxt<'diag, 'tcx: 'diag> {
31    pub tcx: TyCtxt<'tcx>,
32    root_def_id: LocalDefId,
33    /// This contains fully resolved hidden types or `ty::Error`.
34    hidden_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`]
38    unconstrained_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.
42    collect_region_constraints_results:
43        FxIndexMap<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.
48    pub consumer: Option<BorrowckConsumer<'tcx>>,
49}
50
51impl<'diag, 'tcx> BorrowCheckRootCtxt<'diag, 'tcx> {
52    pub(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> {
58        BorrowCheckRootCtxt {
59            tcx,
60            root_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(),
65            tainted_by_errors,
66            consumer,
67        }
68    }
69
70    pub(super) fn root_def_id(&self) -> LocalDefId {
71        self.root_def_id
72    }
73
74    pub(super) fn set_tainted_by_errors(&self, guar: ErrorGuaranteed) {
75        self.tainted_by_errors.set(Some(guar));
76    }
77
78    pub(super) fn dcx(&self) -> DiagCtxtHandle<'diag> {
79        self.tcx.dcx().taintable_handle(&self.tainted_by_errors)
80    }
81
82    pub(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    }
88
89    pub(super) fn finalize(
90        self,
91    ) -> Result<&'tcx FxIndexMap<LocalDefId, ty::DefinitionSiteHiddenType<'tcx>>, ErrorGuaranteed>
92    {
93        if let Some(guar) = self.tainted_by_errors.get() {
94            Err(guar)
95        } else {
96            Ok(self.tcx.arena.alloc(self.hidden_types))
97        }
98    }
99
100    fn handle_opaque_type_uses(&mut self) {
101        let mut per_body_info = Vec::new();
102        for (def_id, input) in &mut self.collect_region_constraints_results {
103            let (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        }
120
121        handle_unconstrained_hidden_type_errors(
122            self.tcx,
123            &mut self.hidden_types,
124            &mut self.unconstrained_hidden_type_errors,
125            &mut self.collect_region_constraints_results,
126        );
127
128        for (input, (opaque_types_storage_num_entries, opaque_types)) in
129            self.collect_region_constraints_results.values_mut().zip(per_body_info)
130        {
131            if 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            }
143
144            detect_opaque_types_added_while_handling_opaque_types(
145                &input.infcx,
146                opaque_types_storage_num_entries,
147            )
148        }
149    }
150
151    /// 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`.
168    fn apply_closure_requirements_modulo_opaques(
169        &mut self,
170        diags_buffer: &mut BorrowckDiagnosticsBuffer<'diag, 'tcx>,
171    ) {
172        let 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.
176        let 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.
179        for (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.
187            let mut depends_on_opaques = input.infcx.has_opaque_types_in_storage();
188
189            // 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`.
196            for (def_id, args, locations) in mem::take(&mut input.deferred_closure_requirements) {
197                let closure_requirements = match self.propagated_borrowck_results.get(&def_id) {
198                    None => {
199                        depends_on_opaques = true;
200                        input.deferred_closure_requirements.push((def_id, args, locations));
201                        &closure_requirements_modulo_opaques[&def_id]
202                    }
203                    Some(result) => &result.closure_requirements,
204                };
205
206                Self::apply_closure_requirements(
207                    &mut input,
208                    closure_requirements,
209                    def_id,
210                    args,
211                    locations,
212                );
213            }
214
215            // 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`.
221            if depends_on_opaques {
222                if def_id != self.root_def_id {
223                    let req = Self::compute_closure_requirements_modulo_opaques(&input);
224                    closure_requirements_modulo_opaques.insert(def_id, req);
225                }
226                self.collect_region_constraints_results.insert(def_id, input);
227            } else {
228                if !input.deferred_closure_requirements.is_empty() {
    ::core::panicking::panic("assertion failed: input.deferred_closure_requirements.is_empty()")
};assert!(input.deferred_closure_requirements.is_empty());
229                let result = borrowck_check_region_constraints(self, diags_buffer, input);
230                self.propagated_borrowck_results.insert(def_id, result);
231            }
232        }
233    }
234
235    fn compute_closure_requirements_modulo_opaques(
236        input: &CollectRegionConstraintsResult<'tcx>,
237    ) -> Option<ClosureRegionRequirements<'tcx>> {
238        compute_closure_requirements_modulo_opaques(
239            &input.infcx,
240            &input.body_owned,
241            Rc::clone(&input.location_map),
242            &input.universal_region_relations,
243            &input.constraints,
244        )
245    }
246
247    fn 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    ) {
254        if 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,
260                locations,
261                input.body_owned.span,      // irrelevant; will be overridden.
262                ConstraintCategory::Boring, // same as above.
263                &mut input.constraints,
264            )
265            .apply_closure_requirements(closure_requirements, closure_def_id, args);
266        }
267    }
268
269    pub(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.
274        let all_bodies = self
275            .tcx
276            .nested_bodies_within(self.root_def_id)
277            .iter()
278            .chain(std::iter::once(self.root_def_id));
279        for def_id in all_bodies {
280            let result = borrowck_collect_region_constraints(self, def_id);
281            self.collect_region_constraints_results.insert(def_id, result);
282        }
283
284        let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
285
286        // 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.
293        self.apply_closure_requirements_modulo_opaques(diags_buffer);
294
295        // We handle opaque type uses for all bodies together.
296        self.handle_opaque_type_uses();
297
298        // 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.
304        for (def_id, mut input) in mem::take(&mut self.collect_region_constraints_results) {
305            for (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.
308                let closure_requirements =
309                    &self.propagated_borrowck_results[&def_id].closure_requirements;
310                Self::apply_closure_requirements(
311                    &mut input,
312                    closure_requirements,
313                    def_id,
314                    args,
315                    locations,
316                );
317            }
318
319            let result = borrowck_check_region_constraints(self, diags_buffer, input);
320            self.propagated_borrowck_results.insert(def_id, result);
321        }
322        diags_buffer.emit_errors();
323    }
324}