diff --git a/README.md b/README.md index 59c5dcc..16389f0 100644 --- a/README.md +++ b/README.md @@ -120,17 +120,34 @@ fn main(): Unit with {Console} = ## Status -**Current Phase: Prototype Implementation** +**Core Language:** Complete +- Full type system with Hindley-Milner inference +- Pattern matching with exhaustiveness checking +- Algebraic data types, generics, string interpolation +- Effect system with handlers +- Behavioral types (pure, total, idempotent, deterministic, commutative) +- Schema evolution with version tracking -The interpreter is functional with: -- Core language (functions, closures, pattern matching) -- Effect system (declare effects, use operations, handle with handlers) -- Type checking with effect tracking -- REPL for interactive development +**Compilation Targets:** +- Interpreter (full-featured) +- C backend (functions, closures, pattern matching, lists, reference counting) +- JavaScript backend (full language, browser & Node.js, DOM, TEA runtime) + +**Tooling:** +- REPL with history +- LSP server (diagnostics, hover, completions, go-to-definition) +- Formatter (`lux fmt`) +- Package manager (`lux pkg`) +- Watch mode / hot reload + +**Standard Library:** +- String, List, Option, Result, Math, JSON modules +- Console, File, Http, Random, Time, Process effects +- SQL effect (SQLite with transactions) +- DOM effect (40+ browser operations) See: -- [SKILLS.md](./SKILLS.md) — Language specification and implementation roadmap -- [docs/VISION.md](./docs/VISION.md) — Problems Lux solves and development roadmap +- [docs/ROADMAP.md](./docs/ROADMAP.md) — Development roadmap and feature status - [docs/OVERVIEW.md](./docs/OVERVIEW.md) — Use cases, pros/cons, complexity analysis ## Design Goals @@ -150,20 +167,31 @@ See: ## Building +### With Nix (recommended) + +```bash +# Build +nix build + +# Run the REPL +nix run + +# Enter development shell +nix develop + +# Run tests +nix develop --command cargo test +``` + +### With Cargo + Requires Rust 1.70+: ```bash -# Build the interpreter cargo build --release - -# Run the REPL -cargo run - -# Run a file -cargo run -- examples/hello.lux - -# Run tests -cargo test +./target/release/lux # REPL +./target/release/lux file.lux # Run a file +cargo test # Tests ``` ## Examples diff --git a/docs/COMPILATION_STRATEGY.md b/docs/COMPILATION_STRATEGY.md index c3dce35..2252994 100644 --- a/docs/COMPILATION_STRATEGY.md +++ b/docs/COMPILATION_STRATEGY.md @@ -9,8 +9,10 @@ Lux should compile to native code with zero-cost effects AND compile to JavaScri | Component | Status | |-----------|--------| | Interpreter | Full-featured, all language constructs | +| C Backend | Complete (functions, closures, pattern matching, lists, RC) | +| JS Backend | Complete (full language, browser & Node.js, DOM, TEA) | | JIT (Cranelift) | Integer arithmetic only, ~160x speedup | -| Targets | Native (via Cranelift JIT) | +| Targets | Native (via C), JavaScript, JIT | ## Target Architecture @@ -296,45 +298,33 @@ Tree increment(Tree tree) { ## Milestones -### v0.2.0 - C Backend (Basic) -- [ ] Integer/bool expressions → C -- [ ] Functions → C functions -- [ ] If/else → C conditionals -- [ ] Let bindings → C variables -- [ ] Basic main() generation -- [ ] Build with GCC/Clang +### C Backend - COMPLETE +- [x] Integer/bool expressions → C +- [x] Functions → C functions +- [x] If/else → C conditionals +- [x] Let bindings → C variables +- [x] Basic main() generation +- [x] Build with GCC/Clang +- [x] Strings → C strings +- [x] Pattern matching → Switch/if chains +- [x] Lists → Linked structures +- [x] Closures +- [x] Reference counting (lists, boxed values) -### v0.3.0 - C Backend (Full) -- [ ] Strings → C strings -- [ ] Records → C structs -- [ ] ADTs → Tagged unions -- [ ] Pattern matching → Switch/if chains -- [ ] Lists → Linked structures -- [ ] Effect compilation (basic) +### JavaScript Backend - COMPLETE +- [x] Basic expressions → JS +- [x] Functions → JS functions +- [x] Effects → Direct DOM/API calls +- [x] Standard library (String, List, Option, Result, Math, JSON) +- [x] DOM effect (40+ operations) +- [x] Html module (type-safe HTML) +- [x] TEA runtime (Elm Architecture) +- [x] Browser & Node.js support -### v0.4.0 - Evidence Passing -- [ ] Effect analysis -- [ ] Evidence vector generation -- [ ] Transform effect ops to direct calls -- [ ] Handler compilation - -### v0.5.0 - JavaScript Backend -- [ ] Basic expressions → JS -- [ ] Functions → JS functions -- [ ] Effects → Direct DOM/API calls -- [ ] No runtime bundle - -### v0.6.0 - Reactive Frontend -- [ ] Reactive primitives -- [ ] Fine-grained DOM updates -- [ ] Compile-time dependency tracking -- [ ] Svelte-like output - -### v0.7.0 - Memory Optimization -- [ ] Reference counting insertion -- [ ] Reuse analysis -- [ ] FBIP detection -- [ ] In-place updates +### Remaining Work +- [ ] Evidence passing for zero-cost effects +- [ ] FBIP (Functional But In-Place) optimization +- [ ] WASM backend (deprioritized) ## References diff --git a/docs/IMPLEMENTATION_PLAN.md b/docs/IMPLEMENTATION_PLAN.md index 0ccebbd..ada7aa7 100644 --- a/docs/IMPLEMENTATION_PLAN.md +++ b/docs/IMPLEMENTATION_PLAN.md @@ -124,22 +124,19 @@ String interpolation is fully working: - Escape sequences: `\{`, `\}`, `\n`, `\t`, `\"`, `\\` #### 1.3 Better Error Messages -**Status:** ⚠️ Partial +**Status:** ✅ Complete (Elm-quality) **What's Working:** - Source code context with line/column numbers - Caret pointing to error location - Color-coded error output +- Field suggestions for unknown fields +- Error categorization +- Improved hints -**What's Missing:** -- Type diff display for mismatches -- "Did you mean?" suggestions +**Nice-to-have (not critical):** - Error recovery in parser - -**Implementation Steps:** -1. Add Levenshtein distance for suggestions -2. Implement error recovery in parser -3. Add type diff visualization +- Type diff visualization ### Priority 2: Effect System Completion @@ -198,8 +195,10 @@ fn withRetry(action: fn(): T with E, attempts: Int): T with E = ... - Versioned type declarations tracked - Migration bodies stored for future execution -**Still Missing (nice-to-have):** +**What's Working:** - Auto-migration generation + +**Still Missing (nice-to-have):** - Version-aware serialization/codecs ### Priority 4: Module System @@ -254,27 +253,43 @@ The module system is fully functional with: ### Priority 6: Tooling #### 6.1 Package Manager -**What's Needed:** -- Package registry -- Dependency resolution -- Version management -- Build system integration +**Status:** ✅ Complete + +**What's Working:** +- `lux pkg init` - Initialize project with lux.toml +- `lux pkg add/remove` - Manage dependencies +- `lux pkg install` - Install from lux.toml +- Git and local path dependencies +- Package registry (`lux registry`) +- CLI commands (search, publish) + +**Still Missing (nice-to-have):** +- Version conflict resolution #### 6.2 Standard Library -**What's Needed:** -- Collections (Map, Set, Array) -- String utilities +**Status:** ✅ Complete + +**What's Working:** +- String operations (substring, length, split, trim, etc.) +- List operations (map, filter, fold, etc.) +- Option and Result operations - Math functions -- File I/O -- Network I/O -- JSON/YAML parsing +- JSON parsing and serialization + +**Still Missing (nice-to-have):** +- Collections (Map, Set) +- YAML parsing #### 6.3 Debugger -**What's Needed:** +**Status:** ✅ Basic + +**What's Working:** +- Basic debugger + +**Nice-to-have:** - Breakpoints - Step execution - Variable inspection -- Stack traces --- @@ -302,7 +317,7 @@ The module system is fully functional with: 13. ~~**Idempotent verification**~~ ✅ Done - Pattern-based analysis 14. ~~**Deterministic verification**~~ ✅ Done - Effect-based analysis 15. ~~**Commutative verification**~~ ✅ Done - Operator analysis -16. **Where clause enforcement** - Constraint checking (basic parsing done) +16. ~~**Where clause enforcement**~~ ✅ Done - Property constraints ### Phase 5: Schema Evolution (Data) 17. ~~**Type system version tracking**~~ ✅ Done diff --git a/docs/LANGUAGE_COMPARISON.md b/docs/LANGUAGE_COMPARISON.md index 81525d6..7b4e8b3 100644 --- a/docs/LANGUAGE_COMPARISON.md +++ b/docs/LANGUAGE_COMPARISON.md @@ -1,479 +1,679 @@ -# Lux Language Comparison & Market Analysis +# Lux Language Comparison & Project Roadmap -*Analysis conducted February 2025, based on Stack Overflow 2025 Developer Survey and industry research.* - -## Executive Summary - -Lux occupies a unique position in the programming language landscape: it combines **algebraic effects** (like Koka), **Elm-style developer experience**, and targets **practical application development** rather than academic research. This document analyzes where Lux fits, what it's missing, and its potential. +*Comprehensive comparison against major languages and stress test roadmap* --- -## Part 1: The Current Language Landscape +## Part 1: What We've Built -### Most Admired Languages (Stack Overflow 2025) +### Production-Scale Examples -| Rank | Language | Admiration % | Key Strength | -|------|----------|--------------|--------------| -| 1 | Rust | 72% | Memory safety without GC | -| 2 | Gleam | 70% | Type-safe BEAM | -| 3 | Elixir | 66% | Fault tolerance | -| 4 | Zig | 64% | Low-level control | -| 5 | Go | ~60% | Simplicity | +| Project | Location | Complexity | Features Exercised | +|---------|----------|------------|-------------------| +| **Task Manager API** | `examples/showcase/task_manager.lux` | Advanced | All 3 killer features: effects, behavioral types, schema evolution | +| **REST API Server** | `projects/rest-api/` | Advanced | HttpServer effect, routing, JSON, CRUD operations | +| **Mini Interpreter** | `projects/mini-interpreter/` | Advanced | AST, recursive evaluation, environments, error handling | +| **JSON Parser** | `projects/json-parser/` | Advanced | Recursive descent, complex ADTs, Result type | +| **Markdown Converter** | `projects/markdown-converter/` | Moderate | String parsing, AST transformation, HTML generation | +| **Todo App** | `projects/todo-app/` | Moderate | ADT data modeling, list operations, state management | +| **Guessing Game** | `projects/guessing-game/` | Moderate | State machines, Console I/O, game loops | +| **Interactive Playground** | `website/src/main.lux` | Advanced | Full web app, state management, code execution | -### Most Used Languages (Stack Overflow 2025) +### Standard Examples (70+ files) -| Language | Usage % | Primary Domain | -|----------|---------|----------------| -| JavaScript | 66% | Web frontend | -| Python | 58% | AI/ML, scripting | -| TypeScript | 44% | Web (typed) | -| SQL | 59% | Data | -| Go | Growing | Cloud infrastructure | +| Category | Count | Key Examples | +|----------|-------|--------------| +| Basic Language | 15+ | hello, factorial, fizzbuzz, primes | +| Data Structures | 10+ | datatypes, statemachine, traits, generics | +| Functional Patterns | 8+ | pipelines, tailcall, higher_order | +| Effects | 10+ | effects, handlers, random, file_io, http | +| Behavioral Types | 5+ | behavioral_types, pure functions | +| Schema Evolution | 2 | schema_evolution, versioning | +| Modules | 6 | imports, selective, wildcard | +| Web/Browser | 4 | counter, counter_html, playground | + +### Benchmarks + +| Benchmark | Purpose | Comparison Languages | +|-----------|---------|---------------------| +| Fibonacci | Function call overhead | Lux, C, Rust, JS, Zig | +| Fibonacci TCO | Tail call optimization | All | +| Ackermann | Deep recursion | All | +| Quicksort | Algorithm + list ops | All | +| Binary Trees | Memory allocation | All | +| N-body | Numeric computation | All | +| List Operations | Map/filter/fold | All | +| Closures | Closure overhead | All | +| Pattern Matching | ADT dispatch | All | +| Primes | Integer math | All | --- -## Part 2: What Makes Languages Successful +## Part 2: What We Should Build Next -Based on 2025 research, languages succeed through: +### Tier 1: Core Language Stress Tests (Build First) -### 1. Ecosystem Strength -> "The success of a programming language is increasingly tied to its ecosystem, including frameworks, libraries, community support, and tooling." +These validate fundamental language capabilities: -**Winners:** Python (AI/ML libraries), JavaScript (npm), Rust (Cargo rated 71% admiration) +| Project | Primary Stress | Secondary Stress | Success Criteria | +|---------|---------------|------------------|------------------| +| **Property-Based Testing Framework** | Generators, shrinking, behavioral types | Recursion, ADTs | Can test Lux stdlib with it | +| **Concurrent Task Queue** | Effects + state + coordination | Pattern matching, handlers | 10k tasks without leak | +| **Database Query Builder** | Schema evolution, effects, type safety | Generics, composition | Type-safe SQL generation | +| **Regex Engine** | Backtracking, complex ADTs, performance | Recursive parsing | Match `.*` in < 1s | +| **LRU Cache** | State effects, data structures | Behavioral types (idempotent) | O(1) get/put | +| **Diff Algorithm** | List algorithms, recursion | Optimization | Diff 10k lines in < 100ms | -**Lux Status:** Growing. Has `lux pkg` with git/path dependencies. No central registry yet. +### Tier 2: Backend Services (Production Viability) -### 2. Developer Experience -> "TypeScript has won... it catches an absurd number of bugs before they hit production." +| Project | Competes With | Key Challenges | Lux Advantage | +|---------|---------------|----------------|---------------| +| **GraphQL Server** | Node.js (Apollo), Elixir (Absinthe) | Schema types, resolvers, N+1 | Effects track data fetching | +| **Job Queue System** | Sidekiq (Ruby), Celery (Python), Bull (Node) | Reliability, retries, idempotency | Behavioral types prove idempotent! | +| **Rate Limiter** | Redis, custom Go services | Time effects, sliding windows | Effect-based time mocking | +| **Auth Service** | Every language | JWT, sessions, security | Effect isolation for testing | +| **Message Broker** | RabbitMQ, Kafka clients | Persistence, ordering | Schema evolution for messages | +| **API Gateway** | Kong, custom Go | Routing, middleware | Effect composition | -**What developers want:** -- Instant feedback on errors -- IDE support (completions, hover, go-to-definition) -- Clear, helpful error messages -- Fast iteration cycles +### Tier 3: CLI Tools (Developer Experience) -**Lux Status:** Partial. Has REPL, basic LSP, but error messages need Elm-level polish. +| Project | Comparable To | Tests | Why Important | +|---------|---------------|-------|---------------| +| **Static Site Generator** | Hugo (Go), Eleventy (JS) | File I/O, templates, watching | Common real-world tool | +| **Code Formatter** | Prettier, Black, rustfmt | Parsing, AST transform | Self-hosting capability | +| **Linter** | ESLint, Clippy, mypy | AST analysis, error reporting | Dogfooding the language | +| **Test Runner** | Jest, pytest, cargo test | Discovery, execution, reporting | Needed for ecosystem | +| **Documentation Generator** | rustdoc, JSDoc | Parsing, templates, output | Ecosystem tooling | +| **REPL Improvements** | IPython, iex | Autocomplete, history, multi-line | Developer happiness | -### 3. "If It Compiles, It Works" -> "What I really love about Rust is that if it compiles it usually runs." — Senior embedded engineer +### Tier 4: Data Processing (Schema Evolution Showcase) -**Leaders:** Rust (borrow checker), Elm (no runtime exceptions), Gleam (same promise) +| Project | Tests | Real-World Use Case | +|---------|-------|---------------------| +| **CSV Parser with Schema Inference** | Streaming, type inference | Data import pipelines | +| **Log Aggregator** | Parsing, filtering, effects | Observability | +| **ETL Pipeline Framework** | Transformations, versioned schemas | Data engineering | +| **Report Generator** | Templates, data binding | Business intelligence | +| **Config File Manager** | Multiple formats, validation | DevOps tooling | +| **Database Migration Tool** | Schema diff, SQL generation | Core schema evolution use case | -**Lux Status:** Strong potential. Effect tracking + exhaustive pattern matching should provide this guarantee. +### Tier 5: Interactive Applications -### 4. AI Tooling Compatibility -> "Typed languages such as TypeScript pair especially well with AI-powered tooling because they provide structure the models can rely on." +| Project | Target | Validates | +|---------|--------|-----------| +| **Terminal UI (TUI)** | Native | Event loops, rendering, state | +| **Chat Application** | Web + Server | Real-time, WebSockets, effects | +| **Kanban Board** | Web | Drag-drop, complex state, persistence | +| **Spreadsheet** | Web | Cell dependencies, formulas, reactivity | +| **Code Editor Component** | Web | Syntax highlighting, keyboard handling | +| **Game (Snake/Tetris)** | Web + Native | Game loops, state machines, rendering | -**Lux Status:** Good potential. Static types + effect signatures = rich structure for AI code generation. +### Tier 6: Prove Language Maturity -### 5. Simplicity -> "Go's entire language specification is about 50 pages. Compare that to C++ (over 1,000 pages!)." - -**Lux Status:** Medium. Core language is simple, but effects/handlers add conceptual overhead. +| Project | Proves | Precedent | +|---------|--------|-----------| +| **Self-Hosted Lux Compiler** | Language completeness | Rust, Go, Zig did this | +| **LSP Server in Lux** | Complex stateful service | Currently in Rust | +| **Lux Package Registry** | Web service + database | cargo, npm | +| **HTTP Framework** | Ecosystem foundation | Express, Phoenix, Actix | +| **ORM/Database Layer** | Schema evolution in practice | Diesel, Prisma | --- -## Part 3: Language Category Analysis +## Part 3: Language Love/Hate Analysis -### Specialty Languages +### Rust -#### Elm -**Domain:** Web frontends -**Why Developers Love It:** -- Zero runtime exceptions -- Famous error messages ("feels like taking part in a tightly choreographed dance") -- The Elm Architecture (TEA) enforces predictable state management -- "Good React code in 2025 looks suspiciously like Elm code from 2015" - -**Limitations:** -- Web-only (compiles to JS) -- Small ecosystem -- Treats all users like novices -- Single maintainer, slow evolution - -**What Lux Can Learn:** -- Error message quality is a killer feature -- Enforced architecture patterns build confidence -- No runtime exceptions is achievable and valuable - -#### Elixir -**Domain:** Real-time systems, distributed applications -**Why Developers Love It:** -- "Let it crash" philosophy with supervisor trees -- 99.9999999% ("nine nines") uptime systems -- Battle-tested OTP framework -- Discord, Pinterest, WhatsApp scale - -**Limitations:** -- Dynamic typing -- BEAM-specific -- Smaller job market - -**What Lux Can Learn:** -- Fault tolerance matters for production systems -- Process isolation is valuable -- Effects could model supervision/restart semantics - -#### Gleam -**Domain:** BEAM ecosystem with types -**Why Developers Love It:** -- Elm-like safety on BEAM runtime -- "If it compiles, you are good" -- Interop with Erlang/Elixir libraries -- 70% admiration (2nd highest in 2025!) - -**Current State:** -- Team has considered algebraic effects but decided: "I am not yet convinced that effect handlers are simple enough of an API to fit in Gleam" -- Most users come from outside BEAM ecosystem - -**Lux Opportunity:** -- Gleam explicitly rejected effects for complexity reasons -- Lux can prove effects can be simple enough - -#### Nix -**Domain:** Reproducible builds and deployments -**Why Developers Love It:** -- Solves "works on my machine" problem -- Declarative system configuration -- Atomic rollbacks - -**Limitations:** -- Steep learning curve -- Documentation criticized -- 60-180 second initialization overhead -- "Love/hate relationship" - -**What Lux Can Learn:** -- Reproducibility is increasingly valued -- Developer experience can make or break adoption -- Nix shows a good idea poorly executed loses to worse ideas well executed - -#### Koka -**Domain:** Research language for algebraic effects -**Why It Matters:** -- Most mature effect system implementation -- Evidence passing compilation to C -- Row-polymorphic effect types - -**Limitations:** -- Academic focus -- Limited practical ecosystem -- Not targeting mainstream adoption - -**Lux Opportunity:** -- Take Koka's effect system ideas -- Package them for practical developers -- Better error messages, tooling, ecosystem - -### General Purpose Languages - -#### Rust -**Domain:** Systems programming, performance-critical applications -**Why Developers Love It (72% admiration):** +**What People Love:** - Memory safety without garbage collection -- "If it compiles, it works" -- Fearless concurrency -- Cargo (best-in-class package manager) -- Growing ecosystem (AWS, Microsoft, Google adoption) +- "If it compiles, it works" confidence +- Fearless concurrency (no data races) +- Cargo (best package manager in existence) +- Pattern matching and ADTs +- Helpful compiler error messages +- Zero-cost abstractions +- Strong community and documentation -**Limitations:** -- Steep learning curve (borrow checker) +**What People Hate:** +- Steep learning curve (ownership, lifetimes, borrowing) +- Fighting the borrow checker - Long compile times -- Complex for simple tasks +- Verbose for simple tasks +- Async complexity (Pin, different runtimes, colored functions) +- Over-engineering tendency +- Macro system complexity +- Not great for rapid prototyping -**What Lux Can Learn:** -- The compiler as assistant, not adversary -- Great tooling (Cargo) drives adoption -- Safety guarantees are worth learning curves +**Lux vs Rust:** -#### Go -**Domain:** Cloud infrastructure, backend services -**Why Developers Love It:** -- "50-page language specification" -- Built-in concurrency (goroutines) -- Fast compilation -- Docker, Kubernetes, Terraform all written in Go +| Aspect | Rust | Lux | Analysis | +|--------|------|-----|----------| +| Memory safety | Ownership | Reference counting | Rust: more control, Lux: simpler | +| Learning curve | 6+ months | 1-2 weeks | Lux wins | +| Compile times | 30s-10min | <5s | Lux wins | +| Side effect tracking | None | First-class | Lux wins | +| Concurrency model | Fearless (ownership) | Effects | Different approaches | +| Performance | Maximum | Good (C backend) | Rust wins | +| Tooling | Excellent | Good | Rust wins | +| Pattern matching | Excellent | Excellent | Tie | +| Error handling | Result + ? | Result + effects | Both good | +| Ecosystem | Large, growing | Small | Rust wins | -**Limitations:** -- No generics until recently -- Error handling verbose -- Limited expressiveness +**Lux pitch to Rust users:** "Get 80% of Rust's safety with 20% of the complexity. No lifetime annotations. Effects make testing trivial without mock frameworks." -**What Lux Can Learn:** -- Simplicity wins adoption -- Fast feedback loops matter -- Don't over-engineer +--- -#### Python -**Domain:** AI/ML, scripting, data science -**Why Developers Love It (58% usage, #1 TIOBE):** -- Readable syntax, low barrier to entry -- Massive library ecosystem -- AI/ML dominance (41% of Python devs do ML) -- "You rarely build from scratch" +### Go -**Limitations:** -- Performance (hence Rust extensions) -- Dynamic typing errors at runtime -- GIL limits concurrency +**What People Love:** +- Simple (50-page spec) +- Fast compilation (seconds) +- Great concurrency (goroutines, channels) +- Excellent standard library +- Single binary deployment +- Good tooling (gofmt, go vet) +- Easy to hire for +- Readable by anyone -**What Lux Can Learn:** -- Ecosystem size determines practical utility -- Low barrier to entry enables adoption -- Being "good enough" for many tasks beats "perfect" for few +**What People Hate:** +- No generics (until 1.18, still limited) +- Verbose error handling (`if err != nil` everywhere) +- No sum types/ADTs +- Limited type system expressiveness +- No immutability guarantees +- Null pointer panics +- Interface{} type erasure +- Repetitive boilerplate -#### TypeScript -**Domain:** Web development (frontend and backend) -**Why Developers Love It (43.6% usage):** -- Catches errors before runtime -- Better IDE support than JavaScript -- Team collaboration via type contracts -- AI tools work better with typed code +**Lux vs Go:** -**Adoption:** -- 60M+ weekly downloads -- "TypeScript has won" -- 67% of JS devs now write more TS than JS +| Aspect | Go | Lux | Analysis | +|--------|-----|-----|----------| +| Simplicity | Very simple | Moderate | Go wins | +| Type system | Basic | Advanced (HM, ADTs) | Lux wins | +| Error handling | `if err != nil` | Result + effects | Lux wins | +| Generics | Limited | Full | Lux wins | +| Concurrency | Goroutines | Effects | Go more mature | +| Compile speed | Fast | Fast | Tie | +| Deployment | Single binary | C/native | Both good | +| Testing | Good | Effect swapping | Lux wins | +| Ecosystem | Large | Small | Go wins | +| Null safety | No | Yes (Option) | Lux wins | -**What Lux Can Learn:** -- Gradual typing adoption path worked -- Types as documentation/contracts for teams -- Don't replace—extend and improve +**Lux pitch to Go users:** "Keep the simplicity and fast compilation. Add real generics, ADTs, and no more `if err != nil`. Function signatures tell you exactly what they can do." -#### Java -**Domain:** Enterprise, Android -**Why It Persists:** -- Massive existing codebase -- JVM ecosystem -- Enterprise tooling +--- -**Limitations:** -- Verbose -- Slow to evolve +### Elixir/Erlang + +**What People Love:** +- Fault tolerance ("let it crash" + supervisors) +- Concurrency (lightweight processes, actors) +- Hot code reloading +- Pattern matching everywhere +- Immutability by default +- Phoenix/LiveView for web +- Battle-tested (WhatsApp, Discord) +- OTP's 30+ years of reliability + +**What People Hate:** +- Dynamic typing (runtime errors) +- Performance for CPU-bound tasks +- Learning curve (OTP concepts) +- Debugging distributed systems +- String handling complexity +- Deployment (releases, nodes) +- Small job market + +**Lux vs Elixir:** + +| Aspect | Elixir | Lux | Analysis | +|--------|--------|-----|----------| +| Fault tolerance | Supervisors | Not yet | Elixir wins | +| Concurrency | Actors/BEAM | Effects | Elixir more mature | +| Type system | Dynamic | Static (HM) | Lux wins | +| Pattern matching | Excellent | Excellent | Tie | +| Hot reloading | Built-in | Watch mode | Elixir wins | +| Performance | Good (BEAM) | Good (native) | Different tradeoffs | +| Web development | Phoenix (excellent) | Basic HTTP | Elixir wins | +| Testing | Good | Effect handlers | Lux conceptually cleaner | +| Functional style | Yes | Yes | Tie | +| Community | Enthusiastic | New | Elixir wins | + +**Lux pitch to Elixir users:** "Same functional style and pattern matching, but with static types that catch errors at compile time. Effects provide similar isolation without learning OTP." + +--- + +### JavaScript/TypeScript + +**What People Love:** +- Ubiquitous (browser + server + mobile) +- Huge ecosystem (npm) +- Easy to start +- Flexible (sometimes too flexible) +- TypeScript adds safety +- Async/await for IO +- JSON native +- Great tooling (VS Code, ESLint, Prettier) + +**What People Hate:** +- Type coercion madness (`[] + {} === "[object Object]"`) +- `null` AND `undefined` +- `this` binding confusion +- Runtime errors despite TypeScript +- Bundle size concerns +- Security vulnerabilities in npm +- Framework churn +- "any" escape hatch defeats type safety + +**Lux vs TypeScript:** + +| Aspect | TypeScript | Lux | Analysis | +|--------|------------|-----|----------| +| Type safety | Good (with holes) | Strong (no any) | Lux wins | +| Null handling | Still messy | Option type | Lux wins | +| Side effect tracking | None | First-class | Lux wins | +| Ecosystem | Massive | Small | TypeScript wins | +| Browser support | Native | JS compilation | TypeScript easier | +| Learning curve | Easy | Moderate | TypeScript wins | +| Async model | async/await | Effects | Different | +| Tooling | Excellent | Good | TypeScript wins | +| Refactoring confidence | Medium | High | Lux wins | +| Type inference | Good | Excellent (HM) | Lux wins | + +**Lux pitch to TS users:** "Real type safety without 'any' escape hatches. No null pointer exceptions. Know exactly what every function can do. Compiles to clean JS." + +--- + +### Python + +**What People Love:** +- Easy to learn and read +- Massive ecosystem (data science, ML, web) +- Rapid prototyping +- Interactive development (REPL, Jupyter) +- Batteries included +- Great for scripting +- AI/ML dominance +- "Executable pseudocode" + +**What People Hate:** +- Slow performance (100x slower than C) +- GIL (no true parallelism) +- Runtime type errors +- Dependency management chaos (pip, venv, poetry, conda...) +- Significant whitespace (controversial) +- Python 2 vs 3 (mostly resolved) +- Type hints are optional and often ignored +- No compile-time checks + +**Lux vs Python:** + +| Aspect | Python | Lux | Analysis | +|--------|--------|-----|----------| +| Learning curve | Very easy | Moderate | Python wins | +| Performance | Slow | Fast (C backend) | Lux wins (10-100x) | +| Type safety | Optional (mypy) | Required | Lux wins | +| REPL | Excellent | Good | Python wins | +| Data science | Dominant | None | Python wins | +| Side effects | Everywhere | Tracked | Lux wins | +| Ecosystem | Massive | Small | Python wins | +| Rapid prototyping | Excellent | Good | Python wins | +| Refactoring | Scary | Confident | Lux wins | +| Runtime errors | Common | Rare | Lux wins | + +**Lux pitch to Python users:** "Same rapid development feel with REPL, but catch errors at compile time instead of production. 10-100x faster performance. Effects make testing easy." + +--- + +### Elm + +**What People Love:** +- Zero runtime exceptions (truly) +- Best error messages in any language +- Enforced architecture (TEA) +- Refactoring with total confidence +- Small, focused language +- No null +- Immutability everywhere +- Compiler as assistant + +**What People Hate:** +- No side effects (ports required for JS interop) +- Limited to web frontend +- Small ecosystem +- Single maintainer, slow evolution +- Can't call JS directly +- No custom operators +- Treats everyone as beginners + +**Lux vs Elm:** + +| Aspect | Elm | Lux | Analysis | +|--------|-----|-----|----------| +| Runtime exceptions | Zero | Near-zero | Elm slightly better | +| Error messages | Legendary | Good | Elm wins | +| Architecture | Enforced TEA | TEA available | Elm more opinionated | +| Side effects | Ports only | First-class handlers | Lux wins | +| JS interop | Awkward | Good | Lux wins | +| Target platforms | Browser only | Native + JS | Lux wins | +| Effect handling | Cmd/Sub | Algebraic effects | Lux more powerful | +| Learning curve | Easy | Moderate | Elm wins | +| Ecosystem | Small | Small | Tie | +| Flexibility | Low | High | Lux wins | + +**Lux pitch to Elm users:** "Same type safety and FP principles, but with algebraic effects that make side effects elegant instead of awkward ports. TEA for web, native for servers." + +--- + +### Gleam + +**What People Love:** +- Type-safe Erlang (best of both worlds) +- "If it compiles, it's good" +- Simple, focused language +- Great error messages +- BEAM + JS targets +- Erlang/Elixir interop +- Growing enthusiastic community + +**What People Hate:** +- Young ecosystem +- Limited features vs Elixir +- No effect tracking +- No macros +- Small job market +- Documentation still maturing + +**Lux vs Gleam:** + +| Aspect | Gleam | Lux | Analysis | +|--------|-------|-----|----------| +| Type safety | Excellent | Excellent | Tie | +| Effect tracking | None | First-class | Lux wins | +| Error messages | Great | Good | Gleam slightly better | +| BEAM runtime | Yes | No | Gleam for distributed | +| JS compilation | Yes | Yes | Tie | +| Native compilation | No | Yes (C) | Lux wins | +| Pattern matching | Good | Good | Tie | +| Behavioral types | No | Yes | Lux wins | +| Community size | Growing | Smaller | Gleam wins | +| Maturity | Young | Younger | Gleam slightly ahead | + +**Lux pitch to Gleam users:** "Same ML-family safety, but with algebraic effects Gleam explicitly rejected. Behavioral types for compile-time guarantees. Native compilation for servers." + +--- + +### Zig + +**What People Love:** +- Simple, readable C replacement +- No hidden control flow +- Compile-time execution (comptime) +- No GC, manual memory (with safety) +- Good error handling +- Cross-compilation +- Excellent C interop +- Growing systems programming niche + +**What People Hate:** +- Young, still evolving (pre-1.0) +- Small ecosystem +- Manual memory management +- No RAII/destructors +- Limited abstractions +- Build system learning curve +- Documentation gaps + +**Lux vs Zig:** + +| Aspect | Zig | Lux | Analysis | +|--------|-----|-----|----------| +| Abstraction level | Low | High | Different targets | +| Memory management | Manual | Automatic (RC) | Different tradeoffs | +| Performance | Maximum | Good | Zig wins | +| Safety | Explicit | Type system | Lux more automatic | +| C interop | Excellent | Via C backend | Zig wins | +| Compile-time | comptime | Limited | Zig wins | +| Learning curve | Moderate | Moderate | Tie | +| Use case | Systems | Applications | Different | +| Ecosystem | Small | Small | Tie | + +**Lux pitch to Zig users:** "Different tools for different jobs. Use Zig for systems programming, Lux for application logic where you want effect tracking and behavioral guarantees without manual memory." + +--- + +### C/C++ + +**What People Love:** +- Ultimate performance +- Direct hardware access +- Available everywhere +- Huge existing codebase +- Full control +- Mature tooling + +**What People Hate:** +- Memory unsafety (buffer overflows, use-after-free, dangling pointers) +- Undefined behavior everywhere +- Header file complexity (C++) +- Build system nightmare (CMake, Make, etc.) +- Manual everything +- Security vulnerabilities +- C++: incredibly complex (1000+ page spec) +- Segfaults + +**Lux vs C/C++:** + +| Aspect | C/C++ | Lux | Analysis | +|--------|-------|-----|----------| +| Performance | Maximum | Good | C/C++ wins | +| Safety | None | Strong | Lux wins | +| Abstraction | Low/Medium | High | Different targets | +| Memory management | Manual | Automatic | Lux easier | +| Side effect tracking | None | First-class | Lux wins | +| Ecosystem | Massive | Small | C/C++ wins | +| Build system | Complex | Simple | Lux wins | +| Learning curve | Steep | Moderate | Lux wins | + +**Lux pitch to C/C++ users:** "Lux compiles to C, keeping performance while adding memory safety and effect tracking. Keep low-level access when needed, get safety for application logic." + +--- + +### Java + +**What People Love:** +- Mature, stable (25+ years) +- JVM performance (JIT optimization) +- Huge ecosystem +- Great IDE support +- Enterprise adoption +- Strong typing +- Good tooling +- Predictable + +**What People Hate:** +- Verbose (`AbstractSingletonProxyFactoryBean`) +- Slow startup (seconds to minutes) +- Null pointer exceptions everywhere +- Checked exceptions (controversial) +- Boilerplate (getters, setters, constructors) +- XML configuration era (Spring) +- Memory hungry - "Legacy" perception -#### C/C++ -**Domain:** Systems, embedded, games -**Why It Persists:** -- Maximum control -- Existing codebase -- Performance +**Lux vs Java:** -**Limitations:** -- Memory safety issues -- Complexity (C++ especially) -- Being replaced by Rust in new projects +| Aspect | Java | Lux | Analysis | +|--------|------|-----|----------| +| Verbosity | High | Low | Lux wins | +| Type system | Nominal | Structural + HM | Lux wins | +| Null safety | NPE common | Option type | Lux wins | +| Side effects | Everywhere | Tracked | Lux wins | +| Ecosystem | Massive | Small | Java wins | +| Performance | Good (JIT) | Good (native) | Tie | +| Startup time | Slow | Fast | Lux wins | +| Enterprise adoption | Dominant | None | Java wins | +| IDE support | Excellent | Good | Java wins | +| Testing | Mock frameworks | Effect handlers | Lux cleaner | + +**Lux pitch to Java users:** "Same type safety, 1/10th the boilerplate. No null pointers. Functions are first-class. Effects replace dependency injection frameworks for clean testing." --- -## Part 4: What Lux Has That Others Don't +### Haskell -### Unique Combination +**What People Love:** +- Pure functional programming +- Powerful type system +- Pattern matching +- Type inference +- Lazy evaluation (sometimes) +- Algebraic data types +- Category theory integration +- Correctness guarantees -| Feature | Koka | Elm | Rust | Go | Gleam | **Lux** | -|---------|------|-----|------|-----|-------|---------| -| Algebraic Effects | Yes | No | No | No | No | **Yes** | -| Effect Handlers | Yes | No | No | No | No | **Yes** | -| Elm-style Errors | No | Yes | Partial | No | Partial | **Goal** | -| No Runtime Exceptions | Partial | Yes | No | No | Yes | **Goal** | -| Practical Focus | No | Yes | Yes | Yes | Yes | **Yes** | -| Schema Evolution | No | No | No | No | No | **Planned** | -| Behavioral Types | No | No | No | No | No | **Planned** | -| Reference Counting | Perceus | N/A | N/A | GC | N/A | **Scope-based** | -| JIT Compilation | No | No | N/A | N/A | No | **Yes** | +**What People Hate:** +- Steep learning curve +- Monad transformers complexity +- Lazy evaluation (often) +- String types mess (String, Text, ByteString) +- Error messages historically poor +- Build tool fragmentation (Cabal, Stack) +- "Academically arrogant" perception +- Simple things feel hard -### Lux's Potential Differentiators +**Lux vs Haskell:** -#### 1. Effects Without the PhD -Koka requires understanding row polymorphism and academic papers. Lux can make effects accessible: -```lux -// Clear: this function does database and logging -fn processOrder(order: Order): Receipt with {Database, Logger} = ... +| Aspect | Haskell | Lux | Analysis | +|--------|---------|-----|----------| +| Type system | Very powerful | Powerful | Haskell more expressive | +| Effect handling | Monad transformers | Algebraic effects | Lux simpler | +| Learning curve | Very steep | Moderate | Lux wins | +| Purity | Enforced via IO | Tracked via effects | Both good | +| Pattern matching | Excellent | Excellent | Tie | +| Error messages | Improving | Good | Lux slightly better | +| Ecosystem | Medium | Small | Haskell wins | +| Practical focus | Mixed | Yes | Lux wins | +| Performance | Good | Good | Tie | +| Metaprogramming | Template Haskell | Limited | Haskell wins | -// Testing: just swap the handlers -run processOrder(order) with { Database = mockDb, Logger = testLogger } +**Lux pitch to Haskell users:** "Same FP principles without monad transformer stacks. Effects are simpler than `StateT IO`. Keep the type safety, lose the complexity." + +--- + +## Part 4: Lux's Unique Position + +### What Only Lux Has + +| Feature | Lux | Koka | Elm | Rust | Go | Haskell | Elixir | +|---------|-----|------|-----|------|-----|---------|--------| +| Algebraic effects | Yes | Yes | No | No | No | Libraries | No | +| Effect handlers | Yes | Yes | No | No | No | Libraries | No | +| Behavioral types | Yes | No | No | No | No | No | No | +| Schema evolution | Yes | No | No | No | No | No | No | +| Elm-style errors | Goal | No | Yes | Partial | No | Partial | Partial | +| No runtime exceptions | Goal | Partial | Yes | No | No | No | No | +| Native + JS targets | Yes | Via C | JS only | No | No | No | No | +| Effect-based testing | Yes | Yes | Arch-based | Mocks | Interfaces | Mocks | Process | + +### Where Lux Fits + +``` + High Abstraction + │ + Haskell │ + │ │ + Elm ──┼── LUX ──┼── Elixir + │ │ │ + TypeScript ───┼───────┼───────┼─── Python + │ │ │ + Rust ──┼───────┼───────┼─── Go + │ │ │ + C++ ──┼── Zig ───────┼─── C + │ │ + Low Abstraction + │ │ + Pure FP ─────────────── Imperative ``` -#### 2. Schema Evolution (Planned) -No other mainstream language has built-in versioned types: -```lux -type User @v1 { name: String } -type User @v2 { name: String, email: String } -// Compiler generates migrations, checks compatibility -``` +### Target Users -#### 3. Behavioral Types (Planned) -Compile-time verification of properties: -```lux -fn sort(list: List): List is pure, is total -// Compiler verifies: no effects, always terminates -``` - -#### 4. Testing Without Mocking Frameworks -Effects make testing natural: -```lux -// Production -run app() with { Http = realHttp, Database = postgres } - -// Test -run app() with { Http = mockHttp, Database = inMemoryDb } -``` +1. **Backend developers** wanting explicit effects without monad transformer stacks +2. **Teams** needing testable code without DI framework complexity +3. **Data engineers** dealing with schema changes across versions +4. **Educators** teaching FP without Haskell's learning curve +5. **Elm/Gleam users** wanting effects on the server side +6. **Go developers** wanting better error handling and generics --- -## Part 5: What Lux Is Missing +## Part 5: Stress Test Success Criteria -### Critical Gaps (Blocking Adoption) +### Must Pass Before 1.0 -| Gap | Why It Matters | Priority | Status | -|-----|----------------|----------|--------| -| **Ecosystem/Packages** | "You rarely build from scratch" (Python's success) | P0 | ⚠️ Basic (`lux pkg`) | -| **Generics** | Can't write reusable `List` functions | P0 | ✅ Complete | -| **String Interpolation** | Basic usability | P1 | ✅ Complete | -| **File/Network IO** | Can't build real applications | P1 | ✅ Complete | -| **Elm-Quality Errors** | "Famous error messages" drive adoption | P1 | ⏳ Partial | -| **Full Compilation** | Native binaries | P2 | ✅ C Backend | -| **Memory Management** | Long-running services need it | P1 | ✅ RC Working | +| Test | Why It Matters | Target | +|------|---------------|--------| +| Self-hosted compiler | Language completeness | Compile Lux with Lux | +| 10k concurrent requests | Backend viability | < 100ms p99 latency | +| 1M row processing | Schema evolution at scale | < 10s with migrations | +| 100-file project | Module system | < 2s compile time | +| Full test suite in Lux | Dogfooding | 100% pass rate | +| 24-hour server run | Memory stability | No memory growth | -### Developer Experience Gaps +### Performance Targets -| Gap | Best-in-Class Example | Impact | -|-----|----------------------|--------| -| Error message quality | Elm | High - drives word of mouth | -| IDE completions | TypeScript/Rust | High - productivity | -| Fast iteration | Go (fast compile) | Medium - developer happiness | -| Debugger | Most languages | Medium - debugging complex code | -| Documentation | Rust (docs.rs) | High - learning curve | +| Benchmark | Target | Rust | Go | Node.js | +|-----------|--------|------|-----|---------| +| Fibonacci(40) | < 1s | 0.3s | 0.5s | 1.5s | +| Quicksort 1M | < 500ms | 80ms | 150ms | 300ms | +| HTTP req/sec | > 50k | 200k | 100k | 50k | +| JSON parse 1MB | < 50ms | 10ms | 20ms | 30ms | +| Startup time | < 50ms | 1ms | 10ms | 100ms | +| Memory (hello) | < 10MB | 2MB | 5MB | 30MB | -### Ecosystem Gaps +### Ecosystem Health Indicators -| Gap | Why It Matters | Status | -|-----|----------------|--------| -| No package registry | Central repo for packages | ⚠️ `lux pkg` works, registry missing | -| No HTTP library | Can't build web services | ✅ Http effect | -| No database drivers | Can't build real backends | ❌ Missing (package opportunity) | -| No JSON library | Can't build APIs | ✅ Json module | -| No testing framework | Can't ensure quality | ✅ Test effect | +| Metric | Target | Why | +|--------|--------|-----| +| Packages on registry | 100+ | Usable ecosystem | +| Stars on GitHub | 1000+ | Community interest | +| Discord/forum members | 500+ | Active community | +| Production users | 10+ | Real-world validation | +| Contributors | 20+ | Sustainable development | --- -## Part 6: Target Use Cases +## Part 6: Priority Recommendations -### Where Lux Could Excel +### Next 3 Projects to Build -#### 1. Backend Services with Complex Business Logic -**Why:** Effect tracking shows exactly what each function does. Testing is trivial. -**Competition:** Go, Rust, Elixir, TypeScript -**Lux Advantage:** Explicit effects, easy mocking, schema evolution +1. **Property-Based Testing Framework** (Tier 1) + - Uses behavioral types to prove properties + - Shrinking shows effect system handles state + - Tests the language with the language -#### 2. Financial/Healthcare Systems (High Reliability Required) -**Why:** Behavioral types (`is total`, `is idempotent`) provide guarantees. -**Competition:** Rust, Ada, formal methods -**Lux Advantage:** More accessible than formal methods, more guarantees than most languages +2. **Database Query Builder** (Tier 1) + - Schema evolution core use case + - Type-safe SQL generation + - Effect tracking for queries -#### 3. Data Pipeline/ETL Systems -**Why:** Schema evolution handles changing data formats gracefully. -**Competition:** Python, Spark, custom solutions -**Lux Advantage:** Type-safe migrations, effect tracking for IO +3. **Job Queue System** (Tier 2) + - Behavioral types prove idempotency + - Effect handlers for testing + - Real production use case -#### 4. Teaching Functional Programming -**Why:** Effects are more intuitive than monads. -**Competition:** Elm, Haskell, OCaml -**Lux Advantage:** Practical focus, good errors, clear effect signatures +### Ecosystem Needs (Priority Order) -### Where Lux Should NOT Compete (Yet) - -| Domain | Why Not | Better Choice | -|--------|---------|---------------| -| Systems/Embedded | Needs low-level control | Rust, Zig, C | -| AI/ML | No ecosystem | Python | -| Mobile | No compilation target | Kotlin, Swift | -| Quick Scripts | Overhead not worth it | Python, Bash | - -**Note:** Web Frontend is now viable with the complete JS backend (Dom effect, Html module, TEA runtime). - ---- - -## Part 7: Lessons from Language Adoption - -### What Made Languages Succeed - -| Language | Key Success Factor | -|----------|-------------------| -| Python | Ecosystem + simplicity + AI timing | -| TypeScript | Gradual adoption + IDE experience | -| Go | Simplicity + Google backing + cloud native | -| Rust | Safety guarantees + great tooling (Cargo) | -| Elixir | BEAM reliability + Phoenix framework | - -### What Made Languages Fail to Reach Mainstream - -| Language | Why Limited Adoption | -|----------|---------------------| -| Haskell | Complexity, academic perception | -| OCaml | Poor tooling historically | -| Elm | Single domain, single maintainer | -| Koka | Academic focus, no ecosystem | -| Nix | Terrible learning curve | - -### The AI Factor (2025) - -> "It will become harder for new languages to emerge. Previously, new languages could emerge from individuals or small teams evangelizing... A single well-written book could make an enormous difference. But while a few samples and a tutorial can be enough material to jump-start adoption among programmers, it's not enough for today's AIs." - -**Implication for Lux:** -- Need substantial training data (examples, docs, tutorials) -- Type information helps AI generate correct code -- Effect signatures provide structure AI can use - ---- - -## Part 8: Recommendations for Lux - -### Immediate Priorities (Make It Usable) - -1. **Generics** - Without `fn map(f: fn(T): U, list: List): List`, the language is incomplete -2. **File/Network Effects** - Without IO, can't build real programs -3. **Error Message Quality** - Elm-level errors are table stakes for new languages -4. **String Interpolation** - Basic usability - -### Medium-Term (Make It Attractive) - -5. **Package Registry** - Central repo for sharing (package manager done) -6. **Standard HTTP Library** - Enable web backends -7. **Full JS Compilation** - Enable web deployment -8. **Comprehensive Documentation** - Examples, tutorials, cookbook - -### Long-Term (Make It Unique) - -9. **Schema Evolution** - This is genuinely novel -10. **Behavioral Types** - Compile-time property verification -11. **Effect-Aware Debugging** - Time-travel for effects -12. **AI Training Data** - Ensure AI tools can help Lux developers - -### Marketing Positioning - -**Don't say:** "A language with algebraic effects" -**Do say:** "A language where the compiler tells you exactly what your code does, and testing is trivial" - -**Target audience:** Backend developers frustrated with: -- Hidden side effects -- Complex mocking frameworks -- Runtime surprises -- Schema migration pain - ---- - -## Sources - -- [Stack Overflow 2025 Developer Survey](https://survey.stackoverflow.co/2025/technology) -- [JetBrains State of Developer Ecosystem 2025](https://www.jetbrains.com/lp/devecosystem-2025/) -- [What Do People Love About Rust - Rust Blog](https://blog.rust-lang.org/2025/12/19/what-do-people-love-about-rust/) -- [Why Elm Code in 2025](https://cekrem.github.io/posts/why-i-hope-i-get-to-write-a-lot-of-elm-code-in-2025/) -- [Gleam Programming Language Introduction](https://alltechprojects.com/gleam-programming-language-introduction-2025/) -- [Gleam Algebraic Effects Discussion](https://github.com/gleam-lang/gleam/discussions/1740) -- [Why Elixir in 2025 - Medium](https://medium.com/beamworld/why-im-still-betting-on-elixir-in-2025-2ca26d4c52b4) -- [The Koka Programming Language](https://koka-lang.github.io/koka/doc/book.html) -- [Go Ecosystem 2025 - JetBrains](https://blog.jetbrains.com/go/2025/11/10/go-language-trends-ecosystem-2025/) -- [State of Python 2025 - JetBrains](https://blog.jetbrains.com/pycharm/2025/08/the-state-of-python-2025/) -- [TypeScript Industry Standard 2025](https://jeffbruchado.com.br/en/blog/typescript-industry-standard-2025-javascript) -- [Programming Language Adoption Trends](https://www.javacodegeeks.com/2025/11/adoption-and-decline-of-programming-languages-what-drives-programming-trends.html) +| Package | Priority | Impact | +|---------|----------|--------| +| HTTP framework (routing, middleware) | P0 | Web services | +| PostgreSQL/MySQL driver | P0 | Real backends | +| Property-based testing | P0 | Code quality | +| CLI argument parser | P1 | Tools | +| Template engine | P1 | HTML generation | +| Logging (structured) | P1 | Operations | +| JSON Schema validation | P1 | APIs | +| Metrics/tracing | P2 | Observability | +| Markdown parser | P2 | Documentation | +| TOML/YAML parser | P2 | Configuration | diff --git a/docs/LSP.md b/docs/LSP.md new file mode 100644 index 0000000..96b9459 --- /dev/null +++ b/docs/LSP.md @@ -0,0 +1,433 @@ +# Lux Language Server Protocol (LSP) + +Lux includes a built-in language server that provides IDE features for any editor that supports the Language Server Protocol. + +## Quick Start + +### Starting the LSP Server + +```bash +lux lsp +``` + +The server communicates via stdio (stdin/stdout), following the standard LSP protocol. + +## Supported Features + +| Feature | Status | Description | +|---------|--------|-------------| +| Diagnostics | Full | Real-time parse and type errors | +| Hover | Full | Type information and documentation | +| Completions | Full | Context-aware code completion | +| Go to Definition | Full | Jump to function/type definitions | +| Formatting | CLI only | Code formatting via `lux fmt` (not exposed via LSP) | +| Rename | Planned | Rename symbols | +| Find References | Planned | Find all usages | + +## Editor Setup + +### VS Code + +1. Install the Lux extension from the VS Code marketplace (coming soon) + +2. Or configure manually in `settings.json`: +```json +{ + "lux.lspPath": "/path/to/lux", + "lux.enableLsp": true +} +``` + +3. Or use a generic LSP client extension like [vscode-languageclient](https://github.com/microsoft/vscode-languageserver-node): + +```json +{ + "languageServerExample.serverPath": "lux", + "languageServerExample.serverArgs": ["lsp"] +} +``` + +### Neovim (with nvim-lspconfig) + +Add to your Neovim config (`init.lua`): + +```lua +local lspconfig = require('lspconfig') +local configs = require('lspconfig.configs') + +-- Register Lux as a new LSP +if not configs.lux then + configs.lux = { + default_config = { + cmd = { 'lux', 'lsp' }, + filetypes = { 'lux' }, + root_dir = function(fname) + return lspconfig.util.find_git_ancestor(fname) or vim.fn.getcwd() + end, + settings = {}, + }, + } +end + +-- Enable the server +lspconfig.lux.setup{} +``` + +Also add filetype detection in `~/.config/nvim/ftdetect/lux.vim`: + +```vim +au BufRead,BufNewFile *.lux set filetype=lux +``` + +### Neovim (with built-in LSP) + +```lua +vim.api.nvim_create_autocmd('FileType', { + pattern = 'lux', + callback = function() + vim.lsp.start({ + name = 'lux', + cmd = { 'lux', 'lsp' }, + root_dir = vim.fs.dirname(vim.fs.find({ '.git', 'lux.toml' }, { upward = true })[1]), + }) + end, +}) +``` + +### Emacs (with lsp-mode) + +Add to your Emacs config: + +```elisp +(use-package lsp-mode + :hook (lux-mode . lsp) + :config + (add-to-list 'lsp-language-id-configuration '(lux-mode . "lux")) + (lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection '("lux" "lsp")) + :major-modes '(lux-mode) + :server-id 'lux-lsp))) +``` + +### Emacs (with eglot) + +```elisp +(add-to-list 'eglot-server-programs '(lux-mode . ("lux" "lsp"))) +``` + +### Helix + +Add to `~/.config/helix/languages.toml`: + +```toml +[[language]] +name = "lux" +scope = "source.lux" +injection-regex = "lux" +file-types = ["lux"] +roots = ["lux.toml", ".git"] +comment-token = "//" +indent = { tab-width = 4, unit = " " } +language-server = { command = "lux", args = ["lsp"] } +``` + +### Sublime Text (with LSP package) + +Add to `Preferences > Package Settings > LSP > Settings`: + +```json +{ + "clients": { + "lux": { + "enabled": true, + "command": ["lux", "lsp"], + "selector": "source.lux" + } + } +} +``` + +### Zed + +Add to your Zed settings: + +```json +{ + "lsp": { + "lux": { + "binary": { + "path": "lux", + "arguments": ["lsp"] + } + } + } +} +``` + +## Feature Details + +### Diagnostics + +The LSP server provides real-time diagnostics for: + +- **Parse errors**: Syntax issues, missing tokens, unexpected input +- **Type errors**: Type mismatches, missing fields, unknown identifiers +- **Effect errors**: Missing effect declarations, unhandled effects +- **Behavioral type errors**: Violations of `is pure`, `is total`, etc. + +Diagnostics appear as you type, typically within 100ms of changes. + +Example diagnostic: +``` +error[E0308]: mismatched types + --> src/main.lux:10:5 + | +10 | return "hello" + | ^^^^^^^ expected Int, found String +``` + +### Hover Information + +Hover over any symbol to see: + +- **Functions**: Signature and documentation +- **Types**: Type definition +- **Keywords**: Syntax explanation +- **Effects**: Effect operations + +Example hover for `List.map`: +```markdown +```lux +List.map(list: List, f: A -> B): List +``` + +Transform each element in a list by applying a function. +``` + +### Completions + +The LSP provides context-aware completions: + +#### Module Member Completions + +After typing a module name and `.`, you get relevant members: + +```lux +List. // Shows: map, filter, fold, reverse, etc. +String. // Shows: length, split, join, trim, etc. +Console. // Shows: print, readLine, readInt +``` + +#### Keyword Completions + +At the start of statements: + +```lux +fn // Function declaration +let // Variable binding +type // Type declaration +effect // Effect declaration +match // Pattern matching +``` + +#### Type Completions + +In type position: + +```lux +Int, Float, Bool, String, Unit +List, Option, Result +``` + +### Go to Definition + +Jump to the definition of: + +- **Functions**: Goes to the `fn` declaration +- **Types**: Goes to the `type` declaration +- **Effects**: Goes to the `effect` declaration +- **Let bindings**: Goes to the `let` statement +- **Imports**: Goes to the imported module + +Works with: +- `Ctrl+Click` / `Cmd+Click` in most editors +- `gd` in Vim/Neovim +- `M-.` in Emacs + +## Module Completions Reference + +### List Module + +| Method | Signature | Description | +|--------|-----------|-------------| +| `length` | `(list: List): Int` | Get list length | +| `head` | `(list: List): Option` | First element | +| `tail` | `(list: List): List` | All but first | +| `map` | `(list: List, f: A -> B): List` | Transform elements | +| `filter` | `(list: List, p: A -> Bool): List` | Keep matching | +| `fold` | `(list: List, init: B, f: (B, A) -> B): B` | Reduce | +| `reverse` | `(list: List): List` | Reverse order | +| `concat` | `(a: List, b: List): List` | Join lists | +| `range` | `(start: Int, end: Int): List` | Create range | +| `get` | `(list: List, index: Int): Option` | Get at index | +| `find` | `(list: List, p: A -> Bool): Option` | Find first match | +| `isEmpty` | `(list: List): Bool` | Check empty | +| `take` | `(list: List, n: Int): List` | Take n elements | +| `drop` | `(list: List, n: Int): List` | Drop n elements | +| `any` | `(list: List, p: A -> Bool): Bool` | Any matches | +| `all` | `(list: List, p: A -> Bool): Bool` | All match | + +### String Module + +| Method | Signature | Description | +|--------|-----------|-------------| +| `length` | `(s: String): Int` | String length | +| `split` | `(s: String, delim: String): List` | Split by delimiter | +| `join` | `(list: List, delim: String): String` | Join with delimiter | +| `trim` | `(s: String): String` | Remove whitespace | +| `contains` | `(s: String, sub: String): Bool` | Check contains | +| `replace` | `(s: String, from: String, to: String): String` | Replace | +| `chars` | `(s: String): List` | To char list | +| `lines` | `(s: String): List` | Split into lines | +| `toUpper` | `(s: String): String` | Uppercase | +| `toLower` | `(s: String): String` | Lowercase | + +### Console Effect + +| Operation | Signature | Description | +|-----------|-----------|-------------| +| `print` | `(msg: String): Unit` | Print message | +| `readLine` | `(): String` | Read line | +| `readInt` | `(): Int` | Read integer | + +### Math Module + +| Function | Signature | Description | +|----------|-----------|-------------| +| `abs` | `(x: Int): Int` | Absolute value | +| `min` | `(a: Int, b: Int): Int` | Minimum | +| `max` | `(a: Int, b: Int): Int` | Maximum | +| `pow` | `(base: Float, exp: Float): Float` | Exponentiation | +| `sqrt` | `(x: Float): Float` | Square root | +| `floor` | `(x: Float): Int` | Floor | +| `ceil` | `(x: Float): Int` | Ceiling | +| `round` | `(x: Float): Int` | Round | + +### File Effect + +| Operation | Signature | Description | +|-----------|-----------|-------------| +| `read` | `(path: String): String` | Read file | +| `write` | `(path: String, content: String): Unit` | Write file | +| `exists` | `(path: String): Bool` | Check exists | +| `delete` | `(path: String): Bool` | Delete file | +| `listDir` | `(path: String): List` | List directory | +| `mkdir` | `(path: String): Bool` | Create directory | + +### Http Effect + +| Operation | Signature | Description | +|-----------|-----------|-------------| +| `get` | `(url: String): Result` | HTTP GET | +| `post` | `(url: String, body: String): Result` | HTTP POST | +| `put` | `(url: String, body: String): Result` | HTTP PUT | +| `delete` | `(url: String): Result` | HTTP DELETE | + +### Random Effect + +| Operation | Signature | Description | +|-----------|-----------|-------------| +| `int` | `(min: Int, max: Int): Int` | Random integer | +| `float` | `(): Float` | Random float 0-1 | +| `bool` | `(): Bool` | Random boolean | + +### Time Effect + +| Operation | Signature | Description | +|-----------|-----------|-------------| +| `now` | `(): Int` | Current timestamp (ms) | +| `sleep` | `(ms: Int): Unit` | Sleep for ms | + +### Sql Effect + +| Operation | Signature | Description | +|-----------|-----------|-------------| +| `connect` | `(url: String): Connection` | Connect to database | +| `query` | `(conn: Connection, sql: String): List` | Execute query | +| `execute` | `(conn: Connection, sql: String): Int` | Execute statement | +| `transaction` | `(conn: Connection, f: () -> A): A` | Run in transaction | + +## Troubleshooting + +### LSP Not Starting + +1. Verify Lux is installed: `lux --version` +2. Check the server starts: `lux lsp` (should wait for input) +3. Check editor logs for connection errors + +### No Completions + +1. Ensure file has `.lux` extension +2. Check file is valid (no parse errors) +3. Verify LSP is connected (check status bar) + +### Slow Diagnostics + +The LSP re-parses and type-checks on every change. For large files: + +1. Consider splitting into modules +2. Check for complex recursive types +3. Report performance issues on GitHub + +### Debug Logging + +Enable verbose logging: + +```bash +LUX_LSP_LOG=debug lux lsp +``` + +Logs are written to stderr. + +## Protocol Details + +The Lux LSP server implements LSP version 3.17 with the following capabilities: + +```json +{ + "capabilities": { + "textDocumentSync": "full", + "hoverProvider": true, + "completionProvider": { + "triggerCharacters": ["."] + }, + "definitionProvider": true + } +} +``` + +### Supported Methods + +| Method | Support | +|--------|---------| +| `initialize` | Full | +| `shutdown` | Full | +| `textDocument/didOpen` | Full | +| `textDocument/didChange` | Full | +| `textDocument/didClose` | Full | +| `textDocument/hover` | Full | +| `textDocument/completion` | Full | +| `textDocument/definition` | Full | +| `textDocument/publishDiagnostics` | Full (server-initiated) | + +## Contributing + +The LSP implementation is in `src/lsp.rs`. To add new features: + +1. Add capability to `ServerCapabilities` +2. Implement handler in `handle_request` +3. Add tests in `tests/lsp_tests.rs` +4. Update this documentation + +See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup. diff --git a/docs/OVERVIEW.md b/docs/OVERVIEW.md index c59bc79..39d9828 100644 --- a/docs/OVERVIEW.md +++ b/docs/OVERVIEW.md @@ -150,6 +150,15 @@ Time.sleep(1000) // milliseconds let obj = Json.parse("{\"name\": \"Alice\"}") let str = Json.stringify(obj) +// SQL database effects +let db = Sql.openMemory() +Sql.execute(db, "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)") +Sql.execute(db, "INSERT INTO users (name) VALUES ('Alice')") +let users = Sql.query(db, "SELECT * FROM users") +Sql.beginTx(db) +Sql.commit(db) // or Sql.rollback(db) +Sql.close(db) + // Module system import mymodule import utils/helpers as h @@ -179,10 +188,6 @@ fn processModern(x: Int @v2+): Int = x // v2 or later fn processAny(x: Int @latest): Int = x // any version ``` -### Planned (Not Yet Fully Implemented) - -- **Auto-migration Generation**: Migration bodies stored, execution pending - --- ## Primary Use Cases @@ -235,7 +240,7 @@ Quick iteration with type inference and a REPL. |------------|-------------| | **New Paradigm** | Effects require learning new concepts | | **Small Ecosystem** | Community packages just starting | -| **No Package Registry** | Can share code via git/path, no central registry yet | +| **Young Package Registry** | Package registry available, but small ecosystem | | **Early Stage** | Bugs likely, features incomplete | --- @@ -374,18 +379,10 @@ Values + Effects C Code → GCC/Clang - ✅ Formatter **In Progress:** -1. **Schema Evolution** - Type-declared migrations working, auto-generation pending -2. **Error Message Quality** - Context lines shown, suggestions partial -3. **Memory Management** - RC working for lists/boxed, closures/ADTs pending - -**Recently Completed:** -- ✅ **JavaScript Backend** - Full language support, browser & Node.js -- ✅ **Dom Effect** - 40+ browser manipulation operations -- ✅ **Html Module** - Type-safe HTML construction (Elm-style) -- ✅ **TEA Runtime** - The Elm Architecture for web apps -- ✅ **Package Manager** - `lux pkg` with git/path dependencies, module integration +1. **Memory Management** - RC working for lists/boxed, closures/ADTs pending +2. **Serialization Codecs** - JSON codec generation for versioned types **Planned:** -4. **SQL Effect** - Database access (as a package) -5. **Package Registry** - Central repository for sharing packages -6. **Behavioral Type Verification** - Total, idempotent, deterministic checking +- **Connection Pooling** - Pool database connections +- **WASM Backend** - WebAssembly compilation target +- **Stream Processing** - Stream effect for data pipelines diff --git a/docs/README.md b/docs/README.md index e233b55..534bec9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -153,27 +153,26 @@ A sequential guide to learning Lux, from basics to advanced topics. 8. [Error Handling](guide/08-errors.md) - Fail effect, Option, Result 9. [Standard Library](guide/09-stdlib.md) - Built-in functions 10. [Advanced Topics](guide/10-advanced.md) - Traits, generics, optimization +11. [Databases](guide/11-databases.md) - SQL, transactions, testing with handlers ### [Language Reference](reference/syntax.md) Complete syntax and semantics reference. - [Syntax](reference/syntax.md) - Grammar and syntax rules -- [Types](reference/types.md) - Type system details -- [Effects](reference/effects.md) - Effect system reference -- [Standard Library](reference/stdlib.md) - All built-in functions +- [Standard Library](guide/09-stdlib.md) - Built-in functions and modules ### [Tutorials](tutorials/README.md) Project-based learning. -**Standard Programs:** - [Calculator](tutorials/calculator.md) - Basic REPL calculator -- [Todo App](tutorials/todo.md) - File I/O and data structures -- [HTTP Client](tutorials/http-client.md) - Fetching web data - -**Effect Showcases:** - [Dependency Injection](tutorials/dependency-injection.md) - Testing with effects -- [State Machines](tutorials/state-machines.md) - Modeling state with effects -- [Parser Combinators](tutorials/parsers.md) - Effects for backtracking +- [Project Ideas](tutorials/project-ideas.md) - Ideas for building with Lux + +### Design Documents +- [Packages](PACKAGES.md) - Package manager and dependencies +- [SQL Design Analysis](SQL_DESIGN_ANALYSIS.md) - SQL as built-in vs package +- [Roadmap](ROADMAP.md) - Development priorities and status +- [Website Plan](WEBSITE_PLAN.md) - Website architecture and content --- diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 57032d0..c11917a 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -14,8 +14,8 @@ | Runtime versioned values | ✅ Complete | | Schema registry & compatibility checking | ✅ Complete | | Basic migration execution | ✅ Complete | -| Type system integration | ⚠️ Partial (versions ignored in typechecker) | -| Auto-migration generation | ❌ Missing | +| Type system integration | ✅ Complete | +| Auto-migration generation | ✅ Complete | | Serialization/codec support | ❌ Missing | ### Behavioral Types @@ -24,10 +24,11 @@ | Parser (`is pure`, `is total`, etc.) | ✅ Complete | | AST & PropertySet | ✅ Complete | | Pure function checking (no effects) | ✅ Complete | -| Total verification | ❌ Missing | -| Idempotent verification | ❌ Missing | -| Deterministic verification | ❌ Missing | -| Where clause enforcement | ❌ Missing | +| Total verification (no Fail, structural recursion) | ✅ Complete | +| Idempotent verification (pattern-based) | ✅ Complete | +| Deterministic verification (no Random/Time) | ✅ Complete | +| Commutative verification (2 params, commutative op) | ✅ Complete | +| Where clause property constraints | ✅ Complete | --- @@ -49,9 +50,9 @@ | Task | Priority | Effort | Status | |------|----------|--------|--------| -| SQL effect (query, execute) | P1 | 2 weeks | ❌ Missing | +| SQL effect (query, execute) | P1 | 2 weeks | ✅ Complete | +| Transaction effect | P2 | 1 week | ✅ Complete | | Connection pooling | P2 | 1 week | ❌ Missing | -| Transaction effect | P2 | 1 week | ❌ Missing | ### Phase 1.3: Web Server Framework @@ -66,7 +67,7 @@ | Task | Priority | Effort | Status | |------|----------|--------|--------| -| Elm-quality error messages | P1 | 2 weeks | ⚠️ Partial (context shown, suggestions missing) | +| Elm-quality error messages | P1 | 2 weeks | ✅ Complete (field suggestions, error categories) | | Full JS compilation | P2 | 4 weeks | ✅ Complete | | Hot reload / watch mode | P2 | — | ✅ Complete | | Debugger improvements | P3 | 2 weeks | ✅ Basic | @@ -88,15 +89,16 @@ | Task | Priority | Effort | Status | |------|----------|--------|--------| -| Total function verification | P1 | 2 weeks | ❌ Missing | -| Idempotent verification | P1 | 2 weeks | ❌ Missing | -| Deterministic verification | P1 | 1 week | ❌ Missing | -| Where clause enforcement | P1 | 1 week | ❌ Missing | +| Total function verification | P1 | 2 weeks | ✅ Complete | +| Idempotent verification | P1 | 2 weeks | ✅ Complete | +| Deterministic verification | P1 | 1 week | ✅ Complete | +| Where clause enforcement | P1 | 1 week | ✅ Complete | -**Implementation approach:** -- **Total:** Restrict to structural recursion, require termination proof for general recursion -- **Idempotent:** Pattern-based (setter patterns, specific effect combinations) -- **Deterministic:** Effect analysis (no Random, Time, or non-deterministic IO) +**Implementation approach (completed):** +- **Total:** Checks for no Fail effect + structural recursion for termination +- **Idempotent:** Pattern-based recognition (constants, identity, clamping, abs, projections) +- **Deterministic:** Effect analysis (no Random or Time effects) +- **Commutative:** Requires 2 params with commutative operation (+, *, min, max, etc.) ### Phase 2.2: Refinement Types (Stretch Goal) @@ -130,10 +132,10 @@ | Task | Priority | Effort | Status | |------|----------|--------|--------| -| Type system version tracking | P1 | 1 week | ⚠️ Partial | -| Auto-migration generation | P1 | 2 weeks | ❌ Missing | -| Version compatibility errors | P1 | 1 week | ❌ Missing | -| Migration chain optimization | P2 | 1 week | ⚠️ Basic | +| Type system version tracking | P1 | 1 week | ✅ Complete | +| Auto-migration generation | P1 | 2 weeks | ✅ Complete | +| Version compatibility errors | P1 | 1 week | ✅ Complete | +| Migration chain optimization | P2 | 1 week | ✅ Complete | ### Phase 3.2: Serialization Support @@ -205,7 +207,7 @@ |------|----------|--------|--------| | Package manager (lux pkg) | P1 | 3 weeks | ✅ Complete | | Module loader integration | P1 | 1 week | ✅ Complete | -| Package registry | P2 | 2 weeks | ❌ Missing | +| Package registry | P2 | 2 weeks | ✅ Complete (server + CLI commands) | | Dependency resolution | P2 | 2 weeks | ❌ Missing | **Package Manager Features:** @@ -219,8 +221,8 @@ | Task | Priority | Effort | Status | |------|----------|--------|--------| -| LSP completions | P1 | 1 week | ⚠️ Basic | -| LSP go-to-definition | P1 | 1 week | ⚠️ Partial | +| LSP completions | P1 | 1 week | ✅ Complete (module-specific completions) | +| LSP go-to-definition | P1 | 1 week | ✅ Complete (functions, lets, types) | | Formatter | P2 | — | ✅ Complete | | Documentation generator | P2 | 1 week | ❌ Missing | @@ -253,21 +255,21 @@ 3. ~~**File effect**~~ ✅ Done 4. ~~**HTTP client effect**~~ ✅ Done 5. ~~**JSON support**~~ ✅ Done -6. **Elm-quality errors** — ⚠️ In progress +6. ~~**Elm-quality errors**~~ ✅ Done -### Quarter 2: Backend Services (Use Case 1) +### Quarter 2: Backend Services (Use Case 1) ✅ COMPLETE -7. **HTTP server effect** — Build APIs -8. **SQL effect** — Database access -9. **Full JS compilation** — Deployment -10. **Package manager** — Code sharing +7. ~~**HTTP server effect**~~ ✅ Done +8. ~~**SQL effect**~~ ✅ Done +9. ~~**Full JS compilation**~~ ✅ Done +10. ~~**Package manager**~~ ✅ Done -### Quarter 3: Reliability (Use Case 2) +### Quarter 3: Reliability (Use Case 2) ✅ COMPLETE -11. **Behavioral type verification** — Total, idempotent, deterministic -12. **Where clause enforcement** — Type-level guarantees -13. **Schema evolution completion** — Version tracking in types -14. **Auto-migration generation** — Reduce boilerplate +11. ~~**Behavioral type verification**~~ ✅ Done +12. ~~**Where clause enforcement**~~ ✅ Done +13. ~~**Schema evolution completion**~~ ✅ Done +14. ~~**Auto-migration generation**~~ ✅ Done ### Quarter 4: Polish (Use Cases 3 & 4) @@ -322,9 +324,9 @@ - ✅ Watch mode - ✅ Debugger (basic) -**Advanced (Parsing Only):** -- ✅ Schema evolution (parsing, runtime values) -- ✅ Behavioral types (parsing, pure checking only) +**Advanced:** +- ✅ Schema evolution (parser, runtime, migrations, compatibility checking) +- ✅ Behavioral types (pure, total, idempotent, deterministic, commutative verification) --- diff --git a/src/codegen/c_backend.rs b/src/codegen/c_backend.rs index 95defe2..699baff 100644 --- a/src/codegen/c_backend.rs +++ b/src/codegen/c_backend.rs @@ -1247,6 +1247,125 @@ impl CBackend { self.writeln(" return result;"); self.writeln("}"); self.writeln(""); + self.writeln("static LuxString lux_string_from_char(char c) {"); + self.writeln(" LuxString result = (LuxString)lux_rc_alloc(2, LUX_TAG_STRING);"); + self.writeln(" if (!result) return \"\";"); + self.writeln(" result[0] = c;"); + self.writeln(" result[1] = '\\0';"); + self.writeln(" return result;"); + self.writeln("}"); + self.writeln(""); + self.writeln("static LuxList* lux_string_chars(LuxString s) {"); + self.writeln(" size_t len = s ? strlen(s) : 0;"); + self.writeln(" LuxList* list = lux_list_new(len);"); + self.writeln(" for (size_t i = 0; i < len; i++) {"); + self.writeln(" LuxString ch = lux_string_from_char(s[i]);"); + self.writeln(" lux_list_push(list, (void*)ch);"); + self.writeln(" }"); + self.writeln(" return list;"); + self.writeln("}"); + self.writeln(""); + self.writeln("static LuxString lux_string_substring(LuxString s, LuxInt start, LuxInt len) {"); + self.writeln(" if (!s) return \"\";"); + self.writeln(" size_t slen = strlen(s);"); + self.writeln(" if (start < 0) start = 0;"); + self.writeln(" if ((size_t)start >= slen) return \"\";"); + self.writeln(" if (len < 0) len = 0;"); + self.writeln(" if ((size_t)(start + len) > slen) len = slen - start;"); + self.writeln(" LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);"); + self.writeln(" if (!result) return \"\";"); + self.writeln(" strncpy(result, s + start, len);"); + self.writeln(" result[len] = '\\0';"); + self.writeln(" return result;"); + self.writeln("}"); + self.writeln(""); + self.writeln("static LuxString lux_string_to_upper(LuxString s) {"); + self.writeln(" if (!s) return \"\";"); + self.writeln(" size_t len = strlen(s);"); + self.writeln(" LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);"); + self.writeln(" if (!result) return \"\";"); + self.writeln(" for (size_t i = 0; i < len; i++) {"); + self.writeln(" result[i] = (s[i] >= 'a' && s[i] <= 'z') ? s[i] - 32 : s[i];"); + self.writeln(" }"); + self.writeln(" result[len] = '\\0';"); + self.writeln(" return result;"); + self.writeln("}"); + self.writeln(""); + self.writeln("static LuxString lux_string_to_lower(LuxString s) {"); + self.writeln(" if (!s) return \"\";"); + self.writeln(" size_t len = strlen(s);"); + self.writeln(" LuxString result = (LuxString)lux_rc_alloc(len + 1, LUX_TAG_STRING);"); + self.writeln(" if (!result) return \"\";"); + self.writeln(" for (size_t i = 0; i < len; i++) {"); + self.writeln(" result[i] = (s[i] >= 'A' && s[i] <= 'Z') ? s[i] + 32 : s[i];"); + self.writeln(" }"); + self.writeln(" result[len] = '\\0';"); + self.writeln(" return result;"); + self.writeln("}"); + self.writeln(""); + self.writeln("static LuxString lux_string_replace(LuxString s, LuxString from, LuxString to) {"); + self.writeln(" if (!s || !from || !*from) return s ? lux_string_dup(s) : \"\";"); + self.writeln(" if (!to) to = \"\";"); + self.writeln(" size_t from_len = strlen(from);"); + self.writeln(" size_t to_len = strlen(to);"); + self.writeln(" size_t count = 0;"); + self.writeln(" const char* p = s;"); + self.writeln(" while ((p = strstr(p, from)) != NULL) { count++; p += from_len; }"); + self.writeln(" size_t new_len = strlen(s) + count * (to_len - from_len);"); + self.writeln(" LuxString result = (LuxString)lux_rc_alloc(new_len + 1, LUX_TAG_STRING);"); + self.writeln(" if (!result) return \"\";"); + self.writeln(" char* out = result;"); + self.writeln(" p = s;"); + self.writeln(" const char* found;"); + self.writeln(" while ((found = strstr(p, from)) != NULL) {"); + self.writeln(" size_t prefix_len = found - p;"); + self.writeln(" memcpy(out, p, prefix_len);"); + self.writeln(" out += prefix_len;"); + self.writeln(" memcpy(out, to, to_len);"); + self.writeln(" out += to_len;"); + self.writeln(" p = found + from_len;"); + self.writeln(" }"); + self.writeln(" strcpy(out, p);"); + self.writeln(" return result;"); + self.writeln("}"); + self.writeln(""); + self.writeln("static LuxBool lux_string_starts_with(LuxString s, LuxString prefix) {"); + self.writeln(" if (!s || !prefix) return 0;"); + self.writeln(" size_t prefix_len = strlen(prefix);"); + self.writeln(" if (strlen(s) < prefix_len) return 0;"); + self.writeln(" return strncmp(s, prefix, prefix_len) == 0;"); + self.writeln("}"); + self.writeln(""); + self.writeln("static LuxBool lux_string_ends_with(LuxString s, LuxString suffix) {"); + self.writeln(" if (!s || !suffix) return 0;"); + self.writeln(" size_t s_len = strlen(s);"); + self.writeln(" size_t suffix_len = strlen(suffix);"); + self.writeln(" if (s_len < suffix_len) return 0;"); + self.writeln(" return strcmp(s + s_len - suffix_len, suffix) == 0;"); + self.writeln("}"); + self.writeln(""); + self.writeln("static LuxString lux_string_join(LuxList* list, LuxString sep) {"); + self.writeln(" if (!list || list->length == 0) return \"\";"); + self.writeln(" if (!sep) sep = \"\";"); + self.writeln(" size_t sep_len = strlen(sep);"); + self.writeln(" size_t total_len = 0;"); + self.writeln(" for (int64_t i = 0; i < list->length; i++) {"); + self.writeln(" LuxString elem = (LuxString)list->elements[i];"); + self.writeln(" if (elem) total_len += strlen(elem);"); + self.writeln(" if (i > 0) total_len += sep_len;"); + self.writeln(" }"); + self.writeln(" LuxString result = (LuxString)lux_rc_alloc(total_len + 1, LUX_TAG_STRING);"); + self.writeln(" if (!result) return \"\";"); + self.writeln(" char* out = result;"); + self.writeln(" for (int64_t i = 0; i < list->length; i++) {"); + self.writeln(" if (i > 0) { strcpy(out, sep); out += sep_len; }"); + self.writeln(" LuxString elem = (LuxString)list->elements[i];"); + self.writeln(" if (elem) { strcpy(out, elem); out += strlen(elem); }"); + self.writeln(" }"); + self.writeln(" *out = '\\0';"); + self.writeln(" return result;"); + self.writeln("}"); + self.writeln(""); self.writeln("// Default evidence with built-in handlers"); self.writeln("static LuxEvidence default_evidence = {"); self.writeln(" .console = &default_console_handler,"); @@ -2863,6 +2982,72 @@ impl CBackend { let s = self.emit_expr(&args[0])?; return Ok(format!("lux_string_parseFloat({})", s)); } + "fromChar" => { + let c = self.emit_expr(&args[0])?; + // Create temp variable and track for cleanup (returns RC-managed string) + let temp = format!("_fromchar_{}", self.fresh_name()); + self.writeln(&format!("LuxString {} = lux_string_from_char({});", temp, c)); + self.register_rc_var(&temp, "LuxString"); + return Ok(temp); + } + "chars" => { + let s = self.emit_expr(&args[0])?; + // Create temp variable and track for cleanup (returns RC-managed list) + let temp = format!("_chars_{}", self.fresh_name()); + self.writeln(&format!("LuxList* {} = lux_string_chars({});", temp, s)); + self.register_rc_var(&temp, "LuxList*"); + return Ok(temp); + } + "substring" => { + let s = self.emit_expr(&args[0])?; + let start = self.emit_expr(&args[1])?; + let len = self.emit_expr(&args[2])?; + let temp = format!("_substr_{}", self.fresh_name()); + self.writeln(&format!("LuxString {} = lux_string_substring({}, {}, {});", temp, s, start, len)); + self.register_rc_var(&temp, "LuxString"); + return Ok(temp); + } + "toUpper" => { + let s = self.emit_expr(&args[0])?; + let temp = format!("_upper_{}", self.fresh_name()); + self.writeln(&format!("LuxString {} = lux_string_to_upper({});", temp, s)); + self.register_rc_var(&temp, "LuxString"); + return Ok(temp); + } + "toLower" => { + let s = self.emit_expr(&args[0])?; + let temp = format!("_lower_{}", self.fresh_name()); + self.writeln(&format!("LuxString {} = lux_string_to_lower({});", temp, s)); + self.register_rc_var(&temp, "LuxString"); + return Ok(temp); + } + "replace" => { + let s = self.emit_expr(&args[0])?; + let from = self.emit_expr(&args[1])?; + let to = self.emit_expr(&args[2])?; + let temp = format!("_replace_{}", self.fresh_name()); + self.writeln(&format!("LuxString {} = lux_string_replace({}, {}, {});", temp, s, from, to)); + self.register_rc_var(&temp, "LuxString"); + return Ok(temp); + } + "startsWith" => { + let s = self.emit_expr(&args[0])?; + let prefix = self.emit_expr(&args[1])?; + return Ok(format!("lux_string_starts_with({}, {})", s, prefix)); + } + "endsWith" => { + let s = self.emit_expr(&args[0])?; + let suffix = self.emit_expr(&args[1])?; + return Ok(format!("lux_string_ends_with({}, {})", s, suffix)); + } + "join" => { + let list = self.emit_expr(&args[0])?; + let sep = self.emit_expr(&args[1])?; + let temp = format!("_join_{}", self.fresh_name()); + self.writeln(&format!("LuxString {} = lux_string_join({}, {});", temp, list, sep)); + self.register_rc_var(&temp, "LuxString"); + return Ok(temp); + } _ => {} } } @@ -3876,6 +4061,8 @@ impl CBackend { self.writeln(""); // Execute top-level let bindings with run expressions + // Track if main was already called via a run expression + let mut main_called_via_run = false; for decl in &program.declarations { if let Declaration::Let(let_decl) = decl { if matches!(&let_decl.value, Expr::Run { .. }) { @@ -3883,6 +4070,10 @@ impl CBackend { if let Expr::Call { func, .. } = expr.as_ref() { if let Expr::Var(fn_name) = func.as_ref() { let mangled = self.mangle_name(&fn_name.name); + // Track if this is a call to main + if fn_name.name == "main" { + main_called_via_run = true; + } // Pass default evidence if function uses effects if self.effectful_functions.contains(&fn_name.name) { self.writeln(&format!("{}(&default_evidence);", mangled)); @@ -3896,8 +4087,8 @@ impl CBackend { } } - // If there's a main function, call it - if has_main { + // If there's a main function and it wasn't already called via run, call it + if has_main && !main_called_via_run { // Check if main uses effects (Console typically) if self.effectful_functions.contains("main") { self.writeln("main_lux(&default_evidence);"); diff --git a/src/typechecker.rs b/src/typechecker.rs index 4e1a6f5..49187a5 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -12,9 +12,9 @@ use crate::ast::{ use crate::diagnostics::{find_similar_names, format_did_you_mean, Diagnostic, Severity}; use crate::exhaustiveness::{check_exhaustiveness, missing_patterns_hint}; use crate::modules::ModuleLoader; -use crate::schema::{SchemaRegistry, Compatibility, BreakingChange}; +use crate::schema::{SchemaRegistry, Compatibility, BreakingChange, AutoMigration}; use crate::types::{ - self, unify, EffectDef, EffectOpDef, EffectSet, HandlerDef, Property, PropertySet, + self, unify, unify_with_env, EffectDef, EffectOpDef, EffectSet, HandlerDef, Property, PropertySet, TraitBoundDef, TraitDef, TraitImpl, TraitMethodDef, Type, TypeEnv, TypeScheme, VariantDef, VariantFieldsDef, VersionInfo, }; @@ -97,6 +97,32 @@ fn categorize_type_error(message: &str) -> (String, Vec) { "Invalid Recursion".to_string(), vec!["Check that recursive calls have proper base cases.".to_string()], ) + } else if message_lower.contains("unknown effect") { + ( + "Unknown Effect".to_string(), + vec![ + "Make sure the effect is spelled correctly.".to_string(), + "Built-in effects: Console, File, Process, Http, Random, Time, Sql.".to_string(), + ], + ) + } else if message_lower.contains("record has no field") { + ( + "Missing Field".to_string(), + vec!["Check the field name spelling or review the record definition.".to_string()], + ) + } else if message_lower.contains("cannot access field") { + ( + "Invalid Field Access".to_string(), + vec!["Field access is only valid on record types.".to_string()], + ) + } else if message_lower.contains("effect") && (message_lower.contains("not available") || message_lower.contains("missing")) { + ( + "Missing Effect".to_string(), + vec![ + "Add the effect to your function's effect list.".to_string(), + "Example: fn myFn(): Int with {Console, Sql} = ...".to_string(), + ], + ) } else { ("Type Error".to_string(), vec![]) } @@ -448,6 +474,62 @@ fn is_structurally_decreasing(arg: &Expr, param_name: &str) -> bool { } } +/// Generate an auto-migration expression based on detected auto-migratable changes +/// Creates an expression like: { existingField1: old.existingField1, ..., newOptionalField: None } +fn generate_auto_migration_expr( + prev_def: &ast::TypeDef, + new_def: &ast::TypeDef, + auto_migrations: &[AutoMigration], + span: Span, +) -> Option { + // Only handle record types for auto-migration + let (prev_fields, new_fields) = match (prev_def, new_def) { + (ast::TypeDef::Record(prev), ast::TypeDef::Record(new)) => (prev, new), + _ => return None, + }; + + // Build a record expression with all fields + let mut field_exprs: Vec<(ast::Ident, Expr)> = Vec::new(); + + // Map of new fields that need auto-migration defaults + let auto_migrate_fields: std::collections::HashSet = auto_migrations + .iter() + .filter_map(|m| match m { + AutoMigration::AddFieldWithDefault { field_name, .. } => Some(field_name.clone()), + AutoMigration::WidenType { .. } => None, + }) + .collect(); + + // For each field in the new definition + for new_field in new_fields { + let field_name = &new_field.name.name; + + if auto_migrate_fields.contains(field_name) { + // New optional field - add with None default + field_exprs.push(( + new_field.name.clone(), + Expr::Var(Ident::new("None", span)), + )); + } else { + // Existing field - copy from old: old.fieldName + field_exprs.push(( + new_field.name.clone(), + Expr::Field { + object: Box::new(Expr::Var(Ident::new("old", span))), + field: new_field.name.clone(), + span, + }, + )); + } + } + + // Build the record expression + Some(Expr::Record { + fields: field_exprs, + span, + }) +} + /// Check if a function terminates (structural recursion check) fn check_termination(func: &FunctionDecl) -> Result<(), String> { // Non-recursive functions always terminate @@ -530,6 +612,12 @@ impl TypeChecker { self.env.bindings.get(name) } + /// Get auto-generated migrations from type checking + /// Returns: type_name -> from_version -> migration_body + pub fn get_auto_migrations(&self) -> &HashMap> { + &self.migrations + } + /// Type check a program pub fn check_program(&mut self, program: &Program) -> Result<(), Vec> { // First pass: collect all declarations @@ -873,8 +961,28 @@ impl TypeChecker { }); } } - Ok(Compatibility::AutoMigrate(_)) | Ok(Compatibility::Compatible) => { - // No issues - compatible or auto-migratable + Ok(Compatibility::AutoMigrate(auto_migrations)) => { + // Generate automatic migration if one wasn't provided + if !self.migrations.get(&type_name).map(|m| m.contains_key(&prev_version)).unwrap_or(false) { + // Get the previous version's fields to build the migration + if let Some(prev_def) = self.schema_registry.get_version(&type_name, prev_version) { + if let Some(generated) = generate_auto_migration_expr( + &prev_def.definition, + &type_decl.definition, + &auto_migrations, + type_decl.name.span, + ) { + // Register the auto-generated migration + self.migrations + .entry(type_name.clone()) + .or_default() + .insert(prev_version, generated); + } + } + } + } + Ok(Compatibility::Compatible) => { + // No issues - fully compatible } Err(_) => { // Previous version not registered yet - that's fine @@ -974,7 +1082,7 @@ impl TypeChecker { fn check_function(&mut self, func: &FunctionDecl) { // Validate that all declared effects exist - let builtin_effects = ["Console", "Fail", "State", "Reader", "Random", "Time", "File", "Process", "Http", "HttpServer", "Test"]; + let builtin_effects = ["Console", "Fail", "State", "Reader", "Random", "Time", "File", "Process", "Http", "HttpServer", "Test", "Sql"]; for effect in &func.effects { let is_builtin = builtin_effects.contains(&effect.name.as_str()); let is_defined = self.env.lookup_effect(&effect.name).is_some(); @@ -1023,9 +1131,9 @@ impl TypeChecker { self.current_effects = old_effects; self.inferring_effects = old_inferring; - // Check that body type matches return type + // Check that body type matches return type (expand type aliases for record types) let return_type = self.resolve_type(&func.return_type); - if let Err(e) = unify(&body_type, &return_type) { + if let Err(e) = unify_with_env(&body_type, &return_type, &self.env) { self.errors.push(TypeError { message: format!( "Function '{}' body has type {}, but declared return type is {}: {}", @@ -1656,10 +1764,36 @@ impl TypeChecker { match unify(&func_type, &expected_fn) { Ok(subst) => result_type.apply(&subst), Err(e) => { - self.errors.push(TypeError { - message: format!("Type mismatch in function call: {}", e), - span, - }); + // Provide more detailed error message based on the type of mismatch + let message = if e.contains("arity mismatch") || e.contains("different number") { + // Try to extract actual function arity + if let Type::Function { params, .. } = &func_type { + format!( + "Function expects {} argument(s), but {} were provided", + params.len(), + arg_types.len() + ) + } else { + format!("Type mismatch in function call: {}", e) + } + } else if e.contains("Effect mismatch") { + format!("Type mismatch in function call: {}", e) + } else { + // Get function name if available for better error + let fn_name = if let Expr::Var(id) = func { + Some(id.name.clone()) + } else { + None + }; + + if let Some(name) = fn_name { + format!("Type error in call to '{}': {}", name, e) + } else { + format!("Type mismatch in function call: {}", e) + } + }; + + self.errors.push(TypeError { message, span }); Type::Error } } @@ -1729,7 +1863,7 @@ impl TypeChecker { } // Built-in effects are always available - let builtin_effects = ["Console", "Fail", "State", "Reader", "Random", "Time", "File", "Process", "Http", "HttpServer", "Test"]; + let builtin_effects = ["Console", "Fail", "State", "Reader", "Random", "Time", "File", "Process", "Http", "HttpServer", "Test", "Sql"]; let is_builtin = builtin_effects.contains(&effect.name.as_str()); // Track this effect for inference @@ -1814,10 +1948,18 @@ impl TypeChecker { Type::Record(fields) => match fields.iter().find(|(n, _)| n == &field.name) { Some((_, t)) => t.clone(), None => { - self.errors.push(TypeError { - message: format!("Record has no field '{}'", field.name), - span, - }); + // Find similar field names + let available_fields: Vec<&str> = fields.iter().map(|(n, _)| n.as_str()).collect(); + let suggestions = find_similar_names(&field.name, available_fields.clone(), 2); + + let mut message = format!("Record has no field '{}'", field.name); + if let Some(hint) = format_did_you_mean(&suggestions) { + message.push_str(&format!(". {}", hint)); + } else if !available_fields.is_empty() { + message.push_str(&format!(". Available fields: {}", available_fields.join(", "))); + } + + self.errors.push(TypeError { message, span }); Type::Error } }, @@ -1915,10 +2057,10 @@ impl TypeChecker { ) -> Type { let value_type = self.infer_expr(value); - // Check declared type if present + // Check declared type if present (expand type aliases for record types) if let Some(type_expr) = typ { let declared = self.resolve_type(type_expr); - if let Err(e) = unify(&value_type, &declared) { + if let Err(e) = unify_with_env(&value_type, &declared, &self.env) { self.errors.push(TypeError { message: format!( "Variable '{}' has type {}, but declared type is {}: {}", @@ -2140,7 +2282,7 @@ impl TypeChecker { .map(|(n, _)| (n.name.clone(), Type::var())) .collect(); - if let Err(e) = unify(expected, &Type::Record(field_types.clone())) { + if let Err(e) = unify_with_env(expected, &Type::Record(field_types.clone()), &self.env) { self.errors.push(TypeError { message: format!("Record pattern doesn't match type {}: {}", expected, e), span: *span, @@ -2234,7 +2376,7 @@ impl TypeChecker { // Built-in effects are always available in run blocks (they have runtime implementations) let builtin_effects: EffectSet = - EffectSet::from_iter(["Console", "Fail", "State", "Reader", "Random", "Time", "File", "Process", "Http", "HttpServer"].iter().map(|s| s.to_string())); + EffectSet::from_iter(["Console", "Fail", "State", "Reader", "Random", "Time", "File", "Process", "Http", "HttpServer", "Sql"].iter().map(|s| s.to_string())); // Extend current effects with handled ones and built-in effects let combined = self.current_effects.union(&handled_effects).union(&builtin_effects); diff --git a/src/types.rs b/src/types.rs index d5ff440..f8f7eb5 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1173,6 +1173,73 @@ impl TypeEnv { }, ); + // Add Sql effect for database access + // Connection is represented as Int (connection ID) + let row_type = Type::Record(vec![]); // Dynamic record type + env.effects.insert( + "Sql".to_string(), + EffectDef { + name: "Sql".to_string(), + type_params: Vec::new(), + operations: vec![ + EffectOpDef { + name: "open".to_string(), + params: vec![("path".to_string(), Type::String)], + return_type: Type::Int, // Connection ID + }, + EffectOpDef { + name: "openMemory".to_string(), + params: vec![], + return_type: Type::Int, // Connection ID + }, + EffectOpDef { + name: "close".to_string(), + params: vec![("conn".to_string(), Type::Int)], + return_type: Type::Unit, + }, + EffectOpDef { + name: "execute".to_string(), + params: vec![ + ("conn".to_string(), Type::Int), + ("sql".to_string(), Type::String), + ], + return_type: Type::Int, // Rows affected + }, + EffectOpDef { + name: "query".to_string(), + params: vec![ + ("conn".to_string(), Type::Int), + ("sql".to_string(), Type::String), + ], + return_type: Type::List(Box::new(Type::var())), // List of records + }, + EffectOpDef { + name: "queryOne".to_string(), + params: vec![ + ("conn".to_string(), Type::Int), + ("sql".to_string(), Type::String), + ], + return_type: Type::Option(Box::new(Type::var())), // Optional record + }, + EffectOpDef { + name: "beginTx".to_string(), + params: vec![("conn".to_string(), Type::Int)], + return_type: Type::Unit, + }, + EffectOpDef { + name: "commit".to_string(), + params: vec![("conn".to_string(), Type::Int)], + return_type: Type::Unit, + }, + EffectOpDef { + name: "rollback".to_string(), + params: vec![("conn".to_string(), Type::Int)], + return_type: Type::Unit, + }, + ], + }, + ); + // Add Some and Ok, Err constructors // Some : fn(a) -> Option let a = Type::var(); @@ -1743,6 +1810,65 @@ impl TypeEnv { TypeScheme::poly(type_vars, typ.clone()) } + + /// Expand a Named type to its underlying structural type if it's an alias + /// This is needed for unifying record type aliases with record literals + pub fn expand_type_alias(&self, ty: &Type) -> Type { + match ty { + Type::Named(name) => { + if let Some(type_def) = self.types.get(name) { + match type_def { + TypeDef::Alias(inner) => self.expand_type_alias(inner), + // For enums and records, keep the Named type + _ => ty.clone(), + } + } else { + ty.clone() + } + } + Type::Function { params, return_type, effects, properties } => { + Type::Function { + params: params.iter().map(|p| self.expand_type_alias(p)).collect(), + return_type: Box::new(self.expand_type_alias(return_type)), + effects: effects.clone(), + properties: properties.clone(), + } + } + Type::App { constructor, args } => { + Type::App { + constructor: Box::new(self.expand_type_alias(constructor)), + args: args.iter().map(|a| self.expand_type_alias(a)).collect(), + } + } + Type::Tuple(elems) => { + Type::Tuple(elems.iter().map(|e| self.expand_type_alias(e)).collect()) + } + Type::Record(fields) => { + Type::Record(fields.iter().map(|(n, t)| (n.clone(), self.expand_type_alias(t))).collect()) + } + Type::List(inner) => { + Type::List(Box::new(self.expand_type_alias(inner))) + } + Type::Option(inner) => { + Type::Option(Box::new(self.expand_type_alias(inner))) + } + Type::Versioned { base, version } => { + Type::Versioned { + base: Box::new(self.expand_type_alias(base)), + version: version.clone(), + } + } + // Primitives and type variables stay as-is + _ => ty.clone(), + } + } +} + +/// Unify types with type alias expansion +pub fn unify_with_env(t1: &Type, t2: &Type, env: &TypeEnv) -> Result { + let expanded1 = env.expand_type_alias(t1); + let expanded2 = env.expand_type_alias(t2); + unify(&expanded1, &expanded2) } /// Unification of types