I feel like this would be more generally useful, easier to explain, and certainly easier to sell as a language feature, if it were instead a lint-requesting attribute applicable to function definitions and to expressions. You'd write
#[bikeshed_all_variants_must_be_possible]
fn bool_check(inp: bool) -> Result<(), String> {
match inp {
true => Ok(()),
false => panic!("incorrect input!"),
}
}
and you'd get something like
error: function `bool_check` never returns `Err` variant of `Result`
This doesn't seem particularly useful for Result, because it's common to need to define functions that have to return a Result but there's no actual way they can fail. But I can imagine uses in other contexts. For example, take this enum and its FromStr impl:
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[non_exhaustive]
// The short name of the Rivest-Shamir-Adleman cryptosystem is RSA, not Rsa.
// Similarly for DSA and ECDSA.
#[allow(clippy::upper_case_acronyms)]
pub enum HostKeyKind {
RSA,
DSA,
ECDSA,
Ed25519,
}
struct HostKeyKindParseError;
impl FromStr for HostKeyKind {
type Err = HostKeyKindParseError;
#[bikeshed_all_variants_must_be_possible(Self)]
fn from_str(s: &str) -> Result<Self, Self::Err> {
use HostKeyKind::*;
for (mnemonic, val) in [
("rsa", RSA),
("dsa", DSA),
("ecdsa", ECDSA),
("ed25519", Ed25519),
] {
if s.eq_ignore_ascii_case(mnemonic) {
return Ok(val);
}
}
Err(HostKeyKindParseError)
}
}
It would indeed be helpful for the compiler to catch it if I happened to leave out one of the entries in the (mnemonic, val) list. But notice how there's no match statement in the body of the function. Also notice how, in this case, what's important is whether the function can return all variants of Self, not whether it can return all variants of Result<Self, Self::Err>. FromStr is actually a perfect example of a function that has to return a Result (because that's the trait API) but in some cases (not this one) will never actually fail (because every possible input string corresponds to a valid value of the output).