Skip to content

Instantly share code, notes, and snippets.

@pnkfelix
Created October 9, 2013 17:38
Show Gist options
  • Save pnkfelix/6905109 to your computer and use it in GitHub Desktop.
Save pnkfelix/6905109 to your computer and use it in GitHub Desktop.
Original bug report for Rust Issue 7331 : https://github.com/mozilla/rust/issues/7331

I tried and failed to strip it down, but the code

// Copyright 2013 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 std::hashmap::HashMap;

#[allow(default_methods)]

/**
 * An "interner" is a data structure that associates values with uint tags, allowing bidirectional
 * lookup (ie, given a value, get the tag, or given a tag, get the value). This allows for efficient
 * storage and comparison of large values that would be expensive to copy around or compare
 */
// FIXME #7312: inherit `Default` when it exists
pub trait Interner<T> {
    pub fn new() -> Self;
    /// Create a new interner and intern all the values in `init`
    pub fn prefill(init: Iterator<T>) -> Self {
        let in = Interner::new();
        for init.advance |&v| {
            in.intern(v);
        }
        in
    }
    /// Intern a value, returning the tag used to refer to it
    pub fn intern(&self, val: T) -> uint;
    /// Get the value corresponding to a tag
    pub fn get(&'self self, tag: uint) -> Option<&'self T>;
    /// Get the tag corresponding to a value equivalent to `Q`
    pub fn find_equiv<Q: Hash + IterBytes + Equiv<T>>(&self, val: &Q) -> Option<uint>;
}

/**
 * A simple implementation of an interner, using a std::hashmap::HashMap for associating a value to a
 * tag and storing values in a vector.
 */
pub struct SimpleInterner<T: Eq + IterBytes + Hash + Copy> {
    priv map: HashMap<T, uint>,
    priv vect: ~[T]
}

impl<T> Interner<T> for SimpleInterner<T> {
    pub fn new() -> SimpleInterner<T> {
        SimpleInterner {
            map: HashMap::new(),
            vect: ~[]
        }
    }
    pub fn prefill(init: Iterator<T>) -> SimpleInterner<T> {
        let hm = HashMap::new();
        hm.reserve_at_least(init.len());
        let mut vect = std::vec::with_capacity(init.len());
        let mut i = 0;
        for init.advance |&v| {
            if hm.find_or_insert(v, i) == i {
                unsafe {
                    std::vec::raw::init_elem(vect, i, v);
                }
                i += 1;
            }
        }
        SimpleInterner {map: hm, vect: vect}
    }
    pub fn intern(&self, val: T) -> uint {
        let i = self.vect.len();
        let x = self.map.find_or_insert(val, i);
        if x == i {
            self.vec.push(val);
        }
        x
    }
    pub fn get(&'self self, tag: uint) -> Option<&'self T> {
        if tag > self.vect.len() {
            None
        } else {
            Some(&self.vect[tag])
        }
    }
    pub fn find_equiv<Q: Hash + IterBytes + Equiv<T>>(&self, val: &Q) -> Option<uint> {
        self.map.find_equiv(val)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[should_fail]
    fn i1 () {
        let i: SimpleInterner<~str> = Interner::new();
        i.get(13);
    }
}

Fails with the ICE

error: internal compiler error: ty::Region#subst(): Reference to self region when given substs with no self region: substs(self_r=None, self_ty=Some('b), tps=['a])

When replace 'self with 'a, though, it works:

// Copyright 2013 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 std::hashmap::HashMap;

#[allow(default_methods)]

/**
 * An "interner" is a data structure that associates values with uint tags, allowing bidirectional
 * lookup (ie, given a value, get the tag, or given a tag, get the value). This allows for efficient
 * storage and comparison of large values that would be expensive to copy around or compare
 */
// FIXME #7312: inherit `Default` when it exists
pub trait Interner<T> {
    pub fn new() -> Self;
    /// Create a new interner and intern all the values in `init`
    pub fn prefill(init: Iterator<T>) -> Self {
        let in = Interner::new();
        for init.advance |&v| {
            in.intern(v);
        }
        in
    }
    /// Intern a value, returning the tag used to refer to it
    pub fn intern(&self, val: T) -> uint;
    /// Get the value corresponding to a tag
    pub fn get<'a>(&'a self, tag: uint) -> Option<&'a T>;
    /// Get the tag corresponding to a value equivalent to `Q`
    pub fn find_equiv<Q: Hash + IterBytes + Equiv<T>>(&self, val: &Q) -> Option<uint>;
}

/**
 * A simple implementation of an interner, using a std::hashmap::HashMap for associating a value to a
 * tag and storing values in a vector.
 */
pub struct SimpleInterner<T: Eq + IterBytes + Hash + Copy> {
    priv map: HashMap<T, uint>,
    priv vect: ~[T]
}

impl<T> Interner<T> for SimpleInterner<T> {
    pub fn new() -> SimpleInterner<T> {
        SimpleInterner {
            map: HashMap::new(),
            vect: ~[]
        }
    }
    pub fn prefill(init: Iterator<T>) -> SimpleInterner<T> {
        let hm = HashMap::new();
        hm.reserve_at_least(init.len());
        let mut vect = std::vec::with_capacity(init.len());
        let mut i = 0;
        for init.advance |&v| {
            if hm.find_or_insert(v, i) == i {
                unsafe {
                    std::vec::raw::init_elem(vect, i, v);
                }
                i += 1;
            }
        }
        SimpleInterner {map: hm, vect: vect}
    }
    pub fn intern(&self, val: T) -> uint {
        let i = self.vect.len();
        let x = self.map.find_or_insert(val, i);
        if x == i {
            self.vec.push(val);
        }
        x
    }
    pub fn get<'a>(&'a self, tag: uint) -> Option<&'a T> {
        if tag > self.vect.len() {
            None
        } else {
            Some(&self.vect[tag])
        }
    }
    pub fn find_equiv<Q: Hash + IterBytes + Equiv<T>>(&self, val: &Q) -> Option<uint> {
        self.map.find_equiv(val)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[should_fail]
    fn i1 () {
        let i: SimpleInterner<~str> = Interner::new();
        i.get(13);
    }
}

Whatever way I tried to strip it down I ended up with a non-ICE failure, so it's probably interaction between two different things.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment