A common pattern in languages with nulls is
if (x != nullptr) {
return expr;
}
x->blah(); // Treat x as nonnull, no safety though!
This is really, really useful for readability, because it avoids rightward drift (which if let Some(_) tends to make really really bad in long chains of if-lets).
What I want is the following behavior:
if let None = x {
return expr
}
let Some(x) = x;
In particular, if an if-let can only execute if x matches a pattern, and its block types as !, then that pattern should be “ruled out” from the list of patterns that are needed to make a match irrefutable. The same holds for breakless while-lets, and match arms that type as !. For example:
enum E { A, B, C, D }
let x: E = E::A;
// E::A is ruled out, since the type is `!`.
if let A = x { return }
// No E::A arm is ok, since x match E::A has been ruled
// out.
match x {
E::B => panic!(), // Types as `!`, so its pattern is
// ruled out in the containing block.
E::C => {},
E::D => {},
}
while let E::C = x {
// no breaks
}
// To reach this line, x cannot be E::C, so that
// pattern is ruled out.
let E::D = x; // Irrefutable, since other variants have
// been ruled out.
(For silly bonus points, you could type x as ! if all its variants are ruled out, but this seems kind of like a bad idea…)
I think this mostly only targets Option right now; if and when we get negative if let, you might imagine that the following is allowed:
// Imaginary syntax, do not bikeshed.
if !let Some(..) = x {
return
}
// Here, *all* patterns except Some are ruled out.
let Some(x) = x;
Of course, you might say “why not just use Option<T>: Try?” Like, you could, but that doesn’t give you a chance do to processing between the is-None check and the return, and you are limited to returning an impl Try. You could also use Option combinators, but I’ve found that long chains of combinators and closures are not exactly readable (see: why we have for-in, and why Haskell has do). Anything more complicated than x.map(..).unwrap_or() is almost certainly too clever.

.