diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2022-06-15 17:40:43 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2022-06-15 17:40:43 +0800 |
commit | b22505b90c6df5fadfcad08bee82ec2f6d91bbaa (patch) | |
tree | cb45d1189a2b87d11f98d05ae22d51b45ce388a5 | |
parent | e6b82117616e5d055399aa1568fee90a99ba8d64 (diff) | |
download | lua-language-server-b22505b90c6df5fadfcad08bee82ec2f6d91bbaa.zip |
resolve #1105 infer type by `type(x)`
-rw-r--r-- | changelog.md | 8 | ||||
-rw-r--r-- | script/vm/node.lua | 26 | ||||
-rw-r--r-- | script/vm/runner.lua | 58 | ||||
-rw-r--r-- | test/type_inference/init.lua | 34 |
4 files changed, 106 insertions, 20 deletions
diff --git a/changelog.md b/changelog.md index 01cb797f..15042aa8 100644 --- a/changelog.md +++ b/changelog.md @@ -26,6 +26,14 @@ local s = t and t.x or 1 -- `t` in `t.x` is `table` ``` +* `CHG` infer type by `type(x)` + ```lua + local x + + if type(x) == 'string' then + print(x) -- `x` is `string` here + end + ``` * `FIX` with clients that support LSP 3.17 (VSCode), workspace diagnostics are triggered every time when opening a file. * `FIX` [#1204](https://github.com/sumneko/lua-language-server/issues/1204) * `FIX` [#1208](https://github.com/sumneko/lua-language-server/issues/1208) diff --git a/script/vm/node.lua b/script/vm/node.lua index 5086f66d..1b3ea45c 100644 --- a/script/vm/node.lua +++ b/script/vm/node.lua @@ -224,6 +224,32 @@ function mt:remove(name) return self end +---@param name string +function mt:narrow(name) + if name ~= 'nil' and self.optional == true then + self.optional = nil + end + for index = #self, 1, -1 do + local c = self[index] + if (c.type == 'global' and c.cate == 'type' and c.name == name) + or (c.type == name) + or (c.type == 'doc.type.integer' and (name == 'number' or name == 'integer')) + or (c.type == 'doc.type.boolean' and name == 'boolean') + or (c.type == 'doc.type.table' and name == 'table') + or (c.type == 'doc.type.array' and name == 'table') + or (c.type == 'doc.type.function' and name == 'function') then + goto CONTINUE + end + table.remove(self, index) + self[c] = nil + ::CONTINUE:: + end + if #self == 0 then + self[#self+1] = vm.getGlobal('type', name) + end + return self +end + ---@param node vm.node function mt:removeNode(node) for _, c in ipairs(node) do diff --git a/script/vm/runner.lua b/script/vm/runner.lua index 2e362871..e6f34656 100644 --- a/script/vm/runner.lua +++ b/script/vm/runner.lua @@ -208,30 +208,48 @@ function mt:_lookInto(action, topNode, outNode) outNode = outNode2 elseif action.op.type == '==' or action.op.type == '~=' then - local loc, checker + local exp, checker for i = 1, 2 do - if action[i].type == 'getlocal' and action[i].node == self._loc then - loc = action[i] - checker = action[3-i] -- Copilot tells me use `3-i` instead of `i%2+1` - elseif action[2].type == 'getlocal' and action[2].node == self._loc then - loc = action[3-i] + if guide.isLiteral(action[i]) then checker = action[i] + exp = action[3-i] -- Copilot tells me use `3-i` instead of `i%2+1` end end - if loc then - self:_fastWard(loc.finish, topNode:copy()) - if guide.isLiteral(checker) then - local checkerNode = vm.compileNode(checker) - if action.op.type == '==' then - topNode = checkerNode - if outNode then - outNode:removeNode(topNode) - end - else - topNode:removeNode(checkerNode) - if outNode then - outNode = checkerNode - end + if not exp then + goto RETURN + end + if exp.type == 'getlocal' + and exp.node == self._loc then + self:_fastWard(exp.finish, topNode:copy()) + local checkerNode = vm.compileNode(checker) + if action.op.type == '==' then + topNode = checkerNode + if outNode then + outNode:removeNode(topNode) + end + else + topNode:removeNode(checkerNode) + if outNode then + outNode = checkerNode + end + end + elseif exp.type == 'call' + and checker.type == 'string' + and exp.node.special == 'type' + and exp.args + and exp.args[1] + and exp.args[1].type == 'getlocal' + and exp.args[1].node == self._loc then + self:_fastWard(exp.finish, topNode:copy()) + if action.op.type == '==' then + topNode:narrow(checker[1]) + if outNode then + outNode:remove(checker[1]) + end + else + topNode:remove(checker[1]) + if outNode then + outNode:narrow(checker[1]) end end end diff --git a/test/type_inference/init.lua b/test/type_inference/init.lua index a12e702f..20d2c6e9 100644 --- a/test/type_inference/init.lua +++ b/test/type_inference/init.lua @@ -2580,3 +2580,37 @@ 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 +]] |