Repository navigation
The lambda-typing gate is INERT: three arms show zero emitted-byte delta, so #8758's carrier gets a corrected cause (two roots, per-site) and the four-name roster goes as cleanup - #8772
Merged
Conversation
… 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>
…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>
…futes 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>
…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>
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>
…ction, delete the refuted one The only genuine conflict was gunbc.lambda_argument_typing_gate, and it was substantive rather than textual. Main had added a citation-enrollment projection to the carrier and still held the ORIGINAL dissolution trigger -- the one keyed to emit_typed_call binding lambda params from the callee's resolved declaration rather than from the four-name roster. That mechanism was measured inert on this branch: three arms, 258 files each, zero differing files, zero diff lines, including a deletion control. Keeping both sides would leave the row with two answers to when it dies, one of them satisfiable by a change that fixes nothing -- delete the roster, retire the row, three sites still red. So main's trigger and the reach paragraph arguing for it are DELETED, not kept beside the replacement, and a merge note records that they were deleted and why, so the removal is not a silent drop of authored rows. Main's enrollment projection is untouched; the imports are the union of both sides. The trait_derive_supplemental_generic_bound_contract_test.dag hunks this branch carried DROPPED OUT on absorb rather than needing resolution, because that repair landed independently through #8780. Verified after the merge: the file is now byte-identical to main. Hand-resolving them would have re-authored a fix already on main and produced a hybrid no generator emitted. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…use, 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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR is, stated before anything else
Two things, and neither of them fixes the three E0282 sites the branch title names:
emit_typed_call— as a cleanup whose receipt is a measured zero emitted-byte delta.The branch title is the original brief. Its causal claim did not survive measurement, and this PR says so rather than quietly delivering something else under it.
The measurement
Two-arm emission. Subject: emitted closures of
v2.compiler.tokenize,v2.compiler.parse,v2.lens.reference_deps. Producer:gunbc compile --target rust, two separately built release binaries in one dispatch. Controls run before either arm: arm B mirrorlambda_argument_scope=2 / roster hits=0, arm Alambda_argument_scope=0 / roster hits=1 — the binaries are provably different.Arm C — the binding deleted entirely, not generalized — is also identical. That is what separates "the mechanism is inert" from "my replacement happens to agree with the roster", and it is the control that makes the null conclusive.
Why the mechanism cannot reach emitted bytes
Every
scope.read insrc/v1/05_emit_rust.dag:type_env204,module_name7,item_registry1,locals1. That singlescope.localsreader isis_already_optional, on the arm taken only when a node carries no resolved type. Emission runs off the typed tree.And the declared parameter types the gate was supposed to supply are already consulted one stage earlier —
v1.compiler.inferinfer_expr'sExprCallarm passes each callee formal as the argument's expected type, and itsExprLambdaarm binds the lambda's parameters from that formal and writes the resolved types back onto the parameter nodes, which is exactly whatlambda_scope_from_childrenreads. So "consult the resolved callee fromlookup_item" would have been a second consultation of a fact inference had already resolved, landing in the same inert scope.What changes in the emitter
map/filter/flat_map/fold) is deleted.lambda_argument_scope).That narrowing is construction cleanup with NO MEASURED CURRENT CONSEQUENCE, and an earlier revision of this body called it "a real leak" — which the same null refutes.
scope.localsis read once in the whole Rust emitter, on an arm taken only when a node carries no resolved type, so nothing measured here shows the leak producing a wrong byte either. It is narrowed because the narrow form is the correct construction, not because a defect was observed, and it stays unearned as a repair until a fixture makes it observable. A PR whose entire point is that an unmeasured mechanism claim was wrong must not carry a second unmeasured mechanism claim in its own body.The surface was a genuine bare-name-keying shape — the null refutes its consequence, not its shape — so this is a syntactic instance with no observable consequence, and deleting it is a cleanup rather than a defect repair. A literal roster that reads as a live decision and decides nothing is a false coverage surface.
The carrier correction, and the dangerous half
#8758's dissolution trigger read "dies when
emit_typed_callbinds a lambda argument's parameters from the callee's resolved declaration rather than from the four-name roster." With the mechanism refuted, that trigger is 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 dissolution trigger disposes of the evidence. The replacement keys on the only fact that can honestly retire the row — the three sites emitting and compiling without an inference failure — and states that no repair to the gate satisfies it on its own.The mechanism verdict is now a typed row carrying its own measurement (
MechanismRefutedByEmittedByteNull), not prose, because prose is precisely how the previous cause got planned against. Cause isCauseUnlocated.Deliberately not over-retracted: the three sites, their locations, the E0282 × E0061 intersection that derived them, the seven companions in the held class, and
UpperBoundPendingResidueCheckwith its standing prediction all survive untouched. None of them depended on the cause. The reach figure is deleted outright rather than softened — it sized the blast radius of repairing a mechanism that changes no byte.Superseded: the
map_keysrepair this PR used to carryThis section described a two-line
map_keysrepair totrait_derive_supplemental_generic_bound_contract_test.dagthat rode along on this branch.It is no longer in this diff and the section is kept only so the record is not silently
rewritten. That repair landed independently through #8780, and when this branch absorbed
main the hunks dropped out on their own rather than needing resolution — verified after the
merge: the file is now byte-identical to main. Hand-resolving them would have re-authored a fix
already on main and produced a hybrid no generator emitted.
Anyone tracing who fixed the
.keys()sites should land on #8780, not here.Caveats, stated rather than buried
.dagauthority emits that same Rust is not established here; it needs regen. The null is a statement about the mechanism's reach, and arm C carries it without depending on the mirror.origin/mainhas since been merged into this branch (it addedrust_call_arg_function_value_adaptat the same site, kept).Where the real root looks to be — not in this PR
The emitted specimen:
eq's parameters are inferable fromimpl Fn(T, T)the momentTis known, andTis knowable only fromprefix/xs.v2.std.textdeclaresString = FreeMonoid<Char>but emits as the hoststd::string::String, so the argument cannot unify withRc<Vec<T>>,Tnever binds, and rustc reports at the closure. The closure is the symptom location, not the cause — which is why a roster of callee names was never going to move it. DESIGN already records this alias special-case inemit_typed_item. Hypothesis with strong supporting structure, not yet a measurement; confirming it needs cargo on the emitted crate, and that is the next lane's work.🤖 Generated with Claude Code