mirror of
https://github.com/luau-lang/luau.git
synced 2025-08-26 11:27:08 +01:00
Sync to upstream/release/684 (#1930)
## General - Support AstStatDeclareGlobal output as a source string (via @karl-police in #1889) - Luau heap dump correctly reports the size of a string, now including overhead for the string type - Prevent yields from Luau `xpcall` error handling function. ## Analysis - Avoid exponential blowup when normalizing union of normalized free variables. - Fix type pack-related bugs that caused infinite recursion when: - A generic type pack was bound to itself during subtyping. - In type pack flattening, when that same generic type pack was now being bound another generic type pack which contained it. - Properly simplify `any & (*error-type* | string)` to `*error-type* | *error-type* | string` instead of hanging due to creating a huge union type. --- Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Ariel Weiss <aaronweiss@roblox.com> Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com> Co-authored-by: Sora Kanosue <skanosue@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com> Co-authored-by: Varun Saini <61795485+vrn-sn@users.noreply.github.com> Co-authored-by: Menarul Alam <malam@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Vighnesh <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Ariel Weiss <aaronweiss@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com>
This commit is contained in:
parent
b668ffb8c8
commit
66202dc4ac
87 changed files with 1103 additions and 520 deletions
|
@ -53,4 +53,4 @@ struct BuiltinTypeFunctions
|
||||||
|
|
||||||
const BuiltinTypeFunctions& builtinTypeFunctions();
|
const BuiltinTypeFunctions& builtinTypeFunctions();
|
||||||
|
|
||||||
}
|
} // namespace Luau
|
||||||
|
|
|
@ -341,7 +341,6 @@ struct Constraint
|
||||||
DenseHashSet<TypeId> getMaybeMutatedFreeTypes_DEPRECATED() const;
|
DenseHashSet<TypeId> getMaybeMutatedFreeTypes_DEPRECATED() const;
|
||||||
|
|
||||||
TypeIds getMaybeMutatedFreeTypes() const;
|
TypeIds getMaybeMutatedFreeTypes() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using ConstraintPtr = std::unique_ptr<Constraint>;
|
using ConstraintPtr = std::unique_ptr<Constraint>;
|
||||||
|
|
|
@ -92,6 +92,11 @@ struct GenericTypeFinder : TypeOnceVisitor
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
|
GenericTypeFinder()
|
||||||
|
: TypeOnceVisitor("GenericTypeFinder")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool visit(TypeId ty) override
|
bool visit(TypeId ty) override
|
||||||
{
|
{
|
||||||
return !found;
|
return !found;
|
||||||
|
|
|
@ -65,4 +65,4 @@ private:
|
||||||
DenseHashSet<T> elementSet{nullptr};
|
DenseHashSet<T> elementSet{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace Luau
|
|
@ -12,8 +12,8 @@ namespace Luau
|
||||||
|
|
||||||
struct RecursionLimitException : public InternalCompilerError
|
struct RecursionLimitException : public InternalCompilerError
|
||||||
{
|
{
|
||||||
RecursionLimitException()
|
RecursionLimitException(const std::string system)
|
||||||
: InternalCompilerError("Internal recursion counter limit exceeded")
|
: InternalCompilerError("Internal recursion counter limit exceeded in " + system)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -38,12 +38,12 @@ protected:
|
||||||
|
|
||||||
struct RecursionLimiter : RecursionCounter
|
struct RecursionLimiter : RecursionCounter
|
||||||
{
|
{
|
||||||
RecursionLimiter(int* count, int limit)
|
RecursionLimiter(const std::string system, int* count, int limit)
|
||||||
: RecursionCounter(count)
|
: RecursionCounter(count)
|
||||||
{
|
{
|
||||||
if (limit > 0 && *count > limit)
|
if (limit > 0 && *count > limit)
|
||||||
{
|
{
|
||||||
throw RecursionLimitException();
|
throw RecursionLimitException(system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -157,8 +157,10 @@ struct Subtyping
|
||||||
Variance variance = Variance::Covariant;
|
Variance variance = Variance::Covariant;
|
||||||
|
|
||||||
using SeenSet = Set<std::pair<TypeId, TypeId>, TypePairHash>;
|
using SeenSet = Set<std::pair<TypeId, TypeId>, TypePairHash>;
|
||||||
|
using SeenTypePackSet = Set<std::pair<TypePackId, TypePackId>, TypePairHash>;
|
||||||
|
|
||||||
SeenSet seenTypes{{}};
|
SeenSet seenTypes{{}};
|
||||||
|
SeenTypePackSet seenPacks{{}};
|
||||||
|
|
||||||
Subtyping(
|
Subtyping(
|
||||||
NotNull<BuiltinTypes> builtinTypes,
|
NotNull<BuiltinTypes> builtinTypes,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Luau/Common.h"
|
#include "Luau/Common.h"
|
||||||
|
#include "Luau/DenseHash.h"
|
||||||
#include "Luau/TypeFwd.h"
|
#include "Luau/TypeFwd.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -134,6 +135,10 @@ std::string dump(TypeId ty);
|
||||||
std::string dump(const std::optional<TypeId>& ty);
|
std::string dump(const std::optional<TypeId>& ty);
|
||||||
std::string dump(TypePackId ty);
|
std::string dump(TypePackId ty);
|
||||||
std::string dump(const std::optional<TypePackId>& ty);
|
std::string dump(const std::optional<TypePackId>& ty);
|
||||||
|
std::string dump(const std::vector<TypeId>& types);
|
||||||
|
std::string dump(DenseHashMap<TypeId, TypeId>& types);
|
||||||
|
std::string dump(DenseHashMap<TypePackId, TypePackId>& types);
|
||||||
|
|
||||||
std::string dump(const Constraint& c);
|
std::string dump(const Constraint& c);
|
||||||
|
|
||||||
std::string dump(const std::shared_ptr<Scope>& scope, const char* name);
|
std::string dump(const std::shared_ptr<Scope>& scope, const char* name);
|
||||||
|
@ -153,4 +158,5 @@ inline std::string toString(const TypeOrPack& tyOrTp)
|
||||||
|
|
||||||
std::string dump(const TypeOrPack& tyOrTp);
|
std::string dump(const TypeOrPack& tyOrTp);
|
||||||
|
|
||||||
|
std::string toStringVector(const std::vector<TypeId>& types, ToStringOptions& opts);
|
||||||
} // namespace Luau
|
} // namespace Luau
|
||||||
|
|
|
@ -32,8 +32,8 @@ public:
|
||||||
TypeIds(const TypeIds&) = default;
|
TypeIds(const TypeIds&) = default;
|
||||||
TypeIds& operator=(const TypeIds&) = default;
|
TypeIds& operator=(const TypeIds&) = default;
|
||||||
|
|
||||||
TypeIds(TypeIds&&) = default;
|
TypeIds(TypeIds&&) noexcept = default;
|
||||||
TypeIds& operator=(TypeIds&&) = default;
|
TypeIds& operator=(TypeIds&&) noexcept = default;
|
||||||
|
|
||||||
void insert(TypeId ty);
|
void insert(TypeId ty);
|
||||||
/// Erase every element that does not also occur in tys
|
/// Erase every element that does not also occur in tys
|
||||||
|
|
|
@ -231,7 +231,7 @@ std::string toString(const TypePath::Path& path, bool prefixDot = false);
|
||||||
/// Converts a Path to a human readable string for error reporting.
|
/// Converts a Path to a human readable string for error reporting.
|
||||||
std::string toStringHuman(const TypePath::Path& path);
|
std::string toStringHuman(const TypePath::Path& path);
|
||||||
|
|
||||||
// TODO: clip traverse_DEPRECATED along with `LuauReturnMappedGenericPacksFromSubtyping`
|
// TODO: clip traverse_DEPRECATED along with `LuauReturnMappedGenericPacksFromSubtyping2`
|
||||||
std::optional<TypeOrPack> traverse_DEPRECATED(TypeId root, const Path& path, NotNull<BuiltinTypes> builtinTypes);
|
std::optional<TypeOrPack> traverse_DEPRECATED(TypeId root, const Path& path, NotNull<BuiltinTypes> builtinTypes);
|
||||||
std::optional<TypeOrPack> traverse_DEPRECATED(TypePackId root, const Path& path, NotNull<BuiltinTypes> builtinTypes);
|
std::optional<TypeOrPack> traverse_DEPRECATED(TypePackId root, const Path& path, NotNull<BuiltinTypes> builtinTypes);
|
||||||
std::optional<TypeOrPack> traverse(
|
std::optional<TypeOrPack> traverse(
|
||||||
|
|
|
@ -73,6 +73,8 @@ struct GenericTypeVisitor
|
||||||
{
|
{
|
||||||
using Set = S;
|
using Set = S;
|
||||||
|
|
||||||
|
const std::string visitorName;
|
||||||
|
|
||||||
Set seen;
|
Set seen;
|
||||||
bool skipBoundTypes = false;
|
bool skipBoundTypes = false;
|
||||||
int recursionCounter = 0;
|
int recursionCounter = 0;
|
||||||
|
@ -80,8 +82,9 @@ struct GenericTypeVisitor
|
||||||
|
|
||||||
GenericTypeVisitor() = default;
|
GenericTypeVisitor() = default;
|
||||||
|
|
||||||
explicit GenericTypeVisitor(Set seen, bool skipBoundTypes = false)
|
explicit GenericTypeVisitor(const std::string visitorName, Set seen, bool skipBoundTypes = false)
|
||||||
: seen(std::move(seen))
|
: visitorName(visitorName)
|
||||||
|
, seen(std::move(seen))
|
||||||
, skipBoundTypes(skipBoundTypes)
|
, skipBoundTypes(skipBoundTypes)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -215,7 +218,7 @@ struct GenericTypeVisitor
|
||||||
|
|
||||||
void traverse(TypeId ty)
|
void traverse(TypeId ty)
|
||||||
{
|
{
|
||||||
RecursionLimiter limiter{&recursionCounter, FInt::LuauVisitRecursionLimit};
|
RecursionLimiter limiter{visitorName, &recursionCounter, FInt::LuauVisitRecursionLimit};
|
||||||
|
|
||||||
if (visit_detail::hasSeen(seen, ty))
|
if (visit_detail::hasSeen(seen, ty))
|
||||||
{
|
{
|
||||||
|
@ -527,8 +530,8 @@ struct GenericTypeVisitor
|
||||||
*/
|
*/
|
||||||
struct TypeVisitor : GenericTypeVisitor<std::unordered_set<void*>>
|
struct TypeVisitor : GenericTypeVisitor<std::unordered_set<void*>>
|
||||||
{
|
{
|
||||||
explicit TypeVisitor(bool skipBoundTypes = false)
|
explicit TypeVisitor(const std::string visitorName, bool skipBoundTypes = false)
|
||||||
: GenericTypeVisitor{{}, skipBoundTypes}
|
: GenericTypeVisitor{visitorName, {}, skipBoundTypes}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -536,8 +539,8 @@ struct TypeVisitor : GenericTypeVisitor<std::unordered_set<void*>>
|
||||||
/// Visit each type under a given type. Each type will only be checked once even if there are multiple paths to it.
|
/// Visit each type under a given type. Each type will only be checked once even if there are multiple paths to it.
|
||||||
struct TypeOnceVisitor : GenericTypeVisitor<DenseHashSet<void*>>
|
struct TypeOnceVisitor : GenericTypeVisitor<DenseHashSet<void*>>
|
||||||
{
|
{
|
||||||
explicit TypeOnceVisitor(bool skipBoundTypes = false)
|
explicit TypeOnceVisitor(const std::string visitorName, bool skipBoundTypes = false)
|
||||||
: GenericTypeVisitor{DenseHashSet<void*>{nullptr}, skipBoundTypes}
|
: GenericTypeVisitor{visitorName, DenseHashSet<void*>{nullptr}, skipBoundTypes}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -583,7 +583,9 @@ std::optional<DocumentationSymbol> getDocumentationSymbolAtPosition(const Source
|
||||||
return checkOverloadedDocumentationSymbol(module, *ty, parentExpr, propIt->second.documentationSymbol);
|
return checkOverloadedDocumentationSymbol(module, *ty, parentExpr, propIt->second.documentationSymbol);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return checkOverloadedDocumentationSymbol(module, propIt->second.type_DEPRECATED(), parentExpr, propIt->second.documentationSymbol);
|
return checkOverloadedDocumentationSymbol(
|
||||||
|
module, propIt->second.type_DEPRECATED(), parentExpr, propIt->second.documentationSymbol
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (const ExternType* etv = get<ExternType>(parentTy))
|
else if (const ExternType* etv = get<ExternType>(parentTy))
|
||||||
|
|
|
@ -771,7 +771,9 @@ bool MagicFormat::typeCheck(const MagicFunctionTypeCheckContext& context)
|
||||||
|
|
||||||
if (iter == end(context.arguments))
|
if (iter == end(context.arguments))
|
||||||
{
|
{
|
||||||
context.typechecker->reportError(CountMismatch{1, std::nullopt, 0, CountMismatch::Arg, true, "string.format"}, context.callSite->location);
|
context.typechecker->reportError(
|
||||||
|
CountMismatch{1, std::nullopt, 0, CountMismatch::Arg, true, "string.format"}, context.callSite->location
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,7 +825,8 @@ bool MagicFormat::typeCheck(const MagicFunctionTypeCheckContext& context)
|
||||||
{
|
{
|
||||||
TypeId actualTy = params[i + paramOffset];
|
TypeId actualTy = params[i + paramOffset];
|
||||||
TypeId expectedTy = expected[i];
|
TypeId expectedTy = expected[i];
|
||||||
Location location = context.callSite->args.data[std::min(context.callSite->args.size - 1, i + (calledWithSelf ? 0 : paramOffset))]->location;
|
Location location =
|
||||||
|
context.callSite->args.data[std::min(context.callSite->args.size - 1, i + (calledWithSelf ? 0 : paramOffset))]->location;
|
||||||
// use subtyping instead here
|
// use subtyping instead here
|
||||||
SubtypingResult result = context.typechecker->subtyping->isSubtype(actualTy, expectedTy, context.checkScope);
|
SubtypingResult result = context.typechecker->subtyping->isSubtype(actualTy, expectedTy, context.checkScope);
|
||||||
|
|
||||||
|
@ -845,7 +848,6 @@ bool MagicFormat::typeCheck(const MagicFunctionTypeCheckContext& context)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -863,7 +865,9 @@ bool MagicFormat::typeCheck(const MagicFunctionTypeCheckContext& context)
|
||||||
|
|
||||||
if (!fmt)
|
if (!fmt)
|
||||||
{
|
{
|
||||||
context.typechecker->reportError(CountMismatch{1, std::nullopt, 0, CountMismatch::Arg, true, "string.format"}, context.callSite->location);
|
context.typechecker->reportError(
|
||||||
|
CountMismatch{1, std::nullopt, 0, CountMismatch::Arg, true, "string.format"}, context.callSite->location
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -887,7 +891,8 @@ bool MagicFormat::typeCheck(const MagicFunctionTypeCheckContext& context)
|
||||||
{
|
{
|
||||||
TypeId actualTy = params[i + paramOffset];
|
TypeId actualTy = params[i + paramOffset];
|
||||||
TypeId expectedTy = expected[i];
|
TypeId expectedTy = expected[i];
|
||||||
Location location = context.callSite->args.data[std::min(context.callSite->args.size - 1, i + (calledWithSelf ? 0 : paramOffset))]->location;
|
Location location =
|
||||||
|
context.callSite->args.data[std::min(context.callSite->args.size - 1, i + (calledWithSelf ? 0 : paramOffset))]->location;
|
||||||
// use subtyping instead here
|
// use subtyping instead here
|
||||||
SubtypingResult result = context.typechecker->subtyping->isSubtype(actualTy, expectedTy, context.checkScope);
|
SubtypingResult result = context.typechecker->subtyping->isSubtype(actualTy, expectedTy, context.checkScope);
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ std::optional<TypeFunctionReductionResult<TypeId>> tryDistributeTypeFunctionApp(
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
TypeFunctionReductionResult<TypeId> notTypeFunction(
|
TypeFunctionReductionResult<TypeId> notTypeFunction(
|
||||||
TypeId instance,
|
TypeId instance,
|
||||||
|
@ -1034,6 +1034,12 @@ TypeFunctionReductionResult<TypeId> eqTypeFunction(
|
||||||
struct FindRefinementBlockers : TypeOnceVisitor
|
struct FindRefinementBlockers : TypeOnceVisitor
|
||||||
{
|
{
|
||||||
DenseHashSet<TypeId> found{nullptr};
|
DenseHashSet<TypeId> found{nullptr};
|
||||||
|
|
||||||
|
FindRefinementBlockers()
|
||||||
|
: TypeOnceVisitor("FindRefinementBlockers")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool visit(TypeId ty, const BlockedType&) override
|
bool visit(TypeId ty, const BlockedType&) override
|
||||||
{
|
{
|
||||||
found.insert(ty);
|
found.insert(ty);
|
||||||
|
@ -1056,7 +1062,7 @@ struct ContainsRefinableType : TypeOnceVisitor
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
ContainsRefinableType()
|
ContainsRefinableType()
|
||||||
: TypeOnceVisitor(/* skipBoundTypes */ true)
|
: TypeOnceVisitor("ContainsRefinableType", /* skipBoundTypes */ true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1199,7 +1205,6 @@ struct RefineTypeScrubber : public Substitution
|
||||||
}
|
}
|
||||||
return ty;
|
return ty;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool occurs(TypeId haystack, TypeId needle, DenseHashSet<TypeId>& seen)
|
bool occurs(TypeId haystack, TypeId needle, DenseHashSet<TypeId>& seen)
|
||||||
|
@ -1431,7 +1436,6 @@ TypeFunctionReductionResult<TypeId> refineTypeFunction(
|
||||||
|
|
||||||
return {resultTy, {}};
|
return {resultTy, {}};
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// refine target with each discriminant type in sequence (reverse of insertion order)
|
// refine target with each discriminant type in sequence (reverse of insertion order)
|
||||||
|
@ -1494,7 +1498,7 @@ struct CollectUnionTypeOptions : TypeOnceVisitor
|
||||||
DenseHashSet<TypeId> blockingTypes{nullptr};
|
DenseHashSet<TypeId> blockingTypes{nullptr};
|
||||||
|
|
||||||
explicit CollectUnionTypeOptions(NotNull<TypeFunctionContext> ctx)
|
explicit CollectUnionTypeOptions(NotNull<TypeFunctionContext> ctx)
|
||||||
: TypeOnceVisitor(/* skipBoundTypes */ true)
|
: TypeOnceVisitor("CollectUnionTypeOptions", /* skipBoundTypes */ true)
|
||||||
, ctx(ctx)
|
, ctx(ctx)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -1764,7 +1768,8 @@ bool computeKeysOf_DEPRECATED(TypeId ty, Set<std::string>& result, DenseHashSet<
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes the keys of `ty` into `result`
|
* Computes the keys of `ty` into `result`
|
||||||
|
@ -1847,7 +1852,7 @@ bool computeKeysOf(TypeId ty, Set<std::optional<std::string>>& result, DenseHash
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
TypeFunctionReductionResult<TypeId> keyofFunctionImpl(
|
TypeFunctionReductionResult<TypeId> keyofFunctionImpl(
|
||||||
const std::vector<TypeId>& typeParams,
|
const std::vector<TypeId>& typeParams,
|
||||||
|
@ -2824,4 +2829,4 @@ const BuiltinTypeFunctions& builtinTypeFunctions()
|
||||||
return *result;
|
return *result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Luau
|
||||||
|
|
|
@ -24,7 +24,8 @@ struct ReferenceCountInitializer_DEPRECATED : TypeOnceVisitor
|
||||||
bool traverseIntoTypeFunctions = true;
|
bool traverseIntoTypeFunctions = true;
|
||||||
|
|
||||||
explicit ReferenceCountInitializer_DEPRECATED(DenseHashSet<TypeId>* result)
|
explicit ReferenceCountInitializer_DEPRECATED(DenseHashSet<TypeId>* result)
|
||||||
: result(result)
|
: TypeOnceVisitor("ReferenceCountInitializer_DEPRECATED")
|
||||||
|
, result(result)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +79,8 @@ struct ReferenceCountInitializer : TypeOnceVisitor
|
||||||
bool traverseIntoTypeFunctions = true;
|
bool traverseIntoTypeFunctions = true;
|
||||||
|
|
||||||
explicit ReferenceCountInitializer(NotNull<TypeIds> result)
|
explicit ReferenceCountInitializer(NotNull<TypeIds> result)
|
||||||
: result(result)
|
: TypeOnceVisitor("ReferenceCountInitializer")
|
||||||
|
, result(result)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,10 @@ struct HasFreeType : TypeOnceVisitor
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
HasFreeType() {}
|
HasFreeType()
|
||||||
|
: TypeOnceVisitor("TypeOnceVisitor")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool visit(TypeId ty) override
|
bool visit(TypeId ty) override
|
||||||
{
|
{
|
||||||
|
@ -640,6 +643,11 @@ struct FindSimplificationBlockers : TypeOnceVisitor
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
|
FindSimplificationBlockers()
|
||||||
|
: TypeOnceVisitor("FindSimplificationBlockers")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool visit(TypeId) override
|
bool visit(TypeId) override
|
||||||
{
|
{
|
||||||
return !found;
|
return !found;
|
||||||
|
@ -1026,7 +1034,7 @@ ControlFlow ConstraintGenerator::visitBlockWithoutChildScope(const ScopePtr& sco
|
||||||
|
|
||||||
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStat* stat)
|
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStat* stat)
|
||||||
{
|
{
|
||||||
RecursionLimiter limiter{&recursionCount, FInt::LuauCheckRecursionLimit};
|
RecursionLimiter limiter{"ConstraintGenerator", &recursionCount, FInt::LuauCheckRecursionLimit};
|
||||||
|
|
||||||
if (auto s = stat->as<AstStatBlock>())
|
if (auto s = stat->as<AstStatBlock>())
|
||||||
return visit(scope, s);
|
return visit(scope, s);
|
||||||
|
|
|
@ -34,7 +34,6 @@ LUAU_FASTINTVARIABLE(LuauSolverRecursionLimit, 500)
|
||||||
LUAU_FASTFLAGVARIABLE(DebugLuauEqSatSimplification)
|
LUAU_FASTFLAGVARIABLE(DebugLuauEqSatSimplification)
|
||||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauGuardAgainstMalformedTypeAliasExpansion2)
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauAvoidGenericsLeakingDuringFunctionCallCheck)
|
LUAU_FASTFLAGVARIABLE(LuauAvoidGenericsLeakingDuringFunctionCallCheck)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauMissingFollowInAssignIndexConstraint)
|
LUAU_FASTFLAGVARIABLE(LuauMissingFollowInAssignIndexConstraint)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauRemoveTypeCallsForReadWriteProps)
|
LUAU_FASTFLAGVARIABLE(LuauRemoveTypeCallsForReadWriteProps)
|
||||||
|
@ -43,6 +42,7 @@ LUAU_FASTFLAGVARIABLE(LuauUseOrderedTypeSetsInConstraints)
|
||||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||||
LUAU_FASTFLAG(LuauAvoidExcessiveTypeCopying)
|
LUAU_FASTFLAG(LuauAvoidExcessiveTypeCopying)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauForceSimplifyConstraint)
|
LUAU_FASTFLAGVARIABLE(LuauForceSimplifyConstraint)
|
||||||
|
LUAU_FASTFLAGVARIABLE(LuauContainsAnyGenericFollowBeforeChecking)
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
|
@ -285,7 +285,8 @@ struct InstantiationQueuer : TypeOnceVisitor
|
||||||
Location location;
|
Location location;
|
||||||
|
|
||||||
explicit InstantiationQueuer(NotNull<Scope> scope, const Location& location, ConstraintSolver* solver)
|
explicit InstantiationQueuer(NotNull<Scope> scope, const Location& location, ConstraintSolver* solver)
|
||||||
: solver(solver)
|
: TypeOnceVisitor("InstantiationQueuer")
|
||||||
|
, solver(solver)
|
||||||
, scope(scope)
|
, scope(scope)
|
||||||
, location(location)
|
, location(location)
|
||||||
{
|
{
|
||||||
|
@ -432,7 +433,8 @@ void ConstraintSolver::run()
|
||||||
{
|
{
|
||||||
for (TypeId ty : constraintSet.freeTypes)
|
for (TypeId ty : constraintSet.freeTypes)
|
||||||
{
|
{
|
||||||
if (auto it = mutatedFreeTypeToConstraint_DEPRECATED.find(ty); it == mutatedFreeTypeToConstraint_DEPRECATED.end() || it->second.empty())
|
if (auto it = mutatedFreeTypeToConstraint_DEPRECATED.find(ty);
|
||||||
|
it == mutatedFreeTypeToConstraint_DEPRECATED.end() || it->second.empty())
|
||||||
generalizeOneType(ty);
|
generalizeOneType(ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -633,8 +635,7 @@ void ConstraintSolver::finalizeTypeFunctions()
|
||||||
if (get<TypeFunctionInstanceType>(ty))
|
if (get<TypeFunctionInstanceType>(ty))
|
||||||
{
|
{
|
||||||
TypeFunctionContext context{NotNull{this}, constraint->scope, NotNull{constraint}};
|
TypeFunctionContext context{NotNull{this}, constraint->scope, NotNull{constraint}};
|
||||||
FunctionGraphReductionResult result =
|
FunctionGraphReductionResult result = reduceTypeFunctions(t, constraint->location, NotNull{&context}, true);
|
||||||
reduceTypeFunctions(t, constraint->location, NotNull{&context}, true);
|
|
||||||
|
|
||||||
for (TypeId r : result.reducedTypes)
|
for (TypeId r : result.reducedTypes)
|
||||||
unblock(r, constraint->location);
|
unblock(r, constraint->location);
|
||||||
|
@ -663,7 +664,8 @@ struct TypeSearcher : TypeVisitor
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit TypeSearcher(TypeId needle, Polarity initialPolarity)
|
explicit TypeSearcher(TypeId needle, Polarity initialPolarity)
|
||||||
: needle(needle)
|
: TypeVisitor("TypeSearcher")
|
||||||
|
, needle(needle)
|
||||||
, current(initialPolarity)
|
, current(initialPolarity)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -1195,7 +1197,8 @@ struct InfiniteTypeFinder : TypeOnceVisitor
|
||||||
bool foundInfiniteType = false;
|
bool foundInfiniteType = false;
|
||||||
|
|
||||||
explicit InfiniteTypeFinder(ConstraintSolver* solver, const InstantiationSignature& signature, NotNull<Scope> scope)
|
explicit InfiniteTypeFinder(ConstraintSolver* solver, const InstantiationSignature& signature, NotNull<Scope> scope)
|
||||||
: solver(solver)
|
: TypeOnceVisitor("InfiniteTypeFinder")
|
||||||
|
, solver(solver)
|
||||||
, signature(signature)
|
, signature(signature)
|
||||||
, scope(scope)
|
, scope(scope)
|
||||||
{
|
{
|
||||||
|
@ -1235,7 +1238,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
|
||||||
auto cTarget = follow(c.target);
|
auto cTarget = follow(c.target);
|
||||||
LUAU_ASSERT(get<PendingExpansionType>(cTarget));
|
LUAU_ASSERT(get<PendingExpansionType>(cTarget));
|
||||||
// We do this check here to ensure that we don't bind an alias to itself
|
// We do this check here to ensure that we don't bind an alias to itself
|
||||||
if (FFlag::LuauGuardAgainstMalformedTypeAliasExpansion2 && occursCheck(cTarget, result))
|
if (occursCheck(cTarget, result))
|
||||||
{
|
{
|
||||||
reportError(OccursCheckFailed{}, constraint->location);
|
reportError(OccursCheckFailed{}, constraint->location);
|
||||||
bind(constraint, cTarget, builtinTypes->errorType);
|
bind(constraint, cTarget, builtinTypes->errorType);
|
||||||
|
@ -1656,6 +1659,11 @@ struct ContainsGenerics_DEPRECATED : public TypeOnceVisitor
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
|
ContainsGenerics_DEPRECATED()
|
||||||
|
: TypeOnceVisitor("ContainsGenerics_DEPRECATED")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool visit(TypeId ty) override
|
bool visit(TypeId ty) override
|
||||||
{
|
{
|
||||||
return !found;
|
return !found;
|
||||||
|
@ -1736,7 +1744,8 @@ struct ContainsGenerics : public TypeOnceVisitor
|
||||||
NotNull<DenseHashSet<const void*>> generics;
|
NotNull<DenseHashSet<const void*>> generics;
|
||||||
|
|
||||||
explicit ContainsGenerics(NotNull<DenseHashSet<const void*>> generics)
|
explicit ContainsGenerics(NotNull<DenseHashSet<const void*>> generics)
|
||||||
: generics{generics}
|
: TypeOnceVisitor("ContainsGenerics")
|
||||||
|
, generics{generics}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2139,7 +2148,7 @@ bool ConstraintSolver::tryDispatchHasIndexer(
|
||||||
Set<TypeId>& seen
|
Set<TypeId>& seen
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
RecursionLimiter _rl{&recursionDepth, FInt::LuauSolverRecursionLimit};
|
RecursionLimiter _rl{"ConstraintSolver::tryDispatchHasIndexer", &recursionDepth, FInt::LuauSolverRecursionLimit};
|
||||||
|
|
||||||
subjectType = follow(subjectType);
|
subjectType = follow(subjectType);
|
||||||
indexType = follow(indexType);
|
indexType = follow(indexType);
|
||||||
|
@ -2315,6 +2324,11 @@ struct BlockedTypeFinder : TypeOnceVisitor
|
||||||
{
|
{
|
||||||
std::optional<TypeId> blocked;
|
std::optional<TypeId> blocked;
|
||||||
|
|
||||||
|
BlockedTypeFinder()
|
||||||
|
: TypeOnceVisitor("ContainsGenerics_DEPRECATED")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool visit(TypeId ty) override
|
bool visit(TypeId ty) override
|
||||||
{
|
{
|
||||||
// If we've already found one, stop traversing.
|
// If we've already found one, stop traversing.
|
||||||
|
@ -2873,7 +2887,7 @@ struct FindAllUnionMembers : TypeOnceVisitor
|
||||||
TypeIds blockedTys;
|
TypeIds blockedTys;
|
||||||
|
|
||||||
FindAllUnionMembers()
|
FindAllUnionMembers()
|
||||||
: TypeOnceVisitor(/* skipBoundTypes */ true)
|
: TypeOnceVisitor("FindAllUnionMembers", /* skipBoundTypes */ true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2959,7 +2973,7 @@ struct ContainsAnyGeneric final : public TypeOnceVisitor
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
explicit ContainsAnyGeneric()
|
explicit ContainsAnyGeneric()
|
||||||
: TypeOnceVisitor(true)
|
: TypeOnceVisitor("ContainsAnyGeneric", /* skipBoundTypes */ true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2971,6 +2985,9 @@ struct ContainsAnyGeneric final : public TypeOnceVisitor
|
||||||
|
|
||||||
bool visit(TypePackId ty) override
|
bool visit(TypePackId ty) override
|
||||||
{
|
{
|
||||||
|
if (FFlag::LuauContainsAnyGenericFollowBeforeChecking)
|
||||||
|
found = found || is<GenericTypePack>(follow(ty));
|
||||||
|
else
|
||||||
found = found || is<GenericTypePack>(ty);
|
found = found || is<GenericTypePack>(ty);
|
||||||
return !found;
|
return !found;
|
||||||
}
|
}
|
||||||
|
@ -3367,7 +3384,8 @@ TablePropLookupResult ConstraintSolver::lookupTableProp(
|
||||||
return {{}, builtinTypes->errorType};
|
return {{}, builtinTypes->errorType};
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeId indexType = FFlag::LuauRemoveTypeCallsForReadWriteProps ? follow(*indexProp->second.readTy) : follow(indexProp->second.type_DEPRECATED());
|
TypeId indexType =
|
||||||
|
FFlag::LuauRemoveTypeCallsForReadWriteProps ? follow(*indexProp->second.readTy) : follow(indexProp->second.type_DEPRECATED());
|
||||||
|
|
||||||
if (auto ft = get<FunctionType>(indexType))
|
if (auto ft = get<FunctionType>(indexType))
|
||||||
{
|
{
|
||||||
|
@ -3654,7 +3672,8 @@ struct Blocker : TypeOnceVisitor
|
||||||
bool blocked = false;
|
bool blocked = false;
|
||||||
|
|
||||||
explicit Blocker(NotNull<ConstraintSolver> solver, NotNull<const Constraint> constraint)
|
explicit Blocker(NotNull<ConstraintSolver> solver, NotNull<const Constraint> constraint)
|
||||||
: solver(solver)
|
: TypeOnceVisitor("Blocker")
|
||||||
|
, solver(solver)
|
||||||
, constraint(constraint)
|
, constraint(constraint)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||||
#include "Luau/BuiltinDefinitions.h"
|
#include "Luau/BuiltinDefinitions.h"
|
||||||
|
|
||||||
LUAU_FASTFLAG(LuauDeclareExternType)
|
|
||||||
LUAU_FASTFLAG(LuauTypeFunOptional)
|
LUAU_FASTFLAG(LuauTypeFunOptional)
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
|
@ -262,8 +261,7 @@ declare buffer: {
|
||||||
|
|
||||||
)BUILTIN_SRC";
|
)BUILTIN_SRC";
|
||||||
|
|
||||||
static const char* const kBuiltinDefinitionVectorSrc = (FFlag::LuauDeclareExternType)
|
static const char* const kBuiltinDefinitionVectorSrc = R"BUILTIN_SRC(
|
||||||
? R"BUILTIN_SRC(
|
|
||||||
|
|
||||||
-- While vector would have been better represented as a built-in primitive type, type solver extern type handling covers most of the properties
|
-- While vector would have been better represented as a built-in primitive type, type solver extern type handling covers most of the properties
|
||||||
declare extern type vector with
|
declare extern type vector with
|
||||||
|
@ -291,35 +289,6 @@ declare vector: {
|
||||||
one: vector,
|
one: vector,
|
||||||
}
|
}
|
||||||
|
|
||||||
)BUILTIN_SRC"
|
|
||||||
: R"BUILTIN_SRC(
|
|
||||||
|
|
||||||
-- While vector would have been better represented as a built-in primitive type, type solver class handling covers most of the properties
|
|
||||||
declare class vector
|
|
||||||
x: number
|
|
||||||
y: number
|
|
||||||
z: number
|
|
||||||
end
|
|
||||||
|
|
||||||
declare vector: {
|
|
||||||
create: @checked (x: number, y: number, z: number?) -> vector,
|
|
||||||
magnitude: @checked (vec: vector) -> number,
|
|
||||||
normalize: @checked (vec: vector) -> vector,
|
|
||||||
cross: @checked (vec1: vector, vec2: vector) -> vector,
|
|
||||||
dot: @checked (vec1: vector, vec2: vector) -> number,
|
|
||||||
angle: @checked (vec1: vector, vec2: vector, axis: vector?) -> number,
|
|
||||||
floor: @checked (vec: vector) -> vector,
|
|
||||||
ceil: @checked (vec: vector) -> vector,
|
|
||||||
abs: @checked (vec: vector) -> vector,
|
|
||||||
sign: @checked (vec: vector) -> vector,
|
|
||||||
clamp: @checked (vec: vector, min: vector, max: vector) -> vector,
|
|
||||||
max: @checked (vector, ...vector) -> vector,
|
|
||||||
min: @checked (vector, ...vector) -> vector,
|
|
||||||
|
|
||||||
zero: vector,
|
|
||||||
one: vector,
|
|
||||||
}
|
|
||||||
|
|
||||||
)BUILTIN_SRC";
|
)BUILTIN_SRC";
|
||||||
|
|
||||||
std::string getBuiltinDefinitionSource()
|
std::string getBuiltinDefinitionSource()
|
||||||
|
|
|
@ -81,7 +81,9 @@ struct IndexerIndexCollector : public TypeOnceVisitor
|
||||||
{
|
{
|
||||||
NotNull<TypeIds> indexes;
|
NotNull<TypeIds> indexes;
|
||||||
|
|
||||||
explicit IndexerIndexCollector(NotNull<TypeIds> indexes) : TypeOnceVisitor(/* skipBoundTypes */ true), indexes(indexes)
|
explicit IndexerIndexCollector(NotNull<TypeIds> indexes)
|
||||||
|
: TypeOnceVisitor("IndexerIndexCollector", /* skipBoundTypes */ true)
|
||||||
|
, indexes(indexes)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +102,6 @@ struct IndexerIndexCollector : public TypeOnceVisitor
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IndexCollector : public TypeOnceVisitor
|
struct IndexCollector : public TypeOnceVisitor
|
||||||
|
@ -108,7 +109,9 @@ struct IndexCollector : public TypeOnceVisitor
|
||||||
NotNull<TypeArena> arena;
|
NotNull<TypeArena> arena;
|
||||||
TypeIds indexes;
|
TypeIds indexes;
|
||||||
|
|
||||||
explicit IndexCollector(NotNull<TypeArena> arena) : TypeOnceVisitor(/* skipBoundTypes */ true), arena(arena)
|
explicit IndexCollector(NotNull<TypeArena> arena)
|
||||||
|
: TypeOnceVisitor("IndexCollector", /* skipBoundTypes */ true)
|
||||||
|
, arena(arena)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,10 +143,9 @@ struct IndexCollector : public TypeOnceVisitor
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
bool ExpectedTypeVisitor::visit(AstExprIndexExpr* expr)
|
bool ExpectedTypeVisitor::visit(AstExprIndexExpr* expr)
|
||||||
{
|
{
|
||||||
|
@ -156,17 +158,11 @@ bool ExpectedTypeVisitor::visit(AstExprIndexExpr* expr)
|
||||||
ic.traverse(*ty);
|
ic.traverse(*ty);
|
||||||
if (ic.indexes.size() > 1)
|
if (ic.indexes.size() > 1)
|
||||||
{
|
{
|
||||||
applyExpectedType(
|
applyExpectedType(arena->addType(UnionType{ic.indexes.take()}), expr->index);
|
||||||
arena->addType(UnionType{ic.indexes.take()}),
|
|
||||||
expr->index
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
else if (ic.indexes.size() == 1)
|
else if (ic.indexes.size() == 1)
|
||||||
{
|
{
|
||||||
applyExpectedType(
|
applyExpectedType(*ic.indexes.begin(), expr->index);
|
||||||
*ic.indexes.begin(),
|
|
||||||
expr->index
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -623,7 +623,6 @@ struct UsageFinder : public AstVisitor
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
localBindingsReferenced.emplace_back(dfg->getDef(local), local->local);
|
localBindingsReferenced.emplace_back(dfg->getDef(local), local->local);
|
||||||
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1016,7 +1016,8 @@ void Frontend::checkBuildQueueItem(BuildQueueItem& item)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModulePtr module = check(sourceModule, mode, requireCycles, environmentScope, /*forAutocomplete*/ false, item.recordJsonLog, std::move(typeCheckLimits));
|
ModulePtr module =
|
||||||
|
check(sourceModule, mode, requireCycles, environmentScope, /*forAutocomplete*/ false, item.recordJsonLog, std::move(typeCheckLimits));
|
||||||
|
|
||||||
double duration = getTimestamp() - timestamp;
|
double duration = getTimestamp() - timestamp;
|
||||||
|
|
||||||
|
@ -1368,6 +1369,11 @@ ModulePtr check(
|
||||||
|
|
||||||
struct InternalTypeFinder : TypeOnceVisitor
|
struct InternalTypeFinder : TypeOnceVisitor
|
||||||
{
|
{
|
||||||
|
InternalTypeFinder()
|
||||||
|
: TypeOnceVisitor("InternalTypeFinder")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool visit(TypeId, const ExternType&) override
|
bool visit(TypeId, const ExternType&) override
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -46,7 +46,7 @@ struct MutatingGeneralizer : TypeOnceVisitor
|
||||||
DenseHashMap<const void*, size_t> positiveTypes,
|
DenseHashMap<const void*, size_t> positiveTypes,
|
||||||
DenseHashMap<const void*, size_t> negativeTypes
|
DenseHashMap<const void*, size_t> negativeTypes
|
||||||
)
|
)
|
||||||
: TypeOnceVisitor(/* skipBoundTypes */ true)
|
: TypeOnceVisitor("MutatingGeneralizer", /* skipBoundTypes */ true)
|
||||||
, arena(arena)
|
, arena(arena)
|
||||||
, builtinTypes(builtinTypes)
|
, builtinTypes(builtinTypes)
|
||||||
, scope(scope)
|
, scope(scope)
|
||||||
|
@ -338,7 +338,7 @@ struct FreeTypeSearcher : TypeVisitor
|
||||||
NotNull<DenseHashSet<TypeId>> cachedTypes;
|
NotNull<DenseHashSet<TypeId>> cachedTypes;
|
||||||
|
|
||||||
explicit FreeTypeSearcher(NotNull<Scope> scope, NotNull<DenseHashSet<TypeId>> cachedTypes)
|
explicit FreeTypeSearcher(NotNull<Scope> scope, NotNull<DenseHashSet<TypeId>> cachedTypes)
|
||||||
: TypeVisitor(/*skipBoundTypes*/ true)
|
: TypeVisitor("FreeTypeSearcher", /*skipBoundTypes*/ true)
|
||||||
, scope(scope)
|
, scope(scope)
|
||||||
, cachedTypes(cachedTypes)
|
, cachedTypes(cachedTypes)
|
||||||
{
|
{
|
||||||
|
@ -649,7 +649,7 @@ struct TypeCacher : TypeOnceVisitor
|
||||||
DenseHashSet<TypePackId> uncacheablePacks{nullptr};
|
DenseHashSet<TypePackId> uncacheablePacks{nullptr};
|
||||||
|
|
||||||
explicit TypeCacher(NotNull<DenseHashSet<TypeId>> cachedTypes)
|
explicit TypeCacher(NotNull<DenseHashSet<TypeId>> cachedTypes)
|
||||||
: TypeOnceVisitor(/* skipBoundTypes */ false)
|
: TypeOnceVisitor("TypeCacher", /* skipBoundTypes */ false)
|
||||||
, cachedTypes(cachedTypes)
|
, cachedTypes(cachedTypes)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -1136,7 +1136,6 @@ struct TypeRemover
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void removeType(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtinTypes, TypeId haystack, TypeId needle)
|
void removeType(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtinTypes, TypeId haystack, TypeId needle)
|
||||||
|
@ -1145,7 +1144,7 @@ void removeType(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtinTypes, Ty
|
||||||
tr.process(haystack);
|
tr.process(haystack);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
GeneralizationResult<TypeId> generalizeType(
|
GeneralizationResult<TypeId> generalizeType(
|
||||||
NotNull<TypeArena> arena,
|
NotNull<TypeArena> arena,
|
||||||
|
@ -1410,7 +1409,8 @@ struct GenericCounter : TypeVisitor
|
||||||
Polarity polarity = Polarity::Positive;
|
Polarity polarity = Polarity::Positive;
|
||||||
|
|
||||||
explicit GenericCounter(NotNull<DenseHashSet<TypeId>> cachedTypes)
|
explicit GenericCounter(NotNull<DenseHashSet<TypeId>> cachedTypes)
|
||||||
: cachedTypes(cachedTypes)
|
: TypeVisitor("GenericCounter")
|
||||||
|
, cachedTypes(cachedTypes)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@ struct InferPolarity : TypeVisitor
|
||||||
Polarity polarity = Polarity::Positive;
|
Polarity polarity = Polarity::Positive;
|
||||||
|
|
||||||
explicit InferPolarity(NotNull<TypeArena> arena, NotNull<Scope> scope)
|
explicit InferPolarity(NotNull<TypeArena> arena, NotNull<Scope> scope)
|
||||||
: arena(arena)
|
: TypeVisitor("InferPolarity")
|
||||||
|
, arena(arena)
|
||||||
, scope(scope)
|
, scope(scope)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ LUAU_FASTFLAGVARIABLE(LuauNormalizationIntersectTablesPreservesExternTypes)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauNormalizationReorderFreeTypeIntersect)
|
LUAU_FASTFLAGVARIABLE(LuauNormalizationReorderFreeTypeIntersect)
|
||||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||||
LUAU_FASTFLAG(LuauUseWorkspacePropToChooseSolver)
|
LUAU_FASTFLAG(LuauUseWorkspacePropToChooseSolver)
|
||||||
|
LUAU_FASTFLAGVARIABLE(LuauNormalizationLimitTyvarUnionSize)
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
|
@ -1530,6 +1531,12 @@ NormalizationResult Normalizer::unionNormals(NormalizedType& here, const Normali
|
||||||
return NormalizationResult::True;
|
return NormalizationResult::True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FFlag::LuauNormalizationLimitTyvarUnionSize)
|
||||||
|
{
|
||||||
|
if (here.tyvars.size() * there.tyvars.size() >= size_t(FInt::LuauNormalizeUnionLimit))
|
||||||
|
return NormalizationResult::HitLimits;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto it = there.tyvars.begin(); it != there.tyvars.end(); it++)
|
for (auto it = there.tyvars.begin(); it != there.tyvars.end(); it++)
|
||||||
{
|
{
|
||||||
TypeId tyvar = it->first;
|
TypeId tyvar = it->first;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include "Luau/Unifier2.h"
|
#include "Luau/Unifier2.h"
|
||||||
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauArityMismatchOnUndersaturatedUnknownArguments)
|
LUAU_FASTFLAGVARIABLE(LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
|
@ -247,9 +247,7 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
TypeFunctionContext context{arena, builtinTypes, scope, simplifier, normalizer, typeFunctionRuntime, ice, limits};
|
TypeFunctionContext context{arena, builtinTypes, scope, simplifier, normalizer, typeFunctionRuntime, ice, limits};
|
||||||
FunctionGraphReductionResult result = reduceTypeFunctions(
|
FunctionGraphReductionResult result = reduceTypeFunctions(fnTy, callLoc, NotNull{&context}, /*force=*/true);
|
||||||
fnTy, callLoc, NotNull{&context}, /*force=*/true
|
|
||||||
);
|
|
||||||
if (!result.errors.empty())
|
if (!result.errors.empty())
|
||||||
return {OverloadIsNonviable, result.errors};
|
return {OverloadIsNonviable, result.errors};
|
||||||
|
|
||||||
|
@ -330,7 +328,7 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
||||||
return {Analysis::Ok, {}};
|
return {Analysis::Ok, {}};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
{
|
{
|
||||||
// If we have an arity mismatch with generic type pack parameters, then subPath matches Args :: Tail :: ...
|
// If we have an arity mismatch with generic type pack parameters, then subPath matches Args :: Tail :: ...
|
||||||
// and superPath matches Args :: ...
|
// and superPath matches Args :: ...
|
||||||
|
@ -405,15 +403,15 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
||||||
: argExprs->size() != 0 ? argExprs->back()->location
|
: argExprs->size() != 0 ? argExprs->back()->location
|
||||||
: fnExpr->location;
|
: fnExpr->location;
|
||||||
|
|
||||||
std::optional<TypeId> failedSubTy = FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
std::optional<TypeId> failedSubTy = FFlag::LuauReturnMappedGenericPacksFromSubtyping2
|
||||||
? traverseForType(fnTy, reason.subPath, builtinTypes, NotNull{&sr.mappedGenericPacks}, arena)
|
? traverseForType(fnTy, reason.subPath, builtinTypes, NotNull{&sr.mappedGenericPacks}, arena)
|
||||||
: traverseForType_DEPRECATED(fnTy, reason.subPath, builtinTypes);
|
: traverseForType_DEPRECATED(fnTy, reason.subPath, builtinTypes);
|
||||||
std::optional<TypeId> failedSuperTy =
|
std::optional<TypeId> failedSuperTy =
|
||||||
FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
FFlag::LuauReturnMappedGenericPacksFromSubtyping2
|
||||||
? traverseForType(prospectiveFunction, reason.superPath, builtinTypes, NotNull{&sr.mappedGenericPacks}, arena)
|
? traverseForType(prospectiveFunction, reason.superPath, builtinTypes, NotNull{&sr.mappedGenericPacks}, arena)
|
||||||
: traverseForType_DEPRECATED(prospectiveFunction, reason.superPath, builtinTypes);
|
: traverseForType_DEPRECATED(prospectiveFunction, reason.superPath, builtinTypes);
|
||||||
|
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
maybeEmplaceError(&errors, argLocation, &reason, failedSubTy, failedSuperTy);
|
maybeEmplaceError(&errors, argLocation, &reason, failedSubTy, failedSuperTy);
|
||||||
else if (failedSubTy && failedSuperTy)
|
else if (failedSubTy && failedSuperTy)
|
||||||
{
|
{
|
||||||
|
@ -443,7 +441,7 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (FFlag::LuauReturnMappedGenericPacksFromSubtyping && reason.superPath.components.size() > 1)
|
else if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2 && reason.superPath.components.size() > 1)
|
||||||
{
|
{
|
||||||
// traverseForIndex only has a value if path is of form [...PackSlice, Index]
|
// traverseForIndex only has a value if path is of form [...PackSlice, Index]
|
||||||
if (const auto index =
|
if (const auto index =
|
||||||
|
@ -466,11 +464,11 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<TypePackId> failedSubPack = FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
std::optional<TypePackId> failedSubPack = FFlag::LuauReturnMappedGenericPacksFromSubtyping2
|
||||||
? traverseForPack(fnTy, reason.subPath, builtinTypes, NotNull{&sr.mappedGenericPacks}, arena)
|
? traverseForPack(fnTy, reason.subPath, builtinTypes, NotNull{&sr.mappedGenericPacks}, arena)
|
||||||
: traverseForPack_DEPRECATED(fnTy, reason.subPath, builtinTypes);
|
: traverseForPack_DEPRECATED(fnTy, reason.subPath, builtinTypes);
|
||||||
std::optional<TypePackId> failedSuperPack =
|
std::optional<TypePackId> failedSuperPack =
|
||||||
FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
FFlag::LuauReturnMappedGenericPacksFromSubtyping2
|
||||||
? traverseForPack(prospectiveFunction, reason.superPath, builtinTypes, NotNull{&sr.mappedGenericPacks}, arena)
|
? traverseForPack(prospectiveFunction, reason.superPath, builtinTypes, NotNull{&sr.mappedGenericPacks}, arena)
|
||||||
: traverseForPack_DEPRECATED(prospectiveFunction, reason.superPath, builtinTypes);
|
: traverseForPack_DEPRECATED(prospectiveFunction, reason.superPath, builtinTypes);
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,8 @@ struct Quantifier final : TypeOnceVisitor
|
||||||
bool seenMutableType = false;
|
bool seenMutableType = false;
|
||||||
|
|
||||||
explicit Quantifier(TypeLevel level)
|
explicit Quantifier(TypeLevel level)
|
||||||
: level(level)
|
: TypeOnceVisitor("Quantifier")
|
||||||
|
, level(level)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauRelateTablesAreNeverDisjoint)
|
LUAU_FASTFLAGVARIABLE(LuauRelateTablesAreNeverDisjoint)
|
||||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauMissingSeenSetRelate)
|
LUAU_FASTFLAGVARIABLE(LuauMissingSeenSetRelate)
|
||||||
|
LUAU_FASTFLAGVARIABLE(LuauSimplifyAnyAndUnion)
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
|
@ -1426,7 +1427,7 @@ std::optional<TypeId> TypeSimplifier::basicIntersect(TypeId left, TypeId right)
|
||||||
|
|
||||||
TypeId TypeSimplifier::intersect(TypeId left, TypeId right)
|
TypeId TypeSimplifier::intersect(TypeId left, TypeId right)
|
||||||
{
|
{
|
||||||
RecursionLimiter rl(&recursionDepth, 15);
|
RecursionLimiter rl("TypeSimplifier::intersect", &recursionDepth, 15);
|
||||||
|
|
||||||
left = simplify(left);
|
left = simplify(left);
|
||||||
right = simplify(right);
|
right = simplify(right);
|
||||||
|
@ -1442,6 +1443,10 @@ TypeId TypeSimplifier::intersect(TypeId left, TypeId right)
|
||||||
return right;
|
return right;
|
||||||
if (get<UnknownType>(right) && !get<ErrorType>(left))
|
if (get<UnknownType>(right) && !get<ErrorType>(left))
|
||||||
return left;
|
return left;
|
||||||
|
if (FFlag::LuauSimplifyAnyAndUnion && get<AnyType>(left) && get<UnionType>(right))
|
||||||
|
return union_(builtinTypes->errorType, right);
|
||||||
|
if (FFlag::LuauSimplifyAnyAndUnion && get<UnionType>(left) && get<AnyType>(right))
|
||||||
|
return union_(builtinTypes->errorType, left);
|
||||||
if (get<AnyType>(left))
|
if (get<AnyType>(left))
|
||||||
return arena->addType(UnionType{{right, builtinTypes->errorType}});
|
return arena->addType(UnionType{{right, builtinTypes->errorType}});
|
||||||
if (get<AnyType>(right))
|
if (get<AnyType>(right))
|
||||||
|
@ -1514,7 +1519,7 @@ TypeId TypeSimplifier::intersect(TypeId left, TypeId right)
|
||||||
|
|
||||||
TypeId TypeSimplifier::union_(TypeId left, TypeId right)
|
TypeId TypeSimplifier::union_(TypeId left, TypeId right)
|
||||||
{
|
{
|
||||||
RecursionLimiter rl(&recursionDepth, 15);
|
RecursionLimiter rl("TypeSimplifier::union", &recursionDepth, 15);
|
||||||
|
|
||||||
left = simplify(left);
|
left = simplify(left);
|
||||||
right = simplify(right);
|
right = simplify(right);
|
||||||
|
@ -1602,7 +1607,7 @@ TypeId TypeSimplifier::simplify(TypeId ty)
|
||||||
|
|
||||||
TypeId TypeSimplifier::simplify(TypeId ty, DenseHashSet<TypeId>& seen)
|
TypeId TypeSimplifier::simplify(TypeId ty, DenseHashSet<TypeId>& seen)
|
||||||
{
|
{
|
||||||
RecursionLimiter limiter(&recursionDepth, 60);
|
RecursionLimiter limiter("TypeSimplifier::simplify", &recursionDepth, 60);
|
||||||
|
|
||||||
ty = follow(ty);
|
ty = follow(ty);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "Luau/Subtyping.h"
|
#include "Luau/Subtyping.h"
|
||||||
|
|
||||||
|
#include "iostream"
|
||||||
#include "Luau/Common.h"
|
#include "Luau/Common.h"
|
||||||
#include "Luau/Error.h"
|
#include "Luau/Error.h"
|
||||||
#include "Luau/Normalize.h"
|
#include "Luau/Normalize.h"
|
||||||
|
@ -21,7 +22,7 @@ LUAU_FASTINTVARIABLE(LuauSubtypingReasoningLimit, 100)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauSubtypingCheckFunctionGenericCounts)
|
LUAU_FASTFLAGVARIABLE(LuauSubtypingCheckFunctionGenericCounts)
|
||||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauReturnMappedGenericPacksFromSubtyping)
|
LUAU_FASTFLAGVARIABLE(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
|
@ -78,7 +79,7 @@ static void assertReasoningValid_DEPRECATED(TID subTy, TID superTy, const Subtyp
|
||||||
template<typename TID>
|
template<typename TID>
|
||||||
static void assertReasoningValid(TID subTy, TID superTy, const SubtypingResult& result, NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena)
|
static void assertReasoningValid(TID subTy, TID superTy, const SubtypingResult& result, NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena)
|
||||||
{
|
{
|
||||||
LUAU_ASSERT(FFlag::LuauReturnMappedGenericPacksFromSubtyping);
|
LUAU_ASSERT(FFlag::LuauReturnMappedGenericPacksFromSubtyping2);
|
||||||
|
|
||||||
if (!FFlag::DebugLuauSubtypingCheckPathValidity)
|
if (!FFlag::DebugLuauSubtypingCheckPathValidity)
|
||||||
return;
|
return;
|
||||||
|
@ -513,7 +514,7 @@ SubtypingResult Subtyping::isSubtype(TypeId subTy, TypeId superTy, NotNull<Scope
|
||||||
* cacheable.
|
* cacheable.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
{
|
{
|
||||||
result.mappedGenericPacks = std::move(env.mappedGenericPacks);
|
result.mappedGenericPacks = std::move(env.mappedGenericPacks);
|
||||||
}
|
}
|
||||||
|
@ -530,7 +531,7 @@ SubtypingResult Subtyping::isSubtype(TypePackId subTp, TypePackId superTp, NotNu
|
||||||
|
|
||||||
SubtypingResult result = isCovariantWith(env, subTp, superTp, scope);
|
SubtypingResult result = isCovariantWith(env, subTp, superTp, scope);
|
||||||
|
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
{
|
{
|
||||||
if (!env.mappedGenericPacks.empty())
|
if (!env.mappedGenericPacks.empty())
|
||||||
result.mappedGenericPacks = std::move(env.mappedGenericPacks);
|
result.mappedGenericPacks = std::move(env.mappedGenericPacks);
|
||||||
|
@ -543,7 +544,7 @@ SubtypingResult Subtyping::cache(SubtypingEnvironment& env, SubtypingResult resu
|
||||||
{
|
{
|
||||||
const std::pair<TypeId, TypeId> p{subTy, superTy};
|
const std::pair<TypeId, TypeId> p{subTy, superTy};
|
||||||
|
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping && !env.mappedGenericPacks.empty())
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2 && !env.mappedGenericPacks.empty())
|
||||||
result.mappedGenericPacks = env.mappedGenericPacks;
|
result.mappedGenericPacks = env.mappedGenericPacks;
|
||||||
|
|
||||||
if (result.isCacheable)
|
if (result.isCacheable)
|
||||||
|
@ -572,6 +573,30 @@ struct SeenSetPopper
|
||||||
seenTypes->erase(pair);
|
seenTypes->erase(pair);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SeenTypePackSetPopper
|
||||||
|
{
|
||||||
|
Subtyping::SeenTypePackSet* seenTypes;
|
||||||
|
std::pair<TypePackId, TypePackId> pair;
|
||||||
|
|
||||||
|
SeenTypePackSetPopper(Subtyping::SeenTypePackSet* seenTypes, std::pair<TypePackId, TypePackId> pair)
|
||||||
|
: seenTypes(seenTypes)
|
||||||
|
, pair(std::move(pair))
|
||||||
|
{
|
||||||
|
LUAU_ASSERT(FFlag::LuauReturnMappedGenericPacksFromSubtyping2);
|
||||||
|
}
|
||||||
|
|
||||||
|
SeenTypePackSetPopper(const SeenTypePackSetPopper&) = delete;
|
||||||
|
SeenTypePackSetPopper& operator=(const SeenTypePackSetPopper&) = delete;
|
||||||
|
SeenTypePackSetPopper(SeenTypePackSetPopper&&) = delete;
|
||||||
|
SeenTypePackSetPopper& operator=(SeenTypePackSetPopper&&) = delete;
|
||||||
|
|
||||||
|
~SeenTypePackSetPopper()
|
||||||
|
{
|
||||||
|
LUAU_ASSERT(FFlag::LuauReturnMappedGenericPacksFromSubtyping2);
|
||||||
|
seenTypes->erase(pair);
|
||||||
|
}
|
||||||
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId subTy, TypeId superTy, NotNull<Scope> scope)
|
SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId subTy, TypeId superTy, NotNull<Scope> scope)
|
||||||
|
@ -598,7 +623,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
||||||
const SubtypingResult* cachedResult = resultCache.find({subTy, superTy});
|
const SubtypingResult* cachedResult = resultCache.find({subTy, superTy});
|
||||||
if (cachedResult)
|
if (cachedResult)
|
||||||
{
|
{
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
{
|
{
|
||||||
for (const auto& [genericTp, boundTp] : cachedResult->mappedGenericPacks)
|
for (const auto& [genericTp, boundTp] : cachedResult->mappedGenericPacks)
|
||||||
env.mappedGenericPacks.try_insert(genericTp, boundTp);
|
env.mappedGenericPacks.try_insert(genericTp, boundTp);
|
||||||
|
@ -610,7 +635,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
||||||
cachedResult = env.tryFindSubtypingResult({subTy, superTy});
|
cachedResult = env.tryFindSubtypingResult({subTy, superTy});
|
||||||
if (cachedResult)
|
if (cachedResult)
|
||||||
{
|
{
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
{
|
{
|
||||||
for (const auto& [genericTp, boundTp] : cachedResult->mappedGenericPacks)
|
for (const auto& [genericTp, boundTp] : cachedResult->mappedGenericPacks)
|
||||||
env.mappedGenericPacks.try_insert(genericTp, boundTp);
|
env.mappedGenericPacks.try_insert(genericTp, boundTp);
|
||||||
|
@ -857,7 +882,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
||||||
else if (auto p = get2<SingletonType, TableType>(subTy, superTy))
|
else if (auto p = get2<SingletonType, TableType>(subTy, superTy))
|
||||||
result = isCovariantWith(env, p, scope);
|
result = isCovariantWith(env, p, scope);
|
||||||
|
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
assertReasoningValid(subTy, superTy, result, builtinTypes, arena);
|
assertReasoningValid(subTy, superTy, result, builtinTypes, arena);
|
||||||
else
|
else
|
||||||
assertReasoningValid_DEPRECATED(subTy, superTy, result, builtinTypes);
|
assertReasoningValid_DEPRECATED(subTy, superTy, result, builtinTypes);
|
||||||
|
@ -870,6 +895,20 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId
|
||||||
subTp = follow(subTp);
|
subTp = follow(subTp);
|
||||||
superTp = follow(superTp);
|
superTp = follow(superTp);
|
||||||
|
|
||||||
|
std::optional<SeenTypePackSetPopper> popper = std::nullopt;
|
||||||
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
|
{
|
||||||
|
std::pair<TypePackId, TypePackId> typePair = {subTp, superTp};
|
||||||
|
if (!seenPacks.insert(typePair))
|
||||||
|
{
|
||||||
|
SubtypingResult res;
|
||||||
|
res.isSubtype = true;
|
||||||
|
res.isCacheable = false;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
popper.emplace(&seenPacks, std::move(typePair));
|
||||||
|
}
|
||||||
|
|
||||||
auto [subHead, subTail] = flatten(subTp);
|
auto [subHead, subTail] = flatten(subTp);
|
||||||
auto [superHead, superTail] = flatten(superTp);
|
auto [superHead, superTail] = flatten(superTp);
|
||||||
|
|
||||||
|
@ -908,15 +947,32 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId
|
||||||
//
|
//
|
||||||
// <X>(X) -> () <: (T) -> ()
|
// <X>(X) -> () <: (T) -> ()
|
||||||
|
|
||||||
|
TypePackId superTailPack;
|
||||||
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
|
{
|
||||||
|
if (headSize == 0)
|
||||||
|
superTailPack = superTp;
|
||||||
|
else if (headSize == superHead.size())
|
||||||
|
superTailPack = superTail ? *superTail : builtinTypes->emptyTypePack;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto superHeadIter = begin(superHead);
|
||||||
|
for (size_t i = 0; i < headSize; ++i)
|
||||||
|
++superHeadIter;
|
||||||
|
std::vector<TypeId> headSlice(std::move(superHeadIter), end(superHead));
|
||||||
|
superTailPack = arena->addTypePack(std::move(headSlice), superTail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Possible optimization: If headSize == 0 then we can just use subTp as-is.
|
// Possible optimization: If headSize == 0 then we can just use subTp as-is.
|
||||||
std::vector<TypeId> headSlice = FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
std::vector<TypeId> headSlice = std::vector<TypeId>(begin(superHead), begin(superHead) + headSize);
|
||||||
? std::vector<TypeId>(begin(superHead) + headSize, end(superHead))
|
superTailPack = arena->addTypePack(std::move(headSlice), superTail);
|
||||||
: std::vector<TypeId>(begin(superHead), begin(superHead) + headSize);
|
}
|
||||||
TypePackId superTailPack = arena->addTypePack(std::move(headSlice), superTail);
|
|
||||||
|
|
||||||
if (TypePackId* other = env.getMappedPackBounds(*subTail))
|
if (TypePackId* other = env.getMappedPackBounds(*subTail))
|
||||||
{
|
{
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
{
|
{
|
||||||
const TypePack* tp = get<TypePack>(*other);
|
const TypePack* tp = get<TypePack>(*other);
|
||||||
if (const VariadicTypePack* vtp = tp ? get<VariadicTypePack>(tp->tail) : nullptr; vtp && vtp->hidden)
|
if (const VariadicTypePack* vtp = tp ? get<VariadicTypePack>(tp->tail) : nullptr; vtp && vtp->hidden)
|
||||||
|
@ -982,15 +1038,32 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId
|
||||||
//
|
//
|
||||||
// <X...>(X...) -> () <: (T) -> ()
|
// <X...>(X...) -> () <: (T) -> ()
|
||||||
|
|
||||||
|
TypePackId subTailPack;
|
||||||
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
|
{
|
||||||
|
if (headSize == 0)
|
||||||
|
subTailPack = subTp;
|
||||||
|
else if (headSize == subHead.size())
|
||||||
|
subTailPack = subTail ? *subTail : builtinTypes->emptyTypePack;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto subHeadIter = begin(subHead);
|
||||||
|
for (size_t i = 0; i < headSize; ++i)
|
||||||
|
++subHeadIter;
|
||||||
|
std::vector<TypeId> headSlice(std::move(subHeadIter), end(subHead));
|
||||||
|
subTailPack = arena->addTypePack(std::move(headSlice), subTail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// Possible optimization: If headSize == 0 then we can just use subTp as-is.
|
// Possible optimization: If headSize == 0 then we can just use subTp as-is.
|
||||||
std::vector<TypeId> headSlice = FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
std::vector<TypeId> headSlice = std::vector<TypeId>(begin(subHead), begin(subHead) + headSize);
|
||||||
? std::vector<TypeId>(begin(subHead) + headSize, end(subHead))
|
subTailPack = arena->addTypePack(std::move(headSlice), subTail);
|
||||||
: std::vector<TypeId>(begin(subHead), begin(subHead) + headSize);
|
}
|
||||||
TypePackId subTailPack = arena->addTypePack(std::move(headSlice), subTail);
|
|
||||||
|
|
||||||
if (TypePackId* other = env.getMappedPackBounds(*superTail))
|
if (TypePackId* other = env.getMappedPackBounds(*superTail))
|
||||||
{
|
{
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
{
|
{
|
||||||
const TypePack* tp = get<TypePack>(*other);
|
const TypePack* tp = get<TypePack>(*other);
|
||||||
if (const VariadicTypePack* vtp = tp ? get<VariadicTypePack>(tp->tail) : nullptr; vtp && vtp->hidden)
|
if (const VariadicTypePack* vtp = tp ? get<VariadicTypePack>(tp->tail) : nullptr; vtp && vtp->hidden)
|
||||||
|
@ -1142,7 +1215,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId
|
||||||
|
|
||||||
SubtypingResult result = SubtypingResult::all(results);
|
SubtypingResult result = SubtypingResult::all(results);
|
||||||
|
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
assertReasoningValid(subTp, superTp, result, builtinTypes, arena);
|
assertReasoningValid(subTp, superTp, result, builtinTypes, arena);
|
||||||
else
|
else
|
||||||
assertReasoningValid_DEPRECATED(subTp, superTp, result, builtinTypes);
|
assertReasoningValid_DEPRECATED(subTp, superTp, result, builtinTypes);
|
||||||
|
@ -1177,7 +1250,7 @@ SubtypingResult Subtyping::isContravariantWith(SubtypingEnvironment& env, SubTy&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
assertReasoningValid(subTy, superTy, result, builtinTypes, arena);
|
assertReasoningValid(subTy, superTy, result, builtinTypes, arena);
|
||||||
else
|
else
|
||||||
assertReasoningValid_DEPRECATED(subTy, superTy, result, builtinTypes);
|
assertReasoningValid_DEPRECATED(subTy, superTy, result, builtinTypes);
|
||||||
|
@ -1198,7 +1271,7 @@ SubtypingResult Subtyping::isInvariantWith(SubtypingEnvironment& env, SubTy&& su
|
||||||
reasoning.variance = SubtypingVariance::Invariant;
|
reasoning.variance = SubtypingVariance::Invariant;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
assertReasoningValid(subTy, superTy, result, builtinTypes, arena);
|
assertReasoningValid(subTy, superTy, result, builtinTypes, arena);
|
||||||
else
|
else
|
||||||
assertReasoningValid_DEPRECATED(subTy, superTy, result, builtinTypes);
|
assertReasoningValid_DEPRECATED(subTy, superTy, result, builtinTypes);
|
||||||
|
@ -1862,7 +1935,9 @@ SubtypingResult Subtyping::isCovariantWith(
|
||||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||||
res.andAlso(isInvariantWith(env, *subProp.readTy, *superProp.readTy, scope).withBothComponent(TypePath::Property::read(name)));
|
res.andAlso(isInvariantWith(env, *subProp.readTy, *superProp.readTy, scope).withBothComponent(TypePath::Property::read(name)));
|
||||||
else
|
else
|
||||||
res.andAlso(isInvariantWith(env, subProp.type_DEPRECATED(), superProp.type_DEPRECATED(), scope).withBothComponent(TypePath::Property::read(name)));
|
res.andAlso(
|
||||||
|
isInvariantWith(env, subProp.type_DEPRECATED(), superProp.type_DEPRECATED(), scope).withBothComponent(TypePath::Property::read(name))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2131,6 +2206,13 @@ bool Subtyping::bindGeneric(SubtypingEnvironment& env, TypePackId subTp, TypePac
|
||||||
if (TypePackId* m = env.getMappedPackBounds(subTp))
|
if (TypePackId* m = env.getMappedPackBounds(subTp))
|
||||||
return *m == superTp;
|
return *m == superTp;
|
||||||
|
|
||||||
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
|
{
|
||||||
|
// We shouldn't bind generic type packs to themselves
|
||||||
|
if (subTp == superTp)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
env.mappedGenericPacks[subTp] = superTp;
|
env.mappedGenericPacks[subTp] = superTp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -52,7 +52,11 @@ namespace
|
||||||
|
|
||||||
struct FindCyclicTypes final : TypeVisitor
|
struct FindCyclicTypes final : TypeVisitor
|
||||||
{
|
{
|
||||||
FindCyclicTypes() = default;
|
FindCyclicTypes()
|
||||||
|
: TypeVisitor("FindCyclicTypes")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
FindCyclicTypes(const FindCyclicTypes&) = delete;
|
FindCyclicTypes(const FindCyclicTypes&) = delete;
|
||||||
FindCyclicTypes& operator=(const FindCyclicTypes&) = delete;
|
FindCyclicTypes& operator=(const FindCyclicTypes&) = delete;
|
||||||
|
|
||||||
|
@ -827,7 +831,9 @@ struct TypeStringifier
|
||||||
|
|
||||||
std::string openbrace = "@@@";
|
std::string openbrace = "@@@";
|
||||||
std::string closedbrace = "@@@?!";
|
std::string closedbrace = "@@@?!";
|
||||||
switch (state.opts.hideTableKind ? ((FFlag::LuauSolverV2 || FFlag::LuauSolverAgnosticStringification) ? TableState::Sealed : TableState::Unsealed) : ttv.state)
|
switch (state.opts.hideTableKind
|
||||||
|
? ((FFlag::LuauSolverV2 || FFlag::LuauSolverAgnosticStringification) ? TableState::Sealed : TableState::Unsealed)
|
||||||
|
: ttv.state)
|
||||||
{
|
{
|
||||||
case TableState::Sealed:
|
case TableState::Sealed:
|
||||||
if (FFlag::LuauSolverV2 || FFlag::LuauSolverAgnosticStringification)
|
if (FFlag::LuauSolverV2 || FFlag::LuauSolverAgnosticStringification)
|
||||||
|
@ -1899,6 +1905,39 @@ std::string dump(const std::optional<TypePackId>& ty)
|
||||||
return "nullopt";
|
return "nullopt";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string dump(const std::vector<TypeId>& types)
|
||||||
|
{
|
||||||
|
return toStringVector(types, dumpOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string dump(DenseHashMap<TypeId, TypeId>& types)
|
||||||
|
{
|
||||||
|
std::string s = "{";
|
||||||
|
ToStringOptions& opts = dumpOptions();
|
||||||
|
for (const auto& [key, value] : types)
|
||||||
|
{
|
||||||
|
if (s.length() == 1)
|
||||||
|
s += ", ";
|
||||||
|
s += toString(key, opts) + " : " + toString(value, opts);
|
||||||
|
}
|
||||||
|
s += "}";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string dump(DenseHashMap<TypePackId, TypePackId>& types)
|
||||||
|
{
|
||||||
|
std::string s = "{";
|
||||||
|
ToStringOptions& opts = dumpOptions();
|
||||||
|
for (const auto& [key, value] : types)
|
||||||
|
{
|
||||||
|
if (s.length() == 1)
|
||||||
|
s += ", ";
|
||||||
|
s += toString(key, opts) + " : " + toString(value, opts);
|
||||||
|
}
|
||||||
|
s += "}";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
std::string dump(const ScopePtr& scope, const char* name)
|
std::string dump(const ScopePtr& scope, const char* name)
|
||||||
{
|
{
|
||||||
auto binding = scope->linearSearchForBinding(name);
|
auto binding = scope->linearSearchForBinding(name);
|
||||||
|
|
|
@ -446,7 +446,7 @@ bool maybeSingleton(TypeId ty)
|
||||||
|
|
||||||
bool hasLength(TypeId ty, DenseHashSet<TypeId>& seen, int* recursionCount)
|
bool hasLength(TypeId ty, DenseHashSet<TypeId>& seen, int* recursionCount)
|
||||||
{
|
{
|
||||||
RecursionLimiter _rl(recursionCount, FInt::LuauTypeInferRecursionLimit);
|
RecursionLimiter _rl("Type::hasLength", recursionCount, FInt::LuauTypeInferRecursionLimit);
|
||||||
|
|
||||||
ty = follow(ty);
|
ty = follow(ty);
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||||
LUAU_FASTFLAG(LuauSubtypingCheckFunctionGenericCounts)
|
LUAU_FASTFLAG(LuauSubtypingCheckFunctionGenericCounts)
|
||||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeCheckFunctionCalls)
|
LUAU_FASTFLAG(LuauTableLiteralSubtypeCheckFunctionCalls)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauSuppressErrorsForMultipleNonviableOverloads)
|
LUAU_FASTFLAGVARIABLE(LuauSuppressErrorsForMultipleNonviableOverloads)
|
||||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
LUAU_FASTFLAG(LuauInferActualIfElseExprType)
|
LUAU_FASTFLAG(LuauInferActualIfElseExprType)
|
||||||
LUAU_FASTFLAG(LuauNewNonStrictSuppressSoloConstraintSolvingIncomplete)
|
LUAU_FASTFLAG(LuauNewNonStrictSuppressSoloConstraintSolvingIncomplete)
|
||||||
|
|
||||||
|
@ -161,6 +161,11 @@ struct TypeFunctionFinder : TypeOnceVisitor
|
||||||
DenseHashSet<TypeId> mentionedFunctions{nullptr};
|
DenseHashSet<TypeId> mentionedFunctions{nullptr};
|
||||||
DenseHashSet<TypePackId> mentionedFunctionPacks{nullptr};
|
DenseHashSet<TypePackId> mentionedFunctionPacks{nullptr};
|
||||||
|
|
||||||
|
TypeFunctionFinder()
|
||||||
|
: TypeOnceVisitor("TypeFunctionFinder")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool visit(TypeId ty, const TypeFunctionInstanceType&) override
|
bool visit(TypeId ty, const TypeFunctionInstanceType&) override
|
||||||
{
|
{
|
||||||
mentionedFunctions.insert(ty);
|
mentionedFunctions.insert(ty);
|
||||||
|
@ -182,6 +187,7 @@ struct InternalTypeFunctionFinder : TypeOnceVisitor
|
||||||
DenseHashSet<TypePackId> mentionedFunctionPacks{nullptr};
|
DenseHashSet<TypePackId> mentionedFunctionPacks{nullptr};
|
||||||
|
|
||||||
explicit InternalTypeFunctionFinder(std::vector<TypeId>& declStack)
|
explicit InternalTypeFunctionFinder(std::vector<TypeId>& declStack)
|
||||||
|
: TypeOnceVisitor("InternalTypeFunctionFinder")
|
||||||
{
|
{
|
||||||
TypeFunctionFinder f;
|
TypeFunctionFinder f;
|
||||||
for (TypeId fn : declStack)
|
for (TypeId fn : declStack)
|
||||||
|
@ -2052,7 +2058,8 @@ void TypeChecker2::visit(AstExprFunction* fn)
|
||||||
TypeFunctionReductionGuessResult result = guesser.guessTypeFunctionReductionForFunctionExpr(*fn, inferredFtv, retTy);
|
TypeFunctionReductionGuessResult result = guesser.guessTypeFunctionReductionForFunctionExpr(*fn, inferredFtv, retTy);
|
||||||
if (result.shouldRecommendAnnotation && !get<UnknownType>(result.guessedReturnType))
|
if (result.shouldRecommendAnnotation && !get<UnknownType>(result.guessedReturnType))
|
||||||
reportError(
|
reportError(
|
||||||
ExplicitFunctionAnnotationRecommended{std::move(result.guessedFunctionAnnotations), result.guessedReturnType}, fn->location
|
ExplicitFunctionAnnotationRecommended{std::move(result.guessedFunctionAnnotations), result.guessedReturnType},
|
||||||
|
fn->location
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2207,7 +2214,9 @@ TypeId TypeChecker2::visit(AstExprBinary* expr, AstNode* overrideKey)
|
||||||
auto name = getIdentifierOfBaseVar(expr->left);
|
auto name = getIdentifierOfBaseVar(expr->left);
|
||||||
reportError(
|
reportError(
|
||||||
CannotInferBinaryOperation{
|
CannotInferBinaryOperation{
|
||||||
expr->op, std::move(name), isComparison ? CannotInferBinaryOperation::OpKind::Comparison : CannotInferBinaryOperation::OpKind::Operation
|
expr->op,
|
||||||
|
std::move(name),
|
||||||
|
isComparison ? CannotInferBinaryOperation::OpKind::Comparison : CannotInferBinaryOperation::OpKind::Operation
|
||||||
},
|
},
|
||||||
expr->location
|
expr->location
|
||||||
);
|
);
|
||||||
|
@ -2920,11 +2929,11 @@ Reasonings TypeChecker2::explainReasonings_(TID subTy, TID superTy, Location loc
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::optional<TypeOrPack> optSubLeaf =
|
std::optional<TypeOrPack> optSubLeaf =
|
||||||
FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
FFlag::LuauReturnMappedGenericPacksFromSubtyping2
|
||||||
? traverse(subTy, reasoning.subPath, builtinTypes, NotNull{&r.mappedGenericPacks}, subtyping->arena)
|
? traverse(subTy, reasoning.subPath, builtinTypes, NotNull{&r.mappedGenericPacks}, subtyping->arena)
|
||||||
: traverse_DEPRECATED(subTy, reasoning.subPath, builtinTypes);
|
: traverse_DEPRECATED(subTy, reasoning.subPath, builtinTypes);
|
||||||
std::optional<TypeOrPack> optSuperLeaf =
|
std::optional<TypeOrPack> optSuperLeaf =
|
||||||
FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
FFlag::LuauReturnMappedGenericPacksFromSubtyping2
|
||||||
? traverse(superTy, reasoning.superPath, builtinTypes, NotNull{&r.mappedGenericPacks}, subtyping->arena)
|
? traverse(superTy, reasoning.superPath, builtinTypes, NotNull{&r.mappedGenericPacks}, subtyping->arena)
|
||||||
: traverse_DEPRECATED(superTy, reasoning.superPath, builtinTypes);
|
: traverse_DEPRECATED(superTy, reasoning.superPath, builtinTypes);
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,12 @@ struct InstanceCollector : TypeOnceVisitor
|
||||||
std::vector<const void*> typeFunctionInstanceStack;
|
std::vector<const void*> typeFunctionInstanceStack;
|
||||||
std::vector<TypeId> cyclicInstance;
|
std::vector<TypeId> cyclicInstance;
|
||||||
|
|
||||||
|
|
||||||
|
InstanceCollector()
|
||||||
|
: TypeOnceVisitor("InstanceCollector")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool visit(TypeId ty, const TypeFunctionInstanceType& tfit) override
|
bool visit(TypeId ty, const TypeFunctionInstanceType& tfit) override
|
||||||
{
|
{
|
||||||
// TypeVisitor performs a depth-first traversal in the absence of
|
// TypeVisitor performs a depth-first traversal in the absence of
|
||||||
|
@ -146,6 +152,11 @@ struct UnscopedGenericFinder : TypeOnceVisitor
|
||||||
std::vector<TypePackId> scopeGenTps;
|
std::vector<TypePackId> scopeGenTps;
|
||||||
bool foundUnscoped = false;
|
bool foundUnscoped = false;
|
||||||
|
|
||||||
|
UnscopedGenericFinder()
|
||||||
|
: TypeOnceVisitor("UnscopedGenericFinder")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool visit(TypeId ty) override
|
bool visit(TypeId ty) override
|
||||||
{
|
{
|
||||||
// Once we have found an unscoped generic, we will stop the traversal
|
// Once we have found an unscoped generic, we will stop the traversal
|
||||||
|
@ -660,8 +671,7 @@ struct TypeFunctionReducer
|
||||||
if (tryGuessing(subject))
|
if (tryGuessing(subject))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TypeFunctionReductionResult<TypePackId> result =
|
TypeFunctionReductionResult<TypePackId> result = tfit->function->reducer(subject, tfit->typeArguments, tfit->packArguments, ctx);
|
||||||
tfit->function->reducer(subject, tfit->typeArguments, tfit->packArguments, ctx);
|
|
||||||
handleTypeFunctionReduction(subject, std::move(result));
|
handleTypeFunctionReduction(subject, std::move(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,11 @@ struct InstanceCollector2 : TypeOnceVisitor
|
||||||
DenseHashSet<TypeId> cyclicInstance{nullptr};
|
DenseHashSet<TypeId> cyclicInstance{nullptr};
|
||||||
DenseHashSet<TypeId> instanceArguments{nullptr};
|
DenseHashSet<TypeId> instanceArguments{nullptr};
|
||||||
|
|
||||||
|
InstanceCollector2()
|
||||||
|
: TypeOnceVisitor("InstanceCollector2")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool visit(TypeId ty, const TypeFunctionInstanceType& it) override
|
bool visit(TypeId ty, const TypeFunctionInstanceType& it) override
|
||||||
{
|
{
|
||||||
// TypeOnceVisitor performs a depth-first traversal in the absence of
|
// TypeOnceVisitor performs a depth-first traversal in the absence of
|
||||||
|
|
|
@ -157,4 +157,4 @@ std::vector<TypeId> TypeIds::take()
|
||||||
return std::move(order);
|
return std::move(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Luau
|
||||||
|
|
|
@ -442,7 +442,7 @@ struct InplaceDemoter : TypeOnceVisitor
|
||||||
TypeArena* arena;
|
TypeArena* arena;
|
||||||
|
|
||||||
InplaceDemoter(TypeLevel level, TypeArena* arena)
|
InplaceDemoter(TypeLevel level, TypeArena* arena)
|
||||||
: TypeOnceVisitor(/* skipBoundTypes= */ true)
|
: TypeOnceVisitor("InplaceDemoter", /* skipBoundTypes= */ true)
|
||||||
, newLevel(level)
|
, newLevel(level)
|
||||||
, arena(arena)
|
, arena(arena)
|
||||||
{
|
{
|
||||||
|
@ -2150,7 +2150,7 @@ std::optional<TypeId> TypeChecker::getIndexTypeFromTypeImpl(
|
||||||
|
|
||||||
for (TypeId t : utv)
|
for (TypeId t : utv)
|
||||||
{
|
{
|
||||||
RecursionLimiter _rl(&recursionCount, FInt::LuauTypeInferRecursionLimit);
|
RecursionLimiter _rl("TypeInfer::UnionType", &recursionCount, FInt::LuauTypeInferRecursionLimit);
|
||||||
|
|
||||||
// Not needed when we normalize types.
|
// Not needed when we normalize types.
|
||||||
if (get<AnyType>(follow(t)))
|
if (get<AnyType>(follow(t)))
|
||||||
|
@ -2189,7 +2189,7 @@ std::optional<TypeId> TypeChecker::getIndexTypeFromTypeImpl(
|
||||||
|
|
||||||
for (TypeId t : itv->parts)
|
for (TypeId t : itv->parts)
|
||||||
{
|
{
|
||||||
RecursionLimiter _rl(&recursionCount, FInt::LuauTypeInferRecursionLimit);
|
RecursionLimiter _rl("TypeInfer::IntersectionType", &recursionCount, FInt::LuauTypeInferRecursionLimit);
|
||||||
|
|
||||||
if (std::optional<TypeId> ty = getIndexTypeFromType(scope, t, name, location, /* addErrors= */ false))
|
if (std::optional<TypeId> ty = getIndexTypeFromType(scope, t, name, location, /* addErrors= */ false))
|
||||||
parts.push_back(*ty);
|
parts.push_back(*ty);
|
||||||
|
@ -4129,7 +4129,9 @@ void TypeChecker::checkArgumentList(
|
||||||
auto [minParams, optMaxParams] = getParameterExtents(&state.log, paramPack);
|
auto [minParams, optMaxParams] = getParameterExtents(&state.log, paramPack);
|
||||||
state.reportError(TypeError{
|
state.reportError(TypeError{
|
||||||
location,
|
location,
|
||||||
CountMismatch{minParams, optMaxParams, std::distance(begin(argPack), end(argPack)), CountMismatch::Context::Arg, false, std::move(namePath)}
|
CountMismatch{
|
||||||
|
minParams, optMaxParams, std::distance(begin(argPack), end(argPack)), CountMismatch::Context::Arg, false, std::move(namePath)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4248,7 +4250,8 @@ void TypeChecker::checkArgumentList(
|
||||||
namePath = *path;
|
namePath = *path;
|
||||||
|
|
||||||
state.reportError(TypeError{
|
state.reportError(TypeError{
|
||||||
funName.location, CountMismatch{minParams, optMaxParams, paramIndex, CountMismatch::Context::Arg, isVariadic, std::move(namePath)}
|
funName.location,
|
||||||
|
CountMismatch{minParams, optMaxParams, paramIndex, CountMismatch::Context::Arg, isVariadic, std::move(namePath)}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include "Luau/Error.h"
|
#include "Luau/Error.h"
|
||||||
#include "Luau/TxnLog.h"
|
#include "Luau/TxnLog.h"
|
||||||
|
|
||||||
#include <stdexcept>
|
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
|
@ -455,10 +455,13 @@ std::pair<std::vector<TypeId>, std::optional<TypePackId>> flatten(TypePackId tp,
|
||||||
|
|
||||||
std::pair<std::vector<TypeId>, std::optional<TypePackId>> flatten(TypePackId tp, const DenseHashMap<TypePackId, TypePackId>& mappedGenericPacks)
|
std::pair<std::vector<TypeId>, std::optional<TypePackId>> flatten(TypePackId tp, const DenseHashMap<TypePackId, TypePackId>& mappedGenericPacks)
|
||||||
{
|
{
|
||||||
|
LUAU_ASSERT(FFlag::LuauReturnMappedGenericPacksFromSubtyping2);
|
||||||
|
|
||||||
tp = mappedGenericPacks.contains(tp) ? *mappedGenericPacks.find(tp) : tp;
|
tp = mappedGenericPacks.contains(tp) ? *mappedGenericPacks.find(tp) : tp;
|
||||||
|
|
||||||
std::vector<TypeId> flattened;
|
std::vector<TypeId> flattened;
|
||||||
std::optional<TypePackId> tail = std::nullopt;
|
std::optional<TypePackId> tail = std::nullopt;
|
||||||
|
DenseHashSet<TypePackId> seenGenericPacks{nullptr};
|
||||||
|
|
||||||
while (tp)
|
while (tp)
|
||||||
{
|
{
|
||||||
|
@ -467,9 +470,10 @@ std::pair<std::vector<TypeId>, std::optional<TypePackId>> flatten(TypePackId tp,
|
||||||
for (; it != end(tp); ++it)
|
for (; it != end(tp); ++it)
|
||||||
flattened.push_back(*it);
|
flattened.push_back(*it);
|
||||||
|
|
||||||
if (const auto tpTail = it.tail(); tpTail && mappedGenericPacks.contains(*tpTail))
|
if (const auto tpTail = it.tail(); tpTail && !seenGenericPacks.contains(*tpTail) && mappedGenericPacks.contains(*tpTail))
|
||||||
{
|
{
|
||||||
tp = *mappedGenericPacks.find(*tpTail);
|
tp = *mappedGenericPacks.find(*tpTail);
|
||||||
|
seenGenericPacks.insert(*tpTail);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
LUAU_FASTFLAG(LuauSolverV2);
|
LUAU_FASTFLAG(LuauSolverV2);
|
||||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
|
|
||||||
// Maximum number of steps to follow when traversing a path. May not always
|
// Maximum number of steps to follow when traversing a path. May not always
|
||||||
// equate to the number of components in a path, depending on the traversal
|
// equate to the number of components in a path, depending on the traversal
|
||||||
|
@ -285,7 +285,7 @@ struct TraversalState
|
||||||
|
|
||||||
TypeOrPack current;
|
TypeOrPack current;
|
||||||
NotNull<BuiltinTypes> builtinTypes;
|
NotNull<BuiltinTypes> builtinTypes;
|
||||||
// TODO: make these NotNull when LuauReturnMappedGenericPacksFromSubtyping is clipped
|
// TODO: make these NotNull when LuauReturnMappedGenericPacksFromSubtyping2 is clipped
|
||||||
const DenseHashMap<TypePackId, TypePackId>* mappedGenericPacks;
|
const DenseHashMap<TypePackId, TypePackId>* mappedGenericPacks;
|
||||||
TypeArena* arena;
|
TypeArena* arena;
|
||||||
int steps = 0;
|
int steps = 0;
|
||||||
|
@ -417,7 +417,7 @@ struct TraversalState
|
||||||
{
|
{
|
||||||
auto currentPack = get<TypePackId>(current);
|
auto currentPack = get<TypePackId>(current);
|
||||||
LUAU_ASSERT(currentPack);
|
LUAU_ASSERT(currentPack);
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
{
|
{
|
||||||
if (const auto tp = get<TypePack>(*currentPack))
|
if (const auto tp = get<TypePack>(*currentPack))
|
||||||
{
|
{
|
||||||
|
@ -576,7 +576,7 @@ struct TraversalState
|
||||||
|
|
||||||
if (auto tail = it.tail())
|
if (auto tail = it.tail())
|
||||||
{
|
{
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping && mappedGenericPacks && mappedGenericPacks->contains(*tail))
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2 && mappedGenericPacks && mappedGenericPacks->contains(*tail))
|
||||||
updateCurrent(*mappedGenericPacks->find(*tail));
|
updateCurrent(*mappedGenericPacks->find(*tail));
|
||||||
else
|
else
|
||||||
updateCurrent(*tail);
|
updateCurrent(*tail);
|
||||||
|
@ -595,9 +595,9 @@ struct TraversalState
|
||||||
if (checkInvariants())
|
if (checkInvariants())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TODO: clip this check once LuauReturnMappedGenericPacksFromSubtyping is clipped
|
// TODO: clip this check once LuauReturnMappedGenericPacksFromSubtyping2 is clipped
|
||||||
// arena and mappedGenericPacks should be NonNull once that happens
|
// arena and mappedGenericPacks should be NonNull once that happens
|
||||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
LUAU_ASSERT(arena && mappedGenericPacks);
|
LUAU_ASSERT(arena && mappedGenericPacks);
|
||||||
else if (!arena || !mappedGenericPacks)
|
else if (!arena || !mappedGenericPacks)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -33,7 +33,8 @@ struct PromoteTypeLevels final : TypeOnceVisitor
|
||||||
TypeLevel minLevel;
|
TypeLevel minLevel;
|
||||||
|
|
||||||
PromoteTypeLevels(TxnLog& log, const TypeArena* typeArena, TypeLevel minLevel)
|
PromoteTypeLevels(TxnLog& log, const TypeArena* typeArena, TypeLevel minLevel)
|
||||||
: log(log)
|
: TypeOnceVisitor("PromoteTypeLevels")
|
||||||
|
, log(log)
|
||||||
, typeArena(typeArena)
|
, typeArena(typeArena)
|
||||||
, minLevel(minLevel)
|
, minLevel(minLevel)
|
||||||
{
|
{
|
||||||
|
@ -145,7 +146,8 @@ void promoteTypeLevels(TxnLog& log, const TypeArena* typeArena, TypeLevel minLev
|
||||||
struct SkipCacheForType final : TypeOnceVisitor
|
struct SkipCacheForType final : TypeOnceVisitor
|
||||||
{
|
{
|
||||||
SkipCacheForType(const DenseHashMap<TypeId, bool>& skipCacheForType, const TypeArena* typeArena)
|
SkipCacheForType(const DenseHashMap<TypeId, bool>& skipCacheForType, const TypeArena* typeArena)
|
||||||
: skipCacheForType(skipCacheForType)
|
: TypeOnceVisitor("SkipCacheForType")
|
||||||
|
, skipCacheForType(skipCacheForType)
|
||||||
, typeArena(typeArena)
|
, typeArena(typeArena)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -404,7 +406,7 @@ static bool isBlocked(const TxnLog& log, TypePackId tp)
|
||||||
|
|
||||||
void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool isIntersection, const LiteralProperties* literalProperties)
|
void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool isIntersection, const LiteralProperties* literalProperties)
|
||||||
{
|
{
|
||||||
RecursionLimiter _ra(&sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
RecursionLimiter _ra("Unifier::tryUnify_", &sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
||||||
|
|
||||||
++sharedState.counters.iterationCount;
|
++sharedState.counters.iterationCount;
|
||||||
|
|
||||||
|
@ -1448,7 +1450,7 @@ void Unifier::tryUnify(TypePackId subTp, TypePackId superTp, bool isFunctionCall
|
||||||
*/
|
*/
|
||||||
void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCall)
|
void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCall)
|
||||||
{
|
{
|
||||||
RecursionLimiter _ra(&sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
RecursionLimiter _ra("Unifier::tryUnify_", &sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
||||||
|
|
||||||
++sharedState.counters.iterationCount;
|
++sharedState.counters.iterationCount;
|
||||||
|
|
||||||
|
@ -2030,7 +2032,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection,
|
||||||
{
|
{
|
||||||
if (FFlag::LuauUnifierRecursionOnRestart)
|
if (FFlag::LuauUnifierRecursionOnRestart)
|
||||||
{
|
{
|
||||||
RecursionLimiter _ra(&sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
RecursionLimiter _ra("Unifier::tryUnifyTables", &sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
||||||
tryUnify(subTy, superTy, false, isIntersection);
|
tryUnify(subTy, superTy, false, isIntersection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2048,7 +2050,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection,
|
||||||
{
|
{
|
||||||
if (errors.empty())
|
if (errors.empty())
|
||||||
{
|
{
|
||||||
RecursionLimiter _ra(&sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
RecursionLimiter _ra("Unifier::tryUnifyTables", &sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
||||||
tryUnifyTables(subTy, superTy, isIntersection);
|
tryUnifyTables(subTy, superTy, isIntersection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2120,7 +2122,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection,
|
||||||
{
|
{
|
||||||
if (FFlag::LuauUnifierRecursionOnRestart)
|
if (FFlag::LuauUnifierRecursionOnRestart)
|
||||||
{
|
{
|
||||||
RecursionLimiter _ra(&sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
RecursionLimiter _ra("Unifier::tryUnifyTables", &sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
||||||
tryUnify(subTy, superTy, false, isIntersection);
|
tryUnify(subTy, superTy, false, isIntersection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2140,7 +2142,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection,
|
||||||
{
|
{
|
||||||
if (errors.empty())
|
if (errors.empty())
|
||||||
{
|
{
|
||||||
RecursionLimiter _ra(&sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
RecursionLimiter _ra("Unifier::tryUnifyTables", &sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
||||||
tryUnifyTables(subTy, superTy, isIntersection);
|
tryUnifyTables(subTy, superTy, isIntersection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2732,7 +2734,7 @@ bool Unifier::occursCheck(TypeId needle, TypeId haystack, bool reversed)
|
||||||
|
|
||||||
bool Unifier::occursCheck(DenseHashSet<TypeId>& seen, TypeId needle, TypeId haystack)
|
bool Unifier::occursCheck(DenseHashSet<TypeId>& seen, TypeId needle, TypeId haystack)
|
||||||
{
|
{
|
||||||
RecursionLimiter _ra(&sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
RecursionLimiter _ra("Unifier::occursCheck", &sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
||||||
|
|
||||||
bool occurrence = false;
|
bool occurrence = false;
|
||||||
|
|
||||||
|
@ -2806,7 +2808,7 @@ bool Unifier::occursCheck(DenseHashSet<TypePackId>& seen, TypePackId needle, Typ
|
||||||
if (!log.getMutable<FreeTypePack>(needle) && !(hideousFixMeGenericsAreActuallyFree && log.is<GenericTypePack>(needle)))
|
if (!log.getMutable<FreeTypePack>(needle) && !(hideousFixMeGenericsAreActuallyFree && log.is<GenericTypePack>(needle)))
|
||||||
ice("Expected needle pack to be free");
|
ice("Expected needle pack to be free");
|
||||||
|
|
||||||
RecursionLimiter _ra(&sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
RecursionLimiter _ra("Unifier::occursCheck", &sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
||||||
|
|
||||||
while (!log.getMutable<ErrorTypePack>(haystack))
|
while (!log.getMutable<ErrorTypePack>(haystack))
|
||||||
{
|
{
|
||||||
|
|
|
@ -722,7 +722,7 @@ TypeId Unifier2::mkIntersection(TypeId left, TypeId right)
|
||||||
|
|
||||||
OccursCheckResult Unifier2::occursCheck(DenseHashSet<TypeId>& seen, TypeId needle, TypeId haystack)
|
OccursCheckResult Unifier2::occursCheck(DenseHashSet<TypeId>& seen, TypeId needle, TypeId haystack)
|
||||||
{
|
{
|
||||||
RecursionLimiter _ra(&recursionCount, recursionLimit);
|
RecursionLimiter _ra("Unifier2::occursCheck", &recursionCount, recursionLimit);
|
||||||
|
|
||||||
OccursCheckResult occurrence = OccursCheckResult::Pass;
|
OccursCheckResult occurrence = OccursCheckResult::Pass;
|
||||||
|
|
||||||
|
@ -784,7 +784,7 @@ OccursCheckResult Unifier2::occursCheck(DenseHashSet<TypePackId>& seen, TypePack
|
||||||
if (!getMutable<FreeTypePack>(needle))
|
if (!getMutable<FreeTypePack>(needle))
|
||||||
ice->ice("Expected needle pack to be free");
|
ice->ice("Expected needle pack to be free");
|
||||||
|
|
||||||
RecursionLimiter _ra(&recursionCount, recursionLimit);
|
RecursionLimiter _ra("Unifier2::occursCheck", &recursionCount, recursionLimit);
|
||||||
|
|
||||||
while (!getMutable<ErrorTypePack>(haystack))
|
while (!getMutable<ErrorTypePack>(haystack))
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,7 +39,7 @@ private:
|
||||||
T oldValue;
|
T oldValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
struct FindUserTypeFunctionBlockers : TypeOnceVisitor
|
struct FindUserTypeFunctionBlockers : TypeOnceVisitor
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,7 @@ struct FindUserTypeFunctionBlockers : TypeOnceVisitor
|
||||||
std::vector<TypeId> blockingTypes;
|
std::vector<TypeId> blockingTypes;
|
||||||
|
|
||||||
explicit FindUserTypeFunctionBlockers(NotNull<TypeFunctionContext> ctx)
|
explicit FindUserTypeFunctionBlockers(NotNull<TypeFunctionContext> ctx)
|
||||||
: TypeOnceVisitor(/* skipBoundTypes */ true)
|
: TypeOnceVisitor("FindUserTypeFunctionBlockers", /* skipBoundTypes */ true)
|
||||||
, ctx(ctx)
|
, ctx(ctx)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100)
|
||||||
// flag so that we don't break production games by reverting syntax changes.
|
// flag so that we don't break production games by reverting syntax changes.
|
||||||
// See docs/SyntaxChanges.md for an explanation.
|
// See docs/SyntaxChanges.md for an explanation.
|
||||||
LUAU_FASTFLAGVARIABLE(LuauSolverV2)
|
LUAU_FASTFLAGVARIABLE(LuauSolverV2)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauDeclareExternType)
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauParseStringIndexer)
|
LUAU_FASTFLAGVARIABLE(LuauParseStringIndexer)
|
||||||
LUAU_FASTFLAGVARIABLE(LuauParseAttributeFixUninit)
|
LUAU_FASTFLAGVARIABLE(LuauParseAttributeFixUninit)
|
||||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(DebugLuauReportReturnTypeVariadicWithTypeSuffix, false)
|
LUAU_DYNAMIC_FASTFLAGVARIABLE(DebugLuauReportReturnTypeVariadicWithTypeSuffix, false)
|
||||||
|
@ -1249,11 +1248,9 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
|
||||||
retTypes
|
retTypes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (AstName(lexer.current().name) == "class" || (FFlag::LuauDeclareExternType && AstName(lexer.current().name) == "extern"))
|
else if (AstName(lexer.current().name) == "class" || AstName(lexer.current().name) == "extern")
|
||||||
{
|
{
|
||||||
bool foundExtern = false;
|
bool foundExtern = false;
|
||||||
if (FFlag::LuauDeclareExternType)
|
|
||||||
{
|
|
||||||
if (AstName(lexer.current().name) == "extern")
|
if (AstName(lexer.current().name) == "extern")
|
||||||
{
|
{
|
||||||
foundExtern = true;
|
foundExtern = true;
|
||||||
|
@ -1263,22 +1260,20 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
|
||||||
lexer.current().location, {}, {}, "Expected `type` keyword after `extern`, but got %s instead", lexer.current().name
|
lexer.current().location, {}, {}, "Expected `type` keyword after `extern`, but got %s instead", lexer.current().name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
nextLexeme();
|
nextLexeme();
|
||||||
|
|
||||||
Location classStart = lexer.current().location;
|
Location classStart = lexer.current().location;
|
||||||
Name className = parseName(FFlag::LuauDeclareExternType ? "type name" : "class name");
|
Name className = parseName("type name");
|
||||||
std::optional<AstName> superName = std::nullopt;
|
std::optional<AstName> superName = std::nullopt;
|
||||||
|
|
||||||
if (AstName(lexer.current().name) == "extends")
|
if (AstName(lexer.current().name) == "extends")
|
||||||
{
|
{
|
||||||
nextLexeme();
|
nextLexeme();
|
||||||
superName = parseName(FFlag::LuauDeclareExternType ? "supertype name" : "superclass name").name;
|
superName = parseName("supertype name").name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FFlag::LuauDeclareExternType)
|
|
||||||
{
|
|
||||||
if (foundExtern)
|
if (foundExtern)
|
||||||
{
|
{
|
||||||
if (AstName(lexer.current().name) != "with")
|
if (AstName(lexer.current().name) != "with")
|
||||||
|
@ -1290,7 +1285,7 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
|
||||||
else
|
else
|
||||||
nextLexeme();
|
nextLexeme();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TempVector<AstDeclaredExternTypeProperty> props(scratchDeclaredClassProps);
|
TempVector<AstDeclaredExternTypeProperty> props(scratchDeclaredClassProps);
|
||||||
AstTableIndexer* indexer = nullptr;
|
AstTableIndexer* indexer = nullptr;
|
||||||
|
@ -1357,10 +1352,7 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
|
||||||
AstTableIndexer* badIndexer = parseTableIndexer(AstTableAccess::ReadWrite, std::nullopt, begin).node;
|
AstTableIndexer* badIndexer = parseTableIndexer(AstTableAccess::ReadWrite, std::nullopt, begin).node;
|
||||||
|
|
||||||
// we lose all additional indexer expressions from the AST after error recovery here
|
// we lose all additional indexer expressions from the AST after error recovery here
|
||||||
if (FFlag::LuauDeclareExternType)
|
|
||||||
report(badIndexer->location, "Cannot have more than one indexer on an extern type");
|
report(badIndexer->location, "Cannot have more than one indexer on an extern type");
|
||||||
else
|
|
||||||
report(badIndexer->location, "Cannot have more than one class indexer");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1427,10 +1419,7 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
|
||||||
AstTableIndexer* badIndexer = parseTableIndexer(AstTableAccess::ReadWrite, std::nullopt, lexer.current()).node;
|
AstTableIndexer* badIndexer = parseTableIndexer(AstTableAccess::ReadWrite, std::nullopt, lexer.current()).node;
|
||||||
|
|
||||||
// we lose all additional indexer expressions from the AST after error recovery here
|
// we lose all additional indexer expressions from the AST after error recovery here
|
||||||
if (FFlag::LuauDeclareExternType)
|
|
||||||
report(badIndexer->location, "Cannot have more than one indexer on an extern type");
|
report(badIndexer->location, "Cannot have more than one indexer on an extern type");
|
||||||
else
|
|
||||||
report(badIndexer->location, "Cannot have more than one class indexer");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1466,13 +1455,9 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
|
||||||
AstType* type = parseType(/* in declaration context */ true);
|
AstType* type = parseType(/* in declaration context */ true);
|
||||||
return allocator.alloc<AstStatDeclareGlobal>(Location(start, type->location), globalName->name, globalName->location, type);
|
return allocator.alloc<AstStatDeclareGlobal>(Location(start, type->location), globalName->name, globalName->location, type);
|
||||||
}
|
}
|
||||||
else if (FFlag::LuauDeclareExternType)
|
|
||||||
{
|
|
||||||
return reportStatError(start, {}, {}, "declare must be followed by an identifier, 'function', or 'extern type'");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return reportStatError(start, {}, {}, "declare must be followed by an identifier, 'function', or 'class'");
|
return reportStatError(start, {}, {}, "declare must be followed by an identifier, 'function', or 'extern type'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,8 @@ inline bool isAnalysisFlagExperimental(const char* flag)
|
||||||
"LuauTableCloneClonesType3", // requires fixes in lua-apps code, terrifyingly
|
"LuauTableCloneClonesType3", // requires fixes in lua-apps code, terrifyingly
|
||||||
"LuauNormalizationReorderFreeTypeIntersect", // requires fixes in lua-apps code, also terrifyingly
|
"LuauNormalizationReorderFreeTypeIntersect", // requires fixes in lua-apps code, also terrifyingly
|
||||||
"LuauSolverV2",
|
"LuauSolverV2",
|
||||||
"UseNewLuauTypeSolverDefaultEnabled", // This can change the default solver used in cli applications, so it also needs to be disabled. Will require fixes in lua-apps code
|
"UseNewLuauTypeSolverDefaultEnabled", // This can change the default solver used in cli applications, so it also needs to be disabled. Will
|
||||||
|
// require fixes in lua-apps code
|
||||||
// makes sure we always have at least one entry
|
// makes sure we always have at least one entry
|
||||||
nullptr,
|
nullptr,
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,10 +26,8 @@ LUAU_FASTINTVARIABLE(LuauCompileInlineThreshold, 25)
|
||||||
LUAU_FASTINTVARIABLE(LuauCompileInlineThresholdMaxBoost, 300)
|
LUAU_FASTINTVARIABLE(LuauCompileInlineThresholdMaxBoost, 300)
|
||||||
LUAU_FASTINTVARIABLE(LuauCompileInlineDepth, 5)
|
LUAU_FASTINTVARIABLE(LuauCompileInlineDepth, 5)
|
||||||
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauCompileInlineNonConstInit)
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauSeparateCompilerTypeInfo)
|
LUAU_FASTFLAGVARIABLE(LuauSeparateCompilerTypeInfo)
|
||||||
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauCompileFixTypeFunctionSkip)
|
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
|
@ -696,10 +694,7 @@ struct Compiler
|
||||||
// if the argument is a local that isn't mutated, we will simply reuse the existing register
|
// if the argument is a local that isn't mutated, we will simply reuse the existing register
|
||||||
if (int reg = le ? getExprLocalReg(le) : -1; reg >= 0 && (!lv || !lv->written))
|
if (int reg = le ? getExprLocalReg(le) : -1; reg >= 0 && (!lv || !lv->written))
|
||||||
{
|
{
|
||||||
if (FFlag::LuauCompileInlineNonConstInit)
|
|
||||||
args.push_back({var, uint8_t(reg), {Constant::Type_Unknown}, kDefaultAllocPc, lv ? lv->init : nullptr});
|
args.push_back({var, uint8_t(reg), {Constant::Type_Unknown}, kDefaultAllocPc, lv ? lv->init : nullptr});
|
||||||
else
|
|
||||||
args.push_back({var, uint8_t(reg), {Constant::Type_Unknown}, kDefaultAllocPc});
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -725,7 +720,7 @@ struct Compiler
|
||||||
{
|
{
|
||||||
pushLocal(arg.local, arg.reg, arg.allocpc);
|
pushLocal(arg.local, arg.reg, arg.allocpc);
|
||||||
|
|
||||||
if (FFlag::LuauCompileInlineNonConstInit && arg.init)
|
if (arg.init)
|
||||||
{
|
{
|
||||||
if (Variable* lv = variables.find(arg.local))
|
if (Variable* lv = variables.find(arg.local))
|
||||||
lv->init = arg.init;
|
lv->init = arg.init;
|
||||||
|
@ -785,12 +780,9 @@ struct Compiler
|
||||||
if (Constant* var = locstants.find(local))
|
if (Constant* var = locstants.find(local))
|
||||||
var->type = Constant::Type_Unknown;
|
var->type = Constant::Type_Unknown;
|
||||||
|
|
||||||
if (FFlag::LuauCompileInlineNonConstInit)
|
|
||||||
{
|
|
||||||
if (Variable* lv = variables.find(local))
|
if (Variable* lv = variables.find(local))
|
||||||
lv->init = nullptr;
|
lv->init = nullptr;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
foldConstants(constants, variables, locstants, builtinsFold, builtinsFoldLibraryK, options.libraryMemberConstantCb, func->body);
|
foldConstants(constants, variables, locstants, builtinsFold, builtinsFoldLibraryK, options.libraryMemberConstantCb, func->body);
|
||||||
}
|
}
|
||||||
|
@ -3956,7 +3948,7 @@ struct Compiler
|
||||||
|
|
||||||
bool visit(AstStatTypeFunction* node) override
|
bool visit(AstStatTypeFunction* node) override
|
||||||
{
|
{
|
||||||
return !FFlag::LuauCompileFixTypeFunctionSkip;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
|
||||||
LUAU_FASTFLAGVARIABLE(LuauCompileCostModelConstants)
|
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
namespace Compile
|
namespace Compile
|
||||||
|
@ -43,25 +41,6 @@ static uint64_t parallelMulSat(uint64_t a, int b)
|
||||||
return r | (s - (s >> 7));
|
return r | (s - (s >> 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool getNumber_DEPRECATED(AstExpr* node, double& result)
|
|
||||||
{
|
|
||||||
// since constant model doesn't use constant folding atm, we perform the basic extraction that's sufficient to handle positive/negative literals
|
|
||||||
if (AstExprConstantNumber* ne = node->as<AstExprConstantNumber>())
|
|
||||||
{
|
|
||||||
result = ne->value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AstExprUnary* ue = node->as<AstExprUnary>(); ue && ue->op == AstExprUnary::Minus)
|
|
||||||
if (AstExprConstantNumber* ne = ue->expr->as<AstExprConstantNumber>())
|
|
||||||
{
|
|
||||||
result = -ne->value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Cost
|
struct Cost
|
||||||
{
|
{
|
||||||
static const uint64_t kLiteral = ~0ull;
|
static const uint64_t kLiteral = ~0ull;
|
||||||
|
@ -132,7 +111,7 @@ struct CostVisitor : AstVisitor
|
||||||
|
|
||||||
Cost model(AstExpr* node)
|
Cost model(AstExpr* node)
|
||||||
{
|
{
|
||||||
if (FFlag::LuauCompileCostModelConstants && constants.contains(node))
|
if (constants.contains(node))
|
||||||
return Cost(0, Cost::kLiteral);
|
return Cost(0, Cost::kLiteral);
|
||||||
|
|
||||||
if (AstExprGroup* expr = node->as<AstExprGroup>())
|
if (AstExprGroup* expr = node->as<AstExprGroup>())
|
||||||
|
@ -280,17 +259,8 @@ struct CostVisitor : AstVisitor
|
||||||
int tripCount = -1;
|
int tripCount = -1;
|
||||||
double from, to, step = 1;
|
double from, to, step = 1;
|
||||||
|
|
||||||
if (FFlag::LuauCompileCostModelConstants)
|
|
||||||
{
|
|
||||||
if (getNumber(node->from, from) && getNumber(node->to, to) && (!node->step || getNumber(node->step, step)))
|
if (getNumber(node->from, from) && getNumber(node->to, to) && (!node->step || getNumber(node->step, step)))
|
||||||
tripCount = getTripCount(from, to, step);
|
tripCount = getTripCount(from, to, step);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (getNumber_DEPRECATED(node->from, from) && getNumber_DEPRECATED(node->to, to) &&
|
|
||||||
(!node->step || getNumber_DEPRECATED(node->step, step)))
|
|
||||||
tripCount = getTripCount(from, to, step);
|
|
||||||
}
|
|
||||||
|
|
||||||
loop(node->body, 1, tripCount < 0 ? 3 : tripCount);
|
loop(node->body, 1, tripCount < 0 ? 3 : tripCount);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
|
|
||||||
#include "Luau/Lexer.h"
|
#include "Luau/Lexer.h"
|
||||||
|
|
||||||
LUAU_FASTFLAG(LuauCompileInlineNonConstInit)
|
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
{
|
{
|
||||||
namespace Compile
|
namespace Compile
|
||||||
|
@ -84,12 +82,9 @@ struct ValueVisitor : AstVisitor
|
||||||
}
|
}
|
||||||
|
|
||||||
bool visit(AstExprFunction* node) override
|
bool visit(AstExprFunction* node) override
|
||||||
{
|
|
||||||
if (FFlag::LuauCompileInlineNonConstInit)
|
|
||||||
{
|
{
|
||||||
for (AstLocal* arg : node->args)
|
for (AstLocal* arg : node->args)
|
||||||
variables[arg].init = nullptr;
|
variables[arg].init = nullptr;
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuauSafeStackCheck, false)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file contains most implementations of core Lua APIs from lua.h.
|
* This file contains most implementations of core Lua APIs from lua.h.
|
||||||
*
|
*
|
||||||
|
@ -138,8 +140,37 @@ int lua_checkstack(lua_State* L, int size)
|
||||||
if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK)
|
if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK)
|
||||||
res = 0; // stack overflow
|
res = 0; // stack overflow
|
||||||
else if (size > 0)
|
else if (size > 0)
|
||||||
|
{
|
||||||
|
if (DFFlag::LuauSafeStackCheck)
|
||||||
|
{
|
||||||
|
if (stacklimitreached(L, size))
|
||||||
|
{
|
||||||
|
struct CallContext
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
|
||||||
|
static void run(lua_State* L, void* ud)
|
||||||
|
{
|
||||||
|
CallContext* ctx = (CallContext*)ud;
|
||||||
|
|
||||||
|
luaD_growstack(L, ctx->size);
|
||||||
|
}
|
||||||
|
} ctx = {size};
|
||||||
|
|
||||||
|
// there could be no memory to extend the stack
|
||||||
|
if (luaD_rawrunprotected(L, &CallContext::run, &ctx) != LUA_OK)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
luaD_checkstack(L, size);
|
luaD_checkstack(L, size);
|
||||||
|
}
|
||||||
|
|
||||||
expandstacklimit(L, L->top + size);
|
expandstacklimit(L, L->top + size);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuauErrorYield, false)
|
||||||
|
|
||||||
// keep max stack allocation request under 1GB
|
// keep max stack allocation request under 1GB
|
||||||
#define MAX_STACK_SIZE (int(1024 / sizeof(TValue)) * 1024 * 1024)
|
#define MAX_STACK_SIZE (int(1024 / sizeof(TValue)) * 1024 * 1024)
|
||||||
|
|
||||||
|
@ -249,6 +251,23 @@ void luaD_checkCstack(lua_State* L)
|
||||||
luaD_throw(L, LUA_ERRERR); // error while handling stack error
|
luaD_throw(L, LUA_ERRERR); // error while handling stack error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void performcall(lua_State* L, StkId func, int nresults)
|
||||||
|
{
|
||||||
|
if (luau_precall(L, func, nresults) == PCRLUA)
|
||||||
|
{ // is a Lua function?
|
||||||
|
L->ci->flags |= LUA_CALLINFO_RETURN; // luau_execute will stop after returning from the stack frame
|
||||||
|
|
||||||
|
bool oldactive = L->isactive;
|
||||||
|
L->isactive = true;
|
||||||
|
luaC_threadbarrier(L);
|
||||||
|
|
||||||
|
luau_execute(L); // call it
|
||||||
|
|
||||||
|
if (!oldactive)
|
||||||
|
L->isactive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Call a function (C or Lua). The function to be called is at *func.
|
** Call a function (C or Lua). The function to be called is at *func.
|
||||||
** The arguments are on the stack, right after the function.
|
** The arguments are on the stack, right after the function.
|
||||||
|
@ -277,6 +296,12 @@ void luaD_call(lua_State* L, StkId func, int nresults)
|
||||||
ptrdiff_t funcoffset = savestack(L, func);
|
ptrdiff_t funcoffset = savestack(L, func);
|
||||||
ptrdiff_t cioffset = saveci(L, L->ci);
|
ptrdiff_t cioffset = saveci(L, L->ci);
|
||||||
|
|
||||||
|
if (DFFlag::LuauErrorYield)
|
||||||
|
{
|
||||||
|
performcall(L, func, nresults);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (luau_precall(L, func, nresults) == PCRLUA)
|
if (luau_precall(L, func, nresults) == PCRLUA)
|
||||||
{ // is a Lua function?
|
{ // is a Lua function?
|
||||||
L->ci->flags |= LUA_CALLINFO_RETURN; // luau_execute will stop after returning from the stack frame
|
L->ci->flags |= LUA_CALLINFO_RETURN; // luau_execute will stop after returning from the stack frame
|
||||||
|
@ -290,6 +315,7 @@ void luaD_call(lua_State* L, StkId func, int nresults)
|
||||||
if (!oldactive)
|
if (!oldactive)
|
||||||
L->isactive = false;
|
L->isactive = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool yielded = L->status == LUA_YIELD || L->status == LUA_BREAK;
|
bool yielded = L->status == LUA_YIELD || L->status == LUA_BREAK;
|
||||||
|
|
||||||
|
@ -314,6 +340,27 @@ void luaD_call(lua_State* L, StkId func, int nresults)
|
||||||
luaC_checkGC(L);
|
luaC_checkGC(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Non-yieldable version of luaD_call, used primarily to call an error handler which cannot yield
|
||||||
|
void luaD_callny(lua_State* L, StkId func, int nresults)
|
||||||
|
{
|
||||||
|
if (++L->nCcalls >= LUAI_MAXCCALLS)
|
||||||
|
luaD_checkCstack(L);
|
||||||
|
|
||||||
|
LUAU_ASSERT(L->nCcalls > L->baseCcalls);
|
||||||
|
|
||||||
|
ptrdiff_t funcoffset = savestack(L, func);
|
||||||
|
|
||||||
|
performcall(L, func, nresults);
|
||||||
|
|
||||||
|
LUAU_ASSERT(L->status != LUA_YIELD && L->status != LUA_BREAK);
|
||||||
|
|
||||||
|
if (nresults != LUA_MULTRET)
|
||||||
|
L->top = restorestack(L, funcoffset) + nresults;
|
||||||
|
|
||||||
|
L->nCcalls--;
|
||||||
|
luaC_checkGC(L);
|
||||||
|
}
|
||||||
|
|
||||||
static void seterrorobj(lua_State* L, int errcode, StkId oldtop)
|
static void seterrorobj(lua_State* L, int errcode, StkId oldtop)
|
||||||
{
|
{
|
||||||
switch (errcode)
|
switch (errcode)
|
||||||
|
@ -595,6 +642,10 @@ static void callerrfunc(lua_State* L, void* ud)
|
||||||
setobj2s(L, L->top, L->top - 1);
|
setobj2s(L, L->top, L->top - 1);
|
||||||
setobj2s(L, L->top - 1, errfunc);
|
setobj2s(L, L->top - 1, errfunc);
|
||||||
incr_top(L);
|
incr_top(L);
|
||||||
|
|
||||||
|
if (DFFlag::LuauErrorYield)
|
||||||
|
luaD_callny(L, L->top - 2, 1);
|
||||||
|
else
|
||||||
luaD_call(L, L->top - 2, 1);
|
luaD_call(L, L->top - 2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,15 +10,16 @@
|
||||||
// returns target stack for 'n' extra elements to reallocate
|
// returns target stack for 'n' extra elements to reallocate
|
||||||
// if possible, stack size growth factor is 2x
|
// if possible, stack size growth factor is 2x
|
||||||
#define getgrownstacksize(L, n) ((n) <= L->stacksize ? 2 * L->stacksize : L->stacksize + (n))
|
#define getgrownstacksize(L, n) ((n) <= L->stacksize ? 2 * L->stacksize : L->stacksize + (n))
|
||||||
|
#define stacklimitreached(L, n) ((char*)L->stack_last - (char*)L->top <= (n) * (int)sizeof(TValue))
|
||||||
|
|
||||||
#define luaD_checkstackfornewci(L, n) \
|
#define luaD_checkstackfornewci(L, n) \
|
||||||
if ((char*)L->stack_last - (char*)L->top <= (n) * (int)sizeof(TValue)) \
|
if (stacklimitreached(L, (n))) \
|
||||||
luaD_reallocstack(L, getgrownstacksize(L, (n)), 1); \
|
luaD_reallocstack(L, getgrownstacksize(L, (n)), 1); \
|
||||||
else \
|
else \
|
||||||
condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK, 1));
|
condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK, 1));
|
||||||
|
|
||||||
#define luaD_checkstack(L, n) \
|
#define luaD_checkstack(L, n) \
|
||||||
if ((char*)L->stack_last - (char*)L->top <= (n) * (int)sizeof(TValue)) \
|
if (stacklimitreached(L, (n))) \
|
||||||
luaD_growstack(L, n); \
|
luaD_growstack(L, n); \
|
||||||
else \
|
else \
|
||||||
condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK, 0));
|
condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK, 0));
|
||||||
|
@ -55,6 +56,7 @@ typedef void (*Pfunc)(lua_State* L, void* ud);
|
||||||
LUAI_FUNC CallInfo* luaD_growCI(lua_State* L);
|
LUAI_FUNC CallInfo* luaD_growCI(lua_State* L);
|
||||||
|
|
||||||
LUAI_FUNC void luaD_call(lua_State* L, StkId func, int nresults);
|
LUAI_FUNC void luaD_call(lua_State* L, StkId func, int nresults);
|
||||||
|
LUAI_FUNC void luaD_callny(lua_State* L, StkId func, int nresults);
|
||||||
LUAI_FUNC int luaD_pcall(lua_State* L, Pfunc func, void* u, ptrdiff_t oldtop, ptrdiff_t ef);
|
LUAI_FUNC int luaD_pcall(lua_State* L, Pfunc func, void* u, ptrdiff_t oldtop, ptrdiff_t ef);
|
||||||
LUAI_FUNC void luaD_reallocCI(lua_State* L, int newsize);
|
LUAI_FUNC void luaD_reallocCI(lua_State* L, int newsize);
|
||||||
LUAI_FUNC void luaD_reallocstack(lua_State* L, int newsize, int fornewci);
|
LUAI_FUNC void luaD_reallocstack(lua_State* L, int newsize, int fornewci);
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
LUAU_FASTFLAGVARIABLE(LuauHeapDumpStringSizeOverhead)
|
||||||
|
|
||||||
static void validateobjref(global_State* g, GCObject* f, GCObject* t)
|
static void validateobjref(global_State* g, GCObject* f, GCObject* t)
|
||||||
{
|
{
|
||||||
LUAU_ASSERT(!isdead(g, t));
|
LUAU_ASSERT(!isdead(g, t));
|
||||||
|
@ -651,6 +653,9 @@ static void enumedges(EnumContext* ctx, GCObject* from, TValue* data, size_t siz
|
||||||
|
|
||||||
static void enumstring(EnumContext* ctx, TString* ts)
|
static void enumstring(EnumContext* ctx, TString* ts)
|
||||||
{
|
{
|
||||||
|
if (FFlag::LuauHeapDumpStringSizeOverhead)
|
||||||
|
enumnode(ctx, obj2gco(ts), sizestring(ts->len), NULL);
|
||||||
|
else
|
||||||
enumnode(ctx, obj2gco(ts), ts->len, NULL);
|
enumnode(ctx, obj2gco(ts), ts->len, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,28 +2,200 @@
|
||||||
#include "luau.pb.h"
|
#include "luau.pb.h"
|
||||||
|
|
||||||
static const std::string kNames[] = {
|
static const std::string kNames[] = {
|
||||||
"_G", "_VERSION", "__add", "__call", "__concat", "__div", "__eq", "__idiv", "__index",
|
"_G",
|
||||||
"__iter", "__le", "__len", "__lt", "__mod", "__mode", "__mul", "__namecall", "__newindex",
|
"_VERSION",
|
||||||
"__pow", "__sub", "__type", "__unm", "abs", "acos", "arshift", "asin", "assert",
|
"__add",
|
||||||
"atan", "atan2", "band", "bit32", "bnot", "boolean", "bor", "btest", "buffer",
|
"__call",
|
||||||
"bxor", "byte", "ceil", "char", "charpattern", "clamp", "clear", "clock", "clone",
|
"__concat",
|
||||||
"close", "codepoint", "codes", "collectgarbage", "concat", "copy", "coroutine", "cos", "cosh",
|
"__div",
|
||||||
"countlz", "countrz", "create", "date", "debug", "deg", "difftime", "error", "exp",
|
"__eq",
|
||||||
"extract", "fill", "find", "floor", "fmod", "foreach", "foreachi", "format", "freeze",
|
"__idiv",
|
||||||
"frexp", "fromstring", "function", "gcinfo", "getfenv", "getmetatable", "getn", "gmatch", "gsub",
|
"__index",
|
||||||
"huge", "info", "insert", "ipairs", "isfrozen", "isyieldable", "ldexp", "len", "loadstring",
|
"__iter",
|
||||||
"log", "log10", "lower", "lrotate", "lshift", "match", "math", "max", "maxn",
|
"__le",
|
||||||
"min", "modf", "move", "newproxy", "next", "nil", "noise", "number", "offset",
|
"__len",
|
||||||
"os", "pack", "packsize", "pairs", "pcall", "pi", "pow", "print", "rad",
|
"__lt",
|
||||||
"random", "randomseed", "rawequal", "rawget", "rawlen", "rawset", "readf32", "readf64", "readi16",
|
"__mod",
|
||||||
"readi32", "readi8", "readstring", "readu16", "readu32", "readu8", "remove", "rep", "replace",
|
"__mode",
|
||||||
"require", "resume", "reverse", "round", "rrotate", "rshift", "running", "select", "setfenv",
|
"__mul",
|
||||||
"setmetatable", "sign", "sin", "sinh", "sort", "split", "sqrt", "status", "string",
|
"__namecall",
|
||||||
"sub", "table", "tan", "tanh", "thread", "time", "tonumber", "tostring", "tostring",
|
"__newindex",
|
||||||
"traceback", "type", "typeof", "unpack", "upper", "userdata", "utf8", "vector", "wrap",
|
"__pow",
|
||||||
"writef32", "writef64", "writei16", "writei32", "writei8", "writestring", "writeu16", "writeu32", "writeu8",
|
"__sub",
|
||||||
"xpcall", "yield", "types", "unknown", "never", "any", "singleton", "optional", "generic",
|
"__type",
|
||||||
"negationof", "unionof", "intersectionof", "newtable", "newfunction",
|
"__unm",
|
||||||
|
"abs",
|
||||||
|
"acos",
|
||||||
|
"arshift",
|
||||||
|
"asin",
|
||||||
|
"assert",
|
||||||
|
"atan",
|
||||||
|
"atan2",
|
||||||
|
"band",
|
||||||
|
"bit32",
|
||||||
|
"bnot",
|
||||||
|
"boolean",
|
||||||
|
"bor",
|
||||||
|
"btest",
|
||||||
|
"buffer",
|
||||||
|
"bxor",
|
||||||
|
"byte",
|
||||||
|
"ceil",
|
||||||
|
"char",
|
||||||
|
"charpattern",
|
||||||
|
"clamp",
|
||||||
|
"clear",
|
||||||
|
"clock",
|
||||||
|
"clone",
|
||||||
|
"close",
|
||||||
|
"codepoint",
|
||||||
|
"codes",
|
||||||
|
"collectgarbage",
|
||||||
|
"concat",
|
||||||
|
"copy",
|
||||||
|
"coroutine",
|
||||||
|
"cos",
|
||||||
|
"cosh",
|
||||||
|
"countlz",
|
||||||
|
"countrz",
|
||||||
|
"create",
|
||||||
|
"date",
|
||||||
|
"debug",
|
||||||
|
"deg",
|
||||||
|
"difftime",
|
||||||
|
"error",
|
||||||
|
"exp",
|
||||||
|
"extract",
|
||||||
|
"fill",
|
||||||
|
"find",
|
||||||
|
"floor",
|
||||||
|
"fmod",
|
||||||
|
"foreach",
|
||||||
|
"foreachi",
|
||||||
|
"format",
|
||||||
|
"freeze",
|
||||||
|
"frexp",
|
||||||
|
"fromstring",
|
||||||
|
"function",
|
||||||
|
"gcinfo",
|
||||||
|
"getfenv",
|
||||||
|
"getmetatable",
|
||||||
|
"getn",
|
||||||
|
"gmatch",
|
||||||
|
"gsub",
|
||||||
|
"huge",
|
||||||
|
"info",
|
||||||
|
"insert",
|
||||||
|
"ipairs",
|
||||||
|
"isfrozen",
|
||||||
|
"isyieldable",
|
||||||
|
"ldexp",
|
||||||
|
"len",
|
||||||
|
"loadstring",
|
||||||
|
"log",
|
||||||
|
"log10",
|
||||||
|
"lower",
|
||||||
|
"lrotate",
|
||||||
|
"lshift",
|
||||||
|
"match",
|
||||||
|
"math",
|
||||||
|
"max",
|
||||||
|
"maxn",
|
||||||
|
"min",
|
||||||
|
"modf",
|
||||||
|
"move",
|
||||||
|
"newproxy",
|
||||||
|
"next",
|
||||||
|
"nil",
|
||||||
|
"noise",
|
||||||
|
"number",
|
||||||
|
"offset",
|
||||||
|
"os",
|
||||||
|
"pack",
|
||||||
|
"packsize",
|
||||||
|
"pairs",
|
||||||
|
"pcall",
|
||||||
|
"pi",
|
||||||
|
"pow",
|
||||||
|
"print",
|
||||||
|
"rad",
|
||||||
|
"random",
|
||||||
|
"randomseed",
|
||||||
|
"rawequal",
|
||||||
|
"rawget",
|
||||||
|
"rawlen",
|
||||||
|
"rawset",
|
||||||
|
"readf32",
|
||||||
|
"readf64",
|
||||||
|
"readi16",
|
||||||
|
"readi32",
|
||||||
|
"readi8",
|
||||||
|
"readstring",
|
||||||
|
"readu16",
|
||||||
|
"readu32",
|
||||||
|
"readu8",
|
||||||
|
"remove",
|
||||||
|
"rep",
|
||||||
|
"replace",
|
||||||
|
"require",
|
||||||
|
"resume",
|
||||||
|
"reverse",
|
||||||
|
"round",
|
||||||
|
"rrotate",
|
||||||
|
"rshift",
|
||||||
|
"running",
|
||||||
|
"select",
|
||||||
|
"setfenv",
|
||||||
|
"setmetatable",
|
||||||
|
"sign",
|
||||||
|
"sin",
|
||||||
|
"sinh",
|
||||||
|
"sort",
|
||||||
|
"split",
|
||||||
|
"sqrt",
|
||||||
|
"status",
|
||||||
|
"string",
|
||||||
|
"sub",
|
||||||
|
"table",
|
||||||
|
"tan",
|
||||||
|
"tanh",
|
||||||
|
"thread",
|
||||||
|
"time",
|
||||||
|
"tonumber",
|
||||||
|
"tostring",
|
||||||
|
"tostring",
|
||||||
|
"traceback",
|
||||||
|
"type",
|
||||||
|
"typeof",
|
||||||
|
"unpack",
|
||||||
|
"upper",
|
||||||
|
"userdata",
|
||||||
|
"utf8",
|
||||||
|
"vector",
|
||||||
|
"wrap",
|
||||||
|
"writef32",
|
||||||
|
"writef64",
|
||||||
|
"writei16",
|
||||||
|
"writei32",
|
||||||
|
"writei8",
|
||||||
|
"writestring",
|
||||||
|
"writeu16",
|
||||||
|
"writeu32",
|
||||||
|
"writeu8",
|
||||||
|
"xpcall",
|
||||||
|
"yield",
|
||||||
|
"types",
|
||||||
|
"unknown",
|
||||||
|
"never",
|
||||||
|
"any",
|
||||||
|
"singleton",
|
||||||
|
"optional",
|
||||||
|
"generic",
|
||||||
|
"negationof",
|
||||||
|
"unionof",
|
||||||
|
"intersectionof",
|
||||||
|
"newtable",
|
||||||
|
"newfunction",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::string kTypes[] = {
|
static const std::string kTypes[] = {
|
||||||
|
@ -46,25 +218,8 @@ static const std::string kExternTypes[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::string kBuiltinTypes[] = {
|
static const std::string kBuiltinTypes[] = {
|
||||||
"len",
|
"len", "unm", "add", "sub", "mul", "div", "idiv", "pow", "mod", "concat",
|
||||||
"unm",
|
"lt", "le", "eq", "keyof", "rawkeyof", "index", "rawget", "setmetatable", "getmetatable",
|
||||||
"add",
|
|
||||||
"sub",
|
|
||||||
"mul",
|
|
||||||
"div",
|
|
||||||
"idiv",
|
|
||||||
"pow",
|
|
||||||
"mod",
|
|
||||||
"concat",
|
|
||||||
"lt",
|
|
||||||
"le",
|
|
||||||
"eq",
|
|
||||||
"keyof",
|
|
||||||
"rawkeyof",
|
|
||||||
"index",
|
|
||||||
"rawget",
|
|
||||||
"setmetatable",
|
|
||||||
"getmetatable",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ProtoToLuau
|
struct ProtoToLuau
|
||||||
|
|
|
@ -12,7 +12,6 @@ namespace Luau
|
||||||
ExternTypeFixture::ExternTypeFixture(bool prepareAutocomplete)
|
ExternTypeFixture::ExternTypeFixture(bool prepareAutocomplete)
|
||||||
: BuiltinsFixture(prepareAutocomplete)
|
: BuiltinsFixture(prepareAutocomplete)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Frontend& ExternTypeFixture::getFrontend()
|
Frontend& ExternTypeFixture::getFrontend()
|
||||||
|
@ -37,7 +36,8 @@ Frontend& ExternTypeFixture::getFrontend()
|
||||||
};
|
};
|
||||||
|
|
||||||
getMutable<ExternType>(connectionType)->props = {
|
getMutable<ExternType>(connectionType)->props = {
|
||||||
{"Connect", {makeFunction(arena, connectionType, {makeFunction(arena, nullopt, {baseClassInstanceType}, {})}, {})}}};
|
{"Connect", {makeFunction(arena, connectionType, {makeFunction(arena, nullopt, {baseClassInstanceType}, {})}, {})}}
|
||||||
|
};
|
||||||
|
|
||||||
TypeId baseClassType = arena.addType(ExternType{"BaseClass", {}, nullopt, nullopt, {}, {}, "Test", {}});
|
TypeId baseClassType = arena.addType(ExternType{"BaseClass", {}, nullopt, nullopt, {}, {}, "Test", {}});
|
||||||
getMutable<ExternType>(baseClassType)->props = {
|
getMutable<ExternType>(baseClassType)->props = {
|
||||||
|
@ -114,7 +114,8 @@ Frontend& ExternTypeFixture::getFrontend()
|
||||||
{arena.addType(IntersectionType{{
|
{arena.addType(IntersectionType{{
|
||||||
makeFunction(arena, vector2InstanceType, {vector2InstanceType}, {vector2InstanceType}),
|
makeFunction(arena, vector2InstanceType, {vector2InstanceType}, {vector2InstanceType}),
|
||||||
makeFunction(arena, vector2InstanceType, {getBuiltins()->numberType}, {vector2InstanceType}),
|
makeFunction(arena, vector2InstanceType, {getBuiltins()->numberType}, {vector2InstanceType}),
|
||||||
}})}}};
|
}})}}
|
||||||
|
};
|
||||||
globals.globalScope->exportedTypeBindings["Vector2"] = TypeFun{{}, vector2InstanceType};
|
globals.globalScope->exportedTypeBindings["Vector2"] = TypeFun{{}, vector2InstanceType};
|
||||||
addGlobalBinding(globals, "Vector2", vector2Type, "@test");
|
addGlobalBinding(globals, "Vector2", vector2Type, "@test");
|
||||||
|
|
||||||
|
|
|
@ -17,15 +17,12 @@ namespace Luau
|
||||||
std::string rep(const std::string& s, size_t n);
|
std::string rep(const std::string& s, size_t n);
|
||||||
}
|
}
|
||||||
|
|
||||||
LUAU_FASTFLAG(LuauCompileInlineNonConstInit)
|
|
||||||
LUAU_FASTINT(LuauCompileInlineDepth)
|
LUAU_FASTINT(LuauCompileInlineDepth)
|
||||||
LUAU_FASTINT(LuauCompileInlineThreshold)
|
LUAU_FASTINT(LuauCompileInlineThreshold)
|
||||||
LUAU_FASTINT(LuauCompileInlineThresholdMaxBoost)
|
LUAU_FASTINT(LuauCompileInlineThresholdMaxBoost)
|
||||||
LUAU_FASTINT(LuauCompileLoopUnrollThreshold)
|
LUAU_FASTINT(LuauCompileLoopUnrollThreshold)
|
||||||
LUAU_FASTINT(LuauCompileLoopUnrollThresholdMaxBoost)
|
LUAU_FASTINT(LuauCompileLoopUnrollThresholdMaxBoost)
|
||||||
LUAU_FASTINT(LuauRecursionLimit)
|
LUAU_FASTINT(LuauRecursionLimit)
|
||||||
LUAU_FASTFLAG(LuauCompileFixTypeFunctionSkip)
|
|
||||||
LUAU_FASTFLAG(LuauCompileCostModelConstants)
|
|
||||||
|
|
||||||
using namespace Luau;
|
using namespace Luau;
|
||||||
|
|
||||||
|
@ -2990,8 +2987,6 @@ TEST_CASE("TypeFunction")
|
||||||
|
|
||||||
TEST_CASE("NoTypeFunctionsInBytecode")
|
TEST_CASE("NoTypeFunctionsInBytecode")
|
||||||
{
|
{
|
||||||
ScopedFastFlag luauCompileFixTypeFunctionSkip{FFlag::LuauCompileFixTypeFunctionSkip, true};
|
|
||||||
|
|
||||||
Luau::BytecodeBuilder bcb;
|
Luau::BytecodeBuilder bcb;
|
||||||
bcb.setDumpFlags(Luau::BytecodeBuilder::Dump_Code);
|
bcb.setDumpFlags(Luau::BytecodeBuilder::Dump_Code);
|
||||||
Luau::compileOrThrow(bcb, R"(
|
Luau::compileOrThrow(bcb, R"(
|
||||||
|
@ -3616,8 +3611,6 @@ RETURN R4 1
|
||||||
|
|
||||||
TEST_CASE("CostModelRemarks")
|
TEST_CASE("CostModelRemarks")
|
||||||
{
|
{
|
||||||
ScopedFastFlag luauCompileCostModelConstants{FFlag::LuauCompileCostModelConstants, true};
|
|
||||||
|
|
||||||
CHECK_EQ(
|
CHECK_EQ(
|
||||||
compileWithRemarks(R"(
|
compileWithRemarks(R"(
|
||||||
local a, b = ...
|
local a, b = ...
|
||||||
|
@ -7624,8 +7617,6 @@ RETURN R1 1
|
||||||
|
|
||||||
TEST_CASE("InlineNonConstInitializers")
|
TEST_CASE("InlineNonConstInitializers")
|
||||||
{
|
{
|
||||||
ScopedFastFlag luauCompileInlineNonConstInit{FFlag::LuauCompileInlineNonConstInit, true};
|
|
||||||
|
|
||||||
CHECK_EQ(
|
CHECK_EQ(
|
||||||
"\n" + compileFunction(
|
"\n" + compileFunction(
|
||||||
R"(
|
R"(
|
||||||
|
@ -7655,8 +7646,6 @@ RETURN R0 0
|
||||||
|
|
||||||
TEST_CASE("InlineNonConstInitializers2")
|
TEST_CASE("InlineNonConstInitializers2")
|
||||||
{
|
{
|
||||||
ScopedFastFlag luauCompileInlineNonConstInit{FFlag::LuauCompileInlineNonConstInit, true};
|
|
||||||
|
|
||||||
CHECK_EQ(
|
CHECK_EQ(
|
||||||
"\n" + compileFunction(
|
"\n" + compileFunction(
|
||||||
R"(
|
R"(
|
||||||
|
|
|
@ -34,9 +34,13 @@ void luaC_validate(lua_State* L);
|
||||||
// internal functions, declared in lvm.h - not exposed via lua.h
|
// internal functions, declared in lvm.h - not exposed via lua.h
|
||||||
void luau_callhook(lua_State* L, lua_Hook hook, void* userdata);
|
void luau_callhook(lua_State* L, lua_Hook hook, void* userdata);
|
||||||
|
|
||||||
|
LUAU_FASTFLAG(LuauHeapDumpStringSizeOverhead)
|
||||||
LUAU_FASTFLAG(DebugLuauAbortingChecks)
|
LUAU_FASTFLAG(DebugLuauAbortingChecks)
|
||||||
LUAU_FASTINT(CodegenHeuristicsInstructionLimit)
|
LUAU_FASTINT(CodegenHeuristicsInstructionLimit)
|
||||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||||
|
LUAU_DYNAMIC_FASTFLAG(LuauErrorYield)
|
||||||
|
LUAU_DYNAMIC_FASTFLAG(LuauSafeStackCheck)
|
||||||
|
|
||||||
|
|
||||||
static lua_CompileOptions defaultOptions()
|
static lua_CompileOptions defaultOptions()
|
||||||
{
|
{
|
||||||
|
@ -754,6 +758,8 @@ TEST_CASE("Closure")
|
||||||
|
|
||||||
TEST_CASE("Calls")
|
TEST_CASE("Calls")
|
||||||
{
|
{
|
||||||
|
ScopedFastFlag luauSafeStackCheck{DFFlag::LuauSafeStackCheck, true};
|
||||||
|
|
||||||
runConformance("calls.luau");
|
runConformance("calls.luau");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -816,6 +822,8 @@ TEST_CASE("UTF8")
|
||||||
|
|
||||||
TEST_CASE("Coroutine")
|
TEST_CASE("Coroutine")
|
||||||
{
|
{
|
||||||
|
ScopedFastFlag luauErrorYield{DFFlag::LuauErrorYield, true};
|
||||||
|
|
||||||
runConformance("coroutine.luau");
|
runConformance("coroutine.luau");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2094,13 +2102,33 @@ int slowlyOverflowStack(lua_State* L)
|
||||||
|
|
||||||
TEST_CASE("ApiStack")
|
TEST_CASE("ApiStack")
|
||||||
{
|
{
|
||||||
StateRef globalState(luaL_newstate(), lua_close);
|
ScopedFastFlag luauSafeStackCheck{DFFlag::LuauSafeStackCheck, true};
|
||||||
lua_State* L = globalState.get();
|
|
||||||
|
StateRef globalState(lua_newstate(blockableRealloc, nullptr), lua_close);
|
||||||
|
lua_State* GL = globalState.get();
|
||||||
|
|
||||||
|
{
|
||||||
|
lua_State* L = lua_newthread(GL);
|
||||||
|
|
||||||
lua_pushcfunction(L, slowlyOverflowStack, "foo");
|
lua_pushcfunction(L, slowlyOverflowStack, "foo");
|
||||||
int result = lua_pcall(L, 0, 0, 0);
|
int result = lua_pcall(L, 0, 0, 0);
|
||||||
REQUIRE(result == LUA_ERRRUN);
|
REQUIRE(result == LUA_ERRRUN);
|
||||||
CHECK(strcmp(luaL_checkstring(L, -1), "stack overflow (test)") == 0);
|
CHECK(strcmp(luaL_checkstring(L, -1), "stack overflow (test)") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
lua_State* L = lua_newthread(GL);
|
||||||
|
|
||||||
|
REQUIRE(lua_checkstack(L, 100) == 1);
|
||||||
|
|
||||||
|
blockableReallocAllowed = false;
|
||||||
|
REQUIRE(lua_checkstack(L, 1000) == 0);
|
||||||
|
blockableReallocAllowed = true;
|
||||||
|
|
||||||
|
REQUIRE(lua_checkstack(L, 1000) == 1);
|
||||||
|
|
||||||
|
REQUIRE(lua_checkstack(L, LUAI_MAXCSTACK * 2) == 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("ApiAlloc")
|
TEST_CASE("ApiAlloc")
|
||||||
|
@ -2315,6 +2343,8 @@ TEST_CASE("StringConversion")
|
||||||
|
|
||||||
TEST_CASE("GCDump")
|
TEST_CASE("GCDump")
|
||||||
{
|
{
|
||||||
|
ScopedFastFlag luauHeapDumpStringSizeOverhead{FFlag::LuauHeapDumpStringSizeOverhead, true};
|
||||||
|
|
||||||
// internal function, declared in lgc.h - not exposed via lua.h
|
// internal function, declared in lgc.h - not exposed via lua.h
|
||||||
extern void luaC_dump(lua_State * L, void* file, const char* (*categoryName)(lua_State* L, uint8_t memcat));
|
extern void luaC_dump(lua_State * L, void* file, const char* (*categoryName)(lua_State* L, uint8_t memcat));
|
||||||
extern void luaC_enumheap(
|
extern void luaC_enumheap(
|
||||||
|
@ -2362,14 +2392,15 @@ local function f()
|
||||||
x[1] = math.abs(42)
|
x[1] = math.abs(42)
|
||||||
end
|
end
|
||||||
function foo()
|
function foo()
|
||||||
coroutine.yield()
|
x[2] = ''
|
||||||
|
for i = 1, 10000 do x[2] ..= '1234567890' end
|
||||||
end
|
end
|
||||||
foo()
|
foo()
|
||||||
return f
|
return f
|
||||||
)");
|
)");
|
||||||
lua_pushstring(CL, "=GCDump");
|
lua_pushstring(CL, "=GCDump");
|
||||||
lua_loadstring(CL);
|
REQUIRE(lua_loadstring(CL) == 1);
|
||||||
lua_resume(CL, nullptr, 0);
|
REQUIRE(lua_resume(CL, nullptr, 0) == LUA_OK);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
const char* path = "NUL";
|
const char* path = "NUL";
|
||||||
|
@ -2380,6 +2411,7 @@ return f
|
||||||
FILE* f = fopen(path, "w");
|
FILE* f = fopen(path, "w");
|
||||||
REQUIRE(f);
|
REQUIRE(f);
|
||||||
|
|
||||||
|
luaC_fullgc(L);
|
||||||
luaC_dump(L, f, nullptr);
|
luaC_dump(L, f, nullptr);
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
@ -2395,14 +2427,10 @@ return f
|
||||||
|
|
||||||
struct EnumContext
|
struct EnumContext
|
||||||
{
|
{
|
||||||
EnumContext()
|
Luau::DenseHashMap<void*, Node> nodes{nullptr};
|
||||||
: nodes{nullptr}
|
Luau::DenseHashMap<void*, void*> edges{nullptr};
|
||||||
, edges{nullptr}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Luau::DenseHashMap<void*, Node> nodes;
|
bool seenTargetString = false;
|
||||||
Luau::DenseHashMap<void*, void*> edges;
|
|
||||||
} ctx;
|
} ctx;
|
||||||
|
|
||||||
luaC_enumheap(
|
luaC_enumheap(
|
||||||
|
@ -2425,6 +2453,14 @@ return f
|
||||||
else if (tt == LUA_TTHREAD)
|
else if (tt == LUA_TTHREAD)
|
||||||
CHECK(sv == "thread at unnamed:1 =GCDump");
|
CHECK(sv == "thread at unnamed:1 =GCDump");
|
||||||
}
|
}
|
||||||
|
else if (tt == LUA_TSTRING && size >= 100000)
|
||||||
|
{
|
||||||
|
CHECK(!context.seenTargetString);
|
||||||
|
context.seenTargetString = true;
|
||||||
|
|
||||||
|
// The only string we have in this test that is 100000 characters long should include string data overhead
|
||||||
|
CHECK(size > 100000);
|
||||||
|
}
|
||||||
|
|
||||||
context.nodes[gco] = {gco, tt, memcat, size, name ? name : ""};
|
context.nodes[gco] = {gco, tt, memcat, size, name ? name : ""};
|
||||||
},
|
},
|
||||||
|
@ -2437,6 +2473,7 @@ return f
|
||||||
|
|
||||||
CHECK(!ctx.nodes.empty());
|
CHECK(!ctx.nodes.empty());
|
||||||
CHECK(!ctx.edges.empty());
|
CHECK(!ctx.edges.empty());
|
||||||
|
CHECK(ctx.seenTargetString);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Interrupt")
|
TEST_CASE("Interrupt")
|
||||||
|
@ -3296,6 +3333,7 @@ TEST_CASE("HugeFunctionLoadFailure")
|
||||||
REQUIRE_EQ(largeAllocationToFail, expectedTotalLargeAllocations);
|
REQUIRE_EQ(largeAllocationToFail, expectedTotalLargeAllocations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("IrInstructionLimit")
|
TEST_CASE("IrInstructionLimit")
|
||||||
{
|
{
|
||||||
if (!codegen || !luau_codegen_supported())
|
if (!codegen || !luau_codegen_supported())
|
||||||
|
|
|
@ -61,7 +61,8 @@ void ConstraintGeneratorFixture::solve(const std::string& code)
|
||||||
{},
|
{},
|
||||||
&logger,
|
&logger,
|
||||||
NotNull{dfg.get()},
|
NotNull{dfg.get()},
|
||||||
{}};
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
cs.run();
|
cs.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
|
|
||||||
#include "doctest.h"
|
#include "doctest.h"
|
||||||
|
|
||||||
LUAU_FASTFLAG(LuauCompileCostModelConstants)
|
|
||||||
|
|
||||||
using namespace Luau;
|
using namespace Luau;
|
||||||
|
|
||||||
namespace Luau
|
namespace Luau
|
||||||
|
@ -133,37 +131,6 @@ end
|
||||||
CHECK_EQ(5, Luau::Compile::computeCost(model, args2, 1));
|
CHECK_EQ(5, Luau::Compile::computeCost(model, args2, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("ControlFlow")
|
|
||||||
{
|
|
||||||
ScopedFastFlag luauCompileCostModelConstants{FFlag::LuauCompileCostModelConstants, false};
|
|
||||||
|
|
||||||
uint64_t model = modelFunction(R"(
|
|
||||||
function test(a)
|
|
||||||
while a < 0 do
|
|
||||||
a += 1
|
|
||||||
end
|
|
||||||
for i=10,1,-1 do
|
|
||||||
a += 1
|
|
||||||
end
|
|
||||||
for i in pairs({}) do
|
|
||||||
a += 1
|
|
||||||
if a % 2 == 0 then continue end
|
|
||||||
end
|
|
||||||
repeat
|
|
||||||
a += 1
|
|
||||||
if a % 2 == 0 then break end
|
|
||||||
until a > 10
|
|
||||||
return a
|
|
||||||
end
|
|
||||||
)");
|
|
||||||
|
|
||||||
const bool args1[] = {false};
|
|
||||||
const bool args2[] = {true};
|
|
||||||
|
|
||||||
CHECK_EQ(76, Luau::Compile::computeCost(model, args1, 1));
|
|
||||||
CHECK_EQ(73, Luau::Compile::computeCost(model, args2, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Conditional")
|
TEST_CASE("Conditional")
|
||||||
{
|
{
|
||||||
uint64_t model = modelFunction(R"(
|
uint64_t model = modelFunction(R"(
|
||||||
|
|
|
@ -135,7 +135,9 @@ TEST_CASE_FIXTURE(ESFixture, "string | never")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(ESFixture, "string | never | number")
|
TEST_CASE_FIXTURE(ESFixture, "string | never | number")
|
||||||
{
|
{
|
||||||
CHECK("number | string" == simplifyStr(arena->addType(UnionType{{getBuiltins()->stringType, getBuiltins()->neverType, getBuiltins()->numberType}})));
|
CHECK(
|
||||||
|
"number | string" == simplifyStr(arena->addType(UnionType{{getBuiltins()->stringType, getBuiltins()->neverType, getBuiltins()->numberType}}))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(ESFixture, "string & string")
|
TEST_CASE_FIXTURE(ESFixture, "string & string")
|
||||||
|
@ -161,9 +163,9 @@ TEST_CASE_FIXTURE(ESFixture, "never & string")
|
||||||
TEST_CASE_FIXTURE(ESFixture, "string & (unknown | never)")
|
TEST_CASE_FIXTURE(ESFixture, "string & (unknown | never)")
|
||||||
{
|
{
|
||||||
CHECK(
|
CHECK(
|
||||||
"string" == simplifyStr(arena->addType(
|
"string" == simplifyStr(arena->addType(IntersectionType{
|
||||||
IntersectionType{{getBuiltins()->stringType, arena->addType(UnionType{{getBuiltins()->unknownType, getBuiltins()->neverType}})}}
|
{getBuiltins()->stringType, arena->addType(UnionType{{getBuiltins()->unknownType, getBuiltins()->neverType}})}
|
||||||
))
|
}))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,7 +388,8 @@ TEST_CASE_FIXTURE(ESFixture, "union<number, number>")
|
||||||
{
|
{
|
||||||
CHECK(
|
CHECK(
|
||||||
"number" ==
|
"number" ==
|
||||||
simplifyStr(arena->addType(TypeFunctionInstanceType{builtinTypeFunctions().unionFunc, {getBuiltins()->numberType, getBuiltins()->numberType}}))
|
simplifyStr(arena->addType(TypeFunctionInstanceType{builtinTypeFunctions().unionFunc, {getBuiltins()->numberType, getBuiltins()->numberType}})
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,9 +421,9 @@ TEST_CASE_FIXTURE(ESFixture, "blocked & ~number & function")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(ESFixture, "(number | boolean | string | nil | table) & (false | nil)")
|
TEST_CASE_FIXTURE(ESFixture, "(number | boolean | string | nil | table) & (false | nil)")
|
||||||
{
|
{
|
||||||
const TypeId t1 = arena->addType(
|
const TypeId t1 = arena->addType(UnionType{
|
||||||
UnionType{{getBuiltins()->numberType, getBuiltins()->booleanType, getBuiltins()->stringType, getBuiltins()->nilType, getBuiltins()->tableType}}
|
{getBuiltins()->numberType, getBuiltins()->booleanType, getBuiltins()->stringType, getBuiltins()->nilType, getBuiltins()->tableType}
|
||||||
);
|
});
|
||||||
|
|
||||||
CHECK("false?" == simplifyStr(arena->addType(IntersectionType{{t1, getBuiltins()->falsyType}})));
|
CHECK("false?" == simplifyStr(arena->addType(IntersectionType{{t1, getBuiltins()->falsyType}})));
|
||||||
}
|
}
|
||||||
|
@ -689,7 +692,8 @@ TEST_CASE_FIXTURE(ESFixture, "lt<number, _> == boolean")
|
||||||
TEST_CASE_FIXTURE(ESFixture, "unknown & ~string")
|
TEST_CASE_FIXTURE(ESFixture, "unknown & ~string")
|
||||||
{
|
{
|
||||||
CHECK_EQ(
|
CHECK_EQ(
|
||||||
"~string", simplifyStr(arena->addType(IntersectionType{{getBuiltins()->unknownType, arena->addType(NegationType{getBuiltins()->stringType})}}))
|
"~string",
|
||||||
|
simplifyStr(arena->addType(IntersectionType{{getBuiltins()->unknownType, arena->addType(NegationType{getBuiltins()->stringType})}}))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -696,7 +696,8 @@ Frontend& Fixture::getFrontend()
|
||||||
&fileResolver,
|
&fileResolver,
|
||||||
&configResolver,
|
&configResolver,
|
||||||
FrontendOptions{
|
FrontendOptions{
|
||||||
/* retainFullTypeGraphs= */ true, /* forAutocomplete */ false, /* runLintChecks */ false, /* randomConstraintResolutionSeed */ randomSeed}
|
/* retainFullTypeGraphs= */ true, /* forAutocomplete */ false, /* runLintChecks */ false, /* randomConstraintResolutionSeed */ randomSeed
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
builtinTypes = f.builtinTypes;
|
builtinTypes = f.builtinTypes;
|
||||||
|
@ -732,7 +733,6 @@ Frontend& Fixture::getFrontend()
|
||||||
BuiltinsFixture::BuiltinsFixture(bool prepareAutocomplete)
|
BuiltinsFixture::BuiltinsFixture(bool prepareAutocomplete)
|
||||||
: Fixture(prepareAutocomplete)
|
: Fixture(prepareAutocomplete)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Frontend& BuiltinsFixture::getFrontend()
|
Frontend& BuiltinsFixture::getFrontend()
|
||||||
|
|
|
@ -185,8 +185,10 @@ struct Fixture
|
||||||
// TODO: test theory about dynamic dispatch
|
// TODO: test theory about dynamic dispatch
|
||||||
NotNull<BuiltinTypes> getBuiltins();
|
NotNull<BuiltinTypes> getBuiltins();
|
||||||
virtual Frontend& getFrontend();
|
virtual Frontend& getFrontend();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool hasDumpedErrors = false;
|
bool hasDumpedErrors = false;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool forAutocomplete = false;
|
bool forAutocomplete = false;
|
||||||
std::optional<Frontend> frontend;
|
std::optional<Frontend> frontend;
|
||||||
|
|
|
@ -238,7 +238,7 @@ struct FragmentAutocompleteFixtureImpl : BaseType
|
||||||
ParseResult parseResult = parseHelper(document);
|
ParseResult parseResult = parseHelper(document);
|
||||||
FrontendOptions options;
|
FrontendOptions options;
|
||||||
FragmentContext context{document, parseResult, options, fragmentEndPosition};
|
FragmentContext context{document, parseResult, options, fragmentEndPosition};
|
||||||
return Luau::tryFragmentAutocomplete(this->getFrontend(). module, cursorPos, context, nullCallback);
|
return Luau::tryFragmentAutocomplete(this->getFrontend().module, cursorPos, context, nullCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceModule& getSource()
|
SourceModule& getSource()
|
||||||
|
@ -3792,11 +3792,17 @@ if result.type == "ok" then
|
||||||
result.
|
result.
|
||||||
end
|
end
|
||||||
)";
|
)";
|
||||||
autocompleteFragmentInOldSolver(source, dest, Position{8, 11}, [](auto& result){
|
autocompleteFragmentInOldSolver(
|
||||||
|
source,
|
||||||
|
dest,
|
||||||
|
Position{8, 11},
|
||||||
|
[](auto& result)
|
||||||
|
{
|
||||||
REQUIRE(result.result);
|
REQUIRE(result.result);
|
||||||
CHECK_EQ(result.result->acResults.entryMap.count("type"), 1);
|
CHECK_EQ(result.result->acResults.entryMap.count("type"), 1);
|
||||||
CHECK_EQ(result.result->acResults.entryMap.count("value"), 1);
|
CHECK_EQ(result.result->acResults.entryMap.count("value"), 1);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "tagged_union_completion_second_branch_of_union_old_solver")
|
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "tagged_union_completion_second_branch_of_union_old_solver")
|
||||||
|
@ -3825,11 +3831,17 @@ if result.type == "err" then
|
||||||
end
|
end
|
||||||
)";
|
)";
|
||||||
|
|
||||||
autocompleteFragmentInOldSolver(source, dest, Position{8, 11}, [](auto& result){
|
autocompleteFragmentInOldSolver(
|
||||||
|
source,
|
||||||
|
dest,
|
||||||
|
Position{8, 11},
|
||||||
|
[](auto& result)
|
||||||
|
{
|
||||||
REQUIRE(result.result);
|
REQUIRE(result.result);
|
||||||
CHECK_EQ(result.result->acResults.entryMap.count("type"), 1);
|
CHECK_EQ(result.result->acResults.entryMap.count("type"), 1);
|
||||||
CHECK_EQ(result.result->acResults.entryMap.count("error"), 1);
|
CHECK_EQ(result.result->acResults.entryMap.count("error"), 1);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "tagged_union_completion_first_branch_of_union_new_solver")
|
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "tagged_union_completion_first_branch_of_union_new_solver")
|
||||||
|
@ -3858,11 +3870,17 @@ if result.type == "ok" then
|
||||||
result.
|
result.
|
||||||
end
|
end
|
||||||
)";
|
)";
|
||||||
autocompleteFragmentInNewSolver(source, dest, Position{8, 11}, [](auto& result){
|
autocompleteFragmentInNewSolver(
|
||||||
|
source,
|
||||||
|
dest,
|
||||||
|
Position{8, 11},
|
||||||
|
[](auto& result)
|
||||||
|
{
|
||||||
REQUIRE(result.result);
|
REQUIRE(result.result);
|
||||||
CHECK_EQ(result.result->acResults.entryMap.count("type"), 1);
|
CHECK_EQ(result.result->acResults.entryMap.count("type"), 1);
|
||||||
CHECK_EQ(result.result->acResults.entryMap.count("value"), 1);
|
CHECK_EQ(result.result->acResults.entryMap.count("value"), 1);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "tagged_union_completion_second_branch_of_union_new_solver")
|
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "tagged_union_completion_second_branch_of_union_new_solver")
|
||||||
|
@ -3891,11 +3909,17 @@ if result.type == "err" then
|
||||||
end
|
end
|
||||||
)";
|
)";
|
||||||
|
|
||||||
autocompleteFragmentInNewSolver(source, dest, Position{8, 11}, [](auto& result){
|
autocompleteFragmentInNewSolver(
|
||||||
|
source,
|
||||||
|
dest,
|
||||||
|
Position{8, 11},
|
||||||
|
[](auto& result)
|
||||||
|
{
|
||||||
REQUIRE(result.result);
|
REQUIRE(result.result);
|
||||||
CHECK_EQ(result.result->acResults.entryMap.count("type"), 1);
|
CHECK_EQ(result.result->acResults.entryMap.count("type"), 1);
|
||||||
CHECK_EQ(result.result->acResults.entryMap.count("error"), 1);
|
CHECK_EQ(result.result->acResults.entryMap.count("error"), 1);
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "inline_prop_read_on_requires_provides_results")
|
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "inline_prop_read_on_requires_provides_results")
|
||||||
|
|
|
@ -623,7 +623,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "produce_errors_for_unchanged_file_with_error
|
||||||
|
|
||||||
getFrontend().check("Modules/A");
|
getFrontend().check("Modules/A");
|
||||||
|
|
||||||
fileResolver.source["Modules/A"] = "local p = 4 -- We have fixed the problem, but we didn't tell the getFrontend(). so it will not recheck this file!";
|
fileResolver.source["Modules/A"] =
|
||||||
|
"local p = 4 -- We have fixed the problem, but we didn't tell the getFrontend(). so it will not recheck this file!";
|
||||||
CheckResult secondResult = getFrontend().check("Modules/A");
|
CheckResult secondResult = getFrontend().check("Modules/A");
|
||||||
|
|
||||||
CHECK_EQ(1, secondResult.errors.size());
|
CHECK_EQ(1, secondResult.errors.size());
|
||||||
|
|
|
@ -201,7 +201,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_point_into_globalTypes_arena")
|
||||||
TableType* exportsTable = getMutable<TableType>(*exports);
|
TableType* exportsTable = getMutable<TableType>(*exports);
|
||||||
REQUIRE(exportsTable != nullptr);
|
REQUIRE(exportsTable != nullptr);
|
||||||
|
|
||||||
TypeId signType = FFlag::LuauRemoveTypeCallsForReadWriteProps ? *exportsTable->props["sign"].readTy : exportsTable->props["sign"].type_DEPRECATED();
|
TypeId signType =
|
||||||
|
FFlag::LuauRemoveTypeCallsForReadWriteProps ? *exportsTable->props["sign"].readTy : exportsTable->props["sign"].type_DEPRECATED();
|
||||||
REQUIRE(signType != nullptr);
|
REQUIRE(signType != nullptr);
|
||||||
|
|
||||||
CHECK(!isInArena(signType, module->interfaceTypes));
|
CHECK(!isInArena(signType, module->interfaceTypes));
|
||||||
|
|
|
@ -206,7 +206,9 @@ TEST_CASE_FIXTURE(Fixture, "inline_table_props_are_also_any")
|
||||||
|
|
||||||
CHECK_EQ(*getBuiltins()->anyType, *ttv->props["one"].type_DEPRECATED());
|
CHECK_EQ(*getBuiltins()->anyType, *ttv->props["one"].type_DEPRECATED());
|
||||||
CHECK_EQ(*getBuiltins()->anyType, *ttv->props["two"].type_DEPRECATED());
|
CHECK_EQ(*getBuiltins()->anyType, *ttv->props["two"].type_DEPRECATED());
|
||||||
CHECK_MESSAGE(get<FunctionType>(follow(ttv->props["three"].type_DEPRECATED())), "Should be a function: " << *ttv->props["three"].type_DEPRECATED());
|
CHECK_MESSAGE(
|
||||||
|
get<FunctionType>(follow(ttv->props["three"].type_DEPRECATED())), "Should be a function: " << *ttv->props["three"].type_DEPRECATED()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_iterator_variables_are_any")
|
TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_iterator_variables_are_any")
|
||||||
|
|
|
@ -16,7 +16,7 @@ LUAU_FASTINT(LuauNormalizeIntersectionLimit)
|
||||||
LUAU_FASTINT(LuauNormalizeUnionLimit)
|
LUAU_FASTINT(LuauNormalizeUnionLimit)
|
||||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
||||||
LUAU_FASTFLAG(LuauNormalizationReorderFreeTypeIntersect)
|
LUAU_FASTFLAG(LuauNormalizationReorderFreeTypeIntersect)
|
||||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
using namespace Luau;
|
using namespace Luau;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -1223,7 +1223,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_union_type_pack_cycle")
|
||||||
ScopedFastFlag sff[] = {
|
ScopedFastFlag sff[] = {
|
||||||
{FFlag::LuauSolverV2, true},
|
{FFlag::LuauSolverV2, true},
|
||||||
{FFlag::LuauSimplifyOutOfLine2, true},
|
{FFlag::LuauSimplifyOutOfLine2, true},
|
||||||
{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true},
|
{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true},
|
||||||
};
|
};
|
||||||
ScopedFastInt sfi{FInt::LuauTypeInferRecursionLimit, 0};
|
ScopedFastInt sfi{FInt::LuauTypeInferRecursionLimit, 0};
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@ LUAU_FASTINT(LuauTypeLengthLimit)
|
||||||
LUAU_FASTINT(LuauParseErrorLimit)
|
LUAU_FASTINT(LuauParseErrorLimit)
|
||||||
LUAU_FASTFLAG(LuauSolverV2)
|
LUAU_FASTFLAG(LuauSolverV2)
|
||||||
LUAU_FASTFLAG(LuauParseStringIndexer)
|
LUAU_FASTFLAG(LuauParseStringIndexer)
|
||||||
LUAU_FASTFLAG(LuauDeclareExternType)
|
|
||||||
LUAU_DYNAMIC_FASTFLAG(DebugLuauReportReturnTypeVariadicWithTypeSuffix)
|
LUAU_DYNAMIC_FASTFLAG(DebugLuauReportReturnTypeVariadicWithTypeSuffix)
|
||||||
|
|
||||||
// Clip with DebugLuauReportReturnTypeVariadicWithTypeSuffix
|
// Clip with DebugLuauReportReturnTypeVariadicWithTypeSuffix
|
||||||
|
@ -1999,8 +1998,6 @@ TEST_CASE_FIXTURE(Fixture, "parse_class_declarations")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations")
|
TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations")
|
||||||
{
|
{
|
||||||
ScopedFastFlag sff{FFlag::LuauDeclareExternType, true};
|
|
||||||
|
|
||||||
AstStatBlock* stat = parseEx(R"(
|
AstStatBlock* stat = parseEx(R"(
|
||||||
declare extern type Foo with
|
declare extern type Foo with
|
||||||
prop: number
|
prop: number
|
||||||
|
@ -2051,8 +2048,6 @@ TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations_missing_with")
|
TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations_missing_with")
|
||||||
{
|
{
|
||||||
ScopedFastFlag sff{FFlag::LuauDeclareExternType, true};
|
|
||||||
|
|
||||||
ParseResult result = tryParse(R"(
|
ParseResult result = tryParse(R"(
|
||||||
declare extern type Foo
|
declare extern type Foo
|
||||||
prop: number
|
prop: number
|
||||||
|
@ -2108,8 +2103,6 @@ TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations_missing_with")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations")
|
TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations")
|
||||||
{
|
{
|
||||||
ScopedFastFlag sff{FFlag::LuauDeclareExternType, true};
|
|
||||||
|
|
||||||
AstStatBlock* stat = parseEx(R"(
|
AstStatBlock* stat = parseEx(R"(
|
||||||
declare extern type Foo with
|
declare extern type Foo with
|
||||||
prop: number
|
prop: number
|
||||||
|
@ -2160,8 +2153,6 @@ TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations_missing_with")
|
TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations_missing_with")
|
||||||
{
|
{
|
||||||
ScopedFastFlag sff{FFlag::LuauDeclareExternType, true};
|
|
||||||
|
|
||||||
ParseResult result = tryParse(R"(
|
ParseResult result = tryParse(R"(
|
||||||
declare extern type Foo
|
declare extern type Foo
|
||||||
prop: number
|
prop: number
|
||||||
|
@ -2281,7 +2272,7 @@ TEST_CASE_FIXTURE(Fixture, "class_indexer")
|
||||||
[number]: number
|
[number]: number
|
||||||
end
|
end
|
||||||
)",
|
)",
|
||||||
(FFlag::LuauDeclareExternType) ? "Cannot have more than one indexer on an extern type" : "Cannot have more than one class indexer"
|
"Cannot have more than one indexer on an extern type"
|
||||||
);
|
);
|
||||||
|
|
||||||
REQUIRE_EQ(1, p1.root->body.size);
|
REQUIRE_EQ(1, p1.root->body.size);
|
||||||
|
|
|
@ -19,6 +19,9 @@ using namespace Luau;
|
||||||
|
|
||||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||||
LUAU_FASTFLAG(LuauSolverV2)
|
LUAU_FASTFLAG(LuauSolverV2)
|
||||||
|
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||||
|
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||||
|
LUAU_FASTFLAG(LuauSimplifyAnyAndUnion)
|
||||||
|
|
||||||
struct LimitFixture : BuiltinsFixture
|
struct LimitFixture : BuiltinsFixture
|
||||||
{
|
{
|
||||||
|
@ -47,7 +50,7 @@ TEST_CASE_FIXTURE(LimitFixture, "typescript_port_of_Result_type")
|
||||||
{
|
{
|
||||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||||
|
|
||||||
constexpr const char* src = R"LUA(
|
constexpr const char* src = R"LUAU(
|
||||||
--!strict
|
--!strict
|
||||||
|
|
||||||
-- Big thanks to Dionysusnu by letting us use this code as part of our test suite!
|
-- Big thanks to Dionysusnu by letting us use this code as part of our test suite!
|
||||||
|
@ -272,11 +275,62 @@ TEST_CASE_FIXTURE(LimitFixture, "typescript_port_of_Result_type")
|
||||||
return {
|
return {
|
||||||
Result = Result,
|
Result = Result,
|
||||||
}
|
}
|
||||||
)LUA";
|
)LUAU";
|
||||||
|
|
||||||
CheckResult result = check(src);
|
CheckResult result = check(src);
|
||||||
|
|
||||||
CHECK(hasError<CodeTooComplex>(result));
|
CHECK(hasError<CodeTooComplex>(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_FIXTURE(LimitFixture, "Signal_exerpt" * doctest::timeout(0.5))
|
||||||
|
{
|
||||||
|
ScopedFastFlag sff[] = {
|
||||||
|
// These flags are required to surface the problem.
|
||||||
|
{FFlag::LuauSolverV2, true},
|
||||||
|
{FFlag::LuauEagerGeneralization4, true},
|
||||||
|
{FFlag::LuauPushFunctionTypesInFunctionStatement, true},
|
||||||
|
|
||||||
|
// And this flag is the one that fixes it.
|
||||||
|
{FFlag::LuauSimplifyAnyAndUnion, true},
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const char* src = R"LUAU(
|
||||||
|
local Signal = {}
|
||||||
|
Signal.ClassName = "Signal"
|
||||||
|
export type Signal<T...> = typeof(setmetatable(
|
||||||
|
{} :: {},
|
||||||
|
{} :: typeof({ __index = Signal })
|
||||||
|
))
|
||||||
|
function Signal.new<T...>(): Signal<T...>
|
||||||
|
return nil :: any
|
||||||
|
end
|
||||||
|
|
||||||
|
function Signal.Connect<T...>(self: Signal<T...>)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Signal.DisconnectAll<T...>(self: Signal<T...>): ()
|
||||||
|
self._handlerListHead = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Signal.Fire<T...>(self: Signal<T...>): ()
|
||||||
|
local connection
|
||||||
|
rawget(connection, "_signal")
|
||||||
|
end
|
||||||
|
|
||||||
|
function Signal.Wait<T...>(self: Signal<T...>)
|
||||||
|
connection = self:Connect(function()
|
||||||
|
connection:Disconnect()
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Signal.Once<T...>(self: Signal<T...>, fn: SignalHandler<T...>): Connection<T...>
|
||||||
|
connection = self:Connect(function() end)
|
||||||
|
end
|
||||||
|
)LUAU";
|
||||||
|
|
||||||
|
CheckResult result = check(src);
|
||||||
|
|
||||||
|
(void)result;
|
||||||
|
}
|
||||||
|
|
||||||
TEST_SUITE_END();
|
TEST_SUITE_END();
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
using namespace Luau;
|
using namespace Luau;
|
||||||
|
|
||||||
LUAU_FASTFLAG(LuauSolverV2)
|
LUAU_FASTFLAG(LuauSolverV2)
|
||||||
|
LUAU_FASTFLAG(LuauSimplifyAnyAndUnion)
|
||||||
LUAU_DYNAMIC_FASTINT(LuauSimplificationComplexityLimit)
|
LUAU_DYNAMIC_FASTINT(LuauSimplificationComplexityLimit)
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -62,6 +63,7 @@ struct SimplifyFixture : Fixture
|
||||||
TypeId anotherChildClassTy = nullptr;
|
TypeId anotherChildClassTy = nullptr;
|
||||||
TypeId unrelatedClassTy = nullptr;
|
TypeId unrelatedClassTy = nullptr;
|
||||||
|
|
||||||
|
// This only affects type stringification.
|
||||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||||
|
|
||||||
SimplifyFixture()
|
SimplifyFixture()
|
||||||
|
@ -619,4 +621,26 @@ TEST_CASE_FIXTURE(SimplifyFixture, "cyclic_never_union_and_string")
|
||||||
CHECK(getBuiltins()->stringType == union_(leftType, getBuiltins()->stringType));
|
CHECK(getBuiltins()->stringType == union_(leftType, getBuiltins()->stringType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_FIXTURE(SimplifyFixture, "any & (error | string)")
|
||||||
|
{
|
||||||
|
ScopedFastFlag sff{FFlag::LuauSimplifyAnyAndUnion, true};
|
||||||
|
|
||||||
|
TypeId errStringTy = arena->addType(UnionType{{getBuiltins()->errorType, getBuiltins()->stringType}});
|
||||||
|
|
||||||
|
auto res = intersect(builtinTypes->anyType, errStringTy);
|
||||||
|
|
||||||
|
CHECK("*error-type* | string" == toString(res));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_FIXTURE(SimplifyFixture, "(error | string) & any")
|
||||||
|
{
|
||||||
|
ScopedFastFlag sff{FFlag::LuauSimplifyAnyAndUnion, true};
|
||||||
|
|
||||||
|
TypeId errStringTy = arena->addType(UnionType{{getBuiltins()->errorType, getBuiltins()->stringType}});
|
||||||
|
|
||||||
|
auto res = intersect(errStringTy, builtinTypes->anyType);
|
||||||
|
|
||||||
|
CHECK("*error-type* | string" == toString(res));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_SUITE_END();
|
TEST_SUITE_END();
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
LUAU_FASTFLAG(LuauSolverV2)
|
LUAU_FASTFLAG(LuauSolverV2)
|
||||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
|
|
||||||
using namespace Luau;
|
using namespace Luau;
|
||||||
|
|
||||||
|
@ -1240,11 +1240,19 @@ TEST_CASE_FIXTURE(SubtypeFixture, "(...unknown) -> () <: <T>(T...) -> ()")
|
||||||
TEST_CASE_FIXTURE(SubtypeFixture, "bill")
|
TEST_CASE_FIXTURE(SubtypeFixture, "bill")
|
||||||
{
|
{
|
||||||
TypeId a = arena.addType(TableType{
|
TypeId a = arena.addType(TableType{
|
||||||
{{"a", getBuiltins()->stringType}}, TableIndexer{getBuiltins()->stringType, getBuiltins()->numberType}, TypeLevel{}, nullptr, TableState::Sealed
|
{{"a", getBuiltins()->stringType}},
|
||||||
|
TableIndexer{getBuiltins()->stringType, getBuiltins()->numberType},
|
||||||
|
TypeLevel{},
|
||||||
|
nullptr,
|
||||||
|
TableState::Sealed
|
||||||
});
|
});
|
||||||
|
|
||||||
TypeId b = arena.addType(TableType{
|
TypeId b = arena.addType(TableType{
|
||||||
{{"a", getBuiltins()->stringType}}, TableIndexer{getBuiltins()->stringType, getBuiltins()->numberType}, TypeLevel{}, nullptr, TableState::Sealed
|
{{"a", getBuiltins()->stringType}},
|
||||||
|
TableIndexer{getBuiltins()->stringType, getBuiltins()->numberType},
|
||||||
|
TypeLevel{},
|
||||||
|
nullptr,
|
||||||
|
TableState::Sealed
|
||||||
});
|
});
|
||||||
|
|
||||||
CHECK(isSubtype(a, b).isSubtype);
|
CHECK(isSubtype(a, b).isSubtype);
|
||||||
|
@ -1387,7 +1395,7 @@ TEST_CASE_FIXTURE(SubtypeFixture, "<T>({ x: T }) -> T <: ({ method: <T>({ x: T }
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(SubtypeFixture, "subtyping_reasonings_to_follow_a_reduced_type_function_instance")
|
TEST_CASE_FIXTURE(SubtypeFixture, "subtyping_reasonings_to_follow_a_reduced_type_function_instance")
|
||||||
{
|
{
|
||||||
ScopedFastFlag sff{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true};
|
ScopedFastFlag sff{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||||
|
|
||||||
TypeId longTy = arena.addType(UnionType{
|
TypeId longTy = arena.addType(UnionType{
|
||||||
{getBuiltins()->booleanType,
|
{getBuiltins()->booleanType,
|
||||||
|
@ -1631,8 +1639,8 @@ TEST_CASE_FIXTURE(SubtypeFixture, "substitute_a_generic_for_a_negation")
|
||||||
TypeId bTy = arena.addType(GenericType{"B"});
|
TypeId bTy = arena.addType(GenericType{"B"});
|
||||||
getMutable<GenericType>(bTy)->scope = moduleScope.get();
|
getMutable<GenericType>(bTy)->scope = moduleScope.get();
|
||||||
|
|
||||||
TypeId genericFunctionTy =
|
TypeId genericFunctionTy = arena.addType(
|
||||||
arena.addType(FunctionType{{aTy, bTy}, {}, arena.addTypePack({aTy, bTy}), arena.addTypePack({join(meet(aTy, getBuiltins()->truthyType), bTy)})}
|
FunctionType{{aTy, bTy}, {}, arena.addTypePack({aTy, bTy}), arena.addTypePack({join(meet(aTy, getBuiltins()->truthyType), bTy)})}
|
||||||
);
|
);
|
||||||
|
|
||||||
const TypeId truthyTy = getBuiltins()->truthyType;
|
const TypeId truthyTy = getBuiltins()->truthyType;
|
||||||
|
|
|
@ -61,7 +61,8 @@ TEST_CASE_FIXTURE(Fixture, "free_types_stringify_the_same_regardless_of_solver")
|
||||||
{
|
{
|
||||||
ScopedFastFlag sff{FFlag::LuauSolverAgnosticStringification, true};
|
ScopedFastFlag sff{FFlag::LuauSolverAgnosticStringification, true};
|
||||||
TypeArena a;
|
TypeArena a;
|
||||||
TypeId t = a.addType(FreeType{getFrontend().globals.globalScope.get(), getFrontend().builtinTypes->neverType, getFrontend().builtinTypes->unknownType});
|
TypeId t =
|
||||||
|
a.addType(FreeType{getFrontend().globals.globalScope.get(), getFrontend().builtinTypes->neverType, getFrontend().builtinTypes->unknownType});
|
||||||
|
|
||||||
CHECK_EQ("'a", toString(t));
|
CHECK_EQ("'a", toString(t));
|
||||||
}
|
}
|
||||||
|
|
|
@ -744,10 +744,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_oss_crash_gh1161")
|
||||||
if (!FFlag::LuauSolverV2)
|
if (!FFlag::LuauSolverV2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ScopedFastFlag sff[] = {
|
ScopedFastFlag sff[] = {{FFlag::LuauEagerGeneralization4, true}, {FFlag::LuauStuckTypeFunctionsStillDispatch, true}};
|
||||||
{FFlag::LuauEagerGeneralization4, true},
|
|
||||||
{FFlag::LuauStuckTypeFunctionsStillDispatch, true}
|
|
||||||
};
|
|
||||||
|
|
||||||
CheckResult result = check(R"(
|
CheckResult result = check(R"(
|
||||||
local EnumVariants = {
|
local EnumVariants = {
|
||||||
|
@ -1787,7 +1784,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_should_not_assert_on_empty_string_prop
|
||||||
LUAU_REQUIRE_NO_ERRORS(results);
|
LUAU_REQUIRE_NO_ERRORS(results);
|
||||||
CHECK_EQ(R"("" | "one")", toString(requireTypeAlias("FoobarKeys")));
|
CHECK_EQ(R"("" | "one")", toString(requireTypeAlias("FoobarKeys")));
|
||||||
CHECK_EQ(R"("" | "two")", toString(requireTypeAlias("TableKeys")));
|
CHECK_EQ(R"("" | "two")", toString(requireTypeAlias("TableKeys")));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TFFixture
|
struct TFFixture
|
||||||
|
@ -1796,7 +1792,10 @@ struct TFFixture
|
||||||
NotNull<TypeArena> arena{&arena_};
|
NotNull<TypeArena> arena{&arena_};
|
||||||
|
|
||||||
BuiltinTypes builtinTypes_;
|
BuiltinTypes builtinTypes_;
|
||||||
NotNull<BuiltinTypes> getBuiltins(){ return NotNull{&builtinTypes_};}
|
NotNull<BuiltinTypes> getBuiltins()
|
||||||
|
{
|
||||||
|
return NotNull{&builtinTypes_};
|
||||||
|
}
|
||||||
|
|
||||||
ScopePtr globalScope = std::make_shared<Scope>(getBuiltins()->anyTypePack);
|
ScopePtr globalScope = std::make_shared<Scope>(getBuiltins()->anyTypePack);
|
||||||
|
|
||||||
|
|
|
@ -2417,10 +2417,7 @@ local function ok(idx: get<>): number return idx end
|
||||||
)");
|
)");
|
||||||
|
|
||||||
LUAU_REQUIRE_ERROR_COUNT(4, result);
|
LUAU_REQUIRE_ERROR_COUNT(4, result);
|
||||||
CHECK(
|
CHECK(toString(result.errors[1]) == R"(Type function instance get<> is uninhabited)");
|
||||||
toString(result.errors[1]) ==
|
|
||||||
R"(Type function instance get<> is uninhabited)"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_unreferenced_do_not_block")
|
TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_unreferenced_do_not_block")
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
using namespace Luau;
|
using namespace Luau;
|
||||||
|
|
||||||
LUAU_FASTFLAG(LuauSolverV2)
|
LUAU_FASTFLAG(LuauSolverV2)
|
||||||
LUAU_FASTFLAG(LuauGuardAgainstMalformedTypeAliasExpansion2)
|
|
||||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||||
|
|
||||||
TEST_SUITE_BEGIN("TypeAliases");
|
TEST_SUITE_BEGIN("TypeAliases");
|
||||||
|
@ -1244,8 +1243,6 @@ TEST_CASE_FIXTURE(Fixture, "exported_type_function_location_is_accessible_on_mod
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "fuzzer_cursed_type_aliases")
|
TEST_CASE_FIXTURE(Fixture, "fuzzer_cursed_type_aliases")
|
||||||
{
|
{
|
||||||
ScopedFastFlag _{FFlag::LuauGuardAgainstMalformedTypeAliasExpansion2, true};
|
|
||||||
|
|
||||||
// This used to crash under the new solver: we would like this to continue
|
// This used to crash under the new solver: we would like this to continue
|
||||||
// to not crash.
|
// to not crash.
|
||||||
LUAU_REQUIRE_ERRORS(check(R"(
|
LUAU_REQUIRE_ERRORS(check(R"(
|
||||||
|
@ -1282,8 +1279,6 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_dont_crash_on_duplicate_with_typeof")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "fuzzer_more_cursed_aliases")
|
TEST_CASE_FIXTURE(Fixture, "fuzzer_more_cursed_aliases")
|
||||||
{
|
{
|
||||||
ScopedFastFlag _{FFlag::LuauGuardAgainstMalformedTypeAliasExpansion2, true};
|
|
||||||
|
|
||||||
LUAU_REQUIRE_ERRORS(check(R"(
|
LUAU_REQUIRE_ERRORS(check(R"(
|
||||||
export type t138 = t0<t138>
|
export type t138 = t0<t138>
|
||||||
export type t0<t0,t10,t10,t109> = t0
|
export type t0<t0,t10,t10,t109> = t0
|
||||||
|
|
|
@ -272,7 +272,8 @@ TEST_CASE_FIXTURE(Fixture, "infer_type_of_value_a_via_typeof_with_assignment")
|
||||||
|
|
||||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||||
CHECK(
|
CHECK(
|
||||||
result.errors[0] == (TypeError{Location{Position{2, 29}, Position{2, 30}}, TypeMismatch{getBuiltins()->nilType, getBuiltins()->numberType}})
|
result.errors[0] ==
|
||||||
|
(TypeError{Location{Position{2, 29}, Position{2, 30}}, TypeMismatch{getBuiltins()->nilType, getBuiltins()->numberType}})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -447,7 +448,8 @@ TEST_CASE_FIXTURE(Fixture, "self_referential_type_alias")
|
||||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||||
REQUIRE(incr->readTy);
|
REQUIRE(incr->readTy);
|
||||||
|
|
||||||
const FunctionType* incrFunc = FFlag::LuauRemoveTypeCallsForReadWriteProps ? get<FunctionType>(*incr->readTy) : get<FunctionType>(incr->type_DEPRECATED());
|
const FunctionType* incrFunc =
|
||||||
|
FFlag::LuauRemoveTypeCallsForReadWriteProps ? get<FunctionType>(*incr->readTy) : get<FunctionType>(incr->type_DEPRECATED());
|
||||||
REQUIRE(incrFunc);
|
REQUIRE(incrFunc);
|
||||||
|
|
||||||
std::optional<TypeId> firstArg = first(incrFunc->argTypes);
|
std::optional<TypeId> firstArg = first(incrFunc->argTypes);
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||||
LUAU_FASTFLAG(LuauSolverV2)
|
LUAU_FASTFLAG(LuauSolverV2)
|
||||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||||
LUAU_FASTFLAG(LuauIntersectNotNil)
|
LUAU_FASTFLAG(LuauIntersectNotNil)
|
||||||
LUAU_FASTFLAG(LuauSubtypingCheckFunctionGenericCounts)
|
LUAU_FASTFLAG(LuauSubtypingCheckFunctionGenericCounts)
|
||||||
|
@ -18,6 +18,7 @@ LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||||
LUAU_FASTFLAG(DebugLuauAssertOnForcedConstraint)
|
LUAU_FASTFLAG(DebugLuauAssertOnForcedConstraint)
|
||||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||||
|
LUAU_FASTFLAG(LuauContainsAnyGenericFollowBeforeChecking)
|
||||||
|
|
||||||
using namespace Luau;
|
using namespace Luau;
|
||||||
|
|
||||||
|
@ -1004,7 +1005,7 @@ local TheDispatcher: Dispatcher = {
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_few")
|
TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_few")
|
||||||
{
|
{
|
||||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true};
|
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||||
|
|
||||||
CheckResult result = check(R"(
|
CheckResult result = check(R"(
|
||||||
function test(a: number)
|
function test(a: number)
|
||||||
|
@ -1032,7 +1033,7 @@ wrapper(test)
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_many")
|
TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_many")
|
||||||
{
|
{
|
||||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true};
|
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||||
|
|
||||||
CheckResult result = check(R"(
|
CheckResult result = check(R"(
|
||||||
function test2(a: number, b: string)
|
function test2(a: number, b: string)
|
||||||
|
@ -1076,7 +1077,7 @@ wrapper(test2, 1, "")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "generic_argument_pack_type_inferred_from_return")
|
TEST_CASE_FIXTURE(Fixture, "generic_argument_pack_type_inferred_from_return")
|
||||||
{
|
{
|
||||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true};
|
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||||
|
|
||||||
CheckResult result = check(R"(
|
CheckResult result = check(R"(
|
||||||
function test2(a: number)
|
function test2(a: number)
|
||||||
|
@ -1106,7 +1107,7 @@ wrapper(test2, 1)
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "generic_argument_pack_type_inferred_from_return_no_error")
|
TEST_CASE_FIXTURE(Fixture, "generic_argument_pack_type_inferred_from_return_no_error")
|
||||||
{
|
{
|
||||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true};
|
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||||
|
|
||||||
CheckResult result = check(R"(
|
CheckResult result = check(R"(
|
||||||
function test2(a: number)
|
function test2(a: number)
|
||||||
|
@ -1124,7 +1125,7 @@ wrapper(test2, "hello")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "nested_generic_argument_type_packs")
|
TEST_CASE_FIXTURE(Fixture, "nested_generic_argument_type_packs")
|
||||||
{
|
{
|
||||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true};
|
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||||
|
|
||||||
CheckResult result = check(R"(
|
CheckResult result = check(R"(
|
||||||
function test2(a: number)
|
function test2(a: number)
|
||||||
|
@ -1851,4 +1852,63 @@ end
|
||||||
LUAU_REQUIRE_NO_ERRORS(result);
|
LUAU_REQUIRE_NO_ERRORS(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_FIXTURE(Fixture, "generic_type_packs_shouldnt_be_bound_to_themselves")
|
||||||
|
{
|
||||||
|
ScopedFastFlag flags[] = {
|
||||||
|
{FFlag::LuauSolverV2, true},
|
||||||
|
{FFlag::LuauSubtypingCheckFunctionGenericCounts, true},
|
||||||
|
{FFlag::LuauEagerGeneralization4, true}
|
||||||
|
};
|
||||||
|
|
||||||
|
CheckResult result = check(R"(
|
||||||
|
export type t1<T...> = {
|
||||||
|
foo: (self: t1<T...>, bar: (T...) -> ()) -> ()
|
||||||
|
}
|
||||||
|
|
||||||
|
export type t2<T...> = {
|
||||||
|
baz: (self: t2<T...>) -> t1<T...>,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type t3<T...> = {
|
||||||
|
f: (self: t3<T...>, T...)-> (),
|
||||||
|
g: t1<T...>,
|
||||||
|
h: t1<(Player, T...)>
|
||||||
|
}
|
||||||
|
|
||||||
|
local t2 = {}
|
||||||
|
|
||||||
|
function t2.new<T...>(): t2<T...>
|
||||||
|
end
|
||||||
|
|
||||||
|
local function create_t3<T...>(): t3<T...>
|
||||||
|
local t2_1 = t2.new()
|
||||||
|
local t2_2 = t2.new()
|
||||||
|
local my_t3 = {
|
||||||
|
f = function(_self: t3<T...>, ...: T...) end,
|
||||||
|
g = t2_1:baz(),
|
||||||
|
h = t2_2:baz()
|
||||||
|
}
|
||||||
|
return my_t3
|
||||||
|
end
|
||||||
|
)");
|
||||||
|
|
||||||
|
// Note: we just need this test not to crash
|
||||||
|
LUAU_REQUIRE_ERROR_COUNT(5, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE_FIXTURE(BuiltinsFixture, "follow_bound_type_packs_in_generic_type_visitor")
|
||||||
|
{
|
||||||
|
ScopedFastFlag _{FFlag::LuauContainsAnyGenericFollowBeforeChecking, true};
|
||||||
|
// Note: we just need this test not to crash
|
||||||
|
check(R"(
|
||||||
|
function (_(_,_,nil))
|
||||||
|
(if l0 then typeof else `{_:_()}`,typeof).n0<A...,A...>(l0)
|
||||||
|
function _:_():typeof<A...>()
|
||||||
|
end
|
||||||
|
function _:_().typeof<A...>()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
)");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_SUITE_END();
|
TEST_SUITE_END();
|
||||||
|
|
|
@ -12,7 +12,7 @@ using namespace Luau;
|
||||||
LUAU_FASTFLAG(LuauSolverV2)
|
LUAU_FASTFLAG(LuauSolverV2)
|
||||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||||
|
|
||||||
|
@ -1162,7 +1162,7 @@ could not be converted into
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_4")
|
TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_4")
|
||||||
{
|
{
|
||||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true};
|
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||||
|
|
||||||
CheckResult result = check(R"(
|
CheckResult result = check(R"(
|
||||||
function f<a...>()
|
function f<a...>()
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||||
LUAU_FASTFLAG(LuauSolverV2)
|
LUAU_FASTFLAG(LuauSolverV2)
|
||||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||||
|
|
||||||
using namespace Luau;
|
using namespace Luau;
|
||||||
|
|
||||||
|
@ -823,7 +823,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cycles_dont_make_everything_any")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(BuiltinsFixture, "cross_module_function_mutation")
|
TEST_CASE_FIXTURE(BuiltinsFixture, "cross_module_function_mutation")
|
||||||
{
|
{
|
||||||
ScopedFastFlag _[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauReturnMappedGenericPacksFromSubtyping, true}};
|
ScopedFastFlag _[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true}};
|
||||||
|
|
||||||
fileResolver.source["game/A"] = R"(
|
fileResolver.source["game/A"] = R"(
|
||||||
function test2(a: number, b: string)
|
function test2(a: number, b: string)
|
||||||
|
|
|
@ -559,7 +559,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "textbook_class_pattern")
|
||||||
if (!FFlag::LuauSolverV2)
|
if (!FFlag::LuauSolverV2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ScopedFastFlag sff[] ={
|
ScopedFastFlag sff[] = {
|
||||||
{FFlag::LuauEagerGeneralization4, true},
|
{FFlag::LuauEagerGeneralization4, true},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -591,7 +591,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "textbook_class_pattern_2")
|
||||||
if (!FFlag::LuauSolverV2)
|
if (!FFlag::LuauSolverV2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ScopedFastFlag sff[] ={
|
ScopedFastFlag sff[] = {
|
||||||
{FFlag::LuauEagerGeneralization4, true},
|
{FFlag::LuauEagerGeneralization4, true},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,8 @@ struct RefinementExternTypeFixture : BuiltinsFixture
|
||||||
};
|
};
|
||||||
|
|
||||||
TypeId optionalPart = arena.addType(UnionType{{part, getBuiltins()->nilType}});
|
TypeId optionalPart = arena.addType(UnionType{{part, getBuiltins()->nilType}});
|
||||||
TypeId weldConstraint = getFrontend().globals.globalTypes.addType(ExternType{"WeldConstraint", {}, inst, std::nullopt, {}, nullptr, "Test", {}});
|
TypeId weldConstraint =
|
||||||
|
getFrontend().globals.globalTypes.addType(ExternType{"WeldConstraint", {}, inst, std::nullopt, {}, nullptr, "Test", {}});
|
||||||
getMutable<ExternType>(weldConstraint)->props = {
|
getMutable<ExternType>(weldConstraint)->props = {
|
||||||
{"Part0", Property{optionalPart}},
|
{"Part0", Property{optionalPart}},
|
||||||
{"Part1", Property{optionalPart}},
|
{"Part1", Property{optionalPart}},
|
||||||
|
@ -2453,7 +2454,7 @@ end)
|
||||||
)"));
|
)"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "refinements_table_intersection_limits" * doctest::timeout(1.0))
|
TEST_CASE_FIXTURE(Fixture, "refinements_table_intersection_limits" * doctest::timeout(1.5))
|
||||||
{
|
{
|
||||||
CheckResult result = check(R"(
|
CheckResult result = check(R"(
|
||||||
--!strict
|
--!strict
|
||||||
|
|
|
@ -40,6 +40,7 @@ LUAU_FASTFLAG(LuauDfgForwardNilFromAndOr)
|
||||||
LUAU_FASTFLAG(LuauInferActualIfElseExprType)
|
LUAU_FASTFLAG(LuauInferActualIfElseExprType)
|
||||||
LUAU_FASTFLAG(LuauDoNotPrototypeTableIndex)
|
LUAU_FASTFLAG(LuauDoNotPrototypeTableIndex)
|
||||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||||
|
LUAU_FASTFLAG(LuauNormalizationLimitTyvarUnionSize)
|
||||||
|
|
||||||
TEST_SUITE_BEGIN("TableTests");
|
TEST_SUITE_BEGIN("TableTests");
|
||||||
|
|
||||||
|
@ -6129,7 +6130,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_119126_regression")
|
||||||
)");
|
)");
|
||||||
|
|
||||||
LUAU_REQUIRE_ERROR_COUNT(2, results);
|
LUAU_REQUIRE_ERROR_COUNT(2, results);
|
||||||
for (const auto& err: results.errors)
|
for (const auto& err : results.errors)
|
||||||
{
|
{
|
||||||
auto e = get<TypeMismatch>(err);
|
auto e = get<TypeMismatch>(err);
|
||||||
REQUIRE(e);
|
REQUIRE(e);
|
||||||
|
@ -6173,5 +6174,23 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1914_access_after_assignment_with_assert
|
||||||
CHECK_EQ("number", toString(requireType("myAge")));
|
CHECK_EQ("number", toString(requireType("myAge")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE_FIXTURE(BuiltinsFixture, "cli_162179_avoid_exponential_blowup_in_normalization" * doctest::timeout(1.0))
|
||||||
|
{
|
||||||
|
ScopedFastFlag sffs[] = {
|
||||||
|
{FFlag::LuauSimplifyOutOfLine2, true},
|
||||||
|
{FFlag::LuauNormalizationLimitTyvarUnionSize, true},
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::string source =
|
||||||
|
"local res = {\n" + rep("\"foo\",\n", 100) + "}\n"
|
||||||
|
+ "local function check(index: number)\n"
|
||||||
|
+ " if res[index] == \"foo\" then\n"
|
||||||
|
+ " print(\"found a foo!\")\n"
|
||||||
|
+ " end\n"
|
||||||
|
+ "end";
|
||||||
|
|
||||||
|
LUAU_REQUIRE_NO_ERRORS(check(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_SUITE_END();
|
TEST_SUITE_END();
|
||||||
|
|
|
@ -1984,7 +1984,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assert_table_freeze_constraint_solving")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_assert_table_freeze_constraint_solving")
|
TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_assert_table_freeze_constraint_solving")
|
||||||
{
|
{
|
||||||
ScopedFastFlag _ {FFlag::LuauSolverV2, true};
|
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||||
// This is the original fuzzer version of the above issue.
|
// This is the original fuzzer version of the above issue.
|
||||||
CheckResult results = check(R"(
|
CheckResult results = check(R"(
|
||||||
local function l0()
|
local function l0()
|
||||||
|
@ -2383,7 +2383,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_remover_heap_use_after_free")
|
||||||
local l249 = require(module0)
|
local l249 = require(module0)
|
||||||
_,_ = {[`{_}`]=_,[_._G._]=(_)(),[_["" + _]._G]={_=_,_=_,[_._G[_]._]=_G,},},_,(_)()
|
_,_ = {[`{_}`]=_,[_._G._]=(_)(),[_["" + _]._G]={_=_,_=_,[_._G[_]._]=_G,},},_,(_)()
|
||||||
)"));
|
)"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "fuzzer_missing_follow_in_assign_index_constraint")
|
TEST_CASE_FIXTURE(Fixture, "fuzzer_missing_follow_in_assign_index_constraint")
|
||||||
|
@ -2476,7 +2475,6 @@ TEST_CASE_FIXTURE(Fixture, "oss_1815_verbatim")
|
||||||
REQUIRE(err3);
|
REQUIRE(err3);
|
||||||
CHECK_EQ("\"foo\"", toString(err3->wantedType));
|
CHECK_EQ("\"foo\"", toString(err3->wantedType));
|
||||||
CHECK_EQ("\"doge2\"", toString(err3->givenType));
|
CHECK_EQ("\"doge2\"", toString(err3->givenType));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(Fixture, "if_then_else_bidirectional_inference")
|
TEST_CASE_FIXTURE(Fixture, "if_then_else_bidirectional_inference")
|
||||||
|
|
|
@ -47,7 +47,8 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "compatible_functions_are_unified")
|
||||||
}};
|
}};
|
||||||
|
|
||||||
Type functionTwo{TypeVariant{FunctionType(
|
Type functionTwo{TypeVariant{FunctionType(
|
||||||
arena.addTypePack({arena.freshType(getBuiltins(), globalScope->level)}), arena.addTypePack({arena.freshType(getBuiltins(), globalScope->level)})
|
arena.addTypePack({arena.freshType(getBuiltins(), globalScope->level)}),
|
||||||
|
arena.addTypePack({arena.freshType(getBuiltins(), globalScope->level)})
|
||||||
)}};
|
)}};
|
||||||
|
|
||||||
state.tryUnify(&functionTwo, &functionOne);
|
state.tryUnify(&functionTwo, &functionOne);
|
||||||
|
@ -291,7 +292,8 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "free_tail_is_grown_properly")
|
||||||
{
|
{
|
||||||
TypePackId threeNumbers =
|
TypePackId threeNumbers =
|
||||||
arena.addTypePack(TypePack{{getBuiltins()->numberType, getBuiltins()->numberType, getBuiltins()->numberType}, std::nullopt});
|
arena.addTypePack(TypePack{{getBuiltins()->numberType, getBuiltins()->numberType, getBuiltins()->numberType}, std::nullopt});
|
||||||
TypePackId numberAndFreeTail = arena.addTypePack(TypePack{{getBuiltins()->numberType}, arena.addTypePack(TypePackVar{FreeTypePack{TypeLevel{}}})});
|
TypePackId numberAndFreeTail =
|
||||||
|
arena.addTypePack(TypePack{{getBuiltins()->numberType}, arena.addTypePack(TypePackVar{FreeTypePack{TypeLevel{}}})});
|
||||||
|
|
||||||
CHECK(state.canUnify(numberAndFreeTail, threeNumbers).empty());
|
CHECK(state.canUnify(numberAndFreeTail, threeNumbers).empty());
|
||||||
}
|
}
|
||||||
|
|
|
@ -710,9 +710,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refinement_through_erroring")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(BuiltinsFixture, "refinement_through_erroring_in_loop")
|
TEST_CASE_FIXTURE(BuiltinsFixture, "refinement_through_erroring_in_loop")
|
||||||
{
|
{
|
||||||
ScopedFastFlag sffs[] = {
|
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauDfgAllowUpdatesInLoops, true}};
|
||||||
{FFlag::LuauSolverV2, true}, {FFlag::LuauDfgAllowUpdatesInLoops, true}
|
|
||||||
};
|
|
||||||
|
|
||||||
CheckResult result = check(R"(
|
CheckResult result = check(R"(
|
||||||
--!strict
|
--!strict
|
||||||
|
|
|
@ -633,7 +633,11 @@ TEST_CASE_FIXTURE(Fixture, "indexing_into_a_cyclic_union_doesnt_crash")
|
||||||
|
|
||||||
u.options.push_back(badCyclicUnionTy);
|
u.options.push_back(badCyclicUnionTy);
|
||||||
u.options.push_back(arena.addType(TableType{
|
u.options.push_back(arena.addType(TableType{
|
||||||
{}, TableIndexer{getBuiltins()->numberType, getBuiltins()->numberType}, TypeLevel{}, getFrontend().globals.globalScope.get(), TableState::Sealed
|
{},
|
||||||
|
TableIndexer{getBuiltins()->numberType, getBuiltins()->numberType},
|
||||||
|
TypeLevel{},
|
||||||
|
getFrontend().globals.globalScope.get(),
|
||||||
|
TableState::Sealed
|
||||||
}));
|
}));
|
||||||
|
|
||||||
asMutable(badCyclicUnionTy)->ty.emplace<UnionType>(std::move(u));
|
asMutable(badCyclicUnionTy)->ty.emplace<UnionType>(std::move(u));
|
||||||
|
|
|
@ -18,6 +18,8 @@ using namespace Luau::TypePath;
|
||||||
LUAU_FASTFLAG(LuauSolverV2);
|
LUAU_FASTFLAG(LuauSolverV2);
|
||||||
LUAU_DYNAMIC_FASTINT(LuauTypePathMaximumTraverseSteps);
|
LUAU_DYNAMIC_FASTINT(LuauTypePathMaximumTraverseSteps);
|
||||||
|
|
||||||
|
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2);
|
||||||
|
|
||||||
struct TypePathFixture : Fixture
|
struct TypePathFixture : Fixture
|
||||||
{
|
{
|
||||||
ScopedFastFlag sff1{FFlag::LuauSolverV2, true};
|
ScopedFastFlag sff1{FFlag::LuauSolverV2, true};
|
||||||
|
@ -494,6 +496,8 @@ TEST_CASE_FIXTURE(TypePathFixture, "tail")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(TypePathFixture, "pack_slice_has_tail")
|
TEST_CASE_FIXTURE(TypePathFixture, "pack_slice_has_tail")
|
||||||
{
|
{
|
||||||
|
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||||
|
|
||||||
TypeArena& arena = getFrontend().globals.globalTypes;
|
TypeArena& arena = getFrontend().globals.globalTypes;
|
||||||
unfreeze(arena);
|
unfreeze(arena);
|
||||||
|
|
||||||
|
@ -510,6 +514,8 @@ TEST_CASE_FIXTURE(TypePathFixture, "pack_slice_has_tail")
|
||||||
|
|
||||||
TEST_CASE_FIXTURE(TypePathFixture, "pack_slice_finite_pack")
|
TEST_CASE_FIXTURE(TypePathFixture, "pack_slice_finite_pack")
|
||||||
{
|
{
|
||||||
|
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||||
|
|
||||||
TypeArena& arena = getFrontend().globals.globalTypes;
|
TypeArena& arena = getFrontend().globals.globalTypes;
|
||||||
unfreeze(arena);
|
unfreeze(arena);
|
||||||
|
|
||||||
|
|
|
@ -365,6 +365,12 @@ struct VisitCountTracker final : TypeOnceVisitor
|
||||||
std::unordered_map<TypeId, unsigned> tyVisits;
|
std::unordered_map<TypeId, unsigned> tyVisits;
|
||||||
std::unordered_map<TypePackId, unsigned> tpVisits;
|
std::unordered_map<TypePackId, unsigned> tpVisits;
|
||||||
|
|
||||||
|
VisitCountTracker()
|
||||||
|
: TypeOnceVisitor("VisitCountTracker")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void cycle(TypeId) override {}
|
void cycle(TypeId) override {}
|
||||||
void cycle(TypePackId) override {}
|
void cycle(TypePackId) override {}
|
||||||
|
|
||||||
|
|
|
@ -241,7 +241,7 @@ if not limitedstack then
|
||||||
function recurse(n, ...) return n <= 1 and (1 + #{...}) or recurse(n-1, table.unpack(table.create(4000, 1))) + 1 end
|
function recurse(n, ...) return n <= 1 and (1 + #{...}) or recurse(n-1, table.unpack(table.create(4000, 1))) + 1 end
|
||||||
|
|
||||||
local ok, msg = pcall(recurse, 19000)
|
local ok, msg = pcall(recurse, 19000)
|
||||||
assert(not ok and string.find(msg, "not enough memory"))
|
assert(not ok and string.find(msg, "too many results to unpack"))
|
||||||
end
|
end
|
||||||
|
|
||||||
return('OK')
|
return('OK')
|
||||||
|
|
|
@ -382,4 +382,13 @@ do
|
||||||
assert(st and msg == nil)
|
assert(st and msg == nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
do
|
||||||
|
local co = coroutine.wrap(xpcall)
|
||||||
|
|
||||||
|
co(0, coroutine.yield, 0)
|
||||||
|
local status, err = pcall(co, 0, 0, 0)
|
||||||
|
assert(status == false)
|
||||||
|
assert(err == "cannot resume dead coroutine")
|
||||||
|
end
|
||||||
|
|
||||||
return 'OK'
|
return 'OK'
|
||||||
|
|
Loading…
Add table
Reference in a new issue