From 4ba0601398478108e4aa05014213346ffc36584b Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Mon, 18 May 2026 09:12:25 +0100 Subject: [PATCH] =?UTF-8?q?refactor(effects):=20rename=20stdlib=20io/state?= =?UTF-8?q?/exn=E2=86=92IO/Mut/Throws,=20retire=20aliases=20(Refs=20#59)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit STAGE-B cleanup. PR-1 (#196) added legacy lowercase aliases as a migration bridge; now that nothing depends on them, retire them and move the stdlib to the canonical v1 names. - stdlib/effects.affine: `effect io/state/exn` → `IO/Mut/Throws`; all 10 `/ io|state|exn` annotations → canonical. - effect.ml/.mli: remove `legacy_aliases`; `canonical_effect_name` is now v1 ∪ reserved only. Lowercase effect names are henceforth valid only if explicitly `effect ;`-declared (so the user-declared `effect io;` test in test_e2e.ml is unaffected — verified). - editors/vscode/README.md: doc snippets `/ io` → `/ IO` for accuracy now the alias is gone. dune build clean; dune test --force 253/253, zero regression (incl. AOT effects smoke + the user-declared-effect e2e test). Refs #59 Co-Authored-By: Claude Opus 4.7 (1M context) --- editors/vscode/README.md | 8 ++++---- lib/effect.ml | 15 +++++++-------- lib/effect.mli | 3 --- stdlib/effects.affine | 26 +++++++++++++------------- 4 files changed, 24 insertions(+), 28 deletions(-) diff --git a/editors/vscode/README.md b/editors/vscode/README.md index 8f271198..f773d795 100644 --- a/editors/vscode/README.md +++ b/editors/vscode/README.md @@ -67,7 +67,7 @@ fn add(x: Int, y: Int) -> Int { } // Impure function with IO effect -fn main() -> Unit / io { +fn main() -> Unit / IO { println("Hello, AffineScript!"); let result = add(40, 2); println(int_to_string(result)); @@ -79,11 +79,11 @@ fn main() -> Unit / io { ```affinescript // Pure functions cannot call impure functions fn pure() -> Int { - return read_line(); // ❌ ERROR: Cannot perform effect io in pure context + return read_line(); // ❌ ERROR: Cannot perform effect IO in pure context } // Impure functions can call pure or impure -fn impure() -> Int / io { +fn impure() -> Int / IO { return read_line(); // ✅ OK } ``` @@ -95,7 +95,7 @@ fn use_value(x: @affine String) -> Unit { println(x); // x is consumed here } -fn main() -> Unit / io { +fn main() -> Unit / IO { let s = "hello"; use_value(s); println(s); // ❌ ERROR: use after move diff --git a/lib/effect.ml b/lib/effect.ml index 0d5eabc1..e0b33f6e 100644 --- a/lib/effect.ml +++ b/lib/effect.ml @@ -137,14 +137,13 @@ let v1_effects = [ "IO"; "Async"; "Partial"; "Throws"; "Mut" ] yet wired into the stdlib. *) let reserved_effects = [ "Random"; "Time"; "Net" ] -(** Legacy lowercase stdlib effects → canonical v1. Kept as aliases so - [stdlib/effects.affine] and existing code compile unchanged - (additive migration; a rename sweep is a later, separate change). *) -let legacy_aliases = [ ("io", "IO"); ("state", "Mut"); ("exn", "Throws") ] - (** Canonical registry name for a source effect name, or [None] if it is - neither a v1/reserved name nor a legacy alias. Callers additionally - accept user-declared effects (`effect ;`). *) + neither a v1 nor a reserved name. Callers additionally accept + user-declared effects (`effect ;`). + + The lowercase [io]/[state]/[exn] migration aliases were retired once + [stdlib/effects.affine] was renamed to the canonical names; legacy + lowercase effect names are now only valid if explicitly declared. *) let canonical_effect_name (s : string) : string option = if List.mem s v1_effects || List.mem s reserved_effects then Some s - else List.assoc_opt s legacy_aliases + else None diff --git a/lib/effect.mli b/lib/effect.mli index 2e149070..c99fdd85 100644 --- a/lib/effect.mli +++ b/lib/effect.mli @@ -35,9 +35,6 @@ val v1_effects : string list (** Reserved-for-v1.x effect names. *) val reserved_effects : string list -(** Legacy lowercase stdlib effect → canonical v1 name. *) -val legacy_aliases : (string * string) list - (** Canonical registry name for a source effect name, or [None] if unknown to the registry (caller also accepts declared effects). *) val canonical_effect_name : string -> string option diff --git a/stdlib/effects.affine b/stdlib/effects.affine index 259bf22f..c329d413 100644 --- a/stdlib/effects.affine +++ b/stdlib/effects.affine @@ -2,31 +2,31 @@ // AffineScript Standard Library - Effect Declarations // Core IO effect - file and console operations -effect io; +effect IO; // State effect - mutable references -effect state; +effect Mut; // Exception effect - panics and error handling -effect exn; +effect Throws; // Built-in IO operations -extern fn print(s: String) -> Unit / io; -extern fn println(s: String) -> Unit / io; -extern fn read_line() -> String / io; -extern fn read_file(path: String) -> String / io; -extern fn write_file(path: String, content: String) -> Unit / io; +extern fn print(s: String) -> Unit / IO; +extern fn println(s: String) -> Unit / IO; +extern fn read_line() -> String / IO; +extern fn read_file(path: String) -> String / IO; +extern fn write_file(path: String, content: String) -> Unit / IO; // Built-in State operations // `make_ref` (not `ref`) because `ref` is a reserved ownership keyword; // see #135 keyword-as-identifier slice. -extern fn make_ref(x: T) -> Ref / state; -extern fn get(r: Ref) -> T / state; -extern fn set(r: Ref, x: T) -> Unit / state; +extern fn make_ref(x: T) -> Ref / Mut; +extern fn get(r: Ref) -> T / Mut; +extern fn set(r: Ref, x: T) -> Unit / Mut; // Built-in Exception operations -extern fn panic(msg: String) -> Never / exn; -extern fn error(msg: String) -> T / exn; +extern fn panic(msg: String) -> Never / Throws; +extern fn error(msg: String) -> T / Throws; // Pure operations (no effects) extern fn int_to_string(n: Int) -> String;