diff --git a/.trinity/seals/TriKdTree.json b/.trinity/seals/TriKdTree.json index f237e32831..a2c85f8594 100644 --- a/.trinity/seals/TriKdTree.json +++ b/.trinity/seals/TriKdTree.json @@ -1,6 +1,6 @@ { "gen_hash_c": "sha256:7658bd16d1d66d14de50176a27cc78f130863a13853fedc2dacc839a2fe4a68f", - "gen_hash_rust": "sha256:ec452f608b4f52459b4c87a32fcc38622f3b833ff8f0591af58949c5a8530bb9", + "gen_hash_rust": "sha256:5109675652b7451a917c1f6f145b99bef55491f2ac4bbc4d9025d55ca37c5fc6", "gen_hash_verilog": "sha256:c1f0afec0673c3db6f521e9b37b4add257f355a964bb55b153707616595c93e3", "gen_hash_zig": "sha256:369f3d5632ef02f40c2edea5a3ab0670cce287040188cf7d66ae11fed6ed3dda", "module": "TriKdTree", diff --git a/.trinity/seals/TriLinkedList.json b/.trinity/seals/TriLinkedList.json index e02bc22525..9c43a0f4fc 100644 --- a/.trinity/seals/TriLinkedList.json +++ b/.trinity/seals/TriLinkedList.json @@ -1,6 +1,6 @@ { "gen_hash_c": "sha256:24973c2e300a0a88db9ca2039d8bfb7ed18cc408ccf22acbcc435ac2e473f365", - "gen_hash_rust": "sha256:a84e33b1e860fca96f97c3c133c599840bc2ec83bd918a53baf33724cdda2262", + "gen_hash_rust": "sha256:428047f5cf573a30fb54b11ae32987750b200b9ba01ad7dec87c8a911c03b45f", "gen_hash_verilog": "sha256:6c52068e721a7503b2bd566c20bf4435c36545b991f689fb4b5e38227b42f7e7", "gen_hash_zig": "sha256:32622c710581aca2415f300aed3c02dad83c1c53136677df3cdcdca5f8df44d3", "module": "TriLinkedList", diff --git a/.trinity/seals/TriOctree.json b/.trinity/seals/TriOctree.json index e1216b2927..5ae0b8f15f 100644 --- a/.trinity/seals/TriOctree.json +++ b/.trinity/seals/TriOctree.json @@ -1,6 +1,6 @@ { "gen_hash_c": "sha256:0bedc286e426f126d811665fd97147dc6ebfba4f96958a522fb9d779d982cfa0", - "gen_hash_rust": "sha256:5884219ea586303bea5c3910b36b8377dd9ac120ec27be8e6fbb1f83fd032062", + "gen_hash_rust": "sha256:524d49b87aed3207a3f394fbfa97699f5b082c401686c473b1394842a456cbe3", "gen_hash_verilog": "sha256:bfdd79ebab78682b40028db81ce198b51da58b7c5cb959580165fc9fa01f276d", "gen_hash_zig": "sha256:01938d9fbbfc4d9f5e19ad941071b5a303b8c7b87e336157ce928c26c34d18eb", "module": "TriOctree", diff --git a/.trinity/seals/TriQuadtree.json b/.trinity/seals/TriQuadtree.json index 82b7154dc3..89250148e5 100644 --- a/.trinity/seals/TriQuadtree.json +++ b/.trinity/seals/TriQuadtree.json @@ -1,6 +1,6 @@ { "gen_hash_c": "sha256:3f1b5f372579e92827fa9a413eb3136abc5272daee917df4dcfd9b2fae31ae82", - "gen_hash_rust": "sha256:251c098726ade16a892350dc069771ef00100f35b339cdef789618a29cf81b02", + "gen_hash_rust": "sha256:42d4017e6b586dc73cbc6cca85351bf20f06c83500f5a5823ee4a3e5f626b9b3", "gen_hash_verilog": "sha256:d13d947ba9e73a5be25d64aa717c5d3f1138396f77674ffdc56a0dfef150fe77", "gen_hash_zig": "sha256:01514daa510c982d521d72b36552a8ef68f946957d0351799bfad2073128ea4d", "module": "TriQuadtree", diff --git a/.trinity/seals/collections_TriLinkedList.json b/.trinity/seals/collections_TriLinkedList.json index e62842e67a..965c32b2d0 100644 --- a/.trinity/seals/collections_TriLinkedList.json +++ b/.trinity/seals/collections_TriLinkedList.json @@ -1,11 +1,11 @@ { "gen_hash_c": "sha256:24973c2e300a0a88db9ca2039d8bfb7ed18cc408ccf22acbcc435ac2e473f365", - "gen_hash_rust": "sha256:a84e33b1e860fca96f97c3c133c599840bc2ec83bd918a53baf33724cdda2262", + "gen_hash_rust": "sha256:428047f5cf573a30fb54b11ae32987750b200b9ba01ad7dec87c8a911c03b45f", "gen_hash_verilog": "sha256:6c52068e721a7503b2bd566c20bf4435c36545b991f689fb4b5e38227b42f7e7", "gen_hash_zig": "sha256:32622c710581aca2415f300aed3c02dad83c1c53136677df3cdcdca5f8df44d3", "module": "TriLinkedList", "ring": 12, - "sealed_at": "2026-09-05T01:08:39Z", + "sealed_at": "2026-09-06T08:02:09Z", "sealed_by": "t27c-bootstrap@0.2.0", "spec_hash": "sha256:5171edf6089a238976e6fad2ba577ed72cff191cf634ee94c28645f3551f9ffc", "spec_path": "specs/tri/collections/linked_list.t27" diff --git a/.trinity/seals/trees_TriKdTree.json b/.trinity/seals/trees_TriKdTree.json index 8c6efb3321..21b6adb107 100644 --- a/.trinity/seals/trees_TriKdTree.json +++ b/.trinity/seals/trees_TriKdTree.json @@ -1,11 +1,11 @@ { "gen_hash_c": "sha256:7658bd16d1d66d14de50176a27cc78f130863a13853fedc2dacc839a2fe4a68f", - "gen_hash_rust": "sha256:ec452f608b4f52459b4c87a32fcc38622f3b833ff8f0591af58949c5a8530bb9", + "gen_hash_rust": "sha256:5109675652b7451a917c1f6f145b99bef55491f2ac4bbc4d9025d55ca37c5fc6", "gen_hash_verilog": "sha256:c1f0afec0673c3db6f521e9b37b4add257f355a964bb55b153707616595c93e3", "gen_hash_zig": "sha256:369f3d5632ef02f40c2edea5a3ab0670cce287040188cf7d66ae11fed6ed3dda", "module": "TriKdTree", "ring": 12, - "sealed_at": "2026-09-05T01:08:39Z", + "sealed_at": "2026-09-06T08:02:09Z", "sealed_by": "t27c-bootstrap@0.2.0", "spec_hash": "sha256:338dda6bd5fe68db61f018bc4216fd6ab671562bcfc3cf92f1692fbdc2440abd", "spec_path": "specs/tri/trees/kd_tree.t27" diff --git a/.trinity/seals/trees_TriOctree.json b/.trinity/seals/trees_TriOctree.json index 0e3a6c913e..d037933558 100644 --- a/.trinity/seals/trees_TriOctree.json +++ b/.trinity/seals/trees_TriOctree.json @@ -1,11 +1,11 @@ { "gen_hash_c": "sha256:0bedc286e426f126d811665fd97147dc6ebfba4f96958a522fb9d779d982cfa0", - "gen_hash_rust": "sha256:5884219ea586303bea5c3910b36b8377dd9ac120ec27be8e6fbb1f83fd032062", + "gen_hash_rust": "sha256:524d49b87aed3207a3f394fbfa97699f5b082c401686c473b1394842a456cbe3", "gen_hash_verilog": "sha256:bfdd79ebab78682b40028db81ce198b51da58b7c5cb959580165fc9fa01f276d", "gen_hash_zig": "sha256:01938d9fbbfc4d9f5e19ad941071b5a303b8c7b87e336157ce928c26c34d18eb", "module": "TriOctree", "ring": 12, - "sealed_at": "2026-09-06T04:36:45Z", + "sealed_at": "2026-09-06T08:02:09Z", "sealed_by": "t27c-bootstrap@0.2.0", "spec_hash": "sha256:63216e4dbe843da95dd62bfc13b7741e6bf343e3bcf3d407e084d6be61e84dfe", "spec_path": "specs/tri/trees/octree.t27" diff --git a/.trinity/seals/trees_TriQuadtree.json b/.trinity/seals/trees_TriQuadtree.json index f184fa943d..217d1b1eb2 100644 --- a/.trinity/seals/trees_TriQuadtree.json +++ b/.trinity/seals/trees_TriQuadtree.json @@ -1,11 +1,11 @@ { "gen_hash_c": "sha256:3f1b5f372579e92827fa9a413eb3136abc5272daee917df4dcfd9b2fae31ae82", - "gen_hash_rust": "sha256:251c098726ade16a892350dc069771ef00100f35b339cdef789618a29cf81b02", + "gen_hash_rust": "sha256:42d4017e6b586dc73cbc6cca85351bf20f06c83500f5a5823ee4a3e5f626b9b3", "gen_hash_verilog": "sha256:d13d947ba9e73a5be25d64aa717c5d3f1138396f77674ffdc56a0dfef150fe77", "gen_hash_zig": "sha256:01514daa510c982d521d72b36552a8ef68f946957d0351799bfad2073128ea4d", "module": "TriQuadtree", "ring": 12, - "sealed_at": "2026-09-06T05:46:34Z", + "sealed_at": "2026-09-06T08:02:09Z", "sealed_by": "t27c-bootstrap@0.2.0", "spec_hash": "sha256:974e62d1cdcc28189ff5fddbf9405c9e02f8bb01325bc2f9860f0578a053b345", "spec_path": "specs/tri/trees/quadtree.t27" diff --git a/bootstrap/src/compiler.rs b/bootstrap/src/compiler.rs index 40af386757..643582a9e1 100644 --- a/bootstrap/src/compiler.rs +++ b/bootstrap/src/compiler.rs @@ -23881,6 +23881,47 @@ impl RustCodegen { } } + /// A field whose type names the struct being defined needs indirection in Rust. + /// + /// `pub const KDNode = struct { left : "?KDNode", ... }` maps to + /// `pub left: Option` inside `pub struct KDNode`, and rustc answers + /// `recursive type `KDNode` has infinite size ... insert some indirection (e.g. a + /// `Box`, `Rc`, or `&`)`. There is no version of this that compiles without one, so + /// this is not a choice about representation -- it is the difference between output + /// and no output. `Box` is the ownership-preserving one of the three rustc names. + /// + /// Nine structs in the corpus refer to themselves; three of them are specs whose ONLY + /// remaining error is this one. + /// + /// Deliberately narrow. `Vec` already carries its indirection and is left alone, + /// and so is anything more deeply nested than `Option` -- a type this does not + /// recognise keeps its current output rather than getting a guess. + fn box_if_self_referential(field_type: &str, struct_name: &str) -> String { + if struct_name.is_empty() { + return field_type.to_string(); + } + if field_type == struct_name { + return format!("Box<{struct_name}>"); + } + let opt = format!("Option<{struct_name}>"); + if field_type == opt { + return format!("Option>"); + } + // `[Option; 8]`. An array is inline storage, so it is as recursive as a + // bare field; only the element needs the box. This was previously written off as + // "genuinely infinitely sized" -- it is not, `[Option>; 8]` is finite + // and is what octree and quadtree need. + if let Some(rest) = field_type.strip_prefix('[') { + if let Some((elem, tail)) = rest.rsplit_once(';') { + let boxed = Self::box_if_self_referential(elem.trim(), struct_name); + if boxed != elem.trim() { + return format!("[{boxed};{tail}"); + } + } + } + field_type.to_string() + } + fn gen_struct(&mut self, node: &Node) { // The serde derives were unconditional, and the corpus compiles this // output as a standalone `--crate-type lib` with no `--extern`. Every @@ -23952,6 +23993,7 @@ 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); + let field_type = Self::box_if_self_referential(&field_type, &node.name); if field_type.trim() == "bool" { self.bool_fields.insert(field_name.clone()); } diff --git a/bootstrap/stage0/FROZEN_HASH b/bootstrap/stage0/FROZEN_HASH index 0543a1f840..237bf8b371 100644 --- a/bootstrap/stage0/FROZEN_HASH +++ b/bootstrap/stage0/FROZEN_HASH @@ -1 +1 @@ -5b05ef6357a7139dbc16bd60977eda9294eecb01f9d2d3be58c8816796e418cc bootstrap/src/compiler.rs +6b3304d63e8f39cbb57953dbaf39769550a677d5565923a387bc4d6c94348f64 bootstrap/src/compiler.rs diff --git a/docs/now/2026-09-06-a-field-that-names-its-own-struct.md b/docs/now/2026-09-06-a-field-that-names-its-own-struct.md new file mode 100644 index 0000000000..c600fc3f49 --- /dev/null +++ b/docs/now/2026-09-06-a-field-that-names-its-own-struct.md @@ -0,0 +1,20 @@ +# NOW -- A field that names its own struct needs a Box (2026-09-06) + +## A field that names its own struct needs a Box (Refs #3377) + +- First fix in five passes to move the column, and the first whose target was PICKED: + `tri one-away` reported this class as the sole error of 3 specs whose count is exact, + and the repair moved exactly those 3. +- `pub left: Option` inside `pub struct KDNode` is infinitely sized. There is + no version that compiles without indirection, so nothing is chosen about representation + -- `Box` is the ownership-preserving one of the three names rustc itself offers. +- Two shapes. `Option` is kd_tree. `[Option; N]` is octree and quadtree, + and an earlier pass of mine wrote octree off as "genuinely infinitely sized". **That was + wrong**: an array is inline storage, only the element needs the box, and + `[Option>; 8]` is finite. +- Measured, two pinned binaries from the same commit in ONE pass, 650 specs: + **357 -> 360, +3, zero regressions.** +- Nine structs in the corpus name themselves. Three were one-away and are now green; the + rest carry other errors. +- Narrow on purpose: `Vec` already carries indirection and is untouched, and a + shape this does not recognise keeps its current output rather than getting a guess.