Skip to content

[ Claude ] eval_fallback bug #710

Description

@jon-wurtz

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.pyTypeInference.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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    category: bugCategory: this is a bug or something isn't working as expected.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions