Skip to content

feat!: map reads are Result(V, Error); emit comma-ok via Go IIFE#94

Merged
haveyaseen merged 4 commits into
mainfrom
feat/map-read-result
Apr 21, 2026
Merged

feat!: map reads are Result(V, Error); emit comma-ok via Go IIFE#94
haveyaseen merged 4 commits into
mainfrom
feat/map-read-result

Conversation

@haveyaseen
Copy link
Copy Markdown
Member

@haveyaseen haveyaseen commented Apr 20, 2026

Rvalue m[k] on map[K]V now infers as Result(V, Error) (missing key is failure). Forst rejects v, ok := m[k]; use ensure x is Ok() (or otherwise handle the Result) before using V. Indexed assignment m[k] = x still types the LHS as V. The Go backend lowers map reads with an IIFE that uses v, ok := and errors.New("missing map key") internally.

Adds examples/in/map_catalog.ft, compiler/pipeline/typechecker coverage, and README catalog/CLI notes.

BREAKING CHANGE: Map subscript expressions are no longer plain V; callers must account for Result(V, Error) or narrow with ensure.

Example:

avail := catalog[sku]
ensure avail is Ok()
println(string(avail))

Summary by CodeRabbit

Release Notes

  • New Features

    • Map index operations now return explicit Result types requiring ensure ... is Ok() error handling before use.
    • Added LSP hover information for map indexing operations displaying Result semantics.
  • Documentation

    • Updated guidance distinguishing .ft files for CLI usage and .go for Go builds.
    • Clarified map lookup patterns and explicit error-handling requirements.
    • Added example demonstrating Result-based map catalog lookups.
  • Tests

    • Expanded test coverage for map indexing type inference and error handling.

Rvalue `m[k]` on `map[K]V` now infers as `Result(V, Error)` (missing key is
failure). Forst rejects `v, ok := m[k]`; use `ensure x is Ok()` (or otherwise
handle the `Result`) before using `V`. Indexed assignment `m[k] = x` still
types the LHS as `V`. The Go backend lowers map reads with an IIFE that uses
`v, ok :=` and `errors.New("missing map key")` internally.

Adds `examples/in/map_catalog.ft`, compiler/pipeline/typechecker coverage, and
README catalog/CLI notes.

BREAKING CHANGE: Map subscript expressions are no longer plain `V`; callers must
account for `Result(V, Error)` or narrow with `ensure`.

Example:

```forst
avail := catalog[sku]
ensure avail is Ok()
println(string(avail))
```
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 20, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ee7be8fc-e4d6-4848-85e4-db71bf1657c9

📥 Commits

Reviewing files that changed from the base of the PR and between 1b0a1b0 and 4bf5b36.

📒 Files selected for processing (24)
  • README.md
  • examples/in/map_catalog.ft
  • examples/out/map_catalog.go
  • forst/cmd/forst/lsp/hover_completion.go
  • forst/cmd/forst/lsp/hover_completion_test.go
  • forst/internal/ast/expression.go
  • forst/internal/compiler/compiler_test.go
  • forst/internal/transformer/go/expression.go
  • forst/internal/transformer/go/expression_map_result.go
  • forst/internal/transformer/go/expression_map_result_test.go
  • forst/internal/transformer/go/function.go
  • forst/internal/transformer/go/import_output_test.go
  • forst/internal/transformer/go/map_index_cache_key_test.go
  • forst/internal/transformer/go/output.go
  • forst/internal/transformer/go/pipeline_integration_test.go
  • forst/internal/transformer/go/result_local.go
  • forst/internal/transformer/go/statement.go
  • forst/internal/transformer/go/transformer.go
  • forst/internal/transformer/ts/type_mapping.go
  • forst/internal/transformer/ts/type_mapping_test.go
  • forst/internal/typechecker/go_builtins.go
  • forst/internal/typechecker/infer_assignment.go
  • forst/internal/typechecker/infer_expression.go
  • forst/internal/typechecker/infer_map_index_test.go

Walkthrough

This PR introduces comprehensive support for map index reads returning Result(V, Error) types. It updates documentation and examples, adds LSP hover support for map indexing, modifies the typechecker to infer map reads as Result-typed expressions, and extends the Go transformer to generate IIFE-based code that handles missing keys explicitly. TypeScript type mapping for Result types is also added.

Changes

Cohort / File(s) Summary
Documentation & Examples
README.md, examples/in/map_catalog.ft, examples/out/map_catalog.go
Documentation clarifies map catalog pattern using .ft files and Result(V, Error) semantics; new example files demonstrate map indexing with ensure result handling and generated Go IIFE lowering.
LSP Hover Support
forst/cmd/forst/lsp/hover_completion.go, forst/cmd/forst/lsp/hover_completion_test.go
Added mapIndexLBracketHoverMarkdown to detect [ tokens on map variables and provide hover text describing Result return type and missing-key behavior; includes test coverage.
AST & Type Declarations
forst/internal/ast/expression.go
Updated IndexExpressionNode documentation to note support for slice, array, or map indexing.
Type Inference & Checking
forst/internal/typechecker/infer_expression.go, forst/internal/typechecker/infer_assignment.go, forst/internal/typechecker/go_builtins.go
Extended index-expression type inference to treat map reads as Result(V, Error); added assignment-target inference for map elements; rejected comma-ok pattern and added map-specific diagnostics; improved error handling for string() calls on map reads.
Type Checker Tests
forst/internal/typechecker/infer_map_index_test.go
Comprehensive test suite validating map indexing semantics, Result-type narrowing, rejection of comma-ok destructuring, and nested/chained indexing behavior.
Go Transformer: Map Result Lowering
forst/internal/transformer/go/expression.go, forst/internal/transformer/go/expression_map_result.go, forst/internal/transformer/go/expression_map_result_test.go, forst/internal/transformer/go/map_index_cache_key_test.go
Detects map reads returning Result types and generates IIFE-style function literals that perform v, ok := m[k] and return (zero, errMissingMapKey) on missing key; includes caching of generated function literals to deduplicate identical reads.
Go Transformer: Supporting Infrastructure
forst/internal/transformer/go/output.go, forst/internal/transformer/go/function.go, forst/internal/transformer/go/statement.go, forst/internal/transformer/go/result_local.go
Extended TransformerOutput to manage var errMissingMapKey declaration; updated function scoping to reset per-function map-index cache; generalized folded-Result detection to include index expressions; modified assignment lowering to handle Result-typed index reads.
Go Transformer: Tests
forst/internal/transformer/go/import_output_test.go, forst/internal/transformer/go/pipeline_integration_test.go, forst/internal/compiler/compiler_test.go
Added validation of errMissingMapKey declaration, golden-file test for map catalog compilation, and pipeline tests for map read/write/reuse patterns.
TypeScript Type Mapping
forst/internal/transformer/ts/type_mapping.go, forst/internal/transformer/ts/type_mapping_test.go
Maps Result(V, Error) to TypeScript discriminated union ({ ok: true; value: V } | { ok: false; error: E }); includes test coverage.

Sequence Diagram(s)

sequenceDiagram
    participant Parser
    participant TypeChecker
    participant Transformer
    participant CodeGen

    Parser->>Parser: Parse map[key] as IndexExpressionNode
    Parser->>TypeChecker: Pass AST node

    TypeChecker->>TypeChecker: Infer target type (TypeMap)
    TypeChecker->>TypeChecker: Validate key compatibility
    TypeChecker->>TypeChecker: Return Result(V, Error) type
    TypeChecker->>Transformer: Provide inferred type

    Transformer->>Transformer: Detect Result type via type inference
    Transformer->>Transformer: Check cache for duplicate reads
    alt Cache Hit
        Transformer->>CodeGen: Return cached function literal
    else Cache Miss
        Transformer->>Transformer: Generate IIFE function literal
        Transformer->>Transformer: v, ok := m[k]<br/>if !ok: return (zero, errMissingMapKey)
        Transformer->>Transformer: Store in per-function cache
        Transformer->>CodeGen: Return new function literal
    end
    CodeGen->>CodeGen: Emit call expression to IIFE
Loading
sequenceDiagram
    participant LSP Client
    participant Hover Handler
    participant TypeChecker
    participant TokenStream

    LSP Client->>Hover Handler: Request hover at bracket position
    Hover Handler->>TokenStream: Locate '[' token
    Hover Handler->>Hover Handler: Check prior token is identifier
    Hover Handler->>TypeChecker: Infer variable type
    TypeChecker->>TypeChecker: Resolve to TypeMap
    alt Is Map Type
        Hover Handler->>Hover Handler: Generate Result(V, Error) hover text
        Hover Handler->>LSP Client: Return map lookup hover markdown
    else Not Map Type
        Hover Handler->>LSP Client: Return empty or fallback hover
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • forst-lang/forst#57: Extends index-expression handling across parser/AST/typechecker/transformer, directly building on the IndexExpressionNode semantics and assignment inference introduced here.
  • forst-lang/forst#56: Modifies compiler and transformer map handling, including related changes to typechecker map type inference logic.
  • forst-lang/forst#42: Introduces hover variable-node inference and LSP refactoring that the new map-index hover functionality depends upon.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/map-read-result

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

haveyaseen and others added 3 commits April 21, 2026 01:54
GetTypeScriptType now handles builtin `Result` with two params, emitting
`({ ok: true; value: S } | { ok: false; error: F })` and wrapping S/F in
parentheses when they already contain `|` or ` & `.

test(examples): add map_catalog.go compiler golden

Locks in emitted Go for `examples/in/map_catalog.ft` (map-read IIFE, missing-key
error, ensure split).

Example (TS mapping for `Result(Int, Error)`):

```ts
({ ok: true; value: number } | { ok: false; error: unknown })
```
Emit `var errMissingMapKey = errors.New("missing map key")` once via
`TransformerOutput.EnsureErrMissingMapKeyDecl`, reuse in map-read IIFEs, and
cache identical `*ast.FuncLit` per function (`mapIndexExprCacheKey`, hit counter
for tests). `goZeroValueGoAST` returns `nil` for pointers; add table tests and
golden/pipeline/compiler marker updates.

feat(lsp): hover on `[` after a map variable

When the cursor is on `LBracket` following a map-typed identifier, show that
lookup is `Result(V, Error)` and to use `ensure … is Ok()` before using `V`.

fix(typechecker): targeted `string()` error for raw map index Result

If the operand is a map subscript typed as `Result`, diagnose map lookup
explicitly instead of only "unsupported operand type Result". Add
`inferExpressionTypeWithExpected` hook for `IndexExpressionNode` and nested /
chained map tests.

docs(ts): clarify Result lowering vs generated TS union

Comment on `TypeResult` in `GeeScriptType`: TS discriminated union is a
static signature hint; Go remains `(T, error)` unless a codec maps wire data.

Example (diagnostic):

```forst
println(string(m["a"])) // map lookup has type Result(V, Error); use ensure first
```
@haveyaseen haveyaseen marked this pull request as ready for review April 21, 2026 00:16
@haveyaseen haveyaseen merged commit 0cebdf1 into main Apr 21, 2026
4 checks passed
@github-actions github-actions Bot mentioned this pull request Apr 21, 2026
@haveyaseen haveyaseen deleted the feat/map-read-result branch April 26, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant