diff --git a/docs/DESIGN.md b/docs/DESIGN.md index ce8a52c..8f049a9 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -883,21 +883,46 @@ extension (e.g. linear ownership) or be rejected at design time. ### Schema additions -**Iter 18a — mode wrappers on `Type`.** +**Iter 18a — parameter modes on `Type::Fn`.** + +The form-A surface for fn signatures gains mode wrappers: ``` -Type::Borrow(Box) ; `(borrow T)` in form-A -Type::Own(Box) ; `(own T)` in form-A +(fn-type (params (borrow (List Int))) (ret (con Int))) +(fn-type (params (own (List Int))) (ret (own (List Int)))) ``` -Both are transparent for unification (they erase to their inner -`Type` for HM purposes) but carry binding mode metadata for the -RC pipeline. Skipped during JSON serialisation when absent so -canonical hashes of every pre-18a fixture stay bit-identical. +Internally, this is *not* a new `Type` variant. Modes are +metadata on `Type::Fn`: + +```rust +Type::Fn { + params: Vec, + param_modes: Vec, // same length as params + ret: Box, + ret_mode: ParamMode, + effects: Vec, +} + +enum ParamMode { Implicit, Own, Borrow } // default: Implicit +``` + +`Implicit` is the legacy (pre-18a) state — semantically +equivalent to `Own` but printed bare (`(con T)`, no wrapper). +`Own` and `Borrow` are explicitly annotated. The implementation +keeps `Type` itself unchanged, so unification, occurs, apply, +and ~190 other `Type` match-arms in the typechecker need no new +branch. + +JSON canonical hash for every pre-18a fixture stays bit- +identical: `param_modes` is skipped when every entry is +`Implicit`, `ret_mode` is skipped when `Implicit`. Existing +modules emit the same bytes as before. + The legacy `(con T)` form is treated as `(own T)` semantically throughout the 18-series; a later iter (deferred) makes the -explicit annotation mandatory and rejects bare `(con T)` for -boxed parameter types. +explicit annotation mandatory and rejects `Implicit` for boxed +parameter types. **Iter 18c/18d — new `Term` variants.**