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
28 changes: 27 additions & 1 deletion bootstrap/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22229,6 +22229,20 @@ pub struct RustCodegen {
bool_fns: std::collections::HashSet<String>,
/// Parameters and locals of the current function declared `bool`.
bool_vars: std::collections::HashSet<String>,
/// Field names this FILE declares as `bool`.
///
/// `expr_is_bool` had no arm for `ExprFieldAccess`, so a condition on a
/// bool field fell to the integer default: `!debouncer.enabled` was emitted
/// as `((debouncer.enabled) == 0)`, which rustc rejects with E0308. The
/// emitter prints `pub enabled: bool,` into the same file and never
/// consulted it.
///
/// Keyed by NAME, not by (struct, field): measured over the corpus, zero
/// of the 650 specs declare one field name as `bool` in one struct and as
/// something else in another, so within a single generated file the name
/// is unambiguous. 35 names collide ACROSS files, which is why this is
/// cleared per file and never shared.
bool_fields: std::collections::HashSet<String>,
/// Rust type of every explicitly typed parameter/local of the current
/// function. Feeds `infer_int_type`.
var_types: std::collections::HashMap<String, String>,
Expand Down Expand Up @@ -22263,6 +22277,7 @@ impl RustCodegen {
fn_ret_type: String::new(),
bool_fns: std::collections::HashSet::new(),
bool_vars: std::collections::HashSet::new(),
bool_fields: std::collections::HashSet::new(),
var_types: std::collections::HashMap::new(),
const_types: std::collections::HashMap::new(),
fn_ret_types: std::collections::HashMap::new(),
Expand Down Expand Up @@ -22418,6 +22433,9 @@ impl RustCodegen {
if child.kind == NodeKind::ExprIdentifier && !child.name.is_empty() {
let field_name = &child.name;
let field_type = Self::t27_type_to_rust(&child.extra_type);
if field_type.trim() == "bool" {
self.bool_fields.insert(field_name.clone());
}
self.write_line(&format!("pub {}: {},", field_name, field_type));
}
}
Expand Down Expand Up @@ -22516,7 +22534,14 @@ impl RustCodegen {

// Check if there's a body
let has_body = node.children.iter().any(|c| {
matches!(c.kind, NodeKind::ExprReturn | NodeKind::StmtExpr | NodeKind::StmtLocal | NodeKind::StmtIf | NodeKind::StmtWhile | NodeKind::StmtFor | NodeKind::StmtForRange)
// StmtAssign was absent, so a function whose body is assignments
// ONLY tested as bodiless and was emitted as `{ unimplemented!() }`
// -- a stub rustc accepts everywhere and that panics at run time.
// 53 functions in 35 specs, and Zig and C lower every one: the
// clock `tick()` in the FPGA testbenches, `uart_reset`, six state
// setters in top_level, both `on_clock` hardware steps. Exactly the
// pure-mutation functions a state machine is made of.
matches!(c.kind, NodeKind::ExprReturn | NodeKind::StmtExpr | NodeKind::StmtLocal | NodeKind::StmtAssign | NodeKind::StmtIf | NodeKind::StmtWhile | NodeKind::StmtFor | NodeKind::StmtForRange)
});

// Infer which locals need `let mut`: scan body for any assignment.
Expand Down Expand Up @@ -23071,6 +23096,7 @@ impl RustCodegen {
NodeKind::ExprLiteral => node.value == "true" || node.value == "false",
NodeKind::ExprIdentifier => self.bool_vars.contains(&node.name),
NodeKind::ExprCall => self.bool_fns.contains(&node.name),
NodeKind::ExprFieldAccess => self.bool_fields.contains(&node.name),
_ => false,
}
}
Expand Down
2 changes: 1 addition & 1 deletion bootstrap/stage0/FROZEN_HASH
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6e3be54a2bd0d899ec680c429be131b9cbf4a857d7bbb578870dbe16dd01b132
95f7168a95945074ce97e0737e9f0a27fa8e35014da1f4d5642a25968bcb9562
12 changes: 12 additions & 0 deletions docs/now/2026-08-30-two-hardcoded-lists-missing-a-case.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# NOW -- Two hardcoded lists, each missing a case (2026-08-30)

## The Rust backend, never audited before (Refs #2844)

- `has_body` decides whether a function has a body by matching statement kinds against a fixed list, and StmtAssign was absent
- so a function whose body is assignments ONLY tested as bodiless and was emitted as `{ unimplemented!() }` -- a stub rustc accepts everywhere and that panics at run time
- 53 functions in 35 specs, and Zig and C lower every one: the clock `tick()` in the FPGA testbenches, `uart_reset`, six state setters, both `on_clock` hardware steps
- `expr_is_bool` had no arm for ExprFieldAccess, so `!debouncer.enabled` became `((debouncer.enabled) == 0)` -- E0308, a hard rustc error
- the emitter prints `pub enabled: bool,` into the same file and never consulted it; now it remembers, per file
- keyed by NAME and not by (struct, field) because ZERO of the 650 specs declare one field name as bool in one struct and something else in another; 35 names collide ACROSS files, which is why the set is cleared per file
- measured: unimplemented stubs 870 -> 817, integer zero-tests on a bool field 25 -> 2, rustc accepts 214 -> 216
- this is #2844 one level up: that fixed the CONTENT of the assignment arms; this is the gate that stopped them being reached
Loading