check: report a generic struct, and say which backend lowers it - #3454
Merged
Conversation
Closes #3453 pub const Map(K, V) = struct { ... } $ t27c check specs/tri/collections/map.t27 Typecheck OK (0 errors, 0 warnings) while the generated C says `unknown type name 'K'`. Nothing noticed because the tolerance is deliberate: the parser records the type parameters and `collect_type_params` hands them to the unknown-type check so `K` and `V` are not reported as undeclared. Correct in itself, and it silences the only reader that might have said something about the rest. THE OBVIOUS MESSAGE WOULD HAVE BEEN FALSE. "No backend lowers generics" -- measured, one does: gen-rust pub struct Box<T>, pub fn get<T>(b: Box<T>) COMPILES gen-c struct Box { ... } without the parameter, then get(Box(T) b) "unknown type name 'T'" gen-zig pub const Box = struct, then get(b: Box(T)) "use of undeclared identifier 'T'" gen-verilog per-field regs, UNSUPPORTED_ICARUS Two backends drop the parameter from the declaration and keep it at every use. That inconsistency is what the warning states, and a test compiles gen-rust's output so the credited half is a checked claim rather than a nicer sentence. Population, from the AST: 28 specs, 33 generic types, all under specs/tri/. A matcher over generated C prototypes said 8 files and 36 prototypes; that is a DIFFERENT question -- C prototypes carrying a two-parameter application -- and it cannot see a single `Option(T)`. Measured over 651 specs: exit codes 573 and 78 before and after, and NOT ONE moved. Whether C and Zig should monomorphise, refuse, or drop the parameter at the use site as well is a design question and is not part of this. FOUND BY ACCIDENT, and worth recording as such. The parity table gained combinations, and a matcher written to count TUPLE parameters caught `Map(K, V)` instead, because a tuple and a generic application are both `Name(A, B)`. The tuple defect it was aiming at is real -- C emits `probe((u8, i32) x)` verbatim, though `c_tuple_info` already handles the return position -- and has a corpus population of ZERO, as does `[]*i32` reaching C as `*i32* x`. Both are latent and said to be. Three mutants, three dead. The first was verified to be a COMPILE failure (E0282) rather than assumed to be a pass from an empty result. `diagnostic_capacity.py` now prints each instrument's version beside its count. The same command gave 20 here and 50 on CI because one `cc` is Apple clang and the other gcc: a diagnostic count measures the code, the instrument AND the machine, and only the first was ever written down. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gHashTag
enabled auto-merge (squash)
September 8, 2026 02:42
Contributor
|
📓 NotebookLM Notebook linked to this PR
This notebook contains session context, decisions, and artifacts for this work. |
Contributor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3453
while the generated C says
unknown type name 'K'.Nothing noticed because the tolerance is deliberate: the parser records the
type parameters and
collect_type_paramshands them to the unknown-type checkso
KandVare not reported as undeclared. Correct in itself — and itsilences the only reader that might have said something about the rest.
The obvious message would have been false
"No backend lowers generics." Measured — one does:
gen-rustpub struct Box<T>,pub fn get<T>(b: Box<T>)gen-cstruct Box { … }— parameter dropped — thenget(Box(T) b)unknown type name 'T'gen-zigpub const Box = struct, thenget(b: Box(T))use of undeclared identifier 'T'gen-verilogUNSUPPORTED_ICARUSTwo backends drop the parameter from the declaration and keep it at every
use. That inconsistency is what the warning states, and
gen_rust_really_does_lower_a_genericcompiles gen-rust's output so thecredited half is a checked claim rather than a nicer sentence.
Population
From the AST: 28 specs, 33 generic types, all under
specs/tri/.A matcher over generated C prototypes said "8 files, 36 prototypes" — a
different question (C prototypes carrying a two-parameter application),
blind to every
Option(T).Measured over 651 specs: exit codes 573 / 78 before and after, not one
moved.
Found by accident, and recorded as such
The parity table gained combinations, and a matcher written to count
tuple parameters caught
Map(K, V)instead — a tuple and a genericapplication are both
Name(A, B).The tuple defect it was aiming at is real and latent: C emits
probe((u8, i32) x)verbatim, thoughc_tuple_infoalready handles thereturn position. Corpus population 0, as for
[]*i32reaching C as*i32* x. Both said to be zero rather than left implied.Mutation
The first attempt at mutant 1 did not compile (
E0282) — verified as a buildfailure rather than assumed to be a pass from an empty result. Full suite:
2620 passed, 0 failed.
Also
diagnostic_capacity.pynow prints each instrument's version beside its count.The same command gave 20 here and 50 on CI because one
ccis Apple clang andthe other gcc — a diagnostic count measures the code, the instrument and the
machine, and only the first was ever written down.