LuaLS / LuaLS/lua-language-server

__pairs and __ipairs metamethods have incorrect annotations

Đang mở
#2,993 1 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Ngôn ngữ chính
Lua
Star
4.4k
Fork
442
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

How are you using the lua-language-server?

Visual Studio Code Extension (sumneko.lua)

Which OS are you using?

Windows

What is the issue affecting?

Annotations

Expected Behaviour

lua-language-server should specify correct function signatures for __pairs and __ipairs.

lua-language-server should in particular say that the __ipairs iterator generator function has 3 return values.

Following the annotation hints for __ipairs should not result in runtime errors.

Given that generic for k, v in pairs(t) --or ipairs(t) for pairs and ipairs are equivilant to:

do
  local f, s, var = pairs(t) --or ipairs(t)
  while true do
    local k, v = f(s, var)
    if k == nil then break end
    var = k
    <block>
  end
end

I believe these are the required function signatures:

__pairs = 
GEN_FUN(ITERABLE)
	RETURNS
		ITER_FUN(ITERABLE,KEY)
			RETURNS 
				KEY
				VALUE
		ITERABLE
		KEY_BEFORE_FIRST
OR nil
__ipairs = 
GEN_FUN(ITERABLE_ARRAY)
	RETURNS 
		ITER_FUN(ITERABLE_ARRAY,INDEX)
			RETURNS 
				INDEX OR nil
				VALUE
		ITERABLE_ARRAY
		INDEX_BEFORE_FIRST
OR nil

which I believe should be:

---@field __pairs (fun(t):((fun(t,k):(any,any)),any,any))|nil
---@field __ipairs (fun(t):((fun(t,k):((integer|nil),any)),any,integer))|nil

Actual Behaviour

__pairs annotation specifies the iterator function as taking a third argument, for the value. Lua versions 5.2 and 5.4 do not pass a third argument to the iterator function.

---@field __pairs (fun(t):((fun(t,k,v):any,any),any,any))|nil

__ipairs annotation specifies the iterator function as taking a third argument, for the value. Lua version 5.2 does not pass a third argument to the iterator function.

__ipairs annotation specifies the generator function as returning only 2 results. Following the annotation hinting results in nil being implicitly passed as the third argument, instead of the correct index.

---@field __ipairs (fun(t):(fun(t,k,v):(integer|nil),any))|nil

Reproduction steps
t = setmetatable({1,2,3}, {
  __ipairs = function(t) local function iter(t, k) k = k + 1 local v = t[k]; if v then return k, v end; end; return iter, t, 0 end,
})

for k, v in ipairs(t) do
  print(v)
end
(field) __ipairs: function|nil
function (t: any)
  -> fun(t: any, k: any, v: any):integer|nil
  2. any
function __ipairs(t: any)
  -> function
  2. unknown
  3. integer
Annotations specify that at most 2 return value(s) are required, found 3 returned here instead.Lua Diagnostics.(redundant-return-value)

Removing the extra return value as the annotation suggests results in :

.\sample.lua:2: attempt to perform arithmetic on local 'k' (a nil value)
stack traceback:
        .\source.txt:2: in function 'for iterator'
        .\source.txt:5: in main chunk
        [C]: in ?
Additional Notes

The example __ipairs sample is essentially what AI generated sample code looks like, so it is likely how someone would use __ipairs.

Lua 5.2 allows iteration with __ipairs to start at any point; this is useful if __ipairs is used to support non-standard ipairs iteration, such as starting from a negative index or starting at some arbitrary positive index, controlled by altering the third return value from the generator function to be a non-zero value.

Some of the __ipairs choices in the suggested annotations I made aren't technically explicitly mandated, but I feel they are in the spirit of the intended functionality; nothing stops anyone violating the implicit assumption that the keys are sequential, have numeric indexes, or they will be traversed in a given order:

t = setmetatable({a=1,b=2,c=3}, {
  __ipairs = function(t) local function iter(t, k) return next(t,k) end; return iter, t, nil end,
})

for k, v in ipairs(t) do
  print(k, v)
end

I kept my suggested annotation for __ipairs in line with the normal behaviors of ipairs when there is no __ipairs metamethod.

Log File

No response

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu với các định nghĩa chú thích __pairs và __ipairs, rồi chạy bản tái hiện Lua được cung cấp trong môi trường lua-language-server. So sánh các chữ ký được suy luận với hành vi lặp của Lua 5.2 và 5.4. Được xem là hoàn tất khi các chú thích chấp nhận ba giá trị trả về của generator, mô hình hóa chính xác các đối số và giá trị trả về của iterator, đồng thời không còn tạo ra các chẩn đoán được hiển thị hoặc lỗi runtime.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
lua
Lĩnh vực
devtools
Loại issue
Lỗi
Độ khó
3/5
Thời gian dự kiến
1-2 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
35/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.