Skip to content

Commit e100ce4

Browse files
committed
Auto merge of rust-lang#51855 - Eh2406:i51821, r=nikomatsakis
A fix for 51821 This dedupe the vec of `OutlivesConstraint` using a `FxHashSet<(RegionVid, RegionVid)>` it alsow adds a `struct ConstraintSet` to encapsulate/ensure this behavere.
2 parents d94b804 + ac5bd5d commit e100ce4

File tree

6 files changed

+137
-67
lines changed

6 files changed

+137
-67
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use rustc::mir::Location;
12+
use rustc::ty::RegionVid;
13+
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
14+
15+
use std::fmt;
16+
use syntax_pos::Span;
17+
use std::ops::Deref;
18+
19+
#[derive(Clone, Default)]
20+
crate struct ConstraintSet {
21+
constraints: IndexVec<ConstraintIndex, OutlivesConstraint>,
22+
}
23+
24+
impl ConstraintSet {
25+
pub fn push(&mut self, constraint: OutlivesConstraint) {
26+
debug!(
27+
"add_outlives({:?}: {:?} @ {:?}",
28+
constraint.sup, constraint.sub, constraint.point
29+
);
30+
if constraint.sup == constraint.sub {
31+
// 'a: 'a is pretty uninteresting
32+
return;
33+
}
34+
self.constraints.push(constraint);
35+
}
36+
37+
/// Once all constraints have been added, `link()` is used to thread together the constraints
38+
/// based on which would be affected when a particular region changes. See the next field of
39+
/// `OutlivesContraint` for more details.
40+
/// link returns a map that is needed later by `each_affected_by_dirty`.
41+
pub fn link(&mut self, len: usize) -> IndexVec<RegionVid, Option<ConstraintIndex>> {
42+
let mut map = IndexVec::from_elem_n(None, len);
43+
44+
for (idx, constraint) in self.constraints.iter_enumerated_mut().rev() {
45+
let mut head = &mut map[constraint.sub];
46+
debug_assert!(constraint.next.is_none());
47+
constraint.next = *head;
48+
*head = Some(idx);
49+
}
50+
51+
map
52+
}
53+
54+
/// When a region R1 changes, we need to reprocess all constraints R2: R1 to take into account
55+
/// any new elements that R1 now has. This method will quickly enumerate all such constraints
56+
/// (that is, constraints where R1 is in the "subregion" position).
57+
/// To use it, invoke with `map[R1]` where map is the map returned by `link`;
58+
/// the callback op will be invoked for each affected constraint.
59+
pub fn each_affected_by_dirty(
60+
&self,
61+
mut opt_dep_idx: Option<ConstraintIndex>,
62+
mut op: impl FnMut(ConstraintIndex),
63+
) {
64+
while let Some(dep_idx) = opt_dep_idx {
65+
op(dep_idx);
66+
opt_dep_idx = self.constraints[dep_idx].next;
67+
}
68+
}
69+
}
70+
71+
impl Deref for ConstraintSet {
72+
type Target = IndexVec<ConstraintIndex, OutlivesConstraint>;
73+
74+
fn deref(&self) -> &Self::Target { &self.constraints }
75+
}
76+
77+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
78+
pub struct OutlivesConstraint {
79+
// NB. The ordering here is not significant for correctness, but
80+
// it is for convenience. Before we dump the constraints in the
81+
// debugging logs, we sort them, and we'd like the "super region"
82+
// to be first, etc. (In particular, span should remain last.)
83+
/// The region SUP must outlive SUB...
84+
pub sup: RegionVid,
85+
86+
/// Region that must be outlived.
87+
pub sub: RegionVid,
88+
89+
/// At this location.
90+
pub point: Location,
91+
92+
/// Later on, we thread the constraints onto a linked list
93+
/// grouped by their `sub` field. So if you had:
94+
///
95+
/// Index | Constraint | Next Field
96+
/// ----- | ---------- | ----------
97+
/// 0 | `'a: 'b` | Some(2)
98+
/// 1 | `'b: 'c` | None
99+
/// 2 | `'c: 'b` | None
100+
pub next: Option<ConstraintIndex>,
101+
102+
/// Where did this constraint arise?
103+
pub span: Span,
104+
}
105+
106+
impl fmt::Debug for OutlivesConstraint {
107+
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
108+
write!(
109+
formatter,
110+
"({:?}: {:?} @ {:?}) due to {:?}",
111+
self.sup, self.sub, self.point, self.span
112+
)
113+
}
114+
}
115+
116+
newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" });

src/librustc_mir/borrow_check/nll/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ mod renumber;
4545
crate mod type_check;
4646
mod universal_regions;
4747

48+
crate mod constraint_set;
49+
4850
use self::facts::AllFacts;
4951
use self::region_infer::RegionInferenceContext;
5052
use self::universal_regions::UniversalRegions;

