Summary
Method.verify() does not validate that each statement's dialect is a member of the method's DialectGroup. A method can contain statements from a dialect that is not in method.dialects, and verify() will still pass. The mismatch only surfaces lazily — as an InterpreterError in kirin.interp.abc (node.dialect not in self.dialects, ~line 297) or during lowering (kirin.lowering.frame, ~line 74) — often far from where the illegal IR was produced.
Observed on kirin-toolchain==0.22.11.
Why it happens
Method.verify() calls self.code.verify(); code is a func.Function, which has no check() override, so it falls through to the base Statement.verify() → no-op Statement.check(). Nothing in that path (nor in any verification pass I could find) compares stmt.dialect against the method's group.
Reproducer
from kirin import ir, types
from kirin.dialects import func
# ... build a Method whose body contains a statement S,
# but construct the DialectGroup WITHOUT S's dialect.
method.verify() # passes, despite S being out-of-group
In our downstream project a lowering pass discarded the source dialect from the group after rewriting, but a statement it didn't handle passed through. verify() (even verify_type()) accepted the result; it only blew up later inside the emitter. We worked around it with a helper that walks the method and flags stmt.dialect is not None and stmt.dialect not in method.dialects.
Proposal
Have verify() (or a dedicated verification pass) check that every statement's dialect is a member of the method's DialectGroup, raising a ValidationError that points at the offending statement. DialectGroup.__contains__ already supports the membership test, so the check is cheap.
Happy to send a PR if this seems reasonable.
Summary
Method.verify()does not validate that each statement's dialect is a member of the method'sDialectGroup. A method can contain statements from a dialect that is not inmethod.dialects, andverify()will still pass. The mismatch only surfaces lazily — as anInterpreterErrorinkirin.interp.abc(node.dialect not in self.dialects, ~line 297) or during lowering (kirin.lowering.frame, ~line 74) — often far from where the illegal IR was produced.Observed on
kirin-toolchain==0.22.11.Why it happens
Method.verify()callsself.code.verify();codeis afunc.Function, which has nocheck()override, so it falls through to the baseStatement.verify()→ no-opStatement.check(). Nothing in that path (nor in any verification pass I could find) comparesstmt.dialectagainst the method's group.Reproducer
In our downstream project a lowering pass discarded the source dialect from the group after rewriting, but a statement it didn't handle passed through.
verify()(evenverify_type()) accepted the result; it only blew up later inside the emitter. We worked around it with a helper that walks the method and flagsstmt.dialect is not None and stmt.dialect not in method.dialects.Proposal
Have
verify()(or a dedicated verification pass) check that every statement's dialect is a member of the method'sDialectGroup, raising aValidationErrorthat points at the offending statement.DialectGroup.__contains__already supports the membership test, so the check is cheap.Happy to send a PR if this seems reasonable.