In programming language intermediate representations (the context of the article) exhaustiveness checking might not be as useful as in other contexts. You will have many variants, but for every concrete operation you want to do on the IR you will only consider a few of them, with a default catch-all case for all others.
For example, imagine you're writing a tool to represent and process source code for a Python-like language. Here are the statement types:
type Statement =
| Assign var value
| ExprStatement value
| If cond true_branch false_branch
| While cond body
| Return value
| Break
| Continue
| With context body
(I'm sure I forgot some interesting ones.) You want to do some analysis related to branching control flow statements. These are If and While, so you write: let analyze_control_flow stmt =
match stmt with
| If _ true_branch false_branch ->
do_something_with true_branch;
do_something_with false_branch
| While _ body ->
do_something_with body
| _ -> // not a branching control flow statement
()
This works nicely. Except that Python recently got pattern matching itself, so you add a new variant to your Statement type: ...
| Match pattern cases
...
and then you recompile and fix a few exhaustiveness errors and feel happy that you have handled everything, except that you haven't. You would also need to update your definition of analyze_control_flow, but due to the catch-all clause your compiler didn't alert you to this.(On the other hand, such fundamental language/IR changes are relatively rare.)