Analysis: Make typeof on a type userdata return "type" (#1568)

This change introduces a flag (`LuauUserTypeFunTypeofReturnsType`) that,
when enabled, sets `__type` on the type userdata's metatable to "type".
This behaviour was described in the user-defined type function RFC
(https://rfcs.luau.org/user-defined-type-functions.html), but seems to
have been missed; this change implements that behaviour.

Currently this does not change `typeof(t) == 'type'` emitting an unknown
type warning as I don't trust myself to implement it due to my general
lack of C++ knowledge; this can be worked on later.
This commit is contained in:
nothing 2025-02-18 04:36:52 +11:00 committed by GitHub
parent bd4fe54f4b
commit 9c198413ec
Signed by: DevComp
GPG key ID: B5690EEEBB952194
2 changed files with 26 additions and 0 deletions

View file

@ -14,6 +14,7 @@
#include <vector> #include <vector>
LUAU_DYNAMIC_FASTINT(LuauTypeFunctionSerdeIterationLimit) LUAU_DYNAMIC_FASTINT(LuauTypeFunctionSerdeIterationLimit)
LUAU_FASTFLAGVARIABLE(LuauUserTypeFunTypeofReturnsType)
namespace Luau namespace Luau
{ {
@ -1564,6 +1565,12 @@ void registerTypeUserData(lua_State* L)
// Create and register metatable for type userdata // Create and register metatable for type userdata
luaL_newmetatable(L, "type"); luaL_newmetatable(L, "type");
if (FFlag::LuauUserTypeFunTypeofReturnsType)
{
lua_pushstring(L, "type");
lua_setfield(L, -2, "__type");
}
// Protect metatable from being changed // Protect metatable from being changed
lua_pushstring(L, "The metatable is locked"); lua_pushstring(L, "The metatable is locked");

View file

@ -9,6 +9,7 @@ using namespace Luau;
LUAU_FASTFLAG(LuauSolverV2) LUAU_FASTFLAG(LuauSolverV2)
LUAU_FASTFLAG(DebugLuauEqSatSimplification) LUAU_FASTFLAG(DebugLuauEqSatSimplification)
LUAU_FASTFLAG(LuauUserTypeFunTypeofReturnsType)
TEST_SUITE_BEGIN("UserDefinedTypeFunctionTests"); TEST_SUITE_BEGIN("UserDefinedTypeFunctionTests");
@ -1866,4 +1867,22 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_eqsat_opaque")
CHECK_EQ("t0<number & string>", toString(simplified->result)); // NOLINT(bugprone-unchecked-optional-access) CHECK_EQ("t0<number & string>", toString(simplified->result)); // NOLINT(bugprone-unchecked-optional-access)
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "typeof_type_userdata_returns_type")
{
ScopedFastFlag solverV2{FFlag::LuauSolverV2, true};
ScopedFastFlag luauUserTypeFunTypeofReturnsType{FFlag::LuauUserTypeFunTypeofReturnsType, true};
CheckResult result = check(R"(
type function test(t)
print(typeof(t))
return t
end
local _:test<number>
)");
LUAU_REQUIRE_ERROR_COUNT(1, result);
CHECK(toString(result.errors[0]) == R"(type)");
}
TEST_SUITE_END(); TEST_SUITE_END();