Repository navigation
fix(ts): mark a parameter unused when its function's output never reads it - #318
Conversation
Quest-Claim: 3b2325247e0d07e9
…ds it Lowering can drop every read of a parameter: a drop of a type that drops nothing, a comparison of values holding nothing. Each function's and arrow's parameters are now marked `_name` when its emitted body names them nowhere, in one pass over the program before merging, replacing the MIR-side guess of which reads lowering keeps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rams # Conflicts: # ts/fixtures/lang/expected/harness.ts # ts/fixtures/lang/src/harness.rs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A function a body makes, such as `flatten`'s `(value) => ...`, binds its own parameters and declarations, which say nothing of the outer function's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rams # Conflicts: # ts/fixtures/lang/expected/harness.ts # ts/fixtures/lang/src/harness.rs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rams # Conflicts: # ts/fixtures/lang/expected/harness.ts # ts/fixtures/lang/src/harness.rs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 59 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed commit: 0a496e8
No actionable bugs found in this change. Moving unread-parameter detection to emitted TypeScript is a sound replacement for the MIR-side approximation. The free-name walk handles nested function/block scopes, and fresh parameter names avoid existing bindings; the added fixtures cover erased drops, folded comparisons and nested callback names.
Verification limits: static inspection of the diff and surrounding lowering, naming and printing code only. I did not run the translator, TypeScript compiler or tests. The bounded-zip issue mentioned in the PR body belongs to unchanged code and was not re-reviewed here.
(Written by OpenAI)
# Conflicts: # ts/fixtures/lang/expected/harness.ts # ts/fixtures/lang/src/harness.rs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Completes quest/m3/ts-unread-params.md.
Problem
Lowering can drop every read of a parameter, and
tscthen refuses the output undernoUnusedParameters. Reproduced in thelangfixture before the fix:The first is the quest's case, a generic
Dropimpl like crossbeam-epoch'sOnceLockinstantiated at aTthat drops nothing. The other two are the()comparisons #303 found. #311'sreads_valuedid not cover them: it guessed from MIR which reads lowering keeps, and saw only reads through fields that hold nothing. It also marked parameters the output still reads, such as_selfinzeros.Names.ts'sclone$Clone.Approach
ts::mark_unreaddecides from the emitted output. A parameter whose function body never names it becomes_name, with a name nothing in the body uses. The same applies to every arrow and lambda nested in the body. It does not matter which part of lowering dropped the reads.Program::mark_unreadruns that pass over every function, method, field initializer, and module value once, beforemerge.reads_valueand the parameter renaming inFxare deleted.prune_unreadalready drops declarations whose output nothing reads.unnamed_paramsalready decides from the emitted field types, and class methods never name a class's type parameters.Lock<u32>,PhantomDatalocals, and a closure parameter.tsccounts that as unread. Optimized MIR drops dead stores, though, and no fixture emits such a body.Tests
The new
zeros::unreadcase in thelangfixture covers:Lock<T>dropped atu32and at a type that drops()andPhantomDatacomparisons, as parameters, as closure parameters, and as localsvaluebesideflatten's own(value) => ...callback, so only the names a nested function reads from outside it counttscchecks its output, and it runs differentially against native wasm32. Other snapshots changed only inlang:zeros.Names.tsno longer marks the parameters it reads.hints.tsrenumbers names, because an unread closure parameter now takes its base name before being marked (_ibecomes_i12).Impact
Alternatives
reads_valuewith each further way lowering drops reads (drops of what drops nothing, folded comparisons). Rejected: it would keep guessing from MIR, and it would miss the next way lowering drops a read.mergecompares parameters, so marking before it keeps identical instances identical.Follow-ups
ts/src/lower/iter.rs:877). Forlet mut r = 0u8..=5; let n = r.by_ref().zip(0..2u8).count(); (n, r.next()), native Rust gives(2, Some(2)). The reviewer reports that the translation consumes one more left item and gives(2, Some(3)). I have not verified it. Worth a quest via/quest-plan.Review
Codex
gpt-6.1-sol, medium effort, viaquest review. The latest round (3) reviewed head0a496e8104a38469b85f4b6d7d9477512c958e05and found nothing.iter.rsbounded zip fold from feat(ts): fold a zip of TrustedLen iterators by its size hint #314, listed under Follow-ups.just cipasses locally on the reviewed head.Merge of main at
49f119b2into0a496e81, as23604dfb: kept main'sfmt::iterscase before this PR'szeros::unreadin the lang harness and regeneratedexpected/harness.ts. Recorded skip, too trivial to review;just cipassed on23604dfb.The Follow-ups' zip over-read was checked and not reproduced on
49f119b2: the translation gives native's(2, Some(2)), and a 1.4M-input sweep found no difference.(written by Claude Opus 5.5)
🤖 Generated with Claude Code