src/librustc_mir/borrow_check/nll/region_infer/graphviz.rs

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use rustc_data_structures::indexed_vec::Idx;
1717
use std::borrow::Cow;
1818
use std::io::{self, Write};
1919
use super::*;
20+
use borrow_check::nll::constraint_set::OutlivesConstraint;
21+
2022

2123
impl<'tcx> RegionInferenceContext<'tcx> {
2224
/// Write out the region constraint graph.

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

+9-62
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
use super::universal_regions::UniversalRegions;
1212
use borrow_check::nll::region_infer::values::ToElementIndex;
13+
use borrow_check::nll::constraint_set::{ConstraintIndex, ConstraintSet, OutlivesConstraint};
1314
use rustc::hir::def_id::DefId;
1415
use rustc::infer::canonical::QueryRegionConstraint;
1516
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
@@ -25,7 +26,6 @@ use rustc::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable};
2526
use rustc::util::common::{self, ErrorReported};
2627
use rustc_data_structures::bitvec::BitVector;
2728
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
28-
use std::fmt;
2929
use std::rc::Rc;
3030
use syntax_pos::Span;
3131

@@ -65,7 +65,7 @@ pub struct RegionInferenceContext<'tcx> {
6565
dependency_map: Option<IndexVec<RegionVid, Option<ConstraintIndex>>>,
6666

6767
/// The constraints we have accumulated and used during solving.
68-
constraints: IndexVec<ConstraintIndex, OutlivesConstraint>,
68+
constraints: ConstraintSet,
6969

7070
/// Type constraints that we check after solving.
7171
type_tests: Vec<TypeTest<'tcx>>,
@@ -114,37 +114,6 @@ pub(crate) enum Cause {
114114
UniversalRegion(RegionVid),
115115
}
116116

117-
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
118-
pub struct OutlivesConstraint {
119-
// NB. The ordering here is not significant for correctness, but
120-
// it is for convenience. Before we dump the constraints in the
121-
// debugging logs, we sort them, and we'd like the "super region"
122-
// to be first, etc. (In particular, span should remain last.)
123-
/// The region SUP must outlive SUB...
124-
pub sup: RegionVid,
125-
126-
/// Region that must be outlived.
127-
pub sub: RegionVid,
128-
129-
/// At this location.
130-
pub point: Location,
131-
132-
/// Later on, we thread the constraints onto a linked list
133-
/// grouped by their `sub` field. So if you had:
134-
///
135-
/// Index | Constraint | Next Field
136-
/// ----- | ---------- | ----------
137-
/// 0 | `'a: 'b` | Some(2)
138-
/// 1 | `'b: 'c` | None
139-
/// 2 | `'c: 'b` | None
140-
pub next: Option<ConstraintIndex>,
141-
142-
/// Where did this constraint arise?
143-
pub span: Span,
144-
}
145-
146-
newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" });
147-
148117
/// A "type test" corresponds to an outlives constraint between a type
149118
/// and a lifetime, like `T: 'x` or `<T as Foo>::Bar: 'x`. They are
150119
/// translated from the `Verify` region constraints in the ordinary
@@ -243,7 +212,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
243212
var_infos: VarInfos,
244213
universal_regions: UniversalRegions<'tcx>,
245214
mir: &Mir<'tcx>,
246-
outlives_constraints: Vec<OutlivesConstraint>,
215+
outlives_constraints: ConstraintSet,
247216
type_tests: Vec<TypeTest<'tcx>>,
248217
) -> Self {
249218
// The `next` field should not yet have been initialized:
@@ -266,7 +235,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
266235
liveness_constraints: RegionValues::new(elements, num_region_variables),
267236
inferred_values: None,
268237
dependency_map: None,
269-
constraints: IndexVec::from_raw(outlives_constraints),
238+
constraints: outlives_constraints,
270239
type_tests,
271240
universal_regions,
272241
};
@@ -392,15 +361,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
392361
sub: RegionVid,
393362
point: Location,
394363
) {
395-
debug!("add_outlives({:?}: {:?} @ {:?}", sup, sub, point);
396364
assert!(self.inferred_values.is_none(), "values already inferred");
397365
self.constraints.push(OutlivesConstraint {
398366
span,
399367
sup,
400368
sub,
401369
point,
402370
next: None,
403-
});
371+
})
404372
}
405373

406374
/// Perform region inference and report errors if we see any
@@ -498,13 +466,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
498466
debug!("propagate_constraints: sub={:?}", constraint.sub);
499467
debug!("propagate_constraints: sup={:?}", constraint.sup);
500468

501-
let mut opt_dep_idx = dependency_map[constraint.sup];
502-
while let Some(dep_idx) = opt_dep_idx {
469+
self.constraints.each_affected_by_dirty(dependency_map[constraint.sup], |dep_idx| {
503470
if clean_bit_vec.remove(dep_idx.index()) {
504471
dirty_list.push(dep_idx);
505472
}
506-
opt_dep_idx = self.constraints[dep_idx].next;
507-
}
473+
});
508474
}
509475

510476
debug!("\n");
@@ -518,16 +484,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
518484
/// These are constraints like Y: X @ P -- so if X changed, we may
519485
/// need to grow Y.
520486
fn build_dependency_map(&mut self) -> IndexVec<RegionVid, Option<ConstraintIndex>> {
521-
let mut map = IndexVec::from_elem(None, &self.definitions);
522-
523-
for (idx, constraint) in self.constraints.iter_enumerated_mut().rev() {
524-
let mut head = &mut map[constraint.sub];
525-
debug_assert!(constraint.next.is_none());
526-
constraint.next = *head;
527-
*head = Some(idx);
528-
}
529-
530-
map
487+
self.constraints.link(self.definitions.len())
531488
}
532489

533490
/// Once regions have been propagated, this method is used to see
@@ -1115,7 +1072,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
11151072

11161073
while changed {
11171074
changed = false;
1118-
for constraint in &self.constraints {
1075+
for constraint in self.constraints.iter() {
11191076
if let Some(n) = result_set[constraint.sup] {
11201077
let m = n + 1;
11211078
if result_set[constraint.sub]
@@ -1146,16 +1103,6 @@ impl<'tcx> RegionDefinition<'tcx> {
11461103
}
11471104
}
11481105

1149-
impl fmt::Debug for OutlivesConstraint {
1150-
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1151-
write!(
1152-
formatter,
1153-
"({:?}: {:?} @ {:?}) due to {:?}",
1154-
self.sup, self.sub, self.point, self.span
1155-
)
1156-
}
1157-
}
1158-
11591106
pub trait ClosureRegionRequirementsExt<'gcx, 'tcx> {
11601107
fn apply_requirements(
11611108
&self,

src/librustc_mir/borrow_check/nll/type_check/constraint_conversion.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
// except according to those terms.
1010

1111
use borrow_check::location::LocationTable;
12+
use borrow_check::nll::constraint_set::OutlivesConstraint;
1213
use borrow_check::nll::facts::AllFacts;
13-
use borrow_check::nll::region_infer::{OutlivesConstraint, RegionTest, TypeTest};
14+
use borrow_check::nll::region_infer::{RegionTest, TypeTest};
1415
use borrow_check::nll::type_check::Locations;
1516
use borrow_check::nll::universal_regions::UniversalRegions;
17+
use borrow_check::nll::constraint_set::ConstraintSet;
1618
use rustc::infer::canonical::QueryRegionConstraint;
1719
use rustc::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
1820
use rustc::infer::region_constraints::{GenericKind, VerifyBound};
@@ -31,7 +33,7 @@ crate struct ConstraintConversion<'a, 'gcx: 'tcx, 'tcx: 'a> {
3133
implicit_region_bound: Option<ty::Region<'tcx>>,
3234
param_env: ty::ParamEnv<'tcx>,
3335
locations: Locations,
34-
outlives_constraints: &'a mut Vec<OutlivesConstraint>,
36+
outlives_constraints: &'a mut ConstraintSet,
3537
type_tests: &'a mut Vec<TypeTest<'tcx>>,
3638
all_facts: &'a mut Option<AllFacts>,
3739
}
@@ -46,7 +48,7 @@ impl<'a, 'gcx, 'tcx> ConstraintConversion<'a, 'gcx, 'tcx> {
4648
implicit_region_bound: Option<ty::Region<'tcx>>,
4749
param_env: ty::ParamEnv<'tcx>,
4850
locations: Locations,
49-
outlives_constraints: &'a mut Vec<OutlivesConstraint>,
51+
outlives_constraints: &'a mut ConstraintSet,
5052
type_tests: &'a mut Vec<TypeTest<'tcx>>,
5153
all_facts: &'a mut Option<AllFacts>,
5254
) -> Self {

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
#![allow(unreachable_code)]
1313

1414
use borrow_check::location::LocationTable;
15+
use borrow_check::nll::constraint_set::ConstraintSet;
1516
use borrow_check::nll::facts::AllFacts;
1617
use borrow_check::nll::region_infer::Cause;
17-
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, OutlivesConstraint, TypeTest};
18+
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
1819
use borrow_check::nll::universal_regions::UniversalRegions;
1920
use dataflow::move_paths::MoveData;
2021
use dataflow::FlowAtLocation;
@@ -621,7 +622,7 @@ crate struct MirTypeckRegionConstraints<'tcx> {
621622
/// hence it must report on their liveness constraints.
622623
crate liveness_set: Vec<(ty::Region<'tcx>, Location, Cause)>,
623624

624-
crate outlives_constraints: Vec<OutlivesConstraint>,
625+
crate outlives_constraints: ConstraintSet,
625626

626627
crate type_tests: Vec<TypeTest<'tcx>>,
627628
}

0 commit comments

Comments
 (0)