Skip to content

Commit 953c918

Browse files
committed
switch from InfallibleUnifyValue to Error associated type
1 parent 2f9a5e5 commit 953c918

File tree

3 files changed

+76
-36
lines changed

3 files changed

+76
-36
lines changed

src/cc/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use petgraph::graph::{Graph, NodeIndex};
99
use std::collections::HashMap;
1010
use std::fmt::Debug;
1111
use std::hash::Hash;
12-
use unify::{UnifyKey, UnifyValue, InfallibleUnifyValue, UnificationTable, UnionedKeys};
12+
use unify::{NoError, UnifyKey, UnifyValue, UnificationTable, UnionedKeys};
1313

1414
#[cfg(test)]
1515
mod test;
@@ -92,7 +92,9 @@ impl UnifyKey for Token {
9292
}
9393

9494
impl UnifyValue for KeyKind {
95-
fn unify_values(&kind1: &Self, &kind2: &Self) -> Result<Self, (Self, Self)> {
95+
type Error = NoError;
96+
97+
fn unify_values(&kind1: &Self, &kind2: &Self) -> Result<Self, NoError> {
9698
match (kind1, kind2) {
9799
(Generative, _) => Ok(Generative),
98100
(_, Generative) => Ok(Generative),
@@ -101,8 +103,6 @@ impl UnifyValue for KeyKind {
101103
}
102104
}
103105

104-
impl InfallibleUnifyValue for KeyKind {}
105-
106106
impl<K: Key> CongruenceClosure<K> {
107107
pub fn new() -> CongruenceClosure<K> {
108108
CongruenceClosure {

src/unify/mod.rs

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@
2222
//! into sets, use the `Value` type of `()`.
2323
//!
2424
//! When you have keys with non-trivial values, you must also define
25-
//! how those values can be merged. If this merging is infallible, you
26-
//! should implement the `InfallibleUnifyValue` trait, which unlocks
27-
//! various more ergonomic methods (e.g., `union()` in place of
28-
//! `unify_var_var()`).
25+
//! how those values can be merged. As part of doing this, you can
26+
//! define the "error" type to return on error; if errors are not
27+
//! possible, use `NoError` (an uninstantiable struct). Using this
28+
//! type also unlocks various more ergonomic methods (e.g., `union()`
29+
//! in place of `unify_var_var()`).
2930
3031
use std::marker;
3132
use std::fmt::Debug;
@@ -76,14 +77,63 @@ pub trait UnifyKey : Copy + Clone + Debug + PartialEq {
7677
}
7778
}
7879

80+
/// Trait implemented for **values** associated with a unification
81+
/// key. This trait defines how to merge the values from two keys that
82+
/// are unioned together. This merging can be fallible. If you attempt
83+
/// to union two keys whose values cannot be merged, then the error is
84+
/// propagated up and the two keys are not unioned.
85+
///
86+
/// This crate provides implementations of `UnifyValue` for `()`
87+
/// (which is infallible) and `Option<T>` (where `T: UnifyValue`). The
88+
/// option implementation merges two sum-values using the `UnifyValue`
89+
/// implementation of `T`.
90+
///
91+
/// See also `EqUnifyValue`, which is a convenience trait for cases
92+
/// where the "merge" operation succeeds only if the two values are
93+
/// equal.
7994
pub trait UnifyValue: Clone + Debug {
95+
/// Defines the type to return when merging of two values fails.
96+
/// If merging is infallible, use the special struct `NoError`
97+
/// found in this crate, which unlocks various more convenient
98+
/// methods on the unification table.
99+
type Error;
100+
80101
/// Given two values, produce a new value that combines them.
81102
/// If that is not possible, produce an error.
82-
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, (Self, Self)>;
103+
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error>;
104+
}
105+
106+
/// A convenient helper for unification values which must be equal or
107+
/// else an error occurs. For example, if you are unifying types in a
108+
/// simple functional language, this may be appropriate, since (e.g.)
109+
/// you can't unify a type variable bound to `int` with one bound to
110+
/// `float` (but you can unify two type variables both bound to
111+
/// `int`).
112+
///
113+
/// Any type which implements `EqUnifyValue` automatially implements
114+
/// `UnifyValue`; if the two values are equal, merging is permitted.
115+
/// Otherwise, the error `(v1, v2)` is returned, where `v1` and `v2`
116+
/// are the two unequal values.
117+
pub trait EqUnifyValue: Eq + Clone + Debug {
118+
}
119+
120+
impl<T: EqUnifyValue> UnifyValue for T {
121+
type Error = (T, T);
122+
123+
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
124+
if value1 == value2 {
125+
Ok(value1.clone())
126+
} else {
127+
Err((value1.clone(), value2.clone()))
128+
}
129+
}
83130
}
84131

85-
/// Marker trait which indicates that `UnifyValues::unify_values` will never return `Err`.
86-
pub trait InfallibleUnifyValue: UnifyValue {
132+
/// A struct which can never be instantiated. Used
133+
/// for the error type for infallible cases.
134+
#[derive(Debug)]
135+
pub struct NoError {
136+
_dummy: ()
87137
}
88138

89139
/// Value of a unification key. We implement Tarjan's union-find
@@ -393,7 +443,7 @@ impl<'tcx, K, V> UnificationTable<K>
393443
/// Unions two keys without the possibility of failure; only
394444
/// applicable to InfallibleUnifyValue.
395445
pub fn union(&mut self, a_id: K, b_id: K)
396-
where V: InfallibleUnifyValue
446+
where V: UnifyValue<Error = NoError>
397447
{
398448
self.unify_var_var(a_id, b_id).unwrap();
399449
}
@@ -408,7 +458,7 @@ impl<'tcx, K, V> UnificationTable<K>
408458
self.get_root_key(id)
409459
}
410460

411-
pub fn unify_var_var(&mut self, a_id: K, b_id: K) -> Result<(), (V, V)> {
461+
pub fn unify_var_var(&mut self, a_id: K, b_id: K) -> Result<(), V::Error> {
412462
let root_a = self.get_root_key(a_id);
413463
let root_b = self.get_root_key(b_id);
414464

@@ -423,7 +473,7 @@ impl<'tcx, K, V> UnificationTable<K>
423473

424474
/// Sets the value of the key `a_id` to `b`, attempting to merge
425475
/// with the previous value.
426-
pub fn unify_var_value(&mut self, a_id: K, b: V) -> Result<(), (V, V)> {
476+
pub fn unify_var_value(&mut self, a_id: K, b: V) -> Result<(), V::Error> {
427477
let root_a = self.get_root_key(a_id);
428478
let value = try!(V::unify_values(&self.value(root_a).value, &b));
429479
self.update_value(root_a, |node| node.value = value);
@@ -440,28 +490,26 @@ impl<'tcx, K, V> UnificationTable<K>
440490
///////////////////////////////////////////////////////////////////////////
441491

442492
impl UnifyValue for () {
443-
fn unify_values(_: &(), _: &()) -> Result<(), ((), ())> {
493+
type Error = NoError;
494+
495+
fn unify_values(_: &(), _: &()) -> Result<(), NoError> {
444496
Ok(())
445497
}
446498
}
447499

448-
impl InfallibleUnifyValue for () {
449-
}
450-
451500
impl<V: UnifyValue> UnifyValue for Option<V> {
452-
fn unify_values(a: &Option<V>, b: &Option<V>) -> Result<Self, (Self, Self)> {
501+
type Error = V::Error;
502+
503+
fn unify_values(a: &Option<V>, b: &Option<V>) -> Result<Self, V::Error> {
453504
match (a, b) {
454505
(&None, &None) => Ok(None),
455506
(&Some(ref v), &None) | (&None, &Some(ref v)) => Ok(Some(v.clone())),
456507
(&Some(ref a), &Some(ref b)) => {
457508
match V::unify_values(a, b) {
458509
Ok(v) => Ok(Some(v)),
459-
Err((a, b)) => Err((Some(a), Some(b))),
510+
Err(err) => Err(err),
460511
}
461512
}
462513
}
463514
}
464515
}
465-
466-
impl<V: InfallibleUnifyValue> InfallibleUnifyValue for Option<V> {
467-
}

src/unify/tests.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ extern crate test;
1414
use self::test::Bencher;
1515
use std::collections::HashSet;
1616
use std::cmp;
17-
use unify::{UnifyKey, UnifyValue, UnificationTable, InfallibleUnifyValue};
17+
use unify::{NoError, UnifyKey, EqUnifyValue, UnifyValue, UnificationTable};
1818

1919
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
2020
struct UnitKey(u32);
@@ -151,15 +151,7 @@ impl UnifyKey for IntKey {
151151
}
152152
}
153153

154-
impl UnifyValue for i32 {
155-
fn unify_values(&a: &i32, &b: &i32) -> Result<Self, (Self, Self)> {
156-
if a == b {
157-
Ok(a)
158-
} else {
159-
Err((a, b))
160-
}
161-
}
162-
}
154+
impl EqUnifyValue for i32 { }
163155

164156
#[test]
165157
fn unify_same_int_twice() {
@@ -268,13 +260,13 @@ impl UnifyKey for OrderedKey {
268260
}
269261

270262
impl UnifyValue for OrderedRank {
271-
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, (Self, Self)> {
263+
type Error = NoError;
264+
265+
fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
272266
Ok(OrderedRank(cmp::max(value1.0, value2.0)))
273267
}
274268
}
275269

276-
impl InfallibleUnifyValue for OrderedRank { }
277-
278270
#[test]
279271
fn ordered_key() {
280272
let mut ut: UnificationTable<OrderedKey> = UnificationTable::new();

0 commit comments

Comments
 (0)