From 6fb7e1861af8d287229146c2357787c8e25b0832 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=80=E8=90=8C=E5=B0=8F=E6=B1=90?= Date: Sat, 11 May 2024 16:02:45 +0800 Subject: =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/type_inference/common.lua | 4194 ++++++++++++++++++++++++++++++++++ test/type_inference/init.lua | 4301 +---------------------------------- test/type_inference/param_match.lua | 107 + 3 files changed, 4303 insertions(+), 4299 deletions(-) create mode 100644 test/type_inference/common.lua create mode 100644 test/type_inference/param_match.lua (limited to 'test/type_inference') diff --git a/test/type_inference/common.lua b/test/type_inference/common.lua new file mode 100644 index 00000000..5922832b --- /dev/null +++ b/test/type_inference/common.lua @@ -0,0 +1,4194 @@ +local config = require 'config' + +TEST 'nil' [[ +local = nil +]] + +TEST 'string' [[ +local = '111' +]] + +TEST 'boolean' [[ +local = true +]] + +TEST 'integer' [[ +local = 1 +]] + +TEST 'number' [[ +local = 1.0 +]] + +TEST 'unknown' [[ +local +]] + +TEST 'unknown' [[ +local +var = y +]] + +TEST 'any' [[ +function f() + +end +]] + +TEST 'any' [[ +function f() + x = 1 +end +]] + +TEST 'string' [[ +local var = '111' +t. = var +]] + +TEST 'string' [[ +local +var = '111' +]] + +TEST 'string' [[ +local var + = '111' +]] + +TEST 'string' [[ +local var +var = '111' +print() +]] + +TEST 'function' [[ +function () +end +]] + +TEST 'function' [[ +local function () +end +]] + +TEST 'function' [[ +local xx + = function () +end +]] + +TEST 'table' [[ +local = {} +]] + +TEST 'unknown' [[ +() +]] + +TEST 'boolean' [[ + = not y +]] + +TEST 'integer' [[ + = #y +]] + +TEST 'integer' [[ + = #'aaaa' +]] + +TEST 'integer' [[ + = #{} +]] + +TEST 'number' [[ + = - y +]] + +TEST 'number' [[ + = - 1.0 +]] + +TEST 'integer' [[ + = ~ y +]] + +TEST 'integer' [[ + = ~ 1 +]] + +TEST 'boolean' [[ + = 1 < 2 +]] + +TEST 'integer' [[ +local a = true +local b = 1 + = a and b +]] + +TEST 'integer' [[ +local a = false +local b = 1 + = a or b +]] + +TEST 'boolean' [[ + = a == b +]] + +TEST 'unknown' [[ + = a << b +]] + +TEST 'integer' [[ + = 1 << 2 +]] + +TEST 'unknown' [[ + = a .. b +]] + +TEST 'string' [[ + = 'a' .. 'b' +]] + +TEST 'string' [[ + = 'a' .. 1 +]] + +TEST 'string' [[ + = 'a' .. 1.0 +]] + +TEST 'unknown' [[ + = a + b +]] + +TEST 'number' [[ + = 1 + 2.0 +]] + +TEST 'integer' [[ + = 1 + 2 +]] + +TEST 'integer' [[ +---@type integer +local a + + = - a +]] + +TEST 'number' [[ +local a + + = - a +]] + +TEST 'unknown' [[ + = 1 + X +]] + +TEST 'unknown' [[ + = 1.0 + X +]] + +TEST 'tablelib' [[ +---@class tablelib +table = {} + +() +]] + +TEST 'string' [[ +_VERSION = 'Lua 5.4' + + = _VERSION +]] + +TEST 'function' [[ +---@class stringlib +local string + +string.xxx = function () end + +return ('x'). +]] + +TEST 'function' [[ +---@class stringlib +String = {} + +String.xxx = function () end + +return ('x'). +]] + +TEST 'function' [[ +---@class stringlib +local string + +string.xxx = function () end + + = ('x').xxx +]] + +TEST 'function' [[ +---@class stringlib +local string + +string.xxx = function () end + +_VERSION = 'Lua 5.4' + + = _VERSION.xxx +]] + +TEST 'table' [[ + = setmetatable({}) +]] + +TEST 'integer' [[ +local function x() + return 1 +end + = x() +]] + +TEST 'integer|nil' [[ +local function x() + return 1 + return nil +end + = x() +]] + +TEST 'unknown|nil' [[ +local function x() + return a + return nil +end + = x() +]] + +TEST 'unknown|nil' [[ +local function x() + return nil + return f() +end + = x() +]] + +TEST 'unknown|nil' [[ +local function x() + return nil + return f() +end +_, = x() +]] + +TEST 'integer' [[ +local function x() + return 1 +end +_, = pcall(x) +]] + +TEST 'integer' [[ +function x() + return 1 +end +_, = pcall(x) +]] + +TEST 'integer' [[ +local function x() + return 1 +end +_, = xpcall(x) +]] + +TEST 'A' [[ +---@class A + +---@return A +local function f2() end + +local function f() + return f2() +end + +local = f() +]] + +-- 不根据调用者的输入参数来推测 +--TEST 'number' [[ +--local function x(a) +-- return +--end +--x(1) +--]] + +--TEST 'table' [[ +--setmetatable() +--]] + +-- 不根据对方函数内的使用情况来推测 +TEST 'unknown' [[ +local function x(a) + _ = a + 1 +end +local b +x() +]] + +TEST 'unknown' [[ +local function x(a, ...) + local _, , _ = ... +end +x(nil, 'xx', 1, true) +]] + +-- 引用不跨越参数 +TEST 'unknown' [[ +local function x(a, ...) + return true, 'ss', ... +end +local _, _, _, , _ = x(nil, true, 1, 'yy') +]] + +TEST 'unknown' [[ +local = next() +]] + +TEST 'unknown' [[ +local a, b +function a() + return b() +end +function b() + return a() +end +local = a() +]] + +TEST 'class' [[ +---@class class +local +]] + +TEST 'string' [[ +---@class string + +---@type string +local +]] + +TEST '1' [[ +---@type 1 +local +]] + +TEST 'string[]' [[ +---@class string + +---@type string[] +local +]] + +TEST 'string|table' [[ +---@class string +---@class table + +---@type string | table +local +]] + +TEST [['enum1'|'enum2']] [[ +---@type 'enum1' | 'enum2' +local +]] + +TEST [["enum1"|"enum2"]] [[ +---@type "enum1" | "enum2" +local +]] + +config.set(nil, 'Lua.hover.expandAlias', false) +TEST 'A' [[ +---@alias A 'enum1' | 'enum2' + +---@type A +local +]] + +TEST 'A' [[ +---@alias A 'enum1' | 'enum2' | A + +---@type A +local +]] + +TEST 'A' [[ +---@alias A 'enum1' | 'enum2' | B + +---@type A +local +]] +config.set(nil, 'Lua.hover.expandAlias', true) +TEST [['enum1'|'enum2']] [[ +---@alias A 'enum1' | 'enum2' + +---@type A +local +]] + +TEST [['enum1'|'enum2']] [[ +---@alias A 'enum1' | 'enum2' | A + +---@type A +local +]] + +TEST [['enum1'|'enum2'|B]] [[ +---@alias A 'enum1' | 'enum2' | B + +---@type A +local +]] + +TEST '1|true' [[ +---@alias A 1 | true + +---@type A +local +]] + +TEST 'fun()' [[ +---@type fun() +local +]] + +TEST 'fun(a: string, b: any, ...any)' [[ +---@type fun(a: string, b, ...) +local +]] + +TEST 'fun(a: string, b: any, c?: boolean, ...any):c, d?, ...unknown' [[ +---@type fun(a: string, b, c?: boolean, ...):c, d?, ... +local +]] + +TEST '{ [string]: string }' [[ +---@type { [string]: string } +local +]] + +TEST 'table' [[ +---@class string +---@class number + +---@type table +local +]] + +TEST 'A' [[ +---@class A + +---@type A +local +]] + +TEST 'string' [[ +---@class string + +---@type string[] +local x +local = x[1] +]] + +TEST 'string' [[ +---@class string + +---@return string[] +local function f() end +local x = f() +local = x[1] +]] + +TEST 'table' [[ +local t = {} +local = setmetatable(t) +]] + +TEST 'CCC' [[ +---@class CCC + +---@type table +local t = {} + +print(t.) +]] + +TEST [['aaa'|'bbb']] [[ +---@type table +local t = {} + +print(t.) +]] + +TEST 'integer' [[ +---@generic K +---@type fun(a?: K):K +local f + +local = f(1) +]] + +TEST 'unknown' [[ +---@generic K +---@type fun(a?: K):K +local f + +local = f(nil) +]] + +TEST 'unknown' [[ +---@generic K +---@type fun(a: K|integer):K +local f + +local = f(1) +]] + +TEST 'integer' [[ +---@class integer + +---@generic T: table, V +---@param t T +---@return fun(table: V[], i?: integer):integer, V +---@return T +---@return integer i +local function ipairs() end + +for in ipairs() do +end +]] + +TEST 'table' [[ +---@generic K, V +---@param t table +---@return K +---@return V +local function next(t) end + +---@type table +local t +local k, v = next() +]] + +TEST 'string' [[ +---@class string + +---@generic K, V +---@param t table +---@return K +---@return V +local function next(t) end + +---@type table +local t +local , v = next(t) +]] + +TEST 'boolean' [[ +---@class boolean + +---@generic K, V +---@param t table +---@return K +---@return V +local function next(t) end + +---@type table +local t +local k, = next(t) +]] + +TEST 'boolean' [[ +---@generic K +---@type fun(arg: K):K +local f + +local = f(true) +]] + +TEST 'string' [[ +---@class string + +---@generic K, V +---@type fun(arg: table):K, V +local f + +---@type table +local t + +local , v = f(t) +]] + +TEST 'boolean' [[ +---@class boolean + +---@generic K, V +---@type fun(arg: table):K, V +local f + +---@type table +local t + +local k, = f(t) +]] + +TEST 'fun()' [[ +---@return fun() +local function f() end + +local = f() +]] + +TEST 'table' [[ +---@return table +local function f() end + +local = f() +]] + +TEST 'string' [[ +---@class string + +---@generic K, V +---@return fun(arg: table):K, V +local function f() end + +local f2 = f() + +---@type table +local t + +local , v = f2(t) +]] + +TEST 'fun(a: ):integer, ' [[ +---@generic K, V +---@param a K +---@return fun(a: V):K, V +local function f(a) end + +local = f(1) +]] + +TEST 'integer' [[ +---@generic K, V +---@param a K +---@return fun(a: V):K, V +local function f(a) end + +local f2 = f(1) +local , v = f2(true) +]] + +TEST 'boolean' [[ +---@generic K, V +---@param a K +---@return fun(a: V):K, V +local function f(a) end + +local f2 = f(1) +local i, = f2(true) +]] + +TEST 'fun(table: table<, >, index?: ):, ' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table, index?: K):K, V +---@return T +---@return nil +local function pairs(t) end + +local = pairs(dummy) +]] + +TEST 'string' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table, index?: K):K, V +---@return T +---@return nil +local function pairs(t) end + +local next = pairs(dummy) + +---@type table +local t +local , v = next(t) +]] + +TEST 'boolean' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table, index?: K):K, V +---@return T +---@return nil +local function pairs(t) end + +local next = pairs(dummy) + +---@type table +local t +local k, = next(t) +]] + +TEST 'string' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table, index?: K):K, V +---@return T +---@return nil +local function pairs(t) end + +local next = pairs(dummy) + +---@type table +local t +local , v = next(t, nil) +]] + +TEST 'boolean' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table, index?: K):K, V +---@return T +---@return nil +local function pairs(t) end + +local next = pairs(dummy) + +---@type table +local t +local k, = next(t, nil) +]] + +TEST 'string' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table, index?: K):K, V +---@return T +---@return nil +local function pairs(t) end + +local next = pairs(dummy) + +---@type table +local t + +for , v in next, t do +end +]] + +TEST 'boolean' [[ +---@class boolean + +---@generic T: table, K, V +---@param t T +---@return fun(table: table, index?: K):K, V +---@return T +local function pairs(t) end + +local f = pairs(t) + +---@type table +local t + +for k, in f, t do +end +]] + +TEST 'string' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table, index?: K):K, V +---@return T +local function pairs(t) end + +---@type table +local t + +for , v in pairs(t) do +end +]] + +TEST 'boolean' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table, index: K):K, V +---@return T +---@return nil +local function pairs(t) end + +---@type table +local t + +for k, in pairs(t) do +end +]] + +TEST 'boolean' [[ +---@generic T: table, V +---@param t T +---@return fun(table: V[], i?: integer):integer, V +---@return T +---@return integer i +local function ipairs(t) end + +---@type boolean[] +local t + +for _, in ipairs(t) do +end +]] + +TEST 'boolean' [[ +---@generic T: table, V +---@param t T +---@return fun(table: V[], i?: integer):integer, V +---@return T +---@return integer i +local function ipairs(t) end + +---@type table +local t + +for _, in ipairs(t) do +end +]] + +TEST 'boolean' [[ +---@generic T: table, V +---@param t T +---@return fun(table: V[], i?: integer):integer, V +---@return T +---@return integer i +local function ipairs(t) end + +---@class MyClass +---@field [integer] boolean +local t + +for _, in ipairs(t) do +end +]] + +TEST 'boolean' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table, index: K):K, V +---@return T +---@return nil +local function pairs(t) end + +---@type boolean[] +local t + +for k, in pairs(t) do +end +]] + +TEST 'integer' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table, index?: K):K, V +---@return T +local function pairs(t) end + +---@type boolean[] +local t + +for , v in pairs(t) do +end +]] + +TEST 'E' [[ +---@class A +---@class B: A +---@class C: B +---@class D: C + +---@class E: D +local m + +function m:f() + return +end +]] + +TEST 'Cls' [[ +---@class Cls +local Cls = {} + +---@generic T +---@param self T +---@return T +function Cls.new(self) return self end + +local = Cls:new() +]] + +TEST 'Cls' [[ +---@class Cls +local Cls = {} + +---@generic T +---@param self T +---@return T +function Cls:new() return self end + +local = Cls:new() +]] + +TEST 'Cls' [[ +---@class Cls +local Cls = {} + +---@generic T +---@param self T +---@return T +function Cls.new(self) return self end + +local = Cls.new(Cls) +]] + +TEST 'Cls' [[ +---@class Cls +local Cls = {} + +---@generic T +---@param self T +---@return T +function Cls:new() return self end + +local = Cls.new(Cls) +]] + +TEST 'Rct' [[ +---@class Obj +local Obj = {} + +---@generic T +---@param self T +---@return T +function Obj.new(self) return self end + + +---@class Pnt:Obj +local Pnt = {x = 0, y = 0} + + +---@class Rct:Pnt +local Rct = {w = 0, h = 0} + + +local = Rct.new(Rct) + +-- local test = Rct:new() + +return test +]] + +TEST 'function' [[ +string.gsub():gsub():() +]] + +config.set(nil, 'Lua.hover.enumsLimit', 5) +TEST [['a'|'b'|'c'|'d'|'e'...(+5)]] [[ +---@type 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j' +local +]] + +config.set(nil, 'Lua.hover.enumsLimit', 1) +TEST [['a'...(+9)]] [[ +---@type 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j' +local +]] + +config.set(nil, 'Lua.hover.enumsLimit', 0) +TEST '...(+10)' [[ +---@type 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j' +local +]] + +config.set(nil, 'Lua.hover.enumsLimit', 5) + +TEST 'string|fun():string' [[ +---@type string | fun(): string +local +]] + +TEST 'string' [[ +local valids = { + ['Lua 5.1'] = false, + ['Lua 5.2'] = false, + ['Lua 5.3'] = false, + ['Lua 5.4'] = false, + ['LuaJIT'] = false, +} + +for , v in pairs(valids) do +end +]] + +TEST 'boolean' [[ +local valids = { + ['Lua 5.1'] = false, + ['Lua 5.2'] = false, + ['Lua 5.3'] = false, + ['Lua 5.4'] = false, + ['LuaJIT'] = false, +} + +for k, in pairs(valids) do +end +]] + +TEST 'string' [[ +local t = { + a = 1, + b = 1, +} + +for , v in pairs(t) do +end +]] + +TEST 'integer' [[ +local t = {'a', 'b'} + +for , v in pairs(t) do +end +]] + +TEST 'string' [[ +local t = {'a', 'b'} + +for k, in pairs(t) do +end +]] + +TEST 'fun():number, boolean' [[ +---@type fun():number, boolean +local +]] + + +TEST 'fun(value: Class)' [[ +---@class Class + +---@param callback fun(value: Class) +function work(callback) +end + +work( (value) +end) +]] + +TEST 'Class' [[ +---@class Class + +---@param callback fun(value: Class) +function work(callback) +end + +work(function () +end) +]] + +TEST 'fun(value: Class)' [[ +---@class Class + +---@param callback fun(value: Class) +function work(callback) +end + +pcall(work, (value) +end) +]] + +TEST 'Class' [[ +---@class Class + +---@param callback fun(value: Class) +function work(callback) +end + +xpcall(work, debug.traceback, function () +end) +]] + +TEST 'string' [[ +---@generic T +---@param x T +---@return { x: T } +local function f(x) end + +local t = f('') + +print(t.) +]] + +TEST 'string' [[ +---@generic T +---@param t T[] +---@param callback fun(v: T) +local function f(t, callback) end + +---@type string[] +local t + +f(t, function () end) +]] + +TEST 'unknown' [[ +---@generic T +---@param t T[] +---@param callback fun(v: T) +local function f(t, callback) end + +local t = {} + +f(t, function () end) +]] + +TEST 'table' [[ +local = setmetatable({}, { __index = function () end }) +]] + +TEST 'player' [[ +---@class player +local t + +:getOwner() +]] + +TEST 'string[][]' [[ +---@type string[][] +local +]] + +TEST 'table' [[ +---@type {}[] +local t + +local = t[1] +]] + +TEST 'string' [[ +---@type string[][] +local v = {} + +for _, a in ipairs(v) do + for i, in ipairs(a) do + end +end +]] + +--TEST 'number' [[ +-----@param x number +--local f +-- +--f = function () end +--]] + +TEST 'fun(i: integer)' [[ +--- @class Emit +--- @field on fun(eventName: string, cb: function) +--- @field on fun(eventName: 'died', cb: fun(i: integer)) +--- @field on fun(eventName: 'won', cb: fun(s: string)) +local emit = {} + +emit.on("died", (i) +end) +]] + +TEST 'integer' [[ +--- @class Emit +--- @field on fun(eventName: string, cb: function) +--- @field on fun(eventName: 'died', cb: fun(i: integer)) +--- @field on fun(eventName: 'won', cb: fun(s: string)) +local emit = {} + +emit.on("died", function () +end) +]] + +TEST 'integer' [[ +--- @class Emit +--- @field on fun(self: Emit, eventName: string, cb: function) +--- @field on fun(self: Emit, eventName: 'died', cb: fun(i: integer)) +--- @field on fun(self: Emit, eventName: 'won', cb: fun(s: string)) +local emit = {} + +emit:on("died", function () +end) +]] + +TEST 'integer' [[ +--- @class Emit +--- @field on fun(self: Emit, eventName: string, cb: function) +--- @field on fun(self: Emit, eventName: '"died"', cb: fun(i: integer)) +--- @field on fun(self: Emit, eventName: '"won"', cb: fun(s: string)) +local emit = {} + +emit.on(self, "died", function () +end) +]] + +TEST '👍' [[ +---@class 👍 +local +]] + +TEST 'integer' [[ +---@type boolean +local x + + = 1 +]] + +TEST 'integer' [[ +---@class Class +local x + + = 1 +]] + +TEST 'unknown' [[ +---@return number +local function f(x) + local = x() +end +]] + +TEST 'unknown' [[ +local mt + +---@return number +function mt:f() end + +local = mt() +]] + +TEST 'unknown' [[ +local + +---@class X +function mt:f(x) end +]] + +TEST 'any' [[ +local mt + +---@class X +function mt:f() end +]] + +TEST 'unknown' [[ +local + +---@type number +function mt:f(x) end +]] + +TEST 'any' [[ +local mt + +---@type number +function mt:f() end +]] + +TEST 'Test' [[ +---@class Test +_G. = {} +]] + +TEST 'integer' [[ +local mt = {} + +---@param callback fun(i: integer) +function mt:loop(callback) end + +mt:loop(function () + +end) +]] + +TEST 'C' [[ +---@class D +---@field y integer # D comment + +---@class C +---@field x integer # C comment +---@field d D + +---@param c C +local function f(c) end + +f + x = , +} +]] + +TEST 'integer' [[ +---@class D +---@field y integer # D comment + +---@class C +---@field x integer # C comment +---@field d D + +---@param c C +local function f(c) end + +f { + = , +} +]] + +TEST 'integer' [[ +---@class D +---@field y integer # D comment + +---@class C +---@field x integer # C comment +---@field d D + +---@param c C +local function f(c) end + +f { + d = { + = , + } +} +]] + +TEST 'integer' [[ +for = a, b, c do end +]] + +TEST 'number' [[ +---@param x number +function F() end + +---@param x boolean +function F(x) end +]] + +TEST 'B' [[ +---@class A +local A + +---@return A +function A:x() end + +---@class B: A +local B + +---@return B +function B:x() end + +---@type B +local t + +local = t.x() +]] + +TEST 'function' [[ +---@overload fun() +function () end +]] + +TEST 'integer' [[ +---@type table +local t + +t. +]] + +TEST '"a"|"b"|"c"' [[ +---@type table +local t + +t. +]] + +TEST 'integer' [[ +---@class A +---@field x integer + +---@type A +local t +t. +]] + +TEST 'boolean' [[ +local = true +var = 1 +var = 1.0 +]] + +TEST 'unknown' [[ +---@return ... +local function f() end + +local = f() +]] + +TEST 'unknown' [[ +---@return ... +local function f() end + +local _, = f() +]] + +TEST 'unknown' [[ +local t = { + x = 1, + y = 2, +} + +local = t[#t] +]] + +TEST 'string' [[ +local t = { + x = 1, + [1] = 'x', +} + +local = t[#t] +]] + +TEST 'string' [[ +local t = { 'x' } + +local = t[#t] +]] + +TEST '(string|integer)[]' [[ +---@type (string|integer)[] +local +]] + +TEST 'boolean' [[ +---@type table +local t + +---@alias uri string + +---@type string +local uri + +local = t[uri] +]] + +TEST 'A' [[ +---@class A +G = {} + +:A() +]] + +TEST 'A' [[ +---@type A +local = nil +]] + +TEST 'A' [[ +---@class A +---@field b B +local mt + +function mt:f() + self.b:x() + print() +end +]] + +TEST 'string?' [[ +---@return string? +local function f() end + +local = f() +]] + +TEST 'AA' [[ +---@class AA +---@overload fun():AA +local AAA + + +local = AAA() +]] + +TEST 'AA' [[ +---@class AA +---@overload fun():AA +AAA = {} + + +local = AAA() +]] + +TEST 'string' [[ +local +x = '1' +x = 1 +]] + +TEST 'string' [[ +local x + = '1' +x = 1 +]] + +TEST 'integer' [[ +local x +x = '1' + = 1 +]] + +TEST 'unknown' [[ +local x +print() +x = '1' +x = 1 +]] + +TEST 'string' [[ +local x +x = '1' +print() +x = 1 +]] + +TEST 'integer' [[ +local x +x = '1' +x = 1 +print() +]] + +TEST 'unknown' [[ +local x + +function A() + print() +end +]] + +TEST 'string' [[ +local x + +function A() + print() +end + +x = '1' +x = 1 +]] + +TEST 'string' [[ +local x + +x = '1' + +function A() + print() +end + +x = 1 +]] + +TEST 'integer' [[ +local x + +x = '1' +x = 1 + +function A() + print() +end + +]] + +TEST 'boolean' [[ +local x + +function A() + x = true + print() +end + +x = '1' +x = 1 +]] + +TEST 'unknown' [[ +local x + +function A() + x = true +end + +print() +x = '1' +x = 1 +]] + +TEST 'boolean' [[ +local x + +function A() + x = true + function B() + print() + end +end + +x = '1' +x = 1 +]] + +TEST 'table' [[ +local x + +function A() + x = true + function B() + x = {} + print() + end +end + +x = '1' +x = 1 +]] + +TEST 'boolean' [[ +local x + +function A() + x = true + function B() + x = {} + end + print() +end + +x = '1' +x = 1 +]] + +TEST 'unknown' [[ +local x + +function A() + x = true + function B() + x = {} + end +end + +function C() + print() +end + +x = '1' +x = 1 +]] + +TEST 'integer' [[ +local x +x = true +do + x = 1 +end +print() +]] + +TEST 'boolean' [[ +local x +x = true +function XX() + do + x = 1 + end +end +print() +]] + +TEST 'integer?' [[ +---@type integer? +local +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if then + print(x) +end +]] +--[[ +context 0 integer? + +save copy 'block' +save copy 'out' +push 'block' +get +push copy +truthy +falsy ref 'out' +get +save HEAD 'final' +push 'out' + +push copy HEAD +merge 'final' +]] + +TEST 'integer' [[ +---@type integer? +local x + +if x then + print() +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if x then + print(x) +end + +print() +]] + +TEST 'nil' [[ +---@type integer? +local x + +if not x then + print() +end + +print(x) +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not x then + x = 1 +end + +print() +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not x then + return +end + +print() +]] + +TEST 'integer' [[ +---@type integer? +local x + +if xxx and x then + print() +end +]] + +TEST 'unknown' [[ +---@type integer? +local x + +if not x and x then + print() +end +]] + +TEST 'integer' [[ +---@type integer? +local x + +if x and not mark[x] then + print() +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if xxx and x then +end + +print() +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if xxx and x then + return +end + +print() +]] + +TEST 'integer' [[ +---@type integer? +local x + +if x ~= nil then + print() +end + +print(x) +]] + +TEST 'integer|nil' [[ +---@type integer? +local x + +if x ~= nil then + print(x) +end + +print() +]] + +TEST 'nil' [[ +---@type integer? +local x + +if x == nil then + print() +end + +print(x) +]] + +TEST 'integer|nil' [[ +---@type integer? +local x + +if x == nil then + print(x) +end + +print() +]] + +TEST 'integer' [[ +---@type integer? +local x + + = x or 1 +]] + +TEST 'integer' [[ +---@type integer? +local x + + = x or y +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not x then + return +end + +print() +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not x then + goto ANYWHERE +end + +print() +]] + +TEST 'integer' [=[ +local x + +print(--[[@as integer]]) +]=] + +TEST 'integer' [=[ +print(--[[@as integer]]) +]=] + +TEST 'integer' [=[ +print(io.--[[@as integer]]) +]=] + +TEST 'integer' [=[ +local = io['open']--[[@as integer]]) +]=] + +TEST 'integer' [=[ +local = 1 + 1--[[@as integer]]) +]=] + +TEST 'integer' [=[ +local = not 1--[[@as integer]]) +]=] + +TEST 'integer' [=[ +local = ()--[[@as integer]]) +]=] + +TEST 'integer?' [[ +---@param x? integer +local function f() + +end +]] + +TEST 'integer' [[ +local x = 1 +x = +]] + +TEST 'integer?' [[ +---@class A +---@field x? integer +local t + +t. +]] + +TEST 'integer?' [[ +---@type { x?: integer } +local t + +t. +]] + +TEST 'boolean' [[ +---@class A +---@field [integer] boolean +local t + +local = t[1] +]] + +TEST 'unknown' [[ +local = y and z +]] + +TEST 'integer' [[ +---@type integer? +local x + +assert(x) + +print() +]] + +TEST 'integer' [[ +---@type integer? +local x + +assert(x ~= nil) + +print() +]] + +TEST 'integer' [[ +---@type integer | nil +local x + +assert(x) + +print() +]] + +TEST 'integer' [[ +---@type integer | nil +local x + +assert(x ~= nil) + +print() +]] + +TEST 'integer' [[ +local x + +assert(x == 1) + +print() +]] + +TEST 'integer' [[ +---@type integer? +local x + +if x and .y then +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if x and x.y then +end + +print() +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if x and x.y then + return +end + +print() +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not x or .y then +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if not x or x.y then + print() +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if x or x.y then + print() +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if x.y or x then + print() +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if x.y or not x then + print() +end +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not x or not y then + return +end + +print() +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not y or not x then + return +end + +print() +]] + +TEST 'integer' [[ +---@type integer? +local x + +while true do + if not x then + break + end + print() +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +while true do + if not x then + break + end +end + +print() +]] + +TEST 'integer' [[ +---@type integer? +local x + +while x do + print() +end +]] + +TEST 'integer' [[ +---@type fun():integer? +local iter + +for in iter do +end +]] + +TEST 'integer' [[ +local x + +---@type integer + = XXX +]] + +TEST 'unknown' [[ +for _ = 1, 999 do + local +end +]] + +TEST 'integer' [[ +local x + +---@cast x integer + +print() +]] + +TEST 'unknown' [[ +local x + +---@cast x integer + +local x +print() +]] + +TEST 'unknown' [[ +local x + +if true then + local x + ---@cast x integer + print(x) +end + +print() +]] + +TEST 'boolean|integer' [[ +local x = 1 + +---@cast x +boolean + +print() +]] + +TEST 'boolean' [[ +---@type integer|boolean +local x + +---@cast x -integer + +print() +]] + +TEST 'boolean?' [[ +---@type boolean +local x + +---@cast x +? + +print() +]] + +TEST 'boolean' [[ +---@type boolean? +local x + +---@cast x -? + +print() +]] + +TEST 'nil' [[ +---@type string? +local x + +if x then + return +else + print() +end + +print(x) +]] + +TEST 'string' [[ +---@type string? +local x + +if not x then + return +else + print() +end + +print(x) +]] + +TEST 'string' [[ +---@type string? +local x + +if not x then + return +else + print(x) +end + +print() +]] + +TEST 'true' [[ +---@type boolean | nil +local x + +if not x then + return +end + +print() +]] + +TEST 'true' [[ +---@type boolean +local t + +if t then + print() + return +end + +print(t) +]] + +TEST 'false' [[ +---@type boolean +local t + +if t then + print(t) + return +end + +print() +]] + +TEST 'nil' [[ +---@type integer? +local t + +if t then +else + print() +end + +print(t) +]] + +TEST 'table' [[ +local function f() + if x then + return y + end + return {} +end + +local = f() +]] + +TEST 'integer|table' [[ +local function returnI() + return 1 +end + +local function f() + if x then + return returnI() + end + return {} +end + +local = f() +]] + +TEST 'number' [[ +for _ in _ do + ---@type number + local +end +]] + +TEST 'unknown' [[ +for _ in _ do + ---@param x number + local +end +]] + +TEST 'unknown' [[ +---@type number +for in _ do +end +]] + +TEST 'number' [[ +---@param x number +for in _ do +end +]] + +TEST 'table' [[ +---@alias tp table + +---@type tp +local +]] + +TEST '{ name: boolean }' [[ +---@alias tp {name: boolean} + +---@type tp +local +]] + +TEST 'boolean|{ name: boolean }' [[ +---@alias tp boolean | {name: boolean} + +---@type tp +local +]] + +TEST '`1`|`true`' [[ +---@type `1` | `true` +local +]] + +TEST 'function' [[ +local x + +function x() end + +print() +]] + +TEST 'unknown' [[ +local x + +if x.field == 'haha' then + print() +end +]] + +TEST 'string' [[ +---@type string? +local t + +if not t or xxx then + return +end + +print() +]] + +TEST 'table' [[ +---@type table|nil +local t + +return function () + if not t then + return + end + + print() +end +]] + +TEST 'table' [[ +---@type table|nil +local t + +f(function () + if not t then + return + end + + print() +end) +]] + +TEST 'table' [[ +---@type table? +local t + +t = t or {} + +print() +]] + +TEST 'unknown|nil' [[ +local x + +if x == nil then +end + +print() +]] + +TEST 'table' [[ +---@alias xxx table + +---@type xxx +local +]] + +TEST 'xxx[][]' [[ +---@alias xxx xxx[] + +---@type xxx +local +]] + +TEST 'fun(x: fun(x: xxx))' [[ +---@alias xxx fun(x: xxx) + +---@type xxx +local +]] + +TEST 'table' [[ +---@type table|nil +local t + +while t do + print() +end +]] + +TEST 'table|nil' [[ +---@type table|nil +local t + +while do + print(t) +end +]] + +TEST 'table' [[ +---@type table|nil +local t + +while t ~= nil do + print() +end +]] + +TEST 'table|nil' [[ +---@type table|nil +local t + +while ~= nil do + print(t) +end +]] + +TEST 'integer' [[ +---@type integer? +local n + +if not n then + error('n is nil') +end + +print() +]] + +TEST 'integer' [[ +---@type integer? +local n + +if not n then + os.exit() +end + +print() +]] + +TEST 'table' [[ +---@type table? +local n + +print((n and .x)) +]] + +TEST 'table' [[ +---@type table? +local n + +n = n and .x or 1 +]] + +TEST 'table' [[ +---@type table? +local n + +n = ff[n and .x] +]] + +TEST 'integer' [[ +local x + +if type(x) == 'integer' then + print() +end +]] + +TEST 'boolean|integer' [[ +local x + +if type(x) == 'integer' +or type(x) == 'boolean' then + print() +end +]] + +TEST 'fun()' [[ +---@type fun()? +local x + +if type(x) == 'function' then + print() +end +]] + +TEST 'function' [[ +local x + +if type(x) == 'function' then + print() +end +]] + +TEST 'integer' [[ +local x +local tp = type(x) + +if tp == 'integer' then + print() +end +]] + +TEST 'integer' [[ +---@type integer? +local x + +if (x == nil) then +else + print() +end +]] + +TEST 'B' [[ +---@class A +---@class B + +---@type A +local x + +---@type B +x = call(x) + +print() +]] + +TEST 'nil' [[ +local function f() +end + +local = f() +]] + +TEST 'integer[]' [[ +---@type integer[] +local x +if not x then + return +end + +print() +]] + +TEST 'unknown' [[ +---@type string[] +local t + +local = t.x +]] + +TEST 'integer|unknown' [[ +local function f() + return GG +end + +local t + +t.x = 1 +t.x = f() + +print(t.) +]] + +TEST 'integer' [[ +local function f() + if X then + return X + else + return 1 + end +end + +local = f() +]] + +TEST 'unknown' [[ +local function f() + return t[k] +end + +local = f() +]] + +TEST 'integer|nil' [[ +local function f() + if x then + return + else + return 1 + end +end + +local = f() +]] + +TEST 'integer' [[ +---@class A +---@field x integer +local m + +m. = true + +print(m.x) +]] + +TEST 'integer' [[ +---@class A +---@field x integer +local m + +m.x = true + +print(m.) +]] + +TEST 'integer' [[ +---@class A +---@field x integer --> 1st +local m = { + x = '' --> 2nd +} + +---@type boolean +m.x = true --> 3rd (with ---@type above) + +m.x = {} --> 4th + +print(m.) +]] + +TEST 'string' [[ +---@class A +----@field x integer --> 1st +local m = { + x = '' --> 2nd +} + +---@type boolean +m.x = true --> 3rd (with ---@type above) + +m.x = {} --> 4th + +print(m.) +]] + +TEST 'boolean' [[ +---@class A +----@field x integer --> 1st +local m = { + --x = '' --> 2nd +} + +---@type boolean +m.x = true --> 3rd (with ---@type above) + +m.x = {} --> 4th + +print(m.) +]] + +TEST 'table' [[ +---@class A +----@field x integer --> 1st +local m = { + --x = '' --> 2nd +} + +---@type boolean +--m.x = true --> 3rd (with ---@type above) + +m.x = {} --> 4th + +print(m.) +]] + +TEST 'boolean?' [[ +---@generic T +---@param x T +---@return T +local function echo(x) end + +---@type boolean? +local b + +local = echo(b) +]] + +TEST 'boolean' [[ +---@generic T +---@param x T? +---@return T +local function echo(x) end + +---@type boolean? +local b + +local = echo(b) +]] + +TEST 'boolean' [[ +---@generic T +---@param x? T +---@return T +local function echo(x) end + +---@type boolean? +local b + +local = echo(b) +]] + +TEST 'boolean' [[ +---@type {[integer]: boolean, xx: integer} +local t + +local = t[1] +]] + +TEST 'boolean' [[ +---@type integer +local i + +---@type {[integer]: boolean, xx: integer} +local t + +local = t[i] +]] + +TEST 'string' [=[ +local x = true +local y = x--[[@as integer]] --is `integer` here +local z = --[[@as string]] --is `true` here +]=] + +TEST 'integer' [[ +---@type integer +local x + +if type(x) == 'number' then + print() +end +]] + +TEST 'boolean' [[ +---@class A +---@field [integer] boolean +local mt + +function mt:f() + ---@type integer + local index + local = self[index] +end +]] + +TEST 'boolean' [[ +---@class A +---@field [B] boolean + +---@class B + +---@type A +local a + +---@type B +local b + +local = a[b] +]] + +TEST 'number' [[ +---@type {x: string ; y: boolean; z: number} +local t + +local = t.z +]] + +TEST 'fun():number, boolean' [[ +---@type {f: fun():number, boolean} +local t + +local = t.f +]] + +TEST 'fun():number' [[ +---@type {(f: fun():number), x: boolean} +local t + +local = t.f +]] + +TEST 'boolean' [[ +---@param ... boolean +local function f(...) + local = ... +end +]] + +TEST 'boolean' [[ +---@param ... boolean +local function f(...) + local _, = ... +end +]] + +TEST 'boolean' [[ +---@return boolean ... +local function f() end + +local = f() +]] + +TEST 'boolean' [[ +---@return boolean ... +local function f() end + +local _, = f() +]] + +TEST 'boolean' [[ +---@type fun():name1: boolean, name2:number +local f + +local = f() +]] + +TEST 'number' [[ +---@type fun():name1: boolean, name2:number +local f + +local _, = f() +]] +TEST 'boolean' [[ +---@type fun():(name1: boolean, name2:number) +local f + +local = f() +]] + +TEST 'number' [[ +---@type fun():(name1: boolean, name2:number) +local f + +local _, = f() +]] + +TEST 'boolean' [[ +---@type fun():...: boolean +local f + +local _, = f() +]] + +TEST 'string' [[ +local s +while true do + s = '' +end +print() +]] + +TEST 'string' [[ +local s +for _ in _ do + s = '' +end +print() +]] + +TEST 'A' [[ +---@class A: string + +---@type A +local = '' +]] + +TEST 'number' [[ +---@return number +local function f() end +local x, = 1, f() +]] + +TEST 'boolean' [[ +---@return number, boolean +local function f() end +local x, y, = 1, f() +]] + +TEST 'number' [[ +---@return number, boolean +local function f() end +local x, y, = 1, 2, f() +]] + +TEST 'unknown' [[ +local f + +print() + +function f() end +]] + +TEST 'unknown' [[ +local f + +do + print() +end + +function f() end +]] + +TEST 'function' [[ +local f + +function A() + print() +end + +function f() end +]] + +TEST 'number' [[ +---@type number|nil +local n + +local t = { + x = n and , +} +]] + +TEST 'table' [[ +---@type table? +local n + +if not n or not .x then +end +]] + +TEST 'table' [[ +---@type table? +local n + +if not n or not [1] then +end +]] + +TEST 'number' [[ +---@type number|false +local n + +---@cast n -false + +print() +]] + +TEST 'table' [[ +---@type number|table +local n + +if n +---@cast n table +and .type == 'xxx' then +end +]] + +TEST 'integer' [[ +---@type integer? +local n +if true then + n = 0 +end +local = n or 0 +]] + +TEST 'number' [=[ +local = F()--[[@as number]] +]=] + +TEST 'number' [=[ +local function f() + return F()--[[@as number]] +end + +local = f() +]=] + +TEST 'number' [=[ +local = X --[[@as number]] +]=] + +TEST 'number' [[ +---@return number?, number? +local function f() end + +for , y in f do +end +]] + +TEST 'number' [[ +---@return number?, number? +local function f() end + +for x, in f do +end +]] + +TEST 'number|nil' [[ +---@type table|nil +local a + +---@type number|nil +local b + +local = a and b +]] + +TEST 'number|table|nil' [[ +---@type table|nil +local a + +---@type number|nil +local b + +local = a or b +]] + +TEST 'number|table|nil' [[ +---@type table|nil +local a + +---@type number|nil +local b + +local c = a and b +local = a or b +]] + +TEST 'number' [[ +local x + +---@return number +local function f() +end + +x = f() + +print() +]] + +TEST 'number' [[ +local x + +---@return number +local function f() +end + +_, x = pcall(f) + +print() +]] + +TEST 'string' [[ +---@type table +local t + +---@type number +local n +---@type string +local s + +local = t[n] +local test2 = t[s] --test and test2 are unknow +]] + +TEST 'string' [[ +---@type table +local t + +---@type number +local n +---@type string +local s + +local test = t[n] +local = t[s] --test and test2 are unknow +]] + +TEST 'table' [[ +---@type table +local t + + = {} +]] + +TEST 'integer' [[ +---@type integer[]|A +local t + +local = t[1] +]] + +TEST 'integer' [[ +---@type integer +---@diagnostic disable +local +]] + +TEST 'A' [[ +---@class A +---@diagnostic disable +local +]] + +TEST '{ [string]: number, [true]: string, [1]: boolean, tag: integer }' [[ +---@type {[string]: number, [true]: string, [1]: boolean, tag: integer} +local +]] + +TEST 'unknown' [[ +local mt = {} +mt. = nil +]] + +TEST 'unknown' [[ +mt = {} +mt. = nil +]] + +TEST 'A' [[ +---@class A +---@operator unm: A + +---@type A +local a +local = -a +]] + +TEST 'A' [[ +---@class A +---@operator bnot: A + +---@type A +local a +local = ~a +]] + +TEST 'A' [[ +---@class A +---@operator len: A + +---@type A +local a +local = #a +]] + +TEST 'A' [[ +---@class A +---@operator add: A + +---@type A +local a +local = a + 1 +]] + +TEST 'A' [[ +---@class A +---@operator sub: A + +---@type A +local a +local = a - 1 +]] + +TEST 'A' [[ +---@class A +---@operator mul: A + +---@type A +local a +local = a * 1 +]] + +TEST 'A' [[ +---@class A +---@operator div: A + +---@type A +local a +local = a / 1 +]] + +TEST 'A' [[ +---@class A +---@operator mod: A + +---@type A +local a +local = a % 1 +]] + +TEST 'A' [[ +---@class A +---@operator pow: A + +---@type A +local a +local = a ^ 1 +]] + +TEST 'A' [[ +---@class A +---@operator idiv: A + +---@type A +local a +local = a // 1 +]] + +TEST 'A' [[ +---@class A +---@operator band: A + +---@type A +local a +local = a & 1 +]] + +TEST 'A' [[ +---@class A +---@operator bor: A + +---@type A +local a +local = a | 1 +]] + +TEST 'A' [[ +---@class A +---@operator bxor: A + +---@type A +local a +local = a ~ 1 +]] + +TEST 'A' [[ +---@class A +---@operator shl: A + +---@type A +local a +local = a << 1 +]] + +TEST 'A' [[ +---@class A +---@operator shr: A + +---@type A +local a +local = a >> 1 +]] + +TEST 'A' [[ +---@class A +---@operator concat: A + +---@type A +local a +local = a .. 1 +]] + +TEST 'A' [[ +---@class A +---@operator add(boolean): boolean +---@operator add(integer): A + +---@type A +local a +local = a + 1 +]] + +TEST 'boolean' [[ +---@class A +---@operator add(boolean): boolean +---@operator add(integer): A + +---@type A +local a +local = a + true +]] + +TEST 'A' [[ +---@class A +---@operator call: A + +---@type A +local a +local = a() +]] + +TEST 'A' [[ +---@class A +---@operator call: A + +---@type A +local a + +local t = { + = a(), +} +]] + +TEST 'boolean' [[ +---@class A +---@field n number +---@field [string] boolean +local t + +local = t.xx +]] + +TEST 'number' [[ +---@class A +---@field n number +---@field [string] boolean +local t + +local = t.n +]] + +TEST 'string' [[ +---@class string +---@operator mod: string + +local = '' % 1 +]] + +TEST 'string|integer' [[ +---@type boolean +local bool + +local = bool and '' or 0 +]] + +TEST 'string|integer' [[ +local bool + +if X then + bool = true +else + bool = false +end + +local = bool and '' or 0 +]] + +TEST 'boolean' [[ +---@type boolean|true|false +local +]] + +TEST 'integer|false' [[ +local = X == 1 and X == 1 and 1 +]] + +TEST 'unknown|nil' [[ +local function f() + if X then + return ({})[1] + end + return nil +end + +local = f() +]] + +TEST 'integer' [[ +---@generic T +---@vararg T # ERROR +---@return T +local function test(...) + return ... +end + +local = test(1) +]] + +TEST 'boolean' [[ +---@type boolean, number +local , y +]] + +TEST 'number' [[ +---@type boolean, number +local x, +]] + +TEST 'unknown' [[ +---@type _, number +local , y +]] + +TEST 'number[]' [[ +local t +---@cast t number[]? + +local x = t and [i] +]] + +TEST 'number?' [[ +---@type number[]? +local t + +local = t and t[i] +]] + +TEST 'number' [[ +---@type number +local x + +if not .y then + x = nil +end +]] + +TEST 'number' [[ +---@type number|nil +local x +while x == nil do + if x == nil then + return + end + + x = nil +end + +print() +]] + +TEST 'integer' [[ +local A = { + ---@class XXX + B = {} +} + +A.B.C = 1 + +print(A.B.) +]] + +TEST '-2|-3|1' [[ +---@type 1|-2|-3 +local +]] + +TEST 'table' [[ +---@enum A +local m = {} + +print() +]] + +TEST 'A' [[ +---@class A +---@overload fun():A +local m = {} + +---@return A +function m:init() + return +end +]] + +TEST 'string' [[ +---@vararg string +function F(...) + local t = {...} + for k, in pairs(t) do + end +end +]] + +TEST 'string' [[ +---@vararg string +function F(...) + local t = {...} + for k, in ipairs(t) do + end +end +]] + +TEST 'integerA' [[ +---@type integerA +for = 1, 10 do +end +]] + +TEST 'string' [[ +---@class A +---@field x string + +---@class B : A +local t = {} + +t.x = t.x + +print(t.) +]] + +TEST 'unknown' [[ +local t = { + x = 1, +} + +local x + +local = t[x] +]] + +TEST 'A|B' [[ +---@class A +---@class B: A + +---@type A|B +local +]] + +TEST 'function' [[ +---@class myClass +local myClass = { has = { nested = {} } } + +function myClass.has.nested.fn() end + +---@type myClass +local class + +class.has.nested.() +]] + +TEST 'integer[]' [[ +---@generic T +---@param f fun(x: T) +---@return T[] +local function x(f) end + +---@param x integer +local = x(function (x) end) +]] + +TEST 'integer[]' [[ +---@generic T +---@param f fun():T +---@return T[] +local function x(f) end + +local = x(function () + return 1 +end) +]] + +TEST 'integer[]' [[ +---@generic T +---@param f fun():T +---@return T[] +local function x(f) end + +---@return integer +local = x(function () end) +]] + +TEST 'integer[]' [[ +---@generic T +---@param f fun(x: T) +---@return T[] +local function x(f) end + +---@type fun(x: integer) +local cb + +local = x(cb) +]] + +TEST 'integer[]' [[ +---@generic T +---@param f fun():T +---@return T[] +local function x(f) end + +---@type fun(): integer +local cb + +local = x(cb) +]] + +TEST 'integer' [[ +---@return fun(x: integer) +local function f() + return function () + end +end +]] + +TEST 'string' [[ +---@class A +---@field f fun(x: string) + +---@type A +local t = { + f = function () end +} +]] + +config.set(nil, 'Lua.runtime.special', { + ['xx.assert'] = 'assert' +}) + +TEST 'number' [[ +---@type number? +local t + +xx.assert(t) + +print() +]] + +config.set(nil, 'Lua.runtime.special', nil) + +TEST 'A' [[ +---@class A +local mt + +---@return +function mt:init() +end +]] + +TEST 'A' [[ +---@class A +local mt + +---@return self +function mt:init() +end + +local = mt:init() +]] + +TEST 'A' [[ +---@class A +---@field x +]] + +TEST 'A' [[ +---@class A +---@field x self + +---@type A +local o + +print(o.) +]] + +TEST 'A' [[ +---@class A +---@overload fun(): self +local A + +local = A() +]] + +TEST 'number' [[ +---@type table<'Test1', fun(x: number)> +local t = { + ["Test1"] = function() end, +} +]] + +TEST 'number' [[ +---@type table<5, fun(x: number)> +local t = { + [5] = function() end, +} +]] + +TEST 'number' [[ +---@type fun(x: number) +local function f() end +]] + +TEST 'boolean' [[ +---@generic T: string | boolean | table +---@param x T +---@return T +local function f(x) + return x +end + +local = f(true) +]] + +TEST 'number' [[ +---@class A +---@field [1] number +---@field [2] boolean +local t + +local = t[1] +]] + +TEST 'boolean' [[ +---@class A +---@field [1] number +---@field [2] boolean +local t + +local = t[2] +]] + +TEST 'N' [[ +---@class N: number +local x + +if x == 0.1 then + print() +end +]] + +TEST 'vec3' [[ +---@class mat4 +---@operator mul(vec3): vec3 -- matrix * vector +---@operator mul(number): mat4 -- matrix * constant + +---@class vec3: number + +---@type mat4, vec3 +local m, v + +local = m * v +]] + +TEST 'mat4' [[ +---@class mat4 +---@operator mul(number): mat4 -- matrix * constant +---@operator mul(vec3): vec3 -- matrix * vector + +---@class vec3: number + +---@type mat4, vec3 +local m, v + +local = m * v +]] + +TEST 'A|B' [[ +---@class A +---@class B + +---@type A|B +local t + +if x then + ---@cast t A +else + print() +end +]] + +TEST 'A|B' [[ +---@class A +---@class B + +---@type A|B +local t + +if x then + ---@cast t A +elseif then +end +]] + +TEST 'A|B' [[ +---@class A +---@class B + +---@type A|B +local t + +if x then + ---@cast t A + print(t) +elseif then +end +]] + +TEST 'A|B' [[ +---@class A +---@class B + +---@type A|B +local t + +if x then + ---@cast t A + print(t) +elseif then + ---@cast t A + print(t) +end +]] + +TEST 'function' [[ +local function x() + print() +end +]] + +TEST 'number' [[ +---@type number? +local x + +do + if not x then + return + end +end + +print() +]] + +TEST 'number' [[ +---@type number[] +local xs + +---@type fun(x): number? +local f + +for _, in ipairs(xs) do + x = f(x) +end +]] + +TEST 'number' [[ +---@type number? +X = Y + +if X then + print() +end +]] + +TEST 'number' [[ +---@type number|boolean +X = Y + +if type(X) == 'number' then + print() +end +]] + +TEST 'boolean' [[ +---@type number|boolean +X = Y + +if type(X) ~= 'number' then + print() +end +]] + +TEST 'boolean' [[ +---@type number +X = Y + +---@cast X boolean + +print() +]] + +TEST 'number' [[ +---@type number +local t + +if xxx == then + print(t) +end +]] + +TEST 'V' [[ +---@class V +X = 1 + +print() +]] + +TEST 'V' [[ +---@class V +X.Y = 1 + +print(X.) +]] + +TEST 'integer' [[ +local x = {} + +x.y = 1 +local y = x.y +x.y = nil + +print() +]] + +TEST 'function' [[ +function X() + () +end + +function Y() +end +]] + +TEST 'A_Class' [[ +---@class A_Class +local A = { x = 5 } + +function A:func() + for i = 1, .x do + print(i) + end + + self.y = 3 + self.y = self.y + 3 +end +]] + +TEST 'number' [[ +---@type number? +local n +local = n or error('') +]] + +TEST 'Foo' [[ +---@class Foo +---@operator mul(Foo): Foo +---@operator mul(Bar): Foo +---@class Bar + +---@type Foo +local foo + +---@type Foo|Bar +local fooOrBar + +local = foo * fooOrBar +]] + +TEST 'number' [[ +local a = 4; +local b = 2; + +local = a / b; +]] + +TEST 'string' [[ +local a = '4'; +local b = '2'; + +local = a .. b; +]] + +TEST 'number|{ [1]: string }' [[ +---@alias Some +---| { [1]: string } +---| number + +local x ---@type Some + +print() +]] + +TEST 'integer' [[ +---@class metatable : table +---@field __index table + +---@param table table +---@param metatable? metatable +---@return table +function setmetatable(table, metatable) end + +local m = setmetatable({},{ __index = { a = 1 } }) + +m. +]] + +TEST 'integer' [[ +---@class metatable : table +---@field __index table + +---@param table table +---@param metatable? metatable +---@return table +function setmetatable(table, metatable) end + +local mt = {a = 1 } +local m = setmetatable({},{ __index = mt }) + +m. +]] + +TEST 'integer' [[ +local x = 1 +repeat +until +]] + +-- #2144 +TEST 'A' [=[ +local function f() + return {} --[[@as A]] +end + +local = f() +]=] + +TEST 'A' [=[ +local function f() + ---@type A + return {} +end + +local = f() +]=] + +TEST 'boolean|number' [[ +---@alias A number +---@alias(partial) A boolean + +---@type A +local +]] diff --git a/test/type_inference/init.lua b/test/type_inference/init.lua index da4590a6..35900bc3 100644 --- a/test/type_inference/init.lua +++ b/test/type_inference/init.lua @@ -44,4302 +44,5 @@ function TEST(wanted) end end -TEST 'nil' [[ -local = nil -]] - -TEST 'string' [[ -local = '111' -]] - -TEST 'boolean' [[ -local = true -]] - -TEST 'integer' [[ -local = 1 -]] - -TEST 'number' [[ -local = 1.0 -]] - -TEST 'unknown' [[ -local -]] - -TEST 'unknown' [[ -local -var = y -]] - -TEST 'any' [[ -function f() - -end -]] - -TEST 'any' [[ -function f() - x = 1 -end -]] - -TEST 'string' [[ -local var = '111' -t. = var -]] - -TEST 'string' [[ -local -var = '111' -]] - -TEST 'string' [[ -local var - = '111' -]] - -TEST 'string' [[ -local var -var = '111' -print() -]] - -TEST 'function' [[ -function () -end -]] - -TEST 'function' [[ -local function () -end -]] - -TEST 'function' [[ -local xx - = function () -end -]] - -TEST 'table' [[ -local = {} -]] - -TEST 'unknown' [[ -() -]] - -TEST 'boolean' [[ - = not y -]] - -TEST 'integer' [[ - = #y -]] - -TEST 'integer' [[ - = #'aaaa' -]] - -TEST 'integer' [[ - = #{} -]] - -TEST 'number' [[ - = - y -]] - -TEST 'number' [[ - = - 1.0 -]] - -TEST 'integer' [[ - = ~ y -]] - -TEST 'integer' [[ - = ~ 1 -]] - -TEST 'boolean' [[ - = 1 < 2 -]] - -TEST 'integer' [[ -local a = true -local b = 1 - = a and b -]] - -TEST 'integer' [[ -local a = false -local b = 1 - = a or b -]] - -TEST 'boolean' [[ - = a == b -]] - -TEST 'unknown' [[ - = a << b -]] - -TEST 'integer' [[ - = 1 << 2 -]] - -TEST 'unknown' [[ - = a .. b -]] - -TEST 'string' [[ - = 'a' .. 'b' -]] - -TEST 'string' [[ - = 'a' .. 1 -]] - -TEST 'string' [[ - = 'a' .. 1.0 -]] - -TEST 'unknown' [[ - = a + b -]] - -TEST 'number' [[ - = 1 + 2.0 -]] - -TEST 'integer' [[ - = 1 + 2 -]] - -TEST 'integer' [[ ----@type integer -local a - - = - a -]] - -TEST 'number' [[ -local a - - = - a -]] - -TEST 'unknown' [[ - = 1 + X -]] - -TEST 'unknown' [[ - = 1.0 + X -]] - -TEST 'tablelib' [[ ----@class tablelib -table = {} - -() -]] - -TEST 'string' [[ -_VERSION = 'Lua 5.4' - - = _VERSION -]] - -TEST 'function' [[ ----@class stringlib -local string - -string.xxx = function () end - -return ('x'). -]] - -TEST 'function' [[ ----@class stringlib -String = {} - -String.xxx = function () end - -return ('x'). -]] - -TEST 'function' [[ ----@class stringlib -local string - -string.xxx = function () end - - = ('x').xxx -]] - -TEST 'function' [[ ----@class stringlib -local string - -string.xxx = function () end - -_VERSION = 'Lua 5.4' - - = _VERSION.xxx -]] - -TEST 'table' [[ - = setmetatable({}) -]] - -TEST 'integer' [[ -local function x() - return 1 -end - = x() -]] - -TEST 'integer|nil' [[ -local function x() - return 1 - return nil -end - = x() -]] - -TEST 'unknown|nil' [[ -local function x() - return a - return nil -end - = x() -]] - -TEST 'unknown|nil' [[ -local function x() - return nil - return f() -end - = x() -]] - -TEST 'unknown|nil' [[ -local function x() - return nil - return f() -end -_, = x() -]] - -TEST 'integer' [[ -local function x() - return 1 -end -_, = pcall(x) -]] - -TEST 'integer' [[ -function x() - return 1 -end -_, = pcall(x) -]] - -TEST 'integer' [[ -local function x() - return 1 -end -_, = xpcall(x) -]] - -TEST 'A' [[ ----@class A - ----@return A -local function f2() end - -local function f() - return f2() -end - -local = f() -]] - --- 不根据调用者的输入参数来推测 ---TEST 'number' [[ ---local function x(a) --- return ---end ---x(1) ---]] - ---TEST 'table' [[ ---setmetatable() ---]] - --- 不根据对方函数内的使用情况来推测 -TEST 'unknown' [[ -local function x(a) - _ = a + 1 -end -local b -x() -]] - -TEST 'unknown' [[ -local function x(a, ...) - local _, , _ = ... -end -x(nil, 'xx', 1, true) -]] - --- 引用不跨越参数 -TEST 'unknown' [[ -local function x(a, ...) - return true, 'ss', ... -end -local _, _, _, , _ = x(nil, true, 1, 'yy') -]] - -TEST 'unknown' [[ -local = next() -]] - -TEST 'unknown' [[ -local a, b -function a() - return b() -end -function b() - return a() -end -local = a() -]] - -TEST 'class' [[ ----@class class -local -]] - -TEST 'string' [[ ----@class string - ----@type string -local -]] - -TEST '1' [[ ----@type 1 -local -]] - -TEST 'string[]' [[ ----@class string - ----@type string[] -local -]] - -TEST 'string|table' [[ ----@class string ----@class table - ----@type string | table -local -]] - -TEST [['enum1'|'enum2']] [[ ----@type 'enum1' | 'enum2' -local -]] - -TEST [["enum1"|"enum2"]] [[ ----@type "enum1" | "enum2" -local -]] - -config.set(nil, 'Lua.hover.expandAlias', false) -TEST 'A' [[ ----@alias A 'enum1' | 'enum2' - ----@type A -local -]] - -TEST 'A' [[ ----@alias A 'enum1' | 'enum2' | A - ----@type A -local -]] - -TEST 'A' [[ ----@alias A 'enum1' | 'enum2' | B - ----@type A -local -]] -config.set(nil, 'Lua.hover.expandAlias', true) -TEST [['enum1'|'enum2']] [[ ----@alias A 'enum1' | 'enum2' - ----@type A -local -]] - -TEST [['enum1'|'enum2']] [[ ----@alias A 'enum1' | 'enum2' | A - ----@type A -local -]] - -TEST [['enum1'|'enum2'|B]] [[ ----@alias A 'enum1' | 'enum2' | B - ----@type A -local -]] - -TEST '1|true' [[ ----@alias A 1 | true - ----@type A -local -]] - -TEST 'fun()' [[ ----@type fun() -local -]] - -TEST 'fun(a: string, b: any, ...any)' [[ ----@type fun(a: string, b, ...) -local -]] - -TEST 'fun(a: string, b: any, c?: boolean, ...any):c, d?, ...unknown' [[ ----@type fun(a: string, b, c?: boolean, ...):c, d?, ... -local -]] - -TEST '{ [string]: string }' [[ ----@type { [string]: string } -local -]] - -TEST 'table' [[ ----@class string ----@class number - ----@type table -local -]] - -TEST 'A' [[ ----@class A - ----@type A -local -]] - -TEST 'string' [[ ----@class string - ----@type string[] -local x -local = x[1] -]] - -TEST 'string' [[ ----@class string - ----@return string[] -local function f() end -local x = f() -local = x[1] -]] - -TEST 'table' [[ -local t = {} -local = setmetatable(t) -]] - -TEST 'CCC' [[ ----@class CCC - ----@type table -local t = {} - -print(t.) -]] - -TEST [['aaa'|'bbb']] [[ ----@type table -local t = {} - -print(t.) -]] - -TEST 'integer' [[ ----@generic K ----@type fun(a?: K):K -local f - -local = f(1) -]] - -TEST 'unknown' [[ ----@generic K ----@type fun(a?: K):K -local f - -local = f(nil) -]] - -TEST 'unknown' [[ ----@generic K ----@type fun(a: K|integer):K -local f - -local = f(1) -]] - -TEST 'integer' [[ ----@class integer - ----@generic T: table, V ----@param t T ----@return fun(table: V[], i?: integer):integer, V ----@return T ----@return integer i -local function ipairs() end - -for in ipairs() do -end -]] - -TEST 'table' [[ ----@generic K, V ----@param t table ----@return K ----@return V -local function next(t) end - ----@type table -local t -local k, v = next() -]] - -TEST 'string' [[ ----@class string - ----@generic K, V ----@param t table ----@return K ----@return V -local function next(t) end - ----@type table -local t -local , v = next(t) -]] - -TEST 'boolean' [[ ----@class boolean - ----@generic K, V ----@param t table ----@return K ----@return V -local function next(t) end - ----@type table -local t -local k, = next(t) -]] - -TEST 'boolean' [[ ----@generic K ----@type fun(arg: K):K -local f - -local = f(true) -]] - -TEST 'string' [[ ----@class string - ----@generic K, V ----@type fun(arg: table):K, V -local f - ----@type table -local t - -local , v = f(t) -]] - -TEST 'boolean' [[ ----@class boolean - ----@generic K, V ----@type fun(arg: table):K, V -local f - ----@type table -local t - -local k, = f(t) -]] - -TEST 'fun()' [[ ----@return fun() -local function f() end - -local = f() -]] - -TEST 'table' [[ ----@return table -local function f() end - -local = f() -]] - -TEST 'string' [[ ----@class string - ----@generic K, V ----@return fun(arg: table):K, V -local function f() end - -local f2 = f() - ----@type table -local t - -local , v = f2(t) -]] - -TEST 'fun(a: ):integer, ' [[ ----@generic K, V ----@param a K ----@return fun(a: V):K, V -local function f(a) end - -local = f(1) -]] - -TEST 'integer' [[ ----@generic K, V ----@param a K ----@return fun(a: V):K, V -local function f(a) end - -local f2 = f(1) -local , v = f2(true) -]] - -TEST 'boolean' [[ ----@generic K, V ----@param a K ----@return fun(a: V):K, V -local function f(a) end - -local f2 = f(1) -local i, = f2(true) -]] - -TEST 'fun(table: table<, >, index?: ):, ' [[ ----@generic T: table, K, V ----@param t T ----@return fun(table: table, index?: K):K, V ----@return T ----@return nil -local function pairs(t) end - -local = pairs(dummy) -]] - -TEST 'string' [[ ----@generic T: table, K, V ----@param t T ----@return fun(table: table, index?: K):K, V ----@return T ----@return nil -local function pairs(t) end - -local next = pairs(dummy) - ----@type table -local t -local , v = next(t) -]] - -TEST 'boolean' [[ ----@generic T: table, K, V ----@param t T ----@return fun(table: table, index?: K):K, V ----@return T ----@return nil -local function pairs(t) end - -local next = pairs(dummy) - ----@type table -local t -local k, = next(t) -]] - -TEST 'string' [[ ----@generic T: table, K, V ----@param t T ----@return fun(table: table, index?: K):K, V ----@return T ----@return nil -local function pairs(t) end - -local next = pairs(dummy) - ----@type table -local t -local , v = next(t, nil) -]] - -TEST 'boolean' [[ ----@generic T: table, K, V ----@param t T ----@return fun(table: table, index?: K):K, V ----@return T ----@return nil -local function pairs(t) end - -local next = pairs(dummy) - ----@type table -local t -local k, = next(t, nil) -]] - -TEST 'string' [[ ----@generic T: table, K, V ----@param t T ----@return fun(table: table, index?: K):K, V ----@return T ----@return nil -local function pairs(t) end - -local next = pairs(dummy) - ----@type table -local t - -for , v in next, t do -end -]] - -TEST 'boolean' [[ ----@class boolean - ----@generic T: table, K, V ----@param t T ----@return fun(table: table, index?: K):K, V ----@return T -local function pairs(t) end - -local f = pairs(t) - ----@type table -local t - -for k, in f, t do -end -]] - -TEST 'string' [[ ----@generic T: table, K, V ----@param t T ----@return fun(table: table, index?: K):K, V ----@return T -local function pairs(t) end - ----@type table -local t - -for , v in pairs(t) do -end -]] - -TEST 'boolean' [[ ----@generic T: table, K, V ----@param t T ----@return fun(table: table, index: K):K, V ----@return T ----@return nil -local function pairs(t) end - ----@type table -local t - -for k, in pairs(t) do -end -]] - -TEST 'boolean' [[ ----@generic T: table, V ----@param t T ----@return fun(table: V[], i?: integer):integer, V ----@return T ----@return integer i -local function ipairs(t) end - ----@type boolean[] -local t - -for _, in ipairs(t) do -end -]] - -TEST 'boolean' [[ ----@generic T: table, V ----@param t T ----@return fun(table: V[], i?: integer):integer, V ----@return T ----@return integer i -local function ipairs(t) end - ----@type table -local t - -for _, in ipairs(t) do -end -]] - -TEST 'boolean' [[ ----@generic T: table, V ----@param t T ----@return fun(table: V[], i?: integer):integer, V ----@return T ----@return integer i -local function ipairs(t) end - ----@class MyClass ----@field [integer] boolean -local t - -for _, in ipairs(t) do -end -]] - -TEST 'boolean' [[ ----@generic T: table, K, V ----@param t T ----@return fun(table: table, index: K):K, V ----@return T ----@return nil -local function pairs(t) end - ----@type boolean[] -local t - -for k, in pairs(t) do -end -]] - -TEST 'integer' [[ ----@generic T: table, K, V ----@param t T ----@return fun(table: table, index?: K):K, V ----@return T -local function pairs(t) end - ----@type boolean[] -local t - -for , v in pairs(t) do -end -]] - -TEST 'E' [[ ----@class A ----@class B: A ----@class C: B ----@class D: C - ----@class E: D -local m - -function m:f() - return -end -]] - -TEST 'Cls' [[ ----@class Cls -local Cls = {} - ----@generic T ----@param self T ----@return T -function Cls.new(self) return self end - -local = Cls:new() -]] - -TEST 'Cls' [[ ----@class Cls -local Cls = {} - ----@generic T ----@param self T ----@return T -function Cls:new() return self end - -local = Cls:new() -]] - -TEST 'Cls' [[ ----@class Cls -local Cls = {} - ----@generic T ----@param self T ----@return T -function Cls.new(self) return self end - -local = Cls.new(Cls) -]] - -TEST 'Cls' [[ ----@class Cls -local Cls = {} - ----@generic T ----@param self T ----@return T -function Cls:new() return self end - -local = Cls.new(Cls) -]] - -TEST 'Rct' [[ ----@class Obj -local Obj = {} - ----@generic T ----@param self T ----@return T -function Obj.new(self) return self end - - ----@class Pnt:Obj -local Pnt = {x = 0, y = 0} - - ----@class Rct:Pnt -local Rct = {w = 0, h = 0} - - -local = Rct.new(Rct) - --- local test = Rct:new() - -return test -]] - -TEST 'function' [[ -string.gsub():gsub():() -]] - -config.set(nil, 'Lua.hover.enumsLimit', 5) -TEST [['a'|'b'|'c'|'d'|'e'...(+5)]] [[ ----@type 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j' -local -]] - -config.set(nil, 'Lua.hover.enumsLimit', 1) -TEST [['a'...(+9)]] [[ ----@type 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j' -local -]] - -config.set(nil, 'Lua.hover.enumsLimit', 0) -TEST '...(+10)' [[ ----@type 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j' -local -]] - -config.set(nil, 'Lua.hover.enumsLimit', 5) - -TEST 'string|fun():string' [[ ----@type string | fun(): string -local -]] - -TEST 'string' [[ -local valids = { - ['Lua 5.1'] = false, - ['Lua 5.2'] = false, - ['Lua 5.3'] = false, - ['Lua 5.4'] = false, - ['LuaJIT'] = false, -} - -for , v in pairs(valids) do -end -]] - -TEST 'boolean' [[ -local valids = { - ['Lua 5.1'] = false, - ['Lua 5.2'] = false, - ['Lua 5.3'] = false, - ['Lua 5.4'] = false, - ['LuaJIT'] = false, -} - -for k, in pairs(valids) do -end -]] - -TEST 'string' [[ -local t = { - a = 1, - b = 1, -} - -for , v in pairs(t) do -end -]] - -TEST 'integer' [[ -local t = {'a', 'b'} - -for , v in pairs(t) do -end -]] - -TEST 'string' [[ -local t = {'a', 'b'} - -for k, in pairs(t) do -end -]] - -TEST 'fun():number, boolean' [[ ----@type fun():number, boolean -local -]] - - -TEST 'fun(value: Class)' [[ ----@class Class - ----@param callback fun(value: Class) -function work(callback) -end - -work( (value) -end) -]] - -TEST 'Class' [[ ----@class Class - ----@param callback fun(value: Class) -function work(callback) -end - -work(function () -end) -]] - -TEST 'fun(value: Class)' [[ ----@class Class - ----@param callback fun(value: Class) -function work(callback) -end - -pcall(work, (value) -end) -]] - -TEST 'Class' [[ ----@class Class - ----@param callback fun(value: Class) -function work(callback) -end - -xpcall(work, debug.traceback, function () -end) -]] - -TEST 'string' [[ ----@generic T ----@param x T ----@return { x: T } -local function f(x) end - -local t = f('') - -print(t.) -]] - -TEST 'string' [[ ----@generic T ----@param t T[] ----@param callback fun(v: T) -local function f(t, callback) end - ----@type string[] -local t - -f(t, function () end) -]] - -TEST 'unknown' [[ ----@generic T ----@param t T[] ----@param callback fun(v: T) -local function f(t, callback) end - -local t = {} - -f(t, function () end) -]] - -TEST 'table' [[ -local = setmetatable({}, { __index = function () end }) -]] - -TEST 'player' [[ ----@class player -local t - -:getOwner() -]] - -TEST 'string[][]' [[ ----@type string[][] -local -]] - -TEST 'table' [[ ----@type {}[] -local t - -local = t[1] -]] - -TEST 'string' [[ ----@type string[][] -local v = {} - -for _, a in ipairs(v) do - for i, in ipairs(a) do - end -end -]] - ---TEST 'number' [[ ------@param x number ---local f --- ---f = function () end ---]] - -TEST 'fun(i: integer)' [[ ---- @class Emit ---- @field on fun(eventName: string, cb: function) ---- @field on fun(eventName: 'died', cb: fun(i: integer)) ---- @field on fun(eventName: 'won', cb: fun(s: string)) -local emit = {} - -emit.on("died", (i) -end) -]] - -TEST 'integer' [[ ---- @class Emit ---- @field on fun(eventName: string, cb: function) ---- @field on fun(eventName: 'died', cb: fun(i: integer)) ---- @field on fun(eventName: 'won', cb: fun(s: string)) -local emit = {} - -emit.on("died", function () -end) -]] - -TEST 'integer' [[ ---- @class Emit ---- @field on fun(self: Emit, eventName: string, cb: function) ---- @field on fun(self: Emit, eventName: 'died', cb: fun(i: integer)) ---- @field on fun(self: Emit, eventName: 'won', cb: fun(s: string)) -local emit = {} - -emit:on("died", function () -end) -]] - -TEST 'integer' [[ ---- @class Emit ---- @field on fun(self: Emit, eventName: string, cb: function) ---- @field on fun(self: Emit, eventName: '"died"', cb: fun(i: integer)) ---- @field on fun(self: Emit, eventName: '"won"', cb: fun(s: string)) -local emit = {} - -emit.on(self, "died", function () -end) -]] - -TEST '👍' [[ ----@class 👍 -local -]] - -TEST 'integer' [[ ----@type boolean -local x - - = 1 -]] - -TEST 'integer' [[ ----@class Class -local x - - = 1 -]] - -TEST 'unknown' [[ ----@return number -local function f(x) - local = x() -end -]] - -TEST 'unknown' [[ -local mt - ----@return number -function mt:f() end - -local = mt() -]] - -TEST 'unknown' [[ -local - ----@class X -function mt:f(x) end -]] - -TEST 'any' [[ -local mt - ----@class X -function mt:f() end -]] - -TEST 'unknown' [[ -local - ----@type number -function mt:f(x) end -]] - -TEST 'any' [[ -local mt - ----@type number -function mt:f() end -]] - -TEST 'Test' [[ ----@class Test -_G. = {} -]] - -TEST 'integer' [[ -local mt = {} - ----@param callback fun(i: integer) -function mt:loop(callback) end - -mt:loop(function () - -end) -]] - -TEST 'C' [[ ----@class D ----@field y integer # D comment - ----@class C ----@field x integer # C comment ----@field d D - ----@param c C -local function f(c) end - -f - x = , -} -]] - -TEST 'integer' [[ ----@class D ----@field y integer # D comment - ----@class C ----@field x integer # C comment ----@field d D - ----@param c C -local function f(c) end - -f { - = , -} -]] - -TEST 'integer' [[ ----@class D ----@field y integer # D comment - ----@class C ----@field x integer # C comment ----@field d D - ----@param c C -local function f(c) end - -f { - d = { - = , - } -} -]] - -TEST 'integer' [[ -for = a, b, c do end -]] - -TEST 'number' [[ ----@param x number -function F() end - ----@param x boolean -function F(x) end -]] - -TEST 'B' [[ ----@class A -local A - ----@return A -function A:x() end - ----@class B: A -local B - ----@return B -function B:x() end - ----@type B -local t - -local = t.x() -]] - -TEST 'function' [[ ----@overload fun() -function () end -]] - -TEST 'integer' [[ ----@type table -local t - -t. -]] - -TEST '"a"|"b"|"c"' [[ ----@type table -local t - -t. -]] - -TEST 'integer' [[ ----@class A ----@field x integer - ----@type A -local t -t. -]] - -TEST 'boolean' [[ -local = true -var = 1 -var = 1.0 -]] - -TEST 'unknown' [[ ----@return ... -local function f() end - -local = f() -]] - -TEST 'unknown' [[ ----@return ... -local function f() end - -local _, = f() -]] - -TEST 'unknown' [[ -local t = { - x = 1, - y = 2, -} - -local = t[#t] -]] - -TEST 'string' [[ -local t = { - x = 1, - [1] = 'x', -} - -local = t[#t] -]] - -TEST 'string' [[ -local t = { 'x' } - -local = t[#t] -]] - -TEST '(string|integer)[]' [[ ----@type (string|integer)[] -local -]] - -TEST 'boolean' [[ ----@type table -local t - ----@alias uri string - ----@type string -local uri - -local = t[uri] -]] - -TEST 'A' [[ ----@class A -G = {} - -:A() -]] - -TEST 'A' [[ ----@type A -local = nil -]] - -TEST 'A' [[ ----@class A ----@field b B -local mt - -function mt:f() - self.b:x() - print() -end -]] - -TEST 'string?' [[ ----@return string? -local function f() end - -local = f() -]] - -TEST 'AA' [[ ----@class AA ----@overload fun():AA -local AAA - - -local = AAA() -]] - -TEST 'AA' [[ ----@class AA ----@overload fun():AA -AAA = {} - - -local = AAA() -]] - -TEST 'string' [[ -local -x = '1' -x = 1 -]] - -TEST 'string' [[ -local x - = '1' -x = 1 -]] - -TEST 'integer' [[ -local x -x = '1' - = 1 -]] - -TEST 'unknown' [[ -local x -print() -x = '1' -x = 1 -]] - -TEST 'string' [[ -local x -x = '1' -print() -x = 1 -]] - -TEST 'integer' [[ -local x -x = '1' -x = 1 -print() -]] - -TEST 'unknown' [[ -local x - -function A() - print() -end -]] - -TEST 'string' [[ -local x - -function A() - print() -end - -x = '1' -x = 1 -]] - -TEST 'string' [[ -local x - -x = '1' - -function A() - print() -end - -x = 1 -]] - -TEST 'integer' [[ -local x - -x = '1' -x = 1 - -function A() - print() -end - -]] - -TEST 'boolean' [[ -local x - -function A() - x = true - print() -end - -x = '1' -x = 1 -]] - -TEST 'unknown' [[ -local x - -function A() - x = true -end - -print() -x = '1' -x = 1 -]] - -TEST 'boolean' [[ -local x - -function A() - x = true - function B() - print() - end -end - -x = '1' -x = 1 -]] - -TEST 'table' [[ -local x - -function A() - x = true - function B() - x = {} - print() - end -end - -x = '1' -x = 1 -]] - -TEST 'boolean' [[ -local x - -function A() - x = true - function B() - x = {} - end - print() -end - -x = '1' -x = 1 -]] - -TEST 'unknown' [[ -local x - -function A() - x = true - function B() - x = {} - end -end - -function C() - print() -end - -x = '1' -x = 1 -]] - -TEST 'integer' [[ -local x -x = true -do - x = 1 -end -print() -]] - -TEST 'boolean' [[ -local x -x = true -function XX() - do - x = 1 - end -end -print() -]] - -TEST 'integer?' [[ ----@type integer? -local -]] - -TEST 'integer?' [[ ----@type integer? -local x - -if then - print(x) -end -]] ---[[ -context 0 integer? - -save copy 'block' -save copy 'out' -push 'block' -get -push copy -truthy -falsy ref 'out' -get -save HEAD 'final' -push 'out' - -push copy HEAD -merge 'final' -]] - -TEST 'integer' [[ ----@type integer? -local x - -if x then - print() -end -]] - -TEST 'integer?' [[ ----@type integer? -local x - -if x then - print(x) -end - -print() -]] - -TEST 'nil' [[ ----@type integer? -local x - -if not x then - print() -end - -print(x) -]] - -TEST 'integer' [[ ----@type integer? -local x - -if not x then - x = 1 -end - -print() -]] - -TEST 'integer' [[ ----@type integer? -local x - -if not x then - return -end - -print() -]] - -TEST 'integer' [[ ----@type integer? -local x - -if xxx and x then - print() -end -]] - -TEST 'unknown' [[ ----@type integer? -local x - -if not x and x then - print() -end -]] - -TEST 'integer' [[ ----@type integer? -local x - -if x and not mark[x] then - print() -end -]] - -TEST 'integer?' [[ ----@type integer? -local x - -if xxx and x then -end - -print() -]] - -TEST 'integer?' [[ ----@type integer? -local x - -if xxx and x then - return -end - -print() -]] - -TEST 'integer' [[ ----@type integer? -local x - -if x ~= nil then - print() -end - -print(x) -]] - -TEST 'integer|nil' [[ ----@type integer? -local x - -if x ~= nil then - print(x) -end - -print() -]] - -TEST 'nil' [[ ----@type integer? -local x - -if x == nil then - print() -end - -print(x) -]] - -TEST 'integer|nil' [[ ----@type integer? -local x - -if x == nil then - print(x) -end - -print() -]] - -TEST 'integer' [[ ----@type integer? -local x - - = x or 1 -]] - -TEST 'integer' [[ ----@type integer? -local x - - = x or y -]] - -TEST 'integer' [[ ----@type integer? -local x - -if not x then - return -end - -print() -]] - -TEST 'integer' [[ ----@type integer? -local x - -if not x then - goto ANYWHERE -end - -print() -]] - -TEST 'integer' [=[ -local x - -print(--[[@as integer]]) -]=] - -TEST 'integer' [=[ -print(--[[@as integer]]) -]=] - -TEST 'integer' [=[ -print(io.--[[@as integer]]) -]=] - -TEST 'integer' [=[ -local = io['open']--[[@as integer]]) -]=] - -TEST 'integer' [=[ -local = 1 + 1--[[@as integer]]) -]=] - -TEST 'integer' [=[ -local = not 1--[[@as integer]]) -]=] - -TEST 'integer' [=[ -local = ()--[[@as integer]]) -]=] - -TEST 'integer?' [[ ----@param x? integer -local function f() - -end -]] - -TEST 'integer' [[ -local x = 1 -x = -]] - -TEST 'integer?' [[ ----@class A ----@field x? integer -local t - -t. -]] - -TEST 'integer?' [[ ----@type { x?: integer } -local t - -t. -]] - -TEST 'boolean' [[ ----@class A ----@field [integer] boolean -local t - -local = t[1] -]] - -TEST 'unknown' [[ -local = y and z -]] - -TEST 'integer' [[ ----@type integer? -local x - -assert(x) - -print() -]] - -TEST 'integer' [[ ----@type integer? -local x - -assert(x ~= nil) - -print() -]] - -TEST 'integer' [[ ----@type integer | nil -local x - -assert(x) - -print() -]] - -TEST 'integer' [[ ----@type integer | nil -local x - -assert(x ~= nil) - -print() -]] - -TEST 'integer' [[ -local x - -assert(x == 1) - -print() -]] - -TEST 'integer' [[ ----@type integer? -local x - -if x and .y then -end -]] - -TEST 'integer?' [[ ----@type integer? -local x - -if x and x.y then -end - -print() -]] - -TEST 'integer?' [[ ----@type integer? -local x - -if x and x.y then - return -end - -print() -]] - -TEST 'integer' [[ ----@type integer? -local x - -if not x or .y then -end -]] - -TEST 'integer?' [[ ----@type integer? -local x - -if not x or x.y then - print() -end -]] - -TEST 'integer?' [[ ----@type integer? -local x - -if x or x.y then - print() -end -]] - -TEST 'integer?' [[ ----@type integer? -local x - -if x.y or x then - print() -end -]] - -TEST 'integer?' [[ ----@type integer? -local x - -if x.y or not x then - print() -end -]] - -TEST 'integer' [[ ----@type integer? -local x - -if not x or not y then - return -end - -print() -]] - -TEST 'integer' [[ ----@type integer? -local x - -if not y or not x then - return -end - -print() -]] - -TEST 'integer' [[ ----@type integer? -local x - -while true do - if not x then - break - end - print() -end -]] - -TEST 'integer?' [[ ----@type integer? -local x - -while true do - if not x then - break - end -end - -print() -]] - -TEST 'integer' [[ ----@type integer? -local x - -while x do - print() -end -]] - -TEST 'integer' [[ ----@type fun():integer? -local iter - -for in iter do -end -]] - -TEST 'integer' [[ -local x - ----@type integer - = XXX -]] - -TEST 'unknown' [[ -for _ = 1, 999 do - local -end -]] - -TEST 'integer' [[ -local x - ----@cast x integer - -print() -]] - -TEST 'unknown' [[ -local x - ----@cast x integer - -local x -print() -]] - -TEST 'unknown' [[ -local x - -if true then - local x - ---@cast x integer - print(x) -end - -print() -]] - -TEST 'boolean|integer' [[ -local x = 1 - ----@cast x +boolean - -print() -]] - -TEST 'boolean' [[ ----@type integer|boolean -local x - ----@cast x -integer - -print() -]] - -TEST 'boolean?' [[ ----@type boolean -local x - ----@cast x +? - -print() -]] - -TEST 'boolean' [[ ----@type boolean? -local x - ----@cast x -? - -print() -]] - -TEST 'nil' [[ ----@type string? -local x - -if x then - return -else - print() -end - -print(x) -]] - -TEST 'string' [[ ----@type string? -local x - -if not x then - return -else - print() -end - -print(x) -]] - -TEST 'string' [[ ----@type string? -local x - -if not x then - return -else - print(x) -end - -print() -]] - -TEST 'true' [[ ----@type boolean | nil -local x - -if not x then - return -end - -print() -]] - -TEST 'true' [[ ----@type boolean -local t - -if t then - print() - return -end - -print(t) -]] - -TEST 'false' [[ ----@type boolean -local t - -if t then - print(t) - return -end - -print() -]] - -TEST 'nil' [[ ----@type integer? -local t - -if t then -else - print() -end - -print(t) -]] - -TEST 'table' [[ -local function f() - if x then - return y - end - return {} -end - -local = f() -]] - -TEST 'integer|table' [[ -local function returnI() - return 1 -end - -local function f() - if x then - return returnI() - end - return {} -end - -local = f() -]] - -TEST 'number' [[ -for _ in _ do - ---@type number - local -end -]] - -TEST 'unknown' [[ -for _ in _ do - ---@param x number - local -end -]] - -TEST 'unknown' [[ ----@type number -for in _ do -end -]] - -TEST 'number' [[ ----@param x number -for in _ do -end -]] - -TEST 'table' [[ ----@alias tp table - ----@type tp -local -]] - -TEST '{ name: boolean }' [[ ----@alias tp {name: boolean} - ----@type tp -local -]] - -TEST 'boolean|{ name: boolean }' [[ ----@alias tp boolean | {name: boolean} - ----@type tp -local -]] - -TEST '`1`|`true`' [[ ----@type `1` | `true` -local -]] - -TEST 'function' [[ -local x - -function x() end - -print() -]] - -TEST 'unknown' [[ -local x - -if x.field == 'haha' then - print() -end -]] - -TEST 'string' [[ ----@type string? -local t - -if not t or xxx then - return -end - -print() -]] - -TEST 'table' [[ ----@type table|nil -local t - -return function () - if not t then - return - end - - print() -end -]] - -TEST 'table' [[ ----@type table|nil -local t - -f(function () - if not t then - return - end - - print() -end) -]] - -TEST 'table' [[ ----@type table? -local t - -t = t or {} - -print() -]] - -TEST 'unknown|nil' [[ -local x - -if x == nil then -end - -print() -]] - -TEST 'table' [[ ----@alias xxx table - ----@type xxx -local -]] - -TEST 'xxx[][]' [[ ----@alias xxx xxx[] - ----@type xxx -local -]] - -TEST 'fun(x: fun(x: xxx))' [[ ----@alias xxx fun(x: xxx) - ----@type xxx -local -]] - -TEST 'table' [[ ----@type table|nil -local t - -while t do - print() -end -]] - -TEST 'table|nil' [[ ----@type table|nil -local t - -while do - print(t) -end -]] - -TEST 'table' [[ ----@type table|nil -local t - -while t ~= nil do - print() -end -]] - -TEST 'table|nil' [[ ----@type table|nil -local t - -while ~= nil do - print(t) -end -]] - -TEST 'integer' [[ ----@type integer? -local n - -if not n then - error('n is nil') -end - -print() -]] - -TEST 'integer' [[ ----@type integer? -local n - -if not n then - os.exit() -end - -print() -]] - -TEST 'table' [[ ----@type table? -local n - -print((n and .x)) -]] - -TEST 'table' [[ ----@type table? -local n - -n = n and .x or 1 -]] - -TEST 'table' [[ ----@type table? -local n - -n = ff[n and .x] -]] - -TEST 'integer' [[ -local x - -if type(x) == 'integer' then - print() -end -]] - -TEST 'boolean|integer' [[ -local x - -if type(x) == 'integer' -or type(x) == 'boolean' then - print() -end -]] - -TEST 'fun()' [[ ----@type fun()? -local x - -if type(x) == 'function' then - print() -end -]] - -TEST 'function' [[ -local x - -if type(x) == 'function' then - print() -end -]] - -TEST 'integer' [[ -local x -local tp = type(x) - -if tp == 'integer' then - print() -end -]] - -TEST 'integer' [[ ----@type integer? -local x - -if (x == nil) then -else - print() -end -]] - -TEST 'B' [[ ----@class A ----@class B - ----@type A -local x - ----@type B -x = call(x) - -print() -]] - -TEST 'nil' [[ -local function f() -end - -local = f() -]] - -TEST 'integer[]' [[ ----@type integer[] -local x -if not x then - return -end - -print() -]] - -TEST 'unknown' [[ ----@type string[] -local t - -local = t.x -]] - -TEST 'integer|unknown' [[ -local function f() - return GG -end - -local t - -t.x = 1 -t.x = f() - -print(t.) -]] - -TEST 'integer' [[ -local function f() - if X then - return X - else - return 1 - end -end - -local = f() -]] - -TEST 'unknown' [[ -local function f() - return t[k] -end - -local = f() -]] - -TEST 'integer|nil' [[ -local function f() - if x then - return - else - return 1 - end -end - -local = f() -]] - -TEST 'integer' [[ ----@class A ----@field x integer -local m - -m. = true - -print(m.x) -]] - -TEST 'integer' [[ ----@class A ----@field x integer -local m - -m.x = true - -print(m.) -]] - -TEST 'integer' [[ ----@class A ----@field x integer --> 1st -local m = { - x = '' --> 2nd -} - ----@type boolean -m.x = true --> 3rd (with ---@type above) - -m.x = {} --> 4th - -print(m.) -]] - -TEST 'string' [[ ----@class A -----@field x integer --> 1st -local m = { - x = '' --> 2nd -} - ----@type boolean -m.x = true --> 3rd (with ---@type above) - -m.x = {} --> 4th - -print(m.) -]] - -TEST 'boolean' [[ ----@class A -----@field x integer --> 1st -local m = { - --x = '' --> 2nd -} - ----@type boolean -m.x = true --> 3rd (with ---@type above) - -m.x = {} --> 4th - -print(m.) -]] - -TEST 'table' [[ ----@class A -----@field x integer --> 1st -local m = { - --x = '' --> 2nd -} - ----@type boolean ---m.x = true --> 3rd (with ---@type above) - -m.x = {} --> 4th - -print(m.) -]] - -TEST 'boolean?' [[ ----@generic T ----@param x T ----@return T -local function echo(x) end - ----@type boolean? -local b - -local = echo(b) -]] - -TEST 'boolean' [[ ----@generic T ----@param x T? ----@return T -local function echo(x) end - ----@type boolean? -local b - -local = echo(b) -]] - -TEST 'boolean' [[ ----@generic T ----@param x? T ----@return T -local function echo(x) end - ----@type boolean? -local b - -local = echo(b) -]] - -TEST 'boolean' [[ ----@overload fun():boolean ----@param x integer ----@return number -function f(x) -end - -local = f() -]] - -TEST 'number' [[ ----@overload fun():boolean ----@param x integer ----@return number -function f(x) -end - -local = f(1) -]] - -TEST 'boolean' [[ ----@overload fun():boolean ----@param x integer ----@return number -function f(x) -end - -function r0() - return -end - -local = f(r0()) -]] - -TEST 'number' [[ ----@overload fun():boolean ----@param x integer ----@return number -function f(x) -end - -function r1() - return 1 -end - -local = f(r1()) -]] - -TEST 'boolean' [[ ----@overload fun():boolean ----@param x integer ----@return number -function f(x) -end - ----@type fun() -local r0 - -local = f(r0()) -]] - -TEST 'number' [[ ----@overload fun():boolean ----@param x integer ----@return number -function f(x) -end - ----@type fun():integer -local r1 - -local = f(r1()) -]] - -TEST 'boolean' [[ ----@overload fun(x: number, y: number):string ----@overload fun(x: number):number ----@return boolean -local function f() end - -local = f() -local n2 = f(0) -local n3 = f(0, 0) -]] - -TEST 'number' [[ ----@overload fun(x: number, y: number):string ----@overload fun(x: number):number ----@return boolean -local function f() end - -local n1 = f() -local = f(0) -local n3 = f(0, 0) -]] - -TEST 'string' [[ ----@overload fun(x: number, y: number):string ----@overload fun(x: number):number ----@return boolean -local function f() end - -local n1 = f() -local n2 = f(0) -local = f(0, 0) -]] - -TEST 'boolean' [[ ----@type {[integer]: boolean, xx: integer} -local t - -local = t[1] -]] - -TEST 'boolean' [[ ----@type integer -local i - ----@type {[integer]: boolean, xx: integer} -local t - -local = t[i] -]] - -TEST 'string' [=[ -local x = true -local y = x--[[@as integer]] --is `integer` here -local z = --[[@as string]] --is `true` here -]=] - -TEST 'integer' [[ ----@type integer -local x - -if type(x) == 'number' then - print() -end -]] - -TEST 'boolean' [[ ----@class A ----@field [integer] boolean -local mt - -function mt:f() - ---@type integer - local index - local = self[index] -end -]] - -TEST 'boolean' [[ ----@class A ----@field [B] boolean - ----@class B - ----@type A -local a - ----@type B -local b - -local = a[b] -]] - -TEST 'number' [[ ----@type {x: string ; y: boolean; z: number} -local t - -local = t.z -]] - -TEST 'fun():number, boolean' [[ ----@type {f: fun():number, boolean} -local t - -local = t.f -]] - -TEST 'fun():number' [[ ----@type {(f: fun():number), x: boolean} -local t - -local = t.f -]] - -TEST 'boolean' [[ ----@param ... boolean -local function f(...) - local = ... -end -]] - -TEST 'boolean' [[ ----@param ... boolean -local function f(...) - local _, = ... -end -]] - -TEST 'boolean' [[ ----@return boolean ... -local function f() end - -local = f() -]] - -TEST 'boolean' [[ ----@return boolean ... -local function f() end - -local _, = f() -]] - -TEST 'boolean' [[ ----@type fun():name1: boolean, name2:number -local f - -local = f() -]] - -TEST 'number' [[ ----@type fun():name1: boolean, name2:number -local f - -local _, = f() -]] -TEST 'boolean' [[ ----@type fun():(name1: boolean, name2:number) -local f - -local = f() -]] - -TEST 'number' [[ ----@type fun():(name1: boolean, name2:number) -local f - -local _, = f() -]] - -TEST 'boolean' [[ ----@type fun():...: boolean -local f - -local _, = f() -]] - -TEST 'string' [[ -local s -while true do - s = '' -end -print() -]] - -TEST 'string' [[ -local s -for _ in _ do - s = '' -end -print() -]] - -TEST 'A' [[ ----@class A: string - ----@type A -local = '' -]] - -TEST 'number' [[ ----@return number -local function f() end -local x, = 1, f() -]] - -TEST 'boolean' [[ ----@return number, boolean -local function f() end -local x, y, = 1, f() -]] - -TEST 'number' [[ ----@return number, boolean -local function f() end -local x, y, = 1, 2, f() -]] - -TEST 'unknown' [[ -local f - -print() - -function f() end -]] - -TEST 'unknown' [[ -local f - -do - print() -end - -function f() end -]] - -TEST 'function' [[ -local f - -function A() - print() -end - -function f() end -]] - -TEST 'number' [[ ----@type number|nil -local n - -local t = { - x = n and , -} -]] - -TEST 'table' [[ ----@type table? -local n - -if not n or not .x then -end -]] - -TEST 'table' [[ ----@type table? -local n - -if not n or not [1] then -end -]] - -TEST 'number' [[ ----@type number|false -local n - ----@cast n -false - -print() -]] - -TEST 'table' [[ ----@type number|table -local n - -if n ----@cast n table -and .type == 'xxx' then -end -]] - -TEST 'integer' [[ ----@type integer? -local n -if true then - n = 0 -end -local = n or 0 -]] - -TEST 'number' [=[ -local = F()--[[@as number]] -]=] - -TEST 'number' [=[ -local function f() - return F()--[[@as number]] -end - -local = f() -]=] - -TEST 'number' [=[ -local = X --[[@as number]] -]=] - -TEST 'number' [[ ----@return number?, number? -local function f() end - -for , y in f do -end -]] - -TEST 'number' [[ ----@return number?, number? -local function f() end - -for x, in f do -end -]] - -TEST 'number|nil' [[ ----@type table|nil -local a - ----@type number|nil -local b - -local = a and b -]] - -TEST 'number|table|nil' [[ ----@type table|nil -local a - ----@type number|nil -local b - -local = a or b -]] - -TEST 'number|table|nil' [[ ----@type table|nil -local a - ----@type number|nil -local b - -local c = a and b -local = a or b -]] - -TEST 'number' [[ -local x - ----@return number -local function f() -end - -x = f() - -print() -]] - -TEST 'number' [[ -local x - ----@return number -local function f() -end - -_, x = pcall(f) - -print() -]] - -TEST 'string' [[ ----@type table -local t - ----@type number -local n ----@type string -local s - -local = t[n] -local test2 = t[s] --test and test2 are unknow -]] - -TEST 'string' [[ ----@type table -local t - ----@type number -local n ----@type string -local s - -local test = t[n] -local = t[s] --test and test2 are unknow -]] - -TEST 'table' [[ ----@type table -local t - - = {} -]] - -TEST 'integer' [[ ----@type integer[]|A -local t - -local = t[1] -]] - -TEST 'integer' [[ ----@type integer ----@diagnostic disable -local -]] - -TEST 'A' [[ ----@class A ----@diagnostic disable -local -]] - -TEST '{ [string]: number, [true]: string, [1]: boolean, tag: integer }' [[ ----@type {[string]: number, [true]: string, [1]: boolean, tag: integer} -local -]] - -TEST 'unknown' [[ -local mt = {} -mt. = nil -]] - -TEST 'unknown' [[ -mt = {} -mt. = nil -]] - -TEST 'A' [[ ----@class A ----@operator unm: A - ----@type A -local a -local = -a -]] - -TEST 'A' [[ ----@class A ----@operator bnot: A - ----@type A -local a -local = ~a -]] - -TEST 'A' [[ ----@class A ----@operator len: A - ----@type A -local a -local = #a -]] - -TEST 'A' [[ ----@class A ----@operator add: A - ----@type A -local a -local = a + 1 -]] - -TEST 'A' [[ ----@class A ----@operator sub: A - ----@type A -local a -local = a - 1 -]] - -TEST 'A' [[ ----@class A ----@operator mul: A - ----@type A -local a -local = a * 1 -]] - -TEST 'A' [[ ----@class A ----@operator div: A - ----@type A -local a -local = a / 1 -]] - -TEST 'A' [[ ----@class A ----@operator mod: A - ----@type A -local a -local = a % 1 -]] - -TEST 'A' [[ ----@class A ----@operator pow: A - ----@type A -local a -local = a ^ 1 -]] - -TEST 'A' [[ ----@class A ----@operator idiv: A - ----@type A -local a -local = a // 1 -]] - -TEST 'A' [[ ----@class A ----@operator band: A - ----@type A -local a -local = a & 1 -]] - -TEST 'A' [[ ----@class A ----@operator bor: A - ----@type A -local a -local = a | 1 -]] - -TEST 'A' [[ ----@class A ----@operator bxor: A - ----@type A -local a -local = a ~ 1 -]] - -TEST 'A' [[ ----@class A ----@operator shl: A - ----@type A -local a -local = a << 1 -]] - -TEST 'A' [[ ----@class A ----@operator shr: A - ----@type A -local a -local = a >> 1 -]] - -TEST 'A' [[ ----@class A ----@operator concat: A - ----@type A -local a -local = a .. 1 -]] - -TEST 'A' [[ ----@class A ----@operator add(boolean): boolean ----@operator add(integer): A - ----@type A -local a -local = a + 1 -]] - -TEST 'boolean' [[ ----@class A ----@operator add(boolean): boolean ----@operator add(integer): A - ----@type A -local a -local = a + true -]] - -TEST 'A' [[ ----@class A ----@operator call: A - ----@type A -local a -local = a() -]] - -TEST 'A' [[ ----@class A ----@operator call: A - ----@type A -local a - -local t = { - = a(), -} -]] - -TEST 'boolean' [[ ----@class A ----@field n number ----@field [string] boolean -local t - -local = t.xx -]] - -TEST 'number' [[ ----@class A ----@field n number ----@field [string] boolean -local t - -local = t.n -]] - -TEST 'string' [[ ----@class string ----@operator mod: string - -local = '' % 1 -]] - -TEST 'string|integer' [[ ----@type boolean -local bool - -local = bool and '' or 0 -]] - -TEST 'string|integer' [[ -local bool - -if X then - bool = true -else - bool = false -end - -local = bool and '' or 0 -]] - -TEST 'boolean' [[ ----@type boolean|true|false -local -]] - -TEST 'integer|false' [[ -local = X == 1 and X == 1 and 1 -]] - -TEST 'unknown|nil' [[ -local function f() - if X then - return ({})[1] - end - return nil -end - -local = f() -]] - -TEST 'integer' [[ ----@generic T ----@vararg T # ERROR ----@return T -local function test(...) - return ... -end - -local = test(1) -]] - -TEST 'boolean' [[ ----@type boolean, number -local , y -]] - -TEST 'number' [[ ----@type boolean, number -local x, -]] - -TEST 'unknown' [[ ----@type _, number -local , y -]] - -TEST 'number[]' [[ -local t ----@cast t number[]? - -local x = t and [i] -]] - -TEST 'number?' [[ ----@type number[]? -local t - -local = t and t[i] -]] - -TEST 'number' [[ ----@type number -local x - -if not .y then - x = nil -end -]] - -TEST 'number' [[ ----@type number|nil -local x -while x == nil do - if x == nil then - return - end - - x = nil -end - -print() -]] - -TEST 'integer' [[ -local A = { - ---@class XXX - B = {} -} - -A.B.C = 1 - -print(A.B.) -]] - -TEST '-2|-3|1' [[ ----@type 1|-2|-3 -local -]] - -TEST 'table' [[ ----@enum A -local m = {} - -print() -]] - -TEST 'A' [[ ----@class A ----@overload fun():A -local m = {} - ----@return A -function m:init() - return -end -]] - -TEST 'string' [[ ----@vararg string -function F(...) - local t = {...} - for k, in pairs(t) do - end -end -]] - -TEST 'string' [[ ----@vararg string -function F(...) - local t = {...} - for k, in ipairs(t) do - end -end -]] - -TEST 'integerA' [[ ----@type integerA -for = 1, 10 do -end -]] - -TEST 'string' [[ ----@class A ----@field x string - ----@class B : A -local t = {} - -t.x = t.x - -print(t.) -]] - -TEST 'unknown' [[ -local t = { - x = 1, -} - -local x - -local = t[x] -]] - -TEST 'A|B' [[ ----@class A ----@class B: A - ----@type A|B -local -]] - -TEST 'function' [[ ----@class myClass -local myClass = { has = { nested = {} } } - -function myClass.has.nested.fn() end - ----@type myClass -local class - -class.has.nested.() -]] - -TEST 'integer[]' [[ ----@generic T ----@param f fun(x: T) ----@return T[] -local function x(f) end - ----@param x integer -local = x(function (x) end) -]] - -TEST 'integer[]' [[ ----@generic T ----@param f fun():T ----@return T[] -local function x(f) end - -local = x(function () - return 1 -end) -]] - -TEST 'integer[]' [[ ----@generic T ----@param f fun():T ----@return T[] -local function x(f) end - ----@return integer -local = x(function () end) -]] - -TEST 'integer[]' [[ ----@generic T ----@param f fun(x: T) ----@return T[] -local function x(f) end - ----@type fun(x: integer) -local cb - -local = x(cb) -]] - -TEST 'integer[]' [[ ----@generic T ----@param f fun():T ----@return T[] -local function x(f) end - ----@type fun(): integer -local cb - -local = x(cb) -]] - -TEST 'integer' [[ ----@return fun(x: integer) -local function f() - return function () - end -end -]] - -TEST 'string' [[ ----@class A ----@field f fun(x: string) - ----@type A -local t = { - f = function () end -} -]] - -config.set(nil, 'Lua.runtime.special', { - ['xx.assert'] = 'assert' -}) - -TEST 'number' [[ ----@type number? -local t - -xx.assert(t) - -print() -]] - -config.set(nil, 'Lua.runtime.special', nil) - -TEST 'A' [[ ----@class A -local mt - ----@return -function mt:init() -end -]] - -TEST 'A' [[ ----@class A -local mt - ----@return self -function mt:init() -end - -local = mt:init() -]] - -TEST 'A' [[ ----@class A ----@field x -]] - -TEST 'A' [[ ----@class A ----@field x self - ----@type A -local o - -print(o.) -]] - -TEST 'A' [[ ----@class A ----@overload fun(): self -local A - -local = A() -]] - -TEST 'number' [[ ----@type table<'Test1', fun(x: number)> -local t = { - ["Test1"] = function() end, -} -]] - -TEST 'number' [[ ----@type table<5, fun(x: number)> -local t = { - [5] = function() end, -} -]] - -TEST 'number' [[ ----@type fun(x: number) -local function f() end -]] - -TEST 'boolean' [[ ----@generic T: string | boolean | table ----@param x T ----@return T -local function f(x) - return x -end - -local = f(true) -]] - -TEST 'number' [[ ----@class A ----@field [1] number ----@field [2] boolean -local t - -local = t[1] -]] - -TEST 'boolean' [[ ----@class A ----@field [1] number ----@field [2] boolean -local t - -local = t[2] -]] - -TEST 'N' [[ ----@class N: number -local x - -if x == 0.1 then - print() -end -]] - -TEST 'vec3' [[ ----@class mat4 ----@operator mul(vec3): vec3 -- matrix * vector ----@operator mul(number): mat4 -- matrix * constant - ----@class vec3: number - ----@type mat4, vec3 -local m, v - -local = m * v -]] - -TEST 'mat4' [[ ----@class mat4 ----@operator mul(number): mat4 -- matrix * constant ----@operator mul(vec3): vec3 -- matrix * vector - ----@class vec3: number - ----@type mat4, vec3 -local m, v - -local = m * v -]] - -TEST 'A|B' [[ ----@class A ----@class B - ----@type A|B -local t - -if x then - ---@cast t A -else - print() -end -]] - -TEST 'A|B' [[ ----@class A ----@class B - ----@type A|B -local t - -if x then - ---@cast t A -elseif then -end -]] - -TEST 'A|B' [[ ----@class A ----@class B - ----@type A|B -local t - -if x then - ---@cast t A - print(t) -elseif then -end -]] - -TEST 'A|B' [[ ----@class A ----@class B - ----@type A|B -local t - -if x then - ---@cast t A - print(t) -elseif then - ---@cast t A - print(t) -end -]] - -TEST 'function' [[ -local function x() - print() -end -]] - -TEST 'number' [[ ----@type number? -local x - -do - if not x then - return - end -end - -print() -]] - -TEST 'number' [[ ----@type number[] -local xs - ----@type fun(x): number? -local f - -for _, in ipairs(xs) do - x = f(x) -end -]] - -TEST 'number' [[ ----@type number? -X = Y - -if X then - print() -end -]] - -TEST 'number' [[ ----@type number|boolean -X = Y - -if type(X) == 'number' then - print() -end -]] - -TEST 'boolean' [[ ----@type number|boolean -X = Y - -if type(X) ~= 'number' then - print() -end -]] - -TEST 'boolean' [[ ----@type number -X = Y - ----@cast X boolean - -print() -]] - -TEST 'number' [[ ----@type number -local t - -if xxx == then - print(t) -end -]] - -TEST 'V' [[ ----@class V -X = 1 - -print() -]] - -TEST 'V' [[ ----@class V -X.Y = 1 - -print(X.) -]] - -TEST 'integer' [[ -local x = {} - -x.y = 1 -local y = x.y -x.y = nil - -print() -]] - -TEST 'function' [[ -function X() - () -end - -function Y() -end -]] - -TEST 'A_Class' [[ ----@class A_Class -local A = { x = 5 } - -function A:func() - for i = 1, .x do - print(i) - end - - self.y = 3 - self.y = self.y + 3 -end -]] - -TEST 'number' [[ ----@type number? -local n -local = n or error('') -]] - -TEST 'Foo' [[ ----@class Foo ----@operator mul(Foo): Foo ----@operator mul(Bar): Foo ----@class Bar - ----@type Foo -local foo - ----@type Foo|Bar -local fooOrBar - -local = foo * fooOrBar -]] - -TEST 'number' [[ -local a = 4; -local b = 2; - -local = a / b; -]] - -TEST 'string' [[ -local a = '4'; -local b = '2'; - -local = a .. b; -]] - -TEST 'number|{ [1]: string }' [[ ----@alias Some ----| { [1]: string } ----| number - -local x ---@type Some - -print() -]] - -TEST 'integer' [[ ----@class metatable : table ----@field __index table - ----@param table table ----@param metatable? metatable ----@return table -function setmetatable(table, metatable) end - -local m = setmetatable({},{ __index = { a = 1 } }) - -m. -]] - -TEST 'integer' [[ ----@class metatable : table ----@field __index table - ----@param table table ----@param metatable? metatable ----@return table -function setmetatable(table, metatable) end - -local mt = {a = 1 } -local m = setmetatable({},{ __index = mt }) - -m. -]] - -TEST 'integer' [[ -local x = 1 -repeat -until -]] - --- #2144 -TEST 'A' [=[ -local function f() - return {} --[[@as A]] -end - -local = f() -]=] - -TEST 'A' [=[ -local function f() - ---@type A - return {} -end - -local = f() -]=] - -TEST 'boolean|number' [[ ----@alias A number ----@alias(partial) A boolean - ----@type A -local -]] +require 'type_inference.common' +require 'type_inference.param_match' diff --git a/test/type_inference/param_match.lua b/test/type_inference/param_match.lua new file mode 100644 index 00000000..3bb167bc --- /dev/null +++ b/test/type_inference/param_match.lua @@ -0,0 +1,107 @@ + +TEST 'boolean' [[ +---@overload fun(x: number, y: number):string +---@overload fun(x: number):number +---@return boolean +local function f() end + +local = f() +local n2 = f(0) +local n3 = f(0, 0) +]] + +TEST 'number' [[ +---@overload fun(x: number, y: number):string +---@overload fun(x: number):number +---@return boolean +local function f() end + +local n1 = f() +local = f(0) +local n3 = f(0, 0) +]] + +TEST 'string' [[ +---@overload fun(x: number, y: number):string +---@overload fun(x: number):number +---@return boolean +local function f() end + +local n1 = f() +local n2 = f(0) +local = f(0, 0) +]] + +TEST 'boolean' [[ +---@overload fun():boolean +---@param x integer +---@return number +function f(x) +end + +local = f() +]] + +TEST 'number' [[ +---@overload fun():boolean +---@param x integer +---@return number +function f(x) +end + +local = f(1) +]] + +TEST 'boolean' [[ +---@overload fun():boolean +---@param x integer +---@return number +function f(x) +end + +function r0() + return +end + +local = f(r0()) +]] + +TEST 'number' [[ +---@overload fun():boolean +---@param x integer +---@return number +function f(x) +end + +function r1() + return 1 +end + +local = f(r1()) +]] + +TEST 'boolean' [[ +---@overload fun():boolean +---@param x integer +---@return number +function f(x) +end + +---@type fun() +local r0 + +local = f(r0()) +]] + +TEST 'number' [[ +---@overload fun():boolean +---@param x integer +---@return number +function f(x) +end + +---@type fun():integer +local r1 + +local = f(r1()) +]] -- cgit v1.2.3