Преглед изворни кода

generics: generic classes work via generic modules (test + finding)

A class declared in a generic module's TYPE block, implemented in the
generic impl, instantiates with the module: GCInt = GBox(INTEGER) gives
GCInt.Box, verified end-to-end (suite GCBoxProg, rc 42). So standalone
GENERIC CLASS syntax is not required for the capability; a type
refinement form remains the option if class-only instantiation is
wanted. Suite 215/215; fixpoint OK.
Eric Streit пре 15 часа
родитељ
комит
ef331d4ec7

+ 2 - 0
compiler/run_tests.sh

@@ -292,6 +292,8 @@ expect_run_files OrdProg 42 \
 expect_run_files GWrapProg 42 \
   g_ordbox.def g_ordbox.mod g_intbox.def g_intbox.mod \
   g_wrap.def g_wrap.mod g_wrapb.def g_wrapb.mod g_wrapprog.mod
+expect_run_files GCBoxProg 42 \
+  g_gcbox.def g_gcbox.mod g_gcint.def g_gcint.mod g_gcprog.mod
 expect_run_files WrapProg 42 \
   ../runtime/syslib/SysShim.def ../runtime/syslib/SysShim.mod \
   ../stdlib/iochan.def ../stdlib/iochan.mod \

+ 8 - 0
compiler/tests/g_gcbox.def

@@ -0,0 +1,8 @@
+GENERIC DEFINITION MODULE GBox (T : TYPE);
+TYPE
+  CLASS Box;
+    v : T;
+    PROCEDURE Put(x : T);
+    PROCEDURE Get() : T;
+  END Box;
+END GBox.

+ 8 - 0
compiler/tests/g_gcbox.mod

@@ -0,0 +1,8 @@
+GENERIC IMPLEMENTATION MODULE GBox;
+CLASS IMPLEMENTATION Box;
+  PROCEDURE Put(x : T);
+  BEGIN v := x END Put;
+  PROCEDURE Get() : T;
+  BEGIN RETURN v END Get;
+END Box;
+END GBox.

+ 2 - 0
compiler/tests/g_gcint.def

@@ -0,0 +1,2 @@
+DEFINITION MODULE GCInt = GBox(INTEGER);
+END GCInt.

+ 2 - 0
compiler/tests/g_gcint.mod

@@ -0,0 +1,2 @@
+IMPLEMENTATION MODULE GCInt = GBox(INTEGER);
+END GCInt.

+ 4 - 0
compiler/tests/g_gcprog.mod

@@ -0,0 +1,4 @@
+MODULE GCBoxProg;
+IMPORT GCInt;
+VAR b : GCInt.Box; ExitCode : INTEGER;
+BEGIN b.Put(42); ExitCode := b.Get() END GCBoxProg.

+ 31 - 6
docs/summary_generics-closed-2026-10-16.md

@@ -41,12 +41,37 @@ mismatch).  Suite: `GenericProg`, `PairProg`, `BufProg`, `g_badbuf`,
   cleanly; verified).  The only "same instance twice" case is a
   refinement's DEFINITION and IMPLEMENTATION, which must instantiate
   the generic's def and impl respectively.
-- **`GENERIC CLASS`** — needs a **design decision**, not extension: the
-  current machinery instantiates *modules* by re-parsing a source file.
-  A generic *class* has no natural refinement form yet (a class is a
-  type declared inside a module; instantiating it would re-parse its
-  enclosing module, or require a `TYPE C = GClass(args)` type-refinement
-  affordance).  Until that syntax is chosen, this stays open.
+- **`GENERIC CLASS`** — **already achievable through generic
+  modules** (verified, suite `GCBoxProg`): declare the class in the
+  generic module's `TYPE` block, implement it in the generic impl, and
+  instantiate the module:
+
+  ```modula2
+  GENERIC DEFINITION MODULE GBox (T : TYPE);
+  TYPE
+    CLASS Box;
+      v : T;
+      PROCEDURE Put(x : T);
+      PROCEDURE Get() : T;
+    END Box;
+  END GBox.
+  * GBox's CLASS IMPLEMENTATION Box holds the method bodies;
+  DEFINITION/IMPLEMENTATION MODULE GCInt = GBox(INTEGER);
+  (* program: *)  b : GCInt.Box;  b.Put(42);  ExitCode := b.Get()
+  ```
+
+  So **no standalone `GENERIC CLASS` syntax is required** for the
+  capability.  Standalone syntax would only matter if a class must be
+  instantiated *without* a whole generic module; the principled form
+  for that is a **type refinement** (`TYPE IntStack = Stack(INTEGER);`),
+  which mirrors `MODULE X = G(args)` at type level but needs the
+  class's `CLASS IMPLEMENTATION` block re-parsed/renamed per instance —
+  a design of its own.  Recommendation: keep the generic-module pattern.
+
+  Minor asymmetry noted: a class is accepted as a top-level item in an
+  IMPLEMENTATION/program `DeclSeq` but not in a DEFINITION unit's item
+  list (only inside a `TYPE` block) — harmless, but a tidy-up
+  candidate.
 
 ## Résumé