Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert typeck constraints in location-sensitive polonius #134920

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
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
Prev Previous commit
address review comments
push constraint creation to where the statement/terminator info is gathered
  • Loading branch information
lqd committed Jan 1, 2025
commit 9eef43a03dc8ba4d3735839430a96410efcd9aa5
130 changes: 68 additions & 62 deletions compiler/rustc_borrowck/src/polonius/typeck_constraints.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::mir::{Body, Location, Statement, StatementKind, Terminator, TerminatorKind};
use rustc_middle::ty::{TyCtxt, TypeVisitable};
use rustc_middle::ty::TyCtxt;
use rustc_mir_dataflow::points::PointIndex;

use super::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
Expand Down Expand Up @@ -52,10 +52,8 @@ pub(super) fn convert_typeck_constraints<'tcx>(
// this information better in MIR typeck instead, for example with a new `Locations`
// variant that contains which node is crossing over between entry and exit.
let point = liveness.point_from_location(location);
let (from, to) = if let Some(stmt) =
body[location.block].statements.get(location.statement_index)
{
localize_statement_constraint(
if let Some(stmt) = body[location.block].statements.get(location.statement_index) {
convert_statement_constraint(
tcx,
body,
stmt,
Expand All @@ -64,34 +62,30 @@ pub(super) fn convert_typeck_constraints<'tcx>(
location,
point,
universal_regions,
localized_outlives_constraints,
)
} else {
assert_eq!(location.statement_index, body[location.block].statements.len());
let terminator = body[location.block].terminator();
localize_terminator_constraint(
convert_terminator_constraint(
tcx,
body,
terminator,
liveness,
&outlives_constraint,
point,
universal_regions,
localized_outlives_constraints,
)
};
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from,
target: outlives_constraint.sub,
to,
});
}
}
}
}
}

/// For a given outlives constraint arising from a MIR statement, computes the CFG `from`-`to`
/// intra-block nodes to localize the constraint.
fn localize_statement_constraint<'tcx>(
fn convert_statement_constraint<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
stmt: &Statement<'tcx>,
Expand All @@ -100,7 +94,8 @@ fn localize_statement_constraint<'tcx>(
current_location: Location,
current_point: PointIndex,
universal_regions: &UniversalRegions<'tcx>,
) -> (PointIndex, PointIndex) {
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
) {
match &stmt.kind {
StatementKind::Assign(box (lhs, rhs)) => {
// To create localized outlives constraints without midpoints, we rely on the property
Expand Down Expand Up @@ -146,33 +141,52 @@ fn localize_statement_constraint<'tcx>(
statement_index: current_location.statement_index + 1,
};
let successor_point = liveness.point_from_location(successor_location);
compute_constraint_direction(
tcx,
outlives_constraint,
&lhs_ty,
current_point,
successor_point,
universal_regions,
)

let mut from = current_point;
let mut to = current_point;
tcx.for_each_free_region(&lhs_ty, |region| {
let region = universal_regions.to_region_vid(region);
if region == outlives_constraint.sub {
// This constraint flows into the LHS, its effects start becoming visible on
// exit.
to = successor_point;
} else if region == outlives_constraint.sup {
// This constraint flows from the LHS, its effects start becoming visible on
// exit.
from = successor_point;
}
});
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from,
target: outlives_constraint.sub,
to,
});
}
_ => {
// For the other cases, we localize an outlives constraint to where it arises.
(current_point, current_point)
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from: current_point,
target: outlives_constraint.sub,
to: current_point,
});
}
}
}

/// For a given outlives constraint arising from a MIR terminator, computes the CFG `from`-`to`
/// inter-block nodes to localize the constraint.
fn localize_terminator_constraint<'tcx>(
fn convert_terminator_constraint<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
terminator: &Terminator<'tcx>,
liveness: &LivenessValues,
outlives_constraint: &OutlivesConstraint<'tcx>,
current_point: PointIndex,
universal_regions: &UniversalRegions<'tcx>,
) -> (PointIndex, PointIndex) {
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
) {
// FIXME: check if other terminators need the same handling as `Call`s, in particular
// Assert/Yield/Drop. A handful of tests are failing with Drop related issues, as well as some
// coroutine tests, and that may be why.
Expand All @@ -185,47 +199,39 @@ fn localize_terminator_constraint<'tcx>(
let destination_ty = destination.ty(&body.local_decls, tcx);
let successor_location = Location { block: *target, statement_index: 0 };
let successor_point = liveness.point_from_location(successor_location);
compute_constraint_direction(
tcx,
outlives_constraint,
&destination_ty,
current_point,
successor_point,
universal_regions,
)

let mut from = current_point;
let mut to = current_point;
tcx.for_each_free_region(&destination_ty, |region| {
let region = universal_regions.to_region_vid(region);
if region == outlives_constraint.sub {
// This constraint flows into the destination, its effects start becoming
// visible on exit.
to = successor_point;
} else if region == outlives_constraint.sup {
// This constraint flows from the destination, its effects start becoming
// visible on exit.
from = successor_point;
}
});

localized_outlives_constraints.push(LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from,
target: outlives_constraint.sub,
to,
});
}
_ => {
// Typeck constraints guide loans between regions at the current point, so we do that in
// the general case, and liveness will take care of making them flow to the terminator's
// successors.
(current_point, current_point)
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from: current_point,
target: outlives_constraint.sub,
to: current_point,
});
}
}
}

/// For a given constraint, returns the `from`-`to` edge according to whether the constraint flows
/// to or from a free region in the given `value`, some kind of result for an effectful operation,
/// like the LHS of an assignment.
fn compute_constraint_direction<'tcx>(
tcx: TyCtxt<'tcx>,
outlives_constraint: &OutlivesConstraint<'tcx>,
value: &impl TypeVisitable<TyCtxt<'tcx>>,
current_point: PointIndex,
successor_point: PointIndex,
universal_regions: &UniversalRegions<'tcx>,
) -> (PointIndex, PointIndex) {
let mut to = current_point;
let mut from = current_point;
tcx.for_each_free_region(value, |region| {
let region = universal_regions.to_region_vid(region);
if region == outlives_constraint.sub {
// This constraint flows into the result, its effects start becoming visible on exit.
to = successor_point;
} else if region == outlives_constraint.sup {
// This constraint flows from the result, its effects start becoming visible on exit.
from = successor_point;
}
});

(from, to)
}
Loading