2022-04-07 22:29:01 +01:00
|
|
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
|
|
|
|
|
|
#include "Luau/Clone.h"
|
|
|
|
#include "Luau/RecursionCounter.h"
|
2022-06-03 23:15:45 +01:00
|
|
|
#include "Luau/TxnLog.h"
|
2022-04-07 22:29:01 +01:00
|
|
|
#include "Luau/TypePack.h"
|
|
|
|
#include "Luau/Unifiable.h"
|
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
LUAU_FASTFLAG(DebugLuauCopyBeforeNormalizing)
|
2022-08-11 22:01:33 +01:00
|
|
|
LUAU_FASTFLAG(LuauClonePublicInterfaceLess)
|
2022-04-15 00:57:43 +01:00
|
|
|
|
2022-04-07 22:29:01 +01:00
|
|
|
LUAU_FASTINTVARIABLE(LuauTypeCloneRecursionLimit, 300)
|
|
|
|
|
|
|
|
namespace Luau
|
|
|
|
{
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
struct TypePackCloner;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Both TypeCloner and TypePackCloner work by depositing the requested type variable into the appropriate 'seen' set.
|
|
|
|
* They do not return anything because their sole consumer (the deepClone function) already has a pointer into this storage.
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct TypeCloner
|
|
|
|
{
|
2022-04-15 00:57:43 +01:00
|
|
|
TypeCloner(TypeArena& dest, TypeId typeId, CloneState& cloneState)
|
2022-04-07 22:29:01 +01:00
|
|
|
: dest(dest)
|
|
|
|
, typeId(typeId)
|
2022-04-15 00:57:43 +01:00
|
|
|
, seenTypes(cloneState.seenTypes)
|
|
|
|
, seenTypePacks(cloneState.seenTypePacks)
|
2022-04-07 22:29:01 +01:00
|
|
|
, cloneState(cloneState)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeArena& dest;
|
|
|
|
TypeId typeId;
|
|
|
|
SeenTypes& seenTypes;
|
|
|
|
SeenTypePacks& seenTypePacks;
|
|
|
|
CloneState& cloneState;
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void defaultClone(const T& t);
|
|
|
|
|
|
|
|
void operator()(const Unifiable::Free& t);
|
|
|
|
void operator()(const Unifiable::Generic& t);
|
|
|
|
void operator()(const Unifiable::Bound<TypeId>& t);
|
|
|
|
void operator()(const Unifiable::Error& t);
|
2022-06-17 02:05:14 +01:00
|
|
|
void operator()(const BlockedTypeVar& t);
|
2022-08-04 23:35:33 +01:00
|
|
|
void operator()(const PendingExpansionTypeVar& t);
|
2022-04-07 22:29:01 +01:00
|
|
|
void operator()(const PrimitiveTypeVar& t);
|
2022-04-15 00:57:43 +01:00
|
|
|
void operator()(const ConstrainedTypeVar& t);
|
2022-04-07 22:29:01 +01:00
|
|
|
void operator()(const SingletonTypeVar& t);
|
|
|
|
void operator()(const FunctionTypeVar& t);
|
|
|
|
void operator()(const TableTypeVar& t);
|
|
|
|
void operator()(const MetatableTypeVar& t);
|
|
|
|
void operator()(const ClassTypeVar& t);
|
|
|
|
void operator()(const AnyTypeVar& t);
|
|
|
|
void operator()(const UnionTypeVar& t);
|
|
|
|
void operator()(const IntersectionTypeVar& t);
|
|
|
|
void operator()(const LazyTypeVar& t);
|
2022-07-08 02:22:39 +01:00
|
|
|
void operator()(const UnknownTypeVar& t);
|
|
|
|
void operator()(const NeverTypeVar& t);
|
2022-04-07 22:29:01 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
struct TypePackCloner
|
|
|
|
{
|
|
|
|
TypeArena& dest;
|
|
|
|
TypePackId typePackId;
|
|
|
|
SeenTypes& seenTypes;
|
|
|
|
SeenTypePacks& seenTypePacks;
|
|
|
|
CloneState& cloneState;
|
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
TypePackCloner(TypeArena& dest, TypePackId typePackId, CloneState& cloneState)
|
2022-04-07 22:29:01 +01:00
|
|
|
: dest(dest)
|
|
|
|
, typePackId(typePackId)
|
2022-04-15 00:57:43 +01:00
|
|
|
, seenTypes(cloneState.seenTypes)
|
|
|
|
, seenTypePacks(cloneState.seenTypePacks)
|
2022-04-07 22:29:01 +01:00
|
|
|
, cloneState(cloneState)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void defaultClone(const T& t)
|
|
|
|
{
|
|
|
|
TypePackId cloned = dest.addTypePack(TypePackVar{t});
|
|
|
|
seenTypePacks[typePackId] = cloned;
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const Unifiable::Free& t)
|
|
|
|
{
|
2022-05-20 01:02:24 +01:00
|
|
|
defaultClone(t);
|
2022-04-07 22:29:01 +01:00
|
|
|
}
|
|
|
|
void operator()(const Unifiable::Generic& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
void operator()(const Unifiable::Error& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
void operator()(const BlockedTypePack& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
2022-04-07 22:29:01 +01:00
|
|
|
// While we are a-cloning, we can flatten out bound TypeVars and make things a bit tighter.
|
|
|
|
// We just need to be sure that we rewrite pointers both to the binder and the bindee to the same pointer.
|
|
|
|
void operator()(const Unifiable::Bound<TypePackId>& t)
|
|
|
|
{
|
2022-04-15 00:57:43 +01:00
|
|
|
TypePackId cloned = clone(t.boundTo, dest, cloneState);
|
|
|
|
if (FFlag::DebugLuauCopyBeforeNormalizing)
|
|
|
|
cloned = dest.addTypePack(TypePackVar{BoundTypePack{cloned}});
|
2022-04-07 22:29:01 +01:00
|
|
|
seenTypePacks[typePackId] = cloned;
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const VariadicTypePack& t)
|
|
|
|
{
|
2022-04-15 00:57:43 +01:00
|
|
|
TypePackId cloned = dest.addTypePack(TypePackVar{VariadicTypePack{clone(t.ty, dest, cloneState), /*hidden*/ t.hidden}});
|
2022-04-07 22:29:01 +01:00
|
|
|
seenTypePacks[typePackId] = cloned;
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const TypePack& t)
|
|
|
|
{
|
|
|
|
TypePackId cloned = dest.addTypePack(TypePack{});
|
|
|
|
TypePack* destTp = getMutable<TypePack>(cloned);
|
|
|
|
LUAU_ASSERT(destTp != nullptr);
|
|
|
|
seenTypePacks[typePackId] = cloned;
|
|
|
|
|
|
|
|
for (TypeId ty : t.head)
|
2022-04-15 00:57:43 +01:00
|
|
|
destTp->head.push_back(clone(ty, dest, cloneState));
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
if (t.tail)
|
2022-04-15 00:57:43 +01:00
|
|
|
destTp->tail = clone(*t.tail, dest, cloneState);
|
2022-04-07 22:29:01 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void TypeCloner::defaultClone(const T& t)
|
|
|
|
{
|
|
|
|
TypeId cloned = dest.addType(t);
|
|
|
|
seenTypes[typeId] = cloned;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const Unifiable::Free& t)
|
|
|
|
{
|
2022-05-20 01:02:24 +01:00
|
|
|
defaultClone(t);
|
2022-04-07 22:29:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const Unifiable::Generic& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const Unifiable::Bound<TypeId>& t)
|
|
|
|
{
|
2022-04-15 00:57:43 +01:00
|
|
|
TypeId boundTo = clone(t.boundTo, dest, cloneState);
|
|
|
|
if (FFlag::DebugLuauCopyBeforeNormalizing)
|
|
|
|
boundTo = dest.addType(BoundTypeVar{boundTo});
|
2022-04-07 22:29:01 +01:00
|
|
|
seenTypes[typeId] = boundTo;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const Unifiable::Error& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
2022-06-17 02:05:14 +01:00
|
|
|
void TypeCloner::operator()(const BlockedTypeVar& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
2022-08-04 23:35:33 +01:00
|
|
|
void TypeCloner::operator()(const PendingExpansionTypeVar& t)
|
|
|
|
{
|
2022-09-02 00:14:03 +01:00
|
|
|
TypeId res = dest.addType(PendingExpansionTypeVar{t.prefix, t.name, t.typeArguments, t.packArguments});
|
2022-08-04 23:35:33 +01:00
|
|
|
PendingExpansionTypeVar* petv = getMutable<PendingExpansionTypeVar>(res);
|
|
|
|
LUAU_ASSERT(petv);
|
|
|
|
|
|
|
|
seenTypes[typeId] = res;
|
|
|
|
|
|
|
|
std::vector<TypeId> typeArguments;
|
|
|
|
for (TypeId arg : t.typeArguments)
|
|
|
|
typeArguments.push_back(clone(arg, dest, cloneState));
|
|
|
|
|
|
|
|
std::vector<TypePackId> packArguments;
|
|
|
|
for (TypePackId arg : t.packArguments)
|
|
|
|
packArguments.push_back(clone(arg, dest, cloneState));
|
|
|
|
|
|
|
|
petv->typeArguments = std::move(typeArguments);
|
|
|
|
petv->packArguments = std::move(packArguments);
|
|
|
|
}
|
|
|
|
|
2022-04-07 22:29:01 +01:00
|
|
|
void TypeCloner::operator()(const PrimitiveTypeVar& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
void TypeCloner::operator()(const ConstrainedTypeVar& t)
|
|
|
|
{
|
|
|
|
TypeId res = dest.addType(ConstrainedTypeVar{t.level});
|
|
|
|
ConstrainedTypeVar* ctv = getMutable<ConstrainedTypeVar>(res);
|
|
|
|
LUAU_ASSERT(ctv);
|
|
|
|
|
|
|
|
seenTypes[typeId] = res;
|
|
|
|
|
|
|
|
std::vector<TypeId> parts;
|
|
|
|
for (TypeId part : t.parts)
|
|
|
|
parts.push_back(clone(part, dest, cloneState));
|
|
|
|
|
|
|
|
ctv->parts = std::move(parts);
|
|
|
|
}
|
|
|
|
|
2022-04-07 22:29:01 +01:00
|
|
|
void TypeCloner::operator()(const SingletonTypeVar& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const FunctionTypeVar& t)
|
|
|
|
{
|
2022-09-29 23:23:10 +01:00
|
|
|
// FISHY: We always erase the scope when we clone things. clone() was
|
|
|
|
// originally written so that we could copy a module's type surface into an
|
|
|
|
// export arena. This probably dates to that.
|
2022-04-07 22:29:01 +01:00
|
|
|
TypeId result = dest.addType(FunctionTypeVar{TypeLevel{0, 0}, {}, {}, nullptr, nullptr, t.definition, t.hasSelf});
|
|
|
|
FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(result);
|
|
|
|
LUAU_ASSERT(ftv != nullptr);
|
|
|
|
|
|
|
|
seenTypes[typeId] = result;
|
|
|
|
|
|
|
|
for (TypeId generic : t.generics)
|
2022-04-15 00:57:43 +01:00
|
|
|
ftv->generics.push_back(clone(generic, dest, cloneState));
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
for (TypePackId genericPack : t.genericPacks)
|
2022-04-15 00:57:43 +01:00
|
|
|
ftv->genericPacks.push_back(clone(genericPack, dest, cloneState));
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
ftv->tags = t.tags;
|
2022-04-15 00:57:43 +01:00
|
|
|
ftv->argTypes = clone(t.argTypes, dest, cloneState);
|
2022-04-07 22:29:01 +01:00
|
|
|
ftv->argNames = t.argNames;
|
2022-06-17 02:05:14 +01:00
|
|
|
ftv->retTypes = clone(t.retTypes, dest, cloneState);
|
2022-05-20 01:02:24 +01:00
|
|
|
ftv->hasNoGenerics = t.hasNoGenerics;
|
2022-04-07 22:29:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const TableTypeVar& t)
|
|
|
|
{
|
|
|
|
// If table is now bound to another one, we ignore the content of the original
|
2022-04-15 00:57:43 +01:00
|
|
|
if (!FFlag::DebugLuauCopyBeforeNormalizing && t.boundTo)
|
2022-04-07 22:29:01 +01:00
|
|
|
{
|
2022-04-15 00:57:43 +01:00
|
|
|
TypeId boundTo = clone(*t.boundTo, dest, cloneState);
|
2022-04-07 22:29:01 +01:00
|
|
|
seenTypes[typeId] = boundTo;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeId result = dest.addType(TableTypeVar{});
|
|
|
|
TableTypeVar* ttv = getMutable<TableTypeVar>(result);
|
|
|
|
LUAU_ASSERT(ttv != nullptr);
|
|
|
|
|
|
|
|
*ttv = t;
|
|
|
|
|
|
|
|
seenTypes[typeId] = result;
|
|
|
|
|
|
|
|
ttv->level = TypeLevel{0, 0};
|
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
if (FFlag::DebugLuauCopyBeforeNormalizing && t.boundTo)
|
|
|
|
ttv->boundTo = clone(*t.boundTo, dest, cloneState);
|
|
|
|
|
2022-04-07 22:29:01 +01:00
|
|
|
for (const auto& [name, prop] : t.props)
|
2022-04-15 00:57:43 +01:00
|
|
|
ttv->props[name] = {clone(prop.type, dest, cloneState), prop.deprecated, {}, prop.location, prop.tags};
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
if (t.indexer)
|
2022-04-15 00:57:43 +01:00
|
|
|
ttv->indexer = TableIndexer{clone(t.indexer->indexType, dest, cloneState), clone(t.indexer->indexResultType, dest, cloneState)};
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
for (TypeId& arg : ttv->instantiatedTypeParams)
|
2022-04-15 00:57:43 +01:00
|
|
|
arg = clone(arg, dest, cloneState);
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
for (TypePackId& arg : ttv->instantiatedTypePackParams)
|
2022-04-15 00:57:43 +01:00
|
|
|
arg = clone(arg, dest, cloneState);
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
ttv->definitionModuleName = t.definitionModuleName;
|
|
|
|
ttv->tags = t.tags;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const MetatableTypeVar& t)
|
|
|
|
{
|
|
|
|
TypeId result = dest.addType(MetatableTypeVar{});
|
|
|
|
MetatableTypeVar* mtv = getMutable<MetatableTypeVar>(result);
|
|
|
|
seenTypes[typeId] = result;
|
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
mtv->table = clone(t.table, dest, cloneState);
|
|
|
|
mtv->metatable = clone(t.metatable, dest, cloneState);
|
2022-04-07 22:29:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const ClassTypeVar& t)
|
|
|
|
{
|
2022-04-21 22:44:27 +01:00
|
|
|
TypeId result = dest.addType(ClassTypeVar{t.name, {}, std::nullopt, std::nullopt, t.tags, t.userData, t.definitionModuleName});
|
2022-04-07 22:29:01 +01:00
|
|
|
ClassTypeVar* ctv = getMutable<ClassTypeVar>(result);
|
|
|
|
|
|
|
|
seenTypes[typeId] = result;
|
|
|
|
|
|
|
|
for (const auto& [name, prop] : t.props)
|
2022-04-15 00:57:43 +01:00
|
|
|
ctv->props[name] = {clone(prop.type, dest, cloneState), prop.deprecated, {}, prop.location, prop.tags};
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
if (t.parent)
|
2022-04-15 00:57:43 +01:00
|
|
|
ctv->parent = clone(*t.parent, dest, cloneState);
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
if (t.metatable)
|
2022-04-15 00:57:43 +01:00
|
|
|
ctv->metatable = clone(*t.metatable, dest, cloneState);
|
2022-04-07 22:29:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const AnyTypeVar& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const UnionTypeVar& t)
|
|
|
|
{
|
|
|
|
std::vector<TypeId> options;
|
|
|
|
options.reserve(t.options.size());
|
|
|
|
|
|
|
|
for (TypeId ty : t.options)
|
2022-04-15 00:57:43 +01:00
|
|
|
options.push_back(clone(ty, dest, cloneState));
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
TypeId result = dest.addType(UnionTypeVar{std::move(options)});
|
|
|
|
seenTypes[typeId] = result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const IntersectionTypeVar& t)
|
|
|
|
{
|
|
|
|
TypeId result = dest.addType(IntersectionTypeVar{});
|
|
|
|
seenTypes[typeId] = result;
|
|
|
|
|
|
|
|
IntersectionTypeVar* option = getMutable<IntersectionTypeVar>(result);
|
|
|
|
LUAU_ASSERT(option != nullptr);
|
|
|
|
|
|
|
|
for (TypeId ty : t.parts)
|
2022-04-15 00:57:43 +01:00
|
|
|
option->parts.push_back(clone(ty, dest, cloneState));
|
2022-04-07 22:29:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const LazyTypeVar& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
2022-07-08 02:22:39 +01:00
|
|
|
void TypeCloner::operator()(const UnknownTypeVar& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const NeverTypeVar& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
2022-04-07 22:29:01 +01:00
|
|
|
} // anonymous namespace
|
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
TypePackId clone(TypePackId tp, TypeArena& dest, CloneState& cloneState)
|
2022-04-07 22:29:01 +01:00
|
|
|
{
|
|
|
|
if (tp->persistent)
|
|
|
|
return tp;
|
|
|
|
|
2022-06-24 02:56:00 +01:00
|
|
|
RecursionLimiter _ra(&cloneState.recursionCount, FInt::LuauTypeCloneRecursionLimit);
|
2022-04-07 22:29:01 +01:00
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
TypePackId& res = cloneState.seenTypePacks[tp];
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
if (res == nullptr)
|
|
|
|
{
|
2022-04-15 00:57:43 +01:00
|
|
|
TypePackCloner cloner{dest, tp, cloneState};
|
2022-04-07 22:29:01 +01:00
|
|
|
Luau::visit(cloner, tp->ty); // Mutates the storage that 'res' points into.
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
TypeId clone(TypeId typeId, TypeArena& dest, CloneState& cloneState)
|
2022-04-07 22:29:01 +01:00
|
|
|
{
|
|
|
|
if (typeId->persistent)
|
|
|
|
return typeId;
|
|
|
|
|
2022-06-24 02:56:00 +01:00
|
|
|
RecursionLimiter _ra(&cloneState.recursionCount, FInt::LuauTypeCloneRecursionLimit);
|
2022-04-07 22:29:01 +01:00
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
TypeId& res = cloneState.seenTypes[typeId];
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
if (res == nullptr)
|
|
|
|
{
|
2022-04-15 00:57:43 +01:00
|
|
|
TypeCloner cloner{dest, typeId, cloneState};
|
2022-04-07 22:29:01 +01:00
|
|
|
Luau::visit(cloner, typeId->ty); // Mutates the storage that 'res' points into.
|
|
|
|
|
|
|
|
// Persistent types are not being cloned and we get the original type back which might be read-only
|
|
|
|
if (!res->persistent)
|
2022-04-21 22:44:27 +01:00
|
|
|
{
|
2022-04-07 22:29:01 +01:00
|
|
|
asMutable(res)->documentationSymbol = typeId->documentationSymbol;
|
2022-04-21 22:44:27 +01:00
|
|
|
asMutable(res)->normal = typeId->normal;
|
|
|
|
}
|
2022-04-07 22:29:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
TypeFun clone(const TypeFun& typeFun, TypeArena& dest, CloneState& cloneState)
|
2022-04-07 22:29:01 +01:00
|
|
|
{
|
|
|
|
TypeFun result;
|
|
|
|
|
|
|
|
for (auto param : typeFun.typeParams)
|
|
|
|
{
|
2022-04-15 00:57:43 +01:00
|
|
|
TypeId ty = clone(param.ty, dest, cloneState);
|
2022-04-07 22:29:01 +01:00
|
|
|
std::optional<TypeId> defaultValue;
|
|
|
|
|
|
|
|
if (param.defaultValue)
|
2022-04-15 00:57:43 +01:00
|
|
|
defaultValue = clone(*param.defaultValue, dest, cloneState);
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
result.typeParams.push_back({ty, defaultValue});
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto param : typeFun.typePackParams)
|
|
|
|
{
|
2022-04-15 00:57:43 +01:00
|
|
|
TypePackId tp = clone(param.tp, dest, cloneState);
|
2022-04-07 22:29:01 +01:00
|
|
|
std::optional<TypePackId> defaultValue;
|
|
|
|
|
|
|
|
if (param.defaultValue)
|
2022-04-15 00:57:43 +01:00
|
|
|
defaultValue = clone(*param.defaultValue, dest, cloneState);
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
result.typePackParams.push_back({tp, defaultValue});
|
|
|
|
}
|
|
|
|
|
2022-04-15 00:57:43 +01:00
|
|
|
result.type = clone(typeFun.type, dest, cloneState);
|
2022-04-07 22:29:01 +01:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-08-11 22:01:33 +01:00
|
|
|
TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool alwaysClone)
|
2022-06-03 23:15:45 +01:00
|
|
|
{
|
|
|
|
ty = log->follow(ty);
|
|
|
|
|
|
|
|
TypeId result = ty;
|
|
|
|
|
|
|
|
if (auto pty = log->pending(ty))
|
|
|
|
ty = &pty->pending;
|
|
|
|
|
|
|
|
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty))
|
|
|
|
{
|
2022-09-29 23:23:10 +01:00
|
|
|
FunctionTypeVar clone = FunctionTypeVar{ftv->level, ftv->scope, ftv->argTypes, ftv->retTypes, ftv->definition, ftv->hasSelf};
|
2022-06-03 23:15:45 +01:00
|
|
|
clone.generics = ftv->generics;
|
|
|
|
clone.genericPacks = ftv->genericPacks;
|
|
|
|
clone.magicFunction = ftv->magicFunction;
|
2022-09-02 00:14:03 +01:00
|
|
|
clone.dcrMagicFunction = ftv->dcrMagicFunction;
|
2022-06-03 23:15:45 +01:00
|
|
|
clone.tags = ftv->tags;
|
|
|
|
clone.argNames = ftv->argNames;
|
|
|
|
result = dest.addType(std::move(clone));
|
|
|
|
}
|
|
|
|
else if (const TableTypeVar* ttv = get<TableTypeVar>(ty))
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(!ttv->boundTo);
|
2022-09-29 23:23:10 +01:00
|
|
|
TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, ttv->level, ttv->scope, ttv->state};
|
2022-06-03 23:15:45 +01:00
|
|
|
clone.definitionModuleName = ttv->definitionModuleName;
|
|
|
|
clone.name = ttv->name;
|
|
|
|
clone.syntheticName = ttv->syntheticName;
|
|
|
|
clone.instantiatedTypeParams = ttv->instantiatedTypeParams;
|
|
|
|
clone.instantiatedTypePackParams = ttv->instantiatedTypePackParams;
|
|
|
|
clone.tags = ttv->tags;
|
|
|
|
result = dest.addType(std::move(clone));
|
|
|
|
}
|
|
|
|
else if (const MetatableTypeVar* mtv = get<MetatableTypeVar>(ty))
|
|
|
|
{
|
|
|
|
MetatableTypeVar clone = MetatableTypeVar{mtv->table, mtv->metatable};
|
|
|
|
clone.syntheticName = mtv->syntheticName;
|
|
|
|
result = dest.addType(std::move(clone));
|
|
|
|
}
|
|
|
|
else if (const UnionTypeVar* utv = get<UnionTypeVar>(ty))
|
|
|
|
{
|
|
|
|
UnionTypeVar clone;
|
|
|
|
clone.options = utv->options;
|
|
|
|
result = dest.addType(std::move(clone));
|
|
|
|
}
|
|
|
|
else if (const IntersectionTypeVar* itv = get<IntersectionTypeVar>(ty))
|
|
|
|
{
|
|
|
|
IntersectionTypeVar clone;
|
|
|
|
clone.parts = itv->parts;
|
|
|
|
result = dest.addType(std::move(clone));
|
|
|
|
}
|
|
|
|
else if (const ConstrainedTypeVar* ctv = get<ConstrainedTypeVar>(ty))
|
|
|
|
{
|
|
|
|
ConstrainedTypeVar clone{ctv->level, ctv->parts};
|
|
|
|
result = dest.addType(std::move(clone));
|
|
|
|
}
|
2022-08-04 23:35:33 +01:00
|
|
|
else if (const PendingExpansionTypeVar* petv = get<PendingExpansionTypeVar>(ty))
|
|
|
|
{
|
2022-09-02 00:14:03 +01:00
|
|
|
PendingExpansionTypeVar clone{petv->prefix, petv->name, petv->typeArguments, petv->packArguments};
|
2022-08-04 23:35:33 +01:00
|
|
|
result = dest.addType(std::move(clone));
|
|
|
|
}
|
2022-08-11 22:01:33 +01:00
|
|
|
else if (const ClassTypeVar* ctv = get<ClassTypeVar>(ty); FFlag::LuauClonePublicInterfaceLess && ctv && alwaysClone)
|
|
|
|
{
|
|
|
|
ClassTypeVar clone{ctv->name, ctv->props, ctv->parent, ctv->metatable, ctv->tags, ctv->userData, ctv->definitionModuleName};
|
|
|
|
result = dest.addType(std::move(clone));
|
|
|
|
}
|
|
|
|
else if (FFlag::LuauClonePublicInterfaceLess && alwaysClone)
|
|
|
|
{
|
|
|
|
result = dest.addType(*ty);
|
|
|
|
}
|
2022-06-03 23:15:45 +01:00
|
|
|
else
|
|
|
|
return result;
|
|
|
|
|
|
|
|
asMutable(result)->documentationSymbol = ty->documentationSymbol;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-04-07 22:29:01 +01:00
|
|
|
} // namespace Luau
|