Skip to content

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

Closed as not planned

Description

@gHashTag

Goal

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

  • Given fn 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.
  • Given fn 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.

Activity

  1. gHashTag commented on Oct 19, 2026

    @gHashTag
    OwnerAuthor

    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

    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:

    pub fn sum(v: &Vec<u32>) -> u32 { .. v.len() .. v[i] .. }   ->  pub fn sum(v: []const u32) -> u32
    pub fn sum_owned(v: Vec<u32>) -> u32 { .. }                   ->  pub fn sum_owned(v: []const u32) -> u32
    pub fn fill(out: &mut Vec<u8>)  { out.push(1); .. }           ->  refused: type `Vec`
    pub fn grow(out: &mut Vec<u8>)  { out.resize(8, 0); }         ->  refused: type `Vec`
    

    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

    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)

    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.

  2. gHashTag commented on Oct 19, 2026

    @gHashTag
    OwnerAuthor

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions