Skip to content

t27o: integer ! is a bitwise ~, the oracle spec uses type_text, the harness drops no_std (Closes #10534) - #10611

Merged
gHashTag merged 5 commits into
masterfrom
t27o/check-defects-10534
Oct 18, 2026
Merged

gHashTag merged 5 commits into
masterfrom
t27o/check-defects-10534

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Closes #10534

Stacked on #10593 (branch t27o/refusal-classes-10526, on auto-merge): this branch is cut from it and edits the same spec, so it merges after it. Lane F of epic #10522. Boundary kept: only specs/tools/t27o/rust_convert.t27, its gen file and its seal; no hand-written code anywhere.

What changed

1. Integer ! is a bitwise ~ (unary). expr_class reads the operand's class from the source: a declared bool/integer type (type_class now returns C_BOOL for bool), a fn's return type (ret_class: all fns of that name must agree; a fn with no -> does not count, ! cannot be applied to ()), a comparison / && / ||, a suffixed literal, a bool-valued std method (std_bool), matches!, a tuple field x.0 and a field of a let-owned local (head_struct), and name_class learns a let whose init is a comparison. Integer -> ~, bool -> today's text (!x, (x == false) for a parenthesized operand), anything else -> refused with `!` of an operand whose type t27o cannot tell `<operand>`. Never a guess.

  • Zig/codegen(zig): unary minus drops the parentheses of its operand: -(a + b) runs as -a + b #6549: the shared t27c (built 2026-10-18; codegen(zig): unary minus drops the parentheses of its operand: -(a + b) runs as -a + b #6549 closed 2026-10-11) keeps the parentheses of ~(x) and !(x) on its Zig, C, Verilog and Rust backends (probed with 17 shapes), so ~(x) is emitted as is. bitwise_not_keeps_the_parentheses_of_its_operand runs it under t27b test and t27c test-report (4 runtime asserts through two small fns; a first cut on constants was folded by t27c and reported vacuous passes 1 of 90). Unsuffixed literals (x & !0) are refused: ~0 is unsupported construct ExprUnary(~) on t27b and BLOCKED ... cannot represent -1 on t27c.
  • Tests: an_integer_not_is_a_bitwise_not_and_a_bool_not_stays_a_boolean_one (bitmask.rs insert / clear_bit give ~m and ~(@as(u32, 1) << bit); a u8 and a bool named alike in one file each keep their own), negative_control_a_bang_on_an_operand_t27o_cannot_class_is_refused_and_says_so (x & !0, a call of another file's fn, a for binding), the tuple/let-owned/method test and its negative control (a method two types share with two return classes, a field of a local built by an unseen call).
  • Mutation checks (rule removed -> the test fails): integer branch writes ! again -> the first test fails; unknown falls to bool -> the negative control fails; unit fns counted in ret_class, tuple fields dropped, ret_class disagreement ignored -> each its own test fails.

2. use tri::t27b::type_text; (ret_has_str / new struct_text). The appended oracle test of FieldDesc::new -> Self compares the struct's name: &'static str with type_text::same, but only a return type spelled str set the use line. A return type that names a struct of this file (or Self) with a text field now counts. Tests: a_struct_result_with_a_text_field_makes_the_spec_use_type_text; negative control ..._without_a_text_field_adds_no_use (a number field, and a text field no fn returns). Removing the struct_text clause fails the first; counting a u8 field as text fails the second and tuple_structs_have_fields_0_and_1.

3. The harness drops #![no_std] / #![no_main] (put_item_source, host_attr), bare or applied by a cfg_attr (the predicate is not read: cfg_attr(not(no_std), ..) stays). It also drops crate-level deny / forbid: with std back, ring-090's #![deny(missing_docs)] failed 30 more times on docs of items the harness leaves out, so the issue's own acceptance command needed it. Tests: the_oracle_harness_drops_a_crate_level_no_std_no_main_deny_and_forbid; negative control ..._an_attribute_that_only_names_a_dropped_word_stays_in_the_harness (no_std as a predicate, in a string, warn, allow). Rule removed -> first test fails; predicate scanned too -> negative control fails; deny not listed -> first test fails.

Verified

  • t27b test specs/tools/t27o/rust_convert.t27: 90 passed, 0 failed (was 81 on the base).
  • t27c test-report: 90 of 90, vacuous passes 0 of 90.
  • t27c seal ... --save, then --verify: all hashes MATCH. gen/rust/tools/t27o/rust_convert.rs is t27c gen-rust of the spec; tri built from this tree.
  • tri t27o bootstrap/src/host/bitmask.rs --check --name chk_bitmask: 20 of 20 (was BLOCKED on type_text), vacuous passes 0 of 20; with a hand vector appended, clear_bit(0xFF, 0) == 0xFE and insert(0xFF, 3, 0, 0) == 0xF0 hold under t27b and t27c. grep -c '== false' on the converted file is 0; ~ is on 2 lines (~m matches one of them).
  • tri t27o rings/ring-090-rust/src/lib.rs --oracle | rustc --edition 2021 compiles (was 415 errors); its --check passes 25 of 25.

Measured on this repository

377 .rs files (tracked, not under gen/, 300000 bytes or less; 5 larger skipped), each run through the new tri, the stacked base's tri (this branch minus this PR) and the shared master tri, 30 s cap each, no timeouts.

  • New vs base: 12 files change. Integer ! became ~ in 3 places in 2 files (bitmask.rs twice, capflags.rs required._0 & !self._0); all are u32. 643 fns convert, base 644: the one loss is ring-097 new_proof_trace_creates_empty (assert!(!t.verified) on a local built by a free fn the head resolver does not follow). 17 more fns now report the ! reason first but were already refused for another reason (the report lines are unchanged).
  • New vs shared master (633 converted): 135 files differ, almost all from t27o: five refusal classes from the roadmap dogfood convert (Closes #10526) #10593's rules. In the diff lines that involve ! / ~ and are code, the only changes are the three ~ above and one newly converted bool assert(!(r.reading.len == 0)) (census.rs, same meaning as the Rust). No converted fn changed meaning otherwise.

Still refused, and why

A ! whose operand is an unsuffixed literal, a call of a fn this file does not show (read_is_complete(30, 30), lab::ssh_should_retry(..)), an index (f[1], ms[1].empty_fns), a field of a local built by a call (stats.has_pending, result.passed, v.ok), or a method two types share with different return classes: t27o cannot tell bool from integer there, and a wrong guess is a different function.

Not touched: cli/tri/src/main.rs, spice_convert.t27, ledger.t27.

🤖 Generated with Claude Code

@gHashTag

Copy link
Copy Markdown
Owner Author

Review (orchestrator, Opus):

This was referenced Oct 18, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-18 19:57:39 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 44
PRs with All Checks Green 6
READY 1
FAILING 44
PENDING 0
NO CHECKS YET 0

These columns do not partition: 1 + 44 + 0 + 0 = 45, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=fad12492937a != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

claude and others added 5 commits October 19, 2026 03:16
…27o cannot class is refused (Closes #10534)

unary wrote every `!` as a boolean NOT, so bootstrap/src/host/bitmask.rs:15 and :27,
`value & !m` and `value & !(1u32 << bit)`, became `value & !m` and
`value & ((@as(u32, 1) << bit) == false)` -- a different function. The operand's class
now decides: expr_class reads it from the source (a declared bool or integer type, a fn's
return type, a comparison, a suffixed literal, a bool-valued std method), an integer gets
`~`, a bool keeps today's text, and anything else is refused with a reason naming `!` and
the unknown type. type_class gains `bool` (C_BOOL) and name_class reads a `let` whose init
is a comparison. `~(x)` keeps its parentheses on the Zig, C, Verilog and Rust backends of
the shared t27c; a test runs it under t27b and t27c.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… type_text (Closes #10534)

The oracle test of bootstrap/src/host/bitmask.rs `FieldDesc::new -> Self` compares the
struct's `name: &'static str` with type_text::same, but only a return type spelled `str`
set the spec's use line, so tri t27o --check said `type_text` was undeclared (t27b: call
to type_text::same undeclared; t27c Zig: use of undeclared identifier). struct_text reads
the struct the return type names (Self is the impl's type) and ret_has_str counts a text
field as a text. `tri t27o bootstrap/src/host/bitmask.rs --check` now passes 20 of 20.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d forbid (Closes #10534)

rings/ring-090-rust/src/lib.rs opens with `#![cfg_attr(not(test), no_std)]`; the harness
copied it and plain rustc (no --test) built the harness without std: 415 errors, format!,
println!, Vec and String not found. put_item_source now leaves out a crate-level no_std or
no_main, bare or carried by a cfg_attr (only what the cfg_attr applies, not its predicate),
and also deny and forbid: with std back the lib's `deny(missing_docs)` failed 30 more times
on the docs of items the harness leaves out. `tri t27o rings/ring-090-rust/src/lib.rs
--oracle` now compiles with rustc and `--check` passes 25 of 25.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… or a method a unit test shares a name with (Closes #10534)

Measured on this repository, the first cut of the integer-! rule refused 4 fns it could
class: capflags.rs `!self.0` (a newtype over u32) twice, and calls of a method that a
`fn name() {}` test repeats. ret_class now ignores a fn with no return type (`!` cannot be
applied to `()`), chain_class reads `x.0` through the tuple struct's field type, and
head_struct finds the struct of `x` by its declared type or by `let x = Type::new(..)`.
A method two types share with different return classes, and a field of a local built by
a call this file does not show, stay refused (negative controls).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closes #10534)

t27c test-report folded the asserts of the first cut (constants) at compile time and
reported "vacuous passes 1 of 90". The pin now calls two small fns: 4 runtime asserts,
vacuous passes 0 of 90, t27b 90 of 90.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-18 20:32:17 UTC

Summary

Status Count
Total Open PRs 50
PRs with Failing Checks 45
PRs with All Checks Green 5
READY 2
FAILING 45
PENDING 0
NO CHECKS YET 0

These columns do not partition: 2 + 45 + 0 + 0 = 47, and there are 50 open PRs. A PR is being counted twice or not at all.

Seal Status

  • ⚠️ STALE -- sha256(compiler.rs)=fad12492937a != manifest seal=87e5cbd3ad94.
    The committed NMSE numbers were certified against an older compiler.rs.
    Run scripts/reseal-check.sh locally for the two-step reseal command (advisory; not a merge gate).

@gHashTag
gHashTag merged commit a800f47 into master Oct 18, 2026
33 of 34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] t27o: integer ! miscompiled as boolean not; oracle tests miss the type_text use; the oracle harness keeps #![no_std]

2 participants