Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions docs/project-words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ recordkey
retlist
retstat
setmetatable
stdlib
subtyping
tableconstructor
tlconfig
Expand Down
1 change: 1 addition & 0 deletions docs/src/compiler_options.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ return {
| `--wdisable` | `disable_warnings` | `{string}` | `check` `run` | Disable the given warnings.
| `--werror` | `warning_error` | `{string}` | `check` `run` | Promote the given warnings to errors.
| `--global-env-def` | `global_env_def` | `string` | `check` `gen` `run` | Specify a definition module declaring any custom globals predefined in your Lua environment. See the [declaration files](declaration_files.md#global-environment-definition) page for details. |
| `--no-stdlib` | `no_stdlib` | `boolean` | `check` `gen` `run` | Don't include the standard library definitions in the type checker. This is useful when using a custom environment that differs from the PUC-Rio Lua standard library. |

### Generated code

Expand Down
34 changes: 34 additions & 0 deletions spec/cli/no_stdlib_spec.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
local assert = require("luassert")
local util = require("spec.util")

describe("--no-stdlib argument", function()
it("prevent the Lua stdlib to be used", function()
util.do_in(util.write_tmp_dir(finally, {
["test.tl"] = [[
print("hello world")
]],
}), function()
local pd = io.popen(util.tl_cmd("check", "--no-stdlib", "test.tl") .. " 2>&1 1>" .. util.os_null, "r")
local output = pd:read("*a")
util.assert_popen_close(1, pd:close())
assert.match("1 error:", output, 1, true)
end)
end)
it("reads no_std from tlconfig.lua", function()
util.do_in(util.write_tmp_dir(finally, {
["test.tl"] = [[
print("hello world")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a line to test.tl here with a simple use of a fundamental prelude type, like:

local function id(x: any): any return x end

We should still only get 1 error from the missing print function.

@Aire-One Aire-One Mar 28, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's indeed a good addition. However, the tests are still green when with prelude words, reporting no more than the initial 1 error for print. To me, it seems like the prelude works, even without the recommended env:require_module("teal.default.prelude").

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, good catch. I don't have it off the top of my head, but maybe any gets special cased when parsing. But I think the default metamethods from the prelude will probably trigger an error if those are missing.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, metatable things fail without the prelude. I have added a new it in the suite to test prelude specifics types.

]],
["tlconfig.lua"] = [[
return {
no_stdlib = true,
}
]],
}), function()
local pd = io.popen(util.tl_cmd("check", "test.tl") .. " 2>&1 1>" .. util.os_null, "r")
local output = pd:read("*a")
util.assert_popen_close(1, pd:close())
assert.match("1 error:", output, 1, true)
end)
end)
end)
1 change: 1 addition & 0 deletions teal/check/context.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1613,6 +1613,7 @@ do

self.errs:add(t, string.format("inherits incompatible array %s and tuple %s", array_type_str, tuple_type_str))
else

self.errs:add_warning("inheritance", t, "inherits overlapping array %s and tuple %s", array_type_str, tuple_type_str)
end
end
Expand Down
5 changes: 4 additions & 1 deletion teal/environment.lua
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ local environment = { EnvOptions = {}, Env = {}, Result = {} }






environment.VERSION = VERSION
Expand Down Expand Up @@ -140,7 +141,9 @@ end
function environment.new(opts)
local env = empty_environment()
env.opts = opts or env.opts
load_precompiled_default_env(env)
if not env.opts.no_stdlib then
load_precompiled_default_env(env)
end
return env
end

Expand Down
5 changes: 4 additions & 1 deletion teal/environment.tl
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ local record environment
gen_compat: GenCompat
gen_target: GenTarget
run_internal_compiler_checks: boolean
no_stdlib: boolean
end

type RequireModuleFn = function(env: Env, module_name: string): Type, string
Expand Down Expand Up @@ -140,7 +141,9 @@ end
function environment.new(opts?: EnvOptions): Env
local env = empty_environment()
env.opts = opts or env.opts
load_precompiled_default_env(env)
if not env.opts.no_stdlib then
load_precompiled_default_env(env)
end

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add an else section here that loads only the default prelude? Otherwise I think --no-stdlib risks becoming a footgun when people fail to require that from their alternative stdlib implementations.

I believe env:require_module("teal.default.prelude") should suffice!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added with a basic else branch.

return env
end

Expand Down
2 changes: 2 additions & 0 deletions teal/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ local teal = { CheckError = {}, Compiler = {}, Input = {}, TokenList = {}, Parse






local Compiler = teal.Compiler
Expand Down Expand Up @@ -369,6 +370,7 @@ function teal.compiler(opts)
feat_arity = opts and opts.feat_arity,
gen_compat = opts and opts.gen_compat,
gen_target = opts and opts.gen_target,
no_stdlib = opts and not not opts.no_stdlib,
}

compiler.env = environment.new(env_opts)
Expand Down
2 changes: 2 additions & 0 deletions teal/init.tl
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ local record teal
feat_arity: Feat
gen_compat: GenCompat
gen_target: GenTarget
no_stdlib: boolean
end

compiler: function(opts?: CompilerOptions): Compiler
Expand Down Expand Up @@ -369,6 +370,7 @@ function teal.compiler(opts?: CompilerOptions): Compiler
feat_arity = opts and opts.feat_arity,
gen_compat = opts and opts.gen_compat,
gen_target = opts and opts.gen_target,
no_stdlib = opts and not not opts.no_stdlib,
}

compiler.env = environment.new(env_opts)
Expand Down
6 changes: 5 additions & 1 deletion tl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4924,6 +4924,7 @@ do

self.errs:add(t, string.format("inherits incompatible array %s and tuple %s", array_type_str, tuple_type_str))
else

self.errs:add_warning("inheritance", t, "inherits overlapping array %s and tuple %s", array_type_str, tuple_type_str)
end
end
Expand Down Expand Up @@ -10607,6 +10608,7 @@ local environment = { EnvOptions = {}, Env = {}, Result = {} }






environment.VERSION = VERSION
Expand Down Expand Up @@ -10662,7 +10664,9 @@ end
function environment.new(opts)
local env = empty_environment()
env.opts = opts or env.opts
load_precompiled_default_env(env)
if not env.opts.no_stdlib then
load_precompiled_default_env(env)
end
return env
end

Expand Down
1 change: 1 addition & 0 deletions tlcli/args.d.tl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ local record Args
file: {string}
gen_target: string
gen_compat: string
no_stdlib: boolean
global_env_def: {string} -- FIXME should be `string`, but argparse can't handle `:count("0-1")`?...
include_dir: {string}
keep_hashbang: boolean
Expand Down
3 changes: 3 additions & 0 deletions tlcli/configuration.lua
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ local function validate_config(config)
gen_target = { ["5.1"] = true, ["5.3"] = true, ["5.4"] = true },
disable_warnings = "{string}",
warning_error = "{string}",
no_stdlib = "boolean",
}

