on master help sign in
397 files changed+7621−1254
since splitsnapshots
unifiedsplit
docs/README.md+3 docs/compiler.md+9−3 docs/development.md+2 docs/open-questions.md+2−2 docs/prompts/milestone-2-finish.md+3−2 docs/prompts/repo-review-finish.md+149 docs/prompts/syntax-review-follow-up.md+80 docs/reviews/2026-11-02-syntax-review.md+14 docs/reviews/2026-11-03-checker-map.md+587 docs/spec/core-language.md+10−9 docs/spec/decisions.md+11−8 docs/spec/grammar.md+47−30 docs/spec/overview.md+8−8 docs/status.md+10−2 jibb-dev/lib/jibb.hoon+892−244 jibb-dev/lib/jibb/prelude.jibb+183−190 my-app/ui/basket.jibb+5−5 my-app/ui/stores/cart.jibb+2−2 my-app/ui/todo-list.jibb+8−8 tests/golden/doc-core-02-update/about.txt+1−1 tests/golden/doc-core-02-update/source.jibb+8−8 tests/golden/doc-core-02-update/tokens.txt+120−122 tests/golden/doc-core-02-update/tree.txt+64−64 tests/golden/doc-grammar-02-buttons/types.txt+1−1 tests/golden/doc-grammar-04-step/about.txt+1−1 tests/golden/doc-grammar-04-step/source.jibb+5−5 tests/golden/doc-grammar-04-step/tokens.txt+36−37 tests/golden/doc-grammar-04-step/tree.txt+13−13 tests/golden/doc-grammar-06-cart-store/about.txt+1−1 tests/golden/doc-grammar-06-cart-store/tokens.txt+27−28 tests/golden/doc-grammar-06-cart-store/tree.txt+11−11 tests/golden/doc-grammar-07-basket/about.txt+1−1 tests/golden/doc-grammar-07-basket/tokens.txt+71−72 tests/golden/doc-grammar-07-basket/tree.txt+33−33 tests/golden/doc-overview-10-todo-list/about.txt+1−1 tests/golden/doc-overview-10-todo-list/tokens.txt+118−120 tests/golden/doc-overview-10-todo-list/tree.txt+64−64 tests/golden/inline-cell-wing-face-bad/about.txt+3 tests/golden/inline-cell-wing-face-bad/source.jibb+1 tests/golden/inline-cell-wing-face-bad/tokens.txt+8 tests/golden/inline-cell-wing-face-bad/tree.txt+3 tests/golden/inline-change-wing/about.txt+3 tests/golden/inline-change-wing/source.jibb+2 tests/golden/inline-change-wing/tokens.txt+18 tests/golden/inline-change-wing/tree.txt+9 tests/golden/inline-decimal-sites/types.txt+1−1 tests/golden/inline-decimal/about.txt+1−1 tests/golden/inline-unface-arity-bad/about.txt+4 tests/golden/inline-unface-arity-bad/modules.txt+1 tests/golden/inline-unface-arity-bad/source.jibb+3 tests/golden/inline-unface-arity-bad/tokens.txt+31 tests/golden/inline-unface-arity-bad/tree.txt+13 tests/golden/inline-unface-arity-bad/types.txt+10 tests/golden/inline-unface-deep/about.txt+4 tests/golden/inline-unface-deep/modules.txt+1 tests/golden/inline-unface-deep/source.jibb+10 tests/golden/inline-unface-deep/tokens.txt+129 tests/golden/inline-unface-deep/tree.txt+55 tests/golden/inline-unface-deep/types.txt+11 tests/golden/inline-unface-gates/about.txt+4 tests/golden/inline-unface-gates/modules.txt+1 tests/golden/inline-unface-gates/source.jibb+11 tests/golden/inline-unface-gates/tokens.txt+160 tests/golden/inline-unface-gates/tree.txt+78 tests/golden/inline-unface-gates/types.txt+30 tests/golden/inline-unface-import/about.txt+4 tests/golden/inline-unface-import/module-trees.txt+43 tests/golden/inline-unface-import/modules.txt+1 tests/golden/inline-unface-import/modules/ui/lib.jibb+9 tests/golden/inline-unface-import/source.jibb+5 tests/golden/inline-unface-import/tokens.txt+38 tests/golden/inline-unface-import/tree.txt+17 tests/golden/inline-unface-import/types.txt+5 tests/golden/inline-unface-labelled-slot/about.txt+4 tests/golden/inline-unface-labelled-slot/modules.txt+1 tests/golden/inline-unface-labelled-slot/source.jibb+5 tests/golden/inline-unface-labelled-slot/tokens.txt+76 tests/golden/inline-unface-labelled-slot/tree.txt+37 tests/golden/inline-unface-labelled-slot/types.txt+12 tests/golden/inline-unface-lambda/about.txt+4 tests/golden/inline-unface-lambda/modules.txt+1 tests/golden/inline-unface-lambda/source.jibb+3 tests/golden/inline-unface-lambda/tokens.txt+52 tests/golden/inline-unface-lambda/tree.txt+28 tests/golden/inline-unface-lambda/types.txt+10 tests/golden/inline-unface-named-union/about.txt+4 tests/golden/inline-unface-named-union/modules.txt+1 tests/golden/inline-unface-named-union/source.jibb+9 tests/golden/inline-unface-named-union/tokens.txt+89 tests/golden/inline-unface-named-union/tree.txt+46 tests/golden/inline-unface-named-union/types.txt+8 tests/golden/inline-unface-records/about.txt+4 tests/golden/inline-unface-records/modules.txt+1 tests/golden/inline-unface-records/source.jibb+8 tests/golden/inline-unface-records/tokens.txt+94 tests/golden/inline-unface-records/tree.txt+44 tests/golden/inline-unface-records/types.txt+21 tests/golden/inline-unface-recursive/about.txt+4 tests/golden/inline-unface-recursive/modules.txt+1 tests/golden/inline-unface-recursive/source.jibb+23 tests/golden/inline-unface-recursive/tokens.txt+182 tests/golden/inline-unface-recursive/tree.txt+98 tests/golden/inline-unface-recursive/types.txt+6 tests/golden/inline-unface-reserved-import/about.txt+4 tests/golden/inline-unface-reserved-import/module-trees.txt+6 tests/golden/inline-unface-reserved-import/modules.txt+1 tests/golden/inline-unface-reserved-import/modules/ui/lib.jibb+1 tests/golden/inline-unface-reserved-import/source.jibb+2 tests/golden/inline-unface-reserved-import/tokens.txt+11 tests/golden/inline-unface-reserved-import/tree.txt+3 tests/golden/inline-unface-reserved-import/types.txt+2 tests/golden/inline-unface-reserved-local/about.txt+4 tests/golden/inline-unface-reserved-local/modules.txt+1 tests/golden/inline-unface-reserved-local/source.jibb+3 tests/golden/inline-unface-reserved-local/tokens.txt+14 tests/golden/inline-unface-reserved-local/tree.txt+8 tests/golden/inline-unface-reserved-local/types.txt+2 tests/golden/inline-unface-reserved-mold/about.txt+4 tests/golden/inline-unface-reserved-mold/modules.txt+1 tests/golden/inline-unface-reserved-mold/source.jibb+2 tests/golden/inline-unface-reserved-mold/tokens.txt+8 tests/golden/inline-unface-reserved-mold/tree.txt+3 tests/golden/inline-unface-reserved-mold/types.txt+2 tests/golden/inline-unface-reserved-no-prelude/about.txt+4 tests/golden/inline-unface-reserved-no-prelude/source.jibb+2 tests/golden/inline-unface-reserved-no-prelude/tokens.txt+8 tests/golden/inline-unface-reserved-no-prelude/tree.txt+3 tests/golden/inline-unface-reserved-no-prelude/types.txt+1 tests/golden/inline-unface-reserved-pattern/about.txt+4 tests/golden/inline-unface-reserved-pattern/modules.txt+1 tests/golden/inline-unface-reserved-pattern/source.jibb+3 tests/golden/inline-unface-reserved-pattern/tokens.txt+21 tests/golden/inline-unface-reserved-pattern/tree.txt+11 tests/golden/inline-unface-reserved-pattern/types.txt+2 tests/golden/inline-unface-reserved-positive/about.txt+4 tests/golden/inline-unface-reserved-positive/modules.txt+1 tests/golden/inline-unface-reserved-positive/source.jibb+6 tests/golden/inline-unface-reserved-positive/tokens.txt+36 tests/golden/inline-unface-reserved-positive/tree.txt+15 tests/golden/inline-unface-reserved-positive/types.txt+5 tests/golden/inline-unface-reserved-sample/about.txt+4 tests/golden/inline-unface-reserved-sample/modules.txt+1 tests/golden/inline-unface-reserved-sample/source.jibb+1 tests/golden/inline-unface-reserved-sample/tokens.txt+13 tests/golden/inline-unface-reserved-sample/tree.txt+7 tests/golden/inline-unface-reserved-sample/types.txt+2 tests/golden/inline-unface-reserved-value/about.txt+4 tests/golden/inline-unface-reserved-value/modules.txt+1 tests/golden/inline-unface-reserved-value/source.jibb+2 tests/golden/inline-unface-reserved-value/tokens.txt+12 tests/golden/inline-unface-reserved-value/tree.txt+6 tests/golden/inline-unface-reserved-value/types.txt+2 tests/golden/inline-unface-unknown/about.txt+4 tests/golden/inline-unface-unknown/modules.txt+1 tests/golden/inline-unface-unknown/source.jibb+3 tests/golden/inline-unface-unknown/tokens.txt+36 tests/golden/inline-unface-unknown/tree.txt+18 tests/golden/inline-unface-unknown/types.txt+4 tests/golden/inline-unface-value-bad/about.txt+4 tests/golden/inline-unface-value-bad/modules.txt+1 tests/golden/inline-unface-value-bad/source.jibb+6 tests/golden/inline-unface-value-bad/tokens.txt+75 tests/golden/inline-unface-value-bad/tree.txt+37 tests/golden/inline-unface-value-bad/types.txt+13 tests/golden/lex-body-rest-bad-1/about.txt+3 tests/golden/lex-body-rest-bad-1/source.jibb+4 tests/golden/lex-body-rest-bad-1/tokens.txt+26 tests/golden/lex-body-rest-bad-1/tree.txt+3 tests/golden/lex-body-rest-bad-10/about.txt+3 tests/golden/lex-body-rest-bad-10/source.jibb+5 tests/golden/lex-body-rest-bad-10/tokens.txt+21 tests/golden/lex-body-rest-bad-10/tree.txt+3 tests/golden/lex-body-rest-bad-11/about.txt+3 tests/golden/lex-body-rest-bad-11/source.jibb+4 tests/golden/lex-body-rest-bad-11/tokens.txt+18 tests/golden/lex-body-rest-bad-11/tree.txt+3 tests/golden/lex-body-rest-bad-12/about.txt+3 tests/golden/lex-body-rest-bad-12/source.jibb+5 tests/golden/lex-body-rest-bad-12/tokens.txt+21 tests/golden/lex-body-rest-bad-12/tree.txt+3 tests/golden/lex-body-rest-bad-13/about.txt+3 tests/golden/lex-body-rest-bad-13/source.jibb+5 tests/golden/lex-body-rest-bad-13/tokens.txt+20 tests/golden/lex-body-rest-bad-13/tree.txt+3 tests/golden/lex-body-rest-bad-14/about.txt+3 tests/golden/lex-body-rest-bad-14/source.jibb+5 tests/golden/lex-body-rest-bad-14/tokens.txt+20 tests/golden/lex-body-rest-bad-14/tree.txt+3 tests/golden/lex-body-rest-bad-15/about.txt+3 tests/golden/lex-body-rest-bad-15/source.jibb+5 tests/golden/lex-body-rest-bad-15/tokens.txt+3 tests/golden/lex-body-rest-bad-15/tree.txt+3 tests/golden/lex-body-rest-bad-16/about.txt+3 tests/golden/lex-body-rest-bad-16/source.jibb+3 tests/golden/lex-body-rest-bad-16/tokens.txt+15 tests/golden/lex-body-rest-bad-16/tree.txt+3 tests/golden/lex-body-rest-bad-2/about.txt+3 tests/golden/lex-body-rest-bad-2/source.jibb+5 tests/golden/lex-body-rest-bad-2/tokens.txt+27 tests/golden/lex-body-rest-bad-2/tree.txt+3 tests/golden/lex-body-rest-bad-3/about.txt+3 tests/golden/lex-body-rest-bad-3/source.jibb+4 tests/golden/lex-body-rest-bad-3/tokens.txt+19 tests/golden/lex-body-rest-bad-3/tree.txt+3 tests/golden/lex-body-rest-bad-4/about.txt+3 tests/golden/lex-body-rest-bad-4/source.jibb+5 tests/golden/lex-body-rest-bad-4/tokens.txt+21 tests/golden/lex-body-rest-bad-4/tree.txt+3 tests/golden/lex-body-rest-bad-5/about.txt+3 tests/golden/lex-body-rest-bad-5/source.jibb+5 tests/golden/lex-body-rest-bad-5/tokens.txt+20 tests/golden/lex-body-rest-bad-5/tree.txt+3 tests/golden/lex-body-rest-bad-6/about.txt+3 tests/golden/lex-body-rest-bad-6/source.jibb+4 tests/golden/lex-body-rest-bad-6/tokens.txt+16 tests/golden/lex-body-rest-bad-6/tree.txt+3 tests/golden/lex-body-rest-bad-7/about.txt+3 tests/golden/lex-body-rest-bad-7/source.jibb+5 tests/golden/lex-body-rest-bad-7/tokens.txt+22 tests/golden/lex-body-rest-bad-7/tree.txt+3 tests/golden/lex-body-rest-bad-8/about.txt+3 tests/golden/lex-body-rest-bad-8/source.jibb+4 tests/golden/lex-body-rest-bad-8/tokens.txt+16 tests/golden/lex-body-rest-bad-8/tree.txt+3 tests/golden/lex-body-rest-bad-9/about.txt+3 tests/golden/lex-body-rest-bad-9/source.jibb+2 tests/golden/lex-body-rest-bad-9/tokens.txt+7 tests/golden/lex-body-rest-bad-9/tree.txt+3 tests/golden/lex-body-rest-ok-1/about.txt+4 tests/golden/lex-body-rest-ok-1/module-trees.txt+4 tests/golden/lex-body-rest-ok-1/modules.txt+1 tests/golden/lex-body-rest-ok-1/modules/ui/lib.jibb+1 tests/golden/lex-body-rest-ok-1/source.jibb+11 tests/golden/lex-body-rest-ok-1/tokens.txt+62 tests/golden/lex-body-rest-ok-1/tree.txt+30 tests/golden/lex-body-rest-ok-1/types.txt+4 tests/golden/lex-body-rest-ok-2/about.txt+4 tests/golden/lex-body-rest-ok-2/module-trees.txt+4 tests/golden/lex-body-rest-ok-2/modules.txt+1 tests/golden/lex-body-rest-ok-2/modules/ui/lib.jibb+1 tests/golden/lex-body-rest-ok-2/source.jibb+12 tests/golden/lex-body-rest-ok-2/tokens.txt+67 tests/golden/lex-body-rest-ok-2/tree.txt+36 tests/golden/lex-body-rest-ok-2/types.txt+4 tests/golden/lex-body-rest-ok-3/about.txt+3 tests/golden/lex-body-rest-ok-3/source.jibb+6 tests/golden/lex-body-rest-ok-3/tokens.txt+35 tests/golden/lex-body-rest-ok-3/tree.txt+18 tests/golden/lex-body-rest-ok-4/about.txt+4 tests/golden/lex-body-rest-ok-4/source.jibb+13 tests/golden/lex-body-rest-ok-4/tokens.txt+46 tests/golden/lex-body-rest-ok-4/tree.txt+23 tests/golden/lex-body-rest-ok-4/types.txt+4 tests/golden/lex-body-rest-ok-5/about.txt+3 tests/golden/lex-body-rest-ok-5/source.jibb+7 tests/golden/lex-body-rest-ok-5/tokens.txt+25 tests/golden/lex-body-rest-ok-5/tree.txt+15 tests/golden/lex-body-rest-ok-6/about.txt+3 tests/golden/lex-body-rest-ok-6/source.jibb+7 tests/golden/lex-body-rest-ok-6/tokens.txt+35 tests/golden/lex-body-rest-ok-6/tree.txt+18 tests/golden/lex-body-rest-ok-7/about.txt+4 tests/golden/lex-body-rest-ok-7/module-trees.txt+4 tests/golden/lex-body-rest-ok-7/modules.txt+1 tests/golden/lex-body-rest-ok-7/modules/ui/lib.jibb+1 tests/golden/lex-body-rest-ok-7/source.jibb+10 tests/golden/lex-body-rest-ok-7/tokens.txt+51 tests/golden/lex-body-rest-ok-7/tree.txt+26 tests/golden/lex-body-rest-ok-7/types.txt+3 tests/golden/lex-body-rest-ok-8/about.txt+4 tests/golden/lex-body-rest-ok-8/module-trees.txt+4 tests/golden/lex-body-rest-ok-8/modules.txt+1 tests/golden/lex-body-rest-ok-8/modules/ui/lib.jibb+1 tests/golden/lex-body-rest-ok-8/source.jibb+14 tests/golden/lex-body-rest-ok-8/tokens.txt+63 tests/golden/lex-body-rest-ok-8/tree.txt+32 tests/golden/lex-body-rest-ok-8/types.txt+3 tests/golden/lex-layout-bad-4/about.txt+1−1 tests/golden/lex-layout-bad-4/tree.txt+1−1 tests/golden/lex-name-bad-5/tokens.txt+4−3 tests/golden/lex-name-bad-5/tree.txt+1−1 tests/golden/lex-rune-layout-bad-3/about.txt−3 tests/golden/lex-rune-layout-bad-3/tree.txt−3 tests/golden/lex-rune-layout-ok-3/about.txt+3 tests/golden/lex-rune-layout-bad-3/source.jibb → tests/golden/lex-rune-layout-ok-3/source.jibb tests/golden/lex-rune-layout-bad-3/tokens.txt → tests/golden/lex-rune-layout-ok-3/tokens.txt tests/golden/lex-rune-layout-ok-3/tree.txt+6 tests/golden/lex-tight-change-bad-10/about.txt+3 tests/golden/lex-tight-change-bad-10/source.jibb+1 tests/golden/lex-tight-change-bad-10/tokens.txt+7 tests/golden/lex-tight-change-bad-10/tree.txt+3 tests/golden/lex-tight-change-bad-11/about.txt+3 tests/golden/lex-tight-change-bad-11/source.jibb+2 tests/golden/lex-tight-change-bad-11/tokens.txt+9 tests/golden/lex-tight-change-bad-11/tree.txt+3 tests/golden/lex-tight-change-bad-5/about.txt+3−3 tests/golden/lex-tight-change-bad-5/source.jibb+1−1 tests/golden/lex-tight-change-bad-5/tokens.txt+1−2 tests/golden/lex-tight-change-bad-5/tree.txt+3−3 tests/golden/lex-tight-change-ok-2/about.txt+3 tests/golden/lex-tight-change-ok-2/source.jibb+7 tests/golden/lex-tight-change-ok-2/tokens.txt+55 tests/golden/lex-tight-change-ok-2/tree.txt+20 tests/golden/lex-typevar-bad-1/about.txt+3 tests/golden/lex-typevar-bad-1/source.jibb+1 tests/golden/lex-typevar-bad-1/tokens.txt+3 tests/golden/lex-typevar-bad-1/tree.txt+3 tests/golden/lex-typevar-bad-2/about.txt+3 tests/golden/lex-typevar-bad-2/source.jibb+1 tests/golden/lex-typevar-bad-2/tokens.txt+3 tests/golden/lex-typevar-bad-2/tree.txt+3 tests/golden/lex-typevar-bad-3/about.txt+3 tests/golden/lex-typevar-bad-3/source.jibb+1 tests/golden/lex-typevar-bad-3/tokens.txt+3 tests/golden/lex-typevar-bad-3/tree.txt+3 tests/golden/lex-typevar-bad-4/about.txt+3 tests/golden/lex-typevar-bad-4/source.jibb+1 tests/golden/lex-typevar-bad-4/tokens.txt+3 tests/golden/lex-typevar-bad-4/tree.txt+3 tests/golden/lex-typevar-ok-1/about.txt+4 tests/golden/lex-typevar-ok-1/source.jibb+3 tests/golden/lex-typevar-ok-1/tokens.txt+39 tests/golden/lex-typevar-ok-1/tree.txt+15 tests/golden/lex-typevar-ok-1/types.txt+4 tests/golden/module-import-api-scope-conflict/types.txt+7−1 tests/golden/module-import-prelude-value-shadow/types.txt+7−1 tests/golden/prelude-unit-list-transforms/types.txt+1−1 tests/golden/types-change-overlap-lines/about.txt+4 tests/golden/types-change-overlap-lines/modules.txt+1 tests/golden/types-change-overlap-lines/source.jibb+7 tests/golden/types-change-overlap-lines/tokens.txt+49 tests/golden/types-change-overlap-lines/tree.txt+18 tests/golden/types-change-overlap-lines/types.txt+8 tests/golden/types-change-overlap/about.txt+4 tests/golden/types-change-overlap/modules.txt+1 tests/golden/types-change-overlap/source.jibb+4 tests/golden/types-change-overlap/tokens.txt+57 tests/golden/types-change-overlap/tree.txt+22 tests/golden/types-change-overlap/types.txt+8 tests/golden/types-change-repeated-wing/about.txt+4 tests/golden/types-change-repeated-wing/modules.txt+1 tests/golden/types-change-repeated-wing/source.jibb+3 tests/golden/types-change-repeated-wing/tokens.txt+41 tests/golden/types-change-repeated-wing/tree.txt+16 tests/golden/types-change-repeated-wing/types.txt+8 tests/golden/types-change-repeated/about.txt+4 tests/golden/types-change-repeated/modules.txt+1 tests/golden/types-change-repeated/source.jibb+2 tests/golden/types-change-repeated/tokens.txt+39 tests/golden/types-change-repeated/tree.txt+15 tests/golden/types-change-repeated/types.txt+8 tests/golden/types-change-wing/about.txt+4 tests/golden/types-change-wing/modules.txt+1 tests/golden/types-change-wing/source.jibb+24 tests/golden/types-change-wing/tokens.txt+289 tests/golden/types-change-wing/tree.txt+111 tests/golden/types-change-wing/types.txt+46 tests/golden/types-constructor-context/types.txt+2−2 tests/golden/types-generic-union-alias-face/types.txt+1−1 tests/golden/types-generic-union-alias/types.txt+1−1 tests/golden/types-generic-union-local/types.txt+1−1 tests/golden/types-prelude-generic-alias/types.txt+1−1 tests/golden/types-prelude-lead-late/types.txt+1−1 tests/golden/types-prelude-list-functions/types.txt+1−1 tests/golden/types-prelude-ui/types.txt+21−21 tests/golden/types-proj-explicit-context/types.txt+2−2 tests/golden/types-proj-nested-no-implicit/types.txt+3−3 tests/golden/types-proj-reserved-imported-definition/types.txt+4−1 tests/golden/types-record-change-generic/about.txt+1−1 tests/golden/types-record-change-generic/source.jibb−1 tests/golden/types-record-change-generic/tokens.txt+35−59 tests/golden/types-record-change-generic/tree.txt+15−24 tests/golden/types-record-change-generic/types.txt−1 tests/golden/types-recursion-scc-groups/types.txt+1−1 tests/golden/types-typevar-names/about.txt+4 tests/golden/types-typevar-names/modules.txt+1 tests/golden/types-typevar-names/source.jibb+14 tests/golden/types-typevar-names/tokens.txt+162 tests/golden/types-typevar-names/tree.txt+67 tests/golden/types-typevar-names/types.txt+27 tests/golden/types-typevar-print/about.txt+4 tests/golden/types-typevar-print/source.jibb+11 tests/golden/types-typevar-print/tokens.txt+108 tests/golden/types-typevar-print/tree.txt+43 tests/golden/types-typevar-print/types.txt+10 tests/lib/jibb-doc-examples.hoon+1−1 tests/lib/jibb-full-diagnostics.hoon+45 tests/lib/jibb-full-scope.hoon+37 tests/lib/jibb-page-main.hoon+2 tests/lib/jibb-store.hoon+4−1 tests/type-buttons/expected.txt+1−1 tests/type-deferred-context/report.txt+1−1 tests/type-deferred-resolver/expected.txt+2−2 tests/type-direct-gate/expected.txt+2−2 tests/type-page-main/hand-built-load.txt+2−2 tools/check+1 tools/doc-fragments+61
docs/README.md+3
@@ -14,11 +14,14 @@ The current full-module checker also has a narrow static/data-page slice, docume
1414| [prelude-inventory.md](prelude-inventory.md) | Working source audit for the prelude's exported inventory |
1515| [prompts/milestone-2.md](prompts/milestone-2.md) | A brief for the developer who builds milestone 2, types and prelude |
1616| [prompts/drop-union-rune.md](prompts/drop-union-rune.md) | The completed brief for dropping `$?`, as decided on 2026-10-30, before milestone 2 |
17+| [prompts/syntax-review-follow-up.md](prompts/syntax-review-follow-up.md) | A brief for finishing the syntax changes Montelot decided on 2026-11-03: open gaps, unfinished reviews, work that waits on the checker core, and questions to ask |
1718| [reviews/2026-11-02-repo-review.md](reviews/2026-11-02-repo-review.md) | A review of the whole repository on 2026-11-02: bugs, gaps and simplifications, each checked by a second reviewer |
1819| [reviews/2026-11-02-questions.md](reviews/2026-11-02-questions.md) | The 45 decisions that review raises, with options and recommendations |
1920| [reviews/2026-11-02-syntax-review.md](reviews/2026-11-02-syntax-review.md) | A review of Jibb's syntax on 2026-11-02: 15 verified proposals with before and after examples, what to keep, and questions for @iko |
2021| [reviews/2026-11-03-milestone-2-review.md](reviews/2026-11-03-milestone-2-review.md) | A review of milestone 2 against the plan on 2026-11-03: the done-criteria, the errors the spec describes, findings M1 to M17, with its [probes](reviews/2026-11-03-milestone-2-probes/) |
2122| [prompts/milestone-2-finish.md](prompts/milestone-2-finish.md) | A brief for finishing milestone 2: the general checker core, diagnostics, patterns, kinds, imports, tests and docs that the milestone 2 review found missing |
23+| [prompts/repo-review-finish.md](prompts/repo-review-finish.md) | A brief for finishing the 2026-11-02 repository review: the open findings no other brief covers, the rulings waiting for @iko, and the review's advice for the checker core |
24+| [reviews/2026-11-03-checker-map.md](reviews/2026-11-03-checker-map.md) | A map of the type checker on 2026-11-03 for whoever builds the general core: its families, recovery slices, hazards, and what the core replaces and keeps |
2225
2326## The spec
2427
docs/compiler.md+9−3
@@ -74,18 +74,22 @@ A single-arm cell pattern can bind two or more positions, with its last binder c
7474
7575String interpolation infers its pieces in order and preserves substitutions and pending constraints. A piece with a known atom aura, unrestricted `@`, or a tape `(list @tD)` is accepted; an isolated decimal literal takes its normal `@ud` default. A known cell reports that it needs a printer, and an explicitly generic atom asks for an aura at its use site. Loobeans, term singletons, non-tape collections, open types and a type fixed only later remain unsupported in this fragment.
7676
77+A bare decimal is a `@ud` (S4): its variable binds only `@ud` or `@u`, and it fits `@` and `*`. A `++` generic over the decimal's aura generalizes it to an atom variable, so there it takes any aura. When a fit fails, `+decimal-misfit` refits with each decimal widened to any aura, so that a generic gate's capital learns its aura from the other arguments, then walks the value's syntax beside the expected type through groups, faces, tuples, term-headed pairs, the union case a head tag picks, units and lists. The first decimal at an atom of another aura gets an error naming it and the expected aura's literal, as "`30` is a @ud, not a @dr; write ~s30"; otherwise the site's own error stands. Casts, call arguments, change fields, list items and tails, unit payloads, branch joins and contextual branch arms use it, and a `?-` over a known union or an atom checks its number patterns against the subject's type the same way.
78+
7779The Hoon bridge translates imported `(unit T)` to the canonical public `unit` union when the prepared template validates as the standard mold. Without that template it retains the older opaque collection behavior. Conversion recurses through imported unions and collection arguments, and API path/diff/poke analysis uses the same prepared reader. The fixtures prove identity, `fall`, `need`, casts, union- and list-nested `need`, canonical unit-typed API full/diff marks, and a canonical direct-poke export while leaving no-prelude output unchanged.
7880
7981The Hoon bridge translates imported `*` as the any-noun type, directly or within supported nonrecursive cells. The reader may still decline a disjoint tagged union with a noun payload, and recursive imports containing `*` remain unsupported. It accepts an exact fork of the two loobean singletons as `?`, and each singleton separately as `%.y` or `%.n`, including inside supported faced cells. Contextual loobean literals specialize against a matching singleton by noun, including a proven singleton in a direct union; named loobean singletons do not silently widen to a distinct aura. Open `%f`, other values, and other forks containing loobean singletons remain unsupported; recursive Hoon molds containing flags can also fail closed.
8082
8183A bare tag that provably matches no case of a known union reports the union and tag sites. This covers casts, single-argument calls, contextual unit payloads, list items and supported branch arms, including unnamed imported unions. For syntactic tuples, ordered fit replay can identify a missing tag in a nested position; an earlier mismatch or uncertainty stops the replay instead of guessing. Existing tags whose shape or payload does not fit retain the ordinary mismatch; unresolved tags stay pending.
8284
83−A change can replace uniquely named fields on a fully known, faced record spine, including through a nested wing. Replacements receive the field type as context, substitutions and pending constraints are retained, and the resulting type remains the original record. Missing fields, empty changes and definite replacement mismatches report sites; the expected-type site is the edit, since the original field declaration location is not retained. Unknown or partly unfaced spines, ambiguous fields and repeated edits remain unsupported. A cast to a known record also supplies field context to a tuple or record initializer, including nested list and union fields. The expected-type site is the cast mold; the original field declaration location is not retained. Isolated cart-style `init` and `update` expressions infer in this fragment. The complete cart-store source fails closed because store kind and declaration scope are not yet checked.
85+A change can replace uniquely named fields on a fully known, faced record spine, including through a nested wing. An item named by a wing, as `m(open.cart=x)`, reads its field through such spines, outermost first. Replacements receive the field type as context, substitutions and pending constraints are retained, and the resulting type remains the original record. Missing fields, empty changes and definite replacement mismatches report sites; the expected-type site is the edit, since the original field declaration location is not retained. A missing field in an item's wing is reported at that name, and a wing through a field that is surely no record, such as a list, an atom or a unit, at the field it goes through. Unknown or partly unfaced spines, wings through tuples and type variables, and ambiguous fields remain unsupported. Two items that set the same field, or one a field inside the other's, are a module error at both items, as a repeated record field is. A cast to a known record also supplies field context to a tuple or record initializer, including nested list and union fields. The expected-type site is the cast mold; the original field declaration location is not retained. Isolated cart-style `init` and `update` expressions infer in this fragment. The complete cart-store source fails closed because store kind and declaration scope are not yet checked.
8486
8587Nested labels of the three public re-exports are normalized recursively to `ask`, `qath` and `raw-poke`, so prepared records and instantiated types do not expose their private `.internal` suffixes. Other private names remain private.
8688
8789For supported closed unions, the type printer keeps the union’s origin separate from its displayed name. It prints an in-scope name such as `msg` or `msg.lib`, including in records and gates; an accessible imported nongeneric alias may name a transitive union. A nongeneric body-local union that escapes its scope, or an origin without an accessible name, prints its cases separated by spaces, parenthesized when nested. That case-list form is print-only. A supported generic union prints its name and all arguments, including unused arguments; when its name is unavailable, the partial printer reports that limitation instead of dropping its arguments. Two faces for the same imported origin remain compatible; compatibility between distinct union origins, including in gate types, remains unsupported. Some comparisons of generic union arguments also remain unsupported rather than deciding equality or mismatch. The Hoon bridge also translates some imported unnamed unions into this representation; unsupported cases remain errors.
8890
91+The type printer shows a type variable by the name it was written with. A variable's ID holds that name above a 64-bit count (`+named-var`), so the name travels through substitution, generalization and instantiation, and `+ienv-fresh-id` counts without it. When a definition is generalized, `+cap-names` names each quantified variable after a capital written in the definition that resolves to it, or else after the earliest made of the named variables joined with it; a call note does the same without the capitals. `+canonical-itype` keeps the names and numbers the other variables as the letters (`+show-var`) that no name in the same type spells.
92+
8993Multi-argument calls form one right-nested sample: `f a b c` supplies `[a [b c]]`, with the last argument able to be a cell itself. The fragment fits the complete sample, preserving known faces and shared variables. Known sample positions can provide list or union context to arguments; unknown sample shapes use ordinary inference and some contextual forms remain unsupported. For a definite mismatch, the diagnostic points to a specific argument when it can establish which one failed; otherwise it reports the combined sample.
9094
9195A list literal can be inferred when a cast or known gate sample supplies a list type and the supplied prelude has the validated standard list definition. Empty, nonempty and nested literals work, including contextual union tags in elements; mismatched elements report the item and expected type. Imported Hoon lists share this representation. Under the same known context, `~` and zero-valued term literals fit an empty list, and a two-item unfaced cell `[head tail]` is a cons; cons cells and list literals can be nested. Mismatched heads or tails report both sites. A known list result also supplies context through complete loobean, unit-shaped and list-shaped branches, including recursive and nested branches. Known loobean result context can propagate through supported complete branches and binder-only cell arms, with a final directional fit; a binder-only arm over a union subject remains unsupported. A known gate with an unresolved result variable can also receive an enclosing result type before its argument is inferred, for example allowing `^- (list @t) (id ~)`; unknown callees and unresolved targets retain the conservative path. A known gate sample supplies context to corresponding positions of a single tuple or record argument, including nested cells; a zero literal can therefore fit a list position. A bound zero constant still remains unsupported rather than a definite mismatch, and an unknown callee does not supply context. Uncontextualized list literals also infer with a fresh element variable, including empty and nested lists; the resulting variable can generalize. Unresolved item tags and uncertain widening remain unsupported. Faced or longer cons cells, and a missing or altered prelude list remain unsupported. For a known standard list with a supported element type, it also infers a complete two-arm branch using `~` and `[item rest]`, in either order. The binders have the element and list types and cannot shadow or duplicate names. Unknown subjects, unsupported element types, other patterns and incomplete arms remain unsupported.
@@ -128,7 +132,7 @@ For a unique supported declaration, `+api-request-parts` retains that evidence w
128132
129133`+api-support-analysis-source` additionally infers supported ordinary API molds and values, resolves every declared mark, and retains their source, dependency and path evidence. Unsupported helpers or marks fail closed. An unused `/-` core is not independently validated, ordinary definitions that need derived gates remain unsupported, and this result is not a checked API interface or an exported request.
130134
131−The ordinary import resolver can infer derived request-gate types for multiple supported API paths. A case may take one typed path parameter before its reply gate, or one diff fold after the reply; a case with both, multiple parameters or diffs, or a separate scry path remains unsupported. Each reply maps the full mark type to a fresh `M` and the request result is `(ask M)`. Checked ordinary API values and molds, declared mark molds and a supported generic poke command helper are exported too. Every selected `/sur` core must have a directly used, successfully read mold; unselected core bindings are not independently validated, and Jibb module imports remain unsupported in this API fragment. An API module outside the fragment fails with the reason its check gave: without `+$ paths`, the poke-only check's, such as `API poke mark %todo-action has no reader result`; otherwise its request constructor's, such as `request paths need unsupported inference`. A failing Jibb import reports its own error, as it does for other modules. A derived `poke` or request name that clashes with a definition, an import face, a prelude value or another derived name is a definite error showing where the name is derived and what it clashes with; `+api-path-analysis-source` and the path evidence entries report it the same way. Only names that surely exist are checked: `poke` when the module declares `+$ poke`, and the case names of a `+$ paths` that reads as path cases. Two cases with the same name do not read as path cases, so that clash stays unsupported, as does a case named `proj`, a reserved name. A name conflict among an API's imports and ordinary definitions reports `module has conflicting names`, as in other modules; a `/%` mark names a mold, so it conflicts only with another mark or mold, and a mark beside a value of the same name, such as a request, is not a conflict. The unchanged todo API fits this fragment.
135+The ordinary import resolver can infer derived request-gate types for multiple supported API paths. A case may take one typed path parameter before its reply gate, or one diff fold after the reply; a case with both, multiple parameters or diffs, or a separate scry path remains unsupported. Each reply maps the full mark type to a fresh `M` and the request result is `(ask M)`. Checked ordinary API values and molds, declared mark molds and a supported generic poke command helper are exported too. Every selected `/sur` core must have a directly used, successfully read mold; unselected core bindings are not independently validated, and Jibb module imports remain unsupported in this API fragment. An API module outside the fragment fails with the reason its check gave: without `+$ paths`, the poke-only check's, such as `API poke mark %todo-action has no reader result`; otherwise its request constructor's, such as `request paths need unsupported inference`. A failing Jibb import reports its own error, as it does for other modules. A derived `poke` or request name that clashes with a definition, an import face, a prelude value or another derived name is a definite error showing where the name is derived and what it clashes with; `+api-path-analysis-source` and the path evidence entries report it the same way. Only names that surely exist are checked: `poke` when the module declares `+$ poke`, and the case names of a `+$ paths` that reads as path cases. Two cases with the same name do not read as path cases, so that clash stays unsupported, as does a case named `proj` or `unface`, a reserved name. A name conflict among an API's imports and ordinary definitions reports `module has conflicting names`, as in other modules; a `/%` mark names a mold, so it conflicts only with another mark or mold, and a mark beside a value of the same name, such as a request, is not a conflict. The unchanged todo API fits this fragment.
132136
133137A call whose direct result is a known named generic union can receive a matching same-origin, same-arity result context before its arguments are inferred. This retains the ordered generic arguments and existing capital checks; pending tags, recursive or variable-bound origins and unrestricted atom cases remain conservative. Constructor fitting reports unsupported when an unresolved or opaque case could contain the requested tagged head. It keeps definite missing-case errors for proven nonmatching cases, including an explicitly atom-only faced head. The real todo callback `|=%got` can infer when an `(ask msg)` result context fixes its message union; the uncontextualized call remains unsupported.
134138
@@ -183,7 +187,9 @@ The internal prelude defines transparent `(ask M)` cases for pure, agent and sto
183187
184188Public identity aliases of private generic unions retain their public name when the origin, arity and argument order match exactly, including through imported values. Fixed, reordered, repeated and phantom generic aliases remain unsupported where a safe public name cannot be recovered; a fixed nongeneric alias is not printed as though it accepted type arguments.
185189
186−The partial checker reserves `proj` in module, local, sample, pattern and import bindings, including bindings inside unsupported source; a field, tag or path segment may still have that spelling. With a known expected record type, it checks selected explicit `(proj record)` calls over closed, uniquely faced records, preserving the source expression, its type, the result type and field axes in the checked interface. Imported and private-prelude dependencies retain the source needed to lower those plans. The checker does not yet lower or execute them. It supports selecting one or more fields in their original order; a single selected field keeps its face and uses one source axis. Reordered fields, unknown or open record spines, some nested contexts and recursive groups with projections remain unsupported. A directional fit of a wider faced record fails closed instead of inserting a projection, including within supported list, unit and record positions. To limit repeated work, record-spine proofs are reused along the same closed spine and stop at 1,024 fields; field boundaries and the special handling of positional calls reset the appropriate proof. Prepared interfaces and their source remain trusted host inputs.
190+The partial checker reserves `proj` and `unface`, one set checked by `+reserved-name`, in module, local, sample, pattern and import bindings, including bindings inside unsupported source; a field, tag or path segment may still have that spelling. With a known expected record type, it checks selected explicit `(proj record)` calls over closed, uniquely faced records, preserving the source expression, its type, the result type and field axes in the checked interface. Imported and private-prelude dependencies retain the source needed to lower those plans. The checker does not yet lower or execute them. It supports selecting one or more fields in their original order; a single selected field keeps its face and uses one source axis. Reordered fields, unknown or open record spines, some nested contexts and recursive groups with projections remain unsupported. A directional fit of a wider faced record fails closed instead of inserting a projection, including within supported list, unit and record positions. To limit repeated work, record-spine proofs are reused along the same closed spine and stop at 1,024 fields; field boundaries and the special handling of positional calls reset the appropriate proof. Prepared interfaces and their source remain trusted host inputs.
191+
192+An explicit `(unface e)` has e's type with every face removed (`+itype-unface`): through cells, a gate's sample and product, collection arguments and the prelude unit's payload, whose own `u=` stays. Other unions and recursive molds go by name or exact cases, so they are kept whole, and an unbound variable stays, keeping any faces it is bound to later. When e's type is still a bare variable the checker reports `unface on a type not yet known is not supported by partial inference`, as it does field access; the deferred transaction declines `unface`. `unface` written as a value, or with other than one argument, is a definite error. A `++` whose body is `(unface |= …)` counts as a gate for self-recursion, recursive groups and the report, with the unfaced type, while direct-call layout evidence, which reads sample faces, leaves it out. Nothing is lowered yet; the core language's row lowers it to its argument.
187193
188194## The tree
189195
docs/development.md+2
@@ -88,6 +88,8 @@ Each file in `tests/lib` is a suite: a core of `test-` arms, with the libraries
8888
8989A golden-report suite has a `report` arm and a golden file bound to the face `expected`; its test arm compares the report with that file, and `tools/test-arms --list` marks it `, report`. `tools/test-arms --report <suite>` prints the report, and `tools/test-arms --update <suite>` writes it to the file; with no suite named, `--update` writes every golden-report suite's. When such a suite's arm fails, `tools/test-arms` prints a unified diff between the file and the report. `jibb-buttons` and `jibb-deferred-prepared` have golden files too, but compare them inside helpers over several cases and have no `report` arm. Every golden file, a `/*` `%txt` file bound to a face containing `expected`, must end in exactly one newline (a suite compares `wain`s, which can't show a missing one) and hold no line that starts `BAD ` or ends `: BAD`; `tools/test-arms` checks that before any eval, and `--update` won't write a report that breaks it.
9090
91+`tools/doc-fragments` guards the examples checked in a larger context: the Core language's `update` must match the todo island's definition, and the valid buttons fixture must match the Grammar's buttons block with `add-button` removed. It runs as part of `tools/check` alongside `tools/doc-blocks`.
92+
9193The `jibb-dev` desk holds `my-app`'s `ui/`, `sur/` and `mar/` under `/my-app` (review question 31), so the suites that check `my-app` files bind them there, as `/* sur %txt /my-app/sur/todo/hoon`, and keep no copies. A mark's `/-` line is Ford's, which `ride` can't parse, so the suites that ride a mark drop it with their `+mark-text` arm. Where the table below calls a `my-app` file byte-identical or unchanged, the suite reads that file itself. Files that only the importer's tests need are kept off `my-app` (review question 34): the Clay fixtures' `/sur` with a Ford import, their mark and the real Tlon notes `/sur` are in `tests/clay-fixtures/desk/`, which the `jibb-fixtures` desk adds to `my-app` and the `jibb-dev` desk leaves out, and the golden cases and `tests/type-poke/mark.txt` that use the mark link to `tests/clay-fixtures/desk/mar/label.hoon`.
9294
9395| Suite | What it checks | Golden files |
docs/open-questions.md+2−2
@@ -50,14 +50,14 @@ In milestone 1 the parser met about thirty places where the doc could be read mo
5050| 1 | `knot` may be empty, so the EBNF admits `//`, `/a//b` and a trailing `/`. Which are paths? | A segment has at least one character, as in Hoon. `/` alone is the empty path, in expressions and molds; `%/` alone is the root application path. `//` fails at the second `/`, and a trailing `/` just past it. `inline-mold-paths` has `/` alone as a mold |
5151| 2 | Is `/` alone a valid path for a `/=` import? | No: `/=` names a module's file, so its path has a segment. `/= card /` fails just past the `/` (`inline-import-root-bad`) |
5252| 3 | The EBNF's `line = [ name "=" ] expr` lets every open bracket's lines take `name=`. What would it mean on a line of an open `(` or `~[`? | An error: `name=` lines belong to tuples and changes. "expected a space between items, found `=`; `name=value` goes in a cell, as [a=1], or a change, as m(a=1)" |
53−| 4 | Does "items named" make every item of a change need `name=`? | Yes: `m(x)` fails just past `x`, "a change's items are named, as in m(done=%.y)" (`lex-tight-change-bad-3` to `-7`; `-8` and `-9` test what follows a name there). The parser still accepts `m()`, though question 6 settled it as an error |
53+| 4 | Does "items named" make every item of a change need `name=`? | Settled on 2026-11-03 (syntax review S6): yes, `name=value` or `wing=value`, as `m(open.cart=x)`. `m(x)` still fails just past `x`, "a change's items are named, as in m(done=%.y)" (`lex-tight-change-bad-3` to `-7`, where `-5` is a wing with no `=`; `-8` and `-9` test what follows a name there) |
5454| 5 | `term` includes `%0`, `%&` and `%\|`, which no mark is called. What does `/%` take? | `%` and a name only: `/% %0` is "expected a mark's term, as `%todo-action`, found `%0`" |
5555| 6 | What does an indented first line mean? | An error: "the first line is indented: top-level lines start at column 1" (`lex-indent-bad-3`) |
5656| 7 | With levels open at columns 1 and 5, what does a line at column 3 mean? | An error naming the open columns: "this line's indentation matches no enclosing line: indent it to column 1 or 5". `lex-indent-bad-2`, with levels at 1, 5 and 7, gives "column 1, 5 or 7" |
5757| 8 | Tabs, carriage returns, other control characters, and non-ASCII text outside strings and comments? | Errors everywhere, strings and comments included, except that UTF-8 is allowed in strings and comments; a tab in a string is written `\09`. `lex-indent-bad-1` and `lex-spacing-bad-2` test tabs |
5858| 9 | Must a file be valid UTF-8? | Not checked yet: any byte from 128 up passes in strings and comments, and columns assume UTF-8. The proposed reading makes a byte that can't continue a UTF-8 sequence an error. An escape such as `\ff` still writes any byte, as in Hoon |
5959| 10 | Inside `{…}`, may `::` start a comment, which would swallow the `}` and the `"`? Is a lone `}` in a string text? May a comment follow code with no space, as in `5::note`? | A `:` inside `{…}` is "a comment can't start inside `{…}`". A lone `}` is text, as in Hoon. `5::note` is `5` and a comment |
60−| 11 | Is a type variable exactly one capital letter, as `typevar = upper` says? | Yes: `Msg` is "a type variable is one capital letter" |
60+| 11 | Is a type variable exactly one capital letter, as `typevar = upper` says? | Settled on 2026-11-03 (syntax review S7): no, a capital then lowercase letters and digits, as `Msg`; `AB` is an error |
6161| 12 | Hoon has more runes of the left-out kinds than the list names: `?~ ?= ?. ?@ ?^`, `:- :+ :^ :_`, `%- %+ %^ %~`, `=+ =? =.`, `;:` and `~&(…)`. Are they all left out? | Yes, with the list's reasons, as "`:-` is left out: indentation covers it; write a cell as [a b]". Naming them in the doc, or saying "Hoon's other runes", would make the messages the doc's words (`inline-leftout-*`) |
6262| 13 | `@s…` and `@r…` auras are "errors wherever used". Is that the parser's error in Jibb source, or the checker's? | An error before the checker. Where a mold goes, the layout pass's, at the `s` or `r`: "signed and floating-point auras are left out of Jibb". Where an expression goes, the parser's, at the `@`: "expected an expression, found `@`; signed and floating-point auras are left out of Jibb". Imported ones are milestone 2's importer's. The case `inline-leftout-signed-float-auras` still says "expect: unclear" |
6363
docs/prompts/milestone-2-finish.md+3−2
@@ -13,7 +13,7 @@ You are finishing milestone 2 of Jibb, a UI language for Urbit: a Hoon dialect w
13133. [docs/spec/implementation-plan.md](../spec/implementation-plan.md), milestone 2, and the spec tabs it points at, closely Grammar's Tag resolution, Literals by context, Patterns, Modules and Imports.
14144. [docs/reviews/2026-11-02-questions.md](../reviews/2026-11-02-questions.md): the owner's answers, marked *(chosen)*. Q5 and Q6 set the direction below. Q16 to Q28 are proposals waiting for @iko, not spec.
15155. [docs/development.md](../development.md): setting up (`nix develop`), the tools, the test suites, and the checks before pushing (`tools/check` or `nix flake check`).
16−6. `git log origin/master`: @iko works in `jibb.hoon` in parallel, and another thread is implementing syntax-review proposals S1, S2, S4 to S7, S11 to S13 and S15 ([syntax review](../reviews/2026-11-02-syntax-review.md)). Rebase often and keep your changes out of theirs where you can.
16+6. `git log origin/master`: @iko works in `jibb.hoon` in parallel, and another thread is implementing syntax-review proposals S1, S2, S4 to S7, S11 to S13 and S15 ([syntax review](../reviews/2026-11-02-syntax-review.md)). Rebase often and keep your changes out of theirs where you can. The thread that fixes the 2026-11-02 review's findings planned this same core on 2026-11-03, in stages that keep every check green; ask in the project chat who is building it before you start step 2.
1717
1818## Ground rules
1919
@@ -32,12 +32,13 @@ The full checker, `infer-jibb-file-detailed`, drops every per-definition reason
3232
3333### 2. The general checker core (Q5)
3434
35−The owner chose this on 2026-11-02: union-find bindings with levels, a queue of deferred constraints, and a usefulness check for matches, built before more recovery paths. It is a long piece of work, so first write its design as a new section of the library's design notes, and share it in the project chat for @iko before replacing code.
35+The owner chose this on 2026-11-02: union-find bindings with levels, a queue of deferred constraints, and a usefulness check for matches, built before more recovery paths. It is a long piece of work, so first write its design as a new section of the library's design notes, and share it in the project chat for @iko before replacing code. Start from [the checker map](../reviews/2026-11-03-checker-map.md), which says what each part of today's checker does, which tests pin it, what the core replaces and keeps, and the hazards; [repo-review-finish.md](repo-review-finish.md) step 6 has the review's advice for staging it.
3636
3737- **Unification**: union-find over type variables, with levels for generalization instead of environment scans; an occurs check; aura variables and the "is an atom" and "contains no gates" constraints carried on the variable, as `0858191` already does for gate-freedom.
3838- **Deferred constraints**: tags, `~`, numbers and cells, wing access, changes and `?-` on a type not yet known each wait in one queue, retried as variables are bound, as the Grammar's Tag resolution says. A tag-constrained variable does not generalize and stays open until something in the module fixes it. At the end of the module, each still-open constraint is an error at its source: "nothing fixes the union of %add; add a `^-`".
3939- **Order**: infer `++`s by the strongly connected components `839f6b0` already computes, a group of mutually recursive gates together; reject a non-gate value that depends on itself, naming the cycle.
4040- **Kinds by type**: check `main` as an ordinary expression. `(program init update view subs)`, `(page load view)` and `(store init update)` are calls whose unification fixes their components' types, messages included, so a tag in `view` is resolved by `main`. Then read the kind from `main`'s type, as the Grammar says, and run each kind's own checks after inference: gate-free island data and models, naming the field; for islands, a walk of the `(list (sub M))` that asks for a watchability proof only for `%watch`; for pages, a load that is any gate to `(ask D)`, `pure` and typed paths included.
41+- **Rulings it must build in**, chosen by Montelot on 2026-11-03 from the syntax review: a capital that meets a faced position binds only the type under the face, never the face, so `[A A]` fits `[x=@ y=@]`, `(hunt lt-a `1 `2)` checks, and `(roll ~[1 2] 0 add-f)` checks with `++ add-f |= [a=@ud b=@ud] (add a b)`; a join keeps a face once a position takes one, so reordering a list's items never changes whether it checks; and, as the syntax thread lands them, the explicit `unface` (S1), bare decimals fitting only `@ud`, `@u`, `@` and `*` (S4), and a bare-name pattern that spells a union tag being an error (S5). Take their final wording from `decisions.md`, and add each ruling's examples as golden cases in the stage that builds it.
4142- **Then delete** the program, page and store recovery chain, the deferred transactions, the prepared-tuple route and the other example-shaped slices as the core covers their tests (the earlier review counts about 1,180 lines of program recovery alone).
4243
4344When this is done, M2 to M5 are gone: every valid variant in the review's [probe corpus](../reviews/2026-11-03-milestone-2-probes/) checks, and each error in an island is reported where it is, as `button "Add" %submitt` giving "msg has no case `%submitt`" at the tag, with the union's site.
docs/prompts/repo-review-finish.mdnew file+149
@@ -0,0 +1,149 @@
1+# Finishing the 2026-11-02 repository review
2+
3+A brief for the developer who finishes what the [2026-11-02 repository review](../reviews/2026-11-02-repo-review.md) started. Paste it as the first message of a session, or hand it to a person; it assumes the repo `iko-soy/jibb`. Written 2026-11-03, at commit `e208bcb`, by the thread that fixed the review's findings, from a check of every question and finding against `master` that day.
4+
5+---
6+
7+You are finishing the follow-up to a review of the whole Jibb repository. Jibb is a UI language for Urbit, a Hoon dialect with an indentation layout; its compiler is a Hoon library, `jibb-dev/lib/jibb.hoon`, with a Hoon type importer in `jibb-dev/lib/jibb-import.hoon`. The review, at commit `4bf477e`, found 137 problems (A1 to A137) and raised 45 questions, which Montelot, the project's owner, answered: each answer is marked *(chosen)* in [the questions](../reviews/2026-11-02-questions.md). Most answers have landed. What is left is small fixes, simplifications and docs that no other brief covers, twelve language rulings and one more question (A62) that wait for @iko, and the review's advice for the checker core, which milestone-2-finish.md builds.
8+
9+Three briefs share the remaining work. Don't do one brief's work under another:
10+
11+- **[milestone-2-finish.md](milestone-2-finish.md)** owns the general checker core (review question 5), the diagnostics the full checker still drops (its step 1), the usefulness check for `?-`, one types pipeline (question 6), kinds, APIs, the import table, tests and speed. Its import table step lists two known gaps from this review, A14 and A50; they are fixed here, in step 1 and under question 26.
12+- **[syntax-review-follow-up.md](syntax-review-follow-up.md)** owns the syntax changes S1 to S15, including `unface` and the gaps in S2, S4 to S7.
13+- **This brief** owns the rest of the repository review: the open findings below, the rulings for @iko, and the review's input to the core.
14+
15+## What landed
16+
17+| Questions | What | Commits |
18+| --- | --- | --- |
19+| 1 to 4 | The review on `master`, fixes as commits straight to `master`, a fake ship in cloud containers | `c7cd17d`, `f583172` |
20+| 7 to 15 and the eight "fix first" bugs | Ordinary inference before recovery, the narrow initializer recovery deleted, imported `(unit T)` as the prelude's unit, `ask` and `qath` printed without `.internal`, one branch-join rule, dependency-order resolution, kept diagnostics, no 26-variable gate, a fresh-ID high-water mark, lexer, `tools/ship` and `tools/golden` fixes | `a211c34`, `38c711c` and `ec7c6d4` (@iko), `93d6b23`, `839f6b0`, `f0411ad`, `ce69a3b`, `447a592`, `2b9666c`, `96d1784`, `c0a0b85`, `941c486`, `452f64c`, `68d9b76` |
21+| 25 | `eq` and the gate-free constraint | `0858191` (@iko) |
22+| 29 to 35 | `tools/test-arms` instead of 52 scripts, `tools/check`, `my-app` read on the test desk, the generated `tests/lib/jibb.hoon` no longer committed, importer fixtures in their suite, a `jibb-fixtures` desk, span and Hoon-reference checks as test arms | `d74b5e2`, `0a86d7c`, `8125287`, `ba67080`, `933bc83`, `d43c99b`, `32f4b78` |
23+| 30 (CI) | A GitHub Actions job ran the eval checks; Montelot had it removed on 2026-11-03. There is no CI; don't add one back without asking | `84b8527`, `f84a29e` |
24+| 36, 37, 39, 43 | Decided to keep things as they are | `bf65f8f` |
25+| 40 to 42, 44, 45 | `tools/hoon --no-debug`, `status.md` as a capability table, the repository spec wins until synced, `open-questions.md` only open questions, the MIT licence | `cdf53c8`, `e97aebe`, `7bc7d54`, `116178b` |
26+
27+## Read first
28+
29+1. [The review](../reviews/2026-11-02-repo-review.md): its summary, and the appendix rows for the findings below. Its line numbers are pinned to `4bf477e` and have drifted; find code by arm name.
30+2. [The questions](../reviews/2026-11-02-questions.md), and in [open-questions.md](../open-questions.md) the section "Review rulings waiting for @iko".
31+3. The two other briefs, so you know what they own.
32+4. [The checker map](../reviews/2026-11-03-checker-map.md), before you touch the type checker: what each family of arms does, which tests pin it, the 22 recovery slices, the five copies of definition finalization, and 22 hazards for anyone changing the checker.
33+5. [development.md](../development.md): setting up (`nix develop`), the tools, the test suites, and the checks to run before pushing (`tools/check`, or `nix flake check`).
34+6. `git log origin/master`. @iko and other threads work in `jibb.hoon` in parallel; rebase often.
35+
36+Then run `tools/check`. Every check should pass before you change anything.
37+
38+## Ground rules
39+
40+- **Push straight to `master`**, rebased on `origin/master`, in commits that each leave every check passing, the ship group included. Never force-push. Before a change to `tools/ship`, the desks or the `%jibb` mark, run the ship checks on a fake ship.
41+- **Every fix is a golden case or a test arm.** A finding that changes behaviour gets a case that fails before the fix.
42+- **Don't decide the language.** Questions 16 to 24 and 26 to 28 are Montelot's proposals, and each waits for @iko to confirm it before it goes in `decisions.md` and the code changes. Ask @iko in the project chat; don't build them on the proposal alone.
43+- **Don't patch what the core replaces.** The findings listed at the end of step 6 are fixed by building the core, not by repairing the old code. Before you change `+itype-unify`, `+itype-fit`, branch joins, `?-` coverage, the program, page and store recovery, or the `dg-*` transaction, ask in the project chat who is building the core and what has landed.
44+- **Keep docs current.** `status.md` is a table of capabilities: change the row a fix affects, don't add history. `compiler.md` follows the code.
45+
46+## Step 1: fixes that don't wait for anything
47+
48+A19 and the inhabitation half of A13 touch `+itype-fit-inner` and `+itype-inhabited-proof`, which the core replaces, so follow the ground rule: ask in the project chat first, and leave them to the core if it has replaced that code. A13's `+gate-free-type` half and A14's bridge are code the core keeps (the checker map, 4.2), so they don't wait.
49+
50+Checker and importer:
51+
52+- **A19.** `+width-scan` counts each faced entry on a spine, so a flat faced tuple has more entries than a record whose last field is a faced nested record. The flat tuple is then refused, as unknown by the `too-wide` guard in `+itype-fit-inner`, and as "record width constraint needs unsupported inference" by `+width-shape` in the cast and call checks. When the target's last field is a faced cell, match the source against it structurally instead of by count, and check the `lth` guards in `+width-proj-shape` and `+width-infer-literal` with the same case.
53+- **A13.** `+itype-inhabited-proof` and `+gate-free-type` know only the list and unit collections. Treat set, map, qeu, mop, jar and jug as inhabited by `~`, and check gate-freedom over all their arguments. Add a union match on a case that holds an imported map.
54+- **A14.** One whitelist of auras, `?(%u %ud %ux %uv %t %ta %tas %p %da %dr)`, is copied in `+rec-pattern`, `+import-to-itype-standard` and the API parameter check, and rejects bare `@` and other unsigned auras. Write one predicate for `@` and every unsigned, non-float aura and use it at all three; teach `+rec-pattern` `*` and `?` fields. Add bridge cases. Milestone-2-finish step 7 lists this gap for its import test; fix it here, and that test then covers it.
55+- **A56.** The importer's `+overlap-source-witness` proves a definite overlap only for a top-level `$?` of tagged cells. Accept `$%` bodies and `?(...)` leaves, so duplicate `$%` tags and `?(%a %a)` give the definite overlap, with cases in `tests/importer/tree.txt`.
56+- **A43.** Without a prelude the partial report says a bare "module has a reserved proj or unface name", with no "partial inference; module not checked" header, while the prepared path says "module has conflicting names". Give both paths one message under the header: the prepared path's, or, if milestone-2-finish step 1 has given `proj` its own wording by then, that wording. `inline-unface-reserved-no-prelude` already covers the no-prelude branch for a mold named `unface`; add a case for `++ proj 1`, and update that case's output.
57+- **A22.** The comment on the noun fit says a bare tag is "fixed as a constant", but the code binds it to the expected type. Fix the comment.
58+
59+Lexer and parser:
60+
61+- **A4.** `+read-string` calls `+doomed` for "the `}` of an interpolation", a case that never happens. Delete the call, fall through to `+bad`, and drop the clause from the notes and `+doomed`'s comment.
62+- **A5.** In the lexer's glyph dispatch, the second-character messages ("`|` begins `|=`…", "`^` begins `^-`") win over the 2.2 character errors, so a tab or control character after a glyph gets the wrong message, and only some left-out runes get the doc's reason. Run `+bad-char` first and give every left-out rune of the doc's kinds its reason. The syntax review's S9 (undecided) would rewrite nearby messages; keep to the review's fix.
63+- **A3, what is left.** About a dozen lexer hints have no golden case, among them "this `}` closes no `{`", "`|` begins …", "`^` begins `^-`", a comment inside `{…}`, interpolation outside a string, a wing's `.`, the `@u` and `@t` literal errors, the date bounds, "Jibb writes no such literal" and "Jibb can't read this literal". Several parser hints have none either, as "`+` begins `++` or `+$`", "patterns take no units: write [~ x]", "`?` alone is the loobean mold" and "the wide gate's body is one operand". Add a `lex-*-bad-*` case for each lexical one and an `inline-*` case for each parser one.
64+
65+## Step 2: tools and tests
66+
67+- **A68.** `tools/golden` splices `jibb-import.hoon` into the "(harness)" segment, so its compile errors and crash frames are blamed on the harness. Add the reader as its own segment, so spots map to `jibb-import.hoon` lines.
68+- **A69.** `tools/ship test`, `sync` and `gen-tests` accept a `--golden` folder that doesn't exist and pass with no tests. Fail when the folder is missing or a named folder has no cases, as `tools/golden` does.
69+- **A70, A84.** `tools/testdata/ship-selftest` hard-codes 45 `tests/lib` names, which miss 14 of the 58 suites, and dozens of fixture names in the checks after them. Replace them with one check: every file under `tests/` except `golden/` and `clay-fixtures/desk/` is in `assemble('jibb-dev')`, and so is the generated `tests/lib/jibb.hoon`. Keep the `--lib` and `--golden` isolation checks. That list is the last place a new suite must be registered by hand, so this also closes A84.
70+- **A74.** An `about.txt` that isn't UTF-8 crashes `tools/golden` and `tools/ship gen-tests` with a traceback, because `wants_types` in `tools/golden_case.py` is called outside the `except ValueError` handlers. Have it raise a `ValueError` that names the file, as `source_path` does, and move its calls inside the handlers: in `Case.__init__` in `tools/golden`, and in `generate_tests`' per-case loop and types-helper test in `tools/ship`. Both then exit 2 with a report.
71+- **A75.** `tools/golden` fills the harness's `{…}` placeholders after splicing in the cases' sources, the reader and the preludes, so any of them that contains a placeholder is rewritten. Substitute every placeholder in one pass.
72+- **A76.** The ship's plain `+check-types` isn't under `mule`, unlike `+check-import-types` and its other siblings, so a crash in it shows only as CRASHED, without the case's tokens and tree results or the label its siblings give. Wrap it. The eval and ship runners also keep separate copies of their Hoon helpers and their walk over a case's metadata; share them.
73+- **A72, A77, A73, A79.** Smaller tool copies: `tools/golden` renders the two preludes twice and repeats its read-to-`rap` code three times; `tools/ship` keeps its own `KNOT`/`TERM`, noun decoding and cord escaping beside `golden_case.py`, `noun.py` and `urbit_eval.py`; `delete_batches` keeps an empty-list case only a selftest uses; `tools/ship`'s `find_urbit` ignores `$URBIT`.
74+- **A71.** `check_fixture_crash_isolated` in `tools/testdata/selftest` runs the real compiler and pins checker output, though the file says the selftest runs against the stub. Give it a stub fixture, or say so.
75+- **Test-only code in the shipped library (A93, A127).** Move `+itype-unify-test` and `+check-spans-test` from `jibb.hoon` into the `jibb-typecheck` and `jibb-check-spans` suites, and have `test-unification` return the unifier's failures as its tang, so the one-line `tests/checker/unification.txt` can go (A85).
76+- **A86.** 38 suites repeat a lines-to-cord helper. Put one in a shared test library bound with `/+`.
77+- **A87, A88.** `development.md`'s golden naming table lists only `lex-`, `inline-` and `doc-`; add `types-`, `module-`, `prelude-`, `parser-` and `fixture-`, fix the ten `about.txt` files that lack a required line, and have `tools/golden` or the selftest reject them. Say in the suites section which `tests/type-*` folder belongs to which suite, or rename the folders after their suites.
78+- **A89.** The importer's fixtures are bound one by one in `tests/lib/jibb-import.hoon`; bind them as one list and derive the report and the missing-file checks from it. `tools/clay-fixtures` prints hand-written counts, "7 passed" and "4 projections passed"; compute them from the expected files.
79+- **A90, A102.** Nothing tests the claims that 100,000 nested brackets and a 20,000-line module parse. Add a suite or selftest step that generates them; milestone-2-finish step 9 then records the timings. Then re-measure design note 3's figures with `tools/hoon --no-debug` and say which mode they use: its "8 s" for starting urbit and building the library is now about 27 s.
80+- **A114.** The Clay fixture `tests/clay-fixtures/desk/sur/import-fixture.hoon` writes `$^(@ud [a=@ud b=@t])`, which accepts only atom-headed cells. Write the intended `$@(@ud [a=@ud b=@t])` and update the `ford-nested-union` expected files.
81+- **A111, A117.** `tools/ship`'s `DESKS` skips a `jibb-dev/tests` folder that doesn't exist, for `my-app` and `jibb-fixtures`; drop the skip and the README's "without tests/", and make the README's desk table match `DESKS`: add the `jibb-fixtures` row, and on `jibb-dev` name `my-app` under `/my-app` and the skipped `tests/clay-fixtures/desk`. Make `tools/ship assemble` fail when `my-app/sys.kelvin` and `jibb/sys.kelvin` differ.
82+- **A118.** `vendor/SOURCES.txt` records the machine-local path `/root/src/urbit` it was copied from, and credits the docket files to urbit/urbit's legacy `pkg/landscape`. Drop the local path, and say where the docket files are maintained now.
83+- **A110.** The Clay fixtures build `my-app`'s marks only as Hoon cores. Add a `%cb` build and a `vale` of one sample noun for each, with milestone-2-finish step 8's `my-app` ship check if that lands first.
84+
85+## Step 3: simplifications in code the core keeps
86+
87+Most are in the parser, the importer, and the module and API code, which the core keeps. A few are dead lines in checker arms that the core replaces, as the fuel of `+itype-closed-sample-match` and the last unify of `+itype-closed-gates-match`; deleting them changes nothing, so they don't wait for the core. Each must leave every golden output unchanged.
88+
89+- **Dead code (A26, A31, A42, A44, A130, A18, part of A45).** Delete `+width-has-projections`, `+infer-width-elaboration` and its type `+$ iwidth-elaboration`, `+direct-find-gate`, `+resolve-supported-defs`, the newly dead `+import-to-itypes`, `+one-request-interface-source` and `+golden-types-with-modules` (and its sentence in `compiler.md`), and the orphan comments above unrelated arms. Drop the narrow API branch, `+one-request-interface-graph`, so every API with `+$ paths` goes through `+multi-request-interface-graph`, after checking that `blog.jibb`'s interface and the `type-api` outputs don't change. Remove the never-decremented fuel of `+itype-closed-sample-match`, the always-true unify at the end of `+itype-closed-gates-match`, `+width-scan`'s unused `sub`, and two dead lines in `+find-imported-mold-prelude`. Of A45, fix only what is outside the recovery and `dg-*` arms: the double negation and the `?~ index` branch in the module driver, and the fake `ifile`s in the store code.
90+- **The `?(` check (A7).** `+hoon-union` walks back over tokens at twelve call sites to report a tight `?(`. Have the lexer's `?` branch report it, with the same column and message, and delete `+hoon-union`.
91+- **Names that shadow the standard library (A8).** Rename `+in`, move the `+fail*` helpers into `+parser` so `file` is in scope, and delete the `file` forwarders and the sixteen `in:..zuse` workarounds. Then drop the Code conventions bullet in `development.md` that says `+in` and `+fail` shadow the standard library, and move the `+fail*` helpers from the `%parser-helpers` row of `compiler.md`'s chapter table to the `%parser` row.
92+- **Copies in the parser (A9).** The path-segment loops of `+read-pathlit`, `+read-qath` and `+read-pathmold`, the open-mold-line loops, and the item and line name branches are near copies. Merge them where the result is clearly simpler; the review found some merges are not.
93+- **`%gate` and `%gate-wide` (A34, A123).** The two nodes carry the same fields, and 39 lines in the checker chapters test both or repeat an identical body for each (A34). Make one `%gate` node with a `wide=?` flag that only the printers read. That merges the checker's copies too and changes note 3's tree forms, but no golden output. Ask first if the core is being built; if its builder wants the old node kept for now, use `?(%gate %gate-wide)` in the parser, the printers and the syntax walkers only, and leave A34 to the core.
94+- **Syntax walkers (A32, A129).** The `scope-*`, `dependency-*`, `duplicate-*`, `*-has-hole` and reserved-name walker families each repeat the per-node dispatch. Add one enumeration of an expression's children and a fold, and rewrite these families on it. The type walkers (A21, A35) wait for the core.
95+- **API and module copies (A27, A29, A31).** `+request-graph-merge` should reuse `+request-graph-inputs-match` and `+request-graph-bounded`, drop its fuel arguments, and make the bound agree with its comment. `+prepare-prelude` and `+prepare-prelude-with-internal`, and `+module-mold-types` and its `-detail` form, should each share one core. `+api-path-evidence-source` and `+api-support-analysis-source` should call their `-graph` forms.
96+- **Importer copies (A57, A58, A59).** A provenance-error helper for the repeated preamble, `+local-arm-source` in `+tagged-union-fallback`, one list of standard collections, one unwrap gate parameterised by the wrapper's tag, one case lister for `$%` and `$?` with the budget as a parameter. A59, a reader that walks once for both the plain and diagnostic results, is low priority.
97+- **Budgets (A124).** The checker's literal budgets (256, 64, 4,096 and others) are scattered. Name the ones in code the core keeps in one arm; the `dg-*` ones go with the core.
98+
99+## Step 4: docs
100+
101+- **The library's header and `compiler.md` (A2, A60, A101, A131).** `jibb.hoon`'s first line says milestone 1, and its API list lacks `infer-jibb-file`, `infer-jibb-file-detailed` and the `golden-types-with-*` entry points. Its API list also lacks `+layout-error`, `+golden-types-imports`, `+prepare-prelude` and `+prepare-prelude-with-internal`, which hosts and `tools/golden` call. Add them all, make `compiler.md`'s API table list the same arms, fix its `%api` row, and add `%union-analysis` to its chapter table with an accurate `%type-inference` row; that chapter also holds the module checker, the API code and the recovery, so say so or split it. The header also still says the doc wins, where question 42 made the copy in `docs/spec/` win, and its Status paragraph calls the checker a partial inference fragment; fix both, as `development.md` words the first, and fix `compiler.md`'s first paragraph, which says "as milestone 1 left it". Milestone-2-finish step 10 rewrites these again for the core; this fix is for the code as it is now.
102+- **Design notes 2.6, 3 and 4.2 (A2).** They don't mention the `_` type hole (its token, where a mold may be `_`, its tree form) or the `?(` hint ("a union is a `+$` with its cases below"). Add them, writing the hint where A7 leaves the check: once the lexer reports it, in note 2.6's table of left-out forms, beside `$?` and `$%`.
103+- **The recovery chain (A41).** Neither `compiler.md` nor `status.md` mentions the plain-view recovery, `+program-plain-view-context`, which runs only when the keyed-view proof declines. Add it to `compiler.md`'s recovery paragraph and to `status.md`'s component-local recovery row, or leave it if the core has deleted it by then.
104+- **The importer's header (A53).** It opens with `+read-mold`, which only tests use; the callers use `+read-named` and `+read-mark` and their `-diagnostic` forms. Rewrite the header's API paragraph around them, and fix the two `jibb.hoon` comments that name `+read-mold`.
105+- **The prelude docs (A54, A105, A63, A99).** `prelude-inventory.md` lists the nine 3g shapes as future work though all exist, and its 2a rows contradict the paragraph above them. `decisions.md`'s Core language row still says three rules in its tab are proposed, but `core-language.md` marks none, and the review found each decided in its own row; drop the clause and set the row's Synced column to No, and ask @iko only about a rule that has no decided row. `internal.jibb` should say in a comment that the compiler adds the public prelude's validated list and unit to `core`, to avoid an import cycle, and `tuba-text` should take `values=(list @tD)`.
106+- **Question 38 (A112).** Montelot chose to keep `my-app`'s deliberately failing buttons example and the theme's static font, and to list them as a milestone 4 question. Add it to `open-questions.md` under "Questions milestone 2 raises", or in the plan's table with "review question 38" in the row, so the table doesn't credit the plan with it.
107+- **A106.** A paragraph about the tools sits under `development.md`'s ground rules, and `docs/README.md` carries status prose. Move the first into "The test suites". Delete the second, after adding to a `status.md` row anything it says that no row does.
108+- **A103, what is left.** `open-questions.md` still lists grammar questions 4 and 11, which the syntax review settled (S6, S7). `decisions.md`'s Syntax and Type variables rows already record the answers, so delete the two rows, keep the other rows' numbers, and update the page's "as of" date.
109+- **A115, A116.** `my-app/mar/todo-action.hoon` says it is "not supplied by the design doc", but it is the overview's `todo-action` block; fix the line. Say in the README's desk table that `my-app`'s `desk.bill` is `~` until fixture agents arrive. List the missing `%todo` and `%blog` fixture agents, and a page that embeds the basket, as gaps in `status.md` for milestones 5 and 6, and ask @iko before adding them to `implementation-plan.md`, which is @iko's tab.
110+
111+## Step 5: the rulings, when @iko confirms them
112+
113+Ask @iko about each in the project chat, with the proposal from `open-questions.md`. When one is confirmed, record it in `decisions.md`, move it out of `open-questions.md`, then change the code with golden cases. Until then, change nothing.
114+
115+| Question | Proposal | Then |
116+| --- | --- | --- |
117+| 16, 17 (A20) | A term literal fits its own aura family, `%1.000` a `@ud` and `%&` a `?`; a name term also fits `@t` | Change the two term-literal branches of `+itype-fit-inner`, the `%atom` row of `+tag-presence`, and the sentence in `grammar.md`'s Tag resolution that lists `@tas`, `@ta`, `@` and `*`; the syntax review's S4 already did this for bare decimals |
118+| 18 (A23) | A gate may fit `*` | No code change; say in `core-language.md` that `*` may hold gates |
119+| 19 (A6, A100) | `[]` and `m()` are rejected in the parser, at the closer | Parser errors at the closer, with golden cases; make the EBNF's `tuple` rule take at least one item; delete the three "empty cell is not supported by partial inference" strings, and the checker's "a change takes at least one field" once the parser reports `m()` |
120+| 20 (A30) | `[a=@ud [a=@t b=?]]` is one record, so the duplicate `a` is an error | `+duplicate-fields` carries seen fields through unfaced tails; fix the comment above `+$ written-fields` in `jibb.hoon`, which says each written record has its own scope |
121+| 21 (A25) | `/% %foo` and `++ foo 1` may share a name | `+module-scope-valid` checks marks only against marks and molds, as the API scope check has done since `ce69a3b`; add golden cases for `/% %foo` beside `++ foo 1` and beside a prelude value in an ordinary module. Tell @iko that API modules already allow it |
122+| 22 (A15) | A `?-` arm that matches no remaining case is a definite error, "arm matches no case" | The core's usefulness check gives it; until then it reads "union pattern is not supported" |
123+| 23 (A55), 24 (A64), 27 (A61) | Match Hoon: no comparator in `(mop K V)`; keep both `each`s; the mark keeps dropping the final newline | No code change; record each in `decisions.md` |
124+| 26 (A50) | The importer reads `$%` with `%&`, `%\|` and `%0` tags, then `each` and `json` | `jibb-import.hoon`'s tag checks, then catalogue entries, with importer fixtures |
125+| 28 (A136) | The printer flattens `[a [b c]]` and prints named molds by name | `+show-itype`, and the missing-tag message, which lists an imported union's cases (`union %no %yes has no case %other` in `types-missing-tag-imported`) instead of naming it, `choice.fixture`; many `types.txt` change, so do it with or after the core's one pipeline |
126+
127+One more was never asked: **A62**, whether the prelude's `+$ attr` should spell `pad` and `gap` with a `+$ space %s0 %s1 %s2 %s3` instead of eight constant cases. It adds a public prelude name, which is @iko's call. Ask with the others.
128+
129+Milestone-2-finish step 7 lists the same import gaps (A50, and A14 from step 1). Build A50 here once @iko confirms question 26, and say in the project chat when it lands, so that brief's builder doesn't build it again.
130+
131+## Step 6: the checker core
132+
133+[milestone-2-finish.md](milestone-2-finish.md), steps 2 to 4, describes the core and owns it. Whoever builds it should start from [the checker map](../reviews/2026-11-03-checker-map.md). The review's own advice for staging it:
134+
135+- Give `istate` a constructor first (A28, A125): it has 27 positional fields, built as literals at 10 places in `jibb.hoon`, so every field the core adds touches all of them. The 13 suites that use it bunt `*istate:jibb` and set fields by name, so they don't need to change.
136+- The partial report re-infers each definition on its own, so a new core can sit behind the report one definition at a time, before the full check changes (map, section 4.4).
137+- The program, page and store recovery arms run only for definitions still missing after ordinary resolution, so when the core resolves one ordinarily, its recovery arm stops firing and can be deleted with its tests kept.
138+- Keep `+itype-fit`'s three answers while old callers remain: `%unknown` should still mean "would need a deferred constraint".
139+- Budget the golden changes: question 6 moves every `types.txt` once, 347 on `master` today (283 when the review counted). Do that in one commit, with every changed output read.
140+
141+These findings close when the core lands, and nobody should patch them before: A11 (same-origin unions compared by their raw cases), A15 with question 22, A16 (variable kinds kept by self-bindings in six copied `+itype-walk` arms), A17 (three union-coverage loops), A21 and A35 (the type walkers and variable-kind disjunctions), A33 (`+infer-recursive-gate` retried after every failure), A36 (the call-argument copies in the check-mode dispatcher), A46 (the report's own resolver), A47 (the `dg-*` transaction), A48 (the program recovery arms), A49 (the generic tree proof), A132 (the prelude parsed again for each direct gate-layout proof), the rest of A42 and A130 (the report's entry chain, which parses and duplicate-checks the source again in `+golden-types-in-context` and repeats its eligibility guards, and the ten `+golden-types*` wrappers, which the one pipeline should reduce to the entry points hosts need), the rest of A45, and A121 and A122, the review's direction items on example-fitted slices and two pipelines.
142+
143+## When you're done
144+
145+- Every finding in steps 1 to 4 is fixed, each with its case, or written up in `open-questions.md` with the reason it was left.
146+- Every ruling @iko has confirmed is in `decisions.md` and built; the rest are still listed as waiting.
147+- Every check passes, under eval and on the ship.
148+- `status.md`, `compiler.md` and `open-questions.md` describe the code as it is.
149+- Everything is pushed to `master`, and a few lines go to Montelot in the project chat: what landed, what was left and why, and what waits on @iko or the core.
docs/prompts/syntax-review-follow-up.mdnew file+80
@@ -0,0 +1,80 @@
1+# Finish the 2026-11-02 syntax review's changes
2+
3+A brief for the developer who finishes what the [2026-11-02 syntax review](../reviews/2026-11-02-syntax-review.md) started. Paste it as the first message of a session, or hand it to a person; it assumes a fresh start in the repo `iko-soy/jibb`. Written 2026-11-03, when S1, S2, S4 to S7, S11 to S13 and S15 landed on `master`.
4+
5+---
6+
7+You are finishing a set of syntax changes to Jibb, a UI language for Urbit: a Hoon dialect with an indentation layout. Its spec is in `docs/spec/`; the parser, checker and printer are `jibb-dev/lib/jibb.hoon`; the prelude is `jibb-dev/lib/jibb/prelude.jibb`. On 2026-11-03 Montelot decided ten of the review's fifteen proposals, and they were built the same day, each on its own branch with its own golden cases, then merged. What is left is the gaps those builds reported, four adversarial reviews that didn't finish, and work that waits on the new checker core.
8+
9+## What landed
10+
11+Each proposal is a section of the review, numbered S1 to S15, and a row of `docs/spec/decisions.md` dated 2026-11-03.
12+
13+| # | What it does now | Where to look |
14+| --- | --- | --- |
15+| S1 | `(unface e)` removes every face from `e`'s type, through cells, a gate's sample and product, containers' arguments and the unit's payload; unions and recursive molds go by name and are kept whole. It is reserved with `proj`, is not a value, and `++ f (unface \|= …)` is still a gate | grammar.md "Unface", `+itype-unface`, `+reserved-name`, `inline-unface-*` |
16+| S1 step 1 | Decided, not built: a capital that meets a faced position binds only the type under the face | decisions.md Inference row, `inline-unface-labelled-slot` |
17+| S2 | A body's final line hands the lines after it at its depth to a tall `\|=`, `^-` or `~&` that ends it; a `?-` that begins a body's final line may take its arms at its own depth | grammar.md "The rest of a body", `lex-body-rest-*` |
18+| S4 | A bare decimal is a `@ud`: it fits `@u`, `@` and `*`, and no other aura, unless its `++` is generic over its aura | grammar.md Literals, `inline-decimal-*` |
19+| S5 | A bare pattern name is an error where a case the pattern can match has a tag there that the name spells | grammar.md Patterns, `inline-pattern-tag-name-*` |
20+| S6 | A change's item may name a wing through record fields, `m(open.cart=x)`; overlapping items are an error | grammar.md Expressions, `inline-change-wing`, `types-change-*` |
21+| S7 | Type variables may be words, `Msg`, `T2`, and print by their written names; `program` is `\|$ [Data Model Msg]` | grammar.md Type variables and Printed types, `lex-typevar-*`, `types-typevar-*` |
22+| S11, S12, S15 | Spec wording for deeper lines and nested patterns; the examples build their models with faced cells | grammar.md Lexical rules and Patterns |
23+| S13 | A cast whose expression takes the deeper lines ends its owner line; the prelude, my-app and the spec's examples use the canonical layout, with flat `?-` arms | grammar.md Spacing, prelude.jibb |
24+
25+## Read first
26+
27+1. `docs/README.md` and `docs/development.md`: the ground rules, the checks, and how golden cases work.
28+2. The review's sections for S1, S2, S4, S5, S6, S7 and S12, and decisions.md's rows dated 2026-11-03.
29+3. `docs/status.md`, the rows that name S1 to S7: each says what is partial.
30+
31+Then run `tools/check`. Everything should pass before you change anything.
32+
33+## Ground rules
34+
35+- **The spec wins**, and a language question is Montelot's to decide, as the 2026-11-03 rows were. Where this brief would decide more of the language, it says so, and you ask instead.
36+- **Another thread is building the checker core** that review question 5 asks for: union-find with levels, deferred constraints and a usefulness check for `?-`. It will replace `+itype-unify`, branch joins, `?-` exhaustiveness and pattern binding. Don't patch those for S1 step 1 or face joins; that thread owns them. Ask in the project chat what has landed before you touch the checker.
37+- **Every change is a golden case or a test arm**, and every check passes, the ship group included (`nix flake check` runs it on a fresh fake ship, or see `docs/development.md`).
38+- **Push straight to `master`**, rebased, in commits that each leave every check passing.
39+- **Keep docs current**: the status.md row for each capability, decisions.md when something is settled.
40+
41+## Step 1: finish the adversarial reviews
42+
43+The reviews of S2, S4, S6 and S7 didn't finish before the merge. For each, try to break it: probe edge cases the golden cases don't cover, check that the spec says exactly what the code does, and check every golden output the change touched. Fix what you find, with a golden case for each fix. The probe recipe is at the end of the review.
44+
45+Known already:
46+
47+- **S2.** A body of 40,000 same-depth `~& x` lines runs out of memory under eval, where 40,000 nested parentheses don't: each rest is a level of recursion in the parser. Make the rest loop iterative, if that stays small. Some new ok cases have no `types.txt` because the partial checker can't type them (`lex-body-rest-ok-3`, `-5` and `-6`).
48+- **S4.** Number patterns are checked against the subject only on known-union and atom subjects. The unit, list, loobean, single-case and deferred `?-` paths don't check them, so `[~ 0]` against a `(unit @dr)` falls through to older messages. A constructor applied directly, `(|=%wait 30)`, and a call whose head is still a variable keep the generic "call's sample and argument types do not unify".
49+- **S6.** A wing through a union field's site note reads just "field `data`", with no type. The inference-level "repeated change fields" check is now unreachable from the module entry points, because the duplicate pass reports overlaps first; keep it as a safety net or remove it.
50+- **S7.** A few messages still say "capital", as "use the same capital for a shared type". Names live in the bits of a variable's ID (`+named-var`, `+var-name`), so any test that compares a prelude scheme's IDs exactly must use the named IDs.
51+
52+## Step 2: close S1's and S5's gaps
53+
54+- `unface` on an argument whose type isn't known yet, as `|= f (unface f)` or `|=(g (unface g))` passed where the call fixes `g`, says "not supported by partial inference". The spec says it waits, as wing access does. Make it wait when the deferred path can, and fail closed otherwise. The check also looks only at the top of the type: a faced variable passes and a bare one is refused.
55+- Islands, pages and stores that find `init`, `update`, `load` or `view` by a literal `|=` (around the program, page and store recognisers) don't see through `unface`. `++ update (unface |= …)` should be a gate there, as it is for recursion (`+unfaced-gate`).
56+- Golden cases for `unface` over a set, a map and a jug, which the code handles but no case shows. `inline-unface-unknown`'s about.txt cites the wrong spec sentence. `(unface)` gets a different error in a `++` body and as a call argument; make it one.
57+- S5's exemption for a union's generic arguments works by type equality, so a concretely typed position whose type happens to equal an argument is skipped. Make it follow where the mold puts the type variable. The full module check reports an S5 error only as "module definitions need unsupported inference"; give it the partial report's message and sites.
58+
59+## Step 3: after the checker core lands
60+
61+These wait on the core from review question 5. Coordinate with that thread first.
62+
63+1. **S1 step 1** is the core's job, with a golden case each for `(hunt lt-a `1 `2)`, `(roll ~[1 2] 0 add-f)` and `[A A]` against `[x=@ y=@]`. The same thread makes joins keep a face once a position has taken one, so `~[lt-u lt-a lt-c]` and `~[lt-a lt-u lt-c]` are errors alike (today the first checks and the second doesn't). Update `inline-unface-labelled-slot` and `inline-unface-lambda` when it lands.
64+2. **The prelude's `args=` gates.** Thirty prelude gates take an unfaced `args=[…]` and open a one-arm `?-` to name its parts, only so that they fit slots with any labels. With step 1, write them with labelled samples, `++ weld |= [xs=(list A) ys=(list A)] ^- (list A)`. Use `(unface |=(…))` only for small gates mostly passed as values, as `lth`, `gte` and `lte`. Each rewrite must keep the gate's type report.
65+3. **S12, later part.** Flatten the eight prelude gates that nest a `?-` inside another's arm to look at two values (`both`, `clap`, `hunt`, `mate`, `clef`, `join`, `snip`, `rear`) into nested cell patterns, as the review shows for `hunt`. The partial checker says "branch is not supported" for those today, so wait until the core types nested patterns.
66+
67+## Step 4: lowering, at milestone 3
68+
69+When the lowering to the core language is built, `(unface e)` lowers to `e`, a `++` whose body is `(unface |= …)` joins its group's `rec` as a gate, and a wing item in a change lowers to an edit at the wing's axis (core-language.md says how).
70+
71+## Questions to ask, not decide
72+
73+Put these to Montelot in the project chat, each with a recommendation, and record the answers in decisions.md:
74+
75+1. **What faces does a cast's result keep?** `^- $-([@ud @ud] ?) lt-a` drops the gate's labels today (the fall-through at the end of `+itype-merge-faces`), while `^- [@t @ud] r` keeps a record's. The critique recommends that a cast never removes faces, so `unface` is the one place labels go.
76+2. **May a flat arm's bare-name pattern hide a prelude name?** With flat arms, Hoon's habit of writing `?:`'s else branch back at the rune's column, as `dec a`, parses as a catch-all arm binding `dec`. Today "pattern binder shadows a name" catches it. If S3 ever lands, it wouldn't.
77+3. **Is a `|=` or `~&` that ends a body's final line written flat or with a deeper body by the formatter?** The prelude keeps deeper bodies for `flit` and `bond`.
78+4. **When named type variables merge, which name prints?** Today a capital written in the `++` wins, otherwise the one made first, so `(cork fk fv)` prints `cork`'s `A`, not `fk`'s `Key`.
79+
80+The review's other proposals (S3, S8, S9, S10 and S14) weren't decided. Leave them unless Montelot asks.
docs/reviews/2026-11-02-syntax-review.md+14
@@ -6,6 +6,20 @@ How it was done: five reviewers each read the spec, the prelude, the example des
66
77This review does not restate the language rulings that [the repository review](2026-11-02-questions.md) raised (questions 16 to 28, now listed in [open-questions.md](../open-questions.md) under "Review rulings waiting for @iko"). Where a proposal extends one of them, it says so. Proposals here are numbered S1 to S15 so they don't collide with those numbers. "Review question N" means a question in that file, and "open question N" means item N of [open-questions.md](../open-questions.md).
88
9+## Outcome, 2026-11-03
10+
11+Montelot decided ten of the proposals on 2026-11-03, and they were built the same day. [decisions.md](../spec/decisions.md) has a row for each, dated 2026-11-03, and [prompts/syntax-review-follow-up.md](../prompts/syntax-review-follow-up.md) lists what is left.
12+
13+| # | Decision | Built |
14+| --- | --- | --- |
15+| S1 | Not as proposed: an explicit `unface` that strips every face from a type, reserved like `proj`, instead of ignoring sample names when gates unify. Step 1 too: a capital binds only the type under a face | `unface` yes; step 1 waits for the checker core of review question 5 |
16+| S2 | Yes, and a `?-` that begins a body's final line may also take its arms at its own depth, without indenting them | Yes |
17+| S4, S5, S6, S7 | Yes | Yes, with gaps listed in the follow-up prompt |
18+| S11, S12, S13, S15 | Yes; S12's prelude rewrite waits for a checker that types nested patterns | Yes |
19+| S3, S8, S9, S10, S14 | Not decided | No |
20+
21+The sections below are the review as written on 2026-11-02, before these decisions.
22+
923## Summary
1024
1125- **The syntax is in good shape.** Open brackets without closers, tightness as the one disambiguator, one exhaustive `?-`, named unions, `|=%tag` constructors and named changes all read well, and nearly every slip the reviewers tried gets an error at the right character. The [keep list](#what-to-keep) says what not to change.
docs/reviews/2026-11-03-checker-map.mdnew file+587
@@ -0,0 +1,587 @@
1+# The checker on 2026-11-03, and what a general core replaces
2+
3+A map of the type checker in `jibb-dev/lib/jibb.hoon`, written for whoever builds the general checker core that [review question 5](2026-11-02-questions.md) chose. It was written by the thread that fixed the [2026-11-02 review](2026-11-02-repo-review.md)'s findings, by reading the code; nothing in it was run. Claims about which tests would fail come from the tests' fixtures, their direct `name:jibb` references, and the code paths.
4+
5+Line numbers without a file are `jibb-dev/lib/jibb.hoon` at commit [`f84a29e`](https://github.com/iko-soy/jibb/blob/f84a29e/jibb-dev/lib/jibb.hoon) (15,838 lines). The syntax changes of 2026-11-03 (`d4aed71` to `706e9ca`: `unface`, S2, S4 to S7) moved them by up to about 800 lines. They added `+itype-unface`, `+infer-unface`, `+unfaced-gate`, the `+decimal-*` arms, `+tag-name-pattern`, `+change-wing-field`, `+wing-overlap` and named type variables kept in the bits of a variable's ID (`+named-var`, `+var-name`, `+show-var`), and renamed `+module-has-reserved-proj` and `+reserved-proj-*` to `+module-has-reserved` and `+reserved-*`. This map doesn't cover them, and its rows in 6.2 for S1, S4, S5, S7 and S12 predate Montelot's decisions of that day; read `decisions.md`'s rows dated 2026-11-03 instead. Find an arm by its name, not its number. Review finding numbers (A1 to A137) come from [the review](2026-11-02-repo-review.md), whose own line numbers are pinned to `4bf477e`.
6+
7+Review Q5 (`docs/reviews/2026-11-02-questions.md:43-49`) was answered (a): *"Build the general core
8+first: union-find bindings with levels, a deferred-constraint queue and Maranget's usefulness check,
9+with `main = (program …)` checked as an ordinary application."* Q6 (l.51-56, one golden pipeline),
10+Q11 (l.88, one branch-join rule) and Q12 (l.95, dependency-order pass) were also chosen.
11+
12+## 0. Numbers
13+
14+| Thing | Value |
15+| --- | --- |
16+| `%type-inference` chapter | 4601-10901 (325 arms) |
17+| `%union-analysis` chapter | 10902-15838 (224 arms). Despite its name it holds union analysis (10902-11302), the module checker, API derivation, program/store recovery, the report and the dg-* transaction (A131) |
18+| Arms and types from 4601 on | 549 `++` arms, 91 `+$` types |
19+| `itype` | 22 cases (4663-4686), six of them variable kinds plus `%tag` |
20+| `istate` | 27 positional fields (5996); built as a positional literal at 10 sites (10699, 10752, 11986, 12001, 12057, 12735, 12769, 14759, 14924, 15107) and bunted at 5 (14497, 14550, 14566, 15610, 15652) |
21+| Program/store/page/static recovery and kind code | 13146-14648 (1,503 lines) |
22+| dg-* deferred transaction | 15147-15719 (573 lines) |
23+| Direct gate-layout evidence | 9002-9228 (227 lines) |
24+| Lines saying "unsupported" or "not supported" | 283 |
25+| Golden cases | 690 in `tests/golden`; 304 have `types.txt`, every one of which starts `partial inference; module not checked`; 177 of those also have `modules.txt` (module-check mode, prepared prelude); 127 of the 304 contain an "unsupported"/"not supported" line |
26+| Suites | 58 files in `tests/lib` (the 57 checker-related suites of the brief plus `jibb-check-spans`/`jibb-hoon-reference`, which are not checker tests); they reference 125 distinct `jibb.hoon` arms and 55 types by `name:jibb` |
27+| Call sites | `itype-fit` 59 (22 in 13311-14648), `itype-unify` 43, `itype-normalize` 95 (20 in program/store, 7 in dg), `instantiate-scheme` 17 (12 in program/store), `itype-merge-faces` 13 (12 in program/store), `direct-invariant` 19 (16 in program/store), `template-apply` 22 (15 in program/store), `add-supported-result` 7 (6 in program/store) |
28+
29+## 1. The checker as it is
30+
31+### 1.1 Data types
32+
33+| Type | Line | Shape | Role and quirks |
34+| --- | --- | --- | --- |
35+| `itype` | 4663 | `%var %fvar %avar %rvar %nvar %rnvar` (one id space), `%atom aura`, `%any-atom` (bare `@`), `%flag`, `%noun`, `%empty`, `%tag [id literal constructor=?]`, `%const literal`, `%collection [name args]`, `%recursive [module name label]`, `%jrec [at name label head aura tail]`, `%grec [at name label proof=shape args]`, `%union [cases origin label args]`, `%face [name body]`, `%fn [sample product]`, `%cell [hed tal]` | The whole type language. `%var` unconstrained; `%fvar` gate-free; `%avar` any atom incl. `?` and `@`; `%rvar` atom other than `?` (arithmetic); `%nvar` decimal literal, defaults to `@ud`; `%rnvar` both. `%tag` is a pending literal resolved by binding its id. Faces and display labels live inside the type, so relabelling changes equality (A11). `%collection` is opaque except list/unit (A13). Three recursive representations (`%recursive` imported, `%jrec` qath-shaped, `%grec` test tree) |
36+| `ibinding`, `isub` | 4687-4688 | `(list [id val])` | Substitution as an association list; first entry wins; entries only prepended; no path compression. Kind refinement is encoded as a self-binding (`[n -> %fvar n]`, `[n -> %rvar n]`, `[n -> %rnvar n]`) |
37+| `ipending` | 4689 | `[id literal at]` | One per `%term`/`%null` literal or `%ctor` tag (created 8780, 8781, 8848) in `istate.tags` |
38+| `igf-form(s)` | 4942-4943 | `[typ sub left]` | Gate-free conversion result with fuel |
39+| `ifit` | 5019 | `%ok [sub next]` / `%bad` / `%unknown` | Three-valued directional fit. `%unknown` is the universal fail-closed answer |
40+| `ischeme`, `ienv`, `imold-types` | 5804-5806 | `[typ vars=(list @ud)]`; `(list [name scheme])`; `(list [name template])` | Schemes with raw (not canonical) quantified ids; environment is newest-first, linear `ienv-lookup` (6001) |
41+| `iderived`, `iwidth-definition`, `iwidth-dependency` | 5807-5809 | | Derived poke constructors; `proj` elaboration evidence (carries the raw `sub`, 10687) |
42+| `irequest-evidence`, `istore-request-evidence`, `irequest-graph` | 5812, 5816, 5820 | | Source-bound API/store request certificates and the trusted closure inputs |
43+| `ifile` | 5822 | `[values molds at derived elaborations dependencies source graph]` | Checked module interface; `graph ~` = detached legacy/prelude file |
44+| `ijimports`, `icap(s)`, `iparams`, `imolds`, `iexternals`, `imark-externals`, `ihole` | 5823-5834 | | Imports in scope; written capitals with their var ids; generic params; local mold shapes; raw importer nouns; type holes (created 7103) |
45+| `iwfield(s)`, `iwstep`, `iwidth-result`, `iwprojection` | 5839-5843 | | Record-spine scan and `proj` plan |
46+| `igf-segment`, `igate-free` | 5931, 5938 | `[verdict=?(%yes %no %unknown) inhabited left path]` | Gate-free proof with witness path |
47+| `igate-prelude-evidence` | 5994 | `[iface gates=(map term def)]` | Re-parsed prelude gate defs for direct-gate recovery |
48+| `dgo` | 5995 | `[left right at context]` | Deferred fit obligation (dg-* only) |
49+| `istate` | 5996 | `next sub caps binders molds globals externals surs mark-externals marks jimports reserved-molds params active tags in-mold at top-molds prelude holes jrec-fuel projections gate-defs head-evidence grec-index defer obligations` | Threaded functional state. `next` restarts at 0 per top-level definition. Recovery-only fields: `jrec-fuel`, `gate-defs`, `head-evidence`, `grec-index`, `defer`, `obligations` |
50+| `idiag`, `iresult`, `isample-result` | 5997-5999 | `[msg sites]`; `(each [typ state] idiag)`; `(each [typ env state] tape)` | A diag with no sites is "unsupported"/retryable (`definite-diag` 7521) |
51+| `irec-pattern` | 6416 | `[pat=upat has=?]` | Imported recursive fork proof |
52+| `ilocal-result` | 7306 | `(each [env state] idiag)` | Locals and groups |
53+| `icap-site` | 7377 | `[name at]` | Written capital occurrence |
54+| `imatch`, `ifinite` | 8106, 8170 | `?(%full %none %unknown)`; `[origin base part]` | Pattern-vs-case classifier; finite loobean refinement row |
55+| `itag-presence` | 8661 | `?(%yes %no %maybe)` | Missing-tag diagnosis |
56+| `iwidth-elaboration` | 8994 | | Dead (only the dead `infer-width-elaboration`) |
57+| `igate-entry`, `igate-seeds` | 10433-10434 | | Recursive-group seeds |
58+| `iresolved` | 10552 | `[env grouped artifacts]` | Resolver output threaded by the recovery chain |
59+| `iadj ivisited iwork iwresult icresult icomponents` | 10553-10558 | | Kosaraju state |
60+| `iadded-definition` | 10668 | `[env checked artifacts]` | `add-supported-result` output |
61+| `icyclesite`, `icycle` | 10788-10789 | | Value-cycle proof |
62+| `upat`, `urelation`, `upair` | 10909, 10919, 10920 | `%unknown %all %empty [%atom (unit @)] %flag [%cell] [%or]`; `?(%disjoint %overlap %unknown)`; `[first second relation]` | Noun-shape projection for disjointness/overlap (also used by the importer at 6463, 6645) |
63+| `uow-case` | 11191 | | Source overlap witness case |
64+| `jsource jbundle jcache jfile-result jfile-overlap jfile-failure jfile-detailed-result jimports(-detailed)-result` | 11507-11518 | | Module sources, per-invocation cache, results with structured overlap evidence |
65+| `written-fields` | 11521 | `(map term span)` | Duplicate-field scope |
66+| `imold-failure` | 11777 | `[message overlap=(unit [name upair])]` | First failing mold |
67+| `iprelude` | 12090 | `[iface values molds]` | Prepared prelude; values/molds reserve every declared name |
68+| `iapi-*` | 12328-12706 | | API path/request/support evidence |
69+| `ione-request-interface`, `imulti-request-gates` | 12780, 13043 | | API constructors |
70+| `istore-declaration` | 13242 | `[action=term defs]` | Store declaration (action always `%poke`) |
71+| `iview-site` | 13608 | `[xs mapper]` | Keyed `each (turn xs mapper)` site |
72+| `igate-free-mold` | 14885 | | `gate-free-mold-source` result |
73+| `dgscan`, `dgcommit`, `dg-step`, `dgparse` | 15149, 15243, 15444, 15581 | | dg-* transaction |
74+| `grec-collected` | 15782 | `[molds proofs]` | grec index input |
75+
76+### 1.2 Pipelines
77+
78+#### (a) The partial golden-types report (all 304 typed goldens)
79+
80+Entry chain:
81+- No prelude (127 typed goldens): `golden-types` 11486 → `golden-types-imports` 11497 → `golden-types-with-marks` 15016 → `golden-types-in-context` 15021 → `golden-types-in-context-core` 15025. `tools/golden:248-253` picks the arm by whether the case has `/sur` or mark fixtures.
82+- Module-check mode (177 typed goldens with `modules.txt`): `tools/golden:254-260` calls `golden-types-with-prepared-prelude` 14975 with a prelude prepared once under `mule` by `prepare-prelude-with-internal` 12103 (`tools/golden:291`), falling back to `golden-types-with-prelude-and-internal` 14969. 14975 parses, runs `duplicate-defs`, `module-scope-valid` 14986, and **resolves Jibb imports with the full checker** (`resolve-jibb-imports` 14989 → `infer-jibb-file-detailed` per imported module), then calls the core.
83+
84+`golden-types-in-context-core` 15025-15146:
85+1. Parse (15029), `duplicate-defs` 15031 (→ `duplicate-fields-report`), reserved `proj` 15033 (bare `'module has reserved proj name'`, no header, A43).
86+2. `resolve-groups` 15040: the same resolver as the full check (10662 → `resolve-groups-core` 10736) but **with no grec index**, so `%grec` never arises here; no program/store recovery, no kind checks.
87+3. `definite-value-cycles` 15041.
88+4. dg-* transaction if eligible (15044-15075): import-free, not API/store, no `main`, incomplete, ≤65,536 bytes, ≤64 defs, and either no prelude + `dg-source-candidate`, or the exact prepared prelude + `dg-prepared-candidate`. Names it adds are "recovered" only if the transaction env is complete and `dg-interface-safe`.
89+5. Per definition in source order (15079-15146): molds → `show-partial-mold` 11431 (never infers the mold; hole report, union disjointness verdict or `not checked`); duplicate name → `name already in scope`; cycle → `non-gate value depends on itself through a cycle`; recovered/grouped → print the scheme from env; otherwise **re-infer the definition afresh** (state literal 15107, `gate-defs`/`head-evidence` 15108-15109, `reserve-def-caps` 15110; gates through `infer-recursive-gate` 15113, others `infer-fragment` 15114) and finalize with its own copy of the finalization (15117-15143, table in 2.8), then `canonical-itype` 15144 + `show-itype` + `show-atom-constraint`.
90+
91+So a report line is not the scheme the resolver published; it is a second inference against the resolved env. The report never runs recovery, kind checks or grec; its messages are the raw per-definition failures.
92+
93+#### (b) The full module check
94+
95+`infer-jibb-file` 14650 (text adapter) → `infer-jibb-file-detailed` 14658-14879:
96+1. Parse 14661 (`module source does not parse: /p`), `duplicate-defs` 14664, API module with `main` rejected 14666.
97+2. `/ui/api/...` branch 14668-14725: `api-poke-interface-result` 12979 first; else `api-derived-clash` 14678, scope with mark rules 14684-14698, prelude required 14699, `resolve-jibb-imports-detailed` 14705, `+$ paths` required 14708, then the "narrow" `one-request-interface-graph` 14711-14721 or `multi-request-interface-graph` 14722-14725. No value inference beyond `api-support-analysis-*` (12708, 12742), which calls `resolve-groups`.
98+3. Other modules: `program-main-def` 14726 and the syntactic recognisers `program-main-parts` 14728, `page-main-parts` 14730, `store-main-parts` 14732; `store-declaration` 14734 (definite clash 14736; `module kind or scope needs unsupported inference` 14740); a `/ui/stores` main that is not a store is rejected 14741.
99+4. `module-scope-valid` 14745, `resolve-jibb-imports-detailed` 14748 (mutual recursion with this arm; cycle check before cache, cache reuse rules 12275).
100+5. Molds: `grec-collect-molds` 15825 only for import-free modules (14750-14752); istate literal 14759; grec index only for import-free prelude-backed modules whose prelude list is exactly `[[%collection %list ~[[%var 0]]] ~[0]]` and that have no local `list` (14762-14772); `module-mold-types-detail` 11799 (first failure aborts; overlap evidence rendered 14774-14780).
101+6. Values: `resolve-groups` or, with an index, `resolve-groups-core` (14781-14784). `resolve-groups-core` 10736-10756: compute names, graph, Kosaraju components, `direct-prelude-evidence` (prelude re-parse) and `dependency-order` 10768 once, then loop: `add-supported-defs-core` 10690 over the ordered defs (fresh positional state per def with `next=0`, `jrec-fuel=256`, `gate-defs` = `direct-checked-gates` of the current env, `head-evidence`; `reserve-def-caps`; `infer-fragment`, then `infer-recursive-gate` if that failed; `add-supported-result` 10670, which **silently drops** any failure or pending tag), then `add-groups` 10645 (cyclic components through `infer-gate-group` 10509), until env stops changing.
102+7. Program recovery chain 14786-14804, only for a direct `(program i u v s)` main: `program-update-context` 13346 → `program-subs-context` 13508 → `program-view-context` 13938 (keyed) → `program-plain-view-context` 13858 (only if keyed declined) → `program-plain-init-context` 14238 → `program-main-context` 14472. Single pass, fixed order, each arm a no-op unless its component (and `main`) is still missing.
103+8. dg fallback 14807-14816: only if incomplete, not a store, no imports **and no prelude** (14809), so it can never affect a prelude-backed check (A47).
104+9. Completeness 14817-14832 (store modules exclude `main`): `module-pending-tag` 10715 (re-infers ≤64 missing defs to find `nothing fixes the union of %x`), then `module-sample-shadow` 12171, then `module definitions need unsupported inference: /p[: ++ name]` with `module-missing-value` 12132 choosing the name.
105+10. `request-graph-merge` 14834; static main swap 14836-14843 (`static-main-specialized` 14487); store main swap 14844-14849 (`store-main-closed` 14599); kind boundary 14850-14857 (`program-main-closed` 14555, `page-main-closed` 14540, store/static results) → `module kind needs unsupported inference: /p`; store-derived exports 14858-14875; `request-graph-bounded` 14876; `ifile` 14878.
106+
107+#### Where the two pipelines differ (A46, A122)
108+
109+| | Report (a) | Full check (b) |
110+| --- | --- | --- |
111+| Resolver | `resolve-groups`, grec index `~` | `resolve-groups-core` with index when import-free |
112+| After resolving | re-infers each definition and prints its own failure | keeps resolver env; failures are silent |
113+| Recovery | none | program chain, static/store main swaps |
114+| Kind checks | none | `program-main-closed`, `page-main-closed`, store, static |
115+| dg-* | eligible with or without prepared prelude (15053-15061) | only without prelude (14809) |
116+| Finalization | 15117-15143 (adds `pending-null`, hidden recursive/generic, merged-capitals messages) | `add-supported-result` 10675-10689 (no `pending-null`, no hidden-name check, merged capitals caught only as `constrained-capitals`) |
117+| Mold check | `show-partial-mold` (projection only) | `module-mold-types-detail` (real templates) |
118+
119+### 1.3 Families, by layer
120+
121+"Category": G general inference, U union analysis, M module and imports, A API and paths, R recovery slice, P reporting/printing, O other. "Tests" lists suites (without the `jibb-` prefix) and goldens; `[call]` marks suites that name the family's arms directly.
122+
123+#### A. Substrate (4601-6400)
124+
125+| Family | Lines | Cat | How it works | Tests |
126+| --- | --- | --- | --- | --- |
127+| Chapter contract, `itype`, `isub` | 4601-4689 | G | Contract comment 4603-4661 (assoc-list sub, occurs check, per-definition generalization, monomorphic binders, capitals shared per definition, `@` one-way, unions keep origin/args; `proj` limits 1,024/4,096; "The unchanged todo API fits this fragment" 4643-4644; closed gate sample may omit one outer face 4653-4655) | every `types-*`; 32 suites build `itype:jibb` |
128+| Lookup, walk, occurs, normalize | 4691-4732, 4817-4843, 6012-6026 | G | Linear `itype-lookup`; `itype-walk` follows chains for the six var kinds and `%tag`, stopping only at a self-binding to `%fvar`/`%rvar`/`%rnvar` (six copied arms, A16); `itype-occurs` (opaque `%recursive`/`%jrec`; same-id `%tag` counts); `itype-normalize` full zonk, leaves `%tag`/`%recursive`/`%jrec` | typecheck, hole-guards [call], arithmetic-guards [call], deferred [call], generic-construction [call]; `types-partial-occurs`, `types-partial-dependency-chain`, `types-partial-shared-tvar` |
129+| Emptiness and inhabitation | 4734-4815 | U | Budgeted; `itype-empty-proof` proves only emptiness; `itype-inhabited-proof` three-valued (`%var` yes only via written capital; only list/unit collections decided, A13; `%grec` via `grec-tree-proof` 4801); `itype-live-cases` drops proven-empty cases, any unknown → `~` | empty [call]; `types-list-patterns`, `types-partial-union-edges`, `types-union-finite-limit`, `types-tuple-context` |
130+| Unification | 4851-4940, 5005-5012 | G | `(unit isub)`, no reason. Walk both, equal → ok; grec by at+name then args; jrec by 5 fields; recursive by module+name; union by origin, then raw `cases` equality when argless (A11) else args; collection by name then args; `%var` binds anything after occurs; `%fvar` via `itype-bind-gate-free`; atom-kind lattice 4884-4925 (nvar~rvar → rnvar with self-binding 4887-4889); const by value; atoms of different aura fail (no widening); face~face same name; fn/cell pointwise | typecheck, arithmetic-guards, gate-free-guards, generic-recursion [call]; `types-arithmetic-*`, `types-partial-atom-*`, `types-union-phantom-generic` |
131+| Gate-free propagation | 4942-5003, 6320-6343 | G | `itype-gate-free-form` (budget; unbound `%var` → self-binding to `%fvar`; fails on fn/noun/tag/recursive/grec); `itype-bind-gate-free` 256 (exhaustion reads as mismatch); `itype-collection-keys` for set/map/mop/jar/jug keys; `itype-var-is-gate-free-fuel` fails open at fuel 0 | gate-free-guards [call], gate-free-source; `types-prelude-unit-helpers` |
132+| Directional fit | 5014-5019, 5451-5711 | G | `itype-fit` = `itype-fit-inner` + empty-source rescue (256). About 45 ordered guards: width (spine ≥1,024 or wider source → unknown); empty/flag-vs-`@f`; `*` accepts anything incl. gates (A23) and binds bare tags to `*` (A22); actual `*` only to a var; grec/jrec/recursive by identity; unions by origin; known union to var by unify; non-var vs union → `itype-fit-cases` (unique %ok wins, two → unknown); tags: ctor only vs fn via `itype-fit-ctor-cases`, term vs `@tas`/`@ta` with no aura check (A20), vs `?` if 0/1, vs `@`; zero vs list → unknown; var vs face unifies with the body (5652); `@` turns a var into a fresh `%avar` (only allocation, 5666); atom by `aura-prefix`; cells head then tail; faces same name; closed gates by `itype-closed-gates-match`; last resort unify, with failures turned to `%unknown` when unions, recursion or related auras are involved. **Gates (fn vs fn) only unify: no variance** | closed-gate-guards, constructor-fit-guards, empty, qath-fuel, generic-construction, arithmetic-guards, generic-recursion, deferred [call]; 32 golden lines `call constraint…`, 37 `cast constraint…` |
133+| Aura families | 5049-5092 | G | `aura-prefix` textual prefix (`@` above all); `itype-family-related` only to turn failures into unknown | `types-partial-aura*`, `types-partial-atom-widening`, `types-partial-branch-widening` |
134+| Branch joins | 5094-5097, 5125-5210 | G | Unify, else `itype-concrete-join` (prefix parent or `@`, never touches sub); n-ary: unify all, else first `@` or common prefix parent present among arms | `types-partial-branch-widening`, `types-list-branch`, `types-union-branch-*`, `types-recursive-branch`, cell-branch, deferred |
135+| Face guards | 5212-5227, 5265-5349 | G | `itype-face-asym` (face on one side vs non-var); `itype-merge-faces` (cast result, 1 + 12 recovery calls); positional rules `itype-positional-face-asym`/`-slot-face-asym` (added with `like`, 640a442); `itype-output-may-be-cell` | positional-face-guards [call], direct-gate-guards [call], deferred [call]; `types-positional-faces`, `types-prelude-like`, `types-generic-face-inference`; 4 golden lines `call result face propagation` |
136+| Closed gate sample matching | 5229-5263 | R | See 3, R12 | closed-gate-guards (via `itype-fit`), todo-api |
137+| Fail-closed structure guards | 5020-5046, 5098-5123, 5372-5449 | G | `itype-has-any-atom/-tag/-union/-recursive/-hidden-generic/-hidden-recursive`; `itype-has-fixed-atom` (5098) is dead | `types-union-unresolved*`, `types-generic-union-escaping`, `types-qath-module-identity` |
138+| Pending tags | 5351-5370 | G | `pending-tags`, `pending-null`, `pending-tag-diagnostic` (`nothing fixes the union of ` + `show-lit`, 5363); checked only at definition end | buttons (`tests/type-buttons/error.txt`), program-init, program-update, deferred [call]; 80 golden lines `tag needs context`, 24 `` `~` needs context `` |
139+| Self-test | 5713-5798 | O | `itype-unify-test`, compared by `jibb-typecheck` with `tests/checker/unification.txt` (the old `tools/hoon` check is gone) | typecheck [call] |
140+| State, env, results | 5800-5806, 5824-5827, 5832-5834, 5995-6006 | G | see 1.1 | 13 suites build `istate:jibb` |
141+| Interface/evidence types | 5807-5823, 5828-5831 | M | see 1.1 | module-*, api-evidence, store, program-watch |
142+| Record width and `proj` | 5835-5923 | O | `width-scan` (closed uniquely faced spine), `width-known-shape`, `width-shape` (wider source → `record width constraint needs unsupported inference`), `width-proj-shape`/`width-project` (source-order planner, 4,096) | proj-guards; `types-proj-*`, `types-partial-projection` |
143+| Gate-free proof with witness | 5925-5992 | O | `gate-free-type` on normalized types; budgeted; list/unit only (A13) | gate-free-guards, gate-free-source, empty, generic-recursion [call]; program-main |
144+| Defaulting, promotion, holes | 6028-6181 | G | `promote-restricted-numbers` (only with written caps), `default-hole-numbers` (only when the type has no gate), `unresolved-hole`, `default-decimals` (`itype-has-gate` treats `%grec` as gate-bearing, ignores union args), `uncertain-hole-msg` | hole-guards [call], generic-recursion [call]; `types-hole-*`, `types-partial-decimal-default` |
145+| Vars, rename, canonical, instantiate | 6183-6318, 6345-6368 | G | `itype-vars` order (fn sample before product, head before tail, union args before cases); `unique-type-vars` O(n²); `itype-rename` single pass, no sub; `canonical-itype` kind precedence rvar > avar (nvar/rnvar → avar) > fvar > var; `instantiate-scheme` pushes fresh fvar/avar/rvar ids onto `binders` | gate-free-guards [call]; `types-partial-generalization`, `types-partial-atom-alias`, `types-many-variables`, `module-import-atom-scheme` |
146+| Local capital and mold lookup | 6370-6395 | M | `icap-lookup`, `find-simple-mold` (unique only), `collect-simple-molds` | 5 suites [call] |
147+
148+#### B. Import bridge and mold elaboration (6397-7253)
149+
150+| Family | Lines | Cat | How it works | Tests |
151+| --- | --- | --- | --- | --- |
152+| Imported Hoon validation and bridge | 6397-6728 | M | `jibb-face-name`, `rec-pattern(s)` (self-recursive disjoint fork → opaque `%recursive`), `imported-faces-valid` (repeated face on a spine fails), `import-to-itype(-standard)` (aura whitelist u ud ux uv t ta tas p da dr tD, duplicated at 6432, 6557, 12666, A14; `%f` pair → `?`; `%unit` → prelude unit union only with the standard template, A10; other forks → originless `%union` after pairwise `union-relate`), `find-imported-mold(-prelude)`, `find-imported-mark(-prelude)`, `collect-sur-imports`, `collect-mark-imports`. 6682-6683 dead (A18). All failures `~` | bridge, api-evidence [call], import*, mark-bridge, tlon-bridge, poke-bridge; `types-import-*`, `module-import-api-*` |
153+| Interface lookup and relabelling | 6730-6841 | M | `find-jibb-interface`, `find-jibb-mold` (~40 callers), `itype-in-import` relabels unions/jrec/grec (display only), `prelude-union-alias`, `identity-union-parameters` | generic-alias, ask-guards, store, page-main, program-watch, todo-full, theme [call]; `module-import-*`, `types-union-print-*` |
154+| Mold elaboration and templates | 6843-6919, 6970-7000, 7099-7253 | G | `infer-simple-shape` (shape→itype; holes allocate a var + `ihole`; unions need `union-pairs` without overlap, else the source slice; local mold expansion guarded by `active`; generic local mold re-elaborated with params bound; generic local unions refused 7216-7217); `template-apply(-sub)` renames scheme vars to args (`template-apply` drops the sub); `infer-mold-template` builds +$ schemes, generalizing exactly the params; `label-direct-union` gives a top-level union its origin | union-source [call], gate-free-guards [call]; `types-generic-*`, `types-hole-*`, `types-union-alias` |
155+| Source-recursive recognisers | 6921-6967 | R | `simple-source-recursive` (`%jrec`), `simple-source-generic-recursive` (`%grec`). See R17, R18 | qath-*, generic-recursion [call] |
156+| Import-invalid replay | 7002-7097 | M | Replays a failed shape to recover the importer's `[%invalid …]` message with site note `invalid imported mold` | import, import-diagnostic, import-overlap, import-structural |
157+| Gate samples | 7255-7300 | G | `infer-sample`: binders fresh `%var`, monomorphic, pushed onto `binders`; shadow → tape `sample shadows a name` | `types-partial-shadow-global`, `module-import-*-shadow` |
158+| Local definitions | 7302-7373, 7514-7702 | G | See 2.7; generalization subtracts `free-env-vars` and `free-cap-vars`; order-independence machinery `shared-types`/`shared-moved`/`closed-local` | `types-local-*`, `types-partial-locals`, `types-local-scc*` |
159+| Capital scope walker | 7375-7512 | G | `scope-*` syntactic walk; `reserve-def-caps` allocates one `%var` per written capital per `++` | `types-local-capitals`, `types-capital-distinct` |
160+| Record field access | 7704-7747 | G | `record-fields-named` on a known faced spine; no deferred has-field constraint | program-init/main/update/watch [call]; `types-record-faces` |
161+
162+#### C. Expression checker (7749-10032)
163+
164+| Family | Lines | Cat | How it works | Tests |
165+| --- | --- | --- | --- | --- |
166+| Contextual branches and list literals | 7749-7921 | G | `infer-union-context` (two loobean arms or unit arms with the same expected type, no join), `infer-list-context` (exact prelude list scheme; cons only under list context), `infer-open-list-items`/`infer-list-items` (drifted copies, A17), each with the `element` fallback hook (R7) | `types-list-*`, `types-flag-branch-context`, `types-union-branch-context`, deferred-context, todo-partial |
167+| Unit and list two-arm branches | 7923-8075 | U | Hand-coded two-arm exhaustiveness (`~` + `[~ x]`, `~` + `[h t]`); unit recognised structurally (no origin check); inhabitation 256 | empty [call]; `types-unit-patterns`, `types-list-patterns` |
168+| String interpolation | 8077-8101 | G | Accepts atoms, `@`, leftover decimals, `(list @tD)`; generic atom from a capital → `a generic atom in interpolation needs an aura`; cell → `a cell in interpolation needs a printer` | `types-string-interpolation` |
169+| Union coverage, three copies | 8103-8390 | U | `union-pattern` %full/%none/%unknown; `infer-known-union-whole` 8208, `-context-whole` 8246, `-finite` 8292 (loobean expansion ≤64 rows); `single-structured-pattern`/`infer-single-case-branch` 8351-8390 | generic-pattern, cell-branch, nested-union-guards, empty; `types-union-patterns*`, `types-union-finite*`, `types-single-case-pattern` |
170+| jrec/grec match views | 8392-8475 | R | R17, R18 | qath-fuel, generic-pattern [call] |
171+| Branch routing | 8477-8549 + 8878-8930 | G | Order in `infer-fragment %branch`: dg → one arm (empty-list, empty-union, grec, structured, cell) → ≥3 arms known-union → two arms: speculative `known-union-subject`, unit, non-literal → known-union, loobeans (unify subject with `?`, infer arms, `itype-branch-join`, failure classified 8921-8929) | `types-union-*`, `types-loobean-*`, `doc-grammar-04-step` |
172+| Empty list / empty union | 8555-8608 | U | `empty-list-null-branch` (exact prelude list; element proven empty), `known-empty-union-wing` | empty [call] |
173+| Record change | 8612-8656 | G | `infer-change-edits` on a known faced spine; `standard-unit-template` 8646 | `types-record-change*` |
174+| Missing-tag diagnostics | 8658-8744 | P | `missing-union-tag` (`{label} has no case %x`), `nested-missing-tag` replay | `types-missing-tag-*`, `types-nested-missing-tag` |
175+| `infer-fragment` | 8749-8980 | G | Synthesis by node kind (literals: `%ud` → `%nvar`, `%loobean` → `%flag`, term/null → `%tag` + `ipending`; ctor → `%tag … &`; `%unit`/`%list`/`%qath` require the exact prelude templates; `%wing` instantiates; `%cast` = shape + check-mode + width check + fit + merge faces; `%gate` monomorphic sample; `%call` → `infer-call-with-head`) | every typed golden; cell-branch, deferred, generic-pattern, qath-source [call] |
176+| Dead code | 8988-9000, 9058-9063, 10780-10783 | O | `width-has-projections`, `infer-width-elaboration`, `direct-find-gate`, `resolve-supported-defs` | none |
177+| Direct gate-layout evidence | 9002-9228 | R | R11 | direct-gate-guards [call] |
178+| Call checking | 9230-9294, 9296-9314 | G | Head first; known `%fn`: context args, width, fit (`itype-fit-inner … skip-width` for multi-arg), else `direct-gate-call-fit`; `%unknown` → `call constraint…` (or a `dgo` in defer mode); `%bad` → missing tag → nested tag → `call's sample and argument types do not unify` (`call-error-site` blame); face-propagation guard 9283-9288. Unknown head: unify with `[%fn arg fresh]` | 116 golden lines `call's sample…` in 53 goldens; positional-face-guards |
179+| Contextual call and singleton/unit/tagged-case | 9316-9562 | R/G | `infer-unit-context` 9321, `infer-contextual-call` 9355 (pre-unify product with expected; `element` exception), `explicit-singleton-in-union` 9480, `contextual-*` 9501-9562 (R15), `grec-direct-context` 9527 | nested-union-guards, constructor-fit-guards [call]; `types-nested-union-context`, `types-unit-context` |
180+| `proj` intrinsic | 9396-9475 | O | `explicit-proj-call`, `infer-proj-context` (check mode only), literal fields by name | proj-guards; `types-proj-*` |
181+| Closed-cell branch retry | 9564-9662 | R | R14 | cell-branch [call]; `types-cell-branch-context` |
182+| Check-mode dispatcher | 9664-9783 | G | `infer-call-context-arg`, ~19 ordered steps (9667-9783): defer → unwrap pair/group/body/trace → peel faces → `proj` → grec ctor → jrec `~`/tuple → call → empty list → structured/cell patterns → loobean singleton → known-union branch → unit → closed-cell → flag/union/list branch → list literal → tagged case → cell tuple → synth. Reads the raw `expected` at 9732, 9743, 9756 to keep provenance (A36). Callers do the final fit | generic-construction, qath-fuel [call] |
183+| Positional items, cell binders | 9785-9928 | G | `infer-call-context-items/-args`, `projection-field-target` (peels one slot face), `infer-simple-items`, `infer-cell-branch` | `types-cell-pattern-*`, `types-multi-call` |
184+| Printers | 9930-10032 | P | `show-itype` (A-Z then T26…; six identical variable arms 9936-9951, A35), `show-itype-cases`, `site-type-note` (bare label for vars, nvar, tags, unions, hidden recursion) | every typed golden; 11 suites [call] |
185+
186+#### D. Definition boundary and module resolver (10034-10900)
187+
188+| Family | Lines | Cat | How it works | Tests |
189+| --- | --- | --- | --- | --- |
190+| Capital and atom-var guards | 10034-10169 | G | `merged-capitals` 10072, `constrained-capitals` 10089 (capital bound to non-var or shared → "explicit capital constraints are not supported"), `atom-var-from-cap`, `atom-var-from-binder`, `unsupported-atom-vars` 10159 (atom vars generalize only from caps or `binders`) | deferred [call]; `types-capital-distinct`, `types-partial-explicit-capital`, `types-partial-aura-*` |
191+| Constraint printing | 10171-10191 | P | `show-atom-constraint`: ` where A is an atom other than ?` / ` is an atom` / ` contains no gates` | all typed goldens with constrained vars |
192+| Names, dependencies | 10193-10214, 10327-10428 | M | `global-value-names`, `unique-value-name`, `dependency-expr` (syntactic, ignores binders, errs closed) | `types-partial-forward`, `types-scope-*` |
193+| Single recursion | 10216-10325 | G | `infer-recursive-gate` 10285: monomorphic `[%fn sam seed-or-fresh]`, body, unify product; `recursive-branch-seed` 10254 (closed base arm of a one-self-call loobean branch); refuses in defer mode; clears `gate-defs` | `types-recursive-*`, `types-local-recursive` |
194+| Mutual recursion groups | 10430-10533 | G | `seed-gate-group`, `infer-gate-group-bodies`, `group-schemes` (short merged-capital text 10495), `infer-gate-group` 10509 (rejects projections, holes, pending tags) | `types-recursion-scc-*`, `types-local-scc*` |
195+| Projection finalization | 10535-10549 | O | `width-finalize` | `types-proj-*` |
196+| Kosaraju SCC | 10552-10643 | M | Work-list DFS; components dependencies-first; duplicates → no components | `types-recursion-scc-order`, `types-value-cycles` |
197+| Resolver fixpoint and finalization | 10645-10778 | M | `add-groups`, `resolve-groups`, `add-supported-result`, `add-supported-defs-core`, `resolve-groups-core`, `dependency-order` (see 1.2(b) step 6, 2.7, 2.8) | all full-check suites; `module-import-*` |
198+| Failure diagnostics, value cycles | 10711-10734, 10785-10900 | P | `module-pending-tag` 10715; `definite-value-cycles` 10885 (report only) | buttons, program-init, program-update; `types-value-cycle*` |
199+
200+#### E. Union analysis and module checker (10902-12600)
201+
202+| Family | Lines | Cat | How it works | Tests |
203+| --- | --- | --- | --- | --- |
204+| Union projection and relation | 10904-11022, 11275-11286 | U | `project-union-mold` (local refs only, `seen` list), `union-relate` (`?` = {0,1}), `union-pairs` O(n²) in (i, j) order | full-overlap-*, import-overlap; 73 goldens print `cases proven disjoint`, 12 `overlapping cases` |
205+| Source disjointness slice + state screen | 11024-11187 | R | R19 | union-source [call] |
206+| Overlap witness | 11189-11273, 11288-11302 | U | `mold-overlap-witness` 11296: first projected overlap, else (only if some pair unknown) `union-source-overlap` 256 | union-alias-overlap, full-overlap-basic [call] |
207+| Hole detection | 11304-11430 | G | `simple-mold-hole` (unit unit span), syntactic `*-has-hole` | hole-guards [call]; `types-hole-*` |
208+| Report printers and entry wrappers | 11431-11500 | P | `show-partial-mold`, `show-inference-diagnostic`, `show-duplicate-fields`, `duplicate-fields-report`, `golden-types`, `golden-types-imports` | all typed goldens |
209+| Duplicate fields | 11520-11693 | O | Pre-inference syntax pass; nested cell opens a new scope (A30); message `record field `x` is repeated` | `types-record-field-*` |
210+| Scope validity, reserved `proj` | 11694-11773 | M | `import-binding-names` (includes `/%` marks, A25), `reserved-proj-*`, `module-scope-valid` | proj-guards, deferred-resolver [call]; `types-proj-reserved-*` |
211+| Module mold elaboration | 11775-11824 | G | `module-mold-types(-detail)`: each mold from the same base state (ids may repeat across templates); first failure aborts; overlap evidence for a union | full-overlap-basic [call]; `module-cache-incomplete` |
212+| Prelude bootstrap | 11826-12024 | R | R21 | `prelude-*`, `types-prelude-*` |
213+| Partial prelude interface | 11913-11926, 12026-12112 | M | `partial-prelude-molds` drops failing molds silently; `prepare-prelude(-with-internal)` re-parse | 33 suites call `prepare-prelude-with-internal`; `tools/golden:291` |
214+| Completeness and failure naming | 12114-12188 | P | `module-values-complete`, `module-missing-value`, `module-sample-shadow` | `module-missing-value-*` |
215+| Import resolver and cache | 12190-12200, 12219-12228, 12275-12324 | M | Cycle check before cache; legacy entries rebuilt; reuse needs identical inputs | `module-import-*`, `module-cache-*`; full-overlap-graph, request-guards |
216+| Request-graph merge | 12202-12218, 12229-12274 | A | Set union of paths; dedup requests/stores; 256/256 bound (A27) | store [call], request-guards |
217+| API path extraction, derived names, typing | 12326-12615 | A | `+$ paths`/`+$ poke` declarations, `api-derived-clash`, `api-path-analysis(-source)`, `api-path-evidence-source` | api-paths, api-evidence, hole-guards, proj-guards [call]; `module-import-api-*` |
218+
219+#### F. API interfaces (12596-13144)
220+
221+| Family | Lines | Cat | How it works | Tests |
222+| --- | --- | --- | --- | --- |
223+| Path evidence | 12596-12652 | A | `api-path-evidence-source/-graph` (copies, A31), `api-path-watchability` | api-evidence [call] |
224+| Request components | 12654-12698 | A | `api-request-parameter-types`, `api-request-fold-type`, `api-request-parts` (argument order not fixed) | api-evidence [call], todo-api |
225+| Supporting definitions | 12700-12774 | A | `api-support-analysis-source/-graph` (copies): ordinary `resolve-groups` with a positional state | api-evidence [call] |
226+| Prelude shape certificates | 12776-12845 | A | `compatible-raw-poke`, `request-compatible-ask`: structural `=` on hard-coded itype nouns | store [call], ask-guards, sub-guards |
227+| Request interface constructors | 12847-12956, 13020-13075, 13099-13144 | A | `one-request-interface-source` (dead) and `-graph` (narrow branch, A44), `api-sur-covered`, `api-request-gates` (fuel 256), `multi-request-interface-graph`; hand-built `∀0` schemes | request-guards, todo-api, page-main, todo-full; `types-request-normal`, `module-import-api-request-reason` |
228+| Poke-only interface | 12958-13018, 13077-13097 | A | `api-poke-interface(-result)`, `api-poke-from-checked`, `api-mark-exports` | hole-guards, api-paths, proj-guards [call]; `module-import-api-poke-*` |
229+
230+#### G. Kind recognition and program/store recovery (13146-14648)
231+
232+| Family | Lines | Cat | How it works | Tests |
233+| --- | --- | --- | --- | --- |
234+| Main-call recognisers | 13146-13240 | M | `program-main-def`, `program-main-wing`, `program-main-args/-parts`, `page-main-parts`, `store-main-parts`: syntax, heads matched by name (four copies of one walk, A48) | program-main, program-watch, store, page-main [call] |
235+| Store declaration, derived-name clash | 13242-13309 | M/P | `store-declaration`, `derived-name-clash` (precedence: definition, import face, another derived name, prelude name) | store; `module-import-store-*`, `module-import-api-*-clash` |
236+| Transparency helpers | 13311-13340 | R | `program-empty-null`, `program-subs-empty`, `program-transparent` | program-main, page-main |
237+| Update, subs recovery | 13342-13606 | R | R1, R2 | via `infer-jibb-file(-detailed)` |
238+| Slot and relation helpers | 13452-13503 | R | `program-inferred-slot`, `program-two-slot-names`, `program-update-relation` | via recovery |
239+| Keyed view-site walker | 13608-13749 | R | R3 | todo-full |
240+| Element message fits | 13751-13853 | R | R7 | todo-full, store, buttons; `types-prelude-ui` |
241+| View recovery | 13855-14155 | R | R3, R4 | todo-full, store |
242+| Initializer | 14157-14312 | R | R5 | program-init |
243+| Derived request/store evidence | 14314-14470 | A | `derived-poke-command-scheme`, `store-derived-schemes`, `program-subs-watch` 14367, `derived-request-member` 14405-14441, `derived-store-request-member` 14443-14470: provenance certificates compared by `=` | store [call], program-watch, page-main |
244+| Program main completion, kind boundary | 14472-14582 | R/M | `program-main-context` (R6), `static-main-specialized` (R9), `page-load-derived`, `page-main-closed` (R10), `program-main-closed` (R6) | program-main, program-watch, store, page-main [call] |
245+| Store kind | 14584-14648 | R | R8 | store |
246+
247+#### H. Driver, report, dg, fresh ids, grec (14650-15838)
248+
249+| Family | Lines | Cat | How it works | Tests |
250+| --- | --- | --- | --- | --- |
251+| Module driver | 14650-14879 | M | 1.2(b) | 23 suites call `infer-jibb-file`, 12 `infer-jibb-file-detailed` |
252+| Mold analysis entry | 14881-14933 | O | `gate-free-mold-source` | gate-free-source [call] |
253+| Report adapters | 14935-15024 | P | `golden-types-with-modules` (dead, A42), `-with-prelude`, `-with-prelude-and-internal`, `-with-prepared-prelude`, `reader-result-for-checker`, `-with-reader-diagnostics`, `-with-marks`, `-in-context` | tools/golden, tools/ship; 24 suites |
254+| Report core | 15025-15146 | P | 1.2(a) | all 304 typed goldens; deferred-prepared [call] |
255+| dg-* | 15147-15656, 15704-15719 | R/G | R20 | deferred, deferred-context, deferred-prepared, deferred-resolver [call] |
256+| Fresh ids | 15658-15702 | G | `ienv-fresh-id` = one above the max id in env (declines on a pending `%tag`); stands in for a global fresh supply | deferred [call]; program recovery suites |
257+| grec trees | 15721-15835 | R | R18 | generic-*, union-source [call] |
258+
259+## 2. Inference today
260+
261+### 2.1 Unification and type comparison: one unifier, one fit, many special comparators
262+
263+| # | Comparator | Lines | Direction | What differs |
264+| --- | --- | --- | --- | --- |
265+| 1 | `itype-unify` | 4851-4940 | symmetric | The only structural unifier. Returns `(unit isub)` with no reason. Nominal rules: grec/jrec/recursive identity; union by origin then (argless) raw case equality or args; face names must match. Atom-kind lattice by pairwise cases 4884-4925. Never widens |
266+| 2 | `itype-fit` / `itype-fit-inner` | 5516-5711 | actual → expected | Widening (aura prefix, `@`, `*`, empty source), tag binding, ctor case selection; three-valued; calls unify for vars and as last resort. Gate types are compared by unify (invariant) except `itype-closed-gates-match` |
267+| 3 | `itype-fit-cases`, `itype-fit-ctor-cases` | 5451-5514 | actual → union cases | Each case tried from the original sub; unique `%ok` wins, two → `%unknown` |
268+| 4 | `itype-closed-gates-match` | 5229-5263 | symmetric, closed only | Gate equality modulo one omitted outer sample-slot face; all unifies from empty sub |
269+| 5 | `direct-invariant` | 9097 | both ways | Fit forward and backward plus a face-asymmetry test; 19 call sites, 16 in program/store recovery |
270+| 6 | `direct-function-fit`, `direct-positional-fit` | 9107, 9142 | both ways per slot | Two-slot gate samples matched with binder-face stripping, then replay must leave `sub`/`next` unchanged |
271+| 7 | `program-union-tag-case`, `program-single-case-fit`, `program-single-generic-fit`, `program-keyed-product-fit` | 13751-13853 | element messages | Select the one literal-tagged case, fit head and tail; element covariance only for a single case |
272+| 8 | `contextual-tagged-case` | 9545 | expected union | Unique const-headed case by head noun |
273+| 9 | Structural `=` on itype | 12782, 12805, 14314-14349, 14408-14470, 14599-14648; `infer-closed-cell-branch` 9616; `dg-stable-fit` 15427; `dg-stage-one` 22-field state equality 15458-15479; `program-init-model` replay 14163-14213 | exact | Prelude certificates and "stability" checks substitute for constraint solving |
274+| 10 | `union-relate` | 10994 | pattern overlap | Not a type relation; noun-shape projection used for disjointness |
275+
276+### 2.2 Substitution
277+
278+- Representation: `isub` assoc list (4688), prepended, never compressed; `itype-lookup` 4691 linear.
279+- Head walk: `itype-walk` 4698-4732, six identical arms (`%var|%fvar`, `%avar`, `%rvar`, `%nvar`, `%rnvar`, `%tag`) that stop at a self-binding to `%fvar`/`%rvar`/`%rnvar` (A16). Self-bindings are created at 4887-4889 (nvar~rvar), 4962 (gate-free form) and in `promote-restricted-numbers` (6119-6131). Any other self-binding loops forever (no fuel).
280+- Second walker: `dg-scan` 15150-15178 follows the sub with fuel; recognises only `%rvar`/`%rnvar` self-bindings, so an `%fvar` self-binding burns fuel and declines.
281+- Full application: `itype-normalize` 6012 (95 call sites); leaves `%tag`, `%recursive`, `%jrec` unexpanded.
282+- Whole-sub scans used as provenance screens: `contextual-simple-sub` 9519 (unbounded), `closed-cell-sub-safe` 9592 (512), `grec-direct-context` 9527 (4,096), `union-state-sub-budget` 11147 (256). Each declines if *any* entry binds a structural type, so behaviour depends on inference order.
283+- Mold-level substitutions (not the type substitution): `bind-params` 6873 (param name → arg type, by re-elaboration), `template-apply-sub` 6882 (rename scheme vars to args), `union-overlap-case` 11206 (tvar → arg pattern).
284+- Rollback is implicit: speculative attempts drop their returned state (`known-union-subject` 8541, closed-cell retry, tagged-case retry 9768-9774, direct-gate replay, `infer-recursive-gate` retry, failed locals).
285+
286+### 2.3 Generalization: six sites, four rules
287+
288+| Site | Lines | Rule |
289+| --- | --- | --- |
290+| Top level (`add-supported-result`) | 10682 | Quantify **every** variable of the normalized type. Sound only because each definition starts at `next=0` (10699) and the env holds closed schemes |
291+| Report (`golden-types-in-context-core`) | 15141 | Same, copied |
292+| Locals (`infer-local-defs`) | 7677-7681 | Type vars minus `free-env-vars(env)` (7307: normalizes every non-quantified var of every env scheme) minus `free-cap-vars(enclosing caps)` (7320) |
293+| Groups (`group-schemes`) | 10502-10504 | Same rule with the outer state's caps |
294+| dg (`dg-generalize`) | 15222 (called 15482) | Vars of the normalized type minus "blocked" = env-free (`dg-env` 15187, whole env scan) + obligation vars + tag-reachable vars (`dg-tags` 15209) + captured; bounded scan 32,768; ≤64 edges |
295+| Molds (`infer-mold-template`) | 6970-7000 | Exactly the fresh param ids; a nongeneric mold must be closed |
296+| Hand-built schemes | 12889, 12943, 13068, 14349, `store-derived-schemes` 14351 | `[… ~[0]]` literals |
297+| Recovery publication | via `add-supported-result` in 13444, 13600, 13927, 14107, 14149, 14306 | Then require `vars ~` and no `itype-vars` (closed-only) |
298+
299+Instantiation is one arm, `instantiate-scheme` 6355 (fresh ids from `next`, kind precedence, fresh atom/gate-free ids pushed onto `binders`, which is what lets `types-partial-atom-alias` re-generalize), plus `template-apply(-sub)` for molds and `itype-rename` 6219. Fresh ids for env-mixing code come from `ienv-fresh-id` 15666 (program recovery 13381, 13543, 13894, 14008, 14271; dg roots 15607, 15649).
300+
301+### 2.4 Branch joins: one join, several non-joins
302+
303+- Join rule (Q11, A133 fixed in 38c711c): `itype-branch-join` 5138 (two arms) and `itype-branch-join-list` 5202 (n arms), falling back to `itype-concrete-join` 5125. Callers: 8029 (list), 8073 (unit), 8226 and 8314 (union folds), 8919 (loobean; failures classified into five messages 8921-8929), 15333 (dg boolean).
304+- Checking-mode branches do not join; each arm is fitted to the expected type and the result is `expected`: `infer-union-context` 7763, `infer-known-union-context-whole` 8246, `infer-known-union-finite` with expected 8292, `infer-single-case-branch` 8361, `infer-cell-branch` 9894, `infer-unit-branch`/`infer-list-branch` with expected (A133 note).
305+- Other "joins": open list literal items are fitted to one element var (`infer-open-list-items` 7879, messages `list item widening is not supported` / `list items do not have compatible types`); `infer-closed-cell-branch` 9616 requires the two arm results to be equal and closed; `dg-boolean-branch` 15316 falls back to a fresh result var with two `dgo` edges.
306+
307+### 2.5 Pending constraints (no queue)
308+
309+| Constraint | Where held | Created | Checked | Outcome when unresolved |
310+| --- | --- | --- | --- | --- |
311+| Tag/`~` literal, ctor | `istate.tags` (`ipending`) + `%tag` pseudo-var | 8780, 8781, 8848 | end of each definition: `pending-tags`/`pending-null` 5351-5370 | locals wait (7673); top level dropped (10680); report prints `tag needs context` / `` `~` needs context `` (15131-15134); groups fail (10529); dg fails (15503); full check explains with `module-pending-tag` 10715 |
312+| Type hole | `istate.holes` (`ihole`) | 7103 | `default-hole-numbers` 6133, `unresolved-hole` 6168 | error (locals, report) or drop (top level); groups reject any new hole (10527) |
313+| Decimal literal | `%nvar`/`%rnvar` | 8773 | `default-decimals` 6062 at top level (10679), report (15130), `width-finalize` | locals do **not** default before generalizing; groups/dg reject `%nvar` (10499, 15481) |
314+| Atom-kind var | `%avar`/`%rvar` + `binders` | 5666, 4887, `instantiate-scheme` | `unsupported-atom-vars` 10159 | locals wait; top level drop; report `unresolved aura-variable inference` |
315+| Written capitals | `istate.caps` | `reserve-def-caps` 7509 | `merged-capitals` 10072, `constrained-capitals` 10089 | definite error (locals, report) or drop |
316+| `proj` | `istate.projections` | 9461 | `width-finalize` 10535 | drop / report message; groups reject |
317+| Call/cast fit `%unknown` | nowhere |: | immediately | `call/cast constraint is not supported…`; in defer mode a `dgo` |
318+| Deferred fit edges | `istate.obligations` (`dgo`) | 9262-9265, 15316, 15355 | `dg-replay-edges` 15252 at transaction close | whole transaction declines; outside dg any obligation is an error (7661) |
319+
320+Nothing carries a constraint from one definition to the next except the dg transaction. A later definition (e.g. `main`) can never fix an earlier definition's tag; that is why the program recovery arms exist.
321+
322+### 2.6 Order of solving
323+
324+Synthesis is left-to-right and eager: every fit is decided when it is met, with `%unknown` meaning "give up". Expected types flow only through `infer-call-context-arg` 9664 and its ~19-step ladder; casts and known call samples are the only sources of context.
325+
326+### 2.7 Fixpoints and retries
327+
328+| Loop | Lines | Bound | Notes |
329+| --- | --- | --- | --- |
330+| Module resolver | 10749-10756 | env stops changing | One productive pass in dependency order (839f6b0) plus a confirming pass; fixpoint kept as fallback (A135) |
331+| `add-supported-defs-core` | 10690-10709 | one pass | Retries `infer-recursive-gate` after every failed `infer-fragment` (10705), gate or not (A33) |
332+| `add-groups` | 10645-10660 | one pass per resolver iteration | Errors discarded |
333+| Locals | 7624-7639 | progress | Pass loop; then `graph-components` + `try-local-group` 7686; then the order-independence rules decide definite vs `local definitions need unsupported inference` (7637) |
334+| dg-stage | 15496-15522 | ≤64 defs, fuel² = 4,096 attempts | Retry `(flop waiting)`; close: replay edges twice and require unchanged `sub`/`next` (15501-15510) |
335+| Program recovery | 14786-14804 | single pass | No fixpoint; order matters |
336+| Report | 15079-15146 | one pass | Re-infers every non-group definition after resolution |
337+| `module-pending-tag` | 10715-10734 | fuel 64 | Failure-path re-inference only |
338+| Replay "stability" checks | 9142/9191 (direct gate), 9616 (closed cell), 14163-14213 (init model), 15501-15510 (dg) |: | Stand-ins for "the constraints are solved" |
339+
340+### 2.8 Definition finalization: five copies
341+
342+| Step | `add-supported-result` 10670 | report 15117 | locals 7659 | groups 10488/10509 | `dg-stage-one` 15445 |
343+| --- | --- | --- | --- | --- | --- |
344+| obligations unchanged |: |: | 7661 | refuses defer 10512 | collects them |
345+| `promote-restricted-numbers` | 10675 | 15117 | 7662 |: |: |
346+| `default-hole-numbers` | 10676 | 15118 | 7663 | holes must not change 10527 | holes unchanged 15477 |
347+| `unresolved-hole` | 10677 drop | 15119 message | 7664 fail |: |: |
348+| `merged-capitals` |: (only via constrained) | 15122 long text | 7666-7669 long text | 10493-10495 short text | any written capital declines 15452 |
349+| `constrained-capitals` | 10678 | 15128 | 7670 | 10496 |: |
350+| `default-decimals` | 10679 | 15130 | **none** | nvar → fail 10499 | nvar → decline 15481 |
351+| `pending-null` |: | 15131 |: |: |: |
352+| pending tags / tag in type | 10680 drop | 15133 | 7673 wait | 10529, 10500 | blocks generalization; 15503 at close |
353+| hidden recursive/generic name |: | 15135-15138 |: | 10500 | `dg-interface-safe` 15573 at publish |
354+| `unsupported-atom-vars` | 10681 drop | 15139 | 7675 wait | 10500 | 15480 |
355+| quantify | all vars 10682 | all vars 15141 | minus env/caps 7677-7680 | minus env/outer caps 10502-10504 | `dg-generalize` 15482 |
356+| `width-finalize` | 10683 | 15142 | (left to the enclosing definition) | projections must not change 10525 | projections unchanged 15479 |
357+
358+## 3. Recovery slices
359+
360+"Would fail if removed today": `[call]` suites name the slice's arms and stop compiling if the arms go; `[out]` suites or goldens whose expected output depends on the path (from fixtures; not executed). **No typed golden reaches R1-R10, R18 or the full-check side of R20**, because the report (15025) runs no recovery, no kind check and no grec index, and the only goldens whose case-local modules have a `main` (`module-import-api-import-error`, `module-import-store-derived-clash`, `module-import-store-face-clash`, all importing a cart store) stop at the derived-name clash before inference. Those slices are pinned only by `tests/lib`.
361+
362+### 3.1 Example-fitted slices
363+
364+| # | Slice | Lines | Serves | Does instead of ordinary inference | Would fail if removed |
365+| --- | --- | --- | --- | --- | --- |
366+| R1 | Update recovery `program-update-context` | 13342-13450 | Todo island `update` (`my-app/ui/todo-list.jibb:16-25`) and basket `update`: bodies end in `[m ~]` and `\|=%acked`, whose tags have no context inside the definition, so `add-supported-result` drops them (10680) | Reads message/model from the written two-slot sample (binder faces stripped), builds `[model (list (cmd message))]` from prelude templates, proves it against program's instantiated slot with `direct-invariant`, checks the body in context, casts, merges faces, publishes only a closed scheme | [out] program-update (all `tests/type-program-update/*`), todo-full, store (basket), page-main (`index.jibb` imports `todo-list`), program-init (needs the update relation) |
367+| R2 | Subs recovery `program-subs-context` | 13505-13606 | Todo `subs ~[[%watch (todos.todo \|=%got)]]`, basket `(state.cart \|=%got)` | Same pattern with `(list (sub message))` and program slot 4 | [out] todo-full, store, page-main, program-init (`initializer-subs`) |
368+| R3 | Keyed view recovery `program-view-context` + view-site walker | 13608-13749, 13938-14155 | Todo `view` with exactly one `each (turn todos.m row-of)` and the mapper `row-of` | Finds the site syntactically, instantiates `each`/`turn`, infers the mapper and the view against hand-built `element message` types, publishes both mapper and view | [out] todo-full (`expected`, `alias`, `ambiguous-mapper`, `open-key`, `non-gate-view`, `wrong-*`), page-main, program-init (`initializer-open-view`) |
369+| R4 | Plain view `program-plain-view-context` | 13855-13936 | Basket `view` (no keyed site, 4bf477e) | Checks the body against `(element message)`; does not check program slot 3 (A48 drift) | [out] store (basket) |
370+| R5 | Initializer `program-init-model`, `program-init-ordinary`, `program-plain-init-context` | 14157-14312 | Todo `init \|= ts=(list item.todo) [ts "" ~]` (`~` needs context), basket `init \|= ~` | Model from the update relation or from a tentative positional fit of main's args (`direct-positional-fit` + replay stability), then context check of the body; ordinary fallback in a separate state | [out] program-init (17 `initializer*` fixtures), todo-full (`cast-init` guards ordering), store, page-main |
371+| R6 | Main completion and program kind check `program-main-context`, `program-main-closed`, `program-subs-watch`, `program-subs-empty` | 13311-13340, 14367-14403, 14472-14482, 14555-14582 | Any direct `(program i u v s)` main | Re-infers `main` after recovery (only agreement check); kind check instantiates program from `*istate`, requires closed invariant main, gate-free init data and model (256 shared budget), and one syntactic watch shape | [call] program-main, program-watch, store (`program-main-closed`); [out] program-main, program-watch, todo-full, store, page-main, program-update/init |
372+| R7 | Element message fits and the list-item hook | 7887-7891, 7909-7913, 9355-9394 (element exception in `infer-contextual-call`), 13751-13853 | Todo union controls (`button "Add" %submit`, `field … \|=%typed`), raw constructors (docs/compiler.md:153) | When an ordinary list-item fit to a prelude `element` union fails, prove the message argument invariantly or pick the single literal case; pre-unify recursive `element` results | [out] todo-full, store, buttons; goldens `types-prelude-ui` (`bad-child` and element lines), probably `doc-grammar-02-buttons` (`labelled`) |
373+| R8 | Store kind and main recovery `store-update-unfaced`, `store-main-closed` | 14584-14648, swap 14844-14849, completeness exception 14817-14819 | Cart store `my-app/ui/stores/cart.jibb` ("The builder erases the action from main", 14597) | Checks prelude `store` value and mold by `=`, checks init/update against local `state`/`poke` invariantly, publishes `[canonical ~]` as `main` even if `main` never inferred | [out] store (cart, basket); compiler.md:143 |
374+| R9 | Static main `static-main-specialized` | 14484-14508, swap 14836-14843 | `about.jibb` `++ main view` | Instantiates main from `*istate`, fits into `(element !!)`, publishes the canonical closed scheme | [out] page-main (about, `wrong-static`) |
375+| R10 | Page kind `page-load-derived`, `page-main-closed` | 14510-14553 | `index.jibb`, `blog/index.jibb` | One syntactic load shape `case.face reply`, provenance via `derived-request-member` | [call] page-main |
376+| R11 | Direct gate-layout evidence `direct-*`, `istate.gate-defs/head-evidence` | 9002-9228; set at 10701-10702, 15108-15109, recovery arms | `(program init update view subs)` with a faced `update \|= [=msg m=model]` against prelude `update=$-([M X] …)` (`prelude.jibb:534`) | After an ordinary call fit is not `%ok`, re-parse the prelude (A132), match written gate samples slot by slot, both ways, then replay | [call] direct-gate-guards; [out] direct-gate-source (`tests/type-direct-gate`), program-main, program-update, todo-full; golden probably `types-prelude-ui` `++ concrete-program` (line 72 of its source) since the report sets `gate-defs` |
377+| R12 | Closed gate sample matching | 5229-5263 (called 5701, 5316) | Todo API named closed fold gates (a1c5f35; contract 4643-4644, 4653-4655) | Gate equality ignoring one outer slot face | [out] closed-gate-guards (through `itype-fit`), todo-api, todo-full, program-watch, page-main |
378+| R13 | Positional face rule | 5313-5349, 9285 | `like` result mapping (640a442) | Ignore one sample-slot face per written argument | [call] positional-face-guards, direct-gate-guards; goldens `types-positional-faces`, `types-prelude-like` |
379+| R14 | Closed-cell branch retry | 9564-9662, dispatch 9743 | Todo `update` inner `?- (gth …)` returning `[m(...) ~]` (22f3788) | Re-check a two-loobean branch against a cell target from the original state; results must be equal, closed, tag-free; replay | [call] cell-branch; golden `types-cell-branch-context`; [out] todo-full |
380+| R15 | Contextual tagged case | 9477-9562 (`contextual-tagged-case` 9545), dispatch 9753-9780 | Todo `subs` body `~[[%watch (todos.todo \|=%got)]]` (72acdb3) | Try ordinary inference; else select the union case by literal head and check the payload in context | [call] nested-union-guards; goldens `types-nested-union-context`, `types-nested-shallow-preserve`; [out] todo-full |
381+| R16 | `infer-contextual-call` element exception | 9355-9394 | Todo controls, `\|=%got` callbacks | Pre-unify a same-origin generic union result with the expected type; recursive only for prelude `element` | goldens `types-generic-result-context`, `types-prelude-ui` (likely); [out] todo-full |
382+| R17 | `%jrec` / qath | 4680, 6925-6952, 8392-8420, 8757-8763, 8807-8821, 9699-9714 | Internal prelude `qath` (`internal.jibb:15-17`, 0ea700d); theme `font=` qath literal; `image`/`link` | Recognise `~ / [h=@aura t=self]`, unfold one layer per fuel (256 per definition) for matching, construction and static path literals | [call] qath-fuel; qath-source, theme; goldens `types-qath-*`, `types-arithmetic-proj-qath`, `types-prelude-ui` (`image-scheme`, `link-scheme` print `qath`) |
383+| R18 | `%grec` generic tree | 4681, 6954-6968, 8422-8475, 9527-9539, 9684-9698, 15721-15835, 4801 | Test-only node tree (`tests/type-generic-recursion`, c96597d) | Fixed two-case shape proof; one-layer view for patterns/construction; index only for import-free prelude-backed modules (14762-14772) | [call] generic-recursion, generic-construction, generic-pattern, union-source; golden `types-generic-recursive-union` only as an unsupported control |
384+| R19 | Union source disjointness, state screen, source overlap witness | 11024-11187, 11189-11273 | One-hop local generic alias with a literal head (b93a94b) | Bounded syntactic proof of distinct heads / positive overlap when projection is unknown | [call] union-source, union-alias-overlap, full-overlap-basic; goldens `types-union-source-alias`, `types-prelude-succ` |
385+| R20 | dg-* deferred transaction | 15147-15656, 15704-15719; hooks 8854, 8879, 8951, 9261-9265, 9281, 9667-9669, 10288, 10512 | Import-free modules without a prelude (full check, 14807-14816); prepared-prelude reports whose fixture is the todo initializer `[xs "" ~]` closed by a later cast (`tests/type-deferred-prepared/good.txt`) | Re-infer definitions with obligation edges for literal branch arms, tuple items and ctor args, retry to a fixpoint, replay edges twice | [call] deferred, deferred-context, deferred-prepared, deferred-resolver; goldens `types-constructor-context`, `types-union-singleton` reach the screens but the transaction declines (report unchanged) |
386+| R21 | Prelude bootstrap | 11826-12024 | `prelude.jibb`, `internal.jibb` | `standard-prelude-list` pattern-matches `\|$ [A] $@(~ [i=A t=(list A)])` and publishes `%collection`; six hard-coded primitive schemes (11930); `infer-private-internal` proof retry; `prelude-label*` | all module-check goldens and 33 suites that prepare the prelude |
387+| R22 | API narrow branch `one-request-interface-graph` | 12904-12956, 14711-14721 | Blog API (one mark import, non-union paths) | Hand-built one-request interface; redundant with multi-request (A44); `one-request-interface-source` 12850 is dead | [out] page-main (blog API), request-guards |
388+
389+### 3.2 Ad hoc slices of general inference (not fitted to one example, but replaced by the core)
390+
391+| Slice | Lines | Replaced by |
392+| --- | --- | --- |
393+| Two-arm unit/list branches | 7923-8075 | usefulness over `~`/cell constructors |
394+| Three coverage loops + 64-row loobean expansion | 8103-8350 | usefulness |
395+| One-arm structured / cell-binder / empty-list / empty-union | 8351-8390, 8555-8608, 9852-9928 | one-row usefulness, empty types have no constructors |
396+| Speculative subject screens | 8477-8549 | infer subject once |
397+| `recursive-branch-seed`, blanket `infer-recursive-gate` retry | 10216-10325, 10705, 10729, 7646 | SCC let-rec with levels |
398+| `known-union-subject` double inference | 8541 |: |
399+| Loobean join failure classification | 8920-8929 | one join + deferred widen |
400+| Import-invalid replay | 7002-7097 | elaboration returning reasons |
401+| `module-pending-tag`, `module-missing-value`, `module-sample-shadow` | 10715, 12132, 12171 | per-definition errors from the core |
402+| Order-independence rules for locals | 7521-7584, 7633-7637 | SCC order + deferral |
403+
404+## 4. What the core replaces, what it must keep, and the hazards
405+
406+### 4.1 Replaced
407+
408+| Core piece | Replaces |
409+| --- | --- |
410+| Union-find store over a map, path compression, one global fresh counter | `isub`/`ibinding` 4687-4688, `itype-lookup` 4691, `itype-walk` 4698-4732, `dg-scan` 15150, `ienv-fresh-id` 15666-15702, per-definition `next=0` (10699, 10752, 14759, 15107) |
411+| Kind on the root (any ⊐ gate-free ⊐ atom ⊐ atom-other-than-? / defaultable number) | `%fvar %avar %rvar %nvar %rnvar` (4666-4670), the pairwise lattice 4884-4925, self-binding refinement (4887-4889, 4962, 6119-6131), `itype-bind-gate-free` 4998 and its 256 budget, `itype-var-is-*` 6267-6343, `binders` bookkeeping for `unsupported-atom-vars` 10159 |
412+| Levels | `free-env-vars` 7307, `free-cap-vars` 7320, `shared-types`/`shared-moved`/`closed-local` 7534-7584, `dg-env` 15187, `dg-generalize` 15222, all-var quantification 10682/15141 |
413+| Deferred-constraint queue (woken on binding, reported at module end) | `%tag` + `ipending` + `pending-tags`/`pending-null` 5351-5370 + drop at 10680 + `module-pending-tag` 10715; holes 6133-6181 (as level-exit obligations); decimal defaulting 6062 and promotion 6119 (as level-exit defaulting); fit `%unknown` (5527-5711) as "enqueue"; `itype-fit-ctor-cases` 5474; field access 7720, change 8622, interpolation 8081, `proj` 9461, cell/cons literals 7834; the whole dg-* transaction 15147-15719 and its hooks |
414+| Bidirectional check mode (synthesize then unify/subsume with expected; push expected into arms and items) | most of `infer-call-context-arg` 9664-9783: contextual branches 7749-7921, unit context 9321, singleton 9480, tagged case 9477-9562, closed-cell retry 9564-9662, `infer-contextual-call` pre-unify 9355 |
415+| Maranget usefulness over a constructor signature taken from the subject type | 7923-8075, 8103-8390, 8395, 8425-8475, 8477-8608, 9852-9928, `dg-boolean-patterns` 15292; branch routing 8878-8930 |
416+| One nominal recursive mold `(module, name, args)` unfolded on demand | `%recursive`/`%jrec`/`%grec` 4679-4681, `simple-source-recursive` 6925, `simple-source-generic-recursive` 6954, `jrec-match-view`, `qath-static-fuel`, grec 15721-15835, `jrec-fuel` |
417+| SCC driver, one pass, scheme-or-error per definition | `resolve-groups-core` fixpoint 10736-10756, `add-supported-defs-core` retries, `add-groups`, locals' pass loop 7611-7681, `try-local-group` 7686, `dg-stage` 15487 |
418+| `main` as an ordinary application, sample-slot faces as labels | program chain 13342-14482, `direct-*` 9002-9228, `itype-closed-gates-match` 5229-5263, positional face rules 5313-5349, element fits 13751-13853 and hooks 7887-7891/7909-7913, `static-main-specialized` 14487, store component recovery 14599-14648 |
419+| One pipeline (Q6) | report re-inference 15079-15146; its separate finalization 15117-15143 |
420+| Five finalization copies (2.8) | one generalization step at level exit |
421+
422+### 4.2 Kept (retargeted to the new representation, behaviour preserved)
423+
424+- **Printers**: `show-itype` 9930-9995 (A-Z then T26…, `(label args)`, space-separated unnamed unions, parenthesised in context), `site-type-note` 10024, `show-atom-constraint` 10171, `canonical-itype` 6345 with `itype-vars` order 6183 (fn sample before product, head before tail, union args before cases) and kind precedence rvar > avar > fvar > var, `show-partial-mold` 11431 (until Q6 changes the report), `show-inference-diagnostic` 11458, `show-duplicate-fields` 11470, `prelude-label*` 11870-11911, `itype-in-import` labels 6806 (display separate from identity).
425+- **Error wording and site notes** (golden-pinned; full list in 4.3).
426+- **API path analysis and derived interfaces**: 12326-13144 and 14314-14470, `derived-name-clash` 13289, request-graph 12202-12274, watchability; they synthesize schemes into interfaces before consumers are checked. The hand-built schemes should become instantiations of declared templates.
427+- **Hoon importer bridge**: 6397-6728 plus `jibb-dev/lib/jibb-import.hoon`; the import-invalid wording (`invalid imported mold` + importer message).
428+- **Overlap witness and disjointness**: `upat`/`union-relate`/`union-pairs` 10904-11022/11275, `mold-overlap-witness` 11296, `module-mold-overlap` 11786, `jfile-overlap` 11513 evidence. `union-relate` is also the importer's disjointness relation (6477, 6665), so either keep `upat` as the importer projection or give itype a pattern view.
429+- **Pre-inference passes**: duplicate fields 11520-11693, scope and reserved `proj` 11694-11773, dependency extraction 10327-10428, Kosaraju 10552-10643, value-cycle diagnosis 10785-10900 (wording), module graph and cache 12190-12324.
430+- **Elaboration**: `infer-simple-shape` 7099 / `infer-mold-template` 6970 / `label-direct-union` 6843 (mold → type, origin assignment), `proj` planning 5835-5923, 9396-9475, `width-finalize` 10535 (artifacts), `gate-free-type` 5925-5992 as a post-solve check with witness path.
431+- **Kind boundary** as post-solve matching of `main`'s closed type against prelude molds; watch/load provenance checks; store-derived exports.
432+
433+### 4.3 Hazards
434+
435+1. **Golden output moves.** All 304 `types.txt` come from the report path. Pinned fail-closed lines: 80 `tag needs context in partial inference`, 24 `` `~` needs context ``, 32 `call constraint is not supported…`, 37 `cast constraint…`, 5 `record width constraint…`, 5 `proj constraint…`, 6 `type hole needs unsupported inference`, 6 `unresolved aura-variable inference`, 4 `call result face propagation`, 31 `local definitions need unsupported inference`, 47 `name is not available to partial inference`; 127 goldens contain some unsupported text. Mold lines: 171 `+$ X: not checked`, 171 `cases proven disjoint; mold not checked`, 6 `case disjointness unresolved`, 22 `overlapping cases`. A stronger core changes these; each stage must either keep the exact `%unknown` sites or budget a deliberate golden update (Q6 predicts ~283 outputs change once).
436+2. **Definite wording to keep byte-exact**: `call's sample and argument types do not unify` + `called gate`/`argument` (116 golden lines, 53 goldens); `branch arms have incompatible types` + `first arm`/`second arm`; `cast mold and expression type do not unify` + `cast mold`/`expression`; `{label} has no case `%x`` + `expected union`/`tag` (8706); `record has no field `x`` + `unknown field`; `change field and replacement do not unify`; `a change takes at least one field` + `empty change`; `missing union case X` (no sites, first remaining case); `branch arm is covered by earlier arms` + `covered arm`; `branch does not cover both loobeans`; `nothing fixes the union of %x` (5363; `tests/type-buttons/error.txt`, program-init, program-update; not in any golden); `non-gate value depends on itself through a cycle` + `value in cycle`/`dependency in cycle`; the long capitals message (7669, 15126) vs the short one (10495); `type hole needs a determined type` + `unresolved type hole`; `a generic atom in interpolation needs an aura`, `a cell in interpolation needs a printer`; `record field `x` is repeated` + `first field`/`repeated field`; derived-name clash texts; module/API texts in 1.2(b).
437+3. **Sites decide definiteness.** `definite-diag` 7521 treats site-less diags as retryable; several definite-sounding errors have no sites (`missing union case`, `pattern binder shadows a name`, `unit present pattern is unreachable`, `sample shadows a name`). Adding sites changes local-definition outcomes (they stop ending as `local definitions need unsupported inference`).
438+4. **Message precedence is order-dependent**: report checks 15117-15143 in fixed order; loobean join classification 8921-8929; missing tag → nested tag → generic after every `%bad`; union coverage checks `%unknown` before coverage and `covered` before `not supported` (A15); locals report the earliest failing local (`rear sure`, 7636); finite expansion prints `%.n` rows before `%.y`; the full check reports pending tag, then shadowing sample, then missing value (14821-14832); API precedence poke-only → clash → scope → import error → constructor reason.
439+5. **Unification semantics goldens rely on**: unequal atoms never unify; argful named unions unify by args only, argless by raw case equality (A11); `%var` binds faces, unions, tags; a `%tag` vs non-var fails in unify; faces must match by name; fit is invariant for gates; `*` accepts gates (A23, pending Q18) and binds bare tags (A22); term literal fits `@tas`/`@ta` with no aura check (A20); `?` vs `@f` is unknown; zero vs list unknown; only `@` allocates in fit.
440+6. **Self-binding invariant**: any self-binding other than `%fvar`/`%rvar`/`%rnvar` loops `itype-walk`. A staged migration that keeps `isub` alongside a union-find store must keep this invariant or convert at the boundary.
441+7. **Ids**: ids restart at 0 per top-level definition, `itype-rename` is single-pass, so scheme ids may coincide with fresh ids by design (6008-6010); `module-mold-types` reuses one base state per mold, so template ids repeat. A union-find store must never assume scheme ids are globally unique; instantiate always.
442+8. **Rollback**: speculative attempts drop state; tests assert that failed retries return the original result and replays leave `sub`/`next` byte-identical (cell-branch, direct-gate-guards, deferred). A mutable store needs a trail/snapshot or a persistent map.
443+9. **Provenance screens**: grec, tagged-case and closed-cell screens decline if any substitution entry is structural; `infer-call-context-arg` reads raw `expected` at 9732, 9743, 9756. Behaviour of these slices depends on inference order; a new store changes when they fire.
444+10. **Budgets pinned by tests**: `jrec-fuel` 256 (qath-fuel uses 0/1/2); grec arms 128; closed-cell screens 512 (cell-branch tests the limits); `union-source-distinct-tags` 18 ok / 17 declines; `union-source-overlap` 20/19; `module-mold-params-valid` 256/257; `union-source-state-safe` 256/257 caps; `dg-direct-source` 63/64 wrappers, `dg-source-candidate` 64/65 defs; `ienv-fresh-id` results `2.000.002`, `1`, `10`; `dg-generalize` results `~[43]`, `~[81]`, `~[722]`, `~[713]`. Other literals: empty proof 256 in fit, live cases 4,096, inhabitation 256, finite 64, width 1,024/4,096, gate-free 256, obligations 62/63/64, `module-pending-tag` 64, request graph 256/256, `api-request-gates` 256.
445+11. **`istate` shape**: 27 positional fields at 10 literal sites, 5 bunts, `dg-stage-one` compares 22 fields (15458-15479), 13 suites use `istate:jibb`, all by bunting `*istate:jibb` and setting fields by name. Adding union-find, level or queue fields touches the 10 literal sites; a constructor arm (A28/A125) should come first.
446+12. **Interfaces are hashed nouns**: `iwidth-definition` carries the raw `sub` (10687) into `ifile.elaborations`; cache reuse compares inputs by equality (12219, 12275). Changing the representation changes interface nouns, cache keys and anything comparing `ifile`s (`request-graph-merge` dedup, `derived-request-member` evidence equality).
447+13. **Structural `=` certificates**: `compatible-raw-poke`, `request-compatible-ask`, `derived-poke-command-scheme` (five `cmd` cases in order `poke go wait now who`, label `raw-poke`), `store-main-closed`, `derived-request-member` (`∀m. $-($-(full m) (ask m))`), `derived-store-request-member`. A new var representation must keep these equal or replace them with template comparisons; any edit to `prelude.jibb`/`internal.jibb` silently disables them.
448+14. **Printer stability**: variable letters depend on `itype-vars` order and kind precedence; `site-type-note` suppression rules; nvar/rnvar print as atom constraints; `(unit qath)` and other public labels rely on `prelude-label-nested` (A134; jibb-theme).
449+15. **Prelude identity checks**: exact list scheme compared at 7844, 7996, 8572, 8800, 14767 (and built at 11920, 11979, 12013, 12064); unit via `standard-unit-template` 8646; `element` by origin `[at.prelude %element]`; qath must be `%jrec` at `/lib/jibb/internal/jibb` (8816). The core must expose the same identities or these paths all fail closed.
450+16. **Two pipelines**: changing the resolver or finalization in one pipeline without the other moves goldens or suites (A46, A122). The golden report also runs the full check on imported case-local modules (14989), so module-check goldens see both.
451+17. **Recovery adapters**: until R1-R10 are retired, they call `itype-fit` (22×), `itype-merge-faces` (12×), `instantiate-scheme` (12×), `direct-invariant` (16×), `template-apply` (15×), `infer-sample`, `reserve-def-caps`, `record-fields-named`, `itype-in-import`, `add-supported-result` (6×), `infer-call-context-arg` (6×), `ienv-fresh-id`; and they mix substitutions on purpose (body inferred from the sample's own sub with the gate-fit's `next`, 13418-13421; mapper from `initial`). A core that threads one store changes their edge behaviour.
452+18. **Negative fixtures that encode recovery limits, not spec errors**: `tests/type-todo-full/ambiguous-mapper.txt`, `alias.txt`, probably `open-key.txt`; generic strings `module definitions need unsupported inference: /p: ++ name` and `module kind needs unsupported inference: /p` asserted by program-update/init/main. An ordinary-application core will accept or reject these differently; decide per fixture.
453+19. **`program-single-generic-fit` is in ordinary inference** (7890, 7912) for any prelude `element` target, so removing the program recovery does not remove it; `types-prelude-ui` and `doc-grammar-02-buttons` depend on the path that reaches it.
454+20. **Performance**: assoc-list lookups and 95 `itype-normalize` calls; `unique-type-vars` O(n²); `free-env-vars`/`dg-env` rescans per generalization; `itype-fit-cases` re-fits every case; subjects inferred twice; whole-to-finite re-inference; prelude re-parsed per `direct-prelude-evidence` call (A132); report re-infers every definition; compiler.md:67-69 reports 38-72 s CPU for 2,000 gates. Brief l.141 asks for seconds.
455+21. **Deviations from the spec the core should not copy unknowingly**: gates fit `*` (Q18 pending), tag fits `@tas`/`@ta` without aura check (Q16/Q17), faces handled by asymmetric guards instead of "unnamed acquires the face" (S1 pending), argless union identity by raw cases (A11), only list/unit in inhabitation/gate-free (A13), arms matching no case reported as unsupported (Q22), decimal defaulting skipped in locals and gate types (compiler.md:59 notes defaulting in gate types is incomplete).
456+22. **Dead code not to port**: `itype-has-fixed-atom` 5098, `width-has-projections` 8988, `infer-width-elaboration` 8995 and `iwidth-elaboration` 8994, `direct-find-gate` 9058, `resolve-supported-defs` 10780, `golden-types-with-modules` 14939, `one-request-interface-source` 12850, unreachable `!!` at 14258 and 14525, the last `[%& …]` of `dg-boolean-branch` (15351), the always-`~` `captured` argument of `dg-generalize`, misplaced headers (5014-5018, 6008-6010, 6320-6321, 6397-6403, 5835-5837), the stale comment at 11502-11505.
457+
458+### 4.4 Seams a staged plan can use (observations, not a plan)
459+
460+- `golden-types-in-context-core` re-infers each definition independently (15107-15114), so a new core can be swapped in per definition behind the same printer and finalization, leaving `resolve-groups` in place, before the full check changes.
461+- The full check's recovery chain only runs for components still missing after `resolve-groups-core` (`?^ (ienv-lookup …) ~` at the top of each arm). A core that resolves a component ordinarily turns its recovery arm into a no-op without deleting it; the `cast-init` regression already guards that ordering.
462+- `itype-fit`'s three-valued API can be preserved over a new store as long as `%unknown` stays the answer for "would need a queued constraint" in the old callers; R1-R10 are its heaviest users.
463+- The dg-* transaction is reachable from the full check only without a prelude (14809) and from the report only on eligible sources; its tests are self-contained (four suites), so it can be retired as a unit once the queue exists.
464+
465+## 5. Entry points that must stay stable during a staged migration
466+
467+### 5.1 Tools (signatures are checked)
468+
469+| Arm | Line | Caller |
470+| --- | --- | --- |
471+| `golden` | (%api chapter) | `tools/golden` (parser outputs), module trees |
472+| `golden-types` `[file=path src=@t] -> @t` | 11486 | `tools/golden:251-253` (signature enforced at `tools/golden:407-408`), `tools/ship:1234` |
473+| `golden-types-imports` | 11497 | `tools/golden:252`, `tools/ship:1257` |
474+| `golden-types-with-marks` | 15016 | `tools/golden:248`, `tools/ship:1288` |
475+| `golden-types-with-prelude-and-internal` | 14969 | `tools/golden:259`, `tools/ship:1345` |
476+| `golden-types-with-prepared-prelude` | 14975 | `tools/golden:260`, `tools/ship:1346` |
477+| `prepare-prelude-with-internal` | 12103 | `tools/golden:291` (under `mule`), `tools/ship:1222` |
478+
479+### 5.2 Module-check API (suites, and itself recursively)
480+
481+`infer-jibb-file` 14650 (23 suites; also builds the internal prelude, 11956), `infer-jibb-file-detailed` 14658 (12 suites; `resolve-jibb-imports-detailed` 12316/12320), `resolve-jibb-imports` 12286 (deferred-resolver, generic-recursion), `prepare-prelude` 12092 (api-evidence, poke-bridge), `prepare-prelude-with-internal` (33 suites), `golden-types-with-prelude` 14955 (bridge, list-alias-guards, module-scope), `golden-types-with-reader-diagnostics` 15007 (bridge, import-*), `golden-types-in-context` 15021 (empty, union-alias-overlap, union-source), `golden-types-in-context-core` 15025 (deferred-prepared), `gate-free-mold-source` 14887, the API evidence arms (`api-path-analysis(-source)`, `api-path-evidence-source`, `api-path-parameters`, `api-path-watchability`, `api-request-parts`, `api-support-analysis-source`, `api-poke-interface`), `find-jibb-cache`, `request-graph-bounded`, `request-graph-reusable`, `module-scope-valid`, `module-mold-params-valid`, `program-main-def`, `program-main-parts`, `page-main-parts`, `parse`, `show-error`, `show-itype` (11 suites), `canonical-itype` (buttons, deferred-resolver, doc-examples), `record-fields-named` (program-init/main/update/watch), `itype-in-import` (5 suites), `itype-vars` (page-main, program-watch, store, theme), `ienv-lookup` (17 suites), `find-jibb-mold` (13 suites), `find-jibb-interface`, `find-simple-mold`, `collect-simple-molds`, `find-imported-mold`, `find-imported-mark`, `import-to-itype`, `template-apply`, `identity-union-parameters`, `prelude-union-alias`, `compatible-raw-poke`, `request-compatible-ask`, `derived-poke-command-scheme`.
482+
483+### 5.3 Substrate arms called by suites (keep or migrate the suites in the same stage)
484+
485+`itype-fit` (8 suites: arithmetic-guards, closed-gate-guards, constructor-fit-guards, deferred, empty, generic-construction, generic-recursion, qath-fuel), `itype-unify` (arithmetic-guards, gate-free-guards, generic-recursion), `itype-unify-test` (typecheck), `itype-walk` (arithmetic-guards, deferred), `itype-lookup` (hole-guards), `itype-normalize` (deferred, generic-construction), `itype-empty-proof`/`itype-inhabited-proof`/`itype-live-cases`/`empty-list-null-branch` (empty), `itype-gate-free-form`/`itype-collection-keys`/`itype-var-is-gate-free`/`instantiate-scheme`/`template-apply-sub` (gate-free-guards), `gate-free-type` (empty, gate-free-guards, generic-recursion), `itype-has-face` (deferred, empty), `itype-face-asym`/`itype-output-may-be-cell`/`pending-tags`/`unsupported-atom-vars` (deferred), `itype-positional-face-asym` (positional-face-guards), `itype-positional-slot-face-asym` (direct-gate-guards), `itype-fit-ctor-cases` (constructor-fit-guards), `itype-has-gate`/`default-decimals` (generic-recursion), `default-hole-numbers`/`simple-mold-hole` (hole-guards), `infer-fragment` (cell-branch, deferred, generic-pattern, qath-source), `infer-call-context-arg` (generic-construction, qath-fuel), `infer-simple-shape` (union-source).
486+
487+### 5.4 Recovery and dg arms called by suites (retire with their suites)
488+
489+direct-gate-guards: `direct-checked-gates`, `direct-gate-call-fit`, `direct-gate-sample`, `direct-positional-fit`, `direct-prelude-evidence`. cell-branch: `closed-cell-branch-eligible`, `closed-cell-retry-safe`, `closed-cell-sub-safe`, `infer-closed-cell-branch`. nested-union-guards: `contextual-direct-union`, `contextual-simple-sub`, `contextual-tagged-case`. constructor-fit-guards: `explicit-singleton-in-union`. qath-fuel: `jrec-match-view`, `qath-static-fuel`. generic-*: `simple-source-generic-recursive`, `grec-direct-context`, `grec-match-view`, `grec-patterns-eligible`, `grec-single-wing-subject`, `grec-unfold-view`. union-source: `grec-collect-molds`, `union-source-distinct-tags`, `union-source-state-safe`. union-alias-overlap and full-overlap-basic: `union-source-overlap`. program-main/-watch/store: `program-main-closed`; page-main: `page-main-closed`. deferred*: `dg-close-env`, `dg-direct-source`, `dg-generalize`, `dg-obligations`, `dg-replay-edges`, `dg-root-detail`, `dg-root-prepared`, `dg-root-source`, `dg-scan`, `dg-source-candidate`, `dg-stable-call-fit`, `dg-stage`, `ienv-fresh-id`.
490+
491+### 5.5 Types constructed by suites
492+
493+`itype` (32 suites), `iprelude` (32), `ifile` (25), `ischeme` (24), `istate` (13: cell-branch, deferred-context, deferred, direct-gate-guards, empty, gate-free-guards, generic-construction, generic-pattern, generic-recursion, hole-guards, qath-fuel, qath-source, union-source), `ienv` (11), `isub` (10), `iresult` (6), `ifit` (6), `upair` (3), `irequest-graph`/`irequest-evidence` (3), `dgo`/`ipending`/`igate-free`/`iwprojection`/`iwidth-definition` (2), `istore-request-evidence`, `igate-prelude-evidence`, `igf-form`, `igf-segment`, `ibinding`, `dgscan`, `dgparse`, `dgcommit`, `grec-collected` (1 each). Q37 decided tests keep calling internal arms (A126) until the core lands; a facade or same-stage suite edits are required for every renamed arm or reshaped type.
494+
495+## 6. Spec rules the core must meet, and open rulings
496+
497+Repository spec wins over the design doc (review Q42); several type-system rows in `decisions.md` are still marked unsynced.
498+
499+### 6.1 Rules
500+
501+| Topic | Rule (short) | Where | Core requirement | Today |
502+| --- | --- | --- | --- | --- |
503+| Inference basis | HM with aura variables; principal types; no general subtyping except listed one-way widenings and explicit `proj` | grammar.md l.121; decisions.md l.35; implementation-plan.md l.15; milestone-2.md l.39, l.62, l.141 | Union-find + levels; widening as directional constraints outside unify | assoc list, env scans, fit mixes widening and unification |
504+| Atoms and auras | `@` any atom per occurrence; specific auras distinct; aura fits `@` and Hoon-family ancestor; reverse needs a check | grammar.md l.124; decisions.md l.59, l.35, Q15 l.134, Q19 l.142 | `fit(actual, expected)` constraint that waits while actual is unbound; unify never widens | `aura-prefix` 5052, fit 5663-5680, `itype-concrete-join` 5125 |
505+| Noun | `*` is the noun type, top of fit only; arbitrary noun does not fit narrower | grammar.md l.121, l.132; decisions.md l.49, Q9 l.122 | unify(`*`, T) fails unless T is `*` | 5549-5557 accepts gates (Q18) |
506+| Empty and crash | `!!` expression has any type; mold `!!` empty; empty-position cells empty, disjoint from all | grammar.md l.62, l.127, l.132; decisions.md l.48, Q17 l.138 | crash = fresh var; usefulness drops uninhabited constructors | `%empty`, 4744, 5521-5525 |
507+| Loobeans | `?` = {0,1}; disjoint from cells, overlaps 0 and 1; arithmetic rejects, comparison accepts | grammar.md l.124, l.127, l.59; decisions.md l.52, l.60, Q16, Q28 | finite constructor set; "atom other than ?" kind | `?` vs `@f` unresolved (5546-5548) |
508+| Constants | singletons compared by noun (`%$` = `%.y` = `~` = 0) | grammar.md l.29-31, l.125, l.144; decisions.md l.29, Q34 | key singletons by noun in unify, fit, ctor, patterns, disjointness | `%const` by value 4926, 5617 |
509+| Literals | decimal `@ud` or any aura by context; prefixed numbers, ships, dates, knots, cords; `` `x ``, `~[…]`, `a+b`, paths, qath read as Hoon | grammar.md l.19-39; decisions.md l.14, l.58 | literal → type or var + literal constraint; prelude unit/list/path/qath templates available | 8770-8821 |
510+| Faces | faces are part of types; unnamed position unifies with faced and takes its face; different faces don't unify; duplicate fields error (also imported); `[a]` is `a`; `[]` error; theme `dark=[tones=…]` must check | grammar.md l.126, l.33; decisions.md l.15, l.42, l.35, Q5, Q8, Q21, Q27 | label slot that may be unknown, bound by unification | `%face` wrapper + asymmetry guards 5212-5349 |
511+| `proj` | explicit, type-directed; expected type selects fields; evaluated once; never inserted implicitly; reserved name | grammar.md l.126; decisions.md l.43; core-language.md l.85; Q32 | deferred `proj(S) : T` with recorded axes | 5835-5923, 9461, 10535, 11706-11760 |
512+| Capitals | generalized per `++`; local `++` shares an enclosing capital it also uses; cannot force two capitals equal; cannot become more specific | grammar.md l.129; decisions.md l.50, Q4, Q23; milestone-2.md l.66 | rigid (skolem) vars scoped before inference; violations name both sites | `merged-capitals` 10072; forcing concrete is "unsupported" (10089) |
513+| Atom/arith constraints | atom constraint and "atom other than ?" retained through generalization and instantiation; printed as where-clauses separated by commas | grammar.md l.124, l.137; decisions.md l.31, l.60, Q28, Q29 | kind lattice on roots | six var kinds, A16 |
514+| Gate-free | `eq` args and map/set keys contain no gates; inferred and generalized; printed `where A contains no gates` | grammar.md l.137; decisions.md l.33, l.106; core-language.md l.39 | gate-free kind, structural propagation, binding a gate fails with sites | `%fvar`, 4998, 5951 |
515+| Holes | `_` wherever a mold may; resolves to a concrete type or written capital; unconstrained is an error; a definition determines its own holes | grammar.md l.123, l.130; decisions.md l.51, Q30, Q31 | hole var with span checked at its level exit | 6133-6181 |
516+| Order, recursion, value cycles | any order; gates self/mutually recursive; non-gate value depending on itself is an error; infer in dependency order, groups together | grammar.md l.56, l.101; decisions.md l.23; core-language.md l.145; milestone-2.md l.66, l.141 | one SCC pass; value cycles reported from the graph | fixpoint fallback 10749-10756; cycle proof needs a cast |
517+| Locals | `++` at the start of any body; mutually visible; generalize locally, captured outer vars shared | grammar.md l.56; decisions.md l.22; milestone-2.md l.97 | levels + same SCC machinery | 7611-7681 |
518+| No shadowing | samples, locals, pattern binders, imports, prelude | grammar.md l.101; decisions.md l.13; core-language.md l.37; milestone-2.md l.95 | scope pass with sites | several site-less messages (8018, 8240…) |
519+| Namespaces | molds and values separate, by position | grammar.md l.102; overview.md l.305 | two tables per scope/interface | `ifile` 5822 |
520+| Tag resolution | tag/`~` = fresh var + pending constraint; non-union = one-case union; checked by shape and shared tag positions, field positions against fields; `@tas`/`@ta`/`@`/`*` make it that constant; no match → `msg has no case %submitt` | grammar.md l.141-143; decisions.md l.29; milestone-2.md l.77 | the deferred queue, woken on binding | `%tag` 4676, 5451, 8693, 8711 |
521+| Non-generalization, module end | tag-constrained vars (and what they mention) do not generalize; an island's `main` fixes its messages; open at module end → error asking for `^-`, never guess | grammar.md l.145-146, l.150-158; milestone-2.md l.79 | keep such vars at module level; module-end pass reports `nothing fixes the union of %add` | dropped at 10680; recovery R1-R5; `module-pending-tag` |
522+| `\|=%tag` | case constructor typed by the expected gate; any case whose head noun equals the tag; no such case is an error | grammar.md l.48, l.141, l.144; decisions.md l.47, Q34; milestone-2.md l.78, l.124 | deferred ctor constraint on the product's root | 5474 |
523+| Numbers by context | wait for context; default `@ud` at the `++` only if unfixed and not generic over it | grammar.md l.162-167; decisions.md l.35; milestone-2.md l.81 | defaultable kind, defaulted at level exit unless linked to a quantified/rigid var | 6062, 6119; incomplete in gate types (compiler.md:59) |
524+| Cell literals | tuple, record or cons (under list); default tuple | grammar.md l.33, l.168, l.172 | deferred cell constraint | cons only under known list context (7834) |
525+| Null | `~` is the `~` case of any union that has one | grammar.md l.31, l.141 | same queue keyed on noun 0 | 5365, 5613-5616 |
526+| Waiting | wing access, changes and `?-` on unknown types wait; patterns don't; `m()` error | grammar.md l.147-148, l.45, l.47; decisions.md l.13, Q6 | deferred has-field / edit / match constraints | 7720, 8622 need a known spine |
527+| Samples, inline gates | every bare name in a sample binds; `\|=(p title.p)` works when the call fixes the type | grammar.md l.48, l.58; decisions.md l.21, l.47; milestone-2.md l.69 | relies on deferred wing access |: |
528+| Calls | right-nested sample; parentheses only group | grammar.md l.43; core-language.md l.29, l.88 | apply = unify/fit with `$-(sample result)` | several call paths |
529+| Named unions | every Jibb union is named; imports may be unnamed; identity = origin + args, display separate | grammar.md l.57, l.127; decisions.md l.29; overview.md l.77 | nominal identity | raw-case equality (A11) |
530+| Disjointness | cases must differ as nouns (for all generic args); `*`, vars and `(list A)` overlap; `!!` disjoint; imported `$% $? $^` too; unverifiable imports fail closed; error suggests leaving `[` open | grammar.md l.127, l.94; decisions.md l.29, l.41, Q16, Q17, Q22; overview.md l.66-68; milestone-2.md l.86, l.125; jibb.hoon 4620 | noun-shape signature shared with usefulness; overlap witness naming both sites | 10909-11302 |
531+| Generic molds | `\|$ [V E]` right after `+$` name; prelude `cmd`/`sub` use `\|$ [M]` | grammar.md l.64, l.131; milestone-2.md l.70 | templates instantiated at exact arity; unions keep origin/args | 6970, 6355; recursive generics only via grec |
532+| Recursive molds | allowed; identity by name and module; imported (e.g. `json`) matched by name | grammar.md l.57, l.135; decisions.md l.56; overview.md l.74 | one nominal recursive type unfolded on demand | three forms |
533+| Containers | list, unit, set, map, mop, qeu, jar, jug; imported maps/sets checked with `apt`; keys gate-free | grammar.md l.128; overview.md l.70-71, l.88, l.102 | inhabitation and gate-free over all containers | list/unit only (A13) |
534+| `?-` | exhaustive, ordered; missing case error naming it; covered arm error; nested patterns allowed; last position binds the rest | grammar.md l.59, l.184-219, l.276-277; decisions.md l.32, l.57; milestone-2.md l.89-92, l.142 | Maranget usefulness with witnesses; one matrix also for milestone-3 lowering | three loops + slices; nested mostly unsupported |
535+| Pattern typing | patterns checked against the subject; binders take position types | grammar.md l.148, l.184; core-language.md l.92-93 | binder types from specialized matrix columns | `union-pattern-bind` 8156 |
536+| Branch join | unify, else widen only to an explicitly present parent aura or `@`; with an expected type each arm fits it | questions.md Q11; A133; grammar.md l.121 | unify + deferred widen; check mode with expected | 5138, 5202 |
537+| Interpolation | atoms print by aura (`@` as `@ud`); text auras and tapes splice; other cells error; generic aura error here and in qath segments; `~&` printer from type | grammar.md l.49, l.170-171; decisions.md l.58; core-language.md l.79, l.95; milestone-2.md l.82 | deferred printable constraint decided at level exit; record the printer | 8081 rejects late-known types |
538+| Paths | constant, empty, typed by aura (`_` allowed); qath with printable segments; route check is milestone 4 | grammar.md l.130, l.36-37, l.173; overview.md l.337 | path mold kind; same printable constraint | jrec qath |
539+| Imports, module values | `/-`, `/%` (no face), `/=` under a face; records read with `.`; module as a value is a cell of definitions in name order; APIs re-export `/%` types; import cycles are errors | grammar.md l.86-94, l.104, l.47; core-language.md l.146; overview.md l.305; milestone-2.md l.98-99 | interface noun; faces as record access with per-use instantiation | `ifile`, 12293, cycle 12304 |
540+| Hoon import table | `$% $? $^` unions if disjoint; `$@`; `$~` dropped; containers by name; tags `%0 %& %\|`; recursive by name; errors where used for duplicates, cores, gates, vases, signed/float auras | overview.md l.60-77; grammar.md l.94; decisions.md l.41, Q21, Q22; milestone-2.md l.102-104, l.134-140, l.153 | imported molds become the same core types; unsupported molds poisoned at use | 6527-6728; whitelist triplicated (A14) |
541+| Module kinds | main's type decides: `(element !!)` page, `(page R D)`, `(program D X M)`, `(store S)`, none = library; built by builders; stages never inferred | grammar.md l.103, l.107-117; overview.md l.106-115; decisions.md l.55, l.66, Q11; milestone-2.md l.100, l.107 | post-solve match of main's closed type; main ordinary (Q5) | syntactic recognisers 13146-13240 |
542+| Islands | `main` record of exactly init/update/view/subs; `island` checks data against init's sample; update/subs/init types from the prelude | overview.md l.112, l.115-121, l.155, l.166; grammar.md l.293-343; decisions.md l.70-71 | follows from prelude types once tags defer across `++` | R1-R6 |
543+| Gate-free island data/model | no gates in data and models; name the field | overview.md l.121; decisions.md l.73; core-language.md l.39; milestone-2.md l.109, l.124 | post-solve gate-free check with witness path | `program-main-closed` 14555 + 5951 (256) |
544+| Effects | `cmd`/`sub` prelude unions with `\|$ [M]`; `raw-poke`, `ask`, `qath` transparent internal types re-exported | overview.md l.140-160; grammar.md l.133-134; decisions.md l.36-37, Q24, Q25 | generic unions with gate payloads; public names in printing | `prelude-label-nested` 11878 |
545+| Stores | `state`, local `+$ poke`, `++ main (store init update)`; builder `\|= [init=S update=$-([A S] S)] ^- (store S)`; kind check verifies A against poke; derived poke helper and state request; one store per page | overview.md l.168-169; grammar.md l.105, l.293-306, l.343; decisions.md l.77-78, Q11 | record A's instantiation at main's application, or check update against `$-([poke state] state)` | R8 |
546+| APIs | `/ui/api/<agent>.jibb` declares `+$ poke` and `+$ paths` (declarations); `(facts full diff …)` with fold `$-([[%mark diff] full] full)`; optional `scry=`; derived poke helper and one request per case; clashes are errors | overview.md l.283-307, l.157-158; grammar.md l.105, l.134; decisions.md l.38-40; milestone-2.md l.111-114 | declaration elaboration into interface schemes | 12329-13148 |
547+| Watchability | islands read agents only by watching; first fact full state; a `scry=` case cannot be watched; unproven watchability is a type error; store state is watchable | overview.md l.159; grammar.md l.105; decisions.md l.38, l.79, Q33 | type-level marker or provenance analysis over the elaborated tree | one syntactic watch shape (14367) |
548+| Pages with data | `load` maps route parameters to one `ask`/`pure`; `view` takes D, returns `(element !!)` | overview.md l.125-130, l.334; grammar.md l.103; decisions.md l.67; milestone-2.md l.161 | ordinary application of `page` | one load shape (14512) |
549+| Elements, attributes | elements are ordinary gates; duplicate attribute in a literal list is an error; `~[text "hi"]` gets a suggestion | overview.md l.174-204; grammar.md l.44; milestone-2.md l.121, l.124 | type-directed post-solve checks | absent |
550+| Theme | `++ theme ^- theme`, backtick units | overview.md l.211-222; decisions.md l.83, Q5 | plain record check | works (uses R17 for the qath font) |
551+| Prelude | Hoon stdlib regrouped in Jibb with a complete inventory; private internal module | overview.md l.81-102; decisions.md l.87-88; open-questions Q3; milestone-2.md l.116-121 | prelude checked by the same core and exported as an interface | partial interface (compiler.md:159) |
552+| No built-ins | type-directed rules only if listed in the Grammar; special cases for one gate are language changes | decisions.md l.34; milestone-2.md l.28 | `program`, `page`, `store`, `each`, `turn`, `element` as ordinary gates | R3, R7 are gate-specific |
553+| Printing | Jibb mold syntax; unnamed unions as space-separated cases; where-clauses; no private names | grammar.md l.137; overview.md l.77; decisions.md l.30-31; milestone-2.md l.143, l.148 | keep origin/name through solving; canonical names past 26 | 9930, 6345, 10171 |
554+| Errors | each error names both sites with excerpts; messages are golden tests; catalogue (aura mismatch, faces, missing case, open constraint, ctor, overlap, missing `?-` case, covered arm, self-dependent value, shadowing, interpolation, capitals, `~[text "hi"]`, clashing derived names, import cycle, `(facts …)` misuse, gate in island data, repeated attribute) | implementation-plan.md Risks; milestone-2.md l.48, l.123-127 | every constraint carries spans; union-find keeps a reason per binding | `idiag` 5997; 283 unsupported lines |
555+| Elaborated output | types/faces/casts leave nothing; lowering needs field axes, edits, decision tree, `proj` plans, printers, path validators | core-language.md l.74-98, l.33-41 | apply the final substitution to a typed tree | only width artifacts (5808) |
556+| Checker as function | caller passes Clay inputs; interface is its own noun; cache with interface and body hashed separately; modules one at a time in dependency order | milestone-2.md l.133; implementation-plan.md (pipeline, cache row); compiler.md:19 | interfaces store generalized schemes with constraints and mold templates | `ifile`, `prepare-prelude` |
557+| Speed | a 2,000-line module checks in seconds | milestone-2.md l.141, l.155; implementation-plan.md Risks | near-constant find, level generalization, one SCC pass | 38-72 s CPU for 2,000 gates (compiler.md:67-69) |
558+| Golden types | third golden output: each definition's type and the module kind, or the rendered error | milestone-2.md l.148; questions.md Q6 | one pipeline returning scheme-or-error per definition | all 304 from the report path (A122) |
559+
560+### 6.2 Open rulings that affect the core
561+
562+| Ruling | State | Effect on the core |
563+| --- | --- | --- |
564+| open-questions.md Q3 (prelude inventory and signatures) | open | Fixes the environment the core checks against; the prepared prelude is partial today |
565+| open-questions.md Q32 (`proj` reordering) | partly settled | How `proj` constraints discharge (jibb.hoon 4625 treats reordering as a doc question) |
566+| Review Q16 (A20): follow Hoon, `%1.000` is `@ud`, `%&` is `?` | proposed, awaiting @iko | How tag constraints discharge against atoms (today 5617-5626, 5636-5648) |
567+| Review Q17 (A20): a name term fits `@t` | proposed | Same discharge rule |
568+| Review Q18 (A23): `*` may hold gates | proposed "yes" | Fit to `*`, gate-free proofs, element's child erasure to `*` (prelude.jibb l.447-466), core-language.md l.33 |
569+| Review Q19 (A6, A100): reject `[]` and `m()` in the parser | proposed | Otherwise the core must reject them |
570+| Review Q20 (A30): `[a=@ud [a=@t b=?]]` is one record, duplicate `a` is an error | proposed | Record and field-access semantics (today nested tails get their own scope, 11556) |
571+| Review Q21 (A25): `/% %foo` beside `++ foo` | proposed | Scope check (11760) |
572+| Review Q22 (A15): an arm matching no remaining case is definite (`arm matches no case`) | proposed | Usefulness reports a useless row; today `union pattern is not supported` (8236, 8273, 8324) |
573+| Review Q23 (A55): `(mop K V)` without comparator | proposed | No comparator in the type |
574+| Review Q24 (A64): Hoon's `each` mold beside the `each` gate | proposed | Relies on separate namespaces |
575+| Review Q26 (A50): importer learns `$%` with `%& %\| %0` tags, then `each` and `json` | proposed | Which imported unions reach the core |
576+| Review Q28 (A136): printer flattens `[a [b c]]`, prints named molds by name | proposed | Core must keep mold names through solving |
577+| Review Q6 (A122): render the report from the full checker | decided, not done | ~283 `types.txt` change once |
578+| Review Q37 (A126): tests keep calling ~137 internal arms | decided; revisit after the core | Keep arms or move suites behind a facade per stage |
579+| Syntax review S1: capitals bind only the type under a face; gate sample names ignored when gate types unify | question for @iko | Decides the face rules; reopens decisions.md l.33 and settled Q8; directly decides whether R11-R13 become unnecessary |
580+| Syntax review S3: samples/binders/locals may reuse prelude value names | question for @iko | Shadowing pass; todo-list's `[%typed text]` fails today |
581+| Syntax review S4: bare decimal fits only `@ud @u @ *` | question for @iko | Number-literal constraint (grammar.md l.21 says any aura) |
582+| Syntax review S5: a pattern name spelling a case tag at a union position is an error | question for @iko | Usefulness-time check |
583+| Syntax review S7: multi-letter type variables | question for @iko | Printer and capital scoping |
584+| Syntax review S12: nested cell patterns shown in the spec | question for @iko | The EBNF allows them; the prelude uses nested `?-` because the checker lacks them, so the core must handle nesting |
585+| Derived request argument order | unresolved in code (`api-request-parts` 12683) | Overview's `(post.api slug same)` suggests segments first |
586+| Application paths vs routes | milestone 4 | Core types `%/…` as qath with printable segments only |
587+| Spec sync | repository copy wins (Q42) | Unsynced decisions.md rows (Unions, Printed type constraints, Partial type annotations, Record fields, Record projection, Store builder, Agent APIs, Effects) may still differ from the design doc |
docs/spec/core-language.md+10−9
@@ -83,8 +83,9 @@ Types, faces and casts leave nothing behind. Everything else lowers by these rul
8383| `/posts/~zod`, `%/blog/(slug)` | A list of knots, typed segments printed by their aura's native; the runtime adds the base path to an application path |
8484| `title.p`, `space.theme.theme` | `slot` at the field's axis, nested for longer wings |
8585| `(proj record)` | Apply a `lam` to the source once; its body constructs the expected record from the required fields using `slot` and `cons`, discarding extra fields |
86+| `(unface e)` | `e`: only its type changes |
8687| `card.card`, an import | The qualified name `components/card:card` |
87−| `m(draft=t error=~)` | One `edit` per item, in order: `(edit 7 (edit 6 m t) ~)` |
88+| `m(draft=t error=~)` | One `edit` per item, in order: `(edit 7 (edit 6 m t) ~)`. A wing's item edits at the wing's axis, so with `cart` at 2 and `open` at 3 inside it, `m(open.cart=x)` is `(edit 5 m x)`. Each value is computed from `m` as it was |
8889| `f a b c` | `(app f (cons a (cons b c)))`: the arguments are the sample |
8990| `\|= [a=@ b=@] body` | `(lam _1 (let a (slot 2 _1) (let b (slot 3 _1) body)))`; a single face, as in `\|= m=model`, names the `lam` itself |
9091| `\|=%got` | `(lam _1 (cons %got _1))` |
@@ -104,14 +105,14 @@ The todo island's `update`, from worked example 3:
104105```jibb
105106++ update |= [=msg m=model]
106107 ?- msg
107− [%typed t]
108− ?- (gth (lent (tuba (trip t))) 80)
109− %.y [m(draft=t error=`"Too long") ~]
110− %.n [m(draft=t error=~) ~]
111− %submit [m(draft="") ~[(poke.todo [%add draft.m] |=%acked)]]
112− [%toggled id] [m ~[(poke.todo [%toggle id] |=%acked)]]
113− [%got ts] [m(todos=ts) ~]
114− [%acked err] [m(error=err) ~]
108+ [%typed t]
109+ ?- (gth (lent (tuba (trip t))) 80)
110+ %.y [m(draft=t error=`"Too long") ~]
111+ %.n [m(draft=t error=~) ~]
112+ %submit [m(draft="") ~[(poke.todo [%add draft.m] |=%acked)]]
113+ [%toggled id] [m ~[(poke.todo [%toggle id] |=%acked)]]
114+ [%got ts] [m(todos=ts) ~]
115+ [%acked err] [m(error=err) ~]
115116```
116117
117118lowers to the program below. The model `[todos draft error]` puts `todos` at axis 2, `draft` at 6 and `error` at 7, and `%submit`, the only atom case, needs no test once `cell?` fails.
docs/spec/decisions.md+11−8
@@ -8,10 +8,12 @@ The choices behind the Language tab, made on 2026-10-23; a later date marks a re
88
99Until the Claude doc is synced with this copy, this copy is the spec (review question 42). Synced says whether the doc's Decisions tab has the row as written here. A row decided by 2026-10-29 or undated was in the doc when `spec/` was copied from it on 2026-10-30, and is unchanged. A row decided on or after 2026-10-31 is only here. A row of 2026-10-30 says Check: the copy had that day's answers to the 12 grammar questions, but other rows of that day were added or edited here afterwards ([docs/README.md](../README.md#the-spec)), and nobody has compared them with the doc yet.
1010
11+Rows dated 2026-11-03 are Montelot's decisions on the [syntax review](../reviews/2026-11-02-syntax-review.md): S1 with its step 1, S2, S4 to S7, S11 to S13 and S15. S1 step 1 is decided but not built yet; the checker core that review question 5 asks for will build it.
12+
1113| Decision | Choice | Status | Synced |
1214| --- | --- | --- | --- |
13−| Syntax | Hoon's runes as keywords, and its literals; wide forms only for `\|=` and `$-`; changes take one or more record items, as `m(draft="x")`, so `m()` is an error; `.` reads fields, imports and prelude groups; no name may shadow another | Decided 2026-10-30 | Check |
14−| Literals | Exactly Hoon's, including `%$` as a term literal and pattern: `1000` is an error, `~2026.2.31` is `~2026.3.3`, and years BC and sub-second groups are dates; `print-date`'s minute form is not a literal | Decided 2026-10-30 | Check |
15+| Syntax | Hoon's runes as keywords, and its literals; wide forms only for `\|=` and `$-`; changes take one or more record items, as `m(draft="x")`, so `m()` is an error; an item may name a wing through record fields, as `m(open.cart=x)`, every value is computed from the original record, and two items that name the same field, or one inside the other, are an error; `.` reads fields, imports and prelude groups; no name may shadow another | Decided 2026-11-03 | No |
16+| Literals | Exactly Hoon's, including `%$` as a term literal and pattern: a bare decimal is a `@ud`, so `^- @dr 30` is an error and a duration is written `~s30`; `1000` is an error, `~2026.2.31` is `~2026.3.3`, and years BC and sub-second groups are dates; `print-date`'s minute form is not a literal | Decided 2026-11-03 | No |
1517| Cells | A single-item cell `[a]` is `a`; an empty `[]` is an error, in expressions and molds | Decided 2026-10-30 | Check |
1618| Numeric terms | `%` and a decimal as Hoon writes it: `%1.000`; `%1000` and `%007` are errors | Decided 2026-10-30 | Check |
1719| Strings | Hoon's escapes: `\\`, `\"`, `\{`, and `\` with two lowercase hex digits; a string and each `{…}` close on the line they open; `::` in a string is text | Decided 2026-10-30 | Check |
@@ -32,7 +34,7 @@ Until the Claude doc is synced with this copy, this copy is the spec (review que
3234| Branching | `?-` only, loobeans included; exhaustive, with explicit catch-alls; covered arms are errors; failures say `!!` | Decided 2026-10-29 | Yes |
3335| Equality and negation | The gates `eq` and `not`, with Hoon's bitwise `not` exposed as `not.bit`; `eq`'s arguments and map and set keys contain no gates, even nested; the checker infers and generalizes that constraint; union matching never inspects a gate to distinguish cases | Decided 2026-10-30 | Check |
3436| Special rules | No built-ins; type-directed rules are welcome, each listed in the Grammar tab | Decided 2026-10-29 | Yes |
35−| Inference | Hindley–Milner with aura variables; `@` is any atom, a specific atom fits `@` and a more specific aura fits an ancestor in its Hoon aura family, but each reverse needs a check, and repeated atom-constrained capitals give the same type; a number takes `@ud` only where its `++` isn't generic over its aura; distinct specific auras remain distinct; faces are part of record types, and an unnamed position can take a face but two different faces don't unify; principal types | Decided 2026-10-30 | Check |
37+| Inference | Hindley–Milner with aura variables; `@` is any atom, a specific atom fits `@` and a more specific aura fits an ancestor in its Hoon aura family, but each reverse needs a check, and repeated atom-constrained capitals give the same type; a decimal is a `@ud`, which fits `@u`, `@` and `*` but no other aura, except where its `++` is generic over its aura; distinct specific auras remain distinct; faces are part of record types, and an unnamed position can take a face but two different faces don't unify; a capital that meets a faced position binds only the type under the face, so `$-([A A] ?)` takes a gate with named parameters (not built yet); principal types | Decided 2026-11-03 | No |
3638| Effects | The library unions `cmd` and `sub`; `raw-poke`, `ask` and `qath` are transparent types defined in the internal prelude and re-exported normally; derived gates and `pure` also construct requests; islands read agents only by watching; replies get full state, and diffs take a fold; timers carry the time; `%who` gives the owner's `@p`; nacks reach replies as text | Decided 2026-11-01 | No |
3739| Poke representation | The source-backed private internal prelude module defines `raw-poke`, and the public prelude re-exports it as an ordinary transparent type. A store's local `poke` action remains an ordinary mold; derived helpers produce the runtime envelope | Decided 2026-11-01 | No |
3840| Agent APIs | `/ui/api/<agent>.jibb` with `+$ poke` and `+$ paths`, over the agent's mark types; a case is a name, a path and a type, with `(facts full diff …)` for diffs, told apart by mark; an optional scry path, for pages; an island may watch a request only when the checker proves it is watchable, so a separate scry path or unknown watchability is an error; typed segments by aura | Decided 2026-10-31 | No |
@@ -40,21 +42,22 @@ Until the Claude doc is synced with this copy, this copy is the spec (review que
4042| Derived gates | API files and stores give a generic `poke` command helper taking an action and reply, and a checked request per path or store state; clashing names are errors, including a derived name that clashes with an import face | Decided 2026-11-01 | No |
4143| Hoon types | A fixed translation table; `map`, `set`, `qeu`, `jar`, `jug` by name; `mop` as `(mop K V)`, read with `on`; imported `$%`, `$?` and `$^` cases must differ as nouns, and records with duplicate field names are errors where used; unused molds skipped | Decided 2026-10-30 | Check |
4244| Record fields | Duplicate field names in a Jibb-written record are an error, as they are in an imported Hoon record | Decided 2026-10-31 | No |
45+| Unface | The explicit type-directed operation `unface` removes every face from its argument's type, through cells, a gate's sample and product, and containers' arguments; unions and recursive molds go by name and are kept whole; like `proj`, it is reserved and not a value; it leaves nothing behind at run time | Decided 2026-11-03 | No |
4346| Record projection | The explicit type-directed operation `proj` takes a record and uses its expected result type to select its fields; no projection is inserted automatically. `proj` is reserved and cannot be defined or imported under that name. The result has exactly the fields declared by its type | Decided 2026-10-31 | No |
44−| Layout | Indentation; juxtaposed calls; a bracket open at line end takes one item per line, with no closer | Decided | Yes |
47+| Layout | Indentation; juxtaposed calls; a bracket open at line end takes one item per line, with no closer; a block of deeper lines belongs to the line above, so a call never continues onto a deeper line; a body's final line may hand the rest of the body, at its depth, to a tall `\|=`, `^-` or `~&` that ends it, and a `?-` that begins it may take its arms at its depth | Decided 2026-11-03 | No |
4548| Elements | Ordinary gates; containers take attribute lists; `stack` switches at `wide`; `el` adds attributes and wins; headings 1 to 6; `form` sends on Enter, the innermost when nested; `image` from an application path, sized from the file, or a sized URL; no focus control for now | Decided 2026-10-29 | Yes |
4649| Long calls | One argument per line inside parentheses | Decided | Yes |
4750| Inline gates | Hoon's wide form; the mold may be inferred; a bare sample name binds; `\|=%got` is a case's constructor, typed by the gate expected; a bare tag is always a value | Decided 2026-10-29 | Yes |
4851| Empty mold | `!!`, with no values; the expression has any type; pages are `(element !!)`, which keeps islands out of islands | Decided 2026-10-29 | Yes |
4952| Noun mold | `*` is the noun type, not a type variable; use a capital for a generic type; a value of a more specific noun type can be used where `*` is expected | Decided 2026-10-30 | Check |
50−| Type variables | Capitals, generalized per `++`; a capital in a local `++` shares the enclosing `++`'s variable of that name if the enclosing `++` also uses it; otherwise it is introduced and generalized locally; a different type takes a different capital; a body cannot force distinct capitals to be equal, so a shared type uses the same capital; one used where an atom is required gains an inferred atom constraint, and cannot be fixed to a more specific type in its body | Decided 2026-10-30 | Check |
53+| Type variables | A capital, then lowercase letters and digits, as `A` or `Msg`, printed by the name they were written with; generalized per `++`; a capital in a local `++` shares the enclosing `++`'s variable of that name if the enclosing `++` also uses it; otherwise it is introduced and generalized locally; a different type takes a different capital; a body cannot force distinct capitals to be equal, so a shared type uses the same capital; one used where an atom is required gains an inferred atom constraint, and cannot be fixed to a more specific type in its body | Decided 2026-11-03 | No |
5154| Partial type annotations | `_` may appear wherever a mold may appear and marks that part of the type for inference; a hole inferred as a named type variable is resolved; an unconstrained hole is an error, and a named mold or value definition must determine its own holes without constraints from later uses | Decided 2026-10-31 | No |
5255| Loobean mold | `?`, switched with `?-` | Decided 2026-10-26 | Yes |
5356| Defaults | None | Decided | Yes |
5457| Modules | Records, not cores | Decided | Yes |
55−| Kinds | The type of `main`: `(element !!)`, `(page R D)`, `(program D X M)` or `(store S)`; other names by file kind, in the Grammar tab | Decided 2026-10-29 | Yes |
58+| Kinds | The type of `main`: `(element !!)`, `(page Params Data)`, `(program Data Model Msg)` or `(store S)`; other names by file kind, in the Grammar tab | Decided 2026-11-03 | No |
5659| Type identity | Recursive molds by name and module | Decided 2026-10-29 | Yes |
57−| Binding patterns | In `?-` arms; the last position binds the rest | Decided 2026-10-29 | Yes |
60+| Binding patterns | In `?-` arms; the last position binds the rest; cells of patterns nest; a bare name is an error where a case the pattern can match has there a tag the name spells, as `stop` for `%stop` | Decided 2026-11-03 | No |
5861| Text | Strings are written only as `"…"` and are always cords; tapes come from `trip`; `{…}` prints by aura, a bare `@` as `@ud`, and an atom whose aura its `++` is generic over is an error; `print-date` prints Urbit-style to the minute in the theme's zone, from jibb-dev's zone table; numbers keep Hoon's form | Decided 2026-10-30 | Check |
5962| Auras | Specific auras stay distinct; `@` is any atom, a more specific aura fits an ancestor in its Hoon aura family one way, with the reverse requiring a check, and shared atom-constrained type variables preserve the same aura | Decided 2026-10-30 | Check |
6063| Loobean arithmetic | Arithmetic rejects loobean operands; comparison may accept them and returns `?` | Decided 2026-10-31 | No |
@@ -96,7 +99,7 @@ Until the Claude doc is synced with this copy, this copy is the spec (review que
9699| Access | Every page is private to the owner; public pages come in a later version | Decided 2026-10-29 | Yes |
97100| Tests | `test-…` arms under `/ui/tests`, run by `-jibb!test`; the JavaScript side and differential tests under Node from jibb-dev | Decided 2026-10-29 | Yes |
98101| Editor support | Tree-sitter grammar | Decided | Yes |
99−| Formatter | One canonical layout | Decided | Yes |
102+| Formatter | One canonical layout: a cast whose expression takes the deeper lines ends the line it belongs to; every `?-` begins its own line, with its arms at its depth where the rest of a body allows that | Decided 2026-11-03 | No |
100103| Name | Jibb | Decided | Yes |
101104
102105## Settled milestone 2 questions
docs/spec/grammar.md+47−30
@@ -6,19 +6,20 @@ The syntax the compiler accepts.
66
77## Lexical rules
88
9−- **Indentation is structure**: a block of deeper lines belongs to the line above it: to the last bracket that line leaves open at its end, to the body of the last rune or `++` on it, to `?-`'s arms, to an arm's body, or to a `+$`'s cases. A deeper line that nothing on the line above takes is an error, so a call never continues onto a deeper line. Returning to an earlier indentation closes every block since. Spaces only; blank and comment-only lines don't count.
9+- **Indentation is structure**: a block of deeper lines belongs to the line above it: to the last bracket that line leaves open at its end, to the body of the last rune or `++` on it, to `?-`'s arms, to an arm's body, or to a `+$`'s cases; or, for a rune or `?-` that ends a body's final line, so do the lines after it at the same depth, as The rest of a body says. A deeper line that nothing on the line above takes is an error, so a call never continues onto a deeper line. Returning to an earlier indentation closes every block since. Spaces only; blank and comment-only lines don't count.
1010- **Layout tokens**: a deeper line emits INDENT, the same depth NEWLINE, a shallower one a DEDENT per closed level, then NEWLINE.
1111- **Open brackets**: a bracket open at line end takes one item per deeper line and closes at the first line that isn't deeper, with no closer. Brackets opened and closed on one line work as usual. A mold's `[` and `(` open the same way, with one field or mold per deeper line. A line may leave several brackets open: the deeper lines go to the last one, or to the body of the last rune, and the others close with it, so `(column ~ ~[` above its items needs no `)`. On the opener's line, spaces separate items, so `~[text "a"` holds two items. In an expression's open bracket each deeper line is one whole item: `text "a"` there is `(text "a")`, `label=trim " x "` is `label=(trim " x ")`, and under a `(` alone the first deeper line is the head. A mold's open bracket takes exactly one field or mold per deeper line.
1212- **Tight forms**: `a+b`, `a.b`, `` `x ``, `|=%got` and the openers `~[`, `|=(`, `$-(` take no spaces. A `(` right after a wing is a change: `m(note=text)` changes, `m (note text)` calls. `%/` starts an application path, `%/blog/(slug)`.
13−- **Spacing**: one space between items; more for alignment. That is style, which the formatter keeps: the parser takes one or more spaces between items, and allows spaces after an opener, before a closer and at the end of a line. Faces `name=value`, puns `=name` and typed path segments `[id=@ud]` take no spaces, and a rune is followed by one.
13+- **Spacing**: one space between items; more for alignment. That is style, which the formatter keeps: the parser takes one or more spaces between items, and allows spaces after an opener, before a closer and at the end of a line. Faces `name=value`, puns `=name` and typed path segments `[id=@ud]` take no spaces, and a rune is followed by one. The formatter puts a cast whose expression takes the deeper lines at the end of the line it belongs to, the `|=`, `++` or arm line, and a cast whose expression fits on its own line on the line below with it. It starts every `?-` on its own line, below the line it belongs to, with its arms at its depth where the rest of a body allows that, and one level deeper on an open bracket's line.
1414- **Comments**: `::` to the end of the line, outside strings; inside a string, `::` is text.
1515- **Names**: Hoon terms; lowercase letters, digits and hyphens, starting with a letter.
16+- **Type variables**: a capital, then lowercase letters and digits: `A`, `Msg`, `T2`. `AB`, `MSG`, `Msg_x` and `Msg-x` are errors. In a mold, a capitalized name is a type variable and a lowercase name is a mold: the reverse of Elm, where `Msg` is a concrete type and `msg` a type variable.
1617
1718## Literals
1819
1920| Form | Example | Type |
2021| --- | --- | --- |
21−| Decimal | `1.000` | `@ud`, or any aura by context; groups of three, as in Hoon |
22+| Decimal | `1.000` | `@ud`, which also fits `@u`, `@` and `*`; groups of three, as in Hoon |
2223| Hexadecimal | `0x1f` | `@ux` |
2324| Base 32 | `0v5.fdf99` | `@uv` |
2425| Ship | `~zod`, `~sampel-palnet` | `@p` |
@@ -42,27 +43,35 @@ Every literal reads exactly as Hoon reads it: `1000` is an error (write `1.000`)
4243
4344- **Call**: `f a b`; parentheses only group. A call open in parentheses puts its head and first arguments on the first line, then one argument per indented line; a `(` alone at the end of a line puts the head on the first indented line.
4445- **Lists**: `~[a b c]`, or `~[` at line end with one item per line. On one line, whitespace separates items, so calls need parentheses: `~[(text "hi")]`, which the checker suggests for `~[text "hi"]`. On indented lines, each line is an item.
45−- **Faced cells**: `[text="milk" done=%.n]`, or one `name=value` per line of an open bracket. A change takes one or more of the same items, as `m(done=%.y)`; `m()` is an error.
46+- **Faced cells**: `[text="milk" done=%.n]`, or one `name=value` per line of an open bracket. A change takes one or more of the same items, as `m(done=%.y)`; `m()` is an error. A change's item, inline or on a line, may name a wing instead, read through record fields only: `m(open.cart=(not open.cart.m))` sets field `open` of field `cart`, as Hoon's `m(open.cart x)`. Every value is computed from the original record. Two items that set the same field, or one a field inside the other's, as `m(cart=c open.cart=%.y)`, are an error. A cell's items take plain names.
4647- **Pairs and units**: `gap+%s2` and `` `x `` bind tighter than calls, so `pad+%s3 gap+%s2` is two items.
4748- **Wing** `title.p`, also for imports and prelude groups, which are records: `card.card`, `space.theme.theme`, `get.by`. **Change** `m(draft="x" error=~)`.
49+- **Unface**: `(unface e)` is `e` with every face removed from its type, so a gate or record fits where other names are expected. `~[(unface lth2) (unface lte2)]` is a list though `lth2` names its sample `[x=A y=A]` and `lte2` names it `[a=A b=A]`, and `(take-kv (unface pair))` passes a `[p=@t q=@ud]` where `[k=@t v=@ud]` is expected; the fields then match by position alone. Faces go from cells, from a gate's sample and product, and from a container's arguments, as in `(list [p=@t q=@ud])`. A union or recursive mold goes by name, so it is kept whole: a gate over `msg` still takes a `msg`. A type variable inside `e`'s type keeps the faces it is bound to later. Like `proj`, it is an operation the checker handles by type, not a gate: it takes one argument, and `(turn gs unface)` is an error; write `|=(g (unface g))`. A `++` whose body is `(unface |= …)` is still a gate, so it can call itself.
4850- **Inline gate**: `|=(p=post.blog title.p)`, or `|=(p title.p)` when the call fixes the type. A bare name in a sample always binds. `|=%got` is case `%got`'s constructor, typed by the gate expected. A bare name binds at any depth of a sample, so `|= [a=@ b]` binds `a` and `b`.
4951- **Interpolation**: `{…}` holds any expression; `\{` writes a brace and `\"` a quote; no `<…>`. Strings take Hoon's escapes: `\\` writes a backslash, and `\` with two lowercase hex digits writes that byte, as `\0a` a line feed; any other `\` is an error. A string and each `{…}` close on the line they open, and `::` inside a string is text.
5052- **No operators**: `eq a b`, `not x`, `gth a b` are gates.
5153
5254## Runes
5355
54−A rune's first children sit on its line, the last taking the rest of it; the others follow, indented.
56+A rune's first children sit on its line, the last taking the rest of it; the others follow, indented. On a body's final line, the last child may instead take the rest of the body at the same depth, as The rest of a body says.
5557
5658- `++` **luslus**: defines a value, at top level or as local names at the start of any body (a gate's, an arm's, a `^-`'s, a `~&`'s or a `++`'s), visible to each other and the final expression. Gates may call themselves and their siblings; other values can't depend on themselves, even through a gate, so `++ title (trim title)` is an error.
5759- `+$` **lusbuc**: defines a mold, likewise: on its line, or as cases on the lines below, one per line, where several cases make a union and one is just that mold. Molds may be recursive.
5860- `|=` **bartis**: a gate with a faced sample, `m=model`, `=msg` (`msg=msg`) or `[a=@ b=@]`; the body on the same line or below.
59−- `?-` **wuthep**: the only branch, exhaustive; the subject on its line, then arms of a pattern and an expression or body. Conditions switch on `%.y` and `%.n`.
61+- `?-` **wuthep**: the only branch, exhaustive; the subject on its line, then arms of a pattern and an expression or body, one per line, deeper. A `?-` that begins a body's final line may instead take its arms at its own depth, to the end of the body. A `?-` takes all its arms deeper or all at its own depth. Conditions switch on `%.y` and `%.n`.
6062- `^-` **kethep**: a cast; the mold on its line, the expression after it or below.
6163- `~&` **sigpam**: prints the value on its line, then runs the body below; output goes to the ship's log or the browser's console.
6264- `!!` **zapzap**: a crash, an expression of any type; as a mold, the empty mold. It is an operand, so `f !!` and `~[!!]` need no parentheses.
6365- `$-` **buchep**: a gate's mold, `$-(sample product)`.
6466- `|$` **barbuc**: a generic mold, right after a `+$`'s name: `+$ result |$ [V E]`, then the mold on its line or the cases below.
6567
68+**The rest of a body.** A body's final line may hand the rest of the body, the lines after it at the same depth, to the rune that ends the line:
69+
70+- a tall `|=`, `^-` or `~&`, or a chain of them such as `^- @ud ~& x`, when the line ends where the innermost rune's last child goes. That child is the rest, a body of its own: first its local `++` and `+$`, then its expression, whose own final line may do the same;
71+- a `?-` that begins the line and ends it with its subject. Its arms are the rest, one per line, so nothing follows them.
72+
73+A gate's body can then be `~& msg`, then `?- msg`, then its arms, all at one depth, and adding or removing the `~&` line moves no other line. This doesn't apply on a `?-` arm's line, on a line of an open bracket, after a bracket opened earlier on the line (the subject's included), at the top level, or to a definition's own expression. So `++ inner |= y=@ud` above `(inner x)`, `[a b] ?- a` above `%.y 1`, `^- @ud ?- x` above `%.y 1` and `++ g ?- x` above `%.y 1` stay errors.
74+
6675Only `|=` and `$-` have wide forms: `|=(sample expr)` and `$-(mold mold)`. Their children are operands, so calls inside need parentheses.
6776
6877Left out on purpose:
@@ -98,9 +107,9 @@ An imported Hoon record with duplicate field names is an error where used; impor
98107A file is a module: imports, then definitions.
99108
100109- `+$ name mold` defines a mold; `++ name expr` a value.
101−- Names may refer to each other in any order, and no name may shadow one already in scope, imports and the prelude included.
110+- Names may refer to each other in any order, and no name may shadow one already in scope, imports and the prelude included. `proj` and `unface` are reserved: no module can define, import or bind either, as a value or a mold.
102111- Molds and values have separate namespaces, told apart by position: `todo-action.todo` is a mold, `poke.todo` its command helper, and `todos.todo` a mold and a request.
103−- `main`'s type decides the kind: `(element !!)` a page; `(page R D)` a page with data, from parameters `R` to data `D`; `(program D X M)` an island, with data, model and messages; `(store S)` a store with state `S`. They're built by `(page load view)`, `(program init update view subs)` and `(store init update)`. A module without `main` is a library.
112+- `main`'s type decides the kind: `(element !!)` a page; `(page Params Data)` a page with data, from parameters to data; `(program Data Model Msg)` an island, with data, model and messages; `(store S)` a store with state `S`. They're built by `(page load view)`, `(program init update view subs)` and `(store init update)`. A module without `main` is a library.
104113- Everything is exported and read through the import's face, as `card.card`. The prelude keeps private helpers in a separate internal module; it imports them without exposing them.
105114- An API module, `/ui/api/<agent>.jibb`, also exports derived gates: a generic `poke` command helper, adding the agent and mark and taking a reply, and a request per `paths` case, taking a reply over full state, plus a fold for `(facts full diff …)`. An island may watch a request only when the checker proves it is watchable. A request whose case has a separate `scry=` path, or whose watchability cannot be proved, is a type error. A store's local `+$ poke` is its ordinary action mold; a store exports a generic `poke` command helper and a `state` request. Clashing derived names are errors, including a derived name that clashes with an import face.
106115
@@ -121,15 +130,16 @@ Every other name is free.
121130A mold is only a type: never called on a noun, and with no default. Types are inferred, Hindley–Milner with aura variables: every expression has a principal type, and there is no general subtyping. These one-way widenings are allowed: a value of a specific atom type fits `@`, a value of a specific noun type fits `*`, and a more specific aura fits an ancestor in its Hoon aura family; the reverse of each widening needs a check. Records can also be projected explicitly, as described below.
122131
123132- **Partial annotations**: `_` may appear wherever a mold may appear. It marks a part of the type for the checker to infer, so a type annotation can specify only the parts it needs to. A hole inferred to be a named type variable is resolved: in `++ id |= x=A ^- _ x`, the result hole is `A`. An unconstrained hole is an error. A named mold or value definition must determine its own holes: `+$ box [item=_]` and `++ id |= x=_ x` do not determine their holes, and later uses cannot fix them.
124−- **Atoms**: `@` is any atom, regardless of aura; auras such as `@ud`, `@t`, `@p` and `@da` are specific atom types. An `@ud` value fits where `@` is expected, but an `@` value needs a check to fit `@ud`. A more specific aura also fits an ancestor in its Hoon aura family: `@ud` and `@ux` fit `@u`, and `@tD` fits `@t`. The reverse needs a check. Distinct specific auras remain distinct; sharing an ancestor does not make them unify. Each bare `@` independently accepts any atom: it is not an aura variable. Atoms that must share a type take one capital, as `[lo=A hi=A]`, with the atom constraint inferred from the body. `add` takes `[A A]` and returns `A`, with `A` constrained to atoms, so `(add n 1)` with `n=@ud` is a `@ud`. Arithmetic rejects loobean operands: `?` contains only 0 and 1, while an arithmetic result need not. Comparison may take loobeans and returns `?`.
133+- **Atoms**: `@` is any atom, regardless of aura; auras such as `@ud`, `@t`, `@p` and `@da` are specific atom types. An `@ud` value fits where `@` is expected, but an `@` value needs a check to fit `@ud`. A more specific aura also fits an ancestor in its Hoon aura family: `@ud` and `@ux` fit `@u`, and `@tD` fits `@t`. The reverse needs a check. Distinct specific auras remain distinct; sharing an ancestor does not make them unify. Each bare `@` independently accepts any atom: it is not an aura variable. Atoms that must share a type take one type variable, as `[lo=A hi=A]`, with the atom constraint inferred from the body. `add` takes `[A A]` and returns `A`, with `A` constrained to atoms, so `(add n 1)` with `n=@ud` is a `@ud`. Arithmetic rejects loobean operands: `?` contains only 0 and 1, while an arithmetic result need not. Comparison may take loobeans and returns `?`.
125134- **Constants**: `%add`, `~` and the loobeans have one value each.
126135- **Records and tuples**: `[text=@t done=?]`, `[@t ?]`. An empty `[]` is an error. Duplicate field names in a record are an error. Faces are part of the type, so `[a=@ b=@]` and `[x=@ y=@]` don't unify. An unnamed position can unify with a faced position and take its face, so `[0 0]` fits `[x=@ud y=@ud]`; two different faces don't unify. The explicit type-directed operation `(proj record)` selects fields from its argument according to the expected result type: `^- [x=@ud y=@ud] (proj wider)`, or `(f (proj wider))` when `f` expects that record. The source is evaluated once, and the result contains exactly the fields in the expected layout. No projection is inserted for a direct call. `proj` is reserved: a module cannot define or import another name `proj`. A record too long for one line can leave its `[` open, with one field per deeper line, as an expression's bracket does.
127136- **Unions**: a `+$` with several cases below it. Every union written in Jibb has a name, so one used in a field, a sample, a cast, a gate's mold or an argument gets its own `+$`; only imports bring in unions without one. Tags take their union from context, as Tag resolution describes. Cases must differ as nouns: inhabited cases must differ at some position of their right-nested cells, where one is an atom and the other a cell, or both are different constants. `*`, type variables and molds that can be either, such as `(list A)`, can overlap atoms and cells. `?` counts as the two atoms `%.y` and `%.n`: it is disjoint from cells and overlaps the constants 0 and 1. The empty mold `!!` is disjoint from every case; a cell with an empty position at any depth is itself empty and is also disjoint from every case. A union whose cases don't all differ is rejected.
128137- **Containers**: `(list A)`, `(unit A)`, `(set A)`, `(map K V)`, `(mop K V)`, `(qeu A)`, `(jar K V)`, `(jug K V)`.
129−- **Gates**: `$-(A B)`. Type variables are capitals, generalized per `++`. A capital in a local `++` shares the enclosing `++`'s variable of the same name if the enclosing `++` also uses it; otherwise the local `++` introduces and generalizes its own variable. For example, `++ inner |= y=A y` uses the enclosing `A` when its enclosing gate has a sample `x=A`; if the enclosing `++` does not use `A`, `inner` generalizes its own `A`. Use another capital for a different type. A body can't force two distinct capitals to be equal; use the same capital wherever a type must be shared. A type variable used where an atom is required gains an atom constraint, so `++ clamp |= [lo=A hi=A n=A]`, whose body calls `gth` and `max`, works on any one aura. It can become nothing more specific: a body that makes `A` a `@ud` or a list is an error.
138+- **Gates**: `$-(A B)`. Type variables are capitalized names, as `A` or `Msg`, generalized per `++`. A capital in a local `++` shares the enclosing `++`'s variable of the same name if the enclosing `++` also uses it; otherwise the local `++` introduces and generalizes its own variable. For example, `++ inner |= y=A y` uses the enclosing `A` when its enclosing gate has a sample `x=A`; if the enclosing `++` does not use `A`, `inner` generalizes its own `A`. Use another capital for a different type. A body can't force two distinct capitals to be equal; use the same capital wherever a type must be shared. A type variable used where an atom is required gains an atom constraint, so `++ clamp |= [lo=A hi=A n=A]`, whose body calls `gth` and `max`, works on any one aura. It can become nothing more specific: a body that makes `A` a `@ud` or a list is an error.
139+- **Printed types** show a type variable by the name it was written with: `++ id |= x=Msg x` prints `$-(Msg Msg)`. A variable from a gate a `++` uses keeps that gate's name, so `++ make program` keeps `program`'s `Data`, `Model` and `Msg`. When several named variables become one, a capital written in the `++` names it; otherwise the one made first does, and a called gate's variables are made before its arguments', so `(cork same same)` prints `$-(A A)`, from `cork`'s `A`. A variable with no name prints as a letter that no other variable in the same type uses: `++ h |= x=A [x same]` prints `$-(A [A $-(B B)])`.
130140- **Paths**: `/todos` is constant, `/` empty, and `/todo/[id=@ud]` typed by aura. A typed segment may use `_` for an inferred aura; it still must resolve to an aura that the path rules can print and parse. `%/blog/(slug)` is an `qath`, checked against routes and static files.
131141- **Generic molds**: `+$ result |$ [V E]` with cases below; `|$` goes only right after a `+$`'s name.
132−- **Noun**: `*`, not a type variable; use a capital for a generic type. A value already known to have a more specific noun type, such as `@ud`, can be used where `*` is expected. **Empty**: `!!`.
142+- **Noun**: `*`, not a type variable; use a type variable for a generic type. A value already known to have a more specific noun type, such as `@ud`, can be used where `*` is expected. **Empty**: `!!`.
133143- **Pokes**: `raw-poke` is defined in the source-backed private internal prelude module and re-exported by the public prelude as an ordinary transparent type. Ordinary modules can construct and inspect its values; derived `poke` helpers return commands.
134144- **Effect and application-path types**: `raw-poke`, `ask` and `qath` are transparent types, defined in the internal prelude and re-exported normally; callers can construct and inspect their values. Derived gates and `pure` also construct requests, and application-path literals have type `qath`. `(facts full diff …)` appears only in an API file's `paths`.
135145- **Identity**: recursive molds go by name and module.
@@ -144,7 +154,7 @@ A tag literal or `~` gets a fresh type variable and a pending constraint: the va
144154- `|=%typed` is a case's constructor: against `$-(@t M)` it is `|=(t [%typed t])`, requiring `M` to have a case `[%typed @t]`. It works for cases whose head is a literal with the same noun as the tag, regardless of how that literal is written: `|=%$` also constructs a case headed by `%.y` or `~`, since each is the noun 0. A bare tag is always a value.
145155- A variable constrained by tag resolution, and any it mentions, doesn't generalize; it stays open until something in the module fixes it. An island's `main` fixes its messages, so islands resolve their own tags. The inferred gate-free constraint is retained when a type variable is generalized.
146156- A constraint still open when its module is checked is an error asking for a `^-`; the checker never guesses. Library helpers can cast, as in `^- (list attr)`.
147−- Wing access, changes and `?-` on a type not yet known wait the same way.
157+- Wing access, changes, `unface` and `?-` on a type not yet known wait the same way.
148158- Patterns need none of this; they're checked against the subject's type.
149159
150160```jibb
@@ -159,12 +169,12 @@ A tag literal or `~` gets a fresh type variable and a pending constraint: the va
159169
160170## Literals by context
161171
162−Number and cell literals resolve like tags: each waits for its context and takes a default when its `++` is checked. A number takes `@ud` only if nothing fixes its aura and its `++` isn't generic over it, so `++ inc |= n=A (add n 1)` stays generic, while the sum in `"{(add 1 2)}"` is a `@ud`.
172+Number and cell literals resolve like tags: each waits for its context and takes a default when its `++` is checked. A number is a `@ud`, as in Hoon: a context can make it a `@u`, and it fits `@` and `*`, but every other aura takes its own literal, as `~s30` for a `@dr`, `~2026.1.1` for a `@da`, `~zod` for a `@p`, `"5"` for a `@t` and `0x1` for a `@ux`. So `^- @dr 30`, `^- @p 0`, `(add ~s1 1)` and `(text 5)` are errors, each naming the number and the aura it met. A number takes `@ud` only if nothing fixes its aura and its `++` isn't generic over it, so `++ inc |= n=A (add n 1)` stays generic, and `(inc ~s1)` is a `@dr`, while the sum in `"{(add 1 2)}"` is a `@ud`.
163173
164174| Literal | Can become | Default |
165175| --- | --- | --- |
166176| Tag `%a`, or `~` | A union's case or a constant atom | None: an error asking for a `^-` |
167−| Number `5` | Any aura | `@ud` |
177+| Number `5` | `@ud` or `@u`, or any aura its `++` is generic over | `@ud` |
168178| Cell `[x xs]` | A tuple, a record, a cons | A tuple |
169179
170180- In `{…}`, an atom prints by its aura: `@ud` as `1.000`, `@da` as a UTC date with sub-seconds, `@p` as a ship, and a bare `@` as `@ud`. `@t`, `@ta`, `@tas` and tapes splice as text; any other cell is an error asking for a printer. Printers are picked when compiling, so an atom whose aura its `++` is generic over, as `n` in `|= n=A` when `A` is constrained to atoms, is an error asking for an aura, here and in a `(…)` segment of an application path. For readers, `print-date` prints in the theme's zone, Urbit-style, to the minute, as `~2026.10.29..14.30`; numbers keep Hoon's form.
@@ -181,7 +191,7 @@ Number and cell literals resolve like tags: each waits for its context and takes
181191
182192## Patterns
183193
184−Arms are tried in order. Every case needs an arm or a catch-all, `*` or a bare name. An arm that earlier arms cover, such as a second `%add` or anything after `[%move * *]`, is an error, and a case that should fail says `!!`. A name in a pattern always binds anew, so compare values with `?- (eq a b)`. A name is an error where the subject's type at its position is a union, or a one-case mold, and a case that the rest of the pattern can match has there the constant the name spells, so `stop` written for `%stop` below is an error, not a catch-all. Positions typed by an aura, `*`, a type variable, a container's element or a recursive mold are unaffected, so `[t %draft] t` still binds `t`, and `x` is still a catch-all on a `@tas` subject. Patterns take terms, numbers, strings without `{…}`, ships, loobeans and `~`, and cells of patterns, which nest; not `~[…]` lists or `a+b` pairs.
194+Arms are tried in order. Every case needs an arm or a catch-all, `*` or a bare name. An arm that earlier arms cover, such as a second `%add` or anything after `[%move * *]`, is an error, and a case that should fail says `!!`. A name in a pattern always binds anew, so compare values with `?- (eq a b)`. A name is an error where the subject's type at its position is a union, or a one-case mold, and a case that the rest of the pattern can match has there the constant the name spells, so `stop` written for `%stop` below is an error, not a catch-all. Positions typed by an aura, `*`, a type variable, a container's element or a recursive mold are unaffected, so `[t %draft] t` still binds `t`, and `x` is still a catch-all on a `@tas` subject. Patterns take terms, numbers, strings without `{…}`, ships, loobeans and `~`, and cells of patterns, which nest; not `~[…]` lists or `a+b` pairs. A number pattern is a `@ud` too, so `0` can't match a `@p` or a `@dr`: write `~zod`, or compare a duration with `eq`.
185195
186196| Pattern | Matches | Binds |
187197| --- | --- | --- |
@@ -213,11 +223,11 @@ Tags can sit anywhere in a case, and a case can carry several:
213223
214224++ describe |= s=step
215225 ?- s
216− [%move %left n] "left {n}"
217− [%move %right n] "right {n}"
218− [t %draft] t
219− [t %sent sent-at] t
220− %stop "stop"
226+ [%move %left n] "left {n}"
227+ [%move %right n] "right {n}"
228+ [t %draft] t
229+ [t %sent sent-at] t
230+ %stop "stop"
221231```
222232
223233Leaving out `%stop` is an error naming it; to crash instead, write `%stop !!`.
@@ -239,14 +249,21 @@ definition = "+$" name [ generic ] ( mold | cases )
239249generic = "|$" "[" typevar { typevar } "]" ;
240250cases = INDENT mold { NEWLINE mold } DEDENT ; (* one case is that mold; more make a union *)
241251
242−body = INDENT { definition NEWLINE } expr DEDENT ;
252+body = INDENT rest DEDENT ;
253+rest = { definition NEWLINE } last ; (* a body's lines, to its DEDENT *)
254+last = expr
255+ | head NEWLINE rest (* the rest is the innermost rune's last child *)
256+ | "?-" expr NEWLINE arm { NEWLINE arm } ; (* arms at the ?-'s depth *)
257+head = { "|=" field | "^-" mold } ( "|=" field | "^-" mold | "~&" expr ) ; (* on one line *)
243258expr = rune | call ;
244259call = operand { operand } ;
245260operand = literal | qath | ref | change | pair | unit | group | list | tuple
246261 | gate | ctor | pathlit | "!!" ;
247262ref = wing ;
248263wing = name { "." name } ;
249−change = wing "(" item { item } ")" | wing "(" { item } open ; (* no space before "("; items named *)
264+change = wing "(" edit { edit } ")" | wing "(" { edit } elines ; (* no space before "(" *)
265+edit = wing "=" operand ; (* a name, or a wing through record fields *)
266+elines = INDENT wing "=" expr { NEWLINE wing "=" expr } DEDENT ;
250267pair = name "+" operand ; (* [%name operand] *)
251268unit = "`" operand ; (* [~ operand] *)
252269group = "(" expr ")" | "(" { operand } open ;
@@ -287,7 +304,7 @@ pathlit = "/" knot { "/" knot } ;
287304term = "%" name | "%" decimal | "%&" | "%|" | "%$" ;
288305loobean = "%.y" | "%.n" ;
289306aura = "@" { lower } [ upper ] ;
290−typevar = upper ;
307+typevar = upper { lower | digit } ;
291308name = lower { lower | digit | "-" } ;
292309knot = { lower | digit | "-" | "." | "~" | "_" } ;
293310```
@@ -305,8 +322,8 @@ knot = { lower | digit | "-" | "." | "~" | "_" } ;
305322++ init ^- state [items=~ open=%.n]
306323++ update |= [a=poke s=state]
307324 ?- a
308− [%add item] s(items=[item items.s])
309− %toggle s(open=(not open.s))
325+ [%add item] s(items=[item items.s])
326+ %toggle s(open=(not open.s))
310327```
311328
312329```jibb
@@ -328,11 +345,11 @@ knot = { lower | digit | "-" | "." | "~" | "_" } ;
328345
329346++ update |= [=msg m=model]
330347 ?- msg
331− [%noted t] [m(note=t) ~]
332− %add [m(note="") ~[(poke.cart [%add note.m] |=%acked)]]
333− %toggle [m ~[(poke.cart %toggle |=%acked)]]
334− [%got c] [m(cart=c) ~]
335− [%acked err] [m ~]
348+ [%noted t] [m(note=t) ~]
349+ %add [m(note="") ~[(poke.cart [%add note.m] |=%acked)]]
350+ %toggle [m ~[(poke.cart %toggle |=%acked)]]
351+ [%got c] [m(cart=c) ~]
352+ [%acked err] [m ~]
336353
337354++ subs |= m=model
338355 ~[[%watch (state.cart |=%got)]]
docs/spec/overview.md+8−8
@@ -469,14 +469,14 @@ A `page`: each request scries `%blog` and renders in Nock.
469469
470470++ update |= [=msg m=model]
471471 ?- msg
472− [%typed t]
473− ?- (gth (lent (tuba (trip t))) 80)
474− %.y [m(draft=t error=`"Too long") ~]
475− %.n [m(draft=t error=~) ~]
476− %submit [m(draft="") ~[(poke.todo [%add draft.m] |=%acked)]]
477− [%toggled id] [m ~[(poke.todo [%toggle id] |=%acked)]]
478− [%got ts] [m(todos=ts) ~]
479− [%acked err] [m(error=err) ~]
472+ [%typed t]
473+ ?- (gth (lent (tuba (trip t))) 80)
474+ %.y [m(draft=t error=`"Too long") ~]
475+ %.n [m(draft=t error=~) ~]
476+ %submit [m(draft="") ~[(poke.todo [%add draft.m] |=%acked)]]
477+ [%toggled id] [m ~[(poke.todo [%toggle id] |=%acked)]]
478+ [%got ts] [m(todos=ts) ~]
479+ [%acked err] [m(error=err) ~]
480480
481481++ subs |= m=model
482482 ~[[%watch (todos.todo |=%got)]]
docs/status.md+10−2
@@ -36,6 +36,8 @@ These rows cover milestone 1. The plan's three done-when criteria are the rows o
3636| Layout pass: `+layout` (library section 2) emits INDENT, DEDENT and NEWLINE | Done | `lex-layout-*`, `lex-indent-*`, `lex-rune-layout-*` |
3737| Lexical rules: for each rule, inputs that break it, with the error's expected place, and inputs that keep it | Done: 148 `-bad-` and 57 `-ok-` cases; the left-out closers, blob and `@c` literals have only `-bad-` cases, and so does `lex-char` | `lex-*` |
3838| Parser: `+parse` and `+parse-tokens` (library section 3) turn the Grammar tab's EBNF into a syntax tree | Done | every golden `tree.txt` |
39+| The rest of a body (syntax review S2): a body's final line hands the lines after it at its depth to a tall `\|=`, `^-` or `~&` that ends it, and a `?-` that begins it may take its arms at its depth; arm, bracket, top-level and definition lines keep deeper bodies | Done: a body of 40,000 same-depth rest lines runs out of memory under eval, where 20,000 parse | `lex-body-rest-*`, [lex-rune-layout-ok-3](../tests/golden/lex-rune-layout-ok-3/) |
40+| Type variables longer than one letter (S7): a capital, then lowercase letters and digits; `AB`, `MSG` and `Msg_x` are errors | Done | `lex-typevar-*` |
3941| Unions without `$?`: a `+$` takes its cases on the lines below, and `$?` is an error | Done | [inline-union-wide](../tests/golden/inline-union-wide/), [inline-union-one-case](../tests/golden/inline-union-one-case/), `inline-hoon-union-*` |
4042| Spans: every node keeps its start and end, and `+golden` appends `SPAN ERROR` when `+check-spans` fails | Done | [jibb-check-spans](../tests/lib/jibb-check-spans.hoon), `tools/golden` |
4143| Parse errors: file, line, column, message, excerpt and caret (`+show-error`), at the first character where the text stops being the start of any valid module (library section 2.0) | Done: each failing case's `about.txt` states the position, except the unclear case below | `lex-*-bad-*`, `inline-*-bad` |
@@ -109,6 +111,7 @@ Two independent audits came before 7c739b7: one compared the library with a refe
109111| Unification: the library's own `+itype-unify-test` cases | Done | [jibb-typecheck](../tests/lib/jibb-typecheck.hoon) |
110112| Atoms: `@`, one-way widening to aura-family parents, branch widening to a present parent, atom constraints from capitals or bare binders | Partial: generic joins needing a common-type rule are unsupported | [types-partial-atom-widening](../tests/golden/types-partial-atom-widening/), [types-partial-aura-family](../tests/golden/types-partial-aura-family/), [types-partial-branch-widening](../tests/golden/types-partial-branch-widening/), [types-partial-bare-atom](../tests/golden/types-partial-bare-atom/), [types-partial-many-atom-constraints](../tests/golden/types-partial-many-atom-constraints/) |
111113| Decimal defaulting: unfixed decimals become `@ud` in gate-free types, including tuples and polymorphic calls | Partial: gate types still report "unresolved aura-variable inference" | [types-partial-decimal-default](../tests/golden/types-partial-decimal-default/) |
114+| Bare decimals fit only `@ud`, `@u`, `@` and `*` (S4), in casts, calls, fields, lists, branch joins and number patterns, with a hint for the aura's own literal | Partial: number patterns are checked only on known-union and atom subjects; a constructor applied directly, `(\|=%wait 30)`, keeps the generic message | `inline-decimal-*` |
112115| Literal heads: `%$` matches null-, loobean-zero- and term-zero-headed cases, and equal heads with disjoint payloads select a unique case | Partial: overlapping same-noun cases decline | [types-literal-constructor-nouns](../tests/golden/types-literal-constructor-nouns/), [types-equal-head-disjoint](../tests/golden/types-equal-head-disjoint/), [types-loobean-singleton-source](../tests/golden/types-loobean-singleton-source/) |
113116| String interpolation: known auras, `@`, tapes and isolated decimals; a known cell asks for a printer, a generic atom for an aura | Partial: a gate or non-tape list, which the Grammar makes a printer error, pending tags, generic or unknown types and a type fixed only later are unsupported | [types-string-interpolation](../tests/golden/types-string-interpolation/) |
114117| Annotation holes: each value or local definition resolves its own `_` before generalization, and later uses cannot repair it | Done: independent decimal holes default to `@ud`, captured and written-capital variables don't, and structural named molds report the hole's site | `types-hole-*`, [jibb-hole-guards](../tests/lib/jibb-hole-guards.hoon) |
@@ -123,10 +126,11 @@ Two independent audits came before 7c739b7: one compared the library with a refe
123126| --- | --- | --- |
124127| Duplicate field names in a written record, including nested records, samples and expressions | Done: both sites are shown | [types-record-field-nested-mold](../tests/golden/types-record-field-nested-mold/), [types-record-field-expr-duplicate](../tests/golden/types-record-field-expr-duplicate/), [types-record-field-sample-duplicate](../tests/golden/types-record-field-sample-duplicate/) |
125128| Acyclic local definitions with captures, simple and nonrecursive generic mold aliases, faced record casts and field reads | Partial: selected shapes only | `types-local-*`, `types-generic-*`, `types-record-*` |
126−| Record changes: uniquely named fields, nested wings, field context for replacements | Done: unknown or partly unfaced spines are unsupported, and mismatches point at the edit, not the field's declaration | [types-record-change](../tests/golden/types-record-change/) |
129+| Record changes: uniquely named fields, wing items through record fields (S6), with same-field and nested overlaps rejected, nested wings, field context for replacements | Done: unknown or partly unfaced spines are unsupported, and mismatches point at the edit, not the field's declaration | [types-record-change](../tests/golden/types-record-change/) |
127130| Record initializers under a known record cast, including nested list and union fields | Partial: mismatches point at the cast mold | [types-record-cast-context](../tests/golden/types-record-cast-context/) |
128131| A value of type variable `A` in a field typed `A`, including union payloads and nested or repeated fields | Partial: faces of differing variables don't merge | [types-generic-face-inference](../tests/golden/types-generic-face-inference/) |
129132| `proj`: explicit `(proj record)` with a known closed record type, keeping field-axis evidence for lowering; `proj` is reserved in definitions, samples, patterns and imports | Partial: same-order fields only; no context, a bare or aliased `proj` and the wrong arity fail closed | [jibb-proj-guards](../tests/lib/jibb-proj-guards.hoon), `types-proj-*` |
133+| `unface` (S1): removes every face from its argument's type, through cells, gate samples and products, containers' arguments and the unit's payload, keeping unions and recursive molds whole; reserved with `proj`; `++ f (unface \|= …)` is a gate for recursion | Partial: an argument of unknown type is unsupported; islands, pages and stores don't see a gate through `unface`; lowering waits for milestone 3 | `inline-unface-*` |
130134| `proj` with reordered fields or in nested unit, list or call contexts; `proj` lowering and execution | Missing: field order is open (question 32 in [open-questions.md](open-questions.md)) | [types-proj-explicit-context](../tests/golden/types-proj-explicit-context/), [types-proj-nested-no-implicit](../tests/golden/types-proj-nested-no-implicit/) |
131135| List literals without context, empty and nested, generalized independently | Partial: unresolved item tags and uncertain widening fail closed | [types-list-open](../tests/golden/types-list-open/), [types-list-open-constraints](../tests/golden/types-list-open-constraints/) |
132136| List literals with the validated prelude list and a known cast or sample: empty, nonempty, nested and cons, contextual tags, imported-list contexts | Done: a bad element, head or tail names both sites | [types-list-context](../tests/golden/types-list-context/), [types-list-cons](../tests/golden/types-list-cons/), [types-list-imported](../tests/golden/types-list-imported/), [types-list-zero-fit](../tests/golden/types-list-zero-fit/) |
@@ -150,6 +154,7 @@ Two independent audits came before 7c739b7: one compared the library with a refe
150154| Generic aliases may reorder, repeat or omit parameters, keeping a union's origin through scopes and library interfaces | Done: generic unions declared in a body and constraints on differing variables' faces are unsupported | [types-generic-union-alias](../tests/golden/types-generic-union-alias/), [types-generic-union-transitive](../tests/golden/types-generic-union-transitive/), [jibb-generic-alias](../tests/lib/jibb-generic-alias.hoon) |
151155| Nested unions compare by runtime noun; an empty field empties a cell, and unknown inhabitation stays unresolved | Done | [types-partial-union-nested-nouns](../tests/golden/types-partial-union-nested-nouns/) |
152156| Union patterns: whole-case arms, payload binders, imported and generic cases and binder-free catch-alls; missing cases and covered arms are reported | Done | [types-union-patterns](../tests/golden/types-union-patterns/), [types-union-patterns-generic](../tests/golden/types-union-patterns-generic/), [types-union-patterns-import](../tests/golden/types-union-patterns-import/) |
157+| A bare pattern name that spells a tag a matching case has at that position is an error (S5), on every checker path that types `?-` | Done: the full module check reports it only as "needs unsupported inference" | `inline-pattern-tag-name-*` |
153158| Partial boolean patterns: `?` positions split into at most 64 alternatives across the union | Done: past the limit the report says "union pattern expansion needs unsupported inference" | [types-union-finite](../tests/golden/types-union-finite/), [types-union-finite-limit](../tests/golden/types-union-finite-limit/), [types-union-finite-generic](../tests/golden/types-union-finite-generic/) |
154159| Other partial patterns, binders spanning cases, some complex two-arm subjects | Missing: fail closed | [types-union-finite-limit](../tests/golden/types-union-finite-limit/), [types-union-patterns-generic](../tests/golden/types-union-patterns-generic/) |
155160| Union pattern result context from a cast or call sample, for a union reached by a wing, grouped wing or shallow call | Partial: other subject forms are unsupported | [types-union-pattern-result-context](../tests/golden/types-union-pattern-result-context/), [types-union-pattern-result-controls](../tests/golden/types-union-pattern-result-controls/), [types-union-finite-context](../tests/golden/types-union-finite-context/) |
@@ -165,6 +170,8 @@ Two independent audits came before 7c739b7: one compared the library with a refe
165170| --- | --- | --- |
166171| Multi-argument calls: a right-nested sample keeping faces and shared variables, giving context to list and union arguments | Done: unknown-callee contexts and pending tags are unsupported | [types-multi-call](../tests/golden/types-multi-call/) |
167172| Positional calls unify a variable argument with a faced sample slot without passing the face on | Done: `labelled` checks as `$-([label=@t msg=A] (element A))` | [jibb-buttons](../tests/lib/jibb-buttons.hoon), [jibb-positional-face-guards](../tests/lib/jibb-positional-face-guards.hoon), [jibb-closed-gate-guards](../tests/lib/jibb-closed-gate-guards.hoon), [types-positional-faces](../tests/golden/types-positional-faces/) |
173+| A capital that meets a faced position binds only the type under the face (S1 step 1, decided 2026-11-03) | Missing: `(hunt lt-a `1 `2)` still fails; the checker core of review question 5 builds it | [inline-unface-labelled-slot](../tests/golden/inline-unface-labelled-slot/) |
174+| Printed type variables keep their written names (S7), as `(program Data Model Msg)`; a variable with no name prints as an unused letter | Done: when named variables merge, a capital written in the `++` names the result, otherwise the earliest-made one | [types-typevar-names](../tests/golden/types-typevar-names/), [types-typevar-print](../tests/golden/types-typevar-print/) |
168175| Named unions through unconstrained polymorphic gates, keeping origin, arguments and faces | Partial: different origins, explicit-capital forcing and pending tags are unsupported | [types-union-polymorphic-identity](../tests/golden/types-union-polymorphic-identity/) |
169176| Direct gate sample fit: a directly named, checked root gate against a generic gate sample in a direct prelude call | Partial: other cases fall back to ordinary inference, and it proves no island or watchability | [jibb-direct-gate-guards](../tests/lib/jibb-direct-gate-guards.hoon), [jibb-direct-gate-source](../tests/lib/jibb-direct-gate-source.hoon) |
170177| Single self-recursive gates, top-level and local: a monomorphic self reference, then generalization; bad recursive arguments name both sites | Done: polymorphic recursion, explicit-capital forcing and local name collisions are unsupported | [types-recursive-sample](../tests/golden/types-recursive-sample/), [types-recursive-gate](../tests/golden/types-recursive-gate/), [types-local-recursive](../tests/golden/types-local-recursive/) |
@@ -202,7 +209,8 @@ Two independent audits came before 7c739b7: one compared the library with a refe
202209| The validated `list` template for the prelude's own gates and mold aliases; an altered, omitted, duplicate or malformed `list` doesn't leak through aliases | Done | [jibb-list-alias-guards](../tests/lib/jibb-list-alias-guards.hoon), [types-prelude-list-alias](../tests/golden/types-prelude-list-alias/), [types-prelude-list-functions](../tests/golden/types-prelude-list-functions/) |
203210| The prelude `list` and imported Hoon lists unify both ways | Partial: other Jibb-written collection molds and most collection operations are unsupported | [types-list-imported](../tests/golden/types-list-imported/), [types-list-pattern-imported](../tests/golden/types-list-pattern-imported/), [jibb-bridge](../tests/lib/jibb-bridge.hoon) |
204211| With `list` or `unit` missing or altered, independent private molds (`qath`) stay available and dependent ones (`ask`) don't | Done | [jibb-qath-source](../tests/lib/jibb-qath-source.hoon), [jibb-ask-guards](../tests/lib/jibb-ask-guards.hoon) |
205−| Module scope: the prepared and source-taking prelude paths compared against the real prelude | Partial: does not establish complete shadowing coverage | [jibb-module-scope](../tests/lib/jibb-module-scope.hoon), [types-prelude-interface](../tests/golden/types-prelude-interface/) |
212+| Module scope: the prepared and source-taking prelude paths compared against the real prelude | Partial: full checks name top-level conflicts and show both sites when sources are available; nested reserved names and API mark conflicts can still be generic | [jibb-full-scope](../tests/lib/jibb-full-scope.hoon), [jibb-module-scope](../tests/lib/jibb-module-scope.hoon), [types-prelude-interface](../tests/golden/types-prelude-interface/) |
213+| Full-check definition diagnostics | Partial: definite inference failures on unresolved definitions retain their sites; mold, kind and context-dependent failures remain incomplete | [jibb-full-diagnostics](../tests/lib/jibb-full-diagnostics.hoon) |
206214| `fall` and `need` | Done | [prelude-list-unit](../tests/golden/prelude-list-unit/), [types-prelude-direct](../tests/golden/types-prelude-direct/) |
207215| `drop`, `skim`, `skip`, `murn`, `join`, `snip`, `rear` and a shared-type `clap` | Partial: no test calls `rear` | [types-prelude-list-helpers](../tests/golden/types-prelude-list-helpers/), [types-prelude-unit-helpers](../tests/golden/types-prelude-unit-helpers/) |
208216| `bond`, `levy`, `lien`, and gate composition and currying | Partial: currying a faced sample is unsupported | [types-prelude-bond](../tests/golden/types-prelude-bond/), [types-prelude-predicates](../tests/golden/types-prelude-predicates/), [types-prelude-functional](../tests/golden/types-prelude-functional/) |
jibb-dev/lib/jibb.hoon+892−244
@@ -206,9 +206,11 @@
206206:: token holds the text after @. An aura starting @s or
207207:: @r is an error at 2nd: "signed and floating-point
208208:: auras are left out of Jibb"
209−:: A-Z type variable: one capital. A letter or digit right
210−:: after it is an error there, "a type variable is one
211−:: capital letter", after the type variable's token
209+:: A-Z type variable [A-Z][a-z0-9]*: a capital, then
210+:: lowercase letters and digits, as M, Msg or T2. Right
211+:: after it, which is emitted first, a capital, _ or -
212+:: is an error there, "a type variable is a capital,
213+:: then lowercase letters and digits"
212214:: a-z name [a-z][a-z0-9-]*, or a wing: two or more names
213215:: joined by dots. Right after the name or wing, which
214216:: is emitted first, a capital or _ is an error there,
@@ -405,6 +407,7 @@
405407:: Why: after the layout pass the grammar is LL(2). Each choice is made by
406408:: the next token, at most with the one after it and whether it is tight:
407409:: name, then = tight a face (items, lines, fields, samples)
410+:: wing, then = tight a change's item or line, wing=value
408411:: name, then + tight a pair
409412:: name or wing, then ( tight a change
410413:: |=, then a term tight a constructor; else, where an
@@ -412,6 +415,9 @@
412415:: ++ or +$ a definition; else a body's final expr
413416:: INDENT a body, an open bracket's lines, arms
414417:: or cases; else the expression goes on
418+:: NEWLINE, after a rune's head the rest of the body, on a body's
419+:: or ?-'s subject final line (The rest of a body);
420+:: else an error
415421:: So the parser never backtracks, its first failure is its furthest, and
416422:: "expected X, found Y" falls out of each arm without tracking failures
417423:: across alternatives. Hoon's combinators read tapes of characters and
@@ -455,7 +461,9 @@
455461:: cases below -> %mold; one case is that mold, several
456462:: are %union. The optional generic wraps either in %generic.
457463:: ++ name expr or body -> %value (a body becomes a %body expr)
458−:: body INDENT { definition NEWLINE } expr DEDENT -> %body
464+:: body INDENT rest DEDENT; rest is { definition NEWLINE } last
465+:: -> %body, and last is expr, or the rest of a body that
466+:: a rune on its final line took (The rest of a body)
459467:: call one operand is that operand; more -> %call head args
460468:: operand literal -> %lit or %str; pathlit -> %path, as a path
461469:: literal is an expression (Decisions); !! -> %crash, as
@@ -472,7 +480,9 @@
472480:: that line, as () is no group. A ( followed by a rune is
473481:: the closed form. Lines of an open group or list take no
474482:: name= (doc question)
475−:: change every item and line has name= (the EBNF's "items named")
483+:: change every item and line has name= or wing=, as open.cart=
484+:: (the EBNF's edit) -> %change of edits, each with its
485+:: names as written; a tuple's item takes no wing=
476486:: rune |= -> %gate; ^- -> %cast; ~& -> %trace; ?- -> %branch.
477487:: !! is an operand, not a rune (Decisions): alone where an
478488:: expression goes it is a call of one operand, and !! a
@@ -553,7 +563,23 @@
553563:: - Local definitions: at the start of any body, a gate's, an arm's,
554564:: a ^-'s, a ~&'s or a ++'s, as the EBNF's body takes them
555565:: (Decisions); +$ as well as ++, as the Runes prose's "likewise"
556−:: says.
566+:: says. The rest of a body is a body too, so it takes them.
567+:: - The rest of a body (decided 2026-11-03, syntax review S2): a
568+:: body's final line is read with a flag, fin (+read-last), that
569+:: passes down the chain of runes on the line, as ^- @ud ~& x, while
570+:: nothing on the line is left open. A rune whose last child would
571+:: go next, and finds NEWLINE there, takes the lines after it at its
572+:: depth as that child, a body of its own (+read-rest); a ?- that
573+:: begins the line takes them as its arms (+read-branch). The flag
574+:: is off everywhere else: in a bracket, on an arm's line, for a
575+:: definition's own expression, and for a ?- after a rune on the
576+:: line, so ^- @ud ?- x keeps its arms deeper. A line nothing takes
577+:: is an error as before. A rest ends at its body's DEDENT, which
578+:: +read-rest leaves for whatever opened the body, so one DEDENT
579+:: ends every rest nested on that body's lines. Each rest is a level
580+:: of nesting, so the stack grows with them, as with brackets: a
581+:: body of 20.000 ~& x lines at one depth parses, and one of 40.000
582+:: runs out of memory, where 40.000 nested parentheses don't.
557583:: - Where errors point: the doc says only "line, column and an
558584:: excerpt"; 2.0 and Errors below say where.
559585::
@@ -604,11 +630,12 @@
604630:: found the end of the line" (+fail-space). No later line can give
605631:: a tight form its next token. A wing and a ( after a space are no
606632:: error: that is a call; nor is / or %/ alone, a whole path. A
607−:: change's item is name=, so a name there with no = right after it
608−:: fails just past the name, whatever follows: `m(b c)` at the
609−:: space, `m(b)` at the ), `m(a"x)` at the " with the layout pass's
610−:: message after the parser's (+unnamed, +moved). `m(a==1)` has its
611−:: =, and fails at the second, where the layout pass does.
633+:: change's item is name= or wing=, so a name or a wing there with
634+:: no = right after it fails just past it, whatever follows: `m(b c)`
635+:: and `m(a.b 1)` at the space, `m(b)` at the ), `m(a"x)` at the "
636+:: with the layout pass's message after the parser's (+unnamed,
637+:: +moved). `m(a==1)` has its =, and fails at the second, where the
638+:: layout pass does.
612639:: - Where the place needs text on its own line and the line ends,
613640:: whatever line comes next: at the end of that line, just past its
614641:: last token, "found the end of the line" (+fail-line), as no later
@@ -786,7 +813,9 @@
786813:: (value 8:1 init
787814:: (cast 8:9
788815:: (ref 8:12 state)
789−:: (tuple 8:18 (lit 8:19 ~) (lit 8:21 %.n))))
816+:: (tuple 8:18
817+:: (face 8:19 items (lit 8:25 ~))
818+:: (face 8:27 open (lit 8:32 %.n)))))
790819:: (value 9:1 update
791820:: (gate 9:11
792821:: (cell 9:14
@@ -795,17 +824,17 @@
795824:: (body 10:3
796825:: (branch 10:3
797826:: (wing 10:6 a)
798−:: (arm 11:5
799−:: (cell 11:5 (lit 11:6 %add) (bind 11:11 item))
800−:: (change 11:18 s
801−:: (edit 11:20 items
802−:: (tuple 11:26 (wing 11:27 item) (wing 11:32 items.s)))))
803−:: (arm 12:5
804−:: (lit 12:5 %toggle)
805−:: (change 12:18 s
806−:: (edit 12:20 open
807−:: (group 12:25
808−:: (call 12:26 (wing 12:26 not) (wing 12:30 open.s)))))))))))
827+:: (arm 11:3
828+:: (cell 11:3 (lit 11:4 %add) (bind 11:9 item))
829+:: (change 11:16 s
830+:: (edit 11:18 items
831+:: (tuple 11:24 (wing 11:25 item) (wing 11:30 items.s)))))
832+:: (arm 12:3
833+:: (lit 12:3 %toggle)
834+:: (change 12:16 s
835+:: (edit 12:18 open
836+:: (group 12:23
837+:: (call 12:24 (wing 12:24 not) (wing 12:28 open.s)))))))))))
809838::
810839:: 4.3 Errors (+show-error): "<file>:<line>:<col>: <message>", then the
811840:: source line, then a caret under the column (col - 1 spaces, then ^).
@@ -816,9 +845,93 @@
816845:: prints as a space, so the caret stays under its column and golden
817846:: files hold no raw control bytes.
818847::
819−:: /ui/basket.jibb:22:5: msg has no case %submitt
820−:: %submitt [m(note="") ~]
821−:: ^
848+:: /ui/basket.jibb:22:3: msg has no case %submitt
849+:: %submitt [m(note="") ~]
850+:: ^
851+::
852+:: ===================================================================
853+:: 5. General checker core (design; not implemented yet)
854+:: ===================================================================
855+::
856+:: The existing inference and recovery paths are described in
857+:: docs/compiler.md. This section is a plan for replacing them, not a
858+:: claim that the current checker implements these rules. The Grammar and
859+:: Decisions are authoritative if this design needs adjustment.
860+::
861+:: 5.1 State and unification. Give each inference variable an identity and
862+:: a union-find entry: parent or binding, rank, level, source, rigidity,
863+:: and the atom, arithmetic-atom and gate-free obligations it carries.
864+:: Hoon's immutable maps hold the entries; operations return the updated
865+:: state. Find compresses paths in that returned state. Bind only after an
866+:: occurs check, merge obligations at roots, and lower levels throughout
867+:: the bound type to the root's level. A rigid written capital may acquire
868+:: allowed constraints but cannot be forced to a concrete type or a
869+:: different written capital. Keep origins for both sides of each fit so
870+:: a failure can show both excerpts. Recursive named molds retain their
871+:: identity; the occurs check is for inference variables, not a ban on
872+:: declared recursion.
873+::
874+:: A scheme quantifies eligible variables above the enclosing level;
875+:: instantiate with fresh variables and copy their obligations. Written
876+:: capitals respect their lexical scope, including sharing with a local
877+:: definition when the enclosing definition uses the same name. Retain
878+:: aura variables and directional aura fits, rather than turning every
879+:: fit into symmetric equality. At a faced position a capital binds the
880+:: type under the face; joining an unnamed position with a faced one keeps
881+:: the face, independently of the order of the inputs. Different explicit
882+:: faces conflict. No gate may hide inside a gate-free type, including in
883+:: a container; propagate the obligation through its arguments.
884+::
885+:: 5.2 Work queue. A constraint owns its source span, the types and
886+:: expression shape it depends on, and the information needed to report
887+:: failure. Tags and constructors, null, decimal and cell literals,
888+:: wings, changes, unface and unknown match subjects enter the same queue.
889+:: Index waiting constraints by the roots they read. Binding or merging a
890+:: root wakes its dependants; a retry either solves, fails with its sites,
891+:: or registers the roots still needed. Run to a fixed point, without
892+:: losing constraints when a root is redirected. Check patterns once the
893+:: subject is known. Contextual tags inspect case shapes and noun-equal
894+:: heads, retaining the named union and its site in diagnostics.
895+::
896+:: Variables reachable from an open tag constraint remain monomorphic
897+:: across definitions, so a later use, including main, can fix them.
898+:: Other eligible variables can generalize, with their atom and gate-free
899+:: obligations intact. At each definition boundary resolve its holes and
900+:: apply the specified decimal and cell defaults, without defaulting a
901+:: decimal whose definition is generic over its aura. A decimal fits @ud,
902+:: @u, @ and *; other concrete auras need their own literal. At module
903+:: completion retry the queue and report each still-open constraint at its
904+:: source; an unresolved tag asks for a ^-, never a guessed union.
905+::
906+:: 5.3 Definition order and kinds. Use the existing dependency graph's
907+:: strongly connected components in dependency order. Give a recursive
908+:: group of gates monomorphic placeholders, infer all members in one state,
909+:: solve what can be solved, then generalize together. Reject a cycle
910+:: involving a non-gate value, including one through a gate, and show the
911+:: cycle. Check a named definition's holes before later uses can fix them.
912+:: Infer main as an ordinary expression against ordinary prelude schemes;
913+:: only its resulting type determines library, page, island or store.
914+:: Afterwards check kind-specific invariants: recursively find the field
915+:: containing a gate in island data or a model, and inspect subscriptions
916+:: for watchability only at %watch. A page load may be any gate to ask,
917+:: including pure and typed paths. Preserve request provenance needed for
918+:: a watchability proof through ordinary calls and aliases.
919+::
920+:: 5.4 Matches and migration. A reusable usefulness matrix over noun
921+:: constructors, constants, cells and wildcards checks nested patterns;
922+:: loobeans, lists and units expand to their cases. Test an arm against
923+:: previous rows for usefulness, then test a wildcard for exhaustiveness;
924+:: keep a witness for a missing case and the covering arm's site for a
925+:: dead one. Recursive types require memoized specialization and a
926+:: terminating treatment of recursive states. The same matrix can later
927+:: drive lowering. The bare-name/tag spelling rule is checked against the
928+:: subject and the cases the rest of the pattern can match.
929+::
930+:: Migrate in small stages with eval and ship goldens for every change.
931+:: Keep diagnostics and source sites in the single full result; types.txt
932+:: is a rendering of that result. As general inference covers an existing
933+:: recovery or source-proven slice, remove that slice and retain its tests.
934+:: An unsupported construct fails closed at its own site until then.
822935::
823936|%
824937+| %positions
@@ -964,9 +1077,10 @@
9641077::
9651078+$ item $~([*span ~ *expr] [at=span face=(unit term) val=expr])
9661079::
967−:: +edit: a change's item or line, name=value
1080+:: +edit: a change's item or line, name=value or wing=value; names
1081+:: as written, as a %wing's: open.cart is ~[%open %cart]
9681082::
969−+$ edit $~([*span %$ *expr] [at=span name=term val=expr])
1083++$ edit $~([*span ~ *expr] [at=span names=(list term) val=expr])
9701084::
9711085:: +arm: a ?- arm, a pattern and an expression or body
9721086::
@@ -1355,10 +1469,10 @@
13551469 =? n &(?=(^ rest) (is-upper i.rest)) +(n)
13561470 (emit +(n) [%aura (@ta (crip (scag n t.cs)))])
13571471 ?: (is-upper a)
1358− => (emit 1 [%tvar a])
1359− ?. &(?=(^ cs) |((is-lower i.cs) (is-upper i.cs) (is-digit i.cs)))
1360− cor
1361− (err col "a type variable is one capital letter")
1472+ =/ n=@ud (run-len t.cs tvar-mask)
1473+ => (emit +(n) [%tvar (crip [a (scag n t.cs)])])
1474+ ?. &(?=(^ cs) |((is-upper i.cs) =('_' i.cs) =('-' i.cs))) cor
1475+ (err col "a type variable is a capital, then lowercase letters and digits")
13621476 ?: =(':' a)
13631477 ?. =(0 dep) (err col "a comment can't start inside `\{…}`")
13641478 ?: =(':' b) comment
@@ -1662,6 +1776,7 @@
16621776++ digit-mask 0x3ff.0000.0000.0000 :: 0-9
16631777++ hex-mask 0x7e.0000.0000.03ff.0000.0000.0000 :: 0-9 a-f
16641778++ name-mask 0x7ff.fffe.0000.0000.03ff.2000.0000.0000 :: a-z 0-9 -
1779+++ tvar-mask 0x7ff.fffe.0000.0000.03ff.0000.0000.0000 :: a-z 0-9
16651780++ knot-mask 0x47ff.fffe.8000.0000.03ff.6000.0000.0000 :: and . ~ _
16661781++ number-mask 0x7ff.fffe.07ff.fffe.03ff.4000.0000.0000 :: a-z A-Z 0-9 .
16671782++ bad-mask 0x8000.0000.0000.0000.0000.0000.ffff.fbff :: 2.2
@@ -2280,7 +2395,7 @@
22802395++ sexp-edit
22812396 |= e=edit
22822397 ^- sexp
2283− (nod "edit" at.e (trip name.e) ~[(sexp-expr val.e)])
2398+ (nod "edit" at.e (show-names names.e) ~[(sexp-expr val.e)])
22842399::
22852400++ sexp-arm
22862401 |= a=arm
@@ -2689,24 +2804,32 @@
26892804 ?~ t.els i.els
26902805 [%call [beg:(span-of i.els) end:(span-of (rear t.els))] i.els t.els]
26912806::
2807+:: +slot: a bracket's item or line as read, before +bracket-node
2808+:: makes it an item or an edit: its name=, or a change's wing=, else ~
2809+::
2810++$ slot [at=span face=(list term) val=expr]
2811+::
26922812:: +bracket-node: a tuple, list or change from its items, ending at fin
26932813::
26942814++ bracket-node
26952815 |= $: kind=?(%tuple %list %change)
26962816 op=token
26972817 target=(unit [t=token names=(list term)])
2698− its=(list item)
2818+ its=(list slot)
26992819 fin=loc
27002820 ==
27012821 ^- expr
27022822 ?- kind
2703− %tuple [%tuple [beg.at.op fin] its]
2704− %list [%list [beg.at.op fin] (turn its |=(i=item val.i))]
2823+ %tuple
2824+ :+ %tuple [beg.at.op fin]
2825+ (turn its |=(i=slot ^-(item [at.i ?~(face.i ~ `i.face.i) val.i])))
2826+ ::
2827+ %list [%list [beg.at.op fin] (turn its |=(i=slot val.i))]
27052828 ::
27062829 %change
27072830 =/ beg=loc ?~(target beg.at.op beg.at.t.u.target)
27082831 :^ %change [beg fin] ?~(target ~ names.u.target)
2709− (turn its |=(i=item ^-(edit [at.i ?~(face.i %$ u.face.i) val.i])))
2832+ (turn its |=(i=slot ^-(edit [at.i face.i val.i])))
27102833 ==
27112834::
27122835+| %parser
@@ -2927,23 +3050,22 @@
29273050 ::
29283051 :: +unnamed: a change's item or line without its name=
29293052 ::
2930− :: A name could still begin one, so the error is just past it, as
2931− :: a tight form's is (+fail-space): `m(b c)` at the space, `m(b)`
2932− :: at the ). So is an error token's text there, unless it begins
2933− :: with the =: `m(a"x)` at the ", with the layout pass's message
2934− :: after the parser's (+moved), but `m(a==1)` at the lexer's error,
2935− :: the second =. So is a wing's first name: `m(a.b=1)` fails at the
2936− :: dot (+fail-in). At an error token whose text can't begin a name,
2937− :: at that text, as `m( @sd` at the @ (+fail-in).
3053+ :: A name or a wing could still begin one, so the error is just
3054+ :: past it, as a tight form's is (+fail-space): `m(b c)` and
3055+ :: `m(a.b 1)` at the space, `m(b)` at the ). So is an error token's
3056+ :: text there, unless it begins with the =: `m(a"x)` at the ", with
3057+ :: the layout pass's message after the parser's (+moved), but
3058+ :: `m(a==1)` at the lexer's error, the second =. At an error token
3059+ :: whose text can't begin a name, at that text, as `m( @sd` at the
3060+ :: @ (+fail-in).
29383061 ::
29393062 ++ unnamed
29403063 |= ts=(list token)
29413064 ^- [%| p=error]
29423065 =/ why=tape "a change's items are named, as in m(done=%.y)"
29433066 ?: ?=([[* * [%error *]] *] ts) (bad-in ts "a named item" lower-mask)
2944− ?: ?=([[* * [%wing *]] *] ts)
2945− (bad-in-why ts "a named item" lower-mask why)
2946− ?. ?=([[* * [%name *]] *] ts) (bad-why ts "a named item" why)
3067+ ?. ?=([[* * ?([%name *] [%wing *])] *] ts)
3068+ (bad-why ts "a named item" why)
29473069 =/ want=tape "`=` right after {(show-found i.ts)}"
29483070 ?: ?& ?=([* [* * [%error *]] *] ts)
29493071 =(end.at.i.ts from.lex.i.t.ts)
@@ -2961,9 +3083,10 @@
29613083 :: closes on its line (2.9). A bracket that needs none of these
29623084 :: closes with the deeper lines instead (+shut). No later line can
29633085 :: give it that, so the error is at the end of the line that took
2964− :: them (section 3, Errors). want is what it needs. Only an error path
2965− :: calls this, and it looks only when after begins with NEWLINE or
2966− :: DEDENT, so it costs nothing on the way to a tree.
3086+ :: them (section 3, Errors). want is what it needs. It looks only when
3087+ :: after begins with NEWLINE or DEDENT, so it costs nothing on the way
3088+ :: to a tree, except where a rune takes the rest of a body (+read-last):
3089+ :: a look at that rune's line.
29673090 ::
29683091 ++ doomed
29693092 |= [ts=(list token) after=(list token) want=tape]
@@ -3120,7 +3243,7 @@
31203243 ?: =(%'++' lex.rune)
31213244 ;< [nam=term after=(list token)] then (read-def-name rune t.ts)
31223245 ;< [e=expr more=(list token)] then
3123− (read-expr-or-body "the name" after)
3246+ (read-expr-or-body | "the name" after)
31243247 [%& [%value [beg.at.rune end:(span-of e)] nam e] more]
31253248 ?: (is-closer rune)
31263249 %^ bad-why ts "a definition"
@@ -3200,20 +3323,36 @@
32003323 [%& p.lex.i.ts t.ts]
32013324 ::
32023325 :: +read-expr-or-body: a space and an expression on the line, or a
3203− :: body on deeper lines; what names what comes before, for errors
3326+ :: body on deeper lines; what names what comes before, for errors.
3327+ :: On a body's final line (fin, +read-last), a line at the same depth
3328+ :: is the rest of the body instead, and the expression on the line
3329+ :: goes on with fin, except a ?-, which keeps its arms deeper
32043330 ::
32053331 ++ read-expr-or-body
3206− |= [what=tape ts=(list token)]
3332+ |= [fin=? what=tape ts=(list token)]
32073333 ^- (pare expr)
32083334 ?: ?=([[* * %indent] *] ts) (read-body t.ts)
3335+ ?: &(fin ?=([[* * %newline] *] ts)) (read-rest t.ts)
32093336 ?: ?=([[* * ?(%newline %dedent)] *] ts)
32103337 (bad ts "an expression, or a body on deeper lines")
32113338 ?: &(?=(^ ts) tight.i.ts) (no-gap ts "a space after {what}")
3212− (read-expr ts)
3339+ (read-last &(fin !?=([[* * %'?-'] *] ts)) ts)
32133340 ::
3214− :: +read-body: after its INDENT, { definition NEWLINE } expr DEDENT
3341+ :: +read-body: after its INDENT, the rest of a body, then its DEDENT
32153342 ::
32163343 ++ read-body
3344+ |= ts=(list token)
3345+ ^- (pare expr)
3346+ ;< [e=expr after=(list token)] then (read-rest ts)
3347+ ?> ?=([[* * %dedent] *] after)
3348+ [%& e t.after]
3349+ ::
3350+ :: +read-rest: { definition NEWLINE } last, up to the DEDENT that ends
3351+ :: a body, which it leaves for whatever opened the body: its INDENT's
3352+ :: reader, or the rune on the final line that took the rest of it
3353+ :: (+read-last)
3354+ ::
3355+ ++ read-rest
32173356 |= ts=(list token)
32183357 ^- (pare expr)
32193358 =| defs=(list def)
@@ -3227,12 +3366,15 @@
32273366 %: bad-in-why ts "a definition or an expression" plus-mask
32283367 "`+` begins `++` or `+$`"
32293368 ==
3230− ;< [e=expr after=(list token)] then (read-expr ts)
3369+ ;< [e=expr after=(list token)] then (read-last & ts)
32313370 ?: ?=([[* * %dedent] *] after)
32323371 =/ ds=(list def) (flop defs)
32333372 =/ beg=loc ?~(ds beg:(span-of e) beg:(span-of i.ds))
3234− [%& [%body [beg end:(span-of e)] ds e] t.after]
3373+ [%& [%body [beg end:(span-of e)] ds e] after]
32353374 ?. ?=([[* * %newline] *] after) (bad-end-in after (tail-can e))
3375+ ?: &(?=(%branch -.e) !?=([* [* * ?(%'++' %'+$')] *] after))
3376+ %^ bad-why after "the end of the body"
3377+ "this `?-`'s arms are on deeper lines, so this one goes there too"
32363378 %^ bad-why after "the end of the body"
32373379 "a body's final expression is its last line"
32383380 ::
@@ -3241,13 +3383,24 @@
32413383 ++ read-expr
32423384 |= ts=(list token)
32433385 ^- (pare expr)
3386+ (read-last | ts)
3387+ ::
3388+ :: +read-last: +read-expr, where fin says the expression is a body's
3389+ :: final line or goes on one, with no bracket open before it: then
3390+ :: the rune that ends the line may take the rest of the body at the
3391+ :: same depth as its last child, and a ?- that begins the line its
3392+ :: arms (section 3, The rest of a body)
3393+ ::
3394+ ++ read-last
3395+ |= [fin=? ts=(list token)]
3396+ ^- (pare expr)
32443397 ?~ ts (bad ts "an expression")
32453398 =* t i.ts
32463399 ?+ lex.t (read-call ts)
3247− %'|=' ?:((is-ctor ts) (read-call ts) (read-gate t t.ts))
3248− %'^-' (read-cast t t.ts)
3249− %'~&' (read-trace t t.ts)
3250− %'?-' (read-branch t t.ts)
3400+ %'|=' ?:((is-ctor ts) (read-call ts) (read-gate fin t t.ts))
3401+ %'^-' (read-cast fin t t.ts)
3402+ %'~&' (read-trace fin t t.ts)
3403+ %'?-' (read-branch fin t t.ts)
32513404 ==
32523405 ::
32533406 :: +read-call: operand { operand }; one operand alone is itself
@@ -3462,9 +3615,9 @@
34623615 (unclosed par ")" after)
34633616 ;< [els=(list expr) after=(list token)] then (read-operands ts)
34643617 ?: ?=([[* * %indent] *] after)
3465− ;< [ls=(list item) more=(list token)] then
3618+ ;< [ls=(list slot) more=(list token)] then
34663619 (read-lines %group t.after)
3467− =/ inner=expr (call-of (weld els (turn ls |=(i=item val.i))))
3620+ =/ inner=expr (call-of (weld els (turn ls |=(i=slot val.i))))
34683621 [%& [%group [beg.at.par end:(span-of inner)] inner] more]
34693622 ?~ els
34703623 ?: ?=([[* * ?(%newline %dedent)] *] after)
@@ -3489,7 +3642,7 @@
34893642 ==
34903643 ^- (pare expr)
34913644 =/ close=?(%')' %']') ?:(?=(%change kind) %')' %']')
3492− =| its=(list item)
3645+ =| its=(list slot)
34933646 |- ^- (pare expr)
34943647 ?~ ts (bad ts "an item")
34953648 =* t i.ts
@@ -3497,8 +3650,8 @@
34973650 [%& (bracket-node kind op target (flop its) end.at.t) t.ts]
34983651 ?: (is-closer t) (unclosed op (trip close) ts)
34993652 ?: ?=(%indent lex.t)
3500− ;< [ls=(list item) more=(list token)] then (read-lines kind t.ts)
3501− =/ every=(list item) (weld (flop its) ls)
3653+ ;< [ls=(list slot) more=(list token)] then (read-lines kind t.ts)
3654+ =/ every=(list slot) (weld (flop its) ls)
35023655 =/ fin=loc ?~(every end.at.op end.at:(rear every))
35033656 [%& (bracket-node kind op target every fin) more]
35043657 ?: &(?=(^ its) (shut op `at.i.its ts))
@@ -3506,21 +3659,21 @@
35063659 ?: ?=(?(%newline %dedent) lex.t)
35073660 (unclosed-open op (trip close) "an item" ts)
35083661 ?: &(tight.t ?=(^ its)) (no-space ts)
3509− ;< [i=item more=(list token)] then (read-item kind ts)
3662+ ;< [i=slot more=(list token)] then (read-item kind ts)
35103663 $(its [i its], ts more)
35113664 ::
35123665 :: +read-item: [ name= ] operand; a tuple's item may be named, a
3513− :: change's must be, a list's is not
3666+ :: change's must be, by a name or a wing, a list's is not
35143667 ::
35153668 ++ read-item
35163669 |= [kind=?(%tuple %list %change) ts=(list token)]
3517− ^- (pare item)
3518− ?: &(!?=(%list kind) ?=([[* * [%name *]] [* %& %'='] *] ts))
3670+ ^- (pare slot)
3671+ ?: &(?=([* * *] ts) (named-item kind ts))
35193672 =* nam i.ts
35203673 =/ rest=(list token) t.t.ts
35213674 ?: |(?=(~ rest) !tight.i.rest) (bad-space i.t.ts rest "a value")
35223675 ;< [v=expr after=(list token)] then (read-operand rest)
3523− [%& [[beg.at.nam end:(span-of v)] `p.lex.nam v] after]
3676+ [%& [[beg.at.nam end:(span-of v)] (names-of lex.nam) v] after]
35243677 ?: ?=(%change kind) (unnamed ts)
35253678 ?: &(?=(^ ts) (is-rune i.ts))
35263679 %: bad-in-why ts "an expression" operand-mask
@@ -3529,15 +3682,25 @@
35293682 ;< [v=expr after=(list token)] then (read-operand ts)
35303683 [%& [(span-of v) ~ v] after]
35313684 ::
3685+ :: +named-item: whether ts begins an item's or a line's name=: a
3686+ :: tuple's or a change's name, or a change's wing, then = tight
3687+ ::
3688+ ++ named-item
3689+ |= [kind=?(%tuple %list %change %group) ts=(list token)]
3690+ ^- ?
3691+ ?. ?=([* [* %& %'='] *] ts) |
3692+ ?: ?=([[* * [%name *]] *] ts) ?=(?(%tuple %change) kind)
3693+ &(?=(%change kind) ?=([[* * [%wing *]] *] ts))
3694+ ::
35323695 :: +read-lines: after an open bracket's INDENT, its lines, an item
35333696 :: each, to its DEDENT
35343697 ::
35353698 ++ read-lines
35363699 |= [kind=?(%tuple %list %change %group) ts=(list token)]
3537− ^- (pare (list item))
3538− =| ls=(list item)
3539− |- ^- (pare (list item))
3540− ;< [l=item after=(list token)] then (read-line kind ts)
3700+ ^- (pare (list slot))
3701+ =| ls=(list slot)
3702+ |- ^- (pare (list slot))
3703+ ;< [l=slot after=(list token)] then (read-line kind ts)
35413704 ?: ?=([[* * %newline] *] after) $(ls [l ls], ts t.after)
35423705 ?: ?=([[* * %dedent] *] after) [%& (flop [l ls]) t.after]
35433706 ?. ?=([[* * ?(%')' %']')] *] after) (bad-end-in after (tail-can val.l))
@@ -3564,22 +3727,20 @@
35643727 "its items end at the first line that isn't deeper"
35653728 ::
35663729 :: +read-line: an open bracket's line, [ name= ] expr; a tuple's may
3567− :: be named, a change's must be, a list's and a group's are not
3568− :: (doc question)
3730+ :: be named, a change's must be, by a name or a wing, a list's and a
3731+ :: group's are not (doc question)
35693732 ::
35703733 ++ read-line
35713734 |= [kind=?(%tuple %list %change %group) ts=(list token)]
3572− ^- (pare item)
3735+ ^- (pare slot)
35733736 =/ cf (closer-first ts "an item")
35743737 ?^ cf u.cf
3575− ?: ?& ?=(?(%tuple %change) kind)
3576− ?=([[* * [%name *]] [* %& %'='] *] ts)
3577− ==
3738+ ?: &(?=([* * *] ts) (named-item kind ts))
35783739 =* nam i.ts
35793740 =/ rest=(list token) t.t.ts
35803741 ?: |(?=(~ rest) !tight.i.rest) (bad-space i.t.ts rest "a value")
35813742 ;< [v=expr after=(list token)] then (read-expr rest)
3582− [%& [[beg.at.nam end:(span-of v)] `p.lex.nam v] after]
3743+ [%& [[beg.at.nam end:(span-of v)] (names-of lex.nam) v] after]
35833744 ?: ?=(%change kind) (unnamed ts)
35843745 ;< [v=expr after=(list token)] then (read-expr ts)
35853746 [%& [(span-of v) ~ v] after]
@@ -3616,10 +3777,11 @@
36163777 %^ bad-why more (closing op ")")
36173778 "the wide gate's body is one operand, so a call goes in parentheses"
36183779 ::
3619− :: +read-gate: |= sample, then an expression or a body
3780+ :: +read-gate: |= sample, then an expression or a body; fin as for
3781+ :: +read-last
36203782 ::
36213783 ++ read-gate
3622− |= [bar=token ts=(list token)]
3784+ |= [fin=? bar=token ts=(list token)]
36233785 ^- (pare expr)
36243786 ?: &(?=(^ ts) tight.i.ts)
36253787 :: a % could begin a constructor's term, as |=%got
@@ -3631,13 +3793,14 @@
36313793 =/ dm (doomed ts after "an expression, or a body on deeper lines")
36323794 ?^ dm u.dm
36333795 ;< [e=expr more=(list token)] then
3634− (read-expr-or-body "the sample" after)
3796+ (read-expr-or-body fin "the sample" after)
36353797 [%& [%gate [beg.at.bar end:(span-of e)] s e] more]
36363798 ::
3637− :: +read-cast: ^- mold, then an expression or a body
3799+ :: +read-cast: ^- mold, then an expression or a body; fin as for
3800+ :: +read-last
36383801 ::
36393802 ++ read-cast
3640− |= [ket=token ts=(list token)]
3803+ |= [fin=? ket=token ts=(list token)]
36413804 ^- (pare expr)
36423805 ?: &(?=(^ ts) tight.i.ts) (wide-rune "^-" ts)
36433806 ;< [s=shape after=(list token)] then (read-mold ts)
@@ -3646,41 +3809,65 @@
36463809 =/ dm (doomed ts after "an expression, or a body on deeper lines")
36473810 ?^ dm u.dm
36483811 ;< [e=expr more=(list token)] then
3649− (read-expr-or-body "the mold" after)
3812+ (read-expr-or-body fin "the mold" after)
36503813 [%& [%cast [beg.at.ket end:(span-of e)] s e] more]
36513814 ::
3652− :: +read-trace: ~& expr, then its body below
3815+ :: +read-trace: ~& expr, then its body below, or, on a body's final
3816+ :: line (fin, +read-last), the rest of the body
36533817 ::
36543818 ++ read-trace
3655− |= [sig=token ts=(list token)]
3819+ |= [fin=? sig=token ts=(list token)]
36563820 ^- (pare expr)
36573821 ?: &(?=(^ ts) tight.i.ts) (wide-rune "~&" ts)
36583822 ;< [v=expr after=(list token)] then (read-expr ts)
3659− ?. ?=([[* * %indent] *] after)
3660− =/ dm (doomed ts after "`~&`'s body on deeper lines")
3661− ?^ dm u.dm
3823+ =/ dm (doomed ts after "`~&`'s body on deeper lines")
3824+ ?^ dm u.dm
3825+ ;< [b=expr more=(list token)] then
3826+ ?: ?=([[* * %indent] *] after) (read-body t.after)
3827+ ?: &(fin ?=([[* * %newline] *] after)) (read-rest t.after)
36623828 (bad after "`~&`'s body on deeper lines")
3663− ;< [b=expr more=(list token)] then (read-body t.after)
36643829 [%& [%trace [beg.at.sig end:(span-of b)] v b] more]
36653830 ::
3666− :: +read-branch: ?- expr, then its arms below, one per line
3831+ :: +read-branch: ?- expr, then its arms below, one per line; or, when
3832+ :: it begins a body's final line (fin, +read-last), at its own depth
3833+ :: to the end of the body, whose DEDENT it leaves (+read-rest)
36673834 ::
36683835 ++ read-branch
3669− |= [wut=token ts=(list token)]
3836+ |= [fin=? wut=token ts=(list token)]
36703837 ^- (pare expr)
36713838 ?: &(?=(^ ts) tight.i.ts) (wide-rune "?-" ts)
36723839 ;< [s=expr after=(list token)] then (read-expr ts)
3673− ?. ?=([[* * %indent] *] after)
3674− =/ dm (doomed ts after "`?-`'s arms on deeper lines")
3675− ?^ dm u.dm
3840+ =/ dm (doomed ts after "`?-`'s arms on deeper lines")
3841+ ?^ dm u.dm
3842+ ?. ?=([[* * ?(%indent %newline)] *] after)
36763843 (bad after "`?-`'s arms on deeper lines")
3844+ =/ flat=? ?=(%newline lex.i.after)
3845+ ?: &(flat !fin) (bad after "`?-`'s arms on deeper lines")
36773846 =| arms=(list arm)
36783847 =/ rest=(list token) t.after
36793848 |- ^- (pare expr)
3680− ;< [a=arm more=(list token)] then (read-arm rest)
3849+ ;< [a=arm more=(list token)] then
3850+ ?:(flat (read-flat-arm rest) (read-arm rest))
36813851 ?: ?=([[* * %newline] *] more) $(arms [a arms], rest t.more)
36823852 ?. ?=([[* * %dedent] *] more) (bad-end-in more (tail-can val.a))
3683− [%& [%branch [beg.at.wut end.at.a] s (flop [a arms])] t.more]
3853+ =/ at=span [beg.at.wut end.at.a]
3854+ [%& [%branch at s (flop [a arms])] ?:(flat more t.more)]
3855+ ::
3856+ :: +read-flat-arm: +read-arm at its ?-'s depth, where a line that
3857+ :: could begin the body's other lines gets a hint
3858+ ::
3859+ ++ read-flat-arm
3860+ |= ts=(list token)
3861+ ^- (pare arm)
3862+ ?: ?=([[* * ?(%'++' %'+$')] *] ts)
3863+ %: bad-in-why ts "a pattern" pattern-mask
3864+ "a body's local definitions come before its final expression"
3865+ ==
3866+ ?: ?=([[* * ?(%'~&' %'^-')] *] ts)
3867+ %: bad-in-why ts "a pattern" pattern-mask
3868+ "a trace or cast goes in the arm's body"
3869+ ==
3870+ (read-arm ts)
36843871 ::
36853872 :: +read-arm: a pattern, then an expression or a body
36863873 ::
@@ -3695,7 +3882,7 @@
36953882 %^ bad-why after "a space after the pattern"
36963883 "patterns take no `name=`: a bare name binds, as [a b]"
36973884 ;< [e=expr more=(list token)] then
3698− (read-expr-or-body "the pattern" after)
3885+ (read-expr-or-body | "the pattern" after)
36993886 [%& [[beg:(span-of p) end:(span-of e)] p e] more]
37003887 ::
37013888 :: +read-pattern: a term, number, string, ship, loobean, ~, * or name,
@@ -4437,7 +4624,7 @@
44374624++ outline-edit
44384625 |= e=edit
44394626 ^- outline
4440− [%edit at.e ~[%name] %kid ~[(outline-expr val.e)]]
4627+ [%edit at.e ~[%name %wing] %kid ~[(outline-expr val.e)]]
44414628::
44424629++ outline-arm
44434630 |= a=arm
@@ -4637,6 +4824,14 @@
46374824:: proofs to fewer than 1,024 cells; the projection planner has a separate
46384825:: 4,096-step bound. These are inference limits, not language limits.
46394826::
4827+:: `unface` is reserved with proj (+reserved-name) and is also handled by
4828+:: type: (unface e) has e's type with every face removed, through cells,
4829+:: gates and collection arguments, keeping unions and recursive molds
4830+:: whole (+itype-unface). It is not a value, it takes one argument, and
4831+:: a bare type variable is unsupported, as field access on one is. A ++
4832+:: whose body is (unface |= …) is a gate for recursion (+unfaced-gate).
4833+:: It lowers to its argument; no lowering is implemented yet.
4834+::
46404835:: Supported API imports derive request-gate types atomically for multiple
46414836:: paths, including one typed segment or one diff fold per case. Their checked
46424837:: ordinary definitions, mark molds and supported poke constructor are also
@@ -4944,6 +5139,35 @@
49445139 $(a tal.a, b tal.b, sub u.first)
49455140 ~
49465141::
5142+:: +itype-unface: t with every face removed, for (unface e)
5143+::
5144+:: It strips through cells, through a gate's sample and product and
5145+:: through a built-in collection's arguments, the prelude's unit
5146+:: included, walking bound variables. Other unions and recursive
5147+:: molds are compared by name or by their exact cases, so stripping
5148+:: inside them would stop them from fitting their own name: they are
5149+:: kept whole. An unbound variable stays, so faces it is bound to
5150+:: later are kept. The unit keeps its own u=, as a list keeps i= and
5151+:: t= in its mold.
5152+::
5153+++ itype-unface
5154+ |= [t=itype sub=isub]
5155+ ^- itype
5156+ =. t (itype-walk t sub)
5157+ ?+ -.t t
5158+ %face $(t body.t)
5159+ %cell [%cell $(t hed.t) $(t tal.t)]
5160+ %fn [%fn $(t sample.t) $(t product.t)]
5161+ %collection [%collection name.t (turn args.t |=(a=itype ^$(t a)))]
5162+ %union
5163+ ?. =(origin.t `[/lib/jibb/prelude/jibb %unit]) t
5164+ ?. ?=([* ~] args.t) t
5165+ =/ nil=itype [%const [%null %n 0 '~']]
5166+ ?. =(cases.t ~[nil [%cell nil [%face %u i.args.t]]]) t
5167+ =/ arg=itype $(t i.args.t)
5168+ t(cases ~[nil [%cell nil [%face %u arg]]], args ~[arg])
5169+ ==
5170+::
49475171+$ igf-form [typ=itype sub=isub left=@ud]
49485172+$ igf-forms [types=(list itype) sub=isub left=@ud]
49495173++ itype-gate-free-forms
@@ -6375,15 +6599,67 @@
63756599 ^- ?
63766600 (itype-var-is-gate-free-fuel n t 256)
63776601::
6602+:: +named-var: the ID of the nth type variable, written as name
6603+::
6604+:: An ID counts in its low 64 bits. The name a variable was written
6605+:: with, as Msg, sits above them, or 0 for none, so the name travels
6606+:: with the variable through substitution, generalization and
6607+:: instantiation, and the printer can show it (+show-var). No two
6608+:: IDs share a count, so a name never makes two variables one.
6609+::
6610+++ named-var
6611+ |= [name=@t n=@ud]
6612+ ^- @ud
6613+ (add (lsh 6 name) (end 6 n))
6614+::
6615+:: +var-name: the name in a type variable's ID, or 0 for none
6616+::
6617+++ var-name
6618+ |= id=@ud
6619+ ^- @t
6620+ (rsh 6 id)
6621+::
6622+:: +var-count: a type variable's ID without its name
6623+::
6624+++ var-count
6625+ |= id=@ud
6626+ ^- @ud
6627+ (end 6 id)
6628+::
6629+:: +canonical-itype: t with the variables in vars renumbered to print
6630+::
6631+:: A variable keeps its name unless one before it in vars has the same
6632+:: name. The others take numbers from 0, skipping any whose letter
6633+:: (+show-var) is a name in vars, so a printed type never shows one
6634+:: name for two variables.
6635+::
63786636++ canonical-itype
63796637 |= [t=itype vars=(list @ud)]
63806638 ^- itype
6639+ =/ names=(list @t) (turn vars var-name)
6640+ =/ used=(list @t) ~
63816641 =/ ren=isub ~
63826642 =/ n=@ud 0
63836643 |-
63846644 ?~ vars (itype-rename t ren)
6385− =/ replacement=itype ?:((itype-var-is-restricted i.vars t) [%rvar n] ?:((itype-var-is-atom i.vars t) [%avar n] ?:((itype-var-is-gate-free i.vars t) [%fvar n] [%var n])))
6386− $(vars t.vars, ren [[i.vars replacement] ren], n +(n))
6645+ =/ name=@t (var-name i.vars)
6646+ =/ own=? &(!=(0 name) !(lien used |=(u=@t =(u name))))
6647+ =? n !own (letter-free n names)
6648+ =/ id=@ud ?:(own (named-var name 0) n)
6649+ =/ replacement=itype ?:((itype-var-is-restricted i.vars t) [%rvar id] ?:((itype-var-is-atom i.vars t) [%avar id] ?:((itype-var-is-gate-free i.vars t) [%fvar id] [%var id])))
6650+ $(vars t.vars, ren [[i.vars replacement] ren], n ?:(own n +(n)), used ?:(own [name used] used))
6651+::
6652+:: +letter-free: the first number from n whose letter is none of names
6653+::
6654+++ letter-free
6655+ |= [n=@ud names=(list @t)]
6656+ ^- @ud
6657+ ?. (lien names |=(m=@t =(m (crip (show-var n))))) n
6658+ $(n +(n))
6659+::
6660+:: +instantiate-scheme: a scheme's type with fresh quantified variables
6661+::
6662+:: Each fresh variable keeps the name of the one it replaces.
63876663::
63886664++ instantiate-scheme
63896665 |= [scheme=ischeme state=istate]
@@ -6392,12 +6668,13 @@
63926668 =/ vars=(list @ud) vars.scheme
63936669 |-
63946670 ?~ vars [(itype-rename typ.scheme ren) state]
6671+ =/ fresh=@ud (named-var (var-name i.vars) next.state)
63956672 =/ replacement=itype
6396− ?:((itype-var-is-restricted i.vars typ.scheme) [%rvar next.state] ?:((itype-var-is-atom i.vars typ.scheme) [%avar next.state] ?:((itype-var-is-gate-free i.vars typ.scheme) [%fvar next.state] [%var next.state])))
6673+ ?:((itype-var-is-restricted i.vars typ.scheme) [%rvar fresh] ?:((itype-var-is-atom i.vars typ.scheme) [%avar fresh] ?:((itype-var-is-gate-free i.vars typ.scheme) [%fvar fresh] [%var fresh])))
63976674 :: A generalized atom variable is a valid origin for re-generalizing
63986675 :: an alias, just as a sample binder is.
63996676 =/ st=istate state(next +(next.state))
6400− =? binders.st |(?=(%fvar -.replacement) ?=(%avar -.replacement) ?=(%rvar -.replacement)) [next.state binders.state]
6677+ =? binders.st |(?=(%fvar -.replacement) ?=(%avar -.replacement) ?=(%rvar -.replacement)) [fresh binders.state]
64016678 $(vars t.vars, ren [[i.vars replacement] ren], state st)
64026679::
64036680++ icap-lookup
@@ -7257,7 +7534,8 @@
72577534 ?: in-mold.state ~
72587535 =/ n=(unit @ud) (icap-lookup name.sh caps.state)
72597536 ?^ n `[[%var u.n] state]
7260− `[[%var next.state] state(next +(next.state), caps [[name.sh next.state at.sh] caps.state])]
7537+ =/ id=@ud (named-var name.sh next.state)
7538+ `[[%var id] state(next +(next.state), caps [[name.sh id at.sh] caps.state])]
72617539 * ~
72627540 ==
72637541::
@@ -7290,12 +7568,12 @@
72907568 ^- isample-result
72917569 ?- -.s
72927570 %bind
7293− ?: |(=(name.s %proj) ?=(^ (ienv-lookup name.s env)) (lien globals.state |=(x=term =(x name.s))))
7571+ ?: |((reserved-name name.s) ?=(^ (ienv-lookup name.s env)) (lien globals.state |=(x=term =(x name.s))))
72947572 [%| "sample shadows a name"]
72957573 =/ t=itype [%var next.state]
72967574 [%& t [[name.s [t ~]] env] state(next +(next.state), binders [next.state binders.state])]
72977575 %face
7298− ?: |(=(name.s %proj) ?=(^ (ienv-lookup name.s env)) (lien globals.state |=(x=term =(x name.s))))
7576+ ?: |((reserved-name name.s) ?=(^ (ienv-lookup name.s env)) (lien globals.state |=(x=term =(x name.s))))
72997577 [%| "sample shadows a name"]
73007578 =/ t=(unit [typ=itype state=istate]) (infer-simple-shape shape.s state)
73017579 ?~ t [%| "sample mold is not supported by partial inference"]
@@ -7363,7 +7641,7 @@
73637641 |-
73647642 ?~ ds &
73657643 ?: ?=(%mold -.i.ds) $(ds t.ds)
7366− ?: =(name.i.ds %proj) |
7644+ ?: (reserved-name name.i.ds) |
73677645 ?. (unique-value-name name.i.ds names) |
73687646 ?: ?=(^ (ienv-lookup name.i.ds env)) |
73697647 ?: (lien globals.state |=(n=term =(n name.i.ds))) |
@@ -7387,7 +7665,7 @@
73877665 |-
73887666 ?~ locals &
73897667 =/ n=term name.i.locals
7390− ?: =(n %proj) |
7668+ ?: (reserved-name n) |
73917669 ?. (unique-value-name n names) |
73927670 ?: (lien molds.state |=(m=[name=term body=shape] =(n name.m))) |
73937671 ?: (lien marks.state |=(m=term =(n m))) |
@@ -7537,7 +7815,8 @@
75377815 ^- istate
75387816 ?~ sites state
75397817 ?: ?=(^ (icap-lookup name.i.sites caps.state)) $(sites t.sites)
7540− $(sites t.sites, state state(next +(next.state), caps [[name.i.sites next.state at.i.sites] caps.state]))
7818+ =/ id=@ud (named-var name.i.sites next.state)
7819+ $(sites t.sites, state state(next +(next.state), caps [[name.i.sites id at.i.sites] caps.state]))
75417820::
75427821++ reserve-def-caps
75437822 |= [e=expr state=istate]
@@ -7711,7 +7990,8 @@
77117990 (weld (free-env-vars env sub.state.p.inferred) (free-cap-vars caps.state sub.state.p.inferred))
77127991 =/ vars=(list @ud) (unique-type-vars (itype-vars typ))
77137992 =. vars (skim vars |=(n=@ud !(lien free |=(f=@ud =(f n)))))
7714− $(ds t.ds, env [[name.d [typ vars]] env], state state.p.inferred(caps caps.state, holes holes.state), progressed &)
7993+ =/ named=[typ=itype vars=(list @ud)] (cap-names typ vars caps.state.p.inferred sub.state.p.inferred)
7994+ $(ds t.ds, env [[name.d named] env], state state.p.inferred(caps caps.state, holes holes.state), progressed &)
77157995::
77167996:: Try complete cyclic local groups after individual definitions stall.
77177997:: Components with non-gates or unresolved constraints stay unavailable.
@@ -8065,7 +8345,7 @@
80658345 [%| ["list branch pattern is not supported by partial inference" ~]]
80668346 =/ binder=(unit [head=term tail=term]) ?:(first-empty second-name first-name)
80678347 ?~ binder [%| ["list branch pattern is not supported by partial inference" ~]]
8068− ?: |(=(head.u.binder %proj) =(tail.u.binder %proj) =(head.u.binder tail.u.binder) ?=(^ (ienv-lookup head.u.binder env)) ?=(^ (ienv-lookup tail.u.binder env)) (lien globals.state |=(n=term |(=(n head.u.binder) =(n tail.u.binder)))))
8348+ ?: |((reserved-name head.u.binder) (reserved-name tail.u.binder) =(head.u.binder tail.u.binder) ?=(^ (ienv-lookup head.u.binder env)) ?=(^ (ienv-lookup tail.u.binder env)) (lien globals.state |=(n=term |(=(n head.u.binder) =(n tail.u.binder)))))
80698349 [%| ["pattern binder shadows a name" ~]]
80708350 =/ extended=ienv [[head.u.binder [i.args.typ ~]] [tail.u.binder [typ ~]] env]
80718351 =/ left=iresult
@@ -8102,7 +8382,7 @@
81028382 [%| ["unit branch pattern is not supported by partial inference" ~]]
81038383 =/ binder=(unit term) ?:(first-empty second-name first-name)
81048384 ?~ binder [%| ["unit branch pattern is not supported by partial inference" ~]]
8105− ?: |(=(u.binder %proj) ?=(^ (ienv-lookup u.binder env)) (lien globals.state |=(n=term =(n u.binder))))
8385+ ?: |((reserved-name u.binder) ?=(^ (ienv-lookup u.binder env)) (lien globals.state |=(n=term =(n u.binder))))
81068386 [%| ["pattern binder shadows a name" ~]]
81078387 =/ payload=(unit itype) (unit-union-payload typ)
81088388 ?~ payload [%| ["unit branch subject is not supported by partial inference" ~]]
@@ -8209,7 +8489,7 @@
82098489 ^- (unit ienv)
82108490 =. t ?:(?=(%face -.t) body.t t)
82118491 ?: ?=(%bind -.p)
8212− ?: |(=(name.p %proj) ?=(^ (ienv-lookup name.p env)) (lien globals |=(n=term =(n name.p)))) ~
8492+ ?: |((reserved-name name.p) ?=(^ (ienv-lookup name.p env)) (lien globals |=(n=term =(n name.p)))) ~
82138493 `[[name.p [t ~]] env]
82148494 ?: ?=(%cell -.p) (union-pattern-bind-items items.p t env globals)
82158495 `env
@@ -8735,7 +9015,9 @@
87359015 `subject
87369016::
87379017:: Infer changes only against a fully known record spine. Retain the
8738−:: target type; unknown spines and repeated edits remain unsupported.
9018+:: target type; unknown spines and overlapping edits remain unsupported.
9019+:: An edit's wing, as open.cart, reads through record fields only,
9020+:: outermost first, and its value fits the field it names.
87399021++ change-spine-known
87409022 |= [t=itype sub=isub]
87419023 ^- ?
@@ -8747,19 +9029,18 @@
87479029 $(t tal.t)
87489030::
87499031++ infer-change-edits
8750− |= [edits=(list edit) target=itype env=ienv state=istate seen=(list term)]
9032+ |= [edits=(list edit) target=itype env=ienv state=istate seen=(list (list term))]
87519033 ^- iresult
87529034 ?~ edits [%& target state]
87539035 =/ entry=edit i.edits
8754− ?: (lien seen |=(name=term =(name name.entry)))
9036+ =/ outer=(list term) (flop names.entry)
9037+ ?: (lien seen |=(prior=(list term) (wing-overlap prior outer)))
87559038 [%| ["repeated change fields are not supported by partial inference" ~]]
87569039 ?. (change-spine-known target sub.state)
87579040 [%| ["change target needs a known record in partial inference" ~]]
8758− =/ found=(list itype) (record-fields-named name.entry target sub.state)
8759− ?~ found
8760− [%| ["record has no field `{(trip name.entry)}`" ~[[at.entry "unknown field"]]]]
8761− ?^ t.found [%| ["change field is ambiguous in partial inference" ~]]
8762− =/ expected=itype i.found
9041+ =/ field=(each itype idiag) (change-wing-field entry target sub.state)
9042+ ?: ?=(%| -.field) [%| p.field]
9043+ =/ expected=itype p.field
87639044 =/ value=iresult (infer-call-context-arg val.entry expected env state at.entry)
87649045 ?: ?=(%| -.value) value
87659046 =/ fit=ifit (itype-fit typ.p.value expected sub.state.p.value next.state.p.value)
@@ -8768,7 +9049,67 @@
87689049 =/ decimal=(unit idiag) (decimal-misfit val.entry typ.p.value expected sub.state.p.value next.state.p.value)
87699050 ?^ decimal [%| u.decimal]
87709051 [%| ["change field and replacement do not unify" ~[[at.entry (site-type-note "expected replacement" expected sub.state.p.value)] [(span-of val.entry) (site-type-note "replacement" typ.p.value sub.state.p.value)]]]]
8771− $(edits t.edits, state state.p.value(sub sub.fit, next next.fit), seen [name.entry seen])
9052+ $(edits t.edits, state state.p.value(sub sub.fit, next next.fit), seen [outer seen])
9053+::
9054+:: +change-wing-field: the type of the field an edit's wing names in
9055+:: a known record target, read through record fields, outermost first
9056+::
9057+++ change-wing-field
9058+ |= [entry=edit target=itype sub=isub]
9059+ ^- (each itype idiag)
9060+ =/ outer=(list term) (flop names.entry)
9061+ =/ k=@ud (lent names.entry)
9062+ =/ typ=itype target
9063+ =| through=(unit [name=term at=span])
9064+ |- ^- (each itype idiag)
9065+ ?~ outer [%& typ]
9066+ =/ here=span (edit-name-at entry (dec k))
9067+ ?: &(?=(^ through) !(change-spine-known typ sub))
9068+ ?. (itype-not-record typ sub)
9069+ [%| ["change wing needs a known record in partial inference" ~]]
9070+ =/ label=tape "field `{(trip name.u.through)}`"
9071+ :- %|
9072+ :- "change wing `{(show-names names.entry)}` goes through `{(trip name.u.through)}`, which is not a record"
9073+ ~[[at.u.through (site-type-note label typ sub)]]
9074+ =/ found=(list itype) (record-fields-named i.outer typ sub)
9075+ ?~ found
9076+ [%| ["record has no field `{(trip i.outer)}`" ~[[here "unknown field"]]]]
9077+ ?^ t.found [%| ["change field is ambiguous in partial inference" ~]]
9078+ $(outer t.outer, k (dec k), typ i.found, through `[i.outer here])
9079+::
9080+:: +edit-name-at: where the kth name of an edit's wing is written,
9081+:: counting from 0: its names are joined by dots from the edit's start
9082+::
9083+++ edit-name-at
9084+ |= [e=edit k=@ud]
9085+ ^- span
9086+ =/ col=@ud col.beg.at.e
9087+ =/ ns=(list term) names.e
9088+ |- ^- span
9089+ ?~ ns at.e
9090+ =/ len=@ud (met 3 i.ns)
9091+ ?: =(0 k) [[line.beg.at.e col] [line.beg.at.e (add col len)]]
9092+ $(ns t.ns, k (dec k), col +((add col len)))
9093+::
9094+:: +itype-not-record: whether a type is surely no record: an atom, a
9095+:: loobean, a list or other collection, a gate, a union or a noun
9096+::
9097+++ itype-not-record
9098+ |= [t=itype sub=isub]
9099+ ^- ?
9100+ =. t (itype-walk t sub)
9101+ ?=(?(%atom %any-atom %flag %const %tag %collection %fn %union %noun %empty) -.t)
9102+::
9103+:: +wing-overlap: whether two edits' wings, outermost first, name the
9104+:: same field or one a field inside the other's
9105+::
9106+++ wing-overlap
9107+ |= [a=(list term) b=(list term)]
9108+ ^- ?
9109+ ?~ a &
9110+ ?~ b &
9111+ ?. =(i.a i.b) |
9112+ $(a t.a, b t.b)
87729113::
87739114:: Backtick constructs the canonical prelude unit, after checking its
87749115:: prepared template has the standard null and [~ u=A] cases.
@@ -9138,6 +9479,7 @@
91389479 [%& typ.instance state.instance]
91399480 =/ scheme=(unit ischeme) (ienv-lookup i.names.e env)
91409481 ?~ scheme
9482+ ?: =(i.names.e %unface) [%| (unface-value at.e)]
91419483 ?~ prelude.state [%| ["name is not available to partial inference" ~]]
91429484 =/ prelude-entry=(unit ischeme) (ienv-lookup i.names.e values.u.prelude.state)
91439485 ?~ prelude-entry [%| ["name is not available to partial inference" ~]]
@@ -9145,7 +9487,10 @@
91459487 [%& typ.inst state.inst]
91469488 =/ instance=[typ=itype state=istate] (instantiate-scheme u.scheme state)
91479489 [%& typ.instance state.instance]
9148− %group $(e inner.e)
9490+ %group
9491+ ?: &(?=(%wing -.inner.e) =(names.inner.e ~[%unface]) ?=(~ (ienv-lookup %unface env)))
9492+ [%| ["unface takes one argument, as (unface e)" ~[[at.e "unface call"]]]]
9493+ $(e inner.e)
91499494 %change
91509495 ?~ edits.e [%| ["a change takes at least one field" ~[[at.e "empty change"]]]]
91519496 =/ target=iresult $(e [%wing at.e target.e])
@@ -9289,6 +9634,7 @@
92899634 ?~ args.e [%| ["call has no argument" ~]]
92909635 ?: (explicit-proj-call e env state)
92919636 [%| ["proj needs an expected record type" ~]]
9637+ ?: (reserved-call %unface e env state) (infer-unface e env state)
92929638 (infer-call-with-head e env state (infer-fragment head.e env state))
92939639 * [%| ["expression is not supported by partial inference" ~]]
92949640 ==
@@ -9679,6 +10025,7 @@
967910025 ^- iresult
968010026 ?> ?=(%call -.e)
968110027 ?~ args.e [%| ["call has no argument" ~]]
10028+ ?: (reserved-call %unface e env state) (infer-unface e env state)
968210029 =/ head=iresult (infer-fragment head.e env state)
968310030 ?: ?=(%| -.head) head
968410031 =/ ht=itype (itype-walk typ.p.head sub.state.p.head)
@@ -9761,18 +10108,70 @@
976110108 `(infer-simple-items items.e env state)
976210109 `(width-infer-items items.e index.u.target env state context)
976310110::
9764−:: Experimental intrinsic recognition; real bindings retain normal calls.
10111+:: +reserved-call: whether e calls the reserved operation n
10112+::
10113+:: Experimental intrinsic recognition; real bindings retain normal calls.
10114+++ reserved-call
10115+ |= [n=term e=expr env=ienv state=istate]
10116+ ^- ?
10117+ ?. ?=(%call -.e) |
10118+ ?. ?=(%wing -.head.e) |
10119+ ?. =(names.head.e ~[n]) |
10120+ ?: ?=(^ (ienv-lookup n env)) |
10121+ ?: (lien globals.state |=(x=term =(x n))) |
10122+ ?~ prelude.state &
10123+ ?:(?=(^ (ienv-lookup n values.u.prelude.state)) | &)
976510124++ explicit-proj-call
976610125 |= [e=expr env=ienv state=istate]
976710126 ^- ?
976810127 ?. ?=(%call -.e) |
976910128 ?. ?=([* ~] args.e) |
9770− ?. ?=(%wing -.head.e) |
9771− ?. =(names.head.e ~[%proj]) |
9772− ?: ?=(^ (ienv-lookup %proj env)) |
9773− ?: (lien globals.state |=(n=term =(n %proj))) |
9774− ?~ prelude.state &
9775− ?:(?=(^ (ienv-lookup %proj values.u.prelude.state)) | &)
10129+ (reserved-call %proj e env state)
10130+::
10131+:: +infer-unface: (unface e), e's type with every face removed
10132+::
10133+:: A reserved operation handled by type, like proj. Any number of
10134+:: arguments is taken here so that a wrong count is an error. A type
10135+:: not yet known would wait, as wing access does; the partial checker
10136+:: has no such wait and reports it as unsupported, as it does field
10137+:: access on such a type.
10138+++ infer-unface
10139+ |= [e=expr env=ienv state=istate]
10140+ ^- iresult
10141+ ?> ?=(%call -.e)
10142+ ?. ?=([* ~] args.e)
10143+ [%| ["unface takes one argument, as (unface e)" ~[[at.e "unface call"]]]]
10144+ ?^ defer.state [%| ["deferred unface needs unsupported inference" ~]]
10145+ =/ value=iresult (infer-fragment i.args.e env state)
10146+ ?: ?=(%| -.value) value
10147+ =/ typ=itype (itype-walk typ.p.value sub.state.p.value)
10148+ ?: ?=(?(%var %fvar) -.typ)
10149+ [%| ["unface on a type not yet known is not supported by partial inference" ~]]
10150+ [%& (itype-unface typ sub.state.p.value) state.p.value]
10151+::
10152+:: +unface-value: the error for unface written where a value goes
10153+::
10154+++ unface-value
10155+ |= at=span
10156+ ^- idiag
10157+ ["unface is not a value; write |=(g (unface g))" ~[[at "unface used as a value"]]]
10158+::
10159+:: +unfaced-gate: the gate under a ++'s (unface |= …), or ~
10160+::
10161+:: Such a ++ is a gate for recursion: its own name has the unfaced
10162+:: type, and its body may call it.
10163+++ unfaced-gate
10164+ |= [e=expr env=ienv state=istate]
10165+ ^- (unit expr)
10166+ ?: ?=(%group -.e) $(e inner.e)
10167+ ?. (reserved-call %unface e env state) ~
10168+ ?> ?=(%call -.e)
10169+ ?. ?=([* ~] args.e) ~
10170+ =/ gate=expr i.args.e
10171+ |-
10172+ ?: ?=(%group -.gate) $(gate inner.gate)
10173+ ?. ?=(?(%gate %gate-wide) -.gate) ~
10174+ `gate
977610175++ infer-proj-source
977710176 |= [e=expr expected=itype env=ienv state=istate context=span]
977810177 ^- iresult
@@ -10179,7 +10578,7 @@
1017910578 ?~ pats [%& ~]
1018010579 ?. ?=(%bind -.i.pats) [%| 'branch pattern is not supported by partial inference']
1018110580 =/ name=term name.i.pats
10182− ?: |(=(name %proj) ?=(^ (ienv-lookup name env)) (lien globals |=(n=term =(n name))) (lien seen |=(n=term =(n name))))
10581+ ?: |((reserved-name name) ?=(^ (ienv-lookup name env)) (lien globals |=(n=term =(n name))) (lien seen |=(n=term =(n name))))
1018310582 [%| 'pattern shadows a name']
1018410583 =/ rest=(each (list term) @t) $(pats t.pats, seen [name seen])
1018510584 ?: ?=(%| -.rest) rest
@@ -10256,24 +10655,12 @@
1025610655 ^- tape
1025710656 =. t (itype-walk t sub)
1025810657 ?- -.t
10259− %var
10260− ?: (lth id.t 26) [(add 65 id.t) ~]
10261− "T{<id.t>}"
10262− %fvar
10263− ?: (lth id.t 26) [(add 65 id.t) ~]
10264− "T{<id.t>}"
10265− %avar
10266− ?: (lth id.t 26) [(add 65 id.t) ~]
10267− "T{<id.t>}"
10268− %rvar
10269− ?: (lth id.t 26) [(add 65 id.t) ~]
10270− "T{<id.t>}"
10271− %nvar
10272− ?: (lth id.t 26) [(add 65 id.t) ~]
10273− "T{<id.t>}"
10274− %rnvar
10275− ?: (lth id.t 26) [(add 65 id.t) ~]
10276− "T{<id.t>}"
10658+ %var (show-var id.t)
10659+ %fvar (show-var id.t)
10660+ %avar (show-var id.t)
10661+ %rvar (show-var id.t)
10662+ %nvar (show-var id.t)
10663+ %rnvar (show-var id.t)
1027710664 %atom "@{(trip aura.t)}"
1027810665 %any-atom "@"
1027910666 %flag "?"
@@ -10294,6 +10681,17 @@
1029410681 %cell "[{(show-itype-item hed.t sub)} {(show-itype-item tal.t sub)}]"
1029510682 ==
1029610683::
10684+:: +show-var: a type variable as printed: its name if it has one, else
10685+:: a letter for its number, A to Z, then T26, T27 and on
10686+::
10687+++ show-var
10688+ |= id=@ud
10689+ ^- tape
10690+ =/ name=@t (var-name id)
10691+ ?. =(0 name) (trip name)
10692+ ?: (lth id 26) [(add 65 id) ~]
10693+ "T{<id>}"
10694+::
1029710695++ show-itype-item
1029810696 |= [t=itype sub=isub]
1029910697 ^- tape
@@ -10352,7 +10750,7 @@
1035210750 ?: |(?=(%var -.normalized) ?=(%fvar -.normalized) ?=(%avar -.normalized) ?=(%rvar -.normalized) (itype-has-nvar normalized) (itype-has-tag normalized) (itype-has-union normalized)) label
1035310751 ?: (itype-has-hidden-recursive normalized) label
1035410752 =/ vars=(list @ud) (unique-type-vars (itype-vars normalized))
10355− =/ printable=itype (canonical-itype normalized vars)
10753+ =/ printable=itype (canonical-itype (cap-names normalized vars ~ sub))
1035610754 "{label} has type {(show-itype printable ~)}{(show-atom-constraint printable)}"
1035710755::
1035810756:: A capital in a written mold is generalized with its enclosing ++.
@@ -10393,6 +10791,116 @@
1039310791 ?: =(n u.ident) `i.caps
1039410792 $(caps t.caps)
1039510793::
10794+:: +cap-names: give each variable in vars the name it was written with
10795+::
10796+:: Unification joins variables, and the one an ID resolves to may not
10797+:: carry the name its definition wrote, as when a capital meets a
10798+:: called gate's variable or an atom variable. Each variable in vars
10799+:: takes the name of the first capital in caps that resolves to it;
10800+:: failing that, of the earliest made of the named variables that
10801+:: resolve to it, itself included (+joined-names). Only the name part
10802+:: of an ID changes, not its count, so IDs stay distinct.
10803+::
10804+++ cap-names
10805+ |= [typ=itype vars=(list @ud) caps=icaps sub=isub]
10806+ ^- [typ=itype vars=(list @ud)]
10807+ =/ written=icaps (flop caps)
10808+ =/ joined=(map @ud @ud) (joined-names sub)
10809+ =/ ren=(map @ud @ud) ~
10810+ =/ out=(list @ud) ~
10811+ |-
10812+ ?~ vars [?~(ren typ (itype-reid typ ren)) (flop out)]
10813+ =/ cap=(unit icap) (cap-with-id i.vars written sub)
10814+ =/ first=(unit @ud) (~(get by joined) i.vars)
10815+ =/ name=@t
10816+ ?^ cap name.u.cap
10817+ ?~ first (var-name i.vars)
10818+ ?: =(0 (var-name i.vars)) (var-name u.first)
10819+ ?: (lth (var-count u.first) (var-count i.vars)) (var-name u.first)
10820+ (var-name i.vars)
10821+ =/ to=@ud (named-var name i.vars)
10822+ ?: =(to i.vars) $(vars t.vars, out [i.vars out])
10823+ $(vars t.vars, out [to out], ren (~(put by ren) i.vars to))
10824+::
10825+:: +joined-names: for each variable that named ones resolve to, the
10826+:: earliest made of those, by count
10827+::
10828+:: One pass over sub keeps each ID's newest binding, as +itype-lookup
10829+:: would find it: the variable it is bound to, or ~ for another type.
10830+:: Each named ID then follows those bindings to the variable it
10831+:: resolves to, if any.
10832+::
10833+++ joined-names
10834+ |= sub=isub
10835+ ^- (map @ud @ud)
10836+ =/ edges=(map @ud (unit @ud))
10837+ %+ roll (flop sub)
10838+ |= [b=ibinding m=(map @ud (unit @ud))]
10839+ (~(put by m) id.b (var-of val.b))
10840+ =/ named=(list @ud)
10841+ (murn ~(tap by edges) |=([k=@ud *] ?:(=(0 (var-name k)) ~ `k)))
10842+ =/ fuel=@ud ~(wyt by edges)
10843+ =/ out=(map @ud @ud) ~
10844+ |-
10845+ ?~ named out
10846+ =/ root=(unit @ud) (follow-var i.named edges fuel)
10847+ ?~ root $(named t.named)
10848+ ?: =(u.root i.named) $(named t.named)
10849+ =/ best=(unit @ud) (~(get by out) u.root)
10850+ ?: &(?=(^ best) (lth (var-count u.best) (var-count i.named)))
10851+ $(named t.named)
10852+ $(named t.named, out (~(put by out) u.root i.named))
10853+::
10854+:: +follow-var: the variable that id resolves to through edges, or ~ if
10855+:: it resolves to another type; fuel bounds the steps
10856+::
10857+++ follow-var
10858+ |= [id=@ud edges=(map @ud (unit @ud)) fuel=@ud]
10859+ ^- (unit @ud)
10860+ |-
10861+ ?: =(0 fuel) ~
10862+ =/ edge=(unit (unit @ud)) (~(get by edges) id)
10863+ ?~ edge `id
10864+ ?~ u.edge ~
10865+ ?: =(u.u.edge id) `id
10866+ $(id u.u.edge, fuel (dec fuel))
10867+::
10868+:: +var-of: the ID of a type variable node, or ~ for another type
10869+::
10870+++ var-of
10871+ |= t=itype
10872+ ^- (unit @ud)
10873+ ?+ -.t ~
10874+ %var `id.t
10875+ %fvar `id.t
10876+ %avar `id.t
10877+ %rvar `id.t
10878+ %nvar `id.t
10879+ %rnvar `id.t
10880+ ==
10881+::
10882+:: +itype-reid: t with the variable IDs in ids replaced, each node
10883+:: keeping its kind
10884+::
10885+++ itype-reid
10886+ |= [t=itype ids=(map @ud @ud)]
10887+ ^- itype
10888+ ?- -.t
10889+ %var t(id (fall (~(get by ids) id.t) id.t))
10890+ %fvar t(id (fall (~(get by ids) id.t) id.t))
10891+ %avar t(id (fall (~(get by ids) id.t) id.t))
10892+ %rvar t(id (fall (~(get by ids) id.t) id.t))
10893+ %nvar t(id (fall (~(get by ids) id.t) id.t))
10894+ %rnvar t(id (fall (~(get by ids) id.t) id.t))
10895+ ?(%atom %any-atom %flag %noun %empty %tag %const %recursive %jrec) t
10896+ %union t(cases (turn cases.t |=(c=itype ^$(t c))), args (turn args.t |=(c=itype ^$(t c))))
10897+ %grec t(args (turn args.t |=(c=itype ^$(t c))))
10898+ %collection t(args (turn args.t |=(c=itype ^$(t c))))
10899+ %face t(body $(t body.t))
10900+ %fn t(sample $(t sample.t), product $(t product.t))
10901+ %cell t(hed $(t hed.t), tal $(t tal.t))
10902+ ==
10903+::
1039610904++ merged-capitals
1039710905 |= [caps=icaps sub=isub]
1039810906 ^- (unit [first=icap second=icap])
@@ -10612,6 +11120,9 @@
1061211120 ?^ defer.state [%| ["deferred recursive inference is unsupported" ~]]
1061311121 =. gate-defs.state ~
1061411122 ?. ?=(%value -.d) [%| ["recursive definition is not a gate" ~]]
11123+ :: A ++ whose body is (unface |= …) is a gate too, unfaced
11124+ =/ peeled=(unit expr) (unfaced-gate val.d env state)
11125+ =? val.d ?=(^ peeled) u.peeled
1061511126 ?. |(?=(%gate -.val.d) ?=(%gate-wide -.val.d))
1061611127 [%| ["recursive definition is not a gate" ~]]
1061711128 =/ result=(unit itype) (recursive-branch-seed d env state)
@@ -10635,6 +11146,7 @@
1063511146 =/ product=itype ?~(result [%var id] u.result)
1063611147 =/ st=istate state.p.sam(next +(id))
1063711148 =/ seed=itype [%fn typ.p.sam product]
11149+ =? seed ?=(^ peeled) (itype-unface seed sub.st)
1063811150 =/ seeded=ienv [[name.d [seed ~]] env.p.sam]
1063911151 =/ body=expr
1064011152 ?- -.gate
@@ -10646,7 +11158,9 @@
1064611158 ?: ?=(%| -.out) out
1064711159 =/ uni=(unit isub) (itype-unify product typ.p.out sub.state.p.out)
1064811160 ?~ uni [%| ["recursive gate constraint is not supported by partial inference" ~]]
10649− [%& [%fn typ.p.sam typ.p.out] state.p.out(sub u.uni)]
11161+ =/ typ=itype [%fn typ.p.sam typ.p.out]
11162+ =? typ ?=(^ peeled) (itype-unface typ u.uni)
11163+ [%& typ state.p.out(sub u.uni)]
1065011164::
1065111165++ dependency-root
1065211166 |= names=(list term)
@@ -10754,7 +11268,7 @@
1075411268:: Infer a cyclic component with one monomorphic seed per gate. All members
1075511269:: must succeed before any scheme is available; pending constraints and
1075611270:: unresolved branch joins remain partial.
10757−+$ igate-entry [name=term typ=itype body=expr env=ienv caps=icaps]
11271++$ igate-entry [name=term typ=itype body=expr env=ienv caps=icaps unfaced=?]
1075811272+$ igate-seeds (each [entries=(list igate-entry) state=istate] idiag)
1075911273++ seed-gate-group
1076011274 |= [ds=(list def) env=ienv state=istate]
@@ -10762,7 +11276,9 @@
1076211276 ?~ ds [%& [~ state]]
1076311277 =/ d=def i.ds
1076411278 ?. ?=(%value -.d) [%| ["recursive group contains a non-gate" ~]]
10765− =/ gate=expr val.d
11279+ :: A ++ whose body is (unface |= …) is a gate too, unfaced
11280+ =/ peeled=(unit expr) (unfaced-gate val.d env state)
11281+ =/ gate=expr ?~(peeled val.d u.peeled)
1076611282 ?. |(?=(%gate -.gate) ?=(%gate-wide -.gate))
1076711283 [%| ["recursive group contains a non-gate" ~]]
1076811284 =/ initial=istate (reserve-def-caps gate state)
@@ -10780,7 +11296,8 @@
1078011296 * !!
1078111297 ==
1078211298 =/ seed=itype [%fn typ.p.sam [%var next.state.p.sam]]
10783− =/ entry=igate-entry [name.d seed body env.p.sam caps.state.p.sam]
11299+ =? seed ?=(^ peeled) (itype-unface seed sub.state.p.sam)
11300+ =/ entry=igate-entry [name.d seed body env.p.sam caps.state.p.sam ?=(^ peeled)]
1078411301 =/ after=istate state.p.sam(next +(next.state.p.sam), caps caps.state)
1078511302 =/ rest=igate-seeds $(ds t.ds, state after)
1078611303 ?: ?=(%| -.rest) rest
@@ -10820,6 +11337,7 @@
1082011337 ?: (constrained-capitals caps.entry sub.state)
1082111338 [%| ["explicit capital constraints are not supported by partial inference" ~]]
1082211339 =/ typ=itype (itype-normalize typ.entry sub.state)
11340+ =? typ unfaced.entry (itype-unface typ ~)
1082311341 ?: (itype-has-nvar typ) [%| ["recursive group needs unsupported inference" ~]]
1082411342 ?: |((itype-has-tag typ) (itype-has-hidden-generic typ) (itype-has-hidden-recursive typ) (unsupported-atom-vars typ caps.entry binders.state sub.state))
1082511343 [%| ["recursive group needs unsupported inference" ~]]
@@ -10828,7 +11346,7 @@
1082811346 =. vars (skim vars |=(n=@ud !(lien free |=(f=@ud =(f n)))))
1082911347 =/ rest=(each ienv idiag) $(entries t.entries)
1083011348 ?: ?=(%| -.rest) rest
10831− [%& [[name.entry [typ vars]] p.rest]]
11349+ [%& [[name.entry (cap-names typ vars caps.entry sub.state)] p.rest]]
1083211350::
1083311351++ infer-gate-group
1083411352 |= [ds=(list def) env=ienv state=istate]
@@ -10873,7 +11391,7 @@
1087311391 `[entry u.rest]
1087411392::
1087511393
10876−+$ iresolved [env=ienv grouped=(list term) artifacts=(list iwidth-definition)]
11394++$ iresolved [env=ienv grouped=(list term) artifacts=(list iwidth-definition) failures=(list [name=term diag=idiag])]
1087711395+$ iadj (map term (list term))
1087811396+$ ivisited (map term ?)
1087911397+$ iwork (list [name=term done=?])
@@ -10969,7 +11487,7 @@
1096911487++ add-groups
1097011488 |= [ds=(list def) components=icomponents graph=iadj env=ienv grouped=(list term) artifacts=(list iwidth-definition) state=istate]
1097111489 ^- iresolved
10972− ?~ components [env grouped artifacts]
11490+ ?~ components [env grouped artifacts ~]
1097311491 =/ component=(list term) i.components
1097411492 ?. (graph-cycle component graph) $(components t.components)
1097511493 ?: (lien component |=(n=term ?=(^ (ienv-lookup n env)))) $(components t.components)
@@ -11010,11 +11528,13 @@
1101011528 =? artifacts ?=(^ u.finalized)
1101111529 [[name.d val.d typ sub.state.p.result (flop u.finalized)] artifacts]
1101211530 =? checked |(?=(%gate -.val.d) ?=(%gate-wide -.val.d)) (~(put by checked) name.d d)
11013− `[[[name.d [typ vars]] env] checked artifacts]
11531+ `[[[name.d (cap-names typ vars caps.state.p.result sub.state.p.result)] env] checked artifacts]
1101411532++ add-supported-defs-core
1101511533 |= [ds=(list def) checked=(map term def) heads=(unit igate-prelude-evidence) env=ienv molds=imolds globals=(list term) externals=iexternals surs=(list term) mark-externals=imark-externals marks=(list term) jimports=ijimports reserved-molds=(list term) at=path prelude=(unit ifile) artifacts=(list iwidth-definition) index=(unit [at=path source=@t prelude=ifile shapes=(map term shape)])]
11016− ^- [env=ienv artifacts=(list iwidth-definition)]
11017− ?~ ds [env artifacts]
11534+ ^- [env=ienv artifacts=(list iwidth-definition) failures=(list [name=term diag=idiag])]
11535+ =/ failures=(list [name=term diag=idiag]) ~
11536+ |-
11537+ ?~ ds [env artifacts (flop failures)]
1101811538 =/ d=def i.ds
1101911539 ?: ?=(%mold -.d) $(ds t.ds)
1102011540 ?. (unique-value-name name.d globals) $(ds t.ds)
@@ -11025,37 +11545,34 @@
1102511545 =. gate-defs.initial checked
1102611546 =. head-evidence.initial heads
1102711547 =. initial (reserve-def-caps val.d initial)
11028− =/ result=iresult (infer-fragment val.d env initial)
11548+ =/ plain=iresult (infer-fragment val.d env initial)
11549+ =/ result=iresult plain
1102911550 =? result ?=(%| -.result) (infer-recursive-gate d env initial)
11551+ ?: ?=(%| -.result)
11552+ =/ failure=idiag
11553+ ?: (definite-diag p.result) p.result
11554+ ?: ?=(%| -.plain) p.plain
11555+ p.result
11556+ =? failures (definite-diag failure) [[name.d failure] failures]
11557+ $(ds t.ds)
1103011558 =/ added=(unit iadded-definition)
1103111559 (add-supported-result d result initial env checked artifacts)
1103211560 ?~ added $(ds t.ds)
1103311561 $(ds t.ds, env env.u.added, checked checked.u.added, artifacts artifacts.u.added)
1103411562::
11035−:: Full checking discards unsupported definitions. On that failure path only,
11036−:: retry a bounded number of missing definitions to explain a pending tag
11037−:: from the same ordinary inference state instead of hiding it behind the
11038−:: generic completeness error. No successful definition takes this path.
11039−++ module-pending-tag
11040− |= [ds=(list def) env=ienv base=istate fuel=@ud]
11563+:: Retry one unresolved definition to explain a pending tag. The gate
11564+:: evidence is built from the whole module, not only this definition.
11565+++ module-pending-tag-one
11566+ |= [d=def env=ienv base=istate checked=(map term def) heads=(unit igate-prelude-evidence)]
1104111567 ^- (unit [at=span msg=tape])
11042− =/ checked=(map term def) (direct-checked-gates ds env)
11043− =/ heads=(unit igate-prelude-evidence) (direct-prelude-evidence ds prelude.base)
11044− |-
11045− ?~ ds ~
11046− ?: =(0 fuel) ~
11047− =/ d=def i.ds
11048− ?: ?=(%mold -.d) $(ds t.ds, fuel (dec fuel))
11049− ?^ (ienv-lookup name.d env) $(ds t.ds, fuel (dec fuel))
11568+ ?. ?=(%value -.d) ~
11569+ ?^ (ienv-lookup name.d env) ~
1105011570 =/ initial=istate base(gate-defs checked, head-evidence heads)
1105111571 =. initial (reserve-def-caps val.d initial)
1105211572 =/ result=iresult (infer-fragment val.d env initial)
1105311573 =? result ?=(%| -.result) (infer-recursive-gate d env initial)
11054− ?: ?=(%| -.result) $(ds t.ds, fuel (dec fuel))
11055− =/ pending=(unit [at=span msg=tape])
11056− (pending-tag-diagnostic tags.state.p.result sub.state.p.result)
11057− ?^ pending pending
11058− $(ds t.ds, fuel (dec fuel))
11574+ ?: ?=(%| -.result) ~
11575+ (pending-tag-diagnostic tags.state.p.result sub.state.p.result)
1105911576::
1106011577++ resolve-groups-core
1106111578 |= [ds=(list def) molds=imolds globals=(list term) externals=iexternals surs=(list term) mark-externals=imark-externals marks=(list term) jimports=ijimports reserved-molds=(list term) at=path prelude=(unit ifile) index=(unit [at=path source=@t prelude=ifile shapes=(map term shape)])]
@@ -11071,12 +11588,12 @@
1107111588 =/ heads=(unit igate-prelude-evidence) (direct-prelude-evidence ds prelude)
1107211589 =/ ordered=(list def) (dependency-order ds components)
1107311590 |-
11074− =/ next=[env=ienv artifacts=(list iwidth-definition)]
11591+ =/ next=[env=ienv artifacts=(list iwidth-definition) failures=(list [name=term diag=idiag])]
1107511592 (add-supported-defs-core ordered (direct-checked-gates ds env) heads env molds globals externals surs mark-externals marks jimports reserved-molds at prelude artifacts index)
1107611593 =/ initial=istate [0 ~ ~ ~ molds globals externals surs mark-externals marks jimports reserved-molds ~ ~ ~ | at top prelude ~ 256 ~ ~ ~ ~ ~ ~]
1107711594 =. grec-index.initial index
1107811595 =/ out=iresolved (add-groups ds components graph env.next grouped artifacts.next initial)
11079− ?: =(env env.out) out
11596+ ?: =(env env.out) out(failures failures.next)
1108011597 $(env env.out, grouped grouped.out, artifacts artifacts.out)
1108111598::
1108211599:: +dependency-order: the value definitions, dependencies first
@@ -11948,13 +12465,29 @@
1194812465 =/ first=(unit idiag) ?:(?=(%expr -.i.segs) (duplicate-expr p.i.segs) ~)
1194912466 ?^ first first
1195012467 $(segs t.segs)
12468+:: A change's items each set a field once: two that name the same field,
12469+:: or one a field inside the other's, as cart and open.cart, overlap.
1195112470++ duplicate-edits
1195212471 |= edits=(list edit)
1195312472 ^- (unit idiag)
12473+ =| seen=(list edit)
12474+ |- ^- (unit idiag)
1195412475 ?~ edits ~
11955− =/ first (duplicate-expr val.i.edits)
12476+ =/ e=edit i.edits
12477+ =/ prior=(list edit)
12478+ (skim seen |=(p=edit (wing-overlap (flop names.p) (flop names.e))))
12479+ ?^ prior
12480+ =/ same=? =(names.i.prior names.e)
12481+ =/ sites=(list [at=span note=tape])
12482+ :~ [at.i.prior "first field"]
12483+ [at.e ?:(same "repeated field" "overlapping field")]
12484+ ==
12485+ ?: same `["change field `{(show-names names.e)}` is repeated" sites]
12486+ =/ a=tape (show-names names.i.prior)
12487+ `["change fields `{a}` and `{(show-names names.e)}` overlap" sites]
12488+ =/ first (duplicate-expr val.e)
1195612489 ?^ first first
11957− $(edits t.edits)
12490+ $(edits t.edits, seen [e seen])
1195812491++ duplicate-arms
1195912492 |= arms=(list arm)
1196012493 ^- (unit idiag)
@@ -12027,59 +12560,142 @@
1202712560 ==
1202812561 [n $(imports t.imports)]
1202912562::
12030−++ reserved-proj-sample
12563+:: +reserved-name: whether n names a reserved operation
12564+::
12565+:: proj and unface are handled by the checker by type, not bound, so
12566+:: no module may define, import or bind either name, as a value or
12567+:: as a mold. A field, tag or path segment may still be spelled so.
12568+++ reserved-name
12569+ |= n=term
12570+ ^- ?
12571+ |(=(n %proj) =(n %unface))
12572+++ reserved-sample
1203112573 |= sam=sample
1203212574 ^- ?
1203312575 ?- -.sam
12034− %bind =(name.sam %proj)
12035− %face =(name.sam %proj)
12036− %pun =(name.sam %proj)
12037− %cell (lien items.sam reserved-proj-sample)
12576+ %bind (reserved-name name.sam)
12577+ %face (reserved-name name.sam)
12578+ %pun (reserved-name name.sam)
12579+ %cell (lien items.sam reserved-sample)
1203812580 * |
1203912581 ==
12040−++ reserved-proj-pattern
12582+++ reserved-pattern
1204112583 |= p=pattern
1204212584 ^- ?
1204312585 ?- -.p
12044− %bind =(name.p %proj)
12045− %cell (lien items.p reserved-proj-pattern)
12586+ %bind (reserved-name name.p)
12587+ %cell (lien items.p reserved-pattern)
1204612588 * |
1204712589 ==
12048−++ reserved-proj-def
12590+++ reserved-def
1204912591 |= d=def
1205012592 ^- ?
12051− ?: =(name.d %proj) &
12052− ?: ?=(%value -.d) (reserved-proj-expr val.d)
12593+ ?: (reserved-name name.d) &
12594+ ?: ?=(%value -.d) (reserved-expr val.d)
1205312595 |
12054−++ reserved-proj-expr
12596+++ reserved-expr
1205512597 |= e=expr
1205612598 ^- ?
1205712599 ?- -.e
12058− %str (lien pieces.e |=(p=piece ?:(?=(%expr -.p) (reserved-proj-expr p.p) |)))
12059− %qath (lien segs.e |=(p=qseg ?:(?=(%expr -.p) (reserved-proj-expr p.p) |)))
12060− %change (lien edits.e |=(p=edit (reserved-proj-expr val.p)))
12600+ %str (lien pieces.e |=(p=piece ?:(?=(%expr -.p) (reserved-expr p.p) |)))
12601+ %qath (lien segs.e |=(p=qseg ?:(?=(%expr -.p) (reserved-expr p.p) |)))
12602+ %change (lien edits.e |=(p=edit (reserved-expr val.p)))
1206112603 %pair $(e val.e)
1206212604 %unit $(e val.e)
1206312605 %group $(e inner.e)
12064− %list (lien items.e reserved-proj-expr)
12065− %tuple (lien items.e |=(i=item (reserved-proj-expr val.i)))
12066− ?(%gate %gate-wide) |((reserved-proj-sample sample.e) $(e body.e))
12606+ %list (lien items.e reserved-expr)
12607+ %tuple (lien items.e |=(i=item (reserved-expr val.i)))
12608+ ?(%gate %gate-wide) |((reserved-sample sample.e) $(e body.e))
1206712609 %cast $(e val.e)
12068− %call |($(e head.e) (lien args.e reserved-proj-expr))
12610+ %call |($(e head.e) (lien args.e reserved-expr))
1206912611 %trace |($(e val.e) $(e then.e))
12070− %branch |($(e subject.e) (lien arms.e |=(a=arm |((reserved-proj-pattern pat.a) (reserved-proj-expr val.a)))))
12071− %body |((lien defs.e reserved-proj-def) $(e final.e))
12612+ %branch |($(e subject.e) (lien arms.e |=(a=arm |((reserved-pattern pat.a) (reserved-expr val.a)))))
12613+ %body |((lien defs.e reserved-def) $(e final.e))
1207212614 * |
1207312615 ==
1207412616::
12075−++ module-has-reserved-proj
12617+++ module-has-reserved
1207612618 |= mod=module
1207712619 ^- ?
1207812620 =/ imported=(list term) (import-binding-names imports.mod)
1207912621 =/ vals=(list term) (global-value-names defs.mod)
1208012622 =/ molds=imolds (collect-simple-molds defs.mod)
1208112623 =/ mold-names=(list term) (turn molds |=(m=[name=term body=shape] name.m))
12082− |((lien (weld imported (weld vals mold-names)) |=(n=term =(n %proj))) (lien defs.mod reserved-proj-def))
12624+ |((lien (weld imported (weld vals mold-names)) reserved-name) (lien defs.mod reserved-def))
12625+::
12626+:: A scope collision retains source sites. Prelude declarations may be in
12627+:: another source, so their name and namespace are retained separately.
12628++$ iscope-diagnostic
12629+ [issue=idiag prelude=(unit [name=term kind=?(%value %mold %any)])]
12630+++ scope-import-diagnostic
12631+ |= [imports=(list import) prelude-values=(list term) prelude-molds=(list term) seen=written-fields]
12632+ ^- (each written-fields iscope-diagnostic)
12633+ ?~ imports [%& seen]
12634+ =/ imp=import i.imports
12635+ =/ n=term
12636+ ?- -.imp
12637+ %jibb face.imp
12638+ %sur name.imp
12639+ %mark mark.imp
12640+ ==
12641+ ?: (reserved-name n)
12642+ [%| [["`{(trip n)}` is reserved and cannot be bound" ~[[at.imp "reserved name"]]] ~]]
12643+ =/ earlier=(unit span) (~(get by seen) n)
12644+ ?^ earlier
12645+ [%| [["import `{(trip n)}` shadows an earlier import" ~[[u.earlier "earlier import"] [at.imp "conflicting import"]]] ~]]
12646+ ?: |((lien prelude-values |=(x=term =(n x))) (lien prelude-molds |=(x=term =(n x))))
12647+ [%| [["import `{(trip n)}` shadows a prelude name" ~[[at.imp "conflicting import"]]] `[n %any]]]
12648+ $(imports t.imports, seen (~(put by seen) n at.imp))
12649+++ scope-def-diagnostic
12650+ |= [defs=(list def) imports=written-fields prelude-values=(list term) prelude-molds=(list term) values=written-fields molds=written-fields]
12651+ ^- (unit iscope-diagnostic)
12652+ ?~ defs ~
12653+ =/ d=def i.defs
12654+ =/ n=term name.d
12655+ ?: (reserved-name n)
12656+ `[["`{(trip n)}` is reserved and cannot be bound" ~[[at.d "reserved name"]]] ~]
12657+ =/ imported=(unit span) (~(get by imports) n)
12658+ ?^ imported
12659+ `[["definition `{(trip n)}` shadows an import" ~[[u.imported "import"] [at.d "conflicting definition"]]] ~]
12660+ =/ seen=written-fields ?:(?=(%value -.d) values molds)
12661+ =/ earlier=(unit span) (~(get by seen) n)
12662+ ?^ earlier
12663+ `[["definition `{(trip n)}` shadows an earlier definition" ~[[u.earlier "earlier definition"] [at.d "conflicting definition"]]] ~]
12664+ =/ prelude-names=(list term) ?:(?=(%value -.d) prelude-values prelude-molds)
12665+ ?: (lien prelude-names |=(x=term =(n x)))
12666+ `[["definition `{(trip n)}` shadows a prelude name" ~[[at.d "conflicting definition"]]] `[n ?:(?=(%value -.d) %value %mold)]]
12667+ ?: ?=(%value -.d)
12668+ $(defs t.defs, values (~(put by values) n at.d))
12669+ $(defs t.defs, molds (~(put by molds) n at.d))
12670+++ module-scope-diagnostic
12671+ |= [mod=module prelude-values=(list term) prelude-molds=(list term)]
12672+ ^- (unit iscope-diagnostic)
12673+ =/ imports=(each written-fields iscope-diagnostic)
12674+ (scope-import-diagnostic imports.mod prelude-values prelude-molds ~)
12675+ ?: ?=(%| -.imports) `p.imports
12676+ (scope-def-diagnostic defs.mod p.imports prelude-values prelude-molds ~ ~)
12677+++ show-scope-diagnostic
12678+ |= [file=path src=@t diagnostic=iscope-diagnostic prelude=(unit ifile)]
12679+ ^- @t
12680+ =/ excerpts=(list @t)
12681+ %+ turn sites.issue.diagnostic
12682+ |= site=[at=span note=tape]
12683+ (show-error src [file line.beg.at.site col.beg.at.site note.site])
12684+ =/ previous=(list @t)
12685+ ?~ prelude.diagnostic ~
12686+ ?~ prelude ~
12687+ ?~ source.u.prelude ~
12688+ =/ parsed (parse at.u.prelude u.source.u.prelude)
12689+ ?: ?=(%| -.parsed) ~
12690+ =/ matching=(list def)
12691+ %+ skim defs.p.parsed
12692+ |= d=def
12693+ ?& =(name.d name.u.prelude.diagnostic)
12694+ |(=(%any kind.u.prelude.diagnostic) =(-.d kind.u.prelude.diagnostic))
12695+ ==
12696+ ?~ matching ~
12697+ ~[(show-error u.source.u.prelude [at.u.prelude line.beg.at.i.matching col.beg.at.i.matching "prelude declaration"])]
12698+ (of-wain:format [(crip msg.issue.diagnostic) (weld excerpts previous)])
1208312699::
1208412700++ module-scope-valid
1208512701 |= [mod=module prelude-values=(list term) prelude-molds=(list term)]
@@ -12088,7 +12704,7 @@
1208812704 =/ vals=(list term) (global-value-names defs.mod)
1208912705 =/ molds=imolds (collect-simple-molds defs.mod)
1209012706 =/ mold-names=(list term) (turn molds |=(m=[name=term body=shape] name.m))
12091− ?: (module-has-reserved-proj mod) |
12707+ ?: (module-has-reserved mod) |
1209212708 ?. %+ levy imported
1209312709 |= n=term
1209412710 &((unique-value-name n imported) !(lien vals |=(v=term =(n v))) !(lien mold-names |=(m=term =(n m))) !(lien prelude-values |=(v=term =(n v))) !(lien prelude-molds |=(m=term =(n m))))
@@ -12511,6 +13127,31 @@
1251113127 ?. (lien values |=(n=term =(n u.name))) $(ds t.ds)
1251213128 `[u.name at.s]
1251313129::
13130+:: Select the first available reason in dependency order, rather than
13131+:: preferring one class of diagnostic across the whole module. Only the
13132+:: first 64 definitions are retried for pending tags, as before.
13133+++ module-unresolved-diagnostic
13134+ |= [ds=(list def) env=ienv base=istate checked=(map term def) heads=(unit igate-prelude-evidence) failures=(list [name=term diag=idiag]) values=(list term) file=path src=@t fuel=@ud]
13135+ ^- (unit @t)
13136+ ?~ ds ~
13137+ =/ d=def i.ds
13138+ =/ remaining=@ud ?:(=(0 fuel) 0 (dec fuel))
13139+ ?: ?=(%mold -.d) $(ds t.ds, fuel remaining)
13140+ ?^ (ienv-lookup name.d env) $(ds t.ds, fuel remaining)
13141+ =/ found=(list [name=term diag=idiag])
13142+ (skim failures |=(failure=[name=term diag=idiag] =(name.failure name.d)))
13143+ ?^ found `(show-inference-diagnostic file src name.d diag.i.found)
13144+ =/ pending=(unit [at=span msg=tape])
13145+ ?: =(0 fuel) ~
13146+ (module-pending-tag-one d env base checked heads)
13147+ ?^ pending
13148+ `(show-error src [file line.beg.at.u.pending col.beg.at.u.pending msg.u.pending])
13149+ =/ shadow=(unit [name=term at=span]) (module-sample-shadow ~[d] env values)
13150+ ?^ shadow
13151+ =/ msg=tape "sample `{(trip name.u.shadow)}` shadows a name already in scope"
13152+ `(show-error src [file line.beg.at.u.shadow col.beg.at.u.shadow msg])
13153+ $(ds t.ds, fuel remaining)
13154+::
1251413155:: Cache only completed interfaces for this invocation. The source bundle,
1251513156:: imported Hoon types and prelude are fixed for the whole graph. Check the
1251613157:: active path and duplicate sources before consulting it, so a cache hit
@@ -12777,7 +13418,7 @@
1277713418 ^- ?
1277813419 =/ path-names=(list term) (turn paths |=(p=iapi-path name.p))
1277913420 =/ derived=(list term) (weld path-names poke-names)
12780− ?: (lien derived |=(n=term =(n %proj))) |
13421+ ?: (lien derived reserved-name) |
1278113422 =/ outer=(list term) (weld prelude-values (weld (global-value-names defs.mod) (api-import-faces imports.mod)))
1278213423 (levy derived |=(n=term &((unique-value-name n derived) !(lien outer |=(x=term =(n x))))))
1278313424::
@@ -12809,7 +13450,7 @@
1280913450 =/ clashes=(list term)
1281013451 %+ skip names
1281113452 |= n=term
12812− ?| =(n %proj)
13453+ ?| (reserved-name n)
1281313454 &((unique-value-name n names) !(lien outer |=(x=term =(n x))))
1281413455 ==
1281513456 ?~ clashes ~
@@ -13584,7 +14225,7 @@
1358414225 =/ action=term %poke
1358514226 =/ ordinary=(list def) ds
1358614227 =/ derived=(list term) ~[%state action]
13587− ?: (lien derived |=(n=term =(n %proj))) [%| ~]
14228+ ?: (lien derived reserved-name) [%| ~]
1358814229 =/ outer=(list term)
1358914230 (weld prelude-values (weld (global-value-names ordinary) (api-import-faces imports.mod)))
1359014231 =/ clashes=(list term)
@@ -13771,7 +14412,7 @@
1377114412 ?~ recovered ~
1377214413 ?. ?=(~ vars.u.recovered) ~
1377314414 ?. ?=(~ (itype-vars typ.u.recovered)) ~
13774− `[env.u.added grouped.resolution artifacts.u.added]
14415+ `[env.u.added grouped.resolution artifacts.u.added failures.resolution]
1377514416::
1377614417++ program-inferred-slot
1377714418 |= [typ=itype name=(unit term)]
@@ -13927,7 +14568,7 @@
1392714568 ?~ recovered ~
1392814569 ?. ?=(~ vars.u.recovered) ~
1392914570 ?. ?=(~ (itype-vars typ.u.recovered)) ~
13930− `[env.u.added grouped.resolution artifacts.u.added]
14571+ `[env.u.added grouped.resolution artifacts.u.added failures.resolution]
1393114572::
1393214573+$ iview-site [xs=expr mapper=term]
1393314574++ program-view-site
@@ -14254,7 +14895,7 @@
1425414895 ?~ recovered ~
1425514896 ?. ?=(~ vars.u.recovered) ~
1425614897 ?. ?=(~ (itype-vars typ.u.recovered)) ~
14257− `[env.u.added grouped.resolution artifacts.u.added]
14898+ `[env.u.added grouped.resolution artifacts.u.added failures.resolution]
1425814899::
1425914900:: Recover exactly one direct keyed each/turn row mapper, then its view.
1426014901:: The prelude's own each and turn schemes determine the mapper gate: the
@@ -14476,7 +15117,7 @@
1447615117 ?~ recovered ~
1447715118 ?. ?=(~ vars.u.recovered) ~
1447815119 ?. ?=(~ (itype-vars typ.u.recovered)) ~
14479− `[env.u.added grouped.resolution artifacts.u.added]
15120+ `[env.u.added grouped.resolution artifacts.u.added failures.resolution]
1448015121::
1448115122:: The model a direct program's initializer must produce. Update's written
1448215123:: two-item sample gives it when it can be read. Otherwise main's own program
@@ -14633,7 +15274,7 @@
1463315274 ?~ recovered ~
1463415275 ?. ?=(~ vars.u.recovered) ~
1463515276 ?. ?=(~ (itype-vars typ.u.recovered)) ~
14636− `[env.u.added grouped.resolution artifacts.u.added]
15277+ `[env.u.added grouped.resolution artifacts.u.added failures.resolution]
1463715278::
1463815279++ derived-poke-command-scheme
1463915280 |= [prelude=ifile action=itype]
@@ -14801,9 +15442,9 @@
1480115442 (direct-prelude-evidence ds prelude.initial)
1480215443 ?~ heads resolution
1480315444 =/ checked=(map term def) (direct-checked-gates ds env.resolution)
14804− =/ completed=[env=ienv artifacts=(list iwidth-definition)]
15445+ =/ completed=[env=ienv artifacts=(list iwidth-definition) failures=(list [name=term diag=idiag])]
1480515446 (add-supported-defs-core ~[main] checked heads env.resolution molds.initial globals.initial externals.initial surs.initial mark-externals.initial marks.initial jimports.initial reserved-molds.initial at.initial prelude.initial artifacts.resolution grec-index.initial)
14806− [env.completed grouped.resolution artifacts.completed]
15447+ [env.completed grouped.resolution artifacts.completed failures.resolution]
1480715448::
1480815449:: A static main may retain a generic element message in its ordinary
1480915450:: scheme. Instantiate that scheme, specialize it to canonical element !!,
@@ -15019,6 +15660,9 @@
1501915660 !(lien prelude-molds |=(m=term =(m n)))
1502015661 ==
1502115662 ==
15663+ =/ scope=(unit iscope-diagnostic)
15664+ (module-scope-diagnostic mod(defs ordinary, imports faces) prelude-values prelude-molds)
15665+ ?^ scope [%| [(show-scope-diagnostic at src u.scope prelude) ~]]
1502215666 [%| [(crip "module has conflicting names: {(spud at)}") ~]]
1502315667 ?~ prelude [%| [(crip "API module needs unsupported inference: {(spud at)}") ~]]
1502415668 =/ prepared=iprelude [u.prelude prelude-values prelude-molds]
@@ -15067,6 +15711,9 @@
1506715711 =/ ds=(list def) ?~(declared defs.mod defs.u.declared)
1506815712 =/ checking=module mod(defs ds)
1506915713 ?. (module-scope-valid checking prelude-values prelude-molds)
15714+ =/ scope=(unit iscope-diagnostic)
15715+ (module-scope-diagnostic checking prelude-values prelude-molds)
15716+ ?^ scope [%| [(show-scope-diagnostic at src u.scope prelude) ~]]
1507015717 [%| [(crip "module has conflicting names: {(spud at)}") ~]]
1507115718 =/ vals=(list term) (global-value-names ds)
1507215719 =/ js=jimports-detailed-result (resolve-jibb-imports-detailed imports.mod externals mark-externals modules active prelude-values prelude-molds cache prelude)
@@ -15142,15 +15789,14 @@
1514215789 ?~ store-parts ds
1514315790 (skim ds |=(d=def !&(?=(%value -.d) =(%main name.d))))
1514415791 ?. (module-values-complete required env)
15145− =/ pending=(unit [at=span msg=tape]) (module-pending-tag required env state 64)
15146− ?^ pending
15147− [%| [(show-error src [at line.beg.at.u.pending col.beg.at.u.pending msg.u.pending]) ~]]
15148− :: A shadowing sample is an error, so it comes before any named value.
15792+ =/ components=icomponents (graph-components required (global-value-names required))
15793+ =/ ordered=(list def) (dependency-order required components)
1514915794 =/ values=(list term) (weld prelude-values (weld (api-import-faces imports.mod) vals))
15150− =/ shadow=(unit [name=term at=span]) (module-sample-shadow required env values)
15151− ?^ shadow
15152− =/ msg=tape "sample `{(trip name.u.shadow)}` shadows a name already in scope"
15153− [%| [(show-error src [at line.beg.at.u.shadow col.beg.at.u.shadow msg]) ~]]
15795+ =/ checked=(map term def) (direct-checked-gates required env)
15796+ =/ heads=(unit igate-prelude-evidence) (direct-prelude-evidence required prelude.state)
15797+ =/ diagnostic=(unit @t)
15798+ (module-unresolved-diagnostic ordered env state checked heads failures.resolution values at src 64)
15799+ ?^ diagnostic [%| [u.diagnostic ~]]
1515415800 =/ missing=(unit term) (module-missing-value required env)
1515515801 =/ named=tape ?~(missing "" ": ++ {(trip u.missing)}")
1515615802 [%| [(crip "module definitions need unsupported inference: {(spud at)}{named}") ~]]
@@ -15354,8 +16000,8 @@
1535416000 ?: ?=(%| -.parsed) (show-error src p.parsed)
1535516001 =/ duplicate=(unit idiag) (duplicate-defs defs.p.parsed)
1535616002 ?^ duplicate (duplicate-fields-report file src u.duplicate)
15357− ?: (module-has-reserved-proj p.parsed)
15358− 'module has reserved proj name'
16003+ ?: (module-has-reserved p.parsed)
16004+ 'module has a reserved proj or unface name'
1535916005 =/ ds=(list def) defs.p.parsed
1536016006 =/ molds=imolds (collect-simple-molds ds)
1536116007 =/ globals=(list term) (weld prelude-values (weld (turn jimports |=(j=[face=term interface=ifile] face.j)) (global-value-names ds)))
@@ -15433,7 +16079,7 @@
1543316079 =. head-evidence.initial heads
1543416080 =. initial (reserve-def-caps val.d initial)
1543516081 =/ result=iresult
15436− ?: |(?=(%gate -.val.d) ?=(%gate-wide -.val.d))
16082+ ?: |(?=(%gate -.val.d) ?=(%gate-wide -.val.d) ?=(^ (unfaced-gate val.d env initial)))
1543716083 (infer-recursive-gate d env initial)
1543816084 (infer-fragment val.d env initial)
1543916085 ?: ?=(%| -.result)
@@ -15465,7 +16111,8 @@
1546516111 =/ vars=(list @ud) (unique-type-vars (itype-vars typ))
1546616112 ?~ (width-finalize projections.state.p.result sub.state.p.result vars)
1546716113 $(ds t.ds, lines [(crip "++ {(trip name.d)}: record projection elaboration needs unsupported inference") lines])
15468− =/ printable=itype (canonical-itype typ vars)
16114+ =/ named=[typ=itype vars=(list @ud)] (cap-names typ vars caps.state.p.result sub.state.p.result)
16115+ =/ printable=itype (canonical-itype named)
1546916116 =/ line=@t (crip "++ {(trip name.d)}: {(show-itype printable ~)}{(show-atom-constraint printable)}")
1547016117 $(ds t.ds, lines [line lines])
1547116118:: Experimental module-owned pending-constraint generalization only.
@@ -15562,7 +16209,7 @@
1556216209 =/ normalized=itype (itype-normalize typ sub.state)
1556316210 =/ vars=(list @ud) (unique-type-vars (itype-vars normalized))
1556416211 =/ quantified=(list @ud) (skim vars |=(n=@ud !(lien ids.u.tagged |=(b=@ud =(b n)))))
15565− `[[normalized quantified]]
16212+ `(cap-names normalized quantified caps.state sub.state)
1556616213::
1556716214+$ dgcommit [env=ienv state=istate]
1556816215:: A branch literal must not acquire a value face through replay.
@@ -15995,20 +16642,21 @@
1599516642 ?~ env `+(top)
1599616643 =/ sc=ischeme scheme.i.env
1599716644 ?: (itype-has-tag typ.sc) ~
15998− $(env t.env, top (itype-max-id typ.sc (max top (roll vars.sc max))))
16645+ $(env t.env, top (itype-max-id typ.sc (max top (roll (turn vars.sc var-count) max))))
1599916646::
16000−:: +itype-max-id: the largest variable or tag ID in t, or top
16647+:: +itype-max-id: the largest variable or tag ID in t, or top, without
16648+:: the variables' names (+named-var)
1600116649::
1600216650++ itype-max-id
1600316651 |= [t=itype top=@ud]
1600416652 ^- @ud
1600516653 ?- -.t
16006− %var (max top id.t)
16007− %fvar (max top id.t)
16008− %avar (max top id.t)
16009− %rvar (max top id.t)
16010− %nvar (max top id.t)
16011− %rnvar (max top id.t)
16654+ %var (max top (var-count id.t))
16655+ %fvar (max top (var-count id.t))
16656+ %avar (max top (var-count id.t))
16657+ %rvar (max top (var-count id.t))
16658+ %nvar (max top (var-count id.t))
16659+ %rnvar (max top (var-count id.t))
1601216660 %tag (max top id.t)
1601316661 ?(%atom %any-atom %flag %noun %empty %const %recursive %jrec) top
1601416662 %collection (itype-max-ids args.t top)
jibb-dev/lib/jibb/prelude.jibb+183−190
@@ -8,16 +8,16 @@
88
99++ head |= p=[A B]
1010 ?- p
11− [a b] a
11+ [a b] a
1212
1313++ tail |= p=[A B]
1414 ?- p
15− [a b] b
15+ [a b] b
1616
1717++ not |= b=?
1818 ?- b
19− %.y %.n
20− %.n %.y
19+ %.y %.n
20+ %.n %.y
2121
2222++ eq |= args=[A A] (eq-data.internal args)
2323
@@ -31,31 +31,29 @@
3131
3232++ fall |= args=[(unit A) A]
3333 ?- args
34− [maybe fallback]
35− ?- maybe
36− ~ fallback
37− [~ value] value
34+ [maybe fallback]
35+ ?- maybe
36+ ~ fallback
37+ [~ value] value
3838
3939++ need |= maybe=(unit A)
4040 ?- maybe
41− ~ !!
42− [~ value] value
41+ ~ !!
42+ [~ value] value
4343
4444++ weld |= args=[(list A) (list A)]
4545 ?- args
46− [xs ys]
47− ^- (list A)
48− ?- xs
49− ~ ys
50− [item rest] [item (weld rest ys)]
46+ [xs ys] ^- (list A)
47+ ?- xs
48+ ~ ys
49+ [item rest] [item (weld rest ys)]
5150
5251++ turn |= args=[(list A) $-(A B)]
5352 ?- args
54− [xs f]
55− ^- (list B)
56− ?- xs
57− ~ ~
58− [item rest] [(f item) (turn rest f)]
53+ [xs f] ^- (list B)
54+ ?- xs
55+ ~ ~
56+ [item rest] [(f item) (turn rest f)]
5957
6058+$ dime [p=@ta q=@]
6159
@@ -104,17 +102,16 @@
104102+$ like |$ [A] [p=hair q=(unit [p=A q=nail])]
105103
106104++ like |= [f=$-(A B) result=(like A)]
107− ++ mapped
108− ^- (unit [p=B q=nail])
109− ?- q.result
110− ~ ~
111− [~ value] `[p=(f p.value) q=q.value]
105+ ++ mapped ^- (unit [p=B q=nail])
106+ ?- q.result
107+ ~ ~
108+ [~ value] `[p=(f p.value) q=q.value]
112109 ^- (like B) [p=p.result q=mapped]
113110
114111++ wonk |= veq=(like A)
115112 ?- q.veq
116− ~ !!
117− [~ product] p.product
113+ ~ !!
114+ [~ product] p.product
118115
119116+$ lone |$ [A] [p=A]
120117
@@ -143,214 +140,209 @@
143140
144141++ snoc |= args=[(list A) A]
145142 ?- args
146− [xs item] (weld xs [item ~])
143+ [xs item] (weld xs [item ~])
147144
148145++ flop |= xs=(list A)
149146 ++ reverse-into |= args=[(list A) (list A)]
150147 ?- args
151− [rest acc]
152− ?- rest
153− ~ acc
154− [item more] (reverse-into more [item acc])
148+ [rest acc]
149+ ?- rest
150+ ~ acc
151+ [item more] (reverse-into more [item acc])
155152 (reverse-into xs ~)
156153
157−++ drop |= maybe=(unit A)
158− ^- (list A)
159− ?- maybe
160− ~ ~
161− [~ value] [value ~]
154+++ drop |= maybe=(unit A) ^- (list A)
155+ ?- maybe
156+ ~ ~
157+ [~ value] [value ~]
162158
163159++ bond |= fallback=$-(~ A)
164160 |= maybe=(unit A)
165161 ?- maybe
166− ~ (fallback ~)
167− [~ value] value
162+ ~ (fallback ~)
163+ [~ value] value
168164
169165++ bind |= args=[(unit A) $-(A B)]
170166 ?- args
171− [maybe f] ^- (unit B)
172− ?- maybe
173− ~ ~
174− [~ value] `(f value)
167+ [maybe f] ^- (unit B)
168+ ?- maybe
169+ ~ ~
170+ [~ value] `(f value)
175171
176172++ biff |= args=[(unit A) $-(A (unit B))]
177173 ?- args
178− [maybe f] ^- (unit B)
179− ?- maybe
180− ~ ~
181− [~ value] (f value)
174+ [maybe f] ^- (unit B)
175+ ?- maybe
176+ ~ ~
177+ [~ value] (f value)
182178
183179++ both |= args=[(unit A) (unit B)]
184180 ?- args
185− [first second] ^- (unit [A B])
186− ?- first
187− ~ ~
188− [~ a]
189− ?- second
190− ~ ~
191− [~ b] `[a b]
181+ [first second] ^- (unit [A B])
182+ ?- first
183+ ~ ~
184+ [~ a]
185+ ?- second
186+ ~ ~
187+ [~ b] `[a b]
192188
193189++ clap |= args=[(unit A) (unit A) $-([A A] A)]
194190 ?- args
195− [first second combine] ^- (unit A)
196− ?- first
197− ~ second
198− [~ a]
199− ?- second
200− ~ first
201− [~ b] `(combine a b)
191+ [first second combine] ^- (unit A)
192+ ?- first
193+ ~ second
194+ [~ a]
195+ ?- second
196+ ~ first
197+ [~ b] `(combine a b)
202198
203199++ hunt |= args=[$-([A A] ?) (unit A) (unit A)]
204200 ?- args
205− [choose first second] ^- (unit A)
206− ?- first
207− ~ second
208− [~ a]
209− ?- second
210− ~ first
211− [~ b]
212− ?- (choose a b)
213− %.y first
214− %.n second
201+ [choose first second] ^- (unit A)
202+ ?- first
203+ ~ second
204+ [~ a]
205+ ?- second
206+ ~ first
207+ [~ b]
208+ ?- (choose a b)
209+ %.y first
210+ %.n second
215211
216212++ mate |= args=[(unit A) (unit A)]
217213 ?- args
218− [first second] ^- (unit A)
219− ?- second
220− ~ first
221− [~ b]
222− ?- first
223− ~ second
224− [~ a]
225− ?- (eq a b)
226− %.y first
227− %.n !!
214+ [first second] ^- (unit A)
215+ ?- second
216+ ~ first
217+ [~ b]
218+ ?- first
219+ ~ second
220+ [~ a]
221+ ?- (eq a b)
222+ %.y first
223+ %.n !!
228224
229225++ clef |= args=[(unit A) (unit B) $-([A B] (unit C))]
230226 ?- args
231− [first second combine] ^- (unit C)
232− ?- first
233− ~ ~
234− [~ a]
235− ?- second
236− ~ ~
237− [~ b] (combine a b)
227+ [first second combine] ^- (unit C)
228+ ?- first
229+ ~ ~
230+ [~ a]
231+ ?- second
232+ ~ ~
233+ [~ b] (combine a b)
238234
239235++ skim |= args=[(list A) $-(A ?)]
240236 ?- args
241− [xs predicate] ^- (list A)
242− ?- xs
243− ~ ~
244− [item rest]
245− ?- (predicate item)
246− %.y [item (skim rest predicate)]
247− %.n (skim rest predicate)
237+ [xs predicate] ^- (list A)
238+ ?- xs
239+ ~ ~
240+ [item rest]
241+ ?- (predicate item)
242+ %.y [item (skim rest predicate)]
243+ %.n (skim rest predicate)
248244
249245++ skip |= args=[(list A) $-(A ?)]
250246 ?- args
251− [xs predicate] ^- (list A)
252− ?- xs
253− ~ ~
254− [item rest]
255− ?- (predicate item)
256− %.y (skip rest predicate)
257− %.n [item (skip rest predicate)]
258−
259−++ levy |= args=[(list A) $-(A ?)]
260− ^- ?
261− ?- args
262− [xs predicate]
263− ?- xs
264− ~ %.y
265− [item rest]
266− ?- (predicate item)
267− %.y (levy rest predicate)
268− %.n %.n
269−
270−++ lien |= args=[(list A) $-(A ?)]
271− ^- ?
272− ?- args
273− [xs predicate]
274− ?- xs
275− ~ %.n
276− [item rest]
277− ?- (predicate item)
278− %.y %.y
279− %.n (lien rest predicate)
247+ [xs predicate] ^- (list A)
248+ ?- xs
249+ ~ ~
250+ [item rest]
251+ ?- (predicate item)
252+ %.y (skip rest predicate)
253+ %.n [item (skip rest predicate)]
254+
255+++ levy |= args=[(list A) $-(A ?)] ^- ?
256+ ?- args
257+ [xs predicate]
258+ ?- xs
259+ ~ %.y
260+ [item rest]
261+ ?- (predicate item)
262+ %.y (levy rest predicate)
263+ %.n %.n
264+
265+++ lien |= args=[(list A) $-(A ?)] ^- ?
266+ ?- args
267+ [xs predicate]
268+ ?- xs
269+ ~ %.n
270+ [item rest]
271+ ?- (predicate item)
272+ %.y %.y
273+ %.n (lien rest predicate)
280274
281275++ roll |= args=[(list A) B $-([A B] B)]
282276 ?- args
283− [xs start combine]
284− ?- xs
285− ~ start
286− [item rest] (roll rest (combine item start) combine)
277+ [xs start combine]
278+ ?- xs
279+ ~ start
280+ [item rest] (roll rest (combine item start) combine)
287281
288282++ reel |= args=[(list A) B $-([A B] B)]
289283 ?- args
290− [xs start combine]
291− ?- xs
292− ~ start
293− [item rest] (combine item (reel rest start combine))
284+ [xs start combine]
285+ ?- xs
286+ ~ start
287+ [item rest] (combine item (reel rest start combine))
294288
295289++ flit |= predicate=$-(A ?)
296− |= value=A
297− ^- (unit A)
298− ?- (predicate value)
299− %.y `value
300− %.n ~
290+ |= value=A ^- (unit A)
291+ ?- (predicate value)
292+ %.y `value
293+ %.n ~
301294
302295++ murn |= args=[(list A) $-(A (unit B))]
303296 ?- args
304− [xs f] ^- (list B)
305− ?- xs
306− ~ ~
307− [item rest]
308− ?- (f item)
309− ~ (murn rest f)
310− [~ value] [value (murn rest f)]
297+ [xs f] ^- (list B)
298+ ?- xs
299+ ~ ~
300+ [item rest]
301+ ?- (f item)
302+ ~ (murn rest f)
303+ [~ value] [value (murn rest f)]
311304
312305++ join |= args=[A (list A)]
313306 ?- args
314− [separator xs] ^- (list A)
315− ?- xs
316− ~ ~
317− [item rest]
318− ?- rest
319− ~ [item ~]
320− [next more] [item [separator (join separator rest)]]
321−
322−++ snip |= xs=(list A)
323− ^- (list A)
307+ [separator xs] ^- (list A)
324308 ?- xs
325− ~ ~
326− [item rest]
327− ?- rest
328− ~ ~
329− [next more] [item (snip rest)]
309+ ~ ~
310+ [item rest]
311+ ?- rest
312+ ~ [item ~]
313+ [next more] [item [separator (join separator rest)]]
314+
315+++ snip |= xs=(list A) ^- (list A)
316+ ?- xs
317+ ~ ~
318+ [item rest]
319+ ?- rest
320+ ~ ~
321+ [next more] [item (snip rest)]
330322
331323++ rear |= xs=(list A)
332324 ?- xs
333− ~ !!
334− [item rest]
335− ?- rest
336− ~ item
337− [next more] (rear rest)
325+ ~ !!
326+ [item rest]
327+ ?- rest
328+ ~ item
329+ [next more] (rear rest)
338330
339331++ cork |= gates=[$-(A B) $-(B C)]
340332 ?- gates
341− [f g] |= x=A (g (f x))
333+ [f g] |= x=A (g (f x))
342334
343335++ corl |= gates=[$-(B C) $-(A B)]
344336 ?- gates
345− [f g] |= x=A (f (g x))
337+ [f g] |= x=A (f (g x))
346338
347339++ cury |= args=[$-([A B] C) A]
348340 ?- args
349− [f a] |= b=B (f a b)
341+ [f a] |= b=B (f a b)
350342
351343++ curr |= args=[$-([A B] C) B]
352344 ?- args
353− [f b] |= a=A (f a b)
345+ [f b] |= a=A (f a b)
354346
355347+$ cmd |$ [M]
356348 [%poke p=raw-poke reply=$-((unit @t) M)]
@@ -373,29 +365,27 @@
373365 [%url reply=$-(path M)]
374366
375367:: Count a finite list with the source-backed addition gate.
376−++ lent |= xs=(list A)
377− ^- @ud
378− ?- xs
379− ~ 0
380− [item rest] (add 1 (lent rest))
368+++ lent |= xs=(list A) ^- @ud
369+ ?- xs
370+ ~ 0
371+ [item rest] (add 1 (lent rest))
381372
382373++ lth |= args=[A A]
383374 ?- args
384− [x y] (gth y x)
375+ [x y] (gth y x)
385376
386377++ gte |= args=[A A]
387378 ?- args
388− [x y] (not (gth y x))
379+ [x y] (not (gth y x))
389380
390381++ lte |= args=[A A]
391382 ?- args
392− [x y] (not (gth x y))
383+ [x y] (not (gth x y))
393384
394−++ zing |= xss=(list (list A))
395− ^- (list A)
396− ?- xss
397− ~ ~
398− [xs rest] (weld xs (zing rest))
385+++ zing |= xss=(list (list A)) ^- (list A)
386+ ?- xss
387+ ~ ~
388+ [xs rest] (weld xs (zing rest))
399389
400390++ lead |= first=A |= second=B [first second]
401391++ late |= second=B |= first=A [first second]
@@ -528,20 +518,23 @@
528518 font=(unit qath)
529519 dark=(unit [tones=[normal=@t background=@t accent=@t danger=@t muted=@t]])
530520
531−+$ program |$ [D X M]
532− [init=$-(D X) update=$-([M X] [X (list (cmd M))]) view=$-(X (element M)) subs=$-(X (list (sub M)))]
521++$ program |$ [Data Model Msg]
522+ [ init=$-(Data Model)
523+ update=$-([Msg Model] [Model (list (cmd Msg))])
524+ view=$-(Model (element Msg))
525+ subs=$-(Model (list (sub Msg)))
533526
534−++ program |= [init=$-(D X) update=$-([M X] [X (list (cmd M))]) view=$-(X (element M)) subs=$-(X (list (sub M)))]
535− ^- (program D X M) [init update view subs]
527+++ program |= [init=$-(Data Model) update=$-([Msg Model] [Model (list (cmd Msg))]) view=$-(Model (element Msg)) subs=$-(Model (list (sub Msg)))]
528+ ^- (program Data Model Msg) [init update view subs]
536529
537−++ island |= [p=(program D X M) data=D]
530+++ island |= [p=(program Data Model Msg) data=Data]
538531 ^- (element !!) [%island [p data]]
539532
540−+$ page |$ [R D]
541− [load=$-(R (ask D)) view=$-(D (element !!))]
533++$ page |$ [Params Data]
534+ [load=$-(Params (ask Data)) view=$-(Data (element !!))]
542535
543−++ page |= [load=$-(R (ask D)) view=$-(D (element !!))]
544− ^- (page R D) [load view]
536+++ page |= [load=$-(Params (ask Data)) view=$-(Data (element !!))]
537+ ^- (page Params Data) [load view]
545538
546539+$ store |$ [S] [init=S update=*]
547540
my-app/ui/basket.jibb+5−5
@@ -16,11 +16,11 @@
1616
1717++ update |= [=msg m=model]
1818 ?- msg
19− [%noted t] [m(note=t) ~]
20− %add [m(note="") ~[(poke.cart [%add note.m] |=%acked)]]
21− %toggle [m ~[(poke.cart %toggle |=%acked)]]
22− [%got c] [m(cart=c) ~]
23− [%acked err] [m ~]
19+ [%noted t] [m(note=t) ~]
20+ %add [m(note="") ~[(poke.cart [%add note.m] |=%acked)]]
21+ %toggle [m ~[(poke.cart %toggle |=%acked)]]
22+ [%got c] [m(cart=c) ~]
23+ [%acked err] [m ~]
2424
2525++ subs |= m=model
2626 ~[[%watch (state.cart |=%got)]]
my-app/ui/stores/cart.jibb+2−2
@@ -8,5 +8,5 @@
88++ init ^- state [items=~ open=%.n]
99++ update |= [a=poke s=state]
1010 ?- a
11− [%add item] s(items=[item items.s])
12− %toggle s(open=(not open.s))
11+ [%add item] s(items=[item items.s])
12+ %toggle s(open=(not open.s))
my-app/ui/todo-list.jibb+8−8
@@ -15,14 +15,14 @@
1515
1616++ update |= [=msg m=model]
1717 ?- msg
18− [%typed t]
19− ?- (gth (lent (tuba (trip t))) 80)
20− %.y [m(draft=t error=`"Too long") ~]
21− %.n [m(draft=t error=~) ~]
22− %submit [m(draft="") ~[(poke.todo [%add draft.m] |=%acked)]]
23− [%toggled id] [m ~[(poke.todo [%toggle id] |=%acked)]]
24− [%got ts] [m(todos=ts) ~]
25− [%acked err] [m(error=err) ~]
18+ [%typed t]
19+ ?- (gth (lent (tuba (trip t))) 80)
20+ %.y [m(draft=t error=`"Too long") ~]
21+ %.n [m(draft=t error=~) ~]
22+ %submit [m(draft="") ~[(poke.todo [%add draft.m] |=%acked)]]
23+ [%toggled id] [m ~[(poke.todo [%toggle id] |=%acked)]]
24+ [%got ts] [m(todos=ts) ~]
25+ [%acked err] [m(error=err) ~]
2626
2727++ subs |= m=model
2828 ~[[%watch (todos.todo |=%got)]]
tests/golden/doc-core-02-update/about.txt+1−1
@@ -1,3 +1,3 @@
11source: Core language tab, section "Example", code block 2 of the tab
2−tests: the todo island's `update` on its own, as the Core language tab quotes it: a module of one `++`; a `?-` arm with its body on the deeper lines holding a nested `?-`; changes, units, lists and constructors in arm expressions. The same text as lines 16-25 of doc-overview-10-todo-list
2+tests: the todo island's `update` on its own, as the Core language tab quotes it: a module of one `++`; a `?-` with its arms at its own depth, one arm with its body on the deeper lines holding a nested `?-` whose arms are at that `?-`'s depth; changes, units, lists and constructors in arm expressions. The same text as lines 16-25 of doc-overview-10-todo-list
33expect: parses
tests/golden/doc-core-02-update/source.jibb+8−8
@@ -1,10 +1,10 @@
11++ update |= [=msg m=model]
22 ?- msg
3− [%typed t]
4− ?- (gth (lent (tuba (trip t))) 80)
5− %.y [m(draft=t error=`"Too long") ~]
6− %.n [m(draft=t error=~) ~]
7− %submit [m(draft="") ~[(poke.todo [%add draft.m] |=%acked)]]
8− [%toggled id] [m ~[(poke.todo [%toggle id] |=%acked)]]
9− [%got ts] [m(todos=ts) ~]
10− [%acked err] [m(error=err) ~]
3+ [%typed t]
4+ ?- (gth (lent (tuba (trip t))) 80)
5+ %.y [m(draft=t error=`"Too long") ~]
6+ %.n [m(draft=t error=~) ~]
7+ %submit [m(draft="") ~[(poke.todo [%add draft.m] |=%acked)]]
8+ [%toggled id] [m ~[(poke.todo [%toggle id] |=%acked)]]
9+ [%got ts] [m(todos=ts) ~]
10+ [%acked err] [m(error=err) ~]
tests/golden/doc-core-02-update/tokens.txt+120−122
@@ -11,126 +11,124 @@
11112:3 INDENT
12122:3 glyph ?-
13132:6 name msg
14−3:5 INDENT
15−3:5 glyph [
16−3:6 tight lit %typed
17−3:13 name t
18−3:14 tight glyph ]
19−4:7 INDENT
20−4:7 glyph ?-
21−4:10 glyph (
22−4:11 tight name gth
23−4:15 glyph (
24−4:16 tight name lent
25−4:21 glyph (
26−4:22 tight name tuba
27−4:27 glyph (
28−4:28 tight name trip
29−4:33 name t
14+3:3 NEWLINE
15+3:3 glyph [
16+3:4 tight lit %typed
17+3:11 name t
18+3:12 tight glyph ]
19+4:5 INDENT
20+4:5 glyph ?-
21+4:8 glyph (
22+4:9 tight name gth
23+4:13 glyph (
24+4:14 tight name lent
25+4:19 glyph (
26+4:20 tight name tuba
27+4:25 glyph (
28+4:26 tight name trip
29+4:31 name t
30+4:32 tight glyph )
31+4:33 tight glyph )
30324:34 tight glyph )
31−4:35 tight glyph )
32−4:36 tight glyph )
33−4:38 lit 80
34−4:40 tight glyph )
35−5:9 INDENT
36−5:9 lit %.y
37−5:14 glyph [
38−5:15 tight name m
39−5:16 tight glyph (
40−5:17 tight name draft
41−5:22 tight glyph =
42−5:23 tight name t
43−5:25 name error
44−5:30 tight glyph =
45−5:31 tight glyph `
46−5:32 tight str "Too long"
47−5:42 tight glyph )
48−5:44 lit ~
49−5:45 tight glyph ]
50−6:9 NEWLINE
51−6:9 lit %.n
52−6:14 glyph [
53−6:15 tight name m
54−6:16 tight glyph (
55−6:17 tight name draft
56−6:22 tight glyph =
57−6:23 tight name t
58−6:25 name error
59−6:30 tight glyph =
60−6:31 tight lit ~
61−6:32 tight glyph )
62−6:34 lit ~
63−6:35 tight glyph ]
64−7:5 DEDENT
65−7:5 DEDENT
66−7:5 NEWLINE
67−7:5 lit %submit
68−7:20 glyph [
69−7:21 tight name m
70−7:22 tight glyph (
71−7:23 tight name draft
72−7:28 tight glyph =
73−7:29 tight str ""
74−7:31 tight glyph )
75−7:33 glyph ~[
76−7:35 tight glyph (
77−7:36 tight wing poke.todo
78−7:46 glyph [
79−7:47 tight lit %add
80−7:52 wing draft.m
81−7:59 tight glyph ]
82−7:61 glyph |=
83−7:63 tight lit %acked
84−7:69 tight glyph )
85−7:70 tight glyph ]
86−7:71 tight glyph ]
87−8:5 NEWLINE
88−8:5 glyph [
89−8:6 tight lit %toggled
90−8:15 name id
91−8:17 tight glyph ]
92−8:20 glyph [
93−8:21 tight name m
94−8:23 glyph ~[
95−8:25 tight glyph (
96−8:26 tight wing poke.todo
97−8:36 glyph [
98−8:37 tight lit %toggle
99−8:45 name id
100−8:47 tight glyph ]
101−8:49 glyph |=
102−8:51 tight lit %acked
103−8:57 tight glyph )
104−8:58 tight glyph ]
105−8:59 tight glyph ]
106−9:5 NEWLINE
107−9:5 glyph [
108−9:6 tight lit %got
109−9:11 name ts
110−9:13 tight glyph ]
111−9:20 glyph [
112−9:21 tight name m
113−9:22 tight glyph (
114−9:23 tight name todos
115−9:28 tight glyph =
116−9:29 tight name ts
117−9:31 tight glyph )
118−9:33 lit ~
119−9:34 tight glyph ]
120−10:5 NEWLINE
121−10:5 glyph [
122−10:6 tight lit %acked
123−10:13 name err
124−10:16 tight glyph ]
125−10:20 glyph [
126−10:21 tight name m
127−10:22 tight glyph (
128−10:23 tight name error
129−10:28 tight glyph =
130−10:29 tight name err
131−10:32 tight glyph )
132−10:34 lit ~
133−10:35 tight glyph ]
134−10:36 DEDENT
135−10:36 DEDENT
136−10:36 NEWLINE
33+4:36 lit 80
34+4:38 tight glyph )
35+5:5 NEWLINE
36+5:5 lit %.y
37+5:10 glyph [
38+5:11 tight name m
39+5:12 tight glyph (
40+5:13 tight name draft
41+5:18 tight glyph =
42+5:19 tight name t
43+5:21 name error
44+5:26 tight glyph =
45+5:27 tight glyph `
46+5:28 tight str "Too long"
47+5:38 tight glyph )
48+5:40 lit ~
49+5:41 tight glyph ]
50+6:5 NEWLINE
51+6:5 lit %.n
52+6:10 glyph [
53+6:11 tight name m
54+6:12 tight glyph (
55+6:13 tight name draft
56+6:18 tight glyph =
57+6:19 tight name t
58+6:21 name error
59+6:26 tight glyph =
60+6:27 tight lit ~
61+6:28 tight glyph )
62+6:30 lit ~
63+6:31 tight glyph ]
64+7:3 DEDENT
65+7:3 NEWLINE
66+7:3 lit %submit
67+7:18 glyph [
68+7:19 tight name m
69+7:20 tight glyph (
70+7:21 tight name draft
71+7:26 tight glyph =
72+7:27 tight str ""
73+7:29 tight glyph )
74+7:31 glyph ~[
75+7:33 tight glyph (
76+7:34 tight wing poke.todo
77+7:44 glyph [
78+7:45 tight lit %add
79+7:50 wing draft.m
80+7:57 tight glyph ]
81+7:59 glyph |=
82+7:61 tight lit %acked
83+7:67 tight glyph )
84+7:68 tight glyph ]
85+7:69 tight glyph ]
86+8:3 NEWLINE
87+8:3 glyph [
88+8:4 tight lit %toggled
89+8:13 name id
90+8:15 tight glyph ]
91+8:18 glyph [
92+8:19 tight name m
93+8:21 glyph ~[
94+8:23 tight glyph (
95+8:24 tight wing poke.todo
96+8:34 glyph [
97+8:35 tight lit %toggle
98+8:43 name id
99+8:45 tight glyph ]
100+8:47 glyph |=
101+8:49 tight lit %acked
102+8:55 tight glyph )
103+8:56 tight glyph ]
104+8:57 tight glyph ]
105+9:3 NEWLINE
106+9:3 glyph [
107+9:4 tight lit %got
108+9:9 name ts
109+9:11 tight glyph ]
110+9:18 glyph [
111+9:19 tight name m
112+9:20 tight glyph (
113+9:21 tight name todos
114+9:26 tight glyph =
115+9:27 tight name ts
116+9:29 tight glyph )
117+9:31 lit ~
118+9:32 tight glyph ]
119+10:3 NEWLINE
120+10:3 glyph [
121+10:4 tight lit %acked
122+10:11 name err
123+10:14 tight glyph ]
124+10:18 glyph [
125+10:19 tight name m
126+10:20 tight glyph (
127+10:21 tight name error
128+10:26 tight glyph =
129+10:27 tight name err
130+10:30 tight glyph )
131+10:32 lit ~
132+10:33 tight glyph ]
133+10:34 DEDENT
134+10:34 NEWLINE
tests/golden/doc-core-02-update/tree.txt+64−64
@@ -7,67 +7,67 @@
77 (body 2:3
88 (branch 2:3
99 (wing 2:6 msg)
10− (arm 3:5
11− (cell 3:5 (lit 3:6 %typed) (bind 3:13 t))
12− (body 4:7
13− (branch 4:7
14− (group 4:10
15− (call 4:11
16− (wing 4:11 gth)
17− (group 4:15
18− (call 4:16
19− (wing 4:16 lent)
20− (group 4:21
21− (call 4:22
22− (wing 4:22 tuba)
23− (group 4:27
24− (call 4:28 (wing 4:28 trip) (wing 4:33 t)))))))
25− (lit 4:38 80)))
26− (arm 5:9
27− (lit 5:9 %.y)
28− (tuple 5:14
29− (change 5:15 m
30− (edit 5:17 draft (wing 5:23 t))
31− (edit 5:25 error
32− (unit 5:31 (str 5:32 "Too long"))))
33− (lit 5:44 ~)))
34− (arm 6:9
35− (lit 6:9 %.n)
36− (tuple 6:14
37− (change 6:15 m
38− (edit 6:17 draft (wing 6:23 t))
39− (edit 6:25 error (lit 6:31 ~)))
40− (lit 6:34 ~))))))
41− (arm 7:5
42− (lit 7:5 %submit)
43− (tuple 7:20
44− (change 7:21 m
45− (edit 7:23 draft (str 7:29 "")))
46− (list 7:33
47− (group 7:35
48− (call 7:36
49− (wing 7:36 poke.todo)
50− (tuple 7:46 (lit 7:47 %add) (wing 7:52 draft.m))
51− (ctor 7:61 %acked))))))
52− (arm 8:5
53− (cell 8:5 (lit 8:6 %toggled) (bind 8:15 id))
54− (tuple 8:20
55− (wing 8:21 m)
56− (list 8:23
57− (group 8:25
58− (call 8:26
59− (wing 8:26 poke.todo)
60− (tuple 8:36 (lit 8:37 %toggle) (wing 8:45 id))
61− (ctor 8:49 %acked))))))
62− (arm 9:5
63− (cell 9:5 (lit 9:6 %got) (bind 9:11 ts))
64− (tuple 9:20
65− (change 9:21 m
66− (edit 9:23 todos (wing 9:29 ts)))
67− (lit 9:33 ~)))
68− (arm 10:5
69− (cell 10:5 (lit 10:6 %acked) (bind 10:13 err))
70− (tuple 10:20
71− (change 10:21 m
72− (edit 10:23 error (wing 10:29 err)))
73− (lit 10:34 ~))))))))
10+ (arm 3:3
11+ (cell 3:3 (lit 3:4 %typed) (bind 3:11 t))
12+ (body 4:5
13+ (branch 4:5
14+ (group 4:8
15+ (call 4:9
16+ (wing 4:9 gth)
17+ (group 4:13
18+ (call 4:14
19+ (wing 4:14 lent)
20+ (group 4:19
21+ (call 4:20
22+ (wing 4:20 tuba)
23+ (group 4:25
24+ (call 4:26 (wing 4:26 trip) (wing 4:31 t)))))))
25+ (lit 4:36 80)))
26+ (arm 5:5
27+ (lit 5:5 %.y)
28+ (tuple 5:10
29+ (change 5:11 m
30+ (edit 5:13 draft (wing 5:19 t))
31+ (edit 5:21 error
32+ (unit 5:27 (str 5:28 "Too long"))))
33+ (lit 5:40 ~)))
34+ (arm 6:5
35+ (lit 6:5 %.n)
36+ (tuple 6:10
37+ (change 6:11 m
38+ (edit 6:13 draft (wing 6:19 t))
39+ (edit 6:21 error (lit 6:27 ~)))
40+ (lit 6:30 ~))))))
41+ (arm 7:3
42+ (lit 7:3 %submit)
43+ (tuple 7:18
44+ (change 7:19 m
45+ (edit 7:21 draft (str 7:27 "")))
46+ (list 7:31
47+ (group 7:33
48+ (call 7:34
49+ (wing 7:34 poke.todo)
50+ (tuple 7:44 (lit 7:45 %add) (wing 7:50 draft.m))
51+ (ctor 7:59 %acked))))))
52+ (arm 8:3
53+ (cell 8:3 (lit 8:4 %toggled) (bind 8:13 id))
54+ (tuple 8:18
55+ (wing 8:19 m)
56+ (list 8:21
57+ (group 8:23
58+ (call 8:24
59+ (wing 8:24 poke.todo)
60+ (tuple 8:34 (lit 8:35 %toggle) (wing 8:43 id))
61+ (ctor 8:47 %acked))))))
62+ (arm 9:3
63+ (cell 9:3 (lit 9:4 %got) (bind 9:9 ts))
64+ (tuple 9:18
65+ (change 9:19 m
66+ (edit 9:21 todos (wing 9:27 ts)))
67+ (lit 9:31 ~)))
68+ (arm 10:3
69+ (cell 10:3 (lit 10:4 %acked) (bind 10:11 err))
70+ (tuple 10:18
71+ (change 10:19 m
72+ (edit 10:21 error (wing 10:27 err)))
73+ (lit 10:32 ~))))))))
tests/golden/doc-grammar-02-buttons/types.txt+1−1
@@ -1,4 +1,4 @@
11partial inference; module not checked
22++ add-button: tag needs context in partial inference
3−++ labelled: $-([label=@t msg=A] (element A))
3+++ labelled: $-([label=@t msg=M] (element M))
44++ wide: (list attr)
tests/golden/doc-grammar-04-step/about.txt+1−1
@@ -1,4 +1,4 @@
11source: Grammar tab, section "Patterns", code block 4 of the tab
2−tests: a union `+$ step` with one case per deeper line: cells with tags at the head, in the middle and at the end, faced fields, and a bare term; a blank line between definitions; a `?-` whose arms are cell patterns mixing tags and binding names, and a bare term, with their expressions aligned by extra spaces; interpolated strings and a name as arm expressions
2+tests: a union `+$ step` with one case per deeper line: cells with tags at the head, in the middle and at the end, faced fields, and a bare term; a blank line between definitions; a `?-` whose arms, at its own depth, are cell patterns mixing tags and binding names, and a bare term, with their expressions aligned by extra spaces; interpolated strings and a name as arm expressions
33expect: parses
44expect-types: a partial inference report
tests/golden/doc-grammar-04-step/source.jibb+5−5
@@ -7,8 +7,8 @@
77
88++ describe |= s=step
99 ?- s
10− [%move %left n] "left {n}"
11− [%move %right n] "right {n}"
12− [t %draft] t
13− [t %sent sent-at] t
14− %stop "stop"
10+ [%move %left n] "left {n}"
11+ [%move %right n] "right {n}"
12+ [t %draft] t
13+ [t %sent sent-at] t
14+ %stop "stop"
tests/golden/doc-grammar-04-step/tokens.txt+36−37
@@ -46,40 +46,39 @@
46469:3 INDENT
47479:3 glyph ?-
48489:6 name s
49−10:5 INDENT
50−10:5 glyph [
51−10:6 tight lit %move
52−10:12 lit %left
53−10:18 name n
54−10:19 tight glyph ]
55−10:23 str-head "left "
56−10:30 tight name n
57−10:31 tight str-tail ""
58−11:5 NEWLINE
59−11:5 glyph [
60−11:6 tight lit %move
61−11:12 lit %right
62−11:19 name n
63−11:20 tight glyph ]
64−11:23 str-head "right "
65−11:31 tight name n
66−11:32 tight str-tail ""
67−12:5 NEWLINE
68−12:5 glyph [
69−12:6 tight name t
70−12:8 lit %draft
71−12:14 tight glyph ]
72−12:23 name t
73−13:5 NEWLINE
74−13:5 glyph [
75−13:6 tight name t
76−13:8 lit %sent
77−13:14 name sent-at
78−13:21 tight glyph ]
79−13:23 name t
80−14:5 NEWLINE
81−14:5 lit %stop
82−14:23 str "stop"
83−14:29 DEDENT
84−14:29 DEDENT
85−14:29 NEWLINE
49+10:3 NEWLINE
50+10:3 glyph [
51+10:4 tight lit %move
52+10:10 lit %left
53+10:16 name n
54+10:17 tight glyph ]
55+10:21 str-head "left "
56+10:28 tight name n
57+10:29 tight str-tail ""
58+11:3 NEWLINE
59+11:3 glyph [
60+11:4 tight lit %move
61+11:10 lit %right
62+11:17 name n
63+11:18 tight glyph ]
64+11:21 str-head "right "
65+11:29 tight name n
66+11:30 tight str-tail ""
67+12:3 NEWLINE
68+12:3 glyph [
69+12:4 tight name t
70+12:6 lit %draft
71+12:12 tight glyph ]
72+12:21 name t
73+13:3 NEWLINE
74+13:3 glyph [
75+13:4 tight name t
76+13:6 lit %sent
77+13:12 name sent-at
78+13:19 tight glyph ]
79+13:21 name t
80+14:3 NEWLINE
81+14:3 lit %stop
82+14:21 str "stop"
83+14:27 DEDENT
84+14:27 NEWLINE
tests/golden/doc-grammar-04-step/tree.txt+13−13
@@ -23,16 +23,16 @@
2323 (body 9:3
2424 (branch 9:3
2525 (wing 9:6 s)
26− (arm 10:5
27− (cell 10:5 (lit 10:6 %move) (lit 10:12 %left) (bind 10:18 n))
28− (str 10:23 "left " (wing 10:30 n)))
29− (arm 11:5
30− (cell 11:5 (lit 11:6 %move) (lit 11:12 %right) (bind 11:19 n))
31− (str 11:23 "right " (wing 11:31 n)))
32− (arm 12:5
33− (cell 12:5 (bind 12:6 t) (lit 12:8 %draft))
34− (wing 12:23 t))
35− (arm 13:5
36− (cell 13:5 (bind 13:6 t) (lit 13:8 %sent) (bind 13:14 sent-at))
37− (wing 13:23 t))
38− (arm 14:5 (lit 14:5 %stop) (str 14:23 "stop")))))))
26+ (arm 10:3
27+ (cell 10:3 (lit 10:4 %move) (lit 10:10 %left) (bind 10:16 n))
28+ (str 10:21 "left " (wing 10:28 n)))
29+ (arm 11:3
30+ (cell 11:3 (lit 11:4 %move) (lit 11:10 %right) (bind 11:17 n))
31+ (str 11:21 "right " (wing 11:29 n)))
32+ (arm 12:3
33+ (cell 12:3 (bind 12:4 t) (lit 12:6 %draft))
34+ (wing 12:21 t))
35+ (arm 13:3
36+ (cell 13:3 (bind 13:4 t) (lit 13:6 %sent) (bind 13:12 sent-at))
37+ (wing 13:21 t))
38+ (arm 14:3 (lit 14:3 %stop) (str 14:21 "stop")))))))
tests/golden/doc-grammar-06-cart-store/about.txt+1−1
@@ -1,4 +1,4 @@
11source: Grammar tab, section "Example: a store and an island", code block 6 of the tab (block 5 is the EBNF)
2−tests: a store module: a record mold with a mold application and the loobean mold `?`; a union with its cases below; a mold that is a name; a blank line; `++ main (store init update)`; a cast with its mold and expression on one line, `^- state [~ %.n]`; a gate with a cell sample; `?-` arms whose expressions are changes, `s(items=[item items.s])` and `s(open=(not open.s))`
2+tests: a store module: a record mold with a mold application and the loobean mold `?`; a union with its cases below; a mold that is a name; a blank line; `++ main (store init update)`; a cast with its mold and expression on one line, `^- state [~ %.n]`; a gate with a cell sample; `?-` arms at the `?-`'s depth whose expressions are changes, `s(items=[item items.s])` and `s(open=(not open.s))`
33expect: parses
44expect-types: a partial inference report; store kind and declaration scope remain unresolved
tests/golden/doc-grammar-06-cart-store/tokens.txt+27−28
@@ -60,31 +60,30 @@
606010:3 INDENT
616110:3 glyph ?-
626210:6 name a
63−11:5 INDENT
64−11:5 glyph [
65−11:6 tight lit %add
66−11:11 name item
67−11:15 tight glyph ]
68−11:18 name s
69−11:19 tight glyph (
70−11:20 tight name items
71−11:25 tight glyph =
72−11:26 tight glyph [
73−11:27 tight name item
74−11:32 wing items.s
75−11:39 tight glyph ]
76−11:40 tight glyph )
77−12:5 NEWLINE
78−12:5 lit %toggle
79−12:18 name s
80−12:19 tight glyph (
81−12:20 tight name open
82−12:24 tight glyph =
83−12:25 tight glyph (
84−12:26 tight name not
85−12:30 wing open.s
86−12:36 tight glyph )
87−12:37 tight glyph )
88−12:38 DEDENT
89−12:38 DEDENT
90−12:38 NEWLINE
63+11:3 NEWLINE
64+11:3 glyph [
65+11:4 tight lit %add
66+11:9 name item
67+11:13 tight glyph ]
68+11:16 name s
69+11:17 tight glyph (
70+11:18 tight name items
71+11:23 tight glyph =
72+11:24 tight glyph [
73+11:25 tight name item
74+11:30 wing items.s
75+11:37 tight glyph ]
76+11:38 tight glyph )
77+12:3 NEWLINE
78+12:3 lit %toggle
79+12:16 name s
80+12:17 tight glyph (
81+12:18 tight name open
82+12:22 tight glyph =
83+12:23 tight glyph (
84+12:24 tight name not
85+12:28 wing open.s
86+12:34 tight glyph )
87+12:35 tight glyph )
88+12:36 DEDENT
89+12:36 NEWLINE
tests/golden/doc-grammar-06-cart-store/tree.txt+11−11
@@ -27,14 +27,14 @@
2727 (body 10:3
2828 (branch 10:3
2929 (wing 10:6 a)
30− (arm 11:5
31− (cell 11:5 (lit 11:6 %add) (bind 11:11 item))
32− (change 11:18 s
33− (edit 11:20 items
34− (tuple 11:26 (wing 11:27 item) (wing 11:32 items.s)))))
35− (arm 12:5
36− (lit 12:5 %toggle)
37− (change 12:18 s
38− (edit 12:20 open
39− (group 12:25
40− (call 12:26 (wing 12:26 not) (wing 12:30 open.s)))))))))))
30+ (arm 11:3
31+ (cell 11:3 (lit 11:4 %add) (bind 11:9 item))
32+ (change 11:16 s
33+ (edit 11:18 items
34+ (tuple 11:24 (wing 11:25 item) (wing 11:30 items.s)))))
35+ (arm 12:3
36+ (lit 12:3 %toggle)
37+ (change 12:16 s
38+ (edit 12:18 open
39+ (group 12:23
40+ (call 12:24 (wing 12:24 not) (wing 12:28 open.s)))))))))))
tests/golden/doc-grammar-07-basket/about.txt+1−1
@@ -1,3 +1,3 @@
11source: Grammar tab, section "Example: a store and an island", code block 7 of the tab
2−tests: an island module: a `/=` import; blank lines between definitions; a record mold holding a wing mold `state.cart`; a union with term, faced-cell and mold-application cases; `|= ~` with its body below; a pun sample `=msg`; arms whose expressions are cells holding changes (`m(note="")`), lists of cells, parenthesised calls of wings and constructors (`|=%acked`); `(state.cart |=%got)`; a list left open at the end of its line whose items are a parenthesised call with an interpolated group `{(lent items.cart.m)}` and two unparenthesised calls, one ending in `|=%noted`
2+tests: an island module: a `/=` import; blank lines between definitions; a record mold holding a wing mold `state.cart`; a union with term, faced-cell and mold-application cases; `|= ~` with its body below; a pun sample `=msg`; arms at the `?-`'s depth whose expressions are cells holding changes (`m(note="")`), lists of cells, parenthesised calls of wings and constructors (`|=%acked`); `(state.cart |=%got)`; a list left open at the end of its line whose items are a parenthesised call with an interpolated group `{(lent items.cart.m)}` and two unparenthesised calls, one ending in `|=%noted`
33expect: parses
tests/golden/doc-grammar-07-basket/tokens.txt+71−72
@@ -95,78 +95,77 @@
959518:3 INDENT
969618:3 glyph ?-
979718:6 name msg
98−19:5 INDENT
99−19:5 glyph [
100−19:6 tight lit %noted
101−19:13 name t
102−19:14 tight glyph ]
103−19:20 glyph [
104−19:21 tight name m
105−19:22 tight glyph (
106−19:23 tight name note
107−19:27 tight glyph =
108−19:28 tight name t
109−19:29 tight glyph )
110−19:31 lit ~
111−19:32 tight glyph ]
112−20:5 NEWLINE
113−20:5 lit %add
114−20:20 glyph [
115−20:21 tight name m
116−20:22 tight glyph (
117−20:23 tight name note
118−20:27 tight glyph =
119−20:28 tight str ""
120−20:30 tight glyph )
121−20:32 glyph ~[
122−20:34 tight glyph (
123−20:35 tight wing poke.cart
124−20:45 glyph [
125−20:46 tight lit %add
126−20:51 wing note.m
127−20:57 tight glyph ]
128−20:59 glyph |=
129−20:61 tight lit %acked
130−20:67 tight glyph )
131−20:68 tight glyph ]
132−20:69 tight glyph ]
133−21:5 NEWLINE
134−21:5 lit %toggle
135−21:20 glyph [
136−21:21 tight name m
137−21:23 glyph ~[
138−21:25 tight glyph (
139−21:26 tight wing poke.cart
140−21:36 lit %toggle
141−21:44 glyph |=
142−21:46 tight lit %acked
143−21:52 tight glyph )
144−21:53 tight glyph ]
145−21:54 tight glyph ]
146−22:5 NEWLINE
147−22:5 glyph [
148−22:6 tight lit %got
149−22:11 name c
150−22:12 tight glyph ]
151−22:20 glyph [
152−22:21 tight name m
153−22:22 tight glyph (
154−22:23 tight name cart
155−22:27 tight glyph =
156−22:28 tight name c
157−22:29 tight glyph )
158−22:31 lit ~
159−22:32 tight glyph ]
160−23:5 NEWLINE
161−23:5 glyph [
162−23:6 tight lit %acked
163−23:13 name err
164−23:16 tight glyph ]
165−23:20 glyph [
166−23:21 tight name m
167−23:23 lit ~
168−23:24 tight glyph ]
169−25:1 DEDENT
98+19:3 NEWLINE
99+19:3 glyph [
100+19:4 tight lit %noted
101+19:11 name t
102+19:12 tight glyph ]
103+19:18 glyph [
104+19:19 tight name m
105+19:20 tight glyph (
106+19:21 tight name note
107+19:25 tight glyph =
108+19:26 tight name t
109+19:27 tight glyph )
110+19:29 lit ~
111+19:30 tight glyph ]
112+20:3 NEWLINE
113+20:3 lit %add
114+20:18 glyph [
115+20:19 tight name m
116+20:20 tight glyph (
117+20:21 tight name note
118+20:25 tight glyph =
119+20:26 tight str ""
120+20:28 tight glyph )
121+20:30 glyph ~[
122+20:32 tight glyph (
123+20:33 tight wing poke.cart
124+20:43 glyph [
125+20:44 tight lit %add
126+20:49 wing note.m
127+20:55 tight glyph ]
128+20:57 glyph |=
129+20:59 tight lit %acked
130+20:65 tight glyph )
131+20:66 tight glyph ]
132+20:67 tight glyph ]
133+21:3 NEWLINE
134+21:3 lit %toggle
135+21:18 glyph [
136+21:19 tight name m
137+21:21 glyph ~[
138+21:23 tight glyph (
139+21:24 tight wing poke.cart
140+21:34 lit %toggle
141+21:42 glyph |=
142+21:44 tight lit %acked
143+21:50 tight glyph )
144+21:51 tight glyph ]
145+21:52 tight glyph ]
146+22:3 NEWLINE
147+22:3 glyph [
148+22:4 tight lit %got
149+22:9 name c
150+22:10 tight glyph ]
151+22:18 glyph [
152+22:19 tight name m
153+22:20 tight glyph (
154+22:21 tight name cart
155+22:25 tight glyph =
156+22:26 tight name c
157+22:27 tight glyph )
158+22:29 lit ~
159+22:30 tight glyph ]
160+23:3 NEWLINE
161+23:3 glyph [
162+23:4 tight lit %acked
163+23:11 name err
164+23:14 tight glyph ]
165+23:18 glyph [
166+23:19 tight name m
167+23:21 lit ~
168+23:22 tight glyph ]
17016925:1 DEDENT
17117025:1 NEWLINE
17217125:1 glyph ++
tests/golden/doc-grammar-07-basket/tree.txt+33−33
@@ -39,39 +39,39 @@
3939 (body 18:3
4040 (branch 18:3
4141 (wing 18:6 msg)
42− (arm 19:5
43− (cell 19:5 (lit 19:6 %noted) (bind 19:13 t))
44− (tuple 19:20
45− (change 19:21 m
46− (edit 19:23 note (wing 19:28 t)))
47− (lit 19:31 ~)))
48− (arm 20:5
49− (lit 20:5 %add)
50− (tuple 20:20
51− (change 20:21 m
52− (edit 20:23 note (str 20:28 "")))
53− (list 20:32
54− (group 20:34
55− (call 20:35
56− (wing 20:35 poke.cart)
57− (tuple 20:45 (lit 20:46 %add) (wing 20:51 note.m))
58− (ctor 20:59 %acked))))))
59− (arm 21:5
60− (lit 21:5 %toggle)
61− (tuple 21:20
62− (wing 21:21 m)
63− (list 21:23
64− (group 21:25
65− (call 21:26 (wing 21:26 poke.cart) (lit 21:36 %toggle) (ctor 21:44 %acked))))))
66− (arm 22:5
67− (cell 22:5 (lit 22:6 %got) (bind 22:11 c))
68− (tuple 22:20
69− (change 22:21 m
70− (edit 22:23 cart (wing 22:28 c)))
71− (lit 22:31 ~)))
72− (arm 23:5
73− (cell 23:5 (lit 23:6 %acked) (bind 23:13 err))
74− (tuple 23:20 (wing 23:21 m) (lit 23:23 ~)))))))
42+ (arm 19:3
43+ (cell 19:3 (lit 19:4 %noted) (bind 19:11 t))
44+ (tuple 19:18
45+ (change 19:19 m
46+ (edit 19:21 note (wing 19:26 t)))
47+ (lit 19:29 ~)))
48+ (arm 20:3
49+ (lit 20:3 %add)
50+ (tuple 20:18
51+ (change 20:19 m
52+ (edit 20:21 note (str 20:26 "")))
53+ (list 20:30
54+ (group 20:32
55+ (call 20:33
56+ (wing 20:33 poke.cart)
57+ (tuple 20:43 (lit 20:44 %add) (wing 20:49 note.m))
58+ (ctor 20:57 %acked))))))
59+ (arm 21:3
60+ (lit 21:3 %toggle)
61+ (tuple 21:18
62+ (wing 21:19 m)
63+ (list 21:21
64+ (group 21:23
65+ (call 21:24 (wing 21:24 poke.cart) (lit 21:34 %toggle) (ctor 21:42 %acked))))))
66+ (arm 22:3
67+ (cell 22:3 (lit 22:4 %got) (bind 22:9 c))
68+ (tuple 22:18
69+ (change 22:19 m
70+ (edit 22:21 cart (wing 22:26 c)))
71+ (lit 22:29 ~)))
72+ (arm 23:3
73+ (cell 23:3 (lit 23:4 %acked) (bind 23:11 err))
74+ (tuple 23:18 (wing 23:19 m) (lit 23:21 ~)))))))
7575 (value 25:1 subs
7676 (gate 25:9
7777 (face 25:12 m (ref 25:14 model))
tests/golden/doc-overview-10-todo-list/about.txt+1−1
@@ -1,3 +1,3 @@
11source: the first tab ("Jibb — an Elm-architecture UI language for Urbit"), section "Worked examples", 3. Interactive: /ui/todo-list.jibb, code block 10 of the tab
2−tests: the interactive island: a record mold with mold applications; a five-case union; a gate with its body below; a `?-` arm whose body is on the deeper lines, a nested `?-` on a deeply nested call with loobean arms; changes holding a unit of a string (`` error=`"Too long" ``) and a null; arms aligned with extra spaces; lists of cells holding constructors; a list left open inside another open list (`row ~[gap+%s1] ~[`); a pair whose operand is a cell; calls ending in `|=%typed`; a gate whose body is a cell holding a call with a cell argument
2+tests: the interactive island: a record mold with mold applications; a five-case union; a gate with its body below; a `?-` with its arms at its own depth, one arm's body on the deeper lines, a nested `?-` on a deeply nested call with loobean arms at its depth; changes holding a unit of a string (`` error=`"Too long" ``) and a null; arms aligned with extra spaces; lists of cells holding constructors; a list left open inside another open list (`row ~[gap+%s1] ~[`); a pair whose operand is a cell; calls ending in `|=%typed`; a gate whose body is a cell holding a call with a cell argument
33expect: parses
tests/golden/doc-overview-10-todo-list/tokens.txt+118−120
@@ -113,127 +113,125 @@
11311317:3 INDENT
11411417:3 glyph ?-
11511517:6 name msg
116−18:5 INDENT
117−18:5 glyph [
118−18:6 tight lit %typed
119−18:13 name t
120−18:14 tight glyph ]
121−19:7 INDENT
122−19:7 glyph ?-
123−19:10 glyph (
124−19:11 tight name gth
125−19:15 glyph (
126−19:16 tight name lent
127−19:21 glyph (
128−19:22 tight name tuba
129−19:27 glyph (
130−19:28 tight name trip
131−19:33 name t
116+18:3 NEWLINE
117+18:3 glyph [
118+18:4 tight lit %typed
119+18:11 name t
120+18:12 tight glyph ]
121+19:5 INDENT
122+19:5 glyph ?-
123+19:8 glyph (
124+19:9 tight name gth
125+19:13 glyph (
126+19:14 tight name lent
127+19:19 glyph (
128+19:20 tight name tuba
129+19:25 glyph (
130+19:26 tight name trip
131+19:31 name t
132+19:32 tight glyph )
133+19:33 tight glyph )
13213419:34 tight glyph )
133−19:35 tight glyph )
134−19:36 tight glyph )
135−19:38 lit 80
136−19:40 tight glyph )
137−20:9 INDENT
138−20:9 lit %.y
139−20:14 glyph [
140−20:15 tight name m
141−20:16 tight glyph (
142−20:17 tight name draft
143−20:22 tight glyph =
144−20:23 tight name t
145−20:25 name error
146−20:30 tight glyph =
147−20:31 tight glyph `
148−20:32 tight str "Too long"
149−20:42 tight glyph )
150−20:44 lit ~
151−20:45 tight glyph ]
152−21:9 NEWLINE
153−21:9 lit %.n
154−21:14 glyph [
155−21:15 tight name m
156−21:16 tight glyph (
157−21:17 tight name draft
158−21:22 tight glyph =
159−21:23 tight name t
160−21:25 name error
161−21:30 tight glyph =
162−21:31 tight lit ~
163−21:32 tight glyph )
164−21:34 lit ~
165−21:35 tight glyph ]
166−22:5 DEDENT
167−22:5 DEDENT
168−22:5 NEWLINE
169−22:5 lit %submit
170−22:20 glyph [
171−22:21 tight name m
172−22:22 tight glyph (
173−22:23 tight name draft
174−22:28 tight glyph =
175−22:29 tight str ""
176−22:31 tight glyph )
177−22:33 glyph ~[
178−22:35 tight glyph (
179−22:36 tight wing poke.todo
180−22:46 glyph [
181−22:47 tight lit %add
182−22:52 wing draft.m
183−22:59 tight glyph ]
184−22:61 glyph |=
185−22:63 tight lit %acked
186−22:69 tight glyph )
187−22:70 tight glyph ]
188−22:71 tight glyph ]
189−23:5 NEWLINE
190−23:5 glyph [
191−23:6 tight lit %toggled
192−23:15 name id
193−23:17 tight glyph ]
194−23:20 glyph [
195−23:21 tight name m
196−23:23 glyph ~[
197−23:25 tight glyph (
198−23:26 tight wing poke.todo
199−23:36 glyph [
200−23:37 tight lit %toggle
201−23:45 name id
202−23:47 tight glyph ]
203−23:49 glyph |=
204−23:51 tight lit %acked
205−23:57 tight glyph )
206−23:58 tight glyph ]
207−23:59 tight glyph ]
208−24:5 NEWLINE
209−24:5 glyph [
210−24:6 tight lit %got
211−24:11 name ts
212−24:13 tight glyph ]
213−24:20 glyph [
214−24:21 tight name m
215−24:22 tight glyph (
216−24:23 tight name todos
217−24:28 tight glyph =
218−24:29 tight name ts
219−24:31 tight glyph )
220−24:33 lit ~
221−24:34 tight glyph ]
222−25:5 NEWLINE
223−25:5 glyph [
224−25:6 tight lit %acked
225−25:13 name err
226−25:16 tight glyph ]
227−25:20 glyph [
228−25:21 tight name m
229−25:22 tight glyph (
230−25:23 tight name error
231−25:28 tight glyph =
232−25:29 tight name err
233−25:32 tight glyph )
234−25:34 lit ~
235−25:35 tight glyph ]
236−27:1 DEDENT
135+19:36 lit 80
136+19:38 tight glyph )
137+20:5 NEWLINE
138+20:5 lit %.y
139+20:10 glyph [
140+20:11 tight name m
141+20:12 tight glyph (
142+20:13 tight name draft
143+20:18 tight glyph =
144+20:19 tight name t
145+20:21 name error
146+20:26 tight glyph =
147+20:27 tight glyph `
148+20:28 tight str "Too long"
149+20:38 tight glyph )
150+20:40 lit ~
151+20:41 tight glyph ]
152+21:5 NEWLINE
153+21:5 lit %.n
154+21:10 glyph [
155+21:11 tight name m
156+21:12 tight glyph (
157+21:13 tight name draft
158+21:18 tight glyph =
159+21:19 tight name t
160+21:21 name error
161+21:26 tight glyph =
162+21:27 tight lit ~
163+21:28 tight glyph )
164+21:30 lit ~
165+21:31 tight glyph ]
166+22:3 DEDENT
167+22:3 NEWLINE
168+22:3 lit %submit
169+22:18 glyph [
170+22:19 tight name m
171+22:20 tight glyph (
172+22:21 tight name draft
173+22:26 tight glyph =
174+22:27 tight str ""
175+22:29 tight glyph )
176+22:31 glyph ~[
177+22:33 tight glyph (
178+22:34 tight wing poke.todo
179+22:44 glyph [
180+22:45 tight lit %add
181+22:50 wing draft.m
182+22:57 tight glyph ]
183+22:59 glyph |=
184+22:61 tight lit %acked
185+22:67 tight glyph )
186+22:68 tight glyph ]
187+22:69 tight glyph ]
188+23:3 NEWLINE
189+23:3 glyph [
190+23:4 tight lit %toggled
191+23:13 name id
192+23:15 tight glyph ]
193+23:18 glyph [
194+23:19 tight name m
195+23:21 glyph ~[
196+23:23 tight glyph (
197+23:24 tight wing poke.todo
198+23:34 glyph [
199+23:35 tight lit %toggle
200+23:43 name id
201+23:45 tight glyph ]
202+23:47 glyph |=
203+23:49 tight lit %acked
204+23:55 tight glyph )
205+23:56 tight glyph ]
206+23:57 tight glyph ]
207+24:3 NEWLINE
208+24:3 glyph [
209+24:4 tight lit %got
210+24:9 name ts
211+24:11 tight glyph ]
212+24:18 glyph [
213+24:19 tight name m
214+24:20 tight glyph (
215+24:21 tight name todos
216+24:26 tight glyph =
217+24:27 tight name ts
218+24:29 tight glyph )
219+24:31 lit ~
220+24:32 tight glyph ]
221+25:3 NEWLINE
222+25:3 glyph [
223+25:4 tight lit %acked
224+25:11 name err
225+25:14 tight glyph ]
226+25:18 glyph [
227+25:19 tight name m
228+25:20 tight glyph (
229+25:21 tight name error
230+25:26 tight glyph =
231+25:27 tight name err
232+25:30 tight glyph )
233+25:32 lit ~
234+25:33 tight glyph ]
23723527:1 DEDENT
23823627:1 NEWLINE
23923727:1 glyph ++
tests/golden/doc-overview-10-todo-list/tree.txt+64−64
@@ -44,70 +44,70 @@
4444 (body 17:3
4545 (branch 17:3
4646 (wing 17:6 msg)
47− (arm 18:5
48− (cell 18:5 (lit 18:6 %typed) (bind 18:13 t))
49− (body 19:7
50− (branch 19:7
51− (group 19:10
52− (call 19:11
53− (wing 19:11 gth)
54− (group 19:15
55− (call 19:16
56− (wing 19:16 lent)
57− (group 19:21
58− (call 19:22
59− (wing 19:22 tuba)
60− (group 19:27
61− (call 19:28 (wing 19:28 trip) (wing 19:33 t)))))))
62− (lit 19:38 80)))
63− (arm 20:9
64− (lit 20:9 %.y)
65− (tuple 20:14
66− (change 20:15 m
67− (edit 20:17 draft (wing 20:23 t))
68− (edit 20:25 error
69− (unit 20:31 (str 20:32 "Too long"))))
70− (lit 20:44 ~)))
71− (arm 21:9
72− (lit 21:9 %.n)
73− (tuple 21:14
74− (change 21:15 m
75− (edit 21:17 draft (wing 21:23 t))
76− (edit 21:25 error (lit 21:31 ~)))
77− (lit 21:34 ~))))))
78− (arm 22:5
79− (lit 22:5 %submit)
80− (tuple 22:20
81− (change 22:21 m
82− (edit 22:23 draft (str 22:29 "")))
83− (list 22:33
84− (group 22:35
85− (call 22:36
86− (wing 22:36 poke.todo)
87− (tuple 22:46 (lit 22:47 %add) (wing 22:52 draft.m))
88− (ctor 22:61 %acked))))))
89− (arm 23:5
90− (cell 23:5 (lit 23:6 %toggled) (bind 23:15 id))
91− (tuple 23:20
92− (wing 23:21 m)
93− (list 23:23
94− (group 23:25
95− (call 23:26
96− (wing 23:26 poke.todo)
97− (tuple 23:36 (lit 23:37 %toggle) (wing 23:45 id))
98− (ctor 23:49 %acked))))))
99− (arm 24:5
100− (cell 24:5 (lit 24:6 %got) (bind 24:11 ts))
101− (tuple 24:20
102− (change 24:21 m
103− (edit 24:23 todos (wing 24:29 ts)))
104− (lit 24:33 ~)))
105− (arm 25:5
106− (cell 25:5 (lit 25:6 %acked) (bind 25:13 err))
107− (tuple 25:20
108− (change 25:21 m
109− (edit 25:23 error (wing 25:29 err)))
110− (lit 25:34 ~)))))))
47+ (arm 18:3
48+ (cell 18:3 (lit 18:4 %typed) (bind 18:11 t))
49+ (body 19:5
50+ (branch 19:5
51+ (group 19:8
52+ (call 19:9
53+ (wing 19:9 gth)
54+ (group 19:13
55+ (call 19:14
56+ (wing 19:14 lent)
57+ (group 19:19
58+ (call 19:20
59+ (wing 19:20 tuba)
60+ (group 19:25
61+ (call 19:26 (wing 19:26 trip) (wing 19:31 t)))))))
62+ (lit 19:36 80)))
63+ (arm 20:5
64+ (lit 20:5 %.y)
65+ (tuple 20:10
66+ (change 20:11 m
67+ (edit 20:13 draft (wing 20:19 t))
68+ (edit 20:21 error
69+ (unit 20:27 (str 20:28 "Too long"))))
70+ (lit 20:40 ~)))
71+ (arm 21:5
72+ (lit 21:5 %.n)
73+ (tuple 21:10
74+ (change 21:11 m
75+ (edit 21:13 draft (wing 21:19 t))
76+ (edit 21:21 error (lit 21:27 ~)))
77+ (lit 21:30 ~))))))
78+ (arm 22:3
79+ (lit 22:3 %submit)
80+ (tuple 22:18
81+ (change 22:19 m
82+ (edit 22:21 draft (str 22:27 "")))
83+ (list 22:31
84+ (group 22:33
85+ (call 22:34
86+ (wing 22:34 poke.todo)
87+ (tuple 22:44 (lit 22:45 %add) (wing 22:50 draft.m))
88+ (ctor 22:59 %acked))))))
89+ (arm 23:3
90+ (cell 23:3 (lit 23:4 %toggled) (bind 23:13 id))
91+ (tuple 23:18
92+ (wing 23:19 m)
93+ (list 23:21
94+ (group 23:23
95+ (call 23:24
96+ (wing 23:24 poke.todo)
97+ (tuple 23:34 (lit 23:35 %toggle) (wing 23:43 id))
98+ (ctor 23:47 %acked))))))
99+ (arm 24:3
100+ (cell 24:3 (lit 24:4 %got) (bind 24:9 ts))
101+ (tuple 24:18
102+ (change 24:19 m
103+ (edit 24:21 todos (wing 24:27 ts)))
104+ (lit 24:31 ~)))
105+ (arm 25:3
106+ (cell 25:3 (lit 25:4 %acked) (bind 25:11 err))
107+ (tuple 25:18
108+ (change 25:19 m
109+ (edit 25:21 error (wing 25:27 err)))
110+ (lit 25:32 ~)))))))
111111 (value 27:1 subs
112112 (gate 27:9
113113 (face 27:12 m (ref 27:14 model))
tests/golden/inline-cell-wing-face-bad/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar, Expressions: "A cell's items take plain names."
2+tests: a cell's item named by a wing, which only a change's item may be
3+expect: error at 1:10, the =: the wing `a.b` is the cell's first item, an operand, and the = after it goes tight where a space between items goes
tests/golden/inline-cell-wing-face-bad/source.jibbnew file+1
@@ -0,0 +1 @@
1+++ x [a.b=1]
tests/golden/inline-cell-wing-face-bad/tokens.txtnew file+8
@@ -0,0 +1,8 @@
1+1:1 glyph ++
2+1:4 name x
3+1:6 glyph [
4+1:7 tight wing a.b
5+1:10 tight glyph =
6+1:11 tight lit 1
7+1:12 tight glyph ]
8+1:13 NEWLINE
tests/golden/inline-cell-wing-face-bad/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/inline-cell-wing-face-bad/source.jibb:1:10: expected a space between items, found `=`; `name=value` goes in a cell, as [a=1], or a change, as m(a=1)
2+++ x [a.b=1]
3+ ^
tests/golden/inline-change-wing/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: docs/reviews/2026-11-02-syntax-review.md, S6, the proposed `toggle-open`; Grammar, Expressions: "`m(open.cart=(not open.cart.m))` sets field `open` of field `cart`, as Hoon's `m(open.cart x)`."
2+tests: the review's nested change, written with a wing item
3+expect: parses: one change of m with the edit open.cart
tests/golden/inline-change-wing/source.jibbnew file+2
@@ -0,0 +1,2 @@
1+++ toggle-open |= m=model
2+ m(open.cart=(not open.cart.m))
tests/golden/inline-change-wing/tokens.txtnew file+18
@@ -0,0 +1,18 @@
1+1:1 glyph ++
2+1:4 name toggle-open
3+1:16 glyph |=
4+1:19 name m
5+1:20 tight glyph =
6+1:21 tight name model
7+2:3 INDENT
8+2:3 name m
9+2:4 tight glyph (
10+2:5 tight wing open.cart
11+2:14 tight glyph =
12+2:15 tight glyph (
13+2:16 tight name not
14+2:20 wing open.cart.m
15+2:31 tight glyph )
16+2:32 tight glyph )
17+2:33 DEDENT
18+2:33 NEWLINE
tests/golden/inline-change-wing/tree.txtnew file+9
@@ -0,0 +1,9 @@
1+(module
2+ (value 1:1 toggle-open
3+ (gate 1:16
4+ (face 1:19 m (ref 1:21 model))
5+ (body 2:3
6+ (change 2:3 m
7+ (edit 2:5 open.cart
8+ (group 2:15
9+ (call 2:16 (wing 2:16 not) (wing 2:20 open.cart.m)))))))))
tests/golden/inline-decimal-sites/types.txt+1−1
@@ -62,7 +62,7 @@ partial inference; module not checked
6262/tests/golden/inline-decimal-sites/source.jibb:22:15: decimal
6363++ note (text 5)
6464 ^
65−++ note-ok: (element A)
65+++ note-ok: (element M)
6666++ shown: `5` is a @ud, not a @t; write "5"
6767/tests/golden/inline-decimal-sites/source.jibb:24:32: decimal
6868++ shown ^- (element !!) (text 5)
tests/golden/inline-decimal/about.txt+1−1
@@ -1,3 +1,3 @@
1−source: Grammar tab, Literals table, the Decimal row: `1.000`, "`@ud`, or any aura by context; groups of three, as in Hoon"
1+source: Grammar tab, Literals table, the Decimal row: `1.000`, "`@ud`, which also fits `@u`, `@` and `*`; groups of three, as in Hoon"
22tests: the decimal literal 1.000
33expect: parses
tests/golden/inline-unface-arity-bad/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Expressions, Unface: "Like `proj`, it is an operation the checker handles by type, not a gate"
2+tests: unface takes exactly one argument: two are an error at the call, and none, (unface), is an error at its parenthesis.
3+expect: parses
4+expect-types: a partial inference report: both are errors at the call
tests/golden/inline-unface-arity-bad/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-arity-bad/source.jibbnew file+3
@@ -0,0 +1,3 @@
1+++ lt-a |= [a=@ud b=@ud] (gth b a)
2+++ two (unface lt-a lt-a)
3+++ none (unface)
tests/golden/inline-unface-arity-bad/tokens.txtnew file+31
@@ -0,0 +1,31 @@
1+1:1 glyph ++
2+1:4 name lt-a
3+1:9 glyph |=
4+1:12 glyph [
5+1:13 tight name a
6+1:14 tight glyph =
7+1:15 tight aura @ud
8+1:19 name b
9+1:20 tight glyph =
10+1:21 tight aura @ud
11+1:24 tight glyph ]
12+1:26 glyph (
13+1:27 tight name gth
14+1:31 name b
15+1:33 name a
16+1:34 tight glyph )
17+2:1 NEWLINE
18+2:1 glyph ++
19+2:4 name two
20+2:8 glyph (
21+2:9 tight name unface
22+2:16 name lt-a
23+2:21 name lt-a
24+2:25 tight glyph )
25+3:1 NEWLINE
26+3:1 glyph ++
27+3:4 name none
28+3:9 glyph (
29+3:10 tight name unface
30+3:16 tight glyph )
31+3:17 NEWLINE
tests/golden/inline-unface-arity-bad/tree.txtnew file+13
@@ -0,0 +1,13 @@
1+(module
2+ (value 1:1 lt-a
3+ (gate 1:9
4+ (cell 1:12
5+ (face 1:13 a (aura 1:15 @ud))
6+ (face 1:19 b (aura 1:21 @ud)))
7+ (group 1:26
8+ (call 1:27 (wing 1:27 gth) (wing 1:31 b) (wing 1:33 a)))))
9+ (value 2:1 two
10+ (group 2:8
11+ (call 2:9 (wing 2:9 unface) (wing 2:16 lt-a) (wing 2:21 lt-a))))
12+ (value 3:1 none
13+ (group 3:9 (wing 3:10 unface))))
tests/golden/inline-unface-arity-bad/types.txtnew file+10
@@ -0,0 +1,10 @@
1+partial inference; module not checked
2+++ lt-a: $-([a=@ud b=@ud] ?)
3+++ two: unface takes one argument, as (unface e)
4+/tests/golden/inline-unface-arity-bad/source.jibb:2:9: unface call
5+++ two (unface lt-a lt-a)
6+ ^
7+++ none: unface takes one argument, as (unface e)
8+/tests/golden/inline-unface-arity-bad/source.jibb:3:9: unface call
9+++ none (unface)
10+ ^
tests/golden/inline-unface-deep/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Expressions, Unface: "`(unface e)` is `e` with every face removed from its type"
2+tests: Faces are removed all the way down: from a gate's product, from a gate in its sample, and from the arguments of a list and a unit, whose own u= stays; a gate with no faces is unchanged.
3+expect: parses
4+expect-types: a partial inference report
tests/golden/inline-unface-deep/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-deep/source.jibbnew file+10
@@ -0,0 +1,10 @@
1+++ make |= n=@ud ^- [label=@t n=@ud] ["x" n]
2+++ make-u (unface make)
3+++ made (make-u 1)
4+++ apply |= f=$-([x=@ud y=@ud] ?) [r=(f 1 2)]
5+++ apply-u (unface apply)
6+++ pairs ^- (list [p=@t q=@ud]) ~[["a" 1]]
7+++ pairs-u (unface pairs)
8+++ maybe ^- (unit [p=@t q=@ud]) `["a" 1]
9+++ maybe-u (unface maybe)
10+++ same-u (unface same)
tests/golden/inline-unface-deep/tokens.txtnew file+129
@@ -0,0 +1,129 @@
1+1:1 glyph ++
2+1:4 name make
3+1:9 glyph |=
4+1:12 name n
5+1:13 tight glyph =
6+1:14 tight aura @ud
7+1:18 glyph ^-
8+1:21 glyph [
9+1:22 tight name label
10+1:27 tight glyph =
11+1:28 tight aura @t
12+1:31 name n
13+1:32 tight glyph =
14+1:33 tight aura @ud
15+1:36 tight glyph ]
16+1:38 glyph [
17+1:39 tight str "x"
18+1:43 name n
19+1:44 tight glyph ]
20+2:1 NEWLINE
21+2:1 glyph ++
22+2:4 name make-u
23+2:11 glyph (
24+2:12 tight name unface
25+2:19 name make
26+2:23 tight glyph )
27+3:1 NEWLINE
28+3:1 glyph ++
29+3:4 name made
30+3:9 glyph (
31+3:10 tight name make-u
32+3:17 lit 1
33+3:18 tight glyph )
34+4:1 NEWLINE
35+4:1 glyph ++
36+4:4 name apply
37+4:10 glyph |=
38+4:13 name f
39+4:14 tight glyph =
40+4:15 tight glyph $-(
41+4:18 tight glyph [
42+4:19 tight name x
43+4:20 tight glyph =
44+4:21 tight aura @ud
45+4:25 name y
46+4:26 tight glyph =
47+4:27 tight aura @ud
48+4:30 tight glyph ]
49+4:32 glyph ?
50+4:33 tight glyph )
51+4:35 glyph [
52+4:36 tight name r
53+4:37 tight glyph =
54+4:38 tight glyph (
55+4:39 tight name f
56+4:41 lit 1
57+4:43 lit 2
58+4:44 tight glyph )
59+4:45 tight glyph ]
60+5:1 NEWLINE
61+5:1 glyph ++
62+5:4 name apply-u
63+5:12 glyph (
64+5:13 tight name unface
65+5:20 name apply
66+5:25 tight glyph )
67+6:1 NEWLINE
68+6:1 glyph ++
69+6:4 name pairs
70+6:10 glyph ^-
71+6:13 glyph (
72+6:14 tight name list
73+6:19 glyph [
74+6:20 tight name p
75+6:21 tight glyph =
76+6:22 tight aura @t
77+6:25 name q
78+6:26 tight glyph =
79+6:27 tight aura @ud
80+6:30 tight glyph ]
81+6:31 tight glyph )
82+6:33 glyph ~[
83+6:35 tight glyph [
84+6:36 tight str "a"
85+6:40 lit 1
86+6:41 tight glyph ]
87+6:42 tight glyph ]
88+7:1 NEWLINE
89+7:1 glyph ++
90+7:4 name pairs-u
91+7:12 glyph (
92+7:13 tight name unface
93+7:20 name pairs
94+7:25 tight glyph )
95+8:1 NEWLINE
96+8:1 glyph ++
97+8:4 name maybe
98+8:10 glyph ^-
99+8:13 glyph (
100+8:14 tight name unit
101+8:19 glyph [
102+8:20 tight name p
103+8:21 tight glyph =
104+8:22 tight aura @t
105+8:25 name q
106+8:26 tight glyph =
107+8:27 tight aura @ud
108+8:30 tight glyph ]
109+8:31 tight glyph )
110+8:33 glyph `
111+8:34 tight glyph [
112+8:35 tight str "a"
113+8:39 lit 1
114+8:40 tight glyph ]
115+9:1 NEWLINE
116+9:1 glyph ++
117+9:4 name maybe-u
118+9:12 glyph (
119+9:13 tight name unface
120+9:20 name maybe
121+9:25 tight glyph )
122+10:1 NEWLINE
123+10:1 glyph ++
124+10:4 name same-u
125+10:11 glyph (
126+10:12 tight name unface
127+10:19 name same
128+10:23 tight glyph )
129+10:24 NEWLINE
tests/golden/inline-unface-deep/tree.txtnew file+55
@@ -0,0 +1,55 @@
1+(module
2+ (value 1:1 make
3+ (gate 1:9
4+ (face 1:12 n (aura 1:14 @ud))
5+ (cast 1:18
6+ (cell 1:21
7+ (face 1:22 label (aura 1:28 @t))
8+ (face 1:31 n (aura 1:33 @ud)))
9+ (tuple 1:38 (str 1:39 "x") (wing 1:43 n)))))
10+ (value 2:1 make-u
11+ (group 2:11
12+ (call 2:12 (wing 2:12 unface) (wing 2:19 make))))
13+ (value 3:1 made
14+ (group 3:9
15+ (call 3:10 (wing 3:10 make-u) (lit 3:17 1))))
16+ (value 4:1 apply
17+ (gate 4:10
18+ (face 4:13 f
19+ (fn 4:15
20+ (cell 4:18
21+ (face 4:19 x (aura 4:21 @ud))
22+ (face 4:25 y (aura 4:27 @ud)))
23+ (flag 4:32)))
24+ (tuple 4:35
25+ (face 4:36 r
26+ (group 4:38
27+ (call 4:39 (wing 4:39 f) (lit 4:41 1) (lit 4:43 2)))))))
28+ (value 5:1 apply-u
29+ (group 5:12
30+ (call 5:13 (wing 5:13 unface) (wing 5:20 apply))))
31+ (value 6:1 pairs
32+ (cast 6:10
33+ (apply 6:13 list
34+ (cell 6:19
35+ (face 6:20 p (aura 6:22 @t))
36+ (face 6:25 q (aura 6:27 @ud))))
37+ (list 6:33
38+ (tuple 6:35 (str 6:36 "a") (lit 6:40 1)))))
39+ (value 7:1 pairs-u
40+ (group 7:12
41+ (call 7:13 (wing 7:13 unface) (wing 7:20 pairs))))
42+ (value 8:1 maybe
43+ (cast 8:10
44+ (apply 8:13 unit
45+ (cell 8:19
46+ (face 8:20 p (aura 8:22 @t))
47+ (face 8:25 q (aura 8:27 @ud))))
48+ (unit 8:33
49+ (tuple 8:34 (str 8:35 "a") (lit 8:39 1)))))
50+ (value 9:1 maybe-u
51+ (group 9:12
52+ (call 9:13 (wing 9:13 unface) (wing 9:20 maybe))))
53+ (value 10:1 same-u
54+ (group 10:11
55+ (call 10:12 (wing 10:12 unface) (wing 10:19 same)))))
tests/golden/inline-unface-deep/types.txtnew file+11
@@ -0,0 +1,11 @@
1+partial inference; module not checked
2+++ make: $-(@ud [label=@t n=@ud])
3+++ make-u: $-(@ud [@t @ud])
4+++ made: [@t @ud]
5+++ apply: $-($-([x=@ud y=@ud] ?) [r=?])
6+++ apply-u: $-($-([@ud @ud] ?) ?)
7+++ pairs: (list [p=@t q=@ud])
8+++ pairs-u: (list [@t @ud])
9+++ maybe: (unit [p=@t q=@ud])
10+++ maybe-u: (unit [@t @ud])
11+++ same-u: $-(A A)
tests/golden/inline-unface-gates/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Expressions, Unface: "`(unface e)` is `e` with every face removed from its type"
2+tests: Gates whose samples are labelled differently share a list and fit slots written with capitals once unfaced; the same gates without unface fail, and a direct call of an unfaced gate takes any labels.
3+expect: parses
4+expect-types: a partial inference report
tests/golden/inline-unface-gates/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-gates/source.jibbnew file+11
@@ -0,0 +1,11 @@
1+++ lth2 |= [x=A y=A] (gth y x)
2+++ lte2 |= [a=A b=A] (not (gth a b))
3+++ lt-a |= [a=@ud b=@ud] (gth b a)
4+++ add-f |= [a=@ud b=@ud] (add a b)
5+++ labelled ~[lth2 lte2]
6+++ pickers ~[(unface lth2) (unface lte2)]
7+++ hunt-labelled (hunt lt-a `1 `2)
8+++ hunt-unfaced (hunt (unface lt-a) `1 `2)
9+++ roll-labelled (roll ~[1 2] 0 add-f)
10+++ roll-unfaced (roll ~[1 2] 0 (unface add-f))
11+++ one-off ((unface add-f) [b=1 a=2])
tests/golden/inline-unface-gates/tokens.txtnew file+160
@@ -0,0 +1,160 @@
1+1:1 glyph ++
2+1:4 name lth2
3+1:9 glyph |=
4+1:12 glyph [
5+1:13 tight name x
6+1:14 tight glyph =
7+1:15 tight tvar A
8+1:17 name y
9+1:18 tight glyph =
10+1:19 tight tvar A
11+1:20 tight glyph ]
12+1:22 glyph (
13+1:23 tight name gth
14+1:27 name y
15+1:29 name x
16+1:30 tight glyph )
17+2:1 NEWLINE
18+2:1 glyph ++
19+2:4 name lte2
20+2:9 glyph |=
21+2:12 glyph [
22+2:13 tight name a
23+2:14 tight glyph =
24+2:15 tight tvar A
25+2:17 name b
26+2:18 tight glyph =
27+2:19 tight tvar A
28+2:20 tight glyph ]
29+2:22 glyph (
30+2:23 tight name not
31+2:27 glyph (
32+2:28 tight name gth
33+2:32 name a
34+2:34 name b
35+2:35 tight glyph )
36+2:36 tight glyph )
37+3:1 NEWLINE
38+3:1 glyph ++
39+3:4 name lt-a
40+3:9 glyph |=
41+3:12 glyph [
42+3:13 tight name a
43+3:14 tight glyph =
44+3:15 tight aura @ud
45+3:19 name b
46+3:20 tight glyph =
47+3:21 tight aura @ud
48+3:24 tight glyph ]
49+3:26 glyph (
50+3:27 tight name gth
51+3:31 name b
52+3:33 name a
53+3:34 tight glyph )
54+4:1 NEWLINE
55+4:1 glyph ++
56+4:4 name add-f
57+4:10 glyph |=
58+4:13 glyph [
59+4:14 tight name a
60+4:15 tight glyph =
61+4:16 tight aura @ud
62+4:20 name b
63+4:21 tight glyph =
64+4:22 tight aura @ud
65+4:25 tight glyph ]
66+4:27 glyph (
67+4:28 tight name add
68+4:32 name a
69+4:34 name b
70+4:35 tight glyph )
71+5:1 NEWLINE
72+5:1 glyph ++
73+5:4 name labelled
74+5:13 glyph ~[
75+5:15 tight name lth2
76+5:20 name lte2
77+5:24 tight glyph ]
78+6:1 NEWLINE
79+6:1 glyph ++
80+6:4 name pickers
81+6:12 glyph ~[
82+6:14 tight glyph (
83+6:15 tight name unface
84+6:22 name lth2
85+6:26 tight glyph )
86+6:28 glyph (
87+6:29 tight name unface
88+6:36 name lte2
89+6:40 tight glyph )
90+6:41 tight glyph ]
91+7:1 NEWLINE
92+7:1 glyph ++
93+7:4 name hunt-labelled
94+7:18 glyph (
95+7:19 tight name hunt
96+7:24 name lt-a
97+7:29 glyph `
98+7:30 tight lit 1
99+7:32 glyph `
100+7:33 tight lit 2
101+7:34 tight glyph )
102+8:1 NEWLINE
103+8:1 glyph ++
104+8:4 name hunt-unfaced
105+8:17 glyph (
106+8:18 tight name hunt
107+8:23 glyph (
108+8:24 tight name unface
109+8:31 name lt-a
110+8:35 tight glyph )
111+8:37 glyph `
112+8:38 tight lit 1
113+8:40 glyph `
114+8:41 tight lit 2
115+8:42 tight glyph )
116+9:1 NEWLINE
117+9:1 glyph ++
118+9:4 name roll-labelled
119+9:18 glyph (
120+9:19 tight name roll
121+9:24 glyph ~[
122+9:26 tight lit 1
123+9:28 lit 2
124+9:29 tight glyph ]
125+9:31 lit 0
126+9:33 name add-f
127+9:38 tight glyph )
128+10:1 NEWLINE
129+10:1 glyph ++
130+10:4 name roll-unfaced
131+10:17 glyph (
132+10:18 tight name roll
133+10:23 glyph ~[
134+10:25 tight lit 1
135+10:27 lit 2
136+10:28 tight glyph ]
137+10:30 lit 0
138+10:32 glyph (
139+10:33 tight name unface
140+10:40 name add-f
141+10:45 tight glyph )
142+10:46 tight glyph )
143+11:1 NEWLINE
144+11:1 glyph ++
145+11:4 name one-off
146+11:12 glyph (
147+11:13 tight glyph (
148+11:14 tight name unface
149+11:21 name add-f
150+11:26 tight glyph )
151+11:28 glyph [
152+11:29 tight name b
153+11:30 tight glyph =
154+11:31 tight lit 1
155+11:33 name a
156+11:34 tight glyph =
157+11:35 tight lit 2
158+11:36 tight glyph ]
159+11:37 tight glyph )
160+11:38 NEWLINE
tests/golden/inline-unface-gates/tree.txtnew file+78
@@ -0,0 +1,78 @@
1+(module
2+ (value 1:1 lth2
3+ (gate 1:9
4+ (cell 1:12
5+ (face 1:13 x (tvar 1:15 A))
6+ (face 1:17 y (tvar 1:19 A)))
7+ (group 1:22
8+ (call 1:23 (wing 1:23 gth) (wing 1:27 y) (wing 1:29 x)))))
9+ (value 2:1 lte2
10+ (gate 2:9
11+ (cell 2:12
12+ (face 2:13 a (tvar 2:15 A))
13+ (face 2:17 b (tvar 2:19 A)))
14+ (group 2:22
15+ (call 2:23
16+ (wing 2:23 not)
17+ (group 2:27
18+ (call 2:28 (wing 2:28 gth) (wing 2:32 a) (wing 2:34 b)))))))
19+ (value 3:1 lt-a
20+ (gate 3:9
21+ (cell 3:12
22+ (face 3:13 a (aura 3:15 @ud))
23+ (face 3:19 b (aura 3:21 @ud)))
24+ (group 3:26
25+ (call 3:27 (wing 3:27 gth) (wing 3:31 b) (wing 3:33 a)))))
26+ (value 4:1 add-f
27+ (gate 4:10
28+ (cell 4:13
29+ (face 4:14 a (aura 4:16 @ud))
30+ (face 4:20 b (aura 4:22 @ud)))
31+ (group 4:27
32+ (call 4:28 (wing 4:28 add) (wing 4:32 a) (wing 4:34 b)))))
33+ (value 5:1 labelled
34+ (list 5:13 (wing 5:15 lth2) (wing 5:20 lte2)))
35+ (value 6:1 pickers
36+ (list 6:12
37+ (group 6:14
38+ (call 6:15 (wing 6:15 unface) (wing 6:22 lth2)))
39+ (group 6:28
40+ (call 6:29 (wing 6:29 unface) (wing 6:36 lte2)))))
41+ (value 7:1 hunt-labelled
42+ (group 7:18
43+ (call 7:19
44+ (wing 7:19 hunt)
45+ (wing 7:24 lt-a)
46+ (unit 7:29 (lit 7:30 1))
47+ (unit 7:32 (lit 7:33 2)))))
48+ (value 8:1 hunt-unfaced
49+ (group 8:17
50+ (call 8:18
51+ (wing 8:18 hunt)
52+ (group 8:23
53+ (call 8:24 (wing 8:24 unface) (wing 8:31 lt-a)))
54+ (unit 8:37 (lit 8:38 1))
55+ (unit 8:40 (lit 8:41 2)))))
56+ (value 9:1 roll-labelled
57+ (group 9:18
58+ (call 9:19
59+ (wing 9:19 roll)
60+ (list 9:24 (lit 9:26 1) (lit 9:28 2))
61+ (lit 9:31 0)
62+ (wing 9:33 add-f))))
63+ (value 10:1 roll-unfaced
64+ (group 10:17
65+ (call 10:18
66+ (wing 10:18 roll)
67+ (list 10:23 (lit 10:25 1) (lit 10:27 2))
68+ (lit 10:30 0)
69+ (group 10:32
70+ (call 10:33 (wing 10:33 unface) (wing 10:40 add-f))))))
71+ (value 11:1 one-off
72+ (group 11:12
73+ (call 11:13
74+ (group 11:13
75+ (call 11:14 (wing 11:14 unface) (wing 11:21 add-f)))
76+ (tuple 11:28
77+ (face 11:29 b (lit 11:31 1))
78+ (face 11:33 a (lit 11:35 2)))))))
tests/golden/inline-unface-gates/types.txtnew file+30
@@ -0,0 +1,30 @@
1+partial inference; module not checked
2+++ lth2: $-([x=A y=A] ?) where A is an atom
3+++ lte2: $-([a=A b=A] ?) where A is an atom
4+++ lt-a: $-([a=@ud b=@ud] ?)
5+++ add-f: $-([a=@ud b=@ud] @ud)
6+++ labelled: list items do not have compatible types
7+/tests/golden/inline-unface-gates/source.jibb:5:13: expected item has type $-([x=A y=A] ?) where A is an atom
8+++ labelled ~[lth2 lte2]
9+ ^
10+/tests/golden/inline-unface-gates/source.jibb:5:20: list item has type $-([a=A b=A] ?) where A is an atom
11+++ labelled ~[lth2 lte2]
12+ ^
13+++ pickers: (list $-([A A] ?)) where A is an atom
14+++ hunt-labelled: call's sample and argument types do not unify
15+/tests/golden/inline-unface-gates/source.jibb:7:19: called gate
16+++ hunt-labelled (hunt lt-a `1 `2)
17+ ^
18+/tests/golden/inline-unface-gates/source.jibb:7:24: argument has type $-([a=@ud b=@ud] ?)
19+++ hunt-labelled (hunt lt-a `1 `2)
20+ ^
21+++ hunt-unfaced: (unit @ud)
22+++ roll-labelled: call's sample and argument types do not unify
23+/tests/golden/inline-unface-gates/source.jibb:9:19: called gate
24+++ roll-labelled (roll ~[1 2] 0 add-f)
25+ ^
26+/tests/golden/inline-unface-gates/source.jibb:9:33: argument has type $-([a=@ud b=@ud] @ud)
27+++ roll-labelled (roll ~[1 2] 0 add-f)
28+ ^
29+++ roll-unfaced: @ud
30+++ one-off: @ud
tests/golden/inline-unface-import/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Expressions, Unface: "`(unface e)` is `e` with every face removed from its type" and "A `++` whose body is `(unface |= …)` is still a gate, so it can call itself"
2+tests: An imported module, checked in full, exports unfaced gates and records, a recursive one included, and the importer uses them with their unfaced types.
3+expect: parses
4+expect-types: a partial inference report
tests/golden/inline-unface-import/module-trees.txtnew file+43
@@ -0,0 +1,43 @@
1+/ui/lib.jibb
2+(module
3+ (value 1:1 lt-a
4+ (gate 1:9
5+ (cell 1:12
6+ (face 1:13 a (aura 1:15 @ud))
7+ (face 1:19 b (aura 1:21 @ud)))
8+ (group 1:26
9+ (call 1:27 (wing 1:27 gth) (wing 1:31 b) (wing 1:33 a)))))
10+ (value 2:1 lt-u
11+ (group 2:9
12+ (call 2:10 (wing 2:10 unface) (wing 2:17 lt-a))))
13+ (value 3:1 weld2
14+ (group 3:10
15+ (call 3:11
16+ (wing 3:11 unface)
17+ (gate 4:3
18+ (cell 4:6
19+ (face 4:7 xs
20+ (apply 4:10 list (tvar 4:16 A)))
21+ (face 4:19 ys
22+ (apply 4:22 list (tvar 4:28 A))))
23+ (cast 4:32
24+ (apply 4:35 list (tvar 4:41 A))
25+ (body 5:5
26+ (branch 5:5
27+ (wing 5:8 xs)
28+ (arm 6:7 (lit 6:7 ~) (wing 6:9 ys))
29+ (arm 7:7
30+ (cell 7:7 (bind 7:8 item) (bind 7:13 rest))
31+ (tuple 7:19
32+ (wing 7:20 item)
33+ (group 7:25
34+ (call 7:26 (wing 7:26 weld2) (wing 7:32 rest) (wing 7:37 ys))))))))))))
35+ (value 8:1 pair
36+ (cast 8:9
37+ (cell 8:12
38+ (face 8:13 p (aura 8:15 @t))
39+ (face 8:18 q (aura 8:20 @ud)))
40+ (tuple 8:25 (str 8:26 "a") (lit 8:30 1))))
41+ (value 9:1 pair-u
42+ (group 9:11
43+ (call 9:12 (wing 9:12 unface) (wing 9:19 pair)))))
tests/golden/inline-unface-import/modules.txtnew file+1
@@ -0,0 +1 @@
1+/ui/lib.jibb
tests/golden/inline-unface-import/modules/ui/lib.jibbnew file+9
@@ -0,0 +1,9 @@
1+++ lt-a |= [a=@ud b=@ud] (gth b a)
2+++ lt-u (unface lt-a)
3+++ weld2 (unface
4+ |= [xs=(list A) ys=(list A)] ^- (list A)
5+ ?- xs
6+ ~ ys
7+ [item rest] [item (weld2 rest ys)]
8+++ pair ^- [p=@t q=@ud] ["a" 1]
9+++ pair-u (unface pair)
tests/golden/inline-unface-import/source.jibbnew file+5
@@ -0,0 +1,5 @@
1+/= lib /ui/lib
2+++ a lt-u.lib
3+++ b (weld2.lib ~[1] ~[2])
4+++ c pair-u.lib
5+++ d (hunt lt-u.lib `1 `2)
tests/golden/inline-unface-import/tokens.txtnew file+38
@@ -0,0 +1,38 @@
1+1:1 glyph /=
2+1:5 name lib
3+1:9 glyph /
4+1:10 tight knot ui
5+1:12 tight glyph /
6+1:13 tight knot lib
7+2:1 NEWLINE
8+2:1 glyph ++
9+2:4 name a
10+2:6 wing lt-u.lib
11+3:1 NEWLINE
12+3:1 glyph ++
13+3:4 name b
14+3:6 glyph (
15+3:7 tight wing weld2.lib
16+3:17 glyph ~[
17+3:19 tight lit 1
18+3:20 tight glyph ]
19+3:22 glyph ~[
20+3:24 tight lit 2
21+3:25 tight glyph ]
22+3:26 tight glyph )
23+4:1 NEWLINE
24+4:1 glyph ++
25+4:4 name c
26+4:6 wing pair-u.lib
27+5:1 NEWLINE
28+5:1 glyph ++
29+5:4 name d
30+5:6 glyph (
31+5:7 tight name hunt
32+5:12 wing lt-u.lib
33+5:21 glyph `
34+5:22 tight lit 1
35+5:24 glyph `
36+5:25 tight lit 2
37+5:26 tight glyph )
38+5:27 NEWLINE
tests/golden/inline-unface-import/tree.txtnew file+17
@@ -0,0 +1,17 @@
1+(module
2+ (jibb 1:1 lib /ui/lib)
3+ (value 2:1 a (wing 2:6 lt-u.lib))
4+ (value 3:1 b
5+ (group 3:6
6+ (call 3:7
7+ (wing 3:7 weld2.lib)
8+ (list 3:17 (lit 3:19 1))
9+ (list 3:22 (lit 3:24 2)))))
10+ (value 4:1 c (wing 4:6 pair-u.lib))
11+ (value 5:1 d
12+ (group 5:6
13+ (call 5:7
14+ (wing 5:7 hunt)
15+ (wing 5:12 lt-u.lib)
16+ (unit 5:21 (lit 5:22 1))
17+ (unit 5:24 (lit 5:25 2))))))
tests/golden/inline-unface-import/types.txtnew file+5
@@ -0,0 +1,5 @@
1+partial inference; module not checked
2+++ a: $-([@ud @ud] ?)
3+++ b: (list @ud)
4+++ c: [@t @ud]
5+++ d: (unit @ud)
tests/golden/inline-unface-labelled-slot/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Expressions, Unface: "`(unface e)` is `e` with every face removed from its type, so a gate or record fits where other names are expected"
2+tests: An unfaced gate passed to a slot that writes its own labels: a closed gate fits, as "an unnamed position can unify with a faced position" allows; a generic one still fails, because its capital A meets the faced x=@ud, and a capital binding only the type under a face is S1 step 1, not part of this rule.
3+expect: parses
4+expect-types: a partial inference report
tests/golden/inline-unface-labelled-slot/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-labelled-slot/source.jibbnew file+5
@@ -0,0 +1,5 @@
1+++ lt-a |= [a=@ud b=@ud] (gth b a)
2+++ lth2 |= [x=A y=A] (gth y x)
3+++ take-xy |= f=$-([x=@ud y=@ud] ?) (f 1 2)
4+++ closed (take-xy (unface lt-a))
5+++ generic (take-xy (unface lth2))
tests/golden/inline-unface-labelled-slot/tokens.txtnew file+76
@@ -0,0 +1,76 @@
1+1:1 glyph ++
2+1:4 name lt-a
3+1:9 glyph |=
4+1:12 glyph [
5+1:13 tight name a
6+1:14 tight glyph =
7+1:15 tight aura @ud
8+1:19 name b
9+1:20 tight glyph =
10+1:21 tight aura @ud
11+1:24 tight glyph ]
12+1:26 glyph (
13+1:27 tight name gth
14+1:31 name b
15+1:33 name a
16+1:34 tight glyph )
17+2:1 NEWLINE
18+2:1 glyph ++
19+2:4 name lth2
20+2:9 glyph |=
21+2:12 glyph [
22+2:13 tight name x
23+2:14 tight glyph =
24+2:15 tight tvar A
25+2:17 name y
26+2:18 tight glyph =
27+2:19 tight tvar A
28+2:20 tight glyph ]
29+2:22 glyph (
30+2:23 tight name gth
31+2:27 name y
32+2:29 name x
33+2:30 tight glyph )
34+3:1 NEWLINE
35+3:1 glyph ++
36+3:4 name take-xy
37+3:12 glyph |=
38+3:15 name f
39+3:16 tight glyph =
40+3:17 tight glyph $-(
41+3:20 tight glyph [
42+3:21 tight name x
43+3:22 tight glyph =
44+3:23 tight aura @ud
45+3:27 name y
46+3:28 tight glyph =
47+3:29 tight aura @ud
48+3:32 tight glyph ]
49+3:34 glyph ?
50+3:35 tight glyph )
51+3:37 glyph (
52+3:38 tight name f
53+3:40 lit 1
54+3:42 lit 2
55+3:43 tight glyph )
56+4:1 NEWLINE
57+4:1 glyph ++
58+4:4 name closed
59+4:11 glyph (
60+4:12 tight name take-xy
61+4:20 glyph (
62+4:21 tight name unface
63+4:28 name lt-a
64+4:32 tight glyph )
65+4:33 tight glyph )
66+5:1 NEWLINE
67+5:1 glyph ++
68+5:4 name generic
69+5:12 glyph (
70+5:13 tight name take-xy
71+5:21 glyph (
72+5:22 tight name unface
73+5:29 name lth2
74+5:33 tight glyph )
75+5:34 tight glyph )
76+5:35 NEWLINE
tests/golden/inline-unface-labelled-slot/tree.txtnew file+37
@@ -0,0 +1,37 @@
1+(module
2+ (value 1:1 lt-a
3+ (gate 1:9
4+ (cell 1:12
5+ (face 1:13 a (aura 1:15 @ud))
6+ (face 1:19 b (aura 1:21 @ud)))
7+ (group 1:26
8+ (call 1:27 (wing 1:27 gth) (wing 1:31 b) (wing 1:33 a)))))
9+ (value 2:1 lth2
10+ (gate 2:9
11+ (cell 2:12
12+ (face 2:13 x (tvar 2:15 A))
13+ (face 2:17 y (tvar 2:19 A)))
14+ (group 2:22
15+ (call 2:23 (wing 2:23 gth) (wing 2:27 y) (wing 2:29 x)))))
16+ (value 3:1 take-xy
17+ (gate 3:12
18+ (face 3:15 f
19+ (fn 3:17
20+ (cell 3:20
21+ (face 3:21 x (aura 3:23 @ud))
22+ (face 3:27 y (aura 3:29 @ud)))
23+ (flag 3:34)))
24+ (group 3:37
25+ (call 3:38 (wing 3:38 f) (lit 3:40 1) (lit 3:42 2)))))
26+ (value 4:1 closed
27+ (group 4:11
28+ (call 4:12
29+ (wing 4:12 take-xy)
30+ (group 4:20
31+ (call 4:21 (wing 4:21 unface) (wing 4:28 lt-a))))))
32+ (value 5:1 generic
33+ (group 5:12
34+ (call 5:13
35+ (wing 5:13 take-xy)
36+ (group 5:21
37+ (call 5:22 (wing 5:22 unface) (wing 5:29 lth2)))))))
tests/golden/inline-unface-labelled-slot/types.txtnew file+12
@@ -0,0 +1,12 @@
1+partial inference; module not checked
2+++ lt-a: $-([a=@ud b=@ud] ?)
3+++ lth2: $-([x=A y=A] ?) where A is an atom
4+++ take-xy: $-($-([x=@ud y=@ud] ?) ?)
5+++ closed: ?
6+++ generic: call's sample and argument types do not unify
7+/tests/golden/inline-unface-labelled-slot/source.jibb:5:13: called gate has type $-($-([x=@ud y=@ud] ?) ?)
8+++ generic (take-xy (unface lth2))
9+ ^
10+/tests/golden/inline-unface-labelled-slot/source.jibb:5:21: argument has type $-([A A] ?) where A is an atom
11+++ generic (take-xy (unface lth2))
12+ ^
tests/golden/inline-unface-lambda/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Expressions, Unface: "`(unface e)` is `e` with every face removed from its type, so a gate or record fits where other names are expected"
2+tests: A lambda that names its sample k and v fails turn's slot over [p=@t q=@ud] and fits it once unfaced. turn's capital A then binds the faced p=@t, so the result keeps p=: that is S1 step 1 (a capital binds only the type under a face), which this rule leaves to the review's unification work.
3+expect: parses
4+expect-types: a partial inference report
tests/golden/inline-unface-lambda/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-lambda/source.jibbnew file+3
@@ -0,0 +1,3 @@
1+++ pairs ^- (list [p=@t q=@ud]) ~[["a" 1]]
2+++ keys-labelled (turn pairs |=([k v] k))
3+++ keys (turn pairs (unface |=([k v] k)))
tests/golden/inline-unface-lambda/tokens.txtnew file+52
@@ -0,0 +1,52 @@
1+1:1 glyph ++
2+1:4 name pairs
3+1:10 glyph ^-
4+1:13 glyph (
5+1:14 tight name list
6+1:19 glyph [
7+1:20 tight name p
8+1:21 tight glyph =
9+1:22 tight aura @t
10+1:25 name q
11+1:26 tight glyph =
12+1:27 tight aura @ud
13+1:30 tight glyph ]
14+1:31 tight glyph )
15+1:33 glyph ~[
16+1:35 tight glyph [
17+1:36 tight str "a"
18+1:40 lit 1
19+1:41 tight glyph ]
20+1:42 tight glyph ]
21+2:1 NEWLINE
22+2:1 glyph ++
23+2:4 name keys-labelled
24+2:18 glyph (
25+2:19 tight name turn
26+2:24 name pairs
27+2:30 glyph |=(
28+2:33 tight glyph [
29+2:34 tight name k
30+2:36 name v
31+2:37 tight glyph ]
32+2:39 name k
33+2:40 tight glyph )
34+2:41 tight glyph )
35+3:1 NEWLINE
36+3:1 glyph ++
37+3:4 name keys
38+3:9 glyph (
39+3:10 tight name turn
40+3:15 name pairs
41+3:21 glyph (
42+3:22 tight name unface
43+3:29 glyph |=(
44+3:32 tight glyph [
45+3:33 tight name k
46+3:35 name v
47+3:36 tight glyph ]
48+3:38 name k
49+3:39 tight glyph )
50+3:40 tight glyph )
51+3:41 tight glyph )
52+3:42 NEWLINE
tests/golden/inline-unface-lambda/tree.txtnew file+28
@@ -0,0 +1,28 @@
1+(module
2+ (value 1:1 pairs
3+ (cast 1:10
4+ (apply 1:13 list
5+ (cell 1:19
6+ (face 1:20 p (aura 1:22 @t))
7+ (face 1:25 q (aura 1:27 @ud))))
8+ (list 1:33
9+ (tuple 1:35 (str 1:36 "a") (lit 1:40 1)))))
10+ (value 2:1 keys-labelled
11+ (group 2:18
12+ (call 2:19
13+ (wing 2:19 turn)
14+ (wing 2:24 pairs)
15+ (gate-wide 2:30
16+ (cell 2:33 (bind 2:34 k) (bind 2:36 v))
17+ (wing 2:39 k)))))
18+ (value 3:1 keys
19+ (group 3:9
20+ (call 3:10
21+ (wing 3:10 turn)
22+ (wing 3:15 pairs)
23+ (group 3:21
24+ (call 3:22
25+ (wing 3:22 unface)
26+ (gate-wide 3:29
27+ (cell 3:32 (bind 3:33 k) (bind 3:35 v))
28+ (wing 3:38 k))))))))
tests/golden/inline-unface-lambda/types.txtnew file+10
@@ -0,0 +1,10 @@
1+partial inference; module not checked
2+++ pairs: (list [p=@t q=@ud])
3+++ keys-labelled: call's sample and argument types do not unify
4+/tests/golden/inline-unface-lambda/source.jibb:2:19: called gate has type $-([(list A) $-(A B)] (list B))
5+++ keys-labelled (turn pairs |=([k v] k))
6+ ^
7+/tests/golden/inline-unface-lambda/source.jibb:2:30: argument has type $-([k=A v=B] A)
8+++ keys-labelled (turn pairs |=([k v] k))
9+ ^
10+++ keys: (list [p=@t])
tests/golden/inline-unface-named-union/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Expressions, Unface: "`(unface e)` is `e` with every face removed from its type"
2+tests: A gate over a named union keeps the union by name, so the unfaced gate still takes a msg and fits a slot written with msg; tags inside unface still take their union from a cast.
3+expect: parses
4+expect-types: a partial inference report
tests/golden/inline-unface-named-union/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-named-union/source.jibbnew file+9
@@ -0,0 +1,9 @@
1++$ msg
2+ [%typed text=@t]
3+ [%sent ~]
4+++ update |= [=msg n=@ud] n
5+++ update-u (unface update)
6+++ direct (update-u [%typed "x"] 1)
7+++ run |= f=$-([msg @ud] @ud) (f [%sent ~] 2)
8+++ ran (run (unface update))
9+++ tagged ^- msg (unface [%typed "x"])
tests/golden/inline-unface-named-union/tokens.txtnew file+89
@@ -0,0 +1,89 @@
1+1:1 glyph +$
2+1:4 name msg
3+2:3 INDENT
4+2:3 glyph [
5+2:4 tight lit %typed
6+2:11 name text
7+2:15 tight glyph =
8+2:16 tight aura @t
9+2:18 tight glyph ]
10+3:3 NEWLINE
11+3:3 glyph [
12+3:4 tight lit %sent
13+3:10 lit ~
14+3:11 tight glyph ]
15+4:1 DEDENT
16+4:1 NEWLINE
17+4:1 glyph ++
18+4:4 name update
19+4:11 glyph |=
20+4:14 glyph [
21+4:15 tight glyph =
22+4:16 tight name msg
23+4:20 name n
24+4:21 tight glyph =
25+4:22 tight aura @ud
26+4:25 tight glyph ]
27+4:27 name n
28+5:1 NEWLINE
29+5:1 glyph ++
30+5:4 name update-u
31+5:13 glyph (
32+5:14 tight name unface
33+5:21 name update
34+5:27 tight glyph )
35+6:1 NEWLINE
36+6:1 glyph ++
37+6:4 name direct
38+6:11 glyph (
39+6:12 tight name update-u
40+6:21 glyph [
41+6:22 tight lit %typed
42+6:29 str "x"
43+6:32 tight glyph ]
44+6:34 lit 1
45+6:35 tight glyph )
46+7:1 NEWLINE
47+7:1 glyph ++
48+7:4 name run
49+7:8 glyph |=
50+7:11 name f
51+7:12 tight glyph =
52+7:13 tight glyph $-(
53+7:16 tight glyph [
54+7:17 tight name msg
55+7:21 aura @ud
56+7:24 tight glyph ]
57+7:26 aura @ud
58+7:29 tight glyph )
59+7:31 glyph (
60+7:32 tight name f
61+7:34 glyph [
62+7:35 tight lit %sent
63+7:41 lit ~
64+7:42 tight glyph ]
65+7:44 lit 2
66+7:45 tight glyph )
67+8:1 NEWLINE
68+8:1 glyph ++
69+8:4 name ran
70+8:8 glyph (
71+8:9 tight name run
72+8:13 glyph (
73+8:14 tight name unface
74+8:21 name update
75+8:27 tight glyph )
76+8:28 tight glyph )
77+9:1 NEWLINE
78+9:1 glyph ++
79+9:4 name tagged
80+9:11 glyph ^-
81+9:14 name msg
82+9:18 glyph (
83+9:19 tight name unface
84+9:26 glyph [
85+9:27 tight lit %typed
86+9:34 str "x"
87+9:37 tight glyph ]
88+9:38 tight glyph )
89+9:39 NEWLINE
tests/golden/inline-unface-named-union/tree.txtnew file+46
@@ -0,0 +1,46 @@
1+(module
2+ (mold 1:1 msg
3+ (union 2:3
4+ (cell 2:3
5+ (const 2:4 %typed)
6+ (face 2:11 text (aura 2:16 @t)))
7+ (cell 3:3 (const 3:4 %sent) (const 3:10 ~))))
8+ (value 4:1 update
9+ (gate 4:11
10+ (cell 4:14
11+ (pun 4:15 msg)
12+ (face 4:20 n (aura 4:22 @ud)))
13+ (wing 4:27 n)))
14+ (value 5:1 update-u
15+ (group 5:13
16+ (call 5:14 (wing 5:14 unface) (wing 5:21 update))))
17+ (value 6:1 direct
18+ (group 6:11
19+ (call 6:12
20+ (wing 6:12 update-u)
21+ (tuple 6:21 (lit 6:22 %typed) (str 6:29 "x"))
22+ (lit 6:34 1))))
23+ (value 7:1 run
24+ (gate 7:8
25+ (face 7:11 f
26+ (fn 7:13
27+ (cell 7:16 (ref 7:17 msg) (aura 7:21 @ud))
28+ (aura 7:26 @ud)))
29+ (group 7:31
30+ (call 7:32
31+ (wing 7:32 f)
32+ (tuple 7:34 (lit 7:35 %sent) (lit 7:41 ~))
33+ (lit 7:44 2)))))
34+ (value 8:1 ran
35+ (group 8:8
36+ (call 8:9
37+ (wing 8:9 run)
38+ (group 8:13
39+ (call 8:14 (wing 8:14 unface) (wing 8:21 update))))))
40+ (value 9:1 tagged
41+ (cast 9:11
42+ (ref 9:14 msg)
43+ (group 9:18
44+ (call 9:19
45+ (wing 9:19 unface)
46+ (tuple 9:26 (lit 9:27 %typed) (str 9:34 "x")))))))
tests/golden/inline-unface-named-union/types.txtnew file+8
@@ -0,0 +1,8 @@
1+partial inference; module not checked
2++$ msg: cases proven disjoint; mold not checked
3+++ update: $-([msg=msg n=@ud] @ud)
4+++ update-u: $-([msg @ud] @ud)
5+++ direct: @ud
6+++ run: $-($-([msg @ud] @ud) @ud)
7+++ ran: @ud
8+++ tagged: msg
tests/golden/inline-unface-records/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Expressions, Unface: "`(unface e)` is `e` with every face removed from its type"
2+tests: A record passed where other labels are expected, which fails without unface; data fields then match by position, so swapped labels pass too.
3+expect: parses
4+expect-types: a partial inference report
tests/golden/inline-unface-records/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-records/source.jibbnew file+8
@@ -0,0 +1,8 @@
1+++ pair-pq ^- [p=@t q=@ud] ["a" 1]
2+++ take-kv |= [k=@t v=@ud] v
3+++ labelled (take-kv pair-pq)
4+++ unfaced (take-kv (unface pair-pq))
5+++ hi-lo ^- [hi=@ud lo=@ud] [10 0]
6+++ want-lo-hi |= r=[lo=@ud hi=@ud] lo.r
7+++ swapped (want-lo-hi hi-lo)
8+++ by-position (want-lo-hi (unface hi-lo))
tests/golden/inline-unface-records/tokens.txtnew file+94
@@ -0,0 +1,94 @@
1+1:1 glyph ++
2+1:4 name pair-pq
3+1:12 glyph ^-
4+1:15 glyph [
5+1:16 tight name p
6+1:17 tight glyph =
7+1:18 tight aura @t
8+1:21 name q
9+1:22 tight glyph =
10+1:23 tight aura @ud
11+1:26 tight glyph ]
12+1:28 glyph [
13+1:29 tight str "a"
14+1:33 lit 1
15+1:34 tight glyph ]
16+2:1 NEWLINE
17+2:1 glyph ++
18+2:4 name take-kv
19+2:12 glyph |=
20+2:15 glyph [
21+2:16 tight name k
22+2:17 tight glyph =
23+2:18 tight aura @t
24+2:21 name v
25+2:22 tight glyph =
26+2:23 tight aura @ud
27+2:26 tight glyph ]
28+2:28 name v
29+3:1 NEWLINE
30+3:1 glyph ++
31+3:4 name labelled
32+3:13 glyph (
33+3:14 tight name take-kv
34+3:22 name pair-pq
35+3:29 tight glyph )
36+4:1 NEWLINE
37+4:1 glyph ++
38+4:4 name unfaced
39+4:12 glyph (
40+4:13 tight name take-kv
41+4:21 glyph (
42+4:22 tight name unface
43+4:29 name pair-pq
44+4:36 tight glyph )
45+4:37 tight glyph )
46+5:1 NEWLINE
47+5:1 glyph ++
48+5:4 name hi-lo
49+5:10 glyph ^-
50+5:13 glyph [
51+5:14 tight name hi
52+5:16 tight glyph =
53+5:17 tight aura @ud
54+5:21 name lo
55+5:23 tight glyph =
56+5:24 tight aura @ud
57+5:27 tight glyph ]
58+5:29 glyph [
59+5:30 tight lit 10
60+5:33 lit 0
61+5:34 tight glyph ]
62+6:1 NEWLINE
63+6:1 glyph ++
64+6:4 name want-lo-hi
65+6:15 glyph |=
66+6:18 name r
67+6:19 tight glyph =
68+6:20 tight glyph [
69+6:21 tight name lo
70+6:23 tight glyph =
71+6:24 tight aura @ud
72+6:28 name hi
73+6:30 tight glyph =
74+6:31 tight aura @ud
75+6:34 tight glyph ]
76+6:36 wing lo.r
77+7:1 NEWLINE
78+7:1 glyph ++
79+7:4 name swapped
80+7:12 glyph (
81+7:13 tight name want-lo-hi
82+7:24 name hi-lo
83+7:29 tight glyph )
84+8:1 NEWLINE
85+8:1 glyph ++
86+8:4 name by-position
87+8:16 glyph (
88+8:17 tight name want-lo-hi
89+8:28 glyph (
90+8:29 tight name unface
91+8:36 name hi-lo
92+8:41 tight glyph )
93+8:42 tight glyph )
94+8:43 NEWLINE
tests/golden/inline-unface-records/tree.txtnew file+44
@@ -0,0 +1,44 @@
1+(module
2+ (value 1:1 pair-pq
3+ (cast 1:12
4+ (cell 1:15
5+ (face 1:16 p (aura 1:18 @t))
6+ (face 1:21 q (aura 1:23 @ud)))
7+ (tuple 1:28 (str 1:29 "a") (lit 1:33 1))))
8+ (value 2:1 take-kv
9+ (gate 2:12
10+ (cell 2:15
11+ (face 2:16 k (aura 2:18 @t))
12+ (face 2:21 v (aura 2:23 @ud)))
13+ (wing 2:28 v)))
14+ (value 3:1 labelled
15+ (group 3:13
16+ (call 3:14 (wing 3:14 take-kv) (wing 3:22 pair-pq))))
17+ (value 4:1 unfaced
18+ (group 4:12
19+ (call 4:13
20+ (wing 4:13 take-kv)
21+ (group 4:21
22+ (call 4:22 (wing 4:22 unface) (wing 4:29 pair-pq))))))
23+ (value 5:1 hi-lo
24+ (cast 5:10
25+ (cell 5:13
26+ (face 5:14 hi (aura 5:17 @ud))
27+ (face 5:21 lo (aura 5:24 @ud)))
28+ (tuple 5:29 (lit 5:30 10) (lit 5:33 0))))
29+ (value 6:1 want-lo-hi
30+ (gate 6:15
31+ (face 6:18 r
32+ (cell 6:20
33+ (face 6:21 lo (aura 6:24 @ud))
34+ (face 6:28 hi (aura 6:31 @ud))))
35+ (wing 6:36 lo.r)))
36+ (value 7:1 swapped
37+ (group 7:12
38+ (call 7:13 (wing 7:13 want-lo-hi) (wing 7:24 hi-lo))))
39+ (value 8:1 by-position
40+ (group 8:16
41+ (call 8:17
42+ (wing 8:17 want-lo-hi)
43+ (group 8:28
44+ (call 8:29 (wing 8:29 unface) (wing 8:36 hi-lo)))))))
tests/golden/inline-unface-records/types.txtnew file+21
@@ -0,0 +1,21 @@
1+partial inference; module not checked
2+++ pair-pq: [p=@t q=@ud]
3+++ take-kv: $-([k=@t v=@ud] @ud)
4+++ labelled: call's sample and argument types do not unify
5+/tests/golden/inline-unface-records/source.jibb:3:14: called gate has type $-([k=@t v=@ud] @ud)
6+++ labelled (take-kv pair-pq)
7+ ^
8+/tests/golden/inline-unface-records/source.jibb:3:22: argument has type [p=@t q=@ud]
9+++ labelled (take-kv pair-pq)
10+ ^
11+++ unfaced: @ud
12+++ hi-lo: [hi=@ud lo=@ud]
13+++ want-lo-hi: $-([lo=@ud hi=@ud] @ud)
14+++ swapped: call's sample and argument types do not unify
15+/tests/golden/inline-unface-records/source.jibb:7:13: called gate has type $-([lo=@ud hi=@ud] @ud)
16+++ swapped (want-lo-hi hi-lo)
17+ ^
18+/tests/golden/inline-unface-records/source.jibb:7:24: argument has type [hi=@ud lo=@ud]
19+++ swapped (want-lo-hi hi-lo)
20+ ^
21+++ by-position: @ud
tests/golden/inline-unface-recursive/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Expressions, Unface: "`(unface e)` is `e` with every face removed from its type"
2+tests: A ++ whose body is (unface |= …) is still a gate: it calls itself, two such gates call each other, and a local one recurses; each name has the unfaced type.
3+expect: parses
4+expect-types: a partial inference report
tests/golden/inline-unface-recursive/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-recursive/source.jibbnew file+23
@@ -0,0 +1,23 @@
1+++ weld2 (unface
2+ |= [xs=(list A) ys=(list A)] ^- (list A)
3+ ?- xs
4+ ~ ys
5+ [item rest] [item (weld2 rest ys)]
6+++ joined (weld2 ~[1] ~[2])
7+++ even (unface
8+ |= n=@ud ^- ?
9+ ?- (eq n 0)
10+ %.y %.y
11+ %.n (odd (dec n))
12+++ odd (unface
13+ |= n=@ud ^- ?
14+ ?- (eq n 0)
15+ %.y %.n
16+ %.n (even (dec n))
17+++ outer |= n=@ud
18+ ++ count (unface
19+ |= [a=@ud b=@ud] ^- @ud
20+ ?- (eq a 0)
21+ %.y b
22+ %.n (count (dec a) b)
23+ (count n 1)
tests/golden/inline-unface-recursive/tokens.txtnew file+182
@@ -0,0 +1,182 @@
1+1:1 glyph ++
2+1:4 name weld2
3+1:10 glyph (
4+1:11 tight name unface
5+2:3 INDENT
6+2:3 glyph |=
7+2:6 glyph [
8+2:7 tight name xs
9+2:9 tight glyph =
10+2:10 tight glyph (
11+2:11 tight name list
12+2:16 tvar A
13+2:17 tight glyph )
14+2:19 name ys
15+2:21 tight glyph =
16+2:22 tight glyph (
17+2:23 tight name list
18+2:28 tvar A
19+2:29 tight glyph )
20+2:30 tight glyph ]
21+2:32 glyph ^-
22+2:35 glyph (
23+2:36 tight name list
24+2:41 tvar A
25+2:42 tight glyph )
26+3:5 INDENT
27+3:5 glyph ?-
28+3:8 name xs
29+4:7 INDENT
30+4:7 lit ~
31+4:9 name ys
32+5:7 NEWLINE
33+5:7 glyph [
34+5:8 tight name item
35+5:13 name rest
36+5:17 tight glyph ]
37+5:19 glyph [
38+5:20 tight name item
39+5:25 glyph (
40+5:26 tight name weld2
41+5:32 name rest
42+5:37 name ys
43+5:39 tight glyph )
44+5:40 tight glyph ]
45+6:1 DEDENT
46+6:1 DEDENT
47+6:1 DEDENT
48+6:1 NEWLINE
49+6:1 glyph ++
50+6:4 name joined
51+6:11 glyph (
52+6:12 tight name weld2
53+6:18 glyph ~[
54+6:20 tight lit 1
55+6:21 tight glyph ]
56+6:23 glyph ~[
57+6:25 tight lit 2
58+6:26 tight glyph ]
59+6:27 tight glyph )
60+7:1 NEWLINE
61+7:1 glyph ++
62+7:4 name even
63+7:9 glyph (
64+7:10 tight name unface
65+8:3 INDENT
66+8:3 glyph |=
67+8:6 name n
68+8:7 tight glyph =
69+8:8 tight aura @ud
70+8:12 glyph ^-
71+8:15 glyph ?
72+9:5 INDENT
73+9:5 glyph ?-
74+9:8 glyph (
75+9:9 tight name eq
76+9:12 name n
77+9:14 lit 0
78+9:15 tight glyph )
79+10:7 INDENT
80+10:7 lit %.y
81+10:11 lit %.y
82+11:7 NEWLINE
83+11:7 lit %.n
84+11:11 glyph (
85+11:12 tight name odd
86+11:16 glyph (
87+11:17 tight name dec
88+11:21 name n
89+11:22 tight glyph )
90+11:23 tight glyph )
91+12:1 DEDENT
92+12:1 DEDENT
93+12:1 DEDENT
94+12:1 NEWLINE
95+12:1 glyph ++
96+12:4 name odd
97+12:8 glyph (
98+12:9 tight name unface
99+13:3 INDENT
100+13:3 glyph |=
101+13:6 name n
102+13:7 tight glyph =
103+13:8 tight aura @ud
104+13:12 glyph ^-
105+13:15 glyph ?
106+14:5 INDENT
107+14:5 glyph ?-
108+14:8 glyph (
109+14:9 tight name eq
110+14:12 name n
111+14:14 lit 0
112+14:15 tight glyph )
113+15:7 INDENT
114+15:7 lit %.y
115+15:11 lit %.n
116+16:7 NEWLINE
117+16:7 lit %.n
118+16:11 glyph (
119+16:12 tight name even
120+16:17 glyph (
121+16:18 tight name dec
122+16:22 name n
123+16:23 tight glyph )
124+16:24 tight glyph )
125+17:1 DEDENT
126+17:1 DEDENT
127+17:1 DEDENT
128+17:1 NEWLINE
129+17:1 glyph ++
130+17:4 name outer
131+17:10 glyph |=
132+17:13 name n
133+17:14 tight glyph =
134+17:15 tight aura @ud
135+18:3 INDENT
136+18:3 glyph ++
137+18:6 name count
138+18:12 glyph (
139+18:13 tight name unface
140+19:5 INDENT
141+19:5 glyph |=
142+19:8 glyph [
143+19:9 tight name a
144+19:10 tight glyph =
145+19:11 tight aura @ud
146+19:15 name b
147+19:16 tight glyph =
148+19:17 tight aura @ud
149+19:20 tight glyph ]
150+19:22 glyph ^-
151+19:25 aura @ud
152+20:7 INDENT
153+20:7 glyph ?-
154+20:10 glyph (
155+20:11 tight name eq
156+20:14 name a
157+20:16 lit 0
158+20:17 tight glyph )
159+21:9 INDENT
160+21:9 lit %.y
161+21:13 name b
162+22:9 NEWLINE
163+22:9 lit %.n
164+22:13 glyph (
165+22:14 tight name count
166+22:20 glyph (
167+22:21 tight name dec
168+22:25 name a
169+22:26 tight glyph )
170+22:28 name b
171+22:29 tight glyph )
172+23:3 DEDENT
173+23:3 DEDENT
174+23:3 DEDENT
175+23:3 NEWLINE
176+23:3 glyph (
177+23:4 tight name count
178+23:10 name n
179+23:12 lit 1
180+23:13 tight glyph )
181+23:14 DEDENT
182+23:14 NEWLINE
tests/golden/inline-unface-recursive/tree.txtnew file+98
@@ -0,0 +1,98 @@
1+(module
2+ (value 1:1 weld2
3+ (group 1:10
4+ (call 1:11
5+ (wing 1:11 unface)
6+ (gate 2:3
7+ (cell 2:6
8+ (face 2:7 xs
9+ (apply 2:10 list (tvar 2:16 A)))
10+ (face 2:19 ys
11+ (apply 2:22 list (tvar 2:28 A))))
12+ (cast 2:32
13+ (apply 2:35 list (tvar 2:41 A))
14+ (body 3:5
15+ (branch 3:5
16+ (wing 3:8 xs)
17+ (arm 4:7 (lit 4:7 ~) (wing 4:9 ys))
18+ (arm 5:7
19+ (cell 5:7 (bind 5:8 item) (bind 5:13 rest))
20+ (tuple 5:19
21+ (wing 5:20 item)
22+ (group 5:25
23+ (call 5:26 (wing 5:26 weld2) (wing 5:32 rest) (wing 5:37 ys))))))))))))
24+ (value 6:1 joined
25+ (group 6:11
26+ (call 6:12
27+ (wing 6:12 weld2)
28+ (list 6:18 (lit 6:20 1))
29+ (list 6:23 (lit 6:25 2)))))
30+ (value 7:1 even
31+ (group 7:9
32+ (call 7:10
33+ (wing 7:10 unface)
34+ (gate 8:3
35+ (face 8:6 n (aura 8:8 @ud))
36+ (cast 8:12
37+ (flag 8:15)
38+ (body 9:5
39+ (branch 9:5
40+ (group 9:8
41+ (call 9:9 (wing 9:9 eq) (wing 9:12 n) (lit 9:14 0)))
42+ (arm 10:7 (lit 10:7 %.y) (lit 10:11 %.y))
43+ (arm 11:7
44+ (lit 11:7 %.n)
45+ (group 11:11
46+ (call 11:12
47+ (wing 11:12 odd)
48+ (group 11:16
49+ (call 11:17 (wing 11:17 dec) (wing 11:21 n)))))))))))))
50+ (value 12:1 odd
51+ (group 12:8
52+ (call 12:9
53+ (wing 12:9 unface)
54+ (gate 13:3
55+ (face 13:6 n (aura 13:8 @ud))
56+ (cast 13:12
57+ (flag 13:15)
58+ (body 14:5
59+ (branch 14:5
60+ (group 14:8
61+ (call 14:9 (wing 14:9 eq) (wing 14:12 n) (lit 14:14 0)))
62+ (arm 15:7 (lit 15:7 %.y) (lit 15:11 %.n))
63+ (arm 16:7
64+ (lit 16:7 %.n)
65+ (group 16:11
66+ (call 16:12
67+ (wing 16:12 even)
68+ (group 16:17
69+ (call 16:18 (wing 16:18 dec) (wing 16:22 n)))))))))))))
70+ (value 17:1 outer
71+ (gate 17:10
72+ (face 17:13 n (aura 17:15 @ud))
73+ (body 18:3
74+ (value 18:3 count
75+ (group 18:12
76+ (call 18:13
77+ (wing 18:13 unface)
78+ (gate 19:5
79+ (cell 19:8
80+ (face 19:9 a (aura 19:11 @ud))
81+ (face 19:15 b (aura 19:17 @ud)))
82+ (cast 19:22
83+ (aura 19:25 @ud)
84+ (body 20:7
85+ (branch 20:7
86+ (group 20:10
87+ (call 20:11 (wing 20:11 eq) (wing 20:14 a) (lit 20:16 0)))
88+ (arm 21:9 (lit 21:9 %.y) (wing 21:13 b))
89+ (arm 22:9
90+ (lit 22:9 %.n)
91+ (group 22:13
92+ (call 22:14
93+ (wing 22:14 count)
94+ (group 22:20
95+ (call 22:21 (wing 22:21 dec) (wing 22:25 a)))
96+ (wing 22:28 b)))))))))))
97+ (group 23:3
98+ (call 23:4 (wing 23:4 count) (wing 23:10 n) (lit 23:12 1)))))))
tests/golden/inline-unface-recursive/types.txtnew file+6
@@ -0,0 +1,6 @@
1+partial inference; module not checked
2+++ weld2: $-([(list A) (list A)] (list A))
3+++ joined: (list @ud)
4+++ even: $-(@ud ?)
5+++ odd: $-(@ud ?)
6+++ outer: $-(@ud @ud)
tests/golden/inline-unface-reserved-import/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Modules: "`proj` and `unface` are reserved: no module can define, import or bind either, as a value or a mold"
2+tests: A Jibb import face named unface is rejected.
3+expect: parses
4+expect-types: a partial inference report: the module has conflicting names
tests/golden/inline-unface-reserved-import/module-trees.txtnew file+6
@@ -0,0 +1,6 @@
1+/ui/lib.jibb
2+(module
3+ (value 1:1 identity
4+ (gate 1:13
5+ (face 1:16 x (aura 1:18 @t))
6+ (wing 1:21 x))))
tests/golden/inline-unface-reserved-import/modules.txtnew file+1
@@ -0,0 +1 @@
1+/ui/lib.jibb
tests/golden/inline-unface-reserved-import/modules/ui/lib.jibbnew file+1
@@ -0,0 +1 @@
1+++ identity |= x=@t x
tests/golden/inline-unface-reserved-import/source.jibbnew file+2
@@ -0,0 +1,2 @@
1+/= unface /ui/lib
2+++ okay "ok"
tests/golden/inline-unface-reserved-import/tokens.txtnew file+11
@@ -0,0 +1,11 @@
1+1:1 glyph /=
2+1:4 name unface
3+1:11 glyph /
4+1:12 tight knot ui
5+1:14 tight glyph /
6+1:15 tight knot lib
7+2:1 NEWLINE
8+2:1 glyph ++
9+2:4 name okay
10+2:9 str "ok"
11+2:13 NEWLINE
tests/golden/inline-unface-reserved-import/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+(module
2+ (jibb 1:1 unface /ui/lib)
3+ (value 2:1 okay (str 2:9 "ok")))
tests/golden/inline-unface-reserved-import/types.txtnew file+2
@@ -0,0 +1,2 @@
1+partial inference; module not checked
2+module has conflicting names
tests/golden/inline-unface-reserved-local/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Modules: "`proj` and `unface` are reserved: no module can define, import or bind either, as a value or a mold"
2+tests: A local value named unface is rejected.
3+expect: parses
4+expect-types: a partial inference report: the module has conflicting names
tests/golden/inline-unface-reserved-local/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-reserved-local/source.jibbnew file+3
@@ -0,0 +1,3 @@
1+++ okay
2+ ++ unface |= x=@t x
3+ "ok"
tests/golden/inline-unface-reserved-local/tokens.txtnew file+14
@@ -0,0 +1,14 @@
1+1:1 glyph ++
2+1:4 name okay
3+2:3 INDENT
4+2:3 glyph ++
5+2:6 name unface
6+2:13 glyph |=
7+2:16 name x
8+2:17 tight glyph =
9+2:18 tight aura @t
10+2:21 name x
11+3:3 NEWLINE
12+3:3 str "ok"
13+3:7 DEDENT
14+3:7 NEWLINE
tests/golden/inline-unface-reserved-local/tree.txtnew file+8
@@ -0,0 +1,8 @@
1+(module
2+ (value 1:1 okay
3+ (body 2:3
4+ (value 2:3 unface
5+ (gate 2:13
6+ (face 2:16 x (aura 2:18 @t))
7+ (wing 2:21 x)))
8+ (str 3:3 "ok"))))
tests/golden/inline-unface-reserved-local/types.txtnew file+2
@@ -0,0 +1,2 @@
1+partial inference; module not checked
2+module has conflicting names
tests/golden/inline-unface-reserved-mold/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Modules: "`proj` and `unface` are reserved: no module can define, import or bind either, as a value or a mold"
2+tests: A mold named unface is rejected, even unused.
3+expect: parses
4+expect-types: a partial inference report: the module has conflicting names
tests/golden/inline-unface-reserved-mold/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-reserved-mold/source.jibbnew file+2
@@ -0,0 +1,2 @@
1++$ unface @t
2+++ okay "ok"
tests/golden/inline-unface-reserved-mold/tokens.txtnew file+8
@@ -0,0 +1,8 @@
1+1:1 glyph +$
2+1:4 name unface
3+1:11 aura @t
4+2:1 NEWLINE
5+2:1 glyph ++
6+2:4 name okay
7+2:9 str "ok"
8+2:13 NEWLINE
tests/golden/inline-unface-reserved-mold/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+(module
2+ (mold 1:1 unface (aura 1:11 @t))
3+ (value 2:1 okay (str 2:9 "ok")))
tests/golden/inline-unface-reserved-mold/types.txtnew file+2
@@ -0,0 +1,2 @@
1+partial inference; module not checked
2+module has conflicting names
tests/golden/inline-unface-reserved-no-prelude/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Modules: "`proj` and `unface` are reserved: no module can define, import or bind either, as a value or a mold"
2+tests: Without the prelude, the report names the reserved names.
3+expect: parses
4+expect-types: the report says the module has a reserved name
tests/golden/inline-unface-reserved-no-prelude/source.jibbnew file+2
@@ -0,0 +1,2 @@
1++$ unface @t
2+++ okay "ok"
tests/golden/inline-unface-reserved-no-prelude/tokens.txtnew file+8
@@ -0,0 +1,8 @@
1+1:1 glyph +$
2+1:4 name unface
3+1:11 aura @t
4+2:1 NEWLINE
5+2:1 glyph ++
6+2:4 name okay
7+2:9 str "ok"
8+2:13 NEWLINE
tests/golden/inline-unface-reserved-no-prelude/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+(module
2+ (mold 1:1 unface (aura 1:11 @t))
3+ (value 2:1 okay (str 2:9 "ok")))
tests/golden/inline-unface-reserved-no-prelude/types.txtnew file+1
@@ -0,0 +1 @@
1+module has a reserved proj or unface name
tests/golden/inline-unface-reserved-pattern/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Modules: "`proj` and `unface` are reserved: no module can define, import or bind either, as a value or a mold"
2+tests: A branch pattern cannot bind unface.
3+expect: parses
4+expect-types: a partial inference report: the module has conflicting names
tests/golden/inline-unface-reserved-pattern/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-reserved-pattern/source.jibbnew file+3
@@ -0,0 +1,3 @@
1+++ okay |= x=[@t @p]
2+ ?- x
3+ [unface other] other
tests/golden/inline-unface-reserved-pattern/tokens.txtnew file+21
@@ -0,0 +1,21 @@
1+1:1 glyph ++
2+1:4 name okay
3+1:9 glyph |=
4+1:12 name x
5+1:13 tight glyph =
6+1:14 tight glyph [
7+1:15 tight aura @t
8+1:18 aura @p
9+1:20 tight glyph ]
10+2:3 INDENT
11+2:3 glyph ?-
12+2:6 name x
13+3:5 INDENT
14+3:5 glyph [
15+3:6 tight name unface
16+3:13 name other
17+3:18 tight glyph ]
18+3:20 name other
19+3:25 DEDENT
20+3:25 DEDENT
21+3:25 NEWLINE
tests/golden/inline-unface-reserved-pattern/tree.txtnew file+11
@@ -0,0 +1,11 @@
1+(module
2+ (value 1:1 okay
3+ (gate 1:9
4+ (face 1:12 x
5+ (cell 1:14 (aura 1:15 @t) (aura 1:18 @p)))
6+ (body 2:3
7+ (branch 2:3
8+ (wing 2:6 x)
9+ (arm 3:5
10+ (cell 3:5 (bind 3:6 unface) (bind 3:13 other))
11+ (wing 3:20 other)))))))
tests/golden/inline-unface-reserved-pattern/types.txtnew file+2
@@ -0,0 +1,2 @@
1+partial inference; module not checked
2+module has conflicting names
tests/golden/inline-unface-reserved-positive/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Modules: "`proj` and `unface` are reserved: no module can define, import or bind either, as a value or a mold"
2+tests: A field label, a tag and a longer name spelled with unface stay free, beside a normal unface call.
3+expect: parses
4+expect-types: a partial inference report
tests/golden/inline-unface-reserved-positive/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-reserved-positive/source.jibbnew file+6
@@ -0,0 +1,6 @@
1++$ action
2+ %unface
3+ %other
4+++ unfaced |= x=[unface=@t other=@p] unface.x
5+++ tag ^- action %unface
6+++ plain (unface unfaced)
tests/golden/inline-unface-reserved-positive/tokens.txtnew file+36
@@ -0,0 +1,36 @@
1+1:1 glyph +$
2+1:4 name action
3+2:3 INDENT
4+2:3 lit %unface
5+3:3 NEWLINE
6+3:3 lit %other
7+4:1 DEDENT
8+4:1 NEWLINE
9+4:1 glyph ++
10+4:4 name unfaced
11+4:12 glyph |=
12+4:15 name x
13+4:16 tight glyph =
14+4:17 tight glyph [
15+4:18 tight name unface
16+4:24 tight glyph =
17+4:25 tight aura @t
18+4:28 name other
19+4:33 tight glyph =
20+4:34 tight aura @p
21+4:36 tight glyph ]
22+4:38 wing unface.x
23+5:1 NEWLINE
24+5:1 glyph ++
25+5:4 name tag
26+5:8 glyph ^-
27+5:11 name action
28+5:18 lit %unface
29+6:1 NEWLINE
30+6:1 glyph ++
31+6:4 name plain
32+6:10 glyph (
33+6:11 tight name unface
34+6:18 name unfaced
35+6:25 tight glyph )
36+6:26 NEWLINE
tests/golden/inline-unface-reserved-positive/tree.txtnew file+15
@@ -0,0 +1,15 @@
1+(module
2+ (mold 1:1 action
3+ (union 2:3 (const 2:3 %unface) (const 3:3 %other)))
4+ (value 4:1 unfaced
5+ (gate 4:12
6+ (face 4:15 x
7+ (cell 4:17
8+ (face 4:18 unface (aura 4:25 @t))
9+ (face 4:28 other (aura 4:34 @p))))
10+ (wing 4:38 unface.x)))
11+ (value 5:1 tag
12+ (cast 5:8 (ref 5:11 action) (lit 5:18 %unface)))
13+ (value 6:1 plain
14+ (group 6:10
15+ (call 6:11 (wing 6:11 unface) (wing 6:18 unfaced)))))
tests/golden/inline-unface-reserved-positive/types.txtnew file+5
@@ -0,0 +1,5 @@
1+partial inference; module not checked
2++$ action: cases proven disjoint; mold not checked
3+++ unfaced: $-([unface=@t other=@p] @t)
4+++ tag: action
5+++ plain: $-([@t @p] @t)
tests/golden/inline-unface-reserved-sample/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Modules: "`proj` and `unface` are reserved: no module can define, import or bind either, as a value or a mold"
2+tests: A gate sample cannot bind unface, alone or inside a cell.
3+expect: parses
4+expect-types: a partial inference report: the module has conflicting names
tests/golden/inline-unface-reserved-sample/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-reserved-sample/source.jibbnew file+1
@@ -0,0 +1 @@
1+++ okay |= [unface=@t other=@p] other
tests/golden/inline-unface-reserved-sample/tokens.txtnew file+13
@@ -0,0 +1,13 @@
1+1:1 glyph ++
2+1:4 name okay
3+1:9 glyph |=
4+1:12 glyph [
5+1:13 tight name unface
6+1:19 tight glyph =
7+1:20 tight aura @t
8+1:23 name other
9+1:28 tight glyph =
10+1:29 tight aura @p
11+1:31 tight glyph ]
12+1:33 name other
13+1:38 NEWLINE
tests/golden/inline-unface-reserved-sample/tree.txtnew file+7
@@ -0,0 +1,7 @@
1+(module
2+ (value 1:1 okay
3+ (gate 1:9
4+ (cell 1:12
5+ (face 1:13 unface (aura 1:20 @t))
6+ (face 1:23 other (aura 1:29 @p)))
7+ (wing 1:33 other))))
tests/golden/inline-unface-reserved-sample/types.txtnew file+2
@@ -0,0 +1,2 @@
1+partial inference; module not checked
2+module has conflicting names
tests/golden/inline-unface-reserved-value/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Modules: "`proj` and `unface` are reserved: no module can define, import or bind either, as a value or a mold"
2+tests: A top-level value named unface is rejected.
3+expect: parses
4+expect-types: a partial inference report: the module has conflicting names
tests/golden/inline-unface-reserved-value/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-reserved-value/source.jibbnew file+2
@@ -0,0 +1,2 @@
1+++ unface |= x=@t x
2+++ okay "ok"
tests/golden/inline-unface-reserved-value/tokens.txtnew file+12
@@ -0,0 +1,12 @@
1+1:1 glyph ++
2+1:4 name unface
3+1:11 glyph |=
4+1:14 name x
5+1:15 tight glyph =
6+1:16 tight aura @t
7+1:19 name x
8+2:1 NEWLINE
9+2:1 glyph ++
10+2:4 name okay
11+2:9 str "ok"
12+2:13 NEWLINE
tests/golden/inline-unface-reserved-value/tree.txtnew file+6
@@ -0,0 +1,6 @@
1+(module
2+ (value 1:1 unface
3+ (gate 1:11
4+ (face 1:14 x (aura 1:16 @t))
5+ (wing 1:19 x)))
6+ (value 2:1 okay (str 2:9 "ok")))
tests/golden/inline-unface-reserved-value/types.txtnew file+2
@@ -0,0 +1,2 @@
1+partial inference; module not checked
2+module has conflicting names
tests/golden/inline-unface-unknown/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Expressions, Unface: "Like `proj`, it is an operation the checker handles by type, not a gate"
2+tests: unface on a type not yet known, a sample with no mold, would wait as wing access does; the partial checker reports it as unsupported, as it does field access, and a sample with a mold infers.
3+expect: parses
4+expect-types: a partial inference report: the untyped sample is unsupported
tests/golden/inline-unface-unknown/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-unknown/source.jibbnew file+3
@@ -0,0 +1,3 @@
1+++ later |= f (unface f)
2+++ get-label |= r label.r
3+++ known |= f=$-([a=@ud b=@ud] ?) (unface f)
tests/golden/inline-unface-unknown/tokens.txtnew file+36
@@ -0,0 +1,36 @@
1+1:1 glyph ++
2+1:4 name later
3+1:10 glyph |=
4+1:13 name f
5+1:15 glyph (
6+1:16 tight name unface
7+1:23 name f
8+1:24 tight glyph )
9+2:1 NEWLINE
10+2:1 glyph ++
11+2:4 name get-label
12+2:14 glyph |=
13+2:17 name r
14+2:19 wing label.r
15+3:1 NEWLINE
16+3:1 glyph ++
17+3:4 name known
18+3:10 glyph |=
19+3:13 name f
20+3:14 tight glyph =
21+3:15 tight glyph $-(
22+3:18 tight glyph [
23+3:19 tight name a
24+3:20 tight glyph =
25+3:21 tight aura @ud
26+3:25 name b
27+3:26 tight glyph =
28+3:27 tight aura @ud
29+3:30 tight glyph ]
30+3:32 glyph ?
31+3:33 tight glyph )
32+3:35 glyph (
33+3:36 tight name unface
34+3:43 name f
35+3:44 tight glyph )
36+3:45 NEWLINE
tests/golden/inline-unface-unknown/tree.txtnew file+18
@@ -0,0 +1,18 @@
1+(module
2+ (value 1:1 later
3+ (gate 1:10
4+ (bind 1:13 f)
5+ (group 1:15
6+ (call 1:16 (wing 1:16 unface) (wing 1:23 f)))))
7+ (value 2:1 get-label
8+ (gate 2:14 (bind 2:17 r) (wing 2:19 label.r)))
9+ (value 3:1 known
10+ (gate 3:10
11+ (face 3:13 f
12+ (fn 3:15
13+ (cell 3:18
14+ (face 3:19 a (aura 3:21 @ud))
15+ (face 3:25 b (aura 3:27 @ud)))
16+ (flag 3:32)))
17+ (group 3:35
18+ (call 3:36 (wing 3:36 unface) (wing 3:43 f))))))
tests/golden/inline-unface-unknown/types.txtnew file+4
@@ -0,0 +1,4 @@
1+partial inference; module not checked
2+++ later: unface on a type not yet known is not supported by partial inference
3+++ get-label: field is not available to partial inference
4+++ known: $-($-([a=@ud b=@ud] ?) $-([@ud @ud] ?))
tests/golden/inline-unface-value-bad/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: docs/spec/grammar.md, Expressions, Unface: "Like `proj`, it is an operation the checker handles by type, not a gate"
2+tests: unface written where a value goes, alone or as a gate's argument, is an error that suggests a lambda; the lambda itself hits the partial checker's gap for a sample whose type the call fixes, and a typed sample infers.
3+expect: parses
4+expect-types: a partial inference report: the bare uses are errors at the name, and the untyped lambda is unsupported
tests/golden/inline-unface-value-bad/modules.txtnew file+1
@@ -0,0 +1 @@
1+# Use source-backed prelude.
tests/golden/inline-unface-value-bad/source.jibbnew file+6
@@ -0,0 +1,6 @@
1+++ lt-a |= [a=@ud b=@ud] (gth b a)
2+++ gates ~[lt-a]
3+++ alias unface
4+++ mapped (turn gates unface)
5+++ wrapped (turn gates |=(g (unface g)))
6+++ typed (turn gates |=(g=$-([a=@ud b=@ud] ?) (unface g)))
tests/golden/inline-unface-value-bad/tokens.txtnew file+75
@@ -0,0 +1,75 @@
1+1:1 glyph ++
2+1:4 name lt-a
3+1:9 glyph |=
4+1:12 glyph [
5+1:13 tight name a
6+1:14 tight glyph =
7+1:15 tight aura @ud
8+1:19 name b
9+1:20 tight glyph =
10+1:21 tight aura @ud
11+1:24 tight glyph ]
12+1:26 glyph (
13+1:27 tight name gth
14+1:31 name b
15+1:33 name a
16+1:34 tight glyph )
17+2:1 NEWLINE
18+2:1 glyph ++
19+2:4 name gates
20+2:10 glyph ~[
21+2:12 tight name lt-a
22+2:16 tight glyph ]
23+3:1 NEWLINE
24+3:1 glyph ++
25+3:4 name alias
26+3:10 name unface
27+4:1 NEWLINE
28+4:1 glyph ++
29+4:4 name mapped
30+4:11 glyph (
31+4:12 tight name turn
32+4:17 name gates
33+4:23 name unface
34+4:29 tight glyph )
35+5:1 NEWLINE
36+5:1 glyph ++
37+5:4 name wrapped
38+5:12 glyph (
39+5:13 tight name turn
40+5:18 name gates
41+5:24 glyph |=(
42+5:27 tight name g
43+5:29 glyph (
44+5:30 tight name unface
45+5:37 name g
46+5:38 tight glyph )
47+5:39 tight glyph )
48+5:40 tight glyph )
49+6:1 NEWLINE
50+6:1 glyph ++
51+6:4 name typed
52+6:10 glyph (
53+6:11 tight name turn
54+6:16 name gates
55+6:22 glyph |=(
56+6:25 tight name g
57+6:26 tight glyph =
58+6:27 tight glyph $-(
59+6:30 tight glyph [
60+6:31 tight name a
61+6:32 tight glyph =
62+6:33 tight aura @ud
63+6:37 name b
64+6:38 tight glyph =
65+6:39 tight aura @ud
66+6:42 tight glyph ]
67+6:44 glyph ?
68+6:45 tight glyph )
69+6:47 glyph (
70+6:48 tight name unface
71+6:55 name g
72+6:56 tight glyph )
73+6:57 tight glyph )
74+6:58 tight glyph )
75+6:59 NEWLINE
tests/golden/inline-unface-value-bad/tree.txtnew file+37
@@ -0,0 +1,37 @@
1+(module
2+ (value 1:1 lt-a
3+ (gate 1:9
4+ (cell 1:12
5+ (face 1:13 a (aura 1:15 @ud))
6+ (face 1:19 b (aura 1:21 @ud)))
7+ (group 1:26
8+ (call 1:27 (wing 1:27 gth) (wing 1:31 b) (wing 1:33 a)))))
9+ (value 2:1 gates
10+ (list 2:10 (wing 2:12 lt-a)))
11+ (value 3:1 alias (wing 3:10 unface))
12+ (value 4:1 mapped
13+ (group 4:11
14+ (call 4:12 (wing 4:12 turn) (wing 4:17 gates) (wing 4:23 unface))))
15+ (value 5:1 wrapped
16+ (group 5:12
17+ (call 5:13
18+ (wing 5:13 turn)
19+ (wing 5:18 gates)
20+ (gate-wide 5:24
21+ (bind 5:27 g)
22+ (group 5:29
23+ (call 5:30 (wing 5:30 unface) (wing 5:37 g)))))))
24+ (value 6:1 typed
25+ (group 6:10
26+ (call 6:11
27+ (wing 6:11 turn)
28+ (wing 6:16 gates)
29+ (gate-wide 6:22
30+ (face 6:25 g
31+ (fn 6:27
32+ (cell 6:30
33+ (face 6:31 a (aura 6:33 @ud))
34+ (face 6:37 b (aura 6:39 @ud)))
35+ (flag 6:44)))
36+ (group 6:47
37+ (call 6:48 (wing 6:48 unface) (wing 6:55 g))))))))
tests/golden/inline-unface-value-bad/types.txtnew file+13
@@ -0,0 +1,13 @@
1+partial inference; module not checked
2+++ lt-a: $-([a=@ud b=@ud] ?)
3+++ gates: (list $-([a=@ud b=@ud] ?))
4+++ alias: unface is not a value; write |=(g (unface g))
5+/tests/golden/inline-unface-value-bad/source.jibb:3:10: unface used as a value
6+++ alias unface
7+ ^
8+++ mapped: unface is not a value; write |=(g (unface g))
9+/tests/golden/inline-unface-value-bad/source.jibb:4:23: unface used as a value
10+++ mapped (turn gates unface)
11+ ^
12+++ wrapped: unface on a type not yet known is not supported by partial inference
13+++ typed: (list $-([@ud @ud] ?))
tests/golden/lex-body-rest-bad-1/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes, The rest of a body: "This doesn't apply on a `?-` arm's line, on a line of an open bracket, after a bracket opened earlier on the line (the subject's included), at the top level, or to a definition's own expression."
2+tests: a local definition's own expression, a gate whose body would be the line below at the same depth
3+expect: error at 3:3 — a definition's own expression never takes the rest of a body, so the gate needs its body on its line or deeper; line 3 is at the same depth
tests/golden/lex-body-rest-bad-1/source.jibbnew file+4
@@ -0,0 +1,4 @@
1+++ f |= x=@ud
2+ ++ inner |= y=@ud
3+ (add y 1)
4+ (inner x)
tests/golden/lex-body-rest-bad-1/tokens.txtnew file+26
@@ -0,0 +1,26 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name x
5+1:10 tight glyph =
6+1:11 tight aura @ud
7+2:3 INDENT
8+2:3 glyph ++
9+2:6 name inner
10+2:12 glyph |=
11+2:15 name y
12+2:16 tight glyph =
13+2:17 tight aura @ud
14+3:3 NEWLINE
15+3:3 glyph (
16+3:4 tight name add
17+3:8 name y
18+3:10 lit 1
19+3:11 tight glyph )
20+4:3 NEWLINE
21+4:3 glyph (
22+4:4 tight name inner
23+4:10 name x
24+4:11 tight glyph )
25+4:12 DEDENT
26+4:12 NEWLINE
tests/golden/lex-body-rest-bad-1/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-1/source.jibb:3:3: expected an expression, or a body on deeper lines, found a line at the same depth
2+ (add y 1)
3+ ^
tests/golden/lex-body-rest-bad-10/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes: "`?-` **wuthep**: … A `?-` that begins a body's final line may instead take its arms at its own depth, to the end of the body. A `?-` takes all its arms deeper or all at its own depth."; the EBNF: `last = … | "?-" expr NEWLINE arm { NEWLINE arm } ;`
2+tests: a `?-` with one arm deeper and the next at its own depth, on the final line of a cast's rest
3+expect: error at 5:3 — a ?- takes all its arms deeper or all at its own depth, and this one's first arm is deeper, so the hint says the next goes there too
tests/golden/lex-body-rest-bad-10/source.jibbnew file+5
@@ -0,0 +1,5 @@
1+++ f |= x=?
2+ ^- @ud
3+ ?- x
4+ %.y 1
5+ %.n 2
tests/golden/lex-body-rest-bad-10/tokens.txtnew file+21
@@ -0,0 +1,21 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name x
5+1:10 tight glyph =
6+1:11 tight glyph ?
7+2:3 INDENT
8+2:3 glyph ^-
9+2:6 aura @ud
10+3:3 NEWLINE
11+3:3 glyph ?-
12+3:6 name x
13+4:5 INDENT
14+4:5 lit %.y
15+4:9 lit 1
16+5:3 DEDENT
17+5:3 NEWLINE
18+5:3 lit %.n
19+5:7 lit 2
20+5:8 DEDENT
21+5:8 NEWLINE
tests/golden/lex-body-rest-bad-10/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-10/source.jibb:5:3: expected the end of the body, found a line at the same depth; this `?-`'s arms are on deeper lines, so this one goes there too
2+ %.n 2
3+ ^
tests/golden/lex-body-rest-bad-11/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes: "`?-` **wuthep**: … A `?-` that begins a body's final line may instead take its arms at its own depth, to the end of the body. A `?-` takes all its arms deeper or all at its own depth."; the EBNF: `last = … | "?-" expr NEWLINE arm { NEWLINE arm } ;`
2+tests: a `?-` with one arm at its own depth and the next deeper
3+expect: error at 4:5 — a ?- takes all its arms deeper or all at its own depth; after an arm at its depth that ends its line, a deeper line goes to nothing
tests/golden/lex-body-rest-bad-11/source.jibbnew file+4
@@ -0,0 +1,4 @@
1+++ f |= x=?
2+ ?- x
3+ %.y 1
4+ %.n 2
tests/golden/lex-body-rest-bad-11/tokens.txtnew file+18
@@ -0,0 +1,18 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name x
5+1:10 tight glyph =
6+1:11 tight glyph ?
7+2:3 INDENT
8+2:3 glyph ?-
9+2:6 name x
10+3:3 NEWLINE
11+3:3 lit %.y
12+3:7 lit 1
13+4:5 INDENT
14+4:5 lit %.n
15+4:9 lit 2
16+4:10 DEDENT
17+4:10 DEDENT
18+4:10 NEWLINE
tests/golden/lex-body-rest-bad-11/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-11/source.jibb:4:5: expected the end of the line, found a deeper line; only a bracket open at the end of a line, or a rune's body, takes deeper lines
2+ %.n 2
3+ ^
tests/golden/lex-body-rest-bad-12/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes: "`?-` **wuthep**: … A `?-` that begins a body's final line may instead take its arms at its own depth, to the end of the body. A `?-` takes all its arms deeper or all at its own depth."; the EBNF: `last = … | "?-" expr NEWLINE arm { NEWLINE arm } ;`
2+tests: a local definition after a `?-`'s arms at its depth
3+expect: error at 5:3 — a line at the arms' depth is the next arm, and a definition is no pattern; the hint says a body's local definitions come first
tests/golden/lex-body-rest-bad-12/source.jibbnew file+5
@@ -0,0 +1,5 @@
1+++ f |= x=?
2+ ?- x
3+ %.y 1
4+ %.n 2
5+ ++ g 3
tests/golden/lex-body-rest-bad-12/tokens.txtnew file+21
@@ -0,0 +1,21 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name x
5+1:10 tight glyph =
6+1:11 tight glyph ?
7+2:3 INDENT
8+2:3 glyph ?-
9+2:6 name x
10+3:3 NEWLINE
11+3:3 lit %.y
12+3:7 lit 1
13+4:3 NEWLINE
14+4:3 lit %.n
15+4:7 lit 2
16+5:3 NEWLINE
17+5:3 glyph ++
18+5:6 name g
19+5:8 lit 3
20+5:9 DEDENT
21+5:9 NEWLINE
tests/golden/lex-body-rest-bad-12/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-12/source.jibb:5:3: expected a pattern, found `++`; a body's local definitions come before its final expression
2+ ++ g 3
3+ ^
tests/golden/lex-body-rest-bad-13/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes: "`?-` **wuthep**: … A `?-` that begins a body's final line may instead take its arms at its own depth, to the end of the body. A `?-` takes all its arms deeper or all at its own depth."; the EBNF: `last = … | "?-" expr NEWLINE arm { NEWLINE arm } ;`
2+tests: a trace where an arm of a `?-` with its arms at its depth goes
3+expect: error at 3:4 — a line at the arms' depth is an arm, and `~&` is no pattern; the error points just past the ~, which alone is the null pattern, and the hint says a trace goes in the arm's body
tests/golden/lex-body-rest-bad-13/source.jibbnew file+5
@@ -0,0 +1,5 @@
1+++ f |= x=?
2+ ?- x
3+ ~& x
4+ %.y 1
5+ %.n 2
tests/golden/lex-body-rest-bad-13/tokens.txtnew file+20
@@ -0,0 +1,20 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name x
5+1:10 tight glyph =
6+1:11 tight glyph ?
7+2:3 INDENT
8+2:3 glyph ?-
9+2:6 name x
10+3:3 NEWLINE
11+3:3 glyph ~&
12+3:6 name x
13+4:3 NEWLINE
14+4:3 lit %.y
15+4:7 lit 1
16+5:3 NEWLINE
17+5:3 lit %.n
18+5:7 lit 2
19+5:8 DEDENT
20+5:8 NEWLINE
tests/golden/lex-body-rest-bad-13/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-13/source.jibb:3:4: expected a pattern, found `~&`; a trace or cast goes in the arm's body
2+ ~& x
3+ ^
tests/golden/lex-body-rest-bad-14/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes: "`?-` **wuthep**: … A `?-` that begins a body's final line may instead take its arms at its own depth, to the end of the body. A `?-` takes all its arms deeper or all at its own depth."; the EBNF: `last = … | "?-" expr NEWLINE arm { NEWLINE arm } ;`
2+tests: a cast where an arm of a `?-` with its arms at its depth goes
3+expect: error at 4:3 — a line at the arms' depth is an arm, and `^-` is no pattern; the hint says a cast goes in the arm's body
tests/golden/lex-body-rest-bad-14/source.jibbnew file+5
@@ -0,0 +1,5 @@
1+++ f |= x=?
2+ ?- x
3+ %.y 1
4+ ^- @ud
5+ %.n 2
tests/golden/lex-body-rest-bad-14/tokens.txtnew file+20
@@ -0,0 +1,20 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name x
5+1:10 tight glyph =
6+1:11 tight glyph ?
7+2:3 INDENT
8+2:3 glyph ?-
9+2:6 name x
10+3:3 NEWLINE
11+3:3 lit %.y
12+3:7 lit 1
13+4:3 NEWLINE
14+4:3 glyph ^-
15+4:6 aura @ud
16+5:3 NEWLINE
17+5:3 lit %.n
18+5:7 lit 2
19+5:8 DEDENT
20+5:8 NEWLINE
tests/golden/lex-body-rest-bad-14/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-14/source.jibb:4:3: expected a pattern, found `^-`; a trace or cast goes in the arm's body
2+ ^- @ud
3+ ^
tests/golden/lex-body-rest-bad-15/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes: "`?-` **wuthep**: … A `?-` that begins a body's final line may instead take its arms at its own depth, to the end of the body. A `?-` takes all its arms deeper or all at its own depth."; the EBNF: `last = … | "?-" expr NEWLINE arm { NEWLINE arm } ;`
2+tests: Hoon's closer `==` at the column of a `?-` whose arms are at its depth
3+expect: error at 5:3 — the line is read as an arm, and the lexer's message about `==` says more than "expected a pattern"
tests/golden/lex-body-rest-bad-15/source.jibbnew file+5
@@ -0,0 +1,5 @@
1+++ f |= x=?
2+ ?- x
3+ %.y 1
4+ %.n 2
5+ ==
tests/golden/lex-body-rest-bad-15/tokens.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-15/source.jibb:5:4: the closer `==` is left out: indentation covers it
2+ ==
3+ ^
tests/golden/lex-body-rest-bad-15/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-15/source.jibb:5:3: expected a pattern, found `=`; the closer `==` is left out: indentation covers it
2+ ==
3+ ^
tests/golden/lex-body-rest-bad-16/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes, The rest of a body: "This doesn't apply on a `?-` arm's line, on a line of an open bracket, after a bracket opened earlier on the line (the subject's included), at the top level, or to a definition's own expression."
2+tests: a cast after a `(` opened earlier on its line, alone there, with its expression on the next line at the same depth
3+expect: error at 3:3 — inside the ( no rune takes the lines after it, so the cast needs its expression on its line or deeper
tests/golden/lex-body-rest-bad-16/source.jibbnew file+3
@@ -0,0 +1,3 @@
1+++ f |= x=@ud
2+ (^- @ud
3+ x)
tests/golden/lex-body-rest-bad-16/tokens.txtnew file+15
@@ -0,0 +1,15 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name x
5+1:10 tight glyph =
6+1:11 tight aura @ud
7+2:3 INDENT
8+2:3 glyph (
9+2:4 tight glyph ^-
10+2:7 aura @ud
11+3:3 NEWLINE
12+3:3 name x
13+3:4 tight glyph )
14+3:5 DEDENT
15+3:5 NEWLINE
tests/golden/lex-body-rest-bad-16/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-16/source.jibb:3:3: expected an expression, or a body on deeper lines, found a line at the same depth
2+ x)
3+ ^
tests/golden/lex-body-rest-bad-2/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes, The rest of a body: "This doesn't apply on a `?-` arm's line, on a line of an open bracket, after a bracket opened earlier on the line (the subject's included), at the top level, or to a definition's own expression."
2+tests: a `?-` on an arm's line, inside a `?-` whose arms are at its depth
3+expect: error at 4:3 — a ?- on an arm's line keeps its arms deeper, since the next line at the arm's depth is the outer ?-'s next arm
tests/golden/lex-body-rest-bad-2/source.jibbnew file+5
@@ -0,0 +1,5 @@
1+++ f |= p=[? ?]
2+ ?- p
3+ [a b] ?- a
4+ %.y 1
5+ %.n 2
tests/golden/lex-body-rest-bad-2/tokens.txtnew file+27
@@ -0,0 +1,27 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name p
5+1:10 tight glyph =
6+1:11 tight glyph [
7+1:12 tight glyph ?
8+1:14 glyph ?
9+1:15 tight glyph ]
10+2:3 INDENT
11+2:3 glyph ?-
12+2:6 name p
13+3:3 NEWLINE
14+3:3 glyph [
15+3:4 tight name a
16+3:6 name b
17+3:7 tight glyph ]
18+3:9 glyph ?-
19+3:12 name a
20+4:3 NEWLINE
21+4:3 lit %.y
22+4:7 lit 1
23+5:3 NEWLINE
24+5:3 lit %.n
25+5:7 lit 2
26+5:8 DEDENT
27+5:8 NEWLINE
tests/golden/lex-body-rest-bad-2/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-2/source.jibb:4:3: expected `?-`'s arms on deeper lines, found a line at the same depth
2+ %.y 1
3+ ^
tests/golden/lex-body-rest-bad-3/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes, The rest of a body: "This doesn't apply on a `?-` arm's line, on a line of an open bracket, after a bracket opened earlier on the line (the subject's included), at the top level, or to a definition's own expression."
2+tests: a `?-` that ends a chain on one line, after `^- @ud`, with its arms at the line's depth
3+expect: error at 3:3 — only a ?- that begins a body's final line takes its arms at its depth; after a rune on the line its arms go deeper
tests/golden/lex-body-rest-bad-3/source.jibbnew file+4
@@ -0,0 +1,4 @@
1+++ f |= x=?
2+ ^- @ud ?- x
3+ %.y 1
4+ %.n 2
tests/golden/lex-body-rest-bad-3/tokens.txtnew file+19
@@ -0,0 +1,19 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name x
5+1:10 tight glyph =
6+1:11 tight glyph ?
7+2:3 INDENT
8+2:3 glyph ^-
9+2:6 aura @ud
10+2:10 glyph ?-
11+2:13 name x
12+3:3 NEWLINE
13+3:3 lit %.y
14+3:7 lit 1
15+4:3 NEWLINE
16+4:3 lit %.n
17+4:7 lit 2
18+4:8 DEDENT
19+4:8 NEWLINE
tests/golden/lex-body-rest-bad-3/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-3/source.jibb:3:3: expected `?-`'s arms on deeper lines, found a line at the same depth
2+ %.y 1
3+ ^
tests/golden/lex-body-rest-bad-4/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes, The rest of a body: "This doesn't apply on a `?-` arm's line, on a line of an open bracket, after a bracket opened earlier on the line (the subject's included), at the top level, or to a definition's own expression."
2+tests: a `?-` that is a local definition's own expression, with its arms at the definition's depth
3+expect: error at 3:3 — a definition's own expression never takes the lines after it at its depth; they would swallow the body's later lines
tests/golden/lex-body-rest-bad-4/source.jibbnew file+5
@@ -0,0 +1,5 @@
1+++ f |= x=?
2+ ++ g ?- x
3+ %.y 1
4+ %.n 2
5+ g
tests/golden/lex-body-rest-bad-4/tokens.txtnew file+21
@@ -0,0 +1,21 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name x
5+1:10 tight glyph =
6+1:11 tight glyph ?
7+2:3 INDENT
8+2:3 glyph ++
9+2:6 name g
10+2:8 glyph ?-
11+2:11 name x
12+3:3 NEWLINE
13+3:3 lit %.y
14+3:7 lit 1
15+4:3 NEWLINE
16+4:3 lit %.n
17+4:7 lit 2
18+5:3 NEWLINE
19+5:3 name g
20+5:4 DEDENT
21+5:4 NEWLINE
tests/golden/lex-body-rest-bad-4/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-4/source.jibb:3:3: expected `?-`'s arms on deeper lines, found a line at the same depth
2+ %.y 1
3+ ^
tests/golden/lex-body-rest-bad-5/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes, The rest of a body: "This doesn't apply on a `?-` arm's line, on a line of an open bracket, after a bracket opened earlier on the line (the subject's included), at the top level, or to a definition's own expression."
2+tests: a `?-` on a line of an open bracket, with its arms at its depth
3+expect: error at 4:5 — on an open bracket's line the next line at its depth is the bracket's next item, so the ?-'s arms go deeper
tests/golden/lex-body-rest-bad-5/source.jibbnew file+5
@@ -0,0 +1,5 @@
1+++ f |= x=?
2+ ~[
3+ ?- x
4+ %.y 1
5+ %.n 2
tests/golden/lex-body-rest-bad-5/tokens.txtnew file+20
@@ -0,0 +1,20 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name x
5+1:10 tight glyph =
6+1:11 tight glyph ?
7+2:3 INDENT
8+2:3 glyph ~[
9+3:5 INDENT
10+3:5 glyph ?-
11+3:8 name x
12+4:5 NEWLINE
13+4:5 lit %.y
14+4:9 lit 1
15+5:5 NEWLINE
16+5:5 lit %.n
17+5:9 lit 2
18+5:10 DEDENT
19+5:10 DEDENT
20+5:10 NEWLINE
tests/golden/lex-body-rest-bad-5/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-5/source.jibb:4:5: expected `?-`'s arms on deeper lines, found a line at the same depth
2+ %.y 1
3+ ^
tests/golden/lex-body-rest-bad-6/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes, The rest of a body: "This doesn't apply on a `?-` arm's line, on a line of an open bracket, after a bracket opened earlier on the line (the subject's included), at the top level, or to a definition's own expression."
2+tests: a cast alone on a line of an open bracket, with its expression on the next line at the same depth
3+expect: error at 4:5 — on an open bracket's line no rune takes the lines after it, so the cast needs its expression on its line or deeper
tests/golden/lex-body-rest-bad-6/source.jibbnew file+4
@@ -0,0 +1,4 @@
1+++ f |= x=@ud
2+ ~[
3+ ^- @ud
4+ x
tests/golden/lex-body-rest-bad-6/tokens.txtnew file+16
@@ -0,0 +1,16 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name x
5+1:10 tight glyph =
6+1:11 tight aura @ud
7+2:3 INDENT
8+2:3 glyph ~[
9+3:5 INDENT
10+3:5 glyph ^-
11+3:8 aura @ud
12+4:5 NEWLINE
13+4:5 name x
14+4:6 DEDENT
15+4:6 DEDENT
16+4:6 NEWLINE
tests/golden/lex-body-rest-bad-6/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-6/source.jibb:4:5: expected an expression, or a body on deeper lines, found a line at the same depth
2+ x
3+ ^
tests/golden/lex-body-rest-bad-7/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes, The rest of a body: "This doesn't apply on a `?-` arm's line, on a line of an open bracket, after a bracket opened earlier on the line (the subject's included), at the top level, or to a definition's own expression."
2+tests: a `?-` whose subject leaves a bracket open, taking the deeper lines, with its arms at the `?-`'s depth after them
3+expect: error at 2:11, the end of line 2 — the subject's ( took the deeper lines, so the line doesn't end where the arms go, and no later line can give the ?- its arms
tests/golden/lex-body-rest-bad-7/source.jibbnew file+5
@@ -0,0 +1,5 @@
1+++ f |= x=?
2+ ?- (eq x
3+ %.y
4+ %.y 1
5+ %.n 2
tests/golden/lex-body-rest-bad-7/tokens.txtnew file+22
@@ -0,0 +1,22 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name x
5+1:10 tight glyph =
6+1:11 tight glyph ?
7+2:3 INDENT
8+2:3 glyph ?-
9+2:6 glyph (
10+2:7 tight name eq
11+2:10 name x
12+3:5 INDENT
13+3:5 lit %.y
14+4:3 DEDENT
15+4:3 NEWLINE
16+4:3 lit %.y
17+4:7 lit 1
18+5:3 NEWLINE
19+5:3 lit %.n
20+5:7 lit 2
21+5:8 DEDENT
22+5:8 NEWLINE
tests/golden/lex-body-rest-bad-7/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-7/source.jibb:2:11: expected `?-`'s arms on deeper lines, found the end of the line; the deeper lines go to the last bracket or rune left open on this line
2+ ?- (eq x
3+ ^
tests/golden/lex-body-rest-bad-8/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes, The rest of a body: "This doesn't apply on a `?-` arm's line, on a line of an open bracket, after a bracket opened earlier on the line (the subject's included), at the top level, or to a definition's own expression."
2+tests: a trace whose value leaves a bracket open, taking the deeper lines, with its body at the trace's depth after them
3+expect: error at 2:8, the end of line 2 — the ~[ took the deeper lines, so the trace can't take the rest of the body
tests/golden/lex-body-rest-bad-8/source.jibbnew file+4
@@ -0,0 +1,4 @@
1+++ f |= x=@ud
2+ ~& ~[
3+ x
4+ x
tests/golden/lex-body-rest-bad-8/tokens.txtnew file+16
@@ -0,0 +1,16 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name x
5+1:10 tight glyph =
6+1:11 tight aura @ud
7+2:3 INDENT
8+2:3 glyph ~&
9+2:6 glyph ~[
10+3:5 INDENT
11+3:5 name x
12+4:3 DEDENT
13+4:3 NEWLINE
14+4:3 name x
15+4:4 DEDENT
16+4:4 NEWLINE
tests/golden/lex-body-rest-bad-8/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-8/source.jibb:2:8: expected `~&`'s body on deeper lines, found the end of the line; the deeper lines go to the last bracket or rune left open on this line
2+ ~& ~[
3+ ^
tests/golden/lex-body-rest-bad-9/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes, The rest of a body: "This doesn't apply on a `?-` arm's line, on a line of an open bracket, after a bracket opened earlier on the line (the subject's included), at the top level, or to a definition's own expression."
2+tests: a top-level definition's trace, with its body on the next line at column 1
3+expect: error at 2:1 — at the top level no rune takes the lines after it, so `~&`'s body goes on deeper lines
tests/golden/lex-body-rest-bad-9/source.jibbnew file+2
@@ -0,0 +1,2 @@
1+++ x ~& "hi"
2+5
tests/golden/lex-body-rest-bad-9/tokens.txtnew file+7
@@ -0,0 +1,7 @@
1+1:1 glyph ++
2+1:4 name x
3+1:6 glyph ~&
4+1:9 str "hi"
5+2:1 NEWLINE
6+2:1 lit 5
7+2:2 NEWLINE
tests/golden/lex-body-rest-bad-9/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-body-rest-bad-9/source.jibb:2:1: expected `~&`'s body on deeper lines, found a line at the same depth
2+5
3+^
tests/golden/lex-body-rest-ok-1/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: Grammar tab, Runes: "**The rest of a body.** A body's final line may hand the rest of the body, the lines after it at the same depth, to the rune that ends the line: a tall `|=`, `^-` or `~&`, or a chain of them such as `^- @ud ~& x`, when the line ends where the innermost rune's last child goes. That child is the rest, a body of its own: first its local `++` and `+$`, then its expression, whose own final line may do the same"; the EBNF: `last = expr | head NEWLINE rest | …`
2+tests: a body's final `^-`, `~&` and `|=`, each alone on its line, taking the rest of the body at the same depth as its last child, with the prelude's add
3+expect: parses: a's cast, b's trace and c's inner gate each hold the line below as a body, the tree the deeper layout gives
4+expect-types: a partial inference report: a and b are $-(@ud @ud), and c $-($-(@ud @ud) $-(@ud @ud)), as their deeper layouts are
tests/golden/lex-body-rest-ok-1/module-trees.txtnew file+4
@@ -0,0 +1,4 @@
1+/ui/lib.jibb
2+(module
3+ (value 1:1 identity
4+ (gate-wide 1:13 (bind 1:16 x) (wing 1:18 x))))
tests/golden/lex-body-rest-ok-1/modules.txtnew file+1
@@ -0,0 +1 @@
1+/ui/lib.jibb
tests/golden/lex-body-rest-ok-1/modules/ui/lib.jibbnew file+1
@@ -0,0 +1 @@
1+++ identity |=(x x)
tests/golden/lex-body-rest-ok-1/source.jibbnew file+11
@@ -0,0 +1,11 @@
1+/= lib /ui/lib
2+
3+++ a |= n=@ud
4+ ^- @ud
5+ (add n 1)
6+++ b |= n=@ud
7+ ~& n
8+ (add n 1)
9+++ c |= f=$-(@ud @ud)
10+ |= n=@ud
11+ (f n)
tests/golden/lex-body-rest-ok-1/tokens.txtnew file+62
@@ -0,0 +1,62 @@
1+1:1 glyph /=
2+1:5 name lib
3+1:9 glyph /
4+1:10 tight knot ui
5+1:12 tight glyph /
6+1:13 tight knot lib
7+3:1 NEWLINE
8+3:1 glyph ++
9+3:4 name a
10+3:6 glyph |=
11+3:9 name n
12+3:10 tight glyph =
13+3:11 tight aura @ud
14+4:3 INDENT
15+4:3 glyph ^-
16+4:6 aura @ud
17+5:3 NEWLINE
18+5:3 glyph (
19+5:4 tight name add
20+5:8 name n
21+5:10 lit 1
22+5:11 tight glyph )
23+6:1 DEDENT
24+6:1 NEWLINE
25+6:1 glyph ++
26+6:4 name b
27+6:6 glyph |=
28+6:9 name n
29+6:10 tight glyph =
30+6:11 tight aura @ud
31+7:3 INDENT
32+7:3 glyph ~&
33+7:6 name n
34+8:3 NEWLINE
35+8:3 glyph (
36+8:4 tight name add
37+8:8 name n
38+8:10 lit 1
39+8:11 tight glyph )
40+9:1 DEDENT
41+9:1 NEWLINE
42+9:1 glyph ++
43+9:4 name c
44+9:6 glyph |=
45+9:9 name f
46+9:10 tight glyph =
47+9:11 tight glyph $-(
48+9:14 tight aura @ud
49+9:18 aura @ud
50+9:21 tight glyph )
51+10:3 INDENT
52+10:3 glyph |=
53+10:6 name n
54+10:7 tight glyph =
55+10:8 tight aura @ud
56+11:3 NEWLINE
57+11:3 glyph (
58+11:4 tight name f
59+11:6 name n
60+11:7 tight glyph )
61+11:8 DEDENT
62+11:8 NEWLINE
tests/golden/lex-body-rest-ok-1/tree.txtnew file+30
@@ -0,0 +1,30 @@
1+(module
2+ (jibb 1:1 lib /ui/lib)
3+ (value 3:1 a
4+ (gate 3:6
5+ (face 3:9 n (aura 3:11 @ud))
6+ (body 4:3
7+ (cast 4:3
8+ (aura 4:6 @ud)
9+ (body 5:3
10+ (group 5:3
11+ (call 5:4 (wing 5:4 add) (wing 5:8 n) (lit 5:10 1))))))))
12+ (value 6:1 b
13+ (gate 6:6
14+ (face 6:9 n (aura 6:11 @ud))
15+ (body 7:3
16+ (trace 7:3
17+ (wing 7:6 n)
18+ (body 8:3
19+ (group 8:3
20+ (call 8:4 (wing 8:4 add) (wing 8:8 n) (lit 8:10 1))))))))
21+ (value 9:1 c
22+ (gate 9:6
23+ (face 9:9 f
24+ (fn 9:11 (aura 9:14 @ud) (aura 9:18 @ud)))
25+ (body 10:3
26+ (gate 10:3
27+ (face 10:6 n (aura 10:8 @ud))
28+ (body 11:3
29+ (group 11:3
30+ (call 11:4 (wing 11:4 f) (wing 11:6 n)))))))))
tests/golden/lex-body-rest-ok-1/types.txtnew file+4
@@ -0,0 +1,4 @@
1+partial inference; module not checked
2+++ a: $-(@ud @ud)
3+++ b: $-(@ud @ud)
4+++ c: $-($-(@ud @ud) $-(@ud @ud))
tests/golden/lex-body-rest-ok-2/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: Grammar tab, Runes: "**The rest of a body.** A body's final line may hand the rest of the body, the lines after it at the same depth, to the rune that ends the line: a tall `|=`, `^-` or `~&`, or a chain of them such as `^- @ud ~& x`, when the line ends where the innermost rune's last child goes. That child is the rest, a body of its own: first its local `++` and `+$`, then its expression, whose own final line may do the same"; the EBNF: `last = expr | head NEWLINE rest | …`
2+tests: a chain of runes on one line, `^- @ud ~& n` and `|= m=@ud ^- @ud`, whose innermost rune takes the rest; and `^-`, then `~&`, then the expression, each on its own line at one depth
3+expect: parses: in a the trace inside the cast holds line 5; in b the cast's rest is the trace, whose rest is line 9; in c the cast inside the inner gate holds line 12
4+expect-types: a partial inference report: a and b are $-(@ud @ud), and c $-(@ud $-(@ud @ud))
tests/golden/lex-body-rest-ok-2/module-trees.txtnew file+4
@@ -0,0 +1,4 @@
1+/ui/lib.jibb
2+(module
3+ (value 1:1 identity
4+ (gate-wide 1:13 (bind 1:16 x) (wing 1:18 x))))
tests/golden/lex-body-rest-ok-2/modules.txtnew file+1
@@ -0,0 +1 @@
1+/ui/lib.jibb
tests/golden/lex-body-rest-ok-2/modules/ui/lib.jibbnew file+1
@@ -0,0 +1 @@
1+++ identity |=(x x)
tests/golden/lex-body-rest-ok-2/source.jibbnew file+12
@@ -0,0 +1,12 @@
1+/= lib /ui/lib
2+
3+++ a |= n=@ud
4+ ^- @ud ~& n
5+ (add n 1)
6+++ b |= n=@ud
7+ ^- @ud
8+ ~& n
9+ (add n 1)
10+++ c |= n=@ud
11+ |= m=@ud ^- @ud
12+ (add n m)
tests/golden/lex-body-rest-ok-2/tokens.txtnew file+67
@@ -0,0 +1,67 @@
1+1:1 glyph /=
2+1:5 name lib
3+1:9 glyph /
4+1:10 tight knot ui
5+1:12 tight glyph /
6+1:13 tight knot lib
7+3:1 NEWLINE
8+3:1 glyph ++
9+3:4 name a
10+3:6 glyph |=
11+3:9 name n
12+3:10 tight glyph =
13+3:11 tight aura @ud
14+4:3 INDENT
15+4:3 glyph ^-
16+4:6 aura @ud
17+4:10 glyph ~&
18+4:13 name n
19+5:3 NEWLINE
20+5:3 glyph (
21+5:4 tight name add
22+5:8 name n
23+5:10 lit 1
24+5:11 tight glyph )
25+6:1 DEDENT
26+6:1 NEWLINE
27+6:1 glyph ++
28+6:4 name b
29+6:6 glyph |=
30+6:9 name n
31+6:10 tight glyph =
32+6:11 tight aura @ud
33+7:3 INDENT
34+7:3 glyph ^-
35+7:6 aura @ud
36+8:3 NEWLINE
37+8:3 glyph ~&
38+8:6 name n
39+9:3 NEWLINE
40+9:3 glyph (
41+9:4 tight name add
42+9:8 name n
43+9:10 lit 1
44+9:11 tight glyph )
45+10:1 DEDENT
46+10:1 NEWLINE
47+10:1 glyph ++
48+10:4 name c
49+10:6 glyph |=
50+10:9 name n
51+10:10 tight glyph =
52+10:11 tight aura @ud
53+11:3 INDENT
54+11:3 glyph |=
55+11:6 name m
56+11:7 tight glyph =
57+11:8 tight aura @ud
58+11:12 glyph ^-
59+11:15 aura @ud
60+12:3 NEWLINE
61+12:3 glyph (
62+12:4 tight name add
63+12:8 name n
64+12:10 name m
65+12:11 tight glyph )
66+12:12 DEDENT
67+12:12 NEWLINE
tests/golden/lex-body-rest-ok-2/tree.txtnew file+36
@@ -0,0 +1,36 @@
1+(module
2+ (jibb 1:1 lib /ui/lib)
3+ (value 3:1 a
4+ (gate 3:6
5+ (face 3:9 n (aura 3:11 @ud))
6+ (body 4:3
7+ (cast 4:3
8+ (aura 4:6 @ud)
9+ (trace 4:10
10+ (wing 4:13 n)
11+ (body 5:3
12+ (group 5:3
13+ (call 5:4 (wing 5:4 add) (wing 5:8 n) (lit 5:10 1)))))))))
14+ (value 6:1 b
15+ (gate 6:6
16+ (face 6:9 n (aura 6:11 @ud))
17+ (body 7:3
18+ (cast 7:3
19+ (aura 7:6 @ud)
20+ (body 8:3
21+ (trace 8:3
22+ (wing 8:6 n)
23+ (body 9:3
24+ (group 9:3
25+ (call 9:4 (wing 9:4 add) (wing 9:8 n) (lit 9:10 1))))))))))
26+ (value 10:1 c
27+ (gate 10:6
28+ (face 10:9 n (aura 10:11 @ud))
29+ (body 11:3
30+ (gate 11:3
31+ (face 11:6 m (aura 11:8 @ud))
32+ (cast 11:12
33+ (aura 11:15 @ud)
34+ (body 12:3
35+ (group 12:3
36+ (call 12:4 (wing 12:4 add) (wing 12:8 n) (wing 12:10 m))))))))))
tests/golden/lex-body-rest-ok-2/types.txtnew file+4
@@ -0,0 +1,4 @@
1+partial inference; module not checked
2+++ a: $-(@ud @ud)
3+++ b: $-(@ud @ud)
4+++ c: $-(@ud $-(@ud @ud))
tests/golden/lex-body-rest-ok-3/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes: "**The rest of a body.** A body's final line may hand the rest of the body, the lines after it at the same depth, to the rune that ends the line: a tall `|=`, `^-` or `~&`, or a chain of them such as `^- @ud ~& x`, when the line ends where the innermost rune's last child goes. That child is the rest, a body of its own: first its local `++` and `+$`, then its expression, whose own final line may do the same"; the EBNF: `last = expr | head NEWLINE rest | …`
2+tests: local `++` and `+$` at the start of a rest: the cast's rest is a body with definitions three and count, after the gate body's own definition two
3+expect: parses: the gate's body defines two, then the cast, whose body defines count and three and ends with the call
tests/golden/lex-body-rest-ok-3/source.jibbnew file+6
@@ -0,0 +1,6 @@
1+++ f |= n=@ud
2+ ++ two 2
3+ ^- @ud
4+ +$ count @ud
5+ ++ three ^- count 3
6+ (add n (add two three))
tests/golden/lex-body-rest-ok-3/tokens.txtnew file+35
@@ -0,0 +1,35 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name n
5+1:10 tight glyph =
6+1:11 tight aura @ud
7+2:3 INDENT
8+2:3 glyph ++
9+2:6 name two
10+2:10 lit 2
11+3:3 NEWLINE
12+3:3 glyph ^-
13+3:6 aura @ud
14+4:3 NEWLINE
15+4:3 glyph +$
16+4:6 name count
17+4:12 aura @ud
18+5:3 NEWLINE
19+5:3 glyph ++
20+5:6 name three
21+5:12 glyph ^-
22+5:15 name count
23+5:21 lit 3
24+6:3 NEWLINE
25+6:3 glyph (
26+6:4 tight name add
27+6:8 name n
28+6:10 glyph (
29+6:11 tight name add
30+6:15 name two
31+6:19 name three
32+6:24 tight glyph )
33+6:25 tight glyph )
34+6:26 DEDENT
35+6:26 NEWLINE
tests/golden/lex-body-rest-ok-3/tree.txtnew file+18
@@ -0,0 +1,18 @@
1+(module
2+ (value 1:1 f
3+ (gate 1:6
4+ (face 1:9 n (aura 1:11 @ud))
5+ (body 2:3
6+ (value 2:3 two (lit 2:10 2))
7+ (cast 3:3
8+ (aura 3:6 @ud)
9+ (body 4:3
10+ (mold 4:3 count (aura 4:12 @ud))
11+ (value 5:3 three
12+ (cast 5:12 (ref 5:15 count) (lit 5:21 3)))
13+ (group 6:3
14+ (call 6:4
15+ (wing 6:4 add)
16+ (wing 6:8 n)
17+ (group 6:10
18+ (call 6:11 (wing 6:11 add) (wing 6:15 two) (wing 6:19 three)))))))))))
tests/golden/lex-body-rest-ok-4/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: Grammar tab, Runes: "`?-` **wuthep**: … A `?-` that begins a body's final line may instead take its arms at its own depth, to the end of the body. A `?-` takes all its arms deeper or all at its own depth."; the EBNF: `last = … | "?-" expr NEWLINE arm { NEWLINE arm } ;`
2+tests: a `?-` that begins a body's final line, with its arms at its own depth, one per line, to the end of the body, over a loobean and over a union, with a comment line and a blank line between two arms
3+expect: parses: each ?- holds the arms below it, the tree the deeper layout gives
4+expect-types: a partial inference report: f is $-(? @ud) and g $-(sign @ud)
tests/golden/lex-body-rest-ok-4/source.jibbnew file+13
@@ -0,0 +1,13 @@
1++$ sign
2+ %zero
3+ %more
4+++ f |= b=? ^- @ud
5+ ?- b
6+ %.y 1
7+ :: comment lines and blank lines between arms emit nothing
8+
9+ %.n 2
10+++ g |= s=sign ^- @ud
11+ ?- s
12+ %zero 0
13+ %more 1
tests/golden/lex-body-rest-ok-4/tokens.txtnew file+46
@@ -0,0 +1,46 @@
1+1:1 glyph +$
2+1:4 name sign
3+2:3 INDENT
4+2:3 lit %zero
5+3:3 NEWLINE
6+3:3 lit %more
7+4:1 DEDENT
8+4:1 NEWLINE
9+4:1 glyph ++
10+4:4 name f
11+4:6 glyph |=
12+4:9 name b
13+4:10 tight glyph =
14+4:11 tight glyph ?
15+4:13 glyph ^-
16+4:16 aura @ud
17+5:3 INDENT
18+5:3 glyph ?-
19+5:6 name b
20+6:3 NEWLINE
21+6:3 lit %.y
22+6:8 lit 1
23+9:3 NEWLINE
24+9:3 lit %.n
25+9:8 lit 2
26+10:1 DEDENT
27+10:1 NEWLINE
28+10:1 glyph ++
29+10:4 name g
30+10:6 glyph |=
31+10:9 name s
32+10:10 tight glyph =
33+10:11 tight name sign
34+10:16 glyph ^-
35+10:19 aura @ud
36+11:3 INDENT
37+11:3 glyph ?-
38+11:6 name s
39+12:3 NEWLINE
40+12:3 lit %zero
41+12:10 lit 0
42+13:3 NEWLINE
43+13:3 lit %more
44+13:10 lit 1
45+13:11 DEDENT
46+13:11 NEWLINE
tests/golden/lex-body-rest-ok-4/tree.txtnew file+23
@@ -0,0 +1,23 @@
1+(module
2+ (mold 1:1 sign
3+ (union 2:3 (const 2:3 %zero) (const 3:3 %more)))
4+ (value 4:1 f
5+ (gate 4:6
6+ (face 4:9 b (flag 4:11))
7+ (cast 4:13
8+ (aura 4:16 @ud)
9+ (body 5:3
10+ (branch 5:3
11+ (wing 5:6 b)
12+ (arm 6:3 (lit 6:3 %.y) (lit 6:8 1))
13+ (arm 9:3 (lit 9:3 %.n) (lit 9:8 2)))))))
14+ (value 10:1 g
15+ (gate 10:6
16+ (face 10:9 s (ref 10:11 sign))
17+ (cast 10:16
18+ (aura 10:19 @ud)
19+ (body 11:3
20+ (branch 11:3
21+ (wing 11:6 s)
22+ (arm 12:3 (lit 12:3 %zero) (lit 12:10 0))
23+ (arm 13:3 (lit 13:3 %more) (lit 13:10 1))))))))
tests/golden/lex-body-rest-ok-4/types.txtnew file+4
@@ -0,0 +1,4 @@
1+partial inference; module not checked
2++$ sign: cases proven disjoint; mold not checked
3+++ f: $-(? @ud)
4+++ g: $-(sign @ud)
tests/golden/lex-body-rest-ok-5/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes: "`?-` **wuthep**: … A `?-` that begins a body's final line may instead take its arms at its own depth, to the end of the body. A `?-` takes all its arms deeper or all at its own depth."; the EBNF: `last = … | "?-" expr NEWLINE arm { NEWLINE arm } ;`
2+tests: arms at the `?-`'s depth whose expressions are bodies on deeper lines, one with a local definition
3+expect: parses: each arm's body is the block below its pattern, and the next arm follows at the ?-'s depth
tests/golden/lex-body-rest-ok-5/source.jibbnew file+7
@@ -0,0 +1,7 @@
1+++ f |= b=?
2+ ?- b
3+ %.y
4+ 1
5+ %.n
6+ ++ two 2
7+ two
tests/golden/lex-body-rest-ok-5/tokens.txtnew file+25
@@ -0,0 +1,25 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name b
5+1:10 tight glyph =
6+1:11 tight glyph ?
7+2:3 INDENT
8+2:3 glyph ?-
9+2:6 name b
10+3:3 NEWLINE
11+3:3 lit %.y
12+4:5 INDENT
13+4:5 lit 1
14+5:3 DEDENT
15+5:3 NEWLINE
16+5:3 lit %.n
17+6:5 INDENT
18+6:5 glyph ++
19+6:8 name two
20+6:12 lit 2
21+7:5 NEWLINE
22+7:5 name two
23+7:8 DEDENT
24+7:8 DEDENT
25+7:8 NEWLINE
tests/golden/lex-body-rest-ok-5/tree.txtnew file+15
@@ -0,0 +1,15 @@
1+(module
2+ (value 1:1 f
3+ (gate 1:6
4+ (face 1:9 b (flag 1:11))
5+ (body 2:3
6+ (branch 2:3
7+ (wing 2:6 b)
8+ (arm 3:3
9+ (lit 3:3 %.y)
10+ (body 4:5 (lit 4:5 1)))
11+ (arm 5:3
12+ (lit 5:3 %.n)
13+ (body 6:5
14+ (value 6:5 two (lit 6:12 2))
15+ (wing 7:5 two))))))))
tests/golden/lex-body-rest-ok-6/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes: "`?-` **wuthep**: … A `?-` that begins a body's final line may instead take its arms at its own depth, to the end of the body. A `?-` takes all its arms deeper or all at its own depth."; the EBNF: `last = … | "?-" expr NEWLINE arm { NEWLINE arm } ;`
2+tests: a `?-` with its arms at its depth inside an arm's deeper body, itself at the outer `?-`'s depth
3+expect: parses: the inner ?- holds the arms at 5:5 and 6:5, and [%.n b] at 7:3 is the outer ?-'s second arm
tests/golden/lex-body-rest-ok-6/source.jibbnew file+7
@@ -0,0 +1,7 @@
1+++ f |= p=[? ?]
2+ ?- p
3+ [%.y b]
4+ ?- b
5+ %.y 1
6+ %.n 2
7+ [%.n b] 3
tests/golden/lex-body-rest-ok-6/tokens.txtnew file+35
@@ -0,0 +1,35 @@
1+1:1 glyph ++
2+1:4 name f
3+1:6 glyph |=
4+1:9 name p
5+1:10 tight glyph =
6+1:11 tight glyph [
7+1:12 tight glyph ?
8+1:14 glyph ?
9+1:15 tight glyph ]
10+2:3 INDENT
11+2:3 glyph ?-
12+2:6 name p
13+3:3 NEWLINE
14+3:3 glyph [
15+3:4 tight lit %.y
16+3:8 name b
17+3:9 tight glyph ]
18+4:5 INDENT
19+4:5 glyph ?-
20+4:8 name b
21+5:5 NEWLINE
22+5:5 lit %.y
23+5:9 lit 1
24+6:5 NEWLINE
25+6:5 lit %.n
26+6:9 lit 2
27+7:3 DEDENT
28+7:3 NEWLINE
29+7:3 glyph [
30+7:4 tight lit %.n
31+7:8 name b
32+7:9 tight glyph ]
33+7:11 lit 3
34+7:12 DEDENT
35+7:12 NEWLINE
tests/golden/lex-body-rest-ok-6/tree.txtnew file+18
@@ -0,0 +1,18 @@
1+(module
2+ (value 1:1 f
3+ (gate 1:6
4+ (face 1:9 p
5+ (cell 1:11 (flag 1:12) (flag 1:14)))
6+ (body 2:3
7+ (branch 2:3
8+ (wing 2:6 p)
9+ (arm 3:3
10+ (cell 3:3 (lit 3:4 %.y) (bind 3:8 b))
11+ (body 4:5
12+ (branch 4:5
13+ (wing 4:8 b)
14+ (arm 5:5 (lit 5:5 %.y) (lit 5:9 1))
15+ (arm 6:5 (lit 6:5 %.n) (lit 6:9 2)))))
16+ (arm 7:3
17+ (cell 7:3 (lit 7:4 %.n) (bind 7:8 b))
18+ (lit 7:11 3)))))))
tests/golden/lex-body-rest-ok-7/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: Grammar tab, Runes: "**The rest of a body.** A body's final line may hand the rest of the body, the lines after it at the same depth, to the rune that ends the line: … a `?-` that begins the line and ends it with its subject. Its arms are the rest, one per line"
2+tests: a trace taking the rest of the body, whose final line is a `?-` with its arms at its depth: removing the `~&` line moves no other line
3+expect: parses: the trace's body is the ?-, which holds both arms
4+expect-types: a partial inference report: update is $-([msg=msg n=@ud] @ud)
tests/golden/lex-body-rest-ok-7/module-trees.txtnew file+4
@@ -0,0 +1,4 @@
1+/ui/lib.jibb
2+(module
3+ (value 1:1 identity
4+ (gate-wide 1:13 (bind 1:16 x) (wing 1:18 x))))
tests/golden/lex-body-rest-ok-7/modules.txtnew file+1
@@ -0,0 +1 @@
1+/ui/lib.jibb
tests/golden/lex-body-rest-ok-7/modules/ui/lib.jibbnew file+1
@@ -0,0 +1 @@
1+++ identity |=(x x)
tests/golden/lex-body-rest-ok-7/source.jibbnew file+10
@@ -0,0 +1,10 @@
1+/= lib /ui/lib
2+
3++$ msg
4+ [%typed text=@t]
5+ %submit
6+++ update |= [=msg n=@ud]
7+ ~& msg
8+ ?- msg
9+ [%typed t] n
10+ %submit (add n 1)
tests/golden/lex-body-rest-ok-7/tokens.txtnew file+51
@@ -0,0 +1,51 @@
1+1:1 glyph /=
2+1:5 name lib
3+1:9 glyph /
4+1:10 tight knot ui
5+1:12 tight glyph /
6+1:13 tight knot lib
7+3:1 NEWLINE
8+3:1 glyph +$
9+3:4 name msg
10+4:3 INDENT
11+4:3 glyph [
12+4:4 tight lit %typed
13+4:11 name text
14+4:15 tight glyph =
15+4:16 tight aura @t
16+4:18 tight glyph ]
17+5:3 NEWLINE
18+5:3 lit %submit
19+6:1 DEDENT
20+6:1 NEWLINE
21+6:1 glyph ++
22+6:4 name update
23+6:11 glyph |=
24+6:14 glyph [
25+6:15 tight glyph =
26+6:16 tight name msg
27+6:20 name n
28+6:21 tight glyph =
29+6:22 tight aura @ud
30+6:25 tight glyph ]
31+7:3 INDENT
32+7:3 glyph ~&
33+7:6 name msg
34+8:3 NEWLINE
35+8:3 glyph ?-
36+8:6 name msg
37+9:3 NEWLINE
38+9:3 glyph [
39+9:4 tight lit %typed
40+9:11 name t
41+9:12 tight glyph ]
42+9:15 name n
43+10:3 NEWLINE
44+10:3 lit %submit
45+10:15 glyph (
46+10:16 tight name add
47+10:20 name n
48+10:22 lit 1
49+10:23 tight glyph )
50+10:24 DEDENT
51+10:24 NEWLINE
tests/golden/lex-body-rest-ok-7/tree.txtnew file+26
@@ -0,0 +1,26 @@
1+(module
2+ (jibb 1:1 lib /ui/lib)
3+ (mold 3:1 msg
4+ (union 4:3
5+ (cell 4:3
6+ (const 4:4 %typed)
7+ (face 4:11 text (aura 4:16 @t)))
8+ (const 5:3 %submit)))
9+ (value 6:1 update
10+ (gate 6:11
11+ (cell 6:14
12+ (pun 6:15 msg)
13+ (face 6:20 n (aura 6:22 @ud)))
14+ (body 7:3
15+ (trace 7:3
16+ (wing 7:6 msg)
17+ (body 8:3
18+ (branch 8:3
19+ (wing 8:6 msg)
20+ (arm 9:3
21+ (cell 9:3 (lit 9:4 %typed) (bind 9:11 t))
22+ (wing 9:15 n))
23+ (arm 10:3
24+ (lit 10:3 %submit)
25+ (group 10:15
26+ (call 10:16 (wing 10:16 add) (wing 10:20 n) (lit 10:22 1)))))))))))
tests/golden/lex-body-rest-ok-7/types.txtnew file+3
@@ -0,0 +1,3 @@
1+partial inference; module not checked
2++$ msg: cases proven disjoint; mold not checked
3+++ update: $-([msg=msg n=@ud] @ud)
tests/golden/lex-body-rest-ok-8/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: Grammar tab, Runes: "**The rest of a body.** A body's final line may hand the rest of the body, the lines after it at the same depth, to the rune that ends the line: … a `?-` that begins the line and ends it with its subject. Its arms are the rest, one per line"
2+tests: a gate and a cast taking the rest of a body, then a `?-` on the rest's final line with its arms at its depth; and a `?-` with its arms at its depth on the final line of a local `++`'s deeper body
3+expect: parses: or-else's inner gate holds the cast, which holds the ?- and its two arms; h's body is the ?-
4+expect-types: a partial inference report: or-else is $-(@ud $-((unit @ud) @ud)) and g $-(? @ud)
tests/golden/lex-body-rest-ok-8/module-trees.txtnew file+4
@@ -0,0 +1,4 @@
1+/ui/lib.jibb
2+(module
3+ (value 1:1 identity
4+ (gate-wide 1:13 (bind 1:16 x) (wing 1:18 x))))
tests/golden/lex-body-rest-ok-8/modules.txtnew file+1
@@ -0,0 +1 @@
1+/ui/lib.jibb
tests/golden/lex-body-rest-ok-8/modules/ui/lib.jibbnew file+1
@@ -0,0 +1 @@
1+++ identity |=(x x)
tests/golden/lex-body-rest-ok-8/source.jibbnew file+14
@@ -0,0 +1,14 @@
1+/= lib /ui/lib
2+
3+++ or-else |= fallback=@ud
4+ |= maybe=(unit @ud)
5+ ^- @ud
6+ ?- maybe
7+ ~ fallback
8+ [~ value] value
9+++ g |= b=?
10+ ++ h ^- @ud
11+ ?- b
12+ %.y 1
13+ %.n 2
14+ h
tests/golden/lex-body-rest-ok-8/tokens.txtnew file+63
@@ -0,0 +1,63 @@
1+1:1 glyph /=
2+1:5 name lib
3+1:9 glyph /
4+1:10 tight knot ui
5+1:12 tight glyph /
6+1:13 tight knot lib
7+3:1 NEWLINE
8+3:1 glyph ++
9+3:4 name or-else
10+3:12 glyph |=
11+3:15 name fallback
12+3:23 tight glyph =
13+3:24 tight aura @ud
14+4:3 INDENT
15+4:3 glyph |=
16+4:6 name maybe
17+4:11 tight glyph =
18+4:12 tight glyph (
19+4:13 tight name unit
20+4:18 aura @ud
21+4:21 tight glyph )
22+5:3 NEWLINE
23+5:3 glyph ^-
24+5:6 aura @ud
25+6:3 NEWLINE
26+6:3 glyph ?-
27+6:6 name maybe
28+7:3 NEWLINE
29+7:3 lit ~
30+7:14 name fallback
31+8:3 NEWLINE
32+8:3 glyph [
33+8:4 tight lit ~
34+8:6 name value
35+8:11 tight glyph ]
36+8:14 name value
37+9:1 DEDENT
38+9:1 NEWLINE
39+9:1 glyph ++
40+9:4 name g
41+9:6 glyph |=
42+9:9 name b
43+9:10 tight glyph =
44+9:11 tight glyph ?
45+10:3 INDENT
46+10:3 glyph ++
47+10:6 name h
48+10:8 glyph ^-
49+10:11 aura @ud
50+11:5 INDENT
51+11:5 glyph ?-
52+11:8 name b
53+12:5 NEWLINE
54+12:5 lit %.y
55+12:9 lit 1
56+13:5 NEWLINE
57+13:5 lit %.n
58+13:9 lit 2
59+14:3 DEDENT
60+14:3 NEWLINE
61+14:3 name h
62+14:4 DEDENT
63+14:4 NEWLINE
tests/golden/lex-body-rest-ok-8/tree.txtnew file+32
@@ -0,0 +1,32 @@
1+(module
2+ (jibb 1:1 lib /ui/lib)
3+ (value 3:1 or-else
4+ (gate 3:12
5+ (face 3:15 fallback (aura 3:24 @ud))
6+ (body 4:3
7+ (gate 4:3
8+ (face 4:6 maybe
9+ (apply 4:12 unit (aura 4:18 @ud)))
10+ (body 5:3
11+ (cast 5:3
12+ (aura 5:6 @ud)
13+ (body 6:3
14+ (branch 6:3
15+ (wing 6:6 maybe)
16+ (arm 7:3 (lit 7:3 ~) (wing 7:14 fallback))
17+ (arm 8:3
18+ (cell 8:3 (lit 8:4 ~) (bind 8:6 value))
19+ (wing 8:14 value))))))))))
20+ (value 9:1 g
21+ (gate 9:6
22+ (face 9:9 b (flag 9:11))
23+ (body 10:3
24+ (value 10:3 h
25+ (cast 10:8
26+ (aura 10:11 @ud)
27+ (body 11:5
28+ (branch 11:5
29+ (wing 11:8 b)
30+ (arm 12:5 (lit 12:5 %.y) (lit 12:9 1))
31+ (arm 13:5 (lit 13:5 %.n) (lit 13:9 2))))))
32+ (wing 14:3 h)))))
tests/golden/lex-body-rest-ok-8/types.txtnew file+3
@@ -0,0 +1,3 @@
1+partial inference; module not checked
2+++ or-else: $-(@ud $-((unit @ud) @ud))
3+++ g: $-(? @ud)
tests/golden/lex-layout-bad-4/about.txt+1−1
@@ -1,3 +1,3 @@
11source: Grammar tab, Lexical rules: "Layout tokens: a deeper line emits INDENT, the same depth NEWLINE, a shallower one a DEDENT per closed level, then NEWLINE."; the EBNF's comment: "Blank and comment-only lines emit nothing."
22tests: an arm written one level too shallow
3−expect: error at 4:3 — line 4 is shallower than the arms, so it closes them (DEDENT) and lands at the body's depth (NEWLINE), after the body's final expression, the ?-
3+expect: error at 4:3 — line 4 is shallower than the arms, so it closes them (DEDENT) and lands at the body's depth (NEWLINE), after the body's final expression, the ?-; its first arm is deeper, so the hint says this one goes there too
tests/golden/lex-layout-bad-4/tree.txt+1−1
@@ -1,3 +1,3 @@
1−/tests/golden/lex-layout-bad-4/source.jibb:4:3: expected the end of the body, found a line at the same depth; a body's final expression is its last line
1+/tests/golden/lex-layout-bad-4/source.jibb:4:3: expected the end of the body, found a line at the same depth; this `?-`'s arms are on deeper lines, so this one goes there too
22 * ~
33 ^
tests/golden/lex-name-bad-5/tokens.txt+4−3
@@ -1,3 +1,4 @@
1−/tests/golden/lex-name-bad-5/source.jibb:1:5: a type variable is one capital letter
2−++ Foo 1
3− ^
1+1:1 glyph ++
2+1:4 tvar Foo
3+1:8 lit 1
4+1:9 NEWLINE
tests/golden/lex-name-bad-5/tree.txt+1−1
@@ -1,3 +1,3 @@
1−/tests/golden/lex-name-bad-5/source.jibb:1:4: expected a name, found `F`; a name starts with a lowercase letter
1+/tests/golden/lex-name-bad-5/source.jibb:1:4: expected a name, found `Foo`; a name starts with a lowercase letter
22++ Foo 1
33 ^
tests/golden/lex-rune-layout-bad-3/about.txtdeleted−3
@@ -1,3 +0,0 @@
1−source: Grammar tab, Runes: "A rune's first children sit on its line, the last taking the rest of it; the others follow, indented."; the EBNF: `rune = "|=" field ( expr | body ) | "^-" mold ( expr | body ) | "~&" expr body | "?-" expr INDENT arm { NEWLINE arm } DEDENT ;`
2−tests: `~&`'s body at the depth of the `~&` line, as Hoon's tall form would put it
3−expect: error at 3:3 — `~&`'s body is indented deeper than its line; line 3 is at the same depth
tests/golden/lex-rune-layout-bad-3/tree.txtdeleted−3
@@ -1,3 +0,0 @@
1−/tests/golden/lex-rune-layout-bad-3/source.jibb:3:3: expected `~&`'s body on deeper lines, found a line at the same depth
2− 5
3− ^
tests/golden/lex-rune-layout-ok-3/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Runes: "A rune's first children sit on its line, the last taking the rest of it; the others follow, indented. On a body's final line, the last child may instead take the rest of the body at the same depth, as The rest of a body says."
2+tests: `~&`'s body at the depth of the `~&` line, as Hoon's tall form would put it, on the final line of a definition's body
3+expect: parses: the `~&` is the body's final line, so the line after it at the same depth is its body, (trace "hi" (body 5))
tests/golden/lex-rune-layout-bad-3/source.jibb → tests/golden/lex-rune-layout-ok-3/source.jibbrenamed

The content is the same.

tests/golden/lex-rune-layout-bad-3/tokens.txt → tests/golden/lex-rune-layout-ok-3/tokens.txtrenamed

The content is the same.

tests/golden/lex-rune-layout-ok-3/tree.txtnew file+6
@@ -0,0 +1,6 @@
1+(module
2+ (value 1:1 x
3+ (body 2:3
4+ (trace 2:3
5+ (str 2:6 "hi")
6+ (body 3:3 (lit 3:3 5))))))
tests/golden/lex-tight-change-bad-10/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar, Expressions: "A change's item, inline or on a line, may name a wing instead, read through record fields only: `m(open.cart=(not open.cart.m))` sets field `open` of field `cart`, as Hoon's `m(open.cart x)`."; the EBNF: `edit = wing "=" operand ;` and `elines = INDENT wing "=" expr { NEWLINE wing "=" expr } DEDENT ;`
2+tests: a change's only item a wing with no `=` after it, then the `)`
3+expect: error at 1:11, the ): `a.b` could still begin the item `a.b=…`, and the ) is the first character that can't go on (library section 3, Errors)
tests/golden/lex-tight-change-bad-10/source.jibbnew file+1
@@ -0,0 +1 @@
1+++ x m(a.b)
tests/golden/lex-tight-change-bad-10/tokens.txtnew file+7
@@ -0,0 +1,7 @@
1+1:1 glyph ++
2+1:4 name x
3+1:6 name m
4+1:7 tight glyph (
5+1:8 tight wing a.b
6+1:11 tight glyph )
7+1:12 NEWLINE
tests/golden/lex-tight-change-bad-10/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-tight-change-bad-10/source.jibb:1:11: expected `=` right after `a.b`, found `)`; a change's items are named, as in m(done=%.y)
2+++ x m(a.b)
3+ ^
tests/golden/lex-tight-change-bad-11/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar, Expressions: "A change's item, inline or on a line, may name a wing instead, read through record fields only: `m(open.cart=(not open.cart.m))` sets field `open` of field `cart`, as Hoon's `m(open.cart x)`."; the EBNF: `edit = wing "=" operand ;` and `elines = INDENT wing "=" expr { NEWLINE wing "=" expr } DEDENT ;`
2+tests: a line of an open change holding a wing, a space and a value, with no `=`
3+expect: error at 2:12, the space: `open.cart` could still begin the line `open.cart=…`, and a wing= takes its `=` at once (library section 3, Errors)
tests/golden/lex-tight-change-bad-11/source.jibbnew file+2
@@ -0,0 +1,2 @@
1+++ x m(
2+ open.cart %.n
tests/golden/lex-tight-change-bad-11/tokens.txtnew file+9
@@ -0,0 +1,9 @@
1+1:1 glyph ++
2+1:4 name x
3+1:6 name m
4+1:7 tight glyph (
5+2:3 INDENT
6+2:3 wing open.cart
7+2:13 lit %.n
8+2:16 DEDENT
9+2:16 NEWLINE
tests/golden/lex-tight-change-bad-11/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-tight-change-bad-11/source.jibb:2:12: expected `=` right after `open.cart`, found a space; a change's items are named, as in m(done=%.y)
2+ open.cart %.n
3+ ^
tests/golden/lex-tight-change-bad-5/about.txt+3−3
@@ -1,3 +1,3 @@
1−source: Grammar tab, Expressions: "**Faced cells**: `[text="milk" done=%.n]`, or one `name=value` per line of an open bracket. A change takes the same items, as `m(done=%.y)`."; the EBNF: `change = wing "(" { item } ")" | wing "(" { item } open ; (* no space before "("; items named *)`
2−tests: a change's item named by a wing, as Hoon's %= allows
3−expect: error at 1:9, the dot: an item's name is a name, which `a` could still begin and the dot can't continue, as `++ a.b 1` fails at its dot (library section 3, Errors)
1+source: Grammar, Expressions: "A change's item, inline or on a line, may name a wing instead, read through record fields only: `m(open.cart=(not open.cart.m))` sets field `open` of field `cart`, as Hoon's `m(open.cart x)`."; the EBNF: `edit = wing "=" operand ;` and `elines = INDENT wing "=" expr { NEWLINE wing "=" expr } DEDENT ;`
2+tests: a change's item that is a wing with no `=` after it, followed by a space and a value, as Hoon's %= writes m(a.b 1)
3+expect: error at 1:11, the space: `a.b` could still begin the item `a.b=…`, and a wing= takes its `=` at once, so the space is the first character that can't go on; the message says "expected `=` right after `a.b`" (library section 3, Errors)
tests/golden/lex-tight-change-bad-5/source.jibb+1−1
@@ -1 +1 @@
1−++ x m(a.b=1)
1+++ x m(a.b 1)
tests/golden/lex-tight-change-bad-5/tokens.txt+1−2
@@ -3,7 +3,6 @@
331:6 name m
441:7 tight glyph (
551:8 tight wing a.b
6−1:11 tight glyph =
7−1:12 tight lit 1
6+1:12 lit 1
871:13 tight glyph )
981:14 NEWLINE
tests/golden/lex-tight-change-bad-5/tree.txt+3−3
@@ -1,3 +1,3 @@
1−/tests/golden/lex-tight-change-bad-5/source.jibb:1:9: expected a named item, found `a.b`; a change's items are named, as in m(done=%.y)
2−++ x m(a.b=1)
3− ^
1+/tests/golden/lex-tight-change-bad-5/source.jibb:1:11: expected `=` right after `a.b`, found a space; a change's items are named, as in m(done=%.y)
2+++ x m(a.b 1)
3+ ^
tests/golden/lex-tight-change-ok-2/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar, Expressions: "A change's item, inline or on a line, may name a wing instead, read through record fields only: `m(open.cart=(not open.cart.m))` sets field `open` of field `cart`, as Hoon's `m(open.cart x)`."; the EBNF: `edit = wing "=" operand ;` and `elines = INDENT wing "=" expr { NEWLINE wing "=" expr } DEDENT ;`
2+tests: a change's items named by wings: alone, beside a named item, under a wing target, and on the lines of an open change
3+expect: parses: four changes, each edit printed with its wing as written
tests/golden/lex-tight-change-ok-2/source.jibbnew file+7
@@ -0,0 +1,7 @@
1+++ a m(a.b=1)
2+++ b m(open.cart=(not open.cart.m) note="")
3+++ c cart.m(level.deep=5)
4+++ d m(
5+ open.cart=%.n
6+ level.deep.cart=(add 1 level.deep.cart.m)
7+ note=""
tests/golden/lex-tight-change-ok-2/tokens.txtnew file+55
@@ -0,0 +1,55 @@
1+1:1 glyph ++
2+1:4 name a
3+1:6 name m
4+1:7 tight glyph (
5+1:8 tight wing a.b
6+1:11 tight glyph =
7+1:12 tight lit 1
8+1:13 tight glyph )
9+2:1 NEWLINE
10+2:1 glyph ++
11+2:4 name b
12+2:6 name m
13+2:7 tight glyph (
14+2:8 tight wing open.cart
15+2:17 tight glyph =
16+2:18 tight glyph (
17+2:19 tight name not
18+2:23 wing open.cart.m
19+2:34 tight glyph )
20+2:36 name note
21+2:40 tight glyph =
22+2:41 tight str ""
23+2:43 tight glyph )
24+3:1 NEWLINE
25+3:1 glyph ++
26+3:4 name c
27+3:6 wing cart.m
28+3:12 tight glyph (
29+3:13 tight wing level.deep
30+3:23 tight glyph =
31+3:24 tight lit 5
32+3:25 tight glyph )
33+4:1 NEWLINE
34+4:1 glyph ++
35+4:4 name d
36+4:6 name m
37+4:7 tight glyph (
38+5:3 INDENT
39+5:3 wing open.cart
40+5:12 tight glyph =
41+5:13 tight lit %.n
42+6:3 NEWLINE
43+6:3 wing level.deep.cart
44+6:18 tight glyph =
45+6:19 tight glyph (
46+6:20 tight name add
47+6:24 lit 1
48+6:26 wing level.deep.cart.m
49+6:43 tight glyph )
50+7:3 NEWLINE
51+7:3 name note
52+7:7 tight glyph =
53+7:8 tight str ""
54+7:10 DEDENT
55+7:10 NEWLINE
tests/golden/lex-tight-change-ok-2/tree.txtnew file+20
@@ -0,0 +1,20 @@
1+(module
2+ (value 1:1 a
3+ (change 1:6 m
4+ (edit 1:8 a.b (lit 1:12 1))))
5+ (value 2:1 b
6+ (change 2:6 m
7+ (edit 2:8 open.cart
8+ (group 2:18
9+ (call 2:19 (wing 2:19 not) (wing 2:23 open.cart.m))))
10+ (edit 2:36 note (str 2:41 ""))))
11+ (value 3:1 c
12+ (change 3:6 cart.m
13+ (edit 3:13 level.deep (lit 3:24 5))))
14+ (value 4:1 d
15+ (change 4:6 m
16+ (edit 5:3 open.cart (lit 5:13 %.n))
17+ (edit 6:3 level.deep.cart
18+ (group 6:19
19+ (call 6:20 (wing 6:20 add) (lit 6:24 1) (wing 6:26 level.deep.cart.m))))
20+ (edit 7:3 note (str 7:8 "")))))
tests/golden/lex-typevar-bad-1/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Lexical rules: "Type variables: a capital, then lowercase letters and digits"; "`AB`, `MSG`, `Msg_x` and `Msg-x` are errors."
2+tests: a second capital right after a type variable's first
3+expect: error at 1:15 — a type variable is a capital, then lowercase letters and digits
tests/golden/lex-typevar-bad-1/source.jibbnew file+1
@@ -0,0 +1 @@
1+++ pair |= x=AB x
tests/golden/lex-typevar-bad-1/tokens.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-typevar-bad-1/source.jibb:1:15: a type variable is a capital, then lowercase letters and digits
2+++ pair |= x=AB x
3+ ^
tests/golden/lex-typevar-bad-1/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-typevar-bad-1/source.jibb:1:15: a type variable is a capital, then lowercase letters and digits
2+++ pair |= x=AB x
3+ ^
tests/golden/lex-typevar-bad-2/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Lexical rules: "Type variables: a capital, then lowercase letters and digits"; "`AB`, `MSG`, `Msg_x` and `Msg-x` are errors."
2+tests: a type variable written in capitals only, as an Elm or C habit might write it
3+expect: error at 1:15 — a type variable is a capital, then lowercase letters and digits
tests/golden/lex-typevar-bad-2/source.jibbnew file+1
@@ -0,0 +1 @@
1+++ pass |= m=MSG m
tests/golden/lex-typevar-bad-2/tokens.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-typevar-bad-2/source.jibb:1:15: a type variable is a capital, then lowercase letters and digits
2+++ pass |= m=MSG m
3+ ^
tests/golden/lex-typevar-bad-2/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-typevar-bad-2/source.jibb:1:15: a type variable is a capital, then lowercase letters and digits
2+++ pass |= m=MSG m
3+ ^
tests/golden/lex-typevar-bad-3/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Lexical rules: "Type variables: a capital, then lowercase letters and digits"; "`AB`, `MSG`, `Msg_x` and `Msg-x` are errors."
2+tests: an underscore inside a type variable
3+expect: error at 1:17 — a type variable is a capital, then lowercase letters and digits
tests/golden/lex-typevar-bad-3/source.jibbnew file+1
@@ -0,0 +1 @@
1+++ pass |= m=Msg_x m
tests/golden/lex-typevar-bad-3/tokens.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-typevar-bad-3/source.jibb:1:17: a type variable is a capital, then lowercase letters and digits
2+++ pass |= m=Msg_x m
3+ ^
tests/golden/lex-typevar-bad-3/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-typevar-bad-3/source.jibb:1:17: a type variable is a capital, then lowercase letters and digits
2+++ pass |= m=Msg_x m
3+ ^
tests/golden/lex-typevar-bad-4/about.txtnew file+3
@@ -0,0 +1,3 @@
1+source: Grammar tab, Lexical rules: "Type variables: a capital, then lowercase letters and digits"; "`AB`, `MSG`, `Msg_x` and `Msg-x` are errors."
2+tests: a hyphen inside a type variable, which a name may hold but a type variable may not
3+expect: error at 1:17 — a type variable is a capital, then lowercase letters and digits
tests/golden/lex-typevar-bad-4/source.jibbnew file+1
@@ -0,0 +1 @@
1+++ pass |= m=Msg-x m
tests/golden/lex-typevar-bad-4/tokens.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-typevar-bad-4/source.jibb:1:17: a type variable is a capital, then lowercase letters and digits
2+++ pass |= m=Msg-x m
3+ ^
tests/golden/lex-typevar-bad-4/tree.txtnew file+3
@@ -0,0 +1,3 @@
1+/tests/golden/lex-typevar-bad-4/source.jibb:1:17: a type variable is a capital, then lowercase letters and digits
2+++ pass |= m=Msg-x m
3+ ^
tests/golden/lex-typevar-ok-1/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: Grammar tab, Lexical rules: "Type variables: a capital, then lowercase letters and digits: `A`, `Msg`, `T2`."
2+tests: type variables of several letters and with digits, as generic parameters and in molds, beside a one-letter one; the printed type keeps each written name
3+expect: parses
4+expect-types: swap prints $-([key=Msg value=T2] [T2 Msg]) and same-one $-(A A)
tests/golden/lex-typevar-ok-1/source.jibbnew file+3
@@ -0,0 +1,3 @@
1++$ entry |$ [Key Value2] [key=Key value=Value2]
2+++ swap |= p=(entry Msg T2) [value.p key.p]
3+++ same-one |= x=A x
tests/golden/lex-typevar-ok-1/tokens.txtnew file+39
@@ -0,0 +1,39 @@
1+1:1 glyph +$
2+1:4 name entry
3+1:10 glyph |$
4+1:13 glyph [
5+1:14 tight tvar Key
6+1:18 tvar Value2
7+1:24 tight glyph ]
8+1:26 glyph [
9+1:27 tight name key
10+1:30 tight glyph =
11+1:31 tight tvar Key
12+1:35 name value
13+1:40 tight glyph =
14+1:41 tight tvar Value2
15+1:47 tight glyph ]
16+2:1 NEWLINE
17+2:1 glyph ++
18+2:4 name swap
19+2:9 glyph |=
20+2:12 name p
21+2:13 tight glyph =
22+2:14 tight glyph (
23+2:15 tight name entry
24+2:21 tvar Msg
25+2:25 tvar T2
26+2:27 tight glyph )
27+2:29 glyph [
28+2:30 tight wing value.p
29+2:38 wing key.p
30+2:43 tight glyph ]
31+3:1 NEWLINE
32+3:1 glyph ++
33+3:4 name same-one
34+3:13 glyph |=
35+3:16 name x
36+3:17 tight glyph =
37+3:18 tight tvar A
38+3:20 name x
39+3:21 NEWLINE
tests/golden/lex-typevar-ok-1/tree.txtnew file+15
@@ -0,0 +1,15 @@
1+(module
2+ (mold 1:1 entry
3+ (generic 1:10 Key Value2
4+ (cell 1:26
5+ (face 1:27 key (tvar 1:31 Key))
6+ (face 1:35 value (tvar 1:41 Value2)))))
7+ (value 2:1 swap
8+ (gate 2:9
9+ (face 2:12 p
10+ (apply 2:14 entry (tvar 2:21 Msg) (tvar 2:25 T2)))
11+ (tuple 2:29 (wing 2:30 value.p) (wing 2:38 key.p))))
12+ (value 3:1 same-one
13+ (gate 3:13
14+ (face 3:16 x (tvar 3:18 A))
15+ (wing 3:20 x))))
tests/golden/lex-typevar-ok-1/types.txtnew file+4
@@ -0,0 +1,4 @@
1+partial inference; module not checked
2++$ entry: not checked
3+++ swap: $-([key=Msg value=T2] [T2 Msg])
4+++ same-one: $-(A A)
tests/golden/module-import-api-scope-conflict/types.txt+7−1
@@ -1,2 +1,8 @@
11partial inference; module not checked
2−module has conflicting names: /ui/api/demo/jibb
2+import `same` shadows a prelude name
3+/ui/api/demo.jibb:2:1: conflicting import
4+/= same /ui/lib
5+^
6+/lib/jibb/prelude.jibb:7:1: prelude declaration
7+++ same |= x=A x
8+^
tests/golden/module-import-prelude-value-shadow/types.txt+7−1
@@ -1,2 +1,8 @@
11partial inference; module not checked
2−module has conflicting names: /ui/lib/jibb
2+definition `same` shadows a prelude name
3+/ui/lib.jibb:1:1: conflicting definition
4+++ same |=(x x)
5+^
6+/lib/jibb/prelude.jibb:7:1: prelude declaration
7+++ same |= x=A x
8+^
tests/golden/prelude-unit-list-transforms/types.txt+1−1
@@ -64,7 +64,7 @@ partial inference; module not checked
6464++ snip: sample mold is not supported by partial inference
6565++ rear: sample mold is not supported by partial inference
6666++ cork: $-([$-(A B) $-(B C)] $-(A C))
67−++ corl: $-([$-(A B) $-(C A)] $-(C B))
67+++ corl: $-([$-(B C) $-(A B)] $-(A C))
6868++ cury: $-([$-([A B] C) A] $-(B C))
6969++ curr: $-([$-([A B] C) B] $-(A C))
7070+$ cmd: cases proven disjoint; mold not checked
tests/golden/types-change-overlap-lines/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: Grammar, Expressions: "Two items that set the same field, or one a field inside the other's, as `m(cart=c open.cart=%.y)`, are an error."
2+tests: an open change whose third line sets a field holding its second line's field
3+expect: parses
4+expect-types: a partial inference report: the module error names both lines
tests/golden/types-change-overlap-lines/modules.txtnew file+1
@@ -0,0 +1 @@
1+# no module fixtures
tests/golden/types-change-overlap-lines/source.jibbnew file+7
@@ -0,0 +1,7 @@
1++$ cart [items=(list @t) open=?]
2++$ model [cart=cart note=@t]
3+++ overlap |= m=model
4+ m(
5+ note="x"
6+ open.cart=%.y
7+ cart=cart.m
tests/golden/types-change-overlap-lines/tokens.txtnew file+49
@@ -0,0 +1,49 @@
1+1:1 glyph +$
2+1:4 name cart
3+1:9 glyph [
4+1:10 tight name items
5+1:15 tight glyph =
6+1:16 tight glyph (
7+1:17 tight name list
8+1:22 aura @t
9+1:24 tight glyph )
10+1:26 name open
11+1:30 tight glyph =
12+1:31 tight glyph ?
13+1:32 tight glyph ]
14+2:1 NEWLINE
15+2:1 glyph +$
16+2:4 name model
17+2:10 glyph [
18+2:11 tight name cart
19+2:15 tight glyph =
20+2:16 tight name cart
21+2:21 name note
22+2:25 tight glyph =
23+2:26 tight aura @t
24+2:28 tight glyph ]
25+3:1 NEWLINE
26+3:1 glyph ++
27+3:4 name overlap
28+3:12 glyph |=
29+3:15 name m
30+3:16 tight glyph =
31+3:17 tight name model
32+4:3 INDENT
33+4:3 name m
34+4:4 tight glyph (
35+5:5 INDENT
36+5:5 name note
37+5:9 tight glyph =
38+5:10 tight str "x"
39+6:5 NEWLINE
40+6:5 wing open.cart
41+6:14 tight glyph =
42+6:15 tight lit %.y
43+7:5 NEWLINE
44+7:5 name cart
45+7:9 tight glyph =
46+7:10 tight wing cart.m
47+7:16 DEDENT
48+7:16 DEDENT
49+7:16 NEWLINE
tests/golden/types-change-overlap-lines/tree.txtnew file+18
@@ -0,0 +1,18 @@
1+(module
2+ (mold 1:1 cart
3+ (cell 1:9
4+ (face 1:10 items
5+ (apply 1:16 list (aura 1:22 @t)))
6+ (face 1:26 open (flag 1:31))))
7+ (mold 2:1 model
8+ (cell 2:10
9+ (face 2:11 cart (ref 2:16 cart))
10+ (face 2:21 note (aura 2:26 @t))))
11+ (value 3:1 overlap
12+ (gate 3:12
13+ (face 3:15 m (ref 3:17 model))
14+ (body 4:3
15+ (change 4:3 m
16+ (edit 5:5 note (str 5:10 "x"))
17+ (edit 6:5 open.cart (lit 6:15 %.y))
18+ (edit 7:5 cart (wing 7:10 cart.m)))))))
tests/golden/types-change-overlap-lines/types.txtnew file+8
@@ -0,0 +1,8 @@
1+partial inference; module not checked
2+change fields `open.cart` and `cart` overlap
3+/tests/golden/types-change-overlap-lines/source.jibb:6:5: first field
4+ open.cart=%.y
5+ ^
6+/tests/golden/types-change-overlap-lines/source.jibb:7:5: overlapping field
7+ cart=cart.m
8+ ^
tests/golden/types-change-overlap/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: Grammar, Expressions: "Two items that set the same field, or one a field inside the other's, as `m(cart=c open.cart=%.y)`, are an error."
2+tests: a change whose second item sets a field inside its first's, beside a change of two sibling fields
3+expect: parses
4+expect-types: a partial inference report: the module error names both items
tests/golden/types-change-overlap/modules.txtnew file+1
@@ -0,0 +1 @@
1+# no module fixtures
tests/golden/types-change-overlap/source.jibbnew file+4
@@ -0,0 +1,4 @@
1++$ cart [items=(list @t) open=?]
2++$ model [cart=cart note=@t]
3+++ fine |= m=model m(open.cart=%.y items.cart=~)
4+++ overlap |= m=model m(cart=cart.m open.cart=%.y)
tests/golden/types-change-overlap/tokens.txtnew file+57
@@ -0,0 +1,57 @@
1+1:1 glyph +$
2+1:4 name cart
3+1:9 glyph [
4+1:10 tight name items
5+1:15 tight glyph =
6+1:16 tight glyph (
7+1:17 tight name list
8+1:22 aura @t
9+1:24 tight glyph )
10+1:26 name open
11+1:30 tight glyph =
12+1:31 tight glyph ?
13+1:32 tight glyph ]
14+2:1 NEWLINE
15+2:1 glyph +$
16+2:4 name model
17+2:10 glyph [
18+2:11 tight name cart
19+2:15 tight glyph =
20+2:16 tight name cart
21+2:21 name note
22+2:25 tight glyph =
23+2:26 tight aura @t
24+2:28 tight glyph ]
25+3:1 NEWLINE
26+3:1 glyph ++
27+3:4 name fine
28+3:9 glyph |=
29+3:12 name m
30+3:13 tight glyph =
31+3:14 tight name model
32+3:20 name m
33+3:21 tight glyph (
34+3:22 tight wing open.cart
35+3:31 tight glyph =
36+3:32 tight lit %.y
37+3:36 wing items.cart
38+3:46 tight glyph =
39+3:47 tight lit ~
40+3:48 tight glyph )
41+4:1 NEWLINE
42+4:1 glyph ++
43+4:4 name overlap
44+4:12 glyph |=
45+4:15 name m
46+4:16 tight glyph =
47+4:17 tight name model
48+4:23 name m
49+4:24 tight glyph (
50+4:25 tight name cart
51+4:29 tight glyph =
52+4:30 tight wing cart.m
53+4:37 wing open.cart
54+4:46 tight glyph =
55+4:47 tight lit %.y
56+4:50 tight glyph )
57+4:51 NEWLINE
tests/golden/types-change-overlap/tree.txtnew file+22
@@ -0,0 +1,22 @@
1+(module
2+ (mold 1:1 cart
3+ (cell 1:9
4+ (face 1:10 items
5+ (apply 1:16 list (aura 1:22 @t)))
6+ (face 1:26 open (flag 1:31))))
7+ (mold 2:1 model
8+ (cell 2:10
9+ (face 2:11 cart (ref 2:16 cart))
10+ (face 2:21 note (aura 2:26 @t))))
11+ (value 3:1 fine
12+ (gate 3:9
13+ (face 3:12 m (ref 3:14 model))
14+ (change 3:20 m
15+ (edit 3:22 open.cart (lit 3:32 %.y))
16+ (edit 3:36 items.cart (lit 3:47 ~)))))
17+ (value 4:1 overlap
18+ (gate 4:12
19+ (face 4:15 m (ref 4:17 model))
20+ (change 4:23 m
21+ (edit 4:25 cart (wing 4:30 cart.m))
22+ (edit 4:37 open.cart (lit 4:47 %.y))))))
tests/golden/types-change-overlap/types.txtnew file+8
@@ -0,0 +1,8 @@
1+partial inference; module not checked
2+change fields `cart` and `open.cart` overlap
3+/tests/golden/types-change-overlap/source.jibb:4:25: first field
4+++ overlap |= m=model m(cart=cart.m open.cart=%.y)
5+ ^
6+/tests/golden/types-change-overlap/source.jibb:4:37: overlapping field
7+++ overlap |= m=model m(cart=cart.m open.cart=%.y)
8+ ^
tests/golden/types-change-repeated-wing/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: Grammar, Expressions: "Two items that set the same field, or one a field inside the other's, as `m(cart=c open.cart=%.y)`, are an error."
2+tests: a change that sets one field twice through the same wing
3+expect: parses
4+expect-types: a partial inference report: the module error names both items
tests/golden/types-change-repeated-wing/modules.txtnew file+1
@@ -0,0 +1 @@
1+# no module fixtures
tests/golden/types-change-repeated-wing/source.jibbnew file+3
@@ -0,0 +1,3 @@
1++$ cart [items=(list @t) open=?]
2++$ model [cart=cart note=@t]
3+++ repeated |= m=model m(open.cart=%.y open.cart=%.n)
tests/golden/types-change-repeated-wing/tokens.txtnew file+41
@@ -0,0 +1,41 @@
1+1:1 glyph +$
2+1:4 name cart
3+1:9 glyph [
4+1:10 tight name items
5+1:15 tight glyph =
6+1:16 tight glyph (
7+1:17 tight name list
8+1:22 aura @t
9+1:24 tight glyph )
10+1:26 name open
11+1:30 tight glyph =
12+1:31 tight glyph ?
13+1:32 tight glyph ]
14+2:1 NEWLINE
15+2:1 glyph +$
16+2:4 name model
17+2:10 glyph [
18+2:11 tight name cart
19+2:15 tight glyph =
20+2:16 tight name cart
21+2:21 name note
22+2:25 tight glyph =
23+2:26 tight aura @t
24+2:28 tight glyph ]
25+3:1 NEWLINE
26+3:1 glyph ++
27+3:4 name repeated
28+3:13 glyph |=
29+3:16 name m
30+3:17 tight glyph =
31+3:18 tight name model
32+3:24 name m
33+3:25 tight glyph (
34+3:26 tight wing open.cart
35+3:35 tight glyph =
36+3:36 tight lit %.y
37+3:40 wing open.cart
38+3:49 tight glyph =
39+3:50 tight lit %.n
40+3:53 tight glyph )
41+3:54 NEWLINE
tests/golden/types-change-repeated-wing/tree.txtnew file+16
@@ -0,0 +1,16 @@
1+(module
2+ (mold 1:1 cart
3+ (cell 1:9
4+ (face 1:10 items
5+ (apply 1:16 list (aura 1:22 @t)))
6+ (face 1:26 open (flag 1:31))))
7+ (mold 2:1 model
8+ (cell 2:10
9+ (face 2:11 cart (ref 2:16 cart))
10+ (face 2:21 note (aura 2:26 @t))))
11+ (value 3:1 repeated
12+ (gate 3:13
13+ (face 3:16 m (ref 3:18 model))
14+ (change 3:24 m
15+ (edit 3:26 open.cart (lit 3:36 %.y))
16+ (edit 3:40 open.cart (lit 3:50 %.n))))))
tests/golden/types-change-repeated-wing/types.txtnew file+8
@@ -0,0 +1,8 @@
1+partial inference; module not checked
2+change field `open.cart` is repeated
3+/tests/golden/types-change-repeated-wing/source.jibb:3:26: first field
4+++ repeated |= m=model m(open.cart=%.y open.cart=%.n)
5+ ^
6+/tests/golden/types-change-repeated-wing/source.jibb:3:40: repeated field
7+++ repeated |= m=model m(open.cart=%.y open.cart=%.n)
8+ ^
tests/golden/types-change-repeated/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: Grammar, Expressions: "Two items that set the same field, or one a field inside the other's, as `m(cart=c open.cart=%.y)`, are an error."
2+tests: a change that sets one named field twice, which was types-record-change-generic's `duplicate` and failed closed before wing items
3+expect: parses
4+expect-types: a partial inference report: the module error names both items
tests/golden/types-change-repeated/modules.txtnew file+1
@@ -0,0 +1 @@
1+# no module fixtures
tests/golden/types-change-repeated/source.jibbnew file+2
@@ -0,0 +1,2 @@
1++$ box |$ [A] [value=A keep=A]
2+++ duplicate |= [s=(box @t) v=@t] s(value=v value=v)
tests/golden/types-change-repeated/tokens.txtnew file+39
@@ -0,0 +1,39 @@
1+1:1 glyph +$
2+1:4 name box
3+1:8 glyph |$
4+1:11 glyph [
5+1:12 tight tvar A
6+1:13 tight glyph ]
7+1:15 glyph [
8+1:16 tight name value
9+1:21 tight glyph =
10+1:22 tight tvar A
11+1:24 name keep
12+1:28 tight glyph =
13+1:29 tight tvar A
14+1:30 tight glyph ]
15+2:1 NEWLINE
16+2:1 glyph ++
17+2:4 name duplicate
18+2:14 glyph |=
19+2:17 glyph [
20+2:18 tight name s
21+2:19 tight glyph =
22+2:20 tight glyph (
23+2:21 tight name box
24+2:25 aura @t
25+2:27 tight glyph )
26+2:29 name v
27+2:30 tight glyph =
28+2:31 tight aura @t
29+2:33 tight glyph ]
30+2:35 name s
31+2:36 tight glyph (
32+2:37 tight name value
33+2:42 tight glyph =
34+2:43 tight name v
35+2:45 name value
36+2:50 tight glyph =
37+2:51 tight name v
38+2:52 tight glyph )
39+2:53 NEWLINE
tests/golden/types-change-repeated/tree.txtnew file+15
@@ -0,0 +1,15 @@
1+(module
2+ (mold 1:1 box
3+ (generic 1:8 A
4+ (cell 1:15
5+ (face 1:16 value (tvar 1:22 A))
6+ (face 1:24 keep (tvar 1:29 A)))))
7+ (value 2:1 duplicate
8+ (gate 2:14
9+ (cell 2:17
10+ (face 2:18 s
11+ (apply 2:20 box (aura 2:25 @t)))
12+ (face 2:29 v (aura 2:31 @t)))
13+ (change 2:35 s
14+ (edit 2:37 value (wing 2:43 v))
15+ (edit 2:45 value (wing 2:51 v))))))
tests/golden/types-change-repeated/types.txtnew file+8
@@ -0,0 +1,8 @@
1+partial inference; module not checked
2+change field `value` is repeated
3+/tests/golden/types-change-repeated/source.jibb:2:37: first field
4+++ duplicate |= [s=(box @t) v=@t] s(value=v value=v)
5+ ^
6+/tests/golden/types-change-repeated/source.jibb:2:45: repeated field
7+++ duplicate |= [s=(box @t) v=@t] s(value=v value=v)
8+ ^
tests/golden/types-change-wing/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: Grammar, Expressions: "A change's item, inline or on a line, may name a wing instead, read through record fields only: `m(open.cart=(not open.cart.m))` sets field `open` of field `cart`, as Hoon's `m(open.cart x)`. Every value is computed from the original record."
2+tests: Wing items change nested record fields, beside named items and sibling fields, on the lines of an open change and under a wing target, and the result has the original record's type; values read the original record. A wing through a list, an atom or a unit, an unknown field at either end of a wing and a value of the wrong type, inline or on a line, are errors at the name or the item. A wing through a tuple or a capital, and a change of an unknown target, fail closed.
3+expect: parses
4+expect-types: a partial inference report
tests/golden/types-change-wing/modules.txtnew file+1
@@ -0,0 +1 @@
1+# no module fixtures
tests/golden/types-change-wing/source.jibbnew file+24
@@ -0,0 +1,24 @@
1++$ cart [items=(list @t) open=? deep=[level=@ud] pair=[@t @ud]]
2++$ model [cart=cart note=@t data=(unit @t)]
3++$ box |$ [A] [value=A]
4+++ flip-open |= m=model m(open.cart=(not open.cart.m))
5+++ siblings |= m=model m(open.cart=%.y items.cart=~ note="x" level.deep.cart=5)
6+++ original |= m=model m(level.deep.cart=(add 1 level.deep.cart.m) open.cart=open.cart.m)
7+++ lines |= m=model
8+ m(
9+ open.cart=%.n
10+ level.deep.cart=(add 1 level.deep.cart.m)
11+++ wing-target |= m=model cart.m(level.deep=1)
12+++ through-list |= m=model m(x.items.cart="a")
13+++ through-atom |= m=model m(x.note="a")
14+++ through-unit |= m=model m(u.data="a")
15+++ unknown-outer |= m=model m(open.carts=%.y)
16+++ unknown-inner |= m=model m(opened.cart=%.y)
17+++ wrong-value |= m=model m(open.cart="yes")
18+++ wrong-line |= m=model
19+ m(
20+ note="ok"
21+ level.deep.cart=~zod
22+++ through-tuple |= m=model m(x.pair.cart=1)
23+++ through-capital |= b=(box A) b(x.value=1)
24+++ unknown-target |= x x(a.b=1)
tests/golden/types-change-wing/tokens.txtnew file+289
@@ -0,0 +1,289 @@
1+1:1 glyph +$
2+1:4 name cart
3+1:9 glyph [
4+1:10 tight name items
5+1:15 tight glyph =
6+1:16 tight glyph (
7+1:17 tight name list
8+1:22 aura @t
9+1:24 tight glyph )
10+1:26 name open
11+1:30 tight glyph =
12+1:31 tight glyph ?
13+1:33 name deep
14+1:37 tight glyph =
15+1:38 tight glyph [
16+1:39 tight name level
17+1:44 tight glyph =
18+1:45 tight aura @ud
19+1:48 tight glyph ]
20+1:50 name pair
21+1:54 tight glyph =
22+1:55 tight glyph [
23+1:56 tight aura @t
24+1:59 aura @ud
25+1:62 tight glyph ]
26+1:63 tight glyph ]
27+2:1 NEWLINE
28+2:1 glyph +$
29+2:4 name model
30+2:10 glyph [
31+2:11 tight name cart
32+2:15 tight glyph =
33+2:16 tight name cart
34+2:21 name note
35+2:25 tight glyph =
36+2:26 tight aura @t
37+2:29 name data
38+2:33 tight glyph =
39+2:34 tight glyph (
40+2:35 tight name unit
41+2:40 aura @t
42+2:42 tight glyph )
43+2:43 tight glyph ]
44+3:1 NEWLINE
45+3:1 glyph +$
46+3:4 name box
47+3:8 glyph |$
48+3:11 glyph [
49+3:12 tight tvar A
50+3:13 tight glyph ]
51+3:15 glyph [
52+3:16 tight name value
53+3:21 tight glyph =
54+3:22 tight tvar A
55+3:23 tight glyph ]
56+4:1 NEWLINE
57+4:1 glyph ++
58+4:4 name flip-open
59+4:14 glyph |=
60+4:17 name m
61+4:18 tight glyph =
62+4:19 tight name model
63+4:25 name m
64+4:26 tight glyph (
65+4:27 tight wing open.cart
66+4:36 tight glyph =
67+4:37 tight glyph (
68+4:38 tight name not
69+4:42 wing open.cart.m
70+4:53 tight glyph )
71+4:54 tight glyph )
72+5:1 NEWLINE
73+5:1 glyph ++
74+5:4 name siblings
75+5:13 glyph |=
76+5:16 name m
77+5:17 tight glyph =
78+5:18 tight name model
79+5:24 name m
80+5:25 tight glyph (
81+5:26 tight wing open.cart
82+5:35 tight glyph =
83+5:36 tight lit %.y
84+5:40 wing items.cart
85+5:50 tight glyph =
86+5:51 tight lit ~
87+5:53 name note
88+5:57 tight glyph =
89+5:58 tight str "x"
90+5:62 wing level.deep.cart
91+5:77 tight glyph =
92+5:78 tight lit 5
93+5:79 tight glyph )
94+6:1 NEWLINE
95+6:1 glyph ++
96+6:4 name original
97+6:13 glyph |=
98+6:16 name m
99+6:17 tight glyph =
100+6:18 tight name model
101+6:24 name m
102+6:25 tight glyph (
103+6:26 tight wing level.deep.cart
104+6:41 tight glyph =
105+6:42 tight glyph (
106+6:43 tight name add
107+6:47 lit 1
108+6:49 wing level.deep.cart.m
109+6:66 tight glyph )
110+6:68 wing open.cart
111+6:77 tight glyph =
112+6:78 tight wing open.cart.m
113+6:89 tight glyph )
114+7:1 NEWLINE
115+7:1 glyph ++
116+7:4 name lines
117+7:10 glyph |=
118+7:13 name m
119+7:14 tight glyph =
120+7:15 tight name model
121+8:3 INDENT
122+8:3 name m
123+8:4 tight glyph (
124+9:5 INDENT
125+9:5 wing open.cart
126+9:14 tight glyph =
127+9:15 tight lit %.n
128+10:5 NEWLINE
129+10:5 wing level.deep.cart
130+10:20 tight glyph =
131+10:21 tight glyph (
132+10:22 tight name add
133+10:26 lit 1
134+10:28 wing level.deep.cart.m
135+10:45 tight glyph )
136+11:1 DEDENT
137+11:1 DEDENT
138+11:1 NEWLINE
139+11:1 glyph ++
140+11:4 name wing-target
141+11:16 glyph |=
142+11:19 name m
143+11:20 tight glyph =
144+11:21 tight name model
145+11:27 wing cart.m
146+11:33 tight glyph (
147+11:34 tight wing level.deep
148+11:44 tight glyph =
149+11:45 tight lit 1
150+11:46 tight glyph )
151+12:1 NEWLINE
152+12:1 glyph ++
153+12:4 name through-list
154+12:17 glyph |=
155+12:20 name m
156+12:21 tight glyph =
157+12:22 tight name model
158+12:28 name m
159+12:29 tight glyph (
160+12:30 tight wing x.items.cart
161+12:42 tight glyph =
162+12:43 tight str "a"
163+12:46 tight glyph )
164+13:1 NEWLINE
165+13:1 glyph ++
166+13:4 name through-atom
167+13:17 glyph |=
168+13:20 name m
169+13:21 tight glyph =
170+13:22 tight name model
171+13:28 name m
172+13:29 tight glyph (
173+13:30 tight wing x.note
174+13:36 tight glyph =
175+13:37 tight str "a"
176+13:40 tight glyph )
177+14:1 NEWLINE
178+14:1 glyph ++
179+14:4 name through-unit
180+14:17 glyph |=
181+14:20 name m
182+14:21 tight glyph =
183+14:22 tight name model
184+14:28 name m
185+14:29 tight glyph (
186+14:30 tight wing u.data
187+14:36 tight glyph =
188+14:37 tight str "a"
189+14:40 tight glyph )
190+15:1 NEWLINE
191+15:1 glyph ++
192+15:4 name unknown-outer
193+15:18 glyph |=
194+15:21 name m
195+15:22 tight glyph =
196+15:23 tight name model
197+15:29 name m
198+15:30 tight glyph (
199+15:31 tight wing open.carts
200+15:41 tight glyph =
201+15:42 tight lit %.y
202+15:45 tight glyph )
203+16:1 NEWLINE
204+16:1 glyph ++
205+16:4 name unknown-inner
206+16:18 glyph |=
207+16:21 name m
208+16:22 tight glyph =
209+16:23 tight name model
210+16:29 name m
211+16:30 tight glyph (
212+16:31 tight wing opened.cart
213+16:42 tight glyph =
214+16:43 tight lit %.y
215+16:46 tight glyph )
216+17:1 NEWLINE
217+17:1 glyph ++
218+17:4 name wrong-value
219+17:16 glyph |=
220+17:19 name m
221+17:20 tight glyph =
222+17:21 tight name model
223+17:27 name m
224+17:28 tight glyph (
225+17:29 tight wing open.cart
226+17:38 tight glyph =
227+17:39 tight str "yes"
228+17:44 tight glyph )
229+18:1 NEWLINE
230+18:1 glyph ++
231+18:4 name wrong-line
232+18:15 glyph |=
233+18:18 name m
234+18:19 tight glyph =
235+18:20 tight name model
236+19:3 INDENT
237+19:3 name m
238+19:4 tight glyph (
239+20:5 INDENT
240+20:5 name note
241+20:9 tight glyph =
242+20:10 tight str "ok"
243+21:5 NEWLINE
244+21:5 wing level.deep.cart
245+21:20 tight glyph =
246+21:21 tight lit ~zod
247+22:1 DEDENT
248+22:1 DEDENT
249+22:1 NEWLINE
250+22:1 glyph ++
251+22:4 name through-tuple
252+22:18 glyph |=
253+22:21 name m
254+22:22 tight glyph =
255+22:23 tight name model
256+22:29 name m
257+22:30 tight glyph (
258+22:31 tight wing x.pair.cart
259+22:42 tight glyph =
260+22:43 tight lit 1
261+22:44 tight glyph )
262+23:1 NEWLINE
263+23:1 glyph ++
264+23:4 name through-capital
265+23:20 glyph |=
266+23:23 name b
267+23:24 tight glyph =
268+23:25 tight glyph (
269+23:26 tight name box
270+23:30 tvar A
271+23:31 tight glyph )
272+23:33 name b
273+23:34 tight glyph (
274+23:35 tight wing x.value
275+23:42 tight glyph =
276+23:43 tight lit 1
277+23:44 tight glyph )
278+24:1 NEWLINE
279+24:1 glyph ++
280+24:4 name unknown-target
281+24:19 glyph |=
282+24:22 name x
283+24:24 name x
284+24:25 tight glyph (
285+24:26 tight wing a.b
286+24:29 tight glyph =
287+24:30 tight lit 1
288+24:31 tight glyph )
289+24:32 NEWLINE
tests/golden/types-change-wing/tree.txtnew file+111
@@ -0,0 +1,111 @@
1+(module
2+ (mold 1:1 cart
3+ (cell 1:9
4+ (face 1:10 items
5+ (apply 1:16 list (aura 1:22 @t)))
6+ (face 1:26 open (flag 1:31))
7+ (face 1:33 deep
8+ (cell 1:38
9+ (face 1:39 level (aura 1:45 @ud))))
10+ (face 1:50 pair
11+ (cell 1:55 (aura 1:56 @t) (aura 1:59 @ud)))))
12+ (mold 2:1 model
13+ (cell 2:10
14+ (face 2:11 cart (ref 2:16 cart))
15+ (face 2:21 note (aura 2:26 @t))
16+ (face 2:29 data
17+ (apply 2:34 unit (aura 2:40 @t)))))
18+ (mold 3:1 box
19+ (generic 3:8 A
20+ (cell 3:15
21+ (face 3:16 value (tvar 3:22 A)))))
22+ (value 4:1 flip-open
23+ (gate 4:14
24+ (face 4:17 m (ref 4:19 model))
25+ (change 4:25 m
26+ (edit 4:27 open.cart
27+ (group 4:37
28+ (call 4:38 (wing 4:38 not) (wing 4:42 open.cart.m)))))))
29+ (value 5:1 siblings
30+ (gate 5:13
31+ (face 5:16 m (ref 5:18 model))
32+ (change 5:24 m
33+ (edit 5:26 open.cart (lit 5:36 %.y))
34+ (edit 5:40 items.cart (lit 5:51 ~))
35+ (edit 5:53 note (str 5:58 "x"))
36+ (edit 5:62 level.deep.cart (lit 5:78 5)))))
37+ (value 6:1 original
38+ (gate 6:13
39+ (face 6:16 m (ref 6:18 model))
40+ (change 6:24 m
41+ (edit 6:26 level.deep.cart
42+ (group 6:42
43+ (call 6:43 (wing 6:43 add) (lit 6:47 1) (wing 6:49 level.deep.cart.m))))
44+ (edit 6:68 open.cart (wing 6:78 open.cart.m)))))
45+ (value 7:1 lines
46+ (gate 7:10
47+ (face 7:13 m (ref 7:15 model))
48+ (body 8:3
49+ (change 8:3 m
50+ (edit 9:5 open.cart (lit 9:15 %.n))
51+ (edit 10:5 level.deep.cart
52+ (group 10:21
53+ (call 10:22 (wing 10:22 add) (lit 10:26 1) (wing 10:28 level.deep.cart.m))))))))
54+ (value 11:1 wing-target
55+ (gate 11:16
56+ (face 11:19 m (ref 11:21 model))
57+ (change 11:27 cart.m
58+ (edit 11:34 level.deep (lit 11:45 1)))))
59+ (value 12:1 through-list
60+ (gate 12:17
61+ (face 12:20 m (ref 12:22 model))
62+ (change 12:28 m
63+ (edit 12:30 x.items.cart (str 12:43 "a")))))
64+ (value 13:1 through-atom
65+ (gate 13:17
66+ (face 13:20 m (ref 13:22 model))
67+ (change 13:28 m
68+ (edit 13:30 x.note (str 13:37 "a")))))
69+ (value 14:1 through-unit
70+ (gate 14:17
71+ (face 14:20 m (ref 14:22 model))
72+ (change 14:28 m
73+ (edit 14:30 u.data (str 14:37 "a")))))
74+ (value 15:1 unknown-outer
75+ (gate 15:18
76+ (face 15:21 m (ref 15:23 model))
77+ (change 15:29 m
78+ (edit 15:31 open.carts (lit 15:42 %.y)))))
79+ (value 16:1 unknown-inner
80+ (gate 16:18
81+ (face 16:21 m (ref 16:23 model))
82+ (change 16:29 m
83+ (edit 16:31 opened.cart (lit 16:43 %.y)))))
84+ (value 17:1 wrong-value
85+ (gate 17:16
86+ (face 17:19 m (ref 17:21 model))
87+ (change 17:27 m
88+ (edit 17:29 open.cart (str 17:39 "yes")))))
89+ (value 18:1 wrong-line
90+ (gate 18:15
91+ (face 18:18 m (ref 18:20 model))
92+ (body 19:3
93+ (change 19:3 m
94+ (edit 20:5 note (str 20:10 "ok"))
95+ (edit 21:5 level.deep.cart (lit 21:21 ~zod))))))
96+ (value 22:1 through-tuple
97+ (gate 22:18
98+ (face 22:21 m (ref 22:23 model))
99+ (change 22:29 m
100+ (edit 22:31 x.pair.cart (lit 22:43 1)))))
101+ (value 23:1 through-capital
102+ (gate 23:20
103+ (face 23:23 b
104+ (apply 23:25 box (tvar 23:30 A)))
105+ (change 23:33 b
106+ (edit 23:35 x.value (lit 23:43 1)))))
107+ (value 24:1 unknown-target
108+ (gate 24:19
109+ (bind 24:22 x)
110+ (change 24:24 x
111+ (edit 24:26 a.b (lit 24:30 1))))))
tests/golden/types-change-wing/types.txtnew file+46
@@ -0,0 +1,46 @@
1+partial inference; module not checked
2++$ cart: not checked
3++$ model: not checked
4++$ box: not checked
5+++ flip-open: $-([cart=[items=(list @t) [open=? [deep=[level=@ud] pair=[@t @ud]]]] [note=@t data=(unit @t)]] [cart=[items=(list @t) [open=? [deep=[level=@ud] pair=[@t @ud]]]] [note=@t data=(unit @t)]])
6+++ siblings: $-([cart=[items=(list @t) [open=? [deep=[level=@ud] pair=[@t @ud]]]] [note=@t data=(unit @t)]] [cart=[items=(list @t) [open=? [deep=[level=@ud] pair=[@t @ud]]]] [note=@t data=(unit @t)]])
7+++ original: $-([cart=[items=(list @t) [open=? [deep=[level=@ud] pair=[@t @ud]]]] [note=@t data=(unit @t)]] [cart=[items=(list @t) [open=? [deep=[level=@ud] pair=[@t @ud]]]] [note=@t data=(unit @t)]])
8+++ lines: $-([cart=[items=(list @t) [open=? [deep=[level=@ud] pair=[@t @ud]]]] [note=@t data=(unit @t)]] [cart=[items=(list @t) [open=? [deep=[level=@ud] pair=[@t @ud]]]] [note=@t data=(unit @t)]])
9+++ wing-target: $-([cart=[items=(list @t) [open=? [deep=[level=@ud] pair=[@t @ud]]]] [note=@t data=(unit @t)]] [items=(list @t) [open=? [deep=[level=@ud] pair=[@t @ud]]]])
10+++ through-list: change wing `x.items.cart` goes through `items`, which is not a record
11+/tests/golden/types-change-wing/source.jibb:12:32: field `items` has type (list @t)
12+++ through-list |= m=model m(x.items.cart="a")
13+ ^
14+++ through-atom: change wing `x.note` goes through `note`, which is not a record
15+/tests/golden/types-change-wing/source.jibb:13:32: field `note` has type @t
16+++ through-atom |= m=model m(x.note="a")
17+ ^
18+++ through-unit: change wing `u.data` goes through `data`, which is not a record
19+/tests/golden/types-change-wing/source.jibb:14:32: field `data`
20+++ through-unit |= m=model m(u.data="a")
21+ ^
22+++ unknown-outer: record has no field `carts`
23+/tests/golden/types-change-wing/source.jibb:15:36: unknown field
24+++ unknown-outer |= m=model m(open.carts=%.y)
25+ ^
26+++ unknown-inner: record has no field `opened`
27+/tests/golden/types-change-wing/source.jibb:16:31: unknown field
28+++ unknown-inner |= m=model m(opened.cart=%.y)
29+ ^
30+++ wrong-value: change field and replacement do not unify
31+/tests/golden/types-change-wing/source.jibb:17:29: expected replacement has type ?
32+++ wrong-value |= m=model m(open.cart="yes")
33+ ^
34+/tests/golden/types-change-wing/source.jibb:17:39: replacement has type @t
35+++ wrong-value |= m=model m(open.cart="yes")
36+ ^
37+++ wrong-line: change field and replacement do not unify
38+/tests/golden/types-change-wing/source.jibb:21:5: expected replacement has type @ud
39+ level.deep.cart=~zod
40+ ^
41+/tests/golden/types-change-wing/source.jibb:21:21: replacement has type @p
42+ level.deep.cart=~zod
43+ ^
44+++ through-tuple: change wing needs a known record in partial inference
45+++ through-capital: change wing needs a known record in partial inference
46+++ unknown-target: change target needs a known record in partial inference
tests/golden/types-constructor-context/types.txt+2−2
@@ -4,8 +4,8 @@ partial inference; module not checked
44+$ wrong-payload: cases proven disjoint; mold not checked
55+$ missing: cases proven disjoint; mold not checked
66+$ maybe: cases proven disjoint; mold not checked
7−++ call: $-($-(@t A) A)
8−++ call-ship: $-($-(@p A) A)
7+++ call: $-($-(@t M) M)
8+++ call-ship: $-($-(@p M) M)
99++ unknown: call constraint is not supported by partial inference
1010++ later-context: msg
1111++ named-alias: msg
tests/golden/types-generic-union-alias-face/types.txt+1−1
@@ -1,7 +1,7 @@
11partial inference; module not checked
22+$ relay: not checked
33++ make: $-(A (choice.base B A))
4−++ reveal: $-((choice.base A B) (choice.base A B))
4+++ reveal: $-((choice.base B A) (choice.base B A))
55++ with-text: (choice.base @p @t)
66++ with-ship: cast mold and expression type do not unify
77/tests/golden/types-generic-union-alias-face/source.jibb:6:17: cast mold
tests/golden/types-generic-union-alias/types.txt+1−1
@@ -4,7 +4,7 @@ partial inference; module not checked
44+$ repeat: not checked
55+$ extra: not checked
66++ reverse-value: (choice @p @t)
7−++ reverse-gate: $-((choice A B) (choice A B))
7+++ reverse-gate: $-((choice B A) (choice B A))
88++ repeat-gate: $-((choice A A) (choice A A))
99++ repeated-call: distinct type variables `A` and `B` must not be forced equal; use the same capital for a shared type
1010/tests/golden/types-generic-union-alias/source.jibb:10:31: first type variable
tests/golden/types-generic-union-local/types.txt+1−1
@@ -11,7 +11,7 @@ partial inference; module not checked
1111++ phantom-gate: (phantom $-(@t @p))
1212++ identity: $-((choice A B) (choice A B))
1313++ repeated: $-((choice A A) (choice A A))
14−++ reverse: $-((choice A B) (choice A B))
14+++ reverse: $-((choice B A) (choice B A))
1515++ first: (choice @t @p)
1616++ second: (choice @t @p)
1717++ third: (choice @p @t)
tests/golden/types-prelude-generic-alias/types.txt+1−1
@@ -5,7 +5,7 @@ partial inference; module not checked
55+$ fixed: not checked
66++ direct: $-((each A B) (each A B))
77++ alias-id: $-((each A B) (each A B))
8−++ reversed: $-((each A B) (each A B))
8+++ reversed: $-((each B A) (each B A))
99++ reversed-concrete: $-((each @p @t) (each @p @t))
1010++ repeated-id: $-((each A A) (each A A))
1111++ fixed-id: $-((each A @p) (each A @p))
tests/golden/types-prelude-lead-late/types.txt+1−1
@@ -1,7 +1,7 @@
11partial inference; module not checked
22++ text-ship: [@t @p]
33++ ship-text: [@p @t]
4−++ first-fn: $-(A [@t A])
4+++ first-fn: $-(B [@t B])
55++ generic-lead: $-([x=A y=B] [A B])
66++ generic-late: $-([x=A y=B] [B A])
77++ generic-gate: $-([f=$-(A B) x=C] [$-(A B) C])
tests/golden/types-prelude-list-functions/types.txt+1−1
@@ -20,7 +20,7 @@ partial inference; module not checked
2020++ turn-nested: (list (list @t))
2121++ turn-import: (list @p)
2222++ turn-mismatch: call's sample and argument types do not unify
23−/tests/golden/types-prelude-list-functions/source.jibb:18:19: called gate has type $-([(list @t) $-(@t A)] (list A))
23+/tests/golden/types-prelude-list-functions/source.jibb:18:19: called gate has type $-([(list @t) $-(@t B)] (list B))
2424++ turn-mismatch (turn ~["a"] |=(x (^- @p x)))
2525 ^
2626/tests/golden/types-prelude-list-functions/source.jibb:18:31: argument has type $-(@p @p)
tests/golden/types-prelude-ui/types.txt+21−21
@@ -1,27 +1,27 @@
11partial inference; module not checked
22+$ msg: cases proven disjoint; mold not checked
33+$ model: not checked
4−++ row-scheme: $-([attrs=(list attr) kids=(list (element A))] (element A))
5−++ column-scheme: $-([attrs=(list attr) kids=(list (element A))] (element A))
6−++ wrap-scheme: $-([attrs=(list attr) kids=(list (element A))] (element A))
7−++ stack-scheme: $-([attrs=(list attr) kids=(list (element A))] (element A))
8−++ el-scheme: $-([attrs=(list attr) kid=(element A)] (element A))
9−++ para-scheme: $-((list (element A)) (element A))
10−++ text-scheme: $-(@t (element A))
11−++ heading-scheme: $-([level=@ud words=@t] (element A))
12−++ each-scheme: $-((list [key=A el=(element B)]) (element B))
13−++ table-scheme: $-([columns=(list [header=@t [width=length align=align]]) rows=(list [key=A cells=(list (element B))])] (element B))
14−++ image-scheme: $-([source=qath description=@t] (element A))
15−++ image-unsafe-scheme: $-([source=[url=@t [width=@ud height=@ud]] description=@t] (element A))
16−++ link-scheme: $-([target=qath label=@t] (element A))
17−++ link-unsafe-scheme: $-([target=@t label=@t] (element A))
18−++ button-scheme: $-([label=@t message=A] (element A))
19−++ toggle-scheme: $-([on=? [label=@t message=A]] (element A))
20−++ field-scheme: $-([label=@t [value=@t reply=$-(@t A)]] (element A))
21−++ form-scheme: $-([message=A kids=(list (element A))] (element A))
22−++ island-scheme: $-([p=[init=$-(A B) [update=$-([C B] [B (list (cmd C))]) [view=$-(B (element C)) subs=$-(B (list (sub C)))]]] data=A] (element !!))
23−++ program-scheme: $-([init=$-(A B) [update=$-([C B] [B (list (cmd C))]) [view=$-(B (element C)) subs=$-(B (list (sub C)))]]] [init=$-(A B) [update=$-([C B] [B (list (cmd C))]) [view=$-(B (element C)) subs=$-(B (list (sub C)))]]])
24−++ page-scheme: $-([load=$-(A (ask B)) view=$-(B (element !!))] [load=$-(A (ask B)) view=$-(B (element !!))])
4+++ row-scheme: $-([attrs=(list attr) kids=(list (element M))] (element M))
5+++ column-scheme: $-([attrs=(list attr) kids=(list (element M))] (element M))
6+++ wrap-scheme: $-([attrs=(list attr) kids=(list (element M))] (element M))
7+++ stack-scheme: $-([attrs=(list attr) kids=(list (element M))] (element M))
8+++ el-scheme: $-([attrs=(list attr) kid=(element M)] (element M))
9+++ para-scheme: $-((list (element M)) (element M))
10+++ text-scheme: $-(@t (element M))
11+++ heading-scheme: $-([level=@ud words=@t] (element M))
12+++ each-scheme: $-((list [key=K el=(element M)]) (element M))
13+++ table-scheme: $-([columns=(list [header=@t [width=length align=align]]) rows=(list [key=K cells=(list (element M))])] (element M))
14+++ image-scheme: $-([source=qath description=@t] (element M))
15+++ image-unsafe-scheme: $-([source=[url=@t [width=@ud height=@ud]] description=@t] (element M))
16+++ link-scheme: $-([target=qath label=@t] (element M))
17+++ link-unsafe-scheme: $-([target=@t label=@t] (element M))
18+++ button-scheme: $-([label=@t message=M] (element M))
19+++ toggle-scheme: $-([on=? [label=@t message=M]] (element M))
20+++ field-scheme: $-([label=@t [value=@t reply=$-(@t M)]] (element M))
21+++ form-scheme: $-([message=M kids=(list (element M))] (element M))
22+++ island-scheme: $-([p=[init=$-(Data Model) [update=$-([Msg Model] [Model (list (cmd Msg))]) [view=$-(Model (element Msg)) subs=$-(Model (list (sub Msg)))]]] data=Data] (element !!))
23+++ program-scheme: $-([init=$-(Data Model) [update=$-([Msg Model] [Model (list (cmd Msg))]) [view=$-(Model (element Msg)) subs=$-(Model (list (sub Msg)))]]] [init=$-(Data Model) [update=$-([Msg Model] [Model (list (cmd Msg))]) [view=$-(Model (element Msg)) subs=$-(Model (list (sub Msg)))]]])
24+++ page-scheme: $-([load=$-(Params (ask Data)) view=$-(Data (element !!))] [load=$-(Params (ask Data)) view=$-(Data (element !!))])
2525++ static-text: (element !!)
2626++ raw-text: (element !!)
2727++ static-ui: (element !!)
tests/golden/types-proj-explicit-context/types.txt+2−2
@@ -6,7 +6,7 @@ partial inference; module not checked
66++ from-call: [a=@t b=@p]
77++ into-call: @t
88++ nested: [result=[a=@t b=@p] done=?]
9−++ generic: $-(A [a=@t b=A])
9+++ generic: $-(B [a=@t b=B])
1010++ no-context: proj needs an expected record type
1111++ unknown-target: proj needs an expected record type
1212++ missing: proj constraint needs unsupported inference
@@ -25,7 +25,7 @@ partial inference; module not checked
2525++ two-arguments: name is not available to partial inference
2626++ one-field: [a=@t]
2727++ exact-record: [a=@t b=@p]
28−++ positional-generic: $-([a=@t b=A] @t)
28+++ positional-generic: $-([a=@t b=B] @t)
2929++ positional-generic-call: @t
3030++ subsequence: [a=@t c=?]
3131++ reversed: proj constraint needs unsupported inference
tests/golden/types-proj-nested-no-implicit/types.txt+3−3
@@ -1,7 +1,7 @@
11partial inference; module not checked
2−++ sink-unit: $-((unit [a=@t b=A]) @t)
2+++ sink-unit: $-((unit [a=@t b=B]) @t)
33++ unit-bad: unit payload constraint is not supported by partial inference
4−++ sink-list: $-((list [a=@t b=A]) @t)
4+++ sink-list: $-((list [a=@t b=B]) @t)
55++ list-bad: list item constraint is not supported by partial inference
6−++ sink-nested: $-([one=[a=@t b=A] other=@ud] @t)
6+++ sink-nested: $-([one=[a=@t b=B] other=@ud] @t)
77++ nested-bad: call constraint is not supported by partial inference
tests/golden/types-proj-reserved-imported-definition/types.txt+4−1
@@ -1,2 +1,5 @@
11partial inference; module not checked
2−module has conflicting names: /ui/lib/jibb
2+`proj` is reserved and cannot be bound
3+/ui/lib.jibb:1:1: reserved name
4+++ proj |= x=@t x
5+^
tests/golden/types-record-change-generic/about.txt+1−1
@@ -1,4 +1,4 @@
11source: Grammar, Molds: "Type variables are capitals, generalized per `++`"; Modules: no name may shadow one already in scope.
2−tests: A replacement preserves shared generic field variables; forcing a written capital concrete stays unsupported and a mismatched replacement reports both sites. Unrelated tags and invalid expressions stay visible; repeated edits fail closed.
2+tests: A replacement preserves shared generic field variables; forcing a written capital concrete stays unsupported and a mismatched replacement reports both sites. Unrelated tags and invalid expressions stay visible. A repeated edit is now a module error, tested in types-change-repeated.
33expect: parses
44expect-types: a partial inference report
tests/golden/types-record-change-generic/source.jibb−1
@@ -2,7 +2,6 @@
22++ keep |= [s=(box A) v=A] s(value=v)
33++ force |= s=(box A) s(value="constant")
44++ mixed |= [s=(box @t) v=@p] s(value=v)
5−++ duplicate |= [s=(box @t) v=@t] s(value=v value=v)
65++ unrelated |= [s=(box @t) v=@t]
76 ~& %orphan
87 s(value=v)
tests/golden/types-record-change-generic/tokens.txt+35−59
@@ -72,7 +72,7 @@
72724:40 tight glyph )
73735:1 NEWLINE
74745:1 glyph ++
75−5:4 name duplicate
75+5:4 name unrelated
76765:14 glyph |=
77775:17 glyph [
78785:18 tight name s
@@ -85,61 +85,37 @@
85855:30 tight glyph =
86865:31 tight aura @t
87875:33 tight glyph ]
88−5:35 name s
89−5:36 tight glyph (
90−5:37 tight name value
91−5:42 tight glyph =
92−5:43 tight name v
93−5:45 name value
94−5:50 tight glyph =
95−5:51 tight name v
96−5:52 tight glyph )
97−6:1 NEWLINE
98−6:1 glyph ++
99−6:4 name unrelated
100−6:14 glyph |=
101−6:17 glyph [
102−6:18 tight name s
103−6:19 tight glyph =
104−6:20 tight glyph (
105−6:21 tight name box
106−6:25 aura @t
107−6:27 tight glyph )
108−6:29 name v
109−6:30 tight glyph =
110−6:31 tight aura @t
111−6:33 tight glyph ]
112−7:3 INDENT
113−7:3 glyph ~&
114−7:6 lit %orphan
115−8:5 INDENT
116−8:5 name s
117−8:6 tight glyph (
118−8:7 tight name value
119−8:12 tight glyph =
120−8:13 tight name v
121−8:14 tight glyph )
122−9:1 DEDENT
123−9:1 DEDENT
124−9:1 NEWLINE
125−9:1 glyph ++
126−9:4 name invalid-value
127−9:18 glyph |=
128−9:21 glyph [
129−9:22 tight name s
130−9:23 tight glyph =
131−9:24 tight glyph (
132−9:25 tight name box
133−9:29 aura @t
134−9:31 tight glyph )
135−9:33 name v
136−9:34 tight glyph =
137−9:35 tight aura @t
138−9:37 tight glyph ]
139−9:39 name s
140−9:40 tight glyph (
141−9:41 tight name value
142−9:46 tight glyph =
143−9:47 tight name missing
144−9:54 tight glyph )
145−9:55 NEWLINE
88+6:3 INDENT
89+6:3 glyph ~&
90+6:6 lit %orphan
91+7:5 INDENT
92+7:5 name s
93+7:6 tight glyph (
94+7:7 tight name value
95+7:12 tight glyph =
96+7:13 tight name v
97+7:14 tight glyph )
98+8:1 DEDENT
99+8:1 DEDENT
100+8:1 NEWLINE
101+8:1 glyph ++
102+8:4 name invalid-value
103+8:18 glyph |=
104+8:21 glyph [
105+8:22 tight name s
106+8:23 tight glyph =
107+8:24 tight glyph (
108+8:25 tight name box
109+8:29 aura @t
110+8:31 tight glyph )
111+8:33 name v
112+8:34 tight glyph =
113+8:35 tight aura @t
114+8:37 tight glyph ]
115+8:39 name s
116+8:40 tight glyph (
117+8:41 tight name value
118+8:46 tight glyph =
119+8:47 tight name missing
120+8:54 tight glyph )
121+8:55 NEWLINE
tests/golden/types-record-change-generic/tree.txt+15−24
@@ -26,32 +26,23 @@
2626 (face 4:25 v (aura 4:27 @p)))
2727 (change 4:31 s
2828 (edit 4:33 value (wing 4:39 v)))))
29− (value 5:1 duplicate
29+ (value 5:1 unrelated
3030 (gate 5:14
3131 (cell 5:17
3232 (face 5:18 s
3333 (apply 5:20 box (aura 5:25 @t)))
3434 (face 5:29 v (aura 5:31 @t)))
35− (change 5:35 s
36− (edit 5:37 value (wing 5:43 v))
37− (edit 5:45 value (wing 5:51 v)))))
38− (value 6:1 unrelated
39− (gate 6:14
40− (cell 6:17
41− (face 6:18 s
42− (apply 6:20 box (aura 6:25 @t)))
43− (face 6:29 v (aura 6:31 @t)))
44− (body 7:3
45− (trace 7:3
46− (lit 7:6 %orphan)
47− (body 8:5
48− (change 8:5 s
49− (edit 8:7 value (wing 8:13 v))))))))
50− (value 9:1 invalid-value
51− (gate 9:18
52− (cell 9:21
53− (face 9:22 s
54− (apply 9:24 box (aura 9:29 @t)))
55− (face 9:33 v (aura 9:35 @t)))
56− (change 9:39 s
57− (edit 9:41 value (wing 9:47 missing))))))
35+ (body 6:3
36+ (trace 6:3
37+ (lit 6:6 %orphan)
38+ (body 7:5
39+ (change 7:5 s
40+ (edit 7:7 value (wing 7:13 v))))))))
41+ (value 8:1 invalid-value
42+ (gate 8:18
43+ (cell 8:21
44+ (face 8:22 s
45+ (apply 8:24 box (aura 8:29 @t)))
46+ (face 8:33 v (aura 8:35 @t)))
47+ (change 8:39 s
48+ (edit 8:41 value (wing 8:47 missing))))))
tests/golden/types-record-change-generic/types.txt−1
@@ -9,6 +9,5 @@ partial inference; module not checked
99/tests/golden/types-record-change-generic/source.jibb:4:39: replacement has type @p
1010++ mixed |= [s=(box @t) v=@p] s(value=v)
1111 ^
12−++ duplicate: repeated change fields are not supported by partial inference
1312++ unrelated: tag needs context in partial inference
1413++ invalid-value: name is not available to partial inference
tests/golden/types-recursion-scc-groups/types.txt+1−1
@@ -5,6 +5,6 @@ partial inference; module not checked
55++ fourth: $-(@p A)
66++ fifth: $-(@p A)
77++ poly-a: $-(A B)
8−++ poly-b: $-(A B)
8+++ poly-b: $-(B A)
99++ call-text: A
1010++ call-ship: A
tests/golden/types-typevar-names/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: Grammar tab, Types: "Printed types show a type variable by the name it was written with"; "A variable from a gate a `++` uses keeps that gate's name"; "When several named variables become one, a capital written in the `++` names it; otherwise the one made first does".
2+tests: written names of several letters print as written; the prelude's program, island and page keep Data, Model, Msg and Params through instantiation; a written capital names its variable when it meets a called gate's atom or gate-free variable; button's M yields to a written Msg; joined prelude variables take the first made, cork's A and turn's A; a call note and a forced-equal error name the written variables
3+expect: parses
4+expect-types: id $-(Msg Msg); make and embed with Data, Model and Msg; load-page with Params and Data; narrow where Num is an atom other than ?; keyed where Key contains no gates; composed $-(A A); applied (list A); use-hunt's note names Num; forced reports Key and Value
tests/golden/types-typevar-names/modules.txtnew file+1
@@ -0,0 +1 @@
1+# no module fixtures
tests/golden/types-typevar-names/source.jibbnew file+14
@@ -0,0 +1,14 @@
1+++ id |= x=Msg x
2+++ swap |= [a=Key b=Value] [b a]
3+++ make program
4+++ embed island
5+++ load-page page
6+++ narrow |= [lo=Num hi=Num] (add lo hi)
7+++ keyed |= [a=Key b=Key] (eq a b)
8+++ button-of |= m=Msg (button "go" m)
9+++ mapped |= xs=(list Item) (turn xs same)
10+++ composed (cork same same)
11+++ applied (turn ~ same)
12+++ before |= [x=Num y=Num] (gth y x)
13+++ use-hunt (hunt before `1 `2)
14+++ forced |= [a=Key b=Value] ^- (list Key) ~[a b]
tests/golden/types-typevar-names/tokens.txtnew file+162
@@ -0,0 +1,162 @@
1+1:1 glyph ++
2+1:4 name id
3+1:7 glyph |=
4+1:10 name x
5+1:11 tight glyph =
6+1:12 tight tvar Msg
7+1:16 name x
8+2:1 NEWLINE
9+2:1 glyph ++
10+2:4 name swap
11+2:9 glyph |=
12+2:12 glyph [
13+2:13 tight name a
14+2:14 tight glyph =
15+2:15 tight tvar Key
16+2:19 name b
17+2:20 tight glyph =
18+2:21 tight tvar Value
19+2:26 tight glyph ]
20+2:28 glyph [
21+2:29 tight name b
22+2:31 name a
23+2:32 tight glyph ]
24+3:1 NEWLINE
25+3:1 glyph ++
26+3:4 name make
27+3:9 name program
28+4:1 NEWLINE
29+4:1 glyph ++
30+4:4 name embed
31+4:10 name island
32+5:1 NEWLINE
33+5:1 glyph ++
34+5:4 name load-page
35+5:14 name page
36+6:1 NEWLINE
37+6:1 glyph ++
38+6:4 name narrow
39+6:11 glyph |=
40+6:14 glyph [
41+6:15 tight name lo
42+6:17 tight glyph =
43+6:18 tight tvar Num
44+6:22 name hi
45+6:24 tight glyph =
46+6:25 tight tvar Num
47+6:28 tight glyph ]
48+6:30 glyph (
49+6:31 tight name add
50+6:35 name lo
51+6:38 name hi
52+6:40 tight glyph )
53+7:1 NEWLINE
54+7:1 glyph ++
55+7:4 name keyed
56+7:10 glyph |=
57+7:13 glyph [
58+7:14 tight name a
59+7:15 tight glyph =
60+7:16 tight tvar Key
61+7:20 name b
62+7:21 tight glyph =
63+7:22 tight tvar Key
64+7:25 tight glyph ]
65+7:27 glyph (
66+7:28 tight name eq
67+7:31 name a
68+7:33 name b
69+7:34 tight glyph )
70+8:1 NEWLINE
71+8:1 glyph ++
72+8:4 name button-of
73+8:14 glyph |=
74+8:17 name m
75+8:18 tight glyph =
76+8:19 tight tvar Msg
77+8:23 glyph (
78+8:24 tight name button
79+8:31 str "go"
80+8:36 name m
81+8:37 tight glyph )
82+9:1 NEWLINE
83+9:1 glyph ++
84+9:4 name mapped
85+9:11 glyph |=
86+9:14 name xs
87+9:16 tight glyph =
88+9:17 tight glyph (
89+9:18 tight name list
90+9:23 tvar Item
91+9:27 tight glyph )
92+9:29 glyph (
93+9:30 tight name turn
94+9:35 name xs
95+9:38 name same
96+9:42 tight glyph )
97+10:1 NEWLINE
98+10:1 glyph ++
99+10:4 name composed
100+10:13 glyph (
101+10:14 tight name cork
102+10:19 name same
103+10:24 name same
104+10:28 tight glyph )
105+11:1 NEWLINE
106+11:1 glyph ++
107+11:4 name applied
108+11:12 glyph (
109+11:13 tight name turn
110+11:18 lit ~
111+11:20 name same
112+11:24 tight glyph )
113+12:1 NEWLINE
114+12:1 glyph ++
115+12:4 name before
116+12:11 glyph |=
117+12:14 glyph [
118+12:15 tight name x
119+12:16 tight glyph =
120+12:17 tight tvar Num
121+12:21 name y
122+12:22 tight glyph =
123+12:23 tight tvar Num
124+12:26 tight glyph ]
125+12:28 glyph (
126+12:29 tight name gth
127+12:33 name y
128+12:35 name x
129+12:36 tight glyph )
130+13:1 NEWLINE
131+13:1 glyph ++
132+13:4 name use-hunt
133+13:13 glyph (
134+13:14 tight name hunt
135+13:19 name before
136+13:26 glyph `
137+13:27 tight lit 1
138+13:29 glyph `
139+13:30 tight lit 2
140+13:31 tight glyph )
141+14:1 NEWLINE
142+14:1 glyph ++
143+14:4 name forced
144+14:11 glyph |=
145+14:14 glyph [
146+14:15 tight name a
147+14:16 tight glyph =
148+14:17 tight tvar Key
149+14:21 name b
150+14:22 tight glyph =
151+14:23 tight tvar Value
152+14:28 tight glyph ]
153+14:30 glyph ^-
154+14:33 glyph (
155+14:34 tight name list
156+14:39 tvar Key
157+14:42 tight glyph )
158+14:44 glyph ~[
159+14:46 tight name a
160+14:48 name b
161+14:49 tight glyph ]
162+14:50 NEWLINE
tests/golden/types-typevar-names/tree.txtnew file+67
@@ -0,0 +1,67 @@
1+(module
2+ (value 1:1 id
3+ (gate 1:7
4+ (face 1:10 x (tvar 1:12 Msg))
5+ (wing 1:16 x)))
6+ (value 2:1 swap
7+ (gate 2:9
8+ (cell 2:12
9+ (face 2:13 a (tvar 2:15 Key))
10+ (face 2:19 b (tvar 2:21 Value)))
11+ (tuple 2:28 (wing 2:29 b) (wing 2:31 a))))
12+ (value 3:1 make (wing 3:9 program))
13+ (value 4:1 embed (wing 4:10 island))
14+ (value 5:1 load-page (wing 5:14 page))
15+ (value 6:1 narrow
16+ (gate 6:11
17+ (cell 6:14
18+ (face 6:15 lo (tvar 6:18 Num))
19+ (face 6:22 hi (tvar 6:25 Num)))
20+ (group 6:30
21+ (call 6:31 (wing 6:31 add) (wing 6:35 lo) (wing 6:38 hi)))))
22+ (value 7:1 keyed
23+ (gate 7:10
24+ (cell 7:13
25+ (face 7:14 a (tvar 7:16 Key))
26+ (face 7:20 b (tvar 7:22 Key)))
27+ (group 7:27
28+ (call 7:28 (wing 7:28 eq) (wing 7:31 a) (wing 7:33 b)))))
29+ (value 8:1 button-of
30+ (gate 8:14
31+ (face 8:17 m (tvar 8:19 Msg))
32+ (group 8:23
33+ (call 8:24 (wing 8:24 button) (str 8:31 "go") (wing 8:36 m)))))
34+ (value 9:1 mapped
35+ (gate 9:11
36+ (face 9:14 xs
37+ (apply 9:17 list (tvar 9:23 Item)))
38+ (group 9:29
39+ (call 9:30 (wing 9:30 turn) (wing 9:35 xs) (wing 9:38 same)))))
40+ (value 10:1 composed
41+ (group 10:13
42+ (call 10:14 (wing 10:14 cork) (wing 10:19 same) (wing 10:24 same))))
43+ (value 11:1 applied
44+ (group 11:12
45+ (call 11:13 (wing 11:13 turn) (lit 11:18 ~) (wing 11:20 same))))
46+ (value 12:1 before
47+ (gate 12:11
48+ (cell 12:14
49+ (face 12:15 x (tvar 12:17 Num))
50+ (face 12:21 y (tvar 12:23 Num)))
51+ (group 12:28
52+ (call 12:29 (wing 12:29 gth) (wing 12:33 y) (wing 12:35 x)))))
53+ (value 13:1 use-hunt
54+ (group 13:13
55+ (call 13:14
56+ (wing 13:14 hunt)
57+ (wing 13:19 before)
58+ (unit 13:26 (lit 13:27 1))
59+ (unit 13:29 (lit 13:30 2)))))
60+ (value 14:1 forced
61+ (gate 14:11
62+ (cell 14:14
63+ (face 14:15 a (tvar 14:17 Key))
64+ (face 14:21 b (tvar 14:23 Value)))
65+ (cast 14:30
66+ (apply 14:33 list (tvar 14:39 Key))
67+ (list 14:44 (wing 14:46 a) (wing 14:48 b))))))
tests/golden/types-typevar-names/types.txtnew file+27
@@ -0,0 +1,27 @@
1+partial inference; module not checked
2+++ id: $-(Msg Msg)
3+++ swap: $-([a=Key b=Value] [Value Key])
4+++ make: $-([init=$-(Data Model) [update=$-([Msg Model] [Model (list (cmd Msg))]) [view=$-(Model (element Msg)) subs=$-(Model (list (sub Msg)))]]] [init=$-(Data Model) [update=$-([Msg Model] [Model (list (cmd Msg))]) [view=$-(Model (element Msg)) subs=$-(Model (list (sub Msg)))]]])
5+++ embed: $-([p=[init=$-(Data Model) [update=$-([Msg Model] [Model (list (cmd Msg))]) [view=$-(Model (element Msg)) subs=$-(Model (list (sub Msg)))]]] data=Data] (element !!))
6+++ load-page: $-([load=$-(Params (ask Data)) view=$-(Data (element !!))] [load=$-(Params (ask Data)) view=$-(Data (element !!))])
7+++ narrow: $-([lo=Num hi=Num] Num) where Num is an atom other than ?
8+++ keyed: $-([a=Key b=Key] ?) where Key contains no gates
9+++ button-of: $-(Msg (element Msg))
10+++ mapped: $-((list Item) (list Item))
11+++ composed: $-(A A)
12+++ applied: (list A)
13+++ before: $-([x=Num y=Num] ?) where Num is an atom
14+++ use-hunt: call's sample and argument types do not unify
15+/tests/golden/types-typevar-names/source.jibb:13:14: called gate
16+++ use-hunt (hunt before `1 `2)
17+ ^
18+/tests/golden/types-typevar-names/source.jibb:13:19: argument has type $-([x=Num y=Num] ?) where Num is an atom
19+++ use-hunt (hunt before `1 `2)
20+ ^
21+++ forced: distinct type variables `Key` and `Value` must not be forced equal; use the same capital for a shared type
22+/tests/golden/types-typevar-names/source.jibb:14:17: first type variable
23+++ forced |= [a=Key b=Value] ^- (list Key) ~[a b]
24+ ^
25+/tests/golden/types-typevar-names/source.jibb:14:23: second type variable
26+++ forced |= [a=Key b=Value] ^- (list Key) ~[a b]
27+ ^
tests/golden/types-typevar-print/about.txtnew file+4
@@ -0,0 +1,4 @@
1+source: Grammar tab, Types: "A variable with no name prints as a letter that no other variable in the same type uses".
2+tests: an unnamed variable prints as the first letter no written name in the same type spells; two variables with one name print the second as a letter; names with digits; a local ++ shares the enclosing ++'s written name
3+expect: parses
4+expect-types: same2 $-(A A); with-a $-(A [A $-(B B)]); with-b $-(B [$-(A A) B]); two $-(* [$-(Msg Msg) $-(A A)]); letters $-(Msg [Msg [$-(A A) $-(B B)]]); outer $-(Item Item)
tests/golden/types-typevar-print/source.jibbnew file+11
@@ -0,0 +1,11 @@
1+++ same2 |=(x x)
2+++ with-a |= x=A [x same2]
3+++ with-b |= x=B [same2 x]
4+++ twice |= x=* [same2 same2]
5+++ pass |= x=Msg x
6+++ two |= x=* [pass pass]
7+++ letters |= x=Msg [x same2 pass]
8+++ digits |= [x=T2 y=A1] [y x]
9+++ outer |= x=Item
10+ ++ inner |= y=Item y
11+ (inner x)
tests/golden/types-typevar-print/tokens.txtnew file+108
@@ -0,0 +1,108 @@
1+1:1 glyph ++
2+1:4 name same2
3+1:10 glyph |=(
4+1:13 tight name x
5+1:15 name x
6+1:16 tight glyph )
7+2:1 NEWLINE
8+2:1 glyph ++
9+2:4 name with-a
10+2:11 glyph |=
11+2:14 name x
12+2:15 tight glyph =
13+2:16 tight tvar A
14+2:18 glyph [
15+2:19 tight name x
16+2:21 name same2
17+2:26 tight glyph ]
18+3:1 NEWLINE
19+3:1 glyph ++
20+3:4 name with-b
21+3:11 glyph |=
22+3:14 name x
23+3:15 tight glyph =
24+3:16 tight tvar B
25+3:18 glyph [
26+3:19 tight name same2
27+3:25 name x
28+3:26 tight glyph ]
29+4:1 NEWLINE
30+4:1 glyph ++
31+4:4 name twice
32+4:10 glyph |=
33+4:13 name x
34+4:14 tight glyph =
35+4:15 tight glyph *
36+4:17 glyph [
37+4:18 tight name same2
38+4:24 name same2
39+4:29 tight glyph ]
40+5:1 NEWLINE
41+5:1 glyph ++
42+5:4 name pass
43+5:9 glyph |=
44+5:12 name x
45+5:13 tight glyph =
46+5:14 tight tvar Msg
47+5:18 name x
48+6:1 NEWLINE
49+6:1 glyph ++
50+6:4 name two
51+6:8 glyph |=
52+6:11 name x
53+6:12 tight glyph =
54+6:13 tight glyph *
55+6:15 glyph [
56+6:16 tight name pass
57+6:21 name pass
58+6:25 tight glyph ]
59+7:1 NEWLINE
60+7:1 glyph ++
61+7:4 name letters
62+7:12 glyph |=
63+7:15 name x
64+7:16 tight glyph =
65+7:17 tight tvar Msg
66+7:21 glyph [
67+7:22 tight name x
68+7:24 name same2
69+7:30 name pass
70+7:34 tight glyph ]
71+8:1 NEWLINE
72+8:1 glyph ++
73+8:4 name digits
74+8:11 glyph |=
75+8:14 glyph [
76+8:15 tight name x
77+8:16 tight glyph =
78+8:17 tight tvar T2
79+8:20 name y
80+8:21 tight glyph =
81+8:22 tight tvar A1
82+8:24 tight glyph ]
83+8:26 glyph [
84+8:27 tight name y
85+8:29 name x
86+8:30 tight glyph ]
87+9:1 NEWLINE
88+9:1 glyph ++
89+9:4 name outer
90+9:10 glyph |=
91+9:13 name x
92+9:14 tight glyph =
93+9:15 tight tvar Item
94+10:3 INDENT
95+10:3 glyph ++
96+10:6 name inner
97+10:12 glyph |=
98+10:15 name y
99+10:16 tight glyph =
100+10:17 tight tvar Item
101+10:22 name y
102+11:3 NEWLINE
103+11:3 glyph (
104+11:4 tight name inner
105+11:10 name x
106+11:11 tight glyph )
107+11:12 DEDENT
108+11:12 NEWLINE
tests/golden/types-typevar-print/tree.txtnew file+43
@@ -0,0 +1,43 @@
1+(module
2+ (value 1:1 same2
3+ (gate-wide 1:10 (bind 1:13 x) (wing 1:15 x)))
4+ (value 2:1 with-a
5+ (gate 2:11
6+ (face 2:14 x (tvar 2:16 A))
7+ (tuple 2:18 (wing 2:19 x) (wing 2:21 same2))))
8+ (value 3:1 with-b
9+ (gate 3:11
10+ (face 3:14 x (tvar 3:16 B))
11+ (tuple 3:18 (wing 3:19 same2) (wing 3:25 x))))
12+ (value 4:1 twice
13+ (gate 4:10
14+ (face 4:13 x (noun 4:15))
15+ (tuple 4:17 (wing 4:18 same2) (wing 4:24 same2))))
16+ (value 5:1 pass
17+ (gate 5:9
18+ (face 5:12 x (tvar 5:14 Msg))
19+ (wing 5:18 x)))
20+ (value 6:1 two
21+ (gate 6:8
22+ (face 6:11 x (noun 6:13))
23+ (tuple 6:15 (wing 6:16 pass) (wing 6:21 pass))))
24+ (value 7:1 letters
25+ (gate 7:12
26+ (face 7:15 x (tvar 7:17 Msg))
27+ (tuple 7:21 (wing 7:22 x) (wing 7:24 same2) (wing 7:30 pass))))
28+ (value 8:1 digits
29+ (gate 8:11
30+ (cell 8:14
31+ (face 8:15 x (tvar 8:17 T2))
32+ (face 8:20 y (tvar 8:22 A1)))
33+ (tuple 8:26 (wing 8:27 y) (wing 8:29 x))))
34+ (value 9:1 outer
35+ (gate 9:10
36+ (face 9:13 x (tvar 9:15 Item))
37+ (body 10:3
38+ (value 10:3 inner
39+ (gate 10:12
40+ (face 10:15 y (tvar 10:17 Item))
41+ (wing 10:22 y)))
42+ (group 11:3
43+ (call 11:4 (wing 11:4 inner) (wing 11:10 x)))))))
tests/golden/types-typevar-print/types.txtnew file+10
@@ -0,0 +1,10 @@
1+partial inference; module not checked
2+++ same2: $-(A A)
3+++ with-a: $-(A [A $-(B B)])
4+++ with-b: $-(B [$-(A A) B])
5+++ twice: $-(* [$-(A A) $-(B B)])
6+++ pass: $-(Msg Msg)
7+++ two: $-(* [$-(Msg Msg) $-(A A)])
8+++ letters: $-(Msg [Msg [$-(A A) $-(B B)]])
9+++ digits: $-([x=T2 y=A1] [A1 T2])
10+++ outer: $-(Item Item)
tests/lib/jibb-doc-examples.hoon+1−1
@@ -158,7 +158,7 @@
158158 (prepare-prelude-with-internal:jibb public private)
159159 ?~ prepared ~["doc-example prelude did not prepare"]
160160 ;: weld
161− (doc-positive "view-day" /ui/view-day/jibb view-source %view '$-([day=@da n=@ud] (element A))' u.prepared)
161+ (doc-positive "view-day" /ui/view-day/jibb view-source %view '$-([day=@da n=@ud] (element M))' u.prepared)
162162 (doc-positive "step" /ui/step/jibb step-source %describe '$-(step @t)' u.prepared)
163163 (doc-cmd-errors cmd-source u.prepared)
164164 (doc-import-errors import-source sur action blog card-source u.prepared)
tests/lib/jibb-full-diagnostics.hoonnew file+45
@@ -0,0 +1,45 @@
1+:: Full-module diagnostics retain their inference sites.
2+/+ jibb
3+|%
4+++ test-full-diagnostics
5+ ^- tang
6+ =/ file=path /ui/probe/jibb
7+ =/ source=@t (of-wain:format ~['++ inc |= n=@ud n' '++ top (inc %.y)'])
8+ =/ result (infer-jibb-file-detailed:jibb file source ~ ~ ~ ~[file] ~ ~ ~ ~)
9+ ?: ?=(%& -.result) ~[leaf+"wrong argument was accepted"]
10+ =/ expected=@t
11+ (of-wain:format ~['++ top: call\'s sample and argument types do not unify' '/ui/probe.jibb:2:9: called gate has type $-(@ud @ud)' '++ top (inc %.y)' ' ^' '/ui/probe.jibb:2:13: argument has type ?' '++ top (inc %.y)' ' ^'])
12+ ?. =(expected message.p.result) ~[leaf+"full checker lost the argument diagnostic"]
13+ =/ forward=@t (of-wain:format ~['++ top (inc 5)' '++ inc |= n=@ud n'])
14+ =/ ok (infer-jibb-file-detailed:jibb file forward ~ ~ ~ ~[file] ~ ~ ~ ~)
15+ ?: ?=(%| -.ok) ~[leaf+"forward definition did not resolve"]
16+ :: An earlier open tag and an earlier shadow must not be hidden by a
17+ :: definite call mismatch in another unresolved definition.
18+ =/ pending-source=@t (of-wain:format ~['++ x %add' '++ inc |= n=@ud n' '++ bad (inc %.y)'])
19+ =/ pending-result (infer-jibb-file-detailed:jibb file pending-source ~ ~ ~ ~[file] ~ ~ ~ ~)
20+ ?: ?=(%& -.pending-result) ~[leaf+"open tag was accepted"]
21+ =/ pending-expected=@t
22+ (of-wain:format ~['/ui/probe.jibb:1:6: nothing fixes the union of %add' '++ x %add' ' ^'])
23+ ?. =(pending-expected message.p.pending-result) ~[leaf+"earlier pending tag was masked"]
24+ :: A forward dependency precedes its user even when its source line is
25+ :: after a separate mismatch.
26+ =/ dependency-source=@t (of-wain:format ~['++ wrapper x' '++ inc |= n=@ud n' '++ bad (inc %.y)' '++ x %add'])
27+ =/ dependency-result (infer-jibb-file-detailed:jibb file dependency-source ~ ~ ~ ~[file] ~ ~ ~ ~)
28+ ?: ?=(%& -.dependency-result) ~[leaf+"forward open tag was accepted"]
29+ =/ dependency-expected=@t
30+ (of-wain:format ~['/ui/probe.jibb:4:6: nothing fixes the union of %add' '++ x %add' ' ^'])
31+ ?. =(dependency-expected message.p.dependency-result) ~[leaf+"dependency diagnostic order differs"]
32+ =/ shadow-source=@t (of-wain:format ~['++ inc |= n=@ud n' '++ before |= inc 0' '++ bad (inc %.y)'])
33+ =/ shadow-result (infer-jibb-file-detailed:jibb file shadow-source ~ ~ ~ ~[file] ~ ~ ~ ~)
34+ ?: ?=(%& -.shadow-result) ~[leaf+"shadowing sample was accepted"]
35+ =/ shadow-expected=@t
36+ (of-wain:format ~['/ui/probe.jibb:2:14: sample `inc` shadows a name already in scope' '++ before |= inc 0' ' ^'])
37+ ?. =(shadow-expected message.p.shadow-result) ~[leaf+"earlier sample shadow was masked"]
38+ =/ reversed-source=@t (of-wain:format ~['++ inc |= n=@ud n' '++ bad (inc %.y)' '++ x %add'])
39+ =/ reversed-result (infer-jibb-file-detailed:jibb file reversed-source ~ ~ ~ ~[file] ~ ~ ~ ~)
40+ ?: ?=(%& -.reversed-result) ~[leaf+"call mismatch was accepted"]
41+ =/ reversed-expected=@t
42+ (of-wain:format ~['++ bad: call\'s sample and argument types do not unify' '/ui/probe.jibb:2:9: called gate has type $-(@ud @ud)' '++ bad (inc %.y)' ' ^' '/ui/probe.jibb:2:13: argument has type ?' '++ bad (inc %.y)' ' ^'])
43+ ?. =(reversed-expected message.p.reversed-result) ~[leaf+"earlier mismatch was masked"]
44+ ~
45+--
tests/lib/jibb-full-scope.hoonnew file+37
@@ -0,0 +1,37 @@
1+:: The full checker reports the names and sites of module scope conflicts.
2+/+ jibb
3+|%
4+++ test-full-scope
5+ ^- tang
6+ =/ file=path /ui/probe/jibb
7+ =/ dup=@t (of-wain:format ~['++ foo 1' '++ foo 2'])
8+ =/ dup-result (infer-jibb-file-detailed:jibb file dup ~ ~ ~ ~[file] ~ ~ ~ ~)
9+ ?: ?=(%& -.dup-result) ~[leaf+"duplicate definition was accepted"]
10+ =/ dup-expected=@t
11+ (of-wain:format ~['definition `foo` shadows an earlier definition' '/ui/probe.jibb:1:1: earlier definition' '++ foo 1' '^' '/ui/probe.jibb:2:1: conflicting definition' '++ foo 2' '^'])
12+ ?. =(dup-expected message.p.dup-result) ~[leaf+"duplicate definition diagnostic differs"]
13+ =/ reserved=@t '++ proj 1'
14+ =/ reserved-result (infer-jibb-file-detailed:jibb file reserved ~ ~ ~ ~[file] ~ ~ ~ ~)
15+ ?: ?=(%& -.reserved-result) ~[leaf+"reserved definition was accepted"]
16+ =/ reserved-expected=@t
17+ (of-wain:format ~['`proj` is reserved and cannot be bound' '/ui/probe.jibb:1:1: reserved name' '++ proj 1' '^'])
18+ ?. =(reserved-expected message.p.reserved-result) ~[leaf+"reserved definition diagnostic differs"]
19+ =/ collision=@t (of-wain:format ~['/= foo /ui/other' '++ foo 1'])
20+ =/ collision-result (infer-jibb-file-detailed:jibb file collision ~ ~ ~ ~[file] ~ ~ ~ ~)
21+ ?: ?=(%& -.collision-result) ~[leaf+"definition shadowing import was accepted"]
22+ =/ collision-expected=@t
23+ (of-wain:format ~['definition `foo` shadows an import' '/ui/probe.jibb:1:1: import' '/= foo /ui/other' '^' '/ui/probe.jibb:2:1: conflicting definition' '++ foo 1' '^'])
24+ ?. =(collision-expected message.p.collision-result) ~[leaf+"import conflict diagnostic differs"]
25+ =/ prelude-source=@t '++ add |= n n'
26+ =/ iface=ifile:jibb [~ ~ /lib/jibb/prelude/jibb ~ ~ ~ `prelude-source ~]
27+ =/ shadows=@t '++ add 1'
28+ =/ shadow-result (infer-jibb-file-detailed:jibb file shadows ~ ~ ~ ~[file] ~[%add] ~ ~ `iface)
29+ ?: ?=(%& -.shadow-result) ~[leaf+"prelude shadow was accepted"]
30+ =/ shadow-expected=@t
31+ (of-wain:format ~['definition `add` shadows a prelude name' '/ui/probe.jibb:1:1: conflicting definition' '++ add 1' '^' '/lib/jibb/prelude.jibb:1:1: prelude declaration' '++ add |= n n' '^'])
32+ ?. =(shadow-expected message.p.shadow-result) ~[leaf+"prelude shadow diagnostic differs"]
33+ =/ nested=@t '++ test |=(proj proj)'
34+ =/ nested-result (infer-jibb-file-detailed:jibb file nested ~ ~ ~ ~[file] ~ ~ ~ ~)
35+ ?: ?=(%& -.nested-result) ~[leaf+"reserved sample was accepted"]
36+ ~
37+--
tests/lib/jibb-page-main.hoon+2
@@ -158,6 +158,8 @@
158158::
159159++ test-page-main
160160 ^- tang
161+ =/ hand-parsed (parse:jibb /ui/index/jibb (text hand-built-load))
162+ ?: ?=(%| -.hand-parsed) ~[leaf+"hand-built load fixture does not parse"]
161163 =/ negatives=(list [label=@t src=@t])
162164 :~ ['wrong static message' (text wrong-static)]
163165 ['arbitrary main' (text arbitrary-main)]
tests/lib/jibb-store.hoon+4−1
@@ -127,8 +127,11 @@
127127 =/ store-mold=(unit ischeme:jibb) (find-jibb-mold:jibb %store iface.u.prepared)
128128 ?~ store-value ~["store builder is missing"]
129129 ?~ store-mold ~["store mold is missing"]
130+ :: The builder's variables keep the names the prelude writes, S and A.
131+ =/ s=@ud (named-var:jibb 'S' 0)
132+ =/ a=@ud (named-var:jibb 'A' 1)
130133 =/ expected-builder=itype:jibb
131− [%fn [%cell [%face %init [%var 0]] [%face %update [%fn [%cell [%var 1] [%var 0]] [%var 0]]]] [%cell [%face %init [%var 0]] [%face %update [%noun ~]]]]
134+ [%fn [%cell [%face %init [%var s]] [%face %update [%fn [%cell [%var a] [%var s]] [%var s]]]] [%cell [%face %init [%var s]] [%face %update [%noun ~]]]]
132135 ?. &(?=([@ @ ~] vars.u.store-value) =(typ.u.store-value expected-builder)) ~["store builder scheme differs"]
133136 =/ expected-mold=itype:jibb [%cell [%face %init [%var 0]] [%face %update [%noun ~]]]
134137 ?. &(?=([@ ~] vars.u.store-mold) =(typ.u.store-mold expected-mold)) ~["store mold scheme differs"]
tests/type-buttons/expected.txt+1−1
@@ -1,2 +1,2 @@
1−labelled: $-([label=@t msg=A] (element A))
1+labelled: $-([label=@t msg=M] (element M))
22wide: (list attr)
tests/type-deferred-context/report.txt+1−1
@@ -10,6 +10,6 @@ partial inference; module not checked
1010++ first: $-(@t message)
1111++ fixed: $-(@t message)
1212++ make: $-(A $-(B B))
13−++ built: $-(A A)
13+++ built: $-(B B)
1414++ reveal: @t
1515++ reveal-ship: @p
tests/type-deferred-resolver/expected.txt+2−2
@@ -1,14 +1,14 @@
11interface retains independent polymorphism
22text use inferred
33ship use inferred
4−stored built: $-(A A)
4+stored built: $-(B B)
55partial inference; module not checked
66+$ message: cases proven disjoint; mold not checked
77++ send: $-($-(@t A) $-(@t A))
88++ make: $-(A $-(B B))
99++ first: $-(@t message)
1010++ second: $-(@t message)
11−++ built: $-(A A)
11+++ built: $-(B B)
1212++ typed: $-(@t message)
1313++ reveal: @t
1414++ reveal-ship: @p
tests/type-direct-gate/expected.txt+2−2
@@ -17,7 +17,7 @@ partial inference; module not checked
1717++ wrong-msg-update: $-([msg=other state=@ud] [@ud (list (cmd other))])
1818++ mismatched-message: call constraint is not supported by partial inference
1919++ pending: tag needs context in partial inference
20−++ program-value: $-([init=$-(A B) [update=$-([C B] [B (list (cmd C))]) [view=$-(B (element C)) subs=$-(B (list (sub C)))]]] [init=$-(A B) [update=$-([C B] [B (list (cmd C))]) [view=$-(B (element C)) subs=$-(B (list (sub C)))]]])
20+++ program-value: $-([init=$-(Data Model) [update=$-([Msg Model] [Model (list (cmd Msg))]) [view=$-(Model (element Msg)) subs=$-(Model (list (sub Msg)))]]] [init=$-(Data Model) [update=$-([Msg Model] [Model (list (cmd Msg))]) [view=$-(Model (element Msg)) subs=$-(Model (list (sub Msg)))]]])
2121++ update-unfaced: $-([message @ud] [@ud (list (cmd message))])
2222++ direct-unfaced: [init=$-(@t @ud) [update=$-([message @ud] [@ud (list (cmd message))]) [view=$-(@ud (element message)) subs=$-(@ud (list (sub message)))]]]
2323+$ record: not checked
@@ -58,7 +58,7 @@ partial inference; module not checked
5858++ unknown-call: $-($-([A B] C) $-([A B] C))
5959++ update-proj-good: $-([msg=message state=[count=@ud label=@t]] [[count=@ud label=@t] (list (cmd message))])
6060++ program-projection: [init=$-(@t [count=@ud label=@t]) [update=$-([message [count=@ud label=@t]] [[count=@ud label=@t] (list (cmd message))]) [view=$-([count=@ud label=@t] (element message)) subs=$-([count=@ud label=@t] (list (sub message)))]]]
61−++ program-alias: $-([init=$-(A B) [update=$-([C B] [B (list (cmd C))]) [view=$-(B (element C)) subs=$-(B (list (sub C)))]]] [init=$-(A B) [update=$-([C B] [B (list (cmd C))]) [view=$-(B (element C)) subs=$-(B (list (sub C)))]]])
61+++ program-alias: $-([init=$-(Data Model) [update=$-([Msg Model] [Model (list (cmd Msg))]) [view=$-(Model (element Msg)) subs=$-(Model (list (sub Msg)))]]] [init=$-(Data Model) [update=$-([Msg Model] [Model (list (cmd Msg))]) [view=$-(Model (element Msg)) subs=$-(Model (list (sub Msg)))]]])
6262++ through-head-alias: call constraint is not supported by partial inference
6363++ update-alias: $-([msg=message state=@ud] [@ud (list (cmd message))])
6464++ through-arg-alias: call constraint is not supported by partial inference
tests/type-page-main/hand-built-load.txt+2−2
@@ -2,9 +2,9 @@
22/= todo-list /ui/todo-list
33
44++ main (page load view)
5−++ load |=(~
5+++ load |= ~
66 ^- (ask (list item.todo))
7− [%agent api="/ui/api/todo" case=%todos agent=%todo path=~[%todos] scry=~ receive=receive])
7+ [%agent api="/ui/api/todo" case=%todos agent=%todo path=~[%todos] scry=~ receive=receive]
88++ receive |= input=[mark=@tas state=(unit *) fact=*]
99 ^- [state=* message=(list item.todo)] [state=0 message=~]
1010
tools/check+1
@@ -80,6 +80,7 @@ CHECKS = [
8080 for i in range(1, ARM_SHARDS + 1)
8181] + [
8282 Check('doc-blocks', 'eval', ['tools/doc-blocks', 'docs/spec']),
83+ tool('doc-fragments'),
8384 # The ship group. ship-selftest leaves its fixture files on the
8485 # jibb-dev desk, and ship-test, which syncs the desk to the repo
8586 # first, puts the real ones back, so it must come after.
tools/doc-fragmentsnew file+61
@@ -0,0 +1,61 @@
1+#!/usr/bin/env python3
2+"""Check that the fragments tested in module context match the doc cases."""
3+
4+from pathlib import Path
5+import difflib
6+import sys
7+
8+ROOT = Path(__file__).resolve().parent.parent
9+
10+
11+def definitions(text):
12+ """Return top-level ++ definitions, including their indented bodies."""
13+ lines = text.splitlines(keepends=True)
14+ starts = [i for i, line in enumerate(lines) if line.startswith('++ ')]
15+ result = {}
16+ for i, start in enumerate(starts):
17+ end = starts[i + 1] if i + 1 < len(starts) else len(lines)
18+ name = lines[start].split()[1]
19+ if name in result:
20+ raise ValueError('duplicate definition: ' + name)
21+ result[name] = ''.join(lines[start:end]).rstrip('\n') + '\n'
22+ return result
23+
24+
25+def read(path):
26+ return (ROOT / path).read_text(encoding='utf-8')
27+
28+
29+def compare(label, expected, actual):
30+ if expected == actual:
31+ print('ok ' + label)
32+ return True
33+ print('FAIL ' + label)
34+ sys.stdout.writelines(difflib.unified_diff(
35+ expected.splitlines(keepends=True), actual.splitlines(keepends=True),
36+ fromfile='documented fragment', tofile='tested fragment'))
37+ return False
38+
39+
40+def main():
41+ try:
42+ core = read('tests/golden/doc-core-02-update/source.jibb')
43+ todo = definitions(read('my-app/ui/todo-list.jibb'))
44+ buttons = definitions(read('tests/golden/doc-grammar-02-buttons/source.jibb'))
45+ valid = read('tests/type-buttons/valid.txt')
46+ checks = [
47+ compare('Core update in todo-list', core, todo['update']),
48+ compare('valid buttons without add-button',
49+ ''.join(body for name, body in buttons.items()
50+ if name != 'add-button'), valid),
51+ ]
52+ if 'add-button' not in buttons:
53+ raise ValueError('documented buttons have no add-button definition')
54+ return 0 if all(checks) else 1
55+ except (OSError, UnicodeError, KeyError, ValueError) as e:
56+ print('doc-fragments: %s' % e, file=sys.stderr)
57+ return 2
58+
59+
60+if __name__ == '__main__':
61+ sys.exit(main())