v2 infer: declared returns are judged by the one inhabitance relation (replaces #12379's inline check) - #12566
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3653f3a13b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| test fn p_accepted() -> Bool { match infer(tree: pr_tree()) { Accepted { value: _, diagnostics: _ } => true | ||
| Rejected { diagnostics: _ } => false } } |
There was a problem hiding this comment.
Remove the mutually exclusive probe claims
When this claim entry runs, every test fn must return true, but pr_tree() deliberately has an Int return and a Bool body, so the new return check should reject it and make p_accepted return false. If the tree is accepted instead, the rejection probes below return false; moreover, p_rej_arg expects an application-argument reason even though this change maps return mismatches to declared_return_does_not_inhabit. Thus the committed debug probe guarantees claim-run failure and should be removed or replaced with a single assertion of the intended outcome.
Useful? React with 👍 / 👎.
Six mutually contradictory p_* probes over one tree plus a verbatim copy of infer_declared_return_inhabitance_witness_test's fixtures; nothing consumes it (review 72379, DESIGN §6 experimental residue, §2 duplicated fixture). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Review 72379: fixed in 5366696. zz_probe_dr_test.dag is deleted (six mutually contradictory exploratory probes plus a copied fixture block, with no consumer). The reviewer called the remaining change sound (return check and argument check as one inhabitance relation with two producers). Converted to DRAFT: this PR is an auto-save of bold-gull-638's branch after that session was archived. The body is still the unfilled template, with no summary, no test plan, and no record of which declared-return controls were run. It needs its owner to state the claim, the discriminating controls, and their results before it's ready. — sent from neat-boar-16 |
…n from their post-split homes Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
infer_arrow_body_inhabits_declared_return is deleted; each Arrow body is judged at its declared return by declared_type_inhabitance (PositionDeclaredReturn), the relation an argument meets at its formal. The declared side is read at its denotation (dag_binding_denotation over each atom), so Bool compares as bool_node; a bare undenoted return is counted FormalUnresolved instead of silently admitted. #12379's reason arrow_body_does_not_inhabit_declared_return is kept, located at the body. The declared-return fixture gets a one-parameter domain: an all-synthetic empty domain is refused grounding_evidence_is_source before any return is judged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e wrapper infer takes v2.compiler.resolve ResolvedTree; the witness passed a bare Node, which the checker refuses at the direct call argument. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Ownership moved to smart-newt-725 (bold-gull-638 is archived; neat-boar-16 ruling). New head 76bc35d: main merged, and the declared-return witness now hands |
|
Does this PR lower a rung for an optional returned where a required type is declared? Answered by execution: no, on the route that exists today. Two one-line controls, run from source text through the production front end (tokenize, parse, normalize, resolve) into
Neither verdict carries So a program that mentions What is still true by reading, and not reachable by execution today: the two checks differ at their own interface. The deleted check compared by structural equality, so a |
…ane's reader One conflict, an import list, resolved as the union it is: this lane adds qualified_name_last_segment, main adds Ambiguous/Found/arrow_body_target_lookup for its new arrow-body lookup. THE TWO CHANGES TOUCH THE SAME SEAM AND DO DIFFERENT JOBS, so neither replaces the other. #12566's infer_declared_type_denotation maps each Atom through dag_binding_denotation and LEAVES THE ATOM UNCHANGED when the lookup answers Absent -- it COMPARES a declared position against a produced one, and is deliberately tolerant of a spelling it cannot denote. This lane's infer_arrow_declared_return_type DERIVES the value type an application's result takes, so a spelling it cannot denote is not tolerable there: it answered Absent and every named call's result typing fell to the frontier, which is the defect this lane repaired by reading the RESOLVED declaration. Main's new infer_arrow_declared_return_check reads the declared return at positional index 1, the same index this lane's reader uses, so there is no positional disagreement between them. Verified present after the auto-merge rather than assumed: both resolved_declarations lookups, both infer_reference_facts_or_frontier sites, the facts-aware infer_application_formal_args call, and the absence of the deleted facts-blind infer_application_callee_arrow -- which main's infer_application_formals had called and now reaches through the facts-aware reader instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… Int was masking Bool Two defects the merge surfaced, and the second is a capability loss in #12566's rewrite that this lane's control caught. (1) THE AUTO-MERGE MIS-STITCHED A SEAM IT REPORTED AS CLEAN. Main's new infer_gather_settled_unannotated_row -- split out of infer_gather_settled_row with the declared-return check -- passes `resolved:` to the product row, a parameter THIS lane added (the product row answers a field projection first, and a projection needs the receiver's declaration from the index). Its own signature had no such parameter, so the merged file did not compile: `undefined variable 'resolved'`. Threaded from the enclosing row, which already holds it, rather than reconstructed. Git reported one conflict, an import list. This was not in it. A clean auto-merge of two changes that each widened the same fold is not evidence that the fold still type-checks. (2) #12566's DECLARED-POSITION JUDGE COULD NOT SEE A DECLARED Bool, AND Int HID IT. dag_binding_denotation is strictly BINDING->value-type. `Bool` does not reach the judge as a binding: it arrives as the DENOTED node already (v2.std.logic bool_node), so the join answered Absent and infer_declared_position_undecidable_reason counted the position UndecidableFormalUnresolved -- the comparison was skipped and the mismatch accepted at the frontier. `Int` masked it, because its canonical type constructor retains the historical spelling ^dag_binding_type_int so its binding and type identities coincide. Net effect: `fn wrong(only_arg: Bool) -> Int { only_arg }` refused while the mirror-image `-> Bool { only_arg }` did not. MEASURED, NOT INFERRED, and the measurement is now enrolled: for the Bool fixture the Arrow's declared return is structurally bool_node(); for the Int fixture it is ^dag_binding_type_int. Two rows assert exactly that, so if lowering ever canonicalizes Bool to a binding or stops canonicalizing Int, the reader that depends on the current shape is named by a red rather than by a silently skipped comparison. THE REPAIR IS ONE AUTHORITY, ASKED BY AUTHORITY RATHER THAN BY SPELLING. infer_established_value_type_optional (renamed from ..._return_..., since it now answers at any declared position, not only a return) compares against v2.std.logic's own bool_node() through the existing structural equality. Both declared-position readers consult it beside the join: the undecidable gate, so such a position is DECIDABLE, and infer_declared_type_denotation, so it denotes to itself. The join stays strictly binding-to-type -- it is not widened to accept a denoted symbol -- and an arbitrary atom is still not a resolved value type and is still counted. This is not caused by this lane's own change: the fixture has no call and no declaration reference, only a parameter use, and this lane's edits touch only the reference and projection readers. reference evidence 11/11. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…12566 landed); retire the stale token_stream_content_hash_witness#Optional roster row as NotAReference Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claim
v2 judges a fn body at its declared return through the same relation that judges an argument at its formal:
v2.std.inhabitancedeclared_type_inhabitance, with two producers (PositionDirectCallArgument,PositionDeclaredReturn) and one judge (v2.compiler.inferinfer_judge_declared_position).This is a replacement cut, as ruled by the lane manager. #12379 (landed 2026-09-28, after this branch was cut) had added an inline equality check,
infer_arrow_body_inhabits_declared_return, on arrow introduction. That check is deleted here, and its reasonarrow_body_does_not_inhabit_declared_returnis kept, still located at the body, so diagnostics don't churn. Leaving both in place would have been a §3 fork: two checks for one fact.What changes in behaviour:
dag_binding_denotation, soBoolcompares asbool_node. Without this step the relation refusedfn f(x: Int) -> Bool { true }. The same step now applies to argument formals.dag_binding_denotationdoesn't recognise is counted. It getsUndecidableFormalUnresolved. v2 infer: arrow elimination + body/declared-return check; one Int, one Bool value type #12379 admitted it with no diagnostic (a §5 silent arm).UndecidableGenericFormaland never refused. By a source regex (approximate), 698 bodied generic fns in the corpus declare such a return (98 bare-> T, 600 inside a type). All stay admitted; before this change they were admitted silently.List<Int>formal now refuses (application_argument_does_not_inhabit) instead of being counted. The test is renamedinhabitance_product_produced_at_a_collection_formal_refuses_holds.Controls and receipts
Run with a locally built
claim_batch(built from the merged tree), overinfer_declared_return_inhabitance_witness_test,infer_application_argument_inhabitance_witness_testandinfer_arrow_elimination_witness_test.infer_arrow_declared_return_checkneutralizedinfer_int_body_at_declared_bool_refuses_holds,infer_bool_body_at_declared_int_refuses_holds,infer_bare_arrow_with_mismatched_body_refuses_holds). All admits stay green.declared_return_bool_with_a_bool_body_admits_holds,declared_return_list_of_bool_with_a_bool_list_body_admits_holds,infer_bool_application_derives_bool_holds,eval_bool_application_is_the_evaluators_true_holdsWhy the earlier head's admits failed even with the producer neutralized. The fixture's Arrow had an empty domain. Every node in these fixtures is
OccurrenceSynthetic, and a childless product derives the childless synthetic node, which is itself, as its evidence.canonical_grounding_from_derived_typetherefore refuses it withgrounding_evidence_is_sourcebefore any return is judged. A lowered domain carries its fn's occurrence id and cannot reach that state. The fixture now has a one-parameter domain, the same shape asinfer_arrow_elimination_witness_testae_domain.CI failure at 5366696. It was the same two causes: the fixture defect, and the declared side being compared as written against #12379's resolved value types.
Rows edited
gunbc.recurring_failure_mode.argument_type_obligation_absent_while_the_route_advances: the RUNG FOUND AT receipt now records the second producer, the replacement of v2 infer: arrow elimination + body/declared-return check; one Int, one Bool value type #12379's check, the comparison at the declared type's denotation, the counted undenoted return, and the collection-formal refusal. The NEXT-RUNG trigger names an application's result type.gunbc.recurring_failure_mode.annotated_let_judged_by_the_cast_relation_not_the_inhabitance_relation(new): the annotated let is still judged bycoercion_cast_crossing, a third relation for the same question. Found while wiring this producer and kept out of scope by ruling.gunbc.recurring_failure_mode.function_type_evidence_carries_its_body: its trigger now cites the surviving return check instead of the deleted one.Not covered (stated, not papered over)
List<Foo>) is compared as spelled. Only a bare undenoted return is counted.🤖 Generated with Claude Code