mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Stop using LinkedGraph in lexical_region_resolve
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_type_ir::RegionVid;
|
||||
|
||||
use crate::infer::SubregionOrigin;
|
||||
use crate::infer::region_constraints::{Constraint, ConstraintKind, RegionConstraintData};
|
||||
|
||||
/// Selects either out-edges or in-edges for [`IndexedConstraintEdges::adjacent_edges`].
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(super) enum EdgeDirection {
|
||||
Out,
|
||||
In,
|
||||
}
|
||||
|
||||
/// Type alias for the pairs stored in [`RegionConstraintData::constraints`],
|
||||
/// which we are indexing.
|
||||
type ConstraintPair<'tcx> = (Constraint<'tcx>, SubregionOrigin<'tcx>);
|
||||
|
||||
/// An index from region variables to their corresponding constraint edges,
|
||||
/// used on some error paths.
|
||||
pub(super) struct IndexedConstraintEdges<'data, 'tcx> {
|
||||
out_edges: IndexVec<RegionVid, Vec<&'data ConstraintPair<'tcx>>>,
|
||||
in_edges: IndexVec<RegionVid, Vec<&'data ConstraintPair<'tcx>>>,
|
||||
}
|
||||
|
||||
impl<'data, 'tcx> IndexedConstraintEdges<'data, 'tcx> {
|
||||
pub(super) fn build_index(num_vars: usize, data: &'data RegionConstraintData<'tcx>) -> Self {
|
||||
let mut out_edges = IndexVec::from_fn_n(|_| vec![], num_vars);
|
||||
let mut in_edges = IndexVec::from_fn_n(|_| vec![], num_vars);
|
||||
|
||||
for pair @ (c, _) in &data.constraints {
|
||||
// Only push a var out-edge for `VarSub...` constraints.
|
||||
match c.kind {
|
||||
ConstraintKind::VarSubVar | ConstraintKind::VarSubReg => {
|
||||
out_edges[c.sub.as_var()].push(pair)
|
||||
}
|
||||
ConstraintKind::RegSubVar | ConstraintKind::RegSubReg => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Index in-edges in reverse order, to match what current tests expect.
|
||||
// (It's unclear whether this is important or not.)
|
||||
for pair @ (c, _) in data.constraints.iter().rev() {
|
||||
// Only push a var in-edge for `...SubVar` constraints.
|
||||
match c.kind {
|
||||
ConstraintKind::VarSubVar | ConstraintKind::RegSubVar => {
|
||||
in_edges[c.sup.as_var()].push(pair)
|
||||
}
|
||||
ConstraintKind::VarSubReg | ConstraintKind::RegSubReg => {}
|
||||
}
|
||||
}
|
||||
|
||||
IndexedConstraintEdges { out_edges, in_edges }
|
||||
}
|
||||
|
||||
/// Returns either the out-edges or in-edges of the specified region var,
|
||||
/// as selected by `dir`.
|
||||
pub(super) fn adjacent_edges(
|
||||
&self,
|
||||
region_vid: RegionVid,
|
||||
dir: EdgeDirection,
|
||||
) -> &[&'data ConstraintPair<'tcx>] {
|
||||
let edges = match dir {
|
||||
EdgeDirection::Out => &self.out_edges,
|
||||
EdgeDirection::In => &self.in_edges,
|
||||
};
|
||||
&edges[region_vid]
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,6 @@
|
||||
use std::fmt;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::graph::linked_graph::{
|
||||
Direction, INCOMING, LinkedGraph, NodeIndex, OUTGOING,
|
||||
};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
@@ -18,11 +15,14 @@
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::outlives::test_type_match;
|
||||
use crate::infer::lexical_region_resolve::indexed_edges::{EdgeDirection, IndexedConstraintEdges};
|
||||
use crate::infer::region_constraints::{
|
||||
Constraint, ConstraintKind, GenericKind, RegionConstraintData, VarInfos, VerifyBound,
|
||||
ConstraintKind, GenericKind, RegionConstraintData, VarInfos, VerifyBound,
|
||||
};
|
||||
use crate::infer::{RegionRelations, RegionVariableOrigin, SubregionOrigin};
|
||||
|
||||
mod indexed_edges;
|
||||
|
||||
/// This function performs lexical region resolution given a complete
|
||||
/// set of constraints and variable origins. It performs a fixed-point
|
||||
/// iteration to find region values which satisfy all constraints,
|
||||
@@ -118,8 +118,6 @@ struct RegionAndOrigin<'tcx> {
|
||||
origin: SubregionOrigin<'tcx>,
|
||||
}
|
||||
|
||||
type RegionGraph<'tcx> = LinkedGraph<(), Constraint<'tcx>>;
|
||||
|
||||
struct LexicalResolver<'cx, 'tcx> {
|
||||
region_rels: &'cx RegionRelations<'cx, 'tcx>,
|
||||
var_infos: VarInfos<'tcx>,
|
||||
@@ -626,9 +624,8 @@ fn collect_var_errors(
|
||||
// overlapping locations.
|
||||
let mut dup_vec = IndexVec::from_elem_n(None, self.num_vars());
|
||||
|
||||
// Only construct the graph when necessary, because it's moderately
|
||||
// expensive.
|
||||
let mut graph = None;
|
||||
// Only construct the edge index when necessary, because it's moderately expensive.
|
||||
let mut edges: Option<IndexedConstraintEdges<'_, 'tcx>> = None;
|
||||
|
||||
for (node_vid, value) in var_data.values.iter_enumerated() {
|
||||
match *value {
|
||||
@@ -662,56 +659,18 @@ fn collect_var_errors(
|
||||
// influence the constraints on this value for
|
||||
// richer diagnostics in `static_impl_trait`.
|
||||
|
||||
let g = graph.get_or_insert_with(|| self.construct_graph());
|
||||
self.collect_error_for_expanding_node(g, &mut dup_vec, node_vid, errors);
|
||||
let e = edges.get_or_insert_with(|| {
|
||||
IndexedConstraintEdges::build_index(self.num_vars(), &self.data)
|
||||
});
|
||||
self.collect_error_for_expanding_node(e, &mut dup_vec, node_vid, errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn construct_graph(&self) -> RegionGraph<'tcx> {
|
||||
let num_vars = self.num_vars();
|
||||
|
||||
let mut graph = LinkedGraph::new();
|
||||
|
||||
for _ in 0..num_vars {
|
||||
graph.add_node(());
|
||||
}
|
||||
|
||||
// Issue #30438: two distinct dummy nodes, one for incoming
|
||||
// edges (dummy_source) and another for outgoing edges
|
||||
// (dummy_sink). In `dummy -> a -> b -> dummy`, using one
|
||||
// dummy node leads one to think (erroneously) there exists a
|
||||
// path from `b` to `a`. Two dummy nodes sidesteps the issue.
|
||||
let dummy_source = graph.add_node(());
|
||||
let dummy_sink = graph.add_node(());
|
||||
|
||||
for (c, _) in &self.data.constraints {
|
||||
match c.kind {
|
||||
ConstraintKind::VarSubVar => {
|
||||
let sub_vid = c.sub.as_var();
|
||||
let sup_vid = c.sup.as_var();
|
||||
graph.add_edge(NodeIndex(sub_vid.index()), NodeIndex(sup_vid.index()), *c);
|
||||
}
|
||||
ConstraintKind::RegSubVar => {
|
||||
graph.add_edge(dummy_source, NodeIndex(c.sup.as_var().index()), *c);
|
||||
}
|
||||
ConstraintKind::VarSubReg => {
|
||||
graph.add_edge(NodeIndex(c.sub.as_var().index()), dummy_sink, *c);
|
||||
}
|
||||
ConstraintKind::RegSubReg => {
|
||||
// this would be an edge from `dummy_source` to
|
||||
// `dummy_sink`; just ignore it.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
graph
|
||||
}
|
||||
|
||||
fn collect_error_for_expanding_node(
|
||||
&self,
|
||||
graph: &RegionGraph<'tcx>,
|
||||
edges: &IndexedConstraintEdges<'_, 'tcx>,
|
||||
dup_vec: &mut IndexSlice<RegionVid, Option<RegionVid>>,
|
||||
node_idx: RegionVid,
|
||||
errors: &mut Vec<RegionResolutionError<'tcx>>,
|
||||
@@ -719,9 +678,9 @@ fn collect_error_for_expanding_node(
|
||||
// Errors in expanding nodes result from a lower-bound that is
|
||||
// not contained by an upper-bound.
|
||||
let (mut lower_bounds, lower_vid_bounds, lower_dup) =
|
||||
self.collect_bounding_regions(graph, node_idx, INCOMING, Some(dup_vec));
|
||||
self.collect_bounding_regions(edges, node_idx, EdgeDirection::In, Some(dup_vec));
|
||||
let (mut upper_bounds, _, upper_dup) =
|
||||
self.collect_bounding_regions(graph, node_idx, OUTGOING, Some(dup_vec));
|
||||
self.collect_bounding_regions(edges, node_idx, EdgeDirection::Out, Some(dup_vec));
|
||||
|
||||
if lower_dup || upper_dup {
|
||||
return;
|
||||
@@ -829,9 +788,9 @@ fn region_order_key(x: &RegionAndOrigin<'_>) -> u8 {
|
||||
/// those returned by a previous call for another region.
|
||||
fn collect_bounding_regions(
|
||||
&self,
|
||||
graph: &RegionGraph<'tcx>,
|
||||
edges: &IndexedConstraintEdges<'_, 'tcx>,
|
||||
orig_node_idx: RegionVid,
|
||||
dir: Direction,
|
||||
dir: EdgeDirection,
|
||||
mut dup_vec: Option<&mut IndexSlice<RegionVid, Option<RegionVid>>>,
|
||||
) -> (Vec<RegionAndOrigin<'tcx>>, FxHashSet<RegionVid>, bool) {
|
||||
struct WalkState<'tcx> {
|
||||
@@ -850,7 +809,7 @@ struct WalkState<'tcx> {
|
||||
|
||||
// to start off the process, walk the source node in the
|
||||
// direction specified
|
||||
process_edges(&self.data, &mut state, graph, orig_node_idx, dir);
|
||||
process_edges(&mut state, edges, orig_node_idx, dir);
|
||||
|
||||
while let Some(node_idx) = state.stack.pop() {
|
||||
// check whether we've visited this node on some previous walk
|
||||
@@ -867,30 +826,25 @@ struct WalkState<'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
process_edges(&self.data, &mut state, graph, node_idx, dir);
|
||||
process_edges(&mut state, edges, node_idx, dir);
|
||||
}
|
||||
|
||||
let WalkState { result, dup_found, set, .. } = state;
|
||||
return (result, set, dup_found);
|
||||
|
||||
fn process_edges<'tcx>(
|
||||
this: &RegionConstraintData<'tcx>,
|
||||
state: &mut WalkState<'tcx>,
|
||||
graph: &RegionGraph<'tcx>,
|
||||
edges: &IndexedConstraintEdges<'_, 'tcx>,
|
||||
source_vid: RegionVid,
|
||||
dir: Direction,
|
||||
dir: EdgeDirection,
|
||||
) {
|
||||
debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
|
||||
|
||||
let source_node_index = NodeIndex(source_vid.index());
|
||||
for (_, edge) in graph.adjacent_edges(source_node_index, dir) {
|
||||
let get_origin =
|
||||
|| this.constraints.iter().find(|(c, _)| *c == edge.data).unwrap().1.clone();
|
||||
|
||||
match edge.data.kind {
|
||||
for (c, origin) in edges.adjacent_edges(source_vid, dir) {
|
||||
match c.kind {
|
||||
ConstraintKind::VarSubVar => {
|
||||
let from_vid = edge.data.sub.as_var();
|
||||
let to_vid = edge.data.sup.as_var();
|
||||
let from_vid = c.sub.as_var();
|
||||
let to_vid = c.sup.as_var();
|
||||
let opp_vid = if from_vid == source_vid { to_vid } else { from_vid };
|
||||
if state.set.insert(opp_vid) {
|
||||
state.stack.push(opp_vid);
|
||||
@@ -898,13 +852,13 @@ fn process_edges<'tcx>(
|
||||
}
|
||||
|
||||
ConstraintKind::RegSubVar => {
|
||||
let origin = get_origin();
|
||||
state.result.push(RegionAndOrigin { region: edge.data.sub, origin });
|
||||
let origin = origin.clone();
|
||||
state.result.push(RegionAndOrigin { region: c.sub, origin });
|
||||
}
|
||||
|
||||
ConstraintKind::VarSubReg => {
|
||||
let origin = get_origin();
|
||||
state.result.push(RegionAndOrigin { region: edge.data.sup, origin });
|
||||
let origin = origin.clone();
|
||||
state.result.push(RegionAndOrigin { region: c.sup, origin });
|
||||
}
|
||||
|
||||
ConstraintKind::RegSubReg => panic!(
|
||||
|
||||
Reference in New Issue
Block a user