Claude found an issue revealed during development of an internal repo.
eval_fallback corrupts result types for statements with multiple mixed-type variadic argument groups
Note: This issue was identified and authored by Claude (Anthropic's AI assistant) while auditing a downstream dialect codebase built on Kirin.
Summary
TypeInference.eval_fallback produces incorrect result types — or raises an internal error — when a statement has more than one variadic argument group (tuple[ir.SSAValue, ...] fields) with different declared element types. The fallback appears to zip field-level types (one per variadic group) against the flat list of SSA values (one per element across all groups), causing a type-count mismatch and incorrect type resolution.
Minimal reproducer
from kirin import ir, types
from kirin.decl import info, statement
my_dialect = ir.Dialect("repro")
@statement(dialect=my_dialect)
class MixedVariadicStmt(ir.Statement):
"""Two variadic groups with different element types."""
blocks: tuple[ir.SSAValue, ...] = info.argument(types.PyClass(object)) # group 1
thetas: tuple[ir.SSAValue, ...] = info.argument(types.Float) # group 2
When TypeInference encounters MixedVariadicStmt with, say, 3 blocks and 3 thetas (6 total SSA inputs), eval_fallback sees 2 declared argument types but 6 SSA values. The zip truncates at 2, leaving 4 values unprocessed, and TypeResolution receives a malformed argument-type pairing.
For void-result statements this silently produces wrong types; for result-bearing statements it can corrupt the inferred result type or raise internally.
Observed behaviour
In a downstream dialect (ParallelRzGate) with fields:
blocks: tuple[ir.SSAValue, ...] = info.argument(BicycleBlockType) # group 1
thetas: tuple[ir.SSAValue, ...] = info.argument(types.Float) # group 2
calling TypeInfer without an explicit @impl(ParallelRzGate) handler causes the type of blocks elements to be resolved as Float (the second group's type) after eval_fallback zips incorrectly. The workaround is to register an explicit — and essentially content-free — handler for every affected statement:
@dialect.register(key="typeinfer")
class MyTypeInfer(MethodTable):
@impl(ParallelRzGate)
def parallel_rz(self, interp_, frame, stmt):
return () # correct: void statement, but only works because it bypasses eval_fallback
This workaround must be repeated for every statement in the dialect that has any variadic group, even those whose result types are trivially correct, because eval_fallback runs on all unhandled statements and corrupts whichever it touches.
Expected behaviour
eval_fallback should correctly handle multiple variadic groups by zipping each group's declared type against only the SSA values belonging to that group. Concretely, for a statement with groups [g1_type × n1, g2_type × n2], type resolution should see n1 arguments of g1_type followed by n2 arguments of g2_type, not n1 + n2 arguments zipped against [g1_type, g2_type].
Suggested fix location
src/kirin/analysis/typeinfer/analysis.py — TypeInference.eval_fallback (or the TypeResolution call it makes). The fix should reconstruct the argument-type sequence by iterating over the statement's argument groups (respecting the args_slice on each field) rather than over the flat stmt.args list paired with stmt.type_parameters.
Impact
Any dialect that declares statements with two or more variadic argument groups of different element types is affected. Single-group variadics and non-variadic statements are not affected. The issue is silent for void-result statements (wrong types but no exception), making it easy to miss in testing.
Environment
- Kirin version: current
main (confirmed against bloqade-lanes / bloqade-circuit as of 2026-08)
- Downstream reproducer:
lib/bicycle dialect in a private QEC dialect framework
Claude found an issue revealed during development of an internal repo.
eval_fallbackcorrupts result types for statements with multiple mixed-type variadic argument groupsSummary
TypeInference.eval_fallbackproduces incorrect result types — or raises an internal error — when a statement has more than one variadic argument group (tuple[ir.SSAValue, ...]fields) with different declared element types. The fallback appears to zip field-level types (one per variadic group) against the flat list of SSA values (one per element across all groups), causing a type-count mismatch and incorrect type resolution.Minimal reproducer
When
TypeInferenceencountersMixedVariadicStmtwith, say, 3blocksand 3thetas(6 total SSA inputs),eval_fallbacksees 2 declared argument types but 6 SSA values. The zip truncates at 2, leaving 4 values unprocessed, andTypeResolutionreceives a malformed argument-type pairing.For void-result statements this silently produces wrong types; for result-bearing statements it can corrupt the inferred result type or raise internally.
Observed behaviour
In a downstream dialect (
ParallelRzGate) with fields:calling
TypeInferwithout an explicit@impl(ParallelRzGate)handler causes the type ofblockselements to be resolved asFloat(the second group's type) aftereval_fallbackzips incorrectly. The workaround is to register an explicit — and essentially content-free — handler for every affected statement:This workaround must be repeated for every statement in the dialect that has any variadic group, even those whose result types are trivially correct, because
eval_fallbackruns on all unhandled statements and corrupts whichever it touches.Expected behaviour
eval_fallbackshould correctly handle multiple variadic groups by zipping each group's declared type against only the SSA values belonging to that group. Concretely, for a statement with groups[g1_type × n1, g2_type × n2], type resolution should seen1arguments ofg1_typefollowed byn2arguments ofg2_type, notn1 + n2arguments zipped against[g1_type, g2_type].Suggested fix location
src/kirin/analysis/typeinfer/analysis.py—TypeInference.eval_fallback(or theTypeResolutioncall it makes). The fix should reconstruct the argument-type sequence by iterating over the statement's argument groups (respecting theargs_sliceon each field) rather than over the flatstmt.argslist paired withstmt.type_parameters.Impact
Any dialect that declares statements with two or more variadic argument groups of different element types is affected. Single-group variadics and non-variadic statements are not affected. The issue is silent for void-result statements (wrong types but no exception), making it easy to miss in testing.
Environment
main(confirmed againstbloqade-lanes/bloqade-circuitas of 2026-08)lib/bicycledialect in a private QEC dialect framework