luau/Analysis/src/Clone.cpp

493 lines
12 KiB
C++
Raw Normal View History

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/NotNull.h"
Sync to upstream/release/591 (#1012) * Fix a use-after-free bug in the new type cloning algorithm * Tighten up the type of `coroutine.wrap`. It is now `<A..., R...>(f: (A...) -> R...) -> ((A...) -> R...)` * Break `.luaurc` out into a separate library target `Luau.Config`. This makes it easier for applications to reason about config files without also depending on the type inference engine. * Move typechecking limits into `FrontendOptions`. This allows embedders more finely-grained control over autocomplete's internal time limits. * Fix stability issue with debugger onprotectederror callback allowing break in non-yieldable contexts New solver: * Initial work toward [Local Type Inference](https://github.com/Roblox/luau/blob/0e1082108fd6fb3a32dfdf5f1766ea3fc1391328/rfcs/local-type-inference.md) * Introduce a new subtyping test. This will be much nicer than the old test because it is completely separate both from actual type inference and from error reporting. Native code generation: * Added function to compute iterated dominance frontier * Optimize barriers in SET_UPVALUE when tag is known * Cache lua_State::global in a register on A64 * Optimize constant stores in A64 lowering * Track table array size state to optimize array size checks * Add split tag/value store into a VM register * Check that spills can outlive the block only in specific conditions --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-08-18 19:15:41 +01:00
#include "Luau/Type.h"
2022-04-07 22:29:01 +01:00
#include "Luau/TypePack.h"
#include "Luau/Unifiable.h"
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution)
2022-04-07 22:29:01 +01:00
// For each `Luau::clone` call, we will clone only up to N amount of types _and_ packs, as controlled by this limit.
LUAU_FASTINTVARIABLE(LuauTypeCloneIterationLimit, 100'000)
2022-04-07 22:29:01 +01:00
namespace Luau
{
namespace
{
using Kind = Variant<TypeId, TypePackId>;
template<typename T>
const T* get(const Kind& kind)
{
return get_if<T>(&kind);
}
class TypeCloner
{
NotNull<TypeArena> arena;
NotNull<BuiltinTypes> builtinTypes;
// A queue of kinds where we cloned it, but whose interior types hasn't
// been updated to point to new clones. Once all of its interior types
// has been updated, it gets removed from the queue.
std::vector<Kind> queue;
NotNull<SeenTypes> types;
NotNull<SeenTypePacks> packs;
int steps = 0;
public:
TypeCloner(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtinTypes, NotNull<SeenTypes> types, NotNull<SeenTypePacks> packs)
: arena(arena)
, builtinTypes(builtinTypes)
, types(types)
, packs(packs)
{
}
TypeId clone(TypeId ty)
{
shallowClone(ty);
run();
if (hasExceededIterationLimit())
{
TypeId error = builtinTypes->errorRecoveryType();
(*types)[ty] = error;
return error;
}
return find(ty).value_or(builtinTypes->errorRecoveryType());
}
TypePackId clone(TypePackId tp)
{
shallowClone(tp);
run();
if (hasExceededIterationLimit())
{
TypePackId error = builtinTypes->errorRecoveryTypePack();
(*packs)[tp] = error;
return error;
}
return find(tp).value_or(builtinTypes->errorRecoveryTypePack());
}
private:
bool hasExceededIterationLimit() const
{
if (FInt::LuauTypeCloneIterationLimit == 0)
return false;
return steps + queue.size() >= size_t(FInt::LuauTypeCloneIterationLimit);
}
void run()
{
while (!queue.empty())
{
++steps;
if (hasExceededIterationLimit())
break;
Kind kind = queue.back();
queue.pop_back();
if (find(kind))
continue;
cloneChildren(kind);
}
}
std::optional<TypeId> find(TypeId ty) const
{
Sync to upstream/release/591 (#1012) * Fix a use-after-free bug in the new type cloning algorithm * Tighten up the type of `coroutine.wrap`. It is now `<A..., R...>(f: (A...) -> R...) -> ((A...) -> R...)` * Break `.luaurc` out into a separate library target `Luau.Config`. This makes it easier for applications to reason about config files without also depending on the type inference engine. * Move typechecking limits into `FrontendOptions`. This allows embedders more finely-grained control over autocomplete's internal time limits. * Fix stability issue with debugger onprotectederror callback allowing break in non-yieldable contexts New solver: * Initial work toward [Local Type Inference](https://github.com/Roblox/luau/blob/0e1082108fd6fb3a32dfdf5f1766ea3fc1391328/rfcs/local-type-inference.md) * Introduce a new subtyping test. This will be much nicer than the old test because it is completely separate both from actual type inference and from error reporting. Native code generation: * Added function to compute iterated dominance frontier * Optimize barriers in SET_UPVALUE when tag is known * Cache lua_State::global in a register on A64 * Optimize constant stores in A64 lowering * Track table array size state to optimize array size checks * Add split tag/value store into a VM register * Check that spills can outlive the block only in specific conditions --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-08-18 19:15:41 +01:00
ty = follow(ty, FollowOption::DisableLazyTypeThunks);
if (auto it = types->find(ty); it != types->end())
return it->second;
else if (ty->persistent)
return ty;
return std::nullopt;
}
std::optional<TypePackId> find(TypePackId tp) const
{
Sync to upstream/release/591 (#1012) * Fix a use-after-free bug in the new type cloning algorithm * Tighten up the type of `coroutine.wrap`. It is now `<A..., R...>(f: (A...) -> R...) -> ((A...) -> R...)` * Break `.luaurc` out into a separate library target `Luau.Config`. This makes it easier for applications to reason about config files without also depending on the type inference engine. * Move typechecking limits into `FrontendOptions`. This allows embedders more finely-grained control over autocomplete's internal time limits. * Fix stability issue with debugger onprotectederror callback allowing break in non-yieldable contexts New solver: * Initial work toward [Local Type Inference](https://github.com/Roblox/luau/blob/0e1082108fd6fb3a32dfdf5f1766ea3fc1391328/rfcs/local-type-inference.md) * Introduce a new subtyping test. This will be much nicer than the old test because it is completely separate both from actual type inference and from error reporting. Native code generation: * Added function to compute iterated dominance frontier * Optimize barriers in SET_UPVALUE when tag is known * Cache lua_State::global in a register on A64 * Optimize constant stores in A64 lowering * Track table array size state to optimize array size checks * Add split tag/value store into a VM register * Check that spills can outlive the block only in specific conditions --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-08-18 19:15:41 +01:00
tp = follow(tp);
if (auto it = packs->find(tp); it != packs->end())
return it->second;
else if (tp->persistent)
return tp;
return std::nullopt;
}
std::optional<Kind> find(Kind kind) const
{
if (auto ty = get<TypeId>(kind))
return find(*ty);
else if (auto tp = get<TypePackId>(kind))
return find(*tp);
else
{
LUAU_ASSERT(!"Unknown kind?");
return std::nullopt;
}
}
private:
TypeId shallowClone(TypeId ty)
{
Sync to upstream/release/591 (#1012) * Fix a use-after-free bug in the new type cloning algorithm * Tighten up the type of `coroutine.wrap`. It is now `<A..., R...>(f: (A...) -> R...) -> ((A...) -> R...)` * Break `.luaurc` out into a separate library target `Luau.Config`. This makes it easier for applications to reason about config files without also depending on the type inference engine. * Move typechecking limits into `FrontendOptions`. This allows embedders more finely-grained control over autocomplete's internal time limits. * Fix stability issue with debugger onprotectederror callback allowing break in non-yieldable contexts New solver: * Initial work toward [Local Type Inference](https://github.com/Roblox/luau/blob/0e1082108fd6fb3a32dfdf5f1766ea3fc1391328/rfcs/local-type-inference.md) * Introduce a new subtyping test. This will be much nicer than the old test because it is completely separate both from actual type inference and from error reporting. Native code generation: * Added function to compute iterated dominance frontier * Optimize barriers in SET_UPVALUE when tag is known * Cache lua_State::global in a register on A64 * Optimize constant stores in A64 lowering * Track table array size state to optimize array size checks * Add split tag/value store into a VM register * Check that spills can outlive the block only in specific conditions --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-08-18 19:15:41 +01:00
// We want to [`Luau::follow`] but without forcing the expansion of [`LazyType`]s.
ty = follow(ty, FollowOption::DisableLazyTypeThunks);
if (auto clone = find(ty))
return *clone;
else if (ty->persistent)
return ty;
Sync to upstream/release/591 (#1012) * Fix a use-after-free bug in the new type cloning algorithm * Tighten up the type of `coroutine.wrap`. It is now `<A..., R...>(f: (A...) -> R...) -> ((A...) -> R...)` * Break `.luaurc` out into a separate library target `Luau.Config`. This makes it easier for applications to reason about config files without also depending on the type inference engine. * Move typechecking limits into `FrontendOptions`. This allows embedders more finely-grained control over autocomplete's internal time limits. * Fix stability issue with debugger onprotectederror callback allowing break in non-yieldable contexts New solver: * Initial work toward [Local Type Inference](https://github.com/Roblox/luau/blob/0e1082108fd6fb3a32dfdf5f1766ea3fc1391328/rfcs/local-type-inference.md) * Introduce a new subtyping test. This will be much nicer than the old test because it is completely separate both from actual type inference and from error reporting. Native code generation: * Added function to compute iterated dominance frontier * Optimize barriers in SET_UPVALUE when tag is known * Cache lua_State::global in a register on A64 * Optimize constant stores in A64 lowering * Track table array size state to optimize array size checks * Add split tag/value store into a VM register * Check that spills can outlive the block only in specific conditions --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-08-18 19:15:41 +01:00
TypeId target = arena->addType(ty->ty);
asMutable(target)->documentationSymbol = ty->documentationSymbol;
if (auto generic = getMutable<GenericType>(target))
generic->scope = nullptr;
else if (auto free = getMutable<FreeType>(target))
free->scope = nullptr;
else if (auto fn = getMutable<FunctionType>(target))
fn->scope = nullptr;
else if (auto table = getMutable<TableType>(target))
table->scope = nullptr;
(*types)[ty] = target;
queue.push_back(target);
return target;
}
TypePackId shallowClone(TypePackId tp)
{
Sync to upstream/release/591 (#1012) * Fix a use-after-free bug in the new type cloning algorithm * Tighten up the type of `coroutine.wrap`. It is now `<A..., R...>(f: (A...) -> R...) -> ((A...) -> R...)` * Break `.luaurc` out into a separate library target `Luau.Config`. This makes it easier for applications to reason about config files without also depending on the type inference engine. * Move typechecking limits into `FrontendOptions`. This allows embedders more finely-grained control over autocomplete's internal time limits. * Fix stability issue with debugger onprotectederror callback allowing break in non-yieldable contexts New solver: * Initial work toward [Local Type Inference](https://github.com/Roblox/luau/blob/0e1082108fd6fb3a32dfdf5f1766ea3fc1391328/rfcs/local-type-inference.md) * Introduce a new subtyping test. This will be much nicer than the old test because it is completely separate both from actual type inference and from error reporting. Native code generation: * Added function to compute iterated dominance frontier * Optimize barriers in SET_UPVALUE when tag is known * Cache lua_State::global in a register on A64 * Optimize constant stores in A64 lowering * Track table array size state to optimize array size checks * Add split tag/value store into a VM register * Check that spills can outlive the block only in specific conditions --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-08-18 19:15:41 +01:00
tp = follow(tp);
if (auto clone = find(tp))
return *clone;
else if (tp->persistent)
return tp;
Sync to upstream/release/591 (#1012) * Fix a use-after-free bug in the new type cloning algorithm * Tighten up the type of `coroutine.wrap`. It is now `<A..., R...>(f: (A...) -> R...) -> ((A...) -> R...)` * Break `.luaurc` out into a separate library target `Luau.Config`. This makes it easier for applications to reason about config files without also depending on the type inference engine. * Move typechecking limits into `FrontendOptions`. This allows embedders more finely-grained control over autocomplete's internal time limits. * Fix stability issue with debugger onprotectederror callback allowing break in non-yieldable contexts New solver: * Initial work toward [Local Type Inference](https://github.com/Roblox/luau/blob/0e1082108fd6fb3a32dfdf5f1766ea3fc1391328/rfcs/local-type-inference.md) * Introduce a new subtyping test. This will be much nicer than the old test because it is completely separate both from actual type inference and from error reporting. Native code generation: * Added function to compute iterated dominance frontier * Optimize barriers in SET_UPVALUE when tag is known * Cache lua_State::global in a register on A64 * Optimize constant stores in A64 lowering * Track table array size state to optimize array size checks * Add split tag/value store into a VM register * Check that spills can outlive the block only in specific conditions --------- Co-authored-by: Arseny Kapoulkine <arseny.kapoulkine@gmail.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2023-08-18 19:15:41 +01:00
TypePackId target = arena->addTypePack(tp->ty);
if (auto generic = getMutable<GenericTypePack>(target))
generic->scope = nullptr;
else if (auto free = getMutable<FreeTypePack>(target))
free->scope = nullptr;
(*packs)[tp] = target;
queue.push_back(target);
return target;
}
Property shallowClone(const Property& p)
{
Sync to upstream/release/614 (#1173) # What's changed? Add program argument passing to scripts run using the Luau REPL! You can now pass `--program-args` (or shorthand `-a`) to the REPL which will treat all remaining arguments as arguments to pass to executed scripts. These values can be accessed through variadic argument expansion. You can read these values like so: ``` local args = {...} -- gets you an array of all the arguments ``` For example if we run the following script like `luau test.lua -a test1 test2 test3`: ``` -- test.lua print(...) ``` you should get the output: ``` test1 test2 test3 ``` ### Native Code Generation * Improve A64 lowering for vector operations by using vector instructions * Fix lowering issue in IR value location tracking! - A developer reported a divergence between code run in the VM and Native Code Generation which we have now fixed ### New Type Solver * Apply substitution to type families, and emit new constraints to reduce those further * More progress on reducing comparison (`lt/le`)type families * Resolve two major sources of cyclic types in the new solver ### Miscellaneous * Turned internal compiler errors (ICE's) into warnings and errors ------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: David Cope <dcope@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2024-02-23 20:08:34 +00:00
if (FFlag::DebugLuauDeferredConstraintResolution)
{
std::optional<TypeId> cloneReadTy;
Sync to upstream/release/614 (#1173) # What's changed? Add program argument passing to scripts run using the Luau REPL! You can now pass `--program-args` (or shorthand `-a`) to the REPL which will treat all remaining arguments as arguments to pass to executed scripts. These values can be accessed through variadic argument expansion. You can read these values like so: ``` local args = {...} -- gets you an array of all the arguments ``` For example if we run the following script like `luau test.lua -a test1 test2 test3`: ``` -- test.lua print(...) ``` you should get the output: ``` test1 test2 test3 ``` ### Native Code Generation * Improve A64 lowering for vector operations by using vector instructions * Fix lowering issue in IR value location tracking! - A developer reported a divergence between code run in the VM and Native Code Generation which we have now fixed ### New Type Solver * Apply substitution to type families, and emit new constraints to reduce those further * More progress on reducing comparison (`lt/le`)type families * Resolve two major sources of cyclic types in the new solver ### Miscellaneous * Turned internal compiler errors (ICE's) into warnings and errors ------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: David Cope <dcope@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2024-02-23 20:08:34 +00:00
if (auto ty = p.readTy)
cloneReadTy = shallowClone(*ty);
std::optional<TypeId> cloneWriteTy;
Sync to upstream/release/614 (#1173) # What's changed? Add program argument passing to scripts run using the Luau REPL! You can now pass `--program-args` (or shorthand `-a`) to the REPL which will treat all remaining arguments as arguments to pass to executed scripts. These values can be accessed through variadic argument expansion. You can read these values like so: ``` local args = {...} -- gets you an array of all the arguments ``` For example if we run the following script like `luau test.lua -a test1 test2 test3`: ``` -- test.lua print(...) ``` you should get the output: ``` test1 test2 test3 ``` ### Native Code Generation * Improve A64 lowering for vector operations by using vector instructions * Fix lowering issue in IR value location tracking! - A developer reported a divergence between code run in the VM and Native Code Generation which we have now fixed ### New Type Solver * Apply substitution to type families, and emit new constraints to reduce those further * More progress on reducing comparison (`lt/le`)type families * Resolve two major sources of cyclic types in the new solver ### Miscellaneous * Turned internal compiler errors (ICE's) into warnings and errors ------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: David Cope <dcope@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
2024-02-23 20:08:34 +00:00
if (auto ty = p.writeTy)
cloneWriteTy = shallowClone(*ty);
Property cloned = Property::create(cloneReadTy, cloneWriteTy);
cloned.deprecated = p.deprecated;
cloned.deprecatedSuggestion = p.deprecatedSuggestion;
cloned.location = p.location;
cloned.tags = p.tags;
cloned.documentationSymbol = p.documentationSymbol;
cloned.typeLocation = p.typeLocation;
return cloned;
}
else
{
return Property{
shallowClone(p.type()),
p.deprecated,
p.deprecatedSuggestion,
p.location,
p.tags,
p.documentationSymbol,
p.typeLocation,
};
}
}
void cloneChildren(TypeId ty)
{
return visit(
[&](auto&& t) {
return cloneChildren(&t);
},
asMutable(ty)->ty);
}
void cloneChildren(TypePackId tp)
{
return visit(
[&](auto&& t) {
return cloneChildren(&t);
},
asMutable(tp)->ty);
}
void cloneChildren(Kind kind)
{
if (auto ty = get<TypeId>(kind))
return cloneChildren(*ty);
else if (auto tp = get<TypePackId>(kind))
return cloneChildren(*tp);
else
LUAU_ASSERT(!"Item holds neither TypeId nor TypePackId when enqueuing its children?");
}
// ErrorType and ErrorTypePack is an alias to this type.
void cloneChildren(Unifiable::Error* t)
{
// noop.
}
void cloneChildren(BoundType* t)
{
t->boundTo = shallowClone(t->boundTo);
}
void cloneChildren(FreeType* t)
{
if (t->lowerBound)
t->lowerBound = shallowClone(t->lowerBound);
if (t->upperBound)
t->upperBound = shallowClone(t->upperBound);
}
void cloneChildren(GenericType* t)
{
// TOOD: clone upper bounds.
}
void cloneChildren(PrimitiveType* t)
{
// noop.
}
void cloneChildren(BlockedType* t)
{
// TODO: In the new solver, we should ice.
}
void cloneChildren(PendingExpansionType* t)
{
// TODO: In the new solver, we should ice.
}
void cloneChildren(SingletonType* t)
{
// noop.
}
void cloneChildren(FunctionType* t)
{
for (TypeId& g : t->generics)
g = shallowClone(g);
for (TypePackId& gp : t->genericPacks)
gp = shallowClone(gp);
t->argTypes = shallowClone(t->argTypes);
t->retTypes = shallowClone(t->retTypes);
}
void cloneChildren(TableType* t)
{
if (t->indexer)
{
t->indexer->indexType = shallowClone(t->indexer->indexType);
t->indexer->indexResultType = shallowClone(t->indexer->indexResultType);
}
for (auto& [_, p] : t->props)
p = shallowClone(p);
for (TypeId& ty : t->instantiatedTypeParams)
ty = shallowClone(ty);
for (TypePackId& tp : t->instantiatedTypePackParams)
tp = shallowClone(tp);
}
void cloneChildren(MetatableType* t)
{
t->table = shallowClone(t->table);
t->metatable = shallowClone(t->metatable);
}
void cloneChildren(ClassType* t)
{
for (auto& [_, p] : t->props)
p = shallowClone(p);
if (t->parent)
t->parent = shallowClone(*t->parent);
if (t->metatable)
t->metatable = shallowClone(*t->metatable);
if (t->indexer)
{
t->indexer->indexType = shallowClone(t->indexer->indexType);
t->indexer->indexResultType = shallowClone(t->indexer->indexResultType);
}
}
void cloneChildren(AnyType* t)
{
// noop.
}
void cloneChildren(UnionType* t)
{
for (TypeId& ty : t->options)
ty = shallowClone(ty);
}
void cloneChildren(IntersectionType* t)
{
for (TypeId& ty : t->parts)
ty = shallowClone(ty);
}
void cloneChildren(LazyType* t)
{
if (auto unwrapped = t->unwrapped.load())
t->unwrapped.store(shallowClone(unwrapped));
}
void cloneChildren(UnknownType* t)
{
// noop.
}
void cloneChildren(NeverType* t)
{
// noop.
}
void cloneChildren(NegationType* t)
{
t->ty = shallowClone(t->ty);
}
void cloneChildren(TypeFamilyInstanceType* t)
{
for (TypeId& ty : t->typeArguments)
ty = shallowClone(ty);
for (TypePackId& tp : t->packArguments)
tp = shallowClone(tp);
}
void cloneChildren(FreeTypePack* t)
{
// TODO: clone lower and upper bounds.
// TODO: In the new solver, we should ice.
}
void cloneChildren(GenericTypePack* t)
{
// TOOD: clone upper bounds.
}
void cloneChildren(BlockedTypePack* t)
{
// TODO: In the new solver, we should ice.
}
void cloneChildren(BoundTypePack* t)
{
t->boundTo = shallowClone(t->boundTo);
}
void cloneChildren(VariadicTypePack* t)
{
t->ty = shallowClone(t->ty);
}
void cloneChildren(TypePack* t)
{
for (TypeId& ty : t->head)
ty = shallowClone(ty);
if (t->tail)
t->tail = shallowClone(*t->tail);
}
void cloneChildren(TypeFamilyInstanceTypePack* t)
{
for (TypeId& ty : t->typeArguments)
ty = shallowClone(ty);
for (TypePackId& tp : t->packArguments)
tp = shallowClone(tp);
}
};
} // 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;
TypeCloner cloner{NotNull{&dest}, cloneState.builtinTypes, NotNull{&cloneState.seenTypes}, NotNull{&cloneState.seenTypePacks}};
return cloner.clone(tp);
2022-04-07 22:29:01 +01:00
}
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;
TypeCloner cloner{NotNull{&dest}, cloneState.builtinTypes, NotNull{&cloneState.seenTypes}, NotNull{&cloneState.seenTypePacks}};
return cloner.clone(typeId);
2022-04-07 22:29:01 +01:00
}
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
{
TypeCloner cloner{NotNull{&dest}, cloneState.builtinTypes, NotNull{&cloneState.seenTypes}, NotNull{&cloneState.seenTypePacks}};
2022-04-07 22:29:01 +01:00
TypeFun copy = typeFun;
2022-04-07 22:29:01 +01:00
for (auto& param : copy.typeParams)
{
param.ty = cloner.clone(param.ty);
if (param.defaultValue)
param.defaultValue = cloner.clone(*param.defaultValue);
}
for (auto& param : copy.typePackParams)
{
param.tp = cloner.clone(param.tp);
if (param.defaultValue)
param.defaultValue = cloner.clone(*param.defaultValue);
}
copy.type = cloner.clone(copy.type);
return copy;
2022-04-07 22:29:01 +01:00
}
} // namespace Luau