mirror of
https://github.com/luau-lang/luau.git
synced 2025-08-26 11:27:08 +01:00
Sync to upstream/release/675 (#1845)
## General - Introduce `Frontend::parseModules` for parsing a group of modules at once. - Support chained function types in the CST. ## New Type Solver - Enable write-only table properties (described in [this RFC](https://rfcs.luau.org/property-writeonly.html)). - Disable singleton inference for large tables to improve performance. - Fix a bug that occurs when we try to expand a type alias to itself. - Catch cancelation during the type-checking phase in addition to during constraint solving. - Fix stringification of the empty type pack: `()`. - Improve errors for calls being rejected on the primitive `function` type. - Rework generalization: We now generalize types as soon as the last constraint relating to them is finished. We think this will reduce the number of cases where type inference fails to complete and reduce the number of instances where `*blocked*` types appear in the inference result. ## VM/Runtime - Dynamically disable native execution for functions that incur a slowdown (relative to bytecode execution). - Improve names for `thread`/`closure`/`proto` in the Luau heap dump. --- Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Ariel Weiss <aaronweiss@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com> Co-authored-by: Talha Pathan <tpathan@roblox.com> Co-authored-by: Varun Saini <vsaini@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com> Co-authored-by: Alexander Youngblood <ayoungblood@roblox.com> Co-authored-by: Menarul Alam <malam@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Vighnesh <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Ariel Weiss <aaronweiss@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com>
This commit is contained in:
parent
92cce5776c
commit
5965818283
70 changed files with 3153 additions and 925 deletions
|
@ -175,6 +175,10 @@ private:
|
|||
|
||||
std::vector<TypeId> unionsToSimplify;
|
||||
|
||||
// Used to keep track of when we are inside a large table and should
|
||||
// opt *not* to do type inference for singletons.
|
||||
size_t largeTableDepth = 0;
|
||||
|
||||
/**
|
||||
* Fabricates a new free type belonging to a given scope.
|
||||
* @param scope the scope the free type belongs to.
|
||||
|
|
|
@ -225,7 +225,7 @@ public:
|
|||
bool tryDispatch(const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);
|
||||
bool tryDispatch(const NameConstraint& c, NotNull<const Constraint> constraint);
|
||||
bool tryDispatch(const TypeAliasExpansionConstraint& c, NotNull<const Constraint> constraint);
|
||||
bool tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint);
|
||||
bool tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint, bool force);
|
||||
bool tryDispatch(const TableCheckConstraint& c, NotNull<const Constraint> constraint);
|
||||
bool tryDispatch(const FunctionCheckConstraint& c, NotNull<const Constraint> constraint);
|
||||
bool tryDispatch(const PrimitiveTypeConstraint& c, NotNull<const Constraint> constraint);
|
||||
|
|
|
@ -166,6 +166,7 @@ struct Frontend
|
|||
|
||||
// Parse module graph and prepare SourceNode/SourceModule data, including required dependencies without running typechecking
|
||||
void parse(const ModuleName& name);
|
||||
void parseModules(const std::vector<ModuleName>& name);
|
||||
|
||||
// Parse and typecheck module graph
|
||||
CheckResult check(const ModuleName& name, std::optional<FrontendOptions> optionOverride = {}); // new shininess
|
||||
|
|
|
@ -63,7 +63,7 @@ struct OverloadResolver
|
|||
InsertionOrderedMap<TypeId, std::pair<OverloadResolver::Analysis, size_t>> resolution;
|
||||
|
||||
|
||||
std::pair<OverloadResolver::Analysis, TypeId> selectOverload(TypeId ty, TypePackId args);
|
||||
std::pair<OverloadResolver::Analysis, TypeId> selectOverload(TypeId ty, TypePackId args, bool useFreeTypeBounds);
|
||||
void resolve(TypeId fnTy, const TypePack* args, AstExpr* selfExpr, const std::vector<AstExpr*>* argExprs);
|
||||
|
||||
private:
|
||||
|
|
|
@ -72,6 +72,11 @@ struct SubtypingResult
|
|||
/// isSubtype is false, depending on the input types.
|
||||
SubtypingReasonings reasoning{kEmptyReasoning};
|
||||
|
||||
// If this subtype result required testing free types, we might be making
|
||||
// assumptions about what the free type eventually resolves to. If so,
|
||||
// those assumptions are recorded here.
|
||||
std::vector<SubtypeConstraint> assumedConstraints;
|
||||
|
||||
SubtypingResult& andAlso(const SubtypingResult& other);
|
||||
SubtypingResult& orElse(const SubtypingResult& other);
|
||||
SubtypingResult& withBothComponent(TypePath::Component component);
|
||||
|
|
|
@ -24,7 +24,6 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
LUAU_FASTINT(LuauTypeInferIterationLimit)
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauMagicVariableNames)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAutocompleteUsesModuleForTypeCompatibility)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAutocompleteMissingFollows)
|
||||
LUAU_FASTFLAG(LuauStoreReturnTypesAsPackOnAst)
|
||||
|
||||
|
@ -163,78 +162,39 @@ static bool checkTypeMatch(
|
|||
UnifierSharedState unifierState(&iceReporter);
|
||||
SimplifierPtr simplifier = newSimplifier(NotNull{typeArena}, builtinTypes);
|
||||
Normalizer normalizer{typeArena, builtinTypes, NotNull{&unifierState}};
|
||||
if (FFlag::LuauAutocompleteUsesModuleForTypeCompatibility)
|
||||
if (module.checkedInNewSolver)
|
||||
{
|
||||
if (module.checkedInNewSolver)
|
||||
{
|
||||
TypeCheckLimits limits;
|
||||
TypeFunctionRuntime typeFunctionRuntime{
|
||||
NotNull{&iceReporter}, NotNull{&limits}
|
||||
}; // TODO: maybe subtyping checks should not invoke user-defined type function runtime
|
||||
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;
|
||||
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
|
||||
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
|
||||
|
||||
Subtyping subtyping{
|
||||
builtinTypes,
|
||||
NotNull{typeArena},
|
||||
NotNull{simplifier.get()},
|
||||
NotNull{&normalizer},
|
||||
NotNull{&typeFunctionRuntime},
|
||||
NotNull{&iceReporter}
|
||||
};
|
||||
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();
|
||||
}
|
||||
return subtyping.isSubtype(subTy, superTy, scope).isSubtype;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
TypeCheckLimits limits;
|
||||
TypeFunctionRuntime typeFunctionRuntime{
|
||||
NotNull{&iceReporter}, NotNull{&limits}
|
||||
}; // TODO: maybe subtyping checks should not invoke user-defined type function runtime
|
||||
Unifier unifier(NotNull<Normalizer>{&normalizer}, scope, Location(), Variance::Covariant);
|
||||
|
||||
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
|
||||
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
|
||||
// Cost of normalization can be too high for autocomplete response time requirements
|
||||
unifier.normalize = false;
|
||||
unifier.checkInhabited = false;
|
||||
|
||||
Subtyping subtyping{
|
||||
builtinTypes,
|
||||
NotNull{typeArena},
|
||||
NotNull{simplifier.get()},
|
||||
NotNull{&normalizer},
|
||||
NotNull{&typeFunctionRuntime},
|
||||
NotNull{&iceReporter}
|
||||
};
|
||||
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
|
||||
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
|
||||
|
||||
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();
|
||||
}
|
||||
return unifier.canUnify(subTy, superTy).empty();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
*/
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTableCloneClonesType3)
|
||||
LUAU_FASTFLAGVARIABLE(LuauMagicFreezeCheckBlocked2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFormatUseLastPosition)
|
||||
|
@ -310,8 +310,8 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
|
|||
|
||||
TypeArena& arena = globals.globalTypes;
|
||||
NotNull<BuiltinTypes> builtinTypes = globals.builtinTypes;
|
||||
Scope* globalScope = nullptr; // NotNull<Scope> when removing FFlag::LuauNonReentrantGeneralization3
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
Scope* globalScope = nullptr; // NotNull<Scope> when removing FFlag::LuauEagerGeneralization
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
globalScope = globals.globalScope.get();
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
|
|
|
@ -12,8 +12,6 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
|
||||
// For each `Luau::clone` call, we will clone only up to N amount of types _and_ packs, as controlled by this limit.
|
||||
LUAU_FASTINTVARIABLE(LuauTypeCloneIterationLimit, 100'000)
|
||||
LUAU_FASTFLAGVARIABLE(LuauClonedTableAndFunctionTypesMustHaveScopes)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDoNotClonePersistentBindings)
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -514,10 +512,7 @@ public:
|
|||
free->scope = replacementForNullScope;
|
||||
}
|
||||
else if (auto tt = getMutable<TableType>(target))
|
||||
{
|
||||
if (FFlag::LuauClonedTableAndFunctionTypesMustHaveScopes)
|
||||
tt->scope = replacementForNullScope;
|
||||
}
|
||||
tt->scope = replacementForNullScope;
|
||||
|
||||
(*types)[ty] = target;
|
||||
queue.emplace_back(target);
|
||||
|
@ -733,7 +728,7 @@ Binding cloneIncremental(const Binding& binding, TypeArena& dest, CloneState& cl
|
|||
b.deprecatedSuggestion = binding.deprecatedSuggestion;
|
||||
b.documentationSymbol = binding.documentationSymbol;
|
||||
b.location = binding.location;
|
||||
b.typeId = FFlag::LuauDoNotClonePersistentBindings && binding.typeId->persistent ? binding.typeId : cloner.clone(binding.typeId);
|
||||
b.typeId = binding.typeId->persistent ? binding.typeId : cloner.clone(binding.typeId);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "Luau/Constraint.h"
|
||||
#include "Luau/VisitType.h"
|
||||
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -17,8 +17,8 @@ Constraint::Constraint(NotNull<Scope> scope, const Location& location, Constrain
|
|||
|
||||
struct ReferenceCountInitializer : TypeOnceVisitor
|
||||
{
|
||||
|
||||
DenseHashSet<TypeId>* result;
|
||||
bool traverseIntoTypeFunctions = true;
|
||||
|
||||
explicit ReferenceCountInitializer(DenseHashSet<TypeId>* result)
|
||||
: result(result)
|
||||
|
@ -51,7 +51,7 @@ struct ReferenceCountInitializer : TypeOnceVisitor
|
|||
|
||||
bool visit(TypeId, const TypeFunctionInstanceType&) override
|
||||
{
|
||||
return FFlag::DebugLuauGreedyGeneralization;
|
||||
return FFlag::LuauEagerGeneralization && traverseIntoTypeFunctions;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -104,10 +104,12 @@ DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
|
|||
{
|
||||
rci.traverse(fchc->argsPack);
|
||||
}
|
||||
else if (auto fcc = get<FunctionCallConstraint>(*this); fcc && FFlag::DebugLuauGreedyGeneralization)
|
||||
else if (auto fcc = get<FunctionCallConstraint>(*this); fcc && FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
rci.traverseIntoTypeFunctions = false;
|
||||
rci.traverse(fcc->fn);
|
||||
rci.traverse(fcc->argsPack);
|
||||
rci.traverseIntoTypeFunctions = true;
|
||||
}
|
||||
else if (auto ptc = get<PrimitiveTypeConstraint>(*this))
|
||||
{
|
||||
|
@ -116,12 +118,12 @@ DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
|
|||
else if (auto hpc = get<HasPropConstraint>(*this))
|
||||
{
|
||||
rci.traverse(hpc->resultType);
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
rci.traverse(hpc->subjectType);
|
||||
}
|
||||
else if (auto hic = get<HasIndexerConstraint>(*this))
|
||||
{
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
rci.traverse(hic->subjectType);
|
||||
rci.traverse(hic->resultType);
|
||||
// `HasIndexerConstraint` should not mutate `indexType`.
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
LUAU_FASTINT(LuauCheckRecursionLimit)
|
||||
LUAU_FASTFLAG(DebugLuauLogSolverToJson)
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauRetainDefinitionAliasLocations)
|
||||
|
||||
|
@ -42,12 +42,15 @@ LUAU_FASTFLAGVARIABLE(LuauWeakNilRefinementType)
|
|||
LUAU_FASTFLAG(LuauStoreReturnTypesAsPackOnAst)
|
||||
LUAU_FASTFLAG(LuauGlobalVariableModuleIsolation)
|
||||
LUAU_FASTFLAG(LuauNoMoreInjectiveTypeFunctions)
|
||||
LUAU_FASTFLAGVARIABLE(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAG(LuauAddCallConstraintForIterableFunctions)
|
||||
LUAU_FASTFLAG(LuauDoNotAddUpvalueTypesToLocalType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAvoidDoubleNegation)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSimplifyOutOfLine)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDisablePrimitiveInferenceInLargeTables)
|
||||
LUAU_FASTINTVARIABLE(LuauPrimitiveInferenceInTableLimit, 500)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -251,7 +254,7 @@ void ConstraintGenerator::visitModuleRoot(AstStatBlock* block)
|
|||
rootScope->location = block->location;
|
||||
module->astScopes[block] = NotNull{scope.get()};
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
interiorFreeTypes.emplace_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.emplace_back();
|
||||
|
@ -287,7 +290,7 @@ void ConstraintGenerator::visitModuleRoot(AstStatBlock* block)
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
scope->interiorFreeTypes = std::move(interiorFreeTypes.back().types);
|
||||
scope->interiorFreeTypePacks = std::move(interiorFreeTypes.back().typePacks);
|
||||
|
@ -306,7 +309,7 @@ void ConstraintGenerator::visitModuleRoot(AstStatBlock* block)
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
interiorFreeTypes.pop_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.pop_back();
|
||||
|
@ -344,13 +347,13 @@ void ConstraintGenerator::visitFragmentRoot(const ScopePtr& resumeScope, AstStat
|
|||
// We prepopulate global data in the resumeScope to avoid writing data into the old modules scopes
|
||||
prepopulateGlobalScopeForFragmentTypecheck(globalScope, resumeScope, block);
|
||||
// Pre
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
interiorFreeTypes.emplace_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.emplace_back();
|
||||
visitBlockWithoutChildScope(resumeScope, block);
|
||||
// Post
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
interiorFreeTypes.pop_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.pop_back();
|
||||
|
@ -380,12 +383,12 @@ void ConstraintGenerator::visitFragmentRoot(const ScopePtr& resumeScope, AstStat
|
|||
|
||||
TypeId ConstraintGenerator::freshType(const ScopePtr& scope, Polarity polarity)
|
||||
{
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
auto ft = Luau::freshType(arena, builtinTypes, scope.get(), polarity);
|
||||
interiorFreeTypes.back().types.push_back(ft);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
freeTypes.insert(ft);
|
||||
|
||||
return ft;
|
||||
|
@ -402,7 +405,7 @@ TypePackId ConstraintGenerator::freshTypePack(const ScopePtr& scope, Polarity po
|
|||
{
|
||||
FreeTypePack f{scope.get(), polarity};
|
||||
TypePackId result = arena->addTypePack(TypePackVar{std::move(f)});
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
interiorFreeTypes.back().typePacks.push_back(result);
|
||||
return result;
|
||||
}
|
||||
|
@ -1393,7 +1396,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatLocalFuncti
|
|||
FunctionSignature sig = checkFunctionSignature(scope, function->func, /* expectedType */ std::nullopt, function->name->location);
|
||||
sig.bodyScope->bindings[function->name] = Binding{sig.signature, function->name->location};
|
||||
|
||||
bool sigFullyDefined = FFlag::DebugLuauGreedyGeneralization ? false : !hasFreeType(sig.signature);
|
||||
bool sigFullyDefined = FFlag::LuauEagerGeneralization ? false : !hasFreeType(sig.signature);
|
||||
if (sigFullyDefined)
|
||||
emplaceType<BoundType>(asMutable(functionType), sig.signature);
|
||||
|
||||
|
@ -1453,7 +1456,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatFunction* f
|
|||
|
||||
Checkpoint start = checkpoint(this);
|
||||
FunctionSignature sig = checkFunctionSignature(scope, function->func, /* expectedType */ std::nullopt, function->name->location);
|
||||
bool sigFullyDefined = FFlag::DebugLuauGreedyGeneralization ? false : !hasFreeType(sig.signature);
|
||||
bool sigFullyDefined = FFlag::LuauEagerGeneralization ? false : !hasFreeType(sig.signature);
|
||||
|
||||
DefId def = dfg->getDef(function->name);
|
||||
|
||||
|
@ -1767,7 +1770,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeFunctio
|
|||
// Place this function as a child of the non-type function scope
|
||||
scope->children.push_back(NotNull{sig.signatureScope.get()});
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
interiorFreeTypes.emplace_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.push_back(std::vector<TypeId>{});
|
||||
|
@ -1785,7 +1788,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeFunctio
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
sig.signatureScope->interiorFreeTypes = std::move(interiorFreeTypes.back().types);
|
||||
sig.signatureScope->interiorFreeTypePacks = std::move(interiorFreeTypes.back().typePacks);
|
||||
|
@ -1794,7 +1797,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeFunctio
|
|||
sig.signatureScope->interiorFreeTypes = std::move(DEPRECATED_interiorTypes.back());
|
||||
|
||||
getMutable<BlockedType>(generalizedTy)->setOwner(gc);
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
interiorFreeTypes.pop_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.pop_back();
|
||||
|
@ -2359,12 +2362,8 @@ InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstExprCall*
|
|||
this,
|
||||
[checkConstraint, callConstraint](const ConstraintPtr& constraint)
|
||||
{
|
||||
if (!(FFlag::DebugLuauGreedyGeneralization && get<PrimitiveTypeConstraint>(*constraint)))
|
||||
{
|
||||
constraint->dependencies.emplace_back(checkConstraint);
|
||||
|
||||
callConstraint->dependencies.emplace_back(constraint.get());
|
||||
}
|
||||
constraint->dependencies.emplace_back(checkConstraint);
|
||||
callConstraint->dependencies.emplace_back(constraint.get());
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -2457,8 +2456,17 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprConstantStrin
|
|||
if (forceSingleton)
|
||||
return Inference{arena->addType(SingletonType{StringSingleton{std::string{string->value.data, string->value.size}}})};
|
||||
|
||||
// Consider a table like:
|
||||
//
|
||||
// local DICTIONARY = { "aback", "abacus", "abandon", --[[ so on and so forth ]] }
|
||||
//
|
||||
// The intent is (probably) not for this to be an array-like table with a massive
|
||||
// union for the value, but instead a `{ string }`.
|
||||
if (FFlag::LuauDisablePrimitiveInferenceInLargeTables && largeTableDepth > 0)
|
||||
return Inference{builtinTypes->stringType};
|
||||
|
||||
TypeId freeTy = nullptr;
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
freeTy = freshType(scope, Polarity::Positive);
|
||||
FreeType* ft = getMutable<FreeType>(freeTy);
|
||||
|
@ -2484,8 +2492,22 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprConstantBool*
|
|||
if (forceSingleton)
|
||||
return Inference{singletonType};
|
||||
|
||||
// Consider a table like:
|
||||
//
|
||||
// local FLAGS = {
|
||||
// Foo = true,
|
||||
// Bar = false,
|
||||
// Baz = true,
|
||||
// -- so on and so forth
|
||||
// }
|
||||
//
|
||||
// The intent is (probably) not for this to be a table where each element
|
||||
// is potentially `true` or `false` as a singleton, but just `boolean`.
|
||||
if (FFlag::LuauDisablePrimitiveInferenceInLargeTables && largeTableDepth > 0)
|
||||
return Inference{builtinTypes->booleanType};
|
||||
|
||||
TypeId freeTy = nullptr;
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
freeTy = freshType(scope, Polarity::Positive);
|
||||
FreeType* ft = getMutable<FreeType>(freeTy);
|
||||
|
@ -2646,7 +2668,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprFunction* fun
|
|||
Checkpoint startCheckpoint = checkpoint(this);
|
||||
FunctionSignature sig = checkFunctionSignature(scope, func, expectedType);
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
interiorFreeTypes.emplace_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.push_back(std::vector<TypeId>{});
|
||||
|
@ -2664,7 +2686,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprFunction* fun
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
sig.signatureScope->interiorFreeTypes = std::move(interiorFreeTypes.back().types);
|
||||
sig.signatureScope->interiorFreeTypePacks = std::move(interiorFreeTypes.back().typePacks);
|
||||
|
@ -3168,7 +3190,10 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
|
|||
ttv->definitionLocation = expr->location;
|
||||
ttv->scope = scope.get();
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauDisablePrimitiveInferenceInLargeTables && FInt::LuauPrimitiveInferenceInTableLimit > 0 && expr->items.size > size_t(FInt::LuauPrimitiveInferenceInTableLimit))
|
||||
largeTableDepth++;
|
||||
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
interiorFreeTypes.back().types.push_back(ty);
|
||||
else
|
||||
DEPRECATED_interiorTypes.back().push_back(ty);
|
||||
|
@ -3230,7 +3255,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
|
|||
{
|
||||
indexKey = *indexKeyLowerBound.begin();
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
indexKey = arena->addType(UnionType{std::vector(indexKeyLowerBound.begin(), indexKeyLowerBound.end())});
|
||||
unionsToSimplify.push_back(indexKey);
|
||||
|
@ -3276,6 +3301,9 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
|
|||
);
|
||||
}
|
||||
|
||||
if (FFlag::LuauDisablePrimitiveInferenceInLargeTables && FInt::LuauPrimitiveInferenceInTableLimit > 0 && expr->items.size > size_t(FInt::LuauPrimitiveInferenceInTableLimit))
|
||||
largeTableDepth--;
|
||||
|
||||
return Inference{ty};
|
||||
}
|
||||
|
||||
|
@ -3425,7 +3453,7 @@ ConstraintGenerator::FunctionSignature ConstraintGenerator::checkFunctionSignatu
|
|||
|
||||
LUAU_ASSERT(nullptr != varargPack);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
// Some of the types in argTypes will eventually be generics, and some
|
||||
// will not. The ones that are not generic will be pruned when
|
||||
|
@ -3490,7 +3518,7 @@ ConstraintGenerator::FunctionSignature ConstraintGenerator::checkFunctionSignatu
|
|||
if (expectedType && get<FreeType>(*expectedType))
|
||||
bindFreeType(*expectedType, actualFunctionType);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
scopeToFunction[signatureScope.get()] = actualFunctionType;
|
||||
|
||||
return {
|
||||
|
@ -3625,8 +3653,11 @@ TypeId ConstraintGenerator::resolveTableType(const ScopePtr& scope, AstType* ty,
|
|||
p.readTy = propTy;
|
||||
break;
|
||||
case AstTableAccess::Write:
|
||||
reportError(*prop.accessLocation, GenericError{"write keyword is illegal here"});
|
||||
p.readTy = propTy;
|
||||
if (!FFlag::LuauEnableWriteOnlyProperties)
|
||||
{
|
||||
reportError(*prop.accessLocation, GenericError{"write keyword is illegal here"});
|
||||
p.readTy = propTy;
|
||||
}
|
||||
p.writeTy = propTy;
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -33,12 +33,12 @@ LUAU_FASTFLAGVARIABLE(DebugLuauLogBindings)
|
|||
LUAU_FASTINTVARIABLE(LuauSolverRecursionLimit, 500)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAGVARIABLE(LuauHasPropProperBlock)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauDeprecatedAttribute)
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTrackInferredFunctionTypeFromCall)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAddCallConstraintForIterableFunctions)
|
||||
LUAU_FASTFLAGVARIABLE(LuauGuardAgainstMalformedTypeAliasExpansion)
|
||||
LUAU_FASTFLAGVARIABLE(LuauGuardAgainstMalformedTypeAliasExpansion2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauInsertErrorTypesIntoIndexerResult)
|
||||
LUAU_FASTFLAGVARIABLE(LuauClipVariadicAnysFromArgsToGenericFuncs2)
|
||||
LUAU_FASTFLAG(LuauSubtypeGenericsAndNegations)
|
||||
|
@ -418,7 +418,7 @@ void ConstraintSolver::run()
|
|||
}
|
||||
|
||||
// Free types that have no constraints at all can be generalized right away.
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
for (TypeId ty : constraintSet.freeTypes)
|
||||
{
|
||||
|
@ -479,7 +479,7 @@ void ConstraintSolver::run()
|
|||
// expansion types, etc, so we need to follow it.
|
||||
ty = follow(ty);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
if (seen.contains(ty))
|
||||
continue;
|
||||
|
@ -498,7 +498,7 @@ void ConstraintSolver::run()
|
|||
if (refCount <= 1)
|
||||
unblock(ty, Location{});
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization && refCount == 0)
|
||||
if (FFlag::LuauEagerGeneralization && refCount == 0)
|
||||
generalizeOneType(ty);
|
||||
}
|
||||
}
|
||||
|
@ -676,7 +676,7 @@ void ConstraintSolver::initFreeTypeTracking()
|
|||
auto [refCount, _] = unresolvedConstraints.try_insert(ty, 0);
|
||||
refCount += 1;
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
auto [it, fresh] = mutatedFreeTypeToConstraint.try_emplace(ty, nullptr);
|
||||
it->second.insert(c.get());
|
||||
|
@ -691,7 +691,7 @@ void ConstraintSolver::initFreeTypeTracking()
|
|||
}
|
||||
|
||||
// Also check flag integrity while we're here
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauSubtypeGenericsAndNegations);
|
||||
LUAU_ASSERT(FFlag::LuauNoMoreInjectiveTypeFunctions);
|
||||
|
@ -739,7 +739,7 @@ void ConstraintSolver::bind(NotNull<const Constraint> constraint, TypeId ty, Typ
|
|||
constraint, ty, constraint->scope, builtinTypes->neverType, builtinTypes->unknownType, Polarity::Mixed
|
||||
); // FIXME? Is this the right polarity?
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
trackInteriorFreeType(constraint->scope, ty);
|
||||
|
||||
return;
|
||||
|
@ -806,7 +806,7 @@ bool ConstraintSolver::tryDispatch(NotNull<const Constraint> constraint, bool fo
|
|||
else if (auto taec = get<TypeAliasExpansionConstraint>(*constraint))
|
||||
success = tryDispatch(*taec, constraint);
|
||||
else if (auto fcc = get<FunctionCallConstraint>(*constraint))
|
||||
success = tryDispatch(*fcc, constraint);
|
||||
success = tryDispatch(*fcc, constraint, force);
|
||||
else if (auto fcc = get<FunctionCheckConstraint>(*constraint))
|
||||
success = tryDispatch(*fcc, constraint);
|
||||
else if (auto tcc = get<TableCheckConstraint>(*constraint))
|
||||
|
@ -900,7 +900,7 @@ bool ConstraintSolver::tryDispatch(const GeneralizationConstraint& c, NotNull<co
|
|||
{
|
||||
for (TypeId ty : *constraint->scope->interiorFreeTypes) // NOLINT(bugprone-unchecked-optional-access)
|
||||
{
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
ty = follow(ty);
|
||||
if (auto freeTy = get<FreeType>(ty))
|
||||
|
@ -922,7 +922,7 @@ bool ConstraintSolver::tryDispatch(const GeneralizationConstraint& c, NotNull<co
|
|||
}
|
||||
}
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
if (constraint->scope->interiorFreeTypePacks)
|
||||
{
|
||||
|
@ -942,7 +942,7 @@ bool ConstraintSolver::tryDispatch(const GeneralizationConstraint& c, NotNull<co
|
|||
}
|
||||
}
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
if (c.noGenerics)
|
||||
{
|
||||
|
@ -1158,8 +1158,17 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
|
|||
{
|
||||
auto cTarget = follow(c.target);
|
||||
LUAU_ASSERT(get<PendingExpansionType>(cTarget));
|
||||
shiftReferences(cTarget, result);
|
||||
bind(constraint, cTarget, result);
|
||||
// We do this check here to ensure that we don't bind an alias to itself
|
||||
if (FFlag::LuauGuardAgainstMalformedTypeAliasExpansion2 && occursCheck(cTarget, result))
|
||||
{
|
||||
reportError(OccursCheckFailed{}, constraint->location);
|
||||
bind(constraint, cTarget, builtinTypes->errorRecoveryType());
|
||||
}
|
||||
else
|
||||
{
|
||||
shiftReferences(cTarget, result);
|
||||
bind(constraint, cTarget, result);
|
||||
}
|
||||
};
|
||||
|
||||
std::optional<TypeFun> tf = (petv->prefix) ? constraint->scope->lookupImportedType(petv->prefix->value, petv->name.value)
|
||||
|
@ -1239,19 +1248,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
|
|||
// deterministic.
|
||||
if (TypeId* cached = instantiatedAliases.find(signature))
|
||||
{
|
||||
// However, we might now be revealing a malformed mutually recursive
|
||||
// alias. `instantiatedAliases` can change from underneath us in a
|
||||
// way that can cause a cached type id to bind to itself if we don't
|
||||
// do this check.
|
||||
if (FFlag::LuauGuardAgainstMalformedTypeAliasExpansion && occursCheck(follow(c.target), *cached))
|
||||
{
|
||||
reportError(OccursCheckFailed{}, constraint->location);
|
||||
bindResult(errorRecoveryType());
|
||||
}
|
||||
else
|
||||
{
|
||||
bindResult(*cached);
|
||||
}
|
||||
bindResult(*cached);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1385,13 +1382,13 @@ void ConstraintSolver::fillInDiscriminantTypes(NotNull<const Constraint> constra
|
|||
}
|
||||
}
|
||||
|
||||
bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint)
|
||||
bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint, bool force)
|
||||
{
|
||||
TypeId fn = follow(c.fn);
|
||||
TypePackId argsPack = follow(c.argsPack);
|
||||
TypePackId result = follow(c.result);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
if (isBlocked(fn))
|
||||
return block(c.fn, constraint);
|
||||
|
@ -1521,7 +1518,7 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
|
|||
NotNull{&limits},
|
||||
constraint->location
|
||||
};
|
||||
auto [status, overload] = resolver.selectOverload(fn, argsPack);
|
||||
auto [status, overload] = resolver.selectOverload(fn, argsPack, /*useFreeTypeBounds*/ force);
|
||||
TypeId overloadToUse = fn;
|
||||
if (status == OverloadResolver::Analysis::Ok)
|
||||
overloadToUse = overload;
|
||||
|
@ -1531,7 +1528,7 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
|
|||
|
||||
const bool occursCheckPassed = u2.unify(overloadToUse, inferredTy);
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
for (TypeId freeTy : u2.newFreshTypes)
|
||||
trackInteriorFreeType(constraint->scope, freeTy);
|
||||
|
@ -1945,7 +1942,7 @@ bool ConstraintSolver::tryDispatchHasIndexer(
|
|||
TypeId upperBound =
|
||||
arena->addType(TableType{/* props */ {}, TableIndexer{indexType, resultType}, TypeLevel{}, ft->scope, TableState::Unsealed});
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
TypeId sr = follow(simplifyIntersection(constraint->scope, constraint->location, ft->upperBound, upperBound));
|
||||
|
||||
|
@ -1976,7 +1973,7 @@ bool ConstraintSolver::tryDispatchHasIndexer(
|
|||
|
||||
FreeType freeResult{tt->scope, builtinTypes->neverType, builtinTypes->unknownType, Polarity::Mixed};
|
||||
emplace<FreeType>(constraint, resultType, freeResult);
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
trackInteriorFreeType(constraint->scope, resultType);
|
||||
|
||||
tt->indexer = TableIndexer{indexType, resultType};
|
||||
|
@ -2166,7 +2163,7 @@ bool ConstraintSolver::tryDispatch(const AssignPropConstraint& c, NotNull<const
|
|||
{
|
||||
auto lhsFreeUpperBound = follow(lhsFree->upperBound);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
const auto [blocked, maybeTy, isIndex] = lookupTableProp(constraint, lhsType, propName, ValueContext::LValue);
|
||||
if (!blocked.empty())
|
||||
|
@ -3067,7 +3064,7 @@ TablePropLookupResult ConstraintSolver::lookupTableProp(
|
|||
{
|
||||
const TypeId upperBound = follow(ft->upperBound);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
if (get<TableType>(upperBound) || get<PrimitiveType>(upperBound))
|
||||
{
|
||||
|
@ -3535,7 +3532,7 @@ void ConstraintSolver::shiftReferences(TypeId source, TypeId target)
|
|||
|
||||
// Any constraint that might have mutated source may now mutate target
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
auto it = mutatedFreeTypeToConstraint.find(source);
|
||||
if (it != mutatedFreeTypeToConstraint.end())
|
||||
|
|
|
@ -18,7 +18,6 @@ LUAU_FASTFLAGVARIABLE(LuauDfgScopeStackNotNull)
|
|||
LUAU_FASTFLAG(LuauStoreReturnTypesAsPackOnAst)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDoNotAddUpvalueTypesToLocalType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDfgIfBlocksShouldRespectControlFlow)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDfgMatchCGScopes)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDfgAllowUpdatesInLoops)
|
||||
|
||||
namespace Luau
|
||||
|
@ -1240,18 +1239,9 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprUnary* u)
|
|||
DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprBinary* b)
|
||||
{
|
||||
visitExpr(b->left);
|
||||
if (FFlag::LuauDfgMatchCGScopes)
|
||||
{
|
||||
PushScope _{scopeStack, makeChildScope()};
|
||||
visitExpr(b->right);
|
||||
return {defArena->freshCell(Symbol{}, b->location), nullptr};
|
||||
}
|
||||
else
|
||||
{
|
||||
visitExpr(b->right);
|
||||
return {defArena->freshCell(Symbol{}, b->location), nullptr};
|
||||
}
|
||||
visitExpr(b->right);
|
||||
|
||||
return {defArena->freshCell(Symbol{}, b->location), nullptr};
|
||||
}
|
||||
|
||||
DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprTypeAssertion* t)
|
||||
|
@ -1264,29 +1254,9 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprTypeAssertion* t)
|
|||
|
||||
DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprIfElse* i)
|
||||
{
|
||||
if (FFlag::LuauDfgMatchCGScopes)
|
||||
{
|
||||
// In the constraint generator, the condition, consequence, and
|
||||
// alternative all have distinct scopes.
|
||||
{
|
||||
PushScope _{scopeStack, makeChildScope()};
|
||||
visitExpr(i->condition);
|
||||
}
|
||||
{
|
||||
PushScope _{scopeStack, makeChildScope()};
|
||||
visitExpr(i->trueExpr);
|
||||
}
|
||||
{
|
||||
PushScope _{scopeStack, makeChildScope()};
|
||||
visitExpr(i->falseExpr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
visitExpr(i->condition);
|
||||
visitExpr(i->trueExpr);
|
||||
visitExpr(i->falseExpr);
|
||||
}
|
||||
visitExpr(i->condition);
|
||||
visitExpr(i->trueExpr);
|
||||
visitExpr(i->falseExpr);
|
||||
|
||||
return {defArena->freshCell(Symbol{}, i->location), nullptr};
|
||||
}
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
#include <unordered_set>
|
||||
|
||||
LUAU_FASTINTVARIABLE(LuauIndentTypeMismatchMaxTypeLength, 10)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauBetterCannotCallFunctionPrimitive)
|
||||
|
||||
static std::string wrongNumberOfArgsString(
|
||||
size_t expectedCount,
|
||||
|
@ -446,6 +448,12 @@ struct ErrorConverter
|
|||
return err;
|
||||
}
|
||||
|
||||
if (FFlag::LuauBetterCannotCallFunctionPrimitive)
|
||||
{
|
||||
if (auto primitiveTy = get<PrimitiveType>(follow(e.ty)); primitiveTy && primitiveTy->type == PrimitiveType::Function)
|
||||
return "The type " + toString(e.ty) + " is not precise enough for us to determine the appropriate result type of this call.";
|
||||
}
|
||||
|
||||
return "Cannot call a value of type " + toString(e.ty);
|
||||
}
|
||||
std::string operator()(const Luau::ExtraInformation& e) const
|
||||
|
@ -655,7 +663,7 @@ struct ErrorConverter
|
|||
}
|
||||
|
||||
// binary operators
|
||||
const auto binaryOps = FFlag::DebugLuauGreedyGeneralization ? kBinaryOps : DEPRECATED_kBinaryOps;
|
||||
const auto binaryOps = FFlag::LuauEagerGeneralization ? kBinaryOps : DEPRECATED_kBinaryOps;
|
||||
if (auto binaryString = binaryOps.find(tfit->function->name); binaryString != binaryOps.end())
|
||||
{
|
||||
std::string result = "Operator '" + std::string(binaryString->second) + "' could not be applied to operands of types ";
|
||||
|
@ -710,7 +718,7 @@ struct ErrorConverter
|
|||
"'";
|
||||
}
|
||||
|
||||
if ((FFlag::DebugLuauGreedyGeneralization ? kUnreachableTypeFunctions : DEPRECATED_kUnreachableTypeFunctions).count(tfit->function->name))
|
||||
if ((FFlag::LuauEagerGeneralization ? kUnreachableTypeFunctions : DEPRECATED_kUnreachableTypeFunctions).count(tfit->function->name))
|
||||
{
|
||||
return "Type function instance " + Luau::toString(e.ty) + " is uninhabited\n" +
|
||||
"This is likely to be a bug, please report it at https://github.com/luau-lang/luau/issues";
|
||||
|
|
|
@ -29,10 +29,6 @@ LUAU_FASTINT(LuauTypeInferIterationLimit);
|
|||
LUAU_FASTINT(LuauTarjanChildLimit)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLogFragmentsFromAutocomplete)
|
||||
LUAU_FASTFLAGVARIABLE(LuauBetterCursorInCommentDetection)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAllFreeTypesHaveScopes)
|
||||
LUAU_FASTFLAGVARIABLE(LuauPersistConstraintGenerationScopes)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCloneTypeAliasBindings)
|
||||
LUAU_FASTFLAGVARIABLE(LuauBetterScopeSelection)
|
||||
LUAU_FASTFLAGVARIABLE(LuauBlockDiffFragmentSelection)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFragmentAcMemoryLeak)
|
||||
|
@ -1261,11 +1257,8 @@ FragmentAutocompleteStatusResult tryFragmentAutocomplete(
|
|||
StringCompletionCallback stringCompletionCB
|
||||
)
|
||||
{
|
||||
if (FFlag::LuauBetterCursorInCommentDetection)
|
||||
{
|
||||
if (isWithinComment(context.freshParse.commentLocations, cursorPosition))
|
||||
return {FragmentAutocompleteStatus::Success, std::nullopt};
|
||||
}
|
||||
if (isWithinComment(context.freshParse.commentLocations, cursorPosition))
|
||||
return {FragmentAutocompleteStatus::Success, std::nullopt};
|
||||
// TODO: we should calculate fragmentEnd position here, by using context.newAstRoot and cursorPosition
|
||||
try
|
||||
{
|
||||
|
|
|
@ -39,12 +39,13 @@ LUAU_FASTINT(LuauTarjanChildLimit)
|
|||
LUAU_FASTFLAG(LuauInferInNoCheckMode)
|
||||
LUAU_FASTFLAGVARIABLE(LuauKnowsTheDataModel3)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJsonFile)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForbidInternalTypes)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForceStrictMode)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForceNonStrictMode)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewSolverTypecheckCatchTimeouts)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -408,6 +409,38 @@ void Frontend::parse(const ModuleName& name)
|
|||
parseGraph(buildQueue, name, false);
|
||||
}
|
||||
|
||||
void Frontend::parseModules(const std::vector<ModuleName>& names)
|
||||
{
|
||||
LUAU_TIMETRACE_SCOPE("Frontend::parseModules", "Frontend");
|
||||
|
||||
DenseHashSet<Luau::ModuleName> seen{{}};
|
||||
|
||||
for (const ModuleName& name : names)
|
||||
{
|
||||
if (seen.contains(name))
|
||||
continue;
|
||||
|
||||
if (auto it = sourceNodes.find(name); it != sourceNodes.end() && !it->second->hasDirtySourceModule())
|
||||
{
|
||||
seen.insert(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<ModuleName> queue;
|
||||
parseGraph(
|
||||
queue,
|
||||
name,
|
||||
false,
|
||||
[&seen](const ModuleName& name)
|
||||
{
|
||||
return seen.contains(name);
|
||||
}
|
||||
);
|
||||
|
||||
seen.insert(name);
|
||||
}
|
||||
}
|
||||
|
||||
CheckResult Frontend::check(const ModuleName& name, std::optional<FrontendOptions> optionOverride)
|
||||
{
|
||||
LUAU_TIMETRACE_SCOPE("Frontend::check", "Frontend");
|
||||
|
@ -1403,13 +1436,13 @@ ModulePtr check(
|
|||
requireCycles
|
||||
};
|
||||
|
||||
// FIXME: Delete this flag when clipping FFlag::DebugLuauGreedyGeneralization.
|
||||
// FIXME: Delete this flag when clipping FFlag::LuauEagerGeneralization.
|
||||
//
|
||||
// This optional<> only exists so that we can run one constructor when the flag
|
||||
// is set, and another when it is unset.
|
||||
std::optional<ConstraintSolver> cs;
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
ConstraintSet constraintSet = cg.run(sourceModule.root);
|
||||
result->errors = std::move(constraintSet.errors);
|
||||
|
@ -1495,6 +1528,52 @@ ModulePtr check(
|
|||
for (auto& [name, tf] : result->exportedTypeBindings)
|
||||
tf.type = builtinTypes->errorRecoveryType();
|
||||
}
|
||||
else if (FFlag::LuauNewSolverTypecheckCatchTimeouts)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case Mode::Nonstrict:
|
||||
Luau::checkNonStrict(
|
||||
builtinTypes,
|
||||
NotNull{simplifier.get()},
|
||||
NotNull{&typeFunctionRuntime},
|
||||
iceHandler,
|
||||
NotNull{&unifierState},
|
||||
NotNull{&dfg},
|
||||
NotNull{&limits},
|
||||
sourceModule,
|
||||
result.get()
|
||||
);
|
||||
break;
|
||||
case Mode::Definition:
|
||||
// fallthrough intentional
|
||||
case Mode::Strict:
|
||||
Luau::check(
|
||||
builtinTypes,
|
||||
NotNull{simplifier.get()},
|
||||
NotNull{&typeFunctionRuntime},
|
||||
NotNull{&unifierState},
|
||||
NotNull{&limits},
|
||||
logger.get(),
|
||||
sourceModule,
|
||||
result.get()
|
||||
);
|
||||
break;
|
||||
case Mode::NoCheck:
|
||||
break;
|
||||
};
|
||||
}
|
||||
catch (const TimeLimitError&)
|
||||
{
|
||||
result->timeout = true;
|
||||
}
|
||||
catch (const UserCancelError&)
|
||||
{
|
||||
result->cancelled = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (mode)
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
#include "Luau/Substitution.h"
|
||||
#include "Luau/VisitType.h"
|
||||
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAGVARIABLE(LuauEagerGeneralization)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -469,7 +469,7 @@ struct FreeTypeSearcher : TypeVisitor
|
|||
|
||||
bool visit(TypeId ty, const FreeType& ft) override
|
||||
{
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
if (!subsumes(scope, ft.scope))
|
||||
return true;
|
||||
|
@ -520,7 +520,7 @@ struct FreeTypeSearcher : TypeVisitor
|
|||
|
||||
if ((tt.state == TableState::Free || tt.state == TableState::Unsealed) && subsumes(scope, tt.scope))
|
||||
{
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
unsealedTables.insert(ty);
|
||||
else
|
||||
{
|
||||
|
@ -544,22 +544,57 @@ struct FreeTypeSearcher : TypeVisitor
|
|||
|
||||
for (const auto& [_name, prop] : tt.props)
|
||||
{
|
||||
if (prop.isReadOnly())
|
||||
traverse(*prop.readTy);
|
||||
if (FFlag::LuauEnableWriteOnlyProperties)
|
||||
{
|
||||
if (prop.isReadOnly())
|
||||
{
|
||||
traverse(*prop.readTy);
|
||||
}
|
||||
else if (prop.isWriteOnly())
|
||||
{
|
||||
Polarity p = polarity;
|
||||
polarity = Polarity::Negative;
|
||||
traverse(*prop.writeTy);
|
||||
polarity = p;
|
||||
}
|
||||
else if (prop.isShared())
|
||||
{
|
||||
Polarity p = polarity;
|
||||
polarity = Polarity::Mixed;
|
||||
traverse(prop.type());
|
||||
polarity = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(prop.isReadWrite() && !prop.isShared());
|
||||
|
||||
traverse(*prop.readTy);
|
||||
Polarity p = polarity;
|
||||
polarity = Polarity::Negative;
|
||||
traverse(*prop.writeTy);
|
||||
polarity = p;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(prop.isShared());
|
||||
if (prop.isReadOnly())
|
||||
traverse(*prop.readTy);
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(prop.isShared());
|
||||
|
||||
Polarity p = polarity;
|
||||
polarity = Polarity::Mixed;
|
||||
traverse(prop.type());
|
||||
polarity = p;
|
||||
Polarity p = polarity;
|
||||
polarity = Polarity::Mixed;
|
||||
traverse(prop.type());
|
||||
polarity = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tt.indexer)
|
||||
{
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
// {[K]: V} is equivalent to three functions: get, set, and iterate
|
||||
//
|
||||
|
@ -617,7 +652,7 @@ struct FreeTypeSearcher : TypeVisitor
|
|||
if (!subsumes(scope, ftp.scope))
|
||||
return true;
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
GeneralizationParams<TypePackId>& params = typePacks[tp];
|
||||
++params.useCount;
|
||||
|
@ -1241,7 +1276,7 @@ GeneralizationResult<TypeId> generalizeType(
|
|||
|
||||
if (!hasLowerBound && !hasUpperBound)
|
||||
{
|
||||
if (!isWithinFunction || (!FFlag::DebugLuauGreedyGeneralization && (params.polarity != Polarity::Mixed && params.useCount == 1)))
|
||||
if (!isWithinFunction || (!FFlag::LuauEagerGeneralization && (params.polarity != Polarity::Mixed && params.useCount == 1)))
|
||||
emplaceType<BoundType>(asMutable(freeTy), builtinTypes->unknownType);
|
||||
else
|
||||
{
|
||||
|
@ -1273,7 +1308,7 @@ GeneralizationResult<TypeId> generalizeType(
|
|||
|
||||
if (follow(lb) != freeTy)
|
||||
emplaceType<BoundType>(asMutable(freeTy), lb);
|
||||
else if (!isWithinFunction || (!FFlag::DebugLuauGreedyGeneralization && params.useCount == 1))
|
||||
else if (!isWithinFunction || (!FFlag::LuauEagerGeneralization && params.useCount == 1))
|
||||
emplaceType<BoundType>(asMutable(freeTy), builtinTypes->unknownType);
|
||||
else
|
||||
{
|
||||
|
@ -1390,7 +1425,7 @@ std::optional<TypeId> generalize(
|
|||
FreeTypeSearcher fts{scope, cachedTypes};
|
||||
fts.traverse(ty);
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
FunctionType* functionTy = getMutable<FunctionType>(ty);
|
||||
auto pushGeneric = [&](TypeId t)
|
||||
|
@ -1521,15 +1556,51 @@ struct GenericCounter : TypeVisitor
|
|||
|
||||
for (const auto& [_name, prop] : tt.props)
|
||||
{
|
||||
if (prop.isReadOnly())
|
||||
traverse(*prop.readTy);
|
||||
if (FFlag::LuauEnableWriteOnlyProperties)
|
||||
{
|
||||
if (prop.isReadOnly())
|
||||
{
|
||||
traverse(*prop.readTy);
|
||||
}
|
||||
else if (prop.isWriteOnly())
|
||||
{
|
||||
Polarity p = polarity;
|
||||
polarity = Polarity::Negative;
|
||||
traverse(*prop.writeTy);
|
||||
polarity = p;
|
||||
}
|
||||
else if (prop.isShared())
|
||||
{
|
||||
Polarity p = polarity;
|
||||
polarity = Polarity::Mixed;
|
||||
traverse(prop.type());
|
||||
polarity = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(prop.isReadWrite() && !prop.isShared());
|
||||
|
||||
traverse(*prop.readTy);
|
||||
Polarity p = polarity;
|
||||
polarity = Polarity::Negative;
|
||||
traverse(*prop.writeTy);
|
||||
polarity = p;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(prop.isShared());
|
||||
if (prop.isReadOnly())
|
||||
traverse(*prop.readTy);
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(prop.isShared());
|
||||
|
||||
polarity = Polarity::Mixed;
|
||||
traverse(prop.type());
|
||||
polarity = previous;
|
||||
Polarity p = polarity;
|
||||
polarity = Polarity::Mixed;
|
||||
traverse(prop.type());
|
||||
polarity = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1582,7 +1653,7 @@ void pruneUnnecessaryGenerics(
|
|||
TypeId ty
|
||||
)
|
||||
{
|
||||
if (!FFlag::DebugLuauGreedyGeneralization)
|
||||
if (!FFlag::LuauEagerGeneralization)
|
||||
return;
|
||||
|
||||
ty = follow(ty);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "Luau/Scope.h"
|
||||
#include "Luau/VisitType.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -133,7 +133,7 @@ struct InferPolarity : TypeVisitor
|
|||
template<typename TID>
|
||||
static void inferGenericPolarities_(NotNull<TypeArena> arena, NotNull<Scope> scope, TID ty)
|
||||
{
|
||||
if (!FFlag::LuauNonReentrantGeneralization3)
|
||||
if (!FFlag::LuauEagerGeneralization)
|
||||
return;
|
||||
|
||||
InferPolarity infer{arena, scope};
|
||||
|
|
|
@ -40,7 +40,7 @@ OverloadResolver::OverloadResolver(
|
|||
{
|
||||
}
|
||||
|
||||
std::pair<OverloadResolver::Analysis, TypeId> OverloadResolver::selectOverload(TypeId ty, TypePackId argsPack)
|
||||
std::pair<OverloadResolver::Analysis, TypeId> OverloadResolver::selectOverload(TypeId ty, TypePackId argsPack, bool useFreeTypeBounds)
|
||||
{
|
||||
auto tryOne = [&](TypeId f)
|
||||
{
|
||||
|
@ -51,6 +51,9 @@ std::pair<OverloadResolver::Analysis, TypeId> OverloadResolver::selectOverload(T
|
|||
SubtypingResult r = subtyping.isSubtype(argsPack, ftv->argTypes, scope);
|
||||
subtyping.variance = variance;
|
||||
|
||||
if (!useFreeTypeBounds && !r.assumedConstraints.empty())
|
||||
return false;
|
||||
|
||||
if (r.isSubtype)
|
||||
return true;
|
||||
}
|
||||
|
@ -461,7 +464,7 @@ static std::optional<TypeId> selectOverload(
|
|||
{
|
||||
auto resolver =
|
||||
std::make_unique<OverloadResolver>(builtinTypes, arena, simplifier, normalizer, typeFunctionRuntime, scope, iceReporter, limits, location);
|
||||
auto [status, overload] = resolver->selectOverload(fn, argsPack);
|
||||
auto [status, overload] = resolver->selectOverload(fn, argsPack, /*useFreeTypeBounds*/ false);
|
||||
|
||||
if (status == OverloadResolver::Analysis::Ok)
|
||||
return overload;
|
||||
|
|
|
@ -21,6 +21,7 @@ LUAU_FASTFLAGVARIABLE(DebugLuauSubtypingCheckPathValidity)
|
|||
LUAU_FASTINTVARIABLE(LuauSubtypingReasoningLimit, 100)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSubtypeGenericsAndNegations)
|
||||
LUAU_FASTFLAG(LuauClipVariadicAnysFromArgsToGenericFuncs2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -680,6 +681,44 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
|||
result.isSubtype = ok;
|
||||
result.isCacheable = false;
|
||||
}
|
||||
else if (auto pair = get2<FreeType, FreeType>(subTy, superTy); FFlag::LuauEagerGeneralization && pair)
|
||||
{
|
||||
// Any two free types are potentially subtypes of one another because
|
||||
// both of them could be narrowed to never.
|
||||
result = {true};
|
||||
result.assumedConstraints.emplace_back(SubtypeConstraint{subTy, superTy});
|
||||
}
|
||||
else if (auto superFree = get<FreeType>(superTy); superFree && FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
// Given SubTy <: (LB <: SuperTy <: UB)
|
||||
//
|
||||
// If SubTy <: UB, then it is possible that SubTy <: SuperTy.
|
||||
// If SubTy </: UB, then it is definitely the case that SubTy </: SuperTy.
|
||||
//
|
||||
// It's always possible for SuperTy's upper bound to later be
|
||||
// constrained, so this relation may not actually hold.
|
||||
|
||||
result = isCovariantWith(env, subTy, superFree->upperBound, scope);
|
||||
|
||||
if (result.isSubtype)
|
||||
result.assumedConstraints.emplace_back(SubtypeConstraint{subTy, superTy});
|
||||
}
|
||||
else if (auto subFree = get<FreeType>(subTy); subFree && FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
// Given (LB <: SubTy <: UB) <: SuperTy
|
||||
//
|
||||
// If UB <: SuperTy, then it is certainly the case that SubTy <: SuperTy.
|
||||
// If SuperTy <: UB and LB <: SuperTy, then it is possible that UB will later be narrowed such that SubTy <: SuperTy.
|
||||
// If LB </: SuperTy, then SubTy </: SuperTy
|
||||
|
||||
if (isCovariantWith(env, subFree->lowerBound, superTy, scope).isSubtype)
|
||||
{
|
||||
result = {true};
|
||||
result.assumedConstraints.emplace_back(SubtypeConstraint{subTy, superTy});
|
||||
}
|
||||
else
|
||||
result = {false};
|
||||
}
|
||||
else if (auto p = get2<NegationType, NegationType>(subTy, superTy))
|
||||
result = isCovariantWith(env, p.first->ty, p.second->ty, scope).withBothComponent(TypePath::TypeField::Negated);
|
||||
else if (auto subNegation = get<NegationType>(subTy))
|
||||
|
@ -1411,8 +1450,24 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Tabl
|
|||
{
|
||||
SubtypingResult result{true};
|
||||
|
||||
if (subTable->props.empty() && !subTable->indexer && superTable->indexer)
|
||||
return {false};
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
if (subTable->props.empty() && !subTable->indexer && subTable->state == TableState::Sealed && superTable->indexer)
|
||||
{
|
||||
// While it is certainly the case that {} </: {T}, the story is a little bit different for {| |} <: {T}
|
||||
// The shape of an unsealed tabel is still in flux, so it is probably the case that the unsealed table
|
||||
// will later gain the necessary indexer as type inference proceeds.
|
||||
//
|
||||
// Unsealed tables are always sealed by the time inference completes, so this should never affect the
|
||||
// type checking phase.
|
||||
return {false};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (subTable->props.empty() && !subTable->indexer && superTable->indexer)
|
||||
return {false};
|
||||
}
|
||||
|
||||
for (const auto& [name, superProp] : superTable->props)
|
||||
{
|
||||
|
@ -1451,6 +1506,12 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Tabl
|
|||
{
|
||||
if (subTable->indexer)
|
||||
result.andAlso(isInvariantWith(env, *subTable->indexer, *superTable->indexer, scope));
|
||||
else if (FFlag::LuauEagerGeneralization && subTable->state != TableState::Sealed)
|
||||
{
|
||||
// As above, we assume that {| |} <: {T} because the unsealed table
|
||||
// on the left will eventually gain the necessary indexer.
|
||||
return {true};
|
||||
}
|
||||
else
|
||||
return {false};
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ LUAU_FASTFLAGVARIABLE(LuauStringPartLengthLimit)
|
|||
*/
|
||||
LUAU_FASTINTVARIABLE(DebugLuauVerboseTypeNames, 0)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauToStringNoLexicalSort)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFixEmptyTypePackStringification)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -479,6 +480,9 @@ struct TypeStringifier
|
|||
|
||||
bool wrap = !singleTp && get<TypePack>(follow(tp));
|
||||
|
||||
if (FFlag::LuauFixEmptyTypePackStringification)
|
||||
wrap &= !isEmpty(tp);
|
||||
|
||||
if (wrap)
|
||||
state.emit("(");
|
||||
|
||||
|
@ -687,14 +691,18 @@ struct TypeStringifier
|
|||
|
||||
state.emit("(");
|
||||
|
||||
if (state.opts.functionTypeArguments)
|
||||
if (FFlag::LuauFixEmptyTypePackStringification && isEmpty(ftv.argTypes))
|
||||
{
|
||||
// if we've got an empty argument pack, we're done.
|
||||
}
|
||||
else if (state.opts.functionTypeArguments)
|
||||
stringify(ftv.argTypes, ftv.argNames);
|
||||
else
|
||||
stringify(ftv.argTypes);
|
||||
|
||||
state.emit(") -> ");
|
||||
|
||||
bool plural = true;
|
||||
bool plural = FFlag::LuauFixEmptyTypePackStringification ? !isEmpty(ftv.retTypes) : true;
|
||||
|
||||
auto retBegin = begin(ftv.retTypes);
|
||||
auto retEnd = end(ftv.retTypes);
|
||||
|
@ -1235,6 +1243,16 @@ struct TypePackStringifier
|
|||
return;
|
||||
}
|
||||
|
||||
if (FFlag::LuauFixEmptyTypePackStringification)
|
||||
{
|
||||
if (tp.head.empty() && (!tp.tail || isEmpty(*tp.tail)))
|
||||
{
|
||||
state.emit("()");
|
||||
state.unsee(&tp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
|
||||
for (const auto& typeId : tp.head)
|
||||
|
@ -1782,17 +1800,34 @@ std::string toStringNamedFunction(const std::string& funcName, const FunctionTyp
|
|||
|
||||
state.emit("): ");
|
||||
|
||||
size_t retSize = size(ftv.retTypes);
|
||||
bool hasTail = !finite(ftv.retTypes);
|
||||
bool wrap = get<TypePack>(follow(ftv.retTypes)) && (hasTail ? retSize != 0 : retSize != 1);
|
||||
if (FFlag::LuauFixEmptyTypePackStringification)
|
||||
{
|
||||
size_t retSize = size(ftv.retTypes);
|
||||
bool hasTail = !finite(ftv.retTypes);
|
||||
bool wrap = get<TypePack>(follow(ftv.retTypes)) && (hasTail ? retSize != 0 : retSize > 1);
|
||||
|
||||
if (wrap)
|
||||
state.emit("(");
|
||||
if (wrap)
|
||||
state.emit("(");
|
||||
|
||||
tvs.stringify(ftv.retTypes);
|
||||
tvs.stringify(ftv.retTypes);
|
||||
|
||||
if (wrap)
|
||||
state.emit(")");
|
||||
if (wrap)
|
||||
state.emit(")");
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t retSize = size(ftv.retTypes);
|
||||
bool hasTail = !finite(ftv.retTypes);
|
||||
bool wrap = get<TypePack>(follow(ftv.retTypes)) && (hasTail ? retSize != 0 : retSize != 1);
|
||||
|
||||
if (wrap)
|
||||
state.emit("(");
|
||||
|
||||
tvs.stringify(ftv.retTypes);
|
||||
|
||||
if (wrap)
|
||||
state.emit(")");
|
||||
}
|
||||
|
||||
return result.name;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,7 +27,6 @@ LUAU_FASTINTVARIABLE(LuauTypeMaximumStringifierLength, 500)
|
|||
LUAU_FASTINTVARIABLE(LuauTableTypeMaximumStringifierLength, 0)
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFreeTypesMustHaveBounds)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include "Luau/TypeArena.h"
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauFreezeArena);
|
||||
LUAU_FASTFLAG(LuauFreeTypesMustHaveBounds)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
LUAU_FASTFLAG(LuauStoreCSTData2)
|
||||
LUAU_FASTFLAG(LuauStoreReturnTypesAsPackOnAst)
|
||||
|
||||
static char* allocateString(Luau::Allocator& allocator, std::string_view contents)
|
||||
|
@ -307,7 +308,8 @@ public:
|
|||
std::optional<AstArgumentName>* arg = &argNames.data[i++];
|
||||
|
||||
if (el)
|
||||
new (arg) std::optional<AstArgumentName>(AstArgumentName(AstName(el->name.c_str()), Location()));
|
||||
new (arg)
|
||||
std::optional<AstArgumentName>(AstArgumentName(AstName(el->name.c_str()), FFlag::LuauStoreCSTData2 ? Location() : el->location));
|
||||
else
|
||||
new (arg) std::optional<AstArgumentName>();
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ LUAU_FASTFLAG(DebugLuauMagicTypes)
|
|||
LUAU_FASTFLAGVARIABLE(LuauTypeCheckerAcceptNumberConcats)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTypeCheckerStricterIndexCheck)
|
||||
LUAU_FASTFLAG(LuauStoreReturnTypesAsPackOnAst)
|
||||
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAGVARIABLE(LuauReportSubtypingErrors)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSkipMalformedTypeAliases)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTableLiteralSubtypeSpecificCheck)
|
||||
|
@ -2984,10 +2985,22 @@ bool TypeChecker2::testPotentialLiteralIsSubtype(AstExpr* expr, TypeId expectedT
|
|||
Set<std::optional<std::string> > missingKeys{{}};
|
||||
for (const auto& [name, prop] : expectedTableType->props)
|
||||
{
|
||||
LUAU_ASSERT(!prop.isWriteOnly());
|
||||
auto readTy = *prop.readTy;
|
||||
if (!isOptional(readTy))
|
||||
missingKeys.insert(name);
|
||||
if (FFlag::LuauEnableWriteOnlyProperties)
|
||||
{
|
||||
if (prop.readTy)
|
||||
{
|
||||
if (!isOptional(*prop.readTy))
|
||||
missingKeys.insert(name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(!prop.isWriteOnly());
|
||||
|
||||
auto readTy = *prop.readTy;
|
||||
if (!isOptional(readTy))
|
||||
missingKeys.insert(name);
|
||||
}
|
||||
}
|
||||
|
||||
bool isArrayLike = false;
|
||||
|
@ -3023,11 +3036,25 @@ bool TypeChecker2::testPotentialLiteralIsSubtype(AstExpr* expr, TypeId expectedT
|
|||
}
|
||||
else
|
||||
{
|
||||
// TODO: What do we do for write only props?
|
||||
LUAU_ASSERT(expectedIt->second.readTy);
|
||||
// Some property is in the expected type: we can test against the specific type.
|
||||
module->astExpectedTypes[item.value] = *expectedIt->second.readTy;
|
||||
isSubtype &= testPotentialLiteralIsSubtype(item.value, *expectedIt->second.readTy);
|
||||
if (FFlag::LuauEnableWriteOnlyProperties)
|
||||
{
|
||||
// If the type has a read type, then we have an expected type for it, otherwise, we actually don't
|
||||
// care what's assigned to it because the only allowed behavior is writing to that property.
|
||||
|
||||
if (expectedIt->second.readTy)
|
||||
{
|
||||
module->astExpectedTypes[item.value] = *expectedIt->second.readTy;
|
||||
isSubtype &= testPotentialLiteralIsSubtype(item.value, *expectedIt->second.readTy);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: What do we do for write only props?
|
||||
LUAU_ASSERT(expectedIt->second.readTy);
|
||||
// Some property is in the expected type: we can test against the specific type.
|
||||
module->astExpectedTypes[item.value] = *expectedIt->second.readTy;
|
||||
isSubtype &= testPotentialLiteralIsSubtype(item.value, *expectedIt->second.readTy);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (item.kind == AstExprTable::Item::List)
|
||||
|
|
|
@ -47,8 +47,8 @@ LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFamilyApplicationCartesianProductLimit, 5'0
|
|||
LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFamilyUseGuesserDepth, -1);
|
||||
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogTypeFamilies)
|
||||
LUAU_FASTFLAG(LuauOptimizeFalsyAndTruthyIntersect)
|
||||
|
@ -283,7 +283,7 @@ struct TypeFunctionReducer
|
|||
}
|
||||
else if (is<GenericType>(ty))
|
||||
{
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
return SkipTestResult::Generic;
|
||||
else
|
||||
return SkipTestResult::Irreducible;
|
||||
|
@ -305,7 +305,7 @@ struct TypeFunctionReducer
|
|||
}
|
||||
else if (is<GenericTypePack>(ty))
|
||||
{
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
return SkipTestResult::Generic;
|
||||
else
|
||||
return SkipTestResult::Irreducible;
|
||||
|
@ -1101,7 +1101,7 @@ TypeFunctionReductionResult<TypeId> unmTypeFunction(
|
|||
if (isPending(operandTy, ctx->solver))
|
||||
return {std::nullopt, Reduction::MaybeOk, {operandTy}, {}};
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
operandTy = follow(operandTy);
|
||||
|
||||
std::shared_ptr<const NormalizedType> normTy = ctx->normalizer->normalize(operandTy);
|
||||
|
@ -1698,7 +1698,7 @@ TypeFunctionReductionResult<TypeId> orTypeFunction(
|
|||
return {rhsTy, Reduction::MaybeOk, {}, {}};
|
||||
|
||||
// check to see if both operand types are resolved enough, and wait to reduce if not
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
if (is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(lhsTy))
|
||||
return {std::nullopt, Reduction::MaybeOk, {lhsTy}, {}};
|
||||
|
@ -1745,7 +1745,7 @@ static TypeFunctionReductionResult<TypeId> comparisonTypeFunction(
|
|||
if (lhsTy == instance || rhsTy == instance)
|
||||
return {ctx->builtins->neverType, Reduction::MaybeOk, {}, {}};
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
if (is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(lhsTy))
|
||||
return {std::nullopt, Reduction::MaybeOk, {lhsTy}, {}};
|
||||
|
@ -2119,7 +2119,7 @@ TypeFunctionReductionResult<TypeId> refineTypeFunction(
|
|||
for (size_t i = 1; i < typeParams.size(); i++)
|
||||
discriminantTypes.push_back(follow(typeParams.at(i)));
|
||||
|
||||
const bool targetIsPending = FFlag::DebugLuauGreedyGeneralization
|
||||
const bool targetIsPending = FFlag::LuauEagerGeneralization
|
||||
? is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(targetTy)
|
||||
: isPending(targetTy, ctx->solver);
|
||||
|
||||
|
@ -2206,7 +2206,7 @@ TypeFunctionReductionResult<TypeId> refineTypeFunction(
|
|||
if (is<TableType>(target) || isSimpleDiscriminant(discriminant))
|
||||
{
|
||||
SimplifyResult result = simplifyIntersection(ctx->builtins, ctx->arena, target, discriminant);
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
// Simplification considers free and generic types to be
|
||||
// 'blocking', but that's not suitable for refine<>.
|
||||
|
@ -3335,7 +3335,7 @@ BuiltinTypeFunctions::BuiltinTypeFunctions()
|
|||
, ltFunc{"lt", ltTypeFunction}
|
||||
, leFunc{"le", leTypeFunction}
|
||||
, eqFunc{"eq", eqTypeFunction}
|
||||
, refineFunc{"refine", refineTypeFunction, /*canReduceGenerics*/ FFlag::DebugLuauGreedyGeneralization}
|
||||
, refineFunc{"refine", refineTypeFunction, /*canReduceGenerics*/ FFlag::LuauEagerGeneralization}
|
||||
, singletonFunc{"singleton", singletonTypeFunction}
|
||||
, unionFunc{"union", unionTypeFunction}
|
||||
, intersectFunc{"intersect", intersectTypeFunction}
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#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
|
||||
|
@ -157,16 +156,12 @@ 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;
|
||||
}
|
||||
|
||||
PathBuilder& PathBuilder::writeProp(std::string name)
|
||||
{
|
||||
if (!FFlag::LuauDisableNewSolverAssertsInMixedMode)
|
||||
LUAU_ASSERT(FFlag::LuauSolverV2);
|
||||
components.push_back(Property{std::move(name), false});
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
#include <algorithm>
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAG(LuauDisableNewSolverAssertsInMixedMode)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAGVARIABLE(LuauErrorSuppressionTypeFunctionArgs)
|
||||
|
||||
namespace Luau
|
||||
|
@ -307,7 +306,7 @@ TypePack extendTypePack(
|
|||
TypePack newPack;
|
||||
newPack.tail = arena.freshTypePack(ftp->scope, ftp->polarity);
|
||||
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
trackInteriorFreeTypePack(ftp->scope, *newPack.tail);
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
|
@ -572,8 +571,6 @@ std::vector<TypeId> findBlockedArgTypesIn(AstExprCall* expr, NotNull<DenseHashMa
|
|||
|
||||
void trackInteriorFreeType(Scope* scope, TypeId ty)
|
||||
{
|
||||
if (!FFlag::LuauDisableNewSolverAssertsInMixedMode)
|
||||
LUAU_ASSERT(FFlag::LuauSolverV2);
|
||||
for (; scope; scope = scope->parent.get())
|
||||
{
|
||||
if (scope->interiorFreeTypes)
|
||||
|
@ -591,7 +588,7 @@ void trackInteriorFreeType(Scope* scope, TypeId ty)
|
|||
void trackInteriorFreeTypePack(Scope* scope, TypePackId tp)
|
||||
{
|
||||
LUAU_ASSERT(tp);
|
||||
if (!FFlag::LuauNonReentrantGeneralization3)
|
||||
if (!FFlag::LuauEagerGeneralization)
|
||||
return;
|
||||
|
||||
for (; scope; scope = scope->parent.get())
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
#include <optional>
|
||||
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -329,12 +329,12 @@ bool Unifier2::unify(TypeId subTy, const FunctionType* superFn)
|
|||
|
||||
for (TypePackId genericPack : subFn->genericPacks)
|
||||
{
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
genericPack = follow(genericPack);
|
||||
|
||||
// TODO: Clip this follow() with DebugLuauGreedyGeneralization
|
||||
// TODO: Clip this follow() with LuauEagerGeneralization
|
||||
const GenericTypePack* gen = get<GenericTypePack>(follow(genericPack));
|
||||
if (gen)
|
||||
genericPackSubstitutions[genericPack] = freshTypePack(scope, gen->polarity);
|
||||
|
@ -413,16 +413,27 @@ bool Unifier2::unify(TableType* subTable, const TableType* superTable)
|
|||
{
|
||||
const Property& superProp = superPropOpt->second;
|
||||
|
||||
if (subProp.isReadOnly() && superProp.isReadOnly())
|
||||
result &= unify(*subProp.readTy, *superPropOpt->second.readTy);
|
||||
else if (subProp.isReadOnly())
|
||||
result &= unify(*subProp.readTy, superProp.type());
|
||||
else if (superProp.isReadOnly())
|
||||
result &= unify(subProp.type(), *superProp.readTy);
|
||||
if (FFlag::LuauEnableWriteOnlyProperties)
|
||||
{
|
||||
if (subProp.readTy && superProp.readTy)
|
||||
result &= unify(*subProp.readTy, *superProp.readTy);
|
||||
|
||||
if (subProp.writeTy && superProp.writeTy)
|
||||
result &= unify(*superProp.writeTy, *subProp.writeTy);
|
||||
}
|
||||
else
|
||||
{
|
||||
result &= unify(subProp.type(), superProp.type());
|
||||
result &= unify(superProp.type(), subProp.type());
|
||||
if (subProp.isReadOnly() && superProp.isReadOnly())
|
||||
result &= unify(*subProp.readTy, *superPropOpt->second.readTy);
|
||||
else if (subProp.isReadOnly())
|
||||
result &= unify(*subProp.readTy, superProp.type());
|
||||
else if (superProp.isReadOnly())
|
||||
result &= unify(subProp.type(), *superProp.readTy);
|
||||
else
|
||||
{
|
||||
result &= unify(subProp.type(), superProp.type());
|
||||
result &= unify(superProp.type(), subProp.type());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -454,7 +465,7 @@ bool Unifier2::unify(TableType* subTable, const TableType* superTable)
|
|||
{
|
||||
result &= unify(subTable->indexer->indexType, superTable->indexer->indexType);
|
||||
result &= unify(subTable->indexer->indexResultType, superTable->indexer->indexResultType);
|
||||
if (FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
// FIXME: We can probably do something more efficient here.
|
||||
result &= unify(superTable->indexer->indexType, subTable->indexer->indexType);
|
||||
|
|
|
@ -245,6 +245,8 @@ private:
|
|||
};
|
||||
|
||||
TableIndexerResult parseTableIndexer(AstTableAccess access, std::optional<Location> accessLocation, Lexeme begin);
|
||||
// Remove with FFlagLuauStoreCSTData2
|
||||
AstTableIndexer* parseTableIndexer_DEPRECATED(AstTableAccess access, std::optional<Location> accessLocation, Lexeme begin);
|
||||
|
||||
AstTypeOrPack parseFunctionType(bool allowPack, const AstArray<AstAttr*>& attributes);
|
||||
AstType* parseFunctionTypeTail(
|
||||
|
|
1046
Ast/src/Parser.cpp
1046
Ast/src/Parser.cpp
File diff suppressed because it is too large
Load diff
|
@ -121,6 +121,8 @@ void create(lua_State* L, SharedCodeGenContext* codeGenContext);
|
|||
// Enable or disable native execution according to `enabled` argument
|
||||
void setNativeExecutionEnabled(lua_State* L, bool enabled);
|
||||
|
||||
void disableNativeExecutionForFunction(lua_State* L, const int level) noexcept;
|
||||
|
||||
// Given a name, this function must return the index of the type which matches the type array used all CompilationOptions and AssemblyOptions
|
||||
// If the type is unknown, 0xff has to be returned
|
||||
using UserdataRemapperCallback = uint8_t(void* context, const char* name, size_t nameLength);
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
|
||||
#include "lstate.h"
|
||||
|
||||
LUAU_DYNAMIC_FASTFLAG(AddReturnExectargetCheck);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
|
@ -179,6 +181,14 @@ void emitReturn(AssemblyBuilderA64& build, ModuleHelpers& helpers)
|
|||
|
||||
build.ldr(x1, mem(rClosure, offsetof(Closure, l.p))); // cl->l.p aka proto
|
||||
|
||||
if (DFFlag::AddReturnExectargetCheck)
|
||||
{
|
||||
// Get new instruction location
|
||||
CODEGEN_ASSERT(offsetof(Proto, exectarget) == offsetof(Proto, execdata) + 8);
|
||||
build.ldp(x3, x4, mem(x1, offsetof(Proto, execdata)));
|
||||
build.cbz(x4, helpers.exitContinueVmClearNativeFlag);
|
||||
}
|
||||
|
||||
CODEGEN_ASSERT(offsetof(Proto, code) == offsetof(Proto, k) + 8);
|
||||
build.ldp(rConstants, rCode, mem(x1, offsetof(Proto, k))); // proto->k, proto->code
|
||||
|
||||
|
@ -188,9 +198,12 @@ void emitReturn(AssemblyBuilderA64& build, ModuleHelpers& helpers)
|
|||
build.ldr(x2, mem(x2, offsetof(CallInfo, savedpc))); // cip->savedpc
|
||||
build.sub(x2, x2, rCode);
|
||||
|
||||
// Get new instruction location and jump to it
|
||||
CODEGEN_ASSERT(offsetof(Proto, exectarget) == offsetof(Proto, execdata) + 8);
|
||||
build.ldp(x3, x4, mem(x1, offsetof(Proto, execdata)));
|
||||
if (!DFFlag::AddReturnExectargetCheck)
|
||||
{
|
||||
// Get new instruction location and jump to it
|
||||
CODEGEN_ASSERT(offsetof(Proto, exectarget) == offsetof(Proto, execdata) + 8);
|
||||
build.ldp(x3, x4, mem(x1, offsetof(Proto, execdata)));
|
||||
}
|
||||
build.ldr(w2, mem(x3, x2));
|
||||
build.add(x4, x4, x2);
|
||||
build.br(x4);
|
||||
|
|
|
@ -671,6 +671,21 @@ void setNativeExecutionEnabled(lua_State* L, bool enabled)
|
|||
L->global->ecb.enter = enabled ? onEnter : onEnterDisabled;
|
||||
}
|
||||
|
||||
void disableNativeExecutionForFunction(lua_State* L, const int level) noexcept
|
||||
{
|
||||
CODEGEN_ASSERT(unsigned(level) < unsigned(L->ci - L->base_ci));
|
||||
|
||||
const CallInfo* ci = L->ci - level;
|
||||
const TValue* o = ci->func;
|
||||
CODEGEN_ASSERT(ttisfunction(o));
|
||||
|
||||
Proto* proto = clvalue(o)->l.p;
|
||||
CODEGEN_ASSERT(proto);
|
||||
|
||||
CODEGEN_ASSERT(proto->codeentry != proto->code);
|
||||
onDestroyFunction(L, proto);
|
||||
}
|
||||
|
||||
static uint8_t userdataRemapperWrap(lua_State* L, const char* str, size_t len)
|
||||
{
|
||||
if (BaseCodeGenContext* codegenCtx = getCodeGenContext(L))
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
|
||||
#include <utility>
|
||||
|
||||
|
||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(AddReturnExectargetCheck, false);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
|
@ -458,6 +461,7 @@ void emitReturn(AssemblyBuilderX64& build, ModuleHelpers& helpers)
|
|||
// Registers alive: r9 (cip)
|
||||
RegisterX64 proto = rcx;
|
||||
RegisterX64 execdata = rbx;
|
||||
RegisterX64 exectarget = r10;
|
||||
|
||||
// Change closure
|
||||
build.mov(rax, qword[cip + offsetof(CallInfo, func)]);
|
||||
|
@ -471,6 +475,13 @@ void emitReturn(AssemblyBuilderX64& build, ModuleHelpers& helpers)
|
|||
build.test(byte[cip + offsetof(CallInfo, flags)], LUA_CALLINFO_NATIVE);
|
||||
build.jcc(ConditionX64::Zero, helpers.exitContinueVm); // Continue in interpreter if function has no native data
|
||||
|
||||
if (DFFlag::AddReturnExectargetCheck)
|
||||
{
|
||||
build.mov(exectarget, qword[proto + offsetof(Proto, exectarget)]);
|
||||
build.test(exectarget, exectarget);
|
||||
build.jcc(ConditionX64::Zero, helpers.exitContinueVmClearNativeFlag);
|
||||
}
|
||||
|
||||
// Change constants
|
||||
build.mov(rConstants, qword[proto + offsetof(Proto, k)]);
|
||||
|
||||
|
@ -486,7 +497,15 @@ void emitReturn(AssemblyBuilderX64& build, ModuleHelpers& helpers)
|
|||
|
||||
// Get new instruction location and jump to it
|
||||
build.mov(edx, dword[execdata + rax]);
|
||||
build.add(rdx, qword[proto + offsetof(Proto, exectarget)]);
|
||||
|
||||
if (DFFlag::AddReturnExectargetCheck)
|
||||
{
|
||||
build.add(rdx, exectarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
build.add(rdx, qword[proto + offsetof(Proto, exectarget)]);
|
||||
}
|
||||
build.jmp(rdx);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
LUAU_FASTFLAG(LuauCurrentLineBounds)
|
||||
LUAU_FASTFLAGVARIABLE(LuauHeapNameDetails)
|
||||
|
||||
static void validateobjref(global_State* g, GCObject* f, GCObject* t)
|
||||
{
|
||||
|
@ -728,10 +729,20 @@ static void enumclosure(EnumContext* ctx, Closure* cl)
|
|||
|
||||
char buf[LUA_IDSIZE];
|
||||
|
||||
if (p->source)
|
||||
snprintf(buf, sizeof(buf), "%s:%d %s", p->debugname ? getstr(p->debugname) : "", p->linedefined, getstr(p->source));
|
||||
if (FFlag::LuauHeapNameDetails)
|
||||
{
|
||||
if (p->source)
|
||||
snprintf(buf, sizeof(buf), "%s:%d %s", p->debugname ? getstr(p->debugname) : "unnamed", p->linedefined, getstr(p->source));
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s:%d", p->debugname ? getstr(p->debugname) : "unnamed", p->linedefined);
|
||||
}
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s:%d", p->debugname ? getstr(p->debugname) : "", p->linedefined);
|
||||
{
|
||||
if (p->source)
|
||||
snprintf(buf, sizeof(buf), "%s:%d %s", p->debugname ? getstr(p->debugname) : "", p->linedefined, getstr(p->source));
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s:%d", p->debugname ? getstr(p->debugname) : "", p->linedefined);
|
||||
}
|
||||
|
||||
enumnode(ctx, obj2gco(cl), sizeLclosure(cl->nupvalues), buf);
|
||||
}
|
||||
|
@ -799,10 +810,21 @@ static void enumthread(EnumContext* ctx, lua_State* th)
|
|||
|
||||
char buf[LUA_IDSIZE];
|
||||
|
||||
if (p->source)
|
||||
snprintf(buf, sizeof(buf), "%s:%d %s", p->debugname ? getstr(p->debugname) : "", p->linedefined, getstr(p->source));
|
||||
if (FFlag::LuauHeapNameDetails)
|
||||
{
|
||||
if (p->source)
|
||||
snprintf(buf, sizeof(buf), "thread at %s:%d %s", p->debugname ? getstr(p->debugname) : "unnamed", p->linedefined, getstr(p->source));
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "thread at %s:%d", p->debugname ? getstr(p->debugname) : "unnamed", p->linedefined);
|
||||
}
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s:%d", p->debugname ? getstr(p->debugname) : "", p->linedefined);
|
||||
{
|
||||
|
||||
if (p->source)
|
||||
snprintf(buf, sizeof(buf), "%s:%d %s", p->debugname ? getstr(p->debugname) : "", p->linedefined, getstr(p->source));
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "%s:%d", p->debugname ? getstr(p->debugname) : "", p->linedefined);
|
||||
}
|
||||
|
||||
enumnode(ctx, obj2gco(th), size, buf);
|
||||
}
|
||||
|
@ -835,7 +857,21 @@ static void enumproto(EnumContext* ctx, Proto* p)
|
|||
ctx->edge(ctx->context, enumtopointer(obj2gco(p)), p->execdata, "[native]");
|
||||
}
|
||||
|
||||
enumnode(ctx, obj2gco(p), size, p->source ? getstr(p->source) : NULL);
|
||||
if (FFlag::LuauHeapNameDetails)
|
||||
{
|
||||
char buf[LUA_IDSIZE];
|
||||
|
||||
if (p->source)
|
||||
snprintf(buf, sizeof(buf), "proto %s:%d %s", p->debugname ? getstr(p->debugname) : "unnamed", p->linedefined, getstr(p->source));
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "proto %s:%d", p->debugname ? getstr(p->debugname) : "unnamed", p->linedefined);
|
||||
|
||||
enumnode(ctx, obj2gco(p), size, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
enumnode(ctx, obj2gco(p), size, p->source ? getstr(p->source) : NULL);
|
||||
}
|
||||
|
||||
if (p->sizek)
|
||||
enumedges(ctx, obj2gco(p), p->k, p->sizek, "constants");
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
LUAU_FASTFLAG(LuauTraceTypesInNonstrictMode2)
|
||||
LUAU_FASTFLAG(LuauSetMetatableDoesNotTimeTravel)
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -4454,10 +4454,10 @@ TEST_CASE_FIXTURE(ACExternTypeFixture, "ac_dont_overflow_on_recursive_union")
|
|||
|
||||
auto ac = autocomplete('1');
|
||||
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
// This `if` statement is because `LuauNonReentrantGeneralization3`
|
||||
// sets some flags
|
||||
// This `if` statement is because `LuauEagerGeneralization`
|
||||
// sets some flags
|
||||
CHECK(ac.entryMap.count("BaseMethod") > 0);
|
||||
CHECK(ac.entryMap.count("Method") > 0);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ LUAU_DYNAMIC_FASTFLAG(LuauStringFormatFixC)
|
|||
LUAU_FASTFLAG(LuauYieldableContinuations)
|
||||
LUAU_FASTFLAG(LuauCurrentLineBounds)
|
||||
LUAU_FASTFLAG(LuauLoadNoOomThrow)
|
||||
LUAU_FASTFLAG(LuauHeapNameDetails)
|
||||
|
||||
static lua_CompileOptions defaultOptions()
|
||||
{
|
||||
|
@ -2280,6 +2281,8 @@ TEST_CASE("StringConversion")
|
|||
|
||||
TEST_CASE("GCDump")
|
||||
{
|
||||
ScopedFastFlag luauHeapNameDetails{FFlag::LuauHeapNameDetails, true};
|
||||
|
||||
// internal function, declared in lgc.h - not exposed via lua.h
|
||||
extern void luaC_dump(lua_State * L, void* file, const char* (*categoryName)(lua_State* L, uint8_t memcat));
|
||||
extern void luaC_enumheap(
|
||||
|
@ -2320,7 +2323,19 @@ TEST_CASE("GCDump")
|
|||
|
||||
lua_State* CL = lua_newthread(L);
|
||||
|
||||
lua_pushstring(CL, "local x x = {} local function f() x[1] = math.abs(42) end function foo() coroutine.yield() end foo() return f");
|
||||
lua_pushstring(CL, R"(
|
||||
local x
|
||||
x = {}
|
||||
local function f()
|
||||
x[1] = math.abs(42)
|
||||
end
|
||||
function foo()
|
||||
coroutine.yield()
|
||||
end
|
||||
foo()
|
||||
return f
|
||||
)");
|
||||
lua_pushstring(CL, "=GCDump");
|
||||
lua_loadstring(CL);
|
||||
lua_resume(CL, nullptr, 0);
|
||||
|
||||
|
@ -2365,8 +2380,19 @@ TEST_CASE("GCDump")
|
|||
{
|
||||
EnumContext& context = *(EnumContext*)ctx;
|
||||
|
||||
if (tt == LUA_TUSERDATA)
|
||||
CHECK(strcmp(name, "u42") == 0);
|
||||
if (name)
|
||||
{
|
||||
std::string_view sv{name};
|
||||
|
||||
if (tt == LUA_TUSERDATA)
|
||||
CHECK(sv == "u42");
|
||||
else if (tt == LUA_TPROTO)
|
||||
CHECK((sv == "proto unnamed:1 =GCDump" || sv == "proto foo:7 =GCDump" || sv == "proto f:4 =GCDump"));
|
||||
else if (tt == LUA_TFUNCTION)
|
||||
CHECK((sv == "test" || sv == "unnamed:1 =GCDump" || sv == "foo:7 =GCDump" || sv == "f:4 =GCDump"));
|
||||
else if (tt == LUA_TTHREAD)
|
||||
CHECK(sv == "thread at unnamed:1 =GCDump");
|
||||
}
|
||||
|
||||
context.nodes[gco] = {gco, tt, memcat, size, name ? name : ""};
|
||||
},
|
||||
|
|
|
@ -234,8 +234,6 @@ TEST_CASE_FIXTURE(DifferFixture, "right_cyclic_table_left_table_property_wrong")
|
|||
|
||||
TEST_CASE_FIXTURE(DifferFixture, "equal_table_two_cyclic_tables_are_not_different")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function id<a>(x: a): a
|
||||
return x
|
||||
|
@ -1473,8 +1471,6 @@ TEST_CASE_FIXTURE(DifferFixtureWithBuiltins, "equal_metatable")
|
|||
|
||||
TEST_CASE_FIXTURE(DifferFixtureWithBuiltins, "metatable_normal")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local metaFoo = {
|
||||
metaBar = 5
|
||||
|
|
|
@ -26,13 +26,6 @@ using namespace Luau;
|
|||
LUAU_FASTINT(LuauParseErrorLimit)
|
||||
|
||||
LUAU_FASTFLAG(LuauBetterReverseDependencyTracking)
|
||||
LUAU_FASTFLAG(LuauAutocompleteUsesModuleForTypeCompatibility)
|
||||
LUAU_FASTFLAG(LuauBetterCursorInCommentDetection)
|
||||
LUAU_FASTFLAG(LuauAllFreeTypesHaveScopes)
|
||||
LUAU_FASTFLAG(LuauClonedTableAndFunctionTypesMustHaveScopes)
|
||||
LUAU_FASTFLAG(LuauDisableNewSolverAssertsInMixedMode)
|
||||
LUAU_FASTFLAG(LuauCloneTypeAliasBindings)
|
||||
LUAU_FASTFLAG(LuauDoNotClonePersistentBindings)
|
||||
LUAU_FASTFLAG(LuauBetterScopeSelection)
|
||||
LUAU_FASTFLAG(LuauBlockDiffFragmentSelection)
|
||||
LUAU_FASTFLAG(LuauFragmentAcMemoryLeak)
|
||||
|
@ -67,14 +60,8 @@ struct FragmentAutocompleteFixtureImpl : BaseType
|
|||
{
|
||||
static_assert(std::is_base_of_v<Fixture, BaseType>, "BaseType must be a descendant of Fixture");
|
||||
|
||||
ScopedFastFlag luauAllFreeTypesHaveScopes{FFlag::LuauAllFreeTypesHaveScopes, true};
|
||||
ScopedFastFlag luauClonedTableAndFunctionTypesMustHaveScopes{FFlag::LuauClonedTableAndFunctionTypesMustHaveScopes, true};
|
||||
ScopedFastFlag luauDisableNewSolverAssertsInMixedMode{FFlag::LuauDisableNewSolverAssertsInMixedMode, true};
|
||||
ScopedFastFlag luauCloneTypeAliasBindings{FFlag::LuauCloneTypeAliasBindings, true};
|
||||
ScopedFastFlag luauDoNotClonePersistentBindings{FFlag::LuauDoNotClonePersistentBindings, true};
|
||||
ScopedFastFlag luauBetterScopeSelection{FFlag::LuauBetterScopeSelection, true};
|
||||
ScopedFastFlag luauBlockDiffFragmentSelection{FFlag::LuauBlockDiffFragmentSelection, true};
|
||||
ScopedFastFlag luauAutocompleteUsesModuleForTypeCompatibility{FFlag::LuauAutocompleteUsesModuleForTypeCompatibility, true};
|
||||
ScopedFastFlag luauFragmentAcMemoryLeak{FFlag::LuauFragmentAcMemoryLeak, true};
|
||||
ScopedFastFlag luauGlobalVariableModuleIsolation{FFlag::LuauGlobalVariableModuleIsolation, true};
|
||||
ScopedFastFlag luauFragmentAutocompleteIfRecommendations{FFlag::LuauFragmentAutocompleteIfRecommendations, true};
|
||||
|
@ -2526,7 +2513,6 @@ l
|
|||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "do_not_recommend_results_in_multiline_comment")
|
||||
{
|
||||
ScopedFastFlag sff = {FFlag::LuauBetterCursorInCommentDetection, true};
|
||||
std::string source = R"(--[[
|
||||
)";
|
||||
std::string dest = R"(--[[
|
||||
|
@ -2547,7 +2533,6 @@ a
|
|||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "no_recs_for_comments_simple")
|
||||
{
|
||||
ScopedFastFlag sff = {FFlag::LuauBetterCursorInCommentDetection, true};
|
||||
const std::string source = R"(
|
||||
-- sel
|
||||
-- retur
|
||||
|
@ -2583,7 +2568,6 @@ bar
|
|||
baz
|
||||
]]
|
||||
)";
|
||||
ScopedFastFlag sff{FFlag::LuauBetterCursorInCommentDetection, true};
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
source,
|
||||
|
@ -2628,7 +2612,6 @@ baz
|
|||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "no_recs_for_comments")
|
||||
{
|
||||
ScopedFastFlag sff = {FFlag::LuauBetterCursorInCommentDetection, true};
|
||||
const std::string source = R"(
|
||||
-- sel
|
||||
-- retur
|
||||
|
@ -2708,7 +2691,6 @@ if x == 5
|
|||
local x = 5
|
||||
if x == 5 then -- a comment
|
||||
)";
|
||||
ScopedFastFlag sff = {FFlag::LuauBetterCursorInCommentDetection, true};
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
updated,
|
||||
|
@ -2964,7 +2946,6 @@ return module
|
|||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "ice_caused_by_mixed_mode_use")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauAutocompleteUsesModuleForTypeCompatibility, true};
|
||||
const std::string source =
|
||||
std::string("--[[\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 " +
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(DebugLuauForbidInternalTypes)
|
||||
LUAU_FASTFLAG(LuauTrackInferredFunctionTypeFromCall)
|
||||
|
||||
|
@ -226,7 +226,7 @@ TEST_CASE_FIXTURE(GeneralizationFixture, "('a) -> 'a")
|
|||
|
||||
TEST_CASE_FIXTURE(GeneralizationFixture, "(t1, (t1 <: 'b)) -> () where t1 = ('a <: (t1 <: 'b) & {number} & {number})")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauNonReentrantGeneralization3, true};
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization, true};
|
||||
|
||||
TableType tt;
|
||||
tt.indexer = TableIndexer{builtinTypes.numberType, builtinTypes.numberType};
|
||||
|
@ -260,7 +260,7 @@ TEST_CASE_FIXTURE(GeneralizationFixture, "(('a <: number | string)) -> string?")
|
|||
|
||||
TEST_CASE_FIXTURE(GeneralizationFixture, "(('a <: {'b})) -> ()")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauNonReentrantGeneralization3, true};
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization, true};
|
||||
|
||||
auto [aTy, aFree] = freshType();
|
||||
auto [bTy, bFree] = freshType();
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3);
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization);
|
||||
|
||||
TEST_SUITE_BEGIN("InferPolarity");
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "T where T = { m: <a>(a) -> T }")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauNonReentrantGeneralization3, true};
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization, true};
|
||||
|
||||
TypeArena arena;
|
||||
ScopePtr globalScope = std::make_shared<Scope>(builtinTypes->anyTypePack);
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LintRedundantNativeAttribute);
|
||||
LUAU_FASTFLAG(LuauDeprecatedAttribute);
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3);
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization);
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -1942,7 +1942,7 @@ print(foo:bar(2.0))
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "TableOperations")
|
||||
{
|
||||
// FIXME: For now this flag causes a stack overflow on Windows.
|
||||
ScopedFastFlag _{FFlag::LuauNonReentrantGeneralization3, false};
|
||||
ScopedFastFlag _{FFlag::LuauEagerGeneralization, false};
|
||||
|
||||
LintResult result = lint(R"(
|
||||
local t = {}
|
||||
|
|
|
@ -280,8 +280,6 @@ TEST_CASE_FIXTURE(Fixture, "clone_class")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "clone_free_types")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
TypeArena arena;
|
||||
TypeId freeTy = freshType(NotNull{&arena}, builtinTypes, nullptr);
|
||||
TypePackVar freeTp(FreeTypePack{TypeLevel{}});
|
||||
|
|
|
@ -14,8 +14,7 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTINT(LuauNormalizeIntersectionLimit)
|
||||
LUAU_FASTINT(LuauNormalizeUnionLimit)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauRefineWaitForBlockedTypesInTarget)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine)
|
||||
LUAU_FASTFLAG(LuauOptimizeFalsyAndTruthyIntersect)
|
||||
|
@ -1177,57 +1176,6 @@ end
|
|||
)");
|
||||
}
|
||||
|
||||
#if 0
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_limit_function_intersection_complexity")
|
||||
{
|
||||
ScopedFastInt luauTypeInferRecursionLimit{FInt::LuauTypeInferRecursionLimit, 80};
|
||||
ScopedFastInt luauNormalizeIntersectionLimit{FInt::LuauNormalizeIntersectionLimit, 50};
|
||||
ScopedFastInt luauNormalizeUnionLimit{FInt::LuauNormalizeUnionLimit, 20};
|
||||
|
||||
ScopedFastFlag _[] = {
|
||||
{FFlag::LuauClipVariadicAnysFromArgsToGenericFuncs2, true},
|
||||
{FFlag::DebugLuauGreedyGeneralization, true},
|
||||
{FFlag::LuauSubtypeGenericsAndNegations, true},
|
||||
{FFlag::LuauNoMoreInjectiveTypeFunctions, true}
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function _(_).readu32(l0)
|
||||
return ({[_(_(_))]=_,[_(if _ then _)]=_,n0=_,})[_],nil
|
||||
end
|
||||
_(_)[_(n32)] %= _(_(_))
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_propagate_normalization_failures")
|
||||
{
|
||||
ScopedFastInt luauNormalizeIntersectionLimit{FInt::LuauNormalizeIntersectionLimit, 50};
|
||||
ScopedFastInt luauNormalizeUnionLimit{FInt::LuauNormalizeUnionLimit, 20};
|
||||
|
||||
ScopedFastFlag _[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauOptimizeFalsyAndTruthyIntersect, true},
|
||||
{FFlag::LuauClipVariadicAnysFromArgsToGenericFuncs2, true},
|
||||
{FFlag::LuauSimplifyOutOfLine, true},
|
||||
{FFlag::LuauNonReentrantGeneralization3, false},
|
||||
{FFlag::DebugLuauGreedyGeneralization, true},
|
||||
{FFlag::LuauNoMoreInjectiveTypeFunctions, true},
|
||||
{FFlag::LuauSubtypeGenericsAndNegations, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function _(_,"").readu32(l0)
|
||||
return ({[_(_(_))]=_,[_(if _ then _,_())]=_,[""]=_,})[_],nil
|
||||
end
|
||||
_().readu32 %= _(_(_(_),_))
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERRORS(result);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_flatten_type_pack_cycle")
|
||||
{
|
||||
ScopedFastFlag sff[] = {{FFlag::LuauSolverV2, true}};
|
||||
|
@ -1258,7 +1206,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_union_type_pack_cycle")
|
|||
{FFlag::LuauNoMoreInjectiveTypeFunctions, true},
|
||||
{FFlag::LuauOptimizeFalsyAndTruthyIntersect, true},
|
||||
{FFlag::LuauClipVariadicAnysFromArgsToGenericFuncs2, true},
|
||||
{FFlag::DebugLuauGreedyGeneralization, true}
|
||||
{FFlag::LuauEagerGeneralization, true}
|
||||
};
|
||||
ScopedFastInt sfi{FInt::LuauTypeInferRecursionLimit, 0};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
LUAU_FASTFLAG(LuauStoreReturnTypesAsPackOnAst)
|
||||
LUAU_FASTFLAG(LuauParseStringIndexer)
|
||||
LUAU_FASTFLAG(LuauDeclareExternType)
|
||||
LUAU_FASTFLAG(LuauStoreCSTData2)
|
||||
LUAU_DYNAMIC_FASTFLAG(DebugLuauReportReturnTypeVariadicWithTypeSuffix)
|
||||
|
||||
// Clip with DebugLuauReportReturnTypeVariadicWithTypeSuffix
|
||||
|
@ -1260,8 +1261,6 @@ until false
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_nesting_based_end_detection_local_function")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
try
|
||||
{
|
||||
parse(R"(-- i am line 1
|
||||
|
@ -1295,8 +1294,6 @@ end
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_nesting_based_end_detection_failsafe_earlier")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
try
|
||||
{
|
||||
parse(R"(-- i am line 1
|
||||
|
@ -2902,6 +2899,8 @@ TEST_CASE_FIXTURE(Fixture, "function_start_locations_are_before_attributes")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "for_loop_with_single_var_has_comma_positions_of_size_zero")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
|
||||
ParseOptions parseOptions;
|
||||
parseOptions.storeCstData = true;
|
||||
|
||||
|
@ -3364,8 +3363,6 @@ TEST_CASE_FIXTURE(Fixture, "AstName_comparison")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_type_list_recovery")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
try
|
||||
{
|
||||
parse(R"(
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauSubtypeGenericsAndNegations)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -1647,4 +1648,19 @@ TEST_CASE_FIXTURE(SubtypeFixture, "substitute_a_generic_for_a_negation")
|
|||
CHECK(result.isSubtype);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "free_types_might_be_subtypes")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization, true};
|
||||
|
||||
TypeId argTy = arena.freshType(builtinTypes, moduleScope.get());
|
||||
FreeType* freeArg = getMutable<FreeType>(argTy);
|
||||
REQUIRE(freeArg);
|
||||
freeArg->lowerBound = arena.addType(SingletonType{StringSingleton{"five"}});
|
||||
freeArg->upperBound = builtinTypes->stringType;
|
||||
|
||||
SubtypingResult result = isSubtype(builtinTypes->stringType, argTy);
|
||||
CHECK(result.isSubtype);
|
||||
REQUIRE(1 == result.assumedConstraints.size());
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -322,8 +322,6 @@ n3 [label="TableType 3"];
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "free")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
Type type{TypeVariant{FreeType{TypeLevel{0, 0}, builtinTypes->neverType, builtinTypes->unknownType}}};
|
||||
ToDotOptions opts;
|
||||
opts.showPointers = false;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "Fixture.h"
|
||||
|
||||
#include "Luau/TypeChecker2.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "ScopedFlags.h"
|
||||
#include "doctest.h"
|
||||
|
||||
|
@ -14,6 +15,7 @@ using namespace Luau;
|
|||
LUAU_FASTFLAG(LuauRecursiveTypeParameterRestriction)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauAttributeSyntax)
|
||||
LUAU_FASTFLAG(LuauFixEmptyTypePackStringification)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
|
||||
TEST_SUITE_BEGIN("ToString");
|
||||
|
@ -492,6 +494,17 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_array_uses_array_syntax")
|
|||
CHECK_EQ("{string}", toString(Type{ttv}));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "the_empty_type_pack_should_be_parenthesized")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauFixEmptyTypePackStringification, true};
|
||||
|
||||
TypePackVar emptyTypePack{TypePack{}};
|
||||
CHECK_EQ(toString(&emptyTypePack), "()");
|
||||
|
||||
auto unitToUnit = Type{FunctionType{&emptyTypePack, &emptyTypePack}};
|
||||
CHECK_EQ(toString(&unitToUnit), "() -> ()");
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_packs_are_stringified_differently_from_generic_types")
|
||||
{
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauStoreCSTData2)
|
||||
LUAU_FASTFLAG(LuauStoreReturnTypesAsPackOnAst)
|
||||
LUAU_FASTFLAG(LuauStoreLocalAnnotationColonPositions)
|
||||
LUAU_FASTFLAG(LuauCSTForReturnTypeFunctionTail)
|
||||
|
||||
TEST_SUITE_BEGIN("TranspilerTests");
|
||||
|
||||
|
@ -47,6 +49,7 @@ TEST_CASE("string_literals_containing_utf8")
|
|||
|
||||
TEST_CASE("if_stmt_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string one = R"( if This then Once() end)";
|
||||
CHECK_EQ(one, transpile(one).code);
|
||||
|
||||
|
@ -95,15 +98,31 @@ TEST_CASE("elseif_chains_indent_sensibly")
|
|||
TEST_CASE("strips_type_annotations")
|
||||
{
|
||||
const std::string code = R"( local s: string= 'hello there' )";
|
||||
const std::string expected = R"( local s = 'hello there' )";
|
||||
CHECK_EQ(expected, transpile(code).code);
|
||||
if (FFlag::LuauStoreCSTData2)
|
||||
{
|
||||
const std::string expected = R"( local s = 'hello there' )";
|
||||
CHECK_EQ(expected, transpile(code).code);
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string expected = R"( local s = 'hello there' )";
|
||||
CHECK_EQ(expected, transpile(code).code);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("strips_type_assertion_expressions")
|
||||
{
|
||||
const std::string code = R"( local s= some_function() :: any+ something_else() :: number )";
|
||||
const std::string expected = R"( local s= some_function() + something_else() )";
|
||||
CHECK_EQ(expected, transpile(code).code);
|
||||
if (FFlag::LuauStoreCSTData2)
|
||||
{
|
||||
const std::string expected = R"( local s= some_function() + something_else() )";
|
||||
CHECK_EQ(expected, transpile(code).code);
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string expected = R"( local s= some_function() + something_else() )";
|
||||
CHECK_EQ(expected, transpile(code).code);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("function_taking_ellipsis")
|
||||
|
@ -130,6 +149,7 @@ TEST_CASE("for_loop")
|
|||
|
||||
TEST_CASE("for_loop_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string one = R"( for index = 1, 10 do call(index) end )";
|
||||
CHECK_EQ(one, transpile(one).code);
|
||||
|
||||
|
@ -154,6 +174,7 @@ TEST_CASE("for_in_loop")
|
|||
|
||||
TEST_CASE("for_in_loop_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string one = R"( for k, v in ipairs(x) do end )";
|
||||
CHECK_EQ(one, transpile(one).code);
|
||||
|
||||
|
@ -172,6 +193,7 @@ TEST_CASE("for_in_loop_spaces_around_tokens")
|
|||
|
||||
TEST_CASE("for_in_single_variable")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string one = R"( for key in pairs(x) do end )";
|
||||
CHECK_EQ(one, transpile(one).code);
|
||||
}
|
||||
|
@ -184,6 +206,7 @@ TEST_CASE("while_loop")
|
|||
|
||||
TEST_CASE("while_loop_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string one = R"( while f(x) do print() end )";
|
||||
CHECK_EQ(one, transpile(one).code);
|
||||
|
||||
|
@ -205,6 +228,7 @@ TEST_CASE("repeat_until_loop")
|
|||
|
||||
TEST_CASE("repeat_until_loop_condition_on_new_line")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"(
|
||||
repeat
|
||||
print()
|
||||
|
@ -236,6 +260,7 @@ TEST_CASE("local_assignment")
|
|||
|
||||
TEST_CASE("local_assignment_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string one = R"( local x = 1 )";
|
||||
CHECK_EQ(one, transpile(one).code);
|
||||
|
||||
|
@ -269,6 +294,7 @@ TEST_CASE("local_function")
|
|||
|
||||
TEST_CASE("local_function_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string one = R"( local function p(o, m, ...) end )";
|
||||
CHECK_EQ(one, transpile(one).code);
|
||||
|
||||
|
@ -287,6 +313,7 @@ TEST_CASE("function")
|
|||
|
||||
TEST_CASE("function_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string two = R"( function p(o, m, ...) end )";
|
||||
CHECK_EQ(two, transpile(two).code);
|
||||
|
||||
|
@ -315,6 +342,7 @@ TEST_CASE("function_spaces_around_tokens")
|
|||
TEST_CASE("function_with_types_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
{FFlag::LuauStoreReturnTypesAsPackOnAst, true},
|
||||
{FFlag::LuauStoreLocalAnnotationColonPositions, true},
|
||||
};
|
||||
|
@ -375,7 +403,7 @@ TEST_CASE("function_with_types_spaces_around_tokens")
|
|||
|
||||
TEST_CASE("returns_spaces_around_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string one = R"( return 1 )";
|
||||
CHECK_EQ(one, transpile(one).code);
|
||||
|
||||
|
@ -388,7 +416,7 @@ TEST_CASE("returns_spaces_around_tokens")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "type_alias_spaces_around_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"( type Foo = string )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -437,7 +465,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_spaces_around_tokens")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "type_alias_with_defaults_spaces_around_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"( type Foo<X = string, Z... = ...any> = string )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -498,7 +526,7 @@ TEST_CASE("table_literal_closing_brace_at_correct_position")
|
|||
|
||||
TEST_CASE("table_literal_with_semicolon_separators")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"(
|
||||
local t = { x = 1; y = 2 }
|
||||
)";
|
||||
|
@ -508,7 +536,7 @@ TEST_CASE("table_literal_with_semicolon_separators")
|
|||
|
||||
TEST_CASE("table_literal_with_trailing_separators")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"(
|
||||
local t = { x = 1, y = 2, }
|
||||
)";
|
||||
|
@ -518,7 +546,7 @@ TEST_CASE("table_literal_with_trailing_separators")
|
|||
|
||||
TEST_CASE("table_literal_with_spaces_around_separator")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"(
|
||||
local t = { x = 1 , y = 2 }
|
||||
)";
|
||||
|
@ -528,7 +556,7 @@ TEST_CASE("table_literal_with_spaces_around_separator")
|
|||
|
||||
TEST_CASE("table_literal_with_spaces_around_equals")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"(
|
||||
local t = { x = 1 }
|
||||
)";
|
||||
|
@ -538,7 +566,7 @@ TEST_CASE("table_literal_with_spaces_around_equals")
|
|||
|
||||
TEST_CASE("table_literal_multiline_with_indexers")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"(
|
||||
local t = {
|
||||
["my first value"] = "x";
|
||||
|
@ -566,7 +594,15 @@ TEST_CASE("spaces_between_keywords_even_if_it_pushes_the_line_estimation_off")
|
|||
// Luau::Parser doesn't exactly preserve the string representation of numbers in Lua, so we can find ourselves
|
||||
// falling out of sync with the original code. We need to push keywords out so that there's at least one space between them.
|
||||
const std::string code = R"( if math.abs(raySlope) < .01 then return 0 end )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
if (FFlag::LuauStoreCSTData2)
|
||||
{
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string expected = R"( if math.abs(raySlope) < 0.01 then return 0 end)";
|
||||
CHECK_EQ(expected, transpile(code).code);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("numbers")
|
||||
|
@ -578,26 +614,34 @@ TEST_CASE("numbers")
|
|||
TEST_CASE("infinity")
|
||||
{
|
||||
const std::string code = R"( local a = 1e500 local b = 1e400 )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
if (FFlag::LuauStoreCSTData2)
|
||||
{
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string expected = R"( local a = 1e500 local b = 1e500 )";
|
||||
CHECK_EQ(expected, transpile(code).code);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("numbers_with_separators")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( local a = 123_456_789 )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
||||
TEST_CASE("hexadecimal_numbers")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( local a = 0xFFFF )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
||||
TEST_CASE("binary_numbers")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( local a = 0b0101 )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
@ -610,28 +654,28 @@ TEST_CASE("single_quoted_strings")
|
|||
|
||||
TEST_CASE("double_quoted_strings")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( local a = "hello world" )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
||||
TEST_CASE("simple_interp_string")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( local a = `hello world` )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
||||
TEST_CASE("raw_strings")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( local a = [[ hello world ]] )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
||||
TEST_CASE("raw_strings_with_blocks")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( local a = [==[ hello world ]==] )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
@ -650,7 +694,7 @@ TEST_CASE("escaped_strings_2")
|
|||
|
||||
TEST_CASE("escaped_strings_newline")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"(
|
||||
print("foo \
|
||||
bar")
|
||||
|
@ -660,14 +704,14 @@ TEST_CASE("escaped_strings_newline")
|
|||
|
||||
TEST_CASE("escaped_strings_raw")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( local x = [=[\v<((do|load)file|require)\s*\(?['"]\zs[^'"]+\ze['"]]=] )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
||||
TEST_CASE("position_correctly_updated_when_writing_multiline_string")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"(
|
||||
call([[
|
||||
testing
|
||||
|
@ -713,56 +757,56 @@ TEST_CASE("function_call_parentheses_multiple_args_no_space")
|
|||
|
||||
TEST_CASE("function_call_parentheses_multiple_args_space_before_commas")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( call(arg1 ,arg3 ,arg3) )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
||||
TEST_CASE("function_call_spaces_before_parentheses")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( call () )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
||||
TEST_CASE("function_call_spaces_within_parentheses")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( call( ) )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
||||
TEST_CASE("function_call_string_double_quotes")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( call "string" )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
||||
TEST_CASE("function_call_string_single_quotes")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( call 'string' )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
||||
TEST_CASE("function_call_string_no_space")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( call'string' )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
||||
TEST_CASE("function_call_table_literal")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( call { x = 1 } )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
||||
TEST_CASE("function_call_table_literal_no_space")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( call{x=1} )";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
|
@ -807,7 +851,7 @@ TEST_CASE("emit_a_do_block_in_cases_of_potentially_ambiguous_syntax")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "parentheses_multiline")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"(
|
||||
local test = (
|
||||
x
|
||||
|
@ -819,6 +863,9 @@ local test = (
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "stmt_semicolon")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = R"( local test = 1; )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -828,6 +875,7 @@ TEST_CASE_FIXTURE(Fixture, "stmt_semicolon")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "do_block_ending_with_semicolon")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"(
|
||||
do
|
||||
return;
|
||||
|
@ -838,6 +886,9 @@ TEST_CASE_FIXTURE(Fixture, "do_block_ending_with_semicolon")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "if_stmt_semicolon")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = R"(
|
||||
if init then
|
||||
x = string.sub(x, utf8.offset(x, init));
|
||||
|
@ -848,6 +899,9 @@ TEST_CASE_FIXTURE(Fixture, "if_stmt_semicolon")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "if_stmt_semicolon_2")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = R"(
|
||||
if (t < 1) then return c/2*t*t + b end;
|
||||
)";
|
||||
|
@ -856,6 +910,9 @@ TEST_CASE_FIXTURE(Fixture, "if_stmt_semicolon_2")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "for_loop_stmt_semicolon")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = R"(
|
||||
for i,v in ... do
|
||||
end;
|
||||
|
@ -865,6 +922,9 @@ TEST_CASE_FIXTURE(Fixture, "for_loop_stmt_semicolon")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "while_do_semicolon")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = R"(
|
||||
while true do
|
||||
end;
|
||||
|
@ -874,6 +934,9 @@ TEST_CASE_FIXTURE(Fixture, "while_do_semicolon")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "function_definition_semicolon")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = R"(
|
||||
function foo()
|
||||
end;
|
||||
|
@ -951,7 +1014,16 @@ TEST_CASE("a_table_key_can_be_the_empty_string")
|
|||
TEST_CASE("always_emit_a_space_after_local_keyword")
|
||||
{
|
||||
std::string code = "do local aZZZZ = Workspace.P1.Shape local bZZZZ = Enum.PartType.Cylinder end";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
|
||||
if (FFlag::LuauStoreCSTData2)
|
||||
{
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string expected = "do local aZZZZ = Workspace.P1 .Shape local bZZZZ= Enum.PartType.Cylinder end";
|
||||
CHECK_EQ(expected, transpile(code).code);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "types_should_not_be_considered_cyclic_if_they_are_not_recursive")
|
||||
|
@ -988,13 +1060,23 @@ TEST_CASE_FIXTURE(Fixture, "type_lists_should_be_emitted_correctly")
|
|||
end
|
||||
)";
|
||||
|
||||
std::string expected = R"(
|
||||
std::string expected = FFlag::LuauStoreCSTData2 ? R"(
|
||||
local a:(a:string,b:number,...string)->(string,...number)=function(a:string,b:number,...:string): (string,...number)
|
||||
end
|
||||
|
||||
local b:(...string)->(...number)=function(...:string): ...number
|
||||
end
|
||||
|
||||
local c:()->()=function(): ()
|
||||
end
|
||||
)"
|
||||
: R"(
|
||||
local a:(string,number,...string)->(string,...number)=function(a:string,b:number,...:string): (string,...number)
|
||||
end
|
||||
|
||||
local b:(...string)->(...number)=function(...:string): ...number
|
||||
end
|
||||
|
||||
local c:()->()=function(): ()
|
||||
end
|
||||
)";
|
||||
|
@ -1034,7 +1116,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_type_assertion")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "type_assertion_spaces_around_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = "local a = 5 :: number";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -1051,7 +1133,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_if_then_else")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_if_then_else_multiple_conditions")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = "local a = if 1 then 2 elseif 3 then 4 else 5";
|
||||
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
|
@ -1059,7 +1141,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_if_then_else_multiple_conditions")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_if_then_else_multiple_conditions_2")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"(
|
||||
local x = if yes
|
||||
then nil
|
||||
|
@ -1075,7 +1157,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_if_then_else_multiple_conditions_2")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "if_then_else_spaces_around_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = "local a = if 1 then 2 else 3";
|
||||
CHECK_EQ(code, transpile(code).code);
|
||||
|
||||
|
@ -1112,7 +1194,7 @@ TEST_CASE_FIXTURE(Fixture, "if_then_else_spaces_around_tokens")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "if_then_else_spaces_between_else_if")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"(
|
||||
return
|
||||
if a then "was a" else
|
||||
|
@ -1140,7 +1222,7 @@ local a: Import.Type
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_type_reference_spaces_around_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"( local _: Foo.Type )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -1169,6 +1251,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_type_reference_spaces_around_tokens")
|
|||
TEST_CASE_FIXTURE(Fixture, "transpile_type_annotation_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
{FFlag::LuauStoreLocalAnnotationColonPositions, true},
|
||||
};
|
||||
std::string code = R"( local _: Type )";
|
||||
|
@ -1190,6 +1273,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_type_annotation_spaces_around_tokens")
|
|||
TEST_CASE_FIXTURE(Fixture, "transpile_for_loop_annotation_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
{FFlag::LuauStoreLocalAnnotationColonPositions, true},
|
||||
};
|
||||
std::string code = R"( for i: number = 1, 10 do end )";
|
||||
|
@ -1230,7 +1314,7 @@ local b: Packed<(number, string)>
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "type_packs_spaces_around_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"( type _ = Packed< T...> )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -1288,7 +1372,11 @@ TEST_CASE_FIXTURE(Fixture, "transpile_union_type_nested_2")
|
|||
TEST_CASE_FIXTURE(Fixture, "transpile_union_type_nested_3")
|
||||
{
|
||||
std::string code = "local a: nil | (string & number)";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
if (FFlag::LuauStoreCSTData2)
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
else
|
||||
CHECK_EQ("local a: (string & number)?", transpile(code, {}, true).code);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_intersection_type_nested")
|
||||
|
@ -1308,6 +1396,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_intersection_type_nested_2")
|
|||
TEST_CASE_FIXTURE(Fixture, "transpile_intersection_type_with_function")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
{FFlag::LuauStoreReturnTypesAsPackOnAst, true},
|
||||
};
|
||||
std::string code = "type FnB<U...> = () -> U... & T";
|
||||
|
@ -1317,6 +1406,9 @@ TEST_CASE_FIXTURE(Fixture, "transpile_intersection_type_with_function")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_leading_union_pipe")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = "local a: | string | number";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -1326,6 +1418,9 @@ TEST_CASE_FIXTURE(Fixture, "transpile_leading_union_pipe")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_union_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = "local a: string | number";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -1335,6 +1430,9 @@ TEST_CASE_FIXTURE(Fixture, "transpile_union_spaces_around_tokens")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_leading_intersection_ampersand")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = "local a: & string & number";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -1344,6 +1442,9 @@ TEST_CASE_FIXTURE(Fixture, "transpile_leading_intersection_ampersand")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_intersection_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = "local a: string & number";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -1353,6 +1454,9 @@ TEST_CASE_FIXTURE(Fixture, "transpile_intersection_spaces_around_tokens")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_mixed_union_intersection")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = "local a: string | (Foo & Bar)";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -1377,6 +1481,9 @@ TEST_CASE_FIXTURE(Fixture, "transpile_mixed_union_intersection")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_preserve_union_optional_style")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = "local a: string | nil";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -1408,7 +1515,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_varargs")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "index_name_spaces_around_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string one = "local _ = a.name";
|
||||
CHECK_EQ(one, transpile(one, {}, true).code);
|
||||
|
||||
|
@ -1421,7 +1528,7 @@ TEST_CASE_FIXTURE(Fixture, "index_name_spaces_around_tokens")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "index_name_ends_with_digit")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = "sparkles.Color = Color3.new()";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
}
|
||||
|
@ -1435,7 +1542,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_index_expr")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "index_expr_spaces_around_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string one = "local _ = a[2]";
|
||||
CHECK_EQ(one, transpile(one, {}, true).code);
|
||||
|
||||
|
@ -1479,7 +1586,7 @@ local _ = # e
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "binary_spaces_around_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"(
|
||||
local _ = 1+1
|
||||
local _ = 1 +1
|
||||
|
@ -1521,7 +1628,7 @@ a ..= ' - result'
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "compound_assignment_spaces_around_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string one = R"( a += 1 )";
|
||||
CHECK_EQ(one, transpile(one, {}, true).code);
|
||||
|
||||
|
@ -1538,7 +1645,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_assign_multiple")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_assign_spaces_around_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string one = "a = 1";
|
||||
CHECK_EQ(one, transpile(one).code);
|
||||
|
||||
|
@ -1574,7 +1681,11 @@ local f: <T,S...>(T, S...)->(number) = foo
|
|||
TEST_CASE_FIXTURE(Fixture, "transpile_union_reverse")
|
||||
{
|
||||
std::string code = "local a: nil | number";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
if (FFlag::LuauStoreCSTData2)
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
else
|
||||
CHECK_EQ("local a: number?", transpile(code, {}, true).code);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_for_in_multiple")
|
||||
|
@ -1689,6 +1800,9 @@ TEST_CASE_FIXTURE(Fixture, "transpile_for_in_multiple_types")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_string_interp")
|
||||
{
|
||||
ScopedFastFlag fflags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = R"( local _ = `hello {name}` )";
|
||||
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
@ -1696,6 +1810,9 @@ TEST_CASE_FIXTURE(Fixture, "transpile_string_interp")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_string_interp_multiline")
|
||||
{
|
||||
ScopedFastFlag fflags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = R"( local _ = `hello {
|
||||
name
|
||||
}!` )";
|
||||
|
@ -1705,6 +1822,9 @@ TEST_CASE_FIXTURE(Fixture, "transpile_string_interp_multiline")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_string_interp_on_new_line")
|
||||
{
|
||||
ScopedFastFlag fflags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = R"(
|
||||
error(
|
||||
`a {b} c`
|
||||
|
@ -1716,6 +1836,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_string_interp_on_new_line")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_string_interp_multiline_escape")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"( local _ = `hello \
|
||||
world!` )";
|
||||
|
||||
|
@ -1724,6 +1845,9 @@ TEST_CASE_FIXTURE(Fixture, "transpile_string_interp_multiline_escape")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_string_literal_escape")
|
||||
{
|
||||
ScopedFastFlag fflags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
std::string code = R"( local _ = ` bracket = \{, backtick = \` = {'ok'} ` )";
|
||||
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
@ -1738,6 +1862,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_type_functions")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_type_functions_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"( type function foo() end )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -1753,6 +1878,7 @@ TEST_CASE_FIXTURE(Fixture, "transpile_type_functions_spaces_around_tokens")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "transpile_typeof_spaces_around_tokens")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"( type X = typeof(x) )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -1777,14 +1903,14 @@ TEST_CASE("transpile_single_quoted_string_types")
|
|||
|
||||
TEST_CASE("transpile_double_quoted_string_types")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( type a = "hello world" )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
}
|
||||
|
||||
TEST_CASE("transpile_raw_string_types")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"( type a = [[ hello world ]] )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -1794,14 +1920,14 @@ TEST_CASE("transpile_raw_string_types")
|
|||
|
||||
TEST_CASE("transpile_escaped_string_types")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"( type a = "\\b\\t\\n\\\\" )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
}
|
||||
|
||||
TEST_CASE("transpile_type_table_semicolon_separators")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
const std::string code = R"(
|
||||
type Foo = {
|
||||
bar: number;
|
||||
|
@ -1813,7 +1939,7 @@ TEST_CASE("transpile_type_table_semicolon_separators")
|
|||
|
||||
TEST_CASE("transpile_type_table_access_modifiers")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"(
|
||||
type Foo = {
|
||||
read bar: number,
|
||||
|
@ -1834,7 +1960,7 @@ TEST_CASE("transpile_type_table_access_modifiers")
|
|||
|
||||
TEST_CASE("transpile_type_table_spaces_between_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"( type Foo = { bar: number, } )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
|
@ -1877,7 +2003,7 @@ TEST_CASE("transpile_type_table_spaces_between_tokens")
|
|||
|
||||
TEST_CASE("transpile_type_table_preserve_original_indexer_style")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"(
|
||||
type Foo = {
|
||||
[number]: string
|
||||
|
@ -1893,7 +2019,7 @@ TEST_CASE("transpile_type_table_preserve_original_indexer_style")
|
|||
|
||||
TEST_CASE("transpile_type_table_preserve_indexer_location")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"(
|
||||
type Foo = {
|
||||
[number]: string,
|
||||
|
@ -1922,7 +2048,7 @@ TEST_CASE("transpile_type_table_preserve_indexer_location")
|
|||
|
||||
TEST_CASE("transpile_type_table_preserve_property_definition_style")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"(
|
||||
type Foo = {
|
||||
["$$typeof1"]: string,
|
||||
|
@ -1934,7 +2060,7 @@ TEST_CASE("transpile_type_table_preserve_property_definition_style")
|
|||
|
||||
TEST_CASE("transpile_type_table_string_properties_spaces_between_tokens")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"(
|
||||
type Foo = {
|
||||
[ "$$typeof1"]: string,
|
||||
|
@ -1946,6 +2072,9 @@ TEST_CASE("transpile_type_table_string_properties_spaces_between_tokens")
|
|||
|
||||
TEST_CASE("transpile_types_preserve_parentheses_style")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
};
|
||||
|
||||
std::string code = R"( type Foo = number )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
@ -1985,6 +2114,7 @@ end
|
|||
TEST_CASE("transpile_type_function_unnamed_arguments")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
{FFlag::LuauStoreReturnTypesAsPackOnAst, true},
|
||||
};
|
||||
std::string code = R"( type Foo = () -> () )";
|
||||
|
@ -2021,6 +2151,7 @@ TEST_CASE("transpile_type_function_unnamed_arguments")
|
|||
TEST_CASE("transpile_type_function_named_arguments")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
{FFlag::LuauStoreReturnTypesAsPackOnAst, true},
|
||||
};
|
||||
std::string code = R"( type Foo = (x: string) -> () )";
|
||||
|
@ -2051,6 +2182,7 @@ TEST_CASE("transpile_type_function_named_arguments")
|
|||
TEST_CASE("transpile_type_function_generics")
|
||||
{
|
||||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
{FFlag::LuauStoreReturnTypesAsPackOnAst, true},
|
||||
};
|
||||
std::string code = R"( type Foo = <X, Y, Z...>() -> () )";
|
||||
|
@ -2087,6 +2219,7 @@ TEST_CASE("transpile_type_function_generics")
|
|||
TEST_CASE("transpile_type_function_return_types")
|
||||
{
|
||||
ScopedFastFlag fflags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
{FFlag::LuauStoreReturnTypesAsPackOnAst, true},
|
||||
};
|
||||
std::string code = R"( type Foo = () -> () )";
|
||||
|
@ -2132,6 +2265,23 @@ TEST_CASE("transpile_type_function_return_types")
|
|||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
}
|
||||
|
||||
TEST_CASE("transpile_chained_function_types")
|
||||
{
|
||||
ScopedFastFlag fflags[] = {
|
||||
{FFlag::LuauStoreCSTData2, true},
|
||||
{FFlag::LuauStoreReturnTypesAsPackOnAst, true},
|
||||
{FFlag::LuauCSTForReturnTypeFunctionTail, true},
|
||||
};
|
||||
std::string code = R"( type Foo = () -> () -> () )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
code = R"( type Foo = () -> () -> () )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
|
||||
code = R"( type Foo = () -> () -> () )";
|
||||
CHECK_EQ(code, transpile(code, {}, true).code);
|
||||
}
|
||||
|
||||
TEST_CASE("fuzzer_nil_optional")
|
||||
{
|
||||
const std::string code = R"( local x: nil? )";
|
||||
|
@ -2140,7 +2290,7 @@ TEST_CASE("fuzzer_nil_optional")
|
|||
|
||||
TEST_CASE("transpile_function_attributes")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauStoreCSTData2, true};
|
||||
std::string code = R"(
|
||||
@native
|
||||
function foo()
|
||||
|
|
|
@ -14,7 +14,7 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeFamilyApplicationCartesianProductLimit)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauHasPropProperBlock)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
|
@ -1725,7 +1725,7 @@ struct TFFixture
|
|||
TypeFunctionRuntime runtime{NotNull{&ice}, NotNull{&limits}};
|
||||
|
||||
const ScopedFastFlag sff[1] = {
|
||||
{FFlag::DebugLuauGreedyGeneralization, true},
|
||||
{FFlag::LuauEagerGeneralization, true},
|
||||
};
|
||||
|
||||
BuiltinTypeFunctions builtinTypeFunctions;
|
||||
|
|
|
@ -9,6 +9,7 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
|
||||
TEST_SUITE_BEGIN("UserDefinedTypeFunctionTests");
|
||||
|
@ -1986,13 +1987,20 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_singleton_equality_bool")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
// FIXME: CLI-151985
|
||||
// This test breaks because we can't see that eq<type?, b> is already fully reduced.
|
||||
return;
|
||||
}
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function compare(arg)
|
||||
return types.singleton(types.singleton(false) == arg)
|
||||
end
|
||||
|
||||
local function ok(idx: compare<false>): true return idx end
|
||||
local function ok(idx: compare<true>): false return idx end
|
||||
local function ok1(idx: compare<false>): true return idx end
|
||||
local function ok2(idx: compare<true>): false return idx end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
@ -2002,6 +2010,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_singleton_equality_string")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
// FIXME: CLI-151985
|
||||
// This test breaks because we can't see that eq<type?, b> is already fully reduced.
|
||||
return;
|
||||
}
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function compare(arg)
|
||||
return types.singleton(types.singleton("") == arg)
|
||||
|
|
|
@ -12,7 +12,7 @@ using namespace Luau;
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauRetainDefinitionAliasLocations)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictVisitTypes2)
|
||||
LUAU_FASTFLAG(LuauGuardAgainstMalformedTypeAliasExpansion)
|
||||
LUAU_FASTFLAG(LuauGuardAgainstMalformedTypeAliasExpansion2)
|
||||
LUAU_FASTFLAG(LuauSkipMalformedTypeAliases)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
|
||||
|
@ -355,8 +355,6 @@ TEST_CASE_FIXTURE(Fixture, "stringify_type_alias_of_recursive_template_table_typ
|
|||
// Check that recursive intersection type doesn't generate an OOM
|
||||
TEST_CASE_FIXTURE(Fixture, "cli_38393_recursive_intersection_oom")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function _(l0:(t0)&((t0)&(((t0)&((t0)->()))->(typeof(_),typeof(# _)))),l39,...):any
|
||||
end
|
||||
|
@ -970,9 +968,6 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_locations")
|
|||
*/
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "dont_lose_track_of_PendingExpansionTypes_after_substitution")
|
||||
{
|
||||
// CLI-114134 - We need egraphs to properly simplify these types.
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
fileResolver.source["game/ReactCurrentDispatcher"] = R"(
|
||||
export type BasicStateAction<S> = ((S) -> S) | S
|
||||
export type Dispatch<A> = (A) -> ()
|
||||
|
@ -1258,7 +1253,7 @@ TEST_CASE_FIXTURE(Fixture, "exported_type_function_location_is_accessible_on_mod
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "fuzzer_cursed_type_aliases")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauGuardAgainstMalformedTypeAliasExpansion, true};
|
||||
ScopedFastFlag _{FFlag::LuauGuardAgainstMalformedTypeAliasExpansion2, true};
|
||||
|
||||
// This used to crash under the new solver: we would like this to continue
|
||||
// to not crash.
|
||||
|
@ -1298,5 +1293,16 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_dont_crash_on_duplicate_with_typeof")
|
|||
CHECK(get<DuplicateTypeDefinition>(result.errors[0]));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "fuzzer_more_cursed_aliases")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauGuardAgainstMalformedTypeAliasExpansion2, true};
|
||||
|
||||
LUAU_REQUIRE_ERRORS(check(R"(
|
||||
export type t138 = t0<t138>
|
||||
export type t0<t0,t10,t10,t109> = t0
|
||||
)"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -11,7 +11,7 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauTableCloneClonesType3)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
|
||||
TEST_SUITE_BEGIN("BuiltinTests");
|
||||
|
@ -460,7 +460,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_pack_reduce")
|
|||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
if (FFlag::LuauSolverV2 && FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauEagerGeneralization)
|
||||
CHECK("{ [number]: string | string | string, n: number }" == toString(requireType("t")));
|
||||
else if (FFlag::LuauSolverV2)
|
||||
CHECK_EQ("{ [number]: string, n: number }", toString(requireType("t")));
|
||||
|
|
|
@ -129,8 +129,6 @@ TEST_CASE_FIXTURE(ExternTypeFixture, "we_can_infer_that_a_parameter_must_be_a_pa
|
|||
|
||||
TEST_CASE_FIXTURE(ExternTypeFixture, "we_can_report_when_someone_is_trying_to_use_a_table_rather_than_a_class")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function makeClone(o)
|
||||
return BaseClass.Clone(o)
|
||||
|
@ -472,9 +470,6 @@ Type 'number' could not be converted into 'string')";
|
|||
|
||||
TEST_CASE_FIXTURE(ExternTypeFixture, "class_type_mismatch_with_name_conflict")
|
||||
{
|
||||
// CLI-116433
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local i = ChildClass.New()
|
||||
type ChildClass = { x: number }
|
||||
|
|
|
@ -22,7 +22,7 @@ LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTINT(LuauTarjanChildLimit)
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
LUAU_FASTFLAG(LuauHasPropProperBlock)
|
||||
LUAU_FASTFLAG(LuauOptimizeFalsyAndTruthyIntersect)
|
||||
|
@ -1038,9 +1038,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "calling_function_with_anytypepack_doesnt_lea
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "too_many_return_values")
|
||||
{
|
||||
// FIXME: CLI-116157 variadic and generic type packs seem to be interacting incorrectly.
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
||||
|
@ -1472,9 +1469,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "variadic_any_is_compatible_with_a_generic_Ty
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "infer_anonymous_function_arguments_outside_call")
|
||||
{
|
||||
// FIXME: CLI-116133 bidirectional type inference needs to push expected types in for higher-order function calls
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Table = { x: number, y: number }
|
||||
local f: (Table) -> number = function(t) return t.x + t.y end
|
||||
|
@ -1694,7 +1688,7 @@ t.f = function(x)
|
|||
end
|
||||
)");
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauEagerGeneralization && FFlag::LuauSolverV2)
|
||||
{
|
||||
// FIXME CLI-151985
|
||||
LUAU_CHECK_ERROR_COUNT(3, result);
|
||||
|
@ -1779,7 +1773,7 @@ t.f = function(x)
|
|||
end
|
||||
)");
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauEagerGeneralization && FFlag::LuauSolverV2)
|
||||
{
|
||||
// FIXME CLI-151985
|
||||
LUAU_CHECK_ERROR_COUNT(2, result);
|
||||
|
@ -1981,10 +1975,15 @@ TEST_CASE_FIXTURE(Fixture, "dont_infer_parameter_types_for_functions_from_their_
|
|||
|
||||
CHECK_EQ("<a>(a) -> a", toString(requireType("f")));
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauEagerGeneralization && FFlag::LuauSolverV2)
|
||||
{
|
||||
LUAU_CHECK_NO_ERRORS(result);
|
||||
CHECK("<a>({ read p: { read q: a } }) -> (a & ~(false?))?" == toString(requireType("g")));
|
||||
}
|
||||
else if (FFlag::LuauSolverV2)
|
||||
{
|
||||
// FIXME CLI-143852: Depends on interleaving generalization and type function reduction.
|
||||
LUAU_REQUIRE_ERRORS(result);
|
||||
LUAU_CHECK_ERRORS(result);
|
||||
CHECK_EQ("({ read p: unknown }) -> (*error-type* | ~(false?))?", toString(requireType("g")));
|
||||
}
|
||||
else
|
||||
|
@ -2941,7 +2940,7 @@ TEST_CASE_FIXTURE(Fixture, "unifier_should_not_bind_free_types")
|
|||
{
|
||||
// The new solver should ideally be able to do better here, but this is no worse than the old solver.
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
auto tm1 = get<TypeMismatch>(result.errors[0]);
|
||||
|
|
|
@ -334,9 +334,6 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed_indirect")
|
||||
{
|
||||
// CLI-116476 Subtyping between type alias and an equivalent but not named type isn't working.
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type X = { x: (number) -> number }
|
||||
type Y = { y: (string) -> string }
|
||||
|
|
|
@ -325,9 +325,6 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_error")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "for_in_loop_on_non_function")
|
||||
{
|
||||
// We report a spuriouus duplicate error here.
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local bad_iter = 5
|
||||
|
||||
|
@ -1130,7 +1127,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dcr_iteration_on_never_gives_never")
|
|||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
CHECK("nil" == toString(requireType("ans")));
|
||||
CHECK("nil" == toString(requireType("ans")));
|
||||
else
|
||||
CHECK(toString(requireType("ans")) == "never");
|
||||
}
|
||||
|
@ -1404,7 +1401,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1413")
|
|||
local bar = foo - foo + foo
|
||||
foo = bar
|
||||
end
|
||||
end
|
||||
end
|
||||
)"));
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauAddCallConstraintForIterableFunctions)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauOptimizeFalsyAndTruthyIntersect)
|
||||
LUAU_FASTFLAG(LuauClipVariadicAnysFromArgsToGenericFuncs2)
|
||||
|
||||
|
@ -787,7 +787,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "leaky_generics")
|
|||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
CHECK_EQ("(unknown) -> unknown", toString(requireTypeAtPosition({13, 23})));
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferOperators");
|
||||
|
||||
|
@ -29,7 +29,7 @@ TEST_CASE_FIXTURE(Fixture, "or_joins_types")
|
|||
)");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
// FIXME: Regression
|
||||
CHECK("(string & ~(false?)) | number" == toString(*requireType("s")));
|
||||
|
@ -51,7 +51,7 @@ TEST_CASE_FIXTURE(Fixture, "or_joins_types_with_no_extras")
|
|||
)");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
// FIXME: Regression.
|
||||
CHECK("(string & ~(false?)) | number" == toString(*requireType("s")));
|
||||
|
@ -72,7 +72,7 @@ TEST_CASE_FIXTURE(Fixture, "or_joins_types_with_no_superfluous_union")
|
|||
)");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
// FIXME: Regression
|
||||
CHECK("(string & ~(false?)) | string" == toString(requireType("s")));
|
||||
|
@ -634,7 +634,20 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus_error")
|
|||
local a = -foo
|
||||
)");
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauEagerGeneralization && FFlag::LuauSolverV2)
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
CHECK("string" == toString(requireType("a")));
|
||||
|
||||
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
|
||||
REQUIRE(tm);
|
||||
|
||||
// FIXME: This error is a bit weird.
|
||||
CHECK("({ @metatable { __unm: (boolean) -> string }, { value: number } }) -> string" == toString(tm->wantedType, {true}));
|
||||
CHECK("(boolean) -> string" == toString(tm->givenType));
|
||||
}
|
||||
else if (FFlag::LuauSolverV2)
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauStoreCSTData2)
|
||||
LUAU_FASTINT(LuauNormalizeCacheLimit)
|
||||
LUAU_FASTINT(LuauTarjanChildLimit)
|
||||
LUAU_FASTINT(LuauTypeInferIterationLimit)
|
||||
|
@ -48,7 +49,7 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_inference_incomplete")
|
|||
end
|
||||
)";
|
||||
|
||||
const std::string expected = R"(
|
||||
const std::string expected = FFlag::LuauStoreCSTData2 ? R"(
|
||||
function f(a:{fn:()->(a,b...)}): ()
|
||||
if type(a) == 'boolean' then
|
||||
local a1:boolean=a
|
||||
|
@ -56,9 +57,18 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_inference_incomplete")
|
|||
local a2:{fn:()->(a,b...)}=a
|
||||
end
|
||||
end
|
||||
)"
|
||||
: R"(
|
||||
function f(a:{fn:()->(a,b...)}): ()
|
||||
if type(a) == 'boolean'then
|
||||
local a1:boolean=a
|
||||
elseif a.fn()then
|
||||
local a2:{fn:()->(a,b...)}=a
|
||||
end
|
||||
end
|
||||
)";
|
||||
|
||||
const std::string expectedWithNewSolver = R"(
|
||||
const std::string expectedWithNewSolver = FFlag::LuauStoreCSTData2 ? R"(
|
||||
function f(a:{fn:()->(unknown,...unknown)}): ()
|
||||
if type(a) == 'boolean' then
|
||||
local a1:{fn:()->(unknown,...unknown)}&boolean=a
|
||||
|
@ -66,9 +76,18 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_inference_incomplete")
|
|||
local a2:{fn:()->(unknown,...unknown)}&(class|function|nil|number|string|thread|buffer|table)=a
|
||||
end
|
||||
end
|
||||
)"
|
||||
: R"(
|
||||
function f(a:{fn:()->(unknown,...unknown)}): ()
|
||||
if type(a) == 'boolean'then
|
||||
local a1:{fn:()->(unknown,...unknown)}&boolean=a
|
||||
elseif a.fn()then
|
||||
local a2:{fn:()->(unknown,...unknown)}&(class|function|nil|number|string|thread|buffer|table)=a
|
||||
end
|
||||
end
|
||||
)";
|
||||
|
||||
const std::string expectedWithEqSat = R"(
|
||||
const std::string expectedWithEqSat = FFlag::LuauStoreCSTData2 ? R"(
|
||||
function f(a:{fn:()->(unknown,...unknown)}): ()
|
||||
if type(a) == 'boolean' then
|
||||
local a1:{fn:()->(unknown,...unknown)}&boolean=a
|
||||
|
@ -76,6 +95,15 @@ TEST_CASE_FIXTURE(Fixture, "typeguard_inference_incomplete")
|
|||
local a2:{fn:()->(unknown,...unknown)}&negate<boolean>=a
|
||||
end
|
||||
end
|
||||
)"
|
||||
: R"(
|
||||
function f(a:{fn:()->(unknown,...unknown)}): ()
|
||||
if type(a) == 'boolean'then
|
||||
local a1:{fn:()->(unknown,...unknown)}&boolean=a
|
||||
elseif a.fn()then
|
||||
local a2:{fn:()->(unknown,...unknown)}&negate<boolean>=a
|
||||
end
|
||||
end
|
||||
)";
|
||||
|
||||
if (FFlag::LuauSolverV2 && !FFlag::DebugLuauEqSatSimplification)
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauFunctionCallsAreNotNilable)
|
||||
LUAU_FASTFLAG(LuauWeakNilRefinementType)
|
||||
LUAU_FASTFLAG(LuauAddCallConstraintForIterableFunctions)
|
||||
LUAU_FASTFLAG(LuauSimplificationTableExternType)
|
||||
LUAU_FASTFLAG(LuauBetterCannotCallFunctionPrimitive)
|
||||
LUAU_FASTFLAG(LuauTypeCheckerStricterIndexCheck)
|
||||
LUAU_FASTFLAG(LuauAvoidDoubleNegation)
|
||||
|
||||
using namespace Luau;
|
||||
|
@ -108,6 +110,13 @@ struct RefinementExternTypeFixture : BuiltinsFixture
|
|||
{"IsA", Property{isA}},
|
||||
};
|
||||
|
||||
TypeId scriptConnection = arena.addType(ExternType("ExternScriptConnection", {}, inst, std::nullopt, {}, nullptr, "Test", {}));
|
||||
TypePackId disconnectArgs = arena.addTypePack({scriptConnection});
|
||||
TypeId disconnect = arena.addType(FunctionType{disconnectArgs, builtinTypes->emptyTypePack});
|
||||
getMutable<ExternType>(scriptConnection)->props = {
|
||||
{"Disconnect", Property{disconnect}},
|
||||
};
|
||||
|
||||
TypeId folder = frontend.globals.globalTypes.addType(ExternType{"Folder", {}, inst, std::nullopt, {}, nullptr, "Test", {}});
|
||||
TypeId part = frontend.globals.globalTypes.addType(ExternType{"Part", {}, inst, std::nullopt, {}, nullptr, "Test", {}});
|
||||
getMutable<ExternType>(part)->props = {
|
||||
|
@ -123,6 +132,7 @@ struct RefinementExternTypeFixture : BuiltinsFixture
|
|||
|
||||
frontend.globals.globalScope->exportedTypeBindings["Vector3"] = TypeFun{{}, vec3};
|
||||
frontend.globals.globalScope->exportedTypeBindings["Instance"] = TypeFun{{}, inst};
|
||||
frontend.globals.globalScope->exportedTypeBindings["ExternScriptConnection"] = TypeFun{{}, scriptConnection};
|
||||
frontend.globals.globalScope->exportedTypeBindings["Folder"] = TypeFun{{}, folder};
|
||||
frontend.globals.globalScope->exportedTypeBindings["Part"] = TypeFun{{}, part};
|
||||
frontend.globals.globalScope->exportedTypeBindings["WeldConstraint"] = TypeFun{{}, weldConstraint};
|
||||
|
@ -760,7 +770,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "nonoptional_type_can_narrow_to_nil_if_sense_
|
|||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
CHECK("nil & string & unknown & unknown" == toString(requireTypeAtPosition({4, 24}))); // type(v) == "nil"
|
||||
CHECK("string & unknown & unknown & ~nil" == toString(requireTypeAtPosition({6, 24}))); // type(v) ~= "nil"
|
||||
|
@ -2504,7 +2514,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "remove_recursive_upper_bound_when_generalizi
|
|||
end
|
||||
)"));
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
CHECK_EQ("nil & string & unknown", toString(requireTypeAtPosition({4, 24})));
|
||||
else
|
||||
CHECK_EQ("nil", toString(requireTypeAtPosition({4, 24})));
|
||||
|
@ -2648,5 +2658,77 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1451")
|
|||
)"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(RefinementExternTypeFixture, "cannot_call_a_function")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Disconnectable = {
|
||||
Disconnect: (self: Disconnectable) -> (...any);
|
||||
} | {
|
||||
disconnect: (self: Disconnectable) -> (...any)
|
||||
} | ExternScriptConnection
|
||||
|
||||
local x: Disconnectable = workspace.ChildAdded:Connect(function()
|
||||
print("child added")
|
||||
end)
|
||||
|
||||
if type(x.Disconnect) == "function" then
|
||||
x:Disconnect()
|
||||
end
|
||||
)");
|
||||
|
||||
if (FFlag::LuauTypeCheckerStricterIndexCheck)
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
|
||||
CHECK_EQ(toString(result.errors[0]), "Key 'Disconnect' is missing from 't2 where t1 = ExternScriptConnection | t2 | { Disconnect: (t1) -> (...any) } ; t2 = { disconnect: (t1) -> (...any) }' in the type 't1 where t1 = ExternScriptConnection | { Disconnect: (t1) -> (...any) } | { disconnect: (t1) -> (...any) }'");
|
||||
|
||||
if (FFlag::LuauBetterCannotCallFunctionPrimitive)
|
||||
CHECK_EQ(toString(result.errors[1]), "The type function is not precise enough for us to determine the appropriate result type of this call.");
|
||||
else
|
||||
CHECK_EQ(toString(result.errors[1]), "Cannot call a value of type function");
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
if (FFlag::LuauBetterCannotCallFunctionPrimitive)
|
||||
CHECK_EQ(toString(result.errors[0]), "The type function is not precise enough for us to determine the appropriate result type of this call.");
|
||||
else
|
||||
CHECK_EQ(toString(result.errors[0]), "Cannot call a value of type function");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1835")
|
||||
{
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
--!strict
|
||||
local t: {name: string}? = nil
|
||||
|
||||
function f()
|
||||
local name = if t then t.name else "name"
|
||||
end
|
||||
)"));
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
--!strict
|
||||
local t: {name: string}? = nil
|
||||
|
||||
function f()
|
||||
if t then end
|
||||
local name = if t then t.name else "name"
|
||||
end
|
||||
)"));
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local t: {name: string}? = nil
|
||||
if t then end
|
||||
print(t.name)
|
||||
local name = if t then t.name else "name"
|
||||
)");
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK(get<OptionalValueAccess>(result.errors[0]));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -21,8 +21,8 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauFixIndexerSubtypingOrdering)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(DebugLuauAssertOnForcedConstraint)
|
||||
LUAU_FASTFLAG(LuauBidirectionalInferenceElideAssert)
|
||||
LUAU_FASTFLAG(LuauOptimizeFalsyAndTruthyIntersect)
|
||||
|
@ -30,6 +30,11 @@ LUAU_FASTFLAG(LuauTypeCheckerStricterIndexCheck)
|
|||
LUAU_FASTFLAG(LuauReportSubtypingErrors)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAG(LuauDisablePrimitiveInferenceInLargeTables)
|
||||
LUAU_FASTINT(LuauPrimitiveInferenceInTableLimit)
|
||||
LUAU_FASTFLAG(LuauSubtypeGenericsAndNegations)
|
||||
LUAU_FASTFLAG(LuauNoMoreInjectiveTypeFunctions)
|
||||
|
||||
TEST_SUITE_BEGIN("TableTests");
|
||||
|
||||
|
@ -594,9 +599,6 @@ TEST_CASE_FIXTURE(Fixture, "okay_to_add_property_to_unsealed_tables_by_assignmen
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "okay_to_add_property_to_unsealed_tables_by_function_call")
|
||||
{
|
||||
// CLI-114873
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
function get(x) return x.opts["MYOPT"] end
|
||||
|
@ -700,7 +702,7 @@ TEST_CASE_FIXTURE(Fixture, "indexers_get_quantified_too")
|
|||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauNonReentrantGeneralization3)
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauEagerGeneralization)
|
||||
CHECK("<a>({a}) -> ()" == toString(requireType("swap")));
|
||||
else if (FFlag::LuauSolverV2)
|
||||
CHECK("({unknown}) -> ()" == toString(requireType("swap")));
|
||||
|
@ -1153,8 +1155,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "meta_add_inferred")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "meta_add_both_ways")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type VectorMt = { __add: (Vector, number) -> Vector }
|
||||
local vectorMt: VectorMt
|
||||
|
@ -2210,7 +2210,6 @@ local Test: {Table} = {
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "common_table_element_general")
|
||||
{
|
||||
// CLI-115275 - Bidirectional inference does not always propagate indexer types into the expression
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -2380,7 +2379,7 @@ TEST_CASE_FIXTURE(Fixture, "invariant_table_properties_means_instantiating_table
|
|||
local c : string = t.m("hi")
|
||||
)");
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauEagerGeneralization && FFlag::LuauSolverV2)
|
||||
{
|
||||
// FIXME CLI-151985
|
||||
LUAU_CHECK_ERROR_COUNT(2, result);
|
||||
|
@ -2651,7 +2650,6 @@ Type 'number' could not be converted into 'string' in an invariant context)";
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "explicitly_typed_table")
|
||||
{
|
||||
// Table properties like HasSuper.p must be invariant. The new solver rightly rejects this program.
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -2702,9 +2700,6 @@ Table type '{ x: number, y: number }' not compatible with type 'Super' because t
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "explicitly_typed_table_with_indexer")
|
||||
{
|
||||
// CLI-114791 Bidirectional inference should be able to cause the inference engine to forget that a table literal has some property
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
type Super = { x : number }
|
||||
|
@ -3752,7 +3747,12 @@ TEST_CASE_FIXTURE(Fixture, "scalar_is_a_subtype_of_a_compatible_polymorphic_shap
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "scalar_is_not_a_subtype_of_a_compatible_polymorphic_shape_type")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauNonReentrantGeneralization3, true}, {FFlag::LuauReportSubtypingErrors, true}};
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauReportSubtypingErrors, true},
|
||||
{FFlag::LuauEagerGeneralization, true},
|
||||
{FFlag::LuauSubtypeGenericsAndNegations, true},
|
||||
{FFlag::LuauNoMoreInjectiveTypeFunctions, true}
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function f(s)
|
||||
|
@ -4412,7 +4412,7 @@ TEST_CASE_FIXTURE(Fixture, "read_and_write_only_table_properties_are_unsupported
|
|||
CHECK(Location{{5, 18}, {5, 23}} == result.errors[3].location);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "read_ond_write_only_indexers_are_unsupported")
|
||||
TEST_CASE_FIXTURE(Fixture, "read_and_write_only_indexers_are_unsupported")
|
||||
{
|
||||
CheckResult result = check(R"(
|
||||
type T = {read [string]: number}
|
||||
|
@ -4442,6 +4442,22 @@ TEST_CASE_FIXTURE(Fixture, "infer_write_property")
|
|||
CHECK("({ y: number }) -> ()" == toString(requireType("f")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "new_solver_supports_read_write_properties")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag sff2{FFlag::LuauEnableWriteOnlyProperties, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type W = {read x: number}
|
||||
type X = {write x: boolean}
|
||||
|
||||
type Y = {read ["prop"]: boolean}
|
||||
type Z = {write ["prop"]: string}
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "table_subtyping_error_suppression")
|
||||
{
|
||||
CheckResult result = check(R"(
|
||||
|
@ -4495,6 +4511,59 @@ TEST_CASE_FIXTURE(Fixture, "write_to_read_only_property")
|
|||
CHECK(PropertyAccessViolation::CannotWrite == pav->context);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "write_to_write_only_property")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag writeOnly{FFlag::LuauEnableWriteOnlyProperties, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(t: {write x: number})
|
||||
t.x = 5
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "bidirectional_typechecking_with_write_only_property")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag writeOnly{FFlag::LuauEnableWriteOnlyProperties, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(t: {write x: number})
|
||||
t.x = 5
|
||||
end
|
||||
|
||||
f({ x = 2 })
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "read_from_write_only_property")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag writeOnly{FFlag::LuauEnableWriteOnlyProperties, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(t: {write x: number})
|
||||
local foo = t.x
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
CHECK("Property x of table '{ write x: number }' is write-only" == toString(result.errors[0]));
|
||||
|
||||
PropertyAccessViolation* pav = get<PropertyAccessViolation>(result.errors[0]);
|
||||
REQUIRE(pav);
|
||||
|
||||
CHECK("{ write x: number }" == toString(pav->table, {true}));
|
||||
CHECK("x" == pav->key);
|
||||
CHECK(PropertyAccessViolation::CannotRead == pav->context);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "write_to_unusually_named_read_only_property")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
@ -4510,7 +4579,7 @@ TEST_CASE_FIXTURE(Fixture, "write_to_unusually_named_read_only_property")
|
|||
CHECK("Property \"hello world\" of table '{ read [\"hello world\"]: number }' is read-only" == toString(result.errors[0]));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "write_annotations_are_unsupported_even_with_the_new_solver")
|
||||
TEST_CASE_FIXTURE(Fixture, "write_annotations_are_supported_with_the_new_solver")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
|
@ -4519,10 +4588,15 @@ TEST_CASE_FIXTURE(Fixture, "write_annotations_are_unsupported_even_with_the_new_
|
|||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
if (FFlag::LuauEnableWriteOnlyProperties)
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
else
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
CHECK("write keyword is illegal here" == toString(result.errors[0]));
|
||||
CHECK(Location{{1, 23}, {1, 28}} == result.errors[0].location);
|
||||
CHECK("write keyword is illegal here" == toString(result.errors[0]));
|
||||
CHECK(Location{{1, 23}, {1, 28}} == result.errors[0].location);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "read_and_write_only_table_properties_are_unsupported")
|
||||
|
@ -4549,10 +4623,8 @@ TEST_CASE_FIXTURE(Fixture, "read_and_write_only_table_properties_are_unsupported
|
|||
CHECK(Location{{5, 18}, {5, 23}} == result.errors[3].location);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "read_ond_write_only_indexers_are_unsupported")
|
||||
TEST_CASE_FIXTURE(Fixture, "read_and_write_only_indexers_are_unsupported")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type T = {read [string]: number}
|
||||
type U = {write [string]: boolean}
|
||||
|
@ -4571,7 +4643,11 @@ TEST_CASE_FIXTURE(Fixture, "table_writes_introduce_write_properties")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag sff[] = {{FFlag::LuauNonReentrantGeneralization3, true}};
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization, true},
|
||||
{FFlag::LuauSubtypeGenericsAndNegations, true},
|
||||
{FFlag::LuauNoMoreInjectiveTypeFunctions, true}
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function oc(player, speaker)
|
||||
|
@ -4622,7 +4698,7 @@ TEST_CASE_FIXTURE(Fixture, "refined_thing_can_be_an_array")
|
|||
end
|
||||
)");
|
||||
|
||||
if (FFlag::LuauSolverV2 && !FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauSolverV2 && !FFlag::LuauEagerGeneralization)
|
||||
{
|
||||
LUAU_CHECK_ERROR_COUNT(1, result);
|
||||
LUAU_CHECK_ERROR(result, NotATable);
|
||||
|
@ -4670,7 +4746,7 @@ TEST_CASE_FIXTURE(Fixture, "parameter_was_set_an_indexer_and_bounded_by_another_
|
|||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
// FIXME CLI-114134. We need to simplify types more consistently.
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
CHECK("({number} & {number}, unknown) -> ()" == toString(requireType("f")));
|
||||
else
|
||||
CHECK_EQ("(unknown & {number} & {number}, unknown) -> ()", toString(requireType("f")));
|
||||
|
@ -5212,8 +5288,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "write_only_table_field_duplicate")
|
|||
}
|
||||
)");
|
||||
|
||||
LUAU_CHECK_ERROR_COUNT(1, result);
|
||||
CHECK_EQ("write keyword is illegal here", toString(result.errors[0]));
|
||||
if (FFlag::LuauEnableWriteOnlyProperties)
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
else
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK_EQ("write keyword is illegal here", toString(result.errors[0]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_musnt_assert")
|
||||
|
@ -5661,5 +5742,81 @@ TEST_CASE_FIXTURE(Fixture, "narrow_table_literal_check_assignment")
|
|||
CHECK_EQ("boolean", toString(tm->wantedType));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "disable_singleton_inference_on_large_tables")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck, true},
|
||||
{FFlag::LuauDisablePrimitiveInferenceInLargeTables, true},
|
||||
};
|
||||
|
||||
ScopedFastInt _{FInt::LuauPrimitiveInferenceInTableLimit, 2};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Word = "foo" | "bar"
|
||||
local words: { Word } = { "foo", "bar", "foo" }
|
||||
)");
|
||||
// We expect this to have errors now, as we've set the limit for inference
|
||||
// in tables so low.
|
||||
LUAU_REQUIRE_ERROR_COUNT(3, result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "disable_singleton_inference_on_large_nested_tables")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck, true},
|
||||
{FFlag::LuauDisablePrimitiveInferenceInLargeTables, true},
|
||||
};
|
||||
|
||||
ScopedFastInt _{FInt::LuauPrimitiveInferenceInTableLimit, 2};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Word = "foo" | "bar"
|
||||
local words: {{ Word }} = {{ "foo", "bar", "foo" }}
|
||||
)");
|
||||
LUAU_REQUIRE_ERROR_COUNT(3, result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "large_table_inference_does_not_bleed")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck, true},
|
||||
{FFlag::LuauDisablePrimitiveInferenceInLargeTables, true},
|
||||
};
|
||||
|
||||
ScopedFastInt _{FInt::LuauPrimitiveInferenceInTableLimit, 2};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Word = "foo" | "bar"
|
||||
local words: { Word } = { "foo", "bar", "foo" }
|
||||
local otherWords: { Word } = {"foo"}
|
||||
)");
|
||||
LUAU_REQUIRE_ERROR_COUNT(3, result);
|
||||
for (const auto& err: result.errors)
|
||||
// Check that all of the errors are localized to `words`, not `otherWords`
|
||||
CHECK(err.location.begin.line == 2);
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "extremely_large_table" * doctest::timeout(2.0))
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauDisablePrimitiveInferenceInLargeTables, true},
|
||||
};
|
||||
|
||||
const std::string source =
|
||||
"local res = {\n" +
|
||||
rep("\"foo\",\n", 100'000) +
|
||||
"}";
|
||||
LUAU_REQUIRE_NO_ERRORS(check(source));
|
||||
CHECK_EQ("{string}", toString(requireType("res"), {true}));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -28,7 +28,7 @@ LUAU_FASTFLAG(LuauTypeCheckerAcceptNumberConcats)
|
|||
LUAU_FASTFLAG(LuauPreprocessTypestatedArgument)
|
||||
LUAU_FASTFLAG(LuauMagicFreezeCheckBlocked2)
|
||||
LUAU_FASTFLAG(LuauNoMoreInjectiveTypeFunctions)
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauOptimizeFalsyAndTruthyIntersect)
|
||||
LUAU_FASTFLAG(LuauHasPropProperBlock)
|
||||
LUAU_FASTFLAG(LuauStringPartLengthLimit)
|
||||
|
@ -37,6 +37,8 @@ LUAU_FASTFLAG(LuauReportSubtypingErrors)
|
|||
LUAU_FASTFLAG(LuauAvoidDoubleNegation)
|
||||
LUAU_FASTFLAG(LuauInsertErrorTypesIntoIndexerResult)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine)
|
||||
LUAU_FASTFLAG(LuauSubtypeGenericsAndNegations)
|
||||
LUAU_FASTFLAG(LuauNoMoreInjectiveTypeFunctions)
|
||||
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
|
||||
|
||||
using namespace Luau;
|
||||
|
@ -445,7 +447,7 @@ TEST_CASE_FIXTURE(Fixture, "check_expr_recursion_limit")
|
|||
#endif
|
||||
ScopedFastInt luauRecursionLimit{FInt::LuauRecursionLimit, limit + 100};
|
||||
ScopedFastInt luauCheckRecursionLimit{FInt::LuauCheckRecursionLimit, limit - 100};
|
||||
ScopedFastFlag _{FFlag::LuauNonReentrantGeneralization3, false};
|
||||
ScopedFastFlag _{FFlag::LuauEagerGeneralization, false};
|
||||
|
||||
CheckResult result = check(R"(("foo"))" + rep(":lower()", limit));
|
||||
|
||||
|
@ -1258,9 +1260,6 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_cache_limit_normalizer")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "follow_on_new_types_in_substitution")
|
||||
{
|
||||
// CLI-114134
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local obj = {}
|
||||
|
||||
|
@ -2042,8 +2041,10 @@ TEST_CASE_FIXTURE(Fixture, "fuzz_generalize_one_remove_type_assert")
|
|||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauHasPropProperBlock, true},
|
||||
{FFlag::LuauNonReentrantGeneralization3, true},
|
||||
{FFlag::LuauOptimizeFalsyAndTruthyIntersect, true}
|
||||
{FFlag::LuauEagerGeneralization, true},
|
||||
{FFlag::LuauOptimizeFalsyAndTruthyIntersect, true},
|
||||
{FFlag::LuauSubtypeGenericsAndNegations, true},
|
||||
{FFlag::LuauNoMoreInjectiveTypeFunctions, true},
|
||||
};
|
||||
|
||||
auto result = check(R"(
|
||||
|
@ -2078,8 +2079,10 @@ TEST_CASE_FIXTURE(Fixture, "fuzz_generalize_one_remove_type_assert_2")
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauNonReentrantGeneralization3, true},
|
||||
{FFlag::LuauEagerGeneralization, true},
|
||||
{FFlag::LuauOptimizeFalsyAndTruthyIntersect, true},
|
||||
{FFlag::LuauSubtypeGenericsAndNegations, true},
|
||||
{FFlag::LuauNoMoreInjectiveTypeFunctions, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -2106,15 +2109,19 @@ TEST_CASE_FIXTURE(Fixture, "fuzz_generalize_one_remove_type_assert_2")
|
|||
LUAU_REQUIRE_NO_ERROR(result, ConstraintSolvingIncompleteError);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_simplify_combinatorial_explosion")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauHasPropProperBlock, true},
|
||||
{FFlag::LuauNonReentrantGeneralization3, true},
|
||||
{FFlag::LuauEagerGeneralization, true},
|
||||
{FFlag::LuauOptimizeFalsyAndTruthyIntersect, true},
|
||||
{FFlag::LuauStringPartLengthLimit, true},
|
||||
{FFlag::LuauSimplificationRecheckAssumption, true},
|
||||
{FFlag::LuauSubtypeGenericsAndNegations, true},
|
||||
{FFlag::LuauNoMoreInjectiveTypeFunctions, true},
|
||||
};
|
||||
|
||||
LUAU_REQUIRE_ERRORS(check(R"(
|
||||
|
@ -2128,6 +2135,8 @@ local _
|
|||
)"));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_missing_follow_table_freeze")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauMagicFreezeCheckBlocked2, true};
|
||||
|
|
|
@ -12,10 +12,11 @@ using namespace Luau;
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauReportSubtypingErrors)
|
||||
LUAU_FASTFLAG(LuauTrackInferredFunctionTypeFromCall)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAG(LuauFixEmptyTypePackStringification)
|
||||
|
||||
TEST_SUITE_BEGIN("TypePackTests");
|
||||
|
||||
|
@ -99,7 +100,7 @@ TEST_CASE_FIXTURE(Fixture, "higher_order_function")
|
|||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
CHECK_EQ("<a, b..., c...>((c...) -> (b...), (a) -> (c...), a) -> (b...)", toString(requireType("apply")));
|
||||
else
|
||||
CHECK_EQ("<a, b..., c...>((b...) -> (c...), (a) -> (b...), a) -> (c...)", toString(requireType("apply")));
|
||||
|
@ -339,7 +340,10 @@ local c: Packed<string, number, boolean>
|
|||
REQUIRE(ttvA->instantiatedTypeParams.size() == 1);
|
||||
REQUIRE(ttvA->instantiatedTypePackParams.size() == 1);
|
||||
CHECK_EQ(toString(ttvA->instantiatedTypeParams[0], {true}), "number");
|
||||
CHECK_EQ(toString(ttvA->instantiatedTypePackParams[0], {true}), "");
|
||||
if (FFlag::LuauFixEmptyTypePackStringification)
|
||||
CHECK_EQ(toString(ttvA->instantiatedTypePackParams[0], {true}), "()");
|
||||
else
|
||||
CHECK_EQ(toString(ttvA->instantiatedTypePackParams[0], {true}), "");
|
||||
|
||||
auto ttvB = get<TableType>(requireType("b"));
|
||||
REQUIRE(ttvB);
|
||||
|
|
|
@ -8,11 +8,12 @@ LUAU_FASTFLAG(LuauRefineWaitForBlockedTypesInTarget)
|
|||
LUAU_FASTFLAG(LuauDoNotAddUpvalueTypesToLocalType)
|
||||
LUAU_FASTFLAG(LuauDfgIfBlocksShouldRespectControlFlow)
|
||||
LUAU_FASTFLAG(LuauReportSubtypingErrors)
|
||||
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
|
||||
LUAU_FASTFLAG(LuauDfgMatchCGScopes)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauPreprocessTypestatedArgument)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
|
||||
LUAU_FASTFLAG(LuauSubtypeGenericsAndNegations)
|
||||
LUAU_FASTFLAG(LuauNoMoreInjectiveTypeFunctions)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -414,7 +415,13 @@ TEST_CASE_FIXTURE(TypeStateFixture, "prototyped_recursive_functions")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "prototyped_recursive_functions_but_has_future_assignments")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauReportSubtypingErrors, true}, {FFlag::LuauNonReentrantGeneralization3, true}};
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauReportSubtypingErrors, true},
|
||||
{FFlag::LuauEagerGeneralization, true},
|
||||
{FFlag::LuauSubtypeGenericsAndNegations, true},
|
||||
{FFlag::LuauNoMoreInjectiveTypeFunctions, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local f
|
||||
|
@ -851,24 +858,22 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "assign_in_an_if_branch_without_else")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "fuzzer_table_freeze_in_binary_expr")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauPreprocessTypestatedArgument, true},
|
||||
{FFlag::LuauDfgMatchCGScopes, true},
|
||||
};
|
||||
|
||||
// Previously this would ICE due to mismatched scopes between the
|
||||
// constraint generator and the data flow graph.
|
||||
LUAU_REQUIRE_ERRORS(check(R"(
|
||||
local _
|
||||
if _ or table.freeze(_,_) or table.freeze(_,_) then
|
||||
end
|
||||
)"));
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
// CLI-154237: This currently throws an exception due to a mismatch between
|
||||
// the scopes created in the data flow graph versus the constraint generator.
|
||||
CHECK_THROWS_AS(
|
||||
check(R"(
|
||||
local _
|
||||
if _ or table.freeze(_,_) or table.freeze(_,_) then
|
||||
end
|
||||
)"),
|
||||
Luau::InternalCompilerError
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_in_conditional")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauDfgMatchCGScopes, true};
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
// NOTE: This _probably_ should be disallowed, but it is representing that
|
||||
// type stating functions in short circuiting binary expressions do not
|
||||
// reflect their type states.
|
||||
|
@ -883,21 +888,19 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_freeze_in_conditional")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "fuzzer_table_freeze_in_conditional_expr")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauPreprocessTypestatedArgument, true},
|
||||
{FFlag::LuauDfgMatchCGScopes, true},
|
||||
};
|
||||
|
||||
// Previously this would ICE due to mismatched scopes between the
|
||||
// constraint generator and the data flow graph.
|
||||
LUAU_REQUIRE_ERRORS(check(R"(
|
||||
--!strict
|
||||
local _
|
||||
if
|
||||
if table.freeze(_,_) then _ else _
|
||||
then
|
||||
end
|
||||
)"));
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
// CLI-154237: This currently throws an exception due to a mismatch between
|
||||
// the scopes created in the data flow graph versus the constraint generator.
|
||||
CHECK_THROWS_AS(
|
||||
check(R"(
|
||||
local _
|
||||
if
|
||||
if table.freeze(_,_) then _ else _
|
||||
then
|
||||
end
|
||||
)"),
|
||||
Luau::InternalCompilerError
|
||||
);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -10,7 +10,7 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
|
||||
TEST_SUITE_BEGIN("UnionTypes");
|
||||
|
@ -902,7 +902,7 @@ TEST_CASE_FIXTURE(Fixture, "less_greedy_unification_with_union_types")
|
|||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
if (FFlag::DebugLuauGreedyGeneralization)
|
||||
if (FFlag::LuauEagerGeneralization)
|
||||
CHECK_EQ(
|
||||
"<a>(({ read x: a } & { x: number }) | ({ read x: a } & { x: string })) -> { x: number } | { x: string }", toString(requireType("f"))
|
||||
);
|
||||
|
|
|
@ -8,7 +8,6 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LuauNoMoreInjectiveTypeFunctions);
|
||||
LUAU_FASTFLAG(DebugLuauGreedyGeneralization);
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferUnknownNever");
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ using namespace Luau::TypePath;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypePathMaximumTraverseSteps);
|
||||
LUAU_FASTFLAG(LuauFreeTypesMustHaveBounds);
|
||||
|
||||
struct TypePathFixture : Fixture
|
||||
{
|
||||
|
|
|
@ -103,6 +103,12 @@ def main():
|
|||
parser.add_argument(
|
||||
"path", action="store", help="Path to the Luau.UnitTest executable"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--fflags",
|
||||
dest="flags",
|
||||
action="store",
|
||||
help="Set extra FFlags",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dump",
|
||||
dest="dump",
|
||||
|
@ -136,9 +142,11 @@ def main():
|
|||
|
||||
failList = loadFailList()
|
||||
|
||||
flags = ["true", "LuauSolverV2"]
|
||||
flags = "true,LuauSolverV2"
|
||||
if args.flags:
|
||||
flags += "," + args.flags
|
||||
|
||||
commandLine = [args.path, "--reporters=xml", "--fflags=" + ",".join(flags)]
|
||||
commandLine = [args.path, "--reporters=xml", "--fflags=" + flags]
|
||||
|
||||
if args.random_seed:
|
||||
commandLine.append("--random-seed=" + str(args.random_seed))
|
||||
|
|
Loading…
Add table
Reference in a new issue