diff --git a/Cargo.lock b/Cargo.lock index e01432b1ce..5f5ce9bd59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4140,7 +4140,6 @@ dependencies = [ "roc_module", "roc_region", "static_assertions 1.1.0", - "ven_ena", ] [[package]] @@ -5076,13 +5075,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "ven_ena" -version = "0.13.1" -dependencies = [ - "log", -] - [[package]] name = "ven_graph" version = "2.0.5-pre" diff --git a/Cargo.toml b/Cargo.toml index 9ead607540..6ec7d2b7d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,6 @@ members = [ "compiler/test_gen", "compiler/roc_target", "compiler/debug_flags", - "vendor/ena", "vendor/inkwell", "vendor/pathfinding", "vendor/pretty", diff --git a/compiler/types/Cargo.toml b/compiler/types/Cargo.toml index a27e2ad4c9..266d118d6c 100644 --- a/compiler/types/Cargo.toml +++ b/compiler/types/Cargo.toml @@ -11,6 +11,5 @@ roc_region = { path = "../region" } roc_module = { path = "../module" } roc_error_macros = {path="../../error_macros"} roc_debug_flags = {path="../debug_flags"} -ven_ena = { path = "../../vendor/ena" } bumpalo = { version = "3.8.0", features = ["collections"] } static_assertions = "1.1.0" diff --git a/compiler/types/src/subs.rs b/compiler/types/src/subs.rs index 7cef696984..7faf9a4585 100644 --- a/compiler/types/src/subs.rs +++ b/compiler/types/src/subs.rs @@ -8,7 +8,6 @@ use roc_module::ident::{Lowercase, TagName, Uppercase}; use roc_module::symbol::Symbol; use std::fmt; use std::iter::{once, Iterator, Map}; -use ven_ena::unify::UnifyKey; use crate::unification_table::{Snapshot, UnificationTable}; @@ -1178,22 +1177,6 @@ impl fmt::Debug for Variable { } } -impl UnifyKey for Variable { - type Value = Descriptor; - - fn index(&self) -> u32 { - self.0 - } - - fn from_index(index: u32) -> Self { - Variable(index) - } - - fn tag() -> &'static str { - "Variable" - } -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct LambdaSet(pub Variable); diff --git a/vendor/ena/Cargo.toml b/vendor/ena/Cargo.toml deleted file mode 100644 index bf28482fde..0000000000 --- a/vendor/ena/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "ven_ena" -description = "Union-find, congruence closure, and other unification code. Based on code from rustc." -license = "MIT/Apache-2.0" -homepage = "https://github.com/rust-lang-nursery/ena" -repository = "https://github.com/rust-lang-nursery/ena" -version = "0.13.1" -authors = ["Niko Matsakis "] -readme = "README.md" -keywords = ["unification", "union-find"] - -[dependencies] -log = "0.4.14" diff --git a/vendor/ena/LICENSE-APACHE b/vendor/ena/LICENSE-APACHE deleted file mode 100644 index 16fe87b06e..0000000000 --- a/vendor/ena/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/ena/LICENSE-MIT b/vendor/ena/LICENSE-MIT deleted file mode 100644 index 25597d5838..0000000000 --- a/vendor/ena/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2010 The Rust Project Developers - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/vendor/ena/src/bitvec.rs b/vendor/ena/src/bitvec.rs deleted file mode 100644 index 3677c8c5e5..0000000000 --- a/vendor/ena/src/bitvec.rs +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// A very simple BitVector type. -pub struct BitVector { - data: Vec, -} - -impl BitVector { - pub fn new(num_bits: usize) -> BitVector { - let num_words = u64s(num_bits); - BitVector { data: vec![0; num_words] } - } - - pub fn contains(&self, bit: usize) -> bool { - let (word, mask) = word_mask(bit); - (self.data[word] & mask) != 0 - } - - /// Returns true if the bit has changed. - pub fn insert(&mut self, bit: usize) -> bool { - let (word, mask) = word_mask(bit); - let data = &mut self.data[word]; - let value = *data; - let new_value = value | mask; - *data = new_value; - new_value != value - } - - pub fn insert_all(&mut self, all: &BitVector) -> bool { - assert!(self.data.len() == all.data.len()); - let mut changed = false; - for (i, j) in self.data.iter_mut().zip(&all.data) { - let value = *i; - *i = value | *j; - if value != *i { - changed = true; - } - } - changed - } - - pub fn grow(&mut self, num_bits: usize) { - let num_words = u64s(num_bits); - let extra_words = self.data.len() - num_words; - self.data.extend((0..extra_words).map(|_| 0)); - } - - /// Iterates over indexes of set bits in a sorted order - pub fn iter<'a>(&'a self) -> BitVectorIter<'a> { - BitVectorIter { - iter: self.data.iter(), - current: 0, - idx: 0, - } - } -} - -pub struct BitVectorIter<'a> { - iter: ::std::slice::Iter<'a, u64>, - current: u64, - idx: usize, -} - -impl<'a> Iterator for BitVectorIter<'a> { - type Item = usize; - fn next(&mut self) -> Option { - while self.current == 0 { - self.current = if let Some(&i) = self.iter.next() { - if i == 0 { - self.idx += 64; - continue; - } else { - self.idx = u64s(self.idx) * 64; - i - } - } else { - return None; - } - } - let offset = self.current.trailing_zeros() as usize; - self.current >>= offset; - self.current >>= 1; // shift otherwise overflows for 0b1000_0000_…_0000 - self.idx += offset + 1; - return Some(self.idx - 1); - } -} - -/// A "bit matrix" is basically a square matrix of booleans -/// represented as one gigantic bitvector. In other words, it is as if -/// you have N bitvectors, each of length N. Note that `elements` here is `N`/ -#[derive(Clone)] -pub struct BitMatrix { - elements: usize, - vector: Vec, -} - -impl BitMatrix { - // Create a new `elements x elements` matrix, initially empty. - pub fn new(elements: usize) -> BitMatrix { - // For every element, we need one bit for every other - // element. Round up to an even number of u64s. - let u64s_per_elem = u64s(elements); - BitMatrix { - elements: elements, - vector: vec![0; elements * u64s_per_elem], - } - } - - /// The range of bits for a given element. - fn range(&self, element: usize) -> (usize, usize) { - let u64s_per_elem = u64s(self.elements); - let start = element * u64s_per_elem; - (start, start + u64s_per_elem) - } - - pub fn add(&mut self, source: usize, target: usize) -> bool { - let (start, _) = self.range(source); - let (word, mask) = word_mask(target); - let mut vector = &mut self.vector[..]; - let v1 = vector[start + word]; - let v2 = v1 | mask; - vector[start + word] = v2; - v1 != v2 - } - - /// Do the bits from `source` contain `target`? - /// - /// Put another way, if the matrix represents (transitive) - /// reachability, can `source` reach `target`? - pub fn contains(&self, source: usize, target: usize) -> bool { - let (start, _) = self.range(source); - let (word, mask) = word_mask(target); - (self.vector[start + word] & mask) != 0 - } - - /// Returns those indices that are reachable from both `a` and - /// `b`. This is an O(n) operation where `n` is the number of - /// elements (somewhat independent from the actual size of the - /// intersection, in particular). - pub fn intersection(&self, a: usize, b: usize) -> Vec { - let (a_start, a_end) = self.range(a); - let (b_start, b_end) = self.range(b); - let mut result = Vec::with_capacity(self.elements); - for (base, (i, j)) in (a_start..a_end).zip(b_start..b_end).enumerate() { - let mut v = self.vector[i] & self.vector[j]; - for bit in 0..64 { - if v == 0 { - break; - } - if v & 0x1 != 0 { - result.push(base * 64 + bit); - } - v >>= 1; - } - } - result - } - - /// Add the bits from `read` to the bits from `write`, - /// return true if anything changed. - /// - /// This is used when computing transitive reachability because if - /// you have an edge `write -> read`, because in that case - /// `write` can reach everything that `read` can (and - /// potentially more). - pub fn merge(&mut self, read: usize, write: usize) -> bool { - let (read_start, read_end) = self.range(read); - let (write_start, write_end) = self.range(write); - let vector = &mut self.vector[..]; - let mut changed = false; - for (read_index, write_index) in (read_start..read_end).zip(write_start..write_end) { - let v1 = vector[write_index]; - let v2 = v1 | vector[read_index]; - vector[write_index] = v2; - changed = changed | (v1 != v2); - } - changed - } -} - -fn u64s(elements: usize) -> usize { - (elements + 63) / 64 -} - -fn word_mask(index: usize) -> (usize, u64) { - let word = index / 64; - let mask = 1 << (index % 64); - (word, mask) -} - -#[test] -fn bitvec_iter_works() { - let mut bitvec = BitVector::new(100); - bitvec.insert(1); - bitvec.insert(10); - bitvec.insert(19); - bitvec.insert(62); - bitvec.insert(63); - bitvec.insert(64); - bitvec.insert(65); - bitvec.insert(66); - bitvec.insert(99); - assert_eq!(bitvec.iter().collect::>(), - [1, 10, 19, 62, 63, 64, 65, 66, 99]); -} - -#[test] -fn bitvec_iter_works_2() { - let mut bitvec = BitVector::new(300); - bitvec.insert(1); - bitvec.insert(10); - bitvec.insert(19); - bitvec.insert(62); - bitvec.insert(66); - bitvec.insert(99); - bitvec.insert(299); - assert_eq!(bitvec.iter().collect::>(), - [1, 10, 19, 62, 66, 99, 299]); - -} - -#[test] -fn bitvec_iter_works_3() { - let mut bitvec = BitVector::new(319); - bitvec.insert(0); - bitvec.insert(127); - bitvec.insert(191); - bitvec.insert(255); - bitvec.insert(319); - assert_eq!(bitvec.iter().collect::>(), [0, 127, 191, 255, 319]); -} - -#[test] -fn union_two_vecs() { - let mut vec1 = BitVector::new(65); - let mut vec2 = BitVector::new(65); - assert!(vec1.insert(3)); - assert!(!vec1.insert(3)); - assert!(vec2.insert(5)); - assert!(vec2.insert(64)); - assert!(vec1.insert_all(&vec2)); - assert!(!vec1.insert_all(&vec2)); - assert!(vec1.contains(3)); - assert!(!vec1.contains(4)); - assert!(vec1.contains(5)); - assert!(!vec1.contains(63)); - assert!(vec1.contains(64)); -} - -#[test] -fn grow() { - let mut vec1 = BitVector::new(65); - assert!(vec1.insert(3)); - assert!(!vec1.insert(3)); - assert!(vec1.insert(5)); - assert!(vec1.insert(64)); - vec1.grow(128); - assert!(vec1.contains(3)); - assert!(vec1.contains(5)); - assert!(vec1.contains(64)); - assert!(!vec1.contains(126)); -} - -#[test] -fn matrix_intersection() { - let mut vec1 = BitMatrix::new(200); - - // (*) Elements reachable from both 2 and 65. - - vec1.add(2, 3); - vec1.add(2, 6); - vec1.add(2, 10); // (*) - vec1.add(2, 64); // (*) - vec1.add(2, 65); - vec1.add(2, 130); - vec1.add(2, 160); // (*) - - vec1.add(64, 133); - - vec1.add(65, 2); - vec1.add(65, 8); - vec1.add(65, 10); // (*) - vec1.add(65, 64); // (*) - vec1.add(65, 68); - vec1.add(65, 133); - vec1.add(65, 160); // (*) - - let intersection = vec1.intersection(2, 64); - assert!(intersection.is_empty()); - - let intersection = vec1.intersection(2, 65); - assert_eq!(intersection, &[10, 64, 160]); -} diff --git a/vendor/ena/src/lib.rs b/vendor/ena/src/lib.rs deleted file mode 100644 index 3a7485bcf4..0000000000 --- a/vendor/ena/src/lib.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! An implementation of union-find. See the `unify` module for more -//! details. - -pub mod snapshot_vec; -pub mod unify; - -#[macro_use] -extern crate log; diff --git a/vendor/ena/src/snapshot_vec.rs b/vendor/ena/src/snapshot_vec.rs deleted file mode 100644 index 5337d33445..0000000000 --- a/vendor/ena/src/snapshot_vec.rs +++ /dev/null @@ -1,399 +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 or the MIT license -// , 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::fmt; -use std::mem; -use std::ops; - -#[derive(Debug)] -pub enum UndoLog { - /// 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), -} - -/// A Vec where we have Debug overridden to render the indices like -/// a hashmap, since we really care about those when debugging one of these. -#[derive(Clone)] -struct BackingVec(Vec); - -pub struct SnapshotVec { - values: BackingVec, - undo_log: Vec>, - num_open_snapshots: usize, -} - -impl fmt::Debug for SnapshotVec -where - D: SnapshotVecDelegate, - D: fmt::Debug, - D::Undo: fmt::Debug, - D::Value: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - self.values.fmt(fmt) - } -} - -// Snapshots are tokens that should be created/consumed linearly. -pub struct Snapshot { - // Number of values at the time the snapshot was taken. - pub(crate) value_count: usize, - // Length of the undo log at the time the snapshot was taken. - undo_len: usize, -} - -pub trait SnapshotVecDelegate { - type Value; - type Undo; - - fn reverse(values: &mut Vec, action: Self::Undo); -} - -// HACK(eddyb) manual impl avoids `Default` bound on `D`. -impl Default for SnapshotVec { - fn default() -> Self { - SnapshotVec { - values: BackingVec(Vec::new()), - undo_log: Vec::new(), - num_open_snapshots: 0, - } - } -} - -impl fmt::Debug for BackingVec -where - T: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{{{{")?; - - for (index, elem) in self.0.iter().enumerate() { - write!(f, "\n {} => {:?},", index, elem)?; - } - - if !self.0.is_empty() { - writeln!(f)?; - } - - write!(f, "}}}}") - } -} - -impl SnapshotVec { - pub fn new() -> Self { - Self::default() - } - - pub fn with_capacity(c: usize) -> SnapshotVec { - SnapshotVec { - values: BackingVec(Vec::with_capacity(c)), - undo_log: Vec::new(), - num_open_snapshots: 0, - } - } - - fn in_snapshot(&self) -> bool { - self.num_open_snapshots > 0 - } - - pub fn record(&mut self, action: D::Undo) { - if self.in_snapshot() { - self.undo_log.push(Other(action)); - } - } - - pub fn len(&self) -> usize { - self.values.0.len() - } - - pub fn is_empty(&self) -> bool { - self.values.0.len() == 0 - } - - pub fn push(&mut self, elem: D::Value) -> usize { - let len = self.values.0.len(); - self.values.0.push(elem); - - if self.in_snapshot() { - self.undo_log.push(NewElem(len)); - } - - len - } - - pub fn get(&self, index: usize) -> &D::Value { - &self.values.0[index] - } - - /// Reserve space for new values, just like an ordinary vec. - pub fn reserve(&mut self, additional: usize) { - // This is not affected by snapshots or anything. - self.values.0.reserve(additional); - } - - /// 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(&mut self, index: usize) -> &mut D::Value { - &mut self.values.0[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.0[index], new_elem); - if self.in_snapshot() { - self.undo_log.push(SetElem(index, old_elem)); - } - } - - /// Updates all elements. Potentially more efficient -- but - /// otherwise equivalent to -- invoking `set` for each element. - pub fn set_all(&mut self, mut new_elems: impl FnMut(usize) -> D::Value) { - if !self.in_snapshot() { - for (index, slot) in self.values.0.iter_mut().enumerate() { - *slot = new_elems(index); - } - } else { - for i in 0..self.values.0.len() { - self.set(i, new_elems(i)); - } - } - } - - pub fn update(&mut self, index: usize, op: OP) - where - OP: FnOnce(&mut D::Value), - D::Value: Clone, - { - if self.in_snapshot() { - let old_elem = self.values.0[index].clone(); - self.undo_log.push(SetElem(index, old_elem)); - } - op(&mut self.values.0[index]); - } - - pub fn start_snapshot(&mut self) -> Snapshot { - self.num_open_snapshots += 1; - Snapshot { - value_count: self.values.0.len(), - undo_len: self.undo_log.len(), - } - } - - pub fn actions_since_snapshot(&self, snapshot: &Snapshot) -> &[UndoLog] { - &self.undo_log[snapshot.undo_len..] - } - - fn assert_open_snapshot(&self, snapshot: &Snapshot) { - // Failures here may indicate a failure to follow a stack discipline. - assert!(self.undo_log.len() >= snapshot.undo_len); - assert!(self.num_open_snapshots > 0); - } - - pub fn rollback_to(&mut self, snapshot: Snapshot) { - debug!("rollback_to({})", snapshot.undo_len); - - self.assert_open_snapshot(&snapshot); - - while self.undo_log.len() > snapshot.undo_len { - match self.undo_log.pop().unwrap() { - NewElem(i) => { - self.values.0.pop(); - assert!(self.values.0.len() == i); - } - - SetElem(i, v) => { - self.values.0[i] = v; - } - - Other(u) => { - D::reverse(&mut self.values.0, u); - } - } - } - - self.num_open_snapshots -= 1; - } - - /// 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.undo_len); - - self.assert_open_snapshot(&snapshot); - - if self.num_open_snapshots == 1 { - // The root snapshot. It's safe to clear the undo log because - // there's no snapshot further out that we might need to roll back - // to. - assert!(snapshot.undo_len == 0); - self.undo_log.clear(); - } - - self.num_open_snapshots -= 1; - } -} - -impl ops::Deref for SnapshotVec { - type Target = [D::Value]; - fn deref(&self) -> &[D::Value] { - &*self.values.0 - } -} - -impl ops::DerefMut for SnapshotVec { - fn deref_mut(&mut self) -> &mut [D::Value] { - &mut *self.values.0 - } -} - -impl ops::Index for SnapshotVec { - type Output = D::Value; - fn index(&self, index: usize) -> &D::Value { - self.get(index) - } -} - -impl ops::IndexMut for SnapshotVec { - fn index_mut(&mut self, index: usize) -> &mut D::Value { - self.get_mut(index) - } -} - -impl Extend for SnapshotVec { - fn extend(&mut self, iterable: T) - where - T: IntoIterator, - { - let initial_len = self.values.0.len(); - self.values.0.extend(iterable); - let final_len = self.values.0.len(); - - if self.in_snapshot() { - self.undo_log.extend((initial_len..final_len).map(NewElem)); - } - } -} - -impl Clone for SnapshotVec -where - D::Value: Clone, - D::Undo: Clone, -{ - fn clone(&self) -> Self { - SnapshotVec { - values: self.values.clone(), - undo_log: self.undo_log.clone(), - num_open_snapshots: self.num_open_snapshots, - } - } -} - -impl Clone for UndoLog -where - D::Value: Clone, - D::Undo: Clone, -{ - fn clone(&self) -> Self { - match *self { - NewElem(i) => NewElem(i), - SetElem(i, ref v) => SetElem(i, v.clone()), - Other(ref u) => Other(u.clone()), - } - } -} - -impl SnapshotVecDelegate for i32 { - type Value = i32; - type Undo = (); - - fn reverse(_: &mut Vec, _: ()) {} -} - -#[test] -fn basic() { - let mut vec: SnapshotVec = SnapshotVec::default(); - assert!(!vec.in_snapshot()); - assert_eq!(vec.len(), 0); - vec.push(22); - vec.push(33); - assert_eq!(vec.len(), 2); - assert_eq!(*vec.get(0), 22); - assert_eq!(*vec.get(1), 33); - vec.set(1, 34); - assert_eq!(vec.len(), 2); - assert_eq!(*vec.get(0), 22); - assert_eq!(*vec.get(1), 34); - - let snapshot = vec.start_snapshot(); - assert!(vec.in_snapshot()); - - vec.push(44); - vec.push(55); - vec.set(1, 35); - assert_eq!(vec.len(), 4); - assert_eq!(*vec.get(0), 22); - assert_eq!(*vec.get(1), 35); - assert_eq!(*vec.get(2), 44); - assert_eq!(*vec.get(3), 55); - - vec.rollback_to(snapshot); - assert!(!vec.in_snapshot()); - - assert_eq!(vec.len(), 2); - assert_eq!(*vec.get(0), 22); - assert_eq!(*vec.get(1), 34); -} - -#[test] -#[should_panic] -fn out_of_order() { - let mut vec: SnapshotVec = SnapshotVec::default(); - vec.push(22); - let snapshot1 = vec.start_snapshot(); - vec.push(33); - let snapshot2 = vec.start_snapshot(); - vec.push(44); - vec.rollback_to(snapshot1); // bogus, but accepted - vec.rollback_to(snapshot2); // asserts -} - -#[test] -fn nested_commit_then_rollback() { - let mut vec: SnapshotVec = SnapshotVec::default(); - vec.push(22); - let snapshot1 = vec.start_snapshot(); - let snapshot2 = vec.start_snapshot(); - vec.set(0, 23); - vec.commit(snapshot2); - assert_eq!(*vec.get(0), 23); - vec.rollback_to(snapshot1); - assert_eq!(*vec.get(0), 22); -} diff --git a/vendor/ena/src/unify/backing_vec.rs b/vendor/ena/src/unify/backing_vec.rs deleted file mode 100644 index e65c882f43..0000000000 --- a/vendor/ena/src/unify/backing_vec.rs +++ /dev/null @@ -1,249 +0,0 @@ -use crate::snapshot_vec as sv; -#[cfg(feature = "persistent")] -use im_rc::Vector; -use std::fmt::{self, Debug}; -use std::marker::PhantomData; -use std::ops::{self, Range}; - -use super::{UnifyKey, VarValue}; - -#[allow(dead_code)] // rustc BUG -#[allow(type_alias_bounds)] -type Key = ::Key; - -/// Largely internal trait implemented by the unification table -/// backing store types. The most common such type is `InPlace`, -/// which indicates a standard, mutable unification table. -pub trait UnificationStore: - ops::Index>> - + ops::IndexMut>> - + Clone - + Default -{ - type Key: UnifyKey; - type Value: Clone + Debug; - type Snapshot; - - fn start_snapshot(&mut self) -> Self::Snapshot; - - fn rollback_to(&mut self, snapshot: Self::Snapshot); - - fn commit(&mut self, snapshot: Self::Snapshot); - - fn values_since_snapshot(&self, snapshot: &Self::Snapshot) -> Range; - - fn reset_unifications(&mut self, value: impl FnMut(usize) -> VarValue); - - fn len(&self) -> usize; - - fn is_empty(&self) -> bool; - - fn push(&mut self, value: VarValue); - - fn reserve(&mut self, num_new_values: usize); - - fn update(&mut self, index: usize, op: F) - where - F: FnOnce(&mut VarValue); - - fn tag() -> &'static str { - Self::Key::tag() - } -} - -/// Backing store for an in-place unification table. -/// Not typically used directly. -#[derive(Clone)] -pub struct InPlace { - values: sv::SnapshotVec>, -} - -impl fmt::Debug for InPlace -where - K: UnifyKey, - K: Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.values.fmt(f) - } -} - -// HACK(eddyb) manual impl avoids `Default` bound on `K`. -impl Default for InPlace { - fn default() -> Self { - InPlace { - values: sv::SnapshotVec::new(), - } - } -} - -impl UnificationStore for InPlace { - type Key = K; - type Value = K::Value; - type Snapshot = sv::Snapshot; - - #[inline] - fn start_snapshot(&mut self) -> Self::Snapshot { - self.values.start_snapshot() - } - - #[inline] - fn rollback_to(&mut self, snapshot: Self::Snapshot) { - self.values.rollback_to(snapshot); - } - - #[inline] - fn commit(&mut self, snapshot: Self::Snapshot) { - self.values.commit(snapshot); - } - - #[inline] - fn values_since_snapshot(&self, snapshot: &Self::Snapshot) -> Range { - snapshot.value_count..self.len() - } - - #[inline] - fn reset_unifications(&mut self, value: impl FnMut(usize) -> VarValue) { - self.values.set_all(value); - } - - fn len(&self) -> usize { - self.values.len() - } - - fn is_empty(&self) -> bool { - self.values.len() == 0 - } - - #[inline] - fn push(&mut self, value: VarValue) { - self.values.push(value); - } - - #[inline] - fn reserve(&mut self, num_new_values: usize) { - self.values.reserve(num_new_values); - } - - #[inline] - fn update(&mut self, index: usize, op: F) - where - F: FnOnce(&mut VarValue), - { - self.values.update(index, op) - } -} - -impl ops::Index for InPlace -where - K: UnifyKey, -{ - type Output = VarValue; - fn index(&self, index: usize) -> &VarValue { - &self.values[index] - } -} - -impl ops::IndexMut for InPlace -where - K: UnifyKey, -{ - fn index_mut(&mut self, index: usize) -> &mut VarValue { - &mut self.values[index] - } -} - -#[derive(Copy, Clone, Debug)] -struct Delegate(PhantomData); - -impl sv::SnapshotVecDelegate for Delegate { - type Value = VarValue; - type Undo = (); - - fn reverse(_: &mut Vec>, _: ()) {} -} - -#[cfg(feature = "persistent")] -#[derive(Clone, Debug)] -pub struct Persistent { - values: Vector>, -} - -// HACK(eddyb) manual impl avoids `Default` bound on `K`. -#[cfg(feature = "persistent")] -impl Default for Persistent { - fn default() -> Self { - Persistent { - values: Vector::new(), - } - } -} - -#[cfg(feature = "persistent")] -impl UnificationStore for Persistent { - type Key = K; - type Value = K::Value; - type Snapshot = Self; - - #[inline] - fn start_snapshot(&mut self) -> Self::Snapshot { - self.clone() - } - - #[inline] - fn rollback_to(&mut self, snapshot: Self::Snapshot) { - *self = snapshot; - } - - #[inline] - fn commit(&mut self, _snapshot: Self::Snapshot) {} - - #[inline] - fn values_since_snapshot(&self, snapshot: &Self::Snapshot) -> Range { - snapshot.len()..self.len() - } - - #[inline] - fn reset_unifications(&mut self, mut value: impl FnMut(usize) -> VarValue) { - // Without extending dogged, there isn't obviously a more - // efficient way to do this. But it's pretty dumb. Maybe - // dogged needs a `map`. [NOTE: revisit in light of replacing dogged with im_rc!] - for i in 0..self.values.len() { - self.values[i] = value(i); - } - } - - fn len(&self) -> usize { - self.values.len() - } - - #[inline] - fn push(&mut self, value: VarValue) { - self.values.push(value); - } - - #[inline] - fn reserve(&mut self, _num_new_values: usize) { - // not obviously relevant to Vector. - } - - #[inline] - fn update(&mut self, index: usize, op: F) - where - F: FnOnce(&mut VarValue), - { - let p = &mut self.values[index]; - op(p); - } -} - -#[cfg(feature = "persistent")] -impl ops::Index for Persistent -where - K: UnifyKey, -{ - type Output = VarValue; - fn index(&self, index: usize) -> &VarValue { - &self.values[index] - } -} diff --git a/vendor/ena/src/unify/mod.rs b/vendor/ena/src/unify/mod.rs deleted file mode 100644 index acc45a469e..0000000000 --- a/vendor/ena/src/unify/mod.rs +++ /dev/null @@ -1,500 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Union-find implementation. The main type is `UnificationTable`. -//! -//! You can define your own type for the *keys* in the table, but you -//! must implement `UnifyKey` for that type. The assumption is that -//! keys will be newtyped integers, hence we require that they -//! implement `Copy`. -//! -//! Keys can have values associated with them. The assumption is that -//! these values are cheaply cloneable (ideally, `Copy`), and some of -//! the interfaces are oriented around that assumption. If you just -//! want the classical "union-find" algorithm where you group things -//! into sets, use the `Value` type of `()`. -//! -//! When you have keys with non-trivial values, you must also define -//! how those values can be merged. As part of doing this, you can -//! define the "error" type to return on error; if errors are not -//! possible, use `NoError` (an uninstantiable struct). Using this -//! type also unlocks various more ergonomic methods (e.g., `union()` -//! in place of `unify_var_var()`). -//! -//! The best way to see how it is used is to read the `tests.rs` file; -//! search for e.g. `UnitKey`. - -use std::cmp::Ordering; -use std::fmt::{self, Debug}; -use std::marker; -use std::ops::Range; - -mod backing_vec; -pub use self::backing_vec::{InPlace, UnificationStore}; - -#[cfg(feature = "persistent")] -pub use self::backing_vec::Persistent; - -/// 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`, representing some -/// (possibly not yet known) sort of integer. -/// -/// Clients are expected to provide implementations of this trait; you -/// can see some examples in the `test` module. -pub trait UnifyKey: Copy + Clone + Debug + PartialEq { - type Value: Clone + Debug; - - fn index(&self) -> u32; - - fn from_index(u: u32) -> Self; - - fn tag() -> &'static str; - - /// If true, then `self` should be preferred as root to `other`. - /// Note that we assume a consistent partial ordering, so - /// returning true implies that `other.prefer_as_root_to(self)` - /// would return false. If there is no ordering between two keys - /// (i.e., `a.prefer_as_root_to(b)` and `b.prefer_as_root_to(a)` - /// both return false) then the rank will be used to determine the - /// root in an optimal way. - /// - /// NB. The only reason to implement this method is if you want to - /// control what value is returned from `find()`. In general, it - /// is better to let the unification table determine the root, - /// since overriding the rank can cause execution time to increase - /// dramatically. - #[allow(unused_variables)] - fn order_roots( - a: Self, - a_value: &Self::Value, - b: Self, - b_value: &Self::Value, - ) -> Option<(Self, Self)> { - None - } -} - -/// A struct which can never be instantiated. Used -/// for the error type for infallible cases. -#[derive(Debug)] -pub struct NoError { - _dummy: (), -} - -/// 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 -/// . -#[derive(PartialEq, Clone)] -pub struct VarValue { - // FIXME pub - parent: K, // if equal to self, this is a root - pub value: K::Value, // value assigned (only relevant to root) - rank: u32, // max depth (only relevant to root) -} - -impl fmt::Debug for VarValue -where - K: UnifyKey, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "p: {:?}, c: {:?}", self.parent, self.value) - } -} - -/// Table of unification keys and their values. You must define a key type K -/// that implements the `UnifyKey` trait. Unification tables can be used in two-modes: -/// -/// - in-place (`UnificationTable>` or `InPlaceUnificationTable`): -/// - This is the standard mutable mode, where the array is modified -/// in place. -/// - To do backtracking, you can employ the `snapshot` and `rollback_to` -/// methods. -/// - persistent (`UnificationTable>` or `PersistentUnificationTable`): -/// - In this mode, we use a persistent vector to store the data, so that -/// cloning the table is an O(1) operation. -/// - This implies that ordinary operations are quite a bit slower though. -/// - Requires the `persistent` feature be selected in your Cargo.toml file. -#[derive(Clone, Default)] -pub struct UnificationTable { - /// Indicates the current value of each key. - values: S, -} - -impl fmt::Debug for UnificationTable -where - S: UnificationStore, - S: Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.values.fmt(f) - } -} - -/// A unification table that uses an "in-place" vector. -#[allow(type_alias_bounds)] -pub type InPlaceUnificationTable = UnificationTable>; - -/// A unification table that uses a "persistent" vector. -#[cfg(feature = "persistent")] -#[allow(type_alias_bounds)] -pub type PersistentUnificationTable = UnificationTable>; - -/// 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 { - // Link snapshot to the unification store `S` of the table. - marker: marker::PhantomData, - snapshot: S::Snapshot, -} - -impl VarValue { - fn new_var(key: K, value: K::Value) -> VarValue { - VarValue::new(key, value, 0) - } - - fn new(parent: K, value: K::Value, rank: u32) -> VarValue { - VarValue { - parent, // this is a root - value, - rank, - } - } - - fn redirect(&mut self, to: K) { - self.parent = to; - } - - fn root(&mut self, rank: u32, value: K::Value) { - self.rank = rank; - self.value = value; - } - - #[inline(always)] - fn parent(&self, self_key: K) -> Option { - self.if_not_self(self.parent, self_key) - } - - fn raw_parent(&self) -> K { - self.parent - } - - #[inline(always)] - fn if_not_self(&self, key: K, self_key: K) -> Option { - if key == self_key { - None - } else { - Some(key) - } - } -} - -// We can't use V:LatticeValue, much as I would like to, -// because frequently the pattern is that V=Option for some -// other type parameter U, and we have no way to say -// Option:LatticeValue. - -impl UnificationTable { - pub fn new() -> Self { - Self::default() - } - - /// Starts a new snapshot. Each snapshot must be either - /// rolled back or committed in a "LIFO" (stack) order. - pub fn snapshot(&mut self) -> Snapshot { - Snapshot { - marker: marker::PhantomData::, - 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) { - debug!("{}: rollback_to()", S::tag()); - 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) { - debug!("{}: commit()", S::tag()); - self.values.commit(snapshot.snapshot); - } - - /// Creates a fresh key with the given value. - pub fn new_key(&mut self, value: S::Value) -> S::Key { - let len = self.values.len() as u32; - let key: S::Key = UnifyKey::from_index(len); - self.values.push(VarValue::new_var(key, value)); - debug!("{}: created new key: {:?}", S::tag(), key); - key - } - - /// Reserve memory for `num_new_keys` to be created. Does not - /// actually create the new keys; you must then invoke `new_key`. - pub fn reserve(&mut self, num_new_keys: usize) { - self.values.reserve(num_new_keys); - } - - /// Clears all unifications that have been performed, resetting to - /// the initial state. The values of each variable are given by - /// the closure. - pub fn reset_unifications(&mut self, mut value: impl FnMut(S::Key) -> S::Value) { - self.values.reset_unifications(|i| { - let key = UnifyKey::from_index(i as u32); - let value = value(key); - VarValue::new_var(key, value) - }); - } - - /// Returns the number of keys created so far. - pub fn len(&self) -> usize { - self.values.len() - } - - /// Returns true iff there have been no keys created yet. - pub fn is_empty(&self) -> bool { - self.values.len() == 0 - } - - /// Returns the keys of all variables created since the `snapshot`. - pub fn vars_since_snapshot(&self, snapshot: &Snapshot) -> Range { - let range = self.values.values_since_snapshot(&snapshot.snapshot); - S::Key::from_index(range.start as u32)..S::Key::from_index(range.end as u32) - } - - /// Obtains the current value for a particular key. - /// Not for end-users; they can use `probe_value`. - pub fn value(&self, key: S::Key) -> &VarValue { - &self.values[key.index() as usize] - } - - /// Obtains the current value for a particular key. - /// Not for end-users; they can use `probe_value`. - pub fn value_mut(&mut self, key: S::Key) -> &mut VarValue { - &mut self.values[key.index() as usize] - } - - /// Find the root node for `vid`. This uses the standard - /// union-find algorithm with path compression: - /// . - /// - /// NB. This is a building-block operation and you would probably - /// prefer to call `probe` below. - /// - /// This is an always-inlined version of this function for the hot - /// callsites. `uninlined_get_root_key` is the never-inlined version. - #[inline(always)] - pub fn inlined_get_root_key(&mut self, vid: S::Key) -> S::Key { - match self.value(vid).parent(vid) { - None => vid, - Some(redirect) => { - let root_key: S::Key = self.uninlined_get_root_key(redirect); - if root_key != redirect { - // Path compression - self.update_value(vid, |value| value.parent = root_key); - } - - root_key - } - } - } - - // This is a never-inlined version of this function for cold callsites. - // 'inlined_get_root_key` is the always-inlined version. - #[inline(never)] - fn uninlined_get_root_key(&mut self, vid: S::Key) -> S::Key { - self.inlined_get_root_key(vid) - } - - #[inline(always)] - pub fn get_root_key_without_compacting(&self, mut vid: S::Key) -> S::Key { - while let Some(redirect) = self.value(vid).parent(vid) { - vid = redirect; - } - - vid - } - - pub fn is_redirect(&self, vid: S::Key) -> bool { - self.value(vid).raw_parent() != vid - } - - pub fn update_value(&mut self, key: S::Key, op: OP) - where - OP: FnOnce(&mut VarValue), - { - self.values.update(key.index() as usize, op); - debug!("Updated variable {:?} to {:?}", key, self.value(key)); - } - - /// 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. - pub fn unify_roots(&mut self, key_a: S::Key, key_b: S::Key, new_value: S::Value) { - debug!("unify(key_a={:?}, key_b={:?})", key_a, key_b); - - let rank_a = self.value(key_a).rank; - let rank_b = self.value(key_b).rank; - if let Some((new_root, redirected)) = S::Key::order_roots( - key_a, - &self.value(key_a).value, - key_b, - &self.value(key_b).value, - ) { - // compute the new rank for the new root that they chose; - // this may not be the optimal choice. - let new_rank = if new_root == key_a { - debug_assert!(redirected == key_b); - if rank_a > rank_b { - rank_a - } else { - rank_b + 1 - } - } else { - debug_assert!(new_root == key_b); - debug_assert!(redirected == key_a); - if rank_b > rank_a { - rank_b - } else { - rank_a + 1 - } - }; - self.redirect_root(new_rank, redirected, new_root, new_value); - } else { - match rank_a.cmp(&rank_b) { - Ordering::Greater => { - // a has greater rank, so a should become b's parent, - // i.e., b should redirect to a. - self.redirect_root(rank_a, key_b, key_a, new_value); - } - Ordering::Less => { - // b has greater rank, so a should redirect to b. - self.redirect_root(rank_b, key_a, key_b, new_value); - } - Ordering::Equal => { - // If equal, redirect one to the other and increment the - // other's rank. - self.redirect_root(rank_a + 1, key_a, key_b, new_value); - } - } - } - } - - /// Internal method to redirect `old_root_key` (which is currently - /// a root) to a child of `new_root_key` (which will remain a - /// root). The rank and value of `new_root_key` will be updated to - /// `new_rank` and `new_value` respectively. - fn redirect_root( - &mut self, - new_rank: u32, - old_root_key: S::Key, - new_root_key: S::Key, - new_value: S::Value, - ) { - self.update_value(old_root_key, |old_root_value| { - old_root_value.redirect(new_root_key); - }); - self.update_value(new_root_key, |new_root_value| { - new_root_value.root(new_rank, new_value); - }); - } -} - -/// //////////////////////////////////////////////////////////////////////// -/// Public API - -impl<'tcx, S, K, V> UnificationTable -where - S: UnificationStore, - K: UnifyKey, - V: Clone + Debug, -{ - /// Given two keys, indicates whether they have been unioned together. - pub fn unioned(&mut self, a_id: K1, b_id: K2) -> bool - where - K1: Into, - K2: Into, - { - self.find(a_id) == self.find(b_id) - } - - /// Given a key, returns the (current) root key. - pub fn find(&mut self, id: K1) -> K - where - K1: Into, - { - let id = id.into(); - self.inlined_get_root_key(id) - } - - /// Returns the current value for the given key. If the key has - /// been union'd, this will give the value from the current root. - #[inline(always)] - pub fn probe_value(&mut self, id: K1) -> V - where - K1: Into, - { - let id = id.into(); - let id = self.inlined_get_root_key(id); - self.value(id).value.clone() - } - - /// Returns the current value for the given key. If the key has - /// been union'd, this will give the value from the current root. - #[inline(always)] - pub fn probe_value_ref(&self, id: K1) -> &VarValue - where - K1: Into, - { - let id = id.into(); - let id = self.get_root_key_without_compacting(id); - self.value(id) - } - - /// Returns the current value for the given key. If the key has - /// been union'd, this will give the value from the current root. - #[inline(always)] - pub fn probe_value_ref_mut(&mut self, id: K1) -> &mut VarValue - where - K1: Into, - { - let id = id.into(); - let id = self.inlined_get_root_key(id); - self.value_mut(id) - } - - /// This is for a debug_assert! in solve() only. Do not use it elsewhere! - #[inline(always)] - pub fn probe_value_without_compacting(&self, id: K1) -> V - where - K1: Into, - { - let id = id.into(); - let id = self.get_root_key_without_compacting(id); - - self.value(id).value.clone() - } -}