mirror of
https://github.com/luau-lang/luau.git
synced 2025-03-03 18:51:42 +00:00
Sync to upstream/release/663
This commit is contained in:
parent
279e15a52f
commit
b6ca2a0c5e
111 changed files with 1020 additions and 1130 deletions
|
@ -96,6 +96,9 @@ struct ConstraintGenerator
|
|||
// will enqueue them during solving.
|
||||
std::vector<ConstraintPtr> unqueuedConstraints;
|
||||
|
||||
// Map a function's signature scope back to its signature type.
|
||||
DenseHashMap<Scope*, TypeId> scopeToFunction{nullptr};
|
||||
|
||||
// The private scope of type aliases for which the type parameters belong to.
|
||||
DenseHashMap<const AstStatTypeAlias*, ScopePtr> astTypeAliasDefiningScopes{nullptr};
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@ struct ConstraintSolver
|
|||
NotNull<TypeFunctionRuntime> typeFunctionRuntime;
|
||||
// The entire set of constraints that the solver is trying to resolve.
|
||||
std::vector<NotNull<Constraint>> constraints;
|
||||
NotNull<DenseHashMap<Scope*, TypeId>> scopeToFunction;
|
||||
NotNull<Scope> rootScope;
|
||||
ModuleName currentModuleName;
|
||||
|
||||
|
@ -119,6 +120,7 @@ struct ConstraintSolver
|
|||
DenseHashMap<TypeId, size_t> unresolvedConstraints{{}};
|
||||
|
||||
std::unordered_map<NotNull<const Constraint>, DenseHashSet<TypeId>> maybeMutatedFreeTypes;
|
||||
std::unordered_map<TypeId, DenseHashSet<const Constraint*>> mutatedFreeTypeToConstraint;
|
||||
|
||||
// Irreducible/uninhabited type functions or type pack functions.
|
||||
DenseHashSet<const void*> uninhabitedTypeFunctions{{}};
|
||||
|
@ -144,6 +146,7 @@ struct ConstraintSolver
|
|||
NotNull<TypeFunctionRuntime> typeFunctionRuntime,
|
||||
NotNull<Scope> rootScope,
|
||||
std::vector<NotNull<Constraint>> constraints,
|
||||
NotNull<DenseHashMap<Scope*, TypeId>> scopeToFunction,
|
||||
ModuleName moduleName,
|
||||
NotNull<ModuleResolver> moduleResolver,
|
||||
std::vector<RequireCycle> requireCycles,
|
||||
|
@ -171,6 +174,8 @@ struct ConstraintSolver
|
|||
bool isDone() const;
|
||||
|
||||
private:
|
||||
void generalizeOneType(TypeId ty);
|
||||
|
||||
/**
|
||||
* Bind a type variable to another type.
|
||||
*
|
||||
|
|
|
@ -82,5 +82,65 @@ FragmentAutocompleteResult fragmentAutocomplete(
|
|||
std::optional<Position> fragmentEndPosition = std::nullopt
|
||||
);
|
||||
|
||||
enum class FragmentAutocompleteStatus
|
||||
{
|
||||
Success,
|
||||
FragmentTypeCheckFail,
|
||||
InternalIce
|
||||
};
|
||||
|
||||
struct FragmentAutocompleteStatusResult
|
||||
{
|
||||
FragmentAutocompleteStatus status;
|
||||
std::optional<FragmentAutocompleteResult> result;
|
||||
};
|
||||
|
||||
struct FragmentContext
|
||||
{
|
||||
std::string_view newSrc;
|
||||
const ParseResult& newAstRoot;
|
||||
std::optional<FrontendOptions> opts;
|
||||
std::optional<Position> DEPRECATED_fragmentEndPosition;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Attempts to compute autocomplete suggestions from the fragment context.
|
||||
*
|
||||
* This function computes autocomplete suggestions using outdated frontend typechecking data
|
||||
* by patching the fragment context of the new script source content.
|
||||
*
|
||||
* @param frontend The Luau Frontend data structure, which may contain outdated typechecking data.
|
||||
*
|
||||
* @param moduleName The name of the target module, specifying which script the caller wants to request autocomplete for.
|
||||
*
|
||||
* @param cursorPosition The position in the script where the caller wants to trigger autocomplete.
|
||||
*
|
||||
* @param context The fragment context that this API will use to patch the outdated typechecking data.
|
||||
*
|
||||
* @param stringCompletionCB A callback function that provides autocomplete suggestions for string contexts.
|
||||
*
|
||||
* @return
|
||||
* The status indicating whether `fragmentAutocomplete` ran successfully or failed, along with the reason for failure.
|
||||
* Also includes autocomplete suggestions if the status is successful.
|
||||
*
|
||||
* @usage
|
||||
* FragmentAutocompleteStatusResult acStatusResult;
|
||||
* if (shouldFragmentAC)
|
||||
* acStatusResult = Luau::tryFragmentAutocomplete(...);
|
||||
*
|
||||
* if (acStatusResult.status != Successful)
|
||||
* {
|
||||
* frontend.check(moduleName, options);
|
||||
* acStatusResult.acResult = Luau::autocomplete(...);
|
||||
* }
|
||||
* return convertResultWithContext(acStatusResult.acResult);
|
||||
*/
|
||||
FragmentAutocompleteStatusResult tryFragmentAutocomplete(
|
||||
Frontend& frontend,
|
||||
const ModuleName& moduleName,
|
||||
Position cursorPosition,
|
||||
FragmentContext context,
|
||||
StringCompletionCallback stringCompletionCB
|
||||
);
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include "Luau/NotNull.h"
|
||||
#include "Luau/TypeFwd.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
|
|
@ -65,11 +65,10 @@ T* getMutable(PendingTypePack* pending)
|
|||
// Log of what TypeIds we are rebinding, to be committed later.
|
||||
struct TxnLog
|
||||
{
|
||||
explicit TxnLog(bool useScopes = false)
|
||||
explicit TxnLog()
|
||||
: typeVarChanges(nullptr)
|
||||
, typePackChanges(nullptr)
|
||||
, ownedSeen()
|
||||
, useScopes(useScopes)
|
||||
, sharedSeen(&ownedSeen)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -216,7 +216,11 @@ struct TypeFunctionClassType
|
|||
|
||||
std::optional<TypeFunctionTypeId> metatable; // metaclass?
|
||||
|
||||
std::optional<TypeFunctionTypeId> parent;
|
||||
// this was mistaken, and we should actually be keeping separate read/write types here.
|
||||
std::optional<TypeFunctionTypeId> parent_DEPRECATED;
|
||||
|
||||
std::optional<TypeFunctionTypeId> readParent;
|
||||
std::optional<TypeFunctionTypeId> writeParent;
|
||||
|
||||
TypeId classTy;
|
||||
|
||||
|
|
|
@ -93,10 +93,6 @@ struct Unifier
|
|||
|
||||
Unifier(NotNull<Normalizer> normalizer, NotNull<Scope> scope, const Location& location, Variance variance, TxnLog* parentLog = nullptr);
|
||||
|
||||
// Configure the Unifier to test for scope subsumption via embedded Scope
|
||||
// pointers rather than TypeLevels.
|
||||
void enableNewSolver();
|
||||
|
||||
// Test whether the two type vars unify. Never commits the result.
|
||||
ErrorVec canUnify(TypeId subTy, TypeId superTy);
|
||||
ErrorVec canUnify(TypePackId subTy, TypePackId superTy, bool isFunctionCall = false);
|
||||
|
@ -169,7 +165,6 @@ private:
|
|||
|
||||
std::optional<TypeId> findTablePropertyRespectingMeta(TypeId lhsType, Name name);
|
||||
|
||||
TxnLog combineLogsIntoIntersection(std::vector<TxnLog> logs);
|
||||
TxnLog combineLogsIntoUnion(std::vector<TxnLog> logs);
|
||||
|
||||
public:
|
||||
|
@ -195,11 +190,6 @@ private:
|
|||
|
||||
// Available after regular type pack unification errors
|
||||
std::optional<int> firstPackErrorPos;
|
||||
|
||||
// If true, we do a bunch of small things differently to work better with
|
||||
// the new type inference engine. Most notably, we use the Scope hierarchy
|
||||
// directly rather than using TypeLevels.
|
||||
bool useNewSolver = false;
|
||||
};
|
||||
|
||||
void promoteTypeLevels(TxnLog& log, const TypeArena* arena, TypeLevel minLevel, Scope* outerScope, bool useScope, TypePackId tp);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "Luau/Autocomplete.h"
|
||||
|
||||
#include "Luau/AstQuery.h"
|
||||
#include "Luau/TimeTrace.h"
|
||||
#include "Luau/TypeArena.h"
|
||||
#include "Luau/Module.h"
|
||||
#include "Luau/Frontend.h"
|
||||
|
@ -15,6 +16,9 @@ namespace Luau
|
|||
|
||||
AutocompleteResult autocomplete(Frontend& frontend, const ModuleName& moduleName, Position position, StringCompletionCallback callback)
|
||||
{
|
||||
LUAU_TIMETRACE_SCOPE("Luau::autocomplete", "Autocomplete");
|
||||
LUAU_TIMETRACE_ARGUMENT("name", moduleName.c_str());
|
||||
|
||||
const SourceModule* sourceModule = frontend.getSourceModule(moduleName);
|
||||
if (!sourceModule)
|
||||
return {};
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Luau/Common.h"
|
||||
#include "Luau/FileResolver.h"
|
||||
#include "Luau/Frontend.h"
|
||||
#include "Luau/TimeTrace.h"
|
||||
#include "Luau/ToString.h"
|
||||
#include "Luau/Subtyping.h"
|
||||
#include "Luau/TypeInfer.h"
|
||||
|
@ -24,7 +25,8 @@ LUAU_FASTINT(LuauTypeInferIterationLimit)
|
|||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauAutocompleteRefactorsForIncrementalAutocomplete)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAutocompleteUseLimits)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauAutocompleteUsesModuleForTypeCompatibility)
|
||||
|
||||
static const std::unordered_set<std::string> kStatementStartingKeywords =
|
||||
{"while", "if", "local", "repeat", "function", "do", "for", "return", "break", "continue", "type", "export"};
|
||||
|
@ -146,14 +148,22 @@ static std::optional<TypeId> findExpectedTypeAt(const Module& module, AstNode* n
|
|||
return *it;
|
||||
}
|
||||
|
||||
static bool checkTypeMatch(TypeId subTy, TypeId superTy, NotNull<Scope> scope, TypeArena* typeArena, NotNull<BuiltinTypes> builtinTypes)
|
||||
static bool checkTypeMatch(
|
||||
const Module& module,
|
||||
TypeId subTy,
|
||||
TypeId superTy,
|
||||
NotNull<Scope> scope,
|
||||
TypeArena* typeArena,
|
||||
NotNull<BuiltinTypes> builtinTypes
|
||||
)
|
||||
{
|
||||
InternalErrorReporter iceReporter;
|
||||
UnifierSharedState unifierState(&iceReporter);
|
||||
SimplifierPtr simplifier = newSimplifier(NotNull{typeArena}, builtinTypes);
|
||||
Normalizer normalizer{typeArena, builtinTypes, NotNull{&unifierState}};
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauAutocompleteUsesModuleForTypeCompatibility)
|
||||
{
|
||||
if (module.checkedInNewSolver)
|
||||
{
|
||||
TypeCheckLimits limits;
|
||||
TypeFunctionRuntime typeFunctionRuntime{
|
||||
|
@ -164,7 +174,12 @@ static bool checkTypeMatch(TypeId subTy, TypeId superTy, NotNull<Scope> scope, T
|
|||
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
|
||||
|
||||
Subtyping subtyping{
|
||||
builtinTypes, NotNull{typeArena}, NotNull{simplifier.get()}, NotNull{&normalizer}, NotNull{&typeFunctionRuntime}, NotNull{&iceReporter}
|
||||
builtinTypes,
|
||||
NotNull{typeArena},
|
||||
NotNull{simplifier.get()},
|
||||
NotNull{&normalizer},
|
||||
NotNull{&typeFunctionRuntime},
|
||||
NotNull{&iceReporter}
|
||||
};
|
||||
|
||||
return subtyping.isSubtype(subTy, superTy, scope).isSubtype;
|
||||
|
@ -177,15 +192,49 @@ static bool checkTypeMatch(TypeId subTy, TypeId superTy, NotNull<Scope> scope, T
|
|||
unifier.normalize = false;
|
||||
unifier.checkInhabited = false;
|
||||
|
||||
if (FFlag::LuauAutocompleteUseLimits)
|
||||
{
|
||||
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
|
||||
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
|
||||
}
|
||||
|
||||
return unifier.canUnify(subTy, superTy).empty();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
TypeCheckLimits limits;
|
||||
TypeFunctionRuntime typeFunctionRuntime{
|
||||
NotNull{&iceReporter}, NotNull{&limits}
|
||||
}; // TODO: maybe subtyping checks should not invoke user-defined type function runtime
|
||||
|
||||
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
|
||||
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
|
||||
|
||||
Subtyping subtyping{
|
||||
builtinTypes,
|
||||
NotNull{typeArena},
|
||||
NotNull{simplifier.get()},
|
||||
NotNull{&normalizer},
|
||||
NotNull{&typeFunctionRuntime},
|
||||
NotNull{&iceReporter}
|
||||
};
|
||||
|
||||
return subtyping.isSubtype(subTy, superTy, scope).isSubtype;
|
||||
}
|
||||
else
|
||||
{
|
||||
Unifier unifier(NotNull<Normalizer>{&normalizer}, scope, Location(), Variance::Covariant);
|
||||
|
||||
// Cost of normalization can be too high for autocomplete response time requirements
|
||||
unifier.normalize = false;
|
||||
unifier.checkInhabited = false;
|
||||
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
|
||||
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
|
||||
|
||||
return unifier.canUnify(subTy, superTy).empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static TypeCorrectKind checkTypeCorrectKind(
|
||||
const Module& module,
|
||||
|
@ -209,10 +258,10 @@ static TypeCorrectKind checkTypeCorrectKind(
|
|||
|
||||
TypeId expectedType = follow(*typeAtPosition);
|
||||
|
||||
auto checkFunctionType = [typeArena, builtinTypes, moduleScope, &expectedType](const FunctionType* ftv)
|
||||
auto checkFunctionType = [typeArena, builtinTypes, moduleScope, &expectedType, &module](const FunctionType* ftv)
|
||||
{
|
||||
if (std::optional<TypeId> firstRetTy = first(ftv->retTypes))
|
||||
return checkTypeMatch(*firstRetTy, expectedType, moduleScope, typeArena, builtinTypes);
|
||||
return checkTypeMatch(module, *firstRetTy, expectedType, moduleScope, typeArena, builtinTypes);
|
||||
|
||||
return false;
|
||||
};
|
||||
|
@ -235,7 +284,7 @@ static TypeCorrectKind checkTypeCorrectKind(
|
|||
}
|
||||
}
|
||||
|
||||
return checkTypeMatch(ty, expectedType, moduleScope, typeArena, builtinTypes) ? TypeCorrectKind::Correct : TypeCorrectKind::None;
|
||||
return checkTypeMatch(module, ty, expectedType, moduleScope, typeArena, builtinTypes) ? TypeCorrectKind::Correct : TypeCorrectKind::None;
|
||||
}
|
||||
|
||||
enum class PropIndexType
|
||||
|
@ -286,7 +335,7 @@ static void autocompleteProps(
|
|||
// When called with '.', but declared with 'self', it is considered invalid if first argument is compatible
|
||||
if (std::optional<TypeId> firstArgTy = first(ftv->argTypes))
|
||||
{
|
||||
if (checkTypeMatch(rootTy, *firstArgTy, NotNull{module.getModuleScope().get()}, typeArena, builtinTypes))
|
||||
if (checkTypeMatch(module, rootTy, *firstArgTy, NotNull{module.getModuleScope().get()}, typeArena, builtinTypes))
|
||||
return calledWithSelf;
|
||||
}
|
||||
|
||||
|
@ -1714,6 +1763,7 @@ AutocompleteResult autocomplete_(
|
|||
StringCompletionCallback callback
|
||||
)
|
||||
{
|
||||
LUAU_TIMETRACE_SCOPE("Luau::autocomplete_", "AutocompleteCore");
|
||||
AstNode* node = ancestry.back();
|
||||
|
||||
AstExprConstantNil dummy{Location{}};
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include "Luau/Constraint.h"
|
||||
#include "Luau/VisitType.h"
|
||||
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -111,6 +113,11 @@ DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
|
|||
{
|
||||
rci.traverse(fchc->argsPack);
|
||||
}
|
||||
else if (auto fcc = get<FunctionCallConstraint>(*this); fcc && FFlag::DebugLuauGreedyGeneralization)
|
||||
{
|
||||
rci.traverse(fcc->fn);
|
||||
rci.traverse(fcc->argsPack);
|
||||
}
|
||||
else if (auto ptc = get<PrimitiveTypeConstraint>(*this))
|
||||
{
|
||||
rci.traverse(ptc->freeType);
|
||||
|
@ -118,7 +125,8 @@ DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
|
|||
else if (auto hpc = get<HasPropConstraint>(*this))
|
||||
{
|
||||
rci.traverse(hpc->resultType);
|
||||
// `HasPropConstraints` should not mutate `subjectType`.
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
rci.traverse(hpc->subjectType);
|
||||
}
|
||||
else if (auto hic = get<HasIndexerConstraint>(*this))
|
||||
{
|
||||
|
|
|
@ -32,11 +32,11 @@ LUAU_FASTINT(LuauCheckRecursionLimit)
|
|||
LUAU_FASTFLAG(DebugLuauLogSolverToJson)
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_FASTFLAG(LuauPreserveUnionIntersectionNodeForLeadingTokenSingleType)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewSolverPrePopulateClasses)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewSolverPopulateTableLocations)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTrackInteriorFreeTypesOnScope)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDeferBidirectionalInferenceForTableAssignment)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUngeneralizedTypesForRecursiveFunctions)
|
||||
|
||||
LUAU_FASTFLAG(LuauFreeTypesMustHaveBounds)
|
||||
LUAU_FASTFLAGVARIABLE(LuauInferLocalTypesInMultipleAssignments)
|
||||
|
@ -785,9 +785,6 @@ void ConstraintGenerator::checkAliases(const ScopePtr& scope, AstStatBlock* bloc
|
|||
}
|
||||
else if (auto classDeclaration = stat->as<AstStatDeclareClass>())
|
||||
{
|
||||
if (!FFlag::LuauNewSolverPrePopulateClasses)
|
||||
continue;
|
||||
|
||||
if (scope->exportedTypeBindings.count(classDeclaration->name.value))
|
||||
{
|
||||
auto it = classDefinitionLocations.find(classDeclaration->name.value);
|
||||
|
@ -1384,6 +1381,28 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatFunction* f
|
|||
FunctionSignature sig = checkFunctionSignature(scope, function->func, /* expectedType */ std::nullopt, function->name->location);
|
||||
bool sigFullyDefined = !hasFreeType(sig.signature);
|
||||
|
||||
DefId def = dfg->getDef(function->name);
|
||||
|
||||
if (FFlag::LuauUngeneralizedTypesForRecursiveFunctions)
|
||||
{
|
||||
if (AstExprLocal* localName = function->name->as<AstExprLocal>())
|
||||
{
|
||||
sig.bodyScope->bindings[localName->local] = Binding{sig.signature, localName->location};
|
||||
sig.bodyScope->lvalueTypes[def] = sig.signature;
|
||||
sig.bodyScope->rvalueRefinements[def] = sig.signature;
|
||||
}
|
||||
else if (AstExprGlobal* globalName = function->name->as<AstExprGlobal>())
|
||||
{
|
||||
sig.bodyScope->bindings[globalName->name] = Binding{sig.signature, globalName->location};
|
||||
sig.bodyScope->lvalueTypes[def] = sig.signature;
|
||||
sig.bodyScope->rvalueRefinements[def] = sig.signature;
|
||||
}
|
||||
else if (AstExprIndexName* indexName = function->name->as<AstExprIndexName>())
|
||||
{
|
||||
sig.bodyScope->rvalueRefinements[def] = sig.signature;
|
||||
}
|
||||
}
|
||||
|
||||
checkFunctionBody(sig.bodyScope, function->func);
|
||||
Checkpoint end = checkpoint(this);
|
||||
|
||||
|
@ -1417,7 +1436,6 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatFunction* f
|
|||
);
|
||||
}
|
||||
|
||||
DefId def = dfg->getDef(function->name);
|
||||
std::optional<TypeId> existingFunctionTy = follow(lookup(scope, function->name->location, def));
|
||||
|
||||
if (AstExprLocal* localName = function->name->as<AstExprLocal>())
|
||||
|
@ -1691,7 +1709,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareClas
|
|||
{
|
||||
// If a class with the same name was already defined, we skip over
|
||||
auto bindingIt = scope->exportedTypeBindings.find(declaredClass->name.value);
|
||||
if (FFlag::LuauNewSolverPrePopulateClasses && bindingIt == scope->exportedTypeBindings.end())
|
||||
if (bindingIt == scope->exportedTypeBindings.end())
|
||||
return ControlFlow::None;
|
||||
|
||||
std::optional<TypeId> superTy = std::make_optional(builtinTypes->classType);
|
||||
|
@ -1708,10 +1726,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareClas
|
|||
|
||||
// We don't have generic classes, so this assertion _should_ never be hit.
|
||||
LUAU_ASSERT(lookupType->typeParams.size() == 0 && lookupType->typePackParams.size() == 0);
|
||||
if (FFlag::LuauNewSolverPrePopulateClasses)
|
||||
superTy = follow(lookupType->type);
|
||||
else
|
||||
superTy = lookupType->type;
|
||||
|
||||
if (!get<ClassType>(follow(*superTy)))
|
||||
{
|
||||
|
@ -1734,14 +1749,8 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareClas
|
|||
|
||||
ctv->metatable = metaTy;
|
||||
|
||||
|
||||
if (FFlag::LuauNewSolverPrePopulateClasses)
|
||||
{
|
||||
TypeId classBindTy = bindingIt->second.type;
|
||||
emplaceType<BoundType>(asMutable(classBindTy), classTy);
|
||||
}
|
||||
else
|
||||
scope->exportedTypeBindings[className] = TypeFun{{}, classTy};
|
||||
|
||||
if (declaredClass->indexer)
|
||||
{
|
||||
|
@ -2930,10 +2939,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
|
|||
|
||||
ttv->state = TableState::Unsealed;
|
||||
ttv->definitionModuleName = module->name;
|
||||
if (FFlag::LuauNewSolverPopulateTableLocations)
|
||||
{
|
||||
ttv->definitionLocation = expr->location;
|
||||
}
|
||||
ttv->scope = scope.get();
|
||||
|
||||
interiorTypes.back().push_back(ty);
|
||||
|
@ -3230,6 +3236,9 @@ ConstraintGenerator::FunctionSignature ConstraintGenerator::checkFunctionSignatu
|
|||
if (expectedType && get<FreeType>(*expectedType))
|
||||
bindFreeType(*expectedType, actualFunctionType);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
scopeToFunction[signatureScope.get()] = actualFunctionType;
|
||||
|
||||
return {
|
||||
/* signature */ actualFunctionType,
|
||||
/* signatureScope */ signatureScope,
|
||||
|
@ -3392,11 +3401,8 @@ TypeId ConstraintGenerator::resolveTableType(const ScopePtr& scope, AstType* ty,
|
|||
TypeId tableTy = arena->addType(TableType{props, indexer, scope->level, scope.get(), TableState::Sealed});
|
||||
TableType* ttv = getMutable<TableType>(tableTy);
|
||||
|
||||
if (FFlag::LuauNewSolverPopulateTableLocations)
|
||||
{
|
||||
ttv->definitionModuleName = module->name;
|
||||
ttv->definitionLocation = tab->location;
|
||||
}
|
||||
|
||||
return tableTy;
|
||||
}
|
||||
|
|
|
@ -27,17 +27,16 @@
|
|||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauAssertOnForcedConstraint)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolver)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverIncludeDependencies)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogBindings)
|
||||
LUAU_FASTINTVARIABLE(LuauSolverRecursionLimit, 500)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauNewSolverPopulateTableLocations)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAllowNilAssignmentToIndexer)
|
||||
LUAU_FASTFLAG(LuauTrackInteriorFreeTypesOnScope)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAlwaysFillInFunctionCallDiscriminantTypes)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTrackInteriorFreeTablesOnScope)
|
||||
LUAU_FASTFLAGVARIABLE(LuauPrecalculateMutatedFreeTypes2)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauGreedyGeneralization)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -328,6 +327,7 @@ ConstraintSolver::ConstraintSolver(
|
|||
NotNull<TypeFunctionRuntime> typeFunctionRuntime,
|
||||
NotNull<Scope> rootScope,
|
||||
std::vector<NotNull<Constraint>> constraints,
|
||||
NotNull<DenseHashMap<Scope*, TypeId>> scopeToFunction,
|
||||
ModuleName moduleName,
|
||||
NotNull<ModuleResolver> moduleResolver,
|
||||
std::vector<RequireCycle> requireCycles,
|
||||
|
@ -341,6 +341,7 @@ ConstraintSolver::ConstraintSolver(
|
|||
, simplifier(simplifier)
|
||||
, typeFunctionRuntime(typeFunctionRuntime)
|
||||
, constraints(std::move(constraints))
|
||||
, scopeToFunction(scopeToFunction)
|
||||
, rootScope(rootScope)
|
||||
, currentModuleName(std::move(moduleName))
|
||||
, dfg(dfg)
|
||||
|
@ -362,6 +363,12 @@ ConstraintSolver::ConstraintSolver(
|
|||
{
|
||||
auto [refCount, _] = unresolvedConstraints.try_insert(ty, 0);
|
||||
refCount += 1;
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
{
|
||||
auto [it, fresh] = mutatedFreeTypeToConstraint.try_emplace(ty, DenseHashSet<const Constraint*>{nullptr});
|
||||
it->second.insert(c.get());
|
||||
}
|
||||
}
|
||||
maybeMutatedFreeTypes.emplace(c, maybeMutatedTypesPerConstraint);
|
||||
}
|
||||
|
@ -453,6 +460,9 @@ void ConstraintSolver::run()
|
|||
snapshot = logger->prepareStepSnapshot(rootScope, c, force, unsolvedConstraints);
|
||||
}
|
||||
|
||||
if (FFlag::DebugLuauAssertOnForcedConstraint)
|
||||
LUAU_ASSERT(!force);
|
||||
|
||||
bool success = tryDispatch(c, force);
|
||||
|
||||
progress |= success;
|
||||
|
@ -467,12 +477,21 @@ void ConstraintSolver::run()
|
|||
const auto maybeMutated = maybeMutatedFreeTypes.find(c);
|
||||
if (maybeMutated != maybeMutatedFreeTypes.end())
|
||||
{
|
||||
DenseHashSet<TypeId> seen{nullptr};
|
||||
for (auto ty : maybeMutated->second)
|
||||
{
|
||||
// There is a high chance that this type has been rebound
|
||||
// across blocked types, rebound free types, pending
|
||||
// expansion types, etc, so we need to follow it.
|
||||
ty = follow(ty);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
{
|
||||
if (seen.contains(ty))
|
||||
continue;
|
||||
seen.insert(ty);
|
||||
}
|
||||
|
||||
size_t& refCount = unresolvedConstraints[ty];
|
||||
if (refCount > 0)
|
||||
refCount -= 1;
|
||||
|
@ -484,6 +503,9 @@ void ConstraintSolver::run()
|
|||
// refcount to be 1 or 0.
|
||||
if (refCount <= 1)
|
||||
unblock(ty, Location{});
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization && refCount == 0)
|
||||
generalizeOneType(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -600,16 +622,154 @@ bool ConstraintSolver::isDone() const
|
|||
return unsolvedConstraints.empty();
|
||||
}
|
||||
|
||||
namespace
|
||||
struct TypeSearcher : TypeVisitor
|
||||
{
|
||||
|
||||
struct TypeAndLocation
|
||||
enum struct Polarity: uint8_t
|
||||
{
|
||||
TypeId typeId;
|
||||
Location location;
|
||||
None = 0b00,
|
||||
Positive = 0b01,
|
||||
Negative = 0b10,
|
||||
Mixed = 0b11,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
TypeId needle;
|
||||
Polarity current = Polarity::Positive;
|
||||
|
||||
Polarity result = Polarity::None;
|
||||
|
||||
explicit TypeSearcher(TypeId needle)
|
||||
: TypeSearcher(needle, Polarity::Positive)
|
||||
{}
|
||||
|
||||
explicit TypeSearcher(TypeId needle, Polarity initialPolarity)
|
||||
: needle(needle)
|
||||
, current(initialPolarity)
|
||||
{}
|
||||
|
||||
bool visit(TypeId ty) override
|
||||
{
|
||||
if (ty == needle)
|
||||
result = Polarity(int(result) | int(current));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void flip()
|
||||
{
|
||||
switch (current)
|
||||
{
|
||||
case Polarity::Positive:
|
||||
current = Polarity::Negative;
|
||||
break;
|
||||
case Polarity::Negative:
|
||||
current = Polarity::Positive;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const FunctionType& ft) override
|
||||
{
|
||||
flip();
|
||||
traverse(ft.argTypes);
|
||||
|
||||
flip();
|
||||
traverse(ft.retTypes);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// bool visit(TypeId ty, const TableType& tt) override
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
bool visit(TypeId ty, const ClassType&) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void ConstraintSolver::generalizeOneType(TypeId ty)
|
||||
{
|
||||
ty = follow(ty);
|
||||
const FreeType* freeTy = get<FreeType>(ty);
|
||||
|
||||
std::string saveme = toString(ty, opts);
|
||||
|
||||
// Some constraints (like prim) will also replace a free type with something
|
||||
// concrete. If so, our work is already done.
|
||||
if (!freeTy)
|
||||
return;
|
||||
|
||||
NotNull<Scope> tyScope{freeTy->scope};
|
||||
|
||||
// TODO: If freeTy occurs within the enclosing function's type, we need to
|
||||
// check to see whether this type should instead be generic.
|
||||
|
||||
TypeId newBound = follow(freeTy->upperBound);
|
||||
|
||||
TypeId* functionTyPtr = nullptr;
|
||||
while (true)
|
||||
{
|
||||
functionTyPtr = scopeToFunction->find(tyScope);
|
||||
if (functionTyPtr || !tyScope->parent)
|
||||
break;
|
||||
else if (tyScope->parent)
|
||||
tyScope = NotNull{tyScope->parent.get()};
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (ty == newBound)
|
||||
ty = builtinTypes->unknownType;
|
||||
|
||||
if (!functionTyPtr)
|
||||
{
|
||||
asMutable(ty)->reassign(Type{BoundType{follow(freeTy->upperBound)}});
|
||||
}
|
||||
else
|
||||
{
|
||||
const TypeId functionTy = follow(*functionTyPtr);
|
||||
FunctionType* const function = getMutable<FunctionType>(functionTy);
|
||||
LUAU_ASSERT(function);
|
||||
|
||||
TypeSearcher ts{ty};
|
||||
ts.traverse(functionTy);
|
||||
|
||||
const TypeId upperBound = follow(freeTy->upperBound);
|
||||
const TypeId lowerBound = follow(freeTy->lowerBound);
|
||||
|
||||
switch (ts.result)
|
||||
{
|
||||
case TypeSearcher::Polarity::None:
|
||||
asMutable(ty)->reassign(Type{BoundType{upperBound}});
|
||||
break;
|
||||
|
||||
case TypeSearcher::Polarity::Negative:
|
||||
case TypeSearcher::Polarity::Mixed:
|
||||
if (get<UnknownType>(upperBound))
|
||||
{
|
||||
asMutable(ty)->reassign(Type{GenericType{tyScope}});
|
||||
function->generics.emplace_back(ty);
|
||||
}
|
||||
else
|
||||
asMutable(ty)->reassign(Type{BoundType{upperBound}});
|
||||
break;
|
||||
|
||||
case TypeSearcher::Polarity::Positive:
|
||||
if (get<UnknownType>(lowerBound))
|
||||
{
|
||||
asMutable(ty)->reassign(Type{GenericType{tyScope}});
|
||||
function->generics.emplace_back(ty);
|
||||
}
|
||||
else
|
||||
asMutable(ty)->reassign(Type{BoundType{lowerBound}});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConstraintSolver::bind(NotNull<const Constraint> constraint, TypeId ty, TypeId boundTo)
|
||||
{
|
||||
|
@ -1170,12 +1330,9 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
|
|||
target = follow(instantiated);
|
||||
}
|
||||
|
||||
if (FFlag::LuauNewSolverPopulateTableLocations)
|
||||
{
|
||||
// This is a new type - redefine the location.
|
||||
ttv->definitionLocation = constraint->location;
|
||||
ttv->definitionModuleName = currentModuleName;
|
||||
}
|
||||
|
||||
ttv->instantiatedTypeParams = typeArguments;
|
||||
ttv->instantiatedTypePackParams = packArguments;
|
||||
|
@ -1222,7 +1379,6 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
|
|||
{
|
||||
emplaceTypePack<BoundTypePack>(asMutable(c.result), builtinTypes->anyTypePack);
|
||||
unblock(c.result, constraint->location);
|
||||
if (FFlag::LuauAlwaysFillInFunctionCallDiscriminantTypes)
|
||||
fillInDiscriminantTypes(constraint, c.discriminantTypes);
|
||||
return true;
|
||||
}
|
||||
|
@ -1231,7 +1387,6 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
|
|||
if (get<ErrorType>(fn))
|
||||
{
|
||||
bind(constraint, c.result, builtinTypes->errorRecoveryTypePack());
|
||||
if (FFlag::LuauAlwaysFillInFunctionCallDiscriminantTypes)
|
||||
fillInDiscriminantTypes(constraint, c.discriminantTypes);
|
||||
return true;
|
||||
}
|
||||
|
@ -1239,7 +1394,6 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
|
|||
if (get<NeverType>(fn))
|
||||
{
|
||||
bind(constraint, c.result, builtinTypes->neverTypePack);
|
||||
if (FFlag::LuauAlwaysFillInFunctionCallDiscriminantTypes)
|
||||
fillInDiscriminantTypes(constraint, c.discriminantTypes);
|
||||
return true;
|
||||
}
|
||||
|
@ -1321,30 +1475,7 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
|
|||
emplace<FreeTypePack>(constraint, c.result, constraint->scope);
|
||||
}
|
||||
|
||||
if (FFlag::LuauAlwaysFillInFunctionCallDiscriminantTypes)
|
||||
{
|
||||
fillInDiscriminantTypes(constraint, c.discriminantTypes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: This is the body of the `fillInDiscriminantTypes` helper.
|
||||
for (std::optional<TypeId> ty : c.discriminantTypes)
|
||||
{
|
||||
if (!ty)
|
||||
continue;
|
||||
|
||||
// If the discriminant type has been transmuted, we need to unblock them.
|
||||
if (!isBlocked(*ty))
|
||||
{
|
||||
unblock(*ty, constraint->location);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We bind any unused discriminants to the `*no-refine*` type indicating that it can be safely ignored.
|
||||
emplaceType<BoundType>(asMutable(follow(*ty)), builtinTypes->noRefineType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OverloadResolver resolver{
|
||||
builtinTypes,
|
||||
|
@ -1912,7 +2043,7 @@ bool ConstraintSolver::tryDispatch(const AssignPropConstraint& c, NotNull<const
|
|||
bind(
|
||||
constraint,
|
||||
c.propType,
|
||||
isIndex && FFlag::LuauAllowNilAssignmentToIndexer ? arena->addType(UnionType{{propTy, builtinTypes->nilType}}) : propTy
|
||||
isIndex ? arena->addType(UnionType{{propTy, builtinTypes->nilType}}) : propTy
|
||||
);
|
||||
unify(constraint, rhsType, propTy);
|
||||
return true;
|
||||
|
@ -2010,8 +2141,7 @@ bool ConstraintSolver::tryDispatch(const AssignIndexConstraint& c, NotNull<const
|
|||
bind(
|
||||
constraint,
|
||||
c.propType,
|
||||
FFlag::LuauAllowNilAssignmentToIndexer ? arena->addType(UnionType{{lhsTable->indexer->indexResultType, builtinTypes->nilType}})
|
||||
: lhsTable->indexer->indexResultType
|
||||
arena->addType(UnionType{{lhsTable->indexer->indexResultType, builtinTypes->nilType}})
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
@ -2064,8 +2194,7 @@ bool ConstraintSolver::tryDispatch(const AssignIndexConstraint& c, NotNull<const
|
|||
bind(
|
||||
constraint,
|
||||
c.propType,
|
||||
FFlag::LuauAllowNilAssignmentToIndexer ? arena->addType(UnionType{{lhsClass->indexer->indexResultType, builtinTypes->nilType}})
|
||||
: lhsClass->indexer->indexResultType
|
||||
arena->addType(UnionType{{lhsClass->indexer->indexResultType, builtinTypes->nilType}})
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
@ -3113,6 +3242,24 @@ void ConstraintSolver::shiftReferences(TypeId source, TypeId target)
|
|||
|
||||
auto [targetRefs, _] = unresolvedConstraints.try_insert(target, 0);
|
||||
targetRefs += count;
|
||||
|
||||
// Any constraint that might have mutated source may now mutate target
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
{
|
||||
auto it = mutatedFreeTypeToConstraint.find(source);
|
||||
if (it != mutatedFreeTypeToConstraint.end())
|
||||
{
|
||||
auto [it2, fresh] = mutatedFreeTypeToConstraint.try_emplace(target, DenseHashSet<const Constraint*>{nullptr});
|
||||
for (const Constraint* constraint : it->second)
|
||||
{
|
||||
it2->second.insert(constraint);
|
||||
|
||||
auto [it3, fresh2] = maybeMutatedFreeTypes.try_emplace(NotNull{constraint}, DenseHashSet<TypeId>{nullptr});
|
||||
it3->second.insert(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<TypeId> ConstraintSolver::generalizeFreeType(NotNull<Scope> scope, TypeId type, bool avoidSealingTables)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
#include "Luau/BuiltinDefinitions.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauBufferBitMethods2)
|
||||
LUAU_FASTFLAG(LuauVector2Constructor)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDebugInfoDefn)
|
||||
|
||||
namespace Luau
|
||||
|
@ -239,37 +237,6 @@ declare utf8: {
|
|||
|
||||
)BUILTIN_SRC";
|
||||
|
||||
static const std::string kBuiltinDefinitionBufferSrc_DEPRECATED = R"BUILTIN_SRC(
|
||||
--- Buffer API
|
||||
declare buffer: {
|
||||
create: @checked (size: number) -> buffer,
|
||||
fromstring: @checked (str: string) -> buffer,
|
||||
tostring: @checked (b: buffer) -> string,
|
||||
len: @checked (b: buffer) -> number,
|
||||
copy: @checked (target: buffer, targetOffset: number, source: buffer, sourceOffset: number?, count: number?) -> (),
|
||||
fill: @checked (b: buffer, offset: number, value: number, count: number?) -> (),
|
||||
readi8: @checked (b: buffer, offset: number) -> number,
|
||||
readu8: @checked (b: buffer, offset: number) -> number,
|
||||
readi16: @checked (b: buffer, offset: number) -> number,
|
||||
readu16: @checked (b: buffer, offset: number) -> number,
|
||||
readi32: @checked (b: buffer, offset: number) -> number,
|
||||
readu32: @checked (b: buffer, offset: number) -> number,
|
||||
readf32: @checked (b: buffer, offset: number) -> number,
|
||||
readf64: @checked (b: buffer, offset: number) -> number,
|
||||
writei8: @checked (b: buffer, offset: number, value: number) -> (),
|
||||
writeu8: @checked (b: buffer, offset: number, value: number) -> (),
|
||||
writei16: @checked (b: buffer, offset: number, value: number) -> (),
|
||||
writeu16: @checked (b: buffer, offset: number, value: number) -> (),
|
||||
writei32: @checked (b: buffer, offset: number, value: number) -> (),
|
||||
writeu32: @checked (b: buffer, offset: number, value: number) -> (),
|
||||
writef32: @checked (b: buffer, offset: number, value: number) -> (),
|
||||
writef64: @checked (b: buffer, offset: number, value: number) -> (),
|
||||
readstring: @checked (b: buffer, offset: number, count: number) -> string,
|
||||
writestring: @checked (b: buffer, offset: number, value: string, count: number?) -> (),
|
||||
}
|
||||
|
||||
)BUILTIN_SRC";
|
||||
|
||||
static const std::string kBuiltinDefinitionBufferSrc = R"BUILTIN_SRC(
|
||||
--- Buffer API
|
||||
declare buffer: {
|
||||
|
@ -303,36 +270,6 @@ declare buffer: {
|
|||
|
||||
)BUILTIN_SRC";
|
||||
|
||||
static const std::string kBuiltinDefinitionVectorSrc_NoVector2Ctor_DEPRECATED = R"BUILTIN_SRC(
|
||||
|
||||
-- While vector would have been better represented as a built-in primitive type, type solver class handling covers most of the properties
|
||||
declare class vector
|
||||
x: number
|
||||
y: number
|
||||
z: number
|
||||
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";
|
||||
|
||||
static const std::string kBuiltinDefinitionVectorSrc = R"BUILTIN_SRC(
|
||||
|
||||
-- While vector would have been better represented as a built-in primitive type, type solver class handling covers most of the properties
|
||||
|
@ -374,13 +311,8 @@ std::string getBuiltinDefinitionSource()
|
|||
result += kBuiltinDefinitionTableSrc;
|
||||
result += FFlag::LuauDebugInfoDefn ? kBuiltinDefinitionDebugSrc : kBuiltinDefinitionDebugSrc_DEPRECATED;
|
||||
result += kBuiltinDefinitionUtf8Src;
|
||||
|
||||
result += FFlag::LuauBufferBitMethods2 ? kBuiltinDefinitionBufferSrc : kBuiltinDefinitionBufferSrc_DEPRECATED;
|
||||
|
||||
if (FFlag::LuauVector2Constructor)
|
||||
result += kBuiltinDefinitionBufferSrc;
|
||||
result += kBuiltinDefinitionVectorSrc;
|
||||
else
|
||||
result += kBuiltinDefinitionVectorSrc_NoVector2Ctor_DEPRECATED;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
LUAU_FASTINT(LuauTypeInferRecursionLimit);
|
||||
LUAU_FASTINT(LuauTypeInferIterationLimit);
|
||||
LUAU_FASTINT(LuauTarjanChildLimit)
|
||||
LUAU_FASTFLAG(LuauAllowFragmentParsing);
|
||||
LUAU_FASTFLAG(LuauAutocompleteRefactorsForIncrementalAutocomplete)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauIncrementalAutocompleteBugfixes)
|
||||
|
@ -98,6 +97,7 @@ void cloneAndSquashScopes(
|
|||
Scope* destScope
|
||||
)
|
||||
{
|
||||
LUAU_TIMETRACE_SCOPE("Luau::cloneAndSquashScopes", "FragmentAutocomplete");
|
||||
std::vector<const Scope*> scopes;
|
||||
for (const Scope* current = staleScope; current; current = current->parent.get())
|
||||
{
|
||||
|
@ -364,6 +364,7 @@ std::optional<FragmentParseResult> parseFragment(
|
|||
|
||||
ModulePtr cloneModule(CloneState& cloneState, const ModulePtr& source, std::unique_ptr<Allocator> alloc)
|
||||
{
|
||||
LUAU_TIMETRACE_SCOPE("Luau::cloneModule", "FragmentAutocomplete");
|
||||
freeze(source->internalTypes);
|
||||
freeze(source->interfaceTypes);
|
||||
ModulePtr incremental = std::make_shared<Module>();
|
||||
|
@ -445,6 +446,8 @@ FragmentTypeCheckResult typecheckFragment_(
|
|||
const FrontendOptions& opts
|
||||
)
|
||||
{
|
||||
LUAU_TIMETRACE_SCOPE("Luau::typecheckFragment_", "FragmentAutocomplete");
|
||||
|
||||
freeze(stale->internalTypes);
|
||||
freeze(stale->interfaceTypes);
|
||||
CloneState cloneState{frontend.builtinTypes};
|
||||
|
@ -533,6 +536,7 @@ FragmentTypeCheckResult typecheckFragment_(
|
|||
NotNull{&typeFunctionRuntime},
|
||||
NotNull(cg.rootScope),
|
||||
borrowConstraints(cg.constraints),
|
||||
NotNull{&cg.scopeToFunction},
|
||||
incrementalModule->name,
|
||||
NotNull{&resolver},
|
||||
{},
|
||||
|
@ -573,6 +577,8 @@ std::pair<FragmentTypeCheckStatus, FragmentTypeCheckResult> typecheckFragment(
|
|||
std::optional<Position> fragmentEndPosition
|
||||
)
|
||||
{
|
||||
LUAU_TIMETRACE_SCOPE("Luau::typecheckFragment", "FragmentAutocomplete");
|
||||
LUAU_TIMETRACE_ARGUMENT("name", moduleName.c_str());
|
||||
|
||||
if (FFlag::LuauBetterReverseDependencyTracking)
|
||||
{
|
||||
|
@ -621,6 +627,35 @@ std::pair<FragmentTypeCheckStatus, FragmentTypeCheckResult> typecheckFragment(
|
|||
return {FragmentTypeCheckStatus::Success, result};
|
||||
}
|
||||
|
||||
FragmentAutocompleteStatusResult tryFragmentAutocomplete(
|
||||
Frontend& frontend,
|
||||
const ModuleName& moduleName,
|
||||
Position cursorPosition,
|
||||
FragmentContext context,
|
||||
StringCompletionCallback stringCompletionCB
|
||||
)
|
||||
{
|
||||
// TODO: we should calculate fragmentEnd position here, by using context.newAstRoot and cursorPosition
|
||||
try
|
||||
{
|
||||
Luau::FragmentAutocompleteResult fragmentAutocomplete = Luau::fragmentAutocomplete(
|
||||
frontend,
|
||||
context.newSrc,
|
||||
moduleName,
|
||||
cursorPosition,
|
||||
context.opts,
|
||||
std::move(stringCompletionCB),
|
||||
context.DEPRECATED_fragmentEndPosition
|
||||
);
|
||||
return {FragmentAutocompleteStatus::Success, std::move(fragmentAutocomplete)};
|
||||
}
|
||||
catch (const Luau::InternalCompilerError& e)
|
||||
{
|
||||
if (FFlag::LogFragmentsFromAutocomplete)
|
||||
logLuau(e.what());
|
||||
return {FragmentAutocompleteStatus::InternalIce, std::nullopt};
|
||||
}
|
||||
}
|
||||
|
||||
FragmentAutocompleteResult fragmentAutocomplete(
|
||||
Frontend& frontend,
|
||||
|
@ -632,8 +667,9 @@ FragmentAutocompleteResult fragmentAutocomplete(
|
|||
std::optional<Position> fragmentEndPosition
|
||||
)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauAllowFragmentParsing);
|
||||
LUAU_ASSERT(FFlag::LuauAutocompleteRefactorsForIncrementalAutocomplete);
|
||||
LUAU_TIMETRACE_SCOPE("Luau::fragmentAutocomplete", "FragmentAutocomplete");
|
||||
LUAU_TIMETRACE_ARGUMENT("name", moduleName.c_str());
|
||||
|
||||
const SourceModule* sourceModule = frontend.getSourceModule(moduleName);
|
||||
if (!sourceModule)
|
||||
|
|
|
@ -1481,6 +1481,7 @@ ModulePtr check(
|
|||
NotNull{&typeFunctionRuntime},
|
||||
NotNull(cg.rootScope),
|
||||
borrowConstraints(cg.constraints),
|
||||
NotNull{&cg.scopeToFunction},
|
||||
result->name,
|
||||
moduleResolver,
|
||||
requireCycles,
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <iostream>
|
||||
#include <iterator>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauCountSelfCallsNonstrict)
|
||||
LUAU_FASTFLAG(LuauFreeTypesMustHaveBounds)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNonStrictVisitorImprovements)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictWarnOnUnknownGlobals)
|
||||
|
@ -628,17 +627,6 @@ struct NonStrictTypeChecker
|
|||
|
||||
NonStrictContext visit(AstExprCall* call)
|
||||
{
|
||||
if (FFlag::LuauCountSelfCallsNonstrict)
|
||||
return visitCall(call);
|
||||
else
|
||||
return visitCall_DEPRECATED(call);
|
||||
}
|
||||
|
||||
// rename this to `visit` when `FFlag::LuauCountSelfCallsNonstrict` is removed, and clean up above `visit`.
|
||||
NonStrictContext visitCall(AstExprCall* call)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauCountSelfCallsNonstrict);
|
||||
|
||||
NonStrictContext fresh{};
|
||||
TypeId* originalCallTy = module->astOriginalCallTypes.find(call->func);
|
||||
if (!originalCallTy)
|
||||
|
@ -747,109 +735,6 @@ struct NonStrictTypeChecker
|
|||
return fresh;
|
||||
}
|
||||
|
||||
// Remove with `FFlag::LuauCountSelfCallsNonstrict` clean up.
|
||||
NonStrictContext visitCall_DEPRECATED(AstExprCall* call)
|
||||
{
|
||||
LUAU_ASSERT(!FFlag::LuauCountSelfCallsNonstrict);
|
||||
|
||||
NonStrictContext fresh{};
|
||||
TypeId* originalCallTy = module->astOriginalCallTypes.find(call->func);
|
||||
if (!originalCallTy)
|
||||
return fresh;
|
||||
|
||||
TypeId fnTy = *originalCallTy;
|
||||
if (auto fn = get<FunctionType>(follow(fnTy)))
|
||||
{
|
||||
if (fn->isCheckedFunction)
|
||||
{
|
||||
// We know fn is a checked function, which means it looks like:
|
||||
// (S1, ... SN) -> T &
|
||||
// (~S1, unknown^N-1) -> error &
|
||||
// (unknown, ~S2, unknown^N-2) -> error
|
||||
// ...
|
||||
// ...
|
||||
// (unknown^N-1, ~S_N) -> error
|
||||
std::vector<TypeId> argTypes;
|
||||
argTypes.reserve(call->args.size);
|
||||
// Pad out the arg types array with the types you would expect to see
|
||||
TypePackIterator curr = begin(fn->argTypes);
|
||||
TypePackIterator fin = end(fn->argTypes);
|
||||
while (curr != fin)
|
||||
{
|
||||
argTypes.push_back(*curr);
|
||||
++curr;
|
||||
}
|
||||
if (auto argTail = curr.tail())
|
||||
{
|
||||
if (const VariadicTypePack* vtp = get<VariadicTypePack>(follow(*argTail)))
|
||||
{
|
||||
while (argTypes.size() < call->args.size)
|
||||
{
|
||||
argTypes.push_back(vtp->ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string functionName = getFunctionNameAsString(*call->func).value_or("");
|
||||
if (call->args.size > argTypes.size())
|
||||
{
|
||||
// We are passing more arguments than we expect, so we should error
|
||||
reportError(CheckedFunctionIncorrectArgs{functionName, argTypes.size(), call->args.size}, call->location);
|
||||
return fresh;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < call->args.size; i++)
|
||||
{
|
||||
// For example, if the arg is "hi"
|
||||
// The actual arg type is string
|
||||
// The expected arg type is number
|
||||
// The type of the argument in the overload is ~number
|
||||
// We will compare arg and ~number
|
||||
AstExpr* arg = call->args.data[i];
|
||||
TypeId expectedArgType = argTypes[i];
|
||||
std::shared_ptr<const NormalizedType> norm = normalizer.normalize(expectedArgType);
|
||||
DefId def = dfg->getDef(arg);
|
||||
TypeId runTimeErrorTy;
|
||||
// If we're dealing with any, negating any will cause all subtype tests to fail
|
||||
// However, when someone calls this function, they're going to want to be able to pass it anything,
|
||||
// for that reason, we manually inject never into the context so that the runtime test will always pass.
|
||||
if (!norm)
|
||||
reportError(NormalizationTooComplex{}, arg->location);
|
||||
|
||||
if (norm && get<AnyType>(norm->tops))
|
||||
runTimeErrorTy = builtinTypes->neverType;
|
||||
else
|
||||
runTimeErrorTy = getOrCreateNegation(expectedArgType);
|
||||
fresh.addContext(def, runTimeErrorTy);
|
||||
}
|
||||
|
||||
// Populate the context and now iterate through each of the arguments to the call to find out if we satisfy the types
|
||||
for (size_t i = 0; i < call->args.size; i++)
|
||||
{
|
||||
AstExpr* arg = call->args.data[i];
|
||||
if (auto runTimeFailureType = willRunTimeError(arg, fresh))
|
||||
reportError(CheckedFunctionCallError{argTypes[i], *runTimeFailureType, functionName, i}, arg->location);
|
||||
}
|
||||
|
||||
if (call->args.size < argTypes.size())
|
||||
{
|
||||
// We are passing fewer arguments than we expect
|
||||
// so we need to ensure that the rest of the args are optional.
|
||||
bool remainingArgsOptional = true;
|
||||
for (size_t i = call->args.size; i < argTypes.size(); i++)
|
||||
remainingArgsOptional = remainingArgsOptional && isOptional(argTypes[i]);
|
||||
if (!remainingArgsOptional)
|
||||
{
|
||||
reportError(CheckedFunctionIncorrectArgs{functionName, argTypes.size(), call->args.size}, call->location);
|
||||
return fresh;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fresh;
|
||||
}
|
||||
|
||||
NonStrictContext visit(AstExprIndexName* indexName, ValueContext context)
|
||||
{
|
||||
if (FFlag::LuauNonStrictVisitorImprovements)
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauStoreCSTData)
|
||||
LUAU_FASTFLAG(LuauExtendStatEndPosWithSemicolon)
|
||||
LUAU_FASTFLAG(LuauAstTypeGroup)
|
||||
LUAU_FASTFLAG(LuauAstTypeGroup2)
|
||||
LUAU_FASTFLAG(LuauFixDoBlockEndLocation)
|
||||
|
||||
namespace
|
||||
|
@ -330,7 +330,7 @@ struct Printer_DEPRECATED
|
|||
else if (typeCount == 1)
|
||||
{
|
||||
bool shouldParenthesize = unconditionallyParenthesize && (list.types.size == 0 || !list.types.data[0]->is<AstTypeGroup>());
|
||||
if (FFlag::LuauAstTypeGroup ? shouldParenthesize : unconditionallyParenthesize)
|
||||
if (FFlag::LuauAstTypeGroup2 ? shouldParenthesize : unconditionallyParenthesize)
|
||||
writer.symbol("(");
|
||||
|
||||
// Only variadic tail
|
||||
|
@ -343,7 +343,7 @@ struct Printer_DEPRECATED
|
|||
visualizeTypeAnnotation(*list.types.data[0]);
|
||||
}
|
||||
|
||||
if (FFlag::LuauAstTypeGroup ? shouldParenthesize : unconditionallyParenthesize)
|
||||
if (FFlag::LuauAstTypeGroup2 ? shouldParenthesize : unconditionallyParenthesize)
|
||||
writer.symbol(")");
|
||||
}
|
||||
else
|
||||
|
@ -1349,7 +1349,7 @@ struct Printer
|
|||
else if (typeCount == 1)
|
||||
{
|
||||
bool shouldParenthesize = unconditionallyParenthesize && (list.types.size == 0 || !list.types.data[0]->is<AstTypeGroup>());
|
||||
if (FFlag::LuauAstTypeGroup ? shouldParenthesize : unconditionallyParenthesize)
|
||||
if (FFlag::LuauAstTypeGroup2 ? shouldParenthesize : unconditionallyParenthesize)
|
||||
writer.symbol("(");
|
||||
|
||||
// Only variadic tail
|
||||
|
@ -1362,7 +1362,7 @@ struct Printer
|
|||
visualizeTypeAnnotation(*list.types.data[0]);
|
||||
}
|
||||
|
||||
if (FFlag::LuauAstTypeGroup ? shouldParenthesize : unconditionallyParenthesize)
|
||||
if (FFlag::LuauAstTypeGroup2 ? shouldParenthesize : unconditionallyParenthesize)
|
||||
writer.symbol(")");
|
||||
}
|
||||
else
|
||||
|
@ -2599,6 +2599,7 @@ struct Printer
|
|||
{
|
||||
writer.symbol("(");
|
||||
visualizeTypeAnnotation(*a->type);
|
||||
advance(Position{a->location.end.line, a->location.end.column - 1});
|
||||
writer.symbol(")");
|
||||
}
|
||||
else if (const auto& a = typeAnnotation.as<AstTypeSingletonBool>())
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauTableKeysAreRValues)
|
||||
LUAU_FASTFLAG(LuauFreeTypesMustHaveBounds)
|
||||
|
||||
namespace Luau
|
||||
|
@ -1847,17 +1846,9 @@ void TypeChecker2::visit(AstExprFunction* fn)
|
|||
void TypeChecker2::visit(AstExprTable* expr)
|
||||
{
|
||||
for (const AstExprTable::Item& item : expr->items)
|
||||
{
|
||||
if (FFlag::LuauTableKeysAreRValues)
|
||||
{
|
||||
if (item.key)
|
||||
visit(item.key, ValueContext::RValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.key)
|
||||
visit(item.key, ValueContext::LValue);
|
||||
}
|
||||
visit(item.value, ValueContext::RValue);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ LUAU_FASTFLAGVARIABLE(LuauMetatableTypeFunctions)
|
|||
LUAU_FASTFLAGVARIABLE(LuauClipNestedAndRecursiveUnion)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDoNotGeneralizeInTypeFunctions)
|
||||
LUAU_FASTFLAGVARIABLE(LuauPreventReentrantTypeFunctionReduction)
|
||||
LUAU_FASTFLAGVARIABLE(LuauIntersectNotNil)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSkipNoRefineDuringRefinement)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -2005,17 +2007,9 @@ TypeFunctionReductionResult<TypeId> refineTypeFunction(
|
|||
}
|
||||
else
|
||||
{
|
||||
/* HACK: Refinements sometimes produce a type T & ~any under the assumption
|
||||
* that ~any is the same as any. This is so so weird, but refinements needs
|
||||
* some way to say "I may refine this, but I'm not sure."
|
||||
*
|
||||
* It does this by refining on a blocked type and deferring the decision
|
||||
* until it is unblocked.
|
||||
*
|
||||
* Refinements also get negated, so we wind up with types like T & ~*blocked*
|
||||
*
|
||||
* We need to treat T & ~any as T in this case.
|
||||
*/
|
||||
if (FFlag::LuauSkipNoRefineDuringRefinement)
|
||||
if (get<NoRefineType>(discriminant))
|
||||
return {target, {}};
|
||||
if (auto nt = get<NegationType>(discriminant))
|
||||
{
|
||||
if (get<NoRefineType>(follow(nt->ty)))
|
||||
|
@ -2292,8 +2286,20 @@ TypeFunctionReductionResult<TypeId> intersectTypeFunction(
|
|||
continue;
|
||||
|
||||
SimplifyResult result = simplifyIntersection(ctx->builtins, ctx->arena, resultTy, ty);
|
||||
|
||||
if (FFlag::LuauIntersectNotNil)
|
||||
{
|
||||
for (TypeId blockedType : result.blockedTypes)
|
||||
{
|
||||
if (!get<GenericType>(blockedType))
|
||||
return {std::nullopt, Reduction::MaybeOk, {result.blockedTypes.begin(), result.blockedTypes.end()}, {}};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!result.blockedTypes.empty())
|
||||
return {std::nullopt, Reduction::MaybeOk, {result.blockedTypes.begin(), result.blockedTypes.end()}, {}};
|
||||
}
|
||||
|
||||
resultTy = result.result;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ LUAU_FASTFLAGVARIABLE(LuauTypeFunFixHydratedClasses)
|
|||
LUAU_DYNAMIC_FASTINT(LuauTypeFunctionSerdeIterationLimit)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTypeFunSingletonEquality)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserTypeFunTypeofReturnsType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTypeFunPrintFix)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTypeFunReadWriteParents)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -1109,7 +1111,7 @@ static int getFunctionGenerics(lua_State* L)
|
|||
|
||||
// Luau: `self:parent() -> type`
|
||||
// Returns the parent of a class type
|
||||
static int getClassParent(lua_State* L)
|
||||
static int getClassParent_DEPRECATED(lua_State* L)
|
||||
{
|
||||
int argumentCount = lua_gettop(L);
|
||||
if (argumentCount != 1)
|
||||
|
@ -1121,10 +1123,54 @@ static int getClassParent(lua_State* L)
|
|||
luaL_error(L, "type.parent: expected self to be a class, but got %s instead", getTag(L, self).c_str());
|
||||
|
||||
// If the parent does not exist, we should return nil
|
||||
if (!tfct->parent)
|
||||
if (!tfct->parent_DEPRECATED)
|
||||
lua_pushnil(L);
|
||||
else
|
||||
allocTypeUserData(L, (*tfct->parent)->type);
|
||||
allocTypeUserData(L, (*tfct->parent_DEPRECATED)->type);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Luau: `self:readparent() -> type`
|
||||
// Returns the read type of the class' parent
|
||||
static int getReadParent(lua_State* L)
|
||||
{
|
||||
int argumentCount = lua_gettop(L);
|
||||
if (argumentCount != 1)
|
||||
luaL_error(L, "type.parent: expected 1 arguments, but got %d", argumentCount);
|
||||
|
||||
TypeFunctionTypeId self = getTypeUserData(L, 1);
|
||||
auto tfct = get<TypeFunctionClassType>(self);
|
||||
if (!tfct)
|
||||
luaL_error(L, "type.parent: expected self to be a class, but got %s instead", getTag(L, self).c_str());
|
||||
|
||||
// If the parent does not exist, we should return nil
|
||||
if (!tfct->readParent)
|
||||
lua_pushnil(L);
|
||||
else
|
||||
allocTypeUserData(L, (*tfct->readParent)->type);
|
||||
|
||||
return 1;
|
||||
}
|
||||
//
|
||||
// Luau: `self:writeparent() -> type`
|
||||
// Returns the write type of the class' parent
|
||||
static int getWriteParent(lua_State* L)
|
||||
{
|
||||
int argumentCount = lua_gettop(L);
|
||||
if (argumentCount != 1)
|
||||
luaL_error(L, "type.parent: expected 1 arguments, but got %d", argumentCount);
|
||||
|
||||
TypeFunctionTypeId self = getTypeUserData(L, 1);
|
||||
auto tfct = get<TypeFunctionClassType>(self);
|
||||
if (!tfct)
|
||||
luaL_error(L, "type.parent: expected self to be a class, but got %s instead", getTag(L, self).c_str());
|
||||
|
||||
// If the parent does not exist, we should return nil
|
||||
if (!tfct->writeParent)
|
||||
lua_pushnil(L);
|
||||
else
|
||||
allocTypeUserData(L, (*tfct->writeParent)->type);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1552,7 +1598,7 @@ void registerTypeUserData(lua_State* L)
|
|||
{"components", getComponents},
|
||||
|
||||
// Class type methods
|
||||
{"parent", getClassParent},
|
||||
{FFlag::LuauTypeFunReadWriteParents ? "readparent" : "parent", FFlag::LuauTypeFunReadWriteParents ? getReadParent : getClassParent_DEPRECATED},
|
||||
|
||||
// Function type methods (cont.)
|
||||
{"setgenerics", setFunctionGenerics},
|
||||
|
@ -1562,6 +1608,9 @@ void registerTypeUserData(lua_State* L)
|
|||
{"name", getGenericName},
|
||||
{"ispack", getGenericIsPack},
|
||||
|
||||
// move this under Class type methods when removing FFlagLuauTypeFunReadWriteParents
|
||||
{FFlag::LuauTypeFunReadWriteParents ? "writeparent" : nullptr, FFlag::LuauTypeFunReadWriteParents ? getWriteParent : nullptr},
|
||||
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
|
@ -1612,7 +1661,12 @@ static int print(lua_State* L)
|
|||
size_t l = 0;
|
||||
const char* s = luaL_tolstring(L, i, &l); // convert to string using __tostring et al
|
||||
if (i > 1)
|
||||
{
|
||||
if (FFlag::LuauTypeFunPrintFix)
|
||||
result.append(1, '\t');
|
||||
else
|
||||
result.append('\t', 1);
|
||||
}
|
||||
result.append(s, l);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
// currently, controls serialization, deserialization, and `type.copy`
|
||||
LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFunctionSerdeIterationLimit, 100'000);
|
||||
LUAU_FASTFLAG(LuauTypeFunFixHydratedClasses)
|
||||
LUAU_FASTFLAG(LuauTypeFunReadWriteParents)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -212,13 +213,13 @@ private:
|
|||
{
|
||||
// Since there aren't any new class types being created in type functions, we will deserialize by using a direct reference to the
|
||||
// original class
|
||||
target = typeFunctionRuntime->typeArena.allocate(TypeFunctionClassType{{}, std::nullopt, std::nullopt, std::nullopt, ty});
|
||||
target = typeFunctionRuntime->typeArena.allocate(TypeFunctionClassType{{}, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, ty});
|
||||
}
|
||||
else
|
||||
{
|
||||
state->classesSerialized_DEPRECATED[c->name] = ty;
|
||||
target = typeFunctionRuntime->typeArena.allocate(
|
||||
TypeFunctionClassType{{}, std::nullopt, std::nullopt, std::nullopt, /* classTy */ nullptr, c->name}
|
||||
TypeFunctionClassType{{}, std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt, /* classTy */ nullptr, c->name}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -441,7 +442,20 @@ private:
|
|||
c2->metatable = shallowSerialize(*c1->metatable);
|
||||
|
||||
if (c1->parent)
|
||||
c2->parent = shallowSerialize(*c1->parent);
|
||||
{
|
||||
TypeFunctionTypeId parent = shallowSerialize(*c1->parent);
|
||||
|
||||
if (FFlag::LuauTypeFunReadWriteParents)
|
||||
{
|
||||
// we don't yet have read/write parents in the type inference engine.
|
||||
c2->readParent = parent;
|
||||
c2->writeParent = parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
c2->parent_DEPRECATED = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void serializeChildren(const GenericType* g1, TypeFunctionGenericType* g2)
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <type_traits>
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauDisableNewSolverAssertsInMixedMode);
|
||||
// Maximum number of steps to follow when traversing a path. May not always
|
||||
// equate to the number of components in a path, depending on the traversal
|
||||
// logic.
|
||||
|
@ -156,6 +156,7 @@ Path PathBuilder::build()
|
|||
|
||||
PathBuilder& PathBuilder::readProp(std::string name)
|
||||
{
|
||||
if (!FFlag::LuauDisableNewSolverAssertsInMixedMode)
|
||||
LUAU_ASSERT(FFlag::LuauSolverV2);
|
||||
components.push_back(Property{std::move(name), true});
|
||||
return *this;
|
||||
|
@ -163,6 +164,7 @@ PathBuilder& PathBuilder::readProp(std::string name)
|
|||
|
||||
PathBuilder& PathBuilder::writeProp(std::string name)
|
||||
{
|
||||
if (!FFlag::LuauDisableNewSolverAssertsInMixedMode)
|
||||
LUAU_ASSERT(FFlag::LuauSolverV2);
|
||||
components.push_back(Property{std::move(name), false});
|
||||
return *this;
|
||||
|
|
|
@ -14,7 +14,7 @@ LUAU_FASTFLAG(LuauSolverV2);
|
|||
LUAU_FASTFLAG(LuauAutocompleteRefactorsForIncrementalAutocomplete);
|
||||
LUAU_FASTFLAG(LuauTrackInteriorFreeTypesOnScope);
|
||||
LUAU_FASTFLAG(LuauFreeTypesMustHaveBounds)
|
||||
|
||||
LUAU_FASTFLAG(LuauDisableNewSolverAssertsInMixedMode)
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -550,6 +550,9 @@ std::vector<TypeId> findBlockedArgTypesIn(AstExprCall* expr, NotNull<DenseHashMa
|
|||
|
||||
void trackInteriorFreeType(Scope* scope, TypeId ty)
|
||||
{
|
||||
if (FFlag::LuauDisableNewSolverAssertsInMixedMode)
|
||||
LUAU_ASSERT(FFlag::LuauTrackInteriorFreeTypesOnScope);
|
||||
else
|
||||
LUAU_ASSERT(FFlag::LuauSolverV2 && FFlag::LuauTrackInteriorFreeTypesOnScope);
|
||||
for (; scope; scope = scope->parent.get())
|
||||
{
|
||||
|
|
|
@ -33,39 +33,21 @@ struct PromoteTypeLevels final : TypeOnceVisitor
|
|||
const TypeArena* typeArena = nullptr;
|
||||
TypeLevel minLevel;
|
||||
|
||||
Scope* outerScope = nullptr;
|
||||
bool useScopes;
|
||||
|
||||
PromoteTypeLevels(TxnLog& log, const TypeArena* typeArena, TypeLevel minLevel, Scope* outerScope, bool useScopes)
|
||||
PromoteTypeLevels(TxnLog& log, const TypeArena* typeArena, TypeLevel minLevel)
|
||||
: log(log)
|
||||
, typeArena(typeArena)
|
||||
, minLevel(minLevel)
|
||||
, outerScope(outerScope)
|
||||
, useScopes(useScopes)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename TID, typename T>
|
||||
void promote(TID ty, T* t)
|
||||
{
|
||||
if (useScopes && !t)
|
||||
return;
|
||||
|
||||
LUAU_ASSERT(t);
|
||||
|
||||
if (useScopes)
|
||||
{
|
||||
if (subsumesStrict(outerScope, t->scope))
|
||||
log.changeScope(ty, NotNull{outerScope});
|
||||
}
|
||||
else
|
||||
{
|
||||
if (minLevel.subsumesStrict(t->level))
|
||||
{
|
||||
log.changeLevel(ty, minLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool visit(TypeId ty) override
|
||||
{
|
||||
|
@ -141,23 +123,23 @@ struct PromoteTypeLevels final : TypeOnceVisitor
|
|||
}
|
||||
};
|
||||
|
||||
static void promoteTypeLevels(TxnLog& log, const TypeArena* typeArena, TypeLevel minLevel, Scope* outerScope, bool useScopes, TypeId ty)
|
||||
static void promoteTypeLevels(TxnLog& log, const TypeArena* typeArena, TypeLevel minLevel, TypeId ty)
|
||||
{
|
||||
// Type levels of types from other modules are already global, so we don't need to promote anything inside
|
||||
if (ty->owningArena != typeArena)
|
||||
return;
|
||||
|
||||
PromoteTypeLevels ptl{log, typeArena, minLevel, outerScope, useScopes};
|
||||
PromoteTypeLevels ptl{log, typeArena, minLevel};
|
||||
ptl.traverse(ty);
|
||||
}
|
||||
|
||||
void promoteTypeLevels(TxnLog& log, const TypeArena* typeArena, TypeLevel minLevel, Scope* outerScope, bool useScopes, TypePackId tp)
|
||||
void promoteTypeLevels(TxnLog& log, const TypeArena* typeArena, TypeLevel minLevel, TypePackId tp)
|
||||
{
|
||||
// Type levels of types from other modules are already global, so we don't need to promote anything inside
|
||||
if (tp->owningArena != typeArena)
|
||||
return;
|
||||
|
||||
PromoteTypeLevels ptl{log, typeArena, minLevel, outerScope, useScopes};
|
||||
PromoteTypeLevels ptl{log, typeArena, minLevel};
|
||||
ptl.traverse(tp);
|
||||
}
|
||||
|
||||
|
@ -370,11 +352,8 @@ static std::optional<std::pair<Luau::Name, const SingletonType*>> getTableMatchT
|
|||
}
|
||||
|
||||
template<typename TY_A, typename TY_B>
|
||||
static bool subsumes(bool useScopes, TY_A* left, TY_B* right)
|
||||
static bool subsumes(TY_A* left, TY_B* right)
|
||||
{
|
||||
if (useScopes)
|
||||
return subsumes(left->scope, right->scope);
|
||||
else
|
||||
return left->level.subsumes(right->level);
|
||||
}
|
||||
|
||||
|
@ -464,7 +443,7 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool
|
|||
auto superFree = log.getMutable<FreeType>(superTy);
|
||||
auto subFree = log.getMutable<FreeType>(subTy);
|
||||
|
||||
if (superFree && subFree && subsumes(useNewSolver, superFree, subFree))
|
||||
if (superFree && subFree && subsumes(superFree, subFree))
|
||||
{
|
||||
if (!occursCheck(subTy, superTy, /* reversed = */ false))
|
||||
log.replace(subTy, BoundType(superTy));
|
||||
|
@ -475,7 +454,7 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool
|
|||
{
|
||||
if (!occursCheck(superTy, subTy, /* reversed = */ true))
|
||||
{
|
||||
if (subsumes(useNewSolver, superFree, subFree))
|
||||
if (subsumes(superFree, subFree))
|
||||
{
|
||||
log.changeLevel(subTy, superFree->level);
|
||||
}
|
||||
|
@ -489,7 +468,7 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool
|
|||
{
|
||||
// Unification can't change the level of a generic.
|
||||
auto subGeneric = log.getMutable<GenericType>(subTy);
|
||||
if (subGeneric && !subsumes(useNewSolver, subGeneric, superFree))
|
||||
if (subGeneric && !subsumes(subGeneric, superFree))
|
||||
{
|
||||
// TODO: a more informative error message? CLI-39912
|
||||
reportError(location, GenericError{"Generic subtype escaping scope"});
|
||||
|
@ -498,7 +477,7 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool
|
|||
|
||||
if (!occursCheck(superTy, subTy, /* reversed = */ true))
|
||||
{
|
||||
promoteTypeLevels(log, types, superFree->level, superFree->scope, useNewSolver, subTy);
|
||||
promoteTypeLevels(log, types, superFree->level, subTy);
|
||||
|
||||
Widen widen{types, builtinTypes};
|
||||
log.replace(superTy, BoundType(widen(subTy)));
|
||||
|
@ -515,7 +494,7 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool
|
|||
|
||||
// Unification can't change the level of a generic.
|
||||
auto superGeneric = log.getMutable<GenericType>(superTy);
|
||||
if (superGeneric && !subsumes(useNewSolver, superGeneric, subFree))
|
||||
if (superGeneric && !subsumes(superGeneric, subFree))
|
||||
{
|
||||
// TODO: a more informative error message? CLI-39912
|
||||
reportError(location, GenericError{"Generic supertype escaping scope"});
|
||||
|
@ -524,7 +503,7 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool
|
|||
|
||||
if (!occursCheck(subTy, superTy, /* reversed = */ false))
|
||||
{
|
||||
promoteTypeLevels(log, types, subFree->level, subFree->scope, useNewSolver, superTy);
|
||||
promoteTypeLevels(log, types, subFree->level, superTy);
|
||||
log.replace(subTy, BoundType(superTy));
|
||||
}
|
||||
|
||||
|
@ -536,7 +515,7 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool
|
|||
auto superGeneric = log.getMutable<GenericType>(superTy);
|
||||
auto subGeneric = log.getMutable<GenericType>(subTy);
|
||||
|
||||
if (superGeneric && subGeneric && subsumes(useNewSolver, superGeneric, subGeneric))
|
||||
if (superGeneric && subGeneric && subsumes(superGeneric, subGeneric))
|
||||
{
|
||||
if (!occursCheck(subTy, superTy, /* reversed = */ false))
|
||||
log.replace(subTy, BoundType(superTy));
|
||||
|
@ -753,9 +732,6 @@ void Unifier::tryUnifyUnionWithType(TypeId subTy, const UnionType* subUnion, Typ
|
|||
std::unique_ptr<Unifier> innerState = makeChildUnifier();
|
||||
innerState->tryUnify_(type, superTy);
|
||||
|
||||
if (useNewSolver)
|
||||
logs.push_back(std::move(innerState->log));
|
||||
|
||||
if (auto e = hasUnificationTooComplex(innerState->errors))
|
||||
unificationTooComplex = e;
|
||||
else if (innerState->failure)
|
||||
|
@ -870,14 +846,9 @@ void Unifier::tryUnifyTypeWithUnion(TypeId subTy, TypeId superTy, const UnionTyp
|
|||
if (!innerState->failure)
|
||||
{
|
||||
found = true;
|
||||
if (useNewSolver)
|
||||
logs.push_back(std::move(innerState->log));
|
||||
else
|
||||
{
|
||||
log.concat(std::move(innerState->log));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (innerState->errors.empty())
|
||||
{
|
||||
errorsSuppressed = true;
|
||||
|
@ -895,9 +866,6 @@ void Unifier::tryUnifyTypeWithUnion(TypeId subTy, TypeId superTy, const UnionTyp
|
|||
}
|
||||
}
|
||||
|
||||
if (useNewSolver)
|
||||
log.concatAsUnion(combineLogsIntoUnion(std::move(logs)), NotNull{types});
|
||||
|
||||
if (unificationTooComplex)
|
||||
{
|
||||
reportError(*unificationTooComplex);
|
||||
|
@ -975,16 +943,10 @@ void Unifier::tryUnifyTypeWithIntersection(TypeId subTy, TypeId superTy, const I
|
|||
firstFailedOption = {innerState->errors.front()};
|
||||
}
|
||||
|
||||
if (useNewSolver)
|
||||
logs.push_back(std::move(innerState->log));
|
||||
else
|
||||
log.concat(std::move(innerState->log));
|
||||
failure |= innerState->failure;
|
||||
}
|
||||
|
||||
if (useNewSolver)
|
||||
log.concat(combineLogsIntoIntersection(std::move(logs)));
|
||||
|
||||
if (unificationTooComplex)
|
||||
reportError(*unificationTooComplex);
|
||||
else if (firstFailedOption)
|
||||
|
@ -1032,28 +994,6 @@ void Unifier::tryUnifyIntersectionWithType(TypeId subTy, const IntersectionType*
|
|||
}
|
||||
}
|
||||
|
||||
if (useNewSolver && normalize)
|
||||
{
|
||||
// Sometimes a negation type is inside one of the types, e.g. { p: number } & { p: ~number }.
|
||||
NegationTypeFinder finder;
|
||||
finder.traverse(subTy);
|
||||
|
||||
if (finder.found)
|
||||
{
|
||||
// It is possible that A & B <: T even though A </: T and B </: T
|
||||
// for example (string?) & ~nil <: string.
|
||||
// We deal with this by type normalization.
|
||||
std::shared_ptr<const NormalizedType> subNorm = normalizer->normalize(subTy);
|
||||
std::shared_ptr<const NormalizedType> superNorm = normalizer->normalize(superTy);
|
||||
if (subNorm && superNorm)
|
||||
tryUnifyNormalizedTypes(subTy, superTy, *subNorm, *superNorm, "none of the intersection parts are compatible");
|
||||
else
|
||||
reportError(location, NormalizationTooComplex{});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<TxnLog> logs;
|
||||
|
||||
for (size_t i = 0; i < uv->parts.size(); ++i)
|
||||
|
@ -1070,7 +1010,7 @@ void Unifier::tryUnifyIntersectionWithType(TypeId subTy, const IntersectionType*
|
|||
{
|
||||
found = true;
|
||||
errorsSuppressed = innerState->failure;
|
||||
if (useNewSolver || innerState->failure)
|
||||
if (innerState->failure)
|
||||
logs.push_back(std::move(innerState->log));
|
||||
else
|
||||
{
|
||||
|
@ -1085,9 +1025,7 @@ void Unifier::tryUnifyIntersectionWithType(TypeId subTy, const IntersectionType*
|
|||
}
|
||||
}
|
||||
|
||||
if (useNewSolver)
|
||||
log.concat(combineLogsIntoIntersection(std::move(logs)));
|
||||
else if (errorsSuppressed)
|
||||
if (errorsSuppressed)
|
||||
log.concat(std::move(logs.front()));
|
||||
|
||||
if (unificationTooComplex)
|
||||
|
@ -1201,24 +1139,6 @@ void Unifier::tryUnifyNormalizedTypes(
|
|||
}
|
||||
}
|
||||
|
||||
if (useNewSolver)
|
||||
{
|
||||
for (TypeId superTable : superNorm.tables)
|
||||
{
|
||||
std::unique_ptr<Unifier> innerState = makeChildUnifier();
|
||||
innerState->tryUnify(subClass, superTable);
|
||||
|
||||
if (innerState->errors.empty())
|
||||
{
|
||||
found = true;
|
||||
log.concat(std::move(innerState->log));
|
||||
break;
|
||||
}
|
||||
else if (auto e = hasUnificationTooComplex(innerState->errors))
|
||||
return reportError(*e);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()});
|
||||
|
@ -1503,12 +1423,6 @@ struct WeirdIter
|
|||
}
|
||||
};
|
||||
|
||||
void Unifier::enableNewSolver()
|
||||
{
|
||||
useNewSolver = true;
|
||||
log.useScopes = true;
|
||||
}
|
||||
|
||||
ErrorVec Unifier::canUnify(TypeId subTy, TypeId superTy)
|
||||
{
|
||||
std::unique_ptr<Unifier> s = makeChildUnifier();
|
||||
|
@ -1588,8 +1502,6 @@ void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCal
|
|||
if (!occursCheck(superTp, subTp, /* reversed = */ true))
|
||||
{
|
||||
Widen widen{types, builtinTypes};
|
||||
if (useNewSolver)
|
||||
promoteTypeLevels(log, types, superFree->level, superFree->scope, /*useScopes*/ true, subTp);
|
||||
log.replace(superTp, Unifiable::Bound<TypePackId>(widen(subTp)));
|
||||
}
|
||||
}
|
||||
|
@ -1597,8 +1509,6 @@ void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCal
|
|||
{
|
||||
if (!occursCheck(subTp, superTp, /* reversed = */ false))
|
||||
{
|
||||
if (useNewSolver)
|
||||
promoteTypeLevels(log, types, subFree->level, subFree->scope, /*useScopes*/ true, superTp);
|
||||
log.replace(subTp, Unifiable::Bound<TypePackId>(superTp));
|
||||
}
|
||||
}
|
||||
|
@ -1687,51 +1597,6 @@ void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCal
|
|||
|
||||
// If both are at the end, we're done
|
||||
if (!superIter.good() && !subIter.good())
|
||||
{
|
||||
if (useNewSolver)
|
||||
{
|
||||
if (subIter.tail() && superIter.tail())
|
||||
tryUnify_(*subIter.tail(), *superIter.tail());
|
||||
else if (subIter.tail())
|
||||
{
|
||||
const TypePackId subTail = log.follow(*subIter.tail());
|
||||
|
||||
if (log.get<FreeTypePack>(subTail))
|
||||
tryUnify_(subTail, emptyTp);
|
||||
else if (log.get<GenericTypePack>(subTail))
|
||||
reportError(location, TypePackMismatch{subTail, emptyTp});
|
||||
else if (log.get<VariadicTypePack>(subTail) || log.get<ErrorTypePack>(subTail))
|
||||
{
|
||||
// Nothing. This is ok.
|
||||
}
|
||||
else
|
||||
{
|
||||
ice("Unexpected subtype tail pack " + toString(subTail), location);
|
||||
}
|
||||
}
|
||||
else if (superIter.tail())
|
||||
{
|
||||
const TypePackId superTail = log.follow(*superIter.tail());
|
||||
|
||||
if (log.get<FreeTypePack>(superTail))
|
||||
tryUnify_(emptyTp, superTail);
|
||||
else if (log.get<GenericTypePack>(superTail))
|
||||
reportError(location, TypePackMismatch{emptyTp, superTail});
|
||||
else if (log.get<VariadicTypePack>(superTail) || log.get<ErrorTypePack>(superTail))
|
||||
{
|
||||
// Nothing. This is ok.
|
||||
}
|
||||
else
|
||||
{
|
||||
ice("Unexpected supertype tail pack " + toString(superTail), location);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing. This is ok.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool lFreeTail = superTpv->tail && log.getMutable<FreeTypePack>(log.follow(*superTpv->tail)) != nullptr;
|
||||
const bool rFreeTail = subTpv->tail && log.getMutable<FreeTypePack>(log.follow(*subTpv->tail)) != nullptr;
|
||||
|
@ -1756,7 +1621,6 @@ void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCal
|
|||
else
|
||||
tryUnify_(*subTpv->tail, *superTpv->tail);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -2212,7 +2076,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection,
|
|||
variance = Invariant;
|
||||
|
||||
std::unique_ptr<Unifier> innerState = makeChildUnifier();
|
||||
if (useNewSolver || FFlag::LuauFixIndexerSubtypingOrdering)
|
||||
if (FFlag::LuauFixIndexerSubtypingOrdering)
|
||||
innerState->tryUnify_(prop.type(), superTable->indexer->indexResultType);
|
||||
else
|
||||
{
|
||||
|
@ -2496,50 +2360,9 @@ void Unifier::tryUnifyWithMetatable(TypeId subTy, TypeId superTy, bool reversed)
|
|||
switch (subTable->state)
|
||||
{
|
||||
case TableState::Free:
|
||||
{
|
||||
if (useNewSolver)
|
||||
{
|
||||
std::unique_ptr<Unifier> innerState = makeChildUnifier();
|
||||
bool missingProperty = false;
|
||||
|
||||
for (const auto& [propName, prop] : subTable->props)
|
||||
{
|
||||
if (std::optional<TypeId> mtPropTy = findTablePropertyRespectingMeta(superTy, propName))
|
||||
{
|
||||
innerState->tryUnify(prop.type(), *mtPropTy);
|
||||
}
|
||||
else
|
||||
{
|
||||
reportError(mismatchError);
|
||||
missingProperty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (const TableType* superTable = log.get<TableType>(log.follow(superMetatable->table)))
|
||||
{
|
||||
// TODO: Unify indexers.
|
||||
}
|
||||
|
||||
if (auto e = hasUnificationTooComplex(innerState->errors))
|
||||
reportError(*e);
|
||||
else if (!innerState->errors.empty())
|
||||
reportError(TypeError{
|
||||
location,
|
||||
TypeMismatch{reversed ? subTy : superTy, reversed ? superTy : subTy, "", innerState->errors.front(), mismatchContext()}
|
||||
});
|
||||
else if (!missingProperty)
|
||||
{
|
||||
log.concat(std::move(innerState->log));
|
||||
log.bindTable(subTy, superTy);
|
||||
failure |= innerState->failure;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tryUnify_(subTy, superMetatable->table);
|
||||
log.bindTable(subTy, superTy);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -2865,18 +2688,9 @@ std::optional<TypeId> Unifier::findTablePropertyRespectingMeta(TypeId lhsType, N
|
|||
return Luau::findTablePropertyRespectingMeta(builtinTypes, errors, lhsType, name, location);
|
||||
}
|
||||
|
||||
TxnLog Unifier::combineLogsIntoIntersection(std::vector<TxnLog> logs)
|
||||
{
|
||||
LUAU_ASSERT(useNewSolver);
|
||||
TxnLog result(useNewSolver);
|
||||
for (TxnLog& log : logs)
|
||||
result.concatAsIntersections(std::move(log), NotNull{types});
|
||||
return result;
|
||||
}
|
||||
|
||||
TxnLog Unifier::combineLogsIntoUnion(std::vector<TxnLog> logs)
|
||||
{
|
||||
TxnLog result(useNewSolver);
|
||||
TxnLog result;
|
||||
for (TxnLog& log : logs)
|
||||
result.concatAsUnion(std::move(log), NotNull{types});
|
||||
return result;
|
||||
|
@ -3021,9 +2835,6 @@ std::unique_ptr<Unifier> Unifier::makeChildUnifier()
|
|||
u->normalize = normalize;
|
||||
u->checkInhabited = checkInhabited;
|
||||
|
||||
if (useNewSolver)
|
||||
u->enableNewSolver();
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
|
|
|
@ -187,6 +187,11 @@ public:
|
|||
static bool fixupQuotedString(std::string& data);
|
||||
static void fixupMultilineString(std::string& data);
|
||||
|
||||
unsigned int getOffset() const
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
private:
|
||||
char peekch() const;
|
||||
char peekch(unsigned int lookahead) const;
|
||||
|
|
|
@ -71,6 +71,19 @@ struct ParseResult
|
|||
CstNodeMap cstNodeMap{nullptr};
|
||||
};
|
||||
|
||||
struct ParseExprResult
|
||||
{
|
||||
AstExpr* expr;
|
||||
size_t lines = 0;
|
||||
|
||||
std::vector<HotComment> hotcomments;
|
||||
std::vector<ParseError> errors;
|
||||
|
||||
std::vector<Comment> commentLocations;
|
||||
|
||||
CstNodeMap cstNodeMap{nullptr};
|
||||
};
|
||||
|
||||
static constexpr const char* kParseNameError = "%error-id%";
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -63,6 +63,14 @@ public:
|
|||
ParseOptions options = ParseOptions()
|
||||
);
|
||||
|
||||
static ParseExprResult parseExpr(
|
||||
const char* buffer,
|
||||
std::size_t bufferSize,
|
||||
AstNameTable& names,
|
||||
Allocator& allocator,
|
||||
ParseOptions options = ParseOptions()
|
||||
);
|
||||
|
||||
private:
|
||||
struct Name;
|
||||
struct Binding;
|
||||
|
|
|
@ -18,7 +18,6 @@ LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100)
|
|||
// flag so that we don't break production games by reverting syntax changes.
|
||||
// See docs/SyntaxChanges.md for an explanation.
|
||||
LUAU_FASTFLAGVARIABLE(LuauSolverV2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAllowFragmentParsing)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAllowComplexTypesInGenericParams)
|
||||
LUAU_FASTFLAGVARIABLE(LuauErrorRecoveryForTableTypes)
|
||||
LUAU_FASTFLAGVARIABLE(LuauErrorRecoveryForClassNames)
|
||||
|
@ -26,7 +25,7 @@ LUAU_FASTFLAGVARIABLE(LuauFixFunctionNameStartPosition)
|
|||
LUAU_FASTFLAGVARIABLE(LuauExtendStatEndPosWithSemicolon)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStoreCSTData)
|
||||
LUAU_FASTFLAGVARIABLE(LuauPreserveUnionIntersectionNodeForLeadingTokenSingleType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAstTypeGroup)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAstTypeGroup2)
|
||||
LUAU_FASTFLAGVARIABLE(ParserNoErrorLimit)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFixDoBlockEndLocation)
|
||||
|
||||
|
@ -182,6 +181,28 @@ ParseResult Parser::parse(const char* buffer, size_t bufferSize, AstNameTable& n
|
|||
}
|
||||
}
|
||||
|
||||
ParseExprResult Parser::parseExpr(const char* buffer, size_t bufferSize, AstNameTable& names, Allocator& allocator, ParseOptions options)
|
||||
{
|
||||
LUAU_TIMETRACE_SCOPE("Parser::parse", "Parser");
|
||||
|
||||
Parser p(buffer, bufferSize, names, allocator, options);
|
||||
|
||||
try
|
||||
{
|
||||
AstExpr* expr = p.parseExpr();
|
||||
size_t lines = p.lexer.current().location.end.line + (bufferSize > 0 && buffer[bufferSize - 1] != '\n');
|
||||
|
||||
return ParseExprResult{expr, lines, std::move(p.hotcomments), std::move(p.parseErrors), std::move(p.commentLocations), std::move(p.cstNodeMap)};
|
||||
}
|
||||
catch (ParseError& err)
|
||||
{
|
||||
// when catching a fatal error, append it to the list of non-fatal errors and return
|
||||
p.parseErrors.push_back(err);
|
||||
|
||||
return ParseExprResult{nullptr, 0, {}, p.parseErrors, {}, std::move(p.cstNodeMap)};
|
||||
}
|
||||
}
|
||||
|
||||
Parser::Parser(const char* buffer, size_t bufferSize, AstNameTable& names, Allocator& allocator, const ParseOptions& options)
|
||||
: options(options)
|
||||
, lexer(buffer, bufferSize, names, options.parseFragment ? options.parseFragment->resumePosition : Position(0, 0))
|
||||
|
@ -197,18 +218,9 @@ Parser::Parser(const char* buffer, size_t bufferSize, AstNameTable& names, Alloc
|
|||
functionStack.reserve(8);
|
||||
functionStack.push_back(top);
|
||||
|
||||
if (FFlag::LuauAllowFragmentParsing)
|
||||
{
|
||||
nameSelf = names.getOrAdd("self");
|
||||
nameNumber = names.getOrAdd("number");
|
||||
nameError = names.getOrAdd(kParseNameError);
|
||||
}
|
||||
else
|
||||
{
|
||||
nameSelf = names.addStatic("self");
|
||||
nameNumber = names.addStatic("number");
|
||||
nameError = names.addStatic(kParseNameError);
|
||||
}
|
||||
nameNil = names.getOrAdd("nil"); // nil is a reserved keyword
|
||||
|
||||
matchRecoveryStopOnToken.assign(Lexeme::Type::Reserved_END, 0);
|
||||
|
@ -231,15 +243,12 @@ Parser::Parser(const char* buffer, size_t bufferSize, AstNameTable& names, Alloc
|
|||
scratchLocal.reserve(16);
|
||||
scratchBinding.reserve(16);
|
||||
|
||||
if (FFlag::LuauAllowFragmentParsing)
|
||||
{
|
||||
if (options.parseFragment)
|
||||
{
|
||||
localMap = options.parseFragment->localMap;
|
||||
localStack = options.parseFragment->localStack;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Parser::blockFollow(const Lexeme& l)
|
||||
{
|
||||
|
@ -1723,7 +1732,7 @@ std::pair<Location, AstTypeList> Parser::parseReturnType()
|
|||
if (lexer.current().type != Lexeme::SkinnyArrow && resultNames.empty())
|
||||
{
|
||||
// If it turns out that it's just '(A)', it's possible that there are unions/intersections to follow, so fold over it.
|
||||
if (FFlag::LuauAstTypeGroup)
|
||||
if (FFlag::LuauAstTypeGroup2)
|
||||
{
|
||||
if (result.size() == 1 && varargAnnotation == nullptr)
|
||||
{
|
||||
|
@ -2034,6 +2043,7 @@ AstTypeOrPack Parser::parseFunctionType(bool allowPack, const AstArray<AstAttr*>
|
|||
if (lexer.current().type != ')')
|
||||
varargAnnotation = parseTypeList(params, names);
|
||||
|
||||
Location closeArgsLocation = lexer.current().location;
|
||||
expectMatchAndConsume(')', parameterStart, true);
|
||||
|
||||
matchRecoveryStopOnToken[Lexeme::SkinnyArrow]--;
|
||||
|
@ -2052,8 +2062,8 @@ AstTypeOrPack Parser::parseFunctionType(bool allowPack, const AstArray<AstAttr*>
|
|||
return {{}, allocator.alloc<AstTypePackExplicit>(begin.location, AstTypeList{paramTypes, nullptr})};
|
||||
else
|
||||
{
|
||||
if (FFlag::LuauAstTypeGroup)
|
||||
return {allocator.alloc<AstTypeGroup>(Location(parameterStart.location, params[0]->location), params[0]), {}};
|
||||
if (FFlag::LuauAstTypeGroup2)
|
||||
return {allocator.alloc<AstTypeGroup>(Location(parameterStart.location, closeArgsLocation), params[0]), {}};
|
||||
else
|
||||
return {params[0], {}};
|
||||
}
|
||||
|
@ -3562,7 +3572,7 @@ AstArray<AstTypeOrPack> Parser::parseTypeParams(Position* openingPosition, TempV
|
|||
// the next lexeme is one that follows a type
|
||||
// (&, |, ?), then assume that this was actually a
|
||||
// parenthesized type.
|
||||
if (FFlag::LuauAstTypeGroup)
|
||||
if (FFlag::LuauAstTypeGroup2)
|
||||
{
|
||||
auto parenthesizedType = explicitTypePack->typeList.types.data[0];
|
||||
parameters.push_back(
|
||||
|
|
|
@ -791,8 +791,6 @@ int replMain(int argc, char** argv)
|
|||
{
|
||||
Luau::assertHandler() = assertionHandler;
|
||||
|
||||
setLuauFlagsDefault();
|
||||
|
||||
#ifdef _WIN32
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
#include "Luau/Repl.h"
|
||||
#include "Luau/Flags.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
setLuauFlagsDefault();
|
||||
|
||||
return replMain(argc, argv);
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
LUAU_FASTFLAGVARIABLE(DebugCodegenNoOpt)
|
||||
LUAU_FASTFLAGVARIABLE(DebugCodegenOptSize)
|
||||
LUAU_FASTFLAGVARIABLE(DebugCodegenSkipNumbering)
|
||||
LUAU_FASTFLAGVARIABLE(CodegenWiderLoweringStats)
|
||||
|
||||
// Per-module IR instruction count limit
|
||||
LUAU_FASTINTVARIABLE(CodegenHeuristicsInstructionLimit, 1'048'576) // 1 M
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
LUAU_FASTFLAG(DebugCodegenNoOpt)
|
||||
LUAU_FASTFLAG(DebugCodegenOptSize)
|
||||
LUAU_FASTFLAG(DebugCodegenSkipNumbering)
|
||||
LUAU_FASTFLAG(CodegenWiderLoweringStats)
|
||||
LUAU_FASTINT(CodegenHeuristicsInstructionLimit)
|
||||
LUAU_FASTINT(CodegenHeuristicsBlockLimit)
|
||||
LUAU_FASTINT(CodegenHeuristicsBlockInstructionLimit)
|
||||
|
@ -300,7 +299,6 @@ inline bool lowerFunction(
|
|||
CodeGenCompilationResult& codeGenCompilationResult
|
||||
)
|
||||
{
|
||||
if (FFlag::CodegenWiderLoweringStats)
|
||||
ir.function.stats = stats;
|
||||
|
||||
killUnusedBlocks(ir.function);
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "lgc.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot)
|
||||
LUAU_FASTFLAG(LuauCodeGenLerp)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -706,7 +705,6 @@ void IrLoweringA64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
|
|||
}
|
||||
case IrCmd::SELECT_NUM:
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauCodeGenLerp);
|
||||
inst.regA64 = regs.allocReuse(KindA64::d, index, {inst.a, inst.b, inst.c, inst.d});
|
||||
|
||||
RegisterA64 temp1 = tempDouble(inst.a);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include "lgc.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot)
|
||||
LUAU_FASTFLAG(LuauCodeGenLerp)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -625,7 +624,6 @@ void IrLoweringX64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
|
|||
}
|
||||
case IrCmd::SELECT_NUM:
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauCodeGenLerp);
|
||||
inst.regX64 = regs.allocRegOrReuse(SizeX64::xmmword, index, {inst.a, inst.c, inst.d}); // can't reuse b if a is a memory operand
|
||||
|
||||
ScopedRegX64 tmp{regs, SizeX64::xmmword};
|
||||
|
|
|
@ -13,9 +13,7 @@
|
|||
static const int kMinMaxUnrolledParams = 5;
|
||||
static const int kBit32BinaryOpUnrolledParams = 5;
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauVectorLibNativeCodegen);
|
||||
LUAU_FASTFLAGVARIABLE(LuauVectorLibNativeDot);
|
||||
LUAU_FASTFLAGVARIABLE(LuauCodeGenLerp);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -297,8 +295,6 @@ static BuiltinImplResult translateBuiltinMathLerp(
|
|||
int pcpos
|
||||
)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauCodeGenLerp);
|
||||
|
||||
if (nparams < 3 || nresults > 1)
|
||||
return {BuiltinImplType::None, -1};
|
||||
|
||||
|
@ -936,8 +932,6 @@ static BuiltinImplResult translateBuiltinVectorMagnitude(
|
|||
int pcpos
|
||||
)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeCodegen);
|
||||
|
||||
IrOp arg1 = build.vmReg(arg);
|
||||
|
||||
if (nparams != 1 || nresults > 1 || arg1.kind == IrOpKind::Constant)
|
||||
|
@ -985,8 +979,6 @@ static BuiltinImplResult translateBuiltinVectorNormalize(
|
|||
int pcpos
|
||||
)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeCodegen);
|
||||
|
||||
IrOp arg1 = build.vmReg(arg);
|
||||
|
||||
if (nparams != 1 || nresults > 1 || arg1.kind == IrOpKind::Constant)
|
||||
|
@ -1037,8 +1029,6 @@ static BuiltinImplResult translateBuiltinVectorNormalize(
|
|||
|
||||
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)
|
||||
|
@ -1076,8 +1066,6 @@ static BuiltinImplResult translateBuiltinVectorCross(IrBuilder& build, int npara
|
|||
|
||||
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)
|
||||
|
@ -1130,8 +1118,6 @@ static BuiltinImplResult translateBuiltinVectorMap1(
|
|||
int pcpos
|
||||
)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeCodegen);
|
||||
|
||||
IrOp arg1 = build.vmReg(arg);
|
||||
|
||||
if (nparams != 1 || nresults > 1 || arg1.kind == IrOpKind::Constant)
|
||||
|
@ -1165,8 +1151,6 @@ static BuiltinImplResult translateBuiltinVectorClamp(
|
|||
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)
|
||||
|
@ -1231,8 +1215,6 @@ static BuiltinImplResult translateBuiltinVectorMap2(
|
|||
int pcpos
|
||||
)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeCodegen);
|
||||
|
||||
IrOp arg1 = build.vmReg(arg);
|
||||
|
||||
if (nparams != 2 || nresults > 1 || arg1.kind == IrOpKind::Constant || args.kind == IrOpKind::Constant)
|
||||
|
@ -1273,8 +1255,6 @@ 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};
|
||||
|
@ -1396,36 +1376,29 @@ BuiltinImplResult translateBuiltin(
|
|||
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;
|
||||
return translateBuiltinVectorMagnitude(build, nparams, ra, arg, args, arg3, nresults, pcpos);
|
||||
case LBF_VECTOR_NORMALIZE:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorNormalize(build, nparams, ra, arg, args, arg3, nresults, pcpos) : noneResult;
|
||||
return translateBuiltinVectorNormalize(build, nparams, ra, arg, args, arg3, nresults, pcpos);
|
||||
case LBF_VECTOR_CROSS:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorCross(build, nparams, ra, arg, args, arg3, nresults, pcpos) : noneResult;
|
||||
return translateBuiltinVectorCross(build, nparams, ra, arg, args, arg3, nresults, pcpos);
|
||||
case LBF_VECTOR_DOT:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorDot(build, nparams, ra, arg, args, arg3, nresults, pcpos) : noneResult;
|
||||
return translateBuiltinVectorDot(build, nparams, ra, arg, args, arg3, nresults, pcpos);
|
||||
case LBF_VECTOR_FLOOR:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorMap1(build, IrCmd::FLOOR_NUM, nparams, ra, arg, args, arg3, nresults, pcpos)
|
||||
: noneResult;
|
||||
return translateBuiltinVectorMap1(build, IrCmd::FLOOR_NUM, nparams, ra, arg, args, arg3, nresults, pcpos);
|
||||
case LBF_VECTOR_CEIL:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorMap1(build, IrCmd::CEIL_NUM, nparams, ra, arg, args, arg3, nresults, pcpos)
|
||||
: noneResult;
|
||||
return translateBuiltinVectorMap1(build, IrCmd::CEIL_NUM, nparams, ra, arg, args, arg3, nresults, pcpos);
|
||||
case LBF_VECTOR_ABS:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorMap1(build, IrCmd::ABS_NUM, nparams, ra, arg, args, arg3, nresults, pcpos)
|
||||
: noneResult;
|
||||
return translateBuiltinVectorMap1(build, IrCmd::ABS_NUM, nparams, ra, arg, args, arg3, nresults, pcpos);
|
||||
case LBF_VECTOR_SIGN:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorMap1(build, IrCmd::SIGN_NUM, nparams, ra, arg, args, arg3, nresults, pcpos)
|
||||
: noneResult;
|
||||
return translateBuiltinVectorMap1(build, IrCmd::SIGN_NUM, nparams, ra, arg, args, arg3, nresults, pcpos);
|
||||
case LBF_VECTOR_CLAMP:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorClamp(build, nparams, ra, arg, args, arg3, nresults, fallback, pcpos)
|
||||
: noneResult;
|
||||
return translateBuiltinVectorClamp(build, nparams, ra, arg, args, arg3, nresults, fallback, pcpos);
|
||||
case LBF_VECTOR_MIN:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorMap2(build, IrCmd::MIN_NUM, nparams, ra, arg, args, arg3, nresults, pcpos)
|
||||
: noneResult;
|
||||
return translateBuiltinVectorMap2(build, IrCmd::MIN_NUM, nparams, ra, arg, args, arg3, nresults, pcpos);
|
||||
case LBF_VECTOR_MAX:
|
||||
return FFlag::LuauVectorLibNativeCodegen ? translateBuiltinVectorMap2(build, IrCmd::MAX_NUM, nparams, ra, arg, args, arg3, nresults, pcpos)
|
||||
: noneResult;
|
||||
return translateBuiltinVectorMap2(build, IrCmd::MAX_NUM, nparams, ra, arg, args, arg3, nresults, pcpos);
|
||||
case LBF_MATH_LERP:
|
||||
return FFlag::LuauCodeGenLerp ? translateBuiltinMathLerp(build, nparams, ra, arg, args, arg3, nresults, fallback, pcpos) : noneResult;
|
||||
return translateBuiltinMathLerp(build, nparams, ra, arg, args, arg3, nresults, fallback, pcpos);
|
||||
default:
|
||||
return {BuiltinImplType::None, -1};
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
#include <math.h>
|
||||
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot);
|
||||
LUAU_FASTFLAG(LuauCodeGenLerp);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -663,7 +662,6 @@ void foldConstants(IrBuilder& build, IrFunction& function, IrBlock& block, uint3
|
|||
}
|
||||
break;
|
||||
case IrCmd::SELECT_NUM:
|
||||
LUAU_ASSERT(FFlag::LuauCodeGenLerp);
|
||||
if (inst.c.kind == IrOpKind::Constant && inst.d.kind == IrOpKind::Constant)
|
||||
{
|
||||
double c = function.doubleOp(inst.c);
|
||||
|
|
|
@ -22,7 +22,6 @@ LUAU_FASTINTVARIABLE(LuauCodeGenReuseUdataTagLimit, 64)
|
|||
LUAU_FASTINTVARIABLE(LuauCodeGenLiveSlotReuseLimit, 8)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauAbortingChecks)
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCodeGenLimitLiveSlotReuse)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -200,11 +199,7 @@ struct ConstPropState
|
|||
// Same goes for table array elements as well
|
||||
void invalidateHeapTableData()
|
||||
{
|
||||
if (FFlag::LuauCodeGenLimitLiveSlotReuse)
|
||||
getSlotNodeCache.clear();
|
||||
else
|
||||
getSlotNodeCache_DEPRECATED.clear();
|
||||
|
||||
checkSlotMatchCache.clear();
|
||||
|
||||
getArrAddrCache.clear();
|
||||
|
@ -428,8 +423,6 @@ struct ConstPropState
|
|||
// Note that this pressure is approximate, as some values that might have been live at one point could have been marked dead later
|
||||
int getMaxInternalOverlap(std::vector<NumberedInstruction>& set, size_t slot)
|
||||
{
|
||||
CODEGEN_ASSERT(FFlag::LuauCodeGenLimitLiveSlotReuse);
|
||||
|
||||
// Start with one live range for the slot we want to reuse
|
||||
int curr = 1;
|
||||
|
||||
|
@ -487,8 +480,6 @@ struct ConstPropState
|
|||
regs[i] = RegisterInfo();
|
||||
|
||||
maxReg = 0;
|
||||
|
||||
if (FFlag::LuauCodeGenLimitLiveSlotReuse)
|
||||
instPos = 0u;
|
||||
|
||||
inSafeEnv = false;
|
||||
|
@ -526,7 +517,6 @@ struct ConstPropState
|
|||
|
||||
// Heap changes might affect table state
|
||||
std::vector<NumberedInstruction> getSlotNodeCache; // Additionally, pcpos argument might be different
|
||||
std::vector<uint32_t> getSlotNodeCache_DEPRECATED; // Additionally, pcpos argument might be different
|
||||
std::vector<uint32_t> checkSlotMatchCache; // Additionally, fallback block argument might be different
|
||||
|
||||
std::vector<uint32_t> getArrAddrCache;
|
||||
|
@ -651,7 +641,6 @@ static void handleBuiltinEffects(ConstPropState& state, LuauBuiltinFunction bfid
|
|||
|
||||
static void constPropInInst(ConstPropState& state, IrBuilder& build, IrFunction& function, IrBlock& block, IrInst& inst, uint32_t index)
|
||||
{
|
||||
if (FFlag::LuauCodeGenLimitLiveSlotReuse)
|
||||
state.instPos++;
|
||||
|
||||
switch (inst.cmd)
|
||||
|
@ -1260,8 +1249,6 @@ static void constPropInInst(ConstPropState& state, IrBuilder& build, IrFunction&
|
|||
state.getArrAddrCache.push_back(index);
|
||||
break;
|
||||
case IrCmd::GET_SLOT_NODE_ADDR:
|
||||
if (FFlag::LuauCodeGenLimitLiveSlotReuse)
|
||||
{
|
||||
for (size_t i = 0; i < state.getSlotNodeCache.size(); i++)
|
||||
{
|
||||
auto&& [prevIdx, num, lastNum] = state.getSlotNodeCache[i];
|
||||
|
@ -1286,23 +1273,6 @@ static void constPropInInst(ConstPropState& state, IrBuilder& build, IrFunction&
|
|||
|
||||
if (int(state.getSlotNodeCache.size()) < FInt::LuauCodeGenReuseSlotLimit)
|
||||
state.getSlotNodeCache.push_back({index, state.instPos, state.instPos});
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint32_t prevIdx : state.getSlotNodeCache_DEPRECATED)
|
||||
{
|
||||
const IrInst& prev = function.instructions[prevIdx];
|
||||
|
||||
if (prev.a == inst.a && prev.c == inst.c)
|
||||
{
|
||||
substitute(function, inst, IrOp{IrOpKind::Inst, prevIdx});
|
||||
return; // Break out from both the loop and the switch
|
||||
}
|
||||
}
|
||||
|
||||
if (int(state.getSlotNodeCache_DEPRECATED.size()) < FInt::LuauCodeGenReuseSlotLimit)
|
||||
state.getSlotNodeCache_DEPRECATED.push_back(index);
|
||||
}
|
||||
break;
|
||||
case IrCmd::GET_HASH_NODE_ADDR:
|
||||
case IrCmd::GET_CLOSURE_UPVAL_ADDR:
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
|
||||
#include <math.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauVector2Constants)
|
||||
LUAU_FASTFLAG(LuauCompileMathLerp)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace Compile
|
||||
|
@ -476,7 +473,7 @@ Constant foldBuiltin(int bfid, const Constant* args, size_t count)
|
|||
case LBF_VECTOR:
|
||||
if (count >= 2 && args[0].type == Constant::Type_Number && args[1].type == Constant::Type_Number)
|
||||
{
|
||||
if (count == 2 && FFlag::LuauVector2Constants)
|
||||
if (count == 2)
|
||||
return cvector(args[0].valueNumber, args[1].valueNumber, 0.0, 0.0);
|
||||
else if (count == 3 && args[2].type == Constant::Type_Number)
|
||||
return cvector(args[0].valueNumber, args[1].valueNumber, args[2].valueNumber, 0.0);
|
||||
|
@ -486,8 +483,7 @@ Constant foldBuiltin(int bfid, const Constant* args, size_t count)
|
|||
break;
|
||||
|
||||
case LBF_MATH_LERP:
|
||||
if (FFlag::LuauCompileMathLerp && count == 3 && args[0].type == Constant::Type_Number && args[1].type == Constant::Type_Number &&
|
||||
args[2].type == Constant::Type_Number)
|
||||
if (count == 3 && args[0].type == Constant::Type_Number && args[1].type == Constant::Type_Number && args[2].type == Constant::Type_Number)
|
||||
{
|
||||
double a = args[0].valueNumber;
|
||||
double b = args[1].valueNumber;
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
|
||||
#include <array>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileMathLerp)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace Compile
|
||||
|
@ -139,7 +137,7 @@ static int getBuiltinFunctionId(const Builtin& builtin, const CompileOptions& op
|
|||
return LBF_MATH_SIGN;
|
||||
if (builtin.method == "round")
|
||||
return LBF_MATH_ROUND;
|
||||
if (FFlag::LuauCompileMathLerp && builtin.method == "lerp")
|
||||
if (builtin.method == "lerp")
|
||||
return LBF_MATH_LERP;
|
||||
}
|
||||
|
||||
|
@ -556,7 +554,6 @@ BuiltinInfo getBuiltinInfo(int bfid)
|
|||
return {-1, 1}; // variadic
|
||||
|
||||
case LBF_MATH_LERP:
|
||||
LUAU_ASSERT(FFlag::LuauCompileMathLerp);
|
||||
return {3, 1, BuiltinInfo::Flag_NoneSafe};
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauBufferBitMethods2)
|
||||
|
||||
// while C API returns 'size_t' for binary compatibility in case of future extensions,
|
||||
// in the current implementation, length and offset are limited to 31 bits
|
||||
// because offset is limited to an integer, a single 64bit comparison can be used and will not overflow
|
||||
|
@ -330,34 +328,6 @@ static int buffer_writebits(lua_State* L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const luaL_Reg bufferlib_DEPRECATED[] = {
|
||||
{"create", buffer_create},
|
||||
{"fromstring", buffer_fromstring},
|
||||
{"tostring", buffer_tostring},
|
||||
{"readi8", buffer_readinteger<int8_t>},
|
||||
{"readu8", buffer_readinteger<uint8_t>},
|
||||
{"readi16", buffer_readinteger<int16_t>},
|
||||
{"readu16", buffer_readinteger<uint16_t>},
|
||||
{"readi32", buffer_readinteger<int32_t>},
|
||||
{"readu32", buffer_readinteger<uint32_t>},
|
||||
{"readf32", buffer_readfp<float, uint32_t>},
|
||||
{"readf64", buffer_readfp<double, uint64_t>},
|
||||
{"writei8", buffer_writeinteger<int8_t>},
|
||||
{"writeu8", buffer_writeinteger<uint8_t>},
|
||||
{"writei16", buffer_writeinteger<int16_t>},
|
||||
{"writeu16", buffer_writeinteger<uint16_t>},
|
||||
{"writei32", buffer_writeinteger<int32_t>},
|
||||
{"writeu32", buffer_writeinteger<uint32_t>},
|
||||
{"writef32", buffer_writefp<float, uint32_t>},
|
||||
{"writef64", buffer_writefp<double, uint64_t>},
|
||||
{"readstring", buffer_readstring},
|
||||
{"writestring", buffer_writestring},
|
||||
{"len", buffer_len},
|
||||
{"copy", buffer_copy},
|
||||
{"fill", buffer_fill},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static const luaL_Reg bufferlib[] = {
|
||||
{"create", buffer_create},
|
||||
{"fromstring", buffer_fromstring},
|
||||
|
@ -390,7 +360,7 @@ static const luaL_Reg bufferlib[] = {
|
|||
|
||||
int luaopen_buffer(lua_State* L)
|
||||
{
|
||||
luaL_register(L, LUA_BUFFERLIBNAME, FFlag::LuauBufferBitMethods2 ? bufferlib : bufferlib_DEPRECATED);
|
||||
luaL_register(L, LUA_BUFFERLIBNAME, bufferlib);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
LUAU_FASTFLAG(LuauVector2Constructor)
|
||||
|
||||
// luauF functions implement FASTCALL instruction that performs a direct execution of some builtin functions from the VM
|
||||
// The rule of thumb is that FASTCALL functions can not call user code, yield, fail, or reallocate stack.
|
||||
// If types of the arguments mismatch, luauF_* needs to return -1 and the execution will fall back to the usual call path
|
||||
|
@ -1056,8 +1054,6 @@ static int luauF_tunpack(lua_State* L, StkId res, TValue* arg0, int nresults, St
|
|||
}
|
||||
|
||||
static int luauF_vector(lua_State* L, StkId res, TValue* arg0, int nresults, StkId args, int nparams)
|
||||
{
|
||||
if (FFlag::LuauVector2Constructor)
|
||||
{
|
||||
if (nparams >= 2 && nresults <= 1 && ttisnumber(arg0) && ttisnumber(args))
|
||||
{
|
||||
|
@ -1087,31 +1083,6 @@ static int luauF_vector(lua_State* L, StkId res, TValue* arg0, int nresults, Stk
|
|||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nparams >= 3 && nresults <= 1 && ttisnumber(arg0) && ttisnumber(args) && ttisnumber(args + 1))
|
||||
{
|
||||
double x = nvalue(arg0);
|
||||
double y = nvalue(args);
|
||||
double z = nvalue(args + 1);
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
double w = 0.0;
|
||||
if (nparams >= 4)
|
||||
{
|
||||
if (!ttisnumber(args + 2))
|
||||
return -1;
|
||||
w = nvalue(args + 2);
|
||||
}
|
||||
setvvalue(res, float(x), float(y), float(z), float(w));
|
||||
#else
|
||||
setvvalue(res, float(x), float(y), float(z), 0.0f);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauMathLerp)
|
||||
|
||||
#undef PI
|
||||
#define PI (3.14159265358979323846)
|
||||
#define RADIANS_PER_DEGREE (PI / 180.0)
|
||||
|
@ -463,6 +461,7 @@ static const luaL_Reg mathlib[] = {
|
|||
{"sign", math_sign},
|
||||
{"round", math_round},
|
||||
{"map", math_map},
|
||||
{"lerp", math_lerp},
|
||||
{NULL, NULL},
|
||||
};
|
||||
|
||||
|
@ -483,11 +482,5 @@ int luaopen_math(lua_State* L)
|
|||
lua_pushnumber(L, HUGE_VAL);
|
||||
lua_setfield(L, -2, "huge");
|
||||
|
||||
if (FFlag::LuauMathLerp)
|
||||
{
|
||||
lua_pushcfunction(L, math_lerp, "lerp");
|
||||
lua_setfield(L, -2, "lerp");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
|
||||
#include <math.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauVector2Constructor)
|
||||
|
||||
static int vector_create(lua_State* L)
|
||||
{
|
||||
// checking argument count to avoid accepting 'nil' as a valid value
|
||||
|
@ -15,7 +13,7 @@ static int vector_create(lua_State* L)
|
|||
|
||||
double x = luaL_checknumber(L, 1);
|
||||
double y = luaL_checknumber(L, 2);
|
||||
double z = FFlag::LuauVector2Constructor ? (count >= 3 ? luaL_checknumber(L, 3) : 0.0) : luaL_checknumber(L, 3);
|
||||
double z = count >= 3 ? luaL_checknumber(L, 3) : 0.0;
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
double w = count >= 4 ? luaL_checknumber(L, 4) : 0.0;
|
||||
|
|
|
@ -19,10 +19,10 @@ LUAU_FASTFLAG(DebugLuauFreezeArena)
|
|||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_FASTFLAG(StudioReportLuauAny2)
|
||||
LUAU_FASTFLAG(LuauTrackInteriorFreeTypesOnScope)
|
||||
LUAU_FASTFLAG(LuauAlwaysFillInFunctionCallDiscriminantTypes)
|
||||
LUAU_FASTFLAG(LuauStoreCSTData)
|
||||
LUAU_FASTFLAG(LuauAstTypeGroup)
|
||||
LUAU_FASTFLAG(LuauAstTypeGroup2)
|
||||
LUAU_FASTFLAG(LuauDeferBidirectionalInferenceForTableAssignment)
|
||||
LUAU_FASTFLAG(LuauSkipNoRefineDuringRefinement)
|
||||
|
||||
|
||||
struct ATSFixture : BuiltinsFixture
|
||||
|
@ -76,7 +76,7 @@ export type t8<t8> = t0 &(<t0 ...>(true | any)->(''))
|
|||
|
||||
LUAU_ASSERT(module->ats.typeInfo.size() == 1);
|
||||
LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::Alias);
|
||||
if (FFlag::LuauStoreCSTData && FFlag::LuauAstTypeGroup)
|
||||
if (FFlag::LuauStoreCSTData && FFlag::LuauAstTypeGroup2)
|
||||
{
|
||||
LUAU_ASSERT(module->ats.typeInfo[0].node == "export type t8<t8> = t0& (<t0...>( true | any)->(''))");
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ export type t8<t8> = t0 &(<t0 ...>(true | any)->(''))
|
|||
{
|
||||
LUAU_ASSERT(module->ats.typeInfo[0].node == "export type t8<t8> = t0 &(<t0...>( true | any)->(''))");
|
||||
}
|
||||
else if (FFlag::LuauAstTypeGroup)
|
||||
else if (FFlag::LuauAstTypeGroup2)
|
||||
{
|
||||
LUAU_ASSERT(module->ats.typeInfo[0].node == "export type t8<t8> = t0& (<t0 ...>(true | any)->(''))");
|
||||
}
|
||||
|
@ -429,7 +429,6 @@ TEST_CASE_FIXTURE(ATSFixture, "CannotExtendTable")
|
|||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::StudioReportLuauAny2, true},
|
||||
{FFlag::LuauAlwaysFillInFunctionCallDiscriminantTypes, true},
|
||||
};
|
||||
|
||||
fileResolver.source["game/Gui/Modules/A"] = R"(
|
||||
|
@ -449,6 +448,13 @@ end
|
|||
|
||||
ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A");
|
||||
|
||||
if (FFlag::LuauSkipNoRefineDuringRefinement)
|
||||
{
|
||||
REQUIRE_EQ(module->ats.typeInfo.size(), 1);
|
||||
CHECK_EQ(module->ats.typeInfo[0].code, Pattern::Assign);
|
||||
CHECK_EQ(module->ats.typeInfo[0].node, "descendant.CollisionGroup = CAR_COLLISION_GROUP");
|
||||
}
|
||||
else
|
||||
LUAU_ASSERT(module->ats.typeInfo.size() == 0);
|
||||
}
|
||||
|
||||
|
@ -522,7 +528,6 @@ TEST_CASE_FIXTURE(ATSFixture, "racing_collision_2")
|
|||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::StudioReportLuauAny2, true},
|
||||
{FFlag::LuauAlwaysFillInFunctionCallDiscriminantTypes, true},
|
||||
};
|
||||
|
||||
fileResolver.source["game/Gui/Modules/A"] = R"(
|
||||
|
@ -590,6 +595,9 @@ initialize()
|
|||
|
||||
ModulePtr module = frontend.moduleResolver.getModule("game/Gui/Modules/A");
|
||||
|
||||
if (FFlag::LuauSkipNoRefineDuringRefinement)
|
||||
CHECK_EQ(module->ats.typeInfo.size(), 12);
|
||||
else
|
||||
LUAU_ASSERT(module->ats.typeInfo.size() == 11);
|
||||
LUAU_ASSERT(module->ats.typeInfo[0].code == Pattern::FuncArg);
|
||||
if (FFlag::LuauStoreCSTData)
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauAstTypeGroup)
|
||||
LUAU_FASTFLAG(LuauAstTypeGroup2)
|
||||
|
||||
struct JsonEncoderFixture
|
||||
{
|
||||
|
@ -473,10 +473,10 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_annotation")
|
|||
{
|
||||
AstStat* statement = expectParseStatement("type T = ((number) -> (string | nil)) & ((string) -> ())");
|
||||
|
||||
if (FFlag::LuauAstTypeGroup)
|
||||
if (FFlag::LuauAstTypeGroup2)
|
||||
{
|
||||
std::string_view expected =
|
||||
R"({"type":"AstStatTypeAlias","location":"0,0 - 0,55","name":"T","generics":[],"genericPacks":[],"value":{"type":"AstTypeIntersection","location":"0,9 - 0,55","types":[{"type":"AstTypeGroup","location":"0,9 - 0,36","inner":{"type":"AstTypeFunction","location":"0,10 - 0,36","attributes":[],"generics":[],"genericPacks":[],"argTypes":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"0,11 - 0,17","name":"number","nameLocation":"0,11 - 0,17","parameters":[]}]},"argNames":[],"returnTypes":{"type":"AstTypeList","types":[{"type":"AstTypeGroup","location":"0,22 - 0,36","inner":{"type":"AstTypeUnion","location":"0,23 - 0,35","types":[{"type":"AstTypeReference","location":"0,23 - 0,29","name":"string","nameLocation":"0,23 - 0,29","parameters":[]},{"type":"AstTypeReference","location":"0,32 - 0,35","name":"nil","nameLocation":"0,32 - 0,35","parameters":[]}]}}]}}},{"type":"AstTypeGroup","location":"0,40 - 0,55","inner":{"type":"AstTypeFunction","location":"0,41 - 0,55","attributes":[],"generics":[],"genericPacks":[],"argTypes":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"0,42 - 0,48","name":"string","nameLocation":"0,42 - 0,48","parameters":[]}]},"argNames":[],"returnTypes":{"type":"AstTypeList","types":[]}}}]},"exported":false})";
|
||||
R"({"type":"AstStatTypeAlias","location":"0,0 - 0,56","name":"T","generics":[],"genericPacks":[],"value":{"type":"AstTypeIntersection","location":"0,9 - 0,56","types":[{"type":"AstTypeGroup","location":"0,9 - 0,37","inner":{"type":"AstTypeFunction","location":"0,10 - 0,36","attributes":[],"generics":[],"genericPacks":[],"argTypes":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"0,11 - 0,17","name":"number","nameLocation":"0,11 - 0,17","parameters":[]}]},"argNames":[],"returnTypes":{"type":"AstTypeList","types":[{"type":"AstTypeGroup","location":"0,22 - 0,36","inner":{"type":"AstTypeUnion","location":"0,23 - 0,35","types":[{"type":"AstTypeReference","location":"0,23 - 0,29","name":"string","nameLocation":"0,23 - 0,29","parameters":[]},{"type":"AstTypeReference","location":"0,32 - 0,35","name":"nil","nameLocation":"0,32 - 0,35","parameters":[]}]}}]}}},{"type":"AstTypeGroup","location":"0,40 - 0,56","inner":{"type":"AstTypeFunction","location":"0,41 - 0,55","attributes":[],"generics":[],"genericPacks":[],"argTypes":{"type":"AstTypeList","types":[{"type":"AstTypeReference","location":"0,42 - 0,48","name":"string","nameLocation":"0,42 - 0,48","parameters":[]}]},"argNames":[],"returnTypes":{"type":"AstTypeList","types":[]}}}]},"exported":false})";
|
||||
CHECK(toJson(statement) == expected);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -23,7 +23,6 @@ LUAU_FASTINT(LuauCompileInlineThresholdMaxBoost)
|
|||
LUAU_FASTINT(LuauCompileLoopUnrollThreshold)
|
||||
LUAU_FASTINT(LuauCompileLoopUnrollThresholdMaxBoost)
|
||||
LUAU_FASTINT(LuauRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauVector2Constants)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -5093,8 +5092,6 @@ L0: RETURN R3 -1
|
|||
|
||||
TEST_CASE("VectorConstants")
|
||||
{
|
||||
ScopedFastFlag luauVector2Constants{FFlag::LuauVector2Constants, true};
|
||||
|
||||
CHECK_EQ("\n" + compileFunction("return vector.create(1, 2)", 0, 2, 0), R"(
|
||||
LOADK R0 K0 [1, 2, 0]
|
||||
RETURN R0 1
|
||||
|
|
|
@ -32,15 +32,10 @@ void luaC_fullgc(lua_State* L);
|
|||
void luaC_validate(lua_State* L);
|
||||
|
||||
LUAU_FASTFLAG(LuauLibWhereErrorAutoreserve)
|
||||
LUAU_FASTFLAG(LuauMathLerp)
|
||||
LUAU_FASTFLAG(DebugLuauAbortingChecks)
|
||||
LUAU_FASTINT(CodegenHeuristicsInstructionLimit)
|
||||
LUAU_DYNAMIC_FASTFLAG(LuauStackLimit)
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeCodegen)
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot)
|
||||
LUAU_FASTFLAG(LuauVector2Constructor)
|
||||
LUAU_FASTFLAG(LuauBufferBitMethods2)
|
||||
LUAU_FASTFLAG(LuauCodeGenLimitLiveSlotReuse)
|
||||
LUAU_DYNAMIC_FASTFLAG(LuauStringFormatFixC)
|
||||
|
||||
static lua_CompileOptions defaultOptions()
|
||||
|
@ -645,32 +640,28 @@ TEST_CASE("CodegenSupported")
|
|||
|
||||
TEST_CASE("Assert")
|
||||
{
|
||||
runConformance("assert.lua");
|
||||
runConformance("assert.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Basic")
|
||||
{
|
||||
runConformance("basic.lua");
|
||||
runConformance("basic.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Buffers")
|
||||
{
|
||||
ScopedFastFlag luauBufferBitMethods{FFlag::LuauBufferBitMethods2, true};
|
||||
|
||||
runConformance("buffers.lua");
|
||||
runConformance("buffers.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Math")
|
||||
{
|
||||
ScopedFastFlag LuauMathLerp{FFlag::LuauMathLerp, true};
|
||||
|
||||
runConformance("math.lua");
|
||||
runConformance("math.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Tables")
|
||||
{
|
||||
runConformance(
|
||||
"tables.lua",
|
||||
"tables.luau",
|
||||
[](lua_State* L)
|
||||
{
|
||||
lua_pushcfunction(
|
||||
|
@ -699,101 +690,101 @@ TEST_CASE("Tables")
|
|||
|
||||
TEST_CASE("PatternMatch")
|
||||
{
|
||||
runConformance("pm.lua");
|
||||
runConformance("pm.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Sort")
|
||||
{
|
||||
runConformance("sort.lua");
|
||||
runConformance("sort.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Move")
|
||||
{
|
||||
runConformance("move.lua");
|
||||
runConformance("move.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Clear")
|
||||
{
|
||||
runConformance("clear.lua");
|
||||
runConformance("clear.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Strings")
|
||||
{
|
||||
ScopedFastFlag luauStringFormatFixC{DFFlag::LuauStringFormatFixC, true};
|
||||
|
||||
runConformance("strings.lua");
|
||||
runConformance("strings.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("StringInterp")
|
||||
{
|
||||
runConformance("stringinterp.lua");
|
||||
runConformance("stringinterp.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("VarArg")
|
||||
{
|
||||
runConformance("vararg.lua");
|
||||
runConformance("vararg.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Locals")
|
||||
{
|
||||
runConformance("locals.lua");
|
||||
runConformance("locals.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Literals")
|
||||
{
|
||||
runConformance("literals.lua");
|
||||
runConformance("literals.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Errors")
|
||||
{
|
||||
runConformance("errors.lua");
|
||||
runConformance("errors.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Events")
|
||||
{
|
||||
runConformance("events.lua");
|
||||
runConformance("events.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Constructs")
|
||||
{
|
||||
runConformance("constructs.lua");
|
||||
runConformance("constructs.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Closure")
|
||||
{
|
||||
runConformance("closure.lua");
|
||||
runConformance("closure.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Calls")
|
||||
{
|
||||
ScopedFastFlag LuauStackLimit{DFFlag::LuauStackLimit, true};
|
||||
|
||||
runConformance("calls.lua");
|
||||
runConformance("calls.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Attrib")
|
||||
{
|
||||
runConformance("attrib.lua");
|
||||
runConformance("attrib.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("GC")
|
||||
{
|
||||
runConformance("gc.lua");
|
||||
runConformance("gc.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Bitwise")
|
||||
{
|
||||
runConformance("bitwise.lua");
|
||||
runConformance("bitwise.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("UTF8")
|
||||
{
|
||||
runConformance("utf8.lua");
|
||||
runConformance("utf8.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Coroutine")
|
||||
{
|
||||
runConformance("coroutine.lua");
|
||||
runConformance("coroutine.luau");
|
||||
}
|
||||
|
||||
static int cxxthrow(lua_State* L)
|
||||
|
@ -810,7 +801,7 @@ TEST_CASE("PCall")
|
|||
ScopedFastFlag LuauStackLimit{DFFlag::LuauStackLimit, true};
|
||||
|
||||
runConformance(
|
||||
"pcall.lua",
|
||||
"pcall.luau",
|
||||
[](lua_State* L)
|
||||
{
|
||||
lua_pushcfunction(L, cxxthrow, "cxxthrow");
|
||||
|
@ -836,7 +827,7 @@ TEST_CASE("PCall")
|
|||
|
||||
TEST_CASE("Pack")
|
||||
{
|
||||
runConformance("tpack.lua");
|
||||
runConformance("tpack.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Vector")
|
||||
|
@ -881,7 +872,7 @@ TEST_CASE("Vector")
|
|||
}
|
||||
|
||||
runConformance(
|
||||
"vector.lua",
|
||||
"vector.luau",
|
||||
[](lua_State* L)
|
||||
{
|
||||
setupVectorHelpers(L);
|
||||
|
@ -896,9 +887,7 @@ TEST_CASE("Vector")
|
|||
|
||||
TEST_CASE("VectorLibrary")
|
||||
{
|
||||
ScopedFastFlag luauVectorLibNativeCodegen{FFlag::LuauVectorLibNativeCodegen, true};
|
||||
ScopedFastFlag luauVectorLibNativeDot{FFlag::LuauVectorLibNativeDot, true};
|
||||
ScopedFastFlag luauVector2Constructor{FFlag::LuauVector2Constructor, true};
|
||||
|
||||
lua_CompileOptions copts = defaultOptions();
|
||||
|
||||
|
@ -915,7 +904,7 @@ TEST_CASE("VectorLibrary")
|
|||
copts.optimizationLevel = 2;
|
||||
}
|
||||
|
||||
runConformance("vector_library.lua", [](lua_State* L) {}, nullptr, nullptr, &copts);
|
||||
runConformance("vector_library.luau", [](lua_State* L) {}, nullptr, nullptr, &copts);
|
||||
}
|
||||
|
||||
static void populateRTTI(lua_State* L, Luau::TypeId type)
|
||||
|
@ -989,11 +978,8 @@ static void populateRTTI(lua_State* L, Luau::TypeId type)
|
|||
|
||||
TEST_CASE("Types")
|
||||
{
|
||||
ScopedFastFlag luauVector2Constructor{FFlag::LuauVector2Constructor, true};
|
||||
ScopedFastFlag luauMathLerp{FFlag::LuauMathLerp, true};
|
||||
|
||||
runConformance(
|
||||
"types.lua",
|
||||
"types.luau",
|
||||
[](lua_State* L)
|
||||
{
|
||||
Luau::NullModuleResolver moduleResolver;
|
||||
|
@ -1018,12 +1004,12 @@ TEST_CASE("Types")
|
|||
|
||||
TEST_CASE("DateTime")
|
||||
{
|
||||
runConformance("datetime.lua");
|
||||
runConformance("datetime.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Debug")
|
||||
{
|
||||
runConformance("debug.lua");
|
||||
runConformance("debug.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Debugger")
|
||||
|
@ -1050,7 +1036,7 @@ TEST_CASE("Debugger")
|
|||
copts.debugLevel = 2;
|
||||
|
||||
runConformance(
|
||||
"debugger.lua",
|
||||
"debugger.luau",
|
||||
[](lua_State* L)
|
||||
{
|
||||
lua_Callbacks* cb = lua_callbacks(L);
|
||||
|
@ -1225,7 +1211,7 @@ TEST_CASE("NDebugGetUpValue")
|
|||
copts.optimizationLevel = 0;
|
||||
|
||||
runConformance(
|
||||
"ndebug_upvalues.lua",
|
||||
"ndebug_upvalues.luau",
|
||||
nullptr,
|
||||
[](lua_State* L)
|
||||
{
|
||||
|
@ -1456,7 +1442,7 @@ TEST_CASE("ApiIter")
|
|||
|
||||
TEST_CASE("ApiCalls")
|
||||
{
|
||||
StateRef globalState = runConformance("apicalls.lua", nullptr, nullptr, lua_newstate(limitedRealloc, nullptr));
|
||||
StateRef globalState = runConformance("apicalls.luau", nullptr, nullptr, lua_newstate(limitedRealloc, nullptr));
|
||||
lua_State* L = globalState.get();
|
||||
|
||||
// lua_call
|
||||
|
@ -1783,7 +1769,7 @@ TEST_CASE("ExceptionObject")
|
|||
return ExceptionResult{false, ""};
|
||||
};
|
||||
|
||||
StateRef globalState = runConformance("exceptions.lua", nullptr, nullptr, lua_newstate(limitedRealloc, nullptr));
|
||||
StateRef globalState = runConformance("exceptions.luau", nullptr, nullptr, lua_newstate(limitedRealloc, nullptr));
|
||||
lua_State* L = globalState.get();
|
||||
|
||||
{
|
||||
|
@ -1822,7 +1808,7 @@ TEST_CASE("ExceptionObject")
|
|||
|
||||
TEST_CASE("IfElseExpression")
|
||||
{
|
||||
runConformance("ifelseexpr.lua");
|
||||
runConformance("ifelseexpr.luau");
|
||||
}
|
||||
|
||||
// Optionally returns debug info for the first Luau stack frame that is encountered on the callstack.
|
||||
|
@ -1860,7 +1846,7 @@ TEST_CASE("TagMethodError")
|
|||
auto yieldCallback = [](lua_State* L) {};
|
||||
|
||||
runConformance(
|
||||
"tmerror.lua",
|
||||
"tmerror.luau",
|
||||
[](lua_State* L)
|
||||
{
|
||||
auto* cb = lua_callbacks(L);
|
||||
|
@ -1898,7 +1884,7 @@ TEST_CASE("Coverage")
|
|||
copts.coverageLevel = 2;
|
||||
|
||||
runConformance(
|
||||
"coverage.lua",
|
||||
"coverage.luau",
|
||||
[](lua_State* L)
|
||||
{
|
||||
lua_pushcfunction(
|
||||
|
@ -1952,7 +1938,7 @@ TEST_CASE("Coverage")
|
|||
|
||||
TEST_CASE("StringConversion")
|
||||
{
|
||||
runConformance("strconv.lua");
|
||||
runConformance("strconv.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("GCDump")
|
||||
|
@ -2065,7 +2051,7 @@ TEST_CASE("Interrupt")
|
|||
|
||||
static int index;
|
||||
|
||||
StateRef globalState = runConformance("interrupt.lua", nullptr, nullptr, nullptr, &copts);
|
||||
StateRef globalState = runConformance("interrupt.luau", nullptr, nullptr, nullptr, &copts);
|
||||
|
||||
lua_State* L = globalState.get();
|
||||
|
||||
|
@ -2366,7 +2352,7 @@ TEST_CASE("DebugApi")
|
|||
|
||||
TEST_CASE("Iter")
|
||||
{
|
||||
runConformance("iter.lua");
|
||||
runConformance("iter.luau");
|
||||
}
|
||||
|
||||
const int kInt64Tag = 1;
|
||||
|
@ -2395,7 +2381,7 @@ static void pushInt64(lua_State* L, int64_t value)
|
|||
TEST_CASE("Userdata")
|
||||
{
|
||||
runConformance(
|
||||
"userdata.lua",
|
||||
"userdata.luau",
|
||||
[](lua_State* L)
|
||||
{
|
||||
// create metatable with all the metamethods
|
||||
|
@ -2617,13 +2603,11 @@ TEST_CASE("Userdata")
|
|||
|
||||
TEST_CASE("SafeEnv")
|
||||
{
|
||||
runConformance("safeenv.lua");
|
||||
runConformance("safeenv.luau");
|
||||
}
|
||||
|
||||
TEST_CASE("Native")
|
||||
{
|
||||
ScopedFastFlag luauCodeGenLimitLiveSlotReuse{FFlag::LuauCodeGenLimitLiveSlotReuse, true};
|
||||
|
||||
// This tests requires code to run natively, otherwise all 'is_native' checks will fail
|
||||
if (!codegen || !luau_codegen_supported())
|
||||
return;
|
||||
|
@ -2639,7 +2623,7 @@ TEST_CASE("Native")
|
|||
}
|
||||
|
||||
runConformance(
|
||||
"native.lua",
|
||||
"native.luau",
|
||||
[](lua_State* L)
|
||||
{
|
||||
setupNativeHelpers(L);
|
||||
|
@ -2654,7 +2638,7 @@ TEST_CASE("NativeTypeAnnotations")
|
|||
return;
|
||||
|
||||
runConformance(
|
||||
"native_types.lua",
|
||||
"native_types.luau",
|
||||
[](lua_State* L)
|
||||
{
|
||||
setupNativeHelpers(L);
|
||||
|
@ -2717,7 +2701,7 @@ TEST_CASE("NativeUserdata")
|
|||
}
|
||||
|
||||
runConformance(
|
||||
"native_userdata.lua",
|
||||
"native_userdata.luau",
|
||||
[](lua_State* L)
|
||||
{
|
||||
Luau::CodeGen::setUserdataRemapper(
|
||||
|
|
|
@ -53,6 +53,7 @@ void ConstraintGeneratorFixture::solve(const std::string& code)
|
|||
NotNull{&typeFunctionRuntime},
|
||||
NotNull{rootScope},
|
||||
constraints,
|
||||
NotNull{&cg->scopeToFunction},
|
||||
"MainModule",
|
||||
NotNull(&moduleResolver),
|
||||
{},
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
static const char* mainModuleName = "MainModule";
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LuauVector2Constructor)
|
||||
LUAU_FASTFLAG(DebugLuauLogSolverToJsonFile)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForceAllNewSolverTests);
|
||||
|
@ -593,8 +592,6 @@ LoadDefinitionFileResult Fixture::loadDefinition(const std::string& source, bool
|
|||
BuiltinsFixture::BuiltinsFixture(bool prepareAutocomplete)
|
||||
: Fixture(prepareAutocomplete)
|
||||
{
|
||||
ScopedFastFlag luauVector2Constructor{FFlag::LuauVector2Constructor, true};
|
||||
|
||||
Luau::unfreeze(frontend.globals.globalTypes);
|
||||
Luau::unfreeze(frontend.globalsForAutocomplete.globalTypes);
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Luau/Frontend.h"
|
||||
#include "Luau/AutocompleteTypes.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "ScopedFlags.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
|
@ -21,7 +22,6 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauAllowFragmentParsing);
|
||||
LUAU_FASTFLAG(LuauAutocompleteRefactorsForIncrementalAutocomplete)
|
||||
LUAU_FASTFLAG(LuauSymbolEquality);
|
||||
LUAU_FASTFLAG(LuauStoreSolverTypeOnModule);
|
||||
|
@ -35,6 +35,7 @@ LUAU_FASTFLAG(LuauMixedModeDefFinderTraversesTypeOf)
|
|||
LUAU_FASTFLAG(LuauFreeTypesMustHaveBounds)
|
||||
|
||||
LUAU_FASTFLAG(LuauBetterReverseDependencyTracking)
|
||||
LUAU_FASTFLAG(LuauAutocompleteUsesModuleForTypeCompatibility)
|
||||
|
||||
static std::optional<AutocompleteEntryMap> nullCallback(std::string tag, std::optional<const ClassType*> ptr, std::optional<std::string> contents)
|
||||
{
|
||||
|
@ -64,8 +65,7 @@ struct FragmentAutocompleteFixtureImpl : BaseType
|
|||
{
|
||||
static_assert(std::is_base_of_v<Fixture, BaseType>, "BaseType must be a descendant of Fixture");
|
||||
|
||||
ScopedFastFlag sffs[7] = {
|
||||
{FFlag::LuauAllowFragmentParsing, true},
|
||||
ScopedFastFlag sffs[6] = {
|
||||
{FFlag::LuauAutocompleteRefactorsForIncrementalAutocomplete, true},
|
||||
{FFlag::LuauStoreSolverTypeOnModule, true},
|
||||
{FFlag::LuauSymbolEquality, true},
|
||||
|
@ -859,17 +859,16 @@ return module)";
|
|||
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
ScopedFastFlag sff2{FFlag::LuauCloneIncrementalModule, true};
|
||||
ScopedFastFlag sff3{FFlag::LuauFreeTypesMustHaveBounds, true};
|
||||
checkAndExamine(source, "module", "{ }");
|
||||
// [TODO] CLI-140762 we shouldn't mutate stale module in autocompleteFragment
|
||||
// early return since the following checking will fail, which it shouldn't!
|
||||
// fragmentACAndCheck(updated1, Position{1, 17}, "module", "{ }", "{ a: (%error-id%: unknown) -> () }");
|
||||
// fragmentACAndCheck(updated2, Position{1, 18}, "module", "{ }", "{ ab: (%error-id%: unknown) -> () }");
|
||||
fragmentACAndCheck(updated1, Position{1, 17}, "module", "{ }", "{ a: (%error-id%: unknown) -> () }");
|
||||
fragmentACAndCheck(updated2, Position{1, 18}, "module", "{ }", "{ ab: (%error-id%: unknown) -> () }");
|
||||
}
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
checkAndExamine(source, "module", "{ }");
|
||||
// [TODO] CLI-140762 we shouldn't mutate stale module in autocompleteFragment
|
||||
// early return since the following checking will fail, which it shouldn't!
|
||||
// [TODO] CLI-140762 Fragment autocomplete still doesn't return correct result when LuauSolverV2 is on
|
||||
return;
|
||||
fragmentACAndCheck(updated1, Position{1, 17}, "module", "{ }", "{ a: (%error-id%: unknown) -> () }");
|
||||
fragmentACAndCheck(updated2, Position{1, 18}, "module", "{ }", "{ ab: (%error-id%: unknown) -> () }");
|
||||
|
@ -2092,5 +2091,15 @@ return module
|
|||
autocompleteFragmentInBothSolvers(source, updated, Position{1, 18}, [](FragmentAutocompleteResult& result) {});
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "ice_caused_by_mixed_mode_use")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauAutocompleteUsesModuleForTypeCompatibility, true};
|
||||
const std::string source = "--[[\n\tPackage link auto-generated by Rotriever\n]]\nlocal PackageIndex = script.Parent._Index\n\nlocal Package = "
|
||||
"require(PackageIndex[\"ReactOtter\"][\"ReactOtter\"])\n\nexport type Goal = Package.Goal\nexport type SpringOptions "
|
||||
"= Package.SpringOptions\n\n\nreturn Pa";
|
||||
autocompleteFragmentInBothSolvers(source, source, Position{11,9}, [](auto& _){
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -15,8 +15,6 @@
|
|||
#include "doctest.h"
|
||||
#include <iostream>
|
||||
|
||||
LUAU_FASTFLAG(LuauCountSelfCallsNonstrict)
|
||||
LUAU_FASTFLAG(LuauVector2Constructor)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictWarnOnUnknownGlobals)
|
||||
LUAU_FASTFLAG(LuauNonStrictVisitorImprovements)
|
||||
|
||||
|
@ -619,9 +617,6 @@ buffer.readi8(b, 0)
|
|||
|
||||
TEST_CASE_FIXTURE(NonStrictTypeCheckerFixture, "nonstrict_method_calls")
|
||||
{
|
||||
ScopedFastFlag luauCountSelfCallsNonstrict{FFlag::LuauCountSelfCallsNonstrict, true};
|
||||
ScopedFastFlag luauVector2Constructor{FFlag::LuauVector2Constructor, true};
|
||||
|
||||
Luau::unfreeze(frontend.globals.globalTypes);
|
||||
Luau::unfreeze(frontend.globalsForAutocomplete.globalTypes);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ LUAU_FASTFLAG(LuauErrorRecoveryForClassNames)
|
|||
LUAU_FASTFLAG(LuauFixFunctionNameStartPosition)
|
||||
LUAU_FASTFLAG(LuauExtendStatEndPosWithSemicolon)
|
||||
LUAU_FASTFLAG(LuauPreserveUnionIntersectionNodeForLeadingTokenSingleType)
|
||||
LUAU_FASTFLAG(LuauAstTypeGroup)
|
||||
LUAU_FASTFLAG(LuauAstTypeGroup2)
|
||||
LUAU_FASTFLAG(LuauFixDoBlockEndLocation)
|
||||
|
||||
namespace
|
||||
|
@ -372,7 +372,7 @@ TEST_CASE_FIXTURE(Fixture, "return_type_is_an_intersection_type_if_led_with_one_
|
|||
|
||||
AstTypeIntersection* returnAnnotation = annotation->returnTypes.types.data[0]->as<AstTypeIntersection>();
|
||||
REQUIRE(returnAnnotation != nullptr);
|
||||
if (FFlag::LuauAstTypeGroup)
|
||||
if (FFlag::LuauAstTypeGroup2)
|
||||
CHECK(returnAnnotation->types.data[0]->as<AstTypeGroup>());
|
||||
else
|
||||
CHECK(returnAnnotation->types.data[0]->as<AstTypeReference>());
|
||||
|
@ -2451,7 +2451,7 @@ TEST_CASE_FIXTURE(Fixture, "leading_union_intersection_with_single_type_preserve
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_simple_ast_type_group")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauAstTypeGroup, true};
|
||||
ScopedFastFlag _{FFlag::LuauAstTypeGroup2, true};
|
||||
|
||||
AstStatBlock* stat = parse(R"(
|
||||
type Foo = (string)
|
||||
|
@ -2469,7 +2469,7 @@ TEST_CASE_FIXTURE(Fixture, "parse_simple_ast_type_group")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_nested_ast_type_group")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauAstTypeGroup, true};
|
||||
ScopedFastFlag _{FFlag::LuauAstTypeGroup2, true};
|
||||
|
||||
AstStatBlock* stat = parse(R"(
|
||||
type Foo = ((string))
|
||||
|
@ -2490,7 +2490,7 @@ TEST_CASE_FIXTURE(Fixture, "parse_nested_ast_type_group")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_return_type_ast_type_group")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauAstTypeGroup, true};
|
||||
ScopedFastFlag _{FFlag::LuauAstTypeGroup2, true};
|
||||
|
||||
AstStatBlock* stat = parse(R"(
|
||||
type Foo = () -> (string)
|
||||
|
@ -3813,7 +3813,7 @@ TEST_CASE_FIXTURE(Fixture, "grouped_function_type")
|
|||
auto unionTy = paramTy.type->as<AstTypeUnion>();
|
||||
LUAU_ASSERT(unionTy);
|
||||
CHECK_EQ(unionTy->types.size, 2);
|
||||
if (FFlag::LuauAstTypeGroup)
|
||||
if (FFlag::LuauAstTypeGroup2)
|
||||
{
|
||||
auto groupTy = unionTy->types.data[0]->as<AstTypeGroup>(); // (() -> ())
|
||||
REQUIRE(groupTy);
|
||||
|
|
|
@ -14,7 +14,7 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauStoreCSTData)
|
||||
LUAU_FASTFLAG(LuauExtendStatEndPosWithSemicolon)
|
||||
LUAU_FASTFLAG(LuauAstTypeGroup);
|
||||
LUAU_FASTFLAG(LuauAstTypeGroup2);
|
||||
LUAU_FASTFLAG(LexerFixInterpStringStart)
|
||||
|
||||
TEST_SUITE_BEGIN("TranspilerTests");
|
||||
|
@ -1175,7 +1175,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_union_type_nested_3")
|
|||
{
|
||||
std::string code = "local a: nil | (string & number)";
|
||||
|
||||
if (FFlag::LuauAstTypeGroup)
|
||||
if (FFlag::LuauAstTypeGroup2)
|
||||
CHECK_EQ("local a: (string & number)?", transpile(code, {}, true).code);
|
||||
else
|
||||
CHECK_EQ("local a: ( string & number)?", transpile(code, {}, true).code);
|
||||
|
@ -1732,4 +1732,24 @@ TEST_CASE("transpile_type_table_preserve_property_definition_style")
|
|||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
}
|
||||
|
||||
TEST_CASE("transpile_types_preserve_parentheses_style")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData, true},
|
||||
{FFlag::LuauAstTypeGroup2, true},
|
||||
};
|
||||
|
||||
std::string code = R"( type Foo = number )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
code = R"( type Foo = (number) )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
code = R"( type Foo = ((number)) )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
code = R"( type Foo = ( (number) ) )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -16,8 +16,8 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
|
||||
struct TxnLogFixture
|
||||
{
|
||||
TxnLog log{/*useScopes*/ true};
|
||||
TxnLog log2{/*useScopes*/ true};
|
||||
TxnLog log;
|
||||
TxnLog log2;
|
||||
TypeArena arena;
|
||||
BuiltinTypes builtinTypes;
|
||||
|
||||
|
@ -33,39 +33,6 @@ struct TxnLogFixture
|
|||
|
||||
TEST_SUITE_BEGIN("TxnLog");
|
||||
|
||||
TEST_CASE_FIXTURE(TxnLogFixture, "colliding_union_incoming_type_has_greater_scope")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
log.replace(c, BoundType{a});
|
||||
log2.replace(a, BoundType{c});
|
||||
|
||||
CHECK(nullptr != log.pending(c));
|
||||
|
||||
log.concatAsUnion(std::move(log2), NotNull{&arena});
|
||||
|
||||
// 'a has greater scope than 'c, so we expect the incoming binding of 'a to
|
||||
// be discarded.
|
||||
|
||||
CHECK(nullptr == log.pending(a));
|
||||
|
||||
const PendingType* pt = log.pending(c);
|
||||
REQUIRE(pt != nullptr);
|
||||
|
||||
CHECK(!pt->dead);
|
||||
const BoundType* bt = get_if<BoundType>(&pt->pending.ty);
|
||||
|
||||
CHECK(a == bt->boundTo);
|
||||
|
||||
log.commit();
|
||||
|
||||
REQUIRE(get<FreeType>(a));
|
||||
|
||||
const BoundType* bound = get<BoundType>(c);
|
||||
REQUIRE(bound);
|
||||
CHECK(a == bound->boundTo);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(TxnLogFixture, "colliding_union_incoming_type_has_lesser_scope")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
|
|
@ -12,6 +12,8 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauTypeFunSingletonEquality)
|
||||
LUAU_FASTFLAG(LuauUserTypeFunTypeofReturnsType)
|
||||
LUAU_FASTFLAG(LuauTypeFunReadWriteParents)
|
||||
LUAU_FASTFLAG(LuauTypeFunPrintFix)
|
||||
|
||||
TEST_SUITE_BEGIN("UserDefinedTypeFunctionTests");
|
||||
|
||||
|
@ -1939,4 +1941,45 @@ local _:test<number>
|
|||
CHECK(toString(result.errors[0]) == R"(type)");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_print_tab_char_fix")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauTypeFunPrintFix, true}};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function test(t)
|
||||
print(1,2)
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
local _:test<number>
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
// It should be \t and not \x1
|
||||
CHECK_EQ("1\t2", toString(result.errors[0]));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ClassFixture, "udtf_class_parent_ops")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag readWriteParents{FFlag::LuauTypeFunReadWriteParents, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function readparentof(arg)
|
||||
return arg:readparent()
|
||||
end
|
||||
|
||||
type function writeparentof(arg)
|
||||
return arg:writeparent()
|
||||
end
|
||||
|
||||
local function ok1(idx: readparentof<ChildClass>): BaseClass return idx end
|
||||
local function ok2(idx: writeparentof<ChildClass>): BaseClass return idx end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauNewSolverPrePopulateClasses)
|
||||
LUAU_FASTFLAG(LuauClipNestedAndRecursiveUnion)
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauPreventReentrantTypeFunctionReduction)
|
||||
|
@ -497,7 +496,6 @@ TEST_CASE_FIXTURE(Fixture, "class_definition_indexer")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "class_definitions_reference_other_classes")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauNewSolverPrePopulateClasses, true};
|
||||
loadDefinition(R"(
|
||||
declare class Channel
|
||||
Messages: { Message }
|
||||
|
|
|
@ -16,11 +16,14 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(DebugLuauAssertOnForcedConstraint)
|
||||
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTINT(LuauTarjanChildLimit)
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauSubtypingFixTailPack)
|
||||
LUAU_FASTFLAG(LuauUngeneralizedTypesForRecursiveFunctions)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferFunctions");
|
||||
|
||||
|
@ -3041,4 +3044,48 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "coroutine_wrap_result_call")
|
|||
// New solver still reports an error in this case, but the main goal of the test is to not crash
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "recursive_function_calls_should_not_use_the_generalized_type")
|
||||
{
|
||||
ScopedFastFlag crashOnForce{FFlag::DebugLuauAssertOnForcedConstraint, true};
|
||||
ScopedFastFlag sff{FFlag::LuauUngeneralizedTypesForRecursiveFunctions, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
||||
function random()
|
||||
return true -- chosen by fair coin toss
|
||||
end
|
||||
|
||||
local f
|
||||
f = 5
|
||||
function f()
|
||||
if random() then f() end
|
||||
end
|
||||
)");
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
else
|
||||
LUAU_REQUIRE_ERRORS(result); // errors without typestate, obviously
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "recursive_function_calls_should_not_use_the_generalized_type_2")
|
||||
{
|
||||
ScopedFastFlag crashOnForce{FFlag::DebugLuauAssertOnForcedConstraint, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
||||
function random()
|
||||
return true -- chosen by fair coin toss
|
||||
end
|
||||
|
||||
local function f()
|
||||
if random() then f() end
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauNewSolverPopulateTableLocations)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -464,13 +463,10 @@ local b: B.T = a
|
|||
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
if (FFlag::LuauNewSolverPopulateTableLocations)
|
||||
CHECK(
|
||||
toString(result.errors.at(0)) ==
|
||||
"Type 'T' from 'game/A' could not be converted into 'T' from 'game/B'; at [read \"x\"], number is not exactly string"
|
||||
);
|
||||
else
|
||||
CHECK(toString(result.errors.at(0)) == "Type 'T' could not be converted into 'T'; at [read \"x\"], number is not exactly string");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -513,13 +509,10 @@ local b: B.T = a
|
|||
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
if (FFlag::LuauNewSolverPopulateTableLocations)
|
||||
CHECK(
|
||||
toString(result.errors.at(0)) ==
|
||||
"Type 'T' from 'game/B' could not be converted into 'T' from 'game/C'; at [read \"x\"], number is not exactly string"
|
||||
);
|
||||
else
|
||||
CHECK(toString(result.errors.at(0)) == "Type 'T' could not be converted into 'T'; at [read \"x\"], number is not exactly string");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -557,7 +557,7 @@ TEST_CASE_FIXTURE(Fixture, "dcr_can_partially_dispatch_a_constraint")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "free_options_cannot_be_unified_together")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
|
||||
TypeArena arena;
|
||||
TypeId nilType = builtinTypes->nilType;
|
||||
|
@ -575,9 +575,6 @@ TEST_CASE_FIXTURE(Fixture, "free_options_cannot_be_unified_together")
|
|||
Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}};
|
||||
Unifier u{NotNull{&normalizer}, NotNull{scope.get()}, Location{}, Variance::Covariant};
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
u.enableNewSolver();
|
||||
|
||||
u.tryUnify(option1, option2);
|
||||
|
||||
CHECK(!u.failure);
|
||||
|
@ -987,7 +984,7 @@ TEST_CASE_FIXTURE(Fixture, "floating_generics_should_not_be_allowed")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "free_options_can_be_unified_together")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, false};
|
||||
|
||||
TypeArena arena;
|
||||
TypeId nilType = builtinTypes->nilType;
|
||||
|
@ -1005,9 +1002,6 @@ TEST_CASE_FIXTURE(Fixture, "free_options_can_be_unified_together")
|
|||
Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}};
|
||||
Unifier u{NotNull{&normalizer}, NotNull{scope.get()}, Location{}, Variance::Covariant};
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
u.enableNewSolver();
|
||||
|
||||
u.tryUnify(option1, option2);
|
||||
|
||||
CHECK(!u.failure);
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauGeneralizationRemoveRecursiveUpperBound2)
|
||||
LUAU_FASTFLAG(LuauIntersectNotNil)
|
||||
LUAU_FASTFLAG(LuauSkipNoRefineDuringRefinement)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -2459,4 +2461,69 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "remove_recursive_upper_bound_when_generalizi
|
|||
CHECK_EQ("(nil & string)?", toString(requireTypeAtPosition({4, 24})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "nonnil_refinement_on_generic")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauIntersectNotNil, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function printOptional<T>(item: T?, printer: (T) -> string): string
|
||||
if item ~= nil then
|
||||
return printer(item)
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
if (FFlag::LuauSolverV2)
|
||||
CHECK_EQ("T & ~nil", toString(requireTypeAtPosition({3, 31})));
|
||||
else
|
||||
CHECK_EQ("T", toString(requireTypeAtPosition({3, 31})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "truthy_refinement_on_generic")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauIntersectNotNil, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function printOptional<T>(item: T?, printer: (T) -> string): string
|
||||
if item then
|
||||
return printer(item)
|
||||
else
|
||||
return ""
|
||||
end
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
if (FFlag::LuauSolverV2)
|
||||
CHECK_EQ("T & ~(false?)", toString(requireTypeAtPosition({3, 31})));
|
||||
else
|
||||
CHECK_EQ("T", toString(requireTypeAtPosition({3, 31})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "truthy_call_of_function_with_table_value_as_argument_should_not_refine_value_as_never")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSkipNoRefineDuringRefinement, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Item = {}
|
||||
|
||||
local function predicate(value: Item): boolean
|
||||
return true
|
||||
end
|
||||
|
||||
local function checkValue(value: Item)
|
||||
if predicate(value) then
|
||||
local _ = value
|
||||
end
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
CHECK_EQ("Item", toString(requireTypeAtPosition({8, 27})));
|
||||
CHECK_EQ("Item", toString(requireTypeAtPosition({9, 28})));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -18,8 +18,6 @@ using namespace Luau;
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauFixIndexerSubtypingOrdering)
|
||||
LUAU_FASTFLAG(LuauTableKeysAreRValues)
|
||||
LUAU_FASTFLAG(LuauAllowNilAssignmentToIndexer)
|
||||
LUAU_FASTFLAG(LuauTrackInteriorFreeTypesOnScope)
|
||||
LUAU_FASTFLAG(LuauTrackInteriorFreeTablesOnScope)
|
||||
LUAU_FASTFLAG(LuauDontInPlaceMutateTableType)
|
||||
|
@ -1932,7 +1930,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")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauAllowNilAssignmentToIndexer, true}};
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local function f(): { [string]: number }
|
||||
|
@ -1991,9 +1989,6 @@ TEST_CASE_FIXTURE(Fixture, "ok_to_set_nil_even_on_non_lvalue_base_expr")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "ok_to_set_nil_on_generic_map")
|
||||
{
|
||||
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauAllowNilAssignmentToIndexer, true}};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
type MyMap<K, V> = { [K]: V }
|
||||
function set<K, V>(m: MyMap<K, V>, k: K, v: V)
|
||||
|
@ -2010,8 +2005,7 @@ TEST_CASE_FIXTURE(Fixture, "ok_to_set_nil_on_generic_map")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "key_setting_inference_given_nil_upper_bound")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauAllowNilAssignmentToIndexer, true}};
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local function setkey_object(t: { [string]: number }, v)
|
||||
t.foo = v
|
||||
|
@ -2942,16 +2936,12 @@ 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
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check("local a = {} a[0] = 7 a[0] = nil");
|
||||
LUAU_REQUIRE_ERROR_COUNT(0, result);
|
||||
LUAU_REQUIRE_NO_ERRORS(check("local a = {} a[0] = 7 a[0] = nil"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "wrong_assign_does_hit_indexer")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauAllowNilAssignmentToIndexer, true}};
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local a = {}
|
||||
|
@ -5055,7 +5045,6 @@ TEST_CASE_FIXTURE(Fixture, "function_check_constraint_too_eager")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "read_only_property_reads")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag sff{FFlag::LuauTableKeysAreRValues, true};
|
||||
|
||||
// none of the `t.id` accesses here should error
|
||||
auto result = check(R"(
|
||||
|
|
|
@ -23,7 +23,7 @@ LUAU_FASTINT(LuauCheckRecursionLimit)
|
|||
LUAU_FASTINT(LuauNormalizeCacheLimit)
|
||||
LUAU_FASTINT(LuauRecursionLimit)
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauAstTypeGroup)
|
||||
LUAU_FASTFLAG(LuauAstTypeGroup2)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictWarnOnUnknownGlobals)
|
||||
LUAU_FASTFLAG(LuauInferLocalTypesInMultipleAssignments)
|
||||
|
||||
|
@ -1201,10 +1201,13 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_normalizer")
|
|||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
CHECK(3 == result.errors.size());
|
||||
if (FFlag::LuauAstTypeGroup2)
|
||||
CHECK(Location{{2, 22}, {2, 42}} == result.errors[0].location);
|
||||
else
|
||||
CHECK(Location{{2, 22}, {2, 41}} == result.errors[0].location);
|
||||
CHECK(Location{{3, 22}, {3, 42}} == result.errors[1].location);
|
||||
if (FFlag::LuauAstTypeGroup)
|
||||
CHECK(Location{{3, 22}, {3, 40}} == result.errors[2].location);
|
||||
if (FFlag::LuauAstTypeGroup2)
|
||||
CHECK(Location{{3, 22}, {3, 41}} == result.errors[2].location);
|
||||
else
|
||||
CHECK(Location{{3, 23}, {3, 40}} == result.errors[2].location);
|
||||
CHECK_EQ("Code is too complex to typecheck! Consider simplifying the code around this area", toString(result.errors[0]));
|
||||
|
|
|
@ -341,43 +341,6 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "txnlog_preserves_pack_owner")
|
|||
CHECK_EQ(a->owningArena, &arena);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(TryUnifyFixture, "metatables_unify_against_shape_of_free_table")
|
||||
{
|
||||
TableType::Props freeProps{
|
||||
{"foo", {builtinTypes->numberType}},
|
||||
};
|
||||
|
||||
TypeId free = arena.addType(TableType{freeProps, std::nullopt, TypeLevel{}, TableState::Free});
|
||||
|
||||
TableType::Props indexProps{
|
||||
{"foo", {builtinTypes->stringType}},
|
||||
};
|
||||
|
||||
TypeId index = arena.addType(TableType{indexProps, std::nullopt, TypeLevel{}, TableState::Sealed});
|
||||
|
||||
TableType::Props mtProps{
|
||||
{"__index", {index}},
|
||||
};
|
||||
|
||||
TypeId mt = arena.addType(TableType{mtProps, std::nullopt, TypeLevel{}, TableState::Sealed});
|
||||
|
||||
TypeId target = arena.addType(TableType{TableState::Unsealed, TypeLevel{}});
|
||||
TypeId metatable = arena.addType(MetatableType{target, mt});
|
||||
|
||||
state.enableNewSolver();
|
||||
state.tryUnify(metatable, free);
|
||||
state.log.commit();
|
||||
|
||||
REQUIRE_EQ(state.errors.size(), 1);
|
||||
const std::string expected = R"(Type
|
||||
'{ @metatable {| __index: {| foo: string |} |}, { } }'
|
||||
could not be converted into
|
||||
'{- foo: number -}'
|
||||
caused by:
|
||||
Type 'number' could not be converted into 'string')";
|
||||
CHECK_EQ(expected, toString(state.errors[0]));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(TryUnifyFixture, "fuzz_tail_unification_issue")
|
||||
{
|
||||
TypePackVar variadicAny{VariadicTypePack{builtinTypes->anyType}};
|
||||
|
@ -403,101 +366,6 @@ local l0:(any)&(typeof(_)),l0:(any)|(any) = _,_
|
|||
LUAU_REQUIRE_ERRORS(result);
|
||||
}
|
||||
|
||||
static TypeId createTheType(TypeArena& arena, NotNull<BuiltinTypes> builtinTypes, Scope* scope, TypeId freeTy)
|
||||
{
|
||||
/*
|
||||
({|
|
||||
render: (
|
||||
(('a) -> ()) | {| current: 'a |}
|
||||
) -> nil
|
||||
|}) -> ()
|
||||
*/
|
||||
TypePackId emptyPack = arena.addTypePack({});
|
||||
|
||||
return arena.addType(FunctionType{
|
||||
arena.addTypePack({arena.addType(TableType{
|
||||
TableType::Props{
|
||||
{{"render",
|
||||
Property(arena.addType(FunctionType{
|
||||
arena.addTypePack({arena.addType(UnionType{
|
||||
{arena.addType(FunctionType{arena.addTypePack({freeTy}), emptyPack}),
|
||||
arena.addType(TableType{TableType::Props{{"current", {freeTy}}}, std::nullopt, TypeLevel{}, scope, TableState::Sealed})}
|
||||
})}),
|
||||
arena.addTypePack({builtinTypes->nilType})
|
||||
}))}}
|
||||
},
|
||||
std::nullopt,
|
||||
TypeLevel{},
|
||||
scope,
|
||||
TableState::Sealed
|
||||
})}),
|
||||
emptyPack
|
||||
});
|
||||
};
|
||||
|
||||
// See CLI-71190
|
||||
TEST_CASE_FIXTURE(TryUnifyFixture, "unifying_two_unions_under_dcr_does_not_create_a_BoundType_cycle")
|
||||
{
|
||||
const std::shared_ptr<Scope> scope = globalScope;
|
||||
const std::shared_ptr<Scope> nestedScope = std::make_shared<Scope>(scope);
|
||||
|
||||
const TypeId outerType = arena.freshType(builtinTypes, scope.get());
|
||||
const TypeId outerType2 = arena.freshType(builtinTypes, scope.get());
|
||||
|
||||
const TypeId innerType = arena.freshType(builtinTypes, nestedScope.get());
|
||||
|
||||
state.enableNewSolver();
|
||||
|
||||
SUBCASE("equal_scopes")
|
||||
{
|
||||
TypeId one = createTheType(arena, builtinTypes, scope.get(), outerType);
|
||||
TypeId two = createTheType(arena, builtinTypes, scope.get(), outerType2);
|
||||
|
||||
state.tryUnify(one, two);
|
||||
state.log.commit();
|
||||
|
||||
ToStringOptions opts;
|
||||
|
||||
CHECK(follow(outerType) == follow(outerType2));
|
||||
}
|
||||
|
||||
SUBCASE("outer_scope_is_subtype")
|
||||
{
|
||||
TypeId one = createTheType(arena, builtinTypes, scope.get(), outerType);
|
||||
TypeId two = createTheType(arena, builtinTypes, scope.get(), innerType);
|
||||
|
||||
state.tryUnify(one, two);
|
||||
state.log.commit();
|
||||
|
||||
ToStringOptions opts;
|
||||
|
||||
CHECK(follow(outerType) == follow(innerType));
|
||||
|
||||
// The scope of outerType exceeds that of innerType. The latter should be bound to the former.
|
||||
const BoundType* bt = get_if<BoundType>(&innerType->ty);
|
||||
REQUIRE(bt);
|
||||
CHECK(bt->boundTo == outerType);
|
||||
}
|
||||
|
||||
SUBCASE("outer_scope_is_supertype")
|
||||
{
|
||||
TypeId one = createTheType(arena, builtinTypes, scope.get(), innerType);
|
||||
TypeId two = createTheType(arena, builtinTypes, scope.get(), outerType);
|
||||
|
||||
state.tryUnify(one, two);
|
||||
state.log.commit();
|
||||
|
||||
ToStringOptions opts;
|
||||
|
||||
CHECK(follow(outerType) == follow(innerType));
|
||||
|
||||
// The scope of outerType exceeds that of innerType. The latter should be bound to the former.
|
||||
const BoundType* bt = get_if<BoundType>(&innerType->ty);
|
||||
REQUIRE(bt);
|
||||
CHECK(bt->boundTo == outerType);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "table_unification_full_restart_recursion")
|
||||
{
|
||||
ScopedFastFlag luauUnifierRecursionOnRestart{FFlag::LuauUnifierRecursionOnRestart, true};
|
||||
|
|
|
@ -36,7 +36,7 @@ assert(foo(1, 2, 3) == 2)
|
|||
assert(concat(pcall(function () end)) == "true")
|
||||
assert(concat(pcall(function () return nil end)) == "true,nil")
|
||||
assert(concat(pcall(function () return 1,2,3 end)) == "true,1,2,3")
|
||||
assert(concat(pcall(function () error("oops") end)) == "false,basic.lua:39: oops")
|
||||
assert(concat(pcall(function () error("oops") end)) == "false,basic.luau:39: oops")
|
||||
|
||||
-- assignments
|
||||
assert((function() local a = 1 a = 2 return a end)() == 2)
|
|
@ -284,7 +284,7 @@ function foo ()
|
|||
error("foo")
|
||||
end
|
||||
|
||||
local fooerr = "closure.lua:284: foo"
|
||||
local fooerr = "closure.luau:284: foo"
|
||||
|
||||
function goo() foo() end
|
||||
x = coroutine.wrap(goo)
|
|
@ -35,7 +35,7 @@ end
|
|||
local co2 = coroutine.create(halp)
|
||||
coroutine.resume(co2, 0 / 0, 42)
|
||||
|
||||
assert(debug.traceback(co2) == "debug.lua:31 function halp\n")
|
||||
assert(debug.traceback(co2) == "debug.luau:31 function halp\n")
|
||||
assert(debug.info(co2, 0, "l") == 31)
|
||||
assert(debug.info(co2, 0, "f") == halp)
|
||||
|
||||
|
@ -64,7 +64,7 @@ assert(baz(1, "n") == "baz")
|
|||
assert(baz(2, "n") == "") -- main/anonymous
|
||||
assert(baz(3, "n") == nil)
|
||||
assert(baz(0, "s") == "[C]")
|
||||
assert(baz(1, "s") == "debug.lua")
|
||||
assert(baz(1, "s") == "debug.luau")
|
||||
assert(baz(0, "l") == -1)
|
||||
assert(baz(1, "l") > 42)
|
||||
assert(baz(0, "f") == debug.info)
|
||||
|
@ -87,7 +87,7 @@ end
|
|||
assert(#(quux(1, "nlsf")) == 4)
|
||||
assert(quux(1, "nlsf")[1] == "quux")
|
||||
assert(quux(1, "nlsf")[2] > 64)
|
||||
assert(quux(1, "nlsf")[3] == "debug.lua")
|
||||
assert(quux(1, "nlsf")[3] == "debug.luau")
|
||||
assert(quux(1, "nlsf")[4] == quux)
|
||||
|
||||
-- info arity
|
|
@ -77,9 +77,9 @@ checkresults({ "yield", "return", true, 1, 2, 3}, colog(function() return pcall(
|
|||
checkresults({ "yield", 1, "yield", 2, "return", true, true, 3}, colog(function() return pcall(function() coroutine.yield(1) return pcall(function() coroutine.yield(2) return 3 end) end) end))
|
||||
|
||||
-- error after yield tests
|
||||
checkresults({ "yield", "return", false, "pcall.lua:80: foo" }, colog(function() return pcall(function() coroutine.yield() error("foo") end) end))
|
||||
checkresults({ "yield", "yield", "return", true, false, "pcall.lua:81: foo" }, colog(function() return pcall(function() coroutine.yield() return pcall(function() coroutine.yield() error("foo") end) end) end))
|
||||
checkresults({ "yield", "yield", "return", false, "pcall.lua:82: bar" }, colog(function() return pcall(function() coroutine.yield() pcall(function() coroutine.yield() error("foo") end) error("bar") end) end))
|
||||
checkresults({ "yield", "return", false, "pcall.luau:80: foo" }, colog(function() return pcall(function() coroutine.yield() error("foo") end) end))
|
||||
checkresults({ "yield", "yield", "return", true, false, "pcall.luau:81: foo" }, colog(function() return pcall(function() coroutine.yield() return pcall(function() coroutine.yield() error("foo") end) end) end))
|
||||
checkresults({ "yield", "yield", "return", false, "pcall.luau:82: bar" }, colog(function() return pcall(function() coroutine.yield() pcall(function() coroutine.yield() error("foo") end) error("bar") end) end))
|
||||
|
||||
-- returning lots of results (past MINSTACK limits)
|
||||
local res = {pcall(function() return table.unpack(table.create(100, 'a')) end)}
|
||||
|
@ -100,15 +100,15 @@ checkresults({ true, 2 }, xpcall(function(...) return select('#', ...) end, erro
|
|||
checkresults({ "yield", "return", true, 42 }, colog(function() return xpcall(function() coroutine.yield() return 42 end, error) end))
|
||||
|
||||
-- xpcall immediate error handling
|
||||
checkresults({ false, "pcall.lua:103: foo" }, xpcall(function() error("foo") end, function(err) return err end))
|
||||
checkresults({ false, "pcall.luau:103: foo" }, xpcall(function() error("foo") end, function(err) return err end))
|
||||
checkresults({ false, "bar" }, xpcall(function() error("foo") end, function(err) return "bar" end))
|
||||
checkresults({ false, 1 }, xpcall(function() error("foo") end, function(err) return 1, 2 end))
|
||||
checkresults({ false, "pcall.lua:106: foo\npcall.lua:106\npcall.lua:106\n" }, xpcall(function() error("foo") end, debug.traceback))
|
||||
checkresults({ false, "pcall.luau:106: foo\npcall.luau:106\npcall.luau:106\n" }, xpcall(function() error("foo") end, debug.traceback))
|
||||
checkresults({ false, "error in error handling" }, xpcall(function() error("foo") end, function(err) error("bar") end))
|
||||
|
||||
-- xpcall error handling after yields
|
||||
checkresults({ "yield", "return", false, "pcall.lua:110: foo" }, colog(function() return xpcall(function() coroutine.yield() error("foo") end, function(err) return err end) end))
|
||||
checkresults({ "yield", "return", false, "pcall.lua:111: foo\npcall.lua:111\npcall.lua:111\n" }, colog(function() return xpcall(function() coroutine.yield() error("foo") end, debug.traceback) end))
|
||||
checkresults({ "yield", "return", false, "pcall.luau:110: foo" }, colog(function() return xpcall(function() coroutine.yield() error("foo") end, function(err) return err end) end))
|
||||
checkresults({ "yield", "return", false, "pcall.luau:111: foo\npcall.luau:111\npcall.luau:111\n" }, colog(function() return xpcall(function() coroutine.yield() error("foo") end, debug.traceback) end))
|
||||
|
||||
-- xpcall error handling during error handling inside xpcall after yields
|
||||
checkresults({ "yield", "return", true, false, "error in error handling" }, colog(function() return xpcall(function() return xpcall(function() coroutine.yield() error("foo") end, function(err) error("bar") end) end, error) end))
|
||||
|
@ -126,7 +126,7 @@ coroutine.yield(weird)
|
|||
weird()
|
||||
end
|
||||
|
||||
checkresults({ false, "pcall.lua:129: cannot resume dead coroutine" }, pcall(function() for _ in coroutine.wrap(pcall), weird do end end))
|
||||
checkresults({ false, "pcall.luau:129: cannot resume dead coroutine" }, pcall(function() for _ in coroutine.wrap(pcall), weird do end end))
|
||||
|
||||
-- c++ exception
|
||||
checkresults({ false, "oops" }, pcall(cxxthrow))
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue