Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Analysis/src/TypeFunctionRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <vector>

LUAU_DYNAMIC_FASTINT(LuauTypeFunctionSerdeIterationLimit)
LUAU_FASTFLAGVARIABLE(DebugLuauTypeFunExternNameMethod)

namespace Luau
{
Expand Down Expand Up @@ -1312,6 +1313,24 @@ static int getWriteParent(lua_State* L)
return 1;
}

// Luau: `self:externname() -> string?`
// Returns the name of a class or 'nil' if there's no name.
static int getExternTypeName(lua_State* L) {
TypeFunctionTypeId self = getTypeUserData(L, 1);
auto tfEx = get<TypeFunctionExternType>(self);
if (!tfEx)
luaL_error(L, "type.externname: expected self to be an extern type, but got %s instead", getTag(L, self).c_str());

if (auto exTy = get<ExternType>(tfEx->externTy))
{
lua_pushstring(L, exTy->name.c_str());
}
else
lua_pushnil(L);

return 1;
}

// Luau: `self:name() -> string?`
// Returns the name of the generic or 'nil' if the generic is unnamed
static int getGenericName(lua_State* L)
Expand Down Expand Up @@ -1747,6 +1766,7 @@ void registerTypeUserData(lua_State* L)
{"name", getGenericName},
{"ispack", getGenericIsPack},

{(FFlag::DebugLuauTypeFunExternNameMethod) ? "externname" : nullptr, (FFlag::DebugLuauTypeFunExternNameMethod) ? getExternTypeName : nullptr},
{nullptr, nullptr}
};

Expand Down
30 changes: 30 additions & 0 deletions tests/TypeFunction.user.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ LUAU_FASTFLAG(LuauEagerGeneralization4)
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
LUAU_FASTFLAG(LuauResetConditionalContextProperly)
LUAU_FASTFLAG(LuauTypeFunNoScopeMapRef)
LUAU_FASTFLAG(DebugLuauTypeFunExternNameMethod)

TEST_SUITE_BEGIN("UserDefinedTypeFunctionTests");

Expand Down Expand Up @@ -2452,6 +2453,35 @@ end
CHECK(toString(result.errors[0]) == R"(Redefinition of type 't0', previously defined at line 2)");
}

TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_externtype_externname_api")
{
ScopedFastFlag sff[]{
{FFlag::LuauSolverV2, true},
{FFlag::DebugLuauTypeFunExternNameMethod, true}
};

loadDefinition(R"(
declare class CustomClass
function testFunc(self): number
end
)");

CheckResult result = check(R"(
type function pass(arg, compare)
if (arg:is("class")) then
assert(arg:externname() == compare:value())
end

return types.unknown
end

type a = pass<CustomClass, "CustomClass">
type b = pass<vector, "vector">
)");

LUAU_REQUIRE_NO_ERRORS(result);
}

TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_fuzz_environment_scope_crash")
{
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
Expand Down
Loading