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: 28 additions & 0 deletions .trinity/seals/conformance_T27bConformanceLazyConst.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"built_by": "t27c-bootstrap@0.5.2+b258b9007",
"closure": [],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:1e01b01a5774a4f17d641c392abfc898e6b4e392ed5f7e55d737bfb9ac8f6bdf",
"gen_hash_rust": "sha256:b461506b690e7222d3f0d3ef69590ac682864a230fd8581b9a9bae5461941dd9",
"gen_hash_verilog": "sha256:cd59e58a1d7bec8e439c41fd713094e76bd8b50fff81efc5ab3a7950b92f67bf",
"gen_hash_zig": "sha256:6b8043cb91521a566655f3d95e75f93e4a6b73b3eaa2183d433ce63295188ae4",
"module": "T27bConformanceLazyConst",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-19T12:26:38Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:a0754e2b43945728b942b864b40cd89b7f72068cb2372540eaacc30111ee73a4",
"spec_path": "specs/tri/t27b/conformance/lazy_const.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 2,
"total": 2,
"vacuous": 0
},
"toolchain": {
"test_runner": "sha256:8512b80da533b79289110fca4a65f3336abd7a059ca4b72ea595d5e33ff8ad10",
"zig": "0.16.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
"module": "T27bConformanceLazySignature",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-19T11:31:38Z",
"sealed_at": "2026-10-19T15:26:06Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:fc31f992b370b61093b637072e3917bcfc0b39b3c18443aae22ba129b1a4a288",
"spec_hash": "sha256:a0b54d456fb8418dedcdfd83c66e7b3c563f6b8cf55c5a8b591e36294dab6fe1",
"spec_path": "specs/tri/t27b/conformance/lazy_signature.t27",
"tests": {
"failed": 0,
Expand Down
16 changes: 8 additions & 8 deletions .trinity/seals/t27b_T27bAstShape.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@
}
],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:928f3d4e3daebf7d936f277297ae93d434cf27c0de7e401a629f3120db95d1a2",
"gen_hash_rust": "sha256:53db31308fcab46e8ac8ab03e978473e2f0292b639319ff03f5f3db7395e3b98",
"gen_hash_verilog": "sha256:1ba2d510ff7fb2a66b6af29af31cd3019f3790a1b23ab21ee44eb4183df3de99",
"gen_hash_zig": "sha256:4ae04819eacf8c61a60c5ee713cac0dc292581df3476cba6bdd80c480553cdbe",
"gen_hash_c": "sha256:d436ba26211e8f4b0bf0a42634f9036fc96c0327201ec7a875437f1cbf06a541",
"gen_hash_rust": "sha256:24b7e530c344a51633df34fc9f759a9958298143f3c00a8f8bd6959c16dc256c",
"gen_hash_verilog": "sha256:8bae3a3038c28a1cc571f6a754a9da76b5380cc4750c0c6b403368cb72979bf3",
"gen_hash_zig": "sha256:e7eff7053e5019ce8000f03963b1637df929e17f8c8a38e614ba6f90ab5ac907",
"module": "T27bAstShape",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-19T09:47:24Z",
"sealed_at": "2026-10-19T14:55:05Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:0307a528afa66ef858b319d8f523dd02d0a6cdb274e027c89627f58e97716422",
"spec_hash": "sha256:16a9ea7c24f3552cb386c4e0dea10e1d806b641faa94a884c812a7d7ba66dd93",
"spec_path": "specs/tri/t27b/ast_shape.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 14,
"total": 14,
"passed": 15,
"total": 15,
"vacuous": 0
},
"toolchain": {
Expand Down
16 changes: 8 additions & 8 deletions .trinity/seals/t27b_T27bLazySigPlan.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,23 @@
}
],
"config": "gen=c,rust,verilog,zig;tests=zig",
"gen_hash_c": "sha256:ead2c0e6a5434b5712c413c0d7665466dcb0bac06d9f110e01bcc8e8054990d9",
"gen_hash_rust": "sha256:020ab7da823994a4637c017477b01060efcc26ec0fbb1654c47303fac1529ba4",
"gen_hash_verilog": "sha256:f034de34241bcff76c6446e91d52706a79181b2156cebe314b1ffae41819a0e3",
"gen_hash_zig": "sha256:395e2cf2b97a16de07baa83feb06c4edb261ca985199712bf4ffa1afe2ac5e4c",
"gen_hash_c": "sha256:ccd92540be347fc5add77a5d9f9f7ffcf99d04e16576963b100f599ff1f33830",
"gen_hash_rust": "sha256:4e03980cb6ca2928e5d30b3e6860baad60f62838e43e1572e777692e12eb5507",
"gen_hash_verilog": "sha256:8060aed536a6d445489c2d2a0d144e2c38c3ad2cd88b923f1c406c24f6b5b1cf",
"gen_hash_zig": "sha256:5a986dff40ab7950b4a31a9386b81f23d51964bea5c785d06ef2ac98a3ac2aad",
"module": "T27bLazySigPlan",
"ring": 12,
"seal_schema": 2,
"sealed_at": "2026-10-19T10:59:10Z",
"sealed_at": "2026-10-19T14:56:37Z",
"sealed_by": "t27c-bootstrap@0.5.2",
"spec_hash": "sha256:864275b577659678b0208e8a1cddc4153c15daa50e437782b1e6a45d9a53e5fc",
"spec_hash": "sha256:325cfa203e2aff509bc1b8f77b96d8a03a91117580e7313314688fb1a26d8a71",
"spec_path": "specs/tri/t27b/lazy_sig_plan.t27",
"tests": {
"failed": 0,
"failing": [],
"forced": false,
"passed": 16,
"total": 16,
"passed": 19,
"total": 19,
"vacuous": 0
},
"toolchain": {
Expand Down
6 changes: 2 additions & 4 deletions cli/t27b/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -770,12 +770,11 @@ fn lower_mode<'a>(
l.nfuncs = next_id;
let mut const_names: Vec<String> = l.const_nodes.keys().cloned().collect();
const_names.sort();
let hw: HashSet<&str> = marked(items.iter().copied(), vp::hw_consts).map(|n| n.name.as_str()).collect();
for name in const_names {
if l.unreferenced_tuple_const(&items, &name) || hw.contains(name.as_str()) || l.alias_target(&name).is_some() || wp::is_wide(l.const_nodes[&name].extra_type.trim().as_bytes()) {
if l.alias_target(&name).is_some() || wp::is_wide(l.const_nodes[&name].extra_type.trim().as_bytes()) {
continue;
}
let _ = l.global(&name);
l.eager_const(&name);
}
for node in std::mem::take(&mut l.var_nodes) {
if l.module_var(node).is_err() {
Expand Down Expand Up @@ -7339,7 +7338,6 @@ fn flat<'n>(ns: impl IntoIterator<Item = &'n Node>) -> (Vec<u8>, Vec<u8>) {
}
const _: () = assert!(NodeKind::StmtExpr as u8 == aw::K_STMT_EXPR && NodeKind::ExprRange as u8 == aw::K_EXPR_RANGE);
#[path = "../../../gen/rust/tri/t27b/verilog_emit.rs"] #[allow(dead_code, unused_parens, unused_variables, while_true)] mod ve; // t27c gen-rust of specs/tri/t27b/verilog_emit.t27: `t27b verilog` (#8796)
#[path = "../../../gen/rust/tri/t27b/verilog_plan.rs"] #[allow(dead_code, unused_parens, unused_variables, while_true)] mod vp; // t27c gen-rust of specs/tri/t27b/verilog_plan.t27: hw_consts, the consts only the hardware reads
#[path = "../../../gen/rust/tri/t27b/ts_emit.rs"] #[allow(dead_code, unused_parens, unused_variables, while_true)] mod tse; // specs/tri/t27b/ts_emit.t27: `t27b ts` (#9994)
/// `t27b verilog` (`t27b ts` when `ts`): `flat`'s bytes and per node four u32 (flags 1 var, 2 pub; line; its params' span in `p`).
pub fn verilog(ast: &Node, ts: bool) -> Result<String, String> {
Expand Down
15 changes: 0 additions & 15 deletions cli/t27b/src/lower/arraylit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@
//! use is `&x` as such an argument (one E for all) or `x.len`, it takes the
//! same slice-local path, and `&x` passes the slice of it (`arg_as`).
//!
//! An untyped module constant bound to a list is `.{ ... }`, a tuple; one
//! nothing names is never analyzed by the reference, so it is skipped
//! (`unreferenced_tuple_const`), not evaluated.
//!
//! `return [ ... ];` (or `&[_]E{ ... }` for a const slice) in a fn returning a slice, or a slice field's literal, is
//! `@constCast(&[_]E{ ... })` (`slice_lit`, plan `specs/tri/t27b/slice_lit_plan.t27`); one whose
//! elements hold a str is a global written at entry (`entry_static`, #8091).
Expand All @@ -28,17 +24,6 @@
use super::*;

impl<'a> Lower<'a> {
/// An untyped module constant whose value is an array literal and whose
/// name no other node carries: Zig never analyzes it.
pub(super) fn unreferenced_tuple_const(&self, items: &[&Node], name: &str) -> bool {
let Some(node) = self.const_nodes.get(name) else { return false };
let untyped_list = node.extra_type.trim().is_empty()
&& node.children.len() == 1
&& node.children[0].kind == NodeKind::ExprArrayLiteral;
let named: usize = items.iter().map(|n| name_count(std::slice::from_ref(*n), name)).sum();
untyped_list && named == 1
}

/// Called from `begin_body`: every `const xs = &[_]T{ ... }`, and every
/// `const x = [N]T{ ... }` used as `&x`, whose uses all fit becomes a
/// slice local of the callees' element type.
Expand Down
23 changes: 14 additions & 9 deletions cli/t27b/src/lower/unanalyzed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//! `fn f() undefined { undefined; }`; Zig would refuse that type ("expected
//! type 'type', found '@TypeOf(undefined)'") only once something calls `f`.

use super::{Lower, Reject, R};
use super::{Lower, Reject, Val, R};
use crate::compiler::{Node, NodeKind};
use crate::ir::{Expr, ExprKind, Stmt, Ty, TrapKind};
use std::collections::HashSet;
Expand Down Expand Up @@ -66,11 +66,22 @@ impl<'a> Lower<'a> {
/// After every body, the refusals `lazy_body` withdrew come back if AstGen refuses the file anyway (`ls::withdrawn_come_back`).
pub(super) fn restore_held(&mut self, items: &[&Node]) {
let prelude = items.iter().any(|c| matches!(c.kind, NodeKind::TestBlock | NodeKind::InvariantBlock));
if !self.held.is_empty() && super::ls::withdrawn_come_back(items.iter().any(|f| f.kind == NodeKind::FnDecl && self.undeclared_in(f, prelude).is_some()), !prelude, self.eql_used || super::marked(items.iter().copied(), super::sh::string_eq).next().is_some()) {
if !self.held.is_empty() && super::ls::withdrawn_come_back(items.iter().any(|f| matches!(f.kind, NodeKind::FnDecl | NodeKind::ConstDecl) && self.undeclared_in(f, prelude).is_some()), !prelude, self.eql_used || super::marked(items.iter().copied(), super::sh::string_eq).next().is_some()) {
self.errors.append(&mut self.held);
}
}

/// `global(name)` for the eager pass: a constant nothing analyzed reaches is lazy like a body (`analyzed`, `ls::const_plan`).
pub(super) fn eager_const(&mut self, name: &str) {
let (nerr, n): (usize, &Node) = (self.errors.len(), self.const_nodes[name]);
let _ = self.global(name);
let spelled = n.extra_type.trim().is_empty() || self.zig_spelled(n.extra_type.trim());
if !self.analyzed.contains(name) && self.errors[nerr..].iter().all(|e| super::ls::const_plan(e.construct.as_bytes(), e.detail.as_bytes(), spelled) == super::ls::UNRESOLVED) {
let dropped = self.withdraw(nerr); self.held.extend(dropped);
self.globals.retain(|_, v| !matches!(v, Val::Poison)); // recovery mode: a reached use must report a withdrawn failure again
}
}

/// A refused signature type Zig resolves only when the fn is analyzed, as `layout` failures are
/// (specs/tri/t27b/lazy_sig_plan.t27): `anytype` on a parameter, `[*]T` with T a type Zig reads here.
pub(super) fn lazy_sig(&self, t: &str, param: bool) -> bool {
Expand Down Expand Up @@ -101,12 +112,6 @@ impl<'a> Lower<'a> {
/// reaches can make one, but the callee's parameter types are unknown
/// here, so the call is refused rather than lowered.
pub(super) fn unresolved_call<T>(&mut self, c: &Node) -> R<T> {
self.reject(
"ExprCall(unresolved fn)",
format!(
"call to `{}`, a fn no test reaches whose signature names a struct t27b cannot lay out",
c.name
),
)
self.reject("ExprCall(unresolved fn)", format!("call to `{}`, a fn no test reaches whose signature names a struct t27b cannot lay out", c.name))
}
}
11 changes: 11 additions & 0 deletions cli/t27b/tests/tail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,10 +388,21 @@ fn a_signature_zig_never_resolves() {
assert!(rejected(&src.replace("all: [*]const Issue", "all: [*]const Issue, m: Missing")).contains("type [*]T"));
assert!(rejected(&src.replace("== 34);", "== 34);\n lazy_unit_new();")).contains("unknown name `LazyUnit`"));
assert!(common::lower_src(&src.replace("return lazy_unit_new();", "return lazy_unit_nowhere();")).unwrap_err().join("\n").contains("ExprCall(undeclared fn)"));
assert!(rejected(&src.replace("fn issue_score(", "fn lazy_local() -> u32 {\n var x : LazyMissing = 0;\n return 1;\n}\n\nfn issue_score(")).contains("type (undeclared)")); // #11053: t27c BLOCKED
let m = common::lower_src(&src.replace("f.write_num", "undeclared_thing")).unwrap_err().join("\n");
assert!(m.contains("ExprIdentifier(undeclared) at line 23 (`undeclared_thing` in `format_into`"), "{}", m);
}

/// #10899, #10903: a constant no analyzed code names is never resolved (conformance/lazy_const.t27; `t27c test-report` 2/2); a test naming the slice (directly or through a fn) or the call-initialised struct, and a constant naming a type, fn or value declared nowhere, keep the refusal.
#[test]
fn a_constant_zig_never_resolves() {
let src = include_str!("../../../specs/tri/t27b/conformance/lazy_const.t27");
assert_eq!(names_ok(&run(src)).len(), 2);
for (from, to, want) in [("== 0x1100", "== 0x1100); assert(LAZY_ALLOWED.len == 2", "ConstDecl(slice) at"), ("== 0x1100", "== 0x1100); assert(lazy_allowed_count() == 2", "ConstDecl(slice) at"), ("== 0x1100", "== 0x1100); assert(lazy_bram_end() == 0x100000", "ConstDecl at"), ("[][]const u8", "[]LazyMissing", "type (undeclared)"), ("lazy_region_new(0, 0x100000)", "lazy_region_nowhere(0, 0x100000)", "ExprCall(undeclared fn)"), ("= LAZY_CSR;", "= LAZY_NOWHERE;", "ExprIdentifier(undeclared)")] {
assert!(common::lower_src(&src.replace(from, to)).unwrap_err().join("\n").contains(want), "{}", to);
}
}

// ------------------------------------------------ f32 @log, @log2 and @log10

/// #7822: of an f32 they call libm.t27's ports of compiler_rt `logf`, `log2f` and `log10f`, folded or not
Expand Down
4 changes: 2 additions & 2 deletions docs/reports/t27b_expectations.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"reference-bug": "the reference passes it for the wrong reason; t27b is right not to",
"n/a": "outside what t27b is for (say why in the PR that sets it)"
},
"max_not_pass": 128,
"max_not_pass": 127,
"entries": [
{"path": "specs/a/b_c.t27", "t27b": "pass"},
{"path": "specs/a_b/c.t27", "t27b": "pass"},
Expand Down Expand Up @@ -536,7 +536,7 @@
{"path": "specs/jobs/suite_ledger_steward.t27", "t27b": "pass"},
{"path": "specs/jobs/t27b_ledger_steward.t27", "t27b": "pass"},
{"path": "specs/lsp/protocol.t27", "t27b": "pass"},
{"path": "specs/lsp/schema.t27", "t27b": "blocked", "blocker": "type mismatch", "reason": "unimplemented"},
{"path": "specs/lsp/schema.t27", "t27b": "pass"},
{"path": "specs/math/constants.t27", "t27b": "pass"},
{"path": "specs/math/gf_competitive.t27", "t27b": "pass"},
{"path": "specs/math/property_test_template.t27", "t27b": "pass"},
Expand Down
Loading
Loading