mirror of
https://github.com/luau-lang/luau.git
synced 2025-08-26 11:27:08 +01:00
Sync to upstream/release/686 (#1948)
## General This week has been spent mostly on fixing bugs in incremental autocomplete as well as making the new Type Solver more stable. - Fixes a bug where registered "require" aliases were case-sensitive instead of case-insensitive. ### New Type Solver - Adjust literal sub typing logic to account for unreduced type functions - Implement a number of subtyping stack utilization improvements - Emit a single error if an internal type escapes a module's interface - Checked function errors in the New Non Strict warn about incorrect argument use with one-indexed positions, e.g. `argument #1 was used incorrectly` instead of `argument #0 was used incorrectly`. - Improvements to type function reduction that let us progress further while reducing - Augment the generalization system to not emit duplicate constraints. - Fix a bug where we didn't seal tables in modules that failed to complete typechecking. ### Fragment Autocomplete - Provide richer autocomplete suggestions inside of for loops - Provide richer autocomplete suggestions inside of interpolated string expressions - Improve the quality of error messages when typing out interpolated strings. ### Compiler - Fixes REX encoding of extended byte registers for the x86 assembly code generation. - Fixes for table shape constant data encoding --- 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: Varun Saini <vsaini@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
This commit is contained in:
parent
f3f3bf8f72
commit
8863bfc950
88 changed files with 2100 additions and 3208 deletions
|
@ -337,9 +337,6 @@ struct Constraint
|
|||
|
||||
std::vector<NotNull<Constraint>> dependencies;
|
||||
|
||||
// Clip with LuauUseOrderedTypeSetsInConstraints
|
||||
DenseHashSet<TypeId> getMaybeMutatedFreeTypes_DEPRECATED() const;
|
||||
|
||||
TypeIds getMaybeMutatedFreeTypes() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "Luau/Normalize.h"
|
||||
#include "Luau/OrderedSet.h"
|
||||
#include "Luau/Substitution.h"
|
||||
#include "Luau/SubtypingVariance.h"
|
||||
#include "Luau/ToString.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeCheckLimits.h"
|
||||
|
@ -41,6 +42,20 @@ struct HashBlockedConstraintId
|
|||
size_t operator()(const BlockedConstraintId& bci) const;
|
||||
};
|
||||
|
||||
struct SubtypeConstraintRecord
|
||||
{
|
||||
TypeId subTy = nullptr;
|
||||
TypeId superTy = nullptr;
|
||||
SubtypingVariance variance = SubtypingVariance::Invalid;
|
||||
|
||||
bool operator==(const SubtypeConstraintRecord& other) const;
|
||||
};
|
||||
|
||||
struct HashSubtypeConstraintRecord
|
||||
{
|
||||
size_t operator()(const SubtypeConstraintRecord& c) const;
|
||||
};
|
||||
|
||||
struct ModuleResolver;
|
||||
|
||||
struct InstantiationSignature
|
||||
|
@ -127,16 +142,14 @@ struct ConstraintSolver
|
|||
// A mapping from free types to the number of unresolved constraints that mention them.
|
||||
DenseHashMap<TypeId, size_t> unresolvedConstraints{{}};
|
||||
|
||||
// Clip with LuauUseOrderedTypeSetsInConstraints
|
||||
std::unordered_map<NotNull<const Constraint>, DenseHashSet<TypeId>> maybeMutatedFreeTypes_DEPRECATED;
|
||||
std::unordered_map<TypeId, DenseHashSet<const Constraint*>> mutatedFreeTypeToConstraint_DEPRECATED;
|
||||
|
||||
std::unordered_map<NotNull<const Constraint>, TypeIds> maybeMutatedFreeTypes;
|
||||
std::unordered_map<TypeId, OrderedSet<const Constraint*>> mutatedFreeTypeToConstraint;
|
||||
|
||||
// Irreducible/uninhabited type functions or type pack functions.
|
||||
DenseHashSet<const void*> uninhabitedTypeFunctions{{}};
|
||||
|
||||
DenseHashMap<SubtypeConstraintRecord, Constraint*, HashSubtypeConstraintRecord> seenConstraints{{}};
|
||||
|
||||
// The set of types that will definitely be unchanged by generalization.
|
||||
DenseHashSet<TypeId> generalizedTypes_{nullptr};
|
||||
const NotNull<DenseHashSet<TypeId>> generalizedTypes{&generalizedTypes_};
|
||||
|
|
|
@ -93,9 +93,6 @@ struct DfgScope
|
|||
std::optional<DefId> lookup(DefId def, const std::string& key) const;
|
||||
|
||||
void inherit(const DfgScope* childScope);
|
||||
|
||||
bool canUpdateDefinition(Symbol symbol) const;
|
||||
bool canUpdateDefinition(DefId def, const std::string& key) const;
|
||||
};
|
||||
|
||||
struct DataFlowResult
|
||||
|
@ -133,7 +130,6 @@ private:
|
|||
/// A stack of scopes used by the visitor to see where we are.
|
||||
ScopeStack scopeStack;
|
||||
NotNull<DfgScope> currentScope();
|
||||
DfgScope* currentScope_DEPRECATED();
|
||||
|
||||
struct FunctionCapture
|
||||
{
|
||||
|
|
|
@ -75,7 +75,6 @@ struct FragmentAutocompleteResult
|
|||
{
|
||||
ModulePtr incrementalModule;
|
||||
Scope* freshScope;
|
||||
TypeArena arenaForAutocomplete_DEPRECATED;
|
||||
AutocompleteResult acResults;
|
||||
};
|
||||
|
||||
|
|
|
@ -170,6 +170,8 @@ struct Frontend
|
|||
double timeParse = 0;
|
||||
double timeCheck = 0;
|
||||
double timeLint = 0;
|
||||
|
||||
size_t dynamicConstraintsCreated = 0;
|
||||
};
|
||||
|
||||
Frontend(FileResolver* fileResolver, ConfigResolver* configResolver, const FrontendOptions& options = {});
|
||||
|
@ -243,6 +245,7 @@ private:
|
|||
std::optional<ScopePtr> environmentScope,
|
||||
bool forAutocomplete,
|
||||
bool recordJsonLog,
|
||||
Frontend::Stats& stats,
|
||||
TypeCheckLimits typeCheckLimits
|
||||
);
|
||||
|
||||
|
@ -333,6 +336,7 @@ ModulePtr check(
|
|||
FrontendOptions options,
|
||||
TypeCheckLimits limits,
|
||||
bool recordJsonLog,
|
||||
Frontend::Stats& stats,
|
||||
std::function<void(const ModuleName&, std::string)> writeJsonLog
|
||||
);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "Luau/DenseHash.h"
|
||||
#include "Luau/EqSatSimplification.h"
|
||||
#include "Luau/Set.h"
|
||||
#include "Luau/SubtypingVariance.h"
|
||||
#include "Luau/TypeCheckLimits.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/TypeFwd.h"
|
||||
|
@ -32,17 +33,6 @@ struct TableIndexer;
|
|||
struct TypeArena;
|
||||
struct TypeCheckLimits;
|
||||
|
||||
enum class SubtypingVariance
|
||||
{
|
||||
// Used for an empty key. Should never appear in actual code.
|
||||
Invalid,
|
||||
Covariant,
|
||||
// This is used to identify cases where we have a covariant + a
|
||||
// contravariant reason and we need to merge them.
|
||||
Contravariant,
|
||||
Invariant,
|
||||
};
|
||||
|
||||
struct SubtypingReasoning
|
||||
{
|
||||
// The path, relative to the _root subtype_, where subtyping failed.
|
||||
|
@ -327,6 +317,12 @@ private:
|
|||
|
||||
[[noreturn]] void unexpected(TypeId ty);
|
||||
[[noreturn]] void unexpected(TypePackId tp);
|
||||
|
||||
SubtypingResult trySemanticSubtyping(SubtypingEnvironment& env,
|
||||
TypeId subTy,
|
||||
TypeId superTy,
|
||||
NotNull<Scope> scope,
|
||||
SubtypingResult& original);
|
||||
};
|
||||
|
||||
} // namespace Luau
|
||||
|
|
19
Analysis/include/Luau/SubtypingVariance.h
Normal file
19
Analysis/include/Luau/SubtypingVariance.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
enum class SubtypingVariance
|
||||
{
|
||||
// Used for an empty key. Should never appear in actual code.
|
||||
Invalid,
|
||||
Covariant,
|
||||
// This is used to identify cases where we have a covariant + a
|
||||
// contravariant reason and we need to merge them.
|
||||
Contravariant,
|
||||
Invariant,
|
||||
};
|
||||
|
||||
}
|
|
@ -130,7 +130,6 @@ struct TypeChecker
|
|||
const PredicateVec& predicates = {}
|
||||
);
|
||||
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprBinary& expr, std::optional<TypeId> expectedType = std::nullopt);
|
||||
WithPredicate<TypeId> checkExpr_DEPRECATED(const ScopePtr& scope, const AstExprBinary& expr, std::optional<TypeId> expectedType = std::nullopt);
|
||||
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprTypeAssertion& expr);
|
||||
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprError& expr);
|
||||
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprIfElse& expr, std::optional<TypeId> expectedType = std::nullopt);
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include <algorithm>
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -526,7 +525,7 @@ static std::optional<DocumentationSymbol> getMetatableDocumentation(
|
|||
return std::nullopt;
|
||||
|
||||
TypeId followed;
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
if (indexIt->second.readTy)
|
||||
followed = follow(*indexIt->second.readTy);
|
||||
|
|
|
@ -21,11 +21,9 @@
|
|||
#include <utility>
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTINT(LuauTypeInferIterationLimit)
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauMagicVariableNames)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAutocompleteMissingFollows)
|
||||
LUAU_FASTFLAG(LuauImplicitTableIndexerKeys3)
|
||||
|
||||
static const std::unordered_set<std::string> kStatementStartingKeywords =
|
||||
|
@ -79,7 +77,6 @@ static ParenthesesRecommendation getParenRecommendationForIntersect(const Inters
|
|||
ParenthesesRecommendation rec = ParenthesesRecommendation::None;
|
||||
for (Luau::TypeId partId : intersect->parts)
|
||||
{
|
||||
if (FFlag::LuauAutocompleteMissingFollows)
|
||||
partId = follow(partId);
|
||||
if (auto partFunc = Luau::get<FunctionType>(partId))
|
||||
{
|
||||
|
@ -370,7 +367,7 @@ static void autocompleteProps(
|
|||
if (indexIt != mtable->props.end())
|
||||
{
|
||||
TypeId followed;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauSolverV2)
|
||||
followed = follow(*indexIt->second.readTy);
|
||||
else
|
||||
followed = follow(indexIt->second.type_DEPRECATED());
|
||||
|
@ -1636,7 +1633,6 @@ static std::optional<AutocompleteEntryMap> autocompleteStringParams(
|
|||
{
|
||||
for (TypeId part : intersect->parts)
|
||||
{
|
||||
if (FFlag::LuauAutocompleteMissingFollows)
|
||||
part = follow(part);
|
||||
if (auto candidateFunctionType = Luau::get<FunctionType>(part))
|
||||
{
|
||||
|
|
|
@ -33,9 +33,7 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTableCloneClonesType3)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStringFormatImprovements)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUpdateSetMetatableTypeSignature)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUpdateGetMetatableTypeSignature)
|
||||
LUAU_FASTFLAG(LuauUseWorkspacePropToChooseSolver)
|
||||
|
@ -339,14 +337,8 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
|
|||
auto it = stringMetatableTable->props.find("__index");
|
||||
LUAU_ASSERT(it != stringMetatableTable->props.end());
|
||||
|
||||
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
addGlobalBinding(globals, "string", *it->second.readTy, "@luau");
|
||||
addGlobalBinding(globals, "string", *it->second.writeTy, "@luau");
|
||||
}
|
||||
else
|
||||
addGlobalBinding(globals, "string", it->second.type_DEPRECATED(), "@luau");
|
||||
|
||||
// Setup 'vector' metatable
|
||||
if (auto it = globals.globalScope->exportedTypeBindings.find("vector"); it != globals.globalScope->exportedTypeBindings.end())
|
||||
|
@ -504,21 +496,11 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
|
|||
ttv->props["foreach"].deprecated = true;
|
||||
ttv->props["foreachi"].deprecated = true;
|
||||
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
attachMagicFunction(*ttv->props["pack"].readTy, std::make_shared<MagicPack>());
|
||||
if (FFlag::LuauTableCloneClonesType3)
|
||||
attachMagicFunction(*ttv->props["clone"].readTy, std::make_shared<MagicClone>());
|
||||
attachMagicFunction(*ttv->props["freeze"].readTy, std::make_shared<MagicFreeze>());
|
||||
}
|
||||
else
|
||||
{
|
||||
attachMagicFunction(ttv->props["pack"].type_DEPRECATED(), std::make_shared<MagicPack>());
|
||||
if (FFlag::LuauTableCloneClonesType3)
|
||||
attachMagicFunction(ttv->props["clone"].type_DEPRECATED(), std::make_shared<MagicClone>());
|
||||
attachMagicFunction(ttv->props["freeze"].type_DEPRECATED(), std::make_shared<MagicFreeze>());
|
||||
}
|
||||
}
|
||||
|
||||
TypeId requireTy = getGlobalBinding(globals, "require");
|
||||
attachTag(requireTy, kRequireTagName);
|
||||
|
@ -665,8 +647,6 @@ bool MagicFormat::infer(const MagicFunctionCallContext& context)
|
|||
{
|
||||
TypeArena* arena = context.solver->arena;
|
||||
|
||||
if (FFlag::LuauStringFormatImprovements)
|
||||
{
|
||||
auto iter = begin(context.arguments);
|
||||
|
||||
// we'll suppress any errors for `string.format` if the format string is error suppressing.
|
||||
|
@ -720,52 +700,8 @@ bool MagicFormat::infer(const MagicFunctionCallContext& context)
|
|||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AstExprConstantString* fmt = nullptr;
|
||||
if (auto index = context.callSite->func->as<AstExprIndexName>(); index && context.callSite->self)
|
||||
{
|
||||
if (auto group = index->expr->as<AstExprGroup>())
|
||||
fmt = group->expr->as<AstExprConstantString>();
|
||||
else
|
||||
fmt = index->expr->as<AstExprConstantString>();
|
||||
}
|
||||
|
||||
if (!context.callSite->self && context.callSite->args.size > 0)
|
||||
fmt = context.callSite->args.data[0]->as<AstExprConstantString>();
|
||||
|
||||
if (!fmt)
|
||||
return false;
|
||||
|
||||
std::vector<TypeId> expected = parseFormatString(context.solver->builtinTypes, fmt->value.data, fmt->value.size);
|
||||
const auto& [params, tail] = flatten(context.arguments);
|
||||
|
||||
size_t paramOffset = 1;
|
||||
|
||||
// unify the prefix one argument at a time - needed if any of the involved types are free
|
||||
for (size_t i = 0; i < expected.size() && i + paramOffset < params.size(); ++i)
|
||||
{
|
||||
context.solver->unify(context.constraint, params[i + paramOffset], expected[i]);
|
||||
}
|
||||
|
||||
// if we know the argument count or if we have too many arguments for sure, we can issue an error
|
||||
size_t numActualParams = params.size();
|
||||
size_t numExpectedParams = expected.size() + 1; // + 1 for the format string
|
||||
|
||||
if (numExpectedParams != numActualParams && (!tail || numExpectedParams < numActualParams))
|
||||
context.solver->reportError(TypeError{context.callSite->location, CountMismatch{numExpectedParams, std::nullopt, numActualParams}});
|
||||
|
||||
// This is invoked at solve time, so we just need to provide a type for the result of :/.format
|
||||
TypePackId resultPack = arena->addTypePack({context.solver->builtinTypes->stringType});
|
||||
asMutable(context.result)->ty.emplace<BoundTypePack>(resultPack);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool MagicFormat::typeCheck(const MagicFunctionTypeCheckContext& context)
|
||||
{
|
||||
if (FFlag::LuauStringFormatImprovements)
|
||||
{
|
||||
auto iter = begin(context.arguments);
|
||||
|
||||
|
@ -849,73 +785,6 @@ bool MagicFormat::typeCheck(const MagicFunctionTypeCheckContext& context)
|
|||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
AstExprConstantString* fmt = nullptr;
|
||||
if (auto index = context.callSite->func->as<AstExprIndexName>(); index && context.callSite->self)
|
||||
{
|
||||
if (auto group = index->expr->as<AstExprGroup>())
|
||||
fmt = group->expr->as<AstExprConstantString>();
|
||||
else
|
||||
fmt = index->expr->as<AstExprConstantString>();
|
||||
}
|
||||
|
||||
if (!context.callSite->self && context.callSite->args.size > 0)
|
||||
fmt = context.callSite->args.data[0]->as<AstExprConstantString>();
|
||||
|
||||
if (!fmt)
|
||||
{
|
||||
context.typechecker->reportError(
|
||||
CountMismatch{1, std::nullopt, 0, CountMismatch::Arg, true, "string.format"}, context.callSite->location
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
// CLI-150726: The block below effectively constructs a type pack and then type checks it by going parameter-by-parameter.
|
||||
// This does _not_ handle cases like:
|
||||
//
|
||||
// local foo : () -> (...string) = (nil :: any)
|
||||
// print(string.format("%s %d %s", foo()))
|
||||
//
|
||||
// ... which should be disallowed.
|
||||
|
||||
std::vector<TypeId> expected = parseFormatString(context.builtinTypes, fmt->value.data, fmt->value.size);
|
||||
|
||||
const auto& [params, tail] = flatten(context.arguments);
|
||||
|
||||
size_t paramOffset = 1;
|
||||
// Compare the expressions passed with the types the function expects to determine whether this function was called with : or .
|
||||
bool calledWithSelf = expected.size() == context.callSite->args.size;
|
||||
// unify the prefix one argument at a time
|
||||
for (size_t i = 0; i < expected.size() && i + paramOffset < params.size(); ++i)
|
||||
{
|
||||
TypeId actualTy = params[i + paramOffset];
|
||||
TypeId expectedTy = expected[i];
|
||||
Location location =
|
||||
context.callSite->args.data[std::min(context.callSite->args.size - 1, i + (calledWithSelf ? 0 : paramOffset))]->location;
|
||||
// use subtyping instead here
|
||||
SubtypingResult result = context.typechecker->subtyping->isSubtype(actualTy, expectedTy, context.checkScope);
|
||||
|
||||
if (!result.isSubtype)
|
||||
{
|
||||
switch (shouldSuppressErrors(NotNull{&context.typechecker->normalizer}, actualTy))
|
||||
{
|
||||
case ErrorSuppression::Suppress:
|
||||
break;
|
||||
case ErrorSuppression::NormalizationFailed:
|
||||
break;
|
||||
case ErrorSuppression::DoNotSuppress:
|
||||
Reasonings reasonings = context.typechecker->explainReasonings(actualTy, expectedTy, location, result);
|
||||
|
||||
if (!reasonings.suppressed)
|
||||
context.typechecker->reportError(TypeMismatch{expectedTy, actualTy, reasonings.toString()}, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<TypeId> parsePatternString(NotNull<BuiltinTypes> builtinTypes, const char* data, size_t size)
|
||||
{
|
||||
|
|
|
@ -17,16 +17,14 @@
|
|||
#include "Luau/UserDefinedTypeFunction.h"
|
||||
#include "Luau/VisitType.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauNotAllBinaryTypeFunsHaveDefaults)
|
||||
LUAU_FASTFLAG(LuauEmptyStringInKeyOf)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAG(LuauUpdateGetMetatableTypeSignature)
|
||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||
LUAU_FASTFLAG(LuauAvoidExcessiveTypeCopying)
|
||||
LUAU_FASTFLAG(LuauOccursCheckForRefinement)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDoNotBlockOnStuckTypeFunctions)
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeFamilyApplicationCartesianProductLimit)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauRefineNoRefineAlways)
|
||||
|
@ -682,6 +680,16 @@ TypeFunctionReductionResult<TypeId> concatTypeFunction(
|
|||
return {ctx->builtins->stringType, Reduction::MaybeOk, {}, {}};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
bool isBlockedOrUnsolvedType(TypeId ty)
|
||||
{
|
||||
if (auto tfit = get<TypeFunctionInstanceType>(ty); tfit && tfit->state == TypeFunctionInstanceState::Unsolved)
|
||||
return true;
|
||||
return is<BlockedType, PendingExpansionType>(ty);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TypeFunctionReductionResult<TypeId> andTypeFunction(
|
||||
TypeId instance,
|
||||
const std::vector<TypeId>& typeParams,
|
||||
|
@ -747,12 +755,22 @@ TypeFunctionReductionResult<TypeId> orTypeFunction(
|
|||
|
||||
// check to see if both operand types are resolved enough, and wait to reduce if not
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (FFlag::LuauDoNotBlockOnStuckTypeFunctions)
|
||||
{
|
||||
if (isBlockedOrUnsolvedType(lhsTy))
|
||||
return {std::nullopt, Reduction::MaybeOk, {lhsTy}, {}};
|
||||
else if (isBlockedOrUnsolvedType(rhsTy))
|
||||
return {std::nullopt, Reduction::MaybeOk, {rhsTy}, {}};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(lhsTy))
|
||||
return {std::nullopt, Reduction::MaybeOk, {lhsTy}, {}};
|
||||
else if (is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(rhsTy))
|
||||
return {std::nullopt, Reduction::MaybeOk, {rhsTy}, {}};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isPending(lhsTy, ctx->solver))
|
||||
|
@ -794,12 +812,22 @@ static TypeFunctionReductionResult<TypeId> comparisonTypeFunction(
|
|||
return {ctx->builtins->neverType, Reduction::MaybeOk, {}, {}};
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (FFlag::LuauDoNotBlockOnStuckTypeFunctions)
|
||||
{
|
||||
if (isBlockedOrUnsolvedType(lhsTy))
|
||||
return {std::nullopt, Reduction::MaybeOk, {lhsTy}, {}};
|
||||
else if (isBlockedOrUnsolvedType(rhsTy))
|
||||
return {std::nullopt, Reduction::MaybeOk, {rhsTy}, {}};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(lhsTy))
|
||||
return {std::nullopt, Reduction::MaybeOk, {lhsTy}, {}};
|
||||
else if (is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(rhsTy))
|
||||
return {std::nullopt, Reduction::MaybeOk, {rhsTy}, {}};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isPending(lhsTy, ctx->solver))
|
||||
|
@ -1302,8 +1330,18 @@ TypeFunctionReductionResult<TypeId> refineTypeFunction(
|
|||
return {targetTy, {}};
|
||||
}
|
||||
|
||||
const bool targetIsPending = FFlag::LuauEagerGeneralization4 ? is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(targetTy)
|
||||
: isPending(targetTy, ctx->solver);
|
||||
bool targetIsPending = false;
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
targetIsPending = FFlag::LuauDoNotBlockOnStuckTypeFunctions
|
||||
? isBlockedOrUnsolvedType(targetTy)
|
||||
: is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(targetTy);
|
||||
}
|
||||
else
|
||||
{
|
||||
targetIsPending = isPending(targetTy, ctx->solver);
|
||||
}
|
||||
|
||||
// check to see if both operand types are resolved enough, and wait to reduce if not
|
||||
if (targetIsPending)
|
||||
|
@ -2133,20 +2171,15 @@ bool searchPropsAndIndexer(
|
|||
if (tblProps.find(stringSingleton->value) != tblProps.end())
|
||||
{
|
||||
|
||||
TypeId propTy;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
Property& prop = tblProps.at(stringSingleton->value);
|
||||
|
||||
TypeId propTy;
|
||||
if (prop.readTy)
|
||||
propTy = follow(*prop.readTy);
|
||||
else if (prop.writeTy)
|
||||
propTy = follow(*prop.writeTy);
|
||||
else // found the property, but there was no type associated with it
|
||||
return false;
|
||||
}
|
||||
else
|
||||
propTy = follow(tblProps.at(stringSingleton->value).type_DEPRECATED());
|
||||
|
||||
// property is a union type -> we need to extend our reduction type
|
||||
if (auto propUnionTy = get<UnionType>(propTy))
|
||||
|
@ -2804,21 +2837,10 @@ void BuiltinTypeFunctions::addToScope(NotNull<TypeArena> arena, NotNull<Scope> s
|
|||
scope->exportedTypeBindings[keyofFunc.name] = mkUnaryTypeFunction(&keyofFunc);
|
||||
scope->exportedTypeBindings[rawkeyofFunc.name] = mkUnaryTypeFunction(&rawkeyofFunc);
|
||||
|
||||
if (FFlag::LuauNotAllBinaryTypeFunsHaveDefaults)
|
||||
{
|
||||
scope->exportedTypeBindings[indexFunc.name] = mkBinaryTypeFunction(&indexFunc);
|
||||
scope->exportedTypeBindings[rawgetFunc.name] = mkBinaryTypeFunction(&rawgetFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
scope->exportedTypeBindings[indexFunc.name] = mkBinaryTypeFunctionWithDefault(&indexFunc);
|
||||
scope->exportedTypeBindings[rawgetFunc.name] = mkBinaryTypeFunctionWithDefault(&rawgetFunc);
|
||||
}
|
||||
|
||||
if (FFlag::LuauNotAllBinaryTypeFunsHaveDefaults)
|
||||
scope->exportedTypeBindings[setmetatableFunc.name] = mkBinaryTypeFunction(&setmetatableFunc);
|
||||
else
|
||||
scope->exportedTypeBindings[setmetatableFunc.name] = mkBinaryTypeFunctionWithDefault(&setmetatableFunc);
|
||||
scope->exportedTypeBindings[getmetatableFunc.name] = mkUnaryTypeFunction(&getmetatableFunc);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,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(LuauSolverAgnosticClone)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -202,8 +201,6 @@ public:
|
|||
|
||||
private:
|
||||
Property shallowClone(const Property& p)
|
||||
{
|
||||
if (FFlag::LuauSolverV2 || FFlag::LuauSolverAgnosticClone)
|
||||
{
|
||||
std::optional<TypeId> cloneReadTy;
|
||||
if (auto ty = p.readTy)
|
||||
|
@ -222,19 +219,6 @@ private:
|
|||
cloned.typeLocation = p.typeLocation;
|
||||
return cloned;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Property{
|
||||
shallowClone(p.type_DEPRECATED()),
|
||||
p.deprecated,
|
||||
p.deprecatedSuggestion,
|
||||
p.location,
|
||||
p.tags,
|
||||
p.documentationSymbol,
|
||||
p.typeLocation,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void cloneChildren(TypeId ty)
|
||||
{
|
||||
|
|
|
@ -18,61 +18,6 @@ Constraint::Constraint(NotNull<Scope> scope, const Location& location, Constrain
|
|||
{
|
||||
}
|
||||
|
||||
struct ReferenceCountInitializer_DEPRECATED : TypeOnceVisitor
|
||||
{
|
||||
DenseHashSet<TypeId>* result;
|
||||
bool traverseIntoTypeFunctions = true;
|
||||
|
||||
explicit ReferenceCountInitializer_DEPRECATED(DenseHashSet<TypeId>* result)
|
||||
: TypeOnceVisitor("ReferenceCountInitializer_DEPRECATED")
|
||||
, result(result)
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const FreeType&) override
|
||||
{
|
||||
result->insert(ty);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const BlockedType&) override
|
||||
{
|
||||
result->insert(ty);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const PendingExpansionType&) override
|
||||
{
|
||||
result->insert(ty);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const TableType& tt) override
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (tt.state == TableState::Unsealed || tt.state == TableState::Free)
|
||||
result->insert(ty);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const ExternType&) override
|
||||
{
|
||||
// ExternTypes never contain free types.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypeId, const TypeFunctionInstanceType& tfit) override
|
||||
{
|
||||
if (FFlag::LuauForceSimplifyConstraint2)
|
||||
return tfit.function->canReduceGenerics;
|
||||
else
|
||||
return FFlag::LuauEagerGeneralization4 && traverseIntoTypeFunctions;
|
||||
}
|
||||
};
|
||||
|
||||
struct ReferenceCountInitializer : TypeOnceVisitor
|
||||
{
|
||||
NotNull<TypeIds> result;
|
||||
|
@ -140,110 +85,6 @@ bool isReferenceCountedType(const TypeId typ)
|
|||
return get<FreeType>(typ) || get<BlockedType>(typ) || get<PendingExpansionType>(typ);
|
||||
}
|
||||
|
||||
DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes_DEPRECATED() const
|
||||
{
|
||||
// For the purpose of this function and reference counting in general, we are only considering
|
||||
// mutations that affect the _bounds_ of the free type, and not something that may bind the free
|
||||
// type itself to a new type. As such, `ReduceConstraint` and `GeneralizationConstraint` have no
|
||||
// contribution to the output set here.
|
||||
|
||||
DenseHashSet<TypeId> types{{}};
|
||||
ReferenceCountInitializer_DEPRECATED rci{&types};
|
||||
|
||||
if (auto ec = get<EqualityConstraint>(*this))
|
||||
{
|
||||
rci.traverse(ec->resultType);
|
||||
// `EqualityConstraints` should not mutate `assignmentType`.
|
||||
}
|
||||
else if (auto sc = get<SubtypeConstraint>(*this))
|
||||
{
|
||||
rci.traverse(sc->subType);
|
||||
rci.traverse(sc->superType);
|
||||
}
|
||||
else if (auto psc = get<PackSubtypeConstraint>(*this))
|
||||
{
|
||||
rci.traverse(psc->subPack);
|
||||
rci.traverse(psc->superPack);
|
||||
}
|
||||
else if (auto itc = get<IterableConstraint>(*this))
|
||||
{
|
||||
for (TypeId ty : itc->variables)
|
||||
rci.traverse(ty);
|
||||
// `IterableConstraints` should not mutate `iterator`.
|
||||
}
|
||||
else if (auto nc = get<NameConstraint>(*this))
|
||||
{
|
||||
rci.traverse(nc->namedType);
|
||||
}
|
||||
else if (auto taec = get<TypeAliasExpansionConstraint>(*this))
|
||||
{
|
||||
rci.traverse(taec->target);
|
||||
}
|
||||
else if (auto fchc = get<FunctionCheckConstraint>(*this))
|
||||
{
|
||||
rci.traverse(fchc->argsPack);
|
||||
}
|
||||
else if (auto fcc = get<FunctionCallConstraint>(*this); fcc && FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
rci.traverseIntoTypeFunctions = false;
|
||||
rci.traverse(fcc->fn);
|
||||
rci.traverse(fcc->argsPack);
|
||||
rci.traverseIntoTypeFunctions = true;
|
||||
}
|
||||
else if (auto ptc = get<PrimitiveTypeConstraint>(*this))
|
||||
{
|
||||
rci.traverse(ptc->freeType);
|
||||
}
|
||||
else if (auto hpc = get<HasPropConstraint>(*this))
|
||||
{
|
||||
rci.traverse(hpc->resultType);
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
rci.traverse(hpc->subjectType);
|
||||
}
|
||||
else if (auto hic = get<HasIndexerConstraint>(*this))
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
rci.traverse(hic->subjectType);
|
||||
rci.traverse(hic->resultType);
|
||||
// `HasIndexerConstraint` should not mutate `indexType`.
|
||||
}
|
||||
else if (auto apc = get<AssignPropConstraint>(*this))
|
||||
{
|
||||
rci.traverse(apc->lhsType);
|
||||
rci.traverse(apc->rhsType);
|
||||
}
|
||||
else if (auto aic = get<AssignIndexConstraint>(*this))
|
||||
{
|
||||
rci.traverse(aic->lhsType);
|
||||
rci.traverse(aic->indexType);
|
||||
rci.traverse(aic->rhsType);
|
||||
}
|
||||
else if (auto uc = get<UnpackConstraint>(*this))
|
||||
{
|
||||
for (TypeId ty : uc->resultPack)
|
||||
rci.traverse(ty);
|
||||
// `UnpackConstraint` should not mutate `sourcePack`.
|
||||
}
|
||||
else if (auto rpc = get<ReducePackConstraint>(*this))
|
||||
{
|
||||
rci.traverse(rpc->tp);
|
||||
}
|
||||
else if (auto tcc = get<TableCheckConstraint>(*this))
|
||||
{
|
||||
rci.traverse(tcc->exprType);
|
||||
}
|
||||
|
||||
if (FFlag::LuauPushFunctionTypesInFunctionStatement)
|
||||
{
|
||||
if (auto pftc = get<PushFunctionTypeConstraint>(*this))
|
||||
{
|
||||
rci.traverse(pftc->functionType);
|
||||
}
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
TypeIds Constraint::getMaybeMutatedFreeTypes() const
|
||||
{
|
||||
// For the purpose of this function and reference counting in general, we are only considering
|
||||
|
|
|
@ -36,21 +36,16 @@ LUAU_FASTINT(LuauCheckRecursionLimit)
|
|||
LUAU_FASTFLAG(DebugLuauLogSolverToJson)
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauGlobalVariableModuleIsolation)
|
||||
LUAU_FASTFLAGVARIABLE(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSimplifyOutOfLine2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDisablePrimitiveInferenceInLargeTables)
|
||||
LUAU_FASTINTVARIABLE(LuauPrimitiveInferenceInTableLimit, 500)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSkipLvalueForCompoundAssignment)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAGVARIABLE(LuauRefineTablesWithReadType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFragmentAutocompleteTracksRValueRefinements)
|
||||
LUAU_FASTFLAGVARIABLE(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAGVARIABLE(LuauInferActualIfElseExprType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauInferActualIfElseExprType2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDoNotPrototypeTableIndex)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTrackFreeInteriorTypePacks)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving3)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -233,6 +228,11 @@ ConstraintGenerator::ConstraintGenerator(
|
|||
, logger(logger)
|
||||
{
|
||||
LUAU_ASSERT(module);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauTrackFreeInteriorTypePacks);
|
||||
}
|
||||
}
|
||||
|
||||
ConstraintSet ConstraintGenerator::run(AstStatBlock* block)
|
||||
|
@ -261,7 +261,7 @@ void ConstraintGenerator::visitModuleRoot(AstStatBlock* block)
|
|||
rootScope->location = block->location;
|
||||
module->astScopes[block] = NotNull{scope.get()};
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
interiorFreeTypes.emplace_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.emplace_back();
|
||||
|
@ -297,7 +297,7 @@ void ConstraintGenerator::visitModuleRoot(AstStatBlock* block)
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
{
|
||||
scope->interiorFreeTypes = std::move(interiorFreeTypes.back().types);
|
||||
scope->interiorFreeTypePacks = std::move(interiorFreeTypes.back().typePacks);
|
||||
|
@ -316,7 +316,7 @@ void ConstraintGenerator::visitModuleRoot(AstStatBlock* block)
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
interiorFreeTypes.pop_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.pop_back();
|
||||
|
@ -354,13 +354,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::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
interiorFreeTypes.emplace_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.emplace_back();
|
||||
visitBlockWithoutChildScope(resumeScope, block);
|
||||
// Post
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
interiorFreeTypes.pop_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.pop_back();
|
||||
|
@ -390,9 +390,12 @@ void ConstraintGenerator::visitFragmentRoot(const ScopePtr& resumeScope, AstStat
|
|||
|
||||
TypeId ConstraintGenerator::freshType(const ScopePtr& scope, Polarity polarity)
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
{
|
||||
auto ft = Luau::freshType(arena, builtinTypes, scope.get(), polarity);
|
||||
const TypeId ft = FFlag::LuauEagerGeneralization4
|
||||
? Luau::freshType(arena, builtinTypes, scope.get(), polarity)
|
||||
: Luau::freshType(arena, builtinTypes, scope.get());
|
||||
|
||||
interiorFreeTypes.back().types.push_back(ft);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
|
@ -412,7 +415,7 @@ TypePackId ConstraintGenerator::freshTypePack(const ScopePtr& scope, Polarity po
|
|||
{
|
||||
FreeTypePack f{scope.get(), polarity};
|
||||
TypePackId result = arena->addTypePack(TypePackVar{std::move(f)});
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
interiorFreeTypes.back().typePacks.push_back(result);
|
||||
return result;
|
||||
}
|
||||
|
@ -1036,6 +1039,11 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStat* stat)
|
|||
{
|
||||
RecursionLimiter limiter{"ConstraintGenerator", &recursionCount, FInt::LuauCheckRecursionLimit};
|
||||
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
LUAU_ASSERT(DEPRECATED_interiorTypes.empty());
|
||||
else
|
||||
LUAU_ASSERT(interiorFreeTypes.empty());
|
||||
|
||||
if (auto s = stat->as<AstStatBlock>())
|
||||
return visit(scope, s);
|
||||
else if (auto i = stat->as<AstStatIf>())
|
||||
|
@ -1741,16 +1749,8 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatCompoundAss
|
|||
{
|
||||
TypeId resultTy = checkAstExprBinary(scope, assign->location, assign->op, assign->var, assign->value, std::nullopt).ty;
|
||||
module->astCompoundAssignResultTypes[assign] = resultTy;
|
||||
|
||||
if (!FFlag::LuauSkipLvalueForCompoundAssignment)
|
||||
{
|
||||
TypeId lhsType = check(scope, assign->var).ty;
|
||||
visitLValue(scope, assign->var, lhsType);
|
||||
|
||||
follow(lhsType);
|
||||
follow(resultTy);
|
||||
}
|
||||
|
||||
// NOTE: We do not update lvalues for compound assignments. This is
|
||||
// intentional.
|
||||
return ControlFlow::None;
|
||||
}
|
||||
|
||||
|
@ -1870,7 +1870,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::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
interiorFreeTypes.emplace_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.push_back(std::vector<TypeId>{});
|
||||
|
@ -1888,7 +1888,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeFunctio
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
{
|
||||
sig.signatureScope->interiorFreeTypes = std::move(interiorFreeTypes.back().types);
|
||||
sig.signatureScope->interiorFreeTypePacks = std::move(interiorFreeTypes.back().typePacks);
|
||||
|
@ -1897,7 +1897,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeFunctio
|
|||
sig.signatureScope->interiorFreeTypes = std::move(DEPRECATED_interiorTypes.back());
|
||||
|
||||
getMutable<BlockedType>(generalizedTy)->setOwner(gc);
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
interiorFreeTypes.pop_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.pop_back();
|
||||
|
@ -1993,7 +1993,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareExte
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving)
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving3)
|
||||
{
|
||||
// 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
|
||||
|
@ -2074,8 +2074,6 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareExte
|
|||
{
|
||||
Luau::Property& prop = props[propName];
|
||||
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
if (auto readTy = prop.readTy)
|
||||
{
|
||||
// We special-case this logic to keep the intersection flat; otherwise we
|
||||
|
@ -2130,36 +2128,6 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareExte
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TypeId currentTy = prop.type_DEPRECATED();
|
||||
|
||||
// We special-case this logic to keep the intersection flat; otherwise we
|
||||
// would create a ton of nested intersection types.
|
||||
if (const IntersectionType* itv = get<IntersectionType>(currentTy))
|
||||
{
|
||||
std::vector<TypeId> options = itv->parts;
|
||||
options.push_back(propTy);
|
||||
TypeId newItv = arena->addType(IntersectionType{std::move(options)});
|
||||
|
||||
prop.readTy = newItv;
|
||||
prop.writeTy = newItv;
|
||||
}
|
||||
else if (get<FunctionType>(currentTy))
|
||||
{
|
||||
TypeId intersection = arena->addType(IntersectionType{{currentTy, propTy}});
|
||||
|
||||
prop.readTy = intersection;
|
||||
prop.writeTy = intersection;
|
||||
}
|
||||
else
|
||||
{
|
||||
reportError(
|
||||
declaredExternType->location, GenericError{format("Cannot overload non-function class member '%s'", propName.c_str())}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ControlFlow::None;
|
||||
|
@ -2653,7 +2621,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprConstantStrin
|
|||
//
|
||||
// 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)
|
||||
if (largeTableDepth > 0)
|
||||
return Inference{builtinTypes->stringType};
|
||||
|
||||
TypeId freeTy = nullptr;
|
||||
|
@ -2694,7 +2662,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprConstantBool*
|
|||
//
|
||||
// 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)
|
||||
if (largeTableDepth > 0)
|
||||
return Inference{builtinTypes->booleanType};
|
||||
|
||||
TypeId freeTy = nullptr;
|
||||
|
@ -2866,7 +2834,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprFunction* fun
|
|||
Checkpoint startCheckpoint = checkpoint(this);
|
||||
FunctionSignature sig = checkFunctionSignature(scope, func, expectedType);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
interiorFreeTypes.emplace_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.push_back(std::vector<TypeId>{});
|
||||
|
@ -2884,7 +2852,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprFunction* fun
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
{
|
||||
sig.signatureScope->interiorFreeTypes = std::move(interiorFreeTypes.back().types);
|
||||
sig.signatureScope->interiorFreeTypePacks = std::move(interiorFreeTypes.back().typePacks);
|
||||
|
@ -3114,7 +3082,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIfElse* ifEls
|
|||
applyRefinements(elseScope, ifElse->falseExpr->location, refinementArena.negation(refinement));
|
||||
TypeId elseType = check(elseScope, ifElse->falseExpr, expectedType).ty;
|
||||
|
||||
if (FFlag::LuauInferActualIfElseExprType)
|
||||
if (FFlag::LuauInferActualIfElseExprType2)
|
||||
return Inference{makeUnion(scope, ifElse->location, thenType, elseType)};
|
||||
else
|
||||
return Inference{expectedType ? *expectedType : makeUnion(scope, ifElse->location, thenType, elseType)};
|
||||
|
@ -3406,11 +3374,10 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
|
|||
ttv->definitionLocation = expr->location;
|
||||
ttv->scope = scope.get();
|
||||
|
||||
if (FFlag::LuauDisablePrimitiveInferenceInLargeTables && FInt::LuauPrimitiveInferenceInTableLimit > 0 &&
|
||||
expr->items.size > size_t(FInt::LuauPrimitiveInferenceInTableLimit))
|
||||
if (FInt::LuauPrimitiveInferenceInTableLimit > 0 && expr->items.size > size_t(FInt::LuauPrimitiveInferenceInTableLimit))
|
||||
largeTableDepth++;
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
interiorFreeTypes.back().types.push_back(ty);
|
||||
else
|
||||
DEPRECATED_interiorTypes.back().push_back(ty);
|
||||
|
@ -3503,23 +3470,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
|
|||
}
|
||||
}
|
||||
|
||||
if (expectedType && !FFlag::LuauTableLiteralSubtypeSpecificCheck2)
|
||||
{
|
||||
addConstraint(
|
||||
scope,
|
||||
expr->location,
|
||||
TableCheckConstraint{
|
||||
*expectedType,
|
||||
ty,
|
||||
expr,
|
||||
NotNull{&module->astTypes},
|
||||
NotNull{&module->astExpectedTypes},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (FFlag::LuauDisablePrimitiveInferenceInLargeTables && FInt::LuauPrimitiveInferenceInTableLimit > 0 &&
|
||||
expr->items.size > size_t(FInt::LuauPrimitiveInferenceInTableLimit))
|
||||
if (FInt::LuauPrimitiveInferenceInTableLimit > 0 && expr->items.size > size_t(FInt::LuauPrimitiveInferenceInTableLimit))
|
||||
largeTableDepth--;
|
||||
|
||||
return Inference{ty};
|
||||
|
@ -3775,7 +3726,7 @@ TypeId ConstraintGenerator::resolveReferenceType(
|
|||
else
|
||||
return resolveType_(scope, ref->parameters.data[0].type, inTypeArguments);
|
||||
}
|
||||
else if (FFlag::LuauLimitDynamicConstraintSolving && ref->name == "_luau_blocked_type")
|
||||
else if (FFlag::LuauLimitDynamicConstraintSolving3 && ref->name == "_luau_blocked_type")
|
||||
{
|
||||
return arena->addType(BlockedType{});
|
||||
}
|
||||
|
@ -3871,11 +3822,6 @@ TypeId ConstraintGenerator::resolveTableType(const ScopePtr& scope, AstType* ty,
|
|||
p.readTy = propTy;
|
||||
break;
|
||||
case AstTableAccess::Write:
|
||||
if (!FFlag::LuauEnableWriteOnlyProperties)
|
||||
{
|
||||
reportError(*prop.accessLocation, GenericError{"write keyword is illegal here"});
|
||||
p.readTy = propTy;
|
||||
}
|
||||
p.writeTy = propTy;
|
||||
break;
|
||||
default:
|
||||
|
@ -4401,17 +4347,6 @@ struct GlobalPrepopulator : AstVisitor
|
|||
|
||||
void ConstraintGenerator::prepopulateGlobalScopeForFragmentTypecheck(const ScopePtr& globalScope, const ScopePtr& resumeScope, AstStatBlock* program)
|
||||
{
|
||||
if (!FFlag::LuauGlobalVariableModuleIsolation)
|
||||
{
|
||||
FragmentTypeCheckGlobalPrepopulator_DEPRECATED gp{NotNull{globalScope.get()}, NotNull{resumeScope.get()}, dfg, arena};
|
||||
|
||||
if (prepareModuleScope)
|
||||
prepareModuleScope(module->name, resumeScope);
|
||||
|
||||
program->visit(&gp);
|
||||
}
|
||||
|
||||
|
||||
// Handle type function globals as well, without preparing a module scope since they have a separate environment
|
||||
GlobalPrepopulator tfgp{NotNull{typeFunctionRuntime->rootScope.get()}, arena, dfg};
|
||||
program->visit(&tfgp);
|
||||
|
|
|
@ -35,22 +35,40 @@ LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverIncludeDependencies)
|
|||
LUAU_FASTFLAGVARIABLE(DebugLuauLogBindings)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAvoidGenericsLeakingDuringFunctionCallCheck)
|
||||
LUAU_FASTFLAGVARIABLE(LuauMissingFollowInAssignIndexConstraint)
|
||||
LUAU_FASTFLAGVARIABLE(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTableLiteralSubtypeCheckFunctionCalls)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUseOrderedTypeSetsInConstraints)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauAvoidExcessiveTypeCopying)
|
||||
LUAU_FASTFLAGVARIABLE(LuauForceSimplifyConstraint2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCollapseShouldNotCrash)
|
||||
LUAU_FASTFLAGVARIABLE(LuauContainsAnyGenericFollowBeforeChecking)
|
||||
LUAU_FASTFLAGVARIABLE(LuauLimitDynamicConstraintSolving)
|
||||
LUAU_FASTFLAGVARIABLE(LuauLimitDynamicConstraintSolving3)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDontDynamicallyCreateRedundantSubtypeConstraints)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
static void hashCombine(size_t& seed, size_t hash)
|
||||
{
|
||||
// Golden Ratio constant used for better hash scattering
|
||||
// See https://softwareengineering.stackexchange.com/a/402543
|
||||
seed ^= hash + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
bool SubtypeConstraintRecord::operator==(const SubtypeConstraintRecord& other) const
|
||||
{
|
||||
return (subTy == other.subTy) && (superTy == other.superTy) && (variance == other.variance);
|
||||
}
|
||||
|
||||
size_t HashSubtypeConstraintRecord::operator()(const SubtypeConstraintRecord& c) const
|
||||
{
|
||||
size_t result = 0;
|
||||
hashCombine(result, intptr_t(c.subTy));
|
||||
hashCombine(result, intptr_t(c.superTy));
|
||||
hashCombine(result, intptr_t(c.variance));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void dump(ConstraintSolver* cs, ToStringOptions& opts);
|
||||
|
||||
size_t HashBlockedConstraintId::operator()(const BlockedConstraintId& bci) const
|
||||
|
@ -426,8 +444,6 @@ void ConstraintSolver::run()
|
|||
|
||||
// Free types that have no constraints at all can be generalized right away.
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (FFlag::LuauUseOrderedTypeSetsInConstraints)
|
||||
{
|
||||
for (TypeId ty : constraintSet.freeTypes)
|
||||
{
|
||||
|
@ -435,16 +451,6 @@ void ConstraintSolver::run()
|
|||
generalizeOneType(ty);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (TypeId ty : constraintSet.freeTypes)
|
||||
{
|
||||
if (auto it = mutatedFreeTypeToConstraint_DEPRECATED.find(ty);
|
||||
it == mutatedFreeTypeToConstraint_DEPRECATED.end() || it->second.empty())
|
||||
generalizeOneType(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constraintSet.freeTypes.clear();
|
||||
|
||||
|
@ -469,7 +475,7 @@ void ConstraintSolver::run()
|
|||
|
||||
// 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)
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving3 && FInt::LuauSolverConstraintLimit > 0 && solverConstraintLimit == 0)
|
||||
break;
|
||||
|
||||
std::string saveMe = FFlag::DebugLuauLogSolver ? toString(*c, opts) : std::string{};
|
||||
|
@ -492,8 +498,6 @@ void ConstraintSolver::run()
|
|||
unblock(c);
|
||||
unsolvedConstraints.erase(unsolvedConstraints.begin() + ptrdiff_t(i));
|
||||
|
||||
if (FFlag::LuauUseOrderedTypeSetsInConstraints)
|
||||
{
|
||||
if (const auto maybeMutated = maybeMutatedFreeTypes.find(c); maybeMutated != maybeMutatedFreeTypes.end())
|
||||
{
|
||||
DenseHashSet<TypeId> seen{nullptr};
|
||||
|
@ -527,44 +531,6 @@ void ConstraintSolver::run()
|
|||
generalizeOneType(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto maybeMutated = maybeMutatedFreeTypes_DEPRECATED.find(c);
|
||||
if (maybeMutated != maybeMutatedFreeTypes_DEPRECATED.end())
|
||||
{
|
||||
DenseHashSet<TypeId> seen{nullptr};
|
||||
for (auto ty : maybeMutated->second)
|
||||
{
|
||||
// There is a high chance that this type has been rebound
|
||||
// across blocked types, rebound free types, pending
|
||||
// expansion types, etc, so we need to follow it.
|
||||
ty = follow(ty);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (seen.contains(ty))
|
||||
continue;
|
||||
seen.insert(ty);
|
||||
}
|
||||
|
||||
size_t& refCount = unresolvedConstraints[ty];
|
||||
if (refCount > 0)
|
||||
refCount -= 1;
|
||||
|
||||
// We have two constraints that are designed to wait for the
|
||||
// refCount on a free type to be equal to 1: the
|
||||
// PrimitiveTypeConstraint and ReduceConstraint. We
|
||||
// therefore wake any constraint waiting for a free type's
|
||||
// refcount to be 1 or 0.
|
||||
if (refCount <= 1)
|
||||
unblock(ty, Location{});
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4 && refCount == 0)
|
||||
generalizeOneType(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (logger)
|
||||
|
@ -730,8 +696,6 @@ struct TypeSearcher : TypeVisitor
|
|||
};
|
||||
|
||||
void ConstraintSolver::initFreeTypeTracking()
|
||||
{
|
||||
if (FFlag::LuauUseOrderedTypeSetsInConstraints)
|
||||
{
|
||||
for (auto c : this->constraints)
|
||||
{
|
||||
|
@ -757,34 +721,6 @@ void ConstraintSolver::initFreeTypeTracking()
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
for (NotNull<Constraint> c : this->constraints)
|
||||
{
|
||||
unsolvedConstraints.emplace_back(c);
|
||||
|
||||
auto maybeMutatedTypesPerConstraint = c->getMaybeMutatedFreeTypes_DEPRECATED();
|
||||
for (auto ty : maybeMutatedTypesPerConstraint)
|
||||
{
|
||||
auto [refCount, _] = unresolvedConstraints.try_insert(ty, 0);
|
||||
refCount += 1;
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
auto [it, fresh] = mutatedFreeTypeToConstraint_DEPRECATED.try_emplace(ty, nullptr);
|
||||
it->second.insert(c.get());
|
||||
}
|
||||
}
|
||||
maybeMutatedFreeTypes_DEPRECATED.emplace(c, maybeMutatedTypesPerConstraint);
|
||||
|
||||
for (NotNull<const Constraint> dep : c->dependencies)
|
||||
{
|
||||
block(dep, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConstraintSolver::generalizeOneType(TypeId ty)
|
||||
{
|
||||
|
@ -1838,9 +1774,6 @@ bool ConstraintSolver::tryDispatch(const FunctionCheckConstraint& c, NotNull<con
|
|||
DenseHashMap<TypeId, TypeId> replacements{nullptr};
|
||||
DenseHashMap<TypePackId, TypePackId> replacementPacks{nullptr};
|
||||
|
||||
if (FFlag::LuauAvoidGenericsLeakingDuringFunctionCallCheck)
|
||||
{
|
||||
|
||||
DenseHashSet<const void*> genericTypesAndPacks{nullptr};
|
||||
|
||||
Unifier2 u2{arena, builtinTypes, constraint->scope, NotNull{&iceReporter}};
|
||||
|
@ -1966,98 +1899,6 @@ bool ConstraintSolver::tryDispatch(const FunctionCheckConstraint& c, NotNull<con
|
|||
inheritBlocks(constraint, addition);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ContainsGenerics_DEPRECATED containsGenerics;
|
||||
|
||||
for (auto generic : ftv->generics)
|
||||
{
|
||||
replacements[generic] = builtinTypes->unknownType;
|
||||
containsGenerics.generics.insert(generic);
|
||||
}
|
||||
|
||||
for (auto genericPack : ftv->genericPacks)
|
||||
{
|
||||
replacementPacks[genericPack] = builtinTypes->unknownTypePack;
|
||||
containsGenerics.generics.insert(genericPack);
|
||||
}
|
||||
|
||||
const std::vector<TypeId> expectedArgs = flatten(ftv->argTypes).first;
|
||||
const std::vector<TypeId> argPackHead = flatten(argsPack).first;
|
||||
|
||||
// If this is a self call, the types will have more elements than the AST call.
|
||||
// We don't attempt to perform bidirectional inference on the self type.
|
||||
const size_t typeOffset = c.callSite->self ? 1 : 0;
|
||||
|
||||
for (size_t i = 0; i < c.callSite->args.size && i + typeOffset < expectedArgs.size() && i + typeOffset < argPackHead.size(); ++i)
|
||||
{
|
||||
const TypeId expectedArgTy = follow(expectedArgs[i + typeOffset]);
|
||||
const TypeId actualArgTy = follow(argPackHead[i + typeOffset]);
|
||||
AstExpr* expr = unwrapGroup(c.callSite->args.data[i]);
|
||||
|
||||
(*c.astExpectedTypes)[expr] = expectedArgTy;
|
||||
|
||||
const FunctionType* lambdaTy = get<FunctionType>(actualArgTy);
|
||||
// Generic types are skipped over entirely, for now.
|
||||
if (containsGenerics.hasGeneric(expectedArgTy))
|
||||
{
|
||||
if (!lambdaTy || !lambdaTy->argTypes)
|
||||
continue;
|
||||
|
||||
const TypePack* argTp = get<TypePack>(follow(lambdaTy->argTypes));
|
||||
if (!argTp || !argTp->tail)
|
||||
continue;
|
||||
|
||||
if (const VariadicTypePack* argTpTail = get<VariadicTypePack>(follow(argTp->tail));
|
||||
argTpTail && argTpTail->hidden && argTpTail->ty == builtinTypes->anyType)
|
||||
{
|
||||
// Strip variadic any
|
||||
const TypePackId anyLessArgTp = arena->addTypePack(TypePack{argTp->head});
|
||||
const TypeId newFuncTypeId = arena->addType(FunctionType{anyLessArgTp, lambdaTy->retTypes});
|
||||
FunctionType* newFunc = getMutable<FunctionType>(newFuncTypeId);
|
||||
newFunc->argNames = lambdaTy->argNames;
|
||||
(*c.astTypes)[expr] = newFuncTypeId;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const FunctionType* expectedLambdaTy = get<FunctionType>(expectedArgTy);
|
||||
const AstExprFunction* lambdaExpr = expr->as<AstExprFunction>();
|
||||
|
||||
if (expectedLambdaTy && lambdaTy && lambdaExpr)
|
||||
{
|
||||
const std::vector<TypeId> expectedLambdaArgTys = flatten(expectedLambdaTy->argTypes).first;
|
||||
const std::vector<TypeId> lambdaArgTys = flatten(lambdaTy->argTypes).first;
|
||||
|
||||
for (size_t j = 0; j < expectedLambdaArgTys.size() && j < lambdaArgTys.size() && j < lambdaExpr->args.size; ++j)
|
||||
{
|
||||
if (!lambdaExpr->args.data[j]->annotation && get<FreeType>(follow(lambdaArgTys[j])))
|
||||
{
|
||||
shiftReferences(lambdaArgTys[j], expectedLambdaArgTys[j]);
|
||||
bind(constraint, lambdaArgTys[j], expectedLambdaArgTys[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (expr->is<AstExprConstantBool>() || expr->is<AstExprConstantString>() || expr->is<AstExprConstantNumber>() ||
|
||||
expr->is<AstExprConstantNil>())
|
||||
{
|
||||
Unifier2 u2{arena, builtinTypes, constraint->scope, NotNull{&iceReporter}};
|
||||
u2.unify(actualArgTy, expectedArgTy);
|
||||
}
|
||||
else if (expr->is<AstExprTable>())
|
||||
{
|
||||
Unifier2 u2{arena, builtinTypes, constraint->scope, NotNull{&iceReporter}};
|
||||
Subtyping sp{builtinTypes, arena, simplifier, normalizer, typeFunctionRuntime, NotNull{&iceReporter}};
|
||||
std::vector<TypeId> toBlock;
|
||||
(void)matchLiteralType(
|
||||
c.astTypes, c.astExpectedTypes, builtinTypes, arena, NotNull{&u2}, NotNull{&sp}, expectedArgTy, actualArgTy, expr, toBlock
|
||||
);
|
||||
LUAU_ASSERT(toBlock.empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -2620,23 +2461,12 @@ bool ConstraintSolver::tryDispatch(const AssignIndexConstraint& c, NotNull<const
|
|||
};
|
||||
|
||||
if (auto lhsFree = getMutable<FreeType>(lhsType))
|
||||
{
|
||||
if (FFlag::LuauMissingFollowInAssignIndexConstraint)
|
||||
{
|
||||
if (auto lhsTable = getMutable<TableType>(follow(lhsFree->upperBound)))
|
||||
{
|
||||
if (auto res = tableStuff(lhsTable))
|
||||
return *res;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto lhsTable = getMutable<TableType>(lhsFree->upperBound))
|
||||
{
|
||||
if (auto res = tableStuff(lhsTable))
|
||||
return *res;
|
||||
}
|
||||
}
|
||||
|
||||
TypeId newUpperBound =
|
||||
arena->addType(TableType{/*props*/ {}, TableIndexer{indexType, rhsType}, TypeLevel{}, constraint->scope, TableState::Free});
|
||||
|
@ -3400,17 +3230,12 @@ TablePropLookupResult ConstraintSolver::lookupTableProp(
|
|||
return {{}, result.propType};
|
||||
|
||||
// TODO: __index can be an overloaded function.
|
||||
//
|
||||
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
// if the property is write-only, then surely we cannot read from it.
|
||||
if (indexProp->second.isWriteOnly())
|
||||
return {{}, builtinTypes->errorType};
|
||||
}
|
||||
|
||||
TypeId indexType =
|
||||
FFlag::LuauRemoveTypeCallsForReadWriteProps ? follow(*indexProp->second.readTy) : follow(indexProp->second.type_DEPRECATED());
|
||||
TypeId indexType = follow(*indexProp->second.readTy);
|
||||
|
||||
if (auto ft = get<FunctionType>(indexType))
|
||||
{
|
||||
|
@ -3448,17 +3273,12 @@ TablePropLookupResult ConstraintSolver::lookupTableProp(
|
|||
if (indexProp == metatable->props.end())
|
||||
return {{}, std::nullopt};
|
||||
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
// if the property is write-only, then surely we cannot read from it.
|
||||
if (indexProp->second.isWriteOnly())
|
||||
return {{}, builtinTypes->errorType};
|
||||
|
||||
return lookupTableProp(constraint, *indexProp->second.readTy, propName, context, inConditional, suppressSimplification, seen);
|
||||
}
|
||||
else
|
||||
return lookupTableProp(constraint, indexProp->second.type_DEPRECATED(), propName, context, inConditional, suppressSimplification, seen);
|
||||
}
|
||||
else if (auto ft = get<FreeType>(subjectType))
|
||||
{
|
||||
const TypeId upperBound = follow(ft->upperBound);
|
||||
|
@ -3826,7 +3646,7 @@ bool ConstraintSolver::isBlocked(TypeId ty) const
|
|||
|
||||
if (auto tfit = get<TypeFunctionInstanceType>(ty))
|
||||
{
|
||||
if (FFlag::LuauStuckTypeFunctionsStillDispatch && tfit->state != TypeFunctionInstanceState::Unsolved)
|
||||
if (FFlag::LuauEagerGeneralization4 && tfit->state != TypeFunctionInstanceState::Unsolved)
|
||||
return false;
|
||||
return uninhabitedTypeFunctions.contains(ty) == false;
|
||||
}
|
||||
|
@ -3852,12 +3672,31 @@ bool ConstraintSolver::isBlocked(NotNull<const Constraint> constraint) const
|
|||
|
||||
NotNull<Constraint> ConstraintSolver::pushConstraint(NotNull<Scope> scope, const Location& location, ConstraintV cv)
|
||||
{
|
||||
std::optional<SubtypeConstraintRecord> scr;
|
||||
if (FFlag::LuauDontDynamicallyCreateRedundantSubtypeConstraints)
|
||||
{
|
||||
if (auto sc = cv.get_if<SubtypeConstraint>())
|
||||
scr.emplace(SubtypeConstraintRecord{sc->subType, sc->superType, SubtypingVariance::Covariant});
|
||||
else if (auto ec = cv.get_if<EqualityConstraint>())
|
||||
scr.emplace(SubtypeConstraintRecord{ec->assignmentType, ec->resultType, SubtypingVariance::Invariant});
|
||||
}
|
||||
|
||||
if (scr)
|
||||
{
|
||||
if (auto f = seenConstraints.find(*scr))
|
||||
return NotNull{*f};
|
||||
}
|
||||
|
||||
std::unique_ptr<Constraint> c = std::make_unique<Constraint>(scope, location, std::move(cv));
|
||||
NotNull<Constraint> borrow = NotNull(c.get());
|
||||
|
||||
if (scr)
|
||||
seenConstraints[*scr] = borrow;
|
||||
|
||||
solverConstraints.push_back(std::move(c));
|
||||
unsolvedConstraints.emplace_back(borrow);
|
||||
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving)
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving3)
|
||||
{
|
||||
if (solverConstraintLimit > 0)
|
||||
{
|
||||
|
@ -3962,9 +3801,6 @@ void ConstraintSolver::shiftReferences(TypeId source, TypeId target)
|
|||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (FFlag::LuauUseOrderedTypeSetsInConstraints)
|
||||
{
|
||||
|
||||
if (auto it = mutatedFreeTypeToConstraint.find(source); it != mutatedFreeTypeToConstraint.end())
|
||||
{
|
||||
const OrderedSet<const Constraint*>& constraintsAffectedBySource = it->second;
|
||||
|
@ -3980,27 +3816,6 @@ void ConstraintSolver::shiftReferences(TypeId source, TypeId target)
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = mutatedFreeTypeToConstraint_DEPRECATED.find(source);
|
||||
if (it != mutatedFreeTypeToConstraint_DEPRECATED.end())
|
||||
{
|
||||
const DenseHashSet<const Constraint*>& constraintsAffectedBySource = it->second;
|
||||
|
||||
auto [it2, fresh2] = mutatedFreeTypeToConstraint_DEPRECATED.try_emplace(target, DenseHashSet<const Constraint*>{nullptr});
|
||||
DenseHashSet<const Constraint*>& constraintsAffectedByTarget = it2->second;
|
||||
|
||||
// auto [it2, fresh] = mutatedFreeTypeToConstraint.try_emplace(target, DenseHashSet<const Constraint*>{nullptr});
|
||||
for (const Constraint* constraint : constraintsAffectedBySource)
|
||||
{
|
||||
constraintsAffectedByTarget.insert(constraint);
|
||||
|
||||
auto [it3, fresh3] = maybeMutatedFreeTypes_DEPRECATED.try_emplace(NotNull{constraint}, DenseHashSet<TypeId>{nullptr});
|
||||
it3->second.insert(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<TypeId> ConstraintSolver::generalizeFreeType(NotNull<Scope> scope, TypeId type)
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
LUAU_FASTFLAG(DebugLuauFreezeArena)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDfgScopeStackNotNull)
|
||||
LUAU_FASTFLAG(LuauFragmentAutocompleteTracksRValueRefinements)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDfgForwardNilFromAndOr)
|
||||
|
||||
|
@ -154,18 +153,6 @@ void DfgScope::inherit(const DfgScope* childScope)
|
|||
}
|
||||
}
|
||||
|
||||
bool DfgScope::canUpdateDefinition(Symbol symbol) const
|
||||
{
|
||||
// NOTE: Vestigial as of clipping LuauDfgAllowUpdatesInLoops
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DfgScope::canUpdateDefinition(DefId def, const std::string& key) const
|
||||
{
|
||||
// NOTE: Vestigial as of clipping LuauDfgAllowUpdatesInLoops
|
||||
return true;
|
||||
}
|
||||
|
||||
DataFlowGraphBuilder::DataFlowGraphBuilder(NotNull<DefArena> defArena, NotNull<RefinementKeyArena> keyArena)
|
||||
: graph{defArena, keyArena}
|
||||
, defArena{defArena}
|
||||
|
@ -185,14 +172,7 @@ DataFlowGraph DataFlowGraphBuilder::build(
|
|||
DataFlowGraphBuilder builder(defArena, keyArena);
|
||||
builder.handle = handle;
|
||||
|
||||
DfgScope* moduleScope;
|
||||
// We're not explicitly calling makeChildScope here because that function relies on currentScope
|
||||
// which guarantees that the scope being returned is NotNull
|
||||
// This means that while the scope stack is empty, we'll have to manually initialize the global scope
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
moduleScope = builder.scopes.emplace_back(new DfgScope{nullptr, DfgScope::ScopeType::Linear}).get();
|
||||
else
|
||||
moduleScope = builder.makeChildScope();
|
||||
DfgScope* moduleScope = builder.scopes.emplace_back(new DfgScope{nullptr, DfgScope::ScopeType::Linear}).get();
|
||||
PushScope ps{builder.scopeStack, moduleScope};
|
||||
builder.visitBlockWithoutChildScope(block);
|
||||
builder.resolveCaptures();
|
||||
|
@ -230,19 +210,9 @@ NotNull<DfgScope> DataFlowGraphBuilder::currentScope()
|
|||
return NotNull{scopeStack.back()};
|
||||
}
|
||||
|
||||
DfgScope* DataFlowGraphBuilder::currentScope_DEPRECATED()
|
||||
{
|
||||
if (scopeStack.empty())
|
||||
return nullptr; // nullptr is the root DFG scope.
|
||||
return scopeStack.back();
|
||||
}
|
||||
|
||||
DfgScope* DataFlowGraphBuilder::makeChildScope(DfgScope::ScopeType scopeType)
|
||||
{
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
return scopes.emplace_back(new DfgScope{currentScope(), scopeType}).get();
|
||||
else
|
||||
return scopes.emplace_back(new DfgScope{currentScope_DEPRECATED(), scopeType}).get();
|
||||
}
|
||||
|
||||
void DataFlowGraphBuilder::join(DfgScope* p, DfgScope* a, DfgScope* b)
|
||||
|
@ -319,7 +289,7 @@ void DataFlowGraphBuilder::joinProps(DfgScope* result, const DfgScope& a, const
|
|||
|
||||
DefId DataFlowGraphBuilder::lookup(Symbol symbol, Location location)
|
||||
{
|
||||
DfgScope* scope = FFlag::LuauDfgScopeStackNotNull ? currentScope() : currentScope_DEPRECATED();
|
||||
DfgScope* scope = currentScope();
|
||||
|
||||
// true if any of the considered scopes are a loop.
|
||||
bool outsideLoopScope = false;
|
||||
|
@ -352,7 +322,7 @@ DefId DataFlowGraphBuilder::lookup(Symbol symbol, Location location)
|
|||
|
||||
DefId DataFlowGraphBuilder::lookup(DefId def, const std::string& key, Location location)
|
||||
{
|
||||
DfgScope* scope = FFlag::LuauDfgScopeStackNotNull ? currentScope() : currentScope_DEPRECATED();
|
||||
DfgScope* scope = currentScope();
|
||||
for (DfgScope* current = scope; current; current = current->parent)
|
||||
{
|
||||
if (auto props = current->props.find(def))
|
||||
|
@ -398,10 +368,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatBlock* b)
|
|||
cf = visitBlockWithoutChildScope(b);
|
||||
}
|
||||
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
currentScope()->inherit(child);
|
||||
else
|
||||
currentScope_DEPRECATED()->inherit(child);
|
||||
return cf;
|
||||
}
|
||||
|
||||
|
@ -486,7 +453,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatIf* i)
|
|||
elsecf = visit(i->elsebody);
|
||||
}
|
||||
|
||||
DfgScope* scope = FFlag::LuauDfgScopeStackNotNull ? currentScope() : currentScope_DEPRECATED();
|
||||
DfgScope* scope = currentScope();
|
||||
// If the control flow from the `if` or `else` block is non-linear,
|
||||
// then we should assume that the _other_ branch is the one taken.
|
||||
if (thencf != ControlFlow::None && elsecf == ControlFlow::None)
|
||||
|
@ -615,10 +582,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatLocal* l)
|
|||
}
|
||||
}
|
||||
graph.localDefs[local] = def;
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
currentScope()->bindings[local] = def;
|
||||
else
|
||||
currentScope_DEPRECATED()->bindings[local] = def;
|
||||
captures[local].allVersions.push_back(def);
|
||||
}
|
||||
|
||||
|
@ -675,10 +639,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatForIn* f)
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -757,10 +718,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatLocalFunction* l)
|
|||
{
|
||||
DefId def = defArena->freshCell(l->name, l->location);
|
||||
graph.localDefs[l->name] = def;
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
currentScope()->bindings[l->name] = def;
|
||||
else
|
||||
currentScope_DEPRECATED()->bindings[l->name] = def;
|
||||
captures[l->name].allVersions.push_back(def);
|
||||
visitExpr(l->func);
|
||||
|
||||
|
@ -793,10 +751,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatDeclareGlobal* d)
|
|||
{
|
||||
DefId def = defArena->freshCell(d->name, d->nameLocation);
|
||||
graph.declaredDefs[d] = def;
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
currentScope()->bindings[d->name] = def;
|
||||
else
|
||||
currentScope_DEPRECATED()->bindings[d->name] = def;
|
||||
captures[d->name].allVersions.push_back(def);
|
||||
|
||||
visitType(d->type);
|
||||
|
@ -808,10 +763,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatDeclareFunction* d)
|
|||
{
|
||||
DefId def = defArena->freshCell(d->name, d->nameLocation);
|
||||
graph.declaredDefs[d] = def;
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
currentScope()->bindings[d->name] = def;
|
||||
else
|
||||
currentScope_DEPRECATED()->bindings[d->name] = def;
|
||||
captures[d->name].allVersions.push_back(def);
|
||||
|
||||
DfgScope* unreachable = makeChildScope();
|
||||
|
@ -1058,10 +1010,7 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprFunction* f)
|
|||
DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprTable* t)
|
||||
{
|
||||
DefId tableCell = defArena->freshCell(Symbol{}, t->location);
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
currentScope()->props[tableCell] = {};
|
||||
else
|
||||
currentScope_DEPRECATED()->props[tableCell] = {};
|
||||
for (AstExprTable::Item item : t->items)
|
||||
{
|
||||
DataFlowResult result = visitExpr(item.value);
|
||||
|
@ -1070,10 +1019,7 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprTable* t)
|
|||
visitExpr(item.key);
|
||||
if (auto string = item.key->as<AstExprConstantString>())
|
||||
{
|
||||
if (FFlag::LuauDfgScopeStackNotNull)
|
||||
currentScope()->props[tableCell][string->value.data] = result.def;
|
||||
else
|
||||
currentScope_DEPRECATED()->props[tableCell][string->value.data] = result.def;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1168,10 +1114,10 @@ void DataFlowGraphBuilder::visitLValue(AstExpr* e, DefId incomingDef)
|
|||
|
||||
DefId DataFlowGraphBuilder::visitLValue(AstExprLocal* l, DefId incomingDef)
|
||||
{
|
||||
DfgScope* scope = FFlag::LuauDfgScopeStackNotNull ? currentScope() : currentScope_DEPRECATED();
|
||||
DfgScope* scope = currentScope();
|
||||
|
||||
// In order to avoid alias tracking, we need to clip the reference to the parent def.
|
||||
if (scope->canUpdateDefinition(l->local) && !l->upvalue)
|
||||
if (!l->upvalue)
|
||||
{
|
||||
DefId updated = defArena->freshCell(l->local, l->location, containsSubscriptedDefinition(incomingDef));
|
||||
scope->bindings[l->local] = updated;
|
||||
|
@ -1184,52 +1130,36 @@ DefId DataFlowGraphBuilder::visitLValue(AstExprLocal* l, DefId incomingDef)
|
|||
|
||||
DefId DataFlowGraphBuilder::visitLValue(AstExprGlobal* g, DefId incomingDef)
|
||||
{
|
||||
DfgScope* scope = FFlag::LuauDfgScopeStackNotNull ? currentScope() : currentScope_DEPRECATED();
|
||||
DfgScope* scope = currentScope();
|
||||
|
||||
// In order to avoid alias tracking, we need to clip the reference to the parent def.
|
||||
if (scope->canUpdateDefinition(g->name))
|
||||
{
|
||||
DefId updated = defArena->freshCell(g->name, g->location, containsSubscriptedDefinition(incomingDef));
|
||||
scope->bindings[g->name] = updated;
|
||||
captures[g->name].allVersions.push_back(updated);
|
||||
return updated;
|
||||
}
|
||||
else
|
||||
return visitExpr(static_cast<AstExpr*>(g)).def;
|
||||
}
|
||||
|
||||
DefId DataFlowGraphBuilder::visitLValue(AstExprIndexName* i, DefId incomingDef)
|
||||
{
|
||||
DefId parentDef = visitExpr(i->expr).def;
|
||||
|
||||
DfgScope* scope = FFlag::LuauDfgScopeStackNotNull ? currentScope() : currentScope_DEPRECATED();
|
||||
if (scope->canUpdateDefinition(parentDef, i->index.value))
|
||||
{
|
||||
DfgScope* scope = currentScope();
|
||||
DefId updated = defArena->freshCell(i->index, i->location, containsSubscriptedDefinition(incomingDef));
|
||||
scope->props[parentDef][i->index.value] = updated;
|
||||
return updated;
|
||||
}
|
||||
else
|
||||
return visitExpr(static_cast<AstExpr*>(i)).def;
|
||||
}
|
||||
|
||||
DefId DataFlowGraphBuilder::visitLValue(AstExprIndexExpr* i, DefId incomingDef)
|
||||
{
|
||||
DefId parentDef = visitExpr(i->expr).def;
|
||||
visitExpr(i->index);
|
||||
|
||||
DfgScope* scope = FFlag::LuauDfgScopeStackNotNull ? currentScope() : currentScope_DEPRECATED();
|
||||
DfgScope* scope = currentScope();
|
||||
if (auto string = i->index->as<AstExprConstantString>())
|
||||
{
|
||||
if (scope->canUpdateDefinition(parentDef, string->value.data))
|
||||
{
|
||||
DefId updated = defArena->freshCell(Symbol{}, i->location, containsSubscriptedDefinition(incomingDef));
|
||||
scope->props[parentDef][string->value.data] = updated;
|
||||
return updated;
|
||||
}
|
||||
else
|
||||
return visitExpr(static_cast<AstExpr*>(i)).def;
|
||||
}
|
||||
else
|
||||
return defArena->freshCell(Symbol{}, i->location, /*subscripted=*/true);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
#include "Luau/BuiltinDefinitions.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauTypeFunOptional)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -364,29 +362,6 @@ export type type = {
|
|||
|
||||
static constexpr const char* kBuiltinDefinitionTypesLibSrc = R"BUILTIN_SRC(
|
||||
|
||||
declare types: {
|
||||
unknown: type,
|
||||
never: type,
|
||||
any: type,
|
||||
boolean: type,
|
||||
number: type,
|
||||
string: type,
|
||||
thread: type,
|
||||
buffer: type,
|
||||
|
||||
singleton: @checked (arg: string | boolean | nil) -> type,
|
||||
generic: @checked (name: string, ispack: boolean?) -> type,
|
||||
negationof: @checked (arg: type) -> type,
|
||||
unionof: @checked (...type) -> type,
|
||||
intersectionof: @checked (...type) -> type,
|
||||
newtable: @checked (props: {[type]: type} | {[type]: { read: type, write: type } } | nil, indexer: { index: type, readresult: type, writeresult: type }?, metatable: type?) -> type,
|
||||
newfunction: @checked (parameters: { head: {type}?, tail: type? }?, returns: { head: {type}?, tail: type? }?, generics: {type}?) -> type,
|
||||
copy: @checked (arg: type) -> type,
|
||||
}
|
||||
)BUILTIN_SRC";
|
||||
|
||||
static constexpr const char* kBuiltinDefinitionTypesLibWithOptionalSrc = R"BUILTIN_SRC(
|
||||
|
||||
declare types: {
|
||||
unknown: type,
|
||||
never: type,
|
||||
|
@ -415,9 +390,6 @@ std::string getTypeFunctionDefinitionSource()
|
|||
|
||||
std::string result = kBuiltinDefinitionTypeMethodSrc;
|
||||
|
||||
if (FFlag::LuauTypeFunOptional)
|
||||
result += kBuiltinDefinitionTypesLibWithOptionalSrc;
|
||||
else
|
||||
result += kBuiltinDefinitionTypesLibSrc;
|
||||
|
||||
return result;
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeArena.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/VisitType.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
@ -25,7 +24,6 @@
|
|||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSimplification)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSimplificationToDot)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauExtraEqSatSanityChecks)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
|
||||
namespace Luau::EqSatSimplification
|
||||
{
|
||||
|
@ -2371,14 +2369,9 @@ void Simplifier::intersectTableProperty(Id id)
|
|||
}
|
||||
|
||||
Id newTableProp =
|
||||
FFlag::LuauRemoveTypeCallsForReadWriteProps
|
||||
? egraph.add(Intersection{
|
||||
egraph.add(Intersection{
|
||||
toId(egraph, builtinTypes, mappingIdToClass, stringCache, *it->second.readTy),
|
||||
toId(egraph, builtinTypes, mappingIdToClass, stringCache, *table1Ty->props.begin()->second.readTy)
|
||||
})
|
||||
: egraph.add(Intersection{
|
||||
toId(egraph, builtinTypes, mappingIdToClass, stringCache, it->second.type_DEPRECATED()),
|
||||
toId(egraph, builtinTypes, mappingIdToClass, stringCache, table1Ty->props.begin()->second.type_DEPRECATED())
|
||||
});
|
||||
|
||||
newIntersectionParts.push_back(egraph.add(TTable{jId, {stringCache.add(it->first)}, {newTableProp}}));
|
||||
|
@ -2451,10 +2444,7 @@ void Simplifier::unneededTableModification(Id id)
|
|||
StringId propName = tbl->propNames[i];
|
||||
const Id propType = tbl->propTypes()[i];
|
||||
|
||||
Id importedProp =
|
||||
FFlag::LuauRemoveTypeCallsForReadWriteProps
|
||||
? toId(egraph, builtinTypes, mappingIdToClass, stringCache, *tt->props.at(stringCache.asString(propName)).readTy)
|
||||
: toId(egraph, builtinTypes, mappingIdToClass, stringCache, tt->props.at(stringCache.asString(propName)).type_DEPRECATED());
|
||||
Id importedProp = toId(egraph, builtinTypes, mappingIdToClass, stringCache, *tt->props.at(stringCache.asString(propName)).readTy);
|
||||
|
||||
if (find(importedProp) != find(propType))
|
||||
{
|
||||
|
|
|
@ -20,9 +20,8 @@
|
|||
LUAU_FASTINTVARIABLE(LuauIndentTypeMismatchMaxTypeLength, 10)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAGVARIABLE(LuauBetterCannotCallFunctionPrimitive)
|
||||
LUAU_FASTFLAG(LuauSolverAgnosticStringification)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictReportsOneIndexedErrors)
|
||||
|
||||
static std::string wrongNumberOfArgsString(
|
||||
size_t expectedCount,
|
||||
|
@ -427,7 +426,7 @@ struct ErrorConverter
|
|||
}
|
||||
else
|
||||
{
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
if (FFlag::LuauSolverV2)
|
||||
return it->second.readTy;
|
||||
else
|
||||
return it->second.type_DEPRECATED();
|
||||
|
@ -462,11 +461,8 @@ 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);
|
||||
}
|
||||
|
@ -785,6 +781,10 @@ struct ErrorConverter
|
|||
std::string operator()(const CheckedFunctionCallError& e) const
|
||||
{
|
||||
// TODO: What happens if checkedFunctionName cannot be found??
|
||||
if (FFlag::LuauNewNonStrictReportsOneIndexedErrors)
|
||||
return "Function '" + e.checkedFunctionName + "' expects '" + toString(e.expected) + "' at argument #" +
|
||||
std::to_string(e.argumentIndex + 1) + ", but got '" + Luau::toString(e.passed) + "'";
|
||||
else
|
||||
return "Function '" + e.checkedFunctionName + "' expects '" + toString(e.expected) + "' at argument #" + std::to_string(e.argumentIndex) +
|
||||
", but got '" + Luau::toString(e.passed) + "'";
|
||||
}
|
||||
|
|
|
@ -31,17 +31,11 @@ LUAU_FASTINT(LuauTypeInferIterationLimit);
|
|||
LUAU_FASTINT(LuauTarjanChildLimit)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLogFragmentsFromAutocomplete)
|
||||
LUAU_FASTFLAGVARIABLE(LuauBetterScopeSelection)
|
||||
LUAU_FASTFLAGVARIABLE(LuauBlockDiffFragmentSelection)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFragmentAcMemoryLeak)
|
||||
LUAU_FASTFLAGVARIABLE(LuauGlobalVariableModuleIsolation)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFragmentAutocompleteIfRecommendations)
|
||||
LUAU_FASTFLAG(LuauExpectedTypeVisitor)
|
||||
LUAU_FASTFLAGVARIABLE(LuauPopulateRefinedTypesInFragmentFromOldSolver)
|
||||
LUAU_FASTFLAG(LuauUseWorkspacePropToChooseSolver)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFragmentRequiresCanBeResolvedToAModule)
|
||||
LUAU_FASTFLAG(LuauFragmentAutocompleteTracksRValueRefinements)
|
||||
LUAU_FASTFLAGVARIABLE(LuauPopulateSelfTypesInFragment)
|
||||
LUAU_FASTFLAGVARIABLE(LuauForInProvidesRecommendations)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -162,22 +156,52 @@ Location getFragmentLocation(AstStat* nearestStatement, const Position& cursorPo
|
|||
|
||||
if (auto forStat = nearestStatement->as<AstStatFor>())
|
||||
{
|
||||
|
||||
if (FFlag::LuauForInProvidesRecommendations)
|
||||
{
|
||||
if (forStat->step && forStat->step->location.containsClosed(cursorPosition))
|
||||
return {forStat->step->location.begin, cursorPosition};
|
||||
if (forStat->to && forStat->to->location.containsClosed(cursorPosition))
|
||||
return {forStat->to->location.begin, cursorPosition};
|
||||
if (forStat->from && forStat->from->location.containsClosed(cursorPosition))
|
||||
return {forStat->from->location.begin, cursorPosition};
|
||||
}
|
||||
|
||||
if (!forStat->hasDo)
|
||||
return nonEmpty;
|
||||
else
|
||||
{
|
||||
if (FFlag::LuauForInProvidesRecommendations)
|
||||
{
|
||||
auto completeableExtents = Location{forStat->location.begin, forStat->doLocation.begin};
|
||||
if (completeableExtents.containsClosed(cursorPosition))
|
||||
return nonEmpty;
|
||||
}
|
||||
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
|
||||
if (auto forIn = nearestStatement->as<AstStatForIn>())
|
||||
{
|
||||
// If we don't have a do statement
|
||||
if (!forIn->hasDo)
|
||||
return nonEmpty;
|
||||
else
|
||||
{
|
||||
if (FFlag::LuauForInProvidesRecommendations)
|
||||
{
|
||||
auto completeableExtents = Location{forIn->location.begin, forIn->doLocation.begin};
|
||||
if (completeableExtents.containsClosed(cursorPosition))
|
||||
{
|
||||
if (!forIn->hasIn)
|
||||
return nonEmpty;
|
||||
else
|
||||
return Location{forIn->inLocation.begin, cursorPosition};
|
||||
}
|
||||
}
|
||||
return empty;
|
||||
}
|
||||
if (FFlag::LuauFragmentAutocompleteIfRecommendations)
|
||||
{
|
||||
}
|
||||
if (auto ifS = getNearestIfToCursor(nearestStatement, cursorPosition))
|
||||
{
|
||||
auto conditionExtents = Location{ifS->condition->location.begin, ifS->condition->location.end};
|
||||
|
@ -208,29 +232,6 @@ Location getFragmentLocation(AstStat* nearestStatement, const Position& cursorPo
|
|||
return empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto ifS = nearestStatement->as<AstStatIf>())
|
||||
{
|
||||
auto conditionExtents = Location{ifS->location.begin, ifS->condition->location.end};
|
||||
if (conditionExtents.containsClosed(cursorPosition))
|
||||
return nonEmpty;
|
||||
else if (ifS->thenbody->location.containsClosed(cursorPosition))
|
||||
return empty;
|
||||
else if (auto elseS = ifS->elsebody)
|
||||
{
|
||||
if (auto elseIf = ifS->elsebody->as<AstStatIf>())
|
||||
{
|
||||
if (elseIf->thenbody->hasEnd)
|
||||
return empty;
|
||||
else
|
||||
return {elseS->location.begin, cursorPosition};
|
||||
}
|
||||
return empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nonEmpty;
|
||||
}
|
||||
|
@ -381,8 +382,7 @@ FragmentAutocompleteAncestryResult findAncestryForFragmentParse(AstStatBlock* st
|
|||
// the freshest ast can sometimes be null if the parse was bad.
|
||||
if (lastGoodParse == nullptr)
|
||||
return {};
|
||||
FragmentRegion region = FFlag::LuauBlockDiffFragmentSelection ? getFragmentRegionWithBlockDiff(stale, lastGoodParse, cursorPos)
|
||||
: getFragmentRegion(lastGoodParse, cursorPos);
|
||||
FragmentRegion region = getFragmentRegionWithBlockDiff(stale, lastGoodParse, cursorPos);
|
||||
std::vector<AstNode*> ancestry = findAncestryAtPositionForAutocomplete(stale, cursorPos);
|
||||
LUAU_ASSERT(ancestry.size() >= 1);
|
||||
// We should only pick up locals that are before the region
|
||||
|
@ -524,19 +524,11 @@ std::optional<FragmentParseResult> parseFragment(
|
|||
if (p.root == nullptr)
|
||||
return std::nullopt;
|
||||
|
||||
std::vector<AstNode*> fabricatedAncestry;
|
||||
// Moves cannot be on the rhs of a ? : statement, so the assignment is placed in an if else stmt
|
||||
// Make sure to trim this comment after you remove FFlag::LuauFragmentAutocompleteIfRecommendations
|
||||
if (FFlag::LuauFragmentAutocompleteIfRecommendations)
|
||||
fabricatedAncestry = findAncestryAtPositionForAutocomplete(mostRecentParse, cursorPos);
|
||||
else
|
||||
fabricatedAncestry = std::move(result.ancestry);
|
||||
std::vector<AstNode*> fabricatedAncestry = findAncestryAtPositionForAutocomplete(mostRecentParse, cursorPos);
|
||||
std::vector<AstNode*> fragmentAncestry = findAncestryAtPositionForAutocomplete(p.root, cursorPos);
|
||||
|
||||
// Computes the accurate ancestry and then replaces the nodes that correspond to the fragment ancestry
|
||||
// Needed because we look up types by pointer identity
|
||||
if (FFlag::LuauFragmentAutocompleteIfRecommendations)
|
||||
{
|
||||
LUAU_ASSERT(!fabricatedAncestry.empty());
|
||||
auto back = fabricatedAncestry.size() - 1;
|
||||
for (auto it = fragmentAncestry.rbegin(); it != fragmentAncestry.rend(); ++it)
|
||||
|
@ -545,9 +537,6 @@ std::optional<FragmentParseResult> parseFragment(
|
|||
fabricatedAncestry[back] = *it;
|
||||
back--;
|
||||
}
|
||||
}
|
||||
else
|
||||
fabricatedAncestry.insert(fabricatedAncestry.end(), fragmentAncestry.begin(), fragmentAncestry.end());
|
||||
|
||||
if (nearestStatement == nullptr)
|
||||
nearestStatement = p.root;
|
||||
|
@ -629,7 +618,6 @@ struct UsageFinder : public AstVisitor
|
|||
|
||||
bool visit(AstExprGlobal* global) override
|
||||
{
|
||||
if (FFlag::LuauGlobalVariableModuleIsolation)
|
||||
globalDefsToPrePopulate.emplace_back(global->name, dfg->getDef(global));
|
||||
if (FFlag::LuauFragmentAutocompleteTracksRValueRefinements)
|
||||
{
|
||||
|
@ -640,12 +628,9 @@ struct UsageFinder : public AstVisitor
|
|||
}
|
||||
|
||||
bool visit(AstStatFunction* function) override
|
||||
{
|
||||
if (FFlag::LuauGlobalVariableModuleIsolation)
|
||||
{
|
||||
if (AstExprGlobal* g = function->name->as<AstExprGlobal>())
|
||||
globalFunctionsReferenced.emplace_back(g->name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -702,13 +687,6 @@ void cloneTypesFromFragment(
|
|||
destScope->lvalueTypes[d] = Luau::cloneIncremental(pair->second.typeId, *destArena, cloneState, destScope);
|
||||
destScope->bindings[pair->first] = Luau::cloneIncremental(pair->second, *destArena, cloneState, destScope);
|
||||
}
|
||||
else if (FFlag::LuauBetterScopeSelection && !FFlag::LuauBlockDiffFragmentSelection)
|
||||
{
|
||||
destScope->lvalueTypes[d] = builtins->unknownType;
|
||||
Binding b;
|
||||
b.typeId = builtins->unknownType;
|
||||
destScope->bindings[Symbol(loc)] = b;
|
||||
}
|
||||
}
|
||||
|
||||
if (FFlag::LuauFragmentAutocompleteTracksRValueRefinements)
|
||||
|
@ -724,7 +702,7 @@ void cloneTypesFromFragment(
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (FFlag::LuauPopulateRefinedTypesInFragmentFromOldSolver && !staleModule->checkedInNewSolver)
|
||||
else if (!staleModule->checkedInNewSolver)
|
||||
{
|
||||
for (const auto& [d, loc] : f.localBindingsReferenced)
|
||||
{
|
||||
|
@ -761,8 +739,6 @@ void cloneTypesFromFragment(
|
|||
}
|
||||
}
|
||||
|
||||
if (FFlag::LuauGlobalVariableModuleIsolation)
|
||||
{
|
||||
// Fourth - prepopulate the global function types
|
||||
for (const auto& name : f.globalFunctionsReferenced)
|
||||
{
|
||||
|
@ -797,7 +773,6 @@ void cloneTypesFromFragment(
|
|||
destScope->lvalueTypes[def] = *ty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, clone the returnType on the staleScope. This helps avoid potential leaks of free types.
|
||||
if (staleScope->returnType)
|
||||
|
@ -952,11 +927,6 @@ static std::pair<size_t, size_t> getDocumentOffsets(std::string_view src, const
|
|||
if (endPos.line == lineCount && endPos.column == colCount)
|
||||
{
|
||||
endOffset = docOffset;
|
||||
if (!FFlag::LuauFragmentAutocompleteIfRecommendations)
|
||||
{
|
||||
while (endOffset < src.size() && src[endOffset] != '\n')
|
||||
endOffset++;
|
||||
}
|
||||
foundEnd = true;
|
||||
}
|
||||
|
||||
|
@ -1006,8 +976,6 @@ ScopePtr findClosestScope_DEPRECATED(const ModulePtr& module, const AstStat* nea
|
|||
ScopePtr findClosestScope(const ModulePtr& module, const Position& scopePos)
|
||||
{
|
||||
LUAU_ASSERT(module->hasModuleScope());
|
||||
if (FFlag::LuauBlockDiffFragmentSelection)
|
||||
{
|
||||
ScopePtr closest = module->getModuleScope();
|
||||
// find the scope the nearest statement belonged to.
|
||||
for (const auto& [loc, sc] : module->scopes)
|
||||
|
@ -1021,18 +989,6 @@ ScopePtr findClosestScope(const ModulePtr& module, const Position& scopePos)
|
|||
}
|
||||
return closest;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScopePtr closest = module->getModuleScope();
|
||||
// find the scope the nearest statement belonged to.
|
||||
for (const auto& [loc, sc] : module->scopes)
|
||||
{
|
||||
if (sc->location.contains(scopePos) && closest->location.begin < sc->location.begin)
|
||||
closest = sc;
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<FragmentParseResult> parseFragment_DEPRECATED(
|
||||
AstStatBlock* root,
|
||||
|
@ -1228,7 +1184,7 @@ FragmentTypeCheckResult typecheckFragment_(
|
|||
NotNull{&resolver},
|
||||
frontend.builtinTypes,
|
||||
iceHandler,
|
||||
FFlag::LuauGlobalVariableModuleIsolation ? freshChildOfNearestScope : stale->getModuleScope(),
|
||||
freshChildOfNearestScope,
|
||||
frontend.globals.globalTypeFunctionScope,
|
||||
nullptr,
|
||||
nullptr,
|
||||
|
@ -1299,8 +1255,6 @@ FragmentTypeCheckResult typecheckFragment_(
|
|||
|
||||
reportWaypoint(reporter, FragmentAutocompleteWaypoint::ConstraintSolverEnd);
|
||||
|
||||
if (FFlag::LuauExpectedTypeVisitor)
|
||||
{
|
||||
ExpectedTypeVisitor etv{
|
||||
NotNull{&incrementalModule->astTypes},
|
||||
NotNull{&incrementalModule->astExpectedTypes},
|
||||
|
@ -1310,7 +1264,6 @@ FragmentTypeCheckResult typecheckFragment_(
|
|||
NotNull{freshChildOfNearestScope.get()}
|
||||
};
|
||||
root->visit(&etv);
|
||||
}
|
||||
|
||||
// In frontend we would forbid internal types
|
||||
// because this is just for autocomplete, we don't actually care
|
||||
|
@ -1386,7 +1339,7 @@ FragmentTypeCheckResult typecheckFragment__DEPRECATED(
|
|||
NotNull{&resolver},
|
||||
frontend.builtinTypes,
|
||||
iceHandler,
|
||||
FFlag::LuauGlobalVariableModuleIsolation ? freshChildOfNearestScope : stale->getModuleScope(),
|
||||
freshChildOfNearestScope,
|
||||
frontend.globals.globalTypeFunctionScope,
|
||||
nullptr,
|
||||
nullptr,
|
||||
|
@ -1457,8 +1410,6 @@ FragmentTypeCheckResult typecheckFragment__DEPRECATED(
|
|||
|
||||
reportWaypoint(reporter, FragmentAutocompleteWaypoint::ConstraintSolverEnd);
|
||||
|
||||
if (FFlag::LuauExpectedTypeVisitor)
|
||||
{
|
||||
ExpectedTypeVisitor etv{
|
||||
NotNull{&incrementalModule->astTypes},
|
||||
NotNull{&incrementalModule->astExpectedTypes},
|
||||
|
@ -1468,7 +1419,6 @@ FragmentTypeCheckResult typecheckFragment__DEPRECATED(
|
|||
NotNull{freshChildOfNearestScope.get()}
|
||||
};
|
||||
root->visit(&etv);
|
||||
}
|
||||
|
||||
// In frontend we would forbid internal types
|
||||
// because this is just for autocomplete, we don't actually care
|
||||
|
@ -1507,8 +1457,7 @@ std::pair<FragmentTypeCheckStatus, FragmentTypeCheckResult> typecheckFragment(
|
|||
}
|
||||
|
||||
std::optional<FragmentParseResult> tryParse;
|
||||
tryParse = FFlag::LuauBetterScopeSelection ? parseFragment(module->root, recentParse, module->names.get(), src, cursorPos, fragmentEndPosition)
|
||||
: parseFragment_DEPRECATED(module->root, module->names.get(), src, cursorPos, fragmentEndPosition);
|
||||
tryParse = parseFragment(module->root, recentParse, module->names.get(), src, cursorPos, fragmentEndPosition);
|
||||
|
||||
|
||||
if (!tryParse)
|
||||
|
@ -1520,8 +1469,7 @@ std::pair<FragmentTypeCheckStatus, FragmentTypeCheckResult> typecheckFragment(
|
|||
return {FragmentTypeCheckStatus::SkipAutocomplete, {}};
|
||||
|
||||
FrontendOptions frontendOptions = opts.value_or(frontend.options);
|
||||
const ScopePtr& closestScope = FFlag::LuauBetterScopeSelection ? findClosestScope(module, parseResult.scopePos)
|
||||
: findClosestScope_DEPRECATED(module, parseResult.nearestStatement);
|
||||
const ScopePtr& closestScope = findClosestScope(module, parseResult.scopePos);
|
||||
FragmentTypeCheckResult result =
|
||||
FFlag::LuauFragmentRequiresCanBeResolvedToAModule
|
||||
? typecheckFragment_(frontend, parseResult.root, module, closestScope, cursorPos, std::move(parseResult.alloc), frontendOptions, reporter)
|
||||
|
@ -1590,13 +1538,11 @@ FragmentAutocompleteResult fragmentAutocomplete(
|
|||
auto globalScope = (opts && opts->forAutocomplete) ? frontend.globalsForAutocomplete.globalScope.get() : frontend.globals.globalScope.get();
|
||||
if (FFlag::DebugLogFragmentsFromAutocomplete)
|
||||
logLuau("Fragment Autocomplete Source Script", src);
|
||||
TypeArena arenaForAutocomplete_DEPRECATED;
|
||||
if (FFlag::LuauFragmentAcMemoryLeak)
|
||||
unfreeze(tcResult.incrementalModule->internalTypes);
|
||||
auto result = Luau::autocomplete_(
|
||||
tcResult.incrementalModule,
|
||||
frontend.builtinTypes,
|
||||
FFlag::LuauFragmentAcMemoryLeak ? &tcResult.incrementalModule->internalTypes : &arenaForAutocomplete_DEPRECATED,
|
||||
&tcResult.incrementalModule->internalTypes,
|
||||
tcResult.ancestry,
|
||||
globalScope,
|
||||
tcResult.freshScope,
|
||||
|
@ -1604,10 +1550,9 @@ FragmentAutocompleteResult fragmentAutocomplete(
|
|||
frontend.fileResolver,
|
||||
std::move(callback)
|
||||
);
|
||||
if (FFlag::LuauFragmentAcMemoryLeak)
|
||||
freeze(tcResult.incrementalModule->internalTypes);
|
||||
reportWaypoint(reporter, FragmentAutocompleteWaypoint::AutocompleteEnd);
|
||||
return {std::move(tcResult.incrementalModule), tcResult.freshScope.get(), std::move(arenaForAutocomplete_DEPRECATED), std::move(result)};
|
||||
return {std::move(tcResult.incrementalModule), tcResult.freshScope.get(), std::move(result)};
|
||||
}
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -44,12 +44,11 @@ LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJsonFile)
|
|||
LUAU_FASTFLAGVARIABLE(DebugLuauForbidInternalTypes)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForceStrictMode)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForceNonStrictMode)
|
||||
LUAU_FASTFLAGVARIABLE(LuauExpectedTypeVisitor)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTrackTypeAllocations)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUseWorkspacePropToChooseSolver)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictSuppressSoloConstraintSolvingIncomplete)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauAlwaysShowConstraintSolvingIncomplete)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving3)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -211,7 +210,8 @@ LoadDefinitionFileResult Frontend::loadDefinitionFile(
|
|||
if (parseResult.errors.size() > 0)
|
||||
return LoadDefinitionFileResult{false, std::move(parseResult), std::move(sourceModule), nullptr};
|
||||
|
||||
ModulePtr checkedModule = check(sourceModule, Mode::Definition, {}, std::nullopt, /*forAutocomplete*/ false, /*recordJsonLog*/ false, {});
|
||||
Frontend::Stats dummyStats;
|
||||
ModulePtr checkedModule = check(sourceModule, Mode::Definition, {}, std::nullopt, /*forAutocomplete*/ false, /*recordJsonLog*/ false, dummyStats, {});
|
||||
|
||||
if (checkedModule->errors.size() > 0)
|
||||
return LoadDefinitionFileResult{false, std::move(parseResult), std::move(sourceModule), std::move(checkedModule)};
|
||||
|
@ -988,6 +988,7 @@ void Frontend::checkBuildQueueItem(BuildQueueItem& item)
|
|||
environmentScope,
|
||||
/*forAutocomplete*/ true,
|
||||
/*recordJsonLog*/ false,
|
||||
item.stats,
|
||||
std::move(typeCheckLimits)
|
||||
);
|
||||
|
||||
|
@ -1018,7 +1019,7 @@ void Frontend::checkBuildQueueItem(BuildQueueItem& item)
|
|||
}
|
||||
|
||||
ModulePtr module =
|
||||
check(sourceModule, mode, requireCycles, environmentScope, /*forAutocomplete*/ false, item.recordJsonLog, std::move(typeCheckLimits));
|
||||
check(sourceModule, mode, requireCycles, environmentScope, /*forAutocomplete*/ false, item.recordJsonLog, item.stats, std::move(typeCheckLimits));
|
||||
|
||||
double duration = getTimestamp() - timestamp;
|
||||
|
||||
|
@ -1171,6 +1172,8 @@ void Frontend::recordItemResult(const BuildQueueItem& item)
|
|||
stats.strSingletonsMinted += item.stats.strSingletonsMinted;
|
||||
stats.uniqueStrSingletonsMinted += item.stats.uniqueStrSingletonsMinted;
|
||||
}
|
||||
|
||||
stats.dynamicConstraintsCreated += item.stats.dynamicConstraintsCreated;
|
||||
}
|
||||
|
||||
void Frontend::performQueueItemTask(std::shared_ptr<BuildQueueWorkState> state, size_t itemPos)
|
||||
|
@ -1333,41 +1336,6 @@ const SourceModule* Frontend::getSourceModule(const ModuleName& moduleName) cons
|
|||
return const_cast<Frontend*>(this)->getSourceModule(moduleName);
|
||||
}
|
||||
|
||||
ModulePtr check(
|
||||
const SourceModule& sourceModule,
|
||||
Mode mode,
|
||||
const std::vector<RequireCycle>& requireCycles,
|
||||
NotNull<BuiltinTypes> builtinTypes,
|
||||
NotNull<InternalErrorReporter> iceHandler,
|
||||
NotNull<ModuleResolver> moduleResolver,
|
||||
NotNull<FileResolver> fileResolver,
|
||||
const ScopePtr& parentScope,
|
||||
const ScopePtr& typeFunctionScope,
|
||||
std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope,
|
||||
FrontendOptions options,
|
||||
TypeCheckLimits limits,
|
||||
std::function<void(const ModuleName&, std::string)> writeJsonLog
|
||||
)
|
||||
{
|
||||
const bool recordJsonLog = FFlag::DebugLuauLogSolverToJson;
|
||||
return check(
|
||||
sourceModule,
|
||||
mode,
|
||||
requireCycles,
|
||||
builtinTypes,
|
||||
iceHandler,
|
||||
moduleResolver,
|
||||
fileResolver,
|
||||
parentScope,
|
||||
typeFunctionScope,
|
||||
std::move(prepareModuleScope),
|
||||
std::move(options),
|
||||
std::move(limits),
|
||||
recordJsonLog,
|
||||
std::move(writeJsonLog)
|
||||
);
|
||||
}
|
||||
|
||||
struct InternalTypeFinder : TypeOnceVisitor
|
||||
{
|
||||
InternalTypeFinder()
|
||||
|
@ -1431,6 +1399,7 @@ ModulePtr check(
|
|||
FrontendOptions options,
|
||||
TypeCheckLimits limits,
|
||||
bool recordJsonLog,
|
||||
Frontend::Stats& stats,
|
||||
std::function<void(const ModuleName&, std::string)> writeJsonLog
|
||||
)
|
||||
{
|
||||
|
@ -1555,6 +1524,8 @@ ModulePtr check(
|
|||
result->cancelled = true;
|
||||
}
|
||||
|
||||
stats.dynamicConstraintsCreated += cs->solverConstraints.size();
|
||||
|
||||
if (recordJsonLog)
|
||||
{
|
||||
std::string output = logger->compileOutput();
|
||||
|
@ -1641,8 +1612,6 @@ ModulePtr check(
|
|||
result->errors.clear();
|
||||
}
|
||||
|
||||
if (FFlag::LuauExpectedTypeVisitor)
|
||||
{
|
||||
ExpectedTypeVisitor etv{
|
||||
NotNull{&result->astTypes},
|
||||
NotNull{&result->astExpectedTypes},
|
||||
|
@ -1652,11 +1621,10 @@ ModulePtr check(
|
|||
NotNull{parentScope.get()}
|
||||
};
|
||||
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::LuauLimitDynamicConstraintSolving3)
|
||||
{
|
||||
if (FFlag::DebugLuauForbidInternalTypes)
|
||||
{
|
||||
|
@ -1696,7 +1664,7 @@ ModulePtr check(
|
|||
else
|
||||
result->clonePublicInterface_DEPRECATED(builtinTypes, *iceHandler);
|
||||
|
||||
if (!FFlag::LuauLimitDynamicConstraintSolving)
|
||||
if (!FFlag::LuauLimitDynamicConstraintSolving3)
|
||||
{
|
||||
if (FFlag::DebugLuauForbidInternalTypes)
|
||||
{
|
||||
|
@ -1751,6 +1719,7 @@ ModulePtr Frontend::check(
|
|||
std::optional<ScopePtr> environmentScope,
|
||||
bool forAutocomplete,
|
||||
bool recordJsonLog,
|
||||
Frontend::Stats& stats,
|
||||
TypeCheckLimits typeCheckLimits
|
||||
)
|
||||
{
|
||||
|
@ -1778,6 +1747,7 @@ ModulePtr Frontend::check(
|
|||
options,
|
||||
std::move(typeCheckLimits),
|
||||
recordJsonLog,
|
||||
stats,
|
||||
writeJsonLog
|
||||
);
|
||||
}
|
||||
|
|
|
@ -15,11 +15,7 @@
|
|||
#include "Luau/TypePack.h"
|
||||
#include "Luau/VisitType.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAGVARIABLE(LuauGeneralizationCannotMutateAcrossModules)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -484,8 +480,6 @@ struct FreeTypeSearcher : TypeVisitor
|
|||
}
|
||||
|
||||
for (const auto& [_name, prop] : tt.props)
|
||||
{
|
||||
if (FFlag::LuauEnableWriteOnlyProperties)
|
||||
{
|
||||
if (prop.isReadOnly())
|
||||
{
|
||||
|
@ -502,10 +496,7 @@ struct FreeTypeSearcher : TypeVisitor
|
|||
{
|
||||
Polarity p = polarity;
|
||||
polarity = Polarity::Mixed;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
traverse(*prop.readTy);
|
||||
else
|
||||
traverse(prop.type_DEPRECATED());
|
||||
polarity = p;
|
||||
}
|
||||
else
|
||||
|
@ -519,24 +510,6 @@ struct FreeTypeSearcher : TypeVisitor
|
|||
polarity = p;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prop.isReadOnly())
|
||||
traverse(*prop.readTy);
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(prop.isShared());
|
||||
|
||||
Polarity p = polarity;
|
||||
polarity = Polarity::Mixed;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
traverse(*prop.readTy);
|
||||
else
|
||||
traverse(prop.type_DEPRECATED());
|
||||
polarity = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tt.indexer)
|
||||
{
|
||||
|
@ -1446,8 +1419,6 @@ struct GenericCounter : TypeVisitor
|
|||
const Polarity previous = polarity;
|
||||
|
||||
for (const auto& [_name, prop] : tt.props)
|
||||
{
|
||||
if (FFlag::LuauEnableWriteOnlyProperties)
|
||||
{
|
||||
if (prop.isReadOnly())
|
||||
{
|
||||
|
@ -1464,10 +1435,7 @@ struct GenericCounter : TypeVisitor
|
|||
{
|
||||
Polarity p = polarity;
|
||||
polarity = Polarity::Mixed;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
traverse(*prop.readTy);
|
||||
else
|
||||
traverse(prop.type_DEPRECATED());
|
||||
polarity = p;
|
||||
}
|
||||
else
|
||||
|
@ -1481,24 +1449,6 @@ struct GenericCounter : TypeVisitor
|
|||
polarity = p;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prop.isReadOnly())
|
||||
traverse(*prop.readTy);
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(prop.isShared());
|
||||
|
||||
Polarity p = polarity;
|
||||
polarity = Polarity::Mixed;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
traverse(*prop.readTy);
|
||||
else
|
||||
traverse(prop.type_DEPRECATED());
|
||||
polarity = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tt.indexer)
|
||||
{
|
||||
|
@ -1596,7 +1546,7 @@ void pruneUnnecessaryGenerics(
|
|||
{
|
||||
if (state.count == 1 && state.polarity != Polarity::Mixed)
|
||||
{
|
||||
if (FFlag::LuauGeneralizationCannotMutateAcrossModules && arena.get() != generic->owningArena)
|
||||
if (arena.get() != generic->owningArena)
|
||||
continue;
|
||||
emplaceType<BoundType>(asMutable(generic), builtinTypes->unknownType);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "Luau/VisitType.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAGVARIABLE(LuauInferPolarityOfReadWriteProperties)
|
||||
|
||||
namespace Luau
|
||||
|
@ -51,8 +50,6 @@ struct InferPolarity : TypeVisitor
|
|||
return false;
|
||||
|
||||
const Polarity p = polarity;
|
||||
if (FFlag::LuauInferPolarityOfReadWriteProperties || FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
for (const auto& [name, prop] : tt.props)
|
||||
{
|
||||
if (prop.isShared())
|
||||
|
@ -74,30 +71,6 @@ struct InferPolarity : TypeVisitor
|
|||
traverse(*prop.writeTy);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& [name, prop] : tt.props)
|
||||
{
|
||||
if (prop.isShared())
|
||||
{
|
||||
polarity = Polarity::Mixed;
|
||||
traverse(prop.type_DEPRECATED());
|
||||
}
|
||||
else if (prop.isReadOnly())
|
||||
{
|
||||
polarity = p;
|
||||
traverse(*prop.readTy);
|
||||
}
|
||||
else if (prop.isWriteOnly())
|
||||
{
|
||||
polarity = invert(p);
|
||||
traverse(*prop.writeTy);
|
||||
}
|
||||
else
|
||||
LUAU_ASSERT(!"Unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
if (tt.indexer)
|
||||
{
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LuauUseWorkspacePropToChooseSolver)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving3)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -100,6 +100,7 @@ struct ClonePublicInterface : Substitution
|
|||
// NOTE: This can be made non-optional after
|
||||
// LuauUseWorkspacePropToChooseSolver is clipped.
|
||||
std::optional<SolverMode> solverMode{std::nullopt};
|
||||
bool internalTypeEscaped = false;
|
||||
|
||||
ClonePublicInterface(const TxnLog* log, NotNull<BuiltinTypes> builtinTypes, Module* module)
|
||||
: Substitution(log, &module->interfaceTypes)
|
||||
|
@ -177,21 +178,20 @@ struct ClonePublicInterface : Substitution
|
|||
{
|
||||
ttv->level = TypeLevel{0, 0};
|
||||
if (isNewSolver())
|
||||
{
|
||||
ttv->scope = nullptr;
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving3)
|
||||
ttv->state = TableState::Sealed;
|
||||
}
|
||||
}
|
||||
|
||||
if (isNewSolver())
|
||||
{
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving)
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving3)
|
||||
{
|
||||
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"}
|
||||
);
|
||||
internalTypeEscaped = true;
|
||||
result = builtinTypes->errorType;
|
||||
}
|
||||
else if (auto genericty = getMutable<GenericType>(result))
|
||||
|
@ -225,16 +225,11 @@ struct ClonePublicInterface : Substitution
|
|||
{
|
||||
if (isNewSolver())
|
||||
{
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving)
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving3)
|
||||
{
|
||||
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"}
|
||||
);
|
||||
internalTypeEscaped = true;
|
||||
return builtinTypes->errorTypePack;
|
||||
}
|
||||
|
||||
|
@ -369,6 +364,16 @@ void Module::clonePublicInterface_DEPRECATED(NotNull<BuiltinTypes> builtinTypes,
|
|||
*tf = clonePublicInterface.cloneTypeFun(*tf);
|
||||
}
|
||||
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving3 && clonePublicInterface.internalTypeEscaped)
|
||||
{
|
||||
errors.emplace_back(
|
||||
Location{}, // Not amazing but the best we can do.
|
||||
name,
|
||||
InternalError{"An internal type is escaping this module; please report this bug at "
|
||||
"https://github.com/luau-lang/luau/issues"}
|
||||
);
|
||||
}
|
||||
|
||||
// Copy external stuff over to Module itself
|
||||
this->returnType = moduleScope->returnType;
|
||||
this->exportedTypeBindings = moduleScope->exportedTypeBindings;
|
||||
|
@ -410,6 +415,16 @@ void Module::clonePublicInterface(NotNull<BuiltinTypes> builtinTypes, InternalEr
|
|||
*tf = clonePublicInterface.cloneTypeFun(*tf);
|
||||
}
|
||||
|
||||
if (FFlag::LuauLimitDynamicConstraintSolving3 && clonePublicInterface.internalTypeEscaped)
|
||||
{
|
||||
errors.emplace_back(
|
||||
Location{}, // Not amazing but the best we can do.
|
||||
name,
|
||||
InternalError{"An internal type is escaping this module; please report this bug at "
|
||||
"https://github.com/luau-lang/luau/issues"}
|
||||
);
|
||||
}
|
||||
|
||||
// Copy external stuff over to Module itself
|
||||
this->returnType = moduleScope->returnType;
|
||||
this->exportedTypeBindings = moduleScope->exportedTypeBindings;
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictFixGenericTypePacks)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictMoreUnknownSymbols)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictNoErrorsPassingNever)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewNonStrictSuppressesDynamicRequireErrors)
|
||||
|
@ -1095,8 +1094,6 @@ struct NonStrictTypeChecker
|
|||
Scope* scope = findInnermostScope(tp->location);
|
||||
LUAU_ASSERT(scope);
|
||||
|
||||
if (FFlag::LuauNewNonStrictFixGenericTypePacks)
|
||||
{
|
||||
if (std::optional<TypePackId> alias = scope->lookupPack(tp->genericName.value))
|
||||
return;
|
||||
|
||||
|
@ -1111,28 +1108,6 @@ struct NonStrictTypeChecker
|
|||
|
||||
reportError(UnknownSymbol{tp->genericName.value, UnknownSymbol::Context::Type}, tp->location);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::optional<TypePackId> alias = scope->lookupPack(tp->genericName.value);
|
||||
if (!alias.has_value())
|
||||
{
|
||||
if (scope->lookupType(tp->genericName.value))
|
||||
{
|
||||
reportError(
|
||||
SwappedGenericTypeParameter{
|
||||
tp->genericName.value,
|
||||
SwappedGenericTypeParameter::Kind::Pack,
|
||||
},
|
||||
tp->location
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reportError(UnknownSymbol{tp->genericName.value, UnknownSymbol::Context::Type}, tp->location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void visitGenerics(AstArray<AstGenericType*> generics, AstArray<AstGenericTypePack*> genericPacks)
|
||||
{
|
||||
|
|
|
@ -21,7 +21,6 @@ LUAU_FASTINTVARIABLE(LuauNormalizeCacheLimit, 100000)
|
|||
LUAU_FASTINTVARIABLE(LuauNormalizeIntersectionLimit, 200)
|
||||
LUAU_FASTINTVARIABLE(LuauNormalizeUnionLimit, 100)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNormalizationIntersectTablesPreservesExternTypes)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNormalizationReorderFreeTypeIntersect)
|
||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||
LUAU_FASTFLAG(LuauUseWorkspacePropToChooseSolver)
|
||||
|
@ -3061,7 +3060,7 @@ NormalizationResult Normalizer::intersectNormalWithTy(
|
|||
}
|
||||
else if (get<TableType>(there) || get<MetatableType>(there))
|
||||
{
|
||||
if (useNewLuauSolver() && FFlag::LuauNormalizationIntersectTablesPreservesExternTypes)
|
||||
if (useNewLuauSolver())
|
||||
{
|
||||
NormalizedExternType externTypes = std::move(here.externTypes);
|
||||
TypeIds tables = std::move(here.tables);
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "Luau/TypeUtils.h"
|
||||
#include "Luau/Unifier2.h"
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
|
||||
namespace Luau
|
||||
|
@ -298,8 +297,6 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
|||
// If any of the unsatisfied arguments are not supertypes of
|
||||
// nil or are `unknown`, then this overload does not match.
|
||||
for (size_t i = firstUnsatisfiedArgument; i < requiredHead.size(); ++i)
|
||||
{
|
||||
if (FFlag::LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
{
|
||||
if (get<UnknownType>(follow(requiredHead[i])) || !subtyping.isSubtype(builtinTypes->nilType, requiredHead[i], scope).isSubtype)
|
||||
{
|
||||
|
@ -313,17 +310,6 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
|||
return {Analysis::ArityMismatch, {std::move(error)}};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!subtyping.isSubtype(builtinTypes->nilType, requiredHead[i], scope).isSubtype)
|
||||
{
|
||||
auto [minParams, optMaxParams] = getParameterExtents(TxnLog::empty(), fn->argTypes);
|
||||
TypeError error{fnExpr->location, CountMismatch{minParams, optMaxParams, args->head.size(), CountMismatch::Arg, isVariadic}};
|
||||
|
||||
return {Analysis::ArityMismatch, {std::move(error)}};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {Analysis::Ok, {}};
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
LUAU_FASTINT(LuauTypeReductionRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_DYNAMIC_FASTINTVARIABLE(LuauSimplificationComplexityLimit, 8)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSimplificationTableExternType)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAGVARIABLE(LuauRelateTablesAreNeverDisjoint)
|
||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauMissingSeenSetRelate)
|
||||
|
@ -307,11 +305,7 @@ Relation relateTables(TypeId left, TypeId right, SimplifierSeenSet& seen)
|
|||
if (!leftProp.isShared() || !rightProp.isShared())
|
||||
return Relation::Intersects;
|
||||
|
||||
Relation r;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
r = relate(*leftProp.readTy, *rightProp.readTy, seen);
|
||||
else
|
||||
r = relate(leftProp.type_DEPRECATED(), rightProp.type_DEPRECATED(), seen);
|
||||
Relation r = relate(*leftProp.readTy, *rightProp.readTy, seen);
|
||||
if (r == Relation::Coincident && 1 != leftTable->props.size())
|
||||
{
|
||||
// eg {tag: "cat", prop: string} & {tag: "cat"}
|
||||
|
@ -394,12 +388,9 @@ Relation relate(TypeId left, TypeId right, SimplifierSeenSet& seen)
|
|||
if (isTypeVariable(left) || isTypeVariable(right))
|
||||
return Relation::Intersects;
|
||||
|
||||
if (FFlag::LuauSimplificationTableExternType)
|
||||
{
|
||||
// if either type is a type function, we cannot know if they'll be related.
|
||||
if (get<TypeFunctionInstanceType>(left) || get<TypeFunctionInstanceType>(right))
|
||||
return Relation::Intersects;
|
||||
}
|
||||
|
||||
if (get<ErrorType>(left))
|
||||
{
|
||||
|
@ -588,8 +579,6 @@ Relation relate(TypeId left, TypeId right, SimplifierSeenSet& seen)
|
|||
return Relation::Intersects;
|
||||
}
|
||||
|
||||
if (FFlag::LuauSimplificationTableExternType)
|
||||
{
|
||||
if (auto re = get<ExternType>(right))
|
||||
{
|
||||
Relation overall = Relation::Coincident;
|
||||
|
@ -604,13 +593,11 @@ Relation relate(TypeId left, TypeId right, SimplifierSeenSet& seen)
|
|||
LUAU_ASSERT(prop.readTy && propInExternType->second.readTy);
|
||||
propRel = relate(*prop.readTy, *propInExternType->second.readTy, seen);
|
||||
}
|
||||
else if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(prop.readTy && propInExternType->second.readTy);
|
||||
propRel = relate(*prop.readTy, *propInExternType->second.readTy);
|
||||
}
|
||||
else
|
||||
propRel = relate(prop.type_DEPRECATED(), propInExternType->second.type_DEPRECATED());
|
||||
|
||||
if (propRel == Relation::Disjoint)
|
||||
return Relation::Disjoint;
|
||||
|
@ -624,7 +611,6 @@ Relation relate(TypeId left, TypeId right, SimplifierSeenSet& seen)
|
|||
|
||||
return overall;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO metatables
|
||||
|
||||
|
@ -1319,11 +1305,7 @@ std::optional<TypeId> TypeSimplifier::basicIntersect(TypeId left, TypeId right)
|
|||
auto it = rt->props.find(propName);
|
||||
if (it != rt->props.end() && leftProp.isShared() && it->second.isShared())
|
||||
{
|
||||
Relation r;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
r = relate(*leftProp.readTy, *it->second.readTy);
|
||||
else
|
||||
r = relate(leftProp.type_DEPRECATED(), it->second.type_DEPRECATED());
|
||||
Relation r = relate(*leftProp.readTy, *it->second.readTy);
|
||||
|
||||
switch (r)
|
||||
{
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
LUAU_FASTINTVARIABLE(LuauTarjanChildLimit, 10000)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTINTVARIABLE(LuauTarjanPreallocationSize, 256)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAG(LuauSolverAgnosticClone)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -190,15 +188,10 @@ void Tarjan::visitChildren(TypeId ty, int index)
|
|||
{
|
||||
LUAU_ASSERT(!ttv->boundTo);
|
||||
for (const auto& [name, prop] : ttv->props)
|
||||
{
|
||||
if (FFlag::LuauSolverV2 || FFlag::LuauSolverAgnosticClone)
|
||||
{
|
||||
visitChild(prop.readTy);
|
||||
visitChild(prop.writeTy);
|
||||
}
|
||||
else
|
||||
visitChild(prop.type_DEPRECATED());
|
||||
}
|
||||
|
||||
if (ttv->indexer)
|
||||
{
|
||||
|
@ -247,7 +240,7 @@ void Tarjan::visitChildren(TypeId ty, int index)
|
|||
{
|
||||
for (const auto& [name, prop] : etv->props)
|
||||
{
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
visitChild(prop.readTy);
|
||||
visitChild(prop.writeTy);
|
||||
|
@ -782,17 +775,12 @@ void Substitution::replaceChildren(TypeId ty)
|
|||
{
|
||||
LUAU_ASSERT(!ttv->boundTo);
|
||||
for (auto& [name, prop] : ttv->props)
|
||||
{
|
||||
if (FFlag::LuauSolverV2 || FFlag::LuauSolverAgnosticClone)
|
||||
{
|
||||
if (prop.readTy)
|
||||
prop.readTy = replace(prop.readTy);
|
||||
if (prop.writeTy)
|
||||
prop.writeTy = replace(prop.writeTy);
|
||||
}
|
||||
else
|
||||
prop.setType(replace(prop.type_DEPRECATED()));
|
||||
}
|
||||
|
||||
if (ttv->indexer)
|
||||
{
|
||||
|
@ -841,7 +829,7 @@ void Substitution::replaceChildren(TypeId ty)
|
|||
{
|
||||
for (auto& [name, prop] : etv->props)
|
||||
{
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
if (prop.readTy)
|
||||
prop.readTy = replace(prop.readTy);
|
||||
|
|
|
@ -21,9 +21,9 @@ LUAU_FASTFLAGVARIABLE(DebugLuauSubtypingCheckPathValidity)
|
|||
LUAU_FASTINTVARIABLE(LuauSubtypingReasoningLimit, 100)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSubtypingCheckFunctionGenericCounts)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAGVARIABLE(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauMissingFollowMappedGenericPacks)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSubtypingNegationsChecksNormalizationComplexity)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -606,11 +606,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
|||
RecursionCounter rc(&counters.recursionCount);
|
||||
|
||||
if (counters.recursionLimit > 0 && counters.recursionLimit < counters.recursionCount)
|
||||
{
|
||||
SubtypingResult result;
|
||||
result.normalizationTooComplex = true;
|
||||
return result;
|
||||
}
|
||||
return SubtypingResult{false, true};
|
||||
|
||||
subTy = follow(subTy);
|
||||
superTy = follow(superTy);
|
||||
|
@ -672,10 +668,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
|||
* For now, we do the conservative thing and refuse to cache anything
|
||||
* that touches a cycle.
|
||||
*/
|
||||
SubtypingResult res;
|
||||
res.isSubtype = true;
|
||||
res.isCacheable = false;
|
||||
return res;
|
||||
return SubtypingResult{true, false, false};
|
||||
}
|
||||
|
||||
SeenSetPopper ssp{&seenTypes, typePair};
|
||||
|
@ -696,19 +689,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
|||
{
|
||||
result = isCovariantWith(env, subTy, superUnion, scope);
|
||||
if (!result.isSubtype && !result.normalizationTooComplex)
|
||||
{
|
||||
SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy), scope);
|
||||
|
||||
if (semantic.normalizationTooComplex)
|
||||
{
|
||||
result = semantic;
|
||||
}
|
||||
else if (semantic.isSubtype)
|
||||
{
|
||||
semantic.reasoning.clear();
|
||||
result = semantic;
|
||||
}
|
||||
}
|
||||
result = trySemanticSubtyping(env, subTy, superTy, scope, result);
|
||||
}
|
||||
else if (auto superIntersection = get<IntersectionType>(superTy))
|
||||
result = isCovariantWith(env, subTy, superIntersection, scope);
|
||||
|
@ -716,21 +697,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
|||
{
|
||||
result = isCovariantWith(env, subIntersection, superTy, scope);
|
||||
if (!result.isSubtype && !result.normalizationTooComplex)
|
||||
{
|
||||
SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy), scope);
|
||||
|
||||
if (semantic.normalizationTooComplex)
|
||||
{
|
||||
result = semantic;
|
||||
}
|
||||
else if (semantic.isSubtype)
|
||||
{
|
||||
// Clear the semantic reasoning, as any reasonings within
|
||||
// potentially contain invalid paths.
|
||||
semantic.reasoning.clear();
|
||||
result = semantic;
|
||||
}
|
||||
}
|
||||
result = trySemanticSubtyping(env, subTy, superTy, scope, result);
|
||||
}
|
||||
else if (get<AnyType>(superTy))
|
||||
result = {true};
|
||||
|
@ -817,6 +784,10 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
|||
{
|
||||
result = isCovariantWith(env, subNegation, superTy, scope);
|
||||
if (!result.isSubtype && !result.normalizationTooComplex)
|
||||
{
|
||||
if (FFlag::LuauSubtypingNegationsChecksNormalizationComplexity)
|
||||
result = trySemanticSubtyping(env, subTy, superTy, scope, result);
|
||||
else
|
||||
{
|
||||
SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy), scope);
|
||||
if (semantic.isSubtype)
|
||||
|
@ -826,10 +797,15 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto superNegation = get<NegationType>(superTy))
|
||||
{
|
||||
result = isCovariantWith(env, subTy, superNegation, scope);
|
||||
if (!result.isSubtype && !result.normalizationTooComplex)
|
||||
{
|
||||
if (FFlag::LuauSubtypingNegationsChecksNormalizationComplexity)
|
||||
result = trySemanticSubtyping(env, subTy, superTy, scope, result);
|
||||
else
|
||||
{
|
||||
SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy), scope);
|
||||
if (semantic.isSubtype)
|
||||
|
@ -839,6 +815,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto subTypeFunctionInstance = get<TypeFunctionInstanceType>(subTy))
|
||||
{
|
||||
if (auto substSubTy = env.applyMappedGenerics(builtinTypes, arena, subTy))
|
||||
|
@ -901,12 +878,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId
|
|||
{
|
||||
std::pair<TypePackId, TypePackId> typePair = {subTp, superTp};
|
||||
if (!seenPacks.insert(typePair))
|
||||
{
|
||||
SubtypingResult res;
|
||||
res.isSubtype = true;
|
||||
res.isCacheable = false;
|
||||
return res;
|
||||
}
|
||||
return SubtypingResult{true, false, false};
|
||||
popper.emplace(&seenPacks, std::move(typePair));
|
||||
}
|
||||
|
||||
|
@ -1658,21 +1630,12 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Tabl
|
|||
if (isCovariantWith(env, builtinTypes->stringType, subTable->indexer->indexType, scope).isSubtype)
|
||||
{
|
||||
if (superProp.isShared())
|
||||
{
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
results.push_back(isInvariantWith(env, subTable->indexer->indexResultType, *superProp.readTy, scope)
|
||||
.withSubComponent(TypePath::TypeField::IndexResult)
|
||||
.withSuperComponent(TypePath::Property::read(name)));
|
||||
}
|
||||
else
|
||||
{
|
||||
results.push_back(isInvariantWith(env, subTable->indexer->indexResultType, superProp.type_DEPRECATED(), scope)
|
||||
.withSubComponent(TypePath::TypeField::IndexResult)
|
||||
.withSuperComponent(TypePath::Property::read(name)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (superProp.readTy)
|
||||
results.push_back(isCovariantWith(env, subTable->indexer->indexResultType, *superProp.readTy, scope)
|
||||
|
@ -1845,9 +1808,6 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Prim
|
|||
if (auto mttv = get<TableType>(follow(metatable)))
|
||||
{
|
||||
if (auto it = mttv->props.find("__index"); it != mttv->props.end())
|
||||
{
|
||||
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
// the `string` metatable should not have any write-only types.
|
||||
LUAU_ASSERT(*it->second.readTy);
|
||||
|
@ -1856,13 +1816,6 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Prim
|
|||
result.orElse(isCovariantWith(env, stringTable, superTable, scope)
|
||||
.withSubPath(TypePath::PathBuilder().mt().readProp("__index").build()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto stringTable = get<TableType>(it->second.type_DEPRECATED()))
|
||||
result.orElse(isCovariantWith(env, stringTable, superTable, scope)
|
||||
.withSubPath(TypePath::PathBuilder().mt().readProp("__index").build()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1890,8 +1843,6 @@ SubtypingResult Subtyping::isCovariantWith(
|
|||
if (auto mttv = get<TableType>(follow(metatable)))
|
||||
{
|
||||
if (auto it = mttv->props.find("__index"); it != mttv->props.end())
|
||||
{
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
// the `string` metatable should not have any write-only types.
|
||||
LUAU_ASSERT(*it->second.readTy);
|
||||
|
@ -1900,13 +1851,6 @@ SubtypingResult Subtyping::isCovariantWith(
|
|||
result.orElse(isCovariantWith(env, stringTable, superTable, scope)
|
||||
.withSubPath(TypePath::PathBuilder().mt().readProp("__index").build()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto stringTable = get<TableType>(it->second.type_DEPRECATED()))
|
||||
result.orElse(isCovariantWith(env, stringTable, superTable, scope)
|
||||
.withSubPath(TypePath::PathBuilder().mt().readProp("__index").build()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1938,14 +1882,7 @@ SubtypingResult Subtyping::isCovariantWith(
|
|||
SubtypingResult res{true};
|
||||
|
||||
if (superProp.isShared() && subProp.isShared())
|
||||
{
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
res.andAlso(isInvariantWith(env, *subProp.readTy, *superProp.readTy, scope).withBothComponent(TypePath::Property::read(name)));
|
||||
else
|
||||
res.andAlso(
|
||||
isInvariantWith(env, subProp.type_DEPRECATED(), superProp.type_DEPRECATED(), scope).withBothComponent(TypePath::Property::read(name))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (superProp.readTy.has_value() && subProp.readTy.has_value())
|
||||
|
@ -2252,4 +2189,25 @@ std::pair<TypeId, ErrorVec> Subtyping::handleTypeFunctionReductionResult(const T
|
|||
return {builtinTypes->neverType, errors};
|
||||
}
|
||||
|
||||
SubtypingResult Subtyping::trySemanticSubtyping(SubtypingEnvironment& env,
|
||||
TypeId subTy,
|
||||
TypeId superTy,
|
||||
NotNull<Scope> scope,
|
||||
SubtypingResult& original)
|
||||
{
|
||||
SubtypingResult semantic = isCovariantWith(env, normalizer->normalize(subTy), normalizer->normalize(superTy), scope);
|
||||
|
||||
if (semantic.normalizationTooComplex)
|
||||
{
|
||||
return semantic;
|
||||
}
|
||||
else if (semantic.isSubtype)
|
||||
{
|
||||
semantic.reasoning.clear();
|
||||
return semantic;
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include <unordered_set>
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -189,8 +188,6 @@ void StateDot::visitChildren(TypeId ty, int index)
|
|||
return visitChild(*t.boundTo, index, "boundTo");
|
||||
|
||||
for (const auto& [name, prop] : t.props)
|
||||
{
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
if (prop.isShared())
|
||||
visitChild(*prop.readTy, index, name.c_str());
|
||||
|
@ -209,9 +206,6 @@ void StateDot::visitChildren(TypeId ty, int index)
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
visitChild(prop.type_DEPRECATED(), index, name.c_str());
|
||||
}
|
||||
if (t.indexer)
|
||||
{
|
||||
visitChild(t.indexer->indexType, index, "[index]");
|
||||
|
@ -329,8 +323,6 @@ void StateDot::visitChildren(TypeId ty, int index)
|
|||
finishNode();
|
||||
|
||||
for (const auto& [name, prop] : t.props)
|
||||
{
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
if (prop.isShared())
|
||||
visitChild(*prop.readTy, index, name.c_str());
|
||||
|
@ -349,9 +341,6 @@ void StateDot::visitChildren(TypeId ty, int index)
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
visitChild(prop.type_DEPRECATED(), index, name.c_str());
|
||||
}
|
||||
|
||||
if (t.parent)
|
||||
visitChild(*t.parent, index, "[parent]");
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
LUAU_FASTFLAGVARIABLE(LuauEnableDenseTableAlias)
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSolverAgnosticStringification)
|
||||
|
||||
/*
|
||||
|
@ -42,7 +41,6 @@ LUAU_FASTFLAGVARIABLE(LuauSolverAgnosticStringification)
|
|||
*/
|
||||
LUAU_FASTINTVARIABLE(DebugLuauVerboseTypeNames, 0)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauToStringNoLexicalSort)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFixEmptyTypePackStringification)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -420,10 +418,7 @@ struct TypeStringifier
|
|||
if (prop.isShared())
|
||||
{
|
||||
emitKey(name);
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
stringify(*prop.readTy);
|
||||
else
|
||||
stringify(prop.type_DEPRECATED());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -493,7 +488,6 @@ struct TypeStringifier
|
|||
|
||||
bool wrap = !singleTp && get<TypePack>(follow(tp));
|
||||
|
||||
if (FFlag::LuauFixEmptyTypePackStringification)
|
||||
wrap &= !isEmpty(tp);
|
||||
|
||||
if (wrap)
|
||||
|
@ -742,7 +736,7 @@ struct TypeStringifier
|
|||
|
||||
state.emit("(");
|
||||
|
||||
if (FFlag::LuauFixEmptyTypePackStringification && isEmpty(ftv.argTypes))
|
||||
if (isEmpty(ftv.argTypes))
|
||||
{
|
||||
// if we've got an empty argument pack, we're done.
|
||||
}
|
||||
|
@ -753,7 +747,7 @@ struct TypeStringifier
|
|||
|
||||
state.emit(") -> ");
|
||||
|
||||
bool plural = FFlag::LuauFixEmptyTypePackStringification ? !isEmpty(ftv.retTypes) : true;
|
||||
bool plural = !isEmpty(ftv.retTypes);
|
||||
|
||||
auto retBegin = begin(ftv.retTypes);
|
||||
auto retEnd = end(ftv.retTypes);
|
||||
|
@ -1270,15 +1264,12 @@ struct TypePackStringifier
|
|||
return;
|
||||
}
|
||||
|
||||
if (FFlag::LuauFixEmptyTypePackStringification)
|
||||
{
|
||||
if (tp.head.empty() && (!tp.tail || isEmpty(*tp.tail)))
|
||||
{
|
||||
state.emit("()");
|
||||
state.unsee(&tp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
|
||||
|
@ -1827,8 +1818,6 @@ std::string toStringNamedFunction(const std::string& funcName, const FunctionTyp
|
|||
|
||||
state.emit("): ");
|
||||
|
||||
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);
|
||||
|
@ -1840,21 +1829,7 @@ std::string toStringNamedFunction(const std::string& funcName, const FunctionTyp
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ LUAU_FASTINTVARIABLE(LuauTableTypeMaximumStringifierLength, 0)
|
|||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauSubtypingCheckFunctionGenericCounts)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAG(LuauUseWorkspacePropToChooseSolver)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSolverAgnosticVisitType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSolverAgnosticSetType)
|
||||
|
@ -714,9 +713,6 @@ Property Property::create(std::optional<TypeId> read, std::optional<TypeId> writ
|
|||
|
||||
TypeId Property::type_DEPRECATED() const
|
||||
{
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps && !FFlag::LuauUseWorkspacePropToChooseSolver)
|
||||
LUAU_ASSERT(!FFlag::LuauSolverV2);
|
||||
|
||||
LUAU_ASSERT(readTy);
|
||||
return *readTy;
|
||||
}
|
||||
|
@ -841,7 +837,7 @@ bool areEqual(SeenSet& seen, const TableType& lhs, const TableType& rhs)
|
|||
if (l->first != r->first)
|
||||
return false;
|
||||
|
||||
if (FFlag::LuauSolverV2 && (FFlag::LuauSubtypingCheckFunctionGenericCounts || FFlag::LuauRemoveTypeCallsForReadWriteProps))
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
if (l->second.readTy && r->second.readTy)
|
||||
{
|
||||
|
@ -1090,7 +1086,7 @@ void persist(TypeId ty)
|
|||
|
||||
for (const auto& [_name, prop] : ttv->props)
|
||||
{
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
if (prop.readTy)
|
||||
queue.push_back(*prop.readTy);
|
||||
|
@ -1112,7 +1108,7 @@ void persist(TypeId ty)
|
|||
{
|
||||
for (const auto& [_name, prop] : etv->props)
|
||||
{
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
if (prop.readTy)
|
||||
queue.push_back(*prop.readTy);
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "Luau/TypeAttach.h"
|
||||
|
||||
#include "Luau/Ast.h"
|
||||
#include "Luau/Error.h"
|
||||
#include "Luau/Module.h"
|
||||
#include "Luau/RecursionCounter.h"
|
||||
#include "Luau/Scope.h"
|
||||
|
@ -14,8 +13,6 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
|
||||
static char* allocateString(Luau::Allocator& allocator, std::string_view contents)
|
||||
{
|
||||
char* result = (char*)allocator.allocate(contents.size() + 1);
|
||||
|
@ -197,8 +194,6 @@ public:
|
|||
|
||||
char* name = allocateString(*allocator, propName);
|
||||
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
if (prop.isShared())
|
||||
{
|
||||
props.data[idx].name = AstName(name);
|
||||
|
@ -228,14 +223,6 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
props.data[idx].name = AstName(name);
|
||||
props.data[idx].type = Luau::visit(*this, prop.type_DEPRECATED()->ty);
|
||||
props.data[idx].location = Location();
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
AstTableIndexer* indexer = nullptr;
|
||||
if (ttv.indexer)
|
||||
|
@ -272,8 +259,6 @@ public:
|
|||
{
|
||||
char* name = allocateString(*allocator, propName);
|
||||
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
if (prop.isShared())
|
||||
{
|
||||
props.data[idx].name = AstName(name);
|
||||
|
@ -303,14 +288,6 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
props.data[idx].name = AstName{name};
|
||||
props.data[idx].type = Luau::visit(*this, prop.type_DEPRECATED()->ty);
|
||||
props.data[idx].location = Location();
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
AstTableIndexer* indexer = nullptr;
|
||||
if (etv.indexer)
|
||||
|
|
|
@ -30,16 +30,13 @@
|
|||
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
|
||||
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictFixGenericTypePacks)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||
LUAU_FASTFLAG(LuauSubtypingCheckFunctionGenericCounts)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeCheckFunctionCalls)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSuppressErrorsForMultipleNonviableOverloads)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
LUAU_FASTFLAG(LuauInferActualIfElseExprType)
|
||||
LUAU_FASTFLAG(LuauInferActualIfElseExprType2)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictSuppressSoloConstraintSolvingIncomplete)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauIceLess)
|
||||
|
||||
|
@ -722,8 +719,6 @@ void TypeChecker2::visit(AstStatReturn* ret)
|
|||
{
|
||||
Scope* scope = findInnermostScope(ret->location);
|
||||
TypePackId expectedRetType = scope->returnType;
|
||||
if (FFlag::LuauTableLiteralSubtypeSpecificCheck2)
|
||||
{
|
||||
if (ret->list.size == 0)
|
||||
{
|
||||
testIsSubtype(builtinTypes->emptyTypePack, expectedRetType, ret->location);
|
||||
|
@ -738,6 +733,9 @@ void TypeChecker2::visit(AstStatReturn* ret)
|
|||
{
|
||||
if (idx < head.size())
|
||||
{
|
||||
if (FFlag::LuauInferActualIfElseExprType2)
|
||||
isSubtype &= testLiteralOrAstTypeIsSubtype(ret->list.data[idx], head[idx]);
|
||||
else
|
||||
isSubtype &= testPotentialLiteralIsSubtype(ret->list.data[idx], head[idx]);
|
||||
actualHead.push_back(head[idx]);
|
||||
}
|
||||
|
@ -769,6 +767,9 @@ void TypeChecker2::visit(AstStatReturn* ret)
|
|||
else
|
||||
{
|
||||
auto lastType = head[ret->list.size - 1];
|
||||
if (FFlag::LuauInferActualIfElseExprType2)
|
||||
isSubtype &= testLiteralOrAstTypeIsSubtype(lastExpr, lastType);
|
||||
else
|
||||
isSubtype &= testPotentialLiteralIsSubtype(lastExpr, lastType);
|
||||
actualHead.push_back(lastType);
|
||||
}
|
||||
|
@ -782,13 +783,6 @@ void TypeChecker2::visit(AstStatReturn* ret)
|
|||
auto reconstructedRetType = module->internalTypes.addTypePack(TypePack{std::move(actualHead), std::move(actualTail)});
|
||||
testIsSubtype(reconstructedRetType, expectedRetType, ret->location);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TypeArena* arena = &module->internalTypes;
|
||||
TypePackId actualRetType = reconstructPack(ret->list, *arena);
|
||||
testIsSubtype(actualRetType, expectedRetType, ret->location);
|
||||
}
|
||||
|
||||
for (AstExpr* expr : ret->list)
|
||||
visit(expr, ValueContext::RValue);
|
||||
|
@ -819,12 +813,7 @@ void TypeChecker2::visit(AstStatLocal* local)
|
|||
TypeId annotationType = lookupAnnotation(var->annotation);
|
||||
TypeId valueType = value ? lookupType(value) : nullptr;
|
||||
if (valueType)
|
||||
{
|
||||
if (FFlag::LuauTableLiteralSubtypeSpecificCheck2)
|
||||
testPotentialLiteralIsSubtype(value, annotationType);
|
||||
else
|
||||
testIsSubtype(valueType, annotationType, value->location);
|
||||
}
|
||||
|
||||
visit(var->annotation);
|
||||
}
|
||||
|
@ -1233,8 +1222,6 @@ void TypeChecker2::visit(AstStatAssign* assign)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (FFlag::LuauTableLiteralSubtypeSpecificCheck2)
|
||||
{
|
||||
// FIXME CLI-142462: Due to the fact that we do not type state
|
||||
// tables properly, table types "time travel." We can take
|
||||
// advantage of this for the specific code pattern of:
|
||||
|
@ -1245,23 +1232,11 @@ void TypeChecker2::visit(AstStatAssign* assign)
|
|||
//
|
||||
if (testLiteralOrAstTypeIsSubtype(rhs, lhsType))
|
||||
{
|
||||
// If rhsType </: lhsType, then it's not useful to also report that rhsType </: bindingType
|
||||
if (std::optional<TypeId> bindingType = getBindingType(lhs))
|
||||
testLiteralOrAstTypeIsSubtype(rhs, *bindingType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bool ok = testIsSubtype(rhsType, lhsType, rhs->location);
|
||||
|
||||
// If rhsType </: lhsType, then it's not useful to also report that rhsType </: bindingType
|
||||
if (ok)
|
||||
{
|
||||
std::optional<TypeId> bindingType = getBindingType(lhs);
|
||||
if (bindingType)
|
||||
testIsSubtype(rhsType, *bindingType, rhs->location);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TypeChecker2::visit(AstStatCompoundAssign* stat)
|
||||
|
@ -2067,7 +2042,7 @@ void TypeChecker2::visit(AstExprFunction* fn)
|
|||
// If the function type has a function annotation, we need to see if we can suggest an annotation
|
||||
if (normalizedFnTy)
|
||||
{
|
||||
if (FFlag::LuauStuckTypeFunctionsStillDispatch)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
suggestAnnotations(fn, normalizedFnTy->functions.parts.front());
|
||||
else
|
||||
{
|
||||
|
@ -2905,8 +2880,6 @@ void TypeChecker2::visit(AstTypePackGeneric* tp)
|
|||
Scope* scope = findInnermostScope(tp->location);
|
||||
LUAU_ASSERT(scope);
|
||||
|
||||
if (FFlag::LuauNewNonStrictFixGenericTypePacks)
|
||||
{
|
||||
if (std::optional<TypePackId> alias = scope->lookupPack(tp->genericName.value))
|
||||
return;
|
||||
|
||||
|
@ -2921,28 +2894,6 @@ void TypeChecker2::visit(AstTypePackGeneric* tp)
|
|||
|
||||
reportError(UnknownSymbol{tp->genericName.value, UnknownSymbol::Context::Type}, tp->location);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::optional<TypePackId> alias = scope->lookupPack(tp->genericName.value);
|
||||
if (!alias.has_value())
|
||||
{
|
||||
if (scope->lookupType(tp->genericName.value))
|
||||
{
|
||||
reportError(
|
||||
SwappedGenericTypeParameter{
|
||||
tp->genericName.value,
|
||||
SwappedGenericTypeParameter::Kind::Pack,
|
||||
},
|
||||
tp->location
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
reportError(UnknownSymbol{tp->genericName.value, UnknownSymbol::Context::Type}, tp->location);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TID>
|
||||
Reasonings TypeChecker2::explainReasonings_(TID subTy, TID superTy, Location location, const SubtypingResult& r)
|
||||
|
@ -3110,7 +3061,7 @@ bool TypeChecker2::testPotentialLiteralIsSubtype(AstExpr* expr, TypeId expectedT
|
|||
auto exprType = follow(lookupType(expr));
|
||||
expectedType = follow(expectedType);
|
||||
|
||||
if (FFlag::LuauInferActualIfElseExprType)
|
||||
if (FFlag::LuauInferActualIfElseExprType2)
|
||||
{
|
||||
if (auto group = expr->as<AstExprGroup>())
|
||||
{
|
||||
|
@ -3161,8 +3112,6 @@ bool TypeChecker2::testPotentialLiteralIsSubtype(AstExpr* expr, TypeId expectedT
|
|||
|
||||
Set<std::optional<std::string>> missingKeys{{}};
|
||||
for (const auto& [name, prop] : expectedTableType->props)
|
||||
{
|
||||
if (FFlag::LuauEnableWriteOnlyProperties)
|
||||
{
|
||||
if (prop.readTy)
|
||||
{
|
||||
|
@ -3170,15 +3119,6 @@ bool TypeChecker2::testPotentialLiteralIsSubtype(AstExpr* expr, TypeId expectedT
|
|||
missingKeys.insert(name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(!prop.isWriteOnly());
|
||||
|
||||
auto readTy = *prop.readTy;
|
||||
if (!isOptional(readTy))
|
||||
missingKeys.insert(name);
|
||||
}
|
||||
}
|
||||
|
||||
bool isArrayLike = false;
|
||||
if (expectedTableType->indexer)
|
||||
|
@ -3212,8 +3152,6 @@ bool TypeChecker2::testPotentialLiteralIsSubtype(AstExpr* expr, TypeId expectedT
|
|||
// If there's not an indexer, then by width subtyping we can just do nothing :)
|
||||
}
|
||||
else
|
||||
{
|
||||
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.
|
||||
|
@ -3224,15 +3162,6 @@ bool TypeChecker2::testPotentialLiteralIsSubtype(AstExpr* expr, TypeId expectedT
|
|||
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)
|
||||
{
|
||||
|
|
|
@ -33,14 +33,10 @@ LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFamilyUseGuesserDepth, -1);
|
|||
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogTypeFamilies)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNotAllBinaryTypeFunsHaveDefaults)
|
||||
LUAU_FASTFLAG(LuauUpdateGetMetatableTypeSignature)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAGVARIABLE(LuauOccursCheckForRefinement)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStuckTypeFunctionsStillDispatch)
|
||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauEmptyStringInKeyOf)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAvoidExcessiveTypeCopying)
|
||||
|
@ -315,7 +311,7 @@ struct TypeFunctionReducer
|
|||
|
||||
if (auto tfit = get<TypeFunctionInstanceType>(t))
|
||||
{
|
||||
if (FFlag::LuauStuckTypeFunctionsStillDispatch)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (tfit->state == TypeFunctionInstanceState::Stuck)
|
||||
return SkipTestResult::Stuck;
|
||||
|
@ -438,7 +434,7 @@ struct TypeFunctionReducer
|
|||
if (FFlag::DebugLuauLogTypeFamilies)
|
||||
printf("%s is uninhabited\n", toString(subject, {true}).c_str());
|
||||
|
||||
if (FFlag::LuauStuckTypeFunctionsStillDispatch)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (getState(subject) == TypeFunctionInstanceState::Unsolved)
|
||||
{
|
||||
|
@ -500,7 +496,7 @@ struct TypeFunctionReducer
|
|||
if (skip == SkipTestResult::Stuck)
|
||||
{
|
||||
// SkipTestResult::Stuck cannot happen when this flag is unset.
|
||||
LUAU_ASSERT(FFlag::LuauStuckTypeFunctionsStillDispatch);
|
||||
LUAU_ASSERT(FFlag::LuauEagerGeneralization4);
|
||||
if (FFlag::DebugLuauLogTypeFamilies)
|
||||
printf("%s is stuck!\n", toString(subject, {true}).c_str());
|
||||
|
||||
|
@ -779,7 +775,7 @@ FunctionGraphReductionResult reduceTypeFunctions(TypePackId entrypoint, Location
|
|||
|
||||
bool isPending(TypeId ty, ConstraintSolver* solver)
|
||||
{
|
||||
if (FFlag::LuauStuckTypeFunctionsStillDispatch)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (auto tfit = get<TypeFunctionInstanceType>(ty); tfit && tfit->state == TypeFunctionInstanceState::Unsolved)
|
||||
return true;
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <vector>
|
||||
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeFunctionSerdeIterationLimit)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTypeFunOptional)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -455,8 +454,6 @@ static int getSingletonValue(lua_State* L)
|
|||
// Otherwise, makes a union of the two things.
|
||||
static int createOptional(lua_State* L)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauTypeFunOptional);
|
||||
|
||||
int argumentCount = lua_gettop(L);
|
||||
if (argumentCount != 1)
|
||||
luaL_error(L, "types.optional: expected 1 argument, but got %d", argumentCount);
|
||||
|
@ -1663,12 +1660,12 @@ void registerTypesLibrary(lua_State* L)
|
|||
{"negationof", createNegation},
|
||||
{"unionof", createUnion},
|
||||
{"intersectionof", createIntersection},
|
||||
{"optional", createOptional},
|
||||
{"newtable", createTable},
|
||||
{"newfunction", createFunction},
|
||||
{"copy", deepCopy},
|
||||
{"generic", createGeneric},
|
||||
|
||||
{(FFlag::LuauTypeFunOptional) ? "optional" : nullptr, (FFlag::LuauTypeFunOptional) ? createOptional : nullptr},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
// currently, controls serialization, deserialization, and `type.copy`
|
||||
LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFunctionSerdeIterationLimit, 100'000);
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauTypeFunctionSerializeFollowMetatable)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -390,7 +388,7 @@ private:
|
|||
void serializeChildren(const MetatableType* m1, TypeFunctionTableType* m2)
|
||||
{
|
||||
// Serialize main part of the metatable immediately
|
||||
if (auto tableTy = get<TableType>(FFlag::LuauTypeFunctionSerializeFollowMetatable ? follow(m1->table) : m1->table))
|
||||
if (auto tableTy = get<TableType>(follow(m1->table)))
|
||||
serializeChildren(tableTy, m2);
|
||||
|
||||
m2->metatable = shallowSerialize(m1->metatable);
|
||||
|
|
|
@ -34,8 +34,6 @@ LUAU_FASTFLAGVARIABLE(DebugLuauFreezeDuringUnification)
|
|||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauUseWorkspacePropToChooseSolver)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauReduceCheckBinaryExprStackPressure)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -1912,7 +1910,7 @@ WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExp
|
|||
else if (auto a = expr.as<AstExprUnary>())
|
||||
result = checkExpr(scope, *a);
|
||||
else if (auto a = expr.as<AstExprBinary>())
|
||||
result = FFlag::LuauReduceCheckBinaryExprStackPressure ? checkExpr(scope, *a, expectedType) : checkExpr_DEPRECATED(scope, *a, expectedType);
|
||||
result = checkExpr(scope, *a, expectedType);
|
||||
else if (auto a = expr.as<AstExprTypeAssertion>())
|
||||
result = checkExpr(scope, *a);
|
||||
else if (auto a = expr.as<AstExprError>())
|
||||
|
@ -3212,63 +3210,6 @@ WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExp
|
|||
}
|
||||
}
|
||||
|
||||
WithPredicate<TypeId> TypeChecker::checkExpr_DEPRECATED(const ScopePtr& scope, const AstExprBinary& expr, std::optional<TypeId> expectedType)
|
||||
{
|
||||
if (expr.op == AstExprBinary::And)
|
||||
{
|
||||
auto [lhsTy, lhsPredicates] = checkExpr(scope, *expr.left, expectedType);
|
||||
|
||||
ScopePtr innerScope = childScope(scope, expr.location);
|
||||
resolve(lhsPredicates, innerScope, true);
|
||||
|
||||
auto [rhsTy, rhsPredicates] = checkExpr(innerScope, *expr.right, expectedType);
|
||||
|
||||
return {checkBinaryOperation(scope, expr, lhsTy, rhsTy), {AndPredicate{std::move(lhsPredicates), std::move(rhsPredicates)}}};
|
||||
}
|
||||
else if (expr.op == AstExprBinary::Or)
|
||||
{
|
||||
auto [lhsTy, lhsPredicates] = checkExpr(scope, *expr.left, expectedType);
|
||||
|
||||
ScopePtr innerScope = childScope(scope, expr.location);
|
||||
resolve(lhsPredicates, innerScope, false);
|
||||
|
||||
auto [rhsTy, rhsPredicates] = checkExpr(innerScope, *expr.right, expectedType);
|
||||
|
||||
// Because of C++, I'm not sure if lhsPredicates was not moved out by the time we call checkBinaryOperation.
|
||||
TypeId result = checkBinaryOperation(scope, expr, lhsTy, rhsTy, lhsPredicates);
|
||||
return {result, {OrPredicate{std::move(lhsPredicates), std::move(rhsPredicates)}}};
|
||||
}
|
||||
else if (expr.op == AstExprBinary::CompareEq || expr.op == AstExprBinary::CompareNe)
|
||||
{
|
||||
// For these, passing expectedType is worse than simply forcing them, because their implementation
|
||||
// may inadvertently check if expectedTypes exist first and use it, instead of forceSingleton first.
|
||||
WithPredicate<TypeId> lhs = checkExpr(scope, *expr.left, std::nullopt, /*forceSingleton=*/true);
|
||||
WithPredicate<TypeId> rhs = checkExpr(scope, *expr.right, std::nullopt, /*forceSingleton=*/true);
|
||||
if (auto predicate = tryGetTypeGuardPredicate(expr))
|
||||
return {booleanType, {std::move(*predicate)}};
|
||||
|
||||
PredicateVec predicates;
|
||||
if (auto lvalue = tryGetLValue(*expr.left))
|
||||
predicates.push_back(EqPredicate{std::move(*lvalue), rhs.type, expr.location});
|
||||
if (auto lvalue = tryGetLValue(*expr.right))
|
||||
predicates.push_back(EqPredicate{std::move(*lvalue), lhs.type, expr.location});
|
||||
|
||||
if (!predicates.empty() && expr.op == AstExprBinary::CompareNe)
|
||||
predicates = {NotPredicate{std::move(predicates)}};
|
||||
|
||||
return {checkBinaryOperation(scope, expr, lhs.type, rhs.type), std::move(predicates)};
|
||||
}
|
||||
else
|
||||
{
|
||||
// Expected types are not useful for other binary operators.
|
||||
WithPredicate<TypeId> lhs = checkExpr(scope, *expr.left);
|
||||
WithPredicate<TypeId> rhs = checkExpr(scope, *expr.right);
|
||||
|
||||
// Intentionally discarding predicates with other operators.
|
||||
return WithPredicate{checkBinaryOperation(scope, expr, lhs.type, rhs.type, lhs.predicates)};
|
||||
}
|
||||
}
|
||||
|
||||
WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExprTypeAssertion& expr)
|
||||
{
|
||||
TypeId annotationType = resolveType(scope, *expr.annotation);
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAGVARIABLE(LuauErrorSuppressionTypeFunctionArgs)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -77,7 +75,7 @@ std::optional<Property> findTableProperty(NotNull<BuiltinTypes> builtinTypes, Er
|
|||
const auto& fit = itt->props.find(name);
|
||||
if (fit != itt->props.end())
|
||||
{
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
if (fit->second.readTy)
|
||||
return fit->second.readTy;
|
||||
|
@ -136,7 +134,7 @@ std::optional<TypeId> findMetatableEntry(
|
|||
auto it = mtt->props.find(entry);
|
||||
if (it != mtt->props.end())
|
||||
{
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
if (it->second.readTy)
|
||||
return it->second.readTy;
|
||||
|
@ -209,7 +207,7 @@ std::optional<TypeId> findTablePropertyRespectingMeta(
|
|||
const auto& fit = itt->props.find(name);
|
||||
if (fit != itt->props.end())
|
||||
{
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
switch (context)
|
||||
{
|
||||
|
@ -468,8 +466,6 @@ TypeId stripNil(NotNull<BuiltinTypes> builtinTypes, TypeArena& arena, TypeId ty)
|
|||
}
|
||||
|
||||
ErrorSuppression shouldSuppressErrors(NotNull<Normalizer> normalizer, TypeId ty)
|
||||
{
|
||||
if (FFlag::LuauErrorSuppressionTypeFunctionArgs)
|
||||
{
|
||||
if (auto tfit = get<TypeFunctionInstanceType>(follow(ty)))
|
||||
{
|
||||
|
@ -486,7 +482,6 @@ ErrorSuppression shouldSuppressErrors(NotNull<Normalizer> normalizer, TypeId ty)
|
|||
|
||||
return ErrorSuppression::DoNotSuppress;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<const NormalizedType> normType = normalizer->normalize(ty);
|
||||
|
||||
|
|
|
@ -18,10 +18,7 @@
|
|||
#include <optional>
|
||||
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||
|
||||
namespace Luau
|
||||
|
@ -52,8 +49,6 @@ static bool areCompatible(TypeId left, TypeId right)
|
|||
// the right table is free (and therefore potentially has an indexer or
|
||||
// a compatible property)
|
||||
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps || FFlag::LuauRefineTablesWithReadType)
|
||||
{
|
||||
if (rightTable->state == TableState::Free || rightTable->indexer.has_value())
|
||||
return true;
|
||||
|
||||
|
@ -65,19 +60,6 @@ static bool areCompatible(TypeId left, TypeId right)
|
|||
|
||||
// FIXME: Could this create an issue for write only / divergent properties?
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(leftProp.isReadOnly() || leftProp.isShared());
|
||||
|
||||
const TypeId leftType = follow(leftProp.isReadOnly() ? *leftProp.readTy : leftProp.type_DEPRECATED());
|
||||
|
||||
if (isOptional(leftType) || get<FreeType>(leftType) || rightTable->state == TableState::Free || rightTable->indexer.has_value())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
for (const auto& [name, leftProp] : leftTable->props)
|
||||
|
@ -106,7 +88,7 @@ static bool areCompatible(TypeId left, TypeId right)
|
|||
// returns `true` if `ty` is irressolvable and should be added to `incompleteSubtypes`.
|
||||
static bool isIrresolvable(TypeId ty)
|
||||
{
|
||||
if (FFlag::LuauStuckTypeFunctionsStillDispatch)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (auto tfit = get<TypeFunctionInstanceType>(ty); tfit && tfit->state != TypeFunctionInstanceState::Unsolved)
|
||||
return false;
|
||||
|
@ -446,29 +428,12 @@ bool Unifier2::unify(TableType* subTable, const TableType* superTable)
|
|||
{
|
||||
const Property& superProp = superPropOpt->second;
|
||||
|
||||
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
|
||||
{
|
||||
if (subProp.isReadOnly() && superProp.isReadOnly())
|
||||
result &= unify(*subProp.readTy, *superPropOpt->second.readTy);
|
||||
else if (subProp.isReadOnly())
|
||||
result &= unify(*subProp.readTy, superProp.type_DEPRECATED());
|
||||
else if (superProp.isReadOnly())
|
||||
result &= unify(subProp.type_DEPRECATED(), *superProp.readTy);
|
||||
else
|
||||
{
|
||||
result &= unify(subProp.type_DEPRECATED(), superProp.type_DEPRECATED());
|
||||
result &= unify(superProp.type_DEPRECATED(), subProp.type_DEPRECATED());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto subTypeParamsIter = subTable->instantiatedTypeParams.begin();
|
||||
|
|
|
@ -192,6 +192,14 @@ public:
|
|||
return offset;
|
||||
}
|
||||
|
||||
enum class BraceType
|
||||
{
|
||||
InterpolatedString,
|
||||
Normal
|
||||
};
|
||||
|
||||
std::optional<Lexer::BraceType> peekBraceStackTop();
|
||||
|
||||
private:
|
||||
char peekch() const;
|
||||
char peekch(unsigned int lookahead) const;
|
||||
|
@ -243,12 +251,6 @@ private:
|
|||
bool skipComments;
|
||||
bool readNames;
|
||||
|
||||
enum class BraceType
|
||||
{
|
||||
InterpolatedString,
|
||||
Normal
|
||||
};
|
||||
|
||||
std::vector<BraceType> braceStack;
|
||||
};
|
||||
|
||||
|
|
|
@ -130,7 +130,6 @@ private:
|
|||
// function funcname funcbody
|
||||
LUAU_FORCEINLINE AstStat* parseFunctionStat(const AstArray<AstAttr*>& attributes = {nullptr, 0});
|
||||
|
||||
std::pair<bool, AstAttr::Type> validateAttribute_DEPRECATED(const char* attributeName, const TempVector<AstAttr*>& attributes);
|
||||
std::optional<AstAttr::Type> validateAttribute(const char* attributeName, const TempVector<AstAttr*>& attributes);
|
||||
|
||||
// attribute ::= '@' NAME
|
||||
|
|
|
@ -1009,6 +1009,14 @@ Lexeme Lexer::readNext()
|
|||
}
|
||||
}
|
||||
|
||||
std::optional<Lexer::BraceType> Lexer::peekBraceStackTop()
|
||||
{
|
||||
if (braceStack.empty())
|
||||
return std::nullopt;
|
||||
else
|
||||
return {braceStack.back()};
|
||||
}
|
||||
|
||||
LUAU_NOINLINE Lexeme Lexer::readUtf8Error()
|
||||
{
|
||||
Position start = position();
|
||||
|
|
|
@ -18,9 +18,8 @@ LUAU_FASTINTVARIABLE(LuauParseErrorLimit, 100)
|
|||
// flag so that we don't break production games by reverting syntax changes.
|
||||
// See docs/SyntaxChanges.md for an explanation.
|
||||
LUAU_FASTFLAGVARIABLE(LuauSolverV2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauParseStringIndexer)
|
||||
LUAU_FASTFLAGVARIABLE(LuauParseAttributeFixUninit)
|
||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(DebugLuauReportReturnTypeVariadicWithTypeSuffix, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauParseIncompleteInterpStringsWithLocation)
|
||||
|
||||
// Clip with DebugLuauReportReturnTypeVariadicWithTypeSuffix
|
||||
bool luau_telemetry_parsed_return_type_variadic_with_type_suffix = false;
|
||||
|
@ -769,53 +768,8 @@ AstStat* Parser::parseFunctionStat(const AstArray<AstAttr*>& attributes)
|
|||
return node;
|
||||
}
|
||||
|
||||
|
||||
std::pair<bool, AstAttr::Type> Parser::validateAttribute_DEPRECATED(const char* attributeName, const TempVector<AstAttr*>& attributes)
|
||||
{
|
||||
LUAU_ASSERT(!FFlag::LuauParseAttributeFixUninit);
|
||||
|
||||
AstAttr::Type type;
|
||||
|
||||
// check if the attribute name is valid
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (int i = 0; kAttributeEntries[i].name; ++i)
|
||||
{
|
||||
found = !strcmp(attributeName, kAttributeEntries[i].name);
|
||||
if (found)
|
||||
{
|
||||
type = kAttributeEntries[i].type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
if (strlen(attributeName) == 1)
|
||||
report(lexer.current().location, "Attribute name is missing");
|
||||
else
|
||||
report(lexer.current().location, "Invalid attribute '%s'", attributeName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check that attribute is not duplicated
|
||||
for (const AstAttr* attr : attributes)
|
||||
{
|
||||
if (attr->type == type)
|
||||
{
|
||||
report(lexer.current().location, "Cannot duplicate attribute '%s'", attributeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {found, type};
|
||||
}
|
||||
|
||||
std::optional<AstAttr::Type> Parser::validateAttribute(const char* attributeName, const TempVector<AstAttr*>& attributes)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauParseAttributeFixUninit);
|
||||
|
||||
// check if the attribute name is valid
|
||||
std::optional<AstAttr::Type> type;
|
||||
|
||||
|
@ -855,8 +809,6 @@ void Parser::parseAttribute(TempVector<AstAttr*>& attributes)
|
|||
|
||||
Location loc = lexer.current().location;
|
||||
|
||||
if (FFlag::LuauParseAttributeFixUninit)
|
||||
{
|
||||
const char* name = lexer.current().name;
|
||||
std::optional<AstAttr::Type> type = validateAttribute(name, attributes);
|
||||
|
||||
|
@ -865,17 +817,6 @@ void Parser::parseAttribute(TempVector<AstAttr*>& attributes)
|
|||
if (type)
|
||||
attributes.push_back(allocator.alloc<AstAttr>(loc, *type));
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* name = lexer.current().name;
|
||||
const auto [found, type] = validateAttribute_DEPRECATED(name, attributes);
|
||||
|
||||
nextLexeme();
|
||||
|
||||
if (found)
|
||||
attributes.push_back(allocator.alloc<AstAttr>(loc, type));
|
||||
}
|
||||
}
|
||||
|
||||
// attributes ::= {attribute}
|
||||
AstArray<AstAttr*> Parser::parseAttributes()
|
||||
|
@ -1308,8 +1249,6 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
|
|||
);
|
||||
}
|
||||
|
||||
if (FFlag::LuauParseStringIndexer)
|
||||
{
|
||||
// There are two possibilities: Either it's a property or a function.
|
||||
if (lexer.current().type == Lexeme::ReservedFunction)
|
||||
{
|
||||
|
@ -1374,74 +1313,6 @@ AstStat* Parser::parseDeclaration(const Location& start, const AstArray<AstAttr*
|
|||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// There are two possibilities: Either it's a property or a function.
|
||||
if (lexer.current().type == Lexeme::ReservedFunction)
|
||||
{
|
||||
props.push_back(parseDeclaredExternTypeMethod(attributes));
|
||||
}
|
||||
else if (lexer.current().type == '[' &&
|
||||
(lexer.lookahead().type == Lexeme::RawString || lexer.lookahead().type == Lexeme::QuotedString))
|
||||
{
|
||||
const Lexeme begin = lexer.current();
|
||||
nextLexeme(); // [
|
||||
|
||||
const Location nameBegin = lexer.current().location;
|
||||
std::optional<AstArray<char>> chars = parseCharArray();
|
||||
|
||||
const Location nameEnd = lexer.previousLocation();
|
||||
|
||||
expectMatchAndConsume(']', begin);
|
||||
expectAndConsume(':', "property type annotation");
|
||||
AstType* type = parseType();
|
||||
|
||||
// since AstName contains a char*, it can't contain null
|
||||
bool containsNull = chars && (memchr(chars->data, 0, chars->size) != nullptr);
|
||||
|
||||
if (chars && !containsNull)
|
||||
{
|
||||
props.push_back(AstDeclaredExternTypeProperty{
|
||||
AstName(chars->data), Location(nameBegin, nameEnd), type, false, Location(begin.location, lexer.previousLocation())
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
report(begin.location, "String literal contains malformed escape sequence or \\0");
|
||||
}
|
||||
}
|
||||
else if (lexer.current().type == '[')
|
||||
{
|
||||
if (indexer)
|
||||
{
|
||||
// maybe we don't need to parse the entire badIndexer...
|
||||
// however, we either have { or [ to lint, not the entire table type or the bad indexer.
|
||||
AstTableIndexer* badIndexer = parseTableIndexer(AstTableAccess::ReadWrite, std::nullopt, lexer.current()).node;
|
||||
|
||||
// we lose all additional indexer expressions from the AST after error recovery here
|
||||
report(badIndexer->location, "Cannot have more than one indexer on an extern type");
|
||||
}
|
||||
else
|
||||
{
|
||||
indexer = parseTableIndexer(AstTableAccess::ReadWrite, std::nullopt, lexer.current()).node;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Location propStart = lexer.current().location;
|
||||
std::optional<Name> propName = parseNameOpt("property name");
|
||||
|
||||
if (!propName)
|
||||
break;
|
||||
|
||||
expectAndConsume(':', "property type annotation");
|
||||
AstType* propType = parseType();
|
||||
props.push_back(AstDeclaredExternTypeProperty{
|
||||
propName->name, propName->location, propType, false, Location(propStart, lexer.previousLocation())
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Location classEnd = lexer.current().location;
|
||||
nextLexeme(); // skip past `end`
|
||||
|
@ -1982,12 +1853,6 @@ std::pair<CstExprConstantString::QuoteStyle, unsigned int> Parser::extractString
|
|||
// TableIndexer ::= `[' Type `]' `:' Type
|
||||
Parser::TableIndexerResult Parser::parseTableIndexer(AstTableAccess access, std::optional<Location> accessLocation, Lexeme begin)
|
||||
{
|
||||
if (!FFlag::LuauParseStringIndexer)
|
||||
{
|
||||
begin = lexer.current();
|
||||
nextLexeme(); // [
|
||||
}
|
||||
|
||||
AstType* index = parseType();
|
||||
|
||||
Position indexerClosePosition = lexer.current().location.begin;
|
||||
|
@ -2046,8 +1911,6 @@ AstType* Parser::parseTableType(bool inDeclarationContext)
|
|||
}
|
||||
}
|
||||
|
||||
if (FFlag::LuauParseStringIndexer)
|
||||
{
|
||||
if (lexer.current().type == '[')
|
||||
{
|
||||
const Lexeme begin = lexer.current();
|
||||
|
@ -2153,113 +2016,6 @@ AstType* Parser::parseTableType(bool inDeclarationContext)
|
|||
lexer.current().location.begin
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lexer.current().type == '[' && (lexer.lookahead().type == Lexeme::RawString || lexer.lookahead().type == Lexeme::QuotedString))
|
||||
{
|
||||
const Lexeme begin = lexer.current();
|
||||
nextLexeme(); // [
|
||||
|
||||
CstExprConstantString::QuoteStyle style;
|
||||
unsigned int blockDepth = 0;
|
||||
if (options.storeCstData)
|
||||
std::tie(style, blockDepth) = extractStringDetails();
|
||||
|
||||
Position stringPosition = lexer.current().location.begin;
|
||||
AstArray<char> sourceString;
|
||||
std::optional<AstArray<char>> chars = parseCharArray(options.storeCstData ? &sourceString : nullptr);
|
||||
|
||||
Position indexerClosePosition = lexer.current().location.begin;
|
||||
expectMatchAndConsume(']', begin);
|
||||
Position colonPosition = lexer.current().location.begin;
|
||||
expectAndConsume(':', "table field");
|
||||
|
||||
AstType* type = parseType();
|
||||
|
||||
// since AstName contains a char*, it can't contain null
|
||||
bool containsNull = chars && (memchr(chars->data, 0, chars->size) != nullptr);
|
||||
|
||||
if (chars && !containsNull)
|
||||
{
|
||||
props.push_back(AstTableProp{AstName(chars->data), begin.location, type, access, accessLocation});
|
||||
if (options.storeCstData)
|
||||
cstItems.push_back(CstTypeTable::Item{
|
||||
CstTypeTable::Item::Kind::StringProperty,
|
||||
begin.location.begin,
|
||||
indexerClosePosition,
|
||||
colonPosition,
|
||||
tableSeparator(),
|
||||
lexer.current().location.begin,
|
||||
allocator.alloc<CstExprConstantString>(sourceString, style, blockDepth),
|
||||
stringPosition
|
||||
});
|
||||
}
|
||||
else
|
||||
report(begin.location, "String literal contains malformed escape sequence or \\0");
|
||||
}
|
||||
else if (lexer.current().type == '[')
|
||||
{
|
||||
if (indexer)
|
||||
{
|
||||
// maybe we don't need to parse the entire badIndexer...
|
||||
// however, we either have { or [ to lint, not the entire table type or the bad indexer.
|
||||
AstTableIndexer* badIndexer = parseTableIndexer(access, accessLocation, lexer.current()).node;
|
||||
|
||||
// we lose all additional indexer expressions from the AST after error recovery here
|
||||
report(badIndexer->location, "Cannot have more than one table indexer");
|
||||
}
|
||||
else
|
||||
{
|
||||
// the last param in the parseTableIndexer is ignored
|
||||
auto tableIndexerResult = parseTableIndexer(access, accessLocation, lexer.current());
|
||||
indexer = tableIndexerResult.node;
|
||||
if (options.storeCstData)
|
||||
cstItems.push_back(CstTypeTable::Item{
|
||||
CstTypeTable::Item::Kind::Indexer,
|
||||
tableIndexerResult.indexerOpenPosition,
|
||||
tableIndexerResult.indexerClosePosition,
|
||||
tableIndexerResult.colonPosition,
|
||||
tableSeparator(),
|
||||
lexer.current().location.begin,
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (props.empty() && !indexer && !(lexer.current().type == Lexeme::Name && lexer.lookahead().type == ':'))
|
||||
{
|
||||
AstType* type = parseType();
|
||||
|
||||
// array-like table type: {T} desugars into {[number]: T}
|
||||
isArray = true;
|
||||
AstType* index = allocator.alloc<AstTypeReference>(type->location, std::nullopt, nameNumber, std::nullopt, type->location);
|
||||
indexer = allocator.alloc<AstTableIndexer>(AstTableIndexer{index, type, type->location, access, accessLocation});
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::optional<Name> name = parseNameOpt("table field");
|
||||
|
||||
if (!name)
|
||||
break;
|
||||
|
||||
Position colonPosition = lexer.current().location.begin;
|
||||
expectAndConsume(':', "table field");
|
||||
|
||||
AstType* type = parseType(inDeclarationContext);
|
||||
|
||||
props.push_back(AstTableProp{name->name, name->location, type, access, accessLocation});
|
||||
if (options.storeCstData)
|
||||
cstItems.push_back(CstTypeTable::Item{
|
||||
CstTypeTable::Item::Kind::Property,
|
||||
Position{0, 0},
|
||||
Position{0, 0},
|
||||
colonPosition,
|
||||
tableSeparator(),
|
||||
lexer.current().location.begin
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (lexer.current().type == ',' || lexer.current().type == ';')
|
||||
{
|
||||
|
@ -3988,7 +3744,34 @@ AstExpr* Parser::parseInterpString()
|
|||
return reportExprError(endLocation, {}, "Double braces are not permitted within interpolated strings; did you mean '\\{'?");
|
||||
case Lexeme::BrokenString:
|
||||
nextLexeme();
|
||||
if (!FFlag::LuauParseIncompleteInterpStringsWithLocation)
|
||||
return reportExprError(endLocation, {}, "Malformed interpolated string; did you forget to add a '}'?");
|
||||
LUAU_FALLTHROUGH;
|
||||
case Lexeme::Eof:
|
||||
{
|
||||
if (FFlag::LuauParseIncompleteInterpStringsWithLocation)
|
||||
{
|
||||
AstArray<AstArray<char>> stringsArray = copy(strings);
|
||||
AstArray<AstExpr*> exprs = copy(expressions);
|
||||
AstExprInterpString* node =
|
||||
allocator.alloc<AstExprInterpString>(Location{startLocation, lexer.previousLocation()}, stringsArray, exprs);
|
||||
if (options.storeCstData)
|
||||
cstNodeMap[node] = allocator.alloc<CstExprInterpString>(copy(sourceStrings), copy(stringPositions));
|
||||
if (auto top = lexer.peekBraceStackTop())
|
||||
{
|
||||
// We are in a broken interpolated string, the top of the stack is non empty, we are missing '}'
|
||||
if (*top == Lexer::BraceType::InterpolatedString)
|
||||
report(lexer.previousLocation(), "Malformed interpolated string; did you forget to add a '}'?");
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are in a broken interpolated string, the top of the stack is empty, we are missing '`'.
|
||||
report(lexer.previousLocation(), "Malformed interpolated string; did you forget to add a '`'?");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
LUAU_FALLTHROUGH;
|
||||
}
|
||||
default:
|
||||
return reportExprError(endLocation, {}, "Malformed interpolated string, got %s", lexer.current().toString().c_str());
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuauCodeGenFixRexw, false)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
|
@ -37,7 +39,10 @@ static_assert(sizeof(cmovTextForCondition) / sizeof(cmovTextForCondition[0]) ==
|
|||
#define OP_PLUS_CC(op, cc) ((op) + uint8_t(cc))
|
||||
|
||||
#define REX_W_BIT(value) (value ? 0x8 : 0x0)
|
||||
#define REX_W(reg) REX_W_BIT((reg).size == SizeX64::qword || ((reg).size == SizeX64::byte && (reg).index >= 4))
|
||||
// TODO: remove with DFFlagLuauCodeGenFixRexw
|
||||
#define REX_W_DEPRECATED(reg) REX_W_BIT((reg).size == SizeX64::qword || ((reg).size == SizeX64::byte && (reg).index >= 4))
|
||||
#define REX_W(reg) REX_W_BIT((reg).size == SizeX64::qword)
|
||||
#define REX_FORCE(reg) (((reg).size == SizeX64::byte && (reg).index >= 4) ? 0x40 : 0x00)
|
||||
#define REX_R(reg) (((reg).index & 0x8) >> 1)
|
||||
#define REX_X(reg) (((reg).index & 0x8) >> 2)
|
||||
#define REX_B(reg) (((reg).index & 0x8) >> 3)
|
||||
|
@ -1390,18 +1395,30 @@ void AssemblyBuilderX64::
|
|||
|
||||
void AssemblyBuilderX64::placeRex(RegisterX64 op)
|
||||
{
|
||||
uint8_t code = REX_W(op) | REX_B(op);
|
||||
if (DFFlag::LuauCodeGenFixRexw)
|
||||
{
|
||||
uint8_t code = REX_W(op) | REX_B(op) | REX_FORCE(op);
|
||||
|
||||
if (code != 0)
|
||||
place(code | 0x40);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t code = REX_W_DEPRECATED(op) | REX_B(op);
|
||||
|
||||
if (code != 0)
|
||||
place(code | 0x40);
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBuilderX64::placeRex(OperandX64 op)
|
||||
{
|
||||
if (DFFlag::LuauCodeGenFixRexw)
|
||||
{
|
||||
uint8_t code = 0;
|
||||
|
||||
if (op.cat == CategoryX64::reg)
|
||||
code = REX_W(op.base) | REX_B(op.base);
|
||||
code = REX_W(op.base) | REX_B(op.base) | REX_FORCE(op.base);
|
||||
else if (op.cat == CategoryX64::mem)
|
||||
code = REX_W_BIT(op.memSize == SizeX64::qword) | REX_X(op.index) | REX_B(op.base);
|
||||
else
|
||||
|
@ -1410,6 +1427,21 @@ void AssemblyBuilderX64::placeRex(OperandX64 op)
|
|||
if (code != 0)
|
||||
place(code | 0x40);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t code = 0;
|
||||
|
||||
if (op.cat == CategoryX64::reg)
|
||||
code = REX_W_DEPRECATED(op.base) | REX_B(op.base);
|
||||
else if (op.cat == CategoryX64::mem)
|
||||
code = REX_W_BIT(op.memSize == SizeX64::qword) | REX_X(op.index) | REX_B(op.base);
|
||||
else
|
||||
CODEGEN_ASSERT(!"No encoding for left operand of this category");
|
||||
|
||||
if (code != 0)
|
||||
place(code | 0x40);
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBuilderX64::placeRexNoW(OperandX64 op)
|
||||
{
|
||||
|
@ -1428,7 +1460,21 @@ void AssemblyBuilderX64::placeRexNoW(OperandX64 op)
|
|||
|
||||
void AssemblyBuilderX64::placeRex(RegisterX64 lhs, OperandX64 rhs)
|
||||
{
|
||||
uint8_t code = REX_W(lhs);
|
||||
if (DFFlag::LuauCodeGenFixRexw)
|
||||
{
|
||||
uint8_t code = REX_W(lhs) | REX_FORCE(lhs);
|
||||
|
||||
if (rhs.cat == CategoryX64::imm)
|
||||
code |= REX_B(lhs);
|
||||
else
|
||||
code |= REX_R(lhs) | REX_X(rhs.index) | REX_B(rhs.base) | REX_FORCE(lhs) | REX_FORCE(rhs.base);
|
||||
|
||||
if (code != 0)
|
||||
place(code | 0x40);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t code = REX_W_DEPRECATED(lhs);
|
||||
|
||||
if (rhs.cat == CategoryX64::imm)
|
||||
code |= REX_B(lhs);
|
||||
|
@ -1438,6 +1484,7 @@ void AssemblyBuilderX64::placeRex(RegisterX64 lhs, OperandX64 rhs)
|
|||
if (code != 0)
|
||||
place(code | 0x40);
|
||||
}
|
||||
}
|
||||
|
||||
void AssemblyBuilderX64::placeVex(OperandX64 dst, OperandX64 src1, OperandX64 src2, bool setW, uint8_t mode, uint8_t prefix)
|
||||
{
|
||||
|
|
|
@ -28,6 +28,7 @@ LUAU_FASTINTVARIABLE(LuauCompileInlineDepth, 5)
|
|||
|
||||
LUAU_FASTFLAGVARIABLE(LuauSeparateCompilerTypeInfo)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileCli162537)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -1928,6 +1929,10 @@ struct Compiler
|
|||
CompileError::raise(ckey->location, "Exceeded constant limit; simplify the code to compile");
|
||||
|
||||
LUAU_ASSERT(shape.length < BytecodeBuilder::TableShape::kMaxLength);
|
||||
|
||||
if (FFlag::LuauCompileCli162537)
|
||||
shape.keys[shape.length++] = cid;
|
||||
else
|
||||
shape.keys[shape.length++] = int16_t(cid);
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,15 @@ static ResolvedRequire resolveRequire(luarequire_Configuration* lrc, lua_State*
|
|||
static int checkRegisteredModules(lua_State* L, const char* path)
|
||||
{
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, registeredCacheTableKey, 1);
|
||||
lua_getfield(L, -1, path);
|
||||
|
||||
std::string pathLower = std::string(path);
|
||||
for (char& c : pathLower)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
c -= ('A' - 'a');
|
||||
}
|
||||
|
||||
lua_getfield(L, -1, pathLower.c_str());
|
||||
if (lua_isnil(L, -1))
|
||||
{
|
||||
lua_pop(L, 2);
|
||||
|
@ -243,6 +251,16 @@ int registerModuleImpl(lua_State* L)
|
|||
if (pathView.empty() || pathView[0] != '@')
|
||||
luaL_argerrorL(L, 1, "path must begin with '@'");
|
||||
|
||||
// Make path lowercase to ensure case-insensitive matching.
|
||||
std::string pathLower = std::string(path, len);
|
||||
for (char& c : pathLower)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
c -= ('A' - 'a');
|
||||
}
|
||||
lua_pushstring(L, pathLower.c_str());
|
||||
lua_replace(L, 1);
|
||||
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, registeredCacheTableKey, 1);
|
||||
// (1) path, (2) result, (3) cache table
|
||||
|
||||
|
|
|
@ -220,6 +220,7 @@ target_sources(Luau.Analysis PRIVATE
|
|||
Analysis/include/Luau/Simplify.h
|
||||
Analysis/include/Luau/Substitution.h
|
||||
Analysis/include/Luau/Subtyping.h
|
||||
Analysis/include/Luau/SubtypingVariance.h
|
||||
Analysis/include/Luau/Symbol.h
|
||||
Analysis/include/Luau/TableLiteralInference.h
|
||||
Analysis/include/Luau/ToDot.h
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
LUAU_DYNAMIC_FASTFLAG(LuauCodeGenFixRexw)
|
||||
|
||||
using namespace Luau::CodeGen;
|
||||
using namespace Luau::CodeGen::X64;
|
||||
|
||||
|
@ -60,6 +62,8 @@ TEST_SUITE_BEGIN("x64Assembly");
|
|||
|
||||
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "BaseBinaryInstructionForms")
|
||||
{
|
||||
ScopedFastFlag luauCodeGenFixRexw{DFFlag::LuauCodeGenFixRexw, true};
|
||||
|
||||
// reg, reg
|
||||
SINGLE_COMPARE(add(rax, rcx), 0x48, 0x03, 0xc1);
|
||||
SINGLE_COMPARE(add(rsp, r12), 0x49, 0x03, 0xe4);
|
||||
|
@ -71,8 +75,8 @@ TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "BaseBinaryInstructionForms")
|
|||
SINGLE_COMPARE(add(rax, 0x80), 0x48, 0x81, 0xc0, 0x80, 0x00, 0x00, 0x00);
|
||||
SINGLE_COMPARE(add(r10, 0x7fffffff), 0x49, 0x81, 0xc2, 0xff, 0xff, 0xff, 0x7f);
|
||||
SINGLE_COMPARE(add(al, 3), 0x80, 0xc0, 0x03);
|
||||
SINGLE_COMPARE(add(sil, 3), 0x48, 0x80, 0xc6, 0x03);
|
||||
SINGLE_COMPARE(add(r11b, 3), 0x49, 0x80, 0xc3, 0x03);
|
||||
SINGLE_COMPARE(add(sil, 3), 0x40, 0x80, 0xc6, 0x03);
|
||||
SINGLE_COMPARE(add(r11b, 3), 0x41, 0x80, 0xc3, 0x03);
|
||||
|
||||
// reg, [reg]
|
||||
SINGLE_COMPARE(add(rax, qword[rax]), 0x48, 0x03, 0x00);
|
||||
|
@ -193,12 +197,14 @@ TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "BaseUnaryInstructionForms")
|
|||
|
||||
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfMov")
|
||||
{
|
||||
ScopedFastFlag luauCodeGenFixRexw{DFFlag::LuauCodeGenFixRexw, true};
|
||||
|
||||
SINGLE_COMPARE(mov(rcx, 1), 0x48, 0xb9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
SINGLE_COMPARE(mov64(rcx, 0x1234567812345678ll), 0x48, 0xb9, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
|
||||
SINGLE_COMPARE(mov(ecx, 2), 0xb9, 0x02, 0x00, 0x00, 0x00);
|
||||
SINGLE_COMPARE(mov(cl, 2), 0xb1, 0x02);
|
||||
SINGLE_COMPARE(mov(sil, 2), 0x48, 0xb6, 0x02);
|
||||
SINGLE_COMPARE(mov(r9b, 2), 0x49, 0xb1, 0x02);
|
||||
SINGLE_COMPARE(mov(sil, 2), 0x40, 0xb6, 0x02);
|
||||
SINGLE_COMPARE(mov(r9b, 2), 0x41, 0xb1, 0x02);
|
||||
SINGLE_COMPARE(mov(rcx, qword[rdi]), 0x48, 0x8b, 0x0f);
|
||||
SINGLE_COMPARE(mov(dword[rax], 0xabcd), 0xc7, 0x00, 0xcd, 0xab, 0x00, 0x00);
|
||||
SINGLE_COMPARE(mov(r13, 1), 0x49, 0xbd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
|
@ -209,8 +215,8 @@ TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfMov")
|
|||
SINGLE_COMPARE(mov(qword[rdx], r9), 0x4c, 0x89, 0x0a);
|
||||
SINGLE_COMPARE(mov(byte[rsi], 0x3), 0xc6, 0x06, 0x03);
|
||||
SINGLE_COMPARE(mov(byte[rsi], al), 0x88, 0x06);
|
||||
SINGLE_COMPARE(mov(byte[rsi], dil), 0x48, 0x88, 0x3e);
|
||||
SINGLE_COMPARE(mov(byte[rsi], r10b), 0x4c, 0x88, 0x16);
|
||||
SINGLE_COMPARE(mov(byte[rsi], dil), 0x40, 0x88, 0x3e);
|
||||
SINGLE_COMPARE(mov(byte[rsi], r10b), 0x44, 0x88, 0x16);
|
||||
SINGLE_COMPARE(mov(wordReg(ebx), 0x3a3d), 0x66, 0xbb, 0x3d, 0x3a);
|
||||
SINGLE_COMPARE(mov(word[rsi], 0x3a3d), 0x66, 0xc7, 0x06, 0x3d, 0x3a);
|
||||
SINGLE_COMPARE(mov(word[rsi], wordReg(eax)), 0x66, 0x89, 0x06);
|
||||
|
@ -232,20 +238,28 @@ TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfMovExtended")
|
|||
|
||||
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfTest")
|
||||
{
|
||||
ScopedFastFlag luauCodeGenFixRexw{DFFlag::LuauCodeGenFixRexw, true};
|
||||
|
||||
SINGLE_COMPARE(test(al, 8), 0xf6, 0xc0, 0x08);
|
||||
SINGLE_COMPARE(test(eax, 8), 0xf7, 0xc0, 0x08, 0x00, 0x00, 0x00);
|
||||
SINGLE_COMPARE(test(rax, 8), 0x48, 0xf7, 0xc0, 0x08, 0x00, 0x00, 0x00);
|
||||
SINGLE_COMPARE(test(rcx, 0xabab), 0x48, 0xf7, 0xc1, 0xab, 0xab, 0x00, 0x00);
|
||||
SINGLE_COMPARE(test(rcx, rax), 0x48, 0x85, 0xc8);
|
||||
SINGLE_COMPARE(test(rax, qword[rcx]), 0x48, 0x85, 0x01);
|
||||
SINGLE_COMPARE(test(al, cl), 0x84, 0xc1);
|
||||
SINGLE_COMPARE(test(al, sil), 0x40, 0x84, 0xc6);
|
||||
SINGLE_COMPARE(test(cl, r12b), 0x41, 0x84, 0xcc);
|
||||
SINGLE_COMPARE(test(sil, dil), 0x40, 0x84, 0xf7);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfShift")
|
||||
{
|
||||
ScopedFastFlag luauCodeGenFixRexw{DFFlag::LuauCodeGenFixRexw, true};
|
||||
|
||||
SINGLE_COMPARE(shl(al, 1), 0xd0, 0xe0);
|
||||
SINGLE_COMPARE(shl(al, cl), 0xd2, 0xe0);
|
||||
SINGLE_COMPARE(shl(sil, cl), 0x48, 0xd2, 0xe6);
|
||||
SINGLE_COMPARE(shl(r10b, cl), 0x49, 0xd2, 0xe2);
|
||||
SINGLE_COMPARE(shl(sil, cl), 0x40, 0xd2, 0xe6);
|
||||
SINGLE_COMPARE(shl(r10b, cl), 0x41, 0xd2, 0xe2);
|
||||
SINGLE_COMPARE(shr(al, 4), 0xc0, 0xe8, 0x04);
|
||||
SINGLE_COMPARE(shr(eax, 1), 0xd1, 0xe8);
|
||||
SINGLE_COMPARE(sal(eax, cl), 0xd3, 0xe0);
|
||||
|
@ -267,8 +281,10 @@ TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfLea")
|
|||
|
||||
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "FormsOfSetcc")
|
||||
{
|
||||
ScopedFastFlag luauCodeGenFixRexw{DFFlag::LuauCodeGenFixRexw, true};
|
||||
|
||||
SINGLE_COMPARE(setcc(ConditionX64::NotEqual, bl), 0x0f, 0x95, 0xc3);
|
||||
SINGLE_COMPARE(setcc(ConditionX64::NotEqual, dil), 0x48, 0x0f, 0x95, 0xc7);
|
||||
SINGLE_COMPARE(setcc(ConditionX64::NotEqual, dil), 0x40, 0x0f, 0x95, 0xc7);
|
||||
SINGLE_COMPARE(setcc(ConditionX64::BelowEqual, byte[rcx]), 0x0f, 0x96, 0x01);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ LUAU_FASTFLAG(LuauTraceTypesInNonstrictMode2)
|
|||
LUAU_FASTFLAG(LuauSetMetatableDoesNotTimeTravel)
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauExpectedTypeVisitor)
|
||||
LUAU_FASTFLAG(LuauImplicitTableIndexerKeys3)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
|
||||
|
@ -4560,8 +4559,6 @@ end
|
|||
|
||||
TEST_CASE_FIXTURE(ACFixture, "autocomplete_for_assignment")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauExpectedTypeVisitor, true};
|
||||
|
||||
check(R"(
|
||||
local function foobar(tbl: { tag: "left" | "right" })
|
||||
tbl.tag = "@1"
|
||||
|
@ -4575,8 +4572,6 @@ TEST_CASE_FIXTURE(ACFixture, "autocomplete_for_assignment")
|
|||
|
||||
TEST_CASE_FIXTURE(ACFixture, "autocomplete_in_local_table")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauExpectedTypeVisitor, true};
|
||||
|
||||
check(R"(
|
||||
type Entry = { field: number, prop: string }
|
||||
local x : {Entry} = {}
|
||||
|
@ -4603,8 +4598,6 @@ TEST_CASE_FIXTURE(ACFixture, "autocomplete_in_local_table")
|
|||
|
||||
TEST_CASE_FIXTURE(ACFixture, "autocomplete_in_type_assertion")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauExpectedTypeVisitor, true};
|
||||
|
||||
check(R"(
|
||||
type Entry = { field: number, prop: string }
|
||||
return ( { f@1, p@2 } :: Entry )
|
||||
|
@ -4621,7 +4614,6 @@ TEST_CASE_FIXTURE(ACFixture, "autocomplete_implicit_named_index_index_expr")
|
|||
ScopedFastFlag sffs[] = {
|
||||
// Somewhat surprisingly, the old solver didn't cover this case.
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauExpectedTypeVisitor, true},
|
||||
{FFlag::LuauImplicitTableIndexerKeys3, true},
|
||||
};
|
||||
|
||||
|
@ -4648,7 +4640,6 @@ TEST_CASE_FIXTURE(ACFixture, "autocomplete_implicit_named_index_index_expr_witho
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauExpectedTypeVisitor, true},
|
||||
{FFlag::LuauImplicitTableIndexerKeys3, true},
|
||||
};
|
||||
|
||||
|
@ -4679,10 +4670,7 @@ TEST_CASE_FIXTURE(ACFixture, "autocomplete_implicit_named_index_index_expr_witho
|
|||
|
||||
TEST_CASE_FIXTURE(ACFixture, "bidirectional_autocomplete_in_function_call")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauExpectedTypeVisitor, true},
|
||||
};
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
|
||||
check(R"(
|
||||
local function take(_: { choice: "left" | "right" }) end
|
||||
|
|
|
@ -37,10 +37,9 @@ void luau_callhook(lua_State* L, lua_Hook hook, void* userdata);
|
|||
LUAU_FASTFLAG(LuauHeapDumpStringSizeOverhead)
|
||||
LUAU_FASTFLAG(DebugLuauAbortingChecks)
|
||||
LUAU_FASTINT(CodegenHeuristicsInstructionLimit)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_DYNAMIC_FASTFLAG(LuauErrorYield)
|
||||
LUAU_DYNAMIC_FASTFLAG(LuauSafeStackCheck)
|
||||
|
||||
LUAU_FASTFLAG(LuauCompileCli162537)
|
||||
|
||||
static lua_CompileOptions defaultOptions()
|
||||
{
|
||||
|
@ -1210,16 +1209,11 @@ static void populateRTTI(lua_State* L, Luau::TypeId type)
|
|||
lua_newtable(L);
|
||||
|
||||
for (const auto& [name, prop] : t->props)
|
||||
{
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
if (prop.readTy)
|
||||
populateRTTI(L, *prop.readTy);
|
||||
else if (prop.writeTy)
|
||||
populateRTTI(L, *prop.writeTy);
|
||||
}
|
||||
else
|
||||
populateRTTI(L, prop.type_DEPRECATED());
|
||||
|
||||
lua_setfield(L, -2, name.c_str());
|
||||
}
|
||||
|
@ -3333,6 +3327,60 @@ TEST_CASE("HugeFunctionLoadFailure")
|
|||
REQUIRE_EQ(largeAllocationToFail, expectedTotalLargeAllocations);
|
||||
}
|
||||
|
||||
TEST_CASE("HugeConstantTable")
|
||||
{
|
||||
ScopedFastFlag luauCompileCli162537{FFlag::LuauCompileCli162537, true};
|
||||
|
||||
std::string source = "function foo(...)\n";
|
||||
|
||||
source += " local args = ...\n";
|
||||
source += " local t = args and {\n";
|
||||
|
||||
for (int i = 0; i < 400; i++)
|
||||
{
|
||||
for (int k = 0; k < 100; k++)
|
||||
{
|
||||
source += "call(";
|
||||
source += std::to_string(i * 100 + k);
|
||||
source += ".125), ";
|
||||
}
|
||||
|
||||
source += "\n ";
|
||||
}
|
||||
|
||||
source += " }\n";
|
||||
source += " return { a = 1, b = 2, c = 3 }\n";
|
||||
source += "end\n";
|
||||
source += "return foo().a + foo().b\n";
|
||||
|
||||
StateRef globalState(luaL_newstate(), lua_close);
|
||||
lua_State* L = globalState.get();
|
||||
|
||||
if (codegen && luau_codegen_supported())
|
||||
luau_codegen_create(L);
|
||||
|
||||
luaL_openlibs(L);
|
||||
luaL_sandbox(L);
|
||||
luaL_sandboxthread(L);
|
||||
|
||||
size_t bytecodeSize = 0;
|
||||
char* bytecode = luau_compile(source.data(), source.size(), nullptr, &bytecodeSize);
|
||||
int result = luau_load(L, "=HugeConstantTable", bytecode, bytecodeSize, 0);
|
||||
free(bytecode);
|
||||
|
||||
REQUIRE(result == 0);
|
||||
|
||||
if (codegen && luau_codegen_supported())
|
||||
{
|
||||
Luau::CodeGen::CompilationOptions nativeOptions{Luau::CodeGen::CodeGen_ColdFunctions};
|
||||
Luau::CodeGen::compile(L, -1, nativeOptions);
|
||||
}
|
||||
|
||||
int status = lua_resume(L, nullptr, 0);
|
||||
REQUIRE(status == 0);
|
||||
|
||||
CHECK(lua_tonumber(L, -1) == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("IrInstructionLimit")
|
||||
{
|
||||
|
|
|
@ -285,6 +285,7 @@ AstStatBlock* Fixture::parse(const std::string& source, const ParseOptions& pars
|
|||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
Mode mode = sourceModule->mode ? *sourceModule->mode : Mode::Strict;
|
||||
Frontend::Stats stats;
|
||||
ModulePtr module = Luau::check(
|
||||
*sourceModule,
|
||||
mode,
|
||||
|
@ -299,6 +300,7 @@ AstStatBlock* Fixture::parse(const std::string& source, const ParseOptions& pars
|
|||
getFrontend().options,
|
||||
{},
|
||||
false,
|
||||
stats,
|
||||
{}
|
||||
);
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
LUAU_FASTFLAG(DebugLuauFreezeArena)
|
||||
LUAU_FASTFLAG(DebugLuauForceAllNewSolverTests)
|
||||
|
||||
LUAU_FASTFLAG(LuauTypeFunOptional)
|
||||
LUAU_FASTFLAG(LuauUpdateSetMetatableTypeSignature)
|
||||
LUAU_FASTFLAG(LuauUpdateGetMetatableTypeSignature)
|
||||
|
||||
|
@ -203,7 +202,6 @@ struct BuiltinsFixture : Fixture
|
|||
explicit BuiltinsFixture(bool prepareAutocomplete = false);
|
||||
|
||||
// For the purpose of our tests, we're always the latest version of type functions.
|
||||
ScopedFastFlag sff_optionalInTypeFunctionLib{FFlag::LuauTypeFunOptional, true};
|
||||
Frontend& getFrontend() override;
|
||||
};
|
||||
|
||||
|
|
|
@ -27,17 +27,13 @@ using namespace Luau;
|
|||
LUAU_FASTINT(LuauParseErrorLimit)
|
||||
|
||||
LUAU_FASTFLAG(LuauBetterReverseDependencyTracking)
|
||||
LUAU_FASTFLAG(LuauBetterScopeSelection)
|
||||
LUAU_FASTFLAG(LuauBlockDiffFragmentSelection)
|
||||
LUAU_FASTFLAG(LuauFragmentAcMemoryLeak)
|
||||
LUAU_FASTFLAG(LuauGlobalVariableModuleIsolation)
|
||||
LUAU_FASTFLAG(LuauFragmentAutocompleteIfRecommendations)
|
||||
LUAU_FASTFLAG(LuauPopulateRefinedTypesInFragmentFromOldSolver)
|
||||
LUAU_FASTFLAG(LuauSolverAgnosticStringification)
|
||||
LUAU_FASTFLAG(LuauFragmentRequiresCanBeResolvedToAModule)
|
||||
LUAU_FASTFLAG(LuauFragmentAutocompleteTracksRValueRefinements)
|
||||
LUAU_FASTFLAG(LuauPopulateSelfTypesInFragment)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauParseIncompleteInterpStringsWithLocation)
|
||||
LUAU_FASTFLAG(LuauForInProvidesRecommendations)
|
||||
|
||||
static std::optional<AutocompleteEntryMap> nullCallback(std::string tag, std::optional<const ExternType*> ptr, std::optional<std::string> contents)
|
||||
{
|
||||
|
@ -67,14 +63,9 @@ struct FragmentAutocompleteFixtureImpl : BaseType
|
|||
{
|
||||
static_assert(std::is_base_of_v<Fixture, BaseType>, "BaseType must be a descendant of Fixture");
|
||||
|
||||
ScopedFastFlag luauBetterScopeSelection{FFlag::LuauBetterScopeSelection, true};
|
||||
ScopedFastFlag luauBlockDiffFragmentSelection{FFlag::LuauBlockDiffFragmentSelection, true};
|
||||
ScopedFastFlag luauFragmentAcMemoryLeak{FFlag::LuauFragmentAcMemoryLeak, true};
|
||||
ScopedFastFlag luauGlobalVariableModuleIsolation{FFlag::LuauGlobalVariableModuleIsolation, true};
|
||||
ScopedFastFlag luauFragmentAutocompleteIfRecommendations{FFlag::LuauFragmentAutocompleteIfRecommendations, true};
|
||||
ScopedFastFlag luauPopulateRefinedTypesInFragmentFromOldSolver{FFlag::LuauPopulateRefinedTypesInFragmentFromOldSolver, true};
|
||||
ScopedFastFlag sffLuauFragmentAutocompleteTracksRValueRefinement{FFlag::LuauFragmentAutocompleteTracksRValueRefinements, true};
|
||||
ScopedFastFlag sffLuauPopulateSelfTypesInFragment{FFlag::LuauPopulateSelfTypesInFragment, true};
|
||||
ScopedFastFlag luauParseIncompleteInterpStringsWithLocation{FFlag::LuauParseIncompleteInterpStringsWithLocation, true};
|
||||
|
||||
FragmentAutocompleteFixtureImpl()
|
||||
: BaseType(true)
|
||||
|
@ -703,6 +694,7 @@ end
|
|||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "partial_for_numeric_in_condition")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauForInProvidesRecommendations, true};
|
||||
auto region = getAutocompleteRegion(
|
||||
R"(
|
||||
for c = 1,3
|
||||
|
@ -710,7 +702,7 @@ for c = 1,3
|
|||
Position{1, 11}
|
||||
);
|
||||
|
||||
CHECK_EQ(Location{{1, 0}, {1, 11}}, region.fragmentLocation);
|
||||
CHECK_EQ(Location{{1, 10}, {1, 11}}, region.fragmentLocation);
|
||||
REQUIRE(region.parentBlock);
|
||||
CHECK(region.nearestStatement->as<AstStatFor>());
|
||||
}
|
||||
|
@ -4110,6 +4102,198 @@ end
|
|||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "string_interpolation_format_provides_autocomplete_results")
|
||||
{
|
||||
const std::string source = R"(
|
||||
type Foo = {x : number, x1 : string, x2 : boolean}
|
||||
local e: Foo = {x = 1, x1 = "1", x2 = true}
|
||||
local s =
|
||||
)";
|
||||
|
||||
const std::string dest = R"(
|
||||
type Foo = {x : number, x1 : string, x2 : boolean}
|
||||
local e : Foo = {x = 1, x1 = "1", x2 = true}
|
||||
local s = `{e. }`
|
||||
)";
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
dest,
|
||||
Position{3, 14},
|
||||
[](auto& result)
|
||||
{
|
||||
CHECK(!result.result->acResults.entryMap.empty());
|
||||
CHECK(result.result->acResults.entryMap.count("x"));
|
||||
CHECK(result.result->acResults.entryMap.count("x1"));
|
||||
CHECK(result.result->acResults.entryMap.count("x2"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "string_interpolation_format_provides_results_inside_of_function_call")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauParseIncompleteInterpStringsWithLocation, true};
|
||||
const std::string source = R"(
|
||||
type T = {x : number, y : number, z : number}
|
||||
local e = {x = 1, y = 2, z = 3}
|
||||
print(`{e.x}`)
|
||||
)";
|
||||
const std::string dest = R"(
|
||||
type T = {x : number, y : number, z : number}
|
||||
local e = {x = 1, y = 2, z = 3}
|
||||
print(`{e.x} {e.}`)
|
||||
)";
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
dest,
|
||||
Position{3, 16},
|
||||
[](auto& result)
|
||||
{
|
||||
CHECK(!result.result->acResults.entryMap.empty());
|
||||
CHECK(result.result->acResults.entryMap.count("x"));
|
||||
CHECK(result.result->acResults.entryMap.count("y"));
|
||||
CHECK(result.result->acResults.entryMap.count("z"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "for_in_should_rec")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauForInProvidesRecommendations, true};
|
||||
const std::string source = R"(
|
||||
type T = { x : {[number] : number}, y: number}
|
||||
local x : T = ({} :: T)
|
||||
for _,n in pairs(x.) do
|
||||
end
|
||||
)";
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
source,
|
||||
Position{3, 19},
|
||||
[](auto& result)
|
||||
{
|
||||
CHECK(!result.result->acResults.entryMap.empty());
|
||||
CHECK(result.result->acResults.entryMap.count("x"));
|
||||
CHECK(result.result->acResults.entryMap.count("y"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "for_expr_in_should_rec_no_do")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauForInProvidesRecommendations, true};
|
||||
const std::string source = R"(
|
||||
type T = { x : {[number] : number}, y: number, z: number}
|
||||
local x : T = ({} :: T)
|
||||
for i =
|
||||
end
|
||||
)";
|
||||
const std::string dest = R"(
|
||||
type T = { x : {[number] : number}, y: number, z : number}
|
||||
local x : T = ({} :: T)
|
||||
for i = x.
|
||||
end
|
||||
)";
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
dest,
|
||||
Position{3, 10},
|
||||
[](auto& result)
|
||||
{
|
||||
CHECK(!result.result->acResults.entryMap.empty());
|
||||
CHECK(result.result->acResults.entryMap.count("x"));
|
||||
CHECK(result.result->acResults.entryMap.count("y"));
|
||||
CHECK(result.result->acResults.entryMap.count("z"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "for_expr_in_should_rec_with_do_in_step")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauForInProvidesRecommendations, true};
|
||||
const std::string source = R"(
|
||||
type T = { x : {[number] : number}, y: number, z: number}
|
||||
local x : T = ({} :: T)
|
||||
for i = x.y, 100 do
|
||||
end
|
||||
)";
|
||||
const std::string dest = R"(
|
||||
type T = { x : {[number] : number}, y: number, z : number}
|
||||
local x : T = ({} :: T)
|
||||
for i = x.y, 100, x. do
|
||||
end
|
||||
)";
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
dest,
|
||||
Position{3, 20},
|
||||
[](auto& result)
|
||||
{
|
||||
CHECK(!result.result->acResults.entryMap.empty());
|
||||
CHECK(result.result->acResults.entryMap.count("x"));
|
||||
CHECK(result.result->acResults.entryMap.count("y"));
|
||||
CHECK(result.result->acResults.entryMap.count("z"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "for_expr_in_should_rec_with_do_in_max_delete")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauForInProvidesRecommendations, true};
|
||||
const std::string source = R"(
|
||||
type T = { x : {[number] : number}, y: number, z: number}
|
||||
local x : T = ({} :: T)
|
||||
for i = x.y, x.z do
|
||||
end
|
||||
)";
|
||||
const std::string dest = R"(
|
||||
type T = { x : {[number] : number}, y: number, z : number}
|
||||
local x : T = ({} :: T)
|
||||
for i = x.y, x. do
|
||||
end
|
||||
)";
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
dest,
|
||||
Position{3, 15},
|
||||
[](auto& result)
|
||||
{
|
||||
CHECK(!result.result->acResults.entryMap.empty());
|
||||
CHECK(result.result->acResults.entryMap.count("x"));
|
||||
CHECK(result.result->acResults.entryMap.count("y"));
|
||||
CHECK(result.result->acResults.entryMap.count("z"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "for_expr_in_should_rec_with_do_in_max_add")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauForInProvidesRecommendations, true};
|
||||
const std::string source = R"(
|
||||
type T = { x : {[number] : number}, y: number, z: number}
|
||||
local x : T = ({} :: T)
|
||||
for i = x.y do
|
||||
end
|
||||
)";
|
||||
const std::string dest = R"(
|
||||
type T = { x : {[number] : number}, y: number, z : number}
|
||||
local x : T = ({} :: T)
|
||||
for i = x.y, x. do
|
||||
end
|
||||
)";
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
dest,
|
||||
Position{3, 15},
|
||||
[](auto& result)
|
||||
{
|
||||
CHECK(!result.result->acResults.entryMap.empty());
|
||||
CHECK(result.result->acResults.entryMap.count("x"));
|
||||
CHECK(result.result->acResults.entryMap.count("y"));
|
||||
CHECK(result.result->acResults.entryMap.count("z"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// NOLINTEND(bugprone-unchecked-optional-access)
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -16,7 +16,6 @@ using namespace Luau;
|
|||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(DebugLuauFreezeArena)
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -877,8 +876,6 @@ TEST_CASE_FIXTURE(FrontendFixture, "discard_type_graphs")
|
|||
|
||||
TEST_CASE_FIXTURE(FrontendFixture, "it_should_be_safe_to_stringify_errors_when_full_type_graph_is_discarded")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
Frontend fe{&fileResolver, &configResolver, {false}};
|
||||
|
||||
fileResolver.source["Module/A"] = R"(
|
||||
|
|
|
@ -16,8 +16,8 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
LUAU_FASTFLAG(DebugLuauForbidInternalTypes)
|
||||
LUAU_FASTFLAG(LuauAvoidGenericsLeakingDuringFunctionCallCheck)
|
||||
|
||||
TEST_SUITE_BEGIN("Generalization");
|
||||
|
||||
|
@ -227,7 +227,10 @@ TEST_CASE_FIXTURE(GeneralizationFixture, "('a) -> 'a")
|
|||
|
||||
TEST_CASE_FIXTURE(GeneralizationFixture, "(t1, (t1 <: 'b)) -> () where t1 = ('a <: (t1 <: 'b) & {number} & {number})")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization4, true};
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
TableType tt;
|
||||
tt.indexer = TableIndexer{builtinTypes.numberType, builtinTypes.numberType};
|
||||
|
@ -261,7 +264,10 @@ TEST_CASE_FIXTURE(GeneralizationFixture, "(('a <: number | string)) -> string?")
|
|||
|
||||
TEST_CASE_FIXTURE(GeneralizationFixture, "(('a <: {'b})) -> ()")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization4, true};
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
auto [aTy, aFree] = freshType();
|
||||
auto [bTy, bFree] = freshType();
|
||||
|
@ -376,10 +382,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "generalization_should_not_leak_free_type")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generics_dont_leak_into_callback")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauAvoidGenericsLeakingDuringFunctionCallCheck, true},
|
||||
};
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local func: <T>(T, (T) -> ()) -> () = nil :: any
|
||||
|
@ -398,10 +401,7 @@ TEST_CASE_FIXTURE(Fixture, "generics_dont_leak_into_callback")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generics_dont_leak_into_callback_2")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauAvoidGenericsLeakingDuringFunctionCallCheck, true},
|
||||
};
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
|
||||
// FIXME: CLI-156389: this is clearly wrong, but also predates this PR.
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
|
@ -415,7 +415,6 @@ TEST_CASE_FIXTURE(Fixture, "generics_dont_leak_into_callback_2")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_argument_with_singleton_oss_1808")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauAvoidGenericsLeakingDuringFunctionCallCheck, true};
|
||||
// All we care about here is that this has no errors, and we correctly
|
||||
// infer that the `false` literal should be typed as `false`.
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
|
@ -428,9 +427,9 @@ TEST_CASE_FIXTURE(Fixture, "generic_argument_with_singleton_oss_1808")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "avoid_cross_module_mutation_in_bidirectional_inference")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauAvoidGenericsLeakingDuringFunctionCallCheck, true},
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
fileResolver.source["Module/ListFns"] = R"(
|
||||
|
|
|
@ -10,12 +10,16 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4);
|
||||
LUAU_FASTFLAG(LuauInferPolarityOfReadWriteProperties)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
|
||||
TEST_SUITE_BEGIN("InferPolarity");
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "T where T = { m: <a>(a) -> T }")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization4, true};
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
TypeArena arena;
|
||||
ScopePtr globalScope = std::make_shared<Scope>(getBuiltins()->anyTypePack);
|
||||
|
@ -53,6 +57,7 @@ TEST_CASE_FIXTURE(Fixture, "<a, b>({ read x: a, write x: b }) -> ()")
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
{FFlag::LuauInferPolarityOfReadWriteProperties, true},
|
||||
};
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ using namespace Luau;
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(DebugLuauFreezeArena)
|
||||
LUAU_FASTINT(LuauTypeCloneIterationLimit)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
|
||||
TEST_SUITE_BEGIN("ModuleTests");
|
||||
|
||||
|
@ -138,8 +137,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
|
|||
|
||||
CHECK_EQ(std::optional<std::string>{"Cyclic"}, ttv->syntheticName);
|
||||
|
||||
|
||||
TypeId methodType = FFlag::LuauRemoveTypeCallsForReadWriteProps ? *ttv->props["get"].readTy : ttv->props["get"].type_DEPRECATED();
|
||||
TypeId methodType = *ttv->props["get"].readTy;
|
||||
REQUIRE(methodType != nullptr);
|
||||
|
||||
const FunctionType* ftv = get<FunctionType>(methodType);
|
||||
|
@ -172,7 +170,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table_2")
|
|||
TableType* ctt = getMutable<TableType>(cloneTy);
|
||||
REQUIRE(ctt);
|
||||
|
||||
TypeId clonedMethodType = FFlag::LuauRemoveTypeCallsForReadWriteProps ? *ctt->props["get"].readTy : ctt->props["get"].type_DEPRECATED();
|
||||
TypeId clonedMethodType = *ctt->props["get"].readTy;
|
||||
REQUIRE(clonedMethodType);
|
||||
|
||||
const FunctionType* cmf = get<FunctionType>(clonedMethodType);
|
||||
|
@ -201,8 +199,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_point_into_globalTypes_arena")
|
|||
TableType* exportsTable = getMutable<TableType>(*exports);
|
||||
REQUIRE(exportsTable != nullptr);
|
||||
|
||||
TypeId signType =
|
||||
FFlag::LuauRemoveTypeCallsForReadWriteProps ? *exportsTable->props["sign"].readTy : exportsTable->props["sign"].type_DEPRECATED();
|
||||
TypeId signType = *exportsTable->props["sign"].readTy;
|
||||
REQUIRE(signType != nullptr);
|
||||
|
||||
CHECK(!isInArena(signType, module->interfaceTypes));
|
||||
|
@ -356,18 +353,10 @@ TEST_CASE_FIXTURE(Fixture, "clone_iteration_limit")
|
|||
for (int i = 0; i < nesting; i++)
|
||||
{
|
||||
TableType* ttv = getMutable<TableType>(nested);
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
ttv->props["a"].readTy = src.addType(TableType{});
|
||||
ttv->props["a"].writeTy = ttv->props["a"].readTy;
|
||||
nested = *ttv->props["a"].readTy;
|
||||
}
|
||||
else
|
||||
{
|
||||
ttv->props["a"].setType(src.addType(TableType{}));
|
||||
nested = ttv->props["a"].type_DEPRECATED();
|
||||
}
|
||||
}
|
||||
|
||||
TypeArena dest;
|
||||
CloneState cloneState{getBuiltins()};
|
||||
|
@ -457,10 +446,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_clone_reexports")
|
|||
TypeId typeB = modBiter->second.type;
|
||||
TableType* tableB = getMutable<TableType>(typeB);
|
||||
REQUIRE(tableB);
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
CHECK(typeA == tableB->props["q"].readTy);
|
||||
else
|
||||
CHECK(typeA == tableB->props["q"].type_DEPRECATED());
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_clone_types_of_reexported_values")
|
||||
|
@ -494,14 +480,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_clone_types_of_reexported_values")
|
|||
TableType* tableB = getMutable<TableType>(*typeB);
|
||||
REQUIRE_MESSAGE(tableB, "Expected a table, but got " << toString(*typeB));
|
||||
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
CHECK(tableA->props["a"].readTy == tableB->props["b"].readTy);
|
||||
CHECK(tableA->props["a"].writeTy == tableB->props["b"].writeTy);
|
||||
}
|
||||
else
|
||||
CHECK(tableA->props["a"].type_DEPRECATED() == tableB->props["b"].type_DEPRECATED());
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "clone_table_bound_to_table_bound_to_table")
|
||||
{
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
#include "doctest.h"
|
||||
#include <iostream>
|
||||
|
||||
LUAU_FASTFLAG(LuauNewNonStrictFixGenericTypePacks)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictMoreUnknownSymbols)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictNoErrorsPassingNever)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictSuppressesDynamicRequireErrors)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictReportsOneIndexedErrors)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -125,6 +125,7 @@ declare os : {
|
|||
}
|
||||
|
||||
@checked declare function require(target : any) : any
|
||||
@checked declare function getAllTheArgsWrong(one: string, two: number, three: boolean) : any
|
||||
)BUILTIN_SRC";
|
||||
};
|
||||
|
||||
|
@ -629,8 +630,6 @@ optionalArgsAtTheEnd1("a", nil, 3)
|
|||
|
||||
TEST_CASE_FIXTURE(NonStrictTypeCheckerFixture, "generic_type_packs_in_non_strict")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauNewNonStrictFixGenericTypePacks, true};
|
||||
|
||||
CheckResult result = checkNonStrict(R"(
|
||||
--!nonstrict
|
||||
local test: <T...>(T...) -> () -- TypeError: Unknown type 'T'
|
||||
|
@ -862,4 +861,22 @@ require("@self/NonExistent")
|
|||
CHECK(req2 != nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(NonStrictTypeCheckerFixture, "new_non_strict_stringifies_checked_function_errors_as_one_indexed")
|
||||
{
|
||||
ScopedFastFlag sff = {FFlag::LuauNewNonStrictReportsOneIndexedErrors, true};
|
||||
CheckResult result = checkNonStrict(R"(
|
||||
getAllTheArgsWrong(3, true, "what")
|
||||
)");
|
||||
LUAU_REQUIRE_ERROR_COUNT(3, result);
|
||||
const CheckedFunctionCallError* err1 = get<CheckedFunctionCallError>(result.errors[0]);
|
||||
const CheckedFunctionCallError* err2 = get<CheckedFunctionCallError>(result.errors[1]);
|
||||
const CheckedFunctionCallError* err3 = get<CheckedFunctionCallError>(result.errors[2]);
|
||||
CHECK(err1 != nullptr);
|
||||
CHECK(err2 != nullptr);
|
||||
CHECK(err3 != nullptr);
|
||||
CHECK_EQ("Function 'getAllTheArgsWrong' expects 'string' at argument #1, but got 'number'", toString(result.errors[0]));
|
||||
CHECK_EQ("Function 'getAllTheArgsWrong' expects 'number' at argument #2, but got 'boolean'", toString(result.errors[1]));
|
||||
CHECK_EQ("Function 'getAllTheArgsWrong' expects 'boolean' at argument #3, but got 'string'", toString(result.errors[2]));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -17,8 +17,8 @@ LUAU_FASTINT(LuauRecursionLimit)
|
|||
LUAU_FASTINT(LuauTypeLengthLimit)
|
||||
LUAU_FASTINT(LuauParseErrorLimit)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauParseStringIndexer)
|
||||
LUAU_DYNAMIC_FASTFLAG(DebugLuauReportReturnTypeVariadicWithTypeSuffix)
|
||||
LUAU_FASTFLAG(LuauParseIncompleteInterpStringsWithLocation)
|
||||
|
||||
// Clip with DebugLuauReportReturnTypeVariadicWithTypeSuffix
|
||||
extern bool luau_telemetry_parsed_return_type_variadic_with_type_suffix;
|
||||
|
@ -951,6 +951,7 @@ TEST_CASE_FIXTURE(Fixture, "parse_interpolated_string_double_brace_mid")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_interpolated_string_without_end_brace")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauParseIncompleteInterpStringsWithLocation, true};
|
||||
auto columnOfEndBraceError = [this](const char* code)
|
||||
{
|
||||
try
|
||||
|
@ -969,9 +970,10 @@ TEST_CASE_FIXTURE(Fixture, "parse_interpolated_string_without_end_brace")
|
|||
}
|
||||
};
|
||||
|
||||
// This makes sure that the error is coming from the brace itself
|
||||
// This makes sure that the error is coming from the closing brace itself
|
||||
CHECK_EQ(columnOfEndBraceError("_ = `{a`"), 7);
|
||||
CHECK_EQ(columnOfEndBraceError("_ = `{abcdefg`"), 13);
|
||||
CHECK_EQ(columnOfEndBraceError("_ = `{a`"), columnOfEndBraceError("_ = `{abcdefg`"));
|
||||
CHECK_NE(columnOfEndBraceError("_ = `{a`"), columnOfEndBraceError("_ = `{a`"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_interpolated_string_without_end_brace_in_table")
|
||||
|
@ -4194,8 +4196,136 @@ TEST_CASE_FIXTURE(Fixture, "parsing_type_suffix_for_return_type_with_variadic")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "parsing_string_union_indexers")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauParseStringIndexer, true};
|
||||
parse(R"(type foo = { ["bar" | "baz"]: number })");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "parsing_incomplete_string_interpolation_missing_curly_at_eof")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauParseIncompleteInterpStringsWithLocation, true};
|
||||
auto parseResult = tryParse(R"(print(`{e.x} {e.a)");
|
||||
const auto first = parseResult.root->body.data[0];
|
||||
auto expr = first->as<AstStatExpr>();
|
||||
CHECK(expr != nullptr);
|
||||
auto call = expr->expr->as<AstExprCall>();
|
||||
CHECK(call != nullptr);
|
||||
auto interpString = call->args.data[0]->as<AstExprInterpString>();
|
||||
CHECK(interpString != nullptr);
|
||||
CHECK(interpString->expressions.size == 2);
|
||||
CHECK(interpString->location.begin == Position(0, 6));
|
||||
CHECK(interpString->location.end == Position(0, 17));
|
||||
CHECK_EQ(parseResult.errors.size(), 2);
|
||||
|
||||
auto err = parseResult.errors[0];
|
||||
CHECK_EQ(err.getMessage(), "Malformed interpolated string; did you forget to add a '}'?");
|
||||
CHECK_EQ(err.getLocation(), Location({0, 16}, {0, 17}));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "parsing_incomplete_string_interpolation_missing_backtick_at_eof")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauParseIncompleteInterpStringsWithLocation, true};
|
||||
auto parseResult = tryParse(R"(print(`{e.x} {e.a})");
|
||||
const auto first = parseResult.root->body.data[0];
|
||||
auto expr = first->as<AstStatExpr>();
|
||||
CHECK(expr != nullptr);
|
||||
auto call = expr->expr->as<AstExprCall>();
|
||||
CHECK(call != nullptr);
|
||||
auto interpString = call->args.data[0]->as<AstExprInterpString>();
|
||||
CHECK(interpString != nullptr);
|
||||
CHECK(interpString->expressions.size == 2);
|
||||
CHECK(interpString->location.begin == Position(0, 6));
|
||||
CHECK(interpString->location.end == Position(0, 18));
|
||||
CHECK_EQ(parseResult.errors.size(), 2);
|
||||
|
||||
auto err = parseResult.errors[0];
|
||||
CHECK_EQ(err.getMessage(), "Malformed interpolated string; did you forget to add a '`'?");
|
||||
CHECK_EQ(err.getLocation(), Location({0, 17}, {0, 18}));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "parsing_incomplete_string_interpolation_missing_curly_with_backtick_at_eof")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauParseIncompleteInterpStringsWithLocation, true};
|
||||
auto parseResult = tryParse(R"(print(`{e.x} {e.a`)");
|
||||
const auto first = parseResult.root->body.data[0];
|
||||
auto expr = first->as<AstStatExpr>();
|
||||
CHECK(expr != nullptr);
|
||||
auto call = expr->expr->as<AstExprCall>();
|
||||
CHECK(call != nullptr);
|
||||
auto interpString = call->args.data[0]->as<AstExprInterpString>();
|
||||
CHECK(interpString != nullptr);
|
||||
CHECK(interpString->expressions.size == 2);
|
||||
CHECK(interpString->location.begin == Position(0, 6));
|
||||
CHECK(interpString->location.end == Position(0, 18));
|
||||
CHECK_EQ(parseResult.errors.size(), 2);
|
||||
|
||||
auto err = parseResult.errors[0];
|
||||
CHECK_EQ(err.getMessage(), "Malformed interpolated string; did you forget to add a '}'?");
|
||||
CHECK_EQ(err.getLocation(), Location({0, 17}, {0, 18}));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "parsing_incomplete_string_interpolation_missing_curly_broken_string")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauParseIncompleteInterpStringsWithLocation, true};
|
||||
auto parseResult = tryParse(R"(print(`{e.x} {e.a
|
||||
)");
|
||||
const auto first = parseResult.root->body.data[0];
|
||||
auto expr = first->as<AstStatExpr>();
|
||||
CHECK(expr != nullptr);
|
||||
auto call = expr->expr->as<AstExprCall>();
|
||||
CHECK(call != nullptr);
|
||||
auto interpString = call->args.data[0]->as<AstExprInterpString>();
|
||||
CHECK(interpString != nullptr);
|
||||
CHECK(interpString->expressions.size == 2);
|
||||
CHECK(interpString->location.begin == Position(0, 6));
|
||||
CHECK(interpString->location.end == Position(0, 17));
|
||||
CHECK_EQ(parseResult.errors.size(), 2);
|
||||
|
||||
auto err = parseResult.errors[0];
|
||||
CHECK_EQ(err.getMessage(), "Malformed interpolated string; did you forget to add a '}'?");
|
||||
CHECK_EQ(err.getLocation(), Location({0, 16}, {0, 17}));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "parsing_incomplete_string_interpolation_missing_backtick_broken_string")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauParseIncompleteInterpStringsWithLocation, true};
|
||||
auto parseResult = tryParse(R"(print(`{e.x} {e.a}
|
||||
)");
|
||||
const auto first = parseResult.root->body.data[0];
|
||||
auto expr = first->as<AstStatExpr>();
|
||||
CHECK(expr != nullptr);
|
||||
auto call = expr->expr->as<AstExprCall>();
|
||||
CHECK(call != nullptr);
|
||||
auto interpString = call->args.data[0]->as<AstExprInterpString>();
|
||||
CHECK(interpString != nullptr);
|
||||
CHECK(interpString->expressions.size == 2);
|
||||
CHECK(interpString->location.begin == Position(0, 6));
|
||||
CHECK(interpString->location.end == Position(0, 18));
|
||||
CHECK_EQ(parseResult.errors.size(), 2);
|
||||
|
||||
auto err = parseResult.errors[0];
|
||||
CHECK_EQ(err.getMessage(), "Malformed interpolated string; did you forget to add a '`'?");
|
||||
CHECK_EQ(err.getLocation(), Location({0, 17}, {0, 18}));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "parsing_incomplete_string_interpolation_missing_curly_with_backtick_broken_string")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauParseIncompleteInterpStringsWithLocation, true};
|
||||
auto parseResult = tryParse(R"(print(`{e.x} {e.a`
|
||||
)");
|
||||
const auto first = parseResult.root->body.data[0];
|
||||
auto expr = first->as<AstStatExpr>();
|
||||
CHECK(expr != nullptr);
|
||||
auto call = expr->expr->as<AstExprCall>();
|
||||
CHECK(call != nullptr);
|
||||
auto interpString = call->args.data[0]->as<AstExprInterpString>();
|
||||
CHECK(interpString != nullptr);
|
||||
CHECK(interpString->expressions.size == 2);
|
||||
CHECK(interpString->location.begin == Position(0, 6));
|
||||
CHECK(interpString->location.end == Position(0, 18));
|
||||
CHECK_EQ(parseResult.errors.size(), 2);
|
||||
|
||||
auto err = parseResult.errors[0];
|
||||
CHECK_EQ(err.getMessage(), "Malformed interpolated string; did you forget to add a '}'?");
|
||||
CHECK_EQ(err.getLocation(), Location({0, 17}, {0, 18}));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -568,6 +568,20 @@ TEST_CASE_FIXTURE(ReplWithPathFixture, "RegisterRuntimeModule")
|
|||
assertOutputContainsAll({"true"});
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ReplWithPathFixture, "RegisterRuntimeModuleCaseInsensitive")
|
||||
{
|
||||
lua_pushcfunction(L, luarequire_registermodule, nullptr);
|
||||
lua_pushstring(L, "@test/helloworld");
|
||||
lua_newtable(L);
|
||||
lua_pushstring(L, "hello");
|
||||
lua_pushstring(L, "world");
|
||||
lua_settable(L, -3);
|
||||
lua_call(L, 2, 0);
|
||||
|
||||
runCode(L, "return require('@TeSt/heLLoWoRld').hello == 'world'");
|
||||
assertOutputContainsAll({"true"});
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ReplWithPathFixture, "ProxyRequire")
|
||||
{
|
||||
luarequire_pushproxyrequire(L, requireConfigInit, createCliRequireContext(L));
|
||||
|
|
|
@ -25,7 +25,9 @@ LUAU_FASTFLAG(LuauEagerGeneralization4)
|
|||
LUAU_FASTFLAG(LuauIceLess)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauSimplifyAnyAndUnion)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving3)
|
||||
LUAU_FASTFLAG(LuauDontDynamicallyCreateRedundantSubtypeConstraints)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
|
||||
struct LimitFixture : BuiltinsFixture
|
||||
{
|
||||
|
@ -292,7 +294,9 @@ TEST_CASE_FIXTURE(LimitFixture, "Signal_exerpt" * doctest::timeout(0.5))
|
|||
// These flags are required to surface the problem.
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
{FFlag::LuauPushFunctionTypesInFunctionStatement, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
|
||||
// And this flag is the one that fixes it.
|
||||
{FFlag::LuauSimplifyAnyAndUnion, true},
|
||||
|
@ -341,7 +345,7 @@ TEST_CASE_FIXTURE(Fixture, "limit_number_of_dynamically_created_constraints")
|
|||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauLimitDynamicConstraintSolving, true},
|
||||
{FFlag::LuauLimitDynamicConstraintSolving3, true},
|
||||
};
|
||||
|
||||
constexpr const char* src = R"(
|
||||
|
@ -369,4 +373,65 @@ TEST_CASE_FIXTURE(Fixture, "limit_number_of_dynamically_created_constraints")
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "limit_number_of_dynamically_created_constraints_2")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauLimitDynamicConstraintSolving3, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
{FFlag::LuauPushFunctionTypesInFunctionStatement, true},
|
||||
{FFlag::LuauDontDynamicallyCreateRedundantSubtypeConstraints, true},
|
||||
};
|
||||
|
||||
ScopedFastInt sfi{FInt::LuauSolverConstraintLimit, 50};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local T = {}
|
||||
|
||||
export type T = typeof(setmetatable(
|
||||
{},
|
||||
{} :: typeof(T)
|
||||
))
|
||||
|
||||
function T.One(): T
|
||||
return nil :: any
|
||||
end
|
||||
|
||||
function T.Two(self: T) end
|
||||
|
||||
function T.Three(self: T, x)
|
||||
self.Prop[x] = true
|
||||
end
|
||||
|
||||
function T.Four(self: T, x)
|
||||
print("", x)
|
||||
end
|
||||
|
||||
function T.Five(self: T) end
|
||||
|
||||
function T.Six(self: T) end
|
||||
|
||||
function T.Seven(self: T) end
|
||||
|
||||
function T.Eight(self: T) end
|
||||
|
||||
function T.Nine(self: T) end
|
||||
|
||||
function T.Ten(self: T) end
|
||||
|
||||
function T.Eleven(self: T) end
|
||||
|
||||
function T.Twelve(self: T) end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
LUAU_REQUIRE_ERROR(result, UnknownProperty);
|
||||
|
||||
// A sanity check to ensure that this statistic is being recorded at all.
|
||||
CHECK(frontend->stats.dynamicConstraintsCreated > 10);
|
||||
|
||||
CHECK(frontend->stats.dynamicConstraintsCreated < 40);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
|
||||
using namespace Luau;
|
||||
|
@ -1654,7 +1655,10 @@ TEST_CASE_FIXTURE(SubtypeFixture, "substitute_a_generic_for_a_negation")
|
|||
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "free_types_might_be_subtypes")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization4, true};
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
TypeId argTy = arena.freshType(getBuiltins(), moduleScope.get());
|
||||
FreeType* freeArg = getMutable<FreeType>(argTy);
|
||||
|
|
|
@ -14,8 +14,6 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauRecursiveTypeParameterRestriction)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauFixEmptyTypePackStringification)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauSolverAgnosticStringification)
|
||||
|
||||
TEST_SUITE_BEGIN("ToString");
|
||||
|
@ -507,8 +505,6 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_array_uses_array_syntax")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "the_empty_type_pack_should_be_parenthesized")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauFixEmptyTypePackStringification, true};
|
||||
|
||||
TypePackVar emptyTypePack{TypePack{}};
|
||||
CHECK_EQ(toString(&emptyTypePack), "()");
|
||||
|
||||
|
@ -889,8 +885,6 @@ TEST_CASE_FIXTURE(Fixture, "tostring_unsee_ttv_if_array")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "tostring_error_mismatch")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
function f1(t: {a : number, b: string, c: {d: string}}) : {a : number, b : string, c : { d : number}}
|
||||
|
|
|
@ -16,10 +16,11 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
LUAU_DYNAMIC_FASTINT(LuauTypeFamilyApplicationCartesianProductLimit)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauErrorSuppressionTypeFunctionArgs)
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||
LUAU_FASTFLAG(LuauEmptyStringInKeyOf)
|
||||
LUAU_FASTFLAG(DebugLuauAssertOnForcedConstraint)
|
||||
LUAU_FASTFLAG(LuauDoNotBlockOnStuckTypeFunctions)
|
||||
LUAU_FASTFLAG(LuauForceSimplifyConstraint2)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
|
||||
struct TypeFunctionFixture : Fixture
|
||||
{
|
||||
|
@ -351,8 +352,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_works")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type MyObject = { x: number, y: number, z: number }
|
||||
type KeysOfMyObject = keyof<MyObject>
|
||||
|
@ -374,8 +373,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_works_with_metatables")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local metatable = { __index = {w = 1} }
|
||||
local obj = setmetatable({x = 1, y = 2, z = 3}, metatable)
|
||||
|
@ -433,8 +430,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_errors_if_it_has_nontabl
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_string_indexer")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
|
@ -466,8 +461,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_common_subset_if_union_o
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type MyObject = { x: number, y: number, z: number }
|
||||
type MyOtherObject = { w: number, y: number, z: number }
|
||||
|
@ -504,8 +497,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_works")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type MyObject = { x: number, y: number, z: number }
|
||||
type KeysOfMyObject = rawkeyof<MyObject>
|
||||
|
@ -527,8 +518,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_ignores_metatables")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local metatable = { __index = {w = 1} }
|
||||
local obj = setmetatable({x = 1, y = 2, z = 3}, metatable)
|
||||
|
@ -570,8 +559,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_common_subset_if_unio
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type MyObject = { x: number, y: number, z: number }
|
||||
type MyOtherObject = { w: number, y: number, z: number }
|
||||
|
@ -608,8 +595,6 @@ TEST_CASE_FIXTURE(ExternTypeFixture, "keyof_type_function_works_on_extern_types"
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type KeysOfMyObject = keyof<BaseClass>
|
||||
|
||||
|
@ -744,7 +729,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_oss_crash_gh1161")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag sff[] = {{FFlag::LuauEagerGeneralization4, true}, {FFlag::LuauStuckTypeFunctionsStillDispatch, true}};
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local EnumVariants = {
|
||||
|
@ -1008,8 +996,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type MyObject = {a: string, b: number, c: boolean}
|
||||
type IdxAType = index<MyObject, "a">
|
||||
|
@ -1182,18 +1168,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_errors_w_var_indexer")
|
|||
type errType1 = index<MyObject, key>
|
||||
)");
|
||||
|
||||
if (FFlag::LuauErrorSuppressionTypeFunctionArgs)
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK(toString(result.errors[0]) == "Unknown type 'key'");
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
CHECK(toString(result.errors[0]) == "Second argument to index<MyObject, _> is not a valid index type");
|
||||
CHECK(toString(result.errors[1]) == "Unknown type 'key'");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works_w_union_type_indexer")
|
||||
{
|
||||
|
@ -1309,8 +1286,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_works")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type MyObject = {a: string, b: number, c: boolean}
|
||||
type RawAType = rawget<MyObject, "a">
|
||||
|
@ -1354,18 +1329,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_errors_w_var_indexer")
|
|||
)");
|
||||
|
||||
|
||||
if (FFlag::LuauErrorSuppressionTypeFunctionArgs)
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK(toString(result.errors[0]) == "Unknown type 'key'");
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
CHECK(toString(result.errors[0]) == "Second argument to rawget<MyObject, _> is not a valid index type");
|
||||
CHECK(toString(result.errors[1]) == "Unknown type 'key'");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_works_w_union_type_indexer")
|
||||
{
|
||||
|
@ -1691,8 +1657,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "error_suppression_should_work_on_type_functi
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag errorSuppressionTypeFunctionArgs{FFlag::LuauErrorSuppressionTypeFunctionArgs, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local Colours = {
|
||||
Red = 1,
|
||||
|
@ -1720,7 +1684,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "fully_dispatch_type_function_that_is_paramet
|
|||
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauStuckTypeFunctionsStillDispatch, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -1747,7 +1711,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "undefined_add_application")
|
|||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauStuckTypeFunctionsStillDispatch, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -1806,8 +1770,9 @@ struct TFFixture
|
|||
TypeCheckLimits limits;
|
||||
TypeFunctionRuntime runtime{NotNull{&ice}, NotNull{&limits}};
|
||||
|
||||
const ScopedFastFlag sff[1] = {
|
||||
const ScopedFastFlag sff[2] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
BuiltinTypeFunctions builtinTypeFunctions;
|
||||
|
@ -1870,7 +1835,10 @@ TEST_CASE_FIXTURE(TFFixture, "a_type_function_parameterized_on_generics_is_solve
|
|||
|
||||
TEST_CASE_FIXTURE(TFFixture, "a_tf_parameterized_on_a_solved_tf_is_solved")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauStuckTypeFunctionsStillDispatch, true};
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
TypeId a = arena->addType(GenericType{"A"});
|
||||
TypeId b = arena->addType(GenericType{"B"});
|
||||
|
@ -1889,7 +1857,10 @@ TEST_CASE_FIXTURE(TFFixture, "a_tf_parameterized_on_a_solved_tf_is_solved")
|
|||
|
||||
TEST_CASE_FIXTURE(TFFixture, "a_tf_parameterized_on_a_stuck_tf_is_stuck")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauStuckTypeFunctionsStillDispatch, true};
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
TypeId innerAddTy = arena->addType(TypeFunctionInstanceType{builtinTypeFunctions.addFunc, {builtinTypes_.bufferType, builtinTypes_.booleanType}});
|
||||
|
||||
|
@ -1903,4 +1874,23 @@ TEST_CASE_FIXTURE(TFFixture, "a_tf_parameterized_on_a_stuck_tf_is_stuck")
|
|||
CHECK(tfit->state == TypeFunctionInstanceState::Stuck);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_type_functions_should_not_get_stuck_or")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
{FFlag::LuauForceSimplifyConstraint2, true},
|
||||
{FFlag::LuauDoNotBlockOnStuckTypeFunctions, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function init(data)
|
||||
return not data or data == ''
|
||||
end
|
||||
)");
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK(get<ExplicitFunctionAnnotationRecommended>(result.errors[0]));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -10,9 +10,7 @@ using namespace Luau;
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||
LUAU_FASTFLAG(LuauTypeFunctionSerializeFollowMetatable)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
|
||||
TEST_SUITE_BEGIN("UserDefinedTypeFunctionTests");
|
||||
|
||||
|
@ -352,7 +350,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_strsingleton_methods_work")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_union_serialization_works")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_union(arg)
|
||||
|
@ -372,7 +369,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_union_serialization_works")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_optional_works")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function numberhuh()
|
||||
|
@ -391,7 +387,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_optional_works")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_optional_works_on_unions")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function foobar()
|
||||
|
@ -413,8 +408,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_union_methods_work")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getunion()
|
||||
local ty = types.unionof(types.string, types.number, types.boolean)
|
||||
|
@ -442,7 +435,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_union_methods_work")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_intersection_serialization_works")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_intersection(arg)
|
||||
|
@ -464,8 +456,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_intersection_methods_work")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getintersection()
|
||||
local tbl1 = types.newtable(nil, nil, nil)
|
||||
|
@ -499,7 +489,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_intersection_methods_work")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_negation_methods_work")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getnegation()
|
||||
|
@ -548,7 +537,6 @@ local function notok(idx: fail<number>): never return idx end
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_table_serialization_works")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_table(arg)
|
||||
|
@ -568,7 +556,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_table_serialization_works")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_table_methods_work")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function gettable()
|
||||
|
@ -607,7 +594,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_table_methods_work")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_metatable_methods_work")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getmetatable()
|
||||
|
@ -657,8 +643,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_function_methods_work")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getfunction()
|
||||
local ty = types.newfunction(nil, nil) -- () -> ()
|
||||
|
@ -718,7 +702,6 @@ TEST_CASE_FIXTURE(ExternTypeFixture, "udtf_class_serialization_works2")
|
|||
TEST_CASE_FIXTURE(ExternTypeFixture, "udtf_class_methods_works")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getclass(arg)
|
||||
|
@ -740,7 +723,6 @@ TEST_CASE_FIXTURE(ExternTypeFixture, "udtf_class_methods_works")
|
|||
TEST_CASE_FIXTURE(ExternTypeFixture, "write_of_readonly_is_nil")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getclass(arg)
|
||||
|
@ -767,7 +749,6 @@ TEST_CASE_FIXTURE(ExternTypeFixture, "write_of_readonly_is_nil")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_check_mutability")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function checkmut()
|
||||
|
@ -799,7 +780,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_check_mutability")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_copy_works")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getcopy()
|
||||
|
@ -985,7 +965,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_function_type_cant_call_get_props")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_calling_each_other")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function foo()
|
||||
|
@ -1006,7 +985,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_calling_each_other")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_calling_each_other_2")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function first(arg)
|
||||
|
@ -1059,7 +1037,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_calling_each_other_3")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_calling_each_other_unordered")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function bar()
|
||||
|
@ -1125,8 +1102,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_optionify")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function optionify(tbl)
|
||||
if not tbl:is("table") then
|
||||
|
@ -1179,8 +1154,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_recursion_and_gc")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function foo(tbl)
|
||||
local count = 0
|
||||
|
@ -1244,8 +1217,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_strip_indexer")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function stripindexer(tbl)
|
||||
if not tbl:is("table") then
|
||||
|
@ -1331,10 +1302,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_eq_field")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "tag_field")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function test(x)
|
||||
|
@ -2403,7 +2371,7 @@ TEST_CASE_FIXTURE(ExternTypeFixture, "type_alias_reduction_errors")
|
|||
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauStuckTypeFunctionsStillDispatch, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -2456,8 +2424,6 @@ end
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "udtf_metatable_serialization_follows")
|
||||
{
|
||||
ScopedFastFlag luauTypeFunctionSerializeFollowMetatable{FFlag::LuauTypeFunctionSerializeFollowMetatable, true};
|
||||
|
||||
LUAU_REQUIRE_ERRORS(check(R"(
|
||||
_ = setmetatable(_(),_),(_) or _ == _ or f
|
||||
while _() do
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeAliases");
|
||||
|
||||
|
@ -205,10 +204,7 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_aliases")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_aliases")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type T<a> = { v: a }
|
||||
|
@ -224,10 +220,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_aliases")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "dependent_generic_aliases")
|
||||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type T<a> = { v: a }
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -445,11 +444,9 @@ TEST_CASE_FIXTURE(Fixture, "self_referential_type_alias")
|
|||
std::optional<Property> incr = get(oTable->props, "incr");
|
||||
REQUIRE(incr);
|
||||
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
REQUIRE(incr->readTy);
|
||||
|
||||
const FunctionType* incrFunc =
|
||||
FFlag::LuauRemoveTypeCallsForReadWriteProps ? get<FunctionType>(*incr->readTy) : get<FunctionType>(incr->type_DEPRECATED());
|
||||
const FunctionType* incrFunc = get<FunctionType>(*incr->readTy);
|
||||
REQUIRE(incrFunc);
|
||||
|
||||
std::optional<TypeId> firstArg = first(incrFunc->argTypes);
|
||||
|
@ -608,14 +605,8 @@ TEST_CASE_FIXTURE(Fixture, "interface_types_belong_to_interface_arena")
|
|||
TableType* exportsTable = getMutable<TableType>(*exportsType);
|
||||
REQUIRE(exportsTable != nullptr);
|
||||
|
||||
TypeId n;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
REQUIRE(exportsTable->props["n"].readTy);
|
||||
n = *exportsTable->props["n"].readTy;
|
||||
}
|
||||
else
|
||||
n = exportsTable->props["n"].type_DEPRECATED();
|
||||
TypeId n = *exportsTable->props["n"].readTy;
|
||||
REQUIRE(n != nullptr);
|
||||
|
||||
CHECK(isInArena(n, mod.interfaceTypes));
|
||||
|
@ -670,24 +661,12 @@ TEST_CASE_FIXTURE(Fixture, "cloned_interface_maintains_pointers_between_definiti
|
|||
TableType* exportsTable = getMutable<TableType>(*exportsType);
|
||||
REQUIRE(exportsTable != nullptr);
|
||||
|
||||
TypeId aType;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
REQUIRE(exportsTable->props["a"].readTy);
|
||||
aType = *exportsTable->props["a"].readTy;
|
||||
}
|
||||
else
|
||||
aType = exportsTable->props["a"].type_DEPRECATED();
|
||||
TypeId aType = *exportsTable->props["a"].readTy;
|
||||
REQUIRE(aType);
|
||||
|
||||
TypeId bType;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
REQUIRE(exportsTable->props["b"].readTy);
|
||||
bType = *exportsTable->props["b"].readTy;
|
||||
}
|
||||
else
|
||||
bType = exportsTable->props["b"].type_DEPRECATED();
|
||||
TypeId bType = *exportsTable->props["b"].readTy;
|
||||
REQUIRE(bType);
|
||||
|
||||
CHECK(isInArena(recordType, mod.interfaceTypes));
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferAnyError");
|
||||
|
||||
|
@ -248,14 +247,9 @@ TEST_CASE_FIXTURE(Fixture, "assign_prop_to_table_by_calling_any_yields_any")
|
|||
REQUIRE(ttv);
|
||||
REQUIRE(ttv->props.count("prop"));
|
||||
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
REQUIRE(ttv->props["prop"].readTy);
|
||||
CHECK_EQ("any", toString(*ttv->props["prop"].readTy));
|
||||
}
|
||||
else
|
||||
REQUIRE_EQ("any", toString(ttv->props["prop"].type_DEPRECATED()));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "quantify_any_does_not_bind_to_itself")
|
||||
{
|
||||
|
|
|
@ -12,11 +12,7 @@ using namespace Luau;
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauTableCloneClonesType3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
LUAU_FASTFLAG(LuauStringFormatImprovements)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAG(LuauWriteOnlyPropertyMangling)
|
||||
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeCheckFunctionCalls)
|
||||
LUAU_FASTFLAG(LuauSuppressErrorsForMultipleNonviableOverloads)
|
||||
|
||||
|
@ -713,19 +709,12 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "bad_select_should_not_crash")
|
|||
end
|
||||
)");
|
||||
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
CHECK_EQ("Argument count mismatch. Function expects at least 1 argument, but none are specified", toString(result.errors[0]));
|
||||
CHECK_EQ("Argument count mismatch. Function expects at least 1 argument, but none are specified", toString(result.errors[1]));
|
||||
}
|
||||
else if (FFlag::LuauSolverV2)
|
||||
{
|
||||
// Counterintuitively, the parameter l0 is unconstrained and therefore it is valid to pass nil.
|
||||
// The new solver therefore considers that parameter to be optional.
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK("Argument count mismatch. Function expects at least 1 argument, but none are specified" == toString(result.errors[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
|
@ -1317,14 +1306,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_persistent_typelevel_change")
|
|||
REQUIRE(mathTy);
|
||||
TableType* ttv = getMutable<TableType>(mathTy);
|
||||
REQUIRE(ttv);
|
||||
const FunctionType* ftv;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
|
||||
REQUIRE(ttv->props["frexp"].readTy);
|
||||
ftv = get<FunctionType>(*ttv->props["frexp"].readTy);
|
||||
}
|
||||
else
|
||||
ftv = get<FunctionType>(ttv->props["frexp"].type_DEPRECATED());
|
||||
const FunctionType* ftv = get<FunctionType>(*ttv->props["frexp"].readTy);
|
||||
|
||||
REQUIRE(ftv);
|
||||
auto original = ftv->level;
|
||||
|
||||
|
@ -1679,7 +1664,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_should_support_any")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_should_support_any_2")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag sff{FFlag::LuauStringFormatImprovements, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local fmt = "Hello, %s!" :: any
|
||||
|
@ -1695,7 +1679,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_should_support_any_2")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_should_support_singleton_types")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag sff{FFlag::LuauStringFormatImprovements, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local fmt: "Hello, %s!" = "Hello, %s!"
|
||||
|
@ -1713,7 +1696,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_should_support_singleton_types
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "better_string_format_error_when_format_string_is_dynamic")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag sff{FFlag::LuauStringFormatImprovements, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local fmt: string = "Hello, %s!"
|
||||
|
@ -1733,7 +1715,6 @@ TEST_CASE_FIXTURE(Fixture, "write_only_table_assertion")
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauEnableWriteOnlyProperties, true},
|
||||
{FFlag::LuauWriteOnlyPropertyMangling, true},
|
||||
{FFlag::LuauTableLiteralSubtypeCheckFunctionCalls, true},
|
||||
};
|
||||
|
|
|
@ -11,7 +11,6 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
|
||||
TEST_SUITE_BEGIN("DefinitionTests");
|
||||
|
||||
|
@ -171,18 +170,19 @@ TEST_CASE_FIXTURE(Fixture, "class_definitions_cannot_overload_non_function")
|
|||
REQUIRE(!result.success);
|
||||
CHECK_EQ(result.parseResult.errors.size(), 0);
|
||||
REQUIRE(bool(result.module));
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
if (FFlag::LuauSolverV2)
|
||||
REQUIRE_EQ(result.module->errors.size(), 2);
|
||||
else
|
||||
REQUIRE_EQ(result.module->errors.size(), 1);
|
||||
|
||||
GenericError* ge = get<GenericError>(result.module->errors[0]);
|
||||
REQUIRE(ge);
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
if (FFlag::LuauSolverV2)
|
||||
CHECK_EQ("Cannot overload read type of non-function class member 'X'", ge->message);
|
||||
else
|
||||
CHECK_EQ("Cannot overload non-function class member 'X'", ge->message);
|
||||
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
GenericError* ge2 = get<GenericError>(result.module->errors[1]);
|
||||
REQUIRE(ge2);
|
||||
|
@ -380,14 +380,8 @@ TEST_CASE_FIXTURE(Fixture, "definitions_symbols_are_generated_for_recursively_re
|
|||
const auto& method = cls->props["myMethod"];
|
||||
CHECK_EQ(method.documentationSymbol, "@test/globaltype/MyClass.myMethod");
|
||||
|
||||
FunctionType* function;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
REQUIRE(method.readTy);
|
||||
function = getMutable<FunctionType>(*method.readTy);
|
||||
}
|
||||
else
|
||||
function = getMutable<FunctionType>(method.type_DEPRECATED());
|
||||
FunctionType* function = getMutable<FunctionType>(*method.readTy);
|
||||
REQUIRE(function);
|
||||
|
||||
REQUIRE(function->definition.has_value());
|
||||
|
|
|
@ -24,16 +24,12 @@ LUAU_FASTINT(LuauTarjanChildLimit)
|
|||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauCollapseShouldNotCrash)
|
||||
LUAU_FASTFLAG(LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
LUAU_FASTFLAG(LuauFormatUseLastPosition)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||
LUAU_FASTFLAG(LuauAvoidGenericsLeakingDuringFunctionCallCheck)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAG(LuauSolverAgnosticStringification)
|
||||
LUAU_FASTFLAG(LuauSuppressErrorsForMultipleNonviableOverloads)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferFunctions");
|
||||
|
||||
|
@ -82,8 +78,6 @@ TEST_CASE_FIXTURE(Fixture, "tc_function")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "check_function_bodies")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function myFunction(): number
|
||||
local a = 0
|
||||
|
@ -195,15 +189,9 @@ TEST_CASE_FIXTURE(Fixture, "generalize_table_property")
|
|||
const TableType* tt = get<TableType>(follow(t));
|
||||
REQUIRE(tt);
|
||||
|
||||
TypeId fooTy;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
const Property& foo = tt->props.at("foo");
|
||||
REQUIRE(foo.readTy);
|
||||
fooTy = *foo.readTy;
|
||||
}
|
||||
else
|
||||
fooTy = tt->props.at("foo").type_DEPRECATED();
|
||||
TypeId fooTy = *foo.readTy;
|
||||
CHECK("<a>(a) -> a" == toString(fooTy));
|
||||
}
|
||||
|
||||
|
@ -249,15 +237,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "vararg_function_is_quantified")
|
|||
|
||||
REQUIRE(ttv->props.count("f"));
|
||||
|
||||
TypeId k;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
const Property& f = ttv->props["f"];
|
||||
REQUIRE(f.readTy);
|
||||
k = *f.readTy;
|
||||
}
|
||||
else
|
||||
k = ttv->props["f"].type_DEPRECATED();
|
||||
TypeId k = *f.readTy;
|
||||
REQUIRE(k);
|
||||
}
|
||||
|
||||
|
@ -1510,8 +1492,6 @@ local a: TableWithFunc = { x = 3, y = 4, f = function(a, b) return a + b end }
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "infer_return_value_type")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function f(): {string|number}
|
||||
return {1, "b", 3}
|
||||
|
@ -1697,8 +1677,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "function_decl_non_self_sealed_overwrite")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "function_decl_non_self_sealed_overwrite_2")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauStuckTypeFunctionsStillDispatch, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local t: { f: ((x: number) -> number)? } = {}
|
||||
|
||||
|
@ -1713,7 +1691,7 @@ t.f = function(x)
|
|||
end
|
||||
)");
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4 && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
LUAU_CHECK_ERROR_COUNT(2, result);
|
||||
LUAU_CHECK_ERROR(result, WhereClauseNeeded); // x2
|
||||
|
@ -1783,8 +1761,6 @@ TEST_CASE_FIXTURE(Fixture, "inferred_higher_order_functions_are_quantified_at_th
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "function_decl_non_self_unsealed_overwrite")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauStuckTypeFunctionsStillDispatch, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local t = { f = nil :: ((x: number) -> number)? }
|
||||
|
||||
|
@ -2061,10 +2037,7 @@ u.b().foo()
|
|||
CHECK_EQ(toString(result.errors[2]), "Argument count mismatch. Function expects 1 to 3 arguments, but none are specified");
|
||||
CHECK_EQ(toString(result.errors[3]), "Argument count mismatch. Function expects 2 to 4 arguments, but none are specified");
|
||||
CHECK_EQ(toString(result.errors[4]), "Argument count mismatch. Function expects at least 1 argument, but none are specified");
|
||||
if (FFlag::LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
CHECK_EQ(toString(result.errors[5]), "Argument count mismatch. Function expects 3 arguments, but only 1 is specified");
|
||||
else
|
||||
CHECK_EQ(toString(result.errors[5]), "Argument count mismatch. Function expects 2 to 3 arguments, but only 1 is specified");
|
||||
CHECK_EQ(toString(result.errors[6]), "Argument count mismatch. Function expects at least 1 argument, but none are specified");
|
||||
CHECK_EQ(toString(result.errors[7]), "Argument count mismatch. Function expects at least 1 argument, but none are specified");
|
||||
CHECK_EQ(toString(result.errors[8]), "Argument count mismatch. Function expects at least 1 argument, but none are specified");
|
||||
|
@ -2454,8 +2427,6 @@ TEST_CASE_FIXTURE(Fixture, "generic_packs_are_not_variadic")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "num_is_solved_before_num_or_str")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function num()
|
||||
return 5
|
||||
|
@ -2478,8 +2449,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "num_is_solved_before_num_or_str")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "num_is_solved_after_num_or_str")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function num_or_str()
|
||||
if math.random() > 0.5 then
|
||||
|
@ -2623,7 +2592,11 @@ end
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "tf_suggest_return_type")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
};
|
||||
|
||||
// CLI-114134: This test:
|
||||
// a) Has a kind of weird result (suggesting `number | false` is not great);
|
||||
|
@ -2637,7 +2610,7 @@ function fib(n)
|
|||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERRORS(result);
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
auto err = get<ExplicitFunctionAnnotationRecommended>(result.errors.back());
|
||||
LUAU_ASSERT(err);
|
||||
CHECK("false | number" == toString(err->recommendedReturn));
|
||||
|
@ -2647,13 +2620,19 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tf_suggest_arg_type")
|
|||
{
|
||||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function fib(n, u)
|
||||
return (n or u) and (n < u and n + fib(n,u))
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERRORS(result);
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
auto err = get<ExplicitFunctionAnnotationRecommended>(result.errors.back());
|
||||
LUAU_ASSERT(err);
|
||||
CHECK("number" == toString(err->recommendedReturn));
|
||||
|
@ -2932,10 +2911,7 @@ TEST_CASE_FIXTURE(Fixture, "fuzzer_missing_follow_in_ast_stat_fun")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "unifier_should_not_bind_free_types")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSimplifyOutOfLine2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSimplifyOutOfLine2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function foo(player)
|
||||
|
@ -2954,17 +2930,23 @@ 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::LuauEagerGeneralization4)
|
||||
if (FFlag::LuauTrackFreeInteriorTypePacks)
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
|
||||
auto tm1 = get<TypeMismatch>(result.errors[0]);
|
||||
REQUIRE(tm1);
|
||||
CHECK(toString(tm1->wantedType) == "string");
|
||||
CHECK(toString(tm1->givenType) == "boolean");
|
||||
|
||||
auto tm2 = get<TypeMismatch>(result.errors[1]);
|
||||
REQUIRE(tm2);
|
||||
CHECK(toString(tm2->wantedType) == "string");
|
||||
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
CHECK(toString(tm2->givenType) == "unknown & ~(false?)");
|
||||
else
|
||||
CHECK(toString(tm2->givenType) == "~(false?)");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -10,15 +10,13 @@
|
|||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauIntersectNotNil)
|
||||
LUAU_FASTFLAG(LuauSubtypingCheckFunctionGenericCounts)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAG(DebugLuauAssertOnForcedConstraint)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauContainsAnyGenericFollowBeforeChecking)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -908,8 +906,6 @@ end
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_functions_should_be_memory_safe")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
-- At one point this produced a UAF
|
||||
|
@ -1213,15 +1209,9 @@ TEST_CASE_FIXTURE(Fixture, "generic_table_method")
|
|||
REQUIRE(tTable != nullptr);
|
||||
|
||||
REQUIRE(tTable->props.count("bar"));
|
||||
TypeId barType;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
Property& bar = tTable->props["bar"];
|
||||
REQUIRE(bar.readTy);
|
||||
barType = *bar.readTy;
|
||||
}
|
||||
else
|
||||
barType = tTable->props["bar"].type_DEPRECATED();
|
||||
TypeId barType = *bar.readTy;
|
||||
REQUIRE(barType != nullptr);
|
||||
|
||||
const FunctionType* ftv = get<FunctionType>(follow(barType));
|
||||
|
@ -1263,15 +1253,8 @@ TEST_CASE_FIXTURE(Fixture, "correctly_instantiate_polymorphic_member_functions")
|
|||
std::optional<Property> fooProp = get(t->props, "foo");
|
||||
REQUIRE(bool(fooProp));
|
||||
|
||||
|
||||
const FunctionType* foo;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
REQUIRE(fooProp->readTy);
|
||||
foo = get<FunctionType>(follow(*fooProp->readTy));
|
||||
}
|
||||
else
|
||||
foo = get<FunctionType>(follow(fooProp->type_DEPRECATED()));
|
||||
const FunctionType* foo = get<FunctionType>(follow(*fooProp->readTy));
|
||||
REQUIRE(bool(foo));
|
||||
|
||||
std::optional<TypeId> ret_ = first(foo->retTypes);
|
||||
|
@ -1318,14 +1301,8 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_cyclic_generic_function")
|
|||
std::optional<Property> methodProp = get(argTable->props, "method");
|
||||
REQUIRE(bool(methodProp));
|
||||
|
||||
const FunctionType* methodFunction;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
REQUIRE(methodProp->readTy);
|
||||
methodFunction = get<FunctionType>(follow(*methodProp->readTy));
|
||||
}
|
||||
else
|
||||
methodFunction = get<FunctionType>(follow(methodProp->type_DEPRECATED()));
|
||||
const FunctionType* methodFunction = get<FunctionType>(follow(*methodProp->readTy));
|
||||
REQUIRE(methodFunction != nullptr);
|
||||
|
||||
std::optional<TypeId> methodArg = first(methodFunction->argTypes);
|
||||
|
@ -1525,12 +1502,12 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_function_function_argument_overloaded"
|
|||
|
||||
// Important FIXME CLI-158432: This test exposes some problems with overload
|
||||
// selection and generic type substitution when
|
||||
// FFlag::LuauStuckTypeFunctionsStillDispatch is set.
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_infer_generic_functions")
|
||||
{
|
||||
ScopedFastFlag _[] = {
|
||||
{FFlag::LuauSubtypingCheckFunctionGenericCounts, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
};
|
||||
CheckResult result;
|
||||
|
||||
|
@ -1547,13 +1524,11 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_infer_generic_functions")
|
|||
local c = sumrec(function(x, y, f) return f(x, y) end) -- type binders are not inferred
|
||||
)");
|
||||
|
||||
if (FFlag::LuauStuckTypeFunctionsStillDispatch) // FIXME CLI-158432
|
||||
CHECK("add<X, X> | number" == toString(requireType("b")));
|
||||
else
|
||||
CHECK("number" == toString(requireType("b")));
|
||||
|
||||
CHECK("add<X, X> | number" == toString(requireType("b"))); // FIXME CLI-161128
|
||||
CHECK("<a>(a, a, (a, a) -> a) -> a" == toString(requireType("sum")));
|
||||
CHECK("<a>(a, a, (a, a) -> a) -> a" == toString(requireTypeAtPosition({7, 29})));
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result); // FIXME CLI-161128
|
||||
CHECK(get<ExplicitFunctionAnnotationRecommended>(result.errors[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1567,11 +1542,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_infer_generic_functions")
|
|||
local b = sumrec(sum) -- ok
|
||||
local c = sumrec(function(x, y, f) return f(x, y) end) -- type binders are not inferred
|
||||
)");
|
||||
}
|
||||
|
||||
if (!FFlag::LuauStuckTypeFunctionsStillDispatch) // FIXME CLI-158432
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "substitution_with_bound_table")
|
||||
|
@ -1857,7 +1830,8 @@ TEST_CASE_FIXTURE(Fixture, "generic_type_packs_shouldnt_be_bound_to_themselves")
|
|||
ScopedFastFlag flags[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauSubtypingCheckFunctionGenericCounts, true},
|
||||
{FFlag::LuauEagerGeneralization4, true}
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
|
|
@ -10,11 +10,9 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
|
||||
TEST_SUITE_BEGIN("IntersectionTypes");
|
||||
|
||||
|
@ -337,10 +335,7 @@ TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "table_intersection_write_sealed_indirect")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauPushFunctionTypesInFunctionStatement, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauPushFunctionTypesInFunctionStatement, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type X = { x: (number) -> number }
|
||||
|
@ -463,8 +458,6 @@ Type 'number' could not be converted into 'X')";
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "error_detailed_intersection_all")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type X = { x: number }
|
||||
type Y = { y: number }
|
||||
|
|
|
@ -15,7 +15,8 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving)
|
||||
LUAU_FASTFLAG(LuauLimitDynamicConstraintSolving3)
|
||||
LUAU_FASTINT(LuauSolverConstraintLimit)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -854,7 +855,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "internal_types_are_scrubbed_from_module")
|
|||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::DebugLuauMagicTypes, true},
|
||||
{FFlag::LuauLimitDynamicConstraintSolving, true}
|
||||
{FFlag::LuauLimitDynamicConstraintSolving3, true}
|
||||
};
|
||||
|
||||
fileResolver.source["game/A"] = R"(
|
||||
|
@ -867,4 +868,55 @@ return function(): _luau_blocked_type return nil :: any end
|
|||
CHECK("(...any) -> *error-type*" == toString(getFrontend().moduleResolver.getModule("game/A")->returnType));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "internal_type_errors_are_only_reported_once")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::DebugLuauMagicTypes, true},
|
||||
{FFlag::LuauLimitDynamicConstraintSolving3, true}
|
||||
};
|
||||
|
||||
fileResolver.source["game/A"] = R"(
|
||||
return function(): { X: _luau_blocked_type, Y: _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) -> { X: *error-type*, Y: *error-type* }" == toString(getFrontend().moduleResolver.getModule("game/A")->returnType));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "scrub_unsealed_tables")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauLimitDynamicConstraintSolving3, true}
|
||||
};
|
||||
|
||||
ScopedFastInt sfi{FInt::LuauSolverConstraintLimit, 5};
|
||||
|
||||
fileResolver.source["game/A"] = R"(
|
||||
type Array<T> = {T}
|
||||
type Hello = Array<Array<Array<Array<Array<Array<Array<Array<Array<Array<number>>>>>>>>>>
|
||||
local X = {}
|
||||
X.foo = 42
|
||||
X.bar = ""
|
||||
return X
|
||||
)";
|
||||
|
||||
fileResolver.source["game/B"] = R"(
|
||||
local x = require(game.A)
|
||||
x.lmao = 42
|
||||
return {}
|
||||
)";
|
||||
|
||||
CheckResult result = getFrontend().check("game/B");
|
||||
// This is going to have a _ton_ of errors
|
||||
LUAU_REQUIRE_ERRORS(result);
|
||||
LUAU_CHECK_ERROR(result, CodeTooComplex);
|
||||
LUAU_CHECK_ERROR(result, ConstraintSolvingIncompleteError);
|
||||
LUAU_CHECK_ERROR(result, InternalError);
|
||||
LUAU_CHECK_ERROR(result, CannotExtendTable);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -52,7 +53,10 @@ TEST_CASE_FIXTURE(NegationFixture, "string_is_not_a_subtype_of_negated_string")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "cofinite_strings_can_be_compared_for_equality")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization4, true};
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(e)
|
||||
|
|
|
@ -14,7 +14,7 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferOOP");
|
||||
|
||||
|
@ -29,12 +29,9 @@ TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_not_defi
|
|||
someTable.Function1() -- Argument count mismatch
|
||||
)");
|
||||
|
||||
if (!FFlag::LuauSolverV2 || FFlag::LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
REQUIRE(get<CountMismatch>(result.errors[0]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_it_wont_help_2")
|
||||
{
|
||||
|
@ -47,12 +44,9 @@ TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_it_wont_
|
|||
someTable.Function2() -- Argument count mismatch
|
||||
)");
|
||||
|
||||
if (!FFlag::LuauSolverV2 || FFlag::LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
REQUIRE(get<CountMismatch>(result.errors[0]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "dont_suggest_using_colon_rather_than_dot_if_another_overload_works")
|
||||
{
|
||||
|
@ -561,6 +555,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "textbook_class_pattern")
|
|||
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -593,6 +588,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "textbook_class_pattern_2")
|
|||
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
|
|
@ -12,17 +12,13 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauFunctionCallsAreNotNilable)
|
||||
LUAU_FASTFLAG(LuauSimplificationTableExternType)
|
||||
LUAU_FASTFLAG(LuauBetterCannotCallFunctionPrimitive)
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||
LUAU_FASTFLAG(LuauNormalizationIntersectTablesPreservesExternTypes)
|
||||
LUAU_FASTFLAG(LuauNormalizationReorderFreeTypeIntersect)
|
||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||
LUAU_FASTFLAG(LuauRefineNoRefineAlways)
|
||||
LUAU_FASTFLAG(LuauDoNotPrototypeTableIndex)
|
||||
LUAU_FASTFLAG(LuauForceSimplifyConstraint2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -661,7 +657,7 @@ TEST_CASE_FIXTURE(Fixture, "free_type_is_equal_to_an_lvalue")
|
|||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauStuckTypeFunctionsStillDispatch, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
{FFlag::LuauNormalizationReorderFreeTypeIntersect, true},
|
||||
};
|
||||
|
||||
|
@ -1633,8 +1629,6 @@ TEST_CASE_FIXTURE(RefinementExternTypeFixture, "refine_param_of_type_folder_or_p
|
|||
|
||||
TEST_CASE_FIXTURE(RefinementExternTypeFixture, "isa_type_refinement_must_be_known_ahead_of_time")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSimplificationTableExternType, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function f(x): Instance
|
||||
if x:IsA("Folder") then
|
||||
|
@ -1673,20 +1667,11 @@ TEST_CASE_FIXTURE(RefinementExternTypeFixture, "asserting_optional_properties_sh
|
|||
local pos = part1.Position
|
||||
)");
|
||||
|
||||
if (FFlag::LuauSolverV2 && !FFlag::LuauNormalizationIntersectTablesPreservesExternTypes)
|
||||
{
|
||||
// CLI-142467: this is a major regression that we need to address.
|
||||
CHECK_EQ("never", toString(requireTypeAtPosition({3, 15})));
|
||||
CHECK_EQ("any", toString(requireTypeAtPosition({6, 29})));
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
CHECK_EQ("WeldConstraint", toString(requireTypeAtPosition({3, 15})));
|
||||
CHECK_EQ("Vector3", toString(requireTypeAtPosition({6, 29})));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(RefinementExternTypeFixture, "asserting_non_existent_properties_should_not_refine_extern_types_to_never")
|
||||
{
|
||||
|
@ -1703,21 +1688,12 @@ TEST_CASE_FIXTURE(RefinementExternTypeFixture, "asserting_non_existent_propertie
|
|||
LUAU_REQUIRE_ERRORS(result);
|
||||
CHECK_EQ(toString(result.errors[0]), "Key 'Part8' not found in class 'WeldConstraint'");
|
||||
|
||||
if (FFlag::LuauSolverV2 && !FFlag::LuauNormalizationIntersectTablesPreservesExternTypes)
|
||||
{
|
||||
// CLI-142467: this is a major regression that we need to address.
|
||||
CHECK_EQ("never", toString(requireTypeAtPosition({3, 15})));
|
||||
CHECK_EQ("any", toString(requireTypeAtPosition({6, 29})));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_EQ("WeldConstraint", toString(requireTypeAtPosition({3, 15})));
|
||||
if (FFlag::LuauSolverV2)
|
||||
CHECK_EQ("any", toString(requireTypeAtPosition({6, 29})));
|
||||
else
|
||||
CHECK_EQ("*error-type*", toString(requireTypeAtPosition({6, 29})));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(RefinementExternTypeFixture, "x_is_not_instance_or_else_not_part")
|
||||
{
|
||||
|
@ -2252,7 +2228,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "luau_polyfill_isindexkey_refine_conjunction"
|
|||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauStuckTypeFunctionsStillDispatch, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
{FFlag::LuauForceSimplifyConstraint2, true},
|
||||
};
|
||||
|
||||
|
@ -2265,7 +2241,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "luau_polyfill_isindexkey_refine_conjunction"
|
|||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(3, result);
|
||||
LUAU_CHECK_ERROR_COUNT(3, result);
|
||||
|
||||
// For some reason we emit three error here.
|
||||
for (const auto& e : result.errors)
|
||||
|
@ -2712,7 +2688,6 @@ TEST_CASE_FIXTURE(RefinementExternTypeFixture, "cannot_call_a_function_single")
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauBetterCannotCallFunctionPrimitive, true},
|
||||
{FFlag::LuauRefineTablesWithReadType, true},
|
||||
};
|
||||
|
||||
|
@ -2732,7 +2707,6 @@ TEST_CASE_FIXTURE(RefinementExternTypeFixture, "cannot_call_a_function_union")
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauBetterCannotCallFunctionPrimitive, true},
|
||||
{FFlag::LuauRefineTablesWithReadType, true},
|
||||
};
|
||||
|
||||
|
@ -2906,7 +2880,6 @@ 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},
|
||||
};
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeSingletons");
|
||||
|
||||
|
@ -376,10 +375,7 @@ TEST_CASE_FIXTURE(Fixture, "indexer_can_be_union_of_singletons")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "table_properties_type_error_escapes")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
@ -396,8 +392,6 @@ TEST_CASE_FIXTURE(Fixture, "table_properties_type_error_escapes")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "error_detailed_tagged_union_mismatch_string")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Cat = { tag: 'cat', catfood: string }
|
||||
type Dog = { tag: 'dog', dogfood: string }
|
||||
|
|
|
@ -24,23 +24,17 @@ LUAU_FASTFLAG(LuauFixIndexerSubtypingOrdering)
|
|||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(DebugLuauAssertOnForcedConstraint)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAG(LuauDisablePrimitiveInferenceInLargeTables)
|
||||
LUAU_FASTINT(LuauPrimitiveInferenceInTableLimit)
|
||||
LUAU_FASTFLAG(LuauAutocompleteMissingFollows)
|
||||
LUAU_FASTFLAG(LuauRemoveTypeCallsForReadWriteProps)
|
||||
LUAU_FASTFLAG(LuauRelateTablesAreNeverDisjoint)
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeCheckFunctionCalls)
|
||||
LUAU_FASTFLAG(LuauAvoidGenericsLeakingDuringFunctionCallCheck)
|
||||
LUAU_FASTFLAG(LuauRefineTablesWithReadType)
|
||||
LUAU_FASTFLAG(LuauSolverAgnosticStringification)
|
||||
LUAU_FASTFLAG(LuauDfgForwardNilFromAndOr)
|
||||
LUAU_FASTFLAG(LuauInferActualIfElseExprType)
|
||||
LUAU_FASTFLAG(LuauInferActualIfElseExprType2)
|
||||
LUAU_FASTFLAG(LuauDoNotPrototypeTableIndex)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(LuauNormalizationLimitTyvarUnionSize)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
|
||||
TEST_SUITE_BEGIN("TableTests");
|
||||
|
||||
|
@ -90,34 +84,19 @@ TEST_CASE_FIXTURE(Fixture, "basic")
|
|||
|
||||
std::optional<Property> fooProp = get(tType->props, "foo");
|
||||
REQUIRE(bool(fooProp));
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
REQUIRE(fooProp->readTy);
|
||||
CHECK_EQ(PrimitiveType::String, getPrimitiveType(*fooProp->readTy));
|
||||
}
|
||||
else
|
||||
CHECK_EQ(PrimitiveType::String, getPrimitiveType(fooProp->type_DEPRECATED()));
|
||||
|
||||
std::optional<Property> bazProp = get(tType->props, "baz");
|
||||
REQUIRE(bool(bazProp));
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
REQUIRE(bazProp->readTy);
|
||||
CHECK_EQ(PrimitiveType::Number, getPrimitiveType(*bazProp->readTy));
|
||||
}
|
||||
else
|
||||
CHECK_EQ(PrimitiveType::Number, getPrimitiveType(bazProp->type_DEPRECATED()));
|
||||
|
||||
std::optional<Property> quuxProp = get(tType->props, "quux");
|
||||
REQUIRE(bool(quuxProp));
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
REQUIRE(quuxProp->readTy);
|
||||
CHECK_EQ(PrimitiveType::NilType, getPrimitiveType(*quuxProp->readTy));
|
||||
}
|
||||
else
|
||||
CHECK_EQ(PrimitiveType::NilType, getPrimitiveType(quuxProp->type_DEPRECATED()));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "augment_table")
|
||||
{
|
||||
|
@ -146,15 +125,9 @@ TEST_CASE_FIXTURE(Fixture, "augment_nested_table")
|
|||
|
||||
REQUIRE(tType->props.find("p") != tType->props.end());
|
||||
|
||||
const TableType* pType;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
Property& p = tType->props["p"];
|
||||
REQUIRE(p.readTy);
|
||||
pType = get<TableType>(p.readTy);
|
||||
}
|
||||
else
|
||||
pType = get<TableType>(tType->props["p"].type_DEPRECATED());
|
||||
const TableType* pType = get<TableType>(p.readTy);
|
||||
REQUIRE(pType != nullptr);
|
||||
|
||||
CHECK("{ p: { foo: string } }" == toString(requireType("t"), {true}));
|
||||
|
@ -298,14 +271,8 @@ TEST_CASE_FIXTURE(Fixture, "tc_member_function")
|
|||
std::optional<Property> fooProp = get(tableType->props, "foo");
|
||||
REQUIRE(bool(fooProp));
|
||||
|
||||
const FunctionType* methodType;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
REQUIRE(fooProp->readTy);
|
||||
methodType = get<FunctionType>(follow(fooProp->readTy));
|
||||
}
|
||||
else
|
||||
methodType = get<FunctionType>(follow(fooProp->type_DEPRECATED()));
|
||||
const FunctionType* methodType = get<FunctionType>(follow(fooProp->readTy));
|
||||
REQUIRE(methodType != nullptr);
|
||||
}
|
||||
|
||||
|
@ -320,14 +287,8 @@ TEST_CASE_FIXTURE(Fixture, "tc_member_function_2")
|
|||
std::optional<Property> uProp = get(tableType->props, "U");
|
||||
REQUIRE(bool(uProp));
|
||||
|
||||
TypeId uType;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
REQUIRE(uProp->readTy);
|
||||
uType = *uProp->readTy;
|
||||
}
|
||||
else
|
||||
uType = uProp->type_DEPRECATED();
|
||||
TypeId uType = *uProp->readTy;
|
||||
|
||||
const TableType* uTable = get<TableType>(uType);
|
||||
REQUIRE(uTable != nullptr);
|
||||
|
@ -335,14 +296,8 @@ TEST_CASE_FIXTURE(Fixture, "tc_member_function_2")
|
|||
std::optional<Property> fooProp = get(uTable->props, "foo");
|
||||
REQUIRE(bool(fooProp));
|
||||
|
||||
const FunctionType* methodType;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
REQUIRE(fooProp->readTy);
|
||||
methodType = get<FunctionType>(follow(fooProp->readTy));
|
||||
}
|
||||
else
|
||||
methodType = get<FunctionType>(follow(fooProp->type_DEPRECATED()));
|
||||
const FunctionType* methodType = get<FunctionType>(follow(fooProp->readTy));
|
||||
REQUIRE(methodType != nullptr);
|
||||
|
||||
std::vector<TypeId> methodArgs = flatten(methodType->argTypes).first;
|
||||
|
@ -958,8 +913,6 @@ TEST_CASE_FIXTURE(Fixture, "array_factory_function")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "sealed_table_indexers_must_unify")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(a: {number}): {string}
|
||||
return a
|
||||
|
@ -1112,16 +1065,9 @@ TEST_CASE_FIXTURE(Fixture, "assigning_to_an_unsealed_table_with_string_literal_s
|
|||
REQUIRE(tableType->indexer == std::nullopt);
|
||||
REQUIRE(0 != tableType->props.count("a"));
|
||||
|
||||
|
||||
TypeId propertyA;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
Property& a = tableType->props["a"];
|
||||
REQUIRE(a.readTy);
|
||||
propertyA = *a.readTy;
|
||||
}
|
||||
else
|
||||
propertyA = tableType->props["a"].type_DEPRECATED();
|
||||
TypeId propertyA = *a.readTy;
|
||||
REQUIRE(propertyA != nullptr);
|
||||
CHECK_EQ(*getBuiltins()->stringType, *propertyA);
|
||||
}
|
||||
|
@ -1750,8 +1696,6 @@ TEST_CASE_FIXTURE(Fixture, "right_table_missing_key2")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "casting_unsealed_tables_with_props_into_table_with_indexer")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type StringToStringMap = { [string]: string }
|
||||
local rt: StringToStringMap = { ["foo"] = 1 }
|
||||
|
@ -1854,8 +1798,6 @@ TEST_CASE_FIXTURE(Fixture, "casting_tables_with_props_into_table_with_indexer4")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "table_subtyping_with_missing_props_dont_report_multiple_errors")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function f(vec1: {x: number}): {x: number, y: number, z: number}
|
||||
return vec1
|
||||
|
@ -1888,8 +1830,6 @@ TEST_CASE_FIXTURE(Fixture, "table_subtyping_with_missing_props_dont_report_multi
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "table_subtyping_with_missing_props_dont_report_multiple_errors2")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type MixedTable = {[number]: number, x: number}
|
||||
local t: MixedTable = {"fail"}
|
||||
|
@ -2098,11 +2038,7 @@ TEST_CASE_FIXTURE(Fixture, "key_setting_inference_given_nil_upper_bound")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "explicit_nil_indexer")
|
||||
{
|
||||
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
auto result = check(R"(
|
||||
local function _(t: { [string]: number? }): number
|
||||
|
@ -2357,12 +2293,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "quantifying_a_bound_var_works")
|
|||
REQUIRE_MESSAGE(ttv, "Expected a table but got " << toString(ty, {true}));
|
||||
REQUIRE(ttv->props.count("new"));
|
||||
Property& prop = ttv->props["new"];
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
REQUIRE(prop.readTy);
|
||||
else
|
||||
REQUIRE(prop.type_DEPRECATED());
|
||||
const FunctionType* ftv =
|
||||
(FFlag::LuauRemoveTypeCallsForReadWriteProps) ? get<FunctionType>(follow(*prop.readTy)) : get<FunctionType>(follow(prop.type_DEPRECATED()));
|
||||
const FunctionType* ftv = get<FunctionType>(follow(*prop.readTy));
|
||||
REQUIRE(ftv);
|
||||
const TypePack* res = get<TypePack>(follow(ftv->retTypes));
|
||||
REQUIRE(res);
|
||||
|
@ -2427,7 +2359,6 @@ local t: { a: {Foo}, b: number } = {
|
|||
// since mutating properties means table properties should be invariant.
|
||||
TEST_CASE_FIXTURE(Fixture, "invariant_table_properties_means_instantiating_tables_in_assignment_is_unsound")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauStuckTypeFunctionsStillDispatch, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
@ -3220,15 +3151,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dont_quantify_table_that_belongs_to_outer_sc
|
|||
REQUIRE(counterType);
|
||||
|
||||
REQUIRE(counterType->props.count("new"));
|
||||
const FunctionType* newType;
|
||||
if (FFlag::LuauRemoveTypeCallsForReadWriteProps)
|
||||
{
|
||||
Property& newProp = counterType->props["new"];
|
||||
REQUIRE(newProp.readTy);
|
||||
newType = get<FunctionType>(follow(*newProp.readTy));
|
||||
}
|
||||
else
|
||||
newType = get<FunctionType>(follow(counterType->props["new"].type_DEPRECATED()));
|
||||
const FunctionType* newType = get<FunctionType>(follow(*newProp.readTy));
|
||||
REQUIRE(newType);
|
||||
|
||||
std::optional<TypeId> newRetType = *first(newType->retTypes);
|
||||
|
@ -3713,7 +3638,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dont_leak_free_table_props")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "mixed_tables_with_implicit_numbered_keys")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
CheckResult result = check(R"(
|
||||
local t: { [string]: number } = { 5, 6, 7 }
|
||||
)");
|
||||
|
@ -3820,7 +3744,10 @@ 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 _{FFlag::LuauEagerGeneralization4, true};
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function f(s)
|
||||
|
@ -4346,10 +4273,7 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_shifted_tables")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "cli_84607_missing_prop_in_array_or_dict")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauFixIndexerSubtypingOrdering, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauFixIndexerSubtypingOrdering, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Thing = { name: string, prop: boolean }
|
||||
|
@ -4417,10 +4341,7 @@ TEST_CASE_FIXTURE(Fixture, "simple_method_definition")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "identify_all_problematic_table_fields")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type T = {
|
||||
|
@ -4514,7 +4435,6 @@ TEST_CASE_FIXTURE(Fixture, "infer_write_property")
|
|||
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}
|
||||
|
@ -4585,7 +4505,6 @@ TEST_CASE_FIXTURE(Fixture, "write_to_read_only_property")
|
|||
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})
|
||||
|
@ -4599,7 +4518,6 @@ TEST_CASE_FIXTURE(Fixture, "write_to_write_only_property")
|
|||
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})
|
||||
|
@ -4615,7 +4533,6 @@ TEST_CASE_FIXTURE(Fixture, "bidirectional_typechecking_with_write_only_property"
|
|||
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})
|
||||
|
@ -4659,15 +4576,7 @@ TEST_CASE_FIXTURE(Fixture, "write_annotations_are_supported_with_the_new_solver"
|
|||
end
|
||||
)");
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "read_and_write_only_table_properties_are_unsupported")
|
||||
|
@ -4716,6 +4625,7 @@ TEST_CASE_FIXTURE(Fixture, "table_writes_introduce_write_properties")
|
|||
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -5248,10 +5158,7 @@ TEST_CASE_FIXTURE(Fixture, "function_check_constraint_too_eager")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "magic_functions_bidirectionally_inferred")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function getStuff(): (string, number, string)
|
||||
|
@ -5355,13 +5262,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "write_only_table_field_duplicate")
|
|||
}
|
||||
)");
|
||||
|
||||
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")
|
||||
|
@ -5444,10 +5345,7 @@ TEST_CASE_FIXTURE(Fixture, "returning_optional_in_table")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "returning_mismatched_optional_in_table")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
auto result = check(R"(
|
||||
local Numbers = { str = ( "" :: string ) }
|
||||
|
@ -5466,7 +5364,7 @@ TEST_CASE_FIXTURE(Fixture, "returning_mismatched_optional_in_table")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "optional_function_in_table")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauTableLiteralSubtypeSpecificCheck2, true}};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
LUAU_CHECK_NO_ERRORS(check(R"(
|
||||
local t: { (() -> ())? } = {
|
||||
|
@ -5520,10 +5418,7 @@ TEST_CASE_FIXTURE(Fixture, "oss_1543_optional_generic_param")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "missing_fields_bidirectional_inference")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
auto result = check(R"(
|
||||
type Book = { title: string, author: string }
|
||||
|
@ -5550,10 +5445,7 @@ TEST_CASE_FIXTURE(Fixture, "missing_fields_bidirectional_inference")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "generic_index_syntax_bidirectional_infer_with_tables")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
auto result = check((R"(
|
||||
local function getStatus(): string
|
||||
|
@ -5615,7 +5507,7 @@ TEST_CASE_FIXTURE(Fixture, "deeply_nested_classish_inference")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "bigger_nested_table_causes_big_type_error")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauTableLiteralSubtypeSpecificCheck2, true}};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
auto result = check(R"(
|
||||
type File = {
|
||||
|
@ -5724,10 +5616,7 @@ TEST_CASE_FIXTURE(Fixture, "fuzz_match_literal_type_crash_again")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "type_mismatch_in_dict")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
@ -5744,10 +5633,8 @@ TEST_CASE_FIXTURE(Fixture, "type_mismatch_in_dict")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "narrow_table_literal_check")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
local dict: { code1: boolean } = {
|
||||
|
@ -5763,10 +5650,8 @@ TEST_CASE_FIXTURE(Fixture, "narrow_table_literal_check")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "narrow_table_literal_check_regression")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
local d1: { code1: boolean } = {
|
||||
|
@ -5783,10 +5668,7 @@ TEST_CASE_FIXTURE(Fixture, "narrow_table_literal_check_regression")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "narrow_table_literal_check_assignment")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
@ -5805,13 +5687,8 @@ TEST_CASE_FIXTURE(Fixture, "narrow_table_literal_check_assignment")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "disable_singleton_inference_on_large_tables")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
{FFlag::LuauDisablePrimitiveInferenceInLargeTables, true},
|
||||
};
|
||||
|
||||
ScopedFastInt _{FInt::LuauPrimitiveInferenceInTableLimit, 2};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
ScopedFastInt sfi{FInt::LuauPrimitiveInferenceInTableLimit, 2};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Word = "foo" | "bar"
|
||||
|
@ -5824,13 +5701,8 @@ TEST_CASE_FIXTURE(Fixture, "disable_singleton_inference_on_large_tables")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "disable_singleton_inference_on_large_nested_tables")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
{FFlag::LuauDisablePrimitiveInferenceInLargeTables, true},
|
||||
};
|
||||
|
||||
ScopedFastInt _{FInt::LuauPrimitiveInferenceInTableLimit, 2};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
ScopedFastInt sfi{FInt::LuauPrimitiveInferenceInTableLimit, 2};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Word = "foo" | "bar"
|
||||
|
@ -5841,13 +5713,8 @@ TEST_CASE_FIXTURE(Fixture, "disable_singleton_inference_on_large_nested_tables")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "large_table_inference_does_not_bleed")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
{FFlag::LuauDisablePrimitiveInferenceInLargeTables, true},
|
||||
};
|
||||
|
||||
ScopedFastInt _{FInt::LuauPrimitiveInferenceInTableLimit, 2};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
ScopedFastInt sfi{FInt::LuauPrimitiveInferenceInTableLimit, 2};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type Word = "foo" | "bar"
|
||||
|
@ -5856,7 +5723,7 @@ TEST_CASE_FIXTURE(Fixture, "large_table_inference_does_not_bleed")
|
|||
)");
|
||||
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 that all the errors are localized to `words`, not `otherWords`
|
||||
CHECK(err.location.begin.line == 2);
|
||||
}
|
||||
|
||||
|
@ -5865,10 +5732,7 @@ TEST_CASE_FIXTURE(Fixture, "large_table_inference_does_not_bleed")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "extremely_large_table" * doctest::timeout(2.0))
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauDisablePrimitiveInferenceInLargeTables, true},
|
||||
};
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
|
||||
const std::string source = "local res = {\n" + rep("\"foo\",\n", 100'000) + "}";
|
||||
LUAU_REQUIRE_NO_ERRORS(check(source));
|
||||
|
@ -5888,10 +5752,7 @@ TEST_CASE_FIXTURE(Fixture, "oss_1838")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "oss_1859")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
@ -6049,9 +5910,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "oss_1450")
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauAvoidGenericsLeakingDuringFunctionCallCheck, true},
|
||||
{FFlag::LuauTableLiteralSubtypeCheckFunctionCalls, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
CheckResult results = check(R"(
|
||||
|
@ -6114,10 +5975,7 @@ TEST_CASE_FIXTURE(Fixture, "oss_1888_and_or_subscriptable")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "cli_119126_regression")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
CheckResult results = check(R"(
|
||||
type literals = "foo" | "bar" | "foobar"
|
||||
|
|
|
@ -28,19 +28,16 @@ LUAU_FASTFLAG(LuauEagerGeneralization4)
|
|||
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
||||
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
|
||||
LUAU_FASTFLAG(LuauUpdateGetMetatableTypeSignature)
|
||||
LUAU_FASTFLAG(LuauSkipLvalueForCompoundAssignment)
|
||||
LUAU_FASTFLAG(LuauMissingFollowInAssignIndexConstraint)
|
||||
LUAU_FASTFLAG(LuauOccursCheckForRefinement)
|
||||
LUAU_FASTFLAG(LuauInferPolarityOfReadWriteProperties)
|
||||
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAG(LuauInferActualIfElseExprType)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauInferActualIfElseExprType2)
|
||||
LUAU_FASTFLAG(LuauForceSimplifyConstraint2)
|
||||
LUAU_FASTFLAG(LuauPushFunctionTypesInFunctionStatement)
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictSuppressSoloConstraintSolvingIncomplete)
|
||||
LUAU_FASTFLAG(LuauReturnMappedGenericPacksFromSubtyping2)
|
||||
LUAU_FASTFLAG(LuauMissingFollowMappedGenericPacks)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -1218,7 +1215,7 @@ TEST_CASE_FIXTURE(Fixture, "type_infer_recursion_limit_normalizer")
|
|||
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
CHECK(4 == result.errors.size());
|
||||
REQUIRE(4 == result.errors.size());
|
||||
CHECK(Location{{2, 22}, {2, 42}} == result.errors[0].location);
|
||||
CHECK(Location{{3, 22}, {3, 42}} == result.errors[1].location);
|
||||
CHECK(Location{{3, 45}, {3, 46}} == result.errors[2].location);
|
||||
|
@ -2021,6 +2018,7 @@ TEST_CASE_FIXTURE(Fixture, "fuzz_generalize_one_remove_type_assert")
|
|||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
};
|
||||
|
||||
auto result = check(R"(
|
||||
|
@ -2056,6 +2054,7 @@ TEST_CASE_FIXTURE(Fixture, "fuzz_generalize_one_remove_type_assert_2")
|
|||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -2089,6 +2088,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "fuzz_simplify_combinatorial_explosion")
|
|||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
};
|
||||
|
||||
LUAU_REQUIRE_ERRORS(check(R"(
|
||||
|
@ -2258,8 +2258,6 @@ end
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "self_bound_due_to_compound_assign")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauSkipLvalueForCompoundAssignment, true};
|
||||
|
||||
loadDefinition(R"(
|
||||
declare class Camera
|
||||
CameraType: string
|
||||
|
@ -2368,7 +2366,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "is_safe_integer_example")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "type_remover_heap_use_after_free")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization4, true};
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
LUAU_REQUIRE_ERRORS(check(R"(
|
||||
_ = if l0.n0.n0 then {n4(...,setmetatable(setmetatable(_),_)),_ == _,} elseif _.ceil._ then _ elseif _ then not _
|
||||
|
@ -2388,8 +2389,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_remover_heap_use_after_free")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "fuzzer_missing_follow_in_assign_index_constraint")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauMissingFollowInAssignIndexConstraint, true};
|
||||
|
||||
LUAU_REQUIRE_ERRORS(check(R"(
|
||||
_._G = nil
|
||||
for _ in ... do
|
||||
|
@ -2421,7 +2420,6 @@ TEST_CASE_FIXTURE(Fixture, "fuzzer_infer_divergent_rw_props")
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauEnableWriteOnlyProperties, true},
|
||||
{FFlag::LuauInferPolarityOfReadWriteProperties, true},
|
||||
};
|
||||
|
||||
|
@ -2446,11 +2444,10 @@ TEST_CASE_FIXTURE(Fixture, "oss_1815_verbatim")
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauInferActualIfElseExprType, true},
|
||||
{FFlag::LuauInferActualIfElseExprType2, true},
|
||||
// This is needed so that we don't hide the string literal free types
|
||||
// behind a `union<_, _>`
|
||||
{FFlag::LuauSimplifyOutOfLine2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
|
||||
CheckResult results = check(R"(
|
||||
|
@ -2482,8 +2479,7 @@ TEST_CASE_FIXTURE(Fixture, "if_then_else_bidirectional_inference")
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauInferActualIfElseExprType, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
{FFlag::LuauInferActualIfElseExprType2, true},
|
||||
};
|
||||
|
||||
CheckResult results = check(R"(
|
||||
|
@ -2504,8 +2500,7 @@ TEST_CASE_FIXTURE(Fixture, "if_then_else_two_errors")
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauInferActualIfElseExprType, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
{FFlag::LuauInferActualIfElseExprType2, true},
|
||||
};
|
||||
|
||||
CheckResult results = check(R"(
|
||||
|
|
|
@ -13,8 +13,6 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
|
||||
LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauFixEmptyTypePackStringification)
|
||||
|
||||
TEST_SUITE_BEGIN("TypePackTests");
|
||||
|
||||
|
@ -338,10 +336,7 @@ local c: Packed<string, number, boolean>
|
|||
REQUIRE(ttvA->instantiatedTypeParams.size() == 1);
|
||||
REQUIRE(ttvA->instantiatedTypePackParams.size() == 1);
|
||||
CHECK_EQ(toString(ttvA->instantiatedTypeParams[0], {true}), "number");
|
||||
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);
|
||||
|
@ -1095,8 +1090,6 @@ TEST_CASE_FIXTURE(Fixture, "unify_variadic_tails_in_arguments")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "unify_variadic_tails_in_arguments_free")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function foo<T...>(...: T...): T...
|
||||
return ...
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -63,8 +63,6 @@ TEST_CASE_FIXTURE(TypeStateFixture, "assign_different_values_to_x")
|
|||
|
||||
TEST_CASE_FIXTURE(TypeStateFixture, "parameter_x_was_constrained_by_two_types")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
// Parameter `x` has a fresh type `'x` bounded by `never` and `unknown`.
|
||||
// The first use of `x` constrains `x`'s upper bound by `string | number`.
|
||||
// The second use of `x`, aliased by `y`, constrains `x`'s upper bound by `string?`.
|
||||
|
@ -404,6 +402,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "prototyped_recursive_functions_but_has_futur
|
|||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
|
|
@ -11,7 +11,6 @@ using namespace Luau;
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
|
||||
TEST_SUITE_BEGIN("UnionTypes");
|
||||
|
||||
|
@ -583,8 +582,6 @@ TEST_CASE_FIXTURE(Fixture, "error_detailed_union_all")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "error_detailed_optional")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type X = { x: number }
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4);
|
||||
LUAU_FASTFLAG(LuauStuckTypeFunctionsStillDispatch);
|
||||
LUAU_FASTFLAG(LuauForceSimplifyConstraint2)
|
||||
LUAU_FASTFLAG(LuauTrackFreeInteriorTypePacks)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferUnknownNever");
|
||||
|
||||
|
@ -332,7 +332,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::LuauTrackFreeInteriorTypePacks, true},
|
||||
{FFlag::LuauForceSimplifyConstraint2, true},
|
||||
};
|
||||
|
||||
|
@ -360,7 +360,7 @@ TEST_CASE_FIXTURE(Fixture, "math_operators_and_never")
|
|||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauStuckTypeFunctionsStillDispatch, true},
|
||||
{FFlag::LuauTrackFreeInteriorTypePacks, true}
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
|
|
@ -9,6 +9,11 @@
|
|||
<DisplayString Condition="size == Luau::CodeGen::X64::SizeX64::byte && index == 1">cl</DisplayString>
|
||||
<DisplayString Condition="size == Luau::CodeGen::X64::SizeX64::byte && index == 2">dl</DisplayString>
|
||||
<DisplayString Condition="size == Luau::CodeGen::X64::SizeX64::byte && index == 3">bl</DisplayString>
|
||||
<DisplayString Condition="size == Luau::CodeGen::X64::SizeX64::byte && index == 4">spl</DisplayString>
|
||||
<DisplayString Condition="size == Luau::CodeGen::X64::SizeX64::byte && index == 5">bpl</DisplayString>
|
||||
<DisplayString Condition="size == Luau::CodeGen::X64::SizeX64::byte && index == 6">sil</DisplayString>
|
||||
<DisplayString Condition="size == Luau::CodeGen::X64::SizeX64::byte && index == 7">dil</DisplayString>
|
||||
<DisplayString Condition="size == Luau::CodeGen::X64::SizeX64::byte && index >= 8">e{(int)index,d}b</DisplayString>
|
||||
|
||||
<DisplayString Condition="size == Luau::CodeGen::X64::SizeX64::dword && index == 0">eax</DisplayString>
|
||||
<DisplayString Condition="size == Luau::CodeGen::X64::SizeX64::dword && index == 1">ecx</DisplayString>
|
||||
|
|
Loading…
Add table
Reference in a new issue