Skip to content
Closed
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
23 changes: 15 additions & 8 deletions compiler/rustc_borrowck/src/nll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ pub(crate) fn compute_regions<'tcx>(
let polonius_output = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_output())
|| infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();

let lowered_constraints = compute_sccs_applying_placeholder_outlives_constraints(
let mut lowered_constraints = compute_sccs_applying_placeholder_outlives_constraints(
constraints,
&universal_region_relations,
infcx,
Expand All @@ -144,20 +144,27 @@ pub(crate) fn compute_regions<'tcx>(
&lowered_constraints,
);

// If requested for `-Zpolonius=next`, compute loan liveness information.
// This is done prior to `RegionInferenceContext::new`, because we may add
// additional liveness constraints.
if let Some(polonius_context) = polonius_context.as_mut() {
let _timer = infcx.tcx.prof.generic_activity("borrowck_polonius_loan_liveness");
polonius_context.compute_loan_liveness(
&mut lowered_constraints.liveness_constraints,
lowered_constraints.outlives_constraints.outlives().iter().copied(),
&universal_region_relations.universal_regions,
body,
borrow_set,
);
}

let mut regioncx = RegionInferenceContext::new(
infcx,
lowered_constraints,
universal_region_relations,
location_map,
);

// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
// and use them to compute loan liveness.
if let Some(polonius_context) = polonius_context.as_mut() {
let _timer = infcx.tcx.prof.generic_activity("borrowck_polonius_loan_liveness");
polonius_context.compute_loan_liveness(&mut regioncx, body, borrow_set)
}

// If requested: dump NLL facts, and run legacy polonius analysis.
let polonius_output = polonius_facts.as_ref().and_then(|polonius_facts| {
if infcx.tcx.sess.opts.unstable_opts.nll_facts {
Expand Down
32 changes: 15 additions & 17 deletions compiler/rustc_borrowck/src/polonius/liveness_constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,23 @@ use rustc_middle::ty::relate::{
};
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable};

use super::{ConstraintDirection, PoloniusContext};
use super::ConstraintDirection;
use crate::universal_regions::UniversalRegions;

impl PoloniusContext {
/// Record the variance of each region contained within the given value.
pub(crate) fn record_live_region_variance<'tcx>(
&mut self,
tcx: TyCtxt<'tcx>,
universal_regions: &UniversalRegions<'tcx>,
value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
) {
let mut extractor = VarianceExtractor {
tcx,
ambient_variance: ty::Variance::Covariant,
directions: &mut self.live_region_variances,
universal_regions,
};
extractor.relate(value, value).expect("Can't have a type error relating to itself");
}
/// Record the variance of each region contained within the given value.
pub(crate) fn record_live_region_variance<'tcx>(
tcx: TyCtxt<'tcx>,
live_region_variances: &mut BTreeMap<RegionVid, ConstraintDirection>,
universal_regions: &UniversalRegions<'tcx>,
value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
) {
let mut extractor = VarianceExtractor {
tcx,
ambient_variance: ty::Variance::Covariant,
directions: live_region_variances,
universal_regions,
};
extractor.relate(value, value).expect("Can't have a type error relating to itself");
}

/// Extracts variances for regions contained within types. Follows the same structure as
Expand Down
21 changes: 12 additions & 9 deletions compiler/rustc_borrowck/src/polonius/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,12 @@ use rustc_mir_dataflow::points::PointIndex;

pub(self) use self::constraints::*;
pub(crate) use self::dump::dump_polonius_mir;
pub(crate) use self::liveness_constraints::record_live_region_variance;
use crate::BorrowSet;
use crate::constraints::OutlivesConstraint;
use crate::dataflow::BorrowIndex;
use crate::region_infer::values::LivenessValues;
use crate::{BorrowSet, RegionInferenceContext};
use crate::universal_regions::UniversalRegions;

pub(crate) type LiveLoans = SparseBitMatrix<PointIndex, BorrowIndex>;

Expand All @@ -65,7 +68,7 @@ pub(crate) struct PoloniusContext {

/// The expected edge direction per live region: the kind of directed edge we'll create as
/// liveness constraints depends on the variance of types with respect to each contained region.
live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
pub(crate) live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,

/// The regions that outlive free regions are used to distinguish relevant live locals from
/// boring locals. A boring local is one whose type contains only such regions. Polonius
Expand All @@ -77,7 +80,7 @@ pub(crate) struct PoloniusContext {
/// The direction a constraint can flow into. Used to create liveness constraints according to
/// variance.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum ConstraintDirection {
pub(crate) enum ConstraintDirection {
/// For covariant cases, we add a forward edge `O at P1 -> O at P2`.
Forward,

Expand All @@ -101,31 +104,31 @@ impl PoloniusContext {
/// The constraint data will be used to compute errors and diagnostics.
pub(crate) fn compute_loan_liveness<'tcx>(
&mut self,
regioncx: &mut RegionInferenceContext<'tcx>,
liveness: &mut LivenessValues,
outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
universal_regions: &UniversalRegions<'tcx>,
body: &Body<'tcx>,
borrow_set: &BorrowSet<'tcx>,
) {
let liveness = regioncx.liveness_constraints();

// We don't need to prepare the graph (index NLL constraints, etc.) if we have no loans to
// trace throughout localized constraints.
if borrow_set.len() > 0 {
// From the outlives constraints, liveness, and variances, we can compute reachability
// on the lazy localized constraint graph to trace the liveness of loans, for the next
// step in the chain (the NLL loan scope and active loans computations).
let graph = LocalizedConstraintGraph::new(liveness, regioncx.outlives_constraints());
let graph = LocalizedConstraintGraph::new(liveness, outlives_constraints);

let mut live_loans = LiveLoans::new(borrow_set.len());
let mut visitor = LoanLivenessVisitor { liveness, live_loans: &mut live_loans };
graph.traverse(
body,
liveness,
&self.live_region_variances,
regioncx.universal_regions(),
universal_regions,
borrow_set,
&mut visitor,
);
regioncx.record_live_loans(live_loans);
liveness.record_live_loans(live_loans);

// The graph can be traversed again during MIR dumping, so we store it here.
self.graph = Some(graph);
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ use crate::constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstra
use crate::dataflow::BorrowIndex;
use crate::diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo};
use crate::handle_placeholders::{LoweredConstraints, RegionTracker};
use crate::polonius::LiveLoans;
use crate::polonius::legacy::PoloniusOutput;
use crate::region_infer::values::{LivenessValues, RegionElement, RegionValues};
use crate::type_check::Locations;
Expand Down Expand Up @@ -1874,12 +1873,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
&self.liveness_constraints
}

/// When using `-Zpolonius=next`, records the given live loans for the loan scopes and active
/// loans dataflow computations.
pub(crate) fn record_live_loans(&mut self, live_loans: LiveLoans) {
self.liveness_constraints.record_live_loans(live_loans);
}

/// Returns whether the `loan_idx` is live at the given `location`: whether its issuing
/// region is contained within the type of a variable that is live at this point.
/// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`.
Expand Down
11 changes: 8 additions & 3 deletions compiler/rustc_borrowck/src/type_check/liveness/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use tracing::debug;

use super::TypeChecker;
use crate::constraints::OutlivesConstraintSet;
use crate::polonius::PoloniusContext;
use crate::polonius::{PoloniusContext, record_live_region_variance};
use crate::region_infer::values::LivenessValues;
use crate::universal_regions::UniversalRegions;

Expand Down Expand Up @@ -67,7 +67,7 @@ pub(super) fn generate<'tcx>(
let (relevant_live_locals, boring_locals) =
compute_relevant_live_locals(typeck.tcx(), &free_regions, typeck.body);

trace::trace(typeck, location_map, move_data, relevant_live_locals, boring_locals);
trace::trace(typeck, location_map, move_data, &relevant_live_locals, &boring_locals);

// Mark regions that should be live where they appear within rvalues or within a call: like
// args, regions, and types.
Expand Down Expand Up @@ -220,7 +220,12 @@ impl<'a, 'tcx> LiveVariablesVisitor<'a, 'tcx> {

// When using `-Zpolonius=next`, we record the variance of each live region.
if let Some(polonius_context) = self.polonius_context {
polonius_context.record_live_region_variance(self.tcx, self.universal_regions, value);
record_live_region_variance(
self.tcx,
&mut polonius_context.live_region_variances,
self.universal_regions,
value,
);
}
}
}
85 changes: 38 additions & 47 deletions compiler/rustc_borrowck/src/type_check/liveness/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use rustc_index::bit_set::DenseBitSet;
use rustc_index::interval::IntervalSet;
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::traits::TraitErrors;
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, HasLocalDecls, Local, Location};
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
use rustc_middle::traits::query::DropckOutlivesResult;
use rustc_middle::ty::relate::Relate;
use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
Expand All @@ -19,7 +19,8 @@ use rustc_trait_selection::traits::query::dropck_outlives;
use rustc_trait_selection::traits::query::type_op::{DropckOutlives, TypeOpOutput};
use tracing::debug;

use crate::polonius;
use crate::BorrowckInferCtxt;
use crate::polonius::{self, record_live_region_variance};
use crate::region_infer::values;
use crate::type_check::liveness::local_use_map::LocalUseMap;
use crate::type_check::{NormalizeLocation, TypeChecker};
Expand All @@ -42,8 +43,8 @@ pub(super) fn trace<'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>,
location_map: &DenseLocationMap,
move_data: &MoveData<'tcx>,
relevant_live_locals: Vec<Local>,
boring_locals: Vec<Local>,
relevant_live_locals: &[Local],
boring_locals: &[Local],
) {
let _timer = typeck.tcx().prof.generic_activity("borrowck_liveness_trace");

Expand All @@ -59,7 +60,7 @@ pub(super) fn trace<'tcx>(

let mut results = LivenessResults::new(cx);

results.add_extra_drop_facts(&relevant_live_locals);
results.add_extra_drop_facts(relevant_live_locals);

results.compute_for_all_locals(relevant_live_locals);

Expand Down Expand Up @@ -131,8 +132,8 @@ impl<'a, 'typeck, 'tcx> LivenessResults<'a, 'typeck, 'tcx> {
}
}

fn compute_for_all_locals(&mut self, relevant_live_locals: Vec<Local>) {
for local in relevant_live_locals {
fn compute_for_all_locals(&mut self, relevant_live_locals: &[Local]) {
for &local in relevant_live_locals {
self.reset_local_state();
self.add_defs_for(local);
self.compute_use_live_points_for(local);
Expand Down Expand Up @@ -161,20 +162,11 @@ impl<'a, 'typeck, 'tcx> LivenessResults<'a, 'typeck, 'tcx> {
/// These are all the locals which do not potentially reference a region local
/// to this body. Locals which only reference free regions are always drop-live
/// and can therefore safely be dropped.
fn dropck_boring_locals(&mut self, boring_locals: Vec<Local>) {
for local in boring_locals {
fn dropck_boring_locals(&mut self, boring_locals: &[Local]) {
for &local in boring_locals {
let local_ty = self.cx.body().local_decls[local].ty;
let local_span = self.cx.body().local_decls[local].source_info.span;
let drop_data = self.cx.drop_data.entry(local_ty).or_insert_with({
let typeck = &self.cx.typeck;
move || LivenessContext::compute_drop_data(typeck, local_ty, local_span)
});

drop_data.dropck_result.report_overflows(
self.cx.typeck.infcx.tcx,
self.cx.typeck.body.local_decls[local].source_info.span,
local_ty,
);
dropck_local(&self.cx.typeck.infcx, &mut self.cx.drop_data, local_ty, local_span);
}
}

Expand Down Expand Up @@ -567,11 +559,9 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
values::pretty_print_points(self.location_map, live_at.iter()),
);

let local_span = self.body().local_decls()[dropped_local].source_info.span;
let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
let typeck = &self.typeck;
move || Self::compute_drop_data(typeck, dropped_ty, local_span)
});
let dropped_span = self.body().local_decls[dropped_local].source_info.span;
let drop_data =
dropck_local(&self.typeck.infcx, &mut self.drop_data, dropped_ty, dropped_span);

if let Some(data) = &drop_data.region_constraint_data {
for &drop_location in drop_locations {
Expand All @@ -583,12 +573,6 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
}
}

drop_data.dropck_result.report_overflows(
self.typeck.infcx.tcx,
self.typeck.body.source_info(*drop_locations.first().unwrap()).span,
dropped_ty,
);

// All things in the `outlives` array may be touched by
// the destructor and must be live at this point.
for &kind in &drop_data.dropck_result.kinds {
Expand Down Expand Up @@ -627,24 +611,27 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {

// When using `-Zpolonius=next`, we record the variance of each live region.
if let Some(polonius_context) = typeck.polonius_context.as_mut() {
polonius_context.record_live_region_variance(
record_live_region_variance(
typeck.infcx.tcx,
&mut polonius_context.live_region_variances,
typeck.universal_regions,
value,
);
}
}
}

fn compute_drop_data(
typeck: &TypeChecker<'_, 'tcx>,
dropped_ty: Ty<'tcx>,
span: Span,
) -> DropData<'tcx> {
debug!("compute_drop_data(dropped_ty={:?})", dropped_ty);

let goal = DropckOutlives { dropped_ty };

match typeck.infcx.fully_perform(goal, DUMMY_SP) {
/// Computes the `DropData` for a given type, caching the result.
/// This also reports the overflow errors from the computation, if any.
fn dropck_local<'tcx, 'd>(
infcx: &BorrowckInferCtxt<'tcx>,
drop_data: &'d mut FxIndexMap<Ty<'tcx>, DropData<'tcx>>,
local_ty: Ty<'tcx>,
local_span: Span,
) -> &'d DropData<'tcx> {
let compute_drop_data = || {
let goal = DropckOutlives { dropped_ty: local_ty };
match infcx.fully_perform(goal, DUMMY_SP) {
Ok(TypeOpOutput { output, constraints, .. }) => {
DropData { dropck_result: output, region_constraint_data: constraints }
}
Expand All @@ -656,12 +643,12 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
//
// Do this inside of a probe because we don't particularly care (or want)
// any region side-effects of this operation in our infcx.
typeck.infcx.probe(|_| {
let ocx = ObligationCtxt::new_with_diagnostics(&typeck.infcx);
infcx.probe(|_| {
let ocx = ObligationCtxt::new_with_diagnostics(infcx);
let errors = match dropck_outlives::compute_dropck_outlives_with_errors(
&ocx,
typeck.infcx.param_env.and(goal),
span,
infcx.param_env.and(goal),
local_span,
) {
Ok(_) => ocx.evaluate_obligations_error_on_ambiguity(),
Err(e) => TraitErrors::HasErrors(e),
Expand All @@ -670,11 +657,15 @@ impl<'tcx> LivenessContext<'_, '_, 'tcx> {
// Could have no errors if a type lowering error, say, caused the query
// to fail.
if let TraitErrors::HasErrors(errors) = errors {
typeck.infcx.err_ctxt().report_fulfillment_errors(errors);
infcx.err_ctxt().report_fulfillment_errors(errors);
}
});
DropData { dropck_result: Default::default(), region_constraint_data: None }
}
}
}
};

let drop_data = drop_data.entry(local_ty).or_insert_with(compute_drop_data);
drop_data.dropck_result.report_overflows(infcx.tcx, local_span, local_ty);
drop_data
}
3 changes: 2 additions & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1769,7 +1769,8 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
Const::Ty(_, ct) => match ct.kind() {
ty::ConstKind::Alias(_, alias_const) => match alias_const.kind {
ty::AliasConstKind::Projection { def_id }
| ty::AliasConstKind::Inherent { def_id }
| ty::AliasConstKind::InherentSelf { def_id }
| ty::AliasConstKind::InherentImpl { def_id }
| ty::AliasConstKind::Free { def_id }
| ty::AliasConstKind::Anon { def_id } => Some(UnevaluatedConst {
def: def_id,
Expand Down
Loading
Loading