Skip to content

feat(codegen): struct field access + container equality — TASK-29 Phase B (Tasks 3–4 of 4) - #9

Merged
ahrzb merged 3 commits into
masterfrom
codegen-container-access-compare
Jul 23, 2026
Merged

feat(codegen): struct field access + container equality — TASK-29 Phase B (Tasks 3–4 of 4)#9
ahrzb merged 3 commits into
masterfrom
codegen-container-access-compare

Conversation

@ahrzb

@ahrzb ahrzb commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Summary

Completes Phase B of the codegen deferred surface: struct field access and struct/list equality. With Tasks 1–2 (merged in #4) this retires every container differential skip except UNNEST — the 5 remaining skips are all UNNEST, deliberately left for Phase C.

Plan: docs/superpowers/plans/2026-07-22-codegen-deferred-phase-b-containers.md (Tasks 3–4).

What's in this PR

Commit What
bee2b39 Task 3 — struct field access. New FieldAccess IR node threaded through _convert_expr/infer_type/_validate_expr/_emit_expr + runtime.getfield. _convert_expr layers FieldAccess over multi-part columns (catalog/db/table qualifiers + leaf); the 2-part s.x stays a Column and is rewritten to FieldAccess in _validate_expr once schemas show the qualifier isn't a relation alias (mirrors native plan.rs). _validate_expr now returns the (possibly rewritten) node; every caller reassigns. Covers s.x, nested s.a.b, qualified t.s.x.
7a502a9 Task 4 — struct/list equality + container guard. runtime._veq (type-tagged deep equality: structs by key order+values, lists elementwise, scalars via val_eq so Int(1) != Float(1.0)); rt.eq/neq route containers through it. infer_type's BinaryOp arm checks containers firsteq/neq → BOOL, every other op defers — which also closes the Phase-A carryover where struct || x mistyped as STR.
795e3e9 Review fixes: fold an unquoted struct-column qualifier (S.xs.x, matching DataFusion); comment the deliberate drop of the 4-part catalog raise (lets t.s.a.b resolve); add list-inequality coverage.

Testing

uv run pytest530 passed, 5 skipped (all UNNEST/Phase C), 5 xfailed. All field-access and equality shapes are value-asserted against the DataFusion oracle on both backends (native + codegen).

  • Field access: s.x, nested s.a.b, qualified t.s.x (all pass on codegen).
  • Equality: struct eq true/false (deep, type-tagged), list eq/ineq.
  • xfail_on_native (codegen matches oracle, native has the gap): mixed-numeric list widening + the new uppercase-qualifier fold.

Scope limited to sql_transform/_codegen/ and tests/no native-engine changes.

Known limitations (out of Phase B's committed surface — flagged for tickets)

  • Native parity gaps surfaced by the diff tests: native doesn't implement struct/make_array construction or fold struct-column qualifiers. Documented via xfail_on_native.
  • struct = scalar returns False on codegen where DataFusion type-errors at planning.
  • Field access on a NULL struct: DataFusion returns 0 (not NULL); neither engine matches. Worth its own investigation.

Review

Ran requesting-code-review on Tasks 3–4 (including independent vetting of the inherited Task 3 code) → ready to merge, no Critical/Important issues. The 795e3e9 fixes address the Minor findings; the remaining two are the noted out-of-scope limitations above.

🤖 Generated with Claude Code

ahrzb and others added 3 commits July 23, 2026 06:53
FieldAccess IR node threaded through convert/validate/infer/emit + rt.getfield.
_convert_expr layers FieldAccess over multi-part columns (catalog/db/table
qualifiers + leaf); the 2-part s.x stays a Column and is rewritten to
FieldAccess in _validate_expr once schemas show the qualifier isn't a relation
alias (mirrors native plan.rs). _validate_expr now returns the (possibly
rewritten) node so callers reassign. Covers s.x, nested s.a.b, qualified t.s.x
against the DataFusion oracle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…29 Phase B (Task 4)

rt._veq: type-tagged deep equality (structs by key order+values, lists
elementwise, scalars via val_eq so Int(1) != Float(1.0)); rt.eq/neq route
containers through it. infer_type's BinaryOp arm now checks containers FIRST:
eq/neq -> BOOL, every other op (arithmetic, dpipe, ordering) defers. That
ordering also closes the Phase-A carryover where 'struct || x' mistyped as STR
instead of deferring. Struct/list equality matches the DataFusion oracle on
both backends.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…Tasks 3-4 review)

Review of Tasks 3-4 flagged an unquoted uppercase struct-column qualifier not
being folded: S.x built a lookup for column 'S' while DataFusion folds it to
's'. Fold the qualifier when the validate rewrite reinterprets it as a column
(safe: the relation lookup already matched it raw and missed). Locked with an
xfail_on_native diff test -- native has the same (worse) gap, wants a ticket.

Also: comment the deliberate drop of the plan's 4-part catalog raise (lets
t.s.a.b resolve via layered FieldAccess), and add list-inequality coverage.

Left unfixed (noted for tickets): struct=scalar returns False where DataFusion
type-errors; field access on a NULL struct (DataFusion returns 0, not NULL) --
both out of Phase B's committed surface.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Repository owner deleted a comment from claude Bot Jul 23, 2026
Repository owner deleted a comment from claude Bot Jul 23, 2026
@ahrzb

ahrzb commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

/review

@claude

claude Bot commented Jul 23, 2026

Copy link
Copy Markdown

Claude Code is working…

I'll analyze this and get back to you.

View job run

@ahrzb
ahrzb merged commit 8d398bf into master Jul 23, 2026
1 check passed
@ahrzb
ahrzb deleted the codegen-container-access-compare branch July 23, 2026 16:32
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.

1 participant