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
6 changes: 3 additions & 3 deletions .trinity/seals/MAC_Testbench.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"gen_hash_c": "sha256:33cf769212351db3c992bd82921dd80b938755b6da543061eaa4e7c39b552add",
"gen_hash_c": "sha256:bdd89dd7974bcb8980a5e3a935ae464b504217de90fe330bed17038588a2e030",
"gen_hash_rust": "sha256:80167949bd4cfe0a422b4a8fe273eb262d7fa1f98d8862a2f2b10ec64d86acf9",
"gen_hash_verilog": "sha256:9cab81dcdc6b62afe3b481d26ee1ea47ab2c776af8358624acdb6a0433f29e09",
"gen_hash_zig": "sha256:8928e5f9b62c3721e845fdc7acef8d518e8ea0c343572ca3e5a38303b5e1cffb",
"module": "MAC_Testbench",
"ring": 12,
"sealed_at": "2026-08-28T00:21:37Z",
"sealed_at": "2026-09-08T06:43:44Z",
"spec_hash": "sha256:af060b6e5cdb2ffe1de0a47995b2c621139367174cf85237d8217aa929af10f7",
"spec_path": "specs/fpga/testbench/mac_tb.t27"
}
}
4 changes: 2 additions & 2 deletions .trinity/seals/coder_igla-coder-eval.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"gen_hash_c": "sha256:5381b4a938de64d6fb921d438690d110e7aa84c60d481eb1760b6f55a3ba8d6a",
"gen_hash_c": "sha256:ecfd21adb83ea534c14bc336324c34b3f89a11eebd960d83298bc2d90ac796da",
"gen_hash_rust": "sha256:d9897ffea08685af7c1f7278356d9c8b9818ef051bdb46a699d6f911fd798776",
"gen_hash_verilog": "sha256:26e15c2e2e2a89bc9fbb19be86dd960c950518c4b1a57385d5ca00c5531ebd31",
"gen_hash_zig": "sha256:cc88c2b3a66f72b4491ffd56e413105f1ad979ef04bf170c5cf202e46a863d6e",
"module": "igla-coder-eval",
"ring": 12,
"sealed_at": "2026-09-08T04:37:29Z",
"sealed_at": "2026-09-08T06:43:46Z",
"sealed_by": "t27c-bootstrap@0.2.0",
"spec_hash": "sha256:665636a59b59cca6f3255f7271f7507e4c49135f2c7c0d08310f3ef1e1ac708b",
"spec_path": "specs/igla/coder/eval.t27"
Expand Down
4 changes: 2 additions & 2 deletions .trinity/seals/testbench_MAC_Testbench.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"gen_hash_c": "sha256:33cf769212351db3c992bd82921dd80b938755b6da543061eaa4e7c39b552add",
"gen_hash_c": "sha256:bdd89dd7974bcb8980a5e3a935ae464b504217de90fe330bed17038588a2e030",
"gen_hash_rust": "sha256:80167949bd4cfe0a422b4a8fe273eb262d7fa1f98d8862a2f2b10ec64d86acf9",
"gen_hash_verilog": "sha256:9cab81dcdc6b62afe3b481d26ee1ea47ab2c776af8358624acdb6a0433f29e09",
"gen_hash_zig": "sha256:8928e5f9b62c3721e845fdc7acef8d518e8ea0c343572ca3e5a38303b5e1cffb",
"module": "MAC_Testbench",
"ring": 12,
"sealed_at": "2026-09-05T04:05:38Z",
"sealed_at": "2026-09-08T06:43:44Z",
"sealed_by": "t27c-bootstrap@0.2.0",
"spec_hash": "sha256:af060b6e5cdb2ffe1de0a47995b2c621139367174cf85237d8217aa929af10f7",
"spec_path": "specs/fpga/testbench/mac_tb.t27"
Expand Down
52 changes: 51 additions & 1 deletion bootstrap/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19365,6 +19365,51 @@ impl CCodegen {
/// Returns None for an empty list and for any element that is not a plain
/// numeric literal -- a call such as `cast_i8(1)` has a return type this
/// does not read, and guessing one would be worse than `__auto_type`.
/// The element type of an array literal whose elements are all CALLS to
/// functions this module declares, when they all return the same thing.
///
/// ~92 of the remaining `__auto_type x = { ... }` errors are lists like
/// `[cast_i8(1), cast_i8(2)]`. The literal inference refuses them because
/// it reads literals and not return types -- and the map it needs,
/// `fn_return_types`, is already built and already consulted a few hundred
/// lines away. A lookup, not an invention: nothing here guesses a type,
/// and a call to a function this module does not declare still refuses.
///
/// All elements must agree. A mixed list has no single element type and
/// `__auto_type` remains the honest answer for it.
fn c_call_list_elem(&self, lit: &Node) -> Option<String> {
if lit.kind != NodeKind::ExprArrayLiteral || lit.children.is_empty() {
return None;
}
let mut found: Option<String> = None;
for e in &lit.children {
if e.kind != NodeKind::ExprCall {
return None;
}
let rt = self.fn_return_types.get(&e.name)?.trim().to_string();
if rt.is_empty() || rt == "void" {
return None;
}
// ONLY a scalar return type. The first version took the return
// type verbatim and emitted `[]Trit structures[2] = { ... }` --
// t27 syntax in a C declarator, and two errors where there had
// been one. An array, a slice, an optional or a pointer needs the
// declarator machinery this branch does not have, and `__auto_type`
// is the better answer until it does.
if rt.starts_with('[') || rt.starts_with('?') || rt.starts_with('*')
|| rt.contains('(') || rt.contains("::")
{
return None;
}
match &found {
None => found = Some(rt),
Some(prev) if *prev == rt => {}
Some(_) => return None,
}
}
found
}

fn c_literal_list_elem(lit: &Node) -> Option<String> {
if lit.kind != NodeKind::ExprArrayLiteral {
return None;
Expand Down Expand Up @@ -20153,7 +20198,10 @@ impl CCodegen {
// `__auto_type x = { 1, 2, 3 }`. Rust and
// Zig infer it; C cannot, so it has to be
// named. See `c_literal_list_elem`.
|| Self::c_literal_list_elem(c).is_some())
|| Self::c_literal_list_elem(c).is_some()
// ... and a list of calls, whose element
// type is a LOOKUP in `fn_return_types`.
|| self.c_call_list_elem(c).is_some())
})
{
// W699 rung 3: `const vals = [_]i32{...}` has no annotation,
Expand All @@ -20166,6 +20214,8 @@ impl CCodegen {
lit.extra_type.clone()
} else if let Some(t) = Self::c_literal_list_elem(lit) {
t
} else if let Some(t) = self.c_call_list_elem(lit) {
t
} else {
// Recovered from the first element; the condition above
// established it is a named struct literal.
Expand Down
2 changes: 1 addition & 1 deletion bootstrap/stage0/FROZEN_HASH
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3f3ef10c5ef12115525bfbfe97cc2ed0c488eb17237634c7df8a7639dc222656 bootstrap/src/compiler.rs
ef36d26b7f0e62f10358dbd6ec06624ae41af0bdfeee560a5c2038df43a8b7dc bootstrap/src/compiler.rs
48 changes: 46 additions & 2 deletions bootstrap/tests/c_literal_list_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ fn cc_present() -> bool {
}

fn gen_c(body: &str, tag: &str) -> (String, std::path::PathBuf) {
gen_c_with("", body, tag)
}

fn gen_c_with(decls: &str, body: &str, tag: &str) -> (String, std::path::PathBuf) {
let d = std::env::temp_dir().join(format!(
"t27c-clit-{tag}-{}-{}",
std::process::id(),
Expand All @@ -31,8 +35,11 @@ fn gen_c(body: &str, tag: &str) -> (String, std::path::PathBuf) {
let _ = std::fs::remove_dir_all(&d);
std::fs::create_dir_all(&d).expect("dir");
let p = d.join("in.t27");
std::fs::write(&p, format!("module P {{\n fn f(v: i32) -> i32 {{ {body} return 0; }}\n}}\n"))
.expect("write");
std::fs::write(
&p,
format!("module P {{\n{decls} fn f(v: i32) -> i32 {{ {body} return 0; }}\n}}\n"),
)
.expect("write");
let out = Command::new(env!("CARGO_BIN_EXE_t27c"))
.arg("gen-c")
.arg(&p)
Expand Down Expand Up @@ -208,3 +215,40 @@ fn an_empty_list_is_left_alone() {
"an empty list keeps __auto_type rather than inventing an element type:\n{h}"
);
}

#[test]
fn a_list_of_calls_to_declared_functions_is_typed() {
// The literal inference refuses calls because it reads literals, not
// return types. `fn_return_types` is already built, so this is a LOOKUP
// rather than a guess: a function this module does not declare is still
// refused, and so is a list whose calls disagree.
let decls = " fn cast_i8(v: i32) -> i8 { return 0; }\n fn other(v: i32) -> u16 { return 0; }\n";
let (h, d) = gen_c_with(decls, "var x = [cast_i8(1), cast_i8(2)];", "calls_ok");
assert!(h.contains("int8_t x[2] ="), "a uniform call list takes the return type:\n{h}");
if cc_present() {
assert!(!errors(&h, &d).contains("error"), "and it compiles");
}
for (body, why) in [
("var x = [cast_i8(1), other(2)];", "disagreeing return types"),
("var x = [nosuch(1)];", "a function this module does not declare"),
("var x = [1, cast_i8(2)];", "a mixed literal-and-call list"),
] {
let (h, _d) = gen_c_with(decls, body, "calls_no");
assert!(
h.contains("__auto_type x"),
"{why} must keep __auto_type:\n{h}"
);
}
}

#[test]
fn a_call_returning_a_composite_is_refused() {
// The first version took the return type VERBATIM and emitted
// `[]Trit structures[2] = { ... }` -- t27 syntax in a C declarator, and
// two errors where there had been one. An array, slice, optional or
// pointer needs declarator machinery this branch does not have.
let decls = " fn mk(v: i32) -> []i32 { return [1]; }\n";
let (h, _d) = gen_c_with(decls, "var x = [mk(1), mk(2)];", "composite");
assert!(h.contains("__auto_type x"), "a composite return must be refused:\n{h}");
assert!(!h.contains("[]i32 x"), "and no t27 spelling may reach C:\n{h}");
}
9 changes: 9 additions & 0 deletions docs/now/2026-09-08-my-estimate-was-off-by-ninety.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# NOW -- My estimate was off by ninety (2026-09-08)

## My estimate was off by ninety (Refs #3459, Closes-adjacent #3464)

- Set out to type lists of calls, estimating **~92** errors from the shape count. The change removed **one**. The reason is the finding, not the fix: `cast_i8` is called in **6 specs and declared in none**, so a lookup-based inference correctly refuses it. The refusal is right; the missing declaration is the defect.
- Counting what that implies, over the generated C with the cap off: **`use of undeclared identifier` 3007**, **`call to undeclared function` 2057** across 91 files, **`unknown type name` 848** -- **5912 in total**, against the **522** remaining in the `__auto_type` class I have followed for three passes. **The undeclared-symbol family is more than ten times larger**, and it went uncounted because I was following one class rather than reading the distribution.
- `cast_i8` is not a user function: `compiler.rs` records it as *«integer cast, `cast_i8(` alone appears 1,100 times»* and, elsewhere, that it is *«never lowered»*. A convention the parser understands and at least one backend does not emit. `len` is the same shape.
- **The change I shipped introduced a defect and the corpus caught it.** Taking the return type verbatim emitted `[]Trit structures[2] = { ... }` -- t27 syntax in a C declarator, two errors where there had been one. Composite return types are now refused. Final: errors **14041 → 14040**, the class 523 → 522, one file better, **none worse**. One error, stated as one.
- What has NOT been measured, and is the next thing: whether the 5912 split into a compiler-known builtin never emitted, a function reached through `use`, or one declared nowhere. Those need different repairs and the counts do not separate them. That separation comes BEFORE any code -- the same first move that turned 1729 `__auto_type` errors into three tractable problems and one impossible one.
Loading