Add files via upload

This commit is contained in:
Babyhamsta 2022-07-30 22:26:36 -05:00 committed by GitHub
parent ec80b48e64
commit d6827d480a
Signed by: DevComp
GPG key ID: 4AEE18F83AFDEB23
56 changed files with 3887 additions and 4053 deletions

View file

@ -1,13 +1,13 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lua.h"
#include "lualib.h"
#include "luacode.h"
#include "Luau/BuiltinDefinitions.h"
#include "Luau/ModuleResolver.h"
#include "Luau/TypeInfer.h"
#include "Luau/StringUtils.h"
#include "Luau/BytecodeBuilder.h"
#include "lluz/BuiltinDefinitions.h"
#include "lluz/ModuleResolver.h"
#include "lluz/TypeInfer.h"
#include "lluz/StringUtils.h"
#include "lluz/BytecodeBuilder.h"
#include "doctest.h"
#include "ScopedFlags.h"
@ -17,16 +17,6 @@
#include <math.h>
extern bool verbose;
extern int optimizationLevel;
static lua_CompileOptions defaultOptions()
{
lua_CompileOptions copts = {};
copts.optimizationLevel = optimizationLevel;
copts.debugLevel = 1;
return copts;
}
static int lua_collectgarbage(lua_State* L)
{
@ -62,8 +52,8 @@ static int lua_loadstring(lua_State* L)
lua_setsafeenv(L, LUA_ENVIRONINDEX, false);
size_t bytecodeSize = 0;
char* bytecode = luau_compile(s, l, nullptr, &bytecodeSize);
int result = luau_load(L, chunkname, bytecode, bytecodeSize, 0);
char* bytecode = lluz_compile(s, l, nullptr, &bytecodeSize);
int result = lluz_load(L, chunkname, bytecode, bytecodeSize, 0);
free(bytecode);
if (result == 0)
@ -111,11 +101,11 @@ static int lua_vector_index(lua_State* L)
if (strcmp(name, "Dot") == 0)
{
lua_pushcfunction(L, lua_vector_dot, "Dot");
lua_pushcfunction(L, lua_vector_dot, XorStr("Dot"));
return 1;
}
luaL_error(L, "%s is not a valid member of vector", name);
luaL_error(L, XorStr("%s is not a valid member of vector"), name);
}
static int lua_vector_namecall(lua_State* L)
@ -126,7 +116,7 @@ static int lua_vector_namecall(lua_State* L)
return lua_vector_dot(L);
}
luaL_error(L, "%s is not a valid method of vector", luaL_checkstring(L, 1));
luaL_error(L, XorStr("%s is not a valid method of vector"), luaL_checkstring(L, 1));
}
int lua_silence(lua_State* L)
@ -137,7 +127,7 @@ int lua_silence(lua_State* L)
using StateRef = std::unique_ptr<lua_State, void (*)(lua_State*)>;
static StateRef runConformance(const char* name, void (*setup)(lua_State* L) = nullptr, void (*yield)(lua_State* L) = nullptr,
lua_State* initialLuaState = nullptr, lua_CompileOptions* options = nullptr)
lua_State* initialLuaState = nullptr, lua_CompileOptions* copts = nullptr)
{
std::string path = __FILE__;
path.erase(path.find_last_of("\\/"));
@ -177,9 +167,9 @@ static StateRef runConformance(const char* name, void (*setup)(lua_State* L) = n
lua_pop(L, 1);
// In some configurations we have a larger C stack consumption which trips some conformance tests
#if defined(LUAU_ENABLE_ASAN) || defined(_NOOPT) || defined(_DEBUG)
#if defined(lluz_ENABLE_ASAN) || defined(_NOOPT) || defined(_DEBUG)
lua_pushboolean(L, true);
lua_setglobal(L, "limitedstack");
lua_setglobal(L, XorStr("limitedstack"));
#endif
// Extra test-specific setup
@ -195,16 +185,13 @@ static StateRef runConformance(const char* name, void (*setup)(lua_State* L) = n
// Lua conformance tests treat _G synonymously with getfenv(); for now cater to them
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_setfield(L, -1, "_G");
lua_setfield(L, -1, XorStr("_G"));
std::string chunkname = "=" + std::string(name);
// note: luau_compile supports nullptr options, but we need to customize our defaults to improve test coverage
lua_CompileOptions opts = options ? *options : defaultOptions();
size_t bytecodeSize = 0;
char* bytecode = luau_compile(source.data(), source.size(), &opts, &bytecodeSize);
int result = luau_load(L, chunkname.c_str(), bytecode, bytecodeSize, 0);
char* bytecode = lluz_compile(source.data(), source.size(), copts, &bytecodeSize);
int result = lluz_load(L, chunkname.c_str(), bytecode, bytecodeSize, 0);
free(bytecode);
int status = (result == 0) ? lua_resume(L, nullptr, 0) : LUA_ERRSYNTAX;
@ -221,7 +208,7 @@ static StateRef runConformance(const char* name, void (*setup)(lua_State* L) = n
if (status == 0)
{
REQUIRE(lua_isstring(L, -1));
CHECK(std::string(lua_tostring(L, -1)) == "OK");
CHECK(std::string(lua_tostring(L, -1)) == XorStr("OK"));
}
else
{
@ -235,28 +222,28 @@ static StateRef runConformance(const char* name, void (*setup)(lua_State* L) = n
return globalState;
}
TEST_SUITE_BEGIN("Conformance");
TEST_SUITE_BEGIN(XorStr("Conformance"));
TEST_CASE("Assert")
{
runConformance("assert.lua");
runConformance(XorStr("assert.lua"));
}
TEST_CASE("Basic")
{
ScopedFastFlag sff("LuauLenTM", true);
ScopedFastFlag sff(XorStr("LluLenTM"), true);
runConformance("basic.lua");
runConformance(XorStr("basic.lua"));
}
TEST_CASE("Math")
{
runConformance("math.lua");
runConformance(XorStr("math.lua"));
}
TEST_CASE("Tables")
TEST_CASE("Table")
{
runConformance("tables.lua", [](lua_State* L) {
runConformance("nextvar.lua", [](lua_State* L) {
lua_pushcfunction(
L,
[](lua_State* L) {
@ -264,118 +251,117 @@ TEST_CASE("Tables")
lua_pushlightuserdata(L, reinterpret_cast<void*>(uintptr_t(v)));
return 1;
},
"makelud");
lua_setglobal(L, "makelud");
XorStr("makelud"));
lua_setglobal(L, XorStr("makelud"));
});
}
TEST_CASE("PatternMatch")
{
runConformance("pm.lua");
runConformance(XorStr("pm.lua"));
}
TEST_CASE("Sort")
{
runConformance("sort.lua");
runConformance(XorStr("sort.lua"));
}
TEST_CASE("Move")
{
runConformance("move.lua");
runConformance(XorStr("move.lua"));
}
TEST_CASE("Clear")
{
runConformance("clear.lua");
runConformance(XorStr("clear.lua"));
}
TEST_CASE("Strings")
{
runConformance("strings.lua");
runConformance(XorStr("strings.lua"));
}
TEST_CASE("VarArg")
{
runConformance("vararg.lua");
runConformance(XorStr("vararg.lua"));
}
TEST_CASE("Locals")
{
runConformance("locals.lua");
runConformance(XorStr("locals.lua"));
}
TEST_CASE("Literals")
{
runConformance("literals.lua");
runConformance(XorStr("literals.lua"));
}
TEST_CASE("Errors")
{
runConformance("errors.lua");
runConformance(XorStr("errors.lua"));
}
TEST_CASE("Events")
{
ScopedFastFlag sff1("LuauLenTM", true);
ScopedFastFlag sff2("LuauBetterNewindex", true);
ScopedFastFlag sff("LluLenTM", true);
runConformance("events.lua");
runConformance(XorStr("events.lua"));
}
TEST_CASE("Constructs")
{
runConformance("constructs.lua");
runConformance(XorStr("constructs.lua"));
}
TEST_CASE("Closure")
{
runConformance("closure.lua");
runConformance(XorStr("closure.lua"));
}
TEST_CASE("Calls")
{
runConformance("calls.lua");
runConformance(XorStr("calls.lua"));
}
TEST_CASE("Attrib")
{
runConformance("attrib.lua");
runConformance(XorStr("attrib.lua"));
}
TEST_CASE("GC")
{
runConformance("gc.lua");
runConformance(XorStr("gc.lua"));
}
TEST_CASE("Bitwise")
{
runConformance("bitwise.lua");
runConformance(XorStr("bitwise.lua"));
}
TEST_CASE("UTF8")
{
runConformance("utf8.lua");
runConformance(XorStr("utf8.lua"));
}
TEST_CASE("Coroutine")
{
runConformance("coroutine.lua");
runConformance(XorStr("coroutine.lua"));
}
static int cxxthrow(lua_State* L)
{
#if LUA_USE_LONGJMP
luaL_error(L, "oops");
luaL_error(L, XorStr("oops"));
#else
throw std::runtime_error("oops");
throw std::runtime_error(XorStr("oops"));
#endif
}
TEST_CASE("PCall")
{
runConformance("pcall.lua", [](lua_State* L) {
lua_pushcfunction(L, cxxthrow, "cxxthrow");
lua_setglobal(L, "cxxthrow");
lua_pushcfunction(L, cxxthrow, XorStr("cxxthrow"));
lua_setglobal(L, XorStr("cxxthrow"));
lua_pushcfunction(
L,
@ -385,39 +371,41 @@ TEST_CASE("PCall")
lua_resumeerror(co, L);
return 0;
},
"resumeerror");
lua_setglobal(L, "resumeerror");
XorStr("resumeerror"));
lua_setglobal(L, XorStr("resumeerror"));
});
}
TEST_CASE("Pack")
{
runConformance("tpack.lua");
runConformance(XorStr("tpack.lua"));
}
TEST_CASE("Vector")
{
lua_CompileOptions copts = defaultOptions();
lua_CompileOptions copts = {};
copts.optimizationLevel = 1;
copts.debugLevel = 1;
copts.vectorCtor = "vector";
runConformance(
"vector.lua",
[](lua_State* L) {
lua_pushcfunction(L, lua_vector, "vector");
lua_setglobal(L, "vector");
lua_pushcfunction(L, lua_vector, XorStr("vector"));
lua_setglobal(L, XorStr("vector"));
#if LUA_VECTOR_SIZE == 4
lua_pushvector(L, 0.0f, 0.0f, 0.0f, 0.0f);
#else
lua_pushvector(L, 0.0f, 0.0f, 0.0f);
#endif
luaL_newmetatable(L, "vector");
luaL_newmetatable(L, XorStr("vector"));
lua_pushstring(L, "__index");
lua_pushstring(L, XorStr("__index"));
lua_pushcfunction(L, lua_vector_index, nullptr);
lua_settable(L, -3);
lua_pushstring(L, "__namecall");
lua_pushstring(L, XorStr("__namecall"));
lua_pushcfunction(L, lua_vector_namecall, nullptr);
lua_settable(L, -3);
@ -428,37 +416,37 @@ TEST_CASE("Vector")
nullptr, nullptr, &copts);
}
static void populateRTTI(lua_State* L, Luau::TypeId type)
static void populateRTTI(lua_State* L, lluz::TypeId type)
{
if (auto p = Luau::get<Luau::PrimitiveTypeVar>(type))
if (auto p = lluz::get<lluz::PrimitiveTypeVar>(type))
{
switch (p->type)
{
case Luau::PrimitiveTypeVar::Boolean:
lua_pushstring(L, "boolean");
case lluz::PrimitiveTypeVar::Boolean:
lua_pushstring(L, XorStr("boolean"));
break;
case Luau::PrimitiveTypeVar::NilType:
lua_pushstring(L, "nil");
case lluz::PrimitiveTypeVar::NilType:
lua_pushstring(L, XorStr("nil"));
break;
case Luau::PrimitiveTypeVar::Number:
lua_pushstring(L, "number");
case lluz::PrimitiveTypeVar::Number:
lua_pushstring(L, XorStr("number"));
break;
case Luau::PrimitiveTypeVar::String:
lua_pushstring(L, "string");
case lluz::PrimitiveTypeVar::String:
lua_pushstring(L, XorStr("string"));
break;
case Luau::PrimitiveTypeVar::Thread:
lua_pushstring(L, "thread");
case lluz::PrimitiveTypeVar::Thread:
lua_pushstring(L, XorStr("thread"));
break;
default:
LUAU_ASSERT(!"Unknown primitive type");
lluz_ASSERT(!XorStr("Unknown primitive type"));
}
}
else if (auto t = Luau::get<Luau::TableTypeVar>(type))
else if (auto t = lluz::get<lluz::TableTypeVar>(type))
{
lua_newtable(L);
@ -468,36 +456,38 @@ static void populateRTTI(lua_State* L, Luau::TypeId type)
lua_setfield(L, -2, name.c_str());
}
}
else if (Luau::get<Luau::FunctionTypeVar>(type))
else if (lluz::get<lluz::FunctionTypeVar>(type))
{
lua_pushstring(L, "function");
lua_pushstring(L, XorStr("function"));
}
else if (Luau::get<Luau::AnyTypeVar>(type))
else if (lluz::get<lluz::AnyTypeVar>(type))
{
lua_pushstring(L, "any");
lua_pushstring(L, XorStr("any"));
}
else if (auto i = Luau::get<Luau::IntersectionTypeVar>(type))
else if (auto i = lluz::get<lluz::IntersectionTypeVar>(type))
{
for (const auto& part : i->parts)
LUAU_ASSERT(Luau::get<Luau::FunctionTypeVar>(part));
lluz_ASSERT(lluz::get<lluz::FunctionTypeVar>(part));
lua_pushstring(L, "function");
lua_pushstring(L, XorStr("function"));
}
else
{
LUAU_ASSERT(!"Unknown type");
lluz_ASSERT(!XorStr("Unknown type"));
}
}
TEST_CASE("Types")
{
runConformance("types.lua", [](lua_State* L) {
Luau::NullModuleResolver moduleResolver;
Luau::InternalErrorReporter iceHandler;
Luau::TypeChecker env(&moduleResolver, &iceHandler);
ScopedFastFlag sff("lluzCheckLenMT", true);
Luau::registerBuiltinTypes(env);
Luau::freeze(env.globalTypes);
runConformance("types.lua", [](lua_State* L) {
lluz::NullModuleResolver moduleResolver;
lluz::InternalErrorReporter iceHandler;
lluz::TypeChecker env(&moduleResolver, &iceHandler);
lluz::registerBuiltinTypes(env);
lluz::freeze(env.globalTypes);
lua_newtable(L);
@ -507,18 +497,18 @@ TEST_CASE("Types")
lua_setfield(L, -2, toString(name).c_str());
}
lua_setglobal(L, "RTTI");
lua_setglobal(L, XorStr("RTTI"));
});
}
TEST_CASE("DateTime")
{
runConformance("datetime.lua");
runConformance(XorStr("datetime.lua"));
}
TEST_CASE("Debug")
{
runConformance("debug.lua");
runConformance(XorStr("debug.lua"));
}
TEST_CASE("Debugger")
@ -529,7 +519,8 @@ TEST_CASE("Debugger")
breakhits = 0;
interruptedthread = nullptr;
lua_CompileOptions copts = defaultOptions();
lua_CompileOptions copts = {};
copts.optimizationLevel = 1;
copts.debugLevel = 2;
runConformance(
@ -572,8 +563,8 @@ TEST_CASE("Debugger")
lua_breakpoint(L, -1, line, enabled);
return 0;
},
"breakpoint");
lua_setglobal(L, "breakpoint");
XorStr("breakpoint"));
lua_setglobal(L, XorStr("breakpoint"));
},
[](lua_State* L) {
CHECK(breakhits % 2 == 1);
@ -665,11 +656,11 @@ TEST_CASE("SameHash")
// To keep VM and compiler separate, we duplicate the hash function definition
// This test validates that the hash function in question returns the same results on basic inputs
// If this is violated, some code may regress in performance due to hash slot misprediction in inline caches
CHECK(luaS_hash("", 0) == Luau::BytecodeBuilder::getStringHash({"", 0}));
CHECK(luaS_hash("lua", 3) == Luau::BytecodeBuilder::getStringHash({"lua", 3}));
CHECK(luaS_hash("luau", 4) == Luau::BytecodeBuilder::getStringHash({"luau", 4}));
CHECK(luaS_hash("luaubytecode", 12) == Luau::BytecodeBuilder::getStringHash({"luaubytecode", 12}));
CHECK(luaS_hash("luaubytecodehash", 16) == Luau::BytecodeBuilder::getStringHash({"luaubytecodehash", 16}));
CHECK(luaS_hash("", 0) == lluz::BytecodeBuilder::getStringHash({"", 0}));
CHECK(luaS_hash("lua", 3) == lluz::BytecodeBuilder::getStringHash({"lua", 3}));
CHECK(luaS_hash("lluz", 4) == lluz::BytecodeBuilder::getStringHash({"lluz", 4}));
CHECK(luaS_hash("lluzbytecode", 12) == lluz::BytecodeBuilder::getStringHash({"lluzbytecode", 12}));
CHECK(luaS_hash("lluzbytecodehash", 16) == lluz::BytecodeBuilder::getStringHash({"lluzbytecodehash", 16}));
// Also hash should work on unaligned source data even when hashing long strings
char buf[128] = {};
@ -722,12 +713,12 @@ TEST_CASE("ApiTables")
lua_newtable(L);
lua_pushnumber(L, 123.0);
lua_setfield(L, -2, "key");
lua_pushstring(L, "test");
lua_setfield(L, -2, XorStr("key"));
lua_pushstring(L, XorStr("test"));
lua_rawseti(L, -2, 5);
// lua_gettable
lua_pushstring(L, "key");
lua_pushstring(L, XorStr("key"));
CHECK(lua_gettable(L, -2) == LUA_TNUMBER);
CHECK(lua_tonumber(L, -1) == 123.0);
lua_pop(L, 1);
@ -743,7 +734,7 @@ TEST_CASE("ApiTables")
lua_pop(L, 1);
// lua_rawget
lua_pushstring(L, "key");
lua_pushstring(L, XorStr("key"));
CHECK(lua_rawget(L, -2) == LUA_TNUMBER);
CHECK(lua_tonumber(L, -1) == 123.0);
lua_pop(L, 1);
@ -758,12 +749,12 @@ TEST_CASE("ApiTables")
TEST_CASE("ApiCalls")
{
StateRef globalState = runConformance("apicalls.lua");
StateRef globalState = runConformance(XorStr("apicalls.lua"));
lua_State* L = globalState.get();
// lua_call
{
lua_getfield(L, LUA_GLOBALSINDEX, "add");
lua_getfield(L, LUA_GLOBALSINDEX, XorStr("add"));
lua_pushnumber(L, 40);
lua_pushnumber(L, 2);
lua_call(L, 2, 1);
@ -774,7 +765,7 @@ TEST_CASE("ApiCalls")
// lua_pcall
{
lua_getfield(L, LUA_GLOBALSINDEX, "add");
lua_getfield(L, LUA_GLOBALSINDEX, XorStr("add"));
lua_pushnumber(L, 40);
lua_pushnumber(L, 2);
lua_pcall(L, 2, 1, 0);
@ -787,11 +778,11 @@ TEST_CASE("ApiCalls")
{
lua_State* L2 = lua_newthread(L);
lua_getfield(L2, LUA_GLOBALSINDEX, "create_with_tm");
lua_getfield(L2, LUA_GLOBALSINDEX, XorStr("create_with_tm"));
lua_pushnumber(L2, 42);
lua_pcall(L2, 1, 1, 0);
lua_getfield(L2, LUA_GLOBALSINDEX, "create_with_tm");
lua_getfield(L2, LUA_GLOBALSINDEX, XorStr("create_with_tm"));
lua_pushnumber(L2, 42);
lua_pcall(L2, 1, 1, 0);
@ -808,18 +799,18 @@ TEST_CASE("ApiCalls")
// lua_clonefunction + fenv
{
lua_getfield(L, LUA_GLOBALSINDEX, "getpi");
lua_getfield(L, LUA_GLOBALSINDEX, XorStr("getpi"));
lua_call(L, 0, 1);
CHECK(lua_tonumber(L, -1) == 3.1415926);
lua_pop(L, 1);
lua_getfield(L, LUA_GLOBALSINDEX, "getpi");
lua_getfield(L, LUA_GLOBALSINDEX, XorStr("getpi"));
// clone & override env
lua_clonefunction(L, -1);
lua_newtable(L);
lua_pushnumber(L, 42);
lua_setfield(L, -2, "pi");
lua_setfield(L, -2, XorStr("pi"));
lua_setfenv(L, -2);
lua_call(L, 0, 1);
@ -834,12 +825,12 @@ TEST_CASE("ApiCalls")
// lua_clonefunction + upvalues
{
lua_getfield(L, LUA_GLOBALSINDEX, "incuv");
lua_getfield(L, LUA_GLOBALSINDEX, XorStr("incuv"));
lua_call(L, 0, 1);
CHECK(lua_tonumber(L, -1) == 1);
lua_pop(L, 1);
lua_getfield(L, LUA_GLOBALSINDEX, "incuv");
lua_getfield(L, LUA_GLOBALSINDEX, XorStr("incuv"));
// two clones
lua_clonefunction(L, -1);
lua_clonefunction(L, -2);
@ -859,41 +850,6 @@ TEST_CASE("ApiCalls")
}
}
TEST_CASE("ApiAtoms")
{
StateRef globalState(luaL_newstate(), lua_close);
lua_State* L = globalState.get();
lua_callbacks(L)->useratom = [](const char* s, size_t l) -> int16_t {
if (strcmp(s, "string") == 0)
return 0;
if (strcmp(s, "important") == 0)
return 1;
return -1;
};
lua_pushstring(L, "string");
lua_pushstring(L, "import");
lua_pushstring(L, "ant");
lua_concat(L, 2);
lua_pushstring(L, "unimportant");
int a1, a2, a3;
const char* s1 = lua_tostringatom(L, -3, &a1);
const char* s2 = lua_tostringatom(L, -2, &a2);
const char* s3 = lua_tostringatom(L, -1, &a3);
CHECK(strcmp(s1, "string") == 0);
CHECK(a1 == 0);
CHECK(strcmp(s2, "important") == 0);
CHECK(a2 == 1);
CHECK(strcmp(s3, "unimportant") == 0);
CHECK(a3 == -1);
}
static bool endsWith(const std::string& str, const std::string& suffix)
{
if (suffix.length() > str.length())
@ -924,7 +880,7 @@ TEST_CASE("ExceptionObject")
CHECK(e.what() != nullptr);
return ExceptionResult{true, e.what()};
}
return ExceptionResult{false, ""};
return ExceptionResult{false, XorStr("")};
};
auto reallocFunc = [](void* /*ud*/, void* ptr, size_t /*osize*/, size_t nsize) -> void* {
@ -950,34 +906,34 @@ TEST_CASE("ExceptionObject")
lua_State* L = globalState.get();
{
ExceptionResult result = captureException(L, "infinite_recursion_error");
ExceptionResult result = captureException(L, XorStr("infinite_recursion_error"));
CHECK(result.exceptionGenerated);
}
{
ExceptionResult result = captureException(L, "empty_function");
ExceptionResult result = captureException(L, XorStr("empty_function"));
CHECK_FALSE(result.exceptionGenerated);
}
{
ExceptionResult result = captureException(L, "pass_number_to_error");
ExceptionResult result = captureException(L, XorStr("pass_number_to_error"));
CHECK(result.exceptionGenerated);
CHECK(endsWith(result.description, "42"));
}
{
ExceptionResult result = captureException(L, "pass_string_to_error");
ExceptionResult result = captureException(L, XorStr("pass_string_to_error"));
CHECK(result.exceptionGenerated);
CHECK(endsWith(result.description, "string argument"));
}
{
ExceptionResult result = captureException(L, "pass_table_to_error");
ExceptionResult result = captureException(L, XorStr("pass_table_to_error"));
CHECK(result.exceptionGenerated);
}
{
ExceptionResult result = captureException(L, "large_allocation_error");
ExceptionResult result = captureException(L, XorStr("large_allocation_error"));
CHECK(result.exceptionGenerated);
}
}
@ -985,7 +941,7 @@ TEST_CASE("ExceptionObject")
TEST_CASE("IfElseExpression")
{
runConformance("ifelseexpr.lua");
runConformance(XorStr("ifelseexpr.lua"));
}
TEST_CASE("TagMethodError")
@ -1001,8 +957,9 @@ TEST_CASE("TagMethodError")
TEST_CASE("Coverage")
{
lua_CompileOptions copts = defaultOptions();
copts.optimizationLevel = 1; // disable inlining to get fixed expected hit results
lua_CompileOptions copts = {};
copts.optimizationLevel = 1;
copts.debugLevel = 1;
copts.coverageLevel = 2;
runConformance(
@ -1011,7 +968,7 @@ TEST_CASE("Coverage")
lua_pushcfunction(
L,
[](lua_State* L) -> int {
luaL_argexpected(L, lua_isLfunction(L, 1), 1, "function");
luaL_argexpected(L, lua_isLfunction(L, 1), 1, XorStr("function"));
lua_newtable(L);
lua_getcoverage(L, 1, L, [](void* context, const char* function, int linedefined, int depth, const int* hits, size_t size) {
@ -1020,13 +977,13 @@ TEST_CASE("Coverage")
lua_newtable(L);
lua_pushstring(L, function);
lua_setfield(L, -2, "name");
lua_setfield(L, -2, XorStr("name"));
lua_pushinteger(L, linedefined);
lua_setfield(L, -2, "linedefined");
lua_setfield(L, -2, XorStr("linedefined"));
lua_pushinteger(L, depth);
lua_setfield(L, -2, "depth");
lua_setfield(L, -2, XorStr("depth"));
for (size_t i = 0; i < size; ++i)
if (hits[i] != -1)
@ -1040,15 +997,15 @@ TEST_CASE("Coverage")
return 1;
},
"getcoverage");
lua_setglobal(L, "getcoverage");
XorStr("getcoverage"));
lua_setglobal(L, XorStr("getcoverage"));
},
nullptr, nullptr, &copts);
}
TEST_CASE("StringConversion")
{
runConformance("strconv.lua");
runConformance(XorStr("strconv.lua"));
}
TEST_CASE("GCDump")
@ -1061,8 +1018,8 @@ TEST_CASE("GCDump")
// push various objects on stack to cover different paths
lua_createtable(L, 1, 2);
lua_pushstring(L, "value");
lua_setfield(L, -2, "key");
lua_pushstring(L, XorStr("value"));
lua_setfield(L, -2, XorStr("key"));
lua_pushinteger(L, 42);
lua_rawseti(L, -2, 1000);
@ -1082,7 +1039,7 @@ TEST_CASE("GCDump")
lua_State* CL = lua_newthread(L);
lua_pushstring(CL, "local x x = {} local function f() x[1] = math.abs(42) end function foo() coroutine.yield() end foo() return f");
lua_pushstring(CL, XorStr("local x x = {} local function f() x[1] = math.abs(42) end function foo() coroutine.yield() end foo() return f"));
lua_loadstring(CL);
lua_resume(CL, nullptr, 0);
@ -1092,7 +1049,7 @@ TEST_CASE("GCDump")
const char* path = "/dev/null";
#endif
FILE* f = fopen(path, "w");
FILE* f = fopen(path, XorStr("w"));
REQUIRE(f);
luaC_dump(L, f, nullptr);
@ -1102,9 +1059,6 @@ TEST_CASE("GCDump")
TEST_CASE("Interrupt")
{
lua_CompileOptions copts = defaultOptions();
copts.optimizationLevel = 1; // disable loop unrolling to get fixed expected hit results
static const int expectedhits[] = {
2,
9,
@ -1155,8 +1109,7 @@ TEST_CASE("Interrupt")
},
[](lua_State* L) {
CHECK(index == 5); // a single yield point
},
nullptr, &copts);
});
CHECK(index == int(std::size(expectedhits)));
}
@ -1199,10 +1152,6 @@ TEST_CASE("UserdataApi")
CHECK(lua_touserdatatagged(L, -1, 41) == nullptr);
CHECK(lua_userdatatag(L, -1) == 42);
lua_setuserdatatag(L, -1, 43);
CHECK(lua_userdatatag(L, -1) == 43);
lua_setuserdatatag(L, -1, 42);
// user data with inline dtor
void* ud3 = lua_newuserdatadtor(L, 4, [](void* data) {
dtorhits += *(int*)data;
@ -1222,7 +1171,7 @@ TEST_CASE("UserdataApi")
TEST_CASE("Iter")
{
runConformance("iter.lua");
runConformance(XorStr("iter.lua"));
}
const int kInt64Tag = 1;
@ -1236,7 +1185,7 @@ static int64_t getInt64(lua_State* L, int idx)
if (lua_isnumber(L, idx))
return lua_tointeger(L, idx);
luaL_typeerror(L, 1, "int64");
luaL_typeerror(L, 1, XorStr("int64"));
}
static void pushInt64(lua_State* L, int64_t value)
@ -1262,7 +1211,7 @@ TEST_CASE("Userdata")
[](lua_State* L) {
void* p = lua_touserdatatagged(L, 1, kInt64Tag);
if (!p)
luaL_typeerror(L, 1, "int64");
luaL_typeerror(L, 1, XorStr("int64"));
const char* name = luaL_checkstring(L, 2);
@ -1272,10 +1221,10 @@ TEST_CASE("Userdata")
return 1;
}
luaL_error(L, "unknown field %s", name);
luaL_error(L, XorStr("unknown field %s"), name);
},
nullptr);
lua_setfield(L, -2, "__index");
lua_setfield(L, -2, XorStr("__index"));
// __newindex
lua_pushcfunction(
@ -1283,7 +1232,7 @@ TEST_CASE("Userdata")
[](lua_State* L) {
void* p = lua_touserdatatagged(L, 1, kInt64Tag);
if (!p)
luaL_typeerror(L, 1, "int64");
luaL_typeerror(L, 1, XorStr("int64"));
const char* name = luaL_checkstring(L, 2);
@ -1294,10 +1243,10 @@ TEST_CASE("Userdata")
return 0;
}
luaL_error(L, "unknown field %s", name);
luaL_error(L, XorStr("unknown field %s"), name);
},
nullptr);
lua_setfield(L, -2, "__newindex");
lua_setfield(L, -2, XorStr("__newindex"));
// __eq
lua_pushcfunction(
@ -1307,7 +1256,7 @@ TEST_CASE("Userdata")
return 1;
},
nullptr);
lua_setfield(L, -2, "__eq");
lua_setfield(L, -2, XorStr("__eq"));
// __lt
lua_pushcfunction(
@ -1317,7 +1266,7 @@ TEST_CASE("Userdata")
return 1;
},
nullptr);
lua_setfield(L, -2, "__lt");
lua_setfield(L, -2, XorStr("__lt"));
// __le
lua_pushcfunction(
@ -1327,7 +1276,7 @@ TEST_CASE("Userdata")
return 1;
},
nullptr);
lua_setfield(L, -2, "__le");
lua_setfield(L, -2, XorStr("__le"));
// __add
lua_pushcfunction(
@ -1337,7 +1286,7 @@ TEST_CASE("Userdata")
return 1;
},
nullptr);
lua_setfield(L, -2, "__add");
lua_setfield(L, -2, XorStr("__add"));
// __sub
lua_pushcfunction(
@ -1347,7 +1296,7 @@ TEST_CASE("Userdata")
return 1;
},
nullptr);
lua_setfield(L, -2, "__sub");
lua_setfield(L, -2, XorStr("__sub"));
// __mul
lua_pushcfunction(
@ -1357,7 +1306,7 @@ TEST_CASE("Userdata")
return 1;
},
nullptr);
lua_setfield(L, -2, "__mul");
lua_setfield(L, -2, XorStr("__mul"));
// __div
lua_pushcfunction(
@ -1368,7 +1317,7 @@ TEST_CASE("Userdata")
return 1;
},
nullptr);
lua_setfield(L, -2, "__div");
lua_setfield(L, -2, XorStr("__div"));
// __mod
lua_pushcfunction(
@ -1379,7 +1328,7 @@ TEST_CASE("Userdata")
return 1;
},
nullptr);
lua_setfield(L, -2, "__mod");
lua_setfield(L, -2, XorStr("__mod"));
// __pow
lua_pushcfunction(
@ -1389,7 +1338,7 @@ TEST_CASE("Userdata")
return 1;
},
nullptr);
lua_setfield(L, -2, "__pow");
lua_setfield(L, -2, XorStr("__pow"));
// __unm
lua_pushcfunction(
@ -1399,7 +1348,7 @@ TEST_CASE("Userdata")
return 1;
},
nullptr);
lua_setfield(L, -2, "__unm");
lua_setfield(L, -2, XorStr("__unm"));
// __tostring
lua_pushcfunction(
@ -1411,7 +1360,7 @@ TEST_CASE("Userdata")
return 1;
},
nullptr);
lua_setfield(L, -2, "__tostring");
lua_setfield(L, -2, XorStr("__tostring"));
// ctor
lua_pushcfunction(
@ -1421,8 +1370,8 @@ TEST_CASE("Userdata")
pushInt64(L, int64_t(v));
return 1;
},
"int64");
lua_setglobal(L, "int64");
XorStr("int64"));
lua_setglobal(L, XorStr("int64"));
});
}

View file

@ -1,13 +1,13 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Fixture.h"
#include "Luau/ConstraintGraphBuilder.h"
#include "lluz/ConstraintGraphBuilder.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("ConstraintGraphBuilder");
TEST_SUITE_BEGIN(XorStr("ConstraintGraphBuilder"));
TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "hello_world")
{

View file

@ -1,22 +1,22 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Fixture.h"
#include "doctest.h"
#include "Luau/ConstraintGraphBuilder.h"
#include "Luau/ConstraintSolver.h"
#include "lluz/ConstraintGraphBuilder.h"
#include "lluz/ConstraintSolver.h"
using namespace Luau;
using namespace lluz;
static TypeId requireBinding(NotNull<Scope> scope, const char* name)
static TypeId requireBinding(NotNull<Scope2> scope, const char* name)
{
auto b = linearSearchForBinding(scope, name);
LUAU_ASSERT(b.has_value());
lluz_ASSERT(b.has_value());
return *b;
}
TEST_SUITE_BEGIN("ConstraintSolver");
TEST_SUITE_BEGIN(XorStr("ConstraintSolver"));
TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "hello")
{
@ -26,13 +26,13 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "hello")
)");
cgb.visit(block);
NotNull<Scope> rootScope = NotNull(cgb.rootScope);
NotNull<Scope2> rootScope = NotNull(cgb.rootScope);
ConstraintSolver cs{&arena, rootScope};
cs.run();
TypeId bType = requireBinding(rootScope, "b");
TypeId bType = requireBinding(rootScope, XorStr("b"));
CHECK("number" == toString(bType));
}
@ -46,13 +46,13 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "generic_function")
)");
cgb.visit(block);
NotNull<Scope> rootScope = NotNull(cgb.rootScope);
NotNull<Scope2> rootScope = NotNull(cgb.rootScope);
ConstraintSolver cs{&arena, rootScope};
cs.run();
TypeId idType = requireBinding(rootScope, "id");
TypeId idType = requireBinding(rootScope, XorStr("id"));
CHECK("<a>(a) -> a" == toString(idType));
}
@ -73,7 +73,7 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "proper_let_generalization")
)");
cgb.visit(block);
NotNull<Scope> rootScope = NotNull(cgb.rootScope);
NotNull<Scope2> rootScope = NotNull(cgb.rootScope);
ToStringOptions opts;
@ -81,7 +81,7 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "proper_let_generalization")
cs.run();
TypeId idType = requireBinding(rootScope, "b");
TypeId idType = requireBinding(rootScope, XorStr("b"));
CHECK("<a>(a) -> number" == toString(idType, opts));
}

View file

@ -1,22 +1,22 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Parser.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Parser.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
namespace Luau
namespace lluz
{
namespace Compile
{
uint64_t modelCost(AstNode* root, AstLocal* const* vars, size_t varCount, const DenseHashMap<AstExprCall*, int>& builtins);
uint64_t modelCost(AstNode* root, AstLocal* const* vars, size_t varCount);
int computeCost(uint64_t model, const bool* varsConst, size_t varCount);
} // namespace Compile
} // namespace Luau
} // namespace lluz
TEST_SUITE_BEGIN("CostModel");
TEST_SUITE_BEGIN(XorStr("CostModel"));
static uint64_t modelFunction(const char* source)
{
@ -29,7 +29,7 @@ static uint64_t modelFunction(const char* source)
AstStatFunction* func = result.root->body.data[0]->as<AstStatFunction>();
REQUIRE(func);
return Luau::Compile::modelCost(func->func->body, func->func->args.data, func->func->args.size, {nullptr});
return lluz::Compile::modelCost(func->func->body, func->func->args.data, func->func->args.size);
}
TEST_CASE("Expression")
@ -43,8 +43,8 @@ end
const bool args1[] = {false, false, false};
const bool args2[] = {false, true, false};
CHECK_EQ(5, Luau::Compile::computeCost(model, args1, 3));
CHECK_EQ(2, Luau::Compile::computeCost(model, args2, 3));
CHECK_EQ(5, lluz::Compile::computeCost(model, args1, 3));
CHECK_EQ(2, lluz::Compile::computeCost(model, args2, 3));
}
TEST_CASE("PropagateVariable")
@ -59,8 +59,8 @@ end
const bool args1[] = {false};
const bool args2[] = {true};
CHECK_EQ(3, Luau::Compile::computeCost(model, args1, 1));
CHECK_EQ(0, Luau::Compile::computeCost(model, args2, 1));
CHECK_EQ(3, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(0, lluz::Compile::computeCost(model, args2, 1));
}
TEST_CASE("LoopAssign")
@ -77,8 +77,8 @@ end
const bool args2[] = {true};
// loop baseline cost is 5
CHECK_EQ(6, Luau::Compile::computeCost(model, args1, 1));
CHECK_EQ(6, Luau::Compile::computeCost(model, args2, 1));
CHECK_EQ(6, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(6, lluz::Compile::computeCost(model, args2, 1));
}
TEST_CASE("MutableVariable")
@ -94,8 +94,8 @@ end
const bool args1[] = {false};
const bool args2[] = {true};
CHECK_EQ(3, Luau::Compile::computeCost(model, args1, 1));
CHECK_EQ(2, Luau::Compile::computeCost(model, args2, 1));
CHECK_EQ(3, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(2, lluz::Compile::computeCost(model, args2, 1));
}
TEST_CASE("ImportCall")
@ -109,8 +109,8 @@ end
const bool args1[] = {false};
const bool args2[] = {true};
CHECK_EQ(6, Luau::Compile::computeCost(model, args1, 1));
CHECK_EQ(6, Luau::Compile::computeCost(model, args2, 1));
CHECK_EQ(6, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(6, lluz::Compile::computeCost(model, args2, 1));
}
TEST_CASE("FastCall")
@ -125,8 +125,8 @@ end
const bool args2[] = {true};
// note: we currently don't treat fast calls differently from cost model perspective
CHECK_EQ(6, Luau::Compile::computeCost(model, args1, 1));
CHECK_EQ(5, Luau::Compile::computeCost(model, args2, 1));
CHECK_EQ(6, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(5, lluz::Compile::computeCost(model, args2, 1));
}
TEST_CASE("ControlFlow")
@ -154,8 +154,8 @@ end
const bool args1[] = {false};
const bool args2[] = {true};
CHECK_EQ(82, Luau::Compile::computeCost(model, args1, 1));
CHECK_EQ(79, Luau::Compile::computeCost(model, args2, 1));
CHECK_EQ(82, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(79, lluz::Compile::computeCost(model, args2, 1));
}
TEST_CASE("Conditional")
@ -169,8 +169,8 @@ end
const bool args1[] = {false};
const bool args2[] = {true};
CHECK_EQ(4, Luau::Compile::computeCost(model, args1, 1));
CHECK_EQ(2, Luau::Compile::computeCost(model, args2, 1));
CHECK_EQ(4, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(2, lluz::Compile::computeCost(model, args2, 1));
}
TEST_CASE("VarArgs")
@ -181,7 +181,7 @@ function test(...)
end
)");
CHECK_EQ(8, Luau::Compile::computeCost(model, nullptr, 0));
CHECK_EQ(8, lluz::Compile::computeCost(model, nullptr, 0));
}
TEST_CASE("TablesFunctions")
@ -192,7 +192,7 @@ function test()
end
)");
CHECK_EQ(22, Luau::Compile::computeCost(model, nullptr, 0));
CHECK_EQ(22, lluz::Compile::computeCost(model, nullptr, 0));
}
TEST_CASE("CostOverflow")
@ -203,7 +203,7 @@ function test()
end
)");
CHECK_EQ(127, Luau::Compile::computeCost(model, nullptr, 0));
CHECK_EQ(127, lluz::Compile::computeCost(model, nullptr, 0));
}
TEST_CASE("TableAssign")
@ -219,8 +219,8 @@ end
const bool args1[] = {false};
const bool args2[] = {true};
CHECK_EQ(7, Luau::Compile::computeCost(model, args1, 1));
CHECK_EQ(6, Luau::Compile::computeCost(model, args2, 1));
CHECK_EQ(7, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(6, lluz::Compile::computeCost(model, args2, 1));
}
TEST_SUITE_END();

View file

@ -1,11 +1,11 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Error.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Error.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("ErrorTests");
TEST_SUITE_BEGIN(XorStr("ErrorTests"));
TEST_CASE("TypeError_code_should_return_nonzero_code")
{

View file

@ -1,13 +1,13 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Fixture.h"
#include "Luau/AstQuery.h"
#include "Luau/Parser.h"
#include "Luau/TypeVar.h"
#include "Luau/TypeAttach.h"
#include "Luau/Transpiler.h"
#include "lluz/AstQuery.h"
#include "lluz/Parser.h"
#include "lluz/TypeVar.h"
#include "lluz/TypeAttach.h"
#include "lluz/Transpiler.h"
#include "Luau/BuiltinDefinitions.h"
#include "lluz/BuiltinDefinitions.h"
#include "doctest.h"
@ -17,25 +17,25 @@
static const char* mainModuleName = "MainModule";
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution);
lluz_FASTFLAG(DebugLluDeferredConstraintResolution);
namespace Luau
namespace lluz
{
std::optional<ModuleInfo> TestFileResolver::resolveModule(const ModuleInfo* context, AstExpr* expr)
{
if (AstExprGlobal* g = expr->as<AstExprGlobal>())
{
if (g->name == "game")
if (g->name == XorStr("game"))
return ModuleInfo{"game"};
if (g->name == "workspace")
if (g->name == XorStr("workspace"))
return ModuleInfo{"workspace"};
if (g->name == "script")
if (g->name == XorStr("script"))
return context ? std::optional<ModuleInfo>(*context) : std::nullopt;
}
else if (AstExprIndexName* i = expr->as<AstExprIndexName>(); i && context)
{
if (i->index == "Parent")
if (i->index == XorStr("Parent"))
{
std::string_view view = context->name;
size_t lastSeparatorIndex = view.find_last_of('/');
@ -63,7 +63,7 @@ std::optional<ModuleInfo> TestFileResolver::resolveModule(const ModuleInfo* cont
{
AstName func = call->func->as<AstExprIndexName>()->index;
if (func == "GetService" && context->name == "game")
if (func == XorStr("GetService") && context->name == XorStr("game"))
return ModuleInfo{"game/" + std::string(index->value.data, index->value.size)};
}
}
@ -86,7 +86,7 @@ std::optional<std::string> TestFileResolver::getEnvironmentForModule(const Modul
}
Fixture::Fixture(bool freeze, bool prepareAutocomplete)
: sff_DebugLuauFreezeArena("DebugLuauFreezeArena", freeze)
: sff_DebuglluzFreezeArena("DebuglluzFreezeArena", freeze)
, frontend(&fileResolver, &configResolver, {/* retainFullTypeGraphs= */ true})
, typeChecker(frontend.typeChecker)
{
@ -94,15 +94,15 @@ Fixture::Fixture(bool freeze, bool prepareAutocomplete)
configResolver.defaultConfig.enabledLint.warningMask = ~0ull;
configResolver.defaultConfig.parseOptions.captureComments = true;
Luau::freeze(frontend.typeChecker.globalTypes);
Luau::freeze(frontend.typeCheckerForAutocomplete.globalTypes);
lluz::freeze(frontend.typeChecker.globalTypes);
lluz::freeze(frontend.typeCheckerForAutocomplete.globalTypes);
Luau::setPrintLine([](auto s) {});
lluz::setPrintLine([](auto s) {});
}
Fixture::~Fixture()
{
Luau::resetPrintLine();
lluz::resetPrintLine();
}
AstStatBlock* Fixture::parse(const std::string& source, const ParseOptions& parseOptions)
@ -123,7 +123,7 @@ AstStatBlock* Fixture::parse(const std::string& source, const ParseOptions& pars
{
frontend.lint(*sourceModule);
typeChecker.check(*sourceModule, sourceModule->mode.value_or(Luau::Mode::Nonstrict));
typeChecker.check(*sourceModule, sourceModule->mode.value_or(lluz::Mode::Nonstrict));
}
throw ParseErrors(result.errors);
@ -195,7 +195,7 @@ ParseResult Fixture::matchParseError(const std::string& source, const std::strin
sourceModule.reset(new SourceModule);
ParseResult result = Parser::parse(source.c_str(), source.length(), *sourceModule->names, *sourceModule->allocator, options);
CHECK_MESSAGE(!result.errors.empty(), "Expected a parse error in '" << source << "'");
CHECK_MESSAGE(!result.errors.empty(), XorStr("Expected a parse error in '" << source << "'"));
if (!result.errors.empty())
{
@ -216,7 +216,7 @@ ParseResult Fixture::matchParseErrorPrefix(const std::string& source, const std:
sourceModule.reset(new SourceModule);
ParseResult result = Parser::parse(source.c_str(), source.length(), *sourceModule->names, *sourceModule->allocator, options);
CHECK_MESSAGE(!result.errors.empty(), "Expected a parse error in '" << source << "'");
CHECK_MESSAGE(!result.errors.empty(), XorStr("Expected a parse error in '" << source << "'"));
if (!result.errors.empty())
{
@ -257,8 +257,8 @@ std::optional<TypeId> Fixture::getType(const std::string& name)
ModulePtr module = getMainModule();
REQUIRE(module);
if (FFlag::DebugLuauDeferredConstraintResolution)
return linearSearchForBinding(module->getModuleScope().get(), name.c_str());
if (FFlag::DebugLluDeferredConstraintResolution)
return linearSearchForBinding(module->getModuleScope2(), name.c_str());
else
return lookupName(module->getModuleScope(), name);
}
@ -266,7 +266,7 @@ std::optional<TypeId> Fixture::getType(const std::string& name)
TypeId Fixture::requireType(const std::string& name)
{
std::optional<TypeId> ty = getType(name);
REQUIRE_MESSAGE(bool(ty), "Unable to requireType \"" << name << "\"");
REQUIRE_MESSAGE(bool(ty), XorStr("Unable to requireType \"" << name << "\""));
return follow(*ty);
}
@ -285,7 +285,7 @@ TypeId Fixture::requireType(const ModulePtr& module, const std::string& name)
TypeId Fixture::requireType(const ScopePtr& scope, const std::string& name)
{
std::optional<TypeId> ty = lookupName(scope, name);
REQUIRE_MESSAGE(ty, "requireType: No type \"" << name << "\"");
REQUIRE_MESSAGE(ty, XorStr("requireType: No type \"" << name << "\""));
return *ty;
}
@ -293,14 +293,14 @@ std::optional<TypeId> Fixture::findTypeAtPosition(Position position)
{
ModulePtr module = getMainModule();
SourceModule* sourceModule = getMainSourceModule();
return Luau::findTypeAtPosition(*module, *sourceModule, position);
return lluz::findTypeAtPosition(*module, *sourceModule, position);
}
std::optional<TypeId> Fixture::findExpectedTypeAtPosition(Position position)
{
ModulePtr module = getMainModule();
SourceModule* sourceModule = getMainSourceModule();
return Luau::findExpectedTypeAtPosition(*module, *sourceModule, position);
return lluz::findExpectedTypeAtPosition(*module, *sourceModule, position);
}
TypeId Fixture::requireTypeAtPosition(Position position)
@ -330,7 +330,7 @@ std::string Fixture::decorateWithTypes(const std::string& code)
{
fileResolver.source[mainModuleName] = code;
Luau::CheckResult typeInfo = frontend.check(mainModuleName);
lluz::CheckResult typeInfo = frontend.check(mainModuleName);
SourceModule* sourceModule = frontend.getSourceModule(mainModuleName);
attachTypeData(*sourceModule, *frontend.moduleResolver.getModule(mainModuleName));
@ -346,7 +346,7 @@ void Fixture::dumpErrors(std::ostream& os, const std::vector<TypeError>& errors)
os << "Error: " << error << std::endl;
std::string_view source = fileResolver.source[error.moduleName];
std::vector<std::string_view> lines = Luau::split(source, '\n');
std::vector<std::string_view> lines = lluz::split(source, '\n');
if (error.location.begin.line >= lines.size())
{
@ -365,9 +365,9 @@ void Fixture::dumpErrors(std::ostream& os, const std::vector<TypeError>& errors)
void Fixture::registerTestTypes()
{
addGlobalBinding(typeChecker, "game", typeChecker.anyType, "@luau");
addGlobalBinding(typeChecker, "workspace", typeChecker.anyType, "@luau");
addGlobalBinding(typeChecker, "script", typeChecker.anyType, "@luau");
addGlobalBinding(typeChecker, XorStr("game", typeChecker.anyType, "@lluz"));
addGlobalBinding(typeChecker, XorStr("workspace", typeChecker.anyType, "@lluz"));
addGlobalBinding(typeChecker, XorStr("script", typeChecker.anyType, "@lluz"));
}
void Fixture::dumpErrors(const CheckResult& cr)
@ -392,13 +392,13 @@ std::string Fixture::getErrors(const CheckResult& cr)
return ss.str();
}
void Fixture::validateErrors(const std::vector<Luau::TypeError>& errors)
void Fixture::validateErrors(const std::vector<lluz::TypeError>& errors)
{
std::ostringstream oss;
// This helps us validate that error stringification doesn't crash, using both user-facing and internal test-only representation
// Also we exercise error comparison to make sure it's at least able to compare the error equal to itself
for (const Luau::TypeError& e : errors)
for (const lluz::TypeError& e : errors)
{
oss.clear();
oss << e;
@ -410,32 +410,32 @@ void Fixture::validateErrors(const std::vector<Luau::TypeError>& errors)
LoadDefinitionFileResult Fixture::loadDefinition(const std::string& source)
{
unfreeze(typeChecker.globalTypes);
LoadDefinitionFileResult result = loadDefinitionFile(typeChecker, typeChecker.globalScope, source, "@test");
LoadDefinitionFileResult result = loadDefinitionFile(typeChecker, typeChecker.globalScope, source, XorStr("@test"));
freeze(typeChecker.globalTypes);
REQUIRE_MESSAGE(result.success, "loadDefinition: unable to load definition file");
REQUIRE_MESSAGE(result.success, XorStr("loadDefinition: unable to load definition file"));
return result;
}
BuiltinsFixture::BuiltinsFixture(bool freeze, bool prepareAutocomplete)
: Fixture(freeze, prepareAutocomplete)
{
Luau::unfreeze(frontend.typeChecker.globalTypes);
Luau::unfreeze(frontend.typeCheckerForAutocomplete.globalTypes);
lluz::unfreeze(frontend.typeChecker.globalTypes);
lluz::unfreeze(frontend.typeCheckerForAutocomplete.globalTypes);
registerBuiltinTypes(frontend.typeChecker);
if (prepareAutocomplete)
registerBuiltinTypes(frontend.typeCheckerForAutocomplete);
registerTestTypes();
Luau::freeze(frontend.typeChecker.globalTypes);
Luau::freeze(frontend.typeCheckerForAutocomplete.globalTypes);
lluz::freeze(frontend.typeChecker.globalTypes);
lluz::freeze(frontend.typeCheckerForAutocomplete.globalTypes);
}
ConstraintGraphBuilderFixture::ConstraintGraphBuilderFixture()
: Fixture()
, cgb(mainModuleName, &arena, NotNull(&ice), frontend.getGlobalScope())
, forceTheFlag{"DebugLuauDeferredConstraintResolution", true}
, cgb(mainModuleName, &arena, NotNull(&ice), frontend.getGlobalScope2())
, forceTheFlag{"DebuglluzDeferredConstraintResolution", true}
{
BlockedTypeVar::nextIndex = 0;
}
@ -479,17 +479,17 @@ std::optional<TypeId> lookupName(ScopePtr scope, const std::string& name)
return std::nullopt;
}
std::optional<TypeId> linearSearchForBinding(Scope* scope, const char* name)
std::optional<TypeId> linearSearchForBinding(Scope2* scope, const char* name)
{
while (scope)
{
for (const auto& [n, ty] : scope->bindings)
{
if (n.astName() == name)
return ty.typeId;
return ty;
}
scope = scope->parent.get();
scope = scope->parent;
}
return std::nullopt;
@ -502,4 +502,4 @@ void dump(const std::vector<Constraint>& constraints)
printf("%s\n", toString(c, opts).c_str());
}
} // namespace Luau
} // namespace lluz

View file

@ -1,17 +1,17 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
#include "Luau/Config.h"
#include "Luau/FileResolver.h"
#include "Luau/Frontend.h"
#include "Luau/IostreamHelpers.h"
#include "Luau/Linter.h"
#include "Luau/Location.h"
#include "Luau/ModuleResolver.h"
#include "Luau/Scope.h"
#include "Luau/ToString.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "lluz/Config.h"
#include "lluz/FileResolver.h"
#include "lluz/Frontend.h"
#include "lluz/IostreamHelpers.h"
#include "lluz/Linter.h"
#include "lluz/Location.h"
#include "lluz/ModuleResolver.h"
#include "lluz/Scope.h"
#include "lluz/ToString.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "IostreamOptional.h"
#include "ScopedFlags.h"
@ -22,7 +22,7 @@
#include <optional>
namespace Luau
namespace lluz
{
struct TestFileResolver
@ -39,7 +39,7 @@ struct TestFileResolver
const ModulePtr getModule(const ModuleName& moduleName) const override
{
LUAU_ASSERT(false);
lluz_ASSERT(false);
return nullptr;
}
@ -95,7 +95,7 @@ struct Fixture
explicit Fixture(bool freeze = true, bool prepareAutocomplete = false);
~Fixture();
// Throws Luau::ParseErrors if the parse fails.
// Throws lluz::ParseErrors if the parse fails.
AstStatBlock* parse(const std::string& source, const ParseOptions& parseOptions = {});
CheckResult check(Mode mode, std::string source);
CheckResult check(const std::string& source);
@ -127,8 +127,7 @@ struct Fixture
std::optional<TypeId> lookupType(const std::string& name);
std::optional<TypeId> lookupImportedType(const std::string& moduleAlias, const std::string& name);
ScopedFastFlag sff_DebugLuauFreezeArena;
ScopedFastFlag sff_UnknownNever{"LuauUnknownAndNeverType", true};
ScopedFastFlag sff_DebuglluzFreezeArena;
TestFileResolver fileResolver;
TestConfigResolver configResolver;
@ -192,11 +191,11 @@ void dump(const std::vector<Constraint>& constraints);
std::optional<TypeId> lookupName(ScopePtr scope, const std::string& name); // Warning: This function runs in O(n**2)
std::optional<TypeId> linearSearchForBinding(Scope* scope, const char* name);
std::optional<TypeId> linearSearchForBinding(Scope2* scope, const char* name);
} // namespace Luau
} // namespace lluz
#define LUAU_REQUIRE_ERRORS(result) \
#define lluz_REQUIRE_ERRORS(result) \
do \
{ \
auto&& r = (result); \
@ -204,7 +203,7 @@ std::optional<TypeId> linearSearchForBinding(Scope* scope, const char* name);
REQUIRE(!r.errors.empty()); \
} while (false)
#define LUAU_REQUIRE_ERROR_COUNT(count, result) \
#define lluz_REQUIRE_ERROR_COUNT(count, result) \
do \
{ \
auto&& r = (result); \
@ -212,4 +211,4 @@ std::optional<TypeId> linearSearchForBinding(Scope* scope, const char* name);
REQUIRE_MESSAGE(count == r.errors.size(), getErrors(r)); \
} while (false)
#define LUAU_REQUIRE_NO_ERRORS(result) LUAU_REQUIRE_ERROR_COUNT(0, result)
#define lluz_REQUIRE_NO_ERRORS(result) lluz_REQUIRE_ERROR_COUNT(0, result)

View file

@ -1,8 +1,8 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/AstQuery.h"
#include "Luau/BuiltinDefinitions.h"
#include "Luau/Frontend.h"
#include "Luau/RequireTracer.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/AstQuery.h"
#include "lluz/BuiltinDefinitions.h"
#include "lluz/Frontend.h"
#include "lluz/RequireTracer.h"
#include "Fixture.h"
@ -10,7 +10,7 @@
#include <algorithm>
using namespace Luau;
using namespace lluz;
namespace
{
@ -49,10 +49,10 @@ struct NaiveFileResolver : NullFileResolver
{
if (AstExprGlobal* g = expr->as<AstExprGlobal>())
{
if (g->name == "Modules")
if (g->name == XorStr("Modules"))
return ModuleInfo{"Modules"};
if (g->name == "game")
if (g->name == XorStr("game"))
return ModuleInfo{"game"};
}
else if (AstExprIndexName* i = expr->as<AstExprIndexName>())
@ -66,7 +66,7 @@ struct NaiveFileResolver : NullFileResolver
{
AstName func = call->func->as<AstExprIndexName>()->index;
if (func == "GetService" && context->name == "game")
if (func == XorStr("GetService") && context->name == XorStr("game"))
return ModuleInfo{"game/" + std::string(index->value.data, index->value.size)};
}
}
@ -81,12 +81,12 @@ struct FrontendFixture : BuiltinsFixture
{
FrontendFixture()
{
addGlobalBinding(typeChecker, "game", frontend.typeChecker.anyType, "@test");
addGlobalBinding(typeChecker, "script", frontend.typeChecker.anyType, "@test");
addGlobalBinding(typeChecker, XorStr("game", frontend.typeChecker.anyType, "@test"));
addGlobalBinding(typeChecker, XorStr("script", frontend.typeChecker.anyType, "@test"));
}
};
TEST_SUITE_BEGIN("FrontendTest");
TEST_SUITE_BEGIN(XorStr("FrontendTest"));
TEST_CASE_FIXTURE(FrontendFixture, "find_a_require")
{
@ -96,9 +96,9 @@ TEST_CASE_FIXTURE(FrontendFixture, "find_a_require")
NaiveFileResolver naiveFileResolver;
auto res = traceRequires(&naiveFileResolver, program, "");
auto res = traceRequires(&naiveFileResolver, program, XorStr(""));
CHECK_EQ(1, res.requireList.size());
CHECK_EQ(res.requireList[0].first, "Modules/Foo/Bar");
CHECK_EQ(res.requireList[0].first, XorStr("Modules/Foo/Bar"));
}
// It could be argued that this should not work.
@ -112,7 +112,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "find_a_require_inside_a_function")
NaiveFileResolver naiveFileResolver;
auto res = traceRequires(&naiveFileResolver, program, "");
auto res = traceRequires(&naiveFileResolver, program, XorStr(""));
CHECK_EQ(1, res.requireList.size());
}
@ -137,7 +137,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "real_source")
NaiveFileResolver naiveFileResolver;
auto res = traceRequires(&naiveFileResolver, program, "");
auto res = traceRequires(&naiveFileResolver, program, XorStr(""));
CHECK_EQ(8, res.requireList.size());
}
@ -150,12 +150,12 @@ TEST_CASE_FIXTURE(FrontendFixture, "automatically_check_dependent_scripts")
return {b_value = A.hello}
)";
frontend.check("game/Gui/Modules/B");
frontend.check(XorStr("game/Gui/Modules/B"));
ModulePtr bModule = frontend.moduleResolver.modules["game/Gui/Modules/B"];
REQUIRE(bModule != nullptr);
CHECK(bModule->errors.empty());
Luau::dumpErrors(bModule);
lluz::dumpErrors(bModule);
auto bExports = first(bModule->getModuleScope()->returnType);
REQUIRE(!!bExports);
@ -188,8 +188,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "automatically_check_cyclically_dependent_scr
return {}
)";
CheckResult result1 = frontend.check("game/Gui/Modules/B");
LUAU_REQUIRE_ERROR_COUNT(4, result1);
CheckResult result1 = frontend.check(XorStr("game/Gui/Modules/B"));
lluz_REQUIRE_ERROR_COUNT(4, result1);
CHECK_MESSAGE(get<ModuleHasCyclicDependency>(result1.errors[0]), "Should have been a ModuleHasCyclicDependency: " << toString(result1.errors[0]));
@ -197,8 +197,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "automatically_check_cyclically_dependent_scr
CHECK_MESSAGE(get<ModuleHasCyclicDependency>(result1.errors[2]), "Should have been a ModuleHasCyclicDependency: " << toString(result1.errors[2]));
CheckResult result2 = frontend.check("game/Gui/Modules/D");
LUAU_REQUIRE_ERROR_COUNT(0, result2);
CheckResult result2 = frontend.check(XorStr("game/Gui/Modules/D"));
lluz_REQUIRE_ERROR_COUNT(0, result2);
}
TEST_CASE_FIXTURE(FrontendFixture, "any_annotation_breaks_cycle")
@ -214,8 +214,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "any_annotation_breaks_cycle")
return {hello = A.hello}
)";
CheckResult result = frontend.check("game/Gui/Modules/A");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = frontend.check(XorStr("game/Gui/Modules/A"));
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(FrontendFixture, "nocheck_modules_are_typed")
@ -237,8 +237,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "nocheck_modules_are_typed")
local five : A.Foo = 5
)";
CheckResult result = frontend.check("game/Gui/Modules/C");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = frontend.check(XorStr("game/Gui/Modules/C"));
lluz_REQUIRE_NO_ERRORS(result);
ModulePtr aModule = frontend.moduleResolver.modules["game/Gui/Modules/A"];
REQUIRE(bool(aModule));
@ -269,8 +269,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_detection_between_check_and_nocheck")
return {hello = A.hello}
)";
CheckResult result = frontend.check("game/Gui/Modules/A");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CheckResult result = frontend.check(XorStr("game/Gui/Modules/A"));
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(FrontendFixture, "nocheck_cycle_used_by_checked")
@ -294,8 +294,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "nocheck_cycle_used_by_checked")
return {a=A, b=B}
)";
CheckResult result = frontend.check("game/Gui/Modules/C");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = frontend.check(XorStr("game/Gui/Modules/C"));
lluz_REQUIRE_NO_ERRORS(result);
ModulePtr cModule = frontend.moduleResolver.modules["game/Gui/Modules/C"];
REQUIRE(bool(cModule));
@ -320,8 +320,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_detection_disabled_in_nocheck")
return {hello = A.hello}
)";
CheckResult result = frontend.check("game/Gui/Modules/A");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = frontend.check(XorStr("game/Gui/Modules/A"));
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(FrontendFixture, "cycle_errors_can_be_fixed")
@ -337,8 +337,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_errors_can_be_fixed")
return {hello = A.hello}
)";
CheckResult result1 = frontend.check("game/Gui/Modules/A");
LUAU_REQUIRE_ERROR_COUNT(2, result1);
CheckResult result1 = frontend.check(XorStr("game/Gui/Modules/A"));
lluz_REQUIRE_ERROR_COUNT(2, result1);
CHECK_MESSAGE(get<ModuleHasCyclicDependency>(result1.errors[0]), "Should have been a ModuleHasCyclicDependency: " << toString(result1.errors[0]));
@ -347,10 +347,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_errors_can_be_fixed")
fileResolver.source["game/Gui/Modules/B"] = R"(
return {hello = 42}
)";
frontend.markDirty("game/Gui/Modules/B");
frontend.markDirty(XorStr("game/Gui/Modules/B"));
CheckResult result2 = frontend.check("game/Gui/Modules/A");
LUAU_REQUIRE_NO_ERRORS(result2);
CheckResult result2 = frontend.check(XorStr("game/Gui/Modules/A"));
lluz_REQUIRE_NO_ERRORS(result2);
}
TEST_CASE_FIXTURE(FrontendFixture, "cycle_error_paths")
@ -366,22 +366,22 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_error_paths")
return {hello = A.hello}
)";
CheckResult result = frontend.check("game/Gui/Modules/A");
LUAU_REQUIRE_ERROR_COUNT(2, result);
CheckResult result = frontend.check(XorStr("game/Gui/Modules/A"));
lluz_REQUIRE_ERROR_COUNT(2, result);
auto ce1 = get<ModuleHasCyclicDependency>(result.errors[0]);
REQUIRE(ce1);
CHECK_EQ(result.errors[0].moduleName, "game/Gui/Modules/B");
CHECK_EQ(result.errors[0].moduleName, XorStr("game/Gui/Modules/B"));
REQUIRE_EQ(ce1->cycle.size(), 2);
CHECK_EQ(ce1->cycle[0], "game/Gui/Modules/A");
CHECK_EQ(ce1->cycle[1], "game/Gui/Modules/B");
CHECK_EQ(ce1->cycle[0], XorStr("game/Gui/Modules/A"));
CHECK_EQ(ce1->cycle[1], XorStr("game/Gui/Modules/B"));
auto ce2 = get<ModuleHasCyclicDependency>(result.errors[1]);
REQUIRE(ce2);
CHECK_EQ(result.errors[1].moduleName, "game/Gui/Modules/A");
CHECK_EQ(result.errors[1].moduleName, XorStr("game/Gui/Modules/A"));
REQUIRE_EQ(ce2->cycle.size(), 2);
CHECK_EQ(ce2->cycle[0], "game/Gui/Modules/B");
CHECK_EQ(ce2->cycle[1], "game/Gui/Modules/A");
CHECK_EQ(ce2->cycle[0], XorStr("game/Gui/Modules/B"));
CHECK_EQ(ce2->cycle[1], XorStr("game/Gui/Modules/A"));
}
TEST_CASE_FIXTURE(FrontendFixture, "cycle_incremental_type_surface")
@ -390,20 +390,20 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_incremental_type_surface")
return {hello = 2}
)";
CheckResult result = frontend.check("game/A");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = frontend.check(XorStr("game/A"));
lluz_REQUIRE_NO_ERRORS(result);
fileResolver.source["game/A"] = R"(
local me = require(game.A)
return {hello = 2}
)";
frontend.markDirty("game/A");
frontend.markDirty(XorStr("game/A"));
result = frontend.check("game/A");
LUAU_REQUIRE_ERRORS(result);
result = frontend.check(XorStr("game/A"));
lluz_REQUIRE_ERRORS(result);
auto ty = requireType("game/A", "me");
CHECK_EQ(toString(ty), "any");
auto ty = requireType(XorStr("game/A", "me"));
CHECK_EQ(toString(ty), XorStr("any"));
}
TEST_CASE_FIXTURE(FrontendFixture, "cycle_incremental_type_surface_longer")
@ -412,36 +412,36 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_incremental_type_surface_longer")
return {mod_a = 2}
)";
CheckResult result = frontend.check("game/A");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = frontend.check(XorStr("game/A"));
lluz_REQUIRE_NO_ERRORS(result);
fileResolver.source["game/B"] = R"(
local me = require(game.A)
return {mod_b = 4}
)";
result = frontend.check("game/B");
LUAU_REQUIRE_NO_ERRORS(result);
result = frontend.check(XorStr("game/B"));
lluz_REQUIRE_NO_ERRORS(result);
fileResolver.source["game/A"] = R"(
local me = require(game.B)
return {mod_a_prime = 3}
)";
frontend.markDirty("game/A");
frontend.markDirty("game/B");
frontend.markDirty(XorStr("game/A"));
frontend.markDirty(XorStr("game/B"));
result = frontend.check("game/A");
LUAU_REQUIRE_ERRORS(result);
result = frontend.check(XorStr("game/A"));
lluz_REQUIRE_ERRORS(result);
TypeId tyA = requireType("game/A", "me");
CHECK_EQ(toString(tyA), "any");
TypeId tyA = requireType(XorStr("game/A", "me"));
CHECK_EQ(toString(tyA), XorStr("any"));
result = frontend.check("game/B");
LUAU_REQUIRE_ERRORS(result);
result = frontend.check(XorStr("game/B"));
lluz_REQUIRE_ERRORS(result);
TypeId tyB = requireType("game/B", "me");
CHECK_EQ(toString(tyB), "any");
TypeId tyB = requireType(XorStr("game/B", "me"));
CHECK_EQ(toString(tyB), XorStr("any"));
}
TEST_CASE_FIXTURE(FrontendFixture, "dont_reparse_clean_file_when_linting")
@ -456,7 +456,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "dont_reparse_clean_file_when_linting")
end
)";
frontend.check("Modules/A");
frontend.check(XorStr("Modules/A"));
fileResolver.source["Modules/A"] = R"(
-- We have fixed the lint error, but we did not tell the Frontend that the file is changed!
@ -465,7 +465,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "dont_reparse_clean_file_when_linting")
configResolver.defaultConfig.enabledLint.enableWarning(LintWarning::Code_ForRange);
LintResult lintResult = frontend.lint("Modules/A");
LintResult lintResult = frontend.lint(XorStr("Modules/A"));
CHECK_EQ(1, lintResult.warnings.size());
}
@ -479,16 +479,16 @@ TEST_CASE_FIXTURE(FrontendFixture, "dont_recheck_script_that_hasnt_been_marked_d
return {b_value = A.hello}
)";
frontend.check("game/Gui/Modules/B");
frontend.check(XorStr("game/Gui/Modules/B"));
fileResolver.source["game/Gui/Modules/A"] =
"Massively incorrect syntax haha oops! However! The frontend doesn't know that this file needs reparsing!";
frontend.check("game/Gui/Modules/B");
frontend.check(XorStr("game/Gui/Modules/B"));
ModulePtr bModule = frontend.moduleResolver.modules["game/Gui/Modules/B"];
CHECK(bModule->errors.empty());
Luau::dumpErrors(bModule);
lluz::dumpErrors(bModule);
}
TEST_CASE_FIXTURE(FrontendFixture, "recheck_if_dependent_script_is_dirty")
@ -500,16 +500,16 @@ TEST_CASE_FIXTURE(FrontendFixture, "recheck_if_dependent_script_is_dirty")
return {b_value = A.hello}
)";
frontend.check("game/Gui/Modules/B");
frontend.check(XorStr("game/Gui/Modules/B"));
fileResolver.source["game/Gui/Modules/A"] = "return {hello='hi!'}";
frontend.markDirty("game/Gui/Modules/A");
frontend.markDirty(XorStr("game/Gui/Modules/A"));
frontend.check("game/Gui/Modules/B");
frontend.check(XorStr("game/Gui/Modules/B"));
ModulePtr bModule = frontend.moduleResolver.modules["game/Gui/Modules/B"];
CHECK(bModule->errors.empty());
Luau::dumpErrors(bModule);
lluz::dumpErrors(bModule);
auto bExports = first(bModule->getModuleScope()->returnType);
REQUIRE(!!bExports);
@ -528,12 +528,12 @@ TEST_CASE_FIXTURE(FrontendFixture, "recheck_if_dependent_script_has_a_parse_erro
return {}
)";
CheckResult result = frontend.check("Modules/B");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CheckResult result = frontend.check(XorStr("Modules/B"));
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Modules/A", result.errors[0].moduleName);
CheckResult result2 = frontend.check("Modules/B");
LUAU_REQUIRE_ERROR_COUNT(1, result2);
CheckResult result2 = frontend.check(XorStr("Modules/B"));
lluz_REQUIRE_ERROR_COUNT(1, result2);
CHECK_EQ(result2.errors[0], result.errors[0]);
}
#endif
@ -542,8 +542,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "produce_errors_for_unchanged_file_with_a_syn
{
fileResolver.source["Modules/A"] = "oh no a blatant syntax error!!";
CheckResult one = frontend.check("Modules/A");
CheckResult two = frontend.check("Modules/A");
CheckResult one = frontend.check(XorStr("Modules/A"));
CheckResult two = frontend.check(XorStr("Modules/A"));
CHECK(!one.errors.empty());
CHECK(!two.errors.empty());
@ -553,10 +553,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "produce_errors_for_unchanged_file_with_error
{
fileResolver.source["Modules/A"] = "local p: number = 'oh no a type error'";
frontend.check("Modules/A");
frontend.check(XorStr("Modules/A"));
fileResolver.source["Modules/A"] = "local p = 4 -- We have fixed the problem, but we didn't tell the frontend, so it will not recheck this file!";
CheckResult secondResult = frontend.check("Modules/A");
CheckResult secondResult = frontend.check(XorStr("Modules/A"));
CHECK_EQ(1, secondResult.errors.size());
}
@ -574,8 +574,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "reports_errors_from_multiple_sources")
local b: number = 'another one! This is quite distressing!'
)";
CheckResult result = frontend.check("game/Gui/Modules/B");
LUAU_REQUIRE_ERROR_COUNT(2, result);
CheckResult result = frontend.check(XorStr("game/Gui/Modules/B"));
lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ("game/Gui/Modules/A", result.errors[0].moduleName);
CHECK_EQ("game/Gui/Modules/B", result.errors[1].moduleName);
@ -588,8 +588,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "report_require_to_nonexistent_file")
local B = require(Modules.B)
)";
CheckResult result = frontend.check("Modules/A");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CheckResult result = frontend.check(XorStr("Modules/A"));
lluz_REQUIRE_ERROR_COUNT(1, result);
std::string s = toString(result.errors[0]);
CHECK_MESSAGE(get<UnknownRequire>(result.errors[0]), "Should have been an UnknownRequire: " << toString(result.errors[0]));
@ -602,8 +602,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "ignore_require_to_nonexistent_file")
local B = require(Modules.B) :: any
)";
CheckResult result = frontend.check("Modules/A");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = frontend.check(XorStr("Modules/A"));
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(FrontendFixture, "report_syntax_error_in_required_file")
@ -614,8 +614,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "report_syntax_error_in_required_file")
local A = require(Modules.A)
)";
CheckResult result = frontend.check("Modules/B");
LUAU_REQUIRE_ERRORS(result);
CheckResult result = frontend.check(XorStr("Modules/B"));
lluz_REQUIRE_ERRORS(result);
CHECK_EQ("Modules/A", result.errors[0].moduleName);
@ -624,7 +624,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "report_syntax_error_in_required_file")
});
if (!b)
{
CHECK_MESSAGE(false, "Expected a syntax error!");
CHECK_MESSAGE(false, XorStr("Expected a syntax error!"));
dumpErrors(result);
}
}
@ -642,11 +642,11 @@ TEST_CASE_FIXTURE(FrontendFixture, "re_report_type_error_in_required_file")
print(A.n)
)";
CheckResult result = frontend.check("Modules/B");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CheckResult result = frontend.check(XorStr("Modules/B"));
lluz_REQUIRE_ERROR_COUNT(1, result);
CheckResult result2 = frontend.check("Modules/B");
LUAU_REQUIRE_ERROR_COUNT(1, result2);
CheckResult result2 = frontend.check(XorStr("Modules/B"));
lluz_REQUIRE_ERROR_COUNT(1, result2);
CHECK_EQ("Modules/A", result.errors[0].moduleName);
}
@ -665,16 +665,16 @@ TEST_CASE_FIXTURE(FrontendFixture, "accumulate_cached_errors")
print(A, b)
)";
CheckResult result1 = frontend.check("Modules/B");
CheckResult result1 = frontend.check(XorStr("Modules/B"));
LUAU_REQUIRE_ERROR_COUNT(2, result1);
lluz_REQUIRE_ERROR_COUNT(2, result1);
CHECK_EQ("Modules/A", result1.errors[0].moduleName);
CHECK_EQ("Modules/B", result1.errors[1].moduleName);
CheckResult result2 = frontend.check("Modules/B");
CheckResult result2 = frontend.check(XorStr("Modules/B"));
LUAU_REQUIRE_ERROR_COUNT(2, result2);
lluz_REQUIRE_ERROR_COUNT(2, result2);
CHECK_EQ("Modules/A", result2.errors[0].moduleName);
CHECK_EQ("Modules/B", result2.errors[1].moduleName);
@ -695,9 +695,9 @@ TEST_CASE_FIXTURE(FrontendFixture, "accumulate_cached_errors_in_consistent_order
return {}
)";
CheckResult result1 = frontend.check("Modules/A");
CheckResult result1 = frontend.check(XorStr("Modules/A"));
LUAU_REQUIRE_ERROR_COUNT(4, result1);
lluz_REQUIRE_ERROR_COUNT(4, result1);
CHECK_EQ("Modules/A", result1.errors[2].moduleName);
CHECK_EQ("Modules/A", result1.errors[3].moduleName);
@ -705,7 +705,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "accumulate_cached_errors_in_consistent_order
CHECK_EQ("Modules/B", result1.errors[0].moduleName);
CHECK_EQ("Modules/B", result1.errors[1].moduleName);
CheckResult result2 = frontend.check("Modules/A");
CheckResult result2 = frontend.check(XorStr("Modules/A"));
CHECK_EQ(4, result2.errors.size());
for (size_t i = 0; i < result1.errors.size(); ++i)
@ -737,12 +737,12 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_lint_uses_correct_config")
configResolver.configFiles["Module/A"].enabledLint.enableWarning(LintWarning::Code_ForRange);
auto result = frontend.lint("Module/A");
auto result = frontend.lint(XorStr("Module/A"));
CHECK_EQ(1, result.warnings.size());
configResolver.configFiles["Module/A"].enabledLint.disableWarning(LintWarning::Code_ForRange);
auto result2 = frontend.lint("Module/A");
auto result2 = frontend.lint(XorStr("Module/A"));
CHECK_EQ(0, result2.warnings.size());
LintOptions overrideOptions;
@ -756,6 +756,26 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_lint_uses_correct_config")
CHECK_EQ(0, result4.warnings.size());
}
TEST_CASE_FIXTURE(FrontendFixture, "lintFragment")
{
LintOptions lintOptions;
lintOptions.enableWarning(LintWarning::Code_ForRange);
auto [_sourceModule, result] = frontend.lintFragment(R"(
local t = {}
for i=#t,1 do
end
for i=#t,1,-1 do
end
)",
lintOptions);
CHECK_EQ(1, result.warnings.size());
CHECK_EQ(0, result.errors.size());
}
TEST_CASE_FIXTURE(FrontendFixture, "discard_type_graphs")
{
Frontend fe{&fileResolver, &configResolver, {false}};
@ -764,9 +784,9 @@ TEST_CASE_FIXTURE(FrontendFixture, "discard_type_graphs")
local a = {1,2,3,4,5}
)";
CheckResult result = fe.check("Module/A");
CheckResult result = fe.check(XorStr("Module/A"));
ModulePtr module = fe.moduleResolver.getModule("Module/A");
ModulePtr module = fe.moduleResolver.getModule(XorStr("Module/A"));
CHECK_EQ(0, module->internalTypes.typeVars.size());
CHECK_EQ(0, module->internalTypes.typePacks.size());
@ -784,7 +804,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "it_should_be_safe_to_stringify_errors_when_f
local a: {Count: number} = {count='five'}
)";
CheckResult result = fe.check("Module/A");
CheckResult result = fe.check(XorStr("Module/A"));
REQUIRE_EQ(1, result.errors.size());
@ -817,9 +837,9 @@ TEST_CASE_FIXTURE(FrontendFixture, "trace_requires_in_nonstrict_mode")
print(A.f(5)) -- OK
)";
CheckResult result = frontend.check("Module/B");
CheckResult result = frontend.check(XorStr("Module/B"));
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(4, result.errors[0].location.begin.line);
CHECK_EQ(5, result.errors[1].location.begin.line);
@ -827,13 +847,13 @@ TEST_CASE_FIXTURE(FrontendFixture, "trace_requires_in_nonstrict_mode")
TEST_CASE_FIXTURE(FrontendFixture, "environments")
{
ScopePtr testScope = frontend.addEnvironment("test");
ScopePtr testScope = frontend.addEnvironment(XorStr("test"));
unfreeze(typeChecker.globalTypes);
loadDefinitionFile(typeChecker, testScope, R"(
export type Foo = number | string
)",
"@test");
XorStr("@test"));
freeze(typeChecker.globalTypes);
fileResolver.source["A"] = R"(
@ -848,11 +868,11 @@ TEST_CASE_FIXTURE(FrontendFixture, "environments")
fileResolver.environments["A"] = "test";
CheckResult resultA = frontend.check("A");
LUAU_REQUIRE_NO_ERRORS(resultA);
CheckResult resultA = frontend.check(XorStr("A"));
lluz_REQUIRE_NO_ERRORS(resultA);
CheckResult resultB = frontend.check("B");
LUAU_REQUIRE_ERROR_COUNT(1, resultB);
CheckResult resultB = frontend.check(XorStr("B"));
lluz_REQUIRE_ERROR_COUNT(1, resultB);
}
TEST_CASE_FIXTURE(FrontendFixture, "ast_node_at_position")
@ -890,17 +910,17 @@ TEST_CASE_FIXTURE(FrontendFixture, "stats_are_not_reset_between_checks")
return {foo = 1}
)";
CheckResult r1 = frontend.check("Module/A");
LUAU_REQUIRE_NO_ERRORS(r1);
CheckResult r1 = frontend.check(XorStr("Module/A"));
lluz_REQUIRE_NO_ERRORS(r1);
Frontend::Stats stats1 = frontend.stats;
CHECK_EQ(2, stats1.files);
frontend.markDirty("Module/A");
frontend.markDirty("Module/B");
frontend.markDirty(XorStr("Module/A"));
frontend.markDirty(XorStr("Module/B"));
CheckResult r2 = frontend.check("Module/A");
LUAU_REQUIRE_NO_ERRORS(r2);
CheckResult r2 = frontend.check(XorStr("Module/A"));
lluz_REQUIRE_NO_ERRORS(r2);
Frontend::Stats stats2 = frontend.stats;
CHECK_EQ(4, stats2.files);
@ -919,18 +939,18 @@ TEST_CASE_FIXTURE(FrontendFixture, "clearStats")
return {foo = 1}
)";
CheckResult r1 = frontend.check("Module/A");
LUAU_REQUIRE_NO_ERRORS(r1);
CheckResult r1 = frontend.check(XorStr("Module/A"));
lluz_REQUIRE_NO_ERRORS(r1);
Frontend::Stats stats1 = frontend.stats;
CHECK_EQ(2, stats1.files);
frontend.markDirty("Module/A");
frontend.markDirty("Module/B");
frontend.markDirty(XorStr("Module/A"));
frontend.markDirty(XorStr("Module/B"));
frontend.clearStats();
CheckResult r2 = frontend.check("Module/A");
LUAU_REQUIRE_NO_ERRORS(r2);
CheckResult r2 = frontend.check(XorStr("Module/A"));
lluz_REQUIRE_NO_ERRORS(r2);
Frontend::Stats stats2 = frontend.stats;
CHECK_EQ(2, stats2.files);
@ -942,13 +962,13 @@ TEST_CASE_FIXTURE(FrontendFixture, "typecheck_twice_for_ast_types")
local a = 1
)";
CheckResult result = frontend.check("Module/A");
CheckResult result = frontend.check(XorStr("Module/A"));
ModulePtr module = frontend.moduleResolver.getModule("Module/A");
ModulePtr module = frontend.moduleResolver.getModule(XorStr("Module/A"));
REQUIRE_EQ(module->astTypes.size(), 1);
auto it = module->astTypes.begin();
CHECK_EQ(toString(it->second), "number");
CHECK_EQ(toString(it->second), XorStr("number"));
}
TEST_CASE_FIXTURE(FrontendFixture, "imported_table_modification_2")
@ -977,14 +997,14 @@ local b = require(script.Parent.B)
a:b() -- this should error, since A doesn't define a:b()
)";
CheckResult resultA = frontend.check("Module/A");
LUAU_REQUIRE_NO_ERRORS(resultA);
CheckResult resultA = frontend.check(XorStr("Module/A"));
lluz_REQUIRE_NO_ERRORS(resultA);
CheckResult resultB = frontend.check("Module/B");
LUAU_REQUIRE_ERRORS(resultB);
CheckResult resultB = frontend.check(XorStr("Module/B"));
lluz_REQUIRE_ERRORS(resultB);
CheckResult resultC = frontend.check("Module/C");
LUAU_REQUIRE_ERRORS(resultC);
CheckResult resultC = frontend.check(XorStr("Module/C"));
lluz_REQUIRE_ERRORS(resultC);
}
// This test does not use TEST_CASE_FIXTURE because we need to set a flag before
@ -992,7 +1012,7 @@ a:b() -- this should error, since A doesn't define a:b()
TEST_CASE("no_use_after_free_with_type_fun_instantiation")
{
// This flag forces this test to crash if there's a UAF in this code.
ScopedFastFlag sff_DebugLuauFreezeArena("DebugLuauFreezeArena", true);
ScopedFastFlag sff_DebuglluzFreezeArena("DebuglluzFreezeArena", true);
FrontendFixture fix;
@ -1008,7 +1028,7 @@ return false;
)";
// We don't care about the result. That we haven't crashed is enough.
fix.frontend.check("Module/B");
fix.frontend.check(XorStr("Module/B"));
}
TEST_CASE("check_without_builtin_next")
@ -1021,77 +1041,8 @@ TEST_CASE("check_without_builtin_next")
fileResolver.source["Module/B"] = "return next";
// We don't care about the result. That we haven't crashed is enough.
frontend.check("Module/A");
frontend.check("Module/B");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "reexport_cyclic_type")
{
ScopedFastFlag sff[] = {
{"LuauForceExportSurfacesToBeNormal", true},
{"LuauLowerBoundsCalculation", true},
{"LuauNormalizeFlagIsConservative", true},
};
fileResolver.source["Module/A"] = R"(
type F<T> = (set: G<T>) -> ()
export type G<T> = {
forEach: (a: F<T>) -> (),
}
function X<T>(a: F<T>): ()
end
return X
)";
fileResolver.source["Module/B"] = R"(
--!strict
local A = require(script.Parent.A)
export type G<T> = A.G<T>
return {
A = A,
}
)";
CheckResult result = frontend.check("Module/B");
LUAU_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "reexport_type_alias")
{
ScopedFastFlag sff[] = {
{"LuauForceExportSurfacesToBeNormal", true},
{"LuauLowerBoundsCalculation", true},
{"LuauNormalizeFlagIsConservative", true},
};
fileResolver.source["Module/A"] = R"(
type KeyOfTestEvents = "test-file-start" | "test-file-success" | "test-file-failure" | "test-case-result"
type unknown = any
export type TestFileEvent<T = KeyOfTestEvents> = (
eventName: T,
args: any --[[ ROBLOX TODO: Unhandled node for type: TSIndexedAccessType ]] --[[ TestEvents[T] ]]
) -> unknown
return {}
)";
fileResolver.source["Module/B"] = R"(
--!strict
local A = require(script.Parent.A)
export type TestFileEvent = A.TestFileEvent
)";
CheckResult result = frontend.check("Module/B");
LUAU_REQUIRE_NO_ERRORS(result);
frontend.check(XorStr("Module/A"));
frontend.check(XorStr("Module/B"));
}
TEST_SUITE_END();

View file

@ -1,4 +1,4 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
#include <ostream>

View file

@ -1,13 +1,13 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Ast.h"
#include "Luau/JsonEncoder.h"
#include "Luau/Parser.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Ast.h"
#include "lluz/JsonEncoder.h"
#include "lluz/Parser.h"
#include "doctest.h"
#include <ostream>
using namespace Luau;
using namespace lluz;
struct JsonEncoderFixture
{
@ -49,26 +49,17 @@ struct JsonEncoderFixture
}
};
TEST_SUITE_BEGIN("JsonEncoderTests");
TEST_SUITE_BEGIN(XorStr("JsonEncoderTests"));
TEST_CASE("encode_constants")
{
AstExprConstantNil nil{Location()};
AstExprConstantBool b{Location(), true};
AstExprConstantNumber n{Location(), 8.2};
AstExprConstantNumber bigNum{Location(), 0.1677721600000003};
AstArray<char> charString;
charString.data = const_cast<char*>("a\x1d\0\\\"b");
charString.size = 6;
AstExprConstantString needsEscaping{Location(), charString};
CHECK_EQ(R"({"type":"AstExprConstantNil","location":"0,0 - 0,0"})", toJson(&nil));
CHECK_EQ(R"({"type":"AstExprConstantBool","location":"0,0 - 0,0","value":true})", toJson(&b));
CHECK_EQ(R"({"type":"AstExprConstantNumber","location":"0,0 - 0,0","value":8.1999999999999993})", toJson(&n));
CHECK_EQ(R"({"type":"AstExprConstantNumber","location":"0,0 - 0,0","value":0.16777216000000031})", toJson(&bigNum));
CHECK_EQ("{\"type\":\"AstExprConstantString\",\"location\":\"0,0 - 0,0\",\"value\":\"a\\u001d\\u0000\\\\\\\"b\"}", toJson(&needsEscaping));
CHECK_EQ(R"({"type":"AstExprConstantNumber","location":"0,0 - 0,0","value":8.2})", toJson(&n));
}
TEST_CASE("basic_escaping")
@ -96,7 +87,7 @@ TEST_CASE("encode_AstStatBlock")
AstStatBlock block{Location(), bodyArray};
CHECK_EQ(
(R"({"type":"AstStatBlock","location":"0,0 - 0,0","body":[{"type":"AstStatLocal","location":"0,0 - 0,0","vars":[{"luauType":null,"name":"a_local","type":"AstLocal","location":"0,0 - 0,0"}],"values":[]}]})"),
(R"({"type":"AstStatBlock","location":"0,0 - 0,0","body":[{"type":"AstStatLocal","location":"0,0 - 0,0","vars":[{"type":null,"name":"a_local","location":"0,0 - 0,0"}],"values":[]}]})"),
toJson(&block));
}
@ -115,31 +106,7 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_tables")
CHECK(
json ==
R"({"type":"AstStatBlock","location":"0,0 - 6,4","body":[{"type":"AstStatLocal","location":"1,8 - 5,9","vars":[{"luauType":{"type":"AstTypeTable","location":"1,17 - 3,9","props":[{"name":"foo","type":"AstTableProp","location":"2,12 - 2,15","propType":{"type":"AstTypeReference","location":"2,17 - 2,23","name":"number","parameters":[]}}],"indexer":null},"name":"x","type":"AstLocal","location":"1,14 - 1,15"}],"values":[{"type":"AstExprTable","location":"3,12 - 5,9","items":[{"type":"AstExprTableItem","kind":"record","key":{"type":"AstExprConstantString","location":"4,12 - 4,15","value":"foo"},"value":{"type":"AstExprConstantNumber","location":"4,18 - 4,21","value":123}}]}]}]})");
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_table_array")
{
std::string src = R"(type X = {string})";
AstStatBlock* root = expectParse(src);
std::string json = toJson(root);
CHECK(
json ==
R"({"type":"AstStatBlock","location":"0,0 - 0,17","body":[{"type":"AstStatTypeAlias","location":"0,0 - 0,17","name":"X","generics":[],"genericPacks":[],"type":{"type":"AstTypeTable","location":"0,9 - 0,17","props":[],"indexer":{"location":"0,10 - 0,16","indexType":{"type":"AstTypeReference","location":"0,10 - 0,16","name":"number","parameters":[]},"resultType":{"type":"AstTypeReference","location":"0,10 - 0,16","name":"string","parameters":[]}}},"exported":false}]})");
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_table_indexer")
{
std::string src = R"(type X = {string})";
AstStatBlock* root = expectParse(src);
std::string json = toJson(root);
CHECK(
json ==
R"({"type":"AstStatBlock","location":"0,0 - 0,17","body":[{"type":"AstStatTypeAlias","location":"0,0 - 0,17","name":"X","generics":[],"genericPacks":[],"type":{"type":"AstTypeTable","location":"0,9 - 0,17","props":[],"indexer":{"location":"0,10 - 0,16","indexType":{"type":"AstTypeReference","location":"0,10 - 0,16","name":"number","parameters":[]},"resultType":{"type":"AstTypeReference","location":"0,10 - 0,16","name":"string","parameters":[]}}},"exported":false}]})");
RXorStr("({"type":"AstStatBlock","location":"0,0 - 6,4","body":[{"type":"AstStatLocal","location":"1,8 - 5,9","vars":[{"type":{"type":"AstTypeTable","location":"1,17 - 3,9","props":[{"name":"foo","location":"2,12 - 2,15","type":{"type":"AstTypeReference","location":"2,17 - 2,23","name":"number","parameters":[]}}],"indexer":false},"name":"x","location":"1,14 - 1,15"}],"values":[{"type":"AstExprTable","location":"3,12 - 5,9","items":[{"kind":"record","key":{"type":"AstExprConstantString","location":"4,12 - 4,15","value":"foo"},"value":{"type":"AstExprConstantNumber","location":"4,18 - 4,21","value":123}}]}]}]})"));
}
TEST_CASE("encode_AstExprGroup")
@ -165,35 +132,24 @@ TEST_CASE("encode_AstExprGlobal")
CHECK(json == expected);
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprIfThen")
{
AstStat* statement = expectParseStatement("local a = if x then y else z");
std::string_view expected =
R"({"type":"AstStatLocal","location":"0,0 - 0,28","vars":[{"luauType":null,"name":"a","type":"AstLocal","location":"0,6 - 0,7"}],"values":[{"type":"AstExprIfElse","location":"0,10 - 0,28","condition":{"type":"AstExprGlobal","location":"0,13 - 0,14","global":"x"},"hasThen":true,"trueExpr":{"type":"AstExprGlobal","location":"0,20 - 0,21","global":"y"},"hasElse":true,"falseExpr":{"type":"AstExprGlobal","location":"0,27 - 0,28","global":"z"}}]})";
CHECK(toJson(statement) == expected);
}
TEST_CASE("encode_AstExprLocal")
{
AstLocal local{AstName{"foo"}, Location{}, nullptr, 0, 0, nullptr};
AstExprLocal exprLocal{Location{}, &local, false};
CHECK(toJson(&exprLocal) == R"({"type":"AstExprLocal","location":"0,0 - 0,0","local":{"luauType":null,"name":"foo","type":"AstLocal","location":"0,0 - 0,0"}})");
CHECK(toJson(&exprLocal) == RXorStr("({"type":"AstExprLocal","location":"0,0 - 0,0","local":{"type":null,"name":"foo","location":"0,0 - 0,0"}})"));
}
TEST_CASE("encode_AstExprVarargs")
{
AstExprVarargs varargs{Location{}};
CHECK(toJson(&varargs) == R"({"type":"AstExprVarargs","location":"0,0 - 0,0"})");
CHECK(toJson(&varargs) == RXorStr("({"type":"AstExprVarargs","location":"0,0 - 0,0"})"));
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprCall")
{
AstExpr* expr = expectParseExpr("foo(1, 2, 3)");
AstExpr* expr = expectParseExpr(XorStr("foo(1, 2, 3)"));
std::string_view expected =
R"({"type":"AstExprCall","location":"0,4 - 0,16","func":{"type":"AstExprGlobal","location":"0,4 - 0,7","global":"foo"},"args":[{"type":"AstExprConstantNumber","location":"0,8 - 0,9","value":1},{"type":"AstExprConstantNumber","location":"0,11 - 0,12","value":2},{"type":"AstExprConstantNumber","location":"0,14 - 0,15","value":3}],"self":false,"argLocation":"0,8 - 0,16"})";
@ -202,7 +158,7 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprCall")
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprIndexName")
{
AstExpr* expr = expectParseExpr("foo.bar");
AstExpr* expr = expectParseExpr(XorStr("foo.bar"));
std::string_view expected =
R"({"type":"AstExprIndexName","location":"0,4 - 0,11","expr":{"type":"AstExprGlobal","location":"0,4 - 0,7","global":"foo"},"index":"bar","indexLocation":"0,8 - 0,11","op":"."})";
@ -212,7 +168,7 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprIndexName")
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprIndexExpr")
{
AstExpr* expr = expectParseExpr("foo['bar']");
AstExpr* expr = expectParseExpr(XorStr("foo['bar']"));
std::string_view expected =
R"({"type":"AstExprIndexExpr","location":"0,4 - 0,14","expr":{"type":"AstExprGlobal","location":"0,4 - 0,7","global":"foo"},"index":{"type":"AstExprConstantString","location":"0,8 - 0,13","value":"bar"}})";
@ -222,37 +178,37 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprIndexExpr")
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprFunction")
{
AstExpr* expr = expectParseExpr("function (a) return a end");
AstExpr* expr = expectParseExpr(XorStr("function (a) return a end"));
std::string_view expected =
R"({"type":"AstExprFunction","location":"0,4 - 0,29","generics":[],"genericPacks":[],"args":[{"luauType":null,"name":"a","type":"AstLocal","location":"0,14 - 0,15"}],"vararg":false,"varargLocation":"0,0 - 0,0","body":{"type":"AstStatBlock","location":"0,16 - 0,26","body":[{"type":"AstStatReturn","location":"0,17 - 0,25","list":[{"type":"AstExprLocal","location":"0,24 - 0,25","local":{"luauType":null,"name":"a","type":"AstLocal","location":"0,14 - 0,15"}}]}]},"functionDepth":1,"debugname":"","hasEnd":true})";
R"({"type":"AstExprFunction","location":"0,4 - 0,29","generics":[],"genericPacks":[],"args":[{"type":null,"name":"a","location":"0,14 - 0,15"}],"vararg":false,"varargLocation":"0,0 - 0,0","body":{"type":"AstStatBlock","location":"0,16 - 0,26","body":[{"type":"AstStatReturn","location":"0,17 - 0,25","list":[{"type":"AstExprLocal","location":"0,24 - 0,25","local":{"type":null,"name":"a","location":"0,14 - 0,15"}}]}]},"functionDepth":1,"debugname":"","hasEnd":true})";
CHECK(toJson(expr) == expected);
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprTable")
{
AstExpr* expr = expectParseExpr("{true, key=true, [key2]=true}");
AstExpr* expr = expectParseExpr(XorStr("{true, key=true, [key2]=true}"));
std::string_view expected =
R"({"type":"AstExprTable","location":"0,4 - 0,33","items":[{"type":"AstExprTableItem","kind":"item","value":{"type":"AstExprConstantBool","location":"0,5 - 0,9","value":true}},{"type":"AstExprTableItem","kind":"record","key":{"type":"AstExprConstantString","location":"0,11 - 0,14","value":"key"},"value":{"type":"AstExprConstantBool","location":"0,15 - 0,19","value":true}},{"type":"AstExprTableItem","kind":"general","key":{"type":"AstExprGlobal","location":"0,22 - 0,26","global":"key2"},"value":{"type":"AstExprConstantBool","location":"0,28 - 0,32","value":true}}]})";
R"({"type":"AstExprTable","location":"0,4 - 0,33","items":[{"kind":"item","value":{"type":"AstExprConstantBool","location":"0,5 - 0,9","value":true}},{"kind":"record","key":{"type":"AstExprConstantString","location":"0,11 - 0,14","value":"key"},"value":{"type":"AstExprConstantBool","location":"0,15 - 0,19","value":true}},{"kind":"general","key":{"type":"AstExprGlobal","location":"0,22 - 0,26","global":"key2"},"value":{"type":"AstExprConstantBool","location":"0,28 - 0,32","value":true}}]})";
CHECK(toJson(expr) == expected);
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprUnary")
{
AstExpr* expr = expectParseExpr("-b");
AstExpr* expr = expectParseExpr(XorStr("-b"));
std::string_view expected =
R"({"type":"AstExprUnary","location":"0,4 - 0,6","op":"Minus","expr":{"type":"AstExprGlobal","location":"0,5 - 0,6","global":"b"}})";
R"({"type":"AstExprUnary","location":"0,4 - 0,6","op":"minus","expr":{"type":"AstExprGlobal","location":"0,5 - 0,6","global":"b"}})";
CHECK(toJson(expr) == expected);
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprBinary")
{
AstExpr* expr = expectParseExpr("b + c");
AstExpr* expr = expectParseExpr(XorStr("b + c"));
std::string_view expected =
R"({"type":"AstExprBinary","location":"0,4 - 0,9","op":"Add","left":{"type":"AstExprGlobal","location":"0,4 - 0,5","global":"b"},"right":{"type":"AstExprGlobal","location":"0,8 - 0,9","global":"c"}})";
@ -262,7 +218,7 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprBinary")
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprTypeAssertion")
{
AstExpr* expr = expectParseExpr("b :: any");
AstExpr* expr = expectParseExpr(XorStr("b :: any"));
std::string_view expected =
R"({"type":"AstExprTypeAssertion","location":"0,4 - 0,12","expr":{"type":"AstExprGlobal","location":"0,4 - 0,5","global":"b"},"annotation":{"type":"AstTypeReference","location":"0,9 - 0,12","name":"any","parameters":[]}})";
@ -290,7 +246,7 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprError")
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatIf")
{
AstStat* statement = expectParseStatement("if true then else end");
AstStat* statement = expectParseStatement(XorStr("if true then else end"));
std::string_view expected =
R"({"type":"AstStatIf","location":"0,0 - 0,21","condition":{"type":"AstExprConstantBool","location":"0,3 - 0,7","value":true},"thenbody":{"type":"AstStatBlock","location":"0,12 - 0,13","body":[]},"elsebody":{"type":"AstStatBlock","location":"0,17 - 0,18","body":[]},"hasThen":true,"hasEnd":true})";
@ -300,17 +256,17 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatIf")
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatWhile")
{
AstStat* statement = expectParseStatement("while true do end");
AstStat* statement = expectParseStatement(XorStr("while true do end"));
std::string_view expected =
R"({"type":"AstStatWhile","location":"0,0 - 0,17","condition":{"type":"AstExprConstantBool","location":"0,6 - 0,10","value":true},"body":{"type":"AstStatBlock","location":"0,13 - 0,14","body":[]},"hasDo":true,"hasEnd":true})";
R"({"type":"AtStatWhile","location":"0,0 - 0,17","condition":{"type":"AstExprConstantBool","location":"0,6 - 0,10","value":true},"body":{"type":"AstStatBlock","location":"0,13 - 0,14","body":[]},"hasDo":true,"hasEnd":true})";
CHECK(toJson(statement) == expected);
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatRepeat")
{
AstStat* statement = expectParseStatement("repeat until true");
AstStat* statement = expectParseStatement(XorStr("repeat until true"));
std::string_view expected =
R"({"type":"AstStatRepeat","location":"0,0 - 0,17","condition":{"type":"AstExprConstantBool","location":"0,13 - 0,17","value":true},"body":{"type":"AstStatBlock","location":"0,6 - 0,7","body":[]},"hasUntil":true})";
@ -320,47 +276,47 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatRepeat")
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatBreak")
{
AstStat* statement = expectParseStatement("while true do break end");
AstStat* statement = expectParseStatement(XorStr("while true do break end"));
std::string_view expected =
R"({"type":"AstStatWhile","location":"0,0 - 0,23","condition":{"type":"AstExprConstantBool","location":"0,6 - 0,10","value":true},"body":{"type":"AstStatBlock","location":"0,13 - 0,20","body":[{"type":"AstStatBreak","location":"0,14 - 0,19"}]},"hasDo":true,"hasEnd":true})";
R"({"type":"AtStatWhile","location":"0,0 - 0,23","condition":{"type":"AstExprConstantBool","location":"0,6 - 0,10","value":true},"body":{"type":"AstStatBlock","location":"0,13 - 0,20","body":[{"type":"AstStatBreak","location":"0,14 - 0,19"}]},"hasDo":true,"hasEnd":true})";
CHECK(toJson(statement) == expected);
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatContinue")
{
AstStat* statement = expectParseStatement("while true do continue end");
AstStat* statement = expectParseStatement(XorStr("while true do continue end"));
std::string_view expected =
R"({"type":"AstStatWhile","location":"0,0 - 0,26","condition":{"type":"AstExprConstantBool","location":"0,6 - 0,10","value":true},"body":{"type":"AstStatBlock","location":"0,13 - 0,23","body":[{"type":"AstStatContinue","location":"0,14 - 0,22"}]},"hasDo":true,"hasEnd":true})";
R"({"type":"AtStatWhile","location":"0,0 - 0,26","condition":{"type":"AstExprConstantBool","location":"0,6 - 0,10","value":true},"body":{"type":"AstStatBlock","location":"0,13 - 0,23","body":[{"type":"AstStatContinue","location":"0,14 - 0,22"}]},"hasDo":true,"hasEnd":true})";
CHECK(toJson(statement) == expected);
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatFor")
{
AstStat* statement = expectParseStatement("for a=0,1 do end");
AstStat* statement = expectParseStatement(XorStr("for a=0,1 do end"));
std::string_view expected =
R"({"type":"AstStatFor","location":"0,0 - 0,16","var":{"luauType":null,"name":"a","type":"AstLocal","location":"0,4 - 0,5"},"from":{"type":"AstExprConstantNumber","location":"0,6 - 0,7","value":0},"to":{"type":"AstExprConstantNumber","location":"0,8 - 0,9","value":1},"body":{"type":"AstStatBlock","location":"0,12 - 0,13","body":[]},"hasDo":true,"hasEnd":true})";
R"({"type":"AstStatFor","location":"0,0 - 0,16","var":{"type":null,"name":"a","location":"0,4 - 0,5"},"from":{"type":"AstExprConstantNumber","location":"0,6 - 0,7","value":0},"to":{"type":"AstExprConstantNumber","location":"0,8 - 0,9","value":1},"body":{"type":"AstStatBlock","location":"0,12 - 0,13","body":[]},"hasDo":true,"hasEnd":true})";
CHECK(toJson(statement) == expected);
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatForIn")
{
AstStat* statement = expectParseStatement("for a in b do end");
AstStat* statement = expectParseStatement(XorStr("for a in b do end"));
std::string_view expected =
R"({"type":"AstStatForIn","location":"0,0 - 0,17","vars":[{"luauType":null,"name":"a","type":"AstLocal","location":"0,4 - 0,5"}],"values":[{"type":"AstExprGlobal","location":"0,9 - 0,10","global":"b"}],"body":{"type":"AstStatBlock","location":"0,13 - 0,14","body":[]},"hasIn":true,"hasDo":true,"hasEnd":true})";
R"({"type":"AstStatForIn","location":"0,0 - 0,17","vars":[{"type":null,"name":"a","location":"0,4 - 0,5"}],"values":[{"type":"AstExprGlobal","location":"0,9 - 0,10","global":"b"}],"body":{"type":"AstStatBlock","location":"0,13 - 0,14","body":[]},"hasIn":true,"hasDo":true,"hasEnd":true})";
CHECK(toJson(statement) == expected);
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatCompoundAssign")
{
AstStat* statement = expectParseStatement("a += b");
AstStat* statement = expectParseStatement(XorStr("a += b"));
std::string_view expected =
R"({"type":"AstStatCompoundAssign","location":"0,0 - 0,6","op":"Add","var":{"type":"AstExprGlobal","location":"0,0 - 0,1","global":"a"},"value":{"type":"AstExprGlobal","location":"0,5 - 0,6","global":"b"}})";
@ -370,17 +326,17 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatCompoundAssign")
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatLocalFunction")
{
AstStat* statement = expectParseStatement("local function a(b) return end");
AstStat* statement = expectParseStatement(XorStr("local function a(b) return end"));
std::string_view expected =
R"({"type":"AstStatLocalFunction","location":"0,0 - 0,30","name":{"luauType":null,"name":"a","type":"AstLocal","location":"0,15 - 0,16"},"func":{"type":"AstExprFunction","location":"0,0 - 0,30","generics":[],"genericPacks":[],"args":[{"luauType":null,"name":"b","type":"AstLocal","location":"0,17 - 0,18"}],"vararg":false,"varargLocation":"0,0 - 0,0","body":{"type":"AstStatBlock","location":"0,19 - 0,27","body":[{"type":"AstStatReturn","location":"0,20 - 0,26","list":[]}]},"functionDepth":1,"debugname":"a","hasEnd":true}})";
R"({"type":"AstStatLocalFunction","location":"0,0 - 0,30","name":{"type":null,"name":"a","location":"0,15 - 0,16"},"func":{"type":"AstExprFunction","location":"0,0 - 0,30","generics":[],"genericPacks":[],"args":[{"type":null,"name":"b","location":"0,17 - 0,18"}],"vararg":false,"varargLocation":"0,0 - 0,0","body":{"type":"AstStatBlock","location":"0,19 - 0,27","body":[{"type":"AstStatReturn","location":"0,20 - 0,26","list":[]}]},"functionDepth":1,"debugname":"a","hasEnd":true}})";
CHECK(toJson(statement) == expected);
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatTypeAlias")
{
AstStat* statement = expectParseStatement("type A = B");
AstStat* statement = expectParseStatement(XorStr("type A = B"));
std::string_view expected =
R"({"type":"AstStatTypeAlias","location":"0,0 - 0,10","name":"A","generics":[],"genericPacks":[],"type":{"type":"AstTypeReference","location":"0,9 - 0,10","name":"B","parameters":[]},"exported":false})";
@ -390,10 +346,10 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatTypeAlias")
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatDeclareFunction")
{
AstStat* statement = expectParseStatement("declare function foo(x: number): string");
AstStat* statement = expectParseStatement(XorStr("declare function foo(x: number): string"));
std::string_view expected =
R"({"type":"AstStatDeclareFunction","location":"0,0 - 0,39","name":"foo","params":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"0,24 - 0,30","name":"number","parameters":[]}]},"retTypes":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"0,33 - 0,39","name":"string","parameters":[]}]},"generics":[],"genericPacks":[]})";
R"({"type":"AstStatDeclareFunction","location":"0,0 - 0,39","name":"foo","params":{"types":[{"type":"AstTypeReference","location":"0,24 - 0,30","name":"number","parameters":[]}]},"retTypes":{"types":[{"type":"AstTypeReference","location":"0,33 - 0,39","name":"string","parameters":[]}]},"generics":[],"genericPacks":[]})";
CHECK(toJson(statement) == expected);
}
@ -414,27 +370,27 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatDeclareClass")
REQUIRE(2 == root->body.size);
std::string_view expected1 =
R"({"type":"AstStatDeclareClass","location":"1,22 - 4,11","name":"Foo","props":[{"name":"prop","type":"AstDeclaredClassProp","luauType":{"type":"AstTypeReference","location":"2,18 - 2,24","name":"number","parameters":[]}},{"name":"method","type":"AstDeclaredClassProp","luauType":{"type":"AstTypeFunction","location":"3,21 - 4,11","generics":[],"genericPacks":[],"argTypes":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"3,39 - 3,45","name":"number","parameters":[]}]},"returnTypes":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"3,48 - 3,54","name":"string","parameters":[]}]}}}]})";
R"({"type":"AstStatDeclareClass","location":"1,22 - 4,11","name":"Foo","props":[{"name":"prop","type":{"type":"AstTypeReference","location":"2,18 - 2,24","name":"number","parameters":[]}},{"name":"method","type":{"type":"AstTypeFunction","location":"3,21 - 4,11","generics":[],"genericPacks":[],"argTypes":{"types":[{"type":"AstTypeReference","location":"3,39 - 3,45","name":"number","parameters":[]}]},"returnTypes":{"types":[{"type":"AstTypeReference","location":"3,48 - 3,54","name":"string","parameters":[]}]}}}]})";
CHECK(toJson(root->body.data[0]) == expected1);
std::string_view expected2 =
R"({"type":"AstStatDeclareClass","location":"6,22 - 8,11","name":"Bar","superName":"Foo","props":[{"name":"prop2","type":"AstDeclaredClassProp","luauType":{"type":"AstTypeReference","location":"7,19 - 7,25","name":"string","parameters":[]}}]})";
R"({"type":"AstStatDeclareClass","location":"6,22 - 8,11","name":"Bar","superName":"Foo","props":[{"name":"prop2","type":{"type":"AstTypeReference","location":"7,19 - 7,25","name":"string","parameters":[]}}]})";
CHECK(toJson(root->body.data[1]) == expected2);
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_annotation")
{
AstStat* statement = expectParseStatement("type T = ((number) -> (string | nil)) & ((string) -> ())");
AstStat* statement = expectParseStatement(XorStr("type T = ((number) -> (string | nil)) & ((string) -> ())"));
std::string_view expected =
R"({"type":"AstStatTypeAlias","location":"0,0 - 0,55","name":"T","generics":[],"genericPacks":[],"type":{"type":"AstTypeIntersection","location":"0,9 - 0,55","types":[{"type":"AstTypeFunction","location":"0,10 - 0,35","generics":[],"genericPacks":[],"argTypes":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"0,11 - 0,17","name":"number","parameters":[]}]},"returnTypes":{"type":"AstTypeList","types":[{"type":"AstTypeUnion","location":"0,23 - 0,35","types":[{"type":"AstTypeReference","location":"0,23 - 0,29","name":"string","parameters":[]},{"type":"AstTypeReference","location":"0,32 - 0,35","name":"nil","parameters":[]}]}]}},{"type":"AstTypeFunction","location":"0,41 - 0,55","generics":[],"genericPacks":[],"argTypes":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"0,42 - 0,48","name":"string","parameters":[]}]},"returnTypes":{"type":"AstTypeList","types":[]}}]},"exported":false})";
R"({"type":"AstStatTypeAlias","location":"0,0 - 0,55","name":"T","generics":[],"genericPacks":[],"type":{"type":"AstTypeIntersection","location":"0,9 - 0,55","types":[{"type":"AstTypeFunction","location":"0,10 - 0,35","generics":[],"genericPacks":[],"argTypes":{"types":[{"type":"AstTypeReference","location":"0,11 - 0,17","name":"number","parameters":[]}]},"returnTypes":{"types":[{"type":"AstTypeUnion","location":"0,23 - 0,35","types":[{"type":"AstTypeReference","location":"0,23 - 0,29","name":"string","parameters":[]},{"type":"AstTypeReference","location":"0,32 - 0,35","name":"nil","parameters":[]}]}]}},{"type":"AstTypeFunction","location":"0,41 - 0,55","generics":[],"genericPacks":[],"argTypes":{"types":[{"type":"AstTypeReference","location":"0,42 - 0,48","name":"string","parameters":[]}]},"returnTypes":{"types":[]}}]},"exported":false})";
CHECK(toJson(statement) == expected);
}
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstTypeError")
{
ParseResult parseResult = parse("type T = ");
ParseResult parseResult = parse(XorStr("type T = "));
REQUIRE(1 == parseResult.root->body.size);
AstStat* statement = parseResult.root->body.data[0];
@ -455,7 +411,7 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstTypePackExplicit")
CHECK(2 == root->body.size);
std::string_view expected =
R"({"type":"AstStatLocal","location":"2,8 - 2,36","vars":[{"luauType":{"type":"AstTypeReference","location":"2,17 - 2,36","name":"A","parameters":[{"type":"AstTypePackExplicit","location":"2,19 - 2,20","typeList":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"2,20 - 2,26","name":"number","parameters":[]},{"type":"AstTypeReference","location":"2,28 - 2,34","name":"string","parameters":[]}]}}]},"name":"a","type":"AstLocal","location":"2,14 - 2,15"}],"values":[]})";
R"({"type":"AstStatLocal","location":"2,8 - 2,36","vars":[{"type":{"type":"AstTypeReference","location":"2,17 - 2,36","name":"A","parameters":[{"type":"AstTypePackExplicit","location":"2,19 - 2,20","typeList":{"types":[{"type":"AstTypeReference","location":"2,20 - 2,26","name":"number","parameters":[]},{"type":"AstTypeReference","location":"2,28 - 2,34","name":"string","parameters":[]}]}}]},"name":"a","location":"2,14 - 2,15"}],"values":[]})";
CHECK(toJson(root->body.data[1]) == expected);
}

View file

@ -1,16 +1,16 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/TypeInfer.h"
#include "Fixture.h"
#include "ScopedFlags.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
static void merge(TypeArena& arena, RefinementMap& l, const RefinementMap& r)
{
Luau::merge(l, r, [&arena](TypeId a, TypeId b) -> TypeId {
lluz::merge(l, r, [&arena](TypeId a, TypeId b) -> TypeId {
// TODO: normalize here also.
std::unordered_set<TypeId> s;
@ -34,9 +34,9 @@ static LValue mkSymbol(const std::string& s)
return Symbol{AstName{s.data()}};
}
TEST_SUITE_BEGIN("LValue");
TEST_SUITE_BEGIN(XorStr("LValue"));
TEST_CASE("Luau_merge_hashmap_order")
TEST_CASE("lluz_merge_hashmap_order")
{
std::string a = "a";
std::string b = "b";
@ -66,7 +66,7 @@ TEST_CASE("Luau_merge_hashmap_order")
CHECK_EQ("boolean | number", toString(m[mkSymbol(c)]));
}
TEST_CASE("Luau_merge_hashmap_order2")
TEST_CASE("lluz_merge_hashmap_order2")
{
std::string a = "a";
std::string b = "b";

View file

@ -1,15 +1,15 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Linter.h"
#include "Luau/BuiltinDefinitions.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Linter.h"
#include "lluz/BuiltinDefinitions.h"
#include "Fixture.h"
#include "ScopedFlags.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("Linter");
TEST_SUITE_BEGIN(XorStr("Linter"));
TEST_CASE_FIXTURE(Fixture, "CleanCode")
{
@ -26,10 +26,10 @@ return math.max(fib(5), 1)
TEST_CASE_FIXTURE(Fixture, "UnknownGlobal")
{
LintResult result = lint("--!nocheck\nreturn foo");
LintResult result = lint(XorStr("--!nocheck\nreturn foo"));
REQUIRE_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Unknown global 'foo'");
CHECK_EQ(result.warnings[0].text, XorStr("Unknown global 'foo'"));
}
TEST_CASE_FIXTURE(Fixture, "DeprecatedGlobal")
@ -37,10 +37,10 @@ TEST_CASE_FIXTURE(Fixture, "DeprecatedGlobal")
// Normally this would be defined externally, so hack it in for testing
addGlobalBinding(typeChecker, "Wait", Binding{typeChecker.anyType, {}, true, "wait", "@test/global/Wait"});
LintResult result = lintTyped("Wait(5)");
LintResult result = lintTyped(XorStr("Wait(5)"));
REQUIRE_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Global 'Wait' is deprecated, use 'wait' instead");
CHECK_EQ(result.warnings[0].text, XorStr("Global 'Wait' is deprecated, use 'wait' instead"));
}
TEST_CASE_FIXTURE(Fixture, "PlaceholderRead")
@ -51,7 +51,7 @@ return _
)");
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Placeholder value '_' is read here; consider using a named variable");
CHECK_EQ(result.warnings[0].text, XorStr("Placeholder value '_' is read here; consider using a named variable"));
}
TEST_CASE_FIXTURE(Fixture, "PlaceholderReadGlobal")
@ -62,7 +62,7 @@ print(_)
)");
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Placeholder value '_' is read here; consider using a named variable");
CHECK_EQ(result.warnings[0].text, XorStr("Placeholder value '_' is read here; consider using a named variable"));
}
TEST_CASE_FIXTURE(Fixture, "PlaceholderWrite")
@ -87,8 +87,8 @@ assert(5)
)");
CHECK_EQ(result.warnings.size(), 2);
CHECK_EQ(result.warnings[0].text, "Built-in global 'math' is overwritten here; consider using a local or changing the name");
CHECK_EQ(result.warnings[1].text, "Built-in global 'assert' is overwritten here; consider using a local or changing the name");
CHECK_EQ(result.warnings[0].text, XorStr("Built-in global 'math' is overwritten here; consider using a local or changing the name"));
CHECK_EQ(result.warnings[1].text, XorStr("Built-in global 'assert' is overwritten here; consider using a local or changing the name"));
}
TEST_CASE_FIXTURE(Fixture, "MultilineBlock")
@ -98,7 +98,7 @@ if true then print(1) print(2) print(3) end
)");
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "A new statement is on the same line; add semi-colon on previous statement to silence");
CHECK_EQ(result.warnings[0].text, XorStr("A new statement is on the same line; add semi-colon on previous statement to silence"));
}
TEST_CASE_FIXTURE(Fixture, "MultilineBlockSemicolonsWhitelisted")
@ -117,7 +117,7 @@ print(1); print(2) print(3)
)");
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "A new statement is on the same line; add semi-colon on previous statement to silence");
CHECK_EQ(result.warnings[0].text, XorStr("A new statement is on the same line; add semi-colon on previous statement to silence"));
}
TEST_CASE_FIXTURE(Fixture, "MultilineBlockLocalDo")
@ -139,7 +139,7 @@ print(math.max(1,
)");
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Statement spans multiple lines; use indentation to silence");
CHECK_EQ(result.warnings[0].text, XorStr("Statement spans multiple lines; use indentation to silence"));
}
TEST_CASE_FIXTURE(Fixture, "GlobalAsLocal")
@ -154,12 +154,12 @@ return bar()
)");
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Global 'foo' is only used in the enclosing function 'bar'; consider changing it to local");
CHECK_EQ(result.warnings[0].text, XorStr("Global 'foo' is only used in the enclosing function 'bar'; consider changing it to local"));
}
TEST_CASE_FIXTURE(Fixture, "GlobalAsLocalMultiFx")
{
ScopedFastFlag sff{"LuauLintGlobalNeverReadBeforeWritten", true};
ScopedFastFlag sff{"lluzLintGlobalNeverReadBeforeWritten", true};
LintResult result = lint(R"(
function bar()
foo = 6
@ -175,12 +175,12 @@ return bar() + baz()
)");
REQUIRE_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Global 'foo' is never read before being written. Consider changing it to local");
CHECK_EQ(result.warnings[0].text, XorStr("Global 'foo' is never read before being written. Consider changing it to local"));
}
TEST_CASE_FIXTURE(Fixture, "GlobalAsLocalMultiFxWithRead")
{
ScopedFastFlag sff{"LuauLintGlobalNeverReadBeforeWritten", true};
ScopedFastFlag sff{"lluzLintGlobalNeverReadBeforeWritten", true};
LintResult result = lint(R"(
function bar()
foo = 6
@ -204,7 +204,7 @@ return bar() + baz() + read()
TEST_CASE_FIXTURE(Fixture, "GlobalAsLocalWithConditional")
{
ScopedFastFlag sff{"LuauLintGlobalNeverReadBeforeWritten", true};
ScopedFastFlag sff{"lluzLintGlobalNeverReadBeforeWritten", true};
LintResult result = lint(R"(
function bar()
if true then foo = 6 end
@ -224,7 +224,7 @@ return bar() + baz()
TEST_CASE_FIXTURE(Fixture, "GlobalAsLocal3WithConditionalRead")
{
ScopedFastFlag sff{"LuauLintGlobalNeverReadBeforeWritten", true};
ScopedFastFlag sff{"lluzLintGlobalNeverReadBeforeWritten", true};
LintResult result = lint(R"(
function bar()
foo = 6
@ -248,7 +248,7 @@ return bar() + baz() + read()
TEST_CASE_FIXTURE(Fixture, "GlobalAsLocalInnerRead")
{
ScopedFastFlag sff{"LuauLintGlobalNeverReadBeforeWritten", true};
ScopedFastFlag sff{"lluzLintGlobalNeverReadBeforeWritten", true};
LintResult result = lint(R"(
function foo()
local f = function() return bar end
@ -292,7 +292,7 @@ fnB() -- prints "false", "nil"
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text,
"Global 'moreInternalLogic' is only used in the enclosing function defined at line 2; consider changing it to local");
XorStr("Global 'moreInternalLogic' is only used in the enclosing function defined at line 2; consider changing it to local"));
}
TEST_CASE_FIXTURE(Fixture, "LocalShadowLocal")
@ -306,7 +306,7 @@ print(arg)
)");
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Variable 'arg' shadows previous declaration at line 2");
CHECK_EQ(result.warnings[0].text, XorStr("Variable 'arg' shadows previous declaration at line 2"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "LocalShadowGlobal")
@ -324,7 +324,7 @@ return bar()
)");
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Variable 'global' shadows a global variable used at line 3");
CHECK_EQ(result.warnings[0].text, XorStr("Variable 'global' shadows a global variable used at line 3"));
}
TEST_CASE_FIXTURE(Fixture, "LocalShadowArgument")
@ -339,7 +339,7 @@ return bar()
)");
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Variable 'a' shadows previous declaration at line 2");
CHECK_EQ(result.warnings[0].text, XorStr("Variable 'a' shadows previous declaration at line 2"));
}
TEST_CASE_FIXTURE(Fixture, "LocalUnused")
@ -359,14 +359,14 @@ return bar()
)");
CHECK_EQ(result.warnings.size(), 2);
CHECK_EQ(result.warnings[0].text, "Variable 'arg' is never used; prefix with '_' to silence");
CHECK_EQ(result.warnings[1].text, "Variable 'blarg' is never used; prefix with '_' to silence");
CHECK_EQ(result.warnings[0].text, XorStr("Variable 'arg' is never used; prefix with '_' to silence"));
CHECK_EQ(result.warnings[1].text, XorStr("Variable 'blarg' is never used; prefix with '_' to silence"));
}
TEST_CASE_FIXTURE(Fixture, "ImportUnused")
{
// Normally this would be defined externally, so hack it in for testing
addGlobalBinding(typeChecker, "game", typeChecker.anyType, "@test");
addGlobalBinding(typeChecker, XorStr("game", typeChecker.anyType, "@test"));
LintResult result = lint(R"(
local Roact = require(game.Packages.Roact)
@ -374,7 +374,7 @@ local _Roact = require(game.Packages.Roact)
)");
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Import 'Roact' is never used; prefix with '_' to silence");
CHECK_EQ(result.warnings[0].text, XorStr("Import 'Roact' is never used; prefix with '_' to silence"));
}
TEST_CASE_FIXTURE(Fixture, "FunctionUnused")
@ -399,8 +399,8 @@ return foo()
)");
CHECK_EQ(result.warnings.size(), 2);
CHECK_EQ(result.warnings[0].text, "Function 'bar' is never used; prefix with '_' to silence");
CHECK_EQ(result.warnings[1].text, "Function 'qux' is never used; prefix with '_' to silence");
CHECK_EQ(result.warnings[0].text, XorStr("Function 'bar' is never used; prefix with '_' to silence"));
CHECK_EQ(result.warnings[1].text, XorStr("Function 'qux' is never used; prefix with '_' to silence"));
}
TEST_CASE_FIXTURE(Fixture, "UnreachableCodeBasic")
@ -415,7 +415,7 @@ print("hi!")
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 5);
CHECK_EQ(result.warnings[0].text, "Unreachable code (previous statement always returns)");
CHECK_EQ(result.warnings[0].text, XorStr("Unreachable code (previous statement always returns)"));
}
TEST_CASE_FIXTURE(Fixture, "UnreachableCodeLoopBreak")
@ -431,7 +431,7 @@ print("hi!")
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 3);
CHECK_EQ(result.warnings[0].text, "Unreachable code (previous statement always breaks)");
CHECK_EQ(result.warnings[0].text, XorStr("Unreachable code (previous statement always breaks)"));
}
TEST_CASE_FIXTURE(Fixture, "UnreachableCodeLoopContinue")
@ -447,7 +447,7 @@ print("hi!")
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 3);
CHECK_EQ(result.warnings[0].text, "Unreachable code (previous statement always continues)");
CHECK_EQ(result.warnings[0].text, XorStr("Unreachable code (previous statement always continues)"));
}
TEST_CASE_FIXTURE(Fixture, "UnreachableCodeIfMerge")
@ -483,7 +483,7 @@ return { foo1, foo2, foo3 }
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 7);
CHECK_EQ(result.warnings[0].text, "Unreachable code (previous statement always returns)");
CHECK_EQ(result.warnings[0].text, XorStr("Unreachable code (previous statement always returns)"));
}
TEST_CASE_FIXTURE(Fixture, "UnreachableCodeErrorReturnSilent")
@ -538,7 +538,7 @@ return foo1
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 7);
CHECK_EQ(result.warnings[0].text, "Unreachable code (previous statement always errors)");
CHECK_EQ(result.warnings[0].text, XorStr("Unreachable code (previous statement always errors)"));
}
TEST_CASE_FIXTURE(Fixture, "UnreachableCodeErrorReturnPropagate")
@ -559,7 +559,7 @@ return foo1
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 8);
CHECK_EQ(result.warnings[0].text, "Unreachable code (previous statement always errors)");
CHECK_EQ(result.warnings[0].text, XorStr("Unreachable code (previous statement always errors)"));
}
TEST_CASE_FIXTURE(Fixture, "UnreachableCodeLoopWhile")
@ -602,7 +602,7 @@ TEST_CASE_FIXTURE(Fixture, "UnknownType")
{"ClassName", {typeChecker.anyType}},
};
TableTypeVar instanceTable{instanceProps, std::nullopt, typeChecker.globalScope->level, Luau::TableState::Sealed};
TableTypeVar instanceTable{instanceProps, std::nullopt, typeChecker.globalScope->level, lluz::TableState::Sealed};
TypeId instanceType = typeChecker.globalTypes.addType(instanceTable);
TypeFun instanceTypeFun{{}, instanceType};
@ -610,22 +610,22 @@ TEST_CASE_FIXTURE(Fixture, "UnknownType")
LintResult result = lint(R"(
local game = ...
local _e01 = type(game) == "Part"
local _e02 = typeof(game) == "Bar"
local _e03 = typeof(game) == "vector"
local _e01 = type(game) == XorStr("Part")
local _e02 = typeof(game) == XorStr("Bar")
local _e03 = typeof(game) == XorStr("vector")
local _o01 = type(game) == "number"
local _o02 = type(game) == "vector"
local _o03 = typeof(game) == "Part"
local _o01 = type(game) == XorStr("number")
local _o02 = type(game) == XorStr("vector")
local _o03 = typeof(game) == XorStr("Part")
)");
REQUIRE_EQ(result.warnings.size(), 3);
CHECK_EQ(result.warnings[0].location.begin.line, 2);
CHECK_EQ(result.warnings[0].text, "Unknown type 'Part' (expected primitive type)");
CHECK_EQ(result.warnings[0].text, XorStr("Unknown type 'Part' (expected primitive type)"));
CHECK_EQ(result.warnings[1].location.begin.line, 3);
CHECK_EQ(result.warnings[1].text, "Unknown type 'Bar'");
CHECK_EQ(result.warnings[1].text, XorStr("Unknown type 'Bar'"));
CHECK_EQ(result.warnings[2].location.begin.line, 4);
CHECK_EQ(result.warnings[2].text, "Unknown type 'vector' (expected primitive or userdata type)");
CHECK_EQ(result.warnings[2].text, XorStr("Unknown type 'vector' (expected primitive or userdata type)"));
}
TEST_CASE_FIXTURE(Fixture, "ForRangeTable")
@ -642,7 +642,7 @@ end
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 3);
CHECK_EQ(result.warnings[0].text, "For loop should iterate backwards; did you forget to specify -1 as step?");
CHECK_EQ(result.warnings[0].text, XorStr("For loop should iterate backwards; did you forget to specify -1 as step?"));
}
TEST_CASE_FIXTURE(Fixture, "ForRangeBackwards")
@ -657,7 +657,7 @@ end
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 1);
CHECK_EQ(result.warnings[0].text, "For loop should iterate backwards; did you forget to specify -1 as step?");
CHECK_EQ(result.warnings[0].text, XorStr("For loop should iterate backwards; did you forget to specify -1 as step?"));
}
TEST_CASE_FIXTURE(Fixture, "ForRangeImprecise")
@ -672,7 +672,7 @@ end
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 1);
CHECK_EQ(result.warnings[0].text, "For loop ends at 7.3 instead of 7.5; did you forget to specify step?");
CHECK_EQ(result.warnings[0].text, XorStr("For loop ends at 7.3 instead of 7.5; did you forget to specify step?"));
}
TEST_CASE_FIXTURE(Fixture, "ForRangeZero")
@ -690,10 +690,10 @@ end
CHECK_EQ(result.warnings.size(), 2);
CHECK_EQ(result.warnings[0].location.begin.line, 1);
CHECK_EQ(result.warnings[0].text, "For loop starts at 0, but arrays start at 1");
CHECK_EQ(result.warnings[0].text, XorStr("For loop starts at 0, but arrays start at 1"));
CHECK_EQ(result.warnings[1].location.begin.line, 7);
CHECK_EQ(result.warnings[1].text,
"For loop should iterate backwards; did you forget to specify -1 as step? Also consider changing 0 to 1 since arrays start at 1");
XorStr("For loop should iterate backwards; did you forget to specify -1 as step? Also consider changing 0 to 1 since arrays start at 1"));
}
TEST_CASE_FIXTURE(Fixture, "UnbalancedAssignment")
@ -718,9 +718,9 @@ end
CHECK_EQ(result.warnings.size(), 2);
CHECK_EQ(result.warnings[0].location.begin.line, 5);
CHECK_EQ(result.warnings[0].text, "Assigning 2 values to 3 variables initializes extra variables with nil; add 'nil' to value list to silence");
CHECK_EQ(result.warnings[0].text, XorStr("Assigning 2 values to 3 variables initializes extra variables with nil; add 'nil' to value list to silence"));
CHECK_EQ(result.warnings[1].location.begin.line, 11);
CHECK_EQ(result.warnings[1].text, "Assigning 4 values to 3 variables leaves some values unused");
CHECK_EQ(result.warnings[1].text, XorStr("Assigning 4 values to 3 variables leaves some values unused"));
}
TEST_CASE_FIXTURE(Fixture, "ImplicitReturn")
@ -784,13 +784,13 @@ return f1,f2,f3,f4,f5,f6,f7
CHECK_EQ(result.warnings.size(), 3);
CHECK_EQ(result.warnings[0].location.begin.line, 4);
CHECK_EQ(result.warnings[0].text,
"Function 'f1' can implicitly return no values even though there's an explicit return at line 4; add explicit return to silence");
XorStr("Function 'f1' can implicitly return no values even though there's an explicit return at line 4; add explicit return to silence"));
CHECK_EQ(result.warnings[1].location.begin.line, 28);
CHECK_EQ(result.warnings[1].text,
"Function 'f4' can implicitly return no values even though there's an explicit return at line 25; add explicit return to silence");
XorStr("Function 'f4' can implicitly return no values even though there's an explicit return at line 25; add explicit return to silence"));
CHECK_EQ(result.warnings[2].location.begin.line, 44);
CHECK_EQ(result.warnings[2].text,
"Function can implicitly return no values even though there's an explicit return at line 44; add explicit return to silence");
XorStr("Function can implicitly return no values even though there's an explicit return at line 44; add explicit return to silence"));
}
TEST_CASE_FIXTURE(Fixture, "ImplicitReturnInfiniteLoop")
@ -840,10 +840,10 @@ return f1,f2,f3,f4
CHECK_EQ(result.warnings.size(), 2);
CHECK_EQ(result.warnings[0].location.begin.line, 25);
CHECK_EQ(result.warnings[0].text,
"Function 'f3' can implicitly return no values even though there's an explicit return at line 21; add explicit return to silence");
XorStr("Function 'f3' can implicitly return no values even though there's an explicit return at line 21; add explicit return to silence"));
CHECK_EQ(result.warnings[1].location.begin.line, 36);
CHECK_EQ(result.warnings[1].text,
"Function 'f4' can implicitly return no values even though there's an explicit return at line 32; add explicit return to silence");
XorStr("Function 'f4' can implicitly return no values even though there's an explicit return at line 32; add explicit return to silence"));
}
TEST_CASE_FIXTURE(Fixture, "TypeAnnotationsShouldNotProduceWarnings")
@ -901,29 +901,29 @@ return foo
)");
CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Variable 'x' is never used; prefix with '_' to silence");
CHECK_EQ(result.warnings[0].text, XorStr("Variable 'x' is never used; prefix with '_' to silence"));
}
TEST_CASE_FIXTURE(Fixture, "FormatStringFormat")
{
LintResult result = lint(R"(
-- incorrect format strings
string.format("%")
string.format("%??d")
string.format("%Y")
string.format(XorStr("%"))
string.format(XorStr("%??d"))
string.format(XorStr("%Y"))
-- incorrect format strings, self call
local _ = ("%"):format()
-- correct format strings, just to uh make sure
string.format("hello %+10d %.02f %%", 4, 5)
string.format(XorStr("hello %+10d %.02f %%"), 4, 5)
)");
CHECK_EQ(result.warnings.size(), 4);
CHECK_EQ(result.warnings[0].text, "Invalid format string: unfinished format specifier");
CHECK_EQ(result.warnings[1].text, "Invalid format string: invalid format specifier: must be a string format specifier or %");
CHECK_EQ(result.warnings[2].text, "Invalid format string: invalid format specifier: must be a string format specifier or %");
CHECK_EQ(result.warnings[3].text, "Invalid format string: unfinished format specifier");
CHECK_EQ(result.warnings[0].text, XorStr("Invalid format string: unfinished format specifier"));
CHECK_EQ(result.warnings[1].text, XorStr("Invalid format string: invalid format specifier: must be a string format specifier or %"));
CHECK_EQ(result.warnings[2].text, XorStr("Invalid format string: invalid format specifier: must be a string format specifier or %"));
CHECK_EQ(result.warnings[3].text, XorStr("Invalid format string: unfinished format specifier"));
}
TEST_CASE_FIXTURE(Fixture, "FormatStringPack")
@ -960,17 +960,17 @@ string.packsize("=!1bbbI3c42")
)");
CHECK_EQ(result.warnings.size(), 11);
CHECK_EQ(result.warnings[0].text, "Invalid pack format: unexpected character; must be a pack specifier or space");
CHECK_EQ(result.warnings[1].text, "Invalid pack format: unexpected character; must be a pack specifier or space");
CHECK_EQ(result.warnings[2].text, "Invalid pack format: unexpected character; must be a pack specifier or space");
CHECK_EQ(result.warnings[3].text, "Invalid pack format: fixed-sized string format must specify the size");
CHECK_EQ(result.warnings[4].text, "Invalid pack format: X must be followed by a size specifier");
CHECK_EQ(result.warnings[5].text, "Invalid pack format: X must be followed by a size specifier");
CHECK_EQ(result.warnings[6].text, "Invalid pack format: pack specifier must be fixed-size");
CHECK_EQ(result.warnings[7].text, "Invalid pack format: integer size must be in range [1,16]");
CHECK_EQ(result.warnings[8].text, "Invalid pack format: integer size must be in range [1,16]");
CHECK_EQ(result.warnings[9].text, "Invalid pack format: size specifier is too large");
CHECK_EQ(result.warnings[10].text, "Invalid pack format: size specifier is too large");
CHECK_EQ(result.warnings[0].text, XorStr("Invalid pack format: unexpected character; must be a pack specifier or space"));
CHECK_EQ(result.warnings[1].text, XorStr("Invalid pack format: unexpected character; must be a pack specifier or space"));
CHECK_EQ(result.warnings[2].text, XorStr("Invalid pack format: unexpected character; must be a pack specifier or space"));
CHECK_EQ(result.warnings[3].text, XorStr("Invalid pack format: fixed-sized string format must specify the size"));
CHECK_EQ(result.warnings[4].text, XorStr("Invalid pack format: X must be followed by a size specifier"));
CHECK_EQ(result.warnings[5].text, XorStr("Invalid pack format: X must be followed by a size specifier"));
CHECK_EQ(result.warnings[6].text, XorStr("Invalid pack format: pack specifier must be fixed-size"));
CHECK_EQ(result.warnings[7].text, XorStr("Invalid pack format: integer size must be in range [1,16]"));
CHECK_EQ(result.warnings[8].text, XorStr("Invalid pack format: integer size must be in range [1,16]"));
CHECK_EQ(result.warnings[9].text, XorStr("Invalid pack format: size specifier is too large"));
CHECK_EQ(result.warnings[10].text, XorStr("Invalid pack format: size specifier is too large"));
}
TEST_CASE_FIXTURE(Fixture, "FormatStringMatch")
@ -1004,20 +1004,20 @@ string.match(s, "[A-Z]+(%d)%1")
)");
CHECK_EQ(result.warnings.size(), 14);
CHECK_EQ(result.warnings[0].text, "Invalid match pattern: invalid character class, must refer to a defined class or its inverse");
CHECK_EQ(result.warnings[1].text, "Invalid match pattern: invalid character class, must refer to a defined class or its inverse");
CHECK_EQ(result.warnings[2].text, "Invalid match pattern: invalid character class, must refer to a defined class or its inverse");
CHECK_EQ(result.warnings[3].text, "Invalid match pattern: invalid character class, must refer to a defined class or its inverse");
CHECK_EQ(result.warnings[4].text, "Invalid match pattern: unfinished character class");
CHECK_EQ(result.warnings[5].text, "Invalid match pattern: sets can not contain capture references");
CHECK_EQ(result.warnings[6].text, "Invalid match pattern: invalid capture reference, must be 1-9");
CHECK_EQ(result.warnings[7].text, "Invalid match pattern: invalid capture reference, must refer to a valid capture");
CHECK_EQ(result.warnings[8].text, "Invalid match pattern: missing brace characters for balanced match");
CHECK_EQ(result.warnings[9].text, "Invalid match pattern: missing set after a frontier pattern");
CHECK_EQ(result.warnings[10].text, "Invalid match pattern: unexpected ) without a matching (");
CHECK_EQ(result.warnings[11].text, "Invalid match pattern: expected ) at the end of the string to close a capture");
CHECK_EQ(result.warnings[12].text, "Invalid match pattern: expected ] at the end of the string to close a set");
CHECK_EQ(result.warnings[13].text, "Invalid match pattern: expected a magic character after %");
CHECK_EQ(result.warnings[0].text, XorStr("Invalid match pattern: invalid character class, must refer to a defined class or its inverse"));
CHECK_EQ(result.warnings[1].text, XorStr("Invalid match pattern: invalid character class, must refer to a defined class or its inverse"));
CHECK_EQ(result.warnings[2].text, XorStr("Invalid match pattern: invalid character class, must refer to a defined class or its inverse"));
CHECK_EQ(result.warnings[3].text, XorStr("Invalid match pattern: invalid character class, must refer to a defined class or its inverse"));
CHECK_EQ(result.warnings[4].text, XorStr("Invalid match pattern: unfinished character class"));
CHECK_EQ(result.warnings[5].text, XorStr("Invalid match pattern: sets can not contain capture references"));
CHECK_EQ(result.warnings[6].text, XorStr("Invalid match pattern: invalid capture reference, must be 1-9"));
CHECK_EQ(result.warnings[7].text, XorStr("Invalid match pattern: invalid capture reference, must refer to a valid capture"));
CHECK_EQ(result.warnings[8].text, XorStr("Invalid match pattern: missing brace characters for balanced match"));
CHECK_EQ(result.warnings[9].text, XorStr("Invalid match pattern: missing set after a frontier pattern"));
CHECK_EQ(result.warnings[10].text, XorStr("Invalid match pattern: unexpected ) without a matching ("));
CHECK_EQ(result.warnings[11].text, XorStr("Invalid match pattern: expected ) at the end of the string to close a capture"));
CHECK_EQ(result.warnings[12].text, XorStr("Invalid match pattern: expected ] at the end of the string to close a set"));
CHECK_EQ(result.warnings[13].text, XorStr("Invalid match pattern: expected a magic character after %"));
}
TEST_CASE_FIXTURE(Fixture, "FormatStringMatchNested")
@ -1036,9 +1036,9 @@ string.match(s, "((a)%3)")
)~");
CHECK_EQ(result.warnings.size(), 2);
CHECK_EQ(result.warnings[0].text, "Invalid match pattern: invalid capture reference, must refer to a closed capture");
CHECK_EQ(result.warnings[0].text, XorStr("Invalid match pattern: invalid capture reference, must refer to a closed capture"));
CHECK_EQ(result.warnings[0].location.begin.line, 7);
CHECK_EQ(result.warnings[1].text, "Invalid match pattern: invalid capture reference, must refer to a valid capture");
CHECK_EQ(result.warnings[1].text, XorStr("Invalid match pattern: invalid capture reference, must refer to a valid capture"));
CHECK_EQ(result.warnings[1].location.begin.line, 10);
}
@ -1074,13 +1074,13 @@ string.match(s, "[^]|'[]")
)~");
CHECK_EQ(result.warnings.size(), 7);
CHECK_EQ(result.warnings[0].text, "Invalid match pattern: expected ] at the end of the string to close a set");
CHECK_EQ(result.warnings[1].text, "Invalid match pattern: expected ] at the end of the string to close a set");
CHECK_EQ(result.warnings[2].text, "Invalid match pattern: character range can't include character sets");
CHECK_EQ(result.warnings[3].text, "Invalid match pattern: character range can't include character sets");
CHECK_EQ(result.warnings[4].text, "Invalid match pattern: invalid character class, must refer to a defined class or its inverse");
CHECK_EQ(result.warnings[5].text, "Invalid match pattern: expected a magic character after %");
CHECK_EQ(result.warnings[6].text, "Invalid match pattern: sets can not contain capture references");
CHECK_EQ(result.warnings[0].text, XorStr("Invalid match pattern: expected ] at the end of the string to close a set"));
CHECK_EQ(result.warnings[1].text, XorStr("Invalid match pattern: expected ] at the end of the string to close a set"));
CHECK_EQ(result.warnings[2].text, XorStr("Invalid match pattern: character range can't include character sets"));
CHECK_EQ(result.warnings[3].text, XorStr("Invalid match pattern: character range can't include character sets"));
CHECK_EQ(result.warnings[4].text, XorStr("Invalid match pattern: invalid character class, must refer to a defined class or its inverse"));
CHECK_EQ(result.warnings[5].text, XorStr("Invalid match pattern: expected a magic character after %"));
CHECK_EQ(result.warnings[6].text, XorStr("Invalid match pattern: sets can not contain capture references"));
}
TEST_CASE_FIXTURE(Fixture, "FormatStringFindArgs")
@ -1100,14 +1100,14 @@ string.find(s, "%q", 1, false)
-- missing arguments
string.find()
string.find("foo");
string.find(XorStr("foo"));
("foo"):find()
)");
CHECK_EQ(result.warnings.size(), 2);
CHECK_EQ(result.warnings[0].text, "Invalid match pattern: invalid character class, must refer to a defined class or its inverse");
CHECK_EQ(result.warnings[0].text, XorStr("Invalid match pattern: invalid character class, must refer to a defined class or its inverse"));
CHECK_EQ(result.warnings[0].location.begin.line, 4);
CHECK_EQ(result.warnings[1].text, "Invalid match pattern: invalid character class, must refer to a defined class or its inverse");
CHECK_EQ(result.warnings[1].text, XorStr("Invalid match pattern: invalid character class, must refer to a defined class or its inverse"));
CHECK_EQ(result.warnings[1].location.begin.line, 11);
}
@ -1128,10 +1128,10 @@ string.gsub(s, 'foo', "%0")
)");
CHECK_EQ(result.warnings.size(), 4);
CHECK_EQ(result.warnings[0].text, "Invalid match replacement: unfinished replacement");
CHECK_EQ(result.warnings[1].text, "Invalid match replacement: unexpected replacement character; must be a digit or %");
CHECK_EQ(result.warnings[2].text, "Invalid match replacement: invalid capture index, must refer to pattern capture");
CHECK_EQ(result.warnings[3].text, "Invalid match replacement: invalid capture index, must refer to pattern capture");
CHECK_EQ(result.warnings[0].text, XorStr("Invalid match replacement: unfinished replacement"));
CHECK_EQ(result.warnings[1].text, XorStr("Invalid match replacement: unexpected replacement character; must be a digit or %"));
CHECK_EQ(result.warnings[2].text, XorStr("Invalid match replacement: invalid capture index, must refer to pattern capture"));
CHECK_EQ(result.warnings[3].text, XorStr("Invalid match replacement: invalid capture index, must refer to pattern capture"));
}
TEST_CASE_FIXTURE(Fixture, "FormatStringDate")
@ -1149,10 +1149,10 @@ os.date("!*t")
)");
CHECK_EQ(result.warnings.size(), 4);
CHECK_EQ(result.warnings[0].text, "Invalid date format: unfinished replacement");
CHECK_EQ(result.warnings[1].text, "Invalid date format: unexpected replacement character; must be a date format specifier or %");
CHECK_EQ(result.warnings[2].text, "Invalid date format: unexpected replacement character; must be a date format specifier or %");
CHECK_EQ(result.warnings[3].text, "Invalid date format: date format can not contain null characters");
CHECK_EQ(result.warnings[0].text, XorStr("Invalid date format: unfinished replacement"));
CHECK_EQ(result.warnings[1].text, XorStr("Invalid date format: unexpected replacement character; must be a date format specifier or %"));
CHECK_EQ(result.warnings[2].text, XorStr("Invalid date format: unexpected replacement character; must be a date format specifier or %"));
CHECK_EQ(result.warnings[3].text, XorStr("Invalid date format: date format can not contain null characters"));
}
TEST_CASE_FIXTURE(Fixture, "FormatStringTyped")
@ -1168,9 +1168,9 @@ nons:match("[]")
)~");
CHECK_EQ(result.warnings.size(), 2);
CHECK_EQ(result.warnings[0].text, "Invalid match pattern: expected ] at the end of the string to close a set");
CHECK_EQ(result.warnings[0].text, XorStr("Invalid match pattern: expected ] at the end of the string to close a set"));
CHECK_EQ(result.warnings[0].location.begin.line, 3);
CHECK_EQ(result.warnings[1].text, "Invalid match pattern: expected ] at the end of the string to close a set");
CHECK_EQ(result.warnings[1].text, XorStr("Invalid match pattern: expected ] at the end of the string to close a set"));
CHECK_EQ(result.warnings[1].location.begin.line, 4);
}
@ -1218,12 +1218,12 @@ _ = {
)");
CHECK_EQ(result.warnings.size(), 6);
CHECK_EQ(result.warnings[0].text, "Table field 'first' is a duplicate; previously defined at line 3");
CHECK_EQ(result.warnings[1].text, "Table field 'first' is a duplicate; previously defined at line 9");
CHECK_EQ(result.warnings[2].text, "Table index 1 is a duplicate; previously defined as a list entry");
CHECK_EQ(result.warnings[3].text, "Table index 3 is a duplicate; previously defined as a list entry");
CHECK_EQ(result.warnings[4].text, "Table type field 'first' is a duplicate; previously defined at line 24");
CHECK_EQ(result.warnings[5].text, "Table index 1 is a duplicate; previously defined at line 36");
CHECK_EQ(result.warnings[0].text, XorStr("Table field 'first' is a duplicate; previously defined at line 3"));
CHECK_EQ(result.warnings[1].text, XorStr("Table field 'first' is a duplicate; previously defined at line 9"));
CHECK_EQ(result.warnings[2].text, XorStr("Table index 1 is a duplicate; previously defined as a list entry"));
CHECK_EQ(result.warnings[3].text, XorStr("Table index 3 is a duplicate; previously defined as a list entry"));
CHECK_EQ(result.warnings[4].text, XorStr("Table type field 'first' is a duplicate; previously defined at line 24"));
CHECK_EQ(result.warnings[5].text, XorStr("Table index 1 is a duplicate; previously defined at line 36"));
}
TEST_CASE_FIXTURE(Fixture, "ImportOnlyUsedInTypeAnnotation")
@ -1235,7 +1235,7 @@ TEST_CASE_FIXTURE(Fixture, "ImportOnlyUsedInTypeAnnotation")
)");
REQUIRE_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Variable 'x' is never used; prefix with '_' to silence");
CHECK_EQ(result.warnings[0].text, XorStr("Variable 'x' is never used; prefix with '_' to silence"));
}
TEST_CASE_FIXTURE(Fixture, "DisableUnknownGlobalWithTypeChecking")
@ -1262,12 +1262,12 @@ TEST_CASE_FIXTURE(Fixture, "no_spurious_warning_after_a_function_type_alias")
TEST_CASE_FIXTURE(Fixture, "use_all_parent_scopes_for_globals")
{
ScopePtr testScope = frontend.addEnvironment("Test");
ScopePtr testScope = frontend.addEnvironment(XorStr("Test"));
unfreeze(typeChecker.globalTypes);
loadDefinitionFile(frontend.typeChecker, testScope, R"(
declare Foo: number
)",
"@test");
XorStr("@test"));
freeze(typeChecker.globalTypes);
fileResolver.environments["A"] = "Test";
@ -1278,7 +1278,7 @@ TEST_CASE_FIXTURE(Fixture, "use_all_parent_scopes_for_globals")
local _bar: typeof(os.clock) = os.clock
)";
LintResult result = frontend.lint("A");
LintResult result = frontend.lint(XorStr("A"));
CHECK_EQ(result.warnings.size(), 0);
}
@ -1307,9 +1307,9 @@ end
)");
CHECK_EQ(result.warnings.size(), 3);
CHECK_EQ(result.warnings[0].text, "Variable 'x' defined at line 4 is never initialized or assigned; initialize with 'nil' to silence");
CHECK_EQ(result.warnings[1].text, "Assigning 2 values to 3 variables initializes extra variables with nil; add 'nil' to value list to silence");
CHECK_EQ(result.warnings[2].text, "Variable 'c' defined at line 12 is never initialized or assigned; initialize with 'nil' to silence");
CHECK_EQ(result.warnings[0].text, XorStr("Variable 'x' defined at line 4 is never initialized or assigned; initialize with 'nil' to silence"));
CHECK_EQ(result.warnings[1].text, XorStr("Assigning 2 values to 3 variables initializes extra variables with nil; add 'nil' to value list to silence"));
CHECK_EQ(result.warnings[2].text, XorStr("Variable 'c' defined at line 12 is never initialized or assigned; initialize with 'nil' to silence"));
}
TEST_CASE_FIXTURE(Fixture, "LocalFunctionNotDead")
@ -1446,7 +1446,7 @@ TEST_CASE_FIXTURE(Fixture, "DeprecatedApi")
{"Wait", {typeChecker.anyType, /* deprecated= */ true}},
};
TypeId colorType = typeChecker.globalTypes.addType(TableTypeVar{{}, std::nullopt, typeChecker.globalScope->level, Luau::TableState::Sealed});
TypeId colorType = typeChecker.globalTypes.addType(TableTypeVar{{}, std::nullopt, typeChecker.globalScope->level, lluz::TableState::Sealed});
getMutable<TableTypeVar>(colorType)->props = {{"toHSV", {typeChecker.anyType, /* deprecated= */ true, "Color3:ToHSV"}}};
@ -1465,9 +1465,9 @@ end
)");
REQUIRE_EQ(result.warnings.size(), 3);
CHECK_EQ(result.warnings[0].text, "Member 'Instance.Wait' is deprecated");
CHECK_EQ(result.warnings[1].text, "Member 'toHSV' is deprecated, use 'Color3:ToHSV' instead");
CHECK_EQ(result.warnings[2].text, "Member 'Instance.DataCost' is deprecated");
CHECK_EQ(result.warnings[0].text, XorStr("Member 'Instance.Wait' is deprecated"));
CHECK_EQ(result.warnings[1].text, XorStr("Member 'toHSV' is deprecated, use 'Color3:ToHSV' instead"));
CHECK_EQ(result.warnings[2].text, XorStr("Member 'Instance.DataCost' is deprecated"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "TableOperations")
@ -1499,20 +1499,20 @@ table.create(42, {} :: {})
REQUIRE_EQ(result.warnings.size(), 10);
CHECK_EQ(result.warnings[0].text, "table.insert will insert the value before the last element, which is likely a bug; consider removing the "
"second argument or wrap it in parentheses to silence");
CHECK_EQ(result.warnings[1].text, "table.insert will append the value to the table; consider removing the second argument for efficiency");
CHECK_EQ(result.warnings[2].text, "table.insert uses index 0 but arrays are 1-based; did you mean 1 instead?");
CHECK_EQ(result.warnings[3].text, "table.remove uses index 0 but arrays are 1-based; did you mean 1 instead?");
XorStr("second argument or wrap it in parentheses to silence"));
CHECK_EQ(result.warnings[1].text, XorStr("table.insert will append the value to the table; consider removing the second argument for efficiency"));
CHECK_EQ(result.warnings[2].text, XorStr("table.insert uses index 0 but arrays are 1-based; did you mean 1 instead?"));
CHECK_EQ(result.warnings[3].text, XorStr("table.remove uses index 0 but arrays are 1-based; did you mean 1 instead?"));
CHECK_EQ(result.warnings[4].text, "table.remove will remove the value before the last element, which is likely a bug; consider removing the "
"second argument or wrap it in parentheses to silence");
XorStr("second argument or wrap it in parentheses to silence"));
CHECK_EQ(result.warnings[5].text,
"table.insert may change behavior if the call returns more than one result; consider adding parentheses around second argument");
CHECK_EQ(result.warnings[6].text, "table.move uses index 0 but arrays are 1-based; did you mean 1 instead?");
CHECK_EQ(result.warnings[7].text, "table.move uses index 0 but arrays are 1-based; did you mean 1 instead?");
XorStr("table.insert may change behavior if the call returns more than one result; consider adding parentheses around second argument"));
CHECK_EQ(result.warnings[6].text, XorStr("table.move uses index 0 but arrays are 1-based; did you mean 1 instead?"));
CHECK_EQ(result.warnings[7].text, XorStr("table.move uses index 0 but arrays are 1-based; did you mean 1 instead?"));
CHECK_EQ(
result.warnings[8].text, "table.create with a table literal will reuse the same object for all elements; consider using a for loop instead");
result.warnings[8].text, XorStr("table.create with a table literal will reuse the same object for all elements; consider using a for loop instead"));
CHECK_EQ(
result.warnings[9].text, "table.create with a table literal will reuse the same object for all elements; consider using a for loop instead");
result.warnings[9].text, XorStr("table.create with a table literal will reuse the same object for all elements; consider using a for loop instead"));
}
TEST_CASE_FIXTURE(Fixture, "DuplicateConditions")
@ -1543,16 +1543,16 @@ _ = if true then 1 elseif true then 2 else 3
)");
REQUIRE_EQ(result.warnings.size(), 8);
CHECK_EQ(result.warnings[0].text, "Condition has already been checked on line 2");
CHECK_EQ(result.warnings[0].text, XorStr("Condition has already been checked on line 2"));
CHECK_EQ(result.warnings[0].location.begin.line + 1, 4);
CHECK_EQ(result.warnings[1].text, "Condition has already been checked on column 5");
CHECK_EQ(result.warnings[2].text, "Condition has already been checked on column 5");
CHECK_EQ(result.warnings[3].text, "Condition has already been checked on column 6");
CHECK_EQ(result.warnings[4].text, "Condition has already been checked on column 6");
CHECK_EQ(result.warnings[5].text, "Condition has already been checked on column 6");
CHECK_EQ(result.warnings[6].text, "Condition has already been checked on column 15");
CHECK_EQ(result.warnings[1].text, XorStr("Condition has already been checked on column 5"));
CHECK_EQ(result.warnings[2].text, XorStr("Condition has already been checked on column 5"));
CHECK_EQ(result.warnings[3].text, XorStr("Condition has already been checked on column 6"));
CHECK_EQ(result.warnings[4].text, XorStr("Condition has already been checked on column 6"));
CHECK_EQ(result.warnings[5].text, XorStr("Condition has already been checked on column 6"));
CHECK_EQ(result.warnings[6].text, XorStr("Condition has already been checked on column 15"));
CHECK_EQ(result.warnings[6].location.begin.line + 1, 19);
CHECK_EQ(result.warnings[7].text, "Condition has already been checked on column 8");
CHECK_EQ(result.warnings[7].text, XorStr("Condition has already been checked on column 8"));
}
TEST_CASE_FIXTURE(Fixture, "DuplicateConditionsExpr")
@ -1567,7 +1567,7 @@ end
)");
REQUIRE_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Condition has already been checked on line 4");
CHECK_EQ(result.warnings[0].text, XorStr("Condition has already been checked on line 4"));
CHECK_EQ(result.warnings[0].location.begin.line + 1, 5);
}
@ -1588,10 +1588,10 @@ return foo, moo, a1, a2
)");
REQUIRE_EQ(result.warnings.size(), 4);
CHECK_EQ(result.warnings[0].text, "Function parameter 'a1' already defined on column 14");
CHECK_EQ(result.warnings[1].text, "Variable 'a1' is never used; prefix with '_' to silence");
CHECK_EQ(result.warnings[2].text, "Variable 'a1' already defined on column 7");
CHECK_EQ(result.warnings[3].text, "Function parameter 'self' already defined implicitly");
CHECK_EQ(result.warnings[0].text, XorStr("Function parameter 'a1' already defined on column 14"));
CHECK_EQ(result.warnings[1].text, XorStr("Variable 'a1' is never used; prefix with '_' to silence"));
CHECK_EQ(result.warnings[2].text, XorStr("Variable 'a1' already defined on column 7"));
CHECK_EQ(result.warnings[3].text, XorStr("Function parameter 'self' already defined implicitly"));
}
TEST_CASE_FIXTURE(Fixture, "MisleadingAndOr")
@ -1606,9 +1606,9 @@ _ = (math.random() < 0.5 and false) or 42 -- currently ignored
REQUIRE_EQ(result.warnings.size(), 2);
CHECK_EQ(result.warnings[0].text, "The and-or expression always evaluates to the second alternative because the first alternative is false; "
"consider using if-then-else expression instead");
XorStr("consider using if-then-else expression instead"));
CHECK_EQ(result.warnings[1].text, "The and-or expression always evaluates to the second alternative because the first alternative is nil; "
"consider using if-then-else expression instead");
XorStr("consider using if-then-else expression instead"));
}
TEST_CASE_FIXTURE(Fixture, "WrongComment")
@ -1627,12 +1627,12 @@ do end
)");
REQUIRE_EQ(result.warnings.size(), 6);
CHECK_EQ(result.warnings[0].text, "Unknown comment directive 'struct'; did you mean 'strict'?");
CHECK_EQ(result.warnings[1].text, "Unknown comment directive 'nolintGlobal'");
CHECK_EQ(result.warnings[2].text, "nolint directive refers to unknown lint rule 'Global'");
CHECK_EQ(result.warnings[3].text, "nolint directive refers to unknown lint rule 'KnownGlobal'; did you mean 'UnknownGlobal'?");
CHECK_EQ(result.warnings[4].text, "Comment directive with the type checking mode has extra symbols at the end of the line");
CHECK_EQ(result.warnings[5].text, "Comment directive is ignored because it is placed after the first non-comment token");
CHECK_EQ(result.warnings[0].text, XorStr("Unknown comment directive 'struct'; did you mean 'strict'?"));
CHECK_EQ(result.warnings[1].text, XorStr("Unknown comment directive 'nolintGlobal'"));
CHECK_EQ(result.warnings[2].text, XorStr("nolint directive refers to unknown lint rule 'Global'"));
CHECK_EQ(result.warnings[3].text, XorStr("nolint directive refers to unknown lint rule 'KnownGlobal'; did you mean 'UnknownGlobal'?"));
CHECK_EQ(result.warnings[4].text, XorStr("Comment directive with the type checking mode has extra symbols at the end of the line"));
CHECK_EQ(result.warnings[5].text, XorStr("Comment directive is ignored because it is placed after the first non-comment token"));
}
TEST_CASE_FIXTURE(Fixture, "WrongCommentMuteSelf")
@ -1655,24 +1655,7 @@ end
)");
REQUIRE_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, "Condition has already been checked on line 2");
}
TEST_CASE_FIXTURE(Fixture, "WrongCommentOptimize")
{
LintResult result = lint(R"(
--!optimize
--!optimize
--!optimize me
--!optimize 100500
--!optimize 2
)");
REQUIRE_EQ(result.warnings.size(), 4);
CHECK_EQ(result.warnings[0].text, "optimize directive requires an optimization level");
CHECK_EQ(result.warnings[1].text, "optimize directive requires an optimization level");
CHECK_EQ(result.warnings[2].text, "optimize directive uses unknown optimization level 'me', 0..2 expected");
CHECK_EQ(result.warnings[3].text, "optimize directive uses unknown optimization level '100500', 0..2 expected");
CHECK_EQ(result.warnings[0].text, XorStr("Condition has already been checked on line 2"));
}
TEST_SUITE_END();

View file

@ -1,18 +1,18 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Clone.h"
#include "Luau/Module.h"
#include "Luau/Scope.h"
#include "Luau/RecursionCounter.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Clone.h"
#include "lluz/Module.h"
#include "lluz/Scope.h"
#include "lluz/RecursionCounter.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
LUAU_FASTFLAG(LuauLowerBoundsCalculation);
lluz_FASTFLAG(LluLowerBoundsCalculation);
TEST_SUITE_BEGIN("ModuleTests");
TEST_SUITE_BEGIN(XorStr("ModuleTests"));
TEST_CASE_FIXTURE(Fixture, "is_within_comment")
{
@ -78,14 +78,14 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
/* The inferred type of Cyclic is {get: () -> Cyclic}
*
* Assert that the return type of get() is the same as the outer table.
*/
TypeId counterType = requireType("Cyclic");
TypeId counterType = requireType(XorStr("Cyclic"));
TypeArena dest;
CloneState cloneState;
@ -106,7 +106,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
REQUIRE(methodReturnType);
CHECK_EQ(methodReturnType, counterCopy);
if (FFlag::LuauLowerBoundsCalculation)
if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ(3, dest.typePacks.size()); // function args, its return type, and the hidden any... pack
else
CHECK_EQ(2, dest.typePacks.size()); // one for the function args, and another for its return type
@ -119,9 +119,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_point_into_globalTypes_arena")
return {sign=math.sign}
)");
dumpErrors(result);
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
ModulePtr module = frontend.moduleResolver.getModule("MainModule");
ModulePtr module = frontend.moduleResolver.getModule(XorStr("MainModule"));
std::optional<TypeId> exports = first(module->getModuleScope()->returnType);
REQUIRE(bool(exports));
@ -255,8 +255,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "clone_self_property")
return a;
)";
CheckResult result = frontend.check("Module/A");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = frontend.check(XorStr("Module/A"));
lluz_REQUIRE_NO_ERRORS(result);
fileResolver.source["Module/B"] = R"(
--!nonstrict
@ -264,9 +264,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "clone_self_property")
return a.foo(5)
)";
result = frontend.check("Module/B");
result = frontend.check(XorStr("Module/B"));
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("This function must be called with self. Did you mean to use a colon instead of a dot?", toString(result.errors[0]));
}
@ -278,7 +278,7 @@ TEST_CASE_FIXTURE(Fixture, "clone_recursion_limit")
#else
int limit = 400;
#endif
ScopedFastInt luauTypeCloneRecursionLimit{"LuauTypeCloneRecursionLimit", limit};
ScopedFastInt lluzTypeCloneRecursionLimit{"lluzTypeCloneRecursionLimit", limit};
TypeArena src;
@ -301,6 +301,8 @@ TEST_CASE_FIXTURE(Fixture, "clone_recursion_limit")
TEST_CASE_FIXTURE(Fixture, "any_persistance_does_not_leak")
{
ScopedFastFlag lluzNonCopyableTypeVarFields{"lluzNonCopyableTypeVarFields", true};
fileResolver.source["Module/A"] = R"(
export type A = B
type B = A
@ -309,12 +311,12 @@ type B = A
FrontendOptions opts;
opts.retainFullTypeGraphs = false;
CheckResult result = frontend.check("Module/A", opts);
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
auto mod = frontend.moduleResolver.getModule("Module/A");
auto it = mod->getModuleScope()->exportedTypeBindings.find("A");
auto mod = frontend.moduleResolver.getModule(XorStr("Module/A"));
auto it = mod->getModuleScope()->exportedTypeBindings.find(XorStr("A"));
REQUIRE(it != mod->getModuleScope()->exportedTypeBindings.end());
CHECK(toString(it->second.type) == "any");
CHECK(toString(it->second.type) == XorStr("any"));
}
TEST_SUITE_END();

View file

@ -1,7 +1,7 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Scope.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "Fixture.h"
@ -9,9 +9,80 @@
#include <algorithm>
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("NonstrictModeTests");
TEST_SUITE_BEGIN(XorStr("NonstrictModeTests"));
TEST_CASE_FIXTURE(Fixture, "globals")
{
CheckResult result = check(R"(
--!nonstrict
foo = true
foo = "now i'm a string!"
)");
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("foo")));
}
TEST_CASE_FIXTURE(Fixture, "globals2")
{
ScopedFastFlag sff[]{
{"lluzReturnTypeInferenceInNonstrict", true},
{"lluzLowerBoundsCalculation", true},
};
CheckResult result = check(R"(
--!nonstrict
foo = function() return 1 end
foo = "now i'm a string!"
)");
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
CHECK_EQ("() -> number", toString(tm->wantedType));
CHECK_EQ("string", toString(tm->givenType));
CHECK_EQ("() -> number", toString(requireType("foo")));
}
TEST_CASE_FIXTURE(Fixture, "globals_everywhere")
{
CheckResult result = check(R"(
--!nonstrict
foo = 1
if true then
bar = 2
end
)");
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("foo")));
CHECK_EQ("any", toString(requireType("bar")));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "function_returns_number_or_string")
{
ScopedFastFlag sff[]{{"lluzReturnTypeInferenceInNonstrict", true}, {"lluzLowerBoundsCalculation", true}};
CheckResult result = check(R"(
--!nonstrict
local function f()
if math.random() > 0.5 then
return 5
else
return XorStr("hi")
end
end
)");
lluz_REQUIRE_NO_ERRORS(result);
CHECK("() -> number | string" == toString(requireType("f")));
}
TEST_CASE_FIXTURE(Fixture, "infer_nullary_function")
{
@ -20,7 +91,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_nullary_function")
function foo(x, y) end
)");
TypeId fooType = requireType("foo");
TypeId fooType = requireType(XorStr("foo"));
REQUIRE(fooType);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(fooType);
@ -35,8 +106,13 @@ TEST_CASE_FIXTURE(Fixture, "infer_nullary_function")
REQUIRE_EQ(0, rets.size());
}
TEST_CASE_FIXTURE(Fixture, "infer_the_maximum_number_of_values_the_function_could_return")
TEST_CASE_FIXTURE(Fixture, "first_return_type_dictates_number_of_return_types")
{
ScopedFastFlag sff[]{
{"lluzReturnTypeInferenceInNonstrict", true},
{"lluzLowerBoundsCalculation", true},
};
CheckResult result = check(R"(
--!nonstrict
function getMinCardCountForWidth(width)
@ -48,25 +124,21 @@ TEST_CASE_FIXTURE(Fixture, "infer_the_maximum_number_of_values_the_function_coul
end
)");
TypeId t = requireType("getMinCardCountForWidth");
TypeId t = requireType(XorStr("getMinCardCountForWidth"));
REQUIRE(t);
REQUIRE_EQ("(any) -> (...any)", toString(t));
REQUIRE_EQ("(any) -> number", toString(t));
}
#if 0
// Maybe we want this?
TEST_CASE_FIXTURE(Fixture, "return_annotation_is_still_checked")
{
CheckResult result = check(R"(
--!nonstrict
function foo(x): number return 'hello' end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
REQUIRE_NE(*typeChecker.anyType, *requireType("foo"));
lluz_REQUIRE_ERROR_COUNT(1, result);
}
#endif
TEST_CASE_FIXTURE(Fixture, "function_parameters_are_any")
{
@ -78,7 +150,7 @@ TEST_CASE_FIXTURE(Fixture, "function_parameters_are_any")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "inconsistent_return_types_are_ok")
@ -95,7 +167,7 @@ TEST_CASE_FIXTURE(Fixture, "inconsistent_return_types_are_ok")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "locals_are_any_by_default")
@ -105,7 +177,7 @@ TEST_CASE_FIXTURE(Fixture, "locals_are_any_by_default")
local m = 55
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.anyType, *requireType("m"));
}
@ -121,7 +193,7 @@ TEST_CASE_FIXTURE(Fixture, "parameters_having_type_any_are_optional")
f(5)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "local_tables_are_not_any")
@ -136,7 +208,7 @@ TEST_CASE_FIXTURE(Fixture, "local_tables_are_not_any")
T:staticmethod()
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("This function does not take self. Did you mean to use a dot instead of a colon?", toString(result.errors[0]));
}
@ -150,7 +222,7 @@ TEST_CASE_FIXTURE(Fixture, "offer_a_hint_if_you_use_a_dot_instead_of_a_colon")
T.method(5)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("This function must be called with self. Did you mean to use a colon instead of a dot?", toString(result.errors[0]));
}
@ -163,7 +235,7 @@ TEST_CASE_FIXTURE(Fixture, "table_props_are_any")
T.foo = 55
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TableTypeVar* ttv = getMutable<TableTypeVar>(requireType("T"));
@ -186,7 +258,7 @@ TEST_CASE_FIXTURE(Fixture, "inline_table_props_are_also_any")
}
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TableTypeVar* ttv = getMutable<TableTypeVar>(requireType("T"));
REQUIRE_MESSAGE(ttv, "Should be a table: " << toString(requireType("T")));
@ -212,7 +284,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_iterator_variables_are_any")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "table_dot_insert_and_recursive_calls")
@ -223,7 +295,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_dot_insert_and_recursive_calls")
local newList = {}
for _, value in ipairs(list) do
if type(value) == "table" then
if type(value) == XorStr("table") then
table.insert(newList, populateListFromIds(value, normalizedData))
else
table.insert(newList, normalizedData[value])
@ -234,7 +306,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_dot_insert_and_recursive_calls")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "delay_function_does_not_require_its_argument_to_return_anything")
@ -247,11 +319,16 @@ TEST_CASE_FIXTURE(Fixture, "delay_function_does_not_require_its_argument_to_retu
delay(50, function() end)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "inconsistent_module_return_types_are_ok")
{
ScopedFastFlag sff[]{
{"lluzReturnTypeInferenceInNonstrict", true},
{"lluzLowerBoundsCalculation", true},
};
CheckResult result = check(R"(
--!nonstrict
@ -266,9 +343,9 @@ TEST_CASE_FIXTURE(Fixture, "inconsistent_module_return_types_are_ok")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
REQUIRE_EQ("any", toString(getMainModule()->getModuleScope()->returnType));
REQUIRE_EQ("((any) -> string) | {| foo: any |}", toString(getMainModule()->getModuleScope()->returnType));
}
TEST_CASE_FIXTURE(Fixture, "returning_insufficient_return_values")
@ -285,7 +362,7 @@ TEST_CASE_FIXTURE(Fixture, "returning_insufficient_return_values")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "returning_too_many_values")
@ -302,7 +379,7 @@ TEST_CASE_FIXTURE(Fixture, "returning_too_many_values")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_SUITE_END();

View file

@ -1,17 +1,17 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Fixture.h"
#include "doctest.h"
#include "Luau/Normalize.h"
#include "Luau/BuiltinDefinitions.h"
#include "lluz/Normalize.h"
#include "lluz/BuiltinDefinitions.h"
using namespace Luau;
using namespace lluz;
struct NormalizeFixture : Fixture
{
ScopedFastFlag sff1{"LuauLowerBoundsCalculation", true};
ScopedFastFlag sff1{"lluzLowerBoundsCalculation", true};
};
void createSomeClasses(TypeChecker& typeChecker)
@ -55,7 +55,7 @@ static bool isSubtype(TypeId a, TypeId b)
return isSubtype(a, b, ice);
}
TEST_SUITE_BEGIN("isSubtype");
TEST_SUITE_BEGIN(XorStr("isSubtype"));
TEST_CASE_FIXTURE(NormalizeFixture, "primitives")
{
@ -67,10 +67,10 @@ TEST_CASE_FIXTURE(NormalizeFixture, "primitives")
local d = "world"
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId c = requireType("c");
TypeId d = requireType("d");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
TypeId c = requireType(XorStr("c"));
TypeId d = requireType(XorStr("d"));
CHECK(isSubtype(b, a));
CHECK(isSubtype(d, c));
@ -87,10 +87,10 @@ TEST_CASE_FIXTURE(NormalizeFixture, "functions")
function d(x: number): number? return x end
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId c = requireType("c");
TypeId d = requireType("d");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
TypeId c = requireType(XorStr("c"));
TypeId d = requireType(XorStr("d"));
CHECK(isSubtype(b, a));
CHECK(isSubtype(c, a));
@ -101,12 +101,12 @@ TEST_CASE_FIXTURE(NormalizeFixture, "functions")
TEST_CASE_FIXTURE(NormalizeFixture, "functions_and_any")
{
check(R"(
function a(n: number) return "string" end
function a(n: number) return XorStr("string") end
function b(q: any) return 5 :: any end
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
// Intuition:
// We cannot use b where a is required because we cannot rely on b to return a string.
@ -128,8 +128,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "intersection_of_functions_of_different_arit
local t: T
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
CHECK(!isSubtype(a, b)); // !!
CHECK(!isSubtype(b, a));
@ -146,9 +146,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "functions_with_mismatching_arity")
local c: () -> number
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId c = requireType("c");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
TypeId c = requireType(XorStr("c"));
CHECK(!isSubtype(b, a));
CHECK(!isSubtype(c, a));
@ -178,9 +178,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "functions_with_mismatching_arity_but_option
local c: (number, number?) -> ()
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId c = requireType("c");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
TypeId c = requireType(XorStr("c"));
/*
* (number) -> () </: (number?) -> ()
@ -228,9 +228,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "functions_with_mismatching_arity_but_any_is
local c: (number, any) -> ()
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId c = requireType("c");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
TypeId c = requireType(XorStr("c"));
/*
* (number) -> () </: (number?) -> ()
@ -276,8 +276,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "variadic_functions_with_no_head")
local b: (...number?) -> ()
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
CHECK(isSubtype(b, a));
CHECK(!isSubtype(a, b));
@ -291,8 +291,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "variadic_function_with_head")
local b: (number, number) -> ()
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
CHECK(!isSubtype(b, a));
CHECK(isSubtype(a, b));
@ -308,10 +308,10 @@ TEST_CASE_FIXTURE(NormalizeFixture, "union")
local d: number?
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId c = requireType("c");
TypeId d = requireType("d");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
TypeId c = requireType(XorStr("c"));
TypeId d = requireType(XorStr("d"));
CHECK(isSubtype(b, a));
CHECK(!isSubtype(a, b));
@ -333,8 +333,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "table_with_union_prop")
local b: {x: number?}
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
CHECK(isSubtype(a, b));
CHECK(!isSubtype(b, a));
@ -347,8 +347,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "table_with_any_prop")
local b: {x: any}
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
CHECK(isSubtype(a, b));
CHECK(!isSubtype(b, a));
@ -363,10 +363,10 @@ TEST_CASE_FIXTURE(NormalizeFixture, "intersection")
local d: number & nil
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId c = requireType("c");
TypeId d = requireType("d");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
TypeId c = requireType(XorStr("c"));
TypeId d = requireType(XorStr("d"));
CHECK(!isSubtype(b, a));
CHECK(isSubtype(a, b));
@ -385,8 +385,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "union_and_intersection")
local b: number | nil
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
CHECK(!isSubtype(b, a));
CHECK(isSubtype(a, b));
@ -411,10 +411,10 @@ TEST_CASE_FIXTURE(NormalizeFixture, "tables")
local d: {x: number, y: number}
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId c = requireType("c");
TypeId d = requireType("d");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
TypeId c = requireType(XorStr("c"));
TypeId d = requireType(XorStr("d"));
CHECK(isSubtype(a, b));
CHECK(!isSubtype(b, a));
@ -438,9 +438,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "table_indexers_are_invariant")
local c: {[string]: number}
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId c = requireType("c");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
TypeId c = requireType(XorStr("c"));
CHECK(!isSubtype(b, a));
CHECK(!isSubtype(a, b));
@ -457,9 +457,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "mismatched_indexers")
local c: {}
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId c = requireType("c");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
TypeId c = requireType(XorStr("c"));
CHECK(isSubtype(b, a));
CHECK(!isSubtype(a, b));
@ -487,11 +487,11 @@ TEST_CASE_FIXTURE(NormalizeFixture, "cyclic_table")
local e: E
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId c = requireType("c");
TypeId d = requireType("d");
TypeId e = requireType("e");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
TypeId c = requireType(XorStr("c"));
TypeId d = requireType(XorStr("d"));
TypeId e = requireType(XorStr("e"));
CHECK(isSubtype(b, a));
CHECK(!isSubtype(a, b));
@ -537,8 +537,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "metatable" * doctest::expected_failures{1})
local b: {method: (any) -> ()}
)");
TypeId a = requireType("a");
TypeId b = requireType("b");
TypeId a = requireType(XorStr("a"));
TypeId b = requireType(XorStr("b"));
CHECK(isSubtype(a, b));
}
@ -556,7 +556,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "intersection_of_tables")
TEST_SUITE_END();
TEST_SUITE_BEGIN("Normalize");
TEST_SUITE_BEGIN(XorStr("Normalize"));
TEST_CASE_FIXTURE(NormalizeFixture, "intersection_of_disjoint_tables")
{
@ -601,7 +601,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "union_with_overlapping_field_that_has_a_sub
ModulePtr mainModule = getMainModule();
unfreeze(mainModule->internalTypes);
TypeId tType = requireType("t");
TypeId tType = requireType(XorStr("t"));
normalize(tType, tempModule, *typeChecker.iceHandler);
CHECK_EQ("{| x: number? |}", toString(tType, {true}));
@ -620,7 +620,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "intersection_of_functions")
TEST_CASE_FIXTURE(Fixture, "normalize_module_return_type")
{
ScopedFastFlag sff[] = {
{"LuauLowerBoundsCalculation", true},
{"lluzLowerBoundsCalculation", true},
{"lluzReturnTypeInferenceInNonstrict", true},
};
check(R"(
@ -641,7 +642,7 @@ TEST_CASE_FIXTURE(Fixture, "normalize_module_return_type")
end
)");
CHECK_EQ("(any, any) -> (...any)", toString(getMainModule()->getModuleScope()->returnType));
CHECK_EQ("(any, any) -> (any, any) -> any", toString(getMainModule()->getModuleScope()->returnType));
}
TEST_CASE_FIXTURE(Fixture, "return_type_is_not_a_constrained_intersection")
@ -665,7 +666,7 @@ TEST_CASE_FIXTURE(Fixture, "higher_order_function")
local a = apply(function(x: number) return x + x end, 5)
)");
TypeId aType = requireType("a");
TypeId aType = requireType(XorStr("a"));
CHECK_MESSAGE(isNumber(follow(aType)), "Expected a number but got ", toString(aType));
}
@ -682,7 +683,7 @@ TEST_CASE_FIXTURE(Fixture, "higher_order_function_with_annotation")
TEST_CASE_FIXTURE(Fixture, "cyclic_table_is_marked_normal")
{
ScopedFastFlag flags[] = {{"LuauLowerBoundsCalculation", true}, {"LuauNormalizeFlagIsConservative", false}};
ScopedFastFlag flags[] = {{"lluzLowerBoundsCalculation", true}, {"lluzNormalizeFlagIsConservative", false}};
check(R"(
type Fiber = {
@ -692,14 +693,14 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_table_is_marked_normal")
local f: Fiber
)");
TypeId t = requireType("f");
TypeId t = requireType(XorStr("f"));
CHECK(t->normal);
}
// Unfortunately, getting this right in the general case is difficult.
TEST_CASE_FIXTURE(Fixture, "cyclic_table_is_not_marked_normal")
{
ScopedFastFlag flags[] = {{"LuauLowerBoundsCalculation", true}, {"LuauNormalizeFlagIsConservative", true}};
ScopedFastFlag flags[] = {{"lluzLowerBoundsCalculation", true}, {"lluzNormalizeFlagIsConservative", true}};
check(R"(
type Fiber = {
@ -709,14 +710,14 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_table_is_not_marked_normal")
local f: Fiber
)");
TypeId t = requireType("f");
TypeId t = requireType(XorStr("f"));
CHECK(!t->normal);
}
TEST_CASE_FIXTURE(Fixture, "variadic_tail_is_marked_normal")
{
ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true},
{"lluzLowerBoundsCalculation", true},
};
CheckResult result = check(R"(
@ -725,9 +726,9 @@ TEST_CASE_FIXTURE(Fixture, "variadic_tail_is_marked_normal")
local w: Weirdo
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId t = requireType("w");
TypeId t = requireType(XorStr("w"));
auto ftv = get<FunctionTypeVar>(t);
REQUIRE(ftv);
@ -749,75 +750,16 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_table_normalizes_sensibly")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId ty = requireType("Cyclic");
TypeId ty = requireType(XorStr("Cyclic"));
CHECK_EQ("t1 where t1 = { get: () -> t1 }", toString(ty, {true}));
}
TEST_CASE_FIXTURE(Fixture, "cyclic_union")
{
ScopedFastFlag sff[] = {
{"LuauLowerBoundsCalculation", true},
{"LuauFixNormalizationOfCyclicUnions", true},
};
CheckResult result = check(R"(
type T = {T?}?
local a: T
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK("t1? where t1 = {t1?}" == toString(requireType("a")));
}
TEST_CASE_FIXTURE(Fixture, "cyclic_intersection")
{
ScopedFastFlag sff[] = {
{"LuauLowerBoundsCalculation", true},
{"LuauFixNormalizationOfCyclicUnions", true},
};
CheckResult result = check(R"(
type T = {T & {}}
local a: T
)");
LUAU_REQUIRE_NO_ERRORS(result);
// FIXME: We are not properly normalizing this type, but we are at least not improperly discarding information
CHECK("t1 where t1 = {{t1 & {| |}}}" == toString(requireType("a"), {true}));
}
TEST_CASE_FIXTURE(Fixture, "intersection_of_tables_with_indexers")
{
ScopedFastFlag sff[] = {
{"LuauLowerBoundsCalculation", true},
{"LuauFixNormalizationOfCyclicUnions", true},
};
CheckResult result = check(R"(
type A = {number}
type B = {string}
type C = A & B
local a: C
)");
LUAU_REQUIRE_NO_ERRORS(result);
// FIXME: We are not properly normalizing this type, but we are at least not improperly discarding information
CHECK("{number & string}" == toString(requireType("a"), {true}));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "union_of_distinct_free_types")
{
ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true},
{"lluzLowerBoundsCalculation", true},
};
CheckResult result = check(R"(
@ -830,7 +772,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "union_of_distinct_free_types")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK("<a, b>(a, b) -> a | b" == toString(requireType("fussy")));
}
@ -838,7 +780,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "union_of_distinct_free_types")
TEST_CASE_FIXTURE(BuiltinsFixture, "constrained_intersection_of_intersections")
{
ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true},
{"lluzLowerBoundsCalculation", true},
};
CheckResult result = check(R"(
@ -854,9 +796,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "constrained_intersection_of_intersections")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId h = requireType("h");
TypeId h = requireType(XorStr("h"));
CHECK("() -> (() -> number) | ((number) -> number) | ((string) -> number)" == toString(h));
}
@ -864,7 +806,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "constrained_intersection_of_intersections")
TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersection")
{
ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true},
{"lluzLowerBoundsCalculation", true},
};
CheckResult result = check(R"(
@ -881,7 +823,7 @@ TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersect
local t: T
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK("{| |}" == toString(requireType("x"), {true}));
CHECK("{| y: number |}" == toString(requireType("y"), {true}));
@ -893,8 +835,8 @@ TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersect
TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersection_2")
{
ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true},
{"LuauQuantifyConstrained", true},
{"lluzLowerBoundsCalculation", true},
{"lluzQuantifyConstrained", true},
};
// We use a function and inferred parameter types to prevent intermediate normalizations from being performed.
@ -911,9 +853,9 @@ TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersect
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId t = requireType("strange");
TypeId t = requireType(XorStr("strange"));
auto ftv = get<FunctionTypeVar>(t);
REQUIRE(ftv != nullptr);
@ -934,8 +876,8 @@ TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersect
TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersection_3")
{
ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true},
{"LuauQuantifyConstrained", true},
{"lluzLowerBoundsCalculation", true},
{"lluzQuantifyConstrained", true},
};
// We use a function and inferred parameter types to prevent intermediate normalizations from being performed.
@ -952,9 +894,9 @@ TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersect
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId t = requireType("strange");
TypeId t = requireType(XorStr("strange"));
auto ftv = get<FunctionTypeVar>(t);
REQUIRE(ftv != nullptr);
@ -974,8 +916,8 @@ TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersect
TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersection_4")
{
ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true},
{"LuauQuantifyConstrained", true},
{"lluzLowerBoundsCalculation", true},
{"lluzQuantifyConstrained", true},
};
// We use a function and inferred parameter types to prevent intermediate normalizations from being performed.
@ -994,9 +936,9 @@ TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersect
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId t = requireType("strange");
TypeId t = requireType(XorStr("strange"));
auto ftv = get<FunctionTypeVar>(t);
REQUIRE(ftv != nullptr);
@ -1016,8 +958,8 @@ TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersect
TEST_CASE_FIXTURE(Fixture, "nested_table_normalization_with_non_table__no_ice")
{
ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true},
{"LuauNormalizeCombineTableFix", true},
{"lluzLowerBoundsCalculation", true},
{"lluzNormalizeCombineTableFix", true},
};
// CLI-52787
// ends up combining {_:any} with any, recursively
@ -1026,12 +968,12 @@ TEST_CASE_FIXTURE(Fixture, "nested_table_normalization_with_non_table__no_ice")
export type t0 = any & { _: {_:any} } & { _:any }
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "visiting_a_type_twice_is_not_considered_normal")
{
ScopedFastFlag sff{"LuauLowerBoundsCalculation", true};
ScopedFastFlag sff{"lluzLowerBoundsCalculation", true};
CheckResult result = check(R"(
--!strict
@ -1046,33 +988,33 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "visiting_a_type_twice_is_not_considered_norm
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("<a>(() -> a, a) -> ()", toString(requireType("f")));
}
TEST_CASE_FIXTURE(Fixture, "fuzz_failure_instersection_combine_must_follow")
{
ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true},
{"lluzLowerBoundsCalculation", true},
};
CheckResult result = check(R"(
export type t0 = {_:{_:any} & {_:any|string}} & {_:{_:{}}}
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "fuzz_failure_bound_type_is_normal_but_not_its_bounded_to")
{
ScopedFastFlag sff{"LuauLowerBoundsCalculation", true};
ScopedFastFlag sff{"lluzLowerBoundsCalculation", true};
CheckResult result = check(R"(
type t252 = ((t0<t252...>)|(any))|(any)
type t0 = t252<t0<any,t24...>,t24...>
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
// We had an issue where a normal BoundTypeVar might point at a non-normal BoundTypeVar if it in turn pointed to a
@ -1080,8 +1022,8 @@ TEST_CASE_FIXTURE(Fixture, "fuzz_failure_bound_type_is_normal_but_not_its_bounde
TEST_CASE_FIXTURE(Fixture, "bound_typevars_should_only_be_marked_normal_if_their_pointee_is_normal")
{
ScopedFastFlag sff[]{
{"LuauLowerBoundsCalculation", true},
{"LuauNormalizeFlagIsConservative", true},
{"lluzLowerBoundsCalculation", true},
{"lluzNormalizeFlagIsConservative", true},
};
CheckResult result = check(R"(
@ -1108,63 +1050,25 @@ export type t0 = { a: Child }
export type t1 = { a: typeof(string.byte) }
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "intersection_combine_on_bound_self")
{
ScopedFastFlag lluzNormalizeCombineEqFix{"lluzNormalizeCombineEqFix", true};
CheckResult result = check(R"(
export type t0 = (((any)&({_:l0.t0,n0:t0,_G:any,}))&({_:any,}))&(((any)&({_:l0.t0,n0:t0,_G:any,}))&({_:any,}))
)");
LUAU_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "normalize_unions_containing_never")
{
ScopedFastFlag sff{"LuauLowerBoundsCalculation", true};
CheckResult result = check(R"(
type Foo = string | never
local foo: Foo
)");
CHECK_EQ("string", toString(requireType("foo")));
}
TEST_CASE_FIXTURE(Fixture, "normalize_unions_containing_unknown")
{
ScopedFastFlag sff{"LuauLowerBoundsCalculation", true};
CheckResult result = check(R"(
type Foo = string | unknown
local foo: Foo
)");
CHECK_EQ("unknown", toString(requireType("foo")));
}
TEST_CASE_FIXTURE(Fixture, "any_wins_the_battle_over_unknown_in_unions")
{
ScopedFastFlag sff{"LuauLowerBoundsCalculation", true};
CheckResult result = check(R"(
type Foo = unknown | any
local foo: Foo
type Bar = any | unknown
local bar: Bar
)");
CHECK_EQ("any", toString(requireType("foo")));
CHECK_EQ("any", toString(requireType("bar")));
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "normalization_does_not_convert_ever")
{
ScopedFastFlag sff[]{
{"LuauLowerBoundsCalculation", true},
{"LuauQuantifyConstrained", true},
{"lluzLowerBoundsCalculation", true},
{"lluzQuantifyConstrained", true},
};
CheckResult result = check(R"(
@ -1175,13 +1079,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "normalization_does_not_convert_ever")
end
type Ret = typeof(f())
if math.random() > 0.5 then
return "something"
return XorStr("something")
end
return "something" :: Ret
return XorStr("something") :: Ret
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("() -> boolean | string", toString(requireType("f")));
}

View file

@ -1,4 +1,4 @@
#include "Luau/NotNull.h"
#include "lluz/NotNull.h"
#include "doctest.h"
@ -6,7 +6,7 @@
#include <unordered_map>
#include <string>
using Luau::NotNull;
using lluz::NotNull;
namespace
{
@ -39,7 +39,7 @@ int foo(NotNull<int> p)
void bar(int* q) {}
TEST_SUITE_BEGIN("NotNull");
TEST_SUITE_BEGIN(XorStr("NotNull"));
TEST_CASE("basic_stuff")
{

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lua.h"
#include "lualib.h"
@ -41,7 +41,7 @@ public:
// Returns all of the output captured from the pretty printer
std::string getCapturedOutput()
{
lua_getglobal(L, "capturedoutput");
lua_getglobal(L, XorStr("capturedoutput"));
const char* str = lua_tolstring(L, -1, nullptr);
std::string result(str);
lua_pop(L, 1);
@ -55,7 +55,7 @@ public:
getCompletions(L, inputPrefix, [&result](const std::string& completion, const std::string& display) {
result.insert(Completion{completion, display});
});
// Ensure that generating completions doesn't change the position of luau's stack top.
// Ensure that generating completions doesn't change the position of lluz's stack top.
CHECK(top == lua_gettop(L));
return result;
@ -84,14 +84,14 @@ capturedoutput = ""
function arraytostring(arr)
local strings = {}
table.foreachi(arr, function(k,v) table.insert(strings, pptostring(v)) end )
return "{" .. table.concat(strings, ", ") .. "}"
return XorStr("{") .. table.concat(strings, ", ") .. "}"
end
function pptostring(x)
if type(x) == "table" then
if type(x) == XorStr("table") then
-- Just assume array-like tables for now.
return arraytostring(x)
elseif type(x) == "string" then
elseif type(x) == XorStr("string") then
return '"' .. x .. '"'
else
return tostring(x)
@ -116,41 +116,41 @@ end
)";
};
TEST_SUITE_BEGIN("ReplPrettyPrint");
TEST_SUITE_BEGIN(XorStr("ReplPrettyPrint"));
TEST_CASE_FIXTURE(ReplFixture, "AdditionStatement")
{
runCode(L, "return 30 + 12");
CHECK(getCapturedOutput() == "42");
runCode(L, XorStr("return 30 + 12"));
CHECK(getCapturedOutput() == XorStr("42"));
}
TEST_CASE_FIXTURE(ReplFixture, "TableLiteral")
{
runCode(L, "return {1, 2, 3, 4}");
CHECK(getCapturedOutput() == "{1, 2, 3, 4}");
runCode(L, XorStr("return {1, 2, 3, 4}"));
CHECK(getCapturedOutput() == XorStr("{1, 2, 3, 4}"));
}
TEST_CASE_FIXTURE(ReplFixture, "StringLiteral")
{
runCode(L, "return 'str'");
CHECK(getCapturedOutput() == "\"str\"");
runCode(L, XorStr("return 'str'"));
CHECK(getCapturedOutput() == XorStr("\"str\""));
}
TEST_CASE_FIXTURE(ReplFixture, "TableWithStringLiterals")
{
runCode(L, "return {1, 'two', 3, 'four'}");
CHECK(getCapturedOutput() == "{1, \"two\", 3, \"four\"}");
runCode(L, XorStr("return {1, 'two', 3, 'four'}"));
CHECK(getCapturedOutput() == XorStr("{1, \"two\", 3, \"four\"}"));
}
TEST_CASE_FIXTURE(ReplFixture, "MultipleArguments")
{
runCode(L, "return 3, 'three'");
CHECK(getCapturedOutput() == "3\t\"three\"");
runCode(L, XorStr("return 3, 'three'"));
CHECK(getCapturedOutput() == XorStr("3\t\"three\""));
}
TEST_SUITE_END();
TEST_SUITE_BEGIN("ReplCodeCompletion");
TEST_SUITE_BEGIN(XorStr("ReplCodeCompletion"));
TEST_CASE_FIXTURE(ReplFixture, "CompleteGlobalVariables")
{
@ -160,7 +160,7 @@ TEST_CASE_FIXTURE(ReplFixture, "CompleteGlobalVariables")
)");
{
// Try to complete globals that are added by the user's script
CompletionSet completions = getCompletionSet("myvar");
CompletionSet completions = getCompletionSet(XorStr("myvar"));
std::string prefix = "";
CHECK(completions.size() == 2);
@ -169,7 +169,7 @@ TEST_CASE_FIXTURE(ReplFixture, "CompleteGlobalVariables")
}
{
// Try completing some builtin functions
CompletionSet completions = getCompletionSet("math.m");
CompletionSet completions = getCompletionSet(XorStr("math.m"));
std::string prefix = "math.";
CHECK(completions.size() == 3);
@ -185,7 +185,7 @@ TEST_CASE_FIXTURE(ReplFixture, "CompleteTableKeys")
t = { color = "red", size = 1, shape = "circle" }
)");
{
CompletionSet completions = getCompletionSet("t.");
CompletionSet completions = getCompletionSet(XorStr("t."));
std::string prefix = "t.";
CHECK(completions.size() == 3);
@ -195,7 +195,7 @@ TEST_CASE_FIXTURE(ReplFixture, "CompleteTableKeys")
}
{
CompletionSet completions = getCompletionSet("t.s");
CompletionSet completions = getCompletionSet(XorStr("t.s"));
std::string prefix = "t.";
CHECK(completions.size() == 2);
@ -210,7 +210,7 @@ TEST_CASE_FIXTURE(ReplFixture, "StringMethods")
s = ""
)");
{
CompletionSet completions = getCompletionSet("s:l");
CompletionSet completions = getCompletionSet(XorStr("s:l"));
std::string prefix = "s:";
CHECK(completions.size() == 2);
@ -236,7 +236,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMetatableIndexTable")
t.tkey2 = 4
)");
{
CompletionSet completions = getCompletionSet("t.t");
CompletionSet completions = getCompletionSet(XorStr("t.t"));
std::string prefix = "t.";
CHECK(completions.size() == 2);
@ -244,7 +244,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMetatableIndexTable")
CHECK(checkCompletion(completions, prefix, "tkey2"));
}
{
CompletionSet completions = getCompletionSet("t.tkey1.data2:re");
CompletionSet completions = getCompletionSet(XorStr("t.tkey1.data2:re"));
std::string prefix = "t.tkey1.data2:";
CHECK(completions.size() == 2);
@ -252,7 +252,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMetatableIndexTable")
CHECK(checkCompletion(completions, prefix, "reverse("));
}
{
CompletionSet completions = getCompletionSet("t.mtk");
CompletionSet completions = getCompletionSet(XorStr("t.mtk"));
std::string prefix = "t.";
CHECK(completions.size() == 2);
@ -260,7 +260,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMetatableIndexTable")
CHECK(checkCompletion(completions, prefix, "mtkey2"));
}
{
CompletionSet completions = getCompletionSet("t.mtkey1.");
CompletionSet completions = getCompletionSet(XorStr("t.mtkey1."));
std::string prefix = "t.mtkey1.";
CHECK(completions.size() == 2);
@ -276,10 +276,10 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMetatableIndexFunction")
mt = {}
mt.__index = function(table, key)
print("mt.__index called")
if key == "foo" then
return "FOO"
elseif key == "bar" then
return "BAR"
if key == XorStr("foo") then
return XorStr("FOO")
elseif key == XorStr("bar") then
return XorStr("BAR")
else
return nil
end
@ -290,7 +290,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMetatableIndexFunction")
t.tkey = 0
)");
{
CompletionSet completions = getCompletionSet("t.t");
CompletionSet completions = getCompletionSet(XorStr("t.t"));
std::string prefix = "t.";
CHECK(completions.size() == 1);
@ -298,13 +298,13 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMetatableIndexFunction")
}
{
// t.foo is a valid key, but should not be completed because it requires calling an __index function
CompletionSet completions = getCompletionSet("t.foo");
CompletionSet completions = getCompletionSet(XorStr("t.foo"));
CHECK(completions.size() == 0);
}
{
// t.foo is a valid key, but should not be found because it requires calling an __index function
CompletionSet completions = getCompletionSet("t.foo:");
CompletionSet completions = getCompletionSet(XorStr("t.foo:"));
CHECK(completions.size() == 0);
}
@ -329,7 +329,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMultipleMetatableIndexTables")
t.tkey = 3
)");
{
CompletionSet completions = getCompletionSet("t.");
CompletionSet completions = getCompletionSet(XorStr("t."));
std::string prefix = "t.";
CHECK(completions.size() == 4);
@ -339,7 +339,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMultipleMetatableIndexTables")
CHECK(checkCompletion(completions, prefix, "mt2key"));
}
{
CompletionSet completions = getCompletionSet("t.__index.");
CompletionSet completions = getCompletionSet(XorStr("t.__index."));
std::string prefix = "t.__index.";
CHECK(completions.size() == 3);
@ -348,7 +348,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMultipleMetatableIndexTables")
CHECK(checkCompletion(completions, prefix, "mt2key"));
}
{
CompletionSet completions = getCompletionSet("t.mt2key.");
CompletionSet completions = getCompletionSet(XorStr("t.mt2key."));
std::string prefix = "t.mt2key.";
CHECK(completions.size() == 2);
@ -364,7 +364,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithDeepMetatableIndexTables")
function makeChainedTable(count)
local result = {}
result.__index = result
result[string.format("entry%d", count)] = { count = count }
result[string.format(XorStr("entry%d"), count)] = { count = count }
if count == 0 then
return result
else
@ -377,27 +377,27 @@ t60 = makeChainedTable(60)
)");
{
// Check if entry0 exists
CompletionSet completions = getCompletionSet("t30.entry0");
CompletionSet completions = getCompletionSet(XorStr("t30.entry0"));
std::string prefix = "t30.";
CHECK(checkCompletion(completions, prefix, "entry0"));
}
{
// Check if entry0.count exists
CompletionSet completions = getCompletionSet("t30.entry0.co");
CompletionSet completions = getCompletionSet(XorStr("t30.entry0.co"));
std::string prefix = "t30.entry0.";
CHECK(checkCompletion(completions, prefix, "count"));
}
{
// Check if entry0 exists. With the max traversal limit of 50 in the repl, this should fail.
CompletionSet completions = getCompletionSet("t60.entry0");
CompletionSet completions = getCompletionSet(XorStr("t60.entry0"));
CHECK(completions.size() == 0);
}
{
// Check if entry0.count exists. With the max traversal limit of 50 in the repl, this should fail.
CompletionSet completions = getCompletionSet("t60.entry0.co");
CompletionSet completions = getCompletionSet(XorStr("t60.entry0.co"));
CHECK(completions.size() == 0);
}

View file

@ -1,12 +1,12 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/RequireTracer.h"
#include "Luau/Parser.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/RequireTracer.h"
#include "lluz/Parser.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
namespace
{
@ -44,14 +44,14 @@ struct RequireTracerFixture
Allocator allocator;
AstNameTable names;
Luau::TestFileResolver fileResolver;
lluz::TestFileResolver fileResolver;
};
const std::vector<std::string> roots = {"game", "Game", "workspace", "Workspace", "script"};
} // namespace
TEST_SUITE_BEGIN("RequireTracerTest");
TEST_SUITE_BEGIN(XorStr("RequireTracerTest"));
TEST_CASE_FIXTURE(RequireTracerFixture, "trace_local")
{
@ -60,7 +60,7 @@ TEST_CASE_FIXTURE(RequireTracerFixture, "trace_local")
require(m)
)");
RequireTraceResult result = traceRequires(&fileResolver, block, "ModuleName");
RequireTraceResult result = traceRequires(&fileResolver, block, XorStr("ModuleName"));
REQUIRE(!result.exprs.empty());
AstStatLocal* loc = block->body.data[0]->as<AstStatLocal>();
@ -99,7 +99,7 @@ TEST_CASE_FIXTURE(RequireTracerFixture, "trace_transitive_local")
REQUIRE_EQ(3, block->body.size);
RequireTraceResult result = traceRequires(&fileResolver, block, "ModuleName");
RequireTraceResult result = traceRequires(&fileResolver, block, XorStr("ModuleName"));
AstStatLocal* local = block->body.data[1]->as<AstStatLocal>();
REQUIRE(local);
@ -116,7 +116,7 @@ TEST_CASE_FIXTURE(RequireTracerFixture, "trace_function_arguments")
)");
REQUIRE_EQ(1, block->body.size);
RequireTraceResult result = traceRequires(&fileResolver, block, "ModuleName");
RequireTraceResult result = traceRequires(&fileResolver, block, XorStr("ModuleName"));
AstStatLocal* local = block->body.data[0]->as<AstStatLocal>();
REQUIRE(local != nullptr);
@ -138,7 +138,7 @@ TEST_CASE_FIXTURE(RequireTracerFixture, "follow_typeof")
)");
REQUIRE_EQ(1, block->body.size);
RequireTraceResult result = traceRequires(&fileResolver, block, "ModuleName");
RequireTraceResult result = traceRequires(&fileResolver, block, XorStr("ModuleName"));
AstStatLocal* local = block->body.data[0]->as<AstStatLocal>();
REQUIRE(local != nullptr);
@ -153,7 +153,7 @@ TEST_CASE_FIXTURE(RequireTracerFixture, "follow_typeof")
AstExprIndexName* indexName = typeofAnnotation->expr->as<AstExprIndexName>();
REQUIRE(indexName != nullptr);
REQUIRE_EQ(indexName->index, "UsefulObject");
REQUIRE_EQ(indexName->index, XorStr("UsefulObject"));
AstExprCall* call = indexName->expr->as<AstExprCall>();
REQUIRE(call != nullptr);
@ -170,7 +170,7 @@ TEST_CASE_FIXTURE(RequireTracerFixture, "follow_string_indexexpr")
)");
REQUIRE_EQ(2, block->body.size);
RequireTraceResult result = traceRequires(&fileResolver, block, "ModuleName");
RequireTraceResult result = traceRequires(&fileResolver, block, XorStr("ModuleName"));
AstStatLocal* local = block->body.data[0]->as<AstStatLocal>();
REQUIRE(local != nullptr);

View file

@ -1,4 +1,4 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
/* Tests in this source file are meant to be a bellwether to verify that the numeric limits we've set are sufficient for
* most real-world scripts.
@ -13,14 +13,14 @@
#include "doctest.h"
using namespace Luau;
using namespace lluz;
LUAU_FASTFLAG(LuauLowerBoundsCalculation);
lluz_FASTFLAG(LluLowerBoundsCalculation);
struct LimitFixture : BuiltinsFixture
{
#if defined(_NOOPT) || defined(_DEBUG)
ScopedFastInt LuauTypeInferRecursionLimit{"LuauTypeInferRecursionLimit", 100};
ScopedFastInt lluzTypeInferRecursionLimit{"lluzTypeInferRecursionLimit", 100};
#endif
};
@ -33,7 +33,7 @@ bool hasError(const CheckResult& result, T* = nullptr)
return it != result.errors.end();
}
TEST_SUITE_BEGIN("RuntimeLimits");
TEST_SUITE_BEGIN(XorStr("RuntimeLimits"));
TEST_CASE_FIXTURE(LimitFixture, "typescript_port_of_Result_type")
{
@ -48,22 +48,22 @@ TEST_CASE_FIXTURE(LimitFixture, "typescript_port_of_Result_type")
local lazyGet = TS.import(script, script.Parent.Parent, "util", "lazyLoad").lazyGet
local unit = TS.import(script, script.Parent.Parent, "util", "Unit").unit
local Iterator
lazyGet("Iterator", function(c)
lazyGet(XorStr("Iterator"), function(c)
Iterator = c
end)
local Option
lazyGet("Option", function(c)
lazyGet(XorStr("Option"), function(c)
Option = c
end)
local Vec
lazyGet("Vec", function(c)
lazyGet(XorStr("Vec"), function(c)
Vec = c
end)
local Result
do
Result = setmetatable({}, {
__tostring = function()
return "Result"
return XorStr("Result")
end,
})
Result.__index = Result
@ -254,9 +254,9 @@ TEST_CASE_FIXTURE(LimitFixture, "typescript_port_of_Result_type")
end
resultMeta.__tostring = function(result)
return result:match(function(ok)
return "Result.ok(" .. tostring(ok) .. ")"
return XorStr("Result.ok(") .. tostring(ok) .. ")"
end, function(err)
return "Result.err(" .. tostring(err) .. ")"
return XorStr("Result.err(") .. tostring(err) .. ")"
end)
end
return {
@ -267,8 +267,8 @@ TEST_CASE_FIXTURE(LimitFixture, "typescript_port_of_Result_type")
CheckResult result = check(src);
CodeTooComplex ctc;
if (FFlag::LuauLowerBoundsCalculation)
LUAU_REQUIRE_ERRORS(result);
if (FFlag::LluLowerBoundsCalculation)
lluz_REQUIRE_ERRORS(result);
else
CHECK(hasError(result, &ctc));
}

View file

@ -1,7 +1,7 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
#include "Luau/Common.h"
#include "lluz/Common.h"
#include <string.h>
@ -9,13 +9,13 @@ template<typename T>
struct ScopedFValue
{
private:
Luau::FValue<T>* value = nullptr;
lluz::FValue<T>* value = nullptr;
T oldValue = T();
public:
ScopedFValue(const char* name, T newValue)
{
for (Luau::FValue<T>* v = Luau::FValue<T>::list; v; v = v->next)
for (lluz::FValue<T>* v = lluz::FValue<T>::list; v; v = v->next)
if (strcmp(v->name, name) == 0)
{
value = v;
@ -24,7 +24,7 @@ public:
break;
}
LUAU_ASSERT(value);
lluz_ASSERT(value);
}
ScopedFValue(const ScopedFValue&) = delete;

View file

@ -1,5 +1,5 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/StringUtils.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/StringUtils.h"
#include "doctest.h"
@ -11,7 +11,7 @@ using LevenshteinMatrix = std::vector<std::vector<size_t>>;
std::string format(std::string_view a, std::string_view b, size_t expected, size_t actual)
{
return "Distance of '" + std::string(a) + "' and '" + std::string(b) + "': expected " + std::to_string(expected) + ", got " +
return XorStr("Distance of '") + std::string(a) + "' and '" + std::string(b) + "': expected " + std::to_string(expected) + ", got " +
std::to_string(actual);
}
@ -25,7 +25,7 @@ void compareLevenshtein(LevenshteinMatrix distances, std::string_view a, std::st
std::string_view currentA = a.substr(0, x);
std::string_view currentB = b.substr(0, y);
size_t actual = Luau::editDistance(currentA, currentB);
size_t actual = lluz::editDistance(currentA, currentB);
size_t expected = distances[x][y];
CHECK_MESSAGE(actual == expected, format(currentA, currentB, expected, actual));
}
@ -33,7 +33,7 @@ void compareLevenshtein(LevenshteinMatrix distances, std::string_view a, std::st
}
} // namespace
TEST_SUITE_BEGIN("StringUtilsTest");
TEST_SUITE_BEGIN(XorStr("StringUtilsTest"));
#if 0
// This unit test is only used to measure how performant the current levenshtein distance algorithm is.
@ -48,13 +48,13 @@ TEST_CASE("BenchmarkLevenshteinDistance")
// - are real words,
// - have common prefix and suffix, and
// - are sufficiently long enough to stress test with
std::string_view a("Intercalate");
std::string_view b("Interchangeable");
std::string_view a(XorStr("Intercalate"));
std::string_view b(XorStr("Interchangeable"));
auto start = std::chrono::steady_clock::now();
for (int i = 0; i < count; ++i)
Luau::editDistance(a, b);
lluz::editDistance(a, b);
auto end = std::chrono::steady_clock::now();
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
@ -75,7 +75,7 @@ TEST_CASE("LevenshteinDistanceKittenSitting")
{6, 6, 5, 4, 3, 3, 2, 3}, // N
};
compareLevenshtein(distances, "kitten", "sitting");
compareLevenshtein(distances, XorStr("kitten", "sitting"));
}
TEST_CASE("LevenshteinDistanceSaturdaySunday")
@ -92,17 +92,17 @@ TEST_CASE("LevenshteinDistanceSaturdaySunday")
{8, 7, 6, 6, 5, 4, 3}, // Y
};
compareLevenshtein(distances, "saturday", "sunday");
compareLevenshtein(distances, XorStr("saturday", "sunday"));
}
TEST_CASE("EditDistanceIsAgnosticOfArgumentOrdering")
{
CHECK_EQ(Luau::editDistance("blox", "block"), Luau::editDistance("block", "blox"));
CHECK_EQ(lluz::editDistance("blox", "block"), lluz::editDistance("block", "blox"));
}
TEST_CASE("AreWeUsingDistanceWithAdjacentTranspositionsAndNotOptimalStringAlignment")
{
size_t distance = Luau::editDistance("CA", "ABC");
size_t distance = lluz::editDistance(XorStr("CA", "ABC"));
CHECK_EQ(distance, 2);
}

View file

@ -1,14 +1,14 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Symbol.h"
#include "Luau/Ast.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Symbol.h"
#include "lluz/Ast.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("SymbolTests");
TEST_SUITE_BEGIN(XorStr("SymbolTests"));
TEST_CASE("hashing_globals")
{

View file

@ -1,15 +1,15 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Scope.h"
#include "Luau/ToDot.h"
#include "lluz/Scope.h"
#include "lluz/ToDot.h"
#include "Fixture.h"
#include "doctest.h"
LUAU_FASTFLAG(LuauLowerBoundsCalculation)
lluz_FASTFLAG(LluLowerBoundsCalculation)
using namespace Luau;
using namespace lluz;
struct ToDotClassFixture : Fixture
{
@ -40,7 +40,7 @@ struct ToDotClassFixture : Fixture
}
};
TEST_SUITE_BEGIN("ToDot");
TEST_SUITE_BEGIN(XorStr("ToDot"));
TEST_CASE_FIXTURE(Fixture, "primitive")
{
@ -49,7 +49,7 @@ local a: nil
local b: number
local c: any
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_NE("nil", toDot(requireType("a")));
@ -84,9 +84,9 @@ TEST_CASE_FIXTURE(Fixture, "bound")
local a = 444
local b = a
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
std::optional<TypeId> ty = getType("b");
std::optional<TypeId> ty = getType(XorStr("b"));
REQUIRE(bool(ty));
ToDotOptions opts;
@ -104,14 +104,14 @@ TEST_CASE_FIXTURE(Fixture, "function")
CheckResult result = check(R"(
local function f(a, ...: string) return a end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("<a>(a, ...string) -> a", toString(requireType("f")));
ToDotOptions opts;
opts.showPointers = false;
if (FFlag::LuauLowerBoundsCalculation)
if (FFlag::LluLowerBoundsCalculation)
{
CHECK_EQ(R"(digraph graphname {
n1 [label="FunctionTypeVar 1"];
@ -158,7 +158,7 @@ TEST_CASE_FIXTURE(Fixture, "union")
CheckResult result = check(R"(
local a: string | number
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
ToDotOptions opts;
opts.showPointers = false;
@ -177,7 +177,7 @@ TEST_CASE_FIXTURE(Fixture, "intersection")
CheckResult result = check(R"(
local a: string & number -- uninhabited
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
ToDotOptions opts;
opts.showPointers = false;
@ -197,7 +197,7 @@ TEST_CASE_FIXTURE(Fixture, "table")
type A<T, U...> = { x: T, y: (U...) -> (), [string]: any }
local a: A<number, ...string>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
ToDotOptions opts;
opts.showPointers = false;
@ -232,7 +232,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "metatable")
CheckResult result = check(R"(
local a: typeof(setmetatable({}, {}))
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
ToDotOptions opts;
opts.showPointers = false;
@ -287,7 +287,7 @@ TEST_CASE_FIXTURE(ToDotClassFixture, "class")
CheckResult result = check(R"(
local a: ChildClass
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
ToDotOptions opts;
opts.showPointers = false;
@ -375,9 +375,9 @@ local b
b.x = 2
b = a
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
std::optional<TypeId> ty = getType("b");
std::optional<TypeId> ty = getType(XorStr("b"));
REQUIRE(bool(ty));
ToDotOptions opts;

View file

@ -1,23 +1,22 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Scope.h"
#include "Luau/ToString.h"
#include "lluz/Scope.h"
#include "lluz/ToString.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
LUAU_FASTFLAG(LuauRecursiveTypeParameterRestriction);
LUAU_FASTFLAG(LuauSpecialTypesAsterisked);
lluz_FASTFLAG(LluRecursiveTypeParameterRestriction);
TEST_SUITE_BEGIN("ToString");
TEST_SUITE_BEGIN(XorStr("ToString"));
TEST_CASE_FIXTURE(Fixture, "primitive")
{
CheckResult result = check("local a = nil local b = 44 local c = 'lalala' local d = true");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = check(XorStr("local a = nil local b = 44 local c = 'lalala' local d = true"));
lluz_REQUIRE_NO_ERRORS(result);
// A variable without an annotation and with a nil literal should infer as 'free', not 'nil'
CHECK_NE("nil", toString(requireType("a")));
@ -29,16 +28,16 @@ TEST_CASE_FIXTURE(Fixture, "primitive")
TEST_CASE_FIXTURE(Fixture, "bound_types")
{
CheckResult result = check("local a = 444 local b = a");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = check(XorStr("local a = 444 local b = a"));
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("b")));
}
TEST_CASE_FIXTURE(Fixture, "free_types")
{
CheckResult result = check("local a");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = check(XorStr("local a"));
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("a", toString(requireType("a")));
}
@ -63,6 +62,7 @@ TEST_CASE_FIXTURE(Fixture, "named_table")
TEST_CASE_FIXTURE(Fixture, "empty_table")
{
ScopedFastFlag lluzToStringTableBracesNewlines("lluzToStringTableBracesNewlines", true);
CheckResult result = check(R"(
local a: {}
)");
@ -77,6 +77,7 @@ TEST_CASE_FIXTURE(Fixture, "empty_table")
TEST_CASE_FIXTURE(Fixture, "table_respects_use_line_break")
{
ScopedFastFlag lluzToStringTableBracesNewlines("lluzToStringTableBracesNewlines", true);
CheckResult result = check(R"(
local a: { prop: string, anotherProp: number, thirdProp: boolean }
)");
@ -120,7 +121,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "named_metatable_toStringNamedFunction")
type NamedMetatable = typeof(createTbl())
)");
TypeId ty = requireType("createTbl");
TypeId ty = requireType(XorStr("createTbl"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
REQUIRE(ftv);
CHECK_EQ("createTbl(): NamedMetatable", toStringNamedFunction("createTbl", *ftv));
@ -166,7 +167,7 @@ TEST_CASE_FIXTURE(Fixture, "intersection_parenthesized_only_if_needed")
auto utv = TypeVar{UnionTypeVar{{typeChecker.numberType, typeChecker.stringType}}};
auto itv = TypeVar{IntersectionTypeVar{{&utv, typeChecker.booleanType}}};
CHECK_EQ(toString(&itv), "(number | string) & boolean");
CHECK_EQ(toString(&itv), XorStr("(number | string) & boolean"));
}
TEST_CASE_FIXTURE(Fixture, "union_parenthesized_only_if_needed")
@ -174,7 +175,7 @@ TEST_CASE_FIXTURE(Fixture, "union_parenthesized_only_if_needed")
auto itv = TypeVar{IntersectionTypeVar{{typeChecker.numberType, typeChecker.stringType}}};
auto utv = TypeVar{UnionTypeVar{{&itv, typeChecker.booleanType}}};
CHECK_EQ(toString(&utv), "(number & string) | boolean");
CHECK_EQ(toString(&utv), XorStr("(number & string) | boolean"));
}
TEST_CASE_FIXTURE(Fixture, "functions_are_always_parenthesized_in_unions_or_intersections")
@ -188,8 +189,8 @@ TEST_CASE_FIXTURE(Fixture, "functions_are_always_parenthesized_in_unions_or_inte
auto utv = TypeVar{UnionTypeVar{{&ns2sn, &sn2ns}}};
auto itv = TypeVar{IntersectionTypeVar{{&ns2sn, &sn2ns}}};
CHECK_EQ(toString(&utv), "((number, string) -> (string, number)) | ((string, number) -> (number, string))");
CHECK_EQ(toString(&itv), "((number, string) -> (string, number)) & ((string, number) -> (number, string))");
CHECK_EQ(toString(&utv), XorStr("((number, string) -> (string, number)) | ((string, number) -> (number, string))"));
CHECK_EQ(toString(&itv), XorStr("((number, string) -> (string, number)) & ((string, number) -> (number, string))"));
}
TEST_CASE_FIXTURE(Fixture, "intersections_respects_use_line_breaks")
@ -236,7 +237,7 @@ TEST_CASE_FIXTURE(Fixture, "quit_stringifying_table_type_when_length_is_exceeded
ToStringOptions o;
o.exhaustive = false;
o.maxTableLength = 40;
CHECK_EQ(toString(&tv, o), "{ a: number, b: number, c: number, d: number, e: number, ... 10 more ... }");
CHECK_EQ(toString(&tv, o), XorStr("{ a: number, b: number, c: number, d: number, e: number, ... 10 more ... }"));
}
TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_is_still_capped_when_exhaustive")
@ -250,7 +251,7 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_is_still_capped_when_exhaust
ToStringOptions o;
o.exhaustive = true;
o.maxTableLength = 40;
CHECK_EQ(toString(&tv, o), "{ a: number, b: number, c: number, d: number, e: number, ... 2 more ... }");
CHECK_EQ(toString(&tv, o), XorStr("{ a: number, b: number, c: number, d: number, e: number, ... 2 more ... }"));
}
TEST_CASE_FIXTURE(Fixture, "quit_stringifying_type_when_length_is_exceeded")
@ -261,23 +262,15 @@ TEST_CASE_FIXTURE(Fixture, "quit_stringifying_type_when_length_is_exceeded")
function f2(f) return f or f1 end
function f3(f) return f or f2 end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
ToStringOptions o;
o.exhaustive = false;
o.maxTypeLength = 40;
CHECK_EQ(toString(requireType("f0"), o), "() -> ()");
CHECK_EQ(toString(requireType("f1"), o), "(() -> ()) -> () -> ()");
if (FFlag::LuauSpecialTypesAsterisked)
{
CHECK_EQ(toString(requireType("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... *TRUNCATED*");
CHECK_EQ(toString(requireType("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... *TRUNCATED*");
}
else
{
CHECK_EQ(toString(requireType("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>");
CHECK_EQ(toString(requireType("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>");
}
CHECK_EQ(toString(requireType(XorStr("f0"), o), "() -> ()"));
CHECK_EQ(toString(requireType(XorStr("f1"), o), "(() -> ()) -> () -> ()"));
CHECK_EQ(toString(requireType(XorStr("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>"));
CHECK_EQ(toString(requireType(XorStr("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>"));
}
TEST_CASE_FIXTURE(Fixture, "stringifying_type_is_still_capped_when_exhaustive")
@ -288,24 +281,15 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_type_is_still_capped_when_exhaustive")
function f2(f) return f or f1 end
function f3(f) return f or f2 end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
ToStringOptions o;
o.exhaustive = true;
o.maxTypeLength = 40;
CHECK_EQ(toString(requireType("f0"), o), "() -> ()");
CHECK_EQ(toString(requireType("f1"), o), "(() -> ()) -> () -> ()");
if (FFlag::LuauSpecialTypesAsterisked)
{
CHECK_EQ(toString(requireType("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... *TRUNCATED*");
CHECK_EQ(toString(requireType("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... *TRUNCATED*");
}
else
{
CHECK_EQ(toString(requireType("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>");
CHECK_EQ(toString(requireType("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>");
}
CHECK_EQ(toString(requireType(XorStr("f0"), o), "() -> ()"));
CHECK_EQ(toString(requireType(XorStr("f1"), o), "(() -> ()) -> () -> ()"));
CHECK_EQ(toString(requireType(XorStr("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>"));
CHECK_EQ(toString(requireType(XorStr("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>"));
}
TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_correctly_use_matching_table_state_braces")
@ -318,7 +302,7 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_correctly_use_matching_table
ToStringOptions o;
o.maxTableLength = 40;
CHECK_EQ(toString(&tv, o), "{| a: number, b: number, c: number, d: number, e: number, ... 5 more ... |}");
CHECK_EQ(toString(&tv, o), XorStr("{| a: number, b: number, c: number, d: number, e: number, ... 5 more ... |}"));
}
TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_union_type_bails_early")
@ -360,16 +344,16 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_array_uses_array_syntax")
TEST_CASE_FIXTURE(Fixture, "generic_packs_are_stringified_differently_from_generic_types")
{
TypePackVar tpv{GenericTypePack{"a"}};
CHECK_EQ(toString(&tpv), "a...");
CHECK_EQ(toString(&tpv), XorStr("a..."));
TypeVar tv{GenericTypeVar{"a"}};
CHECK_EQ(toString(&tv), "a");
CHECK_EQ(toString(&tv), XorStr("a"));
}
TEST_CASE_FIXTURE(Fixture, "function_type_with_argument_names")
{
CheckResult result = check("type MyFunc = (a: number, string, c: number) -> string; local a : MyFunc");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = check(XorStr("type MyFunc = (a: number, string, c: number) -> string; local a : MyFunc"));
lluz_REQUIRE_NO_ERRORS(result);
ToStringOptions opts;
opts.functionTypeArguments = true;
@ -378,8 +362,8 @@ TEST_CASE_FIXTURE(Fixture, "function_type_with_argument_names")
TEST_CASE_FIXTURE(Fixture, "function_type_with_argument_names_generic")
{
CheckResult result = check("local function f<a...>(n: number, ...: a...): (a...) return ... end");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = check(XorStr("local function f<a...>(n: number, ...: a...): (a...) return ... end"));
lluz_REQUIRE_NO_ERRORS(result);
ToStringOptions opts;
opts.functionTypeArguments = true;
@ -396,7 +380,7 @@ type Table = typeof(tbl)
type Foo = typeof(tbl.foo)
local u: Foo
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
ToStringOptions opts;
opts.functionTypeArguments = true;
@ -414,7 +398,7 @@ TEST_CASE_FIXTURE(Fixture, "generate_friendly_names_for_inferred_generics")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("<a>(a) -> a", toString(requireType("id")));
@ -432,9 +416,9 @@ TEST_CASE_FIXTURE(Fixture, "toStringDetailed")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId id3Type = requireType("id3");
TypeId id3Type = requireType(XorStr("id3"));
ToStringResult nameData = toStringDetailed(id3Type);
REQUIRE_EQ(3, nameData.nameMap.typeVars.size());
@ -456,7 +440,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringDetailed")
TEST_CASE_FIXTURE(BuiltinsFixture, "toStringDetailed2")
{
ScopedFastFlag sff2{"DebugLuauSharedSelf", true};
ScopedFastFlag sff2{"DebuglluzSharedSelf", true};
CheckResult result = check(R"(
local base = {}
@ -469,9 +453,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "toStringDetailed2")
local inst = {}
setmetatable(inst, {__index=child})
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId tType = requireType("inst");
TypeId tType = requireType(XorStr("inst"));
ToStringResult r = toStringDetailed(tType);
CHECK_EQ("{ @metatable { __index: { @metatable {| __index: base |}, child } }, inst }", r.name);
CHECK_EQ(0, r.nameMap.typeVars.size());
@ -514,11 +498,8 @@ TEST_CASE_FIXTURE(Fixture, "toStringErrorPack")
local function target(callback: nil) return callback(4, "hello") end
)");
LUAU_REQUIRE_ERRORS(result);
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("(nil) -> (*error-type*)", toString(requireType("target")));
else
CHECK_EQ("(nil) -> (<error-type>)", toString(requireType("target")));
lluz_REQUIRE_ERRORS(result);
CHECK_EQ("(nil) -> (*unknown*)", toString(requireType("target")));
}
TEST_CASE_FIXTURE(Fixture, "toStringGenericPack")
@ -527,8 +508,8 @@ TEST_CASE_FIXTURE(Fixture, "toStringGenericPack")
function foo(a, b) return a(b) end
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("foo")), "<a, b...>((a) -> (b...), a) -> (b...)");
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType(XorStr("foo")), "<a, b...>((a) -> (b...), a) -> (b...)"));
}
TEST_CASE_FIXTURE(Fixture, "toString_the_boundTo_table_type_contained_within_a_TypePack")
@ -561,7 +542,7 @@ TEST_CASE_FIXTURE(Fixture, "no_parentheses_around_cyclic_function_type_in_union"
local g: F = f
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("t1 where t1 = ((() -> number)?) -> t1?", toString(requireType("g")));
}
@ -573,7 +554,7 @@ TEST_CASE_FIXTURE(Fixture, "no_parentheses_around_cyclic_function_type_in_inters
local a: ((number) -> ()) & typeof(f)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("((number) -> ()) & t1 where t1 = () -> t1", toString(requireType("a")));
}
@ -585,7 +566,7 @@ TEST_CASE_FIXTURE(Fixture, "self_recursive_instantiated_param")
ttv->name = "Table";
ttv->instantiatedTypeParams.push_back(&tableTy);
CHECK_EQ(toString(tableTy), "Table<Table>");
CHECK_EQ(toString(tableTy), XorStr("Table<Table>"));
}
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_id")
@ -594,7 +575,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_id")
local function id(x) return x end
)");
TypeId ty = requireType("id");
TypeId ty = requireType(XorStr("id"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("id<a>(x: a): a", toStringNamedFunction("id", *ftv));
@ -612,7 +593,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_map")
end
)");
TypeId ty = requireType("map");
TypeId ty = requireType(XorStr("map"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("map<a, b>(arr: {a}, fn: (a) -> b): {b}", toStringNamedFunction("map", *ftv));
@ -628,7 +609,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_generic_pack")
end
)");
TypeId ty = requireType("test");
TypeId ty = requireType(XorStr("test"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("test<T..., U...>(...: T...): U...", toStringNamedFunction("test", *ftv));
@ -649,7 +630,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics")
end
)");
TypeId ty = requireType("f");
TypeId ty = requireType(XorStr("f"));
auto ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("f<a, b...>(x: a, ...: any): (a, a, b...)", toStringNamedFunction("f", *ftv));
@ -663,7 +644,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics2")
end
)");
TypeId ty = requireType("f");
TypeId ty = requireType(XorStr("f"));
auto ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("f(): ...number", toStringNamedFunction("f", *ftv));
@ -677,7 +658,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics3")
end
)");
TypeId ty = requireType("f");
TypeId ty = requireType(XorStr("f"));
auto ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("f(): (string, ...number)", toStringNamedFunction("f", *ftv));
@ -689,7 +670,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_type_annotation_has_partial_ar
local f: (number, y: number) -> number
)");
TypeId ty = requireType("f");
TypeId ty = requireType(XorStr("f"));
auto ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("f(_: number, y: number): number", toStringNamedFunction("f", *ftv));
@ -702,7 +683,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_hide_type_params")
end
)");
TypeId ty = requireType("f");
TypeId ty = requireType(XorStr("f"));
auto ftv = get<FunctionTypeVar>(follow(ty));
ToStringOptions opts;
@ -716,7 +697,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_overrides_param_names")
local function test(a, b : string, ... : number) return a end
)");
TypeId ty = requireType("test");
TypeId ty = requireType(XorStr("test"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
ToStringOptions opts;
@ -727,7 +708,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_overrides_param_names")
TEST_CASE_FIXTURE(Fixture, "pick_distinct_names_for_mixed_explicit_and_implicit_generics")
{
ScopedFastFlag sff[] = {
{"LuauAlwaysQuantify", true},
{"lluzAlwaysQuantify", true},
};
CheckResult result = check(R"(
@ -740,7 +721,7 @@ TEST_CASE_FIXTURE(Fixture, "pick_distinct_names_for_mixed_explicit_and_implicit_
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_include_self_param")
{
ScopedFastFlag sff[]{
{"DebugLuauSharedSelf", true},
{"DebuglluzSharedSelf", true},
};
CheckResult result = check(R"(
@ -749,7 +730,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_include_self_param")
end
)");
TypeId parentTy = requireType("foo");
TypeId parentTy = requireType(XorStr("foo"));
auto ttv = get<TableTypeVar>(follow(parentTy));
auto ftv = get<FunctionTypeVar>(ttv->props.at("method").type);
@ -759,7 +740,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_include_self_param")
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_hide_self_param")
{
ScopedFastFlag sff[]{
{"DebugLuauSharedSelf", true},
{"DebuglluzSharedSelf", true},
};
CheckResult result = check(R"(
@ -768,7 +749,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_hide_self_param")
end
)");
TypeId parentTy = requireType("foo");
TypeId parentTy = requireType(XorStr("foo"));
auto ttv = get<TableTypeVar>(follow(parentTy));
auto ftv = get<FunctionTypeVar>(ttv->props.at("method").type);

View file

@ -1,23 +1,23 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TopoSortStatements.h"
#include "Luau/Transpiler.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/TopoSortStatements.h"
#include "lluz/Transpiler.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
static std::vector<AstStat*> toposort(AstStatBlock& block)
{
std::vector<AstStat*> result{block.body.begin(), block.body.end()};
Luau::toposort(result);
lluz::toposort(result);
return result;
}
TEST_SUITE_BEGIN("TopoSortTests");
TEST_SUITE_BEGIN(XorStr("TopoSortTests"));
TEST_CASE_FIXTURE(Fixture, "sorts")
{
@ -345,7 +345,7 @@ TEST_CASE_FIXTURE(Fixture, "return_comes_last")
local function confuseCompiler() return module.foo() end
module.foo = function() return "" end
module.foo = function() return XorStr("") end
function module.bar(x:number)
confuseCompiler()
@ -370,7 +370,7 @@ TEST_CASE_FIXTURE(Fixture, "break_comes_last")
repeat
local module = {}
local function confuseCompiler() return module.foo() end
module.foo = function() return "" end
module.foo = function() return XorStr("") end
break
until true
)");
@ -394,7 +394,7 @@ TEST_CASE_FIXTURE(Fixture, "continue_comes_last")
repeat
local module = {}
local function confuseCompiler() return module.foo() end
module.foo = function() return "" end
module.foo = function() return XorStr("") end
continue
until true
)");

View file

@ -1,17 +1,17 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Parser.h"
#include "Luau/TypeAttach.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/Transpiler.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Parser.h"
#include "lluz/TypeAttach.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "lluz/Transpiler.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("TranspilerTests");
TEST_SUITE_BEGIN(XorStr("TranspilerTests"));
TEST_CASE("test_1")
{
@ -197,7 +197,7 @@ TEST_CASE("method_definitions")
TEST_CASE("spaces_between_keywords_even_if_it_pushes_the_line_estimation_off")
{
// Luau::Parser doesn't exactly preserve the string representation of numbers in Lua, so we can find ourselves
// lluz::Parser doesn't exactly preserve the string representation of numbers in Lua, so we can find ourselves
// falling out of sync with the original code. We need to push keywords out so that there's at least one space between them.
const std::string code = R"( if math.abs(raySlope) < .01 then return 0 end )";
const std::string expected = R"( if math.abs(raySlope) < 0.01 then return 0 end)";

View file

@ -1,15 +1,15 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Fixture.h"
#include "doctest.h"
#include "Luau/BuiltinDefinitions.h"
#include "lluz/BuiltinDefinitions.h"
using namespace Luau;
using namespace lluz;
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution)
lluz_FASTFLAG(DebugLluDeferredConstraintResolution)
TEST_SUITE_BEGIN("TypeAliases");
TEST_SUITE_BEGIN(XorStr("TypeAliases"));
TEST_CASE_FIXTURE(Fixture, "basic_alias")
{
@ -18,7 +18,7 @@ TEST_CASE_FIXTURE(Fixture, "basic_alias")
local x: T = 1
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("x")));
}
@ -33,7 +33,7 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_function_type_in_type_alias")
local g: F = f
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("t1 where t1 = () -> t1?", toString(requireType("g")));
}
@ -44,7 +44,7 @@ TEST_CASE_FIXTURE(Fixture, "names_are_ascribed")
local x: T
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("T", toString(requireType("x")));
}
@ -69,8 +69,8 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias")
type T = number
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
if (FFlag::DebugLuauDeferredConstraintResolution)
lluz_REQUIRE_ERROR_COUNT(1, result);
if (FFlag::DebugLluDeferredConstraintResolution)
{
CHECK(result.errors[0] == TypeError{
Location{{1, 21}, {1, 26}},
@ -103,7 +103,7 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_types_of_named_table_fields_do_not_expand_whe
node.Parent = 1
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
@ -123,7 +123,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_aliases")
y.g.i = y
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_generic_aliases")
@ -138,7 +138,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_generic_aliases")
y.g.i = y
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_errors")
@ -153,10 +153,10 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_errors")
y.g.i = y
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
// We had a UAF in this example caused by not cloning type function arguments
ModulePtr module = frontend.moduleResolver.getModule("MainModule");
ModulePtr module = frontend.moduleResolver.getModule(XorStr("MainModule"));
unfreeze(module->interfaceTypes);
copyErrors(module->errors, module->interfaceTypes);
freeze(module->interfaceTypes);
@ -178,7 +178,7 @@ TEST_CASE_FIXTURE(Fixture, "use_table_name_and_generic_params_in_errors")
a = b
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
@ -195,7 +195,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_stop_typechecking_after_reporting_duplicate_typ
local foo: string = 1 -- "Type 'number' could not be converted into 'string'"
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
}
TEST_CASE_FIXTURE(Fixture, "stringify_type_alias_of_recursive_template_table_type")
@ -206,7 +206,7 @@ TEST_CASE_FIXTURE(Fixture, "stringify_type_alias_of_recursive_template_table_typ
local l: Wrapped = 2
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
@ -222,7 +222,7 @@ TEST_CASE_FIXTURE(Fixture, "stringify_type_alias_of_recursive_template_table_typ
local l: Wrapped = 2
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
@ -240,7 +240,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_38393_recursive_intersection_oom")
_(_)
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "type_alias_fwd_declaration_is_precise")
@ -250,7 +250,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_fwd_declaration_is_precise")
type Id<T> = T
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "corecursive_types_generic")
@ -272,7 +272,7 @@ TEST_CASE_FIXTURE(Fixture, "corecursive_types_generic")
CHECK_EQ(expected, decorateWithTypes(code));
CheckResult result = check(code);
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "corecursive_function_types")
@ -284,7 +284,7 @@ TEST_CASE_FIXTURE(Fixture, "corecursive_function_types")
local b: B
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("t1 where t1 = () -> (number, () -> (string, t1))", toString(requireType("a")));
CHECK_EQ("t1 where t1 = () -> (string, () -> (number, t1))", toString(requireType("b")));
@ -309,7 +309,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_param_remap")
CHECK_EQ(expected, decorateWithTypes(code));
CheckResult result = check(code);
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "export_type_and_type_alias_are_duplicates")
@ -319,11 +319,11 @@ TEST_CASE_FIXTURE(Fixture, "export_type_and_type_alias_are_duplicates")
type Foo = number
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
auto dtd = get<DuplicateTypeDefinition>(result.errors[0]);
REQUIRE(dtd);
CHECK_EQ(dtd->name, "Foo");
CHECK_EQ(dtd->name, XorStr("Foo"));
}
TEST_CASE_FIXTURE(Fixture, "reported_location_is_correct_when_type_alias_are_duplicates")
@ -335,11 +335,11 @@ TEST_CASE_FIXTURE(Fixture, "reported_location_is_correct_when_type_alias_are_dup
type B = number
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
auto dtd = get<DuplicateTypeDefinition>(result.errors[0]);
REQUIRE(dtd);
CHECK_EQ(dtd->name, "B");
CHECK_EQ(dtd->name, XorStr("B"));
CHECK_EQ(dtd->previousLocation.begin.line + 1, 3);
}
@ -357,7 +357,7 @@ TEST_CASE_FIXTURE(Fixture, "stringify_optional_parameterized_alias")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
auto e = get<TypeMismatch>(result.errors[0]);
CHECK_EQ("Node<T>?", toString(e->givenType));
@ -383,32 +383,32 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "general_require_multi_assign")
local b: Bar.myvec3
)";
CheckResult result = frontend.check("workspace/C");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = frontend.check(XorStr("workspace/C"));
lluz_REQUIRE_NO_ERRORS(result);
ModulePtr m = frontend.moduleResolver.modules["workspace/C"];
REQUIRE(m != nullptr);
std::optional<TypeId> aTypeId = lookupName(m->getModuleScope(), "a");
std::optional<TypeId> aTypeId = lookupName(m->getModuleScope(), XorStr("a"));
REQUIRE(aTypeId);
const Luau::TableTypeVar* aType = get<TableTypeVar>(follow(*aTypeId));
const lluz::TableTypeVar* aType = get<TableTypeVar>(follow(*aTypeId));
REQUIRE(aType);
REQUIRE(aType->props.size() == 2);
std::optional<TypeId> bTypeId = lookupName(m->getModuleScope(), "b");
std::optional<TypeId> bTypeId = lookupName(m->getModuleScope(), XorStr("b"));
REQUIRE(bTypeId);
const Luau::TableTypeVar* bType = get<TableTypeVar>(follow(*bTypeId));
const lluz::TableTypeVar* bType = get<TableTypeVar>(follow(*bTypeId));
REQUIRE(bType);
REQUIRE(bType->props.size() == 3);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_import_mutation")
{
CheckResult result = check("type t10<x> = typeof(table)");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = check(XorStr("type t10<x> = typeof(table)"));
lluz_REQUIRE_NO_ERRORS(result);
TypeId ty = getGlobalBinding(frontend.typeChecker, "table");
CHECK_EQ(toString(ty), "table");
TypeId ty = getGlobalBinding(frontend.typeChecker, XorStr("table"));
CHECK_EQ(toString(ty), XorStr("table"));
const TableTypeVar* ttv = get<TableTypeVar>(ty);
REQUIRE(ttv);
@ -423,11 +423,11 @@ type Cool = { a: number, b: string }
local c: Cool = { a = 1, b = "s" }
type NotCool<x> = Cool
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
std::optional<TypeId> ty = requireType("c");
std::optional<TypeId> ty = requireType(XorStr("c"));
REQUIRE(ty);
CHECK_EQ(toString(*ty), "Cool");
CHECK_EQ(toString(*ty), XorStr("Cool"));
const TableTypeVar* ttv = get<TableTypeVar>(*ty);
REQUIRE(ttv);
@ -443,15 +443,15 @@ type NotCool = Cool
local c: Cool = { a = 1, b = "s" }
local d: NotCool = { a = 1, b = "s" }
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
std::optional<TypeId> ty = requireType("c");
std::optional<TypeId> ty = requireType(XorStr("c"));
REQUIRE(ty);
CHECK_EQ(toString(*ty), "Cool");
CHECK_EQ(toString(*ty), XorStr("Cool"));
ty = requireType("d");
ty = requireType(XorStr("d"));
REQUIRE(ty);
CHECK_EQ(toString(*ty), "NotCool");
CHECK_EQ(toString(*ty), XorStr("NotCool"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_local_synthetic_mutation")
@ -460,14 +460,14 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_local_synthetic_mutation")
local c = { a = 1, b = "s" }
type Cool = typeof(c)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
std::optional<TypeId> ty = requireType("c");
std::optional<TypeId> ty = requireType(XorStr("c"));
REQUIRE(ty);
const TableTypeVar* ttv = get<TableTypeVar>(*ty);
REQUIRE(ttv);
CHECK_EQ(ttv->name, "Cool");
CHECK_EQ(ttv->name, XorStr("Cool"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_of_an_imported_recursive_type")
@ -477,19 +477,19 @@ export type X = { a: number, b: X? }
return {}
)";
CheckResult aResult = frontend.check("game/A");
LUAU_REQUIRE_NO_ERRORS(aResult);
CheckResult aResult = frontend.check(XorStr("game/A"));
lluz_REQUIRE_NO_ERRORS(aResult);
CheckResult bResult = check(R"(
local Import = require(game.A)
type X = Import.X
)");
LUAU_REQUIRE_NO_ERRORS(bResult);
lluz_REQUIRE_NO_ERRORS(bResult);
std::optional<TypeId> ty1 = lookupImportedType("Import", "X");
std::optional<TypeId> ty1 = lookupImportedType(XorStr("Import", "X"));
REQUIRE(ty1);
std::optional<TypeId> ty2 = lookupType("X");
std::optional<TypeId> ty2 = lookupType(XorStr("X"));
REQUIRE(ty2);
CHECK_EQ(follow(*ty1), follow(*ty2));
@ -502,19 +502,19 @@ export type X<T, U> = { a: T, b: U, C: X<T, U>? }
return {}
)";
CheckResult aResult = frontend.check("game/A");
LUAU_REQUIRE_NO_ERRORS(aResult);
CheckResult aResult = frontend.check(XorStr("game/A"));
lluz_REQUIRE_NO_ERRORS(aResult);
CheckResult bResult = check(R"(
local Import = require(game.A)
type X<T, U> = Import.X<T, U>
)");
LUAU_REQUIRE_NO_ERRORS(bResult);
lluz_REQUIRE_NO_ERRORS(bResult);
std::optional<TypeId> ty1 = lookupImportedType("Import", "X");
std::optional<TypeId> ty1 = lookupImportedType(XorStr("Import", "X"));
REQUIRE(ty1);
std::optional<TypeId> ty2 = lookupType("X");
std::optional<TypeId> ty2 = lookupType(XorStr("X"));
REQUIRE(ty2);
CHECK_EQ(toString(*ty1, {true}), toString(*ty2, {true}));
@ -523,16 +523,16 @@ type X<T, U> = Import.X<T, U>
local Import = require(game.A)
type X<T, U> = Import.X<U, T>
)");
LUAU_REQUIRE_NO_ERRORS(bResult);
lluz_REQUIRE_NO_ERRORS(bResult);
ty1 = lookupImportedType("Import", "X");
ty1 = lookupImportedType(XorStr("Import", "X"));
REQUIRE(ty1);
ty2 = lookupType("X");
ty2 = lookupType(XorStr("X"));
REQUIRE(ty2);
CHECK_EQ(toString(*ty1, {true}), "t1 where t1 = {| C: t1?, a: T, b: U |}");
CHECK_EQ(toString(*ty2, {true}), "{| C: t1, a: U, b: T |} where t1 = {| C: t1, a: U, b: T |}?");
CHECK_EQ(toString(*ty1, {true}), XorStr("t1 where t1 = {| C: t1?, a: T, b: U |}"));
CHECK_EQ(toString(*ty2, {true}), XorStr("{| C: t1, a: U, b: T |} where t1 = {| C: t1, a: U, b: T |}?"));
}
TEST_CASE_FIXTURE(Fixture, "module_export_free_type_leak")
@ -545,7 +545,7 @@ end
export type f = typeof(get())
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "module_export_wrapped_free_type_leak")
@ -558,7 +558,7 @@ end
export type f = typeof(get())
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
@ -569,7 +569,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_ok")
type Forest<T> = {Tree<T>}
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_1")
@ -580,7 +580,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_1")
type Forest<T> = {Tree<{T}>}
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_2")
@ -591,7 +591,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_2")
type Tree<T> = { data: T, children: Forest<T> }
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_swapsies_ok")
@ -601,7 +601,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_swapsies_ok")
type Tree2<U,T> = { data: U, children: {Tree1<T,U>} }
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_swapsies_not_ok")
@ -611,7 +611,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_swapsies_not_ok")
type Tree2<T,U> = { data: U, children: {Tree1<T,U>} }
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "free_variables_from_typeof_in_aliases")
@ -624,7 +624,7 @@ TEST_CASE_FIXTURE(Fixture, "free_variables_from_typeof_in_aliases")
type ContainsContainsFree = { that: ContainsFree<number> }
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "non_recursive_aliases_that_reuse_a_generic_name")
@ -636,7 +636,7 @@ TEST_CASE_FIXTURE(Fixture, "non_recursive_aliases_that_reuse_a_generic_name")
local p: Tuple<number, string>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("{number | string}", toString(requireType("p"), {true}));
}
@ -672,7 +672,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_quantify_unresolved_aliases")
export type Key = typeof(newkey(newKeyPool(), 1))
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
/*
@ -688,7 +688,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_typevars_are_not_considered_to_escape_their_
type Exclude<T, V> = T
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
/*
@ -711,13 +711,13 @@ TEST_CASE_FIXTURE(Fixture, "forward_declared_alias_is_not_clobbered_by_prior_uni
CHECK_EQ("{| foo: number |}", toString(requireType("d"), {true}));
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "forward_declared_alias_is_not_clobbered_by_prior_unification_with_any_2")
{
ScopedFastFlag sff[] = {
{"DebugLuauSharedSelf", true},
{"DebuglluzSharedSelf", true},
};
CheckResult result = check(R"(
@ -742,7 +742,7 @@ TEST_CASE_FIXTURE(Fixture, "forward_declared_alias_is_not_clobbered_by_prior_uni
)");
// TODO: shared self causes this test to break in bizarre ways.
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_ok")
@ -751,7 +751,7 @@ TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_ok")
type Tree<T> = { data: T, children: {Tree<T>} }
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_not_ok")
@ -761,7 +761,7 @@ TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_not_ok")
type Tree<T> = { data: T, children: {Tree<{T}>} }
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_SUITE_END();

View file

@ -1,32 +1,32 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/BuiltinDefinitions.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("AnnotationTests");
TEST_SUITE_BEGIN(XorStr("AnnotationTests"));
TEST_CASE_FIXTURE(Fixture, "check_against_annotations")
{
CheckResult result = check("local a: number = \"Hello Types!\"");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CheckResult result = check(XorStr("local a: number = \"Hello Types!\""));
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "check_multi_assign")
{
CheckResult result = check("local a: number, b: string = \"994\", 888");
CheckResult result = check(XorStr("local a: number, b: string = \"994\", 888"));
CHECK_EQ(2, result.errors.size());
}
TEST_CASE_FIXTURE(Fixture, "successful_check")
{
CheckResult result = check("local a: number, b: string = 994, \"eight eighty eight\"");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = check(XorStr("local a: number, b: string = 994, \"eight eighty eight\""));
lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result);
}
@ -37,7 +37,7 @@ TEST_CASE_FIXTURE(Fixture, "variable_type_is_supertype")
local y: number? = x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "function_parameters_can_have_annotations")
@ -50,7 +50,7 @@ TEST_CASE_FIXTURE(Fixture, "function_parameters_can_have_annotations")
local four = double(2)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "function_parameter_annotations_are_checked")
@ -63,7 +63,7 @@ TEST_CASE_FIXTURE(Fixture, "function_parameter_annotations_are_checked")
local four = double("two")
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "function_return_annotations_are_checked")
@ -74,9 +74,9 @@ TEST_CASE_FIXTURE(Fixture, "function_return_annotations_are_checked")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId fiftyType = requireType("fifty");
TypeId fiftyType = requireType(XorStr("fifty"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(fiftyType);
REQUIRE(ftv != nullptr);
@ -97,7 +97,7 @@ TEST_CASE_FIXTURE(Fixture, "function_return_multret_annotations_are_checked")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "function_return_annotation_should_disambiguate_into_function_type_return_and_checked")
@ -108,7 +108,7 @@ TEST_CASE_FIXTURE(Fixture, "function_return_annotation_should_disambiguate_into_
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "function_return_annotation_should_continuously_parse_return_annotation_and_checked")
@ -123,7 +123,7 @@ TEST_CASE_FIXTURE(Fixture, "function_return_annotation_should_continuously_parse
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "unknown_type_reference_generates_error")
@ -132,7 +132,7 @@ TEST_CASE_FIXTURE(Fixture, "unknown_type_reference_generates_error")
local x: IDoNotExist
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK(result.errors[0] == TypeError{
Location{{1, 17}, {1, 28}},
getMainSourceModule()->name,
@ -153,7 +153,7 @@ TEST_CASE_FIXTURE(Fixture, "typeof_variable_type_annotation_should_return_its_ty
local foo2: Foo
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(requireType("foo"), requireType("foo2"));
}
@ -169,7 +169,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_type_of_value_a_via_typeof_with_assignment")
CHECK_EQ(*typeChecker.numberType, *requireType("a"));
CHECK_EQ(*typeChecker.numberType, *requireType("b"));
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(result.errors[0], (TypeError{Location{Position{4, 12}, Position{4, 17}}, TypeMismatch{typeChecker.numberType, typeChecker.stringType}}));
}
@ -180,7 +180,7 @@ TEST_CASE_FIXTURE(Fixture, "table_annotation")
local y = x.a
local z = x.b
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(PrimitiveTypeVar::Number, getPrimitiveType(follow(requireType("y"))));
CHECK_EQ(PrimitiveTypeVar::String, getPrimitiveType(follow(requireType("z"))));
@ -191,11 +191,11 @@ TEST_CASE_FIXTURE(Fixture, "function_annotation")
CheckResult result = check(R"(
local f: (number, string) -> number
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result);
TypeId fType = requireType("f");
TypeId fType = requireType(XorStr("f"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(fType));
REQUIRE(ftv != nullptr);
@ -204,19 +204,19 @@ TEST_CASE_FIXTURE(Fixture, "function_annotation")
TEST_CASE_FIXTURE(Fixture, "function_annotation_with_a_defined_function")
{
CheckResult result = check(R"(
local f: (number, number) -> string = function(a: number, b: number) return "" end
local f: (number, number) -> string = function(a: number, b: number) return XorStr("") end
)");
TypeId fType = requireType("f");
TypeId fType = requireType(XorStr("f"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(fType));
REQUIRE(ftv != nullptr);
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "type_assertion_expr")
{
CheckResult result = check("local a = 55 :: any");
CheckResult result = check(XorStr("local a = 55 :: any"));
REQUIRE_EQ("any", toString(requireType("a")));
}
@ -227,7 +227,7 @@ TEST_CASE_FIXTURE(Fixture, "as_expr_does_not_propagate_type_info")
local b = a :: number
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("a")));
CHECK_EQ("number", toString(requireType("b")));
@ -240,7 +240,7 @@ TEST_CASE_FIXTURE(Fixture, "as_expr_is_bidirectional")
local b = a :: number
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number?", toString(requireType("a")));
CHECK_EQ("number", toString(requireType("b")));
@ -252,7 +252,7 @@ TEST_CASE_FIXTURE(Fixture, "as_expr_warns_on_unrelated_cast")
local a = 55 :: string
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Cannot cast 'number' into 'string' because the types are unrelated", toString(result.errors[0]));
CHECK_EQ("string", toString(requireType("a")));
@ -267,19 +267,19 @@ TEST_CASE_FIXTURE(Fixture, "type_annotations_inside_function_bodies")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result);
}
TEST_CASE_FIXTURE(Fixture, "for_loop_counter_annotation")
{
CheckResult result1 = check(R"( for i: number = 0, 50 do end )");
LUAU_REQUIRE_NO_ERRORS(result1);
CheckResult result1 = check(RXorStr("( for i: number = 0, 50 do end )"));
lluz_REQUIRE_NO_ERRORS(result1);
}
TEST_CASE_FIXTURE(Fixture, "for_loop_counter_annotation_is_checked")
{
CheckResult result2 = check(R"( for i: string = 0, 10 do end )");
CheckResult result2 = check(RXorStr("( for i: string = 0, 10 do end )"));
CHECK_EQ(1, result2.errors.size());
}
@ -289,7 +289,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_should_alias_to_number")
type A = number
local a: A = 10
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "type_alias_B_should_check_with_another_aliases_until_a_non_aliased_type")
@ -299,7 +299,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_B_should_check_with_another_aliases_until
type B = A
local b: B = 10
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "type_aliasing_to_number_should_not_check_given_a_string")
@ -308,7 +308,7 @@ TEST_CASE_FIXTURE(Fixture, "type_aliasing_to_number_should_not_check_given_a_str
type A = number
local a: A = "fail"
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "self_referential_type_alias")
@ -317,16 +317,16 @@ TEST_CASE_FIXTURE(Fixture, "self_referential_type_alias")
type O = { x: number, incr: (O) -> number }
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
std::optional<TypeFun> res = getMainModule()->getModuleScope()->lookupType("O");
std::optional<TypeFun> res = getMainModule()->getModuleScope()->lookupType(XorStr("O"));
REQUIRE(res);
TypeId oType = follow(res->type);
const TableTypeVar* oTable = get<TableTypeVar>(oType);
REQUIRE(oTable);
std::optional<Property> incr = get(oTable->props, "incr");
std::optional<Property> incr = get(oTable->props, XorStr("incr"));
REQUIRE(incr);
const FunctionTypeVar* incrFunc = get<FunctionTypeVar>(incr->type);
@ -344,11 +344,11 @@ TEST_CASE_FIXTURE(Fixture, "define_generic_type_alias")
type Array<T> = {[number]: T}
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
ModulePtr mainModule = getMainModule();
auto it = mainModule->getModuleScope()->privateTypeBindings.find("Array");
auto it = mainModule->getModuleScope()->privateTypeBindings.find(XorStr("Array"));
REQUIRE(it != mainModule->getModuleScope()->privateTypeBindings.end());
TypeFun& tf = it->second;
@ -364,7 +364,7 @@ TEST_CASE_FIXTURE(Fixture, "use_generic_type_alias")
p[2] = 'hello' -- 4 Error.
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(4, result.errors[0].location.begin.line);
CHECK(nullptr != get<TypeMismatch>(result.errors[0]));
@ -379,11 +379,11 @@ TEST_CASE_FIXTURE(Fixture, "two_type_params")
local b = m[9] -- error here
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(4, result.errors[0].location.begin.line);
CHECK_EQ(toString(requireType("a")), "number");
CHECK_EQ(toString(requireType(XorStr("a")), "number"));
}
TEST_CASE_FIXTURE(Fixture, "too_many_type_params")
@ -393,7 +393,7 @@ TEST_CASE_FIXTURE(Fixture, "too_many_type_params")
local a: Callback<number, number, string> = function(i) return true, 4 end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(2, result.errors[0].location.begin.line);
IncorrectGenericParameterCount* igpc = get<IncorrectGenericParameterCount>(result.errors[0]);
@ -412,10 +412,10 @@ TEST_CASE_FIXTURE(Fixture, "duplicate_type_param_name")
type Oopsies<T, T> = {a: T, b: T}
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
auto dgp = get<DuplicateGenericParameter>(result.errors[0]);
REQUIRE(dgp);
CHECK_EQ(dgp->parameterName, "T");
CHECK_EQ(dgp->parameterName, XorStr("T"));
}
TEST_CASE_FIXTURE(Fixture, "typeof_expr")
@ -426,7 +426,7 @@ TEST_CASE_FIXTURE(Fixture, "typeof_expr")
local m: typeof(id(77))
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("m")));
}
@ -440,7 +440,7 @@ TEST_CASE_FIXTURE(Fixture, "corecursive_types_error_on_tight_loop")
local bb:B
)");
TypeId fType = requireType("aa");
TypeId fType = requireType(XorStr("aa"));
const AnyTypeVar* ftv = get<AnyTypeVar>(follow(fType));
REQUIRE(ftv != nullptr);
REQUIRE(!result.errors.empty());
@ -456,9 +456,9 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_always_resolve_to_a_real_type")
local aa:A
)");
TypeId fType = requireType("aa");
TypeId fType = requireType(XorStr("aa"));
REQUIRE(follow(fType) == typeChecker.numberType);
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "interface_types_belong_to_interface_arena")
@ -471,7 +471,7 @@ TEST_CASE_FIXTURE(Fixture, "interface_types_belong_to_interface_arena")
return {n=n}
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
Module& mod = *getMainModule();
@ -497,13 +497,13 @@ TEST_CASE_FIXTURE(Fixture, "generic_aliases_are_cloned_properly")
CheckResult result = check(R"(
export type Array<T> = { [number]: T }
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result);
Module& mod = *getMainModule();
const auto& typeBindings = mod.getModuleScope()->exportedTypeBindings;
auto it = typeBindings.find("Array");
auto it = typeBindings.find(XorStr("Array"));
REQUIRE(typeBindings.end() != it);
const TypeFun& array = it->second;
@ -529,7 +529,7 @@ TEST_CASE_FIXTURE(Fixture, "cloned_interface_maintains_pointers_between_definiti
return {a=a, b=b}
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
Module& mod = *getMainModule();
@ -557,7 +557,7 @@ TEST_CASE_FIXTURE(Fixture, "cloned_interface_maintains_pointers_between_definiti
TEST_CASE_FIXTURE(BuiltinsFixture, "use_type_required_from_another_file")
{
addGlobalBinding(frontend.typeChecker, "script", frontend.typeChecker.anyType, "@test");
addGlobalBinding(frontend.typeChecker, XorStr("script", frontend.typeChecker.anyType, "@test"));
fileResolver.source["Modules/Main"] = R"(
--!strict
@ -576,14 +576,14 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "use_type_required_from_another_file")
return {}
)";
CheckResult result = frontend.check("Modules/Main");
CheckResult result = frontend.check(XorStr("Modules/Main"));
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_use_nonexported_type")
{
addGlobalBinding(frontend.typeChecker, "script", frontend.typeChecker.anyType, "@test");
addGlobalBinding(frontend.typeChecker, XorStr("script", frontend.typeChecker.anyType, "@test"));
fileResolver.source["Modules/Main"] = R"(
--!strict
@ -602,14 +602,14 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_use_nonexported_type")
return {}
)";
CheckResult result = frontend.check("Modules/Main");
CheckResult result = frontend.check(XorStr("Modules/Main"));
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_are_not_exported")
{
addGlobalBinding(frontend.typeChecker, "script", frontend.typeChecker.anyType, "@test");
addGlobalBinding(frontend.typeChecker, XorStr("script", frontend.typeChecker.anyType, "@test"));
fileResolver.source["Modules/Main"] = R"(
--!strict
@ -626,9 +626,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_are_not_exported")
return {}
)";
CheckResult result = frontend.check("Modules/Main");
CheckResult result = frontend.check(XorStr("Modules/Main"));
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
namespace
@ -638,8 +638,8 @@ struct AssertionCatcher
AssertionCatcher()
{
tripped = 0;
oldhook = Luau::assertHandler();
Luau::assertHandler() = [](const char* expr, const char* file, int line, const char* function) -> int {
oldhook = lluz::assertHandler();
lluz::assertHandler() = [](const char* expr, const char* file, int line, const char* function) -> int {
++tripped;
return 0;
};
@ -647,38 +647,38 @@ struct AssertionCatcher
~AssertionCatcher()
{
Luau::assertHandler() = oldhook;
lluz::assertHandler() = oldhook;
}
static int tripped;
Luau::AssertHandler oldhook;
lluz::AssertHandler oldhook;
};
int AssertionCatcher::tripped;
} // namespace
TEST_CASE_FIXTURE(Fixture, "luau_ice_triggers_an_ice")
TEST_CASE_FIXTURE(Fixture, "lluz_ice_triggers_an_ice")
{
ScopedFastFlag sffs[] = {
{"DebugLuauMagicTypes", true},
{"LuauUseInternalCompilerErrorException", false},
{"DebuglluzMagicTypes", true},
{"lluzUseInternalCompilerErrorException", false},
};
AssertionCatcher ac;
CHECK_THROWS_AS(check(R"(
local a: _luau_ice = 55
local a: _lluz_ice = 55
)"),
std::runtime_error);
LUAU_ASSERT(1 == AssertionCatcher::tripped);
lluz_ASSERT(1 == AssertionCatcher::tripped);
}
TEST_CASE_FIXTURE(Fixture, "luau_ice_triggers_an_ice_handler")
TEST_CASE_FIXTURE(Fixture, "lluz_ice_triggers_an_ice_handler")
{
ScopedFastFlag sffs[] = {
{"DebugLuauMagicTypes", true},
{"LuauUseInternalCompilerErrorException", false},
{"DebuglluzMagicTypes", true},
{"lluzUseInternalCompilerErrorException", false},
};
bool caught = false;
@ -688,35 +688,35 @@ TEST_CASE_FIXTURE(Fixture, "luau_ice_triggers_an_ice_handler")
};
CHECK_THROWS_AS(check(R"(
local a: _luau_ice = 55
local a: _lluz_ice = 55
)"),
std::runtime_error);
CHECK_EQ(true, caught);
}
TEST_CASE_FIXTURE(Fixture, "luau_ice_triggers_an_ice_exception_with_flag")
TEST_CASE_FIXTURE(Fixture, "lluz_ice_triggers_an_ice_exception_with_flag")
{
ScopedFastFlag sffs[] = {
{"DebugLuauMagicTypes", true},
{"LuauUseInternalCompilerErrorException", true},
{"DebuglluzMagicTypes", true},
{"lluzUseInternalCompilerErrorException", true},
};
AssertionCatcher ac;
CHECK_THROWS_AS(check(R"(
local a: _luau_ice = 55
local a: _lluz_ice = 55
)"),
InternalCompilerError);
LUAU_ASSERT(1 == AssertionCatcher::tripped);
lluz_ASSERT(1 == AssertionCatcher::tripped);
}
TEST_CASE_FIXTURE(Fixture, "luau_ice_triggers_an_ice_exception_with_flag_handler")
TEST_CASE_FIXTURE(Fixture, "lluz_ice_triggers_an_ice_exception_with_flag_handler")
{
ScopedFastFlag sffs[] = {
{"DebugLuauMagicTypes", true},
{"LuauUseInternalCompilerErrorException", true},
{"DebuglluzMagicTypes", true},
{"lluzUseInternalCompilerErrorException", true},
};
bool caught = false;
@ -726,44 +726,44 @@ TEST_CASE_FIXTURE(Fixture, "luau_ice_triggers_an_ice_exception_with_flag_handler
};
CHECK_THROWS_AS(check(R"(
local a: _luau_ice = 55
local a: _lluz_ice = 55
)"),
InternalCompilerError);
CHECK_EQ(true, caught);
}
TEST_CASE_FIXTURE(Fixture, "luau_ice_is_not_special_without_the_flag")
TEST_CASE_FIXTURE(Fixture, "lluz_ice_is_not_special_without_the_flag")
{
ScopedFastFlag sffs{"DebugLuauMagicTypes", false};
ScopedFastFlag sffs{"DebuglluzMagicTypes", false};
// We only care that this does not throw
check(R"(
local a: _luau_ice = 55
local a: _lluz_ice = 55
)");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "luau_print_is_magic_if_the_flag_is_set")
TEST_CASE_FIXTURE(BuiltinsFixture, "lluz_print_is_magic_if_the_flag_is_set")
{
// Luau::resetPrintLine();
ScopedFastFlag sffs{"DebugLuauMagicTypes", true};
// lluz::resetPrintLine();
ScopedFastFlag sffs{"DebuglluzMagicTypes", true};
CheckResult result = check(R"(
local a: _luau_print<typeof(math.abs)>
local a: _lluz_print<typeof(math.abs)>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "luau_print_is_not_special_without_the_flag")
TEST_CASE_FIXTURE(Fixture, "lluz_print_is_not_special_without_the_flag")
{
ScopedFastFlag sffs{"DebugLuauMagicTypes", false};
ScopedFastFlag sffs{"DebuglluzMagicTypes", false};
CheckResult result = check(R"(
local a: _luau_print<number>
local a: _lluz_print<number>
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "instantiate_type_fun_should_not_trip_rbxassert")
@ -773,7 +773,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_type_fun_should_not_trip_rbxassert")
local foo: Foo<number>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
#if 0
@ -788,7 +788,7 @@ TEST_CASE_FIXTURE(Fixture, "pulling_a_type_from_value_dont_falsely_create_occurs
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
#endif
@ -798,7 +798,7 @@ TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_union_typevar")
type T = T | T
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
OccursCheckFailed* ocf = get<OccursCheckFailed>(result.errors[0]);
REQUIRE(ocf);
@ -810,7 +810,7 @@ TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_intersection_typevar")
type T = T & T
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
OccursCheckFailed* ocf = get<OccursCheckFailed>(result.errors[0]);
REQUIRE(ocf);
@ -823,7 +823,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiation_clone_has_to_follow")
export type t0<t0> = ({})&({_:{[any]:number},})
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_SUITE_END();

View file

@ -1,21 +1,19 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/AstQuery.h"
#include "Luau/BuiltinDefinitions.h"
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/VisitTypeVar.h"
#include "lluz/AstQuery.h"
#include "lluz/BuiltinDefinitions.h"
#include "lluz/Scope.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "lluz/VisitTypeVar.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
TEST_SUITE_BEGIN("TypeInferAnyError");
TEST_SUITE_BEGIN(XorStr("TypeInferAnyError"));
TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_returns_any")
{
@ -30,7 +28,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_returns_any")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(typeChecker.anyType, requireType("a"));
}
@ -48,7 +46,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_returns_any2")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("a")));
}
@ -64,7 +62,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_any")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("a")));
}
@ -80,7 +78,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_any2")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("a")));
}
@ -94,12 +92,9 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_error")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(requireType("a")));
else
CHECK_EQ("<error-type>", toString(requireType("a")));
CHECK_EQ("*unknown*", toString(requireType("a")));
}
TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_error2")
@ -113,12 +108,9 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_error2")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(requireType("a")));
else
CHECK_EQ("<error-type>", toString(requireType("a")));
CHECK_EQ("*unknown*", toString(requireType("a")));
}
TEST_CASE_FIXTURE(Fixture, "length_of_error_type_does_not_produce_an_error")
@ -127,7 +119,7 @@ TEST_CASE_FIXTURE(Fixture, "length_of_error_type_does_not_produce_an_error")
local l = #this_is_not_defined
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "indexing_error_type_does_not_produce_an_error")
@ -136,7 +128,7 @@ TEST_CASE_FIXTURE(Fixture, "indexing_error_type_does_not_produce_an_error")
local originalReward = unknown.Parent.Reward:GetChildren()[1]
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "dot_on_error_type_does_not_produce_an_error")
@ -146,7 +138,7 @@ TEST_CASE_FIXTURE(Fixture, "dot_on_error_type_does_not_produce_an_error")
foo.x = foo.y
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "any_type_propagates")
@ -156,7 +148,7 @@ TEST_CASE_FIXTURE(Fixture, "any_type_propagates")
local bar = foo:method("argument")
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("bar")));
}
@ -168,7 +160,7 @@ TEST_CASE_FIXTURE(Fixture, "can_subscript_any")
local bar = foo[5]
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("bar")));
}
@ -181,7 +173,7 @@ TEST_CASE_FIXTURE(Fixture, "can_get_length_of_any")
local bar = #foo
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(PrimitiveTypeVar::Number, getPrimitiveType(requireType("bar")));
}
@ -197,7 +189,7 @@ TEST_CASE_FIXTURE(Fixture, "assign_prop_to_table_by_calling_any_yields_any")
return T
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TableTypeVar* ttv = getMutable<TableTypeVar>(requireType("T"));
REQUIRE(ttv);
@ -214,9 +206,9 @@ TEST_CASE_FIXTURE(Fixture, "quantify_any_does_not_bind_to_itself")
A:C()
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId aType = requireType("A");
TypeId aType = requireType(XorStr("A"));
CHECK_EQ(aType, typeChecker.anyType);
}
@ -226,17 +218,14 @@ TEST_CASE_FIXTURE(Fixture, "calling_error_type_yields_error")
local a = unknown.Parent.Reward.GetChildren()
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
UnknownSymbol* err = get<UnknownSymbol>(result.errors[0]);
REQUIRE(err != nullptr);
CHECK_EQ("unknown", err->name);
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(requireType("a")));
else
CHECK_EQ("<error-type>", toString(requireType("a")));
CHECK_EQ("*unknown*", toString(requireType("a")));
}
TEST_CASE_FIXTURE(Fixture, "chain_calling_error_type_yields_error")
@ -245,10 +234,7 @@ TEST_CASE_FIXTURE(Fixture, "chain_calling_error_type_yields_error")
local a = Utility.Create "Foo" {}
)");
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(requireType("a")));
else
CHECK_EQ("<error-type>", toString(requireType("a")));
CHECK_EQ("*unknown*", toString(requireType("a")));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "replace_every_free_type_when_unifying_a_complex_function_with_any")
@ -261,7 +247,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "replace_every_free_type_when_unifying_a_comp
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("b")));
}
@ -284,7 +270,7 @@ function x:y(z: number)
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "CheckMethodsOfError")
@ -296,7 +282,7 @@ function x:y(z: number)
end
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "metatable_of_any_can_be_a_table")
@ -316,7 +302,7 @@ function T:construct(index)
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "type_error_addition")
@ -327,7 +313,7 @@ local foo = makesandwich()
local bar = foo.nutrition + 100
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
// We should definitely get this error
CHECK_EQ("Unknown global 'makesandwich'", toString(result.errors[0]));
@ -343,7 +329,7 @@ TEST_CASE_FIXTURE(Fixture, "prop_access_on_any_with_other_options")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_SUITE_END();

View file

@ -1,17 +1,16 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h"
#include "Luau/BuiltinDefinitions.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/TypeInfer.h"
#include "lluz/BuiltinDefinitions.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
LUAU_FASTFLAG(LuauLowerBoundsCalculation);
LUAU_FASTFLAG(LuauSpecialTypesAsterisked);
lluz_FASTFLAG(LluLowerBoundsCalculation);
TEST_SUITE_BEGIN("BuiltinTests");
TEST_SUITE_BEGIN(XorStr("BuiltinTests"));
TEST_CASE_FIXTURE(BuiltinsFixture, "math_things_are_defined")
{
@ -48,7 +47,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "math_things_are_defined")
local a31 = math.random
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "next_iterator_should_infer_types_and_type_check")
@ -61,7 +60,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "next_iterator_should_infer_types_and_type_ch
local c: string, d: number = next(t)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "pairs_iterator_should_infer_types_and_type_check")
@ -73,7 +72,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "pairs_iterator_should_infer_types_and_type_c
local it: (Map<string, number>, string | nil) -> (string, number), t: Map<string, number>, i: nil = pairs(map)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "ipairs_iterator_should_infer_types_and_type_check")
@ -85,7 +84,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "ipairs_iterator_should_infer_types_and_type_
local it: (Map<number, string>, number) -> (number, string), t: Map<number, string>, i: number = ipairs(array)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "table_dot_remove_optionally_returns_generic")
@ -95,8 +94,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_dot_remove_optionally_returns_generic"
local n = table.remove(t, 7)
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("n")), "number?");
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType(XorStr("n")), "number?"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "table_concat_returns_string")
@ -105,7 +104,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_concat_returns_string")
local r = table.concat({1,2,3,4}, ",", 2);
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.stringType, *requireType("r"));
}
@ -116,7 +115,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "sort")
table.sort(t)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_predicate")
@ -128,7 +127,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_predicate")
table.sort(t, p)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_bad_predicate")
@ -140,7 +139,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_bad_predicate")
table.sort(t, p)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(R"(Type '(number, number) -> boolean' could not be converted into '((a, a) -> boolean)?'
caused by:
None of the union options are compatible. For example: Type '(number, number) -> boolean' could not be converted into '(a, a) -> boolean'
@ -152,10 +151,10 @@ caused by:
TEST_CASE_FIXTURE(Fixture, "strings_have_methods")
{
CheckResult result = check(R"LUA(
local s = ("RoactHostChangeEvent(%s)"):format("hello")
local s = ("RoactHostChangeEvent(%s)"):format(XorStr("hello"))
)LUA");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.stringType, *requireType("s"));
}
@ -165,7 +164,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "math_max_variatic")
local n = math.max(1,2,3,4,5,6,7,8,9,0)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("n"));
}
@ -184,7 +183,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_tables_sealed")
CheckResult result = check(R"LUA(
local b = bit32
)LUA");
TypeId bit32 = requireType("b");
TypeId bit32 = requireType(XorStr("b"));
REQUIRE(bit32 != nullptr);
const TableTypeVar* bit32t = get<TableTypeVar>(bit32);
REQUIRE(bit32t != nullptr);
@ -345,7 +344,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "lua_51_exported_globals_all_exist")
)");
dumpErrors(result);
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_unpacks_arg_types_correctly")
@ -353,7 +352,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_unpacks_arg_types_correctly")
CheckResult result = check(R"(
setmetatable({}, setmetatable({}, {}))
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_correctly_infers_type_of_array_2_args_overload")
@ -364,7 +363,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_correctly_infers_type_of_array_
local s = t[1]
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(typeChecker.stringType, requireType("s"));
}
@ -376,7 +375,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_correctly_infers_type_of_array_
local s = t[1]
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireType("s")));
}
@ -386,7 +385,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_pack")
local t = table.pack(1, "foo", true)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("{| [number]: boolean | number | string, n: number |}", toString(requireType("t")));
}
@ -395,13 +394,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_pack_variadic")
CheckResult result = check(R"(
--!strict
function f(): (string, ...number)
return "str", 2, 3, 4
return XorStr("str"), 2, 3, 4
end
local t = table.pack(f())
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("{| [number]: number | string, n: number |}", toString(requireType("t")));
}
@ -411,14 +410,14 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_pack_reduce")
local t = table.pack(1, 2, true)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("{| [number]: boolean | number, n: number |}", toString(requireType("t")));
result = check(R"(
local t = table.pack("a", "b", "c")
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("{| [number]: string, n: number |}", toString(requireType("t")));
}
@ -428,13 +427,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "gcinfo")
local n = gcinfo()
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("n"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "getfenv")
{
LUAU_REQUIRE_NO_ERRORS(check("getfenv(1)"));
lluz_REQUIRE_NO_ERRORS(check("getfenv(1)"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "os_time_takes_optional_date_table")
@ -445,7 +444,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "os_time_takes_optional_date_table")
local n3 = os.time({ year = 2020, month = 4, day = 20, hour = 0, min = 0, sec = 0, isdst = true })
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("n1"));
CHECK_EQ(*typeChecker.numberType, *requireType("n2"));
CHECK_EQ(*typeChecker.numberType, *requireType("n3"));
@ -457,7 +456,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "thread_is_a_type")
local co = coroutine.create(function() end)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.threadType, *requireType("co"));
}
@ -476,7 +475,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_resume_anything_goes")
local answer = coroutine.resume(co, 3)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_wrap_anything_goes")
@ -495,7 +494,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_wrap_anything_goes")
local answer = f(3)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_should_not_mutate_persisted_types")
@ -506,9 +505,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_should_not_mutate_persisted_typ
setmetatable(string, {})
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
auto stringType = requireType("string");
auto stringType = requireType(XorStr("string"));
auto ttv = get<TableTypeVar>(stringType);
REQUIRE(ttv);
}
@ -518,7 +517,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_arg_types_inference")
CheckResult result = check(R"(
--!strict
function f(a, b, c)
return string.format("%f %d %s", a, b, c)
return string.format(XorStr("%f %d %s"), a, b, c)
end
)");
@ -530,13 +529,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_arg_count_mismatch")
{
CheckResult result = check(R"(
--!strict
string.format("%f %d %s")
string.format("%s", "hi", 42)
string.format("%s", "hi", 42, ...)
string.format("%s", "hi", ...)
string.format(XorStr("%f %d %s"))
string.format(XorStr("%s"), "hi", 42)
string.format(XorStr("%s"), "hi", 42, ...)
string.format(XorStr("%s"), "hi", ...)
)");
LUAU_REQUIRE_ERROR_COUNT(3, result);
lluz_REQUIRE_ERROR_COUNT(3, result);
CHECK_EQ(result.errors[0].location.begin.line, 2);
CHECK_EQ(result.errors[1].location.begin.line, 3);
CHECK_EQ(result.errors[2].location.begin.line, 4);
@ -546,10 +545,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_correctly_ordered_types")
{
CheckResult result = check(R"(
--!strict
string.format("%s", 123)
string.format(XorStr("%s"), 123)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
CHECK_EQ(tm->wantedType, typeChecker.stringType);
@ -566,7 +565,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "xpcall")
)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("boolean", toString(requireType("a")));
CHECK_EQ("number", toString(requireType("b")));
CHECK_EQ("boolean", toString(requireType("c")));
@ -578,7 +577,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "see_thru_select")
local a:number, b:boolean = select(2,"hi", 10, true)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "see_thru_select_count")
@ -588,7 +587,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "see_thru_select_count")
)");
dumpErrors(result);
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_decimal_argument_is_rounded_down")
@ -597,7 +596,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_decimal_argument_is_rounded_down
local a: number, b: boolean = select(2.9, "foo", 1, true)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
// Could be flaky if the fix has regressed.
@ -613,7 +612,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "bad_select_should_not_crash")
end
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ("Argument count mismatch. Function expects at least 1 argument, but none are specified", toString(result.errors[0]));
CHECK_EQ("Argument count mismatch. Function expects 1 argument, but none are specified", toString(result.errors[1]));
}
@ -624,7 +623,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_way_out_of_range")
select(5432598430953240958)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<GenericError>(result.errors[0]));
CHECK_EQ("bad argument #1 to select (index out of range)", toString(result.errors[0]));
}
@ -635,7 +634,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_slightly_out_of_range")
select(3, "a", 1)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<GenericError>(result.errors[0]));
CHECK_EQ("bad argument #1 to select (index out of range)", toString(result.errors[0]));
}
@ -651,7 +650,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_variadic_typepack_tail")
local foo, bar, baz, quux = select(1, f("foo", true))
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("foo")));
CHECK_EQ("any", toString(requireType("bar")));
@ -670,7 +669,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_variadic_typepack_tail_and_strin
local foo, bar, baz, quux = select(1, "foo", f("bar", true))
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("foo")));
CHECK_EQ("any", toString(requireType("bar")));
@ -680,9 +679,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_variadic_typepack_tail_and_strin
TEST_CASE_FIXTURE(Fixture, "string_format_as_method")
{
CheckResult result = check("local _ = ('%s'):format(5)");
CheckResult result = check(XorStr("local _ = ('%s'):format(5)"));
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
@ -693,10 +692,10 @@ TEST_CASE_FIXTURE(Fixture, "string_format_as_method")
TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument")
{
CheckResult result = check(R"(
local _ = ("%s"):format("%d", "hello")
local _ = ("%s"):format(XorStr("%d"), "hello")
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Argument count mismatch. Function expects 1 argument, but 2 are specified", toString(result.errors[0]));
}
@ -704,10 +703,10 @@ TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument")
TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument2")
{
CheckResult result = check(R"(
local _ = ("%s %d").format("%d %s", "A type error", 2)
local _ = ("%s %d").format(XorStr("%d %s"), "A type error", 2)
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ("Type 'string' could not be converted into 'number'", toString(result.errors[0]));
CHECK_EQ("Type 'number' could not be converted into 'string'", toString(result.errors[1]));
@ -727,7 +726,7 @@ debug.traceback(co, "msg")
debug.traceback(co, "msg", 1)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "debug_info_is_crazy")
@ -741,7 +740,7 @@ debug.info(co, 1, "n")
debug.info(f, "n")
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "aliased_string_format")
@ -751,7 +750,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "aliased_string_format")
local s = fmt("%d", "oops")
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type 'string' could not be converted into 'number'", toString(result.errors[0]));
}
@ -771,7 +770,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_lib_self_noself")
local a0 = string.packsize("ff")
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_definition")
@ -784,7 +783,7 @@ for c in ("hey"):gmatch("(.)") do
end
)_");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "select_on_variadic")
@ -797,7 +796,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_on_variadic")
local a, b, c = select(f())
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("a")));
CHECK_EQ("any", toString(requireType("b")));
CHECK_EQ("any", toString(requireType("c")));
@ -807,14 +806,14 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_report_all_type_errors_at_corr
{
CheckResult result = check(R"(
("%s%d%s"):format(1, "hello", true)
string.format("%s%d%s", 1, "hello", true)
string.format(XorStr("%s%d%s"), 1, "hello", true)
)");
TypeId stringType = typeChecker.stringType;
TypeId numberType = typeChecker.numberType;
TypeId booleanType = typeChecker.booleanType;
LUAU_REQUIRE_ERROR_COUNT(6, result);
lluz_REQUIRE_ERROR_COUNT(6, result);
CHECK_EQ(Location(Position{1, 26}, Position{1, 27}), result.errors[0].location);
CHECK_EQ(TypeErrorData(TypeMismatch{stringType, numberType}), result.errors[0].data);
@ -842,7 +841,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tonumber_returns_optional_number_type")
local b: number = tonumber('asdf')
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type 'number?' could not be converted into 'number'", toString(result.errors[0]));
}
@ -853,7 +852,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tonumber_returns_optional_number_type2")
local b: number = tonumber('asdf') or 1
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "dont_add_definitions_to_persistent_types")
@ -863,15 +862,15 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dont_add_definitions_to_persistent_types")
local function g(x) return math.sin(x) end
f = g
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId fType = requireType("f");
TypeId fType = requireType(XorStr("f"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(fType);
REQUIRE(fType);
REQUIRE(fType->persistent);
REQUIRE(!ftv->definition);
TypeId gType = requireType("g");
TypeId gType = requireType(XorStr("g"));
const FunctionTypeVar* gtv = get<FunctionTypeVar>(gType);
REQUIRE(gType);
REQUIRE(!gType->persistent);
@ -886,8 +885,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
if (FFlag::LuauLowerBoundsCalculation)
lluz_REQUIRE_NO_ERRORS(result);
if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ("((boolean | number)?) -> number | true", toString(requireType("f")));
else
CHECK_EQ("((boolean | number)?) -> boolean | number", toString(requireType("f")));
@ -901,7 +900,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types2")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("((boolean | number)?) -> number | true", toString(requireType("f")));
}
@ -913,7 +912,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types_even_from_type_pa
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("(...number?) -> (number, ...number?)", toString(requireType("f")));
}
@ -925,8 +924,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_returns_false_and_string_iff_it_knows
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ("(nil) -> (never, ...never)", toString(requireType("f")));
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("(nil) -> nil", toString(requireType("f")));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic")
@ -947,30 +946,27 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic")
local d = tf1.b
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Key 'b' not found in table '{| a: number |}'", toString(result.errors[0]));
CHECK_EQ("number", toString(requireType("a")));
CHECK_EQ("string", toString(requireType("b")));
CHECK_EQ("boolean", toString(requireType("c")));
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(requireType("d")));
else
CHECK_EQ("<error-type>", toString(requireType("d")));
CHECK_EQ("*unknown*", toString(requireType("d")));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "set_metatable_needs_arguments")
{
ScopedFastFlag sff{"LuauSetMetaTableArgsCheck", true};
ScopedFastFlag sff{"lluzSetMetaTableArgsCheck", true};
CheckResult result = check(R"(
local a = {b=setmetatable}
a.b()
a:b()
a:b({})
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(toString(result.errors[0]), "Argument count mismatch. Function expects 2 arguments, but none are specified");
CHECK_EQ(toString(result.errors[1]), "Argument count mismatch. Function expects 2 arguments, but only 1 is specified");
lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(result.errors[0], (TypeError{Location{{2, 0}, {2, 5}}, CountMismatch{2, 0}}));
CHECK_EQ(result.errors[1], (TypeError{Location{{3, 0}, {3, 5}}, CountMismatch{2, 1}}));
}
TEST_CASE_FIXTURE(Fixture, "typeof_unresolved_function")
@ -978,13 +974,13 @@ TEST_CASE_FIXTURE(Fixture, "typeof_unresolved_function")
CheckResult result = check(R"(
local function f(a: typeof(f)) end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Unknown global 'f'", toString(result.errors[0]));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "no_persistent_typelevel_change")
{
TypeId mathTy = requireType(typeChecker.globalScope, "math");
TypeId mathTy = requireType(typeChecker.globalScope, XorStr("math"));
REQUIRE(mathTy);
TableTypeVar* ttv = getMutable<TableTypeVar>(mathTy);
REQUIRE(ttv);
@ -992,9 +988,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_persistent_typelevel_change")
REQUIRE(ftv);
auto original = ftv->level;
CheckResult result = check("local a = math.frexp");
CheckResult result = check(XorStr("local a = math.frexp"));
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK(ftv->level.level == original.level);
CHECK(ftv->level.subLevel == original.subLevel);
}
@ -1009,252 +1005,7 @@ local function f(x: string)
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types")
{
ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
CheckResult result = check(R"END(
local a, b, c = string.gmatch("This is a string", "(.()(%a+))")()
)END");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "string");
CHECK_EQ(toString(requireType("b")), "number");
CHECK_EQ(toString(requireType("c")), "string");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types2")
{
ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
CheckResult result = check(R"END(
local a, b, c = ("This is a string"):gmatch("(.()(%a+))")()
)END");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "string");
CHECK_EQ(toString(requireType("b")), "number");
CHECK_EQ(toString(requireType("c")), "string");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_default_capture")
{
ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
CheckResult result = check(R"END(
local a, b, c, d = string.gmatch("T(his)() is a string", ".")()
)END");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CountMismatch* acm = get<CountMismatch>(result.errors[0]);
REQUIRE(acm);
CHECK_EQ(acm->context, CountMismatch::Result);
CHECK_EQ(acm->expected, 1);
CHECK_EQ(acm->actual, 4);
CHECK_EQ(toString(requireType("a")), "string");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_balanced_escaped_parens")
{
ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
CheckResult result = check(R"END(
local a, b, c, d = string.gmatch("T(his) is a string", "((.)%b()())")()
)END");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CountMismatch* acm = get<CountMismatch>(result.errors[0]);
REQUIRE(acm);
CHECK_EQ(acm->context, CountMismatch::Result);
CHECK_EQ(acm->expected, 3);
CHECK_EQ(acm->actual, 4);
CHECK_EQ(toString(requireType("a")), "string");
CHECK_EQ(toString(requireType("b")), "string");
CHECK_EQ(toString(requireType("c")), "number");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_parens_in_sets_are_ignored")
{
ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
CheckResult result = check(R"END(
local a, b, c = string.gmatch("T(his)() is a string", "(T[()])()")()
)END");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CountMismatch* acm = get<CountMismatch>(result.errors[0]);
REQUIRE(acm);
CHECK_EQ(acm->context, CountMismatch::Result);
CHECK_EQ(acm->expected, 2);
CHECK_EQ(acm->actual, 3);
CHECK_EQ(toString(requireType("a")), "string");
CHECK_EQ(toString(requireType("b")), "number");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_set_containing_lbracket")
{
ScopedFastFlag sffs{"LuauDeduceGmatchReturnTypes", true};
CheckResult result = check(R"END(
local a, b = string.gmatch("[[[", "()([[])")()
)END");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "number");
CHECK_EQ(toString(requireType("b")), "string");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_leading_end_bracket_is_part_of_set")
{
CheckResult result = check(R"END(
-- An immediate right-bracket following a left-bracket is included within the set;
-- thus, '[]]'' is the set containing ']', and '[]' is an invalid set missing an enclosing
-- right-bracket. We detect an invalid set in this case and fall back to to default gmatch
-- typing.
local foo = string.gmatch("T[hi%]s]]]() is a string", "([]s)")
)END");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("foo")), "() -> (...string)");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_invalid_pattern_fallback_to_builtin")
{
CheckResult result = check(R"END(
local foo = string.gmatch("T(his)() is a string", ")")
)END");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("foo")), "() -> (...string)");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_capture_types_invalid_pattern_fallback_to_builtin2")
{
CheckResult result = check(R"END(
local foo = string.gmatch("T(his)() is a string", "[")
)END");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("foo")), "() -> (...string)");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "match_capture_types")
{
ScopedFastFlag sffs{"LuauDeduceFindMatchReturnTypes", true};
CheckResult result = check(R"END(
local a, b, c = string.match("This is a string", "(.()(%a+))")
)END");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "string");
CHECK_EQ(toString(requireType("b")), "number");
CHECK_EQ(toString(requireType("c")), "string");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "match_capture_types2")
{
ScopedFastFlag sffs{"LuauDeduceFindMatchReturnTypes", true};
CheckResult result = check(R"END(
local a, b, c = string.match("This is a string", "(.()(%a+))", "this should be a number")
)END");
LUAU_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
CHECK_EQ(toString(tm->wantedType), "number?");
CHECK_EQ(toString(tm->givenType), "string");
CHECK_EQ(toString(requireType("a")), "string");
CHECK_EQ(toString(requireType("b")), "number");
CHECK_EQ(toString(requireType("c")), "string");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "find_capture_types")
{
ScopedFastFlag sffs{"LuauDeduceFindMatchReturnTypes", true};
CheckResult result = check(R"END(
local d, e, a, b, c = string.find("This is a string", "(.()(%a+))")
)END");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "string");
CHECK_EQ(toString(requireType("b")), "number");
CHECK_EQ(toString(requireType("c")), "string");
CHECK_EQ(toString(requireType("d")), "number?");
CHECK_EQ(toString(requireType("e")), "number?");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "find_capture_types2")
{
ScopedFastFlag sffs{"LuauDeduceFindMatchReturnTypes", true};
CheckResult result = check(R"END(
local d, e, a, b, c = string.find("This is a string", "(.()(%a+))", "this should be a number")
)END");
LUAU_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
CHECK_EQ(toString(tm->wantedType), "number?");
CHECK_EQ(toString(tm->givenType), "string");
CHECK_EQ(toString(requireType("a")), "string");
CHECK_EQ(toString(requireType("b")), "number");
CHECK_EQ(toString(requireType("c")), "string");
CHECK_EQ(toString(requireType("d")), "number?");
CHECK_EQ(toString(requireType("e")), "number?");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "find_capture_types3")
{
ScopedFastFlag sffs{"LuauDeduceFindMatchReturnTypes", true};
CheckResult result = check(R"END(
local d, e, a, b, c = string.find("This is a string", "(.()(%a+))", 1, "this should be a bool")
)END");
LUAU_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
CHECK_EQ(toString(tm->wantedType), "boolean?");
CHECK_EQ(toString(tm->givenType), "string");
CHECK_EQ(toString(requireType("a")), "string");
CHECK_EQ(toString(requireType("b")), "number");
CHECK_EQ(toString(requireType("c")), "string");
CHECK_EQ(toString(requireType("d")), "number?");
CHECK_EQ(toString(requireType("e")), "number?");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "find_capture_types3")
{
ScopedFastFlag sffs{"LuauDeduceFindMatchReturnTypes", true};
CheckResult result = check(R"END(
local d, e, a, b = string.find("This is a string", "(.()(%a+))", 1, true)
)END");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CountMismatch* acm = get<CountMismatch>(result.errors[0]);
REQUIRE(acm);
CHECK_EQ(acm->context, CountMismatch::Result);
CHECK_EQ(acm->expected, 2);
CHECK_EQ(acm->actual, 4);
CHECK_EQ(toString(requireType("d")), "number?");
CHECK_EQ(toString(requireType("e")), "number?");
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_SUITE_END();

View file

@ -1,13 +1,13 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/BuiltinDefinitions.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
using std::nullopt;
struct ClassFixture : BuiltinsFixture
@ -32,7 +32,7 @@ struct ClassFixture : BuiltinsFixture
{"New", {makeFunction(arena, nullopt, {}, {baseClassInstanceType})}},
};
typeChecker.globalScope->exportedTypeBindings["BaseClass"] = TypeFun{{}, baseClassInstanceType};
addGlobalBinding(typeChecker, "BaseClass", baseClassType, "@test");
addGlobalBinding(typeChecker, XorStr("BaseClass", baseClassType, "@test"));
TypeId childClassInstanceType = arena.addType(ClassTypeVar{"ChildClass", {}, baseClassInstanceType, nullopt, {}, {}, "Test"});
@ -45,7 +45,7 @@ struct ClassFixture : BuiltinsFixture
{"New", {makeFunction(arena, nullopt, {}, {childClassInstanceType})}},
};
typeChecker.globalScope->exportedTypeBindings["ChildClass"] = TypeFun{{}, childClassInstanceType};
addGlobalBinding(typeChecker, "ChildClass", childClassType, "@test");
addGlobalBinding(typeChecker, XorStr("ChildClass", childClassType, "@test"));
TypeId grandChildInstanceType = arena.addType(ClassTypeVar{"GrandChild", {}, childClassInstanceType, nullopt, {}, {}, "Test"});
@ -58,7 +58,7 @@ struct ClassFixture : BuiltinsFixture
{"New", {makeFunction(arena, nullopt, {}, {grandChildInstanceType})}},
};
typeChecker.globalScope->exportedTypeBindings["GrandChild"] = TypeFun{{}, grandChildInstanceType};
addGlobalBinding(typeChecker, "GrandChild", childClassType, "@test");
addGlobalBinding(typeChecker, XorStr("GrandChild", childClassType, "@test"));
TypeId anotherChildInstanceType = arena.addType(ClassTypeVar{"AnotherChild", {}, baseClassInstanceType, nullopt, {}, {}, "Test"});
@ -71,7 +71,7 @@ struct ClassFixture : BuiltinsFixture
{"New", {makeFunction(arena, nullopt, {}, {anotherChildInstanceType})}},
};
typeChecker.globalScope->exportedTypeBindings["AnotherChild"] = TypeFun{{}, anotherChildInstanceType};
addGlobalBinding(typeChecker, "AnotherChild", childClassType, "@test");
addGlobalBinding(typeChecker, XorStr("AnotherChild", childClassType, "@test"));
TypeId vector2MetaType = arena.addType(TableTypeVar{});
@ -89,7 +89,7 @@ struct ClassFixture : BuiltinsFixture
{"__add", {makeFunction(arena, nullopt, {vector2InstanceType, vector2InstanceType}, {vector2InstanceType})}},
};
typeChecker.globalScope->exportedTypeBindings["Vector2"] = TypeFun{{}, vector2InstanceType};
addGlobalBinding(typeChecker, "Vector2", vector2Type, "@test");
addGlobalBinding(typeChecker, XorStr("Vector2", vector2Type, "@test"));
for (const auto& [name, tf] : typeChecker.globalScope->exportedTypeBindings)
persist(tf.type);
@ -98,7 +98,7 @@ struct ClassFixture : BuiltinsFixture
}
};
TEST_SUITE_BEGIN("TypeInferClasses");
TEST_SUITE_BEGIN(XorStr("TypeInferClasses"));
TEST_CASE_FIXTURE(ClassFixture, "call_method_of_a_class")
{
@ -106,7 +106,7 @@ TEST_CASE_FIXTURE(ClassFixture, "call_method_of_a_class")
local m = BaseClass.StaticMethod()
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
REQUIRE_EQ("number", toString(requireType("m")));
}
@ -117,7 +117,7 @@ TEST_CASE_FIXTURE(ClassFixture, "call_method_of_a_child_class")
local m = ChildClass.StaticMethod()
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
REQUIRE_EQ("number", toString(requireType("m")));
}
@ -129,7 +129,7 @@ TEST_CASE_FIXTURE(ClassFixture, "call_instance_method")
local result = i:Method()
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireType("result")));
}
@ -141,7 +141,7 @@ TEST_CASE_FIXTURE(ClassFixture, "call_base_method")
i:BaseMethod(41)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(ClassFixture, "cannot_call_unknown_method_of_a_class")
@ -150,7 +150,7 @@ TEST_CASE_FIXTURE(ClassFixture, "cannot_call_unknown_method_of_a_class")
local m = BaseClass.Nope()
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(ClassFixture, "cannot_call_method_of_child_on_base_instance")
@ -160,7 +160,7 @@ TEST_CASE_FIXTURE(ClassFixture, "cannot_call_method_of_child_on_base_instance")
i:Method()
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(ClassFixture, "we_can_infer_that_a_parameter_must_be_a_particular_class")
@ -194,7 +194,7 @@ TEST_CASE_FIXTURE(ClassFixture, "we_can_report_when_someone_is_trying_to_use_a_t
makeClone(oopsies)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm != nullptr);
@ -209,7 +209,7 @@ TEST_CASE_FIXTURE(ClassFixture, "assign_to_prop_of_class")
v.X = 55
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(ClassFixture, "can_read_prop_of_base_class")
@ -219,7 +219,7 @@ TEST_CASE_FIXTURE(ClassFixture, "can_read_prop_of_base_class")
local x = 1 + c.BaseField
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(ClassFixture, "can_assign_to_prop_of_base_class")
@ -229,7 +229,7 @@ TEST_CASE_FIXTURE(ClassFixture, "can_assign_to_prop_of_base_class")
c.BaseField = 444
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(ClassFixture, "can_read_prop_of_base_class_using_string")
@ -239,7 +239,7 @@ TEST_CASE_FIXTURE(ClassFixture, "can_read_prop_of_base_class_using_string")
local x = 1 + c["BaseField"]
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(ClassFixture, "can_assign_to_prop_of_base_class_using_string")
@ -249,7 +249,7 @@ TEST_CASE_FIXTURE(ClassFixture, "can_assign_to_prop_of_base_class_using_string")
c["BaseField"] = 444
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(ClassFixture, "cannot_unify_class_instance_with_primitive")
@ -259,7 +259,7 @@ TEST_CASE_FIXTURE(ClassFixture, "cannot_unify_class_instance_with_primitive")
v = 444
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(ClassFixture, "warn_when_prop_almost_matches")
@ -268,7 +268,7 @@ TEST_CASE_FIXTURE(ClassFixture, "warn_when_prop_almost_matches")
Vector2.new(0, 0)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
auto err = get<UnknownPropButFoundLikeProp>(result.errors[0]);
REQUIRE(err != nullptr);
@ -285,7 +285,7 @@ TEST_CASE_FIXTURE(ClassFixture, "classes_can_have_overloaded_operators")
local c = a + b
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Vector2", toString(requireType("c")));
}
@ -298,7 +298,7 @@ TEST_CASE_FIXTURE(ClassFixture, "classes_without_overloaded_operators_cannot_be_
local c = a + b
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(ClassFixture, "function_arguments_are_covariant")
@ -309,7 +309,7 @@ TEST_CASE_FIXTURE(ClassFixture, "function_arguments_are_covariant")
f(ChildClass.New())
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(ClassFixture, "higher_order_function_arguments_are_contravariant")
@ -322,7 +322,7 @@ TEST_CASE_FIXTURE(ClassFixture, "higher_order_function_arguments_are_contravaria
apply(function (c: ChildClass) end) -- 5
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(ClassFixture, "higher_order_function_return_values_are_covariant")
@ -337,7 +337,7 @@ TEST_CASE_FIXTURE(ClassFixture, "higher_order_function_return_values_are_covaria
end)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(ClassFixture, "higher_order_function_return_type_is_not_contravariant")
@ -352,7 +352,7 @@ TEST_CASE_FIXTURE(ClassFixture, "higher_order_function_return_type_is_not_contra
end)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(ClassFixture, "table_properties_are_invariant")
@ -373,7 +373,7 @@ TEST_CASE_FIXTURE(ClassFixture, "table_properties_are_invariant")
g(t2) -- line 13. Breaks soundness
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(6, result.errors[0].location.begin.line);
CHECK_EQ(13, result.errors[1].location.begin.line);
}
@ -396,7 +396,7 @@ TEST_CASE_FIXTURE(ClassFixture, "table_indexers_are_invariant")
g(t2) -- line 13. Breaks soundness
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(6, result.errors[0].location.begin.line);
CHECK_EQ(13, result.errors[1].location.begin.line);
}
@ -414,7 +414,7 @@ TEST_CASE_FIXTURE(ClassFixture, "table_class_unification_reports_sane_errors_for
foo(a)
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
REQUIRE_EQ("Key 'w' not found in class 'Vector2'", toString(result.errors[0]));
REQUIRE_EQ("Key 'x' not found in class 'Vector2'. Did you mean 'X'?", toString(result.errors[1]));
}
@ -427,7 +427,7 @@ TEST_CASE_FIXTURE(ClassFixture, "class_unification_type_mismatch_is_correct_orde
local foo2: BaseClass = 1
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
REQUIRE_EQ("Type 'BaseClass' could not be converted into 'number'", toString(result.errors[0]));
REQUIRE_EQ("Type 'number' could not be converted into 'BaseClass'", toString(result.errors[1]));
@ -442,7 +442,7 @@ local a = b.X + b.Z
b.X = 2 -- real Vector2.X is also read-only
)");
LUAU_REQUIRE_ERROR_COUNT(4, result);
lluz_REQUIRE_ERROR_COUNT(4, result);
CHECK_EQ("Value of type 'Vector2?' could be nil", toString(result.errors[0]));
CHECK_EQ("Value of type 'Vector2?' could be nil", toString(result.errors[1]));
CHECK_EQ("Key 'Z' not found in class 'Vector2'", toString(result.errors[2]));
@ -461,7 +461,7 @@ local b = foo
b(a)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(R"(Type 'Vector2' could not be converted into '{- X: a, Y: string -}'
caused by:
Property 'Y' is not compatible. Type 'number' could not be converted into 'string')",
@ -476,7 +476,7 @@ type ChildClass = { x: number }
local a: ChildClass = i
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type 'ChildClass' from 'Test' could not be converted into 'ChildClass' from 'MainModule'", toString(result.errors[0]));
}

View file

@ -1,15 +1,15 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/BuiltinDefinitions.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("DefinitionTests");
TEST_SUITE_BEGIN(XorStr("DefinitionTests"));
TEST_CASE_FIXTURE(Fixture, "definition_file_loading")
{
@ -21,22 +21,22 @@ TEST_CASE_FIXTURE(Fixture, "definition_file_loading")
declare function var(...: any): string
)");
TypeId globalFooTy = getGlobalBinding(frontend.typeChecker, "foo");
CHECK_EQ(toString(globalFooTy), "number");
TypeId globalFooTy = getGlobalBinding(frontend.typeChecker, XorStr("foo"));
CHECK_EQ(toString(globalFooTy), XorStr("number"));
std::optional<TypeFun> globalAsdfTy = frontend.typeChecker.globalScope->lookupType("Asdf");
std::optional<TypeFun> globalAsdfTy = frontend.typeChecker.globalScope->lookupType(XorStr("Asdf"));
REQUIRE(bool(globalAsdfTy));
CHECK_EQ(toString(globalAsdfTy->type), "number | string");
CHECK_EQ(toString(globalAsdfTy->type), XorStr("number | string"));
TypeId globalBarTy = getGlobalBinding(frontend.typeChecker, "bar");
CHECK_EQ(toString(globalBarTy), "(number) -> string");
TypeId globalBarTy = getGlobalBinding(frontend.typeChecker, XorStr("bar"));
CHECK_EQ(toString(globalBarTy), XorStr("(number) -> string"));
TypeId globalFoo2Ty = getGlobalBinding(frontend.typeChecker, "foo2");
CHECK_EQ(toString(globalFoo2Ty), "number");
TypeId globalFoo2Ty = getGlobalBinding(frontend.typeChecker, XorStr("foo2"));
CHECK_EQ(toString(globalFoo2Ty), XorStr("number"));
TypeId globalVarTy = getGlobalBinding(frontend.typeChecker, "var");
TypeId globalVarTy = getGlobalBinding(frontend.typeChecker, XorStr("var"));
CHECK_EQ(toString(globalVarTy), "(...any) -> string");
CHECK_EQ(toString(globalVarTy), XorStr("(...any) -> string"));
CheckResult result = check(R"(
local x: number = foo + 1
@ -45,7 +45,7 @@ TEST_CASE_FIXTURE(Fixture, "definition_file_loading")
z = y
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "load_definition_file_errors_do_not_pollute_global_scope")
@ -54,21 +54,21 @@ TEST_CASE_FIXTURE(Fixture, "load_definition_file_errors_do_not_pollute_global_sc
LoadDefinitionFileResult parseFailResult = loadDefinitionFile(typeChecker, typeChecker.globalScope, R"(
declare foo
)",
"@test");
XorStr("@test"));
freeze(typeChecker.globalTypes);
REQUIRE(!parseFailResult.success);
std::optional<Binding> fooTy = tryGetGlobalBinding(typeChecker, "foo");
std::optional<Binding> fooTy = tryGetGlobalBinding(typeChecker, XorStr("foo"));
CHECK(!fooTy.has_value());
LoadDefinitionFileResult checkFailResult = loadDefinitionFile(typeChecker, typeChecker.globalScope, R"(
local foo: string = 123
declare bar: typeof(foo)
)",
"@test");
XorStr("@test"));
REQUIRE(!checkFailResult.success);
std::optional<Binding> barTy = tryGetGlobalBinding(typeChecker, "bar");
std::optional<Binding> barTy = tryGetGlobalBinding(typeChecker, XorStr("bar"));
CHECK(!barTy.has_value());
}
@ -101,13 +101,13 @@ TEST_CASE_FIXTURE(Fixture, "definition_file_classes")
local inheritedMethod: number = x:inheritance()
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("prop")), "number");
CHECK_EQ(toString(requireType("inheritedProp")), "number");
CHECK_EQ(toString(requireType("method")), "number");
CHECK_EQ(toString(requireType("method2")), "string");
CHECK_EQ(toString(requireType("metamethod")), "Bar");
CHECK_EQ(toString(requireType("inheritedMethod")), "number");
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType(XorStr("prop")), "number"));
CHECK_EQ(toString(requireType(XorStr("inheritedProp")), "number"));
CHECK_EQ(toString(requireType(XorStr("method")), "number"));
CHECK_EQ(toString(requireType(XorStr("method2")), "string"));
CHECK_EQ(toString(requireType(XorStr("metamethod")), "Bar"));
CHECK_EQ(toString(requireType(XorStr("inheritedMethod")), "number"));
}
TEST_CASE_FIXTURE(Fixture, "class_definitions_cannot_overload_non_function")
@ -119,7 +119,7 @@ TEST_CASE_FIXTURE(Fixture, "class_definitions_cannot_overload_non_function")
X: string
end
)",
"@test");
XorStr("@test"));
freeze(typeChecker.globalTypes);
REQUIRE(!result.success);
@ -140,7 +140,7 @@ TEST_CASE_FIXTURE(Fixture, "class_definitions_cannot_extend_non_class")
declare class Foo extends NotAClass
end
)",
"@test");
XorStr("@test"));
freeze(typeChecker.globalTypes);
REQUIRE(!result.success);
@ -162,7 +162,7 @@ TEST_CASE_FIXTURE(Fixture, "no_cyclic_defined_classes")
declare class Bar extends Foo
end
)",
"@test");
XorStr("@test"));
freeze(typeChecker.globalTypes);
REQUIRE(!result.success);
@ -186,13 +186,13 @@ TEST_CASE_FIXTURE(Fixture, "declaring_generic_functions")
local h = h
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("x")), "string");
CHECK_EQ(toString(requireType("w")), "boolean");
CHECK_EQ(toString(requireType("u")), "number");
CHECK_EQ(toString(requireType("f")), "<a, b>(a, b) -> string");
CHECK_EQ(toString(requireType("g")), "<a..., b...>(a...) -> (b...)");
CHECK_EQ(toString(requireType("h")), "<a, b>(a, b) -> (b, a)");
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType(XorStr("x")), "string"));
CHECK_EQ(toString(requireType(XorStr("w")), "boolean"));
CHECK_EQ(toString(requireType(XorStr("u")), "number"));
CHECK_EQ(toString(requireType(XorStr("f")), "<a, b>(a, b) -> string"));
CHECK_EQ(toString(requireType(XorStr("g")), "<a..., b...>(a...) -> (b...)"));
CHECK_EQ(toString(requireType(XorStr("h")), "<a, b>(a, b) -> (b, a)"));
}
TEST_CASE_FIXTURE(Fixture, "class_definition_function_prop")
@ -208,8 +208,8 @@ TEST_CASE_FIXTURE(Fixture, "class_definition_function_prop")
local prop = x.X
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("prop")), "(number) -> string");
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType(XorStr("prop")), "(number) -> string"));
}
TEST_CASE_FIXTURE(Fixture, "definition_file_class_function_args")
@ -230,12 +230,12 @@ TEST_CASE_FIXTURE(Fixture, "definition_file_class_function_args")
local prop = x.y
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
ToStringOptions opts;
opts.functionTypeArguments = true;
CHECK_EQ(toString(requireType("methodRef1"), opts), "(self: Foo, x: number) -> number");
CHECK_EQ(toString(requireType("methodRef2"), opts), "(self: Foo, x: number, y: string) -> number");
CHECK_EQ(toString(requireType("prop"), opts), "(a: number, b: string) -> string");
CHECK_EQ(toString(requireType(XorStr("methodRef1"), opts), "(self: Foo, x: number) -> number"));
CHECK_EQ(toString(requireType(XorStr("methodRef2"), opts), "(self: Foo, x: number, y: string) -> number"));
CHECK_EQ(toString(requireType(XorStr("prop"), opts), "(a: number, b: string) -> string"));
}
TEST_CASE_FIXTURE(Fixture, "definitions_documentation_symbols")
@ -254,32 +254,32 @@ TEST_CASE_FIXTURE(Fixture, "definitions_documentation_symbols")
}
)");
std::optional<Binding> xBinding = typeChecker.globalScope->linearSearchForBinding("x");
std::optional<Binding> xBinding = typeChecker.globalScope->linearSearchForBinding(XorStr("x"));
REQUIRE(bool(xBinding));
// note: loadDefinition uses the @test package name.
CHECK_EQ(xBinding->documentationSymbol, "@test/global/x");
CHECK_EQ(xBinding->documentationSymbol, XorStr("@test/global/x"));
std::optional<TypeFun> fooTy = typeChecker.globalScope->lookupType("Foo");
std::optional<TypeFun> fooTy = typeChecker.globalScope->lookupType(XorStr("Foo"));
REQUIRE(bool(fooTy));
CHECK_EQ(fooTy->type->documentationSymbol, "@test/globaltype/Foo");
CHECK_EQ(fooTy->type->documentationSymbol, XorStr("@test/globaltype/Foo"));
std::optional<TypeFun> barTy = typeChecker.globalScope->lookupType("Bar");
std::optional<TypeFun> barTy = typeChecker.globalScope->lookupType(XorStr("Bar"));
REQUIRE(bool(barTy));
CHECK_EQ(barTy->type->documentationSymbol, "@test/globaltype/Bar");
CHECK_EQ(barTy->type->documentationSymbol, XorStr("@test/globaltype/Bar"));
ClassTypeVar* barClass = getMutable<ClassTypeVar>(barTy->type);
REQUIRE(bool(barClass));
REQUIRE_EQ(barClass->props.count("prop"), 1);
CHECK_EQ(barClass->props["prop"].documentationSymbol, "@test/globaltype/Bar.prop");
CHECK_EQ(barClass->props[XorStr("prop"].documentationSymbol, "@test/globaltype/Bar.prop"));
std::optional<Binding> yBinding = typeChecker.globalScope->linearSearchForBinding("y");
std::optional<Binding> yBinding = typeChecker.globalScope->linearSearchForBinding(XorStr("y"));
REQUIRE(bool(yBinding));
CHECK_EQ(yBinding->documentationSymbol, "@test/global/y");
CHECK_EQ(yBinding->documentationSymbol, XorStr("@test/global/y"));
TableTypeVar* yTtv = getMutable<TableTypeVar>(yBinding->typeId);
REQUIRE(bool(yTtv));
REQUIRE_EQ(yTtv->props.count("x"), 1);
CHECK_EQ(yTtv->props["x"].documentationSymbol, "@test/global/y.x");
CHECK_EQ(yTtv->props[XorStr("x"].documentationSymbol, "@test/global/y.x"));
}
TEST_CASE_FIXTURE(Fixture, "documentation_symbols_dont_attach_to_persistent_types")
@ -288,7 +288,7 @@ TEST_CASE_FIXTURE(Fixture, "documentation_symbols_dont_attach_to_persistent_type
export type Evil = string
)");
std::optional<TypeFun> ty = typeChecker.globalScope->lookupType("Evil");
std::optional<TypeFun> ty = typeChecker.globalScope->lookupType(XorStr("Evil"));
REQUIRE(bool(ty));
CHECK_EQ(ty->type->documentationSymbol, std::nullopt);
}
@ -306,7 +306,7 @@ declare GetCls: () -> (Cls)
local s : Cls = GetCls()
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_SUITE_END();

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/Scope.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "lluz/Scope.h"
#include <algorithm>
@ -9,12 +9,9 @@
#include "doctest.h"
LUAU_FASTFLAG(LuauCheckGenericHOFTypes)
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
using namespace lluz;
using namespace Luau;
TEST_SUITE_BEGIN("GenericsTests");
TEST_SUITE_BEGIN(XorStr("GenericsTests"));
TEST_CASE_FIXTURE(Fixture, "check_generic_function")
{
@ -25,7 +22,7 @@ TEST_CASE_FIXTURE(Fixture, "check_generic_function")
local x: string = id("hi")
local y: number = id(37)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "check_generic_local_function")
@ -37,7 +34,7 @@ TEST_CASE_FIXTURE(Fixture, "check_generic_local_function")
local x: string = id("hi")
local y: number = id(37)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "check_generic_typepack_function")
@ -48,7 +45,7 @@ TEST_CASE_FIXTURE(Fixture, "check_generic_typepack_function")
local z: number = id(37)
id()
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "types_before_typepacks")
@ -56,7 +53,7 @@ TEST_CASE_FIXTURE(Fixture, "types_before_typepacks")
CheckResult result = check(R"(
function f<a,b...>() end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "local_vars_can_be_polytypes")
@ -67,7 +64,7 @@ TEST_CASE_FIXTURE(Fixture, "local_vars_can_be_polytypes")
local x: string = f("hi")
local y: number = f(37)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "inferred_local_vars_can_be_polytypes")
@ -79,7 +76,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "inferred_local_vars_can_be_polytypes")
local x: string = f("hi")
local y: number = f(37)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "local_vars_can_be_instantiated_polytypes")
@ -90,7 +87,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "local_vars_can_be_instantiated_polytypes")
local f: (number)->number = id
local g: (string)->string = id
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "properties_can_be_polytypes")
@ -101,7 +98,7 @@ TEST_CASE_FIXTURE(Fixture, "properties_can_be_polytypes")
local x: string = t.m("hi")
local y: number = t.m(37)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "properties_can_be_instantiated_polytypes")
@ -111,7 +108,7 @@ TEST_CASE_FIXTURE(Fixture, "properties_can_be_instantiated_polytypes")
local function id<a>(x:a):a return x end
t.m = id
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "check_nested_generic_function")
@ -125,7 +122,7 @@ TEST_CASE_FIXTURE(Fixture, "check_nested_generic_function")
local y: number = id(37)
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "check_recursive_generic_function")
@ -137,7 +134,7 @@ TEST_CASE_FIXTURE(Fixture, "check_recursive_generic_function")
return x
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "check_mutual_generic_functions")
@ -155,7 +152,7 @@ TEST_CASE_FIXTURE(Fixture, "check_mutual_generic_functions")
return x
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "generic_functions_in_types")
@ -166,7 +163,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_functions_in_types")
local y: string = x.id("hi")
local z: number = x.id(37)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "generic_factories")
@ -187,7 +184,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_factories")
local y: string = f.build().id("hi")
local z: number = f.build().id(37)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "factories_of_generics")
@ -209,7 +206,7 @@ TEST_CASE_FIXTURE(Fixture, "factories_of_generics")
local y: string = x.id("hi")
local z: number = x.id(37)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "infer_generic_function")
@ -221,9 +218,9 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_function")
local x: string = id("hi")
local y: number = id(37)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId idType = requireType("id");
TypeId idType = requireType(XorStr("id"));
const FunctionTypeVar* idFun = get<FunctionTypeVar>(idType);
REQUIRE(idFun);
auto [args, varargs] = flatten(idFun->argTypes);
@ -244,9 +241,9 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_local_function")
local x: string = id("hi")
local y: number = id(37)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId idType = requireType("id");
TypeId idType = requireType(XorStr("id"));
const FunctionTypeVar* idFun = get<FunctionTypeVar>(idType);
REQUIRE(idFun);
auto [args, varargs] = flatten(idFun->argTypes);
@ -269,12 +266,12 @@ TEST_CASE_FIXTURE(Fixture, "infer_nested_generic_function")
local y: number = id(37)
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "infer_generic_methods")
{
ScopedFastFlag sff{"DebugLuauSharedSelf", true};
ScopedFastFlag sff{"DebuglluzSharedSelf", true};
CheckResult result = check(R"(
local x = {}
@ -283,7 +280,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_methods")
function x:g(): number return self:id(37) end
)");
// TODO: Quantification should be doing the conversion, not normalization.
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "calling_self_generic_methods")
@ -297,7 +294,7 @@ TEST_CASE_FIXTURE(Fixture, "calling_self_generic_methods")
end
)");
// TODO: Should typecheck but currently errors CLI-39916
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "infer_generic_property")
@ -308,7 +305,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_property")
local x: string = t.m("hi")
local y: number = t.m(37)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "function_arguments_can_be_polytypes")
@ -319,7 +316,7 @@ TEST_CASE_FIXTURE(Fixture, "function_arguments_can_be_polytypes")
local y: string = g("hi")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "function_results_can_be_polytypes")
@ -330,7 +327,7 @@ TEST_CASE_FIXTURE(Fixture, "function_results_can_be_polytypes")
return id
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "type_parameters_can_be_polytypes")
@ -339,7 +336,7 @@ TEST_CASE_FIXTURE(Fixture, "type_parameters_can_be_polytypes")
local function id<a>(x:a):a return x end
local f: <a>(a)->a = id(id)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "dont_leak_generic_types")
@ -360,7 +357,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_leak_generic_types")
-- so this assignment should fail
local b: boolean = f(true)
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "dont_leak_inferred_generic_types")
@ -376,7 +373,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_leak_inferred_generic_types")
local y: number = id(37)
end
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "dont_substitute_bound_types")
@ -387,7 +384,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_substitute_bound_types")
local x: T = t.m(37)
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "dont_unify_bound_types")
@ -410,12 +407,12 @@ TEST_CASE_FIXTURE(Fixture, "dont_unify_bound_types")
local a : string = g("not a number", "hi")
local b : number = g(5, 37)
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "mutable_state_polymorphism")
{
// Replaying the classic problem with polymorphism and mutable state in Luau
// Replaying the classic problem with polymorphism and mutable state in lluz
// See, e.g. Tofte (1990)
// https://www.sciencedirect.com/science/article/pii/089054019090018D.
CheckResult result = check(R"(
@ -450,7 +447,7 @@ TEST_CASE_FIXTURE(Fixture, "mutable_state_polymorphism")
-- so b has value "not a number" at run time
local b: number = f(37)
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "rank_N_types_via_typeof")
@ -472,7 +469,7 @@ TEST_CASE_FIXTURE(Fixture, "rank_N_types_via_typeof")
local a: string = f("hi")
local b: number = f(37)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "duplicate_generic_types")
@ -480,7 +477,7 @@ TEST_CASE_FIXTURE(Fixture, "duplicate_generic_types")
CheckResult result = check(R"(
function f<a,a>(x:a):a return x end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "duplicate_generic_type_packs")
@ -488,7 +485,7 @@ TEST_CASE_FIXTURE(Fixture, "duplicate_generic_type_packs")
CheckResult result = check(R"(
function f<a...,a...>() end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "typepacks_before_types")
@ -496,7 +493,7 @@ TEST_CASE_FIXTURE(Fixture, "typepacks_before_types")
CheckResult result = check(R"(
function f<a...,b>() end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "variadic_generics")
@ -507,7 +504,7 @@ TEST_CASE_FIXTURE(Fixture, "variadic_generics")
type F<a> = (...a) -> ...a
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "generic_type_pack_syntax")
@ -516,8 +513,8 @@ TEST_CASE_FIXTURE(Fixture, "generic_type_pack_syntax")
function f<a...>(...: a...): (a...) return ... end
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("f")), "<a...>(a...) -> (a...)");
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType(XorStr("f")), "<a...>(a...) -> (a...)"));
}
TEST_CASE_FIXTURE(Fixture, "generic_type_pack_parentheses")
@ -526,7 +523,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_type_pack_parentheses")
function f<a...>(...: a...): any return (...) end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "better_mismatch_error_messages")
@ -541,15 +538,15 @@ TEST_CASE_FIXTURE(Fixture, "better_mismatch_error_messages")
end
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
SwappedGenericTypeParameter* fErr = get<SwappedGenericTypeParameter>(result.errors[0]);
REQUIRE(fErr);
CHECK_EQ(fErr->name, "T");
CHECK_EQ(fErr->name, XorStr("T"));
CHECK_EQ(fErr->kind, SwappedGenericTypeParameter::Pack);
SwappedGenericTypeParameter* gErr = get<SwappedGenericTypeParameter>(result.errors[1]);
REQUIRE(gErr);
CHECK_EQ(gErr->name, "T");
CHECK_EQ(gErr->name, XorStr("T"));
CHECK_EQ(gErr->kind, SwappedGenericTypeParameter::Type);
}
@ -559,10 +556,10 @@ TEST_CASE_FIXTURE(Fixture, "reject_clashing_generic_and_pack_names")
function f<a, a...>() end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
DuplicateGenericParameter* err = get<DuplicateGenericParameter>(result.errors[0]);
REQUIRE(err != nullptr);
CHECK_EQ(err->parameterName, "a");
CHECK_EQ(err->parameterName, XorStr("a"));
}
TEST_CASE_FIXTURE(Fixture, "instantiation_sharing_types")
@ -581,7 +578,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiation_sharing_types")
local x2, y2, z2 = o2.x, o2.y, o2.z
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK(requireType("x1") != requireType("x2"));
CHECK(requireType("y1") == requireType("y2"));
CHECK(requireType("z1") != requireType("z2"));
@ -596,7 +593,7 @@ TEST_CASE_FIXTURE(Fixture, "quantification_sharing_types")
local z2 = g(true, "hi")
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK(requireType("z1") == requireType("z2"));
}
@ -610,7 +607,7 @@ TEST_CASE_FIXTURE(Fixture, "typefuns_sharing_types")
local x2, y2 = o2.x, o2.y
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK(requireType("x1") != requireType("x2"));
CHECK(requireType("y1") == requireType("y2"));
}
@ -630,7 +627,7 @@ exports.nested = nested
return exports
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "instantiated_function_argument_names")
@ -641,13 +638,13 @@ local function f<T, U...>(a: T, ...: U...) end
f(1, 2, 3)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
auto ty = findTypeAtPosition(Position(3, 0));
REQUIRE(ty);
ToStringOptions opts;
opts.functionTypeArguments = true;
CHECK_EQ(toString(*ty, opts), "(a: number, number, number) -> ()");
CHECK_EQ(toString(*ty, opts), XorStr("(a: number, number, number) -> ()"));
}
TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_generic_types")
@ -660,9 +657,9 @@ local c: C
local d: D = c
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), R"(Type '() -> ()' could not be converted into '<T>() -> ()'; different number of generic type parameters)");
CHECK_EQ(toString(result.errors[0]), RXorStr("(Type '() -> ()' could not be converted into '<T>() -> ()'; different number of generic type parameters)"));
}
TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_generic_pack")
@ -675,16 +672,16 @@ local c: C
local d: D = c
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]),
R"(Type '() -> ()' could not be converted into '<T...>() -> ()'; different number of generic type pack parameters)");
RXorStr("(Type '() -> ()' could not be converted into '<T...>() -> ()'; different number of generic type pack parameters)"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "generic_functions_dont_cache_type_parameters")
{
CheckResult result = check(R"(
-- See https://github.com/Roblox/luau/issues/332
-- See https://github.com/Roblox/lluz/issues/332
-- This function has a type parameter with the same name as clones,
-- so if we cache type parameter names for functions these get confused.
-- function id<Z>(x : Z) : Z
@ -701,7 +698,7 @@ function clone<X, Y>(dict: {[X]:Y}): {[X]:Y}
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "generic_functions_should_be_memory_safe")
@ -717,7 +714,7 @@ local y: T<string> = { a = { c = nil, d = 5 }, b = 37 }
y.a.c = y
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
CHECK_EQ(toString(result.errors[0]),
R"(Type 'y' could not be converted into 'T<string>'
caused by:
@ -741,7 +738,7 @@ local TheDispatcher: Dispatcher = {
}
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "generic_type_pack_unification2")
@ -759,7 +756,7 @@ local TheDispatcher: Dispatcher = {
}
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "generic_type_pack_unification3")
@ -777,7 +774,7 @@ local TheDispatcher: Dispatcher = {
}
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_few")
@ -793,8 +790,8 @@ end
wrapper(test)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), R"(Argument count mismatch. Function expects 2 arguments, but only 1 is specified)");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), RXorStr("(Argument count mismatch. Function expects 2 arguments, but only 1 is specified)"));
}
TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_many")
@ -810,8 +807,8 @@ end
wrapper(test2, 1, "", 3)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), R"(Argument count mismatch. Function expects 3 arguments, but 4 are specified)");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), RXorStr("(Argument count mismatch. Function expects 3 arguments, but 4 are specified)"));
}
TEST_CASE_FIXTURE(Fixture, "generic_function")
@ -822,7 +819,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_function")
local b = id(nil)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("<a>(a) -> a", toString(requireType("id")));
CHECK_EQ(*typeChecker.numberType, *requireType("a"));
@ -839,9 +836,9 @@ TEST_CASE_FIXTURE(Fixture, "generic_table_method")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId tType = requireType("T");
TypeId tType = requireType(XorStr("T"));
TableTypeVar* tTable = getMutable<TableTypeVar>(tType);
REQUIRE(tTable != nullptr);
@ -871,13 +868,13 @@ TEST_CASE_FIXTURE(Fixture, "correctly_instantiate_polymorphic_member_functions")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result);
const TableTypeVar* t = get<TableTypeVar>(requireType("T"));
REQUIRE(t != nullptr);
std::optional<Property> fooProp = get(t->props, "foo");
std::optional<Property> fooProp = get(t->props, XorStr("foo"));
REQUIRE(bool(fooProp));
const FunctionTypeVar* foo = get<FunctionTypeVar>(follow(fooProp->type));
@ -913,7 +910,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_cyclic_generic_function")
end
)");
TypeId g = requireType("g");
TypeId g = requireType(XorStr("g"));
const FunctionTypeVar* gFun = get<FunctionTypeVar>(g);
REQUIRE(gFun != nullptr);
@ -924,7 +921,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_cyclic_generic_function")
const TableTypeVar* argTable = get<TableTypeVar>(arg);
REQUIRE(argTable != nullptr);
std::optional<Property> methodProp = get(argTable->props, "method");
std::optional<Property> methodProp = get(argTable->props, XorStr("method"));
REQUIRE(bool(methodProp));
const FunctionTypeVar* methodFunction = get<FunctionTypeVar>(methodProp->type);
@ -950,7 +947,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_generic_function_in_assignments")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
@ -970,7 +967,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_generic_function_in_assignments2")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
@ -987,8 +984,8 @@ type Self<T> = T
local a: Self<Table>
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "Table");
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType(XorStr("a")), "Table"));
}
TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_quantifying")
@ -1000,14 +997,11 @@ TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_quantifying")
type t0 = t0 | {}
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
std::optional<TypeFun> t0 = getMainModule()->getModuleScope()->lookupType("t0");
std::optional<TypeFun> t0 = getMainModule()->getModuleScope()->lookupType(XorStr("t0"));
REQUIRE(t0);
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(t0->type));
else
CHECK_EQ("<error-type>", toString(t0->type));
CHECK_EQ("*unknown*", toString(t0->type));
auto it = std::find_if(result.errors.begin(), result.errors.end(), [](TypeError& err) {
return get<OccursCheckFailed>(err);
@ -1024,7 +1018,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "infer_generic_function_function_argument")
return sum(2, 3, function(a, b) return a + b end)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
result = check(R"(
local function map<a, b>(arr: {a}, f: (a) -> b)
@ -1038,7 +1032,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "infer_generic_function_function_argument")
local r = map(a, function(a) return a + a > 100 end)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
REQUIRE_EQ("{boolean}", toString(requireType("r")));
check(R"(
@ -1053,7 +1047,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "infer_generic_function_function_argument")
local r = foldl(a, {s=0,c=0}, function(a, b) return {s = a.s + b, c = a.c + 1} end)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
REQUIRE_EQ("{ c: number, s: number }", toString(requireType("r")));
}
@ -1066,7 +1060,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_function_function_argument_overloaded"
g12(1, 2, function(x, y) return x + y end)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
result = check(R"(
local g12: (<T>(T, (T) -> T) -> T) & (<T>(T, T, (T, T) -> T) -> T)
@ -1075,7 +1069,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_function_function_argument_overloaded"
g12({x=1}, {x=2}, function(x, y) return {x=x.x + y.x} end)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "infer_generic_lib_function_function_argument")
@ -1085,7 +1079,7 @@ local a = {{x=4}, {x=7}, {x=1}}
table.sort(a, function(x, y) return x.x < y.x end)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "do_not_infer_generic_functions")
@ -1101,18 +1095,10 @@ local b = sumrec(sum) -- ok
local c = sumrec(function(x, y, f) return f(x, y) end) -- type binders are not inferred
)");
if (FFlag::LuauCheckGenericHOFTypes)
{
LUAU_REQUIRE_NO_ERRORS(result);
}
else
{
LUAU_REQUIRE_ERRORS(result);
CHECK_EQ(
"Type '(a, b, (a, b) -> (c...)) -> (c...)' could not be converted into '<a>(a, a, (a, a) -> a) -> a'; different number of generic type "
"parameters",
toString(result.errors[0]));
}
lluz_REQUIRE_ERRORS(result);
CHECK_EQ("Type '(a, b, (a, b) -> (c...)) -> (c...)' could not be converted into '<a>(a, a, (a, a) -> a) -> a'; different number of generic type "
"parameters",
toString(result.errors[0]));
}
TEST_CASE_FIXTURE(Fixture, "substitution_with_bound_table")
@ -1126,12 +1112,12 @@ TEST_CASE_FIXTURE(Fixture, "substitution_with_bound_table")
local c: X<B>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "apply_type_function_nested_generics1")
{
// https://github.com/Roblox/luau/issues/484
// https://github.com/Roblox/lluz/issues/484
CheckResult result = check(R"(
--!strict
type MyObject = {
@ -1154,12 +1140,12 @@ local complex: ComplexObject<string> = {
}
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "apply_type_function_nested_generics2")
{
// https://github.com/Roblox/luau/issues/484
// https://github.com/Roblox/lluz/issues/484
CheckResult result = check(R"(
--!strict
type MyObject = {
@ -1173,7 +1159,7 @@ type ComplexObject<T> = {
local complex2: ComplexObject<string> = nil
local x = complex2.nested.getReturnValue(function(): string
return ""
return XorStr("")
end)
local y = complex2.nested.getReturnValue(function()
@ -1181,13 +1167,13 @@ local y = complex2.nested.getReturnValue(function()
end)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "quantify_functions_even_if_they_have_an_explicit_generic")
{
ScopedFastFlag sff[] = {
{"LuauAlwaysQuantify", true},
{"lluzAlwaysQuantify", true},
};
CheckResult result = check(R"(
@ -1199,23 +1185,4 @@ TEST_CASE_FIXTURE(Fixture, "quantify_functions_even_if_they_have_an_explicit_gen
CHECK("<X, a...>((X) -> (a...), X) -> (a...)" == toString(requireType("foo")));
}
TEST_CASE_FIXTURE(Fixture, "do_not_always_instantiate_generic_intersection_types")
{
ScopedFastFlag sff[] = {
{"LuauMaybeGenericIntersectionTypes", true},
};
CheckResult result = check(R"(
--!strict
type Array<T> = { [number]: T }
type Array_Statics = {
new: <T>() -> Array<T>,
}
local _Arr : Array<any> & Array_Statics = {} :: Array_Statics
)");
LUAU_REQUIRE_NO_ERRORS(result);
}
TEST_SUITE_END();

View file

@ -1,16 +1,16 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
LUAU_FASTFLAG(LuauLowerBoundsCalculation);
lluz_FASTFLAG(LluLowerBoundsCalculation);
TEST_SUITE_BEGIN("IntersectionTypes");
TEST_SUITE_BEGIN(XorStr("IntersectionTypes"));
TEST_CASE_FIXTURE(Fixture, "select_correct_union_fn")
{
@ -22,7 +22,7 @@ TEST_CASE_FIXTURE(Fixture, "select_correct_union_fn")
local c = f("a") -- c is a number
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(requireType("b"), typeChecker.stringType);
CHECK_EQ(requireType("c"), typeChecker.numberType);
}
@ -35,7 +35,7 @@ TEST_CASE_FIXTURE(Fixture, "table_combines")
local c:A & B = {a=10, b="s"}
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "table_combines_missing")
@ -67,7 +67,7 @@ TEST_CASE_FIXTURE(Fixture, "table_extra_ok")
local d:A = c
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "fx_intersection_as_argument")
@ -81,7 +81,7 @@ TEST_CASE_FIXTURE(Fixture, "fx_intersection_as_argument")
local b = g(f)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "fx_union_as_argument_fails")
@ -108,7 +108,7 @@ TEST_CASE_FIXTURE(Fixture, "argument_is_intersection")
f(true)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "should_still_pick_an_overload_whose_arguments_are_unions")
@ -122,7 +122,7 @@ TEST_CASE_FIXTURE(Fixture, "should_still_pick_an_overload_whose_arguments_are_un
local b1, b2 = f("foo"), f(nil)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*requireType("a1"), *typeChecker.numberType);
CHECK_EQ(*requireType("a2"), *typeChecker.numberType);
@ -161,7 +161,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_an_intersection_type_with_property_guarante
local r = t.x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
const IntersectionTypeVar* r = get<IntersectionTypeVar>(requireType("r"));
REQUIRE(r);
@ -185,7 +185,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_an_intersection_type_works_at_arbitrary_dep
local r = t.x.y.z.thing
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string & string", toString(requireType("r")));
}
@ -199,7 +199,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_an_intersection_type_with_mixed_types")
local r = t.x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number & string", toString(requireType("r"))); // TODO(amccord): This should be an error.
}
@ -213,7 +213,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_an_intersection_type_with_one_part_missing_
local r = t.x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("r")));
}
@ -227,7 +227,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_an_intersection_type_with_one_property_of_t
local r = t.x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.anyType, *requireType("r"));
}
@ -242,11 +242,11 @@ TEST_CASE_FIXTURE(Fixture, "index_on_an_intersection_type_with_all_parts_missing
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
UnknownProperty* up = get<UnknownProperty>(result.errors[0]);
REQUIRE_MESSAGE(up, result.errors[0].data);
CHECK_EQ(up->key, "x");
CHECK_EQ(up->key, XorStr("x"));
}
TEST_CASE_FIXTURE(Fixture, "table_intersection_write")
@ -259,7 +259,7 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write")
a.x = 10
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
result = check(R"(
type X = {}
@ -269,7 +269,7 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write")
a.x = 10
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
result = check(R"(
type X = { x: number }
@ -280,7 +280,7 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write")
a.x = 10
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
result = check(R"(
type A = { x: {y: number} }
@ -291,7 +291,7 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write")
t.x.y = 40
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed")
@ -305,11 +305,11 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed")
a.z = 10
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
if (FFlag::LuauLowerBoundsCalculation)
CHECK_EQ(toString(result.errors[0]), "Cannot add property 'z' to table '{| x: number, y: number |}'");
lluz_REQUIRE_ERROR_COUNT(1, result);
if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ(toString(result.errors[0]), XorStr("Cannot add property 'z' to table '{| x: number, y: number |}'"));
else
CHECK_EQ(toString(result.errors[0]), "Cannot add property 'z' to table 'X & Y'");
CHECK_EQ(toString(result.errors[0]), XorStr("Cannot add property 'z' to table 'X & Y'"));
}
TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed_indirect")
@ -329,20 +329,20 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed_indirect")
function xy:w(a:number) return a * 10 end
)");
LUAU_REQUIRE_ERROR_COUNT(4, result);
lluz_REQUIRE_ERROR_COUNT(4, result);
CHECK_EQ(toString(result.errors[0]), R"(Type '(string, number) -> string' could not be converted into '(string) -> string'
caused by:
Argument count mismatch. Function expects 2 arguments, but only 1 is specified)");
if (FFlag::LuauLowerBoundsCalculation)
CHECK_EQ(toString(result.errors[1]), "Cannot add property 'z' to table '{| x: (number) -> number, y: (string) -> string |}'");
if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ(toString(result.errors[1]), XorStr("Cannot add property 'z' to table '{| x: (number) -> number, y: (string) -> string |}'"));
else
CHECK_EQ(toString(result.errors[1]), "Cannot add property 'z' to table 'X & Y'");
CHECK_EQ(toString(result.errors[2]), "Type 'number' could not be converted into 'string'");
CHECK_EQ(toString(result.errors[1]), XorStr("Cannot add property 'z' to table 'X & Y'"));
CHECK_EQ(toString(result.errors[2]), XorStr("Type 'number' could not be converted into 'string'"));
if (FFlag::LuauLowerBoundsCalculation)
CHECK_EQ(toString(result.errors[3]), "Cannot add property 'w' to table '{| x: (number) -> number, y: (string) -> string |}'");
if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ(toString(result.errors[3]), XorStr("Cannot add property 'w' to table '{| x: (number) -> number, y: (string) -> string |}'"));
else
CHECK_EQ(toString(result.errors[3]), "Cannot add property 'w' to table 'X & Y'");
CHECK_EQ(toString(result.errors[3]), XorStr("Cannot add property 'w' to table 'X & Y'"));
}
TEST_CASE_FIXTURE(Fixture, "table_write_sealed_indirect")
@ -360,13 +360,13 @@ TEST_CASE_FIXTURE(Fixture, "table_write_sealed_indirect")
function xy:w(a:number) return a * 10 end
)");
LUAU_REQUIRE_ERROR_COUNT(4, result);
lluz_REQUIRE_ERROR_COUNT(4, result);
CHECK_EQ(toString(result.errors[0]), R"(Type '(string, number) -> string' could not be converted into '(string) -> string'
caused by:
Argument count mismatch. Function expects 2 arguments, but only 1 is specified)");
CHECK_EQ(toString(result.errors[1]), "Cannot add property 'z' to table 'XY'");
CHECK_EQ(toString(result.errors[2]), "Type 'number' could not be converted into 'string'");
CHECK_EQ(toString(result.errors[3]), "Cannot add property 'w' to table 'XY'");
CHECK_EQ(toString(result.errors[1]), XorStr("Cannot add property 'z' to table 'XY'"));
CHECK_EQ(toString(result.errors[2]), XorStr("Type 'number' could not be converted into 'string'"));
CHECK_EQ(toString(result.errors[3]), XorStr("Cannot add property 'w' to table 'XY'"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "table_intersection_setmetatable")
@ -376,12 +376,12 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_intersection_setmetatable")
setmetatable(t, {})
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "error_detailed_intersection_part")
{
ScopedFastFlag flags[] = {{"LuauLowerBoundsCalculation", false}};
ScopedFastFlag flags[] = {{"lluzLowerBoundsCalculation", false}};
CheckResult result = check(R"(
type X = { x: number }
@ -393,7 +393,7 @@ type XYZ = X & Y & Z
local a: XYZ = 3
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), R"(Type 'number' could not be converted into 'X & Y & Z'
caused by:
Not all intersection parts are compatible. Type 'number' could not be converted into 'X')");
@ -401,7 +401,7 @@ caused by:
TEST_CASE_FIXTURE(Fixture, "error_detailed_intersection_all")
{
ScopedFastFlag flags[] = {{"LuauLowerBoundsCalculation", false}};
ScopedFastFlag flags[] = {{"lluzLowerBoundsCalculation", false}};
CheckResult result = check(R"(
type X = { x: number }
@ -414,8 +414,8 @@ local a: XYZ
local b: number = a
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), R"(Type 'X & Y & Z' could not be converted into 'number'; none of the intersection parts are compatible)");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), RXorStr("(Type 'X & Y & Z' could not be converted into 'number'; none of the intersection parts are compatible)"));
}
TEST_CASE_FIXTURE(Fixture, "overload_is_not_a_function")
@ -443,7 +443,7 @@ TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_flattenintersection")
until _(_)(_)._
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_SUITE_END();

View file

@ -1,21 +1,19 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/AstQuery.h"
#include "Luau/BuiltinDefinitions.h"
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/VisitTypeVar.h"
#include "lluz/AstQuery.h"
#include "lluz/BuiltinDefinitions.h"
#include "lluz/Scope.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "lluz/VisitTypeVar.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
TEST_SUITE_BEGIN("TypeInferLoops");
TEST_SUITE_BEGIN(XorStr("TypeInferLoops"));
TEST_CASE_FIXTURE(Fixture, "for_loop")
{
@ -26,7 +24,7 @@ TEST_CASE_FIXTURE(Fixture, "for_loop")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("q"));
}
@ -42,7 +40,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("n"));
CHECK_EQ(*typeChecker.stringType, *requireType("s"));
@ -59,7 +57,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_next")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("n"));
CHECK_EQ(*typeChecker.stringType, *requireType("s"));
@ -75,7 +73,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_with_an_iterator_of_type_any")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "for_in_loop_should_fail_with_non_function_iterator")
@ -86,7 +84,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_should_fail_with_non_function_iterator")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Cannot call non-function string", toString(result.errors[0]));
}
@ -106,7 +104,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_with_just_one_iterator_is_ok")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_with_a_custom_iterator_should_type_check")
@ -123,7 +121,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_with_a_custom_iterator_should_type_ch
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_error")
@ -143,11 +141,8 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_error")
CHECK_EQ(2, result.errors.size());
TypeId p = requireType("p");
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(p));
else
CHECK_EQ("<error-type>", toString(p));
TypeId p = requireType(XorStr("p"));
CHECK_EQ("*unknown*", toString(p));
}
TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_non_function")
@ -159,7 +154,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_non_function")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<CannotCallNonFunction>(result.errors[0]));
}
@ -199,7 +194,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_factory_not_returning_t
for p in primes3() do print(p) end -- no error
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
CountMismatch* acm = get<CountMismatch>(result.errors[0]);
REQUIRE(acm);
@ -223,7 +218,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_iterator_requiring_args
for p in prime_iter do print(p) end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CountMismatch* acm = get<CountMismatch>(result.errors[0]);
REQUIRE(acm);
@ -244,7 +239,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_with_custom_iterator")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
@ -261,7 +256,7 @@ TEST_CASE_FIXTURE(Fixture, "while_loop")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("i"));
}
@ -275,7 +270,7 @@ TEST_CASE_FIXTURE(Fixture, "repeat_loop")
until true
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.stringType, *requireType("i"));
}
@ -288,7 +283,7 @@ TEST_CASE_FIXTURE(Fixture, "repeat_loop_condition_binds_to_its_block")
until x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "symbols_in_repeat_block_should_not_be_visible_beyond_until_condition")
@ -301,7 +296,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "symbols_in_repeat_block_should_not_be_visibl
print(x)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "varlist_declared_by_for_in_loop_should_be_free")
@ -316,7 +311,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "varlist_declared_by_for_in_loop_should_be_fr
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "properly_infer_iteratee_is_a_free_table")
@ -329,7 +324,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "properly_infer_iteratee_is_a_free_table")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "correctly_scope_locals_while")
@ -342,11 +337,11 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "correctly_scope_locals_while")
print(a) -- oops!
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
UnknownSymbol* us = get<UnknownSymbol>(result.errors[0]);
REQUIRE(us);
CHECK_EQ(us->name, "a");
CHECK_EQ(us->name, XorStr("a"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "ipairs_produces_integral_indices")
@ -356,7 +351,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "ipairs_produces_integral_indices")
for i, e in ipairs({}) do key = i end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
REQUIRE_EQ("number", toString(requireType("key")));
}
@ -394,7 +389,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unreachable_code_after_infinite_loop")
unreachablecodepath(4)
)");
LUAU_REQUIRE_ERROR_COUNT(0, result);
lluz_REQUIRE_ERROR_COUNT(0, result);
}
{
@ -410,7 +405,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unreachable_code_after_infinite_loop")
reachablecodepath(4)
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
CHECK(get<FunctionExitsWithoutReturning>(result.errors[0]));
}
@ -426,7 +421,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unreachable_code_after_infinite_loop")
unreachablecodepath(4)
)");
LUAU_REQUIRE_ERROR_COUNT(0, result);
lluz_REQUIRE_ERROR_COUNT(0, result);
}
{
@ -443,7 +438,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unreachable_code_after_infinite_loop")
reachablecodepath(4)
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
CHECK(get<FunctionExitsWithoutReturning>(result.errors[0]));
}
@ -459,7 +454,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unreachable_code_after_infinite_loop")
unreachablecodepath(4)
)");
LUAU_REQUIRE_ERROR_COUNT(0, result);
lluz_REQUIRE_ERROR_COUNT(0, result);
}
}
@ -473,7 +468,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "loop_typecheck_crash_on_empty_optional")
end
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
}
TEST_CASE_FIXTURE(Fixture, "fuzz_fail_missing_instantitation_follow")
@ -503,7 +498,7 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_basic")
end
)");
LUAU_REQUIRE_ERROR_COUNT(0, result);
lluz_REQUIRE_ERROR_COUNT(0, result);
CHECK_EQ(*typeChecker.numberType, *requireType("key"));
}
@ -517,11 +512,11 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_trailing_nil")
end
)");
LUAU_REQUIRE_ERROR_COUNT(0, result);
lluz_REQUIRE_ERROR_COUNT(0, result);
CHECK_EQ(*typeChecker.nilType, *requireType("extra"));
}
TEST_CASE_FIXTURE(Fixture, "loop_iter_no_indexer_strict")
TEST_CASE_FIXTURE(Fixture, "loop_iter_no_indexer")
{
CheckResult result = check(R"(
local t = {}
@ -529,24 +524,13 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_no_indexer_strict")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
GenericError* ge = get<GenericError>(result.errors[0]);
REQUIRE(ge);
CHECK_EQ("Cannot iterate over a table without indexer", ge->message);
}
TEST_CASE_FIXTURE(Fixture, "loop_iter_no_indexer_nonstrict")
{
CheckResult result = check(Mode::Nonstrict, R"(
local t = {}
for k, v in t do
end
)");
LUAU_REQUIRE_ERROR_COUNT(0, result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_iter_metamethod")
{
CheckResult result = check(R"(
@ -556,7 +540,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_iter_metamethod")
end
)");
LUAU_REQUIRE_ERROR_COUNT(0, result);
lluz_REQUIRE_ERROR_COUNT(0, result);
}
TEST_SUITE_END();

View file

@ -1,26 +1,24 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/AstQuery.h"
#include "Luau/BuiltinDefinitions.h"
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "lluz/AstQuery.h"
#include "lluz/BuiltinDefinitions.h"
#include "lluz/Scope.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
TEST_SUITE_BEGIN("TypeInferModules");
TEST_SUITE_BEGIN(XorStr("TypeInferModules"));
TEST_CASE_FIXTURE(BuiltinsFixture, "require")
{
fileResolver.source["game/A"] = R"(
local function hooty(x: number): string
return "Hi there!"
return XorStr("Hi there!")
end
return {hooty=hooty}
@ -33,13 +31,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require")
local i = Hooty.hooty(h)
)";
CheckResult aResult = frontend.check("game/A");
CheckResult aResult = frontend.check(XorStr("game/A"));
dumpErrors(aResult);
LUAU_REQUIRE_NO_ERRORS(aResult);
lluz_REQUIRE_NO_ERRORS(aResult);
CheckResult bResult = frontend.check("game/B");
CheckResult bResult = frontend.check(XorStr("game/B"));
dumpErrors(bResult);
LUAU_REQUIRE_NO_ERRORS(bResult);
lluz_REQUIRE_NO_ERRORS(bResult);
ModulePtr b = frontend.moduleResolver.modules["game/B"];
@ -47,10 +45,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require")
dumpErrors(bResult);
std::optional<TypeId> iType = requireType(b, "i");
std::optional<TypeId> iType = requireType(b, XorStr("i"));
REQUIRE_EQ("string", toString(*iType));
std::optional<TypeId> hType = requireType(b, "h");
std::optional<TypeId> hType = requireType(b, XorStr("h"));
REQUIRE_EQ("number", toString(*hType));
}
@ -68,13 +66,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require_types")
local h: Hooty.Point
)";
CheckResult bResult = frontend.check("workspace/B");
LUAU_REQUIRE_NO_ERRORS(bResult);
CheckResult bResult = frontend.check(XorStr("workspace/B"));
lluz_REQUIRE_NO_ERRORS(bResult);
ModulePtr b = frontend.moduleResolver.modules["workspace/B"];
REQUIRE(b != nullptr);
TypeId hType = requireType(b, "h");
TypeId hType = requireType(b, XorStr("h"));
REQUIRE_MESSAGE(bool(get<TableTypeVar>(hType)), "Expected table but got " << toString(hType));
}
@ -91,9 +89,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require_a_variadic_function")
local f = A.f
)";
CheckResult result = frontend.check("game/B");
CheckResult result = frontend.check(XorStr("game/B"));
ModulePtr bModule = frontend.moduleResolver.getModule("game/B");
ModulePtr bModule = frontend.moduleResolver.getModule(XorStr("game/B"));
REQUIRE(bModule != nullptr);
TypeId f = follow(requireType(bModule, "f"));
@ -116,7 +114,7 @@ TEST_CASE_FIXTURE(Fixture, "type_error_of_unknown_qualified_type")
local p: SomeModule.DoesNotExist
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE_EQ(result.errors[0], (TypeError{Location{{1, 17}, {1, 40}}, UnknownSymbol{"SomeModule.DoesNotExist"}}));
}
@ -133,8 +131,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require_module_that_does_not_export")
fileResolver.source["game/Workspace/A"] = sourceA;
fileResolver.source["game/Workspace/B"] = sourceB;
frontend.check("game/Workspace/A");
frontend.check("game/Workspace/B");
frontend.check(XorStr("game/Workspace/A"));
frontend.check(XorStr("game/Workspace/B"));
ModulePtr aModule = frontend.moduleResolver.modules["game/Workspace/A"];
ModulePtr bModule = frontend.moduleResolver.modules["game/Workspace/B"];
@ -143,12 +141,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require_module_that_does_not_export")
REQUIRE_EQ(1, bModule->errors.size());
CHECK_MESSAGE(get<IllegalRequire>(bModule->errors[0]), "Should be IllegalRequire: " << toString(bModule->errors[0]));
auto hootyType = requireType(bModule, "Hooty");
auto hootyType = requireType(bModule, XorStr("Hooty"));
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(hootyType));
else
CHECK_EQ("<error-type>", toString(hootyType));
CHECK_EQ("*unknown*", toString(hootyType));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "warn_if_you_try_to_require_a_non_modulescript")
@ -160,9 +155,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "warn_if_you_try_to_require_a_non_modulescrip
local M = require(script.Parent.A)
)";
CheckResult result = frontend.check("Modules/B");
CheckResult result = frontend.check(XorStr("Modules/B"));
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK(get<IllegalRequire>(result.errors[0]));
}
@ -181,8 +176,8 @@ local a : string = ""
a = tbl.abc.def
)";
CheckResult result = frontend.check("game/B");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CheckResult result = frontend.check(XorStr("game/B"));
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type 'number' could not be converted into 'string'", toString(result.errors[0]));
}
@ -196,8 +191,8 @@ return { def = 4 }
local tbl: string = require(game.A)
)";
CheckResult result = frontend.check("game/B");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CheckResult result = frontend.check(XorStr("game/B"));
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type '{| def: number |}' could not be converted into 'string'", toString(result.errors[0]));
}
@ -219,7 +214,7 @@ end
return m
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "custom_require_global")
@ -231,7 +226,7 @@ require = function(a) end
local crash = require(game.A)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "require_failed_module")
@ -240,20 +235,16 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require_failed_module")
return unfortunately()
)";
CheckResult aResult = frontend.check("game/A");
LUAU_REQUIRE_ERRORS(aResult);
CheckResult aResult = frontend.check(XorStr("game/A"));
lluz_REQUIRE_ERRORS(aResult);
CheckResult result = check(R"(
local ModuleA = require(game.A)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
std::optional<TypeId> oty = requireType("ModuleA");
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(*oty));
else
CHECK_EQ("<error-type>", toString(*oty));
std::optional<TypeId> oty = requireType(XorStr("ModuleA"));
CHECK_EQ("*unknown*", toString(*oty));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types")
@ -270,8 +261,8 @@ local x: Type = {}
function x:Destroy(): () end
)";
CheckResult result = frontend.check("game/B");
LUAU_REQUIRE_ERROR_COUNT(2, result);
CheckResult result = frontend.check(XorStr("game/B"));
lluz_REQUIRE_ERROR_COUNT(2, result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types_2")
@ -288,8 +279,8 @@ local x: Type = { x = { a = 2 } }
type Rename = typeof(x.x)
)";
CheckResult result = frontend.check("game/B");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = frontend.check(XorStr("game/B"));
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types_3")
@ -307,32 +298,8 @@ local x: Type = types
type Rename = typeof(x.x)
)";
CheckResult result = frontend.check("game/B");
LUAU_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types_4")
{
fileResolver.source["game/A"] = R"(
export type Array<T> = {T}
local arrayops = {}
function arrayops.foo(x: Array<any>) end
return arrayops
)";
CheckResult result = check(R"(
local arrayops = require(game.A)
local tbl = {}
tbl.a = 2
function tbl:foo(b: number, c: number)
-- introduce BoundTypeVar to imported type
arrayops.foo(self._regions)
end
type Table = typeof(tbl)
)");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = frontend.check(XorStr("game/B"));
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "module_type_conflict")
@ -354,8 +321,8 @@ local a: A.T = { x = 2 }
local b: B.T = a
)";
CheckResult result = frontend.check("game/C");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CheckResult result = frontend.check(XorStr("game/C"));
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), R"(Type 'T' from 'game/A' could not be converted into 'T' from 'game/B'
caused by:
@ -388,29 +355,12 @@ local a: A.T = { x = 2 }
local b: B.T = a
)";
CheckResult result = frontend.check("game/D");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CheckResult result = frontend.check(XorStr("game/D"));
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), R"(Type 'T' from 'game/B' could not be converted into 'T' from 'game/C'
caused by:
Property 'x' is not compatible. Type 'number' could not be converted into 'string')");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "constrained_anyification_clone_immutable_types")
{
ScopedFastFlag luauAnyificationMustClone{"LuauAnyificationMustClone", true};
fileResolver.source["game/A"] = R"(
return function(...) end
)";
fileResolver.source["game/B"] = R"(
local l0 = require(game.A)
return l0
)";
CheckResult result = frontend.check("game/B");
LUAU_REQUIRE_NO_ERRORS(result);
}
TEST_SUITE_END();

View file

@ -1,19 +1,19 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/AstQuery.h"
#include "Luau/BuiltinDefinitions.h"
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/VisitTypeVar.h"
#include "lluz/AstQuery.h"
#include "lluz/BuiltinDefinitions.h"
#include "lluz/Scope.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "lluz/VisitTypeVar.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("TypeInferOOP");
TEST_SUITE_BEGIN(XorStr("TypeInferOOP"));
TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_not_defined_with_colon")
{
@ -26,7 +26,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_not_defi
someTable.Function1() -- Argument count mismatch
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<CountMismatch>(result.errors[0]));
}
@ -42,7 +42,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_it_wont_
someTable.Function2() -- Argument count mismatch
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<CountMismatch>(result.errors[0]));
}
@ -56,7 +56,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_another_
T.method(4)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "method_depends_on_table")
@ -71,7 +71,7 @@ TEST_CASE_FIXTURE(Fixture, "method_depends_on_table")
function f() x:m() end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "methods_are_topologically_sorted")
@ -90,7 +90,7 @@ TEST_CASE_FIXTURE(Fixture, "methods_are_topologically_sorted")
local a, b = T:foo()
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result);
CHECK_EQ(PrimitiveTypeVar::Number, getPrimitiveType(requireType("a")));
@ -181,7 +181,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "object_constructor_can_refer_to_method_of_se
-- foo.fooConn()
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "CheckMethodsOfSealed")
@ -193,7 +193,7 @@ function x:y(z: number)
end
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
}
TEST_CASE_FIXTURE(Fixture, "nonstrict_self_mismatch_tail")
@ -209,7 +209,7 @@ TEST_CASE_FIXTURE(Fixture, "nonstrict_self_mismatch_tail")
bar(2)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "inferred_methods_of_free_tables_have_the_same_level_as_the_enclosing_table")
@ -265,11 +265,11 @@ function test()
local n = c:getx()
local nn = c.x
print(string.format("%d %d", n, nn))
print(string.format(XorStr("%d %d"), n, nn))
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_SUITE_END();

View file

@ -1,19 +1,19 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/AstQuery.h"
#include "Luau/BuiltinDefinitions.h"
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/VisitTypeVar.h"
#include "lluz/AstQuery.h"
#include "lluz/BuiltinDefinitions.h"
#include "lluz/Scope.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "lluz/VisitTypeVar.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("TypeInferOperators");
TEST_SUITE_BEGIN(XorStr("TypeInferOperators"));
TEST_CASE_FIXTURE(Fixture, "or_joins_types")
{
@ -21,9 +21,9 @@ TEST_CASE_FIXTURE(Fixture, "or_joins_types")
local s = "a" or 10
local x:string|number = s
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(*requireType("s")), "number | string");
CHECK_EQ(toString(*requireType("x")), "number | string");
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(*requireType(XorStr("s")), "number | string"));
CHECK_EQ(toString(*requireType(XorStr("x")), "number | string"));
}
TEST_CASE_FIXTURE(Fixture, "or_joins_types_with_no_extras")
@ -34,8 +34,8 @@ TEST_CASE_FIXTURE(Fixture, "or_joins_types_with_no_extras")
local y = x or "s"
)");
CHECK_EQ(0, result.errors.size());
CHECK_EQ(toString(*requireType("s")), "number | string");
CHECK_EQ(toString(*requireType("y")), "number | string");
CHECK_EQ(toString(*requireType(XorStr("s")), "number | string"));
CHECK_EQ(toString(*requireType(XorStr("y")), "number | string"));
}
TEST_CASE_FIXTURE(Fixture, "or_joins_types_with_no_superfluous_union")
@ -55,7 +55,7 @@ TEST_CASE_FIXTURE(Fixture, "and_adds_boolean")
local x:boolean|number = s
)");
CHECK_EQ(0, result.errors.size());
CHECK_EQ(toString(*requireType("s")), "boolean | number");
CHECK_EQ(toString(*requireType(XorStr("s")), "boolean | number"));
}
TEST_CASE_FIXTURE(Fixture, "and_adds_boolean_no_superfluous_union")
@ -74,7 +74,7 @@ TEST_CASE_FIXTURE(Fixture, "and_or_ternary")
local s = (1/2) > 0.5 and "a" or 10
)");
CHECK_EQ(0, result.errors.size());
CHECK_EQ(toString(*requireType("s")), "number | string");
CHECK_EQ(toString(*requireType(XorStr("s")), "number | string"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "primitive_arith_no_metatable")
@ -86,7 +86,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "primitive_arith_no_metatable")
local n, s = add(2,"3")
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* functionType = get<FunctionTypeVar>(requireType("add"));
@ -104,7 +104,7 @@ TEST_CASE_FIXTURE(Fixture, "primitive_arith_no_metatable_with_follows")
local SOLAR_MASS=4*PI * PI
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(requireType("SOLAR_MASS"), typeChecker.numberType);
}
@ -117,7 +117,7 @@ TEST_CASE_FIXTURE(Fixture, "primitive_arith_possible_metatable")
local t = add(1,2)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("t")));
}
@ -131,7 +131,7 @@ TEST_CASE_FIXTURE(Fixture, "some_primitive_binary_ops")
local c = b - a
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("a")));
CHECK_EQ("number", toString(requireType("b")));
@ -165,7 +165,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_overloaded_multiply_that_is_an_int
local e = a * 'cabbage'
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Vec3", toString(requireType("a")));
CHECK_EQ("Vec3", toString(requireType("b")));
@ -199,7 +199,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_overloaded_multiply_that_is_an_int
local e = 'cabbage' * a
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Vec3", toString(requireType("a")));
CHECK_EQ("Vec3", toString(requireType("b")));
@ -216,7 +216,7 @@ TEST_CASE_FIXTURE(Fixture, "compare_numbers")
local c = a < b
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "compare_strings")
@ -227,7 +227,7 @@ TEST_CASE_FIXTURE(Fixture, "compare_strings")
local c = a < b
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "cannot_indirectly_compare_types_that_do_not_have_a_metatable")
@ -238,11 +238,11 @@ TEST_CASE_FIXTURE(Fixture, "cannot_indirectly_compare_types_that_do_not_have_a_m
local c = a < b
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
GenericError* gen = get<GenericError>(result.errors[0]);
REQUIRE_EQ(gen->message, "Type a cannot be compared with < because it has no metatable");
REQUIRE_EQ(gen->message, XorStr("Type a cannot be compared with < because it has no metatable"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_indirectly_compare_types_that_do_not_offer_overloaded_ordering_operators")
@ -259,11 +259,11 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_indirectly_compare_types_that_do_not_
local c = a < b
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
GenericError* gen = get<GenericError>(result.errors[0]);
REQUIRE(gen != nullptr);
REQUIRE_EQ(gen->message, "Table M does not offer metamethod __lt");
REQUIRE_EQ(gen->message, XorStr("Table M does not offer metamethod __lt"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_compare_tables_that_do_not_have_the_same_metatable")
@ -282,7 +282,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_compare_tables_that_do_not_have_the_s
local d = b < a -- line 11
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
REQUIRE_EQ((Location{{10, 18}, {10, 23}}), result.errors[0].location);
@ -305,7 +305,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "produce_the_correct_error_message_when_compa
local c = a < b -- line 10
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
auto err = get<GenericError>(result.errors[0]);
REQUIRE(err != nullptr);
@ -326,7 +326,7 @@ TEST_CASE_FIXTURE(Fixture, "in_nonstrict_mode_strip_nil_from_intersections_when_
local a = maybe_a_number() < maybe_a_number()
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "compound_assign_basic")
@ -336,7 +336,7 @@ TEST_CASE_FIXTURE(Fixture, "compound_assign_basic")
s += 20
)");
CHECK_EQ(0, result.errors.size());
CHECK_EQ(toString(*requireType("s")), "number");
CHECK_EQ(toString(*requireType(XorStr("s")), "number"));
}
TEST_CASE_FIXTURE(Fixture, "compound_assign_mismatch_op")
@ -345,7 +345,7 @@ TEST_CASE_FIXTURE(Fixture, "compound_assign_mismatch_op")
local s = 10
s += true
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(result.errors[0], (TypeError{Location{{2, 13}, {2, 17}}, TypeMismatch{typeChecker.numberType, typeChecker.booleanType}}));
}
@ -356,7 +356,7 @@ TEST_CASE_FIXTURE(Fixture, "compound_assign_mismatch_result")
s += 10
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(result.errors[0], (TypeError{Location{{2, 8}, {2, 9}}, TypeMismatch{typeChecker.numberType, typeChecker.stringType}}));
CHECK_EQ(result.errors[1], (TypeError{Location{{2, 8}, {2, 15}}, TypeMismatch{typeChecker.stringType, typeChecker.numberType}}));
}
@ -398,7 +398,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "compound_assign_mismatch_metatable")
local v2: V2 = setmetatable({ x = 3, y = 4 }, VMT)
v1 %= v2
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
CHECK_EQ(*tm->wantedType, *requireType("v2"));
@ -413,7 +413,7 @@ function g() return 2; end
(f or g)()
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "CallAndOrOfFunctions")
@ -425,7 +425,7 @@ local x = false
(x and f or g)()
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus")
@ -452,13 +452,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus")
local c = -bar -- disallowed
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("string", toString(requireType("a")));
CHECK_EQ("number", toString(requireType("b")));
GenericError* gen = get<GenericError>(result.errors[0]);
REQUIRE_EQ(gen->message, "Unary operator '-' not supported by type 'bar'");
REQUIRE_EQ(gen->message, XorStr("Unary operator '-' not supported by type 'bar'"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus_error")
@ -473,13 +473,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus_error")
setmetatable(foo, mt)
mt.__unm = function(val: boolean): string
return "test"
return XorStr("test")
end
local a = -foo
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("string", toString(requireType("a")));
@ -490,6 +490,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus_error")
TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_len_error")
{
ScopedFastFlag sff("lluzCheckLenMT", true);
CheckResult result = check(R"(
--!strict
local foo = {
@ -499,13 +501,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_len_error")
setmetatable(foo, mt)
mt.__len = function(val: any): string
return "test"
return XorStr("test")
end
local a = #foo
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("number", toString(requireType("a")));
@ -521,7 +523,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unary_not_is_boolean")
local c = not (math.random() > 0.5 and "string" or 7)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
REQUIRE_EQ("boolean", toString(requireType("b")));
REQUIRE_EQ("boolean", toString(requireType("c")));
}
@ -555,7 +557,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "disallow_string_and_types_without_metatables
local d = bar + foo -- not allowed
)");
LUAU_REQUIRE_ERROR_COUNT(3, result);
lluz_REQUIRE_ERROR_COUNT(3, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE_EQ(*tm->wantedType, *typeChecker.numberType);
@ -566,7 +568,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "disallow_string_and_types_without_metatables
CHECK_EQ(*tm2->givenType, *requireType("foo"));
GenericError* gen2 = get<GenericError>(result.errors[1]);
REQUIRE_EQ(gen2->message, "Binary operator '+' not supported by types 'foo' and 'number'");
REQUIRE_EQ(gen2->message, XorStr("Binary operator '+' not supported by types 'foo' and 'number'"));
}
// CLI-29033
@ -579,7 +581,7 @@ TEST_CASE_FIXTURE(Fixture, "unknown_type_in_comparison")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "concat_op_on_free_lhs_and_string_rhs")
@ -590,7 +592,7 @@ TEST_CASE_FIXTURE(Fixture, "concat_op_on_free_lhs_and_string_rhs")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<CannotInferBinaryOperation>(result.errors[0]));
}
@ -598,11 +600,11 @@ TEST_CASE_FIXTURE(Fixture, "concat_op_on_string_lhs_and_free_rhs")
{
CheckResult result = check(R"(
local function f(x)
return "foo" .. x
return XorStr("foo") .. x
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("(string) -> string", toString(requireType("f")));
}
@ -621,7 +623,7 @@ TEST_CASE_FIXTURE(Fixture, "strict_binary_op_where_lhs_unknown")
src += "end";
CheckResult result = check(src);
LUAU_REQUIRE_ERROR_COUNT(ops.size(), result);
lluz_REQUIRE_ERROR_COUNT(ops.size(), result);
CHECK_EQ("Unknown type used in + operation; consider adding a type annotation to 'a'", toString(result.errors[0]));
}
@ -636,7 +638,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "and_binexps_dont_unify")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operators")
@ -647,7 +649,7 @@ TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operato
local foo = a < b
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
GenericError* ge = get<GenericError>(result.errors[0]);
REQUIRE(ge);
@ -662,7 +664,7 @@ TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operato
local foo = a < b
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
GenericError* ge = get<GenericError>(result.errors[0]);
REQUIRE(ge);
@ -677,7 +679,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_38355_recursive_union")
_ += _ and _ or _ and _ or _ and _
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type contains a self-recursive construct that cannot be resolved", toString(result.errors[0]));
}
@ -691,8 +693,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "UnknownGlobalCompoundAssign")
print(a)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Unknown global 'a'");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Unknown global 'a'"));
}
// In strict mode we no longer generate two errors from lhs
@ -703,8 +705,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "UnknownGlobalCompoundAssign")
print(a)
)");
LUAU_REQUIRE_ERRORS(result);
CHECK_EQ(toString(result.errors[0]), "Unknown global 'a'");
lluz_REQUIRE_ERRORS(result);
CHECK_EQ(toString(result.errors[0]), XorStr("Unknown global 'a'"));
}
// In non-strict mode, compound assignment is not a definition, it's a modification
@ -715,8 +717,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "UnknownGlobalCompoundAssign")
print(a)
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(toString(result.errors[0]), "Unknown global 'a'");
lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Unknown global 'a'"));
}
}
@ -728,7 +730,7 @@ local a: number? = nil
local b: number = a or 1
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "strip_nil_from_lhs_or_operator2")
@ -739,7 +741,7 @@ local a: number? = nil
local b: number = a or 1
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "dont_strip_nil_from_rhs_or_operator")
@ -750,7 +752,7 @@ local a: number? = nil
local b: number = 1 or a
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
@ -776,7 +778,7 @@ TEST_CASE_FIXTURE(Fixture, "operator_eq_verifies_types_do_intersect")
return f
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "operator_eq_operands_are_not_subtypes_of_each_other_but_has_overlap")
@ -789,7 +791,7 @@ TEST_CASE_FIXTURE(Fixture, "operator_eq_operands_are_not_subtypes_of_each_other_
// This doesn't produce any errors but for the wrong reasons.
// This unit test serves as a reminder to not try and unify the operands on `==`/`~=`.
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "refine_and_or")
@ -799,7 +801,7 @@ TEST_CASE_FIXTURE(Fixture, "refine_and_or")
local u = t and t.x or 5
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("u")));
}
@ -812,8 +814,8 @@ TEST_CASE_FIXTURE(Fixture, "infer_any_in_all_modes_when_lhs_is_unknown")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Unknown type used in + operation; consider adding a type annotation to 'x'");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Unknown type used in + operation; consider adding a type annotation to 'x'"));
result = check(Mode::Nonstrict, R"(
local function f(x, y)
@ -821,7 +823,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_any_in_all_modes_when_lhs_is_unknown")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
// When type inference is unified, we could add an assertion that
// the strict and nonstrict types are equivalent. This isn't actually
@ -842,7 +844,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "equality_operations_succeed_if_any_union_bra
local v4 = y ~= x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CheckResult result2 = check(R"(
local mm1 = {
@ -865,30 +867,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "equality_operations_succeed_if_any_union_bra
local v2 = x2 == y2
)");
LUAU_REQUIRE_ERROR_COUNT(1, result2);
CHECK(toString(result2.errors[0]) == "Types Foo and Bar cannot be compared with == because they do not have the same metatable");
}
TEST_CASE_FIXTURE(BuiltinsFixture, "expected_types_through_binary_and")
{
ScopedFastFlag sff{"LuauBinaryNeedsExpectedTypesToo", true};
CheckResult result = check(R"(
local x: "a" | "b" | boolean = math.random() > 0.5 and "a"
)");
LUAU_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "expected_types_through_binary_or")
{
ScopedFastFlag sff{"LuauBinaryNeedsExpectedTypesToo", true};
CheckResult result = check(R"(
local x: "a" | "b" | boolean = math.random() > 0.5 or "b"
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_ERROR_COUNT(1, result2);
CHECK(toString(result2.errors[0]) == XorStr("Types Foo and Bar cannot be compared with == because they do not have the same metatable"));
}
TEST_SUITE_END();

View file

@ -1,27 +1,24 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/AstQuery.h"
#include "Luau/BuiltinDefinitions.h"
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/VisitTypeVar.h"
#include "lluz/AstQuery.h"
#include "lluz/BuiltinDefinitions.h"
#include "lluz/Scope.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "lluz/VisitTypeVar.h"
#include "Fixture.h"
#include "doctest.h"
LUAU_FASTFLAG(LuauDeduceFindMatchReturnTypes)
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
using namespace lluz;
using namespace Luau;
TEST_SUITE_BEGIN("TypeInferPrimitives");
TEST_SUITE_BEGIN(XorStr("TypeInferPrimitives"));
TEST_CASE_FIXTURE(Fixture, "cannot_call_primitives")
{
CheckResult result = check("local foo = 5 foo()");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CheckResult result = check(XorStr("local foo = 5 foo()"));
lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<CannotCallNonFunction>(result.errors[0]) != nullptr);
}
@ -33,7 +30,7 @@ TEST_CASE_FIXTURE(Fixture, "string_length")
local t = #s
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("t")));
}
@ -44,16 +41,13 @@ TEST_CASE_FIXTURE(Fixture, "string_index")
local t = s[4]
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
NotATable* nat = get<NotATable>(result.errors[0]);
REQUIRE(nat);
CHECK_EQ("string", toString(nat->ty));
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(requireType("t")));
else
CHECK_EQ("<error-type>", toString(requireType("t")));
CHECK_EQ("*unknown*", toString(requireType("t")));
}
TEST_CASE_FIXTURE(Fixture, "string_method")
@ -86,10 +80,7 @@ TEST_CASE_FIXTURE(Fixture, "string_function_other")
)");
CHECK_EQ(0, result.errors.size());
if (FFlag::LuauDeduceFindMatchReturnTypes)
CHECK_EQ(toString(requireType("p")), "string");
else
CHECK_EQ(toString(requireType("p")), "string?");
CHECK_EQ(toString(requireType(XorStr("p")), "string?"));
}
TEST_CASE_FIXTURE(Fixture, "CheckMethodsOfNumber")
@ -101,9 +92,9 @@ function x:y(z: number)
end
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(toString(result.errors[0]), "Cannot add method to non-table type 'number'");
CHECK_EQ(toString(result.errors[1]), "Type 'number' could not be converted into 'string'");
lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Cannot add method to non-table type 'number'"));
CHECK_EQ(toString(result.errors[1]), XorStr("Type 'number' could not be converted into 'string'"));
}
TEST_SUITE_END();

View file

@ -1,5 +1,5 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/TypeInfer.h"
#include "Fixture.h"
@ -7,11 +7,11 @@
#include <algorithm>
LUAU_FASTFLAG(LuauLowerBoundsCalculation)
lluz_FASTFLAG(LluLowerBoundsCalculation)
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("ProvisionalTests");
TEST_SUITE_BEGIN(XorStr("ProvisionalTests"));
// These tests check for behavior that differs from the final behavior we'd
// like to have. They serve to document the current state of the typechecker.
@ -31,7 +31,7 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_inference_incomplete")
{
const std::string code = R"(
function f(a)
if type(a) == "boolean" then
if type(a) == XorStr("boolean") then
local a1 = a
elseif a.fn() then
local a2 = a
@ -55,7 +55,7 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_inference_incomplete")
TEST_CASE_FIXTURE(BuiltinsFixture, "xpcall_returns_what_f_returns")
{
const std::string code = R"(
local a, b, c = xpcall(function() return 1, "foo" end, function() return "foo", 1 end)
local a, b, c = xpcall(function() return 1, "foo" end, function() return XorStr("foo"), 1 end)
)";
const std::string expected = R"(
@ -73,7 +73,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "xpcall_returns_what_f_returns")
TEST_CASE_FIXTURE(Fixture, "weirditer_should_not_loop_forever")
{
// this flag is intentionally here doing nothing to demonstrate that we exit early via case detection
ScopedFastInt sfis{"LuauTypeInferTypePackLoopLimit", 50};
ScopedFastInt sfis{"lluzTypeInferTypePackLoopLimit", 50};
CheckResult result = check(R"(
local function toVertexList(vertices, x, y, ...)
@ -83,11 +83,11 @@ TEST_CASE_FIXTURE(Fixture, "weirditer_should_not_loop_forever")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
// This should also generate an OccursCheckFailed error too, like the above toVertexList snippet.
// at least up until we can get Luau to recognize this code as a valid function that iterates over a list of values in the pack.
// at least up until we can get lluz to recognize this code as a valid function that iterates over a list of values in the pack.
TEST_CASE_FIXTURE(Fixture, "it_should_be_agnostic_of_actual_size")
{
CheckResult result = check(R"(
@ -99,7 +99,7 @@ TEST_CASE_FIXTURE(Fixture, "it_should_be_agnostic_of_actual_size")
f(3, 2, 1, 0)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
// Ideally setmetatable's second argument would be an optional free table.
@ -113,7 +113,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_constrains_free_type_into_free_
b = 1
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
@ -121,7 +121,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_constrains_free_type_into_free_
CHECK_EQ("number", toString(tm->givenType));
}
// Luau currently doesn't yet know how to allow assignments when the binding was refined.
// lluz currently doesn't yet know how to allow assignments when the binding was refined.
TEST_CASE_FIXTURE(Fixture, "while_body_are_also_refined")
{
CheckResult result = check(R"(
@ -137,7 +137,7 @@ TEST_CASE_FIXTURE(Fixture, "while_body_are_also_refined")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type 'Node<T>?' could not be converted into 'Node<T>'", toString(result.errors[0]));
}
@ -157,7 +157,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "error_on_eq_metamethod_returning_a_type_othe
local a = tab2 == tab
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
GenericError* ge = get<GenericError>(result.errors[0]);
REQUIRE(ge);
@ -175,7 +175,7 @@ TEST_CASE_FIXTURE(Fixture, "operator_eq_completely_incompatible")
local r2 = b == a
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
// Belongs in TypeInfer.refinements.test.cpp.
@ -192,13 +192,13 @@ TEST_CASE_FIXTURE(Fixture, "lvalue_equals_another_lvalue_with_no_overlap")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireTypeAtPosition({3, 33})), "string"); // a == b
CHECK_EQ(toString(requireTypeAtPosition({3, 36})), "boolean?"); // a == b
CHECK_EQ(toString(requireTypeAtPosition({3, 33})), XorStr("string")); // a == b
CHECK_EQ(toString(requireTypeAtPosition({3, 36})), XorStr("boolean?")); // a == b
CHECK_EQ(toString(requireTypeAtPosition({5, 33})), "string"); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({5, 36})), "boolean?"); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({5, 33})), XorStr("string")); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({5, 36})), XorStr("boolean?")); // a ~= b
}
// Also belongs in TypeInfer.refinements.test.cpp.
@ -217,7 +217,7 @@ TEST_CASE_FIXTURE(Fixture, "discriminate_from_x_not_equal_to_nil")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("{| x: string, y: number |}", toString(requireTypeAtPosition({5, 28})));
@ -225,10 +225,10 @@ TEST_CASE_FIXTURE(Fixture, "discriminate_from_x_not_equal_to_nil")
CHECK_EQ("{| x: nil, y: nil |} | {| x: string, y: number |}", toString(requireTypeAtPosition({7, 28})));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "bail_early_if_unification_is_too_complicated" * doctest::timeout(0.5))
TEST_CASE_FIXTURE(Fixture, "bail_early_if_unification_is_too_complicated" * doctest::timeout(0.5))
{
ScopedFastInt sffi{"LuauTarjanChildLimit", 1};
ScopedFastInt sffi2{"LuauTypeInferIterationLimit", 1};
ScopedFastInt sffi{"lluzTarjanChildLimit", 1};
ScopedFastInt sffi2{"lluzTypeInferIterationLimit", 1};
CheckResult result = check(R"LUA(
local Result
@ -259,7 +259,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "bail_early_if_unification_is_too_complicated
if (it == result.errors.end())
{
dumpErrors(result);
FAIL("Expected a UnificationTooComplex error");
FAIL(XorStr("Expected a UnificationTooComplex error"));
}
}
@ -284,14 +284,14 @@ TEST_CASE_FIXTURE(Fixture, "invariant_table_properties_means_instantiating_table
// TODO: this should error!
// This should be fixed by replacing generic tables by generics with type bounds.
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
// FIXME: Move this test to another source file when removing FFlag::LuauLowerBoundsCalculation
// FIXME: Move this test to another source file when removing FFlag::LluLowerBoundsCalculation
TEST_CASE_FIXTURE(Fixture, "do_not_ice_when_trying_to_pick_first_of_generic_type_pack")
{
ScopedFastFlag sff[]{
{"LuauReturnAnyInsteadOfICE", true},
{"lluzReturnAnyInsteadOfICE", true},
};
// In-place quantification causes these types to have the wrong types but only because of nasty interaction with prototyping.
@ -315,9 +315,9 @@ TEST_CASE_FIXTURE(Fixture, "do_not_ice_when_trying_to_pick_first_of_generic_type
local x = (f()) -- should error: no return values to assign from the call to f
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
if (FFlag::LuauLowerBoundsCalculation)
if (FFlag::LluLowerBoundsCalculation)
{
CHECK_EQ("() -> ()", toString(requireType("f")));
CHECK_EQ("() -> ()", toString(requireType("g")));
@ -340,27 +340,13 @@ TEST_CASE_FIXTURE(Fixture, "specialization_binds_with_prototypes_too_early")
local s2s: (string) -> string = id
)");
LUAU_REQUIRE_ERRORS(result); // Should not have any errors.
}
TEST_CASE_FIXTURE(Fixture, "weird_fail_to_unify_type_pack")
{
ScopedFastFlag sff[] = {
{"LuauLowerBoundsCalculation", false},
};
CheckResult result = check(R"(
local function f() return end
local g = function() return f() end
)");
LUAU_REQUIRE_ERRORS(result); // Should not have any errors.
lluz_REQUIRE_ERRORS(result); // Should not have any errors.
}
TEST_CASE_FIXTURE(Fixture, "weird_fail_to_unify_variadic_pack")
{
ScopedFastFlag sff[] = {
{"LuauLowerBoundsCalculation", false},
{"lluzLowerBoundsCalculation", false},
};
CheckResult result = check(R"(
@ -369,13 +355,13 @@ TEST_CASE_FIXTURE(Fixture, "weird_fail_to_unify_variadic_pack")
local g = function(...) return f(...) end
)");
LUAU_REQUIRE_ERRORS(result); // Should not have any errors.
lluz_REQUIRE_ERRORS(result); // Should not have any errors.
}
TEST_CASE_FIXTURE(Fixture, "lower_bounds_calculation_is_too_permissive_with_overloaded_higher_order_functions")
{
ScopedFastFlag sff[] = {
{"LuauLowerBoundsCalculation", true},
{"lluzLowerBoundsCalculation", true},
};
CheckResult result = check(R"(
@ -385,7 +371,7 @@ TEST_CASE_FIXTURE(Fixture, "lower_bounds_calculation_is_too_permissive_with_over
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
// We incorrectly infer that the argument to foo could be called with (number, number) or (string, string)
// even though that is strictly more permissive than the actual source text shows.
@ -396,11 +382,11 @@ TEST_CASE_FIXTURE(Fixture, "lower_bounds_calculation_is_too_permissive_with_over
TEST_CASE_FIXTURE(Fixture, "normalization_fails_on_certain_kinds_of_cyclic_tables")
{
#if defined(_DEBUG) || defined(_NOOPT)
ScopedFastInt sfi("LuauNormalizeIterationLimit", 500);
ScopedFastInt sfi("lluzNormalizeIterationLimit", 500);
#endif
ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true},
{"lluzLowerBoundsCalculation", true},
};
// We use a function and inferred parameter types to prevent intermediate normalizations from being performed.
@ -417,7 +403,7 @@ TEST_CASE_FIXTURE(Fixture, "normalization_fails_on_certain_kinds_of_cyclic_table
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK(nullptr != get<NormalizationTooComplex>(result.errors[0]));
}
@ -430,9 +416,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "pcall_returns_at_least_two_value_but_functio
local ok, res = pcall(f)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Function only returns 1 value. 2 are required here", toString(result.errors[0]));
// LUAU_REQUIRE_NO_ERRORS(result);
// lluz_REQUIRE_NO_ERRORS(result);
// CHECK_EQ("boolean", toString(requireType("ok")));
// CHECK_EQ("any", toString(requireType("res")));
}
@ -452,7 +438,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "choose_the_right_overload_for_pcall")
local ok, res = pcall(f)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("boolean", toString(requireType("ok")));
CHECK_EQ("number", toString(requireType("res")));
// CHECK_EQ("any", toString(requireType("res")));
@ -473,7 +459,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "function_returns_many_things_but_first_of_it
local ok, res, s, b = pcall(f)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("boolean", toString(requireType("ok")));
CHECK_EQ("number", toString(requireType("res")));
// CHECK_EQ("any", toString(requireType("res")));
@ -484,9 +470,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "function_returns_many_things_but_first_of_it
TEST_CASE_FIXTURE(Fixture, "constrained_is_level_dependent")
{
ScopedFastFlag sff[]{
{"LuauLowerBoundsCalculation", true},
{"LuauNormalizeFlagIsConservative", true},
{"LuauQuantifyConstrained", true},
{"lluzLowerBoundsCalculation", true},
{"lluzNormalizeFlagIsConservative", true},
{"lluzQuantifyConstrained", true},
};
CheckResult result = check(R"(
@ -508,25 +494,14 @@ TEST_CASE_FIXTURE(Fixture, "constrained_is_level_dependent")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
// TODO: We're missing generics b...
CHECK_EQ("<a...>(t1) -> {| [t1]: boolean |} where t1 = t2 ; t2 = {+ m1: (t1) -> (a...), m2: (t2) -> (b...) +}", toString(requireType("f")));
}
TEST_CASE_FIXTURE(Fixture, "free_is_not_bound_to_any")
{
CheckResult result = check(R"(
local function foo(f: (any) -> (), x)
f(x)
end
)");
CHECK_EQ("((any) -> (), any) -> ()", toString(requireType("foo")));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "greedy_inference_with_shared_self_triggers_function_with_no_returns")
{
ScopedFastFlag sff{"DebugLuauSharedSelf", true};
ScopedFastFlag sff{"DebuglluzSharedSelf", true};
CheckResult result = check(R"(
local T = {}
@ -542,7 +517,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "greedy_inference_with_shared_self_triggers_f
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Not all codepaths in this function return 'self, a...'.", toString(result.errors[0]));
}

View file

@ -1,16 +1,15 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Normalize.h"
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Normalize.h"
#include "lluz/Scope.h"
#include "lluz/TypeInfer.h"
#include "Fixture.h"
#include "doctest.h"
LUAU_FASTFLAG(LuauLowerBoundsCalculation)
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
lluz_FASTFLAG(LluLowerBoundsCalculation)
using namespace Luau;
using namespace lluz;
namespace
{
@ -20,8 +19,8 @@ std::optional<WithPredicate<TypePackId>> magicFunctionInstanceIsA(
if (expr.args.size != 1)
return std::nullopt;
auto index = expr.func->as<Luau::AstExprIndexName>();
auto str = expr.args.data[0]->as<Luau::AstExprConstantString>();
auto index = expr.func->as<lluz::AstExprIndexName>();
auto str = expr.args.data[0]->as<lluz::AstExprConstantString>();
if (!index || !str)
return std::nullopt;
@ -86,7 +85,7 @@ struct RefinementClassFixture : Fixture
};
} // namespace
TEST_SUITE_BEGIN("RefinementTest");
TEST_SUITE_BEGIN(XorStr("RefinementTest"));
TEST_CASE_FIXTURE(Fixture, "is_truthy_constraint")
{
@ -100,7 +99,7 @@ TEST_CASE_FIXTURE(Fixture, "is_truthy_constraint")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("nil", toString(requireTypeAtPosition({5, 26})));
@ -118,7 +117,7 @@ TEST_CASE_FIXTURE(Fixture, "invert_is_truthy_constraint")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("nil", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("string", toString(requireTypeAtPosition({5, 26})));
@ -136,7 +135,7 @@ TEST_CASE_FIXTURE(Fixture, "parenthesized_expressions_are_followed_through")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("nil", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("string", toString(requireTypeAtPosition({5, 26})));
@ -156,7 +155,7 @@ TEST_CASE_FIXTURE(Fixture, "and_constraint")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("number", toString(requireTypeAtPosition({4, 26})));
@ -179,7 +178,7 @@ TEST_CASE_FIXTURE(Fixture, "not_and_constraint")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string?", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("number?", toString(requireTypeAtPosition({4, 26})));
@ -202,7 +201,7 @@ TEST_CASE_FIXTURE(Fixture, "or_predicate_with_truthy_predicates")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string?", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("number?", toString(requireTypeAtPosition({4, 26})));
@ -222,7 +221,7 @@ TEST_CASE_FIXTURE(Fixture, "type_assertion_expr_carry_its_constraints")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("string", toString(requireTypeAtPosition({4, 26})));
@ -232,13 +231,13 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_in_if_condition_position")
{
CheckResult result = check(R"(
function f(s: any)
if type(s) == "number" then
if type(s) == XorStr("number") then
local n = s
end
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireTypeAtPosition({3, 26})));
}
@ -247,11 +246,11 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typeguard_in_assert_position")
{
CheckResult result = check(R"(
local a
assert(type(a) == "number")
assert(type(a) == XorStr("number"))
local b = a
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
REQUIRE_EQ("number", toString(requireType("b")));
}
@ -264,17 +263,17 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_only_look_up_types_from_global_scope")
type string = number
local foo: string = 1
if type(foo) == "string" then
if type(foo) == XorStr("string") then
local bar: ActuallyString = foo
local baz: boolean = foo
end
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("never", toString(requireTypeAtPosition({8, 44})));
CHECK_EQ("never", toString(requireTypeAtPosition({9, 38})));
CHECK_EQ("*unknown*", toString(requireTypeAtPosition({8, 44})));
CHECK_EQ("*unknown*", toString(requireTypeAtPosition({9, 38})));
}
TEST_CASE_FIXTURE(Fixture, "call_a_more_specific_function_using_typeguard")
@ -285,19 +284,19 @@ TEST_CASE_FIXTURE(Fixture, "call_a_more_specific_function_using_typeguard")
end
local function g(x: any)
if type(x) == "string" then
if type(x) == XorStr("string") then
f(x)
end
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type 'string' could not be converted into 'number'", toString(result.errors[0]));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "impossible_type_narrow_is_not_an_error")
{
// This unit test serves as a reminder to not implement this warning until Luau is intelligent enough.
// This unit test serves as a reminder to not implement this warning until lluz is intelligent enough.
// For instance, getting a value out of the indexer and checking whether the value exists is not an error.
CheckResult result = check(R"(
local t: {string} = {"a", "b", "c"}
@ -309,7 +308,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "impossible_type_narrow_is_not_an_error")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "truthy_constraint_on_properties")
@ -324,7 +323,7 @@ TEST_CASE_FIXTURE(Fixture, "truthy_constraint_on_properties")
local bar = t.x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number?", toString(requireType("bar")));
}
@ -338,7 +337,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_on_a_refined_property")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "assert_non_binary_expressions_actually_resolve_constraints")
@ -349,7 +348,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_non_binary_expressions_actually_resol
local bar: string = foo
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "assign_table_with_refined_property_with_a_similar_type_is_illegal")
@ -362,7 +361,7 @@ TEST_CASE_FIXTURE(Fixture, "assign_table_with_refined_property_with_a_similar_ty
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(R"(Type '{| x: number? |}' could not be converted into '{| x: number |}'
caused by:
Property 'x' is not compatible. Type 'number?' could not be converted into 'number')",
@ -381,13 +380,13 @@ TEST_CASE_FIXTURE(Fixture, "lvalue_is_equal_to_another_lvalue")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireTypeAtPosition({3, 33})), "(number | string)?"); // a == b
CHECK_EQ(toString(requireTypeAtPosition({3, 36})), "boolean?"); // a == b
CHECK_EQ(toString(requireTypeAtPosition({3, 33})), XorStr("(number | string)?")); // a == b
CHECK_EQ(toString(requireTypeAtPosition({3, 36})), XorStr("boolean?")); // a == b
CHECK_EQ(toString(requireTypeAtPosition({5, 33})), "(number | string)?"); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({5, 36})), "boolean?"); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({5, 33})), XorStr("(number | string)?")); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({5, 36})), XorStr("boolean?")); // a ~= b
}
TEST_CASE_FIXTURE(Fixture, "lvalue_is_equal_to_a_term")
@ -402,10 +401,10 @@ TEST_CASE_FIXTURE(Fixture, "lvalue_is_equal_to_a_term")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireTypeAtPosition({3, 28})), "(number | string)?"); // a == 1
CHECK_EQ(toString(requireTypeAtPosition({5, 28})), "(number | string)?"); // a ~= 1
CHECK_EQ(toString(requireTypeAtPosition({3, 28})), XorStr("(number | string)?")); // a == 1
CHECK_EQ(toString(requireTypeAtPosition({5, 28})), XorStr("(number | string)?")); // a ~= 1
}
TEST_CASE_FIXTURE(Fixture, "term_is_equal_to_an_lvalue")
@ -420,10 +419,10 @@ TEST_CASE_FIXTURE(Fixture, "term_is_equal_to_an_lvalue")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireTypeAtPosition({3, 28})), R"("hello")"); // a == "hello"
CHECK_EQ(toString(requireTypeAtPosition({5, 28})), "(number | string)?"); // a ~= "hello"
CHECK_EQ(toString(requireTypeAtPosition({3, 28})), RXorStr("("hello")")); // a == XorStr("hello")
CHECK_EQ(toString(requireTypeAtPosition({5, 28})), XorStr("(number | string)?")); // a ~= "hello"
}
TEST_CASE_FIXTURE(Fixture, "lvalue_is_not_nil")
@ -438,10 +437,10 @@ TEST_CASE_FIXTURE(Fixture, "lvalue_is_not_nil")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireTypeAtPosition({3, 28})), "number | string"); // a ~= nil
CHECK_EQ(toString(requireTypeAtPosition({5, 28})), "(number | string)?"); // a == nil
CHECK_EQ(toString(requireTypeAtPosition({3, 28})), XorStr("number | string")); // a ~= nil
CHECK_EQ(toString(requireTypeAtPosition({5, 28})), XorStr("(number | string)?")); // a == nil
}
TEST_CASE_FIXTURE(Fixture, "free_type_is_equal_to_an_lvalue")
@ -454,10 +453,10 @@ TEST_CASE_FIXTURE(Fixture, "free_type_is_equal_to_an_lvalue")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireTypeAtPosition({3, 33})), "a"); // a == b
CHECK_EQ(toString(requireTypeAtPosition({3, 36})), "string?"); // a == b
CHECK_EQ(toString(requireTypeAtPosition({3, 33})), XorStr("a")); // a == b
CHECK_EQ(toString(requireTypeAtPosition({3, 36})), XorStr("string?")); // a == b
}
TEST_CASE_FIXTURE(Fixture, "unknown_lvalue_is_not_synonymous_with_other_on_not_equal")
@ -470,10 +469,10 @@ TEST_CASE_FIXTURE(Fixture, "unknown_lvalue_is_not_synonymous_with_other_on_not_e
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireTypeAtPosition({3, 33})), "any"); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({3, 36})), "{| x: number |}?"); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({3, 33})), XorStr("any")); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({3, 36})), XorStr("{| x: number |}?")); // a ~= b
}
TEST_CASE_FIXTURE(Fixture, "string_not_equal_to_string_or_nil")
@ -490,13 +489,13 @@ TEST_CASE_FIXTURE(Fixture, "string_not_equal_to_string_or_nil")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireTypeAtPosition({6, 29})), "string"); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({6, 32})), "string?"); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({6, 29})), XorStr("string")); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({6, 32})), XorStr("string?")); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({8, 29})), "string"); // a == b
CHECK_EQ(toString(requireTypeAtPosition({8, 32})), "string?"); // a == b
CHECK_EQ(toString(requireTypeAtPosition({8, 29})), XorStr("string")); // a == b
CHECK_EQ(toString(requireTypeAtPosition({8, 32})), XorStr("string?")); // a == b
}
TEST_CASE_FIXTURE(Fixture, "narrow_property_of_a_bounded_variable")
@ -512,25 +511,22 @@ TEST_CASE_FIXTURE(Fixture, "narrow_property_of_a_bounded_variable")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "type_narrow_to_vector")
{
CheckResult result = check(R"(
local function f(x)
if type(x) == "vector" then
if type(x) == XorStr("vector") then
local foo = x
end
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(requireTypeAtPosition({3, 28})));
else
CHECK_EQ("<error-type>", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("*unknown*", toString(requireTypeAtPosition({3, 28})));
}
TEST_CASE_FIXTURE(Fixture, "nonoptional_type_can_narrow_to_nil_if_sense_is_true")
@ -538,7 +534,7 @@ TEST_CASE_FIXTURE(Fixture, "nonoptional_type_can_narrow_to_nil_if_sense_is_true"
CheckResult result = check(R"(
local t = {"hello"}
local v = t[2]
if type(v) == "nil" then
if type(v) == XorStr("nil") then
local foo = v
else
local foo = v
@ -551,12 +547,12 @@ TEST_CASE_FIXTURE(Fixture, "nonoptional_type_can_narrow_to_nil_if_sense_is_true"
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("nil", toString(requireTypeAtPosition({4, 24}))); // type(v) == "nil"
CHECK_EQ("nil", toString(requireTypeAtPosition({4, 24}))); // type(v) == XorStr("nil")
CHECK_EQ("string", toString(requireTypeAtPosition({6, 24}))); // type(v) ~= "nil"
CHECK_EQ("nil", toString(requireTypeAtPosition({10, 24}))); // equivalent to type(v) == "nil"
CHECK_EQ("nil", toString(requireTypeAtPosition({10, 24}))); // equivalent to type(v) == XorStr("nil")
CHECK_EQ("string", toString(requireTypeAtPosition({12, 24}))); // equivalent to type(v) ~= "nil"
}
@ -572,17 +568,17 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_not_to_be_string")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("boolean | number", toString(requireTypeAtPosition({3, 28}))); // type(x) ~= "string"
CHECK_EQ("string", toString(requireTypeAtPosition({5, 28}))); // type(x) == "string"
CHECK_EQ("string", toString(requireTypeAtPosition({5, 28}))); // type(x) == XorStr("string")
}
TEST_CASE_FIXTURE(Fixture, "typeguard_narrows_for_table")
{
CheckResult result = check(R"(
local function f(x: string | {x: number} | {y: boolean})
if type(x) == "table" then
if type(x) == XorStr("table") then
local foo = x
else
local foo = x
@ -590,9 +586,9 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_narrows_for_table")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("{| x: number |} | {| y: boolean |}", toString(requireTypeAtPosition({3, 28}))); // type(x) == "table"
CHECK_EQ("{| x: number |} | {| y: boolean |}", toString(requireTypeAtPosition({3, 28}))); // type(x) == XorStr("table")
CHECK_EQ("string", toString(requireTypeAtPosition({5, 28}))); // type(x) ~= "table"
}
@ -600,7 +596,7 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_narrows_for_functions")
{
CheckResult result = check(R"(
local function weird(x: string | ((number) -> string))
if type(x) == "function" then
if type(x) == XorStr("function") then
local foo = x
else
local foo = x
@ -608,9 +604,9 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_narrows_for_functions")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("(number) -> string", toString(requireTypeAtPosition({3, 28}))); // type(x) == "function"
CHECK_EQ("(number) -> string", toString(requireTypeAtPosition({3, 28}))); // type(x) == XorStr("function")
CHECK_EQ("string", toString(requireTypeAtPosition({5, 28}))); // type(x) ~= "function"
}
@ -619,7 +615,7 @@ TEST_CASE_FIXTURE(Fixture, "type_guard_can_filter_for_intersection_of_tables")
CheckResult result = check(R"(
type XYCoord = {x: number} & {y: number}
local function f(t: XYCoord?)
if type(t) == "table" then
if type(t) == XorStr("table") then
local foo = t
else
local foo = t
@ -627,9 +623,9 @@ TEST_CASE_FIXTURE(Fixture, "type_guard_can_filter_for_intersection_of_tables")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
if (FFlag::LuauLowerBoundsCalculation)
if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ("{| x: number, y: number |}", toString(requireTypeAtPosition({4, 28})));
else
CHECK_EQ("{| x: number |} & {| y: number |}", toString(requireTypeAtPosition({4, 28})));
@ -641,7 +637,7 @@ TEST_CASE_FIXTURE(Fixture, "type_guard_can_filter_for_overloaded_function")
CheckResult result = check(R"(
type SomeOverloadedFunction = ((number) -> string) & ((string) -> number)
local function f(g: SomeOverloadedFunction?)
if type(g) == "function" then
if type(g) == XorStr("function") then
local foo = g
else
local foo = g
@ -649,13 +645,13 @@ TEST_CASE_FIXTURE(Fixture, "type_guard_can_filter_for_overloaded_function")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("((number) -> string) & ((string) -> number)", toString(requireTypeAtPosition({4, 28})));
CHECK_EQ("nil", toString(requireTypeAtPosition({6, 28})));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "type_guard_narrowed_into_nothingness")
TEST_CASE_FIXTURE(BuiltinsFixture, "type_guard_warns_on_no_overlapping_types_only_when_sense_is_true")
{
CheckResult result = check(R"(
local function f(t: {x: number})
@ -668,9 +664,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_guard_narrowed_into_nothingness")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("never", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("*unknown*", toString(requireTypeAtPosition({3, 28})));
}
TEST_CASE_FIXTURE(Fixture, "not_a_or_not_b")
@ -684,7 +680,7 @@ TEST_CASE_FIXTURE(Fixture, "not_a_or_not_b")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number?", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("number?", toString(requireTypeAtPosition({4, 28})));
@ -701,7 +697,7 @@ TEST_CASE_FIXTURE(Fixture, "not_a_or_not_b2")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number?", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("number?", toString(requireTypeAtPosition({4, 28})));
@ -718,7 +714,7 @@ TEST_CASE_FIXTURE(Fixture, "not_a_and_not_b")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("nil", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("nil", toString(requireTypeAtPosition({4, 28})));
@ -735,7 +731,7 @@ TEST_CASE_FIXTURE(Fixture, "not_a_and_not_b2")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("nil", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("nil", toString(requireTypeAtPosition({4, 28})));
@ -745,13 +741,13 @@ TEST_CASE_FIXTURE(Fixture, "either_number_or_string")
{
CheckResult result = check(R"(
local function f(x: any)
if type(x) == "number" or type(x) == "string" then
if type(x) == XorStr("number") or type(x) == XorStr("string") then
local foo = x
end
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number | string", toString(requireTypeAtPosition({3, 28})));
}
@ -766,7 +762,7 @@ TEST_CASE_FIXTURE(Fixture, "not_t_or_some_prop_of_t")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("{| x: boolean |}?", toString(requireTypeAtPosition({3, 28})));
}
@ -777,11 +773,11 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_a_to_be_truthy_then_assert_a_to_be_nu
local a: (number | string)?
assert(a)
local b = a
assert(type(a) == "number")
assert(type(a) == XorStr("number"))
local c = a
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number | string", toString(requireTypeAtPosition({3, 18})));
CHECK_EQ("number", toString(requireTypeAtPosition({5, 18})));
@ -789,19 +785,19 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_a_to_be_truthy_then_assert_a_to_be_nu
TEST_CASE_FIXTURE(BuiltinsFixture, "merge_should_be_fully_agnostic_of_hashmap_ordering")
{
// This bug came up because there was a mistake in Luau::merge where zipping on two maps would produce the wrong merged result.
// This bug came up because there was a mistake in lluz::merge where zipping on two maps would produce the wrong merged result.
CheckResult result = check(R"(
local function f(b: string | { x: string }, a)
assert(type(a) == "string")
assert(type(b) == "string" or type(b) == "table")
assert(type(a) == XorStr("string"))
assert(type(b) == XorStr("string") or type(b) == XorStr("table"))
if type(b) == "string" then
if type(b) == XorStr("string") then
local foo = b
end
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireTypeAtPosition({6, 28})));
}
@ -818,7 +814,7 @@ TEST_CASE_FIXTURE(Fixture, "refine_the_correct_types_opposite_of_when_a_is_not_n
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("boolean", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("number | string", toString(requireTypeAtPosition({5, 28})));
@ -832,7 +828,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "is_truthy_constraint_ifelse_expression")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireTypeAtPosition({2, 29})));
CHECK_EQ("nil", toString(requireTypeAtPosition({2, 45})));
@ -846,7 +842,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "invert_is_truthy_constraint_ifelse_expressio
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("nil", toString(requireTypeAtPosition({2, 42})));
CHECK_EQ("string", toString(requireTypeAtPosition({2, 50})));
@ -860,11 +856,11 @@ TEST_CASE_FIXTURE(Fixture, "type_comparison_ifelse_expression")
end
function f(v:any)
return if typeof(v) == "number" then v else returnOne(v)
return if typeof(v) == XorStr("number") then v else returnOne(v)
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireTypeAtPosition({6, 49})));
CHECK_EQ("any", toString(requireTypeAtPosition({6, 66})));
@ -879,7 +875,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "correctly_lookup_a_shadowed_local_that_which
print(foo:sub(1, 1))
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type 'number' does not have key 'sub'", toString(result.errors[0]));
}
@ -890,13 +886,13 @@ TEST_CASE_FIXTURE(Fixture, "correctly_lookup_property_whose_base_was_previously_
type T = {x: string | number}
local t: T? = {x = "hi"}
if t then
if type(t.x) == "string" then
if type(t.x) == XorStr("string") then
local foo = t.x
end
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireTypeAtPosition({5, 30})));
}
@ -913,7 +909,7 @@ TEST_CASE_FIXTURE(Fixture, "correctly_lookup_property_whose_base_was_previously_
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireTypeAtPosition({5, 32})));
}
@ -929,12 +925,12 @@ TEST_CASE_FIXTURE(Fixture, "apply_refinements_on_astexprindexexpr_whose_subscrip
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "discriminate_from_truthiness_of_x")
{
ScopedFastFlag sff{"LuauFalsyPredicateReturnsNilInstead", true};
ScopedFastFlag sff{"lluzFalsyPredicateReturnsNilInstead", true};
CheckResult result = check(R"(
type T = {tag: "missing", x: nil} | {tag: "exists", x: string}
@ -948,7 +944,7 @@ TEST_CASE_FIXTURE(Fixture, "discriminate_from_truthiness_of_x")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"({| tag: "exists", x: string |})", toString(requireTypeAtPosition({5, 28})));
CHECK_EQ(R"({| tag: "exists", x: string |} | {| tag: "missing", x: nil |})", toString(requireTypeAtPosition({7, 28})));
@ -962,15 +958,15 @@ TEST_CASE_FIXTURE(Fixture, "discriminate_tag")
type Animal = Cat | Dog
local function f(animal: Animal)
if animal.tag == "Cat" then
if animal.tag == XorStr("Cat") then
local cat: Cat = animal
elseif animal.tag == "Dog" then
elseif animal.tag == XorStr("Dog") then
local dog: Dog = animal
end
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Cat", toString(requireTypeAtPosition({7, 33})));
CHECK_EQ("Dog", toString(requireTypeAtPosition({9, 33})));
@ -984,7 +980,7 @@ TEST_CASE_FIXTURE(Fixture, "and_or_peephole_refinement")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "narrow_boolean_to_true_or_false")
@ -1002,7 +998,7 @@ TEST_CASE_FIXTURE(Fixture, "narrow_boolean_to_true_or_false")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "discriminate_on_properties_of_disjoint_tables_where_that_property_is_true_or_false")
@ -1021,7 +1017,7 @@ TEST_CASE_FIXTURE(Fixture, "discriminate_on_properties_of_disjoint_tables_where_
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "refine_a_property_not_to_be_nil_through_an_intersection_table")
@ -1035,7 +1031,7 @@ TEST_CASE_FIXTURE(Fixture, "refine_a_property_not_to_be_nil_through_an_intersect
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(RefinementClassFixture, "discriminate_from_isa_of_x")
@ -1052,7 +1048,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "discriminate_from_isa_of_x")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"({| tag: "Part", x: Part |})", toString(requireTypeAtPosition({5, 28})));
CHECK_EQ(R"({| tag: "Folder", x: Folder |})", toString(requireTypeAtPosition({7, 28})));
@ -1064,9 +1060,9 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "typeguard_cast_free_table_to_vector")
local function f(vec)
local X, Y, Z = vec.X, vec.Y, vec.Z
if type(vec) == "vector" then
if type(vec) == XorStr("vector") then
local foo = vec
elseif typeof(vec) == "Instance" then
elseif typeof(vec) == XorStr("Instance") then
local foo = vec
else
local foo = vec
@ -1074,11 +1070,11 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "typeguard_cast_free_table_to_vector")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Vector3", toString(requireTypeAtPosition({5, 28}))); // type(vec) == "vector"
CHECK_EQ("Vector3", toString(requireTypeAtPosition({5, 28}))); // type(vec) == XorStr("vector")
CHECK_EQ("never", toString(requireTypeAtPosition({7, 28}))); // typeof(vec) == "Instance"
CHECK_EQ("*unknown*", toString(requireTypeAtPosition({7, 28}))); // typeof(vec) == XorStr("Instance")
CHECK_EQ("{+ X: a, Y: b, Z: c +}", toString(requireTypeAtPosition({9, 28}))); // type(vec) ~= "vector" and typeof(vec) ~= "Instance"
}
@ -1087,7 +1083,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "typeguard_cast_instance_or_vector3_to
{
CheckResult result = check(R"(
local function f(x: Instance | Vector3)
if typeof(x) == "Vector3" then
if typeof(x) == XorStr("Vector3") then
local foo = x
else
local foo = x
@ -1095,7 +1091,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "typeguard_cast_instance_or_vector3_to
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Vector3", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("Instance", toString(requireTypeAtPosition({5, 28})));
@ -1105,7 +1101,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "type_narrow_for_all_the_userdata")
{
CheckResult result = check(R"(
local function f(x: string | number | Instance | Vector3)
if type(x) == "userdata" then
if type(x) == XorStr("userdata") then
local foo = x
else
local foo = x
@ -1113,7 +1109,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "type_narrow_for_all_the_userdata")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Instance | Vector3", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("number | string", toString(requireTypeAtPosition({5, 28})));
@ -1123,7 +1119,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "eliminate_subclasses_of_instance")
{
CheckResult result = check(R"(
local function f(x: Part | Folder | string)
if typeof(x) == "Instance" then
if typeof(x) == XorStr("Instance") then
local foo = x
else
local foo = x
@ -1131,7 +1127,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "eliminate_subclasses_of_instance")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Folder | Part", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("string", toString(requireTypeAtPosition({5, 28})));
@ -1141,7 +1137,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "narrow_this_large_union")
{
CheckResult result = check(R"(
local function f(x: Part | Folder | Instance | string | Vector3 | any)
if typeof(x) == "Instance" then
if typeof(x) == XorStr("Instance") then
local foo = x
else
local foo = x
@ -1149,7 +1145,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "narrow_this_large_union")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Folder | Instance | Part", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("Vector3 | any | string", toString(requireTypeAtPosition({5, 28})));
@ -1161,15 +1157,15 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "x_as_any_if_x_is_instance_elseif_x_is
--!nonstrict
local function f(x)
if typeof(x) == "Instance" and x:IsA("Folder") then
if typeof(x) == XorStr("Instance") and x:IsA("Folder") then
local foo = x
elseif typeof(x) == "table" then
elseif typeof(x) == XorStr("table") then
local foo = x
end
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Folder", toString(requireTypeAtPosition({5, 28})));
CHECK_EQ("any", toString(requireTypeAtPosition({7, 28})));
@ -1187,7 +1183,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "x_is_not_instance_or_else_not_part")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Folder | string", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("Part", toString(requireTypeAtPosition({5, 28})));
@ -1197,7 +1193,7 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_doesnt_leak_to_elseif")
{
CheckResult result = check(R"(
function f(a)
if type(a) == "boolean" then
if type(a) == XorStr("boolean") then
local a1 = a
elseif a.fn() then
local a2 = a
@ -1207,30 +1203,12 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_doesnt_leak_to_elseif")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "refine_unknowns")
{
CheckResult result = check(R"(
local function f(x: unknown)
if type(x) == "string" then
local foo = x
else
local bar = x
end
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("unknown", toString(requireTypeAtPosition({5, 28})));
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "falsiness_of_TruthyPredicate_narrows_into_nil")
{
ScopedFastFlag sff{"LuauFalsyPredicateReturnsNilInstead", true};
ScopedFastFlag sff{"lluzFalsyPredicateReturnsNilInstead", true};
CheckResult result = check(R"(
local function f(t: {number})
@ -1243,25 +1221,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "falsiness_of_TruthyPredicate_narrows_into_ni
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("nil", toString(requireTypeAtPosition({4, 28})));
CHECK_EQ("number", toString(requireTypeAtPosition({6, 28})));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "what_nonsensical_condition")
{
CheckResult result = check(R"(
local function f(x)
if type(x) == "string" and type(x) == "number" then
local foo = x
end
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ("never", toString(requireTypeAtPosition({3, 28})));
}
TEST_SUITE_END();

View file

@ -1,13 +1,13 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Fixture.h"
#include "doctest.h"
#include "Luau/BuiltinDefinitions.h"
#include "lluz/BuiltinDefinitions.h"
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("TypeSingletons");
TEST_SUITE_BEGIN(XorStr("TypeSingletons"));
TEST_CASE_FIXTURE(Fixture, "bool_singletons")
{
@ -16,7 +16,7 @@ TEST_CASE_FIXTURE(Fixture, "bool_singletons")
local b: false = false
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "string_singletons")
@ -26,7 +26,7 @@ TEST_CASE_FIXTURE(Fixture, "string_singletons")
local b: "bar" = "bar"
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "bool_singletons_mismatch")
@ -35,7 +35,7 @@ TEST_CASE_FIXTURE(Fixture, "bool_singletons_mismatch")
local a: true = false
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type 'false' could not be converted into 'true'", toString(result.errors[0]));
}
@ -45,7 +45,7 @@ TEST_CASE_FIXTURE(Fixture, "string_singletons_mismatch")
local a: "foo" = "bar"
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type '\"bar\"' could not be converted into '\"foo\"'", toString(result.errors[0]));
}
@ -55,7 +55,7 @@ TEST_CASE_FIXTURE(Fixture, "string_singletons_escape_chars")
local a: "\n" = "\000\r"
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(R"(Type '"\000\r"' could not be converted into '"\n"')", toString(result.errors[0]));
}
@ -66,7 +66,7 @@ TEST_CASE_FIXTURE(Fixture, "bool_singleton_subtype")
local b: boolean = a
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "string_singleton_subtype")
@ -76,7 +76,7 @@ TEST_CASE_FIXTURE(Fixture, "string_singleton_subtype")
local b: string = a
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "function_call_with_singletons")
@ -86,7 +86,7 @@ TEST_CASE_FIXTURE(Fixture, "function_call_with_singletons")
f(true, "foo")
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "function_call_with_singletons_mismatch")
@ -96,7 +96,7 @@ TEST_CASE_FIXTURE(Fixture, "function_call_with_singletons_mismatch")
f(true, "bar")
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type '\"bar\"' could not be converted into '\"foo\"'", toString(result.errors[0]));
}
@ -109,7 +109,7 @@ TEST_CASE_FIXTURE(Fixture, "overloaded_function_call_with_singletons")
g(false, 37)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "overloaded_function_call_with_singletons_mismatch")
@ -120,7 +120,7 @@ TEST_CASE_FIXTURE(Fixture, "overloaded_function_call_with_singletons_mismatch")
g(true, 37)
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ("Type 'number' could not be converted into 'string'", toString(result.errors[0]));
CHECK_EQ("Other overloads are also not viable: (false, number) -> ()", toString(result.errors[1]));
}
@ -134,7 +134,7 @@ TEST_CASE_FIXTURE(Fixture, "enums_using_singletons")
local c : MyEnum = "baz"
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "enums_using_singletons_mismatch")
@ -144,7 +144,7 @@ TEST_CASE_FIXTURE(Fixture, "enums_using_singletons_mismatch")
local a : MyEnum = "bang"
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type '\"bang\"' could not be converted into '\"bar\" | \"baz\" | \"foo\"'; none of the union options are compatible",
toString(result.errors[0]));
}
@ -159,7 +159,7 @@ TEST_CASE_FIXTURE(Fixture, "enums_using_singletons_subtyping")
local c : string = b
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "tagged_unions_using_singletons")
@ -174,7 +174,7 @@ TEST_CASE_FIXTURE(Fixture, "tagged_unions_using_singletons")
c = b
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "tagged_unions_using_singletons_mismatch")
@ -186,7 +186,7 @@ TEST_CASE_FIXTURE(Fixture, "tagged_unions_using_singletons_mismatch")
local a : Animal = { tag = "Cat", howls = true }
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "tagged_unions_immutable_tag")
@ -199,7 +199,7 @@ TEST_CASE_FIXTURE(Fixture, "tagged_unions_immutable_tag")
a.tag = "Dog"
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "table_properties_singleton_strings")
@ -224,7 +224,7 @@ TEST_CASE_FIXTURE(Fixture, "table_properties_singleton_strings")
t.baz = false
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "table_properties_singleton_strings_mismatch")
{
@ -239,7 +239,7 @@ TEST_CASE_FIXTURE(Fixture, "table_properties_singleton_strings_mismatch")
t["$$bar"] = 5
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type 'number' could not be converted into 'string'", toString(result.errors[0]));
}
@ -254,7 +254,7 @@ TEST_CASE_FIXTURE(Fixture, "table_properties_alias_or_parens_is_indexer")
}
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Cannot have more than one table indexer", toString(result.errors[0]));
}
@ -266,7 +266,7 @@ TEST_CASE_FIXTURE(Fixture, "table_properties_type_error_escapes")
x = { ["\n"] = 5 }
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(R"(Table type '{ ["\n"]: number }' not compatible with type '{| ["<>"]: number |}' because the former is missing field '<>')",
toString(result.errors[0]));
}
@ -281,7 +281,7 @@ type Animal = Cat | Dog
local a: Animal = { tag = 'cat', cafood = 'something' }
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(R"(Type 'a' could not be converted into 'Cat | Dog'
caused by:
None of the union options are compatible. For example: Table type 'a' not compatible with type 'Cat' because the former is missing field 'catfood')",
@ -298,7 +298,7 @@ type Result = Good | Bad
local a: Result = { success = false, result = 'something' }
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(R"(Type 'a' could not be converted into 'Bad | Good'
caused by:
None of the union options are compatible. For example: Table type 'a' not compatible with type 'Bad' because the former is missing field 'error')",
@ -315,21 +315,21 @@ type Animal = Cat | Dog
local a: Animal = if true then { tag = 'cat', catfood = 'something' } else { tag = 'dog', dogfood = 'other' }
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "widen_the_supertype_if_it_is_free_and_subtype_has_singleton")
{
CheckResult result = check(R"(
local function foo(f, x)
if x == "hi" then
if x == XorStr("hi") then
f(x)
f("foo")
end
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"("hi")", toString(requireTypeAtPosition({3, 18})));
// should be <a...>((string) -> a..., string) -> () but needs lower bounds calculation
@ -340,13 +340,13 @@ TEST_CASE_FIXTURE(Fixture, "return_type_of_f_is_not_widened")
{
CheckResult result = check(R"(
local function foo(f, x): "hello"? -- anyone there?
return if x == "hi"
return if x == XorStr("hi")
then f(x)
else nil
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"("hi")", toString(requireTypeAtPosition({3, 23})));
CHECK_EQ(R"(<a, b, c...>((string) -> (a, c...), b) -> "hello"?)", toString(requireType("foo")));
@ -360,7 +360,7 @@ TEST_CASE_FIXTURE(Fixture, "widening_happens_almost_everywhere")
local copy = foo
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireType("copy")));
}
@ -372,10 +372,10 @@ TEST_CASE_FIXTURE(Fixture, "widening_happens_almost_everywhere_except_for_tables
type Animal = Cat | Dog
local function f(tag: "Cat" | "Dog"): Animal?
if tag == "Cat" then
if tag == XorStr("Cat") then
local result = {tag = tag, meows = true}
return result
elseif tag == "Dog" then
elseif tag == XorStr("Dog") then
local result = {tag = tag, barks = true}
return result
else
@ -384,16 +384,16 @@ TEST_CASE_FIXTURE(Fixture, "widening_happens_almost_everywhere_except_for_tables
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_with_a_singleton_argument")
{
ScopedFastFlag sff{"LuauLowerBoundsCalculation", true};
ScopedFastFlag sff{"lluzLowerBoundsCalculation", true};
CheckResult result = check(R"(
local function foo(t, x)
if x == "hi" or x == "bye" then
if x == XorStr("hi") or x == XorStr("bye") then
table.insert(t, x)
end
@ -404,7 +404,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_with_a_singleton_argument")
table.insert(t, "totally_unrelated_type" :: "totally_unrelated_type")
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("{string}", toString(requireType("t")));
}
@ -415,7 +415,7 @@ TEST_CASE_FIXTURE(Fixture, "functions_are_not_to_be_widened")
local function foo(my_enum: "A" | "B") end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"(("A" | "B") -> ())", toString(requireType("foo")));
}
@ -424,12 +424,12 @@ TEST_CASE_FIXTURE(Fixture, "indexing_on_string_singletons")
{
CheckResult result = check(R"(
local a: string = "hi"
if a == "hi" then
if a == XorStr("hi") then
local x = a:byte()
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"("hi")", toString(requireTypeAtPosition({3, 22})));
}
@ -438,12 +438,12 @@ TEST_CASE_FIXTURE(Fixture, "indexing_on_union_of_string_singletons")
{
CheckResult result = check(R"(
local a: string = "hi"
if a == "hi" or a == "bye" then
if a == XorStr("hi") or a == XorStr("bye") then
local x = a:byte()
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"("bye" | "hi")", toString(requireTypeAtPosition({3, 22})));
}
@ -452,12 +452,12 @@ TEST_CASE_FIXTURE(Fixture, "taking_the_length_of_string_singleton")
{
CheckResult result = check(R"(
local a: string = "hi"
if a == "hi" then
if a == XorStr("hi") then
local x = #a
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"("hi")", toString(requireTypeAtPosition({3, 23})));
}
@ -466,31 +466,14 @@ TEST_CASE_FIXTURE(Fixture, "taking_the_length_of_union_of_string_singleton")
{
CheckResult result = check(R"(
local a: string = "hi"
if a == "hi" or a == "bye" then
if a == XorStr("hi") or a == XorStr("bye") then
local x = #a
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"("bye" | "hi")", toString(requireTypeAtPosition({3, 23})));
}
TEST_CASE_FIXTURE(Fixture, "no_widening_from_callsites")
{
ScopedFastFlag sff{"LuauReturnsFromCallsitesAreNotWidened", true};
CheckResult result = check(R"(
type Direction = "North" | "East" | "West" | "South"
local function direction(): Direction
return "North"
end
local d: Direction = direction()
)");
LUAU_REQUIRE_NO_ERRORS(result);
}
TEST_SUITE_END();

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,11 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/AstQuery.h"
#include "Luau/BuiltinDefinitions.h"
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/VisitTypeVar.h"
#include "lluz/AstQuery.h"
#include "lluz/BuiltinDefinitions.h"
#include "lluz/Scope.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "lluz/VisitTypeVar.h"
#include "Fixture.h"
@ -13,45 +13,44 @@
#include <algorithm>
LUAU_FASTFLAG(LuauLowerBoundsCalculation);
LUAU_FASTFLAG(LuauFixLocationSpanTableIndexExpr);
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution);
LUAU_FASTFLAG(LuauSpecialTypesAsterisked);
lluz_FASTFLAG(LluLowerBoundsCalculation);
lluz_FASTFLAG(LluFixLocationSpanTableIndexExpr);
lluz_FASTFLAG(DebugLluDeferredConstraintResolution);
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("TypeInfer");
TEST_SUITE_BEGIN(XorStr("TypeInfer"));
TEST_CASE_FIXTURE(Fixture, "tc_hello_world")
{
CheckResult result = check("local a = 7");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = check(XorStr("local a = 7"));
lluz_REQUIRE_NO_ERRORS(result);
TypeId aType = requireType("a");
TypeId aType = requireType(XorStr("a"));
CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::Number);
}
TEST_CASE_FIXTURE(Fixture, "tc_propagation")
{
CheckResult result = check("local a = 7 local b = a");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = check(XorStr("local a = 7 local b = a"));
lluz_REQUIRE_NO_ERRORS(result);
TypeId bType = requireType("b");
TypeId bType = requireType(XorStr("b"));
CHECK_EQ(getPrimitiveType(bType), PrimitiveTypeVar::Number);
}
TEST_CASE_FIXTURE(Fixture, "tc_error")
{
CheckResult result = check("local a = 7 local b = 'hi' a = b");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CheckResult result = check(XorStr("local a = 7 local b = 'hi' a = b"));
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(result.errors[0], (TypeError{Location{Position{0, 35}, Position{0, 36}}, TypeMismatch{typeChecker.numberType, typeChecker.stringType}}));
}
TEST_CASE_FIXTURE(Fixture, "tc_error_2")
{
CheckResult result = check("local a = 7 a = 'hi'");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CheckResult result = check(XorStr("local a = 7 a = 'hi'"));
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(result.errors[0], (TypeError{Location{Position{0, 18}, Position{0, 22}}, TypeMismatch{
requireType("a"),
@ -61,10 +60,10 @@ TEST_CASE_FIXTURE(Fixture, "tc_error_2")
TEST_CASE_FIXTURE(Fixture, "infer_locals_with_nil_value")
{
CheckResult result = check("local f = nil; f = 'hello world'");
LUAU_REQUIRE_NO_ERRORS(result);
CheckResult result = check(XorStr("local f = nil; f = 'hello world'"));
lluz_REQUIRE_NO_ERRORS(result);
TypeId ty = requireType("f");
TypeId ty = requireType(XorStr("f"));
CHECK_EQ(getPrimitiveType(ty), PrimitiveTypeVar::String);
}
@ -77,7 +76,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_locals_via_assignment_from_its_call_site")
f("foo")
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("number", toString(requireType("a")));
}
@ -85,28 +84,29 @@ TEST_CASE_FIXTURE(Fixture, "infer_locals_via_assignment_from_its_call_site")
TEST_CASE_FIXTURE(Fixture, "infer_in_nocheck_mode")
{
ScopedFastFlag sff[]{
{"DebugLuauDeferredConstraintResolution", false},
{"LuauLowerBoundsCalculation", true},
{"DebuglluzDeferredConstraintResolution", false},
{"lluzReturnTypeInferenceInNonstrict", true},
{"lluzLowerBoundsCalculation", true},
};
CheckResult result = check(R"(
--!nocheck
function f(x)
return x
return 5
end
-- we get type information even if there's type errors
f(1, 2)
)");
CHECK_EQ("(any) -> (...any)", toString(requireType("f")));
CHECK_EQ("(any) -> number", toString(requireType("f")));
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "expr_statement")
{
CheckResult result = check("local foo = 5 foo()");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CheckResult result = check(XorStr("local foo = 5 foo()"));
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "if_statement")
@ -122,7 +122,7 @@ TEST_CASE_FIXTURE(Fixture, "if_statement")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.stringType, *requireType("a"));
CHECK_EQ(*typeChecker.numberType, *requireType("b"));
@ -140,7 +140,7 @@ TEST_CASE_FIXTURE(Fixture, "statements_are_topologically_sorted")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result);
}
@ -156,7 +156,7 @@ TEST_CASE_FIXTURE(Fixture, "unify_nearly_identical_recursive_types")
o = p
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "warn_on_lowercase_parent_property")
@ -165,7 +165,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "warn_on_lowercase_parent_property")
local M = require(script.parent.DoesNotMatter)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
auto ed = get<DeprecatedApiUsed>(result.errors[0]);
REQUIRE(ed);
@ -180,7 +180,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "weird_case")
local d = math.deg(f())
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "dont_ice_when_failing_the_occurs_check")
@ -190,7 +190,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_ice_when_failing_the_occurs_check")
local s
s(s, 'a')
)");
LUAU_REQUIRE_ERROR_COUNT(0, result);
lluz_REQUIRE_ERROR_COUNT(0, result);
}
TEST_CASE_FIXTURE(Fixture, "occurs_check_does_not_recurse_forever_if_asked_to_traverse_a_cyclic_type")
@ -202,7 +202,7 @@ TEST_CASE_FIXTURE(Fixture, "occurs_check_does_not_recurse_forever_if_asked_to_tr
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
#if 0
@ -228,7 +228,7 @@ TEST_CASE_FIXTURE(Fixture, "type_errors_infer_types")
local f = err
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
UnknownProperty* err = get<UnknownProperty>(result.errors[0]);
REQUIRE(err != nullptr);
@ -236,23 +236,12 @@ TEST_CASE_FIXTURE(Fixture, "type_errors_infer_types")
CHECK_EQ("x", err->key);
// TODO: Should we assert anything about these tests when DCR is being used?
if (!FFlag::DebugLuauDeferredConstraintResolution)
if (!FFlag::DebugLluDeferredConstraintResolution)
{
if (FFlag::LuauSpecialTypesAsterisked)
{
CHECK_EQ("*error-type*", toString(requireType("c")));
CHECK_EQ("*error-type*", toString(requireType("d")));
CHECK_EQ("*error-type*", toString(requireType("e")));
CHECK_EQ("*error-type*", toString(requireType("f")));
}
else
{
CHECK_EQ("<error-type>", toString(requireType("c")));
CHECK_EQ("<error-type>", toString(requireType("d")));
CHECK_EQ("<error-type>", toString(requireType("e")));
CHECK_EQ("<error-type>", toString(requireType("f")));
}
CHECK_EQ("*unknown*", toString(requireType("c")));
CHECK_EQ("*unknown*", toString(requireType("d")));
CHECK_EQ("*unknown*", toString(requireType("e")));
CHECK_EQ("*unknown*", toString(requireType("f")));
}
}
@ -268,7 +257,7 @@ TEST_CASE_FIXTURE(Fixture, "should_be_able_to_infer_this_without_stack_overflowi
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "exponential_blowup_from_copying_types")
@ -301,7 +290,7 @@ TEST_CASE_FIXTURE(Fixture, "exponential_blowup_from_copying_types")
return x4
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
ModulePtr module = getMainModule();
// If we're not careful about copying, this ends up with O(2^N) types rather than O(N)
@ -313,7 +302,7 @@ TEST_CASE_FIXTURE(Fixture, "exponential_blowup_from_copying_types")
// checker. We also want it to somewhat match up with production values, so we push up the parser recursion limit a little bit instead.
TEST_CASE_FIXTURE(Fixture, "check_type_infer_recursion_count")
{
#if defined(LUAU_ENABLE_ASAN)
#if defined(lluz_ENABLE_ASAN)
int limit = 250;
#elif defined(_DEBUG) || defined(_NOOPT)
int limit = 350;
@ -321,17 +310,17 @@ TEST_CASE_FIXTURE(Fixture, "check_type_infer_recursion_count")
int limit = 600;
#endif
ScopedFastInt sfi{"LuauCheckRecursionLimit", limit};
ScopedFastInt sfi{"lluzCheckRecursionLimit", limit};
CheckResult result = check("function f() return " + rep("{a=", limit) + "'a'" + rep("}", limit) + " end");
CheckResult result = check(XorStr("function f() return XorStr(" + rep("){a=", limit) + "'a'" + rep("}", limit) + " end"));
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK(nullptr != get<CodeTooComplex>(result.errors[0]));
}
TEST_CASE_FIXTURE(Fixture, "check_block_recursion_limit")
{
#if defined(LUAU_ENABLE_ASAN)
#if defined(lluz_ENABLE_ASAN)
int limit = 250;
#elif defined(_DEBUG) || defined(_NOOPT)
int limit = 350;
@ -339,62 +328,33 @@ TEST_CASE_FIXTURE(Fixture, "check_block_recursion_limit")
int limit = 600;
#endif
ScopedFastInt luauRecursionLimit{"LuauRecursionLimit", limit + 100};
ScopedFastInt luauCheckRecursionLimit{"LuauCheckRecursionLimit", limit - 100};
ScopedFastInt lluzRecursionLimit{"lluzRecursionLimit", limit + 100};
ScopedFastInt lluzCheckRecursionLimit{"lluzCheckRecursionLimit", limit - 100};
CheckResult result = check(rep("do ", limit) + "local a = 1" + rep(" end", limit));
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK(nullptr != get<CodeTooComplex>(result.errors[0]));
}
TEST_CASE_FIXTURE(Fixture, "check_expr_recursion_limit")
{
#if defined(LUAU_ENABLE_ASAN)
#if defined(lluz_ENABLE_ASAN)
int limit = 250;
#elif defined(_DEBUG) || defined(_NOOPT)
int limit = 300;
#else
int limit = 600;
#endif
ScopedFastInt luauRecursionLimit{"LuauRecursionLimit", limit + 100};
ScopedFastInt luauCheckRecursionLimit{"LuauCheckRecursionLimit", limit - 100};
ScopedFastInt lluzRecursionLimit{"lluzRecursionLimit", limit + 100};
ScopedFastInt lluzCheckRecursionLimit{"lluzCheckRecursionLimit", limit - 100};
CheckResult result = check(R"(("foo"))" + rep(":lower()", limit));
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK(nullptr != get<CodeTooComplex>(result.errors[0]));
}
TEST_CASE_FIXTURE(Fixture, "globals")
{
CheckResult result = check(R"(
--!nonstrict
foo = true
foo = "now i'm a string!"
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("foo")));
}
TEST_CASE_FIXTURE(Fixture, "globals2")
{
CheckResult result = check(R"(
--!nonstrict
foo = function() return 1 end
foo = "now i'm a string!"
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
CHECK_EQ("() -> (...any)", toString(tm->wantedType));
CHECK_EQ("string", toString(tm->givenType));
CHECK_EQ("() -> (...any)", toString(requireType("foo")));
}
TEST_CASE_FIXTURE(Fixture, "globals_are_banned_in_strict_mode")
{
CheckResult result = check(R"(
@ -402,7 +362,7 @@ TEST_CASE_FIXTURE(Fixture, "globals_are_banned_in_strict_mode")
foo = true
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
UnknownSymbol* us = get<UnknownSymbol>(result.errors[0]);
REQUIRE(us);
@ -419,11 +379,11 @@ TEST_CASE_FIXTURE(Fixture, "correctly_scope_locals_do")
local b = a -- oops!
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
UnknownSymbol* us = get<UnknownSymbol>(result.errors[0]);
REQUIRE(us);
CHECK_EQ(us->name, "a");
CHECK_EQ(us->name, XorStr("a"));
}
TEST_CASE_FIXTURE(Fixture, "checking_should_not_ice")
@ -496,17 +456,17 @@ TEST_CASE_FIXTURE(Fixture, "tc_after_error_recovery")
local x =
local a = 7
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
TypeId aType = requireType("a");
TypeId aType = requireType(XorStr("a"));
CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::Number);
}
// Check that type checker knows about error expressions
TEST_CASE_FIXTURE(Fixture, "tc_after_error_recovery_no_assert")
{
CheckResult result = check("function +() local _ = true end");
LUAU_REQUIRE_ERRORS(result);
CheckResult result = check(XorStr("function +() local _ = true end"));
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_in_error")
@ -518,7 +478,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_
return t.
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
{
@ -528,7 +488,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_
export type = string
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
}
{
@ -537,7 +497,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_
function string.() end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
{
@ -547,7 +507,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_
local function () end
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
}
{
@ -558,7 +518,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_
function dm.() end
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
}
}
@ -570,7 +530,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_expr_should_be_checked")
print(foo[(true).x])
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
UnknownProperty* up = get<UnknownProperty>(result.errors[0]); // Should probably be NotATable
REQUIRE(up);
@ -586,7 +546,7 @@ TEST_CASE_FIXTURE(Fixture, "stringify_nested_unions_with_optionals")
local b: number = a
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
CHECK_EQ(typeChecker.numberType, tm->wantedType);
@ -600,7 +560,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_39932_use_unifier_in_ensure_methods")
local y = x[1] - x[2]
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstStatError")
@ -609,7 +569,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstStatError")
foo
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstExprError")
@ -618,7 +578,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstExprError")
local a = foo:
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
}
TEST_CASE_FIXTURE(Fixture, "dont_ice_on_astexprerror")
@ -627,10 +587,10 @@ TEST_CASE_FIXTURE(Fixture, "dont_ice_on_astexprerror")
local foo = -;
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "luau_resolves_symbols_the_same_way_lua_does")
TEST_CASE_FIXTURE(Fixture, "lluz_resolves_symbols_the_same_way_lua_does")
{
CheckResult result = check(R"(
--!strict
@ -641,7 +601,7 @@ TEST_CASE_FIXTURE(Fixture, "luau_resolves_symbols_the_same_way_lua_does")
local foo: string = 'hello'
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
auto e = result.errors.front();
REQUIRE_MESSAGE(get<UnknownSymbol>(e) != nullptr, "Expected UnknownSymbol, but got " << e);
@ -658,15 +618,11 @@ TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_isoptional")
_(nil)
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
std::optional<TypeFun> t0 = getMainModule()->getModuleScope()->lookupType("t0");
std::optional<TypeFun> t0 = getMainModule()->getModuleScope()->lookupType(XorStr("t0"));
REQUIRE(t0);
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(t0->type));
else
CHECK_EQ("<error-type>", toString(t0->type));
CHECK_EQ("*unknown*", toString(t0->type));
auto it = std::find_if(result.errors.begin(), result.errors.end(), [](TypeError& err) {
return get<OccursCheckFailed>(err);
@ -687,7 +643,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_stack_overflow_from_isoptional2")
local t: ({})|(t0)
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "no_infinite_loop_when_trying_to_unify_uh_this")
@ -701,7 +657,7 @@ TEST_CASE_FIXTURE(Fixture, "no_infinite_loop_when_trying_to_unify_uh_this")
_()
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "no_heap_use_after_free_error")
@ -718,7 +674,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_heap_use_after_free_error")
end
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "infer_type_assertion_value_type")
@ -729,7 +685,7 @@ local function f()
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "infer_assignment_value_types")
@ -744,7 +700,7 @@ local c: {number|string}
b, c = {2, "s"}, {"b", 4}
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "infer_assignment_value_types_mutable_lval")
@ -755,7 +711,7 @@ a.x = 2
a = setmetatable(a, { __call = function(x) end })
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "infer_through_group_expr")
@ -765,14 +721,14 @@ local function f(a: (number, number) -> number) return a(1, 3) end
f(((function(a, b) return a + b end)))
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions1")
{
CheckResult result = check(R"(local a = if true then "true" else "false")");
LUAU_REQUIRE_NO_ERRORS(result);
TypeId aType = requireType("a");
CheckResult result = check(RXorStr("(local a = if true then "true" else "false")"));
lluz_REQUIRE_NO_ERRORS(result);
TypeId aType = requireType(XorStr("a"));
CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::String);
}
@ -782,17 +738,17 @@ TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions2")
CheckResult result = check(R"(
local a = if false then "a" elseif false then "b" else "c"
)");
LUAU_REQUIRE_NO_ERRORS(result);
TypeId aType = requireType("a");
lluz_REQUIRE_NO_ERRORS(result);
TypeId aType = requireType(XorStr("a"));
CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::String);
}
TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions_type_union")
{
CheckResult result = check(R"(local a: number? = if true then 42 else nil)");
CheckResult result = check(RXorStr("(local a: number? = if true then 42 else nil)"));
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a"), {true}), "number?");
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType(XorStr("a"), {true}), "number?"));
}
TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions_expected_type_1")
@ -802,8 +758,8 @@ type X = {number | string}
local a: X = if true then {"1", 2, 3} else {4, 5, 6}
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a"), {true}), "{number | string}");
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType(XorStr("a"), {true}), "{number | string}"));
}
TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions_expected_type_2")
@ -812,7 +768,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions_expected_type_2")
local a: number? = if true then 1 else nil
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "tc_if_else_expressions_expected_type_3")
@ -826,7 +782,7 @@ local function times<T>(n: any, f: () -> T)
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
/*
@ -899,7 +855,7 @@ local b = getIt()
local c = a or b
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "bound_typepack_promote")
@ -951,7 +907,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_50041_committing_txnlog_in_apollo_client_error")
end
function Policies:getStoreFieldName(specifier: FieldSpecifier): string
return ""
return XorStr("")
end
function Policies:readField(options: ReadFieldOptions)
@ -964,12 +920,12 @@ TEST_CASE_FIXTURE(Fixture, "cli_50041_committing_txnlog_in_apollo_client_error")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_no_ice")
{
ScopedFastInt sfi("LuauTypeInferRecursionLimit", 2);
ScopedFastInt sfi("lluzTypeInferRecursionLimit", 2);
CheckResult result = check(R"(
function complex()
@ -981,7 +937,7 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_no_ice")
end
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
CHECK_EQ("Code is too complex to typecheck! Consider simplifying the code around this area", toString(result.errors[0]));
}
@ -1005,7 +961,7 @@ TEST_CASE_FIXTURE(Fixture, "follow_on_new_types_in_substitution")
return obj
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
/**
@ -1015,7 +971,7 @@ TEST_CASE_FIXTURE(Fixture, "follow_on_new_types_in_substitution")
TEST_CASE_FIXTURE(Fixture, "do_not_bind_a_free_table_to_a_union_containing_that_table")
{
ScopedFastFlag flag[] = {
{"LuauLowerBoundsCalculation", true},
{"lluzLowerBoundsCalculation", true},
};
CheckResult result = check(R"(
@ -1036,7 +992,7 @@ TEST_CASE_FIXTURE(Fixture, "do_not_bind_a_free_table_to_a_union_containing_that_
local B = A:f()
function B.g(t)
assert(type(t) == "table")
assert(type(t) == XorStr("table"))
assert(t.prop ~= nil)
end
@ -1056,7 +1012,7 @@ end
)");
auto node = findNodeAtPosition(*getMainSourceModule(), {2, 16});
auto ty = lookupType("alias");
auto ty = lookupType(XorStr("alias"));
REQUIRE(node);
REQUIRE(node->is<AstExprFunction>());
REQUIRE(ty);

View file

@ -1,15 +1,13 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Scope.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
using namespace lluz;
struct TryUnifyFixture : Fixture
{
@ -20,7 +18,7 @@ struct TryUnifyFixture : Fixture
Unifier state{&arena, Mode::Strict, Location{}, Variance::Covariant, unifierState};
};
TEST_SUITE_BEGIN("TryUnifyTests");
TEST_SUITE_BEGIN(XorStr("TryUnifyTests"));
TEST_CASE_FIXTURE(TryUnifyFixture, "primitives_unify")
{
@ -120,13 +118,10 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "members_of_failed_typepack_unification_are_u
f(a, b)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("a", toString(requireType("a")));
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(requireType("b")));
else
CHECK_EQ("<error-type>", toString(requireType("b")));
CHECK_EQ("*unknown*", toString(requireType("b")));
}
TEST_CASE_FIXTURE(TryUnifyFixture, "result_of_failed_typepack_unification_is_constrained")
@ -138,13 +133,10 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "result_of_failed_typepack_unification_is_con
local c = f(a, b)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("a", toString(requireType("a")));
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(requireType("b")));
else
CHECK_EQ("<error-type>", toString(requireType("b")));
CHECK_EQ("*unknown*", toString(requireType("b")));
CHECK_EQ("number", toString(requireType("c")));
}
@ -163,7 +155,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "typepack_unification_should_trim_free_tails"
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("(number) -> boolean", toString(requireType("f")));
}
@ -197,11 +189,11 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "variadics_should_use_reversed_properly")
local x: string = f(1)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm);
CHECK_EQ(toString(tm->givenType), "number");
CHECK_EQ(toString(tm->wantedType), "string");
CHECK_EQ(toString(tm->givenType), XorStr("number"));
CHECK_EQ(toString(tm->wantedType), XorStr("string"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "cli_41095_concat_log_in_sealed_table_unification")
@ -211,9 +203,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cli_41095_concat_log_in_sealed_table_unifica
table.insert()
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(toString(result.errors[0]), "No overload for function accepts 0 arguments.");
CHECK_EQ(toString(result.errors[1]), "Available overloads: ({a}, a) -> (); and ({a}, number, a) -> ()");
lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(toString(result.errors[0]), XorStr("No overload for function accepts 0 arguments."));
CHECK_EQ(toString(result.errors[1]), XorStr("Available overloads: ({a}, a) -> (); and ({a}, number, a) -> ()"));
}
TEST_CASE_FIXTURE(TryUnifyFixture, "free_tail_is_grown_properly")

View file

@ -1,17 +1,17 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/BuiltinDefinitions.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
LUAU_FASTFLAG(LuauLowerBoundsCalculation);
lluz_FASTFLAG(LluLowerBoundsCalculation);
TEST_SUITE_BEGIN("TypePackTests");
TEST_SUITE_BEGIN(XorStr("TypePackTests"));
TEST_CASE_FIXTURE(Fixture, "infer_multi_return")
{
@ -21,7 +21,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_multi_return")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* takeTwoType = get<FunctionTypeVar>(requireType("take_two"));
REQUIRE(takeTwoType != nullptr);
@ -41,7 +41,7 @@ TEST_CASE_FIXTURE(Fixture, "empty_varargs_should_return_nil_when_not_in_tail_pos
local a, b = ..., 1
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "self_and_varargs_should_work")
@ -52,7 +52,7 @@ TEST_CASE_FIXTURE(Fixture, "self_and_varargs_should_work")
t:f(1)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "last_element_of_return_statement_can_itself_be_a_pack")
@ -67,7 +67,7 @@ TEST_CASE_FIXTURE(Fixture, "last_element_of_return_statement_can_itself_be_a_pac
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result);
const FunctionTypeVar* takeOneMoreType = get<FunctionTypeVar>(requireType("take_three"));
@ -91,7 +91,7 @@ TEST_CASE_FIXTURE(Fixture, "higher_order_function")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("<a, b..., c...>((b...) -> (c...), (a) -> (b...), a) -> (c...)", toString(requireType("apply")));
}
@ -102,7 +102,7 @@ TEST_CASE_FIXTURE(Fixture, "return_type_should_be_empty_if_nothing_is_returned")
function f() end
function g() return end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* fTy = get<FunctionTypeVar>(requireType("f"));
REQUIRE(fTy != nullptr);
CHECK_EQ(0, size(fTy->retTypes));
@ -121,7 +121,7 @@ TEST_CASE_FIXTURE(Fixture, "no_return_size_should_be_zero")
g(h())
f(g(),h())
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* fTy = get<FunctionTypeVar>(requireType("f"));
REQUIRE(fTy != nullptr);
@ -149,7 +149,7 @@ TEST_CASE_FIXTURE(Fixture, "varargs_inference_through_multiple_scopes")
f("foo")
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "multiple_varargs_inference_are_not_confused")
@ -166,7 +166,7 @@ TEST_CASE_FIXTURE(Fixture, "multiple_varargs_inference_are_not_confused")
f("foo", "bar")(1, 2)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "parenthesized_varargs_returns_any")
@ -180,7 +180,7 @@ TEST_CASE_FIXTURE(Fixture, "parenthesized_varargs_returns_any")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("value")));
}
@ -223,7 +223,7 @@ TEST_CASE_FIXTURE(Fixture, "variadic_packs")
bar(1, "foo", "bar", 3)
)");
LUAU_REQUIRE_ERROR_COUNT(2, result);
lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(result.errors[0], (TypeError{Location(Position{3, 21}, Position{3, 26}), TypeMismatch{typeChecker.numberType, typeChecker.stringType}}));
@ -241,8 +241,8 @@ TEST_CASE_FIXTURE(Fixture, "variadic_pack_syntax")
foo(1, 2, 3, 4, 5, 6)
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("foo")), "(...number) -> ()");
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType(XorStr("foo")), "(...number) -> ()"));
}
TEST_CASE_FIXTURE(Fixture, "type_pack_hidden_free_tail_infinite_growth")
@ -259,7 +259,7 @@ elseif _ then
end
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "variadic_argument_tail")
@ -272,7 +272,7 @@ for y in _() do
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "type_alias_type_packs")
@ -284,14 +284,14 @@ local b: Packed<number>
local c: Packed<string, number>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
auto tf = lookupType("Packed");
auto tf = lookupType(XorStr("Packed"));
REQUIRE(tf);
CHECK_EQ(toString(*tf), "(T...) -> (T...)");
CHECK_EQ(toString(requireType("a")), "() -> ()");
CHECK_EQ(toString(requireType("b")), "(number) -> number");
CHECK_EQ(toString(requireType("c")), "(string, number) -> (string, number)");
CHECK_EQ(toString(*tf), XorStr("(T...) -> (T...)"));
CHECK_EQ(toString(requireType(XorStr("a")), "() -> ()"));
CHECK_EQ(toString(requireType(XorStr("b")), "(number) -> number"));
CHECK_EQ(toString(requireType(XorStr("c")), "(string, number) -> (string, number)"));
result = check(R"(
-- (U..., T) cannot be parsed right now
@ -301,42 +301,42 @@ local b: Packed<string, number>
local c: Packed<string, number, boolean>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
tf = lookupType("Packed");
tf = lookupType(XorStr("Packed"));
REQUIRE(tf);
CHECK_EQ(toString(*tf), "Packed<T, U...>");
CHECK_EQ(toString(*tf, {true}), "{| f: (T, U...) -> (T, U...) |}");
CHECK_EQ(toString(*tf), XorStr("Packed<T, U...>"));
CHECK_EQ(toString(*tf, {true}), XorStr("{| f: (T, U...) -> (T, U...) |}"));
auto ttvA = get<TableTypeVar>(requireType("a"));
REQUIRE(ttvA);
CHECK_EQ(toString(requireType("a")), "Packed<number>");
if (FFlag::LuauLowerBoundsCalculation)
CHECK_EQ(toString(requireType("a"), {true}), "{| f: (number) -> number |}");
CHECK_EQ(toString(requireType(XorStr("a")), "Packed<number>"));
if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ(toString(requireType(XorStr("a"), {true}), "{| f: (number) -> number |}"));
else
CHECK_EQ(toString(requireType("a"), {true}), "{| f: (number) -> (number) |}");
CHECK_EQ(toString(requireType(XorStr("a"), {true}), "{| f: (number) -> (number) |}"));
REQUIRE(ttvA->instantiatedTypeParams.size() == 1);
REQUIRE(ttvA->instantiatedTypePackParams.size() == 1);
CHECK_EQ(toString(ttvA->instantiatedTypeParams[0], {true}), "number");
CHECK_EQ(toString(ttvA->instantiatedTypePackParams[0], {true}), "");
CHECK_EQ(toString(ttvA->instantiatedTypeParams[0], {true}), XorStr("number"));
CHECK_EQ(toString(ttvA->instantiatedTypePackParams[0], {true}), XorStr(""));
auto ttvB = get<TableTypeVar>(requireType("b"));
REQUIRE(ttvB);
CHECK_EQ(toString(requireType("b")), "Packed<string, number>");
CHECK_EQ(toString(requireType("b"), {true}), "{| f: (string, number) -> (string, number) |}");
CHECK_EQ(toString(requireType(XorStr("b")), "Packed<string, number>"));
CHECK_EQ(toString(requireType(XorStr("b"), {true}), "{| f: (string, number) -> (string, number) |}"));
REQUIRE(ttvB->instantiatedTypeParams.size() == 1);
REQUIRE(ttvB->instantiatedTypePackParams.size() == 1);
CHECK_EQ(toString(ttvB->instantiatedTypeParams[0], {true}), "string");
CHECK_EQ(toString(ttvB->instantiatedTypePackParams[0], {true}), "number");
CHECK_EQ(toString(ttvB->instantiatedTypeParams[0], {true}), XorStr("string"));
CHECK_EQ(toString(ttvB->instantiatedTypePackParams[0], {true}), XorStr("number"));
auto ttvC = get<TableTypeVar>(requireType("c"));
REQUIRE(ttvC);
CHECK_EQ(toString(requireType("c")), "Packed<string, number, boolean>");
CHECK_EQ(toString(requireType("c"), {true}), "{| f: (string, number, boolean) -> (string, number, boolean) |}");
CHECK_EQ(toString(requireType(XorStr("c")), "Packed<string, number, boolean>"));
CHECK_EQ(toString(requireType(XorStr("c"), {true}), "{| f: (string, number, boolean) -> (string, number, boolean) |}"));
REQUIRE(ttvC->instantiatedTypeParams.size() == 1);
REQUIRE(ttvC->instantiatedTypePackParams.size() == 1);
CHECK_EQ(toString(ttvC->instantiatedTypeParams[0], {true}), "string");
CHECK_EQ(toString(ttvC->instantiatedTypePackParams[0], {true}), "number, boolean");
CHECK_EQ(toString(ttvC->instantiatedTypeParams[0], {true}), XorStr("string"));
CHECK_EQ(toString(ttvC->instantiatedTypePackParams[0], {true}), XorStr("number, boolean"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_type_packs_import")
@ -346,8 +346,8 @@ export type Packed<T, U...> = { a: T, b: (U...) -> () }
return {}
)";
CheckResult aResult = frontend.check("game/A");
LUAU_REQUIRE_NO_ERRORS(aResult);
CheckResult aResult = frontend.check(XorStr("game/A"));
lluz_REQUIRE_NO_ERRORS(aResult);
CheckResult bResult = check(R"(
local Import = require(game.A)
@ -356,17 +356,17 @@ local b: Import.Packed<string, number>
local c: Import.Packed<string, number, boolean>
local d: { a: typeof(c) }
)");
LUAU_REQUIRE_NO_ERRORS(bResult);
lluz_REQUIRE_NO_ERRORS(bResult);
auto tf = lookupImportedType("Import", "Packed");
auto tf = lookupImportedType(XorStr("Import", "Packed"));
REQUIRE(tf);
CHECK_EQ(toString(*tf), "Packed<T, U...>");
CHECK_EQ(toString(*tf, {true}), "{| a: T, b: (U...) -> () |}");
CHECK_EQ(toString(*tf), XorStr("Packed<T, U...>"));
CHECK_EQ(toString(*tf, {true}), XorStr("{| a: T, b: (U...) -> () |}"));
CHECK_EQ(toString(requireType("a"), {true}), "{| a: number, b: () -> () |}");
CHECK_EQ(toString(requireType("b"), {true}), "{| a: string, b: (number) -> () |}");
CHECK_EQ(toString(requireType("c"), {true}), "{| a: string, b: (number, boolean) -> () |}");
CHECK_EQ(toString(requireType("d")), "{| a: Packed<string, number, boolean> |}");
CHECK_EQ(toString(requireType(XorStr("a"), {true}), "{| a: number, b: () -> () |}"));
CHECK_EQ(toString(requireType(XorStr("b"), {true}), "{| a: string, b: (number) -> () |}"));
CHECK_EQ(toString(requireType(XorStr("c"), {true}), "{| a: string, b: (number, boolean) -> () |}"));
CHECK_EQ(toString(requireType(XorStr("d")), "{| a: Packed<string, number, boolean> |}"));
}
TEST_CASE_FIXTURE(BuiltinsFixture, "type_pack_type_parameters")
@ -384,24 +384,24 @@ local a: Alias<string, number, boolean>
type B<X...> = Import.Packed<string, X...>
type C<X...> = Import.Packed<string, (number, X...)>
)");
LUAU_REQUIRE_NO_ERRORS(cResult);
lluz_REQUIRE_NO_ERRORS(cResult);
auto tf = lookupType("Alias");
auto tf = lookupType(XorStr("Alias"));
REQUIRE(tf);
CHECK_EQ(toString(*tf), "Alias<S, T, R...>");
CHECK_EQ(toString(*tf, {true}), "{| a: S, b: (T, R...) -> () |}");
CHECK_EQ(toString(*tf), XorStr("Alias<S, T, R...>"));
CHECK_EQ(toString(*tf, {true}), XorStr("{| a: S, b: (T, R...) -> () |}"));
CHECK_EQ(toString(requireType("a"), {true}), "{| a: string, b: (number, boolean) -> () |}");
CHECK_EQ(toString(requireType(XorStr("a"), {true}), "{| a: string, b: (number, boolean) -> () |}"));
tf = lookupType("B");
tf = lookupType(XorStr("B"));
REQUIRE(tf);
CHECK_EQ(toString(*tf), "B<X...>");
CHECK_EQ(toString(*tf, {true}), "{| a: string, b: (X...) -> () |}");
CHECK_EQ(toString(*tf), XorStr("B<X...>"));
CHECK_EQ(toString(*tf, {true}), XorStr("{| a: string, b: (X...) -> () |}"));
tf = lookupType("C");
tf = lookupType(XorStr("C"));
REQUIRE(tf);
CHECK_EQ(toString(*tf), "C<X...>");
CHECK_EQ(toString(*tf, {true}), "{| a: string, b: (number, X...) -> () |}");
CHECK_EQ(toString(*tf), XorStr("C<X...>"));
CHECK_EQ(toString(*tf, {true}), XorStr("{| a: string, b: (number, X...) -> () |}"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_type_packs_nested")
@ -413,13 +413,13 @@ type Packed3<T...> = (Packed2<T...>, T...) -> (Packed2<T...>, T...)
type Packed4<T...> = (Packed3<T...>, T...) -> (Packed3<T...>, T...)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
auto tf = lookupType("Packed4");
auto tf = lookupType(XorStr("Packed4"));
REQUIRE(tf);
CHECK_EQ(toString(*tf),
"((((T...) -> (T...), T...) -> ((T...) -> (T...), T...), T...) -> (((T...) -> (T...), T...) -> ((T...) -> (T...), T...), T...), T...) -> "
"((((T...) -> (T...), T...) -> ((T...) -> (T...), T...), T...) -> (((T...) -> (T...), T...) -> ((T...) -> (T...), T...), T...), T...)");
XorStr("((((T...) -> (T...), T...) -> ((T...) -> (T...), T...), T...) -> (((T...) -> (T...), T...) -> ((T...) -> (T...), T...), T...), T...)"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_type_pack_variadic")
@ -431,10 +431,10 @@ type D = X<...number>
type E = X<(number, ...string)>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(*lookupType("D")), "(...number) -> (string, ...number)");
CHECK_EQ(toString(*lookupType("E")), "(number, ...string) -> (string, number, ...string)");
CHECK_EQ(toString(*lookupType(XorStr("D")), "(...number) -> (string, ...number)"));
CHECK_EQ(toString(*lookupType(XorStr("E")), "(number, ...string) -> (string, number, ...string)"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_type_pack_multi")
@ -453,16 +453,16 @@ type H<S..., R...> = W<number, S..., R...>
type I<S..., R...> = W<number, (string, S...), R...>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(*lookupType("A")), "(S...) -> (S...)");
CHECK_EQ(toString(*lookupType("B")), "(number, ...string) -> (S...)");
CHECK_EQ(toString(*lookupType(XorStr("A")), "(S...) -> (S...)"));
CHECK_EQ(toString(*lookupType(XorStr("B")), "(number, ...string) -> (S...)"));
CHECK_EQ(toString(*lookupType("E")), "(number) -> (S...)");
CHECK_EQ(toString(*lookupType("F")), "(number) -> (string, S...)");
CHECK_EQ(toString(*lookupType(XorStr("E")), "(number) -> (S...)"));
CHECK_EQ(toString(*lookupType(XorStr("F")), "(number) -> (string, S...)"));
CHECK_EQ(toString(*lookupType("H")), "(number, S...) -> (number, R...)");
CHECK_EQ(toString(*lookupType("I")), "(number, string, S...) -> (number, R...)");
CHECK_EQ(toString(*lookupType(XorStr("H")), "(number, S...) -> (number, R...)"));
CHECK_EQ(toString(*lookupType(XorStr("I")), "(number, string, S...) -> (number, R...)"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_type_pack_explicit")
@ -478,14 +478,14 @@ type E = X<(...number)>
type F = X<(string, ...number)>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(*lookupType("A")), "(S...) -> (S...)");
CHECK_EQ(toString(*lookupType("B")), "() -> ()");
CHECK_EQ(toString(*lookupType("C")), "(number) -> number");
CHECK_EQ(toString(*lookupType("D")), "(number, string) -> (number, string)");
CHECK_EQ(toString(*lookupType("E")), "(...number) -> (...number)");
CHECK_EQ(toString(*lookupType("F")), "(string, ...number) -> (string, ...number)");
CHECK_EQ(toString(*lookupType(XorStr("A")), "(S...) -> (S...)"));
CHECK_EQ(toString(*lookupType(XorStr("B")), "() -> ()"));
CHECK_EQ(toString(*lookupType(XorStr("C")), "(number) -> number"));
CHECK_EQ(toString(*lookupType(XorStr("D")), "(number, string) -> (number, string)"));
CHECK_EQ(toString(*lookupType(XorStr("E")), "(...number) -> (...number)"));
CHECK_EQ(toString(*lookupType(XorStr("F")), "(string, ...number) -> (string, ...number)"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_type_pack_explicit_multi")
@ -499,12 +499,12 @@ type C<S...> = Y<...string, (number, S...)>
type D<X...> = Y<X..., (number, string, X...)>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(*lookupType("A")), "(number, string) -> boolean");
CHECK_EQ(toString(*lookupType("B")), "() -> ()");
CHECK_EQ(toString(*lookupType("C")), "(...string) -> (number, S...)");
CHECK_EQ(toString(*lookupType("D")), "(X...) -> (number, string, X...)");
CHECK_EQ(toString(*lookupType(XorStr("A")), "(number, string) -> boolean"));
CHECK_EQ(toString(*lookupType(XorStr("B")), "() -> ()"));
CHECK_EQ(toString(*lookupType(XorStr("C")), "(...string) -> (number, S...)"));
CHECK_EQ(toString(*lookupType(XorStr("D")), "(X...) -> (number, string, X...)"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_type_pack_explicit_multi_tostring")
@ -516,10 +516,10 @@ local a: Y<(number, string), (boolean)>
local b: Y<(), ()>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "Y<(number, string), (boolean)>");
CHECK_EQ(toString(requireType("b")), "Y<(), ()>");
CHECK_EQ(toString(requireType(XorStr("a")), "Y<(number, string), (boolean)>"));
CHECK_EQ(toString(requireType(XorStr("b")), "Y<(), ()>"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_backwards_compatible")
@ -533,11 +533,11 @@ type B = Y<(number), (boolean)>
type C = Y<(number), boolean>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(*lookupType("A")), "() -> number");
CHECK_EQ(toString(*lookupType("B")), "(number) -> boolean");
CHECK_EQ(toString(*lookupType("C")), "(number) -> boolean");
CHECK_EQ(toString(*lookupType(XorStr("A")), "() -> number"));
CHECK_EQ(toString(*lookupType(XorStr("B")), "(number) -> boolean"));
CHECK_EQ(toString(*lookupType(XorStr("C")), "(number) -> boolean"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_type_packs_errors")
@ -547,56 +547,56 @@ type Packed<T, U, V...> = (T, U) -> (V...)
local b: Packed<number>
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Generic type 'Packed<T, U, V...>' expects at least 2 type arguments, but only 1 is specified");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Generic type 'Packed<T, U, V...>' expects at least 2 type arguments, but only 1 is specified"));
result = check(R"(
type Packed<T, U> = (T, U) -> ()
type B<X...> = Packed<number, string, X...>
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Generic type 'Packed<T, U>' expects 0 type pack arguments, but 1 is specified");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Generic type 'Packed<T, U>' expects 0 type pack arguments, but 1 is specified"));
result = check(R"(
type Packed<T..., U...> = (T...) -> (U...)
type Other<S...> = Packed<S..., string>
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Type parameters must come before type pack parameters");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Type parameters must come before type pack parameters"));
result = check(R"(
type Packed<T, U> = (T) -> U
type Other<S...> = Packed<number, S...>
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Generic type 'Packed<T, U>' expects 2 type arguments, but only 1 is specified");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Generic type 'Packed<T, U>' expects 2 type arguments, but only 1 is specified"));
result = check(R"(
type Packed<T...> = (T...) -> T...
local a: Packed
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Type parameter list is required");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Type parameter list is required"));
result = check(R"(
type Packed<T..., U...> = (T...) -> (U...)
type Other = Packed<>
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Generic type 'Packed<T..., U...>' expects 2 type pack arguments, but none are specified");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Generic type 'Packed<T..., U...>' expects 2 type pack arguments, but none are specified"));
result = check(R"(
type Packed<T..., U...> = (T...) -> (U...)
type Other = Packed<number, string>
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Generic type 'Packed<T..., U...>' expects 2 type pack arguments, but only 1 is specified");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Generic type 'Packed<T..., U...>' expects 2 type pack arguments, but only 1 is specified"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_explicit")
@ -608,10 +608,10 @@ local a: Y<number, number> = { a = 2, b = 3 }
local b: Y<number> = { a = 2, b = "s" }
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "Y<number, number>");
CHECK_EQ(toString(requireType("b")), "Y<number, string>");
CHECK_EQ(toString(requireType(XorStr("a")), "Y<number, number>"));
CHECK_EQ(toString(requireType(XorStr("b")), "Y<number, string>"));
result = check(R"(
type Y<T = string> = { a: T }
@ -621,11 +621,11 @@ local b: Y<> = { a = "s" }
local c: Y = { a = "s" }
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "Y<number>");
CHECK_EQ(toString(requireType("b")), "Y<string>");
CHECK_EQ(toString(requireType("c")), "Y<string>");
CHECK_EQ(toString(requireType(XorStr("a")), "Y<number>"));
CHECK_EQ(toString(requireType(XorStr("b")), "Y<string>"));
CHECK_EQ(toString(requireType(XorStr("c")), "Y<string>"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_self")
@ -637,10 +637,10 @@ local a: Y<number> = { a = 2, b = 3 }
local b: Y<string> = { a = "h", b = "s" }
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "Y<number, number>");
CHECK_EQ(toString(requireType("b")), "Y<string, string>");
CHECK_EQ(toString(requireType(XorStr("a")), "Y<number, number>"));
CHECK_EQ(toString(requireType(XorStr("b")), "Y<string, string>"));
result = check(R"(
type Y<T, U = (T, T) -> string> = { a: T, b: U }
@ -648,9 +648,9 @@ type Y<T, U = (T, T) -> string> = { a: T, b: U }
local a: Y<number>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "Y<number, (number, number) -> string>");
CHECK_EQ(toString(requireType(XorStr("a")), "Y<number, (number, number) -> string>"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_chained")
@ -662,10 +662,10 @@ local a: Y<number>
local b: Y<number, string>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "Y<number, number, number>");
CHECK_EQ(toString(requireType("b")), "Y<number, string, string>");
CHECK_EQ(toString(requireType(XorStr("a")), "Y<number, number, number>"));
CHECK_EQ(toString(requireType(XorStr("b")), "Y<number, string, string>"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_pack_explicit")
@ -675,9 +675,9 @@ type Y<T... = (string, number)> = { a: (T...) -> () }
local a: Y<>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "Y<string, number>");
CHECK_EQ(toString(requireType(XorStr("a")), "Y<string, number>"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_pack_self_ty")
@ -688,9 +688,9 @@ type Y<T, U... = ...T> = { a: T, b: (U...) -> T }
local a: Y<number>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "Y<number, ...number>");
CHECK_EQ(toString(requireType(XorStr("a")), "Y<number, ...number>"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_pack_self_tp")
@ -700,9 +700,9 @@ type Y<T..., U... = T...> = { a: (T...) -> U... }
local a: Y<number, string>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "Y<(number, string), (number, string)>");
CHECK_EQ(toString(requireType(XorStr("a")), "Y<(number, string), (number, string)>"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_pack_self_chained_tp")
@ -712,9 +712,9 @@ type Y<T..., U... = T..., V... = U...> = { a: (T...) -> U..., b: (T...) -> V...
local a: Y<number, string>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "Y<(number, string), (number, string), (number, string)>");
CHECK_EQ(toString(requireType(XorStr("a")), "Y<(number, string), (number, string), (number, string)>"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_default_mixed_self")
@ -727,12 +727,12 @@ local c: Y<number, string, ...boolean>
local d: Y<number, string, ...boolean, ...() -> ()>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "Y<number, number, ...number, (number, number, ...number)>");
CHECK_EQ(toString(requireType("b")), "Y<number, string, ...number, (number, string, ...number)>");
CHECK_EQ(toString(requireType("c")), "Y<number, string, ...boolean, (number, string, ...boolean)>");
CHECK_EQ(toString(requireType("d")), "Y<number, string, ...boolean, ...() -> ()>");
CHECK_EQ(toString(requireType(XorStr("a")), "Y<number, number, ...number, (number, number, ...number)>"));
CHECK_EQ(toString(requireType(XorStr("b")), "Y<number, string, ...number, (number, string, ...number)>"));
CHECK_EQ(toString(requireType(XorStr("c")), "Y<number, string, ...boolean, (number, string, ...boolean)>"));
CHECK_EQ(toString(requireType(XorStr("d")), "Y<number, string, ...boolean, ...() -> ()>"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors")
@ -742,46 +742,46 @@ type Y<T = T> = { a: T }
local a: Y = { a = 2 }
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Unknown type 'T'");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Unknown type 'T'"));
result = check(R"(
type Y<T... = T...> = { a: (T...) -> () }
local a: Y<>
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Unknown type 'T'");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Unknown type 'T'"));
result = check(R"(
type Y<T = string, U... = ...string> = { a: (T) -> U... }
local a: Y<...number>
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Generic type 'Y<T, U...>' expects at least 1 type argument, but none are specified");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Generic type 'Y<T, U...>' expects at least 1 type argument, but none are specified"));
result = check(R"(
type Packed<T> = (T) -> T
local a: Packed
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Type parameter list is required");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), XorStr("Type parameter list is required"));
result = check(R"(
type Y<T, U = T, V> = { a: T }
local a: Y<number>
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
result = check(R"(
type Y<T..., U... = T..., V...> = { a: T }
local a: Y<...number>
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_default_export")
@ -798,8 +798,8 @@ export type H<T... = ()> = { b: (T...) -> T... }
return {}
)";
CheckResult resultTypes = frontend.check("Module/Types");
LUAU_REQUIRE_NO_ERRORS(resultTypes);
CheckResult resultTypes = frontend.check(XorStr("Module/Types"));
lluz_REQUIRE_NO_ERRORS(resultTypes);
fileResolver.source["Module/Users"] = R"(
local Types = require(script.Parent.Types)
@ -815,18 +815,18 @@ local g: Types.G<...number>
local h: Types.H<>
)";
CheckResult resultUsers = frontend.check("Module/Users");
LUAU_REQUIRE_NO_ERRORS(resultUsers);
CheckResult resultUsers = frontend.check(XorStr("Module/Users"));
lluz_REQUIRE_NO_ERRORS(resultUsers);
CHECK_EQ(toString(requireType("Module/Users", "a")), "A<number, string>");
CHECK_EQ(toString(requireType("Module/Users", "b")), "B<number, number>");
CHECK_EQ(toString(requireType("Module/Users", "c")), "C<number, (number, number) -> string>");
CHECK_EQ(toString(requireType("Module/Users", "d")), "D<number, number, number>");
CHECK_EQ(toString(requireType("Module/Users", "e")), "E<string, number>");
CHECK_EQ(toString(requireType("Module/Users", "eVoid")), "E<>");
CHECK_EQ(toString(requireType("Module/Users", "f")), "F<number, ...number>");
CHECK_EQ(toString(requireType("Module/Users", "g")), "G<...number, ()>");
CHECK_EQ(toString(requireType("Module/Users", "h")), "H<>");
CHECK_EQ(toString(requireType(XorStr("Module/Users", "a")), "A<number, string>"));
CHECK_EQ(toString(requireType(XorStr("Module/Users", "b")), "B<number, number>"));
CHECK_EQ(toString(requireType(XorStr("Module/Users", "c")), "C<number, (number, number) -> string>"));
CHECK_EQ(toString(requireType(XorStr("Module/Users", "d")), "D<number, number, number>"));
CHECK_EQ(toString(requireType(XorStr("Module/Users", "e")), "E<string, number>"));
CHECK_EQ(toString(requireType(XorStr("Module/Users", "eVoid")), "E<>"));
CHECK_EQ(toString(requireType(XorStr("Module/Users", "f")), "F<number, ...number>"));
CHECK_EQ(toString(requireType(XorStr("Module/Users", "g")), "G<...number, ()>"));
CHECK_EQ(toString(requireType(XorStr("Module/Users", "h")), "H<>"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_skip_brackets")
@ -836,9 +836,9 @@ type Y<T... = ...string> = (T...) -> number
local a: Y
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "(...string) -> number");
CHECK_EQ(toString(requireType(XorStr("a")), "(...string) -> number"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_defaults_confusing_types")
@ -849,10 +849,10 @@ type B = A<string, (number)>
type C = A<string, (number), (boolean)>
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(*lookupType("B"), {true}), "(string, ...any) -> (number, ...any)");
CHECK_EQ(toString(*lookupType("C"), {true}), "(string, boolean) -> (number, boolean)");
CHECK_EQ(toString(*lookupType(XorStr("B"), {true}), "(string, ...any) -> (number, ...any)"));
CHECK_EQ(toString(*lookupType(XorStr("C"), {true}), "(string, boolean) -> (number, boolean)"));
}
TEST_CASE_FIXTURE(Fixture, "type_alias_defaults_recursive_type")
@ -862,9 +862,9 @@ type F<K = string, V = (K) -> ()> = (K) -> V
type R = { m: F<R> }
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(*lookupType("R"), {true}), "t1 where t1 = {| m: (t1) -> (t1) -> () |}");
CHECK_EQ(toString(*lookupType(XorStr("R"), {true}), "t1 where t1 = {| m: (t1) -> (t1) -> () |}"));
}
TEST_CASE_FIXTURE(Fixture, "pack_tail_unification_check")
@ -875,7 +875,7 @@ local b: () -> (number, ...boolean)
a = b
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), R"(Type '() -> (number, ...boolean)' could not be converted into '() -> (number, ...string)'
caused by:
Type 'boolean' could not be converted into 'string')");
@ -890,7 +890,7 @@ TEST_CASE_FIXTURE(Fixture, "unifying_vararg_pack_with_fixed_length_pack_produces
a(...)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
REQUIRE(bool(getMainModule()->getModuleScope()->varargPack));
@ -949,7 +949,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "detect_cyclic_typepacks")
( ... ) ""
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "detect_cyclic_typepacks2")
@ -961,7 +961,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "detect_cyclic_typepacks2")
end
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_SUITE_END();

View file

@ -1,17 +1,16 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "Fixture.h"
#include "doctest.h"
LUAU_FASTFLAG(LuauLowerBoundsCalculation)
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
lluz_FASTFLAG(LluLowerBoundsCalculation)
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("UnionTypes");
TEST_SUITE_BEGIN(XorStr("UnionTypes"));
TEST_CASE_FIXTURE(Fixture, "return_types_can_be_disjoint")
{
@ -27,7 +26,7 @@ TEST_CASE_FIXTURE(Fixture, "return_types_can_be_disjoint")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* utv = get<FunctionTypeVar>(requireType("most_of_the_natural_numbers"));
REQUIRE(utv != nullptr);
@ -39,7 +38,7 @@ TEST_CASE_FIXTURE(Fixture, "allow_specific_assign")
local a:number|string = 22
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "allow_more_specific_assign")
@ -49,7 +48,7 @@ TEST_CASE_FIXTURE(Fixture, "allow_more_specific_assign")
local b:number|string|nil = a
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "disallow_less_specific_assign")
@ -60,7 +59,7 @@ TEST_CASE_FIXTURE(Fixture, "disallow_less_specific_assign")
a = b
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
}
TEST_CASE_FIXTURE(Fixture, "disallow_less_specific_assign2")
@ -82,7 +81,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_arguments")
f("s")
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "optional_arguments_table")
@ -92,7 +91,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_arguments_table")
a = {a="ok"}
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "optional_arguments_table2")
@ -111,7 +110,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "error_takes_optional_arguments")
error("message", 2)
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "error_optional_argument_enforces_type")
@ -133,7 +132,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_with_property_guaranteed_to_ex
local r = t.x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("r"));
}
@ -147,7 +146,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_with_mixed_types")
local r = t.x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number | string", toString(requireType("r")));
}
@ -161,7 +160,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_works_at_arbitrary_depth")
local r = t.x.y.z.thing
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number | string", toString(requireType("r")));
}
@ -175,7 +174,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_with_one_optional_property")
local r = t.x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number?", toString(requireType("r")));
}
@ -189,21 +188,18 @@ TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_with_missing_property")
local r = t.x
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
MissingUnionProperty* mup = get<MissingUnionProperty>(result.errors[0]);
REQUIRE(mup);
CHECK_EQ(mup->type, requireType("t"));
REQUIRE(mup->missing.size() == 1);
std::optional<TypeId> bTy = lookupType("B");
std::optional<TypeId> bTy = lookupType(XorStr("B"));
REQUIRE(bTy);
CHECK_EQ(mup->missing[0], *bTy);
CHECK_EQ(mup->key, "x");
CHECK_EQ(mup->key, XorStr("x"));
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(requireType("r")));
else
CHECK_EQ("<error-type>", toString(requireType("r")));
CHECK_EQ("*unknown*", toString(requireType("r")));
}
TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_with_one_property_of_type_any")
@ -216,7 +212,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_with_one_property_of_type_any"
local r = t.x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.anyType, *requireType("r"));
}
@ -237,7 +233,7 @@ TEST_CASE_FIXTURE(Fixture, "union_equality_comparisons")
local z = a == c
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "optional_union_members")
@ -250,7 +246,7 @@ local bf = b
local c = bf.a.y
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(*typeChecker.numberType, *requireType("c"));
CHECK_EQ("Value of type 'A?' could be nil", toString(result.errors[0]));
}
@ -265,7 +261,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_union_functions")
local c = b.foo(1, 2)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(*typeChecker.numberType, *requireType("c"));
CHECK_EQ("Value of type 'A?' could be nil", toString(result.errors[0]));
}
@ -280,7 +276,7 @@ local b: A? = a
local c = b:foo(1, 2)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(*typeChecker.numberType, *requireType("c"));
CHECK_EQ("Value of type 'A?' could be nil", toString(result.errors[0]));
}
@ -294,7 +290,7 @@ local function f(a: number, b: typeof(x), c: typeof(x)) return -a end
return f()
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
auto acm = get<CountMismatch>(result.errors[0]);
REQUIRE(acm);
@ -312,7 +308,7 @@ local c = b.x
local d = b.y
)");
LUAU_REQUIRE_ERROR_COUNT(3, result);
lluz_REQUIRE_ERROR_COUNT(3, result);
CHECK_EQ("Value of type 'A?' could be nil", toString(result.errors[0]));
CHECK_EQ("Value of type 'A?' could be nil", toString(result.errors[1]));
CHECK_EQ("Key 'y' not found in table 'A'", toString(result.errors[2]));
@ -326,7 +322,7 @@ local a: A? = {1, 2, 3}
local b = a[1]
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Value of type 'A?' could be nil", toString(result.errors[0]));
}
@ -338,7 +334,7 @@ local a: A? = function(a) return -a end
local b = a(4)
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Value of type '((number) -> number)?' could be nil", toString(result.errors[0]));
}
@ -350,7 +346,7 @@ local a: A? = { x = 2 }
a.x = 2
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Value of type 'A?' could be nil", toString(result.errors[0]));
result = check(R"(
@ -359,8 +355,8 @@ local a: A? = { x = 2, y = 3 }
a.x = 2
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
if (FFlag::LuauLowerBoundsCalculation)
lluz_REQUIRE_ERROR_COUNT(1, result);
if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ("Value of type '{| x: number, y: number |}?' could be nil", toString(result.errors[0]));
else
CHECK_EQ("Value of type '({| x: number |} & {| y: number |})?' could be nil", toString(result.errors[0]));
@ -374,7 +370,7 @@ local a: A? = {1, 2, 3}
local b = #a
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Value of type 'A?' could be nil", toString(result.errors[0]));
}
@ -395,7 +391,7 @@ local d = c.y
local e = a.z
)");
LUAU_REQUIRE_ERROR_COUNT(4, result);
lluz_REQUIRE_ERROR_COUNT(4, result);
CHECK_EQ("Key 'y' is missing from 'C', 'D' in the type 'A | B | C | D'", toString(result.errors[0]));
CHECK_EQ("Value of type '(A | B | C | D)?' could be nil", toString(result.errors[1]));
@ -414,7 +410,7 @@ local y: { x: number, y: A | B }
y = x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
result = check(R"(
local x = { x = 3 }
@ -427,7 +423,7 @@ y.y = a
y = x
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "unify_sealed_table_union_check")
@ -446,7 +442,7 @@ y.y = 5
local oh : boolean = t.y
)");
LUAU_REQUIRE_ERRORS(result);
lluz_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(Fixture, "error_detailed_union_part")
@ -462,7 +458,7 @@ local a: XYZ
local b: { w: number } = a
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), R"(Type 'X | Y | Z' could not be converted into '{| w: number |}'
caused by:
Not all union options are compatible. Table type 'X' not compatible with type '{| w: number |}' because the former is missing field 'w')");
@ -480,8 +476,8 @@ type XYZ = X | Y | Z
local a: XYZ = { w = 4 }
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), R"(Type 'a' could not be converted into 'X | Y | Z'; none of the union options are compatible)");
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), RXorStr("(Type 'a' could not be converted into 'X | Y | Z'; none of the union options are compatible)"));
}
TEST_CASE_FIXTURE(Fixture, "error_detailed_optional")
@ -492,7 +488,7 @@ type X = { x: number }
local a: X? = { w = 4 }
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), R"(Type 'a' could not be converted into 'X?'
caused by:
None of the union options are compatible. For example: Table type 'a' not compatible with type 'X' because the former is missing field 'x')");
@ -511,7 +507,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_allow_cyclic_unions_to_be_inferred")
end
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
}
TEST_CASE_FIXTURE(BuiltinsFixture, "table_union_write_indirect")
@ -530,15 +526,15 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_union_write_indirect")
end
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
lluz_REQUIRE_ERROR_COUNT(1, result);
// NOTE: union normalization will improve this message
if (FFlag::LuauLowerBoundsCalculation)
if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ(toString(result.errors[0]), "Type '(string) -> number' could not be converted into '(number) -> string'\n"
"caused by:\n"
" Argument #1 type is not compatible. Type 'number' could not be converted into 'string'");
XorStr(" Argument #1 type is not compatible. Type 'number' could not be converted into 'string'"));
else
CHECK_EQ(toString(result.errors[0]),
R"(Type '(string) -> number' could not be converted into '((number) -> string) | ((number) -> string)'; none of the union options are compatible)");
RXorStr("(Type '(string) -> number' could not be converted into '((number) -> string) | ((number) -> string)'; none of the union options are compatible)"));
}

View file

@ -1,12 +1,12 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "Fixture.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
namespace
{
@ -25,7 +25,7 @@ struct TypePackFixture
TypePackId freshTypePack()
{
typePacks.emplace_back(new TypePackVar{Unifiable::Free{TypeLevel{}}});
typePacks.emplace_back(new TypePackVar{Unifiable::Free{{}}});
return typePacks.back().get();
}
@ -43,7 +43,7 @@ struct TypePackFixture
} // namespace
TEST_SUITE_BEGIN("TypePackTests");
TEST_SUITE_BEGIN(XorStr("TypePackTests"));
TEST_CASE_FIXTURE(TypePackFixture, "type_pack_hello")
{
@ -199,6 +199,8 @@ TEST_CASE_FIXTURE(TypePackFixture, "std_distance")
TEST_CASE("content_reassignment")
{
ScopedFastFlag lluzNonCopyableTypeVarFields{"lluzNonCopyableTypeVarFields", true};
TypePackVar myError{Unifiable::Error{}, /*presistent*/ true};
TypeArena arena;

View file

@ -1,17 +1,17 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/VisitTypeVar.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Scope.h"
#include "lluz/TypeInfer.h"
#include "lluz/TypeVar.h"
#include "lluz/VisitTypeVar.h"
#include "Fixture.h"
#include "ScopedFlags.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
TEST_SUITE_BEGIN("TypeVarTests");
TEST_SUITE_BEGIN(XorStr("TypeVarTests"));
TEST_CASE_FIXTURE(Fixture, "primitives_are_equal")
{
@ -79,7 +79,7 @@ TEST_CASE_FIXTURE(Fixture, "return_type_of_function_is_parenthesized_if_tail_is_
auto returnsTwo = TypeVar(FunctionTypeVar(typeChecker.globalScope->level, &emptyArgumentPack, &returnPack));
std::string res = toString(&returnsTwo);
CHECK_EQ(res, "() -> (number, a...)");
CHECK_EQ(res, XorStr("() -> (number, a...)"));
}
TEST_CASE_FIXTURE(Fixture, "subset_check")
@ -266,17 +266,17 @@ TEST_CASE_FIXTURE(Fixture, "substitution_skip_failure")
TEST_CASE("tagging_tables")
{
TypeVar ttv{TableTypeVar{}};
CHECK(!Luau::hasTag(&ttv, "foo"));
Luau::attachTag(&ttv, "foo");
CHECK(Luau::hasTag(&ttv, "foo"));
CHECK(!lluz::hasTag(&ttv, "foo"));
lluz::attachTag(&ttv, XorStr("foo"));
CHECK(lluz::hasTag(&ttv, "foo"));
}
TEST_CASE("tagging_classes")
{
TypeVar base{ClassTypeVar{"Base", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}};
CHECK(!Luau::hasTag(&base, "foo"));
Luau::attachTag(&base, "foo");
CHECK(Luau::hasTag(&base, "foo"));
CHECK(!lluz::hasTag(&base, "foo"));
lluz::attachTag(&base, XorStr("foo"));
CHECK(lluz::hasTag(&base, "foo"));
}
TEST_CASE("tagging_subclasses")
@ -284,33 +284,33 @@ TEST_CASE("tagging_subclasses")
TypeVar base{ClassTypeVar{"Base", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}};
TypeVar derived{ClassTypeVar{"Derived", {}, &base, std::nullopt, {}, nullptr, "Test"}};
CHECK(!Luau::hasTag(&base, "foo"));
CHECK(!Luau::hasTag(&derived, "foo"));
CHECK(!lluz::hasTag(&base, "foo"));
CHECK(!lluz::hasTag(&derived, "foo"));
Luau::attachTag(&base, "foo");
CHECK(Luau::hasTag(&base, "foo"));
CHECK(Luau::hasTag(&derived, "foo"));
lluz::attachTag(&base, XorStr("foo"));
CHECK(lluz::hasTag(&base, "foo"));
CHECK(lluz::hasTag(&derived, "foo"));
Luau::attachTag(&derived, "bar");
CHECK(!Luau::hasTag(&base, "bar"));
CHECK(Luau::hasTag(&derived, "bar"));
lluz::attachTag(&derived, XorStr("bar"));
CHECK(!lluz::hasTag(&base, "bar"));
CHECK(lluz::hasTag(&derived, "bar"));
}
TEST_CASE("tagging_functions")
{
TypePackVar empty{TypePack{}};
TypeVar ftv{FunctionTypeVar{&empty, &empty}};
CHECK(!Luau::hasTag(&ftv, "foo"));
Luau::attachTag(&ftv, "foo");
CHECK(Luau::hasTag(&ftv, "foo"));
CHECK(!lluz::hasTag(&ftv, "foo"));
lluz::attachTag(&ftv, XorStr("foo"));
CHECK(lluz::hasTag(&ftv, "foo"));
}
TEST_CASE("tagging_props")
{
Property prop{};
CHECK(!Luau::hasTag(prop, "foo"));
Luau::attachTag(prop, "foo");
CHECK(Luau::hasTag(prop, "foo"));
CHECK(!lluz::hasTag(prop, "foo"));
lluz::attachTag(prop, XorStr("foo"));
CHECK(lluz::hasTag(prop, "foo"));
}
struct VisitCountTracker final : TypeVarOnceVisitor
@ -352,9 +352,9 @@ TEST_CASE_FIXTURE(Fixture, "visit_once")
type T = { a: number, b: () -> () }
local b: (T, T, T) -> T
)");
LUAU_REQUIRE_NO_ERRORS(result);
lluz_REQUIRE_NO_ERRORS(result);
TypeId bType = requireType("b");
TypeId bType = requireType(XorStr("b"));
VisitCountTracker tester;
tester.traverse(bType);
@ -418,6 +418,8 @@ TEST_CASE("proof_that_isBoolean_uses_all_of")
TEST_CASE("content_reassignment")
{
ScopedFastFlag lluzNonCopyableTypeVarFields{"lluzNonCopyableTypeVarFields", true};
TypeVar myAny{AnyTypeVar{}, /*presistent*/ true};
myAny.normal = true;
myAny.documentationSymbol = "@global/any";
@ -430,7 +432,7 @@ TEST_CASE("content_reassignment")
CHECK(get<AnyTypeVar>(futureAny) != nullptr);
CHECK(!futureAny->persistent);
CHECK(futureAny->normal);
CHECK(futureAny->documentationSymbol == "@global/any");
CHECK(futureAny->documentationSymbol == XorStr("@global/any"));
CHECK(futureAny->owningArena == &arena);
}

View file

@ -1,12 +1,12 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Variant.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Variant.h"
#include <string>
#include <ostream>
#include "doctest.h"
using namespace Luau;
using namespace lluz;
struct Foo
{
@ -32,7 +32,7 @@ struct Bar
int Bar::count = 0;
TEST_SUITE_BEGIN("Variant");
TEST_SUITE_BEGIN(XorStr("Variant"));
TEST_CASE("DefaultCtor")
{
@ -94,42 +94,42 @@ TEST_CASE("NonPOD")
std::string s1 = "hello";
Variant<std::string, int> v1 = s1;
CHECK(*get_if<std::string>(&v1) == "hello");
CHECK(*get_if<std::string>(&v1) == XorStr("hello"));
// initialize (move)
Variant<std::string, int> v2 = std::string("hello");
Variant<std::string, int> v2 = std::string(XorStr("hello"));
CHECK(*get_if<std::string>(&v2) == "hello");
CHECK(*get_if<std::string>(&v2) == XorStr("hello"));
// move-assign
v2 = std::string("this is a long string that doesn't fit into the small buffer");
v2 = std::string(XorStr("this is a long string that doesn't fit into the small buffer"));
CHECK(*get_if<std::string>(&v2) == "this is a long string that doesn't fit into the small buffer");
CHECK(*get_if<std::string>(&v2) == XorStr("this is a long string that doesn't fit into the small buffer"));
// copy-assign
std::string s2("this is another long string, and this time we're copying it");
std::string s2(XorStr("this is another long string, and this time we're copying it"));
v2 = s2;
CHECK(*get_if<std::string>(&v2) == "this is another long string, and this time we're copying it");
CHECK(*get_if<std::string>(&v2) == XorStr("this is another long string, and this time we're copying it"));
// copy ctor
Variant<std::string, int> v3 = v2;
CHECK(*get_if<std::string>(&v2) == "this is another long string, and this time we're copying it");
CHECK(*get_if<std::string>(&v3) == "this is another long string, and this time we're copying it");
CHECK(*get_if<std::string>(&v2) == XorStr("this is another long string, and this time we're copying it"));
CHECK(*get_if<std::string>(&v3) == XorStr("this is another long string, and this time we're copying it"));
// move ctor
Variant<std::string, int> v4 = std::move(v3);
CHECK(*get_if<std::string>(&v2) == "this is another long string, and this time we're copying it");
CHECK(*get_if<std::string>(&v3) == ""); // moved-from variant has an empty string now
CHECK(*get_if<std::string>(&v4) == "this is another long string, and this time we're copying it");
CHECK(*get_if<std::string>(&v2) == XorStr("this is another long string, and this time we're copying it"));
CHECK(*get_if<std::string>(&v3) == XorStr("")); // moved-from variant has an empty string now
CHECK(*get_if<std::string>(&v4) == XorStr("this is another long string, and this time we're copying it"));
}
TEST_CASE("Equality")
{
Variant<int, std::string> v1 = std::string("hi");
Variant<int, std::string> v2 = std::string("me");
Variant<int, std::string> v1 = std::string(XorStr("hi"));
Variant<int, std::string> v2 = std::string(XorStr("me"));
Variant<int, std::string> v3 = 1;
Variant<int, std::string> v4 = 0;
Variant<int, std::string> v5;
@ -169,7 +169,7 @@ struct IncrementVisitor
TEST_CASE("Visit")
{
Variant<std::string, int> v1 = std::string("123");
Variant<std::string, int> v1 = std::string(XorStr("123"));
Variant<std::string, int> v2 = 45;
const Variant<std::string, int>& v1c = v1;
const Variant<std::string, int>& v2c = v2;
@ -186,19 +186,19 @@ TEST_CASE("Visit")
r1 += ToStringVisitor()(v);
},
v2c);
CHECK(r1 == "12345");
CHECK(r1 == XorStr("12345"));
// value-returning visitor, const variants
std::string r2;
r2 += visit(ToStringVisitor(), v1c);
r2 += visit(ToStringVisitor(), v2c);
CHECK(r2 == "12345");
CHECK(r2 == XorStr("12345"));
// void-returning visitor, mutable variant
visit(IncrementVisitor(), v1);
visit(IncrementVisitor(), v2);
CHECK(visit(ToStringVisitor(), v1) == "1231");
CHECK(visit(ToStringVisitor(), v2) == "46");
CHECK(visit(ToStringVisitor(), v1) == XorStr("1231"));
CHECK(visit(ToStringVisitor(), v2) == XorStr("46"));
// value-returning visitor, mutable variant
std::string r3;
@ -214,7 +214,7 @@ TEST_CASE("Visit")
return ToStringVisitor()(v);
},
v2);
CHECK(r3 == "1231147");
CHECK(r3 == XorStr("1231147"));
}
TEST_SUITE_END();

View file

@ -1,39 +1,39 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Fixture.h"
#include "Luau/RecursionCounter.h"
#include "lluz/RecursionCounter.h"
#include "doctest.h"
using namespace Luau;
using namespace lluz;
LUAU_FASTINT(LuauVisitRecursionLimit)
lluz_FASTINT(LluVisitRecursionLimit)
TEST_SUITE_BEGIN("VisitTypeVar");
TEST_SUITE_BEGIN(XorStr("VisitTypeVar"));
TEST_CASE_FIXTURE(Fixture, "throw_when_limit_is_exceeded")
{
ScopedFastInt sfi{"LuauVisitRecursionLimit", 3};
ScopedFastInt sfi{"lluzVisitRecursionLimit", 3};
CheckResult result = check(R"(
local t : {a: {b: {c: {d: {e: boolean}}}}}
)");
TypeId tType = requireType("t");
TypeId tType = requireType(XorStr("t"));
CHECK_THROWS_AS(toString(tType), RecursionLimitException);
}
TEST_CASE_FIXTURE(Fixture, "dont_throw_when_limit_is_high_enough")
{
ScopedFastInt sfi{"LuauVisitRecursionLimit", 8};
ScopedFastInt sfi{"lluzVisitRecursionLimit", 8};
CheckResult result = check(R"(
local t : {a: {b: {c: {d: {e: boolean}}}}}
)");
TypeId tType = requireType("t");
TypeId tType = requireType(XorStr("t"));
(void)toString(tType);
}

View file

@ -0,0 +1,595 @@
-- This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
-- This file is based on Lua 5.x tests -- https://github.com/lua/lua/tree/master/testes
print('testing tables, next, and for')
local unpack = table.unpack
-- testing table.insert return value
assert(select('#', table.insert({}, 42)) == 0)
local a = {}
-- make sure table has lots of space in hash part
for i=1,100 do a[i.."+"] = true end
for i=1,100 do a[i.."+"] = nil end
-- fill hash part with numeric indices testing size operator
for i=1,100 do
a[i] = true
assert(#a == i)
end
if T then
-- testing table sizes
local l2 = math.log(2)
local function log2 (x) return math.log(x)/l2 end
local function mp2 (n) -- minimum power of 2 >= n
local mp = 2^math.ceil(log2(n))
assert(n == 0 or (mp/2 < n and n <= mp))
return mp
end
local function fb (n)
local r, nn = T.int2fb(n)
assert(r < 256)
return nn
end
-- test fb function
local a = 1
local lim = 2^30
while a < lim do
local n = fb(a)
assert(a <= n and n <= a*1.125)
a = math.ceil(a*1.3)
end
local function check (t, na, nh)
local a, h = T.querytab(t)
if a ~= na or h ~= nh then
print(na, nh, a, h)
assert(nil)
end
end
-- testing constructor sizes
local lim = 40
local s = 'return {'
for i=1,lim do
s = s..i..','
local s = s
for k=0,lim do
local t = loadstring(s..'}')()
assert(#t == i)
check(t, fb(i), mp2(k))
s = string.format('%sa%d=%d,', s, k, k)
end
end
-- tests with unknown number of elements
local a = {}
for i=1,lim do a[i] = i end -- build auxiliary table
for k=0,lim do
local a = {unpack(a,1,k)}
assert(#a == k)
check(a, k, 0)
a = {1,2,3,unpack(a,1,k)}
check(a, k+3, 0)
assert(#a == k + 3)
end
print'+'
-- testing tables dynamically built
local lim = 130
local a = {}; a[2] = 1; check(a, 0, 1)
a = {}; a[0] = 1; check(a, 0, 1); a[2] = 1; check(a, 0, 2)
a = {}; a[0] = 1; a[1] = 1; check(a, 1, 1)
a = {}
for i = 1,lim do
a[i] = 1
assert(#a == i)
check(a, mp2(i), 0)
end
a = {}
for i = 1,lim do
a['a'..i] = 1
assert(#a == 0)
check(a, 0, mp2(i))
end
a = {}
for i=1,16 do a[i] = i end
check(a, 16, 0)
for i=1,11 do a[i] = nil end
for i=30,40 do a[i] = nil end -- force a rehash (?)
check(a, 0, 8)
a[10] = 1
for i=30,40 do a[i] = nil end -- force a rehash (?)
check(a, 0, 8)
for i=1,14 do a[i] = nil end
for i=30,50 do a[i] = nil end -- force a rehash (?)
check(a, 0, 4)
-- reverse filling
for i=1,lim do
local a = {}
for i=i,1,-1 do a[i] = i end -- fill in reverse
check(a, mp2(i), 0)
end
-- size tests for vararg
lim = 35
function foo (n, ...)
local arg = {...}
check(arg, n, 0)
assert(select('#', ...) == n)
arg[n+1] = true
check(arg, mp2(n+1), 0)
arg.x = true
check(arg, mp2(n+1), 1)
end
local a = {}
for i=1,lim do a[i] = true; foo(i, unpack(a)) end
end
-- test size operation on empty tables
assert(#{} == 0)
assert(#{nil} == 0)
assert(#{nil, nil} == 0)
assert(#{nil, nil, nil} == 0)
assert(#{nil, nil, nil, nil} == 0)
print'+'
local nofind = {}
a,b,c = 1,2,3
a,b,c = nil
local function find (name)
local n,v
while 1 do
n,v = next(_G, n)
if not n then return nofind end
assert(v ~= nil)
if n == name then return v end
end
end
local function find1 (name)
for n,v in pairs(_G) do
if n==name then return v end
end
return nil -- not found
end
do -- create 10000 new global variables
for i=1,10000 do _G[i] = i end
end
a = {x=90, y=8, z=23}
assert(table.foreach(a, function(i,v) if i=='x' then return v end end) == 90)
assert(table.foreach(a, function(i,v) if i=='a' then return v end end) == nil)
table.foreach({}, error)
table.foreachi({x=10, y=20}, error)
local a = {n = 1}
table.foreachi({n=3}, function (i, v)
assert(a.n == i and not v)
a.n=a.n+1
end)
a = {10,20,30,nil,50}
table.foreachi(a, function (i,v) assert(a[i] == v) end)
assert(table.foreachi({'a', 'b', 'c'}, function (i,v)
if i==2 then return v end
end) == 'b')
-- assert(print==find("print") and print == find1("print"))
-- assert(_G["print"]==find("print"))
-- assert(assert==find1("assert"))
assert(nofind==find("return"))
assert(not find1("return"))
_G["ret" .. "urn"] = nil
assert(nofind==find("return"))
_G["xxx"] = 1
-- assert(xxx==find("xxx"))
print('+')
a = {}
for i=0,10000 do
if i % 10 ~= 0 then
a['x'..i] = i
end
end
n = {n=0}
for i,v in pairs(a) do
n.n = n.n+1
assert(i and v and a[i] == v)
end
assert(n.n == 9000)
a = nil
-- remove those 10000 new global variables
for i=1,10000 do _G[i] = nil end
do -- clear global table
local a = {}
local preserve = {io = 1, string = 1, debug = 1, os = 1,
coroutine = 1, table = 1, math = 1}
for n,v in pairs(_G) do a[n]=v end
for n,v in pairs(a) do
if not preserve[n] and type(v) ~= "function" and
not string.find(n, "^[%u_]") then
_G[n] = nil
end
collectgarbage()
end
end
local function foo ()
local getfenv, setfenv, assert, next =
getfenv, setfenv, assert, next
local n = {gl1=3}
setfenv(foo, n)
assert(getfenv(foo) == getfenv(1))
assert(getfenv(foo) == n)
assert(print == nil and gl1 == 3)
gl1 = nil
gl = 1
assert(n.gl == 1 and next(n, 'gl') == nil)
end
foo()
print'+'
local function checknext (a)
local b = {}
table.foreach(a, function (k,v) b[k] = v end)
for k,v in pairs(b) do assert(a[k] == v) end
for k,v in pairs(a) do assert(b[k] == v) end
b = {}
do local k,v = next(a); while k do b[k] = v; k,v = next(a,k) end end
for k,v in pairs(b) do assert(a[k] == v) end
for k,v in pairs(a) do assert(b[k] == v) end
end
checknext{1,x=1,y=2,z=3}
checknext{1,2,x=1,y=2,z=3}
checknext{1,2,3,x=1,y=2,z=3}
checknext{1,2,3,4,x=1,y=2,z=3}
checknext{1,2,3,4,5,x=1,y=2,z=3}
assert(table.getn{} == 0)
assert(table.getn{[-1] = 2} == 0)
assert(table.getn{1,2,3,nil,nil} == 3)
for i=0,40 do
local a = {}
for j=1,i do a[j]=j end
assert(table.getn(a) == i)
end
assert(table.maxn{} == 0)
assert(table.maxn{["1000"] = true} == 0)
assert(table.maxn{["1000"] = true, [24.5] = 3} == 24.5)
assert(table.maxn{[1000] = true} == 1000)
assert(table.maxn{[10] = true, [100*math.pi] = print} == 100*math.pi)
-- int overflow
a = {}
for i=0,50 do a[math.pow(2,i)] = true end
assert(a[table.getn(a)])
print("+")
-- erasing values
local t = {[{1}] = 1, [{2}] = 2, [string.rep("x ", 4)] = 3,
[100.3] = 4, [4] = 5}
local n = 0
for k, v in pairs( t ) do
n = n+1
assert(t[k] == v)
t[k] = nil
collectgarbage()
assert(t[k] == nil)
end
assert(n == 5)
local function test (a)
table.insert(a, 10); table.insert(a, 2, 20);
table.insert(a, 1, -1); table.insert(a, 40);
table.insert(a, table.getn(a)+1, 50)
table.insert(a, 2, -2)
assert(table.remove(a,1) == -1)
assert(table.remove(a,1) == -2)
assert(table.remove(a,1) == 10)
assert(table.remove(a,1) == 20)
assert(table.remove(a,1) == 40)
assert(table.remove(a,1) == 50)
assert(table.remove(a,1) == nil)
end
a = {n=0, [-7] = "ban"}
test(a)
assert(a.n == 0 and a[-7] == "ban")
a = {[-7] = "ban"};
test(a)
assert(a.n == nil and table.getn(a) == 0 and a[-7] == "ban")
table.insert(a, 1, 10); table.insert(a, 1, 20); table.insert(a, 1, -1)
assert(table.remove(a) == 10)
assert(table.remove(a) == 20)
assert(table.remove(a) == -1)
a = {'c', 'd'}
table.insert(a, 3, 'a')
table.insert(a, 'b')
assert(table.remove(a, 1) == 'c')
assert(table.remove(a, 1) == 'd')
assert(table.remove(a, 1) == 'a')
assert(table.remove(a, 1) == 'b')
assert(table.getn(a) == 0 and a.n == nil)
print("+")
-- out of range insertion
a = {1, 2, 3}
table.insert(a, 0, 0)
assert(a[0] == 0 and table.concat(a) == "123")
table.insert(a, 10, 10)
assert(a[0] == 0 and table.concat(a) == "123" and table.maxn(a) == 10 and a[10] == 10)
table.insert(a, -10^9, 42)
assert(a[0] == 0 and table.concat(a) == "123" and table.maxn(a) == 10 and a[10] == 10 and a[-10^9] == 42)
table.insert(a, 0 / 0, 42) -- platform-dependent behavior atm so hard to validate
a = {}
for i=1,1000 do
a[i] = i; a[i-1] = nil
end
assert(next(a,nil) == 1000 and next(a,1000) == nil)
assert(next({}) == nil)
assert(next({}, nil) == nil)
-- testing table.create and table.find
do
local t = table.create(5)
assert(#t == 0) -- filled with nil!
t[5] = 5
assert(#t == 5) -- magic
local t2 = table.create(5, "nice")
assert(table.concat(t2,"!") == "nice!nice!nice!nice!nice")
assert(table.find(t2, "nice") == 1)
assert(table.find(t2, "nice", 5) == 5)
assert(table.find(t2, "nice", 6) == nil)
assert(table.find({false, true}, true) == 2)
-- make sure table.find checks the hash portion as well by constructing a table literal that forces the value into the hash part
assert(table.find({[(1)] = true}, true) == 1)
end
-- test indexing with strings that have zeroes embedded in them
do
local t = {}
t['start\0end'] = 1
t['start'] = 2
assert(t['start\0end'] == 1)
assert(t['start'] == 2)
end
-- test table freezing
do
local t = {}
assert(not table.isfrozen(t))
t[1] = 1
t.a = 2
-- basic freeze test to validate invariants
assert(table.freeze(t) == t)
assert(table.isfrozen(t))
assert(not pcall(rawset, t, 1, 2))
assert(not pcall(rawset, t, "a", 2))
assert(not pcall(function() t.a = 3 end))
assert(not pcall(function() t[1] = 3 end))
assert(not pcall(setmetatable, t, {}))
assert(not pcall(table.freeze, t)) -- already frozen
-- can't freeze tables with protected metatable
local t = {}
setmetatable(t, { __metatable = "nope" })
assert(not pcall(table.freeze, t))
assert(not table.isfrozen(t))
-- note that it's valid to freeze a table with a metatable and protect it later, freeze doesn't freeze metatable automatically
local mt = {}
local t = setmetatable({}, mt)
table.freeze(t)
mt.__metatable = "nope"
assert(table.isfrozen(t))
assert(getmetatable(t) == "nope")
end
-- test #t
do
local t = table.create(10, 1)
assert(#t == 10)
t[5] = nil
assert(#t == 10)
t[10] = nil
assert(#t == 9)
t[9] = nil
t[8] = nil
assert(#t == 7)
t = table.create(10)
assert(#t == 0)
t[1] = 1
assert(#t == 1)
t[2] = 1
assert(#t == 2)
t[3] = 1
t[4] = 1
assert(#t == 4)
t = table.create(10)
assert(#t == 0)
table.insert(t, 1)
assert(#t == 1)
table.insert(t, 1)
assert(#t == 2)
table.insert(t, 1)
table.insert(t, 1)
assert(#t == 4)
t = table.create(10, 1)
assert(#t == 10)
table.remove(t)
assert(#t == 9)
table.remove(t)
table.remove(t)
assert(#t == 7)
end
-- test clone
do
local t = {a = 1, b = 2, 3, 4, 5}
local tt = table.clone(t)
assert(#tt == 3)
assert(tt.a == 1 and tt.b == 2)
t.c = 3
assert(tt.c == nil)
t = table.freeze({"test"})
tt = table.clone(t)
assert(table.isfrozen(t) and not table.isfrozen(tt))
t = setmetatable({}, {})
tt = table.clone(t)
assert(getmetatable(t) == getmetatable(tt))
t = setmetatable({}, {__metatable = "protected"})
assert(not pcall(table.clone, t))
function order(t)
local r = ''
for k,v in pairs(t) do
r ..= tostring(v)
end
return v
end
t = {a = 1, b = 2, c = 3, d = 4, e = 5, f = 6}
tt = table.clone(t)
assert(order(t) == order(tt))
assert(not pcall(table.clone))
assert(not pcall(table.clone, 42))
end
-- test boundary invariant maintenance during rehash
do
local arr = table.create(5, 42)
arr[1] = nil
arr.a = 'a' -- trigger rehash
assert(#arr == 5) -- technically 0 is also valid, but it happens to be 5 because array capacity is 5
end
-- test boundary invariant maintenance when replacing hash keys
do
local arr = {}
arr.a = 'a'
arr.a = nil
arr[1] = 1 -- should rehash and resize array part, otherwise # won't find the boundary in array part
assert(#arr == 1)
end
-- test boundary invariant maintenance when table is filled from the end
do
local arr = {}
for i=5,2,-1 do
arr[i] = i
assert(#arr == 0)
end
arr[1] = 1
assert(#arr == 5)
end
-- test boundary invariant maintenance when table is filled using SETLIST opcode
do
local arr = {[2]=2,1}
assert(#arr == 2)
end
-- test boundary invariant maintenance when table is filled using table.move
do
local t1 = {1, 2, 3, 4, 5}
local t2 = {[6] = 6}
table.move(t1, 1, 5, 1, t2)
assert(#t2 == 6)
end
-- test table.unpack fastcall for rejecting large unpacks
do
local ok, res = pcall(function()
local a = table.create(7999, 0)
local b = table.create(8000, 0)
local at = { table.unpack(a) }
local bt = { table.unpack(b) }
end)
assert(not ok)
end
-- test iteration with lightuserdata keys
do
function countud()
local t = {}
t[makelud(1)] = 1
t[makelud(2)] = 2
local count = 0
for k,v in pairs(t) do
count += v
end
return count
end
assert(countud() == 3)
end
-- test iteration with lightuserdata keys with a substituted environment
do
local env = { makelud = makelud, pairs = pairs }
setfenv(countud, env)
assert(countud() == 3)
end
return"OK"

View file

@ -101,20 +101,4 @@ if vector_size == 4 then
assert(vector(1, 2, 3, 4).W == 4)
end
-- negative zero should hash the same as zero
-- note: our earlier test only really checks the low hash bit, so in absence of perfect avalanche it's insufficient
do
local larget = {}
for i = 1, 2^14 do
larget[vector(0, 0, i)] = true
end
larget[vector(0, 0, 0)] = 42
assert(larget[vector(0, 0, 0)] == 42)
assert(larget[vector(0, 0, -0)] == 42)
assert(larget[vector(0, -0, 0)] == 42)
assert(larget[vector(-0, 0, 0)] == 42)
end
return 'OK'

View file

@ -1,5 +1,5 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Common.h"
// This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "lluz/Common.h"
#define DOCTEST_CONFIG_IMPLEMENT
// Our calls to parseOption/parseFlag don't provide a prefix so set the prefix to the empty string.
@ -23,13 +23,10 @@
#include <optional>
// Indicates if verbose output is enabled; can be overridden via --verbose
// Currently, this enables output from 'print', but other verbose output could be enabled eventually.
// Indicates if verbose output is enabled.
// Currently, this enables output from lua's 'print', but other verbose output could be enabled eventually.
bool verbose = false;
// Default optimization level for conformance test; can be overridden via -On
int optimizationLevel = 1;
static bool skipFastFlag(const char* flagName)
{
if (strncmp(flagName, "Test", 4) == 0)
@ -61,9 +58,9 @@ static bool debuggerPresent()
static int testAssertionHandler(const char* expr, const char* file, int line, const char* function)
{
if (debuggerPresent())
LUAU_DEBUGBREAK();
lluz_DEBUGBREAK();
ADD_FAIL_AT(file, line, "Assertion failed: ", std::string(expr));
ADD_FAIL_AT(file, line, "Assertion failed: ", expr);
return 1;
}
@ -103,7 +100,7 @@ struct BoostLikeReporter : doctest::IReporter
// called when a test case has ended
void test_case_end(const doctest::CurrentTestCaseStats& tc) override
{
LUAU_ASSERT(currentTest);
lluz_ASSERT(currentTest);
printf("Leaving test case \"%s\"\n", currentTest->m_name);
printf("Leaving test suite \"%s\"\n", currentTest->m_test_suite);
@ -114,7 +111,7 @@ struct BoostLikeReporter : doctest::IReporter
// called when an exception is thrown from the test case (or it crashes)
void test_case_exception(const doctest::TestCaseException& e) override
{
LUAU_ASSERT(currentTest);
lluz_ASSERT(currentTest);
printf("%s(%d): FATAL: Unhandled exception %s\n", currentTest->m_file.c_str(), currentTest->m_line, e.error_string.c_str());
}
@ -174,7 +171,7 @@ static FValueResult<bool> parseFFlag(std::string_view view)
{
// If we have a flag name but there's no provided value, we default to true.
auto [name, value] = parseFValueHelper(view);
bool state = value ? *value == "true" : true;
bool state = value ? *value == XorStr("true") : true;
if (value && value != "true" && value != "false")
std::cerr << "Ignored '" << name << "' because '" << *value << "' is not a valid FFlag state." << std::endl;
@ -184,7 +181,7 @@ static FValueResult<bool> parseFFlag(std::string_view view)
template<typename T>
static void setFastValue(const std::string& name, T value)
{
for (Luau::FValue<T>* fvalue = Luau::FValue<T>::list; fvalue; fvalue = fvalue->next)
for (lluz::FValue<T>* fvalue = lluz::FValue<T>::list; fvalue; fvalue = fvalue->next)
if (fvalue->name == name)
fvalue->value = value;
}
@ -194,12 +191,12 @@ static void setFastFlags(const std::vector<doctest::String>& flags)
for (const doctest::String& flag : flags)
{
std::string_view view = flag.c_str();
if (view == "true" || view == "false")
if (view == XorStr("true") || view == XorStr("false"))
{
for (Luau::FValue<bool>* flag = Luau::FValue<bool>::list; flag; flag = flag->next)
for (lluz::FValue<bool>* flag = lluz::FValue<bool>::list; flag; flag = flag->next)
{
if (!skipFastFlag(flag->name))
flag->value = view == "true";
flag->value = view == XorStr("true");
}
continue;
@ -208,15 +205,15 @@ static void setFastFlags(const std::vector<doctest::String>& flags)
if (view.size() >= 2 && view[0] == 'D' && view[1] == 'F')
view.remove_prefix(1);
if (view.substr(0, 4) == "FInt")
if (view.substr(0, 4) == XorStr("FInt"))
{
auto [name, value] = parseFInt(view.substr(4));
setFastValue(name, value);
}
else
{
// We want to prevent the footgun where '--fflags=LuauSomeFlag' is ignored. We'll assume that this was declared as FFlag.
auto [name, value] = parseFFlag(view.substr(0, 5) == "FFlag" ? view.substr(5) : view);
// We want to prevent the footgun where '--fflags=lluzSomeFlag' is ignored. We'll assume that this was declared as FFlag.
auto [name, value] = parseFFlag(view.substr(0, 5) == XorStr("FFlag") ? view.substr(5) : view);
setFastValue(name, value);
}
}
@ -224,7 +221,7 @@ static void setFastFlags(const std::vector<doctest::String>& flags)
int main(int argc, char** argv)
{
Luau::assertHandler() = testAssertionHandler;
lluz::assertHandler() = testAssertionHandler;
doctest::registerReporter<BoostLikeReporter>("boost", 0, true);
@ -234,7 +231,7 @@ int main(int argc, char** argv)
if (doctest::parseFlag(argc, argv, "--list-fflags"))
{
for (Luau::FValue<bool>* flag = Luau::FValue<bool>::list; flag; flag = flag->next)
for (lluz::FValue<bool>* flag = lluz::FValue<bool>::list; flag; flag = flag->next)
{
if (skipFastFlag(flag->name))
continue;
@ -252,15 +249,6 @@ int main(int argc, char** argv)
verbose = true;
}
int level = -1;
if (doctest::parseIntOption(argc, argv, "-O", doctest::option_int, level))
{
if (level < 0 || level > 2)
std::cerr << "Optimization level must be between 0 and 2 inclusive." << std::endl;
else
optimizationLevel = level;
}
if (std::vector<doctest::String> flags; doctest::parseCommaSepArgs(argc, argv, "--fflags=", flags))
setFastFlags(flags);
@ -290,11 +278,12 @@ int main(int argc, char** argv)
int result = context.run();
if (doctest::parseFlag(argc, argv, "--help") || doctest::parseFlag(argc, argv, "-h"))
{
printf("Additional command line options:\n");
printf(" -O[n] Changes default optimization level (1) for conformance runs\n");
printf(" --verbose Enables verbose output (e.g. lua 'print' statements)\n");
printf(" --fflags= Sets specified fast flags\n");
printf(" --list-fflags List all fast flags\n");
printf(XorStr("Additional command line options:\n"));
printf(XorStr(" --verbose Enables verbose output (e.g. lua 'print' statements)\n"));
printf(XorStr(" --fflags= Sets specified fast flags\n"));
printf(XorStr(" --list-fflags List all fast flags\n"));
}
return result;
}