local function check_key(k, v)
Expand Down Expand Up @@ -237,6 +238,8 @@ function configuration.merge_config_and_args(tlconfig, args)
tlconfig["gen_compat"] = args["gen_compat"] or tlconfig["gen_compat"] or
(tlconfig["skip_compat53"] and "off")

tlconfig["no_stdlib"] = args["no_stdlib"] or tlconfig["no_stdlib"]

if args["global_env_def"] then
if #args["global_env_def"] > 1 then
common.die("Error: --global-env-def can be used only once.")
Expand Down
3 changes: 3 additions & 0 deletions tlcli/configuration.tl
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ local function validate_config(config: {any:any}): TlConfig, {string}, {string}
gen_target = { ["5.1"] = true, ["5.3"] = true, ["5.4"] = true },
disable_warnings = "{string}",
warning_error = "{string}",
no_stdlib = "boolean"
}

local function check_key(k: any, v: any)
Expand Down Expand Up @@ -237,6 +238,8 @@ function configuration.merge_config_and_args(tlconfig: TlConfig, args: Args)
tlconfig["gen_compat"] = args["gen_compat"] or tlconfig["gen_compat"]
or (tlconfig["skip_compat53"] and "off")

tlconfig["no_stdlib"] = args["no_stdlib"] or tlconfig["no_stdlib"]

if args["global_env_def"] then
if #args["global_env_def"] > 1 then
common.die("Error: --global-env-def can be used only once.")
Expand Down
1 change: 1 addition & 0 deletions tlcli/driver.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ function driver.setup_compiler(tlconfig)
feat_arity = tlconfig["feat_arity"],
gen_compat = tlconfig["gen_compat"],
gen_target = tlconfig["gen_target"],
no_stdlib = tlconfig["no_stdlib"] == true,
}

if opts.gen_target == "5.4" and opts.gen_compat ~= "off" then
Expand Down
1 change: 1 addition & 0 deletions tlcli/driver.tl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ function driver.setup_compiler(tlconfig: TlConfig): teal.Compiler
feat_arity = tlconfig["feat_arity"] as teal.Feat,
gen_compat = tlconfig["gen_compat"] as teal.GenCompat,
gen_target = tlconfig["gen_target"] as teal.GenTarget,
no_stdlib = tlconfig["no_stdlib"] == true,
}

if opts.gen_target == "5.4" and opts.gen_compat ~= "off" then
Expand Down
2 changes: 2 additions & 0 deletions tlcli/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ local function get_args_parser()
argname("<dtlfilename>"):
count("*")

parser:flag("--no-stdlib", "Do not load the Lua standard library.")

parser:option("-I --include-dir", "Prepend this directory to the module search path."):
argname("<directory>"):
count("*")
Expand Down
2 changes: 2 additions & 0 deletions tlcli/main.tl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ local function get_args_parser(): argparse.Parser
parser:option("--global-env-def", "Predefined types from a custom global environment.")
:argname("<dtlfilename>")
:count("*") -- `:count("0-1")` does not work? we verify by hand later then

parser:flag("--no-stdlib", "Do not load the Lua standard library.")

parser:option("-I --include-dir", "Prepend this directory to the module search path.")
:argname("<directory>")
Expand Down
1 change: 1 addition & 0 deletions tlcli/tlconfig.d.tl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ local record TlConfig
feat_arity: string
gen_target: string
gen_compat: string
no_stdlib: boolean
global_env_def: string
pretend: boolean
quiet: boolean
Expand Down
Loading