General Upvalue type guessing - Type error bug in custom type dictionnary assignement
Description
luau intellisence fails when you are trying to use a dictionnary value of a custom type:
Example
i tried to simplify the example as much as possible
--!strict
export type T = "foo" | "bar" | "toto"
local object: T = "foo"
local getOpposite: {[T]: T} = {
["foo"] = "bar",
["bar"] = "toto",
["toto"] = "foo"
}
local function hello()
local x = getOpposite[object] -- intellisence warning
if x then
object = x -- intellisence warning
end
end
Logs
the error is as follows:
Type Error: Type ' "bar"|"foo"|"toto" | ("bar"|"foo"|"toto") & (buffer|class|function|number|string|table|thread|true)) ' could not be converted into ' "bar"|"foo"|"toto" '; this is because the 4th component of the union is ' ("bar"|"foo"|"toto") & (buffer|class|function|number|string|table|thread|true)) ', which is not a subtype of ' "bar"|"foo"|"toto" '.
(i copied it manually, so it can have typos)
Notes
note that you should have the object declaration in order for it to reproduce the issue
...
local function hello()
local x = getOpposite[object] -- no warning
print(x)
end
also, note that casting the dictionnary into {[T]: string}, {[string]: T} and even {[any]: any} or any will also fail, but sometimes not on both lines, example bellow with {[any]: any}
...
local getOpposite: {[any]: any} = {
["foo"] = "bar",
["bar"] = "toto",
["toto"] = "foo"
}
local function hello()
local x = getOpposite[object] -- no warning
if x then
object = x -- intellisence warning
end
end
the only way i had to fix that was to explicit cast types:
...
local x: T= getOpposite[object::T]
PS: maybe its just me who is dumb, in that case i'm honnestly sorry
related to #1768 and @LuauHater post, it seems to be a global issue with upvalue type guessing, because i tried to debug making object variable in the same scope as the definition, and it seems to work fine:
export type T = "foo" | "bar" | "toto"
local getOpposite: {[T]: T} = {
["foo"] = "bar",
["bar"] = "toto",
["toto"] = "foo"
}
local function hello()
local object: T = "foo"
local x = getOpposite[object]
if x then
object = x
end
end
isolate the error
basically it's just the type guessing that is messy, but on certain conditions, for example when a constant value, a local value and an upvalue is together, it creates the warning:
local function foo()
local carry = 0
for i = 0, 10 do
carry = i + carry + 1 -- warning
end
end
local function foo()
local carry = 0
for i = 0, 10 do
carry = i + carry -- no warning
carry = carry + 1 -- no warning
end
end
for them, the type of the operration is : t1 where t1 = add<number, add<t1, number> | number>
and the type of carry is : t1 where t1 = add<add<number, t1>, number> | number