Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions NOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

Last updated: 2026-08-09

## typecheck: warnings are PRINTED, and the unused-variable false positive is fixed (Refs #1948)

- `typecheck` built every warning message and then dropped it: the OK branch printed only the total, so a warning was unactionable -- you could watch the number grow and never learn what it was. The messages were already in `result.errors`; they are printed now. Some are real correctness findings downgraded to warnings (a call to an undefined function, an argument type mismatch), so the silence actively hid defects
- Printing them immediately exposed a detector bug: a BARE bracket literal (`[a0, 99]`, no `[N]Type{...}` prefix) never becomes child nodes -- the parser captures the whole bracket body as element TEXT in `extra_size`. The unused-variable pass read only children, so every identifier used that way was reported unused. That is the idiomatic "bind elements to locals, then rebuild the array" pattern (health_monitoring::update_health_check, key_management::set_key_slot, cross_layer_optimizer/redundancy_management::set_slot4). `collect_reads` now scans the element text too -- it can only ADD reads, so it removes false warnings and can never introduce one
- tri-net corpus: unused-variable warnings 34 -> 14 (20 were false), total 788 -> 768; all 107 specs still typecheck clean
- FROZEN_HASH resealed


## gen-zig: narrowing unsigned cast lowers to @truncate (Refs #1948)

- t27 `as` truncates a narrowing integer cast (Rust semantics), but gen-zig always emitted checked `@intCast` -> panics in safe builds when the value does not fit (`weighted_total as u32` on a 2^32 multiple)
Expand Down
27 changes: 27 additions & 0 deletions bootstrap/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13782,6 +13782,33 @@ pub fn typecheck_ast(ast: &Node) -> TypeCheckResult {
if node.kind == NodeKind::ExprIdentifier {
reads.insert(node.name.clone());
}
// A BARE bracket literal (`[a0, 99]`, no `[N]Type{...}` prefix)
// never becomes child nodes: the parser captures the whole
// bracket body as element TEXT in extra_size. Reading only
// children therefore missed every identifier used that way and
// reported it as an unused variable -- a false positive on the
// idiomatic "bind the elements to locals, then rebuild the
// array" pattern (health_monitoring::update_health_check,
// key_management::set_key_slot, and others). Scan the text too.
// This can only ADD reads, so it removes false warnings and can
// never introduce one.
if node.kind == NodeKind::ExprArrayLiteral && !node.extra_size.is_empty() {
let mut ident = String::new();
for ch in node.extra_size.chars() {
if ch.is_alphanumeric() || ch == '_' {
ident.push(ch);
} else {
if !ident.is_empty() && !ident.starts_with(|c: char| c.is_ascii_digit()) {
reads.insert(std::mem::take(&mut ident));
} else {
ident.clear();
}
}
}
if !ident.is_empty() && !ident.starts_with(|c: char| c.is_ascii_digit()) {
reads.insert(ident);
}
}
for child in &node.children {
collect_reads(child, reads);
}
Expand Down
10 changes: 10 additions & 0 deletions bootstrap/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4624,6 +4624,16 @@ fn run_typecheck(input_path: &str, json: bool) -> anyhow::Result<()> {
println!("{}", serde_json::to_string_pretty(&resp).unwrap());
} else if result.ok {
println!("Typecheck OK (0 errors, {} warnings)", result.warnings);
// tri-net#375 pinned every spec's warning count, but the messages were
// built and then dropped on the floor: the OK branch printed only the
// total, so a warning was unactionable -- you could see the number grow
// and not what it was. They are already in result.errors; print them.
// Some of these are real correctness findings downgraded to warnings
// (a call to an undefined function, an argument type mismatch), so
// silence here actively hid defects.
for msg in &result.errors {
println!(" - {}", msg);
}
} else {
println!("Typecheck FAILED ({} errors, {} warnings):", result.error_count, result.warnings);
for err in &result.errors {
Expand Down
2 changes: 1 addition & 1 deletion bootstrap/stage0/FROZEN_HASH
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6c30e43706ecea81acaab117b97615d989a071d7973b4e390a78f7a794f69bb5
cd2822f290eb04ed9b6a6530357fea22dff6e09a4fb1ad7575ffc7d6ec744ff7
8 changes: 8 additions & 0 deletions docs/NOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ Last updated: 2026-08-09

Last updated: 2026-08-09

## typecheck: warnings are PRINTED, and the unused-variable false positive is fixed (Refs #1948)

- `typecheck` built every warning message and then dropped it: the OK branch printed only the total, so a warning was unactionable -- you could watch the number grow and never learn what it was. The messages were already in `result.errors`; they are printed now. Some are real correctness findings downgraded to warnings (a call to an undefined function, an argument type mismatch), so the silence actively hid defects
- Printing them immediately exposed a detector bug: a BARE bracket literal (`[a0, 99]`, no `[N]Type{...}` prefix) never becomes child nodes -- the parser captures the whole bracket body as element TEXT in `extra_size`. The unused-variable pass read only children, so every identifier used that way was reported unused. That is the idiomatic "bind elements to locals, then rebuild the array" pattern (health_monitoring::update_health_check, key_management::set_key_slot, cross_layer_optimizer/redundancy_management::set_slot4). `collect_reads` now scans the element text too -- it can only ADD reads, so it removes false warnings and can never introduce one
- tri-net corpus: unused-variable warnings 34 -> 14 (20 were false), total 788 -> 768; all 107 specs still typecheck clean
- FROZEN_HASH resealed


## numeric: GF-T registered in the catalog SSOT, all nine rungs (Refs #2001)

- `specs/numeric/formats_catalog.t27` had **zero GF-T rows** -- the only `gft` id was `gfternary`, a different object (2-bit {-phi,0,+phi} alphabet, not a float with a balanced-ternary exponent field). Four rungs existed as specs with no row and no pack; five did not exist at all, while `zig-golden-float/specs/gft.tri` named this directory as its own source of truth
Expand Down
Loading