Sanity check to detect undeclared identifiers, name clashes, and tricky kinds of global name shadowing that we don't support.
In some Verilog tools, top-level and imported declarations can sometimes be shadowed by local declarations for only part of a module. For instance,
parameter foo = 1; module m (); logic [3:0] a = foo; // references the global foo parameter foo = 2; logic [3:0] b = foo; // references the local foo endmodule
Throughout VL we generally abstract away from the parse order and expect to be able to traverse scopes in a simple set-like way; see scopestack. This approach makes supporting this kind of lexical shadowing a challenge. To avoid any problems due to this kind of shadowing, we implement a special check to prohibit globals from being used before they are locally declared.
This checking depends on the parse order. It occurs as part of the make-implicit-wires transform. Note that we do this checking after we have already introduced implicit wires, so we can assume that implicit wires have explicit declarations.