| use rustc_abi::FieldIdx; |
| use rustc_data_structures::fx::FxHashMap; |
| use rustc_hir::def_id::LocalDefId; |
| use rustc_middle::bug; |
| use rustc_middle::ty::{OpaqueHiddenType, Ty, TyCtxt, TypeVisitableExt}; |
| use rustc_span::ErrorGuaranteed; |
| use smallvec::SmallVec; |
| |
| use crate::{ClosureRegionRequirements, ConcreteOpaqueTypes, PropagatedBorrowCheckResults}; |
| |
| /// The shared context used by both the root as well as all its nested |
| /// items. |
| pub(super) struct BorrowCheckRootCtxt<'tcx> { |
| pub tcx: TyCtxt<'tcx>, |
| root_def_id: LocalDefId, |
| concrete_opaque_types: ConcreteOpaqueTypes<'tcx>, |
| nested_bodies: FxHashMap<LocalDefId, PropagatedBorrowCheckResults<'tcx>>, |
| tainted_by_errors: Option<ErrorGuaranteed>, |
| } |
| |
| impl<'tcx> BorrowCheckRootCtxt<'tcx> { |
| pub(super) fn new(tcx: TyCtxt<'tcx>, root_def_id: LocalDefId) -> BorrowCheckRootCtxt<'tcx> { |
| BorrowCheckRootCtxt { |
| tcx, |
| root_def_id, |
| concrete_opaque_types: Default::default(), |
| nested_bodies: Default::default(), |
| tainted_by_errors: None, |
| } |
| } |
| |
| /// Collect all defining uses of opaque types inside of this typeck root. This |
| /// expects the hidden type to be mapped to the definition parameters of the opaque |
| /// and errors if we end up with distinct hidden types. |
| pub(super) fn add_concrete_opaque_type( |
| &mut self, |
| def_id: LocalDefId, |
| hidden_ty: OpaqueHiddenType<'tcx>, |
| ) { |
| // Sometimes two opaque types are the same only after we remap the generic parameters |
| // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to |
| // `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we |
| // only know that once we convert the generic parameters to those of the opaque type. |
| if let Some(prev) = self.concrete_opaque_types.0.get_mut(&def_id) { |
| if prev.ty != hidden_ty.ty { |
| let guar = hidden_ty.ty.error_reported().err().unwrap_or_else(|| { |
| let (Ok(e) | Err(e)) = |
| prev.build_mismatch_error(&hidden_ty, self.tcx).map(|d| d.emit()); |
| e |
| }); |
| prev.ty = Ty::new_error(self.tcx, guar); |
| } |
| // Pick a better span if there is one. |
| // FIXME(oli-obk): collect multiple spans for better diagnostics down the road. |
| prev.span = prev.span.substitute_dummy(hidden_ty.span); |
| } else { |
| self.concrete_opaque_types.0.insert(def_id, hidden_ty); |
| } |
| } |
| |
| pub(super) fn set_tainted_by_errors(&mut self, guar: ErrorGuaranteed) { |
| self.tainted_by_errors = Some(guar); |
| } |
| |
| pub(super) fn get_or_insert_nested( |
| &mut self, |
| def_id: LocalDefId, |
| ) -> &PropagatedBorrowCheckResults<'tcx> { |
| debug_assert_eq!( |
| self.tcx.typeck_root_def_id(def_id.to_def_id()), |
| self.root_def_id.to_def_id() |
| ); |
| if !self.nested_bodies.contains_key(&def_id) { |
| let result = super::do_mir_borrowck(self, def_id, None).0; |
| if let Some(prev) = self.nested_bodies.insert(def_id, result) { |
| bug!("unexpected previous nested body: {prev:?}"); |
| } |
| } |
| |
| self.nested_bodies.get(&def_id).unwrap() |
| } |
| |
| pub(super) fn closure_requirements( |
| &mut self, |
| nested_body_def_id: LocalDefId, |
| ) -> &Option<ClosureRegionRequirements<'tcx>> { |
| &self.get_or_insert_nested(nested_body_def_id).closure_requirements |
| } |
| |
| pub(super) fn used_mut_upvars( |
| &mut self, |
| nested_body_def_id: LocalDefId, |
| ) -> &SmallVec<[FieldIdx; 8]> { |
| &self.get_or_insert_nested(nested_body_def_id).used_mut_upvars |
| } |
| |
| pub(super) fn finalize(self) -> Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> { |
| if let Some(guar) = self.tainted_by_errors { |
| Err(guar) |
| } else { |
| Ok(self.tcx.arena.alloc(self.concrete_opaque_types)) |
| } |
| } |
| } |