Skip to content

Commit

Permalink
fix: interface instances can be required concretely
Browse files Browse the repository at this point in the history
  • Loading branch information
hishamhm committed Oct 18, 2024
1 parent a7bfd60 commit 644bc44
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 9 deletions.
27 changes: 26 additions & 1 deletion spec/lang/stdlib/require_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1216,7 +1216,7 @@ describe("require", function()

assert.same({}, result.syntax_errors)
assert.same({
{ filename = "main.tl", x = 37, y = 1, msg = "type is not a record" },
{ filename = "main.tl", x = 30, y = 1, msg = "'require' did not return a type, got integer" },
{ filename = "main.tl", x = 45, y = 1, msg = "cannot index key 'Foo' in type integer" },
}, result.type_errors)
end)
Expand Down Expand Up @@ -1324,4 +1324,29 @@ describe("require", function()
}, result.type_errors)
end)

it("a module returning an interface instance can be required concretely (#825)", function ()
util.mock_io(finally, {
["foo.tl"] = [[
local interface IFoo
bar: function(self)
end
local foo: IFoo = {}
return foo
]],
["main.tl"] = [[
local foo = require("foo")
foo.bar = function(self)
print("bar")
end
]],
})
local result, err = tl.process("main.tl")

assert.same({}, result.syntax_errors)
assert.same({}, result.type_errors)
end)

end)
9 changes: 5 additions & 4 deletions tl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11148,7 +11148,7 @@ self:expand_type(node, values, elements) })


if not (ty.typename == "typedecl") then
return a_type(n, "typedecl", { def = ty })
return self.errs:invalid_at(n.e1, "'require' did not return a type, got %s", ty)
end
if ty.is_alias then
return self:resolve_typealias(ty)
Expand Down Expand Up @@ -11669,14 +11669,15 @@ self:expand_type(node, values, elements) })
local expected = self:find_var_type("@return")
if not expected then

expected = self:infer_at(node, got)
local module_type = resolve_tuple(expected)
local module_type = resolve_tuple(got)
if module_type.typename == "nominal" then
self:resolve_nominal(module_type)
self.module_type = module_type.found
self.module_type = module_type.resolved
else
self.module_type = drop_constant_value(module_type)
end

expected = self:infer_at(node, got)
self.st[2].vars["@return"] = { t = expected }
end
local expected_t = expected.tuple
Expand Down
9 changes: 5 additions & 4 deletions tl.tl
Original file line number Diff line number Diff line change
Expand Up @@ -11148,7 +11148,7 @@ do
)
)
if not ty is TypeDeclType then
return a_type(n, "typedecl", { def = ty } as TypeDeclType)
return self.errs:invalid_at(n.e1, "'require' did not return a type, got %s", ty)
end
if ty.is_alias then
return self:resolve_typealias(ty)
Expand Down Expand Up @@ -11669,14 +11669,15 @@ do
local expected = self:find_var_type("@return") as TupleType
if not expected then
-- if at the toplevel
expected = self:infer_at(node, got)
local module_type = resolve_tuple(expected)
local module_type = resolve_tuple(got)
if module_type is NominalType then
self:resolve_nominal(module_type)
self.module_type = module_type.found
self.module_type = module_type.resolved
else
self.module_type = drop_constant_value(module_type)
end

expected = self:infer_at(node, got)
self.st[2].vars["@return"] = { t = expected }
end
local expected_t = expected.tuple
Expand Down

0 comments on commit 644bc44

Please sign in to comment.