Skip to content

Experiment with flow-sensitive typing #122

@timfennis

Description

@timfennis

Summary

The analyser currently uses a single type per variable binding. When a variable is reassigned to a different type, the binding is widened via LUB, which loses precision. Flow-sensitive typing would instead track the exact type at each point in the program, giving more precise inference and better error messages.

Example

let x = 3;       // x : Int
x /= 2;          // x : Rational (result of Int / Int)
x = "test";      // x : String
x.trim();        // fine — we know x is String at this point

With the current LUB approach, x would be widened to Any after the string assignment, losing all type information. With flow typing, each use of x would see the precise type at that program point.

Prior art

  • Crystal — full flow-sensitive typing on assignment; the type of a variable changes at each assignment point
  • Python type checkers (mypy, pyright) — narrow types per assignment
  • Luau (Roblox's typed Lua) — similar per-assignment narrowing
  • TypeScript — flow-based narrowing after type guards and control flow

Implementation considerations

  • The analyser currently does a single forward pass over the AST. Flow typing would likely require building a control flow graph (CFG) first, then propagating types along edges.
  • Joins at control flow merge points (after if/else, loop back-edges) would still need LUB.
  • This interacts with closures: if a variable is captured, the closure might see a different type than the enclosing scope expects. Crystal solves this by restricting captured variables.
  • The current LUB-on-assignment approach (✨ Widen variable types on reassignment via LUB #121) is a good stepping stone — it's correct but conservative.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestexperimentExperimental feature or research

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions