2021-11-05 15:47:21 +00:00
|
|
|
// 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-06-03 23:15:45 +01:00
|
|
|
#include "Luau/ConstraintGraphBuilder.h" // TODO for Scope2; move to separate header
|
2021-11-05 15:47:21 +00:00
|
|
|
|
2022-06-03 23:15:45 +01:00
|
|
|
LUAU_FASTFLAG(LuauAlwaysQuantify);
|
|
|
|
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution);
|
2022-04-15 00:57:43 +01:00
|
|
|
|
2021-11-05 15:47:21 +00:00
|
|
|
namespace Luau
|
|
|
|
{
|
|
|
|
|
2022-05-06 01:03:43 +01:00
|
|
|
struct Quantifier final : TypeVarOnceVisitor
|
2021-11-05 15:47:21 +00:00
|
|
|
{
|
|
|
|
TypeLevel level;
|
|
|
|
std::vector<TypeId> generics;
|
|
|
|
std::vector<TypePackId> genericPacks;
|
2022-06-03 23:15:45 +01:00
|
|
|
Scope2* scope = nullptr;
|
2022-04-15 00:57:43 +01:00
|
|
|
bool seenGenericType = false;
|
|
|
|
bool seenMutableType = false;
|
2021-11-05 15:47:21 +00:00
|
|
|
|
2022-05-06 01:03:43 +01:00
|
|
|
explicit Quantifier(TypeLevel level)
|
2022-02-18 01:18:01 +00:00
|
|
|
: level(level)
|
2021-11-05 15:47:21 +00:00
|
|
|
{
|
2022-06-03 23:15:45 +01:00
|
|
|
LUAU_ASSERT(!FFlag::DebugLuauDeferredConstraintResolution);
|
|
|
|
}
|
|
|
|
|
|
|
|
explicit Quantifier(Scope2* scope)
|
|
|
|
: scope(scope)
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(FFlag::DebugLuauDeferredConstraintResolution);
|
2021-11-05 15:47:21 +00:00
|
|
|
}
|
|
|
|
|
2022-06-03 23:15:45 +01:00
|
|
|
/// @return true if outer encloses inner
|
|
|
|
bool subsumes(Scope2* outer, Scope2* inner)
|
|
|
|
{
|
|
|
|
while (inner)
|
|
|
|
{
|
|
|
|
if (inner == outer)
|
|
|
|
return true;
|
|
|
|
inner = inner->parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-05-06 01:03:43 +01:00
|
|
|
bool visit(TypeId ty, const FreeTypeVar& ftv) override
|
|
|
|
{
|
2022-05-20 01:02:24 +01:00
|
|
|
seenMutableType = true;
|
2022-05-06 01:03:43 +01:00
|
|
|
|
2022-06-03 23:15:45 +01:00
|
|
|
if (FFlag::DebugLuauDeferredConstraintResolution ? !subsumes(scope, ftv.scope) : !level.subsumes(ftv.level))
|
2022-05-06 01:03:43 +01:00
|
|
|
return false;
|
|
|
|
|
2022-06-03 23:15:45 +01:00
|
|
|
if (FFlag::DebugLuauDeferredConstraintResolution)
|
|
|
|
*asMutable(ty) = GenericTypeVar{scope};
|
|
|
|
else
|
|
|
|
*asMutable(ty) = GenericTypeVar{level};
|
|
|
|
|
2022-05-06 01:03:43 +01:00
|
|
|
generics.push_back(ty);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool visit(TypeId ty, const TableTypeVar&) override
|
|
|
|
{
|
|
|
|
LUAU_ASSERT(getMutable<TableTypeVar>(ty));
|
2021-11-05 15:47:21 +00:00
|
|
|
TableTypeVar& ttv = *getMutable<TableTypeVar>(ty);
|
|
|
|
|
2022-05-20 01:02:24 +01:00
|
|
|
if (ttv.state == TableState::Generic)
|
|
|
|
seenGenericType = true;
|
2022-04-15 00:57:43 +01:00
|
|
|
|
2022-05-20 01:02:24 +01:00
|
|
|
if (ttv.state == TableState::Free)
|
|
|
|
seenMutableType = true;
|
2022-04-15 00:57:43 +01:00
|
|
|
|
2021-11-05 15:47:21 +00:00
|
|
|
if (ttv.state == TableState::Sealed || ttv.state == TableState::Generic)
|
|
|
|
return false;
|
2022-06-03 23:15:45 +01:00
|
|
|
if (FFlag::DebugLuauDeferredConstraintResolution ? !subsumes(scope, ttv.scope) : !level.subsumes(ttv.level))
|
2022-04-15 00:57:43 +01:00
|
|
|
{
|
2022-05-20 01:02:24 +01:00
|
|
|
if (ttv.state == TableState::Unsealed)
|
2022-04-15 00:57:43 +01:00
|
|
|
seenMutableType = true;
|
2021-11-05 15:47:21 +00:00
|
|
|
return false;
|
2022-04-15 00:57:43 +01:00
|
|
|
}
|
2021-11-05 15:47:21 +00:00
|
|
|
|
|
|
|
if (ttv.state == TableState::Free)
|
2022-04-15 00:57:43 +01:00
|
|
|
{
|
2021-11-05 15:47:21 +00:00
|
|
|
ttv.state = TableState::Generic;
|
2022-05-20 01:02:24 +01:00
|
|
|
seenGenericType = true;
|
2022-04-15 00:57:43 +01:00
|
|
|
}
|
2021-11-05 15:47:21 +00:00
|
|
|
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
|
2021-11-05 15:47:21 +00:00
|
|
|
{
|
2022-05-20 01:02:24 +01:00
|
|
|
seenMutableType = true;
|
2022-04-15 00:57:43 +01:00
|
|
|
|
2022-06-03 23:15:45 +01:00
|
|
|
if (FFlag::DebugLuauDeferredConstraintResolution ? !subsumes(scope, ftp.scope) : !level.subsumes(ftp.level))
|
2021-11-05 15:47:21 +00:00
|
|
|
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)
|
2021-11-05 15:47:21 +00:00
|
|
|
{
|
2022-02-18 01:18:01 +00:00
|
|
|
Quantifier q{level};
|
2022-05-26 23:08:16 +01:00
|
|
|
q.traverse(ty);
|
2021-11-05 15:47:21 +00:00
|
|
|
|
|
|
|
FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(ty);
|
|
|
|
LUAU_ASSERT(ftv);
|
2022-05-20 01:02:24 +01:00
|
|
|
if (FFlag::LuauAlwaysQuantify)
|
|
|
|
{
|
|
|
|
ftv->generics.insert(ftv->generics.end(), q.generics.begin(), q.generics.end());
|
|
|
|
ftv->genericPacks.insert(ftv->genericPacks.end(), q.genericPacks.begin(), q.genericPacks.end());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ftv->generics = q.generics;
|
|
|
|
ftv->genericPacks = q.genericPacks;
|
|
|
|
}
|
2022-04-15 00:57:43 +01:00
|
|
|
|
2022-05-20 01:02:24 +01:00
|
|
|
if (ftv->generics.empty() && ftv->genericPacks.empty() && !q.seenMutableType && !q.seenGenericType)
|
2022-04-15 00:57:43 +01:00
|
|
|
ftv->hasNoGenerics = true;
|
2022-06-03 23:15:45 +01:00
|
|
|
|
|
|
|
ftv->generalized = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void quantify(TypeId ty, Scope2* scope)
|
|
|
|
{
|
|
|
|
Quantifier q{scope};
|
|
|
|
q.traverse(ty);
|
|
|
|
|
|
|
|
FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(ty);
|
|
|
|
LUAU_ASSERT(ftv);
|
|
|
|
if (FFlag::LuauAlwaysQuantify)
|
|
|
|
{
|
|
|
|
ftv->generics.insert(ftv->generics.end(), q.generics.begin(), q.generics.end());
|
|
|
|
ftv->genericPacks.insert(ftv->genericPacks.end(), q.genericPacks.begin(), q.genericPacks.end());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ftv->generics = q.generics;
|
|
|
|
ftv->genericPacks = q.genericPacks;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ftv->generics.empty() && ftv->genericPacks.empty() && !q.seenMutableType && !q.seenGenericType)
|
|
|
|
ftv->hasNoGenerics = true;
|
|
|
|
|
|
|
|
ftv->generalized = true;
|
2021-11-05 15:47:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Luau
|