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();
|
||||
|
||||
}
|
||||
} // namespace Luau
|
||||
|
|
|
@ -341,7 +341,6 @@ struct Constraint
|
|||
DenseHashSet<TypeId> getMaybeMutatedFreeTypes_DEPRECATED() const;
|
||||
|
||||
TypeIds getMaybeMutatedFreeTypes() const;
|
||||
|
||||
};
|
||||
|
||||
using ConstraintPtr = std::unique_ptr<Constraint>;
|
||||
|
|
|
@ -92,6 +92,11 @@ struct GenericTypeFinder : TypeOnceVisitor
|
|||
{
|
||||
bool found = false;
|
||||
|
||||
GenericTypeFinder()
|
||||
: TypeOnceVisitor("GenericTypeFinder")
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId ty) override
|
||||
{
|
||||
return !found;
|
||||
|
|
|
@ -65,4 +65,4 @@ private:
|
|||
DenseHashSet<T> elementSet{nullptr};
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Luau
|
|
@ -12,8 +12,8 @@ namespace Luau
|
|||
|
||||
struct RecursionLimitException : public InternalCompilerError
|
||||
{
|
||||
RecursionLimitException()
|
||||
: InternalCompilerError("Internal recursion counter limit exceeded")
|
||||
RecursionLimitException(const std::string system)
|
||||
: InternalCompilerError("Internal recursion counter limit exceeded in " + system)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
@ -38,12 +38,12 @@ protected:
|
|||
|
||||
struct RecursionLimiter : RecursionCounter
|
||||
{
|
||||
RecursionLimiter(int* count, int limit)
|
||||
RecursionLimiter(const std::string system, int* count, int limit)
|
||||
: RecursionCounter(count)
|
||||
{
|
||||
if (limit > 0 && *count > limit)
|
||||
{
|
||||
throw RecursionLimitException();
|
||||
throw RecursionLimitException(system);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -157,8 +157,10 @@ struct Subtyping
|
|||
Variance variance = Variance::Covariant;
|
||||
|
||||
using SeenSet = Set<std::pair<TypeId, TypeId>, TypePairHash>;
|
||||
using SeenTypePackSet = Set<std::pair<TypePackId, TypePackId>, TypePairHash>;
|
||||
|
||||
SeenSet seenTypes{{}};
|
||||
SeenTypePackSet seenPacks{{}};
|
||||
|
||||
Subtyping(
|
||||
NotNull<BuiltinTypes> builtinTypes,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Luau/Common.h"
|
||||
#include "Luau/DenseHash.h"
|
||||
#include "Luau/TypeFwd.h"
|
||||
|
||||
#include <memory>
|
||||
|
@ -134,6 +135,10 @@ std::string dump(TypeId ty);
|
|||
std::string dump(const std::optional<TypeId>& ty);
|
||||
std::string dump(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 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 toStringVector(const std::vector<TypeId>& types, ToStringOptions& opts);
|
||||
} // namespace Luau
|
||||
|
|
|
@ -32,8 +32,8 @@ public:
|
|||
TypeIds(const TypeIds&) = default;
|
||||
TypeIds& operator=(const TypeIds&) = default;
|
||||
|
||||
TypeIds(TypeIds&&) = default;
|
||||
TypeIds& operator=(TypeIds&&) = default;
|
||||
TypeIds(TypeIds&&) noexcept = default;
|
||||
TypeIds& operator=(TypeIds&&) noexcept = default;
|
||||
|
||||
void insert(TypeId ty);
|
||||
/// 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.
|
||||
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(TypePackId root, const Path& path, NotNull<BuiltinTypes> builtinTypes);
|
||||
std::optional<TypeOrPack> traverse(
|
||||
|
|
|
@ -73,6 +73,8 @@ struct GenericTypeVisitor
|
|||
{
|
||||
using Set = S;
|
||||
|
||||
const std::string visitorName;
|
||||
|
||||
Set seen;
|
||||
bool skipBoundTypes = false;
|
||||
int recursionCounter = 0;
|
||||
|
@ -80,8 +82,9 @@ struct GenericTypeVisitor
|
|||
|
||||
GenericTypeVisitor() = default;
|
||||
|
||||
explicit GenericTypeVisitor(Set seen, bool skipBoundTypes = false)
|
||||
: seen(std::move(seen))
|
||||
explicit GenericTypeVisitor(const std::string visitorName, Set seen, bool skipBoundTypes = false)
|
||||
: visitorName(visitorName)
|
||||
, seen(std::move(seen))
|
||||
, skipBoundTypes(skipBoundTypes)
|
||||
{
|
||||
}
|
||||
|
@ -215,7 +218,7 @@ struct GenericTypeVisitor
|
|||
|
||||
void traverse(TypeId ty)
|
||||
{
|
||||
RecursionLimiter limiter{&recursionCounter, FInt::LuauVisitRecursionLimit};
|
||||
RecursionLimiter limiter{visitorName, &recursionCounter, FInt::LuauVisitRecursionLimit};
|
||||
|
||||
if (visit_detail::hasSeen(seen, ty))
|
||||
{
|
||||
|
@ -527,8 +530,8 @@ struct GenericTypeVisitor
|
|||
*/
|
||||
struct TypeVisitor : GenericTypeVisitor<std::unordered_set<void*>>
|
||||
{
|
||||
explicit TypeVisitor(bool skipBoundTypes = false)
|
||||
: GenericTypeVisitor{{}, skipBoundTypes}
|
||||
explicit TypeVisitor(const std::string visitorName, bool skipBoundTypes = false)
|
||||
: 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.
|
||||
struct TypeOnceVisitor : GenericTypeVisitor<DenseHashSet<void*>>
|
||||
{
|
||||
explicit TypeOnceVisitor(bool skipBoundTypes = false)
|
||||
: GenericTypeVisitor{DenseHashSet<void*>{nullptr}, skipBoundTypes}
|
||||
explicit TypeOnceVisitor(const std::string visitorName, bool skipBoundTypes = false)
|
||||
: GenericTypeVisitor{visitorName, DenseHashSet<void*>{nullptr}, skipBoundTypes}
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
|
@ -583,7 +583,9 @@ std::optional<DocumentationSymbol> getDocumentationSymbolAtPosition(const Source
|
|||
return checkOverloadedDocumentationSymbol(module, *ty, parentExpr, propIt->second.documentationSymbol);
|
||||
}
|
||||
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))
|
||||
|
|
|
@ -771,7 +771,9 @@ bool MagicFormat::typeCheck(const MagicFunctionTypeCheckContext& context)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -823,7 +825,8 @@ bool MagicFormat::typeCheck(const MagicFunctionTypeCheckContext& context)
|
|||
{
|
||||
TypeId actualTy = params[i + paramOffset];
|
||||
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
|
||||
SubtypingResult result = context.typechecker->subtyping->isSubtype(actualTy, expectedTy, context.checkScope);
|
||||
|
||||
|
@ -845,7 +848,6 @@ bool MagicFormat::typeCheck(const MagicFunctionTypeCheckContext& context)
|
|||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -863,7 +865,9 @@ bool MagicFormat::typeCheck(const MagicFunctionTypeCheckContext& context)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -887,7 +891,8 @@ bool MagicFormat::typeCheck(const MagicFunctionTypeCheckContext& context)
|
|||
{
|
||||
TypeId actualTy = params[i + paramOffset];
|
||||
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
|
||||
SubtypingResult result = context.typechecker->subtyping->isSubtype(actualTy, expectedTy, context.checkScope);
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ std::optional<TypeFunctionReductionResult<TypeId>> tryDistributeTypeFunctionApp(
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TypeFunctionReductionResult<TypeId> notTypeFunction(
|
||||
TypeId instance,
|
||||
|
@ -1034,6 +1034,12 @@ TypeFunctionReductionResult<TypeId> eqTypeFunction(
|
|||
struct FindRefinementBlockers : TypeOnceVisitor
|
||||
{
|
||||
DenseHashSet<TypeId> found{nullptr};
|
||||
|
||||
FindRefinementBlockers()
|
||||
: TypeOnceVisitor("FindRefinementBlockers")
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const BlockedType&) override
|
||||
{
|
||||
found.insert(ty);
|
||||
|
@ -1056,7 +1062,7 @@ struct ContainsRefinableType : TypeOnceVisitor
|
|||
{
|
||||
bool found = false;
|
||||
ContainsRefinableType()
|
||||
: TypeOnceVisitor(/* skipBoundTypes */ true)
|
||||
: TypeOnceVisitor("ContainsRefinableType", /* skipBoundTypes */ true)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1199,7 +1205,6 @@ struct RefineTypeScrubber : public Substitution
|
|||
}
|
||||
return ty;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
bool occurs(TypeId haystack, TypeId needle, DenseHashSet<TypeId>& seen)
|
||||
|
@ -1431,7 +1436,6 @@ TypeFunctionReductionResult<TypeId> refineTypeFunction(
|
|||
|
||||
return {resultTy, {}};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// refine target with each discriminant type in sequence (reverse of insertion order)
|
||||
|
@ -1494,7 +1498,7 @@ struct CollectUnionTypeOptions : TypeOnceVisitor
|
|||
DenseHashSet<TypeId> blockingTypes{nullptr};
|
||||
|
||||
explicit CollectUnionTypeOptions(NotNull<TypeFunctionContext> ctx)
|
||||
: TypeOnceVisitor(/* skipBoundTypes */ true)
|
||||
: TypeOnceVisitor("CollectUnionTypeOptions", /* skipBoundTypes */ true)
|
||||
, ctx(ctx)
|
||||
{
|
||||
}
|
||||
|
@ -1764,7 +1768,8 @@ bool computeKeysOf_DEPRECATED(TypeId ty, Set<std::string>& result, DenseHashSet<
|
|||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
namespace
|
||||
{
|
||||
|
||||
/**
|
||||
* Computes the keys of `ty` into `result`
|
||||
|
@ -1847,7 +1852,7 @@ bool computeKeysOf(TypeId ty, Set<std::optional<std::string>>& result, DenseHash
|
|||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TypeFunctionReductionResult<TypeId> keyofFunctionImpl(
|
||||
const std::vector<TypeId>& typeParams,
|
||||
|
@ -2824,4 +2829,4 @@ const BuiltinTypeFunctions& builtinTypeFunctions()
|
|||
return *result;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Luau
|
||||
|
|
|
@ -24,7 +24,8 @@ struct ReferenceCountInitializer_DEPRECATED : TypeOnceVisitor
|
|||
bool traverseIntoTypeFunctions = true;
|
||||
|
||||
explicit ReferenceCountInitializer_DEPRECATED(DenseHashSet<TypeId>* result)
|
||||
: result(result)
|
||||
: TypeOnceVisitor("ReferenceCountInitializer_DEPRECATED")
|
||||
, result(result)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -78,7 +79,8 @@ struct ReferenceCountInitializer : TypeOnceVisitor
|
|||
bool traverseIntoTypeFunctions = true;
|
||||
|
||||
explicit ReferenceCountInitializer(NotNull<TypeIds> result)
|
||||
: result(result)
|
||||
: TypeOnceVisitor("ReferenceCountInitializer")
|
||||
, result(result)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -139,7 +139,10 @@ struct HasFreeType : TypeOnceVisitor
|
|||
{
|
||||
bool result = false;
|
||||
|
||||
HasFreeType() {}
|
||||
HasFreeType()
|
||||
: TypeOnceVisitor("TypeOnceVisitor")
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId ty) override
|
||||
{
|
||||
|
@ -640,6 +643,11 @@ struct FindSimplificationBlockers : TypeOnceVisitor
|
|||
{
|
||||
bool found = false;
|
||||
|
||||
FindSimplificationBlockers()
|
||||
: TypeOnceVisitor("FindSimplificationBlockers")
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId) override
|
||||
{
|
||||
return !found;
|
||||
|
@ -1026,7 +1034,7 @@ ControlFlow ConstraintGenerator::visitBlockWithoutChildScope(const ScopePtr& sco
|
|||
|
||||
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>())
|
||||
return visit(scope, s);
|
||||
|
|
|
@ -34,7 +34,6 @@ LUAU_FASTINTVARIABLE(LuauSolverRecursionLimit, 500)
|
|||
LUAU_FASTFLAGVARIABLE(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||
LUAU_FASTFLAGVARIABLE(LuauGuardAgainstMalformedTypeAliasExpansion2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAvoidGenericsLeakingDuringFunctionCallCheck)
|
||||
LUAU_FASTFLAGVARIABLE(LuauMissingFollowInAssignIndexConstraint)
|
||||
LUAU_FASTFLAGVARIABLE(LuauRemoveTypeCallsForReadWriteProps)
|
||||
|
@ -43,6 +42,7 @@ LUAU_FASTFLAGVARIABLE(LuauUseOrderedTypeSetsInConstraints)
|
|||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauAvoidExcessiveTypeCopying)
|
||||
LUAU_FASTFLAGVARIABLE(LuauForceSimplifyConstraint)
|
||||
LUAU_FASTFLAGVARIABLE(LuauContainsAnyGenericFollowBeforeChecking)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -285,7 +285,8 @@ struct InstantiationQueuer : TypeOnceVisitor
|
|||
Location location;
|
||||
|
||||
explicit InstantiationQueuer(NotNull<Scope> scope, const Location& location, ConstraintSolver* solver)
|
||||
: solver(solver)
|
||||
: TypeOnceVisitor("InstantiationQueuer")
|
||||
, solver(solver)
|
||||
, scope(scope)
|
||||
, location(location)
|
||||
{
|
||||
|
@ -432,7 +433,8 @@ void ConstraintSolver::run()
|
|||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -633,8 +635,7 @@ void ConstraintSolver::finalizeTypeFunctions()
|
|||
if (get<TypeFunctionInstanceType>(ty))
|
||||
{
|
||||
TypeFunctionContext context{NotNull{this}, constraint->scope, NotNull{constraint}};
|
||||
FunctionGraphReductionResult result =
|
||||
reduceTypeFunctions(t, constraint->location, NotNull{&context}, true);
|
||||
FunctionGraphReductionResult result = reduceTypeFunctions(t, constraint->location, NotNull{&context}, true);
|
||||
|
||||
for (TypeId r : result.reducedTypes)
|
||||
unblock(r, constraint->location);
|
||||
|
@ -663,7 +664,8 @@ struct TypeSearcher : TypeVisitor
|
|||
}
|
||||
|
||||
explicit TypeSearcher(TypeId needle, Polarity initialPolarity)
|
||||
: needle(needle)
|
||||
: TypeVisitor("TypeSearcher")
|
||||
, needle(needle)
|
||||
, current(initialPolarity)
|
||||
{
|
||||
}
|
||||
|
@ -1195,7 +1197,8 @@ struct InfiniteTypeFinder : TypeOnceVisitor
|
|||
bool foundInfiniteType = false;
|
||||
|
||||
explicit InfiniteTypeFinder(ConstraintSolver* solver, const InstantiationSignature& signature, NotNull<Scope> scope)
|
||||
: solver(solver)
|
||||
: TypeOnceVisitor("InfiniteTypeFinder")
|
||||
, solver(solver)
|
||||
, signature(signature)
|
||||
, scope(scope)
|
||||
{
|
||||
|
@ -1235,7 +1238,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
|
|||
auto cTarget = follow(c.target);
|
||||
LUAU_ASSERT(get<PendingExpansionType>(cTarget));
|
||||
// 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);
|
||||
bind(constraint, cTarget, builtinTypes->errorType);
|
||||
|
@ -1656,6 +1659,11 @@ struct ContainsGenerics_DEPRECATED : public TypeOnceVisitor
|
|||
|
||||
bool found = false;
|
||||
|
||||
ContainsGenerics_DEPRECATED()
|
||||
: TypeOnceVisitor("ContainsGenerics_DEPRECATED")
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId ty) override
|
||||
{
|
||||
return !found;
|
||||
|
@ -1736,7 +1744,8 @@ struct ContainsGenerics : public TypeOnceVisitor
|
|||
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
|
||||
)
|
||||
{
|
||||
RecursionLimiter _rl{&recursionDepth, FInt::LuauSolverRecursionLimit};
|
||||
RecursionLimiter _rl{"ConstraintSolver::tryDispatchHasIndexer", &recursionDepth, FInt::LuauSolverRecursionLimit};
|
||||
|
||||
subjectType = follow(subjectType);
|
||||
indexType = follow(indexType);
|
||||
|
@ -2315,6 +2324,11 @@ struct BlockedTypeFinder : TypeOnceVisitor
|
|||
{
|
||||
std::optional<TypeId> blocked;
|
||||
|
||||
BlockedTypeFinder()
|
||||
: TypeOnceVisitor("ContainsGenerics_DEPRECATED")
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId ty) override
|
||||
{
|
||||
// If we've already found one, stop traversing.
|
||||
|
@ -2873,7 +2887,7 @@ struct FindAllUnionMembers : TypeOnceVisitor
|
|||
TypeIds blockedTys;
|
||||
|
||||
FindAllUnionMembers()
|
||||
: TypeOnceVisitor(/* skipBoundTypes */ true)
|
||||
: TypeOnceVisitor("FindAllUnionMembers", /* skipBoundTypes */ true)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -2959,7 +2973,7 @@ struct ContainsAnyGeneric final : public TypeOnceVisitor
|
|||
bool found = false;
|
||||
|
||||
explicit ContainsAnyGeneric()
|
||||
: TypeOnceVisitor(true)
|
||||
: TypeOnceVisitor("ContainsAnyGeneric", /* skipBoundTypes */ true)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -2971,6 +2985,9 @@ struct ContainsAnyGeneric final : public TypeOnceVisitor
|
|||
|
||||
bool visit(TypePackId ty) override
|
||||
{
|
||||
if (FFlag::LuauContainsAnyGenericFollowBeforeChecking)
|
||||
found = found || is<GenericTypePack>(follow(ty));
|
||||
else
|
||||
found = found || is<GenericTypePack>(ty);
|
||||
return !found;
|
||||
}
|
||||
|
@ -3367,7 +3384,8 @@ TablePropLookupResult ConstraintSolver::lookupTableProp(
|
|||
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))
|
||||
{
|
||||
|
@ -3654,7 +3672,8 @@ struct Blocker : TypeOnceVisitor
|
|||
bool blocked = false;
|
||||
|
||||
explicit Blocker(NotNull<ConstraintSolver> solver, NotNull<const Constraint> constraint)
|
||||
: solver(solver)
|
||||
: TypeOnceVisitor("Blocker")
|
||||
, solver(solver)
|
||||
, 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
|
||||
#include "Luau/BuiltinDefinitions.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauDeclareExternType)
|
||||
LUAU_FASTFLAG(LuauTypeFunOptional)
|
||||
|
||||
namespace Luau
|
||||
|
@ -262,8 +261,7 @@ declare buffer: {
|
|||
|
||||
)BUILTIN_SRC";
|
||||
|
||||
static const char* const kBuiltinDefinitionVectorSrc = (FFlag::LuauDeclareExternType)
|
||||
? R"BUILTIN_SRC(
|
||||
static const char* const kBuiltinDefinitionVectorSrc = 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
|
||||
declare extern type vector with
|
||||
|
@ -291,35 +289,6 @@ declare 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";
|
||||
|
||||
std::string getBuiltinDefinitionSource()
|
||||
|
|
|
@ -81,7 +81,9 @@ struct IndexerIndexCollector : public TypeOnceVisitor
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct IndexCollector : public TypeOnceVisitor
|
||||
|
@ -108,7 +109,9 @@ struct IndexCollector : public TypeOnceVisitor
|
|||
NotNull<TypeArena> arena;
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool ExpectedTypeVisitor::visit(AstExprIndexExpr* expr)
|
||||
{
|
||||
|
@ -156,17 +158,11 @@ bool ExpectedTypeVisitor::visit(AstExprIndexExpr* expr)
|
|||
ic.traverse(*ty);
|
||||
if (ic.indexes.size() > 1)
|
||||
{
|
||||
applyExpectedType(
|
||||
arena->addType(UnionType{ic.indexes.take()}),
|
||||
expr->index
|
||||
);
|
||||
applyExpectedType(arena->addType(UnionType{ic.indexes.take()}), expr->index);
|
||||
}
|
||||
else if (ic.indexes.size() == 1)
|
||||
{
|
||||
applyExpectedType(
|
||||
*ic.indexes.begin(),
|
||||
expr->index
|
||||
);
|
||||
applyExpectedType(*ic.indexes.begin(), expr->index);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -623,7 +623,6 @@ struct UsageFinder : public AstVisitor
|
|||
}
|
||||
else
|
||||
localBindingsReferenced.emplace_back(dfg->getDef(local), local->local);
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1016,7 +1016,8 @@ void Frontend::checkBuildQueueItem(BuildQueueItem& item)
|
|||
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;
|
||||
|
||||
|
@ -1368,6 +1369,11 @@ ModulePtr check(
|
|||
|
||||
struct InternalTypeFinder : TypeOnceVisitor
|
||||
{
|
||||
InternalTypeFinder()
|
||||
: TypeOnceVisitor("InternalTypeFinder")
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId, const ExternType&) override
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -46,7 +46,7 @@ struct MutatingGeneralizer : TypeOnceVisitor
|
|||
DenseHashMap<const void*, size_t> positiveTypes,
|
||||
DenseHashMap<const void*, size_t> negativeTypes
|
||||
)
|
||||
: TypeOnceVisitor(/* skipBoundTypes */ true)
|
||||
: TypeOnceVisitor("MutatingGeneralizer", /* skipBoundTypes */ true)
|
||||
, arena(arena)
|
||||
, builtinTypes(builtinTypes)
|
||||
, scope(scope)
|
||||
|
@ -338,7 +338,7 @@ struct FreeTypeSearcher : TypeVisitor
|
|||
NotNull<DenseHashSet<TypeId>> cachedTypes;
|
||||
|
||||
explicit FreeTypeSearcher(NotNull<Scope> scope, NotNull<DenseHashSet<TypeId>> cachedTypes)
|
||||
: TypeVisitor(/*skipBoundTypes*/ true)
|
||||
: TypeVisitor("FreeTypeSearcher", /*skipBoundTypes*/ true)
|
||||
, scope(scope)
|
||||
, cachedTypes(cachedTypes)
|
||||
{
|
||||
|
@ -649,7 +649,7 @@ struct TypeCacher : TypeOnceVisitor
|
|||
DenseHashSet<TypePackId> uncacheablePacks{nullptr};
|
||||
|
||||
explicit TypeCacher(NotNull<DenseHashSet<TypeId>> cachedTypes)
|
||||
: TypeOnceVisitor(/* skipBoundTypes */ false)
|
||||
: TypeOnceVisitor("TypeCacher", /* skipBoundTypes */ false)
|
||||
, cachedTypes(cachedTypes)
|
||||
{
|
||||
}
|
||||
|
@ -1136,7 +1136,6 @@ struct TypeRemover
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
GeneralizationResult<TypeId> generalizeType(
|
||||
NotNull<TypeArena> arena,
|
||||
|
@ -1410,7 +1409,8 @@ struct GenericCounter : TypeVisitor
|
|||
Polarity polarity = Polarity::Positive;
|
||||
|
||||
explicit GenericCounter(NotNull<DenseHashSet<TypeId>> cachedTypes)
|
||||
: cachedTypes(cachedTypes)
|
||||
: TypeVisitor("GenericCounter")
|
||||
, cachedTypes(cachedTypes)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@ struct InferPolarity : TypeVisitor
|
|||
Polarity polarity = Polarity::Positive;
|
||||
|
||||
explicit InferPolarity(NotNull<TypeArena> arena, NotNull<Scope> scope)
|
||||
: arena(arena)
|
||||
: TypeVisitor("InferPolarity")
|
||||
, arena(arena)
|
||||
, scope(scope)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ LUAU_FASTFLAGVARIABLE(LuauNormalizationIntersectTablesPreservesExternTypes)
|
|||
LUAU_FASTFLAGVARIABLE(LuauNormalizationReorderFreeTypeIntersect)
|
||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||
LUAU_FASTFLAG(LuauUseWorkspacePropToChooseSolver)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNormalizationLimitTyvarUnionSize)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -1530,6 +1531,12 @@ NormalizationResult Normalizer::unionNormals(NormalizedType& here, const Normali
|
|||
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++)
|
||||
{
|
||||
TypeId tyvar = it->first;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include "Luau/Unifier2.h"
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -247,9 +247,7 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
|||
)
|
||||
{
|
||||
TypeFunctionContext context{arena, builtinTypes, scope, simplifier, normalizer, typeFunctionRuntime, ice, limits};
|
||||
FunctionGraphReductionResult result = reduceTypeFunctions(
|
||||
fnTy, callLoc, NotNull{&context}, /*force=*/true
|
||||
);
|
||||
FunctionGraphReductionResult result = reduceTypeFunctions(fnTy, callLoc, NotNull{&context}, /*force=*/true);
|
||||
if (!result.errors.empty())
|
||||
return {OverloadIsNonviable, result.errors};
|
||||
|
||||
|
@ -330,7 +328,7 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
|||
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 :: ...
|
||||
// and superPath matches Args :: ...
|
||||
|
@ -405,15 +403,15 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
|||
: argExprs->size() != 0 ? argExprs->back()->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_DEPRECATED(fnTy, reason.subPath, builtinTypes);
|
||||
std::optional<TypeId> failedSuperTy =
|
||||
FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
||||
FFlag::LuauReturnMappedGenericPacksFromSubtyping2
|
||||
? traverseForType(prospectiveFunction, reason.superPath, builtinTypes, NotNull{&sr.mappedGenericPacks}, arena)
|
||||
: traverseForType_DEPRECATED(prospectiveFunction, reason.superPath, builtinTypes);
|
||||
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
maybeEmplaceError(&errors, argLocation, &reason, 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]
|
||||
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_DEPRECATED(fnTy, reason.subPath, builtinTypes);
|
||||
std::optional<TypePackId> failedSuperPack =
|
||||
FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
||||
FFlag::LuauReturnMappedGenericPacksFromSubtyping2
|
||||
? traverseForPack(prospectiveFunction, reason.superPath, builtinTypes, NotNull{&sr.mappedGenericPacks}, arena)
|
||||
: traverseForPack_DEPRECATED(prospectiveFunction, reason.superPath, builtinTypes);
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@ struct Quantifier final : TypeOnceVisitor
|
|||
bool seenMutableType = false;
|
||||
|
||||
explicit Quantifier(TypeLevel level)
|
||||
: level(level)
|
||||
: TypeOnceVisitor("Quantifier")
|
||||
, level(level)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
|||
LUAU_FASTFLAGVARIABLE(LuauRelateTablesAreNeverDisjoint)
|
||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauMissingSeenSetRelate)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSimplifyAnyAndUnion)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -1426,7 +1427,7 @@ std::optional<TypeId> TypeSimplifier::basicIntersect(TypeId left, TypeId right)
|
|||
|
||||
TypeId TypeSimplifier::intersect(TypeId left, TypeId right)
|
||||
{
|
||||
RecursionLimiter rl(&recursionDepth, 15);
|
||||
RecursionLimiter rl("TypeSimplifier::intersect", &recursionDepth, 15);
|
||||
|
||||
left = simplify(left);
|
||||
right = simplify(right);
|
||||
|
@ -1442,6 +1443,10 @@ TypeId TypeSimplifier::intersect(TypeId left, TypeId right)
|
|||
return right;
|
||||
if (get<UnknownType>(right) && !get<ErrorType>(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))
|
||||
return arena->addType(UnionType{{right, builtinTypes->errorType}});
|
||||
if (get<AnyType>(right))
|
||||
|
@ -1514,7 +1519,7 @@ TypeId TypeSimplifier::intersect(TypeId left, TypeId right)
|
|||
|
||||
TypeId TypeSimplifier::union_(TypeId left, TypeId right)
|
||||
{
|
||||
RecursionLimiter rl(&recursionDepth, 15);
|
||||
RecursionLimiter rl("TypeSimplifier::union", &recursionDepth, 15);
|
||||
|
||||
left = simplify(left);
|
||||
right = simplify(right);
|
||||
|
@ -1602,7 +1607,7 @@ TypeId TypeSimplifier::simplify(TypeId ty)
|
|||
|
||||
TypeId TypeSimplifier::simplify(TypeId ty, DenseHashSet<TypeId>& seen)
|
||||
{
|
||||
RecursionLimiter limiter(&recursionDepth, 60);
|
||||
RecursionLimiter limiter("TypeSimplifier::simplify", &recursionDepth, 60);
|
||||
|
||||
ty = follow(ty);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "Luau/Subtyping.h"
|
||||
|
||||
#include "iostream"
|
||||
#include "Luau/Common.h"
|
||||
#include "Luau/Error.h"
|
||||
#include "Luau/Normalize.h"
|
||||
|
@ -21,7 +22,7 @@ LUAU_FASTINTVARIABLE(LuauSubtypingReasoningLimit, 100)
|
|||
LUAU_FASTFLAGVARIABLE(LuauSubtypingCheckFunctionGenericCounts)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAGVARIABLE(LuauReturnMappedGenericPacksFromSubtyping)
|
||||
LUAU_FASTFLAGVARIABLE(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -78,7 +79,7 @@ static void assertReasoningValid_DEPRECATED(TID subTy, TID superTy, const Subtyp
|
|||
template<typename TID>
|
||||
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)
|
||||
return;
|
||||
|
@ -513,7 +514,7 @@ SubtypingResult Subtyping::isSubtype(TypeId subTy, TypeId superTy, NotNull<Scope
|
|||
* cacheable.
|
||||
*/
|
||||
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
{
|
||||
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);
|
||||
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
{
|
||||
if (!env.mappedGenericPacks.empty())
|
||||
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};
|
||||
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping && !env.mappedGenericPacks.empty())
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2 && !env.mappedGenericPacks.empty())
|
||||
result.mappedGenericPacks = env.mappedGenericPacks;
|
||||
|
||||
if (result.isCacheable)
|
||||
|
@ -572,6 +573,30 @@ struct SeenSetPopper
|
|||
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
|
||||
|
||||
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});
|
||||
if (cachedResult)
|
||||
{
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
{
|
||||
for (const auto& [genericTp, boundTp] : cachedResult->mappedGenericPacks)
|
||||
env.mappedGenericPacks.try_insert(genericTp, boundTp);
|
||||
|
@ -610,7 +635,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
|||
cachedResult = env.tryFindSubtypingResult({subTy, superTy});
|
||||
if (cachedResult)
|
||||
{
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
{
|
||||
for (const auto& [genericTp, boundTp] : cachedResult->mappedGenericPacks)
|
||||
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))
|
||||
result = isCovariantWith(env, p, scope);
|
||||
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
assertReasoningValid(subTy, superTy, result, builtinTypes, arena);
|
||||
else
|
||||
assertReasoningValid_DEPRECATED(subTy, superTy, result, builtinTypes);
|
||||
|
@ -870,6 +895,20 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId
|
|||
subTp = follow(subTp);
|
||||
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 [superHead, superTail] = flatten(superTp);
|
||||
|
||||
|
@ -908,15 +947,32 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId
|
|||
//
|
||||
// <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.
|
||||
std::vector<TypeId> headSlice = FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
||||
? std::vector<TypeId>(begin(superHead) + headSize, end(superHead))
|
||||
: std::vector<TypeId>(begin(superHead), begin(superHead) + headSize);
|
||||
TypePackId superTailPack = arena->addTypePack(std::move(headSlice), superTail);
|
||||
std::vector<TypeId> headSlice = std::vector<TypeId>(begin(superHead), begin(superHead) + headSize);
|
||||
superTailPack = arena->addTypePack(std::move(headSlice), superTail);
|
||||
}
|
||||
|
||||
if (TypePackId* other = env.getMappedPackBounds(*subTail))
|
||||
{
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
{
|
||||
const TypePack* tp = get<TypePack>(*other);
|
||||
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) -> ()
|
||||
|
||||
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.
|
||||
std::vector<TypeId> headSlice = FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
||||
? std::vector<TypeId>(begin(subHead) + headSize, end(subHead))
|
||||
: std::vector<TypeId>(begin(subHead), begin(subHead) + headSize);
|
||||
TypePackId subTailPack = arena->addTypePack(std::move(headSlice), subTail);
|
||||
std::vector<TypeId> headSlice = std::vector<TypeId>(begin(subHead), begin(subHead) + headSize);
|
||||
subTailPack = arena->addTypePack(std::move(headSlice), subTail);
|
||||
}
|
||||
|
||||
if (TypePackId* other = env.getMappedPackBounds(*superTail))
|
||||
{
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
{
|
||||
const TypePack* tp = get<TypePack>(*other);
|
||||
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);
|
||||
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
assertReasoningValid(subTp, superTp, result, builtinTypes, arena);
|
||||
else
|
||||
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);
|
||||
else
|
||||
assertReasoningValid_DEPRECATED(subTy, superTy, result, builtinTypes);
|
||||
|
@ -1198,7 +1271,7 @@ SubtypingResult Subtyping::isInvariantWith(SubtypingEnvironment& env, SubTy&& su
|
|||
reasoning.variance = SubtypingVariance::Invariant;
|
||||
}
|
||||
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
assertReasoningValid(subTy, superTy, result, builtinTypes, arena);
|
||||
else
|
||||
assertReasoningValid_DEPRECATED(subTy, superTy, result, builtinTypes);
|
||||
|
@ -1862,7 +1935,9 @@ SubtypingResult Subtyping::isCovariantWith(
|
|||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
res.andAlso(isInvariantWith(env, *subProp.readTy, *superProp.readTy, scope).withBothComponent(TypePath::Property::read(name)));
|
||||
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
|
||||
{
|
||||
|
@ -2131,6 +2206,13 @@ bool Subtyping::bindGeneric(SubtypingEnvironment& env, TypePackId subTp, TypePac
|
|||
if (TypePackId* m = env.getMappedPackBounds(subTp))
|
||||
return *m == superTp;
|
||||
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
{
|
||||
// We shouldn't bind generic type packs to themselves
|
||||
if (subTp == superTp)
|
||||
return true;
|
||||
}
|
||||
|
||||
env.mappedGenericPacks[subTp] = superTp;
|
||||
|
||||
return true;
|
||||
|
|
|
@ -52,7 +52,11 @@ namespace
|
|||
|
||||
struct FindCyclicTypes final : TypeVisitor
|
||||
{
|
||||
FindCyclicTypes() = default;
|
||||
FindCyclicTypes()
|
||||
: TypeVisitor("FindCyclicTypes")
|
||||
{
|
||||
}
|
||||
|
||||
FindCyclicTypes(const FindCyclicTypes&) = delete;
|
||||
FindCyclicTypes& operator=(const FindCyclicTypes&) = delete;
|
||||
|
||||
|
@ -827,7 +831,9 @@ struct TypeStringifier
|
|||
|
||||
std::string openbrace = "@@@";
|
||||
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:
|
||||
if (FFlag::LuauSolverV2 || FFlag::LuauSolverAgnosticStringification)
|
||||
|
@ -1899,6 +1905,39 @@ std::string dump(const std::optional<TypePackId>& ty)
|
|||
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)
|
||||
{
|
||||
auto binding = scope->linearSearchForBinding(name);
|
||||
|
|
|
@ -446,7 +446,7 @@ bool maybeSingleton(TypeId ty)
|
|||
|
||||
bool hasLength(TypeId ty, DenseHashSet<TypeId>& seen, int* recursionCount)
|
||||
{
|
||||
RecursionLimiter _rl(recursionCount, FInt::LuauTypeInferRecursionLimit);
|
||||
RecursionLimiter _rl("Type::hasLength", recursionCount, FInt::LuauTypeInferRecursionLimit);
|
||||
|
||||
ty = follow(ty);
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
|||
LUAU_FASTFLAG(LuauSubtypingCheckFunctionGenericCounts)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeCheckFunctionCalls)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSuppressErrorsForMultipleNonviableOverloads)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
LUAU_FASTFLAG(LuauInferActualIfElseExprType)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictSuppressSoloConstraintSolvingIncomplete)
|
||||
|
||||
|
@ -161,6 +161,11 @@ struct TypeFunctionFinder : TypeOnceVisitor
|
|||
DenseHashSet<TypeId> mentionedFunctions{nullptr};
|
||||
DenseHashSet<TypePackId> mentionedFunctionPacks{nullptr};
|
||||
|
||||
TypeFunctionFinder()
|
||||
: TypeOnceVisitor("TypeFunctionFinder")
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const TypeFunctionInstanceType&) override
|
||||
{
|
||||
mentionedFunctions.insert(ty);
|
||||
|
@ -182,6 +187,7 @@ struct InternalTypeFunctionFinder : TypeOnceVisitor
|
|||
DenseHashSet<TypePackId> mentionedFunctionPacks{nullptr};
|
||||
|
||||
explicit InternalTypeFunctionFinder(std::vector<TypeId>& declStack)
|
||||
: TypeOnceVisitor("InternalTypeFunctionFinder")
|
||||
{
|
||||
TypeFunctionFinder f;
|
||||
for (TypeId fn : declStack)
|
||||
|
@ -2052,7 +2058,8 @@ void TypeChecker2::visit(AstExprFunction* fn)
|
|||
TypeFunctionReductionGuessResult result = guesser.guessTypeFunctionReductionForFunctionExpr(*fn, inferredFtv, retTy);
|
||||
if (result.shouldRecommendAnnotation && !get<UnknownType>(result.guessedReturnType))
|
||||
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);
|
||||
reportError(
|
||||
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
|
||||
);
|
||||
|
@ -2920,11 +2929,11 @@ Reasonings TypeChecker2::explainReasonings_(TID subTy, TID superTy, Location loc
|
|||
continue;
|
||||
|
||||
std::optional<TypeOrPack> optSubLeaf =
|
||||
FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
||||
FFlag::LuauReturnMappedGenericPacksFromSubtyping2
|
||||
? traverse(subTy, reasoning.subPath, builtinTypes, NotNull{&r.mappedGenericPacks}, subtyping->arena)
|
||||
: traverse_DEPRECATED(subTy, reasoning.subPath, builtinTypes);
|
||||
std::optional<TypeOrPack> optSuperLeaf =
|
||||
FFlag::LuauReturnMappedGenericPacksFromSubtyping
|
||||
FFlag::LuauReturnMappedGenericPacksFromSubtyping2
|
||||
? traverse(superTy, reasoning.superPath, builtinTypes, NotNull{&r.mappedGenericPacks}, subtyping->arena)
|
||||
: traverse_DEPRECATED(superTy, reasoning.superPath, builtinTypes);
|
||||
|
||||
|
|
|
@ -60,6 +60,12 @@ struct InstanceCollector : TypeOnceVisitor
|
|||
std::vector<const void*> typeFunctionInstanceStack;
|
||||
std::vector<TypeId> cyclicInstance;
|
||||
|
||||
|
||||
InstanceCollector()
|
||||
: TypeOnceVisitor("InstanceCollector")
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const TypeFunctionInstanceType& tfit) override
|
||||
{
|
||||
// TypeVisitor performs a depth-first traversal in the absence of
|
||||
|
@ -146,6 +152,11 @@ struct UnscopedGenericFinder : TypeOnceVisitor
|
|||
std::vector<TypePackId> scopeGenTps;
|
||||
bool foundUnscoped = false;
|
||||
|
||||
UnscopedGenericFinder()
|
||||
: TypeOnceVisitor("UnscopedGenericFinder")
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId ty) override
|
||||
{
|
||||
// Once we have found an unscoped generic, we will stop the traversal
|
||||
|
@ -660,8 +671,7 @@ struct TypeFunctionReducer
|
|||
if (tryGuessing(subject))
|
||||
return;
|
||||
|
||||
TypeFunctionReductionResult<TypePackId> result =
|
||||
tfit->function->reducer(subject, tfit->typeArguments, tfit->packArguments, ctx);
|
||||
TypeFunctionReductionResult<TypePackId> result = tfit->function->reducer(subject, tfit->typeArguments, tfit->packArguments, ctx);
|
||||
handleTypeFunctionReduction(subject, std::move(result));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,11 @@ struct InstanceCollector2 : TypeOnceVisitor
|
|||
DenseHashSet<TypeId> cyclicInstance{nullptr};
|
||||
DenseHashSet<TypeId> instanceArguments{nullptr};
|
||||
|
||||
InstanceCollector2()
|
||||
: TypeOnceVisitor("InstanceCollector2")
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const TypeFunctionInstanceType& it) override
|
||||
{
|
||||
// TypeOnceVisitor performs a depth-first traversal in the absence of
|
||||
|
|
|
@ -157,4 +157,4 @@ std::vector<TypeId> TypeIds::take()
|
|||
return std::move(order);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Luau
|
||||
|
|
|
@ -442,7 +442,7 @@ struct InplaceDemoter : TypeOnceVisitor
|
|||
TypeArena* arena;
|
||||
|
||||
InplaceDemoter(TypeLevel level, TypeArena* arena)
|
||||
: TypeOnceVisitor(/* skipBoundTypes= */ true)
|
||||
: TypeOnceVisitor("InplaceDemoter", /* skipBoundTypes= */ true)
|
||||
, newLevel(level)
|
||||
, arena(arena)
|
||||
{
|
||||
|
@ -2150,7 +2150,7 @@ std::optional<TypeId> TypeChecker::getIndexTypeFromTypeImpl(
|
|||
|
||||
for (TypeId t : utv)
|
||||
{
|
||||
RecursionLimiter _rl(&recursionCount, FInt::LuauTypeInferRecursionLimit);
|
||||
RecursionLimiter _rl("TypeInfer::UnionType", &recursionCount, FInt::LuauTypeInferRecursionLimit);
|
||||
|
||||
// Not needed when we normalize types.
|
||||
if (get<AnyType>(follow(t)))
|
||||
|
@ -2189,7 +2189,7 @@ std::optional<TypeId> TypeChecker::getIndexTypeFromTypeImpl(
|
|||
|
||||
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))
|
||||
parts.push_back(*ty);
|
||||
|
@ -4129,7 +4129,9 @@ void TypeChecker::checkArgumentList(
|
|||
auto [minParams, optMaxParams] = getParameterExtents(&state.log, paramPack);
|
||||
state.reportError(TypeError{
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "Luau/Error.h"
|
||||
#include "Luau/TxnLog.h"
|
||||
|
||||
#include <stdexcept>
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
|
||||
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)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauReturnMappedGenericPacksFromSubtyping2);
|
||||
|
||||
tp = mappedGenericPacks.contains(tp) ? *mappedGenericPacks.find(tp) : tp;
|
||||
|
||||
std::vector<TypeId> flattened;
|
||||
std::optional<TypePackId> tail = std::nullopt;
|
||||
DenseHashSet<TypePackId> seenGenericPacks{nullptr};
|
||||
|
||||
while (tp)
|
||||
{
|
||||
|
@ -467,9 +470,10 @@ std::pair<std::vector<TypeId>, std::optional<TypePackId>> flatten(TypePackId tp,
|
|||
for (; it != end(tp); ++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);
|
||||
seenGenericPacks.insert(*tpTail);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <sstream>
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
|
||||
// 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
|
||||
|
@ -285,7 +285,7 @@ struct TraversalState
|
|||
|
||||
TypeOrPack current;
|
||||
NotNull<BuiltinTypes> builtinTypes;
|
||||
// TODO: make these NotNull when LuauReturnMappedGenericPacksFromSubtyping is clipped
|
||||
// TODO: make these NotNull when LuauReturnMappedGenericPacksFromSubtyping2 is clipped
|
||||
const DenseHashMap<TypePackId, TypePackId>* mappedGenericPacks;
|
||||
TypeArena* arena;
|
||||
int steps = 0;
|
||||
|
@ -417,7 +417,7 @@ struct TraversalState
|
|||
{
|
||||
auto currentPack = get<TypePackId>(current);
|
||||
LUAU_ASSERT(currentPack);
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
{
|
||||
if (const auto tp = get<TypePack>(*currentPack))
|
||||
{
|
||||
|
@ -576,7 +576,7 @@ struct TraversalState
|
|||
|
||||
if (auto tail = it.tail())
|
||||
{
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping && mappedGenericPacks && mappedGenericPacks->contains(*tail))
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2 && mappedGenericPacks && mappedGenericPacks->contains(*tail))
|
||||
updateCurrent(*mappedGenericPacks->find(*tail));
|
||||
else
|
||||
updateCurrent(*tail);
|
||||
|
@ -595,9 +595,9 @@ struct TraversalState
|
|||
if (checkInvariants())
|
||||
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
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping)
|
||||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
LUAU_ASSERT(arena && mappedGenericPacks);
|
||||
else if (!arena || !mappedGenericPacks)
|
||||
return false;
|
||||
|
|
|
@ -33,7 +33,8 @@ struct PromoteTypeLevels final : TypeOnceVisitor
|
|||
TypeLevel minLevel;
|
||||
|
||||
PromoteTypeLevels(TxnLog& log, const TypeArena* typeArena, TypeLevel minLevel)
|
||||
: log(log)
|
||||
: TypeOnceVisitor("PromoteTypeLevels")
|
||||
, log(log)
|
||||
, typeArena(typeArena)
|
||||
, minLevel(minLevel)
|
||||
{
|
||||
|
@ -145,7 +146,8 @@ void promoteTypeLevels(TxnLog& log, const TypeArena* typeArena, TypeLevel minLev
|
|||
struct SkipCacheForType final : TypeOnceVisitor
|
||||
{
|
||||
SkipCacheForType(const DenseHashMap<TypeId, bool>& skipCacheForType, const TypeArena* typeArena)
|
||||
: skipCacheForType(skipCacheForType)
|
||||
: TypeOnceVisitor("SkipCacheForType")
|
||||
, skipCacheForType(skipCacheForType)
|
||||
, 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)
|
||||
{
|
||||
RecursionLimiter _ra(&sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
||||
RecursionLimiter _ra("Unifier::tryUnify_", &sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
||||
|
||||
++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)
|
||||
{
|
||||
RecursionLimiter _ra(&sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
||||
RecursionLimiter _ra("Unifier::tryUnify_", &sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
||||
|
||||
++sharedState.counters.iterationCount;
|
||||
|
||||
|
@ -2030,7 +2032,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection,
|
|||
{
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
@ -2048,7 +2050,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection,
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -2120,7 +2122,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection,
|
|||
{
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
@ -2140,7 +2142,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection,
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -2732,7 +2734,7 @@ bool Unifier::occursCheck(TypeId needle, TypeId haystack, bool reversed)
|
|||
|
||||
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;
|
||||
|
||||
|
@ -2806,7 +2808,7 @@ bool Unifier::occursCheck(DenseHashSet<TypePackId>& seen, TypePackId needle, Typ
|
|||
if (!log.getMutable<FreeTypePack>(needle) && !(hideousFixMeGenericsAreActuallyFree && log.is<GenericTypePack>(needle)))
|
||||
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))
|
||||
{
|
||||
|
|
|
@ -722,7 +722,7 @@ TypeId Unifier2::mkIntersection(TypeId left, TypeId right)
|
|||
|
||||
OccursCheckResult Unifier2::occursCheck(DenseHashSet<TypeId>& seen, TypeId needle, TypeId haystack)
|
||||
{
|
||||
RecursionLimiter _ra(&recursionCount, recursionLimit);
|
||||
RecursionLimiter _ra("Unifier2::occursCheck", &recursionCount, recursionLimit);
|
||||
|
||||
OccursCheckResult occurrence = OccursCheckResult::Pass;
|
||||
|
||||
|
@ -784,7 +784,7 @@ OccursCheckResult Unifier2::occursCheck(DenseHashSet<TypePackId>& seen, TypePack
|
|||
if (!getMutable<FreeTypePack>(needle))
|
||||
ice->ice("Expected needle pack to be free");
|
||||
|
||||
RecursionLimiter _ra(&recursionCount, recursionLimit);
|
||||
RecursionLimiter _ra("Unifier2::occursCheck", &recursionCount, recursionLimit);
|
||||
|
||||
while (!getMutable<ErrorTypePack>(haystack))
|
||||
{
|
||||
|
|
|
@ -39,7 +39,7 @@ private:
|
|||
T oldValue;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
struct FindUserTypeFunctionBlockers : TypeOnceVisitor
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ struct FindUserTypeFunctionBlockers : TypeOnceVisitor
|
|||
std::vector<TypeId> blockingTypes;
|
||||
|
||||
explicit FindUserTypeFunctionBlockers(NotNull<TypeFunctionContext> ctx)
|
||||
: TypeOnceVisitor(/* skipBoundTypes */ true)
|
||||
: TypeOnceVisitor("FindUserTypeFunctionBlockers", /* skipBoundTypes */ true)
|
||||
, ctx(ctx)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100)
|
|||
// flag so that we don't break production games by reverting syntax changes.
|
||||
// See docs/SyntaxChanges.md for an explanation.
|
||||
LUAU_FASTFLAGVARIABLE(LuauSolverV2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDeclareExternType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauParseStringIndexer)
|
||||
LUAU_FASTFLAGVARIABLE(LuauParseAttributeFixUninit)
|
||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(DebugLuauReportReturnTypeVariadicWithTypeSuffix, false)
|
||||
|
@ -1249,11 +1248,9 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
|
|||
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;
|
||||
if (FFlag::LuauDeclareExternType)
|
||||
{
|
||||
if (AstName(lexer.current().name) == "extern")
|
||||
{
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nextLexeme();
|
||||
|
||||
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;
|
||||
|
||||
if (AstName(lexer.current().name) == "extends")
|
||||
{
|
||||
nextLexeme();
|
||||
superName = parseName(FFlag::LuauDeclareExternType ? "supertype name" : "superclass name").name;
|
||||
superName = parseName("supertype name").name;
|
||||
}
|
||||
|
||||
if (FFlag::LuauDeclareExternType)
|
||||
{
|
||||
if (foundExtern)
|
||||
{
|
||||
if (AstName(lexer.current().name) != "with")
|
||||
|
@ -1290,7 +1285,7 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
|
|||
else
|
||||
nextLexeme();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TempVector<AstDeclaredExternTypeProperty> props(scratchDeclaredClassProps);
|
||||
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;
|
||||
|
||||
// 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");
|
||||
else
|
||||
report(badIndexer->location, "Cannot have more than one class indexer");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1427,10 +1419,7 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
|
|||
AstTableIndexer* badIndexer = parseTableIndexer(AstTableAccess::ReadWrite, std::nullopt, lexer.current()).node;
|
||||
|
||||
// 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");
|
||||
else
|
||||
report(badIndexer->location, "Cannot have more than one class indexer");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1466,13 +1455,9 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
|
|||
AstType* type = parseType(/* in declaration context */ true);
|
||||
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
|
||||
{
|
||||
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
|
||||
"LuauNormalizationReorderFreeTypeIntersect", // requires fixes in lua-apps code, also terrifyingly
|
||||
"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
|
||||
nullptr,
|
||||
};
|
||||
|
|
|
@ -26,10 +26,8 @@ LUAU_FASTINTVARIABLE(LuauCompileInlineThreshold, 25)
|
|||
LUAU_FASTINTVARIABLE(LuauCompileInlineThresholdMaxBoost, 300)
|
||||
LUAU_FASTINTVARIABLE(LuauCompileInlineDepth, 5)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileInlineNonConstInit)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSeparateCompilerTypeInfo)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileFixTypeFunctionSkip)
|
||||
|
||||
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 (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});
|
||||
else
|
||||
args.push_back({var, uint8_t(reg), {Constant::Type_Unknown}, kDefaultAllocPc});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -725,7 +720,7 @@ struct Compiler
|
|||
{
|
||||
pushLocal(arg.local, arg.reg, arg.allocpc);
|
||||
|
||||
if (FFlag::LuauCompileInlineNonConstInit && arg.init)
|
||||
if (arg.init)
|
||||
{
|
||||
if (Variable* lv = variables.find(arg.local))
|
||||
lv->init = arg.init;
|
||||
|
@ -785,12 +780,9 @@ struct Compiler
|
|||
if (Constant* var = locstants.find(local))
|
||||
var->type = Constant::Type_Unknown;
|
||||
|
||||
if (FFlag::LuauCompileInlineNonConstInit)
|
||||
{
|
||||
if (Variable* lv = variables.find(local))
|
||||
lv->init = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
foldConstants(constants, variables, locstants, builtinsFold, builtinsFoldLibraryK, options.libraryMemberConstantCb, func->body);
|
||||
}
|
||||
|
@ -3956,7 +3948,7 @@ struct Compiler
|
|||
|
||||
bool visit(AstStatTypeFunction* node) override
|
||||
{
|
||||
return !FFlag::LuauCompileFixTypeFunctionSkip;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
#include <limits.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileCostModelConstants)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace Compile
|
||||
|
@ -43,25 +41,6 @@ static uint64_t parallelMulSat(uint64_t a, int b)
|
|||
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
|
||||
{
|
||||
static const uint64_t kLiteral = ~0ull;
|
||||
|
@ -132,7 +111,7 @@ struct CostVisitor : AstVisitor
|
|||
|
||||
Cost model(AstExpr* node)
|
||||
{
|
||||
if (FFlag::LuauCompileCostModelConstants && constants.contains(node))
|
||||
if (constants.contains(node))
|
||||
return Cost(0, Cost::kLiteral);
|
||||
|
||||
if (AstExprGroup* expr = node->as<AstExprGroup>())
|
||||
|
@ -280,17 +259,8 @@ struct CostVisitor : AstVisitor
|
|||
int tripCount = -1;
|
||||
double from, to, step = 1;
|
||||
|
||||
if (FFlag::LuauCompileCostModelConstants)
|
||||
{
|
||||
if (getNumber(node->from, from) && getNumber(node->to, to) && (!node->step || getNumber(node->step, 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);
|
||||
return false;
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
#include "Luau/Lexer.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauCompileInlineNonConstInit)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace Compile
|
||||
|
@ -84,12 +82,9 @@ struct ValueVisitor : AstVisitor
|
|||
}
|
||||
|
||||
bool visit(AstExprFunction* node) override
|
||||
{
|
||||
if (FFlag::LuauCompileInlineNonConstInit)
|
||||
{
|
||||
for (AstLocal* arg : node->args)
|
||||
variables[arg].init = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuauSafeStackCheck, false)
|
||||
|
||||
/*
|
||||
* 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)
|
||||
res = 0; // stack overflow
|
||||
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);
|
||||
}
|
||||
|
||||
expandstacklimit(L, L->top + size);
|
||||
}
|
||||
return res;
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuauErrorYield, false)
|
||||
|
||||
// keep max stack allocation request under 1GB
|
||||
#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
|
||||
}
|
||||
|
||||
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.
|
||||
** 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 cioffset = saveci(L, L->ci);
|
||||
|
||||
if (DFFlag::LuauErrorYield)
|
||||
{
|
||||
performcall(L, func, nresults);
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
|
@ -290,6 +315,7 @@ void luaD_call(lua_State* L, StkId func, int nresults)
|
|||
if (!oldactive)
|
||||
L->isactive = false;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
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 - 1, errfunc);
|
||||
incr_top(L);
|
||||
|
||||
if (DFFlag::LuauErrorYield)
|
||||
luaD_callny(L, L->top - 2, 1);
|
||||
else
|
||||
luaD_call(L, L->top - 2, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,15 +10,16 @@
|
|||
// returns target stack for 'n' extra elements to reallocate
|
||||
// if possible, stack size growth factor is 2x
|
||||
#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) \
|
||||
if ((char*)L->stack_last - (char*)L->top <= (n) * (int)sizeof(TValue)) \
|
||||
if (stacklimitreached(L, (n))) \
|
||||
luaD_reallocstack(L, getgrownstacksize(L, (n)), 1); \
|
||||
else \
|
||||
condhardstacktests(luaD_reallocstack(L, L->stacksize - EXTRA_STACK, 1));
|
||||
|
||||
#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); \
|
||||
else \
|
||||
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 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 void luaD_reallocCI(lua_State* L, int newsize);
|
||||
LUAI_FUNC void luaD_reallocstack(lua_State* L, int newsize, int fornewci);
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauHeapDumpStringSizeOverhead)
|
||||
|
||||
static void validateobjref(global_State* g, GCObject* f, GCObject* 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)
|
||||
{
|
||||
if (FFlag::LuauHeapDumpStringSizeOverhead)
|
||||
enumnode(ctx, obj2gco(ts), sizestring(ts->len), NULL);
|
||||
else
|
||||
enumnode(ctx, obj2gco(ts), ts->len, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,28 +2,200 @@
|
|||
#include "luau.pb.h"
|
||||
|
||||
static const std::string kNames[] = {
|
||||
"_G", "_VERSION", "__add", "__call", "__concat", "__div", "__eq", "__idiv", "__index",
|
||||
"__iter", "__le", "__len", "__lt", "__mod", "__mode", "__mul", "__namecall", "__newindex",
|
||||
"__pow", "__sub", "__type", "__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",
|
||||
"_G",
|
||||
"_VERSION",
|
||||
"__add",
|
||||
"__call",
|
||||
"__concat",
|
||||
"__div",
|
||||
"__eq",
|
||||
"__idiv",
|
||||
"__index",
|
||||
"__iter",
|
||||
"__le",
|
||||
"__len",
|
||||
"__lt",
|
||||
"__mod",
|
||||
"__mode",
|
||||
"__mul",
|
||||
"__namecall",
|
||||
"__newindex",
|
||||
"__pow",
|
||||
"__sub",
|
||||
"__type",
|
||||
"__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[] = {
|
||||
|
@ -46,25 +218,8 @@ static const std::string kExternTypes[] = {
|
|||
};
|
||||
|
||||
static const std::string kBuiltinTypes[] = {
|
||||
"len",
|
||||
"unm",
|
||||
"add",
|
||||
"sub",
|
||||
"mul",
|
||||
"div",
|
||||
"idiv",
|
||||
"pow",
|
||||
"mod",
|
||||
"concat",
|
||||
"lt",
|
||||
"le",
|
||||
"eq",
|
||||
"keyof",
|
||||
"rawkeyof",
|
||||
"index",
|
||||
"rawget",
|
||||
"setmetatable",
|
||||
"getmetatable",
|
||||
"len", "unm", "add", "sub", "mul", "div", "idiv", "pow", "mod", "concat",
|
||||
"lt", "le", "eq", "keyof", "rawkeyof", "index", "rawget", "setmetatable", "getmetatable",
|
||||
};
|
||||
|
||||
struct ProtoToLuau
|
||||
|
|
|
@ -12,7 +12,6 @@ namespace Luau
|
|||
ExternTypeFixture::ExternTypeFixture(bool prepareAutocomplete)
|
||||
: BuiltinsFixture(prepareAutocomplete)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Frontend& ExternTypeFixture::getFrontend()
|
||||
|
@ -37,7 +36,8 @@ Frontend& ExternTypeFixture::getFrontend()
|
|||
};
|
||||
|
||||
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", {}});
|
||||
getMutable<ExternType>(baseClassType)->props = {
|
||||
|
@ -114,7 +114,8 @@ Frontend& ExternTypeFixture::getFrontend()
|
|||
{arena.addType(IntersectionType{{
|
||||
makeFunction(arena, vector2InstanceType, {vector2InstanceType}, {vector2InstanceType}),
|
||||
makeFunction(arena, vector2InstanceType, {getBuiltins()->numberType}, {vector2InstanceType}),
|
||||
}})}}};
|
||||
}})}}
|
||||
};
|
||||
globals.globalScope->exportedTypeBindings["Vector2"] = TypeFun{{}, vector2InstanceType};
|
||||
addGlobalBinding(globals, "Vector2", vector2Type, "@test");
|
||||
|
||||
|
|
|
@ -17,15 +17,12 @@ namespace Luau
|
|||
std::string rep(const std::string& s, size_t n);
|
||||
}
|
||||
|
||||
LUAU_FASTFLAG(LuauCompileInlineNonConstInit)
|
||||
LUAU_FASTINT(LuauCompileInlineDepth)
|
||||
LUAU_FASTINT(LuauCompileInlineThreshold)
|
||||
LUAU_FASTINT(LuauCompileInlineThresholdMaxBoost)
|
||||
LUAU_FASTINT(LuauCompileLoopUnrollThreshold)
|
||||
LUAU_FASTINT(LuauCompileLoopUnrollThresholdMaxBoost)
|
||||
LUAU_FASTINT(LuauRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauCompileFixTypeFunctionSkip)
|
||||
LUAU_FASTFLAG(LuauCompileCostModelConstants)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -2990,8 +2987,6 @@ TEST_CASE("TypeFunction")
|
|||
|
||||
TEST_CASE("NoTypeFunctionsInBytecode")
|
||||
{
|
||||
ScopedFastFlag luauCompileFixTypeFunctionSkip{FFlag::LuauCompileFixTypeFunctionSkip, true};
|
||||
|
||||
Luau::BytecodeBuilder bcb;
|
||||
bcb.setDumpFlags(Luau::BytecodeBuilder::Dump_Code);
|
||||
Luau::compileOrThrow(bcb, R"(
|
||||
|
@ -3616,8 +3611,6 @@ RETURN R4 1
|
|||
|
||||
TEST_CASE("CostModelRemarks")
|
||||
{
|
||||
ScopedFastFlag luauCompileCostModelConstants{FFlag::LuauCompileCostModelConstants, true};
|
||||
|
||||
CHECK_EQ(
|
||||
compileWithRemarks(R"(
|
||||
local a, b = ...
|
||||
|
@ -7624,8 +7617,6 @@ RETURN R1 1
|
|||
|
||||
TEST_CASE("InlineNonConstInitializers")
|
||||
{
|
||||
ScopedFastFlag luauCompileInlineNonConstInit{FFlag::LuauCompileInlineNonConstInit, true};
|
||||
|
||||
CHECK_EQ(
|
||||
"\n" + compileFunction(
|
||||
R"(
|
||||
|
@ -7655,8 +7646,6 @@ RETURN R0 0
|
|||
|
||||
TEST_CASE("InlineNonConstInitializers2")
|
||||
{
|
||||
ScopedFastFlag luauCompileInlineNonConstInit{FFlag::LuauCompileInlineNonConstInit, true};
|
||||
|
||||
CHECK_EQ(
|
||||
"\n" + compileFunction(
|
||||
R"(
|
||||
|
|
|
@ -34,9 +34,13 @@ void luaC_validate(lua_State* L);
|
|||
// internal functions, declared in lvm.h - not exposed via lua.h
|
||||
void luau_callhook(lua_State* L, lua_Hook hook, void* userdata);
|
||||
|
||||
LUAU_FASTFLAG(LuauHeapDumpStringSizeOverhead)
|
||||
LUAU_FASTFLAG(DebugLuauAbortingChecks)
|
||||
LUAU_FASTINT(CodegenHeuristicsInstructionLimit)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_DYNAMIC_FASTFLAG(LuauErrorYield)
|
||||
LUAU_DYNAMIC_FASTFLAG(LuauSafeStackCheck)
|
||||
|
||||
|
||||
static lua_CompileOptions defaultOptions()
|
||||
{
|
||||
|
@ -754,6 +758,8 @@ TEST_CASE("Closure")
|
|||
|
||||
TEST_CASE("Calls")
|
||||
{
|
||||
ScopedFastFlag luauSafeStackCheck{DFFlag::LuauSafeStackCheck, true};
|
||||
|
||||
runConformance("calls.luau");
|
||||
}
|
||||
|
||||
|
@ -816,6 +822,8 @@ TEST_CASE("UTF8")
|
|||
|
||||
TEST_CASE("Coroutine")
|
||||
{
|
||||
ScopedFastFlag luauErrorYield{DFFlag::LuauErrorYield, true};
|
||||
|
||||
runConformance("coroutine.luau");
|
||||
}
|
||||
|
||||
|
@ -2094,13 +2102,33 @@ int slowlyOverflowStack(lua_State* L)
|
|||
|
||||
TEST_CASE("ApiStack")
|
||||
{
|
||||
StateRef globalState(luaL_newstate(), lua_close);
|
||||
lua_State* L = globalState.get();
|
||||
ScopedFastFlag luauSafeStackCheck{DFFlag::LuauSafeStackCheck, true};
|
||||
|
||||
StateRef globalState(lua_newstate(blockableRealloc, nullptr), lua_close);
|
||||
lua_State* GL = globalState.get();
|
||||
|
||||
{
|
||||
lua_State* L = lua_newthread(GL);
|
||||
|
||||
lua_pushcfunction(L, slowlyOverflowStack, "foo");
|
||||
int result = lua_pcall(L, 0, 0, 0);
|
||||
REQUIRE(result == LUA_ERRRUN);
|
||||
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")
|
||||
|
@ -2315,6 +2343,8 @@ TEST_CASE("StringConversion")
|
|||
|
||||
TEST_CASE("GCDump")
|
||||
{
|
||||
ScopedFastFlag luauHeapDumpStringSizeOverhead{FFlag::LuauHeapDumpStringSizeOverhead, true};
|
||||
|
||||
// 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_enumheap(
|
||||
|
@ -2362,14 +2392,15 @@ local function f()
|
|||
x[1] = math.abs(42)
|
||||
end
|
||||
function foo()
|
||||
coroutine.yield()
|
||||
x[2] = ''
|
||||
for i = 1, 10000 do x[2] ..= '1234567890' end
|
||||
end
|
||||
foo()
|
||||
return f
|
||||
)");
|
||||
lua_pushstring(CL, "=GCDump");
|
||||
lua_loadstring(CL);
|
||||
lua_resume(CL, nullptr, 0);
|
||||
REQUIRE(lua_loadstring(CL) == 1);
|
||||
REQUIRE(lua_resume(CL, nullptr, 0) == LUA_OK);
|
||||
|
||||
#ifdef _WIN32
|
||||
const char* path = "NUL";
|
||||
|
@ -2380,6 +2411,7 @@ return f
|
|||
FILE* f = fopen(path, "w");
|
||||
REQUIRE(f);
|
||||
|
||||
luaC_fullgc(L);
|
||||
luaC_dump(L, f, nullptr);
|
||||
|
||||
fclose(f);
|
||||
|
@ -2395,14 +2427,10 @@ return f
|
|||
|
||||
struct EnumContext
|
||||
{
|
||||
EnumContext()
|
||||
: nodes{nullptr}
|
||||
, edges{nullptr}
|
||||
{
|
||||
}
|
||||
Luau::DenseHashMap<void*, Node> nodes{nullptr};
|
||||
Luau::DenseHashMap<void*, void*> edges{nullptr};
|
||||
|
||||
Luau::DenseHashMap<void*, Node> nodes;
|
||||
Luau::DenseHashMap<void*, void*> edges;
|
||||
bool seenTargetString = false;
|
||||
} ctx;
|
||||
|
||||
luaC_enumheap(
|
||||
|
@ -2425,6 +2453,14 @@ return f
|
|||
else if (tt == LUA_TTHREAD)
|
||||
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 : ""};
|
||||
},
|
||||
|
@ -2437,6 +2473,7 @@ return f
|
|||
|
||||
CHECK(!ctx.nodes.empty());
|
||||
CHECK(!ctx.edges.empty());
|
||||
CHECK(ctx.seenTargetString);
|
||||
}
|
||||
|
||||
TEST_CASE("Interrupt")
|
||||
|
@ -3296,6 +3333,7 @@ TEST_CASE("HugeFunctionLoadFailure")
|
|||
REQUIRE_EQ(largeAllocationToFail, expectedTotalLargeAllocations);
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("IrInstructionLimit")
|
||||
{
|
||||
if (!codegen || !luau_codegen_supported())
|
||||
|
|
|
@ -61,7 +61,8 @@ void ConstraintGeneratorFixture::solve(const std::string& code)
|
|||
{},
|
||||
&logger,
|
||||
NotNull{dfg.get()},
|
||||
{}};
|
||||
{}
|
||||
};
|
||||
|
||||
cs.run();
|
||||
}
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
#include "doctest.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauCompileCostModelConstants)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
namespace Luau
|
||||
|
@ -133,37 +131,6 @@ end
|
|||
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")
|
||||
{
|
||||
uint64_t model = modelFunction(R"(
|
||||
|
|
|
@ -135,7 +135,9 @@ TEST_CASE_FIXTURE(ESFixture, "string | never")
|
|||
|
||||
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")
|
||||
|
@ -161,9 +163,9 @@ TEST_CASE_FIXTURE(ESFixture, "never & string")
|
|||
TEST_CASE_FIXTURE(ESFixture, "string & (unknown | never)")
|
||||
{
|
||||
CHECK(
|
||||
"string" == simplifyStr(arena->addType(
|
||||
IntersectionType{{getBuiltins()->stringType, arena->addType(UnionType{{getBuiltins()->unknownType, getBuiltins()->neverType}})}}
|
||||
))
|
||||
"string" == simplifyStr(arena->addType(IntersectionType{
|
||||
{getBuiltins()->stringType, arena->addType(UnionType{{getBuiltins()->unknownType, getBuiltins()->neverType}})}
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -386,7 +388,8 @@ TEST_CASE_FIXTURE(ESFixture, "union<number, number>")
|
|||
{
|
||||
CHECK(
|
||||
"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)")
|
||||
{
|
||||
const TypeId t1 = arena->addType(
|
||||
UnionType{{getBuiltins()->numberType, getBuiltins()->booleanType, getBuiltins()->stringType, getBuiltins()->nilType, getBuiltins()->tableType}}
|
||||
);
|
||||
const TypeId t1 = arena->addType(UnionType{
|
||||
{getBuiltins()->numberType, getBuiltins()->booleanType, getBuiltins()->stringType, getBuiltins()->nilType, getBuiltins()->tableType}
|
||||
});
|
||||
|
||||
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")
|
||||
{
|
||||
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,
|
||||
&configResolver,
|
||||
FrontendOptions{
|
||||
/* retainFullTypeGraphs= */ true, /* forAutocomplete */ false, /* runLintChecks */ false, /* randomConstraintResolutionSeed */ randomSeed}
|
||||
/* retainFullTypeGraphs= */ true, /* forAutocomplete */ false, /* runLintChecks */ false, /* randomConstraintResolutionSeed */ randomSeed
|
||||
}
|
||||
);
|
||||
|
||||
builtinTypes = f.builtinTypes;
|
||||
|
@ -732,7 +733,6 @@ Frontend& Fixture::getFrontend()
|
|||
BuiltinsFixture::BuiltinsFixture(bool prepareAutocomplete)
|
||||
: Fixture(prepareAutocomplete)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Frontend& BuiltinsFixture::getFrontend()
|
||||
|
|
|
@ -185,8 +185,10 @@ struct Fixture
|
|||
// TODO: test theory about dynamic dispatch
|
||||
NotNull<BuiltinTypes> getBuiltins();
|
||||
virtual Frontend& getFrontend();
|
||||
|
||||
private:
|
||||
bool hasDumpedErrors = false;
|
||||
|
||||
protected:
|
||||
bool forAutocomplete = false;
|
||||
std::optional<Frontend> frontend;
|
||||
|
|
|
@ -238,7 +238,7 @@ struct FragmentAutocompleteFixtureImpl : BaseType
|
|||
ParseResult parseResult = parseHelper(document);
|
||||
FrontendOptions options;
|
||||
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()
|
||||
|
@ -3792,11 +3792,17 @@ if result.type == "ok" then
|
|||
result.
|
||||
end
|
||||
)";
|
||||
autocompleteFragmentInOldSolver(source, dest, Position{8, 11}, [](auto& result){
|
||||
autocompleteFragmentInOldSolver(
|
||||
source,
|
||||
dest,
|
||||
Position{8, 11},
|
||||
[](auto& result)
|
||||
{
|
||||
REQUIRE(result.result);
|
||||
CHECK_EQ(result.result->acResults.entryMap.count("type"), 1);
|
||||
CHECK_EQ(result.result->acResults.entryMap.count("value"), 1);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "tagged_union_completion_second_branch_of_union_old_solver")
|
||||
|
@ -3825,11 +3831,17 @@ if result.type == "err" then
|
|||
end
|
||||
)";
|
||||
|
||||
autocompleteFragmentInOldSolver(source, dest, Position{8, 11}, [](auto& result){
|
||||
autocompleteFragmentInOldSolver(
|
||||
source,
|
||||
dest,
|
||||
Position{8, 11},
|
||||
[](auto& result)
|
||||
{
|
||||
REQUIRE(result.result);
|
||||
CHECK_EQ(result.result->acResults.entryMap.count("type"), 1);
|
||||
CHECK_EQ(result.result->acResults.entryMap.count("error"), 1);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "tagged_union_completion_first_branch_of_union_new_solver")
|
||||
|
@ -3858,11 +3870,17 @@ if result.type == "ok" then
|
|||
result.
|
||||
end
|
||||
)";
|
||||
autocompleteFragmentInNewSolver(source, dest, Position{8, 11}, [](auto& result){
|
||||
autocompleteFragmentInNewSolver(
|
||||
source,
|
||||
dest,
|
||||
Position{8, 11},
|
||||
[](auto& result)
|
||||
{
|
||||
REQUIRE(result.result);
|
||||
CHECK_EQ(result.result->acResults.entryMap.count("type"), 1);
|
||||
CHECK_EQ(result.result->acResults.entryMap.count("value"), 1);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "tagged_union_completion_second_branch_of_union_new_solver")
|
||||
|
@ -3891,11 +3909,17 @@ if result.type == "err" then
|
|||
end
|
||||
)";
|
||||
|
||||
autocompleteFragmentInNewSolver(source, dest, Position{8, 11}, [](auto& result){
|
||||
autocompleteFragmentInNewSolver(
|
||||
source,
|
||||
dest,
|
||||
Position{8, 11},
|
||||
[](auto& result)
|
||||
{
|
||||
REQUIRE(result.result);
|
||||
CHECK_EQ(result.result->acResults.entryMap.count("type"), 1);
|
||||
CHECK_EQ(result.result->acResults.entryMap.count("error"), 1);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
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");
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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["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")
|
||||
|
|
|
@ -16,7 +16,7 @@ LUAU_FASTINT(LuauNormalizeIntersectionLimit)
|
|||
LUAU_FASTINT(LuauNormalizeUnionLimit)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
||||
LUAU_FASTFLAG(LuauNormalizationReorderFreeTypeIntersect)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
using namespace Luau;
|
||||
|
||||
namespace
|
||||
|
@ -1223,7 +1223,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_union_type_pack_cycle")
|
|||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauSimplifyOutOfLine2, true},
|
||||
{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true},
|
||||
{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true},
|
||||
};
|
||||
ScopedFastInt sfi{FInt::LuauTypeInferRecursionLimit, 0};
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ LUAU_FASTINT(LuauTypeLengthLimit)
|
|||
LUAU_FASTINT(LuauParseErrorLimit)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauParseStringIndexer)
|
||||
LUAU_FASTFLAG(LuauDeclareExternType)
|
||||
LUAU_DYNAMIC_FASTFLAG(DebugLuauReportReturnTypeVariadicWithTypeSuffix)
|
||||
|
||||
// Clip with DebugLuauReportReturnTypeVariadicWithTypeSuffix
|
||||
|
@ -1999,8 +1998,6 @@ TEST_CASE_FIXTURE(Fixture, "parse_class_declarations")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauDeclareExternType, true};
|
||||
|
||||
AstStatBlock* stat = parseEx(R"(
|
||||
declare extern type Foo with
|
||||
prop: number
|
||||
|
@ -2051,8 +2048,6 @@ TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations_missing_with")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauDeclareExternType, true};
|
||||
|
||||
ParseResult result = tryParse(R"(
|
||||
declare extern type Foo
|
||||
prop: number
|
||||
|
@ -2108,8 +2103,6 @@ TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations_missing_with")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauDeclareExternType, true};
|
||||
|
||||
AstStatBlock* stat = parseEx(R"(
|
||||
declare extern type Foo with
|
||||
prop: number
|
||||
|
@ -2160,8 +2153,6 @@ TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_extern_type_declarations_missing_with")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauDeclareExternType, true};
|
||||
|
||||
ParseResult result = tryParse(R"(
|
||||
declare extern type Foo
|
||||
prop: number
|
||||
|
@ -2281,7 +2272,7 @@ TEST_CASE_FIXTURE(Fixture, "class_indexer")
|
|||
[number]: number
|
||||
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);
|
||||
|
|
|
@ -19,6 +19,9 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauSimplifyAnyAndUnion)
|
||||
|
||||
struct LimitFixture : BuiltinsFixture
|
||||
{
|
||||
|
@ -47,7 +50,7 @@ TEST_CASE_FIXTURE(LimitFixture, "typescript_port_of_Result_type")
|
|||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
constexpr const char* src = R"LUA(
|
||||
constexpr const char* src = R"LUAU(
|
||||
--!strict
|
||||
|
||||
-- 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 {
|
||||
Result = Result,
|
||||
}
|
||||
)LUA";
|
||||
)LUAU";
|
||||
|
||||
CheckResult result = check(src);
|
||||
|
||||
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();
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauSimplifyAnyAndUnion)
|
||||
LUAU_DYNAMIC_FASTINT(LuauSimplificationComplexityLimit)
|
||||
|
||||
namespace
|
||||
|
@ -62,6 +63,7 @@ struct SimplifyFixture : Fixture
|
|||
TypeId anotherChildClassTy = nullptr;
|
||||
TypeId unrelatedClassTy = nullptr;
|
||||
|
||||
// This only affects type stringification.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
SimplifyFixture()
|
||||
|
@ -619,4 +621,26 @@ TEST_CASE_FIXTURE(SimplifyFixture, "cyclic_never_union_and_string")
|
|||
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();
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -1240,11 +1240,19 @@ TEST_CASE_FIXTURE(SubtypeFixture, "(...unknown) -> () <: <T>(T...) -> ()")
|
|||
TEST_CASE_FIXTURE(SubtypeFixture, "bill")
|
||||
{
|
||||
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{
|
||||
{{"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);
|
||||
|
@ -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")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true};
|
||||
ScopedFastFlag sff{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||
|
||||
TypeId longTy = arena.addType(UnionType{
|
||||
{getBuiltins()->booleanType,
|
||||
|
@ -1631,8 +1639,8 @@ TEST_CASE_FIXTURE(SubtypeFixture, "substitute_a_generic_for_a_negation")
|
|||
TypeId bTy = arena.addType(GenericType{"B"});
|
||||
getMutable<GenericType>(bTy)->scope = moduleScope.get();
|
||||
|
||||
TypeId genericFunctionTy =
|
||||
arena.addType(FunctionType{{aTy, bTy}, {}, arena.addTypePack({aTy, bTy}), arena.addTypePack({join(meet(aTy, getBuiltins()->truthyType), bTy)})}
|
||||
TypeId genericFunctionTy = arena.addType(
|
||||
FunctionType{{aTy, bTy}, {}, arena.addTypePack({aTy, bTy}), arena.addTypePack({join(meet(aTy, getBuiltins()->truthyType), bTy)})}
|
||||
);
|
||||
|
||||
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};
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -744,10 +744,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_oss_crash_gh1161")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauStuckTypeFunctionsStillDispatch, true}
|
||||
};
|
||||
ScopedFastFlag sff[] = {{FFlag::LuauEagerGeneralization4, true}, {FFlag::LuauStuckTypeFunctionsStillDispatch, true}};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local EnumVariants = {
|
||||
|
@ -1787,7 +1784,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_should_not_assert_on_empty_string_prop
|
|||
LUAU_REQUIRE_NO_ERRORS(results);
|
||||
CHECK_EQ(R"("" | "one")", toString(requireTypeAlias("FoobarKeys")));
|
||||
CHECK_EQ(R"("" | "two")", toString(requireTypeAlias("TableKeys")));
|
||||
|
||||
}
|
||||
|
||||
struct TFFixture
|
||||
|
@ -1796,7 +1792,10 @@ struct TFFixture
|
|||
NotNull<TypeArena> arena{&arena_};
|
||||
|
||||
BuiltinTypes builtinTypes_;
|
||||
NotNull<BuiltinTypes> getBuiltins(){ return NotNull{&builtinTypes_};}
|
||||
NotNull<BuiltinTypes> getBuiltins()
|
||||
{
|
||||
return NotNull{&builtinTypes_};
|
||||
}
|
||||
|
||||
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);
|
||||
CHECK(
|
||||
toString(result.errors[1]) ==
|
||||
R"(Type function instance get<> is uninhabited)"
|
||||
);
|
||||
CHECK(toString(result.errors[1]) == R"(Type function instance get<> is uninhabited)");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_unreferenced_do_not_block")
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauGuardAgainstMalformedTypeAliasExpansion2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
|
||||
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")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauGuardAgainstMalformedTypeAliasExpansion2, true};
|
||||
|
||||
// This used to crash under the new solver: we would like this to continue
|
||||
// to not crash.
|
||||
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")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauGuardAgainstMalformedTypeAliasExpansion2, true};
|
||||
|
||||
LUAU_REQUIRE_ERRORS(check(R"(
|
||||
export type t138 = t0<t138>
|
||||
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);
|
||||
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
|
||||
|
@ -447,7 +448,8 @@ TEST_CASE_FIXTURE(Fixture, "self_referential_type_alias")
|
|||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
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);
|
||||
|
||||
std::optional<TypeId> firstArg = first(incrFunc->argTypes);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauIntersectNotNil)
|
||||
LUAU_FASTFLAG(LuauSubtypingCheckFunctionGenericCounts)
|
||||
|
@ -18,6 +18,7 @@ LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
|||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAG(DebugLuauAssertOnForcedConstraint)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauContainsAnyGenericFollowBeforeChecking)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -1004,7 +1005,7 @@ local TheDispatcher: Dispatcher = {
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_few")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true};
|
||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function test(a: number)
|
||||
|
@ -1032,7 +1033,7 @@ wrapper(test)
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_many")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true};
|
||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function test2(a: number, b: string)
|
||||
|
@ -1076,7 +1077,7 @@ wrapper(test2, 1, "")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_argument_pack_type_inferred_from_return")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true};
|
||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function test2(a: number)
|
||||
|
@ -1106,7 +1107,7 @@ wrapper(test2, 1)
|
|||
|
||||
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"(
|
||||
function test2(a: number)
|
||||
|
@ -1124,7 +1125,7 @@ wrapper(test2, "hello")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "nested_generic_argument_type_packs")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true};
|
||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function test2(a: number)
|
||||
|
@ -1851,4 +1852,63 @@ end
|
|||
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();
|
||||
|
|
|
@ -12,7 +12,7 @@ using namespace Luau;
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
|
||||
|
@ -1162,7 +1162,7 @@ could not be converted into
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_weird_typepacks_4")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping, true};
|
||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f<a...>()
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -823,7 +823,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cycles_dont_make_everything_any")
|
|||
|
||||
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"(
|
||||
function test2(a: number, b: string)
|
||||
|
|
|
@ -559,7 +559,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "textbook_class_pattern")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag sff[] ={
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
};
|
||||
|
||||
|
@ -591,7 +591,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "textbook_class_pattern_2")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag sff[] ={
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
};
|
||||
|
||||
|
|
|
@ -127,7 +127,8 @@ struct RefinementExternTypeFixture : BuiltinsFixture
|
|||
};
|
||||
|
||||
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 = {
|
||||
{"Part0", 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"(
|
||||
--!strict
|
||||
|
|
|
@ -40,6 +40,7 @@ LUAU_FASTFLAG(LuauDfgForwardNilFromAndOr)
|
|||
LUAU_FASTFLAG(LuauInferActualIfElseExprType)
|
||||
LUAU_FASTFLAG(LuauDoNotPrototypeTableIndex)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauNormalizationLimitTyvarUnionSize)
|
||||
|
||||
TEST_SUITE_BEGIN("TableTests");
|
||||
|
||||
|
@ -6129,7 +6130,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_119126_regression")
|
|||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, results);
|
||||
for (const auto& err: results.errors)
|
||||
for (const auto& err : results.errors)
|
||||
{
|
||||
auto e = get<TypeMismatch>(err);
|
||||
REQUIRE(e);
|
||||
|
@ -6173,5 +6174,23 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1914_access_after_assignment_with_assert
|
|||
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();
|
||||
|
|
|
@ -1984,7 +1984,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "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.
|
||||
CheckResult results = check(R"(
|
||||
local function l0()
|
||||
|
@ -2383,7 +2383,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_remover_heap_use_after_free")
|
|||
local l249 = require(module0)
|
||||
_,_ = {[`{_}`]=_,[_._G._]=(_)(),[_["" + _]._G]={_=_,_=_,[_._G[_]._]=_G,},},_,(_)()
|
||||
)"));
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "fuzzer_missing_follow_in_assign_index_constraint")
|
||||
|
@ -2476,7 +2475,6 @@ TEST_CASE_FIXTURE(Fixture, "oss_1815_verbatim")
|
|||
REQUIRE(err3);
|
||||
CHECK_EQ("\"foo\"", toString(err3->wantedType));
|
||||
CHECK_EQ("\"doge2\"", toString(err3->givenType));
|
||||
|
||||
}
|
||||
|
||||
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(
|
||||
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);
|
||||
|
@ -291,7 +292,8 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "free_tail_is_grown_properly")
|
|||
{
|
||||
TypePackId threeNumbers =
|
||||
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());
|
||||
}
|
||||
|
|
|
@ -710,9 +710,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refinement_through_erroring")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "refinement_through_erroring_in_loop")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true}, {FFlag::LuauDfgAllowUpdatesInLoops, true}
|
||||
};
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauDfgAllowUpdatesInLoops, true}};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!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(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));
|
||||
|
|
|
@ -18,6 +18,8 @@ using namespace Luau::TypePath;
|
|||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypePathMaximumTraverseSteps);
|
||||
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2);
|
||||
|
||||
struct TypePathFixture : Fixture
|
||||
{
|
||||
ScopedFastFlag sff1{FFlag::LuauSolverV2, true};
|
||||
|
@ -494,6 +496,8 @@ TEST_CASE_FIXTURE(TypePathFixture, "tail")
|
|||
|
||||
TEST_CASE_FIXTURE(TypePathFixture, "pack_slice_has_tail")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||
|
||||
TypeArena& arena = getFrontend().globals.globalTypes;
|
||||
unfreeze(arena);
|
||||
|
||||
|
@ -510,6 +514,8 @@ TEST_CASE_FIXTURE(TypePathFixture, "pack_slice_has_tail")
|
|||
|
||||
TEST_CASE_FIXTURE(TypePathFixture, "pack_slice_finite_pack")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true};
|
||||
|
||||
TypeArena& arena = getFrontend().globals.globalTypes;
|
||||
unfreeze(arena);
|
||||
|
||||
|
|
|
@ -365,6 +365,12 @@ struct VisitCountTracker final : TypeOnceVisitor
|
|||
std::unordered_map<TypeId, unsigned> tyVisits;
|
||||
std::unordered_map<TypePackId, unsigned> tpVisits;
|
||||
|
||||
VisitCountTracker()
|
||||
: TypeOnceVisitor("VisitCountTracker")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void cycle(TypeId) 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
|
||||
|
||||
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
|
||||
|
||||
return('OK')
|
||||
|
|
|
@ -382,4 +382,13 @@ do
|
|||
assert(st and msg == nil)
|
||||
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'
|
||||
|
|
Loading…
Add table
Reference in a new issue