diff options
| author | bors <bors@rust-lang.org> | 2015-04-18 04:57:56 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-04-18 04:57:56 +0000 |
| commit | 77213d1b28b307401d2bbb143168418bf7e6794c (patch) | |
| tree | c191a85069e53bb24f06b335f17402215590a946 /src/librustc | |
| parent | efa6a46a8eceb4ab792d5ec8e28cf3baaaa96491 (diff) | |
| parent | e47fb489c10f2d86216c3a75ad6cbde3742e9f0c (diff) | |
| download | rust-77213d1b28b307401d2bbb143168418bf7e6794c.tar.gz rust-77213d1b28b307401d2bbb143168418bf7e6794c.zip | |
Auto merge of #24209 - nikomatsakis:refactor-unification, r=nrc
I'm on a quest to slowly refactor a lot of the inference code. A first step for that is moving the "pure data structures" out so as to simplify what's left. This PR moves `snapshot_vec`, `graph`, and `unify` into their own crate (`librustc_data_structures`). They can then be unit-tested, benchmarked, etc more easily. As a benefit, I improved the performance of unification slightly on the benchmark I added vs the original code. r? @nrc
Diffstat (limited to 'src/librustc')
| -rw-r--r-- | src/librustc/lib.rs | 3 | ||||
| -rw-r--r-- | src/librustc/middle/cfg/construct.rs | 2 | ||||
| -rw-r--r-- | src/librustc/middle/cfg/mod.rs | 5 | ||||
| -rw-r--r-- | src/librustc/middle/dataflow.rs | 5 | ||||
| -rw-r--r-- | src/librustc/middle/graph.rs | 484 | ||||
| -rw-r--r-- | src/librustc/middle/infer/freshen.rs | 2 | ||||
| -rw-r--r-- | src/librustc/middle/infer/mod.rs | 5 | ||||
| -rw-r--r-- | src/librustc/middle/infer/region_inference/mod.rs | 30 | ||||
| -rw-r--r-- | src/librustc/middle/infer/type_variable.rs | 8 | ||||
| -rw-r--r-- | src/librustc/middle/infer/unify.rs | 340 | ||||
| -rw-r--r-- | src/librustc/middle/infer/unify_key.rs | 48 | ||||
| -rw-r--r-- | src/librustc/util/snapshot_vec.rs | 186 |
12 files changed, 75 insertions, 1043 deletions
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index a4bb17bc354..ab5c4e76966 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -54,6 +54,7 @@ extern crate graphviz; extern crate libc; extern crate rustc_llvm; extern crate rustc_back; +extern crate rustc_data_structures; extern crate serialize; extern crate rbml; extern crate collections; @@ -103,7 +104,6 @@ pub mod middle { pub mod entry; pub mod expr_use_visitor; pub mod fast_reject; - pub mod graph; pub mod intrinsicck; pub mod infer; pub mod lang_items; @@ -141,7 +141,6 @@ pub mod util { pub mod common; pub mod ppaux; pub mod nodemap; - pub mod snapshot_vec; pub mod lev_distance; } diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index cbc2ef1535e..359a1a486c9 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc_data_structures::graph; use middle::cfg::*; use middle::def; -use middle::graph; use middle::pat_util; use middle::region::CodeExtent; use middle::ty; diff --git a/src/librustc/middle/cfg/mod.rs b/src/librustc/middle/cfg/mod.rs index ad4fdcd7b83..3ca221c9630 100644 --- a/src/librustc/middle/cfg/mod.rs +++ b/src/librustc/middle/cfg/mod.rs @@ -11,7 +11,7 @@ //! Module that constructs a control-flow graph representing an item. //! Uses `Graph` as the underlying representation. -use middle::graph; +use rustc_data_structures::graph; use middle::ty; use syntax::ast; @@ -24,7 +24,7 @@ pub struct CFG { pub exit: CFGIndex, } -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub enum CFGNodeData { AST(ast::NodeId), Entry, @@ -43,6 +43,7 @@ impl CFGNodeData { } } +#[derive(Debug)] pub struct CFGEdgeData { pub exiting_scopes: Vec<ast::NodeId> } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 41b4495c5f0..1d5d4f72fc2 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -576,10 +576,9 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> { pred_bits: &[usize], cfg: &cfg::CFG, cfgidx: CFGIndex) { - cfg.graph.each_outgoing_edge(cfgidx, |_e_idx, edge| { + for (_, edge) in cfg.graph.outgoing_edges(cfgidx) { self.propagate_bits_into_entry_set_for(pred_bits, edge); - true - }); + } } fn propagate_bits_into_entry_set_for(&mut self, diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs deleted file mode 100644 index a9ac61b49ec..00000000000 --- a/src/librustc/middle/graph.rs +++ /dev/null @@ -1,484 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A graph module for use in dataflow, region resolution, and elsewhere. -//! -//! # Interface details -//! -//! You customize the graph by specifying a "node data" type `N` and an -//! "edge data" type `E`. You can then later gain access (mutable or -//! immutable) to these "user-data" bits. Currently, you can only add -//! nodes or edges to the graph. You cannot remove or modify them once -//! added. This could be changed if we have a need. -//! -//! # Implementation details -//! -//! The main tricky thing about this code is the way that edges are -//! stored. The edges are stored in a central array, but they are also -//! threaded onto two linked lists for each node, one for incoming edges -//! and one for outgoing edges. Note that every edge is a member of some -//! incoming list and some outgoing list. Basically you can load the -//! first index of the linked list from the node data structures (the -//! field `first_edge`) and then, for each edge, load the next index from -//! the field `next_edge`). Each of those fields is an array that should -//! be indexed by the direction (see the type `Direction`). - -#![allow(dead_code)] // still WIP - -use std::fmt::{Formatter, Error, Debug}; -use std::usize; -use std::collections::BitSet; - -pub struct Graph<N,E> { - nodes: Vec<Node<N>> , - edges: Vec<Edge<E>> , -} - -pub struct Node<N> { - first_edge: [EdgeIndex; 2], // see module comment - pub data: N, -} - -pub struct Edge<E> { - next_edge: [EdgeIndex; 2], // see module comment - source: NodeIndex, - target: NodeIndex, - pub data: E, -} - -impl<E: Debug> Debug for Edge<E> { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - write!(f, "Edge {{ next_edge: [{:?}, {:?}], source: {:?}, target: {:?}, data: {:?} }}", - self.next_edge[0], self.next_edge[1], self.source, - self.target, self.data) - } -} - -#[derive(Clone, Copy, PartialEq, Debug)] -pub struct NodeIndex(pub usize); -#[allow(non_upper_case_globals)] -pub const InvalidNodeIndex: NodeIndex = NodeIndex(usize::MAX); - -#[derive(Copy, Clone, PartialEq, Debug)] -pub struct EdgeIndex(pub usize); -#[allow(non_upper_case_globals)] -pub const InvalidEdgeIndex: EdgeIndex = EdgeIndex(usize::MAX); - -// Use a private field here to guarantee no more instances are created: -#[derive(Copy, Clone, Debug)] -pub struct Direction { repr: usize } -#[allow(non_upper_case_globals)] -pub const Outgoing: Direction = Direction { repr: 0 }; -#[allow(non_upper_case_globals)] -pub const Incoming: Direction = Direction { repr: 1 }; - -impl NodeIndex { - fn get(&self) -> usize { let NodeIndex(v) = *self; v } - /// Returns unique id (unique with respect to the graph holding associated node). - pub fn node_id(&self) -> usize { self.get() } -} - -impl EdgeIndex { - fn get(&self) -> usize { let EdgeIndex(v) = *self; v } - /// Returns unique id (unique with respect to the graph holding associated edge). - pub fn edge_id(&self) -> usize { self.get() } -} - -impl<N,E> Graph<N,E> { - pub fn new() -> Graph<N,E> { - Graph { - nodes: Vec::new(), - edges: Vec::new(), - } - } - - pub fn with_capacity(num_nodes: usize, - num_edges: usize) -> Graph<N,E> { - Graph { - nodes: Vec::with_capacity(num_nodes), - edges: Vec::with_capacity(num_edges), - } - } - - /////////////////////////////////////////////////////////////////////////// - // Simple accessors - - #[inline] - pub fn all_nodes<'a>(&'a self) -> &'a [Node<N>] { - &self.nodes - } - - #[inline] - pub fn all_edges<'a>(&'a self) -> &'a [Edge<E>] { - &self.edges - } - - /////////////////////////////////////////////////////////////////////////// - // Node construction - - pub fn next_node_index(&self) -> NodeIndex { - NodeIndex(self.nodes.len()) - } - - pub fn add_node(&mut self, data: N) -> NodeIndex { - let idx = self.next_node_index(); - self.nodes.push(Node { - first_edge: [InvalidEdgeIndex, InvalidEdgeIndex], - data: data - }); - idx - } - - pub fn mut_node_data<'a>(&'a mut self, idx: NodeIndex) -> &'a mut N { - &mut self.nodes[idx.get()].data - } - - pub fn node_data<'a>(&'a self, idx: NodeIndex) -> &'a N { - &self.nodes[idx.get()].data - } - - pub fn node<'a>(&'a self, idx: NodeIndex) -> &'a Node<N> { - &self.nodes[idx.get()] - } - - /////////////////////////////////////////////////////////////////////////// - // Edge construction and queries - - pub fn next_edge_index(&self) -> EdgeIndex { - EdgeIndex(self.edges.len()) - } - - pub fn add_edge(&mut self, - source: NodeIndex, - target: NodeIndex, - data: E) -> EdgeIndex { - let idx = self.next_edge_index(); - - // read current first of the list of edges from each node - let source_first = self.nodes[source.get()] - .first_edge[Outgoing.repr]; - let target_first = self.nodes[target.get()] - .first_edge[Incoming.repr]; - - // create the new edge, with the previous firsts from each node - // as the next pointers - self.edges.push(Edge { - next_edge: [source_first, target_first], - source: source, - target: target, - data: data - }); - - // adjust the firsts for each node target be the next object. - self.nodes[source.get()].first_edge[Outgoing.repr] = idx; - self.nodes[target.get()].first_edge[Incoming.repr] = idx; - - return idx; - } - - pub fn mut_edge_data<'a>(&'a mut self, idx: EdgeIndex) -> &'a mut E { - &mut self.edges[idx.get()].data - } - - pub fn edge_data<'a>(&'a self, idx: EdgeIndex) -> &'a E { - &self.edges[idx.get()].data - } - - pub fn edge<'a>(&'a self, idx: EdgeIndex) -> &'a Edge<E> { - &self.edges[idx.get()] - } - - pub fn first_adjacent(&self, node: NodeIndex, dir: Direction) -> EdgeIndex { - //! Accesses the index of the first edge adjacent to `node`. - //! This is useful if you wish to modify the graph while walking - //! the linked list of edges. - - self.nodes[node.get()].first_edge[dir.repr] - } - - pub fn next_adjacent(&self, edge: EdgeIndex, dir: Direction) -> EdgeIndex { - //! Accesses the next edge in a given direction. - //! This is useful if you wish to modify the graph while walking - //! the linked list of edges. - - self.edges[edge.get()].next_edge[dir.repr] - } - - /////////////////////////////////////////////////////////////////////////// - // Iterating over nodes, edges - - pub fn each_node<'a, F>(&'a self, mut f: F) -> bool where - F: FnMut(NodeIndex, &'a Node<N>) -> bool, - { - //! Iterates over all edges defined in the graph. - self.nodes.iter().enumerate().all(|(i, node)| f(NodeIndex(i), node)) - } - - pub fn each_edge<'a, F>(&'a self, mut f: F) -> bool where - F: FnMut(EdgeIndex, &'a Edge<E>) -> bool, - { - //! Iterates over all edges defined in the graph - self.edges.iter().enumerate().all(|(i, edge)| f(EdgeIndex(i), edge)) - } - - pub fn each_outgoing_edge<'a, F>(&'a self, source: NodeIndex, f: F) -> bool where - F: FnMut(EdgeIndex, &'a Edge<E>) -> bool, - { - //! Iterates over all outgoing edges from the node `from` - - self.each_adjacent_edge(source, Outgoing, f) - } - - pub fn each_incoming_edge<'a, F>(&'a self, target: NodeIndex, f: F) -> bool where - F: FnMut(EdgeIndex, &'a Edge<E>) -> bool, - { - //! Iterates over all incoming edges to the node `target` - - self.each_adjacent_edge(target, Incoming, f) - } - - pub fn each_adjacent_edge<'a, F>(&'a self, - node: NodeIndex, - dir: Direction, - mut f: F) - -> bool where - F: FnMut(EdgeIndex, &'a Edge<E>) -> bool, - { - //! Iterates over all edges adjacent to the node `node` - //! in the direction `dir` (either `Outgoing` or `Incoming) - - let mut edge_idx = self.first_adjacent(node, dir); - while edge_idx != InvalidEdgeIndex { - let edge = &self.edges[edge_idx.get()]; - if !f(edge_idx, edge) { - return false; - } - edge_idx = edge.next_edge[dir.repr]; - } - return true; - } - - /////////////////////////////////////////////////////////////////////////// - // Fixed-point iteration - // - // A common use for graphs in our compiler is to perform - // fixed-point iteration. In this case, each edge represents a - // constraint, and the nodes themselves are associated with - // variables or other bitsets. This method facilitates such a - // computation. - - pub fn iterate_until_fixed_point<'a, F>(&'a self, mut op: F) where - F: FnMut(usize, EdgeIndex, &'a Edge<E>) -> bool, - { - let mut iteration = 0; - let mut changed = true; - while changed { - changed = false; - iteration += 1; - for (i, edge) in self.edges.iter().enumerate() { - changed |= op(iteration, EdgeIndex(i), edge); - } - } - } - - pub fn depth_traverse<'a>(&'a self, start: NodeIndex) -> DepthFirstTraversal<'a, N, E> { - DepthFirstTraversal { - graph: self, - stack: vec![start], - visited: BitSet::new() - } - } -} - -pub struct DepthFirstTraversal<'g, N:'g, E:'g> { - graph: &'g Graph<N, E>, - stack: Vec<NodeIndex>, - visited: BitSet -} - -impl<'g, N, E> Iterator for DepthFirstTraversal<'g, N, E> { - type Item = &'g N; - - fn next(&mut self) -> Option<&'g N> { - while let Some(idx) = self.stack.pop() { - if !self.visited.insert(idx.node_id()) { - continue; - } - self.graph.each_outgoing_edge(idx, |_, e| -> bool { - if !self.visited.contains(&e.target().node_id()) { - self.stack.push(e.target()); - } - true - }); - - return Some(self.graph.node_data(idx)); - } - - return None; - } -} - -pub fn each_edge_index<F>(max_edge_index: EdgeIndex, mut f: F) where - F: FnMut(EdgeIndex) -> bool, -{ - let mut i = 0; - let n = max_edge_index.get(); - while i < n { - if !f(EdgeIndex(i)) { - return; - } - i += 1; - } -} - -impl<E> Edge<E> { - pub fn source(&self) -> NodeIndex { - self.source - } - - pub fn target(&self) -> NodeIndex { - self.target - } -} - -#[cfg(test)] -mod test { - use middle::graph::*; - use std::fmt::Debug; - - type TestNode = Node<&'static str>; - type TestEdge = Edge<&'static str>; - type TestGraph = Graph<&'static str, &'static str>; - - fn create_graph() -> TestGraph { - let mut graph = Graph::new(); - - // Create a simple graph - // - // A -+> B --> C - // | | ^ - // | v | - // F D --> E - - let a = graph.add_node("A"); - let b = graph.add_node("B"); - let c = graph.add_node("C"); - let d = graph.add_node("D"); - let e = graph.add_node("E"); - let f = graph.add_node("F"); - - graph.add_edge(a, b, "AB"); - graph.add_edge(b, c, "BC"); - graph.add_edge(b, d, "BD"); - graph.add_edge(d, e, "DE"); - graph.add_edge(e, c, "EC"); - graph.add_edge(f, b, "FB"); - - return graph; - } - - #[test] - fn each_node() { - let graph = create_graph(); - let expected = ["A", "B", "C", "D", "E", "F"]; - graph.each_node(|idx, node| { - assert_eq!(&expected[idx.get()], graph.node_data(idx)); - assert_eq!(expected[idx.get()], node.data); - true - }); - } - - #[test] - fn each_edge() { - let graph = create_graph(); - let expected = ["AB", "BC", "BD", "DE", "EC", "FB"]; - graph.each_edge(|idx, edge| { - assert_eq!(&expected[idx.get()], graph.edge_data(idx)); - assert_eq!(expected[idx.get()], edge.data); - true - }); - } - - fn test_adjacent_edges<N:PartialEq+Debug,E:PartialEq+Debug>(graph: &Graph<N,E>, - start_index: NodeIndex, - start_data: N, - expected_incoming: &[(E,N)], - expected_outgoing: &[(E,N)]) { - assert!(graph.node_data(start_index) == &start_data); - - let mut counter = 0; - graph.each_incoming_edge(start_index, |edge_index, edge| { - assert!(graph.edge_data(edge_index) == &edge.data); - assert!(counter < expected_incoming.len()); - debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", - counter, expected_incoming[counter], edge_index, edge); - match expected_incoming[counter] { - (ref e, ref n) => { - assert!(e == &edge.data); - assert!(n == graph.node_data(edge.source)); - assert!(start_index == edge.target); - } - } - counter += 1; - true - }); - assert_eq!(counter, expected_incoming.len()); - - let mut counter = 0; - graph.each_outgoing_edge(start_index, |edge_index, edge| { - assert!(graph.edge_data(edge_index) == &edge.data); - assert!(counter < expected_outgoing.len()); - debug!("counter={:?} expected={:?} edge_index={:?} edge={:?}", - counter, expected_outgoing[counter], edge_index, edge); - match expected_outgoing[counter] { - (ref e, ref n) => { - assert!(e == &edge.data); - assert!(start_index == edge.source); - assert!(n == graph.node_data(edge.target)); - } - } - counter += 1; - true - }); - assert_eq!(counter, expected_outgoing.len()); - } - - #[test] - fn each_adjacent_from_a() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(0), "A", - &[], - &[("AB", "B")]); - } - - #[test] - fn each_adjacent_from_b() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(1), "B", - &[("FB", "F"), ("AB", "A"),], - &[("BD", "D"), ("BC", "C"),]); - } - - #[test] - fn each_adjacent_from_c() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(2), "C", - &[("EC", "E"), ("BC", "B")], - &[]); - } - - #[test] - fn each_adjacent_from_d() { - let graph = create_graph(); - test_adjacent_edges(&graph, NodeIndex(3), "D", - &[("BD", "B")], - &[("DE", "E")]); - } -} diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index 29f74d12ea3..d93d13beec8 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -37,7 +37,7 @@ use middle::ty_fold::TypeFolder; use std::collections::hash_map::{self, Entry}; use super::InferCtxt; -use super::unify::ToType; +use super::unify_key::ToType; pub struct TypeFreshener<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 0f62b440bf3..b0921a266f3 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -29,6 +29,7 @@ use middle::ty::replace_late_bound_regions; use middle::ty::{self, Ty}; use middle::ty_fold::{TypeFolder, TypeFoldable}; use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use rustc_data_structures::unify::{self, UnificationTable}; use std::cell::{RefCell}; use std::fmt; use std::rc::Rc; @@ -41,8 +42,8 @@ use util::ppaux::{Repr, UserString}; use self::combine::CombineFields; use self::region_inference::{RegionVarBindings, RegionSnapshot}; -use self::unify::{ToType, UnificationTable}; use self::error_reporting::ErrorReporting; +use self::unify_key::ToType; pub mod bivariate; pub mod combine; @@ -57,7 +58,7 @@ pub mod resolve; mod freshen; pub mod sub; pub mod type_variable; -pub mod unify; +pub mod unify_key; pub type Bound<T> = Option<T>; pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index c6be97e6dbe..e76468131e0 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -20,14 +20,13 @@ use self::Classification::*; use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; +use rustc_data_structures::graph::{self, Direction, NodeIndex}; use middle::region; use middle::ty::{self, Ty}; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; use middle::ty_relate::RelateResult; -use middle::graph; -use middle::graph::{Direction, NodeIndex}; use util::common::indenter; use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux::{Repr, UserString}; @@ -1325,10 +1324,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { let num_vars = self.num_vars(); let constraints = self.constraints.borrow(); - let num_edges = constraints.len(); - let mut graph = graph::Graph::with_capacity(num_vars as usize + 1, - num_edges); + let mut graph = graph::Graph::new(); for _ in 0..num_vars { graph.add_node(()); @@ -1370,10 +1367,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // not contained by an upper-bound. let (mut lower_bounds, lower_dup) = self.collect_concrete_regions(graph, var_data, node_idx, - graph::Incoming, dup_vec); + graph::INCOMING, dup_vec); let (mut upper_bounds, upper_dup) = self.collect_concrete_regions(graph, var_data, node_idx, - graph::Outgoing, dup_vec); + graph::OUTGOING, dup_vec); if lower_dup || upper_dup { return; @@ -1433,7 +1430,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // that have no intersection. let (upper_bounds, dup_found) = self.collect_concrete_regions(graph, var_data, node_idx, - graph::Outgoing, dup_vec); + graph::OUTGOING, dup_vec); if dup_found { return; @@ -1508,8 +1505,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // figure out the direction from which this node takes its // values, and search for concrete regions etc in that direction let dir = match classification { - Expanding => graph::Incoming, - Contracting => graph::Outgoing, + Expanding => graph::INCOMING, + Contracting => graph::OUTGOING, }; process_edges(self, &mut state, graph, node_idx, dir); @@ -1519,14 +1516,14 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { return (result, dup_found); fn process_edges<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>, - state: &mut WalkState<'tcx>, - graph: &RegionGraph, - source_vid: RegionVid, - dir: Direction) { + state: &mut WalkState<'tcx>, + graph: &RegionGraph, + source_vid: RegionVid, + dir: Direction) { debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir); let source_node_index = NodeIndex(source_vid.index as usize); - graph.each_adjacent_edge(source_node_index, dir, |_, edge| { + for (_, edge) in graph.adjacent_edges(source_node_index, dir) { match edge.data { ConstrainVarSubVar(from_vid, to_vid) => { let opp_vid = @@ -1544,8 +1541,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { }); } } - true - }); + } } } diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs index 03612a6c1ae..b3e3e016d85 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -17,7 +17,7 @@ use std::cmp::min; use std::marker::PhantomData; use std::mem; use std::u32; -use util::snapshot_vec as sv; +use rustc_data_structures::snapshot_vec as sv; pub struct TypeVariableTable<'tcx> { values: sv::SnapshotVec<Delegate<'tcx>>, @@ -65,7 +65,7 @@ impl RelationDir { impl<'tcx> TypeVariableTable<'tcx> { pub fn new() -> TypeVariableTable<'tcx> { - TypeVariableTable { values: sv::SnapshotVec::new(Delegate(PhantomData)) } + TypeVariableTable { values: sv::SnapshotVec::new() } } fn relations<'a>(&'a mut self, a: ty::TyVid) -> &'a mut Vec<Relation> { @@ -201,9 +201,7 @@ impl<'tcx> sv::SnapshotVecDelegate for Delegate<'tcx> { type Value = TypeVariableData<'tcx>; type Undo = UndoEntry; - fn reverse(&mut self, - values: &mut Vec<TypeVariableData<'tcx>>, - action: UndoEntry) { + fn reverse(values: &mut Vec<TypeVariableData<'tcx>>, action: UndoEntry) { match action { SpecifyVar(vid, relations) => { values[vid.index as usize].value = Bounded(relations); diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs deleted file mode 100644 index 4bbced1d75c..00000000000 --- a/src/librustc/middle/infer/unify.rs +++ /dev/null @@ -1,340 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::VarValue::*; - -use std::marker; - -use middle::ty::{IntVarValue}; -use middle::ty::{self, Ty}; -use std::fmt::Debug; -use std::marker::PhantomData; -use syntax::ast; -use util::snapshot_vec as sv; - -/// This trait is implemented by any type that can serve as a type -/// variable. We call such variables *unification keys*. For example, -/// this trait is implemented by `IntVid`, which represents integral -/// variables. -/// -/// Each key type has an associated value type `V`. For example, for -/// `IntVid`, this is `Option<IntVarValue>`, representing some -/// (possibly not yet known) sort of integer. -/// -/// Implementations of this trait are at the end of this file. -pub trait UnifyKey : Clone + Debug + PartialEq { - type Value : UnifyValue; - - fn index(&self) -> u32; - - fn from_index(u: u32) -> Self; - - fn tag(k: Option<Self>) -> &'static str; -} - -/// Trait for valid types that a type variable can be set to. Note that -/// this is typically not the end type that the value will take on, but -/// rather an `Option` wrapper (where `None` represents a variable -/// whose value is not yet set). -/// -/// Implementations of this trait are at the end of this file. -pub trait UnifyValue : Clone + PartialEq + Debug { -} - -/// Value of a unification key. We implement Tarjan's union-find -/// algorithm: when two keys are unified, one of them is converted -/// into a "redirect" pointing at the other. These redirects form a -/// DAG: the roots of the DAG (nodes that are not redirected) are each -/// associated with a value of type `V` and a rank. The rank is used -/// to keep the DAG relatively balanced, which helps keep the running -/// time of the algorithm under control. For more information, see -/// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>. -#[derive(PartialEq,Clone,Debug)] -pub enum VarValue<K:UnifyKey> { - Redirect(K), - Root(K::Value, usize), -} - -/// Table of unification keys and their values. -pub struct UnificationTable<K:UnifyKey> { - /// Indicates the current value of each key. - values: sv::SnapshotVec<Delegate<K>>, -} - -/// At any time, users may snapshot a unification table. The changes -/// made during the snapshot may either be *committed* or *rolled back*. -pub struct Snapshot<K:UnifyKey> { - // Link snapshot to the key type `K` of the table. - marker: marker::PhantomData<K>, - snapshot: sv::Snapshot, -} - -/// Internal type used to represent the result of a `get()` operation. -/// Conveys the current root and value of the key. -pub struct Node<K:UnifyKey> { - pub key: K, - pub value: K::Value, - pub rank: usize, -} - -#[derive(Copy, Clone)] -pub struct Delegate<K>(PhantomData<K>); - -// We can't use V:LatticeValue, much as I would like to, -// because frequently the pattern is that V=Option<U> for some -// other type parameter U, and we have no way to say -// Option<U>:LatticeValue. - -impl<K:UnifyKey> UnificationTable<K> { - pub fn new() -> UnificationTable<K> { - UnificationTable { - values: sv::SnapshotVec::new(Delegate(PhantomData)), - } - } - - /// Starts a new snapshot. Each snapshot must be either - /// rolled back or committed in a "LIFO" (stack) order. - pub fn snapshot(&mut self) -> Snapshot<K> { - Snapshot { marker: marker::PhantomData::<K>, - snapshot: self.values.start_snapshot() } - } - - /// Reverses all changes since the last snapshot. Also - /// removes any keys that have been created since then. - pub fn rollback_to(&mut self, snapshot: Snapshot<K>) { - debug!("{}: rollback_to()", UnifyKey::tag(None::<K>)); - self.values.rollback_to(snapshot.snapshot); - } - - /// Commits all changes since the last snapshot. Of course, they - /// can still be undone if there is a snapshot further out. - pub fn commit(&mut self, snapshot: Snapshot<K>) { - debug!("{}: commit()", UnifyKey::tag(None::<K>)); - self.values.commit(snapshot.snapshot); - } - - pub fn new_key(&mut self, value: K::Value) -> K { - let index = self.values.push(Root(value, 0)); - let k = UnifyKey::from_index(index as u32); - debug!("{}: created new key: {:?}", - UnifyKey::tag(None::<K>), - k); - k - } - - /// Find the root node for `vid`. This uses the standard - /// union-find algorithm with path compression: - /// <http://en.wikipedia.org/wiki/Disjoint-set_data_structure>. - /// - /// NB. This is a building-block operation and you would probably - /// prefer to call `probe` below. - fn get(&mut self, vid: K) -> Node<K> { - let index = vid.index() as usize; - let value = (*self.values.get(index)).clone(); - match value { - Redirect(redirect) => { - let node: Node<K> = self.get(redirect.clone()); - if node.key != redirect { - // Path compression - self.values.set(index, Redirect(node.key.clone())); - } - node - } - Root(value, rank) => { - Node { key: vid, value: value, rank: rank } - } - } - } - - fn is_root(&self, key: &K) -> bool { - let index = key.index() as usize; - match *self.values.get(index) { - Redirect(..) => false, - Root(..) => true, - } - } - - /// Sets the value for `vid` to `new_value`. `vid` MUST be a root - /// node! This is an internal operation used to impl other things. - fn set(&mut self, key: K, new_value: VarValue<K>) { - assert!(self.is_root(&key)); - - debug!("Updating variable {:?} to {:?}", - key, new_value); - - let index = key.index() as usize; - self.values.set(index, new_value); - } - - /// Either redirects `node_a` to `node_b` or vice versa, depending - /// on the relative rank. The value associated with the new root - /// will be `new_value`. - /// - /// NB: This is the "union" operation of "union-find". It is - /// really more of a building block. If the values associated with - /// your key are non-trivial, you would probably prefer to call - /// `unify_var_var` below. - fn unify(&mut self, node_a: &Node<K>, node_b: &Node<K>, new_value: K::Value) { - debug!("unify(node_a(id={:?}, rank={:?}), node_b(id={:?}, rank={:?}))", - node_a.key, - node_a.rank, - node_b.key, - node_b.rank); - - let (new_root, new_rank) = if node_a.rank > node_b.rank { - // a has greater rank, so a should become b's parent, - // i.e., b should redirect to a. - self.set(node_b.key.clone(), Redirect(node_a.key.clone())); - (node_a.key.clone(), node_a.rank) - } else if node_a.rank < node_b.rank { - // b has greater rank, so a should redirect to b. - self.set(node_a.key.clone(), Redirect(node_b.key.clone())); - (node_b.key.clone(), node_b.rank) - } else { - // If equal, redirect one to the other and increment the - // other's rank. - assert_eq!(node_a.rank, node_b.rank); - self.set(node_b.key.clone(), Redirect(node_a.key.clone())); - (node_a.key.clone(), node_a.rank + 1) - }; - - self.set(new_root, Root(new_value, new_rank)); - } -} - -impl<K:UnifyKey> sv::SnapshotVecDelegate for Delegate<K> { - type Value = VarValue<K>; - type Undo = (); - - fn reverse(&mut self, _: &mut Vec<VarValue<K>>, _: ()) { - panic!("Nothing to reverse"); - } -} - -/////////////////////////////////////////////////////////////////////////// -// Code to handle keys which carry a value, like ints, -// floats---anything that doesn't have a subtyping relationship we -// need to worry about. - -impl<'tcx,K,V> UnificationTable<K> - where K: UnifyKey<Value=Option<V>>, - V: Clone+PartialEq, - Option<V>: UnifyValue, -{ - pub fn unify_var_var(&mut self, - a_id: K, - b_id: K) - -> Result<(),(V,V)> - { - let node_a = self.get(a_id); - let node_b = self.get(b_id); - let a_id = node_a.key.clone(); - let b_id = node_b.key.clone(); - - if a_id == b_id { return Ok(()); } - - let combined = { - match (&node_a.value, &node_b.value) { - (&None, &None) => { - None - } - (&Some(ref v), &None) | (&None, &Some(ref v)) => { - Some(v.clone()) - } - (&Some(ref v1), &Some(ref v2)) => { - if *v1 != *v2 { - return Err((v1.clone(), v2.clone())); - } - Some(v1.clone()) - } - } - }; - - Ok(self.unify(&node_a, &node_b, combined)) - } - - /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping - /// relationships, if `a_id` already has a value, it must be the same as `b`. - pub fn unify_var_value(&mut self, - a_id: K, - b: V) - -> Result<(),(V,V)> - { - let node_a = self.get(a_id); - let a_id = node_a.key.clone(); - - match node_a.value { - None => { - self.set(a_id, Root(Some(b), node_a.rank)); - Ok(()) - } - - Some(ref a_t) => { - if *a_t == b { - Ok(()) - } else { - Err((a_t.clone(), b)) - } - } - } - } - - pub fn has_value(&mut self, id: K) -> bool { - self.get(id).value.is_some() - } - - pub fn probe(&mut self, a_id: K) -> Option<V> { - self.get(a_id).value.clone() - } -} - -/////////////////////////////////////////////////////////////////////////// - -// Integral type keys - -pub trait ToType<'tcx> { - fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>; -} - -impl UnifyKey for ty::IntVid { - type Value = Option<IntVarValue>; - fn index(&self) -> u32 { self.index } - fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } } - fn tag(_: Option<ty::IntVid>) -> &'static str { "IntVid" } -} - -impl<'tcx> ToType<'tcx> for IntVarValue { - fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { - match *self { - ty::IntType(i) => ty::mk_mach_int(tcx, i), - ty::UintType(i) => ty::mk_mach_uint(tcx, i), - } - } -} - -impl UnifyValue for Option<IntVarValue> { } - -// Floating point type keys - -impl UnifyKey for ty::FloatVid { - type Value = Option<ast::FloatTy>; - fn index(&self) -> u32 { self.index } - fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } } - fn tag(_: Option<ty::FloatVid>) -> &'static str { "FloatVid" } -} - -impl UnifyValue for Option<ast::FloatTy> { -} - -impl<'tcx> ToType<'tcx> for ast::FloatTy { - fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { - ty::mk_mach_float(tcx, *self) - } -} diff --git a/src/librustc/middle/infer/unify_key.rs b/src/librustc/middle/infer/unify_key.rs new file mode 100644 index 00000000000..6b23e2c5029 --- /dev/null +++ b/src/librustc/middle/infer/unify_key.rs @@ -0,0 +1,48 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::ty::{self, IntVarValue, Ty}; +use rustc_data_structures::unify::UnifyKey; +use syntax::ast; + +pub trait ToType<'tcx> { + fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>; +} + +impl UnifyKey for ty::IntVid { + type Value = Option<IntVarValue>; + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } } + fn tag(_: Option<ty::IntVid>) -> &'static str { "IntVid" } +} + +impl<'tcx> ToType<'tcx> for IntVarValue { + fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { + match *self { + ty::IntType(i) => ty::mk_mach_int(tcx, i), + ty::UintType(i) => ty::mk_mach_uint(tcx, i), + } + } +} + +// Floating point type keys + +impl UnifyKey for ty::FloatVid { + type Value = Option<ast::FloatTy>; + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } } + fn tag(_: Option<ty::FloatVid>) -> &'static str { "FloatVid" } +} + +impl<'tcx> ToType<'tcx> for ast::FloatTy { + fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { + ty::mk_mach_float(tcx, *self) + } +} diff --git a/src/librustc/util/snapshot_vec.rs b/src/librustc/util/snapshot_vec.rs deleted file mode 100644 index d2e0b3aec2f..00000000000 --- a/src/librustc/util/snapshot_vec.rs +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! A utility class for implementing "snapshottable" things; a snapshottable data structure permits -//! you to take a snapshot (via `start_snapshot`) and then, after making some changes, elect either -//! to rollback to the start of the snapshot or commit those changes. -//! -//! This vector is intended to be used as part of an abstraction, not serve as a complete -//! abstraction on its own. As such, while it will roll back most changes on its own, it also -//! supports a `get_mut` operation that gives you an arbitrary mutable pointer into the vector. To -//! ensure that any changes you make this with this pointer are rolled back, you must invoke -//! `record` to record any changes you make and also supplying a delegate capable of reversing -//! those changes. -use self::UndoLog::*; - -use std::mem; - -pub enum UndoLog<D:SnapshotVecDelegate> { - /// Indicates where a snapshot started. - OpenSnapshot, - - /// Indicates a snapshot that has been committed. - CommittedSnapshot, - - /// New variable with given index was created. - NewElem(usize), - - /// Variable with given index was changed *from* the given value. - SetElem(usize, D::Value), - - /// Extensible set of actions - Other(D::Undo) -} - -pub struct SnapshotVec<D:SnapshotVecDelegate> { - values: Vec<D::Value>, - undo_log: Vec<UndoLog<D>>, - delegate: D -} - -// Snapshots are tokens that should be created/consumed linearly. -pub struct Snapshot { - // Length of the undo log at the time the snapshot was taken. - length: usize, -} - -pub trait SnapshotVecDelegate { - type Value; - type Undo; - - fn reverse(&mut self, values: &mut Vec<Self::Value>, action: Self::Undo); -} - -impl<D:SnapshotVecDelegate> SnapshotVec<D> { - pub fn new(delegate: D) -> SnapshotVec<D> { - SnapshotVec { - values: Vec::new(), - undo_log: Vec::new(), - delegate: delegate - } - } - - fn in_snapshot(&self) -> bool { - !self.undo_log.is_empty() - } - - pub fn record(&mut self, action: D::Undo) { - if self.in_snapshot() { - self.undo_log.push(Other(action)); - } - } - - pub fn push(&mut self, elem: D::Value) -> usize { - let len = self.values.len(); - self.values.push(elem); - - if self.in_snapshot() { - self.undo_log.push(NewElem(len)); - } - - len - } - - pub fn get<'a>(&'a self, index: usize) -> &'a D::Value { - &self.values[index] - } - - /// Returns a mutable pointer into the vec; whatever changes you make here cannot be undone - /// automatically, so you should be sure call `record()` with some sort of suitable undo - /// action. - pub fn get_mut<'a>(&'a mut self, index: usize) -> &'a mut D::Value { - &mut self.values[index] - } - - /// Updates the element at the given index. The old value will saved (and perhaps restored) if - /// a snapshot is active. - pub fn set(&mut self, index: usize, new_elem: D::Value) { - let old_elem = mem::replace(&mut self.values[index], new_elem); - if self.in_snapshot() { - self.undo_log.push(SetElem(index, old_elem)); - } - } - - pub fn start_snapshot(&mut self) -> Snapshot { - let length = self.undo_log.len(); - self.undo_log.push(OpenSnapshot); - Snapshot { length: length } - } - - pub fn actions_since_snapshot(&self, - snapshot: &Snapshot) - -> &[UndoLog<D>] { - &self.undo_log[snapshot.length..] - } - - fn assert_open_snapshot(&self, snapshot: &Snapshot) { - // Or else there was a failure to follow a stack discipline: - assert!(self.undo_log.len() > snapshot.length); - - // Invariant established by start_snapshot(): - assert!( - match self.undo_log[snapshot.length] { - OpenSnapshot => true, - _ => false - }); - } - - pub fn rollback_to(&mut self, snapshot: Snapshot) { - debug!("rollback_to({})", snapshot.length); - - self.assert_open_snapshot(&snapshot); - - while self.undo_log.len() > snapshot.length + 1 { - match self.undo_log.pop().unwrap() { - OpenSnapshot => { - // This indicates a failure to obey the stack discipline. - panic!("Cannot rollback an uncommitted snapshot"); - } - - CommittedSnapshot => { - // This occurs when there are nested snapshots and - // the inner is committed but outer is rolled back. - } - - NewElem(i) => { - self.values.pop(); - assert!(self.values.len() == i); - } - - SetElem(i, v) => { - self.values[i] = v; - } - - Other(u) => { - self.delegate.reverse(&mut self.values, u); - } - } - } - - let v = self.undo_log.pop().unwrap(); - assert!(match v { OpenSnapshot => true, _ => false }); - assert!(self.undo_log.len() == snapshot.length); - } - - /// Commits all changes since the last snapshot. Of course, they - /// can still be undone if there is a snapshot further out. - pub fn commit(&mut self, snapshot: Snapshot) { - debug!("commit({})", snapshot.length); - - self.assert_open_snapshot(&snapshot); - - if snapshot.length == 0 { - // The root snapshot. - self.undo_log.truncate(0); - } else { - self.undo_log[snapshot.length] = CommittedSnapshot; - } - } -} |
