mirror of
https://github.com/luau-lang/luau.git
synced 2025-08-26 11:27:08 +01:00
Sync to upstream/release/685 (#1940)
Another week, another release! ## Analysis - Do not warn on unknown `require`s in non-strict mode. - Improve `Luau::dump`'s output for `DenseHashMap`. - Raise type checking errors when we would otherwise be leaking internal error types from modules. - Fix a crash that would sometimes occur when calling a function with an incomplete type. - Replace uses of `FFlag::LuauSolverV2` in `ClonePublicInterface` with a `solverMode` field. - Limit the number of constraints that can be dynamically created to fail more gracefully in complex cases. - Fix #1932. --------- Co-authored-by: Alexander Youngblood <ayoungblood@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Ariel Weiss <aaronweiss@roblox.com> Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com> Co-authored-by: Sora Kanosue <skanosue@roblox.com> Co-authored-by: Talha Pathan <tpathan@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
This commit is contained in:
parent
eaab9c4363
commit
f3f3bf8f72
28 changed files with 594 additions and 310 deletions
|
@ -102,6 +102,11 @@ struct ConstraintSolver
|
|||
// scope tree.
|
||||
std::vector<std::unique_ptr<Constraint>> solverConstraints;
|
||||
|
||||
// Ticks downward toward zero each time a new constraint is pushed into
|
||||
// solverConstraints. When this counter reaches zero, the type inference
|
||||
// engine reports a CodeTooComplex error and aborts.
|
||||
size_t solverConstraintLimit = 0;
|
||||
|
||||
// This includes every constraint that has not been fully solved.
|
||||
// A constraint can be both blocked and unsolved, for instance.
|
||||
std::vector<NotNull<const Constraint>> unsolvedConstraints;
|
||||
|
|
|
@ -113,7 +113,8 @@ struct FrontendOptions
|
|||
bool applyInternalLimitScaling = false;
|
||||
|
||||
// An optional callback which is called for every *dirty* module was checked
|
||||
// Is multi-threaded typechecking is used, this callback might be called from multiple threads and has to be thread-safe
|
||||
// If multi-threaded typechecking is used, this callback might be called
|
||||
// from multiple threads and has to be thread-safe
|
||||
std::function<void(const SourceModule& sourceModule, const Luau::Module& module)> customModuleCheck;
|
||||
|
||||
bool collectTypeAllocationStats = false;
|
||||
|
|
|
@ -359,6 +359,9 @@ inline constexpr char kLuauPrint[] = "_luau_print";
|
|||
// a constraint solving incomplete error to test semantics around that specific
|
||||
// error.
|
||||
inline constexpr char kLuauForceConstraintSolvingIncomplete[] = "_luau_force_constraint_solving_incomplete";
|
||||
// `_luau_blocked_type` will cause us to always mint a blocked type that does
|
||||
// not get emplaced by constraint solving.
|
||||
inline constexpr char kLuauBlockedType[] = "_luau_blocked_type";
|
||||
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -34,7 +34,7 @@ struct UnifierCounters
|
|||
|
||||
struct UnifierSharedState
|
||||
{
|
||||
UnifierSharedState(InternalErrorReporter* iceHandler)
|
||||
explicit UnifierSharedState(InternalErrorReporter* iceHandler)
|
||||
: iceHandler(iceHandler)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1465,6 +1465,12 @@ struct AstJsonEncoder : public AstVisitor
|
|||
return false;
|
||||
}
|
||||
|
||||
bool visit(class AstTypeOptional* node) override
|
||||
{
|
||||
write(node);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(class AstTypeUnion* node) override
|
||||
{
|
||||
write(node);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauForceSimplifyConstraint)
|
||||
LUAU_FASTFLAG(LuauForceSimplifyConstraint2)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -66,7 +66,7 @@ struct ReferenceCountInitializer_DEPRECATED : TypeOnceVisitor
|
|||
|
||||
bool visit(TypeId, const TypeFunctionInstanceType& tfit) override
|
||||
{
|
||||
if (FFlag::LuauForceSimplifyConstraint)
|
||||
if (FFlag::LuauForceSimplifyConstraint2)
|
||||
return tfit.function->canReduceGenerics;
|
||||
else
|
||||
return FFlag::LuauEagerGeneralization4 && traverseIntoTypeFunctions;
|
||||
|
@ -121,7 +121,7 @@ struct ReferenceCountInitializer : TypeOnceVisitor
|
|||
|
||||
bool visit(TypeId, const TypeFunctionInstanceType& tfit) override
|
||||
{
|
||||
if (FFlag::LuauForceSimplifyConstraint)
|
||||
if (FFlag::LuauForceSimplifyConstraint2)
|
||||
return tfit.function->canReduceGenerics;
|
||||
else
|
||||
return FFlag::LuauEagerGeneralization4 && traverseIntoTypeFunctions;
|
||||
|
|
|
@ -41,7 +41,6 @@ LUAU_FASTFLAG(LuauGlobalVariableModuleIsolation)
|
|||
LUAU_FASTFLAGVARIABLE(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSimplifyOutOfLine2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDisablePrimitiveInferenceInLargeTables)
|
||||
LUAU_FASTINTVARIABLE(LuauPrimitiveInferenceInTableLimit, 500)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSkipLvalueForCompoundAssignment)
|
||||
|
@ -51,6 +50,7 @@ LUAU_FASTFLAGVARIABLE(LuauFragmentAutocompleteTracksRValueRefinements)
|
|||
LUAU_FASTFLAGVARIABLE(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAGVARIABLE(LuauInferActualIfElseExprType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDoNotPrototypeTableIndex)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -1292,7 +1292,6 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatFor* for_)
|
|||
|
||||
visit(forScope, for_->body);
|
||||
|
||||
if (FFlag::LuauDfgAllowUpdatesInLoops)
|
||||
scope->inheritAssignments(forScope);
|
||||
|
||||
return ControlFlow::None;
|
||||
|
@ -1353,7 +1352,6 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatForIn* forI
|
|||
visit(loopScope, forIn->body);
|
||||
Checkpoint end = checkpoint(this);
|
||||
|
||||
if (FFlag::LuauDfgAllowUpdatesInLoops)
|
||||
scope->inheritAssignments(loopScope);
|
||||
|
||||
// This iter constraint must dispatch first.
|
||||
|
@ -1379,7 +1377,6 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatWhile* whil
|
|||
|
||||
visit(whileScope, while_->body);
|
||||
|
||||
if (FFlag::LuauDfgAllowUpdatesInLoops)
|
||||
scope->inheritAssignments(whileScope);
|
||||
|
||||
return ControlFlow::None;
|
||||
|
@ -1393,7 +1390,6 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatRepeat* rep
|
|||
|
||||
check(repeatScope, repeat->condition);
|
||||
|
||||
if (FFlag::LuauDfgAllowUpdatesInLoops)
|
||||
scope->inheritAssignments(repeatScope);
|
||||
|
||||
return ControlFlow::None;
|
||||
|
@ -1997,6 +1993,14 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareExte
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving)
|
||||
{
|
||||
// If we don't emplace an error type here, then later we'll be
|
||||
// exposing a blocked type in this file's type interface. This
|
||||
// is _normally_ harmless.
|
||||
emplaceType<BoundType>(asMutable(bindingIt->second.type), builtinTypes->errorType);
|
||||
}
|
||||
|
||||
return ControlFlow::None;
|
||||
}
|
||||
}
|
||||
|
@ -3771,6 +3775,10 @@ TypeId ConstraintGenerator::resolveReferenceType(
|
|||
else
|
||||
return resolveType_(scope, ref->parameters.data[0].type, inTypeArguments);
|
||||
}
|
||||
else if (FFlag::LuauLimitDynamicConstraintSolving && ref->name == "_luau_blocked_type")
|
||||
{
|
||||
return arena->addType(BlockedType{});
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<TypeFun> alias;
|
||||
|
|
|
@ -26,11 +26,13 @@
|
|||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
LUAU_FASTINTVARIABLE(LuauSolverConstraintLimit, 1000)
|
||||
LUAU_FASTINTVARIABLE(LuauSolverRecursionLimit, 500)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauAssertOnForcedConstraint)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolver)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverIncludeDependencies)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogBindings)
|
||||
LUAU_FASTINTVARIABLE(LuauSolverRecursionLimit, 500)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||
|
@ -41,8 +43,10 @@ LUAU_FASTFLAGVARIABLE(LuauTableLiteralSubtypeCheckFunctionCalls)
|
|||
LUAU_FASTFLAGVARIABLE(LuauUseOrderedTypeSetsInConstraints)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauAvoidExcessiveTypeCopying)
|
||||
LUAU_FASTFLAGVARIABLE(LuauForceSimplifyConstraint)
|
||||
LUAU_FASTFLAGVARIABLE(LuauForceSimplifyConstraint2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCollapseShouldNotCrash)
|
||||
LUAU_FASTFLAGVARIABLE(LuauContainsAnyGenericFollowBeforeChecking)
|
||||
LUAU_FASTFLAGVARIABLE(LuauLimitDynamicConstraintSolving)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -333,6 +337,7 @@ ConstraintSolver::ConstraintSolver(
|
|||
, rootScope(constraintSet.rootScope)
|
||||
, currentModuleName(std::move(moduleName))
|
||||
, dfg(dfg)
|
||||
, solverConstraintLimit(FInt::LuauSolverConstraintLimit)
|
||||
, moduleResolver(moduleResolver)
|
||||
, requireCycles(std::move(requireCycles))
|
||||
, logger(logger)
|
||||
|
@ -367,6 +372,7 @@ ConstraintSolver::ConstraintSolver(
|
|||
, rootScope(rootScope)
|
||||
, currentModuleName(std::move(moduleName))
|
||||
, dfg(dfg)
|
||||
, solverConstraintLimit(FInt::LuauSolverConstraintLimit)
|
||||
, moduleResolver(moduleResolver)
|
||||
, requireCycles(std::move(requireCycles))
|
||||
, logger(logger)
|
||||
|
@ -461,6 +467,11 @@ void ConstraintSolver::run()
|
|||
if (limits.cancellationToken && limits.cancellationToken->requested())
|
||||
throwUserCancelError();
|
||||
|
||||
// If we were _given_ a limit, and the current limit has hit zero, ]
|
||||
// then early exit from constraint solving.
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving && FInt::LuauSolverConstraintLimit > 0 && solverConstraintLimit == 0)
|
||||
break;
|
||||
|
||||
std::string saveMe = FFlag::DebugLuauLogSolver ? toString(*c, opts) : std::string{};
|
||||
StepSnapshot snapshot;
|
||||
|
||||
|
@ -1528,7 +1539,9 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
|
|||
auto it = begin(t);
|
||||
auto endIt = end(t);
|
||||
|
||||
LUAU_ASSERT(it != endIt);
|
||||
if (FFlag::LuauCollapseShouldNotCrash && it == endIt)
|
||||
return std::nullopt;
|
||||
|
||||
TypeId fst = follow(*it);
|
||||
while (it != endIt)
|
||||
{
|
||||
|
@ -2940,14 +2953,14 @@ bool ConstraintSolver::tryDispatch(const SimplifyConstraint& c, NotNull<const Co
|
|||
|
||||
FindAllUnionMembers finder;
|
||||
finder.traverse(target);
|
||||
// Clip this comment with LuauForceSimplifyConstraint
|
||||
// Clip this comment with LuauForceSimplifyConstraint2
|
||||
//
|
||||
// The flagging logic is roughly: if `LuauForceSimplifyConstraint` is
|
||||
// The flagging logic is roughly: if `LuauForceSimplifyConstraint2` is
|
||||
// _not_ set, then we ignore the input `force`, as the RHS of the &&
|
||||
// is always true. Otherwise, when the flag is set, the RHS of the &&
|
||||
// is equivalent to `!force`: we only block on types when we're not
|
||||
// being force solved.
|
||||
if (!finder.blockedTys.empty() && !(FFlag::LuauForceSimplifyConstraint && force))
|
||||
if (!finder.blockedTys.empty() && !(FFlag::LuauForceSimplifyConstraint2 && force))
|
||||
{
|
||||
for (TypeId ty : finder.blockedTys)
|
||||
block(ty, constraint);
|
||||
|
@ -2961,6 +2974,18 @@ bool ConstraintSolver::tryDispatch(const SimplifyConstraint& c, NotNull<const Co
|
|||
continue;
|
||||
result = simplifyUnion(constraint->scope, constraint->location, result, ty);
|
||||
}
|
||||
if (FFlag::LuauForceSimplifyConstraint2)
|
||||
{
|
||||
// If we forced, then there _may_ be blocked types, and we should
|
||||
// include those in the union as well.
|
||||
for (TypeId ty : finder.blockedTys)
|
||||
{
|
||||
ty = follow(ty);
|
||||
if (ty == target)
|
||||
continue;
|
||||
result = simplifyUnion(constraint->scope, constraint->location, result, ty);
|
||||
}
|
||||
}
|
||||
emplaceType<BoundType>(asMutable(target), result);
|
||||
return true;
|
||||
}
|
||||
|
@ -3832,6 +3857,17 @@ NotNull<Constraint> ConstraintSolver::pushConstraint(NotNull<Scope> scope, const
|
|||
solverConstraints.push_back(std::move(c));
|
||||
unsolvedConstraints.emplace_back(borrow);
|
||||
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving)
|
||||
{
|
||||
if (solverConstraintLimit > 0)
|
||||
{
|
||||
--solverConstraintLimit;
|
||||
|
||||
if (solverConstraintLimit == 0)
|
||||
reportError(CodeTooComplex{}, location);
|
||||
}
|
||||
}
|
||||
|
||||
return borrow;
|
||||
}
|
||||
|
||||
|
@ -3899,7 +3935,7 @@ void ConstraintSolver::shiftReferences(TypeId source, TypeId target)
|
|||
if (!isReferenceCountedType(target))
|
||||
return;
|
||||
|
||||
if (FFlag::LuauForceSimplifyConstraint)
|
||||
if (FFlag::LuauForceSimplifyConstraint2)
|
||||
{
|
||||
// This can happen in the _very_ specific case of:
|
||||
//
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
LUAU_FASTFLAG(DebugLuauFreezeArena)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDfgScopeStackNotNull)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDfgAllowUpdatesInLoops)
|
||||
LUAU_FASTFLAG(LuauFragmentAutocompleteTracksRValueRefinements)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDfgForwardNilFromAndOr)
|
||||
|
||||
|
@ -157,33 +156,13 @@ void DfgScope::inherit(const DfgScope* childScope)
|
|||
|
||||
bool DfgScope::canUpdateDefinition(Symbol symbol) const
|
||||
{
|
||||
if (FFlag::LuauDfgAllowUpdatesInLoops)
|
||||
return true;
|
||||
|
||||
for (const DfgScope* current = this; current; current = current->parent)
|
||||
{
|
||||
if (current->bindings.find(symbol))
|
||||
return true;
|
||||
else if (current->scopeType == DfgScope::Loop)
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: Vestigial as of clipping LuauDfgAllowUpdatesInLoops
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DfgScope::canUpdateDefinition(DefId def, const std::string& key) const
|
||||
{
|
||||
if (FFlag::LuauDfgAllowUpdatesInLoops)
|
||||
return true;
|
||||
|
||||
for (const DfgScope* current = this; current; current = current->parent)
|
||||
{
|
||||
if (auto props = current->props.find(def))
|
||||
return true;
|
||||
else if (current->scopeType == DfgScope::Loop)
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: Vestigial as of clipping LuauDfgAllowUpdatesInLoops
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -541,9 +520,6 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatWhile* w)
|
|||
// allow a string to flow into a position that expects.
|
||||
DfgScope* whileScope = makeChildScope(DfgScope::Loop);
|
||||
|
||||
if (FFlag::LuauDfgAllowUpdatesInLoops)
|
||||
{
|
||||
|
||||
ControlFlow cf;
|
||||
{
|
||||
PushScope ps{scopeStack, whileScope};
|
||||
|
@ -558,22 +534,6 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatWhile* w)
|
|||
join(scope, scope, whileScope);
|
||||
|
||||
return ControlFlow::None;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
PushScope ps{scopeStack, whileScope};
|
||||
visitExpr(w->condition);
|
||||
visit(w->body);
|
||||
}
|
||||
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
currentScope()->inherit(whileScope);
|
||||
else
|
||||
currentScope_DEPRECATED()->inherit(whileScope);
|
||||
|
||||
return ControlFlow::None;
|
||||
}
|
||||
}
|
||||
|
||||
ControlFlow DataFlowGraphBuilder::visit(AstStatRepeat* r)
|
||||
|
@ -582,8 +542,6 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatRepeat* r)
|
|||
// does not consider the _second_ loop iteration.
|
||||
DfgScope* repeatScope = makeChildScope(DfgScope::Loop);
|
||||
|
||||
if (FFlag::LuauDfgAllowUpdatesInLoops)
|
||||
{
|
||||
ControlFlow cf;
|
||||
|
||||
{
|
||||
|
@ -601,22 +559,6 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatRepeat* r)
|
|||
// control flow, but if it's throws or returns, then we need to
|
||||
// return _that_ to the parent.
|
||||
return matches(cf, ControlFlow::Breaks | ControlFlow::Continues) ? ControlFlow::None : cf;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
PushScope ps{scopeStack, repeatScope};
|
||||
visitBlockWithoutChildScope(r->body);
|
||||
visitExpr(r->condition);
|
||||
}
|
||||
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
currentScope()->inherit(repeatScope);
|
||||
else
|
||||
currentScope_DEPRECATED()->inherit(repeatScope);
|
||||
|
||||
return ControlFlow::None;
|
||||
}
|
||||
}
|
||||
|
||||
ControlFlow DataFlowGraphBuilder::visit(AstStatBreak* b)
|
||||
|
@ -694,9 +636,6 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatFor* f)
|
|||
if (f->step)
|
||||
visitExpr(f->step);
|
||||
|
||||
if (FFlag::LuauDfgAllowUpdatesInLoops)
|
||||
{
|
||||
|
||||
ControlFlow cf;
|
||||
{
|
||||
PushScope ps{scopeStack, forScope};
|
||||
|
@ -719,43 +658,12 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatFor* f)
|
|||
join(scope, scope, forScope);
|
||||
|
||||
return ControlFlow::None;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
PushScope ps{scopeStack, forScope};
|
||||
|
||||
if (f->var->annotation)
|
||||
visitType(f->var->annotation);
|
||||
|
||||
DefId def = defArena->freshCell(f->var, f->var->location);
|
||||
graph.localDefs[f->var] = def;
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
currentScope()->bindings[f->var] = def;
|
||||
else
|
||||
currentScope_DEPRECATED()->bindings[f->var] = def;
|
||||
captures[f->var].allVersions.push_back(def);
|
||||
|
||||
// TODO(controlflow): entry point has a back edge from exit point
|
||||
visit(f->body);
|
||||
}
|
||||
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
currentScope()->inherit(forScope);
|
||||
else
|
||||
currentScope_DEPRECATED()->inherit(forScope);
|
||||
|
||||
return ControlFlow::None;
|
||||
}
|
||||
}
|
||||
|
||||
ControlFlow DataFlowGraphBuilder::visit(AstStatForIn* f)
|
||||
{
|
||||
DfgScope* forScope = makeChildScope(DfgScope::Loop);
|
||||
|
||||
if (FFlag::LuauDfgAllowUpdatesInLoops)
|
||||
{
|
||||
|
||||
ControlFlow cf;
|
||||
{
|
||||
PushScope ps{scopeStack, forScope};
|
||||
|
@ -789,40 +697,6 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatForIn* f)
|
|||
join(scope, scope, forScope);
|
||||
|
||||
return ControlFlow::None;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
PushScope ps{scopeStack, forScope};
|
||||
|
||||
for (AstLocal* local : f->vars)
|
||||
{
|
||||
if (local->annotation)
|
||||
visitType(local->annotation);
|
||||
|
||||
DefId def = defArena->freshCell(local, local->location);
|
||||
graph.localDefs[local] = def;
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
currentScope()->bindings[local] = def;
|
||||
else
|
||||
currentScope_DEPRECATED()->bindings[local] = def;
|
||||
captures[local].allVersions.push_back(def);
|
||||
}
|
||||
|
||||
// TODO(controlflow): entry point has a back edge from exit point
|
||||
// We're gonna need a `visitExprList` and `visitVariadicExpr` (function calls and `...`)
|
||||
for (AstExpr* e : f->values)
|
||||
visitExpr(e);
|
||||
|
||||
visit(f->body);
|
||||
}
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
currentScope()->inherit(forScope);
|
||||
else
|
||||
currentScope_DEPRECATED()->inherit(forScope);
|
||||
|
||||
return ControlFlow::None;
|
||||
}
|
||||
}
|
||||
|
||||
ControlFlow DataFlowGraphBuilder::visit(AstStatAssign* a)
|
||||
|
|
|
@ -49,6 +49,7 @@ LUAU_FASTFLAGVARIABLE(LuauTrackTypeAllocations)
|
|||
LUAU_FASTFLAGVARIABLE(LuauUseWorkspacePropToChooseSolver)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictSuppressSoloConstraintSolvingIncomplete)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauAlwaysShowConstraintSolvingIncomplete)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -1653,12 +1654,50 @@ ModulePtr check(
|
|||
sourceModule.root->visit(&etv);
|
||||
}
|
||||
|
||||
// NOTE: This used to be done prior to cloning the public interface, but
|
||||
// we now replace "internal" types with `*error-type*`.
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving)
|
||||
{
|
||||
if (FFlag::DebugLuauForbidInternalTypes)
|
||||
{
|
||||
InternalTypeFinder finder;
|
||||
|
||||
// `result->returnType` is not filled in yet, so we
|
||||
// traverse the return type of the root module.
|
||||
finder.traverse(result->getModuleScope()->returnType);
|
||||
|
||||
for (const auto& [_, binding] : result->exportedTypeBindings)
|
||||
finder.traverse(binding.type);
|
||||
|
||||
for (const auto& [_, ty] : result->astTypes)
|
||||
finder.traverse(ty);
|
||||
|
||||
for (const auto& [_, ty] : result->astExpectedTypes)
|
||||
finder.traverse(ty);
|
||||
|
||||
for (const auto& [_, tp] : result->astTypePacks)
|
||||
finder.traverse(tp);
|
||||
|
||||
for (const auto& [_, ty] : result->astResolvedTypes)
|
||||
finder.traverse(ty);
|
||||
|
||||
for (const auto& [_, ty] : result->astOverloadResolvedTypes)
|
||||
finder.traverse(ty);
|
||||
|
||||
for (const auto& [_, tp] : result->astResolvedTypePacks)
|
||||
finder.traverse(tp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unfreeze(result->interfaceTypes);
|
||||
if (FFlag::LuauUseWorkspacePropToChooseSolver)
|
||||
result->clonePublicInterface(builtinTypes, *iceHandler, SolverMode::New);
|
||||
else
|
||||
result->clonePublicInterface_DEPRECATED(builtinTypes, *iceHandler);
|
||||
|
||||
if (!FFlag::LuauLimitDynamicConstraintSolving)
|
||||
{
|
||||
if (FFlag::DebugLuauForbidInternalTypes)
|
||||
{
|
||||
InternalTypeFinder finder;
|
||||
|
@ -1686,6 +1725,7 @@ ModulePtr check(
|
|||
for (const auto& [_, tp] : result->astResolvedTypePacks)
|
||||
finder.traverse(tp);
|
||||
}
|
||||
}
|
||||
|
||||
// It would be nice if we could freeze the arenas before doing type
|
||||
// checking, but we'll have to do some work to get there.
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <algorithm>
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LuauUseWorkspacePropToChooseSolver)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -95,6 +97,9 @@ struct ClonePublicInterface : Substitution
|
|||
{
|
||||
NotNull<BuiltinTypes> builtinTypes;
|
||||
NotNull<Module> module;
|
||||
// NOTE: This can be made non-optional after
|
||||
// LuauUseWorkspacePropToChooseSolver is clipped.
|
||||
std::optional<SolverMode> solverMode{std::nullopt};
|
||||
|
||||
ClonePublicInterface(const TxnLog* log, NotNull<BuiltinTypes> builtinTypes, Module* module)
|
||||
: Substitution(log, &module->interfaceTypes)
|
||||
|
@ -104,6 +109,20 @@ struct ClonePublicInterface : Substitution
|
|||
LUAU_ASSERT(module);
|
||||
}
|
||||
|
||||
ClonePublicInterface(const TxnLog* log, NotNull<BuiltinTypes> builtinTypes, Module* module, SolverMode solverMode)
|
||||
: Substitution(log, &module->interfaceTypes)
|
||||
, builtinTypes(builtinTypes)
|
||||
, module(module)
|
||||
, solverMode(solverMode)
|
||||
{
|
||||
LUAU_ASSERT(module);
|
||||
}
|
||||
|
||||
bool isNewSolver() const
|
||||
{
|
||||
return FFlag::LuauSolverV2 || (FFlag::LuauUseWorkspacePropToChooseSolver && solverMode == SolverMode::New);
|
||||
}
|
||||
|
||||
bool isDirty(TypeId ty) override
|
||||
{
|
||||
if (ty->owningArena == &module->internalTypes)
|
||||
|
@ -157,11 +176,30 @@ struct ClonePublicInterface : Substitution
|
|||
else if (TableType* ttv = getMutable<TableType>(result))
|
||||
{
|
||||
ttv->level = TypeLevel{0, 0};
|
||||
if (FFlag::LuauSolverV2)
|
||||
if (isNewSolver())
|
||||
ttv->scope = nullptr;
|
||||
}
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
if (isNewSolver())
|
||||
{
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving)
|
||||
{
|
||||
if (is<FreeType, BlockedType, PendingExpansionType>(ty))
|
||||
{
|
||||
module->errors.emplace_back(
|
||||
Location{}, // Not amazing but the best we can do.
|
||||
module->name,
|
||||
InternalError{"An internal type is escaping this module; please report this bug at "
|
||||
"https://github.com/luau-lang/luau/issues"}
|
||||
);
|
||||
result = builtinTypes->errorType;
|
||||
}
|
||||
else if (auto genericty = getMutable<GenericType>(result))
|
||||
{
|
||||
genericty->scope = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto freety = getMutable<FreeType>(result))
|
||||
{
|
||||
|
@ -178,14 +216,34 @@ struct ClonePublicInterface : Substitution
|
|||
genericty->scope = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TypePackId clean(TypePackId tp) override
|
||||
{
|
||||
if (FFlag::LuauSolverV2)
|
||||
if (isNewSolver())
|
||||
{
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving)
|
||||
{
|
||||
if (is<FreeTypePack, BlockedTypePack>(tp))
|
||||
{
|
||||
module->errors.emplace_back(
|
||||
Location{},
|
||||
module->name,
|
||||
InternalError{"An internal type pack is escaping this module; please report this bug at "
|
||||
"https://github.com/luau-lang/luau/issues"}
|
||||
);
|
||||
return builtinTypes->errorTypePack;
|
||||
}
|
||||
|
||||
auto clonedTp = clone(tp);
|
||||
if (auto gtp = getMutable<GenericTypePack>(clonedTp))
|
||||
gtp->scope = nullptr;
|
||||
return clonedTp;
|
||||
}
|
||||
|
||||
auto clonedTp = clone(tp);
|
||||
if (auto ftp = getMutable<FreeTypePack>(clonedTp))
|
||||
{
|
||||
|
@ -200,6 +258,7 @@ struct ClonePublicInterface : Substitution
|
|||
else if (auto gtp = getMutable<GenericTypePack>(clonedTp))
|
||||
gtp->scope = nullptr;
|
||||
return clonedTp;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -325,7 +384,7 @@ void Module::clonePublicInterface(NotNull<BuiltinTypes> builtinTypes, InternalEr
|
|||
std::optional<TypePackId> varargPack = mode == SolverMode::New ? std::nullopt : moduleScope->varargPack;
|
||||
|
||||
TxnLog log;
|
||||
ClonePublicInterface clonePublicInterface{&log, builtinTypes, this};
|
||||
ClonePublicInterface clonePublicInterface{&log, builtinTypes, this, mode};
|
||||
|
||||
returnType = clonePublicInterface.cloneTypePack(returnType);
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ LUAU_FASTFLAG(DebugLuauMagicTypes)
|
|||
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictFixGenericTypePacks)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictMoreUnknownSymbols)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictNoErrorsPassingNever)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictSuppressesDynamicRequireErrors)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -1272,6 +1273,22 @@ void checkNonStrict(
|
|||
typeChecker.visit(sourceModule.root);
|
||||
unfreeze(module->interfaceTypes);
|
||||
copyErrors(module->errors, module->interfaceTypes, builtinTypes);
|
||||
|
||||
if (FFlag::LuauNewNonStrictSuppressesDynamicRequireErrors)
|
||||
{
|
||||
module->errors.erase(
|
||||
std::remove_if(
|
||||
module->errors.begin(),
|
||||
module->errors.end(),
|
||||
[](auto err)
|
||||
{
|
||||
return get<UnknownRequire>(err) != nullptr;
|
||||
}
|
||||
),
|
||||
module->errors.end()
|
||||
);
|
||||
}
|
||||
|
||||
freeze(module->interfaceTypes);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ LUAU_FASTFLAGVARIABLE(LuauSubtypingCheckFunctionGenericCounts)
|
|||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAGVARIABLE(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauMissingFollowMappedGenericPacks)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -975,7 +976,10 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId
|
|||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
{
|
||||
const TypePack* tp = get<TypePack>(*other);
|
||||
if (const VariadicTypePack* vtp = tp ? get<VariadicTypePack>(tp->tail) : nullptr; vtp && vtp->hidden)
|
||||
if (const VariadicTypePack* vtp = tp
|
||||
? get<VariadicTypePack>(
|
||||
FFlag::LuauMissingFollowMappedGenericPacks ? follow(tp->tail) : tp->tail)
|
||||
: nullptr; vtp && vtp->hidden)
|
||||
{
|
||||
TypePackId taillessTp = arena->addTypePack(tp->head);
|
||||
results.push_back(isCovariantWith(env, taillessTp, superTailPack, scope)
|
||||
|
@ -1066,7 +1070,10 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId
|
|||
if (FFlag::LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
{
|
||||
const TypePack* tp = get<TypePack>(*other);
|
||||
if (const VariadicTypePack* vtp = tp ? get<VariadicTypePack>(tp->tail) : nullptr; vtp && vtp->hidden)
|
||||
if (const VariadicTypePack* vtp = tp
|
||||
? get<VariadicTypePack>(
|
||||
FFlag::LuauMissingFollowMappedGenericPacks ? follow(tp->tail) : tp->tail)
|
||||
: nullptr; vtp && vtp->hidden)
|
||||
{
|
||||
TypePackId taillessTp = arena->addTypePack(tp->head);
|
||||
results.push_back(isCovariantWith(env, subTailPack, taillessTp, scope)
|
||||
|
|
|
@ -1916,7 +1916,7 @@ std::string dump(DenseHashMap<TypeId, TypeId>& types)
|
|||
ToStringOptions& opts = dumpOptions();
|
||||
for (const auto& [key, value] : types)
|
||||
{
|
||||
if (s.length() == 1)
|
||||
if (s.length() > 1)
|
||||
s += ", ";
|
||||
s += toString(key, opts) + " : " + toString(value, opts);
|
||||
}
|
||||
|
@ -1930,7 +1930,7 @@ std::string dump(DenseHashMap<TypePackId, TypePackId>& types)
|
|||
ToStringOptions& opts = dumpOptions();
|
||||
for (const auto& [key, value] : types)
|
||||
{
|
||||
if (s.length() == 1)
|
||||
if (s.length() > 1)
|
||||
s += ", ";
|
||||
s += toString(key, opts) + " : " + toString(value, opts);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,8 @@ LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
|||
LUAU_FASTFLAG(LuauInferActualIfElseExprType)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictSuppressSoloConstraintSolvingIncomplete)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauIceLess)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -1551,7 +1553,15 @@ void TypeChecker2::visitCall(AstExprCall* call)
|
|||
{
|
||||
AstExprIndexName* indexExpr = call->func->as<AstExprIndexName>();
|
||||
if (!indexExpr)
|
||||
{
|
||||
if (FFlag::LuauIceLess)
|
||||
{
|
||||
reportError(InternalError{"method call expression has no 'self'"}, call->location);
|
||||
return;
|
||||
}
|
||||
else
|
||||
ice->ice("method call expression has no 'self'");
|
||||
}
|
||||
|
||||
args.head.push_back(lookupType(indexExpr->expr));
|
||||
argExprs.push_back(indexExpr->expr);
|
||||
|
@ -1950,12 +1960,26 @@ void TypeChecker2::visit(AstExprFunction* fn)
|
|||
}
|
||||
else if (!normalizedFnTy->hasFunctions())
|
||||
{
|
||||
if (FFlag::LuauIceLess)
|
||||
{
|
||||
reportError(InternalError{"Internal error: Lambda has non-function type " + toString(inferredFnTy)}, fn->location);
|
||||
return;
|
||||
}
|
||||
else
|
||||
ice->ice("Internal error: Lambda has non-function type " + toString(inferredFnTy), fn->location);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (1 != normalizedFnTy->functions.parts.size())
|
||||
{
|
||||
if (FFlag::LuauIceLess)
|
||||
{
|
||||
reportError(InternalError{"Unexpected: Lambda has unexpected type " + toString(inferredFnTy)}, fn->location);
|
||||
return;
|
||||
}
|
||||
else
|
||||
ice->ice("Unexpected: Lambda has unexpected type " + toString(inferredFnTy), fn->location);
|
||||
}
|
||||
|
||||
const FunctionType* inferredFtv = get<FunctionType>(normalizedFnTy->functions.parts.front());
|
||||
LUAU_ASSERT(inferredFtv);
|
||||
|
@ -2591,6 +2615,11 @@ TypeId TypeChecker2::flattenPack(TypePackId pack)
|
|||
return builtinTypes->errorType;
|
||||
else if (finite(pack) && size(pack) == 0)
|
||||
return builtinTypes->nilType; // `(f())` where `f()` returns no values is coerced into `nil`
|
||||
else if (FFlag::LuauIceLess)
|
||||
{
|
||||
reportError(InternalError{"flattenPack got a weird pack!"}, Location{});
|
||||
return builtinTypes->errorType; // todo test this
|
||||
}
|
||||
else
|
||||
ice->ice("flattenPack got a weird pack!");
|
||||
}
|
||||
|
@ -2648,7 +2677,7 @@ void TypeChecker2::visit(AstTypeReference* ty)
|
|||
{
|
||||
// No further validation is necessary in this case. The main logic for
|
||||
// _luau_print is contained in lookupAnnotation.
|
||||
if (FFlag::DebugLuauMagicTypes && (ty->name == kLuauPrint || ty->name == kLuauForceConstraintSolvingIncomplete))
|
||||
if (FFlag::DebugLuauMagicTypes && (ty->name == kLuauPrint || ty->name == kLuauForceConstraintSolvingIncomplete || ty->name == kLuauBlockedType))
|
||||
return;
|
||||
|
||||
for (const AstTypeOrPack& param : ty->parameters)
|
||||
|
@ -2938,7 +2967,15 @@ Reasonings TypeChecker2::explainReasonings_(TID subTy, TID superTy, Location loc
|
|||
: traverse_DEPRECATED(superTy, reasoning.superPath, builtinTypes);
|
||||
|
||||
if (!optSubLeaf || !optSuperLeaf)
|
||||
{
|
||||
if (FFlag::LuauIceLess)
|
||||
{
|
||||
reportError(InternalError{"Subtyping test returned a reasoning with an invalid path"}, location);
|
||||
return {}; // TOOD test this
|
||||
}
|
||||
else
|
||||
ice->ice("Subtyping test returned a reasoning with an invalid path", location);
|
||||
}
|
||||
|
||||
const TypeOrPack& subLeaf = *optSubLeaf;
|
||||
const TypeOrPack& superLeaf = *optSuperLeaf;
|
||||
|
@ -2950,7 +2987,15 @@ Reasonings TypeChecker2::explainReasonings_(TID subTy, TID superTy, Location loc
|
|||
auto superLeafTp = get<TypePackId>(superLeaf);
|
||||
|
||||
if (!subLeafTy && !superLeafTy && !subLeafTp && !superLeafTp)
|
||||
{
|
||||
if (FFlag::LuauIceLess)
|
||||
{
|
||||
reportError(InternalError{"Subtyping test returned a reasoning where one path ends at a type and the other ends at a pack."}, location);
|
||||
return {}; // TODO test this?
|
||||
}
|
||||
else
|
||||
ice->ice("Subtyping test returned a reasoning where one path ends at a type and the other ends at a pack.", location);
|
||||
}
|
||||
|
||||
std::string relation = "a subtype of";
|
||||
if (reasoning.variance == SubtypingVariance::Invariant)
|
||||
|
|
|
@ -592,4 +592,18 @@ TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstGenericTypePackWithDefault")
|
|||
CHECK(toJson(root->body.data[0]) == expected);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(JsonEncoderFixture, "encode_AstTypeOptional")
|
||||
{
|
||||
AstStatBlock* root = expectParse(R"(
|
||||
type Foo = string?
|
||||
)");
|
||||
|
||||
CHECK(1 == root->body.size);
|
||||
|
||||
std::string_view expected =
|
||||
R"({"type":"AstStatTypeAlias","location":"1,12 - 1,30","name":"Foo","generics":[],"genericPacks":[],"value":{"type":"AstTypeUnion","location":"1,23 - 1,30","types":[{"type":"AstTypeReference","location":"1,23 - 1,29","name":"string","nameLocation":"1,23 - 1,29","parameters":[]},{"type":"AstTypeOptional","location":"1,29 - 1,30"}]},"exported":false})";
|
||||
|
||||
CHECK(toJson(root->body.data[0]) == expected);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
|
||||
|
||||
struct DataFlowGraphFixture
|
||||
{
|
||||
|
@ -129,8 +128,6 @@ TEST_CASE_FIXTURE(DataFlowGraphFixture, "phi")
|
|||
|
||||
TEST_CASE_FIXTURE(DataFlowGraphFixture, "mutate_local_not_owned_by_while")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
|
||||
dfg(R"(
|
||||
local x
|
||||
|
||||
|
@ -170,8 +167,6 @@ TEST_CASE_FIXTURE(DataFlowGraphFixture, "mutate_local_owned_by_while")
|
|||
|
||||
TEST_CASE_FIXTURE(DataFlowGraphFixture, "mutate_local_not_owned_by_repeat")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
|
||||
dfg(R"(
|
||||
local x
|
||||
|
||||
|
@ -210,8 +205,6 @@ TEST_CASE_FIXTURE(DataFlowGraphFixture, "mutate_local_owned_by_repeat")
|
|||
|
||||
TEST_CASE_FIXTURE(DataFlowGraphFixture, "mutate_local_not_owned_by_for")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
|
||||
dfg(R"(
|
||||
local x
|
||||
|
||||
|
@ -251,8 +244,6 @@ TEST_CASE_FIXTURE(DataFlowGraphFixture, "mutate_local_owned_by_for")
|
|||
|
||||
TEST_CASE_FIXTURE(DataFlowGraphFixture, "mutate_local_not_owned_by_for_in")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
|
||||
dfg(R"(
|
||||
local x
|
||||
|
||||
|
@ -292,8 +283,6 @@ TEST_CASE_FIXTURE(DataFlowGraphFixture, "mutate_local_owned_by_for_in")
|
|||
|
||||
TEST_CASE_FIXTURE(DataFlowGraphFixture, "mutate_preexisting_property_not_owned_by_while")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
|
||||
dfg(R"(
|
||||
local t = {}
|
||||
t.x = 5
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
LUAU_FASTFLAG(LuauNewNonStrictFixGenericTypePacks)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictMoreUnknownSymbols)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictNoErrorsPassingNever)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictSuppressesDynamicRequireErrors)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -814,5 +815,51 @@ TEST_CASE_FIXTURE(Fixture, "unknown_globals_in_one_sided_conditionals")
|
|||
CHECK_EQ(err->context, UnknownSymbol::Context::Binding);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "new_non_strict_should_suppress_dynamic_require_errors")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauNewNonStrictSuppressesDynamicRequireErrors, true}};
|
||||
// Avoid warning about dynamic requires in new nonstrict mode
|
||||
CheckResult result = check(Mode::Nonstrict, R"(
|
||||
function passThrough(module)
|
||||
require(module)
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(0, result);
|
||||
// We should still warn about dynamic requires in strict mode
|
||||
result = check(Mode::Strict, R"(
|
||||
function passThrough(module)
|
||||
require(module)
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
const UnknownRequire* req = get<UnknownRequire>(result.errors[0]);
|
||||
CHECK(req != nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "new_non_strict_should_suppress_unknown_require_errors")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauNewNonStrictSuppressesDynamicRequireErrors, true}};
|
||||
|
||||
// Avoid warning about dynamic requires in new nonstrict mode
|
||||
CheckResult result = check(Mode::Nonstrict, R"(
|
||||
require(script.NonExistent)
|
||||
require("@self/NonExistent")
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(0, result);
|
||||
// We should still warn about dynamic requires in strict mode
|
||||
result = check(Mode::Strict, R"(
|
||||
require(script.NonExistent)
|
||||
require("@self/NonExistent")
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
const UnknownRequire* req1 = get<UnknownRequire>(result.errors[0]);
|
||||
CHECK(req1 != nullptr);
|
||||
const UnknownRequire* req2 = get<UnknownRequire>(result.errors[1]);
|
||||
CHECK(req2 != nullptr);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -17,11 +17,15 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTINT(LuauSolverConstraintLimit)
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauIceLess)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauSimplifyAnyAndUnion)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving)
|
||||
|
||||
struct LimitFixture : BuiltinsFixture
|
||||
{
|
||||
|
@ -333,4 +337,36 @@ TEST_CASE_FIXTURE(LimitFixture, "Signal_exerpt" * doctest::timeout(0.5))
|
|||
(void)result;
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "limit_number_of_dynamically_created_constraints")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauLimitDynamicConstraintSolving, true},
|
||||
};
|
||||
|
||||
constexpr const char* src = R"(
|
||||
type Array<T> = {T}
|
||||
|
||||
type Hello = Array<Array<Array<Array<Array<Array<Array<Array<Array<Array<number>>>>>>>>>>
|
||||
)";
|
||||
|
||||
{
|
||||
ScopedFastInt sfi{FInt::LuauSolverConstraintLimit, 1};
|
||||
CheckResult result = check(src);
|
||||
LUAU_CHECK_ERROR(result, CodeTooComplex);
|
||||
}
|
||||
|
||||
{
|
||||
ScopedFastInt sfi{FInt::LuauSolverConstraintLimit, 1000};
|
||||
CheckResult result = check(src);
|
||||
LUAU_CHECK_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
{
|
||||
ScopedFastInt sfi{FInt::LuauSolverConstraintLimit, 0};
|
||||
CheckResult result = check(src);
|
||||
LUAU_CHECK_NO_ERRORS(result);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferAnyError");
|
||||
|
@ -305,8 +304,6 @@ TEST_CASE_FIXTURE(Fixture, "chain_calling_error_type_yields_error")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "replace_every_free_type_when_unifying_a_complex_function_with_any")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local a: any
|
||||
local b
|
||||
|
|
|
@ -23,6 +23,7 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
LUAU_FASTINT(LuauTarjanChildLimit)
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauCollapseShouldNotCrash)
|
||||
LUAU_FASTFLAG(LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
LUAU_FASTFLAG(LuauFormatUseLastPosition)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
||||
|
@ -3306,4 +3307,42 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "generic_function_statement")
|
|||
CHECK_EQ("a", toString(requireTypeAtPosition({9, 21})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "function_calls_should_not_crash")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
// crash only happens right now with eager generalization off
|
||||
{FFlag::LuauEagerGeneralization4, false},
|
||||
{FFlag::LuauCollapseShouldNotCrash, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
return {
|
||||
StartAPI = function()
|
||||
local pointers = {}
|
||||
local API = {}
|
||||
local function getRealEnvResult(PointerOrPath)
|
||||
if pointers[PointerOrPath] then
|
||||
return pointers[PointerOrPath]
|
||||
end
|
||||
end
|
||||
API.OnInvoke = function()
|
||||
local realEnvResult, isResultPointer = getRealEnvResult(FunctionInEnvToRunPath)
|
||||
return realEnvResult(table.unpack(args, 2, args.n))
|
||||
if TableInEnvPath and type(TableInEnvPath) == 'string' then
|
||||
local realEnvResult, isResultPointer = getRealEnvResult(TableInEnvPath)
|
||||
return getmetatable(realEnvResult)
|
||||
end
|
||||
local realEnvResult, isResultPointer = getRealEnvResult(TableInEnvPath)
|
||||
local metaTableInEnv = getmetatable(realEnvResult)
|
||||
local result = metaTableInEnv[FuncToRun](realEnvResult,table.unpack(args, 3, args.n))
|
||||
end
|
||||
end
|
||||
}
|
||||
)");
|
||||
|
||||
// no expected behavior here beyond not crashing
|
||||
}
|
||||
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -16,7 +16,6 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
||||
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferLoops");
|
||||
|
||||
|
@ -183,10 +182,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_next")
|
|||
}
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_loop_with_next_and_multiple_elements")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSimplifyOutOfLine2, true},
|
||||
{FFlag::LuauDfgAllowUpdatesInLoops, true},
|
||||
};
|
||||
ScopedFastFlag _{FFlag::LuauSimplifyOutOfLine2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local n
|
||||
|
@ -1106,8 +1102,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dcr_iteration_on_never_gives_never")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local iter: never
|
||||
local ans
|
||||
|
@ -1329,8 +1323,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_require")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "oss_1480")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
type Part = { Parent: Part? }
|
||||
type Instance = Part
|
||||
|
@ -1346,8 +1338,6 @@ TEST_CASE_FIXTURE(Fixture, "oss_1480")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1413")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local function KahanSum(values: {number}): number
|
||||
local sum: number = 0
|
||||
|
@ -1401,10 +1391,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "while_loop_error_in_body")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauDfgAllowUpdatesInLoops, true},
|
||||
};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local function foo()
|
||||
local x = ""
|
||||
|
@ -1421,10 +1407,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "while_loop_error_in_body")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "while_loop_assign_different_type")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauDfgAllowUpdatesInLoops, true},
|
||||
};
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local function takesString(_: string) end
|
||||
|
@ -1445,8 +1428,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "while_loop_assign_different_type")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "repeat_loop_assignment")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local x = nil
|
||||
repeat
|
||||
|
@ -1460,8 +1441,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "repeat_loop_assignment")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "repeat_loop_assignment_with_break")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local x = nil
|
||||
repeat
|
||||
|
@ -1475,8 +1454,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "repeat_loop_assignment_with_break")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "repeat_unconditionally_fires_error")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local x = nil
|
||||
repeat
|
||||
|
@ -1495,8 +1472,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "repeat_is_linearish")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local x = nil
|
||||
if math.random () > 0.5 then
|
||||
|
@ -1515,10 +1490,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "repeat_is_linearish")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "ensure_local_in_loop_does_not_escape")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauDfgAllowUpdatesInLoops, true},
|
||||
};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local x = 42
|
||||
repeat
|
||||
|
|
|
@ -14,6 +14,8 @@ LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -847,4 +849,22 @@ return wrapper(test2, 1, "")
|
|||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "internal_types_are_scrubbed_from_module")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::DebugLuauMagicTypes, true},
|
||||
{FFlag::LuauLimitDynamicConstraintSolving, true}
|
||||
};
|
||||
|
||||
fileResolver.source["game/A"] = R"(
|
||||
return function(): _luau_blocked_type return nil :: any end
|
||||
)";
|
||||
|
||||
CheckResult result = getFrontend().check("game/A");
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK(get<InternalError>(result.errors[0]));
|
||||
CHECK("(...any) -> *error-type*" == toString(getFrontend().moduleResolver.getModule("game/A")->returnType));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -18,7 +18,6 @@ LUAU_FASTINT(LuauTarjanChildLimit)
|
|||
LUAU_FASTINT(LuauTypeInferIterationLimit)
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTINT(LuauTypeInferTypePackLoopLimit)
|
||||
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
|
||||
LUAU_FASTFLAG(LuauSolverAgnosticStringification)
|
||||
|
||||
TEST_SUITE_BEGIN("ProvisionalTests");
|
||||
|
@ -1340,10 +1339,8 @@ TEST_CASE_FIXTURE(Fixture, "we_cannot_infer_functions_that_return_inconsistently
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "loop_unsoundness")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauDfgAllowUpdatesInLoops, true},
|
||||
};
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
|
||||
// This is a tactical unsoundness we're introducing to resolve issues around
|
||||
// cyclic types. You can see that if this loop were to run more than once,
|
||||
// we'd error as we'd try to call a number.
|
||||
|
|
|
@ -20,7 +20,9 @@ LUAU_FASTFLAG(LuauNormalizationReorderFreeTypeIntersect)
|
|||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||
LUAU_FASTFLAG(LuauRefineNoRefineAlways)
|
||||
LUAU_FASTFLAG(LuauDoNotPrototypeTableIndex)
|
||||
LUAU_FASTFLAG(LuauForceSimplifyConstraint)
|
||||
LUAU_FASTFLAG(LuauForceSimplifyConstraint2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -2251,7 +2253,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "luau_polyfill_isindexkey_refine_conjunction"
|
|||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauStuckTypeFunctionsStillDispatch, true},
|
||||
{FFlag::LuauForceSimplifyConstraint, true},
|
||||
{FFlag::LuauForceSimplifyConstraint2, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -2900,4 +2902,31 @@ TEST_CASE_FIXTURE(Fixture, "cli_120460_table_access_on_phi_node")
|
|||
)"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "force_simplify_constraint_doesnt_drop_blocked_type")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
{FFlag::LuauForceSimplifyConstraint2, true},
|
||||
{FFlag::LuauSimplifyOutOfLine2, true},
|
||||
};
|
||||
|
||||
CheckResult results = check(R"(
|
||||
local function track(instance): boolean
|
||||
local isBasePart = instance:IsA("BasePart")
|
||||
local isCharacter = false
|
||||
if not isBasePart then
|
||||
isCharacter = instance:FindFirstChildOfClass("Humanoid") and instance:FindFirstChild("HumanoidRootPart")
|
||||
end
|
||||
-- A verison of `SimplifyConstraint` mucked up the fact that this
|
||||
-- is `boolean | and<unknown, unknown>`, and claimed it was only
|
||||
-- `boolean`.
|
||||
return isCharacter
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, results);
|
||||
REQUIRE(get<TypeMismatch>(results.errors[0]));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -35,10 +35,12 @@ LUAU_FASTFLAG(LuauInferPolarityOfReadWriteProperties)
|
|||
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAG(LuauInferActualIfElseExprType)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauForceSimplifyConstraint)
|
||||
LUAU_FASTFLAG(LuauForceSimplifyConstraint2)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictSuppressSoloConstraintSolvingIncomplete)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
LUAU_FASTFLAG(LuauMissingFollowMappedGenericPacks)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -1902,7 +1904,6 @@ end
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "fuzzer_derived_unsound_loops")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauDfgAllowUpdatesInLoops, true};
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
for _ in ... do
|
||||
repeat
|
||||
|
@ -2529,7 +2530,7 @@ TEST_CASE_FIXTURE(Fixture, "simplify_constraint_can_force")
|
|||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauForceSimplifyConstraint, true},
|
||||
{FFlag::LuauForceSimplifyConstraint2, true},
|
||||
{FFlag::LuauSimplifyOutOfLine2, true},
|
||||
// NOTE: Feel free to clip this test when this flag is clipped.
|
||||
{FFlag::LuauPushFunctionTypesInFunctionStatement, false},
|
||||
|
@ -2589,4 +2590,48 @@ TEST_CASE_FIXTURE(Fixture, "non_standalone_constraint_solving_incomplete_is_hidd
|
|||
CHECK(get<TypeMismatch>(results.errors[1]));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "fuzzer_missing_type_pack_follow")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauReturnMappedGenericPacksFromSubtyping2, true},
|
||||
{FFlag::LuauMissingFollowMappedGenericPacks, true},
|
||||
};
|
||||
|
||||
LUAU_REQUIRE_ERRORS(check(R"(
|
||||
local _ = {[0]=_,}
|
||||
while _ do
|
||||
do
|
||||
local l2 = require(module0)
|
||||
end
|
||||
end
|
||||
do end
|
||||
function _(l0:typeof(_),l0,l0)
|
||||
local l0 = require(module0)
|
||||
_()(l0(),_,_(_())((_)))
|
||||
do end
|
||||
end
|
||||
_()(_(if nil then _))("",_,_(_,(_)))
|
||||
do end
|
||||
)"));
|
||||
|
||||
LUAU_REQUIRE_ERRORS(check(R"(
|
||||
local _ = {_,}
|
||||
while _ do
|
||||
do
|
||||
do end
|
||||
end
|
||||
end
|
||||
_ = nil
|
||||
function _(l0,l0,l0)
|
||||
local l0 = require(module0)
|
||||
_()(_(),_,_(_())(_,true)(_,_),l0)
|
||||
do end
|
||||
end
|
||||
_()(_())("",_.n0,_,_(_,true,(_)))
|
||||
do end
|
||||
)"));
|
||||
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -710,7 +709,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refinement_through_erroring")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "refinement_through_erroring_in_loop")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauDfgAllowUpdatesInLoops, true}};
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
|
|
@ -9,7 +9,7 @@ using namespace Luau;
|
|||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4);
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch);
|
||||
LUAU_FASTFLAG(LuauForceSimplifyConstraint)
|
||||
LUAU_FASTFLAG(LuauForceSimplifyConstraint2)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferUnknownNever");
|
||||
|
||||
|
@ -333,7 +333,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_unify_operands_if_one_of_the_operand_is_never_i
|
|||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauStuckTypeFunctionsStillDispatch, true},
|
||||
{FFlag::LuauForceSimplifyConstraint, true},
|
||||
{FFlag::LuauForceSimplifyConstraint2, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
|
Loading…
Add table
Reference in a new issue