So what if it looked like this then, to make it clear that it's not a generic "is truthy" / "bool coercion", and additionally to make it possible to return custom values when short circuiting:
enum ShortCircuit<S, L> {
Short(S),
Long(L),
}
trait LogicalOr<Rhs = Self>: Sized {
type Output;
/// Decide whether the *logical or* should short-circuit
/// or not based on its left-hand side argument. If so,
/// return its final result, otherwise return the value
/// that will get passed to `logical_or()` (normally this
/// means returning self back, but you can change the value).
fn short_circuit_or(self) -> ShortCircuit<Self::Output, Self>;
/// Complete the *logical or* in case it did not short-circuit.
/// Normally this would just return `rhs`.
fn logical_or(self, rhs: Rhs) -> Self::Output;
}
then A() || B() desugars to
match A().short_circuit_or() {
ShortCircuit::Short(res) => res,
ShortCircuit::Long(l) => l.logical_or(B()),
}
This way it'd be possible to have
impl<T> LogicalOr<T> for Option<T> {
type Output = T;
...
}
(currently known as .unwrap_or()), where if it short-circuits, the output type is T, not Option<T>; and it also works for non-Copy types — in your proposal, self would be consumed by is_truthy(), in mine it is (typically) returned back wrapped in ShortCircuit::Long().
Here's a playground with LogicalOr, LogicalAnd, some impls for bool and Option, a logical! macro to perform the desugaring, and a demo.