Benjamin-Dobell / IntelliJ-Luanalysis

Type-safe Lua IDE — IntelliJ IDEA plugin
Apache License 2.0
155 stars 21 forks source link

Invalid type mismatch error is given when passing along optional `shape` from one function to another #145

Closed pouwelsjochem closed 1 year ago

pouwelsjochem commented 1 year ago

Environment

Name Version
IDEA version 2022.3.1
Luanalysis version 1.4.0
OS MacOS

Lua

Name Setting
Language level 5.2

Type Safety

Name Setting
Strict nil checks
Unknown type (any) is indexable ☑️
Unknown type (any) is callabale ☑️

What are the steps to reproduce this issue?

---@shape MyShape
---@class MyClass

---@param _shape? MyShape
local function acceptOptionalShape1(_shape) end
---@param _shape? MyShape
local function acceptOptionalShape2(_shape)
    acceptOptionalShape1(_shape)
end

---@param _string? string
local function acceptOptionalString1(_string) end
---@param _string? string
local function acceptOptionalString2(_string)
    acceptOptionalString1(_string)
end

---@param _class? MyClass
local function acceptOptionalNillableClass1(_class) end
---@param _class? MyClass
local function acceptOptionalNillableClass2(_class)
    acceptOptionalNillableClass1(_class)
end

---@param _shape? nil|MyShape
local function acceptOptionalNillableShape1(_shape) end
---@param _shape? MyShape
local function acceptOptionalNillableShape2(_shape)
    acceptOptionalNillableShape1(_shape)
end

What happens?

When passing along an optional @shape from one function to another there's a Type mismatch. Required: 'MyShape' Found: 'MyShape | nil' message. This doesn't happen when the optional param is a literal like string, also doesn't happen when the optional param is a @class. It does also happen when the @shape is defined with the {key:type} format.

What were you expecting to happen?

No error to be given when passing along optional shapes.

Sebaestschjin commented 1 year ago

I'd like to add that it's not specific to shapes and I have the same thing happen for base types like number or string:

---@param p? number
local function acceptOptional(p) end

---@param p? number
local function callee(p)
  acceptOptional(p)
end

Results in

Type mismatch. Required: 'number' Found: 'nil | number'

At the call of acceptOptional.

The error doesn't happen when called function takes a parameter of type nil | number instead:

---@param p nil | number
local function acceptOptional(p) end
Benjamin-Dobell commented 1 year ago

Sorry, I missed this issue until @Sebaestschjin commented. There should be no difference in this behaviour between shapes, classes and primitives. Assuming there is no such difference, then this behaviour is definitely intended. This behaviour and the motivation is documented at https://github.com/Benjamin-Dobell/IntelliJ-Luanalysis#support-for-optional-parameters

I.e. optional does not mean nil | type. Instead it means the parameter itself may be omitted. You can of course combine the two if that is the desired behaviour. But the distinction between the absence of a parameter and presence of a parameter that is nil is very important as function implementations may wish (or in the case of bindings, perhaps need) to depend on the number of parameters passed.

pouwelsjochem commented 1 year ago

I agree Luanalysis should keep absence of a param and a nillable param separated. Did some more testing and found out that the distinction between the shape parameter and other parameters only occurs if 'Strict nil checks' is disabled. When enabled it does indeed work like you described.

Going to use 'Strict nil checks' from now on :)