diff --git a/Analysis/src/Frontend.cpp b/Analysis/src/Frontend.cpp index 34ccdac..b8f7836 100644 --- a/Analysis/src/Frontend.cpp +++ b/Analysis/src/Frontend.cpp @@ -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 { diff --git a/Analysis/src/Linter.cpp b/Analysis/src/Linter.cpp index 5608e4b..200b7d1 100644 --- a/Analysis/src/Linter.cpp +++ b/Analysis/src/Linter.cpp @@ -2653,12 +2653,12 @@ static void lintComments(LintContext& context, const std::vector& 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& 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) diff --git a/Analysis/src/Substitution.cpp b/Analysis/src/Substitution.cpp index 1b51fa3..30d8574 100644 --- a/Analysis/src/Substitution.cpp +++ b/Analysis/src/Substitution.cpp @@ -8,7 +8,7 @@ #include LUAU_FASTFLAG(LuauLowerBoundsCalculation) -LUAU_FASTINTVARIABLE(LuauTarjanChildLimit, 1000) +LUAU_FASTINTVARIABLE(LuauTarjanChildLimit, 10000) LUAU_FASTFLAG(LuauTypecheckOptPass) LUAU_FASTFLAGVARIABLE(LuauSubstituteFollowNewTypes, false) LUAU_FASTFLAGVARIABLE(LuauSubstituteFollowPossibleMutations, false) diff --git a/Analysis/src/TypeInfer.cpp b/Analysis/src/TypeInfer.cpp index 6411e2a..ba91ae1 100644 --- a/Analysis/src/TypeInfer.cpp +++ b/Analysis/src/TypeInfer.cpp @@ -22,29 +22,25 @@ #include 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(iterTy); @@ -1172,7 +1168,12 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatForIn& forin) unify(varTy, var, forin.location); if (!get(iterTy) && !get(iterTy) && !get(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(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 TypeChecker::checkExpr_(const ScopePtr& scope, const AstExprT } } } - else if (FFlag::LuauExpectedTypesOfProperties) - if (const UnionTypeVar* utv = get(follow(*expectedType))) - expectedUnion = utv; + else if (const UnionTypeVar* utv = get(follow(*expectedType))) + expectedUnion = utv; } for (size_t i = 0; i < expr.items.size; ++i) @@ -2334,7 +2333,7 @@ ExprResult 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 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 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 tail = flatten(paramPack, state.log).second; - if (tail) - isVariadic = Luau::isVariadic(*tail); - } + std::optional 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 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 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(overloadsThatMatchArgCount[0]); - if (!overload && !overloadsThatDont.empty()) - overload = get(overloadsThatDont[0]); - if (overload) - return {errorRecoveryTypePack(overload->retType)}; - } + const FunctionTypeVar* overload = nullptr; + if (!overloadsThatMatchArgCount.empty()) + overload = get(overloadsThatMatchArgCount[0]); + if (!overload && !overloadsThatDont.empty()) + overload = get(overloadsThatDont[0]); + if (overload) + return {errorRecoveryTypePack(overload->retType)}; return {errorRecoveryTypePack(retPack)}; } @@ -4129,7 +4077,7 @@ std::optional> 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(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(ty)) return true; else if (get(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(follow(ty)); + const FunctionTypeVar* ftv = get(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(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}; diff --git a/Analysis/src/TypeVar.cpp b/Analysis/src/TypeVar.cpp index 4d42573..463b465 100644 --- a/Analysis/src/TypeVar.cpp +++ b/Analysis/src/TypeVar.cpp @@ -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() diff --git a/Analysis/src/Unifier.cpp b/Analysis/src/Unifier.cpp index 9862d7b..334806c 100644 --- a/Analysis/src/Unifier.cpp +++ b/Analysis/src/Unifier.cpp @@ -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(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(superTy); + TableTypeVar* newSubTable = log.getMutable(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(superTy); - TableTypeVar* newSubTable = log.getMutable(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(superTy); + TableTypeVar* newSubTable = log.getMutable(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(superTy); - TableTypeVar* newSubTable = log.getMutable(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(superTy); - subTable = log.getMutable(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(superTy); - TableTypeVar* newSubTable = log.getMutable(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(superTy); + subTable = log.getMutable(subTy); if (!missingProperties.empty()) { diff --git a/Ast/src/Lexer.cpp b/Ast/src/Lexer.cpp index 5dd4f04..a1f1d46 100644 --- a/Ast/src/Lexer.cpp +++ b/Ast/src/Lexer.cpp @@ -6,8 +6,6 @@ #include -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(); diff --git a/CLI/FileUtils.cpp b/CLI/FileUtils.cpp index fb6ac37..39a14ec 100644 --- a/CLI/FileUtils.cpp +++ b/CLI/FileUtils.cpp @@ -240,7 +240,7 @@ std::optional 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 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 ""; diff --git a/CLI/Repl.cpp b/CLI/Repl.cpp index 345cb7a..4cb2234 100644 --- a/CLI/Repl.cpp +++ b/CLI/Repl.cpp @@ -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"); diff --git a/Compiler/include/Luau/BytecodeBuilder.h b/Compiler/include/Luau/BytecodeBuilder.h index 67b9302..b00440a 100644 --- a/Compiler/include/Luau/BytecodeBuilder.h +++ b/Compiler/include/Luau/BytecodeBuilder.h @@ -232,7 +232,7 @@ private: DenseHashMap stringTable; - DenseHashMap debugRemarks; + std::vector> debugRemarks; std::string debugRemarkBuffer; BytecodeEncoder* encoder = nullptr; diff --git a/Compiler/src/BytecodeBuilder.cpp b/Compiler/src/BytecodeBuilder.cpp index 6c6f122..871a148 100644 --- a/Compiler/src/BytecodeBuilder.cpp +++ b/Compiler/src/BytecodeBuilder.cpp @@ -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) { diff --git a/Compiler/src/Compiler.cpp b/Compiler/src/Compiler.cpp index 810caae..0f17ee0 100644 --- a/Compiler/src/Compiler.cpp +++ b/Compiler/src/Compiler.cpp @@ -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; diff --git a/Compiler/src/CostModel.cpp b/Compiler/src/CostModel.cpp index d8511bd..9afd09f 100644 --- a/Compiler/src/CostModel.cpp +++ b/Compiler/src/CostModel.cpp @@ -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; } diff --git a/Sources.cmake b/Sources.cmake index 60e5dfd..f9263b2 100644 --- a/Sources.cmake +++ b/Sources.cmake @@ -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 diff --git a/VM/include/lua.h b/VM/include/lua.h index d08b73e..c3ebadb 100644 --- a/VM/include/lua.h +++ b/VM/include/lua.h @@ -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); diff --git a/VM/src/lapi.cpp b/VM/src/lapi.cpp index 431f7e5..1f3b094 100644 --- a/VM/src/lapi.cpp +++ b/VM/src/lapi.cpp @@ -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; diff --git a/VM/src/lstate.h b/VM/src/lstate.h index 45d9ba2..423514a 100644 --- a/VM/src/lstate.h +++ b/VM/src/lstate.h @@ -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; diff --git a/VM/src/ltable.cpp b/VM/src/ltable.cpp index dc40b6e..3dc3bd1 100644 --- a/VM/src/ltable.cpp +++ b/VM/src/ltable.cpp @@ -33,7 +33,6 @@ #include -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; diff --git a/VM/src/ludata.cpp b/VM/src/ludata.cpp index 819d186..2815268 100644 --- a/VM/src/ludata.cpp +++ b/VM/src/ludata.cpp @@ -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); } diff --git a/fuzz/proto.cpp b/fuzz/proto.cpp index a48f068..22483f9 100644 --- a/fuzz/proto.cpp +++ b/fuzz/proto.cpp @@ -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 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(); diff --git a/tests/Autocomplete.test.cpp b/tests/Autocomplete.test.cpp index f66e23e..5b70481 100644 --- a/tests/Autocomplete.test.cpp +++ b/tests/Autocomplete.test.cpp @@ -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" diff --git a/tests/Compiler.test.cpp b/tests/Compiler.test.cpp index f3e6069..7b4bfc7 100644 --- a/tests/Compiler.test.cpp +++ b/tests/Compiler.test.cpp @@ -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(); diff --git a/tests/Conformance.test.cpp b/tests/Conformance.test.cpp index 0ed7dc4..6f136d3 100644 --- a/tests/Conformance.test.cpp +++ b/tests/Conformance.test.cpp @@ -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; }); diff --git a/tests/Frontend.test.cpp b/tests/Frontend.test.cpp index 9fc0a00..e771b6b 100644 --- a/tests/Frontend.test.cpp +++ b/tests/Frontend.test.cpp @@ -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(); diff --git a/tests/Module.test.cpp b/tests/Module.test.cpp index af7d76d..44cc20a 100644 --- a/tests/Module.test.cpp +++ b/tests/Module.test.cpp @@ -199,7 +199,6 @@ TEST_CASE_FIXTURE(Fixture, "clone_class") TEST_CASE_FIXTURE(Fixture, "clone_free_types") { ScopedFastFlag sff[]{ - {"LuauErrorRecoveryType", true}, {"LuauLosslessClone", true}, }; diff --git a/tests/NonstrictMode.test.cpp b/tests/NonstrictMode.test.cpp index 9748eb2..feeaf2c 100644 --- a/tests/NonstrictMode.test.cpp +++ b/tests/NonstrictMode.test.cpp @@ -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"( diff --git a/tests/Parser.test.cpp b/tests/Parser.test.cpp index b941103..55eafe3 100644 --- a/tests/Parser.test.cpp +++ b/tests/Parser.test.cpp @@ -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 diff --git a/tests/RuntimeLimits.test.cpp b/tests/RuntimeLimits.test.cpp new file mode 100644 index 0000000..0b615e1 --- /dev/null +++ b/tests/RuntimeLimits.test.cpp @@ -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) + ScopedFastInt LuauTypeInferRecursionLimit{"LuauTypeInferRecursionLimit", 150}; +#endif + + ScopedFastFlag LuauJustOneCallFrameForHaveSeen{"LuauJustOneCallFrameForHaveSeen", true}; +}; + +template +bool hasError(const CheckResult& result, T* = nullptr) +{ + auto it = std::find_if(result.errors.begin(), result.errors.end(), [](const TypeError& a) { + return nullptr != get(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(); diff --git a/tests/TypeInfer.aliases.test.cpp b/tests/TypeInfer.aliases.test.cpp index b2e7605..b0eb31c 100644 --- a/tests/TypeInfer.aliases.test.cpp +++ b/tests/TypeInfer.aliases.test.cpp @@ -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(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 = { data: T, children: Forest } @@ -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 = {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 = { data: T, children: {Tree2} } type Tree2 = { data: U, children: {Tree1} } @@ -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 = { data: T, children: {Tree<{T}>} } diff --git a/tests/TypeInfer.annotations.test.cpp b/tests/TypeInfer.annotations.test.cpp index e2971ad..7f1c757 100644 --- a/tests/TypeInfer.annotations.test.cpp +++ b/tests/TypeInfer.annotations.test.cpp @@ -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 diff --git a/tests/TypeInfer.functions.test.cpp b/tests/TypeInfer.functions.test.cpp index 7cd7bec..0e07121 100644 --- a/tests/TypeInfer.functions.test.cpp +++ b/tests/TypeInfer.functions.test.cpp @@ -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 diff --git a/tests/TypeInfer.generics.test.cpp b/tests/TypeInfer.generics.test.cpp index 49d31fc..91be2c1 100644 --- a/tests/TypeInfer.generics.test.cpp +++ b/tests/TypeInfer.generics.test.cpp @@ -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") diff --git a/tests/TypeInfer.loops.test.cpp b/tests/TypeInfer.loops.test.cpp index 30df717..960c6ed 100644 --- a/tests/TypeInfer.loops.test.cpp +++ b/tests/TypeInfer.loops.test.cpp @@ -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(); diff --git a/tests/TypeInfer.operators.test.cpp b/tests/TypeInfer.operators.test.cpp index 5f2e240..a2787ca 100644 --- a/tests/TypeInfer.operators.test.cpp +++ b/tests/TypeInfer.operators.test.cpp @@ -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 = {} diff --git a/tests/TypeInfer.primitives.test.cpp b/tests/TypeInfer.primitives.test.cpp index 3ddf981..e1684df 100644 --- a/tests/TypeInfer.primitives.test.cpp +++ b/tests/TypeInfer.primitives.test.cpp @@ -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) diff --git a/tests/TypeInfer.provisional.test.cpp b/tests/TypeInfer.provisional.test.cpp index 4b5075d..2ef7741 100644 --- a/tests/TypeInfer.provisional.test.cpp +++ b/tests/TypeInfer.provisional.test.cpp @@ -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(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. diff --git a/tests/TypeInfer.singletons.test.cpp b/tests/TypeInfer.singletons.test.cpp index 2b01c29..8d6682b 100644 --- a/tests/TypeInfer.singletons.test.cpp +++ b/tests/TypeInfer.singletons.test.cpp @@ -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 } diff --git a/tests/TypeInfer.tables.test.cpp b/tests/TypeInfer.tables.test.cpp index 2a727bb..5bd522a 100644 --- a/tests/TypeInfer.tables.test.cpp +++ b/tests/TypeInfer.tables.test.cpp @@ -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 _ diff --git a/tests/TypeInfer.tryUnify.test.cpp b/tests/TypeInfer.tryUnify.test.cpp index c21e162..b6e9326 100644 --- a/tests/TypeInfer.tryUnify.test.cpp +++ b/tests/TypeInfer.tryUnify.test.cpp @@ -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 diff --git a/tests/TypeVar.test.cpp b/tests/TypeVar.test.cpp index d03bb03..e033fe2 100644 --- a/tests/TypeVar.test.cpp +++ b/tests/TypeVar.test.cpp @@ -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}}};