Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require "global function" in global functions #543

Merged
merged 1 commit into from
Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/grammar.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ precedence, see below.

label ::= ‘::’ Name ‘::’

funcname ::= Name {‘.’ Name} [‘:’ Name]
+ funcname ::= Name {‘.’ Name} ‘:’ Name | Name {‘.’ Name} ‘.’ Name

varlist ::= var {‘,’ var}

Expand Down
12 changes: 9 additions & 3 deletions docs/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ You can declare functions that generate iterators which can be used in
This is an example [taken the book "Programming in Lua"](https://www.lua.org/pil/7.1.html):

```
function allwords(): (function(): string)
local function allwords(): (function(): string)
local line = io.read()
local pos = 1
return function(): string
Expand Down Expand Up @@ -711,7 +711,7 @@ in both function declarations.
Just like in Lua, some functions in Teal may receive a variable amount of arguments. Variadic functions can be declared by specifying `...` as the last argument of the function:

```
function test(...: number)
local function test(...: number)
print(...)
end

Expand All @@ -721,7 +721,7 @@ test(1, 2, 3)
In case your function returns a variable amount of values, you may also declare variadic return types by using the `type...` syntax:

```
function test(...: number): number...
local function test(...: number): number...
return ...
end

Expand Down Expand Up @@ -854,10 +854,16 @@ declaration and/or assignment:

```
global n: number

global m: {string:boolean} = {}

global hi = function(): string
return "hi"
end

global function my_function()
print("I am a global function")
end
```

You can also declare global types, which are visible across modules, as long
Expand Down
6 changes: 3 additions & 3 deletions spec/call/generic_function_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ describe("generic function", function()

it("does not leak an unresolved generic type", function()
local _, ast = util.check([[
function mypairs<a, b>(map: {a:b}): (a, b)
local function mypairs<a, b>(map: {a:b}): (a, b)
end

local _, resolved = mypairs({["hello"] = true})
Expand All @@ -397,9 +397,9 @@ describe("generic function", function()
end)

it("does not produce a recursive type", util.lax_check([[
function mypairs<a, b>(map: {a:b}): (a, b)
local function mypairs<a, b>(map: {a:b}): (a, b)
end
function myipairs<a>(array: {a}): (a)
local function myipairs<a>(array: {a}): (a)
end

local _, xs = mypairs(xss)
Expand Down
2 changes: 1 addition & 1 deletion spec/call/record_method_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe("record method call", function()
end
return "what"
end
function foo()
local function foo()
r:f(r:f("hello"))
end
]])
Expand Down
12 changes: 3 additions & 9 deletions spec/cli/global_env_def_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@ describe("--global-env-def argument", function()
util.do_in(util.write_tmp_dir(finally, {
mod = {
["add.tl"] = [[
function add(n: number, m: number): number
global function add(n: number, m: number): number
return n + m
end

return add
]],
},
["test.tl"] = [[
Expand Down Expand Up @@ -39,11 +37,9 @@ describe("--global-env-def argument", function()
util.do_in(util.write_tmp_dir(finally, {
mod = {
["add.tl"] = [[
function add(n: number, m: number): number
global function add(n: number, m: number): number
return n + m
end

return add
]],
},
["test.tl"] = [[
Expand All @@ -60,11 +56,9 @@ describe("--global-env-def argument", function()
util.do_in(util.write_tmp_dir(finally, {
mod = {
["add.tl"] = [[
function add(n: number, m: number): number
global function add(n: number, m: number): number
return n + m
end

return add
]],
},
["test.tl"] = [[
Expand Down
13 changes: 8 additions & 5 deletions spec/cli/include_dir_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,28 @@ describe("-I --include-dir argument", function()
util.do_in(util.write_tmp_dir(finally, {
mod = {
["add.tl"] = [[
function add(n: number, m: number): number
local function add(n: number, m: number): number
return n + m
end

return add
]],
["subtract.tl"] = [[
function subtract(n: number, m: number): number
global function subtract(n: number, m: number): number
return n - m
end

return subtract
]],
},
["test.tl"] = [[
require("add")
local add = require("add")
local x: number = add(1, 2)

assert(x == 3)

require("subtract")
local y: number = subtract(100, 90)

assert(y == 10)
]],
}), function()
local pd = io.popen(util.tl_cmd("check", "-I", "mod", "test.tl"), "r")
Expand Down
4 changes: 2 additions & 2 deletions spec/compat/lua_versions_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ local util = require("spec.util")
describe("Lua version compatibility", function()
if _VERSION == "Lua 5.1" or _VERSION == "Lua 5.2" then
it("generates compat code for // operator", util.gen([[
function hello(n: number): number
local function hello(n: number): number
return 9
end

local x = 124 // 3
local x = hello(12) // hello(hello(12) // 12)
]], [[
function hello(n)
local function hello(n)
return 9
end

Expand Down
71 changes: 47 additions & 24 deletions spec/declaration/global_function_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -50,17 +50,40 @@ describe("global function", function()
}))
end)

for _, decl in ipairs({ "function", "global function" }) do
describe("'" .. decl .. "'", function()
it("declaration", util.check([[
]] .. decl .. [[ f(a: number, b: string): boolean
it("a bare 'function' can only be used in lax mode", util.check_type_error([[
function f()
print("I am a bare function")
end
]], {
{ y = 1, msg = "functions need an explicit 'local' or 'global' annotation" },
}))

local modes = {
{
fn = "function",
check = function(code) return util.lax_check(code, {}) end,
check_type_error = util.lax_check_type_error,
check_syntax_error = util.check_syntax_error,
},
{
fn = "global function",
check = util.check,
check_type_error = util.check_type_error,
check_syntax_error = util.check_syntax_error,
},
}

for _, mode in ipairs(modes) do
describe("'" .. mode.fn .. "'", function()
it("declaration", mode.check([[
]] .. mode.fn .. [[ f(a: number, b: string): boolean
return #b == a
end
local ok = f(3, "abc")
]]))

it("declaration with type variables", util.check([[
]] .. decl .. [[ f<a, b>(a1: a, a2: a, b1: b, b2: b): b
it("declaration with type variables", mode.check([[
]] .. mode.fn .. [[ f<a, b>(a1: a, a2: a, b1: b, b2: b): b
if a1 == a2 then
return b1
else
Expand All @@ -70,39 +93,39 @@ describe("global function", function()
local ok = f(10, 20, "hello", "world")
]]))

it("declaration with nil as return", util.check([[
]] .. decl .. [[ f(a: number, b: string): nil
it("declaration with nil as return", mode.check([[
]] .. mode.fn .. [[ f(a: number, b: string): nil
return
end
local ok = f(3, "abc")
f(3, "abc")
]]))

it("declaration with no return", util.check([[
]] .. decl .. [[ f(a: number, b: string): ()
it("declaration with no return", mode.check([[
]] .. mode.fn .. [[ f(a: number, b: string): ()
return
end
f(3, "abc")
]]))

it("declaration with no return cannot be used in assignment", util.check_type_error([[
]] .. decl .. [[ f(a: number, b: string): ()
it("declaration with no return cannot be used in assignment", mode.check_type_error([[
]] .. mode.fn .. [[ f(a: number, b: string): ()
return
end
local x = f(3, "abc")
]], {
{ msg = "assignment in declaration did not produce an initial value for variable 'x'" }
}))
]], mode.fn == "global function"
and {{ msg = "assignment in declaration did not produce an initial value for variable 'x'" }}
or {}))

it("declaration with return nil can be used in assignment", util.check([[
]] .. decl .. [[ f(a: number, b: string): nil
it("declaration with return nil can be used in assignment", mode.check([[
]] .. mode.fn .. [[ f(a: number, b: string): nil
return
end
local x = f(3, "abc")
local x: nil = f(3, "abc")
]]))

describe("with function arguments", function()
it("has ambiguity without parentheses in function type return", util.check_syntax_error([[
]] .. decl .. [[ map<a, b>(f: function(a):b, xs: {a}): {b}
it("has ambiguity without parentheses in function type return", mode.check_syntax_error([[
]] .. mode.fn .. [[ map<a, b>(f: function(a):b, xs: {a}): {b}
local r = {}
for i, x in ipairs(xs) do
r[i] = f(x)
Expand All @@ -115,14 +138,14 @@ describe("global function", function()

print(table.concat(map(quoted, {"red", "green", "blue"}), ", "))
]], {
{ y = 1, x = 47 + #decl, msg = "syntax error" },
{ y = 1, x = 47 + #mode.fn, msg = "syntax error" },
{ y = 1 },
{ y = 1 },
{ y = 1 },
}))

it("has no ambiguity with parentheses in function type return", util.check([[
]] .. decl .. [[ map<a,b>(f: function(a):(b), xs: {a}): {b}
it("has no ambiguity with parentheses in function type return", mode.check([[
]] .. mode.fn .. [[ map<a,b>(f: function(a):(b), xs: {a}): {b}
local r = {}
for i, x in ipairs(xs) do
r[i] = f(x)
Expand Down
2 changes: 1 addition & 1 deletion spec/declaration/local_function_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ describe("local function", function()

local normal: number

function new(normal: string): Name
local function new(normal: string): Name
return {
normal = normal:upper()
}
Expand Down
12 changes: 6 additions & 6 deletions spec/declaration/record_method_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -293,12 +293,12 @@ describe("record method", function()
end)

it("does not fail when declaring methods on untyped self (regression test for #427)", util.check_type_error([[
function foo()
local self = { }
function self:bar(): string
return "bar"
end
return self
local function foo()
local self = { }
function self:bar(): string
return "bar"
end
return self
end
]], {
{ msg = "in return value: excess return values" }
Expand Down
12 changes: 6 additions & 6 deletions spec/declaration/record_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ for i, name in ipairs({"records", "arrayrecords"}) do
foo: R
end

function id(r: R): R
local function id(r: R): R
return r
end
]]))
Expand All @@ -115,7 +115,7 @@ for i, name in ipairs({"records", "arrayrecords"}) do
graphics: love_graphics
end

function main()
global function main()
love.graphics.print("Hello world", 100, 100)
end
]]))
Expand Down Expand Up @@ -152,7 +152,7 @@ for i, name in ipairs({"records", "arrayrecords"}) do
u: function(): string
end

function f(r: R): R
local function f(r: R): R
return r
end
]], {
Expand All @@ -166,7 +166,7 @@ for i, name in ipairs({"records", "arrayrecords"}) do
u: function(): UnknownType
end

function f(r: R): R
local function f(r: R): R
return r
end
]], {
Expand Down Expand Up @@ -579,7 +579,7 @@ for i, name in ipairs({"records", "arrayrecords"}) do
foo: R
end

function id(r: R): R
local function id(r: R): R
return r
end
]]))
Expand All @@ -601,7 +601,7 @@ for i, name in ipairs({"records", "arrayrecords"}) do
foo: R
end

function id(r: R): R
local function id(r: R): R
return r
end
]], {
Expand Down
4 changes: 2 additions & 2 deletions spec/operator/eq_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ describe("flow analysis with ==", function()
local type UnionAorB = A | B
local b: B = {}

function head(n: UnionAorB): UnionAorB
local function head(n: UnionAorB): UnionAorB
if n == b then
return n.h
end
Expand Down Expand Up @@ -279,7 +279,7 @@ describe("flow analysis with ==", function()
}))

it("resolves == on the test", util.check [[
function process(ts: {number | string})
local function process(ts: {number | string})
local t: number | string
t = ts[1]
local i = 1
Expand Down
Loading