diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2024-05-11 16:02:45 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2024-05-11 16:02:45 +0800 |
commit | 6fb7e1861af8d287229146c2357787c8e25b0832 (patch) | |
tree | 8d31b5e28dc554d2b0efb98e36796998653060f6 /test/type_inference/common.lua | |
parent | d6a314f694dcc1303933bbf62e7a307e3d20245c (diff) | |
download | lua-language-server-6fb7e1861af8d287229146c2357787c8e25b0832.zip |
整理代码
Diffstat (limited to 'test/type_inference/common.lua')
-rw-r--r-- | test/type_inference/common.lua | 4194 |
1 files changed, 4194 insertions, 0 deletions
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 <?t?> = nil +]] + +TEST 'string' [[ +local <?var?> = '111' +]] + +TEST 'boolean' [[ +local <?var?> = true +]] + +TEST 'integer' [[ +local <?var?> = 1 +]] + +TEST 'number' [[ +local <?var?> = 1.0 +]] + +TEST 'unknown' [[ +local <?var?> +]] + +TEST 'unknown' [[ +local <?var?> +var = y +]] + +TEST 'any' [[ +function f(<?x?>) + +end +]] + +TEST 'any' [[ +function f(<?x?>) + x = 1 +end +]] + +TEST 'string' [[ +local var = '111' +t.<?x?> = var +]] + +TEST 'string' [[ +local <?var?> +var = '111' +]] + +TEST 'string' [[ +local var +<?var?> = '111' +]] + +TEST 'string' [[ +local var +var = '111' +print(<?var?>) +]] + +TEST 'function' [[ +function <?xx?>() +end +]] + +TEST 'function' [[ +local function <?xx?>() +end +]] + +TEST 'function' [[ +local xx +<?xx?> = function () +end +]] + +TEST 'table' [[ +local <?t?> = {} +]] + +TEST 'unknown' [[ +<?x?>() +]] + +TEST 'boolean' [[ +<?x?> = not y +]] + +TEST 'integer' [[ +<?x?> = #y +]] + +TEST 'integer' [[ +<?x?> = #'aaaa' +]] + +TEST 'integer' [[ +<?x?> = #{} +]] + +TEST 'number' [[ +<?x?> = - y +]] + +TEST 'number' [[ +<?x?> = - 1.0 +]] + +TEST 'integer' [[ +<?x?> = ~ y +]] + +TEST 'integer' [[ +<?x?> = ~ 1 +]] + +TEST 'boolean' [[ +<?x?> = 1 < 2 +]] + +TEST 'integer' [[ +local a = true +local b = 1 +<?x?> = a and b +]] + +TEST 'integer' [[ +local a = false +local b = 1 +<?x?> = a or b +]] + +TEST 'boolean' [[ +<?x?> = a == b +]] + +TEST 'unknown' [[ +<?x?> = a << b +]] + +TEST 'integer' [[ +<?x?> = 1 << 2 +]] + +TEST 'unknown' [[ +<?x?> = a .. b +]] + +TEST 'string' [[ +<?x?> = 'a' .. 'b' +]] + +TEST 'string' [[ +<?x?> = 'a' .. 1 +]] + +TEST 'string' [[ +<?x?> = 'a' .. 1.0 +]] + +TEST 'unknown' [[ +<?x?> = a + b +]] + +TEST 'number' [[ +<?x?> = 1 + 2.0 +]] + +TEST 'integer' [[ +<?x?> = 1 + 2 +]] + +TEST 'integer' [[ +---@type integer +local a + +<?x?> = - a +]] + +TEST 'number' [[ +local a + +<?x?> = - a +]] + +TEST 'unknown' [[ +<?x?> = 1 + X +]] + +TEST 'unknown' [[ +<?x?> = 1.0 + X +]] + +TEST 'tablelib' [[ +---@class tablelib +table = {} + +<?table?>() +]] + +TEST 'string' [[ +_VERSION = 'Lua 5.4' + +<?x?> = _VERSION +]] + +TEST 'function' [[ +---@class stringlib +local string + +string.xxx = function () end + +return ('x').<?xxx?> +]] + +TEST 'function' [[ +---@class stringlib +String = {} + +String.xxx = function () end + +return ('x').<?xxx?> +]] + +TEST 'function' [[ +---@class stringlib +local string + +string.xxx = function () end + +<?x?> = ('x').xxx +]] + +TEST 'function' [[ +---@class stringlib +local string + +string.xxx = function () end + +_VERSION = 'Lua 5.4' + +<?x?> = _VERSION.xxx +]] + +TEST 'table' [[ +<?x?> = setmetatable({}) +]] + +TEST 'integer' [[ +local function x() + return 1 +end +<?y?> = x() +]] + +TEST 'integer|nil' [[ +local function x() + return 1 + return nil +end +<?y?> = x() +]] + +TEST 'unknown|nil' [[ +local function x() + return a + return nil +end +<?y?> = x() +]] + +TEST 'unknown|nil' [[ +local function x() + return nil + return f() +end +<?y?> = x() +]] + +TEST 'unknown|nil' [[ +local function x() + return nil + return f() +end +_, <?y?> = x() +]] + +TEST 'integer' [[ +local function x() + return 1 +end +_, <?y?> = pcall(x) +]] + +TEST 'integer' [[ +function x() + return 1 +end +_, <?y?> = pcall(x) +]] + +TEST 'integer' [[ +local function x() + return 1 +end +_, <?y?> = xpcall(x) +]] + +TEST 'A' [[ +---@class A + +---@return A +local function f2() end + +local function f() + return f2() +end + +local <?x?> = f() +]] + +-- 不根据调用者的输入参数来推测 +--TEST 'number' [[ +--local function x(a) +-- return <?a?> +--end +--x(1) +--]] + +--TEST 'table' [[ +--setmetatable(<?b?>) +--]] + +-- 不根据对方函数内的使用情况来推测 +TEST 'unknown' [[ +local function x(a) + _ = a + 1 +end +local b +x(<?b?>) +]] + +TEST 'unknown' [[ +local function x(a, ...) + local _, <?b?>, _ = ... +end +x(nil, 'xx', 1, true) +]] + +-- 引用不跨越参数 +TEST 'unknown' [[ +local function x(a, ...) + return true, 'ss', ... +end +local _, _, _, <?b?>, _ = x(nil, true, 1, 'yy') +]] + +TEST 'unknown' [[ +local <?x?> = next() +]] + +TEST 'unknown' [[ +local a, b +function a() + return b() +end +function b() + return a() +end +local <?x?> = a() +]] + +TEST 'class' [[ +---@class class +local <?x?> +]] + +TEST 'string' [[ +---@class string + +---@type string +local <?x?> +]] + +TEST '1' [[ +---@type 1 +local <?v?> +]] + +TEST 'string[]' [[ +---@class string + +---@type string[] +local <?x?> +]] + +TEST 'string|table' [[ +---@class string +---@class table + +---@type string | table +local <?x?> +]] + +TEST [['enum1'|'enum2']] [[ +---@type 'enum1' | 'enum2' +local <?x?> +]] + +TEST [["enum1"|"enum2"]] [[ +---@type "enum1" | "enum2" +local <?x?> +]] + +config.set(nil, 'Lua.hover.expandAlias', false) +TEST 'A' [[ +---@alias A 'enum1' | 'enum2' + +---@type A +local <?x?> +]] + +TEST 'A' [[ +---@alias A 'enum1' | 'enum2' | A + +---@type A +local <?x?> +]] + +TEST 'A' [[ +---@alias A 'enum1' | 'enum2' | B + +---@type A +local <?x?> +]] +config.set(nil, 'Lua.hover.expandAlias', true) +TEST [['enum1'|'enum2']] [[ +---@alias A 'enum1' | 'enum2' + +---@type A +local <?x?> +]] + +TEST [['enum1'|'enum2']] [[ +---@alias A 'enum1' | 'enum2' | A + +---@type A +local <?x?> +]] + +TEST [['enum1'|'enum2'|B]] [[ +---@alias A 'enum1' | 'enum2' | B + +---@type A +local <?x?> +]] + +TEST '1|true' [[ +---@alias A 1 | true + +---@type A +local <?x?> +]] + +TEST 'fun()' [[ +---@type fun() +local <?x?> +]] + +TEST 'fun(a: string, b: any, ...any)' [[ +---@type fun(a: string, b, ...) +local <?x?> +]] + +TEST 'fun(a: string, b: any, c?: boolean, ...any):c, d?, ...unknown' [[ +---@type fun(a: string, b, c?: boolean, ...):c, d?, ... +local <?x?> +]] + +TEST '{ [string]: string }' [[ +---@type { [string]: string } +local <?x?> +]] + +TEST 'table<string, number>' [[ +---@class string +---@class number + +---@type table<string, number> +local <?x?> +]] + +TEST 'A<string, number>' [[ +---@class A + +---@type A<string, number> +local <?x?> +]] + +TEST 'string' [[ +---@class string + +---@type string[] +local x +local <?y?> = x[1] +]] + +TEST 'string' [[ +---@class string + +---@return string[] +local function f() end +local x = f() +local <?y?> = x[1] +]] + +TEST 'table' [[ +local t = {} +local <?v?> = setmetatable(t) +]] + +TEST 'CCC' [[ +---@class CCC + +---@type table<string, CCC> +local t = {} + +print(t.<?a?>) +]] + +TEST [['aaa'|'bbb']] [[ +---@type table<string, 'aaa'|'bbb'> +local t = {} + +print(t.<?a?>) +]] + +TEST 'integer' [[ +---@generic K +---@type fun(a?: K):K +local f + +local <?n?> = f(1) +]] + +TEST 'unknown' [[ +---@generic K +---@type fun(a?: K):K +local f + +local <?n?> = f(nil) +]] + +TEST 'unknown' [[ +---@generic K +---@type fun(a: K|integer):K +local f + +local <?n?> = 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 <?i?> in ipairs() do +end +]] + +TEST 'table<string, boolean>' [[ +---@generic K, V +---@param t table<K, V> +---@return K +---@return V +local function next(t) end + +---@type table<string, boolean> +local t +local k, v = next(<?t?>) +]] + +TEST 'string' [[ +---@class string + +---@generic K, V +---@param t table<K, V> +---@return K +---@return V +local function next(t) end + +---@type table<string, boolean> +local t +local <?k?>, v = next(t) +]] + +TEST 'boolean' [[ +---@class boolean + +---@generic K, V +---@param t table<K, V> +---@return K +---@return V +local function next(t) end + +---@type table<string, boolean> +local t +local k, <?v?> = next(t) +]] + +TEST 'boolean' [[ +---@generic K +---@type fun(arg: K):K +local f + +local <?r?> = f(true) +]] + +TEST 'string' [[ +---@class string + +---@generic K, V +---@type fun(arg: table<K, V>):K, V +local f + +---@type table<string, boolean> +local t + +local <?k?>, v = f(t) +]] + +TEST 'boolean' [[ +---@class boolean + +---@generic K, V +---@type fun(arg: table<K, V>):K, V +local f + +---@type table<string, boolean> +local t + +local k, <?v?> = f(t) +]] + +TEST 'fun()' [[ +---@return fun() +local function f() end + +local <?r?> = f() +]] + +TEST 'table<string, boolean>' [[ +---@return table<string, boolean> +local function f() end + +local <?r?> = f() +]] + +TEST 'string' [[ +---@class string + +---@generic K, V +---@return fun(arg: table<K, V>):K, V +local function f() end + +local f2 = f() + +---@type table<string, boolean> +local t + +local <?k?>, v = f2(t) +]] + +TEST 'fun(a: <V>):integer, <V>' [[ +---@generic K, V +---@param a K +---@return fun(a: V):K, V +local function f(a) end + +local <?f2?> = 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 <?i?>, 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, <?v?> = f2(true) +]] + +TEST 'fun(table: table<<K>, <V>>, index?: <K>):<K>, <V>' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table<K, V>, index?: K):K, V +---@return T +---@return nil +local function pairs(t) end + +local <?next?> = pairs(dummy) +]] + +TEST 'string' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table<K, V>, index?: K):K, V +---@return T +---@return nil +local function pairs(t) end + +local next = pairs(dummy) + +---@type table<string, boolean> +local t +local <?k?>, v = next(t) +]] + +TEST 'boolean' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table<K, V>, index?: K):K, V +---@return T +---@return nil +local function pairs(t) end + +local next = pairs(dummy) + +---@type table<string, boolean> +local t +local k, <?v?> = next(t) +]] + +TEST 'string' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table<K, V>, index?: K):K, V +---@return T +---@return nil +local function pairs(t) end + +local next = pairs(dummy) + +---@type table<string, boolean> +local t +local <?k?>, v = next(t, nil) +]] + +TEST 'boolean' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table<K, V>, index?: K):K, V +---@return T +---@return nil +local function pairs(t) end + +local next = pairs(dummy) + +---@type table<string, boolean> +local t +local k, <?v?> = next(t, nil) +]] + +TEST 'string' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table<K, V>, index?: K):K, V +---@return T +---@return nil +local function pairs(t) end + +local next = pairs(dummy) + +---@type table<string, boolean> +local t + +for <?k?>, v in next, t do +end +]] + +TEST 'boolean' [[ +---@class boolean + +---@generic T: table, K, V +---@param t T +---@return fun(table: table<K, V>, index?: K):K, V +---@return T +local function pairs(t) end + +local f = pairs(t) + +---@type table<string, boolean> +local t + +for k, <?v?> in f, t do +end +]] + +TEST 'string' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table<K, V>, index?: K):K, V +---@return T +local function pairs(t) end + +---@type table<string, boolean> +local t + +for <?k?>, v in pairs(t) do +end +]] + +TEST 'boolean' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table<K, V>, index: K):K, V +---@return T +---@return nil +local function pairs(t) end + +---@type table<string, boolean> +local t + +for k, <?v?> 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 _, <?v?> 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<integer, boolean> +local t + +for _, <?v?> 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 _, <?v?> in ipairs(t) do +end +]] + +TEST 'boolean' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table<K, V>, index: K):K, V +---@return T +---@return nil +local function pairs(t) end + +---@type boolean[] +local t + +for k, <?v?> in pairs(t) do +end +]] + +TEST 'integer' [[ +---@generic T: table, K, V +---@param t T +---@return fun(table: table<K, V>, index?: K):K, V +---@return T +local function pairs(t) end + +---@type boolean[] +local t + +for <?k?>, 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 <?self?> +end +]] + +TEST 'Cls' [[ +---@class Cls +local Cls = {} + +---@generic T +---@param self T +---@return T +function Cls.new(self) return self end + +local <?test?> = Cls:new() +]] + +TEST 'Cls' [[ +---@class Cls +local Cls = {} + +---@generic T +---@param self T +---@return T +function Cls:new() return self end + +local <?test?> = Cls:new() +]] + +TEST 'Cls' [[ +---@class Cls +local Cls = {} + +---@generic T +---@param self T +---@return T +function Cls.new(self) return self end + +local <?test?> = Cls.new(Cls) +]] + +TEST 'Cls' [[ +---@class Cls +local Cls = {} + +---@generic T +---@param self T +---@return T +function Cls:new() return self end + +local <?test?> = 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 <?test?> = Rct.new(Rct) + +-- local test = Rct:new() + +return test +]] + +TEST 'function' [[ +string.gsub():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 <?t?> +]] + +config.set(nil, 'Lua.hover.enumsLimit', 1) +TEST [['a'...(+9)]] [[ +---@type 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j' +local <?t?> +]] + +config.set(nil, 'Lua.hover.enumsLimit', 0) +TEST '...(+10)' [[ +---@type 'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j' +local <?t?> +]] + +config.set(nil, 'Lua.hover.enumsLimit', 5) + +TEST 'string|fun():string' [[ +---@type string | fun(): string +local <?t?> +]] + +TEST 'string' [[ +local valids = { + ['Lua 5.1'] = false, + ['Lua 5.2'] = false, + ['Lua 5.3'] = false, + ['Lua 5.4'] = false, + ['LuaJIT'] = false, +} + +for <?k?>, 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, <?v?> in pairs(valids) do +end +]] + +TEST 'string' [[ +local t = { + a = 1, + b = 1, +} + +for <?k?>, v in pairs(t) do +end +]] + +TEST 'integer' [[ +local t = {'a', 'b'} + +for <?k?>, v in pairs(t) do +end +]] + +TEST 'string' [[ +local t = {'a', 'b'} + +for k, <?v?> in pairs(t) do +end +]] + +TEST 'fun():number, boolean' [[ +---@type fun():number, boolean +local <?t?> +]] + + +TEST 'fun(value: Class)' [[ +---@class Class + +---@param callback fun(value: Class) +function work(callback) +end + +work(<?function?> (value) +end) +]] + +TEST 'Class' [[ +---@class Class + +---@param callback fun(value: Class) +function work(callback) +end + +work(function (<?value?>) +end) +]] + +TEST 'fun(value: Class)' [[ +---@class Class + +---@param callback fun(value: Class) +function work(callback) +end + +pcall(work, <?function?> (value) +end) +]] + +TEST 'Class' [[ +---@class Class + +---@param callback fun(value: Class) +function work(callback) +end + +xpcall(work, debug.traceback, function (<?value?>) +end) +]] + +TEST 'string' [[ +---@generic T +---@param x T +---@return { x: T } +local function f(x) end + +local t = f('') + +print(t.<?x?>) +]] + +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 (<?v?>) end) +]] + +TEST 'unknown' [[ +---@generic T +---@param t T[] +---@param callback fun(v: T) +local function f(t, callback) end + +local t = {} + +f(t, function (<?v?>) end) +]] + +TEST 'table' [[ +local <?t?> = setmetatable({}, { __index = function () end }) +]] + +TEST 'player' [[ +---@class player +local t + +<?t?>:getOwner() +]] + +TEST 'string[][]' [[ +---@type string[][] +local <?t?> +]] + +TEST 'table' [[ +---@type {}[] +local t + +local <?v?> = t[1] +]] + +TEST 'string' [[ +---@type string[][] +local v = {} + +for _, a in ipairs(v) do + for i, <?b?> in ipairs(a) do + end +end +]] + +--TEST 'number' [[ +-----@param x number +--local f +-- +--f = function (<?x?>) 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", <?function?> (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 (<?i?>) +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 (<?i?>) +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 (<?i?>) +end) +]] + +TEST '👍' [[ +---@class 👍 +local <?x?> +]] + +TEST 'integer' [[ +---@type boolean +local x + +<?x?> = 1 +]] + +TEST 'integer' [[ +---@class Class +local x + +<?x?> = 1 +]] + +TEST 'unknown' [[ +---@return number +local function f(x) + local <?y?> = x() +end +]] + +TEST 'unknown' [[ +local mt + +---@return number +function mt:f() end + +local <?v?> = mt() +]] + +TEST 'unknown' [[ +local <?mt?> + +---@class X +function mt:f(x) end +]] + +TEST 'any' [[ +local mt + +---@class X +function mt:f(<?x?>) end +]] + +TEST 'unknown' [[ +local <?mt?> + +---@type number +function mt:f(x) end +]] + +TEST 'any' [[ +local mt + +---@type number +function mt:f(<?x?>) end +]] + +TEST 'Test' [[ +---@class Test +_G.<?Test?> = {} +]] + +TEST 'integer' [[ +local mt = {} + +---@param callback fun(i: integer) +function mt:loop(callback) end + +mt:loop(function (<?i?>) + +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 { + <?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 { + d = { + <?y?> = , + } +} +]] + +TEST 'integer' [[ +for <?i?> = a, b, c do end +]] + +TEST 'number' [[ +---@param x number +function F(<?x?>) 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 <?v?> = t.x() +]] + +TEST 'function' [[ +---@overload fun() +function <?f?>() end +]] + +TEST 'integer' [[ +---@type table<string, integer> +local t + +t.<?a?> +]] + +TEST '"a"|"b"|"c"' [[ +---@type table<string, "a"|"b"|"c"> +local t + +t.<?a?> +]] + +TEST 'integer' [[ +---@class A +---@field x integer + +---@type A +local t +t.<?x?> +]] + +TEST 'boolean' [[ +local <?var?> = true +var = 1 +var = 1.0 +]] + +TEST 'unknown' [[ +---@return ... +local function f() end + +local <?x?> = f() +]] + +TEST 'unknown' [[ +---@return ... +local function f() end + +local _, <?x?> = f() +]] + +TEST 'unknown' [[ +local t = { + x = 1, + y = 2, +} + +local <?x?> = t[#t] +]] + +TEST 'string' [[ +local t = { + x = 1, + [1] = 'x', +} + +local <?x?> = t[#t] +]] + +TEST 'string' [[ +local t = { 'x' } + +local <?x?> = t[#t] +]] + +TEST '(string|integer)[]' [[ +---@type (string|integer)[] +local <?x?> +]] + +TEST 'boolean' [[ +---@type table<string, boolean> +local t + +---@alias uri string + +---@type string +local uri + +local <?v?> = t[uri] +]] + +TEST 'A' [[ +---@class A +G = {} + +<?G?>:A() +]] + +TEST 'A' [[ +---@type A +local <?x?> = nil +]] + +TEST 'A' [[ +---@class A +---@field b B +local mt + +function mt:f() + self.b:x() + print(<?self?>) +end +]] + +TEST 'string?' [[ +---@return string? +local function f() end + +local <?x?> = f() +]] + +TEST 'AA' [[ +---@class AA +---@overload fun():AA +local AAA + + +local <?x?> = AAA() +]] + +TEST 'AA' [[ +---@class AA +---@overload fun():AA +AAA = {} + + +local <?x?> = AAA() +]] + +TEST 'string' [[ +local <?x?> +x = '1' +x = 1 +]] + +TEST 'string' [[ +local x +<?x?> = '1' +x = 1 +]] + +TEST 'integer' [[ +local x +x = '1' +<?x?> = 1 +]] + +TEST 'unknown' [[ +local x +print(<?x?>) +x = '1' +x = 1 +]] + +TEST 'string' [[ +local x +x = '1' +print(<?x?>) +x = 1 +]] + +TEST 'integer' [[ +local x +x = '1' +x = 1 +print(<?x?>) +]] + +TEST 'unknown' [[ +local x + +function A() + print(<?x?>) +end +]] + +TEST 'string' [[ +local x + +function A() + print(<?x?>) +end + +x = '1' +x = 1 +]] + +TEST 'string' [[ +local x + +x = '1' + +function A() + print(<?x?>) +end + +x = 1 +]] + +TEST 'integer' [[ +local x + +x = '1' +x = 1 + +function A() + print(<?x?>) +end + +]] + +TEST 'boolean' [[ +local x + +function A() + x = true + print(<?x?>) +end + +x = '1' +x = 1 +]] + +TEST 'unknown' [[ +local x + +function A() + x = true +end + +print(<?x?>) +x = '1' +x = 1 +]] + +TEST 'boolean' [[ +local x + +function A() + x = true + function B() + print(<?x?>) + end +end + +x = '1' +x = 1 +]] + +TEST 'table' [[ +local x + +function A() + x = true + function B() + x = {} + print(<?x?>) + end +end + +x = '1' +x = 1 +]] + +TEST 'boolean' [[ +local x + +function A() + x = true + function B() + x = {} + end + print(<?x?>) +end + +x = '1' +x = 1 +]] + +TEST 'unknown' [[ +local x + +function A() + x = true + function B() + x = {} + end +end + +function C() + print(<?x?>) +end + +x = '1' +x = 1 +]] + +TEST 'integer' [[ +local x +x = true +do + x = 1 +end +print(<?x?>) +]] + +TEST 'boolean' [[ +local x +x = true +function XX() + do + x = 1 + end +end +print(<?x?>) +]] + +TEST 'integer?' [[ +---@type integer? +local <?x?> +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if <?x?> 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(<?x?>) +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if x then + print(x) +end + +print(<?x?>) +]] + +TEST 'nil' [[ +---@type integer? +local x + +if not x then + print(<?x?>) +end + +print(x) +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not x then + x = 1 +end + +print(<?x?>) +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not x then + return +end + +print(<?x?>) +]] + +TEST 'integer' [[ +---@type integer? +local x + +if xxx and x then + print(<?x?>) +end +]] + +TEST 'unknown' [[ +---@type integer? +local x + +if not x and x then + print(<?x?>) +end +]] + +TEST 'integer' [[ +---@type integer? +local x + +if x and not mark[x] then + print(<?x?>) +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if xxx and x then +end + +print(<?x?>) +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if xxx and x then + return +end + +print(<?x?>) +]] + +TEST 'integer' [[ +---@type integer? +local x + +if x ~= nil then + print(<?x?>) +end + +print(x) +]] + +TEST 'integer|nil' [[ +---@type integer? +local x + +if x ~= nil then + print(x) +end + +print(<?x?>) +]] + +TEST 'nil' [[ +---@type integer? +local x + +if x == nil then + print(<?x?>) +end + +print(x) +]] + +TEST 'integer|nil' [[ +---@type integer? +local x + +if x == nil then + print(x) +end + +print(<?x?>) +]] + +TEST 'integer' [[ +---@type integer? +local x + +<?x?> = x or 1 +]] + +TEST 'integer' [[ +---@type integer? +local x + +<?x?> = x or y +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not x then + return +end + +print(<?x?>) +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not x then + goto ANYWHERE +end + +print(<?x?>) +]] + +TEST 'integer' [=[ +local x + +print(<?x?>--[[@as integer]]) +]=] + +TEST 'integer' [=[ +print(<?io?>--[[@as integer]]) +]=] + +TEST 'integer' [=[ +print(io.<?open?>--[[@as integer]]) +]=] + +TEST 'integer' [=[ +local <?x?> = io['open']--[[@as integer]]) +]=] + +TEST 'integer' [=[ +local <?x?> = 1 + 1--[[@as integer]]) +]=] + +TEST 'integer' [=[ +local <?x?> = not 1--[[@as integer]]) +]=] + +TEST 'integer' [=[ +local <?x?> = ()--[[@as integer]]) +]=] + +TEST 'integer?' [[ +---@param x? integer +local function f(<?x?>) + +end +]] + +TEST 'integer' [[ +local x = 1 +x = <?x?> +]] + +TEST 'integer?' [[ +---@class A +---@field x? integer +local t + +t.<?x?> +]] + +TEST 'integer?' [[ +---@type { x?: integer } +local t + +t.<?x?> +]] + +TEST 'boolean' [[ +---@class A +---@field [integer] boolean +local t + +local <?x?> = t[1] +]] + +TEST 'unknown' [[ +local <?x?> = y and z +]] + +TEST 'integer' [[ +---@type integer? +local x + +assert(x) + +print(<?x?>) +]] + +TEST 'integer' [[ +---@type integer? +local x + +assert(x ~= nil) + +print(<?x?>) +]] + +TEST 'integer' [[ +---@type integer | nil +local x + +assert(x) + +print(<?x?>) +]] + +TEST 'integer' [[ +---@type integer | nil +local x + +assert(x ~= nil) + +print(<?x?>) +]] + +TEST 'integer' [[ +local x + +assert(x == 1) + +print(<?x?>) +]] + +TEST 'integer' [[ +---@type integer? +local x + +if x and <?x?>.y then +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if x and x.y then +end + +print(<?x?>) +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if x and x.y then + return +end + +print(<?x?>) +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not x or <?x?>.y then +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if not x or x.y then + print(<?x?>) +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if x or x.y then + print(<?x?>) +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if x.y or x then + print(<?x?>) +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +if x.y or not x then + print(<?x?>) +end +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not x or not y then + return +end + +print(<?x?>) +]] + +TEST 'integer' [[ +---@type integer? +local x + +if not y or not x then + return +end + +print(<?x?>) +]] + +TEST 'integer' [[ +---@type integer? +local x + +while true do + if not x then + break + end + print(<?x?>) +end +]] + +TEST 'integer?' [[ +---@type integer? +local x + +while true do + if not x then + break + end +end + +print(<?x?>) +]] + +TEST 'integer' [[ +---@type integer? +local x + +while x do + print(<?x?>) +end +]] + +TEST 'integer' [[ +---@type fun():integer? +local iter + +for <?x?> in iter do +end +]] + +TEST 'integer' [[ +local x + +---@type integer +<?x?> = XXX +]] + +TEST 'unknown' [[ +for _ = 1, 999 do + local <?x?> +end +]] + +TEST 'integer' [[ +local x + +---@cast x integer + +print(<?x?>) +]] + +TEST 'unknown' [[ +local x + +---@cast x integer + +local x +print(<?x?>) +]] + +TEST 'unknown' [[ +local x + +if true then + local x + ---@cast x integer + print(x) +end + +print(<?x?>) +]] + +TEST 'boolean|integer' [[ +local x = 1 + +---@cast x +boolean + +print(<?x?>) +]] + +TEST 'boolean' [[ +---@type integer|boolean +local x + +---@cast x -integer + +print(<?x?>) +]] + +TEST 'boolean?' [[ +---@type boolean +local x + +---@cast x +? + +print(<?x?>) +]] + +TEST 'boolean' [[ +---@type boolean? +local x + +---@cast x -? + +print(<?x?>) +]] + +TEST 'nil' [[ +---@type string? +local x + +if x then + return +else + print(<?x?>) +end + +print(x) +]] + +TEST 'string' [[ +---@type string? +local x + +if not x then + return +else + print(<?x?>) +end + +print(x) +]] + +TEST 'string' [[ +---@type string? +local x + +if not x then + return +else + print(x) +end + +print(<?x?>) +]] + +TEST 'true' [[ +---@type boolean | nil +local x + +if not x then + return +end + +print(<?x?>) +]] + +TEST 'true' [[ +---@type boolean +local t + +if t then + print(<?t?>) + return +end + +print(t) +]] + +TEST 'false' [[ +---@type boolean +local t + +if t then + print(t) + return +end + +print(<?t?>) +]] + +TEST 'nil' [[ +---@type integer? +local t + +if t then +else + print(<?t?>) +end + +print(t) +]] + +TEST 'table' [[ +local function f() + if x then + return y + end + return {} +end + +local <?z?> = f() +]] + +TEST 'integer|table' [[ +local function returnI() + return 1 +end + +local function f() + if x then + return returnI() + end + return {} +end + +local <?z?> = f() +]] + +TEST 'number' [[ +for _ in _ do + ---@type number + local <?x?> +end +]] + +TEST 'unknown' [[ +for _ in _ do + ---@param x number + local <?x?> +end +]] + +TEST 'unknown' [[ +---@type number +for <?x?> in _ do +end +]] + +TEST 'number' [[ +---@param x number +for <?x?> in _ do +end +]] + +TEST 'table' [[ +---@alias tp table + +---@type tp +local <?x?> +]] + +TEST '{ name: boolean }' [[ +---@alias tp {name: boolean} + +---@type tp +local <?x?> +]] + +TEST 'boolean|{ name: boolean }' [[ +---@alias tp boolean | {name: boolean} + +---@type tp +local <?x?> +]] + +TEST '`1`|`true`' [[ +---@type `1` | `true` +local <?x?> +]] + +TEST 'function' [[ +local x + +function x() end + +print(<?x?>) +]] + +TEST 'unknown' [[ +local x + +if x.field == 'haha' then + print(<?x?>) +end +]] + +TEST 'string' [[ +---@type string? +local t + +if not t or xxx then + return +end + +print(<?t?>) +]] + +TEST 'table' [[ +---@type table|nil +local t + +return function () + if not t then + return + end + + print(<?t?>) +end +]] + +TEST 'table' [[ +---@type table|nil +local t + +f(function () + if not t then + return + end + + print(<?t?>) +end) +]] + +TEST 'table' [[ +---@type table? +local t + +t = t or {} + +print(<?t?>) +]] + +TEST 'unknown|nil' [[ +local x + +if x == nil then +end + +print(<?x?>) +]] + +TEST 'table<xxx, true>' [[ +---@alias xxx table<xxx, true> + +---@type xxx +local <?t?> +]] + +TEST 'xxx[][]' [[ +---@alias xxx xxx[] + +---@type xxx +local <?t?> +]] + +TEST 'fun(x: fun(x: xxx))' [[ +---@alias xxx fun(x: xxx) + +---@type xxx +local <?t?> +]] + +TEST 'table' [[ +---@type table|nil +local t + +while t do + print(<?t?>) +end +]] + +TEST 'table|nil' [[ +---@type table|nil +local t + +while <?t?> do + print(t) +end +]] + +TEST 'table' [[ +---@type table|nil +local t + +while t ~= nil do + print(<?t?>) +end +]] + +TEST 'table|nil' [[ +---@type table|nil +local t + +while <?t?> ~= nil do + print(t) +end +]] + +TEST 'integer' [[ +---@type integer? +local n + +if not n then + error('n is nil') +end + +print(<?n?>) +]] + +TEST 'integer' [[ +---@type integer? +local n + +if not n then + os.exit() +end + +print(<?n?>) +]] + +TEST 'table' [[ +---@type table? +local n + +print((n and <?n?>.x)) +]] + +TEST 'table' [[ +---@type table? +local n + +n = n and <?n?>.x or 1 +]] + +TEST 'table' [[ +---@type table? +local n + +n = ff[n and <?n?>.x] +]] + +TEST 'integer' [[ +local x + +if type(x) == 'integer' then + print(<?x?>) +end +]] + +TEST 'boolean|integer' [[ +local x + +if type(x) == 'integer' +or type(x) == 'boolean' then + print(<?x?>) +end +]] + +TEST 'fun()' [[ +---@type fun()? +local x + +if type(x) == 'function' then + print(<?x?>) +end +]] + +TEST 'function' [[ +local x + +if type(x) == 'function' then + print(<?x?>) +end +]] + +TEST 'integer' [[ +local x +local tp = type(x) + +if tp == 'integer' then + print(<?x?>) +end +]] + +TEST 'integer' [[ +---@type integer? +local x + +if (x == nil) then +else + print(<?x?>) +end +]] + +TEST 'B' [[ +---@class A +---@class B + +---@type A +local x + +---@type B +x = call(x) + +print(<?x?>) +]] + +TEST 'nil' [[ +local function f() +end + +local <?x?> = f() +]] + +TEST 'integer[]' [[ +---@type integer[] +local x +if not x then + return +end + +print(<?x?>) +]] + +TEST 'unknown' [[ +---@type string[] +local t + +local <?x?> = t.x +]] + +TEST 'integer|unknown' [[ +local function f() + return GG +end + +local t + +t.x = 1 +t.x = f() + +print(t.<?x?>) +]] + +TEST 'integer' [[ +local function f() + if X then + return X + else + return 1 + end +end + +local <?n?> = f() +]] + +TEST 'unknown' [[ +local function f() + return t[k] +end + +local <?n?> = f() +]] + +TEST 'integer|nil' [[ +local function f() + if x then + return + else + return 1 + end +end + +local <?n?> = f() +]] + +TEST 'integer' [[ +---@class A +---@field x integer +local m + +m.<?x?> = true + +print(m.x) +]] + +TEST 'integer' [[ +---@class A +---@field x integer +local m + +m.x = true + +print(m.<?x?>) +]] + +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.<?x?>) +]] + +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.<?x?>) +]] + +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.<?x?>) +]] + +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.<?x?>) +]] + +TEST 'boolean?' [[ +---@generic T +---@param x T +---@return T +local function echo(x) end + +---@type boolean? +local b + +local <?x?> = echo(b) +]] + +TEST 'boolean' [[ +---@generic T +---@param x T? +---@return T +local function echo(x) end + +---@type boolean? +local b + +local <?x?> = echo(b) +]] + +TEST 'boolean' [[ +---@generic T +---@param x? T +---@return T +local function echo(x) end + +---@type boolean? +local b + +local <?x?> = echo(b) +]] + +TEST 'boolean' [[ +---@type {[integer]: boolean, xx: integer} +local t + +local <?n?> = t[1] +]] + +TEST 'boolean' [[ +---@type integer +local i + +---@type {[integer]: boolean, xx: integer} +local t + +local <?n?> = t[i] +]] + +TEST 'string' [=[ +local x = true +local y = x--[[@as integer]] --is `integer` here +local z = <?x?>--[[@as string]] --is `true` here +]=] + +TEST 'integer' [[ +---@type integer +local x + +if type(x) == 'number' then + print(<?x?>) +end +]] + +TEST 'boolean' [[ +---@class A +---@field [integer] boolean +local mt + +function mt:f() + ---@type integer + local index + local <?x?> = self[index] +end +]] + +TEST 'boolean' [[ +---@class A +---@field [B] boolean + +---@class B + +---@type A +local a + +---@type B +local b + +local <?x?> = a[b] +]] + +TEST 'number' [[ +---@type {x: string ; y: boolean; z: number} +local t + +local <?z?> = t.z +]] + +TEST 'fun():number, boolean' [[ +---@type {f: fun():number, boolean} +local t + +local <?f?> = t.f +]] + +TEST 'fun():number' [[ +---@type {(f: fun():number), x: boolean} +local t + +local <?f?> = t.f +]] + +TEST 'boolean' [[ +---@param ... boolean +local function f(...) + local <?n?> = ... +end +]] + +TEST 'boolean' [[ +---@param ... boolean +local function f(...) + local _, <?n?> = ... +end +]] + +TEST 'boolean' [[ +---@return boolean ... +local function f() end + +local <?n?> = f() +]] + +TEST 'boolean' [[ +---@return boolean ... +local function f() end + +local _, <?n?> = f() +]] + +TEST 'boolean' [[ +---@type fun():name1: boolean, name2:number +local f + +local <?n?> = f() +]] + +TEST 'number' [[ +---@type fun():name1: boolean, name2:number +local f + +local _, <?n?> = f() +]] +TEST 'boolean' [[ +---@type fun():(name1: boolean, name2:number) +local f + +local <?n?> = f() +]] + +TEST 'number' [[ +---@type fun():(name1: boolean, name2:number) +local f + +local _, <?n?> = f() +]] + +TEST 'boolean' [[ +---@type fun():...: boolean +local f + +local _, <?n?> = f() +]] + +TEST 'string' [[ +local s +while true do + s = '' +end +print(<?s?>) +]] + +TEST 'string' [[ +local s +for _ in _ do + s = '' +end +print(<?s?>) +]] + +TEST 'A' [[ +---@class A: string + +---@type A +local <?s?> = '' +]] + +TEST 'number' [[ +---@return number +local function f() end +local x, <?y?> = 1, f() +]] + +TEST 'boolean' [[ +---@return number, boolean +local function f() end +local x, y, <?z?> = 1, f() +]] + +TEST 'number' [[ +---@return number, boolean +local function f() end +local x, y, <?z?> = 1, 2, f() +]] + +TEST 'unknown' [[ +local f + +print(<?f?>) + +function f() end +]] + +TEST 'unknown' [[ +local f + +do + print(<?f?>) +end + +function f() end +]] + +TEST 'function' [[ +local f + +function A() + print(<?f?>) +end + +function f() end +]] + +TEST 'number' [[ +---@type number|nil +local n + +local t = { + x = n and <?n?>, +} +]] + +TEST 'table' [[ +---@type table? +local n + +if not n or not <?n?>.x then +end +]] + +TEST 'table' [[ +---@type table? +local n + +if not n or not <?n?>[1] then +end +]] + +TEST 'number' [[ +---@type number|false +local n + +---@cast n -false + +print(<?n?>) +]] + +TEST 'table' [[ +---@type number|table +local n + +if n +---@cast n table +and <?n?>.type == 'xxx' then +end +]] + +TEST 'integer' [[ +---@type integer? +local n +if true then + n = 0 +end +local <?x?> = n or 0 +]] + +TEST 'number' [=[ +local <?x?> = F()--[[@as number]] +]=] + +TEST 'number' [=[ +local function f() + return F()--[[@as number]] +end + +local <?x?> = f() +]=] + +TEST 'number' [=[ +local <?x?> = X --[[@as number]] +]=] + +TEST 'number' [[ +---@return number?, number? +local function f() end + +for <?x?>, y in f do +end +]] + +TEST 'number' [[ +---@return number?, number? +local function f() end + +for x, <?y?> in f do +end +]] + +TEST 'number|nil' [[ +---@type table|nil +local a + +---@type number|nil +local b + +local <?c?> = a and b +]] + +TEST 'number|table|nil' [[ +---@type table|nil +local a + +---@type number|nil +local b + +local <?c?> = a or b +]] + +TEST 'number|table|nil' [[ +---@type table|nil +local a + +---@type number|nil +local b + +local c = a and b +local <?d?> = a or b +]] + +TEST 'number' [[ +local x + +---@return number +local function f() +end + +x = f() + +print(<?x?>) +]] + +TEST 'number' [[ +local x + +---@return number +local function f() +end + +_, x = pcall(f) + +print(<?x?>) +]] + +TEST 'string' [[ +---@type table<string|number, string> +local t + +---@type number +local n +---@type string +local s + +local <?test?> = t[n] +local test2 = t[s] --test and test2 are unknow +]] + +TEST 'string' [[ +---@type table<string|number, string> +local t + +---@type number +local n +---@type string +local s + +local test = t[n] +local <?test2?> = t[s] --test and test2 are unknow +]] + +TEST 'table<number, boolean>' [[ +---@type table<number, boolean> +local t + +<?t?> = {} +]] + +TEST 'integer' [[ +---@type integer[]|A +local t + +local <?x?> = t[1] +]] + +TEST 'integer' [[ +---@type integer +---@diagnostic disable +local <?t?> +]] + +TEST 'A' [[ +---@class A +---@diagnostic disable +local <?t?> +]] + +TEST '{ [string]: number, [true]: string, [1]: boolean, tag: integer }' [[ +---@type {[string]: number, [true]: string, [1]: boolean, tag: integer} +local <?t?> +]] + +TEST 'unknown' [[ +local mt = {} +mt.<?x?> = nil +]] + +TEST 'unknown' [[ +mt = {} +mt.<?x?> = nil +]] + +TEST 'A' [[ +---@class A +---@operator unm: A + +---@type A +local a +local <?b?> = -a +]] + +TEST 'A' [[ +---@class A +---@operator bnot: A + +---@type A +local a +local <?b?> = ~a +]] + +TEST 'A' [[ +---@class A +---@operator len: A + +---@type A +local a +local <?b?> = #a +]] + +TEST 'A' [[ +---@class A +---@operator add: A + +---@type A +local a +local <?b?> = a + 1 +]] + +TEST 'A' [[ +---@class A +---@operator sub: A + +---@type A +local a +local <?b?> = a - 1 +]] + +TEST 'A' [[ +---@class A +---@operator mul: A + +---@type A +local a +local <?b?> = a * 1 +]] + +TEST 'A' [[ +---@class A +---@operator div: A + +---@type A +local a +local <?b?> = a / 1 +]] + +TEST 'A' [[ +---@class A +---@operator mod: A + +---@type A +local a +local <?b?> = a % 1 +]] + +TEST 'A' [[ +---@class A +---@operator pow: A + +---@type A +local a +local <?b?> = a ^ 1 +]] + +TEST 'A' [[ +---@class A +---@operator idiv: A + +---@type A +local a +local <?b?> = a // 1 +]] + +TEST 'A' [[ +---@class A +---@operator band: A + +---@type A +local a +local <?b?> = a & 1 +]] + +TEST 'A' [[ +---@class A +---@operator bor: A + +---@type A +local a +local <?b?> = a | 1 +]] + +TEST 'A' [[ +---@class A +---@operator bxor: A + +---@type A +local a +local <?b?> = a ~ 1 +]] + +TEST 'A' [[ +---@class A +---@operator shl: A + +---@type A +local a +local <?b?> = a << 1 +]] + +TEST 'A' [[ +---@class A +---@operator shr: A + +---@type A +local a +local <?b?> = a >> 1 +]] + +TEST 'A' [[ +---@class A +---@operator concat: A + +---@type A +local a +local <?b?> = a .. 1 +]] + +TEST 'A' [[ +---@class A +---@operator add(boolean): boolean +---@operator add(integer): A + +---@type A +local a +local <?b?> = a + 1 +]] + +TEST 'boolean' [[ +---@class A +---@operator add(boolean): boolean +---@operator add(integer): A + +---@type A +local a +local <?b?> = a + true +]] + +TEST 'A' [[ +---@class A +---@operator call: A + +---@type A +local a +local <?b?> = a() +]] + +TEST 'A' [[ +---@class A +---@operator call: A + +---@type A +local a + +local t = { + <?x?> = a(), +} +]] + +TEST 'boolean' [[ +---@class A +---@field n number +---@field [string] boolean +local t + +local <?x?> = t.xx +]] + +TEST 'number' [[ +---@class A +---@field n number +---@field [string] boolean +local t + +local <?x?> = t.n +]] + +TEST 'string' [[ +---@class string +---@operator mod: string + +local <?b?> = '' % 1 +]] + +TEST 'string|integer' [[ +---@type boolean +local bool + +local <?x?> = bool and '' or 0 +]] + +TEST 'string|integer' [[ +local bool + +if X then + bool = true +else + bool = false +end + +local <?x?> = bool and '' or 0 +]] + +TEST 'boolean' [[ +---@type boolean|true|false +local <?b?> +]] + +TEST 'integer|false' [[ +local <?b?> = X == 1 and X == 1 and 1 +]] + +TEST 'unknown|nil' [[ +local function f() + if X then + return ({})[1] + end + return nil +end + +local <?n?> = f() +]] + +TEST 'integer' [[ +---@generic T +---@vararg T # ERROR +---@return T +local function test(...) + return ... +end + +local <?n?> = test(1) +]] + +TEST 'boolean' [[ +---@type boolean, number +local <?x?>, y +]] + +TEST 'number' [[ +---@type boolean, number +local x, <?y?> +]] + +TEST 'unknown' [[ +---@type _, number +local <?x?>, y +]] + +TEST 'number[]' [[ +local t +---@cast t number[]? + +local x = t and <?t?>[i] +]] + +TEST 'number?' [[ +---@type number[]? +local t + +local <?x?> = t and t[i] +]] + +TEST 'number' [[ +---@type number +local x + +if not <?x?>.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(<?x?>) +]] + +TEST 'integer' [[ +local A = { + ---@class XXX + B = {} +} + +A.B.C = 1 + +print(A.B.<?C?>) +]] + +TEST '-2|-3|1' [[ +---@type 1|-2|-3 +local <?n?> +]] + +TEST 'table' [[ +---@enum A +local m = {} + +print(<?m?>) +]] + +TEST 'A' [[ +---@class A +---@overload fun():A +local m = {} + +---@return A +function m:init() + return <?self?> +end +]] + +TEST 'string' [[ +---@vararg string +function F(...) + local t = {...} + for k, <?v?> in pairs(t) do + end +end +]] + +TEST 'string' [[ +---@vararg string +function F(...) + local t = {...} + for k, <?v?> in ipairs(t) do + end +end +]] + +TEST 'integerA' [[ +---@type integerA +for <?i?> = 1, 10 do +end +]] + +TEST 'string' [[ +---@class A +---@field x string + +---@class B : A +local t = {} + +t.x = t.x + +print(t.<?x?>) +]] + +TEST 'unknown' [[ +local t = { + x = 1, +} + +local x + +local <?v?> = t[x] +]] + +TEST 'A|B' [[ +---@class A +---@class B: A + +---@type A|B +local <?t?> +]] + +TEST 'function' [[ +---@class myClass +local myClass = { has = { nested = {} } } + +function myClass.has.nested.fn() end + +---@type myClass +local class + +class.has.nested.<?fn?>() +]] + +TEST 'integer[]' [[ +---@generic T +---@param f fun(x: T) +---@return T[] +local function x(f) end + +---@param x integer +local <?arr?> = x(function (x) end) +]] + +TEST 'integer[]' [[ +---@generic T +---@param f fun():T +---@return T[] +local function x(f) end + +local <?arr?> = x(function () + return 1 +end) +]] + +TEST 'integer[]' [[ +---@generic T +---@param f fun():T +---@return T[] +local function x(f) end + +---@return integer +local <?arr?> = 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 <?arr?> = x(cb) +]] + +TEST 'integer[]' [[ +---@generic T +---@param f fun():T +---@return T[] +local function x(f) end + +---@type fun(): integer +local cb + +local <?arr?> = x(cb) +]] + +TEST 'integer' [[ +---@return fun(x: integer) +local function f() + return function (<?x?>) + end +end +]] + +TEST 'string' [[ +---@class A +---@field f fun(x: string) + +---@type A +local t = { + f = function (<?x?>) end +} +]] + +config.set(nil, 'Lua.runtime.special', { + ['xx.assert'] = 'assert' +}) + +TEST 'number' [[ +---@type number? +local t + +xx.assert(t) + +print(<?t?>) +]] + +config.set(nil, 'Lua.runtime.special', nil) + +TEST 'A' [[ +---@class A +local mt + +---@return <?self?> +function mt:init() +end +]] + +TEST 'A' [[ +---@class A +local mt + +---@return self +function mt:init() +end + +local <?o?> = mt:init() +]] + +TEST 'A' [[ +---@class A +---@field x <?self?> +]] + +TEST 'A' [[ +---@class A +---@field x self + +---@type A +local o + +print(o.<?x?>) +]] + +TEST 'A' [[ +---@class A +---@overload fun(): self +local A + +local <?o?> = A() +]] + +TEST 'number' [[ +---@type table<'Test1', fun(x: number)> +local t = { + ["Test1"] = function(<?x?>) end, +} +]] + +TEST 'number' [[ +---@type table<5, fun(x: number)> +local t = { + [5] = function(<?x?>) end, +} +]] + +TEST 'number' [[ +---@type fun(x: number) +local function f(<?x?>) end +]] + +TEST 'boolean' [[ +---@generic T: string | boolean | table +---@param x T +---@return T +local function f(x) + return x +end + +local <?x?> = f(true) +]] + +TEST 'number' [[ +---@class A +---@field [1] number +---@field [2] boolean +local t + +local <?n?> = t[1] +]] + +TEST 'boolean' [[ +---@class A +---@field [1] number +---@field [2] boolean +local t + +local <?n?> = t[2] +]] + +TEST 'N' [[ +---@class N: number +local x + +if x == 0.1 then + print(<?x?>) +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 <?r?> = 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 <?r?> = m * v +]] + +TEST 'A|B' [[ +---@class A +---@class B + +---@type A|B +local t + +if x then + ---@cast t A +else + print(<?t?>) +end +]] + +TEST 'A|B' [[ +---@class A +---@class B + +---@type A|B +local t + +if x then + ---@cast t A +elseif <?t?> then +end +]] + +TEST 'A|B' [[ +---@class A +---@class B + +---@type A|B +local t + +if x then + ---@cast t A + print(t) +elseif <?t?> then +end +]] + +TEST 'A|B' [[ +---@class A +---@class B + +---@type A|B +local t + +if x then + ---@cast t A + print(t) +elseif <?t?> then + ---@cast t A + print(t) +end +]] + +TEST 'function' [[ +local function x() + print(<?x?>) +end +]] + +TEST 'number' [[ +---@type number? +local x + +do + if not x then + return + end +end + +print(<?x?>) +]] + +TEST 'number' [[ +---@type number[] +local xs + +---@type fun(x): number? +local f + +for _, <?x?> in ipairs(xs) do + x = f(x) +end +]] + +TEST 'number' [[ +---@type number? +X = Y + +if X then + print(<?X?>) +end +]] + +TEST 'number' [[ +---@type number|boolean +X = Y + +if type(X) == 'number' then + print(<?X?>) +end +]] + +TEST 'boolean' [[ +---@type number|boolean +X = Y + +if type(X) ~= 'number' then + print(<?X?>) +end +]] + +TEST 'boolean' [[ +---@type number +X = Y + +---@cast X boolean + +print(<?X?>) +]] + +TEST 'number' [[ +---@type number +local t + +if xxx == <?t?> then + print(t) +end +]] + +TEST 'V' [[ +---@class V +X = 1 + +print(<?X?>) +]] + +TEST 'V' [[ +---@class V +X.Y = 1 + +print(X.<?Y?>) +]] + +TEST 'integer' [[ +local x = {} + +x.y = 1 +local y = x.y +x.y = nil + +print(<?y?>) +]] + +TEST 'function' [[ +function X() + <?Y?>() +end + +function Y() +end +]] + +TEST 'A_Class' [[ +---@class A_Class +local A = { x = 5 } + +function A:func() + for i = 1, <?self?>.x do + print(i) + end + + self.y = 3 + self.y = self.y + 3 +end +]] + +TEST 'number' [[ +---@type number? +local n +local <?v?> = 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 <?b?> = foo * fooOrBar +]] + +TEST 'number' [[ +local a = 4; +local b = 2; + +local <?c?> = a / b; +]] + +TEST 'string' [[ +local a = '4'; +local b = '2'; + +local <?c?> = a .. b; +]] + +TEST 'number|{ [1]: string }' [[ +---@alias Some +---| { [1]: string } +---| number + +local x ---@type Some + +print(<?x?>) +]] + +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.<?a?> +]] + +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.<?a?> +]] + +TEST 'integer' [[ +local x = 1 +repeat +until <?x?> +]] + +-- #2144 +TEST 'A' [=[ +local function f() + return {} --[[@as A]] +end + +local <?x?> = f() +]=] + +TEST 'A' [=[ +local function f() + ---@type A + return {} +end + +local <?x?> = f() +]=] + +TEST 'boolean|number' [[ +---@alias A number +---@alias(partial) A boolean + +---@type A +local <?x?> +]] |