Benjamin-Dobell / IntelliJ-Luanalysis

Type-safe Lua IDE — IntelliJ IDEA plugin

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Missing validation when casting an argument

pouwelsjochem opened this issue · comments

Environment

Name Version
IDEA version 2021
Luanalysis version 1.3.0
OS macOS 11.5

What are the steps to reproduce this issue?

---@shape shapeA
---@field fieldA string

local variableA = "A"
local function receiveAny(_any)
    
end
receiveAny(--[[---@type number]] "")
receiveAny(--[[---@type number]] {})
receiveAny(--[[---@type number]] variableA)
receiveAny(--[[---@type shapeA]] variableA)

What happens?

None of the arguments in the receiveAny executions are validated, everything is accepted.

What were you expecting to happen?

All of the receiveAny executions should fail.

receiveAny will accept an argument of any type, in which case it doesn't matter what type you pass it, any type is valid. No errors are expected.

However, you can verify that type checking is working as expected in the presence of type casts by restricting the accepted parameter type e.g.

---@shape shapeA
---@field fieldA string

local variableA = "A"

---@param value number
local function receiveNumber(value)
end

receiveNumber(--[[---@type number]] "")
receiveNumber(--[[---@type number]] {})
receiveNumber(--[[---@type number]] variableA)
receiveNumber(--[[---@type shapeA]] variableA)

You'll see that the first 3 are valid, and the last is not. This is expected because the type is cast to a number, which is what the function wants.

Granted, casting a string literal (that doesn't represent a number) or object literal to a number probably isn't a great idea, but that's the purpose of casting i.e. essentially it's the dev saying to the IDE, "I know better than you, and I take full responsibility."

@pouwelsjochem Feel free to jump into Discord https://discord.gg/xrqynr2 then the #luanalysis-ide channel if you've any questions. Technically the Discord server is for Tabletop Simulator Lua development, but I run the server, so it's fine 😆

Thanks for the quick reply and server invitation! Definitely good to be in there :)

I see now that casting is meant to forcefully cast, understandable and useful!
The origin of my issue came from wanting to see validation on a @shape I pass as an argument to a function of an external library without having to create a local variable.

Essentialy wanting to do this:

externalLibrary.sendData(--[[---@type shapeA]] {fieldA = "A"})

Instead of:

local shapeA = {fieldA = "A"} ---@type shapeA
externalLibrary.sendData({fieldA = "A"})

But I can solve my issue by writing wrapper functions which expect the right type as signature instead. (i.e. sendShapeA)

Assuming the external library doesn't already have types, you can provide your own types for the library. Here's an example for Tabletop Simulator:

https://github.com/Benjamin-Dobell/tts-types/tree/master/tts

Those .def.lua files provide Lua definitions for functions/tables/userdata which are (mostly) implemented in C#. However, the same process ought to work for regular Lua libraries. Basically anywhere in your IntelliJ project you can provide a <module name>.def.lua file that provides types. The only thing special about the .def.lua extension is that irrelevant inspections are disabled.

Thanks! I was aware of the .def.lua files indeed, used them to map out the parts of the Solar2D engine I use ^^
However I'm not a fan of adding game-specific shapes to that definition file, hence I'm more in favour of writing a wrapper :)