Skip to content

Use NotImplemented as the infer-default sentinel; free None as a literal value#10

Merged
behdad merged 2 commits into
masterfrom
fix/default-none-literal
Jul 1, 2026
Merged

Use NotImplemented as the infer-default sentinel; free None as a literal value#10
behdad merged 2 commits into
masterfrom
fix/default-none-literal

Conversation

@behdad

@behdad behdad commented Jul 1, 2026

Copy link
Copy Markdown
Member

Problem

f0495bc ("Support inferred defaults from boundary values") repurposed
default=None to mean "infer the default". That collided with None being a
legitimate value: HarfBuzz's decomposition (dm) dataset packs a dict
with default=None and a mapping that sends None -> 0 ("no decomposition").
After that commit, regenerating HarfBuzz's tables fails:

ValueError: default=None is only supported for list input

This was a latent break since f0495bc; it surfaces whenever HarfBuzz is
regenerated against current packtab.

Fix

Move the inference request off None and onto the explicit sentinel
NotImplemented, restoring None as an ordinary value:

pack_table(list_data, default=NotImplemented)    # infer from boundary values
pack_table(dict_data, default=None, mapping=m)    # None is a real, mapped value
  • None is now mapped like any other value (e.g. None -> 0).
  • Inference is requested with default=NotImplemented (list input only; dict + NotImplemented still raises).
  • Default remains 0, so existing callers are unaffected.
  • In the Rust port this is naturally expressed with Option; NotImplemented
    is the Python equivalent now that None is a real value.

Also included

  • Repair Code.print_h, which referenced a nonexistent Function.linkage and
    would raise AttributeError if called. It now emits valid C prototypes for
    the public functions. Not on any generated-code path — no output changes.

Verification

  • pytest: 231 passing (updated inference tests to NotImplemented; added
    tests that None is a literal value with a mapping, and that dict + NotImplemented raises).
  • End-to-end: make -f update-unicode-tables.make clean all in HarfBuzz now
    succeeds, and hb-ucd-table.hh regenerates byte-identical to the
    committed table.

🤖 Generated with Claude Code

behdad and others added 2 commits July 1, 2026 12:04
print_h referenced a nonexistent Function.linkage attribute and would raise
AttributeError if ever called.  Emit valid C prototypes for the public
functions instead (private static helpers are skipped, as befits a header).
It is not on any generated-code path, so no generated output changes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
default=None was repurposed in f0495bc to mean "infer the default from the
boundary values", which collided with None as a legitimate *value*: HarfBuzz's
decomposition table packs a dict with default=None and a mapping that sends
None -> 0 ("no decomposition"), and that stopped working (ValueError:
"default=None is only supported for list input").

Restore None as an ordinary value (mapped like any other) and move the
inference request to the explicit sentinel NotImplemented:

  pack_table(list_data, default=NotImplemented)   # infer from boundaries
  pack_table(dict_data, default=None, mapping=m)   # None is a real value

dict + NotImplemented still raises (inference needs list input).  Verified by
regenerating HarfBuzz's Unicode tables (make -f update-unicode-tables.make
clean all): succeeds and hb-ucd-table.hh is byte-identical to the committed
table.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@behdad behdad merged commit da4bf94 into master Jul 1, 2026
8 checks passed
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