Skip to content

Commit

Permalink
fix is inference taking into account that unions imply nil (#699)
Browse files Browse the repository at this point in the history
This behavior will change one day when we make types not imply nil,
but for now we need to be consistent with the fact that they do.

So silence the warning on the last `elseif V is T` and drop the
error in the `else` case.

Fixes #695.
  • Loading branch information
hishamhm authored Sep 13, 2023
1 parent 28ce7ef commit 3f13595
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 7 deletions.
13 changes: 13 additions & 0 deletions spec/inference/if_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,17 @@ describe("flow typing in 'if' statements", function()
]], {
{ msg = "cannot use operator '+' for types integer | boolean | string and integer" },
}))

-- see also pending test "detects empty unions" in spec/operators/is_spec.lua
it("detects a union value to be nil if all types are exhausted (regression test for #695)", util.check_warnings([[
global function f2(val: string|number)
if val is string then
print(val)
elseif val is number then
print(val)
else
error("string or number expected")
end
end
]], {}, {}))
end)
3 changes: 2 additions & 1 deletion spec/operator/is_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,8 @@ describe("flow analysis with is", function()
{ y = 5, msg = [[cannot use operator '+' for types string (inferred at foo.tl:4:10) and integer]] },
}))

it("detects empty unions", util.check_type_error([[
-- this is not an empty union because `number | string` implies nil.
pending("detects empty unions", util.check_type_error([[
local t: number | string
if t is number then
t = t + 1
Expand Down
7 changes: 4 additions & 3 deletions tl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8238,7 +8238,7 @@ tl.type_check = function(ast, opts)
elseif is_a(t2, t1) then
return t2
else
return INVALID
return NIL
end
end
end
Expand Down Expand Up @@ -8279,7 +8279,7 @@ tl.type_check = function(ast, opts)
end

if #types == 0 then
return INVALID
return NIL
end

return unite(types)
Expand Down Expand Up @@ -8403,7 +8403,8 @@ tl.type_check = function(ast, opts)
end
if typ.typename ~= "typevar" then
if is_a(typ, f.typ) then
node_warning("branch", f.where, f.var .. " (of type %s) is always a %s", show_type(typ), show_type(f.typ))


return { [f.var] = f }
elseif not is_a(f.typ, typ) then
node_error(f.where, f.var .. " (of type %s) can never be a %s", typ, f.typ)
Expand Down
7 changes: 4 additions & 3 deletions tl.tl
Original file line number Diff line number Diff line change
Expand Up @@ -8238,7 +8238,7 @@ tl.type_check = function(ast: Node, opts: TypeCheckOptions): Result, string
elseif is_a(t2, t1) then
return t2
else
return INVALID
return NIL -- because of implicit nil in all unions
end
end
end
Expand Down Expand Up @@ -8279,7 +8279,7 @@ tl.type_check = function(ast: Node, opts: TypeCheckOptions): Result, string
end

if #types == 0 then
return INVALID
return NIL -- because of implicit nil in all unions
end

return unite(types)
Expand Down Expand Up @@ -8403,7 +8403,8 @@ tl.type_check = function(ast: Node, opts: TypeCheckOptions): Result, string
end
if typ.typename ~= "typevar" then
if is_a(typ, f.typ) then
node_warning("branch", f.where, f.var .. " (of type %s) is always a %s", show_type(typ), show_type(f.typ))
-- drop this warning because of implicit nil in all unions
-- node_warning("branch", f.where, f.var .. " (of type %s) is always a %s", show_type(typ), show_type(f.typ))
return { [f.var] = f }
elseif not is_a(f.typ, typ) then
node_error(f.where, f.var .. " (of type %s) can never be a %s", typ, f.typ)
Expand Down

0 comments on commit 3f13595

Please sign in to comment.