Skip to content

Reject unsupported zero-result ops in ZKLean conversion#496

Open
Kuhai9801 wants to merge 6 commits into
project-llzk:mainfrom
Kuhai9801:reject-unsupported-zklean-ops
Open

Reject unsupported zero-result ops in ZKLean conversion#496
Kuhai9801 wants to merge 6 commits into
project-llzk:mainfrom
Kuhai9801:reject-unsupported-zklean-ops

Conversation

@Kuhai9801

Copy link
Copy Markdown
Contributor

Summary

Fixes #495.

--convert-llzk-to-zklean previously rejected unsupported operations only when they produced SSA results. Unsupported zero-result operations could therefore fall through without diagnostics, allowing constraint operations such as constrain.in or zero-result function.call to be omitted from the emitted ZKLean module while conversion still succeeded.

This change makes the converter fail on every unhandled operation except an empty function.return.

Changes

  • Treat only zero-operand function.return as an intentional no-op during LLZK-to-ZKLean conversion.
  • Emit an unsupported-op diagnostic for all other unhandled operations, including zero-result ops.
  • Reject multi-block LLZK functions before conversion, since the converter only processes a single block.
  • Add regression coverage for:
    • constrain.in
    • zero-result constraint helper calls
    • result-bearing function.return

Testing

  • git diff --check

@Kuhai9801 Kuhai9801 requested a review from a team as a code owner May 29, 2026 19:43
@Kuhai9801 Kuhai9801 marked this pull request as draft May 29, 2026 19:59
@Kuhai9801 Kuhai9801 force-pushed the reject-unsupported-zklean-ops branch from b85c69a to 3e599cd Compare May 30, 2026 03:02
@Kuhai9801 Kuhai9801 marked this pull request as ready for review May 30, 2026 20:42
@tim-hoffman tim-hoffman requested a review from Copilot June 1, 2026 14:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a correctness hole in the LLZK → ZKLean conversion pass (--convert-llzk-to-zklean) where unsupported operations that produce zero SSA results could be silently ignored, allowing constraint semantics to be dropped without diagnostics (Fixes #495).

Changes:

  • Reject all unhandled operations during conversion (including zero-result ops), except for an empty function.return treated as an intentional no-op.
  • Reject multi-block function.def bodies up-front since the converter only processes a single block.
  • Add lit regression tests for dropped zero-result constraint ops / calls and for result-bearing function.return, plus a changelog entry.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
backends/zklean/lib/Conversions/LLZKToZKLean.cpp Tightens error handling to fail on unhandled ops (including zero-result), treats only empty function.return as no-op, rejects multi-block functions, and emits a module-level failure when nothing is converted.
test/Conversions/llzk_to_zklean_unsupported_zero_result_fail.llzk Adds regression coverage to ensure unsupported zero-result ops and value-returning function.return fail with diagnostics.
test/Conversions/llzk_to_zklean_no_eligible_fail.llzk Verifies the pass fails when no eligible functions are converted (no ZKLean module produced).
changelogs/unreleased/reject-unsupported-zklean-ops.yaml Documents the fix in the unreleased changelog.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +401 to +405
if (!func.getBody().hasOneBlock()) {
func.emitError("ZKLean conversion only supports single-block functions").report();
state.hadError = true;
return false;
}

@tim-hoffman tim-hoffman left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial feedback

Comment thread backends/zklean/lib/Conversions/LLZKToZKLean.cpp Outdated
Comment thread backends/zklean/lib/Conversions/LLZKToZKLean.cpp Outdated
@tim-hoffman

tim-hoffman commented Jun 1, 2026

Copy link
Copy Markdown
Member

@benoitrazet, this PR revealed a few scenarios that are not handled in the llzk-to-zklean conversion and I'm hoping you can give some feedback about what's expected from the zklean backend.

  1. The transformation does not currently support structs that use other structs for sub-circuits (see: circomlib.llzk where the error "unsupported member type for ZKLean struct conversion" occurs because of the struct.type member, and convertOperation() has no handling for CallOp). Should the transformation handle subcomponents directly or is it expected to run the inline-structs pass first? If the latter, I think we should just make it a pipeline that always runs that pass.
  2. Since there is no handling for CallOp, free (non-struct) functions called from a @constrain function would also be dropped (see: poseidon). The inline-structs pass will not help in this case so the common question is, can the ZKLean output contain function calls? If not, we will need a pass to inline these as well (fitting into my idea of making it a pipeline if necessary).
  3. The constrain.in op is not currently handled. Does ZKLean have a means to represent that op?

@Kuhai9801 Kuhai9801 force-pushed the reject-unsupported-zklean-ops branch from 91fd3be to 788f14b Compare June 2, 2026 02:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LLZK-to-ZKLean conversion silently drops zero-result constraint operations

3 participants