Skip to content

Commit

Permalink
Merge pull request #571 from bjornbm/allchecks
Browse files Browse the repository at this point in the history
Include variable verifications in checking
  • Loading branch information
hugomg committed May 13, 2023
2 parents 4b333a8 + a47632a commit dced1c7
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 84 deletions.
2 changes: 1 addition & 1 deletion spec/execution_tests.lua
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ function execution_tests.run(compile_file, backend, _ENV, only_compile)

local tests = {

-- Non-comparison operators, same order as checker.lua
-- Non-comparison operators, same order as typechecker.lua

{ "add_ii", "+", "integer", "integer", "integer" },
{ "add_if", "+", "integer", "float", "float" },
Expand Down
20 changes: 20 additions & 0 deletions spec/translator_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,7 @@ local m: module = {}
local xs: {any} = {10, "hello", 3.14}
local function f(x: any, y: any): any
return nil
end
return m
Expand All @@ -492,8 +493,27 @@ local m = {}
local xs = {10, "hello", 3.14}
local function f(x, y)
return nil
end
return m
]])
end)

it("Remove casts in return statement", function ()
assert_translation(
[[
local m: module = {}
local function f(): (any, any)
return nil as nil, 1 as integer
end
return m
]],
[[
local m = {}
local function f()
return nil, 1
end
return m
]])
end)
Expand Down
12 changes: 6 additions & 6 deletions spec/checker_spec.lua → spec/typechecker_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@
local driver = require 'pallene.driver'
local util = require 'pallene.util'

-- Organization of the Checker Test Suite
-- --------------------------------------
-- Organization of the Type Checker Test Suite
-- -------------------------------------------
--
-- Try to order the tests by the order that things appear in parser.lua.
-- This way, it's easier to know if a test case is missing.
--
-- Try to have a test case for every named error. Look for functions in the checker.lua that take
-- Try to have a test case for every named error. Look for functions in the typechecker.lua that take
-- an error string as a paremeter. For example, type_error and check_exp_verify.

local function run_checker(code)
local function run_typechecker(code)
-- "__test__.pln" does not exist on disk. The name is only used for error messages.
local module, errs = driver.compile_internal("__test__.pln", code, "checker")
local module, errs = driver.compile_internal("__test__.pln", code, "typechecker")
errs = errs or {}
return module, table.concat(errs, "\n")
end

local function assert_error(body, expected_err)
local module, errs = run_checker(util.render([[
local module, errs = run_typechecker(util.render([[
local m: module = {}
$body
return m
Expand Down
10 changes: 5 additions & 5 deletions src/pallene/assignment_conversion.lua
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ local util = require "pallene.util"
local typedecl = require "pallene.typedecl"
local types = require "pallene.types"
local ast = require "pallene.ast"
local checker = require "pallene.checker"
local typechecker = require "pallene.typechecker"

local converter = {}

Expand Down Expand Up @@ -189,7 +189,7 @@ function Converter:apply_transformations()
--- -- capture and mutate $n
--- end
local param = ast.Exp.Var(decl.loc, ast.Var.Name(decl.loc, decl.name))
param.var._def = checker.Def.Variable(decl)
param.var._def = typechecker.Def.Variable(decl)
param.var._type = assert(decl._type)
param._type = decl._type

Expand Down Expand Up @@ -232,7 +232,7 @@ function Converter:apply_transformations()
-- references to captured parameters get replaced by references to `value` field of
-- their proxy variables.
local proxy_var = ast.Var.Name(old_var.loc, "$"..decl.name)
proxy_var._def = checker.Def.Variable(proxy_decl)
proxy_var._def = typechecker.Def.Variable(proxy_decl)
dot_exp = ast.Exp.Var(loc, proxy_var)
else
dot_exp = ast.Exp.Var(loc, old_var)
Expand Down Expand Up @@ -350,7 +350,7 @@ function Converter:visit_stat(stat)
elseif tag == "ast.Stat.Assign" then
for i, var in ipairs(stat.vars) do
if var._tag == "ast.Var.Name" then
if var._def._tag == "checker.Def.Variable" then
if var._def._tag == "typechecker.Def.Variable" then
local decl = assert(var._def.decl)
self:register_decl(decl)

Expand Down Expand Up @@ -406,7 +406,7 @@ function Converter:visit_var(var, update_fn)
local vtag = var._tag

if vtag == "ast.Var.Name" and not var._exported_as then
if var._def._tag == "checker.Def.Variable" then
if var._def._tag == "typechecker.Def.Variable" then
local decl = assert(var._def.decl)
assert(self.update_ref_of_decl[decl])

Expand Down
2 changes: 1 addition & 1 deletion src/pallene/ast.lua
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ declare_type("Exp", {
Binop = {"loc", "lhs", "op", "rhs"},
Cast = {"loc", "exp", "target"},
Paren = {"loc", "exp"},
ExtraRet = {"loc", "call_exp", "i"}, -- Inserted by checker.lua
ExtraRet = {"loc", "call_exp", "i"}, -- Inserted by typechecker.lua
ToFloat = {"loc", "exp"}, -- Inserted by checker.lua
UpvalueRecord = {"loc"}, -- Inserted by assignment_conversion.lua
})
Expand Down
16 changes: 12 additions & 4 deletions src/pallene/driver.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
-- invoke the compiler passes in the right order, passing the data as needed.

local c_compiler = require "pallene.c_compiler"
local checker = require "pallene.checker"
local typechecker = require "pallene.typechecker"
local assignment_conversion = require "pallene.assignment_conversion"
local constant_propagation = require "pallene.constant_propagation"
local coder = require "pallene.coder"
Expand Down Expand Up @@ -72,9 +72,9 @@ function driver.compile_internal(filename, input, stop_after, opt_level)
if not prog_ast then return abort() end
if stop_after == "ast" then return prog_ast end

prog_ast, errs = checker.check(prog_ast)
prog_ast, errs = typechecker.check(prog_ast)
if not prog_ast then return abort() end
if stop_after == "checker" then return prog_ast end
if stop_after == "typechecker" then return prog_ast end

prog_ast, errs = assignment_conversion.convert(prog_ast)
if not prog_ast then return abort() end
Expand Down Expand Up @@ -154,7 +154,15 @@ local function compile_pln_to_lua(input_ext, output_ext, input_file_name, base_n
return false, { err }
end

local prog_ast, errs = driver.compile_internal(input_file_name, input, "checker")
-- Perform compilation steps up to (including) variable verifications.
local prog_ast, errs = driver.compile_internal(input_file_name, input, "uninitialized")
if not prog_ast then
return false, errs
end

-- Redo the compilation, this time stopping after the type checker to have
-- an AST that we can translate to lua.
prog_ast, errs = driver.compile_internal(input_file_name, input, "typechecker")
if not prog_ast then
return false, errs
end
Expand Down
2 changes: 1 addition & 1 deletion src/pallene/pallenec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ local function compile_up_to(stop_after)
end

local function do_check()
compile_up_to("checker")
compile_up_to("uninitialized")
end

local function do_print_ir()
Expand Down
2 changes: 1 addition & 1 deletion src/pallene/parser.lua
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ function Parser:Program()
exp.var._tag == "ast.Var.Name" and
exp.var.name == modname)
then
-- The checker also needs to check that this name has not been shadowed
-- The type checker also needs to check that this name has not been shadowed
self:syntax_error(exp.loc,
"must return exactly the module variable '%s'", modname)
end
Expand Down
20 changes: 10 additions & 10 deletions src/pallene/to_ir.lua
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ function ToIR:convert_stat(cmds, stat)
local is_ipairs = (
e1._tag == "ast.Exp.CallFunc" and
e1.exp._tag == "ast.Exp.Var" and
e1.exp.var._def._tag == "checker.Def.Builtin" and
e1.exp.var._def._tag == "typechecker.Def.Builtin" and
e1.exp.var._def.id == "ipairs")


Expand Down Expand Up @@ -535,7 +535,7 @@ function ToIR:convert_stat(cmds, stat)
for j = i+1, #vars do
local var = vars[j]
if var._tag == "ast.Var.Name" and
var._def._tag == "checker.Def.Variable" and
var._def._tag == "typechecker.Def.Variable" and
self.loc_id_of_decl[var._def.decl] == val.id
then
local v = ir.add_local(self.func, false, exp._type)
Expand All @@ -550,7 +550,7 @@ function ToIR:convert_stat(cmds, stat)
local lhss = {}
for i, var in ipairs(vars) do
if var._tag == "ast.Var.Name" then
assert(var._def._tag == "checker.Def.Variable")
assert(var._def._tag == "typechecker.Def.Variable")
local var_info = self:resolve_variable(var._def.decl)
if var_info._tag == "to_ir.Var.LocalVar" then
table.insert(lhss, to_ir.LHS.Local(var_info.id))
Expand Down Expand Up @@ -862,11 +862,11 @@ function ToIR:exp_to_value(cmds, exp, is_recursive)
local def = var._def

local decl
if def._tag == "checker.Def.Variable" then
if def._tag == "typechecker.Def.Variable" then
decl = def.decl
elseif def._tag == "checker.Def.Function" then
elseif def._tag == "typechecker.Def.Function" then
decl = def.func
elseif def._tag == "checker.Def.Builtin" then
elseif def._tag == "typechecker.Def.Builtin" then
local bname = def.id
if bname == "math.pi" then return ir.Value.Float(math.pi)
elseif bname == "math.huge" then return ir.Value.Float(math.huge)
Expand Down Expand Up @@ -1028,7 +1028,7 @@ function ToIR:exp_to_assignment(cmds, dst, exp)

-- Evaluate the function call expression
local f_val
if def and def._tag == "checker.Def.Builtin" then
if def and def._tag == "typechecker.Def.Builtin" then
f_val = false
else
f_val = self:exp_to_value(cmds, exp.exp)
Expand All @@ -1041,7 +1041,7 @@ function ToIR:exp_to_assignment(cmds, dst, exp)
end

-- Generate the function call command
if def and def._tag == "checker.Def.Builtin" then
if def and def._tag == "typechecker.Def.Builtin" then
local bname = def.id
if bname == "io.write" then
assert(#xs == 1)
Expand Down Expand Up @@ -1094,7 +1094,7 @@ function ToIR:exp_to_assignment(cmds, dst, exp)
typedecl.tag_error(bname)
end

elseif def and def._tag == "checker.Def.Function" then
elseif def and def._tag == "typechecker.Def.Function" then
-- CallStatic is used to call toplevel functions, which are always referenced
-- as upvalues or local variables.
assert(f_val._tag == "ir.Value.Upvalue" or f_val._tag == "ir.Value.LocalVar")
Expand All @@ -1110,7 +1110,7 @@ function ToIR:exp_to_assignment(cmds, dst, exp)
local var = exp.var
if var._tag == "ast.Var.Name" then
local def = var._def
if def._tag == "checker.Def.Variable" then
if def._tag == "typechecker.Def.Variable" then
local var_info = self:resolve_variable(def.decl)

if var_info._tag == "to_ir.Var.LocalVar" or var_info._tag == "to_ir.Var.Upvalue" then
Expand Down

0 comments on commit dced1c7

Please sign in to comment.