#include "Luau/Constraint.h"
#include "Luau/TypeFunction.h"
#include "Luau/VisitType.h"
LUAU_FASTFLAG(LuauUseConstraintSetsToTrackFreeTypes)
namespace Luau
{
Constraint::Constraint(NotNull<Scope> scope, const Location& location, ConstraintV&& c)
: scope(scope)
, location(location)
, c(std::move(c))
{
}
struct ReferenceCountInitializer : TypeOnceVisitor
{
NotNull<TypeIds> mutatedTypes;
TypePackIds* mutatedTypePacks;
bool traverseIntoTypeFunctions = true;
explicit ReferenceCountInitializer(NotNull<TypeIds> mutatedTypes)
: TypeOnceVisitor("ReferenceCountInitializer", true)
, mutatedTypes(mutatedTypes)
, mutatedTypePacks(nullptr)
{
LUAU_ASSERT(!FFlag::LuauUseConstraintSetsToTrackFreeTypes);
}
explicit ReferenceCountInitializer(
NotNull<TypeIds> mutatedTypes,
NotNull<TypePackIds> mutatedTypePacks
)
: TypeOnceVisitor("ReferenceCountInitializer", true)
, mutatedTypes(mutatedTypes)
, mutatedTypePacks(mutatedTypePacks.get())
{
LUAU_ASSERT(FFlag::LuauUseConstraintSetsToTrackFreeTypes);
}
bool visit(TypeId ty, const FreeType&) override
{
mutatedTypes->insert(ty);
return false;
}
bool visit(TypeId ty, const BlockedType&) override
{
mutatedTypes->insert(ty);
return false;
}
bool visit(TypeId ty, const PendingExpansionType&) override
{
mutatedTypes->insert(ty);
return false;
}
bool visit(TypeId ty, const TableType& tt) override
{
if (tt.state == TableState::Unsealed || tt.state == TableState::Free)
mutatedTypes->insert(ty);
return true;
}
bool visit(TypeId ty, const ExternType&) override
{
return false;
}
bool visit(TypeId, const TypeFunctionInstanceType& tfit) override
{
return tfit.function->canReduceGenerics;
}
};
bool isReferenceCountedType(const TypeId typ)
{
if (auto tt = get<TableType>(typ))
return tt->state == TableState::Free || tt->state == TableState::Unsealed;
return get<FreeType>(typ) || get<BlockedType>(typ) || get<PendingExpansionType>(typ);
}
TypeIds Constraint::DEPRECATED_getMaybeMutatedFreeTypes() const
{
LUAU_ASSERT(!FFlag::LuauUseConstraintSetsToTrackFreeTypes);
TypeIds types;
ReferenceCountInitializer rci{NotNull{&types}};
if (auto ec = get<EqualityConstraint>(*this))
{
rci.traverse(ec->resultType);
rci.traverse(ec->assignmentType);
}
else if (auto sc = get<SubtypeConstraint>(*this))
{
rci.traverse(sc->subType);
rci.traverse(sc->superType);
}
else if (auto psc = get<PackSubtypeConstraint>(*this))
{
rci.traverse(psc->subPack);
rci.traverse(psc->superPack);
}
else if (auto itc = get<IterableConstraint>(*this))
{
for (TypeId ty : itc->variables)
rci.traverse(ty);
}
else if (auto nc = get<NameConstraint>(*this))
{
rci.traverse(nc->namedType);
}
else if (auto taec = get<TypeAliasExpansionConstraint>(*this))
{
rci.traverse(taec->target);
}
else if (auto fchc = get<FunctionCheckConstraint>(*this))
{
rci.traverse(fchc->argsPack);
}
else if (auto fcc = get<FunctionCallConstraint>(*this))
{
rci.traverseIntoTypeFunctions = false;
rci.traverse(fcc->fn);
rci.traverse(fcc->argsPack);
rci.traverseIntoTypeFunctions = true;
}
else if (auto ptc = get<PrimitiveTypeConstraint>(*this))
{
rci.traverse(ptc->freeType);
}
else if (auto hpc = get<HasPropConstraint>(*this))
{
rci.traverse(hpc->resultType);
rci.traverse(hpc->subjectType);
}
else if (auto hic = get<HasIndexerConstraint>(*this))
{
rci.traverse(hic->subjectType);
rci.traverse(hic->resultType);
}
else if (auto apc = get<AssignPropConstraint>(*this))
{
rci.traverse(apc->lhsType);
rci.traverse(apc->rhsType);
}
else if (auto aic = get<AssignIndexConstraint>(*this))
{
rci.traverse(aic->lhsType);
rci.traverse(aic->indexType);
rci.traverse(aic->rhsType);
}
else if (auto uc = get<UnpackConstraint>(*this))
{
for (TypeId ty : uc->resultPack)
rci.traverse(ty);
}
else if (auto rpc = get<ReducePackConstraint>(*this))
{
rci.traverse(rpc->tp);
}
else if (auto pftc = get<PushFunctionTypeConstraint>(*this))
{
rci.traverse(pftc->functionType);
}
else if (auto ptc = get<PushTypeConstraint>(*this))
{
rci.traverse(ptc->targetType);
}
return types;
}
std::pair<TypeIds, TypePackIds> Constraint::getMaybeMutatedTypes() const
{
LUAU_ASSERT(FFlag::LuauUseConstraintSetsToTrackFreeTypes);
TypeIds types;
TypePackIds typePacks;
ReferenceCountInitializer rci{NotNull{&types}, NotNull{&typePacks}};
if (auto ec = get<EqualityConstraint>(*this))
{
rci.traverse(ec->resultType);
rci.traverse(ec->assignmentType);
}
else if (auto sc = get<SubtypeConstraint>(*this))
{
rci.traverse(sc->subType);
rci.traverse(sc->superType);
}
else if (auto psc = get<PackSubtypeConstraint>(*this))
{
rci.traverse(psc->subPack);
rci.traverse(psc->superPack);
}
else if (auto itc = get<IterableConstraint>(*this))
{
for (TypeId ty : itc->variables)
rci.traverse(ty);
}
else if (auto nc = get<NameConstraint>(*this))
{
rci.traverse(nc->namedType);
}
else if (auto taec = get<TypeAliasExpansionConstraint>(*this))
{
rci.traverse(taec->target);
}
else if (auto fchc = get<FunctionCheckConstraint>(*this))
{
rci.traverse(fchc->argsPack);
}
else if (auto fcc = get<FunctionCallConstraint>(*this))
{
rci.traverseIntoTypeFunctions = false;
rci.traverse(fcc->fn);
rci.traverse(fcc->argsPack);
rci.traverseIntoTypeFunctions = true;
}
else if (auto ptc = get<PrimitiveTypeConstraint>(*this))
{
rci.traverse(ptc->freeType);
}
else if (auto hpc = get<HasPropConstraint>(*this))
{
rci.traverse(hpc->resultType);
rci.traverse(hpc->subjectType);
}
else if (auto hic = get<HasIndexerConstraint>(*this))
{
rci.traverse(hic->subjectType);
rci.traverse(hic->resultType);
}
else if (auto apc = get<AssignPropConstraint>(*this))
{
rci.traverse(apc->lhsType);
rci.traverse(apc->rhsType);
}
else if (auto aic = get<AssignIndexConstraint>(*this))
{
rci.traverse(aic->lhsType);
rci.traverse(aic->indexType);
rci.traverse(aic->rhsType);
}
else if (auto uc = get<UnpackConstraint>(*this))
{
for (TypeId ty : uc->resultPack)
rci.traverse(ty);
rci.traverse(uc->sourcePack);
}
else if (auto rpc = get<ReducePackConstraint>(*this))
{
rci.traverse(rpc->tp);
}
else if (auto pftc = get<PushFunctionTypeConstraint>(*this))
{
rci.traverse(pftc->functionType);
}
else if (auto ptc = get<PushTypeConstraint>(*this))
{
rci.traverse(ptc->targetType);
}
return { std::move(types), std::move(typePacks) };
}
}