Sorry for being confusing. I think this might be better description of static type analysis:
http://learnyousomeerlang.com/dialyzer
Erlang is a dynamic, strongly typed language. Dynamic means the compiler doesn't do static type checks. "Strongly typed" means once a variable has a type it usually doesn't get automatically coerced to other types. So adding a string "5" and an integer 1 doesn't return a string "6" or integer 6 but throws an exception.
In addition to the compiler there is also a tool called Dialyzer. It's based on the idea of Success Types (paper on it: http://www.it.uu.se/research/group/hipe/papers/succ_types.pd...).
It checks for type inconsistencies, violations, etc just like a compiler in a traditional statically typed language. But it doesn't emit optimized code based on it. So say it deduced that a variable can only be an integer between 1 and 10 it doesn't have a way to emit some optimized assembly code based on that information. Besides the types it automatically infers, additional typing constraints can be specified by the user.
So for the guard in question, if say the second clause of right_age(_) -> wasn't there and it saw calls to the function with X=105, then Dialyzer would come back with an error with something like:
your_module:105: Clause guard cannot succeed.