LuaLS / LuaLS/lua-language-server

Feature Request: Typestate / Self-Type Refinement for Method Calls

Ouverte
#3,407 3 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Langage dominant
Lua
Étoiles
4.4k
Forks
442
Métriques de merge des PR
Aucune PR mergée en 30 j

Description

Problem

Lua is a highly dynamic language, and many real-world Lua frameworks mutate object capabilities at runtime.

This pattern is especially common in:

  • game engines
  • UI frameworks
  • ECS architectures
  • builder APIs
  • runtime mixin systems
  • userdata bindings from native engines

Currently, LuaLS/LuaCats cannot properly express:

"after calling this method, self now has additional capabilities/methods"

This becomes a major DX limitation for frameworks that dynamically extend objects.


Real-world Example

Consider a UI framework where all elements start as a generic UIElement.

---@class UIElement
local UIElement = {}

Calling:

element:setupUIImage()

injects image-related functionality into the element at runtime:

element:setImage(...)

However, LuaLS still sees element as only UIElement.

The only current workaround is manual casting:

element:setupUIImage()

---@cast element UIImage
element:setImage(material)

This works technically, but becomes repetitive and hurts DX significantly in large codebases.


Comparison to TypeScript

TypeScript supports type refinement after method calls through assertion signatures such as:

asserts this is SomeType

This allows APIs to safely refine object types after capability-changing methods.

A good real-world example is discord.js, where Interaction objects can be refined into subtypes through methods like:

interaction.isButton()
interaction.isChatInputCommand()

After refinement, TypeScript understands the new subtype automatically.

Lua frameworks often use similar runtime patterns, but LuaLS currently cannot model them.


Proposed Solution

Introduce a LuaCats annotation for self-type refinement / capability injection.

Possible syntax examples:

---@injects UIImage
function UIElement:setupUIImage() end

or:

---@mutates self UIImage
function UIElement:setupUIImage() end

or:

---@becomes UIImage
function UIElement:setupUIImage() end

Expected Behavior

After:

element:setupUIImage()

LuaLS would understand:

element :: UIElement & UIImage

allowing:

element:setImage(...)

without requiring manual casts.


Why This Matters

This would greatly improve support for:

  • dynamic Lua architectures
  • runtime capability injection
  • engine bindings
  • UI frameworks
  • builder APIs
  • fluent APIs
  • mixin systems

while keeping Lua's dynamic nature intact.

This feature would also reduce:

  • repetitive ---@cast
  • noisy annotations
  • inaccurate supersets in base classes
  • degraded autocomplete quality

Additional Notes

This feature does not need to become full typestate analysis or advanced dependent typing.

Even a pragmatic flow-sensitive refinement system limited to:

  • direct method calls
  • current scope
  • explicit annotations only

would already provide massive DX improvements.


Example Use Case

---@class UIImage
---@field setImage fun(self: UIImage, material: string)

---@class UIElement

---@injects UIImage
function UIElement:setupUIImage() end

local element = UIElement.new()

element:setupUIImage()

element:setImage("icon")

Expected:

  • autocomplete works
  • diagnostics recognize setImage
  • no manual cast required

Thanks for all the amazing work on LuaLS and LuaCats.
This would significantly improve tooling support for dynamic Lua patterns commonly used in real-world frameworks and game engines.

Guide de contribution

Ouvrir le guide de contribution

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Piste de recherche

L’issue ne nomme aucun fichier d’implémentation ni aucun test. Commencez par examiner comment LuaLS gère actuellement les ---@cast explicites et les appels de méthodes, puis évaluez la portée de l’affinement proposé : appels directs, portée actuelle et annotations explicites. Le travail sera considéré comme terminé lorsqu’un design d’annotations sera arrêté, avec un affinement des capacités sensible au flux, la complétion automatique et les diagnostics fonctionnant sans cast manuel.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
lua
Domaine
devtools
Type d'issue
Fonctionnalité
Difficulté
5/5
Temps estimé
Plus d'une semaine
Activité
Calme
Clarté
Plutôt claire
Accessibilité débutants
45/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.