Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 2 additions & 9 deletions compiler/rustc_borrowck/src/consumers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub use super::polonius::legacy::{
RichLocation, RustcFacts,
};
pub use super::region_infer::RegionInferenceContext;
use crate::{BorrowCheckRootCtxt, do_mir_borrowck};
use crate::BorrowCheckRootCtxt;

/// Struct used during mir borrowck to collect bodies with facts for a typeck root and all
/// its nested bodies.
Expand Down Expand Up @@ -127,13 +127,6 @@ pub fn get_bodies_with_borrowck_facts(
) -> 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.do_mir_borrowck();
root_cx.consumer.unwrap().bodies
}
117 changes: 84 additions & 33 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ use std::ops::{ControlFlow, Deref};
use std::rc::Rc;

use borrow_set::LocalsStateAtExit;
use polonius_engine::AllFacts;
use root_cx::BorrowCheckRootCtxt;
use rustc_abi::FieldIdx;
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::dominators::Dominators;
use rustc_errors::LintDiagnostic;
Expand All @@ -32,6 +34,7 @@ use rustc_hir::CRATE_HIR_ID;
use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::MixedBitSet;
use rustc_index::{IndexSlice, IndexVec};
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::{
InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
};
Expand All @@ -53,23 +56,25 @@ use smallvec::SmallVec;
use tracing::{debug, instrument};

use crate::borrow_set::{BorrowData, BorrowSet};
use crate::consumers::BodyWithBorrowckFacts;
use crate::consumers::{BodyWithBorrowckFacts, RustcFacts};
use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
use crate::diagnostics::{
AccessKind, BorrowckDiagnosticsBuffer, IllegalMoveOriginKind, MoveError, RegionName,
};
use crate::path_utils::*;
use crate::place_ext::PlaceExt;
use crate::places_conflict::{PlaceConflictBias, places_conflict};
use crate::polonius::PoloniusDiagnosticsContext;
use crate::polonius::legacy::{
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
};
use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext};
use crate::prefixes::PrefixSet;
use crate::region_infer::RegionInferenceContext;
use crate::region_infer::opaque_types::DeferredOpaqueTypeError;
use crate::renumber::RegionCtxt;
use crate::session_diagnostics::VarNeedNotMut;
use crate::type_check::MirTypeckResults;
use crate::type_check::free_region_relations::UniversalRegionRelations;
use crate::type_check::{Locations, MirTypeckRegionConstraints, MirTypeckResults};

mod borrow_set;
mod borrowck_errors;
Expand Down Expand Up @@ -129,18 +134,7 @@ fn mir_borrowck(
Ok(tcx.arena.alloc(opaque_types))
} else {
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def, None);
// We need to manually borrowck all nested bodies from the HIR as
// we do not generate MIR for dead code. Not doing so causes us to
// never check closures in dead code.
let nested_bodies = tcx.nested_bodies_within(def);
for def_id in nested_bodies {
root_cx.get_or_insert_nested(def_id);
}

let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
do_mir_borrowck(&mut root_cx, def);
debug_assert!(closure_requirements.is_none());
debug_assert!(used_mut_upvars.is_empty());
root_cx.do_mir_borrowck();
root_cx.finalize()
}
}
Expand All @@ -153,6 +147,8 @@ struct PropagatedBorrowCheckResults<'tcx> {
used_mut_upvars: SmallVec<[FieldIdx; 8]>,
}

type DeferredClosureRequirements<'tcx> = Vec<(LocalDefId, ty::GenericArgsRef<'tcx>, Locations)>;

/// After we borrow check a closure, we are left with various
/// requirements that we have inferred between the free regions that
/// appear in the closure's signature or on its field types. These
Expand Down Expand Up @@ -291,14 +287,31 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
}
}

/// Perform the actual borrow checking.
///
/// For nested bodies this should only be called through `root_cx.get_or_insert_nested`.
#[instrument(skip(root_cx), level = "debug")]
fn do_mir_borrowck<'tcx>(
struct CollectRegionConstraintsResult<'tcx> {
infcx: BorrowckInferCtxt<'tcx>,
body_owned: Body<'tcx>,
promoted: IndexVec<Promoted, Body<'tcx>>,
move_data: MoveData<'tcx>,
borrow_set: BorrowSet<'tcx>,
location_table: PoloniusLocationTable,
location_map: Rc<DenseLocationMap>,
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
region_bound_pairs: Frozen<RegionBoundPairs<'tcx>>,
known_type_outlives_obligations: Frozen<Vec<ty::PolyTypeOutlivesPredicate<'tcx>>>,
constraints: MirTypeckRegionConstraints<'tcx>,
deferred_closure_requirements: DeferredClosureRequirements<'tcx>,
deferred_opaque_type_errors: Vec<DeferredOpaqueTypeError<'tcx>>,
polonius_facts: Option<AllFacts<RustcFacts>>,
polonius_context: Option<PoloniusContext>,
}

