blob: 1c4ff5a677902cad69d99016be36682bf9f73c1a [file] [log] [blame]
//! This file provides API for compiler consumers.
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::LocalDefId;
use rustc_index::IndexVec;
use rustc_middle::bug;
use rustc_middle::mir::{Body, Promoted};
use rustc_middle::ty::TyCtxt;
pub use super::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
pub use super::constraints::OutlivesConstraint;
pub use super::dataflow::{BorrowIndex, Borrows, calculate_borrows_out_of_scope_at_location};
pub use super::place_ext::PlaceExt;
pub use super::places_conflict::{PlaceConflictBias, places_conflict};
pub use super::polonius::legacy::{
PoloniusFacts as PoloniusInput, PoloniusLocationTable, PoloniusOutput, PoloniusRegionVid,
RichLocation, RustcFacts,
};
pub use super::region_infer::RegionInferenceContext;
use crate::{BorrowCheckRootCtxt, do_mir_borrowck};
/// Struct used during mir borrowck to collect bodies with facts for a typeck root and all
/// its nested bodies.
pub(crate) struct BorrowckConsumer<'tcx> {
options: ConsumerOptions,
bodies: FxHashMap<LocalDefId, BodyWithBorrowckFacts<'tcx>>,
}
impl<'tcx> BorrowckConsumer<'tcx> {
pub(crate) fn new(options: ConsumerOptions) -> Self {
Self { options, bodies: Default::default() }
}
pub(crate) fn insert_body(&mut self, def_id: LocalDefId, body: BodyWithBorrowckFacts<'tcx>) {
if self.bodies.insert(def_id, body).is_some() {
bug!("unexpected previous body for {def_id:?}");
}
}
/// Should the Polonius input facts be computed?
pub(crate) fn polonius_input(&self) -> bool {
matches!(
self.options,
ConsumerOptions::PoloniusInputFacts | ConsumerOptions::PoloniusOutputFacts
)
}
/// Should we run Polonius and collect the output facts?
pub(crate) fn polonius_output(&self) -> bool {
matches!(self.options, ConsumerOptions::PoloniusOutputFacts)
}
}
/// Options determining the output behavior of [`get_bodies_with_borrowck_facts`].
///
/// If executing under `-Z polonius` the choice here has no effect, and everything as if
/// [`PoloniusOutputFacts`](ConsumerOptions::PoloniusOutputFacts) had been selected
/// will be retrieved.
#[derive(Debug, Copy, Clone)]
pub enum ConsumerOptions {
/// Retrieve the [`Body`] along with the [`BorrowSet`]
/// and [`RegionInferenceContext`]. If you would like the body only, use
/// [`TyCtxt::mir_promoted`].
///
/// These can be used in conjunction with [`calculate_borrows_out_of_scope_at_location`].
RegionInferenceContext,
/// The recommended option. Retrieves the maximal amount of information
/// without significant slowdowns.
///
/// Implies [`RegionInferenceContext`](ConsumerOptions::RegionInferenceContext),
/// and additionally retrieve the [`PoloniusLocationTable`] and [`PoloniusInput`] that
/// would be given to Polonius. Critically, this does not run Polonius, which
/// one may want to avoid due to performance issues on large bodies.
PoloniusInputFacts,
/// Implies [`PoloniusInputFacts`](ConsumerOptions::PoloniusInputFacts),
/// and additionally runs Polonius to calculate the [`PoloniusOutput`].
PoloniusOutputFacts,
}
/// A `Body` with information computed by the borrow checker. This struct is
/// intended to be consumed by compiler consumers.
///
/// We need to include the MIR body here because the region identifiers must
/// match the ones in the Polonius facts.
pub struct BodyWithBorrowckFacts<'tcx> {
/// A mir body that contains region identifiers.
pub body: Body<'tcx>,
/// The mir bodies of promoteds.
pub promoted: IndexVec<Promoted, Body<'tcx>>,
/// The set of borrows occurring in `body` with data about them.
pub borrow_set: BorrowSet<'tcx>,
/// Context generated during borrowck, intended to be passed to
/// [`calculate_borrows_out_of_scope_at_location`].
pub region_inference_context: RegionInferenceContext<'tcx>,
/// The table that maps Polonius points to locations in the table.
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
/// or [`ConsumerOptions::PoloniusOutputFacts`].
pub location_table: Option<PoloniusLocationTable>,
/// Polonius input facts.
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
/// or [`ConsumerOptions::PoloniusOutputFacts`].
pub input_facts: Option<Box<PoloniusInput>>,
/// Polonius output facts. Populated when using
/// [`ConsumerOptions::PoloniusOutputFacts`].
pub output_facts: Option<Box<PoloniusOutput>>,
}
/// This function computes borrowck facts for the given def id and all its nested bodies.
/// It must be called with a typeck root which will then borrowck all nested bodies as well.
/// The [`ConsumerOptions`] determine which facts are returned. This function makes a copy
/// of the bodies because it needs to regenerate the region identifiers. It should never be
/// invoked during a typical compilation session due to the unnecessary overhead of
/// returning [`BodyWithBorrowckFacts`].
///
/// Note:
/// * This function will panic if the required bodies were already stolen. This
/// can, for example, happen when requesting a body of a `const` function
/// because they are evaluated during typechecking. The panic can be avoided
/// by overriding the `mir_borrowck` query. You can find a complete example
/// that shows how to do this at `tests/ui-fulldeps/obtain-borrowck.rs`.
///
/// * Polonius is highly unstable, so expect regular changes in its signature or other details.
pub fn get_bodies_with_borrowck_facts(
tcx: TyCtxt<'_>,
root_def_id: LocalDefId,
options: ConsumerOptions,
) -> FxHashMap<LocalDefId, BodyWithBorrowckFacts<'_>> {
let mut root_cx =
BorrowCheckRootCtxt::new(tcx, root_def_id, Some(BorrowckConsumer::new(options)));
// See comment in `rustc_borrowck::mir_borrowck`
let nested_bodies = tcx.nested_bodies_within(root_def_id);
for def_id in nested_bodies {
root_cx.get_or_insert_nested(def_id);
}
do_mir_borrowck(&mut root_cx, root_def_id);
root_cx.consumer.unwrap().bodies
}