Skip to content

t27o: read-only vec![..] becomes a typed array (step 1 of #10546) - #10648

Merged
gHashTag merged 4 commits into
masterfrom
t27o/vec-literals-10546
Oct 18, 2026
Merged

gHashTag merged 4 commits into
masterfrom
t27o/vec-literals-10546

Conversation

@gHashTag

Copy link
Copy Markdown
Owner

Step 1 of #10546 (lane V of epic #10522). Closes #10643.

Stacked on #10631 (linear lookups) and, under it, #10611: all three edit specs/tools/t27o/rust_convert.t27. Until they land, this diff shows their commits too; the commits of this PR are the last four.

What

A vec![a, b, c] or vec![x; N] that the fn only reads is a typed t27 array:

let v: Vec<u8> = vec![1, 2, 3];      const v : [3]u8 = [1, 2, 3];
let z = vec![0u8; 4];                const z : [4]u8 = [@as(u8, 0)] ** 4;
let rs = vec![rec(1), rec(2)];       const rs : [2]Rec = [rec(1), rec(2)];   // total(&rs): rs is passed as &rs

The array literal is the existing one (array_lit); let_vec adds the type. The type is never guessed, it comes from the source, in this order:

  1. the Vec<T> annotation;
  2. the first element: a suffixed number, a text, a bool, a variant of an enum of the file, a struct literal of a struct of the file, a call of a fn of the file that returns one plain type;
  3. the &[T] parameter of the call that takes &v (site_elem, the code empty_arg used for &[], now shared).

N is one number without a suffix or one const of the file (t27b's ** n takes a literal or a name). let mut v that is never changed is a var.

A vec stays refused, with a reason that says which:

reason when
a vec! the fn changes (push, resize, assign into, &mut) v.push(..), any method that is not a read, v[i] = .., v = .., &mut v
a vec! the fn hands on or returns v passed by value, bound to another name, returned, put in a struct
a vec! whose element type or length t27o cannot tell no annotation, no self-typed first element, no &v argument that names a type; a repeat count that is not a number or a const
macro vec (unchanged) a vec! that is not the init of a let: a struct field, an assignment, an argument, an assert_eq! operand

A later let of the same name ends the scope (its init still counts). array_local knows v = vec![..], so &v is written &v as for any array.

Separate commit: super::, self::, crate::

deps read super::f(..) as a path and never as a use of f, so a test that called a refused fn through super:: reached its stub. Measured on the baseline binary with a four-line file. With vec! converting, four tests of cli/tri/src/orphaned.rs converted that way and tri t27o --check answered BLOCKED (expected type '[][]const u8', a stub). The path now counts as a use of the fn of this file. Cost on the baseline: 10 fns that converted by reaching a stub or a name another file declares are refused (gates.rs 7, service.rs 2, trios channel.rs 1), 1 inside the 16,775-fn set.

Measure

tri t27o over git ls-files '*.rs' of the same five repositories at the same commits (t27 7496ed2, trios 483dd9ee, trinity 0770abb9, trinity-fpga 20bf4c418, 999-multibots-telegraf 6e5512881); before = the stack tip (#10631), after = this branch. Files excluded as in the stack-tip baseline: bootstrap/src/compiler.rs, bootstrap/src/service.rs, cli/t27b/src/lower.rs, cli/tri/src/fpga.rs, cli/tri/src/gates.rs.

first refusal before after
macro vec 1,372 536
a vec! the fn changes 0 82
a vec! the fn hands on or returns 0 21
a vec! whose element type or length t27o cannot tell 0 71
type Vec 1,141 1,130
uses refused (cascade) 3,404 3,977
fns converted of 16,775 seen 1,666 1,665

All files: macro vec 1,430 to 561; converted 1,841 to 1,831 of 19,402.

Of the 1,430 fns whose first refusal was the vec!, 190 are now refused for what the fn does with it (changes 91, unknown type or length 78, hands on 21), 561 stay macro vec, and 679 are past it. None of the 679 converts: 575 stop at uses refused of a callee, and the callee's own first refusal is type BTreeSet (223) plus path BTreeSet::new (53) (the trios guard validators), method to_string (41), method iter (39), type Vec (34); the vec! was hiding that layer. The converted count does not move because the four tests the vec! alone converted were the stub-reaching ones above.

Of the 561 that stay macro vec: 237 struct field labels, 105 assignments, 57 assert_eq! operands, 100 lets whose init holds the vec! inside a call or a struct literal, 47 vec! at the start of a line (arguments, fields), 15 call arguments. These are the callee-owns-a-Vec forms (steps 2 and 3).

No converted output changed except where a vec! was involved, or by the super:: commit: of 1,388 per-file outputs, 1,125 are byte-identical; the other 263 differ in a vec! reason, in what a fn that passed the vec! reaches next, in the first refusal of a typed Vec<T> let, or in a uses refused that the super:: commit added.

The sample

30 random first refusals macro vec of the 1,430, read at the source: 19 a local that is only read (18 handed to a callee as &v, 1 through .as_slice(); 2 of them hold Strings), 3 a struct field initialiser, 2 a field assignment, 2 a local handed on whole, 1 a local pushed to, 3 an argument or assert_eq! operand. 28 of 30 sit in #[test] fns. Over all 1,430: 1,280 in tests, 145 not.

Tests

t27b test 107 of 107 (was 101); t27c test-report vacuous passes 0 of 107. New: one test per form (read by index, iterated with for and .iter(), let mut never changed, &v with a struct, an integer and a repeat), negative controls (pushed, indexed assignment, &mut, moved, rebound, shadowed then pushed, runtime length, expression length, unknown type, an argument), and the super:: pair. tri t27o --check on a file with all the forms: 8 of 8 pass under t27b. Sealed.

🤖 Generated with Claude Code

@gHashTag

Copy link
Copy Markdown
Owner Author

Review (orchestrator, Opus):

@github-actions

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-18 20:59:26 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).

claude and others added 4 commits October 19, 2026 04:16
…hared with the empty slice (Closes #10643)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…e number or one const (Closes #10643)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… fn, so a test that reaches a refused fn that way is refused with it (Closes #10643)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…10643)

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

Copy link
Copy Markdown
Contributor

PR Dashboard

Generated at: 2026-10-18 21:23:05 UTC

Summary

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

These columns do not partition: 2 + 46 + 0 + 0 = 48, 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 e189a60 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.

t27o: read-only vec![..] literals become array literals (step 1 of #10546)

2 participants