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 "lua.h"
#include "lualib.h" #include "lualib.h"
#include "luacode.h" #include "luacode.h"
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Luau/ModuleResolver.h" #include "lluz/ModuleResolver.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/StringUtils.h" #include "lluz/StringUtils.h"
#include "Luau/BytecodeBuilder.h" #include "lluz/BytecodeBuilder.h"
#include "doctest.h" #include "doctest.h"
#include "ScopedFlags.h" #include "ScopedFlags.h"
@ -17,16 +17,6 @@
#include <math.h> #include <math.h>
extern bool verbose; 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) static int lua_collectgarbage(lua_State* L)
{ {
@ -62,8 +52,8 @@ static int lua_loadstring(lua_State* L)
lua_setsafeenv(L, LUA_ENVIRONINDEX, false); lua_setsafeenv(L, LUA_ENVIRONINDEX, false);
size_t bytecodeSize = 0; size_t bytecodeSize = 0;
char* bytecode = luau_compile(s, l, nullptr, &bytecodeSize); char* bytecode = lluz_compile(s, l, nullptr, &bytecodeSize);
int result = luau_load(L, chunkname, bytecode, bytecodeSize, 0); int result = lluz_load(L, chunkname, bytecode, bytecodeSize, 0);
free(bytecode); free(bytecode);
if (result == 0) if (result == 0)
@ -111,11 +101,11 @@ static int lua_vector_index(lua_State* L)
if (strcmp(name, "Dot") == 0) if (strcmp(name, "Dot") == 0)
{ {
lua_pushcfunction(L, lua_vector_dot, "Dot"); lua_pushcfunction(L, lua_vector_dot, XorStr("Dot"));
return 1; 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) 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); 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) 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*)>; 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, 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__; std::string path = __FILE__;
path.erase(path.find_last_of("\\/")); 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); lua_pop(L, 1);
// In some configurations we have a larger C stack consumption which trips some conformance tests // 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_pushboolean(L, true);
lua_setglobal(L, "limitedstack"); lua_setglobal(L, XorStr("limitedstack"));
#endif #endif
// Extra test-specific setup // 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 conformance tests treat _G synonymously with getfenv(); for now cater to them
lua_pushvalue(L, LUA_GLOBALSINDEX); lua_pushvalue(L, LUA_GLOBALSINDEX);
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); 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; size_t bytecodeSize = 0;
char* bytecode = luau_compile(source.data(), source.size(), &opts, &bytecodeSize); char* bytecode = lluz_compile(source.data(), source.size(), copts, &bytecodeSize);
int result = luau_load(L, chunkname.c_str(), bytecode, bytecodeSize, 0); int result = lluz_load(L, chunkname.c_str(), bytecode, bytecodeSize, 0);
free(bytecode); free(bytecode);
int status = (result == 0) ? lua_resume(L, nullptr, 0) : LUA_ERRSYNTAX; 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) if (status == 0)
{ {
REQUIRE(lua_isstring(L, -1)); REQUIRE(lua_isstring(L, -1));
CHECK(std::string(lua_tostring(L, -1)) == "OK"); CHECK(std::string(lua_tostring(L, -1)) == XorStr("OK"));
} }
else else
{ {
@ -235,28 +222,28 @@ static StateRef runConformance(const char* name, void (*setup)(lua_State* L) = n
return globalState; return globalState;
} }
TEST_SUITE_BEGIN("Conformance"); TEST_SUITE_BEGIN(XorStr("Conformance"));
TEST_CASE("Assert") TEST_CASE("Assert")
{ {
runConformance("assert.lua"); runConformance(XorStr("assert.lua"));
} }
TEST_CASE("Basic") TEST_CASE("Basic")
{ {
ScopedFastFlag sff("LuauLenTM", true); ScopedFastFlag sff(XorStr("LluLenTM"), true);
runConformance("basic.lua"); runConformance(XorStr("basic.lua"));
} }
TEST_CASE("Math") 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( lua_pushcfunction(
L, L,
[](lua_State* L) { [](lua_State* L) {
@ -264,118 +251,117 @@ TEST_CASE("Tables")
lua_pushlightuserdata(L, reinterpret_cast<void*>(uintptr_t(v))); lua_pushlightuserdata(L, reinterpret_cast<void*>(uintptr_t(v)));
return 1; return 1;
}, },
"makelud"); XorStr("makelud"));
lua_setglobal(L, "makelud"); lua_setglobal(L, XorStr("makelud"));
}); });
} }
TEST_CASE("PatternMatch") TEST_CASE("PatternMatch")
{ {
runConformance("pm.lua"); runConformance(XorStr("pm.lua"));
} }
TEST_CASE("Sort") TEST_CASE("Sort")
{ {
runConformance("sort.lua"); runConformance(XorStr("sort.lua"));
} }
TEST_CASE("Move") TEST_CASE("Move")
{ {
runConformance("move.lua"); runConformance(XorStr("move.lua"));
} }
TEST_CASE("Clear") TEST_CASE("Clear")
{ {
runConformance("clear.lua"); runConformance(XorStr("clear.lua"));
} }
TEST_CASE("Strings") TEST_CASE("Strings")
{ {
runConformance("strings.lua"); runConformance(XorStr("strings.lua"));
} }
TEST_CASE("VarArg") TEST_CASE("VarArg")
{ {
runConformance("vararg.lua"); runConformance(XorStr("vararg.lua"));
} }
TEST_CASE("Locals") TEST_CASE("Locals")
{ {
runConformance("locals.lua"); runConformance(XorStr("locals.lua"));
} }
TEST_CASE("Literals") TEST_CASE("Literals")
{ {
runConformance("literals.lua"); runConformance(XorStr("literals.lua"));
} }
TEST_CASE("Errors") TEST_CASE("Errors")
{ {
runConformance("errors.lua"); runConformance(XorStr("errors.lua"));
} }
TEST_CASE("Events") TEST_CASE("Events")
{ {
ScopedFastFlag sff1("LuauLenTM", true); ScopedFastFlag sff("LluLenTM", true);
ScopedFastFlag sff2("LuauBetterNewindex", true);
runConformance("events.lua"); runConformance(XorStr("events.lua"));
} }
TEST_CASE("Constructs") TEST_CASE("Constructs")
{ {
runConformance("constructs.lua"); runConformance(XorStr("constructs.lua"));
} }
TEST_CASE("Closure") TEST_CASE("Closure")
{ {
runConformance("closure.lua"); runConformance(XorStr("closure.lua"));
} }
TEST_CASE("Calls") TEST_CASE("Calls")
{ {
runConformance("calls.lua"); runConformance(XorStr("calls.lua"));
} }
TEST_CASE("Attrib") TEST_CASE("Attrib")
{ {
runConformance("attrib.lua"); runConformance(XorStr("attrib.lua"));
} }
TEST_CASE("GC") TEST_CASE("GC")
{ {
runConformance("gc.lua"); runConformance(XorStr("gc.lua"));
} }
TEST_CASE("Bitwise") TEST_CASE("Bitwise")
{ {
runConformance("bitwise.lua"); runConformance(XorStr("bitwise.lua"));
} }
TEST_CASE("UTF8") TEST_CASE("UTF8")
{ {
runConformance("utf8.lua"); runConformance(XorStr("utf8.lua"));
} }
TEST_CASE("Coroutine") TEST_CASE("Coroutine")
{ {
runConformance("coroutine.lua"); runConformance(XorStr("coroutine.lua"));
} }
static int cxxthrow(lua_State* L) static int cxxthrow(lua_State* L)
{ {
#if LUA_USE_LONGJMP #if LUA_USE_LONGJMP
luaL_error(L, "oops"); luaL_error(L, XorStr("oops"));
#else #else
throw std::runtime_error("oops"); throw std::runtime_error(XorStr("oops"));
#endif #endif
} }
TEST_CASE("PCall") TEST_CASE("PCall")
{ {
runConformance("pcall.lua", [](lua_State* L) { runConformance("pcall.lua", [](lua_State* L) {
lua_pushcfunction(L, cxxthrow, "cxxthrow"); lua_pushcfunction(L, cxxthrow, XorStr("cxxthrow"));
lua_setglobal(L, "cxxthrow"); lua_setglobal(L, XorStr("cxxthrow"));
lua_pushcfunction( lua_pushcfunction(
L, L,
@ -385,39 +371,41 @@ TEST_CASE("PCall")
lua_resumeerror(co, L); lua_resumeerror(co, L);
return 0; return 0;
}, },
"resumeerror"); XorStr("resumeerror"));
lua_setglobal(L, "resumeerror"); lua_setglobal(L, XorStr("resumeerror"));
}); });
} }
TEST_CASE("Pack") TEST_CASE("Pack")
{ {
runConformance("tpack.lua"); runConformance(XorStr("tpack.lua"));
} }
TEST_CASE("Vector") TEST_CASE("Vector")
{ {
lua_CompileOptions copts = defaultOptions(); lua_CompileOptions copts = {};
copts.optimizationLevel = 1;
copts.debugLevel = 1;
copts.vectorCtor = "vector"; copts.vectorCtor = "vector";
runConformance( runConformance(
"vector.lua", "vector.lua",
[](lua_State* L) { [](lua_State* L) {
lua_pushcfunction(L, lua_vector, "vector"); lua_pushcfunction(L, lua_vector, XorStr("vector"));
lua_setglobal(L, "vector"); lua_setglobal(L, XorStr("vector"));
#if LUA_VECTOR_SIZE == 4 #if LUA_VECTOR_SIZE == 4
lua_pushvector(L, 0.0f, 0.0f, 0.0f, 0.0f); lua_pushvector(L, 0.0f, 0.0f, 0.0f, 0.0f);
#else #else
lua_pushvector(L, 0.0f, 0.0f, 0.0f); lua_pushvector(L, 0.0f, 0.0f, 0.0f);
#endif #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_pushcfunction(L, lua_vector_index, nullptr);
lua_settable(L, -3); lua_settable(L, -3);
lua_pushstring(L, "__namecall"); lua_pushstring(L, XorStr("__namecall"));
lua_pushcfunction(L, lua_vector_namecall, nullptr); lua_pushcfunction(L, lua_vector_namecall, nullptr);
lua_settable(L, -3); lua_settable(L, -3);
@ -428,37 +416,37 @@ TEST_CASE("Vector")
nullptr, nullptr, &copts); 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) switch (p->type)
{ {
case Luau::PrimitiveTypeVar::Boolean: case lluz::PrimitiveTypeVar::Boolean:
lua_pushstring(L, "boolean"); lua_pushstring(L, XorStr("boolean"));
break; break;
case Luau::PrimitiveTypeVar::NilType: case lluz::PrimitiveTypeVar::NilType:
lua_pushstring(L, "nil"); lua_pushstring(L, XorStr("nil"));
break; break;
case Luau::PrimitiveTypeVar::Number: case lluz::PrimitiveTypeVar::Number:
lua_pushstring(L, "number"); lua_pushstring(L, XorStr("number"));
break; break;
case Luau::PrimitiveTypeVar::String: case lluz::PrimitiveTypeVar::String:
lua_pushstring(L, "string"); lua_pushstring(L, XorStr("string"));
break; break;
case Luau::PrimitiveTypeVar::Thread: case lluz::PrimitiveTypeVar::Thread:
lua_pushstring(L, "thread"); lua_pushstring(L, XorStr("thread"));
break; break;
default: 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); lua_newtable(L);
@ -468,36 +456,38 @@ static void populateRTTI(lua_State* L, Luau::TypeId type)
lua_setfield(L, -2, name.c_str()); 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) 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 else
{ {
LUAU_ASSERT(!"Unknown type"); lluz_ASSERT(!XorStr("Unknown type"));
} }
} }
TEST_CASE("Types") TEST_CASE("Types")
{ {
runConformance("types.lua", [](lua_State* L) { ScopedFastFlag sff("lluzCheckLenMT", true);
Luau::NullModuleResolver moduleResolver;
Luau::InternalErrorReporter iceHandler;
Luau::TypeChecker env(&moduleResolver, &iceHandler);
Luau::registerBuiltinTypes(env); runConformance("types.lua", [](lua_State* L) {
Luau::freeze(env.globalTypes); lluz::NullModuleResolver moduleResolver;
lluz::InternalErrorReporter iceHandler;
lluz::TypeChecker env(&moduleResolver, &iceHandler);
lluz::registerBuiltinTypes(env);
lluz::freeze(env.globalTypes);
lua_newtable(L); lua_newtable(L);
@ -507,18 +497,18 @@ TEST_CASE("Types")
lua_setfield(L, -2, toString(name).c_str()); lua_setfield(L, -2, toString(name).c_str());
} }
lua_setglobal(L, "RTTI"); lua_setglobal(L, XorStr("RTTI"));
}); });
} }
TEST_CASE("DateTime") TEST_CASE("DateTime")
{ {
runConformance("datetime.lua"); runConformance(XorStr("datetime.lua"));
} }
TEST_CASE("Debug") TEST_CASE("Debug")
{ {
runConformance("debug.lua"); runConformance(XorStr("debug.lua"));
} }
TEST_CASE("Debugger") TEST_CASE("Debugger")
@ -529,7 +519,8 @@ TEST_CASE("Debugger")
breakhits = 0; breakhits = 0;
interruptedthread = nullptr; interruptedthread = nullptr;
lua_CompileOptions copts = defaultOptions(); lua_CompileOptions copts = {};
copts.optimizationLevel = 1;
copts.debugLevel = 2; copts.debugLevel = 2;
runConformance( runConformance(
@ -572,8 +563,8 @@ TEST_CASE("Debugger")
lua_breakpoint(L, -1, line, enabled); lua_breakpoint(L, -1, line, enabled);
return 0; return 0;
}, },
"breakpoint"); XorStr("breakpoint"));
lua_setglobal(L, "breakpoint"); lua_setglobal(L, XorStr("breakpoint"));
}, },
[](lua_State* L) { [](lua_State* L) {
CHECK(breakhits % 2 == 1); CHECK(breakhits % 2 == 1);
@ -665,11 +656,11 @@ TEST_CASE("SameHash")
// To keep VM and compiler separate, we duplicate the hash function definition // 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 // 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 // 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("", 0) == lluz::BytecodeBuilder::getStringHash({"", 0}));
CHECK(luaS_hash("lua", 3) == Luau::BytecodeBuilder::getStringHash({"lua", 3})); CHECK(luaS_hash("lua", 3) == lluz::BytecodeBuilder::getStringHash({"lua", 3}));
CHECK(luaS_hash("luau", 4) == Luau::BytecodeBuilder::getStringHash({"luau", 4})); CHECK(luaS_hash("lluz", 4) == lluz::BytecodeBuilder::getStringHash({"lluz", 4}));
CHECK(luaS_hash("luaubytecode", 12) == Luau::BytecodeBuilder::getStringHash({"luaubytecode", 12})); CHECK(luaS_hash("lluzbytecode", 12) == lluz::BytecodeBuilder::getStringHash({"lluzbytecode", 12}));
CHECK(luaS_hash("luaubytecodehash", 16) == Luau::BytecodeBuilder::getStringHash({"luaubytecodehash", 16})); CHECK(luaS_hash("lluzbytecodehash", 16) == lluz::BytecodeBuilder::getStringHash({"lluzbytecodehash", 16}));
// Also hash should work on unaligned source data even when hashing long strings // Also hash should work on unaligned source data even when hashing long strings
char buf[128] = {}; char buf[128] = {};
@ -722,12 +713,12 @@ TEST_CASE("ApiTables")
lua_newtable(L); lua_newtable(L);
lua_pushnumber(L, 123.0); lua_pushnumber(L, 123.0);
lua_setfield(L, -2, "key"); lua_setfield(L, -2, XorStr("key"));
lua_pushstring(L, "test"); lua_pushstring(L, XorStr("test"));
lua_rawseti(L, -2, 5); lua_rawseti(L, -2, 5);
// lua_gettable // lua_gettable
lua_pushstring(L, "key"); lua_pushstring(L, XorStr("key"));
CHECK(lua_gettable(L, -2) == LUA_TNUMBER); CHECK(lua_gettable(L, -2) == LUA_TNUMBER);
CHECK(lua_tonumber(L, -1) == 123.0); CHECK(lua_tonumber(L, -1) == 123.0);
lua_pop(L, 1); lua_pop(L, 1);
@ -743,7 +734,7 @@ TEST_CASE("ApiTables")
lua_pop(L, 1); lua_pop(L, 1);
// lua_rawget // lua_rawget
lua_pushstring(L, "key"); lua_pushstring(L, XorStr("key"));
CHECK(lua_rawget(L, -2) == LUA_TNUMBER); CHECK(lua_rawget(L, -2) == LUA_TNUMBER);
CHECK(lua_tonumber(L, -1) == 123.0); CHECK(lua_tonumber(L, -1) == 123.0);
lua_pop(L, 1); lua_pop(L, 1);
@ -758,12 +749,12 @@ TEST_CASE("ApiTables")
TEST_CASE("ApiCalls") TEST_CASE("ApiCalls")
{ {
StateRef globalState = runConformance("apicalls.lua"); StateRef globalState = runConformance(XorStr("apicalls.lua"));
lua_State* L = globalState.get(); lua_State* L = globalState.get();
// lua_call // lua_call
{ {
lua_getfield(L, LUA_GLOBALSINDEX, "add"); lua_getfield(L, LUA_GLOBALSINDEX, XorStr("add"));
lua_pushnumber(L, 40); lua_pushnumber(L, 40);
lua_pushnumber(L, 2); lua_pushnumber(L, 2);
lua_call(L, 2, 1); lua_call(L, 2, 1);
@ -774,7 +765,7 @@ TEST_CASE("ApiCalls")
// lua_pcall // lua_pcall
{ {
lua_getfield(L, LUA_GLOBALSINDEX, "add"); lua_getfield(L, LUA_GLOBALSINDEX, XorStr("add"));
lua_pushnumber(L, 40); lua_pushnumber(L, 40);
lua_pushnumber(L, 2); lua_pushnumber(L, 2);
lua_pcall(L, 2, 1, 0); lua_pcall(L, 2, 1, 0);
@ -787,11 +778,11 @@ TEST_CASE("ApiCalls")
{ {
lua_State* L2 = lua_newthread(L); 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_pushnumber(L2, 42);
lua_pcall(L2, 1, 1, 0); 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_pushnumber(L2, 42);
lua_pcall(L2, 1, 1, 0); lua_pcall(L2, 1, 1, 0);
@ -808,18 +799,18 @@ TEST_CASE("ApiCalls")
// lua_clonefunction + fenv // lua_clonefunction + fenv
{ {
lua_getfield(L, LUA_GLOBALSINDEX, "getpi"); lua_getfield(L, LUA_GLOBALSINDEX, XorStr("getpi"));
lua_call(L, 0, 1); lua_call(L, 0, 1);
CHECK(lua_tonumber(L, -1) == 3.1415926); CHECK(lua_tonumber(L, -1) == 3.1415926);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, LUA_GLOBALSINDEX, "getpi"); lua_getfield(L, LUA_GLOBALSINDEX, XorStr("getpi"));
// clone & override env // clone & override env
lua_clonefunction(L, -1); lua_clonefunction(L, -1);
lua_newtable(L); lua_newtable(L);
lua_pushnumber(L, 42); lua_pushnumber(L, 42);
lua_setfield(L, -2, "pi"); lua_setfield(L, -2, XorStr("pi"));
lua_setfenv(L, -2); lua_setfenv(L, -2);
lua_call(L, 0, 1); lua_call(L, 0, 1);
@ -834,12 +825,12 @@ TEST_CASE("ApiCalls")
// lua_clonefunction + upvalues // lua_clonefunction + upvalues
{ {
lua_getfield(L, LUA_GLOBALSINDEX, "incuv"); lua_getfield(L, LUA_GLOBALSINDEX, XorStr("incuv"));
lua_call(L, 0, 1); lua_call(L, 0, 1);
CHECK(lua_tonumber(L, -1) == 1); CHECK(lua_tonumber(L, -1) == 1);
lua_pop(L, 1); lua_pop(L, 1);
lua_getfield(L, LUA_GLOBALSINDEX, "incuv"); lua_getfield(L, LUA_GLOBALSINDEX, XorStr("incuv"));
// two clones // two clones
lua_clonefunction(L, -1); lua_clonefunction(L, -1);
lua_clonefunction(L, -2); 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) static bool endsWith(const std::string& str, const std::string& suffix)
{ {
if (suffix.length() > str.length()) if (suffix.length() > str.length())
@ -924,7 +880,7 @@ TEST_CASE("ExceptionObject")
CHECK(e.what() != nullptr); CHECK(e.what() != nullptr);
return ExceptionResult{true, e.what()}; 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* { 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(); lua_State* L = globalState.get();
{ {
ExceptionResult result = captureException(L, "infinite_recursion_error"); ExceptionResult result = captureException(L, XorStr("infinite_recursion_error"));
CHECK(result.exceptionGenerated); CHECK(result.exceptionGenerated);
} }
{ {
ExceptionResult result = captureException(L, "empty_function"); ExceptionResult result = captureException(L, XorStr("empty_function"));
CHECK_FALSE(result.exceptionGenerated); 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(result.exceptionGenerated);
CHECK(endsWith(result.description, "42")); 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(result.exceptionGenerated);
CHECK(endsWith(result.description, "string argument")); 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); CHECK(result.exceptionGenerated);
} }
{ {
ExceptionResult result = captureException(L, "large_allocation_error"); ExceptionResult result = captureException(L, XorStr("large_allocation_error"));
CHECK(result.exceptionGenerated); CHECK(result.exceptionGenerated);
} }
} }
@ -985,7 +941,7 @@ TEST_CASE("ExceptionObject")
TEST_CASE("IfElseExpression") TEST_CASE("IfElseExpression")
{ {
runConformance("ifelseexpr.lua"); runConformance(XorStr("ifelseexpr.lua"));
} }
TEST_CASE("TagMethodError") TEST_CASE("TagMethodError")
@ -1001,8 +957,9 @@ TEST_CASE("TagMethodError")
TEST_CASE("Coverage") TEST_CASE("Coverage")
{ {
lua_CompileOptions copts = defaultOptions(); lua_CompileOptions copts = {};
copts.optimizationLevel = 1; // disable inlining to get fixed expected hit results copts.optimizationLevel = 1;
copts.debugLevel = 1;
copts.coverageLevel = 2; copts.coverageLevel = 2;
runConformance( runConformance(
@ -1011,7 +968,7 @@ TEST_CASE("Coverage")
lua_pushcfunction( lua_pushcfunction(
L, L,
[](lua_State* L) -> int { [](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_newtable(L);
lua_getcoverage(L, 1, L, [](void* context, const char* function, int linedefined, int depth, const int* hits, size_t size) { 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_newtable(L);
lua_pushstring(L, function); lua_pushstring(L, function);
lua_setfield(L, -2, "name"); lua_setfield(L, -2, XorStr("name"));
lua_pushinteger(L, linedefined); lua_pushinteger(L, linedefined);
lua_setfield(L, -2, "linedefined"); lua_setfield(L, -2, XorStr("linedefined"));
lua_pushinteger(L, depth); lua_pushinteger(L, depth);
lua_setfield(L, -2, "depth"); lua_setfield(L, -2, XorStr("depth"));
for (size_t i = 0; i < size; ++i) for (size_t i = 0; i < size; ++i)
if (hits[i] != -1) if (hits[i] != -1)
@ -1040,15 +997,15 @@ TEST_CASE("Coverage")
return 1; return 1;
}, },
"getcoverage"); XorStr("getcoverage"));
lua_setglobal(L, "getcoverage"); lua_setglobal(L, XorStr("getcoverage"));
}, },
nullptr, nullptr, &copts); nullptr, nullptr, &copts);
} }
TEST_CASE("StringConversion") TEST_CASE("StringConversion")
{ {
runConformance("strconv.lua"); runConformance(XorStr("strconv.lua"));
} }
TEST_CASE("GCDump") TEST_CASE("GCDump")
@ -1061,8 +1018,8 @@ TEST_CASE("GCDump")
// push various objects on stack to cover different paths // push various objects on stack to cover different paths
lua_createtable(L, 1, 2); lua_createtable(L, 1, 2);
lua_pushstring(L, "value"); lua_pushstring(L, XorStr("value"));
lua_setfield(L, -2, "key"); lua_setfield(L, -2, XorStr("key"));
lua_pushinteger(L, 42); lua_pushinteger(L, 42);
lua_rawseti(L, -2, 1000); lua_rawseti(L, -2, 1000);
@ -1082,7 +1039,7 @@ TEST_CASE("GCDump")
lua_State* CL = lua_newthread(L); 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_loadstring(CL);
lua_resume(CL, nullptr, 0); lua_resume(CL, nullptr, 0);
@ -1092,7 +1049,7 @@ TEST_CASE("GCDump")
const char* path = "/dev/null"; const char* path = "/dev/null";
#endif #endif
FILE* f = fopen(path, "w"); FILE* f = fopen(path, XorStr("w"));
REQUIRE(f); REQUIRE(f);
luaC_dump(L, f, nullptr); luaC_dump(L, f, nullptr);
@ -1102,9 +1059,6 @@ TEST_CASE("GCDump")
TEST_CASE("Interrupt") TEST_CASE("Interrupt")
{ {
lua_CompileOptions copts = defaultOptions();
copts.optimizationLevel = 1; // disable loop unrolling to get fixed expected hit results
static const int expectedhits[] = { static const int expectedhits[] = {
2, 2,
9, 9,
@ -1155,8 +1109,7 @@ TEST_CASE("Interrupt")
}, },
[](lua_State* L) { [](lua_State* L) {
CHECK(index == 5); // a single yield point CHECK(index == 5); // a single yield point
}, });
nullptr, &copts);
CHECK(index == int(std::size(expectedhits))); CHECK(index == int(std::size(expectedhits)));
} }
@ -1199,10 +1152,6 @@ TEST_CASE("UserdataApi")
CHECK(lua_touserdatatagged(L, -1, 41) == nullptr); CHECK(lua_touserdatatagged(L, -1, 41) == nullptr);
CHECK(lua_userdatatag(L, -1) == 42); 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 // user data with inline dtor
void* ud3 = lua_newuserdatadtor(L, 4, [](void* data) { void* ud3 = lua_newuserdatadtor(L, 4, [](void* data) {
dtorhits += *(int*)data; dtorhits += *(int*)data;
@ -1222,7 +1171,7 @@ TEST_CASE("UserdataApi")
TEST_CASE("Iter") TEST_CASE("Iter")
{ {
runConformance("iter.lua"); runConformance(XorStr("iter.lua"));
} }
const int kInt64Tag = 1; const int kInt64Tag = 1;
@ -1236,7 +1185,7 @@ static int64_t getInt64(lua_State* L, int idx)
if (lua_isnumber(L, idx)) if (lua_isnumber(L, idx))
return lua_tointeger(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) static void pushInt64(lua_State* L, int64_t value)
@ -1262,7 +1211,7 @@ TEST_CASE("Userdata")
[](lua_State* L) { [](lua_State* L) {
void* p = lua_touserdatatagged(L, 1, kInt64Tag); void* p = lua_touserdatatagged(L, 1, kInt64Tag);
if (!p) if (!p)
luaL_typeerror(L, 1, "int64"); luaL_typeerror(L, 1, XorStr("int64"));
const char* name = luaL_checkstring(L, 2); const char* name = luaL_checkstring(L, 2);
@ -1272,10 +1221,10 @@ TEST_CASE("Userdata")
return 1; return 1;
} }
luaL_error(L, "unknown field %s", name); luaL_error(L, XorStr("unknown field %s"), name);
}, },
nullptr); nullptr);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, XorStr("__index"));
// __newindex // __newindex
lua_pushcfunction( lua_pushcfunction(
@ -1283,7 +1232,7 @@ TEST_CASE("Userdata")
[](lua_State* L) { [](lua_State* L) {
void* p = lua_touserdatatagged(L, 1, kInt64Tag); void* p = lua_touserdatatagged(L, 1, kInt64Tag);
if (!p) if (!p)
luaL_typeerror(L, 1, "int64"); luaL_typeerror(L, 1, XorStr("int64"));
const char* name = luaL_checkstring(L, 2); const char* name = luaL_checkstring(L, 2);
@ -1294,10 +1243,10 @@ TEST_CASE("Userdata")
return 0; return 0;
} }
luaL_error(L, "unknown field %s", name); luaL_error(L, XorStr("unknown field %s"), name);
}, },
nullptr); nullptr);
lua_setfield(L, -2, "__newindex"); lua_setfield(L, -2, XorStr("__newindex"));
// __eq // __eq
lua_pushcfunction( lua_pushcfunction(
@ -1307,7 +1256,7 @@ TEST_CASE("Userdata")
return 1; return 1;
}, },
nullptr); nullptr);
lua_setfield(L, -2, "__eq"); lua_setfield(L, -2, XorStr("__eq"));
// __lt // __lt
lua_pushcfunction( lua_pushcfunction(
@ -1317,7 +1266,7 @@ TEST_CASE("Userdata")
return 1; return 1;
}, },
nullptr); nullptr);
lua_setfield(L, -2, "__lt"); lua_setfield(L, -2, XorStr("__lt"));
// __le // __le
lua_pushcfunction( lua_pushcfunction(
@ -1327,7 +1276,7 @@ TEST_CASE("Userdata")
return 1; return 1;
}, },
nullptr); nullptr);
lua_setfield(L, -2, "__le"); lua_setfield(L, -2, XorStr("__le"));
// __add // __add
lua_pushcfunction( lua_pushcfunction(
@ -1337,7 +1286,7 @@ TEST_CASE("Userdata")
return 1; return 1;
}, },
nullptr); nullptr);
lua_setfield(L, -2, "__add"); lua_setfield(L, -2, XorStr("__add"));
// __sub // __sub
lua_pushcfunction( lua_pushcfunction(
@ -1347,7 +1296,7 @@ TEST_CASE("Userdata")
return 1; return 1;
}, },
nullptr); nullptr);
lua_setfield(L, -2, "__sub"); lua_setfield(L, -2, XorStr("__sub"));
// __mul // __mul
lua_pushcfunction( lua_pushcfunction(
@ -1357,7 +1306,7 @@ TEST_CASE("Userdata")
return 1; return 1;
}, },
nullptr); nullptr);
lua_setfield(L, -2, "__mul"); lua_setfield(L, -2, XorStr("__mul"));
// __div // __div
lua_pushcfunction( lua_pushcfunction(
@ -1368,7 +1317,7 @@ TEST_CASE("Userdata")
return 1; return 1;
}, },
nullptr); nullptr);
lua_setfield(L, -2, "__div"); lua_setfield(L, -2, XorStr("__div"));
// __mod // __mod
lua_pushcfunction( lua_pushcfunction(
@ -1379,7 +1328,7 @@ TEST_CASE("Userdata")
return 1; return 1;
}, },
nullptr); nullptr);
lua_setfield(L, -2, "__mod"); lua_setfield(L, -2, XorStr("__mod"));
// __pow // __pow
lua_pushcfunction( lua_pushcfunction(
@ -1389,7 +1338,7 @@ TEST_CASE("Userdata")
return 1; return 1;
}, },
nullptr); nullptr);
lua_setfield(L, -2, "__pow"); lua_setfield(L, -2, XorStr("__pow"));
// __unm // __unm
lua_pushcfunction( lua_pushcfunction(
@ -1399,7 +1348,7 @@ TEST_CASE("Userdata")
return 1; return 1;
}, },
nullptr); nullptr);
lua_setfield(L, -2, "__unm"); lua_setfield(L, -2, XorStr("__unm"));
// __tostring // __tostring
lua_pushcfunction( lua_pushcfunction(
@ -1411,7 +1360,7 @@ TEST_CASE("Userdata")
return 1; return 1;
}, },
nullptr); nullptr);
lua_setfield(L, -2, "__tostring"); lua_setfield(L, -2, XorStr("__tostring"));
// ctor // ctor
lua_pushcfunction( lua_pushcfunction(
@ -1421,8 +1370,8 @@ TEST_CASE("Userdata")
pushInt64(L, int64_t(v)); pushInt64(L, int64_t(v));
return 1; return 1;
}, },
"int64"); XorStr("int64"));
lua_setglobal(L, "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 "Fixture.h"
#include "Luau/ConstraintGraphBuilder.h" #include "lluz/ConstraintGraphBuilder.h"
#include "doctest.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") 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 "Fixture.h"
#include "doctest.h" #include "doctest.h"
#include "Luau/ConstraintGraphBuilder.h" #include "lluz/ConstraintGraphBuilder.h"
#include "Luau/ConstraintSolver.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); auto b = linearSearchForBinding(scope, name);
LUAU_ASSERT(b.has_value()); lluz_ASSERT(b.has_value());
return *b; return *b;
} }
TEST_SUITE_BEGIN("ConstraintSolver"); TEST_SUITE_BEGIN(XorStr("ConstraintSolver"));
TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "hello") TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "hello")
{ {
@ -26,13 +26,13 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "hello")
)"); )");
cgb.visit(block); cgb.visit(block);
NotNull<Scope> rootScope = NotNull(cgb.rootScope); NotNull<Scope2> rootScope = NotNull(cgb.rootScope);
ConstraintSolver cs{&arena, rootScope}; ConstraintSolver cs{&arena, rootScope};
cs.run(); cs.run();
TypeId bType = requireBinding(rootScope, "b"); TypeId bType = requireBinding(rootScope, XorStr("b"));
CHECK("number" == toString(bType)); CHECK("number" == toString(bType));
} }
@ -46,13 +46,13 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "generic_function")
)"); )");
cgb.visit(block); cgb.visit(block);
NotNull<Scope> rootScope = NotNull(cgb.rootScope); NotNull<Scope2> rootScope = NotNull(cgb.rootScope);
ConstraintSolver cs{&arena, rootScope}; ConstraintSolver cs{&arena, rootScope};
cs.run(); cs.run();
TypeId idType = requireBinding(rootScope, "id"); TypeId idType = requireBinding(rootScope, XorStr("id"));
CHECK("<a>(a) -> a" == toString(idType)); CHECK("<a>(a) -> a" == toString(idType));
} }
@ -73,7 +73,7 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "proper_let_generalization")
)"); )");
cgb.visit(block); cgb.visit(block);
NotNull<Scope> rootScope = NotNull(cgb.rootScope); NotNull<Scope2> rootScope = NotNull(cgb.rootScope);
ToStringOptions opts; ToStringOptions opts;
@ -81,7 +81,7 @@ TEST_CASE_FIXTURE(ConstraintGraphBuilderFixture, "proper_let_generalization")
cs.run(); cs.run();
TypeId idType = requireBinding(rootScope, "b"); TypeId idType = requireBinding(rootScope, XorStr("b"));
CHECK("<a>(a) -> number" == toString(idType, opts)); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Parser.h" #include "lluz/Parser.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
namespace Luau namespace lluz
{ {
namespace Compile 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); int computeCost(uint64_t model, const bool* varsConst, size_t varCount);
} // namespace Compile } // namespace Compile
} // namespace Luau } // namespace lluz
TEST_SUITE_BEGIN("CostModel"); TEST_SUITE_BEGIN(XorStr("CostModel"));
static uint64_t modelFunction(const char* source) 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>(); AstStatFunction* func = result.root->body.data[0]->as<AstStatFunction>();
REQUIRE(func); 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") TEST_CASE("Expression")
@ -43,8 +43,8 @@ end
const bool args1[] = {false, false, false}; const bool args1[] = {false, false, false};
const bool args2[] = {false, true, false}; const bool args2[] = {false, true, false};
CHECK_EQ(5, Luau::Compile::computeCost(model, args1, 3)); CHECK_EQ(5, lluz::Compile::computeCost(model, args1, 3));
CHECK_EQ(2, Luau::Compile::computeCost(model, args2, 3)); CHECK_EQ(2, lluz::Compile::computeCost(model, args2, 3));
} }
TEST_CASE("PropagateVariable") TEST_CASE("PropagateVariable")
@ -59,8 +59,8 @@ end
const bool args1[] = {false}; const bool args1[] = {false};
const bool args2[] = {true}; const bool args2[] = {true};
CHECK_EQ(3, Luau::Compile::computeCost(model, args1, 1)); CHECK_EQ(3, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(0, Luau::Compile::computeCost(model, args2, 1)); CHECK_EQ(0, lluz::Compile::computeCost(model, args2, 1));
} }
TEST_CASE("LoopAssign") TEST_CASE("LoopAssign")
@ -77,8 +77,8 @@ end
const bool args2[] = {true}; const bool args2[] = {true};
// loop baseline cost is 5 // loop baseline cost is 5
CHECK_EQ(6, Luau::Compile::computeCost(model, args1, 1)); CHECK_EQ(6, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(6, Luau::Compile::computeCost(model, args2, 1)); CHECK_EQ(6, lluz::Compile::computeCost(model, args2, 1));
} }
TEST_CASE("MutableVariable") TEST_CASE("MutableVariable")
@ -94,8 +94,8 @@ end
const bool args1[] = {false}; const bool args1[] = {false};
const bool args2[] = {true}; const bool args2[] = {true};
CHECK_EQ(3, Luau::Compile::computeCost(model, args1, 1)); CHECK_EQ(3, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(2, Luau::Compile::computeCost(model, args2, 1)); CHECK_EQ(2, lluz::Compile::computeCost(model, args2, 1));
} }
TEST_CASE("ImportCall") TEST_CASE("ImportCall")
@ -109,8 +109,8 @@ end
const bool args1[] = {false}; const bool args1[] = {false};
const bool args2[] = {true}; const bool args2[] = {true};
CHECK_EQ(6, Luau::Compile::computeCost(model, args1, 1)); CHECK_EQ(6, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(6, Luau::Compile::computeCost(model, args2, 1)); CHECK_EQ(6, lluz::Compile::computeCost(model, args2, 1));
} }
TEST_CASE("FastCall") TEST_CASE("FastCall")
@ -125,8 +125,8 @@ end
const bool args2[] = {true}; const bool args2[] = {true};
// note: we currently don't treat fast calls differently from cost model perspective // note: we currently don't treat fast calls differently from cost model perspective
CHECK_EQ(6, Luau::Compile::computeCost(model, args1, 1)); CHECK_EQ(6, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(5, Luau::Compile::computeCost(model, args2, 1)); CHECK_EQ(5, lluz::Compile::computeCost(model, args2, 1));
} }
TEST_CASE("ControlFlow") TEST_CASE("ControlFlow")
@ -154,8 +154,8 @@ end
const bool args1[] = {false}; const bool args1[] = {false};
const bool args2[] = {true}; const bool args2[] = {true};
CHECK_EQ(82, Luau::Compile::computeCost(model, args1, 1)); CHECK_EQ(82, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(79, Luau::Compile::computeCost(model, args2, 1)); CHECK_EQ(79, lluz::Compile::computeCost(model, args2, 1));
} }
TEST_CASE("Conditional") TEST_CASE("Conditional")
@ -169,8 +169,8 @@ end
const bool args1[] = {false}; const bool args1[] = {false};
const bool args2[] = {true}; const bool args2[] = {true};
CHECK_EQ(4, Luau::Compile::computeCost(model, args1, 1)); CHECK_EQ(4, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(2, Luau::Compile::computeCost(model, args2, 1)); CHECK_EQ(2, lluz::Compile::computeCost(model, args2, 1));
} }
TEST_CASE("VarArgs") TEST_CASE("VarArgs")
@ -181,7 +181,7 @@ function test(...)
end end
)"); )");
CHECK_EQ(8, Luau::Compile::computeCost(model, nullptr, 0)); CHECK_EQ(8, lluz::Compile::computeCost(model, nullptr, 0));
} }
TEST_CASE("TablesFunctions") TEST_CASE("TablesFunctions")
@ -192,7 +192,7 @@ function test()
end end
)"); )");
CHECK_EQ(22, Luau::Compile::computeCost(model, nullptr, 0)); CHECK_EQ(22, lluz::Compile::computeCost(model, nullptr, 0));
} }
TEST_CASE("CostOverflow") TEST_CASE("CostOverflow")
@ -203,7 +203,7 @@ function test()
end end
)"); )");
CHECK_EQ(127, Luau::Compile::computeCost(model, nullptr, 0)); CHECK_EQ(127, lluz::Compile::computeCost(model, nullptr, 0));
} }
TEST_CASE("TableAssign") TEST_CASE("TableAssign")
@ -219,8 +219,8 @@ end
const bool args1[] = {false}; const bool args1[] = {false};
const bool args2[] = {true}; const bool args2[] = {true};
CHECK_EQ(7, Luau::Compile::computeCost(model, args1, 1)); CHECK_EQ(7, lluz::Compile::computeCost(model, args1, 1));
CHECK_EQ(6, Luau::Compile::computeCost(model, args2, 1)); CHECK_EQ(6, lluz::Compile::computeCost(model, args2, 1));
} }
TEST_SUITE_END(); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Error.h" #include "lluz/Error.h"
#include "doctest.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") 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 "Fixture.h"
#include "Luau/AstQuery.h" #include "lluz/AstQuery.h"
#include "Luau/Parser.h" #include "lluz/Parser.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Luau/TypeAttach.h" #include "lluz/TypeAttach.h"
#include "Luau/Transpiler.h" #include "lluz/Transpiler.h"
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "doctest.h" #include "doctest.h"
@ -17,25 +17,25 @@
static const char* mainModuleName = "MainModule"; 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) std::optional<ModuleInfo> TestFileResolver::resolveModule(const ModuleInfo* context, AstExpr* expr)
{ {
if (AstExprGlobal* g = expr->as<AstExprGlobal>()) if (AstExprGlobal* g = expr->as<AstExprGlobal>())
{ {
if (g->name == "game") if (g->name == XorStr("game"))
return ModuleInfo{"game"}; return ModuleInfo{"game"};
if (g->name == "workspace") if (g->name == XorStr("workspace"))
return ModuleInfo{"workspace"}; return ModuleInfo{"workspace"};
if (g->name == "script") if (g->name == XorStr("script"))
return context ? std::optional<ModuleInfo>(*context) : std::nullopt; return context ? std::optional<ModuleInfo>(*context) : std::nullopt;
} }
else if (AstExprIndexName* i = expr->as<AstExprIndexName>(); i && context) else if (AstExprIndexName* i = expr->as<AstExprIndexName>(); i && context)
{ {
if (i->index == "Parent") if (i->index == XorStr("Parent"))
{ {
std::string_view view = context->name; std::string_view view = context->name;
size_t lastSeparatorIndex = view.find_last_of('/'); 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; 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)}; 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) Fixture::Fixture(bool freeze, bool prepareAutocomplete)
: sff_DebugLuauFreezeArena("DebugLuauFreezeArena", freeze) : sff_DebuglluzFreezeArena("DebuglluzFreezeArena", freeze)
, frontend(&fileResolver, &configResolver, {/* retainFullTypeGraphs= */ true}) , frontend(&fileResolver, &configResolver, {/* retainFullTypeGraphs= */ true})
, typeChecker(frontend.typeChecker) , typeChecker(frontend.typeChecker)
{ {
@ -94,15 +94,15 @@ Fixture::Fixture(bool freeze, bool prepareAutocomplete)
configResolver.defaultConfig.enabledLint.warningMask = ~0ull; configResolver.defaultConfig.enabledLint.warningMask = ~0ull;
configResolver.defaultConfig.parseOptions.captureComments = true; configResolver.defaultConfig.parseOptions.captureComments = true;
Luau::freeze(frontend.typeChecker.globalTypes); lluz::freeze(frontend.typeChecker.globalTypes);
Luau::freeze(frontend.typeCheckerForAutocomplete.globalTypes); lluz::freeze(frontend.typeCheckerForAutocomplete.globalTypes);
Luau::setPrintLine([](auto s) {}); lluz::setPrintLine([](auto s) {});
} }
Fixture::~Fixture() Fixture::~Fixture()
{ {
Luau::resetPrintLine(); lluz::resetPrintLine();
} }
AstStatBlock* Fixture::parse(const std::string& source, const ParseOptions& parseOptions) 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); 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); throw ParseErrors(result.errors);
@ -195,7 +195,7 @@ ParseResult Fixture::matchParseError(const std::string& source, const std::strin
sourceModule.reset(new SourceModule); sourceModule.reset(new SourceModule);
ParseResult result = Parser::parse(source.c_str(), source.length(), *sourceModule->names, *sourceModule->allocator, options); 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()) if (!result.errors.empty())
{ {
@ -216,7 +216,7 @@ ParseResult Fixture::matchParseErrorPrefix(const std::string& source, const std:
sourceModule.reset(new SourceModule); sourceModule.reset(new SourceModule);
ParseResult result = Parser::parse(source.c_str(), source.length(), *sourceModule->names, *sourceModule->allocator, options); 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()) if (!result.errors.empty())
{ {
@ -257,8 +257,8 @@ std::optional<TypeId> Fixture::getType(const std::string& name)
ModulePtr module = getMainModule(); ModulePtr module = getMainModule();
REQUIRE(module); REQUIRE(module);
if (FFlag::DebugLuauDeferredConstraintResolution) if (FFlag::DebugLluDeferredConstraintResolution)
return linearSearchForBinding(module->getModuleScope().get(), name.c_str()); return linearSearchForBinding(module->getModuleScope2(), name.c_str());
else else
return lookupName(module->getModuleScope(), name); 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) TypeId Fixture::requireType(const std::string& name)
{ {
std::optional<TypeId> ty = getType(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); 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) TypeId Fixture::requireType(const ScopePtr& scope, const std::string& name)
{ {
std::optional<TypeId> ty = lookupName(scope, 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; return *ty;
} }
@ -293,14 +293,14 @@ std::optional<TypeId> Fixture::findTypeAtPosition(Position position)
{ {
ModulePtr module = getMainModule(); ModulePtr module = getMainModule();
SourceModule* sourceModule = getMainSourceModule(); SourceModule* sourceModule = getMainSourceModule();
return Luau::findTypeAtPosition(*module, *sourceModule, position); return lluz::findTypeAtPosition(*module, *sourceModule, position);
} }
std::optional<TypeId> Fixture::findExpectedTypeAtPosition(Position position) std::optional<TypeId> Fixture::findExpectedTypeAtPosition(Position position)
{ {
ModulePtr module = getMainModule(); ModulePtr module = getMainModule();
SourceModule* sourceModule = getMainSourceModule(); SourceModule* sourceModule = getMainSourceModule();
return Luau::findExpectedTypeAtPosition(*module, *sourceModule, position); return lluz::findExpectedTypeAtPosition(*module, *sourceModule, position);
} }
TypeId Fixture::requireTypeAtPosition(Position position) TypeId Fixture::requireTypeAtPosition(Position position)
@ -330,7 +330,7 @@ std::string Fixture::decorateWithTypes(const std::string& code)
{ {
fileResolver.source[mainModuleName] = code; fileResolver.source[mainModuleName] = code;
Luau::CheckResult typeInfo = frontend.check(mainModuleName); lluz::CheckResult typeInfo = frontend.check(mainModuleName);
SourceModule* sourceModule = frontend.getSourceModule(mainModuleName); SourceModule* sourceModule = frontend.getSourceModule(mainModuleName);
attachTypeData(*sourceModule, *frontend.moduleResolver.getModule(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; os << "Error: " << error << std::endl;
std::string_view source = fileResolver.source[error.moduleName]; 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()) 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() void Fixture::registerTestTypes()
{ {
addGlobalBinding(typeChecker, "game", typeChecker.anyType, "@luau"); addGlobalBinding(typeChecker, XorStr("game", typeChecker.anyType, "@lluz"));
addGlobalBinding(typeChecker, "workspace", typeChecker.anyType, "@luau"); addGlobalBinding(typeChecker, XorStr("workspace", typeChecker.anyType, "@lluz"));
addGlobalBinding(typeChecker, "script", typeChecker.anyType, "@luau"); addGlobalBinding(typeChecker, XorStr("script", typeChecker.anyType, "@lluz"));
} }
void Fixture::dumpErrors(const CheckResult& cr) void Fixture::dumpErrors(const CheckResult& cr)
@ -392,13 +392,13 @@ std::string Fixture::getErrors(const CheckResult& cr)
return ss.str(); return ss.str();
} }
void Fixture::validateErrors(const std::vector<Luau::TypeError>& errors) void Fixture::validateErrors(const std::vector<lluz::TypeError>& errors)
{ {
std::ostringstream oss; std::ostringstream oss;
// This helps us validate that error stringification doesn't crash, using both user-facing and internal test-only representation // 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 // 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.clear();
oss << e; oss << e;
@ -410,32 +410,32 @@ void Fixture::validateErrors(const std::vector<Luau::TypeError>& errors)
LoadDefinitionFileResult Fixture::loadDefinition(const std::string& source) LoadDefinitionFileResult Fixture::loadDefinition(const std::string& source)
{ {
unfreeze(typeChecker.globalTypes); unfreeze(typeChecker.globalTypes);
LoadDefinitionFileResult result = loadDefinitionFile(typeChecker, typeChecker.globalScope, source, "@test"); LoadDefinitionFileResult result = loadDefinitionFile(typeChecker, typeChecker.globalScope, source, XorStr("@test"));
freeze(typeChecker.globalTypes); 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; return result;
} }
BuiltinsFixture::BuiltinsFixture(bool freeze, bool prepareAutocomplete) BuiltinsFixture::BuiltinsFixture(bool freeze, bool prepareAutocomplete)
: Fixture(freeze, prepareAutocomplete) : Fixture(freeze, prepareAutocomplete)
{ {
Luau::unfreeze(frontend.typeChecker.globalTypes); lluz::unfreeze(frontend.typeChecker.globalTypes);
Luau::unfreeze(frontend.typeCheckerForAutocomplete.globalTypes); lluz::unfreeze(frontend.typeCheckerForAutocomplete.globalTypes);
registerBuiltinTypes(frontend.typeChecker); registerBuiltinTypes(frontend.typeChecker);
if (prepareAutocomplete) if (prepareAutocomplete)
registerBuiltinTypes(frontend.typeCheckerForAutocomplete); registerBuiltinTypes(frontend.typeCheckerForAutocomplete);
registerTestTypes(); registerTestTypes();
Luau::freeze(frontend.typeChecker.globalTypes); lluz::freeze(frontend.typeChecker.globalTypes);
Luau::freeze(frontend.typeCheckerForAutocomplete.globalTypes); lluz::freeze(frontend.typeCheckerForAutocomplete.globalTypes);
} }
ConstraintGraphBuilderFixture::ConstraintGraphBuilderFixture() ConstraintGraphBuilderFixture::ConstraintGraphBuilderFixture()
: Fixture() : Fixture()
, cgb(mainModuleName, &arena, NotNull(&ice), frontend.getGlobalScope()) , cgb(mainModuleName, &arena, NotNull(&ice), frontend.getGlobalScope2())
, forceTheFlag{"DebugLuauDeferredConstraintResolution", true} , forceTheFlag{"DebuglluzDeferredConstraintResolution", true}
{ {
BlockedTypeVar::nextIndex = 0; BlockedTypeVar::nextIndex = 0;
} }
@ -479,17 +479,17 @@ std::optional<TypeId> lookupName(ScopePtr scope, const std::string& name)
return std::nullopt; return std::nullopt;
} }
std::optional<TypeId> linearSearchForBinding(Scope* scope, const char* name) std::optional<TypeId> linearSearchForBinding(Scope2* scope, const char* name)
{ {
while (scope) while (scope)
{ {
for (const auto& [n, ty] : scope->bindings) for (const auto& [n, ty] : scope->bindings)
{ {
if (n.astName() == name) if (n.astName() == name)
return ty.typeId; return ty;
} }
scope = scope->parent.get(); scope = scope->parent;
} }
return std::nullopt; return std::nullopt;
@ -502,4 +502,4 @@ void dump(const std::vector<Constraint>& constraints)
printf("%s\n", toString(c, opts).c_str()); 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 #pragma once
#include "Luau/Config.h" #include "lluz/Config.h"
#include "Luau/FileResolver.h" #include "lluz/FileResolver.h"
#include "Luau/Frontend.h" #include "lluz/Frontend.h"
#include "Luau/IostreamHelpers.h" #include "lluz/IostreamHelpers.h"
#include "Luau/Linter.h" #include "lluz/Linter.h"
#include "Luau/Location.h" #include "lluz/Location.h"
#include "Luau/ModuleResolver.h" #include "lluz/ModuleResolver.h"
#include "Luau/Scope.h" #include "lluz/Scope.h"
#include "Luau/ToString.h" #include "lluz/ToString.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "IostreamOptional.h" #include "IostreamOptional.h"
#include "ScopedFlags.h" #include "ScopedFlags.h"
@ -22,7 +22,7 @@
#include <optional> #include <optional>
namespace Luau namespace lluz
{ {
struct TestFileResolver struct TestFileResolver
@ -39,7 +39,7 @@ struct TestFileResolver
const ModulePtr getModule(const ModuleName& moduleName) const override const ModulePtr getModule(const ModuleName& moduleName) const override
{ {
LUAU_ASSERT(false); lluz_ASSERT(false);
return nullptr; return nullptr;
} }
@ -95,7 +95,7 @@ struct Fixture
explicit Fixture(bool freeze = true, bool prepareAutocomplete = false); explicit Fixture(bool freeze = true, bool prepareAutocomplete = false);
~Fixture(); ~Fixture();
// Throws Luau::ParseErrors if the parse fails. // Throws lluz::ParseErrors if the parse fails.
AstStatBlock* parse(const std::string& source, const ParseOptions& parseOptions = {}); AstStatBlock* parse(const std::string& source, const ParseOptions& parseOptions = {});
CheckResult check(Mode mode, std::string source); CheckResult check(Mode mode, std::string source);
CheckResult check(const 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> lookupType(const std::string& name);
std::optional<TypeId> lookupImportedType(const std::string& moduleAlias, const std::string& name); std::optional<TypeId> lookupImportedType(const std::string& moduleAlias, const std::string& name);
ScopedFastFlag sff_DebugLuauFreezeArena; ScopedFastFlag sff_DebuglluzFreezeArena;
ScopedFastFlag sff_UnknownNever{"LuauUnknownAndNeverType", true};
TestFileResolver fileResolver; TestFileResolver fileResolver;
TestConfigResolver configResolver; 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> 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 \ do \
{ \ { \
auto&& r = (result); \ auto&& r = (result); \
@ -204,7 +203,7 @@ std::optional<TypeId> linearSearchForBinding(Scope* scope, const char* name);
REQUIRE(!r.errors.empty()); \ REQUIRE(!r.errors.empty()); \
} while (false) } while (false)
#define LUAU_REQUIRE_ERROR_COUNT(count, result) \ #define lluz_REQUIRE_ERROR_COUNT(count, result) \
do \ do \
{ \ { \
auto&& r = (result); \ auto&& r = (result); \
@ -212,4 +211,4 @@ std::optional<TypeId> linearSearchForBinding(Scope* scope, const char* name);
REQUIRE_MESSAGE(count == r.errors.size(), getErrors(r)); \ REQUIRE_MESSAGE(count == r.errors.size(), getErrors(r)); \
} while (false) } 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 // 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 "lluz/AstQuery.h"
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Luau/Frontend.h" #include "lluz/Frontend.h"
#include "Luau/RequireTracer.h" #include "lluz/RequireTracer.h"
#include "Fixture.h" #include "Fixture.h"
@ -10,7 +10,7 @@
#include <algorithm> #include <algorithm>
using namespace Luau; using namespace lluz;
namespace namespace
{ {
@ -49,10 +49,10 @@ struct NaiveFileResolver : NullFileResolver
{ {
if (AstExprGlobal* g = expr->as<AstExprGlobal>()) if (AstExprGlobal* g = expr->as<AstExprGlobal>())
{ {
if (g->name == "Modules") if (g->name == XorStr("Modules"))
return ModuleInfo{"Modules"}; return ModuleInfo{"Modules"};
if (g->name == "game") if (g->name == XorStr("game"))
return ModuleInfo{"game"}; return ModuleInfo{"game"};
} }
else if (AstExprIndexName* i = expr->as<AstExprIndexName>()) else if (AstExprIndexName* i = expr->as<AstExprIndexName>())
@ -66,7 +66,7 @@ struct NaiveFileResolver : NullFileResolver
{ {
AstName func = call->func->as<AstExprIndexName>()->index; 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)}; return ModuleInfo{"game/" + std::string(index->value.data, index->value.size)};
} }
} }
@ -81,12 +81,12 @@ struct FrontendFixture : BuiltinsFixture
{ {
FrontendFixture() FrontendFixture()
{ {
addGlobalBinding(typeChecker, "game", frontend.typeChecker.anyType, "@test"); addGlobalBinding(typeChecker, XorStr("game", frontend.typeChecker.anyType, "@test"));
addGlobalBinding(typeChecker, "script", 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") TEST_CASE_FIXTURE(FrontendFixture, "find_a_require")
{ {
@ -96,9 +96,9 @@ TEST_CASE_FIXTURE(FrontendFixture, "find_a_require")
NaiveFileResolver naiveFileResolver; NaiveFileResolver naiveFileResolver;
auto res = traceRequires(&naiveFileResolver, program, ""); auto res = traceRequires(&naiveFileResolver, program, XorStr(""));
CHECK_EQ(1, res.requireList.size()); 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. // 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; NaiveFileResolver naiveFileResolver;
auto res = traceRequires(&naiveFileResolver, program, ""); auto res = traceRequires(&naiveFileResolver, program, XorStr(""));
CHECK_EQ(1, res.requireList.size()); CHECK_EQ(1, res.requireList.size());
} }
@ -137,7 +137,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "real_source")
NaiveFileResolver naiveFileResolver; NaiveFileResolver naiveFileResolver;
auto res = traceRequires(&naiveFileResolver, program, ""); auto res = traceRequires(&naiveFileResolver, program, XorStr(""));
CHECK_EQ(8, res.requireList.size()); CHECK_EQ(8, res.requireList.size());
} }
@ -150,12 +150,12 @@ TEST_CASE_FIXTURE(FrontendFixture, "automatically_check_dependent_scripts")
return {b_value = A.hello} 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"]; ModulePtr bModule = frontend.moduleResolver.modules["game/Gui/Modules/B"];
REQUIRE(bModule != nullptr); REQUIRE(bModule != nullptr);
CHECK(bModule->errors.empty()); CHECK(bModule->errors.empty());
Luau::dumpErrors(bModule); lluz::dumpErrors(bModule);
auto bExports = first(bModule->getModuleScope()->returnType); auto bExports = first(bModule->getModuleScope()->returnType);
REQUIRE(!!bExports); REQUIRE(!!bExports);
@ -188,8 +188,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "automatically_check_cyclically_dependent_scr
return {} return {}
)"; )";
CheckResult result1 = frontend.check("game/Gui/Modules/B"); CheckResult result1 = frontend.check(XorStr("game/Gui/Modules/B"));
LUAU_REQUIRE_ERROR_COUNT(4, result1); lluz_REQUIRE_ERROR_COUNT(4, result1);
CHECK_MESSAGE(get<ModuleHasCyclicDependency>(result1.errors[0]), "Should have been a ModuleHasCyclicDependency: " << toString(result1.errors[0])); 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])); CHECK_MESSAGE(get<ModuleHasCyclicDependency>(result1.errors[2]), "Should have been a ModuleHasCyclicDependency: " << toString(result1.errors[2]));
CheckResult result2 = frontend.check("game/Gui/Modules/D"); CheckResult result2 = frontend.check(XorStr("game/Gui/Modules/D"));
LUAU_REQUIRE_ERROR_COUNT(0, result2); lluz_REQUIRE_ERROR_COUNT(0, result2);
} }
TEST_CASE_FIXTURE(FrontendFixture, "any_annotation_breaks_cycle") TEST_CASE_FIXTURE(FrontendFixture, "any_annotation_breaks_cycle")
@ -214,8 +214,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "any_annotation_breaks_cycle")
return {hello = A.hello} return {hello = A.hello}
)"; )";
CheckResult result = frontend.check("game/Gui/Modules/A"); CheckResult result = frontend.check(XorStr("game/Gui/Modules/A"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(FrontendFixture, "nocheck_modules_are_typed") 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 local five : A.Foo = 5
)"; )";
CheckResult result = frontend.check("game/Gui/Modules/C"); CheckResult result = frontend.check(XorStr("game/Gui/Modules/C"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ModulePtr aModule = frontend.moduleResolver.modules["game/Gui/Modules/A"]; ModulePtr aModule = frontend.moduleResolver.modules["game/Gui/Modules/A"];
REQUIRE(bool(aModule)); REQUIRE(bool(aModule));
@ -269,8 +269,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_detection_between_check_and_nocheck")
return {hello = A.hello} return {hello = A.hello}
)"; )";
CheckResult result = frontend.check("game/Gui/Modules/A"); CheckResult result = frontend.check(XorStr("game/Gui/Modules/A"));
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(FrontendFixture, "nocheck_cycle_used_by_checked") 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} return {a=A, b=B}
)"; )";
CheckResult result = frontend.check("game/Gui/Modules/C"); CheckResult result = frontend.check(XorStr("game/Gui/Modules/C"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ModulePtr cModule = frontend.moduleResolver.modules["game/Gui/Modules/C"]; ModulePtr cModule = frontend.moduleResolver.modules["game/Gui/Modules/C"];
REQUIRE(bool(cModule)); REQUIRE(bool(cModule));
@ -320,8 +320,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_detection_disabled_in_nocheck")
return {hello = A.hello} return {hello = A.hello}
)"; )";
CheckResult result = frontend.check("game/Gui/Modules/A"); CheckResult result = frontend.check(XorStr("game/Gui/Modules/A"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(FrontendFixture, "cycle_errors_can_be_fixed") 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} return {hello = A.hello}
)"; )";
CheckResult result1 = frontend.check("game/Gui/Modules/A"); CheckResult result1 = frontend.check(XorStr("game/Gui/Modules/A"));
LUAU_REQUIRE_ERROR_COUNT(2, result1); lluz_REQUIRE_ERROR_COUNT(2, result1);
CHECK_MESSAGE(get<ModuleHasCyclicDependency>(result1.errors[0]), "Should have been a ModuleHasCyclicDependency: " << toString(result1.errors[0])); 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"( fileResolver.source["game/Gui/Modules/B"] = R"(
return {hello = 42} return {hello = 42}
)"; )";
frontend.markDirty("game/Gui/Modules/B"); frontend.markDirty(XorStr("game/Gui/Modules/B"));
CheckResult result2 = frontend.check("game/Gui/Modules/A"); CheckResult result2 = frontend.check(XorStr("game/Gui/Modules/A"));
LUAU_REQUIRE_NO_ERRORS(result2); lluz_REQUIRE_NO_ERRORS(result2);
} }
TEST_CASE_FIXTURE(FrontendFixture, "cycle_error_paths") TEST_CASE_FIXTURE(FrontendFixture, "cycle_error_paths")
@ -366,22 +366,22 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_error_paths")
return {hello = A.hello} return {hello = A.hello}
)"; )";
CheckResult result = frontend.check("game/Gui/Modules/A"); CheckResult result = frontend.check(XorStr("game/Gui/Modules/A"));
LUAU_REQUIRE_ERROR_COUNT(2, result); lluz_REQUIRE_ERROR_COUNT(2, result);
auto ce1 = get<ModuleHasCyclicDependency>(result.errors[0]); auto ce1 = get<ModuleHasCyclicDependency>(result.errors[0]);
REQUIRE(ce1); 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); REQUIRE_EQ(ce1->cycle.size(), 2);
CHECK_EQ(ce1->cycle[0], "game/Gui/Modules/A"); CHECK_EQ(ce1->cycle[0], XorStr("game/Gui/Modules/A"));
CHECK_EQ(ce1->cycle[1], "game/Gui/Modules/B"); CHECK_EQ(ce1->cycle[1], XorStr("game/Gui/Modules/B"));
auto ce2 = get<ModuleHasCyclicDependency>(result.errors[1]); auto ce2 = get<ModuleHasCyclicDependency>(result.errors[1]);
REQUIRE(ce2); 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); REQUIRE_EQ(ce2->cycle.size(), 2);
CHECK_EQ(ce2->cycle[0], "game/Gui/Modules/B"); CHECK_EQ(ce2->cycle[0], XorStr("game/Gui/Modules/B"));
CHECK_EQ(ce2->cycle[1], "game/Gui/Modules/A"); CHECK_EQ(ce2->cycle[1], XorStr("game/Gui/Modules/A"));
} }
TEST_CASE_FIXTURE(FrontendFixture, "cycle_incremental_type_surface") TEST_CASE_FIXTURE(FrontendFixture, "cycle_incremental_type_surface")
@ -390,20 +390,20 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_incremental_type_surface")
return {hello = 2} return {hello = 2}
)"; )";
CheckResult result = frontend.check("game/A"); CheckResult result = frontend.check(XorStr("game/A"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
fileResolver.source["game/A"] = R"( fileResolver.source["game/A"] = R"(
local me = require(game.A) local me = require(game.A)
return {hello = 2} return {hello = 2}
)"; )";
frontend.markDirty("game/A"); frontend.markDirty(XorStr("game/A"));
result = frontend.check("game/A"); result = frontend.check(XorStr("game/A"));
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
auto ty = requireType("game/A", "me"); auto ty = requireType(XorStr("game/A", "me"));
CHECK_EQ(toString(ty), "any"); CHECK_EQ(toString(ty), XorStr("any"));
} }
TEST_CASE_FIXTURE(FrontendFixture, "cycle_incremental_type_surface_longer") 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} return {mod_a = 2}
)"; )";
CheckResult result = frontend.check("game/A"); CheckResult result = frontend.check(XorStr("game/A"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
fileResolver.source["game/B"] = R"( fileResolver.source["game/B"] = R"(
local me = require(game.A) local me = require(game.A)
return {mod_b = 4} return {mod_b = 4}
)"; )";
result = frontend.check("game/B"); result = frontend.check(XorStr("game/B"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
fileResolver.source["game/A"] = R"( fileResolver.source["game/A"] = R"(
local me = require(game.B) local me = require(game.B)
return {mod_a_prime = 3} return {mod_a_prime = 3}
)"; )";
frontend.markDirty("game/A"); frontend.markDirty(XorStr("game/A"));
frontend.markDirty("game/B"); frontend.markDirty(XorStr("game/B"));
result = frontend.check("game/A"); result = frontend.check(XorStr("game/A"));
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
TypeId tyA = requireType("game/A", "me"); TypeId tyA = requireType(XorStr("game/A", "me"));
CHECK_EQ(toString(tyA), "any"); CHECK_EQ(toString(tyA), XorStr("any"));
result = frontend.check("game/B"); result = frontend.check(XorStr("game/B"));
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
TypeId tyB = requireType("game/B", "me"); TypeId tyB = requireType(XorStr("game/B", "me"));
CHECK_EQ(toString(tyB), "any"); CHECK_EQ(toString(tyB), XorStr("any"));
} }
TEST_CASE_FIXTURE(FrontendFixture, "dont_reparse_clean_file_when_linting") 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 end
)"; )";
frontend.check("Modules/A"); frontend.check(XorStr("Modules/A"));
fileResolver.source["Modules/A"] = R"( fileResolver.source["Modules/A"] = R"(
-- We have fixed the lint error, but we did not tell the Frontend that the file is changed! -- 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); 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()); 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} return {b_value = A.hello}
)"; )";
frontend.check("game/Gui/Modules/B"); frontend.check(XorStr("game/Gui/Modules/B"));
fileResolver.source["game/Gui/Modules/A"] = fileResolver.source["game/Gui/Modules/A"] =
"Massively incorrect syntax haha oops! However! The frontend doesn't know that this file needs reparsing!"; "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"]; ModulePtr bModule = frontend.moduleResolver.modules["game/Gui/Modules/B"];
CHECK(bModule->errors.empty()); CHECK(bModule->errors.empty());
Luau::dumpErrors(bModule); lluz::dumpErrors(bModule);
} }
TEST_CASE_FIXTURE(FrontendFixture, "recheck_if_dependent_script_is_dirty") 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} 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!'}"; 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"]; ModulePtr bModule = frontend.moduleResolver.modules["game/Gui/Modules/B"];
CHECK(bModule->errors.empty()); CHECK(bModule->errors.empty());
Luau::dumpErrors(bModule); lluz::dumpErrors(bModule);
auto bExports = first(bModule->getModuleScope()->returnType); auto bExports = first(bModule->getModuleScope()->returnType);
REQUIRE(!!bExports); REQUIRE(!!bExports);
@ -528,12 +528,12 @@ TEST_CASE_FIXTURE(FrontendFixture, "recheck_if_dependent_script_has_a_parse_erro
return {} return {}
)"; )";
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_EQ("Modules/A", result.errors[0].moduleName); CHECK_EQ("Modules/A", result.errors[0].moduleName);
CheckResult result2 = frontend.check("Modules/B"); CheckResult result2 = frontend.check(XorStr("Modules/B"));
LUAU_REQUIRE_ERROR_COUNT(1, result2); lluz_REQUIRE_ERROR_COUNT(1, result2);
CHECK_EQ(result2.errors[0], result.errors[0]); CHECK_EQ(result2.errors[0], result.errors[0]);
} }
#endif #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!!"; fileResolver.source["Modules/A"] = "oh no a blatant syntax error!!";
CheckResult one = frontend.check("Modules/A"); CheckResult one = frontend.check(XorStr("Modules/A"));
CheckResult two = frontend.check("Modules/A"); CheckResult two = frontend.check(XorStr("Modules/A"));
CHECK(!one.errors.empty()); CHECK(!one.errors.empty());
CHECK(!two.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'"; 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!"; 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()); 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!' local b: number = 'another one! This is quite distressing!'
)"; )";
CheckResult result = frontend.check("game/Gui/Modules/B"); CheckResult result = frontend.check(XorStr("game/Gui/Modules/B"));
LUAU_REQUIRE_ERROR_COUNT(2, result); lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ("game/Gui/Modules/A", result.errors[0].moduleName); CHECK_EQ("game/Gui/Modules/A", result.errors[0].moduleName);
CHECK_EQ("game/Gui/Modules/B", result.errors[1].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) local B = require(Modules.B)
)"; )";
CheckResult result = frontend.check("Modules/A"); CheckResult result = frontend.check(XorStr("Modules/A"));
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
std::string s = toString(result.errors[0]); std::string s = toString(result.errors[0]);
CHECK_MESSAGE(get<UnknownRequire>(result.errors[0]), "Should have been an UnknownRequire: " << 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 local B = require(Modules.B) :: any
)"; )";
CheckResult result = frontend.check("Modules/A"); CheckResult result = frontend.check(XorStr("Modules/A"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(FrontendFixture, "report_syntax_error_in_required_file") 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) local A = require(Modules.A)
)"; )";
CheckResult result = frontend.check("Modules/B"); CheckResult result = frontend.check(XorStr("Modules/B"));
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
CHECK_EQ("Modules/A", result.errors[0].moduleName); CHECK_EQ("Modules/A", result.errors[0].moduleName);
@ -624,7 +624,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "report_syntax_error_in_required_file")
}); });
if (!b) if (!b)
{ {
CHECK_MESSAGE(false, "Expected a syntax error!"); CHECK_MESSAGE(false, XorStr("Expected a syntax error!"));
dumpErrors(result); dumpErrors(result);
} }
} }
@ -642,11 +642,11 @@ TEST_CASE_FIXTURE(FrontendFixture, "re_report_type_error_in_required_file")
print(A.n) print(A.n)
)"; )";
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);
CheckResult result2 = frontend.check("Modules/B"); CheckResult result2 = frontend.check(XorStr("Modules/B"));
LUAU_REQUIRE_ERROR_COUNT(1, result2); lluz_REQUIRE_ERROR_COUNT(1, result2);
CHECK_EQ("Modules/A", result.errors[0].moduleName); CHECK_EQ("Modules/A", result.errors[0].moduleName);
} }
@ -665,16 +665,16 @@ TEST_CASE_FIXTURE(FrontendFixture, "accumulate_cached_errors")
print(A, b) 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/A", result1.errors[0].moduleName);
CHECK_EQ("Modules/B", result1.errors[1].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/A", result2.errors[0].moduleName);
CHECK_EQ("Modules/B", result2.errors[1].moduleName); CHECK_EQ("Modules/B", result2.errors[1].moduleName);
@ -695,9 +695,9 @@ TEST_CASE_FIXTURE(FrontendFixture, "accumulate_cached_errors_in_consistent_order
return {} 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[2].moduleName);
CHECK_EQ("Modules/A", result1.errors[3].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[0].moduleName);
CHECK_EQ("Modules/B", result1.errors[1].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()); CHECK_EQ(4, result2.errors.size());
for (size_t i = 0; i < result1.errors.size(); ++i) 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); 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()); CHECK_EQ(1, result.warnings.size());
configResolver.configFiles["Module/A"].enabledLint.disableWarning(LintWarning::Code_ForRange); 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()); CHECK_EQ(0, result2.warnings.size());
LintOptions overrideOptions; LintOptions overrideOptions;
@ -756,6 +756,26 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_lint_uses_correct_config")
CHECK_EQ(0, result4.warnings.size()); 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") TEST_CASE_FIXTURE(FrontendFixture, "discard_type_graphs")
{ {
Frontend fe{&fileResolver, &configResolver, {false}}; Frontend fe{&fileResolver, &configResolver, {false}};
@ -764,9 +784,9 @@ TEST_CASE_FIXTURE(FrontendFixture, "discard_type_graphs")
local a = {1,2,3,4,5} 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.typeVars.size());
CHECK_EQ(0, module->internalTypes.typePacks.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'} 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()); REQUIRE_EQ(1, result.errors.size());
@ -817,9 +837,9 @@ TEST_CASE_FIXTURE(FrontendFixture, "trace_requires_in_nonstrict_mode")
print(A.f(5)) -- OK 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(4, result.errors[0].location.begin.line);
CHECK_EQ(5, result.errors[1].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") TEST_CASE_FIXTURE(FrontendFixture, "environments")
{ {
ScopePtr testScope = frontend.addEnvironment("test"); ScopePtr testScope = frontend.addEnvironment(XorStr("test"));
unfreeze(typeChecker.globalTypes); unfreeze(typeChecker.globalTypes);
loadDefinitionFile(typeChecker, testScope, R"( loadDefinitionFile(typeChecker, testScope, R"(
export type Foo = number | string export type Foo = number | string
)", )",
"@test"); XorStr("@test"));
freeze(typeChecker.globalTypes); freeze(typeChecker.globalTypes);
fileResolver.source["A"] = R"( fileResolver.source["A"] = R"(
@ -848,11 +868,11 @@ TEST_CASE_FIXTURE(FrontendFixture, "environments")
fileResolver.environments["A"] = "test"; fileResolver.environments["A"] = "test";
CheckResult resultA = frontend.check("A"); CheckResult resultA = frontend.check(XorStr("A"));
LUAU_REQUIRE_NO_ERRORS(resultA); lluz_REQUIRE_NO_ERRORS(resultA);
CheckResult resultB = frontend.check("B"); CheckResult resultB = frontend.check(XorStr("B"));
LUAU_REQUIRE_ERROR_COUNT(1, resultB); lluz_REQUIRE_ERROR_COUNT(1, resultB);
} }
TEST_CASE_FIXTURE(FrontendFixture, "ast_node_at_position") 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} return {foo = 1}
)"; )";
CheckResult r1 = frontend.check("Module/A"); CheckResult r1 = frontend.check(XorStr("Module/A"));
LUAU_REQUIRE_NO_ERRORS(r1); lluz_REQUIRE_NO_ERRORS(r1);
Frontend::Stats stats1 = frontend.stats; Frontend::Stats stats1 = frontend.stats;
CHECK_EQ(2, stats1.files); CHECK_EQ(2, stats1.files);
frontend.markDirty("Module/A"); frontend.markDirty(XorStr("Module/A"));
frontend.markDirty("Module/B"); frontend.markDirty(XorStr("Module/B"));
CheckResult r2 = frontend.check("Module/A"); CheckResult r2 = frontend.check(XorStr("Module/A"));
LUAU_REQUIRE_NO_ERRORS(r2); lluz_REQUIRE_NO_ERRORS(r2);
Frontend::Stats stats2 = frontend.stats; Frontend::Stats stats2 = frontend.stats;
CHECK_EQ(4, stats2.files); CHECK_EQ(4, stats2.files);
@ -919,18 +939,18 @@ TEST_CASE_FIXTURE(FrontendFixture, "clearStats")
return {foo = 1} return {foo = 1}
)"; )";
CheckResult r1 = frontend.check("Module/A"); CheckResult r1 = frontend.check(XorStr("Module/A"));
LUAU_REQUIRE_NO_ERRORS(r1); lluz_REQUIRE_NO_ERRORS(r1);
Frontend::Stats stats1 = frontend.stats; Frontend::Stats stats1 = frontend.stats;
CHECK_EQ(2, stats1.files); CHECK_EQ(2, stats1.files);
frontend.markDirty("Module/A"); frontend.markDirty(XorStr("Module/A"));
frontend.markDirty("Module/B"); frontend.markDirty(XorStr("Module/B"));
frontend.clearStats(); frontend.clearStats();
CheckResult r2 = frontend.check("Module/A"); CheckResult r2 = frontend.check(XorStr("Module/A"));
LUAU_REQUIRE_NO_ERRORS(r2); lluz_REQUIRE_NO_ERRORS(r2);
Frontend::Stats stats2 = frontend.stats; Frontend::Stats stats2 = frontend.stats;
CHECK_EQ(2, stats2.files); CHECK_EQ(2, stats2.files);
@ -942,13 +962,13 @@ TEST_CASE_FIXTURE(FrontendFixture, "typecheck_twice_for_ast_types")
local a = 1 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); REQUIRE_EQ(module->astTypes.size(), 1);
auto it = module->astTypes.begin(); 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") 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() a:b() -- this should error, since A doesn't define a:b()
)"; )";
CheckResult resultA = frontend.check("Module/A"); CheckResult resultA = frontend.check(XorStr("Module/A"));
LUAU_REQUIRE_NO_ERRORS(resultA); lluz_REQUIRE_NO_ERRORS(resultA);
CheckResult resultB = frontend.check("Module/B"); CheckResult resultB = frontend.check(XorStr("Module/B"));
LUAU_REQUIRE_ERRORS(resultB); lluz_REQUIRE_ERRORS(resultB);
CheckResult resultC = frontend.check("Module/C"); CheckResult resultC = frontend.check(XorStr("Module/C"));
LUAU_REQUIRE_ERRORS(resultC); lluz_REQUIRE_ERRORS(resultC);
} }
// This test does not use TEST_CASE_FIXTURE because we need to set a flag before // 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") 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. // 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; FrontendFixture fix;
@ -1008,7 +1028,7 @@ return false;
)"; )";
// We don't care about the result. That we haven't crashed is enough. // 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") TEST_CASE("check_without_builtin_next")
@ -1021,77 +1041,8 @@ TEST_CASE("check_without_builtin_next")
fileResolver.source["Module/B"] = "return next"; fileResolver.source["Module/B"] = "return next";
// We don't care about the result. That we haven't crashed is enough. // We don't care about the result. That we haven't crashed is enough.
frontend.check("Module/A"); frontend.check(XorStr("Module/A"));
frontend.check("Module/B"); frontend.check(XorStr("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);
} }
TEST_SUITE_END(); 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 #pragma once
#include <ostream> #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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Ast.h" #include "lluz/Ast.h"
#include "Luau/JsonEncoder.h" #include "lluz/JsonEncoder.h"
#include "Luau/Parser.h" #include "lluz/Parser.h"
#include "doctest.h" #include "doctest.h"
#include <ostream> #include <ostream>
using namespace Luau; using namespace lluz;
struct JsonEncoderFixture struct JsonEncoderFixture
{ {
@ -49,26 +49,17 @@ struct JsonEncoderFixture
} }
}; };
TEST_SUITE_BEGIN("JsonEncoderTests"); TEST_SUITE_BEGIN(XorStr("JsonEncoderTests"));
TEST_CASE("encode_constants") TEST_CASE("encode_constants")
{ {
AstExprConstantNil nil{Location()}; AstExprConstantNil nil{Location()};
AstExprConstantBool b{Location(), true}; AstExprConstantBool b{Location(), true};
AstExprConstantNumber n{Location(), 8.2}; 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":"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":"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":8.2})", 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));
} }
TEST_CASE("basic_escaping") TEST_CASE("basic_escaping")
@ -96,7 +87,7 @@ TEST_CASE("encode_AstStatBlock")
AstStatBlock block{Location(), bodyArray}; AstStatBlock block{Location(), bodyArray};
CHECK_EQ( 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)); toJson(&block));
} }
@ -115,31 +106,7 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_tables")
CHECK( CHECK(
json == 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}}]}]}]})"); 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_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}]})");
} }
TEST_CASE("encode_AstExprGroup") TEST_CASE("encode_AstExprGroup")
@ -165,35 +132,24 @@ TEST_CASE("encode_AstExprGlobal")
CHECK(json == expected); 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") TEST_CASE("encode_AstExprLocal")
{ {
AstLocal local{AstName{"foo"}, Location{}, nullptr, 0, 0, nullptr}; AstLocal local{AstName{"foo"}, Location{}, nullptr, 0, 0, nullptr};
AstExprLocal exprLocal{Location{}, &local, false}; 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") TEST_CASE("encode_AstExprVarargs")
{ {
AstExprVarargs varargs{Location{}}; 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") 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 = 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"})"; 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") TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprIndexName")
{ {
AstExpr* expr = expectParseExpr("foo.bar"); AstExpr* expr = expectParseExpr(XorStr("foo.bar"));
std::string_view expected = 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":"."})"; 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") TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprIndexExpr")
{ {
AstExpr* expr = expectParseExpr("foo['bar']"); AstExpr* expr = expectParseExpr(XorStr("foo['bar']"));
std::string_view expected = 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"}})"; 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") 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 = 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); CHECK(toJson(expr) == expected);
} }
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprTable") 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 = 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); CHECK(toJson(expr) == expected);
} }
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprUnary") TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprUnary")
{ {
AstExpr* expr = expectParseExpr("-b"); AstExpr* expr = expectParseExpr(XorStr("-b"));
std::string_view expected = 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); CHECK(toJson(expr) == expected);
} }
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprBinary") TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprBinary")
{ {
AstExpr* expr = expectParseExpr("b + c"); AstExpr* expr = expectParseExpr(XorStr("b + c"));
std::string_view expected = 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"}})"; 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") TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstExprTypeAssertion")
{ {
AstExpr* expr = expectParseExpr("b :: any"); AstExpr* expr = expectParseExpr(XorStr("b :: any"));
std::string_view expected = 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":[]}})"; 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") 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 = 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})"; 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") 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 = 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); CHECK(toJson(statement) == expected);
} }
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatRepeat") TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatRepeat")
{ {
AstStat* statement = expectParseStatement("repeat until true"); AstStat* statement = expectParseStatement(XorStr("repeat until true"));
std::string_view expected = 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})"; 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") 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 = 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); CHECK(toJson(statement) == expected);
} }
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatContinue") 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 = 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); CHECK(toJson(statement) == expected);
} }
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatFor") 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 = 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); CHECK(toJson(statement) == expected);
} }
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatForIn") 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 = 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); CHECK(toJson(statement) == expected);
} }
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatCompoundAssign") TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatCompoundAssign")
{ {
AstStat* statement = expectParseStatement("a += b"); AstStat* statement = expectParseStatement(XorStr("a += b"));
std::string_view expected = 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"}})"; 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") 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 = 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); CHECK(toJson(statement) == expected);
} }
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatTypeAlias") TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatTypeAlias")
{ {
AstStat* statement = expectParseStatement("type A = B"); AstStat* statement = expectParseStatement(XorStr("type A = B"));
std::string_view expected = 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})"; 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") 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 = 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); CHECK(toJson(statement) == expected);
} }
@ -414,27 +370,27 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstStatDeclareClass")
REQUIRE(2 == root->body.size); REQUIRE(2 == root->body.size);
std::string_view expected1 = 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); CHECK(toJson(root->body.data[0]) == expected1);
std::string_view expected2 = 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); CHECK(toJson(root->body.data[1]) == expected2);
} }
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_annotation") 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 = 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); CHECK(toJson(statement) == expected);
} }
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstTypeError") TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstTypeError")
{ {
ParseResult parseResult = parse("type T = "); ParseResult parseResult = parse(XorStr("type T = "));
REQUIRE(1 == parseResult.root->body.size); REQUIRE(1 == parseResult.root->body.size);
AstStat* statement = parseResult.root->body.data[0]; AstStat* statement = parseResult.root->body.data[0];
@ -455,7 +411,7 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstTypePackExplicit")
CHECK(2 == root->body.size); CHECK(2 == root->body.size);
std::string_view expected = 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); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Fixture.h" #include "Fixture.h"
#include "ScopedFlags.h" #include "ScopedFlags.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
static void merge(TypeArena& arena, RefinementMap& l, const RefinementMap& r) 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. // TODO: normalize here also.
std::unordered_set<TypeId> s; std::unordered_set<TypeId> s;
@ -34,9 +34,9 @@ static LValue mkSymbol(const std::string& s)
return Symbol{AstName{s.data()}}; 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 a = "a";
std::string b = "b"; std::string b = "b";
@ -66,7 +66,7 @@ TEST_CASE("Luau_merge_hashmap_order")
CHECK_EQ("boolean | number", toString(m[mkSymbol(c)])); 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 a = "a";
std::string b = "b"; 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Linter.h" #include "lluz/Linter.h"
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Fixture.h" #include "Fixture.h"
#include "ScopedFlags.h" #include "ScopedFlags.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
TEST_SUITE_BEGIN("Linter"); TEST_SUITE_BEGIN(XorStr("Linter"));
TEST_CASE_FIXTURE(Fixture, "CleanCode") TEST_CASE_FIXTURE(Fixture, "CleanCode")
{ {
@ -26,10 +26,10 @@ return math.max(fib(5), 1)
TEST_CASE_FIXTURE(Fixture, "UnknownGlobal") TEST_CASE_FIXTURE(Fixture, "UnknownGlobal")
{ {
LintResult result = lint("--!nocheck\nreturn foo"); LintResult result = lint(XorStr("--!nocheck\nreturn foo"));
REQUIRE_EQ(result.warnings.size(), 1); 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") 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 // Normally this would be defined externally, so hack it in for testing
addGlobalBinding(typeChecker, "Wait", Binding{typeChecker.anyType, {}, true, "wait", "@test/global/Wait"}); 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); 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") TEST_CASE_FIXTURE(Fixture, "PlaceholderRead")
@ -51,7 +51,7 @@ return _
)"); )");
CHECK_EQ(result.warnings.size(), 1); 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") TEST_CASE_FIXTURE(Fixture, "PlaceholderReadGlobal")
@ -62,7 +62,7 @@ print(_)
)"); )");
CHECK_EQ(result.warnings.size(), 1); 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") TEST_CASE_FIXTURE(Fixture, "PlaceholderWrite")
@ -87,8 +87,8 @@ assert(5)
)"); )");
CHECK_EQ(result.warnings.size(), 2); 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[0].text, XorStr("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[1].text, XorStr("Built-in global 'assert' is overwritten here; consider using a local or changing the name"));
} }
TEST_CASE_FIXTURE(Fixture, "MultilineBlock") 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.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") 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.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") TEST_CASE_FIXTURE(Fixture, "MultilineBlockLocalDo")
@ -139,7 +139,7 @@ print(math.max(1,
)"); )");
CHECK_EQ(result.warnings.size(), 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") TEST_CASE_FIXTURE(Fixture, "GlobalAsLocal")
@ -154,12 +154,12 @@ return bar()
)"); )");
CHECK_EQ(result.warnings.size(), 1); 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") TEST_CASE_FIXTURE(Fixture, "GlobalAsLocalMultiFx")
{ {
ScopedFastFlag sff{"LuauLintGlobalNeverReadBeforeWritten", true}; ScopedFastFlag sff{"lluzLintGlobalNeverReadBeforeWritten", true};
LintResult result = lint(R"( LintResult result = lint(R"(
function bar() function bar()
foo = 6 foo = 6
@ -175,12 +175,12 @@ return bar() + baz()
)"); )");
REQUIRE_EQ(result.warnings.size(), 1); 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") TEST_CASE_FIXTURE(Fixture, "GlobalAsLocalMultiFxWithRead")
{ {
ScopedFastFlag sff{"LuauLintGlobalNeverReadBeforeWritten", true}; ScopedFastFlag sff{"lluzLintGlobalNeverReadBeforeWritten", true};
LintResult result = lint(R"( LintResult result = lint(R"(
function bar() function bar()
foo = 6 foo = 6
@ -204,7 +204,7 @@ return bar() + baz() + read()
TEST_CASE_FIXTURE(Fixture, "GlobalAsLocalWithConditional") TEST_CASE_FIXTURE(Fixture, "GlobalAsLocalWithConditional")
{ {
ScopedFastFlag sff{"LuauLintGlobalNeverReadBeforeWritten", true}; ScopedFastFlag sff{"lluzLintGlobalNeverReadBeforeWritten", true};
LintResult result = lint(R"( LintResult result = lint(R"(
function bar() function bar()
if true then foo = 6 end if true then foo = 6 end
@ -224,7 +224,7 @@ return bar() + baz()
TEST_CASE_FIXTURE(Fixture, "GlobalAsLocal3WithConditionalRead") TEST_CASE_FIXTURE(Fixture, "GlobalAsLocal3WithConditionalRead")
{ {
ScopedFastFlag sff{"LuauLintGlobalNeverReadBeforeWritten", true}; ScopedFastFlag sff{"lluzLintGlobalNeverReadBeforeWritten", true};
LintResult result = lint(R"( LintResult result = lint(R"(
function bar() function bar()
foo = 6 foo = 6
@ -248,7 +248,7 @@ return bar() + baz() + read()
TEST_CASE_FIXTURE(Fixture, "GlobalAsLocalInnerRead") TEST_CASE_FIXTURE(Fixture, "GlobalAsLocalInnerRead")
{ {
ScopedFastFlag sff{"LuauLintGlobalNeverReadBeforeWritten", true}; ScopedFastFlag sff{"lluzLintGlobalNeverReadBeforeWritten", true};
LintResult result = lint(R"( LintResult result = lint(R"(
function foo() function foo()
local f = function() return bar end local f = function() return bar end
@ -292,7 +292,7 @@ fnB() -- prints "false", "nil"
CHECK_EQ(result.warnings.size(), 1); CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].text, 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") TEST_CASE_FIXTURE(Fixture, "LocalShadowLocal")
@ -306,7 +306,7 @@ print(arg)
)"); )");
CHECK_EQ(result.warnings.size(), 1); 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") TEST_CASE_FIXTURE(BuiltinsFixture, "LocalShadowGlobal")
@ -324,7 +324,7 @@ return bar()
)"); )");
CHECK_EQ(result.warnings.size(), 1); 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") TEST_CASE_FIXTURE(Fixture, "LocalShadowArgument")
@ -339,7 +339,7 @@ return bar()
)"); )");
CHECK_EQ(result.warnings.size(), 1); 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") TEST_CASE_FIXTURE(Fixture, "LocalUnused")
@ -359,14 +359,14 @@ return bar()
)"); )");
CHECK_EQ(result.warnings.size(), 2); 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[0].text, XorStr("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[1].text, XorStr("Variable 'blarg' is never used; prefix with '_' to silence"));
} }
TEST_CASE_FIXTURE(Fixture, "ImportUnused") TEST_CASE_FIXTURE(Fixture, "ImportUnused")
{ {
// Normally this would be defined externally, so hack it in for testing // 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"( LintResult result = lint(R"(
local Roact = require(game.Packages.Roact) 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.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") TEST_CASE_FIXTURE(Fixture, "FunctionUnused")
@ -399,8 +399,8 @@ return foo()
)"); )");
CHECK_EQ(result.warnings.size(), 2); 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[0].text, XorStr("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[1].text, XorStr("Function 'qux' is never used; prefix with '_' to silence"));
} }
TEST_CASE_FIXTURE(Fixture, "UnreachableCodeBasic") TEST_CASE_FIXTURE(Fixture, "UnreachableCodeBasic")
@ -415,7 +415,7 @@ print("hi!")
CHECK_EQ(result.warnings.size(), 1); CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 5); 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") TEST_CASE_FIXTURE(Fixture, "UnreachableCodeLoopBreak")
@ -431,7 +431,7 @@ print("hi!")
CHECK_EQ(result.warnings.size(), 1); CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 3); 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") TEST_CASE_FIXTURE(Fixture, "UnreachableCodeLoopContinue")
@ -447,7 +447,7 @@ print("hi!")
CHECK_EQ(result.warnings.size(), 1); CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 3); 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") TEST_CASE_FIXTURE(Fixture, "UnreachableCodeIfMerge")
@ -483,7 +483,7 @@ return { foo1, foo2, foo3 }
CHECK_EQ(result.warnings.size(), 1); CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 7); 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") TEST_CASE_FIXTURE(Fixture, "UnreachableCodeErrorReturnSilent")
@ -538,7 +538,7 @@ return foo1
CHECK_EQ(result.warnings.size(), 1); CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 7); 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") TEST_CASE_FIXTURE(Fixture, "UnreachableCodeErrorReturnPropagate")
@ -559,7 +559,7 @@ return foo1
CHECK_EQ(result.warnings.size(), 1); CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 8); 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") TEST_CASE_FIXTURE(Fixture, "UnreachableCodeLoopWhile")
@ -602,7 +602,7 @@ TEST_CASE_FIXTURE(Fixture, "UnknownType")
{"ClassName", {typeChecker.anyType}}, {"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); TypeId instanceType = typeChecker.globalTypes.addType(instanceTable);
TypeFun instanceTypeFun{{}, instanceType}; TypeFun instanceTypeFun{{}, instanceType};
@ -610,22 +610,22 @@ TEST_CASE_FIXTURE(Fixture, "UnknownType")
LintResult result = lint(R"( LintResult result = lint(R"(
local game = ... local game = ...
local _e01 = type(game) == "Part" local _e01 = type(game) == XorStr("Part")
local _e02 = typeof(game) == "Bar" local _e02 = typeof(game) == XorStr("Bar")
local _e03 = typeof(game) == "vector" local _e03 = typeof(game) == XorStr("vector")
local _o01 = type(game) == "number" local _o01 = type(game) == XorStr("number")
local _o02 = type(game) == "vector" local _o02 = type(game) == XorStr("vector")
local _o03 = typeof(game) == "Part" local _o03 = typeof(game) == XorStr("Part")
)"); )");
REQUIRE_EQ(result.warnings.size(), 3); REQUIRE_EQ(result.warnings.size(), 3);
CHECK_EQ(result.warnings[0].location.begin.line, 2); 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].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].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") TEST_CASE_FIXTURE(Fixture, "ForRangeTable")
@ -642,7 +642,7 @@ end
CHECK_EQ(result.warnings.size(), 1); CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 3); 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") TEST_CASE_FIXTURE(Fixture, "ForRangeBackwards")
@ -657,7 +657,7 @@ end
CHECK_EQ(result.warnings.size(), 1); CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 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") TEST_CASE_FIXTURE(Fixture, "ForRangeImprecise")
@ -672,7 +672,7 @@ end
CHECK_EQ(result.warnings.size(), 1); CHECK_EQ(result.warnings.size(), 1);
CHECK_EQ(result.warnings[0].location.begin.line, 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") TEST_CASE_FIXTURE(Fixture, "ForRangeZero")
@ -690,10 +690,10 @@ end
CHECK_EQ(result.warnings.size(), 2); CHECK_EQ(result.warnings.size(), 2);
CHECK_EQ(result.warnings[0].location.begin.line, 1); 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].location.begin.line, 7);
CHECK_EQ(result.warnings[1].text, 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") TEST_CASE_FIXTURE(Fixture, "UnbalancedAssignment")
@ -718,9 +718,9 @@ end
CHECK_EQ(result.warnings.size(), 2); CHECK_EQ(result.warnings.size(), 2);
CHECK_EQ(result.warnings[0].location.begin.line, 5); 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].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") 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.size(), 3);
CHECK_EQ(result.warnings[0].location.begin.line, 4); CHECK_EQ(result.warnings[0].location.begin.line, 4);
CHECK_EQ(result.warnings[0].text, 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].location.begin.line, 28);
CHECK_EQ(result.warnings[1].text, 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].location.begin.line, 44);
CHECK_EQ(result.warnings[2].text, 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") TEST_CASE_FIXTURE(Fixture, "ImplicitReturnInfiniteLoop")
@ -840,10 +840,10 @@ return f1,f2,f3,f4
CHECK_EQ(result.warnings.size(), 2); CHECK_EQ(result.warnings.size(), 2);
CHECK_EQ(result.warnings[0].location.begin.line, 25); CHECK_EQ(result.warnings[0].location.begin.line, 25);
CHECK_EQ(result.warnings[0].text, 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].location.begin.line, 36);
CHECK_EQ(result.warnings[1].text, 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") TEST_CASE_FIXTURE(Fixture, "TypeAnnotationsShouldNotProduceWarnings")
@ -901,29 +901,29 @@ return foo
)"); )");
CHECK_EQ(result.warnings.size(), 1); 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") TEST_CASE_FIXTURE(Fixture, "FormatStringFormat")
{ {
LintResult result = lint(R"( LintResult result = lint(R"(
-- incorrect format strings -- incorrect format strings
string.format("%") string.format(XorStr("%"))
string.format("%??d") string.format(XorStr("%??d"))
string.format("%Y") string.format(XorStr("%Y"))
-- incorrect format strings, self call -- incorrect format strings, self call
local _ = ("%"):format() local _ = ("%"):format()
-- correct format strings, just to uh make sure -- 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.size(), 4);
CHECK_EQ(result.warnings[0].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, "Invalid format string: invalid format specifier: must be a string format specifier or %"); 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, "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, "Invalid format string: unfinished format specifier"); CHECK_EQ(result.warnings[3].text, XorStr("Invalid format string: unfinished format specifier"));
} }
TEST_CASE_FIXTURE(Fixture, "FormatStringPack") TEST_CASE_FIXTURE(Fixture, "FormatStringPack")
@ -960,17 +960,17 @@ string.packsize("=!1bbbI3c42")
)"); )");
CHECK_EQ(result.warnings.size(), 11); 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[0].text, XorStr("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[1].text, XorStr("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[2].text, XorStr("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[3].text, XorStr("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[4].text, XorStr("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[5].text, XorStr("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[6].text, XorStr("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[7].text, XorStr("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[8].text, XorStr("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[9].text, XorStr("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[10].text, XorStr("Invalid pack format: size specifier is too large"));
} }
TEST_CASE_FIXTURE(Fixture, "FormatStringMatch") 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.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[0].text, XorStr("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[1].text, XorStr("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[2].text, XorStr("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[3].text, XorStr("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[4].text, XorStr("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[5].text, XorStr("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[6].text, XorStr("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[7].text, XorStr("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[8].text, XorStr("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[9].text, XorStr("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[10].text, XorStr("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[11].text, XorStr("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[12].text, XorStr("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[13].text, XorStr("Invalid match pattern: expected a magic character after %"));
} }
TEST_CASE_FIXTURE(Fixture, "FormatStringMatchNested") TEST_CASE_FIXTURE(Fixture, "FormatStringMatchNested")
@ -1036,9 +1036,9 @@ string.match(s, "((a)%3)")
)~"); )~");
CHECK_EQ(result.warnings.size(), 2); 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[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); 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.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[0].text, XorStr("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[1].text, XorStr("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[2].text, XorStr("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[3].text, XorStr("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[4].text, XorStr("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[5].text, XorStr("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[6].text, XorStr("Invalid match pattern: sets can not contain capture references"));
} }
TEST_CASE_FIXTURE(Fixture, "FormatStringFindArgs") TEST_CASE_FIXTURE(Fixture, "FormatStringFindArgs")
@ -1100,14 +1100,14 @@ string.find(s, "%q", 1, false)
-- missing arguments -- missing arguments
string.find() string.find()
string.find("foo"); string.find(XorStr("foo"));
("foo"):find() ("foo"):find()
)"); )");
CHECK_EQ(result.warnings.size(), 2); 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[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); 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.size(), 4);
CHECK_EQ(result.warnings[0].text, "Invalid match replacement: unfinished replacement"); CHECK_EQ(result.warnings[0].text, XorStr("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[1].text, XorStr("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[2].text, XorStr("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[3].text, XorStr("Invalid match replacement: invalid capture index, must refer to pattern capture"));
} }
TEST_CASE_FIXTURE(Fixture, "FormatStringDate") TEST_CASE_FIXTURE(Fixture, "FormatStringDate")
@ -1149,10 +1149,10 @@ os.date("!*t")
)"); )");
CHECK_EQ(result.warnings.size(), 4); CHECK_EQ(result.warnings.size(), 4);
CHECK_EQ(result.warnings[0].text, "Invalid date format: unfinished replacement"); CHECK_EQ(result.warnings[0].text, XorStr("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[1].text, XorStr("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[2].text, XorStr("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[3].text, XorStr("Invalid date format: date format can not contain null characters"));
} }
TEST_CASE_FIXTURE(Fixture, "FormatStringTyped") TEST_CASE_FIXTURE(Fixture, "FormatStringTyped")
@ -1168,9 +1168,9 @@ nons:match("[]")
)~"); )~");
CHECK_EQ(result.warnings.size(), 2); 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[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); CHECK_EQ(result.warnings[1].location.begin.line, 4);
} }
@ -1218,12 +1218,12 @@ _ = {
)"); )");
CHECK_EQ(result.warnings.size(), 6); 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[0].text, XorStr("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[1].text, XorStr("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[2].text, XorStr("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[3].text, XorStr("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[4].text, XorStr("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[5].text, XorStr("Table index 1 is a duplicate; previously defined at line 36"));
} }
TEST_CASE_FIXTURE(Fixture, "ImportOnlyUsedInTypeAnnotation") TEST_CASE_FIXTURE(Fixture, "ImportOnlyUsedInTypeAnnotation")
@ -1235,7 +1235,7 @@ TEST_CASE_FIXTURE(Fixture, "ImportOnlyUsedInTypeAnnotation")
)"); )");
REQUIRE_EQ(result.warnings.size(), 1); 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") 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") TEST_CASE_FIXTURE(Fixture, "use_all_parent_scopes_for_globals")
{ {
ScopePtr testScope = frontend.addEnvironment("Test"); ScopePtr testScope = frontend.addEnvironment(XorStr("Test"));
unfreeze(typeChecker.globalTypes); unfreeze(typeChecker.globalTypes);
loadDefinitionFile(frontend.typeChecker, testScope, R"( loadDefinitionFile(frontend.typeChecker, testScope, R"(
declare Foo: number declare Foo: number
)", )",
"@test"); XorStr("@test"));
freeze(typeChecker.globalTypes); freeze(typeChecker.globalTypes);
fileResolver.environments["A"] = "Test"; 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 local _bar: typeof(os.clock) = os.clock
)"; )";
LintResult result = frontend.lint("A"); LintResult result = frontend.lint(XorStr("A"));
CHECK_EQ(result.warnings.size(), 0); CHECK_EQ(result.warnings.size(), 0);
} }
@ -1307,9 +1307,9 @@ end
)"); )");
CHECK_EQ(result.warnings.size(), 3); 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[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, "Assigning 2 values to 3 variables initializes extra variables with nil; add 'nil' to value list 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, "Variable 'c' defined at line 12 is never initialized or assigned; initialize with 'nil' 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") TEST_CASE_FIXTURE(Fixture, "LocalFunctionNotDead")
@ -1446,7 +1446,7 @@ TEST_CASE_FIXTURE(Fixture, "DeprecatedApi")
{"Wait", {typeChecker.anyType, /* deprecated= */ true}}, {"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"}}}; getMutable<TableTypeVar>(colorType)->props = {{"toHSV", {typeChecker.anyType, /* deprecated= */ true, "Color3:ToHSV"}}};
@ -1465,9 +1465,9 @@ end
)"); )");
REQUIRE_EQ(result.warnings.size(), 3); REQUIRE_EQ(result.warnings.size(), 3);
CHECK_EQ(result.warnings[0].text, "Member 'Instance.Wait' is deprecated"); CHECK_EQ(result.warnings[0].text, XorStr("Member 'Instance.Wait' is deprecated"));
CHECK_EQ(result.warnings[1].text, "Member 'toHSV' is deprecated, use 'Color3:ToHSV' instead"); CHECK_EQ(result.warnings[1].text, XorStr("Member 'toHSV' is deprecated, use 'Color3:ToHSV' instead"));
CHECK_EQ(result.warnings[2].text, "Member 'Instance.DataCost' is deprecated"); CHECK_EQ(result.warnings[2].text, XorStr("Member 'Instance.DataCost' is deprecated"));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "TableOperations") TEST_CASE_FIXTURE(BuiltinsFixture, "TableOperations")
@ -1499,20 +1499,20 @@ table.create(42, {} :: {})
REQUIRE_EQ(result.warnings.size(), 10); 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 " 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"); XorStr("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[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, "table.insert uses index 0 but arrays are 1-based; did you mean 1 instead?"); 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, "table.remove 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 " 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, 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"); 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, "table.move uses index 0 but arrays are 1-based; did you mean 1 instead?"); 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, "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( 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( 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") 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); 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[0].location.begin.line + 1, 4);
CHECK_EQ(result.warnings[1].text, "Condition has already been checked on column 5"); CHECK_EQ(result.warnings[1].text, XorStr("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[2].text, XorStr("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[3].text, XorStr("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[4].text, XorStr("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[5].text, XorStr("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[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[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") TEST_CASE_FIXTURE(Fixture, "DuplicateConditionsExpr")
@ -1567,7 +1567,7 @@ end
)"); )");
REQUIRE_EQ(result.warnings.size(), 1); 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); 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); REQUIRE_EQ(result.warnings.size(), 4);
CHECK_EQ(result.warnings[0].text, "Function parameter 'a1' already defined on column 14"); CHECK_EQ(result.warnings[0].text, XorStr("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[1].text, XorStr("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[2].text, XorStr("Variable 'a1' already defined on column 7"));
CHECK_EQ(result.warnings[3].text, "Function parameter 'self' already defined implicitly"); CHECK_EQ(result.warnings[3].text, XorStr("Function parameter 'self' already defined implicitly"));
} }
TEST_CASE_FIXTURE(Fixture, "MisleadingAndOr") 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); 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; " 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; " 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") TEST_CASE_FIXTURE(Fixture, "WrongComment")
@ -1627,12 +1627,12 @@ do end
)"); )");
REQUIRE_EQ(result.warnings.size(), 6); REQUIRE_EQ(result.warnings.size(), 6);
CHECK_EQ(result.warnings[0].text, "Unknown comment directive 'struct'; did you mean 'strict'?"); CHECK_EQ(result.warnings[0].text, XorStr("Unknown comment directive 'struct'; did you mean 'strict'?"));
CHECK_EQ(result.warnings[1].text, "Unknown comment directive 'nolintGlobal'"); CHECK_EQ(result.warnings[1].text, XorStr("Unknown comment directive 'nolintGlobal'"));
CHECK_EQ(result.warnings[2].text, "nolint directive refers to unknown lint rule 'Global'"); CHECK_EQ(result.warnings[2].text, XorStr("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[3].text, XorStr("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[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, "Comment directive is ignored because it is placed after the first non-comment token"); 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") TEST_CASE_FIXTURE(Fixture, "WrongCommentMuteSelf")
@ -1655,24 +1655,7 @@ end
)"); )");
REQUIRE_EQ(result.warnings.size(), 1); REQUIRE_EQ(result.warnings.size(), 1);
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"));
}
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");
} }
TEST_SUITE_END(); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Clone.h" #include "lluz/Clone.h"
#include "Luau/Module.h" #include "lluz/Module.h"
#include "Luau/Scope.h" #include "lluz/Scope.h"
#include "Luau/RecursionCounter.h" #include "lluz/RecursionCounter.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.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") TEST_CASE_FIXTURE(Fixture, "is_within_comment")
{ {
@ -78,14 +78,14 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
/* The inferred type of Cyclic is {get: () -> Cyclic} /* The inferred type of Cyclic is {get: () -> Cyclic}
* *
* Assert that the return type of get() is the same as the outer table. * 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; TypeArena dest;
CloneState cloneState; CloneState cloneState;
@ -106,7 +106,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
REQUIRE(methodReturnType); REQUIRE(methodReturnType);
CHECK_EQ(methodReturnType, counterCopy); 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 CHECK_EQ(3, dest.typePacks.size()); // function args, its return type, and the hidden any... pack
else else
CHECK_EQ(2, dest.typePacks.size()); // one for the function args, and another for its return type 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} return {sign=math.sign}
)"); )");
dumpErrors(result); 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); std::optional<TypeId> exports = first(module->getModuleScope()->returnType);
REQUIRE(bool(exports)); REQUIRE(bool(exports));
@ -255,8 +255,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "clone_self_property")
return a; return a;
)"; )";
CheckResult result = frontend.check("Module/A"); CheckResult result = frontend.check(XorStr("Module/A"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
fileResolver.source["Module/B"] = R"( fileResolver.source["Module/B"] = R"(
--!nonstrict --!nonstrict
@ -264,9 +264,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "clone_self_property")
return a.foo(5) 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])); 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 #else
int limit = 400; int limit = 400;
#endif #endif
ScopedFastInt luauTypeCloneRecursionLimit{"LuauTypeCloneRecursionLimit", limit}; ScopedFastInt lluzTypeCloneRecursionLimit{"lluzTypeCloneRecursionLimit", limit};
TypeArena src; TypeArena src;
@ -301,6 +301,8 @@ TEST_CASE_FIXTURE(Fixture, "clone_recursion_limit")
TEST_CASE_FIXTURE(Fixture, "any_persistance_does_not_leak") TEST_CASE_FIXTURE(Fixture, "any_persistance_does_not_leak")
{ {
ScopedFastFlag lluzNonCopyableTypeVarFields{"lluzNonCopyableTypeVarFields", true};
fileResolver.source["Module/A"] = R"( fileResolver.source["Module/A"] = R"(
export type A = B export type A = B
type B = A type B = A
@ -309,12 +311,12 @@ type B = A
FrontendOptions opts; FrontendOptions opts;
opts.retainFullTypeGraphs = false; opts.retainFullTypeGraphs = false;
CheckResult result = frontend.check("Module/A", opts); CheckResult result = frontend.check("Module/A", opts);
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
auto mod = frontend.moduleResolver.getModule("Module/A"); auto mod = frontend.moduleResolver.getModule(XorStr("Module/A"));
auto it = mod->getModuleScope()->exportedTypeBindings.find("A"); auto it = mod->getModuleScope()->exportedTypeBindings.find(XorStr("A"));
REQUIRE(it != mod->getModuleScope()->exportedTypeBindings.end()); REQUIRE(it != mod->getModuleScope()->exportedTypeBindings.end());
CHECK(toString(it->second.type) == "any"); CHECK(toString(it->second.type) == XorStr("any"));
} }
TEST_SUITE_END(); 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 // 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 "lluz/Scope.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Fixture.h" #include "Fixture.h"
@ -9,9 +9,80 @@
#include <algorithm> #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") TEST_CASE_FIXTURE(Fixture, "infer_nullary_function")
{ {
@ -20,7 +91,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_nullary_function")
function foo(x, y) end function foo(x, y) end
)"); )");
TypeId fooType = requireType("foo"); TypeId fooType = requireType(XorStr("foo"));
REQUIRE(fooType); REQUIRE(fooType);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(fooType); const FunctionTypeVar* ftv = get<FunctionTypeVar>(fooType);
@ -35,8 +106,13 @@ TEST_CASE_FIXTURE(Fixture, "infer_nullary_function")
REQUIRE_EQ(0, rets.size()); 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"( CheckResult result = check(R"(
--!nonstrict --!nonstrict
function getMinCardCountForWidth(width) function getMinCardCountForWidth(width)
@ -48,25 +124,21 @@ TEST_CASE_FIXTURE(Fixture, "infer_the_maximum_number_of_values_the_function_coul
end end
)"); )");
TypeId t = requireType("getMinCardCountForWidth"); TypeId t = requireType(XorStr("getMinCardCountForWidth"));
REQUIRE(t); 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") TEST_CASE_FIXTURE(Fixture, "return_annotation_is_still_checked")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
--!nonstrict
function foo(x): number return 'hello' end function foo(x): number return 'hello' end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE_NE(*typeChecker.anyType, *requireType("foo"));
} }
#endif
TEST_CASE_FIXTURE(Fixture, "function_parameters_are_any") TEST_CASE_FIXTURE(Fixture, "function_parameters_are_any")
{ {
@ -78,7 +150,7 @@ TEST_CASE_FIXTURE(Fixture, "function_parameters_are_any")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "inconsistent_return_types_are_ok") TEST_CASE_FIXTURE(Fixture, "inconsistent_return_types_are_ok")
@ -95,7 +167,7 @@ TEST_CASE_FIXTURE(Fixture, "inconsistent_return_types_are_ok")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "locals_are_any_by_default") 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 local m = 55
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.anyType, *requireType("m")); CHECK_EQ(*typeChecker.anyType, *requireType("m"));
} }
@ -121,7 +193,7 @@ TEST_CASE_FIXTURE(Fixture, "parameters_having_type_any_are_optional")
f(5) f(5)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "local_tables_are_not_any") TEST_CASE_FIXTURE(Fixture, "local_tables_are_not_any")
@ -136,7 +208,7 @@ TEST_CASE_FIXTURE(Fixture, "local_tables_are_not_any")
T:staticmethod() 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])); 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) 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])); 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 T.foo = 55
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
TableTypeVar* ttv = getMutable<TableTypeVar>(requireType("T")); 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")); TableTypeVar* ttv = getMutable<TableTypeVar>(requireType("T"));
REQUIRE_MESSAGE(ttv, "Should be a table: " << toString(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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "table_dot_insert_and_recursive_calls") 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 = {} local newList = {}
for _, value in ipairs(list) do for _, value in ipairs(list) do
if type(value) == "table" then if type(value) == XorStr("table") then
table.insert(newList, populateListFromIds(value, normalizedData)) table.insert(newList, populateListFromIds(value, normalizedData))
else else
table.insert(newList, normalizedData[value]) table.insert(newList, normalizedData[value])
@ -234,7 +306,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_dot_insert_and_recursive_calls")
end 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") 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) delay(50, function() end)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "inconsistent_module_return_types_are_ok") TEST_CASE_FIXTURE(Fixture, "inconsistent_module_return_types_are_ok")
{ {
ScopedFastFlag sff[]{
{"lluzReturnTypeInferenceInNonstrict", true},
{"lluzLowerBoundsCalculation", true},
};
CheckResult result = check(R"( CheckResult result = check(R"(
--!nonstrict --!nonstrict
@ -266,9 +343,9 @@ TEST_CASE_FIXTURE(Fixture, "inconsistent_module_return_types_are_ok")
end 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") TEST_CASE_FIXTURE(Fixture, "returning_insufficient_return_values")
@ -285,7 +362,7 @@ TEST_CASE_FIXTURE(Fixture, "returning_insufficient_return_values")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "returning_too_many_values") TEST_CASE_FIXTURE(Fixture, "returning_too_many_values")
@ -302,7 +379,7 @@ TEST_CASE_FIXTURE(Fixture, "returning_too_many_values")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_SUITE_END(); 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 "Fixture.h"
#include "doctest.h" #include "doctest.h"
#include "Luau/Normalize.h" #include "lluz/Normalize.h"
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
using namespace Luau; using namespace lluz;
struct NormalizeFixture : Fixture struct NormalizeFixture : Fixture
{ {
ScopedFastFlag sff1{"LuauLowerBoundsCalculation", true}; ScopedFastFlag sff1{"lluzLowerBoundsCalculation", true};
}; };
void createSomeClasses(TypeChecker& typeChecker) void createSomeClasses(TypeChecker& typeChecker)
@ -55,7 +55,7 @@ static bool isSubtype(TypeId a, TypeId b)
return isSubtype(a, b, ice); return isSubtype(a, b, ice);
} }
TEST_SUITE_BEGIN("isSubtype"); TEST_SUITE_BEGIN(XorStr("isSubtype"));
TEST_CASE_FIXTURE(NormalizeFixture, "primitives") TEST_CASE_FIXTURE(NormalizeFixture, "primitives")
{ {
@ -67,10 +67,10 @@ TEST_CASE_FIXTURE(NormalizeFixture, "primitives")
local d = "world" local d = "world"
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
TypeId c = requireType("c"); TypeId c = requireType(XorStr("c"));
TypeId d = requireType("d"); TypeId d = requireType(XorStr("d"));
CHECK(isSubtype(b, a)); CHECK(isSubtype(b, a));
CHECK(isSubtype(d, c)); CHECK(isSubtype(d, c));
@ -87,10 +87,10 @@ TEST_CASE_FIXTURE(NormalizeFixture, "functions")
function d(x: number): number? return x end function d(x: number): number? return x end
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
TypeId c = requireType("c"); TypeId c = requireType(XorStr("c"));
TypeId d = requireType("d"); TypeId d = requireType(XorStr("d"));
CHECK(isSubtype(b, a)); CHECK(isSubtype(b, a));
CHECK(isSubtype(c, a)); CHECK(isSubtype(c, a));
@ -101,12 +101,12 @@ TEST_CASE_FIXTURE(NormalizeFixture, "functions")
TEST_CASE_FIXTURE(NormalizeFixture, "functions_and_any") TEST_CASE_FIXTURE(NormalizeFixture, "functions_and_any")
{ {
check(R"( 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 function b(q: any) return 5 :: any end
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
// Intuition: // Intuition:
// We cannot use b where a is required because we cannot rely on b to return a string. // 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 local t: T
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
CHECK(!isSubtype(a, b)); // !! CHECK(!isSubtype(a, b)); // !!
CHECK(!isSubtype(b, a)); CHECK(!isSubtype(b, a));
@ -146,9 +146,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "functions_with_mismatching_arity")
local c: () -> number local c: () -> number
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
TypeId c = requireType("c"); TypeId c = requireType(XorStr("c"));
CHECK(!isSubtype(b, a)); CHECK(!isSubtype(b, a));
CHECK(!isSubtype(c, a)); CHECK(!isSubtype(c, a));
@ -178,9 +178,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "functions_with_mismatching_arity_but_option
local c: (number, number?) -> () local c: (number, number?) -> ()
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
TypeId c = requireType("c"); TypeId c = requireType(XorStr("c"));
/* /*
* (number) -> () </: (number?) -> () * (number) -> () </: (number?) -> ()
@ -228,9 +228,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "functions_with_mismatching_arity_but_any_is
local c: (number, any) -> () local c: (number, any) -> ()
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
TypeId c = requireType("c"); TypeId c = requireType(XorStr("c"));
/* /*
* (number) -> () </: (number?) -> () * (number) -> () </: (number?) -> ()
@ -276,8 +276,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "variadic_functions_with_no_head")
local b: (...number?) -> () local b: (...number?) -> ()
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
CHECK(isSubtype(b, a)); CHECK(isSubtype(b, a));
CHECK(!isSubtype(a, b)); CHECK(!isSubtype(a, b));
@ -291,8 +291,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "variadic_function_with_head")
local b: (number, number) -> () local b: (number, number) -> ()
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
CHECK(!isSubtype(b, a)); CHECK(!isSubtype(b, a));
CHECK(isSubtype(a, b)); CHECK(isSubtype(a, b));
@ -308,10 +308,10 @@ TEST_CASE_FIXTURE(NormalizeFixture, "union")
local d: number? local d: number?
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
TypeId c = requireType("c"); TypeId c = requireType(XorStr("c"));
TypeId d = requireType("d"); TypeId d = requireType(XorStr("d"));
CHECK(isSubtype(b, a)); CHECK(isSubtype(b, a));
CHECK(!isSubtype(a, b)); CHECK(!isSubtype(a, b));
@ -333,8 +333,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "table_with_union_prop")
local b: {x: number?} local b: {x: number?}
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
CHECK(isSubtype(a, b)); CHECK(isSubtype(a, b));
CHECK(!isSubtype(b, a)); CHECK(!isSubtype(b, a));
@ -347,8 +347,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "table_with_any_prop")
local b: {x: any} local b: {x: any}
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
CHECK(isSubtype(a, b)); CHECK(isSubtype(a, b));
CHECK(!isSubtype(b, a)); CHECK(!isSubtype(b, a));
@ -363,10 +363,10 @@ TEST_CASE_FIXTURE(NormalizeFixture, "intersection")
local d: number & nil local d: number & nil
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
TypeId c = requireType("c"); TypeId c = requireType(XorStr("c"));
TypeId d = requireType("d"); TypeId d = requireType(XorStr("d"));
CHECK(!isSubtype(b, a)); CHECK(!isSubtype(b, a));
CHECK(isSubtype(a, b)); CHECK(isSubtype(a, b));
@ -385,8 +385,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "union_and_intersection")
local b: number | nil local b: number | nil
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
CHECK(!isSubtype(b, a)); CHECK(!isSubtype(b, a));
CHECK(isSubtype(a, b)); CHECK(isSubtype(a, b));
@ -411,10 +411,10 @@ TEST_CASE_FIXTURE(NormalizeFixture, "tables")
local d: {x: number, y: number} local d: {x: number, y: number}
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
TypeId c = requireType("c"); TypeId c = requireType(XorStr("c"));
TypeId d = requireType("d"); TypeId d = requireType(XorStr("d"));
CHECK(isSubtype(a, b)); CHECK(isSubtype(a, b));
CHECK(!isSubtype(b, a)); CHECK(!isSubtype(b, a));
@ -438,9 +438,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "table_indexers_are_invariant")
local c: {[string]: number} local c: {[string]: number}
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
TypeId c = requireType("c"); TypeId c = requireType(XorStr("c"));
CHECK(!isSubtype(b, a)); CHECK(!isSubtype(b, a));
CHECK(!isSubtype(a, b)); CHECK(!isSubtype(a, b));
@ -457,9 +457,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "mismatched_indexers")
local c: {} local c: {}
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
TypeId c = requireType("c"); TypeId c = requireType(XorStr("c"));
CHECK(isSubtype(b, a)); CHECK(isSubtype(b, a));
CHECK(!isSubtype(a, b)); CHECK(!isSubtype(a, b));
@ -487,11 +487,11 @@ TEST_CASE_FIXTURE(NormalizeFixture, "cyclic_table")
local e: E local e: E
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
TypeId c = requireType("c"); TypeId c = requireType(XorStr("c"));
TypeId d = requireType("d"); TypeId d = requireType(XorStr("d"));
TypeId e = requireType("e"); TypeId e = requireType(XorStr("e"));
CHECK(isSubtype(b, a)); CHECK(isSubtype(b, a));
CHECK(!isSubtype(a, b)); CHECK(!isSubtype(a, b));
@ -537,8 +537,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "metatable" * doctest::expected_failures{1})
local b: {method: (any) -> ()} local b: {method: (any) -> ()}
)"); )");
TypeId a = requireType("a"); TypeId a = requireType(XorStr("a"));
TypeId b = requireType("b"); TypeId b = requireType(XorStr("b"));
CHECK(isSubtype(a, b)); CHECK(isSubtype(a, b));
} }
@ -556,7 +556,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "intersection_of_tables")
TEST_SUITE_END(); TEST_SUITE_END();
TEST_SUITE_BEGIN("Normalize"); TEST_SUITE_BEGIN(XorStr("Normalize"));
TEST_CASE_FIXTURE(NormalizeFixture, "intersection_of_disjoint_tables") 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(); ModulePtr mainModule = getMainModule();
unfreeze(mainModule->internalTypes); unfreeze(mainModule->internalTypes);
TypeId tType = requireType("t"); TypeId tType = requireType(XorStr("t"));
normalize(tType, tempModule, *typeChecker.iceHandler); normalize(tType, tempModule, *typeChecker.iceHandler);
CHECK_EQ("{| x: number? |}", toString(tType, {true})); 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") TEST_CASE_FIXTURE(Fixture, "normalize_module_return_type")
{ {
ScopedFastFlag sff[] = { ScopedFastFlag sff[] = {
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
{"lluzReturnTypeInferenceInNonstrict", true},
}; };
check(R"( check(R"(
@ -641,7 +642,7 @@ TEST_CASE_FIXTURE(Fixture, "normalize_module_return_type")
end 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") 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) 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)); 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") TEST_CASE_FIXTURE(Fixture, "cyclic_table_is_marked_normal")
{ {
ScopedFastFlag flags[] = {{"LuauLowerBoundsCalculation", true}, {"LuauNormalizeFlagIsConservative", false}}; ScopedFastFlag flags[] = {{"lluzLowerBoundsCalculation", true}, {"lluzNormalizeFlagIsConservative", false}};
check(R"( check(R"(
type Fiber = { type Fiber = {
@ -692,14 +693,14 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_table_is_marked_normal")
local f: Fiber local f: Fiber
)"); )");
TypeId t = requireType("f"); TypeId t = requireType(XorStr("f"));
CHECK(t->normal); CHECK(t->normal);
} }
// Unfortunately, getting this right in the general case is difficult. // Unfortunately, getting this right in the general case is difficult.
TEST_CASE_FIXTURE(Fixture, "cyclic_table_is_not_marked_normal") TEST_CASE_FIXTURE(Fixture, "cyclic_table_is_not_marked_normal")
{ {
ScopedFastFlag flags[] = {{"LuauLowerBoundsCalculation", true}, {"LuauNormalizeFlagIsConservative", true}}; ScopedFastFlag flags[] = {{"lluzLowerBoundsCalculation", true}, {"lluzNormalizeFlagIsConservative", true}};
check(R"( check(R"(
type Fiber = { type Fiber = {
@ -709,14 +710,14 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_table_is_not_marked_normal")
local f: Fiber local f: Fiber
)"); )");
TypeId t = requireType("f"); TypeId t = requireType(XorStr("f"));
CHECK(!t->normal); CHECK(!t->normal);
} }
TEST_CASE_FIXTURE(Fixture, "variadic_tail_is_marked_normal") TEST_CASE_FIXTURE(Fixture, "variadic_tail_is_marked_normal")
{ {
ScopedFastFlag flags[] = { ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
@ -725,9 +726,9 @@ TEST_CASE_FIXTURE(Fixture, "variadic_tail_is_marked_normal")
local w: Weirdo 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); auto ftv = get<FunctionTypeVar>(t);
REQUIRE(ftv); REQUIRE(ftv);
@ -749,75 +750,16 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_table_normalizes_sensibly")
end 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})); 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") TEST_CASE_FIXTURE(BuiltinsFixture, "union_of_distinct_free_types")
{ {
ScopedFastFlag flags[] = { ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
@ -830,7 +772,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "union_of_distinct_free_types")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK("<a, b>(a, b) -> a | b" == toString(requireType("fussy"))); 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") TEST_CASE_FIXTURE(BuiltinsFixture, "constrained_intersection_of_intersections")
{ {
ScopedFastFlag flags[] = { ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
@ -854,9 +796,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "constrained_intersection_of_intersections")
end 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)); 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") TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersection")
{ {
ScopedFastFlag flags[] = { ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
@ -881,7 +823,7 @@ TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersect
local t: T local t: T
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK("{| |}" == toString(requireType("x"), {true})); CHECK("{| |}" == toString(requireType("x"), {true}));
CHECK("{| y: number |}" == toString(requireType("y"), {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") TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersection_2")
{ {
ScopedFastFlag flags[] = { ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
{"LuauQuantifyConstrained", true}, {"lluzQuantifyConstrained", true},
}; };
// We use a function and inferred parameter types to prevent intermediate normalizations from being performed. // 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 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); auto ftv = get<FunctionTypeVar>(t);
REQUIRE(ftv != nullptr); 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") TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersection_3")
{ {
ScopedFastFlag flags[] = { ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
{"LuauQuantifyConstrained", true}, {"lluzQuantifyConstrained", true},
}; };
// We use a function and inferred parameter types to prevent intermediate normalizations from being performed. // 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 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); auto ftv = get<FunctionTypeVar>(t);
REQUIRE(ftv != nullptr); 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") TEST_CASE_FIXTURE(Fixture, "intersection_inside_a_table_inside_another_intersection_4")
{ {
ScopedFastFlag flags[] = { ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
{"LuauQuantifyConstrained", true}, {"lluzQuantifyConstrained", true},
}; };
// We use a function and inferred parameter types to prevent intermediate normalizations from being performed. // 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 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); auto ftv = get<FunctionTypeVar>(t);
REQUIRE(ftv != nullptr); 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") TEST_CASE_FIXTURE(Fixture, "nested_table_normalization_with_non_table__no_ice")
{ {
ScopedFastFlag flags[] = { ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
{"LuauNormalizeCombineTableFix", true}, {"lluzNormalizeCombineTableFix", true},
}; };
// CLI-52787 // CLI-52787
// ends up combining {_:any} with any, recursively // 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 } 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") TEST_CASE_FIXTURE(BuiltinsFixture, "visiting_a_type_twice_is_not_considered_normal")
{ {
ScopedFastFlag sff{"LuauLowerBoundsCalculation", true}; ScopedFastFlag sff{"lluzLowerBoundsCalculation", true};
CheckResult result = check(R"( CheckResult result = check(R"(
--!strict --!strict
@ -1046,33 +988,33 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "visiting_a_type_twice_is_not_considered_norm
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("<a>(() -> a, a) -> ()", toString(requireType("f"))); CHECK_EQ("<a>(() -> a, a) -> ()", toString(requireType("f")));
} }
TEST_CASE_FIXTURE(Fixture, "fuzz_failure_instersection_combine_must_follow") TEST_CASE_FIXTURE(Fixture, "fuzz_failure_instersection_combine_must_follow")
{ {
ScopedFastFlag flags[] = { ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
export type t0 = {_:{_:any} & {_:any|string}} & {_:{_:{}}} 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") 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"( CheckResult result = check(R"(
type t252 = ((t0<t252...>)|(any))|(any) type t252 = ((t0<t252...>)|(any))|(any)
type t0 = t252<t0<any,t24...>,t24...> 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 // 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") TEST_CASE_FIXTURE(Fixture, "bound_typevars_should_only_be_marked_normal_if_their_pointee_is_normal")
{ {
ScopedFastFlag sff[]{ ScopedFastFlag sff[]{
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
{"LuauNormalizeFlagIsConservative", true}, {"lluzNormalizeFlagIsConservative", true},
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
@ -1108,63 +1050,25 @@ export type t0 = { a: Child }
export type t1 = { a: typeof(string.byte) } 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") TEST_CASE_FIXTURE(Fixture, "intersection_combine_on_bound_self")
{ {
ScopedFastFlag lluzNormalizeCombineEqFix{"lluzNormalizeCombineEqFix", true};
CheckResult result = check(R"( CheckResult result = check(R"(
export type t0 = (((any)&({_:l0.t0,n0:t0,_G:any,}))&({_:any,}))&(((any)&({_:l0.t0,n0:t0,_G:any,}))&({_:any,})) export type t0 = (((any)&({_:l0.t0,n0:t0,_G:any,}))&({_:any,}))&(((any)&({_:l0.t0,n0:t0,_G:any,}))&({_:any,}))
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_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")));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "normalization_does_not_convert_ever") TEST_CASE_FIXTURE(BuiltinsFixture, "normalization_does_not_convert_ever")
{ {
ScopedFastFlag sff[]{ ScopedFastFlag sff[]{
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
{"LuauQuantifyConstrained", true}, {"lluzQuantifyConstrained", true},
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
@ -1175,13 +1079,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "normalization_does_not_convert_ever")
end end
type Ret = typeof(f()) type Ret = typeof(f())
if math.random() > 0.5 then if math.random() > 0.5 then
return "something" return XorStr("something")
end end
return "something" :: Ret return XorStr("something") :: Ret
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("() -> boolean | string", toString(requireType("f"))); CHECK_EQ("() -> boolean | string", toString(requireType("f")));
} }

View file

@ -1,4 +1,4 @@
#include "Luau/NotNull.h" #include "lluz/NotNull.h"
#include "doctest.h" #include "doctest.h"
@ -6,7 +6,7 @@
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
using Luau::NotNull; using lluz::NotNull;
namespace namespace
{ {
@ -39,7 +39,7 @@ int foo(NotNull<int> p)
void bar(int* q) {} void bar(int* q) {}
TEST_SUITE_BEGIN("NotNull"); TEST_SUITE_BEGIN(XorStr("NotNull"));
TEST_CASE("basic_stuff") 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 "lua.h"
#include "lualib.h" #include "lualib.h"
@ -41,7 +41,7 @@ public:
// Returns all of the output captured from the pretty printer // Returns all of the output captured from the pretty printer
std::string getCapturedOutput() std::string getCapturedOutput()
{ {
lua_getglobal(L, "capturedoutput"); lua_getglobal(L, XorStr("capturedoutput"));
const char* str = lua_tolstring(L, -1, nullptr); const char* str = lua_tolstring(L, -1, nullptr);
std::string result(str); std::string result(str);
lua_pop(L, 1); lua_pop(L, 1);
@ -55,7 +55,7 @@ public:
getCompletions(L, inputPrefix, [&result](const std::string& completion, const std::string& display) { getCompletions(L, inputPrefix, [&result](const std::string& completion, const std::string& display) {
result.insert(Completion{completion, 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)); CHECK(top == lua_gettop(L));
return result; return result;
@ -84,14 +84,14 @@ capturedoutput = ""
function arraytostring(arr) function arraytostring(arr)
local strings = {} local strings = {}
table.foreachi(arr, function(k,v) table.insert(strings, pptostring(v)) end ) table.foreachi(arr, function(k,v) table.insert(strings, pptostring(v)) end )
return "{" .. table.concat(strings, ", ") .. "}" return XorStr("{") .. table.concat(strings, ", ") .. "}"
end end
function pptostring(x) function pptostring(x)
if type(x) == "table" then if type(x) == XorStr("table") then
-- Just assume array-like tables for now. -- Just assume array-like tables for now.
return arraytostring(x) return arraytostring(x)
elseif type(x) == "string" then elseif type(x) == XorStr("string") then
return '"' .. x .. '"' return '"' .. x .. '"'
else else
return tostring(x) return tostring(x)
@ -116,41 +116,41 @@ end
)"; )";
}; };
TEST_SUITE_BEGIN("ReplPrettyPrint"); TEST_SUITE_BEGIN(XorStr("ReplPrettyPrint"));
TEST_CASE_FIXTURE(ReplFixture, "AdditionStatement") TEST_CASE_FIXTURE(ReplFixture, "AdditionStatement")
{ {
runCode(L, "return 30 + 12"); runCode(L, XorStr("return 30 + 12"));
CHECK(getCapturedOutput() == "42"); CHECK(getCapturedOutput() == XorStr("42"));
} }
TEST_CASE_FIXTURE(ReplFixture, "TableLiteral") TEST_CASE_FIXTURE(ReplFixture, "TableLiteral")
{ {
runCode(L, "return {1, 2, 3, 4}"); runCode(L, XorStr("return {1, 2, 3, 4}"));
CHECK(getCapturedOutput() == "{1, 2, 3, 4}"); CHECK(getCapturedOutput() == XorStr("{1, 2, 3, 4}"));
} }
TEST_CASE_FIXTURE(ReplFixture, "StringLiteral") TEST_CASE_FIXTURE(ReplFixture, "StringLiteral")
{ {
runCode(L, "return 'str'"); runCode(L, XorStr("return 'str'"));
CHECK(getCapturedOutput() == "\"str\""); CHECK(getCapturedOutput() == XorStr("\"str\""));
} }
TEST_CASE_FIXTURE(ReplFixture, "TableWithStringLiterals") TEST_CASE_FIXTURE(ReplFixture, "TableWithStringLiterals")
{ {
runCode(L, "return {1, 'two', 3, 'four'}"); runCode(L, XorStr("return {1, 'two', 3, 'four'}"));
CHECK(getCapturedOutput() == "{1, \"two\", 3, \"four\"}"); CHECK(getCapturedOutput() == XorStr("{1, \"two\", 3, \"four\"}"));
} }
TEST_CASE_FIXTURE(ReplFixture, "MultipleArguments") TEST_CASE_FIXTURE(ReplFixture, "MultipleArguments")
{ {
runCode(L, "return 3, 'three'"); runCode(L, XorStr("return 3, 'three'"));
CHECK(getCapturedOutput() == "3\t\"three\""); CHECK(getCapturedOutput() == XorStr("3\t\"three\""));
} }
TEST_SUITE_END(); TEST_SUITE_END();
TEST_SUITE_BEGIN("ReplCodeCompletion"); TEST_SUITE_BEGIN(XorStr("ReplCodeCompletion"));
TEST_CASE_FIXTURE(ReplFixture, "CompleteGlobalVariables") 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 // Try to complete globals that are added by the user's script
CompletionSet completions = getCompletionSet("myvar"); CompletionSet completions = getCompletionSet(XorStr("myvar"));
std::string prefix = ""; std::string prefix = "";
CHECK(completions.size() == 2); CHECK(completions.size() == 2);
@ -169,7 +169,7 @@ TEST_CASE_FIXTURE(ReplFixture, "CompleteGlobalVariables")
} }
{ {
// Try completing some builtin functions // Try completing some builtin functions
CompletionSet completions = getCompletionSet("math.m"); CompletionSet completions = getCompletionSet(XorStr("math.m"));
std::string prefix = "math."; std::string prefix = "math.";
CHECK(completions.size() == 3); CHECK(completions.size() == 3);
@ -185,7 +185,7 @@ TEST_CASE_FIXTURE(ReplFixture, "CompleteTableKeys")
t = { color = "red", size = 1, shape = "circle" } t = { color = "red", size = 1, shape = "circle" }
)"); )");
{ {
CompletionSet completions = getCompletionSet("t."); CompletionSet completions = getCompletionSet(XorStr("t."));
std::string prefix = "t."; std::string prefix = "t.";
CHECK(completions.size() == 3); 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."; std::string prefix = "t.";
CHECK(completions.size() == 2); CHECK(completions.size() == 2);
@ -210,7 +210,7 @@ TEST_CASE_FIXTURE(ReplFixture, "StringMethods")
s = "" s = ""
)"); )");
{ {
CompletionSet completions = getCompletionSet("s:l"); CompletionSet completions = getCompletionSet(XorStr("s:l"));
std::string prefix = "s:"; std::string prefix = "s:";
CHECK(completions.size() == 2); CHECK(completions.size() == 2);
@ -236,7 +236,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMetatableIndexTable")
t.tkey2 = 4 t.tkey2 = 4
)"); )");
{ {
CompletionSet completions = getCompletionSet("t.t"); CompletionSet completions = getCompletionSet(XorStr("t.t"));
std::string prefix = "t."; std::string prefix = "t.";
CHECK(completions.size() == 2); CHECK(completions.size() == 2);
@ -244,7 +244,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMetatableIndexTable")
CHECK(checkCompletion(completions, prefix, "tkey2")); 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:"; std::string prefix = "t.tkey1.data2:";
CHECK(completions.size() == 2); CHECK(completions.size() == 2);
@ -252,7 +252,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMetatableIndexTable")
CHECK(checkCompletion(completions, prefix, "reverse(")); CHECK(checkCompletion(completions, prefix, "reverse("));
} }
{ {
CompletionSet completions = getCompletionSet("t.mtk"); CompletionSet completions = getCompletionSet(XorStr("t.mtk"));
std::string prefix = "t."; std::string prefix = "t.";
CHECK(completions.size() == 2); CHECK(completions.size() == 2);
@ -260,7 +260,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMetatableIndexTable")
CHECK(checkCompletion(completions, prefix, "mtkey2")); CHECK(checkCompletion(completions, prefix, "mtkey2"));
} }
{ {
CompletionSet completions = getCompletionSet("t.mtkey1."); CompletionSet completions = getCompletionSet(XorStr("t.mtkey1."));
std::string prefix = "t.mtkey1."; std::string prefix = "t.mtkey1.";
CHECK(completions.size() == 2); CHECK(completions.size() == 2);
@ -276,10 +276,10 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMetatableIndexFunction")
mt = {} mt = {}
mt.__index = function(table, key) mt.__index = function(table, key)
print("mt.__index called") print("mt.__index called")
if key == "foo" then if key == XorStr("foo") then
return "FOO" return XorStr("FOO")
elseif key == "bar" then elseif key == XorStr("bar") then
return "BAR" return XorStr("BAR")
else else
return nil return nil
end end
@ -290,7 +290,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMetatableIndexFunction")
t.tkey = 0 t.tkey = 0
)"); )");
{ {
CompletionSet completions = getCompletionSet("t.t"); CompletionSet completions = getCompletionSet(XorStr("t.t"));
std::string prefix = "t."; std::string prefix = "t.";
CHECK(completions.size() == 1); 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 // 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); CHECK(completions.size() == 0);
} }
{ {
// t.foo is a valid key, but should not be found because it requires calling an __index function // 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); CHECK(completions.size() == 0);
} }
@ -329,7 +329,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMultipleMetatableIndexTables")
t.tkey = 3 t.tkey = 3
)"); )");
{ {
CompletionSet completions = getCompletionSet("t."); CompletionSet completions = getCompletionSet(XorStr("t."));
std::string prefix = "t."; std::string prefix = "t.";
CHECK(completions.size() == 4); CHECK(completions.size() == 4);
@ -339,7 +339,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMultipleMetatableIndexTables")
CHECK(checkCompletion(completions, prefix, "mt2key")); CHECK(checkCompletion(completions, prefix, "mt2key"));
} }
{ {
CompletionSet completions = getCompletionSet("t.__index."); CompletionSet completions = getCompletionSet(XorStr("t.__index."));
std::string prefix = "t.__index."; std::string prefix = "t.__index.";
CHECK(completions.size() == 3); CHECK(completions.size() == 3);
@ -348,7 +348,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithMultipleMetatableIndexTables")
CHECK(checkCompletion(completions, prefix, "mt2key")); CHECK(checkCompletion(completions, prefix, "mt2key"));
} }
{ {
CompletionSet completions = getCompletionSet("t.mt2key."); CompletionSet completions = getCompletionSet(XorStr("t.mt2key."));
std::string prefix = "t.mt2key."; std::string prefix = "t.mt2key.";
CHECK(completions.size() == 2); CHECK(completions.size() == 2);
@ -364,7 +364,7 @@ TEST_CASE_FIXTURE(ReplFixture, "TableWithDeepMetatableIndexTables")
function makeChainedTable(count) function makeChainedTable(count)
local result = {} local result = {}
result.__index = 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 if count == 0 then
return result return result
else else
@ -377,27 +377,27 @@ t60 = makeChainedTable(60)
)"); )");
{ {
// Check if entry0 exists // Check if entry0 exists
CompletionSet completions = getCompletionSet("t30.entry0"); CompletionSet completions = getCompletionSet(XorStr("t30.entry0"));
std::string prefix = "t30."; std::string prefix = "t30.";
CHECK(checkCompletion(completions, prefix, "entry0")); CHECK(checkCompletion(completions, prefix, "entry0"));
} }
{ {
// Check if entry0.count exists // Check if entry0.count exists
CompletionSet completions = getCompletionSet("t30.entry0.co"); CompletionSet completions = getCompletionSet(XorStr("t30.entry0.co"));
std::string prefix = "t30.entry0."; std::string prefix = "t30.entry0.";
CHECK(checkCompletion(completions, prefix, "count")); CHECK(checkCompletion(completions, prefix, "count"));
} }
{ {
// Check if entry0 exists. With the max traversal limit of 50 in the repl, this should fail. // 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(completions.size() == 0);
} }
{ {
// Check if entry0.count exists. With the max traversal limit of 50 in the repl, this should fail. // 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); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/RequireTracer.h" #include "lluz/RequireTracer.h"
#include "Luau/Parser.h" #include "lluz/Parser.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
namespace namespace
{ {
@ -44,14 +44,14 @@ struct RequireTracerFixture
Allocator allocator; Allocator allocator;
AstNameTable names; AstNameTable names;
Luau::TestFileResolver fileResolver; lluz::TestFileResolver fileResolver;
}; };
const std::vector<std::string> roots = {"game", "Game", "workspace", "Workspace", "script"}; const std::vector<std::string> roots = {"game", "Game", "workspace", "Workspace", "script"};
} // namespace } // namespace
TEST_SUITE_BEGIN("RequireTracerTest"); TEST_SUITE_BEGIN(XorStr("RequireTracerTest"));
TEST_CASE_FIXTURE(RequireTracerFixture, "trace_local") TEST_CASE_FIXTURE(RequireTracerFixture, "trace_local")
{ {
@ -60,7 +60,7 @@ TEST_CASE_FIXTURE(RequireTracerFixture, "trace_local")
require(m) require(m)
)"); )");
RequireTraceResult result = traceRequires(&fileResolver, block, "ModuleName"); RequireTraceResult result = traceRequires(&fileResolver, block, XorStr("ModuleName"));
REQUIRE(!result.exprs.empty()); REQUIRE(!result.exprs.empty());
AstStatLocal* loc = block->body.data[0]->as<AstStatLocal>(); 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); 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>(); AstStatLocal* local = block->body.data[1]->as<AstStatLocal>();
REQUIRE(local); REQUIRE(local);
@ -116,7 +116,7 @@ TEST_CASE_FIXTURE(RequireTracerFixture, "trace_function_arguments")
)"); )");
REQUIRE_EQ(1, block->body.size); 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>(); AstStatLocal* local = block->body.data[0]->as<AstStatLocal>();
REQUIRE(local != nullptr); REQUIRE(local != nullptr);
@ -138,7 +138,7 @@ TEST_CASE_FIXTURE(RequireTracerFixture, "follow_typeof")
)"); )");
REQUIRE_EQ(1, block->body.size); 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>(); AstStatLocal* local = block->body.data[0]->as<AstStatLocal>();
REQUIRE(local != nullptr); REQUIRE(local != nullptr);
@ -153,7 +153,7 @@ TEST_CASE_FIXTURE(RequireTracerFixture, "follow_typeof")
AstExprIndexName* indexName = typeofAnnotation->expr->as<AstExprIndexName>(); AstExprIndexName* indexName = typeofAnnotation->expr->as<AstExprIndexName>();
REQUIRE(indexName != nullptr); REQUIRE(indexName != nullptr);
REQUIRE_EQ(indexName->index, "UsefulObject"); REQUIRE_EQ(indexName->index, XorStr("UsefulObject"));
AstExprCall* call = indexName->expr->as<AstExprCall>(); AstExprCall* call = indexName->expr->as<AstExprCall>();
REQUIRE(call != nullptr); REQUIRE(call != nullptr);
@ -170,7 +170,7 @@ TEST_CASE_FIXTURE(RequireTracerFixture, "follow_string_indexexpr")
)"); )");
REQUIRE_EQ(2, block->body.size); 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>(); AstStatLocal* local = block->body.data[0]->as<AstStatLocal>();
REQUIRE(local != nullptr); 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 /* 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. * most real-world scripts.
@ -13,14 +13,14 @@
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
LUAU_FASTFLAG(LuauLowerBoundsCalculation); lluz_FASTFLAG(LluLowerBoundsCalculation);
struct LimitFixture : BuiltinsFixture struct LimitFixture : BuiltinsFixture
{ {
#if defined(_NOOPT) || defined(_DEBUG) #if defined(_NOOPT) || defined(_DEBUG)
ScopedFastInt LuauTypeInferRecursionLimit{"LuauTypeInferRecursionLimit", 100}; ScopedFastInt lluzTypeInferRecursionLimit{"lluzTypeInferRecursionLimit", 100};
#endif #endif
}; };
@ -33,7 +33,7 @@ bool hasError(const CheckResult& result, T* = nullptr)
return it != result.errors.end(); return it != result.errors.end();
} }
TEST_SUITE_BEGIN("RuntimeLimits"); TEST_SUITE_BEGIN(XorStr("RuntimeLimits"));
TEST_CASE_FIXTURE(LimitFixture, "typescript_port_of_Result_type") 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 lazyGet = TS.import(script, script.Parent.Parent, "util", "lazyLoad").lazyGet
local unit = TS.import(script, script.Parent.Parent, "util", "Unit").unit local unit = TS.import(script, script.Parent.Parent, "util", "Unit").unit
local Iterator local Iterator
lazyGet("Iterator", function(c) lazyGet(XorStr("Iterator"), function(c)
Iterator = c Iterator = c
end) end)
local Option local Option
lazyGet("Option", function(c) lazyGet(XorStr("Option"), function(c)
Option = c Option = c
end) end)
local Vec local Vec
lazyGet("Vec", function(c) lazyGet(XorStr("Vec"), function(c)
Vec = c Vec = c
end) end)
local Result local Result
do do
Result = setmetatable({}, { Result = setmetatable({}, {
__tostring = function() __tostring = function()
return "Result" return XorStr("Result")
end, end,
}) })
Result.__index = Result Result.__index = Result
@ -254,9 +254,9 @@ TEST_CASE_FIXTURE(LimitFixture, "typescript_port_of_Result_type")
end end
resultMeta.__tostring = function(result) resultMeta.__tostring = function(result)
return result:match(function(ok) return result:match(function(ok)
return "Result.ok(" .. tostring(ok) .. ")" return XorStr("Result.ok(") .. tostring(ok) .. ")"
end, function(err) end, function(err)
return "Result.err(" .. tostring(err) .. ")" return XorStr("Result.err(") .. tostring(err) .. ")"
end) end)
end end
return { return {
@ -267,8 +267,8 @@ TEST_CASE_FIXTURE(LimitFixture, "typescript_port_of_Result_type")
CheckResult result = check(src); CheckResult result = check(src);
CodeTooComplex ctc; CodeTooComplex ctc;
if (FFlag::LuauLowerBoundsCalculation) if (FFlag::LluLowerBoundsCalculation)
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
else else
CHECK(hasError(result, &ctc)); 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 #pragma once
#include "Luau/Common.h" #include "lluz/Common.h"
#include <string.h> #include <string.h>
@ -9,13 +9,13 @@ template<typename T>
struct ScopedFValue struct ScopedFValue
{ {
private: private:
Luau::FValue<T>* value = nullptr; lluz::FValue<T>* value = nullptr;
T oldValue = T(); T oldValue = T();
public: public:
ScopedFValue(const char* name, T newValue) 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) if (strcmp(v->name, name) == 0)
{ {
value = v; value = v;
@ -24,7 +24,7 @@ public:
break; break;
} }
LUAU_ASSERT(value); lluz_ASSERT(value);
} }
ScopedFValue(const ScopedFValue&) = delete; 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/StringUtils.h" #include "lluz/StringUtils.h"
#include "doctest.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) 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); 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 currentA = a.substr(0, x);
std::string_view currentB = b.substr(0, y); 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]; size_t expected = distances[x][y];
CHECK_MESSAGE(actual == expected, format(currentA, currentB, expected, actual)); CHECK_MESSAGE(actual == expected, format(currentA, currentB, expected, actual));
} }
@ -33,7 +33,7 @@ void compareLevenshtein(LevenshteinMatrix distances, std::string_view a, std::st
} }
} // namespace } // namespace
TEST_SUITE_BEGIN("StringUtilsTest"); TEST_SUITE_BEGIN(XorStr("StringUtilsTest"));
#if 0 #if 0
// This unit test is only used to measure how performant the current levenshtein distance algorithm is. // 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, // - are real words,
// - have common prefix and suffix, and // - have common prefix and suffix, and
// - are sufficiently long enough to stress test with // - are sufficiently long enough to stress test with
std::string_view a("Intercalate"); std::string_view a(XorStr("Intercalate"));
std::string_view b("Interchangeable"); std::string_view b(XorStr("Interchangeable"));
auto start = std::chrono::steady_clock::now(); auto start = std::chrono::steady_clock::now();
for (int i = 0; i < count; ++i) for (int i = 0; i < count; ++i)
Luau::editDistance(a, b); lluz::editDistance(a, b);
auto end = std::chrono::steady_clock::now(); auto end = std::chrono::steady_clock::now();
auto time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start); 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 {6, 6, 5, 4, 3, 3, 2, 3}, // N
}; };
compareLevenshtein(distances, "kitten", "sitting"); compareLevenshtein(distances, XorStr("kitten", "sitting"));
} }
TEST_CASE("LevenshteinDistanceSaturdaySunday") TEST_CASE("LevenshteinDistanceSaturdaySunday")
@ -92,17 +92,17 @@ TEST_CASE("LevenshteinDistanceSaturdaySunday")
{8, 7, 6, 6, 5, 4, 3}, // Y {8, 7, 6, 6, 5, 4, 3}, // Y
}; };
compareLevenshtein(distances, "saturday", "sunday"); compareLevenshtein(distances, XorStr("saturday", "sunday"));
} }
TEST_CASE("EditDistanceIsAgnosticOfArgumentOrdering") 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") TEST_CASE("AreWeUsingDistanceWithAdjacentTranspositionsAndNotOptimalStringAlignment")
{ {
size_t distance = Luau::editDistance("CA", "ABC"); size_t distance = lluz::editDistance(XorStr("CA", "ABC"));
CHECK_EQ(distance, 2); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Symbol.h" #include "lluz/Symbol.h"
#include "Luau/Ast.h" #include "lluz/Ast.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
TEST_SUITE_BEGIN("SymbolTests"); TEST_SUITE_BEGIN(XorStr("SymbolTests"));
TEST_CASE("hashing_globals") 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 "lluz/Scope.h"
#include "Luau/ToDot.h" #include "lluz/ToDot.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
LUAU_FASTFLAG(LuauLowerBoundsCalculation) lluz_FASTFLAG(LluLowerBoundsCalculation)
using namespace Luau; using namespace lluz;
struct ToDotClassFixture : Fixture struct ToDotClassFixture : Fixture
{ {
@ -40,7 +40,7 @@ struct ToDotClassFixture : Fixture
} }
}; };
TEST_SUITE_BEGIN("ToDot"); TEST_SUITE_BEGIN(XorStr("ToDot"));
TEST_CASE_FIXTURE(Fixture, "primitive") TEST_CASE_FIXTURE(Fixture, "primitive")
{ {
@ -49,7 +49,7 @@ local a: nil
local b: number local b: number
local c: any local c: any
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_NE("nil", toDot(requireType("a"))); CHECK_NE("nil", toDot(requireType("a")));
@ -84,9 +84,9 @@ TEST_CASE_FIXTURE(Fixture, "bound")
local a = 444 local a = 444
local b = a 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)); REQUIRE(bool(ty));
ToDotOptions opts; ToDotOptions opts;
@ -104,14 +104,14 @@ TEST_CASE_FIXTURE(Fixture, "function")
CheckResult result = check(R"( CheckResult result = check(R"(
local function f(a, ...: string) return a end 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"))); CHECK_EQ("<a>(a, ...string) -> a", toString(requireType("f")));
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
if (FFlag::LuauLowerBoundsCalculation) if (FFlag::LluLowerBoundsCalculation)
{ {
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="FunctionTypeVar 1"]; n1 [label="FunctionTypeVar 1"];
@ -158,7 +158,7 @@ TEST_CASE_FIXTURE(Fixture, "union")
CheckResult result = check(R"( CheckResult result = check(R"(
local a: string | number local a: string | number
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
@ -177,7 +177,7 @@ TEST_CASE_FIXTURE(Fixture, "intersection")
CheckResult result = check(R"( CheckResult result = check(R"(
local a: string & number -- uninhabited local a: string & number -- uninhabited
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
@ -197,7 +197,7 @@ TEST_CASE_FIXTURE(Fixture, "table")
type A<T, U...> = { x: T, y: (U...) -> (), [string]: any } type A<T, U...> = { x: T, y: (U...) -> (), [string]: any }
local a: A<number, ...string> local a: A<number, ...string>
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
@ -232,7 +232,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "metatable")
CheckResult result = check(R"( CheckResult result = check(R"(
local a: typeof(setmetatable({}, {})) local a: typeof(setmetatable({}, {}))
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
@ -287,7 +287,7 @@ TEST_CASE_FIXTURE(ToDotClassFixture, "class")
CheckResult result = check(R"( CheckResult result = check(R"(
local a: ChildClass local a: ChildClass
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
@ -375,9 +375,9 @@ local b
b.x = 2 b.x = 2
b = a 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)); REQUIRE(bool(ty));
ToDotOptions opts; 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 "lluz/Scope.h"
#include "Luau/ToString.h" #include "lluz/ToString.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
LUAU_FASTFLAG(LuauRecursiveTypeParameterRestriction); lluz_FASTFLAG(LluRecursiveTypeParameterRestriction);
LUAU_FASTFLAG(LuauSpecialTypesAsterisked);
TEST_SUITE_BEGIN("ToString"); TEST_SUITE_BEGIN(XorStr("ToString"));
TEST_CASE_FIXTURE(Fixture, "primitive") TEST_CASE_FIXTURE(Fixture, "primitive")
{ {
CheckResult result = check("local a = nil local b = 44 local c = 'lalala' local d = true"); CheckResult result = check(XorStr("local a = nil local b = 44 local c = 'lalala' local d = true"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
// A variable without an annotation and with a nil literal should infer as 'free', not 'nil' // A variable without an annotation and with a nil literal should infer as 'free', not 'nil'
CHECK_NE("nil", toString(requireType("a"))); CHECK_NE("nil", toString(requireType("a")));
@ -29,16 +28,16 @@ TEST_CASE_FIXTURE(Fixture, "primitive")
TEST_CASE_FIXTURE(Fixture, "bound_types") TEST_CASE_FIXTURE(Fixture, "bound_types")
{ {
CheckResult result = check("local a = 444 local b = a"); CheckResult result = check(XorStr("local a = 444 local b = a"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("b"))); CHECK_EQ("number", toString(requireType("b")));
} }
TEST_CASE_FIXTURE(Fixture, "free_types") TEST_CASE_FIXTURE(Fixture, "free_types")
{ {
CheckResult result = check("local a"); CheckResult result = check(XorStr("local a"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("a", toString(requireType("a"))); CHECK_EQ("a", toString(requireType("a")));
} }
@ -63,6 +62,7 @@ TEST_CASE_FIXTURE(Fixture, "named_table")
TEST_CASE_FIXTURE(Fixture, "empty_table") TEST_CASE_FIXTURE(Fixture, "empty_table")
{ {
ScopedFastFlag lluzToStringTableBracesNewlines("lluzToStringTableBracesNewlines", true);
CheckResult result = check(R"( CheckResult result = check(R"(
local a: {} local a: {}
)"); )");
@ -77,6 +77,7 @@ TEST_CASE_FIXTURE(Fixture, "empty_table")
TEST_CASE_FIXTURE(Fixture, "table_respects_use_line_break") TEST_CASE_FIXTURE(Fixture, "table_respects_use_line_break")
{ {
ScopedFastFlag lluzToStringTableBracesNewlines("lluzToStringTableBracesNewlines", true);
CheckResult result = check(R"( CheckResult result = check(R"(
local a: { prop: string, anotherProp: number, thirdProp: boolean } local a: { prop: string, anotherProp: number, thirdProp: boolean }
)"); )");
@ -120,7 +121,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "named_metatable_toStringNamedFunction")
type NamedMetatable = typeof(createTbl()) type NamedMetatable = typeof(createTbl())
)"); )");
TypeId ty = requireType("createTbl"); TypeId ty = requireType(XorStr("createTbl"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty)); const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
REQUIRE(ftv); REQUIRE(ftv);
CHECK_EQ("createTbl(): NamedMetatable", toStringNamedFunction("createTbl", *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 utv = TypeVar{UnionTypeVar{{typeChecker.numberType, typeChecker.stringType}}};
auto itv = TypeVar{IntersectionTypeVar{{&utv, typeChecker.booleanType}}}; 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") 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 itv = TypeVar{IntersectionTypeVar{{typeChecker.numberType, typeChecker.stringType}}};
auto utv = TypeVar{UnionTypeVar{{&itv, typeChecker.booleanType}}}; 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") 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 utv = TypeVar{UnionTypeVar{{&ns2sn, &sn2ns}}};
auto itv = TypeVar{IntersectionTypeVar{{&ns2sn, &sn2ns}}}; auto itv = TypeVar{IntersectionTypeVar{{&ns2sn, &sn2ns}}};
CHECK_EQ(toString(&utv), "((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), "((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") 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; ToStringOptions o;
o.exhaustive = false; o.exhaustive = false;
o.maxTableLength = 40; 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") 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; ToStringOptions o;
o.exhaustive = true; o.exhaustive = true;
o.maxTableLength = 40; 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") 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 f2(f) return f or f1 end
function f3(f) return f or f2 end function f3(f) return f or f2 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ToStringOptions o; ToStringOptions o;
o.exhaustive = false; o.exhaustive = false;
o.maxTypeLength = 40; o.maxTypeLength = 40;
CHECK_EQ(toString(requireType("f0"), o), "() -> ()"); CHECK_EQ(toString(requireType(XorStr("f0"), o), "() -> ()"));
CHECK_EQ(toString(requireType("f1"), o), "(() -> ()) -> () -> ()"); CHECK_EQ(toString(requireType(XorStr("f1"), o), "(() -> ()) -> () -> ()"));
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ(toString(requireType(XorStr("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>"));
{ CHECK_EQ(toString(requireType(XorStr("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>"));
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>");
}
} }
TEST_CASE_FIXTURE(Fixture, "stringifying_type_is_still_capped_when_exhaustive") 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 f2(f) return f or f1 end
function f3(f) return f or f2 end function f3(f) return f or f2 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ToStringOptions o; ToStringOptions o;
o.exhaustive = true; o.exhaustive = true;
o.maxTypeLength = 40; o.maxTypeLength = 40;
CHECK_EQ(toString(requireType("f0"), o), "() -> ()"); CHECK_EQ(toString(requireType(XorStr("f0"), o), "() -> ()"));
CHECK_EQ(toString(requireType("f1"), o), "(() -> ()) -> () -> ()"); CHECK_EQ(toString(requireType(XorStr("f1"), o), "(() -> ()) -> () -> ()"));
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ(toString(requireType(XorStr("f2"), o), "((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>"));
{ CHECK_EQ(toString(requireType(XorStr("f3"), o), "(((() -> ()) -> () -> ()) -> (() -> ()) -> ... <TRUNCATED>"));
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>");
}
} }
TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_correctly_use_matching_table_state_braces") 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; ToStringOptions o;
o.maxTableLength = 40; 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") 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") TEST_CASE_FIXTURE(Fixture, "generic_packs_are_stringified_differently_from_generic_types")
{ {
TypePackVar tpv{GenericTypePack{"a"}}; TypePackVar tpv{GenericTypePack{"a"}};
CHECK_EQ(toString(&tpv), "a..."); CHECK_EQ(toString(&tpv), XorStr("a..."));
TypeVar tv{GenericTypeVar{"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") TEST_CASE_FIXTURE(Fixture, "function_type_with_argument_names")
{ {
CheckResult result = check("type MyFunc = (a: number, string, c: number) -> string; local a : MyFunc"); CheckResult result = check(XorStr("type MyFunc = (a: number, string, c: number) -> string; local a : MyFunc"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ToStringOptions opts; ToStringOptions opts;
opts.functionTypeArguments = true; 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") TEST_CASE_FIXTURE(Fixture, "function_type_with_argument_names_generic")
{ {
CheckResult result = check("local function f<a...>(n: number, ...: a...): (a...) return ... end"); CheckResult result = check(XorStr("local function f<a...>(n: number, ...: a...): (a...) return ... end"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ToStringOptions opts; ToStringOptions opts;
opts.functionTypeArguments = true; opts.functionTypeArguments = true;
@ -396,7 +380,7 @@ type Table = typeof(tbl)
type Foo = typeof(tbl.foo) type Foo = typeof(tbl.foo)
local u: Foo local u: Foo
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ToStringOptions opts; ToStringOptions opts;
opts.functionTypeArguments = true; opts.functionTypeArguments = true;
@ -414,7 +398,7 @@ TEST_CASE_FIXTURE(Fixture, "generate_friendly_names_for_inferred_generics")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("<a>(a) -> a", toString(requireType("id"))); CHECK_EQ("<a>(a) -> a", toString(requireType("id")));
@ -432,9 +416,9 @@ TEST_CASE_FIXTURE(Fixture, "toStringDetailed")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
TypeId id3Type = requireType("id3"); TypeId id3Type = requireType(XorStr("id3"));
ToStringResult nameData = toStringDetailed(id3Type); ToStringResult nameData = toStringDetailed(id3Type);
REQUIRE_EQ(3, nameData.nameMap.typeVars.size()); REQUIRE_EQ(3, nameData.nameMap.typeVars.size());
@ -456,7 +440,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringDetailed")
TEST_CASE_FIXTURE(BuiltinsFixture, "toStringDetailed2") TEST_CASE_FIXTURE(BuiltinsFixture, "toStringDetailed2")
{ {
ScopedFastFlag sff2{"DebugLuauSharedSelf", true}; ScopedFastFlag sff2{"DebuglluzSharedSelf", true};
CheckResult result = check(R"( CheckResult result = check(R"(
local base = {} local base = {}
@ -469,9 +453,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "toStringDetailed2")
local inst = {} local inst = {}
setmetatable(inst, {__index=child}) 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); ToStringResult r = toStringDetailed(tType);
CHECK_EQ("{ @metatable { __index: { @metatable {| __index: base |}, child } }, inst }", r.name); CHECK_EQ("{ @metatable { __index: { @metatable {| __index: base |}, child } }, inst }", r.name);
CHECK_EQ(0, r.nameMap.typeVars.size()); 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 local function target(callback: nil) return callback(4, "hello") end
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("(nil) -> (*unknown*)", toString(requireType("target")));
CHECK_EQ("(nil) -> (*error-type*)", toString(requireType("target")));
else
CHECK_EQ("(nil) -> (<error-type>)", toString(requireType("target")));
} }
TEST_CASE_FIXTURE(Fixture, "toStringGenericPack") TEST_CASE_FIXTURE(Fixture, "toStringGenericPack")
@ -527,8 +508,8 @@ TEST_CASE_FIXTURE(Fixture, "toStringGenericPack")
function foo(a, b) return a(b) end function foo(a, b) return a(b) end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("foo")), "<a, b...>((a) -> (b...), a) -> (b...)"); 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") 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 local g: F = f
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("t1 where t1 = ((() -> number)?) -> t1?", toString(requireType("g"))); 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) 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"))); 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->name = "Table";
ttv->instantiatedTypeParams.push_back(&tableTy); ttv->instantiatedTypeParams.push_back(&tableTy);
CHECK_EQ(toString(tableTy), "Table<Table>"); CHECK_EQ(toString(tableTy), XorStr("Table<Table>"));
} }
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_id") TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_id")
@ -594,7 +575,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_id")
local function id(x) return x end local function id(x) return x end
)"); )");
TypeId ty = requireType("id"); TypeId ty = requireType(XorStr("id"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty)); const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("id<a>(x: a): a", toStringNamedFunction("id", *ftv)); CHECK_EQ("id<a>(x: a): a", toStringNamedFunction("id", *ftv));
@ -612,7 +593,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_map")
end end
)"); )");
TypeId ty = requireType("map"); TypeId ty = requireType(XorStr("map"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty)); const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("map<a, b>(arr: {a}, fn: (a) -> b): {b}", toStringNamedFunction("map", *ftv)); 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 end
)"); )");
TypeId ty = requireType("test"); TypeId ty = requireType(XorStr("test"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty)); const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("test<T..., U...>(...: T...): U...", toStringNamedFunction("test", *ftv)); CHECK_EQ("test<T..., U...>(...: T...): U...", toStringNamedFunction("test", *ftv));
@ -649,7 +630,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics")
end end
)"); )");
TypeId ty = requireType("f"); TypeId ty = requireType(XorStr("f"));
auto ftv = get<FunctionTypeVar>(follow(ty)); auto ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("f<a, b...>(x: a, ...: any): (a, a, b...)", toStringNamedFunction("f", *ftv)); 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 end
)"); )");
TypeId ty = requireType("f"); TypeId ty = requireType(XorStr("f"));
auto ftv = get<FunctionTypeVar>(follow(ty)); auto ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("f(): ...number", toStringNamedFunction("f", *ftv)); CHECK_EQ("f(): ...number", toStringNamedFunction("f", *ftv));
@ -677,7 +658,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics3")
end end
)"); )");
TypeId ty = requireType("f"); TypeId ty = requireType(XorStr("f"));
auto ftv = get<FunctionTypeVar>(follow(ty)); auto ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("f(): (string, ...number)", toStringNamedFunction("f", *ftv)); 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 local f: (number, y: number) -> number
)"); )");
TypeId ty = requireType("f"); TypeId ty = requireType(XorStr("f"));
auto ftv = get<FunctionTypeVar>(follow(ty)); auto ftv = get<FunctionTypeVar>(follow(ty));
CHECK_EQ("f(_: number, y: number): number", toStringNamedFunction("f", *ftv)); CHECK_EQ("f(_: number, y: number): number", toStringNamedFunction("f", *ftv));
@ -702,7 +683,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_hide_type_params")
end end
)"); )");
TypeId ty = requireType("f"); TypeId ty = requireType(XorStr("f"));
auto ftv = get<FunctionTypeVar>(follow(ty)); auto ftv = get<FunctionTypeVar>(follow(ty));
ToStringOptions opts; ToStringOptions opts;
@ -716,7 +697,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_overrides_param_names")
local function test(a, b : string, ... : number) return a end 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)); const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
ToStringOptions opts; 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") TEST_CASE_FIXTURE(Fixture, "pick_distinct_names_for_mixed_explicit_and_implicit_generics")
{ {
ScopedFastFlag sff[] = { ScopedFastFlag sff[] = {
{"LuauAlwaysQuantify", true}, {"lluzAlwaysQuantify", true},
}; };
CheckResult result = check(R"( 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") TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_include_self_param")
{ {
ScopedFastFlag sff[]{ ScopedFastFlag sff[]{
{"DebugLuauSharedSelf", true}, {"DebuglluzSharedSelf", true},
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
@ -749,7 +730,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_include_self_param")
end end
)"); )");
TypeId parentTy = requireType("foo"); TypeId parentTy = requireType(XorStr("foo"));
auto ttv = get<TableTypeVar>(follow(parentTy)); auto ttv = get<TableTypeVar>(follow(parentTy));
auto ftv = get<FunctionTypeVar>(ttv->props.at("method").type); 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") TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_hide_self_param")
{ {
ScopedFastFlag sff[]{ ScopedFastFlag sff[]{
{"DebugLuauSharedSelf", true}, {"DebuglluzSharedSelf", true},
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
@ -768,7 +749,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_hide_self_param")
end end
)"); )");
TypeId parentTy = requireType("foo"); TypeId parentTy = requireType(XorStr("foo"));
auto ttv = get<TableTypeVar>(follow(parentTy)); auto ttv = get<TableTypeVar>(follow(parentTy));
auto ftv = get<FunctionTypeVar>(ttv->props.at("method").type); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TopoSortStatements.h" #include "lluz/TopoSortStatements.h"
#include "Luau/Transpiler.h" #include "lluz/Transpiler.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
static std::vector<AstStat*> toposort(AstStatBlock& block) static std::vector<AstStat*> toposort(AstStatBlock& block)
{ {
std::vector<AstStat*> result{block.body.begin(), block.body.end()}; std::vector<AstStat*> result{block.body.begin(), block.body.end()};
Luau::toposort(result); lluz::toposort(result);
return result; return result;
} }
TEST_SUITE_BEGIN("TopoSortTests"); TEST_SUITE_BEGIN(XorStr("TopoSortTests"));
TEST_CASE_FIXTURE(Fixture, "sorts") TEST_CASE_FIXTURE(Fixture, "sorts")
{ {
@ -345,7 +345,7 @@ TEST_CASE_FIXTURE(Fixture, "return_comes_last")
local function confuseCompiler() return module.foo() end local function confuseCompiler() return module.foo() end
module.foo = function() return "" end module.foo = function() return XorStr("") end
function module.bar(x:number) function module.bar(x:number)
confuseCompiler() confuseCompiler()
@ -370,7 +370,7 @@ TEST_CASE_FIXTURE(Fixture, "break_comes_last")
repeat repeat
local module = {} local module = {}
local function confuseCompiler() return module.foo() end local function confuseCompiler() return module.foo() end
module.foo = function() return "" end module.foo = function() return XorStr("") end
break break
until true until true
)"); )");
@ -394,7 +394,7 @@ TEST_CASE_FIXTURE(Fixture, "continue_comes_last")
repeat repeat
local module = {} local module = {}
local function confuseCompiler() return module.foo() end local function confuseCompiler() return module.foo() end
module.foo = function() return "" end module.foo = function() return XorStr("") end
continue continue
until true 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Parser.h" #include "lluz/Parser.h"
#include "Luau/TypeAttach.h" #include "lluz/TypeAttach.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Luau/Transpiler.h" #include "lluz/Transpiler.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
TEST_SUITE_BEGIN("TranspilerTests"); TEST_SUITE_BEGIN(XorStr("TranspilerTests"));
TEST_CASE("test_1") 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") 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. // 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 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)"; 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 "Fixture.h"
#include "doctest.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") TEST_CASE_FIXTURE(Fixture, "basic_alias")
{ {
@ -18,7 +18,7 @@ TEST_CASE_FIXTURE(Fixture, "basic_alias")
local x: T = 1 local x: T = 1
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("x"))); CHECK_EQ("number", toString(requireType("x")));
} }
@ -33,7 +33,7 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_function_type_in_type_alias")
local g: F = f local g: F = f
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("t1 where t1 = () -> t1?", toString(requireType("g"))); CHECK_EQ("t1 where t1 = () -> t1?", toString(requireType("g")));
} }
@ -44,7 +44,7 @@ TEST_CASE_FIXTURE(Fixture, "names_are_ascribed")
local x: T local x: T
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("T", toString(requireType("x"))); CHECK_EQ("T", toString(requireType("x")));
} }
@ -69,8 +69,8 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias")
type T = number type T = number
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
if (FFlag::DebugLuauDeferredConstraintResolution) if (FFlag::DebugLluDeferredConstraintResolution)
{ {
CHECK(result.errors[0] == TypeError{ CHECK(result.errors[0] == TypeError{
Location{{1, 21}, {1, 26}}, 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 node.Parent = 1
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm); REQUIRE(tm);
@ -123,7 +123,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_aliases")
y.g.i = y y.g.i = y
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_generic_aliases") TEST_CASE_FIXTURE(Fixture, "mutually_recursive_generic_aliases")
@ -138,7 +138,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_generic_aliases")
y.g.i = y y.g.i = y
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_errors") TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_errors")
@ -153,10 +153,10 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_errors")
y.g.i = y 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 // 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); unfreeze(module->interfaceTypes);
copyErrors(module->errors, module->interfaceTypes); copyErrors(module->errors, module->interfaceTypes);
freeze(module->interfaceTypes); freeze(module->interfaceTypes);
@ -178,7 +178,7 @@ TEST_CASE_FIXTURE(Fixture, "use_table_name_and_generic_params_in_errors")
a = b a = b
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm); 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'" 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") 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 local l: Wrapped = 2
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm); REQUIRE(tm);
@ -222,7 +222,7 @@ TEST_CASE_FIXTURE(Fixture, "stringify_type_alias_of_recursive_template_table_typ
local l: Wrapped = 2 local l: Wrapped = 2
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm); 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") 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 type Id<T> = T
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "corecursive_types_generic") TEST_CASE_FIXTURE(Fixture, "corecursive_types_generic")
@ -272,7 +272,7 @@ TEST_CASE_FIXTURE(Fixture, "corecursive_types_generic")
CHECK_EQ(expected, decorateWithTypes(code)); CHECK_EQ(expected, decorateWithTypes(code));
CheckResult result = check(code); CheckResult result = check(code);
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "corecursive_function_types") TEST_CASE_FIXTURE(Fixture, "corecursive_function_types")
@ -284,7 +284,7 @@ TEST_CASE_FIXTURE(Fixture, "corecursive_function_types")
local b: B 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 = () -> (number, () -> (string, t1))", toString(requireType("a")));
CHECK_EQ("t1 where t1 = () -> (string, () -> (number, t1))", toString(requireType("b"))); 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)); CHECK_EQ(expected, decorateWithTypes(code));
CheckResult result = check(code); CheckResult result = check(code);
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "export_type_and_type_alias_are_duplicates") 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 type Foo = number
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
auto dtd = get<DuplicateTypeDefinition>(result.errors[0]); auto dtd = get<DuplicateTypeDefinition>(result.errors[0]);
REQUIRE(dtd); 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") 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 type B = number
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
auto dtd = get<DuplicateTypeDefinition>(result.errors[0]); auto dtd = get<DuplicateTypeDefinition>(result.errors[0]);
REQUIRE(dtd); REQUIRE(dtd);
CHECK_EQ(dtd->name, "B"); CHECK_EQ(dtd->name, XorStr("B"));
CHECK_EQ(dtd->previousLocation.begin.line + 1, 3); CHECK_EQ(dtd->previousLocation.begin.line + 1, 3);
} }
@ -357,7 +357,7 @@ TEST_CASE_FIXTURE(Fixture, "stringify_optional_parameterized_alias")
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
auto e = get<TypeMismatch>(result.errors[0]); auto e = get<TypeMismatch>(result.errors[0]);
CHECK_EQ("Node<T>?", toString(e->givenType)); CHECK_EQ("Node<T>?", toString(e->givenType));
@ -383,32 +383,32 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "general_require_multi_assign")
local b: Bar.myvec3 local b: Bar.myvec3
)"; )";
CheckResult result = frontend.check("workspace/C"); CheckResult result = frontend.check(XorStr("workspace/C"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ModulePtr m = frontend.moduleResolver.modules["workspace/C"]; ModulePtr m = frontend.moduleResolver.modules["workspace/C"];
REQUIRE(m != nullptr); REQUIRE(m != nullptr);
std::optional<TypeId> aTypeId = lookupName(m->getModuleScope(), "a"); std::optional<TypeId> aTypeId = lookupName(m->getModuleScope(), XorStr("a"));
REQUIRE(aTypeId); REQUIRE(aTypeId);
const Luau::TableTypeVar* aType = get<TableTypeVar>(follow(*aTypeId)); const lluz::TableTypeVar* aType = get<TableTypeVar>(follow(*aTypeId));
REQUIRE(aType); REQUIRE(aType);
REQUIRE(aType->props.size() == 2); REQUIRE(aType->props.size() == 2);
std::optional<TypeId> bTypeId = lookupName(m->getModuleScope(), "b"); std::optional<TypeId> bTypeId = lookupName(m->getModuleScope(), XorStr("b"));
REQUIRE(bTypeId); REQUIRE(bTypeId);
const Luau::TableTypeVar* bType = get<TableTypeVar>(follow(*bTypeId)); const lluz::TableTypeVar* bType = get<TableTypeVar>(follow(*bTypeId));
REQUIRE(bType); REQUIRE(bType);
REQUIRE(bType->props.size() == 3); REQUIRE(bType->props.size() == 3);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_import_mutation") TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_import_mutation")
{ {
CheckResult result = check("type t10<x> = typeof(table)"); CheckResult result = check(XorStr("type t10<x> = typeof(table)"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
TypeId ty = getGlobalBinding(frontend.typeChecker, "table"); TypeId ty = getGlobalBinding(frontend.typeChecker, XorStr("table"));
CHECK_EQ(toString(ty), "table"); CHECK_EQ(toString(ty), XorStr("table"));
const TableTypeVar* ttv = get<TableTypeVar>(ty); const TableTypeVar* ttv = get<TableTypeVar>(ty);
REQUIRE(ttv); REQUIRE(ttv);
@ -423,11 +423,11 @@ type Cool = { a: number, b: string }
local c: Cool = { a = 1, b = "s" } local c: Cool = { a = 1, b = "s" }
type NotCool<x> = Cool 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); REQUIRE(ty);
CHECK_EQ(toString(*ty), "Cool"); CHECK_EQ(toString(*ty), XorStr("Cool"));
const TableTypeVar* ttv = get<TableTypeVar>(*ty); const TableTypeVar* ttv = get<TableTypeVar>(*ty);
REQUIRE(ttv); REQUIRE(ttv);
@ -443,15 +443,15 @@ type NotCool = Cool
local c: Cool = { a = 1, b = "s" } local c: Cool = { a = 1, b = "s" }
local d: NotCool = { 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); REQUIRE(ty);
CHECK_EQ(toString(*ty), "Cool"); CHECK_EQ(toString(*ty), XorStr("Cool"));
ty = requireType("d"); ty = requireType(XorStr("d"));
REQUIRE(ty); REQUIRE(ty);
CHECK_EQ(toString(*ty), "NotCool"); CHECK_EQ(toString(*ty), XorStr("NotCool"));
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_local_synthetic_mutation") 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" } local c = { a = 1, b = "s" }
type Cool = typeof(c) 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); REQUIRE(ty);
const TableTypeVar* ttv = get<TableTypeVar>(*ty); const TableTypeVar* ttv = get<TableTypeVar>(*ty);
REQUIRE(ttv); REQUIRE(ttv);
CHECK_EQ(ttv->name, "Cool"); CHECK_EQ(ttv->name, XorStr("Cool"));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_of_an_imported_recursive_type") TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_of_an_imported_recursive_type")
@ -477,19 +477,19 @@ export type X = { a: number, b: X? }
return {} return {}
)"; )";
CheckResult aResult = frontend.check("game/A"); CheckResult aResult = frontend.check(XorStr("game/A"));
LUAU_REQUIRE_NO_ERRORS(aResult); lluz_REQUIRE_NO_ERRORS(aResult);
CheckResult bResult = check(R"( CheckResult bResult = check(R"(
local Import = require(game.A) local Import = require(game.A)
type X = Import.X 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); REQUIRE(ty1);
std::optional<TypeId> ty2 = lookupType("X"); std::optional<TypeId> ty2 = lookupType(XorStr("X"));
REQUIRE(ty2); REQUIRE(ty2);
CHECK_EQ(follow(*ty1), follow(*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 {} return {}
)"; )";
CheckResult aResult = frontend.check("game/A"); CheckResult aResult = frontend.check(XorStr("game/A"));
LUAU_REQUIRE_NO_ERRORS(aResult); lluz_REQUIRE_NO_ERRORS(aResult);
CheckResult bResult = check(R"( CheckResult bResult = check(R"(
local Import = require(game.A) local Import = require(game.A)
type X<T, U> = Import.X<T, U> 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); REQUIRE(ty1);
std::optional<TypeId> ty2 = lookupType("X"); std::optional<TypeId> ty2 = lookupType(XorStr("X"));
REQUIRE(ty2); REQUIRE(ty2);
CHECK_EQ(toString(*ty1, {true}), toString(*ty2, {true})); 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) local Import = require(game.A)
type X<T, U> = Import.X<U, T> 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); REQUIRE(ty1);
ty2 = lookupType("X"); ty2 = lookupType(XorStr("X"));
REQUIRE(ty2); REQUIRE(ty2);
CHECK_EQ(toString(*ty1, {true}), "t1 where t1 = {| C: t1?, a: T, b: U |}"); CHECK_EQ(toString(*ty1, {true}), XorStr("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(*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") TEST_CASE_FIXTURE(Fixture, "module_export_free_type_leak")
@ -545,7 +545,7 @@ end
export type f = typeof(get()) 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") TEST_CASE_FIXTURE(Fixture, "module_export_wrapped_free_type_leak")
@ -558,7 +558,7 @@ end
export type f = typeof(get()) 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>} 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") 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}>} type Forest<T> = {Tree<{T}>}
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_2") 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> } 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") 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>} } 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") 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>} } 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") 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> } 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") 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> local p: Tuple<number, string>
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("{number | string}", toString(requireType("p"), {true})); 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)) 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 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})); 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") TEST_CASE_FIXTURE(Fixture, "forward_declared_alias_is_not_clobbered_by_prior_unification_with_any_2")
{ {
ScopedFastFlag sff[] = { ScopedFastFlag sff[] = {
{"DebugLuauSharedSelf", true}, {"DebuglluzSharedSelf", true},
}; };
CheckResult result = check(R"( 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. // 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") 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>} } 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") 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}>} } type Tree<T> = { data: T, children: {Tree<{T}>} }
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_SUITE_END(); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.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") TEST_CASE_FIXTURE(Fixture, "check_against_annotations")
{ {
CheckResult result = check("local a: number = \"Hello Types!\""); CheckResult result = check(XorStr("local a: number = \"Hello Types!\""));
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(Fixture, "check_multi_assign") 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()); CHECK_EQ(2, result.errors.size());
} }
TEST_CASE_FIXTURE(Fixture, "successful_check") TEST_CASE_FIXTURE(Fixture, "successful_check")
{ {
CheckResult result = check("local a: number, b: string = 994, \"eight eighty eight\""); CheckResult result = check(XorStr("local a: number, b: string = 994, \"eight eighty eight\""));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result); dumpErrors(result);
} }
@ -37,7 +37,7 @@ TEST_CASE_FIXTURE(Fixture, "variable_type_is_supertype")
local y: number? = x local y: number? = x
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "function_parameters_can_have_annotations") 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) local four = double(2)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "function_parameter_annotations_are_checked") 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") 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") TEST_CASE_FIXTURE(Fixture, "function_return_annotations_are_checked")
@ -74,9 +74,9 @@ TEST_CASE_FIXTURE(Fixture, "function_return_annotations_are_checked")
end 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); const FunctionTypeVar* ftv = get<FunctionTypeVar>(fiftyType);
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
@ -97,7 +97,7 @@ TEST_CASE_FIXTURE(Fixture, "function_return_multret_annotations_are_checked")
end 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") 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 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") 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 end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(Fixture, "unknown_type_reference_generates_error") 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 local x: IDoNotExist
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK(result.errors[0] == TypeError{ CHECK(result.errors[0] == TypeError{
Location{{1, 17}, {1, 28}}, Location{{1, 17}, {1, 28}},
getMainSourceModule()->name, getMainSourceModule()->name,
@ -153,7 +153,7 @@ TEST_CASE_FIXTURE(Fixture, "typeof_variable_type_annotation_should_return_its_ty
local foo2: Foo local foo2: Foo
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(requireType("foo"), requireType("foo2")); 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("a"));
CHECK_EQ(*typeChecker.numberType, *requireType("b")); 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}})); 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 y = x.a
local z = x.b 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::Number, getPrimitiveType(follow(requireType("y"))));
CHECK_EQ(PrimitiveTypeVar::String, getPrimitiveType(follow(requireType("z")))); CHECK_EQ(PrimitiveTypeVar::String, getPrimitiveType(follow(requireType("z"))));
@ -191,11 +191,11 @@ TEST_CASE_FIXTURE(Fixture, "function_annotation")
CheckResult result = check(R"( CheckResult result = check(R"(
local f: (number, string) -> number local f: (number, string) -> number
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result); dumpErrors(result);
TypeId fType = requireType("f"); TypeId fType = requireType(XorStr("f"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(fType)); const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(fType));
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
@ -204,19 +204,19 @@ TEST_CASE_FIXTURE(Fixture, "function_annotation")
TEST_CASE_FIXTURE(Fixture, "function_annotation_with_a_defined_function") TEST_CASE_FIXTURE(Fixture, "function_annotation_with_a_defined_function")
{ {
CheckResult result = check(R"( 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)); const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(fType));
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "type_assertion_expr") 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"))); 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 local b = a :: number
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("a"))); CHECK_EQ("any", toString(requireType("a")));
CHECK_EQ("number", toString(requireType("b"))); CHECK_EQ("number", toString(requireType("b")));
@ -240,7 +240,7 @@ TEST_CASE_FIXTURE(Fixture, "as_expr_is_bidirectional")
local b = a :: number 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("a")));
CHECK_EQ("number", toString(requireType("b"))); CHECK_EQ("number", toString(requireType("b")));
@ -252,7 +252,7 @@ TEST_CASE_FIXTURE(Fixture, "as_expr_warns_on_unrelated_cast")
local a = 55 :: string 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("Cannot cast 'number' into 'string' because the types are unrelated", toString(result.errors[0]));
CHECK_EQ("string", toString(requireType("a"))); CHECK_EQ("string", toString(requireType("a")));
@ -267,19 +267,19 @@ TEST_CASE_FIXTURE(Fixture, "type_annotations_inside_function_bodies")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result); dumpErrors(result);
} }
TEST_CASE_FIXTURE(Fixture, "for_loop_counter_annotation") TEST_CASE_FIXTURE(Fixture, "for_loop_counter_annotation")
{ {
CheckResult result1 = check(R"( for i: number = 0, 50 do end )"); CheckResult result1 = check(RXorStr("( for i: number = 0, 50 do end )"));
LUAU_REQUIRE_NO_ERRORS(result1); lluz_REQUIRE_NO_ERRORS(result1);
} }
TEST_CASE_FIXTURE(Fixture, "for_loop_counter_annotation_is_checked") 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()); CHECK_EQ(1, result2.errors.size());
} }
@ -289,7 +289,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_should_alias_to_number")
type A = number type A = number
local a: A = 10 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") 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 type B = A
local b: B = 10 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") 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 type A = number
local a: A = "fail" local a: A = "fail"
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(Fixture, "self_referential_type_alias") 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 } 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); REQUIRE(res);
TypeId oType = follow(res->type); TypeId oType = follow(res->type);
const TableTypeVar* oTable = get<TableTypeVar>(oType); const TableTypeVar* oTable = get<TableTypeVar>(oType);
REQUIRE(oTable); REQUIRE(oTable);
std::optional<Property> incr = get(oTable->props, "incr"); std::optional<Property> incr = get(oTable->props, XorStr("incr"));
REQUIRE(incr); REQUIRE(incr);
const FunctionTypeVar* incrFunc = get<FunctionTypeVar>(incr->type); const FunctionTypeVar* incrFunc = get<FunctionTypeVar>(incr->type);
@ -344,11 +344,11 @@ TEST_CASE_FIXTURE(Fixture, "define_generic_type_alias")
type Array<T> = {[number]: T} type Array<T> = {[number]: T}
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ModulePtr mainModule = getMainModule(); ModulePtr mainModule = getMainModule();
auto it = mainModule->getModuleScope()->privateTypeBindings.find("Array"); auto it = mainModule->getModuleScope()->privateTypeBindings.find(XorStr("Array"));
REQUIRE(it != mainModule->getModuleScope()->privateTypeBindings.end()); REQUIRE(it != mainModule->getModuleScope()->privateTypeBindings.end());
TypeFun& tf = it->second; TypeFun& tf = it->second;
@ -364,7 +364,7 @@ TEST_CASE_FIXTURE(Fixture, "use_generic_type_alias")
p[2] = 'hello' -- 4 Error. 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_EQ(4, result.errors[0].location.begin.line);
CHECK(nullptr != get<TypeMismatch>(result.errors[0])); CHECK(nullptr != get<TypeMismatch>(result.errors[0]));
@ -379,11 +379,11 @@ TEST_CASE_FIXTURE(Fixture, "two_type_params")
local b = m[9] -- error here 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(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") 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 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); CHECK_EQ(2, result.errors[0].location.begin.line);
IncorrectGenericParameterCount* igpc = get<IncorrectGenericParameterCount>(result.errors[0]); 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} 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]); auto dgp = get<DuplicateGenericParameter>(result.errors[0]);
REQUIRE(dgp); REQUIRE(dgp);
CHECK_EQ(dgp->parameterName, "T"); CHECK_EQ(dgp->parameterName, XorStr("T"));
} }
TEST_CASE_FIXTURE(Fixture, "typeof_expr") TEST_CASE_FIXTURE(Fixture, "typeof_expr")
@ -426,7 +426,7 @@ TEST_CASE_FIXTURE(Fixture, "typeof_expr")
local m: typeof(id(77)) local m: typeof(id(77))
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("m"))); CHECK_EQ("number", toString(requireType("m")));
} }
@ -440,7 +440,7 @@ TEST_CASE_FIXTURE(Fixture, "corecursive_types_error_on_tight_loop")
local bb:B local bb:B
)"); )");
TypeId fType = requireType("aa"); TypeId fType = requireType(XorStr("aa"));
const AnyTypeVar* ftv = get<AnyTypeVar>(follow(fType)); const AnyTypeVar* ftv = get<AnyTypeVar>(follow(fType));
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
REQUIRE(!result.errors.empty()); REQUIRE(!result.errors.empty());
@ -456,9 +456,9 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_always_resolve_to_a_real_type")
local aa:A local aa:A
)"); )");
TypeId fType = requireType("aa"); TypeId fType = requireType(XorStr("aa"));
REQUIRE(follow(fType) == typeChecker.numberType); 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") 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} return {n=n}
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
Module& mod = *getMainModule(); Module& mod = *getMainModule();
@ -497,13 +497,13 @@ TEST_CASE_FIXTURE(Fixture, "generic_aliases_are_cloned_properly")
CheckResult result = check(R"( CheckResult result = check(R"(
export type Array<T> = { [number]: T } export type Array<T> = { [number]: T }
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result); dumpErrors(result);
Module& mod = *getMainModule(); Module& mod = *getMainModule();
const auto& typeBindings = mod.getModuleScope()->exportedTypeBindings; const auto& typeBindings = mod.getModuleScope()->exportedTypeBindings;
auto it = typeBindings.find("Array"); auto it = typeBindings.find(XorStr("Array"));
REQUIRE(typeBindings.end() != it); REQUIRE(typeBindings.end() != it);
const TypeFun& array = it->second; const TypeFun& array = it->second;
@ -529,7 +529,7 @@ TEST_CASE_FIXTURE(Fixture, "cloned_interface_maintains_pointers_between_definiti
return {a=a, b=b} return {a=a, b=b}
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
Module& mod = *getMainModule(); 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") 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"( fileResolver.source["Modules/Main"] = R"(
--!strict --!strict
@ -576,14 +576,14 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "use_type_required_from_another_file")
return {} 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") 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"( fileResolver.source["Modules/Main"] = R"(
--!strict --!strict
@ -602,14 +602,14 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_use_nonexported_type")
return {} 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") 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"( fileResolver.source["Modules/Main"] = R"(
--!strict --!strict
@ -626,9 +626,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_are_not_exported")
return {} 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 namespace
@ -638,8 +638,8 @@ struct AssertionCatcher
AssertionCatcher() AssertionCatcher()
{ {
tripped = 0; tripped = 0;
oldhook = Luau::assertHandler(); oldhook = lluz::assertHandler();
Luau::assertHandler() = [](const char* expr, const char* file, int line, const char* function) -> int { lluz::assertHandler() = [](const char* expr, const char* file, int line, const char* function) -> int {
++tripped; ++tripped;
return 0; return 0;
}; };
@ -647,38 +647,38 @@ struct AssertionCatcher
~AssertionCatcher() ~AssertionCatcher()
{ {
Luau::assertHandler() = oldhook; lluz::assertHandler() = oldhook;
} }
static int tripped; static int tripped;
Luau::AssertHandler oldhook; lluz::AssertHandler oldhook;
}; };
int AssertionCatcher::tripped; int AssertionCatcher::tripped;
} // namespace } // namespace
TEST_CASE_FIXTURE(Fixture, "luau_ice_triggers_an_ice") TEST_CASE_FIXTURE(Fixture, "lluz_ice_triggers_an_ice")
{ {
ScopedFastFlag sffs[] = { ScopedFastFlag sffs[] = {
{"DebugLuauMagicTypes", true}, {"DebuglluzMagicTypes", true},
{"LuauUseInternalCompilerErrorException", false}, {"lluzUseInternalCompilerErrorException", false},
}; };
AssertionCatcher ac; AssertionCatcher ac;
CHECK_THROWS_AS(check(R"( CHECK_THROWS_AS(check(R"(
local a: _luau_ice = 55 local a: _lluz_ice = 55
)"), )"),
std::runtime_error); 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[] = { ScopedFastFlag sffs[] = {
{"DebugLuauMagicTypes", true}, {"DebuglluzMagicTypes", true},
{"LuauUseInternalCompilerErrorException", false}, {"lluzUseInternalCompilerErrorException", false},
}; };
bool caught = false; bool caught = false;
@ -688,35 +688,35 @@ TEST_CASE_FIXTURE(Fixture, "luau_ice_triggers_an_ice_handler")
}; };
CHECK_THROWS_AS(check(R"( CHECK_THROWS_AS(check(R"(
local a: _luau_ice = 55 local a: _lluz_ice = 55
)"), )"),
std::runtime_error); std::runtime_error);
CHECK_EQ(true, caught); 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[] = { ScopedFastFlag sffs[] = {
{"DebugLuauMagicTypes", true}, {"DebuglluzMagicTypes", true},
{"LuauUseInternalCompilerErrorException", true}, {"lluzUseInternalCompilerErrorException", true},
}; };
AssertionCatcher ac; AssertionCatcher ac;
CHECK_THROWS_AS(check(R"( CHECK_THROWS_AS(check(R"(
local a: _luau_ice = 55 local a: _lluz_ice = 55
)"), )"),
InternalCompilerError); 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[] = { ScopedFastFlag sffs[] = {
{"DebugLuauMagicTypes", true}, {"DebuglluzMagicTypes", true},
{"LuauUseInternalCompilerErrorException", true}, {"lluzUseInternalCompilerErrorException", true},
}; };
bool caught = false; 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"( CHECK_THROWS_AS(check(R"(
local a: _luau_ice = 55 local a: _lluz_ice = 55
)"), )"),
InternalCompilerError); InternalCompilerError);
CHECK_EQ(true, caught); 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 // We only care that this does not throw
check(R"( 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(); // lluz::resetPrintLine();
ScopedFastFlag sffs{"DebugLuauMagicTypes", true}; ScopedFastFlag sffs{"DebuglluzMagicTypes", true};
CheckResult result = check(R"( 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"( 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") 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> local foo: Foo<number>
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
#if 0 #if 0
@ -788,7 +788,7 @@ TEST_CASE_FIXTURE(Fixture, "pulling_a_type_from_value_dont_falsely_create_occurs
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
#endif #endif
@ -798,7 +798,7 @@ TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_union_typevar")
type T = T | T type T = T | T
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
OccursCheckFailed* ocf = get<OccursCheckFailed>(result.errors[0]); OccursCheckFailed* ocf = get<OccursCheckFailed>(result.errors[0]);
REQUIRE(ocf); REQUIRE(ocf);
@ -810,7 +810,7 @@ TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_intersection_typevar")
type T = T & T type T = T & T
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
OccursCheckFailed* ocf = get<OccursCheckFailed>(result.errors[0]); OccursCheckFailed* ocf = get<OccursCheckFailed>(result.errors[0]);
REQUIRE(ocf); REQUIRE(ocf);
@ -823,7 +823,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiation_clone_has_to_follow")
export type t0<t0> = ({})&({_:{[any]:number},}) export type t0<t0> = ({})&({_:{[any]:number},})
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_SUITE_END(); 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 "lluz/AstQuery.h"
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Luau/Scope.h" #include "lluz/Scope.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Luau/VisitTypeVar.h" #include "lluz/VisitTypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
LUAU_FASTFLAG(LuauSpecialTypesAsterisked) TEST_SUITE_BEGIN(XorStr("TypeInferAnyError"));
TEST_SUITE_BEGIN("TypeInferAnyError");
TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_returns_any") 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(typeChecker.anyType, requireType("a")); CHECK_EQ(typeChecker.anyType, requireType("a"));
} }
@ -48,7 +46,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_returns_any2")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("a"))); CHECK_EQ("any", toString(requireType("a")));
} }
@ -64,7 +62,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_any")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("a"))); CHECK_EQ("any", toString(requireType("a")));
} }
@ -80,7 +78,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_any2")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("a"))); CHECK_EQ("any", toString(requireType("a")));
} }
@ -94,12 +92,9 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_error")
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("*unknown*", toString(requireType("a")));
CHECK_EQ("*error-type*", toString(requireType("a")));
else
CHECK_EQ("<error-type>", toString(requireType("a")));
} }
TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_is_error2") 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 end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("*unknown*", toString(requireType("a")));
CHECK_EQ("*error-type*", toString(requireType("a")));
else
CHECK_EQ("<error-type>", toString(requireType("a")));
} }
TEST_CASE_FIXTURE(Fixture, "length_of_error_type_does_not_produce_an_error") 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 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") 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] 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") 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 foo.x = foo.y
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(Fixture, "any_type_propagates") TEST_CASE_FIXTURE(Fixture, "any_type_propagates")
@ -156,7 +148,7 @@ TEST_CASE_FIXTURE(Fixture, "any_type_propagates")
local bar = foo:method("argument") local bar = foo:method("argument")
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("bar"))); CHECK_EQ("any", toString(requireType("bar")));
} }
@ -168,7 +160,7 @@ TEST_CASE_FIXTURE(Fixture, "can_subscript_any")
local bar = foo[5] local bar = foo[5]
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("bar"))); CHECK_EQ("any", toString(requireType("bar")));
} }
@ -181,7 +173,7 @@ TEST_CASE_FIXTURE(Fixture, "can_get_length_of_any")
local bar = #foo local bar = #foo
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(PrimitiveTypeVar::Number, getPrimitiveType(requireType("bar"))); 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 return T
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
TableTypeVar* ttv = getMutable<TableTypeVar>(requireType("T")); TableTypeVar* ttv = getMutable<TableTypeVar>(requireType("T"));
REQUIRE(ttv); REQUIRE(ttv);
@ -214,9 +206,9 @@ TEST_CASE_FIXTURE(Fixture, "quantify_any_does_not_bind_to_itself")
A:C() 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); CHECK_EQ(aType, typeChecker.anyType);
} }
@ -226,17 +218,14 @@ TEST_CASE_FIXTURE(Fixture, "calling_error_type_yields_error")
local a = unknown.Parent.Reward.GetChildren() 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]); UnknownSymbol* err = get<UnknownSymbol>(result.errors[0]);
REQUIRE(err != nullptr); REQUIRE(err != nullptr);
CHECK_EQ("unknown", err->name); CHECK_EQ("unknown", err->name);
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("*unknown*", toString(requireType("a")));
CHECK_EQ("*error-type*", toString(requireType("a")));
else
CHECK_EQ("<error-type>", toString(requireType("a")));
} }
TEST_CASE_FIXTURE(Fixture, "chain_calling_error_type_yields_error") 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" {} local a = Utility.Create "Foo" {}
)"); )");
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("*unknown*", toString(requireType("a")));
CHECK_EQ("*error-type*", toString(requireType("a")));
else
CHECK_EQ("<error-type>", toString(requireType("a")));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "replace_every_free_type_when_unifying_a_complex_function_with_any") 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("b"))); CHECK_EQ("any", toString(requireType("b")));
} }
@ -284,7 +270,7 @@ function x:y(z: number)
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(Fixture, "CheckMethodsOfError") TEST_CASE_FIXTURE(Fixture, "CheckMethodsOfError")
@ -296,7 +282,7 @@ function x:y(z: number)
end end
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "metatable_of_any_can_be_a_table") TEST_CASE_FIXTURE(BuiltinsFixture, "metatable_of_any_can_be_a_table")
@ -316,7 +302,7 @@ function T:construct(index)
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "type_error_addition") TEST_CASE_FIXTURE(Fixture, "type_error_addition")
@ -327,7 +313,7 @@ local foo = makesandwich()
local bar = foo.nutrition + 100 local bar = foo.nutrition + 100
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
// We should definitely get this error // We should definitely get this error
CHECK_EQ("Unknown global 'makesandwich'", toString(result.errors[0])); 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_SUITE_END(); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
LUAU_FASTFLAG(LuauLowerBoundsCalculation); lluz_FASTFLAG(LluLowerBoundsCalculation);
LUAU_FASTFLAG(LuauSpecialTypesAsterisked);
TEST_SUITE_BEGIN("BuiltinTests"); TEST_SUITE_BEGIN(XorStr("BuiltinTests"));
TEST_CASE_FIXTURE(BuiltinsFixture, "math_things_are_defined") TEST_CASE_FIXTURE(BuiltinsFixture, "math_things_are_defined")
{ {
@ -48,7 +47,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "math_things_are_defined")
local a31 = math.random 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") 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) 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") 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) 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") 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) 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") 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) local n = table.remove(t, 7)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("n")), "number?"); CHECK_EQ(toString(requireType(XorStr("n")), "number?"));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "table_concat_returns_string") 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); 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")); CHECK_EQ(*typeChecker.stringType, *requireType("r"));
} }
@ -116,7 +115,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "sort")
table.sort(t) table.sort(t)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_predicate") TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_predicate")
@ -128,7 +127,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_predicate")
table.sort(t, p) table.sort(t, p)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_bad_predicate") TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_bad_predicate")
@ -140,7 +139,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_bad_predicate")
table.sort(t, p) 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)?' CHECK_EQ(R"(Type '(number, number) -> boolean' could not be converted into '((a, a) -> boolean)?'
caused by: caused by:
None of the union options are compatible. For example: Type '(number, number) -> boolean' could not be converted into '(a, a) -> boolean' 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") TEST_CASE_FIXTURE(Fixture, "strings_have_methods")
{ {
CheckResult result = check(R"LUA( CheckResult result = check(R"LUA(
local s = ("RoactHostChangeEvent(%s)"):format("hello") local s = ("RoactHostChangeEvent(%s)"):format(XorStr("hello"))
)LUA"); )LUA");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.stringType, *requireType("s")); 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) 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")); CHECK_EQ(*typeChecker.numberType, *requireType("n"));
} }
@ -184,7 +183,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_tables_sealed")
CheckResult result = check(R"LUA( CheckResult result = check(R"LUA(
local b = bit32 local b = bit32
)LUA"); )LUA");
TypeId bit32 = requireType("b"); TypeId bit32 = requireType(XorStr("b"));
REQUIRE(bit32 != nullptr); REQUIRE(bit32 != nullptr);
const TableTypeVar* bit32t = get<TableTypeVar>(bit32); const TableTypeVar* bit32t = get<TableTypeVar>(bit32);
REQUIRE(bit32t != nullptr); REQUIRE(bit32t != nullptr);
@ -345,7 +344,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "lua_51_exported_globals_all_exist")
)"); )");
dumpErrors(result); dumpErrors(result);
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_unpacks_arg_types_correctly") 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"( CheckResult result = check(R"(
setmetatable({}, setmetatable({}, {})) 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") 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] local s = t[1]
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(typeChecker.stringType, requireType("s")); 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] local s = t[1]
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireType("s"))); CHECK_EQ("string", toString(requireType("s")));
} }
@ -386,7 +385,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_pack")
local t = table.pack(1, "foo", true) 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"))); 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"( CheckResult result = check(R"(
--!strict --!strict
function f(): (string, ...number) function f(): (string, ...number)
return "str", 2, 3, 4 return XorStr("str"), 2, 3, 4
end end
local t = table.pack(f()) 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"))); 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) 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"))); CHECK_EQ("{| [number]: boolean | number, n: number |}", toString(requireType("t")));
result = check(R"( result = check(R"(
local t = table.pack("a", "b", "c") 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"))); CHECK_EQ("{| [number]: string, n: number |}", toString(requireType("t")));
} }
@ -428,13 +427,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "gcinfo")
local n = gcinfo() local n = gcinfo()
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("n")); CHECK_EQ(*typeChecker.numberType, *requireType("n"));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "getfenv") 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") 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 }) 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("n1"));
CHECK_EQ(*typeChecker.numberType, *requireType("n2")); CHECK_EQ(*typeChecker.numberType, *requireType("n2"));
CHECK_EQ(*typeChecker.numberType, *requireType("n3")); CHECK_EQ(*typeChecker.numberType, *requireType("n3"));
@ -457,7 +456,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "thread_is_a_type")
local co = coroutine.create(function() end) local co = coroutine.create(function() end)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.threadType, *requireType("co")); CHECK_EQ(*typeChecker.threadType, *requireType("co"));
} }
@ -476,7 +475,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_resume_anything_goes")
local answer = coroutine.resume(co, 3) local answer = coroutine.resume(co, 3)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_wrap_anything_goes") TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_wrap_anything_goes")
@ -495,7 +494,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_wrap_anything_goes")
local answer = f(3) local answer = f(3)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_should_not_mutate_persisted_types") 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, {}) 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); auto ttv = get<TableTypeVar>(stringType);
REQUIRE(ttv); REQUIRE(ttv);
} }
@ -518,7 +517,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_arg_types_inference")
CheckResult result = check(R"( CheckResult result = check(R"(
--!strict --!strict
function f(a, b, c) 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 end
)"); )");
@ -530,13 +529,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_arg_count_mismatch")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
--!strict --!strict
string.format("%f %d %s") string.format(XorStr("%f %d %s"))
string.format("%s", "hi", 42) string.format(XorStr("%s"), "hi", 42)
string.format("%s", "hi", 42, ...) string.format(XorStr("%s"), "hi", 42, ...)
string.format("%s", "hi", ...) 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[0].location.begin.line, 2);
CHECK_EQ(result.errors[1].location.begin.line, 3); CHECK_EQ(result.errors[1].location.begin.line, 3);
CHECK_EQ(result.errors[2].location.begin.line, 4); 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"( CheckResult result = check(R"(
--!strict --!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]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm); REQUIRE(tm);
CHECK_EQ(tm->wantedType, typeChecker.stringType); 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("boolean", toString(requireType("a")));
CHECK_EQ("number", toString(requireType("b"))); CHECK_EQ("number", toString(requireType("b")));
CHECK_EQ("boolean", toString(requireType("c"))); 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) 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") TEST_CASE_FIXTURE(BuiltinsFixture, "see_thru_select_count")
@ -588,7 +587,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "see_thru_select_count")
)"); )");
dumpErrors(result); dumpErrors(result);
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_decimal_argument_is_rounded_down") 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) 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. // Could be flaky if the fix has regressed.
@ -613,7 +612,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "bad_select_should_not_crash")
end 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 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])); 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) select(5432598430953240958)
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<GenericError>(result.errors[0])); REQUIRE(get<GenericError>(result.errors[0]));
CHECK_EQ("bad argument #1 to select (index out of range)", toString(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) select(3, "a", 1)
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<GenericError>(result.errors[0])); REQUIRE(get<GenericError>(result.errors[0]));
CHECK_EQ("bad argument #1 to select (index out of range)", toString(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)) 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("foo")));
CHECK_EQ("any", toString(requireType("bar"))); 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)) 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("foo")));
CHECK_EQ("any", toString(requireType("bar"))); 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") 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]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm); REQUIRE(tm);
@ -693,10 +692,10 @@ TEST_CASE_FIXTURE(Fixture, "string_format_as_method")
TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument") TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument")
{ {
CheckResult result = check(R"( 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])); 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") TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument2")
{ {
CheckResult result = check(R"( 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 '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])); 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) debug.traceback(co, "msg", 1)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "debug_info_is_crazy") TEST_CASE_FIXTURE(BuiltinsFixture, "debug_info_is_crazy")
@ -741,7 +740,7 @@ debug.info(co, 1, "n")
debug.info(f, "n") debug.info(f, "n")
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "aliased_string_format") TEST_CASE_FIXTURE(BuiltinsFixture, "aliased_string_format")
@ -751,7 +750,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "aliased_string_format")
local s = fmt("%d", "oops") 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])); 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") local a0 = string.packsize("ff")
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_definition") TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_definition")
@ -784,7 +783,7 @@ for c in ("hey"):gmatch("(.)") do
end end
)_"); )_");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "select_on_variadic") TEST_CASE_FIXTURE(BuiltinsFixture, "select_on_variadic")
@ -797,7 +796,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "select_on_variadic")
local a, b, c = select(f()) 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("a")));
CHECK_EQ("any", toString(requireType("b"))); CHECK_EQ("any", toString(requireType("b")));
CHECK_EQ("any", toString(requireType("c"))); 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"( CheckResult result = check(R"(
("%s%d%s"):format(1, "hello", true) ("%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 stringType = typeChecker.stringType;
TypeId numberType = typeChecker.numberType; TypeId numberType = typeChecker.numberType;
TypeId booleanType = typeChecker.booleanType; 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(Location(Position{1, 26}, Position{1, 27}), result.errors[0].location);
CHECK_EQ(TypeErrorData(TypeMismatch{stringType, numberType}), result.errors[0].data); 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') 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])); 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 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") 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 local function g(x) return math.sin(x) end
f = g 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); const FunctionTypeVar* ftv = get<FunctionTypeVar>(fType);
REQUIRE(fType); REQUIRE(fType);
REQUIRE(fType->persistent); REQUIRE(fType->persistent);
REQUIRE(!ftv->definition); REQUIRE(!ftv->definition);
TypeId gType = requireType("g"); TypeId gType = requireType(XorStr("g"));
const FunctionTypeVar* gtv = get<FunctionTypeVar>(gType); const FunctionTypeVar* gtv = get<FunctionTypeVar>(gType);
REQUIRE(gType); REQUIRE(gType);
REQUIRE(!gType->persistent); REQUIRE(!gType->persistent);
@ -886,8 +885,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
if (FFlag::LuauLowerBoundsCalculation) if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ("((boolean | number)?) -> number | true", toString(requireType("f"))); CHECK_EQ("((boolean | number)?) -> number | true", toString(requireType("f")));
else else
CHECK_EQ("((boolean | number)?) -> boolean | number", toString(requireType("f"))); CHECK_EQ("((boolean | number)?) -> boolean | number", toString(requireType("f")));
@ -901,7 +900,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types2")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("((boolean | number)?) -> number | true", toString(requireType("f"))); 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("(...number?) -> (number, ...number?)", toString(requireType("f"))); 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("(nil) -> (never, ...never)", toString(requireType("f"))); CHECK_EQ("(nil) -> nil", toString(requireType("f")));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic") TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic")
@ -947,30 +946,27 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic")
local d = tf1.b 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("Key 'b' not found in table '{| a: number |}'", toString(result.errors[0]));
CHECK_EQ("number", toString(requireType("a"))); CHECK_EQ("number", toString(requireType("a")));
CHECK_EQ("string", toString(requireType("b"))); CHECK_EQ("string", toString(requireType("b")));
CHECK_EQ("boolean", toString(requireType("c"))); CHECK_EQ("boolean", toString(requireType("c")));
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("*unknown*", toString(requireType("d")));
CHECK_EQ("*error-type*", toString(requireType("d")));
else
CHECK_EQ("<error-type>", toString(requireType("d")));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "set_metatable_needs_arguments") TEST_CASE_FIXTURE(BuiltinsFixture, "set_metatable_needs_arguments")
{ {
ScopedFastFlag sff{"LuauSetMetaTableArgsCheck", true}; ScopedFastFlag sff{"lluzSetMetaTableArgsCheck", true};
CheckResult result = check(R"( CheckResult result = check(R"(
local a = {b=setmetatable} local a = {b=setmetatable}
a.b() a.b()
a:b() a:b()
a:b({}) a:b({})
)"); )");
LUAU_REQUIRE_ERROR_COUNT(2, result); lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(toString(result.errors[0]), "Argument count mismatch. Function expects 2 arguments, but none are specified"); CHECK_EQ(result.errors[0], (TypeError{Location{{2, 0}, {2, 5}}, CountMismatch{2, 0}}));
CHECK_EQ(toString(result.errors[1]), "Argument count mismatch. Function expects 2 arguments, but only 1 is specified"); CHECK_EQ(result.errors[1], (TypeError{Location{{3, 0}, {3, 5}}, CountMismatch{2, 1}}));
} }
TEST_CASE_FIXTURE(Fixture, "typeof_unresolved_function") TEST_CASE_FIXTURE(Fixture, "typeof_unresolved_function")
@ -978,13 +974,13 @@ TEST_CASE_FIXTURE(Fixture, "typeof_unresolved_function")
CheckResult result = check(R"( CheckResult result = check(R"(
local function f(a: typeof(f)) end 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])); CHECK_EQ("Unknown global 'f'", toString(result.errors[0]));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "no_persistent_typelevel_change") TEST_CASE_FIXTURE(BuiltinsFixture, "no_persistent_typelevel_change")
{ {
TypeId mathTy = requireType(typeChecker.globalScope, "math"); TypeId mathTy = requireType(typeChecker.globalScope, XorStr("math"));
REQUIRE(mathTy); REQUIRE(mathTy);
TableTypeVar* ttv = getMutable<TableTypeVar>(mathTy); TableTypeVar* ttv = getMutable<TableTypeVar>(mathTy);
REQUIRE(ttv); REQUIRE(ttv);
@ -992,9 +988,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_persistent_typelevel_change")
REQUIRE(ftv); REQUIRE(ftv);
auto original = ftv->level; 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.level == original.level);
CHECK(ftv->level.subLevel == original.subLevel); CHECK(ftv->level.subLevel == original.subLevel);
} }
@ -1009,252 +1005,7 @@ local function f(x: string)
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_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?");
} }
TEST_SUITE_END(); 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 "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
using std::nullopt; using std::nullopt;
struct ClassFixture : BuiltinsFixture struct ClassFixture : BuiltinsFixture
@ -32,7 +32,7 @@ struct ClassFixture : BuiltinsFixture
{"New", {makeFunction(arena, nullopt, {}, {baseClassInstanceType})}}, {"New", {makeFunction(arena, nullopt, {}, {baseClassInstanceType})}},
}; };
typeChecker.globalScope->exportedTypeBindings["BaseClass"] = TypeFun{{}, 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"}); TypeId childClassInstanceType = arena.addType(ClassTypeVar{"ChildClass", {}, baseClassInstanceType, nullopt, {}, {}, "Test"});
@ -45,7 +45,7 @@ struct ClassFixture : BuiltinsFixture
{"New", {makeFunction(arena, nullopt, {}, {childClassInstanceType})}}, {"New", {makeFunction(arena, nullopt, {}, {childClassInstanceType})}},
}; };
typeChecker.globalScope->exportedTypeBindings["ChildClass"] = TypeFun{{}, 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"}); TypeId grandChildInstanceType = arena.addType(ClassTypeVar{"GrandChild", {}, childClassInstanceType, nullopt, {}, {}, "Test"});
@ -58,7 +58,7 @@ struct ClassFixture : BuiltinsFixture
{"New", {makeFunction(arena, nullopt, {}, {grandChildInstanceType})}}, {"New", {makeFunction(arena, nullopt, {}, {grandChildInstanceType})}},
}; };
typeChecker.globalScope->exportedTypeBindings["GrandChild"] = TypeFun{{}, 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"}); TypeId anotherChildInstanceType = arena.addType(ClassTypeVar{"AnotherChild", {}, baseClassInstanceType, nullopt, {}, {}, "Test"});
@ -71,7 +71,7 @@ struct ClassFixture : BuiltinsFixture
{"New", {makeFunction(arena, nullopt, {}, {anotherChildInstanceType})}}, {"New", {makeFunction(arena, nullopt, {}, {anotherChildInstanceType})}},
}; };
typeChecker.globalScope->exportedTypeBindings["AnotherChild"] = TypeFun{{}, anotherChildInstanceType}; typeChecker.globalScope->exportedTypeBindings["AnotherChild"] = TypeFun{{}, anotherChildInstanceType};
addGlobalBinding(typeChecker, "AnotherChild", childClassType, "@test"); addGlobalBinding(typeChecker, XorStr("AnotherChild", childClassType, "@test"));
TypeId vector2MetaType = arena.addType(TableTypeVar{}); TypeId vector2MetaType = arena.addType(TableTypeVar{});
@ -89,7 +89,7 @@ struct ClassFixture : BuiltinsFixture
{"__add", {makeFunction(arena, nullopt, {vector2InstanceType, vector2InstanceType}, {vector2InstanceType})}}, {"__add", {makeFunction(arena, nullopt, {vector2InstanceType, vector2InstanceType}, {vector2InstanceType})}},
}; };
typeChecker.globalScope->exportedTypeBindings["Vector2"] = TypeFun{{}, 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) for (const auto& [name, tf] : typeChecker.globalScope->exportedTypeBindings)
persist(tf.type); 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") 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() local m = BaseClass.StaticMethod()
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
REQUIRE_EQ("number", toString(requireType("m"))); REQUIRE_EQ("number", toString(requireType("m")));
} }
@ -117,7 +117,7 @@ TEST_CASE_FIXTURE(ClassFixture, "call_method_of_a_child_class")
local m = ChildClass.StaticMethod() local m = ChildClass.StaticMethod()
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
REQUIRE_EQ("number", toString(requireType("m"))); REQUIRE_EQ("number", toString(requireType("m")));
} }
@ -129,7 +129,7 @@ TEST_CASE_FIXTURE(ClassFixture, "call_instance_method")
local result = i:Method() local result = i:Method()
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireType("result"))); CHECK_EQ("string", toString(requireType("result")));
} }
@ -141,7 +141,7 @@ TEST_CASE_FIXTURE(ClassFixture, "call_base_method")
i:BaseMethod(41) i:BaseMethod(41)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(ClassFixture, "cannot_call_unknown_method_of_a_class") 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() 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") 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() 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") 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) makeClone(oopsies)
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm != nullptr); REQUIRE(tm != nullptr);
@ -209,7 +209,7 @@ TEST_CASE_FIXTURE(ClassFixture, "assign_to_prop_of_class")
v.X = 55 v.X = 55
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(ClassFixture, "can_read_prop_of_base_class") 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 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") 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 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") 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"] 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") 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 c["BaseField"] = 444
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(ClassFixture, "cannot_unify_class_instance_with_primitive") 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 v = 444
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(ClassFixture, "warn_when_prop_almost_matches") 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) Vector2.new(0, 0)
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
auto err = get<UnknownPropButFoundLikeProp>(result.errors[0]); auto err = get<UnknownPropButFoundLikeProp>(result.errors[0]);
REQUIRE(err != nullptr); REQUIRE(err != nullptr);
@ -285,7 +285,7 @@ TEST_CASE_FIXTURE(ClassFixture, "classes_can_have_overloaded_operators")
local c = a + b local c = a + b
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Vector2", toString(requireType("c"))); CHECK_EQ("Vector2", toString(requireType("c")));
} }
@ -298,7 +298,7 @@ TEST_CASE_FIXTURE(ClassFixture, "classes_without_overloaded_operators_cannot_be_
local c = a + b local c = a + b
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(ClassFixture, "function_arguments_are_covariant") TEST_CASE_FIXTURE(ClassFixture, "function_arguments_are_covariant")
@ -309,7 +309,7 @@ TEST_CASE_FIXTURE(ClassFixture, "function_arguments_are_covariant")
f(ChildClass.New()) f(ChildClass.New())
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(ClassFixture, "higher_order_function_arguments_are_contravariant") 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 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") 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) end)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(ClassFixture, "higher_order_function_return_type_is_not_contravariant") 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) end)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(ClassFixture, "table_properties_are_invariant") 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 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(6, result.errors[0].location.begin.line);
CHECK_EQ(13, result.errors[1].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 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(6, result.errors[0].location.begin.line);
CHECK_EQ(13, result.errors[1].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) 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 '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])); 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 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 '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])); 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 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[0]));
CHECK_EQ("Value of type 'Vector2?' could be nil", toString(result.errors[1])); 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])); CHECK_EQ("Key 'Z' not found in class 'Vector2'", toString(result.errors[2]));
@ -461,7 +461,7 @@ local b = foo
b(a) 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 -}' CHECK_EQ(R"(Type 'Vector2' could not be converted into '{- X: a, Y: string -}'
caused by: caused by:
Property 'Y' is not compatible. Type 'number' could not be converted into 'string')", 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 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])); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.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") TEST_CASE_FIXTURE(Fixture, "definition_file_loading")
{ {
@ -21,22 +21,22 @@ TEST_CASE_FIXTURE(Fixture, "definition_file_loading")
declare function var(...: any): string declare function var(...: any): string
)"); )");
TypeId globalFooTy = getGlobalBinding(frontend.typeChecker, "foo"); TypeId globalFooTy = getGlobalBinding(frontend.typeChecker, XorStr("foo"));
CHECK_EQ(toString(globalFooTy), "number"); 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)); REQUIRE(bool(globalAsdfTy));
CHECK_EQ(toString(globalAsdfTy->type), "number | string"); CHECK_EQ(toString(globalAsdfTy->type), XorStr("number | string"));
TypeId globalBarTy = getGlobalBinding(frontend.typeChecker, "bar"); TypeId globalBarTy = getGlobalBinding(frontend.typeChecker, XorStr("bar"));
CHECK_EQ(toString(globalBarTy), "(number) -> string"); CHECK_EQ(toString(globalBarTy), XorStr("(number) -> string"));
TypeId globalFoo2Ty = getGlobalBinding(frontend.typeChecker, "foo2"); TypeId globalFoo2Ty = getGlobalBinding(frontend.typeChecker, XorStr("foo2"));
CHECK_EQ(toString(globalFoo2Ty), "number"); 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"( CheckResult result = check(R"(
local x: number = foo + 1 local x: number = foo + 1
@ -45,7 +45,7 @@ TEST_CASE_FIXTURE(Fixture, "definition_file_loading")
z = y 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") 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"( LoadDefinitionFileResult parseFailResult = loadDefinitionFile(typeChecker, typeChecker.globalScope, R"(
declare foo declare foo
)", )",
"@test"); XorStr("@test"));
freeze(typeChecker.globalTypes); freeze(typeChecker.globalTypes);
REQUIRE(!parseFailResult.success); REQUIRE(!parseFailResult.success);
std::optional<Binding> fooTy = tryGetGlobalBinding(typeChecker, "foo"); std::optional<Binding> fooTy = tryGetGlobalBinding(typeChecker, XorStr("foo"));
CHECK(!fooTy.has_value()); CHECK(!fooTy.has_value());
LoadDefinitionFileResult checkFailResult = loadDefinitionFile(typeChecker, typeChecker.globalScope, R"( LoadDefinitionFileResult checkFailResult = loadDefinitionFile(typeChecker, typeChecker.globalScope, R"(
local foo: string = 123 local foo: string = 123
declare bar: typeof(foo) declare bar: typeof(foo)
)", )",
"@test"); XorStr("@test"));
REQUIRE(!checkFailResult.success); REQUIRE(!checkFailResult.success);
std::optional<Binding> barTy = tryGetGlobalBinding(typeChecker, "bar"); std::optional<Binding> barTy = tryGetGlobalBinding(typeChecker, XorStr("bar"));
CHECK(!barTy.has_value()); CHECK(!barTy.has_value());
} }
@ -101,13 +101,13 @@ TEST_CASE_FIXTURE(Fixture, "definition_file_classes")
local inheritedMethod: number = x:inheritance() local inheritedMethod: number = x:inheritance()
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("prop")), "number"); CHECK_EQ(toString(requireType(XorStr("prop")), "number"));
CHECK_EQ(toString(requireType("inheritedProp")), "number"); CHECK_EQ(toString(requireType(XorStr("inheritedProp")), "number"));
CHECK_EQ(toString(requireType("method")), "number"); CHECK_EQ(toString(requireType(XorStr("method")), "number"));
CHECK_EQ(toString(requireType("method2")), "string"); CHECK_EQ(toString(requireType(XorStr("method2")), "string"));
CHECK_EQ(toString(requireType("metamethod")), "Bar"); CHECK_EQ(toString(requireType(XorStr("metamethod")), "Bar"));
CHECK_EQ(toString(requireType("inheritedMethod")), "number"); CHECK_EQ(toString(requireType(XorStr("inheritedMethod")), "number"));
} }
TEST_CASE_FIXTURE(Fixture, "class_definitions_cannot_overload_non_function") 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 X: string
end end
)", )",
"@test"); XorStr("@test"));
freeze(typeChecker.globalTypes); freeze(typeChecker.globalTypes);
REQUIRE(!result.success); REQUIRE(!result.success);
@ -140,7 +140,7 @@ TEST_CASE_FIXTURE(Fixture, "class_definitions_cannot_extend_non_class")
declare class Foo extends NotAClass declare class Foo extends NotAClass
end end
)", )",
"@test"); XorStr("@test"));
freeze(typeChecker.globalTypes); freeze(typeChecker.globalTypes);
REQUIRE(!result.success); REQUIRE(!result.success);
@ -162,7 +162,7 @@ TEST_CASE_FIXTURE(Fixture, "no_cyclic_defined_classes")
declare class Bar extends Foo declare class Bar extends Foo
end end
)", )",
"@test"); XorStr("@test"));
freeze(typeChecker.globalTypes); freeze(typeChecker.globalTypes);
REQUIRE(!result.success); REQUIRE(!result.success);
@ -186,13 +186,13 @@ TEST_CASE_FIXTURE(Fixture, "declaring_generic_functions")
local h = h local h = h
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("x")), "string"); CHECK_EQ(toString(requireType(XorStr("x")), "string"));
CHECK_EQ(toString(requireType("w")), "boolean"); CHECK_EQ(toString(requireType(XorStr("w")), "boolean"));
CHECK_EQ(toString(requireType("u")), "number"); CHECK_EQ(toString(requireType(XorStr("u")), "number"));
CHECK_EQ(toString(requireType("f")), "<a, b>(a, b) -> string"); CHECK_EQ(toString(requireType(XorStr("f")), "<a, b>(a, b) -> string"));
CHECK_EQ(toString(requireType("g")), "<a..., b...>(a...) -> (b...)"); CHECK_EQ(toString(requireType(XorStr("g")), "<a..., b...>(a...) -> (b...)"));
CHECK_EQ(toString(requireType("h")), "<a, b>(a, b) -> (b, a)"); CHECK_EQ(toString(requireType(XorStr("h")), "<a, b>(a, b) -> (b, a)"));
} }
TEST_CASE_FIXTURE(Fixture, "class_definition_function_prop") TEST_CASE_FIXTURE(Fixture, "class_definition_function_prop")
@ -208,8 +208,8 @@ TEST_CASE_FIXTURE(Fixture, "class_definition_function_prop")
local prop = x.X local prop = x.X
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("prop")), "(number) -> string"); CHECK_EQ(toString(requireType(XorStr("prop")), "(number) -> string"));
} }
TEST_CASE_FIXTURE(Fixture, "definition_file_class_function_args") 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 local prop = x.y
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ToStringOptions opts; ToStringOptions opts;
opts.functionTypeArguments = true; opts.functionTypeArguments = true;
CHECK_EQ(toString(requireType("methodRef1"), opts), "(self: Foo, x: number) -> number"); CHECK_EQ(toString(requireType(XorStr("methodRef1"), opts), "(self: Foo, x: number) -> number"));
CHECK_EQ(toString(requireType("methodRef2"), opts), "(self: Foo, x: number, y: string) -> number"); CHECK_EQ(toString(requireType(XorStr("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("prop"), opts), "(a: number, b: string) -> string"));
} }
TEST_CASE_FIXTURE(Fixture, "definitions_documentation_symbols") 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)); REQUIRE(bool(xBinding));
// note: loadDefinition uses the @test package name. // 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)); 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)); 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); ClassTypeVar* barClass = getMutable<ClassTypeVar>(barTy->type);
REQUIRE(bool(barClass)); REQUIRE(bool(barClass));
REQUIRE_EQ(barClass->props.count("prop"), 1); 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)); REQUIRE(bool(yBinding));
CHECK_EQ(yBinding->documentationSymbol, "@test/global/y"); CHECK_EQ(yBinding->documentationSymbol, XorStr("@test/global/y"));
TableTypeVar* yTtv = getMutable<TableTypeVar>(yBinding->typeId); TableTypeVar* yTtv = getMutable<TableTypeVar>(yBinding->typeId);
REQUIRE(bool(yTtv)); REQUIRE(bool(yTtv));
REQUIRE_EQ(yTtv->props.count("x"), 1); 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") 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 export type Evil = string
)"); )");
std::optional<TypeFun> ty = typeChecker.globalScope->lookupType("Evil"); std::optional<TypeFun> ty = typeChecker.globalScope->lookupType(XorStr("Evil"));
REQUIRE(bool(ty)); REQUIRE(bool(ty));
CHECK_EQ(ty->type->documentationSymbol, std::nullopt); CHECK_EQ(ty->type->documentationSymbol, std::nullopt);
} }
@ -306,7 +306,7 @@ declare GetCls: () -> (Cls)
local s : Cls = GetCls() local s : Cls = GetCls()
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_SUITE_END(); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Luau/Scope.h" #include "lluz/Scope.h"
#include <algorithm> #include <algorithm>
@ -9,12 +9,9 @@
#include "doctest.h" #include "doctest.h"
LUAU_FASTFLAG(LuauCheckGenericHOFTypes) using namespace lluz;
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
using namespace Luau; TEST_SUITE_BEGIN(XorStr("GenericsTests"));
TEST_SUITE_BEGIN("GenericsTests");
TEST_CASE_FIXTURE(Fixture, "check_generic_function") TEST_CASE_FIXTURE(Fixture, "check_generic_function")
{ {
@ -25,7 +22,7 @@ TEST_CASE_FIXTURE(Fixture, "check_generic_function")
local x: string = id("hi") local x: string = id("hi")
local y: number = id(37) local y: number = id(37)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "check_generic_local_function") 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 x: string = id("hi")
local y: number = id(37) local y: number = id(37)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "check_generic_typepack_function") 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) local z: number = id(37)
id() id()
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "types_before_typepacks") TEST_CASE_FIXTURE(Fixture, "types_before_typepacks")
@ -56,7 +53,7 @@ TEST_CASE_FIXTURE(Fixture, "types_before_typepacks")
CheckResult result = check(R"( CheckResult result = check(R"(
function f<a,b...>() end function f<a,b...>() end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "local_vars_can_be_polytypes") 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 x: string = f("hi")
local y: number = f(37) 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") 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 x: string = f("hi")
local y: number = f(37) 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") 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 f: (number)->number = id
local g: (string)->string = id local g: (string)->string = id
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "properties_can_be_polytypes") 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 x: string = t.m("hi")
local y: number = t.m(37) 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") 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 local function id<a>(x:a):a return x end
t.m = id t.m = id
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "check_nested_generic_function") 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) local y: number = id(37)
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "check_recursive_generic_function") TEST_CASE_FIXTURE(Fixture, "check_recursive_generic_function")
@ -137,7 +134,7 @@ TEST_CASE_FIXTURE(Fixture, "check_recursive_generic_function")
return x return x
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "check_mutual_generic_functions") TEST_CASE_FIXTURE(Fixture, "check_mutual_generic_functions")
@ -155,7 +152,7 @@ TEST_CASE_FIXTURE(Fixture, "check_mutual_generic_functions")
return x return x
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "generic_functions_in_types") 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 y: string = x.id("hi")
local z: number = x.id(37) local z: number = x.id(37)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "generic_factories") TEST_CASE_FIXTURE(Fixture, "generic_factories")
@ -187,7 +184,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_factories")
local y: string = f.build().id("hi") local y: string = f.build().id("hi")
local z: number = f.build().id(37) local z: number = f.build().id(37)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "factories_of_generics") 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 y: string = x.id("hi")
local z: number = x.id(37) local z: number = x.id(37)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "infer_generic_function") TEST_CASE_FIXTURE(Fixture, "infer_generic_function")
@ -221,9 +218,9 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_function")
local x: string = id("hi") local x: string = id("hi")
local y: number = id(37) 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); const FunctionTypeVar* idFun = get<FunctionTypeVar>(idType);
REQUIRE(idFun); REQUIRE(idFun);
auto [args, varargs] = flatten(idFun->argTypes); auto [args, varargs] = flatten(idFun->argTypes);
@ -244,9 +241,9 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_local_function")
local x: string = id("hi") local x: string = id("hi")
local y: number = id(37) 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); const FunctionTypeVar* idFun = get<FunctionTypeVar>(idType);
REQUIRE(idFun); REQUIRE(idFun);
auto [args, varargs] = flatten(idFun->argTypes); auto [args, varargs] = flatten(idFun->argTypes);
@ -269,12 +266,12 @@ TEST_CASE_FIXTURE(Fixture, "infer_nested_generic_function")
local y: number = id(37) local y: number = id(37)
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "infer_generic_methods") TEST_CASE_FIXTURE(Fixture, "infer_generic_methods")
{ {
ScopedFastFlag sff{"DebugLuauSharedSelf", true}; ScopedFastFlag sff{"DebuglluzSharedSelf", true};
CheckResult result = check(R"( CheckResult result = check(R"(
local x = {} local x = {}
@ -283,7 +280,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_methods")
function x:g(): number return self:id(37) end function x:g(): number return self:id(37) end
)"); )");
// TODO: Quantification should be doing the conversion, not normalization. // 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") TEST_CASE_FIXTURE(Fixture, "calling_self_generic_methods")
@ -297,7 +294,7 @@ TEST_CASE_FIXTURE(Fixture, "calling_self_generic_methods")
end end
)"); )");
// TODO: Should typecheck but currently errors CLI-39916 // TODO: Should typecheck but currently errors CLI-39916
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "infer_generic_property") 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 x: string = t.m("hi")
local y: number = t.m(37) 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") 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") local y: string = g("hi")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "function_results_can_be_polytypes") TEST_CASE_FIXTURE(Fixture, "function_results_can_be_polytypes")
@ -330,7 +327,7 @@ TEST_CASE_FIXTURE(Fixture, "function_results_can_be_polytypes")
return id return id
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "type_parameters_can_be_polytypes") 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 function id<a>(x:a):a return x end
local f: <a>(a)->a = id(id) 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") 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 -- so this assignment should fail
local b: boolean = f(true) local b: boolean = f(true)
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "dont_leak_inferred_generic_types") 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) local y: number = id(37)
end end
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "dont_substitute_bound_types") 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) local x: T = t.m(37)
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "dont_unify_bound_types") 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 a : string = g("not a number", "hi")
local b : number = g(5, 37) local b : number = g(5, 37)
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "mutable_state_polymorphism") 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) // See, e.g. Tofte (1990)
// https://www.sciencedirect.com/science/article/pii/089054019090018D. // https://www.sciencedirect.com/science/article/pii/089054019090018D.
CheckResult result = check(R"( 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 -- so b has value "not a number" at run time
local b: number = f(37) local b: number = f(37)
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "rank_N_types_via_typeof") 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 a: string = f("hi")
local b: number = f(37) local b: number = f(37)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "duplicate_generic_types") TEST_CASE_FIXTURE(Fixture, "duplicate_generic_types")
@ -480,7 +477,7 @@ TEST_CASE_FIXTURE(Fixture, "duplicate_generic_types")
CheckResult result = check(R"( CheckResult result = check(R"(
function f<a,a>(x:a):a return x end 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") TEST_CASE_FIXTURE(Fixture, "duplicate_generic_type_packs")
@ -488,7 +485,7 @@ TEST_CASE_FIXTURE(Fixture, "duplicate_generic_type_packs")
CheckResult result = check(R"( CheckResult result = check(R"(
function f<a...,a...>() end function f<a...,a...>() end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(Fixture, "typepacks_before_types") TEST_CASE_FIXTURE(Fixture, "typepacks_before_types")
@ -496,7 +493,7 @@ TEST_CASE_FIXTURE(Fixture, "typepacks_before_types")
CheckResult result = check(R"( CheckResult result = check(R"(
function f<a...,b>() end function f<a...,b>() end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(Fixture, "variadic_generics") TEST_CASE_FIXTURE(Fixture, "variadic_generics")
@ -507,7 +504,7 @@ TEST_CASE_FIXTURE(Fixture, "variadic_generics")
type F<a> = (...a) -> ...a type F<a> = (...a) -> ...a
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "generic_type_pack_syntax") 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 function f<a...>(...: a...): (a...) return ... end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("f")), "<a...>(a...) -> (a...)"); CHECK_EQ(toString(requireType(XorStr("f")), "<a...>(a...) -> (a...)"));
} }
TEST_CASE_FIXTURE(Fixture, "generic_type_pack_parentheses") 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 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") TEST_CASE_FIXTURE(Fixture, "better_mismatch_error_messages")
@ -541,15 +538,15 @@ TEST_CASE_FIXTURE(Fixture, "better_mismatch_error_messages")
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(2, result); lluz_REQUIRE_ERROR_COUNT(2, result);
SwappedGenericTypeParameter* fErr = get<SwappedGenericTypeParameter>(result.errors[0]); SwappedGenericTypeParameter* fErr = get<SwappedGenericTypeParameter>(result.errors[0]);
REQUIRE(fErr); REQUIRE(fErr);
CHECK_EQ(fErr->name, "T"); CHECK_EQ(fErr->name, XorStr("T"));
CHECK_EQ(fErr->kind, SwappedGenericTypeParameter::Pack); CHECK_EQ(fErr->kind, SwappedGenericTypeParameter::Pack);
SwappedGenericTypeParameter* gErr = get<SwappedGenericTypeParameter>(result.errors[1]); SwappedGenericTypeParameter* gErr = get<SwappedGenericTypeParameter>(result.errors[1]);
REQUIRE(gErr); REQUIRE(gErr);
CHECK_EQ(gErr->name, "T"); CHECK_EQ(gErr->name, XorStr("T"));
CHECK_EQ(gErr->kind, SwappedGenericTypeParameter::Type); 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 function f<a, a...>() end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
DuplicateGenericParameter* err = get<DuplicateGenericParameter>(result.errors[0]); DuplicateGenericParameter* err = get<DuplicateGenericParameter>(result.errors[0]);
REQUIRE(err != nullptr); REQUIRE(err != nullptr);
CHECK_EQ(err->parameterName, "a"); CHECK_EQ(err->parameterName, XorStr("a"));
} }
TEST_CASE_FIXTURE(Fixture, "instantiation_sharing_types") 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 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("x1") != requireType("x2"));
CHECK(requireType("y1") == requireType("y2")); CHECK(requireType("y1") == requireType("y2"));
CHECK(requireType("z1") != requireType("z2")); CHECK(requireType("z1") != requireType("z2"));
@ -596,7 +593,7 @@ TEST_CASE_FIXTURE(Fixture, "quantification_sharing_types")
local z2 = g(true, "hi") local z2 = g(true, "hi")
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK(requireType("z1") == requireType("z2")); CHECK(requireType("z1") == requireType("z2"));
} }
@ -610,7 +607,7 @@ TEST_CASE_FIXTURE(Fixture, "typefuns_sharing_types")
local x2, y2 = o2.x, o2.y local x2, y2 = o2.x, o2.y
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK(requireType("x1") != requireType("x2")); CHECK(requireType("x1") != requireType("x2"));
CHECK(requireType("y1") == requireType("y2")); CHECK(requireType("y1") == requireType("y2"));
} }
@ -630,7 +627,7 @@ exports.nested = nested
return exports return exports
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "instantiated_function_argument_names") 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) f(1, 2, 3)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
auto ty = findTypeAtPosition(Position(3, 0)); auto ty = findTypeAtPosition(Position(3, 0));
REQUIRE(ty); REQUIRE(ty);
ToStringOptions opts; ToStringOptions opts;
opts.functionTypeArguments = true; 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") TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_generic_types")
@ -660,9 +657,9 @@ local c: C
local d: D = 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") TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_generic_pack")
@ -675,16 +672,16 @@ local c: C
local d: D = c local d: D = c
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), 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") TEST_CASE_FIXTURE(BuiltinsFixture, "generic_functions_dont_cache_type_parameters")
{ {
CheckResult result = check(R"( 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, -- This function has a type parameter with the same name as clones,
-- so if we cache type parameter names for functions these get confused. -- so if we cache type parameter names for functions these get confused.
-- function id<Z>(x : Z) : Z -- function id<Z>(x : Z) : Z
@ -701,7 +698,7 @@ function clone<X, Y>(dict: {[X]:Y}): {[X]:Y}
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "generic_functions_should_be_memory_safe") 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 y.a.c = y
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
CHECK_EQ(toString(result.errors[0]), CHECK_EQ(toString(result.errors[0]),
R"(Type 'y' could not be converted into 'T<string>' R"(Type 'y' could not be converted into 'T<string>'
caused by: 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") 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") 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") TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_few")
@ -793,8 +790,8 @@ end
wrapper(test) wrapper(test)
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), R"(Argument count mismatch. Function expects 2 arguments, but only 1 is specified)"); 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") TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_many")
@ -810,8 +807,8 @@ end
wrapper(test2, 1, "", 3) wrapper(test2, 1, "", 3)
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), R"(Argument count mismatch. Function expects 3 arguments, but 4 are specified)"); CHECK_EQ(toString(result.errors[0]), RXorStr("(Argument count mismatch. Function expects 3 arguments, but 4 are specified)"));
} }
TEST_CASE_FIXTURE(Fixture, "generic_function") TEST_CASE_FIXTURE(Fixture, "generic_function")
@ -822,7 +819,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_function")
local b = id(nil) local b = id(nil)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("<a>(a) -> a", toString(requireType("id"))); CHECK_EQ("<a>(a) -> a", toString(requireType("id")));
CHECK_EQ(*typeChecker.numberType, *requireType("a")); CHECK_EQ(*typeChecker.numberType, *requireType("a"));
@ -839,9 +836,9 @@ TEST_CASE_FIXTURE(Fixture, "generic_table_method")
end 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); TableTypeVar* tTable = getMutable<TableTypeVar>(tType);
REQUIRE(tTable != nullptr); REQUIRE(tTable != nullptr);
@ -871,13 +868,13 @@ TEST_CASE_FIXTURE(Fixture, "correctly_instantiate_polymorphic_member_functions")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result); dumpErrors(result);
const TableTypeVar* t = get<TableTypeVar>(requireType("T")); const TableTypeVar* t = get<TableTypeVar>(requireType("T"));
REQUIRE(t != nullptr); REQUIRE(t != nullptr);
std::optional<Property> fooProp = get(t->props, "foo"); std::optional<Property> fooProp = get(t->props, XorStr("foo"));
REQUIRE(bool(fooProp)); REQUIRE(bool(fooProp));
const FunctionTypeVar* foo = get<FunctionTypeVar>(follow(fooProp->type)); const FunctionTypeVar* foo = get<FunctionTypeVar>(follow(fooProp->type));
@ -913,7 +910,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_cyclic_generic_function")
end end
)"); )");
TypeId g = requireType("g"); TypeId g = requireType(XorStr("g"));
const FunctionTypeVar* gFun = get<FunctionTypeVar>(g); const FunctionTypeVar* gFun = get<FunctionTypeVar>(g);
REQUIRE(gFun != nullptr); REQUIRE(gFun != nullptr);
@ -924,7 +921,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_cyclic_generic_function")
const TableTypeVar* argTable = get<TableTypeVar>(arg); const TableTypeVar* argTable = get<TableTypeVar>(arg);
REQUIRE(argTable != nullptr); REQUIRE(argTable != nullptr);
std::optional<Property> methodProp = get(argTable->props, "method"); std::optional<Property> methodProp = get(argTable->props, XorStr("method"));
REQUIRE(bool(methodProp)); REQUIRE(bool(methodProp));
const FunctionTypeVar* methodFunction = get<FunctionTypeVar>(methodProp->type); const FunctionTypeVar* methodFunction = get<FunctionTypeVar>(methodProp->type);
@ -950,7 +947,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_generic_function_in_assignments")
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm); REQUIRE(tm);
@ -970,7 +967,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_generic_function_in_assignments2")
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm); REQUIRE(tm);
@ -987,8 +984,8 @@ type Self<T> = T
local a: Self<Table> local a: Self<Table>
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a")), "Table"); CHECK_EQ(toString(requireType(XorStr("a")), "Table"));
} }
TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_quantifying") 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 | {} 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); REQUIRE(t0);
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("*unknown*", toString(t0->type));
CHECK_EQ("*error-type*", toString(t0->type));
else
CHECK_EQ("<error-type>", toString(t0->type));
auto it = std::find_if(result.errors.begin(), result.errors.end(), [](TypeError& err) { auto it = std::find_if(result.errors.begin(), result.errors.end(), [](TypeError& err) {
return get<OccursCheckFailed>(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) return sum(2, 3, function(a, b) return a + b end)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
result = check(R"( result = check(R"(
local function map<a, b>(arr: {a}, f: (a) -> b) 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) 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"))); REQUIRE_EQ("{boolean}", toString(requireType("r")));
check(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) 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"))); 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) g12(1, 2, function(x, y) return x + y end)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
result = check(R"( result = check(R"(
local g12: (<T>(T, (T) -> T) -> T) & (<T>(T, T, (T, T) -> T) -> T) 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) 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") 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) 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") 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 local c = sumrec(function(x, y, f) return f(x, y) end) -- type binders are not inferred
)"); )");
if (FFlag::LuauCheckGenericHOFTypes) 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 "
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", "parameters",
toString(result.errors[0])); toString(result.errors[0]));
}
} }
TEST_CASE_FIXTURE(Fixture, "substitution_with_bound_table") TEST_CASE_FIXTURE(Fixture, "substitution_with_bound_table")
@ -1126,12 +1112,12 @@ TEST_CASE_FIXTURE(Fixture, "substitution_with_bound_table")
local c: X<B> local c: X<B>
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "apply_type_function_nested_generics1") 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"( CheckResult result = check(R"(
--!strict --!strict
type MyObject = { 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") 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"( CheckResult result = check(R"(
--!strict --!strict
type MyObject = { type MyObject = {
@ -1173,7 +1159,7 @@ type ComplexObject<T> = {
local complex2: ComplexObject<string> = nil local complex2: ComplexObject<string> = nil
local x = complex2.nested.getReturnValue(function(): string local x = complex2.nested.getReturnValue(function(): string
return "" return XorStr("")
end) end)
local y = complex2.nested.getReturnValue(function() local y = complex2.nested.getReturnValue(function()
@ -1181,13 +1167,13 @@ local y = complex2.nested.getReturnValue(function()
end) end)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "quantify_functions_even_if_they_have_an_explicit_generic") TEST_CASE_FIXTURE(Fixture, "quantify_functions_even_if_they_have_an_explicit_generic")
{ {
ScopedFastFlag sff[] = { ScopedFastFlag sff[] = {
{"LuauAlwaysQuantify", true}, {"lluzAlwaysQuantify", true},
}; };
CheckResult result = check(R"( 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"))); 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(); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.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") 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 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("b"), typeChecker.stringType);
CHECK_EQ(requireType("c"), typeChecker.numberType); CHECK_EQ(requireType("c"), typeChecker.numberType);
} }
@ -35,7 +35,7 @@ TEST_CASE_FIXTURE(Fixture, "table_combines")
local c:A & B = {a=10, b="s"} 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") TEST_CASE_FIXTURE(Fixture, "table_combines_missing")
@ -67,7 +67,7 @@ TEST_CASE_FIXTURE(Fixture, "table_extra_ok")
local d:A = c local d:A = c
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "fx_intersection_as_argument") TEST_CASE_FIXTURE(Fixture, "fx_intersection_as_argument")
@ -81,7 +81,7 @@ TEST_CASE_FIXTURE(Fixture, "fx_intersection_as_argument")
local b = g(f) local b = g(f)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "fx_union_as_argument_fails") TEST_CASE_FIXTURE(Fixture, "fx_union_as_argument_fails")
@ -108,7 +108,7 @@ TEST_CASE_FIXTURE(Fixture, "argument_is_intersection")
f(true) 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") 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) 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("a1"), *typeChecker.numberType);
CHECK_EQ(*requireType("a2"), *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 local r = t.x
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
const IntersectionTypeVar* r = get<IntersectionTypeVar>(requireType("r")); const IntersectionTypeVar* r = get<IntersectionTypeVar>(requireType("r"));
REQUIRE(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 local r = t.x.y.z.thing
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string & string", toString(requireType("r"))); 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 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. 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 local r = t.x
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("r"))); 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 local r = t.x
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.anyType, *requireType("r")); CHECK_EQ(*typeChecker.anyType, *requireType("r"));
} }
@ -242,11 +242,11 @@ TEST_CASE_FIXTURE(Fixture, "index_on_an_intersection_type_with_all_parts_missing
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
UnknownProperty* up = get<UnknownProperty>(result.errors[0]); UnknownProperty* up = get<UnknownProperty>(result.errors[0]);
REQUIRE_MESSAGE(up, result.errors[0].data); 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") TEST_CASE_FIXTURE(Fixture, "table_intersection_write")
@ -259,7 +259,7 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write")
a.x = 10 a.x = 10
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
result = check(R"( result = check(R"(
type X = {} type X = {}
@ -269,7 +269,7 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write")
a.x = 10 a.x = 10
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
result = check(R"( result = check(R"(
type X = { x: number } type X = { x: number }
@ -280,7 +280,7 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write")
a.x = 10 a.x = 10
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
result = check(R"( result = check(R"(
type A = { x: {y: number} } type A = { x: {y: number} }
@ -291,7 +291,7 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write")
t.x.y = 40 t.x.y = 40
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed") TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed")
@ -305,11 +305,11 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed")
a.z = 10 a.z = 10
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
if (FFlag::LuauLowerBoundsCalculation) if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ(toString(result.errors[0]), "Cannot add property 'z' to table '{| x: number, y: number |}'"); CHECK_EQ(toString(result.errors[0]), XorStr("Cannot add property 'z' to table '{| x: number, y: number |}'"));
else 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") 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 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' CHECK_EQ(toString(result.errors[0]), R"(Type '(string, number) -> string' could not be converted into '(string) -> string'
caused by: caused by:
Argument count mismatch. Function expects 2 arguments, but only 1 is specified)"); Argument count mismatch. Function expects 2 arguments, but only 1 is specified)");
if (FFlag::LuauLowerBoundsCalculation) if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ(toString(result.errors[1]), "Cannot add property 'z' to table '{| x: (number) -> number, y: (string) -> string |}'"); CHECK_EQ(toString(result.errors[1]), XorStr("Cannot add property 'z' to table '{| x: (number) -> number, y: (string) -> string |}'"));
else else
CHECK_EQ(toString(result.errors[1]), "Cannot add property 'z' to table 'X & Y'"); CHECK_EQ(toString(result.errors[1]), XorStr("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[2]), XorStr("Type 'number' could not be converted into 'string'"));
if (FFlag::LuauLowerBoundsCalculation) if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ(toString(result.errors[3]), "Cannot add property 'w' to table '{| x: (number) -> number, y: (string) -> string |}'"); CHECK_EQ(toString(result.errors[3]), XorStr("Cannot add property 'w' to table '{| x: (number) -> number, y: (string) -> string |}'"));
else 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") 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 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' CHECK_EQ(toString(result.errors[0]), R"(Type '(string, number) -> string' could not be converted into '(string) -> string'
caused by: caused by:
Argument count mismatch. Function expects 2 arguments, but only 1 is specified)"); 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[1]), XorStr("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[2]), XorStr("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[3]), XorStr("Cannot add property 'w' to table 'XY'"));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "table_intersection_setmetatable") TEST_CASE_FIXTURE(BuiltinsFixture, "table_intersection_setmetatable")
@ -376,12 +376,12 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_intersection_setmetatable")
setmetatable(t, {}) setmetatable(t, {})
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "error_detailed_intersection_part") TEST_CASE_FIXTURE(Fixture, "error_detailed_intersection_part")
{ {
ScopedFastFlag flags[] = {{"LuauLowerBoundsCalculation", false}}; ScopedFastFlag flags[] = {{"lluzLowerBoundsCalculation", false}};
CheckResult result = check(R"( CheckResult result = check(R"(
type X = { x: number } type X = { x: number }
@ -393,7 +393,7 @@ type XYZ = X & Y & Z
local a: XYZ = 3 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' CHECK_EQ(toString(result.errors[0]), R"(Type 'number' could not be converted into 'X & Y & Z'
caused by: caused by:
Not all intersection parts are compatible. Type 'number' could not be converted into 'X')"); 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") TEST_CASE_FIXTURE(Fixture, "error_detailed_intersection_all")
{ {
ScopedFastFlag flags[] = {{"LuauLowerBoundsCalculation", false}}; ScopedFastFlag flags[] = {{"lluzLowerBoundsCalculation", false}};
CheckResult result = check(R"( CheckResult result = check(R"(
type X = { x: number } type X = { x: number }
@ -414,8 +414,8 @@ local a: XYZ
local b: number = a local b: 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 'number'; none of the intersection parts are compatible)"); 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") TEST_CASE_FIXTURE(Fixture, "overload_is_not_a_function")
@ -443,7 +443,7 @@ TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_flattenintersection")
until _(_)(_)._ until _(_)(_)._
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_SUITE_END(); 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 "lluz/AstQuery.h"
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Luau/Scope.h" #include "lluz/Scope.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Luau/VisitTypeVar.h" #include "lluz/VisitTypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
LUAU_FASTFLAG(LuauSpecialTypesAsterisked) TEST_SUITE_BEGIN(XorStr("TypeInferLoops"));
TEST_SUITE_BEGIN("TypeInferLoops");
TEST_CASE_FIXTURE(Fixture, "for_loop") TEST_CASE_FIXTURE(Fixture, "for_loop")
{ {
@ -26,7 +24,7 @@ TEST_CASE_FIXTURE(Fixture, "for_loop")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("q")); CHECK_EQ(*typeChecker.numberType, *requireType("q"));
} }
@ -42,7 +40,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("n")); CHECK_EQ(*typeChecker.numberType, *requireType("n"));
CHECK_EQ(*typeChecker.stringType, *requireType("s")); CHECK_EQ(*typeChecker.stringType, *requireType("s"));
@ -59,7 +57,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_next")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("n")); CHECK_EQ(*typeChecker.numberType, *requireType("n"));
CHECK_EQ(*typeChecker.stringType, *requireType("s")); CHECK_EQ(*typeChecker.stringType, *requireType("s"));
@ -75,7 +73,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_with_an_iterator_of_type_any")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "for_in_loop_should_fail_with_non_function_iterator") 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 end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Cannot call non-function string", toString(result.errors[0])); 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_with_a_custom_iterator_should_type_check") 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 end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_error") 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()); CHECK_EQ(2, result.errors.size());
TypeId p = requireType("p"); TypeId p = requireType(XorStr("p"));
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("*unknown*", toString(p));
CHECK_EQ("*error-type*", toString(p));
else
CHECK_EQ("<error-type>", toString(p));
} }
TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_non_function") 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 end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<CannotCallNonFunction>(result.errors[0])); 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 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]); CountMismatch* acm = get<CountMismatch>(result.errors[0]);
REQUIRE(acm); 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 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]); CountMismatch* acm = get<CountMismatch>(result.errors[0]);
REQUIRE(acm); REQUIRE(acm);
@ -244,7 +239,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_with_custom_iterator")
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm); REQUIRE(tm);
@ -261,7 +256,7 @@ TEST_CASE_FIXTURE(Fixture, "while_loop")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("i")); CHECK_EQ(*typeChecker.numberType, *requireType("i"));
} }
@ -275,7 +270,7 @@ TEST_CASE_FIXTURE(Fixture, "repeat_loop")
until true until true
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.stringType, *requireType("i")); CHECK_EQ(*typeChecker.stringType, *requireType("i"));
} }
@ -288,7 +283,7 @@ TEST_CASE_FIXTURE(Fixture, "repeat_loop_condition_binds_to_its_block")
until x 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") 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) 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") 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "properly_infer_iteratee_is_a_free_table") 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "correctly_scope_locals_while") TEST_CASE_FIXTURE(BuiltinsFixture, "correctly_scope_locals_while")
@ -342,11 +337,11 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "correctly_scope_locals_while")
print(a) -- oops! print(a) -- oops!
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
UnknownSymbol* us = get<UnknownSymbol>(result.errors[0]); UnknownSymbol* us = get<UnknownSymbol>(result.errors[0]);
REQUIRE(us); REQUIRE(us);
CHECK_EQ(us->name, "a"); CHECK_EQ(us->name, XorStr("a"));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "ipairs_produces_integral_indices") 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 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"))); REQUIRE_EQ("number", toString(requireType("key")));
} }
@ -394,7 +389,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unreachable_code_after_infinite_loop")
unreachablecodepath(4) 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) reachablecodepath(4)
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
CHECK(get<FunctionExitsWithoutReturning>(result.errors[0])); CHECK(get<FunctionExitsWithoutReturning>(result.errors[0]));
} }
@ -426,7 +421,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unreachable_code_after_infinite_loop")
unreachablecodepath(4) 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) reachablecodepath(4)
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
CHECK(get<FunctionExitsWithoutReturning>(result.errors[0])); CHECK(get<FunctionExitsWithoutReturning>(result.errors[0]));
} }
@ -459,7 +454,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unreachable_code_after_infinite_loop")
unreachablecodepath(4) 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 end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(2, result); lluz_REQUIRE_ERROR_COUNT(2, result);
} }
TEST_CASE_FIXTURE(Fixture, "fuzz_fail_missing_instantitation_follow") TEST_CASE_FIXTURE(Fixture, "fuzz_fail_missing_instantitation_follow")
@ -503,7 +498,7 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_basic")
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(0, result); lluz_REQUIRE_ERROR_COUNT(0, result);
CHECK_EQ(*typeChecker.numberType, *requireType("key")); CHECK_EQ(*typeChecker.numberType, *requireType("key"));
} }
@ -517,11 +512,11 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_trailing_nil")
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(0, result); lluz_REQUIRE_ERROR_COUNT(0, result);
CHECK_EQ(*typeChecker.nilType, *requireType("extra")); 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"( CheckResult result = check(R"(
local t = {} local t = {}
@ -529,24 +524,13 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_no_indexer_strict")
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
GenericError* ge = get<GenericError>(result.errors[0]); GenericError* ge = get<GenericError>(result.errors[0]);
REQUIRE(ge); REQUIRE(ge);
CHECK_EQ("Cannot iterate over a table without indexer", ge->message); 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") TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_iter_metamethod")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
@ -556,7 +540,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_iter_metamethod")
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(0, result); lluz_REQUIRE_ERROR_COUNT(0, result);
} }
TEST_SUITE_END(); 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 "lluz/AstQuery.h"
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Luau/Scope.h" #include "lluz/Scope.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
LUAU_FASTFLAG(LuauSpecialTypesAsterisked) TEST_SUITE_BEGIN(XorStr("TypeInferModules"));
TEST_SUITE_BEGIN("TypeInferModules");
TEST_CASE_FIXTURE(BuiltinsFixture, "require") TEST_CASE_FIXTURE(BuiltinsFixture, "require")
{ {
fileResolver.source["game/A"] = R"( fileResolver.source["game/A"] = R"(
local function hooty(x: number): string local function hooty(x: number): string
return "Hi there!" return XorStr("Hi there!")
end end
return {hooty=hooty} return {hooty=hooty}
@ -33,13 +31,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require")
local i = Hooty.hooty(h) local i = Hooty.hooty(h)
)"; )";
CheckResult aResult = frontend.check("game/A"); CheckResult aResult = frontend.check(XorStr("game/A"));
dumpErrors(aResult); 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); dumpErrors(bResult);
LUAU_REQUIRE_NO_ERRORS(bResult); lluz_REQUIRE_NO_ERRORS(bResult);
ModulePtr b = frontend.moduleResolver.modules["game/B"]; ModulePtr b = frontend.moduleResolver.modules["game/B"];
@ -47,10 +45,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require")
dumpErrors(bResult); dumpErrors(bResult);
std::optional<TypeId> iType = requireType(b, "i"); std::optional<TypeId> iType = requireType(b, XorStr("i"));
REQUIRE_EQ("string", toString(*iType)); 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)); REQUIRE_EQ("number", toString(*hType));
} }
@ -68,13 +66,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require_types")
local h: Hooty.Point local h: Hooty.Point
)"; )";
CheckResult bResult = frontend.check("workspace/B"); CheckResult bResult = frontend.check(XorStr("workspace/B"));
LUAU_REQUIRE_NO_ERRORS(bResult); lluz_REQUIRE_NO_ERRORS(bResult);
ModulePtr b = frontend.moduleResolver.modules["workspace/B"]; ModulePtr b = frontend.moduleResolver.modules["workspace/B"];
REQUIRE(b != nullptr); 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)); 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 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); REQUIRE(bModule != nullptr);
TypeId f = follow(requireType(bModule, "f")); TypeId f = follow(requireType(bModule, "f"));
@ -116,7 +114,7 @@ TEST_CASE_FIXTURE(Fixture, "type_error_of_unknown_qualified_type")
local p: SomeModule.DoesNotExist 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"}})); 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/A"] = sourceA;
fileResolver.source["game/Workspace/B"] = sourceB; fileResolver.source["game/Workspace/B"] = sourceB;
frontend.check("game/Workspace/A"); frontend.check(XorStr("game/Workspace/A"));
frontend.check("game/Workspace/B"); frontend.check(XorStr("game/Workspace/B"));
ModulePtr aModule = frontend.moduleResolver.modules["game/Workspace/A"]; ModulePtr aModule = frontend.moduleResolver.modules["game/Workspace/A"];
ModulePtr bModule = frontend.moduleResolver.modules["game/Workspace/B"]; 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()); REQUIRE_EQ(1, bModule->errors.size());
CHECK_MESSAGE(get<IllegalRequire>(bModule->errors[0]), "Should be IllegalRequire: " << toString(bModule->errors[0])); 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("*unknown*", toString(hootyType));
CHECK_EQ("*error-type*", toString(hootyType));
else
CHECK_EQ("<error-type>", toString(hootyType));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "warn_if_you_try_to_require_a_non_modulescript") 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) 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])); CHECK(get<IllegalRequire>(result.errors[0]));
} }
@ -181,8 +176,8 @@ local a : string = ""
a = tbl.abc.def a = tbl.abc.def
)"; )";
CheckResult result = frontend.check("game/B"); CheckResult result = frontend.check(XorStr("game/B"));
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])); 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) local tbl: string = require(game.A)
)"; )";
CheckResult result = frontend.check("game/B"); CheckResult result = frontend.check(XorStr("game/B"));
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("Type '{| def: number |}' could not be converted into 'string'", toString(result.errors[0])); CHECK_EQ("Type '{| def: number |}' could not be converted into 'string'", toString(result.errors[0]));
} }
@ -219,7 +214,7 @@ end
return m return m
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "custom_require_global") TEST_CASE_FIXTURE(BuiltinsFixture, "custom_require_global")
@ -231,7 +226,7 @@ require = function(a) end
local crash = require(game.A) local crash = require(game.A)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "require_failed_module") TEST_CASE_FIXTURE(BuiltinsFixture, "require_failed_module")
@ -240,20 +235,16 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require_failed_module")
return unfortunately() return unfortunately()
)"; )";
CheckResult aResult = frontend.check("game/A"); CheckResult aResult = frontend.check(XorStr("game/A"));
LUAU_REQUIRE_ERRORS(aResult); lluz_REQUIRE_ERRORS(aResult);
CheckResult result = check(R"( CheckResult result = check(R"(
local ModuleA = require(game.A) local ModuleA = require(game.A)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
std::optional<TypeId> oty = requireType("ModuleA"); std::optional<TypeId> oty = requireType(XorStr("ModuleA"));
CHECK_EQ("*unknown*", toString(*oty));
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(*oty));
else
CHECK_EQ("<error-type>", toString(*oty));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types") TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types")
@ -270,8 +261,8 @@ local x: Type = {}
function x:Destroy(): () end function x:Destroy(): () end
)"; )";
CheckResult result = frontend.check("game/B"); CheckResult result = frontend.check(XorStr("game/B"));
LUAU_REQUIRE_ERROR_COUNT(2, result); lluz_REQUIRE_ERROR_COUNT(2, result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types_2") 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) type Rename = typeof(x.x)
)"; )";
CheckResult result = frontend.check("game/B"); CheckResult result = frontend.check(XorStr("game/B"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types_3") TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types_3")
@ -307,32 +298,8 @@ local x: Type = types
type Rename = typeof(x.x) type Rename = typeof(x.x)
)"; )";
CheckResult result = frontend.check("game/B"); CheckResult result = frontend.check(XorStr("game/B"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_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);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "module_type_conflict") TEST_CASE_FIXTURE(BuiltinsFixture, "module_type_conflict")
@ -354,8 +321,8 @@ local a: A.T = { x = 2 }
local b: B.T = a local b: B.T = a
)"; )";
CheckResult result = frontend.check("game/C"); CheckResult result = frontend.check(XorStr("game/C"));
LUAU_REQUIRE_ERROR_COUNT(1, result); 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' CHECK_EQ(toString(result.errors[0]), R"(Type 'T' from 'game/A' could not be converted into 'T' from 'game/B'
caused by: caused by:
@ -388,29 +355,12 @@ local a: A.T = { x = 2 }
local b: B.T = a local b: B.T = a
)"; )";
CheckResult result = frontend.check("game/D"); CheckResult result = frontend.check(XorStr("game/D"));
LUAU_REQUIRE_ERROR_COUNT(1, result); 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' CHECK_EQ(toString(result.errors[0]), R"(Type 'T' from 'game/B' could not be converted into 'T' from 'game/C'
caused by: caused by:
Property 'x' is not compatible. Type 'number' could not be converted into 'string')"); 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(); 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 "lluz/AstQuery.h"
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Luau/Scope.h" #include "lluz/Scope.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Luau/VisitTypeVar.h" #include "lluz/VisitTypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.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") 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 someTable.Function1() -- Argument count mismatch
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<CountMismatch>(result.errors[0])); 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 someTable.Function2() -- Argument count mismatch
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<CountMismatch>(result.errors[0])); 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) T.method(4)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "method_depends_on_table") 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 function f() x:m() end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "methods_are_topologically_sorted") 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() local a, b = T:foo()
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result); dumpErrors(result);
CHECK_EQ(PrimitiveTypeVar::Number, getPrimitiveType(requireType("a"))); 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() -- foo.fooConn()
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "CheckMethodsOfSealed") TEST_CASE_FIXTURE(Fixture, "CheckMethodsOfSealed")
@ -193,7 +193,7 @@ function x:y(z: number)
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(2, result); lluz_REQUIRE_ERROR_COUNT(2, result);
} }
TEST_CASE_FIXTURE(Fixture, "nonstrict_self_mismatch_tail") TEST_CASE_FIXTURE(Fixture, "nonstrict_self_mismatch_tail")
@ -209,7 +209,7 @@ TEST_CASE_FIXTURE(Fixture, "nonstrict_self_mismatch_tail")
bar(2) 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") 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 n = c:getx()
local nn = c.x local nn = c.x
print(string.format("%d %d", n, nn)) print(string.format(XorStr("%d %d"), n, nn))
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_SUITE_END(); 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 "lluz/AstQuery.h"
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Luau/Scope.h" #include "lluz/Scope.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Luau/VisitTypeVar.h" #include "lluz/VisitTypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.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") TEST_CASE_FIXTURE(Fixture, "or_joins_types")
{ {
@ -21,9 +21,9 @@ TEST_CASE_FIXTURE(Fixture, "or_joins_types")
local s = "a" or 10 local s = "a" or 10
local x:string|number = s local x:string|number = s
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(*requireType("s")), "number | string"); CHECK_EQ(toString(*requireType(XorStr("s")), "number | string"));
CHECK_EQ(toString(*requireType("x")), "number | string"); CHECK_EQ(toString(*requireType(XorStr("x")), "number | string"));
} }
TEST_CASE_FIXTURE(Fixture, "or_joins_types_with_no_extras") 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" local y = x or "s"
)"); )");
CHECK_EQ(0, result.errors.size()); CHECK_EQ(0, result.errors.size());
CHECK_EQ(toString(*requireType("s")), "number | string"); CHECK_EQ(toString(*requireType(XorStr("s")), "number | string"));
CHECK_EQ(toString(*requireType("y")), "number | string"); CHECK_EQ(toString(*requireType(XorStr("y")), "number | string"));
} }
TEST_CASE_FIXTURE(Fixture, "or_joins_types_with_no_superfluous_union") 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 local x:boolean|number = s
)"); )");
CHECK_EQ(0, result.errors.size()); 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") 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 local s = (1/2) > 0.5 and "a" or 10
)"); )");
CHECK_EQ(0, result.errors.size()); 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") 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") local n, s = add(2,"3")
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* functionType = get<FunctionTypeVar>(requireType("add")); 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 local SOLAR_MASS=4*PI * PI
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(requireType("SOLAR_MASS"), typeChecker.numberType); CHECK_EQ(requireType("SOLAR_MASS"), typeChecker.numberType);
} }
@ -117,7 +117,7 @@ TEST_CASE_FIXTURE(Fixture, "primitive_arith_possible_metatable")
local t = add(1,2) local t = add(1,2)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("t"))); CHECK_EQ("any", toString(requireType("t")));
} }
@ -131,7 +131,7 @@ TEST_CASE_FIXTURE(Fixture, "some_primitive_binary_ops")
local c = b - a 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("a")));
CHECK_EQ("number", toString(requireType("b"))); 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' 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("a")));
CHECK_EQ("Vec3", toString(requireType("b"))); 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 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("a")));
CHECK_EQ("Vec3", toString(requireType("b"))); CHECK_EQ("Vec3", toString(requireType("b")));
@ -216,7 +216,7 @@ TEST_CASE_FIXTURE(Fixture, "compare_numbers")
local c = a < b local c = a < b
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "compare_strings") TEST_CASE_FIXTURE(Fixture, "compare_strings")
@ -227,7 +227,7 @@ TEST_CASE_FIXTURE(Fixture, "compare_strings")
local c = a < b 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") 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 local c = a < b
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
GenericError* gen = get<GenericError>(result.errors[0]); 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") 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 local c = a < b
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
GenericError* gen = get<GenericError>(result.errors[0]); GenericError* gen = get<GenericError>(result.errors[0]);
REQUIRE(gen != nullptr); 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") 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 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); 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 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]); auto err = get<GenericError>(result.errors[0]);
REQUIRE(err != nullptr); 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() 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") TEST_CASE_FIXTURE(Fixture, "compound_assign_basic")
@ -336,7 +336,7 @@ TEST_CASE_FIXTURE(Fixture, "compound_assign_basic")
s += 20 s += 20
)"); )");
CHECK_EQ(0, result.errors.size()); 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") TEST_CASE_FIXTURE(Fixture, "compound_assign_mismatch_op")
@ -345,7 +345,7 @@ TEST_CASE_FIXTURE(Fixture, "compound_assign_mismatch_op")
local s = 10 local s = 10
s += true 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}})); 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 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[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}})); 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) local v2: V2 = setmetatable({ x = 3, y = 4 }, VMT)
v1 %= v2 v1 %= v2
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
CHECK_EQ(*tm->wantedType, *requireType("v2")); CHECK_EQ(*tm->wantedType, *requireType("v2"));
@ -413,7 +413,7 @@ function g() return 2; end
(f or g)() (f or g)()
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "CallAndOrOfFunctions") TEST_CASE_FIXTURE(Fixture, "CallAndOrOfFunctions")
@ -425,7 +425,7 @@ local x = false
(x and f or g)() (x and f or g)()
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus") TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus")
@ -452,13 +452,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus")
local c = -bar -- disallowed local c = -bar -- disallowed
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("string", toString(requireType("a"))); CHECK_EQ("string", toString(requireType("a")));
CHECK_EQ("number", toString(requireType("b"))); CHECK_EQ("number", toString(requireType("b")));
GenericError* gen = get<GenericError>(result.errors[0]); 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") TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus_error")
@ -473,13 +473,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus_error")
setmetatable(foo, mt) setmetatable(foo, mt)
mt.__unm = function(val: boolean): string mt.__unm = function(val: boolean): string
return "test" return XorStr("test")
end end
local a = -foo local a = -foo
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("string", toString(requireType("a"))); 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") TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_len_error")
{ {
ScopedFastFlag sff("lluzCheckLenMT", true);
CheckResult result = check(R"( CheckResult result = check(R"(
--!strict --!strict
local foo = { local foo = {
@ -499,13 +501,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_len_error")
setmetatable(foo, mt) setmetatable(foo, mt)
mt.__len = function(val: any): string mt.__len = function(val: any): string
return "test" return XorStr("test")
end end
local a = #foo local a = #foo
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("number", toString(requireType("a"))); 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) 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("b")));
REQUIRE_EQ("boolean", toString(requireType("c"))); 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 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]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE_EQ(*tm->wantedType, *typeChecker.numberType); 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")); CHECK_EQ(*tm2->givenType, *requireType("foo"));
GenericError* gen2 = get<GenericError>(result.errors[1]); 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 // CLI-29033
@ -579,7 +581,7 @@ TEST_CASE_FIXTURE(Fixture, "unknown_type_in_comparison")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "concat_op_on_free_lhs_and_string_rhs") 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 end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<CannotInferBinaryOperation>(result.errors[0])); 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"( CheckResult result = check(R"(
local function f(x) local function f(x)
return "foo" .. x return XorStr("foo") .. x
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("(string) -> string", toString(requireType("f"))); CHECK_EQ("(string) -> string", toString(requireType("f")));
} }
@ -621,7 +623,7 @@ TEST_CASE_FIXTURE(Fixture, "strict_binary_op_where_lhs_unknown")
src += "end"; src += "end";
CheckResult result = check(src); 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])); 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operators") 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 local foo = a < b
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
GenericError* ge = get<GenericError>(result.errors[0]); GenericError* ge = get<GenericError>(result.errors[0]);
REQUIRE(ge); REQUIRE(ge);
@ -662,7 +664,7 @@ TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operato
local foo = a < b local foo = a < b
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
GenericError* ge = get<GenericError>(result.errors[0]); GenericError* ge = get<GenericError>(result.errors[0]);
REQUIRE(ge); REQUIRE(ge);
@ -677,7 +679,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_38355_recursive_union")
_ += _ and _ or _ and _ or _ and _ _ += _ 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])); 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) print(a)
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Unknown global 'a'"); CHECK_EQ(toString(result.errors[0]), XorStr("Unknown global 'a'"));
} }
// In strict mode we no longer generate two errors from lhs // In strict mode we no longer generate two errors from lhs
@ -703,8 +705,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "UnknownGlobalCompoundAssign")
print(a) print(a)
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
CHECK_EQ(toString(result.errors[0]), "Unknown global 'a'"); CHECK_EQ(toString(result.errors[0]), XorStr("Unknown global 'a'"));
} }
// In non-strict mode, compound assignment is not a definition, it's a modification // 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) print(a)
)"); )");
LUAU_REQUIRE_ERROR_COUNT(2, result); lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(toString(result.errors[0]), "Unknown global 'a'"); CHECK_EQ(toString(result.errors[0]), XorStr("Unknown global 'a'"));
} }
} }
@ -728,7 +730,7 @@ local a: number? = nil
local b: number = a or 1 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") TEST_CASE_FIXTURE(Fixture, "strip_nil_from_lhs_or_operator2")
@ -739,7 +741,7 @@ local a: number? = nil
local b: number = a or 1 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") 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 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]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm); REQUIRE(tm);
@ -776,7 +778,7 @@ TEST_CASE_FIXTURE(Fixture, "operator_eq_verifies_types_do_intersect")
return f 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") 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 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 `==`/`~=`. // 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") 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 local u = t and t.x or 5
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("u"))); CHECK_EQ("number", toString(requireType("u")));
} }
@ -812,8 +814,8 @@ TEST_CASE_FIXTURE(Fixture, "infer_any_in_all_modes_when_lhs_is_unknown")
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Unknown type used in + operation; consider adding a type annotation to 'x'"); CHECK_EQ(toString(result.errors[0]), XorStr("Unknown type used in + operation; consider adding a type annotation to 'x'"));
result = check(Mode::Nonstrict, R"( result = check(Mode::Nonstrict, R"(
local function f(x, y) local function f(x, y)
@ -821,7 +823,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_any_in_all_modes_when_lhs_is_unknown")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
// When type inference is unified, we could add an assertion that // When type inference is unified, we could add an assertion that
// the strict and nonstrict types are equivalent. This isn't actually // 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 local v4 = y ~= x
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CheckResult result2 = check(R"( CheckResult result2 = check(R"(
local mm1 = { local mm1 = {
@ -865,30 +867,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "equality_operations_succeed_if_any_union_bra
local v2 = x2 == y2 local v2 = x2 == y2
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result2); lluz_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"); CHECK(toString(result2.errors[0]) == XorStr("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);
} }
TEST_SUITE_END(); 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 "lluz/AstQuery.h"
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Luau/Scope.h" #include "lluz/Scope.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Luau/VisitTypeVar.h" #include "lluz/VisitTypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
LUAU_FASTFLAG(LuauDeduceFindMatchReturnTypes) using namespace lluz;
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
using namespace Luau; TEST_SUITE_BEGIN(XorStr("TypeInferPrimitives"));
TEST_SUITE_BEGIN("TypeInferPrimitives");
TEST_CASE_FIXTURE(Fixture, "cannot_call_primitives") TEST_CASE_FIXTURE(Fixture, "cannot_call_primitives")
{ {
CheckResult result = check("local foo = 5 foo()"); CheckResult result = check(XorStr("local foo = 5 foo()"));
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
REQUIRE(get<CannotCallNonFunction>(result.errors[0]) != nullptr); REQUIRE(get<CannotCallNonFunction>(result.errors[0]) != nullptr);
} }
@ -33,7 +30,7 @@ TEST_CASE_FIXTURE(Fixture, "string_length")
local t = #s local t = #s
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireType("t"))); CHECK_EQ("number", toString(requireType("t")));
} }
@ -44,16 +41,13 @@ TEST_CASE_FIXTURE(Fixture, "string_index")
local t = s[4] local t = s[4]
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
NotATable* nat = get<NotATable>(result.errors[0]); NotATable* nat = get<NotATable>(result.errors[0]);
REQUIRE(nat); REQUIRE(nat);
CHECK_EQ("string", toString(nat->ty)); CHECK_EQ("string", toString(nat->ty));
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("*unknown*", toString(requireType("t")));
CHECK_EQ("*error-type*", toString(requireType("t")));
else
CHECK_EQ("<error-type>", toString(requireType("t")));
} }
TEST_CASE_FIXTURE(Fixture, "string_method") TEST_CASE_FIXTURE(Fixture, "string_method")
@ -86,10 +80,7 @@ TEST_CASE_FIXTURE(Fixture, "string_function_other")
)"); )");
CHECK_EQ(0, result.errors.size()); CHECK_EQ(0, result.errors.size());
if (FFlag::LuauDeduceFindMatchReturnTypes) CHECK_EQ(toString(requireType(XorStr("p")), "string?"));
CHECK_EQ(toString(requireType("p")), "string");
else
CHECK_EQ(toString(requireType("p")), "string?");
} }
TEST_CASE_FIXTURE(Fixture, "CheckMethodsOfNumber") TEST_CASE_FIXTURE(Fixture, "CheckMethodsOfNumber")
@ -101,9 +92,9 @@ function x:y(z: number)
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(2, result); lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(toString(result.errors[0]), "Cannot add method to non-table type 'number'"); CHECK_EQ(toString(result.errors[0]), XorStr("Cannot add method to non-table type 'number'"));
CHECK_EQ(toString(result.errors[1]), "Type 'number' could not be converted into 'string'"); CHECK_EQ(toString(result.errors[1]), XorStr("Type 'number' could not be converted into 'string'"));
} }
TEST_SUITE_END(); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Fixture.h" #include "Fixture.h"
@ -7,11 +7,11 @@
#include <algorithm> #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 // 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. // 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"( const std::string code = R"(
function f(a) function f(a)
if type(a) == "boolean" then if type(a) == XorStr("boolean") then
local a1 = a local a1 = a
elseif a.fn() then elseif a.fn() then
local a2 = a local a2 = a
@ -55,7 +55,7 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_inference_incomplete")
TEST_CASE_FIXTURE(BuiltinsFixture, "xpcall_returns_what_f_returns") TEST_CASE_FIXTURE(BuiltinsFixture, "xpcall_returns_what_f_returns")
{ {
const std::string code = R"( 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"( 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") 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 // 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"( CheckResult result = check(R"(
local function toVertexList(vertices, x, y, ...) local function toVertexList(vertices, x, y, ...)
@ -83,11 +83,11 @@ TEST_CASE_FIXTURE(Fixture, "weirditer_should_not_loop_forever")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
// This should also generate an OccursCheckFailed error too, like the above toVertexList snippet. // 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") TEST_CASE_FIXTURE(Fixture, "it_should_be_agnostic_of_actual_size")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
@ -99,7 +99,7 @@ TEST_CASE_FIXTURE(Fixture, "it_should_be_agnostic_of_actual_size")
f(3, 2, 1, 0) 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. // 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 b = 1
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm); REQUIRE(tm);
@ -121,7 +121,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_constrains_free_type_into_free_
CHECK_EQ("number", toString(tm->givenType)); 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") TEST_CASE_FIXTURE(Fixture, "while_body_are_also_refined")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
@ -137,7 +137,7 @@ TEST_CASE_FIXTURE(Fixture, "while_body_are_also_refined")
end 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])); 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 local a = tab2 == tab
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
GenericError* ge = get<GenericError>(result.errors[0]); GenericError* ge = get<GenericError>(result.errors[0]);
REQUIRE(ge); REQUIRE(ge);
@ -175,7 +175,7 @@ TEST_CASE_FIXTURE(Fixture, "operator_eq_completely_incompatible")
local r2 = b == a local r2 = b == a
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
// Belongs in TypeInfer.refinements.test.cpp. // Belongs in TypeInfer.refinements.test.cpp.
@ -192,13 +192,13 @@ TEST_CASE_FIXTURE(Fixture, "lvalue_equals_another_lvalue_with_no_overlap")
end 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, 33})), XorStr("string")); // a == b
CHECK_EQ(toString(requireTypeAtPosition({3, 36})), "boolean?"); // 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, 33})), XorStr("string")); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({5, 36})), "boolean?"); // a ~= b CHECK_EQ(toString(requireTypeAtPosition({5, 36})), XorStr("boolean?")); // a ~= b
} }
// Also belongs in TypeInfer.refinements.test.cpp. // Also belongs in TypeInfer.refinements.test.cpp.
@ -217,7 +217,7 @@ TEST_CASE_FIXTURE(Fixture, "discriminate_from_x_not_equal_to_nil")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("{| x: string, y: number |}", toString(requireTypeAtPosition({5, 28}))); 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}))); 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 sffi{"lluzTarjanChildLimit", 1};
ScopedFastInt sffi2{"LuauTypeInferIterationLimit", 1}; ScopedFastInt sffi2{"lluzTypeInferIterationLimit", 1};
CheckResult result = check(R"LUA( CheckResult result = check(R"LUA(
local Result local Result
@ -259,7 +259,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "bail_early_if_unification_is_too_complicated
if (it == result.errors.end()) if (it == result.errors.end())
{ {
dumpErrors(result); 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! // TODO: this should error!
// This should be fixed by replacing generic tables by generics with type bounds. // 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") TEST_CASE_FIXTURE(Fixture, "do_not_ice_when_trying_to_pick_first_of_generic_type_pack")
{ {
ScopedFastFlag sff[]{ 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. // 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 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("f")));
CHECK_EQ("() -> ()", toString(requireType("g"))); CHECK_EQ("() -> ()", toString(requireType("g")));
@ -340,27 +340,13 @@ TEST_CASE_FIXTURE(Fixture, "specialization_binds_with_prototypes_too_early")
local s2s: (string) -> string = id local s2s: (string) -> string = id
)"); )");
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_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.
} }
TEST_CASE_FIXTURE(Fixture, "weird_fail_to_unify_variadic_pack") TEST_CASE_FIXTURE(Fixture, "weird_fail_to_unify_variadic_pack")
{ {
ScopedFastFlag sff[] = { ScopedFastFlag sff[] = {
{"LuauLowerBoundsCalculation", false}, {"lluzLowerBoundsCalculation", false},
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
@ -369,13 +355,13 @@ TEST_CASE_FIXTURE(Fixture, "weird_fail_to_unify_variadic_pack")
local g = function(...) return f(...) 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, "lower_bounds_calculation_is_too_permissive_with_overloaded_higher_order_functions") TEST_CASE_FIXTURE(Fixture, "lower_bounds_calculation_is_too_permissive_with_overloaded_higher_order_functions")
{ {
ScopedFastFlag sff[] = { ScopedFastFlag sff[] = {
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
@ -385,7 +371,7 @@ TEST_CASE_FIXTURE(Fixture, "lower_bounds_calculation_is_too_permissive_with_over
end 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) // 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. // 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") TEST_CASE_FIXTURE(Fixture, "normalization_fails_on_certain_kinds_of_cyclic_tables")
{ {
#if defined(_DEBUG) || defined(_NOOPT) #if defined(_DEBUG) || defined(_NOOPT)
ScopedFastInt sfi("LuauNormalizeIterationLimit", 500); ScopedFastInt sfi("lluzNormalizeIterationLimit", 500);
#endif #endif
ScopedFastFlag flags[] = { ScopedFastFlag flags[] = {
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
}; };
// We use a function and inferred parameter types to prevent intermediate normalizations from being performed. // 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 end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK(nullptr != get<NormalizationTooComplex>(result.errors[0])); 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) 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])); 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("boolean", toString(requireType("ok")));
// CHECK_EQ("any", toString(requireType("res"))); // 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) local ok, res = pcall(f)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("boolean", toString(requireType("ok"))); CHECK_EQ("boolean", toString(requireType("ok")));
CHECK_EQ("number", toString(requireType("res"))); CHECK_EQ("number", toString(requireType("res")));
// CHECK_EQ("any", 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) 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("boolean", toString(requireType("ok")));
CHECK_EQ("number", toString(requireType("res"))); CHECK_EQ("number", toString(requireType("res")));
// CHECK_EQ("any", 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") TEST_CASE_FIXTURE(Fixture, "constrained_is_level_dependent")
{ {
ScopedFastFlag sff[]{ ScopedFastFlag sff[]{
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
{"LuauNormalizeFlagIsConservative", true}, {"lluzNormalizeFlagIsConservative", true},
{"LuauQuantifyConstrained", true}, {"lluzQuantifyConstrained", true},
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
@ -508,25 +494,14 @@ TEST_CASE_FIXTURE(Fixture, "constrained_is_level_dependent")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
// TODO: We're missing generics b... // 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"))); 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") 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"( CheckResult result = check(R"(
local T = {} local T = {}
@ -542,7 +517,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "greedy_inference_with_shared_self_triggers_f
end 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])); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Normalize.h" #include "lluz/Normalize.h"
#include "Luau/Scope.h" #include "lluz/Scope.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
LUAU_FASTFLAG(LuauLowerBoundsCalculation) lluz_FASTFLAG(LluLowerBoundsCalculation)
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
using namespace Luau; using namespace lluz;
namespace namespace
{ {
@ -20,8 +19,8 @@ std::optional<WithPredicate<TypePackId>> magicFunctionInstanceIsA(
if (expr.args.size != 1) if (expr.args.size != 1)
return std::nullopt; return std::nullopt;
auto index = expr.func->as<Luau::AstExprIndexName>(); auto index = expr.func->as<lluz::AstExprIndexName>();
auto str = expr.args.data[0]->as<Luau::AstExprConstantString>(); auto str = expr.args.data[0]->as<lluz::AstExprConstantString>();
if (!index || !str) if (!index || !str)
return std::nullopt; return std::nullopt;
@ -86,7 +85,7 @@ struct RefinementClassFixture : Fixture
}; };
} // namespace } // namespace
TEST_SUITE_BEGIN("RefinementTest"); TEST_SUITE_BEGIN(XorStr("RefinementTest"));
TEST_CASE_FIXTURE(Fixture, "is_truthy_constraint") TEST_CASE_FIXTURE(Fixture, "is_truthy_constraint")
{ {
@ -100,7 +99,7 @@ TEST_CASE_FIXTURE(Fixture, "is_truthy_constraint")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireTypeAtPosition({3, 26}))); CHECK_EQ("string", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("nil", toString(requireTypeAtPosition({5, 26}))); CHECK_EQ("nil", toString(requireTypeAtPosition({5, 26})));
@ -118,7 +117,7 @@ TEST_CASE_FIXTURE(Fixture, "invert_is_truthy_constraint")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("nil", toString(requireTypeAtPosition({3, 26}))); CHECK_EQ("nil", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("string", toString(requireTypeAtPosition({5, 26}))); CHECK_EQ("string", toString(requireTypeAtPosition({5, 26})));
@ -136,7 +135,7 @@ TEST_CASE_FIXTURE(Fixture, "parenthesized_expressions_are_followed_through")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("nil", toString(requireTypeAtPosition({3, 26}))); CHECK_EQ("nil", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("string", toString(requireTypeAtPosition({5, 26}))); CHECK_EQ("string", toString(requireTypeAtPosition({5, 26})));
@ -156,7 +155,7 @@ TEST_CASE_FIXTURE(Fixture, "and_constraint")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireTypeAtPosition({3, 26}))); CHECK_EQ("string", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("number", toString(requireTypeAtPosition({4, 26}))); CHECK_EQ("number", toString(requireTypeAtPosition({4, 26})));
@ -179,7 +178,7 @@ TEST_CASE_FIXTURE(Fixture, "not_and_constraint")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string?", toString(requireTypeAtPosition({3, 26}))); CHECK_EQ("string?", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("number?", toString(requireTypeAtPosition({4, 26}))); CHECK_EQ("number?", toString(requireTypeAtPosition({4, 26})));
@ -202,7 +201,7 @@ TEST_CASE_FIXTURE(Fixture, "or_predicate_with_truthy_predicates")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string?", toString(requireTypeAtPosition({3, 26}))); CHECK_EQ("string?", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("number?", toString(requireTypeAtPosition({4, 26}))); CHECK_EQ("number?", toString(requireTypeAtPosition({4, 26})));
@ -222,7 +221,7 @@ TEST_CASE_FIXTURE(Fixture, "type_assertion_expr_carry_its_constraints")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireTypeAtPosition({3, 26}))); CHECK_EQ("number", toString(requireTypeAtPosition({3, 26})));
CHECK_EQ("string", toString(requireTypeAtPosition({4, 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"( CheckResult result = check(R"(
function f(s: any) function f(s: any)
if type(s) == "number" then if type(s) == XorStr("number") then
local n = s local n = s
end end
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireTypeAtPosition({3, 26}))); CHECK_EQ("number", toString(requireTypeAtPosition({3, 26})));
} }
@ -247,11 +246,11 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typeguard_in_assert_position")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
local a local a
assert(type(a) == "number") assert(type(a) == XorStr("number"))
local b = a local b = a
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
REQUIRE_EQ("number", toString(requireType("b"))); 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 type string = number
local foo: string = 1 local foo: string = 1
if type(foo) == "string" then if type(foo) == XorStr("string") then
local bar: ActuallyString = foo local bar: ActuallyString = foo
local baz: boolean = foo local baz: boolean = foo
end end
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("never", toString(requireTypeAtPosition({8, 44}))); CHECK_EQ("*unknown*", toString(requireTypeAtPosition({8, 44})));
CHECK_EQ("never", toString(requireTypeAtPosition({9, 38}))); CHECK_EQ("*unknown*", toString(requireTypeAtPosition({9, 38})));
} }
TEST_CASE_FIXTURE(Fixture, "call_a_more_specific_function_using_typeguard") 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 end
local function g(x: any) local function g(x: any)
if type(x) == "string" then if type(x) == XorStr("string") then
f(x) f(x)
end end
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])); 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") 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. // For instance, getting a value out of the indexer and checking whether the value exists is not an error.
CheckResult result = check(R"( CheckResult result = check(R"(
local t: {string} = {"a", "b", "c"} local t: {string} = {"a", "b", "c"}
@ -309,7 +308,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "impossible_type_narrow_is_not_an_error")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "truthy_constraint_on_properties") TEST_CASE_FIXTURE(Fixture, "truthy_constraint_on_properties")
@ -324,7 +323,7 @@ TEST_CASE_FIXTURE(Fixture, "truthy_constraint_on_properties")
local bar = t.x local bar = t.x
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number?", toString(requireType("bar"))); CHECK_EQ("number?", toString(requireType("bar")));
} }
@ -338,7 +337,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_on_a_refined_property")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "assert_non_binary_expressions_actually_resolve_constraints") 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 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") 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 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 |}' CHECK_EQ(R"(Type '{| x: number? |}' could not be converted into '{| x: number |}'
caused by: caused by:
Property 'x' is not compatible. Type 'number?' could not be converted into 'number')", 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 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, 33})), XorStr("(number | string)?")); // a == b
CHECK_EQ(toString(requireTypeAtPosition({3, 36})), "boolean?"); // 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, 33})), XorStr("(number | string)?")); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({5, 36})), "boolean?"); // a ~= b CHECK_EQ(toString(requireTypeAtPosition({5, 36})), XorStr("boolean?")); // a ~= b
} }
TEST_CASE_FIXTURE(Fixture, "lvalue_is_equal_to_a_term") 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 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({3, 28})), XorStr("(number | string)?")); // a == 1
CHECK_EQ(toString(requireTypeAtPosition({5, 28})), "(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") 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 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({3, 28})), RXorStr("("hello")")); // a == XorStr("hello")
CHECK_EQ(toString(requireTypeAtPosition({5, 28})), "(number | string)?"); // a ~= "hello" CHECK_EQ(toString(requireTypeAtPosition({5, 28})), XorStr("(number | string)?")); // a ~= "hello"
} }
TEST_CASE_FIXTURE(Fixture, "lvalue_is_not_nil") TEST_CASE_FIXTURE(Fixture, "lvalue_is_not_nil")
@ -438,10 +437,10 @@ TEST_CASE_FIXTURE(Fixture, "lvalue_is_not_nil")
end 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({3, 28})), XorStr("number | string")); // a ~= nil
CHECK_EQ(toString(requireTypeAtPosition({5, 28})), "(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") 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 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, 33})), XorStr("a")); // a == b
CHECK_EQ(toString(requireTypeAtPosition({3, 36})), "string?"); // 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") 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 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, 33})), XorStr("any")); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({3, 36})), "{| x: number |}?"); // a ~= b CHECK_EQ(toString(requireTypeAtPosition({3, 36})), XorStr("{| x: number |}?")); // a ~= b
} }
TEST_CASE_FIXTURE(Fixture, "string_not_equal_to_string_or_nil") 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 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, 29})), XorStr("string")); // a ~= b
CHECK_EQ(toString(requireTypeAtPosition({6, 32})), "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, 29})), XorStr("string")); // a == b
CHECK_EQ(toString(requireTypeAtPosition({8, 32})), "string?"); // a == b CHECK_EQ(toString(requireTypeAtPosition({8, 32})), XorStr("string?")); // a == b
} }
TEST_CASE_FIXTURE(Fixture, "narrow_property_of_a_bounded_variable") 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "type_narrow_to_vector") TEST_CASE_FIXTURE(Fixture, "type_narrow_to_vector")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
local function f(x) local function f(x)
if type(x) == "vector" then if type(x) == XorStr("vector") then
local foo = x local foo = x
end end
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("*unknown*", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("*error-type*", toString(requireTypeAtPosition({3, 28})));
else
CHECK_EQ("<error-type>", toString(requireTypeAtPosition({3, 28})));
} }
TEST_CASE_FIXTURE(Fixture, "nonoptional_type_can_narrow_to_nil_if_sense_is_true") 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"( CheckResult result = check(R"(
local t = {"hello"} local t = {"hello"}
local v = t[2] local v = t[2]
if type(v) == "nil" then if type(v) == XorStr("nil") then
local foo = v local foo = v
else else
local foo = v local foo = v
@ -551,12 +547,12 @@ TEST_CASE_FIXTURE(Fixture, "nonoptional_type_can_narrow_to_nil_if_sense_is_true"
end 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("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" 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("boolean | number", toString(requireTypeAtPosition({3, 28}))); // type(x) ~= "string" 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") TEST_CASE_FIXTURE(Fixture, "typeguard_narrows_for_table")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
local function f(x: string | {x: number} | {y: boolean}) local function f(x: string | {x: number} | {y: boolean})
if type(x) == "table" then if type(x) == XorStr("table") then
local foo = x local foo = x
else else
local foo = x local foo = x
@ -590,9 +586,9 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_narrows_for_table")
end 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" 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"( CheckResult result = check(R"(
local function weird(x: string | ((number) -> string)) local function weird(x: string | ((number) -> string))
if type(x) == "function" then if type(x) == XorStr("function") then
local foo = x local foo = x
else else
local foo = x local foo = x
@ -608,9 +604,9 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_narrows_for_functions")
end 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" 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"( CheckResult result = check(R"(
type XYCoord = {x: number} & {y: number} type XYCoord = {x: number} & {y: number}
local function f(t: XYCoord?) local function f(t: XYCoord?)
if type(t) == "table" then if type(t) == XorStr("table") then
local foo = t local foo = t
else else
local foo = t local foo = t
@ -627,9 +623,9 @@ TEST_CASE_FIXTURE(Fixture, "type_guard_can_filter_for_intersection_of_tables")
end 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}))); CHECK_EQ("{| x: number, y: number |}", toString(requireTypeAtPosition({4, 28})));
else else
CHECK_EQ("{| x: number |} & {| y: number |}", toString(requireTypeAtPosition({4, 28}))); 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"( CheckResult result = check(R"(
type SomeOverloadedFunction = ((number) -> string) & ((string) -> number) type SomeOverloadedFunction = ((number) -> string) & ((string) -> number)
local function f(g: SomeOverloadedFunction?) local function f(g: SomeOverloadedFunction?)
if type(g) == "function" then if type(g) == XorStr("function") then
local foo = g local foo = g
else else
local foo = g local foo = g
@ -649,13 +645,13 @@ TEST_CASE_FIXTURE(Fixture, "type_guard_can_filter_for_overloaded_function")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("((number) -> string) & ((string) -> number)", toString(requireTypeAtPosition({4, 28}))); CHECK_EQ("((number) -> string) & ((string) -> number)", toString(requireTypeAtPosition({4, 28})));
CHECK_EQ("nil", toString(requireTypeAtPosition({6, 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"( CheckResult result = check(R"(
local function f(t: {x: number}) local function f(t: {x: number})
@ -668,9 +664,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_guard_narrowed_into_nothingness")
end 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") TEST_CASE_FIXTURE(Fixture, "not_a_or_not_b")
@ -684,7 +680,7 @@ TEST_CASE_FIXTURE(Fixture, "not_a_or_not_b")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number?", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("number?", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("number?", toString(requireTypeAtPosition({4, 28}))); CHECK_EQ("number?", toString(requireTypeAtPosition({4, 28})));
@ -701,7 +697,7 @@ TEST_CASE_FIXTURE(Fixture, "not_a_or_not_b2")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number?", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("number?", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("number?", toString(requireTypeAtPosition({4, 28}))); CHECK_EQ("number?", toString(requireTypeAtPosition({4, 28})));
@ -718,7 +714,7 @@ TEST_CASE_FIXTURE(Fixture, "not_a_and_not_b")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("nil", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("nil", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("nil", toString(requireTypeAtPosition({4, 28}))); CHECK_EQ("nil", toString(requireTypeAtPosition({4, 28})));
@ -735,7 +731,7 @@ TEST_CASE_FIXTURE(Fixture, "not_a_and_not_b2")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("nil", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("nil", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("nil", toString(requireTypeAtPosition({4, 28}))); CHECK_EQ("nil", toString(requireTypeAtPosition({4, 28})));
@ -745,13 +741,13 @@ TEST_CASE_FIXTURE(Fixture, "either_number_or_string")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
local function f(x: any) 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 local foo = x
end end
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number | string", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("number | string", toString(requireTypeAtPosition({3, 28})));
} }
@ -766,7 +762,7 @@ TEST_CASE_FIXTURE(Fixture, "not_t_or_some_prop_of_t")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("{| x: boolean |}?", toString(requireTypeAtPosition({3, 28}))); 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)? local a: (number | string)?
assert(a) assert(a)
local b = a local b = a
assert(type(a) == "number") assert(type(a) == XorStr("number"))
local c = a local c = a
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number | string", toString(requireTypeAtPosition({3, 18}))); CHECK_EQ("number | string", toString(requireTypeAtPosition({3, 18})));
CHECK_EQ("number", toString(requireTypeAtPosition({5, 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") 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"( CheckResult result = check(R"(
local function f(b: string | { x: string }, a) local function f(b: string | { x: string }, a)
assert(type(a) == "string") assert(type(a) == XorStr("string"))
assert(type(b) == "string" or type(b) == "table") assert(type(b) == XorStr("string") or type(b) == XorStr("table"))
if type(b) == "string" then if type(b) == XorStr("string") then
local foo = b local foo = b
end end
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireTypeAtPosition({6, 28}))); 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("boolean", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("boolean", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("number | string", toString(requireTypeAtPosition({5, 28}))); CHECK_EQ("number | string", toString(requireTypeAtPosition({5, 28})));
@ -832,7 +828,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "is_truthy_constraint_ifelse_expression")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireTypeAtPosition({2, 29}))); CHECK_EQ("string", toString(requireTypeAtPosition({2, 29})));
CHECK_EQ("nil", toString(requireTypeAtPosition({2, 45}))); CHECK_EQ("nil", toString(requireTypeAtPosition({2, 45})));
@ -846,7 +842,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "invert_is_truthy_constraint_ifelse_expressio
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("nil", toString(requireTypeAtPosition({2, 42}))); CHECK_EQ("nil", toString(requireTypeAtPosition({2, 42})));
CHECK_EQ("string", toString(requireTypeAtPosition({2, 50}))); CHECK_EQ("string", toString(requireTypeAtPosition({2, 50})));
@ -860,11 +856,11 @@ TEST_CASE_FIXTURE(Fixture, "type_comparison_ifelse_expression")
end end
function f(v:any) 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireTypeAtPosition({6, 49}))); CHECK_EQ("number", toString(requireTypeAtPosition({6, 49})));
CHECK_EQ("any", toString(requireTypeAtPosition({6, 66}))); 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)) 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])); 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} type T = {x: string | number}
local t: T? = {x = "hi"} local t: T? = {x = "hi"}
if t then if t then
if type(t.x) == "string" then if type(t.x) == XorStr("string") then
local foo = t.x local foo = t.x
end end
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireTypeAtPosition({5, 30}))); CHECK_EQ("string", toString(requireTypeAtPosition({5, 30})));
} }
@ -913,7 +909,7 @@ TEST_CASE_FIXTURE(Fixture, "correctly_lookup_property_whose_base_was_previously_
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number", toString(requireTypeAtPosition({5, 32}))); CHECK_EQ("number", toString(requireTypeAtPosition({5, 32})));
} }
@ -929,12 +925,12 @@ TEST_CASE_FIXTURE(Fixture, "apply_refinements_on_astexprindexexpr_whose_subscrip
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "discriminate_from_truthiness_of_x") TEST_CASE_FIXTURE(Fixture, "discriminate_from_truthiness_of_x")
{ {
ScopedFastFlag sff{"LuauFalsyPredicateReturnsNilInstead", true}; ScopedFastFlag sff{"lluzFalsyPredicateReturnsNilInstead", true};
CheckResult result = check(R"( CheckResult result = check(R"(
type T = {tag: "missing", x: nil} | {tag: "exists", x: string} type T = {tag: "missing", x: nil} | {tag: "exists", x: string}
@ -948,7 +944,7 @@ TEST_CASE_FIXTURE(Fixture, "discriminate_from_truthiness_of_x")
end 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 |})", toString(requireTypeAtPosition({5, 28})));
CHECK_EQ(R"({| tag: "exists", x: string |} | {| tag: "missing", x: nil |})", toString(requireTypeAtPosition({7, 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 type Animal = Cat | Dog
local function f(animal: Animal) local function f(animal: Animal)
if animal.tag == "Cat" then if animal.tag == XorStr("Cat") then
local cat: Cat = animal local cat: Cat = animal
elseif animal.tag == "Dog" then elseif animal.tag == XorStr("Dog") then
local dog: Dog = animal local dog: Dog = animal
end end
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Cat", toString(requireTypeAtPosition({7, 33}))); CHECK_EQ("Cat", toString(requireTypeAtPosition({7, 33})));
CHECK_EQ("Dog", toString(requireTypeAtPosition({9, 33}))); CHECK_EQ("Dog", toString(requireTypeAtPosition({9, 33})));
@ -984,7 +980,7 @@ TEST_CASE_FIXTURE(Fixture, "and_or_peephole_refinement")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "narrow_boolean_to_true_or_false") 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 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") 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 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") 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(RefinementClassFixture, "discriminate_from_isa_of_x") TEST_CASE_FIXTURE(RefinementClassFixture, "discriminate_from_isa_of_x")
@ -1052,7 +1048,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "discriminate_from_isa_of_x")
end 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: "Part", x: Part |})", toString(requireTypeAtPosition({5, 28})));
CHECK_EQ(R"({| tag: "Folder", x: Folder |})", toString(requireTypeAtPosition({7, 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 function f(vec)
local X, Y, Z = vec.X, vec.Y, vec.Z local X, Y, Z = vec.X, vec.Y, vec.Z
if type(vec) == "vector" then if type(vec) == XorStr("vector") then
local foo = vec local foo = vec
elseif typeof(vec) == "Instance" then elseif typeof(vec) == XorStr("Instance") then
local foo = vec local foo = vec
else else
local foo = vec local foo = vec
@ -1074,11 +1070,11 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "typeguard_cast_free_table_to_vector")
end 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" 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"( CheckResult result = check(R"(
local function f(x: Instance | Vector3) local function f(x: Instance | Vector3)
if typeof(x) == "Vector3" then if typeof(x) == XorStr("Vector3") then
local foo = x local foo = x
else else
local foo = x local foo = x
@ -1095,7 +1091,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "typeguard_cast_instance_or_vector3_to
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Vector3", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("Vector3", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("Instance", toString(requireTypeAtPosition({5, 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"( CheckResult result = check(R"(
local function f(x: string | number | Instance | Vector3) local function f(x: string | number | Instance | Vector3)
if type(x) == "userdata" then if type(x) == XorStr("userdata") then
local foo = x local foo = x
else else
local foo = x local foo = x
@ -1113,7 +1109,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "type_narrow_for_all_the_userdata")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Instance | Vector3", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("Instance | Vector3", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("number | string", toString(requireTypeAtPosition({5, 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"( CheckResult result = check(R"(
local function f(x: Part | Folder | string) local function f(x: Part | Folder | string)
if typeof(x) == "Instance" then if typeof(x) == XorStr("Instance") then
local foo = x local foo = x
else else
local foo = x local foo = x
@ -1131,7 +1127,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "eliminate_subclasses_of_instance")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Folder | Part", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("Folder | Part", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("string", toString(requireTypeAtPosition({5, 28}))); CHECK_EQ("string", toString(requireTypeAtPosition({5, 28})));
@ -1141,7 +1137,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "narrow_this_large_union")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
local function f(x: Part | Folder | Instance | string | Vector3 | any) local function f(x: Part | Folder | Instance | string | Vector3 | any)
if typeof(x) == "Instance" then if typeof(x) == XorStr("Instance") then
local foo = x local foo = x
else else
local foo = x local foo = x
@ -1149,7 +1145,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "narrow_this_large_union")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Folder | Instance | Part", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("Folder | Instance | Part", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("Vector3 | any | string", toString(requireTypeAtPosition({5, 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 --!nonstrict
local function f(x) 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 local foo = x
elseif typeof(x) == "table" then elseif typeof(x) == XorStr("table") then
local foo = x local foo = x
end end
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Folder", toString(requireTypeAtPosition({5, 28}))); CHECK_EQ("Folder", toString(requireTypeAtPosition({5, 28})));
CHECK_EQ("any", toString(requireTypeAtPosition({7, 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("Folder | string", toString(requireTypeAtPosition({3, 28}))); CHECK_EQ("Folder | string", toString(requireTypeAtPosition({3, 28})));
CHECK_EQ("Part", toString(requireTypeAtPosition({5, 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"( CheckResult result = check(R"(
function f(a) function f(a)
if type(a) == "boolean" then if type(a) == XorStr("boolean") then
local a1 = a local a1 = a
elseif a.fn() then elseif a.fn() then
local a2 = a local a2 = a
@ -1207,30 +1203,12 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_doesnt_leak_to_elseif")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_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})));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "falsiness_of_TruthyPredicate_narrows_into_nil") TEST_CASE_FIXTURE(BuiltinsFixture, "falsiness_of_TruthyPredicate_narrows_into_nil")
{ {
ScopedFastFlag sff{"LuauFalsyPredicateReturnsNilInstead", true}; ScopedFastFlag sff{"lluzFalsyPredicateReturnsNilInstead", true};
CheckResult result = check(R"( CheckResult result = check(R"(
local function f(t: {number}) local function f(t: {number})
@ -1243,25 +1221,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "falsiness_of_TruthyPredicate_narrows_into_ni
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("nil", toString(requireTypeAtPosition({4, 28}))); CHECK_EQ("nil", toString(requireTypeAtPosition({4, 28})));
CHECK_EQ("number", toString(requireTypeAtPosition({6, 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(); 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 "Fixture.h"
#include "doctest.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") TEST_CASE_FIXTURE(Fixture, "bool_singletons")
{ {
@ -16,7 +16,7 @@ TEST_CASE_FIXTURE(Fixture, "bool_singletons")
local b: false = false local b: false = false
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "string_singletons") TEST_CASE_FIXTURE(Fixture, "string_singletons")
@ -26,7 +26,7 @@ TEST_CASE_FIXTURE(Fixture, "string_singletons")
local b: "bar" = "bar" local b: "bar" = "bar"
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "bool_singletons_mismatch") TEST_CASE_FIXTURE(Fixture, "bool_singletons_mismatch")
@ -35,7 +35,7 @@ TEST_CASE_FIXTURE(Fixture, "bool_singletons_mismatch")
local a: true = false 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])); 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" 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])); 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" 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])); 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 local b: boolean = a
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "string_singleton_subtype") TEST_CASE_FIXTURE(Fixture, "string_singleton_subtype")
@ -76,7 +76,7 @@ TEST_CASE_FIXTURE(Fixture, "string_singleton_subtype")
local b: string = a local b: string = a
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "function_call_with_singletons") TEST_CASE_FIXTURE(Fixture, "function_call_with_singletons")
@ -86,7 +86,7 @@ TEST_CASE_FIXTURE(Fixture, "function_call_with_singletons")
f(true, "foo") f(true, "foo")
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "function_call_with_singletons_mismatch") 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") 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])); 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) g(false, 37)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "overloaded_function_call_with_singletons_mismatch") 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) 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("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])); 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" local c : MyEnum = "baz"
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "enums_using_singletons_mismatch") TEST_CASE_FIXTURE(Fixture, "enums_using_singletons_mismatch")
@ -144,7 +144,7 @@ TEST_CASE_FIXTURE(Fixture, "enums_using_singletons_mismatch")
local a : MyEnum = "bang" 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", CHECK_EQ("Type '\"bang\"' could not be converted into '\"bar\" | \"baz\" | \"foo\"'; none of the union options are compatible",
toString(result.errors[0])); toString(result.errors[0]));
} }
@ -159,7 +159,7 @@ TEST_CASE_FIXTURE(Fixture, "enums_using_singletons_subtyping")
local c : string = b local c : string = b
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "tagged_unions_using_singletons") TEST_CASE_FIXTURE(Fixture, "tagged_unions_using_singletons")
@ -174,7 +174,7 @@ TEST_CASE_FIXTURE(Fixture, "tagged_unions_using_singletons")
c = b c = b
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "tagged_unions_using_singletons_mismatch") 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 } local a : Animal = { tag = "Cat", howls = true }
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "tagged_unions_immutable_tag") TEST_CASE_FIXTURE(Fixture, "tagged_unions_immutable_tag")
@ -199,7 +199,7 @@ TEST_CASE_FIXTURE(Fixture, "tagged_unions_immutable_tag")
a.tag = "Dog" a.tag = "Dog"
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "table_properties_singleton_strings") TEST_CASE_FIXTURE(Fixture, "table_properties_singleton_strings")
@ -224,7 +224,7 @@ TEST_CASE_FIXTURE(Fixture, "table_properties_singleton_strings")
t.baz = false t.baz = false
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "table_properties_singleton_strings_mismatch") 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 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])); 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])); 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 } 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 '<>')", CHECK_EQ(R"(Table type '{ ["\n"]: number }' not compatible with type '{| ["<>"]: number |}' because the former is missing field '<>')",
toString(result.errors[0])); toString(result.errors[0]));
} }
@ -281,7 +281,7 @@ type Animal = Cat | Dog
local a: Animal = { tag = 'cat', cafood = 'something' } 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' CHECK_EQ(R"(Type 'a' could not be converted into 'Cat | Dog'
caused by: 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')", 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' } 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' CHECK_EQ(R"(Type 'a' could not be converted into 'Bad | Good'
caused by: 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')", 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' } 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") TEST_CASE_FIXTURE(Fixture, "widen_the_supertype_if_it_is_free_and_subtype_has_singleton")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
local function foo(f, x) local function foo(f, x)
if x == "hi" then if x == XorStr("hi") then
f(x) f(x)
f("foo") f("foo")
end end
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"("hi")", toString(requireTypeAtPosition({3, 18}))); CHECK_EQ(R"("hi")", toString(requireTypeAtPosition({3, 18})));
// should be <a...>((string) -> a..., string) -> () but needs lower bounds calculation // 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"( CheckResult result = check(R"(
local function foo(f, x): "hello"? -- anyone there? local function foo(f, x): "hello"? -- anyone there?
return if x == "hi" return if x == XorStr("hi")
then f(x) then f(x)
else nil else nil
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"("hi")", toString(requireTypeAtPosition({3, 23}))); CHECK_EQ(R"("hi")", toString(requireTypeAtPosition({3, 23})));
CHECK_EQ(R"(<a, b, c...>((string) -> (a, c...), b) -> "hello"?)", toString(requireType("foo"))); 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 local copy = foo
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("string", toString(requireType("copy"))); 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 type Animal = Cat | Dog
local function f(tag: "Cat" | "Dog"): Animal? local function f(tag: "Cat" | "Dog"): Animal?
if tag == "Cat" then if tag == XorStr("Cat") then
local result = {tag = tag, meows = true} local result = {tag = tag, meows = true}
return result return result
elseif tag == "Dog" then elseif tag == XorStr("Dog") then
local result = {tag = tag, barks = true} local result = {tag = tag, barks = true}
return result return result
else else
@ -384,16 +384,16 @@ TEST_CASE_FIXTURE(Fixture, "widening_happens_almost_everywhere_except_for_tables
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_with_a_singleton_argument") TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_with_a_singleton_argument")
{ {
ScopedFastFlag sff{"LuauLowerBoundsCalculation", true}; ScopedFastFlag sff{"lluzLowerBoundsCalculation", true};
CheckResult result = check(R"( CheckResult result = check(R"(
local function foo(t, x) 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) table.insert(t, x)
end end
@ -404,7 +404,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_with_a_singleton_argument")
table.insert(t, "totally_unrelated_type" :: "totally_unrelated_type") 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"))); 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 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"))); CHECK_EQ(R"(("A" | "B") -> ())", toString(requireType("foo")));
} }
@ -424,12 +424,12 @@ TEST_CASE_FIXTURE(Fixture, "indexing_on_string_singletons")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
local a: string = "hi" local a: string = "hi"
if a == "hi" then if a == XorStr("hi") then
local x = a:byte() local x = a:byte()
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"("hi")", toString(requireTypeAtPosition({3, 22}))); 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"( CheckResult result = check(R"(
local a: string = "hi" local a: string = "hi"
if a == "hi" or a == "bye" then if a == XorStr("hi") or a == XorStr("bye") then
local x = a:byte() local x = a:byte()
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"("bye" | "hi")", toString(requireTypeAtPosition({3, 22}))); 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"( CheckResult result = check(R"(
local a: string = "hi" local a: string = "hi"
if a == "hi" then if a == XorStr("hi") then
local x = #a local x = #a
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"("hi")", toString(requireTypeAtPosition({3, 23}))); 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"( CheckResult result = check(R"(
local a: string = "hi" local a: string = "hi"
if a == "hi" or a == "bye" then if a == XorStr("hi") or a == XorStr("bye") then
local x = #a local x = #a
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(R"("bye" | "hi")", toString(requireTypeAtPosition({3, 23}))); 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(); 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 "lluz/AstQuery.h"
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Luau/Scope.h" #include "lluz/Scope.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Luau/VisitTypeVar.h" #include "lluz/VisitTypeVar.h"
#include "Fixture.h" #include "Fixture.h"
@ -13,45 +13,44 @@
#include <algorithm> #include <algorithm>
LUAU_FASTFLAG(LuauLowerBoundsCalculation); lluz_FASTFLAG(LluLowerBoundsCalculation);
LUAU_FASTFLAG(LuauFixLocationSpanTableIndexExpr); lluz_FASTFLAG(LluFixLocationSpanTableIndexExpr);
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); lluz_FASTFLAG(DebugLluDeferredConstraintResolution);
LUAU_FASTFLAG(LuauSpecialTypesAsterisked);
using namespace Luau; using namespace lluz;
TEST_SUITE_BEGIN("TypeInfer"); TEST_SUITE_BEGIN(XorStr("TypeInfer"));
TEST_CASE_FIXTURE(Fixture, "tc_hello_world") TEST_CASE_FIXTURE(Fixture, "tc_hello_world")
{ {
CheckResult result = check("local a = 7"); CheckResult result = check(XorStr("local a = 7"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
TypeId aType = requireType("a"); TypeId aType = requireType(XorStr("a"));
CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::Number); CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::Number);
} }
TEST_CASE_FIXTURE(Fixture, "tc_propagation") TEST_CASE_FIXTURE(Fixture, "tc_propagation")
{ {
CheckResult result = check("local a = 7 local b = a"); CheckResult result = check(XorStr("local a = 7 local b = a"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
TypeId bType = requireType("b"); TypeId bType = requireType(XorStr("b"));
CHECK_EQ(getPrimitiveType(bType), PrimitiveTypeVar::Number); CHECK_EQ(getPrimitiveType(bType), PrimitiveTypeVar::Number);
} }
TEST_CASE_FIXTURE(Fixture, "tc_error") TEST_CASE_FIXTURE(Fixture, "tc_error")
{ {
CheckResult result = check("local a = 7 local b = 'hi' a = b"); CheckResult result = check(XorStr("local a = 7 local b = 'hi' a = b"));
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(result.errors[0], (TypeError{Location{Position{0, 35}, Position{0, 36}}, TypeMismatch{typeChecker.numberType, typeChecker.stringType}})); 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") TEST_CASE_FIXTURE(Fixture, "tc_error_2")
{ {
CheckResult result = check("local a = 7 a = 'hi'"); CheckResult result = check(XorStr("local a = 7 a = 'hi'"));
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(result.errors[0], (TypeError{Location{Position{0, 18}, Position{0, 22}}, TypeMismatch{ CHECK_EQ(result.errors[0], (TypeError{Location{Position{0, 18}, Position{0, 22}}, TypeMismatch{
requireType("a"), requireType("a"),
@ -61,10 +60,10 @@ TEST_CASE_FIXTURE(Fixture, "tc_error_2")
TEST_CASE_FIXTURE(Fixture, "infer_locals_with_nil_value") TEST_CASE_FIXTURE(Fixture, "infer_locals_with_nil_value")
{ {
CheckResult result = check("local f = nil; f = 'hello world'"); CheckResult result = check(XorStr("local f = nil; f = 'hello world'"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
TypeId ty = requireType("f"); TypeId ty = requireType(XorStr("f"));
CHECK_EQ(getPrimitiveType(ty), PrimitiveTypeVar::String); CHECK_EQ(getPrimitiveType(ty), PrimitiveTypeVar::String);
} }
@ -77,7 +76,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_locals_via_assignment_from_its_call_site")
f("foo") f("foo")
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("number", toString(requireType("a"))); 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") TEST_CASE_FIXTURE(Fixture, "infer_in_nocheck_mode")
{ {
ScopedFastFlag sff[]{ ScopedFastFlag sff[]{
{"DebugLuauDeferredConstraintResolution", false}, {"DebuglluzDeferredConstraintResolution", false},
{"LuauLowerBoundsCalculation", true}, {"lluzReturnTypeInferenceInNonstrict", true},
{"lluzLowerBoundsCalculation", true},
}; };
CheckResult result = check(R"( CheckResult result = check(R"(
--!nocheck --!nocheck
function f(x) function f(x)
return x return 5
end end
-- we get type information even if there's type errors -- we get type information even if there's type errors
f(1, 2) 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") TEST_CASE_FIXTURE(Fixture, "expr_statement")
{ {
CheckResult result = check("local foo = 5 foo()"); CheckResult result = check(XorStr("local foo = 5 foo()"));
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(Fixture, "if_statement") TEST_CASE_FIXTURE(Fixture, "if_statement")
@ -122,7 +122,7 @@ TEST_CASE_FIXTURE(Fixture, "if_statement")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.stringType, *requireType("a")); CHECK_EQ(*typeChecker.stringType, *requireType("a"));
CHECK_EQ(*typeChecker.numberType, *requireType("b")); CHECK_EQ(*typeChecker.numberType, *requireType("b"));
@ -140,7 +140,7 @@ TEST_CASE_FIXTURE(Fixture, "statements_are_topologically_sorted")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result); dumpErrors(result);
} }
@ -156,7 +156,7 @@ TEST_CASE_FIXTURE(Fixture, "unify_nearly_identical_recursive_types")
o = p o = p
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "warn_on_lowercase_parent_property") 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) 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]); auto ed = get<DeprecatedApiUsed>(result.errors[0]);
REQUIRE(ed); REQUIRE(ed);
@ -180,7 +180,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "weird_case")
local d = math.deg(f()) 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") 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 local s
s(s, 'a') 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") 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
#if 0 #if 0
@ -228,7 +228,7 @@ TEST_CASE_FIXTURE(Fixture, "type_errors_infer_types")
local f = err local f = err
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
UnknownProperty* err = get<UnknownProperty>(result.errors[0]); UnknownProperty* err = get<UnknownProperty>(result.errors[0]);
REQUIRE(err != nullptr); REQUIRE(err != nullptr);
@ -236,23 +236,12 @@ TEST_CASE_FIXTURE(Fixture, "type_errors_infer_types")
CHECK_EQ("x", err->key); CHECK_EQ("x", err->key);
// TODO: Should we assert anything about these tests when DCR is being used? // TODO: Should we assert anything about these tests when DCR is being used?
if (!FFlag::DebugLuauDeferredConstraintResolution) if (!FFlag::DebugLluDeferredConstraintResolution)
{ {
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("*unknown*", toString(requireType("c")));
{ CHECK_EQ("*unknown*", toString(requireType("d")));
CHECK_EQ("*error-type*", toString(requireType("c"))); CHECK_EQ("*unknown*", toString(requireType("e")));
CHECK_EQ("*error-type*", toString(requireType("d"))); CHECK_EQ("*unknown*", toString(requireType("f")));
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")));
}
} }
} }
@ -268,7 +257,7 @@ TEST_CASE_FIXTURE(Fixture, "should_be_able_to_infer_this_without_stack_overflowi
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "exponential_blowup_from_copying_types") TEST_CASE_FIXTURE(Fixture, "exponential_blowup_from_copying_types")
@ -301,7 +290,7 @@ TEST_CASE_FIXTURE(Fixture, "exponential_blowup_from_copying_types")
return x4 return x4
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
ModulePtr module = getMainModule(); ModulePtr module = getMainModule();
// If we're not careful about copying, this ends up with O(2^N) types rather than O(N) // 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. // 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") TEST_CASE_FIXTURE(Fixture, "check_type_infer_recursion_count")
{ {
#if defined(LUAU_ENABLE_ASAN) #if defined(lluz_ENABLE_ASAN)
int limit = 250; int limit = 250;
#elif defined(_DEBUG) || defined(_NOOPT) #elif defined(_DEBUG) || defined(_NOOPT)
int limit = 350; int limit = 350;
@ -321,17 +310,17 @@ TEST_CASE_FIXTURE(Fixture, "check_type_infer_recursion_count")
int limit = 600; int limit = 600;
#endif #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])); CHECK(nullptr != get<CodeTooComplex>(result.errors[0]));
} }
TEST_CASE_FIXTURE(Fixture, "check_block_recursion_limit") TEST_CASE_FIXTURE(Fixture, "check_block_recursion_limit")
{ {
#if defined(LUAU_ENABLE_ASAN) #if defined(lluz_ENABLE_ASAN)
int limit = 250; int limit = 250;
#elif defined(_DEBUG) || defined(_NOOPT) #elif defined(_DEBUG) || defined(_NOOPT)
int limit = 350; int limit = 350;
@ -339,62 +328,33 @@ TEST_CASE_FIXTURE(Fixture, "check_block_recursion_limit")
int limit = 600; int limit = 600;
#endif #endif
ScopedFastInt luauRecursionLimit{"LuauRecursionLimit", limit + 100}; ScopedFastInt lluzRecursionLimit{"lluzRecursionLimit", limit + 100};
ScopedFastInt luauCheckRecursionLimit{"LuauCheckRecursionLimit", limit - 100}; ScopedFastInt lluzCheckRecursionLimit{"lluzCheckRecursionLimit", limit - 100};
CheckResult result = check(rep("do ", limit) + "local a = 1" + rep(" end", limit)); 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])); CHECK(nullptr != get<CodeTooComplex>(result.errors[0]));
} }
TEST_CASE_FIXTURE(Fixture, "check_expr_recursion_limit") TEST_CASE_FIXTURE(Fixture, "check_expr_recursion_limit")
{ {
#if defined(LUAU_ENABLE_ASAN) #if defined(lluz_ENABLE_ASAN)
int limit = 250; int limit = 250;
#elif defined(_DEBUG) || defined(_NOOPT) #elif defined(_DEBUG) || defined(_NOOPT)
int limit = 300; int limit = 300;
#else #else
int limit = 600; int limit = 600;
#endif #endif
ScopedFastInt luauRecursionLimit{"LuauRecursionLimit", limit + 100}; ScopedFastInt lluzRecursionLimit{"lluzRecursionLimit", limit + 100};
ScopedFastInt luauCheckRecursionLimit{"LuauCheckRecursionLimit", limit - 100}; ScopedFastInt lluzCheckRecursionLimit{"lluzCheckRecursionLimit", limit - 100};
CheckResult result = check(R"(("foo"))" + rep(":lower()", limit)); 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])); 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") TEST_CASE_FIXTURE(Fixture, "globals_are_banned_in_strict_mode")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
@ -402,7 +362,7 @@ TEST_CASE_FIXTURE(Fixture, "globals_are_banned_in_strict_mode")
foo = true foo = true
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
UnknownSymbol* us = get<UnknownSymbol>(result.errors[0]); UnknownSymbol* us = get<UnknownSymbol>(result.errors[0]);
REQUIRE(us); REQUIRE(us);
@ -419,11 +379,11 @@ TEST_CASE_FIXTURE(Fixture, "correctly_scope_locals_do")
local b = a -- oops! local b = a -- oops!
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
UnknownSymbol* us = get<UnknownSymbol>(result.errors[0]); UnknownSymbol* us = get<UnknownSymbol>(result.errors[0]);
REQUIRE(us); REQUIRE(us);
CHECK_EQ(us->name, "a"); CHECK_EQ(us->name, XorStr("a"));
} }
TEST_CASE_FIXTURE(Fixture, "checking_should_not_ice") TEST_CASE_FIXTURE(Fixture, "checking_should_not_ice")
@ -496,17 +456,17 @@ TEST_CASE_FIXTURE(Fixture, "tc_after_error_recovery")
local x = local x =
local a = 7 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_EQ(getPrimitiveType(aType), PrimitiveTypeVar::Number);
} }
// Check that type checker knows about error expressions // Check that type checker knows about error expressions
TEST_CASE_FIXTURE(Fixture, "tc_after_error_recovery_no_assert") TEST_CASE_FIXTURE(Fixture, "tc_after_error_recovery_no_assert")
{ {
CheckResult result = check("function +() local _ = true end"); CheckResult result = check(XorStr("function +() local _ = true end"));
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_in_error") 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. 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 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 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 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 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]) 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 UnknownProperty* up = get<UnknownProperty>(result.errors[0]); // Should probably be NotATable
REQUIRE(up); REQUIRE(up);
@ -586,7 +546,7 @@ TEST_CASE_FIXTURE(Fixture, "stringify_nested_unions_with_optionals")
local b: number = a local b: number = a
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm); REQUIRE(tm);
CHECK_EQ(typeChecker.numberType, tm->wantedType); 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] 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") 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 foo
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstExprError") 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: local a = foo:
)"); )");
LUAU_REQUIRE_ERROR_COUNT(2, result); lluz_REQUIRE_ERROR_COUNT(2, result);
} }
TEST_CASE_FIXTURE(Fixture, "dont_ice_on_astexprerror") TEST_CASE_FIXTURE(Fixture, "dont_ice_on_astexprerror")
@ -627,10 +587,10 @@ TEST_CASE_FIXTURE(Fixture, "dont_ice_on_astexprerror")
local foo = -; 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"( CheckResult result = check(R"(
--!strict --!strict
@ -641,7 +601,7 @@ TEST_CASE_FIXTURE(Fixture, "luau_resolves_symbols_the_same_way_lua_does")
local foo: string = 'hello' local foo: string = 'hello'
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
auto e = result.errors.front(); auto e = result.errors.front();
REQUIRE_MESSAGE(get<UnknownSymbol>(e) != nullptr, "Expected UnknownSymbol, but got " << e); 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) _(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); REQUIRE(t0);
CHECK_EQ("*unknown*", toString(t0->type));
if (FFlag::LuauSpecialTypesAsterisked)
CHECK_EQ("*error-type*", toString(t0->type));
else
CHECK_EQ("<error-type>", toString(t0->type));
auto it = std::find_if(result.errors.begin(), result.errors.end(), [](TypeError& err) { auto it = std::find_if(result.errors.begin(), result.errors.end(), [](TypeError& err) {
return get<OccursCheckFailed>(err); return get<OccursCheckFailed>(err);
@ -687,7 +643,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_stack_overflow_from_isoptional2")
local t: ({})|(t0) local t: ({})|(t0)
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "no_infinite_loop_when_trying_to_unify_uh_this") 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") 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 end
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "infer_type_assertion_value_type") TEST_CASE_FIXTURE(Fixture, "infer_type_assertion_value_type")
@ -729,7 +685,7 @@ local function f()
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "infer_assignment_value_types") TEST_CASE_FIXTURE(Fixture, "infer_assignment_value_types")
@ -744,7 +700,7 @@ local c: {number|string}
b, c = {2, "s"}, {"b", 4} 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") TEST_CASE_FIXTURE(BuiltinsFixture, "infer_assignment_value_types_mutable_lval")
@ -755,7 +711,7 @@ a.x = 2
a = setmetatable(a, { __call = function(x) end }) 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") 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))) 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") TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions1")
{ {
CheckResult result = check(R"(local a = if true then "true" else "false")"); CheckResult result = check(RXorStr("(local a = if true then "true" else "false")"));
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
TypeId aType = requireType("a"); TypeId aType = requireType(XorStr("a"));
CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::String); CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::String);
} }
@ -782,17 +738,17 @@ TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions2")
CheckResult result = check(R"( CheckResult result = check(R"(
local a = if false then "a" elseif false then "b" else "c" local a = if false then "a" elseif false then "b" else "c"
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
TypeId aType = requireType("a"); TypeId aType = requireType(XorStr("a"));
CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::String); CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::String);
} }
TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions_type_union") 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); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a"), {true}), "number?"); CHECK_EQ(toString(requireType(XorStr("a"), {true}), "number?"));
} }
TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions_expected_type_1") 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} local a: X = if true then {"1", 2, 3} else {4, 5, 6}
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("a"), {true}), "{number | string}"); CHECK_EQ(toString(requireType(XorStr("a"), {true}), "{number | string}"));
} }
TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions_expected_type_2") 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 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") TEST_CASE_FIXTURE(BuiltinsFixture, "tc_if_else_expressions_expected_type_3")
@ -826,7 +782,7 @@ local function times<T>(n: any, f: () -> T)
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
/* /*
@ -899,7 +855,7 @@ local b = getIt()
local c = a or b local c = a or b
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "bound_typepack_promote") TEST_CASE_FIXTURE(Fixture, "bound_typepack_promote")
@ -951,7 +907,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_50041_committing_txnlog_in_apollo_client_error")
end end
function Policies:getStoreFieldName(specifier: FieldSpecifier): string function Policies:getStoreFieldName(specifier: FieldSpecifier): string
return "" return XorStr("")
end end
function Policies:readField(options: ReadFieldOptions) function Policies:readField(options: ReadFieldOptions)
@ -964,12 +920,12 @@ TEST_CASE_FIXTURE(Fixture, "cli_50041_committing_txnlog_in_apollo_client_error")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_no_ice") TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_no_ice")
{ {
ScopedFastInt sfi("LuauTypeInferRecursionLimit", 2); ScopedFastInt sfi("lluzTypeInferRecursionLimit", 2);
CheckResult result = check(R"( CheckResult result = check(R"(
function complex() function complex()
@ -981,7 +937,7 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_no_ice")
end 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])); 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 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") TEST_CASE_FIXTURE(Fixture, "do_not_bind_a_free_table_to_a_union_containing_that_table")
{ {
ScopedFastFlag flag[] = { ScopedFastFlag flag[] = {
{"LuauLowerBoundsCalculation", true}, {"lluzLowerBoundsCalculation", true},
}; };
CheckResult result = check(R"( 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() local B = A:f()
function B.g(t) function B.g(t)
assert(type(t) == "table") assert(type(t) == XorStr("table"))
assert(t.prop ~= nil) assert(t.prop ~= nil)
end end
@ -1056,7 +1012,7 @@ end
)"); )");
auto node = findNodeAtPosition(*getMainSourceModule(), {2, 16}); auto node = findNodeAtPosition(*getMainSourceModule(), {2, 16});
auto ty = lookupType("alias"); auto ty = lookupType(XorStr("alias"));
REQUIRE(node); REQUIRE(node);
REQUIRE(node->is<AstExprFunction>()); REQUIRE(node->is<AstExprFunction>());
REQUIRE(ty); 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 // 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 "lluz/Scope.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
struct TryUnifyFixture : Fixture struct TryUnifyFixture : Fixture
{ {
@ -20,7 +18,7 @@ struct TryUnifyFixture : Fixture
Unifier state{&arena, Mode::Strict, Location{}, Variance::Covariant, unifierState}; Unifier state{&arena, Mode::Strict, Location{}, Variance::Covariant, unifierState};
}; };
TEST_SUITE_BEGIN("TryUnifyTests"); TEST_SUITE_BEGIN(XorStr("TryUnifyTests"));
TEST_CASE_FIXTURE(TryUnifyFixture, "primitives_unify") TEST_CASE_FIXTURE(TryUnifyFixture, "primitives_unify")
{ {
@ -120,13 +118,10 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "members_of_failed_typepack_unification_are_u
f(a, b) f(a, b)
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("a", toString(requireType("a"))); CHECK_EQ("a", toString(requireType("a")));
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("*unknown*", toString(requireType("b")));
CHECK_EQ("*error-type*", toString(requireType("b")));
else
CHECK_EQ("<error-type>", toString(requireType("b")));
} }
TEST_CASE_FIXTURE(TryUnifyFixture, "result_of_failed_typepack_unification_is_constrained") 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) local c = f(a, b)
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("a", toString(requireType("a"))); CHECK_EQ("a", toString(requireType("a")));
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("*unknown*", toString(requireType("b")));
CHECK_EQ("*error-type*", toString(requireType("b")));
else
CHECK_EQ("<error-type>", toString(requireType("b")));
CHECK_EQ("number", toString(requireType("c"))); CHECK_EQ("number", toString(requireType("c")));
} }
@ -163,7 +155,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "typepack_unification_should_trim_free_tails"
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ("(number) -> boolean", toString(requireType("f"))); 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) local x: string = f(1)
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]); TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
REQUIRE(tm); REQUIRE(tm);
CHECK_EQ(toString(tm->givenType), "number"); CHECK_EQ(toString(tm->givenType), XorStr("number"));
CHECK_EQ(toString(tm->wantedType), "string"); CHECK_EQ(toString(tm->wantedType), XorStr("string"));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "cli_41095_concat_log_in_sealed_table_unification") 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() table.insert()
)"); )");
LUAU_REQUIRE_ERROR_COUNT(2, result); lluz_REQUIRE_ERROR_COUNT(2, result);
CHECK_EQ(toString(result.errors[0]), "No overload for function accepts 0 arguments."); CHECK_EQ(toString(result.errors[0]), XorStr("No overload for function accepts 0 arguments."));
CHECK_EQ(toString(result.errors[1]), "Available overloads: ({a}, a) -> (); and ({a}, number, a) -> ()"); CHECK_EQ(toString(result.errors[1]), XorStr("Available overloads: ({a}, a) -> (); and ({a}, number, a) -> ()"));
} }
TEST_CASE_FIXTURE(TryUnifyFixture, "free_tail_is_grown_properly") 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/BuiltinDefinitions.h" #include "lluz/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.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") TEST_CASE_FIXTURE(Fixture, "infer_multi_return")
{ {
@ -21,7 +21,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_multi_return")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* takeTwoType = get<FunctionTypeVar>(requireType("take_two")); const FunctionTypeVar* takeTwoType = get<FunctionTypeVar>(requireType("take_two"));
REQUIRE(takeTwoType != nullptr); 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 local a, b = ..., 1
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "self_and_varargs_should_work") 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) 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") 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
dumpErrors(result); dumpErrors(result);
const FunctionTypeVar* takeOneMoreType = get<FunctionTypeVar>(requireType("take_three")); const FunctionTypeVar* takeOneMoreType = get<FunctionTypeVar>(requireType("take_three"));
@ -91,7 +91,7 @@ TEST_CASE_FIXTURE(Fixture, "higher_order_function")
end 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"))); 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 f() end
function g() return end function g() return end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* fTy = get<FunctionTypeVar>(requireType("f")); const FunctionTypeVar* fTy = get<FunctionTypeVar>(requireType("f"));
REQUIRE(fTy != nullptr); REQUIRE(fTy != nullptr);
CHECK_EQ(0, size(fTy->retTypes)); CHECK_EQ(0, size(fTy->retTypes));
@ -121,7 +121,7 @@ TEST_CASE_FIXTURE(Fixture, "no_return_size_should_be_zero")
g(h()) g(h())
f(g(),h()) f(g(),h())
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* fTy = get<FunctionTypeVar>(requireType("f")); const FunctionTypeVar* fTy = get<FunctionTypeVar>(requireType("f"));
REQUIRE(fTy != nullptr); REQUIRE(fTy != nullptr);
@ -149,7 +149,7 @@ TEST_CASE_FIXTURE(Fixture, "varargs_inference_through_multiple_scopes")
f("foo") f("foo")
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "multiple_varargs_inference_are_not_confused") 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) f("foo", "bar")(1, 2)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "parenthesized_varargs_returns_any") TEST_CASE_FIXTURE(Fixture, "parenthesized_varargs_returns_any")
@ -180,7 +180,7 @@ TEST_CASE_FIXTURE(Fixture, "parenthesized_varargs_returns_any")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("any", toString(requireType("value"))); CHECK_EQ("any", toString(requireType("value")));
} }
@ -223,7 +223,7 @@ TEST_CASE_FIXTURE(Fixture, "variadic_packs")
bar(1, "foo", "bar", 3) 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}})); 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) foo(1, 2, 3, 4, 5, 6)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(toString(requireType("foo")), "(...number) -> ()"); CHECK_EQ(toString(requireType(XorStr("foo")), "(...number) -> ()"));
} }
TEST_CASE_FIXTURE(Fixture, "type_pack_hidden_free_tail_infinite_growth") TEST_CASE_FIXTURE(Fixture, "type_pack_hidden_free_tail_infinite_growth")
@ -259,7 +259,7 @@ elseif _ then
end end
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "variadic_argument_tail") TEST_CASE_FIXTURE(Fixture, "variadic_argument_tail")
@ -272,7 +272,7 @@ for y in _() do
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_type_packs") TEST_CASE_FIXTURE(Fixture, "type_alias_type_packs")
@ -284,14 +284,14 @@ local b: Packed<number>
local c: Packed<string, 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); REQUIRE(tf);
CHECK_EQ(toString(*tf), "(T...) -> (T...)"); CHECK_EQ(toString(*tf), XorStr("(T...) -> (T...)"));
CHECK_EQ(toString(requireType("a")), "() -> ()"); CHECK_EQ(toString(requireType(XorStr("a")), "() -> ()"));
CHECK_EQ(toString(requireType("b")), "(number) -> number"); CHECK_EQ(toString(requireType(XorStr("b")), "(number) -> number"));
CHECK_EQ(toString(requireType("c")), "(string, number) -> (string, number)"); CHECK_EQ(toString(requireType(XorStr("c")), "(string, number) -> (string, number)"));
result = check(R"( result = check(R"(
-- (U..., T) cannot be parsed right now -- (U..., T) cannot be parsed right now
@ -301,42 +301,42 @@ local b: Packed<string, number>
local c: Packed<string, number, boolean> 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); REQUIRE(tf);
CHECK_EQ(toString(*tf), "Packed<T, U...>"); CHECK_EQ(toString(*tf), XorStr("Packed<T, U...>"));
CHECK_EQ(toString(*tf, {true}), "{| f: (T, U...) -> (T, U...) |}"); CHECK_EQ(toString(*tf, {true}), XorStr("{| f: (T, U...) -> (T, U...) |}"));
auto ttvA = get<TableTypeVar>(requireType("a")); auto ttvA = get<TableTypeVar>(requireType("a"));
REQUIRE(ttvA); REQUIRE(ttvA);
CHECK_EQ(toString(requireType("a")), "Packed<number>"); CHECK_EQ(toString(requireType(XorStr("a")), "Packed<number>"));
if (FFlag::LuauLowerBoundsCalculation) if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ(toString(requireType("a"), {true}), "{| f: (number) -> number |}"); CHECK_EQ(toString(requireType(XorStr("a"), {true}), "{| f: (number) -> number |}"));
else 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->instantiatedTypeParams.size() == 1);
REQUIRE(ttvA->instantiatedTypePackParams.size() == 1); REQUIRE(ttvA->instantiatedTypePackParams.size() == 1);
CHECK_EQ(toString(ttvA->instantiatedTypeParams[0], {true}), "number"); CHECK_EQ(toString(ttvA->instantiatedTypeParams[0], {true}), XorStr("number"));
CHECK_EQ(toString(ttvA->instantiatedTypePackParams[0], {true}), ""); CHECK_EQ(toString(ttvA->instantiatedTypePackParams[0], {true}), XorStr(""));
auto ttvB = get<TableTypeVar>(requireType("b")); auto ttvB = get<TableTypeVar>(requireType("b"));
REQUIRE(ttvB); REQUIRE(ttvB);
CHECK_EQ(toString(requireType("b")), "Packed<string, number>"); CHECK_EQ(toString(requireType(XorStr("b")), "Packed<string, number>"));
CHECK_EQ(toString(requireType("b"), {true}), "{| f: (string, number) -> (string, number) |}"); CHECK_EQ(toString(requireType(XorStr("b"), {true}), "{| f: (string, number) -> (string, number) |}"));
REQUIRE(ttvB->instantiatedTypeParams.size() == 1); REQUIRE(ttvB->instantiatedTypeParams.size() == 1);
REQUIRE(ttvB->instantiatedTypePackParams.size() == 1); REQUIRE(ttvB->instantiatedTypePackParams.size() == 1);
CHECK_EQ(toString(ttvB->instantiatedTypeParams[0], {true}), "string"); CHECK_EQ(toString(ttvB->instantiatedTypeParams[0], {true}), XorStr("string"));
CHECK_EQ(toString(ttvB->instantiatedTypePackParams[0], {true}), "number"); CHECK_EQ(toString(ttvB->instantiatedTypePackParams[0], {true}), XorStr("number"));
auto ttvC = get<TableTypeVar>(requireType("c")); auto ttvC = get<TableTypeVar>(requireType("c"));
REQUIRE(ttvC); REQUIRE(ttvC);
CHECK_EQ(toString(requireType("c")), "Packed<string, number, boolean>"); CHECK_EQ(toString(requireType(XorStr("c")), "Packed<string, number, boolean>"));
CHECK_EQ(toString(requireType("c"), {true}), "{| f: (string, number, boolean) -> (string, number, boolean) |}"); CHECK_EQ(toString(requireType(XorStr("c"), {true}), "{| f: (string, number, boolean) -> (string, number, boolean) |}"));
REQUIRE(ttvC->instantiatedTypeParams.size() == 1); REQUIRE(ttvC->instantiatedTypeParams.size() == 1);
REQUIRE(ttvC->instantiatedTypePackParams.size() == 1); REQUIRE(ttvC->instantiatedTypePackParams.size() == 1);
CHECK_EQ(toString(ttvC->instantiatedTypeParams[0], {true}), "string"); CHECK_EQ(toString(ttvC->instantiatedTypeParams[0], {true}), XorStr("string"));
CHECK_EQ(toString(ttvC->instantiatedTypePackParams[0], {true}), "number, boolean"); CHECK_EQ(toString(ttvC->instantiatedTypePackParams[0], {true}), XorStr("number, boolean"));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_type_packs_import") TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_type_packs_import")
@ -346,8 +346,8 @@ export type Packed<T, U...> = { a: T, b: (U...) -> () }
return {} return {}
)"; )";
CheckResult aResult = frontend.check("game/A"); CheckResult aResult = frontend.check(XorStr("game/A"));
LUAU_REQUIRE_NO_ERRORS(aResult); lluz_REQUIRE_NO_ERRORS(aResult);
CheckResult bResult = check(R"( CheckResult bResult = check(R"(
local Import = require(game.A) local Import = require(game.A)
@ -356,17 +356,17 @@ local b: Import.Packed<string, number>
local c: Import.Packed<string, number, boolean> local c: Import.Packed<string, number, boolean>
local d: { a: typeof(c) } 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); REQUIRE(tf);
CHECK_EQ(toString(*tf), "Packed<T, U...>"); CHECK_EQ(toString(*tf), XorStr("Packed<T, U...>"));
CHECK_EQ(toString(*tf, {true}), "{| a: T, b: (U...) -> () |}"); CHECK_EQ(toString(*tf, {true}), XorStr("{| a: T, b: (U...) -> () |}"));
CHECK_EQ(toString(requireType("a"), {true}), "{| a: number, b: () -> () |}"); CHECK_EQ(toString(requireType(XorStr("a"), {true}), "{| a: number, b: () -> () |}"));
CHECK_EQ(toString(requireType("b"), {true}), "{| a: string, b: (number) -> () |}"); CHECK_EQ(toString(requireType(XorStr("b"), {true}), "{| a: string, b: (number) -> () |}"));
CHECK_EQ(toString(requireType("c"), {true}), "{| a: string, b: (number, boolean) -> () |}"); CHECK_EQ(toString(requireType(XorStr("c"), {true}), "{| a: string, b: (number, boolean) -> () |}"));
CHECK_EQ(toString(requireType("d")), "{| a: Packed<string, number, boolean> |}"); CHECK_EQ(toString(requireType(XorStr("d")), "{| a: Packed<string, number, boolean> |}"));
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "type_pack_type_parameters") 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 B<X...> = Import.Packed<string, X...>
type C<X...> = Import.Packed<string, (number, 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); REQUIRE(tf);
CHECK_EQ(toString(*tf), "Alias<S, T, R...>"); CHECK_EQ(toString(*tf), XorStr("Alias<S, T, R...>"));
CHECK_EQ(toString(*tf, {true}), "{| a: S, b: (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); REQUIRE(tf);
CHECK_EQ(toString(*tf), "B<X...>"); CHECK_EQ(toString(*tf), XorStr("B<X...>"));
CHECK_EQ(toString(*tf, {true}), "{| a: string, b: (X...) -> () |}"); CHECK_EQ(toString(*tf, {true}), XorStr("{| a: string, b: (X...) -> () |}"));
tf = lookupType("C"); tf = lookupType(XorStr("C"));
REQUIRE(tf); REQUIRE(tf);
CHECK_EQ(toString(*tf), "C<X...>"); CHECK_EQ(toString(*tf), XorStr("C<X...>"));
CHECK_EQ(toString(*tf, {true}), "{| a: string, b: (number, X...) -> () |}"); CHECK_EQ(toString(*tf, {true}), XorStr("{| a: string, b: (number, X...) -> () |}"));
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_type_packs_nested") 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...) 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); REQUIRE(tf);
CHECK_EQ(toString(*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...) -> "
"((((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") TEST_CASE_FIXTURE(Fixture, "type_alias_type_pack_variadic")
@ -431,10 +431,10 @@ type D = X<...number>
type E = X<(number, ...string)> 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(XorStr("D")), "(...number) -> (string, ...number)"));
CHECK_EQ(toString(*lookupType("E")), "(number, ...string) -> (string, number, ...string)"); CHECK_EQ(toString(*lookupType(XorStr("E")), "(number, ...string) -> (string, number, ...string)"));
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_type_pack_multi") 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...> 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(XorStr("A")), "(S...) -> (S...)"));
CHECK_EQ(toString(*lookupType("B")), "(number, ...string) -> (S...)"); CHECK_EQ(toString(*lookupType(XorStr("B")), "(number, ...string) -> (S...)"));
CHECK_EQ(toString(*lookupType("E")), "(number) -> (S...)"); CHECK_EQ(toString(*lookupType(XorStr("E")), "(number) -> (S...)"));
CHECK_EQ(toString(*lookupType("F")), "(number) -> (string, S...)"); CHECK_EQ(toString(*lookupType(XorStr("F")), "(number) -> (string, S...)"));
CHECK_EQ(toString(*lookupType("H")), "(number, S...) -> (number, R...)"); CHECK_EQ(toString(*lookupType(XorStr("H")), "(number, S...) -> (number, R...)"));
CHECK_EQ(toString(*lookupType("I")), "(number, string, S...) -> (number, R...)"); CHECK_EQ(toString(*lookupType(XorStr("I")), "(number, string, S...) -> (number, R...)"));
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_type_pack_explicit") TEST_CASE_FIXTURE(Fixture, "type_alias_type_pack_explicit")
@ -478,14 +478,14 @@ type E = X<(...number)>
type F = X<(string, ...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(XorStr("A")), "(S...) -> (S...)"));
CHECK_EQ(toString(*lookupType("B")), "() -> ()"); CHECK_EQ(toString(*lookupType(XorStr("B")), "() -> ()"));
CHECK_EQ(toString(*lookupType("C")), "(number) -> number"); CHECK_EQ(toString(*lookupType(XorStr("C")), "(number) -> number"));
CHECK_EQ(toString(*lookupType("D")), "(number, string) -> (number, string)"); CHECK_EQ(toString(*lookupType(XorStr("D")), "(number, string) -> (number, string)"));
CHECK_EQ(toString(*lookupType("E")), "(...number) -> (...number)"); CHECK_EQ(toString(*lookupType(XorStr("E")), "(...number) -> (...number)"));
CHECK_EQ(toString(*lookupType("F")), "(string, ...number) -> (string, ...number)"); CHECK_EQ(toString(*lookupType(XorStr("F")), "(string, ...number) -> (string, ...number)"));
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_type_pack_explicit_multi") 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...)> 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(XorStr("A")), "(number, string) -> boolean"));
CHECK_EQ(toString(*lookupType("B")), "() -> ()"); CHECK_EQ(toString(*lookupType(XorStr("B")), "() -> ()"));
CHECK_EQ(toString(*lookupType("C")), "(...string) -> (number, S...)"); CHECK_EQ(toString(*lookupType(XorStr("C")), "(...string) -> (number, S...)"));
CHECK_EQ(toString(*lookupType("D")), "(X...) -> (number, string, X...)"); CHECK_EQ(toString(*lookupType(XorStr("D")), "(X...) -> (number, string, X...)"));
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_type_pack_explicit_multi_tostring") TEST_CASE_FIXTURE(Fixture, "type_alias_type_pack_explicit_multi_tostring")
@ -516,10 +516,10 @@ local a: Y<(number, string), (boolean)>
local b: Y<(), ()> 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(XorStr("a")), "Y<(number, string), (boolean)>"));
CHECK_EQ(toString(requireType("b")), "Y<(), ()>"); CHECK_EQ(toString(requireType(XorStr("b")), "Y<(), ()>"));
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_backwards_compatible") TEST_CASE_FIXTURE(Fixture, "type_alias_backwards_compatible")
@ -533,11 +533,11 @@ type B = Y<(number), (boolean)>
type C = 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(XorStr("A")), "() -> number"));
CHECK_EQ(toString(*lookupType("B")), "(number) -> boolean"); CHECK_EQ(toString(*lookupType(XorStr("B")), "(number) -> boolean"));
CHECK_EQ(toString(*lookupType("C")), "(number) -> boolean"); CHECK_EQ(toString(*lookupType(XorStr("C")), "(number) -> boolean"));
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_type_packs_errors") 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> local b: Packed<number>
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_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"); 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"( result = check(R"(
type Packed<T, U> = (T, U) -> () type Packed<T, U> = (T, U) -> ()
type B<X...> = Packed<number, string, X...> type B<X...> = Packed<number, string, X...>
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_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"); CHECK_EQ(toString(result.errors[0]), XorStr("Generic type 'Packed<T, U>' expects 0 type pack arguments, but 1 is specified"));
result = check(R"( result = check(R"(
type Packed<T..., U...> = (T...) -> (U...) type Packed<T..., U...> = (T...) -> (U...)
type Other<S...> = Packed<S..., string> type Other<S...> = Packed<S..., string>
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Type parameters must come before type pack parameters"); CHECK_EQ(toString(result.errors[0]), XorStr("Type parameters must come before type pack parameters"));
result = check(R"( result = check(R"(
type Packed<T, U> = (T) -> U type Packed<T, U> = (T) -> U
type Other<S...> = Packed<number, S...> type Other<S...> = Packed<number, S...>
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_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"); CHECK_EQ(toString(result.errors[0]), XorStr("Generic type 'Packed<T, U>' expects 2 type arguments, but only 1 is specified"));
result = check(R"( result = check(R"(
type Packed<T...> = (T...) -> T... type Packed<T...> = (T...) -> T...
local a: Packed local a: Packed
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Type parameter list is required"); CHECK_EQ(toString(result.errors[0]), XorStr("Type parameter list is required"));
result = check(R"( result = check(R"(
type Packed<T..., U...> = (T...) -> (U...) type Packed<T..., U...> = (T...) -> (U...)
type Other = Packed<> type Other = Packed<>
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_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"); CHECK_EQ(toString(result.errors[0]), XorStr("Generic type 'Packed<T..., U...>' expects 2 type pack arguments, but none are specified"));
result = check(R"( result = check(R"(
type Packed<T..., U...> = (T...) -> (U...) type Packed<T..., U...> = (T...) -> (U...)
type Other = Packed<number, string> type Other = Packed<number, string>
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_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"); 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") 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" } 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(XorStr("a")), "Y<number, number>"));
CHECK_EQ(toString(requireType("b")), "Y<number, string>"); CHECK_EQ(toString(requireType(XorStr("b")), "Y<number, string>"));
result = check(R"( result = check(R"(
type Y<T = string> = { a: T } type Y<T = string> = { a: T }
@ -621,11 +621,11 @@ local b: Y<> = { a = "s" }
local c: 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(XorStr("a")), "Y<number>"));
CHECK_EQ(toString(requireType("b")), "Y<string>"); CHECK_EQ(toString(requireType(XorStr("b")), "Y<string>"));
CHECK_EQ(toString(requireType("c")), "Y<string>"); CHECK_EQ(toString(requireType(XorStr("c")), "Y<string>"));
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_self") 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" } 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(XorStr("a")), "Y<number, number>"));
CHECK_EQ(toString(requireType("b")), "Y<string, string>"); CHECK_EQ(toString(requireType(XorStr("b")), "Y<string, string>"));
result = check(R"( result = check(R"(
type Y<T, U = (T, T) -> string> = { a: T, b: U } 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> 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") TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_chained")
@ -662,10 +662,10 @@ local a: Y<number>
local b: Y<number, string> 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(XorStr("a")), "Y<number, number, number>"));
CHECK_EQ(toString(requireType("b")), "Y<number, string, string>"); CHECK_EQ(toString(requireType(XorStr("b")), "Y<number, string, string>"));
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_pack_explicit") TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_pack_explicit")
@ -675,9 +675,9 @@ type Y<T... = (string, number)> = { a: (T...) -> () }
local a: Y<> 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") 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> 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") 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> 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") 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> 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") 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, ...() -> ()> 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(XorStr("a")), "Y<number, number, ...number, (number, number, ...number)>"));
CHECK_EQ(toString(requireType("b")), "Y<number, string, ...number, (number, string, ...number)>"); CHECK_EQ(toString(requireType(XorStr("b")), "Y<number, string, ...number, (number, string, ...number)>"));
CHECK_EQ(toString(requireType("c")), "Y<number, string, ...boolean, (number, string, ...boolean)>"); CHECK_EQ(toString(requireType(XorStr("c")), "Y<number, string, ...boolean, (number, string, ...boolean)>"));
CHECK_EQ(toString(requireType("d")), "Y<number, string, ...boolean, ...() -> ()>"); CHECK_EQ(toString(requireType(XorStr("d")), "Y<number, string, ...boolean, ...() -> ()>"));
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors") TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors")
@ -742,46 +742,46 @@ type Y<T = T> = { a: T }
local a: Y = { a = 2 } local a: Y = { a = 2 }
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Unknown type 'T'"); CHECK_EQ(toString(result.errors[0]), XorStr("Unknown type 'T'"));
result = check(R"( result = check(R"(
type Y<T... = T...> = { a: (T...) -> () } type Y<T... = T...> = { a: (T...) -> () }
local a: Y<> local a: Y<>
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Unknown type 'T'"); CHECK_EQ(toString(result.errors[0]), XorStr("Unknown type 'T'"));
result = check(R"( result = check(R"(
type Y<T = string, U... = ...string> = { a: (T) -> U... } type Y<T = string, U... = ...string> = { a: (T) -> U... }
local a: Y<...number> local a: Y<...number>
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_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"); 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"( result = check(R"(
type Packed<T> = (T) -> T type Packed<T> = (T) -> T
local a: Packed local a: Packed
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
CHECK_EQ(toString(result.errors[0]), "Type parameter list is required"); CHECK_EQ(toString(result.errors[0]), XorStr("Type parameter list is required"));
result = check(R"( result = check(R"(
type Y<T, U = T, V> = { a: T } type Y<T, U = T, V> = { a: T }
local a: Y<number> local a: Y<number>
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
result = check(R"( result = check(R"(
type Y<T..., U... = T..., V...> = { a: T } type Y<T..., U... = T..., V...> = { a: T }
local a: Y<...number> local a: Y<...number>
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_default_export") TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_default_export")
@ -798,8 +798,8 @@ export type H<T... = ()> = { b: (T...) -> T... }
return {} return {}
)"; )";
CheckResult resultTypes = frontend.check("Module/Types"); CheckResult resultTypes = frontend.check(XorStr("Module/Types"));
LUAU_REQUIRE_NO_ERRORS(resultTypes); lluz_REQUIRE_NO_ERRORS(resultTypes);
fileResolver.source["Module/Users"] = R"( fileResolver.source["Module/Users"] = R"(
local Types = require(script.Parent.Types) local Types = require(script.Parent.Types)
@ -815,18 +815,18 @@ local g: Types.G<...number>
local h: Types.H<> local h: Types.H<>
)"; )";
CheckResult resultUsers = frontend.check("Module/Users"); CheckResult resultUsers = frontend.check(XorStr("Module/Users"));
LUAU_REQUIRE_NO_ERRORS(resultUsers); lluz_REQUIRE_NO_ERRORS(resultUsers);
CHECK_EQ(toString(requireType("Module/Users", "a")), "A<number, string>"); CHECK_EQ(toString(requireType(XorStr("Module/Users", "a")), "A<number, string>"));
CHECK_EQ(toString(requireType("Module/Users", "b")), "B<number, number>"); CHECK_EQ(toString(requireType(XorStr("Module/Users", "b")), "B<number, number>"));
CHECK_EQ(toString(requireType("Module/Users", "c")), "C<number, (number, number) -> string>"); CHECK_EQ(toString(requireType(XorStr("Module/Users", "c")), "C<number, (number, number) -> string>"));
CHECK_EQ(toString(requireType("Module/Users", "d")), "D<number, number, number>"); CHECK_EQ(toString(requireType(XorStr("Module/Users", "d")), "D<number, number, number>"));
CHECK_EQ(toString(requireType("Module/Users", "e")), "E<string, number>"); CHECK_EQ(toString(requireType(XorStr("Module/Users", "e")), "E<string, number>"));
CHECK_EQ(toString(requireType("Module/Users", "eVoid")), "E<>"); CHECK_EQ(toString(requireType(XorStr("Module/Users", "eVoid")), "E<>"));
CHECK_EQ(toString(requireType("Module/Users", "f")), "F<number, ...number>"); CHECK_EQ(toString(requireType(XorStr("Module/Users", "f")), "F<number, ...number>"));
CHECK_EQ(toString(requireType("Module/Users", "g")), "G<...number, ()>"); CHECK_EQ(toString(requireType(XorStr("Module/Users", "g")), "G<...number, ()>"));
CHECK_EQ(toString(requireType("Module/Users", "h")), "H<>"); CHECK_EQ(toString(requireType(XorStr("Module/Users", "h")), "H<>"));
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_skip_brackets") TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_skip_brackets")
@ -836,9 +836,9 @@ type Y<T... = ...string> = (T...) -> number
local a: Y 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") TEST_CASE_FIXTURE(Fixture, "type_alias_defaults_confusing_types")
@ -849,10 +849,10 @@ type B = A<string, (number)>
type C = A<string, (number), (boolean)> 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(XorStr("B"), {true}), "(string, ...any) -> (number, ...any)"));
CHECK_EQ(toString(*lookupType("C"), {true}), "(string, boolean) -> (number, boolean)"); CHECK_EQ(toString(*lookupType(XorStr("C"), {true}), "(string, boolean) -> (number, boolean)"));
} }
TEST_CASE_FIXTURE(Fixture, "type_alias_defaults_recursive_type") 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> } 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") TEST_CASE_FIXTURE(Fixture, "pack_tail_unification_check")
@ -875,7 +875,7 @@ local b: () -> (number, ...boolean)
a = b 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)' CHECK_EQ(toString(result.errors[0]), R"(Type '() -> (number, ...boolean)' could not be converted into '() -> (number, ...string)'
caused by: caused by:
Type 'boolean' could not be converted into 'string')"); 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(...) a(...)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
REQUIRE(bool(getMainModule()->getModuleScope()->varargPack)); 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") TEST_CASE_FIXTURE(BuiltinsFixture, "detect_cyclic_typepacks2")
@ -961,7 +961,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "detect_cyclic_typepacks2")
end end
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_SUITE_END(); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
LUAU_FASTFLAG(LuauLowerBoundsCalculation) lluz_FASTFLAG(LluLowerBoundsCalculation)
LUAU_FASTFLAG(LuauSpecialTypesAsterisked)
using namespace Luau; using namespace lluz;
TEST_SUITE_BEGIN("UnionTypes"); TEST_SUITE_BEGIN(XorStr("UnionTypes"));
TEST_CASE_FIXTURE(Fixture, "return_types_can_be_disjoint") TEST_CASE_FIXTURE(Fixture, "return_types_can_be_disjoint")
{ {
@ -27,7 +26,7 @@ TEST_CASE_FIXTURE(Fixture, "return_types_can_be_disjoint")
end end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* utv = get<FunctionTypeVar>(requireType("most_of_the_natural_numbers")); const FunctionTypeVar* utv = get<FunctionTypeVar>(requireType("most_of_the_natural_numbers"));
REQUIRE(utv != nullptr); REQUIRE(utv != nullptr);
@ -39,7 +38,7 @@ TEST_CASE_FIXTURE(Fixture, "allow_specific_assign")
local a:number|string = 22 local a:number|string = 22
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "allow_more_specific_assign") 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 local b:number|string|nil = a
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "disallow_less_specific_assign") TEST_CASE_FIXTURE(Fixture, "disallow_less_specific_assign")
@ -60,7 +59,7 @@ TEST_CASE_FIXTURE(Fixture, "disallow_less_specific_assign")
a = b a = b
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
} }
TEST_CASE_FIXTURE(Fixture, "disallow_less_specific_assign2") TEST_CASE_FIXTURE(Fixture, "disallow_less_specific_assign2")
@ -82,7 +81,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_arguments")
f("s") f("s")
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "optional_arguments_table") TEST_CASE_FIXTURE(Fixture, "optional_arguments_table")
@ -92,7 +91,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_arguments_table")
a = {a="ok"} a = {a="ok"}
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "optional_arguments_table2") TEST_CASE_FIXTURE(Fixture, "optional_arguments_table2")
@ -111,7 +110,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "error_takes_optional_arguments")
error("message", 2) error("message", 2)
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "error_optional_argument_enforces_type") 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 local r = t.x
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.numberType, *requireType("r")); 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 local r = t.x
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number | string", toString(requireType("r"))); 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 local r = t.x.y.z.thing
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number | string", toString(requireType("r"))); 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 local r = t.x
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ("number?", toString(requireType("r"))); 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 local r = t.x
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
MissingUnionProperty* mup = get<MissingUnionProperty>(result.errors[0]); MissingUnionProperty* mup = get<MissingUnionProperty>(result.errors[0]);
REQUIRE(mup); REQUIRE(mup);
CHECK_EQ(mup->type, requireType("t")); CHECK_EQ(mup->type, requireType("t"));
REQUIRE(mup->missing.size() == 1); REQUIRE(mup->missing.size() == 1);
std::optional<TypeId> bTy = lookupType("B"); std::optional<TypeId> bTy = lookupType(XorStr("B"));
REQUIRE(bTy); REQUIRE(bTy);
CHECK_EQ(mup->missing[0], *bTy); CHECK_EQ(mup->missing[0], *bTy);
CHECK_EQ(mup->key, "x"); CHECK_EQ(mup->key, XorStr("x"));
if (FFlag::LuauSpecialTypesAsterisked) CHECK_EQ("*unknown*", toString(requireType("r")));
CHECK_EQ("*error-type*", toString(requireType("r")));
else
CHECK_EQ("<error-type>", toString(requireType("r")));
} }
TEST_CASE_FIXTURE(Fixture, "index_on_a_union_type_with_one_property_of_type_any") 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 local r = t.x
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
CHECK_EQ(*typeChecker.anyType, *requireType("r")); CHECK_EQ(*typeChecker.anyType, *requireType("r"));
} }
@ -237,7 +233,7 @@ TEST_CASE_FIXTURE(Fixture, "union_equality_comparisons")
local z = a == c local z = a == c
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "optional_union_members") TEST_CASE_FIXTURE(Fixture, "optional_union_members")
@ -250,7 +246,7 @@ local bf = b
local c = bf.a.y 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(*typeChecker.numberType, *requireType("c"));
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[0]));
} }
@ -265,7 +261,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_union_functions")
local c = b.foo(1, 2) 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(*typeChecker.numberType, *requireType("c"));
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[0]));
} }
@ -280,7 +276,7 @@ local b: A? = a
local c = b:foo(1, 2) 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(*typeChecker.numberType, *requireType("c"));
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[0]));
} }
@ -294,7 +290,7 @@ local function f(a: number, b: typeof(x), c: typeof(x)) return -a end
return f() return f()
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
auto acm = get<CountMismatch>(result.errors[0]); auto acm = get<CountMismatch>(result.errors[0]);
REQUIRE(acm); REQUIRE(acm);
@ -312,7 +308,7 @@ local c = b.x
local d = b.y 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[0]));
CHECK_EQ("Value of type 'A?' could be nil", toString(result.errors[1])); 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])); 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] 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])); 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) 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])); 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 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])); CHECK_EQ("Value of type 'A?' could be nil", toString(result.errors[0]));
result = check(R"( result = check(R"(
@ -359,8 +355,8 @@ local a: A? = { x = 2, y = 3 }
a.x = 2 a.x = 2
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
if (FFlag::LuauLowerBoundsCalculation) if (FFlag::LluLowerBoundsCalculation)
CHECK_EQ("Value of type '{| x: number, y: number |}?' could be nil", toString(result.errors[0])); CHECK_EQ("Value of type '{| x: number, y: number |}?' could be nil", toString(result.errors[0]));
else else
CHECK_EQ("Value of type '({| x: number |} & {| y: number |})?' could be nil", toString(result.errors[0])); 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 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])); 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 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("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])); 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 y = x
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
result = check(R"( result = check(R"(
local x = { x = 3 } local x = { x = 3 }
@ -427,7 +423,7 @@ y.y = a
y = x y = x
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "unify_sealed_table_union_check") TEST_CASE_FIXTURE(Fixture, "unify_sealed_table_union_check")
@ -446,7 +442,7 @@ y.y = 5
local oh : boolean = t.y local oh : boolean = t.y
)"); )");
LUAU_REQUIRE_ERRORS(result); lluz_REQUIRE_ERRORS(result);
} }
TEST_CASE_FIXTURE(Fixture, "error_detailed_union_part") TEST_CASE_FIXTURE(Fixture, "error_detailed_union_part")
@ -462,7 +458,7 @@ local a: XYZ
local b: { w: number } = a 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 |}' CHECK_EQ(toString(result.errors[0]), R"(Type 'X | Y | Z' could not be converted into '{| w: number |}'
caused by: caused by:
Not all union options are compatible. Table type 'X' not compatible with type '{| w: number |}' because the former is missing field 'w')"); 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 } local a: XYZ = { 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 | Y | Z'; none of the union options are compatible)"); 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") TEST_CASE_FIXTURE(Fixture, "error_detailed_optional")
@ -492,7 +488,7 @@ type X = { x: number }
local a: X? = { w = 4 } 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?' CHECK_EQ(toString(result.errors[0]), R"(Type 'a' could not be converted into 'X?'
caused by: 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')"); 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 end
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); lluz_REQUIRE_NO_ERRORS(result);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "table_union_write_indirect") TEST_CASE_FIXTURE(BuiltinsFixture, "table_union_write_indirect")
@ -530,15 +526,15 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_union_write_indirect")
end end
)"); )");
LUAU_REQUIRE_ERROR_COUNT(1, result); lluz_REQUIRE_ERROR_COUNT(1, result);
// NOTE: union normalization will improve this message // 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" CHECK_EQ(toString(result.errors[0]), "Type '(string) -> number' could not be converted into '(number) -> string'\n"
"caused by:\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 else
CHECK_EQ(toString(result.errors[0]), 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
namespace namespace
{ {
@ -25,7 +25,7 @@ struct TypePackFixture
TypePackId freshTypePack() TypePackId freshTypePack()
{ {
typePacks.emplace_back(new TypePackVar{Unifiable::Free{TypeLevel{}}}); typePacks.emplace_back(new TypePackVar{Unifiable::Free{{}}});
return typePacks.back().get(); return typePacks.back().get();
} }
@ -43,7 +43,7 @@ struct TypePackFixture
} // namespace } // namespace
TEST_SUITE_BEGIN("TypePackTests"); TEST_SUITE_BEGIN(XorStr("TypePackTests"));
TEST_CASE_FIXTURE(TypePackFixture, "type_pack_hello") TEST_CASE_FIXTURE(TypePackFixture, "type_pack_hello")
{ {
@ -199,6 +199,8 @@ TEST_CASE_FIXTURE(TypePackFixture, "std_distance")
TEST_CASE("content_reassignment") TEST_CASE("content_reassignment")
{ {
ScopedFastFlag lluzNonCopyableTypeVarFields{"lluzNonCopyableTypeVarFields", true};
TypePackVar myError{Unifiable::Error{}, /*presistent*/ true}; TypePackVar myError{Unifiable::Error{}, /*presistent*/ true};
TypeArena arena; 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 // 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 "lluz/Scope.h"
#include "Luau/TypeInfer.h" #include "lluz/TypeInfer.h"
#include "Luau/TypeVar.h" #include "lluz/TypeVar.h"
#include "Luau/VisitTypeVar.h" #include "lluz/VisitTypeVar.h"
#include "Fixture.h" #include "Fixture.h"
#include "ScopedFlags.h" #include "ScopedFlags.h"
#include "doctest.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") 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)); auto returnsTwo = TypeVar(FunctionTypeVar(typeChecker.globalScope->level, &emptyArgumentPack, &returnPack));
std::string res = toString(&returnsTwo); std::string res = toString(&returnsTwo);
CHECK_EQ(res, "() -> (number, a...)"); CHECK_EQ(res, XorStr("() -> (number, a...)"));
} }
TEST_CASE_FIXTURE(Fixture, "subset_check") TEST_CASE_FIXTURE(Fixture, "subset_check")
@ -266,17 +266,17 @@ TEST_CASE_FIXTURE(Fixture, "substitution_skip_failure")
TEST_CASE("tagging_tables") TEST_CASE("tagging_tables")
{ {
TypeVar ttv{TableTypeVar{}}; TypeVar ttv{TableTypeVar{}};
CHECK(!Luau::hasTag(&ttv, "foo")); CHECK(!lluz::hasTag(&ttv, "foo"));
Luau::attachTag(&ttv, "foo"); lluz::attachTag(&ttv, XorStr("foo"));
CHECK(Luau::hasTag(&ttv, "foo")); CHECK(lluz::hasTag(&ttv, "foo"));
} }
TEST_CASE("tagging_classes") TEST_CASE("tagging_classes")
{ {
TypeVar base{ClassTypeVar{"Base", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}}; TypeVar base{ClassTypeVar{"Base", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}};
CHECK(!Luau::hasTag(&base, "foo")); CHECK(!lluz::hasTag(&base, "foo"));
Luau::attachTag(&base, "foo"); lluz::attachTag(&base, XorStr("foo"));
CHECK(Luau::hasTag(&base, "foo")); CHECK(lluz::hasTag(&base, "foo"));
} }
TEST_CASE("tagging_subclasses") TEST_CASE("tagging_subclasses")
@ -284,33 +284,33 @@ TEST_CASE("tagging_subclasses")
TypeVar base{ClassTypeVar{"Base", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}}; TypeVar base{ClassTypeVar{"Base", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}};
TypeVar derived{ClassTypeVar{"Derived", {}, &base, std::nullopt, {}, nullptr, "Test"}}; TypeVar derived{ClassTypeVar{"Derived", {}, &base, std::nullopt, {}, nullptr, "Test"}};
CHECK(!Luau::hasTag(&base, "foo")); CHECK(!lluz::hasTag(&base, "foo"));
CHECK(!Luau::hasTag(&derived, "foo")); CHECK(!lluz::hasTag(&derived, "foo"));
Luau::attachTag(&base, "foo"); lluz::attachTag(&base, XorStr("foo"));
CHECK(Luau::hasTag(&base, "foo")); CHECK(lluz::hasTag(&base, "foo"));
CHECK(Luau::hasTag(&derived, "foo")); CHECK(lluz::hasTag(&derived, "foo"));
Luau::attachTag(&derived, "bar"); lluz::attachTag(&derived, XorStr("bar"));
CHECK(!Luau::hasTag(&base, "bar")); CHECK(!lluz::hasTag(&base, "bar"));
CHECK(Luau::hasTag(&derived, "bar")); CHECK(lluz::hasTag(&derived, "bar"));
} }
TEST_CASE("tagging_functions") TEST_CASE("tagging_functions")
{ {
TypePackVar empty{TypePack{}}; TypePackVar empty{TypePack{}};
TypeVar ftv{FunctionTypeVar{&empty, &empty}}; TypeVar ftv{FunctionTypeVar{&empty, &empty}};
CHECK(!Luau::hasTag(&ftv, "foo")); CHECK(!lluz::hasTag(&ftv, "foo"));
Luau::attachTag(&ftv, "foo"); lluz::attachTag(&ftv, XorStr("foo"));
CHECK(Luau::hasTag(&ftv, "foo")); CHECK(lluz::hasTag(&ftv, "foo"));
} }
TEST_CASE("tagging_props") TEST_CASE("tagging_props")
{ {
Property prop{}; Property prop{};
CHECK(!Luau::hasTag(prop, "foo")); CHECK(!lluz::hasTag(prop, "foo"));
Luau::attachTag(prop, "foo"); lluz::attachTag(prop, XorStr("foo"));
CHECK(Luau::hasTag(prop, "foo")); CHECK(lluz::hasTag(prop, "foo"));
} }
struct VisitCountTracker final : TypeVarOnceVisitor struct VisitCountTracker final : TypeVarOnceVisitor
@ -352,9 +352,9 @@ TEST_CASE_FIXTURE(Fixture, "visit_once")
type T = { a: number, b: () -> () } type T = { a: number, b: () -> () }
local b: (T, T, T) -> T 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; VisitCountTracker tester;
tester.traverse(bType); tester.traverse(bType);
@ -418,6 +418,8 @@ TEST_CASE("proof_that_isBoolean_uses_all_of")
TEST_CASE("content_reassignment") TEST_CASE("content_reassignment")
{ {
ScopedFastFlag lluzNonCopyableTypeVarFields{"lluzNonCopyableTypeVarFields", true};
TypeVar myAny{AnyTypeVar{}, /*presistent*/ true}; TypeVar myAny{AnyTypeVar{}, /*presistent*/ true};
myAny.normal = true; myAny.normal = true;
myAny.documentationSymbol = "@global/any"; myAny.documentationSymbol = "@global/any";
@ -430,7 +432,7 @@ TEST_CASE("content_reassignment")
CHECK(get<AnyTypeVar>(futureAny) != nullptr); CHECK(get<AnyTypeVar>(futureAny) != nullptr);
CHECK(!futureAny->persistent); CHECK(!futureAny->persistent);
CHECK(futureAny->normal); CHECK(futureAny->normal);
CHECK(futureAny->documentationSymbol == "@global/any"); CHECK(futureAny->documentationSymbol == XorStr("@global/any"));
CHECK(futureAny->owningArena == &arena); 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Variant.h" #include "lluz/Variant.h"
#include <string> #include <string>
#include <ostream> #include <ostream>
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace lluz;
struct Foo struct Foo
{ {
@ -32,7 +32,7 @@ struct Bar
int Bar::count = 0; int Bar::count = 0;
TEST_SUITE_BEGIN("Variant"); TEST_SUITE_BEGIN(XorStr("Variant"));
TEST_CASE("DefaultCtor") TEST_CASE("DefaultCtor")
{ {
@ -94,42 +94,42 @@ TEST_CASE("NonPOD")
std::string s1 = "hello"; std::string s1 = "hello";
Variant<std::string, int> v1 = s1; Variant<std::string, int> v1 = s1;
CHECK(*get_if<std::string>(&v1) == "hello"); CHECK(*get_if<std::string>(&v1) == XorStr("hello"));
// initialize (move) // 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 // 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 // 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; 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 // copy ctor
Variant<std::string, int> v3 = v2; 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>(&v2) == XorStr("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>(&v3) == XorStr("this is another long string, and this time we're copying it"));
// move ctor // move ctor
Variant<std::string, int> v4 = std::move(v3); 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>(&v2) == XorStr("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>(&v3) == XorStr("")); // 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>(&v4) == XorStr("this is another long string, and this time we're copying it"));
} }
TEST_CASE("Equality") TEST_CASE("Equality")
{ {
Variant<int, std::string> v1 = std::string("hi"); Variant<int, std::string> v1 = std::string(XorStr("hi"));
Variant<int, std::string> v2 = std::string("me"); Variant<int, std::string> v2 = std::string(XorStr("me"));
Variant<int, std::string> v3 = 1; Variant<int, std::string> v3 = 1;
Variant<int, std::string> v4 = 0; Variant<int, std::string> v4 = 0;
Variant<int, std::string> v5; Variant<int, std::string> v5;
@ -169,7 +169,7 @@ struct IncrementVisitor
TEST_CASE("Visit") 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; Variant<std::string, int> v2 = 45;
const Variant<std::string, int>& v1c = v1; const Variant<std::string, int>& v1c = v1;
const Variant<std::string, int>& v2c = v2; const Variant<std::string, int>& v2c = v2;
@ -186,19 +186,19 @@ TEST_CASE("Visit")
r1 += ToStringVisitor()(v); r1 += ToStringVisitor()(v);
}, },
v2c); v2c);
CHECK(r1 == "12345"); CHECK(r1 == XorStr("12345"));
// value-returning visitor, const variants // value-returning visitor, const variants
std::string r2; std::string r2;
r2 += visit(ToStringVisitor(), v1c); r2 += visit(ToStringVisitor(), v1c);
r2 += visit(ToStringVisitor(), v2c); r2 += visit(ToStringVisitor(), v2c);
CHECK(r2 == "12345"); CHECK(r2 == XorStr("12345"));
// void-returning visitor, mutable variant // void-returning visitor, mutable variant
visit(IncrementVisitor(), v1); visit(IncrementVisitor(), v1);
visit(IncrementVisitor(), v2); visit(IncrementVisitor(), v2);
CHECK(visit(ToStringVisitor(), v1) == "1231"); CHECK(visit(ToStringVisitor(), v1) == XorStr("1231"));
CHECK(visit(ToStringVisitor(), v2) == "46"); CHECK(visit(ToStringVisitor(), v2) == XorStr("46"));
// value-returning visitor, mutable variant // value-returning visitor, mutable variant
std::string r3; std::string r3;
@ -214,7 +214,7 @@ TEST_CASE("Visit")
return ToStringVisitor()(v); return ToStringVisitor()(v);
}, },
v2); v2);
CHECK(r3 == "1231147"); CHECK(r3 == XorStr("1231147"));
} }
TEST_SUITE_END(); 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 "Fixture.h"
#include "Luau/RecursionCounter.h" #include "lluz/RecursionCounter.h"
#include "doctest.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") TEST_CASE_FIXTURE(Fixture, "throw_when_limit_is_exceeded")
{ {
ScopedFastInt sfi{"LuauVisitRecursionLimit", 3}; ScopedFastInt sfi{"lluzVisitRecursionLimit", 3};
CheckResult result = check(R"( CheckResult result = check(R"(
local t : {a: {b: {c: {d: {e: boolean}}}}} local t : {a: {b: {c: {d: {e: boolean}}}}}
)"); )");
TypeId tType = requireType("t"); TypeId tType = requireType(XorStr("t"));
CHECK_THROWS_AS(toString(tType), RecursionLimitException); CHECK_THROWS_AS(toString(tType), RecursionLimitException);
} }
TEST_CASE_FIXTURE(Fixture, "dont_throw_when_limit_is_high_enough") TEST_CASE_FIXTURE(Fixture, "dont_throw_when_limit_is_high_enough")
{ {
ScopedFastInt sfi{"LuauVisitRecursionLimit", 8}; ScopedFastInt sfi{"lluzVisitRecursionLimit", 8};
CheckResult result = check(R"( CheckResult result = check(R"(
local t : {a: {b: {c: {d: {e: boolean}}}}} local t : {a: {b: {c: {d: {e: boolean}}}}}
)"); )");
TypeId tType = requireType("t"); TypeId tType = requireType(XorStr("t"));
(void)toString(tType); (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) assert(vector(1, 2, 3, 4).W == 4)
end 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' 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 // This file is part of the lluz programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Common.h" #include "lluz/Common.h"
#define DOCTEST_CONFIG_IMPLEMENT #define DOCTEST_CONFIG_IMPLEMENT
// Our calls to parseOption/parseFlag don't provide a prefix so set the prefix to the empty string. // Our calls to parseOption/parseFlag don't provide a prefix so set the prefix to the empty string.
@ -23,13 +23,10 @@
#include <optional> #include <optional>
// Indicates if verbose output is enabled; can be overridden via --verbose // Indicates if verbose output is enabled.
// Currently, this enables output from 'print', but other verbose output could be enabled eventually. // Currently, this enables output from lua's 'print', but other verbose output could be enabled eventually.
bool verbose = false; bool verbose = false;
// Default optimization level for conformance test; can be overridden via -On
int optimizationLevel = 1;
static bool skipFastFlag(const char* flagName) static bool skipFastFlag(const char* flagName)
{ {
if (strncmp(flagName, "Test", 4) == 0) 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) static int testAssertionHandler(const char* expr, const char* file, int line, const char* function)
{ {
if (debuggerPresent()) 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; return 1;
} }
@ -103,7 +100,7 @@ struct BoostLikeReporter : doctest::IReporter
// called when a test case has ended // called when a test case has ended
void test_case_end(const doctest::CurrentTestCaseStats& tc) override 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 case \"%s\"\n", currentTest->m_name);
printf("Leaving test suite \"%s\"\n", currentTest->m_test_suite); 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) // called when an exception is thrown from the test case (or it crashes)
void test_case_exception(const doctest::TestCaseException& e) override 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()); 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. // If we have a flag name but there's no provided value, we default to true.
auto [name, value] = parseFValueHelper(view); auto [name, value] = parseFValueHelper(view);
bool state = value ? *value == "true" : true; bool state = value ? *value == XorStr("true") : true;
if (value && value != "true" && value != "false") if (value && value != "true" && value != "false")
std::cerr << "Ignored '" << name << "' because '" << *value << "' is not a valid FFlag state." << std::endl; 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> template<typename T>
static void setFastValue(const std::string& name, T value) 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) if (fvalue->name == name)
fvalue->value = value; fvalue->value = value;
} }
@ -194,12 +191,12 @@ static void setFastFlags(const std::vector<doctest::String>& flags)
for (const doctest::String& flag : flags) for (const doctest::String& flag : flags)
{ {
std::string_view view = flag.c_str(); 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)) if (!skipFastFlag(flag->name))
flag->value = view == "true"; flag->value = view == XorStr("true");
} }
continue; continue;
@ -208,15 +205,15 @@ static void setFastFlags(const std::vector<doctest::String>& flags)
if (view.size() >= 2 && view[0] == 'D' && view[1] == 'F') if (view.size() >= 2 && view[0] == 'D' && view[1] == 'F')
view.remove_prefix(1); view.remove_prefix(1);
if (view.substr(0, 4) == "FInt") if (view.substr(0, 4) == XorStr("FInt"))
{ {
auto [name, value] = parseFInt(view.substr(4)); auto [name, value] = parseFInt(view.substr(4));
setFastValue(name, value); setFastValue(name, value);
} }
else else
{ {
// We want to prevent the footgun where '--fflags=LuauSomeFlag' is ignored. We'll assume that this was declared as FFlag. // 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) == "FFlag" ? view.substr(5) : view); auto [name, value] = parseFFlag(view.substr(0, 5) == XorStr("FFlag") ? view.substr(5) : view);
setFastValue(name, value); setFastValue(name, value);
} }
} }
@ -224,7 +221,7 @@ static void setFastFlags(const std::vector<doctest::String>& flags)
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
Luau::assertHandler() = testAssertionHandler; lluz::assertHandler() = testAssertionHandler;
doctest::registerReporter<BoostLikeReporter>("boost", 0, true); doctest::registerReporter<BoostLikeReporter>("boost", 0, true);
@ -234,7 +231,7 @@ int main(int argc, char** argv)
if (doctest::parseFlag(argc, argv, "--list-fflags")) 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)) if (skipFastFlag(flag->name))
continue; continue;
@ -252,15 +249,6 @@ int main(int argc, char** argv)
verbose = true; 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)) if (std::vector<doctest::String> flags; doctest::parseCommaSepArgs(argc, argv, "--fflags=", flags))
setFastFlags(flags); setFastFlags(flags);
@ -290,11 +278,12 @@ int main(int argc, char** argv)
int result = context.run(); int result = context.run();
if (doctest::parseFlag(argc, argv, "--help") || doctest::parseFlag(argc, argv, "-h")) if (doctest::parseFlag(argc, argv, "--help") || doctest::parseFlag(argc, argv, "-h"))
{ {
printf("Additional command line options:\n"); printf(XorStr("Additional command line options:\n"));
printf(" -O[n] Changes default optimization level (1) for conformance runs\n"); printf(XorStr(" --verbose Enables verbose output (e.g. lua 'print' statements)\n"));
printf(" --verbose Enables verbose output (e.g. lua 'print' statements)\n"); printf(XorStr(" --fflags= Sets specified fast flags\n"));
printf(" --fflags= Sets specified fast flags\n"); printf(XorStr(" --list-fflags List all fast flags\n"));
printf(" --list-fflags List all fast flags\n");
} }
return result; return result;
} }