Skip to content

Instantly share code, notes, and snippets.

@japaric
Last active August 29, 2015 14:10
Show Gist options
  • Save japaric/4b0d094998bfd47143b8 to your computer and use it in GitHub Desktop.
Save japaric/4b0d094998bfd47143b8 to your computer and use it in GitHub Desktop.
unboxed inference bug

Context:

https://github.com/rust-lang/rust/blob/6d965cc2c99787a949d38abf225412fe502d3ed8/src/libcollections/btree/set.rs#L454-487

(That's an unit test)

As part of the "unboxing closures" PR, I need to unbox the nested closure in the check function, which I have done in this commit. However, when I ran make check-stage1-collections I got a compiler error about the compiler not being able to infer the type of the closure in the check_intersection function. The weird part is that, upon isolating the unit test (which I did to understand/fix the compiler error), I found out that the code actually compiles!


  1. Build a compiler that includes #19449

  2. Checkout rust-lang/rust#19467

  3. configure the build system to use the compiler built in step (1) as the stage0 compiler

  4. make check-stage1-collections

rustc: x86_64-unknown-linux-gnu/stage2/test/collectionstest-x86_64-unknown-linux-gnu
/root/rust/src/libcollections/btree/set.rs:488:13: 488:18 error: unable to infer enough type information about `_`; type annotations required
/root/rust/src/libcollections/btree/set.rs:488             check(a, b, expected, |x, y, f| x.intersection(y).all(f))
  1. But if you compile unboxed.rs directly... It works!
$ LD_LIBRARY_PATH=~/rust/build/x86_64-unknown-linux-gnu/stage1/lib ~/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc unboxed.rs && echo It works!
It works!
use std::collections::BTreeSet;
fn check(a: &[int],
b: &[int],
expected: &[int],
f: |&BTreeSet<int>, &BTreeSet<int>, f: |&int| -> bool| -> bool) {
let mut set_a = BTreeSet::new();
let mut set_b = BTreeSet::new();
for x in a.iter() { assert!(set_a.insert(*x)) }
for y in b.iter() { assert!(set_b.insert(*y)) }
let mut i = 0;
f(&set_a, &set_b, |x| {
assert_eq!(*x, expected[i]);
i += 1;
true
});
assert_eq!(i, expected.len());
}
fn test_intersection() {
fn check_intersection(a: &[int], b: &[int], expected: &[int]) {
check(a, b, expected, |x, y, f| x.intersection(y).all(f))
}
check_intersection(&[], &[], &[]);
check_intersection(&[1, 2, 3], &[], &[]);
check_intersection(&[], &[1, 2, 3], &[]);
check_intersection(&[2], &[1, 2, 3], &[2]);
check_intersection(&[1, 2, 3], &[2], &[2]);
check_intersection(&[11, 1, 3, 77, 103, 5, -5],
&[2, 11, 77, -9, -42, 5, 3],
&[3, 5, 11, 77]);
}
fn main() {}
use std::collections::BTreeSet;
struct Counter<'a, 'b> {
i: &'a mut uint,
expected: &'b [int],
}
impl<'a, 'b> FnMut(&int) -> bool for Counter<'a, 'b> {
extern "rust-call" fn call_mut(&mut self, (&x,): (&int,)) -> bool {
assert_eq!(x, self.expected[*self.i]);
*self.i += 1;
true
}
}
fn check(a: &[int], b: &[int], expected: &[int], f: F) where
// FIXME Replace `Counter` with `Box<FnMut(_) -> _>`
F: FnOnce(&BTreeSet<int>, &BTreeSet<int>, Counter) -> bool,
{
let mut set_a = BTreeSet::new();
let mut set_b = BTreeSet::new();
for x in a.iter() { assert!(set_a.insert(*x)) }
for y in b.iter() { assert!(set_b.insert(*y)) }
let mut i = 0;
f(&set_a, &set_b, Counter { i: &mut i, expected: expected });
assert_eq!(i, expected.len());
}
fn test_intersection() {
fn check_intersection(a: &[int], b: &[int], expected: &[int]) {
check(a, b, expected, |x, y, f| x.intersection(y).all(f))
}
check_intersection(&[], &[], &[]);
check_intersection(&[1, 2, 3], &[], &[]);
check_intersection(&[], &[1, 2, 3], &[]);
check_intersection(&[2], &[1, 2, 3], &[2]);
check_intersection(&[1, 2, 3], &[2], &[2]);
check_intersection(&[11, 1, 3, 77, 103, 5, -5],
&[2, 11, 77, -9, -42, 5, 3],
&[3, 5, 11, 77]);
}
fn main() {}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment