Skip to content

Commit

Permalink
fix: do not infer typevars on failed poly match
Browse files Browse the repository at this point in the history
In `assert(f:read("a"))`, the return type of the failed poly match of
`file:read` was matching the `A` typevar of `assert`. We now reset
the temporary scope of a call typecheck fully when backtracking to
test different poly entries (previously we were backtracking only
the poly's own typeargs).
  • Loading branch information
hishamhm committed Sep 18, 2024
1 parent 8f63a86 commit f0d714e
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 44 deletions.
6 changes: 6 additions & 0 deletions spec/stdlib/io_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ describe("io", function()
print(n + m)
]]))

it("with a string format, in assert", util.check([[
local f = assert(io.open("file.txt", "rb"))
local r = assert(f:read("a"))
f:close()
]]))

it("with multiple formats", util.check([[
local a, b, c = io.read("l", 12, 13)
print(a:upper())
Expand Down
41 changes: 19 additions & 22 deletions tl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9275,26 +9275,6 @@ a.types[i], b.types[i]), }
end
end

local function push_typeargs(self, func)
if func.typeargs then
for _, fnarg in ipairs(func.typeargs) do
self:add_var(nil, fnarg.typearg, a_type(fnarg, "unresolved_typearg", {
constraint = fnarg.constraint,
}))
end
end
end

local function pop_typeargs(self, func)
if func.typeargs then
for _, fnarg in ipairs(func.typeargs) do
if self.st[#self.st].vars[fnarg.typearg] then
self.st[#self.st].vars[fnarg.typearg] = nil
end
end
end
end




Expand Down Expand Up @@ -9373,6 +9353,16 @@ a.types[i], b.types[i]), }
return false
end

local function add_call_typeargs(self, func)
if func.typeargs then
for _, fnarg in ipairs(func.typeargs) do
self:add_var(nil, fnarg.typearg, a_type(fnarg, "unresolved_typearg", {
constraint = fnarg.constraint,
}))
end
end
end

check_call = function(self, w, wargs, f, args, expected_rets, cm, argdelta)
local arg1 = args.tuple[1]
if cm == "method" and arg1 then
Expand All @@ -9392,7 +9382,7 @@ a.types[i], b.types[i]), }
return nil, { Err_at(w, "wrong number of arguments (given " .. given .. ", expects " .. show_arity(f) .. ")") }
end

push_typeargs(self, f)
add_call_typeargs(self, f)

return check_args_rets(self, w, wargs, f, args, expected_rets, argdelta)
end
Expand All @@ -9414,6 +9404,13 @@ a.types[i], b.types[i]), }
return { Err_at(w, "wrong number of arguments (given " .. given .. ", expects " .. table.concat(expects, " or ") .. ")") }
end

local function reset_scope(self)
local vars = self.st[#self.st].vars
for k, _ in pairs(vars) do
vars[k] = nil
end
end

check_poly_call = function(self, w, wargs, p, args, expected_rets, cm, argdelta)
local given = #args.tuple

Expand Down Expand Up @@ -9444,7 +9441,7 @@ a.types[i], b.types[i]), }
infer_emptytables(self, w, wargs, f.rets, f.rets, argdelta)
end

pop_typeargs(self, f)
reset_scope(self)

first_errs = first_errs or errs
tried[i] = true
Expand Down
41 changes: 19 additions & 22 deletions tl.tl
Original file line number Diff line number Diff line change
Expand Up @@ -9275,26 +9275,6 @@ do
end
end

local function push_typeargs(self: TypeChecker, func: FunctionType)
if func.typeargs then
for _, fnarg in ipairs(func.typeargs) do
self:add_var(nil, fnarg.typearg, a_type(fnarg, "unresolved_typearg", {
constraint = fnarg.constraint,
} as UnresolvedTypeArgType))
end
end
end

local function pop_typeargs(self: TypeChecker, func: FunctionType)
if func.typeargs then
for _, fnarg in ipairs(func.typeargs) do
if self.st[#self.st].vars[fnarg.typearg] then
self.st[#self.st].vars[fnarg.typearg] = nil
end
end
end
end

local enum CallMode
"method" -- a method colon-call, e.g. `my_object:my_method()`
"plain" -- a plain call or a dot-call, e.g `my_func()` or `my_object.my_func()`
Expand Down Expand Up @@ -9373,6 +9353,16 @@ do
return false
end

local function add_call_typeargs(self: TypeChecker, func: FunctionType)
if func.typeargs then
for _, fnarg in ipairs(func.typeargs) do
self:add_var(nil, fnarg.typearg, a_type(fnarg, "unresolved_typearg", {
constraint = fnarg.constraint,
} as UnresolvedTypeArgType))
end
end
end

check_call = function(self: TypeChecker, w: Where, wargs: {Where}, f: FunctionType, args: TupleType, expected_rets: TupleType, cm: CallMode, argdelta: integer): boolean, {Error}
local arg1 = args.tuple[1]
if cm == "method" and arg1 then
Expand All @@ -9392,7 +9382,7 @@ do
return nil, { Err_at(w, "wrong number of arguments (given " .. given .. ", expects " .. show_arity(f) .. ")") }
end

push_typeargs(self, f)
add_call_typeargs(self, f)

return check_args_rets(self, w, wargs, f, args, expected_rets, argdelta)
end
Expand All @@ -9414,6 +9404,13 @@ do
return { Err_at(w, "wrong number of arguments (given " .. given .. ", expects " .. table.concat(expects, " or ") .. ")") }
end

local function reset_scope(self: TypeChecker)
local vars = self.st[#self.st].vars
for k, _ in pairs(vars) do
vars[k] = nil
end
end

check_poly_call = function(self: TypeChecker, w: Where, wargs: {Where}, p: PolyType, args: TupleType, expected_rets: TupleType, cm: CallMode, argdelta: integer): FunctionType, TupleType, {Error}
local given = #args.tuple

Expand Down Expand Up @@ -9444,7 +9441,7 @@ do
infer_emptytables(self, w, wargs, f.rets, f.rets, argdelta)
end

pop_typeargs(self, f)
reset_scope(self)

first_errs = first_errs or errs
tried[i] = true
Expand Down

0 comments on commit f0d714e

Please sign in to comment.