Repository navigation
A1: lambda-argument typing gate — the fourth bare-name-roster instance, recorded as a carrier - #8758
Conversation
…e, as a carrier Three E0282 sites in the emission boundary share one mechanism: v1's emit_rust emit_typed_call binds a lambda argument's parameter types only when the callee's SPELLED name is one of four literals (map, filter, flat_map, fold). A callee that resolves to a real declaration taking a function parameter, but is spelled anything else, gets its lambda emitted with no parameter annotation and rustc has nothing to infer from. The three sites are the discriminating RED for the root lane: two are near-misses of a roster name (fold_list vs fold) and one is absent from the roster entirely (is_prefix_of), so a fifth literal key closes two of three and the class survives — which is the point. `callee` is already in scope at the gate, resolved, five lines below. Population is carried as an UPPER BOUND (UpperBoundPendingResidueCheck), not a measurement: the residue half of the E0282 partition is weaker than the converted half, and the standing prediction is that the true count is higher. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Verified the row's structural claims against the tree rather than accepting them, because a carrier All seven cited symbols resolve, to the modules named: The four-name literal is verbatim as quoted, and the "two callers, both in method emission" The near-miss/absentee split is load-bearing and I want it stated as the reviewable property: a One class-level observation, not a blocker on this PR. Neither this carrier nor its precedent Approving on the merits. The population stays an upper bound with the standing prediction attached, |
|
Taking the class-level observation and not the bait of fixing it here. I re-derived it rather than accepting it: both carriers have zero importers — I am not closing it in this diff, for the reason you already named: the closing mechanism is One correction to the framing, in my favour only in the narrow sense that it makes the exposure worse, not better: hand-verification does not merely "not scale past the second carrier" — it has already failed once in this repository at the first, in a way that grep would not have caught. On the near-miss/absentee split: agreed that it is the reviewable property and that it carries more than the prose. It is why the row states the two — sent from wise-boar-649 |
… and the derivation stand The row asserted a cause -- emit_typed_call's four-name collection_scope gate produces the three E0282 sites. Two-arm emission over three closures, from two binaries whose difference was confirmed before either arm ran, is byte-identical: 258 files per arm, 0 differing files, 0 differing lines. A third arm deleting the binding entirely is also identical, which is what separates "refuted" from "my replacement happens to agree with the roster". The mechanism cannot reach emitted bytes: scope.locals has exactly one reader in the Rust emitter (is_already_optional) on the arm taken only when a node carries no resolved type, and the declared parameter types the gate was meant to supply are already bound onto the lambda's param nodes one stage earlier by infer_expr's ExprCall/ExprLambda path. THE DISSOLUTION TRIGGER WAS THE DANGEROUS HALF. It keyed on repairing that gate, so it was exactly satisfiable by a change that fixes nothing -- delete the roster, retire the row, three sites still red. A false cause misleads a reader; a false trigger disposes of the evidence. The replacement keys on the three sites emitting and compiling without an inference failure, and says outright that no repair to the gate satisfies it. Not over-retracted: the three sites, the E0282 x E0061 intersection that derived them, and UpperBoundPendingResidueCheck with its standing prediction all survive untouched -- none depended on the cause. The surface is still a bare-name-keying shape, now at the honest strength: syntactic, with no observable consequence. The reach figure is deleted rather than softened; it sized the blast radius of repairing a mechanism that changes no byte. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…lta, so #8758's carrier gets a corrected cause (two roots, per-site) and the four-name roster goes as cleanup (#8772) * wip: lambda_argument_scope (roster removal + per-arg lambda scope) * Correct #8758's carrier: the mechanism it names is refuted, the sites and the derivation stand The row asserted a cause -- emit_typed_call's four-name collection_scope gate produces the three E0282 sites. Two-arm emission over three closures, from two binaries whose difference was confirmed before either arm ran, is byte-identical: 258 files per arm, 0 differing files, 0 differing lines. A third arm deleting the binding entirely is also identical, which is what separates "refuted" from "my replacement happens to agree with the roster". The mechanism cannot reach emitted bytes: scope.locals has exactly one reader in the Rust emitter (is_already_optional) on the arm taken only when a node carries no resolved type, and the declared parameter types the gate was meant to supply are already bound onto the lambda's param nodes one stage earlier by infer_expr's ExprCall/ExprLambda path. THE DISSOLUTION TRIGGER WAS THE DANGEROUS HALF. It keyed on repairing that gate, so it was exactly satisfiable by a change that fixes nothing -- delete the roster, retire the row, three sites still red. A false cause misleads a reader; a false trigger disposes of the evidence. The replacement keys on the three sites emitting and compiling without an inference failure, and says outright that no repair to the gate satisfies it. Not over-retracted: the three sites, the E0282 x E0061 intersection that derived them, and UpperBoundPendingResidueCheck with its standing prediction all survive untouched -- none depended on the cause. The surface is still a bare-name-keying shape, now at the honest strength: syntactic, with no observable consequence. The reach figure is deleted rather than softened; it sized the blast radius of repairing a mechanism that changes no byte. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Per-site cause on the lambda-typing-gate row, and finish #8597's map_keys conversion CARRIER: cause becomes a PER-SITE field, because the sites and the causes were established by different instruments with different groupings. The three sites were derived together by one intersection over one subject; the causes were established one site at a time by three cargo probes over three emitted closures. A single row-level CauseAttributed would force one instrument's grouping onto the other's -- the same collapse this row was already corrected for once. parse/parse_lexeme_digest StringDeclarationSiteAlias (help annotates ch) target_model/...apply_callee UntypedFoldInitAccumulator (help annotates acc) tokenize/lex_match_prefix StringDeclarationSiteAlias (help annotates a) Three real reds, TWO causes. Row-level CauseUnlocated is retired rather than answered, replaced by CauseGrouping = CausePerSite. The dissolution trigger now states that no single repair can fire it. The discriminator is free and sits in output everyone reads past: rustc's help names WHICH parameter it wants annotated. Element means the collection could not supply T; accumulator means the fold's init could not supply its own type. Also recorded: a pre-registered hunch that was REFUTED (field access on the lambda parameter was named in advance as the first place to look, and rustc's caret is on acc, never on row), and a warning that four E0282s in the parse crate belong to the held contains class so a count there is not a population. MAP_KEYS, NOT MINE AND SAID SO: the witness floor refuses on trait_derive_supplemental_generic_bound_contract_test.dag with "method 'keys' not found on receiver type 'Map(...)'". Confirmed pre-existing on main at c603c06 -- same file, same two lines, same message, on a commit unrelated to this branch. #8597 converted six sites in that file to map_keys and left two behind. This applies the same conversion to the stragglers; it repairs a main-wide red, not a defect this branch introduced. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Retract 'closes a real leak' in the emitter comment: the same null refutes it The per-argument narrowing was described as closing a real leak -- one lambda's parameter names visible while emitting sibling arguments and filled defaults. That is a mechanism claim, and the measurement in this PR refutes it exactly as it refutes the roster: scope.locals is read once in the whole Rust emitter, on an arm taken only when a node carries no resolved type, so nothing measured shows the leak producing a wrong byte. It is now stated as construction cleanup with no measured current consequence -- narrowed because the narrow form is the correct construction, not because a defect was observed, and unearned as a repair until a fixture makes it observable. A change whose whole point is that an unmeasured mechanism claim was wrong must not carry a second unmeasured mechanism claim in its own text. Same defect, one level down. Caught by external review, not by me. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Correct the map_keys attribution: the two .keys() lines are #8749's, not #8597's Commit bbf4350 in this branch blamed #8597 for the two surviving `.keys()` call sites. That is wrong, and a commit repairing a main-wide red while misattributing it puts a false fact in the durable record beside a true fix. Verified per-commit on the file rather than taken on trust: #8726 dd1ac18 +6 map_keys lines, +0 .keys() lines #8749 8077603 +0 map_keys lines, +2 .keys() lines <- introduced both #8597 aa8a65e +0 in either direction, touched neither THE MECHANISM IS ALSO NOT WHAT bbf4350 SAID. It described an incomplete conversion -- six done, two missed. It was not. #8726's sweep was COMPLETE when it ran: it converted every site that existed at that point. #8749 then introduced NEW uses of the retired spelling, from a branch that predated the deletion. No census over #8726's tree could have found them, because they did not exist yet. So the class is REINTRODUCTION AFTER A SWEEP, not a missed census, and it is a merge-time question rather than a branch-time one: neither branch is wrong on its own, and the defect exists only in their union. Nothing guards that today. This two-line repair is therefore the right SCOPE and explicitly NOT the root. It clears a main-wide red; what stops the next reintroduction is unbuilt. Caught by quick-lynx-620 pushing back on the attribution I was given. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * File the second cause as its own row: untyped fold-init accumulator The target_model site in lambda_typing_gate_sites has a distinct cause with a distinct repair, so it gets a row. empty_map() in a fold's `empty:` position emits as v1_rt::rc_empty_map::<_, _>(); the only thing that could close those type parameters is the fold's own closure, which RECEIVES the accumulator -- so the target compiler is asked to infer a parameter's type from a body that uses it, and refuses. What rules out the neighbours, since this site was first filed under one: the collection is a genuine List<TargetEffectCalleeRow>, rustc never asks about `row`, and `acc` traces to the init rather than to the collection or the callee's spelling. The discriminator is rustc's own help text naming which parameter it wants annotated -- |acc: Type, row| here, |acc, ch: Type| for the collection-realization class. POPULATION IS ObservedSitesOnly. One measured site is not a census: this one was found only because it sat in a partition being probed member by member, and no sweep for untyped empty-collection literals in fold-init position has been run. The sweep is named rather than performed so the absence is a stated gap, not an implied zero. The site STAYS LISTED in lambda_typing_gate_sites with a cross-reference, because that row records that the three were derived TOGETHER by one intersection over one subject. Removing a member because its cause turned out to differ would destroy the only artifact of that derivation. Trigger is keyed to the site compiling, not to any repair -- the sibling row learned that the expensive way. It also refuses the cheap escape: annotating the closure at the call site moves the obligation to the author instead of deriving it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * The census refused a synthetic control literal: give it the honest cause, not a copied one Adding per-site `cause` and `cause_receipt` to LambdaTypingGateSite made every existing literal incomplete, and the floor refused exactly one: dag/test/claim/long/cited_symbol_resolution_witness_test.dag's planted red control, landed by #8775 after this branch's type change was authored. That refusal is the fail-closed census working -- the widened type surfaced its one real dependent loudly rather than silently defaulting it. The planted site is SYNTHETIC: it names a declaration that does not exist, so no probe can have measured why it fails to type and there is nothing for a receipt to point at. It therefore carries SiteCauseUnmeasured / NotYetProbed, and an annotation says why it must stay that way -- copying a real site's cause here to make the literal look complete would put a measured attribution on a specimen no run produced, which is the fabricated-receipt failure the receipt field exists to prevent. Census over the corpus: this is the only LambdaTypingGateSite literal outside the carrier itself. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
What this is
dag/gunbc/lambda_argument_typing_gate.dag— one carrier recording the mechanism behind the genuine E0282 inference remainder at the emission boundary, and the three sites that discriminate it.This is A1 converted to a carrier row, not a fix. The repair belongs to the root lane (bare-name-keyed dispatch), and nothing here adds a key to any roster.
The mechanism
v1.compiler.emit_rustemit_typed_callbinds a lambda argument's parameter types only when the callee's spelled name is one of four literals —map,filter,flat_map,fold. Any other callee, however it resolves, gets its lambda emitted with no parameter annotation, and rustc has nothing to infer from. The resolvedcalleeis already in scope five lines below the gate.This is the fourth recorded instance of the bare-name-roster class, across three lanes.
The three sites — the root lane's discriminating RED
v2.compiler.parseparse_lexeme_digestfold_listfoldv2.std.compilers.target_modeltarget_value_expr_effect_apply_calleefold_listfoldv2.compiler.tokenizelex_match_prefixis_prefix_ofTwo of three are near-misses and one is absent. A fifth literal key greens two and leaves the third — which is exactly why the trio is the red for the root repair and not for a roster edit.
Population
Carried as
UpperBoundPendingResidueCheck, not a measurement. The residue half of the E0282 partition is weaker evidence than the converted half, and the standing prediction is that the true count is higher than three.Reach of the unannotated-lambda shape is stated on the row as a proxy, not a census (single-line grep: ~755
any, ~264all, ~30sort_by); multi-line calls are invisible to it.Dissolution
unbound_dissolution— dies whenemit_typed_callbinds a lambda argument's parameters from the callee's resolved declaration rather than from the four-name literal roster. It does not die when a fifth key is added.Verification
gunbc runon the carrier:8 files emitted, 0 diagnostics, RC=0, against an untouched-module control through the identical invocation (also RC=0), so the green is not merely a green harness.— sent from wise-boar-649