3
votes

This example fails to compile:

extern crate nix;
use std::os::unix::io::RawFd;

fn func(fd: RawFd, buf: &mut [u8]) -> Result<(), nix::Error> {
    let (size, nix_addr) = nix::sys::socket::recvfrom(
        fd, buf
    )?;

    let addr = match nix_addr {
        //nix::sys::socket::SockAddr::Inet(addr) => addr.to_std(),
        Inet(addr) => addr.to_std(),
        _ => panic!(),
    };

    Ok(())
}

fn main() {}

The error, in this version is:

error[E0531]: unresolved tuple struct/variant `Inet`
  --> match_arms.rs:14:3
   |
14 |        Inet(addr) => addr.to_std(),
   |        ^^^^

Swapping the Inet line for the commented out one successfully compiles.

The compiler seems to be requiring me to specify the enum type itself, I suppose so that it knows that the variant I'm specifying in the match arm is legit. But why? Can't the enum be inferred? Doesn't the compiler have enough information here to realize that nix_addr is a nix::…::SocketAddr, and thus, that Inet is a valid variant (and one with data)?

Why do I have to type the whole thing out, or drag the name into the current scope with a use?

I also tried _::Inet, which also failed.

1

1 Answers

7
votes
  • But why? Can't the enum be inferred?

According to RFC 390 which introduced enum namespacing, this inference is considered a hack and not having it is better designwise. From the RFC's alternatives section:

We can implement enum namespacing after 1.0 by adding a "fallback" case to resolve, where variants can be referenced from their "flat" definition location if no other definition would conflict in that namespace. In the grand scheme of hacks to preserve backwards compatibility, this is not that bad, but still decidedly worse than not having to worry about fallback at all.

The official reason why inference is not considered after RFC 390, is no one really cared enough to propose the change:

@sfackler:

@netvl Java's an interesting case in that you can only refer to variants in the "bare" form (FOO, not MyEnum.FOO) in switch statements. The situation in Rust is a bit more complex as match allows more powerful pattern matching than traditional switch statements. The closest analogue would probably be to implicitly treat all the relevant stuff as imported in a pattern. That seems like something sufficiently orthogonal to this proposal that it'd probably deserve its own RFC.

(and no one has written an RFC for this since then.)

The chance such an RFC will pass is slim, though. After all, you just need to add one line use nix::sys::socket::SockAddr::* somewhere to make it work. Adding a feature to the language requires so many consideration about the proper specification and corner cases (e.g. what happens when you use nix::sys::socket::SockAddr::Unix as Inet) that it may not worth the time.