types(TY5): method-call sugar — r.f(…) → Tr::f(r, …) via receiver type #26
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/026-types-ty5-method-call-sugar-r-f-tr-f-r-via-rec"
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?
types(TY5): method-call sugar — r.f(…) → Tr::f(r, …) via receiver type
Along the way:
-> Treturn to the receiver typeTouches 45 files:
docs/impl/08-diagnostics.md,docs/impl/type-system/README.md,docs/impl/type-system/TY5-method-call-sugar.md,docs/impl/type-system/TY6-construction-and-projection.md,docs/impl/type-system/inherent-impls-and-receiver-binding.md,src/rust/crates/ck_cktest/src/diag_trap.rsand 39 more.Happy with this. I ran the suite against the branch and it is green,
src/rust/crates/ck_types/src/method_call.rsincluded.@ -586,0 +721,4 @@);let (_, tail) = root_block(&body);let ExprKind::With { base, value } = body.expr(tail.expect("trailing with")).kind else {panic!("expected a With, got {:?}", body.expr(tail.unwrap()).kind);exprunwraps here. If this is reachable from user input it is a panic in front of a person rather than an error they can read. Is it provably there at this point, or should it carry a??, at src/rust/crates/ck_resolve/src/lower.rs:724.@ -0,0 +365,4 @@/// means a wrong receiver neither resolves nor causes a spurious ambiguity:/// exactly one accepting → resolved; many → **E0729**; none, but a match was/// rejected only on the receiver → **E0702**; no match at all → **E0728**.fn select_candidate(matches: Vec<Candidate>, recv_ty: &Ty) -> MethodResolution {select_candidatereads, decides and writes in one function. The deciding part is the piece I would want to test on its own. Worth splitting?@ -0,0 +244,4 @@// pass; the receiver slot (and its E0702 secondary label) is the *last*// parameter under data-last binding.let mut params: Vec<Ty> = Vec::new();let mut param_idents: Vec<ParamIdent> = Vec::new();param_identsallocates a fresh buffer per call. If this runs per frame or per token, can the buffer be reused?Looked through
src/rust/crates/ck_types/src/method_call.rsas well. Fine by me.Split. The decision in
select_candidateis a pure function now, with its own tests insrc/rust/crates/ck_types/src/method_call.rs.It runs per token. The buffer behind
param_identslives on the struct insrc/rust/crates/ck_types/src/trait_methods.rsnow and is cleared rather than reallocated.It is reachable. The function in
src/rust/crates/ck_resolve/src/lower.rsreturns a Result now and the caller reports it, so the unwrap onexpris gone, at src/rust/crates/ck_resolve/src/lower.rs:724.-> Treturn to the receiver type 2091e02faeCloses TY5 deferral 1. The receiver is argument 0, so a method whose first parameter does not accept the receiver's type is not callable as `r.f(…)` — e.g. `someCat.count()` against `fn count(n: Int) -> Int` (the receiver slot is `Int`, not `Cat`). Previously the resolver matched on trait-impl + name + arity alone and wrongly accepted such calls. `resolve_method_call` now substitutes the trait's primary type parameter into the receiver slot as well as the return, then partitions the name+arity matches on `assignable(receiver, params[0])`: - exactly one accepting candidate → resolved; - a match rejected only on the receiver → E0702 (reusing the argument- mismatch diagnostic, secondary on the trait method's receiver param); - no match at all → E0728. Partitioning before the count also means a wrong receiver no longer causes a spurious E0729 ambiguity. `TraitMethodSig` gained `recv_param_span` for the E0702 secondary; the candidate-selection logic is split into `select_candidate` to stay under the R4 function-LoC cap. Still deferred: checking arguments 1.. against parameters 1.. (only the receiver is checked today). Proof: tests/types/method_call_receiver_mismatch.cktest (trapped E0702) plus the receiver_not_assignable_to_first_parameter_is_a_mismatch unit test. Gates green: build, clippy -D warnings, R4, 796 tests.`render_blessed` emitted all three `# expected:` sections (tokens, cst, diagnostics) for every fixture, so `tests/types/` and `tests/resolve/` goldens carried token/CST dumps that are conceptually wrong for the topic and brittle (every byte-offset shifts on any source edit). The `tests/<topic>/` directory is now the single source of truth for which sections a fixture carries, via `topic_sections`: - lex → tokens + diagnostics (lexer output is its token stream) - parser → cst + diagnostics (parser output is its CST) - else → diagnostics only (resolve, types: observed via diagnostics) `diagnostics` is universal (every stage emits them; `# trap` reconciliation reads them); the primary section is topic-specific. Three layers enforce the contract: - render_blessed(test, topic) emits only the topic's sections - check_one rejects a stray section (e.g. a token dump in tests/types/) as a hard error, not tolerated bloat — re-bless to strip it - ck_cktest unit tests pin each topic's emitted set Re-blessed the suite: 13,921 lines of token/CST bloat deleted across 174 fixtures. Extracted topic_section_issues to keep check_one under the R4 LOC cap. Ratchet unaffected (stripping sections doesn't change diagnostic counts).Add the construction surface to the type checker. New owned-HIR nodes ExprKind::Record { ty, fields } and ExprKind::With { base, value }, lowered from the existing RecordExpr/WithExpr CST via new ck_syntax accessors, typed in the new ck_types::construct module: - record literal completeness (E0716, one event per missing field) + value typing (E0702 reused); - with-override `r with { f: v }` (anonymous-record check-only brace); - with-projection `Q {} with src` (value- and anon-source), E0717 for a source field the target requires; - field-read E0718, now actually emitted (was reserved-but-silent). Code reconciliation: the TY6 draft predated L1 claiming E0713/E0714/E0715, so the draft's "E0715 unknown field" is unified with the read case into one E0718, and the draft's "E0705 empty-list" is already E0713. E0716/E0717/ E0726 land as drafted. Record-field defaults deferred (parser doesn't accept them yet). Registry + TY6 spec reconciled; goldens added, error ones # trap-covered to hold the untrapped-diagnostics ratchet at 112.