Comment by knorker
Of course it allows invalid combinations.
This also compiles:
let f = std::fs::File::open("/dev/null").unwrap();
let f: std::os::fd::OwnedFd = f.into();
let socket: std::net::UdpSocket = f.into();
If you convert a high level object into a low level one, and then back up as another type, then what exactly do you expect the language to do about that?> "protected from or not exposed to danger or risk."
A computer will do what you tell it to do, not what you intend it to do. Opening a file is way more dangerous than risking errors because "this syscall doesn't work on that fd".
There's also always risk that a syscall will fail at runtime, whether the type of fd is correct or not.
It sounds like you would prefer if UdpSocket From<OwnedFD> should run getsockname() or something to confirm it's of the expected type, but I would prefer not. Indeed, in the general case some perfectly coded `unsafe` code could `dup2()` over the fd, so any checking at UdpSocket creation time is moot; you still don't get the safety you are asking for.
I agree with everything you wrote except for this:
> Indeed, in the general case some perfectly coded `unsafe` code could `dup2()` over the fd, so any checking at UdpSocket creation time is moot; you still don't get the safety you are asking for.
If `unsafe` code breaks safe code's soundness guarantees (let's assume for a second an alternate world in which "fd is of the correct type" is a soundness guarantee Rust makes), the bug is in the `unsafe` code.