mirror of
https://github.com/luau-lang/luau.git
synced 2024-12-13 13:30:40 +00:00
Sync to upstream/release/525 (#467)
This commit is contained in:
parent
74c84815a0
commit
bd6d44f5e3
40 changed files with 527 additions and 641 deletions
|
@ -24,7 +24,7 @@ LUAU_FASTFLAGVARIABLE(LuauKnowsTheDataModel3, false)
|
|||
LUAU_FASTFLAGVARIABLE(LuauSeparateTypechecks, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAutocompleteDynamicLimits, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDirtySourceModule, false)
|
||||
LUAU_FASTINTVARIABLE(LuauAutocompleteCheckTimeoutMs, 0)
|
||||
LUAU_FASTINTVARIABLE(LuauAutocompleteCheckTimeoutMs, 100)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
|
|
@ -2653,12 +2653,12 @@ static void lintComments(LintContext& context, const std::vector<HotComment>& ho
|
|||
}
|
||||
else
|
||||
{
|
||||
std::string::size_type space = hc.content.find_first_of(" \t");
|
||||
size_t space = hc.content.find_first_of(" \t");
|
||||
std::string_view first = std::string_view(hc.content).substr(0, space);
|
||||
|
||||
if (first == "nolint")
|
||||
{
|
||||
std::string::size_type notspace = hc.content.find_first_not_of(" \t", space);
|
||||
size_t notspace = hc.content.find_first_not_of(" \t", space);
|
||||
|
||||
if (space == std::string::npos || notspace == std::string::npos)
|
||||
{
|
||||
|
@ -2827,7 +2827,7 @@ uint64_t LintWarning::parseMask(const std::vector<HotComment>& hotcomments)
|
|||
if (hc.content.compare(0, 6, "nolint") != 0)
|
||||
continue;
|
||||
|
||||
std::string::size_type name = hc.content.find_first_not_of(" \t", 6);
|
||||
size_t name = hc.content.find_first_not_of(" \t", 6);
|
||||
|
||||
// --!nolint disables everything
|
||||
if (name == std::string::npos)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <stdexcept>
|
||||
|
||||
LUAU_FASTFLAG(LuauLowerBoundsCalculation)
|
||||
LUAU_FASTINTVARIABLE(LuauTarjanChildLimit, 1000)
|
||||
LUAU_FASTINTVARIABLE(LuauTarjanChildLimit, 10000)
|
||||
LUAU_FASTFLAG(LuauTypecheckOptPass)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSubstituteFollowNewTypes, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSubstituteFollowPossibleMutations, false)
|
||||
|
|
|
@ -22,29 +22,25 @@
|
|||
#include <iterator>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauMagicTypes, false)
|
||||
LUAU_FASTINTVARIABLE(LuauTypeInferRecursionLimit, 500)
|
||||
LUAU_FASTINTVARIABLE(LuauTypeInferIterationLimit, 2000)
|
||||
LUAU_FASTINTVARIABLE(LuauTypeInferRecursionLimit, 165)
|
||||
LUAU_FASTINTVARIABLE(LuauTypeInferIterationLimit, 20000)
|
||||
LUAU_FASTINTVARIABLE(LuauTypeInferTypePackLoopLimit, 5000)
|
||||
LUAU_FASTINTVARIABLE(LuauCheckRecursionLimit, 500)
|
||||
LUAU_FASTINTVARIABLE(LuauCheckRecursionLimit, 300)
|
||||
LUAU_FASTFLAG(LuauKnowsTheDataModel3)
|
||||
LUAU_FASTFLAG(LuauSeparateTypechecks)
|
||||
LUAU_FASTFLAG(LuauAutocompleteDynamicLimits)
|
||||
LUAU_FASTFLAG(LuauAutocompleteSingletonTypes)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCyclicModuleTypeSurface, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDoNotRelyOnNextBinding, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauEqConstraint, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauWeakEqConstraint, false) // Eventually removed as false.
|
||||
LUAU_FASTFLAGVARIABLE(LuauLowerBoundsCalculation, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauFreezeDuringUnification, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauRecursiveTypeParameterRestriction, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauGenericFunctionsDontCacheTypeParams, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauInferStatFunction, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSealExports, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauInstantiateFollows, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSelfCallAutocompleteFix, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDiscriminableUnions2, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauExpectedTypesOfProperties, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauErrorRecoveryType, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauOnlyMutateInstantiatedTables, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauPropertiesGetExpectedType, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStatFunctionSimplify4, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTypecheckOptPass, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUnsealedTableLiteral, false)
|
||||
|
@ -54,12 +50,9 @@ LUAU_FASTFLAGVARIABLE(LuauReturnAnyInsteadOfICE, false) // Eventually removed as
|
|||
LUAU_FASTFLAG(LuauWidenIfSupertypeIsFree2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDoNotTryToReduce, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDoNotAccidentallyDependOnPointerOrdering, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFixArgumentCountMismatchAmountWithGenericTypes, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFixIncorrectLineNumberDuplicateType, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCheckImplicitNumbericKeys, false)
|
||||
LUAU_FASTFLAG(LuauAnyInIsOptionalIsOptional)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDecoupleOperatorInferenceFromUnifiedTypeInference, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauArgCountMismatchSaysAtLeastWhenVariadic, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTableUseCounterInstead, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauReturnTypeInferenceInNonstrict, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauRecursionLimitException, false);
|
||||
|
@ -1160,7 +1153,10 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatForIn& forin)
|
|||
}
|
||||
else
|
||||
{
|
||||
iterTy = follow(instantiate(scope, checkExpr(scope, *firstValue).type, firstValue->location));
|
||||
if (FFlag::LuauInstantiateFollows)
|
||||
iterTy = instantiate(scope, checkExpr(scope, *firstValue).type, firstValue->location);
|
||||
else
|
||||
iterTy = follow(instantiate(scope, checkExpr(scope, *firstValue).type, firstValue->location));
|
||||
}
|
||||
|
||||
const FunctionTypeVar* iterFunc = get<FunctionTypeVar>(iterTy);
|
||||
|
@ -1172,7 +1168,12 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatForIn& forin)
|
|||
unify(varTy, var, forin.location);
|
||||
|
||||
if (!get<ErrorTypeVar>(iterTy) && !get<AnyTypeVar>(iterTy) && !get<FreeTypeVar>(iterTy))
|
||||
reportError(TypeError{firstValue->location, TypeMismatch{globalScope->bindings[AstName{"next"}].typeId, iterTy}});
|
||||
{
|
||||
if (FFlag::LuauDoNotRelyOnNextBinding)
|
||||
reportError(firstValue->location, CannotCallNonFunction{iterTy});
|
||||
else
|
||||
reportError(TypeError{firstValue->location, TypeMismatch{globalScope->bindings[AstName{"next"}].typeId, iterTy}});
|
||||
}
|
||||
|
||||
return check(loopScope, *forin.body);
|
||||
}
|
||||
|
@ -1427,8 +1428,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatTypeAlias& typealias
|
|||
ftv->forwardedTypeAlias = true;
|
||||
bindingsMap[name] = {std::move(generics), std::move(genericPacks), ty};
|
||||
|
||||
if (FFlag::LuauFixIncorrectLineNumberDuplicateType)
|
||||
scope->typeAliasLocations[name] = typealias.location;
|
||||
scope->typeAliasLocations[name] = typealias.location;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2217,7 +2217,7 @@ TypeId TypeChecker::checkExprTable(
|
|||
if (isNonstrictMode() && !getTableType(exprType) && !get<FunctionTypeVar>(exprType))
|
||||
exprType = anyType;
|
||||
|
||||
if (FFlag::LuauPropertiesGetExpectedType && expectedTable)
|
||||
if (expectedTable)
|
||||
{
|
||||
auto it = expectedTable->props.find(key->value.data);
|
||||
if (it != expectedTable->props.end())
|
||||
|
@ -2309,9 +2309,8 @@ ExprResult<TypeId> TypeChecker::checkExpr_(const ScopePtr& scope, const AstExprT
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (FFlag::LuauExpectedTypesOfProperties)
|
||||
if (const UnionTypeVar* utv = get<UnionTypeVar>(follow(*expectedType)))
|
||||
expectedUnion = utv;
|
||||
else if (const UnionTypeVar* utv = get<UnionTypeVar>(follow(*expectedType)))
|
||||
expectedUnion = utv;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < expr.items.size; ++i)
|
||||
|
@ -2334,7 +2333,7 @@ ExprResult<TypeId> TypeChecker::checkExpr_(const ScopePtr& scope, const AstExprT
|
|||
if (auto prop = expectedTable->props.find(key->value.data); prop != expectedTable->props.end())
|
||||
expectedResultType = prop->second.type;
|
||||
}
|
||||
else if (FFlag::LuauExpectedTypesOfProperties && expectedUnion)
|
||||
else if (expectedUnion)
|
||||
{
|
||||
std::vector<TypeId> expectedResultTypes;
|
||||
for (TypeId expectedOption : expectedUnion)
|
||||
|
@ -2713,8 +2712,6 @@ TypeId TypeChecker::checkBinaryOperation(
|
|||
{
|
||||
auto name = getIdentifierOfBaseVar(expr.left);
|
||||
reportError(expr.location, CannotInferBinaryOperation{expr.op, name, CannotInferBinaryOperation::Operation});
|
||||
if (!FFlag::LuauErrorRecoveryType)
|
||||
return errorRecoveryType(scope);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2754,7 +2751,7 @@ TypeId TypeChecker::checkBinaryOperation(
|
|||
reportErrors(state.errors);
|
||||
bool hasErrors = !state.errors.empty();
|
||||
|
||||
if (FFlag::LuauErrorRecoveryType && hasErrors)
|
||||
if (hasErrors)
|
||||
{
|
||||
// If there are unification errors, the return type may still be unknown
|
||||
// so we loosen the argument types to see if that helps.
|
||||
|
@ -2768,8 +2765,7 @@ TypeId TypeChecker::checkBinaryOperation(
|
|||
if (state.errors.empty())
|
||||
state.log.commit();
|
||||
}
|
||||
|
||||
if (!hasErrors)
|
||||
else
|
||||
{
|
||||
state.log.commit();
|
||||
}
|
||||
|
@ -3196,16 +3192,7 @@ TypeId TypeChecker::checkFunctionName(const ScopePtr& scope, AstExpr& funName, T
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!ttv)
|
||||
{
|
||||
if (!FFlag::LuauErrorRecoveryType && !isTableIntersection(lhsType))
|
||||
// This error now gets reported when we check the function body.
|
||||
reportError(TypeError{funName.location, OnlyTablesCanHaveMethods{lhsType}});
|
||||
|
||||
return errorRecoveryType(scope);
|
||||
}
|
||||
|
||||
if (lhsType->persistent || ttv->state == TableState::Sealed)
|
||||
if (!ttv || lhsType->persistent || ttv->state == TableState::Sealed)
|
||||
return errorRecoveryType(scope);
|
||||
}
|
||||
|
||||
|
@ -3532,32 +3519,6 @@ ExprResult<TypePackId> TypeChecker::checkExprPack(const ScopePtr& scope, const A
|
|||
}
|
||||
|
||||
// Returns the minimum number of arguments the argument list can accept.
|
||||
static size_t getMinParameterCount_DEPRECATED(TypePackId tp)
|
||||
{
|
||||
size_t minCount = 0;
|
||||
size_t optionalCount = 0;
|
||||
|
||||
auto it = begin(tp);
|
||||
auto endIter = end(tp);
|
||||
|
||||
while (it != endIter)
|
||||
{
|
||||
TypeId ty = *it;
|
||||
if (isOptional(ty))
|
||||
++optionalCount;
|
||||
else
|
||||
{
|
||||
minCount += optionalCount;
|
||||
optionalCount = 0;
|
||||
minCount++;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
return minCount;
|
||||
}
|
||||
|
||||
static size_t getMinParameterCount(TxnLog* log, TypePackId tp)
|
||||
{
|
||||
size_t minCount = 0;
|
||||
|
@ -3597,19 +3558,14 @@ void TypeChecker::checkArgumentList(
|
|||
|
||||
size_t paramIndex = 0;
|
||||
|
||||
size_t minParams = FFlag::LuauFixIncorrectLineNumberDuplicateType ? 0 : getMinParameterCount_DEPRECATED(paramPack);
|
||||
|
||||
auto reportCountMismatchError = [&state, &argLocations, minParams, paramPack, argPack]() {
|
||||
auto reportCountMismatchError = [&state, &argLocations, paramPack, argPack]() {
|
||||
// For this case, we want the error span to cover every errant extra parameter
|
||||
Location location = state.location;
|
||||
if (!argLocations.empty())
|
||||
location = {state.location.begin, argLocations.back().end};
|
||||
|
||||
size_t mp = minParams;
|
||||
if (FFlag::LuauFixArgumentCountMismatchAmountWithGenericTypes)
|
||||
mp = getMinParameterCount(&state.log, paramPack);
|
||||
|
||||
state.reportError(TypeError{location, CountMismatch{mp, std::distance(begin(argPack), end(argPack))}});
|
||||
size_t minParams = getMinParameterCount(&state.log, paramPack);
|
||||
state.reportError(TypeError{location, CountMismatch{minParams, std::distance(begin(argPack), end(argPack))}});
|
||||
};
|
||||
|
||||
while (true)
|
||||
|
@ -3707,16 +3663,10 @@ void TypeChecker::checkArgumentList(
|
|||
} // ok
|
||||
else
|
||||
{
|
||||
if (FFlag::LuauFixArgumentCountMismatchAmountWithGenericTypes)
|
||||
minParams = getMinParameterCount(&state.log, paramPack);
|
||||
size_t minParams = getMinParameterCount(&state.log, paramPack);
|
||||
|
||||
bool isVariadic = false;
|
||||
if (FFlag::LuauArgCountMismatchSaysAtLeastWhenVariadic)
|
||||
{
|
||||
std::optional<TypePackId> tail = flatten(paramPack, state.log).second;
|
||||
if (tail)
|
||||
isVariadic = Luau::isVariadic(*tail);
|
||||
}
|
||||
std::optional<TypePackId> tail = flatten(paramPack, state.log).second;
|
||||
bool isVariadic = tail && Luau::isVariadic(*tail);
|
||||
|
||||
state.reportError(TypeError{state.location, CountMismatch{minParams, paramIndex, CountMismatch::Context::Arg, isVariadic}});
|
||||
return;
|
||||
|
@ -3863,7 +3813,8 @@ ExprResult<TypePackId> TypeChecker::checkExprPack(const ScopePtr& scope, const A
|
|||
actualFunctionType = instantiate(scope, functionType, expr.func->location);
|
||||
}
|
||||
|
||||
actualFunctionType = follow(actualFunctionType);
|
||||
if (!FFlag::LuauInstantiateFollows)
|
||||
actualFunctionType = follow(actualFunctionType);
|
||||
|
||||
TypePackId retPack;
|
||||
if (FFlag::LuauLowerBoundsCalculation || !FFlag::LuauWidenIfSupertypeIsFree2)
|
||||
|
@ -3930,16 +3881,13 @@ ExprResult<TypePackId> TypeChecker::checkExprPack(const ScopePtr& scope, const A
|
|||
|
||||
reportOverloadResolutionError(scope, expr, retPack, argPack, argLocations, overloads, overloadsThatMatchArgCount, errors);
|
||||
|
||||
if (FFlag::LuauErrorRecoveryType)
|
||||
{
|
||||
const FunctionTypeVar* overload = nullptr;
|
||||
if (!overloadsThatMatchArgCount.empty())
|
||||
overload = get<FunctionTypeVar>(overloadsThatMatchArgCount[0]);
|
||||
if (!overload && !overloadsThatDont.empty())
|
||||
overload = get<FunctionTypeVar>(overloadsThatDont[0]);
|
||||
if (overload)
|
||||
return {errorRecoveryTypePack(overload->retType)};
|
||||
}
|
||||
const FunctionTypeVar* overload = nullptr;
|
||||
if (!overloadsThatMatchArgCount.empty())
|
||||
overload = get<FunctionTypeVar>(overloadsThatMatchArgCount[0]);
|
||||
if (!overload && !overloadsThatDont.empty())
|
||||
overload = get<FunctionTypeVar>(overloadsThatDont[0]);
|
||||
if (overload)
|
||||
return {errorRecoveryTypePack(overload->retType)};
|
||||
|
||||
return {errorRecoveryTypePack(retPack)};
|
||||
}
|
||||
|
@ -4129,7 +4077,7 @@ std::optional<ExprResult<TypePackId>> TypeChecker::checkCallOverload(const Scope
|
|||
|
||||
if (!argMismatch)
|
||||
overloadsThatMatchArgCount.push_back(fn);
|
||||
else if (FFlag::LuauErrorRecoveryType)
|
||||
else
|
||||
overloadsThatDont.push_back(fn);
|
||||
|
||||
errors.emplace_back(std::move(state.errors), args->head, ftv);
|
||||
|
@ -4715,7 +4663,7 @@ bool Anyification::isDirty(TypeId ty)
|
|||
return false;
|
||||
|
||||
if (const TableTypeVar* ttv = log->getMutable<TableTypeVar>(ty))
|
||||
return (ttv->state == TableState::Free || (FFlag::LuauSealExports && ttv->state == TableState::Unsealed));
|
||||
return (ttv->state == TableState::Free || ttv->state == TableState::Unsealed);
|
||||
else if (log->getMutable<FreeTypeVar>(ty))
|
||||
return true;
|
||||
else if (get<ConstrainedTypeVar>(ty))
|
||||
|
@ -4743,12 +4691,9 @@ TypeId Anyification::clean(TypeId ty)
|
|||
TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, ttv->level, TableState::Sealed};
|
||||
clone.methodDefinitionLocations = ttv->methodDefinitionLocations;
|
||||
clone.definitionModuleName = ttv->definitionModuleName;
|
||||
if (FFlag::LuauSealExports)
|
||||
{
|
||||
clone.name = ttv->name;
|
||||
clone.syntheticName = ttv->syntheticName;
|
||||
clone.tags = ttv->tags;
|
||||
}
|
||||
clone.name = ttv->name;
|
||||
clone.syntheticName = ttv->syntheticName;
|
||||
clone.tags = ttv->tags;
|
||||
TypeId res = addType(std::move(clone));
|
||||
asMutable(res)->normal = ty->normal;
|
||||
return res;
|
||||
|
@ -4791,9 +4736,12 @@ TypeId TypeChecker::quantify(const ScopePtr& scope, TypeId ty, Location location
|
|||
|
||||
TypeId TypeChecker::instantiate(const ScopePtr& scope, TypeId ty, Location location, const TxnLog* log)
|
||||
{
|
||||
if (FFlag::LuauInstantiateFollows)
|
||||
ty = follow(ty);
|
||||
|
||||
if (FFlag::LuauTypecheckOptPass)
|
||||
{
|
||||
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
|
||||
const FunctionTypeVar* ftv = get<FunctionTypeVar>(FFlag::LuauInstantiateFollows ? ty : follow(ty));
|
||||
if (ftv && ftv->hasNoGenerics)
|
||||
return ty;
|
||||
}
|
||||
|
@ -5175,8 +5123,6 @@ TypeId TypeChecker::resolveType(const ScopePtr& scope, const AstType& annotation
|
|||
{
|
||||
reportError(TypeError{annotation.location, GenericError{"Type parameter list is required"}});
|
||||
parameterCountErrorReported = true;
|
||||
if (!FFlag::LuauErrorRecoveryType)
|
||||
return errorRecoveryType(scope);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5294,33 +5240,25 @@ TypeId TypeChecker::resolveType(const ScopePtr& scope, const AstType& annotation
|
|||
reportError(
|
||||
TypeError{annotation.location, IncorrectGenericParameterCount{lit->name.value, *tf, typeParams.size(), typePackParams.size()}});
|
||||
|
||||
if (FFlag::LuauErrorRecoveryType)
|
||||
{
|
||||
// Pad the types out with error recovery types
|
||||
while (typeParams.size() < tf->typeParams.size())
|
||||
typeParams.push_back(errorRecoveryType(scope));
|
||||
while (typePackParams.size() < tf->typePackParams.size())
|
||||
typePackParams.push_back(errorRecoveryTypePack(scope));
|
||||
}
|
||||
else
|
||||
return errorRecoveryType(scope);
|
||||
// Pad the types out with error recovery types
|
||||
while (typeParams.size() < tf->typeParams.size())
|
||||
typeParams.push_back(errorRecoveryType(scope));
|
||||
while (typePackParams.size() < tf->typePackParams.size())
|
||||
typePackParams.push_back(errorRecoveryTypePack(scope));
|
||||
}
|
||||
|
||||
if (FFlag::LuauRecursiveTypeParameterRestriction)
|
||||
{
|
||||
bool sameTys = std::equal(typeParams.begin(), typeParams.end(), tf->typeParams.begin(), tf->typeParams.end(), [](auto&& itp, auto&& tp) {
|
||||
return itp == tp.ty;
|
||||
bool sameTys = std::equal(typeParams.begin(), typeParams.end(), tf->typeParams.begin(), tf->typeParams.end(), [](auto&& itp, auto&& tp) {
|
||||
return itp == tp.ty;
|
||||
});
|
||||
bool sameTps = std::equal(
|
||||
typePackParams.begin(), typePackParams.end(), tf->typePackParams.begin(), tf->typePackParams.end(), [](auto&& itpp, auto&& tpp) {
|
||||
return itpp == tpp.tp;
|
||||
});
|
||||
bool sameTps = std::equal(
|
||||
typePackParams.begin(), typePackParams.end(), tf->typePackParams.begin(), tf->typePackParams.end(), [](auto&& itpp, auto&& tpp) {
|
||||
return itpp == tpp.tp;
|
||||
});
|
||||
|
||||
// If the generic parameters and the type arguments are the same, we are about to
|
||||
// perform an identity substitution, which we can just short-circuit.
|
||||
if (sameTys && sameTps)
|
||||
return tf->type;
|
||||
}
|
||||
// If the generic parameters and the type arguments are the same, we are about to
|
||||
// perform an identity substitution, which we can just short-circuit.
|
||||
if (sameTys && sameTps)
|
||||
return tf->type;
|
||||
|
||||
return instantiateTypeFun(scope, *tf, typeParams, typePackParams, annotation.location);
|
||||
}
|
||||
|
@ -5483,7 +5421,7 @@ bool ApplyTypeFunction::isDirty(TypeId ty)
|
|||
return true;
|
||||
else if (const FreeTypeVar* ftv = get<FreeTypeVar>(ty))
|
||||
{
|
||||
if (FFlag::LuauRecursiveTypeParameterRestriction && ftv->forwardedTypeAlias)
|
||||
if (ftv->forwardedTypeAlias)
|
||||
encounteredForwardedType = true;
|
||||
return false;
|
||||
}
|
||||
|
@ -5562,7 +5500,7 @@ TypeId TypeChecker::instantiateTypeFun(const ScopePtr& scope, const TypeFun& tf,
|
|||
reportError(location, UnificationTooComplex{});
|
||||
return errorRecoveryType(scope);
|
||||
}
|
||||
if (FFlag::LuauRecursiveTypeParameterRestriction && applyTypeFunction.encounteredForwardedType)
|
||||
if (applyTypeFunction.encounteredForwardedType)
|
||||
{
|
||||
reportError(TypeError{location, GenericError{"Recursive type being used with different parameters"}});
|
||||
return errorRecoveryType(scope);
|
||||
|
@ -5632,7 +5570,7 @@ GenericTypeDefinitions TypeChecker::createGenericTypes(const ScopePtr& scope, st
|
|||
}
|
||||
|
||||
TypeId g;
|
||||
if (FFlag::LuauRecursiveTypeParameterRestriction && (!FFlag::LuauGenericFunctionsDontCacheTypeParams || useCache))
|
||||
if (useCache)
|
||||
{
|
||||
TypeId& cached = scope->parent->typeAliasTypeParameters[n];
|
||||
if (!cached)
|
||||
|
@ -5667,21 +5605,12 @@ GenericTypeDefinitions TypeChecker::createGenericTypes(const ScopePtr& scope, st
|
|||
reportError(TypeError{node.location, DuplicateGenericParameter{n}});
|
||||
}
|
||||
|
||||
TypePackId g;
|
||||
if (FFlag::LuauRecursiveTypeParameterRestriction)
|
||||
{
|
||||
TypePackId& cached = scope->parent->typeAliasTypePackParameters[n];
|
||||
if (!cached)
|
||||
cached = addTypePack(TypePackVar{Unifiable::Generic{level, n}});
|
||||
g = cached;
|
||||
}
|
||||
else
|
||||
{
|
||||
g = addTypePack(TypePackVar{Unifiable::Generic{level, n}});
|
||||
}
|
||||
TypePackId& cached = scope->parent->typeAliasTypePackParameters[n];
|
||||
if (!cached)
|
||||
cached = addTypePack(TypePackVar{Unifiable::Generic{level, n}});
|
||||
|
||||
genericPacks.push_back({g, defaultValue});
|
||||
scope->privateTypePackBindings[n] = g;
|
||||
genericPacks.push_back({cached, defaultValue});
|
||||
scope->privateTypePackBindings[n] = cached;
|
||||
}
|
||||
|
||||
return {generics, genericPacks};
|
||||
|
|
|
@ -23,7 +23,6 @@ LUAU_FASTFLAG(DebugLuauFreezeArena)
|
|||
LUAU_FASTINTVARIABLE(LuauTypeMaximumStringifierLength, 500)
|
||||
LUAU_FASTINTVARIABLE(LuauTableTypeMaximumStringifierLength, 0)
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauErrorRecoveryType)
|
||||
LUAU_FASTFLAG(LuauSubtypingAddOptPropsToUnsealedTables)
|
||||
LUAU_FASTFLAG(LuauDiscriminableUnions2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAnyInIsOptionalIsOptional, false)
|
||||
|
@ -775,18 +774,12 @@ TypePackId SingletonTypes::errorRecoveryTypePack()
|
|||
|
||||
TypeId SingletonTypes::errorRecoveryType(TypeId guess)
|
||||
{
|
||||
if (FFlag::LuauErrorRecoveryType)
|
||||
return guess;
|
||||
else
|
||||
return &errorType_;
|
||||
return guess;
|
||||
}
|
||||
|
||||
TypePackId SingletonTypes::errorRecoveryTypePack(TypePackId guess)
|
||||
{
|
||||
if (FFlag::LuauErrorRecoveryType)
|
||||
return guess;
|
||||
else
|
||||
return &errorTypePack_;
|
||||
return guess;
|
||||
}
|
||||
|
||||
SingletonTypes& getSingletonTypes()
|
||||
|
|
|
@ -23,10 +23,7 @@ LUAU_FASTFLAG(LuauErrorRecoveryType);
|
|||
LUAU_FASTFLAGVARIABLE(LuauSubtypingAddOptPropsToUnsealedTables, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauWidenIfSupertypeIsFree2, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDifferentOrderOfUnificationDoesntMatter, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTxnLogSeesTypePacks2, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTxnLogCheckForInvalidation, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTxnLogRefreshFunctionPointers, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTxnLogDontRetryForIndexers, false)
|
||||
LUAU_FASTFLAG(LuauAnyInIsOptionalIsOptional)
|
||||
LUAU_FASTFLAG(LuauTypecheckOptPass)
|
||||
|
||||
|
@ -1021,7 +1018,7 @@ void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCal
|
|||
if (superTp == subTp)
|
||||
return;
|
||||
|
||||
if (FFlag::LuauTxnLogSeesTypePacks2 && log.haveSeen(superTp, subTp))
|
||||
if (log.haveSeen(superTp, subTp))
|
||||
return;
|
||||
|
||||
if (log.getMutable<Unifiable::Free>(superTp))
|
||||
|
@ -1265,12 +1262,9 @@ void Unifier::tryUnifyFunctions(TypeId subTy, TypeId superTy, bool isFunctionCal
|
|||
log.pushSeen(superFunction->generics[i], subFunction->generics[i]);
|
||||
}
|
||||
|
||||
if (FFlag::LuauTxnLogSeesTypePacks2)
|
||||
for (size_t i = 0; i < numGenericPacks; i++)
|
||||
{
|
||||
for (size_t i = 0; i < numGenericPacks; i++)
|
||||
{
|
||||
log.pushSeen(superFunction->genericPacks[i], subFunction->genericPacks[i]);
|
||||
}
|
||||
log.pushSeen(superFunction->genericPacks[i], subFunction->genericPacks[i]);
|
||||
}
|
||||
|
||||
CountMismatch::Context context = ctx;
|
||||
|
@ -1330,12 +1324,9 @@ void Unifier::tryUnifyFunctions(TypeId subTy, TypeId superTy, bool isFunctionCal
|
|||
|
||||
ctx = context;
|
||||
|
||||
if (FFlag::LuauTxnLogSeesTypePacks2)
|
||||
for (int i = int(numGenericPacks) - 1; 0 <= i; i--)
|
||||
{
|
||||
for (int i = int(numGenericPacks) - 1; 0 <= i; i--)
|
||||
{
|
||||
log.popSeen(superFunction->genericPacks[i], subFunction->genericPacks[i]);
|
||||
}
|
||||
log.popSeen(superFunction->genericPacks[i], subFunction->genericPacks[i]);
|
||||
}
|
||||
|
||||
for (int i = int(numGenerics) - 1; 0 <= i; i--)
|
||||
|
@ -1499,20 +1490,17 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection)
|
|||
else
|
||||
missingProperties.push_back(name);
|
||||
|
||||
if (FFlag::LuauTxnLogCheckForInvalidation)
|
||||
// Recursive unification can change the txn log, and invalidate the old
|
||||
// table. If we detect that this has happened, we start over, with the updated
|
||||
// txn log.
|
||||
TableTypeVar* newSuperTable = log.getMutable<TableTypeVar>(superTy);
|
||||
TableTypeVar* newSubTable = log.getMutable<TableTypeVar>(subTy);
|
||||
if (superTable != newSuperTable || subTable != newSubTable)
|
||||
{
|
||||
// Recursive unification can change the txn log, and invalidate the old
|
||||
// table. If we detect that this has happened, we start over, with the updated
|
||||
// txn log.
|
||||
TableTypeVar* newSuperTable = log.getMutable<TableTypeVar>(superTy);
|
||||
TableTypeVar* newSubTable = log.getMutable<TableTypeVar>(subTy);
|
||||
if (superTable != newSuperTable || subTable != newSubTable)
|
||||
{
|
||||
if (errors.empty())
|
||||
return tryUnifyTables(subTy, superTy, isIntersection);
|
||||
else
|
||||
return;
|
||||
}
|
||||
if (errors.empty())
|
||||
return tryUnifyTables(subTy, superTy, isIntersection);
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1570,20 +1558,17 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection)
|
|||
else
|
||||
extraProperties.push_back(name);
|
||||
|
||||
if (FFlag::LuauTxnLogCheckForInvalidation)
|
||||
// Recursive unification can change the txn log, and invalidate the old
|
||||
// table. If we detect that this has happened, we start over, with the updated
|
||||
// txn log.
|
||||
TableTypeVar* newSuperTable = log.getMutable<TableTypeVar>(superTy);
|
||||
TableTypeVar* newSubTable = log.getMutable<TableTypeVar>(subTy);
|
||||
if (superTable != newSuperTable || subTable != newSubTable)
|
||||
{
|
||||
// Recursive unification can change the txn log, and invalidate the old
|
||||
// table. If we detect that this has happened, we start over, with the updated
|
||||
// txn log.
|
||||
TableTypeVar* newSuperTable = log.getMutable<TableTypeVar>(superTy);
|
||||
TableTypeVar* newSubTable = log.getMutable<TableTypeVar>(subTy);
|
||||
if (superTable != newSuperTable || subTable != newSubTable)
|
||||
{
|
||||
if (errors.empty())
|
||||
return tryUnifyTables(subTy, superTy, isIntersection);
|
||||
else
|
||||
return;
|
||||
}
|
||||
if (errors.empty())
|
||||
return tryUnifyTables(subTy, superTy, isIntersection);
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1630,27 +1615,9 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection)
|
|||
}
|
||||
}
|
||||
|
||||
if (FFlag::LuauTxnLogDontRetryForIndexers)
|
||||
{
|
||||
// Changing the indexer can invalidate the table pointers.
|
||||
superTable = log.getMutable<TableTypeVar>(superTy);
|
||||
subTable = log.getMutable<TableTypeVar>(subTy);
|
||||
}
|
||||
else if (FFlag::LuauTxnLogCheckForInvalidation)
|
||||
{
|
||||
// Recursive unification can change the txn log, and invalidate the old
|
||||
// table. If we detect that this has happened, we start over, with the updated
|
||||
// txn log.
|
||||
TableTypeVar* newSuperTable = log.getMutable<TableTypeVar>(superTy);
|
||||
TableTypeVar* newSubTable = log.getMutable<TableTypeVar>(subTy);
|
||||
if (superTable != newSuperTable || subTable != newSubTable)
|
||||
{
|
||||
if (errors.empty())
|
||||
return tryUnifyTables(subTy, superTy, isIntersection);
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Changing the indexer can invalidate the table pointers.
|
||||
superTable = log.getMutable<TableTypeVar>(superTy);
|
||||
subTable = log.getMutable<TableTypeVar>(subTy);
|
||||
|
||||
if (!missingProperties.empty())
|
||||
{
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
#include <limits.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauParseLocationIgnoreCommentSkip, false)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -361,7 +359,7 @@ const Lexeme& Lexer::next(bool skipComments, bool updatePrevLocation)
|
|||
while (isSpace(peekch()))
|
||||
consume();
|
||||
|
||||
if (!FFlag::LuauParseLocationIgnoreCommentSkip || updatePrevLocation)
|
||||
if (updatePrevLocation)
|
||||
prevLocation = lexeme.location;
|
||||
|
||||
lexeme = readNext();
|
||||
|
|
|
@ -240,7 +240,7 @@ std::optional<std::string> getParentPath(const std::string& path)
|
|||
return std::nullopt;
|
||||
#endif
|
||||
|
||||
std::string::size_type slash = path.find_last_of("\\/", path.size() - 1);
|
||||
size_t slash = path.find_last_of("\\/", path.size() - 1);
|
||||
|
||||
if (slash == 0)
|
||||
return "/";
|
||||
|
@ -253,7 +253,7 @@ std::optional<std::string> getParentPath(const std::string& path)
|
|||
|
||||
static std::string getExtension(const std::string& path)
|
||||
{
|
||||
std::string::size_type dot = path.find_last_of(".\\/");
|
||||
size_t dot = path.find_last_of(".\\/");
|
||||
|
||||
if (dot == std::string::npos || path[dot] != '.')
|
||||
return "";
|
||||
|
|
|
@ -34,7 +34,8 @@ enum class CliMode
|
|||
enum class CompileFormat
|
||||
{
|
||||
Text,
|
||||
Binary
|
||||
Binary,
|
||||
Null
|
||||
};
|
||||
|
||||
constexpr int MaxTraversalLimit = 50;
|
||||
|
@ -594,6 +595,8 @@ static bool compileFile(const char* name, CompileFormat format)
|
|||
case CompileFormat::Binary:
|
||||
fwrite(bcb.getBytecode().data(), 1, bcb.getBytecode().size(), stdout);
|
||||
break;
|
||||
case CompileFormat::Null:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -716,6 +719,10 @@ int replMain(int argc, char** argv)
|
|||
{
|
||||
compileFormat = CompileFormat::Text;
|
||||
}
|
||||
else if (strcmp(argv[1], "--compile=null") == 0)
|
||||
{
|
||||
compileFormat = CompileFormat::Null;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error: Unrecognized value for '--compile' specified.\n");
|
||||
|
|
|
@ -232,7 +232,7 @@ private:
|
|||
|
||||
DenseHashMap<StringRef, unsigned int, StringRefHash> stringTable;
|
||||
|
||||
DenseHashMap<uint32_t, uint32_t> debugRemarks;
|
||||
std::vector<std::pair<uint32_t, uint32_t>> debugRemarks;
|
||||
std::string debugRemarkBuffer;
|
||||
|
||||
BytecodeEncoder* encoder = nullptr;
|
||||
|
|
|
@ -181,7 +181,6 @@ BytecodeBuilder::BytecodeBuilder(BytecodeEncoder* encoder)
|
|||
: constantMap({Constant::Type_Nil, ~0ull})
|
||||
, tableShapeMap(TableShape())
|
||||
, stringTable({nullptr, 0})
|
||||
, debugRemarks(~0u)
|
||||
, encoder(encoder)
|
||||
{
|
||||
LUAU_ASSERT(stringTable.find(StringRef{"", 0}) == nullptr);
|
||||
|
@ -257,6 +256,8 @@ void BytecodeBuilder::endFunction(uint8_t maxstacksize, uint8_t numupvalues)
|
|||
|
||||
void BytecodeBuilder::setMainFunction(uint32_t fid)
|
||||
{
|
||||
LUAU_ASSERT(fid < functions.size());
|
||||
|
||||
mainFunction = fid;
|
||||
}
|
||||
|
||||
|
@ -531,7 +532,7 @@ void BytecodeBuilder::addDebugRemark(const char* format, ...)
|
|||
// we null-terminate all remarks to avoid storing remark length
|
||||
debugRemarkBuffer += '\0';
|
||||
|
||||
debugRemarks[uint32_t(insns.size())] = uint32_t(offset);
|
||||
debugRemarks.emplace_back(uint32_t(insns.size()), uint32_t(offset));
|
||||
}
|
||||
|
||||
void BytecodeBuilder::finalize()
|
||||
|
@ -1719,6 +1720,7 @@ std::string BytecodeBuilder::dumpCurrentFunction() const
|
|||
const uint32_t* codeEnd = insns.data() + insns.size();
|
||||
|
||||
int lastLine = -1;
|
||||
size_t nextRemark = 0;
|
||||
|
||||
std::string result;
|
||||
|
||||
|
@ -1741,6 +1743,7 @@ std::string BytecodeBuilder::dumpCurrentFunction() const
|
|||
while (code != codeEnd)
|
||||
{
|
||||
uint8_t op = LUAU_INSN_OP(*code);
|
||||
uint32_t pc = uint32_t(code - insns.data());
|
||||
|
||||
if (op == LOP_PREPVARARGS)
|
||||
{
|
||||
|
@ -1751,15 +1754,16 @@ std::string BytecodeBuilder::dumpCurrentFunction() const
|
|||
|
||||
if (dumpFlags & Dump_Remarks)
|
||||
{
|
||||
const uint32_t* remark = debugRemarks.find(uint32_t(code - insns.data()));
|
||||
|
||||
if (remark)
|
||||
formatAppend(result, "REMARK %s\n", debugRemarkBuffer.c_str() + *remark);
|
||||
while (nextRemark < debugRemarks.size() && debugRemarks[nextRemark].first == pc)
|
||||
{
|
||||
formatAppend(result, "REMARK %s\n", debugRemarkBuffer.c_str() + debugRemarks[nextRemark].second);
|
||||
nextRemark++;
|
||||
}
|
||||
}
|
||||
|
||||
if (dumpFlags & Dump_Source)
|
||||
{
|
||||
int line = lines[code - insns.data()];
|
||||
int line = lines[pc];
|
||||
|
||||
if (line > 0 && line != lastLine)
|
||||
{
|
||||
|
@ -1771,7 +1775,7 @@ std::string BytecodeBuilder::dumpCurrentFunction() const
|
|||
|
||||
if (dumpFlags & Dump_Lines)
|
||||
{
|
||||
formatAppend(result, "%d: ", lines[code - insns.data()]);
|
||||
formatAppend(result, "%d: ", lines[pc]);
|
||||
}
|
||||
|
||||
code = dumpInstruction(code, result);
|
||||
|
@ -1784,11 +1788,11 @@ void BytecodeBuilder::setDumpSource(const std::string& source)
|
|||
{
|
||||
dumpSource.clear();
|
||||
|
||||
std::string::size_type pos = 0;
|
||||
size_t pos = 0;
|
||||
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
std::string::size_type next = source.find('\n', pos);
|
||||
size_t next = source.find('\n', pos);
|
||||
|
||||
if (next == std::string::npos)
|
||||
{
|
||||
|
|
|
@ -2206,9 +2206,15 @@ struct Compiler
|
|||
return false;
|
||||
}
|
||||
|
||||
if (Variable* lv = variables.find(stat->var); lv && lv->written)
|
||||
{
|
||||
bytecode.addDebugRemark("loop unroll failed: mutable loop variable");
|
||||
return false;
|
||||
}
|
||||
|
||||
int tripCount = (to - from) / step + 1;
|
||||
|
||||
if (tripCount > thresholdBase * thresholdMaxBoost / 100)
|
||||
if (tripCount > thresholdBase)
|
||||
{
|
||||
bytecode.addDebugRemark("loop unroll failed: too many iterations (%d)", tripCount);
|
||||
return false;
|
||||
|
|
|
@ -249,7 +249,7 @@ int computeCost(uint64_t model, const bool* varsConst, size_t varCount)
|
|||
return cost;
|
||||
|
||||
for (size_t i = 0; i < varCount && i < 7; ++i)
|
||||
cost -= int((model >> (8 * i + 8)) & 0x7f) * varsConst[i];
|
||||
cost -= int((model >> (i * 8 + 8)) & 0x7f) * varsConst[i];
|
||||
|
||||
return cost;
|
||||
}
|
||||
|
|
|
@ -220,8 +220,8 @@ if(TARGET Luau.UnitTest)
|
|||
tests/Autocomplete.test.cpp
|
||||
tests/BuiltinDefinitions.test.cpp
|
||||
tests/Compiler.test.cpp
|
||||
tests/CostModel.test.cpp
|
||||
tests/Config.test.cpp
|
||||
tests/CostModel.test.cpp
|
||||
tests/Error.test.cpp
|
||||
tests/Frontend.test.cpp
|
||||
tests/JsonEncoder.test.cpp
|
||||
|
@ -232,6 +232,7 @@ if(TARGET Luau.UnitTest)
|
|||
tests/Normalize.test.cpp
|
||||
tests/Parser.test.cpp
|
||||
tests/RequireTracer.test.cpp
|
||||
tests/RuntimeLimits.test.cpp
|
||||
tests/StringUtils.test.cpp
|
||||
tests/Symbol.test.cpp
|
||||
tests/ToDot.test.cpp
|
||||
|
|
|
@ -299,7 +299,7 @@ LUA_API uintptr_t lua_encodepointer(lua_State* L, uintptr_t p);
|
|||
|
||||
LUA_API double lua_clock();
|
||||
|
||||
LUA_API void lua_setuserdatadtor(lua_State* L, int tag, void (*dtor)(void*));
|
||||
LUA_API void lua_setuserdatadtor(lua_State* L, int tag, void (*dtor)(lua_State*, void*));
|
||||
|
||||
LUA_API void lua_clonefunction(lua_State* L, int idx);
|
||||
|
||||
|
|
|
@ -1323,7 +1323,7 @@ void lua_unref(lua_State* L, int ref)
|
|||
return;
|
||||
}
|
||||
|
||||
void lua_setuserdatadtor(lua_State* L, int tag, void (*dtor)(void*))
|
||||
void lua_setuserdatadtor(lua_State* L, int tag, void (*dtor)(lua_State*, void*))
|
||||
{
|
||||
api_check(L, unsigned(tag) < LUA_UTAG_LIMIT);
|
||||
L->global->udatagc[tag] = dtor;
|
||||
|
|
|
@ -200,7 +200,7 @@ typedef struct global_State
|
|||
uint64_t rngstate; /* PCG random number generator state */
|
||||
uint64_t ptrenckey[4]; /* pointer encoding key for display */
|
||||
|
||||
void (*udatagc[LUA_UTAG_LIMIT])(void*); /* for each userdata tag, a gc callback to be called immediately before freeing memory */
|
||||
void (*udatagc[LUA_UTAG_LIMIT])(lua_State*, void*); /* for each userdata tag, a gc callback to be called immediately before freeing memory */
|
||||
|
||||
lua_Callbacks cb;
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauTableRehashRework, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTableNewBoundary2, false)
|
||||
|
||||
// max size of both array and hash part is 2^MAXBITS
|
||||
|
@ -400,16 +399,9 @@ static void resize(lua_State* L, Table* t, int nasize, int nhsize)
|
|||
{
|
||||
if (!ttisnil(&t->array[i]))
|
||||
{
|
||||
if (FFlag::LuauTableRehashRework)
|
||||
{
|
||||
TValue ok;
|
||||
setnvalue(&ok, cast_num(i + 1));
|
||||
setobjt2t(L, newkey(L, t, &ok), &t->array[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
setobjt2t(L, luaH_setnum(L, t, i + 1), &t->array[i]);
|
||||
}
|
||||
TValue ok;
|
||||
setnvalue(&ok, cast_num(i + 1));
|
||||
setobjt2t(L, newkey(L, t, &ok), &t->array[i]);
|
||||
}
|
||||
}
|
||||
/* shrink array */
|
||||
|
@ -418,30 +410,14 @@ static void resize(lua_State* L, Table* t, int nasize, int nhsize)
|
|||
/* used for the migration check at the end */
|
||||
TValue* anew = t->array;
|
||||
/* re-insert elements from hash part */
|
||||
if (FFlag::LuauTableRehashRework)
|
||||
for (int i = twoto(oldhsize) - 1; i >= 0; i--)
|
||||
{
|
||||
for (int i = twoto(oldhsize) - 1; i >= 0; i--)
|
||||
LuaNode* old = nold + i;
|
||||
if (!ttisnil(gval(old)))
|
||||
{
|
||||
LuaNode* old = nold + i;
|
||||
if (!ttisnil(gval(old)))
|
||||
{
|
||||
TValue ok;
|
||||
getnodekey(L, &ok, old);
|
||||
setobjt2t(L, arrayornewkey(L, t, &ok), gval(old));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = twoto(oldhsize) - 1; i >= 0; i--)
|
||||
{
|
||||
LuaNode* old = nold + i;
|
||||
if (!ttisnil(gval(old)))
|
||||
{
|
||||
TValue ok;
|
||||
getnodekey(L, &ok, old);
|
||||
setobjt2t(L, luaH_set(L, t, &ok), gval(old));
|
||||
}
|
||||
TValue ok;
|
||||
getnodekey(L, &ok, old);
|
||||
setobjt2t(L, arrayornewkey(L, t, &ok), gval(old));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -559,7 +535,7 @@ static TValue* newkey(lua_State* L, Table* t, const TValue* key)
|
|||
{
|
||||
rehash(L, t, key); /* grow table */
|
||||
|
||||
// after rehash, numeric keys might be located in the new array part, but won't be found in the node part
|
||||
/* after rehash, numeric keys might be located in the new array part, but won't be found in the node part */
|
||||
return arrayornewkey(L, t, key);
|
||||
}
|
||||
|
||||
|
@ -571,15 +547,8 @@ static TValue* newkey(lua_State* L, Table* t, const TValue* key)
|
|||
{ /* cannot find a free place? */
|
||||
rehash(L, t, key); /* grow table */
|
||||
|
||||
if (!FFlag::LuauTableRehashRework)
|
||||
{
|
||||
return luaH_set(L, t, key); /* re-insert key into grown table */
|
||||
}
|
||||
else
|
||||
{
|
||||
// after rehash, numeric keys might be located in the new array part, but won't be found in the node part
|
||||
return arrayornewkey(L, t, key);
|
||||
}
|
||||
/* after rehash, numeric keys might be located in the new array part, but won't be found in the node part */
|
||||
return arrayornewkey(L, t, key);
|
||||
}
|
||||
LUAU_ASSERT(n != dummynode);
|
||||
TValue mk;
|
||||
|
|
|
@ -22,14 +22,21 @@ Udata* luaU_newudata(lua_State* L, size_t s, int tag)
|
|||
|
||||
void luaU_freeudata(lua_State* L, Udata* u, lua_Page* page)
|
||||
{
|
||||
void (*dtor)(void*) = nullptr;
|
||||
if (u->tag < LUA_UTAG_LIMIT)
|
||||
{
|
||||
void (*dtor)(lua_State*, void*) = nullptr;
|
||||
dtor = L->global->udatagc[u->tag];
|
||||
if (dtor)
|
||||
dtor(L, u->data);
|
||||
}
|
||||
else if (u->tag == UTAG_IDTOR)
|
||||
{
|
||||
void (*dtor)(void*) = nullptr;
|
||||
memcpy(&dtor, &u->data + u->len - sizeof(dtor), sizeof(dtor));
|
||||
if (dtor)
|
||||
dtor(u->data);
|
||||
}
|
||||
|
||||
if (dtor)
|
||||
dtor(u->data);
|
||||
|
||||
luaM_freegco(L, u, sizeudata(u->len), u->memcat, page);
|
||||
}
|
||||
|
|
|
@ -137,6 +137,21 @@ int registerTypes(Luau::TypeChecker& env)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setupFrontend(Luau::Frontend& frontend)
|
||||
{
|
||||
registerTypes(frontend.typeChecker);
|
||||
Luau::freeze(frontend.typeChecker.globalTypes);
|
||||
|
||||
registerTypes(frontend.typeCheckerForAutocomplete);
|
||||
Luau::freeze(frontend.typeCheckerForAutocomplete.globalTypes);
|
||||
|
||||
frontend.iceHandler.onInternalError = [](const char* error) {
|
||||
printf("ICE: %s\n", error);
|
||||
LUAU_ASSERT(!"ICE");
|
||||
};
|
||||
}
|
||||
|
||||
struct FuzzFileResolver : Luau::FileResolver
|
||||
{
|
||||
std::optional<Luau::SourceCode> readSource(const Luau::ModuleName& name) override
|
||||
|
@ -238,19 +253,11 @@ DEFINE_PROTO_FUZZER(const luau::ModuleSet& message)
|
|||
if (kFuzzTypeck)
|
||||
{
|
||||
static FuzzFileResolver fileResolver;
|
||||
static Luau::NullConfigResolver configResolver;
|
||||
static FuzzConfigResolver configResolver;
|
||||
static Luau::FrontendOptions options{true, true};
|
||||
static Luau::Frontend frontend(&fileResolver, &configResolver, options);
|
||||
|
||||
static int once = registerTypes(frontend.typeChecker);
|
||||
(void)once;
|
||||
static int once2 = (Luau::freeze(frontend.typeChecker.globalTypes), 0);
|
||||
(void)once2;
|
||||
|
||||
frontend.iceHandler.onInternalError = [](const char* error) {
|
||||
printf("ICE: %s\n", error);
|
||||
LUAU_ASSERT(!"ICE");
|
||||
};
|
||||
static int once = (setupFrontend(frontend), 0);
|
||||
|
||||
// restart
|
||||
frontend.clear();
|
||||
|
|
|
@ -2761,7 +2761,6 @@ TEST_CASE_FIXTURE(ACFixture, "autocomplete_on_string_singletons")
|
|||
TEST_CASE_FIXTURE(ACFixture, "autocomplete_string_singletons")
|
||||
{
|
||||
ScopedFastFlag luauAutocompleteSingletonTypes{"LuauAutocompleteSingletonTypes", true};
|
||||
ScopedFastFlag luauExpectedTypesOfProperties{"LuauExpectedTypesOfProperties", true};
|
||||
|
||||
check(R"(
|
||||
type tag = "cat" | "dog"
|
||||
|
|
|
@ -2698,16 +2698,22 @@ TEST_CASE("DebugRemarks")
|
|||
|
||||
uint32_t fid = bcb.beginFunction(0);
|
||||
|
||||
bcb.addDebugRemark("test remark #%d", 42);
|
||||
bcb.addDebugRemark("test remark #%d", 1);
|
||||
bcb.emitABC(LOP_LOADNIL, 0, 0, 0);
|
||||
bcb.addDebugRemark("test remark #%d", 2);
|
||||
bcb.addDebugRemark("test remark #%d", 3);
|
||||
bcb.emitABC(LOP_RETURN, 0, 1, 0);
|
||||
|
||||
bcb.endFunction(0, 0);
|
||||
bcb.endFunction(1, 0);
|
||||
|
||||
bcb.setMainFunction(fid);
|
||||
bcb.finalize();
|
||||
|
||||
CHECK_EQ("\n" + bcb.dumpFunction(0), R"(
|
||||
REMARK test remark #42
|
||||
REMARK test remark #1
|
||||
LOADNIL R0
|
||||
REMARK test remark #2
|
||||
REMARK test remark #3
|
||||
RETURN R0 0
|
||||
)");
|
||||
}
|
||||
|
@ -4332,7 +4338,7 @@ RETURN R0 1
|
|||
// loops with body that's long but has a high boost factor due to constant folding
|
||||
CHECK_EQ("\n" + compileFunction(R"(
|
||||
local t = {}
|
||||
for i=1,30 do
|
||||
for i=1,25 do
|
||||
t[i] = i * i * i
|
||||
end
|
||||
return t
|
||||
|
@ -4390,16 +4396,6 @@ LOADN R1 13824
|
|||
SETTABLEN R1 R0 24
|
||||
LOADN R1 15625
|
||||
SETTABLEN R1 R0 25
|
||||
LOADN R1 17576
|
||||
SETTABLEN R1 R0 26
|
||||
LOADN R1 19683
|
||||
SETTABLEN R1 R0 27
|
||||
LOADN R1 21952
|
||||
SETTABLEN R1 R0 28
|
||||
LOADN R1 24389
|
||||
SETTABLEN R1 R0 29
|
||||
LOADN R1 27000
|
||||
SETTABLEN R1 R0 30
|
||||
RETURN R0 1
|
||||
)");
|
||||
|
||||
|
@ -4431,4 +4427,30 @@ RETURN R0 1
|
|||
)");
|
||||
}
|
||||
|
||||
TEST_CASE("LoopUnrollMutable")
|
||||
{
|
||||
// can't unroll loops that mutate iteration variable
|
||||
CHECK_EQ("\n" + compileFunction(R"(
|
||||
for i=1,3 do
|
||||
i = 3
|
||||
print(i) -- should print 3 three times in a row
|
||||
end
|
||||
)",
|
||||
0, 2),
|
||||
R"(
|
||||
LOADN R2 1
|
||||
LOADN R0 3
|
||||
LOADN R1 1
|
||||
FORNPREP R0 +7
|
||||
MOVE R3 R2
|
||||
LOADN R3 3
|
||||
GETIMPORT R4 1
|
||||
MOVE R5 R3
|
||||
CALL R4 1 0
|
||||
FORNLOOP R0 -7
|
||||
RETURN R0 0
|
||||
)");
|
||||
}
|
||||
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -1056,7 +1056,7 @@ TEST_CASE("UserdataApi")
|
|||
lua_State* L = globalState.get();
|
||||
|
||||
// setup dtor for tag 42 (created later)
|
||||
lua_setuserdatadtor(L, 42, [](void* data) {
|
||||
lua_setuserdatadtor(L, 42, [](lua_State* l, void* data) {
|
||||
dtorhits += *(int*)data;
|
||||
});
|
||||
|
||||
|
|
|
@ -975,8 +975,6 @@ TEST_CASE_FIXTURE(FrontendFixture, "typecheck_twice_for_ast_types")
|
|||
|
||||
TEST_CASE_FIXTURE(FrontendFixture, "imported_table_modification_2")
|
||||
{
|
||||
ScopedFastFlag sffs("LuauSealExports", true);
|
||||
|
||||
frontend.options.retainFullTypeGraphs = false;
|
||||
|
||||
fileResolver.source["Module/A"] = R"(
|
||||
|
@ -1035,4 +1033,20 @@ return false;
|
|||
fix.frontend.check("Module/B");
|
||||
}
|
||||
|
||||
TEST_CASE("check_without_builtin_next")
|
||||
{
|
||||
ScopedFastFlag luauDoNotRelyOnNextBinding{"LuauDoNotRelyOnNextBinding", true};
|
||||
|
||||
TestFileResolver fileResolver;
|
||||
TestConfigResolver configResolver;
|
||||
Frontend frontend(&fileResolver, &configResolver);
|
||||
|
||||
fileResolver.source["Module/A"] = "for k,v in 2 do end";
|
||||
fileResolver.source["Module/B"] = "return next";
|
||||
|
||||
// We don't care about the result. That we haven't crashed is enough.
|
||||
frontend.check("Module/A");
|
||||
frontend.check("Module/B");
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -199,7 +199,6 @@ TEST_CASE_FIXTURE(Fixture, "clone_class")
|
|||
TEST_CASE_FIXTURE(Fixture, "clone_free_types")
|
||||
{
|
||||
ScopedFastFlag sff[]{
|
||||
{"LuauErrorRecoveryType", true},
|
||||
{"LuauLosslessClone", true},
|
||||
};
|
||||
|
||||
|
|
|
@ -283,7 +283,6 @@ TEST_CASE_FIXTURE(Fixture, "inconsistent_module_return_types_are_ok")
|
|||
ScopedFastFlag sff[]{
|
||||
{"LuauReturnTypeInferenceInNonstrict", true},
|
||||
{"LuauLowerBoundsCalculation", true},
|
||||
{"LuauSealExports", true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
|
|
@ -1606,8 +1606,6 @@ TEST_CASE_FIXTURE(Fixture, "end_extent_of_functions_unions_and_intersections")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "end_extent_doesnt_consume_comments")
|
||||
{
|
||||
ScopedFastFlag luauParseLocationIgnoreCommentSkip{"LuauParseLocationIgnoreCommentSkip", true};
|
||||
|
||||
AstStatBlock* block = parse(R"(
|
||||
type F = number
|
||||
--comment
|
||||
|
@ -1620,7 +1618,6 @@ TEST_CASE_FIXTURE(Fixture, "end_extent_doesnt_consume_comments")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "end_extent_doesnt_consume_comments_even_with_capture")
|
||||
{
|
||||
ScopedFastFlag luauParseLocationIgnoreCommentSkip{"LuauParseLocationIgnoreCommentSkip", true};
|
||||
ScopedFastFlag luauParseLocationIgnoreCommentSkipInCapture{"LuauParseLocationIgnoreCommentSkipInCapture", true};
|
||||
|
||||
// Same should hold when comments are captured
|
||||
|
|
270
tests/RuntimeLimits.test.cpp
Normal file
270
tests/RuntimeLimits.test.cpp
Normal file
|
@ -0,0 +1,270 @@
|
|||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
|
||||
/* Tests in this source file are meant to be a bellwether to verify that the numeric limits we've set are sufficient for
|
||||
* most real-world scripts.
|
||||
*
|
||||
* If a change breaks a test in this source file, please don't adjust the flag values set in the fixture. Instead,
|
||||
* consider it a latent performance problem by default.
|
||||
*
|
||||
* We should periodically revisit this to retest the limits.
|
||||
*/
|
||||
|
||||
#include "Fixture.h"
|
||||
|
||||
#include "doctest.h"
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauLowerBoundsCalculation);
|
||||
|
||||
struct LimitFixture : Fixture
|
||||
{
|
||||
#if defined(_NOOPT) || defined(_DEBUG)
|
||||
ScopedFastInt LuauTypeInferRecursionLimit{"LuauTypeInferRecursionLimit", 100};
|
||||
#endif
|
||||
|
||||
ScopedFastFlag LuauJustOneCallFrameForHaveSeen{"LuauJustOneCallFrameForHaveSeen", true};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool hasError(const CheckResult& result, T* = nullptr)
|
||||
{
|
||||
auto it = std::find_if(result.errors.begin(), result.errors.end(), [](const TypeError& a) {
|
||||
return nullptr != get<T>(a);
|
||||
});
|
||||
return it != result.errors.end();
|
||||
}
|
||||
|
||||
TEST_SUITE_BEGIN("RuntimeLimitTests");
|
||||
|
||||
TEST_CASE_FIXTURE(LimitFixture, "bail_early_on_typescript_port_of_Result_type" * doctest::timeout(1.0))
|
||||
{
|
||||
constexpr const char* src = R"LUA(
|
||||
--!strict
|
||||
local TS = _G[script]
|
||||
local lazyGet = TS.import(script, script.Parent.Parent, "util", "lazyLoad").lazyGet
|
||||
local unit = TS.import(script, script.Parent.Parent, "util", "Unit").unit
|
||||
local Iterator
|
||||
lazyGet("Iterator", function(c)
|
||||
Iterator = c
|
||||
end)
|
||||
local Option
|
||||
lazyGet("Option", function(c)
|
||||
Option = c
|
||||
end)
|
||||
local Vec
|
||||
lazyGet("Vec", function(c)
|
||||
Vec = c
|
||||
end)
|
||||
local Result
|
||||
do
|
||||
Result = setmetatable({}, {
|
||||
__tostring = function()
|
||||
return "Result"
|
||||
end,
|
||||
})
|
||||
Result.__index = Result
|
||||
function Result.new(...)
|
||||
local self = setmetatable({}, Result)
|
||||
self:constructor(...)
|
||||
return self
|
||||
end
|
||||
function Result:constructor(okValue, errValue)
|
||||
self.okValue = okValue
|
||||
self.errValue = errValue
|
||||
end
|
||||
function Result:ok(val)
|
||||
return Result.new(val, nil)
|
||||
end
|
||||
function Result:err(val)
|
||||
return Result.new(nil, val)
|
||||
end
|
||||
function Result:fromCallback(c)
|
||||
local _0 = c
|
||||
local _1, _2 = pcall(_0)
|
||||
local result = _1 and {
|
||||
success = true,
|
||||
value = _2,
|
||||
} or {
|
||||
success = false,
|
||||
error = _2,
|
||||
}
|
||||
return result.success and Result:ok(result.value) or Result:err(Option:wrap(result.error))
|
||||
end
|
||||
function Result:fromVoidCallback(c)
|
||||
local _0 = c
|
||||
local _1, _2 = pcall(_0)
|
||||
local result = _1 and {
|
||||
success = true,
|
||||
value = _2,
|
||||
} or {
|
||||
success = false,
|
||||
error = _2,
|
||||
}
|
||||
return result.success and Result:ok(unit()) or Result:err(Option:wrap(result.error))
|
||||
end
|
||||
Result.fromPromise = TS.async(function(self, p)
|
||||
local _0, _1 = TS.try(function()
|
||||
return TS.TRY_RETURN, { Result:ok(TS.await(p)) }
|
||||
end, function(e)
|
||||
return TS.TRY_RETURN, { Result:err(Option:wrap(e)) }
|
||||
end)
|
||||
if _0 then
|
||||
return unpack(_1)
|
||||
end
|
||||
end)
|
||||
Result.fromVoidPromise = TS.async(function(self, p)
|
||||
local _0, _1 = TS.try(function()
|
||||
TS.await(p)
|
||||
return TS.TRY_RETURN, { Result:ok(unit()) }
|
||||
end, function(e)
|
||||
return TS.TRY_RETURN, { Result:err(Option:wrap(e)) }
|
||||
end)
|
||||
if _0 then
|
||||
return unpack(_1)
|
||||
end
|
||||
end)
|
||||
function Result:isOk()
|
||||
return self.okValue ~= nil
|
||||
end
|
||||
function Result:isErr()
|
||||
return self.errValue ~= nil
|
||||
end
|
||||
function Result:contains(x)
|
||||
return self.okValue == x
|
||||
end
|
||||
function Result:containsErr(x)
|
||||
return self.errValue == x
|
||||
end
|
||||
function Result:okOption()
|
||||
return Option:wrap(self.okValue)
|
||||
end
|
||||
function Result:errOption()
|
||||
return Option:wrap(self.errValue)
|
||||
end
|
||||
function Result:map(func)
|
||||
return self:isOk() and Result:ok(func(self.okValue)) or Result:err(self.errValue)
|
||||
end
|
||||
function Result:mapOr(def, func)
|
||||
local _0
|
||||
if self:isOk() then
|
||||
_0 = func(self.okValue)
|
||||
else
|
||||
_0 = def
|
||||
end
|
||||
return _0
|
||||
end
|
||||
function Result:mapOrElse(def, func)
|
||||
local _0
|
||||
if self:isOk() then
|
||||
_0 = func(self.okValue)
|
||||
else
|
||||
_0 = def(self.errValue)
|
||||
end
|
||||
return _0
|
||||
end
|
||||
function Result:mapErr(func)
|
||||
return self:isErr() and Result:err(func(self.errValue)) or Result:ok(self.okValue)
|
||||
end
|
||||
Result["and"] = function(self, other)
|
||||
return self:isErr() and Result:err(self.errValue) or other
|
||||
end
|
||||
function Result:andThen(func)
|
||||
return self:isErr() and Result:err(self.errValue) or func(self.okValue)
|
||||
end
|
||||
Result["or"] = function(self, other)
|
||||
return self:isOk() and Result:ok(self.okValue) or other
|
||||
end
|
||||
function Result:orElse(other)
|
||||
return self:isOk() and Result:ok(self.okValue) or other(self.errValue)
|
||||
end
|
||||
function Result:expect(msg)
|
||||
if self:isOk() then
|
||||
return self.okValue
|
||||
else
|
||||
error(msg)
|
||||
end
|
||||
end
|
||||
function Result:unwrap()
|
||||
return self:expect("called `Result.unwrap()` on an `Err` value: " .. tostring(self.errValue))
|
||||
end
|
||||
function Result:unwrapOr(def)
|
||||
local _0
|
||||
if self:isOk() then
|
||||
_0 = self.okValue
|
||||
else
|
||||
_0 = def
|
||||
end
|
||||
return _0
|
||||
end
|
||||
function Result:unwrapOrElse(gen)
|
||||
local _0
|
||||
if self:isOk() then
|
||||
_0 = self.okValue
|
||||
else
|
||||
_0 = gen(self.errValue)
|
||||
end
|
||||
return _0
|
||||
end
|
||||
function Result:expectErr(msg)
|
||||
if self:isErr() then
|
||||
return self.errValue
|
||||
else
|
||||
error(msg)
|
||||
end
|
||||
end
|
||||
function Result:unwrapErr()
|
||||
return self:expectErr("called `Result.unwrapErr()` on an `Ok` value: " .. tostring(self.okValue))
|
||||
end
|
||||
function Result:transpose()
|
||||
return self:isOk() and self.okValue:map(function(some)
|
||||
return Result:ok(some)
|
||||
end) or Option:some(Result:err(self.errValue))
|
||||
end
|
||||
function Result:flatten()
|
||||
return self:isOk() and Result.new(self.okValue.okValue, self.okValue.errValue) or Result:err(self.errValue)
|
||||
end
|
||||
function Result:match(ifOk, ifErr)
|
||||
local _0
|
||||
if self:isOk() then
|
||||
_0 = ifOk(self.okValue)
|
||||
else
|
||||
_0 = ifErr(self.errValue)
|
||||
end
|
||||
return _0
|
||||
end
|
||||
function Result:asPtr()
|
||||
local _0 = (self.okValue)
|
||||
if _0 == nil then
|
||||
_0 = (self.errValue)
|
||||
end
|
||||
return _0
|
||||
end
|
||||
end
|
||||
local resultMeta = Result
|
||||
resultMeta.__eq = function(a, b)
|
||||
return b:match(function(ok)
|
||||
return a:contains(ok)
|
||||
end, function(err)
|
||||
return a:containsErr(err)
|
||||
end)
|
||||
end
|
||||
resultMeta.__tostring = function(result)
|
||||
return result:match(function(ok)
|
||||
return "Result.ok(" .. tostring(ok) .. ")"
|
||||
end, function(err)
|
||||
return "Result.err(" .. tostring(err) .. ")"
|
||||
end)
|
||||
end
|
||||
return {
|
||||
Result = Result,
|
||||
}
|
||||
)LUA";
|
||||
|
||||
if (FFlag::LuauLowerBoundsCalculation)
|
||||
(void)check(src);
|
||||
else
|
||||
CHECK_THROWS_AS(check(src), std::exception);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauFixIncorrectLineNumberDuplicateType)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeAliases");
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "cyclic_function_type_in_type_alias")
|
||||
|
@ -257,11 +255,7 @@ TEST_CASE_FIXTURE(Fixture, "reported_location_is_correct_when_type_alias_are_dup
|
|||
auto dtd = get<DuplicateTypeDefinition>(result.errors[0]);
|
||||
REQUIRE(dtd);
|
||||
CHECK_EQ(dtd->name, "B");
|
||||
|
||||
if (FFlag::LuauFixIncorrectLineNumberDuplicateType)
|
||||
CHECK_EQ(dtd->previousLocation.begin.line + 1, 3);
|
||||
else
|
||||
CHECK_EQ(dtd->previousLocation.begin.line + 1, 1);
|
||||
CHECK_EQ(dtd->previousLocation.begin.line + 1, 3);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "stringify_optional_parameterized_alias")
|
||||
|
@ -495,8 +489,6 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_ok")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_1")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauRecursiveTypeParameterRestriction", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
-- OK because forwarded types are used with their parameters.
|
||||
type Tree<T> = { data: T, children: Forest<T> }
|
||||
|
@ -508,8 +500,6 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_1")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_2")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauRecursiveTypeParameterRestriction", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
-- Not OK because forwarded types are used with different types than their parameters.
|
||||
type Forest<T> = {Tree<{T}>}
|
||||
|
@ -531,8 +521,6 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_swapsies_ok")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_swapsies_not_ok")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauRecursiveTypeParameterRestriction", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Tree1<T,U> = { data: T, children: {Tree2<U,T>} }
|
||||
type Tree2<T,U> = { data: U, children: {Tree1<T,U>} }
|
||||
|
@ -647,9 +635,6 @@ TEST_CASE_FIXTURE(Fixture, "forward_declared_alias_is_not_clobbered_by_prior_uni
|
|||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{"LuauTwoPassAliasDefinitionFix", true},
|
||||
|
||||
// We also force this flag because it surfaced an unfortunate interaction.
|
||||
{"LuauErrorRecoveryType", true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -687,8 +672,6 @@ TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_ok")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_not_ok")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauRecursiveTypeParameterRestriction", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
-- this would be an infinite type if we allowed it
|
||||
type Tree<T> = { data: T, children: {Tree<{T}>} }
|
||||
|
|
|
@ -221,8 +221,6 @@ TEST_CASE_FIXTURE(Fixture, "as_expr_is_bidirectional")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "as_expr_warns_on_unrelated_cast")
|
||||
{
|
||||
ScopedFastFlag sff2{"LuauErrorRecoveryType", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local a = 55 :: string
|
||||
)");
|
||||
|
@ -407,8 +405,6 @@ TEST_CASE_FIXTURE(Fixture, "typeof_expr")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "corecursive_types_error_on_tight_loop")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauErrorRecoveryType", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type A = B
|
||||
type B = A
|
||||
|
|
|
@ -951,8 +951,6 @@ TEST_CASE_FIXTURE(Fixture, "record_matching_overload")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "return_type_by_overload")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauErrorRecoveryType", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Overload = ((string) -> string) & ((number, number) -> number)
|
||||
local abc: Overload
|
||||
|
@ -1538,7 +1536,6 @@ caused by:
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "too_few_arguments_variadic")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauArgCountMismatchSaysAtLeastWhenVariadic", true};
|
||||
CheckResult result = check(R"(
|
||||
function test(a: number, b: string, ...)
|
||||
end
|
||||
|
@ -1560,8 +1557,6 @@ TEST_CASE_FIXTURE(Fixture, "too_few_arguments_variadic")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "too_few_arguments_variadic_generic")
|
||||
{
|
||||
ScopedFastFlag sff1{"LuauArgCountMismatchSaysAtLeastWhenVariadic", true};
|
||||
ScopedFastFlag sff2{"LuauFixArgumentCountMismatchAmountWithGenericTypes", true};
|
||||
CheckResult result = check(R"(
|
||||
function test(a: number, b: string, ...)
|
||||
return 1
|
||||
|
@ -1587,8 +1582,6 @@ wrapper(test)
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "too_few_arguments_variadic_generic2")
|
||||
{
|
||||
ScopedFastFlag sff1{"LuauArgCountMismatchSaysAtLeastWhenVariadic", true};
|
||||
ScopedFastFlag sff2{"LuauFixArgumentCountMismatchAmountWithGenericTypes", true};
|
||||
CheckResult result = check(R"(
|
||||
function test(a: number, b: string, ...)
|
||||
return 1
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauFixArgumentCountMismatchAmountWithGenericTypes)
|
||||
|
||||
TEST_SUITE_BEGIN("GenericsTests");
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "check_generic_function")
|
||||
|
@ -679,8 +677,6 @@ local d: D = c
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_functions_dont_cache_type_parameters")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauGenericFunctionsDontCacheTypeParams", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
-- See https://github.com/Roblox/luau/issues/332
|
||||
-- This function has a type parameter with the same name as clones,
|
||||
|
@ -707,8 +703,6 @@ TEST_CASE_FIXTURE(Fixture, "generic_functions_should_be_memory_safe")
|
|||
ScopedFastFlag sffs[] = {
|
||||
{"LuauTableSubtypingVariance2", true},
|
||||
{"LuauUnsealedTableLiteral", true},
|
||||
{"LuauPropertiesGetExpectedType", true},
|
||||
{"LuauRecursiveTypeParameterRestriction", true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -733,8 +727,6 @@ caused by:
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_type_pack_unification1")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauTxnLogSeesTypePacks2", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
type Dispatcher = {
|
||||
|
@ -753,8 +745,6 @@ local TheDispatcher: Dispatcher = {
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_type_pack_unification2")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauTxnLogSeesTypePacks2", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
type Dispatcher = {
|
||||
|
@ -773,8 +763,6 @@ local TheDispatcher: Dispatcher = {
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_type_pack_unification3")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauTxnLogSeesTypePacks2", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
type Dispatcher = {
|
||||
|
@ -805,11 +793,7 @@ wrapper(test)
|
|||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
if (FFlag::LuauFixArgumentCountMismatchAmountWithGenericTypes)
|
||||
CHECK_EQ(toString(result.errors[0]), R"(Argument count mismatch. Function expects 2 arguments, but only 1 is specified)");
|
||||
else
|
||||
CHECK_EQ(toString(result.errors[0]), R"(Argument count mismatch. Function expects 1 argument, but 1 is specified)");
|
||||
CHECK_EQ(toString(result.errors[0]), R"(Argument count mismatch. Function expects 2 arguments, but only 1 is specified)");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_many")
|
||||
|
@ -826,11 +810,7 @@ wrapper(test2, 1, "", 3)
|
|||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
if (FFlag::LuauFixArgumentCountMismatchAmountWithGenericTypes)
|
||||
CHECK_EQ(toString(result.errors[0]), R"(Argument count mismatch. Function expects 3 arguments, but 4 are specified)");
|
||||
else
|
||||
CHECK_EQ(toString(result.errors[0]), R"(Argument count mismatch. Function expects 1 argument, but 4 are specified)");
|
||||
CHECK_EQ(toString(result.errors[0]), R"(Argument count mismatch. Function expects 3 arguments, but 4 are specified)");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_function")
|
||||
|
|
|
@ -78,6 +78,8 @@ TEST_CASE_FIXTURE(Fixture, "for_in_with_an_iterator_of_type_any")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "for_in_loop_should_fail_with_non_function_iterator")
|
||||
{
|
||||
ScopedFastFlag luauDoNotRelyOnNextBinding{"LuauDoNotRelyOnNextBinding", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local foo = "bar"
|
||||
for i, v in foo do
|
||||
|
@ -85,6 +87,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_should_fail_with_non_function_iterator")
|
|||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK_EQ("Cannot call non-function string", toString(result.errors[0]));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "for_in_with_just_one_iterator_is_ok")
|
||||
|
@ -470,4 +473,19 @@ TEST_CASE_FIXTURE(Fixture, "loop_typecheck_crash_on_empty_optional")
|
|||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "fuzz_fail_missing_instantitation_follow")
|
||||
{
|
||||
ScopedFastFlag luauInstantiateFollows{"LuauInstantiateFollows", true};
|
||||
|
||||
// Just check that this doesn't assert
|
||||
check(R"(
|
||||
--!nonstrict
|
||||
function _(l0:number)
|
||||
return _
|
||||
end
|
||||
for _ in _(8) do
|
||||
end
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -142,8 +142,6 @@ TEST_CASE_FIXTURE(Fixture, "some_primitive_binary_ops")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "typecheck_overloaded_multiply_that_is_an_intersection")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauErrorRecoveryType", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
local Vec3 = {}
|
||||
|
@ -178,8 +176,6 @@ TEST_CASE_FIXTURE(Fixture, "typecheck_overloaded_multiply_that_is_an_intersectio
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "typecheck_overloaded_multiply_that_is_an_intersection_on_rhs")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauErrorRecoveryType", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
local Vec3 = {}
|
||||
|
|
|
@ -85,8 +85,6 @@ TEST_CASE_FIXTURE(Fixture, "string_function_other")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "CheckMethodsOfNumber")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauErrorRecoveryType", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local x: number = 9999
|
||||
function x:y(z: number)
|
||||
|
|
|
@ -268,242 +268,6 @@ TEST_CASE_FIXTURE(Fixture, "bail_early_if_unification_is_too_complicated" * doct
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "bail_early_on_typescript_port_of_Result_type" * doctest::timeout(1.0))
|
||||
{
|
||||
ScopedFastInt sffi{"LuauTarjanChildLimit", 400};
|
||||
|
||||
CheckResult result = check(R"LUA(
|
||||
--!strict
|
||||
local TS = _G[script]
|
||||
local lazyGet = TS.import(script, script.Parent.Parent, "util", "lazyLoad").lazyGet
|
||||
local unit = TS.import(script, script.Parent.Parent, "util", "Unit").unit
|
||||
local Iterator
|
||||
lazyGet("Iterator", function(c)
|
||||
Iterator = c
|
||||
end)
|
||||
local Option
|
||||
lazyGet("Option", function(c)
|
||||
Option = c
|
||||
end)
|
||||
local Vec
|
||||
lazyGet("Vec", function(c)
|
||||
Vec = c
|
||||
end)
|
||||
local Result
|
||||
do
|
||||
Result = setmetatable({}, {
|
||||
__tostring = function()
|
||||
return "Result"
|
||||
end,
|
||||
})
|
||||
Result.__index = Result
|
||||
function Result.new(...)
|
||||
local self = setmetatable({}, Result)
|
||||
self:constructor(...)
|
||||
return self
|
||||
end
|
||||
function Result:constructor(okValue, errValue)
|
||||
self.okValue = okValue
|
||||
self.errValue = errValue
|
||||
end
|
||||
function Result:ok(val)
|
||||
return Result.new(val, nil)
|
||||
end
|
||||
function Result:err(val)
|
||||
return Result.new(nil, val)
|
||||
end
|
||||
function Result:fromCallback(c)
|
||||
local _0 = c
|
||||
local _1, _2 = pcall(_0)
|
||||
local result = _1 and {
|
||||
success = true,
|
||||
value = _2,
|
||||
} or {
|
||||
success = false,
|
||||
error = _2,
|
||||
}
|
||||
return result.success and Result:ok(result.value) or Result:err(Option:wrap(result.error))
|
||||
end
|
||||
function Result:fromVoidCallback(c)
|
||||
local _0 = c
|
||||
local _1, _2 = pcall(_0)
|
||||
local result = _1 and {
|
||||
success = true,
|
||||
value = _2,
|
||||
} or {
|
||||
success = false,
|
||||
error = _2,
|
||||
}
|
||||
return result.success and Result:ok(unit()) or Result:err(Option:wrap(result.error))
|
||||
end
|
||||
Result.fromPromise = TS.async(function(self, p)
|
||||
local _0, _1 = TS.try(function()
|
||||
return TS.TRY_RETURN, { Result:ok(TS.await(p)) }
|
||||
end, function(e)
|
||||
return TS.TRY_RETURN, { Result:err(Option:wrap(e)) }
|
||||
end)
|
||||
if _0 then
|
||||
return unpack(_1)
|
||||
end
|
||||
end)
|
||||
Result.fromVoidPromise = TS.async(function(self, p)
|
||||
local _0, _1 = TS.try(function()
|
||||
TS.await(p)
|
||||
return TS.TRY_RETURN, { Result:ok(unit()) }
|
||||
end, function(e)
|
||||
return TS.TRY_RETURN, { Result:err(Option:wrap(e)) }
|
||||
end)
|
||||
if _0 then
|
||||
return unpack(_1)
|
||||
end
|
||||
end)
|
||||
function Result:isOk()
|
||||
return self.okValue ~= nil
|
||||
end
|
||||
function Result:isErr()
|
||||
return self.errValue ~= nil
|
||||
end
|
||||
function Result:contains(x)
|
||||
return self.okValue == x
|
||||
end
|
||||
function Result:containsErr(x)
|
||||
return self.errValue == x
|
||||
end
|
||||
function Result:okOption()
|
||||
return Option:wrap(self.okValue)
|
||||
end
|
||||
function Result:errOption()
|
||||
return Option:wrap(self.errValue)
|
||||
end
|
||||
function Result:map(func)
|
||||
return self:isOk() and Result:ok(func(self.okValue)) or Result:err(self.errValue)
|
||||
end
|
||||
function Result:mapOr(def, func)
|
||||
local _0
|
||||
if self:isOk() then
|
||||
_0 = func(self.okValue)
|
||||
else
|
||||
_0 = def
|
||||
end
|
||||
return _0
|
||||
end
|
||||
function Result:mapOrElse(def, func)
|
||||
local _0
|
||||
if self:isOk() then
|
||||
_0 = func(self.okValue)
|
||||
else
|
||||
_0 = def(self.errValue)
|
||||
end
|
||||
return _0
|
||||
end
|
||||
function Result:mapErr(func)
|
||||
return self:isErr() and Result:err(func(self.errValue)) or Result:ok(self.okValue)
|
||||
end
|
||||
Result["and"] = function(self, other)
|
||||
return self:isErr() and Result:err(self.errValue) or other
|
||||
end
|
||||
function Result:andThen(func)
|
||||
return self:isErr() and Result:err(self.errValue) or func(self.okValue)
|
||||
end
|
||||
Result["or"] = function(self, other)
|
||||
return self:isOk() and Result:ok(self.okValue) or other
|
||||
end
|
||||
function Result:orElse(other)
|
||||
return self:isOk() and Result:ok(self.okValue) or other(self.errValue)
|
||||
end
|
||||
function Result:expect(msg)
|
||||
if self:isOk() then
|
||||
return self.okValue
|
||||
else
|
||||
error(msg)
|
||||
end
|
||||
end
|
||||
function Result:unwrap()
|
||||
return self:expect("called `Result.unwrap()` on an `Err` value: " .. tostring(self.errValue))
|
||||
end
|
||||
function Result:unwrapOr(def)
|
||||
local _0
|
||||
if self:isOk() then
|
||||
_0 = self.okValue
|
||||
else
|
||||
_0 = def
|
||||
end
|
||||
return _0
|
||||
end
|
||||
function Result:unwrapOrElse(gen)
|
||||
local _0
|
||||
if self:isOk() then
|
||||
_0 = self.okValue
|
||||
else
|
||||
_0 = gen(self.errValue)
|
||||
end
|
||||
return _0
|
||||
end
|
||||
function Result:expectErr(msg)
|
||||
if self:isErr() then
|
||||
return self.errValue
|
||||
else
|
||||
error(msg)
|
||||
end
|
||||
end
|
||||
function Result:unwrapErr()
|
||||
return self:expectErr("called `Result.unwrapErr()` on an `Ok` value: " .. tostring(self.okValue))
|
||||
end
|
||||
function Result:transpose()
|
||||
return self:isOk() and self.okValue:map(function(some)
|
||||
return Result:ok(some)
|
||||
end) or Option:some(Result:err(self.errValue))
|
||||
end
|
||||
function Result:flatten()
|
||||
return self:isOk() and Result.new(self.okValue.okValue, self.okValue.errValue) or Result:err(self.errValue)
|
||||
end
|
||||
function Result:match(ifOk, ifErr)
|
||||
local _0
|
||||
if self:isOk() then
|
||||
_0 = ifOk(self.okValue)
|
||||
else
|
||||
_0 = ifErr(self.errValue)
|
||||
end
|
||||
return _0
|
||||
end
|
||||
function Result:asPtr()
|
||||
local _0 = (self.okValue)
|
||||
if _0 == nil then
|
||||
_0 = (self.errValue)
|
||||
end
|
||||
return _0
|
||||
end
|
||||
end
|
||||
local resultMeta = Result
|
||||
resultMeta.__eq = function(a, b)
|
||||
return b:match(function(ok)
|
||||
return a:contains(ok)
|
||||
end, function(err)
|
||||
return a:containsErr(err)
|
||||
end)
|
||||
end
|
||||
resultMeta.__tostring = function(result)
|
||||
return result:match(function(ok)
|
||||
return "Result.ok(" .. tostring(ok) .. ")"
|
||||
end, function(err)
|
||||
return "Result.err(" .. tostring(err) .. ")"
|
||||
end)
|
||||
end
|
||||
return {
|
||||
Result = Result,
|
||||
}
|
||||
)LUA");
|
||||
|
||||
auto it = std::find_if(result.errors.begin(), result.errors.end(), [](TypeError& a) {
|
||||
return nullptr != get<UnificationTooComplex>(a);
|
||||
});
|
||||
if (it == result.errors.end())
|
||||
{
|
||||
dumpErrors(result);
|
||||
FAIL("Expected a UnificationTooComplex error");
|
||||
}
|
||||
}
|
||||
|
||||
// Should be in TypeInfer.tables.test.cpp
|
||||
// It's unsound to instantiate tables containing generic methods,
|
||||
// since mutating properties means table properties should be invariant.
|
||||
|
|
|
@ -164,10 +164,6 @@ TEST_CASE_FIXTURE(Fixture, "enums_using_singletons_subtyping")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "tagged_unions_using_singletons")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{"LuauExpectedTypesOfProperties", true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Dog = { tag: "Dog", howls: boolean }
|
||||
type Cat = { tag: "Cat", meows: boolean }
|
||||
|
@ -281,10 +277,6 @@ TEST_CASE_FIXTURE(Fixture, "table_properties_type_error_escapes")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "error_detailed_tagged_union_mismatch_string")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{"LuauExpectedTypesOfProperties", true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Cat = { tag: 'cat', catfood: string }
|
||||
type Dog = { tag: 'dog', dogfood: string }
|
||||
|
@ -302,10 +294,6 @@ caused by:
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "error_detailed_tagged_union_mismatch_bool")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{"LuauExpectedTypesOfProperties", true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Good = { success: true, result: string }
|
||||
type Bad = { success: false, error: string }
|
||||
|
@ -323,10 +311,6 @@ caused by:
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "if_then_else_expression_singleton_options")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{"LuauExpectedTypesOfProperties", true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Cat = { tag: 'cat', catfood: string }
|
||||
type Dog = { tag: 'dog', dogfood: string }
|
||||
|
|
|
@ -2122,8 +2122,6 @@ caused by:
|
|||
TEST_CASE_FIXTURE(Fixture, "explicitly_typed_table")
|
||||
{
|
||||
ScopedFastFlag sffs[]{
|
||||
{"LuauPropertiesGetExpectedType", true},
|
||||
{"LuauExpectedTypesOfProperties", true},
|
||||
{"LuauTableSubtypingVariance2", true},
|
||||
};
|
||||
|
||||
|
@ -2143,8 +2141,6 @@ a.p = { x = 9 }
|
|||
TEST_CASE_FIXTURE(Fixture, "explicitly_typed_table_error")
|
||||
{
|
||||
ScopedFastFlag sffs[]{
|
||||
{"LuauPropertiesGetExpectedType", true},
|
||||
{"LuauExpectedTypesOfProperties", true},
|
||||
{"LuauTableSubtypingVariance2", true},
|
||||
{"LuauUnsealedTableLiteral", true},
|
||||
};
|
||||
|
@ -2171,8 +2167,6 @@ caused by:
|
|||
TEST_CASE_FIXTURE(Fixture, "explicitly_typed_table_with_indexer")
|
||||
{
|
||||
ScopedFastFlag sffs[]{
|
||||
{"LuauPropertiesGetExpectedType", true},
|
||||
{"LuauExpectedTypesOfProperties", true},
|
||||
{"LuauTableSubtypingVariance2", true},
|
||||
};
|
||||
|
||||
|
@ -2377,8 +2371,6 @@ TEST_CASE_FIXTURE(Fixture, "pass_a_union_of_tables_to_a_function_that_requires_a
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "unifying_tables_shouldnt_uaf1")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauTxnLogCheckForInvalidation", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
-- This example produced a UAF at one point, caused by pointers to table types becoming
|
||||
-- invalidated by child unifiers. (Calling log.concat can cause pointers to become invalid.)
|
||||
|
@ -2409,8 +2401,6 @@ end
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "unifying_tables_shouldnt_uaf2")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauTxnLogCheckForInvalidation", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
-- Another example that UAFd, this time found by fuzzing.
|
||||
local _
|
||||
|
|
|
@ -126,8 +126,6 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "members_of_failed_typepack_unification_are_u
|
|||
|
||||
TEST_CASE_FIXTURE(TryUnifyFixture, "result_of_failed_typepack_unification_is_constrained")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauErrorRecoveryType", true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(arg: number) return arg end
|
||||
local a
|
||||
|
|
|
@ -184,8 +184,6 @@ TEST_CASE_FIXTURE(Fixture, "UnionTypeVarIterator_with_empty_union")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "substitution_skip_failure")
|
||||
{
|
||||
ScopedFastFlag sff{"LuauSealExports", true};
|
||||
|
||||
TypeVar ftv11{FreeTypeVar{TypeLevel{}}};
|
||||
|
||||
TypePackVar tp24{TypePack{{&ftv11}}};
|
||||
|
|
Loading…
Reference in a new issue