mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-16 22:16:53 +00:00
support revealing-uses in closures
This commit is contained in:
parent
1bce98ff06
commit
d85f8b0222
@ -15,7 +15,7 @@ pub use super::polonius::legacy::{
|
||||
RichLocation, RustcFacts,
|
||||
};
|
||||
pub use super::region_infer::RegionInferenceContext;
|
||||
use crate::{BorrowCheckRootCtxt, do_mir_borrowck};
|
||||
use crate::BorrowCheckRootCtxt;
|
||||
|
||||
/// Options determining the output behavior of [`get_body_with_borrowck_facts`].
|
||||
///
|
||||
@ -101,6 +101,6 @@ pub fn get_body_with_borrowck_facts(
|
||||
def_id: LocalDefId,
|
||||
options: ConsumerOptions,
|
||||
) -> BodyWithBorrowckFacts<'_> {
|
||||
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def_id);
|
||||
*do_mir_borrowck(&mut root_cx, def_id, Some(options)).1.unwrap()
|
||||
let root_cx = BorrowCheckRootCtxt::new(tcx, def_id);
|
||||
*root_cx.borrowck_root(Some(options)).1.unwrap()
|
||||
}
|
||||
|
@ -21,10 +21,14 @@ use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
use std::rc::Rc;
|
||||
|
||||
use borrow_set::LocalsStateAtExit;
|
||||
use polonius_engine::AllFacts;
|
||||
use region_infer::opaque_types::DeferredOpaqueTypeError;
|
||||
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;
|
||||
@ -33,6 +37,7 @@ use rustc_hir::CRATE_HIR_ID;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
||||
use rustc_infer::infer::{
|
||||
InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
|
||||
};
|
||||
@ -48,14 +53,17 @@ use rustc_mir_dataflow::impls::{
|
||||
use rustc_mir_dataflow::move_paths::{
|
||||
InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
|
||||
};
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
|
||||
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||
use smallvec::SmallVec;
|
||||
use tracing::{debug, instrument};
|
||||
use type_check::free_region_relations::UniversalRegionRelations;
|
||||
use type_check::{Locations, MirTypeckRegionConstraints, MirTypeckResults};
|
||||
|
||||
use crate::borrow_set::{BorrowData, BorrowSet};
|
||||
use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
|
||||
use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions, RustcFacts};
|
||||
use crate::dataflow::{BorrowIndex, Borrowck, BorrowckDomain, Borrows};
|
||||
use crate::diagnostics::{
|
||||
AccessKind, BorrowckDiagnosticsBuffer, IllegalMoveOriginKind, MoveError, RegionName,
|
||||
@ -63,8 +71,10 @@ use crate::diagnostics::{
|
||||
use crate::path_utils::*;
|
||||
use crate::place_ext::PlaceExt;
|
||||
use crate::places_conflict::{PlaceConflictBias, places_conflict};
|
||||
use crate::polonius::PoloniusDiagnosticsContext;
|
||||
use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
|
||||
use crate::polonius::legacy::{
|
||||
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
||||
};
|
||||
use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext};
|
||||
use crate::prefixes::PrefixSet;
|
||||
use crate::region_infer::RegionInferenceContext;
|
||||
use crate::renumber::RegionCtxt;
|
||||
@ -126,12 +136,8 @@ fn mir_borrowck(
|
||||
let opaque_types = ConcreteOpaqueTypes(Default::default());
|
||||
Ok(tcx.arena.alloc(opaque_types))
|
||||
} else {
|
||||
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def);
|
||||
let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
|
||||
do_mir_borrowck(&mut root_cx, def, None).0;
|
||||
debug_assert!(closure_requirements.is_none());
|
||||
debug_assert!(used_mut_upvars.is_empty());
|
||||
root_cx.finalize()
|
||||
let root_cx = BorrowCheckRootCtxt::new(tcx, def);
|
||||
root_cx.borrowck_root(None).0
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,6 +149,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
|
||||
@ -281,6 +289,24 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
struct BorrowckState<'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>,
|
||||
}
|
||||
|
||||
/// Perform the actual borrow checking.
|
||||
///
|
||||
/// Use `consumer_options: None` for the default behavior of returning
|
||||
@ -289,11 +315,11 @@ impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
|
||||
///
|
||||
/// 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>(
|
||||
fn start_do_mir_borrowck<'tcx>(
|
||||
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
|
||||
def: LocalDefId,
|
||||
consumer_options: Option<ConsumerOptions>,
|
||||
) -> (PropagatedBorrowCheckResults<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
|
||||
) -> BorrowckState<'tcx> {
|
||||
let tcx = root_cx.tcx;
|
||||
let infcx = BorrowckInferCtxt::new(tcx, def);
|
||||
let (input_body, promoted) = tcx.mir_promoted(def);
|
||||
@ -314,6 +340,7 @@ fn do_mir_borrowck<'tcx>(
|
||||
let body = &body_owned; // no further changes
|
||||
|
||||
let location_table = PoloniusLocationTable::new(body);
|
||||
let location_map = Rc::new(DenseLocationMap::new(body));
|
||||
|
||||
let move_data = MoveData::gather_moves(body, tcx, |_| true);
|
||||
|
||||
@ -324,6 +351,80 @@ fn do_mir_borrowck<'tcx>(
|
||||
let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure();
|
||||
let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
|
||||
|
||||
let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
|
||||
let polonius_input = consumer_options.map(|c| c.polonius_input()).unwrap_or_default()
|
||||
|| is_polonius_legacy_enabled;
|
||||
let mut polonius_facts =
|
||||
(polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
|
||||
|
||||
// Run the MIR type-checker.
|
||||
let MirTypeckResults {
|
||||
constraints,
|
||||
universal_region_relations,
|
||||
region_bound_pairs,
|
||||
known_type_outlives_obligations,
|
||||
deferred_closure_requirements,
|
||||
polonius_context,
|
||||
} = type_check::type_check(
|
||||
root_cx,
|
||||
&infcx,
|
||||
&body,
|
||||
&promoted,
|
||||
universal_regions,
|
||||
&location_table,
|
||||
&borrow_set,
|
||||
&mut polonius_facts,
|
||||
flow_inits,
|
||||
&move_data,
|
||||
Rc::clone(&location_map),
|
||||
);
|
||||
|
||||
BorrowckState {
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
fn resume_do_mir_borrowck<'tcx>(
|
||||
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
|
||||
consumer_options: Option<ConsumerOptions>,
|
||||
BorrowckState {
|
||||
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,
|
||||
}: BorrowckState<'tcx>,
|
||||
) -> (PropagatedBorrowCheckResults<'tcx>, Option<Box<BodyWithBorrowckFacts<'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.
|
||||
let nll::NllOutput {
|
||||
regioncx,
|
||||
@ -333,18 +434,23 @@ fn do_mir_borrowck<'tcx>(
|
||||
nll_errors,
|
||||
polonius_diagnostics,
|
||||
} = nll::compute_regions(
|
||||
root_cx,
|
||||
&infcx,
|
||||
universal_regions,
|
||||
body,
|
||||
&promoted,
|
||||
&location_table,
|
||||
flow_inits,
|
||||
&move_data,
|
||||
&borrow_set,
|
||||
location_map,
|
||||
consumer_options,
|
||||
universal_region_relations,
|
||||
constraints,
|
||||
polonius_facts,
|
||||
polonius_context,
|
||||
);
|
||||
|
||||
if nll_errors.has_errors().is_none() && !deferred_opaque_type_errors.is_empty() {
|
||||
regioncx.emit_deferred_opaque_type_errors(root_cx, &infcx, deferred_opaque_type_errors);
|
||||
}
|
||||
|
||||
// Dump MIR results into a file, if that is enabled. This lets us
|
||||
// write unit-tests, as well as helping with debugging.
|
||||
nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
|
||||
|
@ -5,14 +5,13 @@ use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
|
||||
use polonius_engine::{Algorithm, Output};
|
||||
use polonius_engine::{Algorithm, AllFacts, Output};
|
||||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options};
|
||||
use rustc_middle::mir::{Body, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_mir_dataflow::ResultsCursor;
|
||||
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
|
||||
use rustc_mir_dataflow::move_paths::MoveData;
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_session::config::MirIncludeSpans;
|
||||
@ -20,19 +19,19 @@ use rustc_span::sym;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::consumers::ConsumerOptions;
|
||||
use crate::consumers::{ConsumerOptions, RustcFacts};
|
||||
use crate::diagnostics::RegionErrors;
|
||||
use crate::polonius::PoloniusDiagnosticsContext;
|
||||
use crate::polonius::legacy::{
|
||||
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
||||
};
|
||||
use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext};
|
||||
use crate::region_infer::RegionInferenceContext;
|
||||
use crate::region_infer::opaque_types::handle_opaque_type_uses;
|
||||
use crate::type_check::{self, MirTypeckResults};
|
||||
use crate::type_check::MirTypeckRegionConstraints;
|
||||
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
use crate::{
|
||||
BorrowCheckRootCtxt, BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements,
|
||||
polonius, renumber,
|
||||
BorrowckInferCtxt, BorrowckState, ClosureOutlivesSubject, ClosureRegionRequirements, polonius,
|
||||
renumber,
|
||||
};
|
||||
|
||||
/// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any
|
||||
@ -73,55 +72,47 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
|
||||
universal_regions
|
||||
}
|
||||
|
||||
/// Computes the (non-lexical) regions from the input MIR.
|
||||
pub(crate) fn compute_closure_requirements_modulo_opaques<'tcx>(
|
||||
partial_result: &BorrowckState<'tcx>,
|
||||
) -> Option<ClosureRegionRequirements<'tcx>> {
|
||||
let BorrowckState {
|
||||
infcx,
|
||||
body_owned,
|
||||
location_map,
|
||||
universal_region_relations,
|
||||
constraints,
|
||||
..
|
||||
} = partial_result;
|
||||
|
||||
let mut regioncx = RegionInferenceContext::new(
|
||||
&infcx,
|
||||
constraints.clone(),
|
||||
universal_region_relations.clone(),
|
||||
location_map.clone(),
|
||||
);
|
||||
let (closure_region_requirements, _nll_errors) = regioncx.solve(infcx, &body_owned, None);
|
||||
closure_region_requirements
|
||||
}
|
||||
|
||||
/// Computes and checks the region graph for the given constraints.
|
||||
///
|
||||
/// This may result in errors being reported.
|
||||
pub(crate) fn compute_regions<'a, 'tcx>(
|
||||
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
|
||||
pub(crate) fn compute_regions<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||
location_table: &PoloniusLocationTable,
|
||||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
consumer_options: Option<ConsumerOptions>,
|
||||
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
mut polonius_facts: Option<AllFacts<RustcFacts>>,
|
||||
polonius_context: Option<PoloniusContext>,
|
||||
) -> NllOutput<'tcx> {
|
||||
let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
|
||||
let polonius_input = consumer_options.map(|c| c.polonius_input()).unwrap_or_default()
|
||||
|| is_polonius_legacy_enabled;
|
||||
let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default()
|
||||
|| is_polonius_legacy_enabled;
|
||||
let mut polonius_facts =
|
||||
(polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
|
||||
|
||||
let location_map = Rc::new(DenseLocationMap::new(body));
|
||||
|
||||
// Run the MIR type-checker.
|
||||
let MirTypeckResults { constraints, universal_region_relations, polonius_context } =
|
||||
type_check::type_check(
|
||||
root_cx,
|
||||
infcx,
|
||||
body,
|
||||
promoted,
|
||||
universal_regions,
|
||||
location_table,
|
||||
borrow_set,
|
||||
&mut polonius_facts,
|
||||
flow_inits,
|
||||
move_data,
|
||||
Rc::clone(&location_map),
|
||||
);
|
||||
|
||||
let (constraints, deferred_opaque_type_errors) = handle_opaque_type_uses(
|
||||
root_cx,
|
||||
infcx,
|
||||
constraints,
|
||||
&universal_region_relations,
|
||||
Rc::clone(&location_map),
|
||||
);
|
||||
|
||||
// If requested, emit legacy polonius facts.
|
||||
polonius::legacy::emit_facts(
|
||||
&mut polonius_facts,
|
||||
@ -169,10 +160,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
||||
regioncx.solve(infcx, body, polonius_output.clone());
|
||||
|
||||
if let Some(guar) = nll_errors.has_errors() {
|
||||
// Suppress unhelpful extra errors in `infer_opaque_types`.
|
||||
infcx.set_tainted_by_errors(guar);
|
||||
} else if !deferred_opaque_type_errors.is_empty() {
|
||||
regioncx.emit_deferred_opaque_type_errors(root_cx, infcx, deferred_opaque_type_errors);
|
||||
}
|
||||
|
||||
NllOutput {
|
||||
|
@ -31,7 +31,7 @@ use crate::consumers::OutlivesConstraint;
|
||||
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
||||
use crate::type_check::{Locations, MirTypeckRegionConstraints};
|
||||
use crate::universal_regions::{RegionClassification, UniversalRegions};
|
||||
use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt};
|
||||
use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt, BorrowckState};
|
||||
|
||||
pub(crate) enum DeferredOpaqueTypeError<'tcx> {
|
||||
UnexpectedHiddenRegion {
|
||||
@ -45,16 +45,39 @@ pub(crate) enum DeferredOpaqueTypeError<'tcx> {
|
||||
InvalidOpaqueTypeArgs(InvalidOpaqueTypeArgs<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
||||
pub(crate) fn handle_opaque_type_uses(&mut self, borrowck_state: &mut BorrowckState<'tcx>) {
|
||||
let BorrowckState {
|
||||
infcx,
|
||||
constraints,
|
||||
universal_region_relations,
|
||||
location_map,
|
||||
deferred_opaque_type_errors,
|
||||
..
|
||||
} = borrowck_state;
|
||||
|
||||
handle_opaque_type_uses(
|
||||
self,
|
||||
infcx,
|
||||
constraints,
|
||||
deferred_opaque_type_errors,
|
||||
universal_region_relations,
|
||||
Rc::clone(location_map),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn handle_opaque_type_uses<'tcx>(
|
||||
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
mut constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
deferred_errors: &mut Vec<DeferredOpaqueTypeError<'tcx>>,
|
||||
universal_region_relations: &Frozen<UniversalRegionRelations<'tcx>>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
) -> (MirTypeckRegionConstraints<'tcx>, Vec<DeferredOpaqueTypeError<'tcx>>) {
|
||||
) {
|
||||
let opaque_types = infcx.take_opaque_types();
|
||||
if opaque_types.is_empty() {
|
||||
return (constraints, Vec::new());
|
||||
return;
|
||||
}
|
||||
|
||||
let tcx = infcx.tcx;
|
||||
@ -116,8 +139,6 @@ pub(crate) fn handle_opaque_type_uses<'tcx>(
|
||||
})
|
||||
}
|
||||
|
||||
let mut deferred_errors = Vec::new();
|
||||
|
||||
// We start by looking for defining uses of the opaque. These are uses where all arguments
|
||||
// of the opaque are free regions. We apply "member constraints" to its hidden region and
|
||||
// map the hidden type to the definition site of the opaque.
|
||||
@ -157,7 +178,7 @@ pub(crate) fn handle_opaque_type_uses<'tcx>(
|
||||
|
||||
opaque_type_key,
|
||||
hidden_type,
|
||||
deferred_errors: &mut deferred_errors,
|
||||
deferred_errors,
|
||||
|
||||
arg_regions: &arg_regions,
|
||||
universal_region_relations,
|
||||
@ -177,7 +198,6 @@ pub(crate) fn handle_opaque_type_uses<'tcx>(
|
||||
)
|
||||
});
|
||||
|
||||
// TODO this doesn't seem to help
|
||||
if !tcx.use_typing_mode_borrowck() {
|
||||
if let ty::Alias(ty::Opaque, alias_ty) = ty.kind()
|
||||
&& alias_ty.def_id == opaque_type_key.def_id.to_def_id()
|
||||
@ -220,12 +240,8 @@ pub(crate) fn handle_opaque_type_uses<'tcx>(
|
||||
}
|
||||
});
|
||||
|
||||
let mut relation = EquateRegions {
|
||||
infcx,
|
||||
span: hidden_type.span,
|
||||
universal_regions,
|
||||
constraints: &mut constraints,
|
||||
};
|
||||
let mut relation =
|
||||
EquateRegions { infcx, span: hidden_type.span, universal_regions, constraints };
|
||||
match TypeRelation::relate(&mut relation, hidden_type.ty, expected.ty) {
|
||||
Ok(_) => {}
|
||||
Err(_) => {
|
||||
@ -245,8 +261,6 @@ pub(crate) fn handle_opaque_type_uses<'tcx>(
|
||||
// without it we could manually walk over the types using a type relation and equate region vars
|
||||
// that way.
|
||||
}
|
||||
|
||||
(constraints, deferred_errors)
|
||||
}
|
||||
|
||||
fn to_region_vid<'tcx>(
|
||||
|
@ -39,6 +39,7 @@ pub(crate) enum RegionElement {
|
||||
|
||||
/// Records the CFG locations where each region is live. When we initially compute liveness, we use
|
||||
/// an interval matrix storing liveness ranges for each region-vid.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct LivenessValues {
|
||||
/// The map from locations to points.
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
@ -195,7 +196,7 @@ impl LivenessValues {
|
||||
/// Maps from `ty::PlaceholderRegion` values that are used in the rest of
|
||||
/// rustc to the internal `PlaceholderIndex` values that are used in
|
||||
/// NLL.
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub(crate) struct PlaceholderIndices {
|
||||
indices: FxIndexSet<ty::PlaceholderRegion>,
|
||||
}
|
||||
|
@ -6,7 +6,13 @@ use rustc_middle::ty::{EarlyBinder, OpaqueHiddenType, Ty, TyCtxt, TypeVisitableE
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{ClosureRegionRequirements, ConcreteOpaqueTypes, PropagatedBorrowCheckResults};
|
||||
use crate::consumers::{BodyWithBorrowckFacts, ConsumerOptions};
|
||||
use crate::nll::compute_closure_requirements_modulo_opaques;
|
||||
use crate::type_check::apply_closure_requirements_considering_opaques;
|
||||
use crate::{
|
||||
BorrowckState, ClosureRegionRequirements, ConcreteOpaqueTypes, PropagatedBorrowCheckResults,
|
||||
resume_do_mir_borrowck, start_do_mir_borrowck,
|
||||
};
|
||||
|
||||
/// The shared context used by both the root as well as all its nested
|
||||
/// items.
|
||||
@ -14,7 +20,10 @@ pub(super) struct BorrowCheckRootCtxt<'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
root_def_id: LocalDefId,
|
||||
concrete_opaque_types: ConcreteOpaqueTypes<'tcx>,
|
||||
nested_bodies: FxHashMap<LocalDefId, PropagatedBorrowCheckResults<'tcx>>,
|
||||
partial_results: FxHashMap<LocalDefId, Option<BorrowckState<'tcx>>>,
|
||||
closure_requirements_modulo_opaques:
|
||||
FxHashMap<LocalDefId, Option<ClosureRegionRequirements<'tcx>>>,
|
||||
final_results: FxHashMap<LocalDefId, PropagatedBorrowCheckResults<'tcx>>,
|
||||
tainted_by_errors: Option<ErrorGuaranteed>,
|
||||
}
|
||||
|
||||
@ -24,7 +33,9 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
||||
tcx,
|
||||
root_def_id,
|
||||
concrete_opaque_types: Default::default(),
|
||||
nested_bodies: Default::default(),
|
||||
partial_results: Default::default(),
|
||||
closure_requirements_modulo_opaques: Default::default(),
|
||||
final_results: Default::default(),
|
||||
tainted_by_errors: None,
|
||||
}
|
||||
}
|
||||
@ -73,40 +84,121 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
||||
self.tainted_by_errors = Some(guar);
|
||||
}
|
||||
|
||||
fn get_or_insert_nested(&mut self, def_id: LocalDefId) -> &PropagatedBorrowCheckResults<'tcx> {
|
||||
fn compute_partial_results(&mut self, def_id: LocalDefId) {
|
||||
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) {
|
||||
if !self.partial_results.contains_key(&def_id) {
|
||||
let result = start_do_mir_borrowck(self, def_id, None);
|
||||
// We only need to store the partial result if it depends on opaque types
|
||||
// or depends on a nested item which does.
|
||||
let relies_on_opaques = result.infcx.has_opaque_types_in_storage()
|
||||
|| !result.deferred_closure_requirements.is_empty();
|
||||
|
||||
let to_insert = if !relies_on_opaques {
|
||||
let final_result = resume_do_mir_borrowck(self, None, result).0;
|
||||
if self.final_results.insert(def_id, final_result).is_some() {
|
||||
bug!("unexpected previous final result for {def_id:?}");
|
||||
}
|
||||
None
|
||||
} else {
|
||||
Some(result)
|
||||
};
|
||||
|
||||
if self.partial_results.insert(def_id, to_insert).is_some() {
|
||||
bug!("unexpected previous partial result for: {def_id:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_or_insert_final(&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.final_results.contains_key(&def_id) {
|
||||
let mut yield_do_mir_borrowck = self.partial_results.remove(&def_id).unwrap().unwrap();
|
||||
self.handle_opaque_type_uses(&mut yield_do_mir_borrowck);
|
||||
apply_closure_requirements_considering_opaques(self, &mut yield_do_mir_borrowck);
|
||||
let result = resume_do_mir_borrowck(self, None, yield_do_mir_borrowck).0;
|
||||
if let Some(prev) = self.final_results.insert(def_id, result) {
|
||||
bug!("unexpected previous nested body: {prev:?}");
|
||||
}
|
||||
}
|
||||
|
||||
self.nested_bodies.get(&def_id).unwrap()
|
||||
self.final_results.get(&def_id).unwrap()
|
||||
}
|
||||
|
||||
pub(super) fn closure_requirements(
|
||||
pub(crate) fn get_closure_requirements_considering_regions(
|
||||
&mut self,
|
||||
nested_body_def_id: LocalDefId,
|
||||
def_id: LocalDefId,
|
||||
) -> &Option<ClosureRegionRequirements<'tcx>> {
|
||||
&self.get_or_insert_nested(nested_body_def_id).closure_requirements
|
||||
&self.get_or_insert_final(def_id).closure_requirements
|
||||
}
|
||||
|
||||
/// Get the closure requirements of the nested body `def_id`. In case
|
||||
/// this nested body relies on opaques, checking that the hidden type
|
||||
/// matches the final definition may introduce new region constraints
|
||||
/// we aren't considering yet.
|
||||
///
|
||||
/// In these cases, we need to later add these requirements again, including
|
||||
/// the constraints from opaque types.
|
||||
pub(crate) fn get_closure_requirements_modulo_opaques(
|
||||
&mut self,
|
||||
def_id: LocalDefId,
|
||||
) -> (&Option<ClosureRegionRequirements<'tcx>>, bool) {
|
||||
self.compute_partial_results(def_id);
|
||||
// In case the nested item does not use any opaque types or depend on nested items
|
||||
// which do, we eagerly compute its final result to avoid duplicate work.
|
||||
if let Some(final_result) = self.final_results.get(&def_id) {
|
||||
(&final_result.closure_requirements, false)
|
||||
} else if self.closure_requirements_modulo_opaques.contains_key(&def_id) {
|
||||
(self.closure_requirements_modulo_opaques.get(&def_id).unwrap(), true)
|
||||
} else {
|
||||
let partial_result = self.partial_results.get(&def_id).unwrap().as_ref().unwrap();
|
||||
let modulo_opaques = compute_closure_requirements_modulo_opaques(partial_result);
|
||||
self.closure_requirements_modulo_opaques.insert(def_id, modulo_opaques);
|
||||
(self.closure_requirements_modulo_opaques.get(&def_id).unwrap(), true)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
&self.get_or_insert_final(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 {
|
||||
/// The actual borrowck routine. This should only be called for the typeck root,
|
||||
/// not for any nested bodies.
|
||||
pub(super) fn borrowck_root(
|
||||
mut self,
|
||||
consumer_options: Option<ConsumerOptions>,
|
||||
) -> (
|
||||
Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed>,
|
||||
Option<Box<BodyWithBorrowckFacts<'tcx>>>,
|
||||
) {
|
||||
let root_def_id = self.root_def_id;
|
||||
let mut yield_do_mir_borrowck =
|
||||
start_do_mir_borrowck(&mut self, root_def_id, consumer_options);
|
||||
|
||||
self.handle_opaque_type_uses(&mut yield_do_mir_borrowck);
|
||||
apply_closure_requirements_considering_opaques(&mut self, &mut yield_do_mir_borrowck);
|
||||
let (PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars }, consumer_data) =
|
||||
resume_do_mir_borrowck(&mut self, consumer_options, yield_do_mir_borrowck);
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
if cfg!(debug_assertions) {
|
||||
assert!(closure_requirements.is_none());
|
||||
assert!(used_mut_upvars.is_empty());
|
||||
assert!(self.partial_results.values().all(|entry| entry.is_none()));
|
||||
}
|
||||
|
||||
let result = if let Some(guar) = self.tainted_by_errors {
|
||||
Err(guar)
|
||||
} else {
|
||||
Ok(self.tcx.arena.alloc(self.concrete_opaque_types))
|
||||
}
|
||||
Ok(&*self.tcx.arena.alloc(self.concrete_opaque_types))
|
||||
};
|
||||
(result, consumer_data)
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ use type_op::TypeOpOutput;
|
||||
use crate::type_check::{Locations, MirTypeckRegionConstraints, constraint_conversion};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct UniversalRegionRelations<'tcx> {
|
||||
pub(crate) universal_regions: UniversalRegions<'tcx>,
|
||||
|
||||
@ -41,8 +41,8 @@ type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
|
||||
|
||||
pub(crate) struct CreateResult<'tcx> {
|
||||
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||
pub(crate) known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
|
||||
pub(crate) region_bound_pairs: Frozen<RegionBoundPairs<'tcx>>,
|
||||
pub(crate) known_type_outlives_obligations: Frozen<Vec<ty::PolyTypeOutlivesPredicate<'tcx>>>,
|
||||
pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
|
||||
}
|
||||
|
||||
@ -326,8 +326,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
||||
outlives: self.outlives.freeze(),
|
||||
inverse_outlives: self.inverse_outlives.freeze(),
|
||||
}),
|
||||
known_type_outlives_obligations,
|
||||
region_bound_pairs: self.region_bound_pairs,
|
||||
known_type_outlives_obligations: Frozen::freeze(known_type_outlives_obligations),
|
||||
region_bound_pairs: Frozen::freeze(self.region_bound_pairs),
|
||||
normalized_inputs_and_output,
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,9 @@ use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderI
|
||||
use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
|
||||
use crate::type_check::free_region_relations::{CreateResult, UniversalRegionRelations};
|
||||
use crate::universal_regions::{DefiningTy, UniversalRegions};
|
||||
use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt, path_utils};
|
||||
use crate::{
|
||||
BorrowCheckRootCtxt, BorrowckInferCtxt, BorrowckState, DeferredClosureRequirements, path_utils,
|
||||
};
|
||||
|
||||
macro_rules! span_mirbug {
|
||||
($context:expr, $elem:expr, $($message:tt)*) => ({
|
||||
@ -148,14 +150,15 @@ pub(crate) fn type_check<'a, 'tcx>(
|
||||
body,
|
||||
promoted,
|
||||
user_type_annotations: &body.user_type_annotations,
|
||||
region_bound_pairs,
|
||||
known_type_outlives_obligations,
|
||||
region_bound_pairs: ®ion_bound_pairs,
|
||||
known_type_outlives_obligations: &known_type_outlives_obligations,
|
||||
reported_errors: Default::default(),
|
||||
universal_regions: &universal_region_relations.universal_regions,
|
||||
location_table,
|
||||
polonius_facts,
|
||||
borrow_set,
|
||||
constraints: &mut constraints,
|
||||
deferred_closure_requirements: Default::default(),
|
||||
polonius_liveness,
|
||||
};
|
||||
|
||||
@ -178,7 +181,15 @@ pub(crate) fn type_check<'a, 'tcx>(
|
||||
)
|
||||
});
|
||||
|
||||
MirTypeckResults { constraints, universal_region_relations, polonius_context }
|
||||
let deferred_closure_requirements = typeck.deferred_closure_requirements;
|
||||
MirTypeckResults {
|
||||
constraints,
|
||||
universal_region_relations,
|
||||
region_bound_pairs,
|
||||
known_type_outlives_obligations,
|
||||
deferred_closure_requirements,
|
||||
polonius_context,
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
@ -208,14 +219,15 @@ struct TypeChecker<'a, 'tcx> {
|
||||
/// User type annotations are shared between the main MIR and the MIR of
|
||||
/// all of the promoted items.
|
||||
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
|
||||
region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||
known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
known_type_outlives_obligations: &'a Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
|
||||
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
polonius_facts: &'a mut Option<PoloniusFacts>,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||
deferred_closure_requirements: DeferredClosureRequirements<'tcx>,
|
||||
/// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints.
|
||||
polonius_liveness: Option<PoloniusLivenessContext>,
|
||||
}
|
||||
@ -225,11 +237,15 @@ struct TypeChecker<'a, 'tcx> {
|
||||
pub(crate) struct MirTypeckResults<'tcx> {
|
||||
pub(crate) constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
pub(crate) region_bound_pairs: Frozen<RegionBoundPairs<'tcx>>,
|
||||
pub(crate) known_type_outlives_obligations: Frozen<Vec<ty::PolyTypeOutlivesPredicate<'tcx>>>,
|
||||
pub(crate) deferred_closure_requirements: DeferredClosureRequirements<'tcx>,
|
||||
pub(crate) polonius_context: Option<PoloniusContext>,
|
||||
}
|
||||
|
||||
/// A collection of region constraints that must be satisfied for the
|
||||
/// program to be considered well-typed.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct MirTypeckRegionConstraints<'tcx> {
|
||||
/// Maps from a `ty::Placeholder` to the corresponding
|
||||
/// `PlaceholderIndex` bit that we will use for it.
|
||||
@ -2483,7 +2499,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
args: GenericArgsRef<'tcx>,
|
||||
locations: Locations,
|
||||
) -> ty::InstantiatedPredicates<'tcx> {
|
||||
if let Some(closure_requirements) = &self.root_cx.closure_requirements(def_id) {
|
||||
let (closure_requirements, needs_defer) =
|
||||
self.root_cx.get_closure_requirements_modulo_opaques(def_id);
|
||||
if needs_defer {
|
||||
self.deferred_closure_requirements.push((def_id, args, locations));
|
||||
}
|
||||
|
||||
if let Some(closure_requirements) = closure_requirements {
|
||||
constraint_conversion::ConstraintConversion::new(
|
||||
self.infcx,
|
||||
self.universal_regions,
|
||||
@ -2537,6 +2559,41 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn apply_closure_requirements_considering_opaques<'tcx>(
|
||||
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
|
||||
borrowck_state: &mut BorrowckState<'tcx>,
|
||||
) {
|
||||
let BorrowckState {
|
||||
infcx,
|
||||
body_owned,
|
||||
universal_region_relations,
|
||||
region_bound_pairs,
|
||||
known_type_outlives_obligations,
|
||||
constraints,
|
||||
deferred_closure_requirements,
|
||||
..
|
||||
} = borrowck_state;
|
||||
|
||||
for (def_id, args, locations) in mem::take(deferred_closure_requirements).into_iter() {
|
||||
if let Some(closure_requirements) =
|
||||
root_cx.get_closure_requirements_considering_regions(def_id)
|
||||
{
|
||||
constraint_conversion::ConstraintConversion::new(
|
||||
infcx,
|
||||
&universal_region_relations.universal_regions,
|
||||
region_bound_pairs,
|
||||
infcx.param_env,
|
||||
known_type_outlives_obligations,
|
||||
locations,
|
||||
body_owned.span, // irrelevant; will be overridden.
|
||||
ConstraintCategory::Boring, // same as above.
|
||||
constraints,
|
||||
)
|
||||
.apply_closure_requirements(closure_requirements, def_id, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait NormalizeLocation: fmt::Debug + Copy {
|
||||
fn to_locations(self) -> Locations;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ use tracing::{debug, instrument};
|
||||
use crate::BorrowckInferCtxt;
|
||||
use crate::renumber::RegionCtxt;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct UniversalRegions<'tcx> {
|
||||
indices: UniversalRegionIndices<'tcx>,
|
||||
|
||||
@ -199,7 +199,7 @@ impl<'tcx> DefiningTy<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
struct UniversalRegionIndices<'tcx> {
|
||||
/// For those regions that may appear in the parameter environment
|
||||
/// ('static and early-bound regions), we maintain a map from the
|
||||
|
@ -46,7 +46,7 @@
|
||||
//! Frozen::freeze(new_bar)`).
|
||||
|
||||
/// An owned immutable value.
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Frozen<T>(T);
|
||||
|
||||
impl<T> Frozen<T> {
|
||||
|
@ -953,6 +953,10 @@ impl<'tcx> InferCtxt<'tcx> {
|
||||
storage.var_infos.clone()
|
||||
}
|
||||
|
||||
pub fn has_opaque_types_in_storage(&self) -> bool {
|
||||
!self.inner.borrow().opaque_type_storage.opaque_types.is_empty()
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub fn take_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
|
||||
std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
|
||||
|
Loading…
Reference in New Issue
Block a user