Skip to content

Commit

Permalink
improve error message when 'local type' is needed
Browse files Browse the repository at this point in the history
  • Loading branch information
hishamhm committed Oct 21, 2024
1 parent 644bc44 commit 07b97fc
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 21 deletions.
5 changes: 4 additions & 1 deletion spec/lang/stdlib/require_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1320,8 +1320,11 @@ describe("require", function()

assert.same({}, result.syntax_errors)
assert.same({
{ filename = "main.tl", x = 33, y = 1, msg = "module type is abstract; use a 'type' declaration" }
{ filename = "main.tl", x = 33, y = 1, msg = "module type is abstract: interface IFoo" }
}, result.type_errors)
assert.same({
{ filename = "main.tl", x = 19, y = 1, msg = "hint: consider using 'local type' instead", tag = "hint" }
}, result.warnings)
end)

it("a module returning an interface instance can be required concretely (#825)", function ()
Expand Down
25 changes: 15 additions & 10 deletions tl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6341,16 +6341,19 @@ function Errors:add_prefixing(w, src, prefix, dst)
end
end

local function ensure_not_abstract(t)
local function ensure_not_abstract(t, node)
if t.typename == "function" and t.macroexp then
return nil, "macroexps are abstract; consider using a concrete function"
elseif t.typename == "typedecl" then
local def = t.def
if def.typename == "interface" then
if def.typename == "record" then
return true
elseif node and node_is_require_call(node) then
return nil, "module type is abstract: " .. tostring(t.def)
elseif def.typename == "interface" then
return nil, "interfaces are abstract; consider using a concrete record"
elseif not (def.typename == "record") then
return nil, "cannot use a type definition as a concrete value"
end
return nil, "cannot use a type definition as a concrete value"
end
return true
end
Expand Down Expand Up @@ -11369,6 +11372,9 @@ self:expand_type(node, values, elements) })

assert(var)
self:add_var(var, var.tk, t, var.attribute, is_localizing_a_variable(node, i) and "localizing")
if var.elide_type then
self.errs:add_warning("hint", node, "hint: consider using 'local type' instead")
end

local infertype = infertypes.tuple[i]
if ok and infertype then
Expand Down Expand Up @@ -11407,6 +11413,9 @@ self:expand_type(node, values, elements) })
end

self:add_global(var, var.tk, t, is_inferred)
if var.elide_type then
self.errs:add_warning("hint", node, "hint: consider using 'global type' instead")
end

self:dismiss_unresolved(var.tk)
end
Expand Down Expand Up @@ -11727,13 +11736,9 @@ self:expand_type(node, values, elements) })
tuple = flatten_tuple(tuple)

for i, t in ipairs(tuple.tuple) do
local ok, err = ensure_not_abstract(t)
local ok, err = ensure_not_abstract(t, node[i])
if not ok then
if node_is_require_call(node[i]) then
self.errs:add(node[i], "module type is abstract; use a 'type' declaration")
else
self.errs:add(node[i], err)
end
self.errs:add(node[i], err)
end
end

Expand Down
25 changes: 15 additions & 10 deletions tl.tl
Original file line number Diff line number Diff line change
Expand Up @@ -6341,16 +6341,19 @@ function Errors:add_prefixing(w: Where, src: {Error}, prefix: string, dst?: {Err
end
end

local function ensure_not_abstract(t: Type): boolean, string
local function ensure_not_abstract(t: Type, node?: Node): boolean, string
if t is FunctionType and t.macroexp then
return nil, "macroexps are abstract; consider using a concrete function"
elseif t is TypeDeclType then
local def = t.def
if def is InterfaceType then
if def is RecordType then
return true
elseif node and node_is_require_call(node) then
return nil, "module type is abstract: " .. tostring(t.def)
elseif def is InterfaceType then
return nil, "interfaces are abstract; consider using a concrete record"
elseif not def is RecordType then
return nil, "cannot use a type definition as a concrete value"
end
return nil, "cannot use a type definition as a concrete value"
end
return true
end
Expand Down Expand Up @@ -11369,6 +11372,9 @@ do

assert(var)
self:add_var(var, var.tk, t, var.attribute, is_localizing_a_variable(node, i) and "localizing")
if var.elide_type then
self.errs:add_warning("hint", node, "hint: consider using 'local type' instead")
end

local infertype = infertypes.tuple[i]
if ok and infertype then
Expand Down Expand Up @@ -11407,6 +11413,9 @@ do
end

self:add_global(var, var.tk, t, is_inferred)
if var.elide_type then
self.errs:add_warning("hint", node, "hint: consider using 'global type' instead")
end

self:dismiss_unresolved(var.tk)
end
Expand Down Expand Up @@ -11727,13 +11736,9 @@ do
tuple = flatten_tuple(tuple)

for i, t in ipairs(tuple.tuple) do
local ok, err = ensure_not_abstract(t)
local ok, err = ensure_not_abstract(t, node[i])
if not ok then
if node_is_require_call(node[i]) then
self.errs:add(node[i], "module type is abstract; use a 'type' declaration")
else
self.errs:add(node[i], err)
end
self.errs:add(node[i], err)
end
end

Expand Down

0 comments on commit 07b97fc

Please sign in to comment.