Rustc leads me down wrong path


#1

So, I am writing the simplest function you can imagine. And hey, there’s an error in it:

enum Stack<T> {
    Nil,
    Cons(T, Box<Stack<T>>)
}

fn isEmpty<T>(s: Stack<T>) -> bool {
    match s {
        Nil => true,
        _   => false,
    }    
}

Excitingly rustc tells me:

$ cargo build --verbose
Compiling stack v0.1.0 (file:///home/pmatos/Projects/okasaki-rust/chp2-persistence/stack)
Running rustc src/lib.rs --crate-name stack --crate-type lib -g --out-dir /home/pmatos/Projects/okasaki-rust/chp2-persistence/stack/target/debug --emit=dep-info,link -L dependency=/home/pmatos/Projects/okasaki-rust/chp2-persistence/stack/target/debug -L dependency=/home/pmatos/Projects/okasaki-rust/chp2-persistence/stack/target/debug/deps
src/lib.rs:10:9: 10:12 warning: pattern binding Nil is named the same as one of the variants of the type Stack<T> [E0170]
src/lib.rs:10 Nil => true,
^~~
src/lib.rs:10:9: 10:12 help: run rustc --explain E0170 to see a detailed explanation
src/lib.rs:10:9: 10:12 help: if you meant to match on a variant, consider making the path in the pattern qualified: Stack<T>::Nil
src/lib.rs:11:9: 11:10 error: unreachable pattern [E0001]
src/lib.rs:11 _ => false,
^
src/lib.rs:11:9: 11:10 help: run rustc --explain E0001 to see a detailed explanation
error: aborting due to previous error
Could not compile stack.

Caused by:
Process didn’t exit successfully: rustc src/lib.rs --crate-name stack --crate-type lib -g --out-dir /home/pmatos/Projects/okasaki-rust/chp2-persistence/stack/target/debug --emit=dep-info,link -L dependency=/home/pmatos/Projects/okasaki-rust/chp2-persistence/stack/target/debug -L dependency=/home/pmatos/Projects/okasaki-rust/chp2-persistence/stack/target/debug/deps (exit code: 101)

So now I follow rustc advice:

enum Stack<T> {
    Nil,
    Cons(T, Box<Stack<T>>)
}

fn isEmpty<T>(s: Stack<T>) -> bool {
    match s {
        Stack<T>::Nil => true,
        _   => false,
    }    
}

But this is wrong again and now rust helps you no further. Any hints?

$ cargo build --verbose
Compiling stack v0.1.0 (file:///home/pmatos/Projects/okasaki-rust/chp2-persistence/stack)
Running rustc src/lib.rs --crate-name stack --crate-type lib -g --out-dir /home/pmatos/Projects/okasaki-rust/chp2-persistence/stack/target/debug --emit=dep-info,link -L dependency=/home/pmatos/Projects/okasaki-rust/chp2-persistence/stack/target/debug -L dependency=/home/pmatos/Projects/okasaki-rust/chp2-persistence/stack/target/debug/deps
src/lib.rs:10:14: 10:15 error: expected one of =>, @, if, or |, found <
src/lib.rs:10 Stack::Nil => true,
^
Could not compile stack.

Caused by:
Process didn’t exit successfully: rustc src/lib.rs --crate-name stack --crate-type lib -g --out-dir /home/pmatos/Projects/okasaki-rust/chp2-persistence/stack/target/debug --emit=dep-info,link -L dependency=/home/pmatos/Projects/okasaki-rust/chp2-persistence/stack/target/debug -L dependency=/home/pmatos/Projects/okasaki-rust/chp2-persistence/stack/target/debug/deps (exit code: 101)


#2

I am a relative newbie when it comes to rust, so unfortunately I’m not sure of the underlying reasons for why this is an issue. However, the following change fixes the problem:

fn isEmpty<T>(s: Stack<T>) -> bool {
    match s {
        Stack::Nil => true,
        _ => false,
    }
}    

I assume that it doesn’t like the argument type definition being part of the pattern match.

I am using rust 1.4 and got slightly different compilation errors than you (including the ones you listed). Hopefully this fixes the issue for you as well.


#3

You don’t have to add the <T> part when referring to Nil, as long as T can be inferred. Otherwise, the correct syntax is Stack::<T>::Nil. I like to think of the <T> part as a virtual sub module under Stack.


#4

That works. Thanks.


#5

Stack::<T>::Nil really? That’s ridiculous. Why? oh why?

And you actually not do that since you get:

$ cargo build
Compiling stack v0.1.0 (file:///home/pmatos/Projects/okasaki-rust/chp2-persistence/stack)
src/lib.rs:10:17: 10:18 error: type parameters are not allowed on this type [E0109]
src/lib.rs:10 Stack::::Nil => true,
^
src/lib.rs:10:17: 10:18 help: run rustc --explain E0109 to see a detailed explanation
error: aborting due to previous error
Could not compile stack.


#7

Oh, looks like my memory failed me. Stack::Nil::<T> is the way to go.

Anyway, it’s a problem with the parser. It needs the extra :: to know that you are not trying to write something like this:

let T = 1;
let Stack = 2;

Stack < T

It doesn’t keep track of much context, so it can’t know which one of Stack<T> and Stack < T you are writing.


#8

Thanks for the help.


#9

Thanks for the report. Here’s an issue.