Pre/post-order verifiers

Currently, op verifiers are executed pre-order: the parent op is checked before its children. This is problematic when an op needs to verify some invariants about the regions it contains. Conceptually, it is the parent op that defines the semantics of the regions so it should be up to this up to verify the region. Practically, attempting to inspect child ops in the verifier can lead to crashes and all sorts of undesirable behavior because those ops are not guaranteed to be valid. I’ve hit this problem repeatedly: with function names before we had reusable SymbolTable (the module would verify name uniqueness), with scf.parallel-like operations that have an invariant on the number of nested operations of a specific type, and more recently with an interface that expects an op to contain specific ops.

I would like to have post-order verification where such things could be handled. This can be opt-in and complementary to the current pre-order verification.

I can see theoretical arguments where preorder is better, but not many. It would be better to keep the system simple if possible. Do you think it would be a problem in practice to switch to post-order verification exclusively?