1
Fork 0

introduce polonius context

This context struct will hold data to help creating localized
constraints:
- the live regions, with the shape matching a CFG walk, indexed per
  point
- the variance of these live regions, represented as the direction we'll
  add the appropriate

We also add this structure to the mir typeck to record liveness data,
and make it responsible for localized constraint creation.
This commit is contained in:
Rémy Rakic 2024-12-22 22:09:44 +00:00
parent 64feb9b502
commit 42f28cbae6
3 changed files with 102 additions and 45 deletions

View file

@ -100,19 +100,23 @@ pub(crate) fn compute_regions<'a, 'tcx>(
let elements = Rc::new(DenseLocationMap::new(body)); let elements = Rc::new(DenseLocationMap::new(body));
// Run the MIR type-checker. // Run the MIR type-checker.
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } = let MirTypeckResults {
type_check::type_check( constraints,
infcx, universal_region_relations,
body, opaque_type_values,
promoted, mut polonius_context,
universal_regions, } = type_check::type_check(
location_table, infcx,
borrow_set, body,
&mut all_facts, promoted,
flow_inits, universal_regions,
move_data, location_table,
Rc::clone(&elements), borrow_set,
); &mut all_facts,
flow_inits,
move_data,
Rc::clone(&elements),
);
// Create the region inference context, taking ownership of the // Create the region inference context, taking ownership of the
// region inference data that was contained in `infcx`, and the // region inference data that was contained in `infcx`, and the
@ -141,12 +145,9 @@ pub(crate) fn compute_regions<'a, 'tcx>(
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives // If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives
// constraints. // constraints.
let localized_outlives_constraints = let localized_outlives_constraints = polonius_context
if infcx.tcx.sess.opts.unstable_opts.polonius.is_next_enabled() { .as_mut()
Some(polonius::create_localized_constraints(&mut regioncx, body)) .map(|polonius_context| polonius_context.create_localized_constraints(&mut regioncx, body));
} else {
None
};
// If requested: dump NLL facts, and run legacy polonius analysis. // If requested: dump NLL facts, and run legacy polonius analysis.
let polonius_output = all_facts.as_ref().and_then(|all_facts| { let polonius_output = all_facts.as_ref().and_then(|all_facts| {

View file

@ -34,45 +34,84 @@
//! //!
mod constraints; mod constraints;
pub(crate) use constraints::*;
mod dump; mod dump;
pub(crate) use dump::dump_polonius_mir;
pub(crate) mod legacy; pub(crate) mod legacy;
use std::collections::BTreeMap;
use rustc_index::bit_set::SparseBitMatrix;
use rustc_middle::mir::{Body, Location}; use rustc_middle::mir::{Body, Location};
use rustc_middle::ty::RegionVid;
use rustc_mir_dataflow::points::PointIndex; use rustc_mir_dataflow::points::PointIndex;
pub(crate) use self::constraints::*;
pub(crate) use self::dump::dump_polonius_mir;
use crate::RegionInferenceContext; use crate::RegionInferenceContext;
use crate::constraints::OutlivesConstraint; use crate::constraints::OutlivesConstraint;
use crate::region_infer::values::LivenessValues; use crate::region_infer::values::LivenessValues;
use crate::type_check::Locations; use crate::type_check::Locations;
use crate::universal_regions::UniversalRegions; use crate::universal_regions::UniversalRegions;
/// Creates a constraint set for `-Zpolonius=next` by: /// This struct holds the data needed to create the Polonius localized constraints.
/// - converting NLL typeck constraints to be localized pub(crate) struct PoloniusContext {
/// - encoding liveness constraints /// The set of regions that are live at a given point in the CFG, used to create localized
pub(crate) fn create_localized_constraints<'tcx>( /// outlives constraints between regions that are live at connected points in the CFG.
regioncx: &mut RegionInferenceContext<'tcx>, live_regions: SparseBitMatrix<PointIndex, RegionVid>,
body: &Body<'tcx>,
) -> LocalizedOutlivesConstraintSet {
let mut localized_outlives_constraints = LocalizedOutlivesConstraintSet::default();
convert_typeck_constraints(
body,
regioncx.liveness_constraints(),
regioncx.outlives_constraints(),
&mut localized_outlives_constraints,
);
create_liveness_constraints(
body,
regioncx.liveness_constraints(),
regioncx.universal_regions(),
&mut localized_outlives_constraints,
);
// FIXME: here, we can trace loan reachability in the constraint graph and record this as loan /// The expected edge direction per live region: the kind of directed edge we'll create as
// liveness for the next step in the chain, the NLL loan scope and active loans computations. /// liveness constraints depends on the variance of types with respect to each contained region.
live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
}
localized_outlives_constraints /// The direction a constraint can flow into. Used to create liveness constraints according to
/// variance.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum ConstraintDirection {
/// For covariant cases, we add a forward edge `O at P1 -> O at P2`.
Forward,
/// For contravariant cases, we add a backward edge `O at P2 -> O at P1`
Backward,
/// For invariant cases, we add both the forward and backward edges `O at P1 <-> O at P2`.
Bidirectional,
}
impl PoloniusContext {
pub(crate) fn new(num_regions: usize) -> PoloniusContext {
Self {
live_region_variances: BTreeMap::new(),
live_regions: SparseBitMatrix::new(num_regions),
}
}
/// Creates a constraint set for `-Zpolonius=next` by:
/// - converting NLL typeck constraints to be localized
/// - encoding liveness constraints
pub(crate) fn create_localized_constraints<'tcx>(
&self,
regioncx: &RegionInferenceContext<'tcx>,
body: &Body<'tcx>,
) -> LocalizedOutlivesConstraintSet {
let mut localized_outlives_constraints = LocalizedOutlivesConstraintSet::default();
convert_typeck_constraints(
body,
regioncx.liveness_constraints(),
regioncx.outlives_constraints(),
&mut localized_outlives_constraints,
);
create_liveness_constraints(
body,
regioncx.liveness_constraints(),
regioncx.universal_regions(),
&mut localized_outlives_constraints,
);
// FIXME: here, we can trace loan reachability in the constraint graph and record this as loan
// liveness for the next step in the chain, the NLL loan scope and active loans computations.
localized_outlives_constraints
}
} }
/// Propagate loans throughout the subset graph at a given point (with some subtleties around the /// Propagate loans throughout the subset graph at a given point (with some subtleties around the

View file

@ -50,6 +50,7 @@ use crate::diagnostics::UniverseInfo;
use crate::facts::AllFacts; use crate::facts::AllFacts;
use crate::location::LocationTable; use crate::location::LocationTable;
use crate::member_constraints::MemberConstraintSet; use crate::member_constraints::MemberConstraintSet;
use crate::polonius::PoloniusContext;
use crate::region_infer::TypeTest; use crate::region_infer::TypeTest;
use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices}; use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices};
use crate::renumber::RegionCtxt; use crate::renumber::RegionCtxt;
@ -148,6 +149,13 @@ pub(crate) fn type_check<'a, 'tcx>(
debug!(?normalized_inputs_and_output); debug!(?normalized_inputs_and_output);
let mut polonius_context = if infcx.tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
let num_regions = infcx.num_region_vars();
Some(PoloniusContext::new(num_regions))
} else {
None
};
let mut typeck = TypeChecker { let mut typeck = TypeChecker {
infcx, infcx,
last_span: body.span, last_span: body.span,
@ -162,6 +170,7 @@ pub(crate) fn type_check<'a, 'tcx>(
all_facts, all_facts,
borrow_set, borrow_set,
constraints: &mut constraints, constraints: &mut constraints,
polonius_context: &mut polonius_context,
}; };
typeck.check_user_type_annotations(); typeck.check_user_type_annotations();
@ -178,7 +187,12 @@ pub(crate) fn type_check<'a, 'tcx>(
let opaque_type_values = let opaque_type_values =
opaque_types::take_opaques_and_register_member_constraints(&mut typeck); opaque_types::take_opaques_and_register_member_constraints(&mut typeck);
MirTypeckResults { constraints, universal_region_relations, opaque_type_values } MirTypeckResults {
constraints,
universal_region_relations,
opaque_type_values,
polonius_context,
}
} }
#[track_caller] #[track_caller]
@ -546,6 +560,8 @@ struct TypeChecker<'a, 'tcx> {
all_facts: &'a mut Option<AllFacts>, all_facts: &'a mut Option<AllFacts>,
borrow_set: &'a BorrowSet<'tcx>, borrow_set: &'a BorrowSet<'tcx>,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
/// When using `-Zpolonius=next`, the helper data used to create polonius constraints.
polonius_context: &'a mut Option<PoloniusContext>,
} }
/// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions /// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions
@ -554,6 +570,7 @@ pub(crate) struct MirTypeckResults<'tcx> {
pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, pub(crate) constraints: MirTypeckRegionConstraints<'tcx>,
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>, pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
pub(crate) opaque_type_values: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>, pub(crate) opaque_type_values: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
pub(crate) polonius_context: Option<PoloniusContext>,
} }
/// A collection of region constraints that must be satisfied for the /// A collection of region constraints that must be satisfied for the