luau/Analysis/src/Quantify.cpp

142 lines
3.3 KiB
C++
Raw Normal View History

// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/Quantify.h"
#include "Luau/VisitTypeVar.h"
2022-04-15 00:57:43 +01:00
LUAU_FASTFLAG(LuauTypecheckOptPass)
namespace Luau
{
2022-05-06 01:03:43 +01:00
struct Quantifier final : TypeVarOnceVisitor
{
TypeLevel level;
std::vector<TypeId> generics;
std::vector<TypePackId> genericPacks;
2022-04-15 00:57:43 +01:00
bool seenGenericType = false;
bool seenMutableType = false;
2022-05-06 01:03:43 +01:00
explicit Quantifier(TypeLevel level)
2022-02-18 01:18:01 +00:00
: level(level)
{
}
2022-05-06 01:03:43 +01:00
void cycle(TypeId) override {}
void cycle(TypePackId) override {}
bool operator()(TypeId ty, const FreeTypeVar& ftv)
{
2022-05-06 01:03:43 +01:00
return visit(ty, ftv);
}
template<typename T>
bool operator()(TypeId ty, const T& t)
{
return true;
}
template<typename T>
bool operator()(TypePackId, const T&)
{
return true;
}
2022-04-15 00:57:43 +01:00
bool operator()(TypeId ty, const ConstrainedTypeVar&)
{
return true;
}
2022-05-06 01:03:43 +01:00
bool operator()(TypeId ty, const TableTypeVar& ttv)
{
return visit(ty, ttv);
}
bool operator()(TypePackId tp, const FreeTypePack& ftp)
{
2022-05-06 01:03:43 +01:00
return visit(tp, ftp);
}
bool visit(TypeId ty, const FreeTypeVar& ftv) override
{
if (FFlag::LuauTypecheckOptPass)
seenMutableType = true;
if (!level.subsumes(ftv.level))
return false;
*asMutable(ty) = GenericTypeVar{level};
generics.push_back(ty);
return false;
}
bool visit(TypeId ty, const TableTypeVar&) override
{
LUAU_ASSERT(getMutable<TableTypeVar>(ty));
TableTypeVar& ttv = *getMutable<TableTypeVar>(ty);
2022-04-15 00:57:43 +01:00
if (FFlag::LuauTypecheckOptPass)
{
if (ttv.state == TableState::Generic)
seenGenericType = true;
if (ttv.state == TableState::Free)
seenMutableType = true;
}
if (ttv.state == TableState::Sealed || ttv.state == TableState::Generic)
return false;
if (!level.subsumes(ttv.level))
2022-04-15 00:57:43 +01:00
{
if (FFlag::LuauTypecheckOptPass && ttv.state == TableState::Unsealed)
seenMutableType = true;
return false;
2022-04-15 00:57:43 +01:00
}
if (ttv.state == TableState::Free)
2022-04-15 00:57:43 +01:00
{
ttv.state = TableState::Generic;
2022-04-15 00:57:43 +01:00
if (FFlag::LuauTypecheckOptPass)
seenGenericType = true;
}
else if (ttv.state == TableState::Unsealed)
ttv.state = TableState::Sealed;
ttv.level = level;
return true;
}
2022-05-06 01:03:43 +01:00
bool visit(TypePackId tp, const FreeTypePack& ftp) override
{
2022-04-15 00:57:43 +01:00
if (FFlag::LuauTypecheckOptPass)
seenMutableType = true;
if (!level.subsumes(ftp.level))
return false;
*asMutable(tp) = GenericTypePack{level};
genericPacks.push_back(tp);
return true;
}
};
2022-02-18 01:18:01 +00:00
void quantify(TypeId ty, TypeLevel level)
{
2022-02-18 01:18:01 +00:00
Quantifier q{level};
DenseHashSet<void*> seen{nullptr};
2022-05-06 01:03:43 +01:00
DEPRECATED_visitTypeVarOnce(ty, q, seen);
FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(ty);
LUAU_ASSERT(ftv);
ftv->generics = q.generics;
ftv->genericPacks = q.genericPacks;
2022-04-15 00:57:43 +01:00
if (FFlag::LuauTypecheckOptPass && ftv->generics.empty() && ftv->genericPacks.empty() && !q.seenMutableType && !q.seenGenericType)
ftv->hasNoGenerics = true;
}
} // namespace Luau