Skip to content

spec: Typecheck padding#670

Open
RobinJadoul wants to merge 8 commits into
spec/mainfrom
spec/typecheck-padding
Open

spec: Typecheck padding#670
RobinJadoul wants to merge 8 commits into
spec/mainfrom
spec/typecheck-padding

Conversation

@RobinJadoul

Copy link
Copy Markdown
Collaborator

This manages to catch both the observed issue with the CPUs padding for half_instruction_length and an previously unknown issue in the padding for DVRM.

@RobinJadoul RobinJadoul requested a review from erik-3milabs June 16, 2026 11:20
@RobinJadoul RobinJadoul self-assigned this Jun 16, 2026
@RobinJadoul RobinJadoul added the spec Updates and improvements to the spec document label Jun 16, 2026
@github-actions

Copy link
Copy Markdown

Codex Code Review

No issues found in the PR diff.

I reviewed the changed TOML padding values and the new recursive padding/template checker in spec/tooling/chip.py. I also ran:

python spec/tooling/chip.py spec/src/config.toml spec/src/signatures.toml spec/src/*.toml

It completed with No issues were found.

Comment thread spec/tooling/chip.py
Comment thread spec/tooling/chip.py Outdated
@claude

claude Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review: spec/typecheck-padding

Summary

This PR introduces type-checking for padding values in chip specs, fixing two concrete bugs:

  • half_instruction_length had pad 2 (incorrect) → now 0
  • q in DVRM had pad 0 (incorrect for a 4-element array type) → now ["arr", 65535, 65535, 65535, 65535]

It also reorders carry_a/carry_e in sha256round so they appear after temp1/temp2 (which they depend on), required by the new populate_env ordering contract.

The overall approach is sound. Two issues worth addressing:

Issues

Medium – Signature.matches ignores the new condition field (see inline)
The field is populated via build_signature and InteractionLike.typecheck, but matches never compares it. If condition types are intentionally excluded from structural matching, a comment explaining why would prevent future confusion.

Medium – Unhandled KeyError in check_assignment (see inline)
check_template[sig.tag] will crash with a Python traceback for any unknown template tag. Since tags come from TOML files, a typo would produce an unguarded exception instead of a reporter.error. It also leaves the context stack dirty (push without pop) which corrupts subsequent error locations.

Minor notes

  • The push_context/pop_context pattern appears in several places without try/finally. This is fine as long as reporter.error never raises — but the KeyError above shows a case where it can. Worth keeping in mind as the checker grows.
  • The workaround comment in CastExpr.typecheck ("This may become cleaner if we eventually get to the cast rework from spec: Tighter range checks #326") is a good breadcrumb; no action needed now.

Comment thread spec/src/dvrm.toml

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I agree that the padding is invalid.
The proposed solution works.
A cleaner solution might be to have div_by_zero = 0.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Encoding 0/1 = 0 then?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Aha, the downside is that it makes the NEG workaround no longer work, because then we have NEG<1, signed>

Comment thread spec/tooling/chip.py Outdated
if file in sys.argv[1:3]:
continue
chips.append(Chip.from_file(config, file))
chips.append(chip := Chip.from_file(config, file))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not a fan of the walrus here.

Suggested change
chips.append(chip := Chip.from_file(config, file))
chip = Chip.from_file(config, file)
chips.append(chip)

Comment thread spec/tooling/chip.py Outdated
continue
chips.append(Chip.from_file(config, file))
chips.append(chip := Chip.from_file(config, file))
template_checkers[chip.name] = template_checker(template_checkers, chip)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this recursion is trippy: to set template_checkers[some chip]: Callable, it passes in all of template_checkers, which gets bound (?) into a function which is then returned?

This, I believe, requires proper documentation, either directly here, or by wrapping this in a well-named function and documenting that function. I cannot make heads or tails of what is happening here, nor what template_checkers even means / is supposed to do.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

template_checkers is a collection of functions, indexed by template name/tag, that checks whether a given assignment satisfies the template.

Passing in template_checkers could be delayed to the invocations of these checkers as well, we're just tying the knot a bit earlier here.
We need to pass template_checkers to an individual checker somewhere to be able to deal with templates inside of a template definition (such as IS_BIT inside of ADD).
The downside of delaying the access to all templates to later is that the typing of template_checkers itself needs to become recursive, since now the Callable needs an argument of the type dict[str, Callable[dict[...], Optional[Type], ...]. Which could in itself work out

Comment thread spec/tooling/chip.py Outdated
Comment on lines +405 to +413
def check_padding_fits(var_name: str, config: "Config", type: Type, pad: Expr):
def fits(v, t):
if isinstance(v, Range):
return v.is_const() and constant_fits(v.get_const(), t)
else:
return isinstance(v, list) and isinstance(t, list) and len(v) == len(t) and all(map(fits, v, t))

val = pad.typecheck(Environment(config, {}, {}))
reporter.asserts(fits(val, type), f"{var_name!r}: Invalid padding {pad!r} for type {type!r}")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Given that var_name is passed in to be solely passed on to reporter, consider passing it in through reporter.context to give this function a cleaner signature.

Comment thread spec/tooling/chip.py

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we do something about the names typecheck, type_match and Type?
To me, typecheck suggests a function with boolean output (fail/pass), but instead it returns an object of type Type (another stumbling block), which is actually an evaluation of sorts.
I also never know what the difference between typecheck and type_match are supposed to be.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is using type checking as the act of assigning types to expressions. While technically the correct term for this may actually be typing, that feels more confusing to me.
Type being a type is kinda inherent to the reification of types that you need in a context like this.

type_match is more of a local thing for individual kinds of expression, that may have a different name possible. Where it is used, it's doing essentially some combination of type coercion to make operands compatible and computing the type for the combination of the result. The reason it's separate from the typecheck method in those places is because there's a variadic number of operands in those expressions, and we collapse them with a fold. Maybe typecheck_binary is a replacement name?

@RobinJadoul RobinJadoul requested a review from erik-3milabs June 16, 2026 15:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

spec Updates and improvements to the spec document

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants