From a36b1eb29ba5c6c414305b4bbd2b6e2c58ed7d06 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Fri, 13 May 2022 12:36:37 -0700 Subject: [PATCH] Sync to upstream/release/527 (#481) --- Analysis/include/Luau/TypeVar.h | 2 +- Analysis/src/Clone.cpp | 4 +- Analysis/src/Normalize.cpp | 3 +- Analysis/src/Substitution.cpp | 4 +- Analysis/src/ToString.cpp | 16 +- Analysis/src/TypeInfer.cpp | 191 ++++++++------------- Ast/src/Parser.cpp | 3 +- CMakeLists.txt | 6 + Compiler/src/Compiler.cpp | 30 +++- Compiler/src/ConstantFolding.cpp | 6 +- Compiler/src/CostModel.cpp | 2 +- extern/isocline/src/bbcode.c | 1 + tests/AstQuery.test.cpp | 2 +- tests/Autocomplete.test.cpp | 44 +++-- tests/BuiltinDefinitions.test.cpp | 4 +- tests/Compiler.test.cpp | 71 ++++++-- tests/CostModel.test.cpp | 14 +- tests/Fixture.cpp | 19 +- tests/Fixture.h | 5 + tests/Frontend.test.cpp | 2 +- tests/Linter.test.cpp | 6 +- tests/Module.test.cpp | 4 +- tests/NonstrictMode.test.cpp | 6 +- tests/Normalize.test.cpp | 7 +- tests/Parser.test.cpp | 2 - tests/RuntimeLimits.test.cpp | 2 +- tests/ToDot.test.cpp | 2 +- tests/ToString.test.cpp | 4 +- tests/TypeInfer.aliases.test.cpp | 10 +- tests/TypeInfer.annotations.test.cpp | 8 +- tests/TypeInfer.anyerror.test.cpp | 4 +- tests/TypeInfer.builtins.test.cpp | 117 +++++++------ tests/TypeInfer.classes.test.cpp | 2 +- tests/TypeInfer.functions.test.cpp | 38 ++-- tests/TypeInfer.generics.test.cpp | 12 +- tests/TypeInfer.intersectionTypes.test.cpp | 6 +- tests/TypeInfer.loops.test.cpp | 28 +-- tests/TypeInfer.modules.test.cpp | 28 +-- tests/TypeInfer.oop.test.cpp | 4 +- tests/TypeInfer.operators.test.cpp | 71 ++++++-- tests/TypeInfer.provisional.test.cpp | 10 +- tests/TypeInfer.refinements.test.cpp | 20 +-- tests/TypeInfer.singletons.test.cpp | 2 +- tests/TypeInfer.tables.test.cpp | 74 ++++---- tests/TypeInfer.test.cpp | 17 +- tests/TypeInfer.tryUnify.test.cpp | 2 +- tests/TypeInfer.typePacks.cpp | 6 +- tests/TypeInfer.unionTypes.test.cpp | 6 +- 48 files changed, 511 insertions(+), 416 deletions(-) diff --git a/Analysis/include/Luau/TypeVar.h b/Analysis/include/Luau/TypeVar.h index 84576758..9cacbc6d 100644 --- a/Analysis/include/Luau/TypeVar.h +++ b/Analysis/include/Luau/TypeVar.h @@ -329,7 +329,7 @@ struct TableTypeVar // We need to know which is which when we stringify types. std::optional syntheticName; - std::map methodDefinitionLocations; + std::map methodDefinitionLocations; // TODO: Remove with FFlag::LuauNoMethodLocations std::vector instantiatedTypeParams; std::vector instantiatedTypePackParams; ModuleName definitionModuleName; diff --git a/Analysis/src/Clone.cpp b/Analysis/src/Clone.cpp index d5bd9dab..1aa556eb 100644 --- a/Analysis/src/Clone.cpp +++ b/Analysis/src/Clone.cpp @@ -11,6 +11,7 @@ LUAU_FASTFLAG(DebugLuauCopyBeforeNormalizing) LUAU_FASTINTVARIABLE(LuauTypeCloneRecursionLimit, 300) LUAU_FASTFLAG(LuauTypecheckOptPass) LUAU_FASTFLAGVARIABLE(LuauLosslessClone, false) +LUAU_FASTFLAG(LuauNoMethodLocations) namespace Luau { @@ -277,7 +278,8 @@ void TypeCloner::operator()(const TableTypeVar& t) } ttv->definitionModuleName = t.definitionModuleName; - ttv->methodDefinitionLocations = t.methodDefinitionLocations; + if (!FFlag::LuauNoMethodLocations) + ttv->methodDefinitionLocations = t.methodDefinitionLocations; ttv->tags = t.tags; } diff --git a/Analysis/src/Normalize.cpp b/Analysis/src/Normalize.cpp index d8c11388..ef5377a1 100644 --- a/Analysis/src/Normalize.cpp +++ b/Analysis/src/Normalize.cpp @@ -14,7 +14,6 @@ LUAU_FASTFLAGVARIABLE(DebugLuauCopyBeforeNormalizing, false) // This could theoretically be 2000 on amd64, but x86 requires this. LUAU_FASTINTVARIABLE(LuauNormalizeIterationLimit, 1200); LUAU_FASTFLAGVARIABLE(LuauNormalizeCombineTableFix, false); -LUAU_FASTFLAGVARIABLE(LuauNormalizeCombineIntersectionFix, false); namespace Luau { @@ -863,7 +862,7 @@ struct Normalize final : TypeVarVisitor TypeId theTable = result->parts.back(); - if (!get(FFlag::LuauNormalizeCombineIntersectionFix ? follow(theTable) : theTable)) + if (!get(follow(theTable))) { result->parts.push_back(arena.addType(TableTypeVar{TableState::Sealed, TypeLevel{}})); theTable = result->parts.back(); diff --git a/Analysis/src/Substitution.cpp b/Analysis/src/Substitution.cpp index 30d8574a..c5c7977a 100644 --- a/Analysis/src/Substitution.cpp +++ b/Analysis/src/Substitution.cpp @@ -12,6 +12,7 @@ LUAU_FASTINTVARIABLE(LuauTarjanChildLimit, 10000) LUAU_FASTFLAG(LuauTypecheckOptPass) LUAU_FASTFLAGVARIABLE(LuauSubstituteFollowNewTypes, false) LUAU_FASTFLAGVARIABLE(LuauSubstituteFollowPossibleMutations, false) +LUAU_FASTFLAG(LuauNoMethodLocations) namespace Luau { @@ -408,7 +409,8 @@ TypeId Substitution::clone(TypeId ty) { LUAU_ASSERT(!ttv->boundTo); TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, ttv->level, ttv->state}; - clone.methodDefinitionLocations = ttv->methodDefinitionLocations; + if (!FFlag::LuauNoMethodLocations) + clone.methodDefinitionLocations = ttv->methodDefinitionLocations; clone.definitionModuleName = ttv->definitionModuleName; clone.name = ttv->name; clone.syntheticName = ttv->syntheticName; diff --git a/Analysis/src/ToString.cpp b/Analysis/src/ToString.cpp index b5d6a550..51665f7f 100644 --- a/Analysis/src/ToString.cpp +++ b/Analysis/src/ToString.cpp @@ -248,6 +248,13 @@ struct StringifierState result.name += s; } + void emit(TypeLevel level) + { + emit(std::to_string(level.level)); + emit("-"); + emit(std::to_string(level.subLevel)); + } + void emit(const char* s) { if (opts.maxTypeLength > 0 && result.name.length() > opts.maxTypeLength) @@ -379,7 +386,7 @@ struct TypeVarStringifier if (FFlag::DebugLuauVerboseTypeNames) { state.emit("-"); - state.emit(std::to_string(ftv.level.level)); + state.emit(ftv.level); } } @@ -403,7 +410,10 @@ struct TypeVarStringifier { state.result.invalid = true; - state.emit("[["); + state.emit("["); + if (FFlag::DebugLuauVerboseTypeNames) + state.emit(ctv.level); + state.emit("["); bool first = true; for (TypeId ty : ctv.parts) @@ -947,7 +957,7 @@ struct TypePackStringifier if (FFlag::DebugLuauVerboseTypeNames) { state.emit("-"); - state.emit(std::to_string(pack.level.level)); + state.emit(pack.level); } state.emit("..."); diff --git a/Analysis/src/TypeInfer.cpp b/Analysis/src/TypeInfer.cpp index 4466ede2..a13abd53 100644 --- a/Analysis/src/TypeInfer.cpp +++ b/Analysis/src/TypeInfer.cpp @@ -36,13 +36,11 @@ LUAU_FASTFLAGVARIABLE(LuauEqConstraint, false) LUAU_FASTFLAGVARIABLE(LuauWeakEqConstraint, false) // Eventually removed as false. LUAU_FASTFLAGVARIABLE(LuauLowerBoundsCalculation, false) LUAU_FASTFLAGVARIABLE(DebugLuauFreezeDuringUnification, false) -LUAU_FASTFLAGVARIABLE(LuauInferStatFunction, false) LUAU_FASTFLAGVARIABLE(LuauInstantiateFollows, false) LUAU_FASTFLAGVARIABLE(LuauSelfCallAutocompleteFix, false) LUAU_FASTFLAGVARIABLE(LuauDiscriminableUnions2, false) LUAU_FASTFLAGVARIABLE(LuauReduceUnionRecursion, false) LUAU_FASTFLAGVARIABLE(LuauOnlyMutateInstantiatedTables, false) -LUAU_FASTFLAGVARIABLE(LuauStatFunctionSimplify4, false) LUAU_FASTFLAGVARIABLE(LuauTypecheckOptPass, false) LUAU_FASTFLAGVARIABLE(LuauUnsealedTableLiteral, false) LUAU_FASTFLAGVARIABLE(LuauTwoPassAliasDefinitionFix, false) @@ -53,12 +51,13 @@ LUAU_FASTFLAGVARIABLE(LuauDoNotTryToReduce, false) LUAU_FASTFLAGVARIABLE(LuauDoNotAccidentallyDependOnPointerOrdering, false) LUAU_FASTFLAGVARIABLE(LuauCheckImplicitNumbericKeys, false) LUAU_FASTFLAG(LuauAnyInIsOptionalIsOptional) -LUAU_FASTFLAGVARIABLE(LuauDecoupleOperatorInferenceFromUnifiedTypeInference, false) LUAU_FASTFLAGVARIABLE(LuauTableUseCounterInstead, false) LUAU_FASTFLAGVARIABLE(LuauReturnTypeInferenceInNonstrict, false) LUAU_FASTFLAGVARIABLE(LuauRecursionLimitException, false); LUAU_FASTFLAG(LuauLosslessClone) LUAU_FASTFLAGVARIABLE(LuauTypecheckIter, false); +LUAU_FASTFLAGVARIABLE(LuauSuccessTypingForEqualityOperations, false) +LUAU_FASTFLAGVARIABLE(LuauNoMethodLocations, false); namespace Luau { @@ -587,7 +586,7 @@ void TypeChecker::checkBlockWithoutRecursionCheck(const ScopePtr& scope, const A { std::optional expectedType; - if (FFlag::LuauInferStatFunction && !fun->func->self) + if (!fun->func->self) { if (auto name = fun->name->as()) { @@ -1307,7 +1306,7 @@ void TypeChecker::check(const ScopePtr& scope, TypeId ty, const ScopePtr& funSco scope->bindings[name->local] = {anyIfNonstrict(quantify(funScope, ty, name->local->location)), name->local->location}; return; } - else if (auto name = function.name->as(); name && FFlag::LuauStatFunctionSimplify4) + else if (auto name = function.name->as()) { TypeId exprTy = checkExpr(scope, *name->expr).type; TableTypeVar* ttv = getMutableTableType(exprTy); @@ -1341,7 +1340,7 @@ void TypeChecker::check(const ScopePtr& scope, TypeId ty, const ScopePtr& funSco if (ttv && ttv->state != TableState::Sealed) ttv->props[name->index.value] = {follow(quantify(funScope, ty, name->indexLocation)), /* deprecated */ false, {}, name->indexLocation}; } - else if (FFlag::LuauStatFunctionSimplify4) + else { LUAU_ASSERT(function.name->is()); @@ -1349,71 +1348,6 @@ void TypeChecker::check(const ScopePtr& scope, TypeId ty, const ScopePtr& funSco checkFunctionBody(funScope, ty, *function.func); } - else if (function.func->self) - { - LUAU_ASSERT(!FFlag::LuauStatFunctionSimplify4); - - AstExprIndexName* indexName = function.name->as(); - if (!indexName) - ice("member function declaration has malformed name expression"); - - TypeId selfTy = checkExpr(scope, *indexName->expr).type; - TableTypeVar* tableSelf = getMutableTableType(selfTy); - if (!tableSelf) - { - if (isTableIntersection(selfTy)) - reportError(TypeError{function.location, CannotExtendTable{selfTy, CannotExtendTable::Property, indexName->index.value}}); - else if (!get(selfTy) && !get(selfTy)) - reportError(TypeError{function.location, OnlyTablesCanHaveMethods{selfTy}}); - } - else if (tableSelf->state == TableState::Sealed) - reportError(TypeError{function.location, CannotExtendTable{selfTy, CannotExtendTable::Property, indexName->index.value}}); - - const bool tableIsExtendable = tableSelf && tableSelf->state != TableState::Sealed; - - ty = follow(ty); - - if (tableIsExtendable) - tableSelf->props[indexName->index.value] = {ty, /* deprecated */ false, {}, indexName->indexLocation}; - - const FunctionTypeVar* funTy = get(ty); - if (!funTy) - ice("Methods should be functions"); - - std::optional arg0 = first(funTy->argTypes); - if (!arg0) - ice("Methods should always have at least 1 argument (self)"); - - checkFunctionBody(funScope, ty, *function.func); - - if (tableIsExtendable) - tableSelf->props[indexName->index.value] = { - follow(quantify(funScope, ty, indexName->indexLocation)), /* deprecated */ false, {}, indexName->indexLocation}; - } - else - { - LUAU_ASSERT(!FFlag::LuauStatFunctionSimplify4); - - TypeId leftType = checkLValueBinding(scope, *function.name); - - checkFunctionBody(funScope, ty, *function.func); - - unify(ty, leftType, function.location); - - LUAU_ASSERT(function.name->is() || function.name->is()); - - if (auto exprIndexName = function.name->as()) - { - if (auto typeIt = currentModule->astTypes.find(exprIndexName->expr)) - { - if (auto ttv = getMutableTableType(*typeIt)) - { - if (auto it = ttv->props.find(exprIndexName->index.value); it != ttv->props.end()) - it->second.type = follow(quantify(funScope, leftType, function.name->location)); - } - } - } - } } void TypeChecker::check(const ScopePtr& scope, TypeId ty, const ScopePtr& funScope, const AstStatLocalFunction& function) @@ -1523,7 +1457,8 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatTypeAlias& typealias // This is a shallow clone, original recursive links to self are not updated TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, ttv->level, ttv->state}; - clone.methodDefinitionLocations = ttv->methodDefinitionLocations; + if (!FFlag::LuauNoMethodLocations) + clone.methodDefinitionLocations = ttv->methodDefinitionLocations; clone.definitionModuleName = ttv->definitionModuleName; clone.name = name; @@ -2652,13 +2587,58 @@ TypeId TypeChecker::checkRelationalOperation( std::optional leftMetatable = isString(lhsType) ? std::nullopt : getMetatable(follow(lhsType)); std::optional rightMetatable = isString(rhsType) ? std::nullopt : getMetatable(follow(rhsType)); - // TODO: this check seems odd, the second part is redundant - // is it meant to be if (leftMetatable && rightMetatable && leftMetatable != rightMetatable) - if (bool(leftMetatable) != bool(rightMetatable) && leftMetatable != rightMetatable) + if (FFlag::LuauSuccessTypingForEqualityOperations) { - reportError(expr.location, GenericError{format("Types %s and %s cannot be compared with %s because they do not have the same metatable", - toString(lhsType).c_str(), toString(rhsType).c_str(), toString(expr.op).c_str())}); - return errorRecoveryType(booleanType); + if (leftMetatable != rightMetatable) + { + bool matches = false; + if (isEquality) + { + if (const UnionTypeVar* utv = get(leftType); utv && rightMetatable) + { + for (TypeId leftOption : utv) + { + if (getMetatable(follow(leftOption)) == rightMetatable) + { + matches = true; + break; + } + } + } + + if (!matches) + { + if (const UnionTypeVar* utv = get(rhsType); utv && leftMetatable) + { + for (TypeId rightOption : utv) + { + if (getMetatable(follow(rightOption)) == leftMetatable) + { + matches = true; + break; + } + } + } + } + } + + + if (!matches) + { + reportError(expr.location, GenericError{format("Types %s and %s cannot be compared with %s because they do not have the same metatable", + toString(lhsType).c_str(), toString(rhsType).c_str(), toString(expr.op).c_str())}); + return errorRecoveryType(booleanType); + } + } + } + else + { + if (bool(leftMetatable) != bool(rightMetatable) && leftMetatable != rightMetatable) + { + reportError(expr.location, GenericError{format("Types %s and %s cannot be compared with %s because they do not have the same metatable", + toString(lhsType).c_str(), toString(rhsType).c_str(), toString(expr.op).c_str())}); + return errorRecoveryType(booleanType); + } } if (leftMetatable) @@ -2754,22 +2734,11 @@ TypeId TypeChecker::checkBinaryOperation( lhsType = follow(lhsType); rhsType = follow(rhsType); - if (FFlag::LuauDecoupleOperatorInferenceFromUnifiedTypeInference) + if (!isNonstrictMode() && get(lhsType)) { - if (!isNonstrictMode() && get(lhsType)) - { - auto name = getIdentifierOfBaseVar(expr.left); - reportError(expr.location, CannotInferBinaryOperation{expr.op, name, CannotInferBinaryOperation::Operation}); - // We will fall-through to the `return anyType` check below. - } - } - else - { - if (!isNonstrictMode() && get(lhsType)) - { - auto name = getIdentifierOfBaseVar(expr.left); - reportError(expr.location, CannotInferBinaryOperation{expr.op, name, CannotInferBinaryOperation::Operation}); - } + auto name = getIdentifierOfBaseVar(expr.left); + reportError(expr.location, CannotInferBinaryOperation{expr.op, name, CannotInferBinaryOperation::Operation}); + // We will fall-through to the `return anyType` check below. } // If we know nothing at all about the lhs type, we can usually say nothing about the result. @@ -3231,43 +3200,27 @@ TypeId TypeChecker::checkFunctionName(const ScopePtr& scope, AstExpr& funName, T else if (auto indexName = funName.as()) { TypeId lhsType = checkExpr(scope, *indexName->expr).type; - - if (!FFlag::LuauStatFunctionSimplify4 && (get(lhsType) || get(lhsType))) - return lhsType; - TableTypeVar* ttv = getMutableTableType(lhsType); - if (FFlag::LuauStatFunctionSimplify4) + if (!ttv || ttv->state == TableState::Sealed) { - if (!ttv || ttv->state == TableState::Sealed) - { - if (auto ty = getIndexTypeFromType(scope, lhsType, indexName->index.value, indexName->indexLocation, false)) - return *ty; + if (auto ty = getIndexTypeFromType(scope, lhsType, indexName->index.value, indexName->indexLocation, false)) + return *ty; - return errorRecoveryType(scope); - } - } - else - { - if (!ttv || lhsType->persistent || ttv->state == TableState::Sealed) - return errorRecoveryType(scope); + return errorRecoveryType(scope); } Name name = indexName->index.value; if (ttv->props.count(name)) - { - if (FFlag::LuauStatFunctionSimplify4) - return ttv->props[name].type; - else - return errorRecoveryType(scope); - } + return ttv->props[name].type; Property& property = ttv->props[name]; property.type = freshTy(); property.location = indexName->indexLocation; - ttv->methodDefinitionLocations[name] = funName.location; + if (!FFlag::LuauNoMethodLocations) + ttv->methodDefinitionLocations[name] = funName.location; return property.type; } else if (funName.is()) @@ -4669,7 +4622,8 @@ TypeId ReplaceGenerics::clean(TypeId ty) if (const TableTypeVar* ttv = log->getMutable(ty)) { TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, level, TableState::Free}; - clone.methodDefinitionLocations = ttv->methodDefinitionLocations; + if (!FFlag::LuauNoMethodLocations) + clone.methodDefinitionLocations = ttv->methodDefinitionLocations; clone.definitionModuleName = ttv->definitionModuleName; return addType(std::move(clone)); } @@ -4715,7 +4669,8 @@ TypeId Anyification::clean(TypeId ty) if (const TableTypeVar* ttv = log->getMutable(ty)) { TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, ttv->level, TableState::Sealed}; - clone.methodDefinitionLocations = ttv->methodDefinitionLocations; + if (!FFlag::LuauNoMethodLocations) + clone.methodDefinitionLocations = ttv->methodDefinitionLocations; clone.definitionModuleName = ttv->definitionModuleName; clone.name = ttv->name; clone.syntheticName = ttv->syntheticName; diff --git a/Ast/src/Parser.cpp b/Ast/src/Parser.cpp index 91f5cd25..c053e6bd 100644 --- a/Ast/src/Parser.cpp +++ b/Ast/src/Parser.cpp @@ -10,7 +10,6 @@ // See docs/SyntaxChanges.md for an explanation. LUAU_FASTINTVARIABLE(LuauRecursionLimit, 1000) LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100) -LUAU_FASTFLAGVARIABLE(LuauParseLocationIgnoreCommentSkipInCapture, false) namespace Luau { @@ -2821,7 +2820,7 @@ void Parser::nextLexeme() hotcomments.push_back({hotcommentHeader, lexeme.location, std::string(text + 1, text + end)}); } - type = lexer.next(/* skipComments= */ false, !FFlag::LuauParseLocationIgnoreCommentSkipInCapture).type; + type = lexer.next(/* skipComments= */ false, /* updatePrevLocation= */ false).type; } } else diff --git a/CMakeLists.txt b/CMakeLists.txt index af03b33a..ea352309 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,6 +110,12 @@ if (MSVC AND MSVC_VERSION GREATER_EQUAL 1924) set_source_files_properties(VM/src/lvmexecute.cpp PROPERTIES COMPILE_FLAGS /d2ssa-pre-) endif() +if(MSVC AND LUAU_BUILD_CLI) + # the default stack size that MSVC linker uses is 1 MB; we need more stack space in Debug because stack frames are larger + set_target_properties(Luau.Analyze.CLI PROPERTIES LINK_FLAGS_DEBUG /STACK:2097152) + set_target_properties(Luau.Repl.CLI PROPERTIES LINK_FLAGS_DEBUG /STACK:2097152) +endif() + # embed .natvis inside the library debug information if(MSVC) target_link_options(Luau.Ast INTERFACE /NATVIS:${CMAKE_CURRENT_SOURCE_DIR}/tools/natvis/Ast.natvis) diff --git a/Compiler/src/Compiler.cpp b/Compiler/src/Compiler.cpp index 4fe26222..e177e928 100644 --- a/Compiler/src/Compiler.cpp +++ b/Compiler/src/Compiler.cpp @@ -628,7 +628,12 @@ struct Compiler return; if (fi && !fi->canInline) - bytecode.addDebugRemark("inlining failed: complex constructs in function body"); + { + if (func->vararg) + bytecode.addDebugRemark("inlining failed: function is variadic"); + else + bytecode.addDebugRemark("inlining failed: complex constructs in function body"); + } } RegScope rs(this); @@ -2342,17 +2347,28 @@ struct Compiler RegScope rs(this); uint8_t temp = 0; + bool consecutive = false; bool multRet = false; - // Optimization: return local value directly instead of copying it into a temporary - if (stat->list.size == 1 && isExprLocalReg(stat->list.data[0])) + // Optimization: return locals directly instead of copying them into a temporary + // this is very important for a single return value and occasionally effective for multiple values + if (stat->list.size > 0 && isExprLocalReg(stat->list.data[0])) { - AstExprLocal* le = stat->list.data[0]->as(); - LUAU_ASSERT(le); + temp = getLocal(stat->list.data[0]->as()->local); + consecutive = true; - temp = getLocal(le->local); + for (size_t i = 1; i < stat->list.size; ++i) + { + AstExpr* v = stat->list.data[i]; + if (!isExprLocalReg(v) || getLocal(v->as()->local) != temp + i) + { + consecutive = false; + break; + } + } } - else if (stat->list.size > 0) + + if (!consecutive && stat->list.size > 0) { temp = allocReg(stat, unsigned(stat->list.size)); diff --git a/Compiler/src/ConstantFolding.cpp b/Compiler/src/ConstantFolding.cpp index 52ece73e..e4d59ea1 100644 --- a/Compiler/src/ConstantFolding.cpp +++ b/Compiler/src/ConstantFolding.cpp @@ -195,12 +195,16 @@ struct ConstantVisitor : AstVisitor DenseHashMap& variables; DenseHashMap& locals; + bool wasEmpty = false; + ConstantVisitor( DenseHashMap& constants, DenseHashMap& variables, DenseHashMap& locals) : constants(constants) , variables(variables) , locals(locals) { + // since we do a single pass over the tree, if the initial state was empty we don't need to clear out old entries + wasEmpty = constants.empty() && locals.empty(); } Constant analyze(AstExpr* node) @@ -326,7 +330,7 @@ struct ConstantVisitor : AstVisitor { if (value.type != Constant::Type_Unknown) map[key] = value; - else if (!FFlag::LuauCompileSupportInlining) + else if (!FFlag::LuauCompileSupportInlining || wasEmpty) ; else if (Constant* old = map.find(key)) old->type = Constant::Type_Unknown; diff --git a/Compiler/src/CostModel.cpp b/Compiler/src/CostModel.cpp index 9afd09f6..f804e9de 100644 --- a/Compiler/src/CostModel.cpp +++ b/Compiler/src/CostModel.cpp @@ -187,7 +187,7 @@ struct CostVisitor : AstVisitor if (node->is()) result += 2; else if (node->is() || node->is() || node->is() || node->is()) - result += 2; + result += 5; else if (node->is() || node->is()) result += 1; diff --git a/extern/isocline/src/bbcode.c b/extern/isocline/src/bbcode.c index 4d11ac38..8722cbd6 100644 --- a/extern/isocline/src/bbcode.c +++ b/extern/isocline/src/bbcode.c @@ -575,6 +575,7 @@ ic_private const char* parse_tag_value( tag_t* tag, char* idbuf, const char* s, } // limit name and attr to 128 bytes char valbuf[128]; + valbuf[0] = 0; // fixes gcc uninitialized warning ic_strncpy( idbuf, 128, id, idend - id); ic_strncpy( valbuf, 128, val, valend - val); ic_str_tolower(idbuf); diff --git a/tests/AstQuery.test.cpp b/tests/AstQuery.test.cpp index 292625b0..12c68450 100644 --- a/tests/AstQuery.test.cpp +++ b/tests/AstQuery.test.cpp @@ -7,7 +7,7 @@ using namespace Luau; -struct DocumentationSymbolFixture : Fixture +struct DocumentationSymbolFixture : BuiltinsFixture { std::optional getDocSymbol(const std::string& source, Position position) { diff --git a/tests/Autocomplete.test.cpp b/tests/Autocomplete.test.cpp index 1c284f1f..b4e9340c 100644 --- a/tests/Autocomplete.test.cpp +++ b/tests/Autocomplete.test.cpp @@ -27,7 +27,7 @@ template struct ACFixtureImpl : BaseType { ACFixtureImpl() - : Fixture(true, true) + : BaseType(true, true) { } @@ -111,6 +111,18 @@ struct ACFixtureImpl : BaseType }; struct ACFixture : ACFixtureImpl +{ + ACFixture() + : ACFixtureImpl() + { + addGlobalBinding(frontend.typeChecker, "table", Binding{typeChecker.anyType}); + addGlobalBinding(frontend.typeChecker, "math", Binding{typeChecker.anyType}); + addGlobalBinding(frontend.typeCheckerForAutocomplete, "table", Binding{typeChecker.anyType}); + addGlobalBinding(frontend.typeCheckerForAutocomplete, "math", Binding{typeChecker.anyType}); + } +}; + +struct ACBuiltinsFixture : ACFixtureImpl { }; @@ -277,7 +289,7 @@ TEST_CASE_FIXTURE(ACFixture, "function_parameters") CHECK(ac.entryMap.count("test")); } -TEST_CASE_FIXTURE(ACFixture, "get_member_completions") +TEST_CASE_FIXTURE(ACBuiltinsFixture, "get_member_completions") { check(R"( local a = table.@1 @@ -376,7 +388,7 @@ TEST_CASE_FIXTURE(ACFixture, "table_intersection") CHECK(ac.entryMap.count("c3")); } -TEST_CASE_FIXTURE(ACFixture, "get_string_completions") +TEST_CASE_FIXTURE(ACBuiltinsFixture, "get_string_completions") { check(R"( local a = ("foo"):@1 @@ -427,7 +439,7 @@ TEST_CASE_FIXTURE(ACFixture, "method_call_inside_function_body") CHECK(!ac.entryMap.count("math")); } -TEST_CASE_FIXTURE(ACFixture, "method_call_inside_if_conditional") +TEST_CASE_FIXTURE(ACBuiltinsFixture, "method_call_inside_if_conditional") { check(R"( if table: @1 @@ -1884,7 +1896,7 @@ ex.b(function(x: CHECK(!ac.entryMap.count("(done) -> number")); } -TEST_CASE_FIXTURE(ACFixture, "suggest_external_module_type") +TEST_CASE_FIXTURE(ACBuiltinsFixture, "suggest_external_module_type") { fileResolver.source["Module/A"] = R"( export type done = { x: number, y: number } @@ -2235,7 +2247,7 @@ local a: aaa.do CHECK(ac.entryMap.count("other")); } -TEST_CASE_FIXTURE(ACFixture, "autocompleteSource") +TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocompleteSource") { std::string_view source = R"( local a = table. -- Line 1 @@ -2269,7 +2281,7 @@ TEST_CASE_FIXTURE(ACFixture, "autocompleteSource_comments") CHECK_EQ(0, ac.entryMap.size()); } -TEST_CASE_FIXTURE(ACFixture, "autocompleteProp_index_function_metamethod_is_variadic") +TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocompleteProp_index_function_metamethod_is_variadic") { std::string_view source = R"( type Foo = {x: number} @@ -2720,7 +2732,7 @@ type A = () -> T CHECK(ac.entryMap.count("string")); } -TEST_CASE_FIXTURE(ACFixture, "autocomplete_oop_implicit_self") +TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocomplete_oop_implicit_self") { check(R"( --!strict @@ -2728,15 +2740,15 @@ local Class = {} Class.__index = Class type Class = typeof(setmetatable({} :: { x: number }, Class)) function Class.new(x: number): Class - return setmetatable({x = x}, Class) + return setmetatable({x = x}, Class) end function Class.getx(self: Class) - return self.x + return self.x end function test() - local c = Class.new(42) - local n = c:@1 - print(n) + local c = Class.new(42) + local n = c:@1 + print(n) end )"); @@ -2745,7 +2757,7 @@ end CHECK(ac.entryMap.count("getx")); } -TEST_CASE_FIXTURE(ACFixture, "autocomplete_on_string_singletons") +TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocomplete_on_string_singletons") { check(R"( --!strict @@ -2989,7 +3001,7 @@ s.@1 CHECK(ac.entryMap["sub"].wrongIndexType == true); } -TEST_CASE_FIXTURE(ACFixture, "string_library_non_self_calls_are_fine") +TEST_CASE_FIXTURE(ACBuiltinsFixture, "string_library_non_self_calls_are_fine") { ScopedFastFlag selfCallAutocompleteFix{"LuauSelfCallAutocompleteFix", true}; @@ -3007,7 +3019,7 @@ string.@1 CHECK(ac.entryMap["sub"].wrongIndexType == false); } -TEST_CASE_FIXTURE(ACFixture, "string_library_self_calls_are_invalid") +TEST_CASE_FIXTURE(ACBuiltinsFixture, "string_library_self_calls_are_invalid") { ScopedFastFlag selfCallAutocompleteFix{"LuauSelfCallAutocompleteFix", true}; diff --git a/tests/BuiltinDefinitions.test.cpp b/tests/BuiltinDefinitions.test.cpp index dbe80f2c..496df4b4 100644 --- a/tests/BuiltinDefinitions.test.cpp +++ b/tests/BuiltinDefinitions.test.cpp @@ -10,8 +10,10 @@ using namespace Luau; TEST_SUITE_BEGIN("BuiltinDefinitionsTest"); -TEST_CASE_FIXTURE(Fixture, "lib_documentation_symbols") +TEST_CASE_FIXTURE(BuiltinsFixture, "lib_documentation_symbols") { + CHECK(!typeChecker.globalScope->bindings.empty()); + for (const auto& [name, binding] : typeChecker.globalScope->bindings) { std::string nameString(name.c_str()); diff --git a/tests/Compiler.test.cpp b/tests/Compiler.test.cpp index f206438f..b032060e 100644 --- a/tests/Compiler.test.cpp +++ b/tests/Compiler.test.cpp @@ -4713,7 +4713,6 @@ local function foo() end local a, b = foo() - return a, b )", 1, 2), @@ -4721,9 +4720,7 @@ return a, b DUPCLOSURE R0 K0 LOADNIL R1 LOADNIL R2 -MOVE R3 R1 -MOVE R4 R2 -RETURN R3 2 +RETURN R1 2 )"); // this happens even if the function returns conditionally @@ -4733,7 +4730,6 @@ local function foo(a) end local a, b = foo(false) - return a, b )", 1, 2), @@ -4741,9 +4737,7 @@ return a, b DUPCLOSURE R0 K0 LOADNIL R1 LOADNIL R2 -MOVE R3 R1 -MOVE R4 R2 -RETURN R3 2 +RETURN R1 2 )"); // note though that we can't inline a function like this in multret context @@ -4880,11 +4874,7 @@ LOADN R5 1 ADD R4 R5 R1 LOADN R5 3 ADD R6 R1 R2 -MOVE R7 R3 -MOVE R8 R4 -MOVE R9 R5 -MOVE R10 R6 -RETURN R7 4 +RETURN R3 4 )"); } @@ -5151,4 +5141,59 @@ RETURN R0 0 )"); } +TEST_CASE("ReturnConsecutive") +{ + // we can return a single local directly + CHECK_EQ("\n" + compileFunction0(R"( +local x = ... +return x +)"), + R"( +GETVARARGS R0 1 +RETURN R0 1 +)"); + + // or multiple, when they are allocated in consecutive registers + CHECK_EQ("\n" + compileFunction0(R"( +local x, y = ... +return x, y +)"), + R"( +GETVARARGS R0 2 +RETURN R0 2 +)"); + + // but not if it's an expression + CHECK_EQ("\n" + compileFunction0(R"( +local x, y = ... +return x, y + 1 +)"), + R"( +GETVARARGS R0 2 +MOVE R2 R0 +ADDK R3 R1 K0 +RETURN R2 2 +)"); + + // or a local with wrong register number + CHECK_EQ("\n" + compileFunction0(R"( +local x, y = ... +return y, x +)"), + R"( +GETVARARGS R0 2 +MOVE R2 R1 +MOVE R3 R0 +RETURN R2 2 +)"); + + // also double check the optimization doesn't trip on no-argument return (these are rare) + CHECK_EQ("\n" + compileFunction0(R"( +return +)"), + R"( +RETURN R0 0 +)"); +} + TEST_SUITE_END(); diff --git a/tests/CostModel.test.cpp b/tests/CostModel.test.cpp index aa5b7284..2fa0659b 100644 --- a/tests/CostModel.test.cpp +++ b/tests/CostModel.test.cpp @@ -76,9 +76,9 @@ end const bool args1[] = {false}; const bool args2[] = {true}; - // loop baseline cost is 2 - CHECK_EQ(3, Luau::Compile::computeCost(model, args1, 1)); - CHECK_EQ(3, Luau::Compile::computeCost(model, args2, 1)); + // loop baseline cost is 5 + CHECK_EQ(6, Luau::Compile::computeCost(model, args1, 1)); + CHECK_EQ(6, Luau::Compile::computeCost(model, args2, 1)); } TEST_CASE("MutableVariable") @@ -154,8 +154,8 @@ end const bool args1[] = {false}; const bool args2[] = {true}; - CHECK_EQ(38, Luau::Compile::computeCost(model, args1, 1)); - CHECK_EQ(37, Luau::Compile::computeCost(model, args2, 1)); + CHECK_EQ(50, Luau::Compile::computeCost(model, args1, 1)); + CHECK_EQ(49, Luau::Compile::computeCost(model, args2, 1)); } TEST_CASE("Conditional") @@ -219,8 +219,8 @@ end const bool args1[] = {false}; const bool args2[] = {true}; - CHECK_EQ(4, Luau::Compile::computeCost(model, args1, 1)); - CHECK_EQ(3, Luau::Compile::computeCost(model, args2, 1)); + CHECK_EQ(7, Luau::Compile::computeCost(model, args1, 1)); + CHECK_EQ(6, Luau::Compile::computeCost(model, args2, 1)); } TEST_SUITE_END(); diff --git a/tests/Fixture.cpp b/tests/Fixture.cpp index d8b37a65..03f3e15c 100644 --- a/tests/Fixture.cpp +++ b/tests/Fixture.cpp @@ -92,10 +92,6 @@ Fixture::Fixture(bool freeze, bool prepareAutocomplete) configResolver.defaultConfig.enabledLint.warningMask = ~0ull; configResolver.defaultConfig.parseOptions.captureComments = true; - registerBuiltinTypes(frontend.typeChecker); - if (prepareAutocomplete) - registerBuiltinTypes(frontend.typeCheckerForAutocomplete); - registerTestTypes(); Luau::freeze(frontend.typeChecker.globalTypes); Luau::freeze(frontend.typeCheckerForAutocomplete.globalTypes); @@ -410,6 +406,21 @@ LoadDefinitionFileResult Fixture::loadDefinition(const std::string& source) return result; } +BuiltinsFixture::BuiltinsFixture(bool freeze, bool prepareAutocomplete) + : Fixture(freeze, prepareAutocomplete) +{ + Luau::unfreeze(frontend.typeChecker.globalTypes); + Luau::unfreeze(frontend.typeCheckerForAutocomplete.globalTypes); + + registerBuiltinTypes(frontend.typeChecker); + if (prepareAutocomplete) + registerBuiltinTypes(frontend.typeCheckerForAutocomplete); + registerTestTypes(); + + Luau::freeze(frontend.typeChecker.globalTypes); + Luau::freeze(frontend.typeCheckerForAutocomplete.globalTypes); +} + ModuleName fromString(std::string_view name) { return ModuleName(name); diff --git a/tests/Fixture.h b/tests/Fixture.h index 0d1233bf..901f7d42 100644 --- a/tests/Fixture.h +++ b/tests/Fixture.h @@ -151,6 +151,11 @@ struct Fixture LoadDefinitionFileResult loadDefinition(const std::string& source); }; +struct BuiltinsFixture : Fixture +{ + BuiltinsFixture(bool freeze = true, bool prepareAutocomplete = false); +}; + ModuleName fromString(std::string_view name); template diff --git a/tests/Frontend.test.cpp b/tests/Frontend.test.cpp index a10e8f7f..33b81be8 100644 --- a/tests/Frontend.test.cpp +++ b/tests/Frontend.test.cpp @@ -77,7 +77,7 @@ struct NaiveFileResolver : NullFileResolver } // namespace -struct FrontendFixture : Fixture +struct FrontendFixture : BuiltinsFixture { FrontendFixture() { diff --git a/tests/Linter.test.cpp b/tests/Linter.test.cpp index 6649cb7f..202aeceb 100644 --- a/tests/Linter.test.cpp +++ b/tests/Linter.test.cpp @@ -75,7 +75,7 @@ _ = 6 CHECK_EQ(result.warnings.size(), 0); } -TEST_CASE_FIXTURE(Fixture, "BuiltinGlobalWrite") +TEST_CASE_FIXTURE(BuiltinsFixture, "BuiltinGlobalWrite") { LintResult result = lint(R"( math = {} @@ -309,7 +309,7 @@ print(arg) CHECK_EQ(result.warnings[0].text, "Variable 'arg' shadows previous declaration at line 2"); } -TEST_CASE_FIXTURE(Fixture, "LocalShadowGlobal") +TEST_CASE_FIXTURE(BuiltinsFixture, "LocalShadowGlobal") { LintResult result = lint(R"( local math = math @@ -1470,7 +1470,7 @@ end CHECK_EQ(result.warnings[2].text, "Member 'Instance.DataCost' is deprecated"); } -TEST_CASE_FIXTURE(Fixture, "TableOperations") +TEST_CASE_FIXTURE(BuiltinsFixture, "TableOperations") { LintResult result = lintTyped(R"( local t = {} diff --git a/tests/Module.test.cpp b/tests/Module.test.cpp index 44cc20a7..4a999861 100644 --- a/tests/Module.test.cpp +++ b/tests/Module.test.cpp @@ -113,7 +113,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table") CHECK_EQ(2, dest.typeVars.size()); // One table and one function } -TEST_CASE_FIXTURE(Fixture, "builtin_types_point_into_globalTypes_arena") +TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_point_into_globalTypes_arena") { CheckResult result = check(R"( return {sign=math.sign} @@ -250,7 +250,7 @@ TEST_CASE_FIXTURE(Fixture, "clone_constrained_intersection") CHECK_EQ(getSingletonTypes().stringType, ctv->parts[1]); } -TEST_CASE_FIXTURE(Fixture, "clone_self_property") +TEST_CASE_FIXTURE(BuiltinsFixture, "clone_self_property") { ScopedFastFlag sff{"LuauAnyInIsOptionalIsOptional", true}; diff --git a/tests/NonstrictMode.test.cpp b/tests/NonstrictMode.test.cpp index feeaf2c2..69430b1c 100644 --- a/tests/NonstrictMode.test.cpp +++ b/tests/NonstrictMode.test.cpp @@ -13,7 +13,7 @@ using namespace Luau; TEST_SUITE_BEGIN("NonstrictModeTests"); -TEST_CASE_FIXTURE(Fixture, "function_returns_number_or_string") +TEST_CASE_FIXTURE(BuiltinsFixture, "function_returns_number_or_string") { ScopedFastFlag sff[]{ {"LuauReturnTypeInferenceInNonstrict", true}, @@ -224,7 +224,7 @@ TEST_CASE_FIXTURE(Fixture, "inline_table_props_are_also_any") CHECK_MESSAGE(get(ttv->props["three"].type), "Should be a function: " << *ttv->props["three"].type); } -TEST_CASE_FIXTURE(Fixture, "for_in_iterator_variables_are_any") +TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_iterator_variables_are_any") { CheckResult result = check(R"( --!nonstrict @@ -243,7 +243,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_iterator_variables_are_any") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "table_dot_insert_and_recursive_calls") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_dot_insert_and_recursive_calls") { CheckResult result = check(R"( --!nonstrict diff --git a/tests/Normalize.test.cpp b/tests/Normalize.test.cpp index d3778f67..41830682 100644 --- a/tests/Normalize.test.cpp +++ b/tests/Normalize.test.cpp @@ -739,7 +739,7 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_table_normalizes_sensibly") CHECK_EQ("t1 where t1 = { get: () -> t1 }", toString(ty, {true})); } -TEST_CASE_FIXTURE(Fixture, "union_of_distinct_free_types") +TEST_CASE_FIXTURE(BuiltinsFixture, "union_of_distinct_free_types") { ScopedFastFlag flags[] = { {"LuauLowerBoundsCalculation", true}, @@ -760,7 +760,7 @@ TEST_CASE_FIXTURE(Fixture, "union_of_distinct_free_types") CHECK("(a, b) -> a | b" == toString(requireType("fussy"))); } -TEST_CASE_FIXTURE(Fixture, "constrained_intersection_of_intersections") +TEST_CASE_FIXTURE(BuiltinsFixture, "constrained_intersection_of_intersections") { ScopedFastFlag flags[] = { {"LuauLowerBoundsCalculation", true}, @@ -951,7 +951,7 @@ TEST_CASE_FIXTURE(Fixture, "nested_table_normalization_with_non_table__no_ice") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "visiting_a_type_twice_is_not_considered_normal") +TEST_CASE_FIXTURE(BuiltinsFixture, "visiting_a_type_twice_is_not_considered_normal") { ScopedFastFlag sff{"LuauLowerBoundsCalculation", true}; @@ -976,7 +976,6 @@ TEST_CASE_FIXTURE(Fixture, "fuzz_failure_instersection_combine_must_follow") { ScopedFastFlag flags[] = { {"LuauLowerBoundsCalculation", true}, - {"LuauNormalizeCombineIntersectionFix", true}, }; CheckResult result = check(R"( diff --git a/tests/Parser.test.cpp b/tests/Parser.test.cpp index 69ff73ad..c9d8d0b8 100644 --- a/tests/Parser.test.cpp +++ b/tests/Parser.test.cpp @@ -1618,8 +1618,6 @@ TEST_CASE_FIXTURE(Fixture, "end_extent_doesnt_consume_comments") TEST_CASE_FIXTURE(Fixture, "end_extent_doesnt_consume_comments_even_with_capture") { - ScopedFastFlag luauParseLocationIgnoreCommentSkipInCapture{"LuauParseLocationIgnoreCommentSkipInCapture", true}; - // Same should hold when comments are captured ParseOptions opts; opts.captureComments = true; diff --git a/tests/RuntimeLimits.test.cpp b/tests/RuntimeLimits.test.cpp index 538f3576..c16f60d5 100644 --- a/tests/RuntimeLimits.test.cpp +++ b/tests/RuntimeLimits.test.cpp @@ -17,7 +17,7 @@ using namespace Luau; LUAU_FASTFLAG(LuauLowerBoundsCalculation); -struct LimitFixture : Fixture +struct LimitFixture : BuiltinsFixture { #if defined(_NOOPT) || defined(_DEBUG) ScopedFastInt LuauTypeInferRecursionLimit{"LuauTypeInferRecursionLimit", 100}; diff --git a/tests/ToDot.test.cpp b/tests/ToDot.test.cpp index 332a4b22..e9fa5b26 100644 --- a/tests/ToDot.test.cpp +++ b/tests/ToDot.test.cpp @@ -224,7 +224,7 @@ n1 -> n4 [label="typePackParam"]; (void)toDot(requireType("a")); } -TEST_CASE_FIXTURE(Fixture, "metatable") +TEST_CASE_FIXTURE(BuiltinsFixture, "metatable") { CheckResult result = check(R"( local a: typeof(setmetatable({}, {})) diff --git a/tests/ToString.test.cpp b/tests/ToString.test.cpp index ccf5c583..50d0838e 100644 --- a/tests/ToString.test.cpp +++ b/tests/ToString.test.cpp @@ -60,7 +60,7 @@ TEST_CASE_FIXTURE(Fixture, "named_table") CHECK_EQ("TheTable", toString(&table)); } -TEST_CASE_FIXTURE(Fixture, "exhaustive_toString_of_cyclic_table") +TEST_CASE_FIXTURE(BuiltinsFixture, "exhaustive_toString_of_cyclic_table") { CheckResult result = check(R"( --!strict @@ -338,7 +338,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringDetailed") REQUIRE_EQ("c", toString(params[2], opts)); } -TEST_CASE_FIXTURE(Fixture, "toStringDetailed2") +TEST_CASE_FIXTURE(BuiltinsFixture, "toStringDetailed2") { ScopedFastFlag sff{"LuauUnsealedTableLiteral", true}; diff --git a/tests/TypeInfer.aliases.test.cpp b/tests/TypeInfer.aliases.test.cpp index b0eb31ce..7562a4d7 100644 --- a/tests/TypeInfer.aliases.test.cpp +++ b/tests/TypeInfer.aliases.test.cpp @@ -279,7 +279,7 @@ TEST_CASE_FIXTURE(Fixture, "stringify_optional_parameterized_alias") CHECK_EQ("Node", toString(e->wantedType)); } -TEST_CASE_FIXTURE(Fixture, "general_require_multi_assign") +TEST_CASE_FIXTURE(BuiltinsFixture, "general_require_multi_assign") { fileResolver.source["workspace/A"] = R"( export type myvec2 = {x: number, y: number} @@ -317,7 +317,7 @@ TEST_CASE_FIXTURE(Fixture, "general_require_multi_assign") REQUIRE(bType->props.size() == 3); } -TEST_CASE_FIXTURE(Fixture, "type_alias_import_mutation") +TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_import_mutation") { CheckResult result = check("type t10 = typeof(table)"); LUAU_REQUIRE_NO_ERRORS(result); @@ -385,7 +385,7 @@ type Cool = typeof(c) CHECK_EQ(ttv->name, "Cool"); } -TEST_CASE_FIXTURE(Fixture, "type_alias_of_an_imported_recursive_type") +TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_of_an_imported_recursive_type") { fileResolver.source["game/A"] = R"( export type X = { a: number, b: X? } @@ -410,7 +410,7 @@ type X = Import.X CHECK_EQ(follow(*ty1), follow(*ty2)); } -TEST_CASE_FIXTURE(Fixture, "type_alias_of_an_imported_recursive_generic_type") +TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_of_an_imported_recursive_generic_type") { fileResolver.source["game/A"] = R"( export type X = { a: T, b: U, C: X? } @@ -564,7 +564,7 @@ TEST_CASE_FIXTURE(Fixture, "non_recursive_aliases_that_reuse_a_generic_name") * * We solved this by ascribing a unique subLevel to each prototyped alias. */ -TEST_CASE_FIXTURE(Fixture, "do_not_quantify_unresolved_aliases") +TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_quantify_unresolved_aliases") { CheckResult result = check(R"( --!strict diff --git a/tests/TypeInfer.annotations.test.cpp b/tests/TypeInfer.annotations.test.cpp index 7f1c757a..b9e1ae96 100644 --- a/tests/TypeInfer.annotations.test.cpp +++ b/tests/TypeInfer.annotations.test.cpp @@ -528,7 +528,7 @@ TEST_CASE_FIXTURE(Fixture, "cloned_interface_maintains_pointers_between_definiti CHECK_EQ(recordType, bType); } -TEST_CASE_FIXTURE(Fixture, "use_type_required_from_another_file") +TEST_CASE_FIXTURE(BuiltinsFixture, "use_type_required_from_another_file") { addGlobalBinding(frontend.typeChecker, "script", frontend.typeChecker.anyType, "@test"); @@ -554,7 +554,7 @@ TEST_CASE_FIXTURE(Fixture, "use_type_required_from_another_file") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "cannot_use_nonexported_type") +TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_use_nonexported_type") { addGlobalBinding(frontend.typeChecker, "script", frontend.typeChecker.anyType, "@test"); @@ -580,7 +580,7 @@ TEST_CASE_FIXTURE(Fixture, "cannot_use_nonexported_type") LUAU_REQUIRE_ERROR_COUNT(1, result); } -TEST_CASE_FIXTURE(Fixture, "builtin_types_are_not_exported") +TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_are_not_exported") { addGlobalBinding(frontend.typeChecker, "script", frontend.typeChecker.anyType, "@test"); @@ -676,7 +676,7 @@ TEST_CASE_FIXTURE(Fixture, "luau_ice_is_not_special_without_the_flag") )"); } -TEST_CASE_FIXTURE(Fixture, "luau_print_is_magic_if_the_flag_is_set") +TEST_CASE_FIXTURE(BuiltinsFixture, "luau_print_is_magic_if_the_flag_is_set") { // Luau::resetPrintLine(); ScopedFastFlag sffs{"DebugLuauMagicTypes", true}; diff --git a/tests/TypeInfer.anyerror.test.cpp b/tests/TypeInfer.anyerror.test.cpp index 5224b5d8..bc55940e 100644 --- a/tests/TypeInfer.anyerror.test.cpp +++ b/tests/TypeInfer.anyerror.test.cpp @@ -237,7 +237,7 @@ TEST_CASE_FIXTURE(Fixture, "chain_calling_error_type_yields_error") CHECK_EQ("*unknown*", toString(requireType("a"))); } -TEST_CASE_FIXTURE(Fixture, "replace_every_free_type_when_unifying_a_complex_function_with_any") +TEST_CASE_FIXTURE(BuiltinsFixture, "replace_every_free_type_when_unifying_a_complex_function_with_any") { CheckResult result = check(R"( local a: any @@ -285,7 +285,7 @@ end LUAU_REQUIRE_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "metatable_of_any_can_be_a_table") +TEST_CASE_FIXTURE(BuiltinsFixture, "metatable_of_any_can_be_a_table") { CheckResult result = check(R"( --!strict diff --git a/tests/TypeInfer.builtins.test.cpp b/tests/TypeInfer.builtins.test.cpp index 1ae65947..b710ea0d 100644 --- a/tests/TypeInfer.builtins.test.cpp +++ b/tests/TypeInfer.builtins.test.cpp @@ -12,7 +12,7 @@ LUAU_FASTFLAG(LuauLowerBoundsCalculation); TEST_SUITE_BEGIN("BuiltinTests"); -TEST_CASE_FIXTURE(Fixture, "math_things_are_defined") +TEST_CASE_FIXTURE(BuiltinsFixture, "math_things_are_defined") { CheckResult result = check(R"( local a00 = math.frexp @@ -50,7 +50,7 @@ TEST_CASE_FIXTURE(Fixture, "math_things_are_defined") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "next_iterator_should_infer_types_and_type_check") +TEST_CASE_FIXTURE(BuiltinsFixture, "next_iterator_should_infer_types_and_type_check") { CheckResult result = check(R"( local a: string, b: number = next({ 1 }) @@ -63,7 +63,7 @@ TEST_CASE_FIXTURE(Fixture, "next_iterator_should_infer_types_and_type_check") LUAU_REQUIRE_ERROR_COUNT(1, result); } -TEST_CASE_FIXTURE(Fixture, "pairs_iterator_should_infer_types_and_type_check") +TEST_CASE_FIXTURE(BuiltinsFixture, "pairs_iterator_should_infer_types_and_type_check") { CheckResult result = check(R"( type Map = { [K]: V } @@ -75,7 +75,7 @@ TEST_CASE_FIXTURE(Fixture, "pairs_iterator_should_infer_types_and_type_check") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "ipairs_iterator_should_infer_types_and_type_check") +TEST_CASE_FIXTURE(BuiltinsFixture, "ipairs_iterator_should_infer_types_and_type_check") { CheckResult result = check(R"( type Map = { [K]: V } @@ -87,7 +87,7 @@ TEST_CASE_FIXTURE(Fixture, "ipairs_iterator_should_infer_types_and_type_check") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "table_dot_remove_optionally_returns_generic") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_dot_remove_optionally_returns_generic") { CheckResult result = check(R"( local t = { 1 } @@ -98,7 +98,7 @@ TEST_CASE_FIXTURE(Fixture, "table_dot_remove_optionally_returns_generic") CHECK_EQ(toString(requireType("n")), "number?"); } -TEST_CASE_FIXTURE(Fixture, "table_concat_returns_string") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_concat_returns_string") { CheckResult result = check(R"( local r = table.concat({1,2,3,4}, ",", 2); @@ -108,7 +108,7 @@ TEST_CASE_FIXTURE(Fixture, "table_concat_returns_string") CHECK_EQ(*typeChecker.stringType, *requireType("r")); } -TEST_CASE_FIXTURE(Fixture, "sort") +TEST_CASE_FIXTURE(BuiltinsFixture, "sort") { CheckResult result = check(R"( local t = {1, 2, 3}; @@ -118,7 +118,7 @@ TEST_CASE_FIXTURE(Fixture, "sort") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "sort_with_predicate") +TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_predicate") { CheckResult result = check(R"( --!strict @@ -130,7 +130,7 @@ TEST_CASE_FIXTURE(Fixture, "sort_with_predicate") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "sort_with_bad_predicate") +TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_bad_predicate") { CheckResult result = check(R"( --!strict @@ -140,6 +140,12 @@ TEST_CASE_FIXTURE(Fixture, "sort_with_bad_predicate") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); + CHECK_EQ(R"(Type '(number, number) -> boolean' could not be converted into '((a, a) -> boolean)?' +caused by: + None of the union options are compatible. For example: Type '(number, number) -> boolean' could not be converted into '(a, a) -> boolean' +caused by: + Argument #1 type is not compatible. Type 'string' could not be converted into 'number')", + toString(result.errors[0])); } TEST_CASE_FIXTURE(Fixture, "strings_have_methods") @@ -152,7 +158,7 @@ TEST_CASE_FIXTURE(Fixture, "strings_have_methods") CHECK_EQ(*typeChecker.stringType, *requireType("s")); } -TEST_CASE_FIXTURE(Fixture, "math_max_variatic") +TEST_CASE_FIXTURE(BuiltinsFixture, "math_max_variatic") { CheckResult result = check(R"( local n = math.max(1,2,3,4,5,6,7,8,9,0) @@ -162,16 +168,17 @@ TEST_CASE_FIXTURE(Fixture, "math_max_variatic") CHECK_EQ(*typeChecker.numberType, *requireType("n")); } -TEST_CASE_FIXTURE(Fixture, "math_max_checks_for_numbers") +TEST_CASE_FIXTURE(BuiltinsFixture, "math_max_checks_for_numbers") { CheckResult result = check(R"( local n = math.max(1,2,"3") )"); CHECK(!result.errors.empty()); + CHECK_EQ("Type 'string' could not be converted into 'number'", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "builtin_tables_sealed") +TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_tables_sealed") { CheckResult result = check(R"LUA( local b = bit32 @@ -183,7 +190,7 @@ TEST_CASE_FIXTURE(Fixture, "builtin_tables_sealed") CHECK_EQ(bit32t->state, TableState::Sealed); } -TEST_CASE_FIXTURE(Fixture, "lua_51_exported_globals_all_exist") +TEST_CASE_FIXTURE(BuiltinsFixture, "lua_51_exported_globals_all_exist") { // Extracted from lua5.1 CheckResult result = check(R"( @@ -340,7 +347,7 @@ TEST_CASE_FIXTURE(Fixture, "lua_51_exported_globals_all_exist") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "setmetatable_unpacks_arg_types_correctly") +TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_unpacks_arg_types_correctly") { CheckResult result = check(R"( setmetatable({}, setmetatable({}, {})) @@ -348,7 +355,7 @@ TEST_CASE_FIXTURE(Fixture, "setmetatable_unpacks_arg_types_correctly") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "table_insert_correctly_infers_type_of_array_2_args_overload") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_correctly_infers_type_of_array_2_args_overload") { CheckResult result = check(R"( local t = {} @@ -360,7 +367,7 @@ TEST_CASE_FIXTURE(Fixture, "table_insert_correctly_infers_type_of_array_2_args_o CHECK_EQ(typeChecker.stringType, requireType("s")); } -TEST_CASE_FIXTURE(Fixture, "table_insert_correctly_infers_type_of_array_3_args_overload") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_correctly_infers_type_of_array_3_args_overload") { CheckResult result = check(R"( local t = {} @@ -372,7 +379,7 @@ TEST_CASE_FIXTURE(Fixture, "table_insert_correctly_infers_type_of_array_3_args_o CHECK_EQ("string", toString(requireType("s"))); } -TEST_CASE_FIXTURE(Fixture, "table_pack") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_pack") { CheckResult result = check(R"( local t = table.pack(1, "foo", true) @@ -382,7 +389,7 @@ TEST_CASE_FIXTURE(Fixture, "table_pack") CHECK_EQ("{| [number]: boolean | number | string, n: number |}", toString(requireType("t"))); } -TEST_CASE_FIXTURE(Fixture, "table_pack_variadic") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_pack_variadic") { CheckResult result = check(R"( --!strict @@ -397,7 +404,7 @@ local t = table.pack(f()) CHECK_EQ("{| [number]: number | string, n: number |}", toString(requireType("t"))); } -TEST_CASE_FIXTURE(Fixture, "table_pack_reduce") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_pack_reduce") { CheckResult result = check(R"( local t = table.pack(1, 2, true) @@ -414,7 +421,7 @@ TEST_CASE_FIXTURE(Fixture, "table_pack_reduce") CHECK_EQ("{| [number]: string, n: number |}", toString(requireType("t"))); } -TEST_CASE_FIXTURE(Fixture, "gcinfo") +TEST_CASE_FIXTURE(BuiltinsFixture, "gcinfo") { CheckResult result = check(R"( local n = gcinfo() @@ -424,12 +431,12 @@ TEST_CASE_FIXTURE(Fixture, "gcinfo") CHECK_EQ(*typeChecker.numberType, *requireType("n")); } -TEST_CASE_FIXTURE(Fixture, "getfenv") +TEST_CASE_FIXTURE(BuiltinsFixture, "getfenv") { LUAU_REQUIRE_NO_ERRORS(check("getfenv(1)")); } -TEST_CASE_FIXTURE(Fixture, "os_time_takes_optional_date_table") +TEST_CASE_FIXTURE(BuiltinsFixture, "os_time_takes_optional_date_table") { CheckResult result = check(R"( local n1 = os.time() @@ -443,7 +450,7 @@ TEST_CASE_FIXTURE(Fixture, "os_time_takes_optional_date_table") CHECK_EQ(*typeChecker.numberType, *requireType("n3")); } -TEST_CASE_FIXTURE(Fixture, "thread_is_a_type") +TEST_CASE_FIXTURE(BuiltinsFixture, "thread_is_a_type") { CheckResult result = check(R"( local co = coroutine.create(function() end) @@ -453,7 +460,7 @@ TEST_CASE_FIXTURE(Fixture, "thread_is_a_type") CHECK_EQ(*typeChecker.threadType, *requireType("co")); } -TEST_CASE_FIXTURE(Fixture, "coroutine_resume_anything_goes") +TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_resume_anything_goes") { CheckResult result = check(R"( local function nifty(x, y) @@ -471,7 +478,7 @@ TEST_CASE_FIXTURE(Fixture, "coroutine_resume_anything_goes") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "coroutine_wrap_anything_goes") +TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_wrap_anything_goes") { CheckResult result = check(R"( --!nonstrict @@ -490,7 +497,7 @@ TEST_CASE_FIXTURE(Fixture, "coroutine_wrap_anything_goes") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "setmetatable_should_not_mutate_persisted_types") +TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_should_not_mutate_persisted_types") { CheckResult result = check(R"( local string = string @@ -505,7 +512,7 @@ TEST_CASE_FIXTURE(Fixture, "setmetatable_should_not_mutate_persisted_types") REQUIRE(ttv); } -TEST_CASE_FIXTURE(Fixture, "string_format_arg_types_inference") +TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_arg_types_inference") { CheckResult result = check(R"( --!strict @@ -518,7 +525,7 @@ TEST_CASE_FIXTURE(Fixture, "string_format_arg_types_inference") CHECK_EQ("(number, number, string) -> string", toString(requireType("f"))); } -TEST_CASE_FIXTURE(Fixture, "string_format_arg_count_mismatch") +TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_arg_count_mismatch") { CheckResult result = check(R"( --!strict @@ -534,7 +541,7 @@ TEST_CASE_FIXTURE(Fixture, "string_format_arg_count_mismatch") CHECK_EQ(result.errors[2].location.begin.line, 4); } -TEST_CASE_FIXTURE(Fixture, "string_format_correctly_ordered_types") +TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_correctly_ordered_types") { CheckResult result = check(R"( --!strict @@ -548,7 +555,7 @@ TEST_CASE_FIXTURE(Fixture, "string_format_correctly_ordered_types") CHECK_EQ(tm->givenType, typeChecker.numberType); } -TEST_CASE_FIXTURE(Fixture, "xpcall") +TEST_CASE_FIXTURE(BuiltinsFixture, "xpcall") { CheckResult result = check(R"( --!strict @@ -564,7 +571,7 @@ TEST_CASE_FIXTURE(Fixture, "xpcall") CHECK_EQ("boolean", toString(requireType("c"))); } -TEST_CASE_FIXTURE(Fixture, "see_thru_select") +TEST_CASE_FIXTURE(BuiltinsFixture, "see_thru_select") { CheckResult result = check(R"( local a:number, b:boolean = select(2,"hi", 10, true) @@ -573,7 +580,7 @@ TEST_CASE_FIXTURE(Fixture, "see_thru_select") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "see_thru_select_count") +TEST_CASE_FIXTURE(BuiltinsFixture, "see_thru_select_count") { CheckResult result = check(R"( local a = select("#","hi", 10, true) @@ -583,7 +590,7 @@ TEST_CASE_FIXTURE(Fixture, "see_thru_select_count") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "select_with_decimal_argument_is_rounded_down") +TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_decimal_argument_is_rounded_down") { CheckResult result = check(R"( local a: number, b: boolean = select(2.9, "foo", 1, true) @@ -608,7 +615,7 @@ TEST_CASE_FIXTURE(Fixture, "bad_select_should_not_crash") CHECK_LE(0, result.errors.size()); } -TEST_CASE_FIXTURE(Fixture, "select_way_out_of_range") +TEST_CASE_FIXTURE(BuiltinsFixture, "select_way_out_of_range") { CheckResult result = check(R"( select(5432598430953240958) @@ -619,7 +626,7 @@ TEST_CASE_FIXTURE(Fixture, "select_way_out_of_range") CHECK_EQ("bad argument #1 to select (index out of range)", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "select_slightly_out_of_range") +TEST_CASE_FIXTURE(BuiltinsFixture, "select_slightly_out_of_range") { CheckResult result = check(R"( select(3, "a", 1) @@ -630,7 +637,7 @@ TEST_CASE_FIXTURE(Fixture, "select_slightly_out_of_range") CHECK_EQ("bad argument #1 to select (index out of range)", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "select_with_variadic_typepack_tail") +TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_variadic_typepack_tail") { CheckResult result = check(R"( --!nonstrict @@ -649,7 +656,7 @@ TEST_CASE_FIXTURE(Fixture, "select_with_variadic_typepack_tail") CHECK_EQ("any", toString(requireType("quux"))); } -TEST_CASE_FIXTURE(Fixture, "select_with_variadic_typepack_tail_and_string_head") +TEST_CASE_FIXTURE(BuiltinsFixture, "select_with_variadic_typepack_tail_and_string_head") { CheckResult result = check(R"( --!nonstrict @@ -703,7 +710,7 @@ TEST_CASE_FIXTURE(Fixture, "string_format_use_correct_argument2") CHECK_EQ("Type 'number' could not be converted into 'string'", toString(result.errors[1])); } -TEST_CASE_FIXTURE(Fixture, "debug_traceback_is_crazy") +TEST_CASE_FIXTURE(BuiltinsFixture, "debug_traceback_is_crazy") { CheckResult result = check(R"( local co: thread = ... @@ -720,7 +727,7 @@ debug.traceback(co, "msg", 1) LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "debug_info_is_crazy") +TEST_CASE_FIXTURE(BuiltinsFixture, "debug_info_is_crazy") { CheckResult result = check(R"( local co: thread, f: ()->() = ... @@ -734,7 +741,7 @@ debug.info(f, "n") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "aliased_string_format") +TEST_CASE_FIXTURE(BuiltinsFixture, "aliased_string_format") { CheckResult result = check(R"( local fmt = string.format @@ -745,7 +752,7 @@ TEST_CASE_FIXTURE(Fixture, "aliased_string_format") CHECK_EQ("Type 'string' could not be converted into 'number'", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "string_lib_self_noself") +TEST_CASE_FIXTURE(BuiltinsFixture, "string_lib_self_noself") { CheckResult result = check(R"( --!nonstrict @@ -764,7 +771,7 @@ TEST_CASE_FIXTURE(Fixture, "string_lib_self_noself") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "gmatch_definition") +TEST_CASE_FIXTURE(BuiltinsFixture, "gmatch_definition") { CheckResult result = check(R"_( local a, b, c = ("hey"):gmatch("(.)(.)(.)")() @@ -777,7 +784,7 @@ end LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "select_on_variadic") +TEST_CASE_FIXTURE(BuiltinsFixture, "select_on_variadic") { CheckResult result = check(R"( local function f(): (number, ...(boolean | number)) @@ -793,7 +800,7 @@ TEST_CASE_FIXTURE(Fixture, "select_on_variadic") CHECK_EQ("any", toString(requireType("c"))); } -TEST_CASE_FIXTURE(Fixture, "string_format_report_all_type_errors_at_correct_positions") +TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_report_all_type_errors_at_correct_positions") { CheckResult result = check(R"( ("%s%d%s"):format(1, "hello", true) @@ -825,7 +832,7 @@ TEST_CASE_FIXTURE(Fixture, "string_format_report_all_type_errors_at_correct_posi CHECK_EQ(TypeErrorData(TypeMismatch{stringType, booleanType}), result.errors[5].data); } -TEST_CASE_FIXTURE(Fixture, "tonumber_returns_optional_number_type") +TEST_CASE_FIXTURE(BuiltinsFixture, "tonumber_returns_optional_number_type") { CheckResult result = check(R"( --!strict @@ -836,7 +843,7 @@ TEST_CASE_FIXTURE(Fixture, "tonumber_returns_optional_number_type") CHECK_EQ("Type 'number?' could not be converted into 'number'", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "tonumber_returns_optional_number_type2") +TEST_CASE_FIXTURE(BuiltinsFixture, "tonumber_returns_optional_number_type2") { CheckResult result = check(R"( --!strict @@ -846,7 +853,7 @@ TEST_CASE_FIXTURE(Fixture, "tonumber_returns_optional_number_type2") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "dont_add_definitions_to_persistent_types") +TEST_CASE_FIXTURE(BuiltinsFixture, "dont_add_definitions_to_persistent_types") { CheckResult result = check(R"( local f = math.sin @@ -868,7 +875,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_add_definitions_to_persistent_types") REQUIRE(gtv->definition); } -TEST_CASE_FIXTURE(Fixture, "assert_removes_falsy_types") +TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types") { ScopedFastFlag sff[]{ {"LuauAssertStripsFalsyTypes", true}, @@ -889,7 +896,7 @@ TEST_CASE_FIXTURE(Fixture, "assert_removes_falsy_types") CHECK_EQ("((boolean | number)?) -> boolean | number", toString(requireType("f"))); } -TEST_CASE_FIXTURE(Fixture, "assert_removes_falsy_types2") +TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types2") { ScopedFastFlag sff[]{ {"LuauAssertStripsFalsyTypes", true}, @@ -907,7 +914,7 @@ TEST_CASE_FIXTURE(Fixture, "assert_removes_falsy_types2") CHECK_EQ("((boolean | number)?) -> number | true", toString(requireType("f"))); } -TEST_CASE_FIXTURE(Fixture, "assert_removes_falsy_types_even_from_type_pack_tail_but_only_for_the_first_type") +TEST_CASE_FIXTURE(BuiltinsFixture, "assert_removes_falsy_types_even_from_type_pack_tail_but_only_for_the_first_type") { ScopedFastFlag sff[]{ {"LuauAssertStripsFalsyTypes", true}, @@ -924,7 +931,7 @@ TEST_CASE_FIXTURE(Fixture, "assert_removes_falsy_types_even_from_type_pack_tail_ CHECK_EQ("(...number?) -> (number, ...number?)", toString(requireType("f"))); } -TEST_CASE_FIXTURE(Fixture, "assert_returns_false_and_string_iff_it_knows_the_first_argument_cannot_be_truthy") +TEST_CASE_FIXTURE(BuiltinsFixture, "assert_returns_false_and_string_iff_it_knows_the_first_argument_cannot_be_truthy") { ScopedFastFlag sff[]{ {"LuauAssertStripsFalsyTypes", true}, @@ -941,7 +948,7 @@ TEST_CASE_FIXTURE(Fixture, "assert_returns_false_and_string_iff_it_knows_the_fir CHECK_EQ("(nil) -> nil", toString(requireType("f"))); } -TEST_CASE_FIXTURE(Fixture, "table_freeze_is_generic") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic") { CheckResult result = check(R"( local t1: {a: number} = {a = 42} @@ -968,7 +975,7 @@ TEST_CASE_FIXTURE(Fixture, "table_freeze_is_generic") CHECK_EQ("*unknown*", toString(requireType("d"))); } -TEST_CASE_FIXTURE(Fixture, "set_metatable_needs_arguments") +TEST_CASE_FIXTURE(BuiltinsFixture, "set_metatable_needs_arguments") { ScopedFastFlag sff{"LuauSetMetaTableArgsCheck", true}; CheckResult result = check(R"( @@ -991,7 +998,7 @@ local function f(a: typeof(f)) end CHECK_EQ("Unknown global 'f'", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "no_persistent_typelevel_change") +TEST_CASE_FIXTURE(BuiltinsFixture, "no_persistent_typelevel_change") { TypeId mathTy = requireType(typeChecker.globalScope, "math"); REQUIRE(mathTy); @@ -1008,7 +1015,7 @@ TEST_CASE_FIXTURE(Fixture, "no_persistent_typelevel_change") CHECK(ftv->level.subLevel == original.subLevel); } -TEST_CASE_FIXTURE(Fixture, "global_singleton_types_are_sealed") +TEST_CASE_FIXTURE(BuiltinsFixture, "global_singleton_types_are_sealed") { CheckResult result = check(R"( local function f(x: string) diff --git a/tests/TypeInfer.classes.test.cpp b/tests/TypeInfer.classes.test.cpp index 5a6e4032..d90129d7 100644 --- a/tests/TypeInfer.classes.test.cpp +++ b/tests/TypeInfer.classes.test.cpp @@ -10,7 +10,7 @@ using namespace Luau; using std::nullopt; -struct ClassFixture : Fixture +struct ClassFixture : BuiltinsFixture { ClassFixture() { diff --git a/tests/TypeInfer.functions.test.cpp b/tests/TypeInfer.functions.test.cpp index 0e071217..14f1f703 100644 --- a/tests/TypeInfer.functions.test.cpp +++ b/tests/TypeInfer.functions.test.cpp @@ -85,7 +85,7 @@ TEST_CASE_FIXTURE(Fixture, "vararg_functions_should_allow_calls_of_any_types_and LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "vararg_function_is_quantified") +TEST_CASE_FIXTURE(BuiltinsFixture, "vararg_function_is_quantified") { CheckResult result = check(R"( local T = {} @@ -555,7 +555,7 @@ TEST_CASE_FIXTURE(Fixture, "higher_order_function_3") CHECK(bool(argType->indexer)); } -TEST_CASE_FIXTURE(Fixture, "higher_order_function_4") +TEST_CASE_FIXTURE(BuiltinsFixture, "higher_order_function_4") { CheckResult result = check(R"( function bottomupmerge(comp, a, b, left, mid, right) @@ -620,7 +620,7 @@ TEST_CASE_FIXTURE(Fixture, "higher_order_function_4") CHECK_EQ(*arg0->indexer->indexResultType, *arg1Args[1]); } -TEST_CASE_FIXTURE(Fixture, "mutual_recursion") +TEST_CASE_FIXTURE(BuiltinsFixture, "mutual_recursion") { CheckResult result = check(R"( --!strict @@ -639,7 +639,7 @@ TEST_CASE_FIXTURE(Fixture, "mutual_recursion") dumpErrors(result); } -TEST_CASE_FIXTURE(Fixture, "toposort_doesnt_break_mutual_recursion") +TEST_CASE_FIXTURE(BuiltinsFixture, "toposort_doesnt_break_mutual_recursion") { CheckResult result = check(R"( --!strict @@ -676,7 +676,7 @@ TEST_CASE_FIXTURE(Fixture, "check_function_before_lambda_that_uses_it") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "it_is_ok_to_oversaturate_a_higher_order_function_argument") +TEST_CASE_FIXTURE(BuiltinsFixture, "it_is_ok_to_oversaturate_a_higher_order_function_argument") { CheckResult result = check(R"( function onerror() end @@ -794,7 +794,7 @@ TEST_CASE_FIXTURE(Fixture, "calling_function_with_incorrect_argument_type_yields }})); } -TEST_CASE_FIXTURE(Fixture, "calling_function_with_anytypepack_doesnt_leak_free_types") +TEST_CASE_FIXTURE(BuiltinsFixture, "calling_function_with_anytypepack_doesnt_leak_free_types") { ScopedFastFlag sff[]{ {"LuauReturnTypeInferenceInNonstrict", true}, @@ -966,7 +966,7 @@ TEST_CASE_FIXTURE(Fixture, "return_type_by_overload") CHECK_EQ("string", toString(requireType("z"))); } -TEST_CASE_FIXTURE(Fixture, "infer_anonymous_function_arguments") +TEST_CASE_FIXTURE(BuiltinsFixture, "infer_anonymous_function_arguments") { // Simple direct arg to arg propagation CheckResult result = check(R"( @@ -1068,7 +1068,7 @@ f(function(x) return x * 2 end) } } -TEST_CASE_FIXTURE(Fixture, "infer_anonymous_function_arguments") +TEST_CASE_FIXTURE(BuiltinsFixture, "infer_anonymous_function_arguments") { // Simple direct arg to arg propagation CheckResult result = check(R"( @@ -1287,10 +1287,8 @@ caused by: Return #2 type is not compatible. Type 'string' could not be converted into 'boolean')"); } -TEST_CASE_FIXTURE(Fixture, "function_decl_quantify_right_type") +TEST_CASE_FIXTURE(BuiltinsFixture, "function_decl_quantify_right_type") { - ScopedFastFlag statFunctionSimplify{"LuauStatFunctionSimplify4", true}; - fileResolver.source["game/isAMagicMock"] = R"( --!nonstrict return function(value) @@ -1311,10 +1309,8 @@ end LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "function_decl_non_self_sealed_overwrite") +TEST_CASE_FIXTURE(BuiltinsFixture, "function_decl_non_self_sealed_overwrite") { - ScopedFastFlag statFunctionSimplify{"LuauStatFunctionSimplify4", true}; - CheckResult result = check(R"( function string.len(): number return 1 @@ -1333,11 +1329,8 @@ print(string.len('hello')) LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "function_decl_non_self_sealed_overwrite_2") +TEST_CASE_FIXTURE(BuiltinsFixture, "function_decl_non_self_sealed_overwrite_2") { - ScopedFastFlag statFunctionSimplify{"LuauStatFunctionSimplify4", true}; - ScopedFastFlag inferStatFunction{"LuauInferStatFunction", true}; - CheckResult result = check(R"( local t: { f: ((x: number) -> number)? } = {} @@ -1477,11 +1470,8 @@ TEST_CASE_FIXTURE(Fixture, "inferred_higher_order_functions_are_quantified_at_th LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "function_decl_non_self_unsealed_overwrite") +TEST_CASE_FIXTURE(BuiltinsFixture, "function_decl_non_self_unsealed_overwrite") { - ScopedFastFlag statFunctionSimplify{"LuauStatFunctionSimplify4", true}; - ScopedFastFlag inferStatFunction{"LuauInferStatFunction", true}; - CheckResult result = check(R"( local t = { f = nil :: ((x: number) -> number)? } @@ -1518,8 +1508,6 @@ TEST_CASE_FIXTURE(Fixture, "strict_mode_ok_with_missing_arguments") TEST_CASE_FIXTURE(Fixture, "function_statement_sealed_table_assignment_through_indexer") { - ScopedFastFlag statFunctionSimplify{"LuauStatFunctionSimplify4", true}; - CheckResult result = check(R"( local t: {[string]: () -> number} = {} @@ -1580,7 +1568,7 @@ wrapper(test) CHECK(acm->isVariadic); } -TEST_CASE_FIXTURE(Fixture, "too_few_arguments_variadic_generic2") +TEST_CASE_FIXTURE(BuiltinsFixture, "too_few_arguments_variadic_generic2") { CheckResult result = check(R"( function test(a: number, b: string, ...) diff --git a/tests/TypeInfer.generics.test.cpp b/tests/TypeInfer.generics.test.cpp index 91be2c1c..de0c9391 100644 --- a/tests/TypeInfer.generics.test.cpp +++ b/tests/TypeInfer.generics.test.cpp @@ -67,7 +67,7 @@ TEST_CASE_FIXTURE(Fixture, "local_vars_can_be_polytypes") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "inferred_local_vars_can_be_polytypes") +TEST_CASE_FIXTURE(BuiltinsFixture, "inferred_local_vars_can_be_polytypes") { CheckResult result = check(R"( local function id(x) return x end @@ -79,7 +79,7 @@ TEST_CASE_FIXTURE(Fixture, "inferred_local_vars_can_be_polytypes") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "local_vars_can_be_instantiated_polytypes") +TEST_CASE_FIXTURE(BuiltinsFixture, "local_vars_can_be_instantiated_polytypes") { CheckResult result = check(R"( local function id(x) return x end @@ -609,7 +609,7 @@ TEST_CASE_FIXTURE(Fixture, "typefuns_sharing_types") CHECK(requireType("y1") == requireType("y2")); } -TEST_CASE_FIXTURE(Fixture, "bound_tables_do_not_clone_original_fields") +TEST_CASE_FIXTURE(BuiltinsFixture, "bound_tables_do_not_clone_original_fields") { CheckResult result = check(R"( local exports = {} @@ -675,7 +675,7 @@ local d: D = c R"(Type '() -> ()' could not be converted into '() -> ()'; different number of generic type pack parameters)"); } -TEST_CASE_FIXTURE(Fixture, "generic_functions_dont_cache_type_parameters") +TEST_CASE_FIXTURE(BuiltinsFixture, "generic_functions_dont_cache_type_parameters") { CheckResult result = check(R"( -- See https://github.com/Roblox/luau/issues/332 @@ -1013,7 +1013,7 @@ TEST_CASE_FIXTURE(Fixture, "no_stack_overflow_from_quantifying") CHECK(it != result.errors.end()); } -TEST_CASE_FIXTURE(Fixture, "infer_generic_function_function_argument") +TEST_CASE_FIXTURE(BuiltinsFixture, "infer_generic_function_function_argument") { ScopedFastFlag sff{"LuauUnsealedTableLiteral", true}; @@ -1078,7 +1078,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_function_function_argument_overloaded" LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "infer_generic_lib_function_function_argument") +TEST_CASE_FIXTURE(BuiltinsFixture, "infer_generic_lib_function_function_argument") { CheckResult result = check(R"( local a = {{x=4}, {x=7}, {x=1}} diff --git a/tests/TypeInfer.intersectionTypes.test.cpp b/tests/TypeInfer.intersectionTypes.test.cpp index 3675919f..41bc0c21 100644 --- a/tests/TypeInfer.intersectionTypes.test.cpp +++ b/tests/TypeInfer.intersectionTypes.test.cpp @@ -316,8 +316,6 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed") TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed_indirect") { - ScopedFastFlag statFunctionSimplify{"LuauStatFunctionSimplify4", true}; - CheckResult result = check(R"( type X = { x: (number) -> number } type Y = { y: (string) -> string } @@ -351,8 +349,6 @@ caused by: TEST_CASE_FIXTURE(Fixture, "table_write_sealed_indirect") { - ScopedFastFlag statFunctionSimplify{"LuauStatFunctionSimplify4", true}; - // After normalization, previous 'table_intersection_write_sealed_indirect' is identical to this one CheckResult result = check(R"( type XY = { x: (number) -> number, y: (string) -> string } @@ -375,7 +371,7 @@ caused by: CHECK_EQ(toString(result.errors[3]), "Cannot add property 'w' to table 'XY'"); } -TEST_CASE_FIXTURE(Fixture, "table_intersection_setmetatable") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_intersection_setmetatable") { CheckResult result = check(R"( local t: {} & {} diff --git a/tests/TypeInfer.loops.test.cpp b/tests/TypeInfer.loops.test.cpp index f9b510c1..765419c6 100644 --- a/tests/TypeInfer.loops.test.cpp +++ b/tests/TypeInfer.loops.test.cpp @@ -29,7 +29,7 @@ TEST_CASE_FIXTURE(Fixture, "for_loop") CHECK_EQ(*typeChecker.numberType, *requireType("q")); } -TEST_CASE_FIXTURE(Fixture, "for_in_loop") +TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop") { CheckResult result = check(R"( local n @@ -46,7 +46,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop") CHECK_EQ(*typeChecker.stringType, *requireType("s")); } -TEST_CASE_FIXTURE(Fixture, "for_in_loop_with_next") +TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_next") { CheckResult result = check(R"( local n @@ -90,7 +90,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_should_fail_with_non_function_iterator") CHECK_EQ("Cannot call non-function string", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "for_in_with_just_one_iterator_is_ok") +TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_with_just_one_iterator_is_ok") { CheckResult result = check(R"( local function keys(dictionary) @@ -109,7 +109,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_with_just_one_iterator_is_ok") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "for_in_with_a_custom_iterator_should_type_check") +TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_with_a_custom_iterator_should_type_check") { CheckResult result = check(R"( local function range(l, h): () -> number @@ -161,7 +161,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_non_function") REQUIRE(get(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "for_in_loop_error_on_factory_not_returning_the_right_amount_of_values") +TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_factory_not_returning_the_right_amount_of_values") { CheckResult result = check(R"( local function hasDivisors(value: number, table) @@ -210,7 +210,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_error_on_factory_not_returning_the_right CHECK_EQ(typeChecker.stringType, tm->givenType); } -TEST_CASE_FIXTURE(Fixture, "for_in_loop_error_on_iterator_requiring_args_but_none_given") +TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_iterator_requiring_args_but_none_given") { CheckResult result = check(R"( function prime_iter(state, index) @@ -288,7 +288,7 @@ TEST_CASE_FIXTURE(Fixture, "repeat_loop_condition_binds_to_its_block") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "symbols_in_repeat_block_should_not_be_visible_beyond_until_condition") +TEST_CASE_FIXTURE(BuiltinsFixture, "symbols_in_repeat_block_should_not_be_visible_beyond_until_condition") { CheckResult result = check(R"( repeat @@ -301,7 +301,7 @@ TEST_CASE_FIXTURE(Fixture, "symbols_in_repeat_block_should_not_be_visible_beyond LUAU_REQUIRE_ERROR_COUNT(1, result); } -TEST_CASE_FIXTURE(Fixture, "varlist_declared_by_for_in_loop_should_be_free") +TEST_CASE_FIXTURE(BuiltinsFixture, "varlist_declared_by_for_in_loop_should_be_free") { CheckResult result = check(R"( local T = {} @@ -316,7 +316,7 @@ TEST_CASE_FIXTURE(Fixture, "varlist_declared_by_for_in_loop_should_be_free") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "properly_infer_iteratee_is_a_free_table") +TEST_CASE_FIXTURE(BuiltinsFixture, "properly_infer_iteratee_is_a_free_table") { // In this case, we cannot know the element type of the table {}. It could be anything. // We therefore must initially ascribe a free typevar to iter. @@ -329,7 +329,7 @@ TEST_CASE_FIXTURE(Fixture, "properly_infer_iteratee_is_a_free_table") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "correctly_scope_locals_while") +TEST_CASE_FIXTURE(BuiltinsFixture, "correctly_scope_locals_while") { CheckResult result = check(R"( while true do @@ -346,7 +346,7 @@ TEST_CASE_FIXTURE(Fixture, "correctly_scope_locals_while") CHECK_EQ(us->name, "a"); } -TEST_CASE_FIXTURE(Fixture, "ipairs_produces_integral_indices") +TEST_CASE_FIXTURE(BuiltinsFixture, "ipairs_produces_integral_indices") { CheckResult result = check(R"( local key @@ -378,7 +378,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_where_iteratee_is_free") )"); } -TEST_CASE_FIXTURE(Fixture, "unreachable_code_after_infinite_loop") +TEST_CASE_FIXTURE(BuiltinsFixture, "unreachable_code_after_infinite_loop") { { CheckResult result = check(R"( @@ -460,7 +460,7 @@ TEST_CASE_FIXTURE(Fixture, "unreachable_code_after_infinite_loop") } } -TEST_CASE_FIXTURE(Fixture, "loop_typecheck_crash_on_empty_optional") +TEST_CASE_FIXTURE(BuiltinsFixture, "loop_typecheck_crash_on_empty_optional") { CheckResult result = check(R"( local t = {} @@ -541,7 +541,7 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_no_indexer") CHECK_EQ("Cannot iterate over a table without indexer", ge->message); } -TEST_CASE_FIXTURE(Fixture, "loop_iter_iter_metamethod") +TEST_CASE_FIXTURE(BuiltinsFixture, "loop_iter_iter_metamethod") { ScopedFastFlag sff{"LuauTypecheckIter", true}; diff --git a/tests/TypeInfer.modules.test.cpp b/tests/TypeInfer.modules.test.cpp index b6f49f9f..efa2a98d 100644 --- a/tests/TypeInfer.modules.test.cpp +++ b/tests/TypeInfer.modules.test.cpp @@ -16,7 +16,7 @@ LUAU_FASTFLAG(LuauTableSubtypingVariance2) TEST_SUITE_BEGIN("TypeInferModules"); -TEST_CASE_FIXTURE(Fixture, "require") +TEST_CASE_FIXTURE(BuiltinsFixture, "require") { fileResolver.source["game/A"] = R"( local function hooty(x: number): string @@ -54,7 +54,7 @@ TEST_CASE_FIXTURE(Fixture, "require") REQUIRE_EQ("number", toString(*hType)); } -TEST_CASE_FIXTURE(Fixture, "require_types") +TEST_CASE_FIXTURE(BuiltinsFixture, "require_types") { fileResolver.source["workspace/A"] = R"( export type Point = {x: number, y: number} @@ -69,7 +69,7 @@ TEST_CASE_FIXTURE(Fixture, "require_types") )"; CheckResult bResult = frontend.check("workspace/B"); - dumpErrors(bResult); + LUAU_REQUIRE_NO_ERRORS(bResult); ModulePtr b = frontend.moduleResolver.modules["workspace/B"]; REQUIRE(b != nullptr); @@ -78,7 +78,7 @@ TEST_CASE_FIXTURE(Fixture, "require_types") REQUIRE_MESSAGE(bool(get(hType)), "Expected table but got " << toString(hType)); } -TEST_CASE_FIXTURE(Fixture, "require_a_variadic_function") +TEST_CASE_FIXTURE(BuiltinsFixture, "require_a_variadic_function") { fileResolver.source["game/A"] = R"( local T = {} @@ -121,7 +121,7 @@ TEST_CASE_FIXTURE(Fixture, "type_error_of_unknown_qualified_type") REQUIRE_EQ(result.errors[0], (TypeError{Location{{1, 17}, {1, 40}}, UnknownSymbol{"SomeModule.DoesNotExist"}})); } -TEST_CASE_FIXTURE(Fixture, "require_module_that_does_not_export") +TEST_CASE_FIXTURE(BuiltinsFixture, "require_module_that_does_not_export") { const std::string sourceA = R"( )"; @@ -148,7 +148,7 @@ TEST_CASE_FIXTURE(Fixture, "require_module_that_does_not_export") CHECK_EQ("*unknown*", toString(hootyType)); } -TEST_CASE_FIXTURE(Fixture, "warn_if_you_try_to_require_a_non_modulescript") +TEST_CASE_FIXTURE(BuiltinsFixture, "warn_if_you_try_to_require_a_non_modulescript") { fileResolver.source["Modules/A"] = ""; fileResolver.sourceTypes["Modules/A"] = SourceCode::Local; @@ -164,7 +164,7 @@ TEST_CASE_FIXTURE(Fixture, "warn_if_you_try_to_require_a_non_modulescript") CHECK(get(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "general_require_call_expression") +TEST_CASE_FIXTURE(BuiltinsFixture, "general_require_call_expression") { fileResolver.source["game/A"] = R"( --!strict @@ -183,7 +183,7 @@ a = tbl.abc.def CHECK_EQ("Type 'number' could not be converted into 'string'", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "general_require_type_mismatch") +TEST_CASE_FIXTURE(BuiltinsFixture, "general_require_type_mismatch") { fileResolver.source["game/A"] = R"( return { def = 4 } @@ -219,7 +219,7 @@ return m LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "custom_require_global") +TEST_CASE_FIXTURE(BuiltinsFixture, "custom_require_global") { CheckResult result = check(R"( --!nonstrict @@ -231,7 +231,7 @@ local crash = require(game.A) LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "require_failed_module") +TEST_CASE_FIXTURE(BuiltinsFixture, "require_failed_module") { fileResolver.source["game/A"] = R"( return unfortunately() @@ -267,7 +267,7 @@ function x:Destroy(): () end LUAU_REQUIRE_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "do_not_modify_imported_types_2") +TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types_2") { fileResolver.source["game/A"] = R"( export type Type = { x: { a: number } } @@ -285,7 +285,7 @@ type Rename = typeof(x.x) LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "do_not_modify_imported_types_3") +TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_modify_imported_types_3") { fileResolver.source["game/A"] = R"( local y = setmetatable({}, {}) @@ -304,7 +304,7 @@ type Rename = typeof(x.x) LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "module_type_conflict") +TEST_CASE_FIXTURE(BuiltinsFixture, "module_type_conflict") { fileResolver.source["game/A"] = R"( export type T = { x: number } @@ -338,7 +338,7 @@ caused by: } } -TEST_CASE_FIXTURE(Fixture, "module_type_conflict_instantiated") +TEST_CASE_FIXTURE(BuiltinsFixture, "module_type_conflict_instantiated") { fileResolver.source["game/A"] = R"( export type Wrap = { x: T } diff --git a/tests/TypeInfer.oop.test.cpp b/tests/TypeInfer.oop.test.cpp index 5cd3f3ba..41690704 100644 --- a/tests/TypeInfer.oop.test.cpp +++ b/tests/TypeInfer.oop.test.cpp @@ -142,7 +142,7 @@ TEST_CASE_FIXTURE(Fixture, "inferring_hundreds_of_self_calls_should_not_suffocat CHECK_GE(50, module->internalTypes.typeVars.size()); } -TEST_CASE_FIXTURE(Fixture, "object_constructor_can_refer_to_method_of_self") +TEST_CASE_FIXTURE(BuiltinsFixture, "object_constructor_can_refer_to_method_of_self") { // CLI-30902 CheckResult result = check(R"( @@ -243,7 +243,7 @@ TEST_CASE_FIXTURE(Fixture, "inferred_methods_of_free_tables_have_the_same_level_ )"); } -TEST_CASE_FIXTURE(Fixture, "table_oop") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_oop") { CheckResult result = check(R"( --!strict diff --git a/tests/TypeInfer.operators.test.cpp b/tests/TypeInfer.operators.test.cpp index a2787cad..51f6fdfb 100644 --- a/tests/TypeInfer.operators.test.cpp +++ b/tests/TypeInfer.operators.test.cpp @@ -77,7 +77,7 @@ TEST_CASE_FIXTURE(Fixture, "and_or_ternary") CHECK_EQ(toString(*requireType("s")), "number | string"); } -TEST_CASE_FIXTURE(Fixture, "primitive_arith_no_metatable") +TEST_CASE_FIXTURE(BuiltinsFixture, "primitive_arith_no_metatable") { CheckResult result = check(R"( function add(a: number, b: string) @@ -140,7 +140,7 @@ TEST_CASE_FIXTURE(Fixture, "some_primitive_binary_ops") CHECK_EQ("number", toString(requireType("c"))); } -TEST_CASE_FIXTURE(Fixture, "typecheck_overloaded_multiply_that_is_an_intersection") +TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_overloaded_multiply_that_is_an_intersection") { CheckResult result = check(R"( --!strict @@ -174,7 +174,7 @@ TEST_CASE_FIXTURE(Fixture, "typecheck_overloaded_multiply_that_is_an_intersectio CHECK_EQ("Vec3", toString(requireType("e"))); } -TEST_CASE_FIXTURE(Fixture, "typecheck_overloaded_multiply_that_is_an_intersection_on_rhs") +TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_overloaded_multiply_that_is_an_intersection_on_rhs") { CheckResult result = check(R"( --!strict @@ -245,7 +245,7 @@ TEST_CASE_FIXTURE(Fixture, "cannot_indirectly_compare_types_that_do_not_have_a_m REQUIRE_EQ(gen->message, "Type a cannot be compared with < because it has no metatable"); } -TEST_CASE_FIXTURE(Fixture, "cannot_indirectly_compare_types_that_do_not_offer_overloaded_ordering_operators") +TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_indirectly_compare_types_that_do_not_offer_overloaded_ordering_operators") { CheckResult result = check(R"( local M = {} @@ -266,7 +266,7 @@ TEST_CASE_FIXTURE(Fixture, "cannot_indirectly_compare_types_that_do_not_offer_ov REQUIRE_EQ(gen->message, "Table M does not offer metamethod __lt"); } -TEST_CASE_FIXTURE(Fixture, "cannot_compare_tables_that_do_not_have_the_same_metatable") +TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_compare_tables_that_do_not_have_the_same_metatable") { CheckResult result = check(R"( --!strict @@ -289,7 +289,7 @@ TEST_CASE_FIXTURE(Fixture, "cannot_compare_tables_that_do_not_have_the_same_meta REQUIRE_EQ((Location{{11, 18}, {11, 23}}), result.errors[1].location); } -TEST_CASE_FIXTURE(Fixture, "produce_the_correct_error_message_when_comparing_a_table_with_a_metatable_with_one_that_does_not") +TEST_CASE_FIXTURE(BuiltinsFixture, "produce_the_correct_error_message_when_comparing_a_table_with_a_metatable_with_one_that_does_not") { CheckResult result = check(R"( --!strict @@ -361,7 +361,7 @@ TEST_CASE_FIXTURE(Fixture, "compound_assign_mismatch_result") CHECK_EQ(result.errors[1], (TypeError{Location{{2, 8}, {2, 15}}, TypeMismatch{typeChecker.stringType, typeChecker.numberType}})); } -TEST_CASE_FIXTURE(Fixture, "compound_assign_metatable") +TEST_CASE_FIXTURE(BuiltinsFixture, "compound_assign_metatable") { CheckResult result = check(R"( --!strict @@ -381,7 +381,7 @@ TEST_CASE_FIXTURE(Fixture, "compound_assign_metatable") CHECK_EQ(0, result.errors.size()); } -TEST_CASE_FIXTURE(Fixture, "compound_assign_mismatch_metatable") +TEST_CASE_FIXTURE(BuiltinsFixture, "compound_assign_mismatch_metatable") { CheckResult result = check(R"( --!strict @@ -428,7 +428,7 @@ local x = false LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "typecheck_unary_minus") +TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus") { CheckResult result = check(R"( --!strict @@ -461,7 +461,7 @@ TEST_CASE_FIXTURE(Fixture, "typecheck_unary_minus") REQUIRE_EQ(gen->message, "Unary operator '-' not supported by type 'bar'"); } -TEST_CASE_FIXTURE(Fixture, "unary_not_is_boolean") +TEST_CASE_FIXTURE(BuiltinsFixture, "unary_not_is_boolean") { CheckResult result = check(R"( local b = not "string" @@ -473,7 +473,7 @@ TEST_CASE_FIXTURE(Fixture, "unary_not_is_boolean") REQUIRE_EQ("boolean", toString(requireType("c"))); } -TEST_CASE_FIXTURE(Fixture, "disallow_string_and_types_without_metatables_from_arithmetic_binary_ops") +TEST_CASE_FIXTURE(BuiltinsFixture, "disallow_string_and_types_without_metatables_from_arithmetic_binary_ops") { CheckResult result = check(R"( --!strict @@ -573,7 +573,7 @@ TEST_CASE_FIXTURE(Fixture, "strict_binary_op_where_lhs_unknown") CHECK_EQ("Unknown type used in + operation; consider adding a type annotation to 'a'", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "and_binexps_dont_unify") +TEST_CASE_FIXTURE(BuiltinsFixture, "and_binexps_dont_unify") { CheckResult result = check(R"( --!strict @@ -628,7 +628,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_38355_recursive_union") CHECK_EQ("Type contains a self-recursive construct that cannot be resolved", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "UnknownGlobalCompoundAssign") +TEST_CASE_FIXTURE(BuiltinsFixture, "UnknownGlobalCompoundAssign") { // In non-strict mode, global definition is still allowed { @@ -755,8 +755,6 @@ TEST_CASE_FIXTURE(Fixture, "refine_and_or") TEST_CASE_FIXTURE(Fixture, "infer_any_in_all_modes_when_lhs_is_unknown") { - ScopedFastFlag sff{"LuauDecoupleOperatorInferenceFromUnifiedTypeInference", true}; - CheckResult result = check(Mode::Strict, R"( local function f(x, y) return x + y @@ -779,4 +777,47 @@ TEST_CASE_FIXTURE(Fixture, "infer_any_in_all_modes_when_lhs_is_unknown") // the case right now, though. } +TEST_CASE_FIXTURE(BuiltinsFixture, "equality_operations_succeed_if_any_union_branch_succeeds") +{ + ScopedFastFlag sff("LuauSuccessTypingForEqualityOperations", true); + + CheckResult result = check(R"( + local mm = {} + type Foo = typeof(setmetatable({}, mm)) + local x: Foo + local y: Foo? + + local v1 = x == y + local v2 = y == x + local v3 = x ~= y + local v4 = y ~= x + )"); + + LUAU_REQUIRE_NO_ERRORS(result); + + CheckResult result2 = check(R"( + local mm1 = { + x = "foo", + } + + local mm2 = { + y = "bar", + } + + type Foo = typeof(setmetatable({}, mm1)) + type Bar = typeof(setmetatable({}, mm2)) + + local x1: Foo + local x2: Foo? + local y1: Bar + local y2: Bar? + + local v1 = x1 == y1 + local v2 = x2 == y2 + )"); + + LUAU_REQUIRE_ERROR_COUNT(1, result2); + CHECK(toString(result2.errors[0]) == "Types Foo and Bar cannot be compared with == because they do not have the same metatable"); +} + TEST_SUITE_END(); diff --git a/tests/TypeInfer.provisional.test.cpp b/tests/TypeInfer.provisional.test.cpp index 2ef77419..ee3ae972 100644 --- a/tests/TypeInfer.provisional.test.cpp +++ b/tests/TypeInfer.provisional.test.cpp @@ -53,7 +53,7 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_inference_incomplete") CHECK_EQ(expected, decorateWithTypes(code)); } -TEST_CASE_FIXTURE(Fixture, "xpcall_returns_what_f_returns") +TEST_CASE_FIXTURE(BuiltinsFixture, "xpcall_returns_what_f_returns") { const std::string code = R"( local a, b, c = xpcall(function() return 1, "foo" end, function() return "foo", 1 end) @@ -105,7 +105,7 @@ TEST_CASE_FIXTURE(Fixture, "it_should_be_agnostic_of_actual_size") // Ideally setmetatable's second argument would be an optional free table. // For now, infer it as just a free table. -TEST_CASE_FIXTURE(Fixture, "setmetatable_constrains_free_type_into_free_table") +TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_constrains_free_type_into_free_table") { CheckResult result = check(R"( local a = {} @@ -146,7 +146,7 @@ TEST_CASE_FIXTURE(Fixture, "while_body_are_also_refined") // Originally from TypeInfer.test.cpp. // I dont think type checking the metamethod at every site of == is the correct thing to do. // We should be type checking the metamethod at the call site of setmetatable. -TEST_CASE_FIXTURE(Fixture, "error_on_eq_metamethod_returning_a_type_other_than_boolean") +TEST_CASE_FIXTURE(BuiltinsFixture, "error_on_eq_metamethod_returning_a_type_other_than_boolean") { CheckResult result = check(R"( local tab = {a = 1} @@ -428,7 +428,7 @@ TEST_CASE_FIXTURE(Fixture, "pcall_returns_at_least_two_value_but_function_return } // Belongs in TypeInfer.builtins.test.cpp. -TEST_CASE_FIXTURE(Fixture, "choose_the_right_overload_for_pcall") +TEST_CASE_FIXTURE(BuiltinsFixture, "choose_the_right_overload_for_pcall") { CheckResult result = check(R"( local function f(): number @@ -449,7 +449,7 @@ TEST_CASE_FIXTURE(Fixture, "choose_the_right_overload_for_pcall") } // Belongs in TypeInfer.builtins.test.cpp. -TEST_CASE_FIXTURE(Fixture, "function_returns_many_things_but_first_of_it_is_forgotten") +TEST_CASE_FIXTURE(BuiltinsFixture, "function_returns_many_things_but_first_of_it_is_forgotten") { CheckResult result = check(R"( local function f(): (number, string, boolean) diff --git a/tests/TypeInfer.refinements.test.cpp b/tests/TypeInfer.refinements.test.cpp index 136ca00a..8c130490 100644 --- a/tests/TypeInfer.refinements.test.cpp +++ b/tests/TypeInfer.refinements.test.cpp @@ -240,7 +240,7 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_in_if_condition_position") CHECK_EQ("number", toString(requireTypeAtPosition({3, 26}))); } -TEST_CASE_FIXTURE(Fixture, "typeguard_in_assert_position") +TEST_CASE_FIXTURE(BuiltinsFixture, "typeguard_in_assert_position") { CheckResult result = check(R"( local a @@ -300,7 +300,7 @@ TEST_CASE_FIXTURE(Fixture, "call_a_more_specific_function_using_typeguard") CHECK_EQ("Type 'string' could not be converted into 'number'", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "impossible_type_narrow_is_not_an_error") +TEST_CASE_FIXTURE(BuiltinsFixture, "impossible_type_narrow_is_not_an_error") { // This unit test serves as a reminder to not implement this warning until Luau is intelligent enough. // For instance, getting a value out of the indexer and checking whether the value exists is not an error. @@ -333,7 +333,7 @@ TEST_CASE_FIXTURE(Fixture, "truthy_constraint_on_properties") CHECK_EQ("number?", toString(requireType("bar"))); } -TEST_CASE_FIXTURE(Fixture, "index_on_a_refined_property") +TEST_CASE_FIXTURE(BuiltinsFixture, "index_on_a_refined_property") { CheckResult result = check(R"( local t: {x: {y: string}?} = {x = {y = "hello!"}} @@ -346,7 +346,7 @@ TEST_CASE_FIXTURE(Fixture, "index_on_a_refined_property") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "assert_non_binary_expressions_actually_resolve_constraints") +TEST_CASE_FIXTURE(BuiltinsFixture, "assert_non_binary_expressions_actually_resolve_constraints") { CheckResult result = check(R"( local foo: string? = "hello" @@ -730,7 +730,7 @@ TEST_CASE_FIXTURE(Fixture, "type_guard_can_filter_for_overloaded_function") CHECK_EQ("nil", toString(requireTypeAtPosition({6, 28}))); } -TEST_CASE_FIXTURE(Fixture, "type_guard_warns_on_no_overlapping_types_only_when_sense_is_true") +TEST_CASE_FIXTURE(BuiltinsFixture, "type_guard_warns_on_no_overlapping_types_only_when_sense_is_true") { CheckResult result = check(R"( local function f(t: {x: number}) @@ -846,7 +846,7 @@ TEST_CASE_FIXTURE(Fixture, "not_t_or_some_prop_of_t") CHECK_EQ("{| x: boolean |}?", toString(requireTypeAtPosition({3, 28}))); } -TEST_CASE_FIXTURE(Fixture, "assert_a_to_be_truthy_then_assert_a_to_be_number") +TEST_CASE_FIXTURE(BuiltinsFixture, "assert_a_to_be_truthy_then_assert_a_to_be_number") { CheckResult result = check(R"( local a: (number | string)? @@ -862,7 +862,7 @@ TEST_CASE_FIXTURE(Fixture, "assert_a_to_be_truthy_then_assert_a_to_be_number") CHECK_EQ("number", toString(requireTypeAtPosition({5, 18}))); } -TEST_CASE_FIXTURE(Fixture, "merge_should_be_fully_agnostic_of_hashmap_ordering") +TEST_CASE_FIXTURE(BuiltinsFixture, "merge_should_be_fully_agnostic_of_hashmap_ordering") { // This bug came up because there was a mistake in Luau::merge where zipping on two maps would produce the wrong merged result. CheckResult result = check(R"( @@ -899,7 +899,7 @@ TEST_CASE_FIXTURE(Fixture, "refine_the_correct_types_opposite_of_when_a_is_not_n CHECK_EQ("number | string", toString(requireTypeAtPosition({5, 28}))); } -TEST_CASE_FIXTURE(Fixture, "is_truthy_constraint_ifelse_expression") +TEST_CASE_FIXTURE(BuiltinsFixture, "is_truthy_constraint_ifelse_expression") { CheckResult result = check(R"( function f(v:string?) @@ -913,7 +913,7 @@ TEST_CASE_FIXTURE(Fixture, "is_truthy_constraint_ifelse_expression") CHECK_EQ("nil", toString(requireTypeAtPosition({2, 45}))); } -TEST_CASE_FIXTURE(Fixture, "invert_is_truthy_constraint_ifelse_expression") +TEST_CASE_FIXTURE(BuiltinsFixture, "invert_is_truthy_constraint_ifelse_expression") { CheckResult result = check(R"( function f(v:string?) @@ -945,7 +945,7 @@ TEST_CASE_FIXTURE(Fixture, "type_comparison_ifelse_expression") CHECK_EQ("any", toString(requireTypeAtPosition({6, 66}))); } -TEST_CASE_FIXTURE(Fixture, "correctly_lookup_a_shadowed_local_that_which_was_previously_refined") +TEST_CASE_FIXTURE(BuiltinsFixture, "correctly_lookup_a_shadowed_local_that_which_was_previously_refined") { CheckResult result = check(R"( local foo: string? = "hi" diff --git a/tests/TypeInfer.singletons.test.cpp b/tests/TypeInfer.singletons.test.cpp index 8d6682b8..79eeb824 100644 --- a/tests/TypeInfer.singletons.test.cpp +++ b/tests/TypeInfer.singletons.test.cpp @@ -415,7 +415,7 @@ TEST_CASE_FIXTURE(Fixture, "widening_happens_almost_everywhere_except_for_tables LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "table_insert_with_a_singleton_argument") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_with_a_singleton_argument") { ScopedFastFlag sff[]{ {"LuauWidenIfSupertypeIsFree2", true}, diff --git a/tests/TypeInfer.tables.test.cpp b/tests/TypeInfer.tables.test.cpp index 8e535995..5078b0bf 100644 --- a/tests/TypeInfer.tables.test.cpp +++ b/tests/TypeInfer.tables.test.cpp @@ -201,7 +201,7 @@ TEST_CASE_FIXTURE(Fixture, "used_dot_instead_of_colon") REQUIRE(it != result.errors.end()); } -TEST_CASE_FIXTURE(Fixture, "used_colon_correctly") +TEST_CASE_FIXTURE(BuiltinsFixture, "used_colon_correctly") { CheckResult result = check(R"( --!nonstrict @@ -883,7 +883,7 @@ TEST_CASE_FIXTURE(Fixture, "assigning_to_an_unsealed_table_with_string_literal_s CHECK_EQ(*typeChecker.stringType, *propertyA); } -TEST_CASE_FIXTURE(Fixture, "oop_indexer_works") +TEST_CASE_FIXTURE(BuiltinsFixture, "oop_indexer_works") { CheckResult result = check(R"( local clazz = {} @@ -906,7 +906,7 @@ TEST_CASE_FIXTURE(Fixture, "oop_indexer_works") CHECK_EQ(*typeChecker.stringType, *requireType("words")); } -TEST_CASE_FIXTURE(Fixture, "indexer_table") +TEST_CASE_FIXTURE(BuiltinsFixture, "indexer_table") { CheckResult result = check(R"( local clazz = {a="hello"} @@ -919,7 +919,7 @@ TEST_CASE_FIXTURE(Fixture, "indexer_table") CHECK_EQ(*typeChecker.stringType, *requireType("b")); } -TEST_CASE_FIXTURE(Fixture, "indexer_fn") +TEST_CASE_FIXTURE(BuiltinsFixture, "indexer_fn") { CheckResult result = check(R"( local instanace = setmetatable({}, {__index=function() return 10 end}) @@ -930,7 +930,7 @@ TEST_CASE_FIXTURE(Fixture, "indexer_fn") CHECK_EQ(*typeChecker.numberType, *requireType("b")); } -TEST_CASE_FIXTURE(Fixture, "meta_add") +TEST_CASE_FIXTURE(BuiltinsFixture, "meta_add") { // Note: meta_add_inferred and this unit test are currently the same exact thing. // We'll want to change this one in particular when we add real syntax for metatables. @@ -947,7 +947,7 @@ TEST_CASE_FIXTURE(Fixture, "meta_add") CHECK_EQ(follow(requireType("a")), follow(requireType("c"))); } -TEST_CASE_FIXTURE(Fixture, "meta_add_inferred") +TEST_CASE_FIXTURE(BuiltinsFixture, "meta_add_inferred") { CheckResult result = check(R"( local a = {} @@ -960,7 +960,7 @@ TEST_CASE_FIXTURE(Fixture, "meta_add_inferred") CHECK_EQ(*requireType("a"), *requireType("c")); } -TEST_CASE_FIXTURE(Fixture, "meta_add_both_ways") +TEST_CASE_FIXTURE(BuiltinsFixture, "meta_add_both_ways") { CheckResult result = check(R"( type VectorMt = { __add: (Vector, number) -> Vector } @@ -980,7 +980,7 @@ TEST_CASE_FIXTURE(Fixture, "meta_add_both_ways") // This test exposed a bug where we let go of the "seen" stack while unifying table types // As a result, type inference crashed with a stack overflow. -TEST_CASE_FIXTURE(Fixture, "unification_of_unions_in_a_self_referential_type") +TEST_CASE_FIXTURE(BuiltinsFixture, "unification_of_unions_in_a_self_referential_type") { CheckResult result = check(R"( type A = {} @@ -1009,7 +1009,7 @@ TEST_CASE_FIXTURE(Fixture, "unification_of_unions_in_a_self_referential_type") CHECK_EQ(bmtv->metatable, requireType("bmt")); } -TEST_CASE_FIXTURE(Fixture, "oop_polymorphic") +TEST_CASE_FIXTURE(BuiltinsFixture, "oop_polymorphic") { CheckResult result = check(R"( local animal = {} @@ -1060,7 +1060,7 @@ TEST_CASE_FIXTURE(Fixture, "user_defined_table_types_are_named") CHECK_EQ("Vector3", toString(requireType("v"))); } -TEST_CASE_FIXTURE(Fixture, "result_is_always_any_if_lhs_is_any") +TEST_CASE_FIXTURE(BuiltinsFixture, "result_is_always_any_if_lhs_is_any") { CheckResult result = check(R"( type Vector3MT = { @@ -1133,7 +1133,7 @@ TEST_CASE_FIXTURE(Fixture, "nice_error_when_trying_to_fetch_property_of_boolean" CHECK_EQ("Type 'boolean' does not have key 'some_prop'", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "defining_a_method_for_a_builtin_sealed_table_must_fail") +TEST_CASE_FIXTURE(BuiltinsFixture, "defining_a_method_for_a_builtin_sealed_table_must_fail") { CheckResult result = check(R"( function string.m() end @@ -1142,7 +1142,7 @@ TEST_CASE_FIXTURE(Fixture, "defining_a_method_for_a_builtin_sealed_table_must_fa LUAU_REQUIRE_ERROR_COUNT(1, result); } -TEST_CASE_FIXTURE(Fixture, "defining_a_self_method_for_a_builtin_sealed_table_must_fail") +TEST_CASE_FIXTURE(BuiltinsFixture, "defining_a_self_method_for_a_builtin_sealed_table_must_fail") { CheckResult result = check(R"( function string:m() end @@ -1261,7 +1261,7 @@ TEST_CASE_FIXTURE(Fixture, "found_like_key_in_table_function_call") CHECK_EQ(toString(te), "Key 'fOo' not found in table 't'. Did you mean 'Foo'?"); } -TEST_CASE_FIXTURE(Fixture, "found_like_key_in_table_property_access") +TEST_CASE_FIXTURE(BuiltinsFixture, "found_like_key_in_table_property_access") { CheckResult result = check(R"( local t = {X = 1} @@ -1286,7 +1286,7 @@ TEST_CASE_FIXTURE(Fixture, "found_like_key_in_table_property_access") CHECK_EQ(toString(te), "Key 'x' not found in table 't'. Did you mean 'X'?"); } -TEST_CASE_FIXTURE(Fixture, "found_multiple_like_keys") +TEST_CASE_FIXTURE(BuiltinsFixture, "found_multiple_like_keys") { CheckResult result = check(R"( local t = {Foo = 1, foO = 2} @@ -1312,7 +1312,7 @@ TEST_CASE_FIXTURE(Fixture, "found_multiple_like_keys") CHECK_EQ(toString(te), "Key 'foo' not found in table 't'. Did you mean one of 'Foo', 'foO'?"); } -TEST_CASE_FIXTURE(Fixture, "dont_suggest_exact_match_keys") +TEST_CASE_FIXTURE(BuiltinsFixture, "dont_suggest_exact_match_keys") { CheckResult result = check(R"( local t = {} @@ -1339,7 +1339,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_suggest_exact_match_keys") CHECK_EQ(toString(te), "Key 'Foo' not found in table 't'. Did you mean 'foO'?"); } -TEST_CASE_FIXTURE(Fixture, "getmetatable_returns_pointer_to_metatable") +TEST_CASE_FIXTURE(BuiltinsFixture, "getmetatable_returns_pointer_to_metatable") { CheckResult result = check(R"( local t = {x = 1} @@ -1352,7 +1352,7 @@ TEST_CASE_FIXTURE(Fixture, "getmetatable_returns_pointer_to_metatable") CHECK_EQ(*requireType("mt"), *requireType("returnedMT")); } -TEST_CASE_FIXTURE(Fixture, "metatable_mismatch_should_fail") +TEST_CASE_FIXTURE(BuiltinsFixture, "metatable_mismatch_should_fail") { CheckResult result = check(R"( local t1 = {x = 1} @@ -1374,7 +1374,7 @@ TEST_CASE_FIXTURE(Fixture, "metatable_mismatch_should_fail") CHECK_EQ(*tm->givenType, *requireType("t2")); } -TEST_CASE_FIXTURE(Fixture, "property_lookup_through_tabletypevar_metatable") +TEST_CASE_FIXTURE(BuiltinsFixture, "property_lookup_through_tabletypevar_metatable") { CheckResult result = check(R"( local t = {x = 1} @@ -1393,7 +1393,7 @@ TEST_CASE_FIXTURE(Fixture, "property_lookup_through_tabletypevar_metatable") CHECK_EQ(up->key, "z"); } -TEST_CASE_FIXTURE(Fixture, "missing_metatable_for_sealed_tables_do_not_get_inferred") +TEST_CASE_FIXTURE(BuiltinsFixture, "missing_metatable_for_sealed_tables_do_not_get_inferred") { CheckResult result = check(R"( local t = {x = 1} @@ -1742,7 +1742,7 @@ TEST_CASE_FIXTURE(Fixture, "hide_table_error_properties") CHECK_EQ("Cannot add property 'b' to table '{| x: number |}'", toString(result.errors[1])); } -TEST_CASE_FIXTURE(Fixture, "builtin_table_names") +TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_table_names") { CheckResult result = check(R"( os.h = 2 @@ -1755,7 +1755,7 @@ TEST_CASE_FIXTURE(Fixture, "builtin_table_names") CHECK_EQ("Cannot add property 'k' to table 'string'", toString(result.errors[1])); } -TEST_CASE_FIXTURE(Fixture, "persistent_sealed_table_is_immutable") +TEST_CASE_FIXTURE(BuiltinsFixture, "persistent_sealed_table_is_immutable") { CheckResult result = check(R"( --!nonstrict @@ -1858,7 +1858,7 @@ local foos: {Foo} = { LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "quantifying_a_bound_var_works") +TEST_CASE_FIXTURE(BuiltinsFixture, "quantifying_a_bound_var_works") { CheckResult result = check(R"( local clazz = {} @@ -1983,7 +1983,7 @@ TEST_CASE_FIXTURE(Fixture, "invariant_table_properties_means_instantiating_table LUAU_REQUIRE_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "table_insert_should_cope_with_optional_properties_in_nonstrict") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_should_cope_with_optional_properties_in_nonstrict") { CheckResult result = check(R"( --!nonstrict @@ -1996,7 +1996,7 @@ TEST_CASE_FIXTURE(Fixture, "table_insert_should_cope_with_optional_properties_in LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "table_insert_should_cope_with_optional_properties_in_strict") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_should_cope_with_optional_properties_in_strict") { ScopedFastFlag sff{"LuauTableSubtypingVariance2", true}; @@ -2052,7 +2052,7 @@ caused by: Property 'y' is not compatible. Type 'number' could not be converted into 'string')"); } -TEST_CASE_FIXTURE(Fixture, "error_detailed_metatable_prop") +TEST_CASE_FIXTURE(BuiltinsFixture, "error_detailed_metatable_prop") { ScopedFastFlag sff[]{ {"LuauTableSubtypingVariance2", true}, @@ -2183,7 +2183,7 @@ a.p = { x = 9 } LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "recursive_metatable_type_call") +TEST_CASE_FIXTURE(BuiltinsFixture, "recursive_metatable_type_call") { ScopedFastFlag sff[]{ {"LuauUnsealedTableLiteral", true}, @@ -2277,7 +2277,7 @@ local y = #x LUAU_REQUIRE_ERROR_COUNT(1, result); } -TEST_CASE_FIXTURE(Fixture, "dont_hang_when_trying_to_look_up_in_cyclic_metatable_index") +TEST_CASE_FIXTURE(BuiltinsFixture, "dont_hang_when_trying_to_look_up_in_cyclic_metatable_index") { ScopedFastFlag sff{"LuauTerminateCyclicMetatableIndexLookup", true}; @@ -2296,7 +2296,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_hang_when_trying_to_look_up_in_cyclic_metatable CHECK_EQ("Type 't' does not have key 'p'", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "give_up_after_one_metatable_index_look_up") +TEST_CASE_FIXTURE(BuiltinsFixture, "give_up_after_one_metatable_index_look_up") { CheckResult result = check(R"( local data = { x = 5 } @@ -2478,7 +2478,7 @@ TEST_CASE_FIXTURE(Fixture, "free_rhs_table_can_also_be_bound") )"); } -TEST_CASE_FIXTURE(Fixture, "table_unifies_into_map") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_unifies_into_map") { CheckResult result = check(R"( local Instance: any @@ -2564,7 +2564,7 @@ TEST_CASE_FIXTURE(Fixture, "generalize_table_argument") * the generalization process), then it loses the knowledge that its metatable will have an :incr() * method. */ -TEST_CASE_FIXTURE(Fixture, "dont_quantify_table_that_belongs_to_outer_scope") +TEST_CASE_FIXTURE(BuiltinsFixture, "dont_quantify_table_that_belongs_to_outer_scope") { CheckResult result = check(R"( local Counter = {} @@ -2606,7 +2606,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_quantify_table_that_belongs_to_outer_scope") } // TODO: CLI-39624 -TEST_CASE_FIXTURE(Fixture, "instantiate_tables_at_scope_level") +TEST_CASE_FIXTURE(BuiltinsFixture, "instantiate_tables_at_scope_level") { CheckResult result = check(R"( --!strict @@ -2690,7 +2690,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_crash_when_setmetatable_does_not_produce_a_meta LUAU_REQUIRE_ERROR_COUNT(1, result); } -TEST_CASE_FIXTURE(Fixture, "instantiate_table_cloning") +TEST_CASE_FIXTURE(BuiltinsFixture, "instantiate_table_cloning") { CheckResult result = check(R"( --!nonstrict @@ -2711,7 +2711,7 @@ type t0 = any CHECK(ttv->instantiatedTypeParams.empty()); } -TEST_CASE_FIXTURE(Fixture, "instantiate_table_cloning_2") +TEST_CASE_FIXTURE(BuiltinsFixture, "instantiate_table_cloning_2") { ScopedFastFlag sff{"LuauOnlyMutateInstantiatedTables", true}; @@ -2767,7 +2767,7 @@ local baz = foo[bar] CHECK_EQ(result.errors[0].location, Location{Position{3, 16}, Position{3, 19}}); } -TEST_CASE_FIXTURE(Fixture, "table_simple_call") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_simple_call") { CheckResult result = check(R"( local a = setmetatable({ x = 2 }, { @@ -2783,7 +2783,7 @@ local c = a(2) -- too many arguments CHECK_EQ("Argument count mismatch. Function expects 1 argument, but 2 are specified", toString(result.errors[0])); } -TEST_CASE_FIXTURE(Fixture, "access_index_metamethod_that_returns_variadic") +TEST_CASE_FIXTURE(BuiltinsFixture, "access_index_metamethod_that_returns_variadic") { CheckResult result = check(R"( type Foo = {x: string} @@ -2878,7 +2878,7 @@ TEST_CASE_FIXTURE(Fixture, "pairs_parameters_are_not_unsealed_tables") )"); } -TEST_CASE_FIXTURE(Fixture, "table_function_check_use_after_free") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_function_check_use_after_free") { CheckResult result = check(R"( local t = {} @@ -2916,7 +2916,7 @@ TEST_CASE_FIXTURE(Fixture, "inferred_properties_of_a_table_should_start_with_the } // The real bug here was that we weren't always uncondionally typechecking a trailing return statement last. -TEST_CASE_FIXTURE(Fixture, "dont_leak_free_table_props") +TEST_CASE_FIXTURE(BuiltinsFixture, "dont_leak_free_table_props") { CheckResult result = check(R"( local function a(state) diff --git a/tests/TypeInfer.test.cpp b/tests/TypeInfer.test.cpp index e81ef1a9..48cd1c3d 100644 --- a/tests/TypeInfer.test.cpp +++ b/tests/TypeInfer.test.cpp @@ -161,7 +161,7 @@ TEST_CASE_FIXTURE(Fixture, "unify_nearly_identical_recursive_types") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "warn_on_lowercase_parent_property") +TEST_CASE_FIXTURE(BuiltinsFixture, "warn_on_lowercase_parent_property") { CheckResult result = check(R"( local M = require(script.parent.DoesNotMatter) @@ -175,7 +175,7 @@ TEST_CASE_FIXTURE(Fixture, "warn_on_lowercase_parent_property") REQUIRE_EQ("parent", ed->symbol); } -TEST_CASE_FIXTURE(Fixture, "weird_case") +TEST_CASE_FIXTURE(BuiltinsFixture, "weird_case") { CheckResult result = check(R"( local function f() return 4 end @@ -419,7 +419,7 @@ TEST_CASE_FIXTURE(Fixture, "globals_everywhere") CHECK_EQ("any", toString(requireType("bar"))); } -TEST_CASE_FIXTURE(Fixture, "correctly_scope_locals_do") +TEST_CASE_FIXTURE(BuiltinsFixture, "correctly_scope_locals_do") { CheckResult result = check(R"( do @@ -534,7 +534,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_after_error_recovery_no_assert") LUAU_REQUIRE_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "tc_after_error_recovery_no_replacement_name_in_error") +TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_in_error") { { CheckResult result = check(R"( @@ -587,7 +587,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_after_error_recovery_no_replacement_name_in_error } } -TEST_CASE_FIXTURE(Fixture, "index_expr_should_be_checked") +TEST_CASE_FIXTURE(BuiltinsFixture, "index_expr_should_be_checked") { CheckResult result = check(R"( local foo: any @@ -768,7 +768,7 @@ b, c = {2, "s"}, {"b", 4} LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "infer_assignment_value_types_mutable_lval") +TEST_CASE_FIXTURE(BuiltinsFixture, "infer_assignment_value_types_mutable_lval") { CheckResult result = check(R"( local a = {} @@ -836,7 +836,7 @@ local a: number? = if true then 1 else nil LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions_expected_type_3") +TEST_CASE_FIXTURE(BuiltinsFixture, "tc_if_else_expressions_expected_type_3") { CheckResult result = check(R"( local function times(n: any, f: () -> T) @@ -907,7 +907,7 @@ TEST_CASE_FIXTURE(Fixture, "fuzzer_found_this") )"); } -TEST_CASE_FIXTURE(Fixture, "recursive_metatable_crash") +TEST_CASE_FIXTURE(BuiltinsFixture, "recursive_metatable_crash") { CheckResult result = check(R"( local function getIt() @@ -1041,7 +1041,6 @@ TEST_CASE_FIXTURE(Fixture, "follow_on_new_types_in_substitution") TEST_CASE_FIXTURE(Fixture, "do_not_bind_a_free_table_to_a_union_containing_that_table") { ScopedFastFlag flag[] = { - {"LuauStatFunctionSimplify4", true}, {"LuauLowerBoundsCalculation", true}, {"LuauDifferentOrderOfUnificationDoesntMatter2", true}, }; diff --git a/tests/TypeInfer.tryUnify.test.cpp b/tests/TypeInfer.tryUnify.test.cpp index 87562644..49deae71 100644 --- a/tests/TypeInfer.tryUnify.test.cpp +++ b/tests/TypeInfer.tryUnify.test.cpp @@ -196,7 +196,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "variadics_should_use_reversed_properly") CHECK_EQ(toString(tm->wantedType), "string"); } -TEST_CASE_FIXTURE(TryUnifyFixture, "cli_41095_concat_log_in_sealed_table_unification") +TEST_CASE_FIXTURE(BuiltinsFixture, "cli_41095_concat_log_in_sealed_table_unification") { CheckResult result = check(R"( --!strict diff --git a/tests/TypeInfer.typePacks.cpp b/tests/TypeInfer.typePacks.cpp index f141622f..fd66b080 100644 --- a/tests/TypeInfer.typePacks.cpp +++ b/tests/TypeInfer.typePacks.cpp @@ -339,7 +339,7 @@ local c: Packed CHECK_EQ(toString(ttvC->instantiatedTypePackParams[0], {true}), "number, boolean"); } -TEST_CASE_FIXTURE(Fixture, "type_alias_type_packs_import") +TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_type_packs_import") { fileResolver.source["game/A"] = R"( export type Packed = { a: T, b: (U...) -> () } @@ -369,7 +369,7 @@ local d: { a: typeof(c) } CHECK_EQ(toString(requireType("d")), "{| a: Packed |}"); } -TEST_CASE_FIXTURE(Fixture, "type_pack_type_parameters") +TEST_CASE_FIXTURE(BuiltinsFixture, "type_pack_type_parameters") { fileResolver.source["game/A"] = R"( export type Packed = { a: T, b: (U...) -> () } @@ -784,7 +784,7 @@ local a: Y<...number> LUAU_REQUIRE_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "type_alias_default_export") +TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_default_export") { fileResolver.source["Module/Types"] = R"( export type A = { a: T, b: U } diff --git a/tests/TypeInfer.unionTypes.test.cpp b/tests/TypeInfer.unionTypes.test.cpp index 96bdd534..277f3887 100644 --- a/tests/TypeInfer.unionTypes.test.cpp +++ b/tests/TypeInfer.unionTypes.test.cpp @@ -104,7 +104,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_arguments_table2") REQUIRE(!result.errors.empty()); } -TEST_CASE_FIXTURE(Fixture, "error_takes_optional_arguments") +TEST_CASE_FIXTURE(BuiltinsFixture, "error_takes_optional_arguments") { CheckResult result = check(R"( error("message") @@ -517,10 +517,8 @@ TEST_CASE_FIXTURE(Fixture, "dont_allow_cyclic_unions_to_be_inferred") LUAU_REQUIRE_NO_ERRORS(result); } -TEST_CASE_FIXTURE(Fixture, "table_union_write_indirect") +TEST_CASE_FIXTURE(BuiltinsFixture, "table_union_write_indirect") { - ScopedFastFlag statFunctionSimplify{"LuauStatFunctionSimplify4", true}; - CheckResult result = check(R"( type A = { x: number, y: (number) -> string } | { z: number, y: (number) -> string }