mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 06:15:44 +08:00
Sync to upstream/release/650
This commit is contained in:
parent
1de169f006
commit
ee5b473b86
@ -265,4 +265,6 @@ void registerTypeUserData(lua_State* L);
|
||||
|
||||
void setTypeFunctionEnvironment(lua_State* L);
|
||||
|
||||
void resetTypeFunctionState(lua_State* L);
|
||||
|
||||
} // namespace Luau
|
||||
|
@ -38,7 +38,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(StudioReportLuauAny2, false);
|
||||
LUAU_FASTFLAGVARIABLE(StudioReportLuauAny2);
|
||||
LUAU_FASTINTVARIABLE(LuauAnySummaryRecursionLimit, 300);
|
||||
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes);
|
||||
@ -161,7 +161,7 @@ void AnyTypeSummary::visit(const Scope* scope, AstStatReturn* ret, const Module*
|
||||
typeInfo.push_back(ti);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (ret->list.size > 1 && !seenTP)
|
||||
{
|
||||
if (containsAny(retScope->returnType))
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauDocumentationAtPosition, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDocumentationAtPosition)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <utility>
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAGVARIABLE(AutocompleteRequirePathSuggestions, false)
|
||||
LUAU_FASTFLAGVARIABLE(AutocompleteRequirePathSuggestions)
|
||||
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
|
||||
LUAU_FASTINT(LuauTypeInferIterationLimit)
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "Luau/Ast.h"
|
||||
#include "Luau/Clone.h"
|
||||
#include "Luau/DenseHash.h"
|
||||
#include "Luau/Error.h"
|
||||
#include "Luau/Frontend.h"
|
||||
#include "Luau/Symbol.h"
|
||||
@ -29,8 +30,8 @@
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTypestateBuiltins, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStringFormatArityFix, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTypestateBuiltins2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStringFormatArityFix)
|
||||
|
||||
LUAU_FASTFLAG(AutocompleteRequirePathSuggestions)
|
||||
|
||||
@ -421,7 +422,7 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
|
||||
|
||||
attachMagicFunction(ttv->props["pack"].type(), magicFunctionPack);
|
||||
attachDcrMagicFunction(ttv->props["pack"].type(), dcrMagicFunctionPack);
|
||||
if (FFlag::LuauTypestateBuiltins)
|
||||
if (FFlag::LuauTypestateBuiltins2)
|
||||
attachDcrMagicFunction(ttv->props["freeze"].type(), dcrMagicFunctionFreeze);
|
||||
}
|
||||
|
||||
@ -1338,54 +1339,86 @@ static bool dcrMagicFunctionPack(MagicFunctionCallContext context)
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::optional<TypeId> freezeTable(TypeId inputType, MagicFunctionCallContext& context)
|
||||
{
|
||||
TypeArena* arena = context.solver->arena;
|
||||
|
||||
if (auto mt = get<MetatableType>(inputType))
|
||||
{
|
||||
std::optional<TypeId> frozenTable = freezeTable(mt->table, context);
|
||||
|
||||
if (!frozenTable)
|
||||
return std::nullopt;
|
||||
|
||||
TypeId resultType = arena->addType(MetatableType{*frozenTable, mt->metatable, mt->syntheticName});
|
||||
|
||||
return resultType;
|
||||
}
|
||||
|
||||
if (get<TableType>(inputType))
|
||||
{
|
||||
// Clone the input type, this will become our final result type after we mutate it.
|
||||
CloneState cloneState{context.solver->builtinTypes};
|
||||
TypeId resultType = shallowClone(inputType, *arena, cloneState);
|
||||
auto tableTy = getMutable<TableType>(resultType);
|
||||
// `clone` should not break this.
|
||||
LUAU_ASSERT(tableTy);
|
||||
tableTy->state = TableState::Sealed;
|
||||
|
||||
// We'll mutate the table to make every property type read-only.
|
||||
for (auto iter = tableTy->props.begin(); iter != tableTy->props.end();)
|
||||
{
|
||||
if (iter->second.isWriteOnly())
|
||||
iter = tableTy->props.erase(iter);
|
||||
else
|
||||
{
|
||||
iter->second.writeTy = std::nullopt;
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
return resultType;
|
||||
}
|
||||
|
||||
context.solver->reportError(TypeMismatch{context.solver->builtinTypes->tableType, inputType}, context.callSite->argLocation);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
static bool dcrMagicFunctionFreeze(MagicFunctionCallContext context)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauTypestateBuiltins);
|
||||
LUAU_ASSERT(FFlag::LuauTypestateBuiltins2);
|
||||
|
||||
TypeArena* arena = context.solver->arena;
|
||||
const DataFlowGraph* dfg = context.solver->dfg.get();
|
||||
Scope* scope = context.constraint->scope.get();
|
||||
|
||||
const auto& [paramTypes, paramTail] = extendTypePack(*arena, context.solver->builtinTypes, context.arguments, 1);
|
||||
LUAU_ASSERT(paramTypes.size() >= 1);
|
||||
|
||||
TypeId inputType = follow(paramTypes.at(0));
|
||||
|
||||
// we'll check if it's a table first since this magic function also produces the error if it's not until we have bounded generics
|
||||
if (!get<TableType>(inputType))
|
||||
if (paramTypes.empty() || context.callSite->args.size == 0)
|
||||
{
|
||||
context.solver->reportError(TypeMismatch{context.solver->builtinTypes->tableType, inputType}, context.callSite->argLocation);
|
||||
context.solver->reportError(CountMismatch{1, std::nullopt, 0}, context.callSite->argLocation);
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeId inputType = follow(paramTypes[0]);
|
||||
|
||||
AstExpr* targetExpr = context.callSite->args.data[0];
|
||||
std::optional<DefId> resultDef = dfg->getDefOptional(targetExpr);
|
||||
std::optional<TypeId> resultTy = resultDef ? scope->lookup(*resultDef) : std::nullopt;
|
||||
|
||||
// Clone the input type, this will become our final result type after we mutate it.
|
||||
CloneState cloneState{context.solver->builtinTypes};
|
||||
TypeId clonedType = shallowClone(inputType, *arena, cloneState);
|
||||
auto tableTy = getMutable<TableType>(clonedType);
|
||||
// `clone` should not break this.
|
||||
LUAU_ASSERT(tableTy);
|
||||
tableTy->state = TableState::Sealed;
|
||||
tableTy->syntheticName = std::nullopt;
|
||||
std::optional<TypeId> frozenType = freezeTable(inputType, context);
|
||||
|
||||
// We'll mutate the table to make every property type read-only.
|
||||
for (auto iter = tableTy->props.begin(); iter != tableTy->props.end();)
|
||||
if (!frozenType)
|
||||
{
|
||||
if (iter->second.isWriteOnly())
|
||||
iter = tableTy->props.erase(iter);
|
||||
else
|
||||
{
|
||||
iter->second.writeTy = std::nullopt;
|
||||
iter++;
|
||||
}
|
||||
if (resultTy)
|
||||
asMutable(*resultTy)->ty.emplace<BoundType>(context.solver->builtinTypes->errorType);
|
||||
asMutable(context.result)->ty.emplace<BoundTypePack>(context.solver->builtinTypes->errorTypePack);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (resultTy)
|
||||
asMutable(*resultTy)->ty.emplace<BoundType>(clonedType);
|
||||
asMutable(context.result)->ty.emplace<BoundTypePack>(arena->addTypePack({clonedType}));
|
||||
asMutable(*resultTy)->ty.emplace<BoundType>(*frozenType);
|
||||
asMutable(context.result)->ty.emplace<BoundTypePack>(arena->addTypePack({*frozenType}));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -31,9 +31,9 @@ LUAU_FASTINT(LuauCheckRecursionLimit)
|
||||
LUAU_FASTFLAG(DebugLuauLogSolverToJson)
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
|
||||
LUAU_FASTFLAG(LuauTypestateBuiltins)
|
||||
LUAU_FASTFLAG(LuauTypestateBuiltins2)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewSolverVisitErrorExprLvalues, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewSolverVisitErrorExprLvalues)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
@ -1078,7 +1078,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatLocal* stat
|
||||
addConstraint(scope, value->location, NameConstraint{*firstValueType, var->name.value, /*synthetic*/ true});
|
||||
else if (const AstExprCall* call = value->as<AstExprCall>())
|
||||
{
|
||||
if (FFlag::LuauTypestateBuiltins)
|
||||
if (FFlag::LuauTypestateBuiltins2)
|
||||
{
|
||||
if (matchSetMetatable(*call))
|
||||
addConstraint(scope, value->location, NameConstraint{*firstValueType, var->name.value, /*synthetic*/ true});
|
||||
@ -2062,7 +2062,7 @@ InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstExprCall*
|
||||
return InferencePack{arena->addTypePack({resultTy}), {refinementArena.variadic(returnRefinements)}};
|
||||
}
|
||||
|
||||
if (FFlag::LuauTypestateBuiltins && shouldTypestateForFirstArgument(*call) && call->args.size > 0 && isLValue(call->args.data[0]))
|
||||
if (FFlag::LuauTypestateBuiltins2 && shouldTypestateForFirstArgument(*call) && call->args.size > 0 && isLValue(call->args.data[0]))
|
||||
{
|
||||
AstExpr* targetExpr = call->args.data[0];
|
||||
auto resultTy = arena->addType(BlockedType{});
|
||||
@ -2913,7 +2913,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
|
||||
std::vector<TypeId> toBlock;
|
||||
if (DFInt::LuauTypeSolverRelease >= 648)
|
||||
{
|
||||
// This logic is incomplete as we want to re-run this
|
||||
// This logic is incomplete as we want to re-run this
|
||||
// _after_ blocked types have resolved, but this
|
||||
// allows us to do some bidirectional inference.
|
||||
toBlock = findBlockedTypesIn(expr, NotNull{&module->astTypes});
|
||||
@ -2931,7 +2931,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
|
||||
toBlock
|
||||
);
|
||||
// The visitor we ran prior should ensure that there are no
|
||||
// blocked types that we would encounter while matching on
|
||||
// blocked types that we would encounter while matching on
|
||||
// this expression.
|
||||
LUAU_ASSERT(toBlock.empty());
|
||||
}
|
||||
|
@ -27,12 +27,12 @@
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolver, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverIncludeDependencies, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogBindings, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolver)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverIncludeDependencies)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogBindings)
|
||||
LUAU_FASTINTVARIABLE(LuauSolverRecursionLimit, 500)
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
|
||||
LUAU_FASTFLAGVARIABLE(LuauRemoveNotAnyHack, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauRemoveNotAnyHack)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
@ -1337,7 +1337,7 @@ bool ConstraintSolver::tryDispatch(const FunctionCheckConstraint& c, NotNull<con
|
||||
{
|
||||
// This is expensive as we need to traverse a (potentially large)
|
||||
// literal up front in order to determine if there are any blocked
|
||||
// types, otherwise we may run `matchTypeLiteral` multiple times,
|
||||
// types, otherwise we may run `matchTypeLiteral` multiple times,
|
||||
// which right now may fail due to being non-idempotent (it
|
||||
// destructively updates the underlying literal type).
|
||||
auto blockedTypes = findBlockedArgTypesIn(c.callSite, c.astTypes);
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
LUAU_FASTFLAG(DebugLuauFreezeArena)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauTypestateBuiltins)
|
||||
LUAU_FASTFLAG(LuauTypestateBuiltins2)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
@ -939,7 +939,7 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprCall* c)
|
||||
{
|
||||
visitExpr(c->func);
|
||||
|
||||
if (FFlag::LuauTypestateBuiltins && shouldTypestateForFirstArgument(*c) && c->args.size > 1 && isLValue(*c->args.begin()))
|
||||
if (FFlag::LuauTypestateBuiltins2 && shouldTypestateForFirstArgument(*c) && c->args.size > 1 && isLValue(*c->args.begin()))
|
||||
{
|
||||
AstExpr* firstArg = *c->args.begin();
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
LUAU_FASTFLAG(LuauMathMap)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauVectorDefinitions)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
@ -450,9 +452,39 @@ declare buffer: {
|
||||
|
||||
)BUILTIN_SRC";
|
||||
|
||||
static const std::string kBuiltinDefinitionVectorSrc = R"BUILTIN_SRC(
|
||||
|
||||
-- TODO: this will be replaced with a built-in primitive type
|
||||
declare class vector end
|
||||
|
||||
declare vector: {
|
||||
create: @checked (x: number, y: number, z: number) -> vector,
|
||||
magnitude: @checked (vec: vector) -> number,
|
||||
normalize: @checked (vec: vector) -> vector,
|
||||
cross: @checked (vec1: vector, vec2: vector) -> vector,
|
||||
dot: @checked (vec1: vector, vec2: vector) -> number,
|
||||
angle: @checked (vec1: vector, vec2: vector, axis: vector?) -> number,
|
||||
floor: @checked (vec: vector) -> vector,
|
||||
ceil: @checked (vec: vector) -> vector,
|
||||
abs: @checked (vec: vector) -> vector,
|
||||
sign: @checked (vec: vector) -> vector,
|
||||
clamp: @checked (vec: vector, min: vector, max: vector) -> vector,
|
||||
max: @checked (vector, ...vector) -> vector,
|
||||
min: @checked (vector, ...vector) -> vector,
|
||||
|
||||
zero: vector,
|
||||
one: vector,
|
||||
}
|
||||
|
||||
)BUILTIN_SRC";
|
||||
|
||||
std::string getBuiltinDefinitionSource()
|
||||
{
|
||||
std::string result = FFlag::LuauMathMap ? kBuiltinDefinitionLuaSrcChecked : kBuiltinDefinitionLuaSrcChecked_DEPRECATED;
|
||||
|
||||
if (FFlag::LuauVectorDefinitions)
|
||||
result += kBuiltinDefinitionVectorSrc;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -36,20 +36,20 @@ LUAU_FASTINT(LuauTypeInferIterationLimit)
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTINT(LuauTarjanChildLimit)
|
||||
LUAU_FASTFLAG(LuauInferInNoCheckMode)
|
||||
LUAU_FASTFLAGVARIABLE(LuauKnowsTheDataModel3, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStoreCommentsForDefinitionFiles, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauKnowsTheDataModel3)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStoreCommentsForDefinitionFiles)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJsonFile, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForbidInternalTypes, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForceStrictMode, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForceNonStrictMode, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctionNoEvaluation, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJsonFile)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForbidInternalTypes)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForceStrictMode)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForceNonStrictMode)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctionNoEvaluation)
|
||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuauRunCustomModuleChecks, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauMoreThoroughCycleDetection, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauMoreThoroughCycleDetection)
|
||||
|
||||
LUAU_FASTFLAG(StudioReportLuauAny2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStoreDFGOnModule2, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStoreDFGOnModule2)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -18,7 +18,7 @@ LUAU_FASTFLAG(LuauSolverV2)
|
||||
|
||||
LUAU_FASTFLAG(LuauAttribute)
|
||||
LUAU_FASTFLAG(LuauNativeAttribute)
|
||||
LUAU_FASTFLAGVARIABLE(LintRedundantNativeAttribute, false)
|
||||
LUAU_FASTFLAGVARIABLE(LintRedundantNativeAttribute)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserTypeFunNonstrict)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
@ -421,7 +423,9 @@ struct NonStrictTypeChecker
|
||||
|
||||
NonStrictContext visit(AstStatTypeFunction* typeFunc)
|
||||
{
|
||||
reportError(GenericError{"This syntax is not supported"}, typeFunc->location);
|
||||
if (!FFlag::LuauUserTypeFunNonstrict)
|
||||
reportError(GenericError{"This syntax is not supported"}, typeFunc->location);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -15,14 +15,14 @@
|
||||
#include "Luau/TypeFwd.h"
|
||||
#include "Luau/Unifier.h"
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauCheckNormalizeInvariant, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauCheckNormalizeInvariant)
|
||||
|
||||
LUAU_FASTINTVARIABLE(LuauNormalizeCacheLimit, 100000);
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
|
||||
LUAU_FASTINTVARIABLE(LuauNormalizeIntersectionLimit, 200)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNormalizationTracksCyclicPairsThroughInhabitance, false);
|
||||
LUAU_FASTFLAGVARIABLE(LuauIntersectNormalsNeedsToTrackResourceLimits, false);
|
||||
LUAU_FASTFLAGVARIABLE(LuauNormalizationTracksCyclicPairsThroughInhabitance);
|
||||
LUAU_FASTFLAGVARIABLE(LuauIntersectNormalsNeedsToTrackResourceLimits);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -15,7 +15,7 @@
|
||||
LUAU_FASTINT(LuauTypeReductionRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_DYNAMIC_FASTINTVARIABLE(LuauSimplificationComplexityLimit, 8);
|
||||
LUAU_FASTFLAGVARIABLE(LuauFlagBasicIntersectFollows, false);
|
||||
LUAU_FASTFLAGVARIABLE(LuauFlagBasicIntersectFollows);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -21,8 +21,9 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauSubtypingCheckPathValidity, false);
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauSubtypingCheckPathValidity)
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
|
||||
LUAU_FASTFLAGVARIABLE(LuauRetrySubtypingWithoutHiddenPack)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
@ -1477,6 +1478,20 @@ SubtypingResult Subtyping::isCovariantWith(
|
||||
result.orElse(
|
||||
isContravariantWith(env, subFunction->argTypes, superFunction->argTypes, scope).withBothComponent(TypePath::PackField::Arguments)
|
||||
);
|
||||
|
||||
// If subtyping failed in the argument packs, we should check if there's a hidden variadic tail and try ignoring it.
|
||||
// This might cause subtyping correctly because the sub type here may not have a hidden variadic tail or equivalent.
|
||||
if (FFlag::LuauRetrySubtypingWithoutHiddenPack && !result.isSubtype)
|
||||
{
|
||||
auto [arguments, tail] = flatten(superFunction->argTypes);
|
||||
|
||||
if (auto variadic = get<VariadicTypePack>(tail); variadic && variadic->hidden)
|
||||
{
|
||||
result.orElse(
|
||||
isContravariantWith(env, subFunction->argTypes, arena->addTypePack(TypePack{arguments}), scope).withBothComponent(TypePath::PackField::Arguments)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.andAlso(isCovariantWith(env, subFunction->retTypes, superFunction->retTypes, scope).withBothComponent(TypePath::PackField::Returns));
|
||||
|
@ -38,7 +38,7 @@ LUAU_FASTFLAG(LuauSolverV2)
|
||||
* 3: Suffix free/generic types with their scope pointer, if present.
|
||||
*/
|
||||
LUAU_FASTINTVARIABLE(DebugLuauVerboseTypeNames, 0)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauToStringNoLexicalSort, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauToStringNoLexicalSort)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "Luau/TypeArena.h"
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauFreezeArena, false);
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauFreezeArena);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -45,11 +45,12 @@ LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFamilyApplicationCartesianProductLimit, 5'0
|
||||
// when this value is set to a negative value, guessing will be totally disabled.
|
||||
LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFamilyUseGuesserDepth, -1);
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogTypeFamilies, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctions2, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogTypeFamilies)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctions2)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctionNoEvaluation)
|
||||
LUAU_FASTFLAG(LuauUserTypeFunFixRegister)
|
||||
LUAU_FASTFLAG(LuauRemoveNotAnyHack)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctionResetState)
|
||||
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
|
||||
|
||||
@ -645,6 +646,9 @@ TypeFunctionReductionResult<TypeId> userDefinedTypeFunction(
|
||||
lua_getglobal(global, name.value);
|
||||
lua_xmove(global, L, 1);
|
||||
|
||||
if (FFlag::LuauUserDefinedTypeFunctionResetState)
|
||||
resetTypeFunctionState(L);
|
||||
|
||||
// Push serialized arguments onto the stack
|
||||
|
||||
// Since there aren't any new class types being created in type functions, there isn't a deserialization function
|
||||
|
@ -15,8 +15,8 @@
|
||||
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeFunctionSerdeIterationLimit)
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserTypeFunFixRegister, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserTypeFunFixNoReadWrite, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserTypeFunFixRegister)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserTypeFunFixNoReadWrite)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
@ -1647,6 +1647,15 @@ void setTypeFunctionEnvironment(lua_State* L)
|
||||
}
|
||||
}
|
||||
|
||||
void resetTypeFunctionState(lua_State* L)
|
||||
{
|
||||
lua_getglobal(L, "math");
|
||||
lua_getfield(L, -1, "randomseed");
|
||||
lua_pushnumber(L, 0);
|
||||
lua_call(L, 1, 0);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Below are helper methods for __eq
|
||||
* Same as one from Type.cpp
|
||||
|
@ -20,6 +20,8 @@
|
||||
// currently, controls serialization, deserialization, and `type.copy`
|
||||
LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFunctionSerdeIterationLimit, 100'000);
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserTypeFunFixMetatable)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
@ -241,31 +243,31 @@ private:
|
||||
return target;
|
||||
}
|
||||
|
||||
void serializeChildren(TypeId ty, TypeFunctionTypeId tfti)
|
||||
void serializeChildren(const TypeId ty, TypeFunctionTypeId tfti)
|
||||
{
|
||||
if (auto [p1, p2] = std::tuple{getMutable<PrimitiveType>(ty), getMutable<TypeFunctionPrimitiveType>(tfti)}; p1 && p2)
|
||||
if (auto [p1, p2] = std::tuple{get<PrimitiveType>(ty), getMutable<TypeFunctionPrimitiveType>(tfti)}; p1 && p2)
|
||||
serializeChildren(p1, p2);
|
||||
else if (auto [u1, u2] = std::tuple{getMutable<UnknownType>(ty), getMutable<TypeFunctionUnknownType>(tfti)}; u1 && u2)
|
||||
else if (auto [u1, u2] = std::tuple{get<UnknownType>(ty), getMutable<TypeFunctionUnknownType>(tfti)}; u1 && u2)
|
||||
serializeChildren(u1, u2);
|
||||
else if (auto [n1, n2] = std::tuple{getMutable<NeverType>(ty), getMutable<TypeFunctionNeverType>(tfti)}; n1 && n2)
|
||||
else if (auto [n1, n2] = std::tuple{get<NeverType>(ty), getMutable<TypeFunctionNeverType>(tfti)}; n1 && n2)
|
||||
serializeChildren(n1, n2);
|
||||
else if (auto [a1, a2] = std::tuple{getMutable<AnyType>(ty), getMutable<TypeFunctionAnyType>(tfti)}; a1 && a2)
|
||||
else if (auto [a1, a2] = std::tuple{get<AnyType>(ty), getMutable<TypeFunctionAnyType>(tfti)}; a1 && a2)
|
||||
serializeChildren(a1, a2);
|
||||
else if (auto [s1, s2] = std::tuple{getMutable<SingletonType>(ty), getMutable<TypeFunctionSingletonType>(tfti)}; s1 && s2)
|
||||
else if (auto [s1, s2] = std::tuple{get<SingletonType>(ty), getMutable<TypeFunctionSingletonType>(tfti)}; s1 && s2)
|
||||
serializeChildren(s1, s2);
|
||||
else if (auto [u1, u2] = std::tuple{getMutable<UnionType>(ty), getMutable<TypeFunctionUnionType>(tfti)}; u1 && u2)
|
||||
else if (auto [u1, u2] = std::tuple{get<UnionType>(ty), getMutable<TypeFunctionUnionType>(tfti)}; u1 && u2)
|
||||
serializeChildren(u1, u2);
|
||||
else if (auto [i1, i2] = std::tuple{getMutable<IntersectionType>(ty), getMutable<TypeFunctionIntersectionType>(tfti)}; i1 && i2)
|
||||
else if (auto [i1, i2] = std::tuple{get<IntersectionType>(ty), getMutable<TypeFunctionIntersectionType>(tfti)}; i1 && i2)
|
||||
serializeChildren(i1, i2);
|
||||
else if (auto [n1, n2] = std::tuple{getMutable<NegationType>(ty), getMutable<TypeFunctionNegationType>(tfti)}; n1 && n2)
|
||||
else if (auto [n1, n2] = std::tuple{get<NegationType>(ty), getMutable<TypeFunctionNegationType>(tfti)}; n1 && n2)
|
||||
serializeChildren(n1, n2);
|
||||
else if (auto [t1, t2] = std::tuple{getMutable<TableType>(ty), getMutable<TypeFunctionTableType>(tfti)}; t1 && t2)
|
||||
else if (auto [t1, t2] = std::tuple{get<TableType>(ty), getMutable<TypeFunctionTableType>(tfti)}; t1 && t2)
|
||||
serializeChildren(t1, t2);
|
||||
else if (auto [m1, m2] = std::tuple{getMutable<MetatableType>(ty), getMutable<TypeFunctionTableType>(tfti)}; m1 && m2)
|
||||
else if (auto [m1, m2] = std::tuple{get<MetatableType>(ty), getMutable<TypeFunctionTableType>(tfti)}; m1 && m2)
|
||||
serializeChildren(m1, m2);
|
||||
else if (auto [f1, f2] = std::tuple{getMutable<FunctionType>(ty), getMutable<TypeFunctionFunctionType>(tfti)}; f1 && f2)
|
||||
else if (auto [f1, f2] = std::tuple{get<FunctionType>(ty), getMutable<TypeFunctionFunctionType>(tfti)}; f1 && f2)
|
||||
serializeChildren(f1, f2);
|
||||
else if (auto [c1, c2] = std::tuple{getMutable<ClassType>(ty), getMutable<TypeFunctionClassType>(tfti)}; c1 && c2)
|
||||
else if (auto [c1, c2] = std::tuple{get<ClassType>(ty), getMutable<TypeFunctionClassType>(tfti)}; c1 && c2)
|
||||
serializeChildren(c1, c2);
|
||||
else
|
||||
{ // Either this or ty and tfti do not represent the same type
|
||||
@ -274,12 +276,11 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void serializeChildren(TypePackId tp, TypeFunctionTypePackId tftp)
|
||||
void serializeChildren(const TypePackId tp, TypeFunctionTypePackId tftp)
|
||||
{
|
||||
if (auto [tPack1, tPack2] = std::tuple{getMutable<TypePack>(tp), getMutable<TypeFunctionTypePack>(tftp)}; tPack1 && tPack2)
|
||||
if (auto [tPack1, tPack2] = std::tuple{get<TypePack>(tp), getMutable<TypeFunctionTypePack>(tftp)}; tPack1 && tPack2)
|
||||
serializeChildren(tPack1, tPack2);
|
||||
else if (auto [vPack1, vPack2] = std::tuple{getMutable<VariadicTypePack>(tp), getMutable<TypeFunctionVariadicTypePack>(tftp)};
|
||||
vPack1 && vPack2)
|
||||
else if (auto [vPack1, vPack2] = std::tuple{get<VariadicTypePack>(tp), getMutable<TypeFunctionVariadicTypePack>(tftp)}; vPack1 && vPack2)
|
||||
serializeChildren(vPack1, vPack2);
|
||||
else
|
||||
{ // Either this or ty and tfti do not represent the same type
|
||||
@ -298,49 +299,49 @@ private:
|
||||
state->ctx->ice->ice("Serializing user defined type function arguments: kind and tfkind do not represent the same type");
|
||||
}
|
||||
|
||||
void serializeChildren(PrimitiveType* p1, TypeFunctionPrimitiveType* p2)
|
||||
void serializeChildren(const PrimitiveType* p1, TypeFunctionPrimitiveType* p2)
|
||||
{
|
||||
// noop.
|
||||
}
|
||||
|
||||
void serializeChildren(UnknownType* u1, TypeFunctionUnknownType* u2)
|
||||
void serializeChildren(const UnknownType* u1, TypeFunctionUnknownType* u2)
|
||||
{
|
||||
// noop.
|
||||
}
|
||||
|
||||
void serializeChildren(NeverType* n1, TypeFunctionNeverType* n2)
|
||||
void serializeChildren(const NeverType* n1, TypeFunctionNeverType* n2)
|
||||
{
|
||||
// noop.
|
||||
}
|
||||
|
||||
void serializeChildren(AnyType* a1, TypeFunctionAnyType* a2)
|
||||
void serializeChildren(const AnyType* a1, TypeFunctionAnyType* a2)
|
||||
{
|
||||
// noop.
|
||||
}
|
||||
|
||||
void serializeChildren(SingletonType* s1, TypeFunctionSingletonType* s2)
|
||||
void serializeChildren(const SingletonType* s1, TypeFunctionSingletonType* s2)
|
||||
{
|
||||
// noop.
|
||||
}
|
||||
|
||||
void serializeChildren(UnionType* u1, TypeFunctionUnionType* u2)
|
||||
void serializeChildren(const UnionType* u1, TypeFunctionUnionType* u2)
|
||||
{
|
||||
for (TypeId& ty : u1->options)
|
||||
for (const TypeId& ty : u1->options)
|
||||
u2->components.push_back(shallowSerialize(ty));
|
||||
}
|
||||
|
||||
void serializeChildren(IntersectionType* i1, TypeFunctionIntersectionType* i2)
|
||||
void serializeChildren(const IntersectionType* i1, TypeFunctionIntersectionType* i2)
|
||||
{
|
||||
for (TypeId& ty : i1->parts)
|
||||
for (const TypeId& ty : i1->parts)
|
||||
i2->components.push_back(shallowSerialize(ty));
|
||||
}
|
||||
|
||||
void serializeChildren(NegationType* n1, TypeFunctionNegationType* n2)
|
||||
void serializeChildren(const NegationType* n1, TypeFunctionNegationType* n2)
|
||||
{
|
||||
n2->type = shallowSerialize(n1->ty);
|
||||
}
|
||||
|
||||
void serializeChildren(TableType* t1, TypeFunctionTableType* t2)
|
||||
void serializeChildren(const TableType* t1, TypeFunctionTableType* t2)
|
||||
{
|
||||
for (const auto& [k, p] : t1->props)
|
||||
{
|
||||
@ -359,25 +360,34 @@ private:
|
||||
t2->indexer = TypeFunctionTableIndexer(shallowSerialize(t1->indexer->indexType), shallowSerialize(t1->indexer->indexResultType));
|
||||
}
|
||||
|
||||
void serializeChildren(MetatableType* m1, TypeFunctionTableType* m2)
|
||||
void serializeChildren(const MetatableType* m1, TypeFunctionTableType* m2)
|
||||
{
|
||||
auto tmpTable = get<TypeFunctionTableType>(shallowSerialize(m1->table));
|
||||
if (!tmpTable)
|
||||
state->ctx->ice->ice("Serializing user defined type function arguments: metatable's table is not a TableType");
|
||||
if (FFlag::LuauUserTypeFunFixMetatable)
|
||||
{
|
||||
// Serialize main part of the metatable immediately
|
||||
if (auto tableTy = get<TableType>(m1->table))
|
||||
serializeChildren(tableTy, m2);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto tmpTable = get<TypeFunctionTableType>(shallowSerialize(m1->table));
|
||||
if (!tmpTable)
|
||||
state->ctx->ice->ice("Serializing user defined type function arguments: metatable's table is not a TableType");
|
||||
|
||||
m2->props = tmpTable->props;
|
||||
m2->indexer = tmpTable->indexer;
|
||||
m2->props = tmpTable->props;
|
||||
m2->indexer = tmpTable->indexer;
|
||||
}
|
||||
|
||||
m2->metatable = shallowSerialize(m1->metatable);
|
||||
}
|
||||
|
||||
void serializeChildren(FunctionType* f1, TypeFunctionFunctionType* f2)
|
||||
void serializeChildren(const FunctionType* f1, TypeFunctionFunctionType* f2)
|
||||
{
|
||||
f2->argTypes = shallowSerialize(f1->argTypes);
|
||||
f2->retTypes = shallowSerialize(f1->retTypes);
|
||||
}
|
||||
|
||||
void serializeChildren(ClassType* c1, TypeFunctionClassType* c2)
|
||||
void serializeChildren(const ClassType* c1, TypeFunctionClassType* c2)
|
||||
{
|
||||
for (const auto& [k, p] : c1->props)
|
||||
{
|
||||
@ -402,16 +412,16 @@ private:
|
||||
c2->parent = shallowSerialize(*c1->parent);
|
||||
}
|
||||
|
||||
void serializeChildren(TypePack* t1, TypeFunctionTypePack* t2)
|
||||
void serializeChildren(const TypePack* t1, TypeFunctionTypePack* t2)
|
||||
{
|
||||
for (TypeId& ty : t1->head)
|
||||
for (const TypeId& ty : t1->head)
|
||||
t2->head.push_back(shallowSerialize(ty));
|
||||
|
||||
if (t1->tail.has_value())
|
||||
t2->tail = shallowSerialize(*t1->tail);
|
||||
}
|
||||
|
||||
void serializeChildren(VariadicTypePack* v1, TypeFunctionVariadicTypePack* v2)
|
||||
void serializeChildren(const VariadicTypePack* v1, TypeFunctionVariadicTypePack* v2)
|
||||
{
|
||||
v2->type = shallowSerialize(v1->ty);
|
||||
}
|
||||
|
@ -23,16 +23,18 @@
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauMagicTypes, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauMagicTypes)
|
||||
LUAU_FASTINTVARIABLE(LuauTypeInferRecursionLimit, 165)
|
||||
LUAU_FASTINTVARIABLE(LuauTypeInferIterationLimit, 20000)
|
||||
LUAU_FASTINTVARIABLE(LuauTypeInferTypePackLoopLimit, 5000)
|
||||
LUAU_FASTINTVARIABLE(LuauCheckRecursionLimit, 300)
|
||||
LUAU_FASTINTVARIABLE(LuauVisitRecursionLimit, 500)
|
||||
LUAU_FASTFLAG(LuauKnowsTheDataModel3)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauFreezeDuringUnification, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauFreezeDuringUnification)
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAcceptIndexingTableUnionsIntersections, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAcceptIndexingTableUnionsIntersections)
|
||||
LUAU_FASTFLAGVARIABLE(LuauMetatableFollow)
|
||||
LUAU_FASTFLAGVARIABLE(LuauRequireCyclesDontAlwaysReturnAny)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
@ -263,10 +265,17 @@ ModulePtr TypeChecker::checkWithoutRecursionCheck(const SourceModule& module, Mo
|
||||
ScopePtr parentScope = environmentScope.value_or(globalScope);
|
||||
ScopePtr moduleScope = std::make_shared<Scope>(parentScope);
|
||||
|
||||
if (module.cyclic)
|
||||
moduleScope->returnType = addTypePack(TypePack{{anyType}, std::nullopt});
|
||||
else
|
||||
if (FFlag::LuauRequireCyclesDontAlwaysReturnAny)
|
||||
{
|
||||
moduleScope->returnType = freshTypePack(moduleScope);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (module.cyclic)
|
||||
moduleScope->returnType = addTypePack(TypePack{{anyType}, std::nullopt});
|
||||
else
|
||||
moduleScope->returnType = freshTypePack(moduleScope);
|
||||
}
|
||||
|
||||
moduleScope->varargPack = anyTypePack;
|
||||
|
||||
@ -2870,7 +2879,7 @@ TypeId TypeChecker::checkRelationalOperation(
|
||||
std::optional<TypeId> metamethod = findMetatableEntry(lhsType, metamethodName, expr.location, /* addErrors= */ true);
|
||||
if (metamethod)
|
||||
{
|
||||
if (const FunctionType* ftv = get<FunctionType>(*metamethod))
|
||||
if (const FunctionType* ftv = get<FunctionType>(FFlag::LuauMetatableFollow ? follow(*metamethod) : *metamethod))
|
||||
{
|
||||
if (isEquality)
|
||||
{
|
||||
|
@ -17,11 +17,11 @@
|
||||
|
||||
LUAU_FASTINT(LuauTypeInferTypePackLoopLimit)
|
||||
LUAU_FASTFLAG(LuauErrorRecoveryType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauInstantiateInSubtyping, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTransitiveSubtyping, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTransitiveSubtyping)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFixIndexerSubtypingOrdering, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUnifierRecursionOnRestart, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFixIndexerSubtypingOrdering)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUnifierRecursionOnRestart)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -217,7 +217,7 @@ private:
|
||||
AstType* parseTableType(bool inDeclarationContext = false);
|
||||
AstTypeOrPack parseSimpleType(bool allowPack, bool inDeclarationContext = false);
|
||||
|
||||
AstTypeOrPack parseTypeOrPack();
|
||||
AstTypeOrPack parseSimpleTypeOrPack();
|
||||
AstType* parseType(bool inDeclarationContext = false);
|
||||
|
||||
AstTypePack* parseTypePack();
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
LUAU_FASTINTVARIABLE(LuauRecursionLimit, 1000)
|
||||
LUAU_FASTINTVARIABLE(LuauTypeLengthLimit, 1000)
|
||||
@ -16,11 +17,12 @@ LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100)
|
||||
// Warning: If you are introducing new syntax, ensure that it is behind a separate
|
||||
// flag so that we don't break production games by reverting syntax changes.
|
||||
// See docs/SyntaxChanges.md for an explanation.
|
||||
LUAU_FASTFLAGVARIABLE(LuauSolverV2, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNativeAttribute, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAttributeSyntaxFunExpr, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctionsSyntax2, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAllowFragmentParsing, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSolverV2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNativeAttribute)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAttributeSyntaxFunExpr)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctionsSyntax2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAllowFragmentParsing)
|
||||
LUAU_FASTFLAGVARIABLE(LuauPortableStringZeroCheck)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
@ -1131,7 +1133,8 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
|
||||
AstType* type = parseType();
|
||||
|
||||
// since AstName contains a char*, it can't contain null
|
||||
bool containsNull = chars && (strnlen(chars->data, chars->size) < chars->size);
|
||||
bool containsNull = chars && (FFlag::LuauPortableStringZeroCheck ? memchr(chars->data, 0, chars->size) != nullptr
|
||||
: strnlen(chars->data, chars->size) < chars->size);
|
||||
|
||||
if (chars && !containsNull)
|
||||
{
|
||||
@ -1609,7 +1612,8 @@ AstType* Parser::parseTableType(bool inDeclarationContext)
|
||||
AstType* type = parseType();
|
||||
|
||||
// since AstName contains a char*, it can't contain null
|
||||
bool containsNull = chars && (strnlen(chars->data, chars->size) < chars->size);
|
||||
bool containsNull = chars && (FFlag::LuauPortableStringZeroCheck ? memchr(chars->data, 0, chars->size) != nullptr
|
||||
: strnlen(chars->data, chars->size) < chars->size);
|
||||
|
||||
if (chars && !containsNull)
|
||||
props.push_back(AstTableProp{AstName(chars->data), begin.location, type, access, accessLocation});
|
||||
@ -1858,7 +1862,7 @@ AstType* Parser::parseTypeSuffix(AstType* type, const Location& begin)
|
||||
ParseError::raise(begin, "Composite type was not an intersection or union.");
|
||||
}
|
||||
|
||||
AstTypeOrPack Parser::parseTypeOrPack()
|
||||
AstTypeOrPack Parser::parseSimpleTypeOrPack()
|
||||
{
|
||||
unsigned int oldRecursionCount = recursionCounter;
|
||||
// recursion counter is incremented in parseSimpleType
|
||||
@ -2873,7 +2877,7 @@ std::pair<AstArray<AstGenericType>, AstArray<AstGenericTypePack>> Parser::parseG
|
||||
}
|
||||
else
|
||||
{
|
||||
auto [type, typePack] = parseTypeOrPack();
|
||||
auto [type, typePack] = parseSimpleTypeOrPack();
|
||||
|
||||
if (type)
|
||||
report(type->location, "Expected type pack after '=', got type");
|
||||
@ -2950,7 +2954,7 @@ AstArray<AstTypeOrPack> Parser::parseTypeParams()
|
||||
}
|
||||
else if (lexer.current().type == '(')
|
||||
{
|
||||
auto [type, typePack] = parseTypeOrPack();
|
||||
auto [type, typePack] = parseSimpleTypeOrPack();
|
||||
|
||||
if (typePack)
|
||||
parameters.push_back({{}, typePack});
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
#include <time.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauTimeTracing, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauTimeTracing)
|
||||
namespace Luau
|
||||
{
|
||||
namespace TimeTrace
|
||||
|
@ -515,6 +515,40 @@ static void applyBuiltinCall(int bfid, BytecodeTypes& types)
|
||||
types.a = LBC_TYPE_TABLE;
|
||||
types.b = LBC_TYPE_TABLE;
|
||||
break;
|
||||
case LBF_VECTOR_MAGNITUDE:
|
||||
types.result = LBC_TYPE_NUMBER;
|
||||
types.a = LBC_TYPE_VECTOR;
|
||||
break;
|
||||
case LBF_VECTOR_NORMALIZE:
|
||||
types.result = LBC_TYPE_VECTOR;
|
||||
types.a = LBC_TYPE_VECTOR;
|
||||
break;
|
||||
case LBF_VECTOR_CROSS:
|
||||
types.result = LBC_TYPE_VECTOR;
|
||||
types.a = LBC_TYPE_VECTOR;
|
||||
types.b = LBC_TYPE_VECTOR;
|
||||
break;
|
||||
case LBF_VECTOR_DOT:
|
||||
types.result = LBC_TYPE_NUMBER;
|
||||
types.a = LBC_TYPE_VECTOR;
|
||||
types.b = LBC_TYPE_VECTOR;
|
||||
break;
|
||||
case LBF_VECTOR_FLOOR:
|
||||
case LBF_VECTOR_CEIL:
|
||||
case LBF_VECTOR_ABS:
|
||||
case LBF_VECTOR_SIGN:
|
||||
case LBF_VECTOR_CLAMP:
|
||||
types.result = LBC_TYPE_VECTOR;
|
||||
types.a = LBC_TYPE_VECTOR;
|
||||
types.b = LBC_TYPE_VECTOR;
|
||||
break;
|
||||
case LBF_VECTOR_MIN:
|
||||
case LBF_VECTOR_MAX:
|
||||
types.result = LBC_TYPE_VECTOR;
|
||||
types.a = LBC_TYPE_VECTOR;
|
||||
types.b = LBC_TYPE_VECTOR;
|
||||
types.c = LBC_TYPE_VECTOR; // We can mark optional arguments
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,9 +41,9 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugCodegenNoOpt, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugCodegenOptSize, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugCodegenSkipNumbering, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugCodegenNoOpt)
|
||||
LUAU_FASTFLAGVARIABLE(DebugCodegenOptSize)
|
||||
LUAU_FASTFLAGVARIABLE(DebugCodegenSkipNumbering)
|
||||
|
||||
// Per-module IR instruction count limit
|
||||
LUAU_FASTINTVARIABLE(CodegenHeuristicsInstructionLimit, 1'048'576) // 1 M
|
||||
|
@ -226,9 +226,10 @@ Udata* newUserdata(lua_State* L, size_t s, int tag)
|
||||
|
||||
if (Table* h = L->global->udatamt[tag])
|
||||
{
|
||||
u->metatable = h;
|
||||
// currently, we always allocate unmarked objects, so forward barrier can be skipped
|
||||
LUAU_ASSERT(!isblack(obj2gco(u)));
|
||||
|
||||
luaC_objbarrier(L, u, h);
|
||||
u->metatable = h;
|
||||
}
|
||||
|
||||
return u;
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugCodegenChaosA64, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugCodegenChaosA64)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -13,6 +13,8 @@
|
||||
static const int kMinMaxUnrolledParams = 5;
|
||||
static const int kBit32BinaryOpUnrolledParams = 5;
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauVectorLibNativeCodegen);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
@ -885,6 +887,300 @@ static BuiltinImplResult translateBuiltinBufferWrite(
|
||||
return {BuiltinImplType::Full, 0};
|
||||
}
|
||||
|
||||
static BuiltinImplResult translateBuiltinVectorMagnitude(
|
||||
IrBuilder& build,
|
||||
int nparams,
|
||||
int ra,
|
||||
int arg,
|
||||
IrOp args,
|
||||
IrOp arg3,
|
||||
int nresults,
|
||||
int pcpos
|
||||
)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeCodegen);
|
||||
|
||||
IrOp arg1 = build.vmReg(arg);
|
||||
|
||||
if (nparams != 1 || nresults > 1 || arg1.kind == IrOpKind::Constant)
|
||||
return {BuiltinImplType::None, -1};
|
||||
|
||||
build.loadAndCheckTag(arg1, LUA_TVECTOR, build.vmExit(pcpos));
|
||||
|
||||
IrOp x = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(0));
|
||||
IrOp y = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(4));
|
||||
IrOp z = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(8));
|
||||
|
||||
IrOp x2 = build.inst(IrCmd::MUL_NUM, x, x);
|
||||
IrOp y2 = build.inst(IrCmd::MUL_NUM, y, y);
|
||||
IrOp z2 = build.inst(IrCmd::MUL_NUM, z, z);
|
||||
|
||||
IrOp sum = build.inst(IrCmd::ADD_NUM, build.inst(IrCmd::ADD_NUM, x2, y2), z2);
|
||||
|
||||
IrOp mag = build.inst(IrCmd::SQRT_NUM, sum);
|
||||
|
||||
build.inst(IrCmd::STORE_DOUBLE, build.vmReg(ra), mag);
|
||||
build.inst(IrCmd::STORE_TAG, build.vmReg(ra), build.constTag(LUA_TNUMBER));
|
||||
|
||||
return {BuiltinImplType::Full, 1};
|
||||
}
|
||||
|
||||
static BuiltinImplResult translateBuiltinVectorNormalize(
|
||||
IrBuilder& build,
|
||||
int nparams,
|
||||
int ra,
|
||||
int arg,
|
||||
IrOp args,
|
||||
IrOp arg3,
|
||||
int nresults,
|
||||
int pcpos
|
||||
)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeCodegen);
|
||||
|
||||
IrOp arg1 = build.vmReg(arg);
|
||||
|
||||
if (nparams != 1 || nresults > 1 || arg1.kind == IrOpKind::Constant)
|
||||
return {BuiltinImplType::None, -1};
|
||||
|
||||
build.loadAndCheckTag(arg1, LUA_TVECTOR, build.vmExit(pcpos));
|
||||
|
||||
IrOp x = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(0));
|
||||
IrOp y = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(4));
|
||||
IrOp z = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(8));
|
||||
|
||||
IrOp x2 = build.inst(IrCmd::MUL_NUM, x, x);
|
||||
IrOp y2 = build.inst(IrCmd::MUL_NUM, y, y);
|
||||
IrOp z2 = build.inst(IrCmd::MUL_NUM, z, z);
|
||||
|
||||
IrOp sum = build.inst(IrCmd::ADD_NUM, build.inst(IrCmd::ADD_NUM, x2, y2), z2);
|
||||
|
||||
IrOp mag = build.inst(IrCmd::SQRT_NUM, sum);
|
||||
IrOp inv = build.inst(IrCmd::DIV_NUM, build.constDouble(1.0), mag);
|
||||
|
||||
IrOp xr = build.inst(IrCmd::MUL_NUM, x, inv);
|
||||
IrOp yr = build.inst(IrCmd::MUL_NUM, y, inv);
|
||||
IrOp zr = build.inst(IrCmd::MUL_NUM, z, inv);
|
||||
|
||||
build.inst(IrCmd::STORE_VECTOR, build.vmReg(ra), xr, yr, zr);
|
||||
build.inst(IrCmd::STORE_TAG, build.vmReg(ra), build.constTag(LUA_TVECTOR));
|
||||
|
||||
return {BuiltinImplType::Full, 1};
|
||||
}
|
||||
|
||||
static BuiltinImplResult translateBuiltinVectorCross(IrBuilder& build, int nparams, int ra, int arg, IrOp args, IrOp arg3, int nresults, int pcpos)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeCodegen);
|
||||
|
||||
IrOp arg1 = build.vmReg(arg);
|
||||
|
||||
if (nparams != 2 || nresults > 1 || arg1.kind == IrOpKind::Constant || args.kind == IrOpKind::Constant)
|
||||
return {BuiltinImplType::None, -1};
|
||||
|
||||
build.loadAndCheckTag(arg1, LUA_TVECTOR, build.vmExit(pcpos));
|
||||
build.loadAndCheckTag(args, LUA_TVECTOR, build.vmExit(pcpos));
|
||||
|
||||
IrOp x1 = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(0));
|
||||
IrOp x2 = build.inst(IrCmd::LOAD_FLOAT, args, build.constInt(0));
|
||||
|
||||
IrOp y1 = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(4));
|
||||
IrOp y2 = build.inst(IrCmd::LOAD_FLOAT, args, build.constInt(4));
|
||||
|
||||
IrOp z1 = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(8));
|
||||
IrOp z2 = build.inst(IrCmd::LOAD_FLOAT, args, build.constInt(8));
|
||||
|
||||
IrOp y1z2 = build.inst(IrCmd::MUL_NUM, y1, z2);
|
||||
IrOp z1y2 = build.inst(IrCmd::MUL_NUM, z1, y2);
|
||||
IrOp xr = build.inst(IrCmd::SUB_NUM, y1z2, z1y2);
|
||||
|
||||
IrOp z1x2 = build.inst(IrCmd::MUL_NUM, z1, x2);
|
||||
IrOp x1z2 = build.inst(IrCmd::MUL_NUM, x1, z2);
|
||||
IrOp yr = build.inst(IrCmd::SUB_NUM, z1x2, x1z2);
|
||||
|
||||
IrOp x1y2 = build.inst(IrCmd::MUL_NUM, x1, y2);
|
||||
IrOp y1x2 = build.inst(IrCmd::MUL_NUM, y1, x2);
|
||||
IrOp zr = build.inst(IrCmd::SUB_NUM, x1y2, y1x2);
|
||||
|
||||
build.inst(IrCmd::STORE_VECTOR, build.vmReg(ra), xr, yr, zr);
|
||||
build.inst(IrCmd::STORE_TAG, build.vmReg(ra), build.constTag(LUA_TVECTOR));
|
||||
|
||||
return {BuiltinImplType::Full, 1};
|
||||
}
|
||||
|
||||
static BuiltinImplResult translateBuiltinVectorDot(IrBuilder& build, int nparams, int ra, int arg, IrOp args, IrOp arg3, int nresults, int pcpos)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeCodegen);
|
||||
|
||||
IrOp arg1 = build.vmReg(arg);
|
||||
|
||||
if (nparams != 2 || nresults > 1 || arg1.kind == IrOpKind::Constant || args.kind == IrOpKind::Constant)
|
||||
return {BuiltinImplType::None, -1};
|
||||
|
||||
build.loadAndCheckTag(arg1, LUA_TVECTOR, build.vmExit(pcpos));
|
||||
build.loadAndCheckTag(args, LUA_TVECTOR, build.vmExit(pcpos));
|
||||
|
||||
IrOp x1 = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(0));
|
||||
IrOp x2 = build.inst(IrCmd::LOAD_FLOAT, args, build.constInt(0));
|
||||
IrOp xx = build.inst(IrCmd::MUL_NUM, x1, x2);
|
||||
|
||||
IrOp y1 = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(4));
|
||||
IrOp y2 = build.inst(IrCmd::LOAD_FLOAT, args, build.constInt(4));
|
||||
IrOp yy = build.inst(IrCmd::MUL_NUM, y1, y2);
|
||||
|
||||
IrOp z1 = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(8));
|
||||
IrOp z2 = build.inst(IrCmd::LOAD_FLOAT, args, build.constInt(8));
|
||||
IrOp zz = build.inst(IrCmd::MUL_NUM, z1, z2);
|
||||
|
||||
IrOp sum = build.inst(IrCmd::ADD_NUM, build.inst(IrCmd::ADD_NUM, xx, yy), zz);
|
||||
|
||||
build.inst(IrCmd::STORE_DOUBLE, build.vmReg(ra), sum);
|
||||
build.inst(IrCmd::STORE_TAG, build.vmReg(ra), build.constTag(LUA_TNUMBER));
|
||||
|
||||
return {BuiltinImplType::Full, 1};
|
||||
}
|
||||
|
||||
static BuiltinImplResult translateBuiltinVectorMap1(
|
||||
IrBuilder& build,
|
||||
IrCmd cmd,
|
||||
int nparams,
|
||||
int ra,
|
||||
int arg,
|
||||
IrOp args,
|
||||
IrOp arg3,
|
||||
int nresults,
|
||||
int pcpos
|
||||
)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeCodegen);
|
||||
|
||||
IrOp arg1 = build.vmReg(arg);
|
||||
|
||||
if (nparams != 1 || nresults > 1 || arg1.kind == IrOpKind::Constant)
|
||||
return {BuiltinImplType::None, -1};
|
||||
|
||||
build.loadAndCheckTag(arg1, LUA_TVECTOR, build.vmExit(pcpos));
|
||||
|
||||
IrOp x1 = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(0));
|
||||
IrOp y1 = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(4));
|
||||
IrOp z1 = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(8));
|
||||
|
||||
IrOp xr = build.inst(cmd, x1);
|
||||
IrOp yr = build.inst(cmd, y1);
|
||||
IrOp zr = build.inst(cmd, z1);
|
||||
|
||||
build.inst(IrCmd::STORE_VECTOR, build.vmReg(ra), xr, yr, zr);
|
||||
build.inst(IrCmd::STORE_TAG, build.vmReg(ra), build.constTag(LUA_TVECTOR));
|
||||
|
||||
return {BuiltinImplType::Full, 1};
|
||||
}
|
||||
|
||||
static BuiltinImplResult translateBuiltinVectorClamp(
|
||||
IrBuilder& build,
|
||||
int nparams,
|
||||
int ra,
|
||||
int arg,
|
||||
IrOp args,
|
||||
IrOp arg3,
|
||||
int nresults,
|
||||
IrOp fallback,
|
||||
int pcpos
|
||||
)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeCodegen);
|
||||
|
||||
IrOp arg1 = build.vmReg(arg);
|
||||
|
||||
if (nparams != 3 || nresults > 1 || arg1.kind == IrOpKind::Constant || args.kind == IrOpKind::Constant || arg3.kind == IrOpKind::Constant)
|
||||
return {BuiltinImplType::None, -1};
|
||||
|
||||
build.loadAndCheckTag(arg1, LUA_TVECTOR, build.vmExit(pcpos));
|
||||
build.loadAndCheckTag(args, LUA_TVECTOR, build.vmExit(pcpos));
|
||||
build.loadAndCheckTag(arg3, LUA_TVECTOR, build.vmExit(pcpos));
|
||||
|
||||
IrOp block1 = build.block(IrBlockKind::Internal);
|
||||
IrOp block2 = build.block(IrBlockKind::Internal);
|
||||
IrOp block3 = build.block(IrBlockKind::Internal);
|
||||
|
||||
IrOp x = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(0));
|
||||
IrOp xmin = build.inst(IrCmd::LOAD_FLOAT, args, build.constInt(0));
|
||||
IrOp xmax = build.inst(IrCmd::LOAD_FLOAT, arg3, build.constInt(0));
|
||||
|
||||
build.inst(IrCmd::JUMP_CMP_NUM, xmin, xmax, build.cond(IrCondition::NotLessEqual), fallback, block1);
|
||||
|
||||
build.beginBlock(block1);
|
||||
|
||||
IrOp y = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(4));
|
||||
IrOp ymin = build.inst(IrCmd::LOAD_FLOAT, args, build.constInt(4));
|
||||
IrOp ymax = build.inst(IrCmd::LOAD_FLOAT, arg3, build.constInt(4));
|
||||
|
||||
build.inst(IrCmd::JUMP_CMP_NUM, ymin, ymax, build.cond(IrCondition::NotLessEqual), fallback, block2);
|
||||
|
||||
build.beginBlock(block2);
|
||||
|
||||
IrOp z = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(8));
|
||||
IrOp zmin = build.inst(IrCmd::LOAD_FLOAT, args, build.constInt(8));
|
||||
IrOp zmax = build.inst(IrCmd::LOAD_FLOAT, arg3, build.constInt(8));
|
||||
|
||||
build.inst(IrCmd::JUMP_CMP_NUM, zmin, zmax, build.cond(IrCondition::NotLessEqual), fallback, block3);
|
||||
|
||||
build.beginBlock(block3);
|
||||
|
||||
IrOp xtemp = build.inst(IrCmd::MAX_NUM, xmin, x);
|
||||
IrOp xclamped = build.inst(IrCmd::MIN_NUM, xmax, xtemp);
|
||||
|
||||
IrOp ytemp = build.inst(IrCmd::MAX_NUM, ymin, y);
|
||||
IrOp yclamped = build.inst(IrCmd::MIN_NUM, ymax, ytemp);
|
||||
|
||||
IrOp ztemp = build.inst(IrCmd::MAX_NUM, zmin, z);
|
||||
IrOp zclamped = build.inst(IrCmd::MIN_NUM, zmax, ztemp);
|
||||
|
||||
build.inst(IrCmd::STORE_VECTOR, build.vmReg(ra), xclamped, yclamped, zclamped);
|
||||
build.inst(IrCmd::STORE_TAG, build.vmReg(ra), build.constTag(LUA_TVECTOR));
|
||||
|
||||
return {BuiltinImplType::UsesFallback, 1};
|
||||
}
|
||||
|
||||
static BuiltinImplResult translateBuiltinVectorMap2(
|
||||
IrBuilder& build,
|
||||
IrCmd cmd,
|
||||
int nparams,
|
||||
int ra,
|
||||
int arg,
|
||||
IrOp args,
|
||||
IrOp arg3,
|
||||
int nresults,
|
||||
int pcpos
|
||||
)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeCodegen);
|
||||
|
||||
IrOp arg1 = build.vmReg(arg);
|
||||
|
||||
if (nparams != 2 || nresults > 1 || arg1.kind == IrOpKind::Constant || args.kind == IrOpKind::Constant)
|
||||
return {BuiltinImplType::None, -1};
|
||||
|
||||
build.loadAndCheckTag(arg1, LUA_TVECTOR, build.vmExit(pcpos));
|
||||
build.loadAndCheckTag(args, LUA_TVECTOR, build.vmExit(pcpos));
|
||||
|
||||
IrOp x1 = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(0));
|
||||
IrOp y1 = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(4));
|
||||
IrOp z1 = build.inst(IrCmd::LOAD_FLOAT, arg1, build.constInt(8));
|
||||
|
||||
IrOp x2 = build.inst(IrCmd::LOAD_FLOAT, args, build.constInt(0));
|
||||
IrOp y2 = build.inst(IrCmd::LOAD_FLOAT, args, build.constInt(4));
|
||||
IrOp z2 = build.inst(IrCmd::LOAD_FLOAT, args, build.constInt(8));
|
||||
|
||||
IrOp xr = build.inst(cmd, x1, x2);
|
||||
IrOp yr = build.inst(cmd, y1, y2);
|
||||
IrOp zr = build.inst(cmd, z1, z2);
|
||||
|
||||
build.inst(IrCmd::STORE_VECTOR, build.vmReg(ra), xr, yr, zr);
|
||||
build.inst(IrCmd::STORE_TAG, build.vmReg(ra), build.constTag(LUA_TVECTOR));
|
||||
|
||||
return {BuiltinImplType::Full, 1};
|
||||
}
|
||||
|
||||
|
||||
BuiltinImplResult translateBuiltin(
|
||||
IrBuilder& build,
|
||||
int bfid,
|
||||
@ -898,6 +1194,8 @@ BuiltinImplResult translateBuiltin(
|
||||
int pcpos
|
||||
)
|
||||
{
|
||||
BuiltinImplResult noneResult = {BuiltinImplType::None, -1};
|
||||
|
||||
// Builtins are not allowed to handle variadic arguments
|
||||
if (nparams == LUA_MULTRET)
|
||||
return {BuiltinImplType::None, -1};
|
||||
@ -1018,6 +1316,35 @@ BuiltinImplResult translateBuiltin(
|
||||
return translateBuiltinBufferRead(build, nparams, ra, arg, args, arg3, nresults, pcpos, IrCmd::BUFFER_READF64, 8, IrCmd::NOP);
|
||||
case LBF_BUFFER_WRITEF64:
|
||||
return translateBuiltinBufferWrite(build, nparams, ra, arg, args, arg3, nresults, pcpos, IrCmd::BUFFER_WRITEF64, 8, IrCmd::NOP);
|
||||
case LBF_VECTOR_MAGNITUDE:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorMagnitude(build, nparams, ra, arg, args, arg3, nresults, pcpos) : noneResult;
|
||||
case LBF_VECTOR_NORMALIZE:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorNormalize(build, nparams, ra, arg, args, arg3, nresults, pcpos) : noneResult;
|
||||
case LBF_VECTOR_CROSS:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorCross(build, nparams, ra, arg, args, arg3, nresults, pcpos) : noneResult;
|
||||
case LBF_VECTOR_DOT:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorDot(build, nparams, ra, arg, args, arg3, nresults, pcpos) : noneResult;
|
||||
case LBF_VECTOR_FLOOR:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorMap1(build, IrCmd::FLOOR_NUM, nparams, ra, arg, args, arg3, nresults, pcpos)
|
||||
: noneResult;
|
||||
case LBF_VECTOR_CEIL:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorMap1(build, IrCmd::CEIL_NUM, nparams, ra, arg, args, arg3, nresults, pcpos)
|
||||
: noneResult;
|
||||
case LBF_VECTOR_ABS:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorMap1(build, IrCmd::ABS_NUM, nparams, ra, arg, args, arg3, nresults, pcpos)
|
||||
: noneResult;
|
||||
case LBF_VECTOR_SIGN:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorMap1(build, IrCmd::SIGN_NUM, nparams, ra, arg, args, arg3, nresults, pcpos)
|
||||
: noneResult;
|
||||
case LBF_VECTOR_CLAMP:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorClamp(build, nparams, ra, arg, args, arg3, nresults, fallback, pcpos)
|
||||
: noneResult;
|
||||
case LBF_VECTOR_MIN:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorMap2(build, IrCmd::MIN_NUM, nparams, ra, arg, args, arg3, nresults, pcpos)
|
||||
: noneResult;
|
||||
case LBF_VECTOR_MAX:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorMap2(build, IrCmd::MAX_NUM, nparams, ra, arg, args, arg3, nresults, pcpos)
|
||||
: noneResult;
|
||||
default:
|
||||
return {BuiltinImplType::None, -1};
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
LUAU_FASTINTVARIABLE(LuauCodeGenMinLinearBlockPath, 3)
|
||||
LUAU_FASTINTVARIABLE(LuauCodeGenReuseSlotLimit, 64)
|
||||
LUAU_FASTINTVARIABLE(LuauCodeGenReuseUdataTagLimit, 64)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauAbortingChecks, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauAbortingChecks)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
@ -536,6 +536,17 @@ static void handleBuiltinEffects(ConstPropState& state, LuauBuiltinFunction bfid
|
||||
case LBF_BUFFER_WRITEF32:
|
||||
case LBF_BUFFER_READF64:
|
||||
case LBF_BUFFER_WRITEF64:
|
||||
case LBF_VECTOR_MAGNITUDE:
|
||||
case LBF_VECTOR_NORMALIZE:
|
||||
case LBF_VECTOR_CROSS:
|
||||
case LBF_VECTOR_DOT:
|
||||
case LBF_VECTOR_FLOOR:
|
||||
case LBF_VECTOR_CEIL:
|
||||
case LBF_VECTOR_ABS:
|
||||
case LBF_VECTOR_SIGN:
|
||||
case LBF_VECTOR_CLAMP:
|
||||
case LBF_VECTOR_MIN:
|
||||
case LBF_VECTOR_MAX:
|
||||
break;
|
||||
case LBF_TABLE_INSERT:
|
||||
state.invalidateHeap();
|
||||
|
@ -600,6 +600,19 @@ enum LuauBuiltinFunction
|
||||
LBF_BUFFER_WRITEF32,
|
||||
LBF_BUFFER_READF64,
|
||||
LBF_BUFFER_WRITEF64,
|
||||
|
||||
// vector.
|
||||
LBF_VECTOR_MAGNITUDE,
|
||||
LBF_VECTOR_NORMALIZE,
|
||||
LBF_VECTOR_CROSS,
|
||||
LBF_VECTOR_DOT,
|
||||
LBF_VECTOR_FLOOR,
|
||||
LBF_VECTOR_CEIL,
|
||||
LBF_VECTOR_ABS,
|
||||
LBF_VECTOR_SIGN,
|
||||
LBF_VECTOR_CLAMP,
|
||||
LBF_VECTOR_MIN,
|
||||
LBF_VECTOR_MAX,
|
||||
};
|
||||
|
||||
// Capture type, used in LOP_CAPTURE
|
||||
|
@ -106,10 +106,10 @@ FValue<T>* FValue<T>::list = nullptr;
|
||||
{ \
|
||||
extern Luau::FValue<bool> flag; \
|
||||
}
|
||||
#define LUAU_FASTFLAGVARIABLE(flag, def) \
|
||||
#define LUAU_FASTFLAGVARIABLE(flag) \
|
||||
namespace FFlag \
|
||||
{ \
|
||||
Luau::FValue<bool> flag(#flag, def, false); \
|
||||
Luau::FValue<bool> flag(#flag, false, false); \
|
||||
}
|
||||
#define LUAU_FASTINT(flag) \
|
||||
namespace FInt \
|
||||
|
@ -37,11 +37,11 @@ struct CompileOptions
|
||||
// 2 - statement and expression coverage (verbose)
|
||||
int coverageLevel = 0;
|
||||
|
||||
// global builtin to construct vectors; disabled by default
|
||||
// alternative global builtin to construct vectors, in addition to default builtin 'vector.create'
|
||||
const char* vectorLib = nullptr;
|
||||
const char* vectorCtor = nullptr;
|
||||
|
||||
// vector type name for type tables; disabled by default
|
||||
// alternative vector type name for type tables, in addition to default type 'vector'
|
||||
const char* vectorType = nullptr;
|
||||
|
||||
// null-terminated array of globals that are mutable; disables the import optimization for fields accessed through these
|
||||
|
@ -33,11 +33,11 @@ struct lua_CompileOptions
|
||||
// 2 - statement and expression coverage (verbose)
|
||||
int coverageLevel; // default=0
|
||||
|
||||
// global builtin to construct vectors; disabled by default
|
||||
// alternative global builtin to construct vectors, in addition to default builtin 'vector.create'
|
||||
const char* vectorLib;
|
||||
const char* vectorCtor;
|
||||
|
||||
// vector type name for type tables; disabled by default
|
||||
// alternative vector type name for type tables, in addition to default type 'vector'
|
||||
const char* vectorType;
|
||||
|
||||
// null-terminated array of globals that are mutable; disables the import optimization for fields accessed through these
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include "Luau/Bytecode.h"
|
||||
#include "Luau/Compiler.h"
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauVectorBuiltins)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace Compile
|
||||
@ -220,6 +222,34 @@ static int getBuiltinFunctionId(const Builtin& builtin, const CompileOptions& op
|
||||
return LBF_BUFFER_WRITEF64;
|
||||
}
|
||||
|
||||
if (FFlag::LuauVectorBuiltins && builtin.object == "vector")
|
||||
{
|
||||
if (builtin.method == "create")
|
||||
return LBF_VECTOR;
|
||||
if (builtin.method == "magnitude")
|
||||
return LBF_VECTOR_MAGNITUDE;
|
||||
if (builtin.method == "normalize")
|
||||
return LBF_VECTOR_NORMALIZE;
|
||||
if (builtin.method == "cross")
|
||||
return LBF_VECTOR_CROSS;
|
||||
if (builtin.method == "dot")
|
||||
return LBF_VECTOR_DOT;
|
||||
if (builtin.method == "floor")
|
||||
return LBF_VECTOR_FLOOR;
|
||||
if (builtin.method == "ceil")
|
||||
return LBF_VECTOR_CEIL;
|
||||
if (builtin.method == "abs")
|
||||
return LBF_VECTOR_ABS;
|
||||
if (builtin.method == "sign")
|
||||
return LBF_VECTOR_SIGN;
|
||||
if (builtin.method == "clamp")
|
||||
return LBF_VECTOR_CLAMP;
|
||||
if (builtin.method == "min")
|
||||
return LBF_VECTOR_MIN;
|
||||
if (builtin.method == "max")
|
||||
return LBF_VECTOR_MAX;
|
||||
}
|
||||
|
||||
if (options.vectorCtor)
|
||||
{
|
||||
if (options.vectorLib)
|
||||
@ -463,6 +493,23 @@ BuiltinInfo getBuiltinInfo(int bfid)
|
||||
case LBF_BUFFER_WRITEF32:
|
||||
case LBF_BUFFER_WRITEF64:
|
||||
return {3, 0, BuiltinInfo::Flag_NoneSafe};
|
||||
|
||||
case LBF_VECTOR_MAGNITUDE:
|
||||
case LBF_VECTOR_NORMALIZE:
|
||||
return {1, 1, BuiltinInfo::Flag_NoneSafe};
|
||||
case LBF_VECTOR_CROSS:
|
||||
case LBF_VECTOR_DOT:
|
||||
return {2, 1, BuiltinInfo::Flag_NoneSafe};
|
||||
case LBF_VECTOR_FLOOR:
|
||||
case LBF_VECTOR_CEIL:
|
||||
case LBF_VECTOR_ABS:
|
||||
case LBF_VECTOR_SIGN:
|
||||
return {1, 1, BuiltinInfo::Flag_NoneSafe};
|
||||
case LBF_VECTOR_CLAMP:
|
||||
return {3, 1, BuiltinInfo::Flag_NoneSafe};
|
||||
case LBF_VECTOR_MIN:
|
||||
case LBF_VECTOR_MAX:
|
||||
return {-1, 1}; // variadic
|
||||
}
|
||||
|
||||
LUAU_UNREACHABLE();
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include "Luau/BytecodeBuilder.h"
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileVectorTypeInfo)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
@ -29,6 +31,8 @@ static LuauBytecodeType getPrimitiveType(AstName name)
|
||||
return LBC_TYPE_THREAD;
|
||||
else if (name == "buffer")
|
||||
return LBC_TYPE_BUFFER;
|
||||
else if (FFlag::LuauCompileVectorTypeInfo && name == "vector")
|
||||
return LBC_TYPE_VECTOR;
|
||||
else if (name == "any" || name == "unknown")
|
||||
return LBC_TYPE_ANY;
|
||||
else
|
||||
@ -40,7 +44,7 @@ static LuauBytecodeType getType(
|
||||
const AstArray<AstGenericType>& generics,
|
||||
const DenseHashMap<AstName, AstStatTypeAlias*>& typeAliases,
|
||||
bool resolveAliases,
|
||||
const char* vectorType,
|
||||
const char* hostVectorType,
|
||||
const DenseHashMap<AstName, uint8_t>& userdataTypes,
|
||||
BytecodeBuilder& bytecode
|
||||
)
|
||||
@ -54,7 +58,7 @@ static LuauBytecodeType getType(
|
||||
{
|
||||
// note: we only resolve aliases to the depth of 1 to avoid dealing with recursive aliases
|
||||
if (resolveAliases)
|
||||
return getType((*alias)->type, (*alias)->generics, typeAliases, /* resolveAliases= */ false, vectorType, userdataTypes, bytecode);
|
||||
return getType((*alias)->type, (*alias)->generics, typeAliases, /* resolveAliases= */ false, hostVectorType, userdataTypes, bytecode);
|
||||
else
|
||||
return LBC_TYPE_ANY;
|
||||
}
|
||||
@ -62,7 +66,7 @@ static LuauBytecodeType getType(
|
||||
if (isGeneric(ref->name, generics))
|
||||
return LBC_TYPE_ANY;
|
||||
|
||||
if (vectorType && ref->name == vectorType)
|
||||
if (hostVectorType && ref->name == hostVectorType)
|
||||
return LBC_TYPE_VECTOR;
|
||||
|
||||
if (LuauBytecodeType prim = getPrimitiveType(ref->name); prim != LBC_TYPE_INVALID)
|
||||
@ -92,7 +96,7 @@ static LuauBytecodeType getType(
|
||||
|
||||
for (AstType* ty : un->types)
|
||||
{
|
||||
LuauBytecodeType et = getType(ty, generics, typeAliases, resolveAliases, vectorType, userdataTypes, bytecode);
|
||||
LuauBytecodeType et = getType(ty, generics, typeAliases, resolveAliases, hostVectorType, userdataTypes, bytecode);
|
||||
|
||||
if (et == LBC_TYPE_NIL)
|
||||
{
|
||||
@ -126,7 +130,7 @@ static LuauBytecodeType getType(
|
||||
static std::string getFunctionType(
|
||||
const AstExprFunction* func,
|
||||
const DenseHashMap<AstName, AstStatTypeAlias*>& typeAliases,
|
||||
const char* vectorType,
|
||||
const char* hostVectorType,
|
||||
const DenseHashMap<AstName, uint8_t>& userdataTypes,
|
||||
BytecodeBuilder& bytecode
|
||||
)
|
||||
@ -146,8 +150,9 @@ static std::string getFunctionType(
|
||||
for (AstLocal* arg : func->args)
|
||||
{
|
||||
LuauBytecodeType ty =
|
||||
arg->annotation ? getType(arg->annotation, func->generics, typeAliases, /* resolveAliases= */ true, vectorType, userdataTypes, bytecode)
|
||||
: LBC_TYPE_ANY;
|
||||
arg->annotation
|
||||
? getType(arg->annotation, func->generics, typeAliases, /* resolveAliases= */ true, hostVectorType, userdataTypes, bytecode)
|
||||
: LBC_TYPE_ANY;
|
||||
|
||||
if (ty != LBC_TYPE_ANY)
|
||||
haveNonAnyParam = true;
|
||||
@ -175,7 +180,7 @@ struct TypeMapVisitor : AstVisitor
|
||||
DenseHashMap<AstExprFunction*, std::string>& functionTypes;
|
||||
DenseHashMap<AstLocal*, LuauBytecodeType>& localTypes;
|
||||
DenseHashMap<AstExpr*, LuauBytecodeType>& exprTypes;
|
||||
const char* vectorType;
|
||||
const char* hostVectorType;
|
||||
const DenseHashMap<AstName, uint8_t>& userdataTypes;
|
||||
const BuiltinAstTypes& builtinTypes;
|
||||
const DenseHashMap<AstExprCall*, int>& builtinCalls;
|
||||
@ -191,7 +196,7 @@ struct TypeMapVisitor : AstVisitor
|
||||
DenseHashMap<AstExprFunction*, std::string>& functionTypes,
|
||||
DenseHashMap<AstLocal*, LuauBytecodeType>& localTypes,
|
||||
DenseHashMap<AstExpr*, LuauBytecodeType>& exprTypes,
|
||||
const char* vectorType,
|
||||
const char* hostVectorType,
|
||||
const DenseHashMap<AstName, uint8_t>& userdataTypes,
|
||||
const BuiltinAstTypes& builtinTypes,
|
||||
const DenseHashMap<AstExprCall*, int>& builtinCalls,
|
||||
@ -201,7 +206,7 @@ struct TypeMapVisitor : AstVisitor
|
||||
: functionTypes(functionTypes)
|
||||
, localTypes(localTypes)
|
||||
, exprTypes(exprTypes)
|
||||
, vectorType(vectorType)
|
||||
, hostVectorType(hostVectorType)
|
||||
, userdataTypes(userdataTypes)
|
||||
, builtinTypes(builtinTypes)
|
||||
, builtinCalls(builtinCalls)
|
||||
@ -271,7 +276,7 @@ struct TypeMapVisitor : AstVisitor
|
||||
|
||||
resolvedExprs[expr] = ty;
|
||||
|
||||
LuauBytecodeType bty = getType(ty, {}, typeAliases, /* resolveAliases= */ true, vectorType, userdataTypes, bytecode);
|
||||
LuauBytecodeType bty = getType(ty, {}, typeAliases, /* resolveAliases= */ true, hostVectorType, userdataTypes, bytecode);
|
||||
exprTypes[expr] = bty;
|
||||
return bty;
|
||||
}
|
||||
@ -282,7 +287,7 @@ struct TypeMapVisitor : AstVisitor
|
||||
|
||||
resolvedLocals[local] = ty;
|
||||
|
||||
LuauBytecodeType bty = getType(ty, {}, typeAliases, /* resolveAliases= */ true, vectorType, userdataTypes, bytecode);
|
||||
LuauBytecodeType bty = getType(ty, {}, typeAliases, /* resolveAliases= */ true, hostVectorType, userdataTypes, bytecode);
|
||||
|
||||
if (bty != LBC_TYPE_ANY)
|
||||
localTypes[local] = bty;
|
||||
@ -370,7 +375,7 @@ struct TypeMapVisitor : AstVisitor
|
||||
|
||||
bool visit(AstExprFunction* node) override
|
||||
{
|
||||
std::string type = getFunctionType(node, typeAliases, vectorType, userdataTypes, bytecode);
|
||||
std::string type = getFunctionType(node, typeAliases, hostVectorType, userdataTypes, bytecode);
|
||||
|
||||
if (!type.empty())
|
||||
functionTypes[node] = std::move(type);
|
||||
@ -675,6 +680,8 @@ struct TypeMapVisitor : AstVisitor
|
||||
case LBF_BUFFER_READU32:
|
||||
case LBF_BUFFER_READF32:
|
||||
case LBF_BUFFER_READF64:
|
||||
case LBF_VECTOR_MAGNITUDE:
|
||||
case LBF_VECTOR_DOT:
|
||||
recordResolvedType(node, &builtinTypes.numberType);
|
||||
break;
|
||||
|
||||
@ -691,6 +698,15 @@ struct TypeMapVisitor : AstVisitor
|
||||
break;
|
||||
|
||||
case LBF_VECTOR:
|
||||
case LBF_VECTOR_NORMALIZE:
|
||||
case LBF_VECTOR_CROSS:
|
||||
case LBF_VECTOR_FLOOR:
|
||||
case LBF_VECTOR_CEIL:
|
||||
case LBF_VECTOR_ABS:
|
||||
case LBF_VECTOR_SIGN:
|
||||
case LBF_VECTOR_CLAMP:
|
||||
case LBF_VECTOR_MIN:
|
||||
case LBF_VECTOR_MAX:
|
||||
recordResolvedType(node, &builtinTypes.vectorType);
|
||||
break;
|
||||
}
|
||||
@ -712,7 +728,7 @@ void buildTypeMap(
|
||||
DenseHashMap<AstLocal*, LuauBytecodeType>& localTypes,
|
||||
DenseHashMap<AstExpr*, LuauBytecodeType>& exprTypes,
|
||||
AstNode* root,
|
||||
const char* vectorType,
|
||||
const char* hostVectorType,
|
||||
const DenseHashMap<AstName, uint8_t>& userdataTypes,
|
||||
const BuiltinAstTypes& builtinTypes,
|
||||
const DenseHashMap<AstExprCall*, int>& builtinCalls,
|
||||
@ -720,7 +736,7 @@ void buildTypeMap(
|
||||
BytecodeBuilder& bytecode
|
||||
)
|
||||
{
|
||||
TypeMapVisitor visitor(functionTypes, localTypes, exprTypes, vectorType, userdataTypes, builtinTypes, builtinCalls, globals, bytecode);
|
||||
TypeMapVisitor visitor(functionTypes, localTypes, exprTypes, hostVectorType, userdataTypes, builtinTypes, builtinCalls, globals, bytecode);
|
||||
root->visit(&visitor);
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,8 @@ class BytecodeBuilder;
|
||||
|
||||
struct BuiltinAstTypes
|
||||
{
|
||||
BuiltinAstTypes(const char* vectorType)
|
||||
: vectorType{{}, std::nullopt, AstName{vectorType}, std::nullopt, {}}
|
||||
BuiltinAstTypes(const char* hostVectorType)
|
||||
: hostVectorType{{}, std::nullopt, AstName{hostVectorType}, std::nullopt, {}}
|
||||
{
|
||||
}
|
||||
|
||||
@ -23,7 +23,9 @@ struct BuiltinAstTypes
|
||||
AstTypeReference booleanType{{}, std::nullopt, AstName{"boolean"}, std::nullopt, {}};
|
||||
AstTypeReference numberType{{}, std::nullopt, AstName{"number"}, std::nullopt, {}};
|
||||
AstTypeReference stringType{{}, std::nullopt, AstName{"string"}, std::nullopt, {}};
|
||||
AstTypeReference vectorType;
|
||||
AstTypeReference vectorType{{}, std::nullopt, AstName{"vector"}, std::nullopt, {}};
|
||||
|
||||
AstTypeReference hostVectorType;
|
||||
};
|
||||
|
||||
void buildTypeMap(
|
||||
@ -31,7 +33,7 @@ void buildTypeMap(
|
||||
DenseHashMap<AstLocal*, LuauBytecodeType>& localTypes,
|
||||
DenseHashMap<AstExpr*, LuauBytecodeType>& exprTypes,
|
||||
AstNode* root,
|
||||
const char* vectorType,
|
||||
const char* hostVectorType,
|
||||
const DenseHashMap<AstName, uint8_t>& userdataTypes,
|
||||
const BuiltinAstTypes& builtinTypes,
|
||||
const DenseHashMap<AstExprCall*, int>& builtinCalls,
|
||||
|
@ -351,6 +351,7 @@ target_sources(Luau.VM PRIVATE
|
||||
VM/src/ltm.cpp
|
||||
VM/src/ludata.cpp
|
||||
VM/src/lutf8lib.cpp
|
||||
VM/src/lveclib.cpp
|
||||
VM/src/lvmexecute.cpp
|
||||
VM/src/lvmload.cpp
|
||||
VM/src/lvmutils.cpp
|
||||
|
@ -189,6 +189,7 @@ LUA_API int lua_pushthread(lua_State* L);
|
||||
|
||||
LUA_API void lua_pushlightuserdatatagged(lua_State* L, void* p, int tag);
|
||||
LUA_API void* lua_newuserdatatagged(lua_State* L, size_t sz, int tag);
|
||||
LUA_API void* lua_newuserdatataggedwithmetatable(lua_State* L, size_t sz, int tag); // metatable fetched with lua_getuserdatametatable
|
||||
LUA_API void* lua_newuserdatadtor(lua_State* L, size_t sz, void (*dtor)(void*));
|
||||
|
||||
LUA_API void* lua_newbuffer(lua_State* L, size_t sz);
|
||||
|
@ -136,6 +136,9 @@ LUALIB_API int luaopen_math(lua_State* L);
|
||||
#define LUA_DBLIBNAME "debug"
|
||||
LUALIB_API int luaopen_debug(lua_State* L);
|
||||
|
||||
#define LUA_VECLIBNAME "vector"
|
||||
LUALIB_API int luaopen_vector(lua_State* L);
|
||||
|
||||
// open all builtin libraries
|
||||
LUALIB_API void luaL_openlibs(lua_State* L);
|
||||
|
||||
|
@ -1283,6 +1283,26 @@ void* lua_newuserdatatagged(lua_State* L, size_t sz, int tag)
|
||||
return u->data;
|
||||
}
|
||||
|
||||
void* lua_newuserdatataggedwithmetatable(lua_State* L, size_t sz, int tag)
|
||||
{
|
||||
api_check(L, unsigned(tag) < LUA_UTAG_LIMIT);
|
||||
luaC_checkGC(L);
|
||||
luaC_threadbarrier(L);
|
||||
Udata* u = luaU_newudata(L, sz, tag);
|
||||
|
||||
// currently, we always allocate unmarked objects, so forward barrier can be skipped
|
||||
LUAU_ASSERT(!isblack(obj2gco(u)));
|
||||
|
||||
Table* h = L->global->udatamt[tag];
|
||||
api_check(L, h != nullptr);
|
||||
|
||||
u->metatable = h;
|
||||
|
||||
setuvalue(L, L->top, u);
|
||||
api_incr_top(L);
|
||||
return u->data;
|
||||
}
|
||||
|
||||
void* lua_newuserdatadtor(lua_State* L, size_t sz, void (*dtor)(void*))
|
||||
{
|
||||
luaC_checkGC(L);
|
||||
|
@ -1437,6 +1437,263 @@ static int luauF_writefp(lua_State* L, StkId res, TValue* arg0, int nresults, St
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int luauF_vectormagnitude(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
|
||||
{
|
||||
if (nparams >= 1 && nresults <= 1 && ttisvector(arg0))
|
||||
{
|
||||
const float* v = vvalue(arg0);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
setnvalue(res, sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]));
|
||||
#else
|
||||
setnvalue(res, sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int luauF_vectornormalize(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
|
||||
{
|
||||
if (nparams >= 1 && nresults <= 1 && ttisvector(arg0))
|
||||
{
|
||||
const float* v = vvalue(arg0);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
float invSqrt = 1.0f / sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
|
||||
|
||||
setvvalue(res, v[0] * invSqrt, v[1] * invSqrt, v[2] * invSqrt, v[3] * invSqrt);
|
||||
#else
|
||||
float invSqrt = 1.0f / sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||
|
||||
setvvalue(res, v[0] * invSqrt, v[1] * invSqrt, v[2] * invSqrt, 0.0f);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int luauF_vectorcross(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
|
||||
{
|
||||
if (nparams >= 2 && nresults <= 1 && ttisvector(arg0) && ttisvector(args))
|
||||
{
|
||||
const float* a = vvalue(arg0);
|
||||
const float* b = vvalue(args);
|
||||
|
||||
// same for 3- and 4- wide vectors
|
||||
setvvalue(res, a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int luauF_vectordot(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
|
||||
{
|
||||
if (nparams >= 2 && nresults <= 1 && ttisvector(arg0) && ttisvector(args))
|
||||
{
|
||||
const float* a = vvalue(arg0);
|
||||
const float* b = vvalue(args);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
setnvalue(res, a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]);
|
||||
#else
|
||||
setnvalue(res, a[0] * b[0] + a[1] * b[1] + a[2] * b[2]);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int luauF_vectorfloor(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
|
||||
{
|
||||
if (nparams >= 1 && nresults <= 1 && ttisvector(arg0))
|
||||
{
|
||||
const float* v = vvalue(arg0);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
setvvalue(res, floorf(v[0]), floorf(v[1]), floorf(v[2]), floorf(v[3]));
|
||||
#else
|
||||
setvvalue(res, floorf(v[0]), floorf(v[1]), floorf(v[2]), 0.0f);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int luauF_vectorceil(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
|
||||
{
|
||||
if (nparams >= 1 && nresults <= 1 && ttisvector(arg0))
|
||||
{
|
||||
const float* v = vvalue(arg0);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
setvvalue(res, ceilf(v[0]), ceilf(v[1]), ceilf(v[2]), ceilf(v[3]));
|
||||
#else
|
||||
setvvalue(res, ceilf(v[0]), ceilf(v[1]), ceilf(v[2]), 0.0f);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int luauF_vectorabs(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
|
||||
{
|
||||
if (nparams >= 1 && nresults <= 1 && ttisvector(arg0))
|
||||
{
|
||||
const float* v = vvalue(arg0);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
setvvalue(res, fabsf(v[0]), fabsf(v[1]), fabsf(v[2]), fabsf(v[3]));
|
||||
#else
|
||||
setvvalue(res, fabsf(v[0]), fabsf(v[1]), fabsf(v[2]), 0.0f);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int luauF_vectorsign(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
|
||||
{
|
||||
if (nparams >= 1 && nresults <= 1 && ttisvector(arg0))
|
||||
{
|
||||
const float* v = vvalue(arg0);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
setvvalue(res, luaui_signf(v[0]), luaui_signf(v[1]), luaui_signf(v[2]), luaui_signf(v[3]));
|
||||
#else
|
||||
setvvalue(res, luaui_signf(v[0]), luaui_signf(v[1]), luaui_signf(v[2]), 0.0f);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int luauF_vectorclamp(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
|
||||
{
|
||||
if (nparams >= 3 && nresults <= 1 && ttisvector(arg0) && ttisvector(args) && ttisvector(args + 1))
|
||||
{
|
||||
const float* v = vvalue(arg0);
|
||||
const float* min = vvalue(args);
|
||||
const float* max = vvalue(args + 1);
|
||||
|
||||
if (min[0] <= max[0] && min[1] <= max[1] && min[2] <= max[2])
|
||||
{
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
setvvalue(
|
||||
res,
|
||||
luaui_clampf(v[0], min[0], max[0]),
|
||||
luaui_clampf(v[1], min[1], max[1]),
|
||||
luaui_clampf(v[2], min[2], max[2]),
|
||||
luaui_clampf(v[3], min[3], max[3])
|
||||
);
|
||||
#else
|
||||
setvvalue(res, luaui_clampf(v[0], min[0], max[0]), luaui_clampf(v[1], min[1], max[1]), luaui_clampf(v[2], min[2], max[2]), 0.0f);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int luauF_vectormin(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
|
||||
{
|
||||
if (nparams >= 2 && nresults <= 1 && ttisvector(arg0) && ttisvector(args))
|
||||
{
|
||||
const float* a = vvalue(arg0);
|
||||
const float* b = vvalue(args);
|
||||
|
||||
float result[4];
|
||||
|
||||
result[0] = (b[0] < a[0]) ? b[0] : a[0];
|
||||
result[1] = (b[1] < a[1]) ? b[1] : a[1];
|
||||
result[2] = (b[2] < a[2]) ? b[2] : a[2];
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
result[3] = (b[3] < a[3]) ? b[3] : a[3];
|
||||
#else
|
||||
result[3] = 0.0f;
|
||||
#endif
|
||||
|
||||
for (int i = 3; i <= nparams; ++i)
|
||||
{
|
||||
if (!ttisvector(args + (i - 2)))
|
||||
return -1;
|
||||
|
||||
const float* c = vvalue(args + (i - 2));
|
||||
|
||||
result[0] = (c[0] < result[0]) ? c[0] : result[0];
|
||||
result[1] = (c[1] < result[1]) ? c[1] : result[1];
|
||||
result[2] = (c[2] < result[2]) ? c[2] : result[2];
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
result[3] = (c[3] < result[3]) ? c[3] : result[3];
|
||||
#endif
|
||||
}
|
||||
|
||||
setvvalue(res, result[0], result[1], result[2], result[3]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int luauF_vectormax(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
|
||||
{
|
||||
if (nparams >= 2 && nresults <= 1 && ttisvector(arg0) && ttisvector(args))
|
||||
{
|
||||
const float* a = vvalue(arg0);
|
||||
const float* b = vvalue(args);
|
||||
|
||||
float result[4];
|
||||
|
||||
result[0] = (b[0] > a[0]) ? b[0] : a[0];
|
||||
result[1] = (b[1] > a[1]) ? b[1] : a[1];
|
||||
result[2] = (b[2] > a[2]) ? b[2] : a[2];
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
result[3] = (b[3] > a[3]) ? b[3] : a[3];
|
||||
#else
|
||||
result[3] = 0.0f;
|
||||
#endif
|
||||
|
||||
for (int i = 3; i <= nparams; ++i)
|
||||
{
|
||||
if (!ttisvector(args + (i - 2)))
|
||||
return -1;
|
||||
|
||||
const float* c = vvalue(args + (i - 2));
|
||||
|
||||
result[0] = (c[0] > result[0]) ? c[0] : result[0];
|
||||
result[1] = (c[1] > result[1]) ? c[1] : result[1];
|
||||
result[2] = (c[2] > result[2]) ? c[2] : result[2];
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
result[3] = (c[3] > result[3]) ? c[3] : result[3];
|
||||
#endif
|
||||
}
|
||||
|
||||
setvvalue(res, result[0], result[1], result[2], result[3]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int luauF_missing(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
|
||||
{
|
||||
return -1;
|
||||
@ -1620,6 +1877,18 @@ const luau_FastFunction luauF_table[256] = {
|
||||
luauF_readfp<double>,
|
||||
luauF_writefp<double>,
|
||||
|
||||
luauF_vectormagnitude,
|
||||
luauF_vectornormalize,
|
||||
luauF_vectorcross,
|
||||
luauF_vectordot,
|
||||
luauF_vectorfloor,
|
||||
luauF_vectorceil,
|
||||
luauF_vectorabs,
|
||||
luauF_vectorsign,
|
||||
luauF_vectorclamp,
|
||||
luauF_vectormin,
|
||||
luauF_vectormax,
|
||||
|
||||
// When adding builtins, add them above this line; what follows is 64 "dummy" entries with luauF_missing fallback.
|
||||
// This is important so that older versions of the runtime that don't support newer builtins automatically fall back via luauF_missing.
|
||||
// Given the builtin addition velocity this should always provide a larger compatibility window than bytecode versions suggest.
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuauDebugInfoInvArgLeftovers, false)
|
||||
|
||||
static lua_State* getthread(lua_State* L, int* arg)
|
||||
{
|
||||
if (lua_isthread(L, 1))
|
||||
@ -107,6 +109,10 @@ static int db_info(lua_State* L)
|
||||
break;
|
||||
|
||||
default:
|
||||
// restore stack state of another thread as 'f' option might not have been visited yet
|
||||
if (DFFlag::LuauDebugInfoInvArgLeftovers && L != L1)
|
||||
lua_settop(L1, l1top);
|
||||
|
||||
luaL_argerror(L, arg + 2, "invalid option");
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ static const luaL_Reg lualibs[] = {
|
||||
{LUA_UTF8LIBNAME, luaopen_utf8},
|
||||
{LUA_BITLIBNAME, luaopen_bit32},
|
||||
{LUA_BUFFERLIBNAME, luaopen_buffer},
|
||||
{LUA_VECLIBNAME, luaopen_vector},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauMathMap, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauMathMap)
|
||||
|
||||
#undef PI
|
||||
#define PI (3.14159265358979323846)
|
||||
|
@ -33,6 +33,17 @@ inline bool luai_vecisnan(const float* a)
|
||||
#endif
|
||||
}
|
||||
|
||||
inline float luaui_signf(float v)
|
||||
{
|
||||
return v > 0.0f ? 1.0f : v < 0.0f ? -1.0f : 0.0f;
|
||||
}
|
||||
|
||||
inline float luaui_clampf(float v, float min, float max)
|
||||
{
|
||||
float r = v < min ? min : v;
|
||||
return r > max ? max : r;
|
||||
}
|
||||
|
||||
LUAU_FASTMATH_BEGIN
|
||||
inline double luai_nummod(double a, double b)
|
||||
{
|
||||
|
291
VM/src/lveclib.cpp
Normal file
291
VM/src/lveclib.cpp
Normal file
@ -0,0 +1,291 @@
|
||||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
#include "lualib.h"
|
||||
|
||||
#include "lcommon.h"
|
||||
#include "lnumutils.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
static int vector_create(lua_State* L)
|
||||
{
|
||||
double x = luaL_checknumber(L, 1);
|
||||
double y = luaL_checknumber(L, 2);
|
||||
double z = luaL_checknumber(L, 3);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
// checking argument count to avoid accepting 'nil' as a valid value
|
||||
double w = lua_gettop(L) >= 4 ? luaL_checknumber(L, 4) : 0.0;
|
||||
|
||||
lua_pushvector(L, float(x), float(y), float(z), float(w));
|
||||
#else
|
||||
lua_pushvector(L, float(x), float(y), float(z));
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vector_magnitude(lua_State* L)
|
||||
{
|
||||
const float* v = luaL_checkvector(L, 1);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushnumber(L, sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]));
|
||||
#else
|
||||
lua_pushnumber(L, sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vector_normalize(lua_State* L)
|
||||
{
|
||||
const float* v = luaL_checkvector(L, 1);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
float invSqrt = 1.0f / sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
|
||||
|
||||
lua_pushvector(L, v[0] * invSqrt, v[1] * invSqrt, v[2] * invSqrt, v[3] * invSqrt);
|
||||
#else
|
||||
float invSqrt = 1.0f / sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
||||
|
||||
lua_pushvector(L, v[0] * invSqrt, v[1] * invSqrt, v[2] * invSqrt);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vector_cross(lua_State* L)
|
||||
{
|
||||
const float* a = luaL_checkvector(L, 1);
|
||||
const float* b = luaL_checkvector(L, 2);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushvector(L, a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0f);
|
||||
#else
|
||||
lua_pushvector(L, a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vector_dot(lua_State* L)
|
||||
{
|
||||
const float* a = luaL_checkvector(L, 1);
|
||||
const float* b = luaL_checkvector(L, 2);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushnumber(L, a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]);
|
||||
#else
|
||||
lua_pushnumber(L, a[0] * b[0] + a[1] * b[1] + a[2] * b[2]);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vector_angle(lua_State* L)
|
||||
{
|
||||
const float* a = luaL_checkvector(L, 1);
|
||||
const float* b = luaL_checkvector(L, 2);
|
||||
const float* axis = luaL_optvector(L, 3, nullptr);
|
||||
|
||||
// cross(a, b)
|
||||
float cross[] = {a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]};
|
||||
|
||||
double sinA = sqrt(cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2]);
|
||||
double cosA = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
||||
double angle = atan2(sinA, cosA);
|
||||
|
||||
if (axis)
|
||||
{
|
||||
if (cross[0] * axis[0] + cross[1] * axis[1] + cross[2] * axis[2] < 0.0f)
|
||||
angle = -angle;
|
||||
}
|
||||
|
||||
lua_pushnumber(L, angle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vector_floor(lua_State* L)
|
||||
{
|
||||
const float* v = luaL_checkvector(L, 1);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushvector(L, floorf(v[0]), floorf(v[1]), floorf(v[2]), floorf(v[3]));
|
||||
#else
|
||||
lua_pushvector(L, floorf(v[0]), floorf(v[1]), floorf(v[2]));
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vector_ceil(lua_State* L)
|
||||
{
|
||||
const float* v = luaL_checkvector(L, 1);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushvector(L, ceilf(v[0]), ceilf(v[1]), ceilf(v[2]), ceilf(v[3]));
|
||||
#else
|
||||
lua_pushvector(L, ceilf(v[0]), ceilf(v[1]), ceilf(v[2]));
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vector_abs(lua_State* L)
|
||||
{
|
||||
const float* v = luaL_checkvector(L, 1);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushvector(L, fabsf(v[0]), fabsf(v[1]), fabsf(v[2]), fabsf(v[3]));
|
||||
#else
|
||||
lua_pushvector(L, fabsf(v[0]), fabsf(v[1]), fabsf(v[2]));
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vector_sign(lua_State* L)
|
||||
{
|
||||
const float* v = luaL_checkvector(L, 1);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushvector(L, luaui_signf(v[0]), luaui_signf(v[1]), luaui_signf(v[2]), luaui_signf(v[3]));
|
||||
#else
|
||||
lua_pushvector(L, luaui_signf(v[0]), luaui_signf(v[1]), luaui_signf(v[2]));
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vector_clamp(lua_State* L)
|
||||
{
|
||||
const float* v = luaL_checkvector(L, 1);
|
||||
const float* min = luaL_checkvector(L, 2);
|
||||
const float* max = luaL_checkvector(L, 3);
|
||||
|
||||
luaL_argcheck(L, min[0] <= max[0], 3, "max.x must be greater than or equal to min.x");
|
||||
luaL_argcheck(L, min[1] <= max[1], 3, "max.y must be greater than or equal to min.y");
|
||||
luaL_argcheck(L, min[2] <= max[2], 3, "max.z must be greater than or equal to min.z");
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushvector(
|
||||
L,
|
||||
luaui_clampf(v[0], min[0], max[0]),
|
||||
luaui_clampf(v[1], min[1], max[1]),
|
||||
luaui_clampf(v[2], min[2], max[2]),
|
||||
luaui_clampf(v[3], min[3], max[3])
|
||||
);
|
||||
#else
|
||||
lua_pushvector(L, luaui_clampf(v[0], min[0], max[0]), luaui_clampf(v[1], min[1], max[1]), luaui_clampf(v[2], min[2], max[2]));
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vector_min(lua_State* L)
|
||||
{
|
||||
int n = lua_gettop(L);
|
||||
const float* v = luaL_checkvector(L, 1);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
float result[] = {v[0], v[1], v[2], v[3]};
|
||||
#else
|
||||
float result[] = {v[0], v[1], v[2]};
|
||||
#endif
|
||||
|
||||
for (int i = 2; i <= n; i++)
|
||||
{
|
||||
const float* b = luaL_checkvector(L, i);
|
||||
|
||||
if (b[0] < result[0])
|
||||
result[0] = b[0];
|
||||
if (b[1] < result[1])
|
||||
result[1] = b[1];
|
||||
if (b[2] < result[2])
|
||||
result[2] = b[2];
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
if (b[3] < result[3])
|
||||
result[3] = b[3];
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushvector(L, result[0], result[1], result[2], result[3]);
|
||||
#else
|
||||
lua_pushvector(L, result[0], result[1], result[2]);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int vector_max(lua_State* L)
|
||||
{
|
||||
int n = lua_gettop(L);
|
||||
const float* v = luaL_checkvector(L, 1);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
float result[] = {v[0], v[1], v[2], v[3]};
|
||||
#else
|
||||
float result[] = {v[0], v[1], v[2]};
|
||||
#endif
|
||||
|
||||
for (int i = 2; i <= n; i++)
|
||||
{
|
||||
const float* b = luaL_checkvector(L, i);
|
||||
|
||||
if (b[0] > result[0])
|
||||
result[0] = b[0];
|
||||
if (b[1] > result[1])
|
||||
result[1] = b[1];
|
||||
if (b[2] > result[2])
|
||||
result[2] = b[2];
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
if (b[3] > result[3])
|
||||
result[3] = b[3];
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushvector(L, result[0], result[1], result[2], result[3]);
|
||||
#else
|
||||
lua_pushvector(L, result[0], result[1], result[2]);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const luaL_Reg vectorlib[] = {
|
||||
{"create", vector_create},
|
||||
{"magnitude", vector_magnitude},
|
||||
{"normalize", vector_normalize},
|
||||
{"cross", vector_cross},
|
||||
{"dot", vector_dot},
|
||||
{"angle", vector_angle},
|
||||
{"floor", vector_floor},
|
||||
{"ceil", vector_ceil},
|
||||
{"abs", vector_abs},
|
||||
{"sign", vector_sign},
|
||||
{"clamp", vector_clamp},
|
||||
{"max", vector_max},
|
||||
{"min", vector_min},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
int luaopen_vector(lua_State* L)
|
||||
{
|
||||
luaL_register(L, LUA_VECLIBNAME, vectorlib);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushvector(L, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
lua_setfield(L, -2, "zero");
|
||||
lua_pushvector(L, 1.0f, 1.0f, 1.0f, 1.0f);
|
||||
lua_setfield(L, -2, "one");
|
||||
#else
|
||||
lua_pushvector(L, 0.0f, 0.0f, 0.0f);
|
||||
lua_setfield(L, -2, "zero");
|
||||
lua_pushvector(L, 1.0f, 1.0f, 1.0f);
|
||||
lua_setfield(L, -2, "one");
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
165
bench/tests/mesh-normal-vector.lua
Normal file
165
bench/tests/mesh-normal-vector.lua
Normal file
@ -0,0 +1,165 @@
|
||||
--!strict
|
||||
local function prequire(name) local success, result = pcall(require, name); return if success then result else nil end
|
||||
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
|
||||
|
||||
function test()
|
||||
|
||||
type Vertex = { p: vector, uv: vector, n: vector, t: vector, b: vector, h: number }
|
||||
|
||||
local grid_size = 100
|
||||
|
||||
local mesh: {
|
||||
vertices: {Vertex},
|
||||
indices: {number},
|
||||
triangle_cone_p: {vector},
|
||||
triangle_cone_n: {vector}
|
||||
} = {
|
||||
vertices = table.create(grid_size * grid_size),
|
||||
indices = table.create((grid_size - 1) * (grid_size - 1) * 6),
|
||||
triangle_cone_p = table.create((grid_size - 1) * (grid_size - 1) * 2),
|
||||
triangle_cone_n = table.create((grid_size - 1) * (grid_size - 1) * 2)
|
||||
}
|
||||
|
||||
function init_vertices()
|
||||
local i = 1
|
||||
for y = 1,grid_size do
|
||||
for x = 1,grid_size do
|
||||
local v: Vertex = {}
|
||||
|
||||
v.p = vector.create(x, y, math.cos(x) + math.sin(y))
|
||||
v.uv = vector.create((x-1)/(grid_size-1), (y-1)/(grid_size-1), 0)
|
||||
v.n = vector.create(0, 0, 0)
|
||||
v.b = vector.create(0, 0, 0)
|
||||
v.t = vector.create(0, 0, 0)
|
||||
v.h = 0
|
||||
|
||||
mesh.vertices[i] = v
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function init_indices()
|
||||
local i = 1
|
||||
for y = 1,grid_size-1 do
|
||||
for x = 1,grid_size-1 do
|
||||
mesh.indices[i] = x + (y-1)*grid_size
|
||||
i += 1
|
||||
mesh.indices[i] = x + y*grid_size
|
||||
i += 1
|
||||
mesh.indices[i] = (x+1) + (y-1)*grid_size
|
||||
i += 1
|
||||
mesh.indices[i] = (x+1) + (y-1)*grid_size
|
||||
i += 1
|
||||
mesh.indices[i] = x + y*grid_size
|
||||
i += 1
|
||||
mesh.indices[i] = (x+1) + y*grid_size
|
||||
i += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function calculate_normals()
|
||||
local norm_sum = 0
|
||||
|
||||
for i = 1,#mesh.indices,3 do
|
||||
local a = mesh.vertices[mesh.indices[i]]
|
||||
local b = mesh.vertices[mesh.indices[i + 1]]
|
||||
local c = mesh.vertices[mesh.indices[i + 2]]
|
||||
|
||||
local n = vector.cross(a.p - b.p, a.p - c.p)
|
||||
|
||||
a.n += n
|
||||
b.n += n
|
||||
c.n += n
|
||||
end
|
||||
|
||||
for _,v in ipairs(mesh.vertices) do
|
||||
v.n = vector.normalize(v.n)
|
||||
|
||||
norm_sum += vector.dot(v.n, v.n)
|
||||
end
|
||||
|
||||
return norm_sum
|
||||
end
|
||||
|
||||
function compute_triangle_cones()
|
||||
local mesh_area = 0
|
||||
|
||||
local i = 1
|
||||
for i = 1,#mesh.indices,3 do
|
||||
local p0 = mesh.vertices[mesh.indices[i]]
|
||||
local p1 = mesh.vertices[mesh.indices[i + 1]]
|
||||
local p2 = mesh.vertices[mesh.indices[i + 2]]
|
||||
|
||||
local p10 = p1.p - p0.p
|
||||
local p20 = p2.p - p0.p
|
||||
|
||||
local normal = vector.cross(p10, p20)
|
||||
|
||||
local area = vector.magnitude(normal)
|
||||
local invarea = (area == 0) and 0 or 1 / area;
|
||||
|
||||
mesh.triangle_cone_p[i] = (p0.p + p1.p + p2.p) / 3
|
||||
mesh.triangle_cone_n[i] = normal * invarea
|
||||
i += 1
|
||||
|
||||
mesh_area += area
|
||||
end
|
||||
|
||||
return mesh_area
|
||||
end
|
||||
|
||||
function compute_tangent_space()
|
||||
local checksum = 0
|
||||
|
||||
for i = 1,#mesh.indices,3 do
|
||||
local a = mesh.vertices[mesh.indices[i]]
|
||||
local b = mesh.vertices[mesh.indices[i + 1]]
|
||||
local c = mesh.vertices[mesh.indices[i + 2]]
|
||||
|
||||
local vba = b.p - a.p
|
||||
local vca = c.p - a.p
|
||||
|
||||
local uvba = b.uv - a.uv
|
||||
local uvca = c.uv - a.uv
|
||||
|
||||
local r = 1.0 / (uvba.X * uvca.Y - uvca.X * uvba.Y);
|
||||
|
||||
local sdir = (uvca.Y * vba - uvba.Y * vca) * r
|
||||
local tdir = (uvba.X * vca - uvca.X * vba) * r
|
||||
|
||||
a.t += sdir
|
||||
b.t += sdir
|
||||
c.t += sdir
|
||||
|
||||
a.b += tdir
|
||||
b.b += tdir
|
||||
c.b += tdir
|
||||
end
|
||||
|
||||
for _,v in ipairs(mesh.vertices) do
|
||||
local t = v.t
|
||||
|
||||
-- Gram-Schmidt orthogonalize
|
||||
v.t = vector.normalize(t - v.n * vector.dot(v.n, t))
|
||||
|
||||
local ht = vector.dot(vector.cross(v.n, t), v.b)
|
||||
|
||||
v.h = ht < 0 and -1 or 1
|
||||
|
||||
checksum += v.t.X + v.h
|
||||
end
|
||||
|
||||
return checksum
|
||||
end
|
||||
|
||||
|
||||
init_vertices()
|
||||
init_indices()
|
||||
calculate_normals()
|
||||
compute_triangle_cones()
|
||||
compute_tangent_space()
|
||||
end
|
||||
|
||||
bench.runCode(test, "mesh-normal-vector")
|
39
bench/tests/vector-math.lua
Normal file
39
bench/tests/vector-math.lua
Normal file
@ -0,0 +1,39 @@
|
||||
local function prequire(name) local success, result = pcall(require, name); if success then return result end return nil end
|
||||
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../bench_support")
|
||||
|
||||
function fma(a: vector, b: vector, c: vector)
|
||||
return a * b + c
|
||||
end
|
||||
|
||||
function approx(a: vector): vector
|
||||
local r = vector.create(1, 1, 1)
|
||||
local aa = a
|
||||
r += aa * 0.123
|
||||
aa *= a
|
||||
r += aa * 0.123
|
||||
aa *= a
|
||||
r += aa * 0.123
|
||||
aa *= a
|
||||
r += aa * 0.123
|
||||
aa *= a
|
||||
r += aa * 0.123
|
||||
aa *= a
|
||||
r += aa * 0.123
|
||||
return r
|
||||
end
|
||||
|
||||
function test()
|
||||
local A = vector.create(1, 2, 3)
|
||||
local B = vector.create(4, 5, 6)
|
||||
local C = vector.create(7, 8, 9)
|
||||
local fma = fma
|
||||
local approx = approx
|
||||
|
||||
for i=1,100000 do
|
||||
fma(A, B, C)
|
||||
|
||||
approx(A)
|
||||
end
|
||||
end
|
||||
|
||||
bench.runCode(test, "vector math")
|
@ -209,7 +209,7 @@ TEST_SUITE_BEGIN("AstQuery");
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "last_argument_function_call_type")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
check(R"(
|
||||
local function foo() return 2 end
|
||||
|
@ -22,6 +22,7 @@ LUAU_FASTINT(LuauCompileLoopUnrollThreshold)
|
||||
LUAU_FASTINT(LuauCompileLoopUnrollThresholdMaxBoost)
|
||||
LUAU_FASTINT(LuauRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctionsSyntax2)
|
||||
LUAU_FASTFLAG(LuauCompileVectorTypeInfo)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
@ -94,6 +95,8 @@ TEST_CASE("BytecodeIsStable")
|
||||
// Note: these aren't strictly bound to specific bytecode versions, but must monotonically increase to keep backwards compat
|
||||
CHECK(LBF_VECTOR == 54);
|
||||
CHECK(LBF_TOSTRING == 63);
|
||||
CHECK(LBF_BUFFER_WRITEF64 == 77);
|
||||
CHECK(LBF_VECTOR_MAX == 88);
|
||||
|
||||
// Bytecode capture type (serialized & in-memory)
|
||||
CHECK(LCT_UPVAL == 2); // bytecode v1
|
||||
@ -8417,6 +8420,21 @@ end
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE("BuiltinTypeVector")
|
||||
{
|
||||
ScopedFastFlag luauCompileVectorTypeInfo{FFlag::LuauCompileVectorTypeInfo, true};
|
||||
|
||||
CHECK_EQ(
|
||||
"\n" + compileTypeTable(R"(
|
||||
function myfunc(test: Instance, pos: vector)
|
||||
end
|
||||
)"),
|
||||
R"(
|
||||
0: function(userdata, vector)
|
||||
)"
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE("TypeAliasScoping")
|
||||
{
|
||||
CHECK_EQ(
|
||||
|
@ -36,6 +36,9 @@ LUAU_FASTFLAG(DebugLuauAbortingChecks)
|
||||
LUAU_FASTINT(CodegenHeuristicsInstructionLimit)
|
||||
LUAU_FASTFLAG(LuauNativeAttribute)
|
||||
LUAU_DYNAMIC_FASTFLAG(LuauStackLimit)
|
||||
LUAU_FASTFLAG(LuauVectorDefinitions)
|
||||
LUAU_DYNAMIC_FASTFLAG(LuauDebugInfoInvArgLeftovers)
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeCodegen)
|
||||
|
||||
static lua_CompileOptions defaultOptions()
|
||||
{
|
||||
@ -884,6 +887,30 @@ TEST_CASE("Vector")
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE("VectorLibrary")
|
||||
{
|
||||
ScopedFastFlag luauVectorLibNativeCodegen{FFlag::LuauVectorLibNativeCodegen, true};
|
||||
|
||||
lua_CompileOptions copts = defaultOptions();
|
||||
|
||||
SUBCASE("O0")
|
||||
{
|
||||
copts.optimizationLevel = 0;
|
||||
}
|
||||
SUBCASE("O1")
|
||||
{
|
||||
copts.optimizationLevel = 1;
|
||||
}
|
||||
SUBCASE("O2")
|
||||
{
|
||||
copts.optimizationLevel = 2;
|
||||
}
|
||||
|
||||
runConformance(
|
||||
"vector_library.lua", [](lua_State* L) {}, nullptr, nullptr, &copts
|
||||
);
|
||||
}
|
||||
|
||||
static void populateRTTI(lua_State* L, Luau::TypeId type)
|
||||
{
|
||||
if (auto p = Luau::get<Luau::PrimitiveType>(type))
|
||||
@ -943,6 +970,10 @@ static void populateRTTI(lua_State* L, Luau::TypeId type)
|
||||
|
||||
lua_pushstring(L, "function");
|
||||
}
|
||||
else if (auto c = Luau::get<Luau::ClassType>(type))
|
||||
{
|
||||
lua_pushstring(L, c->name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(!"Unknown type");
|
||||
@ -951,6 +982,8 @@ static void populateRTTI(lua_State* L, Luau::TypeId type)
|
||||
|
||||
TEST_CASE("Types")
|
||||
{
|
||||
ScopedFastFlag luauVectorDefinitions{FFlag::LuauVectorDefinitions, true};
|
||||
|
||||
runConformance(
|
||||
"types.lua",
|
||||
[](lua_State* L)
|
||||
@ -982,6 +1015,8 @@ TEST_CASE("DateTime")
|
||||
|
||||
TEST_CASE("Debug")
|
||||
{
|
||||
ScopedFastFlag luauDebugInfoInvArgLeftovers{DFFlag::LuauDebugInfoInvArgLeftovers, true};
|
||||
|
||||
runConformance("debug.lua");
|
||||
}
|
||||
|
||||
@ -2196,9 +2231,7 @@ TEST_CASE("UserdataApi")
|
||||
lua_getuserdatametatable(L, 50);
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
void* ud8 = lua_newuserdatatagged(L, 16, 51);
|
||||
lua_getuserdatametatable(L, 51);
|
||||
lua_setmetatable(L, -2);
|
||||
void* ud8 = lua_newuserdatataggedwithmetatable(L, 16, 51);
|
||||
|
||||
CHECK(luaL_checkudata(L, -2, "udata3") == ud7);
|
||||
CHECK(luaL_checkudata(L, -1, "udata4") == ud8);
|
||||
|
@ -234,7 +234,7 @@ TEST_CASE_FIXTURE(DifferFixture, "right_cyclic_table_left_table_property_wrong")
|
||||
|
||||
TEST_CASE_FIXTURE(DifferFixture, "equal_table_two_cyclic_tables_are_not_different")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function id<a>(x: a): a
|
||||
@ -1473,7 +1473,7 @@ TEST_CASE_FIXTURE(DifferFixtureWithBuiltins, "equal_metatable")
|
||||
|
||||
TEST_CASE_FIXTURE(DifferFixtureWithBuiltins, "metatable_normal")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local metaFoo = {
|
||||
|
@ -28,6 +28,8 @@ LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(DebugLuauLogSolverToJsonFile)
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForceAllNewSolverTests);
|
||||
|
||||
extern std::optional<unsigned> randomSeed; // tests/main.cpp
|
||||
|
||||
namespace Luau
|
||||
|
@ -26,6 +26,12 @@
|
||||
#include <vector>
|
||||
|
||||
LUAU_FASTFLAG(DebugLuauFreezeArena)
|
||||
LUAU_FASTFLAG(DebugLuauForceAllNewSolverTests)
|
||||
|
||||
#define DOES_NOT_PASS_NEW_SOLVER_GUARD_IMPL(line) \
|
||||
ScopedFastFlag sff_##line{FFlag::LuauSolverV2, FFlag::DebugLuauForceAllNewSolverTests};
|
||||
|
||||
#define DOES_NOT_PASS_NEW_SOLVER_GUARD() DOES_NOT_PASS_NEW_SOLVER_GUARD_IMPL(__LINE__)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -12,7 +12,8 @@
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LuauRequireCyclesDontAlwaysReturnAny);
|
||||
LUAU_FASTFLAG(DebugLuauFreezeArena);
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes);
|
||||
|
||||
@ -313,6 +314,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "nocheck_cycle_used_by_checked")
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
CHECK_EQ("{ a: { hello: any }, b: { hello: any } }", toString(*cExports));
|
||||
else if (FFlag::LuauRequireCyclesDontAlwaysReturnAny)
|
||||
CHECK("{| a: any, b: any |}, {| a: {| hello: any |}, b: {| hello: any |} |}" == toString(*cExports));
|
||||
else
|
||||
CHECK_EQ("{| a: any, b: any |}", toString(*cExports));
|
||||
}
|
||||
@ -1375,7 +1378,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "checked_modules_have_the_correct_mode")
|
||||
|
||||
TEST_CASE_FIXTURE(FrontendFixture, "separate_caches_for_autocomplete")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
fileResolver.source["game/A"] = R"(
|
||||
--!nonstrict
|
||||
|
@ -110,9 +110,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
|
||||
// breaks this test. I'm not sure if that behaviour change is important or
|
||||
// not, but it's tangental to the core purpose of this test.
|
||||
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, false},
|
||||
};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local Cyclic = {}
|
||||
@ -283,7 +281,7 @@ TEST_CASE_FIXTURE(Fixture, "clone_class")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "clone_free_types")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
TypeArena arena;
|
||||
TypeId freeTy = freshType(NotNull{&arena}, builtinTypes, nullptr);
|
||||
|
@ -16,7 +16,7 @@ TEST_SUITE_BEGIN("NonstrictModeTests");
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "infer_nullary_function")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
function foo(x, y) end
|
||||
@ -39,7 +39,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_nullary_function")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "infer_the_maximum_number_of_values_the_function_could_return")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
function getMinCardCountForWidth(width)
|
||||
@ -103,7 +103,7 @@ TEST_CASE_FIXTURE(Fixture, "inconsistent_return_types_are_ok")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "locals_are_any_by_default")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
local m = 55
|
||||
@ -130,7 +130,7 @@ TEST_CASE_FIXTURE(Fixture, "parameters_having_type_any_are_optional")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "local_tables_are_not_any")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
local T = {}
|
||||
@ -148,7 +148,7 @@ TEST_CASE_FIXTURE(Fixture, "local_tables_are_not_any")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "offer_a_hint_if_you_use_a_dot_instead_of_a_colon")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
local T = {}
|
||||
@ -163,7 +163,7 @@ TEST_CASE_FIXTURE(Fixture, "offer_a_hint_if_you_use_a_dot_instead_of_a_colon")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "table_props_are_any")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
local T = {}
|
||||
@ -185,7 +185,7 @@ TEST_CASE_FIXTURE(Fixture, "table_props_are_any")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "inline_table_props_are_also_any")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
local T = {
|
||||
@ -261,7 +261,7 @@ TEST_CASE_FIXTURE(Fixture, "delay_function_does_not_require_its_argument_to_retu
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "inconsistent_module_return_types_are_ok")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
|
||||
|
@ -1191,9 +1191,7 @@ until false
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_nesting_based_end_detection_local_function")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, false},
|
||||
};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
try
|
||||
{
|
||||
@ -1228,9 +1226,7 @@ end
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_nesting_based_end_detection_failsafe_earlier")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, false},
|
||||
};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
try
|
||||
{
|
||||
@ -2628,9 +2624,7 @@ TEST_CASE_FIXTURE(Fixture, "recovery_of_parenthesized_expressions")
|
||||
}
|
||||
};
|
||||
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, false},
|
||||
};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
checkRecovery("function foo(a, b. c) return a + b end", "function foo(a, b) return a + b end", 1);
|
||||
checkRecovery(
|
||||
@ -2872,9 +2866,7 @@ TEST_CASE_FIXTURE(Fixture, "AstName_comparison")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_type_list_recovery")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, false},
|
||||
};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -45,9 +45,7 @@ TEST_SUITE_BEGIN("RuntimeLimits");
|
||||
|
||||
TEST_CASE_FIXTURE(LimitFixture, "typescript_port_of_Result_type")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, false},
|
||||
};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
constexpr const char* src = R"LUA(
|
||||
--!strict
|
||||
|
@ -322,9 +322,7 @@ n3 [label="TableType 3"];
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "free")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, false},
|
||||
};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
Type type{TypeVariant{FreeType{TypeLevel{0, 0}}}};
|
||||
|
||||
|
@ -45,7 +45,7 @@ TEST_CASE_FIXTURE(Fixture, "bound_types")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "free_types")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check("local a");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
@ -166,7 +166,7 @@ TEST_CASE_FIXTURE(Fixture, "named_metatable")
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "named_metatable_toStringNamedFunction")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function createTbl(): NamedMetatable
|
||||
@ -594,7 +594,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringDetailed")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "toStringErrorPack")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function target(callback: nil) return callback(4, "hello") end
|
||||
|
@ -13,6 +13,9 @@ LUAU_FASTFLAG(LuauUserDefinedTypeFunctions2)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctionNoEvaluation)
|
||||
LUAU_FASTFLAG(LuauUserTypeFunFixRegister)
|
||||
LUAU_FASTFLAG(LuauUserTypeFunFixNoReadWrite)
|
||||
LUAU_FASTFLAG(LuauUserTypeFunFixMetatable)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctionResetState)
|
||||
LUAU_FASTFLAG(LuauUserTypeFunNonstrict)
|
||||
|
||||
TEST_SUITE_BEGIN("UserDefinedTypeFunctionTests");
|
||||
|
||||
@ -987,6 +990,23 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_no_shared_state")
|
||||
CHECK(toString(result.errors[1]) == R"(Type function instance bar<"x"> is uninhabited)");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_math_reset")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserDefinedTypeFunctionResetState{FFlag::LuauUserDefinedTypeFunctionResetState, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function foo(x)
|
||||
return types.singleton(tostring(math.random(1, 100)))
|
||||
end
|
||||
local x: foo<'a'> = ('' :: any) :: foo<'b'>
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_optionify")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
@ -1230,4 +1250,52 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tag_field")
|
||||
CHECK(toString(result.errors[2]) == R"(Type pack '"table"' could not be converted into 'never'; at [0], "table" is not a subtype of never)");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "metatable_serialization")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserTypeFunFixRegister{FFlag::LuauUserTypeFunFixRegister, true};
|
||||
ScopedFastFlag luauUserTypeFunFixMetatable{FFlag::LuauUserTypeFunFixMetatable, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function makemttbl()
|
||||
local metaprops = {
|
||||
[types.singleton("ma")] = types.boolean
|
||||
}
|
||||
local mt = types.newtable(metaprops)
|
||||
|
||||
local props = {
|
||||
[types.singleton("a")] = types.number
|
||||
}
|
||||
return types.newtable(props, nil, mt)
|
||||
end
|
||||
|
||||
type function id(x)
|
||||
return x
|
||||
end
|
||||
|
||||
local a: number = {} :: id<makemttbl<>>
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK(toString(result.errors[0]) == R"(Type '{ @metatable { ma: boolean }, { a: number } }' could not be converted into 'number')");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "nonstrict_mode")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserTypeFunFixRegister{FFlag::LuauUserTypeFunFixRegister, true};
|
||||
ScopedFastFlag luauUserTypeFunNonstrict{FFlag::LuauUserTypeFunNonstrict, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
type function foo() return types.string end
|
||||
local a: foo<> = "a"
|
||||
)");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
@ -106,7 +106,7 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias")
|
||||
TEST_CASE_FIXTURE(Fixture, "mismatched_generic_type_param")
|
||||
{
|
||||
// We erroneously report an extra error in this case when the new solver is enabled.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type T<A> = (A...) -> ()
|
||||
@ -245,7 +245,7 @@ TEST_CASE_FIXTURE(Fixture, "dependent_generic_aliases")
|
||||
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_generic_aliases")
|
||||
{
|
||||
// CLI-116108
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -355,9 +355,7 @@ TEST_CASE_FIXTURE(Fixture, "stringify_type_alias_of_recursive_template_table_typ
|
||||
// Check that recursive intersection type doesn't generate an OOM
|
||||
TEST_CASE_FIXTURE(Fixture, "cli_38393_recursive_intersection_oom")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, false},
|
||||
}; // FIXME
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function _(l0:(t0)&((t0)&(((t0)&((t0)->()))->(typeof(_),typeof(# _)))),l39,...):any
|
||||
@ -418,7 +416,7 @@ TEST_CASE_FIXTURE(Fixture, "corecursive_function_types")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_param_remap")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
const std::string code = R"(
|
||||
-- An example of a forwarded use of a type that has different type arguments than parameters
|
||||
@ -544,7 +542,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_import_mutation")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "type_alias_local_mutation")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Cool = { a: number, b: string }
|
||||
@ -565,7 +563,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_local_mutation")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "type_alias_local_rename")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Cool = { a: number, b: string }
|
||||
@ -713,7 +711,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_ok")
|
||||
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_1")
|
||||
{
|
||||
// CLI-116108
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
-- OK because forwarded types are used with their parameters.
|
||||
@ -727,7 +725,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_1")
|
||||
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_restriction_not_ok_2")
|
||||
{
|
||||
// CLI-116108
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
-- Not OK because forwarded types are used with different types than their parameters.
|
||||
@ -751,7 +749,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_swapsies_ok")
|
||||
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_swapsies_not_ok")
|
||||
{
|
||||
// CLI-116108
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Tree1<T,U> = { data: T, children: {Tree2<U,T>} }
|
||||
@ -876,7 +874,7 @@ TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_ok")
|
||||
TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_not_ok")
|
||||
{
|
||||
// CLI-116108
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
-- this would be an infinite type if we allowed it
|
||||
@ -889,7 +887,7 @@ TEST_CASE_FIXTURE(Fixture, "recursive_types_restriction_not_ok")
|
||||
TEST_CASE_FIXTURE(Fixture, "report_shadowed_aliases")
|
||||
{
|
||||
// CLI-116110
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
// We allow a previous type alias to depend on a future type alias. That exact feature enables a confusing example, like the following snippet,
|
||||
// which has the type alias FakeString point to the type alias `string` that which points to `number`.
|
||||
@ -973,7 +971,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_locations")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "dont_lose_track_of_PendingExpansionTypes_after_substitution")
|
||||
{
|
||||
// CLI-114134 - We need egraphs to properly simplify these types.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
fileResolver.source["game/ReactCurrentDispatcher"] = R"(
|
||||
export type BasicStateAction<S> = ((S) -> S) | S
|
||||
|
@ -11,7 +11,7 @@ using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
|
||||
LUAU_FASTFLAG(LuauTypestateBuiltins)
|
||||
LUAU_FASTFLAG(LuauTypestateBuiltins2)
|
||||
LUAU_FASTFLAG(LuauStringFormatArityFix)
|
||||
|
||||
TEST_SUITE_BEGIN("BuiltinTests");
|
||||
@ -136,7 +136,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_predicate")
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "sort_with_bad_predicate")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -516,7 +516,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "buffer_is_a_type")
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_resume_anything_goes")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function nifty(x, y)
|
||||
@ -1133,7 +1133,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic")
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauTypestateBuiltins)
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauTypestateBuiltins2)
|
||||
CHECK("Key 'b' not found in table '{ read a: number }'" == toString(result.errors[0]));
|
||||
else if (FFlag::LuauSolverV2)
|
||||
CHECK("Key 'b' not found in table '{ a: number }'" == toString(result.errors[0]));
|
||||
@ -1141,7 +1141,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_is_generic")
|
||||
CHECK_EQ("Key 'b' not found in table '{| a: number |}'", toString(result.errors[0]));
|
||||
CHECK(Location({13, 18}, {13, 23}) == result.errors[0].location);
|
||||
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauTypestateBuiltins)
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauTypestateBuiltins2)
|
||||
{
|
||||
CHECK_EQ("{ read a: number }", toString(requireTypeAtPosition({15, 19})));
|
||||
CHECK_EQ("{ read b: string }", toString(requireTypeAtPosition({16, 19})));
|
||||
@ -1178,13 +1178,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_does_not_retroactively_block_mu
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
|
||||
if (FFlag::LuauTypestateBuiltins)
|
||||
if (FFlag::LuauTypestateBuiltins2)
|
||||
{
|
||||
CHECK_EQ("t1 | { read a: number, read q: string }", toString(requireType("t1")));
|
||||
CHECK_EQ("{ a: number, q: string } | { read a: number, read q: string }", toString(requireType("t1"), {/*exhaustive */ true}));
|
||||
// before the assignment, it's `t1`
|
||||
CHECK_EQ("t1", toString(requireTypeAtPosition({3, 8})));
|
||||
CHECK_EQ("{ a: number, q: string }", toString(requireTypeAtPosition({3, 8}), {/*exhaustive */ true}));
|
||||
// after the assignment, it's read-only.
|
||||
CHECK_EQ("{ read a: number, read q: string }", toString(requireTypeAtPosition({8, 18})));
|
||||
CHECK_EQ("{ read a: number, read q: string }", toString(requireTypeAtPosition({8, 18}), {/*exhaustive */ true}));
|
||||
}
|
||||
|
||||
CHECK_EQ("number", toString(requireType("a")));
|
||||
@ -1208,10 +1208,46 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_no_generic_table")
|
||||
end
|
||||
)");
|
||||
|
||||
if (FFlag::LuauTypestateBuiltins)
|
||||
if (FFlag::LuauTypestateBuiltins2)
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_on_metatable")
|
||||
{
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
local meta = {
|
||||
__index = function()
|
||||
return "foo"
|
||||
end
|
||||
}
|
||||
|
||||
local myTable = setmetatable({}, meta)
|
||||
table.freeze(myTable)
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_errors_on_no_args")
|
||||
{
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
table.freeze()
|
||||
)");
|
||||
|
||||
// this does not error in the new solver without the typestate builtins functionality.
|
||||
if (FFlag::LuauSolverV2 && !FFlag::LuauTypestateBuiltins2)
|
||||
{
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
return;
|
||||
}
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
CHECK(get<CountMismatch>(result.errors[0]));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_errors_on_non_tables")
|
||||
{
|
||||
CheckResult result = check(R"(
|
||||
@ -1220,7 +1256,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_errors_on_non_tables")
|
||||
)");
|
||||
|
||||
// this does not error in the new solver without the typestate builtins functionality.
|
||||
if (FFlag::LuauSolverV2 && !FFlag::LuauTypestateBuiltins)
|
||||
if (FFlag::LuauSolverV2 && !FFlag::LuauTypestateBuiltins2)
|
||||
{
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
return;
|
||||
@ -1231,7 +1267,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_errors_on_non_tables")
|
||||
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
|
||||
REQUIRE(tm);
|
||||
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauTypestateBuiltins)
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauTypestateBuiltins2)
|
||||
CHECK_EQ(toString(tm->wantedType), "table");
|
||||
else
|
||||
CHECK_EQ(toString(tm->wantedType), "{- -}");
|
||||
@ -1241,7 +1277,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_errors_on_non_tables")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "set_metatable_needs_arguments")
|
||||
{
|
||||
// In the new solver, nil can certainly be used where a generic is required, so all generic parameters are optional.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local a = {b=setmetatable}
|
||||
|
@ -128,7 +128,7 @@ TEST_CASE_FIXTURE(ClassFixture, "we_can_infer_that_a_parameter_must_be_a_particu
|
||||
|
||||
TEST_CASE_FIXTURE(ClassFixture, "we_can_report_when_someone_is_trying_to_use_a_table_rather_than_a_class")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function makeClone(o)
|
||||
@ -235,7 +235,7 @@ TEST_CASE_FIXTURE(ClassFixture, "can_assign_to_prop_of_base_class_using_string")
|
||||
TEST_CASE_FIXTURE(ClassFixture, "cannot_unify_class_instance_with_primitive")
|
||||
{
|
||||
// This is allowed in the new solver
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local v = Vector2.New(0, 5)
|
||||
@ -472,7 +472,7 @@ Type 'number' could not be converted into 'string')";
|
||||
TEST_CASE_FIXTURE(ClassFixture, "class_type_mismatch_with_name_conflict")
|
||||
{
|
||||
// CLI-116433
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local i = ChildClass.New()
|
||||
|
@ -443,6 +443,26 @@ TEST_CASE_FIXTURE(Fixture, "class_definition_string_props")
|
||||
CHECK_EQ(toString(requireType("y")), "string");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "class_definition_malformed_string")
|
||||
{
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
LoadDefinitionFileResult result = frontend.loadDefinitionFile(
|
||||
frontend.globals,
|
||||
frontend.globals.globalScope,
|
||||
R"(
|
||||
declare class Foo
|
||||
["a\0property"]: string
|
||||
end
|
||||
)",
|
||||
"@test",
|
||||
/* captureComments */ false
|
||||
);
|
||||
freeze(frontend.globals.globalTypes);
|
||||
|
||||
REQUIRE(!result.success);
|
||||
REQUIRE_EQ(result.parseResult.errors.size(), 1);
|
||||
CHECK_EQ(result.parseResult.errors[0].getMessage(), "String literal contains malformed escape sequence or \\0");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "class_definition_indexer")
|
||||
{
|
||||
|
@ -16,9 +16,10 @@
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping);
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTINT(LuauTarjanChildLimit);
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTINT(LuauTarjanChildLimit)
|
||||
LUAU_FASTFLAG(LuauRetrySubtypingWithoutHiddenPack)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferFunctions");
|
||||
|
||||
@ -310,7 +311,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_return_type_from_selected_overload")
|
||||
TEST_CASE_FIXTURE(Fixture, "too_many_arguments")
|
||||
{
|
||||
// This is not part of the new non-strict specification currently.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
@ -602,7 +603,7 @@ TEST_CASE_FIXTURE(Fixture, "duplicate_functions_allowed_in_nonstrict")
|
||||
TEST_CASE_FIXTURE(Fixture, "duplicate_functions_with_different_signatures_not_allowed_in_nonstrict")
|
||||
{
|
||||
// This is not part of the spec for the new non-strict mode currently.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
@ -881,7 +882,7 @@ TEST_CASE_FIXTURE(Fixture, "another_indirect_function_case_where_it_is_ok_to_pro
|
||||
TEST_CASE_FIXTURE(Fixture, "report_exiting_without_return_nonstrict")
|
||||
{
|
||||
// new non-strict mode spec does not include this error yet.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
@ -1016,7 +1017,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "calling_function_with_anytypepack_doesnt_lea
|
||||
TEST_CASE_FIXTURE(Fixture, "too_many_return_values")
|
||||
{
|
||||
// FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -1040,7 +1041,7 @@ TEST_CASE_FIXTURE(Fixture, "too_many_return_values")
|
||||
TEST_CASE_FIXTURE(Fixture, "too_many_return_values_in_parentheses")
|
||||
{
|
||||
// FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -1064,7 +1065,7 @@ TEST_CASE_FIXTURE(Fixture, "too_many_return_values_in_parentheses")
|
||||
TEST_CASE_FIXTURE(Fixture, "too_many_return_values_no_function")
|
||||
{
|
||||
// FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -1233,7 +1234,7 @@ TEST_CASE_FIXTURE(Fixture, "return_type_by_overload")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "infer_anonymous_function_arguments")
|
||||
{
|
||||
// FIXME: CLI-116133 bidirectional type inference needs to push expected types in for higher-order function calls
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
// Simple direct arg to arg propagation
|
||||
CheckResult result = check(R"(
|
||||
@ -1352,7 +1353,7 @@ f(function(x) return x * 2 end)
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "infer_generic_function_function_argument")
|
||||
{
|
||||
// FIXME: CLI-116133 bidirectional type inference needs to push expected types in for higher-order function calls
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function sum<a>(x: a, y: a, f: (a, a) -> a) return f(x, y) end
|
||||
@ -1383,7 +1384,7 @@ local r = foldl(a, {s=0,c=0}, function(a, b) return {s = a.s + b, c = a.c + 1} e
|
||||
TEST_CASE_FIXTURE(Fixture, "infer_generic_function_function_argument_overloaded")
|
||||
{
|
||||
// FIXME: CLI-116133 bidirectional type inference needs to push expected types in for higher-order function calls
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function g1<T>(a: T, f: (T) -> T) return f(a) end
|
||||
@ -1450,7 +1451,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "variadic_any_is_compatible_with_a_generic_Ty
|
||||
TEST_CASE_FIXTURE(Fixture, "infer_anonymous_function_arguments_outside_call")
|
||||
{
|
||||
// FIXME: CLI-116133 bidirectional type inference needs to push expected types in for higher-order function calls
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Table = { x: number, y: number }
|
||||
@ -1493,7 +1494,7 @@ end
|
||||
TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_arg_count")
|
||||
{
|
||||
// FIXME: CLI-116111 test disabled until type path stringification is improved
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type A = (number, number) -> string
|
||||
@ -1516,7 +1517,7 @@ caused by:
|
||||
TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_arg")
|
||||
{
|
||||
// FIXME: CLI-116111 test disabled until type path stringification is improved
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type A = (number, number) -> string
|
||||
@ -1540,7 +1541,7 @@ Type 'string' could not be converted into 'number')";
|
||||
TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_ret_count")
|
||||
{
|
||||
// FIXME: CLI-116111 test disabled until type path stringification is improved
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type A = (number, number) -> (number)
|
||||
@ -1563,7 +1564,7 @@ caused by:
|
||||
TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_ret")
|
||||
{
|
||||
// FIXME: CLI-116111 test disabled until type path stringification is improved
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type A = (number, number) -> string
|
||||
@ -1587,7 +1588,7 @@ Type 'string' could not be converted into 'number')";
|
||||
TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_ret_mult")
|
||||
{
|
||||
// FIXME: CLI-116111 test disabled until type path stringification is improved
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type A = (number, number) -> (number, string)
|
||||
@ -1718,7 +1719,7 @@ TEST_CASE_FIXTURE(Fixture, "inferred_higher_order_functions_are_quantified_at_th
|
||||
{
|
||||
// This test regresses in the new solver, but is sort of nonsensical insofar as `foo` is known to be `nil`, so it's "right" to not be able to call
|
||||
// it.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local foo
|
||||
@ -1787,7 +1788,7 @@ TEST_CASE_FIXTURE(Fixture, "strict_mode_ok_with_missing_arguments")
|
||||
TEST_CASE_FIXTURE(Fixture, "function_statement_sealed_table_assignment_through_indexer")
|
||||
{
|
||||
// FIXME: CLI-116122 bug where `t:b` does not check against the type from the indexer annotation on `t`.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local t: {[string]: () -> number} = {}
|
||||
@ -1832,7 +1833,7 @@ TEST_CASE_FIXTURE(Fixture, "too_few_arguments_variadic")
|
||||
TEST_CASE_FIXTURE(Fixture, "too_few_arguments_variadic_generic")
|
||||
{
|
||||
// FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function test(a: number, b: string, ...)
|
||||
@ -1860,7 +1861,7 @@ wrapper(test)
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "too_few_arguments_variadic_generic2")
|
||||
{
|
||||
// FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function test(a: number, b: string, ...)
|
||||
@ -2014,7 +2015,7 @@ u.b().foo()
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "improved_function_arg_mismatch_error_nonstrict")
|
||||
{
|
||||
// This behavior is not part of the current specification of the new type solver.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
@ -2029,7 +2030,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "improved_function_arg_mismatch_error_nonstri
|
||||
TEST_CASE_FIXTURE(Fixture, "luau_subtyping_is_np_hard")
|
||||
{
|
||||
// The case that _should_ succeed here (`z = x`) does not currently in the new solver.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -2994,4 +2995,25 @@ local u,v = id(3), id(id(44))
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "hidden_variadics_should_not_break_subtyping")
|
||||
{
|
||||
// Only applies to new solver.
|
||||
ScopedFastFlag sff{FFlag::LuauRetrySubtypingWithoutHiddenPack, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
type FooType = {
|
||||
SetValue: (Value: number) -> ()
|
||||
}
|
||||
|
||||
local Foo: FooType = {
|
||||
SetValue = function(Value: number)
|
||||
|
||||
end
|
||||
}
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
@ -143,7 +143,7 @@ TEST_CASE_FIXTURE(Fixture, "properties_can_be_polytypes")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "properties_can_be_instantiated_polytypes")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local t: { m: (number)->number } = { m = function(x:number) return x+1 end }
|
||||
@ -261,7 +261,7 @@ TEST_CASE_FIXTURE(Fixture, "check_mutual_generic_functions_errors")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_functions_in_types_old_solver")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type T = { id: <a>(a) -> a }
|
||||
@ -287,7 +287,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_functions_in_types_new_solver")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_factories")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type T<a> = { id: (a) -> a }
|
||||
@ -310,7 +310,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_factories")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "factories_of_generics")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type T = { id: <a>(a) -> a }
|
||||
@ -775,7 +775,7 @@ return exports
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "instantiated_function_argument_names_old_solver")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function f<T, U...>(a: T, ...: U...) end
|
||||
@ -794,7 +794,7 @@ TEST_CASE_FIXTURE(Fixture, "instantiated_function_argument_names_old_solver")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_generic_types")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type C = () -> ()
|
||||
@ -811,7 +811,7 @@ local d: D = c
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "error_detailed_function_mismatch_generic_pack")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type C = () -> ()
|
||||
@ -887,7 +887,7 @@ Type 'number' could not be converted into 'string' in an invariant context)";
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_type_pack_unification1")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -907,7 +907,7 @@ local TheDispatcher: Dispatcher = {
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_type_pack_unification2")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -927,7 +927,7 @@ local TheDispatcher: Dispatcher = {
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_type_pack_unification3")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -947,7 +947,7 @@ local TheDispatcher: Dispatcher = {
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_few")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function test(a: number)
|
||||
@ -966,7 +966,7 @@ wrapper(test)
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_argument_count_too_many")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function test2(a: number, b: string)
|
||||
@ -1463,7 +1463,7 @@ TEST_CASE_FIXTURE(Fixture, "no_extra_quantification_for_generic_functions")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "do_not_always_instantiate_generic_intersection_types")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -1498,8 +1498,9 @@ end
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "higher_rank_polymorphism_should_not_accept_instantiated_arguments")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, false},
|
||||
{FFlag::LuauInstantiateInSubtyping, true},
|
||||
};
|
||||
|
||||
@ -1579,7 +1580,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_implicit_explicit_name_clash")
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "generic_type_functions_work_in_subtyping")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
@ -332,9 +332,9 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed_indirect")
|
||||
{
|
||||
ScopedFastFlag dcr{
|
||||
FFlag::LuauSolverV2, false
|
||||
}; // CLI-116476 Subtyping between type alias and an equivalent but not named type isn't working.
|
||||
// CLI-116476 Subtyping between type alias and an equivalent but not named type isn't working.
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type X = { x: (number) -> number }
|
||||
type Y = { y: (string) -> string }
|
||||
@ -372,7 +372,7 @@ caused by:
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "table_write_sealed_indirect")
|
||||
{
|
||||
ScopedFastFlag dcr{FFlag::LuauSolverV2, false}; // CLI-
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
// 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 }
|
||||
@ -581,9 +581,9 @@ could not be converted into
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "union_saturate_overloaded_functions")
|
||||
{
|
||||
ScopedFastFlag dcr{
|
||||
FFlag::LuauSolverV2, false
|
||||
}; // CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions
|
||||
// CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(x: ((number) -> number) & ((string) -> string))
|
||||
local y : ((number | string) -> (number | string)) = x -- OK
|
||||
@ -811,9 +811,9 @@ could not be converted into
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_unknown_result")
|
||||
{
|
||||
ScopedFastFlag dcr{
|
||||
FFlag::LuauSolverV2, false
|
||||
}; // CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions
|
||||
// CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f<a...,b...>()
|
||||
function g(x : ((number) -> number) & ((nil) -> unknown))
|
||||
@ -833,9 +833,9 @@ could not be converted into
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_unknown_arguments")
|
||||
{
|
||||
ScopedFastFlag dcr{
|
||||
FFlag::LuauSolverV2, false
|
||||
}; // CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions
|
||||
// CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f<a...,b...>()
|
||||
function g(x : ((number) -> number?) & ((unknown) -> string?))
|
||||
@ -939,9 +939,9 @@ could not be converted into
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "overloadeded_functions_with_overlapping_results_and_variadics")
|
||||
{
|
||||
ScopedFastFlag dcr{
|
||||
FFlag::LuauSolverV2, false
|
||||
}; // CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions
|
||||
// CLI-116474 Semantic subtyping of assignments needs to decide how to interpret intersections of functions
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(x : ((string?) -> (string | number)) & ((number?) -> ...number))
|
||||
local y : ((nil) -> (number, number?)) = x -- OK
|
||||
|
@ -152,7 +152,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_next")
|
||||
{
|
||||
// CLI-116494 The generics K and V are leaking out of the next() function somehow.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local n
|
||||
@ -270,7 +270,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_error")
|
||||
TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_non_function")
|
||||
{
|
||||
// We report a spuriouus duplicate error here.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local bad_iter = 5
|
||||
@ -287,7 +287,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_non_function")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_factory_not_returning_the_right_amount_of_values")
|
||||
{
|
||||
// Spurious duplicate errors
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function hasDivisors(value: number, table)
|
||||
@ -339,7 +339,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_factory_not_returning_t
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_error_on_iterator_requiring_args_but_none_given")
|
||||
{
|
||||
// CLI-116496
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function prime_iter(state, index)
|
||||
@ -757,7 +757,7 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_basic")
|
||||
TEST_CASE_FIXTURE(Fixture, "loop_iter_trailing_nil")
|
||||
{
|
||||
// CLI-116498 Sometimes you can iterate over tables with no indexers.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local t: {string} = {}
|
||||
@ -774,9 +774,7 @@ TEST_CASE_FIXTURE(Fixture, "loop_iter_trailing_nil")
|
||||
TEST_CASE_FIXTURE(Fixture, "loop_iter_no_indexer_strict")
|
||||
{
|
||||
// CLI-116498 Sometimes you can iterate over tables with no indexers.
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, false},
|
||||
};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local t = {}
|
||||
@ -1082,7 +1080,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dcr_iteration_on_never_gives_never")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "iterate_over_properties")
|
||||
{
|
||||
// CLI-116498 - Sometimes you can iterate over tables with no indexer.
|
||||
ScopedFastFlag sff0{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function f()
|
||||
|
@ -11,8 +11,9 @@
|
||||
#include "doctest.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauRequireCyclesDontAlwaysReturnAny)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauTypestateBuiltins)
|
||||
LUAU_FASTFLAG(LuauTypestateBuiltins2)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
@ -184,7 +185,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cross_module_table_freeze")
|
||||
ModulePtr b = frontend.moduleResolver.getModule("game/B");
|
||||
REQUIRE(b != nullptr);
|
||||
// confirm that no cross-module mutation happened here!
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauTypestateBuiltins)
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauTypestateBuiltins2)
|
||||
CHECK(toString(b->returnType) == "{ read a: number }");
|
||||
else if (FFlag::LuauSolverV2)
|
||||
CHECK(toString(b->returnType) == "{ a: number }");
|
||||
@ -604,7 +605,7 @@ function createUpdater(renderer)
|
||||
function updater.enqueueForceUpdate(publicInstance, callback, _callerName)
|
||||
updater._renderer.render(
|
||||
updater._renderer,
|
||||
updater._renderer._element,
|
||||
updater._renderer._element,
|
||||
updater._renderer._context
|
||||
)
|
||||
end
|
||||
@ -617,7 +618,7 @@ function createUpdater(renderer)
|
||||
)
|
||||
updater._renderer.render(
|
||||
updater._renderer,
|
||||
updater._renderer._element,
|
||||
updater._renderer._element,
|
||||
updater._renderer._context
|
||||
)
|
||||
end
|
||||
@ -626,7 +627,7 @@ function createUpdater(renderer)
|
||||
local currentState = updater._renderer._newState or publicInstance.state
|
||||
updater._renderer.render(
|
||||
updater._renderer,
|
||||
updater._renderer._element,
|
||||
updater._renderer._element,
|
||||
updater._renderer._context
|
||||
)
|
||||
end
|
||||
@ -736,4 +737,45 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "spooky_blocked_type_laundered_by_bound_type"
|
||||
)"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "cycles_dont_make_everything_any")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauRequireCyclesDontAlwaysReturnAny, true};
|
||||
|
||||
fileResolver.source["game/A"] = R"(
|
||||
--!strict
|
||||
local module = {}
|
||||
|
||||
function module.foo()
|
||||
return 2
|
||||
end
|
||||
|
||||
function module.bar()
|
||||
local m = require(game.B)
|
||||
return m.foo() + 1
|
||||
end
|
||||
|
||||
return module
|
||||
)";
|
||||
|
||||
fileResolver.source["game/B"] = R"(
|
||||
--!strict
|
||||
local module = {}
|
||||
|
||||
function module.foo()
|
||||
return 2
|
||||
end
|
||||
|
||||
function module.bar()
|
||||
local m = require(game.A)
|
||||
return m.foo() + 1
|
||||
end
|
||||
|
||||
return module
|
||||
)";
|
||||
|
||||
frontend.check("game/A");
|
||||
|
||||
CHECK("module" == toString(frontend.moduleResolver.getModule("game/B")->returnType));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
@ -19,7 +19,7 @@ TEST_SUITE_BEGIN("TypeInferOOP");
|
||||
TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_not_defined_with_colon")
|
||||
{
|
||||
// CLI-116571 method calls are missing arity checking?
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local someTable = {}
|
||||
@ -37,7 +37,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_not_defi
|
||||
TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_it_wont_help_2")
|
||||
{
|
||||
// CLI-116571 method calls are missing arity checking?
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local someTable = {}
|
||||
|
@ -17,6 +17,7 @@
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauMetatableFollow)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferOperators");
|
||||
|
||||
@ -630,7 +631,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus_error")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_len_error")
|
||||
{
|
||||
// CLI-116463
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -884,7 +885,7 @@ TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operato
|
||||
TEST_CASE_FIXTURE(Fixture, "cli_38355_recursive_union")
|
||||
{
|
||||
// There's an extra spurious warning here when the new solver is enabled.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -1425,7 +1426,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "luau_polyfill_is_array_simplified")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "luau_polyfill_is_array")
|
||||
{
|
||||
// CLI-116480 Subtyping bug: table should probably be a subtype of {[unknown]: unknown}
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -1611,4 +1612,28 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "compound_operator_on_upvalue")
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "metatable_operator_follow")
|
||||
{
|
||||
ScopedFastFlag luauMetatableFollow{FFlag::LuauMetatableFollow, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local t1 = {}
|
||||
local t2 = {}
|
||||
local mt = {}
|
||||
|
||||
mt.__eq = function(a, b)
|
||||
return false
|
||||
end
|
||||
|
||||
setmetatable(t1, mt)
|
||||
setmetatable(t2, mt)
|
||||
|
||||
if t1 == t2 then
|
||||
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
@ -73,7 +73,7 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_inference_incomplete")
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "luau-polyfill.Array.filter")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
// This test exercises the fact that we should reduce sealed/unsealed/free tables
|
||||
// res is a unsealed table with type {((T & ~nil)?) & any}
|
||||
@ -172,7 +172,7 @@ TEST_CASE_FIXTURE(Fixture, "it_should_be_agnostic_of_actual_size")
|
||||
// For now, infer it as just a free table.
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_constrains_free_type_into_free_table")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local a = {}
|
||||
@ -192,7 +192,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_constrains_free_type_into_free_
|
||||
// Luau currently doesn't yet know how to allow assignments when the binding was refined.
|
||||
TEST_CASE_FIXTURE(Fixture, "while_body_are_also_refined")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Node<T> = { value: T, child: Node<T>? }
|
||||
@ -217,7 +217,7 @@ TEST_CASE_FIXTURE(Fixture, "while_body_are_also_refined")
|
||||
// We should be type checking the metamethod at the call site of setmetatable.
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "error_on_eq_metamethod_returning_a_type_other_than_boolean")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local tab = {a = 1}
|
||||
@ -390,11 +390,9 @@ TEST_CASE_FIXTURE(Fixture, "specialization_binds_with_prototypes_too_early")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "weird_fail_to_unify_type_pack")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
// I'm not sure why this is broken without DCR, but it seems to be fixed
|
||||
// when DCR is enabled.
|
||||
{FFlag::LuauSolverV2, false},
|
||||
};
|
||||
// I'm not sure why this is broken without DCR, but it seems to be fixed
|
||||
// when DCR is enabled.
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function f() return end
|
||||
@ -517,7 +515,7 @@ TEST_CASE_FIXTURE(Fixture, "dcr_can_partially_dispatch_a_constraint")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "free_options_cannot_be_unified_together")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
TypeArena arena;
|
||||
TypeId nilType = builtinTypes->nilType;
|
||||
@ -553,7 +551,7 @@ TEST_CASE_FIXTURE(Fixture, "free_options_cannot_be_unified_together")
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_zero_iterators")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function no_iter() end
|
||||
@ -847,7 +845,7 @@ Type 'number?' could not be converted into 'number' in an invariant context)";
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_with_a_singleton_argument")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function foo(t, x)
|
||||
@ -921,7 +919,7 @@ TEST_CASE_FIXTURE(Fixture, "expected_type_should_be_a_helpful_deduction_guide_fo
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "floating_generics_should_not_be_allowed")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local assign : <T, U, V, W>(target: T, source0: U?, source1: V?, source2: W?, ...any) -> T & U & V & W = (nil :: any)
|
||||
@ -945,7 +943,7 @@ TEST_CASE_FIXTURE(Fixture, "floating_generics_should_not_be_allowed")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "free_options_can_be_unified_together")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
TypeArena arena;
|
||||
TypeId nilType = builtinTypes->nilType;
|
||||
@ -992,7 +990,7 @@ TEST_CASE_FIXTURE(Fixture, "unify_more_complex_unions_that_include_nil")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "optional_class_instances_are_invariant_old_solver")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
createSomeClasses(&frontend);
|
||||
|
||||
@ -1076,7 +1074,7 @@ end
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "table_unification_infinite_recursion")
|
||||
{
|
||||
// The new solver doesn't recurse as heavily in this situation.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
#if defined(_NOOPT) || defined(_DEBUG)
|
||||
ScopedFastInt LuauTypeInferRecursionLimit{FInt::LuauTypeInferRecursionLimit, 100};
|
||||
|
@ -1375,7 +1375,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "discriminate_from_isa_of_x")
|
||||
TEST_CASE_FIXTURE(RefinementClassFixture, "typeguard_cast_free_table_to_vector")
|
||||
{
|
||||
// CLI-115286 - Refining via type(x) == 'vector' does not work in the new solver
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function f(vec)
|
||||
@ -1569,7 +1569,7 @@ TEST_CASE_FIXTURE(RefinementClassFixture, "isa_type_refinement_must_be_known_ahe
|
||||
{
|
||||
// CLI-115087 - The new solver does not consistently combine tables with
|
||||
// class types when they appear in the upper bounds of a free type.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function f(x): Instance
|
||||
|
@ -153,7 +153,7 @@ TEST_CASE_FIXTURE(Fixture, "overloaded_function_call_with_singletons")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "overloaded_function_call_with_singletons_mismatch")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(g: ((true, string) -> ()) & ((false, number) -> ()))
|
||||
@ -463,7 +463,7 @@ local a: Animal = if true then { tag = 'cat', catfood = 'something' } else { tag
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "widen_the_supertype_if_it_is_free_and_subtype_has_singleton")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function foo(f, x)
|
||||
@ -483,7 +483,7 @@ TEST_CASE_FIXTURE(Fixture, "widen_the_supertype_if_it_is_free_and_subtype_has_si
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "return_type_of_f_is_not_widened")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function foo(f, x): "hello"? -- anyone there?
|
||||
|
@ -19,6 +19,7 @@ LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauFixIndexerSubtypingOrdering)
|
||||
LUAU_FASTFLAG(LuauAcceptIndexingTableUnionsIntersections)
|
||||
LUAU_FASTFLAG(LuauRetrySubtypingWithoutHiddenPack)
|
||||
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeSolverRelease)
|
||||
|
||||
@ -318,7 +319,7 @@ TEST_CASE_FIXTURE(Fixture, "call_method_with_explicit_self_argument")
|
||||
TEST_CASE_FIXTURE(Fixture, "used_dot_instead_of_colon")
|
||||
{
|
||||
// CLI-114792 Dot vs colon warnings aren't in the new solver yet.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local T = {}
|
||||
@ -371,7 +372,7 @@ TEST_CASE_FIXTURE(Fixture, "used_dot_instead_of_colon_but_correctly")
|
||||
TEST_CASE_FIXTURE(Fixture, "used_colon_instead_of_dot")
|
||||
{
|
||||
// CLI-114792 Dot vs colon warnings aren't in the new solver yet.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local T = {}
|
||||
@ -396,7 +397,7 @@ TEST_CASE_FIXTURE(Fixture, "used_colon_instead_of_dot")
|
||||
TEST_CASE_FIXTURE(Fixture, "open_table_unification_2")
|
||||
{
|
||||
// CLI-114792 We don't report MissingProperties in many places where the old solver does.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local a = {}
|
||||
@ -536,7 +537,7 @@ TEST_CASE_FIXTURE(Fixture, "table_param_width_subtyping_3")
|
||||
TEST_CASE_FIXTURE(Fixture, "table_unification_4")
|
||||
{
|
||||
// CLI-114134 - Use egraphs to simplify types better.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function foo(o)
|
||||
@ -567,7 +568,7 @@ TEST_CASE_FIXTURE(Fixture, "ok_to_add_property_to_free_table")
|
||||
TEST_CASE_FIXTURE(Fixture, "okay_to_add_property_to_unsealed_tables_by_assignment")
|
||||
{
|
||||
// CLI-114872
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -586,7 +587,7 @@ TEST_CASE_FIXTURE(Fixture, "okay_to_add_property_to_unsealed_tables_by_assignmen
|
||||
TEST_CASE_FIXTURE(Fixture, "okay_to_add_property_to_unsealed_tables_by_function_call")
|
||||
{
|
||||
// CLI-114873
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -811,7 +812,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_indexer_from_value_property_in_literal")
|
||||
TEST_CASE_FIXTURE(Fixture, "infer_indexer_from_its_variable_type_and_unifiable")
|
||||
{
|
||||
// This code is totally different in the new solver. We instead create a new type state for t2.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local t1: { [string]: string } = {}
|
||||
@ -893,7 +894,7 @@ TEST_CASE_FIXTURE(Fixture, "sealed_table_value_can_infer_an_indexer")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "array_factory_function")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function empty() return {} end
|
||||
@ -930,7 +931,7 @@ TEST_CASE_FIXTURE(Fixture, "indexer_on_sealed_table_must_unify_with_free_table")
|
||||
// CLI-114134 What should be happening here is that the type of `t` should
|
||||
// be reduced from `{number} & {string}` to `never`, but that's not
|
||||
// happening.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function F(t): {number}
|
||||
@ -993,7 +994,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "indexing_from_a_table_should_prefer_properti
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "any_when_indexing_into_an_unsealed_table_with_no_indexer_in_nonstrict_mode")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
@ -1145,7 +1146,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "meta_add_inferred")
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "meta_add_both_ways")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type VectorMt = { __add: (Vector, number) -> Vector }
|
||||
@ -1523,7 +1524,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "found_multiple_like_keys")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "dont_suggest_exact_match_keys")
|
||||
{
|
||||
// CLI-114977 Unsealed table writes don't account for order properly
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local t = {}
|
||||
@ -1566,7 +1567,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "getmetatable_returns_pointer_to_metatable")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "metatable_mismatch_should_fail")
|
||||
{
|
||||
// This test is invalid because we now create a new type state for t1 at the assignment.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local t1 = {x = 1}
|
||||
@ -1610,7 +1611,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "property_lookup_through_tabletypevar_metatab
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "missing_metatable_for_sealed_tables_do_not_get_inferred")
|
||||
{
|
||||
// This test is invalid because we now create a new type state for t at the assignment.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local t = {x = 1}
|
||||
@ -1665,7 +1666,7 @@ TEST_CASE_FIXTURE(Fixture, "right_table_missing_key")
|
||||
TEST_CASE_FIXTURE(Fixture, "right_table_missing_key2")
|
||||
{
|
||||
// CLI-114792 We don't report MissingProperties
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(t: {}): { [string]: string, a: string }
|
||||
@ -1927,7 +1928,7 @@ TEST_CASE_FIXTURE(Fixture, "type_mismatch_on_massive_table_is_cut_short")
|
||||
TEST_CASE_FIXTURE(Fixture, "ok_to_set_nil_even_on_non_lvalue_base_expr")
|
||||
{
|
||||
// CLI-100076 Assigning nil to an indexer should always succeed
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function f(): { [string]: number }
|
||||
@ -2096,7 +2097,7 @@ local Test: {Table} = {
|
||||
TEST_CASE_FIXTURE(Fixture, "common_table_element_general")
|
||||
{
|
||||
// CLI-115275 - Bidirectional inference does not always propagate indexer types into the expression
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Table = {
|
||||
@ -2218,7 +2219,7 @@ foo({
|
||||
TEST_CASE_FIXTURE(Fixture, "common_table_element_union_in_call_tail")
|
||||
{
|
||||
// CLI-115239 - Bidirectional checking does not work for __call metamethods
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Foo = {x: number | string}
|
||||
@ -2265,7 +2266,16 @@ TEST_CASE_FIXTURE(Fixture, "invariant_table_properties_means_instantiating_table
|
||||
local c : string = t.m("hi")
|
||||
)");
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauRetrySubtypingWithoutHiddenPack)
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
CHECK(get<ExplicitFunctionAnnotationRecommended>(result.errors[0]));
|
||||
|
||||
// This is not actually the expected behavior, but the typemismatch we were seeing before was for the wrong reason.
|
||||
// The behavior of this test is just regressed generally in the new solver, and will need to be consciously addressed.
|
||||
}
|
||||
else if (FFlag::LuauSolverV2)
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
|
||||
@ -2504,7 +2514,7 @@ Type 'number' could not be converted into 'string' in an invariant context)";
|
||||
TEST_CASE_FIXTURE(Fixture, "explicitly_typed_table")
|
||||
{
|
||||
// Table properties like HasSuper.p must be invariant. The new solver rightly rejects this program.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -2554,7 +2564,7 @@ Table type '{ x: number, y: number }' not compatible with type 'Super' because t
|
||||
TEST_CASE_FIXTURE(Fixture, "explicitly_typed_table_with_indexer")
|
||||
{
|
||||
// CLI-114791 Bidirectional inference should be able to cause the inference engine to forget that a table literal has some property
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -2572,7 +2582,7 @@ TEST_CASE_FIXTURE(Fixture, "explicitly_typed_table_with_indexer")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "recursive_metatable_type_call")
|
||||
{
|
||||
// CLI-114782
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local b
|
||||
@ -2827,7 +2837,7 @@ TEST_CASE_FIXTURE(Fixture, "table_length")
|
||||
TEST_CASE_FIXTURE(Fixture, "nil_assign_doesnt_hit_indexer")
|
||||
{
|
||||
// CLI-100076 - Assigning a table key to `nil` in the presence of an indexer should always be permitted
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check("local a = {} a[0] = 7 a[0] = nil");
|
||||
LUAU_REQUIRE_ERROR_COUNT(0, result);
|
||||
@ -3296,7 +3306,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_call_metamethod_generic")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "table_simple_call")
|
||||
{
|
||||
// The new solver can see that this function is safe to oversaturate.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local a = setmetatable({ x = 2 }, {
|
||||
@ -3589,7 +3599,7 @@ local b = a.x
|
||||
TEST_CASE_FIXTURE(Fixture, "scalar_is_a_subtype_of_a_compatible_polymorphic_shape_type")
|
||||
{
|
||||
// CLI-115087 The new solver cannot infer that a table-like type is actually string
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function f(s)
|
||||
@ -3678,7 +3688,7 @@ Table type 'typeof(string)' not compatible with type 't1 where t1 = {- absolutel
|
||||
TEST_CASE_FIXTURE(Fixture, "a_free_shape_can_turn_into_a_scalar_if_it_is_compatible")
|
||||
{
|
||||
// CLI-115087 The new solver cannot infer that a table-like type is actually string
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function f(s): string
|
||||
@ -3733,7 +3743,7 @@ Table type 'typeof(string)' not compatible with type 't1 where t1 = {+ absolutel
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "a_free_shape_can_turn_into_a_scalar_directly")
|
||||
{
|
||||
// We need egraphs to simplify the type of `out` here. CLI-114134
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function stringByteList(str)
|
||||
@ -4231,9 +4241,7 @@ TEST_CASE_FIXTURE(Fixture, "identify_all_problematic_table_fields")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "read_and_write_only_table_properties_are_unsupported")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, false},
|
||||
};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type W = {read x: number}
|
||||
@ -4370,7 +4378,7 @@ TEST_CASE_FIXTURE(Fixture, "write_annotations_are_unsupported_even_with_the_new_
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "read_and_write_only_table_properties_are_unsupported")
|
||||
{
|
||||
ScopedFastFlag sff[] = {{FFlag::LuauSolverV2, false}};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type W = {read x: number}
|
||||
@ -4394,7 +4402,7 @@ TEST_CASE_FIXTURE(Fixture, "read_and_write_only_table_properties_are_unsupported
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "read_ond_write_only_indexers_are_unsupported")
|
||||
{
|
||||
ScopedFastFlag sff[] = {{FFlag::LuauSolverV2, false}};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type T = {read [string]: number}
|
||||
|
@ -146,9 +146,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_locals_via_assignment_from_its_call_site")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "infer_in_nocheck_mode")
|
||||
{
|
||||
ScopedFastFlag sff[]{
|
||||
{FFlag::LuauSolverV2, false},
|
||||
};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!nocheck
|
||||
@ -225,7 +223,7 @@ TEST_CASE_FIXTURE(Fixture, "statements_are_topologically_sorted")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "unify_nearly_identical_recursive_types")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local o
|
||||
@ -266,7 +264,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "weird_case")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "dont_ice_when_failing_the_occurs_check")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -385,7 +383,7 @@ TEST_CASE_FIXTURE(Fixture, "exponential_blowup_from_copying_types")
|
||||
// checker. We also want it to somewhat match up with production values, so we push up the parser recursion limit a little bit instead.
|
||||
TEST_CASE_FIXTURE(Fixture, "check_type_infer_recursion_count")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
#if defined(LUAU_ENABLE_ASAN)
|
||||
int limit = 250;
|
||||
@ -443,7 +441,7 @@ TEST_CASE_FIXTURE(Fixture, "check_expr_recursion_limit")
|
||||
TEST_CASE_FIXTURE(Fixture, "globals")
|
||||
{
|
||||
// The new solver does not permit assignments to globals like this.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
@ -457,7 +455,7 @@ TEST_CASE_FIXTURE(Fixture, "globals")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "globals2")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!nonstrict
|
||||
@ -507,7 +505,7 @@ TEST_CASE_FIXTURE(Fixture, "correctly_scope_locals_do")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "checking_should_not_ice")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CHECK_NOTHROW(check(R"(
|
||||
--!nonstrict
|
||||
@ -601,7 +599,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_after_error_recovery_no_assert")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_in_error")
|
||||
{
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -623,7 +621,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tc_after_error_recovery_no_replacement_name_
|
||||
}
|
||||
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -698,7 +696,7 @@ TEST_CASE_FIXTURE(Fixture, "cli_39932_use_unifier_in_ensure_methods")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstStatError")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
foo
|
||||
@ -709,7 +707,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstStatError")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "dont_report_type_errors_within_an_AstExprError")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local a = foo:
|
||||
@ -1100,7 +1098,7 @@ end
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "cli_50041_committing_txnlog_in_apollo_client_error")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
@ -1223,7 +1221,7 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_cache_limit_normalizer")
|
||||
TEST_CASE_FIXTURE(Fixture, "follow_on_new_types_in_substitution")
|
||||
{
|
||||
// CLI-114134
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local obj = {}
|
||||
@ -1564,7 +1562,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "lti_must_record_contributing_locations")
|
||||
*/
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "be_sure_to_use_active_txnlog_when_evaluating_a_variadic_overload")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function concat<T>(target: {T}, ...: {T} | T): {T}
|
||||
|
@ -17,7 +17,7 @@ LUAU_FASTFLAG(LuauUnifierRecursionOnRestart);
|
||||
struct TryUnifyFixture : Fixture
|
||||
{
|
||||
// Cannot use `TryUnifyFixture` under DCR.
|
||||
ScopedFastFlag noDcr{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
TypeArena arena;
|
||||
ScopePtr globalScope{new Scope{arena.addTypePack({TypeId{}})}};
|
||||
@ -154,7 +154,7 @@ TEST_CASE_FIXTURE(Fixture, "uninhabited_intersection_sub_anything")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_never")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(arg : { prop : string & number }) : never
|
||||
@ -166,7 +166,7 @@ TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_never")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_anything")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(arg : { prop : string & number }) : boolean
|
||||
@ -178,7 +178,7 @@ TEST_CASE_FIXTURE(Fixture, "uninhabited_table_sub_anything")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "members_of_failed_typepack_unification_are_unified_with_errorType")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(arg: number) end
|
||||
@ -195,7 +195,7 @@ TEST_CASE_FIXTURE(Fixture, "members_of_failed_typepack_unification_are_unified_w
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "result_of_failed_typepack_unification_is_constrained")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(arg: number) return arg end
|
||||
|
@ -787,7 +787,7 @@ local d: Y<number, string, ...boolean, ...() -> ()>
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Y<T = T> = { a: T }
|
||||
@ -811,7 +811,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors2")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors3")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Y<T = string, U... = ...string> = { a: (T) -> U... }
|
||||
@ -824,7 +824,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors3")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "type_alias_default_type_errors4")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Packed<T> = (T) -> T
|
||||
@ -1065,7 +1065,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "detect_cyclic_typepacks2")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "unify_variadic_tails_in_arguments")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function foo(...: string): number
|
||||
|
@ -36,7 +36,7 @@ TEST_CASE_FIXTURE(Fixture, "return_types_can_be_disjoint")
|
||||
{
|
||||
// CLI-114134 We need egraphs to consistently reduce the cyclic union
|
||||
// introduced by the increment here.
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local count = 0
|
||||
@ -122,7 +122,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_arguments")
|
||||
TEST_CASE_FIXTURE(Fixture, "optional_arguments_table")
|
||||
{
|
||||
// CLI-115588 - Bidirectional inference does not happen for assignments
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local a:{a:string, b:string?}
|
||||
@ -478,7 +478,7 @@ end
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "unify_unsealed_table_union_check")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local x = { x = 3 }
|
||||
@ -653,7 +653,7 @@ TEST_CASE_FIXTURE(Fixture, "indexing_into_a_cyclic_union_doesnt_crash")
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "table_union_write_indirect")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type A = { x: number, y: (number) -> string } | { z: number, y: (number) -> string }
|
||||
@ -729,7 +729,7 @@ TEST_CASE_FIXTURE(Fixture, "union_of_generic_typepack_functions")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "union_of_functions_mentioning_generics")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f<a,b>()
|
||||
@ -749,7 +749,7 @@ TEST_CASE_FIXTURE(Fixture, "union_of_functions_mentioning_generics")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "union_of_functions_mentioning_generic_typepacks")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f<a...>()
|
||||
@ -770,7 +770,7 @@ could not be converted into
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_mismatching_arg_arities")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(x : (number) -> number?)
|
||||
@ -789,7 +789,7 @@ could not be converted into
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_mismatching_result_arities")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(x : () -> (number | string))
|
||||
@ -808,7 +808,7 @@ could not be converted into
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_variadics")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(x : (...nil) -> (...number?))
|
||||
@ -854,7 +854,7 @@ could not be converted into
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "union_of_functions_with_mismatching_result_variadics")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(x : () -> (number?, ...number))
|
||||
@ -922,7 +922,7 @@ TEST_CASE_FIXTURE(Fixture, "union_table_any_property")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "union_function_any_args")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(sup : ((...any) -> (...any))?, sub : ((number) -> (...any)))
|
||||
@ -946,7 +946,7 @@ TEST_CASE_FIXTURE(Fixture, "optional_any")
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_function_with_optional_arg")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f<T>(x : T?) : {T}
|
||||
|
@ -538,9 +538,7 @@ TEST_SUITE_BEGIN("TypePathToString");
|
||||
|
||||
TEST_CASE("field")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, false},
|
||||
};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CHECK(toString(PathBuilder().prop("foo").build()) == R"(["foo"])");
|
||||
}
|
||||
@ -567,9 +565,7 @@ TEST_CASE("empty_path")
|
||||
|
||||
TEST_CASE("prop")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, false},
|
||||
};
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
Path p = PathBuilder().prop("foo").build();
|
||||
CHECK(p == Path(TypePath::Property{"foo"}));
|
||||
|
@ -138,4 +138,17 @@ end)
|
||||
|
||||
coroutine.resume(wrapped2)
|
||||
|
||||
local wrapped3 = coroutine.create(function()
|
||||
local thread = coroutine.create(function(target)
|
||||
for i = 1, 100 do pcall(debug.info, target, 0, "?f") end
|
||||
return 123
|
||||
end)
|
||||
|
||||
local success, res = coroutine.resume(thread, coroutine.running())
|
||||
assert(success)
|
||||
assert(res == 123)
|
||||
end)
|
||||
|
||||
coroutine.resume(wrapped3)
|
||||
|
||||
return 'OK'
|
||||
|
159
tests/conformance/vector_library.lua
Normal file
159
tests/conformance/vector_library.lua
Normal file
@ -0,0 +1,159 @@
|
||||
-- This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
print('testing vector library')
|
||||
|
||||
function ecall(fn, ...)
|
||||
local ok, err = pcall(fn, ...)
|
||||
assert(not ok)
|
||||
return err:sub((err:find(": ") or -1) + 2, #err)
|
||||
end
|
||||
|
||||
-- make sure we cover both builtin and C impl
|
||||
assert(vector.create(1, 2, 4) == vector.create("1", "2", "4"))
|
||||
|
||||
-- testing 'dot' with error handling and different call kinds to mostly check details in the codegen
|
||||
assert(vector.dot(vector.create(1, 2, 4), vector.create(5, 6, 7)) == 45)
|
||||
assert(ecall(function() vector.dot(vector.create(1, 2, 4)) end) == "missing argument #2 to 'dot' (vector expected)")
|
||||
assert(ecall(function() vector.dot(vector.create(1, 2, 4), 2) end) == "invalid argument #2 to 'dot' (vector expected, got number)")
|
||||
|
||||
local function doDot1(a: vector, b)
|
||||
return vector.dot(a, b)
|
||||
end
|
||||
|
||||
local function doDot2(a: vector, b)
|
||||
return (vector.dot(a, b))
|
||||
end
|
||||
|
||||
local v124 = vector.create(1, 2, 4)
|
||||
|
||||
assert(doDot1(v124, vector.create(5, 6, 7)) == 45)
|
||||
assert(doDot2(v124, vector.create(5, 6, 7)) == 45)
|
||||
assert(ecall(function() doDot1(v124, "a") end) == "invalid argument #2 to 'dot' (vector expected, got string)")
|
||||
assert(ecall(function() doDot2(v124, "a") end) == "invalid argument #2 to 'dot' (vector expected, got string)")
|
||||
assert(select("#", doDot1(v124, vector.create(5, 6, 7))) == 1)
|
||||
assert(select("#", doDot2(v124, vector.create(5, 6, 7))) == 1)
|
||||
|
||||
-- 'cross' tests and next ones will only test basic results
|
||||
assert(vector.cross(vector.create(1, 0, 0), vector.create(0, 1, 0)) == vector.create(0, 0, 1))
|
||||
assert(vector.cross(vector.create(0, 1, 0), vector.create(1, 0, 0)) == vector.create(0, 0, -1))
|
||||
assert(select("#", vector.cross(vector.zero, vector.one)) == 1)
|
||||
|
||||
-- 'normalize'
|
||||
assert(vector.normalize(vector.create(0.5, 0, 0)) == vector.create(1, 0, 0))
|
||||
assert(select("#", vector.normalize(vector.one)) == 1)
|
||||
|
||||
-- 'magnitude'
|
||||
assert(vector.magnitude(vector.create(1, 2, 2)) == 3)
|
||||
assert(select("#", vector.magnitude(vector.one)) == 1)
|
||||
|
||||
-- 'abs'
|
||||
assert(vector.abs(-vector.one) == vector.one)
|
||||
assert(vector.abs(vector.create(math.huge, 0, 0)).x == math.abs(math.huge))
|
||||
assert(vector.abs(vector.create(0/0, 0, 0)).x ~= 0/0)
|
||||
assert(select("#", vector.abs(vector.one)) == 1)
|
||||
|
||||
-- 'floor'
|
||||
assert(vector.floor(vector.create(1, 2, 3)) == vector.create(1, 2, 3))
|
||||
assert(vector.floor(vector.create(1.5, 2.4, 3)) == vector.create(1, 2, 3))
|
||||
assert(vector.floor(vector.create(-1.5, -2.4, -3)) == vector.create(-2, -3, -3))
|
||||
assert(select("#", vector.floor(vector.one)) == 1)
|
||||
|
||||
-- 'ceil'
|
||||
assert(vector.ceil(vector.create(1, 2, 3)) == vector.create(1, 2, 3))
|
||||
assert(vector.ceil(vector.create(1.5, 2.4, 3)) == vector.create(2, 3, 3))
|
||||
assert(vector.ceil(vector.create(-1.5, -2.4, -3)) == vector.create(-1, -2, -3))
|
||||
assert(select("#", vector.ceil(vector.one)) == 1)
|
||||
|
||||
-- 'sign'
|
||||
assert(vector.sign(vector.zero) == vector.zero)
|
||||
assert(vector.sign(vector.one) == vector.one)
|
||||
assert(vector.sign(vector.create(-10, 0, 10)) == vector.create(-1, 0, 1))
|
||||
assert(vector.sign(vector.create(math.huge, 0, -math.huge)) == vector.create(1, 0, -1))
|
||||
-- negative zero and nan are consistent with math library, even if implementation defined
|
||||
assert(vector.sign(vector.create(-0, 0, 0)).x == math.sign(-0))
|
||||
assert(vector.sign(vector.create(0/0, 0, 0)).x == math.sign(0/0))
|
||||
assert(select("#", vector.sign(vector.one)) == 1)
|
||||
|
||||
-- 'angle'
|
||||
assert(math.abs(vector.angle(vector.create(1, 2, 3), vector.create(4, 5, 6)) - 0.2257259) < 0.00001)
|
||||
assert(select("#", vector.angle(vector.zero, vector.one)) == 1)
|
||||
assert(select("#", vector.angle(vector.one, -vector.one, vector.zero)) == 1)
|
||||
|
||||
do
|
||||
-- random (non-unit) vectors
|
||||
local rand = {
|
||||
vector.create(-1.05, -0.04, 1.06),
|
||||
vector.create(-0.75, 1.71, 1.29),
|
||||
vector.create(1.94, 0.76, -0.93),
|
||||
vector.create(0.02, -1.58, 0.20),
|
||||
vector.create(1.64, -0.76, -0.73),
|
||||
vector.create(-2.44, 0.66, 1.06),
|
||||
vector.create(-2.61, 1.01, 0.50),
|
||||
vector.create(1.21, -2.28, -0.45),
|
||||
vector.create(-0.31, -0.12, 1.96),
|
||||
vector.create(1.16, -0.07, -1.93)
|
||||
}
|
||||
|
||||
-- numeric answers to the tests below (in degrees)
|
||||
local ans = {
|
||||
-105.1702,
|
||||
-69.49491,
|
||||
0.0,
|
||||
-102.9083,
|
||||
0.0,
|
||||
0.0,
|
||||
180.0,
|
||||
-0.02797646,
|
||||
-90.0,
|
||||
165.8858
|
||||
}
|
||||
|
||||
for i,v in ans do
|
||||
ans[i] = math.rad(ans[i])
|
||||
end
|
||||
|
||||
local function fuzzyeq(x, y, eps) return x == y or math.abs(x - y) < (eps or 1e-6) end
|
||||
|
||||
assert(fuzzyeq(vector.angle(rand[10], rand[1]), math.abs(ans[10])))
|
||||
assert(fuzzyeq(vector.angle(rand[2], rand[3]), math.abs(ans[1])))
|
||||
assert(fuzzyeq(vector.angle(rand[4], rand[5]), math.abs(ans[2])))
|
||||
assert(fuzzyeq(vector.angle(vector.zero, rand[6]), math.abs(ans[3])))
|
||||
assert(fuzzyeq(vector.angle(vector.one, rand[7]), math.abs(ans[4])))
|
||||
assert(fuzzyeq(vector.angle(vector.zero, vector.zero), math.abs(ans[5])))
|
||||
assert(fuzzyeq(vector.angle(rand[8], rand[8]), math.abs(ans[6])))
|
||||
assert(fuzzyeq(vector.angle(-rand[8], rand[8]), math.abs(ans[7])))
|
||||
assert(fuzzyeq(vector.angle(rand[9], rand[9] + vector.create(0, 1, 0) * 0.001), math.abs(ans[8]), 1e-3)) -- slightly more generous eps
|
||||
assert(fuzzyeq(vector.angle(vector.create(1, 0, 0), vector.create(0, 1, 0)), math.abs(ans[9])))
|
||||
|
||||
assert(fuzzyeq(vector.angle(rand[10], rand[1], rand[2]), ans[10]))
|
||||
assert(fuzzyeq(vector.angle(rand[2], rand[3], rand[4]), ans[1]))
|
||||
assert(fuzzyeq(vector.angle(rand[4], rand[5], rand[5]), ans[2]))
|
||||
assert(fuzzyeq(vector.angle(vector.zero, rand[6], rand[10]), ans[3]))
|
||||
assert(fuzzyeq(vector.angle(vector.one, rand[7], rand[10]), ans[4]))
|
||||
assert(fuzzyeq(vector.angle(vector.zero, vector.zero, vector.zero), ans[5]))
|
||||
assert(fuzzyeq(vector.angle(rand[8], rand[8], rand[10]), ans[6]))
|
||||
assert(fuzzyeq(vector.angle(rand[9], rand[9] + vector.create(0, 1, 0) * 0.001, rand[10]), ans[8], 1e-3)) -- slightly more generous eps
|
||||
assert(fuzzyeq(vector.angle(vector.create(1, 0, 0), vector.create(0, 1, 0), rand[10]), ans[9]))
|
||||
end
|
||||
|
||||
-- 'min'/'max'
|
||||
assert(vector.max(vector.create(-1, 2, 0.5)) == vector.create(-1, 2, 0.5))
|
||||
assert(vector.min(vector.create(-1, 2, 0.5)) == vector.create(-1, 2, 0.5))
|
||||
|
||||
assert(ecall(function() vector.min() end) == "missing argument #1 to 'min' (vector expected)")
|
||||
assert(ecall(function() vector.max() end) == "missing argument #1 to 'max' (vector expected)")
|
||||
|
||||
assert(select("#", vector.max(vector.zero, vector.one)) == 1)
|
||||
assert(select("#", vector.min(vector.zero, vector.one)) == 1)
|
||||
|
||||
assert(vector.max(vector.create(-1, 2, 3), vector.create(3, 2, 1)) == vector.create(3, 2, 3))
|
||||
assert(vector.min(vector.create(-1, 2, 3), vector.create(3, 2, 1)) == vector.create(-1, 2, 1))
|
||||
|
||||
assert(vector.max(vector.create(1, 2, 3),vector.create(2, 3, 4),vector.create(3, 4, 5),vector.create(4, 5, 6)) == vector.create(4, 5, 6))
|
||||
assert(vector.min(vector.create(1, 2, 3),vector.create(2, 3, 4),vector.create(3, 4, 5),vector.create(4, 5, 6)) == vector.create(1, 2, 3))
|
||||
|
||||
-- clamp
|
||||
assert(vector.clamp(vector.create(1, 1, 1), vector.create(0, 1, 2), vector.create(3, 3, 3)) == vector.create(1, 1, 2))
|
||||
assert(vector.clamp(vector.create(1, 1, 1), vector.create(-1, -1, -1), vector.create(0, 1, 2)) == vector.create(0, 1, 1))
|
||||
assert(select("#", vector.clamp(vector.zero, vector.zero, vector.one)) == 1)
|
||||
|
||||
return 'OK'
|
Loading…
Reference in New Issue
Block a user