Skip to content

fix(serializer): preserve TypeAttribute reference identity - #713

Merged
weinbe58 merged 2 commits into
mainfrom
dl/serializer-attribute-instances
Sep 1, 2026
Merged

fix(serializer): preserve TypeAttribute reference identity#713
weinbe58 merged 2 commits into
mainfrom
dl/serializer-attribute-instances

Conversation

@zhenrongliew

Copy link
Copy Markdown
Collaborator

Summary

Serialization should preserve identity relationships:

Original IR (De)serialized-roundtrip IR
Same instance referenced twice One new instance referenced twice
Two distinct but equal instances Two distinct but equal new instances

Motivation

#711 encodes repeated TypeAttribute instances as one definition followed by
attr_refs. However, the decoder recreated the referenced definition for every
attr_ref, preserving v1's value behavior but losing the identity relationship of the original IR.

As @weinbe58 demonstrated, this can also make decoding exponential:

typ = types.Generic(tuple, typ, types.Vararg(typ))

Each level references the previous type twice. The serialized DAG is linear, but
recreating every reference expands it into a binary tree during decoding.

Fix

Add a TypeAttribute_Lookup instance table to SerializationContext. Each
TypeAttribute definition is decoded once and cached by its serialization ID;
subsequent attr_refs return that same instance.

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

☂️ Code Coverage

current status: ✅

Overall Coverage

Statements Covered Coverage Threshold Status
11889 10725 90% 0% 🟢

New Files

No new covered files...

Modified Files

File Coverage Status
src/kirin/ir/attrs/types.py 88% 🟢
src/kirin/serialization/base/context.py 96% 🟢
src/kirin/serialization/base/deserializer.py 84% 🟢
TOTAL 89% 🟢

updated for commit: c85e772 by action🐍

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-09-01 13:20 UTC

@codecov

codecov Bot commented Aug 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@weinbe58

Copy link
Copy Markdown
Member

Verified the fix separately — the exponential decode is gone (flat ~0.5 ms across depths 8–22, vs ~43 s at depth 22 before), encode is unaffected, and the full suite is green.

One coverage regression worth fixing before merge: rewriting test_nested_type_graph_preserves_v1_value_semantics into test_nested_type_graph_preserves_identity_relationships dropped the only Union/Literal coverage in the serialization tests. The old version built types.Literal(1, leaf) and types.Union(literal, types.String); the new one only exercises Generic. After this PR, types.Union and types.Literal appear in no serialization test anywhere under test/ — on main they're at test_type_attribute_refs.py:190-191.

Worth keeping because those two have the least ordinary construction paths, and they interact with the new TypeAttribute_Lookup caching in ways Generic doesn't exercise: UnionMeta.__call__ does subset-simplification and can return a member instead of a Union, and LiteralMeta interns on (data, datatype). A small separate test that round-trips a nested Union/Literal graph and asserts the shared leaf comes back shared would cover it — no need to restore the old test's shape.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

@zhenrongliew

Copy link
Copy Markdown
Collaborator Author

Verified the fix separately — the exponential decode is gone (flat ~0.5 ms across depths 8–22, vs ~43 s at depth 22 before), encode is unaffected, and the full suite is green.

One coverage regression worth fixing before merge: rewriting test_nested_type_graph_preserves_v1_value_semantics into test_nested_type_graph_preserves_identity_relationships dropped the only Union/Literal coverage in the serialization tests. The old version built types.Literal(1, leaf) and types.Union(literal, types.String); the new one only exercises Generic. After this PR, types.Union and types.Literal appear in no serialization test anywhere under test/ — on main they're at test_type_attribute_refs.py:190-191.

Worth keeping because those two have the least ordinary construction paths, and they interact with the new TypeAttribute_Lookup caching in ways Generic doesn't exercise: UnionMeta.__call__ does subset-simplification and can return a member instead of a Union, and LiteralMeta interns on (data, datatype). A small separate test that round-trips a nested Union/Literal graph and asserts the shared leaf comes back shared would cover it — no need to restore the old test's shape.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

Restored separate Union/Literal structural round-trip coverage and added a test where a TypeVar is shared between a Literal and a Generic.
The identity test exposed an issue: Literal.deserialize called the normal Literal(...) constructor, whose LiteralMeta cache could return the source Literal. That retained the source leaf instead of the decoded leaf, so the objects were structurally equal but the shared instance was lost.
I updated Literal.deserialize to reconstruct a fresh instance without consulting the process-local interning cache.

@weinbe58 weinbe58 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.

LGTM

@weinbe58
weinbe58 merged commit 024f6ce into main Sep 1, 2026
11 checks passed
@weinbe58
weinbe58 deleted the dl/serializer-attribute-instances branch September 1, 2026 13:20
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Backport results for 024f6ce

Succeeded:

zhenrongliew pushed a commit that referenced this pull request Sep 2, 2026
Automated backport of PR #713 (024f6ce)
to `release-0-22`.

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants