-- Test that compilation of invalid Ravi code fails correctly!
-- All tests are negative tests here

-- =================== start copy from Lua testsuite ===============
local function checkerr (msg, f, ...)
  local st, err = pcall(f, ...)
  assert(not st and string.find(err, msg))
end

local function doit (s)
  local f, msg = load(s)
  if f == nil then return msg end
  local cond, msg = pcall(f)
  return (not cond) and msg
end

local function checkmessage (prog, msg)
  local m = doit(prog)
  --print(m)
  assert(string.find(m, msg, 1, true))
end

local function checksyntax (prog, extra, token, line)
  local msg = doit(prog)
  if not string.find(token, "^<%a") and not string.find(token, "^char%(")
    then token = "'"..token.."'" end
  token = string.gsub(token, "(%p)", "%%%1")
  local pt = string.format([[^%%[string ".*"%%]:%d: .- near %s$]],
                           line, token)
  assert(string.find(msg, pt))
  assert(string.find(msg, msg, 1, true))
end
-- =================== end copy from Lua testsuite ===============

checkmessage('local t: table = {}; local t2: table = {}; t=t2[1]', 'Invalid assignment: table expected')
checkmessage('local t: table = {}; t=1', 'Invalid assignment: table expected')
checkmessage('local t: table = {}; t=function() end', 'table expected')
checkmessage('local t: table = {}; local t2: number[] = {}; t=t2', 'Invalid assignment: table expected')
checkmessage('local t: table = {}; local t2: table = { data={} }; t=t2.data', 'Invalid assignment: table expected')
checkmessage('local t: table = {}; local f=function() t = 1 end; f()', 'upvalue of table type, cannot be set to non table value')
checkmessage('local t: table = {}; local x=function() return 0 end; local f=function() t = x() end; f()', 'upvalue of table type, cannot be set to non table value')
checkmessage('local t: table = {}; local x=function() t[1] = 1; local f=function() t = 1 end; f(); end; x()', 'upvalue of table type, cannot be set to non table value')
checkmessage('local i: integer, t: table, j: number', 'uninitialized table in local variable')

checkmessage('local t: integer[] = {}; local t2: integer[] = {1}; t=t2[1]', 'Invalid assignment: integer[] expected')
checkmessage('local t: integer[] = {}; t=1', 'Invalid assignment: integer[] expected')
checkmessage('local t: integer[] = {}; t=function() end', 'integer[] expected')
checkmessage('local t: integer[] = {}; local t2: number[] = {}; t=t2', 'Invalid assignment: integer[] expected')
checkmessage('local t: integer[] = {}; local t2: table = {}; t=t2', 'Invalid assignment: integer[] expected')
checkmessage('local t: integer[] = {}; local t2: table = {true}; t[1]=t2[1]', 'integer expected')
checkmessage('local t: integer[] = {}; local t2: table = {"hi"}; t[1]=t2[1]', 'integer expected')
checkmessage('local t: integer[] = {}; local t2: table = { data={} }; t=t2.data', 'Invalid assignment: integer[] expected')
checkmessage('local t: integer[] = {}; local f=function() t = 1 end; f()', 'upvalue of integer[] type, cannot be set to non integer[] value')
checkmessage('local t: integer[] = {}; local x=function() return 0 end; local f=function() t = x() end; f()', 'upvalue of integer[] type, cannot be set to non integer[] value')
checkmessage('local t: integer[] = {}; local x=function() t[1] = 1; local f=function() t = 1 end; f(); end; x()', 'upvalue of integer[] type, cannot be set to non integer[] value')
checkmessage('local t: integer[] = {false}', 'value cannot be converted to integer')
checkmessage('local x=function() return "hi" end; local t: integer[] = {x()}', 'value cannot be converted to integer')
checkmessage('local x=function() return "hi" end; local t: integer[] = {}; t[1] = x()', 'integer expected')
checkmessage('local i: integer, t: integer[], j: number', 'uninitialized integer[] in local variable')
checkmessage('local t: integer = "a"', 'Invalid local assignment')
checkmessage('local t: integer = function() return "hell" end', 'Invalid local assignment')
checkmessage('local function j() return "hell" end; local t: integer = j()', 'integer expected')
checkmessage('local t: integer = 5; local x=function() return "string" end; local f=function() t = x() end; f()', 'upvalue of integer type, cannot be set to non integer value')
checkmessage('local t: integer = 5.5', 'Invalid local assignment')
checkmessage('local function f() local t: integer[] = {}; t[1] = 4; t[5] = 2; end; f()', 'array out of bounds')
checkmessage('local function f() local t: integer[] = {}; t[1] = 4; t[-5] = 2; end; f()', 'array out of bounds')
checkmessage('local mt: integer[] = {}; local t = {}; setmetatable(t, mt)', 'Lua table expected')
checkmessage('local mt: integer[] = {}; local t: table = {}; setmetatable(t, mt)', 'Lua table expected')


checkmessage('local t: number[] = {}; local t2: number[] = {1.0}; t=t2[1]', 'Invalid assignment: number[] expected')
checkmessage('local t: number[] = {}; t=1', 'Invalid assignment: number[] expected')
checkmessage('local t: number[] = {}; t=function() end', 'number[] expected')
checkmessage('local t: number[] = {}; local t2: integer[] = {}; t=t2', 'Invalid assignment: number[] expected')
checkmessage('local t: number[] = {}; local t2: table = {}; t=t2', 'Invalid assignment: number[] expected')
checkmessage('local t: number[] = {}; local t2: table = {true}; t[1]=t2[1]', 'number expected')
checkmessage('local t: number[] = {}; local t2: table = {"hi"}; t[1]=t2[1]', 'number expected')
checkmessage('local t: number[] = {}; local t2: table = { data={} }; t=t2.data', 'Invalid assignment: number[] expected')
checkmessage('local t: number[] = {}; local f=function() t = 1 end; f()', 'upvalue of number[] type, cannot be set to non number[] value')
checkmessage('local t: number[] = {}; local x=function() return 0 end; local f=function() t = x() end; f()', 'upvalue of number[] type, cannot be set to non number[] value')
checkmessage('local t: number[] = {}; local x=function() t[1] = 1; local f=function() t = 1 end; f(); end; x()', 'upvalue of number[] type, cannot be set to non number[] value')
checkmessage('local t: number[] = {false}', 'value cannot be converted to number')
checkmessage('local x=function() return "hi" end; local t: number[] = {x()}', 'value cannot be converted to number')
checkmessage('local x=function() return "hi" end; local t: number[] = {}; t[1] = x()', 'number expected')
checkmessage('local i: integer, t: number[], j: number', 'uninitialized number[] in local variable')
checkmessage('local t: number = "a"', 'Invalid local assignment')
checkmessage('local t: number = function() return "hell" end', 'Invalid local assignment')
checkmessage('local function j() return "hell" end; local t: number = j()', 'number expected')
checkmessage('local t: number = 5.5; local x=function() return "string" end; local f=function() t = x() end; f()', 'upvalue of number type, cannot be set to non number value')
checkmessage('local t: number = 5', 'Invalid local assignment')
checkmessage('local function f() local t: number[] = {}; t[1] = 4.2; t[5] = 2.4; end; f()', 'array out of bounds')
checkmessage('local function f() local t: number[] = {}; t[1] = 4.2; t[-5] = 2.4; end; f()', 'array out of bounds')
checkmessage('local mt: number[] = {}; local t = {}; setmetatable(t, mt)', 'Lua table expected')
checkmessage('local mt: number[] = {}; local t: table = {}; setmetatable(t, mt)', 'Lua table expected')

checkmessage('for i=1,10 do i="a" end', 'Invalid assignment: integer expected')
checkmessage('for i=1,10 do local f = function() i="a" end; f(); end', 'upvalue of integer type, cannot be set to non integer value')
checkmessage('local x: number[] = {1,2}; x:try()', 'attempt to incorrectly index a table value')
checkmessage('@integer ""', 'unexpected symbol near @integer') -- FIXME bad error message
checkmessage('@string 1', 'unexpected symbol near @string') -- FIXME bad error message
checkmessage('@MyType 1', "unexpected symbol near '@'") -- FIXME bad error message
checkmessage('local function x(y: MyType) end x(1)', 'type mismatch: expected MyType')
checkmessage('local function x(y: string) end x(1)', 'string expected')
checkmessage('local function x(y: closure) end x(1)', 'closure expected')
checkmessage('local function x() local s: string; s = 1 end', "Invalid assignment: string expected near 'end'")
checkmessage('function x() local s: string; s = (function() return 1 end)() end; x()', 'string expected')
checkmessage('function x() local s: User; s = (function() return 1 end)() end; x()', 'type mismatch: expected User')

print 'Ok'