/// Start borrow checking by collecting the region constraints for
/// the current body. This initializes the relevant data structures
/// and then type checks the MIR body.
fn borrowck_collect_region_constraints<'tcx>(
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
def: LocalDefId,
) -> PropagatedBorrowCheckResults<'tcx> {
) -> CollectRegionConstraintsResult<'tcx> {
let tcx = root_cx.tcx;
let infcx = BorrowckInferCtxt::new(tcx, def, root_cx.root_def_id());
let (input_body, promoted) = tcx.mir_promoted(def);
Expand Down Expand Up @@ -334,10 +347,11 @@ fn do_mir_borrowck<'tcx>(

// Run the MIR type-checker.
let MirTypeckResults {
mut constraints,
constraints,
universal_region_relations,
region_bound_pairs,
known_type_outlives_obligations,
deferred_closure_requirements,
polonius_context,
} = type_check::type_check(
root_cx,
Expand All @@ -352,16 +366,53 @@ fn do_mir_borrowck<'tcx>(
Rc::clone(&location_map),
);

let opaque_type_errors = region_infer::opaque_types::handle_opaque_type_uses(
root_cx,
&infcx,
&body,
&universal_region_relations,
&region_bound_pairs,
&known_type_outlives_obligations,
&location_map,
&mut constraints,
);
CollectRegionConstraintsResult {
infcx,
body_owned,
promoted,
move_data,
borrow_set,
location_table,
location_map,
universal_region_relations,
region_bound_pairs,
known_type_outlives_obligations,
constraints,
deferred_closure_requirements,
deferred_opaque_type_errors: Default::default(),
polonius_facts,
polonius_context,
}
}

/// Using the region constraints computed by [borrowck_collect_region_constraints]
/// and the additional constraints from [BorrowCheckRootCtxt::handle_opaque_type_uses],
/// compute the region graph and actually check for any borrowck errors.
fn borrowck_check_region_constraints<'tcx>(
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
CollectRegionConstraintsResult {
infcx,
body_owned,
promoted,
move_data,
borrow_set,
location_table,
location_map,
universal_region_relations,
region_bound_pairs: _,
known_type_outlives_obligations: _,
constraints,
deferred_closure_requirements,
deferred_opaque_type_errors,
polonius_facts,
polonius_context,
}: CollectRegionConstraintsResult<'tcx>,
) -> PropagatedBorrowCheckResults<'tcx> {
assert!(!infcx.has_opaque_types_in_storage());
assert!(deferred_closure_requirements.is_empty());
let tcx = root_cx.tcx;
let body = &body_owned;
let def = body.source.def_id().expect_local();

// Compute non-lexical lifetimes using the constraints computed
// by typechecking the MIR body.
Expand Down Expand Up @@ -481,7 +532,7 @@ fn do_mir_borrowck<'tcx>(

// Compute and report region errors, if any.
if nll_errors.is_empty() {
mbcx.report_opaque_type_errors(opaque_type_errors);
mbcx.report_opaque_type_errors(deferred_opaque_type_errors);
} else {
mbcx.report_region_errors(nll_errors);
}
Expand Down
32 changes: 32 additions & 0 deletions compiler/rustc_borrowck/src/nll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,38 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
universal_regions
}

/// Computes the closure requirements given the current inference state.
///
/// This is intended to be used by before [BorrowCheckRootCtxt::handle_opaque_type_uses]
/// because applying member constraints may rely on closure requirements.
/// This is frequently the case of async functions where pretty much everything
/// happens inside of the inner async block but the opaque only gets constrained
/// in the parent function.
pub(crate) fn compute_closure_requirements_modulo_opaques<'tcx>(
infcx: &BorrowckInferCtxt<'tcx>,
body: &Body<'tcx>,
location_map: Rc<DenseLocationMap>,
universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
constraints: &MirTypeckRegionConstraints<'tcx>,
) -> Option<ClosureRegionRequirements<'tcx>> {
// FIXME(closure-req-clone): we shouldn't have to clone all this stuff here.
// Computing the region graph should take at least some of it by reference/`Rc`.
let lowered_constraints = compute_sccs_applying_placeholder_outlives_constraints(
constraints.clone(),
&universal_region_relations,
infcx,
);
let mut regioncx = RegionInferenceContext::new(
&infcx,
lowered_constraints,
universal_region_relations.clone(),
location_map,
);

let (closure_region_requirements, _nll_errors) = regioncx.solve(infcx, body, None);
closure_region_requirements
}

/// Computes the (non-lexical) regions from the input MIR.
///
/// This may result in errors being reported.
Expand Down
Loading
Loading