
# Projektplan: Hybride Monomorphisierung

* **Datum:** 30.10.2025
* **Version:** 1.0

## 1. Motivation

Das aktuelle Typsystem (`Myc.Ast.Types`) ist mächtig, aber die Inferenz für Lambda-Parameter endet bei `stUnknown`. Dies erzwingt Laufzeit-Typüberprüfungen im `TEvaluatorVisitor` und verkompliziert AOT/JIT-Kompilierung.

## 2. Ziel

Implementierung einer **hybriden Monomorphisierungsstrategie** zur Compile-Zeit (innerhalb des `TAstBinder`).

1.  **Statische Spezialisierung:** Alle Funktionsaufrufe, deren Callee *und* Argumenttypen zur Compile-Zeit statisch bekannt sind, werden spezialisiert. `stUnknown` wird für diese Pfade eliminiert.
2.  **Dynamischer Fallback:** Alle dynamischen Aufrufe (z.B. Higher-Order-Funktionen, deren Callee aus einer Variable stammt) nutzen weiterhin den bestehenden dynamischen Pfad (`vkMethod` mit `TDataValue`-Wrapper).
3.  **Optimierungs-Vorbereitung:** Der statisch spezialisierte AST (der "Entrypoint") dient als saubere Basis für optionale Optimierungen (z.B. LLVM-Codegen).

## 3. Ergebnis: Die Strategie

Die Implementierung erfordert eine Erweiterung des `TAstBinder`, um einen **Spezialisierungs-Cache** zu verwalten und bei Bedarf **rekursive Binding-Pässe** durchzuführen.

### Phase 1: Modifikation der Kern-Typen

1.  **`TBoundLambdaExpressionNode` (Generic):**
    * Muss seinen *originalen, ungebundenen* Body (`IAstNode`) behalten, um als Vorlage für das Re-Binding zu dienen.
    * Führt einen **Spezialisierungs-Cache** (z.B. `TDictionary<TSignatureHash, ISpecializedBody>`).
2.  **`ISpecializedBody` (Interface):**
    * Repräsentiert einen erfolgreich monomorphisierten Entrypoint.
    * `function GetBodyAst: IAstNode;`
    * `function GetScopeDescriptor: IScopeDescriptor;`
    * `function GetReturnType: IStaticType;`
3.  **`TBoundFunctionCallNode`:**
    * Benötigt ein neues Feld, um *entweder* den dynamischen Callee (wie bisher) *oder* den statischen `ISpecializedBody` (den Entrypoint) zu halten.

### Phase 2: Anpassung des `TAstBinder` (Trigger)

`TAstBinder.VisitFunctionCall` wird zur zentralen Weichenstellung:

1.  Binde alle Argumente und ermittle ihre statischen Typen (die `Aufrufsignatur`).
2.  Binde den `Callee`.
3.  **Fallunterscheidung:**
    * **Fall A (Dynamischer Aufruf):** Der `Callee` ist *nicht* als `TBoundLambdaExpressionNode` statisch bekannt (z.B. `(map (if flag f1 f2) ...)`).
        * **Aktion:** Der Aufruf wird als dynamisch belassen (Fallback). Es wird lediglich geprüft, ob der `Callee` den Typ `stMethod` hat. Es findet keine Spezialisierung statt.
    * **Fall B (Statischer Aufruf):** Der `Callee` ist ein `TBoundLambdaExpressionNode`.
        * **Aktion:** Trigger die Monomorphisierung.
        * Rufe `Callee.GetSpecialization(Aufrufsignatur)` auf.
        * Der `TBoundFunctionCallNode` wird modifiziert und verweist direkt auf das zurückgegebene `ISpecializedBody`.
        * Der `StaticType` des `TBoundFunctionCallNode` wird auf `ISpecializedBody.GetReturnType` gesetzt.

### Phase 3: Die Monomorphisierung (Der Re-Bind Pass)

Dies ist die Kernlogik (z.B. in `TBoundLambdaExpressionNode.GetSpecialization`):

1.  **Cache-Lookup:** Prüfe, ob für die `Aufrufsignatur` bereits ein `ISpecializedBody` im Cache existiert.
2.  **Cache-Miss (Re-Binding):**
    * Erzeuge einen neuen, temporären `IScopeDescriptor` für den Sub-Bind-Prozess.
    * **Populiere den Scope:** Definiere die Parameter-Namen (z.B. `[a b]`) in diesem Scope, aber verwende die *konkreten Typen* der `Aufrufsignatur` (z.B. `stFloat`, `stOrdinal`) anstelle von `stUnknown`.
    * **Rekursiver Binder:** Erzeuge einen neuen `TAstBinder` (oder rufe den aktuellen re-entrant auf), der den *originalen, ungebundenen Body* des Lambdas mit diesem spezialisierten Scope bindet.
    * **Fehlerbehandlung:** Schlägt dieser Sub-Bind-Prozess fehl (z.B. `ETypeException`, weil `a` (jetzt `stFloat`) mit einem `Text` addiert wird), ist der Aufruf ungültig -> **Compile-Fehler**.
    * **Erfolg:** Das Ergebnis ist der spezialisierte `IAstNode` (Body) und der `IScopeDescriptor`. Erzeuge ein `ISpecializedBody`-Objekt, speichere es im Cache und gib es zurück.

### Phase 4: Anpassung des `TEvaluatorVisitor` (Ausführung)

`TEvaluatorVisitor.VisitFunctionCall` muss nun zwei Arten von Calls behandeln:

1.  **Dynamischer Call:** `Callee` ist `vkMethod`. (Wie bisher: `(calleeValue.AsMethod)(argValues)`).
2.  **Statischer/Monomorphisierter Call:** `Callee` ist ein `ISpecializedBody`.
    * Erzeuge den `IExecutionScope` (via `ISpecializedBody.GetScopeDescriptor`).
    * Populiere den Scope mit den (bereits evaluierten) `argValues`.
    * Führe den `ISpecializedBody.GetBodyAst` direkt mit `Accept(Self)` aus. (TCO muss hier ebenfalls beachtet werden).

### Phase 5: LLVM-Optimierung (Optional)

Der in Phase 3 erzeugte `ISpecializedBody` ist der "corner case" für die Optimierung:

* Wenn ein `ISpecializedBody` erfolgreich erstellt wurde *und* dieser AST-Body die "harten" Kriterien erfüllt (keine dynamischen Internals), wird er als **Kandidat für LLVM-AOT/JIT** markiert.
* Ein LLVM-Backend kann diese Kandidaten aufnehmen, LLVM-IR generieren und den `ISpecializedBody` im Cache durch einen nativen Funktionspointer (den FFI-Entrypoint) ersetzen.

---

## 4. TODOs

* [ ] `TBoundLambdaExpressionNode` erweitern, um den originalen Body und den Spezialisierungs-Cache zu halten.
* [ ] `ISpecializedBody` (oder äquivalente Struktur) definieren.
* [ ] `TAstBinder.VisitFunctionCall` um die Weichenstellung (Fall A/B) erweitern.
* [ ] Den re-entranten Monomorphisierungs-Pass (Phase 3) implementieren.
* [ ] `TEvaluatorVisitor.VisitFunctionCall` für die Ausführung von `ISpecializedBody` anpassen.
* [ ] Typsystem (`TTypeRules`) auf Robustheit für die neuen, strikten Prüfungen im Sub-Bind-Pass testen.