Commit Graph

85 Commits

Author SHA1 Message Date
Brummel 47d95d0c60 iter 23.1.3 fixup: clarify imports-fallback anchor + comment on env.imports vs env.module_imports duplication 2026-05-10 21:28:53 +02:00
Brummel 24af13e7e0 iter 23.1.3 fixup: cover AmbiguousType branch with cross-module test 2026-05-10 21:25:26 +02:00
Brummel 842df380a4 iter 23.1.3: implicit prelude import + symmetric bare-type-name imports-fallback in Term::Ctor synth 2026-05-10 21:24:16 +02:00
Brummel 6be5abf23a fix: Pattern::Lit::Float typecheck-reject is unreachable through check_module 2026-05-10 17:10:31 +02:00
Brummel 23b625f326 test: red for Pattern::Lit::Float not rejected through full check pipeline
Pins fieldtest finding B1 (docs/specs/2026-05-10-fieldtest-floats.md).
DESIGN.md and JOURNAL Floats.3 promise that pattern-matching on a
Float literal is hard-rejected at typecheck via
CheckError::FloatPatternNotAllowed, but the rejection only fires when
typecheck is reached directly. The full check pipeline runs
ailang_core::desugar::desugar_module first, and build_eq rewrites
Pattern::Lit { Literal::Float } arms into (== scrutinee 1.5_FLOAT)
before typecheck — so the existing iter-3.4 reject arm at lib.rs:2316
is unreachable on input flowing through check / check_module /
check_workspace.

The existing reject_float_pattern_in_match test in builtins.rs calls
synth(...) directly on a hand-built Term::Match, bypassing desugar; it
passes today but does not protect the spec'd property. This new test
exercises check(&m) end-to-end and asserts the FloatPatternNotAllowed
error — currently fails because check returns Ok(CheckedModule).

GREEN side handed off to skills/implement mini-mode.
2026-05-10 17:04:12 +02:00
Brummel d6da5c26b1 floats iter 3.4: typecheck rejects Pattern::Lit Float with FloatPatternNotAllowed 2026-05-10 15:40:33 +02:00
Brummel fd3f74cfa0 floats iter 3.3: install Float constants nan/inf/neg_inf + io/print_float effect op 2026-05-10 15:35:19 +02:00
Brummel 60a4c687b3 floats iter 3.2: install neg/int_to_float/float_to_int_truncate/float_to_str/is_nan 2026-05-10 15:31:14 +02:00
Brummel 6890aa244f floats iter 3.1 fixup: correct stale ==-comparison comment + asymmetric Float test args + drop spec-section reference 2026-05-10 15:28:55 +02:00
Brummel 0981804dd3 floats iter 3.1: widen +/-/*/// and !=/</<=/>/>= to polymorphic forall a 2026-05-10 15:24:13 +02:00
Brummel ec2811194b floats iter 1.1: Literal::Float variant + canonical hex serde + drift-test anchors 2026-05-10 14:36:08 +02:00
Brummel 557bf57cdb iter 22-tidy.4: mono::primitive_surface_name delegates to ailang-core 2026-05-10 04:18:46 +02:00
Brummel 5fd95e4e9f iter 22-tidy.4: route 4 matches! sites through is_primitive_name 2026-05-10 04:15:47 +02:00
Brummel c3fd1c08a3 iter env-unify.audit: tidy stale Env docs, pin-test docstring; queue types/ctor_index shape 2026-05-10 02:36:27 +02:00
Brummel d7e333fdf7 iter env-unify.2: drop redundant overlay comments 2026-05-10 02:28:54 +02:00
Brummel 2ab9d77113 iter env-unify.2: check_in_workspace consumes build_check_env 2026-05-10 02:26:24 +02:00
Brummel 92b94afa2a iter env-unify.1: rustdoc fixup (re-anchor check_in_workspace doc, drop transient task tag) 2026-05-10 02:19:24 +02:00
Brummel d6870d7a62 iter env-unify.1: extract build_check_env, mono uses it 2026-05-10 02:16:21 +02:00
Brummel cd08f53315 test: fix env-pin globals assertion (builtins seed operators workspace-flat) 2026-05-10 02:14:38 +02:00
Brummel 42a7ed7673 test: clean red signal for env-construction pin (inline module_types) 2026-05-10 02:06:46 +02:00
Brummel d7706dc3ed test: red for env-construction drift-shape pin 2026-05-10 02:03:09 +02:00
Brummel a9c685ded8 fix: mono pass seeds env.imports for qualified cross-module refs in class workspace 2026-05-10 01:23:07 +02:00
Brummel 13b36ccb0f fix: mono pass seeds env.globals for recursive top-level fn in class workspace 2026-05-10 01:10:31 +02:00
Brummel 5c5180fc48 fix: mono pass seeds env.types and env.ctor_index for user ADTs 2026-05-09 22:43:54 +02:00
Brummel b59820b737 iter 22b.3.7: synthetic fixture — class+instance compiles, runs, prints 5 2026-05-09 21:28:41 +02:00
Brummel 7f260b82ad iter 22b.3.6: fix — quality-review (shadow-aware walker, cross-mod test, Option-typed targets, const helper) 2026-05-09 21:21:33 +02:00
Brummel d1b590ceab iter 22b.3.6: call-site rewrite — same/cross module qualified names 2026-05-09 21:07:58 +02:00
Brummel e8018d48b6 iter 22b.3.5: fix — quality-review (chained-call test, hoist class_index, drop noise comments) 2026-05-09 20:59:43 +02:00
Brummel dd87b36e00 iter 22b.3.5: workspace fixpoint loop — dedup + synth-append 2026-05-09 20:52:07 +02:00
Brummel d2954010ea iter 22b.3.4: fix — quality-review (zero-arg test, drop what-comments + param-name pin) 2026-05-09 20:45:56 +02:00
Brummel d6084a71fb iter 22b.3.4: synthesise_mono_fn — instance body + class default fallback 2026-05-09 20:41:45 +02:00
Brummel 9f86c072dc iter 22b.3.3: fix — revert dead pub(crate), reuse build_module_types, drop defensive unwrap
Quality-review follow-up to 89311ee:

- Revert `substitute_rigids` to private. Task 3 does not call it; the
  visibility bump was forward-looking for Task 4 (synthesise_mono_fn).
  Task 4 will re-bump it in the same diff that uses it.
- Promote `build_module_types` to pub(crate); drop the inline
  reimplementation in `mono::build_workspace_env`. Removes drift risk
  between the two paths.
- Replace defensive `unwrap_or_default()` on `build_module_globals`
  with `expect(...)` naming the pre-condition. Silent default violated
  CLAUDE.md "no defensive validation in internal code paths".
- Add a one-line drift-risk reminder at the top of `build_workspace_env`
  flagging that it and `check_in_workspace` both populate `Env`.

Build clean; all 5 typeclass_22b3 tests green; no workspace regressions.
2026-05-09 20:36:52 +02:00
Brummel 89311ee20b iter 22b.3.3: collect_mono_targets — synth-replay residual gathering 2026-05-09 20:31:12 +02:00
Brummel c77fd1b85e iter 22b.3.2: fix — drop speculative Float (plan-text overreach)
Float is referenced nowhere else in the codebase; the plan-text
listed it aspirationally. Restored parity with the four other
primitive enumerations across the crate. When Float lands as a
real type (post-22b.4 Prelude work, if at all), the arm gets
re-added in the same iter that introduces Type::float().

Deferred (not part of this fix):
- Shared-constant extraction across the four primitive enumeration
  sites (linearity.rs:143, lib.rs:1232/2214, mono.rs) — workspace-
  level cleanup belonging to the milestone-22 audit phase.
- pub mod mono vs sibling pub use lift::lift_letrecs style — plan
  prescribed pub mod for 22b.3 because Tasks 3-7 add multiple pub
  items reached by integration tests; per-item pub use would
  proliferate.
2026-05-09 20:25:51 +02:00
Brummel 028227587b iter 22b.3.2: mono_symbol — primitive surface forms + hash for compound 2026-05-09 20:21:24 +02:00
Brummel 108115f7dd iter 22b.3.1: fix — quality-review (doc reframe + class-present test) 2026-05-09 20:18:20 +02:00
Brummel 209074ee5d iter 22b.3.1: mono pass skeleton — identity for class-free workspaces 2026-05-09 20:12:36 +02:00
Brummel 47bec74b26 iter 22b.2.10: fix — positive green-path test, drop dead let _ = ws
Adds the missing positive counterpart to the no-instance test:
`show 42` with `instance Show Int` PRESENT must typecheck green.
This guards against registry-keying or threading bugs that would
otherwise sneak past the negative-only test (an empty registry at
typecheck time, or a key shape mismatch, would silently fire
no-instance even when the instance exists).

Also drops the dead `let _ = ws;` and its stale comment in
`check_in_workspace` — the line above already consumes
`ws.registry`, so the explicit drop is redundant. The remaining
comment is folded into the registry-threading comment so the
"registry is the only thing threaded" rationale is preserved.
2026-05-09 19:13:32 +02:00
Brummel 3600e82ec2 iter 22b.2.10: no-instance per-fn diagnostic 2026-05-09 19:07:46 +02:00
Brummel b741a8ba05 iter 22b.2.9: fix — superclass-walk tests, simplify class_superclasses map shape 2026-05-09 18:59:15 +02:00
Brummel 7cff741632 iter 22b.2.9: missing-constraint per-fn diagnostic 2026-05-09 18:51:39 +02:00
Brummel afa06a3f3d iter 22b.2.8: fix — fold double-match, IndexMap parity, broader contract test 2026-05-09 18:37:49 +02:00
Brummel 17605a3327 iter 22b.2.8: register class methods in module globals 2026-05-09 18:33:01 +02:00
Brummel b636b883a3 iter 22b.2.1: add Constraint struct, Type::Forall.constraints 2026-05-09 17:34:39 +02:00
Brummel eb4db9dafc iter 22b.1.2: workspace registry skeleton + coherence checks
Adds the workspace-global typeclass instance registry per Decision 11
"Resolution and monomorphisation". Built at the end of load_workspace
after the DFS over imports completes; keyed by (class-name, type-hash)
where type-hash uses the new canonical::type_hash (16-hex prefix,
parallel to def_hash and module_hash).

Three coherence checks fire from build_registry, each surfacing as a
distinct WorkspaceLoadError variant:

- OrphanInstance: `instance C T` not in C's or T's defining module.
- DuplicateInstance: two entries share the same (class, type-hash) key.
- MissingMethod: instance omits a required (non-default) method.

The CLI's workspace_error_to_diagnostic is extended with the three new
codes (orphan-instance / duplicate-instance / missing-method).

All existing Workspace { ... } construction sites get the new
`registry` field, defaulting to Registry::default() at synthetic /
test-only paths and threading through ws.registry.clone() at codepath
sites that already hold a real workspace.

Includes hash-stability regression tests (iter22b1_schema_extension_*
and iter22b1_classdef_empty_optionals_hash_stable) and the empty-
registry positive test against examples/sum.ail.json. Test count:
288 → 291 (3 new tests, all pass).
2026-05-09 12:37:00 +02:00
Brummel f25d7b6cd6 iter 22b.1.1: ClassDef/InstanceDef AST + downstream match arms
Adds Def::Class(ClassDef) and Def::Instance(InstanceDef) variants per
Decision 11 §"Form-A schema". All optional fields (superclass, doc,
default body) carry skip_serializing_if so canonical-JSON bytes of
pre-22b fixtures stay bit-identical.

Downstream match-on-Def sites are extended with explicit Class/Instance
arms. Behaviour for 22b.1 is placeholder (skip in typecheck/codegen,
one-line summary in pretty/manifest, placeholder marker in prose/print)
with TODO comments naming the deferred sub-iters (22b.2 typecheck,
22b.3 codegen, 22b.4 prose-projection arms).
2026-05-09 12:31:23 +02:00
Brummel 50b68267fe check: mode-strict-because suppression (iter 19b)
Closes the 19a/19a.1/19b arc. Corpus signal from 19a.1 (5/65
fixtures fire over-strict-mode, all deliberate RC codegen-test
fixtures) justified shipping the suppress mechanism end-to-end.

Schema: Suppress { code, because } on FnDef. Pre-19b hashes
bit-identical via skip_serializing_if. Typechecker drops matching
diagnostics; empty 'because' is Error severity; wrong codes are
silent no-ops (open-set registry).

Form-A: (suppress (code "...") (because "...")) clause, parser
+ printer round-trip clean. Form-B: '// @suppress <code>: <reason>'
above the doc string, lossless contract metadata.

5 RC fixtures migrated (.ail.json + .ailx + .prose.txt). Corpus
signal: 5/65 -> 0/65. Lint still fires on any future fn that's
accidentally over-strict without an authored reason.

Test counts: ailang-check 55->61, ailang-core 26->28, ailang-surface
21->26, ailang-prose 49->52, e2e 70 unchanged.

Known debt: .ailx comment headers lost on regen (ail render's
contract excludes comments); parse_suppress_attr accepts
duplicate code/because attrs without diagnose (bounded by canonical
print order).
2026-05-08 19:36:04 +02:00
Brummel 9f3f10ce6e check: precise sub-binder analysis for over-strict-mode (iter 19a.1)
Corpus-signal upgrade: orchestrator ran 19a's lint across 65
fixtures, zero warnings fired. The conservative match-scrutinee
carve-out filtered every (own T) fixture because every such body
destructures the param via match. Real-corpus signal warranted
the precise variant.

Precise rule: for an Own param with consume_count == 0, walk each
match arm whose scrutinee is the param; if any HEAP-TYPED
pattern-binder has consume_count > 0, stay silent (sub-consume
forces ownership). Otherwise fire.

Heap-type filter is the implementer's design call (not in the
brief): reading a primitive (h: Int) is load-by-value, no RC, no
heap-data move; reading heap-typed t: IntList IS a pointer move
requiring outer-cell ownership. Documented in module-doc.

Corpus signal after upgrade: 5/65 fixtures fire — all RC
codegen-test fixtures with deliberate over-strictness for the
codegen path. Justifies 19b (mode-strict-because suppression).

ailang-check test count: 53 → 55. e2e + everything else green.
Known debt: deeply-nested-match-on-sub-binder (no fixture hits).
2026-05-08 19:19:31 +02:00
Brummel 41804a39fb check: over-strict-mode lint (iter 19a)
When a fn-param is annotated (own T) but the body never consumes
it (consume_count == 0) and never destructures it via match, the
linearity pass now emits a Severity::Warning diagnostic with a
form-A-rendered (borrow T) rewrite as suggested_rewrite. Pure
advisory, Decision 10 unchanged.

First Warning-severity diagnostic the typechecker emits; three
CLI exit paths gated on Error-only.

JOURNAL: design entry + iter 19a shipping entry.
2026-05-08 17:56:58 +02:00
Brummel 6b3ff3bbed tidy: rewrite stale 18b/18c.x doc-headers to match shipped state
First half of the post-18-arc tidy-iter (per the new CLAUDE.md
iter-cycle rule). Architect's drift review flagged module-doc
headers describing 18b's leak-everything snapshot or 18c.x's
"deferred" debt that has since shipped. Doc-only changes; cargo
build clean, cargo test --workspace green at e2e=61, no
behavioural change.

- runtime/rc.c top-of-file header: rewrote from "Iter 18b
  deliberately stops at the layout and the alloc... programs
  leak every allocation" (false post-18c.3) to a stage summary
  spanning 18b–18e. Fixed `--memory=rc` reference (renamed to
  `--alloc=rc` in 18b's CLI work). Updated ailang_rc_inc /
  ailang_rc_dec block comments to point at `drop_<m>_<T>` and
  the worklist as the cascade owners, not at "18c will wire
  this up".

- ailang-check uniqueness.rs module-doc: replaced the "deferred
  to later iters" block (which named 18c.4 + 18d as future
  work, both shipped) with a current "what this pass does NOT
  do" block. Cross-fn reasoning is still genuinely deferred;
  per-type drop fns and recursive cascades are NOT this pass's
  job by design (codegen does them, not the inference).

- ailang-codegen emit_drop_fn_for_type doc + in-body comment:
  rewrote "Iter 18e replaces the recursive call with an
  iterative worklist free" to describe the actual shipped
  behaviour — the 18e (drop-iterative) annotation routes
  annotated types through emit_iterative_drop_fn_for_type;
  unannotated types stay recursive by orchestrator design
  (cheaper IR, no worklist alloc).

Held back for the second half of the tidy-iter (pending the
ailang-bencher determinism result):

- DESIGN.md Decision 10 line 700 says modes are "mandatory"
  but lines 940–952 admit they're opt-in with deferred
  mandatoriness. The bench result either supports tightening
  the mandatoriness claim or backs down to "opt-in with
  performance benefit" — orchestrator-level decision blocked
  on the bench data.
- Dynamic-tag partial-drop debt is captured in JOURNAL but
  should be surfaced in DESIGN as a known precision gap.
2026-05-08 13:34:32 +02:00