Skip to content

Commit

Permalink
makes a copy of the method type with is_method false if it is copied …
Browse files Browse the repository at this point in the history
…to a newly declared variable or table entry

adds test cases to spec/calls/record_method_spec for calls on aliases of methods
  • Loading branch information
JR-Mitchell authored and hishamhm committed Mar 18, 2023
1 parent 88564d1 commit e907fbe
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 0 deletions.
43 changes: 43 additions & 0 deletions spec/call/record_method_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,47 @@ describe("record method call", function()
m.a.add(first)
]], {}, {}))

it("reports correct errors for calls on aliases of method", util.check_type_error([[
local record Foo
x: integer
end
function Foo:add(other: integer)
self.x = other and (self.x + other) or self.x
end
local first: Foo = {}
local fadd = first.add
fadd(12)
global gadd = first.add
gadd(13)
local tab = {
hadd = first.add
}
tab.hadd(14)
]],
{
{ y = 9, msg = "argument 1: got integer, expected Foo" },
{ y = 11, msg = "argument 1: got integer, expected Foo" },
{ y = 15, msg = "argument 1: got integer, expected Foo" },
}))

it("reports no warnings for correctly-typed calls on aliases of method", util.check_warnings([[
local record Foo
x: integer
end
function Foo:add(other: Foo)
self.x = other and (self.x + other.x) or self.x
end
local first: Foo = {}
local fadd = first.add
fadd(first)
global gadd = first.add
gadd(first)
local tab = {
hadd = first.add
}
tab.hadd(first)
]], {}, {}))

end)
20 changes: 20 additions & 0 deletions tl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1430,6 +1430,17 @@ local function new_type(ps, i, typename)
})
end


local function shallow_copy_type(t)
local copy = {}
for k, v in pairs(t) do
copy[k] = v
end
local typ = copy
typ.typeid = new_typeid()
return typ
end

local function verify_kind(ps, i, kind, node_kind)
if ps.tokens[i].kind == kind then
return i + 1, new_node(ps.tokens, i, node_kind)
Expand Down Expand Up @@ -8787,6 +8798,10 @@ tl.type_check = function(ast, opts)
node_error(node.vars[i], "cannot infer declaration type; an explicit type annotation is necessary")
ok = false
infertype = INVALID
elseif infertype and infertype.is_method then

infertype = shallow_copy_type(infertype)
infertype.is_method = false
end
end

Expand Down Expand Up @@ -9486,6 +9501,11 @@ tl.type_check = function(ast, opts)
vtype = node.decltype
assert_is_a(node.value, children[2], node.decltype, "in table item")
end
if vtype.is_method then

vtype = shallow_copy_type(vtype)
vtype.is_method = false
end
node.type = a_type({
y = node.y,
x = node.x,
Expand Down
20 changes: 20 additions & 0 deletions tl.tl
Original file line number Diff line number Diff line change
Expand Up @@ -1430,6 +1430,17 @@ local function new_type(ps: ParseState, i: integer, typename: TypeName): Type
}
end

-- Makes a shallow copy of the given type with a new typeid
local function shallow_copy_type(t: Type): Type
local copy: {any:any} = {}
for k, v in pairs(t as {any:any}) do
copy[k] = v
end
local typ: Type = copy as Type
typ.typeid = new_typeid()
return typ
end

local function verify_kind(ps: ParseState, i: integer, kind: TokenKind, node_kind: NodeKind): integer, Node
if ps.tokens[i].kind == kind then
return i + 1, new_node(ps.tokens, i, node_kind)
Expand Down Expand Up @@ -8787,6 +8798,10 @@ tl.type_check = function(ast: Node, opts: TypeCheckOptions): Result, string
node_error(node.vars[i], "cannot infer declaration type; an explicit type annotation is necessary")
ok = false
infertype = INVALID
elseif infertype and infertype.is_method then
-- If we assign a method to a variable, e.g local myfunc = myobj.dothing, the variable should not be treated as a method
infertype = shallow_copy_type(infertype)
infertype.is_method = false
end
end

Expand Down Expand Up @@ -9486,6 +9501,11 @@ tl.type_check = function(ast: Node, opts: TypeCheckOptions): Result, string
vtype = node.decltype
assert_is_a(node.value, children[2], node.decltype, "in table item")
end
if vtype.is_method then
-- If we assign a method to a table item, e.g local a = { myfunc = myobj.dothing }, the table item should not be treated as a method
vtype = shallow_copy_type(vtype)
vtype.is_method = false
end
node.type = a_type {
y = node.y,
x = node.x,
Expand Down

0 comments on commit e907fbe

Please sign in to comment.