Benjamin-Dobell / IntelliJ-Luanalysis

Type-safe Lua IDE — IntelliJ IDEA plugin
Apache License 2.0
155 stars 21 forks source link

Tables can not easily be declared by inference #122

Open LoganDark opened 2 years ago

LoganDark commented 2 years ago

Environment

Name Version
IDEA version IntelliJ IDEA 2021.2.3
Luanalysis version 1.3.0
OS Windows 10 2004 build 19041.928 x86_64

Preferences

image

Lua

Name Setting
Language level Lua 5.1

Type Safety

Name Setting
Strict nil checks ☑️
Unknown type (any) is indexable
Unknown type (any) is callabale

What are the steps to reproduce this issue?

  1. Download this file: https://gist.github.com/LoganDark/04bd291d585e5f054c63958bbf08ff12 (work in progress actually up-to-date OpenResty types)
  2. Open it in in your IDE
  3. You will see Luanalysis sometimes decides the file has 92 errors, and sometimes decides there are no errors at all.
  4. Press space anywhere in the file and it will probably flip its decision. Same with pressing Ctrl+S or doing pretty much anything

What happens?

https://user-images.githubusercontent.com/4723091/162651248-6bb9b83d-1dae-495e-b567-b7bdf9200736.mp4

What were you expecting to happen?

no errors

Any logs, error output, etc?

Nope

Any other comments?

I can't do this by declaring everything in the table constructor because of #120. The combination of the two make it extremely infuriating to try to declare the existence of a large environment.

It may be worth adopting something similar to Luau's "sealed/unsealed tables", where, in the scope where a table is first declared as {}, it is "unsealed" and therefore legal to add any new fields/functions to it and the table's type will be inferred using those members. Outside the declaring scope, or if the table was declared with a different literal, then it is "sealed", which means its type is known and will not be inferred further.

LoganDark commented 2 years ago

Okay so I kind of figured out what I want to do - if I slap ---@module ngx (which is completely undocumented by the way!) at the top of that file, then all the globals it defines become members of a type called ngx. Then I can do this:

local ngx = --[[---@type ngx]] require('ngx')

which only works because OpenResty allows me to require ngx, but is also inefficient because it's a function call at runtime - whatever, who cares. If that's what it takes for static analysis then I guess I can take the hit.

(edit 2: turns out you can just slap ngx = --[[---@type ngx]] require('ngx') into any random lua file, even one you don't actually execute, and ngx will be recognized as a global. Cool beans.)

Weirdly, when I switched the module to using @module, there are no errors at all! I added the working version to the gist (as ngx.fixed.def.lua).

edit: Leaving this issue open because the nondeterminism is back. It's just using globals skirts around the issue a bit, but setting properties on nested tables (even within a module) still raises errors.

LoganDark commented 2 years ago

Using --- @class whatever on each table that needs to be declared by inference works, but pollutes the global type scope