teal-language / tl

The compiler for Teal, a typed dialect of Lua
MIT License
2.02k stars 101 forks source link

Type guard doesn't work properly with unions #742

Open RobertBouillon opened 2 months ago

RobertBouillon commented 2 months ago

Type guards with unions that include a record (table) will only check for the table. Other values included in the union will not be captured.

global record Foo
  bar : string
end

global function repro(x:Foo|string|nil) : integer
  local y = x
  if y is string | Foo then
    return 1
  elseif y is nil then
    return 2
  end
  return 3 -- string falls through here!
end

print(repro({} as Foo)) --1
print(repro("1"))       --3
print(repro(nil))       --2

Workaround

You can add a manual type guard in place of the union, which then gets inferred, but only if: 1) it's in an elseif block and 2) the if statement starts with an is expression

global function repro(x:Foo|string|nil) : integer
  local y = x
  if y is nil then
    local z : nil = y 
    return 2
  elseif type(y) == "table" or type(y) == "string" then
    local z : Foo | string = y
    return 1
  end
  return 3 --No fall through
end
hishamhm commented 2 months ago

Thanks for the report!

This should also function as a workaround:

  if y is string or y is Foo then
RobertBouillon commented 2 months ago

Thanks for the report!

This should also function as a workaround:

  if y is string or y is Foo then

I like that better, thanks!

Incredible library, by the way. Takes a lot of the sting out of large Lua scripts, especially coming from C#, Java, and TS.