Conditionals with separate returns is failing to infer a union in the New Type Solver
(This issue was rewritten after the discussion below to capture the actual bug being reported.)
The following code does not typecheck or infer correctly under the New Type Solver:
--!strict
local function choice(a, b, c)
if a then
return b
else
return c
end
end
local b = choice(true, "Hello", 42)
local c = choice(false, "Hello", 42)
print(b, c)
For inference, this produces choice : <a, b>(a: a, b: b, c: b) -> b which is a reasonable type since b can be instantiated with a union here, but automatic instantiation fails to do this correctly (likely owing to changes to bidirectional type inference) and so you instead get an error on the two calls:
local b = choice(true, "Hello", 42) -- number is not string
local c = choice(false, "Hello", 42) -- number is not string
For typechecking, if we annotate the arguments explicitly, we also fail to infer the union type for the function overall, e.g.
--!strict
local function choice(a, b: string, c: number)
if a then
return b
else
return c -- number is not string
end
end
local b = choice(true, "Hello", 42)
local c = choice(false, "Hello", 42)
print(b, c)
We would expect that choice infers to have a return type of string | number and the function calls succeed.
the generic type a can be instantiated with a union, so <a>(unknown, a, a) -> a could very well be instantiated to be (unknown, string | number, string | number) -> string | number. is there some actual need you have for inference to produce two separate generics with a union for the result here? if so, you should substantiate that in this issue, especially given that you can clearly annotate the program to have the exact desired signature.
the generic type
acan be instantiated with a union, so<a>(unknown, a, a) -> acould very well be instantiated to be(unknown, string | number, string | number) -> string | number. is there some actual need you have for inference to produce two separate generics with a union for the result here? if so, you should substantiate that in this issue, especially given that you can clearly annotate the program to have the exact desired signature.
My mistake, the "main point" of this Issue doesn't make any sense.
However, is the type error in the last snippet intentional? The return value has been inferred as string and not string | number.
--!strict
local function choice(a, b: string, c: number)
if a then
return b
else
return c -- "Type 'number' could not be converted into 'string'"
end
end
local b = choice(true, "Hello", 42)
local c = choice(false, "Hello", 42)
print(b, c)
If you're using the old type solver (which it seems like you are), it's expected, but undesirable. The video you linked with zeux is talking about what we have been building in the new type solver which does support inferring the result type as b | c here.
If you're using the old type solver (which it seems like you are), it's expected, but undesirable. The video you linked with zeux is talking about what we have been building in the new type solver which does support inferring the result type as
b | chere.
I checked Luau LSP, the luau-analyze tool (with --fflags=LuauSolverV2) and Studio. It looks to me like the issue is occurring in the New Solver
Additional snippet using type functions but without the New Solver enabled to show that the switch was actually having an effect:
That is a bug then, I'll adjust your issue description.