Sync to upstream/release/525 (#467)

This commit is contained in:
Arseny Kapoulkine 2022-04-28 18:24:24 -07:00 committed by GitHub
parent 74c84815a0
commit bd6d44f5e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 527 additions and 641 deletions

View File

@ -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
{

View File

@ -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)

View File

@ -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)

View File

@ -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};

View File

@ -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()

View File

@ -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())
{

View File

@ -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();

View File

@ -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 "";

View File

@ -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");

View File

@ -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;

View File

@ -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)
{

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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();

View File

@ -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"

View File

@ -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();