mirror of
https://github.com/luau-lang/luau.git
synced 2025-04-02 01:40:54 +01:00
Merge branch 'upstream' into merge
This commit is contained in:
commit
4fa6e97caa
67 changed files with 783 additions and 407 deletions
|
@ -295,11 +295,25 @@ private:
|
|||
Inference check(const ScopePtr& scope, AstExprFunction* func, std::optional<TypeId> expectedType, bool generalize);
|
||||
Inference check(const ScopePtr& scope, AstExprUnary* unary);
|
||||
Inference check(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType);
|
||||
Inference checkAstExprBinary(
|
||||
const ScopePtr& scope,
|
||||
const Location& location,
|
||||
AstExprBinary::Op op,
|
||||
AstExpr* left,
|
||||
AstExpr* right,
|
||||
std::optional<TypeId> expectedType
|
||||
);
|
||||
Inference check(const ScopePtr& scope, AstExprIfElse* ifElse, std::optional<TypeId> expectedType);
|
||||
Inference check(const ScopePtr& scope, AstExprTypeAssertion* typeAssert);
|
||||
Inference check(const ScopePtr& scope, AstExprInterpString* interpString);
|
||||
Inference check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType);
|
||||
std::tuple<TypeId, TypeId, RefinementId> checkBinary(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType);
|
||||
std::tuple<TypeId, TypeId, RefinementId> checkBinary(
|
||||
const ScopePtr& scope,
|
||||
AstExprBinary::Op op,
|
||||
AstExpr* left,
|
||||
AstExpr* right,
|
||||
std::optional<TypeId> expectedType
|
||||
);
|
||||
|
||||
void visitLValue(const ScopePtr& scope, AstExpr* expr, TypeId rhsType);
|
||||
void visitLValue(const ScopePtr& scope, AstExprLocal* local, TypeId rhsType);
|
||||
|
|
|
@ -59,6 +59,25 @@ struct HashInstantiationSignature
|
|||
size_t operator()(const InstantiationSignature& signature) const;
|
||||
};
|
||||
|
||||
|
||||
struct TablePropLookupResult
|
||||
{
|
||||
// What types are we blocked on for determining this type?
|
||||
std::vector<TypeId> blockedTypes;
|
||||
// The type of the property (if we were able to determine it).
|
||||
std::optional<TypeId> propType;
|
||||
// Whether or not this is _definitely_ derived as the result of an indexer.
|
||||
// We use this to determine whether or not code like:
|
||||
//
|
||||
// t.lol = nil;
|
||||
//
|
||||
// ... is legal. If `t: { [string]: ~nil }` then this is legal as
|
||||
// there's no guarantee on whether "lol" specifically exists.
|
||||
// However, if `t: { lol: ~nil }`, then we cannot allow assignment as
|
||||
// that would remove "lol" from the table entirely.
|
||||
bool isIndex = false;
|
||||
};
|
||||
|
||||
struct ConstraintSolver
|
||||
{
|
||||
NotNull<TypeArena> arena;
|
||||
|
@ -211,7 +230,7 @@ public:
|
|||
// for a, ... in next_function, t, ... do
|
||||
bool tryDispatchIterableFunction(TypeId nextTy, TypeId tableTy, const IterableConstraint& c, NotNull<const Constraint> constraint);
|
||||
|
||||
std::pair<std::vector<TypeId>, std::optional<TypeId>> lookupTableProp(
|
||||
TablePropLookupResult lookupTableProp(
|
||||
NotNull<const Constraint> constraint,
|
||||
TypeId subjectType,
|
||||
const std::string& propName,
|
||||
|
@ -219,7 +238,8 @@ public:
|
|||
bool inConditional = false,
|
||||
bool suppressSimplification = false
|
||||
);
|
||||
std::pair<std::vector<TypeId>, std::optional<TypeId>> lookupTableProp(
|
||||
|
||||
TablePropLookupResult lookupTableProp(
|
||||
NotNull<const Constraint> constraint,
|
||||
TypeId subjectType,
|
||||
const std::string& propName,
|
||||
|
|
|
@ -84,7 +84,6 @@ struct DfgScope
|
|||
|
||||
DfgScope* parent;
|
||||
ScopeType scopeType;
|
||||
Location location;
|
||||
|
||||
using Bindings = DenseHashMap<Symbol, const Def*>;
|
||||
using Props = DenseHashMap<const Def*, std::unordered_map<std::string, const Def*>>;
|
||||
|
@ -156,7 +155,7 @@ private:
|
|||
DenseHashMap<Symbol, FunctionCapture> captures{Symbol{}};
|
||||
void resolveCaptures();
|
||||
|
||||
DfgScope* makeChildScope(Location loc, DfgScope::ScopeType scopeType = DfgScope::Linear);
|
||||
DfgScope* makeChildScope(DfgScope::ScopeType scopeType = DfgScope::Linear);
|
||||
|
||||
void join(DfgScope* p, DfgScope* a, DfgScope* b);
|
||||
void joinBindings(DfgScope* p, const DfgScope& a, const DfgScope& b);
|
||||
|
|
|
@ -53,7 +53,7 @@ struct Replacer : Substitution
|
|||
};
|
||||
|
||||
// A substitution which replaces generic functions by monomorphic functions
|
||||
struct Instantiation2 : Substitution
|
||||
struct Instantiation2 final : Substitution
|
||||
{
|
||||
// Mapping from generic types to free types to be used in instantiation.
|
||||
DenseHashMap<TypeId, TypeId> genericSubstitutions{nullptr};
|
||||
|
|
|
@ -135,9 +135,6 @@ struct Module
|
|||
|
||||
TypePackId returnType = nullptr;
|
||||
std::unordered_map<Name, TypeFun> exportedTypeBindings;
|
||||
// We also need to keep DFG data alive between runs
|
||||
std::shared_ptr<DataFlowGraph> dataFlowGraph = nullptr;
|
||||
std::vector<std::unique_ptr<DfgScope>> dfgScopes;
|
||||
|
||||
bool hasModuleScope() const;
|
||||
ScopePtr getModuleScope() const;
|
||||
|
|
|
@ -762,7 +762,7 @@ struct NegationType
|
|||
TypeId ty;
|
||||
};
|
||||
|
||||
using ErrorType = Unifiable::Error;
|
||||
using ErrorType = Unifiable::Error<TypeId>;
|
||||
|
||||
using TypeVariant = Unifiable::Variant<
|
||||
TypeId,
|
||||
|
|
|
@ -52,7 +52,7 @@ struct GenericTypePack
|
|||
};
|
||||
|
||||
using BoundTypePack = Unifiable::Bound<TypePackId>;
|
||||
using ErrorTypePack = Unifiable::Error;
|
||||
using ErrorTypePack = Unifiable::Error<TypePackId>;
|
||||
|
||||
using TypePackVariant =
|
||||
Unifiable::Variant<TypePackId, FreeTypePack, GenericTypePack, TypePack, VariadicTypePack, BlockedTypePack, TypeFunctionInstanceTypePack>;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Luau/Variant.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace Luau
|
||||
|
@ -94,19 +95,29 @@ struct Bound
|
|||
Id boundTo;
|
||||
};
|
||||
|
||||
template<typename Id>
|
||||
struct Error
|
||||
{
|
||||
// This constructor has to be public, since it's used in Type and TypePack,
|
||||
// but shouldn't be called directly. Please use errorRecoveryType() instead.
|
||||
Error();
|
||||
explicit Error();
|
||||
|
||||
explicit Error(Id synthetic)
|
||||
: synthetic{synthetic}
|
||||
{
|
||||
}
|
||||
|
||||
int index;
|
||||
|
||||
// This is used to create an error that can be rendered out using this field
|
||||
// as appropriate metadata for communicating it to the user.
|
||||
std::optional<Id> synthetic;
|
||||
|
||||
private:
|
||||
static int nextIndex;
|
||||
};
|
||||
|
||||
template<typename Id, typename... Value>
|
||||
using Variant = Luau::Variant<Bound<Id>, Error, Value...>;
|
||||
using Variant = Luau::Variant<Bound<Id>, Error<Id>, Value...>;
|
||||
|
||||
} // namespace Luau::Unifiable
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "Type.h"
|
||||
|
||||
LUAU_FASTINT(LuauVisitRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauBoundLazyTypes2)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
|
||||
namespace Luau
|
||||
|
@ -190,7 +189,7 @@ struct GenericTypeVisitor
|
|||
{
|
||||
return visit(tp);
|
||||
}
|
||||
virtual bool visit(TypePackId tp, const Unifiable::Error& etp)
|
||||
virtual bool visit(TypePackId tp, const ErrorTypePack& etp)
|
||||
{
|
||||
return visit(tp);
|
||||
}
|
||||
|
@ -461,7 +460,7 @@ struct GenericTypeVisitor
|
|||
else if (auto gtv = get<GenericTypePack>(tp))
|
||||
visit(tp, *gtv);
|
||||
|
||||
else if (auto etv = get<Unifiable::Error>(tp))
|
||||
else if (auto etv = get<ErrorTypePack>(tp))
|
||||
visit(tp, *etv);
|
||||
|
||||
else if (auto pack = get<TypePack>(tp))
|
||||
|
|
|
@ -257,8 +257,7 @@ private:
|
|||
LUAU_ASSERT(!"Item holds neither TypeId nor TypePackId when enqueuing its children?");
|
||||
}
|
||||
|
||||
// ErrorType and ErrorTypePack is an alias to this type.
|
||||
void cloneChildren(Unifiable::Error* t)
|
||||
void cloneChildren(ErrorType* t)
|
||||
{
|
||||
// noop.
|
||||
}
|
||||
|
@ -428,6 +427,11 @@ private:
|
|||
t->boundTo = shallowClone(t->boundTo);
|
||||
}
|
||||
|
||||
void cloneChildren(ErrorTypePack* t)
|
||||
{
|
||||
// noop.
|
||||
}
|
||||
|
||||
void cloneChildren(VariadicTypePack* t)
|
||||
{
|
||||
t->ty = shallowClone(t->ty);
|
||||
|
|
|
@ -69,13 +69,11 @@ struct TypeGuard
|
|||
std::string type;
|
||||
};
|
||||
|
||||
static std::optional<TypeGuard> matchTypeGuard(const AstExprBinary* binary)
|
||||
static std::optional<TypeGuard> matchTypeGuard(const AstExprBinary::Op op, AstExpr* left, AstExpr* right)
|
||||
{
|
||||
if (binary->op != AstExprBinary::CompareEq && binary->op != AstExprBinary::CompareNe)
|
||||
if (op != AstExprBinary::CompareEq && op != AstExprBinary::CompareNe)
|
||||
return std::nullopt;
|
||||
|
||||
AstExpr* left = binary->left;
|
||||
AstExpr* right = binary->right;
|
||||
if (right->is<AstExprCall>())
|
||||
std::swap(left, right);
|
||||
|
||||
|
@ -1459,8 +1457,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatAssign* ass
|
|||
|
||||
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatCompoundAssign* assign)
|
||||
{
|
||||
AstExprBinary binop = AstExprBinary{assign->location, assign->op, assign->var, assign->value};
|
||||
TypeId resultTy = check(scope, &binop).ty;
|
||||
TypeId resultTy = checkAstExprBinary(scope, assign->location, assign->op, assign->var, assign->value, std::nullopt).ty;
|
||||
module->astCompoundAssignResultTypes[assign] = resultTy;
|
||||
|
||||
TypeId lhsType = check(scope, assign->var).ty;
|
||||
|
@ -2437,63 +2434,75 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprUnary* unary)
|
|||
|
||||
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType)
|
||||
{
|
||||
auto [leftType, rightType, refinement] = checkBinary(scope, binary, expectedType);
|
||||
return checkAstExprBinary(scope, binary->location, binary->op, binary->left, binary->right, expectedType);
|
||||
}
|
||||
|
||||
switch (binary->op)
|
||||
Inference ConstraintGenerator::checkAstExprBinary(
|
||||
const ScopePtr& scope,
|
||||
const Location& location,
|
||||
AstExprBinary::Op op,
|
||||
AstExpr* left,
|
||||
AstExpr* right,
|
||||
std::optional<TypeId> expectedType
|
||||
)
|
||||
{
|
||||
auto [leftType, rightType, refinement] = checkBinary(scope, op, left, right, expectedType);
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case AstExprBinary::Op::Add:
|
||||
{
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().addFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().addFunc, {leftType, rightType}, {}, scope, location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Sub:
|
||||
{
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().subFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().subFunc, {leftType, rightType}, {}, scope, location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Mul:
|
||||
{
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().mulFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().mulFunc, {leftType, rightType}, {}, scope, location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Div:
|
||||
{
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().divFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().divFunc, {leftType, rightType}, {}, scope, location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::FloorDiv:
|
||||
{
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().idivFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().idivFunc, {leftType, rightType}, {}, scope, location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Pow:
|
||||
{
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().powFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().powFunc, {leftType, rightType}, {}, scope, location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Mod:
|
||||
{
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().modFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().modFunc, {leftType, rightType}, {}, scope, location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Concat:
|
||||
{
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().concatFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().concatFunc, {leftType, rightType}, {}, scope, location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::And:
|
||||
{
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().andFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().andFunc, {leftType, rightType}, {}, scope, location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Or:
|
||||
{
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().orFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().orFunc, {leftType, rightType}, {}, scope, location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::CompareLt:
|
||||
{
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().ltFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().ltFunc, {leftType, rightType}, {}, scope, location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::CompareGe:
|
||||
|
@ -2503,13 +2512,13 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprBinary* binar
|
|||
{rightType, leftType}, // lua decided that `__ge(a, b)` is instead just `__lt(b, a)`
|
||||
{},
|
||||
scope,
|
||||
binary->location
|
||||
location
|
||||
);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::CompareLe:
|
||||
{
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().leFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().leFunc, {leftType, rightType}, {}, scope, location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::CompareGt:
|
||||
|
@ -2519,15 +2528,15 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprBinary* binar
|
|||
{rightType, leftType}, // lua decided that `__gt(a, b)` is instead just `__le(b, a)`
|
||||
{},
|
||||
scope,
|
||||
binary->location
|
||||
location
|
||||
);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::CompareEq:
|
||||
case AstExprBinary::Op::CompareNe:
|
||||
{
|
||||
DefId leftDef = dfg->getDef(binary->left);
|
||||
DefId rightDef = dfg->getDef(binary->right);
|
||||
DefId leftDef = dfg->getDef(left);
|
||||
DefId rightDef = dfg->getDef(right);
|
||||
bool leftSubscripted = containsSubscriptedDefinition(leftDef);
|
||||
bool rightSubscripted = containsSubscriptedDefinition(rightDef);
|
||||
|
||||
|
@ -2536,11 +2545,11 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprBinary* binar
|
|||
// we cannot add nil in this case because then we will blindly accept comparisons that we should not.
|
||||
}
|
||||
else if (leftSubscripted)
|
||||
leftType = makeUnion(scope, binary->location, leftType, builtinTypes->nilType);
|
||||
leftType = makeUnion(scope, location, leftType, builtinTypes->nilType);
|
||||
else if (rightSubscripted)
|
||||
rightType = makeUnion(scope, binary->location, rightType, builtinTypes->nilType);
|
||||
rightType = makeUnion(scope, location, rightType, builtinTypes->nilType);
|
||||
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().eqFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().eqFunc, {leftType, rightType}, {}, scope, location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Op__Count:
|
||||
|
@ -2586,44 +2595,46 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprInterpString*
|
|||
|
||||
std::tuple<TypeId, TypeId, RefinementId> ConstraintGenerator::checkBinary(
|
||||
const ScopePtr& scope,
|
||||
AstExprBinary* binary,
|
||||
AstExprBinary::Op op,
|
||||
AstExpr* left,
|
||||
AstExpr* right,
|
||||
std::optional<TypeId> expectedType
|
||||
)
|
||||
{
|
||||
if (binary->op == AstExprBinary::And)
|
||||
if (op == AstExprBinary::And)
|
||||
{
|
||||
std::optional<TypeId> relaxedExpectedLhs;
|
||||
|
||||
if (expectedType)
|
||||
relaxedExpectedLhs = arena->addType(UnionType{{builtinTypes->falsyType, *expectedType}});
|
||||
|
||||
auto [leftType, leftRefinement] = check(scope, binary->left, relaxedExpectedLhs);
|
||||
auto [leftType, leftRefinement] = check(scope, left, relaxedExpectedLhs);
|
||||
|
||||
ScopePtr rightScope = childScope(binary->right, scope);
|
||||
applyRefinements(rightScope, binary->right->location, leftRefinement);
|
||||
auto [rightType, rightRefinement] = check(rightScope, binary->right, expectedType);
|
||||
ScopePtr rightScope = childScope(right, scope);
|
||||
applyRefinements(rightScope, right->location, leftRefinement);
|
||||
auto [rightType, rightRefinement] = check(rightScope, right, expectedType);
|
||||
|
||||
return {leftType, rightType, refinementArena.conjunction(leftRefinement, rightRefinement)};
|
||||
}
|
||||
else if (binary->op == AstExprBinary::Or)
|
||||
else if (op == AstExprBinary::Or)
|
||||
{
|
||||
std::optional<TypeId> relaxedExpectedLhs;
|
||||
|
||||
if (expectedType)
|
||||
relaxedExpectedLhs = arena->addType(UnionType{{builtinTypes->falsyType, *expectedType}});
|
||||
|
||||
auto [leftType, leftRefinement] = check(scope, binary->left, relaxedExpectedLhs);
|
||||
auto [leftType, leftRefinement] = check(scope, left, relaxedExpectedLhs);
|
||||
|
||||
ScopePtr rightScope = childScope(binary->right, scope);
|
||||
applyRefinements(rightScope, binary->right->location, refinementArena.negation(leftRefinement));
|
||||
auto [rightType, rightRefinement] = check(rightScope, binary->right, expectedType);
|
||||
ScopePtr rightScope = childScope(right, scope);
|
||||
applyRefinements(rightScope, right->location, refinementArena.negation(leftRefinement));
|
||||
auto [rightType, rightRefinement] = check(rightScope, right, expectedType);
|
||||
|
||||
return {leftType, rightType, refinementArena.disjunction(leftRefinement, rightRefinement)};
|
||||
}
|
||||
else if (auto typeguard = matchTypeGuard(binary))
|
||||
else if (auto typeguard = matchTypeGuard(op, left, right))
|
||||
{
|
||||
TypeId leftType = check(scope, binary->left).ty;
|
||||
TypeId rightType = check(scope, binary->right).ty;
|
||||
TypeId leftType = check(scope, left).ty;
|
||||
TypeId rightType = check(scope, right).ty;
|
||||
|
||||
const RefinementKey* key = dfg->getRefinementKey(typeguard->target);
|
||||
if (!key)
|
||||
|
@ -2665,24 +2676,24 @@ std::tuple<TypeId, TypeId, RefinementId> ConstraintGenerator::checkBinary(
|
|||
}
|
||||
|
||||
RefinementId proposition = refinementArena.proposition(key, discriminantTy);
|
||||
if (binary->op == AstExprBinary::CompareEq)
|
||||
if (op == AstExprBinary::CompareEq)
|
||||
return {leftType, rightType, proposition};
|
||||
else if (binary->op == AstExprBinary::CompareNe)
|
||||
else if (op == AstExprBinary::CompareNe)
|
||||
return {leftType, rightType, refinementArena.negation(proposition)};
|
||||
else
|
||||
ice->ice("matchTypeGuard should only return a Some under `==` or `~=`!");
|
||||
}
|
||||
else if (binary->op == AstExprBinary::CompareEq || binary->op == AstExprBinary::CompareNe)
|
||||
else if (op == AstExprBinary::CompareEq || op == AstExprBinary::CompareNe)
|
||||
{
|
||||
// We are checking a binary expression of the form a op b
|
||||
// Just because a op b is epxected to return a bool, doesn't mean a, b are expected to be bools too
|
||||
TypeId leftType = check(scope, binary->left, {}, true).ty;
|
||||
TypeId rightType = check(scope, binary->right, {}, true).ty;
|
||||
TypeId leftType = check(scope, left, {}, true).ty;
|
||||
TypeId rightType = check(scope, right, {}, true).ty;
|
||||
|
||||
RefinementId leftRefinement = refinementArena.proposition(dfg->getRefinementKey(binary->left), rightType);
|
||||
RefinementId rightRefinement = refinementArena.proposition(dfg->getRefinementKey(binary->right), leftType);
|
||||
RefinementId leftRefinement = refinementArena.proposition(dfg->getRefinementKey(left), rightType);
|
||||
RefinementId rightRefinement = refinementArena.proposition(dfg->getRefinementKey(right), leftType);
|
||||
|
||||
if (binary->op == AstExprBinary::CompareNe)
|
||||
if (op == AstExprBinary::CompareNe)
|
||||
{
|
||||
leftRefinement = refinementArena.negation(leftRefinement);
|
||||
rightRefinement = refinementArena.negation(rightRefinement);
|
||||
|
@ -2692,8 +2703,8 @@ std::tuple<TypeId, TypeId, RefinementId> ConstraintGenerator::checkBinary(
|
|||
}
|
||||
else
|
||||
{
|
||||
TypeId leftType = check(scope, binary->left).ty;
|
||||
TypeId rightType = check(scope, binary->right).ty;
|
||||
TypeId leftType = check(scope, left).ty;
|
||||
TypeId rightType = check(scope, right).ty;
|
||||
return {leftType, rightType, nullptr};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ LUAU_FASTINTVARIABLE(LuauSolverRecursionLimit, 500)
|
|||
LUAU_FASTFLAGVARIABLE(LuauRemoveNotAnyHack)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauNewSolverPopulateTableLocations)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAllowNilAssignmentToIndexer)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -1501,7 +1502,8 @@ bool ConstraintSolver::tryDispatch(const HasPropConstraint& c, NotNull<const Con
|
|||
}
|
||||
}
|
||||
|
||||
auto [blocked, result] = lookupTableProp(constraint, subjectType, c.prop, c.context, c.inConditional, c.suppressSimplification);
|
||||
// It doesn't matter whether this type came from an indexer or not.
|
||||
auto [blocked, result, _isIndex] = lookupTableProp(constraint, subjectType, c.prop, c.context, c.inConditional, c.suppressSimplification);
|
||||
if (!blocked.empty())
|
||||
{
|
||||
for (TypeId blocked : blocked)
|
||||
|
@ -1783,7 +1785,7 @@ bool ConstraintSolver::tryDispatch(const AssignPropConstraint& c, NotNull<const
|
|||
|
||||
// Handle the case that lhsType is a table that already has the property or
|
||||
// a matching indexer. This also handles unions and intersections.
|
||||
const auto [blocked, maybeTy] = lookupTableProp(constraint, lhsType, propName, ValueContext::LValue);
|
||||
const auto [blocked, maybeTy, isIndex] = lookupTableProp(constraint, lhsType, propName, ValueContext::LValue);
|
||||
if (!blocked.empty())
|
||||
{
|
||||
for (TypeId t : blocked)
|
||||
|
@ -1793,8 +1795,12 @@ bool ConstraintSolver::tryDispatch(const AssignPropConstraint& c, NotNull<const
|
|||
|
||||
if (maybeTy)
|
||||
{
|
||||
const TypeId propTy = *maybeTy;
|
||||
bind(constraint, c.propType, propTy);
|
||||
TypeId propTy = *maybeTy;
|
||||
bind(
|
||||
constraint,
|
||||
c.propType,
|
||||
isIndex && FFlag::LuauAllowNilAssignmentToIndexer ? arena->addType(UnionType{{propTy, builtinTypes->nilType}}) : propTy
|
||||
);
|
||||
unify(constraint, rhsType, propTy);
|
||||
return true;
|
||||
}
|
||||
|
@ -1888,7 +1894,12 @@ bool ConstraintSolver::tryDispatch(const AssignIndexConstraint& c, NotNull<const
|
|||
{
|
||||
unify(constraint, indexType, lhsTable->indexer->indexType);
|
||||
unify(constraint, rhsType, lhsTable->indexer->indexResultType);
|
||||
bind(constraint, c.propType, lhsTable->indexer->indexResultType);
|
||||
bind(
|
||||
constraint,
|
||||
c.propType,
|
||||
FFlag::LuauAllowNilAssignmentToIndexer ? arena->addType(UnionType{{lhsTable->indexer->indexResultType, builtinTypes->nilType}})
|
||||
: lhsTable->indexer->indexResultType
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1937,7 +1948,12 @@ bool ConstraintSolver::tryDispatch(const AssignIndexConstraint& c, NotNull<const
|
|||
{
|
||||
unify(constraint, indexType, lhsClass->indexer->indexType);
|
||||
unify(constraint, rhsType, lhsClass->indexer->indexResultType);
|
||||
bind(constraint, c.propType, lhsClass->indexer->indexResultType);
|
||||
bind(
|
||||
constraint,
|
||||
c.propType,
|
||||
FFlag::LuauAllowNilAssignmentToIndexer ? arena->addType(UnionType{{lhsClass->indexer->indexResultType, builtinTypes->nilType}})
|
||||
: lhsClass->indexer->indexResultType
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2360,7 +2376,7 @@ NotNull<const Constraint> ConstraintSolver::unpackAndAssign(
|
|||
return c;
|
||||
}
|
||||
|
||||
std::pair<std::vector<TypeId>, std::optional<TypeId>> ConstraintSolver::lookupTableProp(
|
||||
TablePropLookupResult ConstraintSolver::lookupTableProp(
|
||||
NotNull<const Constraint> constraint,
|
||||
TypeId subjectType,
|
||||
const std::string& propName,
|
||||
|
@ -2373,7 +2389,7 @@ std::pair<std::vector<TypeId>, std::optional<TypeId>> ConstraintSolver::lookupTa
|
|||
return lookupTableProp(constraint, subjectType, propName, context, inConditional, suppressSimplification, seen);
|
||||
}
|
||||
|
||||
std::pair<std::vector<TypeId>, std::optional<TypeId>> ConstraintSolver::lookupTableProp(
|
||||
TablePropLookupResult ConstraintSolver::lookupTableProp(
|
||||
NotNull<const Constraint> constraint,
|
||||
TypeId subjectType,
|
||||
const std::string& propName,
|
||||
|
@ -2413,7 +2429,7 @@ std::pair<std::vector<TypeId>, std::optional<TypeId>> ConstraintSolver::lookupTa
|
|||
}
|
||||
|
||||
if (ttv->indexer && maybeString(ttv->indexer->indexType))
|
||||
return {{}, ttv->indexer->indexResultType};
|
||||
return {{}, ttv->indexer->indexResultType, /* isIndex = */ true};
|
||||
|
||||
if (ttv->state == TableState::Free)
|
||||
{
|
||||
|
@ -2455,9 +2471,9 @@ std::pair<std::vector<TypeId>, std::optional<TypeId>> ConstraintSolver::lookupTa
|
|||
}
|
||||
else if (auto mt = get<MetatableType>(subjectType); mt && context == ValueContext::RValue)
|
||||
{
|
||||
auto [blocked, result] = lookupTableProp(constraint, mt->table, propName, context, inConditional, suppressSimplification, seen);
|
||||
if (!blocked.empty() || result)
|
||||
return {blocked, result};
|
||||
auto result = lookupTableProp(constraint, mt->table, propName, context, inConditional, suppressSimplification, seen);
|
||||
if (!result.blockedTypes.empty() || result.propType)
|
||||
return result;
|
||||
|
||||
TypeId mtt = follow(mt->metatable);
|
||||
|
||||
|
@ -2467,7 +2483,7 @@ std::pair<std::vector<TypeId>, std::optional<TypeId>> ConstraintSolver::lookupTa
|
|||
{
|
||||
auto indexProp = metatable->props.find("__index");
|
||||
if (indexProp == metatable->props.end())
|
||||
return {{}, result};
|
||||
return {{}, result.propType};
|
||||
|
||||
// TODO: __index can be an overloaded function.
|
||||
|
||||
|
@ -2497,7 +2513,7 @@ std::pair<std::vector<TypeId>, std::optional<TypeId>> ConstraintSolver::lookupTa
|
|||
return {{}, context == ValueContext::RValue ? p->readTy : p->writeTy};
|
||||
if (ct->indexer)
|
||||
{
|
||||
return {{}, ct->indexer->indexResultType};
|
||||
return {{}, ct->indexer->indexResultType, /* isIndex = */ true};
|
||||
}
|
||||
}
|
||||
else if (auto pt = get<PrimitiveType>(subjectType); pt && pt->metatable)
|
||||
|
@ -2548,10 +2564,10 @@ std::pair<std::vector<TypeId>, std::optional<TypeId>> ConstraintSolver::lookupTa
|
|||
|
||||
for (TypeId ty : utv)
|
||||
{
|
||||
auto [innerBlocked, innerResult] = lookupTableProp(constraint, ty, propName, context, inConditional, suppressSimplification, seen);
|
||||
blocked.insert(blocked.end(), innerBlocked.begin(), innerBlocked.end());
|
||||
if (innerResult)
|
||||
options.insert(*innerResult);
|
||||
auto result = lookupTableProp(constraint, ty, propName, context, inConditional, suppressSimplification, seen);
|
||||
blocked.insert(blocked.end(), result.blockedTypes.begin(), result.blockedTypes.end());
|
||||
if (result.propType)
|
||||
options.insert(*result.propType);
|
||||
}
|
||||
|
||||
if (!blocked.empty())
|
||||
|
@ -2585,10 +2601,10 @@ std::pair<std::vector<TypeId>, std::optional<TypeId>> ConstraintSolver::lookupTa
|
|||
|
||||
for (TypeId ty : itv)
|
||||
{
|
||||
auto [innerBlocked, innerResult] = lookupTableProp(constraint, ty, propName, context, inConditional, suppressSimplification, seen);
|
||||
blocked.insert(blocked.end(), innerBlocked.begin(), innerBlocked.end());
|
||||
if (innerResult)
|
||||
options.insert(*innerResult);
|
||||
auto result = lookupTableProp(constraint, ty, propName, context, inConditional, suppressSimplification, seen);
|
||||
blocked.insert(blocked.end(), result.blockedTypes.begin(), result.blockedTypes.end());
|
||||
if (result.propType)
|
||||
options.insert(*result.propType);
|
||||
}
|
||||
|
||||
if (!blocked.empty())
|
||||
|
@ -2920,7 +2936,7 @@ TypeId ConstraintSolver::resolveModule(const ModuleInfo& info, const Location& l
|
|||
}
|
||||
|
||||
TypePackId modulePack = module->returnType;
|
||||
if (get<Unifiable::Error>(modulePack))
|
||||
if (get<ErrorTypePack>(modulePack))
|
||||
return errorRecoveryType();
|
||||
|
||||
std::optional<TypeId> moduleType = first(modulePack);
|
||||
|
|
|
@ -184,7 +184,7 @@ DataFlowGraph DataFlowGraphBuilder::build(AstStatBlock* block, NotNull<InternalE
|
|||
|
||||
DataFlowGraphBuilder builder;
|
||||
builder.handle = handle;
|
||||
DfgScope* moduleScope = builder.makeChildScope(block->location);
|
||||
DfgScope* moduleScope = builder.makeChildScope();
|
||||
PushScope ps{builder.scopeStack, moduleScope};
|
||||
builder.visitBlockWithoutChildScope(block);
|
||||
builder.resolveCaptures();
|
||||
|
@ -208,7 +208,7 @@ std::pair<std::shared_ptr<DataFlowGraph>, std::vector<std::unique_ptr<DfgScope>>
|
|||
|
||||
DataFlowGraphBuilder builder;
|
||||
builder.handle = handle;
|
||||
DfgScope* moduleScope = builder.makeChildScope(block->location);
|
||||
DfgScope* moduleScope = builder.makeChildScope();
|
||||
PushScope ps{builder.scopeStack, moduleScope};
|
||||
builder.visitBlockWithoutChildScope(block);
|
||||
builder.resolveCaptures();
|
||||
|
@ -247,9 +247,9 @@ DfgScope* DataFlowGraphBuilder::currentScope()
|
|||
return scopeStack.back();
|
||||
}
|
||||
|
||||
DfgScope* DataFlowGraphBuilder::makeChildScope(Location loc, DfgScope::ScopeType scopeType)
|
||||
DfgScope* DataFlowGraphBuilder::makeChildScope(DfgScope::ScopeType scopeType)
|
||||
{
|
||||
return scopes.emplace_back(new DfgScope{currentScope(), scopeType, loc}).get();
|
||||
return scopes.emplace_back(new DfgScope{currentScope(), scopeType}).get();
|
||||
}
|
||||
|
||||
void DataFlowGraphBuilder::join(DfgScope* p, DfgScope* a, DfgScope* b)
|
||||
|
@ -397,7 +397,7 @@ DefId DataFlowGraphBuilder::lookup(DefId def, const std::string& key)
|
|||
|
||||
ControlFlow DataFlowGraphBuilder::visit(AstStatBlock* b)
|
||||
{
|
||||
DfgScope* child = makeChildScope(b->location);
|
||||
DfgScope* child = makeChildScope();
|
||||
|
||||
ControlFlow cf;
|
||||
{
|
||||
|
@ -474,8 +474,8 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatIf* i)
|
|||
{
|
||||
visitExpr(i->condition);
|
||||
|
||||
DfgScope* thenScope = makeChildScope(i->thenbody->location);
|
||||
DfgScope* elseScope = makeChildScope(i->elsebody ? i->elsebody->location : i->location);
|
||||
DfgScope* thenScope = makeChildScope();
|
||||
DfgScope* elseScope = makeChildScope();
|
||||
|
||||
ControlFlow thencf;
|
||||
{
|
||||
|
@ -509,7 +509,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatIf* i)
|
|||
ControlFlow DataFlowGraphBuilder::visit(AstStatWhile* w)
|
||||
{
|
||||
// TODO(controlflow): entry point has a back edge from exit point
|
||||
DfgScope* whileScope = makeChildScope(w->location, DfgScope::Loop);
|
||||
DfgScope* whileScope = makeChildScope(DfgScope::Loop);
|
||||
|
||||
{
|
||||
PushScope ps{scopeStack, whileScope};
|
||||
|
@ -525,7 +525,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatWhile* w)
|
|||
ControlFlow DataFlowGraphBuilder::visit(AstStatRepeat* r)
|
||||
{
|
||||
// TODO(controlflow): entry point has a back edge from exit point
|
||||
DfgScope* repeatScope = makeChildScope(r->location, DfgScope::Loop);
|
||||
DfgScope* repeatScope = makeChildScope(DfgScope::Loop);
|
||||
|
||||
{
|
||||
PushScope ps{scopeStack, repeatScope};
|
||||
|
@ -601,7 +601,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatLocal* l)
|
|||
|
||||
ControlFlow DataFlowGraphBuilder::visit(AstStatFor* f)
|
||||
{
|
||||
DfgScope* forScope = makeChildScope(f->location, DfgScope::Loop);
|
||||
DfgScope* forScope = makeChildScope(DfgScope::Loop);
|
||||
|
||||
visitExpr(f->from);
|
||||
visitExpr(f->to);
|
||||
|
@ -630,7 +630,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatFor* f)
|
|||
|
||||
ControlFlow DataFlowGraphBuilder::visit(AstStatForIn* f)
|
||||
{
|
||||
DfgScope* forScope = makeChildScope(f->location, DfgScope::Loop);
|
||||
DfgScope* forScope = makeChildScope(DfgScope::Loop);
|
||||
|
||||
{
|
||||
PushScope ps{scopeStack, forScope};
|
||||
|
@ -726,7 +726,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatLocalFunction* l)
|
|||
|
||||
ControlFlow DataFlowGraphBuilder::visit(AstStatTypeAlias* t)
|
||||
{
|
||||
DfgScope* unreachable = makeChildScope(t->location);
|
||||
DfgScope* unreachable = makeChildScope();
|
||||
PushScope ps{scopeStack, unreachable};
|
||||
|
||||
visitGenerics(t->generics);
|
||||
|
@ -738,7 +738,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatTypeAlias* t)
|
|||
|
||||
ControlFlow DataFlowGraphBuilder::visit(AstStatTypeFunction* f)
|
||||
{
|
||||
DfgScope* unreachable = makeChildScope(f->location);
|
||||
DfgScope* unreachable = makeChildScope();
|
||||
PushScope ps{scopeStack, unreachable};
|
||||
|
||||
visitExpr(f->body);
|
||||
|
@ -765,7 +765,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatDeclareFunction* d)
|
|||
currentScope()->bindings[d->name] = def;
|
||||
captures[d->name].allVersions.push_back(def);
|
||||
|
||||
DfgScope* unreachable = makeChildScope(d->location);
|
||||
DfgScope* unreachable = makeChildScope();
|
||||
PushScope ps{scopeStack, unreachable};
|
||||
|
||||
visitGenerics(d->generics);
|
||||
|
@ -781,7 +781,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatDeclareClass* d)
|
|||
// This declaration does not "introduce" any bindings in value namespace,
|
||||
// so there's no symbolic value to begin with. We'll traverse the properties
|
||||
// because their type annotations may depend on something in the value namespace.
|
||||
DfgScope* unreachable = makeChildScope(d->location);
|
||||
DfgScope* unreachable = makeChildScope();
|
||||
PushScope ps{scopeStack, unreachable};
|
||||
|
||||
for (AstDeclaredClassProp prop : d->props)
|
||||
|
@ -792,7 +792,7 @@ ControlFlow DataFlowGraphBuilder::visit(AstStatDeclareClass* d)
|
|||
|
||||
ControlFlow DataFlowGraphBuilder::visit(AstStatError* error)
|
||||
{
|
||||
DfgScope* unreachable = makeChildScope(error->location);
|
||||
DfgScope* unreachable = makeChildScope();
|
||||
PushScope ps{scopeStack, unreachable};
|
||||
|
||||
for (AstStat* s : error->statements)
|
||||
|
@ -904,10 +904,7 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprCall* c)
|
|||
|
||||
LUAU_ASSERT(result);
|
||||
|
||||
Location location = currentScope()->location;
|
||||
// This scope starts at the end of the call site and continues to the end of the original scope.
|
||||
location.begin = c->location.end;
|
||||
DfgScope* child = makeChildScope(location);
|
||||
DfgScope* child = makeChildScope();
|
||||
scopeStack.push_back(child);
|
||||
|
||||
auto [def, key] = *result;
|
||||
|
@ -952,7 +949,7 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprIndexExpr* i)
|
|||
|
||||
DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprFunction* f)
|
||||
{
|
||||
DfgScope* signatureScope = makeChildScope(f->location, DfgScope::Function);
|
||||
DfgScope* signatureScope = makeChildScope(DfgScope::Function);
|
||||
PushScope ps{scopeStack, signatureScope};
|
||||
|
||||
if (AstLocal* self = f->self)
|
||||
|
@ -1056,7 +1053,7 @@ DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprInterpString* i)
|
|||
|
||||
DataFlowResult DataFlowGraphBuilder::visitExpr(AstExprError* error)
|
||||
{
|
||||
DfgScope* unreachable = makeChildScope(error->location);
|
||||
DfgScope* unreachable = makeChildScope();
|
||||
PushScope ps{scopeStack, unreachable};
|
||||
|
||||
for (AstExpr* e : error->expressions)
|
||||
|
|
|
@ -719,7 +719,7 @@ static DifferResult diffUsingEnv(DifferEnvironment& env, TypeId left, TypeId rig
|
|||
env.popVisiting();
|
||||
return diffRes;
|
||||
}
|
||||
if (auto le = get<Luau::Unifiable::Error>(left))
|
||||
if (auto le = get<ErrorType>(left))
|
||||
{
|
||||
// TODO: return debug-friendly result state
|
||||
env.popVisiting();
|
||||
|
|
|
@ -27,7 +27,6 @@ LUAU_FASTINT(LuauTypeInferRecursionLimit);
|
|||
LUAU_FASTINT(LuauTypeInferIterationLimit);
|
||||
LUAU_FASTINT(LuauTarjanChildLimit)
|
||||
LUAU_FASTFLAG(LuauAllowFragmentParsing);
|
||||
LUAU_FASTFLAG(LuauStoreDFGOnModule2);
|
||||
LUAU_FASTFLAG(LuauAutocompleteRefactorsForIncrementalAutocomplete)
|
||||
|
||||
namespace
|
||||
|
@ -89,6 +88,25 @@ FragmentAutocompleteAncestryResult findAncestryForFragmentParse(AstStatBlock* ro
|
|||
{
|
||||
localStack.push_back(locFun->name);
|
||||
localMap[locFun->name->name] = locFun->name;
|
||||
if (locFun->location.contains(cursorPos))
|
||||
{
|
||||
for (AstLocal* loc : locFun->func->args)
|
||||
{
|
||||
localStack.push_back(loc);
|
||||
localMap[loc->name] = loc;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto globFun = stat->as<AstStatFunction>())
|
||||
{
|
||||
if (globFun->location.contains(cursorPos))
|
||||
{
|
||||
for (AstLocal* loc : globFun->func->args)
|
||||
{
|
||||
localStack.push_back(loc);
|
||||
localMap[loc->name] = loc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -234,9 +252,9 @@ FragmentParseResult parseFragment(
|
|||
// If we added to the end of the sourceModule, use the end of the nearest location
|
||||
if (appended && multiline)
|
||||
startPos = nearestStatement->location.end;
|
||||
// Statement spans one line && cursorPos is on a different line
|
||||
else if (!multiline && cursorPos.line != nearestStatement->location.end.line)
|
||||
startPos = nearestStatement->location.end;
|
||||
// Statement spans one line && cursorPos is either on the same line or after
|
||||
else if (!multiline && cursorPos.line >= nearestStatement->location.end.line)
|
||||
startPos = nearestStatement->location.begin;
|
||||
else if (multiline && nearestStatement->location.end.line < cursorPos.line)
|
||||
startPos = nearestStatement->location.end;
|
||||
else
|
||||
|
@ -300,6 +318,7 @@ struct MixedModeIncrementalTCDefFinder : public AstVisitor
|
|||
referencedLocalDefs.push_back({local->local, local});
|
||||
return true;
|
||||
}
|
||||
|
||||
// ast defs is just a mapping from expr -> def in general
|
||||
// will get built up by the dfg builder
|
||||
|
||||
|
@ -495,7 +514,6 @@ FragmentAutocompleteResult fragmentAutocomplete(
|
|||
)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauAllowFragmentParsing);
|
||||
LUAU_ASSERT(FFlag::LuauStoreDFGOnModule2);
|
||||
LUAU_ASSERT(FFlag::LuauAutocompleteRefactorsForIncrementalAutocomplete);
|
||||
|
||||
const SourceModule* sourceModule = frontend.getSourceModule(moduleName);
|
||||
|
|
|
@ -45,11 +45,9 @@ LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJsonFile)
|
|||
LUAU_FASTFLAGVARIABLE(DebugLuauForbidInternalTypes)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForceStrictMode)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForceNonStrictMode)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctionNoEvaluation)
|
||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(LuauRunCustomModuleChecks, false)
|
||||
|
||||
LUAU_FASTFLAG(StudioReportLuauAny2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStoreDFGOnModule2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStoreSolverTypeOnModule)
|
||||
|
||||
namespace Luau
|
||||
|
@ -1307,19 +1305,7 @@ ModulePtr check(
|
|||
}
|
||||
}
|
||||
|
||||
DataFlowGraph oldDfg = DataFlowGraphBuilder::build(sourceModule.root, iceHandler);
|
||||
DataFlowGraph* dfgForConstraintGeneration = nullptr;
|
||||
if (FFlag::LuauStoreDFGOnModule2)
|
||||
{
|
||||
auto [dfg, scopes] = DataFlowGraphBuilder::buildShared(sourceModule.root, iceHandler);
|
||||
result->dataFlowGraph = std::move(dfg);
|
||||
result->dfgScopes = std::move(scopes);
|
||||
dfgForConstraintGeneration = result->dataFlowGraph.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
dfgForConstraintGeneration = &oldDfg;
|
||||
}
|
||||
DataFlowGraph dfg = DataFlowGraphBuilder::build(sourceModule.root, iceHandler);
|
||||
|
||||
UnifierSharedState unifierState{iceHandler};
|
||||
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
|
||||
|
@ -1329,8 +1315,7 @@ ModulePtr check(
|
|||
SimplifierPtr simplifier = newSimplifier(NotNull{&result->internalTypes}, builtinTypes);
|
||||
TypeFunctionRuntime typeFunctionRuntime{iceHandler, NotNull{&limits}};
|
||||
|
||||
if (FFlag::LuauUserDefinedTypeFunctionNoEvaluation)
|
||||
typeFunctionRuntime.allowEvaluation = sourceModule.parseErrors.empty();
|
||||
typeFunctionRuntime.allowEvaluation = sourceModule.parseErrors.empty();
|
||||
|
||||
ConstraintGenerator cg{
|
||||
result,
|
||||
|
@ -1343,7 +1328,7 @@ ModulePtr check(
|
|||
parentScope,
|
||||
std::move(prepareModuleScope),
|
||||
logger.get(),
|
||||
NotNull{dfgForConstraintGeneration},
|
||||
NotNull{&dfg},
|
||||
requireCycles
|
||||
};
|
||||
|
||||
|
@ -1360,7 +1345,7 @@ ModulePtr check(
|
|||
moduleResolver,
|
||||
requireCycles,
|
||||
logger.get(),
|
||||
NotNull{dfgForConstraintGeneration},
|
||||
NotNull{&dfg},
|
||||
limits
|
||||
};
|
||||
|
||||
|
@ -1414,32 +1399,16 @@ ModulePtr check(
|
|||
switch (mode)
|
||||
{
|
||||
case Mode::Nonstrict:
|
||||
if (FFlag::LuauStoreDFGOnModule2)
|
||||
{
|
||||
Luau::checkNonStrict(
|
||||
builtinTypes,
|
||||
NotNull{&typeFunctionRuntime},
|
||||
iceHandler,
|
||||
NotNull{&unifierState},
|
||||
NotNull{dfgForConstraintGeneration},
|
||||
NotNull{&limits},
|
||||
sourceModule,
|
||||
result.get()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
Luau::checkNonStrict(
|
||||
builtinTypes,
|
||||
NotNull{&typeFunctionRuntime},
|
||||
iceHandler,
|
||||
NotNull{&unifierState},
|
||||
NotNull{&oldDfg},
|
||||
NotNull{&limits},
|
||||
sourceModule,
|
||||
result.get()
|
||||
);
|
||||
}
|
||||
Luau::checkNonStrict(
|
||||
builtinTypes,
|
||||
NotNull{&typeFunctionRuntime},
|
||||
iceHandler,
|
||||
NotNull{&unifierState},
|
||||
NotNull{&dfg},
|
||||
NotNull{&limits},
|
||||
sourceModule,
|
||||
result.get()
|
||||
);
|
||||
break;
|
||||
case Mode::Definition:
|
||||
// fallthrough intentional
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "Luau/TypePack.h"
|
||||
#include "Luau/VisitType.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauAutocompleteRefactorsForIncrementalAutocomplete)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -445,7 +447,7 @@ struct FreeTypeSearcher : TypeVisitor
|
|||
traverse(*prop.readTy);
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(prop.isShared());
|
||||
LUAU_ASSERT(prop.isShared() || FFlag::LuauAutocompleteRefactorsForIncrementalAutocomplete);
|
||||
|
||||
Polarity p = polarity;
|
||||
polarity = Both;
|
||||
|
@ -894,7 +896,7 @@ struct TypeCacher : TypeOnceVisitor
|
|||
return true;
|
||||
}
|
||||
|
||||
bool visit(TypePackId tp, const Unifiable::Error& etp) override
|
||||
bool visit(TypePackId tp, const ErrorTypePack& etp) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ LUAU_FASTINTVARIABLE(LuauSuggestionDistance, 4)
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
|
||||
LUAU_FASTFLAG(LuauAttribute)
|
||||
LUAU_FASTFLAG(LuauNativeAttribute)
|
||||
LUAU_FASTFLAGVARIABLE(LintRedundantNativeAttribute)
|
||||
|
||||
namespace Luau
|
||||
|
@ -3239,7 +3238,6 @@ static void lintComments(LintContext& context, const std::vector<HotComment>& ho
|
|||
|
||||
static bool hasNativeCommentDirective(const std::vector<HotComment>& hotcomments)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauNativeAttribute);
|
||||
LUAU_ASSERT(FFlag::LintRedundantNativeAttribute);
|
||||
|
||||
for (const HotComment& hc : hotcomments)
|
||||
|
@ -3265,7 +3263,6 @@ struct LintRedundantNativeAttribute : AstVisitor
|
|||
public:
|
||||
LUAU_NOINLINE static void process(LintContext& context)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauNativeAttribute);
|
||||
LUAU_ASSERT(FFlag::LintRedundantNativeAttribute);
|
||||
|
||||
LintRedundantNativeAttribute pass;
|
||||
|
@ -3389,7 +3386,7 @@ std::vector<LintWarning> lint(
|
|||
if (context.warningEnabled(LintWarning::Code_ComparisonPrecedence))
|
||||
LintComparisonPrecedence::process(context);
|
||||
|
||||
if (FFlag::LuauNativeAttribute && FFlag::LintRedundantNativeAttribute && context.warningEnabled(LintWarning::Code_RedundantNativeAttribute))
|
||||
if (FFlag::LintRedundantNativeAttribute && context.warningEnabled(LintWarning::Code_RedundantNativeAttribute))
|
||||
{
|
||||
if (hasNativeCommentDirective(hotcomments))
|
||||
LintRedundantNativeAttribute::process(context);
|
||||
|
|
|
@ -218,7 +218,7 @@ struct NonStrictTypeChecker
|
|||
|
||||
return result;
|
||||
}
|
||||
else if (get<Unifiable::Error>(pack))
|
||||
else if (get<ErrorTypePack>(pack))
|
||||
return builtinTypes->errorRecoveryType();
|
||||
else if (finite(pack) && size(pack) == 0)
|
||||
return builtinTypes->nilType; // `(f())` where `f()` returns no values is coerced into `nil`
|
||||
|
|
|
@ -417,8 +417,8 @@ std::optional<TypeId> selectOverload(
|
|||
TypePackId argsPack
|
||||
)
|
||||
{
|
||||
OverloadResolver resolver{builtinTypes, arena, normalizer, typeFunctionRuntime, scope, iceReporter, limits, location};
|
||||
auto [status, overload] = resolver.selectOverload(fn, argsPack);
|
||||
auto resolver = std::make_unique<OverloadResolver>(builtinTypes, arena, normalizer, typeFunctionRuntime, scope, iceReporter, limits, location);
|
||||
auto [status, overload] = resolver->selectOverload(fn, argsPack);
|
||||
|
||||
if (status == OverloadResolver::Analysis::Ok)
|
||||
return overload;
|
||||
|
@ -456,9 +456,9 @@ SolveResult solveFunctionCall(
|
|||
|
||||
if (!u2.genericSubstitutions.empty() || !u2.genericPackSubstitutions.empty())
|
||||
{
|
||||
Instantiation2 instantiation{arena, std::move(u2.genericSubstitutions), std::move(u2.genericPackSubstitutions)};
|
||||
auto instantiation = std::make_unique<Instantiation2>(arena, std::move(u2.genericSubstitutions), std::move(u2.genericPackSubstitutions));
|
||||
|
||||
std::optional<TypePackId> subst = instantiation.substitute(resultPack);
|
||||
std::optional<TypePackId> subst = instantiation->substitute(resultPack);
|
||||
|
||||
if (!subst)
|
||||
return {SolveResult::CodeTooComplex};
|
||||
|
|
|
@ -4,13 +4,15 @@
|
|||
#include "Luau/Common.h"
|
||||
#include "Luau/Clone.h"
|
||||
#include "Luau/TxnLog.h"
|
||||
#include "Luau/Type.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdexcept>
|
||||
|
||||
LUAU_FASTINTVARIABLE(LuauTarjanChildLimit, 10000)
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTINTVARIABLE(LuauTarjanPreallocationSize, 256);
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTINTVARIABLE(LuauTarjanPreallocationSize, 256)
|
||||
LUAU_FASTFLAG(LuauSyntheticErrors)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -57,8 +59,25 @@ static TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool a
|
|||
}
|
||||
else if constexpr (std::is_same_v<T, ErrorType>)
|
||||
{
|
||||
LUAU_ASSERT(ty->persistent);
|
||||
return ty;
|
||||
if (FFlag::LuauSyntheticErrors)
|
||||
{
|
||||
LUAU_ASSERT(ty->persistent || a.synthetic);
|
||||
|
||||
if (ty->persistent)
|
||||
return ty;
|
||||
|
||||
// While this code intentionally works (and clones) even if `a.synthetic` is `std::nullopt`,
|
||||
// we still assert above because we consider it a bug to have a non-persistent error type
|
||||
// without any associated metadata. We should always use the persistent version in such cases.
|
||||
ErrorType clone = ErrorType{};
|
||||
clone.synthetic = a.synthetic;
|
||||
return dest.addType(clone);
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(ty->persistent);
|
||||
return ty;
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, UnknownType>)
|
||||
{
|
||||
|
|
|
@ -420,7 +420,7 @@ void StateDot::visitChildren(TypePackId tp, int index)
|
|||
finishNodeLabel(tp);
|
||||
finishNode();
|
||||
}
|
||||
else if (get<Unifiable::Error>(tp))
|
||||
else if (get<ErrorTypePack>(tp))
|
||||
{
|
||||
formatAppend(result, "ErrorTypePack %d", index);
|
||||
finishNodeLabel(tp);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <string>
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSyntheticErrors)
|
||||
|
||||
/*
|
||||
* Enables increasing levels of verbosity for Luau type names when stringifying.
|
||||
|
@ -998,7 +999,15 @@ struct TypeStringifier
|
|||
void operator()(TypeId, const ErrorType& tv)
|
||||
{
|
||||
state.result.error = true;
|
||||
state.emit("*error-type*");
|
||||
|
||||
if (FFlag::LuauSyntheticErrors && tv.synthetic)
|
||||
{
|
||||
state.emit("*error-type<");
|
||||
stringify(*tv.synthetic);
|
||||
state.emit(">*");
|
||||
}
|
||||
else
|
||||
state.emit("*error-type*");
|
||||
}
|
||||
|
||||
void operator()(TypeId, const LazyType& ltv)
|
||||
|
@ -1173,10 +1182,18 @@ struct TypePackStringifier
|
|||
state.unsee(&tp);
|
||||
}
|
||||
|
||||
void operator()(TypePackId, const Unifiable::Error& error)
|
||||
void operator()(TypePackId, const ErrorTypePack& error)
|
||||
{
|
||||
state.result.error = true;
|
||||
state.emit("*error-type*");
|
||||
|
||||
if (FFlag::LuauSyntheticErrors && error.synthetic)
|
||||
{
|
||||
state.emit("*");
|
||||
stringify(*error.synthetic);
|
||||
state.emit("*");
|
||||
}
|
||||
else
|
||||
state.emit("*error-type*");
|
||||
}
|
||||
|
||||
void operator()(TypePackId, const VariadicTypePack& pack)
|
||||
|
|
|
@ -1045,7 +1045,7 @@ BuiltinTypes::BuiltinTypes()
|
|||
, unknownTypePack(arena->addTypePack(TypePackVar{VariadicTypePack{unknownType}, /*persistent*/ true}))
|
||||
, neverTypePack(arena->addTypePack(TypePackVar{VariadicTypePack{neverType}, /*persistent*/ true}))
|
||||
, uninhabitableTypePack(arena->addTypePack(TypePackVar{TypePack{{neverType}, neverTypePack}, /*persistent*/ true}))
|
||||
, errorTypePack(arena->addTypePack(TypePackVar{Unifiable::Error{}, /*persistent*/ true}))
|
||||
, errorTypePack(arena->addTypePack(TypePackVar{ErrorTypePack{}, /*persistent*/ true}))
|
||||
{
|
||||
freeze(*arena);
|
||||
}
|
||||
|
|
|
@ -329,7 +329,7 @@ public:
|
|||
Location(), generics, genericPacks, AstTypeList{argTypes, argTailAnnotation}, argNames, AstTypeList{returnTypes, retTailAnnotation}
|
||||
);
|
||||
}
|
||||
AstType* operator()(const Unifiable::Error&)
|
||||
AstType* operator()(const ErrorType&)
|
||||
{
|
||||
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("Unifiable<Error>"), std::nullopt, Location());
|
||||
}
|
||||
|
@ -458,7 +458,7 @@ public:
|
|||
return allocator->alloc<AstTypePackGeneric>(Location(), AstName("free"));
|
||||
}
|
||||
|
||||
AstTypePack* operator()(const Unifiable::Error&) const
|
||||
AstTypePack* operator()(const ErrorTypePack&) const
|
||||
{
|
||||
return allocator->alloc<AstTypePackGeneric>(Location(), AstName("Unifiable<Error>"));
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
#include <ostream>
|
||||
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctions2)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauTableKeysAreRValues)
|
||||
|
||||
|
@ -1200,8 +1199,6 @@ void TypeChecker2::visit(AstStatTypeAlias* stat)
|
|||
void TypeChecker2::visit(AstStatTypeFunction* stat)
|
||||
{
|
||||
// TODO: add type checking for user-defined type functions
|
||||
if (!FFlag::LuauUserDefinedTypeFunctions2)
|
||||
reportError(TypeError{stat->location, GenericError{"This syntax is not supported"}});
|
||||
}
|
||||
|
||||
void TypeChecker2::visit(AstTypeList types)
|
||||
|
@ -2353,7 +2350,7 @@ TypeId TypeChecker2::flattenPack(TypePackId pack)
|
|||
|
||||
return result;
|
||||
}
|
||||
else if (get<Unifiable::Error>(pack))
|
||||
else if (get<ErrorTypePack>(pack))
|
||||
return builtinTypes->errorRecoveryType();
|
||||
else if (finite(pack) && size(pack) == 0)
|
||||
return builtinTypes->nilType; // `(f())` where `f()` returns no values is coerced into `nil`
|
||||
|
|
|
@ -46,8 +46,6 @@ LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFamilyApplicationCartesianProductLimit, 5'0
|
|||
LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFamilyUseGuesserDepth, -1);
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogTypeFamilies)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctions2)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctionNoEvaluation)
|
||||
LUAU_FASTFLAG(LuauUserTypeFunFixRegister)
|
||||
LUAU_FASTFLAG(LuauRemoveNotAnyHack)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctionResetState)
|
||||
|
@ -634,12 +632,9 @@ TypeFunctionReductionResult<TypeId> userDefinedTypeFunction(
|
|||
}
|
||||
}
|
||||
|
||||
if (FFlag::LuauUserDefinedTypeFunctionNoEvaluation)
|
||||
{
|
||||
// If type functions cannot be evaluated because of errors in the code, we do not generate any additional ones
|
||||
if (!ctx->typeFunctionRuntime->allowEvaluation)
|
||||
return {ctx->builtins->errorRecoveryType(), false, {}, {}};
|
||||
}
|
||||
// If type functions cannot be evaluated because of errors in the code, we do not generate any additional ones
|
||||
if (!ctx->typeFunctionRuntime->allowEvaluation)
|
||||
return {ctx->builtins->errorRecoveryType(), false, {}, {}};
|
||||
|
||||
for (auto typeParam : typeParams)
|
||||
{
|
||||
|
@ -994,12 +989,9 @@ TypeFunctionRuntime::~TypeFunctionRuntime() {}
|
|||
|
||||
std::optional<std::string> TypeFunctionRuntime::registerFunction(AstStatTypeFunction* function)
|
||||
{
|
||||
if (FFlag::LuauUserDefinedTypeFunctionNoEvaluation)
|
||||
{
|
||||
// If evaluation is disabled, we do not generate additional error messages
|
||||
if (!allowEvaluation)
|
||||
return std::nullopt;
|
||||
}
|
||||
// If evaluation is disabled, we do not generate additional error messages
|
||||
if (!allowEvaluation)
|
||||
return std::nullopt;
|
||||
|
||||
prepareState();
|
||||
|
||||
|
|
|
@ -964,7 +964,7 @@ ControlFlow TypeChecker::check(const ScopePtr& scope, const AstStatAssign& assig
|
|||
else if (auto tail = valueIter.tail())
|
||||
{
|
||||
TypePackId tailPack = follow(*tail);
|
||||
if (get<Unifiable::Error>(tailPack))
|
||||
if (get<ErrorTypePack>(tailPack))
|
||||
right = errorRecoveryType(scope);
|
||||
else if (auto vtp = get<VariadicTypePack>(tailPack))
|
||||
right = vtp->ty;
|
||||
|
@ -1244,7 +1244,7 @@ ControlFlow TypeChecker::check(const ScopePtr& scope, const AstStatForIn& forin)
|
|||
iterTy = freshType(scope);
|
||||
unify(callRetPack, addTypePack({{iterTy}, freshTypePack(scope)}), scope, forin.location);
|
||||
}
|
||||
else if (get<Unifiable::Error>(callRetPack) || !first(callRetPack))
|
||||
else if (get<ErrorTypePack>(callRetPack) || !first(callRetPack))
|
||||
{
|
||||
for (TypeId var : varTypes)
|
||||
unify(errorRecoveryType(scope), var, scope, forin.location);
|
||||
|
@ -1972,7 +1972,7 @@ WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExp
|
|||
*asMutable(varargPack) = TypePack{{head}, tail};
|
||||
return WithPredicate{head};
|
||||
}
|
||||
if (get<ErrorType>(varargPack))
|
||||
if (get<ErrorTypePack>(varargPack))
|
||||
return WithPredicate{errorRecoveryType(scope)};
|
||||
else if (auto vtp = get<VariadicTypePack>(varargPack))
|
||||
return WithPredicate{vtp->ty};
|
||||
|
@ -2002,7 +2002,7 @@ WithPredicate<TypeId> TypeChecker::checkExpr(const ScopePtr& scope, const AstExp
|
|||
unify(pack, retPack, scope, expr.location);
|
||||
return {head, std::move(result.predicates)};
|
||||
}
|
||||
if (get<Unifiable::Error>(retPack))
|
||||
if (get<ErrorTypePack>(retPack))
|
||||
return {errorRecoveryType(scope), std::move(result.predicates)};
|
||||
else if (auto vtp = get<VariadicTypePack>(retPack))
|
||||
return {vtp->ty, std::move(result.predicates)};
|
||||
|
@ -4093,7 +4093,7 @@ void TypeChecker::checkArgumentList(
|
|||
if (argIter.tail())
|
||||
{
|
||||
TypePackId tail = *argIter.tail();
|
||||
if (state.log.getMutable<Unifiable::Error>(tail))
|
||||
if (state.log.getMutable<ErrorTypePack>(tail))
|
||||
{
|
||||
// Unify remaining parameters so we don't leave any free-types hanging around.
|
||||
while (paramIter != endIter)
|
||||
|
@ -4178,7 +4178,7 @@ void TypeChecker::checkArgumentList(
|
|||
}
|
||||
TypePackId tail = state.log.follow(*paramIter.tail());
|
||||
|
||||
if (state.log.getMutable<Unifiable::Error>(tail))
|
||||
if (state.log.getMutable<ErrorTypePack>(tail))
|
||||
{
|
||||
// Function is variadic. Ok.
|
||||
return;
|
||||
|
@ -4314,7 +4314,7 @@ WithPredicate<TypePackId> TypeChecker::checkExprPackHelper(const ScopePtr& scope
|
|||
WithPredicate<TypePackId> argListResult = checkExprList(scope, expr.location, expr.args, false, {}, expectedTypes);
|
||||
TypePackId argPack = argListResult.type;
|
||||
|
||||
if (get<Unifiable::Error>(argPack))
|
||||
if (get<ErrorTypePack>(argPack))
|
||||
return WithPredicate{errorRecoveryTypePack(scope)};
|
||||
|
||||
TypePack* args = nullptr;
|
||||
|
@ -4904,7 +4904,7 @@ TypeId TypeChecker::checkRequire(const ScopePtr& scope, const ModuleInfo& module
|
|||
|
||||
TypePackId modulePack = module->returnType;
|
||||
|
||||
if (get<Unifiable::Error>(modulePack))
|
||||
if (get<ErrorTypePack>(modulePack))
|
||||
return errorRecoveryType(scope);
|
||||
|
||||
std::optional<TypeId> moduleType = first(modulePack);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <algorithm>
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LuauAutocompleteRefactorsForIncrementalAutocomplete);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -331,7 +332,7 @@ TypePack extendTypePack(
|
|||
|
||||
return result;
|
||||
}
|
||||
else if (const Unifiable::Error* etp = getMutable<Unifiable::Error>(pack))
|
||||
else if (auto etp = getMutable<ErrorTypePack>(pack))
|
||||
{
|
||||
while (result.head.size() < length)
|
||||
result.head.push_back(builtinTypes->errorRecoveryType());
|
||||
|
@ -426,7 +427,7 @@ TypeId stripNil(NotNull<BuiltinTypes> builtinTypes, TypeArena& arena, TypeId ty)
|
|||
|
||||
ErrorSuppression shouldSuppressErrors(NotNull<Normalizer> normalizer, TypeId ty)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauSolverV2);
|
||||
LUAU_ASSERT(FFlag::LuauSolverV2 || FFlag::LuauAutocompleteRefactorsForIncrementalAutocomplete);
|
||||
std::shared_ptr<const NormalizedType> normType = normalizer->normalize(ty);
|
||||
|
||||
if (!normType)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
#include "Luau/Unifiable.h"
|
||||
#include "Luau/TypeFwd.h"
|
||||
#include "Luau/TypePack.h"
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -13,12 +15,17 @@ int freshIndex()
|
|||
return ++nextIndex;
|
||||
}
|
||||
|
||||
Error::Error()
|
||||
template<typename Id>
|
||||
Error<Id>::Error()
|
||||
: index(++nextIndex)
|
||||
{
|
||||
}
|
||||
|
||||
int Error::nextIndex = 0;
|
||||
template<typename Id>
|
||||
int Error<Id>::nextIndex = 0;
|
||||
|
||||
template struct Error<TypeId>;
|
||||
template struct Error<TypePackId>;
|
||||
|
||||
} // namespace Unifiable
|
||||
} // namespace Luau
|
||||
|
|
|
@ -1616,9 +1616,9 @@ void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCal
|
|||
log.replace(subTp, Unifiable::Bound<TypePackId>(superTp));
|
||||
}
|
||||
}
|
||||
else if (log.getMutable<Unifiable::Error>(superTp))
|
||||
else if (log.getMutable<ErrorTypePack>(superTp))
|
||||
tryUnifyWithAny(subTp, superTp);
|
||||
else if (log.getMutable<Unifiable::Error>(subTp))
|
||||
else if (log.getMutable<ErrorTypePack>(subTp))
|
||||
tryUnifyWithAny(superTp, subTp);
|
||||
else if (log.getMutable<VariadicTypePack>(superTp))
|
||||
tryUnifyVariadics(subTp, superTp, false);
|
||||
|
@ -2741,7 +2741,7 @@ void Unifier::tryUnifyVariadics(TypePackId subTp, TypePackId superTp, bool rever
|
|||
else
|
||||
log.replace(tail, BoundTypePack{superTp});
|
||||
}
|
||||
else if (get<Unifiable::Error>(tail))
|
||||
else if (get<ErrorTypePack>(tail))
|
||||
{
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
@ -2845,7 +2845,7 @@ void Unifier::tryUnifyWithAny(TypeId subTy, TypeId anyTy)
|
|||
|
||||
void Unifier::tryUnifyWithAny(TypePackId subTy, TypePackId anyTp)
|
||||
{
|
||||
LUAU_ASSERT(get<Unifiable::Error>(anyTp));
|
||||
LUAU_ASSERT(get<ErrorTypePack>(anyTp));
|
||||
|
||||
const TypeId anyTy = builtinTypes->errorRecoveryType();
|
||||
|
||||
|
@ -2997,7 +2997,7 @@ bool Unifier::occursCheck(DenseHashSet<TypePackId>& seen, TypePackId needle, Typ
|
|||
|
||||
RecursionLimiter _ra(&sharedState.counters.recursionCount, sharedState.counters.recursionLimit);
|
||||
|
||||
while (!log.getMutable<ErrorType>(haystack))
|
||||
while (!log.getMutable<ErrorTypePack>(haystack))
|
||||
{
|
||||
if (needle == haystack)
|
||||
return true;
|
||||
|
|
|
@ -908,7 +908,7 @@ OccursCheckResult Unifier2::occursCheck(DenseHashSet<TypePackId>& seen, TypePack
|
|||
|
||||
RecursionLimiter _ra(&recursionCount, recursionLimit);
|
||||
|
||||
while (!getMutable<Unifiable::Error>(haystack))
|
||||
while (!getMutable<ErrorTypePack>(haystack))
|
||||
{
|
||||
if (needle == haystack)
|
||||
return OccursCheckResult::Fail;
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
#include "Luau/Common.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauNativeAttribute)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -239,8 +237,6 @@ void AstExprFunction::visit(AstVisitor* visitor)
|
|||
|
||||
bool AstExprFunction::hasNativeAttribute() const
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauNativeAttribute);
|
||||
|
||||
for (const auto attribute : attributes)
|
||||
{
|
||||
if (attribute->type == AstAttr::Type::Native)
|
||||
|
|
|
@ -18,13 +18,12 @@ 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(LuauNativeAttribute)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAttributeSyntaxFunExpr)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunctionsSyntax2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserDefinedTypeFunParseExport)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAllowFragmentParsing)
|
||||
LUAU_FASTFLAGVARIABLE(LuauPortableStringZeroCheck)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAllowComplexTypesInGenericParams)
|
||||
LUAU_FASTFLAGVARIABLE(LuauErrorRecoveryForTableTypes)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -724,10 +723,6 @@ std::pair<bool, AstAttr::Type> Parser::validateAttribute(const char* attributeNa
|
|||
if (found)
|
||||
{
|
||||
type = kAttributeEntries[i].type;
|
||||
|
||||
if (!FFlag::LuauNativeAttribute && type == AstAttr::Type::Native)
|
||||
found = false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1278,6 +1273,19 @@ std::pair<AstExprFunction*, AstLocal*> Parser::parseFunctionBody(
|
|||
MatchLexeme matchParen = lexer.current();
|
||||
expectAndConsume('(', "function");
|
||||
|
||||
// NOTE: This was added in conjunction with passing `searchForMissing` to
|
||||
// `expectMatchAndConsume` inside `parseTableType` so that the behavior of
|
||||
// parsing code like below (note the missing `}`):
|
||||
//
|
||||
// function (t: { a: number ) end
|
||||
//
|
||||
// ... will still parse as (roughly):
|
||||
//
|
||||
// function (t: { a: number }) end
|
||||
//
|
||||
if (FFlag::LuauErrorRecoveryForTableTypes)
|
||||
matchRecoveryStopOnToken[')']++;
|
||||
|
||||
TempVector<Binding> args(scratchBinding);
|
||||
|
||||
bool vararg = false;
|
||||
|
@ -1294,6 +1302,9 @@ std::pair<AstExprFunction*, AstLocal*> Parser::parseFunctionBody(
|
|||
|
||||
expectMatchAndConsume(')', matchParen, true);
|
||||
|
||||
if (FFlag::LuauErrorRecoveryForTableTypes)
|
||||
matchRecoveryStopOnToken[')']--;
|
||||
|
||||
std::optional<AstTypeList> typelist = parseOptionalReturnType();
|
||||
|
||||
AstLocal* funLocal = nullptr;
|
||||
|
@ -1678,7 +1689,7 @@ AstType* Parser::parseTableType(bool inDeclarationContext)
|
|||
|
||||
Location end = lexer.current().location;
|
||||
|
||||
if (!expectMatchAndConsume('}', matchBrace))
|
||||
if (!expectMatchAndConsume('}', matchBrace, /* searchForMissing = */ FFlag::LuauErrorRecoveryForTableTypes))
|
||||
end = lexer.previousLocation();
|
||||
|
||||
return allocator.alloc<AstTypeTable>(Location(start, end), copy(props), indexer);
|
||||
|
@ -2526,7 +2537,7 @@ AstExpr* Parser::parseSimpleExpr()
|
|||
|
||||
AstArray<AstAttr*> attributes{nullptr, 0};
|
||||
|
||||
if (FFlag::LuauAttributeSyntaxFunExpr && lexer.current().type == Lexeme::Attribute)
|
||||
if (lexer.current().type == Lexeme::Attribute)
|
||||
{
|
||||
attributes = parseAttributes();
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "Luau/Common.h"
|
||||
#include "Luau/IrData.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
|
@ -177,6 +179,9 @@ inline bool hasResult(IrCmd cmd)
|
|||
case IrCmd::MUL_VEC:
|
||||
case IrCmd::DIV_VEC:
|
||||
case IrCmd::DOT_VEC:
|
||||
if (cmd == IrCmd::DOT_VEC)
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeDot);
|
||||
LUAU_FALLTHROUGH;
|
||||
case IrCmd::UNM_VEC:
|
||||
case IrCmd::NOT_ANY:
|
||||
case IrCmd::CMP_ANY:
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
|
@ -588,6 +590,7 @@ void AssemblyBuilderA64::fabs(RegisterA64 dst, RegisterA64 src)
|
|||
|
||||
void AssemblyBuilderA64::faddp(RegisterA64 dst, RegisterA64 src)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeDot);
|
||||
CODEGEN_ASSERT(dst.kind == KindA64::d || dst.kind == KindA64::s);
|
||||
CODEGEN_ASSERT(dst.kind == src.kind);
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
|
@ -948,6 +950,7 @@ void AssemblyBuilderX64::vpinsrd(RegisterX64 dst, RegisterX64 src1, OperandX64 s
|
|||
|
||||
void AssemblyBuilderX64::vdpps(OperandX64 dst, OperandX64 src1, OperandX64 src2, uint8_t mask)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeDot);
|
||||
placeAvx("vdpps", dst, src1, src2, mask, 0x40, false, AVX_0F3A, AVX_66);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
#include "lobject.h"
|
||||
#include "lstate.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauNativeAttribute)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
|
@ -58,10 +56,7 @@ std::vector<FunctionBytecodeSummary> summarizeBytecode(lua_State* L, int idx, un
|
|||
Proto* root = clvalue(func)->l.p;
|
||||
|
||||
std::vector<Proto*> protos;
|
||||
if (FFlag::LuauNativeAttribute)
|
||||
gatherFunctions(protos, root, CodeGen_ColdFunctions, root->flags & LPF_NATIVE_FUNCTION);
|
||||
else
|
||||
gatherFunctions_DEPRECATED(protos, root, CodeGen_ColdFunctions);
|
||||
gatherFunctions(protos, root, CodeGen_ColdFunctions, root->flags & LPF_NATIVE_FUNCTION);
|
||||
|
||||
std::vector<FunctionBytecodeSummary> summaries;
|
||||
summaries.reserve(protos.size());
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
#include "lapi.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauNativeAttribute)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
|
@ -155,10 +153,7 @@ static std::string getAssemblyImpl(AssemblyBuilder& build, const TValue* func, A
|
|||
}
|
||||
|
||||
std::vector<Proto*> protos;
|
||||
if (FFlag::LuauNativeAttribute)
|
||||
gatherFunctions(protos, root, options.compilationOptions.flags, root->flags & LPF_NATIVE_FUNCTION);
|
||||
else
|
||||
gatherFunctions_DEPRECATED(protos, root, options.compilationOptions.flags);
|
||||
gatherFunctions(protos, root, options.compilationOptions.flags, root->flags & LPF_NATIVE_FUNCTION);
|
||||
|
||||
protos.erase(
|
||||
std::remove_if(
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
LUAU_FASTINTVARIABLE(LuauCodeGenBlockSize, 4 * 1024 * 1024)
|
||||
LUAU_FASTINTVARIABLE(LuauCodeGenMaxTotalSize, 256 * 1024 * 1024)
|
||||
LUAU_FASTFLAG(LuauNativeAttribute)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -510,10 +509,7 @@ template<typename AssemblyBuilder>
|
|||
return CompilationResult{CodeGenCompilationResult::CodeGenNotInitialized};
|
||||
|
||||
std::vector<Proto*> protos;
|
||||
if (FFlag::LuauNativeAttribute)
|
||||
gatherFunctions(protos, root, options.flags, root->flags & LPF_NATIVE_FUNCTION);
|
||||
else
|
||||
gatherFunctions_DEPRECATED(protos, root, options.flags);
|
||||
gatherFunctions(protos, root, options.flags, root->flags & LPF_NATIVE_FUNCTION);
|
||||
|
||||
// Skip protos that have been compiled during previous invocations of CodeGen::compile
|
||||
protos.erase(
|
||||
|
|
|
@ -27,31 +27,12 @@ LUAU_FASTFLAG(DebugCodegenSkipNumbering)
|
|||
LUAU_FASTINT(CodegenHeuristicsInstructionLimit)
|
||||
LUAU_FASTINT(CodegenHeuristicsBlockLimit)
|
||||
LUAU_FASTINT(CodegenHeuristicsBlockInstructionLimit)
|
||||
LUAU_FASTFLAG(LuauNativeAttribute)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
{
|
||||
|
||||
inline void gatherFunctions_DEPRECATED(std::vector<Proto*>& results, Proto* proto, unsigned int flags)
|
||||
{
|
||||
if (results.size() <= size_t(proto->bytecodeid))
|
||||
results.resize(proto->bytecodeid + 1);
|
||||
|
||||
// Skip protos that we've already compiled in this run: this happens because at -O2, inlined functions get their protos reused
|
||||
if (results[proto->bytecodeid])
|
||||
return;
|
||||
|
||||
// Only compile cold functions if requested
|
||||
if ((proto->flags & LPF_NATIVE_COLD) == 0 || (flags & CodeGen_ColdFunctions) != 0)
|
||||
results[proto->bytecodeid] = proto;
|
||||
|
||||
// Recursively traverse child protos even if we aren't compiling this one
|
||||
for (int i = 0; i < proto->sizep; i++)
|
||||
gatherFunctions_DEPRECATED(results, proto->p[i], flags);
|
||||
}
|
||||
|
||||
inline void gatherFunctionsHelper(
|
||||
std::vector<Proto*>& results,
|
||||
Proto* proto,
|
||||
|
@ -82,7 +63,6 @@ inline void gatherFunctionsHelper(
|
|||
|
||||
inline void gatherFunctions(std::vector<Proto*>& results, Proto* root, const unsigned int flags, const bool hasNativeFunctions = false)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauNativeAttribute);
|
||||
gatherFunctionsHelper(results, root, flags, hasNativeFunctions, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include <stdarg.h>
|
||||
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
|
@ -164,6 +166,7 @@ const char* getCmdName(IrCmd cmd)
|
|||
case IrCmd::UNM_VEC:
|
||||
return "UNM_VEC";
|
||||
case IrCmd::DOT_VEC:
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeDot);
|
||||
return "DOT_VEC";
|
||||
case IrCmd::NOT_ANY:
|
||||
return "NOT_ANY";
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "lstate.h"
|
||||
#include "lgc.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
|
@ -730,6 +732,8 @@ void IrLoweringA64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
|
|||
}
|
||||
case IrCmd::DOT_VEC:
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeDot);
|
||||
|
||||
inst.regA64 = regs.allocReg(KindA64::d, index);
|
||||
|
||||
RegisterA64 temp = regs.allocTemp(KindA64::q);
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include "lstate.h"
|
||||
#include "lgc.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
|
@ -677,6 +679,8 @@ void IrLoweringX64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
|
|||
}
|
||||
case IrCmd::DOT_VEC:
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeDot);
|
||||
|
||||
inst.regX64 = regs.allocRegOrReuse(SizeX64::xmmword, index, {inst.a, inst.b});
|
||||
|
||||
ScopedRegX64 tmp1{regs};
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
|
@ -76,6 +78,7 @@ IrValueKind getCmdValueKind(IrCmd cmd)
|
|||
case IrCmd::UNM_VEC:
|
||||
return IrValueKind::Tvalue;
|
||||
case IrCmd::DOT_VEC:
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeDot);
|
||||
return IrValueKind::Double;
|
||||
case IrCmd::NOT_ANY:
|
||||
case IrCmd::CMP_ANY:
|
||||
|
|
|
@ -18,6 +18,7 @@ LUAU_FASTINTVARIABLE(LuauCodeGenMinLinearBlockPath, 3)
|
|||
LUAU_FASTINTVARIABLE(LuauCodeGenReuseSlotLimit, 64)
|
||||
LUAU_FASTINTVARIABLE(LuauCodeGenReuseUdataTagLimit, 64)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauAbortingChecks)
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -1344,6 +1345,9 @@ static void constPropInInst(ConstPropState& state, IrBuilder& build, IrFunction&
|
|||
case IrCmd::MUL_VEC:
|
||||
case IrCmd::DIV_VEC:
|
||||
case IrCmd::DOT_VEC:
|
||||
if (inst.cmd == IrCmd::DOT_VEC)
|
||||
LUAU_ASSERT(FFlag::LuauVectorLibNativeDot);
|
||||
|
||||
if (IrInst* a = function.asInstOp(inst.a); a && a->cmd == IrCmd::TAG_VECTOR)
|
||||
replace(function, inst.a, a->a);
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ LUAU_FASTINTVARIABLE(LuauCompileInlineThreshold, 25)
|
|||
LUAU_FASTINTVARIABLE(LuauCompileInlineThresholdMaxBoost, 300)
|
||||
LUAU_FASTINTVARIABLE(LuauCompileInlineDepth, 5)
|
||||
|
||||
LUAU_FASTFLAG(LuauNativeAttribute)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCompileOptimizeRevArith)
|
||||
|
||||
namespace Luau
|
||||
|
@ -286,7 +285,7 @@ struct Compiler
|
|||
if (func->functionDepth == 0 && !hasLoops)
|
||||
protoflags |= LPF_NATIVE_COLD;
|
||||
|
||||
if (FFlag::LuauNativeAttribute && func->hasNativeAttribute())
|
||||
if (func->hasNativeAttribute())
|
||||
protoflags |= LPF_NATIVE_FUNCTION;
|
||||
|
||||
bytecode.endFunction(uint8_t(stackSize), uint8_t(upvals.size()), protoflags);
|
||||
|
@ -3927,7 +3926,7 @@ struct Compiler
|
|||
// this makes sure all functions that are used when compiling this one have been already added to the vector
|
||||
functions.push_back(node);
|
||||
|
||||
if (FFlag::LuauNativeAttribute && !hasNativeFunction && node->hasNativeAttribute())
|
||||
if (!hasNativeFunction && node->hasNativeAttribute())
|
||||
hasNativeFunction = true;
|
||||
|
||||
return false;
|
||||
|
@ -4272,7 +4271,7 @@ void compileOrThrow(BytecodeBuilder& bytecode, const ParseResult& parseResult, c
|
|||
|
||||
// If a function has native attribute and the whole module is not native, we set LPF_NATIVE_FUNCTION flag
|
||||
// This ensures that LPF_NATIVE_MODULE and LPF_NATIVE_FUNCTION are exclusive.
|
||||
if (FFlag::LuauNativeAttribute && (protoflags & LPF_NATIVE_FUNCTION) && !(mainFlags & LPF_NATIVE_MODULE))
|
||||
if ((protoflags & LPF_NATIVE_FUNCTION) && !(mainFlags & LPF_NATIVE_MODULE))
|
||||
mainFlags |= LPF_NATIVE_FUNCTION;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ struct Config
|
|||
|
||||
DenseHashMap<std::string, AliasInfo> aliases{""};
|
||||
|
||||
void setAlias(std::string alias, const std::string& value, const std::string configLocation);
|
||||
void setAlias(std::string alias, std::string value, const std::string& configLocation);
|
||||
|
||||
private:
|
||||
// Prevents making unnecessary copies of the same config location string.
|
||||
|
|
|
@ -28,15 +28,7 @@ Config::Config(const Config& other)
|
|||
{
|
||||
for (const auto& [alias, aliasInfo] : other.aliases)
|
||||
{
|
||||
std::string configLocation = std::string(aliasInfo.configLocation);
|
||||
|
||||
if (!configLocationCache.contains(configLocation))
|
||||
configLocationCache[configLocation] = std::make_unique<std::string>(configLocation);
|
||||
|
||||
AliasInfo newAliasInfo;
|
||||
newAliasInfo.value = aliasInfo.value;
|
||||
newAliasInfo.configLocation = *configLocationCache[configLocation];
|
||||
aliases[alias] = std::move(newAliasInfo);
|
||||
setAlias(alias, aliasInfo.value, std::string(aliasInfo.configLocation));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,10 +42,10 @@ Config& Config::operator=(const Config& other)
|
|||
return *this;
|
||||
}
|
||||
|
||||
void Config::setAlias(std::string alias, const std::string& value, const std::string configLocation)
|
||||
void Config::setAlias(std::string alias, std::string value, const std::string& configLocation)
|
||||
{
|
||||
AliasInfo& info = aliases[alias];
|
||||
info.value = value;
|
||||
info.value = std::move(value);
|
||||
|
||||
if (!configLocationCache.contains(configLocation))
|
||||
configLocationCache[configLocation] = std::make_unique<std::string>(configLocation);
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include <math.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauVectorMetatable)
|
||||
|
||||
static int vector_create(lua_State* L)
|
||||
{
|
||||
double x = luaL_checknumber(L, 1);
|
||||
|
@ -254,6 +256,35 @@ static int vector_max(lua_State* L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int vector_index(lua_State* L)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorMetatable);
|
||||
|
||||
const float* v = luaL_checkvector(L, 1);
|
||||
size_t namelen = 0;
|
||||
const char* name = luaL_checklstring(L, 2, &namelen);
|
||||
|
||||
// field access implementation mirrors the fast-path we have in the VM
|
||||
if (namelen == 1)
|
||||
{
|
||||
int ic = (name[0] | ' ') - 'x';
|
||||
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
// 'w' is before 'x' in ascii, so ic is -1 when indexing with 'w'
|
||||
if (ic == -1)
|
||||
ic = 3;
|
||||
#endif
|
||||
|
||||
if (unsigned(ic) < LUA_VECTOR_SIZE)
|
||||
{
|
||||
lua_pushnumber(L, v[ic]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
luaL_error(L, "attempt to index vector with '%s'", name);
|
||||
}
|
||||
|
||||
static const luaL_Reg vectorlib[] = {
|
||||
{"create", vector_create},
|
||||
{"magnitude", vector_magnitude},
|
||||
|
@ -271,6 +302,30 @@ static const luaL_Reg vectorlib[] = {
|
|||
{NULL, NULL},
|
||||
};
|
||||
|
||||
static void createmetatable(lua_State* L)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauVectorMetatable);
|
||||
|
||||
lua_createtable(L, 0, 1); // create metatable for vectors
|
||||
|
||||
// push dummy vector
|
||||
#if LUA_VECTOR_SIZE == 4
|
||||
lua_pushvector(L, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
#else
|
||||
lua_pushvector(L, 0.0f, 0.0f, 0.0f);
|
||||
#endif
|
||||
|
||||
lua_pushvalue(L, -2);
|
||||
lua_setmetatable(L, -2); // set vector metatable
|
||||
lua_pop(L, 1); // pop dummy vector
|
||||
|
||||
lua_pushcfunction(L, vector_index, nullptr);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_setreadonly(L, -1, true);
|
||||
lua_pop(L, 1); // pop the metatable
|
||||
}
|
||||
|
||||
int luaopen_vector(lua_State* L)
|
||||
{
|
||||
luaL_register(L, LUA_VECLIBNAME, vectorlib);
|
||||
|
@ -287,5 +342,8 @@ int luaopen_vector(lua_State* L)
|
|||
lua_setfield(L, -2, "one");
|
||||
#endif
|
||||
|
||||
if (FFlag::LuauVectorMetatable)
|
||||
createmetatable(L);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
using namespace Luau::CodeGen;
|
||||
using namespace Luau::CodeGen::A64;
|
||||
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot);
|
||||
|
||||
static std::string bytecodeAsArray(const std::vector<uint8_t>& bytecode)
|
||||
{
|
||||
std::string result = "{";
|
||||
|
@ -387,6 +389,8 @@ TEST_CASE_FIXTURE(AssemblyBuilderA64Fixture, "FPBasic")
|
|||
|
||||
TEST_CASE_FIXTURE(AssemblyBuilderA64Fixture, "FPMath")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauVectorLibNativeDot, true};
|
||||
|
||||
SINGLE_COMPARE(fabs(d1, d2), 0x1E60C041);
|
||||
SINGLE_COMPARE(fadd(d1, d2, d3), 0x1E632841);
|
||||
SINGLE_COMPARE(fadd(s29, s29, s28), 0x1E3C2BBD);
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
using namespace Luau::CodeGen;
|
||||
using namespace Luau::CodeGen::X64;
|
||||
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot);
|
||||
|
||||
static std::string bytecodeAsArray(const std::vector<uint8_t>& bytecode)
|
||||
{
|
||||
std::string result = "{";
|
||||
|
@ -568,6 +570,8 @@ TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXConversionInstructionForms")
|
|||
|
||||
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXTernaryInstructionForms")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauVectorLibNativeDot, true};
|
||||
|
||||
SINGLE_COMPARE(vroundsd(xmm7, xmm12, xmm3, RoundingModeX64::RoundToNegativeInfinity), 0xc4, 0xe3, 0x19, 0x0b, 0xfb, 0x09);
|
||||
SINGLE_COMPARE(
|
||||
vroundsd(xmm8, xmm13, xmmword[r13 + rdx], RoundingModeX64::RoundToPositiveInfinity), 0xc4, 0x43, 0x11, 0x0b, 0x44, 0x15, 0x00, 0x0a
|
||||
|
|
|
@ -34,11 +34,13 @@ void luaC_validate(lua_State* L);
|
|||
LUAU_FASTFLAG(LuauMathMap)
|
||||
LUAU_FASTFLAG(DebugLuauAbortingChecks)
|
||||
LUAU_FASTINT(CodegenHeuristicsInstructionLimit)
|
||||
LUAU_FASTFLAG(LuauNativeAttribute)
|
||||
LUAU_DYNAMIC_FASTFLAG(LuauStackLimit)
|
||||
LUAU_FASTFLAG(LuauVectorDefinitions)
|
||||
LUAU_DYNAMIC_FASTFLAG(LuauDebugInfoInvArgLeftovers)
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeCodegen)
|
||||
LUAU_FASTFLAG(LuauVectorLibNativeDot)
|
||||
LUAU_FASTFLAG(LuauVectorBuiltins)
|
||||
LUAU_FASTFLAG(LuauVectorMetatable)
|
||||
|
||||
static lua_CompileOptions defaultOptions()
|
||||
{
|
||||
|
@ -889,7 +891,10 @@ TEST_CASE("Vector")
|
|||
|
||||
TEST_CASE("VectorLibrary")
|
||||
{
|
||||
ScopedFastFlag luauVectorBuiltins{FFlag::LuauVectorBuiltins, true};
|
||||
ScopedFastFlag luauVectorLibNativeCodegen{FFlag::LuauVectorLibNativeCodegen, true};
|
||||
ScopedFastFlag luauVectorLibNativeDot{FFlag::LuauVectorLibNativeDot, true};
|
||||
ScopedFastFlag luauVectorMetatable{FFlag::LuauVectorMetatable, true};
|
||||
|
||||
lua_CompileOptions copts = defaultOptions();
|
||||
|
||||
|
@ -2951,8 +2956,6 @@ TEST_CASE("NativeAttribute")
|
|||
if (!codegen || !luau_codegen_supported())
|
||||
return;
|
||||
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauNativeAttribute, true}};
|
||||
|
||||
std::string source = R"R(
|
||||
@native
|
||||
local function sum(x, y)
|
||||
|
|
|
@ -562,12 +562,14 @@ void Fixture::validateErrors(const std::vector<Luau::TypeError>& errors)
|
|||
}
|
||||
}
|
||||
|
||||
LoadDefinitionFileResult Fixture::loadDefinition(const std::string& source)
|
||||
LoadDefinitionFileResult Fixture::loadDefinition(const std::string& source, bool forAutocomplete)
|
||||
{
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
LoadDefinitionFileResult result =
|
||||
frontend.loadDefinitionFile(frontend.globals, frontend.globals.globalScope, source, "@test", /* captureComments */ false);
|
||||
freeze(frontend.globals.globalTypes);
|
||||
GlobalTypes& globals = forAutocomplete ? frontend.globalsForAutocomplete : frontend.globals;
|
||||
unfreeze(globals.globalTypes);
|
||||
LoadDefinitionFileResult result = frontend.loadDefinitionFile(
|
||||
globals, globals.globalScope, source, "@test", /* captureComments */ false, /* typecheckForAutocomplete */ forAutocomplete
|
||||
);
|
||||
freeze(globals.globalTypes);
|
||||
|
||||
if (result.module)
|
||||
dumpErrors(result.module);
|
||||
|
|
|
@ -139,7 +139,7 @@ struct Fixture
|
|||
|
||||
void registerTestTypes();
|
||||
|
||||
LoadDefinitionFileResult loadDefinition(const std::string& source);
|
||||
LoadDefinitionFileResult loadDefinition(const std::string& source, bool forAutocomplete = false);
|
||||
};
|
||||
|
||||
struct BuiltinsFixture : Fixture
|
||||
|
|
|
@ -15,12 +15,12 @@
|
|||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauAllowFragmentParsing);
|
||||
LUAU_FASTFLAG(LuauStoreDFGOnModule2);
|
||||
LUAU_FASTFLAG(LuauAutocompleteRefactorsForIncrementalAutocomplete)
|
||||
LUAU_FASTFLAG(LuauSymbolEquality);
|
||||
LUAU_FASTFLAG(LuauStoreSolverTypeOnModule);
|
||||
|
@ -46,12 +46,11 @@ static FrontendOptions getOptions()
|
|||
template<class BaseType>
|
||||
struct FragmentAutocompleteFixtureImpl : BaseType
|
||||
{
|
||||
ScopedFastFlag sffs[5] = {
|
||||
ScopedFastFlag sffs[4] = {
|
||||
{FFlag::LuauAllowFragmentParsing, true},
|
||||
{FFlag::LuauStoreDFGOnModule2, true},
|
||||
{FFlag::LuauAutocompleteRefactorsForIncrementalAutocomplete, true},
|
||||
{FFlag::LuauStoreSolverTypeOnModule, true},
|
||||
{FFlag::LuauSymbolEquality, true}
|
||||
{FFlag::LuauSymbolEquality, true},
|
||||
};
|
||||
|
||||
FragmentAutocompleteFixtureImpl()
|
||||
|
@ -140,6 +139,25 @@ struct FragmentAutocompleteFixture : FragmentAutocompleteFixtureImpl<Fixture>
|
|||
|
||||
struct FragmentAutocompleteBuiltinsFixture : FragmentAutocompleteFixtureImpl<BuiltinsFixture>
|
||||
{
|
||||
FragmentAutocompleteBuiltinsFixture()
|
||||
: FragmentAutocompleteFixtureImpl<BuiltinsFixture>()
|
||||
{
|
||||
const std::string fakeVecDecl = R"(
|
||||
declare class FakeVec
|
||||
function dot(self, x: FakeVec) : FakeVec
|
||||
zero : FakeVec
|
||||
end
|
||||
)";
|
||||
// The old solver always performs a strict mode check and populates the module resolver and globals
|
||||
// for autocomplete.
|
||||
// The new solver just populates the globals and the moduleResolver.
|
||||
// Because these tests run in both the old solver and the new solver, and the test suite
|
||||
// now picks the module resolver as appropriate in order to better mimic the studio code path,
|
||||
// we have to load the definition file into both the 'globals'/'resolver' and the equivalent
|
||||
// 'for autocomplete'.
|
||||
loadDefinition(fakeVecDecl);
|
||||
loadDefinition(fakeVecDecl, /* For Autocomplete Module */ true);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_SUITE_BEGIN("FragmentAutocompleteTraversalTests");
|
||||
|
@ -316,11 +334,11 @@ local z = x + y
|
|||
Position{3, 15}
|
||||
);
|
||||
|
||||
CHECK_EQ("\nlocal z = x + y", fragment.fragmentToParse);
|
||||
CHECK_EQ("local y = 5\nlocal z = x + y", fragment.fragmentToParse);
|
||||
CHECK_EQ(5, fragment.ancestry.size());
|
||||
REQUIRE(fragment.root);
|
||||
CHECK_EQ(1, fragment.root->body.size);
|
||||
auto stat = fragment.root->body.data[0]->as<AstStatLocal>();
|
||||
CHECK_EQ(2, fragment.root->body.size);
|
||||
auto stat = fragment.root->body.data[1]->as<AstStatLocal>();
|
||||
REQUIRE(stat);
|
||||
CHECK_EQ(1, stat->vars.size);
|
||||
CHECK_EQ(1, stat->values.size);
|
||||
|
@ -422,7 +440,7 @@ abc("bar")
|
|||
Position{1, 10}
|
||||
);
|
||||
|
||||
CHECK_EQ("\nabc(\"foo\")", callFragment.fragmentToParse);
|
||||
CHECK_EQ("function abc(foo: string) end\nabc(\"foo\")", callFragment.fragmentToParse);
|
||||
CHECK(callFragment.nearestStatement->is<AstStatFunction>());
|
||||
|
||||
CHECK_GE(callFragment.ancestry.size(), 2);
|
||||
|
@ -447,7 +465,7 @@ abc("bar")
|
|||
Position{1, 9}
|
||||
);
|
||||
|
||||
CHECK_EQ("\nabc(\"foo\"", stringFragment.fragmentToParse);
|
||||
CHECK_EQ("function abc(foo: string) end\nabc(\"foo\"", stringFragment.fragmentToParse);
|
||||
CHECK(stringFragment.nearestStatement->is<AstStatFunction>());
|
||||
|
||||
CHECK_GE(stringFragment.ancestry.size(), 1);
|
||||
|
@ -482,7 +500,7 @@ abc("bar")
|
|||
Position{3, 1}
|
||||
);
|
||||
|
||||
CHECK_EQ("\nabc(\n\"foo\"\n)", fragment.fragmentToParse);
|
||||
CHECK_EQ("function abc(foo: string) end\nabc(\n\"foo\"\n)", fragment.fragmentToParse);
|
||||
CHECK(fragment.nearestStatement->is<AstStatFunction>());
|
||||
|
||||
CHECK_GE(fragment.ancestry.size(), 2);
|
||||
|
@ -1223,4 +1241,140 @@ TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "method_call_inside_function_body
|
|||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "tbl_function_parameter")
|
||||
{
|
||||
const std::string source = R"(
|
||||
--!strict
|
||||
type Foo = {x : number, y : number}
|
||||
local function func(abc : Foo)
|
||||
abc.
|
||||
end
|
||||
)";
|
||||
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
source,
|
||||
Position{4, 7},
|
||||
[](FragmentAutocompleteResult& result)
|
||||
{
|
||||
CHECK_EQ(2, result.acResults.entryMap.size());
|
||||
CHECK(result.acResults.entryMap.count("x"));
|
||||
CHECK(result.acResults.entryMap.count("y"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "tbl_local_function_parameter")
|
||||
{
|
||||
const std::string source = R"(
|
||||
--!strict
|
||||
type Foo = {x : number, y : number}
|
||||
local function func(abc : Foo)
|
||||
abc.
|
||||
end
|
||||
)";
|
||||
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
source,
|
||||
Position{4, 7},
|
||||
[](FragmentAutocompleteResult& result)
|
||||
{
|
||||
CHECK_EQ(2, result.acResults.entryMap.size());
|
||||
CHECK(result.acResults.entryMap.count("x"));
|
||||
CHECK(result.acResults.entryMap.count("y"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "vec3_function_parameter")
|
||||
{
|
||||
const std::string source = R"(
|
||||
--!strict
|
||||
local function func(abc : FakeVec)
|
||||
abc.
|
||||
end
|
||||
)";
|
||||
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
source,
|
||||
Position{3, 7},
|
||||
[](FragmentAutocompleteResult& result)
|
||||
{
|
||||
CHECK_EQ(2, result.acResults.entryMap.size());
|
||||
CHECK(result.acResults.entryMap.count("zero"));
|
||||
CHECK(result.acResults.entryMap.count("dot"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "vec3_local_function_parameter")
|
||||
{
|
||||
const std::string source = R"(
|
||||
--!strict
|
||||
local function func(abc : FakeVec)
|
||||
abc.
|
||||
end
|
||||
)";
|
||||
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
source,
|
||||
Position{3, 7},
|
||||
[](FragmentAutocompleteResult& result)
|
||||
{
|
||||
CHECK_EQ(2, result.acResults.entryMap.size());
|
||||
CHECK(result.acResults.entryMap.count("zero"));
|
||||
CHECK(result.acResults.entryMap.count("dot"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "function_parameter_not_recommending_out_of_scope_argument")
|
||||
{
|
||||
const std::string source = R"(
|
||||
--!strict
|
||||
local function foo(abd: FakeVec)
|
||||
end
|
||||
local function bar(abc : FakeVec)
|
||||
a
|
||||
end
|
||||
)";
|
||||
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
source,
|
||||
Position{5, 5},
|
||||
[](FragmentAutocompleteResult& result)
|
||||
{
|
||||
CHECK(result.acResults.entryMap.count("abc"));
|
||||
CHECK(!result.acResults.entryMap.count("abd"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteBuiltinsFixture, "bad_range")
|
||||
{
|
||||
const std::string source = R"(
|
||||
l
|
||||
)";
|
||||
const std::string updated = R"(
|
||||
local t = 1
|
||||
t
|
||||
)";
|
||||
|
||||
autocompleteFragmentInBothSolvers(
|
||||
source,
|
||||
updated,
|
||||
Position{2, 1},
|
||||
[](FragmentAutocompleteResult& result)
|
||||
{
|
||||
auto opt = linearSearchForBinding(result.freshScope, "t");
|
||||
REQUIRE(opt);
|
||||
CHECK_EQ("number", toString(*opt));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "doctest.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LuauNativeAttribute);
|
||||
LUAU_FASTFLAG(LintRedundantNativeAttribute);
|
||||
|
||||
using namespace Luau;
|
||||
|
@ -1999,7 +1998,7 @@ local _ = a <= (b == 0)
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "RedundantNativeAttribute")
|
||||
{
|
||||
ScopedFastFlag sff[] = {{FFlag::LuauNativeAttribute, true}, {FFlag::LintRedundantNativeAttribute, true}};
|
||||
ScopedFastFlag sff[] = {{FFlag::LintRedundantNativeAttribute, true}};
|
||||
|
||||
LintResult result = lint(R"(
|
||||
--!native
|
||||
|
|
|
@ -16,10 +16,10 @@ LUAU_FASTINT(LuauRecursionLimit)
|
|||
LUAU_FASTINT(LuauTypeLengthLimit)
|
||||
LUAU_FASTINT(LuauParseErrorLimit)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauAttributeSyntaxFunExpr)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctionsSyntax2)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunParseExport)
|
||||
LUAU_FASTFLAG(LuauAllowComplexTypesInGenericParams)
|
||||
LUAU_FASTFLAG(LuauErrorRecoveryForTableTypes)
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -3351,8 +3351,6 @@ end)");
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "parse_attribute_for_function_expression")
|
||||
{
|
||||
ScopedFastFlag sff[] = {{FFlag::LuauAttributeSyntaxFunExpr, true}};
|
||||
|
||||
AstStatBlock* stat1 = parse(R"(
|
||||
local function invoker(f)
|
||||
return f(1)
|
||||
|
@ -3521,8 +3519,6 @@ function foo1 () @checked return 'a' end
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "dont_parse_attribute_on_argument_non_function")
|
||||
{
|
||||
ScopedFastFlag sff[] = {{FFlag::LuauAttributeSyntaxFunExpr, true}};
|
||||
|
||||
ParseResult pr = tryParse(R"(
|
||||
local function invoker(f, y)
|
||||
return f(y)
|
||||
|
@ -3743,5 +3739,18 @@ TEST_CASE_FIXTURE(Fixture, "complex_union_in_generic_ty")
|
|||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "recover_from_bad_table_type")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauErrorRecoveryForTableTypes, true};
|
||||
ParseOptions opts;
|
||||
opts.allowDeclarationSyntax = true;
|
||||
const auto result = tryParse(R"(
|
||||
declare class Widget
|
||||
state: {string: function(string, Widget)}
|
||||
end
|
||||
)", opts);
|
||||
CHECK_EQ(result.errors.size(), 2);
|
||||
}
|
||||
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -431,7 +431,7 @@ n1 [label="FreeTypePack 1"];
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "error_pack")
|
||||
{
|
||||
TypePackVar pack{TypePackVariant{Unifiable::Error{}}};
|
||||
TypePackVar pack{TypePackVariant{ErrorTypePack{}}};
|
||||
|
||||
ToDotOptions opts;
|
||||
opts.showPointers = false;
|
||||
|
|
|
@ -13,7 +13,6 @@ using namespace Luau;
|
|||
LUAU_FASTFLAG(LuauRecursiveTypeParameterRestriction);
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LuauAttributeSyntax);
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctions2)
|
||||
|
||||
TEST_SUITE_BEGIN("ToString");
|
||||
|
||||
|
@ -969,7 +968,7 @@ TEST_CASE_FIXTURE(Fixture, "correct_stringification_user_defined_type_functions"
|
|||
|
||||
Type tv{tftt};
|
||||
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauUserDefinedTypeFunctions2)
|
||||
if (FFlag::LuauSolverV2)
|
||||
CHECK_EQ(toString(&tv, {}), "woohoo<number>");
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctions2)
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeFamilyApplicationCartesianProductLimit)
|
||||
|
||||
struct TypeFunctionFixture : Fixture
|
||||
|
|
|
@ -9,8 +9,6 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctionsSyntax2)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctions2)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctionNoEvaluation)
|
||||
LUAU_FASTFLAG(LuauUserTypeFunFixRegister)
|
||||
LUAU_FASTFLAG(LuauUserTypeFunFixNoReadWrite)
|
||||
LUAU_FASTFLAG(LuauUserTypeFunFixMetatable)
|
||||
|
@ -25,7 +23,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_nil_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_nil(arg)
|
||||
|
@ -42,7 +39,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_nil_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getnil()
|
||||
|
@ -63,7 +59,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_unknown_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_unknown(arg)
|
||||
|
@ -80,7 +75,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_unknown_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getunknown()
|
||||
|
@ -101,7 +95,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_never_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_never(arg)
|
||||
|
@ -118,7 +111,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_never_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getnever()
|
||||
|
@ -139,7 +131,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_any_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_any(arg)
|
||||
|
@ -156,7 +147,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_any_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getany()
|
||||
|
@ -177,7 +167,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_boolean_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_bool(arg)
|
||||
|
@ -194,7 +183,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_boolean_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getboolean()
|
||||
|
@ -215,7 +203,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_number_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_num(arg)
|
||||
|
@ -232,7 +219,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_number_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getnumber()
|
||||
|
@ -253,7 +239,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_string_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_str(arg)
|
||||
|
@ -270,7 +255,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_string_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getstring()
|
||||
|
@ -291,7 +275,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_boolsingleton_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_boolsingleton(arg)
|
||||
|
@ -308,7 +291,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_boolsingleton_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getboolsingleton()
|
||||
|
@ -329,7 +311,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_strsingleton_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_strsingleton(arg)
|
||||
|
@ -346,7 +327,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_strsingleton_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getstrsingleton()
|
||||
|
@ -367,7 +347,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_union_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_union(arg)
|
||||
|
@ -388,7 +367,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_union_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getunion()
|
||||
|
@ -418,7 +396,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_intersection_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_intersection(arg)
|
||||
|
@ -439,7 +416,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_intersection_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getintersection()
|
||||
|
@ -475,7 +451,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_negation_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getnegation()
|
||||
|
@ -501,7 +476,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_table_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_table(arg)
|
||||
|
@ -522,7 +496,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_table_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function gettable()
|
||||
|
@ -562,7 +535,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_metatable_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getmetatable()
|
||||
|
@ -596,7 +568,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_function_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_func(arg)
|
||||
|
@ -613,7 +584,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_function_methods_work")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getfunction()
|
||||
|
@ -644,7 +614,6 @@ TEST_CASE_FIXTURE(ClassFixture, "udtf_class_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_class(arg)
|
||||
|
@ -660,7 +629,6 @@ TEST_CASE_FIXTURE(ClassFixture, "udtf_class_methods_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -684,7 +652,6 @@ TEST_CASE_FIXTURE(ClassFixture, "write_of_readonly_is_nil")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag udtfRwFix{FFlag::LuauUserTypeFunFixNoReadWrite, true};
|
||||
|
||||
|
||||
|
@ -714,7 +681,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_check_mutability")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function checkmut()
|
||||
|
@ -747,7 +713,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_copy_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getcopy()
|
||||
|
@ -781,7 +746,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_simple_cyclic_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_cycle(arg)
|
||||
|
@ -803,7 +767,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_createtable_bad_metatable")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function badmetatable()
|
||||
|
@ -825,7 +788,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_complex_cyclic_serialization_works")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_cycle2(arg)
|
||||
|
@ -855,7 +817,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_user_error_is_reported")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function errors_if_string(arg)
|
||||
|
@ -878,7 +839,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_type_overrides_call_metamethod")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function hello(arg)
|
||||
|
@ -897,7 +857,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_type_overrides_eq_metamethod")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function hello()
|
||||
|
@ -923,7 +882,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_function_type_cant_call_get_props")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function hello(arg)
|
||||
|
@ -945,7 +903,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_calling_each_other")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function foo()
|
||||
|
@ -967,7 +924,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_no_shared_state")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function foo()
|
||||
|
@ -996,7 +952,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_math_reset")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserDefinedTypeFunctionResetState{FFlag::LuauUserDefinedTypeFunctionResetState, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -1013,7 +968,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_optionify")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function optionify(tbl)
|
||||
|
@ -1043,7 +997,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_calling_illegal_global")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function illegal(arg)
|
||||
|
@ -1065,7 +1018,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_recursion_and_gc")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function foo(tbl)
|
||||
|
@ -1091,8 +1043,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_recovery_no_upvalues")
|
|||
{
|
||||
ScopedFastFlag solverV2{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag userDefinedTypeFunctionsSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag userDefinedTypeFunctions{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag userDefinedTypeFunctionNoEvaluation{FFlag::LuauUserDefinedTypeFunctionNoEvaluation, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local var
|
||||
|
@ -1116,7 +1066,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_follow")
|
|||
{
|
||||
ScopedFastFlag solverV2{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag userDefinedTypeFunctionsSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag userDefinedTypeFunctions{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type t0 = any
|
||||
|
@ -1133,7 +1082,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_strip_indexer")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function stripindexer(tbl)
|
||||
|
@ -1159,7 +1107,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_type_methods_on_types")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserTypeFunFixRegister{FFlag::LuauUserTypeFunFixRegister, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -1177,7 +1124,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_types_functions_on_type")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserTypeFunFixRegister{FFlag::LuauUserTypeFunFixRegister, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -1195,7 +1141,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_metatable_writes")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserTypeFunFixRegister{FFlag::LuauUserTypeFunFixRegister, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -1215,7 +1160,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_eq_field")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserTypeFunFixRegister{FFlag::LuauUserTypeFunFixRegister, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -1233,7 +1177,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tag_field")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserTypeFunFixRegister{FFlag::LuauUserTypeFunFixRegister, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -1256,7 +1199,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "metatable_serialization")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserTypeFunFixRegister{FFlag::LuauUserTypeFunFixRegister, true};
|
||||
ScopedFastFlag luauUserTypeFunFixMetatable{FFlag::LuauUserTypeFunFixMetatable, true};
|
||||
|
||||
|
@ -1288,7 +1230,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "nonstrict_mode")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserTypeFunFixRegister{FFlag::LuauUserTypeFunFixRegister, true};
|
||||
ScopedFastFlag luauUserTypeFunNonstrict{FFlag::LuauUserTypeFunNonstrict, true};
|
||||
|
||||
|
@ -1304,7 +1245,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "implicit_export")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserTypeFunFixRegister{FFlag::LuauUserTypeFunFixRegister, true};
|
||||
ScopedFastFlag luauUserTypeFunExportedAndLocal{FFlag::LuauUserTypeFunExportedAndLocal, true};
|
||||
|
||||
|
@ -1335,7 +1275,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "local_scope")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserTypeFunFixRegister{FFlag::LuauUserTypeFunFixRegister, true};
|
||||
ScopedFastFlag luauUserTypeFunExportedAndLocal{FFlag::LuauUserTypeFunExportedAndLocal, true};
|
||||
|
||||
|
@ -1361,7 +1300,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "explicit_export")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag udtfSyntax{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag udtf{FFlag::LuauUserDefinedTypeFunctions2, true};
|
||||
ScopedFastFlag luauUserTypeFunFixRegister{FFlag::LuauUserTypeFunFixRegister, true};
|
||||
ScopedFastFlag luauUserTypeFunExportedAndLocal{FFlag::LuauUserTypeFunExportedAndLocal, true};
|
||||
ScopedFastFlag luauUserDefinedTypeFunParseExport{FFlag::LuauUserDefinedTypeFunParseExport, true};
|
||||
|
|
|
@ -10,7 +10,6 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctionsSyntax2)
|
||||
LUAU_FASTFLAG(LuauUserDefinedTypeFunctions2)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeAliases");
|
||||
|
||||
|
@ -1154,7 +1153,7 @@ type Foo<T> = Foo<T> | string
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_adds_reduce_constraint_for_type_function")
|
||||
{
|
||||
if (!FFlag::LuauSolverV2 || !FFlag::LuauUserDefinedTypeFunctions2)
|
||||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -1166,20 +1165,6 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_adds_reduce_constraint_for_type_f
|
|||
LUAU_CHECK_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "user_defined_type_function_errors")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauUserDefinedTypeFunctionsSyntax2, true};
|
||||
ScopedFastFlag noUDTFimpl{FFlag::LuauUserDefinedTypeFunctions2, false};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function foo()
|
||||
return nil
|
||||
end
|
||||
)");
|
||||
LUAU_CHECK_ERROR_COUNT(1, result);
|
||||
CHECK(toString(result.errors[0]) == "This syntax is not supported");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "bound_type_in_alias_segfault")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
|
|
@ -2049,10 +2049,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "refinements_should_preserve_error_suppressio
|
|||
end
|
||||
)");
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
else
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "many_refinements_on_val")
|
||||
|
|
|
@ -20,6 +20,7 @@ LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
|||
LUAU_FASTFLAG(LuauFixIndexerSubtypingOrdering)
|
||||
LUAU_FASTFLAG(LuauRetrySubtypingWithoutHiddenPack)
|
||||
LUAU_FASTFLAG(LuauTableKeysAreRValues)
|
||||
LUAU_FASTFLAG(LuauAllowNilAssignmentToIndexer)
|
||||
|
||||
TEST_SUITE_BEGIN("TableTests");
|
||||
|
||||
|
@ -1925,18 +1926,128 @@ TEST_CASE_FIXTURE(Fixture, "type_mismatch_on_massive_table_is_cut_short")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "ok_to_set_nil_even_on_non_lvalue_base_expr")
|
||||
{
|
||||
// CLI-100076 Assigning nil to an indexer should always succeed
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauAllowNilAssignmentToIndexer, true}};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local function f(): { [string]: number }
|
||||
return { ["foo"] = 1 }
|
||||
end
|
||||
|
||||
f()["foo"] = nil
|
||||
)"));
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local function f(
|
||||
t: {known_prop: boolean, [string]: number},
|
||||
key: string
|
||||
)
|
||||
t[key] = nil
|
||||
t["hello"] = nil
|
||||
t.undefined = nil
|
||||
end
|
||||
)"));
|
||||
|
||||
auto result = check(R"(
|
||||
local function f(t: {known_prop: boolean, [string]: number, })
|
||||
t.known_prop = nil
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK_EQ(Location{{2, 27}, {2, 30}}, result.errors[0].location);
|
||||
CHECK_EQ("Type 'nil' could not be converted into 'boolean'", toString(result.errors[0]));
|
||||
|
||||
loadDefinition(R"(
|
||||
declare class FancyHashtable
|
||||
[string]: number
|
||||
real_property: string
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local function removekey(fh: FancyHashtable, other_key: string)
|
||||
fh["hmmm"] = nil
|
||||
fh[other_key] = nil
|
||||
fh.dne = nil
|
||||
end
|
||||
)"));
|
||||
|
||||
result = check(R"(
|
||||
local function removekey(fh: FancyHashtable)
|
||||
fh.real_property = nil
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK_EQ(result.errors[0].location, Location{{2, 31}, {2, 34}});
|
||||
CHECK_EQ(toString(result.errors[0]), "Type 'nil' could not be converted into 'string'");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "ok_to_set_nil_on_generic_map")
|
||||
{
|
||||
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauAllowNilAssignmentToIndexer, true}};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
type MyMap<K, V> = { [K]: V }
|
||||
function set<K, V>(m: MyMap<K, V>, k: K, v: V)
|
||||
m[k] = v
|
||||
end
|
||||
function unset<K, V>(m: MyMap<K, V>, k: K)
|
||||
m[k] = nil
|
||||
end
|
||||
local m: MyMap<string, boolean> = {}
|
||||
set(m, "foo", true)
|
||||
unset(m, "foo")
|
||||
)"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "key_setting_inference_given_nil_upper_bound")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauAllowNilAssignmentToIndexer, true}};
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local function setkey_object(t: { [string]: number }, v)
|
||||
t.foo = v
|
||||
t.foo = nil
|
||||
end
|
||||
local function setkey_constindex(t: { [string]: number }, v)
|
||||
t["foo"] = v
|
||||
t["foo"] = nil
|
||||
end
|
||||
local function setkey_unknown(t: { [string]: number }, k, v)
|
||||
t[k] = v
|
||||
t[k] = nil
|
||||
end
|
||||
)"));
|
||||
CHECK_EQ(toString(requireType("setkey_object")), "({ [string]: number }, number) -> ()");
|
||||
CHECK_EQ(toString(requireType("setkey_constindex")), "({ [string]: number }, number) -> ()");
|
||||
CHECK_EQ(toString(requireType("setkey_unknown")), "({ [string]: number }, string, number) -> ()");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(check(R"(
|
||||
local function on_number(v: number): () end
|
||||
local function setkey_object(t: { [string]: number }, v)
|
||||
t.foo = v
|
||||
on_number(v)
|
||||
end
|
||||
)"));
|
||||
CHECK_EQ(toString(requireType("setkey_object")), "({ [string]: number }, number) -> ()");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "explicit_nil_indexer")
|
||||
{
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauSolverV2, true};
|
||||
|
||||
auto result = check(R"(
|
||||
local function _(t: { [string]: number? }): number
|
||||
return t.hello
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK_EQ(result.errors[0].location, Location{{2, 12}, {2, 26}});
|
||||
CHECK(get<TypePackMismatch>(result.errors[0]));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "ok_to_provide_a_subtype_during_construction")
|
||||
|
@ -2843,17 +2954,20 @@ TEST_CASE_FIXTURE(Fixture, "nil_assign_doesnt_hit_indexer")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "wrong_assign_does_hit_indexer")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {{FFlag::LuauSolverV2, true}, {FFlag::LuauAllowNilAssignmentToIndexer, true}};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local a = {}
|
||||
a[0] = 7
|
||||
a[0] = 't'
|
||||
a[0] = nil
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK((Location{Position{3, 15}, Position{3, 18}}) == result.errors[0].location);
|
||||
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
|
||||
REQUIRE(tm);
|
||||
CHECK(tm->wantedType == builtinTypes->numberType);
|
||||
CHECK_EQ("number?", toString(tm->wantedType));
|
||||
CHECK(tm->givenType == builtinTypes->stringType);
|
||||
}
|
||||
|
||||
|
|
|
@ -199,14 +199,14 @@ TEST_CASE_FIXTURE(TypePackFixture, "std_distance")
|
|||
|
||||
TEST_CASE("content_reassignment")
|
||||
{
|
||||
TypePackVar myError{Unifiable::Error{}, /*presistent*/ true};
|
||||
TypePackVar myError{ErrorTypePack{}, /*presistent*/ true};
|
||||
|
||||
TypeArena arena;
|
||||
|
||||
TypePackId futureError = arena.addTypePack(TypePackVar{FreeTypePack{TypeLevel{}}});
|
||||
asMutable(futureError)->reassign(myError);
|
||||
|
||||
CHECK(get<ErrorType>(futureError) != nullptr);
|
||||
CHECK(get<ErrorTypePack>(futureError) != nullptr);
|
||||
CHECK(!futureError->persistent);
|
||||
CHECK(futureError->owningArena == &arena);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
-- This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
print('testing vector library')
|
||||
|
||||
-- detect vector size
|
||||
local vector_size = if pcall(function() return vector(0, 0, 0).w end) then 4 else 3
|
||||
|
||||
function ecall(fn, ...)
|
||||
local ok, err = pcall(fn, ...)
|
||||
assert(not ok)
|
||||
|
@ -156,4 +159,32 @@ assert(vector.clamp(vector.create(1, 1, 1), vector.create(0, 1, 2), vector.creat
|
|||
assert(vector.clamp(vector.create(1, 1, 1), vector.create(-1, -1, -1), vector.create(0, 1, 2)) == vector.create(0, 1, 1))
|
||||
assert(select("#", vector.clamp(vector.zero, vector.zero, vector.one)) == 1)
|
||||
|
||||
-- validate component access
|
||||
assert(vector.create(1, 2, 3).x == 1)
|
||||
assert(vector.create(1, 2, 3).X == 1)
|
||||
assert(vector.create(1, 2, 3)['X'] == 1)
|
||||
assert(vector.create(1, 2, 3).y == 2)
|
||||
assert(vector.create(1, 2, 3).Y == 2)
|
||||
assert(vector.create(1, 2, 3)['Y'] == 2)
|
||||
assert(vector.create(1, 2, 3).z == 3)
|
||||
assert(vector.create(1, 2, 3).Z == 3)
|
||||
assert(vector.create(1, 2, 3)['Z'] == 3)
|
||||
|
||||
local function getcomp(v: vector, field: string)
|
||||
return v[field]
|
||||
end
|
||||
|
||||
assert(getcomp(vector.create(1, 2, 3), 'x') == 1)
|
||||
assert(getcomp(vector.create(1, 2, 3), 'y') == 2)
|
||||
assert(getcomp(vector.create(1, 2, 3), 'z') == 3)
|
||||
|
||||
assert(ecall(function() return vector.create(1, 2, 3).zz end) == "attempt to index vector with 'zz'")
|
||||
|
||||
-- additional checks for 4-component vectors
|
||||
if vector_size == 4 then
|
||||
assert(vector.create(1, 2, 3, 4).w == 4)
|
||||
assert(vector.create(1, 2, 3, 4).W == 4)
|
||||
assert(vector.create(1, 2, 3, 4)['W'] == 4)
|
||||
end
|
||||
|
||||
return 'OK'
|
||||
|
|
Loading…
Add table
Reference in a new issue