I want to add that this is actually hard to do correctly in practice. You would effectively need to implement a large chunk of the compiler. For example, take this code:
foo(a + b)
How many variables are used?
Well, if “foo” is a macro, then foo may define several variables in it. You would have to expand all macros recursively to give the correct answer.
For example, what about this code?
destructure [foo, bar], [1]
This is valid Elixir code today and you know that foo and bar are variables only by expanding the macro and then traversing all of Elixir special forms and reimplementing how they handle variables. The reason it works for defguard is because guards are a very small subset of the language. So reimplementing it is trivial.






















