Skip to content

Commit

Permalink
Type narrowing proof of concept
Browse files Browse the repository at this point in the history
  • Loading branch information
fgaz committed Nov 3, 2022
1 parent eeaaa72 commit f361b96
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 12 deletions.
31 changes: 31 additions & 0 deletions spec/is/is.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
local util = require("spec.util")

describe("Is<T>:", function()

it("success", util.check [[
local record Is<T> end
local record MyRecord
a: number
end
local record OtherRecord
a: boolean
end
local r : MyRecord | OtherRecord = { a = 1 }
local n : number
local function is_myrecord(x: any): Is<MyRecord>
if x is table then
local a = x.a
return (a is number) as Is<MyRecord>
else return false as Is<MyRecord> end
end
if is_myrecord(r) then
n = r.a
end
]])

end)
15 changes: 9 additions & 6 deletions tl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5585,7 +5585,6 @@ tl.type_check = function(ast, opts)
local function is_valid_union(typ)


local n_table_types = 0
local n_function_types = 0
local n_userdata_types = 0
local n_string_enum = 0
Expand All @@ -5597,11 +5596,6 @@ tl.type_check = function(ast, opts)
if n_userdata_types > 1 then
return false, "cannot discriminate a union between multiple userdata types: %s"
end
elseif ut == "table" then
n_table_types = n_table_types + 1
if n_table_types > 1 then
return false, "cannot discriminate a union between multiple table types: %s"
end
elseif ut == "function" then
n_function_types = n_function_types + 1
if n_function_types > 1 then
Expand Down Expand Up @@ -9114,6 +9108,15 @@ node.exps[3] and node.exps[3].type, }
end
end
elseif node.op.op == "@funcall" then

if a.typename == "function" and a.rets[1] and a.rets[1].tk == "Is" and node.e2[1] then
node.known = Fact({
fact = "is",
var = node.e2[1].tk,
typ = a.rets[1].typevals[1],
where = node,
})
end
if lax and is_unknown(a) then
if node.e1.op and node.e1.op.op == ":" and node.e1.e1.kind == "variable" then
add_unknown_dot(node, node.e1.e1.tk .. "." .. node.e1.e2.tk)
Expand Down
15 changes: 9 additions & 6 deletions tl.tl
Original file line number Diff line number Diff line change
Expand Up @@ -5585,7 +5585,6 @@ tl.type_check = function(ast: Node, opts: TypeCheckOptions): Result, string
local function is_valid_union(typ: Type): boolean, string
-- check for limitations in our union support
-- due to codegen limitations (we only check with type() so far)
local n_table_types = 0
local n_function_types = 0
local n_userdata_types = 0
local n_string_enum = 0
Expand All @@ -5597,11 +5596,6 @@ tl.type_check = function(ast: Node, opts: TypeCheckOptions): Result, string
if n_userdata_types > 1 then
return false, "cannot discriminate a union between multiple userdata types: %s"
end
elseif ut == "table" then
n_table_types = n_table_types + 1
if n_table_types > 1 then
return false, "cannot discriminate a union between multiple table types: %s"
end
elseif ut == "function" then
n_function_types = n_function_types + 1
if n_function_types > 1 then
Expand Down Expand Up @@ -9114,6 +9108,15 @@ tl.type_check = function(ast: Node, opts: TypeCheckOptions): Result, string
end
end
elseif node.op.op == "@funcall" then
-- Huge hack
if a.typename == "function" and a.rets[1] and a.rets[1].tk == "Is" and node.e2[1] then
node.known = Fact {
fact = "is",
var = node.e2[1].tk, -- first argument of function
typ = a.rets[1].typevals[1], -- type argument of Is<>
where = node,
}
end
if lax and is_unknown(a) then
if node.e1.op and node.e1.op.op == ":" and node.e1.e1.kind == "variable" then
add_unknown_dot(node, node.e1.e1.tk .. "." .. node.e1.e2.tk)
Expand Down

0 comments on commit f361b96

Please sign in to comment.