"Cannot infer type - type annotations needed", but the type is already known

Viewed 323

I've been practicing on LC where I hit the following issue.

pub fn largest_rectangle_area(heights: Vec<i32>) -> i32 {
    let mut widths = vec![(0usize, heights.len()); heights.len()];
    let mut stack = vec![];

    for (idx, &x) in heights.iter().enumerate() {
        while let Some(&pos) = stack.last() {
            if x >= heights[pos] {
                break;
            }

            widths[pos].1 = idx;
            stack.pop();
        }

        stack.push(idx);
    }

    todo!()
}

error[E0282]: type annotations needed
  --> src/lib.rs:11:13
   |
11 |             widths[pos].1 = idx;
   |             ^^^^^^^^^^^ cannot infer type
   |
   = note: type must be known at this point

What's even stranger is that if I do a widths[pos] = (0, idx); first, then the error disappears:

pub fn largest_rectangle_area(heights: Vec<i32>) -> i32 {
    let mut widths = vec![(0, heights.len()); heights.len()];
    let mut stack = vec![];

    for (idx, &x) in heights.iter().enumerate() {
        while let Some(&pos) = stack.last() {
            if x >= heights[pos] {
                break;
            }

            widths[pos] = (0, idx); // do a full update
            stack.pop();
        }

        stack.push(idx);
    }
    stack.clear();

    for (idx, &x) in heights.iter().enumerate().rev() {
        while let Some(&pos) = stack.last() {
            if x >= heights[pos] {
                break;
            }

            widths[pos].0 = idx + 1; // now it's fine to use `.0`
            stack.pop();
        }

        stack.push(idx);
    }
    todo!()
}

Am I missing something, or is this a bug in the compiler ?

Update

@ Ömer Erden discovered, that it fails to infer the type of pos which should be usize as it's coming from enumerate() indirectly.

It seems pretty strange because it fails to infer the type of pos when doing widths[pos].1 = idx;, but succeeds when doing widths[pos] = (0, idx);

He also managed to create more minimal MCVE:

fn _some_fn() {
    let mut widths = vec![(0usize, 0usize); 100];
    let mut stack = vec![];
    //let mut stack:Vec<usize> = vec![]; //why explicit type definition needed

    let a = stack.pop().unwrap();
    let idx = 0usize;
    widths[a].1 = idx;

    stack.push(idx);
}

Bug Report

https://github.com/rust-lang/rust/issues/90252

1 Answers

I dont know why the compiler is unable to elide the type, but you can manually annotate it with some easy changes:

pub fn largest_rectangle_area(heights: Vec<i32>) -> i32 {
    let mut widths = vec![(0usize, heights.len()); heights.len()];
    let mut stack = vec![];

    for (idx, &x) in heights.iter().enumerate() {
        while let Some(&pos) = stack.last() {
            if x >= heights[pos] {
                break;
            }
            let at_pos: &mut (usize, usize) = &mut widths[pos];
            at_pos.1 = idx;
            stack.pop();
        }

        stack.push(idx);
    }

    todo!()
}

Playground

Related