Skip to content

Commit f0f5ef5

Browse files
committed
address review comments
1 parent 5c39a2a commit f0f5ef5

File tree

3 files changed

+90
-62
lines changed

3 files changed

+90
-62
lines changed

src/librustc/traits/fulfill.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use infer::{InferCtxt, InferOk};
1313
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt};
1414
use rustc_data_structures::obligation_forest::{ObligationForest, Error};
1515
use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
16+
use std::marker::PhantomData;
1617
use std::mem;
1718
use syntax::ast;
1819
use util::common::ErrorReported;
@@ -314,13 +315,14 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx,
314315
}).collect()))
315316
}
316317

317-
fn process_backedge<'c, I>(&mut self, cycle: I)
318-
where I: Clone + Iterator<Item=*const Self::Obligation>,
318+
fn process_backedge<'c, I>(&mut self, cycle: I,
319+
_marker: PhantomData<&'c PendingPredicateObligation<'tcx>>)
320+
where I: Clone + Iterator<Item=&'c PendingPredicateObligation<'tcx>>,
319321
{
320322
if coinductive_match(self.selcx, cycle.clone()) {
321323
debug!("process_child_obligations: coinductive match");
322324
} else {
323-
let cycle : Vec<_> = cycle.map(|c| unsafe { &*c }.obligation.clone()).collect();
325+
let cycle : Vec<_> = cycle.map(|c| c.obligation.clone()).collect();
324326
self.selcx.infcx().report_overflow_error_cycle(&cycle);
325327
}
326328
}
@@ -536,13 +538,14 @@ fn process_predicate<'a, 'gcx, 'tcx>(
536538
/// - it also appears in the backtrace at some position `X`; and,
537539
/// - all the predicates at positions `X..` between `X` an the top are
538540
/// also defaulted traits.
539-
fn coinductive_match<'a,'gcx,'tcx,I>(selcx: &mut SelectionContext<'a,'gcx,'tcx>, cycle: I) -> bool
540-
where I: Iterator<Item=*const PendingPredicateObligation<'tcx>>
541+
fn coinductive_match<'a,'c,'gcx,'tcx,I>(selcx: &mut SelectionContext<'a,'gcx,'tcx>,
542+
cycle: I) -> bool
543+
where I: Iterator<Item=&'c PendingPredicateObligation<'tcx>>,
544+
'tcx: 'c
541545
{
542546
let mut cycle = cycle;
543547
cycle
544548
.all(|bt_obligation| {
545-
let bt_obligation = unsafe { &*bt_obligation };
546549
let result = coinductive_obligation(selcx, &bt_obligation.obligation);
547550
debug!("coinductive_match: bt_obligation={:?} coinductive={}",
548551
bt_obligation, result);

src/librustc_data_structures/obligation_forest/mod.rs

+75-51
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@ use std::cell::Cell;
2121
use std::collections::hash_map::Entry;
2222
use std::fmt::Debug;
2323
use std::hash;
24+
use std::marker::PhantomData;
2425

2526
mod node_index;
2627
use self::node_index::NodeIndex;
2728

2829
#[cfg(test)]
2930
mod test;
3031

31-
pub trait ForestObligation : Clone {
32-
type Predicate : Clone + hash::Hash + Eq + ::std::fmt::Debug;
32+
pub trait ForestObligation : Clone + Debug {
33+
type Predicate : Clone + hash::Hash + Eq + Debug;
3334

3435
fn as_predicate(&self) -> &Self::Predicate;
3536
}
@@ -42,9 +43,9 @@ pub trait ObligationProcessor {
4243
obligation: &mut Self::Obligation)
4344
-> Result<Option<Vec<Self::Obligation>>, Self::Error>;
4445

45-
// FIXME: crazy lifetime troubles
46-
fn process_backedge<I>(&mut self, cycle: I)
47-
where I: Clone + Iterator<Item=*const Self::Obligation>;
46+
fn process_backedge<'c, I>(&mut self, cycle: I,
47+
_marker: PhantomData<&'c Self::Obligation>)
48+
where I: Clone + Iterator<Item=&'c Self::Obligation>;
4849
}
4950

5051
struct SnapshotData {
@@ -66,8 +67,12 @@ pub struct ObligationForest<O: ForestObligation> {
6667
/// at a higher index than its parent. This is needed by the
6768
/// backtrace iterator (which uses `split_at`).
6869
nodes: Vec<Node<O>>,
70+
/// A cache of predicates that have been successfully completed.
6971
done_cache: FnvHashSet<O::Predicate>,
72+
/// An cache of the nodes in `nodes`, indexed by predicate.
7073
waiting_cache: FnvHashMap<O::Predicate, NodeIndex>,
74+
/// A list of the obligations added in snapshots, to allow
75+
/// for their removal.
7176
cache_list: Vec<O::Predicate>,
7277
snapshots: Vec<SnapshotData>,
7378
scratch: Option<Vec<usize>>,
@@ -82,33 +87,33 @@ struct Node<O> {
8287
obligation: O,
8388
state: Cell<NodeState>,
8489

85-
// these both go *in the same direction*.
90+
/// Obligations that depend on this obligation for their
91+
/// completion. They must all be in a non-pending state.
92+
dependents: Vec<NodeIndex>,
93+
/// The parent of a node - the original obligation of
94+
/// which it is a subobligation. Except for error reporting,
95+
/// this is just another member of `dependents`.
8696
parent: Option<NodeIndex>,
87-
dependants: Vec<NodeIndex>,
8897
}
8998

9099
/// The state of one node in some tree within the forest. This
91100
/// represents the current state of processing for the obligation (of
92101
/// type `O`) associated with this node.
102+
///
103+
/// Outside of ObligationForest methods, nodes should be either Pending
104+
/// or Waiting.
93105
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
94106
enum NodeState {
95-
/// Obligation not yet resolved to success or error.
107+
/// Obligations for which selection had not yet returned a
108+
/// non-ambiguous result.
96109
Pending,
97110

98-
/// Used before garbage collection
111+
/// This obligation was selected successfuly, but may or
112+
/// may not have subobligations.
99113
Success,
100114

101-
/// Used in DFS loops
102-
InLoop,
103-
104-
/// Obligation resolved to success; `num_incomplete_children`
105-
/// indicates the number of children still in an "incomplete"
106-
/// state. Incomplete means that either the child is still
107-
/// pending, or it has children which are incomplete. (Basically,
108-
/// there is pending work somewhere in the subtree of the child.)
109-
///
110-
/// Once all children have completed, success nodes are removed
111-
/// from the vector by the compression step.
115+
/// This obligation was selected sucessfully, but it has
116+
/// a pending subobligation.
112117
Waiting,
113118

114119
/// This obligation, along with its subobligations, are complete,
@@ -118,6 +123,10 @@ enum NodeState {
118123
/// This obligation was resolved to an error. Error nodes are
119124
/// removed from the vector by the compression step.
120125
Error,
126+
127+
/// This is a temporary state used in DFS loops to detect cycles,
128+
/// it should not exist outside of these DFSes.
129+
OnDfsStack,
121130
}
122131

123132
#[derive(Debug)]
@@ -144,7 +153,7 @@ pub struct Error<O, E> {
144153
pub backtrace: Vec<O>,
145154
}
146155

147-
impl<O: Debug + ForestObligation> ObligationForest<O> {
156+
impl<O: ForestObligation> ObligationForest<O> {
148157
pub fn new() -> ObligationForest<O> {
149158
ObligationForest {
150159
nodes: vec![],
@@ -210,7 +219,12 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
210219
debug!("register_obligation_at({:?}, {:?}) - duplicate of {:?}!",
211220
obligation, parent, o.get());
212221
if let Some(parent) = parent {
213-
self.nodes[o.get().get()].dependants.push(parent);
222+
if self.nodes[o.get().get()].dependents.contains(&parent) {
223+
debug!("register_obligation_at({:?}, {:?}) - duplicate subobligation",
224+
obligation, parent);
225+
} else {
226+
self.nodes[o.get().get()].dependents.push(parent);
227+
}
214228
}
215229
}
216230
Entry::Vacant(v) => {
@@ -230,7 +244,6 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
230244
assert!(!self.in_snapshot());
231245
let mut errors = vec![];
232246
for index in 0..self.nodes.len() {
233-
debug_assert!(!self.nodes[index].is_popped());
234247
if let NodeState::Pending = self.nodes[index].state.get() {
235248
let backtrace = self.error_at(index);
236249
errors.push(Error {
@@ -269,8 +282,6 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
269282
let mut stalled = true;
270283

271284
for index in 0..self.nodes.len() {
272-
debug_assert!(!self.nodes[index].is_popped());
273-
274285
debug!("process_obligations: node {} == {:?}",
275286
index,
276287
self.nodes[index]);
@@ -327,57 +338,69 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
327338
}
328339
}
329340

330-
pub fn process_cycles<P>(&mut self, processor: &mut P)
341+
/// Mark all NodeState::Success nodes as NodeState::Done and
342+
/// report all cycles between them. This should be called
343+
/// after `mark_as_waiting` marks all nodes with pending
344+
/// subobligations as NodeState::Waiting.
345+
fn process_cycles<P>(&mut self, processor: &mut P)
331346
where P: ObligationProcessor<Obligation=O>
332347
{
333348
let mut stack = self.scratch.take().unwrap();
334349

335350
for node in 0..self.nodes.len() {
336-
self.visit_node(&mut stack, processor, node);
351+
self.find_cycles_from_node(&mut stack, processor, node);
337352
}
338353

339354
self.scratch = Some(stack);
340355
}
341356

342-
fn visit_node<P>(&self, stack: &mut Vec<usize>, processor: &mut P, index: usize)
357+
fn find_cycles_from_node<P>(&self, stack: &mut Vec<usize>,
358+
processor: &mut P, index: usize)
343359
where P: ObligationProcessor<Obligation=O>
344360
{
345361
let node = &self.nodes[index];
346362
let state = node.state.get();
347363
match state {
348-
NodeState::InLoop => {
364+
NodeState::OnDfsStack => {
349365
let index =
350366
stack.iter().rposition(|n| *n == index).unwrap();
351367
// I need a Clone closure
352368
#[derive(Clone)]
353369
struct GetObligation<'a, O: 'a>(&'a [Node<O>]);
354370
impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> {
355-
type Output = *const O;
356-
extern "rust-call" fn call_once(self, args: (&'b usize,)) -> *const O {
371+
type Output = &'a O;
372+
extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O {
357373
&self.0[*args.0].obligation
358374
}
359375
}
360376
impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> {
361-
extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> *const O {
377+
extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O {
362378
&self.0[*args.0].obligation
363379
}
364380
}
365381

366-
processor.process_backedge(stack[index..].iter().map(GetObligation(&self.nodes)));
382+
processor.process_backedge(stack[index..].iter().map(GetObligation(&self.nodes)),
383+
PhantomData);
367384
}
368385
NodeState::Success => {
369-
node.state.set(NodeState::InLoop);
386+
node.state.set(NodeState::OnDfsStack);
370387
stack.push(index);
371388
if let Some(parent) = node.parent {
372-
self.visit_node(stack, processor, parent.get());
389+
self.find_cycles_from_node(stack, processor, parent.get());
373390
}
374-
for dependant in &node.dependants {
375-
self.visit_node(stack, processor, dependant.get());
391+
for dependent in &node.dependents {
392+
self.find_cycles_from_node(stack, processor, dependent.get());
376393
}
377394
stack.pop();
378395
node.state.set(NodeState::Done);
379396
},
380-
_ => return
397+
NodeState::Waiting | NodeState::Pending => {
398+
// this node is still reachable from some pending node. We
399+
// will get to it when they are all processed.
400+
}
401+
NodeState::Done | NodeState::Error => {
402+
// already processed that node
403+
}
381404
};
382405
}
383406

@@ -391,7 +414,7 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
391414
loop {
392415
self.nodes[n].state.set(NodeState::Error);
393416
trace.push(self.nodes[n].obligation.clone());
394-
error_stack.extend(self.nodes[n].dependants.iter().map(|x| x.get()));
417+
error_stack.extend(self.nodes[n].dependents.iter().map(|x| x.get()));
395418

396419
// loop to the parent
397420
match self.nodes[n].parent {
@@ -415,15 +438,15 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
415438
}
416439

417440
error_stack.extend(
418-
node.dependants.iter().cloned().chain(node.parent).map(|x| x.get())
441+
node.dependents.iter().cloned().chain(node.parent).map(|x| x.get())
419442
);
420443
}
421444

422445
self.scratch = Some(error_stack);
423446
trace
424447
}
425448

426-
/// Marks all nodes that depend on a pending node as "waiting".
449+
/// Marks all nodes that depend on a pending node as NodeState;:Waiting.
427450
fn mark_as_waiting(&self) {
428451
for node in &self.nodes {
429452
if node.state.get() == NodeState::Waiting {
@@ -441,7 +464,7 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
441464
fn mark_as_waiting_from(&self, node: &Node<O>) {
442465
match node.state.get() {
443466
NodeState::Pending | NodeState::Done => {},
444-
NodeState::Waiting | NodeState::Error | NodeState::InLoop => return,
467+
NodeState::Waiting | NodeState::Error | NodeState::OnDfsStack => return,
445468
NodeState::Success => {
446469
node.state.set(NodeState::Waiting);
447470
}
@@ -451,8 +474,8 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
451474
self.mark_as_waiting_from(&self.nodes[parent.get()]);
452475
}
453476

454-
for dependant in &node.dependants {
455-
self.mark_as_waiting_from(&self.nodes[dependant.get()]);
477+
for dependent in &node.dependents {
478+
self.mark_as_waiting_from(&self.nodes[dependent.get()]);
456479
}
457480
}
458481

@@ -546,12 +569,12 @@ impl<O: Debug + ForestObligation> ObligationForest<O> {
546569
}
547570

548571
let mut i = 0;
549-
while i < node.dependants.len() {
550-
let new_index = node_rewrites[node.dependants[i].get()];
572+
while i < node.dependents.len() {
573+
let new_index = node_rewrites[node.dependents[i].get()];
551574
if new_index >= nodes_len {
552-
node.dependants.swap_remove(i);
575+
node.dependents.swap_remove(i);
553576
} else {
554-
node.dependants[i] = NodeIndex::new(new_index);
577+
node.dependents[i] = NodeIndex::new(new_index);
555578
i += 1;
556579
}
557580
}
@@ -577,14 +600,15 @@ impl<O> Node<O> {
577600
obligation: obligation,
578601
parent: parent,
579602
state: Cell::new(NodeState::Pending),
580-
dependants: vec![],
603+
dependents: vec![],
581604
}
582605
}
583606

584607
fn is_popped(&self) -> bool {
585608
match self.state.get() {
586-
NodeState::Pending | NodeState::Success | NodeState::Waiting => false,
587-
NodeState::Error | NodeState::Done | NodeState::InLoop => true,
609+
NodeState::Pending | NodeState::Waiting => false,
610+
NodeState::Error | NodeState::Done => true,
611+
NodeState::OnDfsStack | NodeState::Success => unreachable!()
588612
}
589613
}
590614
}

src/librustc_data_structures/obligation_forest/test.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ impl<'a> super::ForestObligation for &'a str {
2525

2626
struct ClosureObligationProcessor<OF, BF, O, E> {
2727
process_obligation: OF,
28-
process_backedge: BF,
28+
_process_backedge: BF,
2929
marker: PhantomData<(O, E)>,
3030
}
3131

@@ -36,7 +36,7 @@ fn C<OF, BF, O>(of: OF, bf: BF) -> ClosureObligationProcessor<OF, BF, O, &'stati
3636
{
3737
ClosureObligationProcessor {
3838
process_obligation: of,
39-
process_backedge: bf,
39+
_process_backedge: bf,
4040
marker: PhantomData
4141
}
4242
}
@@ -57,9 +57,10 @@ impl<OF, BF, O, E> ObligationProcessor for ClosureObligationProcessor<OF, BF, O,
5757
(self.process_obligation)(obligation)
5858
}
5959

60-
fn process_backedge(&mut self, cycle: &[Self::Obligation]) {
61-
(self.process_backedge)(cycle);
62-
}
60+
fn process_backedge<'c, I>(&mut self, _cycle: I,
61+
_marker: PhantomData<&'c Self::Obligation>)
62+
where I: Clone + Iterator<Item=&'c Self::Obligation> {
63+
}
6364
}
6465

6566

0 commit comments

Comments
 (0)