I'm guessing, but I think the tricky part for Rust might be the automated construction of the Error-union type. E.g., at a certain call-point, the full union of all possible errors is ErrorSet<E1, E2, E3, ..., En>. The compiler determines this union, not the programmer. At the next call point, the union may be entirely different. To my best knowledge, Rust doesn't currently allow for variadic type constructors (i.e., where the number of parameters may be knowable at compile time, but the arbitrary-length parameter list cannot be expressed in the abstract syntax of the language).
edit: when I say "full union of all possible errors", I just want to be clear that this means "all the possible errors that could occur at this call point, and no others." It's not just a bag of "all possible errors that the language/library declares to exist."
edit #2: On second thought, I guess it might be possible for a Rust tool to build these types, although I think it would require changes to the language implementation. Variadic type constructors aren't necessarily needed. Another approach would be that every (type-specialized) function returns a Result<T, ES> type, where ES is some type that implements an "ErrorSet" kind, and where ES is very possibly unique to the function (that is, no other function might return Result<ES>). For example function A() might fail due only to two cases (say, out-of-memory or disk-full, but never network-error), and function B() might fail only on disk-full. Then the ErrorSet type for A has two constructors (OOM and DiskFull), where the ErrorSet type for B has only one (DiskFull). You could then use Rust's (excellent) pattern matching to exhaustively handle all cases (i.e., the specific constructors of that ErrorSet type) at the call site.
So the tricks would be:
1. Instrument the language to tag each specialized function with its error-set; this is computed recursively by examining the failure modes in the function body, as well as the error-sets of every function it might itself call, and taking the union of those sets. (Side note: I believe that, in Zig, a type-specialized function maps to a single error-set -- i.e., the error-set doesn't depend on runtime arguments in any way. But I could be wrong about this.)
2. Generate a potentially new ErrorSet-ish type for each function, or more spefically, for each error-set that is generated using the process in step #1. (I suppose you would have to give the type a name, but maybe it could be an anonymous internal type if there is language support for that.)
3. Then you could naturally "match" on the function's return value, and know that you've covered (exactly) the possible failure modes.
But this is just armchair-quarterbacking on my part. I don't know the internals of the Zig error system, nor what changes Rust would actually need.
https://ziglang.org/documentation/master/#Errors
edit: when I say "full union of all possible errors", I just want to be clear that this means "all the possible errors that could occur at this call point, and no others." It's not just a bag of "all possible errors that the language/library declares to exist."
edit #2: On second thought, I guess it might be possible for a Rust tool to build these types, although I think it would require changes to the language implementation. Variadic type constructors aren't necessarily needed. Another approach would be that every (type-specialized) function returns a Result<T, ES> type, where ES is some type that implements an "ErrorSet" kind, and where ES is very possibly unique to the function (that is, no other function might return Result<ES>). For example function A() might fail due only to two cases (say, out-of-memory or disk-full, but never network-error), and function B() might fail only on disk-full. Then the ErrorSet type for A has two constructors (OOM and DiskFull), where the ErrorSet type for B has only one (DiskFull). You could then use Rust's (excellent) pattern matching to exhaustively handle all cases (i.e., the specific constructors of that ErrorSet type) at the call site.
So the tricks would be:
1. Instrument the language to tag each specialized function with its error-set; this is computed recursively by examining the failure modes in the function body, as well as the error-sets of every function it might itself call, and taking the union of those sets. (Side note: I believe that, in Zig, a type-specialized function maps to a single error-set -- i.e., the error-set doesn't depend on runtime arguments in any way. But I could be wrong about this.)
2. Generate a potentially new ErrorSet-ish type for each function, or more spefically, for each error-set that is generated using the process in step #1. (I suppose you would have to give the type a name, but maybe it could be an anonymous internal type if there is language support for that.)
3. Then you could naturally "match" on the function's return value, and know that you've covered (exactly) the possible failure modes.
But this is just armchair-quarterbacking on my part. I don't know the internals of the Zig error system, nor what changes Rust would actually need.