Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type guard doesn't work properly with unions #742

Closed
RobertBouillon opened this issue Apr 9, 2024 · 2 comments · Fixed by #819
Closed

Type guard doesn't work properly with unions #742

RobertBouillon opened this issue Apr 9, 2024 · 2 comments · Fixed by #819
Labels
bug Something isn't working

Comments

@RobertBouillon
Copy link

RobertBouillon commented Apr 9, 2024

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 hishamhm added the bug Something isn't working label Apr 9, 2024
@hishamhm
Copy link
Member

hishamhm commented Apr 9, 2024

Thanks for the report!

This should also function as a workaround:

  if y is string or y is Foo then

@RobertBouillon
Copy link
Author

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.

hishamhm added a commit that referenced this issue Oct 13, 2024
This expands an `is` applied to a union (even in behind an alias)
into a chain of `or` tests with individual `is` checks on the
types of the union. If the individual entries have __is metamethods,
expands their code as well.

This implementation is not recursive (i.e. it does not handle
unions of unions), but it is a major improvement over the previous
behavior.

Fixes #742.
hishamhm added a commit that referenced this issue Oct 16, 2024
This expands an `is` applied to a union (even in behind an alias)
into a chain of `or` tests with individual `is` checks on the
types of the union. If the individual entries have __is metamethods,
expands their code as well.

This implementation is not recursive (i.e. it does not handle
unions of unions), but it is a major improvement over the previous
behavior.

Fixes #742.
hishamhm added a commit that referenced this issue Oct 16, 2024
This expands an `is` applied to a union (even in behind an alias)
into a chain of `or` tests with individual `is` checks on the
types of the union. If the individual entries have __is metamethods,
expands their code as well.

This implementation is not recursive (i.e. it does not handle
unions of unions), but it is a major improvement over the previous
behavior.

Fixes #742.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants