You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
t27o: Vec parameters -- measure them, then convert a read-only &Vec<T> to a slice and a push-only &mut Vec<T> to the out-buffer form #11135
Measure how many of the type Vec first refusals are a Vec<T>, &Vec<T> or &mut Vec<T> PARAMETER (not a return and not a local), then convert the read-only forms: a &Vec<T> or &[T]-like parameter that the fn only reads becomes a slice parameter, and a &mut Vec<T> that the fn only pushes to or overwrites becomes the out-buffer form already used for a returned Vec.
Why
After the root attribution of #11127, type is the largest root reason of the converter's first refusals and Vec is its largest token (1,289 of 16,057 on the sweep of 2026-10-19). The Vec work so far covered a returned Vec built by push (#11109): it converted 4 fns, because only 91 of 626 fns returning a bare Vec build it by push alone. A parameter needs no heap at all (a slice is what t27 already has), so it is the form most likely to move the converted share, and nobody has counted it yet. Issue #10546 step 3 (a Vec used as a scratch list) is separate.
Boundary
specs/tools/t27o/rust_convert.t27
gen/rust/tools/t27o/rust_convert.rs
.trinity/seals/t27o_T27oRust.json
User Scenarios
Givenfn sum(v: &Vec<u32>) -> u32 that only reads v, when t27o converts it, then the parameter is a slice and the fn converts with its oracle.
Givenfn fill(out: &mut Vec<u8>) that only pushes, when t27o converts it, then it converts in the out-buffer form, or is refused with a reason that names the form.
Given a Vec parameter that the fn resizes, removes from or returns, when t27o converts it, then it stays refused with a reason that names the use.
Requirements
FR-001: The pull request MUST first report the split of the type Vec first refusals into parameter, return and local, with the sweep driver and the commits named.
FR-002: A read-only Vec parameter MUST convert to a slice parameter without changing the fn's meaning (oracle vectors agree on the files --check can run).
FR-003: The rule MUST live in rust_convert.t27 with a failing test first and a negative control; hand Rust MUST NOT grow (own-language net <= 0); no converted fn may become refused and no file may go from pass to not-pass.
Success Criteria
The type Vec first refusals over the 1,388 tracked Rust files fall by at least 10% (from 1,289) and the converted fns rise by at least 20 fns, measured with the same sweep driver before and after.
t27b test specs/tools/t27o/rust_convert.t27 ends with exit 0 and 0 tests failing, and t27c test-report reports 0 vacuous passes.
Step 1 measured (lane A5): the Vec PARAMETER form cannot reach this issue's success criteria, so no rule PR is opened. Numbers first, then what they mean.
Result of the sweep: 19,392 fn seen, 1,824 converted, 16,057 first refusals, 1,289 of them type Vec -- the same numbers as in this issue, so this is the same base.
Classification: a scratch Python reader over the sweep outputs and the sources (not committed). The refusal line gives the fn line and the token line; the token is placed in the signature's parameter list, the return type, or the body. A &mut Vec parameter's body is classified by what it does with the name (regex over the body with strings and comments blanked, so "handed on" means the name appears as a call argument; approximate).
1. Where the refused Vec is (1,289 first refusals)
the refused Vec is in
fns
share
a parameter
87
6.7 %
the return type
674
52.3 %
a local (let x: Vec<T> ..)
528
41.0 %
Parameters (87): &mut Vec<T> 71; &[Vec<T>] 11 and &mut [Vec<T>] 2 (a slice of lists: t27 has no slice of slices); a Vec nested in a Vec / &Vec parameter 3; mut v: Vec<T> by value 0; &Vec<T> or Vec<T> by value 0 (they are slices already, see 3).
Return (674): -> Vec<T> 606 (element: struct or enum 254, text 119, integer 103, tuple 50, float 47, bool 3, other 30), Result<Vec<T>, E> 50, Option<Vec<T>> 15, other 3.
Local (528): let x: Vec<T> = ..collect() 496 (435 with a closure in the chain, 451 inside test fns); an empty start (Vec::new(), with_capacity, vec![]) 27 (19 outside tests); clone / to_vec / into 3; other 2.
2. The 71 &mut Vec<T> parameters: use of the parameter x element type
what the body does with the parameter
scalar element (integer, float, bool)
other element
total
only push / extend / extend_from_slice
4
18
22
push, and the Vec is handed on to a call
0
20
20
push, plus reads or element writes
0
4
4
resized, removed from, or replaced
0
6
6
element writes and reads only (a &mut [T] would do)
0
4
4
only handed on to a call
0
14
14
read only (and handed on)
0
1
1
total
4
67
71
Element types of the 71: Stmt 39, Node 14 (9, and 5 as &Node), other structs 5, String 5, tuples 3, a nested Vec 1, u32 2, u8 2, no float, no bool. 50 of the 71 sit in lower.rs (33) and compiler.rs (17); their element is a data-carrying enum that the converter refuses on its own. None of the 71 returns the parameter.
3. The read-only form already exists, and moves nothing
param_slice (#8999) turns a read-only Vec<T> or &Vec<T> parameter into []const T; run on the merge base:
Over all five repositories 221 fns (247 parameters) have a Vec in a parameter. 209 of those parameters are seen by the converter (38 sit in cfg-off variants it drops), and 0 of the 221 fns convert. The 74 read-only parameters (Vec<T> by value 71, &Vec<T> 3) are first refused elsewhere: type 22 (usually the return or a second Vec), uses refused 18 (a struct with a Vec field), method 16, tuple 8, undeclared 5, other 5. So a slice parameter is not the missing piece.
The other 83 first refusals of a parameter have an element the converter refuses by itself (data-carrying enums, String, tuples, nested lists), or are a slice of lists.
5. Against the success criteria
Fall of at least 10 % in type Vec (at least 129 fns): the whole parameter class is 87 (6.7 %), so even a perfect conversion of every one cannot reach it.
Converted fns up by at least 20: the census above has 0 converted today and 1 reachable.
What would move the number instead (observation, not a plan)
If wanted, the only cheap change on the parameter side is the wording: a &mut Vec<T> parameter is refused as "type Vec" and could say so ("a &mut Vec parameter"). No fn would convert; I did not make it.
Not run: tri t27o-sweep itself (no cargo build -p tri: low disk); replay of oracle harnesses (nothing was converted); the classification of "handed on" calls into what the callee does with the Vec.
Closing as not planned, on the measurement in the comment above (lane A5): Vec parameters are 87 of the 1,289 type Vec first refusals (6.7%; returns 674, locals 528). A read-only &Vec<T>/Vec<T> parameter already converts to a slice on master (#8999) and none of the 221 fns with a Vec parameter converts anyway, because other refusals block them; of the 71 &mut Vec<T> parameters only 4 have an integer element and the ceiling is 1 fn. The success criteria (10% fewer type Vec refusals, +20 converted fns) are out of reach for this form. My premise in this issue, that parameters would be the form most likely to move the converted share, was wrong; the count is what showed it.
What the table points at instead: 496 of the 528 locals are let x: Vec<T> = ..collect() (435 with a closure in the chain) and 151 of the 626 fns returning a bare Vec use collect. Removing the Vec refusal there only moves the first refusal to closure. The next measurement is the iterator chain with a single-expression closure: see the new issue linked below.
Activity
gHashTag commentedon Oct 19, 2026
Step 1 measured (lane A5): the Vec PARAMETER form cannot reach this issue's success criteria, so no rule PR is opened. Numbers first, then what they mean.
How it was measured
gen/rust/tools/t27o/rust_convert.rsat master ca90be1 (after t27o: a fn returning Vec<T> built by push converts in the out-buffer form -- a last out: []T, the result the count, the oracle checks the written prefix (Closes #11073, Closes #11112) #11109, t27o-sweep: a cascade refusal is counted under its root, and the files that convert whole are counted #11127, t27o: converter trio -- callers of an out-buffer String fn refused, a match in the oracle of a two-text fn, refused receivers named #11130), built withrustc; the driver makes the same calls ascmd_t27o(scratch, nothing added to the repo). One process per file, 30 s cap..rsfiles,gen/andtarget/left out, the five large files included).Vec-- the same numbers as in this issue, so this is the same base.&mut Vecparameter's body is classified by what it does with the name (regex over the body with strings and comments blanked, so "handed on" means the name appears as a call argument; approximate).1. Where the refused
Vecis (1,289 first refusals)Vecis inlet x: Vec<T> ..)&mut Vec<T>71;&[Vec<T>]11 and&mut [Vec<T>]2 (a slice of lists: t27 has no slice of slices); a Vec nested in aVec/&Vecparameter 3;mut v: Vec<T>by value 0;&Vec<T>orVec<T>by value 0 (they are slices already, see 3).-> Vec<T>606 (element: struct or enum 254, text 119, integer 103, tuple 50, float 47, bool 3, other 30),Result<Vec<T>, E>50,Option<Vec<T>>15, other 3.let x: Vec<T> = ..collect()496 (435 with a closure in the chain, 451 inside test fns); an empty start (Vec::new(),with_capacity,vec![]) 27 (19 outside tests); clone /to_vec/into3; other 2.2. The 71
&mut Vec<T>parameters: use of the parameter x element typepush/extend/extend_from_slicepush, and the Vec is handed on to a callpush, plus reads or element writes&mut [T]would do)Element types of the 71:
Stmt39,Node14 (9, and 5 as&Node), other structs 5,String5, tuples 3, a nestedVec1,u322,u82, no float, no bool. 50 of the 71 sit inlower.rs(33) andcompiler.rs(17); their element is a data-carrying enum that the converter refuses on its own. None of the 71 returns the parameter.3. The read-only form already exists, and moves nothing
param_slice(#8999) turns a read-onlyVec<T>or&Vec<T>parameter into[]const T; run on the merge base:Over all five repositories 221 fns (247 parameters) have a Vec in a parameter. 209 of those parameters are seen by the converter (38 sit in cfg-off variants it drops), and 0 of the 221 fns convert. The 74 read-only parameters (
Vec<T>by value 71,&Vec<T>3) are first refused elsewhere: type 22 (usually the return or a second Vec), uses refused 18 (a struct with a Vec field), method 16, tuple 8, undeclared 5, other 5. So a slice parameter is not the missing piece.4. What would convert
mov_imm(cli/t27b/src/a64.rs),mov_addr(cli/t27b/src/jit.rs),bit_fieldandhex8(specs/xilinx7/bitwalk.rs). Each written in the equivalent returned out-buffer form (the t27o: a fn returning Vec<T> built by push converts in the out-buffer form -- a last out: []T, the result the count, the oracle checks the written prefix (Closes #11073, Closes #11112) #11109 rule) and run through the same converter:bit_fieldconverts;hex8stops at(0..8).rev(),mov_addrat anifused as a value,mov_immatextendof a mapped iterator. The ceiling of the parameter form is 1 fn.String, tuples, nested lists), or are a slice of lists.5. Against the success criteria
Vec(at least 129 fns): the whole parameter class is 87 (6.7 %), so even a perfect conversion of every one cannot reach it.What would move the number instead (observation, not a plan)
(0..n).map(|i| ..).collect()), which the converter refuses next; removing theVecrefusal there moves the first refusal toclosureand converts nothing. Only 27 locals start empty, so step 3 of t27o: Vec<T> and vec![..] without a heap -- read-only literals, then the out-buffer form (16 % of first refusals) #10546 (a scratch list) is small.&mut Vec<T>parameter is refused as "typeVec" and could say so ("a&mut Vecparameter"). No fn would convert; I did not make it.Not run:
tri t27o-sweepitself (nocargo build -p tri: low disk); replay of oracle harnesses (nothing was converted); the classification of "handed on" calls into what the callee does with the Vec.gHashTag commentedon Oct 19, 2026
Closing as not planned, on the measurement in the comment above (lane A5):
Vecparameters are 87 of the 1,289type Vecfirst refusals (6.7%; returns 674, locals 528). A read-only&Vec<T>/Vec<T>parameter already converts to a slice on master (#8999) and none of the 221 fns with a Vec parameter converts anyway, because other refusals block them; of the 71&mut Vec<T>parameters only 4 have an integer element and the ceiling is 1 fn. The success criteria (10% fewertype Vecrefusals, +20 converted fns) are out of reach for this form. My premise in this issue, that parameters would be the form most likely to move the converted share, was wrong; the count is what showed it.What the table points at instead: 496 of the 528 locals are
let x: Vec<T> = ..collect()(435 with a closure in the chain) and 151 of the 626 fns returning a bare Vec usecollect. Removing theVecrefusal there only moves the first refusal toclosure. The next measurement is the iterator chain with a single-expression closure: see the new issue linked below.docs(t27o): RFC for heap-free collections, owned strings and inlined …