Sync to upstream/release/513 (#340)
This commit is contained in:
parent
c572f6944f
commit
d58e70b8c1
|
@ -285,12 +285,12 @@ struct TypesAreUnrelated
|
|||
bool operator==(const TypesAreUnrelated& rhs) const;
|
||||
};
|
||||
|
||||
using TypeErrorData = Variant<TypeMismatch, UnknownSymbol, UnknownProperty, NotATable, CannotExtendTable, OnlyTablesCanHaveMethods,
|
||||
DuplicateTypeDefinition, CountMismatch, FunctionDoesNotTakeSelf, FunctionRequiresSelf, OccursCheckFailed, UnknownRequire,
|
||||
IncorrectGenericParameterCount, SyntaxError, CodeTooComplex, UnificationTooComplex, UnknownPropButFoundLikeProp, GenericError,
|
||||
CannotCallNonFunction, ExtraInformation, DeprecatedApiUsed, ModuleHasCyclicDependency, IllegalRequire, FunctionExitsWithoutReturning,
|
||||
DuplicateGenericParameter, CannotInferBinaryOperation, MissingProperties, SwappedGenericTypeParameter, OptionalValueAccess, MissingUnionProperty,
|
||||
TypesAreUnrelated>;
|
||||
using TypeErrorData =
|
||||
Variant<TypeMismatch, UnknownSymbol, UnknownProperty, NotATable, CannotExtendTable, OnlyTablesCanHaveMethods, DuplicateTypeDefinition,
|
||||
CountMismatch, FunctionDoesNotTakeSelf, FunctionRequiresSelf, OccursCheckFailed, UnknownRequire, IncorrectGenericParameterCount, SyntaxError,
|
||||
CodeTooComplex, UnificationTooComplex, UnknownPropButFoundLikeProp, GenericError, CannotCallNonFunction, ExtraInformation, DeprecatedApiUsed,
|
||||
ModuleHasCyclicDependency, IllegalRequire, FunctionExitsWithoutReturning, DuplicateGenericParameter, CannotInferBinaryOperation,
|
||||
MissingProperties, SwappedGenericTypeParameter, OptionalValueAccess, MissingUnionProperty, TypesAreUnrelated>;
|
||||
|
||||
struct TypeError
|
||||
{
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "Luau/Variant.h"
|
||||
#include "Luau/Symbol.h"
|
||||
|
||||
#include <map> // TODO: Kill with LuauLValueAsKey.
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
|
@ -38,24 +37,13 @@ std::optional<LValue> tryGetLValue(const class AstExpr& expr);
|
|||
// Utility function: breaks down an LValue to get at the Symbol, and reverses the vector of keys.
|
||||
std::pair<Symbol, std::vector<std::string>> getFullName(const LValue& lvalue);
|
||||
|
||||
// Kill with LuauLValueAsKey.
|
||||
std::string toString(const LValue& lvalue);
|
||||
|
||||
template<typename T>
|
||||
const T* get(const LValue& lvalue)
|
||||
{
|
||||
return get_if<T>(&lvalue);
|
||||
}
|
||||
|
||||
using NEW_RefinementMap = std::unordered_map<LValue, TypeId, LValueHasher>;
|
||||
using DEPRECATED_RefinementMap = std::map<std::string, TypeId>;
|
||||
|
||||
// Transient. Kill with LuauLValueAsKey.
|
||||
struct RefinementMap
|
||||
{
|
||||
NEW_RefinementMap NEW_refinements;
|
||||
DEPRECATED_RefinementMap DEPRECATED_refinements;
|
||||
};
|
||||
using RefinementMap = std::unordered_map<LValue, TypeId, LValueHasher>;
|
||||
|
||||
void merge(RefinementMap& l, const RefinementMap& r, std::function<TypeId(TypeId, TypeId)> f);
|
||||
void addRefinement(RefinementMap& refis, const LValue& lvalue, TypeId ty);
|
||||
|
|
|
@ -55,6 +55,8 @@
|
|||
namespace Luau
|
||||
{
|
||||
|
||||
struct TxnLog;
|
||||
|
||||
enum class TarjanResult
|
||||
{
|
||||
TooManyChildren,
|
||||
|
@ -89,6 +91,10 @@ struct Tarjan
|
|||
|
||||
int childCount = 0;
|
||||
|
||||
// This should never be null; ensure you initialize it before calling
|
||||
// substitution methods.
|
||||
const TxnLog* log;
|
||||
|
||||
std::vector<TypeId> edgesTy;
|
||||
std::vector<TypePackId> edgesTp;
|
||||
std::vector<TarjanWorklistVertex> worklist;
|
||||
|
|
|
@ -72,6 +72,9 @@ struct PendingType
|
|||
}
|
||||
};
|
||||
|
||||
std::string toString(PendingType* pending);
|
||||
std::string dump(PendingType* pending);
|
||||
|
||||
// Pending state for a TypePackVar. Generated by a TxnLog and committed via
|
||||
// TxnLog::commit.
|
||||
struct PendingTypePack
|
||||
|
@ -85,6 +88,9 @@ struct PendingTypePack
|
|||
}
|
||||
};
|
||||
|
||||
std::string toString(PendingTypePack* pending);
|
||||
std::string dump(PendingTypePack* pending);
|
||||
|
||||
template<typename T>
|
||||
T* getMutable(PendingType* pending)
|
||||
{
|
||||
|
@ -237,7 +243,7 @@ struct TxnLog
|
|||
|
||||
// Follows a type, accounting for pending type states. The returned type may have
|
||||
// pending state; you should use `pending` or `get` to find out.
|
||||
TypeId follow(TypeId ty);
|
||||
TypeId follow(TypeId ty) const;
|
||||
|
||||
// Follows a type pack, accounting for pending type states. The returned type pack
|
||||
// may have pending state; you should use `pending` or `get` to find out.
|
||||
|
|
|
@ -262,7 +262,7 @@ public:
|
|||
* {method: ({method: (<CYCLE>) -> a}) -> a}
|
||||
*
|
||||
*/
|
||||
TypeId instantiate(const ScopePtr& scope, TypeId ty, Location location);
|
||||
TypeId instantiate(const ScopePtr& scope, TypeId ty, Location location, const TxnLog* log = TxnLog::empty());
|
||||
|
||||
// Replace any free types or type packs by `any`.
|
||||
// This is used when exporting types from modules, to make sure free types don't leak.
|
||||
|
@ -308,9 +308,15 @@ private:
|
|||
TypeId singletonType(bool value);
|
||||
TypeId singletonType(std::string value);
|
||||
|
||||
TypeIdPredicate mkTruthyPredicate(bool sense);
|
||||
|
||||
// Returns nullopt if the predicate filters down the TypeId to 0 options.
|
||||
std::optional<TypeId> filterMap(TypeId type, TypeIdPredicate predicate);
|
||||
|
||||
public:
|
||||
std::optional<TypeId> pickTypesFromSense(TypeId type, bool sense);
|
||||
|
||||
private:
|
||||
TypeId unionOfTypes(TypeId a, TypeId b, const Location& location, bool unifyFreeTypes = true);
|
||||
|
||||
// ex
|
||||
|
@ -349,7 +355,6 @@ private:
|
|||
void refineLValue(const LValue& lvalue, RefinementMap& refis, const ScopePtr& scope, TypeIdPredicate predicate);
|
||||
|
||||
std::optional<TypeId> resolveLValue(const ScopePtr& scope, const LValue& lvalue);
|
||||
std::optional<TypeId> DEPRECATED_resolveLValue(const ScopePtr& scope, const LValue& lvalue);
|
||||
std::optional<TypeId> resolveLValue(const RefinementMap& refis, const ScopePtr& scope, const LValue& lvalue);
|
||||
|
||||
void resolve(const PredicateVec& predicates, ErrorVec& errVec, RefinementMap& refis, const ScopePtr& scope, bool sense, bool fromOr = false);
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
LUAU_FASTFLAG(LuauTypedAllocatorZeroStart)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -22,10 +20,7 @@ class TypedAllocator
|
|||
public:
|
||||
TypedAllocator()
|
||||
{
|
||||
if (FFlag::LuauTypedAllocatorZeroStart)
|
||||
currentBlockSize = kBlockSize;
|
||||
else
|
||||
appendBlock();
|
||||
currentBlockSize = kBlockSize;
|
||||
}
|
||||
|
||||
~TypedAllocator()
|
||||
|
@ -64,18 +59,12 @@ public:
|
|||
|
||||
bool empty() const
|
||||
{
|
||||
if (FFlag::LuauTypedAllocatorZeroStart)
|
||||
return stuff.empty();
|
||||
else
|
||||
return stuff.size() == 1 && currentBlockSize == 0;
|
||||
return stuff.empty();
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
if (FFlag::LuauTypedAllocatorZeroStart)
|
||||
return stuff.empty() ? 0 : kBlockSize * (stuff.size() - 1) + currentBlockSize;
|
||||
else
|
||||
return kBlockSize * (stuff.size() - 1) + currentBlockSize;
|
||||
return stuff.empty() ? 0 : kBlockSize * (stuff.size() - 1) + currentBlockSize;
|
||||
}
|
||||
|
||||
void clear()
|
||||
|
@ -84,10 +73,7 @@ public:
|
|||
unfreeze();
|
||||
free();
|
||||
|
||||
if (FFlag::LuauTypedAllocatorZeroStart)
|
||||
currentBlockSize = kBlockSize;
|
||||
else
|
||||
appendBlock();
|
||||
currentBlockSize = kBlockSize;
|
||||
}
|
||||
|
||||
void freeze()
|
||||
|
|
|
@ -51,6 +51,10 @@ struct Unifier
|
|||
|
||||
private:
|
||||
void tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall = false, bool isIntersection = false);
|
||||
void tryUnifyUnionWithType(TypeId subTy, const UnionTypeVar* uv, TypeId superTy);
|
||||
void tryUnifyTypeWithUnion(TypeId subTy, TypeId superTy, const UnionTypeVar* uv, bool cacheEnabled, bool isFunctionCall);
|
||||
void tryUnifyTypeWithIntersection(TypeId subTy, TypeId superTy, const IntersectionTypeVar* uv);
|
||||
void tryUnifyIntersectionWithType(TypeId subTy, const IntersectionTypeVar* uv, TypeId superTy, bool cacheEnabled, bool isFunctionCall);
|
||||
void tryUnifyPrimitives(TypeId subTy, TypeId superTy);
|
||||
void tryUnifySingletons(TypeId subTy, TypeId superTy);
|
||||
void tryUnifyFunctions(TypeId subTy, TypeId superTy, bool isFunctionCall = false);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
LUAU_FASTFLAG(LuauAssertStripsFalsyTypes)
|
||||
|
||||
/** FIXME: Many of these type definitions are not quite completely accurate.
|
||||
*
|
||||
* Some of them require richer generics than we have. For instance, we do not yet have a way to talk
|
||||
|
@ -391,12 +393,41 @@ static std::optional<ExprResult<TypePackId>> magicFunctionAssert(
|
|||
{
|
||||
auto [paramPack, predicates] = exprResult;
|
||||
|
||||
if (expr.args.size < 1)
|
||||
if (FFlag::LuauAssertStripsFalsyTypes)
|
||||
{
|
||||
TypeArena& arena = typechecker.currentModule->internalTypes;
|
||||
|
||||
auto [head, tail] = flatten(paramPack);
|
||||
if (head.empty() && tail)
|
||||
{
|
||||
std::optional<TypeId> fst = first(*tail);
|
||||
if (!fst)
|
||||
return ExprResult<TypePackId>{paramPack};
|
||||
head.push_back(*fst);
|
||||
}
|
||||
|
||||
typechecker.reportErrors(typechecker.resolve(predicates, scope, true));
|
||||
|
||||
if (head.size() > 0)
|
||||
{
|
||||
std::optional<TypeId> newhead = typechecker.pickTypesFromSense(head[0], true);
|
||||
if (!newhead)
|
||||
head = {typechecker.nilType};
|
||||
else
|
||||
head[0] = *newhead;
|
||||
}
|
||||
|
||||
return ExprResult<TypePackId>{arena.addTypePack(TypePack{std::move(head), tail})};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (expr.args.size < 1)
|
||||
return ExprResult<TypePackId>{paramPack};
|
||||
|
||||
typechecker.reportErrors(typechecker.resolve(predicates, scope, true));
|
||||
|
||||
return ExprResult<TypePackId>{paramPack};
|
||||
|
||||
typechecker.reportErrors(typechecker.resolve(predicates, scope, true));
|
||||
|
||||
return ExprResult<TypePackId>{paramPack};
|
||||
}
|
||||
}
|
||||
|
||||
static std::optional<ExprResult<TypePackId>> magicFunctionPack(
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
LUAU_FASTFLAG(LuauLValueAsKey)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -94,17 +92,7 @@ std::pair<Symbol, std::vector<std::string>> getFullName(const LValue& lvalue)
|
|||
return {*symbol, std::vector<std::string>(keys.rbegin(), keys.rend())};
|
||||
}
|
||||
|
||||
// Kill with LuauLValueAsKey.
|
||||
std::string toString(const LValue& lvalue)
|
||||
{
|
||||
auto [symbol, keys] = getFullName(lvalue);
|
||||
std::string s = toString(symbol);
|
||||
for (std::string key : keys)
|
||||
s += "." + key;
|
||||
return s;
|
||||
}
|
||||
|
||||
static void merge(NEW_RefinementMap& l, const NEW_RefinementMap& r, std::function<TypeId(TypeId, TypeId)> f)
|
||||
void merge(RefinementMap& l, const RefinementMap& r, std::function<TypeId(TypeId, TypeId)> f)
|
||||
{
|
||||
for (const auto& [k, a] : r)
|
||||
{
|
||||
|
@ -115,45 +103,9 @@ static void merge(NEW_RefinementMap& l, const NEW_RefinementMap& r, std::functio
|
|||
}
|
||||
}
|
||||
|
||||
static void merge(DEPRECATED_RefinementMap& l, const DEPRECATED_RefinementMap& r, std::function<TypeId(TypeId, TypeId)> f)
|
||||
{
|
||||
auto itL = l.begin();
|
||||
auto itR = r.begin();
|
||||
while (itL != l.end() && itR != r.end())
|
||||
{
|
||||
const auto& [k, a] = *itR;
|
||||
if (itL->first == k)
|
||||
{
|
||||
l[k] = f(itL->second, a);
|
||||
++itL;
|
||||
++itR;
|
||||
}
|
||||
else if (itL->first < k)
|
||||
++itL;
|
||||
else
|
||||
{
|
||||
l[k] = a;
|
||||
++itR;
|
||||
}
|
||||
}
|
||||
|
||||
l.insert(itR, r.end());
|
||||
}
|
||||
|
||||
void merge(RefinementMap& l, const RefinementMap& r, std::function<TypeId(TypeId, TypeId)> f)
|
||||
{
|
||||
if (FFlag::LuauLValueAsKey)
|
||||
return merge(l.NEW_refinements, r.NEW_refinements, f);
|
||||
else
|
||||
return merge(l.DEPRECATED_refinements, r.DEPRECATED_refinements, f);
|
||||
}
|
||||
|
||||
void addRefinement(RefinementMap& refis, const LValue& lvalue, TypeId ty)
|
||||
{
|
||||
if (FFlag::LuauLValueAsKey)
|
||||
refis.NEW_refinements[lvalue] = ty;
|
||||
else
|
||||
refis.DEPRECATED_refinements[toString(lvalue)] = ty;
|
||||
refis[lvalue] = ty;
|
||||
}
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauLintTableCreateTable, false)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -2155,7 +2153,7 @@ private:
|
|||
"table.move uses index 0 but arrays are 1-based; did you mean 1 instead?");
|
||||
}
|
||||
|
||||
if (FFlag::LuauLintTableCreateTable && func->index == "create" && node->args.size == 2)
|
||||
if (func->index == "create" && node->args.size == 2)
|
||||
{
|
||||
// table.create(n, {...})
|
||||
if (args[1]->is<AstExprTable>())
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "Luau/Substitution.h"
|
||||
|
||||
#include "Luau/Common.h"
|
||||
#include "Luau/TxnLog.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
@ -13,17 +14,17 @@ namespace Luau
|
|||
|
||||
void Tarjan::visitChildren(TypeId ty, int index)
|
||||
{
|
||||
ty = follow(ty);
|
||||
ty = log->follow(ty);
|
||||
|
||||
if (ignoreChildren(ty))
|
||||
return;
|
||||
|
||||
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty))
|
||||
if (const FunctionTypeVar* ftv = log->getMutable<FunctionTypeVar>(ty))
|
||||
{
|
||||
visitChild(ftv->argTypes);
|
||||
visitChild(ftv->retType);
|
||||
}
|
||||
else if (const TableTypeVar* ttv = get<TableTypeVar>(ty))
|
||||
else if (const TableTypeVar* ttv = log->getMutable<TableTypeVar>(ty))
|
||||
{
|
||||
LUAU_ASSERT(!ttv->boundTo);
|
||||
for (const auto& [name, prop] : ttv->props)
|
||||
|
@ -40,17 +41,17 @@ void Tarjan::visitChildren(TypeId ty, int index)
|
|||
for (TypePackId itp : ttv->instantiatedTypePackParams)
|
||||
visitChild(itp);
|
||||
}
|
||||
else if (const MetatableTypeVar* mtv = get<MetatableTypeVar>(ty))
|
||||
else if (const MetatableTypeVar* mtv = log->getMutable<MetatableTypeVar>(ty))
|
||||
{
|
||||
visitChild(mtv->table);
|
||||
visitChild(mtv->metatable);
|
||||
}
|
||||
else if (const UnionTypeVar* utv = get<UnionTypeVar>(ty))
|
||||
else if (const UnionTypeVar* utv = log->getMutable<UnionTypeVar>(ty))
|
||||
{
|
||||
for (TypeId opt : utv->options)
|
||||
visitChild(opt);
|
||||
}
|
||||
else if (const IntersectionTypeVar* itv = get<IntersectionTypeVar>(ty))
|
||||
else if (const IntersectionTypeVar* itv = log->getMutable<IntersectionTypeVar>(ty))
|
||||
{
|
||||
for (TypeId part : itv->parts)
|
||||
visitChild(part);
|
||||
|
@ -59,19 +60,19 @@ void Tarjan::visitChildren(TypeId ty, int index)
|
|||
|
||||
void Tarjan::visitChildren(TypePackId tp, int index)
|
||||
{
|
||||
tp = follow(tp);
|
||||
tp = log->follow(tp);
|
||||
|
||||
if (ignoreChildren(tp))
|
||||
return;
|
||||
|
||||
if (const TypePack* tpp = get<TypePack>(tp))
|
||||
if (const TypePack* tpp = log->getMutable<TypePack>(tp))
|
||||
{
|
||||
for (TypeId tv : tpp->head)
|
||||
visitChild(tv);
|
||||
if (tpp->tail)
|
||||
visitChild(*tpp->tail);
|
||||
}
|
||||
else if (const VariadicTypePack* vtp = get<VariadicTypePack>(tp))
|
||||
else if (const VariadicTypePack* vtp = log->getMutable<VariadicTypePack>(tp))
|
||||
{
|
||||
visitChild(vtp->ty);
|
||||
}
|
||||
|
@ -79,7 +80,7 @@ void Tarjan::visitChildren(TypePackId tp, int index)
|
|||
|
||||
std::pair<int, bool> Tarjan::indexify(TypeId ty)
|
||||
{
|
||||
ty = follow(ty);
|
||||
ty = log->follow(ty);
|
||||
|
||||
bool fresh = !typeToIndex.contains(ty);
|
||||
int& index = typeToIndex[ty];
|
||||
|
@ -97,7 +98,7 @@ std::pair<int, bool> Tarjan::indexify(TypeId ty)
|
|||
|
||||
std::pair<int, bool> Tarjan::indexify(TypePackId tp)
|
||||
{
|
||||
tp = follow(tp);
|
||||
tp = log->follow(tp);
|
||||
|
||||
bool fresh = !packToIndex.contains(tp);
|
||||
int& index = packToIndex[tp];
|
||||
|
@ -115,7 +116,7 @@ std::pair<int, bool> Tarjan::indexify(TypePackId tp)
|
|||
|
||||
void Tarjan::visitChild(TypeId ty)
|
||||
{
|
||||
ty = follow(ty);
|
||||
ty = log->follow(ty);
|
||||
|
||||
edgesTy.push_back(ty);
|
||||
edgesTp.push_back(nullptr);
|
||||
|
@ -123,7 +124,7 @@ void Tarjan::visitChild(TypeId ty)
|
|||
|
||||
void Tarjan::visitChild(TypePackId tp)
|
||||
{
|
||||
tp = follow(tp);
|
||||
tp = log->follow(tp);
|
||||
|
||||
edgesTy.push_back(nullptr);
|
||||
edgesTp.push_back(tp);
|
||||
|
@ -243,7 +244,7 @@ void Tarjan::clear()
|
|||
TarjanResult Tarjan::visitRoot(TypeId ty)
|
||||
{
|
||||
childCount = 0;
|
||||
ty = follow(ty);
|
||||
ty = log->follow(ty);
|
||||
|
||||
clear();
|
||||
auto [index, fresh] = indexify(ty);
|
||||
|
@ -254,7 +255,7 @@ TarjanResult Tarjan::visitRoot(TypeId ty)
|
|||
TarjanResult Tarjan::visitRoot(TypePackId tp)
|
||||
{
|
||||
childCount = 0;
|
||||
tp = follow(tp);
|
||||
tp = log->follow(tp);
|
||||
|
||||
clear();
|
||||
auto [index, fresh] = indexify(tp);
|
||||
|
@ -325,7 +326,7 @@ TarjanResult FindDirty::findDirty(TypePackId tp)
|
|||
|
||||
std::optional<TypeId> Substitution::substitute(TypeId ty)
|
||||
{
|
||||
ty = follow(ty);
|
||||
ty = log->follow(ty);
|
||||
newTypes.clear();
|
||||
newPacks.clear();
|
||||
|
||||
|
@ -345,7 +346,7 @@ std::optional<TypeId> Substitution::substitute(TypeId ty)
|
|||
|
||||
std::optional<TypePackId> Substitution::substitute(TypePackId tp)
|
||||
{
|
||||
tp = follow(tp);
|
||||
tp = log->follow(tp);
|
||||
newTypes.clear();
|
||||
newPacks.clear();
|
||||
|
||||
|
@ -365,11 +366,11 @@ std::optional<TypePackId> Substitution::substitute(TypePackId tp)
|
|||
|
||||
TypeId Substitution::clone(TypeId ty)
|
||||
{
|
||||
ty = follow(ty);
|
||||
ty = log->follow(ty);
|
||||
|
||||
TypeId result = ty;
|
||||
|
||||
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty))
|
||||
if (const FunctionTypeVar* ftv = log->getMutable<FunctionTypeVar>(ty))
|
||||
{
|
||||
FunctionTypeVar clone = FunctionTypeVar{ftv->level, ftv->argTypes, ftv->retType, ftv->definition, ftv->hasSelf};
|
||||
clone.generics = ftv->generics;
|
||||
|
@ -379,7 +380,7 @@ TypeId Substitution::clone(TypeId ty)
|
|||
clone.argNames = ftv->argNames;
|
||||
result = addType(std::move(clone));
|
||||
}
|
||||
else if (const TableTypeVar* ttv = get<TableTypeVar>(ty))
|
||||
else if (const TableTypeVar* ttv = log->getMutable<TableTypeVar>(ty))
|
||||
{
|
||||
LUAU_ASSERT(!ttv->boundTo);
|
||||
TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, ttv->level, ttv->state};
|
||||
|
@ -392,19 +393,19 @@ TypeId Substitution::clone(TypeId ty)
|
|||
clone.tags = ttv->tags;
|
||||
result = addType(std::move(clone));
|
||||
}
|
||||
else if (const MetatableTypeVar* mtv = get<MetatableTypeVar>(ty))
|
||||
else if (const MetatableTypeVar* mtv = log->getMutable<MetatableTypeVar>(ty))
|
||||
{
|
||||
MetatableTypeVar clone = MetatableTypeVar{mtv->table, mtv->metatable};
|
||||
clone.syntheticName = mtv->syntheticName;
|
||||
result = addType(std::move(clone));
|
||||
}
|
||||
else if (const UnionTypeVar* utv = get<UnionTypeVar>(ty))
|
||||
else if (const UnionTypeVar* utv = log->getMutable<UnionTypeVar>(ty))
|
||||
{
|
||||
UnionTypeVar clone;
|
||||
clone.options = utv->options;
|
||||
result = addType(std::move(clone));
|
||||
}
|
||||
else if (const IntersectionTypeVar* itv = get<IntersectionTypeVar>(ty))
|
||||
else if (const IntersectionTypeVar* itv = log->getMutable<IntersectionTypeVar>(ty))
|
||||
{
|
||||
IntersectionTypeVar clone;
|
||||
clone.parts = itv->parts;
|
||||
|
@ -417,15 +418,15 @@ TypeId Substitution::clone(TypeId ty)
|
|||
|
||||
TypePackId Substitution::clone(TypePackId tp)
|
||||
{
|
||||
tp = follow(tp);
|
||||
if (const TypePack* tpp = get<TypePack>(tp))
|
||||
tp = log->follow(tp);
|
||||
if (const TypePack* tpp = log->getMutable<TypePack>(tp))
|
||||
{
|
||||
TypePack clone;
|
||||
clone.head = tpp->head;
|
||||
clone.tail = tpp->tail;
|
||||
return addTypePack(std::move(clone));
|
||||
}
|
||||
else if (const VariadicTypePack* vtp = get<VariadicTypePack>(tp))
|
||||
else if (const VariadicTypePack* vtp = log->getMutable<VariadicTypePack>(tp))
|
||||
{
|
||||
VariadicTypePack clone;
|
||||
clone.ty = vtp->ty;
|
||||
|
@ -437,7 +438,7 @@ TypePackId Substitution::clone(TypePackId tp)
|
|||
|
||||
void Substitution::foundDirty(TypeId ty)
|
||||
{
|
||||
ty = follow(ty);
|
||||
ty = log->follow(ty);
|
||||
if (isDirty(ty))
|
||||
newTypes[ty] = clean(ty);
|
||||
else
|
||||
|
@ -446,7 +447,7 @@ void Substitution::foundDirty(TypeId ty)
|
|||
|
||||
void Substitution::foundDirty(TypePackId tp)
|
||||
{
|
||||
tp = follow(tp);
|
||||
tp = log->follow(tp);
|
||||
if (isDirty(tp))
|
||||
newPacks[tp] = clean(tp);
|
||||
else
|
||||
|
@ -455,7 +456,7 @@ void Substitution::foundDirty(TypePackId tp)
|
|||
|
||||
TypeId Substitution::replace(TypeId ty)
|
||||
{
|
||||
ty = follow(ty);
|
||||
ty = log->follow(ty);
|
||||
if (TypeId* prevTy = newTypes.find(ty))
|
||||
return *prevTy;
|
||||
else
|
||||
|
@ -464,7 +465,7 @@ TypeId Substitution::replace(TypeId ty)
|
|||
|
||||
TypePackId Substitution::replace(TypePackId tp)
|
||||
{
|
||||
tp = follow(tp);
|
||||
tp = log->follow(tp);
|
||||
if (TypePackId* prevTp = newPacks.find(tp))
|
||||
return *prevTp;
|
||||
else
|
||||
|
@ -473,7 +474,7 @@ TypePackId Substitution::replace(TypePackId tp)
|
|||
|
||||
void Substitution::replaceChildren(TypeId ty)
|
||||
{
|
||||
ty = follow(ty);
|
||||
ty = log->follow(ty);
|
||||
|
||||
if (ignoreChildren(ty))
|
||||
return;
|
||||
|
@ -519,7 +520,7 @@ void Substitution::replaceChildren(TypeId ty)
|
|||
|
||||
void Substitution::replaceChildren(TypePackId tp)
|
||||
{
|
||||
tp = follow(tp);
|
||||
tp = log->follow(tp);
|
||||
|
||||
if (ignoreChildren(tp))
|
||||
return;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
#include "Luau/TxnLog.h"
|
||||
|
||||
#include "Luau/ToString.h"
|
||||
#include "Luau/TypePack.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -80,6 +81,56 @@ void DEPRECATED_TxnLog::popSeen(TypeId lhs, TypeId rhs)
|
|||
sharedSeen->pop_back();
|
||||
}
|
||||
|
||||
const std::string nullPendingResult = "<nullptr>";
|
||||
|
||||
std::string toString(PendingType* pending)
|
||||
{
|
||||
if (pending == nullptr)
|
||||
return nullPendingResult;
|
||||
|
||||
return toString(pending->pending);
|
||||
}
|
||||
|
||||
std::string dump(PendingType* pending)
|
||||
{
|
||||
if (pending == nullptr)
|
||||
{
|
||||
printf("%s\n", nullPendingResult.c_str());
|
||||
return nullPendingResult;
|
||||
}
|
||||
|
||||
ToStringOptions opts;
|
||||
opts.exhaustive = true;
|
||||
opts.functionTypeArguments = true;
|
||||
std::string result = toString(pending->pending, opts);
|
||||
printf("%s\n", result.c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string toString(PendingTypePack* pending)
|
||||
{
|
||||
if (pending == nullptr)
|
||||
return nullPendingResult;
|
||||
|
||||
return toString(pending->pending);
|
||||
}
|
||||
|
||||
std::string dump(PendingTypePack* pending)
|
||||
{
|
||||
if (pending == nullptr)
|
||||
{
|
||||
printf("%s\n", nullPendingResult.c_str());
|
||||
return nullPendingResult;
|
||||
}
|
||||
|
||||
ToStringOptions opts;
|
||||
opts.exhaustive = true;
|
||||
opts.functionTypeArguments = true;
|
||||
std::string result = toString(pending->pending, opts);
|
||||
printf("%s\n", result.c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
static const TxnLog emptyLog;
|
||||
|
||||
const TxnLog* TxnLog::empty()
|
||||
|
@ -199,8 +250,6 @@ PendingTypePack* TxnLog::queue(TypePackId tp)
|
|||
|
||||
PendingType* TxnLog::pending(TypeId ty) const
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauUseCommittingTxnLog);
|
||||
|
||||
for (const TxnLog* current = this; current; current = current->parent)
|
||||
{
|
||||
if (auto it = current->typeVarChanges.find(ty); it != current->typeVarChanges.end())
|
||||
|
@ -212,8 +261,6 @@ PendingType* TxnLog::pending(TypeId ty) const
|
|||
|
||||
PendingTypePack* TxnLog::pending(TypePackId tp) const
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauUseCommittingTxnLog);
|
||||
|
||||
for (const TxnLog* current = this; current; current = current->parent)
|
||||
{
|
||||
if (auto it = current->typePackChanges.find(tp); it != current->typePackChanges.end())
|
||||
|
@ -225,8 +272,6 @@ PendingTypePack* TxnLog::pending(TypePackId tp) const
|
|||
|
||||
PendingType* TxnLog::replace(TypeId ty, TypeVar replacement)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauUseCommittingTxnLog);
|
||||
|
||||
PendingType* newTy = queue(ty);
|
||||
newTy->pending = replacement;
|
||||
return newTy;
|
||||
|
@ -234,8 +279,6 @@ PendingType* TxnLog::replace(TypeId ty, TypeVar replacement)
|
|||
|
||||
PendingTypePack* TxnLog::replace(TypePackId tp, TypePackVar replacement)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauUseCommittingTxnLog);
|
||||
|
||||
PendingTypePack* newTp = queue(tp);
|
||||
newTp->pending = replacement;
|
||||
return newTp;
|
||||
|
@ -243,7 +286,6 @@ PendingTypePack* TxnLog::replace(TypePackId tp, TypePackVar replacement)
|
|||
|
||||
PendingType* TxnLog::bindTable(TypeId ty, std::optional<TypeId> newBoundTo)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauUseCommittingTxnLog);
|
||||
LUAU_ASSERT(get<TableTypeVar>(ty));
|
||||
|
||||
PendingType* newTy = queue(ty);
|
||||
|
@ -255,7 +297,6 @@ PendingType* TxnLog::bindTable(TypeId ty, std::optional<TypeId> newBoundTo)
|
|||
|
||||
PendingType* TxnLog::changeLevel(TypeId ty, TypeLevel newLevel)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauUseCommittingTxnLog);
|
||||
LUAU_ASSERT(get<FreeTypeVar>(ty) || get<TableTypeVar>(ty) || get<FunctionTypeVar>(ty));
|
||||
|
||||
PendingType* newTy = queue(ty);
|
||||
|
@ -278,7 +319,6 @@ PendingType* TxnLog::changeLevel(TypeId ty, TypeLevel newLevel)
|
|||
|
||||
PendingTypePack* TxnLog::changeLevel(TypePackId tp, TypeLevel newLevel)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauUseCommittingTxnLog);
|
||||
LUAU_ASSERT(get<FreeTypePack>(tp));
|
||||
|
||||
PendingTypePack* newTp = queue(tp);
|
||||
|
@ -292,7 +332,6 @@ PendingTypePack* TxnLog::changeLevel(TypePackId tp, TypeLevel newLevel)
|
|||
|
||||
PendingType* TxnLog::changeIndexer(TypeId ty, std::optional<TableIndexer> indexer)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauUseCommittingTxnLog);
|
||||
LUAU_ASSERT(get<TableTypeVar>(ty));
|
||||
|
||||
PendingType* newTy = queue(ty);
|
||||
|
@ -306,8 +345,6 @@ PendingType* TxnLog::changeIndexer(TypeId ty, std::optional<TableIndexer> indexe
|
|||
|
||||
std::optional<TypeLevel> TxnLog::getLevel(TypeId ty) const
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauUseCommittingTxnLog);
|
||||
|
||||
if (FreeTypeVar* ftv = getMutable<FreeTypeVar>(ty))
|
||||
return ftv->level;
|
||||
else if (TableTypeVar* ttv = getMutable<TableTypeVar>(ty); ttv && (ttv->state == TableState::Free || ttv->state == TableState::Generic))
|
||||
|
@ -318,10 +355,8 @@ std::optional<TypeLevel> TxnLog::getLevel(TypeId ty) const
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
TypeId TxnLog::follow(TypeId ty)
|
||||
TypeId TxnLog::follow(TypeId ty) const
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauUseCommittingTxnLog);
|
||||
|
||||
return Luau::follow(ty, [this](TypeId ty) {
|
||||
PendingType* state = this->pending(ty);
|
||||
|
||||
|
@ -337,8 +372,6 @@ TypeId TxnLog::follow(TypeId ty)
|
|||
|
||||
TypePackId TxnLog::follow(TypePackId tp) const
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauUseCommittingTxnLog);
|
||||
|
||||
return Luau::follow(tp, [this](TypePackId tp) {
|
||||
PendingTypePack* state = this->pending(tp);
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ LUAU_FASTFLAGVARIABLE(LuauRecursiveTypeParameterRestriction, false)
|
|||
LUAU_FASTFLAGVARIABLE(LuauIfElseBranchTypeUnion, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauIfElseExpectedType2, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauLengthOnCompositeType, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNoSealedTypeMod, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauQuantifyInPlace2, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSealExports, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSingletonTypes, false)
|
||||
|
@ -40,13 +41,12 @@ LUAU_FASTFLAGVARIABLE(LuauTypeAliasDefaults, false)
|
|||
LUAU_FASTFLAGVARIABLE(LuauExpectedTypesOfProperties, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauErrorRecoveryType, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauPropertiesGetExpectedType, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauLValueAsKey, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauRefiLookupFromIndexExpr, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauPerModuleUnificationCache, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauProperTypeLevels, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAscribeCorrectLevelToInferredProperitesOfFreeTables, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauBidirectionalAsExpr, false)
|
||||
LUAU_FASTFLAG(LuauUnionTagMatchFix)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUnsealedTableLiteral, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAssertStripsFalsyTypes, false)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -1117,7 +1117,7 @@ void TypeChecker::check(const ScopePtr& scope, TypeId ty, const ScopePtr& funSco
|
|||
|
||||
ty = follow(ty);
|
||||
|
||||
if (tableSelf && !selfTy->persistent)
|
||||
if (tableSelf && (FFlag::LuauNoSealedTypeMod ? tableSelf->state != TableState::Sealed : !selfTy->persistent))
|
||||
tableSelf->props[indexName->index.value] = {ty, /* deprecated */ false, {}, indexName->indexLocation};
|
||||
|
||||
const FunctionTypeVar* funTy = get<FunctionTypeVar>(ty);
|
||||
|
@ -1130,7 +1130,7 @@ void TypeChecker::check(const ScopePtr& scope, TypeId ty, const ScopePtr& funSco
|
|||
|
||||
checkFunctionBody(funScope, ty, *function.func);
|
||||
|
||||
if (tableSelf && !selfTy->persistent)
|
||||
if (tableSelf && (FFlag::LuauNoSealedTypeMod ? tableSelf->state != TableState::Sealed : !selfTy->persistent))
|
||||
tableSelf->props[indexName->index.value] = {
|
||||
follow(quantify(funScope, ty, indexName->indexLocation)), /* deprecated */ false, {}, indexName->indexLocation};
|
||||
}
|
||||
|
@ -1657,7 +1657,7 @@ std::optional<TypeId> TypeChecker::getIndexTypeFromType(
|
|||
RecursionLimiter _rl(&recursionCount, FInt::LuauTypeInferRecursionLimit);
|
||||
|
||||
// Not needed when we normalize types.
|
||||
if (FFlag::LuauLValueAsKey && get<AnyTypeVar>(follow(t)))
|
||||
if (get<AnyTypeVar>(follow(t)))
|
||||
return t;
|
||||
|
||||
if (std::optional<TypeId> ty = getIndexTypeFromType(scope, t, name, location, false))
|
||||
|
@ -1802,12 +1802,9 @@ ExprResult<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExprIn
|
|||
{
|
||||
TypeId ty = checkLValue(scope, expr);
|
||||
|
||||
if (FFlag::LuauRefiLookupFromIndexExpr)
|
||||
{
|
||||
if (std::optional<LValue> lvalue = tryGetLValue(expr))
|
||||
if (std::optional<TypeId> refiTy = resolveLValue(scope, *lvalue))
|
||||
return {*refiTy, {TruthyPredicate{std::move(*lvalue), expr.location}}};
|
||||
}
|
||||
if (std::optional<LValue> lvalue = tryGetLValue(expr))
|
||||
if (std::optional<TypeId> refiTy = resolveLValue(scope, *lvalue))
|
||||
return {*refiTy, {TruthyPredicate{std::move(*lvalue), expr.location}}};
|
||||
|
||||
return {ty};
|
||||
}
|
||||
|
@ -2471,33 +2468,28 @@ ExprResult<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExprBi
|
|||
{
|
||||
if (expr.op == AstExprBinary::And)
|
||||
{
|
||||
ExprResult<TypeId> lhs = checkExpr(scope, *expr.left);
|
||||
auto [lhsTy, lhsPredicates] = checkExpr(scope, *expr.left);
|
||||
|
||||
// We can't just report errors here.
|
||||
// This function can be called from AstStatLocal or from AstStatIf, or even from AstExprBinary (and others).
|
||||
// For now, ignore the errors returned by the predicate resolver.
|
||||
// We may need an extra property for each predicate set that indicates it has been resolved.
|
||||
// Requires a slight modification to the data structure.
|
||||
ScopePtr innerScope = childScope(scope, expr.location);
|
||||
resolve(lhs.predicates, innerScope, true);
|
||||
resolve(lhsPredicates, innerScope, true);
|
||||
|
||||
ExprResult<TypeId> rhs = checkExpr(innerScope, *expr.right);
|
||||
auto [rhsTy, rhsPredicates] = checkExpr(innerScope, *expr.right);
|
||||
|
||||
return {checkBinaryOperation(FFlag::LuauDiscriminableUnions ? scope : innerScope, expr, lhs.type, rhs.type),
|
||||
{AndPredicate{std::move(lhs.predicates), std::move(rhs.predicates)}}};
|
||||
return {checkBinaryOperation(FFlag::LuauDiscriminableUnions ? scope : innerScope, expr, lhsTy, rhsTy),
|
||||
{AndPredicate{std::move(lhsPredicates), std::move(rhsPredicates)}}};
|
||||
}
|
||||
else if (expr.op == AstExprBinary::Or)
|
||||
{
|
||||
ExprResult<TypeId> lhs = checkExpr(scope, *expr.left);
|
||||
auto [lhsTy, lhsPredicates] = checkExpr(scope, *expr.left);
|
||||
|
||||
ScopePtr innerScope = childScope(scope, expr.location);
|
||||
resolve(lhs.predicates, innerScope, false);
|
||||
resolve(lhsPredicates, innerScope, false);
|
||||
|
||||
ExprResult<TypeId> rhs = checkExpr(innerScope, *expr.right);
|
||||
auto [rhsTy, rhsPredicates] = checkExpr(innerScope, *expr.right);
|
||||
|
||||
// Because of C++, I'm not sure if lhs.predicates was not moved out by the time we call checkBinaryOperation.
|
||||
TypeId result = checkBinaryOperation(FFlag::LuauDiscriminableUnions ? scope : innerScope, expr, lhs.type, rhs.type, lhs.predicates);
|
||||
return {result, {OrPredicate{std::move(lhs.predicates), std::move(rhs.predicates)}}};
|
||||
// Because of C++, I'm not sure if lhsPredicates was not moved out by the time we call checkBinaryOperation.
|
||||
TypeId result = checkBinaryOperation(FFlag::LuauDiscriminableUnions ? scope : innerScope, expr, lhsTy, rhsTy, lhsPredicates);
|
||||
return {result, {OrPredicate{std::move(lhsPredicates), std::move(rhsPredicates)}}};
|
||||
}
|
||||
else if (expr.op == AstExprBinary::CompareEq || expr.op == AstExprBinary::CompareNe)
|
||||
{
|
||||
|
@ -2535,27 +2527,15 @@ ExprResult<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExprTy
|
|||
TypeId annotationType = resolveType(scope, *expr.annotation);
|
||||
ExprResult<TypeId> result = checkExpr(scope, *expr.expr, annotationType);
|
||||
|
||||
if (FFlag::LuauBidirectionalAsExpr)
|
||||
{
|
||||
// Note: As an optimization, we try 'number <: number | string' first, as that is the more likely case.
|
||||
if (canUnify(annotationType, result.type, expr.location).empty())
|
||||
return {annotationType, std::move(result.predicates)};
|
||||
|
||||
if (canUnify(result.type, annotationType, expr.location).empty())
|
||||
return {annotationType, std::move(result.predicates)};
|
||||
|
||||
reportError(expr.location, TypesAreUnrelated{result.type, annotationType});
|
||||
return {errorRecoveryType(annotationType), std::move(result.predicates)};
|
||||
}
|
||||
else
|
||||
{
|
||||
ErrorVec errorVec = canUnify(annotationType, result.type, expr.location);
|
||||
reportErrors(errorVec);
|
||||
if (!errorVec.empty())
|
||||
annotationType = errorRecoveryType(annotationType);
|
||||
|
||||
// Note: As an optimization, we try 'number <: number | string' first, as that is the more likely case.
|
||||
if (canUnify(annotationType, result.type, expr.location).empty())
|
||||
return {annotationType, std::move(result.predicates)};
|
||||
}
|
||||
|
||||
if (canUnify(result.type, annotationType, expr.location).empty())
|
||||
return {annotationType, std::move(result.predicates)};
|
||||
|
||||
reportError(expr.location, TypesAreUnrelated{result.type, annotationType});
|
||||
return {errorRecoveryType(annotationType), std::move(result.predicates)};
|
||||
}
|
||||
|
||||
ExprResult<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExprError& expr)
|
||||
|
@ -4295,7 +4275,7 @@ void TypeChecker::unifyWithInstantiationIfNeeded(const ScopePtr& scope, TypeId s
|
|||
child.tryUnify(subTy, superTy, /*isFunctionCall*/ false);
|
||||
if (!child.errors.empty())
|
||||
{
|
||||
TypeId instantiated = instantiate(scope, subTy, state.location);
|
||||
TypeId instantiated = instantiate(scope, subTy, state.location, &child.log);
|
||||
if (subTy == instantiated)
|
||||
{
|
||||
// Instantiating the argument made no difference, so just report any child errors
|
||||
|
@ -4330,7 +4310,7 @@ void TypeChecker::unifyWithInstantiationIfNeeded(const ScopePtr& scope, TypeId s
|
|||
|
||||
bool Instantiation::isDirty(TypeId ty)
|
||||
{
|
||||
if (get<FunctionTypeVar>(ty))
|
||||
if (log->getMutable<FunctionTypeVar>(ty))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
@ -4343,7 +4323,7 @@ bool Instantiation::isDirty(TypePackId tp)
|
|||
|
||||
bool Instantiation::ignoreChildren(TypeId ty)
|
||||
{
|
||||
if (get<FunctionTypeVar>(ty))
|
||||
if (log->getMutable<FunctionTypeVar>(ty))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
@ -4351,7 +4331,7 @@ bool Instantiation::ignoreChildren(TypeId ty)
|
|||
|
||||
TypeId Instantiation::clean(TypeId ty)
|
||||
{
|
||||
const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty);
|
||||
const FunctionTypeVar* ftv = log->getMutable<FunctionTypeVar>(ty);
|
||||
LUAU_ASSERT(ftv);
|
||||
|
||||
FunctionTypeVar clone = FunctionTypeVar{level, ftv->argTypes, ftv->retType, ftv->definition, ftv->hasSelf};
|
||||
|
@ -4362,6 +4342,7 @@ TypeId Instantiation::clean(TypeId ty)
|
|||
|
||||
// Annoyingly, we have to do this even if there are no generics,
|
||||
// to replace any generic tables.
|
||||
replaceGenerics.log = log;
|
||||
replaceGenerics.level = level;
|
||||
replaceGenerics.currentModule = currentModule;
|
||||
replaceGenerics.generics.assign(ftv->generics.begin(), ftv->generics.end());
|
||||
|
@ -4383,7 +4364,7 @@ TypePackId Instantiation::clean(TypePackId tp)
|
|||
|
||||
bool ReplaceGenerics::ignoreChildren(TypeId ty)
|
||||
{
|
||||
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty))
|
||||
if (const FunctionTypeVar* ftv = log->getMutable<FunctionTypeVar>(ty))
|
||||
// We aren't recursing in the case of a generic function which
|
||||
// binds the same generics. This can happen if, for example, there's recursive types.
|
||||
// If T = <a>(a,T)->T then instantiating T should produce T' = (X,T)->T not T' = (X,T')->T'.
|
||||
|
@ -4396,9 +4377,9 @@ bool ReplaceGenerics::ignoreChildren(TypeId ty)
|
|||
|
||||
bool ReplaceGenerics::isDirty(TypeId ty)
|
||||
{
|
||||
if (const TableTypeVar* ttv = get<TableTypeVar>(ty))
|
||||
if (const TableTypeVar* ttv = log->getMutable<TableTypeVar>(ty))
|
||||
return ttv->state == TableState::Generic;
|
||||
else if (get<GenericTypeVar>(ty))
|
||||
else if (log->getMutable<GenericTypeVar>(ty))
|
||||
return std::find(generics.begin(), generics.end(), ty) != generics.end();
|
||||
else
|
||||
return false;
|
||||
|
@ -4406,7 +4387,7 @@ bool ReplaceGenerics::isDirty(TypeId ty)
|
|||
|
||||
bool ReplaceGenerics::isDirty(TypePackId tp)
|
||||
{
|
||||
if (get<GenericTypePack>(tp))
|
||||
if (log->getMutable<GenericTypePack>(tp))
|
||||
return std::find(genericPacks.begin(), genericPacks.end(), tp) != genericPacks.end();
|
||||
else
|
||||
return false;
|
||||
|
@ -4415,7 +4396,7 @@ bool ReplaceGenerics::isDirty(TypePackId tp)
|
|||
TypeId ReplaceGenerics::clean(TypeId ty)
|
||||
{
|
||||
LUAU_ASSERT(isDirty(ty));
|
||||
if (const TableTypeVar* ttv = get<TableTypeVar>(ty))
|
||||
if (const TableTypeVar* ttv = log->getMutable<TableTypeVar>(ty))
|
||||
{
|
||||
TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, level, TableState::Free};
|
||||
clone.methodDefinitionLocations = ttv->methodDefinitionLocations;
|
||||
|
@ -4434,9 +4415,9 @@ TypePackId ReplaceGenerics::clean(TypePackId tp)
|
|||
|
||||
bool Quantification::isDirty(TypeId ty)
|
||||
{
|
||||
if (const TableTypeVar* ttv = get<TableTypeVar>(ty))
|
||||
if (const TableTypeVar* ttv = log->getMutable<TableTypeVar>(ty))
|
||||
return level.subsumes(ttv->level) && ((ttv->state == TableState::Free) || (ttv->state == TableState::Unsealed));
|
||||
else if (const FreeTypeVar* ftv = get<FreeTypeVar>(ty))
|
||||
else if (const FreeTypeVar* ftv = log->getMutable<FreeTypeVar>(ty))
|
||||
return level.subsumes(ftv->level);
|
||||
else
|
||||
return false;
|
||||
|
@ -4444,7 +4425,7 @@ bool Quantification::isDirty(TypeId ty)
|
|||
|
||||
bool Quantification::isDirty(TypePackId tp)
|
||||
{
|
||||
if (const FreeTypePack* ftv = get<FreeTypePack>(tp))
|
||||
if (const FreeTypePack* ftv = log->getMutable<FreeTypePack>(tp))
|
||||
return level.subsumes(ftv->level);
|
||||
else
|
||||
return false;
|
||||
|
@ -4453,7 +4434,7 @@ bool Quantification::isDirty(TypePackId tp)
|
|||
TypeId Quantification::clean(TypeId ty)
|
||||
{
|
||||
LUAU_ASSERT(isDirty(ty));
|
||||
if (const TableTypeVar* ttv = get<TableTypeVar>(ty))
|
||||
if (const TableTypeVar* ttv = log->getMutable<TableTypeVar>(ty))
|
||||
{
|
||||
TableState state = (ttv->state == TableState::Unsealed ? TableState::Sealed : TableState::Generic);
|
||||
TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, level, state};
|
||||
|
@ -4479,9 +4460,9 @@ TypePackId Quantification::clean(TypePackId tp)
|
|||
|
||||
bool Anyification::isDirty(TypeId ty)
|
||||
{
|
||||
if (const TableTypeVar* ttv = get<TableTypeVar>(ty))
|
||||
if (const TableTypeVar* ttv = log->getMutable<TableTypeVar>(ty))
|
||||
return (ttv->state == TableState::Free || (FFlag::LuauSealExports && ttv->state == TableState::Unsealed));
|
||||
else if (get<FreeTypeVar>(ty))
|
||||
else if (log->getMutable<FreeTypeVar>(ty))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
@ -4489,7 +4470,7 @@ bool Anyification::isDirty(TypeId ty)
|
|||
|
||||
bool Anyification::isDirty(TypePackId tp)
|
||||
{
|
||||
if (get<FreeTypePack>(tp))
|
||||
if (log->getMutable<FreeTypePack>(tp))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
|
@ -4498,7 +4479,7 @@ bool Anyification::isDirty(TypePackId tp)
|
|||
TypeId Anyification::clean(TypeId ty)
|
||||
{
|
||||
LUAU_ASSERT(isDirty(ty));
|
||||
if (const TableTypeVar* ttv = get<TableTypeVar>(ty))
|
||||
if (const TableTypeVar* ttv = log->getMutable<TableTypeVar>(ty))
|
||||
{
|
||||
TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, ttv->level, TableState::Sealed};
|
||||
clone.methodDefinitionLocations = ttv->methodDefinitionLocations;
|
||||
|
@ -4535,6 +4516,7 @@ TypeId TypeChecker::quantify(const ScopePtr& scope, TypeId ty, Location location
|
|||
return ty;
|
||||
}
|
||||
|
||||
quantification.log = TxnLog::empty();
|
||||
quantification.level = scope->level;
|
||||
quantification.generics.clear();
|
||||
quantification.genericPacks.clear();
|
||||
|
@ -4558,8 +4540,11 @@ TypeId TypeChecker::quantify(const ScopePtr& scope, TypeId ty, Location location
|
|||
return *qty;
|
||||
}
|
||||
|
||||
TypeId TypeChecker::instantiate(const ScopePtr& scope, TypeId ty, Location location)
|
||||
TypeId TypeChecker::instantiate(const ScopePtr& scope, TypeId ty, Location location, const TxnLog* log)
|
||||
{
|
||||
LUAU_ASSERT(log != nullptr);
|
||||
|
||||
instantiation.log = FFlag::LuauUseCommittingTxnLog ? log : TxnLog::empty();
|
||||
instantiation.level = scope->level;
|
||||
instantiation.currentModule = currentModule;
|
||||
std::optional<TypeId> instantiated = instantiation.substitute(ty);
|
||||
|
@ -4574,6 +4559,7 @@ TypeId TypeChecker::instantiate(const ScopePtr& scope, TypeId ty, Location locat
|
|||
|
||||
TypeId TypeChecker::anyify(const ScopePtr& scope, TypeId ty, Location location)
|
||||
{
|
||||
anyification.log = TxnLog::empty();
|
||||
anyification.anyType = anyType;
|
||||
anyification.anyTypePack = anyTypePack;
|
||||
anyification.currentModule = currentModule;
|
||||
|
@ -4589,6 +4575,7 @@ TypeId TypeChecker::anyify(const ScopePtr& scope, TypeId ty, Location location)
|
|||
|
||||
TypePackId TypeChecker::anyify(const ScopePtr& scope, TypePackId ty, Location location)
|
||||
{
|
||||
anyification.log = TxnLog::empty();
|
||||
anyification.anyType = anyType;
|
||||
anyification.anyTypePack = anyTypePack;
|
||||
anyification.currentModule = currentModule;
|
||||
|
@ -4660,7 +4647,7 @@ void TypeChecker::diagnoseMissingTableKey(UnknownProperty* utk, TypeErrorData& d
|
|||
}
|
||||
};
|
||||
|
||||
if (auto ttv = getTableType(follow(utk->table)))
|
||||
if (auto ttv = getTableType(FFlag::LuauUnionTagMatchFix ? utk->table : follow(utk->table)))
|
||||
accumulate(ttv->props);
|
||||
else if (auto ctv = get<ClassTypeVar>(follow(utk->table)))
|
||||
{
|
||||
|
@ -4775,6 +4762,29 @@ TypePackId TypeChecker::errorRecoveryTypePack(TypePackId guess)
|
|||
return getSingletonTypes().errorRecoveryTypePack(guess);
|
||||
}
|
||||
|
||||
TypeIdPredicate TypeChecker::mkTruthyPredicate(bool sense) {
|
||||
return [this, sense](TypeId ty) -> std::optional<TypeId> {
|
||||
// any/error/free gets a special pass unconditionally because they can't be decided.
|
||||
if (get<AnyTypeVar>(ty) || get<ErrorTypeVar>(ty) || get<FreeTypeVar>(ty))
|
||||
return ty;
|
||||
|
||||
// maps boolean primitive to the corresponding singleton equal to sense
|
||||
if (isPrim(ty, PrimitiveTypeVar::Boolean))
|
||||
return singletonType(sense);
|
||||
|
||||
// if we have boolean singleton, eliminate it if the sense doesn't match with that singleton
|
||||
if (auto boolean = get<BooleanSingleton>(get<SingletonTypeVar>(ty)))
|
||||
return boolean->value == sense ? std::optional<TypeId>(ty) : std::nullopt;
|
||||
|
||||
// if we have nil, eliminate it if sense is true, otherwise take it
|
||||
if (isNil(ty))
|
||||
return sense ? std::nullopt : std::optional<TypeId>(ty);
|
||||
|
||||
// at this point, anything else is kept if sense is true, or eliminated otherwise
|
||||
return sense ? std::optional<TypeId>(ty) : std::nullopt;
|
||||
};
|
||||
}
|
||||
|
||||
std::optional<TypeId> TypeChecker::filterMap(TypeId type, TypeIdPredicate predicate)
|
||||
{
|
||||
std::vector<TypeId> types = Luau::filterMap(type, predicate);
|
||||
|
@ -4783,6 +4793,11 @@ std::optional<TypeId> TypeChecker::filterMap(TypeId type, TypeIdPredicate predic
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<TypeId> TypeChecker::pickTypesFromSense(TypeId type, bool sense)
|
||||
{
|
||||
return filterMap(type, mkTruthyPredicate(sense));
|
||||
}
|
||||
|
||||
TypeId TypeChecker::addTV(TypeVar&& tv)
|
||||
{
|
||||
return currentModule->internalTypes.addType(std::move(tv));
|
||||
|
@ -4962,6 +4977,7 @@ TypeId TypeChecker::resolveType(const ScopePtr& scope, const AstType& annotation
|
|||
if (notEnoughParameters && hasDefaultParameters)
|
||||
{
|
||||
// 'applyTypeFunction' is used to substitute default types that reference previous generic types
|
||||
applyTypeFunction.log = TxnLog::empty();
|
||||
applyTypeFunction.typeArguments.clear();
|
||||
applyTypeFunction.typePackArguments.clear();
|
||||
applyTypeFunction.currentModule = currentModule;
|
||||
|
@ -5293,6 +5309,7 @@ TypeId TypeChecker::instantiateTypeFun(const ScopePtr& scope, const TypeFun& tf,
|
|||
for (size_t i = 0; i < tf.typePackParams.size(); ++ |