lift: a name is found the same way wherever it is asked for #219
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/219-lift-a-name-is-found-the-same-way-wherever-it"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
lift: a name is found the same way wherever it is asked for
Along the way:
Touches 12 files:
plan.md,src/rust/crates/ck_driver/tests/capability.rs,src/rust/crates/ck_types/src/field_access.rs,src/rust/crates/ck_types/src/lift.rs,src/rust/crates/ck_types/src/newtype_ctor.rs,tests/capability/money_add_operator_does_not_lower.cktestand 6 more.Read it too. No objection to
src/rust/crates/ck_types/src/field_access.rs.Two things inline. The one in
src/rust/crates/ck_types/src/field_access.rsis the one I care about.@ -239,1 +242,3 @@return None;return interner.newtype_scalar_target(id).map(|leaf| Ty::nominal(leaf, Vec::new()));mapallocates a fresh buffer per call. If this runs per frame or per token, can the buffer be reused?@ -70,0 +116,4 @@/// One rule otherwise, read off the declaration's own parameter list — no type/// name, and no per-parameter *kind* (a tag and a size are treated alike; the/// question is only whether the bare name fills the slot).fn under_determined(id: TypeId, ret: &Ty, interner: &Interner) -> bool {under_determinedreads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?Good. The second pass on
src/rust/crates/ck_types/src/field_access.rsis what I hoped for.It runs per token. The buffer behind
maplives on the struct insrc/rust/crates/ck_types/src/field_access.rsnow and is cleared rather than reallocated.Split. The decision in
under_determinedis a pure function now, with its own tests insrc/rust/crates/ck_types/src/newtype_ctor.rs.Updated. The point about
src/rust/crates/ck_types/src/field_access.rsturned out to be a real bug, so thank you.`ck_types::field_access::newtype_rep_ty` claimed in its own doc to be "the ONE rep-type law shared by both convention surfaces" — the `v.value` accessor and the `N(r)` constructor — and answered only ONE of the two rep shapes a `newtype` can declare. The named-tuple rep (`newtype String<size> = (| position, len |)`) came out of it; the scalar rep (`newtype DateSpan = i64`) did not. The accessor covered for that with a second arm of its own; the constructor had none, so a scalar-rep newtype had no constructor type at all. The cost was not a diagnostic. `DateSpan(42)` synthesized `Unknown`, the coherence probe needs a `Ty::Nominal` operand to project its input-position key from (`method_call.rs:632`), so the operand pair was dropped, the driver settled no impl for the call (`mono::method_impls_for_body`), and `lower_method_call` fell through to the spanned `Unsupported` codegen refuses. `a + DateSpan(42)` therefore did not lower while `let s = DateSpan(42); a + s` did — the operand's FORM decided, which an operand's form must never do. Both shapes now come out of the one function, and the accessor keeps only the accessor-name reservation. The exactness this buys is the other direction too: `f(DateSpan(1))` against a `String` parameter is now E0702 where it used to check clean and reach the Cranelift verifier. Ratchets: `BROKEN_CELL_COUNT` 54 -> 49, `CELL_COUNT` 437 -> 438. Six cells flip to WORKS; only ONE is earned by this change: · newtype_ctor_call_as_an_operator_operand <- this commit The other five were ALREADY green at b5668540 and had merely never been re-run, because `--test capability` is the only harness that executes them and it has not run since the slices that fixed them merged (plan.md §1, §6): · money_add_operator_does_not_lower · money_equals_operator_does_not_lower · money_show_does_not_lower · money_value_projection_does_not_lower · tag_newtype_operator_across_a_module_boundary `money_add_operator_does_not_lower`'s tail changes from a bare `42` to `c.value` so that it observes the FOLDED SUM (21 + 21 minor units) instead of proving only that the program compiled. Its own comment block had said to do exactly this once `.value` answered on a tag-parameterised newtype, which it now does. `Types.ck`'s KNOWN GAP note — "an app-side `Show::show(m)` on a TAG-parameterised type lowers Unsupported today" — is retired in this commit, which is what `money_show_does_not_lower` was written to force. One new cell, BROKEN: `tag_newtype_ctor_result_is_under_determined`. A constructor on a newtype with an UNFILLED generic parameter (`Money::<USD>(1)`) still has no RESULT type. Inference here is synthesis-only by design, so neither the turbofish nor the slot reaches the node, and naming the zero-argument head `Money` would be a WRONG answer rather than a partial one — nominal assignability is invariant, so it refuses the `Money<USD>` slot the value is legitimately bound to (measured: E0722 out of `impl Add<Money<USD>, …>`'s own body). The under-determined result therefore stays fail-soft `Unknown`, scoped to the scalar rep shape, with the reason written at `under_determined`: the named-tuple shape must keep its bare head or twelve `list_*` cells stop lowering (`List.ck` spells its own slots bare), and nothing in the two declarations separates them — only their consumers' spelling does. That is an asymmetry, it is measured, and it is pinned rather than left in prose. Verified without the capability harness (not this session's to run): all 438 cells materialized and taken to `ckc check` + `ckc disassemble` before and after — exactly one cell moves, plus the new one; all 143 project directories under tests/{corpus,corpus_test_run,corpus_parked} byte-identical at `ckc check`; the six flipped cells linked freestanding and executed natively, each exit 42. `--test conformance`, `--test architecture`, `-p ck_types`, `-p ck_lower`, `-p ck_resolve`, `-p ck_cktest` green. `cargo fmt --check` clean; `clippy --workspace --all-targets -D warnings` 0 warnings, 0 errors.