2021-10-29 21:25:12 +01:00
|
|
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
|
|
#include "Luau/Module.h"
|
|
|
|
|
2021-12-03 06:41:04 +00:00
|
|
|
#include "Luau/Common.h"
|
|
|
|
#include "Luau/RecursionCounter.h"
|
2021-11-05 02:34:35 +00:00
|
|
|
#include "Luau/Scope.h"
|
2021-10-29 21:25:12 +01:00
|
|
|
#include "Luau/TypeInfer.h"
|
|
|
|
#include "Luau/TypePack.h"
|
|
|
|
#include "Luau/TypeVar.h"
|
|
|
|
#include "Luau/VisitTypeVar.h"
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
LUAU_FASTFLAGVARIABLE(DebugLuauFreezeArena, false)
|
|
|
|
LUAU_FASTFLAGVARIABLE(DebugLuauTrackOwningArena, false)
|
2022-01-07 01:46:53 +00:00
|
|
|
LUAU_FASTINTVARIABLE(LuauTypeCloneRecursionLimit, 300)
|
2022-01-14 16:20:09 +00:00
|
|
|
LUAU_FASTFLAG(LuauTypeAliasDefaults)
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
namespace Luau
|
|
|
|
{
|
|
|
|
|
|
|
|
static bool contains(Position pos, Comment comment)
|
|
|
|
{
|
|
|
|
if (comment.location.contains(pos))
|
|
|
|
return true;
|
2021-12-10 22:05:05 +00:00
|
|
|
else if (comment.type == Lexeme::BrokenComment &&
|
2021-10-29 21:25:12 +01:00
|
|
|
comment.location.begin <= pos) // Broken comments are broken specifically because they don't have an end
|
|
|
|
return true;
|
|
|
|
else if (comment.type == Lexeme::Comment && comment.location.end == pos)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isWithinComment(const SourceModule& sourceModule, Position pos)
|
|
|
|
{
|
|
|
|
auto iter = std::lower_bound(sourceModule.commentLocations.begin(), sourceModule.commentLocations.end(),
|
|
|
|
Comment{Lexeme::Comment, Location{pos, pos}}, [](const Comment& a, const Comment& b) {
|
|
|
|
return a.location.end < b.location.end;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (iter == sourceModule.commentLocations.end())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (contains(pos, *iter))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Due to the nature of std::lower_bound, it is possible that iter points at a comment that ends
|
|
|
|
// at pos. We'll try the next comment, if it exists.
|
|
|
|
++iter;
|
|
|
|
if (iter == sourceModule.commentLocations.end())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return contains(pos, *iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeArena::clear()
|
|
|
|
{
|
|
|
|
typeVars.clear();
|
|
|
|
typePacks.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeId TypeArena::addTV(TypeVar&& tv)
|
|
|
|
{
|
|
|
|
TypeId allocated = typeVars.allocate(std::move(tv));
|
|
|
|
|
|
|
|
if (FFlag::DebugLuauTrackOwningArena)
|
|
|
|
asMutable(allocated)->owningArena = this;
|
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeId TypeArena::freshType(TypeLevel level)
|
|
|
|
{
|
|
|
|
TypeId allocated = typeVars.allocate(FreeTypeVar{level});
|
|
|
|
|
|
|
|
if (FFlag::DebugLuauTrackOwningArena)
|
|
|
|
asMutable(allocated)->owningArena = this;
|
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypePackId TypeArena::addTypePack(std::initializer_list<TypeId> types)
|
|
|
|
{
|
|
|
|
TypePackId allocated = typePacks.allocate(TypePack{std::move(types)});
|
|
|
|
|
|
|
|
if (FFlag::DebugLuauTrackOwningArena)
|
|
|
|
asMutable(allocated)->owningArena = this;
|
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypePackId TypeArena::addTypePack(std::vector<TypeId> types)
|
|
|
|
{
|
|
|
|
TypePackId allocated = typePacks.allocate(TypePack{std::move(types)});
|
|
|
|
|
|
|
|
if (FFlag::DebugLuauTrackOwningArena)
|
|
|
|
asMutable(allocated)->owningArena = this;
|
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypePackId TypeArena::addTypePack(TypePack tp)
|
|
|
|
{
|
|
|
|
TypePackId allocated = typePacks.allocate(std::move(tp));
|
|
|
|
|
|
|
|
if (FFlag::DebugLuauTrackOwningArena)
|
|
|
|
asMutable(allocated)->owningArena = this;
|
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypePackId TypeArena::addTypePack(TypePackVar tp)
|
|
|
|
{
|
|
|
|
TypePackId allocated = typePacks.allocate(std::move(tp));
|
|
|
|
|
|
|
|
if (FFlag::DebugLuauTrackOwningArena)
|
|
|
|
asMutable(allocated)->owningArena = this;
|
|
|
|
|
|
|
|
return allocated;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
2021-12-03 06:41:04 +00:00
|
|
|
TypeCloner(TypeArena& dest, TypeId typeId, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState& cloneState)
|
2021-10-29 21:25:12 +01:00
|
|
|
: dest(dest)
|
|
|
|
, typeId(typeId)
|
|
|
|
, seenTypes(seenTypes)
|
|
|
|
, seenTypePacks(seenTypePacks)
|
2021-12-03 06:41:04 +00:00
|
|
|
, cloneState(cloneState)
|
2021-10-29 21:25:12 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
TypeArena& dest;
|
|
|
|
TypeId typeId;
|
|
|
|
SeenTypes& seenTypes;
|
|
|
|
SeenTypePacks& seenTypePacks;
|
2021-12-03 06:41:04 +00:00
|
|
|
CloneState& cloneState;
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
void operator()(const PrimitiveTypeVar& t);
|
2021-11-19 16:10:07 +00:00
|
|
|
void operator()(const SingletonTypeVar& t);
|
2021-10-29 21:25:12 +01:00
|
|
|
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);
|
|
|
|
};
|
|
|
|
|
|
|
|
struct TypePackCloner
|
|
|
|
{
|
|
|
|
TypeArena& dest;
|
|
|
|
TypePackId typePackId;
|
|
|
|
SeenTypes& seenTypes;
|
|
|
|
SeenTypePacks& seenTypePacks;
|
2021-12-03 06:41:04 +00:00
|
|
|
CloneState& cloneState;
|
2021-10-29 21:25:12 +01:00
|
|
|
|
2021-12-03 06:41:04 +00:00
|
|
|
TypePackCloner(TypeArena& dest, TypePackId typePackId, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState& cloneState)
|
2021-10-29 21:25:12 +01:00
|
|
|
: dest(dest)
|
|
|
|
, typePackId(typePackId)
|
|
|
|
, seenTypes(seenTypes)
|
|
|
|
, seenTypePacks(seenTypePacks)
|
2021-12-03 06:41:04 +00:00
|
|
|
, cloneState(cloneState)
|
2021-10-29 21:25:12 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void defaultClone(const T& t)
|
|
|
|
{
|
2021-11-05 02:34:35 +00:00
|
|
|
TypePackId cloned = dest.addTypePack(TypePackVar{t});
|
2021-10-29 21:25:12 +01:00
|
|
|
seenTypePacks[typePackId] = cloned;
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const Unifiable::Free& t)
|
|
|
|
{
|
2021-12-03 06:41:04 +00:00
|
|
|
cloneState.encounteredFreeType = true;
|
2021-10-29 21:25:12 +01:00
|
|
|
|
2021-12-10 22:05:05 +00:00
|
|
|
TypePackId err = getSingletonTypes().errorRecoveryTypePack(getSingletonTypes().anyTypePack);
|
2021-11-19 16:10:07 +00:00
|
|
|
TypePackId cloned = dest.addTypePack(*err);
|
|
|
|
seenTypePacks[typePackId] = cloned;
|
2021-10-29 21:25:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const Unifiable::Generic& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
void operator()(const Unifiable::Error& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
{
|
2021-12-03 06:41:04 +00:00
|
|
|
TypePackId cloned = clone(t.boundTo, dest, seenTypes, seenTypePacks, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
seenTypePacks[typePackId] = cloned;
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const VariadicTypePack& t)
|
|
|
|
{
|
2021-12-03 06:41:04 +00:00
|
|
|
TypePackId cloned = dest.addTypePack(TypePackVar{VariadicTypePack{clone(t.ty, dest, seenTypes, seenTypePacks, cloneState)}});
|
2021-10-29 21:25:12 +01:00
|
|
|
seenTypePacks[typePackId] = cloned;
|
|
|
|
}
|
|
|
|
|
|
|
|
void operator()(const TypePack& t)
|
|
|
|
{
|
2021-11-05 02:34:35 +00:00
|
|
|
TypePackId cloned = dest.addTypePack(TypePack{});
|
2021-10-29 21:25:12 +01:00
|
|
|
TypePack* destTp = getMutable<TypePack>(cloned);
|
|
|
|
LUAU_ASSERT(destTp != nullptr);
|
|
|
|
seenTypePacks[typePackId] = cloned;
|
|
|
|
|
|
|
|
for (TypeId ty : t.head)
|
2021-12-03 06:41:04 +00:00
|
|
|
destTp->head.push_back(clone(ty, dest, seenTypes, seenTypePacks, cloneState));
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
if (t.tail)
|
2021-12-03 06:41:04 +00:00
|
|
|
destTp->tail = clone(*t.tail, dest, seenTypes, seenTypePacks, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void TypeCloner::defaultClone(const T& t)
|
|
|
|
{
|
2021-11-05 02:34:35 +00:00
|
|
|
TypeId cloned = dest.addType(t);
|
2021-10-29 21:25:12 +01:00
|
|
|
seenTypes[typeId] = cloned;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const Unifiable::Free& t)
|
|
|
|
{
|
2021-12-03 06:41:04 +00:00
|
|
|
cloneState.encounteredFreeType = true;
|
2021-12-10 22:05:05 +00:00
|
|
|
TypeId err = getSingletonTypes().errorRecoveryType(getSingletonTypes().anyType);
|
2021-11-19 16:10:07 +00:00
|
|
|
TypeId cloned = dest.addType(*err);
|
|
|
|
seenTypes[typeId] = cloned;
|
2021-10-29 21:25:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const Unifiable::Generic& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const Unifiable::Bound<TypeId>& t)
|
|
|
|
{
|
2021-12-03 06:41:04 +00:00
|
|
|
TypeId boundTo = clone(t.boundTo, dest, seenTypes, seenTypePacks, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
seenTypes[typeId] = boundTo;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const Unifiable::Error& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
2021-11-19 16:10:07 +00:00
|
|
|
|
2021-10-29 21:25:12 +01:00
|
|
|
void TypeCloner::operator()(const PrimitiveTypeVar& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
2021-11-19 16:10:07 +00:00
|
|
|
void TypeCloner::operator()(const SingletonTypeVar& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
2021-10-29 21:25:12 +01:00
|
|
|
void TypeCloner::operator()(const FunctionTypeVar& t)
|
|
|
|
{
|
2021-11-05 02:34:35 +00:00
|
|
|
TypeId result = dest.addType(FunctionTypeVar{TypeLevel{0, 0}, {}, {}, nullptr, nullptr, t.definition, t.hasSelf});
|
2021-10-29 21:25:12 +01:00
|
|
|
FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(result);
|
|
|
|
LUAU_ASSERT(ftv != nullptr);
|
|
|
|
|
|
|
|
seenTypes[typeId] = result;
|
|
|
|
|
|
|
|
for (TypeId generic : t.generics)
|
2021-12-03 06:41:04 +00:00
|
|
|
ftv->generics.push_back(clone(generic, dest, seenTypes, seenTypePacks, cloneState));
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
for (TypePackId genericPack : t.genericPacks)
|
2021-12-03 06:41:04 +00:00
|
|
|
ftv->genericPacks.push_back(clone(genericPack, dest, seenTypes, seenTypePacks, cloneState));
|
2021-10-29 21:25:12 +01:00
|
|
|
|
2021-11-12 14:27:34 +00:00
|
|
|
ftv->tags = t.tags;
|
2021-12-03 06:41:04 +00:00
|
|
|
ftv->argTypes = clone(t.argTypes, dest, seenTypes, seenTypePacks, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
ftv->argNames = t.argNames;
|
2021-12-03 06:41:04 +00:00
|
|
|
ftv->retType = clone(t.retType, dest, seenTypes, seenTypePacks, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const TableTypeVar& t)
|
|
|
|
{
|
2021-11-05 15:47:21 +00:00
|
|
|
// If table is now bound to another one, we ignore the content of the original
|
2021-12-03 06:41:04 +00:00
|
|
|
if (t.boundTo)
|
2021-11-05 15:47:21 +00:00
|
|
|
{
|
2021-12-03 06:41:04 +00:00
|
|
|
TypeId boundTo = clone(*t.boundTo, dest, seenTypes, seenTypePacks, cloneState);
|
2021-11-05 15:47:21 +00:00
|
|
|
seenTypes[typeId] = boundTo;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-11-05 02:34:35 +00:00
|
|
|
TypeId result = dest.addType(TableTypeVar{});
|
2021-10-29 21:25:12 +01:00
|
|
|
TableTypeVar* ttv = getMutable<TableTypeVar>(result);
|
|
|
|
LUAU_ASSERT(ttv != nullptr);
|
|
|
|
|
|
|
|
*ttv = t;
|
|
|
|
|
|
|
|
seenTypes[typeId] = result;
|
|
|
|
|
|
|
|
ttv->level = TypeLevel{0, 0};
|
|
|
|
|
|
|
|
for (const auto& [name, prop] : t.props)
|
2021-12-03 06:41:04 +00:00
|
|
|
ttv->props[name] = {clone(prop.type, dest, seenTypes, seenTypePacks, cloneState), prop.deprecated, {}, prop.location, prop.tags};
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
if (t.indexer)
|
2021-12-03 06:41:04 +00:00
|
|
|
ttv->indexer = TableIndexer{clone(t.indexer->indexType, dest, seenTypes, seenTypePacks, cloneState),
|
|
|
|
clone(t.indexer->indexResultType, dest, seenTypes, seenTypePacks, cloneState)};
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
for (TypeId& arg : ttv->instantiatedTypeParams)
|
2021-12-03 06:41:04 +00:00
|
|
|
arg = clone(arg, dest, seenTypes, seenTypePacks, cloneState);
|
2021-11-05 02:34:35 +00:00
|
|
|
|
2021-12-03 06:41:04 +00:00
|
|
|
for (TypePackId& arg : ttv->instantiatedTypePackParams)
|
|
|
|
arg = clone(arg, dest, seenTypes, seenTypePacks, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
if (ttv->state == TableState::Free)
|
|
|
|
{
|
2021-12-03 06:41:04 +00:00
|
|
|
cloneState.encounteredFreeType = true;
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
ttv->state = TableState::Sealed;
|
|
|
|
}
|
|
|
|
|
|
|
|
ttv->definitionModuleName = t.definitionModuleName;
|
|
|
|
ttv->methodDefinitionLocations = t.methodDefinitionLocations;
|
|
|
|
ttv->tags = t.tags;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const MetatableTypeVar& t)
|
|
|
|
{
|
2021-11-05 02:34:35 +00:00
|
|
|
TypeId result = dest.addType(MetatableTypeVar{});
|
2021-10-29 21:25:12 +01:00
|
|
|
MetatableTypeVar* mtv = getMutable<MetatableTypeVar>(result);
|
|
|
|
seenTypes[typeId] = result;
|
|
|
|
|
2021-12-03 06:41:04 +00:00
|
|
|
mtv->table = clone(t.table, dest, seenTypes, seenTypePacks, cloneState);
|
|
|
|
mtv->metatable = clone(t.metatable, dest, seenTypes, seenTypePacks, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const ClassTypeVar& t)
|
|
|
|
{
|
2021-11-05 02:34:35 +00:00
|
|
|
TypeId result = dest.addType(ClassTypeVar{t.name, {}, std::nullopt, std::nullopt, t.tags, t.userData});
|
2021-10-29 21:25:12 +01:00
|
|
|
ClassTypeVar* ctv = getMutable<ClassTypeVar>(result);
|
|
|
|
|
|
|
|
seenTypes[typeId] = result;
|
|
|
|
|
|
|
|
for (const auto& [name, prop] : t.props)
|
2021-12-03 06:41:04 +00:00
|
|
|
ctv->props[name] = {clone(prop.type, dest, seenTypes, seenTypePacks, cloneState), prop.deprecated, {}, prop.location, prop.tags};
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
if (t.parent)
|
2021-12-03 06:41:04 +00:00
|
|
|
ctv->parent = clone(*t.parent, dest, seenTypes, seenTypePacks, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
if (t.metatable)
|
2021-12-03 06:41:04 +00:00
|
|
|
ctv->metatable = clone(*t.metatable, dest, seenTypes, seenTypePacks, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const AnyTypeVar& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const UnionTypeVar& t)
|
|
|
|
{
|
2021-11-05 02:34:35 +00:00
|
|
|
TypeId result = dest.addType(UnionTypeVar{});
|
2021-10-29 21:25:12 +01:00
|
|
|
seenTypes[typeId] = result;
|
|
|
|
|
|
|
|
UnionTypeVar* option = getMutable<UnionTypeVar>(result);
|
|
|
|
LUAU_ASSERT(option != nullptr);
|
|
|
|
|
|
|
|
for (TypeId ty : t.options)
|
2021-12-03 06:41:04 +00:00
|
|
|
option->options.push_back(clone(ty, dest, seenTypes, seenTypePacks, cloneState));
|
2021-10-29 21:25:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const IntersectionTypeVar& t)
|
|
|
|
{
|
2021-11-05 02:34:35 +00:00
|
|
|
TypeId result = dest.addType(IntersectionTypeVar{});
|
2021-10-29 21:25:12 +01:00
|
|
|
seenTypes[typeId] = result;
|
|
|
|
|
|
|
|
IntersectionTypeVar* option = getMutable<IntersectionTypeVar>(result);
|
|
|
|
LUAU_ASSERT(option != nullptr);
|
|
|
|
|
|
|
|
for (TypeId ty : t.parts)
|
2021-12-03 06:41:04 +00:00
|
|
|
option->parts.push_back(clone(ty, dest, seenTypes, seenTypePacks, cloneState));
|
2021-10-29 21:25:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TypeCloner::operator()(const LazyTypeVar& t)
|
|
|
|
{
|
|
|
|
defaultClone(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
2021-12-03 06:41:04 +00:00
|
|
|
TypePackId clone(TypePackId tp, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState& cloneState)
|
2021-10-29 21:25:12 +01:00
|
|
|
{
|
|
|
|
if (tp->persistent)
|
|
|
|
return tp;
|
|
|
|
|
2021-12-03 06:41:04 +00:00
|
|
|
RecursionLimiter _ra(&cloneState.recursionCount, FInt::LuauTypeCloneRecursionLimit);
|
|
|
|
|
2021-10-29 21:25:12 +01:00
|
|
|
TypePackId& res = seenTypePacks[tp];
|
|
|
|
|
|
|
|
if (res == nullptr)
|
|
|
|
{
|
2021-12-03 06:41:04 +00:00
|
|
|
TypePackCloner cloner{dest, tp, seenTypes, seenTypePacks, cloneState};
|
2021-10-29 21:25:12 +01:00
|
|
|
Luau::visit(cloner, tp->ty); // Mutates the storage that 'res' points into.
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2021-12-03 06:41:04 +00:00
|
|
|
TypeId clone(TypeId typeId, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState& cloneState)
|
2021-10-29 21:25:12 +01:00
|
|
|
{
|
|
|
|
if (typeId->persistent)
|
|
|
|
return typeId;
|
|
|
|
|
2021-12-03 06:41:04 +00:00
|
|
|
RecursionLimiter _ra(&cloneState.recursionCount, FInt::LuauTypeCloneRecursionLimit);
|
|
|
|
|
2021-10-29 21:25:12 +01:00
|
|
|
TypeId& res = seenTypes[typeId];
|
|
|
|
|
|
|
|
if (res == nullptr)
|
|
|
|
{
|
2021-12-03 06:41:04 +00:00
|
|
|
TypeCloner cloner{dest, typeId, seenTypes, seenTypePacks, cloneState};
|
2021-10-29 21:25:12 +01:00
|
|
|
Luau::visit(cloner, typeId->ty); // Mutates the storage that 'res' points into.
|
2021-12-10 22:05:05 +00:00
|
|
|
|
|
|
|
// TODO: Make this work when the arena of 'res' might be frozen
|
2021-10-29 21:25:12 +01:00
|
|
|
asMutable(res)->documentationSymbol = typeId->documentationSymbol;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2021-12-03 06:41:04 +00:00
|
|
|
TypeFun clone(const TypeFun& typeFun, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState& cloneState)
|
2021-10-29 21:25:12 +01:00
|
|
|
{
|
|
|
|
TypeFun result;
|
2021-11-05 02:34:35 +00:00
|
|
|
|
2022-01-14 16:20:09 +00:00
|
|
|
for (auto param : typeFun.typeParams)
|
|
|
|
{
|
|
|
|
TypeId ty = clone(param.ty, dest, seenTypes, seenTypePacks, cloneState);
|
|
|
|
std::optional<TypeId> defaultValue;
|
|
|
|
|
|
|
|
if (FFlag::LuauTypeAliasDefaults && param.defaultValue)
|
|
|
|
defaultValue = clone(*param.defaultValue, dest, seenTypes, seenTypePacks, cloneState);
|
|
|
|
|
|
|
|
result.typeParams.push_back({ty, defaultValue});
|
|
|
|
}
|
|
|
|
|
|
|
|
for (auto param : typeFun.typePackParams)
|
|
|
|
{
|
|
|
|
TypePackId tp = clone(param.tp, dest, seenTypes, seenTypePacks, cloneState);
|
|
|
|
std::optional<TypePackId> defaultValue;
|
|
|
|
|
|
|
|
if (FFlag::LuauTypeAliasDefaults && param.defaultValue)
|
|
|
|
defaultValue = clone(*param.defaultValue, dest, seenTypes, seenTypePacks, cloneState);
|
|
|
|
|
|
|
|
result.typePackParams.push_back({tp, defaultValue});
|
|
|
|
}
|
2021-10-29 21:25:12 +01:00
|
|
|
|
2021-12-03 06:41:04 +00:00
|
|
|
result.type = clone(typeFun.type, dest, seenTypes, seenTypePacks, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
ScopePtr Module::getModuleScope() const
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(!scopes.empty());
|
|
|
|
return scopes.front().second;
|
|
|
|
}
|
|
|
|
|
|
|
|
void freeze(TypeArena& arena)
|
|
|
|
{
|
|
|
|
if (!FFlag::DebugLuauFreezeArena)
|
|
|
|
return;
|
|
|
|
|
|
|
|
arena.typeVars.freeze();
|
|
|
|
arena.typePacks.freeze();
|
|
|
|
}
|
|
|
|
|
|
|
|
void unfreeze(TypeArena& arena)
|
|
|
|
{
|
|
|
|
if (!FFlag::DebugLuauFreezeArena)
|
|
|
|
return;
|
|
|
|
|
|
|
|
arena.typeVars.unfreeze();
|
|
|
|
arena.typePacks.unfreeze();
|
|
|
|
}
|
|
|
|
|
|
|
|
Module::~Module()
|
|
|
|
{
|
|
|
|
unfreeze(interfaceTypes);
|
|
|
|
unfreeze(internalTypes);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Module::clonePublicInterface()
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(interfaceTypes.typeVars.empty());
|
|
|
|
LUAU_ASSERT(interfaceTypes.typePacks.empty());
|
|
|
|
|
|
|
|
SeenTypes seenTypes;
|
2021-12-03 06:41:04 +00:00
|
|
|
SeenTypePacks seenTypePacks;
|
|
|
|
CloneState cloneState;
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
ScopePtr moduleScope = getModuleScope();
|
|
|
|
|
2021-12-03 06:41:04 +00:00
|
|
|
moduleScope->returnType = clone(moduleScope->returnType, interfaceTypes, seenTypes, seenTypePacks, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
if (moduleScope->varargPack)
|
2021-12-03 06:41:04 +00:00
|
|
|
moduleScope->varargPack = clone(*moduleScope->varargPack, interfaceTypes, seenTypes, seenTypePacks, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
|
2021-12-10 22:05:05 +00:00
|
|
|
for (auto& [name, tf] : moduleScope->exportedTypeBindings)
|
|
|
|
tf = clone(tf, interfaceTypes, seenTypes, seenTypePacks, cloneState);
|
2021-10-29 21:25:12 +01:00
|
|
|
|
|
|
|
for (TypeId ty : moduleScope->returnType)
|
|
|
|
if (get<GenericTypeVar>(follow(ty)))
|
|
|
|
*asMutable(ty) = AnyTypeVar{};
|
|
|
|
|
|
|
|
freeze(internalTypes);
|
|
|
|
freeze(interfaceTypes);
|
|
|
|
|
2021-12-03 06:41:04 +00:00
|
|
|
return cloneState.encounteredFreeType;
|
2021-10-29 21:25:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Luau
|