mirror of
https://github.com/luau-lang/luau.git
synced 2025-08-26 11:27:08 +01:00
Sync to upstream/release/678 (#1878)
# What's Changed? We've been hard at work fixing bugs in the new type solver and getting it ready to go! ## Native Codegen * Specialized Luau Codegen instruction for fetching an import. As a reminder, an import is an expression like `global.thing` and covers stuff like libraries without fastcalls `coroutine.resume`) and atomic extern libraries. ## New Type Solver * Fix an issue that prevented eager generalization from working properly with OO styled code. * Avoid copying uninitialized memory in Luau attribute parsing * Improve type inference of unsealed tables. * This fixes https://github.com/luau-lang/luau/issues/1838 * and https://github.com/luau-lang/luau/issues/1859 * Infer potential singleton string keys in autocomplete when the expected index type is a union type. * Avoid creating cyclic types when reducing types of the form `t1 where t1 = refine<T, t1, Y>` * The type cloner now does the same thing for the new and old solvers. * Properly infer polarity (aka variance) for divergent table properties. (ie tables whose read type and write type are not the same) * Crash fixes. --------- Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com> Co-authored-by: Varun Saini <61795485+vrn-sn@users.noreply.github.com> Co-authored-by: Alexander Youngblood <ayoungblood@roblox.com> Co-authored-by: Menarul Alam <malam@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Vighnesh <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Ariel Weiss <aaronweiss@roblox.com>
This commit is contained in:
parent
68cdcc4a3a
commit
713ee2ff8b
120 changed files with 3114 additions and 2075 deletions
|
@ -439,9 +439,6 @@ public:
|
|||
TypeId simplifyIntersection(NotNull<Scope> scope, Location location, std::set<TypeId> parts);
|
||||
TypeId simplifyUnion(NotNull<Scope> scope, Location location, TypeId left, TypeId right);
|
||||
|
||||
TypeId errorRecoveryType() const;
|
||||
TypePackId errorRecoveryTypePack() const;
|
||||
|
||||
TypePackId anyifyModuleReturnTypePackGenerics(TypePackId tp);
|
||||
|
||||
void throwTimeLimitError() const;
|
||||
|
|
|
@ -52,6 +52,10 @@ struct ExpectedTypeVisitor : public AstVisitor
|
|||
// parameters.
|
||||
bool visit(AstExprCall* expr) override;
|
||||
|
||||
// If we have an expression like `A[B]`, then the expected type of B is
|
||||
// clearly the properties and indexer of `A`.
|
||||
bool visit(AstExprIndexExpr* expr) override;
|
||||
|
||||
// If we have an expression of type:
|
||||
//
|
||||
// return X :: Y
|
||||
|
|
|
@ -970,8 +970,6 @@ struct BuiltinTypes
|
|||
|
||||
TypeId errorRecoveryType(TypeId guess) const;
|
||||
TypePackId errorRecoveryTypePack(TypePackId guess) const;
|
||||
TypeId errorRecoveryType() const;
|
||||
TypePackId errorRecoveryTypePack() const;
|
||||
|
||||
friend TypeId makeStringMetatable(NotNull<BuiltinTypes> builtinTypes);
|
||||
friend struct GlobalTypes;
|
||||
|
|
|
@ -194,7 +194,9 @@ private:
|
|||
void explainError(TypeId subTy, TypeId superTy, Location location, const SubtypingResult& result);
|
||||
void explainError(TypePackId subTy, TypePackId superTy, Location location, const SubtypingResult& result);
|
||||
|
||||
bool testPotentialLiteralIsSubtype(AstExpr* expr, TypeId expectedTy);
|
||||
bool testLiteralOrAstTypeIsSubtype(AstExpr* expr, TypeId expectedType);
|
||||
|
||||
bool testPotentialLiteralIsSubtype(AstExpr* expr, TypeId expectedType);
|
||||
|
||||
bool testIsSubtype(TypeId subTy, TypeId superTy, Location location);
|
||||
bool testIsSubtype(TypePackId subTy, TypePackId superTy, Location location);
|
||||
|
|
|
@ -40,11 +40,11 @@ struct InConditionalContext
|
|||
TypeContext* typeContext;
|
||||
TypeContext oldValue;
|
||||
|
||||
explicit InConditionalContext(TypeContext* c)
|
||||
explicit InConditionalContext(TypeContext* c, TypeContext newValue = TypeContext::Condition)
|
||||
: typeContext(c)
|
||||
, oldValue(*c)
|
||||
{
|
||||
*typeContext = TypeContext::Condition;
|
||||
*typeContext = newValue;
|
||||
}
|
||||
|
||||
~InConditionalContext()
|
||||
|
|
|
@ -483,7 +483,7 @@ static std::optional<DocumentationSymbol> checkOverloadedDocumentationSymbol(
|
|||
const Module& module,
|
||||
const TypeId ty,
|
||||
const AstExpr* parentExpr,
|
||||
const std::optional<DocumentationSymbol> documentationSymbol
|
||||
std::optional<DocumentationSymbol> documentationSymbol
|
||||
)
|
||||
{
|
||||
if (!documentationSymbol)
|
||||
|
|
|
@ -46,7 +46,7 @@ AutocompleteResult autocomplete(Frontend& frontend, const ModuleName& moduleName
|
|||
std::vector<AstNode*> ancestry = findAncestryAtPositionForAutocomplete(*sourceModule, position);
|
||||
LUAU_ASSERT(!ancestry.empty());
|
||||
ScopePtr startScope = findScopeAtPosition(*module, position);
|
||||
return autocomplete_(module, builtinTypes, &typeArena, ancestry, globalScope, startScope, position, frontend.fileResolver, callback);
|
||||
return autocomplete_(module, builtinTypes, &typeArena, ancestry, globalScope, startScope, position, frontend.fileResolver, std::move(callback));
|
||||
}
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -760,7 +760,7 @@ static bool tryAddTypeCorrectSuggestion(AutocompleteEntryMap& result, ScopePtr s
|
|||
if (!ty)
|
||||
return false;
|
||||
|
||||
if (auto name = tryGetTypeNameInScope(scope, *ty))
|
||||
if (auto name = tryGetTypeNameInScope(std::move(scope), *ty))
|
||||
{
|
||||
if (auto it = result.find(*name); it != result.end())
|
||||
it->second.typeCorrect = TypeCorrectKind::Correct;
|
||||
|
@ -966,7 +966,7 @@ AutocompleteEntryMap autocompleteTypeNames(
|
|||
}
|
||||
|
||||
if (inferredType)
|
||||
tryAddTypeCorrectSuggestion(result, startScope, topType, inferredType, position);
|
||||
tryAddTypeCorrectSuggestion(result, std::move(startScope), topType, inferredType, position);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -1066,7 +1066,7 @@ AutocompleteEntryMap autocompleteTypeNames(
|
|||
if (const FunctionType* ftv = tryGetExpectedFunctionType(module, node))
|
||||
{
|
||||
if (auto ty = tryGetTypePackTypeAt(ftv->retTypes, ~0u))
|
||||
tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position);
|
||||
tryAddTypeCorrectSuggestion(result, std::move(startScope), topType, *ty, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1079,7 +1079,7 @@ AutocompleteEntryMap autocompleteTypeNames(
|
|||
if (const FunctionType* ftv = tryGetExpectedFunctionType(module, node))
|
||||
{
|
||||
if (auto ty = tryGetTypePackTypeAt(ftv->retTypes, ~0u))
|
||||
tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position);
|
||||
tryAddTypeCorrectSuggestion(result, std::move(startScope), topType, *ty, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1115,7 +1115,7 @@ AutocompleteEntryMap autocompleteTypeNames(
|
|||
if (const FunctionType* ftv = tryGetExpectedFunctionType(module, node))
|
||||
{
|
||||
if (auto ty = tryGetTypePackTypeAt(ftv->retTypes, ~0u))
|
||||
tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position);
|
||||
tryAddTypeCorrectSuggestion(result, std::move(startScope), topType, *ty, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1485,7 +1485,7 @@ static AutocompleteResult autocompleteExpression(
|
|||
{
|
||||
AutocompleteEntryMap result;
|
||||
AutocompleteContext context = autocompleteExpression(module, builtinTypes, typeArena, ancestry, scopeAtPosition, position, result);
|
||||
return {result, ancestry, context};
|
||||
return {std::move(result), ancestry, context};
|
||||
}
|
||||
|
||||
static std::optional<const ExternType*> getMethodContainingExternType(const ModulePtr& module, AstExpr* funcExpr)
|
||||
|
@ -2025,7 +2025,7 @@ AutocompleteResult autocomplete_(
|
|||
if (!key)
|
||||
autocompleteExpression(*module, builtinTypes, typeArena, ancestry, scopeAtPosition, position, result);
|
||||
|
||||
return {result, ancestry, AutocompleteContext::Property};
|
||||
return {std::move(result), ancestry, AutocompleteContext::Property};
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -2061,12 +2061,12 @@ AutocompleteResult autocomplete_(
|
|||
// Also offer general expression suggestions
|
||||
autocompleteExpression(*module, builtinTypes, typeArena, ancestry, scopeAtPosition, position, result);
|
||||
|
||||
return {result, ancestry, AutocompleteContext::Property};
|
||||
return {std::move(result), ancestry, AutocompleteContext::Property};
|
||||
}
|
||||
else if (isIdentifier(node) && (parent->is<AstStatExpr>() || parent->is<AstStatError>()))
|
||||
return {autocompleteStatement(*module, ancestry, scopeAtPosition, position), ancestry, AutocompleteContext::Statement};
|
||||
|
||||
if (std::optional<AutocompleteEntryMap> ret = autocompleteStringParams(module, ancestry, position, fileResolver, callback))
|
||||
if (std::optional<AutocompleteEntryMap> ret = autocompleteStringParams(module, ancestry, position, fileResolver, std::move(callback)))
|
||||
{
|
||||
return {*ret, ancestry, AutocompleteContext::String};
|
||||
}
|
||||
|
@ -2094,14 +2094,14 @@ AutocompleteResult autocomplete_(
|
|||
}
|
||||
}
|
||||
|
||||
return {result, ancestry, AutocompleteContext::String};
|
||||
return {std::move(result), ancestry, AutocompleteContext::String};
|
||||
}
|
||||
else if (stringPartOfInterpString(node, position))
|
||||
{
|
||||
// We're not a simple interpolated string, we're something like `a{"b"}@1`, and we
|
||||
// can't know what to format to
|
||||
AutocompleteEntryMap map;
|
||||
return {map, ancestry, AutocompleteContext::String};
|
||||
return {std::move(map), ancestry, AutocompleteContext::String};
|
||||
}
|
||||
|
||||
if (node->is<AstExprConstantNumber>())
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
*/
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTableCloneClonesType3)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStringFormatImprovements)
|
||||
LUAU_FASTFLAGVARIABLE(LuauMagicFreezeCheckBlocked2)
|
||||
|
@ -238,7 +238,7 @@ void addGlobalBinding(GlobalTypes& globals, const std::string& name, TypeId ty,
|
|||
|
||||
void addGlobalBinding(GlobalTypes& globals, const std::string& name, Binding binding)
|
||||
{
|
||||
addGlobalBinding(globals, globals.globalScope, name, binding);
|
||||
addGlobalBinding(globals, globals.globalScope, name, std::move(binding));
|
||||
}
|
||||
|
||||
void addGlobalBinding(GlobalTypes& globals, const ScopePtr& scope, const std::string& name, TypeId ty, const std::string& packageName)
|
||||
|
@ -312,8 +312,8 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
|
|||
|
||||
TypeArena& arena = globals.globalTypes;
|
||||
NotNull<BuiltinTypes> builtinTypes = globals.builtinTypes;
|
||||
Scope* globalScope = nullptr; // NotNull<Scope> when removing FFlag::LuauEagerGeneralization2
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
Scope* globalScope = nullptr; // NotNull<Scope> when removing FFlag::LuauEagerGeneralization4
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
globalScope = globals.globalScope.get();
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
|
@ -376,7 +376,7 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
|
|||
TypeId genericMT = arena.addType(GenericType{globalScope, "MT"});
|
||||
|
||||
TableType tab{TableState::Generic, globals.globalScope->level};
|
||||
TypeId tabTy = arena.addType(tab);
|
||||
TypeId tabTy = arena.addType(std::move(tab));
|
||||
|
||||
TypeId tableMetaMT = arena.addType(MetatableType{tabTy, genericMT});
|
||||
|
||||
|
@ -509,7 +509,7 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
|
|||
globals.globalTypeFunctionScope->builtinTypeNames = globals.globalScope->builtinTypeNames;
|
||||
|
||||
// Type function runtime also removes a few standard libraries and globals, so we will take only the ones that are defined
|
||||
static const char* typeFunctionRuntimeBindings[] = {
|
||||
static constexpr const char* typeFunctionRuntimeBindings[] = {
|
||||
// Libraries
|
||||
"math",
|
||||
"table",
|
||||
|
@ -598,7 +598,7 @@ std::optional<WithPredicate<TypePackId>> MagicFormat::handleOldSolver(
|
|||
WithPredicate<TypePackId> withPredicate
|
||||
)
|
||||
{
|
||||
auto [paramPack, _predicates] = withPredicate;
|
||||
auto [paramPack, _predicates] = std::move(withPredicate);
|
||||
|
||||
TypeArena& arena = typechecker.currentModule->internalTypes;
|
||||
|
||||
|
@ -959,7 +959,7 @@ std::optional<WithPredicate<TypePackId>> MagicGmatch::handleOldSolver(
|
|||
WithPredicate<TypePackId> withPredicate
|
||||
)
|
||||
{
|
||||
auto [paramPack, _predicates] = withPredicate;
|
||||
auto [paramPack, _predicates] = std::move(withPredicate);
|
||||
const auto& [params, tail] = flatten(paramPack);
|
||||
|
||||
if (params.size() != 2)
|
||||
|
@ -983,7 +983,7 @@ std::optional<WithPredicate<TypePackId>> MagicGmatch::handleOldSolver(
|
|||
typechecker.unify(params[0], typechecker.stringType, scope, expr.args.data[0]->location);
|
||||
|
||||
const TypePackId emptyPack = arena.addTypePack({});
|
||||
const TypePackId returnList = arena.addTypePack(returnTypes);
|
||||
const TypePackId returnList = arena.addTypePack(std::move(returnTypes));
|
||||
const TypeId iteratorType = arena.addType(FunctionType{emptyPack, returnList});
|
||||
return WithPredicate<TypePackId>{arena.addTypePack({iteratorType})};
|
||||
}
|
||||
|
@ -1013,7 +1013,7 @@ bool MagicGmatch::infer(const MagicFunctionCallContext& context)
|
|||
context.solver->unify(context.constraint, params[0], context.solver->builtinTypes->stringType);
|
||||
|
||||
const TypePackId emptyPack = arena->addTypePack({});
|
||||
const TypePackId returnList = arena->addTypePack(returnTypes);
|
||||
const TypePackId returnList = arena->addTypePack(std::move(returnTypes));
|
||||
const TypeId iteratorType = arena->addType(FunctionType{emptyPack, returnList});
|
||||
const TypePackId resTypePack = arena->addTypePack({iteratorType});
|
||||
asMutable(context.result)->ty.emplace<BoundTypePack>(resTypePack);
|
||||
|
@ -1028,7 +1028,7 @@ std::optional<WithPredicate<TypePackId>> MagicMatch::handleOldSolver(
|
|||
WithPredicate<TypePackId> withPredicate
|
||||
)
|
||||
{
|
||||
auto [paramPack, _predicates] = withPredicate;
|
||||
auto [paramPack, _predicates] = std::move(withPredicate);
|
||||
const auto& [params, tail] = flatten(paramPack);
|
||||
|
||||
if (params.size() < 2 || params.size() > 3)
|
||||
|
@ -1057,7 +1057,7 @@ std::optional<WithPredicate<TypePackId>> MagicMatch::handleOldSolver(
|
|||
if (params.size() == 3 && expr.args.size > initIndex)
|
||||
typechecker.unify(params[2], optionalNumber, scope, expr.args.data[initIndex]->location);
|
||||
|
||||
const TypePackId returnList = arena.addTypePack(returnTypes);
|
||||
const TypePackId returnList = arena.addTypePack(std::move(returnTypes));
|
||||
return WithPredicate<TypePackId>{returnList};
|
||||
}
|
||||
|
||||
|
@ -1091,7 +1091,7 @@ bool MagicMatch::infer(const MagicFunctionCallContext& context)
|
|||
if (params.size() == 3 && context.callSite->args.size > initIndex)
|
||||
context.solver->unify(context.constraint, params[2], optionalNumber);
|
||||
|
||||
const TypePackId returnList = arena->addTypePack(returnTypes);
|
||||
const TypePackId returnList = arena->addTypePack(std::move(returnTypes));
|
||||
asMutable(context.result)->ty.emplace<BoundTypePack>(returnList);
|
||||
|
||||
return true;
|
||||
|
@ -1104,7 +1104,7 @@ std::optional<WithPredicate<TypePackId>> MagicFind::handleOldSolver(
|
|||
WithPredicate<TypePackId> withPredicate
|
||||
)
|
||||
{
|
||||
auto [paramPack, _predicates] = withPredicate;
|
||||
auto [paramPack, _predicates] = std::move(withPredicate);
|
||||
const auto& [params, tail] = flatten(paramPack);
|
||||
|
||||
if (params.size() < 2 || params.size() > 4)
|
||||
|
@ -1151,7 +1151,7 @@ std::optional<WithPredicate<TypePackId>> MagicFind::handleOldSolver(
|
|||
|
||||
returnTypes.insert(returnTypes.begin(), {optionalNumber, optionalNumber});
|
||||
|
||||
const TypePackId returnList = arena.addTypePack(returnTypes);
|
||||
const TypePackId returnList = arena.addTypePack(std::move(returnTypes));
|
||||
return WithPredicate<TypePackId>{returnList};
|
||||
}
|
||||
|
||||
|
@ -1204,7 +1204,7 @@ bool MagicFind::infer(const MagicFunctionCallContext& context)
|
|||
|
||||
returnTypes.insert(returnTypes.begin(), {optionalNumber, optionalNumber});
|
||||
|
||||
const TypePackId returnList = arena->addTypePack(returnTypes);
|
||||
const TypePackId returnList = arena->addTypePack(std::move(returnTypes));
|
||||
asMutable(context.result)->ty.emplace<BoundTypePack>(returnList);
|
||||
return true;
|
||||
}
|
||||
|
@ -1233,7 +1233,7 @@ TypeId makeStringMetatable(NotNull<BuiltinTypes> builtinTypes)
|
|||
|
||||
FunctionType formatFTV{arena->addTypePack(TypePack{{stringType}, variadicTailPack}), oneStringPack};
|
||||
formatFTV.isCheckedFunction = true;
|
||||
const TypeId formatFn = arena->addType(formatFTV);
|
||||
const TypeId formatFn = arena->addType(std::move(formatFTV));
|
||||
attachMagicFunction(formatFn, std::make_shared<MagicFormat>());
|
||||
|
||||
|
||||
|
@ -1254,7 +1254,7 @@ TypeId makeStringMetatable(NotNull<BuiltinTypes> builtinTypes)
|
|||
arena->addTypePack({stringType, stringType, optionalNumber}), arena->addTypePack(TypePackVar{VariadicTypePack{stringType}})
|
||||
};
|
||||
matchFuncTy.isCheckedFunction = true;
|
||||
const TypeId matchFunc = arena->addType(matchFuncTy);
|
||||
const TypeId matchFunc = arena->addType(std::move(matchFuncTy));
|
||||
attachMagicFunction(matchFunc, std::make_shared<MagicMatch>());
|
||||
|
||||
FunctionType findFuncTy{
|
||||
|
@ -1262,7 +1262,7 @@ TypeId makeStringMetatable(NotNull<BuiltinTypes> builtinTypes)
|
|||
arena->addTypePack(TypePack{{optionalNumber, optionalNumber}, stringVariadicList})
|
||||
};
|
||||
findFuncTy.isCheckedFunction = true;
|
||||
const TypeId findFunc = arena->addType(findFuncTy);
|
||||
const TypeId findFunc = arena->addType(std::move(findFuncTy));
|
||||
attachMagicFunction(findFunc, std::make_shared<MagicFind>());
|
||||
|
||||
// string.byte : string -> number? -> number? -> ...number
|
||||
|
@ -1281,8 +1281,8 @@ TypeId makeStringMetatable(NotNull<BuiltinTypes> builtinTypes)
|
|||
stringDotUnpack.isCheckedFunction = true;
|
||||
|
||||
TableType::Props stringLib = {
|
||||
{"byte", {arena->addType(stringDotByte)}},
|
||||
{"char", {arena->addType(stringDotChar)}},
|
||||
{"byte", {arena->addType(std::move(stringDotByte))}},
|
||||
{"char", {arena->addType(std::move(stringDotChar))}},
|
||||
{"find", {findFunc}},
|
||||
{"format", {formatFn}}, // FIXME
|
||||
{"gmatch", {gmatchFunc}},
|
||||
|
@ -1311,7 +1311,7 @@ TypeId makeStringMetatable(NotNull<BuiltinTypes> builtinTypes)
|
|||
oneStringPack,
|
||||
})}},
|
||||
{"packsize", {makeFunction(*arena, stringType, {}, {}, {}, {}, {numberType}, /* checked */ true)}},
|
||||
{"unpack", {arena->addType(stringDotUnpack)}},
|
||||
{"unpack", {arena->addType(std::move(stringDotUnpack))}},
|
||||
};
|
||||
|
||||
assignPropDocumentationSymbols(stringLib, "@luau/global/string");
|
||||
|
@ -1331,7 +1331,7 @@ std::optional<WithPredicate<TypePackId>> MagicSelect::handleOldSolver(
|
|||
WithPredicate<TypePackId> withPredicate
|
||||
)
|
||||
{
|
||||
auto [paramPack, _predicates] = withPredicate;
|
||||
auto [paramPack, _predicates] = std::move(withPredicate);
|
||||
|
||||
(void)scope;
|
||||
|
||||
|
@ -1421,7 +1421,7 @@ std::optional<WithPredicate<TypePackId>> MagicSetMetatable::handleOldSolver(
|
|||
WithPredicate<TypePackId> withPredicate
|
||||
)
|
||||
{
|
||||
auto [paramPack, _predicates] = withPredicate;
|
||||
auto [paramPack, _predicates] = std::move(withPredicate);
|
||||
|
||||
if (size(paramPack) < 2 && finite(paramPack))
|
||||
return std::nullopt;
|
||||
|
@ -1455,7 +1455,7 @@ std::optional<WithPredicate<TypePackId>> MagicSetMetatable::handleOldSolver(
|
|||
mtv.syntheticName = tableName;
|
||||
}
|
||||
|
||||
TypeId mtTy = arena.addType(mtv);
|
||||
TypeId mtTy = arena.addType(std::move(mtv));
|
||||
|
||||
if (expr.args.size < 1)
|
||||
return std::nullopt;
|
||||
|
@ -1508,7 +1508,7 @@ std::optional<WithPredicate<TypePackId>> MagicAssert::handleOldSolver(
|
|||
WithPredicate<TypePackId> withPredicate
|
||||
)
|
||||
{
|
||||
auto [paramPack, predicates] = withPredicate;
|
||||
auto [paramPack, predicates] = std::move(withPredicate);
|
||||
|
||||
TypeArena& arena = typechecker.currentModule->internalTypes;
|
||||
|
||||
|
@ -1547,7 +1547,7 @@ std::optional<WithPredicate<TypePackId>> MagicPack::handleOldSolver(
|
|||
WithPredicate<TypePackId> withPredicate
|
||||
)
|
||||
{
|
||||
auto [paramPack, _predicates] = withPredicate;
|
||||
auto [paramPack, _predicates] = std::move(withPredicate);
|
||||
|
||||
TypeArena& arena = typechecker.currentModule->internalTypes;
|
||||
|
||||
|
@ -1632,7 +1632,7 @@ std::optional<WithPredicate<TypePackId>> MagicClone::handleOldSolver(
|
|||
{
|
||||
LUAU_ASSERT(FFlag::LuauTableCloneClonesType3);
|
||||
|
||||
auto [paramPack, _predicates] = withPredicate;
|
||||
auto [paramPack, _predicates] = std::move(withPredicate);
|
||||
|
||||
TypeArena& arena = typechecker.currentModule->internalTypes;
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
|
||||
// For each `Luau::clone` call, we will clone only up to N amount of types _and_ packs, as controlled by this limit.
|
||||
LUAU_FASTINTVARIABLE(LuauTypeCloneIterationLimit, 100'000)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSolverAgnosticClone)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -73,12 +75,12 @@ public:
|
|||
|
||||
if (hasExceededIterationLimit())
|
||||
{
|
||||
TypeId error = builtinTypes->errorRecoveryType();
|
||||
TypeId error = builtinTypes->errorType;
|
||||
(*types)[ty] = error;
|
||||
return error;
|
||||
}
|
||||
|
||||
return find(ty).value_or(builtinTypes->errorRecoveryType());
|
||||
return find(ty).value_or(builtinTypes->errorType);
|
||||
}
|
||||
|
||||
TypePackId clone(TypePackId tp)
|
||||
|
@ -88,12 +90,12 @@ public:
|
|||
|
||||
if (hasExceededIterationLimit())
|
||||
{
|
||||
TypePackId error = builtinTypes->errorRecoveryTypePack();
|
||||
TypePackId error = builtinTypes->errorTypePack;
|
||||
(*packs)[tp] = error;
|
||||
return error;
|
||||
}
|
||||
|
||||
return find(tp).value_or(builtinTypes->errorRecoveryTypePack());
|
||||
return find(tp).value_or(builtinTypes->errorTypePack);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -208,7 +210,7 @@ public:
|
|||
private:
|
||||
Property shallowClone(const Property& p)
|
||||
{
|
||||
if (FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauSolverV2 || FFlag::LuauSolverAgnosticClone)
|
||||
{
|
||||
std::optional<TypeId> cloneReadTy;
|
||||
if (auto ty = p.readTy)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "Luau/Constraint.h"
|
||||
#include "Luau/VisitType.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -43,6 +43,17 @@ struct ReferenceCountInitializer : TypeOnceVisitor
|
|||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const TableType& tt) override
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (tt.state == TableState::Unsealed || tt.state == TableState::Free)
|
||||
result->insert(ty);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const ExternType&) override
|
||||
{
|
||||
// ExternTypes never contain free types.
|
||||
|
@ -51,12 +62,18 @@ struct ReferenceCountInitializer : TypeOnceVisitor
|
|||
|
||||
bool visit(TypeId, const TypeFunctionInstanceType&) override
|
||||
{
|
||||
return FFlag::LuauEagerGeneralization3 && traverseIntoTypeFunctions;
|
||||
return FFlag::LuauEagerGeneralization4 && traverseIntoTypeFunctions;
|
||||
}
|
||||
};
|
||||
|
||||
bool isReferenceCountedType(const TypeId typ)
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (auto tt = get<TableType>(typ))
|
||||
return tt->state == TableState::Free || tt->state == TableState::Unsealed;
|
||||
}
|
||||
|
||||
// n.b. this should match whatever `ReferenceCountInitializer` includes.
|
||||
return get<FreeType>(typ) || get<BlockedType>(typ) || get<PendingExpansionType>(typ);
|
||||
}
|
||||
|
@ -104,7 +121,7 @@ DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
|
|||
{
|
||||
rci.traverse(fchc->argsPack);
|
||||
}
|
||||
else if (auto fcc = get<FunctionCallConstraint>(*this); fcc && FFlag::LuauEagerGeneralization3)
|
||||
else if (auto fcc = get<FunctionCallConstraint>(*this); fcc && FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
rci.traverseIntoTypeFunctions = false;
|
||||
rci.traverse(fcc->fn);
|
||||
|
@ -118,12 +135,12 @@ DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
|
|||
else if (auto hpc = get<HasPropConstraint>(*this))
|
||||
{
|
||||
rci.traverse(hpc->resultType);
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
rci.traverse(hpc->subjectType);
|
||||
}
|
||||
else if (auto hic = get<HasIndexerConstraint>(*this))
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
rci.traverse(hic->subjectType);
|
||||
rci.traverse(hic->resultType);
|
||||
// `HasIndexerConstraint` should not mutate `indexType`.
|
||||
|
|
|
@ -34,8 +34,8 @@
|
|||
LUAU_FASTINT(LuauCheckRecursionLimit)
|
||||
LUAU_FASTFLAG(DebugLuauLogSolverToJson)
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauStoreReturnTypesAsPackOnAst)
|
||||
LUAU_FASTFLAG(LuauGlobalVariableModuleIsolation)
|
||||
LUAU_FASTFLAGVARIABLE(LuauEnableWriteOnlyProperties)
|
||||
|
@ -43,12 +43,14 @@ LUAU_FASTFLAG(LuauAddCallConstraintForIterableFunctions)
|
|||
LUAU_FASTFLAG(LuauDoNotAddUpvalueTypesToLocalType)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAvoidDoubleNegation)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSimplifyOutOfLine2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauDfgAllowUpdatesInLoops)
|
||||
LUAU_FASTFLAGVARIABLE(LuauDisablePrimitiveInferenceInLargeTables)
|
||||
LUAU_FASTINTVARIABLE(LuauPrimitiveInferenceInTableLimit, 500)
|
||||
LUAU_FASTFLAGVARIABLE(LuauUserTypeFunctionAliases)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSkipLvalueForCompoundAssignment)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFollowTypeAlias)
|
||||
LUAU_FASTFLAGVARIABLE(LuauFollowExistingTypeFunction)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -256,7 +258,7 @@ void ConstraintGenerator::visitModuleRoot(AstStatBlock* block)
|
|||
rootScope->location = block->location;
|
||||
module->astScopes[block] = NotNull{scope.get()};
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
interiorFreeTypes.emplace_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.emplace_back();
|
||||
|
@ -292,7 +294,7 @@ void ConstraintGenerator::visitModuleRoot(AstStatBlock* block)
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
scope->interiorFreeTypes = std::move(interiorFreeTypes.back().types);
|
||||
scope->interiorFreeTypePacks = std::move(interiorFreeTypes.back().typePacks);
|
||||
|
@ -311,7 +313,7 @@ void ConstraintGenerator::visitModuleRoot(AstStatBlock* block)
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
interiorFreeTypes.pop_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.pop_back();
|
||||
|
@ -349,13 +351,13 @@ void ConstraintGenerator::visitFragmentRoot(const ScopePtr& resumeScope, AstStat
|
|||
// We prepopulate global data in the resumeScope to avoid writing data into the old modules scopes
|
||||
prepopulateGlobalScopeForFragmentTypecheck(globalScope, resumeScope, block);
|
||||
// Pre
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
interiorFreeTypes.emplace_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.emplace_back();
|
||||
visitBlockWithoutChildScope(resumeScope, block);
|
||||
// Post
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
interiorFreeTypes.pop_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.pop_back();
|
||||
|
@ -385,12 +387,12 @@ void ConstraintGenerator::visitFragmentRoot(const ScopePtr& resumeScope, AstStat
|
|||
|
||||
TypeId ConstraintGenerator::freshType(const ScopePtr& scope, Polarity polarity)
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
auto ft = Luau::freshType(arena, builtinTypes, scope.get(), polarity);
|
||||
interiorFreeTypes.back().types.push_back(ft);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
freeTypes.insert(ft);
|
||||
|
||||
return ft;
|
||||
|
@ -407,7 +409,7 @@ TypePackId ConstraintGenerator::freshTypePack(const ScopePtr& scope, Polarity po
|
|||
{
|
||||
FreeTypePack f{scope.get(), polarity};
|
||||
TypePackId result = arena->addTypePack(TypePackVar{std::move(f)});
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
interiorFreeTypes.back().typePacks.push_back(result);
|
||||
return result;
|
||||
}
|
||||
|
@ -708,7 +710,7 @@ void ConstraintGenerator::applyRefinements(const ScopePtr& scope, Location locat
|
|||
const TypeFunction& func = kind == RefinementsOpKind::Intersect ? builtinTypeFunctions().intersectFunc : builtinTypeFunctions().refineFunc;
|
||||
LUAU_ASSERT(!func.name.empty());
|
||||
args.insert(args.end(), discriminants.begin(), discriminants.end());
|
||||
TypeId resultType = createTypeFunctionInstance(func, args, {}, scope, location);
|
||||
TypeId resultType = createTypeFunctionInstance(func, std::move(args), {}, scope, location);
|
||||
discriminants.clear();
|
||||
return resultType;
|
||||
};
|
||||
|
@ -945,7 +947,8 @@ void ConstraintGenerator::checkAliases(const ScopePtr& scope, AstStatBlock* bloc
|
|||
auto addToEnvironment =
|
||||
[this, &globalNameCollector](UserDefinedFunctionData& userFuncData, ScopePtr scope, const Name& name, TypeFun tf, size_t level)
|
||||
{
|
||||
if (auto ty = get<TypeFunctionInstanceType>(tf.type); ty && ty->userFuncData.definition)
|
||||
if (auto ty = get<TypeFunctionInstanceType>(FFlag::LuauFollowTypeAlias ? follow(tf.type) : tf.type);
|
||||
ty && ty->userFuncData.definition)
|
||||
{
|
||||
if (userFuncData.environmentFunction.find(name))
|
||||
return;
|
||||
|
@ -958,7 +961,8 @@ void ConstraintGenerator::checkAliases(const ScopePtr& scope, AstStatBlock* bloc
|
|||
scope->bindings[ty->userFuncData.definition->name] = Binding{existing->typeId, ty->userFuncData.definition->location};
|
||||
}
|
||||
}
|
||||
else if (FFlag::LuauUserTypeFunctionAliases && !get<TypeFunctionInstanceType>(tf.type))
|
||||
else if (FFlag::LuauUserTypeFunctionAliases &&
|
||||
!get<TypeFunctionInstanceType>(FFlag::LuauFollowTypeAlias ? follow(tf.type) : tf.type))
|
||||
{
|
||||
if (userFuncData.environmentAlias.find(name))
|
||||
return;
|
||||
|
@ -1417,7 +1421,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatLocalFuncti
|
|||
FunctionSignature sig = checkFunctionSignature(scope, function->func, /* expectedType */ std::nullopt, function->name->location);
|
||||
sig.bodyScope->bindings[function->name] = Binding{sig.signature, function->name->location};
|
||||
|
||||
bool sigFullyDefined = FFlag::LuauEagerGeneralization3 ? false : !hasFreeType(sig.signature);
|
||||
bool sigFullyDefined = FFlag::LuauEagerGeneralization4 ? false : !hasFreeType(sig.signature);
|
||||
if (sigFullyDefined)
|
||||
emplaceType<BoundType>(asMutable(functionType), sig.signature);
|
||||
|
||||
|
@ -1477,7 +1481,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatFunction* f
|
|||
|
||||
Checkpoint start = checkpoint(this);
|
||||
FunctionSignature sig = checkFunctionSignature(scope, function->func, /* expectedType */ std::nullopt, function->name->location);
|
||||
bool sigFullyDefined = FFlag::LuauEagerGeneralization3 ? false : !hasFreeType(sig.signature);
|
||||
bool sigFullyDefined = FFlag::LuauEagerGeneralization4 ? false : !hasFreeType(sig.signature);
|
||||
|
||||
DefId def = dfg->getDef(function->name);
|
||||
|
||||
|
@ -1564,7 +1568,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatFunction* f
|
|||
}
|
||||
else if (AstExprError* err = function->name->as<AstExprError>())
|
||||
{
|
||||
generalizedType = builtinTypes->errorRecoveryType();
|
||||
generalizedType = builtinTypes->errorType;
|
||||
}
|
||||
|
||||
if (generalizedType == nullptr)
|
||||
|
@ -1794,7 +1798,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeFunctio
|
|||
// Place this function as a child of the non-type function scope
|
||||
scope->children.push_back(NotNull{sig.signatureScope.get()});
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
interiorFreeTypes.emplace_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.push_back(std::vector<TypeId>{});
|
||||
|
@ -1812,7 +1816,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeFunctio
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
sig.signatureScope->interiorFreeTypes = std::move(interiorFreeTypes.back().types);
|
||||
sig.signatureScope->interiorFreeTypePacks = std::move(interiorFreeTypes.back().typePacks);
|
||||
|
@ -1821,7 +1825,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeFunctio
|
|||
sig.signatureScope->interiorFreeTypes = std::move(DEPRECATED_interiorTypes.back());
|
||||
|
||||
getMutable<BlockedType>(generalizedTy)->setOwner(gc);
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
interiorFreeTypes.pop_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.pop_back();
|
||||
|
@ -1850,8 +1854,18 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeFunctio
|
|||
if (!existingFunctionTy)
|
||||
ice->ice("checkAliases did not populate type function name", function->nameLocation);
|
||||
|
||||
if (FFlag::LuauFollowExistingTypeFunction)
|
||||
{
|
||||
TypeId unpackedTy = follow(*existingFunctionTy);
|
||||
|
||||
if (auto bt = get<BlockedType>(unpackedTy); bt && nullptr == bt->getOwner())
|
||||
emplaceType<BoundType>(asMutable(unpackedTy), generalizedTy);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto bt = get<BlockedType>(*existingFunctionTy); bt && nullptr == bt->getOwner())
|
||||
emplaceType<BoundType>(asMutable(*existingFunctionTy), generalizedTy);
|
||||
}
|
||||
|
||||
return ControlFlow::None;
|
||||
}
|
||||
|
@ -1896,7 +1910,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareExte
|
|||
|
||||
if (!lookupType)
|
||||
{
|
||||
reportError(declaredExternType->location, UnknownSymbol{superName, UnknownSymbol::Type});
|
||||
reportError(declaredExternType->location, UnknownSymbol{std::move(superName), UnknownSymbol::Type});
|
||||
return ControlFlow::None;
|
||||
}
|
||||
|
||||
|
@ -1918,7 +1932,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareExte
|
|||
|
||||
Name className(declaredExternType->name.value);
|
||||
|
||||
TypeId externTy = arena->addType(ExternType(className, {}, superTy, std::nullopt, {}, {}, module->name, declaredExternType->location));
|
||||
TypeId externTy = arena->addType(ExternType(std::move(className), {}, superTy, std::nullopt, {}, {}, module->name, declaredExternType->location));
|
||||
ExternType* etv = getMutable<ExternType>(externTy);
|
||||
|
||||
TypeId metaTy = arena->addType(TableType{TableState::Sealed, scope->level, scope.get()});
|
||||
|
@ -2120,7 +2134,7 @@ InferencePack ConstraintGenerator::checkPack(
|
|||
if (recursionCount >= FInt::LuauCheckRecursionLimit)
|
||||
{
|
||||
reportCodeTooComplex(expr->location);
|
||||
return InferencePack{builtinTypes->errorRecoveryTypePack()};
|
||||
return InferencePack{builtinTypes->errorTypePack};
|
||||
}
|
||||
|
||||
InferencePack result;
|
||||
|
@ -2132,7 +2146,7 @@ InferencePack ConstraintGenerator::checkPack(
|
|||
if (scope->varargPack)
|
||||
result = InferencePack{*scope->varargPack};
|
||||
else
|
||||
result = InferencePack{builtinTypes->errorRecoveryTypePack()};
|
||||
result = InferencePack{builtinTypes->errorTypePack};
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2189,7 +2203,14 @@ InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstExprCall*
|
|||
|
||||
Checkpoint funcBeginCheckpoint = checkpoint(this);
|
||||
|
||||
TypeId fnType = check(scope, call->func).ty;
|
||||
TypeId fnType = nullptr;
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
InConditionalContext icc2{&typeContext, TypeContext::Default};
|
||||
fnType = check(scope, call->func).ty;
|
||||
}
|
||||
else
|
||||
fnType = check(scope, call->func).ty;
|
||||
|
||||
Checkpoint funcEndCheckpoint = checkpoint(this);
|
||||
|
||||
|
@ -2273,7 +2294,7 @@ InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstExprCall*
|
|||
mt = arena->addType(BlockedType{});
|
||||
unpackedTypes.emplace_back(mt);
|
||||
|
||||
auto c = addConstraint(scope, call->location, UnpackConstraint{unpackedTypes, *argTail});
|
||||
auto c = addConstraint(scope, call->location, UnpackConstraint{std::move(unpackedTypes), *argTail});
|
||||
getMutable<BlockedType>(mt)->setOwner(c);
|
||||
if (auto b = getMutable<BlockedType>(target); b && b->getOwner() == nullptr)
|
||||
b->setOwner(c);
|
||||
|
@ -2402,7 +2423,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExpr* expr, std::
|
|||
if (recursionCount >= FInt::LuauCheckRecursionLimit)
|
||||
{
|
||||
reportCodeTooComplex(expr->location);
|
||||
return Inference{builtinTypes->errorRecoveryType()};
|
||||
return Inference{builtinTypes->errorType};
|
||||
}
|
||||
|
||||
// We may recurse a given expression more than once when checking compound
|
||||
|
@ -2459,7 +2480,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExpr* expr, std::
|
|||
for (AstExpr* subExpr : err->expressions)
|
||||
check(scope, subExpr);
|
||||
|
||||
result = Inference{builtinTypes->errorRecoveryType()};
|
||||
result = Inference{builtinTypes->errorType};
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2491,7 +2512,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprConstantStrin
|
|||
return Inference{builtinTypes->stringType};
|
||||
|
||||
TypeId freeTy = nullptr;
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
freeTy = freshType(scope, Polarity::Positive);
|
||||
FreeType* ft = getMutable<FreeType>(freeTy);
|
||||
|
@ -2532,7 +2553,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprConstantBool*
|
|||
return Inference{builtinTypes->booleanType};
|
||||
|
||||
TypeId freeTy = nullptr;
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
freeTy = freshType(scope, Polarity::Positive);
|
||||
FreeType* ft = getMutable<FreeType>(freeTy);
|
||||
|
@ -2591,7 +2612,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprGlobal* globa
|
|||
return Inference{*ty, refinementArena.proposition(key, builtinTypes->truthyType)};
|
||||
}
|
||||
else
|
||||
return Inference{builtinTypes->errorRecoveryType()};
|
||||
return Inference{builtinTypes->errorType};
|
||||
}
|
||||
|
||||
Inference ConstraintGenerator::checkIndexName(
|
||||
|
@ -2688,10 +2709,14 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIndexExpr* in
|
|||
|
||||
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprFunction* func, std::optional<TypeId> expectedType, bool generalize)
|
||||
{
|
||||
std::optional<InConditionalContext> inContext;
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
inContext.emplace(&typeContext, TypeContext::Default);
|
||||
|
||||
Checkpoint startCheckpoint = checkpoint(this);
|
||||
FunctionSignature sig = checkFunctionSignature(scope, func, expectedType);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
interiorFreeTypes.emplace_back();
|
||||
else
|
||||
DEPRECATED_interiorTypes.push_back(std::vector<TypeId>{});
|
||||
|
@ -2709,7 +2734,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprFunction* fun
|
|||
}
|
||||
);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
sig.signatureScope->interiorFreeTypes = std::move(interiorFreeTypes.back().types);
|
||||
sig.signatureScope->interiorFreeTypePacks = std::move(interiorFreeTypes.back().typePacks);
|
||||
|
@ -2755,6 +2780,10 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprFunction* fun
|
|||
|
||||
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprUnary* unary)
|
||||
{
|
||||
std::optional<InConditionalContext> inContext;
|
||||
if (FFlag::LuauEagerGeneralization4 && unary->op != AstExprUnary::Op::Not)
|
||||
inContext.emplace(&typeContext, TypeContext::Default);
|
||||
|
||||
auto [operandType, refinement] = check(scope, unary->expr);
|
||||
|
||||
switch (unary->op)
|
||||
|
@ -2916,6 +2945,10 @@ Inference ConstraintGenerator::checkAstExprBinary(
|
|||
|
||||
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIfElse* ifElse, std::optional<TypeId> expectedType)
|
||||
{
|
||||
std::optional<InConditionalContext> inContext;
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
inContext.emplace(&typeContext, TypeContext::Default);
|
||||
|
||||
RefinementId refinement = [&]()
|
||||
{
|
||||
InConditionalContext flipper{&typeContext};
|
||||
|
@ -2942,6 +2975,10 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTypeAssertion
|
|||
|
||||
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprInterpString* interpString)
|
||||
{
|
||||
std::optional<InConditionalContext> inContext;
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
inContext.emplace(&typeContext, TypeContext::Default);
|
||||
|
||||
for (AstExpr* expr : interpString->expressions)
|
||||
check(scope, expr);
|
||||
|
||||
|
@ -2956,6 +2993,13 @@ std::tuple<TypeId, TypeId, RefinementId> ConstraintGenerator::checkBinary(
|
|||
std::optional<TypeId> expectedType
|
||||
)
|
||||
{
|
||||
std::optional<InConditionalContext> inContext;
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (op != AstExprBinary::And && op != AstExprBinary::Or && op != AstExprBinary::CompareEq && op != AstExprBinary::CompareNe)
|
||||
inContext.emplace(&typeContext, TypeContext::Default);
|
||||
}
|
||||
|
||||
if (op == AstExprBinary::And)
|
||||
{
|
||||
std::optional<TypeId> relaxedExpectedLhs;
|
||||
|
@ -3200,6 +3244,10 @@ void ConstraintGenerator::visitLValue(const ScopePtr& scope, AstExprIndexExpr* e
|
|||
|
||||
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType)
|
||||
{
|
||||
std::optional<InConditionalContext> inContext;
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
inContext.emplace(&typeContext, TypeContext::Default);
|
||||
|
||||
TypeId ty = arena->addType(TableType{});
|
||||
TableType* ttv = getMutable<TableType>(ty);
|
||||
LUAU_ASSERT(ttv);
|
||||
|
@ -3213,7 +3261,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
|
|||
expr->items.size > size_t(FInt::LuauPrimitiveInferenceInTableLimit))
|
||||
largeTableDepth++;
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
interiorFreeTypes.back().types.push_back(ty);
|
||||
else
|
||||
DEPRECATED_interiorTypes.back().push_back(ty);
|
||||
|
@ -3306,7 +3354,7 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
|
|||
}
|
||||
}
|
||||
|
||||
if (expectedType && !FFlag::LuauTableLiteralSubtypeSpecificCheck)
|
||||
if (expectedType && !FFlag::LuauTableLiteralSubtypeSpecificCheck2)
|
||||
{
|
||||
addConstraint(
|
||||
scope,
|
||||
|
@ -3474,7 +3522,7 @@ ConstraintGenerator::FunctionSignature ConstraintGenerator::checkFunctionSignatu
|
|||
|
||||
LUAU_ASSERT(nullptr != varargPack);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
// Some of the types in argTypes will eventually be generics, and some
|
||||
// will not. The ones that are not generic will be pruned when
|
||||
|
@ -3517,7 +3565,7 @@ ConstraintGenerator::FunctionSignature ConstraintGenerator::checkFunctionSignatu
|
|||
|
||||
// TODO: Preserve argument names in the function's type.
|
||||
|
||||
FunctionType actualFunction{TypeLevel{}, arena->addTypePack(argTypes, varargPack), returnType};
|
||||
FunctionType actualFunction{TypeLevel{}, arena->addTypePack(std::move(argTypes), varargPack), returnType};
|
||||
actualFunction.generics = std::move(genericTypes);
|
||||
actualFunction.genericPacks = std::move(genericTypePacks);
|
||||
actualFunction.argNames = std::move(argNames);
|
||||
|
@ -3539,13 +3587,13 @@ ConstraintGenerator::FunctionSignature ConstraintGenerator::checkFunctionSignatu
|
|||
if (expectedType && get<FreeType>(*expectedType))
|
||||
bindFreeType(*expectedType, actualFunctionType);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
scopeToFunction[signatureScope.get()] = actualFunctionType;
|
||||
|
||||
return {
|
||||
/* signature */ actualFunctionType,
|
||||
/* signatureScope */ signatureScope,
|
||||
/* bodyScope */ bodyScope,
|
||||
/* signatureScope */ std::move(signatureScope),
|
||||
/* bodyScope */ std::move(bodyScope),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -3576,8 +3624,8 @@ TypeId ConstraintGenerator::resolveReferenceType(
|
|||
if (ref->parameters.size != 1 || !ref->parameters.data[0].type)
|
||||
{
|
||||
reportError(ty->location, GenericError{"_luau_print requires one generic parameter"});
|
||||
module->astResolvedTypes[ty] = builtinTypes->errorRecoveryType();
|
||||
return builtinTypes->errorRecoveryType();
|
||||
module->astResolvedTypes[ty] = builtinTypes->errorType;
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
else
|
||||
return resolveType_(scope, ref->parameters.data[0].type, inTypeArguments);
|
||||
|
@ -3633,7 +3681,7 @@ TypeId ConstraintGenerator::resolveReferenceType(
|
|||
}
|
||||
}
|
||||
|
||||
result = arena->addType(PendingExpansionType{ref->prefix, ref->name, parameters, packParameters});
|
||||
result = arena->addType(PendingExpansionType{ref->prefix, ref->name, std::move(parameters), std::move(packParameters)});
|
||||
|
||||
// If we're not in a type argument context, we need to create a constraint that expands this.
|
||||
// The dispatching of the above constraint will queue up additional constraints for nested
|
||||
|
@ -3644,7 +3692,7 @@ TypeId ConstraintGenerator::resolveReferenceType(
|
|||
}
|
||||
else
|
||||
{
|
||||
result = builtinTypes->errorRecoveryType();
|
||||
result = builtinTypes->errorType;
|
||||
if (replaceErrorWithFresh)
|
||||
result = freshType(scope, Polarity::Mixed);
|
||||
}
|
||||
|
@ -3840,7 +3888,7 @@ TypeId ConstraintGenerator::resolveType_(const ScopePtr& scope, AstType* ty, boo
|
|||
parts.push_back(resolveType_(scope, part, inTypeArguments));
|
||||
}
|
||||
|
||||
result = arena->addType(UnionType{parts});
|
||||
result = arena->addType(UnionType{std::move(parts)});
|
||||
}
|
||||
}
|
||||
else if (auto intersectionAnnotation = ty->as<AstTypeIntersection>())
|
||||
|
@ -3855,7 +3903,7 @@ TypeId ConstraintGenerator::resolveType_(const ScopePtr& scope, AstType* ty, boo
|
|||
parts.push_back(resolveType_(scope, part, inTypeArguments));
|
||||
}
|
||||
|
||||
result = arena->addType(IntersectionType{parts});
|
||||
result = arena->addType(IntersectionType{std::move(parts)});
|
||||
}
|
||||
}
|
||||
else if (auto typeGroupAnnotation = ty->as<AstTypeGroup>())
|
||||
|
@ -3875,14 +3923,14 @@ TypeId ConstraintGenerator::resolveType_(const ScopePtr& scope, AstType* ty, boo
|
|||
}
|
||||
else if (ty->is<AstTypeError>())
|
||||
{
|
||||
result = builtinTypes->errorRecoveryType();
|
||||
result = builtinTypes->errorType;
|
||||
if (replaceErrorWithFresh)
|
||||
result = freshType(scope);
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(0);
|
||||
result = builtinTypes->errorRecoveryType();
|
||||
result = builtinTypes->errorType;
|
||||
}
|
||||
|
||||
module->astResolvedTypes[ty] = result;
|
||||
|
@ -3917,13 +3965,13 @@ TypePackId ConstraintGenerator::resolveTypePack_(const ScopePtr& scope, AstTypeP
|
|||
else
|
||||
{
|
||||
reportError(tp->location, UnknownSymbol{gen->genericName.value, UnknownSymbol::Context::Type});
|
||||
result = builtinTypes->errorRecoveryTypePack();
|
||||
result = builtinTypes->errorTypePack;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LUAU_ASSERT(0);
|
||||
result = builtinTypes->errorRecoveryTypePack();
|
||||
result = builtinTypes->errorTypePack;
|
||||
}
|
||||
|
||||
module->astResolvedTypePacks[tp] = result;
|
||||
|
@ -4391,7 +4439,7 @@ TypeId ConstraintGenerator::createTypeFunctionInstance(
|
|||
Location location
|
||||
)
|
||||
{
|
||||
TypeId result = arena->addTypeFunction(function, typeArguments, packArguments);
|
||||
TypeId result = arena->addTypeFunction(function, std::move(typeArguments), std::move(packArguments));
|
||||
addConstraint(scope, location, ReduceConstraint{result});
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -32,13 +32,11 @@ LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverIncludeDependencies)
|
|||
LUAU_FASTFLAGVARIABLE(DebugLuauLogBindings)
|
||||
LUAU_FASTINTVARIABLE(LuauSolverRecursionLimit, 500)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauDeprecatedAttribute)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAddCallConstraintForIterableFunctions)
|
||||
LUAU_FASTFLAGVARIABLE(LuauGuardAgainstMalformedTypeAliasExpansion2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauInsertErrorTypesIntoIndexerResult)
|
||||
LUAU_FASTFLAGVARIABLE(LuauClipVariadicAnysFromArgsToGenericFuncs2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAvoidGenericsLeakingDuringFunctionCallCheck)
|
||||
LUAU_FASTFLAGVARIABLE(LuauMissingFollowInAssignIndexConstraint)
|
||||
|
||||
|
@ -187,7 +185,7 @@ std::pair<std::vector<TypeId>, std::vector<TypePackId>> saturateArguments(
|
|||
if (!defaultTy)
|
||||
break;
|
||||
|
||||
TypeId instantiatedDefault = atf.substitute(defaultTy).value_or(builtinTypes->errorRecoveryType());
|
||||
TypeId instantiatedDefault = atf.substitute(defaultTy).value_or(builtinTypes->errorType);
|
||||
atf.typeArguments[fn.typeParams[i].ty] = instantiatedDefault;
|
||||
saturatedTypeArguments.push_back(instantiatedDefault);
|
||||
}
|
||||
|
@ -205,7 +203,7 @@ std::pair<std::vector<TypeId>, std::vector<TypePackId>> saturateArguments(
|
|||
if (!defaultTp)
|
||||
break;
|
||||
|
||||
TypePackId instantiatedDefault = atf.substitute(defaultTp).value_or(builtinTypes->errorRecoveryTypePack());
|
||||
TypePackId instantiatedDefault = atf.substitute(defaultTp).value_or(builtinTypes->errorTypePack);
|
||||
atf.typePackArguments[fn.typePackParams[i].tp] = instantiatedDefault;
|
||||
saturatedPackArguments.push_back(instantiatedDefault);
|
||||
}
|
||||
|
@ -223,12 +221,12 @@ std::pair<std::vector<TypeId>, std::vector<TypePackId>> saturateArguments(
|
|||
// even if they're missing, so we use the error type as a filler.
|
||||
for (size_t i = saturatedTypeArguments.size(); i < typesRequired; ++i)
|
||||
{
|
||||
saturatedTypeArguments.push_back(builtinTypes->errorRecoveryType());
|
||||
saturatedTypeArguments.push_back(builtinTypes->errorType);
|
||||
}
|
||||
|
||||
for (size_t i = saturatedPackArguments.size(); i < packsRequired; ++i)
|
||||
{
|
||||
saturatedPackArguments.push_back(builtinTypes->errorRecoveryTypePack());
|
||||
saturatedPackArguments.push_back(builtinTypes->errorTypePack);
|
||||
}
|
||||
|
||||
for (TypeId& arg : saturatedTypeArguments)
|
||||
|
@ -416,7 +414,7 @@ void ConstraintSolver::run()
|
|||
}
|
||||
|
||||
// Free types that have no constraints at all can be generalized right away.
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
for (TypeId ty : constraintSet.freeTypes)
|
||||
{
|
||||
|
@ -477,7 +475,7 @@ void ConstraintSolver::run()
|
|||
// expansion types, etc, so we need to follow it.
|
||||
ty = follow(ty);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (seen.contains(ty))
|
||||
continue;
|
||||
|
@ -496,7 +494,7 @@ void ConstraintSolver::run()
|
|||
if (refCount <= 1)
|
||||
unblock(ty, Location{});
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3 && refCount == 0)
|
||||
if (FFlag::LuauEagerGeneralization4 && refCount == 0)
|
||||
generalizeOneType(ty);
|
||||
}
|
||||
}
|
||||
|
@ -674,7 +672,7 @@ void ConstraintSolver::initFreeTypeTracking()
|
|||
auto [refCount, _] = unresolvedConstraints.try_insert(ty, 0);
|
||||
refCount += 1;
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
auto [it, fresh] = mutatedFreeTypeToConstraint.try_emplace(ty, nullptr);
|
||||
it->second.insert(c.get());
|
||||
|
@ -730,7 +728,7 @@ void ConstraintSolver::bind(NotNull<const Constraint> constraint, TypeId ty, Typ
|
|||
constraint, ty, constraint->scope, builtinTypes->neverType, builtinTypes->unknownType, Polarity::Mixed
|
||||
); // FIXME? Is this the right polarity?
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
trackInteriorFreeType(constraint->scope, ty);
|
||||
|
||||
return;
|
||||
|
@ -882,7 +880,7 @@ bool ConstraintSolver::tryDispatch(const GeneralizationConstraint& c, NotNull<co
|
|||
else
|
||||
{
|
||||
reportError(CodeTooComplex{}, constraint->location);
|
||||
bind(constraint, c.generalizedType, builtinTypes->errorRecoveryType());
|
||||
bind(constraint, c.generalizedType, builtinTypes->errorType);
|
||||
}
|
||||
|
||||
// We check if this member is initialized and then access it, but
|
||||
|
@ -891,7 +889,7 @@ bool ConstraintSolver::tryDispatch(const GeneralizationConstraint& c, NotNull<co
|
|||
{
|
||||
for (TypeId ty : *constraint->scope->interiorFreeTypes) // NOLINT(bugprone-unchecked-optional-access)
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
ty = follow(ty);
|
||||
if (auto freeTy = get<FreeType>(ty))
|
||||
|
@ -912,7 +910,7 @@ bool ConstraintSolver::tryDispatch(const GeneralizationConstraint& c, NotNull<co
|
|||
}
|
||||
}
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (constraint->scope->interiorFreeTypePacks)
|
||||
{
|
||||
|
@ -932,7 +930,7 @@ bool ConstraintSolver::tryDispatch(const GeneralizationConstraint& c, NotNull<co
|
|||
}
|
||||
}
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (c.noGenerics)
|
||||
{
|
||||
|
@ -1013,7 +1011,7 @@ bool ConstraintSolver::tryDispatch(const IterableConstraint& c, NotNull<const Co
|
|||
if (0 == iterator.head.size())
|
||||
{
|
||||
for (TypeId ty : c.variables)
|
||||
unify(constraint, builtinTypes->errorRecoveryType(), ty);
|
||||
unify(constraint, builtinTypes->errorType, ty);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1152,7 +1150,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
|
|||
if (FFlag::LuauGuardAgainstMalformedTypeAliasExpansion2 && occursCheck(cTarget, result))
|
||||
{
|
||||
reportError(OccursCheckFailed{}, constraint->location);
|
||||
bind(constraint, cTarget, builtinTypes->errorRecoveryType());
|
||||
bind(constraint, cTarget, builtinTypes->errorType);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1167,7 +1165,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
|
|||
if (!tf.has_value())
|
||||
{
|
||||
reportError(UnknownSymbol{petv->name.value, UnknownSymbol::Context::Type}, constraint->location);
|
||||
bindResult(errorRecoveryType());
|
||||
bindResult(builtinTypes->errorType);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1183,7 +1181,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
|
|||
if (occursCheck(lhs, rhs))
|
||||
{
|
||||
reportError(OccursCheckFailed{}, constraint->location);
|
||||
bindResult(errorRecoveryType());
|
||||
bindResult(builtinTypes->errorType);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1254,7 +1252,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
|
|||
if (itf.foundInfiniteType)
|
||||
{
|
||||
// TODO (CLI-56761): Report an error.
|
||||
bindResult(errorRecoveryType());
|
||||
bindResult(builtinTypes->errorType);
|
||||
reportError(GenericError{"Recursive type being used with different parameters"}, constraint->location);
|
||||
return true;
|
||||
}
|
||||
|
@ -1278,7 +1276,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
|
|||
if (!maybeInstantiated.has_value())
|
||||
{
|
||||
// TODO (CLI-56761): Report an error.
|
||||
bindResult(errorRecoveryType());
|
||||
bindResult(builtinTypes->errorType);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1377,7 +1375,7 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
|
|||
TypePackId argsPack = follow(c.argsPack);
|
||||
TypePackId result = follow(c.result);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (isBlocked(fn))
|
||||
return block(c.fn, constraint);
|
||||
|
@ -1401,7 +1399,7 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
|
|||
// if we're calling an error type, the result is an error type, and that's that.
|
||||
if (get<ErrorType>(fn))
|
||||
{
|
||||
bind(constraint, c.result, builtinTypes->errorRecoveryTypePack());
|
||||
bind(constraint, c.result, builtinTypes->errorTypePack);
|
||||
fillInDiscriminantTypes(constraint, c.discriminantTypes);
|
||||
return true;
|
||||
}
|
||||
|
@ -1517,7 +1515,7 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
|
|||
|
||||
const bool occursCheckPassed = u2.unify(overloadToUse, inferredTy);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
for (TypeId freeTy : u2.newFreshTypes)
|
||||
trackInteriorFreeType(constraint->scope, freeTy);
|
||||
|
@ -2084,7 +2082,7 @@ bool ConstraintSolver::tryDispatchHasIndexer(
|
|||
TypeId upperBound =
|
||||
arena->addType(TableType{/* props */ {}, TableIndexer{indexType, resultType}, TypeLevel{}, ft->scope, TableState::Unsealed});
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
TypeId sr = follow(simplifyIntersection(constraint->scope, constraint->location, ft->upperBound, upperBound));
|
||||
|
||||
|
@ -2115,7 +2113,7 @@ bool ConstraintSolver::tryDispatchHasIndexer(
|
|||
|
||||
FreeType freeResult{tt->scope, builtinTypes->neverType, builtinTypes->unknownType, Polarity::Mixed};
|
||||
emplace<FreeType>(constraint, resultType, freeResult);
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
trackInteriorFreeType(constraint->scope, resultType);
|
||||
|
||||
tt->indexer = TableIndexer{indexType, resultType};
|
||||
|
@ -2304,7 +2302,7 @@ bool ConstraintSolver::tryDispatch(const AssignPropConstraint& c, NotNull<const
|
|||
{
|
||||
auto lhsFreeUpperBound = follow(lhsFree->upperBound);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
const auto [blocked, maybeTy, isIndex] = lookupTableProp(constraint, lhsType, propName, ValueContext::LValue);
|
||||
if (!blocked.empty())
|
||||
|
@ -2424,6 +2422,10 @@ bool ConstraintSolver::tryDispatch(const AssignPropConstraint& c, NotNull<const
|
|||
|
||||
if (lhsTable->state == TableState::Unsealed || lhsTable->state == TableState::Free)
|
||||
{
|
||||
// eg if inserting a free type 'a into a table {| |}, anything that
|
||||
// might affect {| |} is now known to potentially affect 'a
|
||||
shiftReferences(lhsType, rhsType);
|
||||
|
||||
bind(constraint, c.propType, rhsType);
|
||||
Property& newProp = lhsTable->props[propName];
|
||||
newProp.readTy = rhsType;
|
||||
|
@ -2907,7 +2909,7 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl
|
|||
{
|
||||
std::vector<TypeId> expectedVariables{iteratorTable->indexer->indexType, iteratorTable->indexer->indexResultType};
|
||||
while (c.variables.size() >= expectedVariables.size())
|
||||
expectedVariables.push_back(builtinTypes->errorRecoveryType());
|
||||
expectedVariables.push_back(builtinTypes->errorType);
|
||||
|
||||
for (size_t i = 0; i < c.variables.size(); ++i)
|
||||
{
|
||||
|
@ -3216,7 +3218,7 @@ TablePropLookupResult ConstraintSolver::lookupTableProp(
|
|||
{
|
||||
const TypeId upperBound = follow(ft->upperBound);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (get<TableType>(upperBound) || get<PrimitiveType>(upperBound))
|
||||
{
|
||||
|
@ -3273,7 +3275,7 @@ TablePropLookupResult ConstraintSolver::lookupTableProp(
|
|||
}
|
||||
|
||||
if (!blocked.empty())
|
||||
return {blocked, std::nullopt};
|
||||
return {std::move(blocked), std::nullopt};
|
||||
|
||||
if (options.empty())
|
||||
return {{}, std::nullopt};
|
||||
|
@ -3310,7 +3312,7 @@ TablePropLookupResult ConstraintSolver::lookupTableProp(
|
|||
}
|
||||
|
||||
if (!blocked.empty())
|
||||
return {blocked, std::nullopt};
|
||||
return {std::move(blocked), std::nullopt};
|
||||
|
||||
if (options.empty())
|
||||
return {{}, std::nullopt};
|
||||
|
@ -3613,7 +3615,7 @@ TypeId ConstraintSolver::resolveModule(const ModuleInfo& info, const Location& l
|
|||
if (info.name.empty())
|
||||
{
|
||||
reportError(UnknownRequire{}, location);
|
||||
return errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
|
||||
for (const auto& [location, path] : requireCycles)
|
||||
|
@ -3628,24 +3630,24 @@ TypeId ConstraintSolver::resolveModule(const ModuleInfo& info, const Location& l
|
|||
if (!moduleResolver->moduleExists(info.name) && !info.optional)
|
||||
reportError(UnknownRequire{moduleResolver->getHumanReadableModuleName(info.name)}, location);
|
||||
|
||||
return errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
|
||||
if (module->type != SourceCode::Type::Module)
|
||||
{
|
||||
reportError(IllegalRequire{module->humanReadableName, "Module is not a ModuleScript. It cannot be required."}, location);
|
||||
return errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
|
||||
TypePackId modulePack = module->returnType;
|
||||
if (get<ErrorTypePack>(modulePack))
|
||||
return errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
|
||||
std::optional<TypeId> moduleType = first(modulePack);
|
||||
if (!moduleType)
|
||||
{
|
||||
reportError(IllegalRequire{module->humanReadableName, "Module does not return exactly 1 value. It cannot be required."}, location);
|
||||
return errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
|
||||
return *moduleType;
|
||||
|
@ -3673,28 +3675,33 @@ void ConstraintSolver::shiftReferences(TypeId source, TypeId target)
|
|||
return;
|
||||
|
||||
auto sourceRefs = unresolvedConstraints.find(source);
|
||||
if (!sourceRefs)
|
||||
return;
|
||||
|
||||
if (sourceRefs)
|
||||
{
|
||||
// we read out the count before proceeding to avoid hash invalidation issues.
|
||||
size_t count = *sourceRefs;
|
||||
|
||||
auto [targetRefs, _] = unresolvedConstraints.try_insert(target, 0);
|
||||
targetRefs += count;
|
||||
}
|
||||
|
||||
// Any constraint that might have mutated source may now mutate target
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
auto it = mutatedFreeTypeToConstraint.find(source);
|
||||
if (it != mutatedFreeTypeToConstraint.end())
|
||||
{
|
||||
auto [it2, fresh] = mutatedFreeTypeToConstraint.try_emplace(target, DenseHashSet<const Constraint*>{nullptr});
|
||||
for (const Constraint* constraint : it->second)
|
||||
{
|
||||
it2->second.insert(constraint);
|
||||
const DenseHashSet<const Constraint*>& constraintsAffectedBySource = it->second;
|
||||
|
||||
auto [it3, fresh2] = maybeMutatedFreeTypes.try_emplace(NotNull{constraint}, DenseHashSet<TypeId>{nullptr});
|
||||
auto [it2, fresh2] = mutatedFreeTypeToConstraint.try_emplace(target, DenseHashSet<const Constraint*>{nullptr});
|
||||
DenseHashSet<const Constraint*>& constraintsAffectedByTarget = it2->second;
|
||||
|
||||
// auto [it2, fresh] = mutatedFreeTypeToConstraint.try_emplace(target, DenseHashSet<const Constraint*>{nullptr});
|
||||
for (const Constraint* constraint : constraintsAffectedBySource)
|
||||
{
|
||||
constraintsAffectedByTarget.insert(constraint);
|
||||
|
||||
auto [it3, fresh3] = maybeMutatedFreeTypes.try_emplace(NotNull{constraint}, DenseHashSet<TypeId>{nullptr});
|
||||
it3->second.insert(target);
|
||||
}
|
||||
}
|
||||
|
@ -3784,16 +3791,6 @@ TypeId ConstraintSolver::simplifyUnion(NotNull<Scope> scope, Location location,
|
|||
return ::Luau::simplifyUnion(builtinTypes, arena, left, right).result;
|
||||
}
|
||||
|
||||
TypeId ConstraintSolver::errorRecoveryType() const
|
||||
{
|
||||
return builtinTypes->errorRecoveryType();
|
||||
}
|
||||
|
||||
TypePackId ConstraintSolver::errorRecoveryTypePack() const
|
||||
{
|
||||
return builtinTypes->errorRecoveryTypePack();
|
||||
}
|
||||
|
||||
TypePackId ConstraintSolver::anyifyModuleReturnTypePackGenerics(TypePackId tp)
|
||||
{
|
||||
tp = follow(tp);
|
||||
|
@ -3821,7 +3818,7 @@ TypePackId ConstraintSolver::anyifyModuleReturnTypePackGenerics(TypePackId tp)
|
|||
if (std::optional<TypePackId> tail = it.tail())
|
||||
resultTail = anyifyModuleReturnTypePackGenerics(*tail);
|
||||
|
||||
return arena->addTypePack(resultTypes, resultTail);
|
||||
return arena->addTypePack(std::move(resultTypes), resultTail);
|
||||
}
|
||||
|
||||
LUAU_NOINLINE void ConstraintSolver::throwTimeLimitError() const
|
||||
|
|
|
@ -253,10 +253,10 @@ static ScopeSnapshot snapshotScope(const Scope* scope, ToStringOptions& opts)
|
|||
}
|
||||
|
||||
return ScopeSnapshot{
|
||||
bindings,
|
||||
typeBindings,
|
||||
typePackBindings,
|
||||
children,
|
||||
std::move(bindings),
|
||||
std::move(typeBindings),
|
||||
std::move(typePackBindings),
|
||||
std::move(children),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ void DcrLogger::captureGenerationError(const TypeError& error)
|
|||
{
|
||||
std::string stringifiedError = toString(error);
|
||||
generationLog.errors.push_back(ErrorSnapshot{
|
||||
/* message */ stringifiedError,
|
||||
/* message */ std::move(stringifiedError),
|
||||
/* location */ error.location,
|
||||
});
|
||||
}
|
||||
|
@ -424,7 +424,7 @@ StepSnapshot DcrLogger::prepareStepSnapshot(
|
|||
current,
|
||||
force,
|
||||
std::move(constraints),
|
||||
scopeSnapshot,
|
||||
std::move(scopeSnapshot),
|
||||
std::move(typeStrings),
|
||||
};
|
||||
}
|
||||
|
@ -443,7 +443,7 @@ void DcrLogger::captureTypeCheckError(const TypeError& error)
|
|||
{
|
||||
std::string stringifiedError = toString(error);
|
||||
checkLog.errors.push_back(ErrorSnapshot{
|
||||
/* message */ stringifiedError,
|
||||
/* message */ std::move(stringifiedError),
|
||||
/* location */ error.location,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <unordered_set>
|
||||
|
||||
LUAU_FASTINTVARIABLE(LuauIndentTypeMismatchMaxTypeLength, 10)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauBetterCannotCallFunctionPrimitive)
|
||||
|
||||
|
@ -159,7 +159,7 @@ struct ErrorConverter
|
|||
}
|
||||
|
||||
if (result.empty())
|
||||
result = constructErrorMessage(givenTypeName, wantedTypeName, std::nullopt, std::nullopt);
|
||||
result = constructErrorMessage(std::move(givenTypeName), std::move(wantedTypeName), std::nullopt, std::nullopt);
|
||||
|
||||
|
||||
if (tm.error)
|
||||
|
@ -663,7 +663,7 @@ struct ErrorConverter
|
|||
}
|
||||
|
||||
// binary operators
|
||||
const auto binaryOps = FFlag::LuauEagerGeneralization3 ? kBinaryOps : DEPRECATED_kBinaryOps;
|
||||
const auto binaryOps = FFlag::LuauEagerGeneralization4 ? kBinaryOps : DEPRECATED_kBinaryOps;
|
||||
if (auto binaryString = binaryOps.find(tfit->function->name); binaryString != binaryOps.end())
|
||||
{
|
||||
std::string result = "Operator '" + std::string(binaryString->second) + "' could not be applied to operands of types ";
|
||||
|
@ -718,7 +718,7 @@ struct ErrorConverter
|
|||
"'";
|
||||
}
|
||||
|
||||
if ((FFlag::LuauEagerGeneralization3 ? kUnreachableTypeFunctions : DEPRECATED_kUnreachableTypeFunctions).count(tfit->function->name))
|
||||
if ((FFlag::LuauEagerGeneralization4 ? kUnreachableTypeFunctions : DEPRECATED_kUnreachableTypeFunctions).count(tfit->function->name))
|
||||
{
|
||||
return "Type function instance " + Luau::toString(e.ty) + " is uninhabited\n" +
|
||||
"This is likely to be a bug, please report it at https://github.com/luau-lang/luau/issues";
|
||||
|
@ -906,14 +906,14 @@ TypeMismatch::TypeMismatch(TypeId wantedType, TypeId givenType)
|
|||
TypeMismatch::TypeMismatch(TypeId wantedType, TypeId givenType, std::string reason)
|
||||
: wantedType(wantedType)
|
||||
, givenType(givenType)
|
||||
, reason(reason)
|
||||
, reason(std::move(reason))
|
||||
{
|
||||
}
|
||||
|
||||
TypeMismatch::TypeMismatch(TypeId wantedType, TypeId givenType, std::string reason, std::optional<TypeError> error)
|
||||
: wantedType(wantedType)
|
||||
, givenType(givenType)
|
||||
, reason(reason)
|
||||
, reason(std::move(reason))
|
||||
, error(error ? std::make_shared<TypeError>(std::move(*error)) : nullptr)
|
||||
{
|
||||
}
|
||||
|
@ -929,7 +929,7 @@ TypeMismatch::TypeMismatch(TypeId wantedType, TypeId givenType, std::string reas
|
|||
: wantedType(wantedType)
|
||||
, givenType(givenType)
|
||||
, context(context)
|
||||
, reason(reason)
|
||||
, reason(std::move(reason))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -937,7 +937,7 @@ TypeMismatch::TypeMismatch(TypeId wantedType, TypeId givenType, std::string reas
|
|||
: wantedType(wantedType)
|
||||
, givenType(givenType)
|
||||
, context(context)
|
||||
, reason(reason)
|
||||
, reason(std::move(reason))
|
||||
, error(error ? std::make_shared<TypeError>(std::move(*error)) : nullptr)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -3,8 +3,12 @@
|
|||
|
||||
#include "Luau/Scope.h"
|
||||
#include "Luau/TypeArena.h"
|
||||
#include "Luau/TypeIds.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/TypeUtils.h"
|
||||
#include "Luau/VisitType.h"
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauImplicitTableIndexerKeys)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -70,6 +74,106 @@ bool ExpectedTypeVisitor::visit(AstStatReturn* stat)
|
|||
return true;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct IndexerIndexCollector : public TypeOnceVisitor
|
||||
{
|
||||
NotNull<TypeIds> indexes;
|
||||
|
||||
explicit IndexerIndexCollector(NotNull<TypeIds> indexes) : TypeOnceVisitor(/* skipBoundTypes */ true), indexes(indexes)
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId ty) override
|
||||
{
|
||||
indexes->insert(ty);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypeId, const UnionType&) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visit(TypeId, const IntersectionType&) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct IndexCollector : public TypeOnceVisitor
|
||||
{
|
||||
NotNull<TypeArena> arena;
|
||||
TypeIds indexes;
|
||||
|
||||
explicit IndexCollector(NotNull<TypeArena> arena) : TypeOnceVisitor(/* skipBoundTypes */ true), arena(arena)
|
||||
{
|
||||
}
|
||||
|
||||
bool visit(TypeId ty) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypeId, const UnionType&) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visit(TypeId, const IntersectionType&) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visit(TypeId, const TableType& ttv) override
|
||||
{
|
||||
for (const auto& [name, _] : ttv.props)
|
||||
indexes.insert(arena->addType(SingletonType{StringSingleton{name}}));
|
||||
|
||||
if (ttv.indexer)
|
||||
{
|
||||
IndexerIndexCollector iic{NotNull{&indexes}};
|
||||
iic.traverse(ttv.indexer->indexType);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
bool ExpectedTypeVisitor::visit(AstExprIndexExpr* expr)
|
||||
{
|
||||
if (!FFlag::LuauImplicitTableIndexerKeys)
|
||||
return true;
|
||||
|
||||
if (auto ty = astTypes->find(expr->expr))
|
||||
{
|
||||
IndexCollector ic{arena};
|
||||
ic.traverse(*ty);
|
||||
if (ic.indexes.size() > 1)
|
||||
{
|
||||
applyExpectedType(
|
||||
arena->addType(UnionType{ic.indexes.take()}),
|
||||
expr->index
|
||||
);
|
||||
}
|
||||
else if (ic.indexes.size() == 1)
|
||||
{
|
||||
applyExpectedType(
|
||||
*ic.indexes.begin(),
|
||||
expr->index
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ExpectedTypeVisitor::visit(AstExprCall* expr)
|
||||
{
|
||||
auto ty = astTypes->find(expr->func);
|
||||
|
|
|
@ -479,7 +479,7 @@ FragmentAutocompleteAncestryResult findAncestryForFragmentParse(AstStatBlock* st
|
|||
}
|
||||
}
|
||||
|
||||
return {localMap, localStack, ancestry, region.nearestStatement, region.parentBlock, region.fragmentLocation};
|
||||
return {std::move(localMap), std::move(localStack), std::move(ancestry), region.nearestStatement, region.parentBlock, region.fragmentLocation};
|
||||
}
|
||||
|
||||
std::optional<FragmentParseResult> parseFragment(
|
||||
|
@ -512,7 +512,7 @@ std::optional<FragmentParseResult> parseFragment(
|
|||
opts.allowDeclarationSyntax = false;
|
||||
opts.captureComments = true;
|
||||
opts.parseFragment = FragmentParseResumeSettings{std::move(result.localMap), std::move(result.localStack), startPos};
|
||||
ParseResult p = Luau::Parser::parse(srcStart, parseLength, *names, *fragmentResult.alloc, opts);
|
||||
ParseResult p = Luau::Parser::parse(srcStart, parseLength, *names, *fragmentResult.alloc, std::move(opts));
|
||||
// This means we threw a ParseError and we should decline to offer autocomplete here.
|
||||
if (p.root == nullptr)
|
||||
return std::nullopt;
|
||||
|
@ -1037,7 +1037,7 @@ std::optional<FragmentParseResult> parseFragment_DEPRECATED(
|
|||
opts.allowDeclarationSyntax = false;
|
||||
opts.captureComments = true;
|
||||
opts.parseFragment = FragmentParseResumeSettings{std::move(result.localMap), std::move(result.localStack), startPos};
|
||||
ParseResult p = Luau::Parser::parse(srcStart, parseLength, *names, *fragmentResult.alloc, opts);
|
||||
ParseResult p = Luau::Parser::parse(srcStart, parseLength, *names, *fragmentResult.alloc, std::move(opts));
|
||||
// This means we threw a ParseError and we should decline to offer autocomplete here.
|
||||
if (p.root == nullptr)
|
||||
return std::nullopt;
|
||||
|
@ -1192,7 +1192,7 @@ FragmentTypeCheckResult typecheckFragment_(
|
|||
{},
|
||||
nullptr,
|
||||
NotNull{&dfg},
|
||||
limits
|
||||
std::move(limits)
|
||||
};
|
||||
|
||||
try
|
||||
|
@ -1351,7 +1351,7 @@ FragmentAutocompleteResult fragmentAutocomplete(
|
|||
tcResult.freshScope,
|
||||
cursorPosition,
|
||||
frontend.fileResolver,
|
||||
callback
|
||||
std::move(callback)
|
||||
);
|
||||
if (FFlag::LuauFragmentAcMemoryLeak)
|
||||
freeze(tcResult.incrementalModule->internalTypes);
|
||||
|
|
|
@ -40,7 +40,7 @@ LUAU_FASTINT(LuauTarjanChildLimit)
|
|||
LUAU_FASTFLAG(LuauInferInNoCheckMode)
|
||||
LUAU_FASTFLAGVARIABLE(LuauKnowsTheDataModel3)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJsonFile)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauForbidInternalTypes)
|
||||
|
@ -207,16 +207,16 @@ LoadDefinitionFileResult Frontend::loadDefinitionFile(
|
|||
|
||||
Luau::ParseResult parseResult = parseSourceForModule(source, sourceModule, captureComments);
|
||||
if (parseResult.errors.size() > 0)
|
||||
return LoadDefinitionFileResult{false, parseResult, sourceModule, nullptr};
|
||||
return LoadDefinitionFileResult{false, std::move(parseResult), std::move(sourceModule), nullptr};
|
||||
|
||||
ModulePtr checkedModule = check(sourceModule, Mode::Definition, {}, std::nullopt, /*forAutocomplete*/ false, /*recordJsonLog*/ false, {});
|
||||
|
||||
if (checkedModule->errors.size() > 0)
|
||||
return LoadDefinitionFileResult{false, parseResult, sourceModule, checkedModule};
|
||||
return LoadDefinitionFileResult{false, std::move(parseResult), std::move(sourceModule), std::move(checkedModule)};
|
||||
|
||||
persistCheckedTypes(checkedModule, globals, targetScope, packageName);
|
||||
persistCheckedTypes(checkedModule, globals, std::move(targetScope), packageName);
|
||||
|
||||
return LoadDefinitionFileResult{true, parseResult, sourceModule, checkedModule};
|
||||
return LoadDefinitionFileResult{true, std::move(parseResult), std::move(sourceModule), std::move(checkedModule)};
|
||||
}
|
||||
|
||||
namespace
|
||||
|
@ -970,7 +970,7 @@ void Frontend::checkBuildQueueItem(BuildQueueItem& item)
|
|||
environmentScope,
|
||||
/*forAutocomplete*/ true,
|
||||
/*recordJsonLog*/ false,
|
||||
typeCheckLimits
|
||||
std::move(typeCheckLimits)
|
||||
);
|
||||
|
||||
double duration = getTimestamp() - timestamp;
|
||||
|
@ -990,7 +990,7 @@ void Frontend::checkBuildQueueItem(BuildQueueItem& item)
|
|||
return;
|
||||
}
|
||||
|
||||
ModulePtr module = check(sourceModule, mode, requireCycles, environmentScope, /*forAutocomplete*/ false, item.recordJsonLog, typeCheckLimits);
|
||||
ModulePtr module = check(sourceModule, mode, requireCycles, environmentScope, /*forAutocomplete*/ false, item.recordJsonLog, std::move(typeCheckLimits));
|
||||
|
||||
double duration = getTimestamp() - timestamp;
|
||||
|
||||
|
@ -1172,7 +1172,7 @@ void Frontend::sendQueueCycleItemTask(std::shared_ptr<BuildQueueWorkState> state
|
|||
|
||||
if (!item.processing)
|
||||
{
|
||||
sendQueueItemTask(state, i);
|
||||
sendQueueItemTask(std::move(state), i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1314,10 +1314,10 @@ ModulePtr check(
|
|||
parentScope,
|
||||
typeFunctionScope,
|
||||
std::move(prepareModuleScope),
|
||||
options,
|
||||
limits,
|
||||
std::move(options),
|
||||
std::move(limits),
|
||||
recordJsonLog,
|
||||
writeJsonLog
|
||||
std::move(writeJsonLog)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1438,13 +1438,13 @@ ModulePtr check(
|
|||
requireCycles
|
||||
};
|
||||
|
||||
// FIXME: Delete this flag when clipping FFlag::LuauEagerGeneralization2.
|
||||
// FIXME: Delete this flag when clipping FFlag::LuauEagerGeneralization4.
|
||||
//
|
||||
// This optional<> only exists so that we can run one constructor when the flag
|
||||
// is set, and another when it is unset.
|
||||
std::optional<ConstraintSolver> cs;
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
ConstraintSet constraintSet = cg.run(sourceModule.root);
|
||||
result->errors = std::move(constraintSet.errors);
|
||||
|
@ -1522,13 +1522,13 @@ ModulePtr check(
|
|||
// If solver was interrupted, skip typechecking and replace all module results with error-supressing types to avoid leaking blocked/pending
|
||||
// types
|
||||
ScopePtr moduleScope = result->getModuleScope();
|
||||
moduleScope->returnType = builtinTypes->errorRecoveryTypePack();
|
||||
moduleScope->returnType = builtinTypes->errorTypePack;
|
||||
|
||||
for (auto& [name, ty] : result->declaredGlobals)
|
||||
ty = builtinTypes->errorRecoveryType();
|
||||
ty = builtinTypes->errorType;
|
||||
|
||||
for (auto& [name, tf] : result->exportedTypeBindings)
|
||||
tf.type = builtinTypes->errorRecoveryType();
|
||||
tf.type = builtinTypes->errorType;
|
||||
}
|
||||
else if (FFlag::LuauNewSolverTypecheckCatchTimeouts)
|
||||
{
|
||||
|
@ -1705,7 +1705,7 @@ ModulePtr Frontend::check(
|
|||
globals.globalTypeFunctionScope,
|
||||
prepareModuleScopeWrap,
|
||||
options,
|
||||
typeCheckLimits,
|
||||
std::move(typeCheckLimits),
|
||||
recordJsonLog,
|
||||
writeJsonLog
|
||||
);
|
||||
|
@ -1740,7 +1740,7 @@ ModulePtr Frontend::check(
|
|||
typeChecker.unifierIterationLimit = typeCheckLimits.unifierIterationLimit;
|
||||
typeChecker.cancellationToken = typeCheckLimits.cancellationToken;
|
||||
|
||||
return typeChecker.check(sourceModule, mode, environmentScope);
|
||||
return typeChecker.check(sourceModule, mode, std::move(environmentScope));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAGVARIABLE(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAGVARIABLE(LuauGeneralizationCannotMutateAcrossModules)
|
||||
|
||||
namespace Luau
|
||||
|
@ -470,7 +470,7 @@ struct FreeTypeSearcher : TypeVisitor
|
|||
|
||||
bool visit(TypeId ty, const FreeType& ft) override
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (!subsumes(scope, ft.scope))
|
||||
return true;
|
||||
|
@ -521,7 +521,7 @@ struct FreeTypeSearcher : TypeVisitor
|
|||
|
||||
if ((tt.state == TableState::Free || tt.state == TableState::Unsealed) && subsumes(scope, tt.scope))
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
unsealedTables.insert(ty);
|
||||
else
|
||||
{
|
||||
|
@ -594,7 +594,7 @@ struct FreeTypeSearcher : TypeVisitor
|
|||
|
||||
if (tt.indexer)
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
// {[K]: V} is equivalent to three functions: get, set, and iterate
|
||||
//
|
||||
|
@ -652,7 +652,7 @@ struct FreeTypeSearcher : TypeVisitor
|
|||
if (!subsumes(scope, ftp.scope))
|
||||
return true;
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
GeneralizationParams<TypePackId>& params = typePacks[tp];
|
||||
++params.useCount;
|
||||
|
@ -1223,7 +1223,7 @@ GeneralizationResult<TypeId> generalizeType(
|
|||
|
||||
if (!hasLowerBound && !hasUpperBound)
|
||||
{
|
||||
if (!isWithinFunction || (!FFlag::LuauEagerGeneralization3 && (params.polarity != Polarity::Mixed && params.useCount == 1)))
|
||||
if (!isWithinFunction || (!FFlag::LuauEagerGeneralization4 && (params.polarity != Polarity::Mixed && params.useCount == 1)))
|
||||
emplaceType<BoundType>(asMutable(freeTy), builtinTypes->unknownType);
|
||||
else
|
||||
{
|
||||
|
@ -1247,7 +1247,7 @@ GeneralizationResult<TypeId> generalizeType(
|
|||
|
||||
if (follow(lb) != freeTy)
|
||||
emplaceType<BoundType>(asMutable(freeTy), lb);
|
||||
else if (!isWithinFunction || (!FFlag::LuauEagerGeneralization3 && params.useCount == 1))
|
||||
else if (!isWithinFunction || (!FFlag::LuauEagerGeneralization4 && params.useCount == 1))
|
||||
emplaceType<BoundType>(asMutable(freeTy), builtinTypes->unknownType);
|
||||
else
|
||||
{
|
||||
|
@ -1353,7 +1353,7 @@ std::optional<TypeId> generalize(
|
|||
FreeTypeSearcher fts{scope, cachedTypes};
|
||||
fts.traverse(ty);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
FunctionType* functionTy = getMutable<FunctionType>(ty);
|
||||
auto pushGeneric = [&](TypeId t)
|
||||
|
@ -1597,7 +1597,7 @@ void pruneUnnecessaryGenerics(
|
|||
TypeId ty
|
||||
)
|
||||
{
|
||||
if (!FFlag::LuauEagerGeneralization3)
|
||||
if (!FFlag::LuauEagerGeneralization4)
|
||||
return;
|
||||
|
||||
ty = follow(ty);
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
#include "Luau/Scope.h"
|
||||
#include "Luau/VisitType.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAGVARIABLE(LuauInferPolarityOfReadWriteProperties)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -48,6 +49,32 @@ struct InferPolarity : TypeVisitor
|
|||
return false;
|
||||
|
||||
const Polarity p = polarity;
|
||||
if (FFlag::LuauInferPolarityOfReadWriteProperties)
|
||||
{
|
||||
for (const auto& [name, prop] : tt.props)
|
||||
{
|
||||
if (prop.isShared())
|
||||
{
|
||||
polarity = Polarity::Mixed;
|
||||
traverse(*prop.readTy);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prop.readTy)
|
||||
{
|
||||
polarity = p;
|
||||
traverse(*prop.readTy);
|
||||
}
|
||||
|
||||
if (prop.writeTy)
|
||||
{
|
||||
polarity = invert(p);
|
||||
traverse(*prop.writeTy);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& [name, prop] : tt.props)
|
||||
{
|
||||
if (prop.isShared())
|
||||
|
@ -68,6 +95,7 @@ struct InferPolarity : TypeVisitor
|
|||
else
|
||||
LUAU_ASSERT(!"Unreachable");
|
||||
}
|
||||
}
|
||||
|
||||
if (tt.indexer)
|
||||
{
|
||||
|
@ -133,7 +161,7 @@ struct InferPolarity : TypeVisitor
|
|||
template<typename TID>
|
||||
static void inferGenericPolarities_(NotNull<TypeArena> arena, NotNull<Scope> scope, TID ty)
|
||||
{
|
||||
if (!FFlag::LuauEagerGeneralization3)
|
||||
if (!FFlag::LuauEagerGeneralization4)
|
||||
return;
|
||||
|
||||
InferPolarity infer{arena, scope};
|
||||
|
|
|
@ -16,9 +16,6 @@ LUAU_FASTINTVARIABLE(LuauSuggestionDistance, 4)
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
|
||||
LUAU_FASTFLAG(LuauAttribute)
|
||||
LUAU_FASTFLAGVARIABLE(LintRedundantNativeAttribute)
|
||||
|
||||
LUAU_FASTFLAG(LuauStoreReturnTypesAsPackOnAst)
|
||||
|
||||
namespace Luau
|
||||
|
@ -107,7 +104,7 @@ static void emitWarning(LintContext& context, LintWarning::Code code, const Loca
|
|||
std::string message = vformat(format, args);
|
||||
va_end(args);
|
||||
|
||||
LintWarning warning = {code, location, message};
|
||||
LintWarning warning = {code, location, std::move(message)};
|
||||
context.result.push_back(warning);
|
||||
}
|
||||
|
||||
|
@ -3392,8 +3389,6 @@ static void lintComments(LintContext& context, const std::vector<HotComment>& ho
|
|||
|
||||
static bool hasNativeCommentDirective(const std::vector<HotComment>& hotcomments)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LintRedundantNativeAttribute);
|
||||
|
||||
for (const HotComment& hc : hotcomments)
|
||||
{
|
||||
if (hc.content.empty() || hc.content[0] == ' ' || hc.content[0] == '\t')
|
||||
|
@ -3417,8 +3412,6 @@ struct LintRedundantNativeAttribute : AstVisitor
|
|||
public:
|
||||
LUAU_NOINLINE static void process(LintContext& context)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LintRedundantNativeAttribute);
|
||||
|
||||
LintRedundantNativeAttribute pass;
|
||||
pass.context = &context;
|
||||
context.root->visit(&pass);
|
||||
|
@ -3540,7 +3533,7 @@ std::vector<LintWarning> lint(
|
|||
if (context.warningEnabled(LintWarning::Code_ComparisonPrecedence))
|
||||
LintComparisonPrecedence::process(context);
|
||||
|
||||
if (FFlag::LintRedundantNativeAttribute && context.warningEnabled(LintWarning::Code_RedundantNativeAttribute))
|
||||
if (context.warningEnabled(LintWarning::Code_RedundantNativeAttribute))
|
||||
{
|
||||
if (hasNativeCommentDirective(hotcomments))
|
||||
LintRedundantNativeAttribute::process(context);
|
||||
|
|
|
@ -172,7 +172,7 @@ struct ClonePublicInterface : Substitution
|
|||
InternalError{"Free type is escaping its module; please report this bug at "
|
||||
"https://github.com/luau-lang/luau/issues"}
|
||||
);
|
||||
result = builtinTypes->errorRecoveryType();
|
||||
result = builtinTypes->errorType;
|
||||
}
|
||||
else if (auto genericty = getMutable<GenericType>(result))
|
||||
{
|
||||
|
@ -196,7 +196,7 @@ struct ClonePublicInterface : Substitution
|
|||
InternalError{"Free type pack is escaping its module; please report this bug at "
|
||||
"https://github.com/luau-lang/luau/issues"}
|
||||
);
|
||||
clonedTp = builtinTypes->errorRecoveryTypePack();
|
||||
clonedTp = builtinTypes->errorTypePack;
|
||||
}
|
||||
else if (auto gtp = getMutable<GenericTypePack>(clonedTp))
|
||||
gtp->scope = nullptr;
|
||||
|
@ -218,7 +218,7 @@ struct ClonePublicInterface : Substitution
|
|||
else
|
||||
{
|
||||
module->errors.push_back(TypeError{module->scopes[0].first, UnificationTooComplex{}});
|
||||
return builtinTypes->errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,7 +232,7 @@ struct ClonePublicInterface : Substitution
|
|||
else
|
||||
{
|
||||
module->errors.push_back(TypeError{module->scopes[0].first, UnificationTooComplex{}});
|
||||
return builtinTypes->errorRecoveryTypePack();
|
||||
return builtinTypes->errorTypePack;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,7 +265,7 @@ struct ClonePublicInterface : Substitution
|
|||
|
||||
TypeId type = cloneType(tf.type);
|
||||
|
||||
return TypeFun{typeParams, typePackParams, type, tf.definitionLocation};
|
||||
return TypeFun{std::move(typeParams), std::move(typePackParams), type, tf.definitionLocation};
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -226,7 +226,7 @@ struct NonStrictTypeChecker
|
|||
return result;
|
||||
}
|
||||
else if (get<ErrorTypePack>(pack))
|
||||
return builtinTypes->errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
else if (finite(pack) && size(pack) == 0)
|
||||
return builtinTypes->nilType; // `(f())` where `f()` returns no values is coerced into `nil`
|
||||
else
|
||||
|
@ -682,7 +682,7 @@ struct NonStrictTypeChecker
|
|||
if (arguments.size() > argTypes.size())
|
||||
{
|
||||
// We are passing more arguments than we expect, so we should error
|
||||
reportError(CheckedFunctionIncorrectArgs{functionName, argTypes.size(), arguments.size()}, call->location);
|
||||
reportError(CheckedFunctionIncorrectArgs{std::move(functionName), argTypes.size(), arguments.size()}, call->location);
|
||||
return fresh;
|
||||
}
|
||||
|
||||
|
@ -729,7 +729,7 @@ struct NonStrictTypeChecker
|
|||
|
||||
if (!remainingArgsOptional)
|
||||
{
|
||||
reportError(CheckedFunctionIncorrectArgs{functionName, argTypes.size(), arguments.size()}, call->location);
|
||||
reportError(CheckedFunctionIncorrectArgs{std::move(functionName), argTypes.size(), arguments.size()}, call->location);
|
||||
return fresh;
|
||||
}
|
||||
}
|
||||
|
@ -1009,7 +1009,7 @@ struct NonStrictTypeChecker
|
|||
}
|
||||
symbol += ty->name.value;
|
||||
|
||||
reportError(UnknownSymbol{symbol, UnknownSymbol::Context::Type}, ty->location);
|
||||
reportError(UnknownSymbol{std::move(symbol), UnknownSymbol::Context::Type}, ty->location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1363,7 +1363,7 @@ std::optional<TypePackId> Normalizer::unionOfTypePacks(TypePackId here, TypePack
|
|||
else if (thereSubHere)
|
||||
return here;
|
||||
if (!head.empty())
|
||||
return arena->addTypePack(TypePack{head, tail});
|
||||
return arena->addTypePack(TypePack{std::move(head), tail});
|
||||
else if (tail)
|
||||
return *tail;
|
||||
else
|
||||
|
@ -1822,7 +1822,7 @@ std::optional<NormalizedType> Normalizer::negateNormal(const NormalizedType& her
|
|||
}
|
||||
|
||||
if (!rootNegations.empty())
|
||||
result.externTypes.pushPair(builtinTypes->externType, rootNegations);
|
||||
result.externTypes.pushPair(builtinTypes->externType, std::move(rootNegations));
|
||||
}
|
||||
|
||||
result.nils = get<NeverType>(here.nils) ? builtinTypes->nilType : builtinTypes->neverType;
|
||||
|
@ -2375,7 +2375,7 @@ std::optional<TypePackId> Normalizer::intersectionOfTypePacks(TypePackId here, T
|
|||
else if (thereSubHere)
|
||||
return there;
|
||||
if (!head.empty())
|
||||
return arena->addTypePack(TypePack{head, tail});
|
||||
return arena->addTypePack(TypePack{std::move(head), tail});
|
||||
else if (tail)
|
||||
return *tail;
|
||||
else
|
||||
|
|
|
@ -256,7 +256,7 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
|||
|
||||
TypeError error{fnExpr->location, CountMismatch{minParams, optMaxParams, args->head.size(), CountMismatch::Arg, isVariadic}};
|
||||
|
||||
return {Analysis::ArityMismatch, {error}};
|
||||
return {Analysis::ArityMismatch, {std::move(error)}};
|
||||
}
|
||||
|
||||
// If any of the unsatisfied arguments are not supertypes of
|
||||
|
@ -274,7 +274,7 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
|||
|
||||
TypeError error{fnExpr->location, CountMismatch{minParams, optMaxParams, args->head.size(), CountMismatch::Arg, isVariadic}};
|
||||
|
||||
return {Analysis::ArityMismatch, {error}};
|
||||
return {Analysis::ArityMismatch, {std::move(error)}};
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -284,7 +284,7 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
|||
auto [minParams, optMaxParams] = getParameterExtents(TxnLog::empty(), fn->argTypes);
|
||||
TypeError error{fnExpr->location, CountMismatch{minParams, optMaxParams, args->head.size(), CountMismatch::Arg, isVariadic}};
|
||||
|
||||
return {Analysis::ArityMismatch, {error}};
|
||||
return {Analysis::ArityMismatch, {std::move(error)}};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -305,7 +305,7 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
|||
auto [minParams, optMaxParams] = getParameterExtents(TxnLog::empty(), fn->argTypes);
|
||||
TypeError error{fnExpr->location, CountMismatch{minParams, optMaxParams, args->head.size(), CountMismatch::Arg}};
|
||||
|
||||
return {Analysis::ArityMismatch, {error}};
|
||||
return {Analysis::ArityMismatch, {std::move(error)}};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
LUAU_FASTINTVARIABLE(LuauTarjanChildLimit, 10000)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTINTVARIABLE(LuauTarjanPreallocationSize, 256)
|
||||
LUAU_FASTFLAG(LuauSolverAgnosticClone)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -189,7 +190,7 @@ void Tarjan::visitChildren(TypeId ty, int index)
|
|||
LUAU_ASSERT(!ttv->boundTo);
|
||||
for (const auto& [name, prop] : ttv->props)
|
||||
{
|
||||
if (FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauSolverV2 || FFlag::LuauSolverAgnosticClone)
|
||||
{
|
||||
visitChild(prop.readTy);
|
||||
visitChild(prop.writeTy);
|
||||
|
@ -773,7 +774,7 @@ void Substitution::replaceChildren(TypeId ty)
|
|||
LUAU_ASSERT(!ttv->boundTo);
|
||||
for (auto& [name, prop] : ttv->props)
|
||||
{
|
||||
if (FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauSolverV2 || FFlag::LuauSolverAgnosticClone)
|
||||
{
|
||||
if (prop.readTy)
|
||||
prop.readTy = replace(prop.readTy);
|
||||
|
|
|
@ -20,7 +20,7 @@ LUAU_FASTFLAGVARIABLE(DebugLuauSubtypingCheckPathValidity)
|
|||
LUAU_FASTINTVARIABLE(LuauSubtypingReasoningLimit, 100)
|
||||
LUAU_FASTFLAG(LuauClipVariadicAnysFromArgsToGenericFuncs2)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSubtypingCheckFunctionGenericCounts)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -165,13 +165,13 @@ SubtypingResult& SubtypingResult::orElse(const SubtypingResult& other)
|
|||
|
||||
SubtypingResult& SubtypingResult::withBothComponent(TypePath::Component component)
|
||||
{
|
||||
return withSubComponent(component).withSuperComponent(component);
|
||||
return withSubComponent(component).withSuperComponent(std::move(component));
|
||||
}
|
||||
|
||||
SubtypingResult& SubtypingResult::withSubComponent(TypePath::Component component)
|
||||
{
|
||||
if (reasoning.empty())
|
||||
reasoning.insert(SubtypingReasoning{Path(component), TypePath::kEmpty});
|
||||
reasoning.insert(SubtypingReasoning{Path(std::move(component)), TypePath::kEmpty});
|
||||
else
|
||||
{
|
||||
for (auto& r : reasoning)
|
||||
|
@ -184,7 +184,7 @@ SubtypingResult& SubtypingResult::withSubComponent(TypePath::Component component
|
|||
SubtypingResult& SubtypingResult::withSuperComponent(TypePath::Component component)
|
||||
{
|
||||
if (reasoning.empty())
|
||||
reasoning.insert(SubtypingReasoning{TypePath::kEmpty, Path(component)});
|
||||
reasoning.insert(SubtypingReasoning{TypePath::kEmpty, Path(std::move(component))});
|
||||
else
|
||||
{
|
||||
for (auto& r : reasoning)
|
||||
|
@ -196,13 +196,13 @@ SubtypingResult& SubtypingResult::withSuperComponent(TypePath::Component compone
|
|||
|
||||
SubtypingResult& SubtypingResult::withBothPath(TypePath::Path path)
|
||||
{
|
||||
return withSubPath(path).withSuperPath(path);
|
||||
return withSubPath(path).withSuperPath(std::move(path));
|
||||
}
|
||||
|
||||
SubtypingResult& SubtypingResult::withSubPath(TypePath::Path path)
|
||||
{
|
||||
if (reasoning.empty())
|
||||
reasoning.insert(SubtypingReasoning{path, TypePath::kEmpty});
|
||||
reasoning.insert(SubtypingReasoning{std::move(path), TypePath::kEmpty});
|
||||
else
|
||||
{
|
||||
for (auto& r : reasoning)
|
||||
|
@ -215,7 +215,7 @@ SubtypingResult& SubtypingResult::withSubPath(TypePath::Path path)
|
|||
SubtypingResult& SubtypingResult::withSuperPath(TypePath::Path path)
|
||||
{
|
||||
if (reasoning.empty())
|
||||
reasoning.insert(SubtypingReasoning{TypePath::kEmpty, path});
|
||||
reasoning.insert(SubtypingReasoning{TypePath::kEmpty, std::move(path)});
|
||||
else
|
||||
{
|
||||
for (auto& r : reasoning)
|
||||
|
@ -680,14 +680,14 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
|||
result.isSubtype = ok;
|
||||
result.isCacheable = false;
|
||||
}
|
||||
else if (auto pair = get2<FreeType, FreeType>(subTy, superTy); FFlag::LuauEagerGeneralization3 && pair)
|
||||
else if (auto pair = get2<FreeType, FreeType>(subTy, superTy); FFlag::LuauEagerGeneralization4 && pair)
|
||||
{
|
||||
// Any two free types are potentially subtypes of one another because
|
||||
// both of them could be narrowed to never.
|
||||
result = {true};
|
||||
result.assumedConstraints.emplace_back(SubtypeConstraint{subTy, superTy});
|
||||
}
|
||||
else if (auto superFree = get<FreeType>(superTy); superFree && FFlag::LuauEagerGeneralization3)
|
||||
else if (auto superFree = get<FreeType>(superTy); superFree && FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
// Given SubTy <: (LB <: SuperTy <: UB)
|
||||
//
|
||||
|
@ -702,7 +702,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
|||
if (result.isSubtype)
|
||||
result.assumedConstraints.emplace_back(SubtypeConstraint{subTy, superTy});
|
||||
}
|
||||
else if (auto subFree = get<FreeType>(subTy); subFree && FFlag::LuauEagerGeneralization3)
|
||||
else if (auto subFree = get<FreeType>(subTy); subFree && FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
// Given (LB <: SubTy <: UB) <: SuperTy
|
||||
//
|
||||
|
@ -792,7 +792,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
|||
|
||||
assertReasoningValid(subTy, superTy, result, builtinTypes);
|
||||
|
||||
return cache(env, result, subTy, superTy);
|
||||
return cache(env, std::move(result), subTy, superTy);
|
||||
}
|
||||
|
||||
SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypePackId subTp, TypePackId superTp, NotNull<Scope> scope)
|
||||
|
@ -1437,7 +1437,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Tabl
|
|||
{
|
||||
SubtypingResult result{true};
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (subTable->props.empty() && !subTable->indexer && subTable->state == TableState::Sealed && superTable->indexer)
|
||||
{
|
||||
|
@ -1493,7 +1493,7 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const Tabl
|
|||
{
|
||||
if (subTable->indexer)
|
||||
result.andAlso(isInvariantWith(env, *subTable->indexer, *superTable->indexer, scope));
|
||||
else if (FFlag::LuauEagerGeneralization3 && subTable->state != TableState::Sealed)
|
||||
else if (FFlag::LuauEagerGeneralization4 && subTable->state != TableState::Sealed)
|
||||
{
|
||||
// As above, we assume that {| |} <: {T} because the unsealed table
|
||||
// on the left will eventually gain the necessary indexer.
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "Luau/TypeUtils.h"
|
||||
#include "Luau/Unifier2.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAGVARIABLE(LuauWriteOnlyPropertyMangling)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -195,11 +195,20 @@ TypeId matchLiteralType(
|
|||
|
||||
Property& prop = it->second;
|
||||
|
||||
if (FFlag::LuauWriteOnlyPropertyMangling)
|
||||
{
|
||||
// If the property is write-only, do nothing.
|
||||
if (prop.isWriteOnly())
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we encounter a duplcate property, we may have already
|
||||
// set it to be read-only. If that's the case, the only thing
|
||||
// that will definitely crash is trying to access a write
|
||||
// only property.
|
||||
LUAU_ASSERT(!prop.isWriteOnly());
|
||||
}
|
||||
TypeId propTy = *prop.readTy;
|
||||
|
||||
auto it2 = expectedTableTy->props.find(keyStr);
|
||||
|
|
|
@ -148,7 +148,7 @@ void findCyclicTypes(std::set<TypeId>& cycles, std::set<TypePackId>& cycleTPs, T
|
|||
|
||||
static std::pair<bool, std::optional<Luau::Name>> canUseTypeNameInScope(ScopePtr scope, const std::string& name)
|
||||
{
|
||||
for (ScopePtr curr = scope; curr; curr = curr->parent)
|
||||
for (ScopePtr curr = std::move(scope); curr; curr = curr->parent)
|
||||
{
|
||||
for (const auto& [importName, nameTable] : curr->importedTypeBindings)
|
||||
{
|
||||
|
@ -1957,7 +1957,7 @@ std::string toString(const Constraint& constraint, ToStringOptions& opts)
|
|||
return tos(c.resultType) + " ~ hasIndexer " + tos(c.subjectType) + " " + tos(c.indexType);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, AssignPropConstraint>)
|
||||
return "assignProp " + tos(c.lhsType) + " " + c.propName + " " + tos(c.rhsType);
|
||||
return tos(c.propType) + " ~ assignProp " + tos(c.lhsType) + " " + c.propName + " " + tos(c.rhsType);
|
||||
else if constexpr (std::is_same_v<T, AssignIndexConstraint>)
|
||||
return "assignIndex " + tos(c.lhsType) + " " + tos(c.indexType) + " " + tos(c.rhsType);
|
||||
else if constexpr (std::is_same_v<T, UnpackConstraint>)
|
||||
|
|
|
@ -2960,7 +2960,7 @@ TranspileResult transpile(std::string_view source, ParseOptions options, bool wi
|
|||
|
||||
auto allocator = Allocator{};
|
||||
auto names = AstNameTable{allocator};
|
||||
ParseResult parseResult = Parser::parse(source.data(), source.size(), names, allocator, options);
|
||||
ParseResult parseResult = Parser::parse(source.data(), source.size(), names, allocator, std::move(options));
|
||||
|
||||
if (!parseResult.errors.empty())
|
||||
{
|
||||
|
|
|
@ -585,8 +585,8 @@ PendingExpansionType::PendingExpansionType(
|
|||
)
|
||||
: prefix(prefix)
|
||||
, name(name)
|
||||
, typeArguments(typeArguments)
|
||||
, packArguments(packArguments)
|
||||
, typeArguments(std::move(typeArguments))
|
||||
, packArguments(std::move(packArguments))
|
||||
, index(++nextIndex)
|
||||
{
|
||||
}
|
||||
|
@ -619,8 +619,8 @@ FunctionType::FunctionType(
|
|||
bool hasSelf
|
||||
)
|
||||
: definition(std::move(defn))
|
||||
, generics(generics)
|
||||
, genericPacks(genericPacks)
|
||||
, generics(std::move(generics))
|
||||
, genericPacks(std::move(genericPacks))
|
||||
, argTypes(argTypes)
|
||||
, retTypes(retTypes)
|
||||
, hasSelf(hasSelf)
|
||||
|
@ -637,8 +637,8 @@ FunctionType::FunctionType(
|
|||
bool hasSelf
|
||||
)
|
||||
: definition(std::move(defn))
|
||||
, generics(generics)
|
||||
, genericPacks(genericPacks)
|
||||
, generics(std::move(generics))
|
||||
, genericPacks(std::move(genericPacks))
|
||||
, level(level)
|
||||
, argTypes(argTypes)
|
||||
, retTypes(retTypes)
|
||||
|
@ -1046,16 +1046,6 @@ BuiltinTypes::~BuiltinTypes()
|
|||
FFlag::DebugLuauFreezeArena.value = prevFlag;
|
||||
}
|
||||
|
||||
TypeId BuiltinTypes::errorRecoveryType() const
|
||||
{
|
||||
return errorType;
|
||||
}
|
||||
|
||||
TypePackId BuiltinTypes::errorRecoveryTypePack() const
|
||||
{
|
||||
return errorTypePack;
|
||||
}
|
||||
|
||||
TypeId BuiltinTypes::errorRecoveryType(TypeId guess) const
|
||||
{
|
||||
return guess;
|
||||
|
|
|
@ -36,7 +36,7 @@ LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
|||
LUAU_FASTFLAG(LuauNewNonStrictFixGenericTypePacks)
|
||||
LUAU_FASTFLAGVARIABLE(LuauReportSubtypingErrors)
|
||||
LUAU_FASTFLAGVARIABLE(LuauSkipMalformedTypeAliases)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauSubtypingCheckFunctionGenericCounts)
|
||||
|
||||
namespace Luau
|
||||
|
@ -598,7 +598,7 @@ TypePackId TypeChecker2::reconstructPack(AstArray<AstExpr*> exprs, TypeArena& ar
|
|||
}
|
||||
|
||||
TypePackId tail = lookupPack(exprs.data[exprs.size - 1]);
|
||||
return arena.addTypePack(TypePack{head, tail});
|
||||
return arena.addTypePack(TypePack{std::move(head), tail});
|
||||
}
|
||||
|
||||
Scope* TypeChecker2::findInnermostScope(Location location) const
|
||||
|
@ -713,7 +713,7 @@ void TypeChecker2::visit(AstStatReturn* ret)
|
|||
{
|
||||
Scope* scope = findInnermostScope(ret->location);
|
||||
TypePackId expectedRetType = scope->returnType;
|
||||
if (FFlag::LuauTableLiteralSubtypeSpecificCheck)
|
||||
if (FFlag::LuauTableLiteralSubtypeSpecificCheck2)
|
||||
{
|
||||
if (ret->list.size == 0)
|
||||
{
|
||||
|
@ -811,7 +811,7 @@ void TypeChecker2::visit(AstStatLocal* local)
|
|||
TypeId valueType = value ? lookupType(value) : nullptr;
|
||||
if (valueType)
|
||||
{
|
||||
if (FFlag::LuauTableLiteralSubtypeSpecificCheck)
|
||||
if (FFlag::LuauTableLiteralSubtypeSpecificCheck2)
|
||||
testPotentialLiteralIsSubtype(value, annotationType);
|
||||
else
|
||||
testIsSubtype(valueType, annotationType, value->location);
|
||||
|
@ -960,7 +960,7 @@ void TypeChecker2::visit(AstStatForIn* forInStatement)
|
|||
}
|
||||
|
||||
// and now we can put everything together to get the actual typepack of the iterators.
|
||||
TypePackId iteratorPack = arena.addTypePack(valueTypes, iteratorTail);
|
||||
TypePackId iteratorPack = arena.addTypePack(std::move(valueTypes), iteratorTail);
|
||||
|
||||
// ... and then expand it out to 3 values (if possible)
|
||||
TypePack iteratorTypes = extendTypePack(arena, builtinTypes, iteratorPack, 3);
|
||||
|
@ -1120,7 +1120,7 @@ void TypeChecker2::visit(AstStatForIn* forInStatement)
|
|||
|
||||
if (const FunctionType* nextFtv = get<FunctionType>(*instantiatedNextFn))
|
||||
{
|
||||
checkFunction(nextFtv, instantiatedIteratorTypes, true);
|
||||
checkFunction(nextFtv, std::move(instantiatedIteratorTypes), true);
|
||||
}
|
||||
else if (!isErrorSuppressing(forInStatement->values.data[0]->location, *instantiatedNextFn))
|
||||
{
|
||||
|
@ -1224,13 +1224,20 @@ void TypeChecker2::visit(AstStatAssign* assign)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (FFlag::LuauTableLiteralSubtypeSpecificCheck)
|
||||
if (FFlag::LuauTableLiteralSubtypeSpecificCheck2)
|
||||
{
|
||||
// If rhsType </: lhsType, then it's not useful to also report that rhsType </: bindingType
|
||||
if (testPotentialLiteralIsSubtype(rhs, lhsType))
|
||||
// FIXME CLI-142462: Due to the fact that we do not type state
|
||||
// tables properly, table types "time travel." We can take
|
||||
// advantage of this for the specific code pattern of:
|
||||
//
|
||||
// local t = {}
|
||||
// t.foo = {} -- Type of the RHS gets time warped to `{ bar: {} }`
|
||||
// t.foo.bar = {}
|
||||
//
|
||||
if (testLiteralOrAstTypeIsSubtype(rhs, lhsType))
|
||||
{
|
||||
if (std::optional<TypeId> bindingType = getBindingType(lhs))
|
||||
testPotentialLiteralIsSubtype(rhs, *bindingType);
|
||||
testLiteralOrAstTypeIsSubtype(rhs, *bindingType);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2137,7 +2144,7 @@ TypeId TypeChecker2::visit(AstExprBinary* expr, AstNode* overrideKey)
|
|||
auto name = getIdentifierOfBaseVar(expr->left);
|
||||
reportError(
|
||||
CannotInferBinaryOperation{
|
||||
expr->op, name, isComparison ? CannotInferBinaryOperation::OpKind::Comparison : CannotInferBinaryOperation::OpKind::Operation
|
||||
expr->op, std::move(name), isComparison ? CannotInferBinaryOperation::OpKind::Comparison : CannotInferBinaryOperation::OpKind::Operation
|
||||
},
|
||||
expr->location
|
||||
);
|
||||
|
@ -2197,7 +2204,7 @@ TypeId TypeChecker2::visit(AstExprBinary* expr, AstNode* overrideKey)
|
|||
expr->location
|
||||
);
|
||||
|
||||
return builtinTypes->errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
|
||||
std::optional<TypeId> mm;
|
||||
|
@ -2280,7 +2287,7 @@ TypeId TypeChecker2::visit(AstExprBinary* expr, AstNode* overrideKey)
|
|||
reportError(GenericError{format("Metamethod '%s' must return a value", it->second)}, expr->location);
|
||||
}
|
||||
|
||||
return builtinTypes->errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -2288,7 +2295,7 @@ TypeId TypeChecker2::visit(AstExprBinary* expr, AstNode* overrideKey)
|
|||
reportError(CannotCallNonFunction{*mm}, expr->location);
|
||||
}
|
||||
|
||||
return builtinTypes->errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
// If this is a string comparison, or a concatenation of strings, we
|
||||
// want to fall through to primitive behavior.
|
||||
|
@ -2323,7 +2330,7 @@ TypeId TypeChecker2::visit(AstExprBinary* expr, AstNode* overrideKey)
|
|||
);
|
||||
}
|
||||
|
||||
return builtinTypes->errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
else if (!leftMt && !rightMt && (get<TableType>(leftType) || get<TableType>(rightType)))
|
||||
{
|
||||
|
@ -2352,7 +2359,7 @@ TypeId TypeChecker2::visit(AstExprBinary* expr, AstNode* overrideKey)
|
|||
);
|
||||
}
|
||||
|
||||
return builtinTypes->errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2410,7 +2417,7 @@ TypeId TypeChecker2::visit(AstExprBinary* expr, AstNode* overrideKey)
|
|||
)},
|
||||
expr->location
|
||||
);
|
||||
return builtinTypes->errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
|
||||
case AstExprBinary::Op::And:
|
||||
|
@ -2423,7 +2430,7 @@ TypeId TypeChecker2::visit(AstExprBinary* expr, AstNode* overrideKey)
|
|||
default:
|
||||
// Unhandled AstExprBinary::Op possibility.
|
||||
LUAU_ASSERT(false);
|
||||
return builtinTypes->errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2509,7 +2516,7 @@ TypeId TypeChecker2::flattenPack(TypePackId pack)
|
|||
return result;
|
||||
}
|
||||
else if (get<ErrorTypePack>(pack))
|
||||
return builtinTypes->errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
else if (finite(pack) && size(pack) == 0)
|
||||
return builtinTypes->nilType; // `(f())` where `f()` returns no values is coerced into `nil`
|
||||
else
|
||||
|
@ -2721,7 +2728,7 @@ void TypeChecker2::visit(AstTypeReference* ty)
|
|||
}
|
||||
symbol += ty->name.value;
|
||||
|
||||
reportError(UnknownSymbol{symbol, UnknownSymbol::Context::Type}, ty->location);
|
||||
reportError(UnknownSymbol{std::move(symbol), UnknownSymbol::Context::Type}, ty->location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2967,6 +2974,17 @@ void TypeChecker2::explainError(TypePackId subTy, TypePackId superTy, Location l
|
|||
reportError(TypePackMismatch{superTy, subTy, reasonings.toString()}, location);
|
||||
}
|
||||
|
||||
bool TypeChecker2::testLiteralOrAstTypeIsSubtype(AstExpr* expr, TypeId expectedType)
|
||||
{
|
||||
NotNull<Scope> scope{findInnermostScope(expr->location)};
|
||||
auto exprTy = lookupType(expr);
|
||||
SubtypingResult r = subtyping->isSubtype(exprTy, expectedType, scope);
|
||||
if (r.isSubtype)
|
||||
return true;
|
||||
|
||||
return testPotentialLiteralIsSubtype(expr, expectedType);
|
||||
}
|
||||
|
||||
bool TypeChecker2::testPotentialLiteralIsSubtype(AstExpr* expr, TypeId expectedType)
|
||||
{
|
||||
auto exprType = follow(lookupType(expr));
|
||||
|
@ -3298,7 +3316,7 @@ PropertyTypes TypeChecker2::lookupProp(
|
|||
}
|
||||
}
|
||||
|
||||
return {typesOfProp, typesMissingTheProp};
|
||||
return {std::move(typesOfProp), std::move(typesMissingTheProp)};
|
||||
}
|
||||
|
||||
|
||||
|
@ -3445,9 +3463,9 @@ PropertyType TypeChecker2::hasIndexTypeFromType(
|
|||
|
||||
TypeId propTy;
|
||||
if (context == ValueContext::LValue)
|
||||
propTy = module->internalTypes.addType(IntersectionType{parts});
|
||||
propTy = module->internalTypes.addType(IntersectionType{std::move(parts)});
|
||||
else
|
||||
propTy = module->internalTypes.addType(UnionType{parts});
|
||||
propTy = module->internalTypes.addType(UnionType{std::move(parts)});
|
||||
|
||||
return {NormalizationResult::True, propTy};
|
||||
}
|
||||
|
@ -3501,7 +3519,7 @@ void TypeChecker2::diagnoseMissingTableKey(UnknownProperty* utk, TypeErrorData&
|
|||
}
|
||||
|
||||
if (!candidates.empty())
|
||||
data = TypeErrorData(UnknownPropButFoundLikeProp{utk->table, utk->key, candidates});
|
||||
data = TypeErrorData(UnknownPropButFoundLikeProp{utk->table, utk->key, std::move(candidates)});
|
||||
}
|
||||
|
||||
bool TypeChecker2::isErrorSuppressing(Location loc, TypeId ty)
|
||||
|
|
|
@ -48,14 +48,15 @@ LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFamilyApplicationCartesianProductLimit, 5'0
|
|||
LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFamilyUseGuesserDepth, -1);
|
||||
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauLogTypeFamilies)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNarrowIntersectionNevers)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNotAllBinaryTypeFunsHaveDefaults)
|
||||
LUAU_FASTFLAG(LuauUserTypeFunctionAliases)
|
||||
LUAU_FASTFLAG(LuauUpdateGetMetatableTypeSignature)
|
||||
LUAU_FASTFLAGVARIABLE(LuauOccursCheckForRefinement)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -264,7 +265,7 @@ struct TypeFunctionReducer
|
|||
Okay,
|
||||
};
|
||||
|
||||
SkipTestResult testForSkippability(TypeId ty)
|
||||
SkipTestResult DEPRECATED_testForSkippability(TypeId ty)
|
||||
{
|
||||
ty = follow(ty);
|
||||
|
||||
|
@ -283,7 +284,7 @@ struct TypeFunctionReducer
|
|||
}
|
||||
else if (is<GenericType>(ty))
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
return SkipTestResult::Generic;
|
||||
else
|
||||
return SkipTestResult::Irreducible;
|
||||
|
@ -292,6 +293,51 @@ struct TypeFunctionReducer
|
|||
return SkipTestResult::Okay;
|
||||
}
|
||||
|
||||
SkipTestResult testForSkippability(TypeId ty)
|
||||
{
|
||||
if (!FFlag::LuauEagerGeneralization4)
|
||||
return DEPRECATED_testForSkippability(ty);
|
||||
|
||||
VecDeque<TypeId> queue;
|
||||
DenseHashSet<TypeId> seen{nullptr};
|
||||
|
||||
queue.push_back(follow(ty));
|
||||
|
||||
while (!queue.empty())
|
||||
{
|
||||
TypeId t = queue.front();
|
||||
queue.pop_front();
|
||||
|
||||
if (seen.contains(t))
|
||||
continue;
|
||||
|
||||
if (is<TypeFunctionInstanceType>(t))
|
||||
{
|
||||
for (auto cyclicTy : cyclicTypeFunctions)
|
||||
{
|
||||
if (t == cyclicTy)
|
||||
return SkipTestResult::CyclicTypeFunction;
|
||||
}
|
||||
|
||||
if (!irreducible.contains(t))
|
||||
return SkipTestResult::Defer;
|
||||
|
||||
return SkipTestResult::Irreducible;
|
||||
}
|
||||
else if (is<GenericType>(t))
|
||||
return SkipTestResult::Generic;
|
||||
else if (auto it = get<IntersectionType>(t))
|
||||
{
|
||||
for (TypeId part : it->parts)
|
||||
queue.push_back(follow(part));
|
||||
}
|
||||
|
||||
seen.insert(t);
|
||||
}
|
||||
|
||||
return SkipTestResult::Okay;
|
||||
}
|
||||
|
||||
SkipTestResult testForSkippability(TypePackId ty) const
|
||||
{
|
||||
ty = follow(ty);
|
||||
|
@ -305,7 +351,7 @@ struct TypeFunctionReducer
|
|||
}
|
||||
else if (is<GenericTypePack>(ty))
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
return SkipTestResult::Generic;
|
||||
else
|
||||
return SkipTestResult::Irreducible;
|
||||
|
@ -517,7 +563,7 @@ struct TypeFunctionReducer
|
|||
ctx.userFuncName = tfit->userFuncName;
|
||||
|
||||
TypeFunctionReductionResult<TypeId> result = tfit->function->reducer(subject, tfit->typeArguments, tfit->packArguments, NotNull{&ctx});
|
||||
handleTypeFunctionReduction(subject, result);
|
||||
handleTypeFunctionReduction(subject, std::move(result));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -542,7 +588,7 @@ struct TypeFunctionReducer
|
|||
|
||||
TypeFunctionReductionResult<TypePackId> result =
|
||||
tfit->function->reducer(subject, tfit->typeArguments, tfit->packArguments, NotNull{&ctx});
|
||||
handleTypeFunctionReduction(subject, result);
|
||||
handleTypeFunctionReduction(subject, std::move(result));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -752,7 +798,7 @@ static std::optional<TypeFunctionReductionResult<TypeId>> tryDistributeTypeFunct
|
|||
}
|
||||
|
||||
if (reductionStatus != Reduction::MaybeOk || !blockedTypes.empty())
|
||||
return {{std::nullopt, reductionStatus, blockedTypes, {}}};
|
||||
return {{std::nullopt, reductionStatus, std::move(blockedTypes), {}}};
|
||||
|
||||
if (!results.empty())
|
||||
{
|
||||
|
@ -924,7 +970,7 @@ TypeFunctionReductionResult<TypeId> userDefinedTypeFunction(
|
|||
|
||||
// If type functions cannot be evaluated because of errors in the code, we do not generate any additional ones
|
||||
if (!ctx->typeFunctionRuntime->allowEvaluation || typeFunction->userFuncData.definition->hasErrors)
|
||||
return {ctx->builtins->errorRecoveryType(), Reduction::MaybeOk, {}, {}};
|
||||
return {ctx->builtins->errorType, Reduction::MaybeOk, {}, {}};
|
||||
|
||||
FindUserTypeFunctionBlockers check{ctx};
|
||||
|
||||
|
@ -949,7 +995,7 @@ TypeFunctionReductionResult<TypeId> userDefinedTypeFunction(
|
|||
{
|
||||
// Cannot evaluate if a potential dependency couldn't be parsed
|
||||
if (definition.first->hasErrors)
|
||||
return {ctx->builtins->errorRecoveryType(), Reduction::MaybeOk, {}, {}};
|
||||
return {ctx->builtins->errorType, Reduction::MaybeOk, {}, {}};
|
||||
|
||||
if (std::optional<std::string> error = ctx->typeFunctionRuntime->registerFunction(definition.first))
|
||||
{
|
||||
|
@ -1090,7 +1136,7 @@ TypeFunctionReductionResult<TypeId> userDefinedTypeFunction(
|
|||
ctx->typeFunctionRuntime->messages.clear();
|
||||
|
||||
if (auto error = checkResultForError(L, name.value, lua_pcall(L, int(typeParams.size()), 1, 0)))
|
||||
return {std::nullopt, Reduction::Erroneous, {}, {}, error, ctx->typeFunctionRuntime->messages};
|
||||
return {std::nullopt, Reduction::Erroneous, {}, {}, std::move(error), ctx->typeFunctionRuntime->messages};
|
||||
|
||||
// If the return value is not a type userdata, return with error message
|
||||
if (!isTypeUserData(L, 1))
|
||||
|
@ -1222,7 +1268,7 @@ TypeFunctionReductionResult<TypeId> lenTypeFunction(
|
|||
|
||||
const FunctionType* instantiatedMmFtv = get<FunctionType>(*instantiatedMmType);
|
||||
if (!instantiatedMmFtv)
|
||||
return {ctx->builtins->errorRecoveryType(), Reduction::MaybeOk, {}, {}};
|
||||
return {ctx->builtins->errorType, Reduction::MaybeOk, {}, {}};
|
||||
|
||||
TypePackId inferredArgPack = ctx->arena->addTypePack({operandTy});
|
||||
Unifier2 u2{ctx->arena, ctx->builtins, ctx->scope, ctx->ice};
|
||||
|
@ -1259,7 +1305,7 @@ TypeFunctionReductionResult<TypeId> unmTypeFunction(
|
|||
if (isPending(operandTy, ctx->solver))
|
||||
return {std::nullopt, Reduction::MaybeOk, {operandTy}, {}};
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
operandTy = follow(operandTy);
|
||||
|
||||
std::shared_ptr<const NormalizedType> normTy = ctx->normalizer->normalize(operandTy);
|
||||
|
@ -1305,7 +1351,7 @@ TypeFunctionReductionResult<TypeId> unmTypeFunction(
|
|||
|
||||
const FunctionType* instantiatedMmFtv = get<FunctionType>(*instantiatedMmType);
|
||||
if (!instantiatedMmFtv)
|
||||
return {ctx->builtins->errorRecoveryType(), Reduction::MaybeOk, {}, {}};
|
||||
return {ctx->builtins->errorType, Reduction::MaybeOk, {}, {}};
|
||||
|
||||
TypePackId inferredArgPack = ctx->arena->addTypePack({operandTy});
|
||||
Unifier2 u2{ctx->arena, ctx->builtins, ctx->scope, ctx->ice};
|
||||
|
@ -1772,7 +1818,7 @@ TypeFunctionReductionResult<TypeId> concatTypeFunction(
|
|||
|
||||
const FunctionType* instantiatedMmFtv = get<FunctionType>(*instantiatedMmType);
|
||||
if (!instantiatedMmFtv)
|
||||
return {ctx->builtins->errorRecoveryType(), Reduction::MaybeOk, {}, {}};
|
||||
return {ctx->builtins->errorType, Reduction::MaybeOk, {}, {}};
|
||||
|
||||
std::vector<TypeId> inferredArgs;
|
||||
if (!reversed)
|
||||
|
@ -1856,7 +1902,7 @@ TypeFunctionReductionResult<TypeId> orTypeFunction(
|
|||
return {rhsTy, Reduction::MaybeOk, {}, {}};
|
||||
|
||||
// check to see if both operand types are resolved enough, and wait to reduce if not
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(lhsTy))
|
||||
return {std::nullopt, Reduction::MaybeOk, {lhsTy}, {}};
|
||||
|
@ -1903,7 +1949,7 @@ static TypeFunctionReductionResult<TypeId> comparisonTypeFunction(
|
|||
if (lhsTy == instance || rhsTy == instance)
|
||||
return {ctx->builtins->neverType, Reduction::MaybeOk, {}, {}};
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(lhsTy))
|
||||
return {std::nullopt, Reduction::MaybeOk, {lhsTy}, {}};
|
||||
|
@ -1997,7 +2043,7 @@ static TypeFunctionReductionResult<TypeId> comparisonTypeFunction(
|
|||
|
||||
const FunctionType* instantiatedMmFtv = get<FunctionType>(*instantiatedMmType);
|
||||
if (!instantiatedMmFtv)
|
||||
return {ctx->builtins->errorRecoveryType(), Reduction::MaybeOk, {}, {}};
|
||||
return {ctx->builtins->errorType, Reduction::MaybeOk, {}, {}};
|
||||
|
||||
TypePackId inferredArgPack = ctx->arena->addTypePack({lhsTy, rhsTy});
|
||||
Unifier2 u2{ctx->arena, ctx->builtins, ctx->scope, ctx->ice};
|
||||
|
@ -2126,7 +2172,7 @@ TypeFunctionReductionResult<TypeId> eqTypeFunction(
|
|||
|
||||
const FunctionType* instantiatedMmFtv = get<FunctionType>(*instantiatedMmType);
|
||||
if (!instantiatedMmFtv)
|
||||
return {ctx->builtins->errorRecoveryType(), Reduction::MaybeOk, {}, {}};
|
||||
return {ctx->builtins->errorType, Reduction::MaybeOk, {}, {}};
|
||||
|
||||
TypePackId inferredArgPack = ctx->arena->addTypePack({lhsTy, rhsTy});
|
||||
Unifier2 u2{ctx->arena, ctx->builtins, ctx->scope, ctx->ice};
|
||||
|
@ -2247,6 +2293,98 @@ bool isSimpleDiscriminant(TypeId ty)
|
|||
return isApproximateTruthy(ty) || isApproximateFalsy(ty);
|
||||
}
|
||||
|
||||
struct RefineTypeScrubber : public Substitution
|
||||
{
|
||||
NotNull<TypeFunctionContext> ctx;
|
||||
TypeId needle;
|
||||
|
||||
explicit RefineTypeScrubber(NotNull<TypeFunctionContext> ctx, TypeId needle)
|
||||
: Substitution(ctx->arena)
|
||||
, ctx{ctx}
|
||||
, needle{needle}
|
||||
{
|
||||
}
|
||||
|
||||
bool isDirty(TypePackId tp) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ignoreChildren(TypePackId tp) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TypePackId clean(TypePackId tp) override
|
||||
{
|
||||
return tp;
|
||||
}
|
||||
|
||||
bool isDirty(TypeId ty) override
|
||||
{
|
||||
if (auto ut = get<UnionType>(ty))
|
||||
{
|
||||
for (auto option : ut)
|
||||
{
|
||||
if (option == needle)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (auto it = get<IntersectionType>(ty))
|
||||
{
|
||||
for (auto part : it)
|
||||
{
|
||||
if (part == needle)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ignoreChildren(TypeId ty) override
|
||||
{
|
||||
return !is<UnionType, IntersectionType>(ty);
|
||||
}
|
||||
|
||||
TypeId clean(TypeId ty) override
|
||||
{
|
||||
// NOTE: this feels pretty similar to other places where we try to
|
||||
// filter over a set type, may be worth combining those in the future.
|
||||
if (auto ut = get<UnionType>(ty))
|
||||
{
|
||||
TypeIds newOptions;
|
||||
for (auto option : ut)
|
||||
{
|
||||
if (option != needle && !is<NeverType>(option))
|
||||
newOptions.insert(option);
|
||||
}
|
||||
if (newOptions.empty())
|
||||
return ctx->builtins->neverType;
|
||||
else if (newOptions.size() == 1)
|
||||
return *newOptions.begin();
|
||||
else
|
||||
return ctx->arena->addType(UnionType{newOptions.take()});
|
||||
}
|
||||
else if (auto it = get<IntersectionType>(ty))
|
||||
{
|
||||
TypeIds newParts;
|
||||
for (auto part : it)
|
||||
{
|
||||
if (part != needle && !is<UnknownType>(part))
|
||||
newParts.insert(part);
|
||||
}
|
||||
if (newParts.empty())
|
||||
return ctx->builtins->unknownType;
|
||||
else if (newParts.size() == 1)
|
||||
return *newParts.begin();
|
||||
else
|
||||
return ctx->arena->addType(IntersectionType{newParts.take()});
|
||||
}
|
||||
return ty;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TypeFunctionReductionResult<TypeId> refineTypeFunction(
|
||||
|
@ -2263,11 +2401,30 @@ TypeFunctionReductionResult<TypeId> refineTypeFunction(
|
|||
}
|
||||
|
||||
TypeId targetTy = follow(typeParams.at(0));
|
||||
|
||||
if (FFlag::LuauOccursCheckForRefinement)
|
||||
{
|
||||
// If we end up minting a refine type like:
|
||||
//
|
||||
// t1 where t1 = refine<T | t1, Y>
|
||||
//
|
||||
// This can create a degenerate set type such as:
|
||||
//
|
||||
// t1 where t1 = (T | t1) & Y
|
||||
//
|
||||
// Instead, we can clip the recursive part:
|
||||
//
|
||||
// t1 where t1 = refine<T | t1, Y> => refine<T, Y>
|
||||
RefineTypeScrubber rts{ctx, instance};
|
||||
if (auto result = rts.substitute(targetTy))
|
||||
targetTy = *result;
|
||||
}
|
||||
|
||||
std::vector<TypeId> discriminantTypes;
|
||||
for (size_t i = 1; i < typeParams.size(); i++)
|
||||
discriminantTypes.push_back(follow(typeParams.at(i)));
|
||||
|
||||
const bool targetIsPending = FFlag::LuauEagerGeneralization3 ? is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(targetTy)
|
||||
const bool targetIsPending = FFlag::LuauEagerGeneralization4 ? is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(targetTy)
|
||||
: isPending(targetTy, ctx->solver);
|
||||
|
||||
// check to see if both operand types are resolved enough, and wait to reduce if not
|
||||
|
@ -2348,7 +2505,7 @@ TypeFunctionReductionResult<TypeId> refineTypeFunction(
|
|||
if (is<TableType>(target) || isSimpleDiscriminant(discriminant))
|
||||
{
|
||||
SimplifyResult result = simplifyIntersection(ctx->builtins, ctx->arena, target, discriminant);
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
// Simplification considers free and generic types to be
|
||||
// 'blocking', but that's not suitable for refine<>.
|
||||
|
@ -2844,7 +3001,7 @@ TypeFunctionReductionResult<TypeId> keyofFunctionImpl(
|
|||
if (singletons.size() == 1)
|
||||
return {singletons.front(), Reduction::MaybeOk, {}, {}};
|
||||
|
||||
return {ctx->arena->addType(UnionType{singletons}), Reduction::MaybeOk, {}, {}};
|
||||
return {ctx->arena->addType(UnionType{std::move(singletons)}), Reduction::MaybeOk, {}, {}};
|
||||
}
|
||||
|
||||
TypeFunctionReductionResult<TypeId> keyofTypeFunction(
|
||||
|
@ -3289,7 +3446,7 @@ TypeFunctionReductionResult<TypeId> setmetatableTypeFunction(
|
|||
blockedTypes.reserve(simplified.blockedTypes.size());
|
||||
for (auto ty : simplified.blockedTypes)
|
||||
blockedTypes.push_back(ty);
|
||||
return {std::nullopt, Reduction::MaybeOk, blockedTypes, {}};
|
||||
return {std::nullopt, Reduction::MaybeOk, std::move(blockedTypes), {}};
|
||||
}
|
||||
|
||||
result = simplified.result;
|
||||
|
@ -3489,7 +3646,7 @@ BuiltinTypeFunctions::BuiltinTypeFunctions()
|
|||
, ltFunc{"lt", ltTypeFunction}
|
||||
, leFunc{"le", leTypeFunction}
|
||||
, eqFunc{"eq", eqTypeFunction}
|
||||
, refineFunc{"refine", refineTypeFunction, /*canReduceGenerics*/ FFlag::LuauEagerGeneralization3}
|
||||
, refineFunc{"refine", refineTypeFunction, /*canReduceGenerics*/ FFlag::LuauEagerGeneralization4}
|
||||
, singletonFunc{"singleton", singletonTypeFunction}
|
||||
, unionFunc{"union", unionTypeFunction}
|
||||
, intersectFunc{"intersect", intersectTypeFunction}
|
||||
|
|
|
@ -125,7 +125,7 @@ std::optional<TypePackId> TypeFunctionReductionGuesser::guess(TypePackId tp)
|
|||
guessedHead.push_back(*guessedType);
|
||||
}
|
||||
|
||||
return arena->addTypePack(TypePack{guessedHead, tail});
|
||||
return arena->addTypePack(TypePack{std::move(guessedHead), tail});
|
||||
}
|
||||
|
||||
TypeFunctionReductionGuessResult TypeFunctionReductionGuesser::guessTypeFunctionReductionForFunctionExpr(
|
||||
|
@ -182,7 +182,7 @@ TypeFunctionReductionGuessResult TypeFunctionReductionGuesser::guessTypeFunction
|
|||
functionReducesTo.clear();
|
||||
substitutable.clear();
|
||||
|
||||
return TypeFunctionReductionGuessResult{results, recommendedAnnotation};
|
||||
return TypeFunctionReductionGuessResult{std::move(results), recommendedAnnotation};
|
||||
}
|
||||
|
||||
std::optional<TypeId> TypeFunctionReductionGuesser::guessType(TypeId arg)
|
||||
|
|
|
@ -342,7 +342,7 @@ static int createOptional(lua_State* L)
|
|||
|
||||
components.emplace_back(allocateTypeFunctionType(L, TypeFunctionPrimitiveType(TypeFunctionPrimitiveType::NilType)));
|
||||
|
||||
allocTypeUserData(L, TypeFunctionUnionType{components});
|
||||
allocTypeUserData(L, TypeFunctionUnionType{std::move(components)});
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -362,7 +362,7 @@ static int createUnion(lua_State* L)
|
|||
for (int i = 1; i <= argSize; i++)
|
||||
components.push_back(getTypeUserData(L, i));
|
||||
|
||||
allocTypeUserData(L, TypeFunctionUnionType{components});
|
||||
allocTypeUserData(L, TypeFunctionUnionType{std::move(components)});
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -382,7 +382,7 @@ static int createIntersection(lua_State* L)
|
|||
for (int i = 1; i <= argSize; i++)
|
||||
components.push_back(getTypeUserData(L, i));
|
||||
|
||||
allocTypeUserData(L, TypeFunctionIntersectionType{components});
|
||||
allocTypeUserData(L, TypeFunctionIntersectionType{std::move(components)});
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -542,7 +542,7 @@ static int createTable(lua_State* L)
|
|||
if (metatable && !get<TypeFunctionTableType>(*metatable))
|
||||
luaL_error(L, "types.newtable: expected to be given a table type as a metatable, but got %s instead", getTag(L, *metatable).c_str());
|
||||
|
||||
allocTypeUserData(L, TypeFunctionTableType{props, indexer, metatable});
|
||||
allocTypeUserData(L, TypeFunctionTableType{std::move(props), indexer, metatable});
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -904,7 +904,7 @@ static TypeFunctionTypePackId getTypePack(lua_State* L, int headIdx, int tailIdx
|
|||
if (head.size() == 0 && tail.has_value())
|
||||
result = *tail;
|
||||
else
|
||||
result = allocateTypeFunctionTypePack(L, TypeFunctionTypePack{head, tail});
|
||||
result = allocateTypeFunctionTypePack(L, TypeFunctionTypePack{std::move(head), tail});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -218,7 +218,7 @@ private:
|
|||
if (!g->explicitName)
|
||||
name = format("g%d", g->index);
|
||||
|
||||
target = typeFunctionRuntime->typeArena.allocate(TypeFunctionGenericType{g->explicitName, false, name});
|
||||
target = typeFunctionRuntime->typeArena.allocate(TypeFunctionGenericType{g->explicitName, false, std::move(name)});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -251,7 +251,7 @@ private:
|
|||
if (!gPack->explicitName)
|
||||
name = format("g%d", gPack->index);
|
||||
|
||||
target = typeFunctionRuntime->typePackArena.allocate(TypeFunctionGenericTypePack{gPack->explicitName, name});
|
||||
target = typeFunctionRuntime->typePackArena.allocate(TypeFunctionGenericTypePack{gPack->explicitName, std::move(name)});
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -527,12 +527,12 @@ public:
|
|||
|
||||
if (hasExceededIterationLimit() || state->errors.size() != 0)
|
||||
{
|
||||
TypeId error = state->ctx->builtins->errorRecoveryType();
|
||||
TypeId error = state->ctx->builtins->errorType;
|
||||
types[ty] = error;
|
||||
return error;
|
||||
}
|
||||
|
||||
return find(ty).value_or(state->ctx->builtins->errorRecoveryType());
|
||||
return find(ty).value_or(state->ctx->builtins->errorType);
|
||||
}
|
||||
|
||||
TypePackId deserialize(TypeFunctionTypePackId tp)
|
||||
|
@ -542,12 +542,12 @@ public:
|
|||
|
||||
if (hasExceededIterationLimit() || state->errors.size() != 0)
|
||||
{
|
||||
TypePackId error = state->ctx->builtins->errorRecoveryTypePack();
|
||||
TypePackId error = state->ctx->builtins->errorTypePack;
|
||||
packs[tp] = error;
|
||||
return error;
|
||||
}
|
||||
|
||||
return find(tp).value_or(state->ctx->builtins->errorRecoveryTypePack());
|
||||
return find(tp).value_or(state->ctx->builtins->errorTypePack);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -232,7 +232,7 @@ ModulePtr TypeChecker::check(const SourceModule& module, Mode mode, std::optiona
|
|||
{
|
||||
try
|
||||
{
|
||||
return checkWithoutRecursionCheck(module, mode, environmentScope);
|
||||
return checkWithoutRecursionCheck(module, mode, std::move(environmentScope));
|
||||
}
|
||||
catch (const RecursionLimitException&)
|
||||
{
|
||||
|
@ -688,7 +688,7 @@ static std::optional<Predicate> tryGetTypeGuardPredicate(const AstExprBinary& ex
|
|||
if (!lvalue)
|
||||
return std::nullopt;
|
||||
|
||||
Predicate predicate{TypeGuardPredicate{std::move(*lvalue), expr.location, ssval, isTypeof}};
|
||||
Predicate predicate{TypeGuardPredicate{std::move(*lvalue), expr.location, std::move(ssval), isTypeof}};
|
||||
if (expr.op == AstExprBinary::Op::CompareNe)
|
||||
return NotPredicate{{std::move(predicate)}};
|
||||
|
||||
|
@ -1372,7 +1372,7 @@ ControlFlow TypeChecker::check(const ScopePtr& scope, const AstStatForIn& forin)
|
|||
varTypes.front() = *fty;
|
||||
}
|
||||
|
||||
TypePackId varPack = addTypePack(TypePackVar{TypePack{varTypes, freshTypePack(scope)}});
|
||||
TypePackId varPack = addTypePack(TypePackVar{TypePack{std::move(varTypes), freshTypePack(scope)}});
|
||||
|
||||
unify(retPack, varPack, scope, forin.location);
|
||||
|
||||
|
@ -1681,7 +1681,7 @@ void TypeChecker::prototype(const ScopePtr& scope, const AstStatDeclareExternTyp
|
|||
|
||||
if (!lookupType)
|
||||
{
|
||||
reportError(declaredExternType.location, UnknownSymbol{superName, UnknownSymbol::Type});
|
||||
reportError(declaredExternType.location, UnknownSymbol{std::move(superName), UnknownSymbol::Type});
|
||||
incorrectExternTypeDefinitions.insert(&declaredExternType);
|
||||
return;
|
||||
}
|
||||
|
@ -2166,7 +2166,7 @@ std::optional<TypeId> TypeChecker::getIndexTypeFromTypeImpl(
|
|||
if (goodOptions.empty())
|
||||
reportError(location, UnknownProperty{type, name});
|
||||
else
|
||||
reportError(location, MissingUnionProperty{type, badOptions, name});
|
||||
reportError(location, MissingUnionProperty{type, std::move(badOptions), name});
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -2615,7 +2615,7 @@ TypeId TypeChecker::unionOfTypes(TypeId a, TypeId b, const ScopePtr& scope, cons
|
|||
if (types.size() == 1)
|
||||
return types[0];
|
||||
|
||||
return addType(UnionType{types});
|
||||
return addType(UnionType{std::move(types)});
|
||||
}
|
||||
|
||||
static std::optional<std::string> getIdentifierOfBaseVar(AstExpr* node)
|
||||
|
@ -2923,7 +2923,7 @@ TypeId TypeChecker::checkRelationalOperation(
|
|||
if (get<FreeType>(follow(lhsType)) && !isEquality)
|
||||
{
|
||||
auto name = getIdentifierOfBaseVar(expr.left);
|
||||
reportError(expr.location, CannotInferBinaryOperation{expr.op, name, CannotInferBinaryOperation::Comparison});
|
||||
reportError(expr.location, CannotInferBinaryOperation{expr.op, std::move(name), CannotInferBinaryOperation::Comparison});
|
||||
return errorRecoveryType(booleanType);
|
||||
}
|
||||
|
||||
|
@ -3032,7 +3032,7 @@ TypeId TypeChecker::checkBinaryOperation(
|
|||
if (!isNonstrictMode() && get<FreeType>(lhsType))
|
||||
{
|
||||
auto name = getIdentifierOfBaseVar(expr.left);
|
||||
reportError(expr.location, CannotInferBinaryOperation{expr.op, name, CannotInferBinaryOperation::Operation});
|
||||
reportError(expr.location, CannotInferBinaryOperation{expr.op, std::move(name), CannotInferBinaryOperation::Operation});
|
||||
// We will fall-through to the `return anyType` check below.
|
||||
}
|
||||
|
||||
|
@ -3102,7 +3102,7 @@ TypeId TypeChecker::checkBinaryOperation(
|
|||
std::string op = opToMetaTableEntry(expr.op);
|
||||
if (auto fnt = findMetatableEntry(lhsType, op, expr.location, /* addErrors= */ true))
|
||||
return checkMetatableCall(*fnt, lhsType, rhsType);
|
||||
if (auto fnt = findMetatableEntry(rhsType, op, expr.location, /* addErrors= */ true))
|
||||
if (auto fnt = findMetatableEntry(rhsType, std::move(op), expr.location, /* addErrors= */ true))
|
||||
{
|
||||
// Note the intentionally reversed arguments here.
|
||||
return checkMetatableCall(*fnt, rhsType, lhsType);
|
||||
|
@ -3382,7 +3382,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprGloba
|
|||
// If we're in strict mode, we want to report defining a global as an error,
|
||||
// but still add it to the bindings, so that autocomplete includes it in completions.
|
||||
if (!isNonstrictMode())
|
||||
reportError(TypeError{expr.location, UnknownSymbol{name, UnknownSymbol::Binding}});
|
||||
reportError(TypeError{expr.location, UnknownSymbol{std::move(name), UnknownSymbol::Binding}});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -3426,7 +3426,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex
|
|||
if (!state.errors.empty())
|
||||
{
|
||||
|
||||
reportError(expr.location, UnknownProperty{lhs, name});
|
||||
reportError(expr.location, UnknownProperty{lhs, std::move(name)});
|
||||
retType = errorRecoveryType(retType);
|
||||
}
|
||||
else
|
||||
|
@ -3436,7 +3436,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex
|
|||
}
|
||||
else if (lhsTable->state == TableState::Sealed)
|
||||
{
|
||||
reportError(TypeError{expr.location, CannotExtendTable{lhs, CannotExtendTable::Property, name}});
|
||||
reportError(TypeError{expr.location, CannotExtendTable{lhs, CannotExtendTable::Property, std::move(name)}});
|
||||
return errorRecoveryType(scope);
|
||||
}
|
||||
else
|
||||
|
@ -3463,7 +3463,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex
|
|||
}
|
||||
}
|
||||
|
||||
reportError(TypeError{expr.location, UnknownProperty{lhs, name}});
|
||||
reportError(TypeError{expr.location, UnknownProperty{lhs, std::move(name)}});
|
||||
return errorRecoveryType(scope);
|
||||
}
|
||||
else if (get<IntersectionType>(lhs))
|
||||
|
@ -3474,7 +3474,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex
|
|||
// If intersection has a table part, report that it cannot be extended just as a sealed table
|
||||
if (isTableIntersection(lhs))
|
||||
{
|
||||
reportError(TypeError{expr.location, CannotExtendTable{lhs, CannotExtendTable::Property, name}});
|
||||
reportError(TypeError{expr.location, CannotExtendTable{lhs, CannotExtendTable::Property, std::move(name)}});
|
||||
return errorRecoveryType(scope);
|
||||
}
|
||||
}
|
||||
|
@ -3530,7 +3530,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex
|
|||
// If intersection has a table part, report that it cannot be extended just as a sealed table
|
||||
if (isTableIntersection(exprType))
|
||||
{
|
||||
reportError(TypeError{expr.location, CannotExtendTable{exprType, CannotExtendTable::Property, name}});
|
||||
reportError(TypeError{expr.location, CannotExtendTable{exprType, CannotExtendTable::Property, std::move(name)}});
|
||||
return errorRecoveryType(scope);
|
||||
}
|
||||
}
|
||||
|
@ -3645,7 +3645,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex
|
|||
if (options.size() == 1)
|
||||
return options[0];
|
||||
|
||||
return addType(UnionType{options});
|
||||
return addType(UnionType{std::move(options)});
|
||||
}
|
||||
|
||||
return addType(IntersectionType{{propTypes.begin(), propTypes.end()}});
|
||||
|
@ -3700,7 +3700,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex
|
|||
if (options.size() == 1)
|
||||
return options[0];
|
||||
|
||||
return addType(UnionType{options});
|
||||
return addType(UnionType{std::move(options)});
|
||||
}
|
||||
|
||||
return addType(IntersectionType{{resultTypes.begin(), resultTypes.end()}});
|
||||
|
@ -3941,7 +3941,7 @@ std::pair<TypeId, ScopePtr> TypeChecker::checkFunctionSignature(
|
|||
++expectedArgsCurr;
|
||||
}
|
||||
|
||||
TypePackId argPack = addTypePack(TypePackVar(TypePack{argTypes, funScope->varargPack}));
|
||||
TypePackId argPack = addTypePack(TypePackVar(TypePack{std::move(argTypes), funScope->varargPack}));
|
||||
|
||||
FunctionDefinition defn;
|
||||
defn.definitionModuleName = currentModule->name;
|
||||
|
@ -4129,7 +4129,7 @@ void TypeChecker::checkArgumentList(
|
|||
auto [minParams, optMaxParams] = getParameterExtents(&state.log, paramPack);
|
||||
state.reportError(TypeError{
|
||||
location,
|
||||
CountMismatch{minParams, optMaxParams, std::distance(begin(argPack), end(argPack)), CountMismatch::Context::Arg, false, namePath}
|
||||
CountMismatch{minParams, optMaxParams, std::distance(begin(argPack), end(argPack)), CountMismatch::Context::Arg, false, std::move(namePath)}
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -4219,7 +4219,7 @@ void TypeChecker::checkArgumentList(
|
|||
return;
|
||||
}
|
||||
|
||||
TypePackId varPack = addTypePack(TypePackVar{TypePack{rest, paramIter.tail()}});
|
||||
TypePackId varPack = addTypePack(TypePackVar{TypePack{std::move(rest), paramIter.tail()}});
|
||||
state.tryUnify(tail, varPack);
|
||||
return;
|
||||
}
|
||||
|
@ -4248,7 +4248,7 @@ void TypeChecker::checkArgumentList(
|
|||
namePath = *path;
|
||||
|
||||
state.reportError(TypeError{
|
||||
funName.location, CountMismatch{minParams, optMaxParams, paramIndex, CountMismatch::Context::Arg, isVariadic, namePath}
|
||||
funName.location, CountMismatch{minParams, optMaxParams, paramIndex, CountMismatch::Context::Arg, isVariadic, std::move(namePath)}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -4325,7 +4325,7 @@ void TypeChecker::checkArgumentList(
|
|||
return;
|
||||
}
|
||||
|
||||
TypePackId varPack = addTypePack(TypePackVar{TypePack{rest, argIter.tail()}});
|
||||
TypePackId varPack = addTypePack(TypePackVar{TypePack{std::move(rest), argIter.tail()}});
|
||||
state.tryUnify(varPack, tail);
|
||||
|
||||
return;
|
||||
|
@ -4950,7 +4950,7 @@ WithPredicate<TypePackId> TypeChecker::checkExprList(
|
|||
|
||||
if (uninhabitable)
|
||||
return WithPredicate{uninhabitableTypePack};
|
||||
return {pack, predicates};
|
||||
return {pack, std::move(predicates)};
|
||||
}
|
||||
|
||||
std::optional<AstExpr*> TypeChecker::matchRequire(const AstExprCall& call)
|
||||
|
@ -5314,7 +5314,7 @@ void TypeChecker::diagnoseMissingTableKey(UnknownProperty* utk, TypeErrorData& d
|
|||
}
|
||||
|
||||
if (!candidates.empty())
|
||||
data = TypeErrorData(UnknownPropButFoundLikeProp{utk->table, utk->key, candidates});
|
||||
data = TypeErrorData(UnknownPropButFoundLikeProp{utk->table, utk->key, std::move(candidates)});
|
||||
}
|
||||
|
||||
LUAU_NOINLINE void TypeChecker::reportErrorCodeTooComplex(const Location& location)
|
||||
|
@ -5404,7 +5404,7 @@ TypeId TypeChecker::singletonType(std::string value)
|
|||
|
||||
TypeId TypeChecker::errorRecoveryType(const ScopePtr& scope)
|
||||
{
|
||||
return builtinTypes->errorRecoveryType();
|
||||
return builtinTypes->errorType;
|
||||
}
|
||||
|
||||
TypeId TypeChecker::errorRecoveryType(TypeId guess)
|
||||
|
@ -5414,7 +5414,7 @@ TypeId TypeChecker::errorRecoveryType(TypeId guess)
|
|||
|
||||
TypePackId TypeChecker::errorRecoveryTypePack(const ScopePtr& scope)
|
||||
{
|
||||
return builtinTypes->errorRecoveryTypePack();
|
||||
return builtinTypes->errorTypePack;
|
||||
}
|
||||
|
||||
TypePackId TypeChecker::errorRecoveryTypePack(TypePackId guess)
|
||||
|
@ -5449,7 +5449,7 @@ TypeIdPredicate TypeChecker::mkTruthyPredicate(bool sense, TypeId emptySetTy)
|
|||
|
||||
std::optional<TypeId> TypeChecker::filterMapImpl(TypeId type, TypeIdPredicate predicate)
|
||||
{
|
||||
std::vector<TypeId> types = Luau::filterMap(type, predicate);
|
||||
std::vector<TypeId> types = Luau::filterMap(type, std::move(predicate));
|
||||
if (!types.empty())
|
||||
return types.size() == 1 ? types[0] : addType(UnionType{std::move(types)});
|
||||
return std::nullopt;
|
||||
|
@ -5457,7 +5457,7 @@ std::optional<TypeId> TypeChecker::filterMapImpl(TypeId type, TypeIdPredicate pr
|
|||
|
||||
std::pair<std::optional<TypeId>, bool> TypeChecker::filterMap(TypeId type, TypeIdPredicate predicate)
|
||||
{
|
||||
TypeId ty = filterMapImpl(type, predicate).value_or(neverType);
|
||||
TypeId ty = filterMapImpl(type, std::move(predicate)).value_or(neverType);
|
||||
return {ty, !bool(get<NeverType>(ty))};
|
||||
}
|
||||
|
||||
|
@ -5556,9 +5556,9 @@ TypeId TypeChecker::resolveTypeWorker(const ScopePtr& scope, const AstType& anno
|
|||
typeName += lit->name.value;
|
||||
|
||||
if (scope->lookupPack(typeName))
|
||||
reportError(TypeError{annotation.location, SwappedGenericTypeParameter{typeName, SwappedGenericTypeParameter::Type}});
|
||||
reportError(TypeError{annotation.location, SwappedGenericTypeParameter{std::move(typeName), SwappedGenericTypeParameter::Type}});
|
||||
else
|
||||
reportError(TypeError{annotation.location, UnknownSymbol{typeName, UnknownSymbol::Type}});
|
||||
reportError(TypeError{annotation.location, UnknownSymbol{std::move(typeName), UnknownSymbol::Type}});
|
||||
|
||||
return errorRecoveryType(scope);
|
||||
}
|
||||
|
@ -5844,7 +5844,7 @@ TypeId TypeChecker::resolveTypeWorker(const ScopePtr& scope, const AstType& anno
|
|||
for (AstType* ann : un->types)
|
||||
types.push_back(resolveType(scope, *ann));
|
||||
|
||||
return addType(UnionType{types});
|
||||
return addType(UnionType{std::move(types)});
|
||||
}
|
||||
else if (const auto& un = annotation.as<AstTypeIntersection>())
|
||||
{
|
||||
|
@ -5854,7 +5854,7 @@ TypeId TypeChecker::resolveTypeWorker(const ScopePtr& scope, const AstType& anno
|
|||
for (AstType* ann : un->types)
|
||||
types.push_back(resolveType(scope, *ann));
|
||||
|
||||
return addType(IntersectionType{types});
|
||||
return addType(IntersectionType{std::move(types)});
|
||||
}
|
||||
else if (const auto& g = annotation.as<AstTypeGroup>())
|
||||
{
|
||||
|
@ -5890,7 +5890,7 @@ TypePackId TypeChecker::resolveTypePack(const ScopePtr& scope, const AstTypeList
|
|||
head.push_back(resolveType(scope, *ann));
|
||||
|
||||
std::optional<TypePackId> tail = types.tailType ? std::optional<TypePackId>(resolveTypePack(scope, *types.tailType)) : std::nullopt;
|
||||
return addTypePack(TypePack{head, tail});
|
||||
return addTypePack(TypePack{std::move(head), tail});
|
||||
}
|
||||
|
||||
return addTypePack(TypePack{});
|
||||
|
@ -5911,9 +5911,9 @@ TypePackId TypeChecker::resolveTypePack(const ScopePtr& scope, const AstTypePack
|
|||
if (!genericTy)
|
||||
{
|
||||
if (scope->lookupType(genericName))
|
||||
reportError(TypeError{generic->location, SwappedGenericTypeParameter{genericName, SwappedGenericTypeParameter::Pack}});
|
||||
reportError(TypeError{generic->location, SwappedGenericTypeParameter{std::move(genericName), SwappedGenericTypeParameter::Pack}});
|
||||
else
|
||||
reportError(TypeError{generic->location, UnknownSymbol{genericName, UnknownSymbol::Type}});
|
||||
reportError(TypeError{generic->location, UnknownSymbol{std::move(genericName), UnknownSymbol::Type}});
|
||||
|
||||
result = errorRecoveryTypePack(scope);
|
||||
}
|
||||
|
@ -6089,7 +6089,7 @@ GenericTypeDefinitions TypeChecker::createGenericTypes(
|
|||
scope->privateTypePackBindings[n] = cached;
|
||||
}
|
||||
|
||||
return {generics, genericPacks};
|
||||
return {std::move(generics), std::move(genericPacks)};
|
||||
}
|
||||
|
||||
void TypeChecker::refineLValue(const LValue& lvalue, RefinementMap& refis, const ScopePtr& scope, TypeIdPredicate predicate)
|
||||
|
@ -6117,7 +6117,7 @@ void TypeChecker::refineLValue(const LValue& lvalue, RefinementMap& refis, const
|
|||
// If we do not have a key, it means we're not trying to discriminate anything, so it's a simple matter of just filtering for a subset.
|
||||
if (!key)
|
||||
{
|
||||
auto [result, ok] = filterMap(*ty, predicate);
|
||||
auto [result, ok] = filterMap(*ty, std::move(predicate));
|
||||
addRefinement(refis, *target, *result);
|
||||
return;
|
||||
}
|
||||
|
@ -6416,7 +6416,7 @@ void TypeChecker::resolve(const TypeGuardPredicate& typeguardP, RefinementMap& r
|
|||
return std::nullopt;
|
||||
};
|
||||
|
||||
refineLValue(lvalue, refis, scope, predicate);
|
||||
refineLValue(lvalue, refis, scope, std::move(predicate));
|
||||
};
|
||||
|
||||
// Note: "vector" never happens here at this point, so we don't have to write something for it.
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <algorithm>
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAGVARIABLE(LuauErrorSuppressionTypeFunctionArgs)
|
||||
|
||||
namespace Luau
|
||||
|
@ -306,7 +306,7 @@ TypePack extendTypePack(
|
|||
TypePack newPack;
|
||||
newPack.tail = arena.freshTypePack(ftp->scope, ftp->polarity);
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
trackInteriorFreeTypePack(ftp->scope, *newPack.tail);
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
|
@ -343,7 +343,7 @@ TypePack extendTypePack(
|
|||
else if (auto etp = getMutable<ErrorTypePack>(pack))
|
||||
{
|
||||
while (result.head.size() < length)
|
||||
result.head.push_back(builtinTypes->errorRecoveryType());
|
||||
result.head.push_back(builtinTypes->errorType);
|
||||
|
||||
result.tail = pack;
|
||||
return result;
|
||||
|
@ -588,7 +588,7 @@ void trackInteriorFreeType(Scope* scope, TypeId ty)
|
|||
void trackInteriorFreeTypePack(Scope* scope, TypePackId tp)
|
||||
{
|
||||
LUAU_ASSERT(tp);
|
||||
if (!FFlag::LuauEagerGeneralization3)
|
||||
if (!FFlag::LuauEagerGeneralization4)
|
||||
return;
|
||||
|
||||
for (; scope; scope = scope->parent.get())
|
||||
|
|
|
@ -1078,33 +1078,33 @@ void Unifier::tryUnifyNormalizedTypes(
|
|||
return;
|
||||
|
||||
if (get<UnknownType>(subNorm.tops))
|
||||
return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()});
|
||||
return reportError(location, TypeMismatch{superTy, subTy, std::move(reason), std::move(error), mismatchContext()});
|
||||
|
||||
if (get<PrimitiveType>(subNorm.booleans))
|
||||
{
|
||||
if (!get<PrimitiveType>(superNorm.booleans))
|
||||
return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()});
|
||||
return reportError(location, TypeMismatch{superTy, subTy, std::move(reason), std::move(error), mismatchContext()});
|
||||
}
|
||||
else if (const SingletonType* stv = get<SingletonType>(subNorm.booleans))
|
||||
{
|
||||
if (!get<PrimitiveType>(superNorm.booleans) && stv != get<SingletonType>(superNorm.booleans))
|
||||
return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()});
|
||||
return reportError(location, TypeMismatch{superTy, subTy, std::move(reason), std::move(error), mismatchContext()});
|
||||
}
|
||||
|
||||
if (get<PrimitiveType>(subNorm.nils))
|
||||
if (!get<PrimitiveType>(superNorm.nils))
|
||||
return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()});
|
||||
return reportError(location, TypeMismatch{superTy, subTy, std::move(reason), std::move(error), mismatchContext()});
|
||||
|
||||
if (get<PrimitiveType>(subNorm.numbers))
|
||||
if (!get<PrimitiveType>(superNorm.numbers))
|
||||
return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()});
|
||||
return reportError(location, TypeMismatch{superTy, subTy, std::move(reason), std::move(error), mismatchContext()});
|
||||
|
||||
if (!isSubtype(subNorm.strings, superNorm.strings))
|
||||
return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()});
|
||||
return reportError(location, TypeMismatch{superTy, subTy, std::move(reason), std::move(error), mismatchContext()});
|
||||
|
||||
if (get<PrimitiveType>(subNorm.threads))
|
||||
if (!get<PrimitiveType>(superNorm.errors))
|
||||
return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()});
|
||||
return reportError(location, TypeMismatch{superTy, subTy, std::move(reason), std::move(error), mismatchContext()});
|
||||
|
||||
for (const auto& [subExternType, _] : subNorm.externTypes.externTypes)
|
||||
{
|
||||
|
@ -1140,7 +1140,7 @@ void Unifier::tryUnifyNormalizedTypes(
|
|||
|
||||
if (!found)
|
||||
{
|
||||
return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()});
|
||||
return reportError(location, TypeMismatch{superTy, subTy, std::move(reason), std::move(error), mismatchContext()});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1169,19 +1169,19 @@ void Unifier::tryUnifyNormalizedTypes(
|
|||
return reportError(*e);
|
||||
}
|
||||
if (!found)
|
||||
return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()});
|
||||
return reportError(location, TypeMismatch{superTy, subTy, std::move(reason), std::move(error), mismatchContext()});
|
||||
}
|
||||
|
||||
if (!subNorm.functions.isNever())
|
||||
{
|
||||
if (superNorm.functions.isNever())
|
||||
return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()});
|
||||
return reportError(location, TypeMismatch{superTy, subTy, std::move(reason), std::move(error), mismatchContext()});
|
||||
for (TypeId superFun : superNorm.functions.parts)
|
||||
{
|
||||
std::unique_ptr<Unifier> innerState = makeChildUnifier();
|
||||
const FunctionType* superFtv = get<FunctionType>(superFun);
|
||||
if (!superFtv)
|
||||
return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()});
|
||||
return reportError(location, TypeMismatch{superTy, subTy, std::move(reason), std::move(error), mismatchContext()});
|
||||
TypePackId tgt = innerState->tryApplyOverloadedFunction(subTy, subNorm.functions, superFtv->argTypes);
|
||||
innerState->tryUnify_(tgt, superFtv->retTypes);
|
||||
if (innerState->errors.empty())
|
||||
|
@ -1189,7 +1189,7 @@ void Unifier::tryUnifyNormalizedTypes(
|
|||
else if (auto e = hasUnificationTooComplex(innerState->errors))
|
||||
return reportError(*e);
|
||||
else
|
||||
return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()});
|
||||
return reportError(location, TypeMismatch{superTy, subTy, std::move(reason), std::move(error), mismatchContext()});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1210,7 +1210,7 @@ TypePackId Unifier::tryApplyOverloadedFunction(TypeId function, const Normalized
|
|||
if (overloads.isNever())
|
||||
{
|
||||
reportError(location, CannotCallNonFunction{function});
|
||||
return builtinTypes->errorRecoveryTypePack();
|
||||
return builtinTypes->errorTypePack;
|
||||
}
|
||||
|
||||
std::optional<TypePackId> result;
|
||||
|
@ -1266,7 +1266,7 @@ TypePackId Unifier::tryApplyOverloadedFunction(TypeId function, const Normalized
|
|||
else
|
||||
{
|
||||
reportError(location, CannotCallNonFunction{function});
|
||||
return builtinTypes->errorRecoveryTypePack();
|
||||
return builtinTypes->errorTypePack;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1677,13 +1677,13 @@ void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCal
|
|||
|
||||
while (superIter.good())
|
||||
{
|
||||
tryUnify_(*superIter, builtinTypes->errorRecoveryType());
|
||||
tryUnify_(*superIter, builtinTypes->errorType);
|
||||
superIter.advance();
|
||||
}
|
||||
|
||||
while (subIter.good())
|
||||
{
|
||||
tryUnify_(*subIter, builtinTypes->errorRecoveryType());
|
||||
tryUnify_(*subIter, builtinTypes->errorType);
|
||||
subIter.advance();
|
||||
}
|
||||
|
||||
|
@ -2256,9 +2256,9 @@ void Unifier::tryUnifyScalarShape(TypeId subTy, TypeId superTy, bool reversed)
|
|||
{
|
||||
std::string reason = "The former's metatable does not satisfy the requirements.";
|
||||
if (e)
|
||||
reportError(location, TypeMismatch{osuperTy, osubTy, reason, *e, mismatchContext()});
|
||||
reportError(location, TypeMismatch{osuperTy, osubTy, std::move(reason), std::move(e), mismatchContext()});
|
||||
else
|
||||
reportError(location, TypeMismatch{osuperTy, osubTy, reason, mismatchContext()});
|
||||
reportError(location, TypeMismatch{osuperTy, osubTy, std::move(reason), mismatchContext()});
|
||||
};
|
||||
|
||||
// Given t1 where t1 = { lower: (t1) -> (a, b...) }
|
||||
|
@ -2369,7 +2369,7 @@ void Unifier::tryUnifyWithMetatable(TypeId subTy, TypeId superTy, bool reversed)
|
|||
case TableState::Sealed:
|
||||
case TableState::Unsealed:
|
||||
case TableState::Generic:
|
||||
reportError(mismatchError);
|
||||
reportError(std::move(mismatchError));
|
||||
}
|
||||
}
|
||||
else if (log.getMutable<AnyType>(subTy) || log.getMutable<ErrorType>(subTy))
|
||||
|
@ -2377,7 +2377,7 @@ void Unifier::tryUnifyWithMetatable(TypeId subTy, TypeId superTy, bool reversed)
|
|||
}
|
||||
else
|
||||
{
|
||||
reportError(mismatchError);
|
||||
reportError(std::move(mismatchError));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2462,7 +2462,7 @@ void Unifier::tryUnifyWithExternType(TypeId subTy, TypeId superTy, bool reversed
|
|||
{
|
||||
ok = false;
|
||||
std::string msg = "Extern type " + superExternType->name + " does not have an indexer";
|
||||
reportError(location, GenericError{msg});
|
||||
reportError(location, GenericError{std::move(msg)});
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
|
@ -2670,7 +2670,7 @@ void Unifier::tryUnifyWithAny(TypePackId subTy, TypePackId anyTp)
|
|||
{
|
||||
LUAU_ASSERT(get<ErrorTypePack>(anyTp));
|
||||
|
||||
const TypeId anyTy = builtinTypes->errorRecoveryType();
|
||||
const TypeId anyTy = builtinTypes->errorType;
|
||||
|
||||
std::vector<TypeId> queue;
|
||||
|
||||
|
@ -2726,7 +2726,7 @@ bool Unifier::occursCheck(TypeId needle, TypeId haystack, bool reversed)
|
|||
if (innerState->failure)
|
||||
{
|
||||
reportError(location, OccursCheckFailed{});
|
||||
log.replace(needle, BoundType{builtinTypes->errorRecoveryType()});
|
||||
log.replace(needle, BoundType{builtinTypes->errorType});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2787,7 +2787,7 @@ bool Unifier::occursCheck(TypePackId needle, TypePackId haystack, bool reversed)
|
|||
if (occurs)
|
||||
{
|
||||
reportError(location, OccursCheckFailed{});
|
||||
log.replace(needle, BoundTypePack{builtinTypes->errorRecoveryTypePack()});
|
||||
log.replace(needle, BoundTypePack{builtinTypes->errorTypePack});
|
||||
}
|
||||
|
||||
return occurs;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauEnableWriteOnlyProperties)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -329,12 +329,12 @@ bool Unifier2::unify(TypeId subTy, const FunctionType* superFn)
|
|||
|
||||
for (TypePackId genericPack : subFn->genericPacks)
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
genericPack = follow(genericPack);
|
||||
|
||||
// TODO: Clip this follow() with LuauEagerGeneralization2
|
||||
// TODO: Clip this follow() with LuauEagerGeneralization4
|
||||
const GenericTypePack* gen = get<GenericTypePack>(follow(genericPack));
|
||||
if (gen)
|
||||
genericPackSubstitutions[genericPack] = freshTypePack(scope, gen->polarity);
|
||||
|
@ -465,7 +465,7 @@ bool Unifier2::unify(TableType* subTable, const TableType* superTable)
|
|||
{
|
||||
result &= unify(subTable->indexer->indexType, superTable->indexer->indexType);
|
||||
result &= unify(subTable->indexer->indexResultType, superTable->indexer->indexResultType);
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
// FIXME: We can probably do something more efficient here.
|
||||
result &= unify(superTable->indexer->indexType, subTable->indexer->indexType);
|
||||
|
|
|
@ -130,7 +130,8 @@ private:
|
|||
// function funcname funcbody
|
||||
LUAU_FORCEINLINE AstStat* parseFunctionStat(const AstArray<AstAttr*>& attributes = {nullptr, 0});
|
||||
|
||||
std::pair<bool, AstAttr::Type> validateAttribute(const char* attributeName, const TempVector<AstAttr*>& attributes);
|
||||
std::pair<bool, AstAttr::Type> validateAttribute_DEPRECATED(const char* attributeName, const TempVector<AstAttr*>& attributes);
|
||||
std::optional<AstAttr::Type> validateAttribute(const char* attributeName, const TempVector<AstAttr*>& attributes);
|
||||
|
||||
// attribute ::= '@' NAME
|
||||
void parseAttribute(TempVector<AstAttr*>& attribute);
|
||||
|
|
|
@ -24,6 +24,7 @@ LUAU_FASTFLAGVARIABLE(LuauParseStringIndexer)
|
|||
LUAU_FASTFLAGVARIABLE(LuauStoreReturnTypesAsPackOnAst)
|
||||
LUAU_FASTFLAGVARIABLE(LuauStoreLocalAnnotationColonPositions)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCSTForReturnTypeFunctionTail)
|
||||
LUAU_FASTFLAGVARIABLE(LuauParseAttributeFixUninit)
|
||||
LUAU_DYNAMIC_FASTFLAGVARIABLE(DebugLuauReportReturnTypeVariadicWithTypeSuffix, false)
|
||||
|
||||
// Clip with DebugLuauReportReturnTypeVariadicWithTypeSuffix
|
||||
|
@ -808,8 +809,10 @@ AstStat* Parser::parseFunctionStat(const AstArray<AstAttr*>& attributes)
|
|||
}
|
||||
|
||||
|
||||
std::pair<bool, AstAttr::Type> Parser::validateAttribute(const char* attributeName, const TempVector<AstAttr*>& attributes)
|
||||
std::pair<bool, AstAttr::Type> Parser::validateAttribute_DEPRECATED(const char* attributeName, const TempVector<AstAttr*>& attributes)
|
||||
{
|
||||
LUAU_ASSERT(!FFlag::LuauParseAttributeFixUninit);
|
||||
|
||||
AstAttr::Type type;
|
||||
|
||||
// check if the attribute name is valid
|
||||
|
@ -848,6 +851,42 @@ std::pair<bool, AstAttr::Type> Parser::validateAttribute(const char* attributeNa
|
|||
return {found, type};
|
||||
}
|
||||
|
||||
std::optional<AstAttr::Type> Parser::validateAttribute(const char* attributeName, const TempVector<AstAttr*>& attributes)
|
||||
{
|
||||
LUAU_ASSERT(FFlag::LuauParseAttributeFixUninit);
|
||||
|
||||
// check if the attribute name is valid
|
||||
std::optional<AstAttr::Type> type;
|
||||
|
||||
for (int i = 0; kAttributeEntries[i].name; ++i)
|
||||
{
|
||||
if (strcmp(attributeName, kAttributeEntries[i].name) == 0)
|
||||
{
|
||||
type = kAttributeEntries[i].type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!type)
|
||||
{
|
||||
if (strlen(attributeName) == 1)
|
||||
report(lexer.current().location, "Attribute name is missing");
|
||||
else
|
||||
report(lexer.current().location, "Invalid attribute '%s'", attributeName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check that attribute is not duplicated
|
||||
for (const AstAttr* attr : attributes)
|
||||
{
|
||||
if (attr->type == *type)
|
||||
report(lexer.current().location, "Cannot duplicate attribute '%s'", attributeName);
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
// attribute ::= '@' NAME
|
||||
void Parser::parseAttribute(TempVector<AstAttr*>& attributes)
|
||||
{
|
||||
|
@ -855,14 +894,27 @@ void Parser::parseAttribute(TempVector<AstAttr*>& attributes)
|
|||
|
||||
Location loc = lexer.current().location;
|
||||
|
||||
if (FFlag::LuauParseAttributeFixUninit)
|
||||
{
|
||||
const char* name = lexer.current().name;
|
||||
const auto [found, type] = validateAttribute(name, attributes);
|
||||
std::optional<AstAttr::Type> type = validateAttribute(name, attributes);
|
||||
|
||||
nextLexeme();
|
||||
|
||||
if (type)
|
||||
attributes.push_back(allocator.alloc<AstAttr>(loc, *type));
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* name = lexer.current().name;
|
||||
const auto [found, type] = validateAttribute_DEPRECATED(name, attributes);
|
||||
|
||||
nextLexeme();
|
||||
|
||||
if (found)
|
||||
attributes.push_back(allocator.alloc<AstAttr>(loc, type));
|
||||
}
|
||||
}
|
||||
|
||||
// attributes ::= {attribute}
|
||||
AstArray<AstAttr*> Parser::parseAttributes()
|
||||
|
|
|
@ -178,7 +178,7 @@ struct CliFileResolver : Luau::FileResolver
|
|||
Luau::Require::ErrorHandler nullErrorHandler{};
|
||||
|
||||
Luau::Require::Navigator navigator(navigationContext, nullErrorHandler);
|
||||
if (navigator.navigate(path) != Luau::Require::Navigator::Status::Success)
|
||||
if (navigator.navigate(std::move(path)) != Luau::Require::Navigator::Status::Success)
|
||||
return std::nullopt;
|
||||
|
||||
if (!navigationContext.isModulePresent())
|
||||
|
|
|
@ -66,7 +66,7 @@ int main(int argc, char** argv)
|
|||
options.captureComments = true;
|
||||
options.allowDeclarationSyntax = true;
|
||||
|
||||
Luau::ParseResult parseResult = Luau::Parser::parse(source.data(), source.size(), names, allocator, options);
|
||||
Luau::ParseResult parseResult = Luau::Parser::parse(source.data(), source.size(), names, allocator, std::move(options));
|
||||
|
||||
if (parseResult.errors.size() > 0)
|
||||
{
|
||||
|
|
|
@ -490,8 +490,8 @@ int main(int argc, char** argv)
|
|||
help(args);
|
||||
}
|
||||
|
||||
const std::string scriptName = argv[1];
|
||||
const std::string appName = argv[2];
|
||||
std::string scriptName = argv[1];
|
||||
std::string appName = argv[2];
|
||||
const std::string searchText = argv[3];
|
||||
|
||||
std::optional<std::string> source = readFile(scriptName);
|
||||
|
@ -503,5 +503,5 @@ int main(int argc, char** argv)
|
|||
}
|
||||
|
||||
Reducer reducer;
|
||||
reducer.run(scriptName, appName, *source, searchText);
|
||||
reducer.run(std::move(scriptName), std::move(appName), *source, searchText);
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ struct IrBuilder
|
|||
|
||||
IrOp constInt(int value);
|
||||
IrOp constUint(unsigned value);
|
||||
IrOp constImport(unsigned value);
|
||||
IrOp constDouble(double value);
|
||||
IrOp constTag(uint8_t value);
|
||||
IrOp constAny(IrConst constant, uint64_t asCommonKey);
|
||||
|
|
|
@ -392,11 +392,19 @@ enum class IrCmd : uint8_t
|
|||
// C: Rn or unsigned int (key)
|
||||
SET_TABLE,
|
||||
|
||||
// TODO: remove with FFlagLuauCodeGenSimplifyImport
|
||||
// Lookup a value in the environment
|
||||
// A: Rn (where to store the result)
|
||||
// B: unsigned int (import path)
|
||||
GET_IMPORT,
|
||||
|
||||
// Store an import from constant or the import path
|
||||
// A: Rn (where to store the result)
|
||||
// B: Kn
|
||||
// C: unsigned int (import path)
|
||||
// D: unsigned int (pcpos)
|
||||
GET_CACHED_IMPORT,
|
||||
|
||||
// Concatenate multiple TValues into a string
|
||||
// A: Rn (value start)
|
||||
// B: unsigned int (number of registers to go over)
|
||||
|
@ -763,6 +771,7 @@ enum class IrConstKind : uint8_t
|
|||
Uint,
|
||||
Double,
|
||||
Tag,
|
||||
Import,
|
||||
};
|
||||
|
||||
struct IrConst
|
||||
|
@ -1129,6 +1138,14 @@ struct IrFunction
|
|||
return value.valueUint;
|
||||
}
|
||||
|
||||
unsigned importOp(IrOp op)
|
||||
{
|
||||
IrConst& value = constOp(op);
|
||||
|
||||
CODEGEN_ASSERT(value.kind == IrConstKind::Import);
|
||||
return value.valueUint;
|
||||
}
|
||||
|
||||
std::optional<unsigned> asUintOp(IrOp op)
|
||||
{
|
||||
if (op.kind != IrOpKind::Constant)
|
||||
|
|
|
@ -32,7 +32,7 @@ void toString(IrToStringContext& ctx, const IrInst& inst, uint32_t index);
|
|||
void toString(IrToStringContext& ctx, const IrBlock& block, uint32_t index); // Block title
|
||||
void toString(IrToStringContext& ctx, IrOp op);
|
||||
|
||||
void toString(std::string& result, IrConst constant);
|
||||
void toString(std::string& result, Proto* proto, IrConst constant);
|
||||
|
||||
const char* getBytecodeTypeName(uint8_t type, const char* const* userdataTypes);
|
||||
|
||||
|
|
|
@ -68,6 +68,9 @@ static void visitVmRegDefsUses(T& visitor, IrFunction& function, const IrInst& i
|
|||
case IrCmd::GET_IMPORT:
|
||||
visitor.def(inst.a);
|
||||
break;
|
||||
case IrCmd::GET_CACHED_IMPORT:
|
||||
visitor.def(inst.a);
|
||||
break;
|
||||
case IrCmd::CONCAT:
|
||||
visitor.useRange(vmRegOp(inst.a), function.uintOp(inst.b));
|
||||
|
||||
|
|
|
@ -235,6 +235,14 @@ Udata* newUserdata(lua_State* L, size_t s, int tag)
|
|||
return u;
|
||||
}
|
||||
|
||||
void getImport(lua_State* L, StkId res, unsigned id, unsigned pc)
|
||||
{
|
||||
Closure* cl = clvalue(L->ci->func);
|
||||
L->ci->savedpc = cl->l.p->code + pc;
|
||||
|
||||
luaV_getimport(L, cl->env, cl->l.p->k, res, id, /*propagatenil*/ false);
|
||||
}
|
||||
|
||||
// Extracted as-is from lvmexecute.cpp with the exception of control flow (reentry) and removed interrupts/savedpc
|
||||
Closure* callFallback(lua_State* L, StkId ra, StkId argtop, int nresults)
|
||||
{
|
||||
|
|
|
@ -18,6 +18,7 @@ Closure* callProlog(lua_State* L, TValue* ra, StkId argtop, int nresults);
|
|||
void callEpilogC(lua_State* L, int nresults, int n);
|
||||
|
||||
Udata* newUserdata(lua_State* L, size_t s, int tag);
|
||||
void getImport(lua_State* L, StkId res, unsigned id, unsigned pc);
|
||||
|
||||
#define CALL_FALLBACK_YIELD 1
|
||||
|
||||
|
|
|
@ -676,6 +676,14 @@ IrOp IrBuilder::constUint(unsigned value)
|
|||
return constAny(constant, uint64_t(value));
|
||||
}
|
||||
|
||||
IrOp IrBuilder::constImport(unsigned value)
|
||||
{
|
||||
IrConst constant;
|
||||
constant.kind = IrConstKind::Import;
|
||||
constant.valueUint = value;
|
||||
return constAny(constant, uint64_t(value));
|
||||
}
|
||||
|
||||
IrOp IrBuilder::constDouble(double value)
|
||||
{
|
||||
IrConst constant;
|
||||
|
|
|
@ -251,6 +251,8 @@ const char* getCmdName(IrCmd cmd)
|
|||
return "SET_TABLE";
|
||||
case IrCmd::GET_IMPORT:
|
||||
return "GET_IMPORT";
|
||||
case IrCmd::GET_CACHED_IMPORT:
|
||||
return "GET_CACHED_IMPORT";
|
||||
case IrCmd::CONCAT:
|
||||
return "CONCAT";
|
||||
case IrCmd::GET_UPVALUE:
|
||||
|
@ -501,7 +503,7 @@ void toString(IrToStringContext& ctx, IrOp op)
|
|||
append(ctx.result, "undef");
|
||||
break;
|
||||
case IrOpKind::Constant:
|
||||
toString(ctx.result, ctx.constants[op.index]);
|
||||
toString(ctx.result, ctx.proto, ctx.constants[op.index]);
|
||||
break;
|
||||
case IrOpKind::Condition:
|
||||
CODEGEN_ASSERT(op.index < uint32_t(IrCondition::Count));
|
||||
|
@ -539,7 +541,7 @@ void toString(IrToStringContext& ctx, IrOp op)
|
|||
}
|
||||
}
|
||||
|
||||
void toString(std::string& result, IrConst constant)
|
||||
void toString(std::string& result, Proto* proto, IrConst constant)
|
||||
{
|
||||
switch (constant.kind)
|
||||
{
|
||||
|
@ -558,6 +560,36 @@ void toString(std::string& result, IrConst constant)
|
|||
case IrConstKind::Tag:
|
||||
result.append(getTagName(constant.valueTag));
|
||||
break;
|
||||
case IrConstKind::Import:
|
||||
append(result, "%uu", constant.valueUint);
|
||||
|
||||
if (proto)
|
||||
{
|
||||
append(result, " (");
|
||||
|
||||
int count = constant.valueUint >> 30;
|
||||
int id0 = count > 0 ? int(constant.valueUint >> 20) & 1023 : -1;
|
||||
int id1 = count > 1 ? int(constant.valueUint >> 10) & 1023 : -1;
|
||||
int id2 = count > 2 ? int(constant.valueUint) & 1023 : -1;
|
||||
|
||||
if (id0 != -1)
|
||||
appendVmConstant(result, proto, id0);
|
||||
|
||||
if (id1 != -1)
|
||||
{
|
||||
append(result, ".");
|
||||
appendVmConstant(result, proto, id1);
|
||||
}
|
||||
|
||||
if (id2 != -1)
|
||||
{
|
||||
append(result, ".");
|
||||
appendVmConstant(result, proto, id2);
|
||||
}
|
||||
|
||||
append(result, ")");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1382,6 +1382,47 @@ void IrLoweringA64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
|
|||
|
||||
emitUpdateBase(build);
|
||||
break;
|
||||
case IrCmd::GET_CACHED_IMPORT:
|
||||
{
|
||||
Label skip, exit;
|
||||
RegisterA64 tempTag = regs.allocTemp(KindA64::w);
|
||||
|
||||
AddressA64 addrConstTag = tempAddr(inst.b, offsetof(TValue, tt));
|
||||
build.ldr(tempTag, addrConstTag);
|
||||
|
||||
// If the constant for the import is set, we will use it directly, otherwise we have to call an import path lookup function
|
||||
CODEGEN_ASSERT(LUA_TNIL == 0);
|
||||
build.cbnz(tempTag, skip);
|
||||
|
||||
{
|
||||
size_t spills = regs.spill(build, index);
|
||||
|
||||
build.mov(x0, rState);
|
||||
build.add(x1, rBase, uint16_t(vmRegOp(inst.a) * sizeof(TValue)));
|
||||
build.mov(w2, importOp(inst.c));
|
||||
build.mov(w3, uintOp(inst.d));
|
||||
build.ldr(x4, mem(rNativeContext, offsetof(NativeContext, getImport)));
|
||||
build.blr(x4);
|
||||
|
||||
regs.restore(build, spills); // Need to restore before skip so that registers are in a consistent state
|
||||
|
||||
emitUpdateBase(build);
|
||||
build.b(exit);
|
||||
}
|
||||
|
||||
RegisterA64 tempTv = regs.allocTemp(KindA64::q);
|
||||
|
||||
build.setLabel(skip);
|
||||
|
||||
AddressA64 addrConst = tempAddr(inst.b, 0);
|
||||
build.ldr(tempTv, addrConst);
|
||||
|
||||
AddressA64 addrReg = tempAddr(inst.a, 0);
|
||||
build.str(tempTv, addrReg);
|
||||
|
||||
build.setLabel(exit);
|
||||
break;
|
||||
}
|
||||
case IrCmd::CONCAT:
|
||||
regs.spill(build, index);
|
||||
build.mov(x0, rState);
|
||||
|
@ -2720,6 +2761,11 @@ unsigned IrLoweringA64::uintOp(IrOp op) const
|
|||
return function.uintOp(op);
|
||||
}
|
||||
|
||||
unsigned IrLoweringA64::importOp(IrOp op) const
|
||||
{
|
||||
return function.importOp(op);
|
||||
}
|
||||
|
||||
double IrLoweringA64::doubleOp(IrOp op) const
|
||||
{
|
||||
return function.doubleOp(op);
|
||||
|
|
|
@ -54,6 +54,7 @@ struct IrLoweringA64
|
|||
uint8_t tagOp(IrOp op) const;
|
||||
int intOp(IrOp op) const;
|
||||
unsigned uintOp(IrOp op) const;
|
||||
unsigned importOp(IrOp op) const;
|
||||
double doubleOp(IrOp op) const;
|
||||
|
||||
IrBlock& blockOp(IrOp op) const;
|
||||
|
|
|
@ -1219,6 +1219,36 @@ void IrLoweringX64::lowerInst(IrInst& inst, uint32_t index, const IrBlock& next)
|
|||
emitUpdateBase(build);
|
||||
break;
|
||||
}
|
||||
case IrCmd::GET_CACHED_IMPORT:
|
||||
{
|
||||
Label skip, exit;
|
||||
|
||||
// If the constant for the import is set, we will use it directly, otherwise we have to call an import path lookup function
|
||||
build.cmp(luauConstantTag(vmConstOp(inst.b)), LUA_TNIL);
|
||||
build.jcc(ConditionX64::NotEqual, skip);
|
||||
|
||||
{
|
||||
ScopedSpills spillGuard(regs);
|
||||
|
||||
IrCallWrapperX64 callWrap(regs, build, index);
|
||||
callWrap.addArgument(SizeX64::qword, rState);
|
||||
callWrap.addArgument(SizeX64::qword, luauRegAddress(vmRegOp(inst.a)));
|
||||
callWrap.addArgument(SizeX64::dword, importOp(inst.c));
|
||||
callWrap.addArgument(SizeX64::dword, uintOp(inst.d));
|
||||
callWrap.call(qword[rNativeContext + offsetof(NativeContext, getImport)]);
|
||||
}
|
||||
|
||||
emitUpdateBase(build);
|
||||
build.jmp(exit);
|
||||
|
||||
ScopedRegX64 tmp1{regs, SizeX64::xmmword};
|
||||
|
||||
build.setLabel(skip);
|
||||
build.vmovups(tmp1.reg, luauConstant(vmConstOp(inst.b)));
|
||||
build.vmovups(luauReg(vmRegOp(inst.a)), tmp1.reg);
|
||||
build.setLabel(exit);
|
||||
break;
|
||||
}
|
||||
case IrCmd::CONCAT:
|
||||
{
|
||||
IrCallWrapperX64 callWrap(regs, build, index);
|
||||
|
@ -2350,6 +2380,11 @@ unsigned IrLoweringX64::uintOp(IrOp op) const
|
|||
return function.uintOp(op);
|
||||
}
|
||||
|
||||
unsigned IrLoweringX64::importOp(IrOp op) const
|
||||
{
|
||||
return function.importOp(op);
|
||||
}
|
||||
|
||||
double IrLoweringX64::doubleOp(IrOp op) const
|
||||
{
|
||||
return function.doubleOp(op);
|
||||
|
|
|
@ -57,6 +57,7 @@ struct IrLoweringX64
|
|||
uint8_t tagOp(IrOp op) const;
|
||||
int intOp(IrOp op) const;
|
||||
unsigned uintOp(IrOp op) const;
|
||||
unsigned importOp(IrOp op) const;
|
||||
double doubleOp(IrOp op) const;
|
||||
|
||||
IrBlock& blockOp(IrOp op) const;
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include "lstate.h"
|
||||
#include "ltm.h"
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauCodeGenSimplifyImport)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
|
@ -1215,6 +1217,13 @@ void translateInstGetImport(IrBuilder& build, const Instruction* pc, int pcpos)
|
|||
int k = LUAU_INSN_D(*pc);
|
||||
uint32_t aux = pc[1];
|
||||
|
||||
if (FFlag::LuauCodeGenSimplifyImport)
|
||||
{
|
||||
build.inst(IrCmd::CHECK_SAFE_ENV, build.vmExit(pcpos));
|
||||
build.inst(IrCmd::GET_CACHED_IMPORT, build.vmReg(ra), build.vmConst(k), build.constImport(aux), build.constUint(pcpos + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
IrOp fastPath = build.block(IrBlockKind::Internal);
|
||||
IrOp fallback = build.block(IrBlockKind::Fallback);
|
||||
|
||||
|
@ -1237,6 +1246,7 @@ void translateInstGetImport(IrBuilder& build, const Instruction* pc, int pcpos)
|
|||
build.inst(IrCmd::GET_IMPORT, build.vmReg(ra), build.constUint(aux));
|
||||
build.inst(IrCmd::JUMP, next);
|
||||
}
|
||||
}
|
||||
|
||||
void translateInstGetTableKS(IrBuilder& build, const Instruction* pc, int pcpos)
|
||||
{
|
||||
|
|
|
@ -240,6 +240,7 @@ IrValueKind getCmdValueKind(IrCmd cmd)
|
|||
case IrCmd::GET_TABLE:
|
||||
case IrCmd::SET_TABLE:
|
||||
case IrCmd::GET_IMPORT:
|
||||
case IrCmd::GET_CACHED_IMPORT:
|
||||
case IrCmd::CONCAT:
|
||||
case IrCmd::GET_UPVALUE:
|
||||
case IrCmd::SET_UPVALUE:
|
||||
|
|
|
@ -55,6 +55,7 @@ void IrValueLocationTracking::beforeInstLowering(IrInst& inst)
|
|||
case IrCmd::DO_LEN:
|
||||
case IrCmd::GET_TABLE:
|
||||
case IrCmd::GET_IMPORT:
|
||||
case IrCmd::GET_CACHED_IMPORT:
|
||||
invalidateRestoreOp(inst.a, /*skipValueInvalidation*/ false);
|
||||
break;
|
||||
case IrCmd::CONCAT:
|
||||
|
|
|
@ -90,6 +90,7 @@ void initFunctions(NativeContext& context)
|
|||
context.callProlog = callProlog;
|
||||
context.callEpilogC = callEpilogC;
|
||||
context.newUserdata = newUserdata;
|
||||
context.getImport = getImport;
|
||||
|
||||
context.callFallback = callFallback;
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ struct NativeContext
|
|||
Closure* (*callProlog)(lua_State* L, TValue* ra, StkId argtop, int nresults) = nullptr;
|
||||
void (*callEpilogC)(lua_State* L, int nresults, int n) = nullptr;
|
||||
Udata* (*newUserdata)(lua_State* L, size_t s, int tag) = nullptr;
|
||||
void (*getImport)(lua_State* L, StkId res, unsigned id, unsigned pc) = nullptr;
|
||||
|
||||
Closure* (*callFallback)(lua_State* L, StkId ra, StkId argtop, int nresults) = nullptr;
|
||||
|
||||
|
|
|
@ -1539,6 +1539,13 @@ static void constPropInInst(ConstPropState& state, IrBuilder& build, IrFunction&
|
|||
state.invalidate(inst.a);
|
||||
state.invalidateUserCall();
|
||||
break;
|
||||
case IrCmd::GET_CACHED_IMPORT:
|
||||
state.invalidate(inst.a);
|
||||
|
||||
// Outside of safe environment, environment traversal for an import can execute custom code
|
||||
if (!state.inSafeEnv)
|
||||
state.invalidateUserCall();
|
||||
break;
|
||||
case IrCmd::CONCAT:
|
||||
state.invalidateRegisterRange(vmRegOp(inst.a), function.uintOp(inst.b));
|
||||
state.invalidateUserCall(); // TODO: if only strings and numbers are concatenated, there will be no user calls
|
||||
|
|
|
@ -767,6 +767,7 @@ static void markDeadStoresInInst(RemoveDeadStoreState& state, IrBuilder& build,
|
|||
case IrCmd::GET_TABLE:
|
||||
case IrCmd::SET_TABLE:
|
||||
case IrCmd::GET_IMPORT:
|
||||
case IrCmd::GET_CACHED_IMPORT:
|
||||
case IrCmd::CONCAT:
|
||||
case IrCmd::INTERRUPT:
|
||||
case IrCmd::CHECK_GC:
|
||||
|
|
|
@ -39,10 +39,26 @@ message Local {
|
|||
required int32 name = 1;
|
||||
}
|
||||
|
||||
message Typename {
|
||||
message RegularTypeName {
|
||||
required int32 index = 1;
|
||||
}
|
||||
|
||||
message GenericTypeName {
|
||||
required int32 index = 1;
|
||||
}
|
||||
|
||||
message BuiltinTypeName {
|
||||
required int32 index = 1;
|
||||
}
|
||||
|
||||
message TypeName {
|
||||
oneof expr_oneof {
|
||||
RegularTypeName regular = 1;
|
||||
GenericTypeName generic = 2;
|
||||
BuiltinTypeName builtin = 3;
|
||||
}
|
||||
}
|
||||
|
||||
message Name {
|
||||
oneof name_oneof {
|
||||
int32 builtin = 1;
|
||||
|
@ -97,8 +113,8 @@ message ExprIndexExpr {
|
|||
}
|
||||
|
||||
message ExprFunction {
|
||||
repeated Typename generics = 1;
|
||||
repeated Typename genericpacks = 2;
|
||||
repeated GenericTypeName generics = 1;
|
||||
repeated GenericTypeName genericpacks = 2;
|
||||
repeated Local args = 3;
|
||||
required bool vararg = 4;
|
||||
required StatBlock body = 5;
|
||||
|
@ -195,6 +211,7 @@ message Stat {
|
|||
StatLocalFunction local_function = 15;
|
||||
StatTypeAlias type_alias = 16;
|
||||
StatRequireIntoLocalHelper require_into_local = 17;
|
||||
StatTypeFunction type_function = 18;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,10 +306,16 @@ message StatLocalFunction {
|
|||
|
||||
message StatTypeAlias {
|
||||
required bool export = 1;
|
||||
required Typename name = 2;
|
||||
required RegularTypeName name = 2;
|
||||
required Type type = 3;
|
||||
repeated Typename generics = 4;
|
||||
repeated Typename genericpacks = 5;
|
||||
repeated GenericTypeName generics = 4;
|
||||
repeated GenericTypeName genericpacks = 5;
|
||||
}
|
||||
|
||||
message StatTypeFunction {
|
||||
required bool export = 1;
|
||||
required RegularTypeName name = 2;
|
||||
required ExprFunction func = 3;
|
||||
}
|
||||
|
||||
message StatRequireIntoLocalHelper {
|
||||
|
@ -309,7 +332,7 @@ message Type {
|
|||
TypeTypeof typeof = 5;
|
||||
TypeUnion union = 6;
|
||||
TypeIntersection intersection = 7;
|
||||
TypeClass class = 8;
|
||||
TypeExtern extern = 8;
|
||||
TypeRef ref = 9;
|
||||
TypeBoolean boolean = 10;
|
||||
TypeString string = 11;
|
||||
|
@ -321,19 +344,26 @@ message TypePrimitive {
|
|||
}
|
||||
|
||||
message TypeLiteral {
|
||||
required Typename name = 1;
|
||||
required TypeName name = 1;
|
||||
repeated Type generics = 2;
|
||||
repeated Typename genericpacks = 3;
|
||||
repeated GenericTypeName genericpacks = 3;
|
||||
}
|
||||
|
||||
enum TableFieldAccess {
|
||||
Read = 1;
|
||||
Write = 2;
|
||||
}
|
||||
|
||||
message TypeTableItem {
|
||||
required Name key = 1;
|
||||
required Type type = 2;
|
||||
optional TableFieldAccess access = 1;
|
||||
required Name key = 2;
|
||||
required Type type = 3;
|
||||
}
|
||||
|
||||
message TypeTableIndexer {
|
||||
required Type key = 1;
|
||||
required Type value = 2;
|
||||
optional TableFieldAccess access = 1;
|
||||
required Type key = 2;
|
||||
required Type value = 3;
|
||||
}
|
||||
|
||||
message TypeTable {
|
||||
|
@ -342,8 +372,8 @@ message TypeTable {
|
|||
}
|
||||
|
||||
message TypeFunction {
|
||||
repeated Typename generics = 1;
|
||||
repeated Typename genericpacks = 2;
|
||||
repeated GenericTypeName generics = 1;
|
||||
repeated GenericTypeName genericpacks = 2;
|
||||
repeated Type args = 3;
|
||||
repeated Type rets = 4;
|
||||
// TODO: vararg?
|
||||
|
@ -363,13 +393,13 @@ message TypeIntersection {
|
|||
required Type right = 2;
|
||||
}
|
||||
|
||||
message TypeClass {
|
||||
message TypeExtern {
|
||||
required int32 kind = 1;
|
||||
}
|
||||
|
||||
message TypeRef {
|
||||
required Local prefix = 1;
|
||||
required Typename index = 2;
|
||||
required TypeName index = 2;
|
||||
}
|
||||
|
||||
message TypeBoolean {
|
||||
|
|
|
@ -22,7 +22,8 @@ static const std::string kNames[] = {
|
|||
"sub", "table", "tan", "tanh", "thread", "time", "tonumber", "tostring", "tostring",
|
||||
"traceback", "type", "typeof", "unpack", "upper", "userdata", "utf8", "vector", "wrap",
|
||||
"writef32", "writef64", "writei16", "writei32", "writei8", "writestring", "writeu16", "writeu32", "writeu8",
|
||||
"xpcall", "yield",
|
||||
"xpcall", "yield", "types", "unknown", "never", "any", "singleton", "optional", "generic",
|
||||
"negationof", "unionof", "intersectionof", "newtable", "newfunction",
|
||||
};
|
||||
|
||||
static const std::string kTypes[] = {
|
||||
|
@ -34,6 +35,8 @@ static const std::string kTypes[] = {
|
|||
"string",
|
||||
"thread",
|
||||
"vector",
|
||||
"unknown",
|
||||
"never",
|
||||
};
|
||||
|
||||
static const std::string kExternTypes[] = {
|
||||
|
@ -42,6 +45,28 @@ static const std::string kExternTypes[] = {
|
|||
"Part",
|
||||
};
|
||||
|
||||
static const std::string kBuiltinTypes[] = {
|
||||
"len",
|
||||
"unm",
|
||||
"add",
|
||||
"sub",
|
||||
"mul",
|
||||
"div",
|
||||
"idiv",
|
||||
"pow",
|
||||
"mod",
|
||||
"concat",
|
||||
"lt",
|
||||
"le",
|
||||
"eq",
|
||||
"keyof",
|
||||
"rawkeyof",
|
||||
"index",
|
||||
"rawget",
|
||||
"setmetatable",
|
||||
"getmetatable",
|
||||
};
|
||||
|
||||
struct ProtoToLuau
|
||||
{
|
||||
struct Function
|
||||
|
@ -79,12 +104,35 @@ struct ProtoToLuau
|
|||
}
|
||||
}
|
||||
|
||||
void ident(const luau::Typename& name)
|
||||
void ident(const luau::RegularTypeName& name)
|
||||
{
|
||||
source += 't';
|
||||
source += std::to_string(name.index() & 0xff);
|
||||
}
|
||||
|
||||
void ident(const luau::GenericTypeName& name)
|
||||
{
|
||||
source += char('A' + (name.index() % 26));
|
||||
}
|
||||
|
||||
void ident(const luau::BuiltinTypeName& name)
|
||||
{
|
||||
size_t index = size_t(name.index()) % std::size(kBuiltinTypes);
|
||||
source += kBuiltinTypes[index];
|
||||
}
|
||||
|
||||
void ident(const luau::TypeName& name)
|
||||
{
|
||||
if (name.has_regular())
|
||||
ident(name.regular());
|
||||
else if (name.has_generic())
|
||||
ident(name.generic());
|
||||
else if (name.has_builtin())
|
||||
ident(name.builtin());
|
||||
else
|
||||
source += "any";
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void genericidents(const T& node)
|
||||
{
|
||||
|
@ -480,6 +528,8 @@ struct ProtoToLuau
|
|||
print(stat.type_alias());
|
||||
else if (stat.has_require_into_local())
|
||||
print(stat.require_into_local());
|
||||
else if (stat.has_type_function())
|
||||
print(stat.type_function());
|
||||
else
|
||||
source += "do end\n";
|
||||
}
|
||||
|
@ -768,6 +818,17 @@ struct ProtoToLuau
|
|||
source += " = require(module" + std::to_string(stat.modulenum() % 2) + ")\n";
|
||||
}
|
||||
|
||||
void print(const luau::StatTypeFunction& stat)
|
||||
{
|
||||
if (stat.export_())
|
||||
source += "export ";
|
||||
|
||||
source += "type function ";
|
||||
ident(stat.name());
|
||||
function(stat.func());
|
||||
source += '\n';
|
||||
}
|
||||
|
||||
void print(const luau::Type& type)
|
||||
{
|
||||
if (type.has_primitive())
|
||||
|
@ -784,8 +845,8 @@ struct ProtoToLuau
|
|||
print(type.union_());
|
||||
else if (type.has_intersection())
|
||||
print(type.intersection());
|
||||
else if (type.has_class_())
|
||||
print(type.class_());
|
||||
else if (type.has_extern_())
|
||||
print(type.extern_());
|
||||
else if (type.has_ref())
|
||||
print(type.ref());
|
||||
else if (type.has_boolean())
|
||||
|
@ -832,22 +893,46 @@ struct ProtoToLuau
|
|||
}
|
||||
}
|
||||
|
||||
void print(const luau::TableFieldAccess& expr)
|
||||
{
|
||||
if (expr == luau::TableFieldAccess::Read)
|
||||
source += "read";
|
||||
else if (expr == luau::TableFieldAccess::Write)
|
||||
source += "write";
|
||||
}
|
||||
|
||||
void print(const luau::TypeTable& type)
|
||||
{
|
||||
source += '{';
|
||||
for (size_t i = 0; i < type.items_size(); ++i)
|
||||
{
|
||||
ident(type.items(i).key());
|
||||
auto& item = type.items(i);
|
||||
|
||||
if (item.has_access())
|
||||
{
|
||||
print(item.access());
|
||||
source += ' ';
|
||||
}
|
||||
|
||||
ident(item.key());
|
||||
source += ':';
|
||||
print(type.items(i).type());
|
||||
print(item.type());
|
||||
source += ',';
|
||||
}
|
||||
if (type.has_indexer())
|
||||
{
|
||||
auto& indexer = type.indexer();
|
||||
|
||||
if (indexer.has_access())
|
||||
{
|
||||
print(indexer.access());
|
||||
source += ' ';
|
||||
}
|
||||
|
||||
source += '[';
|
||||
print(type.indexer().key());
|
||||
print(indexer.key());
|
||||
source += "]:";
|
||||
print(type.indexer().value());
|
||||
print(indexer.value());
|
||||
}
|
||||
source += '}';
|
||||
}
|
||||
|
@ -900,7 +985,7 @@ struct ProtoToLuau
|
|||
source += ')';
|
||||
}
|
||||
|
||||
void print(const luau::TypeClass& type)
|
||||
void print(const luau::TypeExtern& type)
|
||||
{
|
||||
size_t index = size_t(type.kind()) % std::size(kExternTypes);
|
||||
source += kExternTypes[index];
|
||||
|
|
|
@ -19,8 +19,9 @@
|
|||
LUAU_FASTFLAG(LuauTraceTypesInNonstrictMode2)
|
||||
LUAU_FASTFLAG(LuauSetMetatableDoesNotTimeTravel)
|
||||
LUAU_FASTINT(LuauTypeInferRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauExpectedTypeVisitor)
|
||||
LUAU_FASTFLAG(LuauImplicitTableIndexerKeys)
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -45,9 +46,9 @@ struct ACFixtureImpl : BaseType
|
|||
// NOTE: Autocomplete does *not* require strict checking, meaning we should
|
||||
// try to check all of these examples in `--!nocheck` mode.
|
||||
this->configResolver.defaultConfig.mode = Mode::NoCheck;
|
||||
this->frontend.check("MainModule", opts);
|
||||
this->getFrontend().check("MainModule", opts);
|
||||
|
||||
return Luau::autocomplete(this->frontend, "MainModule", Position{row, column}, nullCallback);
|
||||
return Luau::autocomplete(this->getFrontend(), "MainModule", Position{row, column}, nullCallback);
|
||||
}
|
||||
|
||||
AutocompleteResult autocomplete(char marker, StringCompletionCallback callback = nullCallback)
|
||||
|
@ -58,9 +59,9 @@ struct ACFixtureImpl : BaseType
|
|||
// NOTE: Autocomplete does *not* require strict checking, meaning we should
|
||||
// try to check all of these examples in `--!nocheck` mode.
|
||||
this->configResolver.defaultConfig.mode = Mode::NoCheck;
|
||||
this->frontend.check("MainModule", opts);
|
||||
this->getFrontend().check("MainModule", opts);
|
||||
|
||||
return Luau::autocomplete(this->frontend, "MainModule", getPosition(marker), callback);
|
||||
return Luau::autocomplete(this->getFrontend(), "MainModule", getPosition(marker), callback);
|
||||
}
|
||||
|
||||
AutocompleteResult autocomplete(const ModuleName& name, Position pos, StringCompletionCallback callback = nullCallback)
|
||||
|
@ -71,9 +72,9 @@ struct ACFixtureImpl : BaseType
|
|||
// NOTE: Autocomplete does *not* require strict checking, meaning we should
|
||||
// try to check all of these examples in `--!nocheck` mode.
|
||||
this->configResolver.defaultConfig.mode = Mode::NoCheck;
|
||||
this->frontend.check(name, opts);
|
||||
this->getFrontend().check(name, opts);
|
||||
|
||||
return Luau::autocomplete(this->frontend, name, pos, callback);
|
||||
return Luau::autocomplete(this->getFrontend(), name, pos, callback);
|
||||
}
|
||||
|
||||
CheckResult check(const std::string& source)
|
||||
|
@ -120,18 +121,18 @@ struct ACFixtureImpl : BaseType
|
|||
|
||||
LoadDefinitionFileResult loadDefinition(const std::string& source)
|
||||
{
|
||||
GlobalTypes& globals = this->frontend.globalsForAutocomplete;
|
||||
GlobalTypes& globals = this->getFrontend().globalsForAutocomplete;
|
||||
unfreeze(globals.globalTypes);
|
||||
LoadDefinitionFileResult result = this->frontend.loadDefinitionFile(
|
||||
LoadDefinitionFileResult result = this->getFrontend().loadDefinitionFile(
|
||||
globals, globals.globalScope, source, "@test", /* captureComments */ false, /* typeCheckForAutocomplete */ true
|
||||
);
|
||||
freeze(globals.globalTypes);
|
||||
|
||||
if (FFlag::LuauSolverV2)
|
||||
{
|
||||
GlobalTypes& globals = this->frontend.globals;
|
||||
GlobalTypes& globals = this->getFrontend().globals;
|
||||
unfreeze(globals.globalTypes);
|
||||
LoadDefinitionFileResult result = this->frontend.loadDefinitionFile(
|
||||
LoadDefinitionFileResult result = this->getFrontend().loadDefinitionFile(
|
||||
globals, globals.globalScope, source, "@test", /* captureComments */ false, /* typeCheckForAutocomplete */ true
|
||||
);
|
||||
freeze(globals.globalTypes);
|
||||
|
@ -156,10 +157,11 @@ struct ACFixture : ACFixtureImpl<Fixture>
|
|||
ACFixture()
|
||||
: ACFixtureImpl<Fixture>()
|
||||
{
|
||||
addGlobalBinding(frontend.globals, "table", Binding{builtinTypes->anyType});
|
||||
addGlobalBinding(frontend.globals, "math", Binding{builtinTypes->anyType});
|
||||
addGlobalBinding(frontend.globalsForAutocomplete, "table", Binding{builtinTypes->anyType});
|
||||
addGlobalBinding(frontend.globalsForAutocomplete, "math", Binding{builtinTypes->anyType});
|
||||
// TODO - move this into its own consructor
|
||||
addGlobalBinding(getFrontend().globals, "table", Binding{getBuiltins()->anyType});
|
||||
addGlobalBinding(getFrontend().globals, "math", Binding{getBuiltins()->anyType});
|
||||
addGlobalBinding(getFrontend().globalsForAutocomplete, "table", Binding{getBuiltins()->anyType});
|
||||
addGlobalBinding(getFrontend().globalsForAutocomplete, "math", Binding{getBuiltins()->anyType});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1388,14 +1390,14 @@ export type B = { z: number, w: number }
|
|||
return {}
|
||||
)";
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(frontend.check("Module/A"));
|
||||
LUAU_REQUIRE_NO_ERRORS(getFrontend().check("Module/A"));
|
||||
|
||||
fileResolver.source["Module/B"] = R"(
|
||||
local aaa = require(script.Parent.A)
|
||||
local a: aa
|
||||
)";
|
||||
|
||||
frontend.check("Module/B");
|
||||
getFrontend().check("Module/B");
|
||||
|
||||
auto ac = autocomplete("Module/B", Position{2, 11});
|
||||
|
||||
|
@ -1411,14 +1413,14 @@ export type B = { z: number, w: number }
|
|||
return {}
|
||||
)";
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(frontend.check("Module/A"));
|
||||
LUAU_REQUIRE_NO_ERRORS(getFrontend().check("Module/A"));
|
||||
|
||||
fileResolver.source["Module/B"] = R"(
|
||||
local aaa = require(script.Parent.A)
|
||||
local a: aaa.
|
||||
)";
|
||||
|
||||
frontend.check("Module/B");
|
||||
getFrontend().check("Module/B");
|
||||
|
||||
auto ac = autocomplete("Module/B", Position{2, 13});
|
||||
|
||||
|
@ -2071,14 +2073,14 @@ local function b(a: ((done) -> number) -> number) return a(function(done) return
|
|||
return {a = a, b = b}
|
||||
)";
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(frontend.check("Module/A"));
|
||||
LUAU_REQUIRE_NO_ERRORS(getFrontend().check("Module/A"));
|
||||
|
||||
fileResolver.source["Module/B"] = R"(
|
||||
local ex = require(script.Parent.A)
|
||||
ex.a(function(x:
|
||||
)";
|
||||
|
||||
frontend.check("Module/B");
|
||||
getFrontend().check("Module/B");
|
||||
|
||||
auto ac = autocomplete("Module/B", Position{2, 16});
|
||||
|
||||
|
@ -2089,7 +2091,7 @@ local ex = require(script.Parent.A)
|
|||
ex.b(function(x:
|
||||
)";
|
||||
|
||||
frontend.check("Module/C");
|
||||
getFrontend().check("Module/C");
|
||||
|
||||
ac = autocomplete("Module/C", Position{2, 16});
|
||||
|
||||
|
@ -2105,14 +2107,14 @@ local function b(a: ((done) -> number) -> number) return a(function(done) return
|
|||
return {a = a, b = b}
|
||||
)";
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(frontend.check("Module/A"));
|
||||
LUAU_REQUIRE_NO_ERRORS(getFrontend().check("Module/A"));
|
||||
|
||||
fileResolver.source["Module/B"] = R"(
|
||||
local ex = require(script.Parent.A)
|
||||
ex.a(function(x:
|
||||
)";
|
||||
|
||||
frontend.check("Module/B");
|
||||
getFrontend().check("Module/B");
|
||||
|
||||
auto ac = autocomplete("Module/B", Position{2, 16});
|
||||
|
||||
|
@ -2125,7 +2127,7 @@ local ex = require(script.Parent.A)
|
|||
ex.b(function(x:
|
||||
)";
|
||||
|
||||
frontend.check("Module/C");
|
||||
getFrontend().check("Module/C");
|
||||
|
||||
ac = autocomplete("Module/C", Position{2, 16});
|
||||
|
||||
|
@ -2441,14 +2443,14 @@ export type other = { z: number, w: number }
|
|||
return {}
|
||||
)";
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(frontend.check("Module/A"));
|
||||
LUAU_REQUIRE_NO_ERRORS(getFrontend().check("Module/A"));
|
||||
|
||||
fileResolver.source["Module/B"] = R"(
|
||||
local aaa = require(script.Parent.A)
|
||||
local a: aaa.do
|
||||
)";
|
||||
|
||||
frontend.check("Module/B");
|
||||
getFrontend().check("Module/B");
|
||||
|
||||
auto ac = autocomplete("Module/B", Position{2, 15});
|
||||
|
||||
|
@ -3089,12 +3091,29 @@ TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocomplete_on_string_singletons")
|
|||
CHECK(ac.entryMap.count("format"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ACFixture, "autocomplete_string_singletons")
|
||||
TEST_CASE_FIXTURE(ACFixture, "autocomplete_string_singletons_in_literal")
|
||||
{
|
||||
if (FFlag::LuauSolverV2) // CLI-116814 Autocomplete needs to populate expected types for function arguments correctly
|
||||
// (overloads and singletons)
|
||||
if (FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
// CLI-116814: Under the new solver, we fail to properly apply the expected
|
||||
// type to `tag` as we fail to recognize that we can "break apart" unions
|
||||
// when trying to apply an expected type.
|
||||
|
||||
check(R"(
|
||||
type tagged = {tag:"cat", fieldx:number} | {tag:"dog", fieldy:number}
|
||||
local x: tagged = {tag="@1"}
|
||||
)");
|
||||
|
||||
auto ac = autocomplete('1');
|
||||
|
||||
CHECK(ac.entryMap.count("cat"));
|
||||
CHECK(ac.entryMap.count("dog"));
|
||||
CHECK_EQ(ac.context, AutocompleteContext::String);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ACFixture, "autocomplete_string_singletons")
|
||||
{
|
||||
check(R"(
|
||||
type tag = "cat" | "dog"
|
||||
local function f(a: tag) end
|
||||
|
@ -3120,17 +3139,6 @@ TEST_CASE_FIXTURE(ACFixture, "autocomplete_string_singletons")
|
|||
CHECK(ac.entryMap.count("cat"));
|
||||
CHECK(ac.entryMap.count("dog"));
|
||||
CHECK_EQ(ac.context, AutocompleteContext::String);
|
||||
|
||||
check(R"(
|
||||
type tagged = {tag:"cat", fieldx:number} | {tag:"dog", fieldy:number}
|
||||
local x: tagged = {tag="@4"}
|
||||
)");
|
||||
|
||||
ac = autocomplete('4');
|
||||
|
||||
CHECK(ac.entryMap.count("cat"));
|
||||
CHECK(ac.entryMap.count("dog"));
|
||||
CHECK_EQ(ac.context, AutocompleteContext::String);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ACFixture, "string_singleton_as_table_key_iso")
|
||||
|
@ -3705,7 +3713,7 @@ local a = { x = 2, y = 4 }
|
|||
a.@1
|
||||
)");
|
||||
|
||||
frontend.clear();
|
||||
getFrontend().clear();
|
||||
|
||||
auto ac = autocomplete('1');
|
||||
|
||||
|
@ -3714,21 +3722,21 @@ a.@1
|
|||
CHECK(ac.entryMap.count("x"));
|
||||
CHECK(ac.entryMap.count("y"));
|
||||
|
||||
frontend.check("MainModule", {});
|
||||
getFrontend().check("MainModule", {});
|
||||
|
||||
ac = autocomplete('1');
|
||||
|
||||
CHECK(ac.entryMap.count("x"));
|
||||
CHECK(ac.entryMap.count("y"));
|
||||
|
||||
frontend.markDirty("MainModule", nullptr);
|
||||
getFrontend().markDirty("MainModule", nullptr);
|
||||
|
||||
ac = autocomplete('1');
|
||||
|
||||
CHECK(ac.entryMap.count("x"));
|
||||
CHECK(ac.entryMap.count("y"));
|
||||
|
||||
frontend.check("MainModule", {});
|
||||
getFrontend().check("MainModule", {});
|
||||
|
||||
ac = autocomplete('1');
|
||||
|
||||
|
@ -3763,7 +3771,7 @@ TEST_CASE_FIXTURE(ACFixture, "string_contents_is_available_to_callback")
|
|||
declare function require(path: string): any
|
||||
)");
|
||||
|
||||
GlobalTypes& globals = FFlag::LuauSolverV2 ? frontend.globals : frontend.globalsForAutocomplete;
|
||||
GlobalTypes& globals = FFlag::LuauSolverV2 ? getFrontend().globals : getFrontend().globalsForAutocomplete;
|
||||
|
||||
std::optional<Binding> require = globals.globalScope->linearSearchForBinding("require");
|
||||
REQUIRE(require);
|
||||
|
@ -3944,7 +3952,7 @@ local a: T@1
|
|||
CHECK_EQ(ac.context, AutocompleteContext::Type);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ACFixture, "frontend_use_correct_global_scope")
|
||||
TEST_CASE_FIXTURE(ACFixture, "getFrontend().use_correct_global_scope")
|
||||
{
|
||||
loadDefinition(R"(
|
||||
declare class Instance
|
||||
|
@ -3970,7 +3978,7 @@ TEST_CASE_FIXTURE(ACFixture, "string_completion_outside_quotes")
|
|||
declare function require(path: string): any
|
||||
)");
|
||||
|
||||
GlobalTypes& globals = FFlag::LuauSolverV2 ? frontend.globals : frontend.globalsForAutocomplete;
|
||||
GlobalTypes& globals = FFlag::LuauSolverV2 ? getFrontend().globals : getFrontend().globalsForAutocomplete;
|
||||
|
||||
std::optional<Binding> require = globals.globalScope->linearSearchForBinding("require");
|
||||
REQUIRE(require);
|
||||
|
@ -4468,9 +4476,9 @@ TEST_CASE_FIXTURE(ACExternTypeFixture, "ac_dont_overflow_on_recursive_union")
|
|||
|
||||
auto ac = autocomplete('1');
|
||||
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauSolverV2 && FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
// This `if` statement is because `LuauEagerGeneralization2`
|
||||
// This `if` statement is because `LuauEagerGeneralization4`
|
||||
// sets some flags
|
||||
CHECK(ac.entryMap.count("BaseMethod") > 0);
|
||||
CHECK(ac.entryMap.count("Method") > 0);
|
||||
|
@ -4501,8 +4509,8 @@ TEST_CASE_FIXTURE(ACBuiltinsFixture, "type_function_private_scope")
|
|||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
|
||||
// Global scope polution by the embedder has no effect
|
||||
addGlobalBinding(frontend.globals, "thisAlsoShouldNotBeThere", Binding{builtinTypes->anyType});
|
||||
addGlobalBinding(frontend.globalsForAutocomplete, "thisAlsoShouldNotBeThere", Binding{builtinTypes->anyType});
|
||||
addGlobalBinding(getFrontend().globals, "thisAlsoShouldNotBeThere", Binding{getBuiltins()->anyType});
|
||||
addGlobalBinding(getFrontend().globalsForAutocomplete, "thisAlsoShouldNotBeThere", Binding{getBuiltins()->anyType});
|
||||
|
||||
check(R"(
|
||||
local function thisShouldNotBeThere() end
|
||||
|
@ -4607,4 +4615,29 @@ TEST_CASE_FIXTURE(ACFixture, "autocomplete_in_type_assertion")
|
|||
CHECK_EQ(ac2.entryMap.count("prop"), 1);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ACFixture, "autocomplete_implicit_named_index_index_expr")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
// Somewhat surprisingly, the old solver didn't cover this case.
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauExpectedTypeVisitor, true},
|
||||
{FFlag::LuauImplicitTableIndexerKeys, true},
|
||||
};
|
||||
|
||||
check(R"(
|
||||
type Constraint = "A" | "B" | "C"
|
||||
local foo : { [Constraint]: string } = {
|
||||
A = "Value for A",
|
||||
B = "Value for B",
|
||||
C = "Value for C",
|
||||
}
|
||||
foo["@1"]
|
||||
)");
|
||||
|
||||
auto ac = autocomplete('1');
|
||||
CHECK_EQ(ac.entryMap.count("A"), 1);
|
||||
CHECK_EQ(ac.entryMap.count("B"), 1);
|
||||
CHECK_EQ(ac.entryMap.count("C"), 1);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -12,9 +12,9 @@ TEST_SUITE_BEGIN("BuiltinDefinitionsTest");
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "lib_documentation_symbols")
|
||||
{
|
||||
CHECK(!frontend.globals.globalScope->bindings.empty());
|
||||
CHECK(!getFrontend().globals.globalScope->bindings.empty());
|
||||
|
||||
for (const auto& [name, binding] : frontend.globals.globalScope->bindings)
|
||||
for (const auto& [name, binding] : getFrontend().globals.globalScope->bindings)
|
||||
{
|
||||
std::string nameString(name.c_str());
|
||||
std::string expectedRootSymbol = "@luau/global/" + nameString;
|
||||
|
|
|
@ -12,10 +12,17 @@ namespace Luau
|
|||
ExternTypeFixture::ExternTypeFixture(bool prepareAutocomplete)
|
||||
: BuiltinsFixture(prepareAutocomplete)
|
||||
{
|
||||
GlobalTypes& globals = frontend.globals;
|
||||
|
||||
}
|
||||
|
||||
Frontend& ExternTypeFixture::getFrontend()
|
||||
{
|
||||
Frontend& f = BuiltinsFixture::getFrontend();
|
||||
|
||||
GlobalTypes& globals = f.globals;
|
||||
TypeArena& arena = globals.globalTypes;
|
||||
TypeId numberType = builtinTypes->numberType;
|
||||
TypeId stringType = builtinTypes->stringType;
|
||||
TypeId numberType = getBuiltins()->numberType;
|
||||
TypeId stringType = getBuiltins()->stringType;
|
||||
|
||||
unfreeze(arena);
|
||||
|
||||
|
@ -30,8 +37,7 @@ ExternTypeFixture::ExternTypeFixture(bool prepareAutocomplete)
|
|||
};
|
||||
|
||||
getMutable<ExternType>(connectionType)->props = {
|
||||
{"Connect", {makeFunction(arena, connectionType, {makeFunction(arena, nullopt, {baseClassInstanceType}, {})}, {})}}
|
||||
};
|
||||
{"Connect", {makeFunction(arena, connectionType, {makeFunction(arena, nullopt, {baseClassInstanceType}, {})}, {})}}};
|
||||
|
||||
TypeId baseClassType = arena.addType(ExternType{"BaseClass", {}, nullopt, nullopt, {}, {}, "Test", {}});
|
||||
getMutable<ExternType>(baseClassType)->props = {
|
||||
|
@ -107,9 +113,8 @@ ExternTypeFixture::ExternTypeFixture(bool prepareAutocomplete)
|
|||
{"__mul",
|
||||
{arena.addType(IntersectionType{{
|
||||
makeFunction(arena, vector2InstanceType, {vector2InstanceType}, {vector2InstanceType}),
|
||||
makeFunction(arena, vector2InstanceType, {builtinTypes->numberType}, {vector2InstanceType}),
|
||||
}})}}
|
||||
};
|
||||
makeFunction(arena, vector2InstanceType, {getBuiltins()->numberType}, {vector2InstanceType}),
|
||||
}})}}};
|
||||
globals.globalScope->exportedTypeBindings["Vector2"] = TypeFun{{}, vector2InstanceType};
|
||||
addGlobalBinding(globals, "Vector2", vector2Type, "@test");
|
||||
|
||||
|
@ -146,6 +151,7 @@ ExternTypeFixture::ExternTypeFixture(bool prepareAutocomplete)
|
|||
persist(tf.type);
|
||||
|
||||
freeze(arena);
|
||||
return *frontend;
|
||||
}
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -10,6 +10,8 @@ struct ExternTypeFixture : BuiltinsFixture
|
|||
{
|
||||
explicit ExternTypeFixture(bool prepareAutocomplete = false);
|
||||
|
||||
Frontend& getFrontend() override;
|
||||
|
||||
TypeId vector2Type;
|
||||
TypeId vector2InstanceType;
|
||||
};
|
||||
|
|
|
@ -10,9 +10,10 @@ namespace Luau
|
|||
ConstraintGeneratorFixture::ConstraintGeneratorFixture()
|
||||
: Fixture()
|
||||
, mainModule(new Module)
|
||||
, simplifier(newSimplifier(NotNull{&arena}, builtinTypes))
|
||||
, simplifier(newSimplifier(NotNull{&arena}, getBuiltins()))
|
||||
, forceTheFlag{FFlag::LuauSolverV2, true}
|
||||
{
|
||||
getFrontend(); // Force the frontend to exist in the constructor.
|
||||
mainModule->name = "MainModule";
|
||||
mainModule->humanReadableName = "MainModule";
|
||||
|
||||
|
@ -31,10 +32,10 @@ void ConstraintGeneratorFixture::generateConstraints(const std::string& code)
|
|||
NotNull{simplifier.get()},
|
||||
NotNull{&typeFunctionRuntime},
|
||||
NotNull(&moduleResolver),
|
||||
builtinTypes,
|
||||
getBuiltins(),
|
||||
NotNull(&ice),
|
||||
frontend.globals.globalScope,
|
||||
frontend.globals.globalTypeFunctionScope,
|
||||
getFrontend().globals.globalScope,
|
||||
getFrontend().globals.globalTypeFunctionScope,
|
||||
/*prepareModuleScope*/ nullptr,
|
||||
&logger,
|
||||
NotNull{dfg.get()},
|
||||
|
@ -60,8 +61,7 @@ void ConstraintGeneratorFixture::solve(const std::string& code)
|
|||
{},
|
||||
&logger,
|
||||
NotNull{dfg.get()},
|
||||
{}
|
||||
};
|
||||
{}};
|
||||
|
||||
cs.run();
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ struct ConstraintGeneratorFixture : Fixture
|
|||
ModulePtr mainModule;
|
||||
DcrLogger logger;
|
||||
UnifierSharedState sharedState{&ice};
|
||||
Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}};
|
||||
Normalizer normalizer{&arena, getBuiltins(), NotNull{&sharedState}};
|
||||
SimplifierPtr simplifier;
|
||||
TypeCheckLimits limits;
|
||||
TypeFunctionRuntime typeFunctionRuntime{NotNull{&ice}, NotNull{&limits}};
|
||||
|
|
|
@ -25,17 +25,17 @@ struct ESFixture : Fixture
|
|||
TypeId genericU = arena_.addType(GenericType{"U"});
|
||||
|
||||
TypeId numberToString =
|
||||
arena_.addType(FunctionType{arena_.addTypePack({builtinTypes->numberType}), arena_.addTypePack({builtinTypes->stringType})});
|
||||
arena_.addType(FunctionType{arena_.addTypePack({getBuiltins()->numberType}), arena_.addTypePack({getBuiltins()->stringType})});
|
||||
|
||||
TypeId stringToNumber =
|
||||
arena_.addType(FunctionType{arena_.addTypePack({builtinTypes->stringType}), arena_.addTypePack({builtinTypes->numberType})});
|
||||
arena_.addType(FunctionType{arena_.addTypePack({getBuiltins()->stringType}), arena_.addTypePack({getBuiltins()->numberType})});
|
||||
|
||||
ESFixture()
|
||||
: simplifier(newSimplifier(arena, builtinTypes))
|
||||
: simplifier(newSimplifier(arena, getBuiltins()))
|
||||
{
|
||||
createSomeExternTypes(&frontend);
|
||||
createSomeExternTypes(getFrontend());
|
||||
|
||||
ScopePtr moduleScope = frontend.globals.globalScope;
|
||||
ScopePtr moduleScope = getFrontend().globals.globalScope;
|
||||
|
||||
parentClass = moduleScope->linearSearchForBinding("Parent")->typeId;
|
||||
childClass = moduleScope->linearSearchForBinding("Child")->typeId;
|
||||
|
@ -60,116 +60,116 @@ TEST_SUITE_BEGIN("EqSatSimplification");
|
|||
|
||||
TEST_CASE_FIXTURE(ESFixture, "primitive")
|
||||
{
|
||||
CHECK("number" == simplifyStr(builtinTypes->numberType));
|
||||
CHECK("number" == simplifyStr(getBuiltins()->numberType));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "number | number")
|
||||
{
|
||||
TypeId ty = arena->addType(UnionType{{builtinTypes->numberType, builtinTypes->numberType}});
|
||||
TypeId ty = arena->addType(UnionType{{getBuiltins()->numberType, getBuiltins()->numberType}});
|
||||
|
||||
CHECK("number" == simplifyStr(ty));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "number | string")
|
||||
{
|
||||
CHECK("number | string" == simplifyStr(arena->addType(UnionType{{builtinTypes->numberType, builtinTypes->stringType}})));
|
||||
CHECK("number | string" == simplifyStr(arena->addType(UnionType{{getBuiltins()->numberType, getBuiltins()->stringType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "t1 where t1 = number | t1")
|
||||
{
|
||||
TypeId ty = arena->freshType(builtinTypes, nullptr);
|
||||
asMutable(ty)->ty.emplace<UnionType>(std::vector<TypeId>{builtinTypes->numberType, ty});
|
||||
TypeId ty = arena->freshType(getBuiltins(), nullptr);
|
||||
asMutable(ty)->ty.emplace<UnionType>(std::vector<TypeId>{getBuiltins()->numberType, ty});
|
||||
|
||||
CHECK("number" == simplifyStr(ty));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "number | string | number")
|
||||
{
|
||||
TypeId ty = arena->addType(UnionType{{builtinTypes->numberType, builtinTypes->stringType, builtinTypes->numberType}});
|
||||
TypeId ty = arena->addType(UnionType{{getBuiltins()->numberType, getBuiltins()->stringType, getBuiltins()->numberType}});
|
||||
|
||||
CHECK("number | string" == simplifyStr(ty));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "string | (number | string) | number")
|
||||
{
|
||||
TypeId u1 = arena->addType(UnionType{{builtinTypes->numberType, builtinTypes->stringType}});
|
||||
TypeId u2 = arena->addType(UnionType{{builtinTypes->stringType, u1, builtinTypes->numberType}});
|
||||
TypeId u1 = arena->addType(UnionType{{getBuiltins()->numberType, getBuiltins()->stringType}});
|
||||
TypeId u2 = arena->addType(UnionType{{getBuiltins()->stringType, u1, getBuiltins()->numberType}});
|
||||
|
||||
CHECK("number | string" == simplifyStr(u2));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "string | any")
|
||||
{
|
||||
CHECK("any" == simplifyStr(arena->addType(UnionType{{builtinTypes->stringType, builtinTypes->anyType}})));
|
||||
CHECK("any" == simplifyStr(arena->addType(UnionType{{getBuiltins()->stringType, getBuiltins()->anyType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "any | string")
|
||||
{
|
||||
CHECK("any" == simplifyStr(arena->addType(UnionType{{builtinTypes->anyType, builtinTypes->stringType}})));
|
||||
CHECK("any" == simplifyStr(arena->addType(UnionType{{getBuiltins()->anyType, getBuiltins()->stringType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "any | never")
|
||||
{
|
||||
CHECK("any" == simplifyStr(arena->addType(UnionType{{builtinTypes->anyType, builtinTypes->neverType}})));
|
||||
CHECK("any" == simplifyStr(arena->addType(UnionType{{getBuiltins()->anyType, getBuiltins()->neverType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "string | unknown")
|
||||
{
|
||||
CHECK("unknown" == simplifyStr(arena->addType(UnionType{{builtinTypes->stringType, builtinTypes->unknownType}})));
|
||||
CHECK("unknown" == simplifyStr(arena->addType(UnionType{{getBuiltins()->stringType, getBuiltins()->unknownType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "unknown | string")
|
||||
{
|
||||
CHECK("unknown" == simplifyStr(arena->addType(UnionType{{builtinTypes->unknownType, builtinTypes->stringType}})));
|
||||
CHECK("unknown" == simplifyStr(arena->addType(UnionType{{getBuiltins()->unknownType, getBuiltins()->stringType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "unknown | never")
|
||||
{
|
||||
CHECK("unknown" == simplifyStr(arena->addType(UnionType{{builtinTypes->unknownType, builtinTypes->neverType}})));
|
||||
CHECK("unknown" == simplifyStr(arena->addType(UnionType{{getBuiltins()->unknownType, getBuiltins()->neverType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "string | never")
|
||||
{
|
||||
CHECK("string" == simplifyStr(arena->addType(UnionType{{builtinTypes->stringType, builtinTypes->neverType}})));
|
||||
CHECK("string" == simplifyStr(arena->addType(UnionType{{getBuiltins()->stringType, getBuiltins()->neverType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "string | never | number")
|
||||
{
|
||||
CHECK("number | string" == simplifyStr(arena->addType(UnionType{{builtinTypes->stringType, builtinTypes->neverType, builtinTypes->numberType}})));
|
||||
CHECK("number | string" == simplifyStr(arena->addType(UnionType{{getBuiltins()->stringType, getBuiltins()->neverType, getBuiltins()->numberType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "string & string")
|
||||
{
|
||||
CHECK("string" == simplifyStr(arena->addType(IntersectionType{{builtinTypes->stringType, builtinTypes->stringType}})));
|
||||
CHECK("string" == simplifyStr(arena->addType(IntersectionType{{getBuiltins()->stringType, getBuiltins()->stringType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "string & number")
|
||||
{
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{builtinTypes->stringType, builtinTypes->numberType}})));
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{getBuiltins()->stringType, getBuiltins()->numberType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "string & unknown")
|
||||
{
|
||||
CHECK("string" == simplifyStr(arena->addType(IntersectionType{{builtinTypes->stringType, builtinTypes->unknownType}})));
|
||||
CHECK("string" == simplifyStr(arena->addType(IntersectionType{{getBuiltins()->stringType, getBuiltins()->unknownType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "never & string")
|
||||
{
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{builtinTypes->neverType, builtinTypes->stringType}})));
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{getBuiltins()->neverType, getBuiltins()->stringType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "string & (unknown | never)")
|
||||
{
|
||||
CHECK(
|
||||
"string" == simplifyStr(arena->addType(
|
||||
IntersectionType{{builtinTypes->stringType, arena->addType(UnionType{{builtinTypes->unknownType, builtinTypes->neverType}})}}
|
||||
IntersectionType{{getBuiltins()->stringType, arena->addType(UnionType{{getBuiltins()->unknownType, getBuiltins()->neverType}})}}
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "true | false")
|
||||
{
|
||||
CHECK("boolean" == simplifyStr(arena->addType(UnionType{{builtinTypes->trueType, builtinTypes->falseType}})));
|
||||
CHECK("boolean" == simplifyStr(arena->addType(UnionType{{getBuiltins()->trueType, getBuiltins()->falseType}})));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -185,9 +185,9 @@ TEST_CASE_FIXTURE(ESFixture, "true | false")
|
|||
TEST_CASE_FIXTURE(ESFixture, "t1 where t1 = string & (number | t1)")
|
||||
{
|
||||
TypeId intersectionTy = arena->addType(BlockedType{});
|
||||
TypeId unionTy = arena->addType(UnionType{{builtinTypes->numberType, intersectionTy}});
|
||||
TypeId unionTy = arena->addType(UnionType{{getBuiltins()->numberType, intersectionTy}});
|
||||
|
||||
asMutable(intersectionTy)->ty.emplace<IntersectionType>(std::vector<TypeId>{builtinTypes->stringType, unionTy});
|
||||
asMutable(intersectionTy)->ty.emplace<IntersectionType>(std::vector<TypeId>{getBuiltins()->stringType, unionTy});
|
||||
|
||||
CHECK("string" == simplifyStr(intersectionTy));
|
||||
}
|
||||
|
@ -195,21 +195,21 @@ TEST_CASE_FIXTURE(ESFixture, "t1 where t1 = string & (number | t1)")
|
|||
TEST_CASE_FIXTURE(ESFixture, "t1 where t1 = string & (unknown | t1)")
|
||||
{
|
||||
TypeId intersectionTy = arena->addType(BlockedType{});
|
||||
TypeId unionTy = arena->addType(UnionType{{builtinTypes->unknownType, intersectionTy}});
|
||||
TypeId unionTy = arena->addType(UnionType{{getBuiltins()->unknownType, intersectionTy}});
|
||||
|
||||
asMutable(intersectionTy)->ty.emplace<IntersectionType>(std::vector<TypeId>{builtinTypes->stringType, unionTy});
|
||||
asMutable(intersectionTy)->ty.emplace<IntersectionType>(std::vector<TypeId>{getBuiltins()->stringType, unionTy});
|
||||
|
||||
CHECK("string" == simplifyStr(intersectionTy));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "error | unknown")
|
||||
{
|
||||
CHECK("any" == simplifyStr(arena->addType(UnionType{{builtinTypes->errorType, builtinTypes->unknownType}})));
|
||||
CHECK("any" == simplifyStr(arena->addType(UnionType{{getBuiltins()->errorType, getBuiltins()->unknownType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "\"hello\" | string")
|
||||
{
|
||||
CHECK("string" == simplifyStr(arena->addType(UnionType{{arena->addType(SingletonType{StringSingleton{"hello"}}), builtinTypes->stringType}})));
|
||||
CHECK("string" == simplifyStr(arena->addType(UnionType{{arena->addType(SingletonType{StringSingleton{"hello"}}), getBuiltins()->stringType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "\"hello\" | \"world\" | \"hello\"")
|
||||
|
@ -227,22 +227,22 @@ TEST_CASE_FIXTURE(ESFixture, "nil | boolean | number | string | thread | functio
|
|||
{
|
||||
CHECK(
|
||||
"unknown" == simplifyStr(arena->addType(UnionType{{
|
||||
builtinTypes->nilType,
|
||||
builtinTypes->booleanType,
|
||||
builtinTypes->numberType,
|
||||
builtinTypes->stringType,
|
||||
builtinTypes->threadType,
|
||||
builtinTypes->functionType,
|
||||
builtinTypes->tableType,
|
||||
builtinTypes->externType,
|
||||
builtinTypes->bufferType,
|
||||
getBuiltins()->nilType,
|
||||
getBuiltins()->booleanType,
|
||||
getBuiltins()->numberType,
|
||||
getBuiltins()->stringType,
|
||||
getBuiltins()->threadType,
|
||||
getBuiltins()->functionType,
|
||||
getBuiltins()->tableType,
|
||||
getBuiltins()->externType,
|
||||
getBuiltins()->bufferType,
|
||||
}}))
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "Parent & number")
|
||||
{
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{parentClass, builtinTypes->numberType}})));
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{parentClass, getBuiltins()->numberType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "Child & Parent")
|
||||
|
@ -262,12 +262,12 @@ TEST_CASE_FIXTURE(ESFixture, "Child | Parent")
|
|||
|
||||
TEST_CASE_FIXTURE(ESFixture, "class | Child")
|
||||
{
|
||||
CHECK("class" == simplifyStr(arena->addType(UnionType{{builtinTypes->externType, childClass}})));
|
||||
CHECK("class" == simplifyStr(arena->addType(UnionType{{getBuiltins()->externType, childClass}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "Parent | class | Child")
|
||||
{
|
||||
CHECK("class" == simplifyStr(arena->addType(UnionType{{parentClass, builtinTypes->externType, childClass}})));
|
||||
CHECK("class" == simplifyStr(arena->addType(UnionType{{parentClass, getBuiltins()->externType, childClass}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "Parent | Unrelated")
|
||||
|
@ -277,16 +277,16 @@ TEST_CASE_FIXTURE(ESFixture, "Parent | Unrelated")
|
|||
|
||||
TEST_CASE_FIXTURE(ESFixture, "never | Parent | Unrelated")
|
||||
{
|
||||
CHECK("Parent | Unrelated" == simplifyStr(arena->addType(UnionType{{builtinTypes->neverType, parentClass, unrelatedClass}})));
|
||||
CHECK("Parent | Unrelated" == simplifyStr(arena->addType(UnionType{{getBuiltins()->neverType, parentClass, unrelatedClass}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "never | Parent | (number & string) | Unrelated")
|
||||
{
|
||||
CHECK(
|
||||
"Parent | Unrelated" == simplifyStr(arena->addType(UnionType{
|
||||
{builtinTypes->neverType,
|
||||
{getBuiltins()->neverType,
|
||||
parentClass,
|
||||
arena->addType(IntersectionType{{builtinTypes->numberType, builtinTypes->stringType}}),
|
||||
arena->addType(IntersectionType{{getBuiltins()->numberType, getBuiltins()->stringType}}),
|
||||
unrelatedClass}
|
||||
}))
|
||||
);
|
||||
|
@ -299,33 +299,33 @@ TEST_CASE_FIXTURE(ESFixture, "T & U")
|
|||
|
||||
TEST_CASE_FIXTURE(ESFixture, "boolean & true")
|
||||
{
|
||||
CHECK("true" == simplifyStr(arena->addType(IntersectionType{{builtinTypes->booleanType, builtinTypes->trueType}})));
|
||||
CHECK("true" == simplifyStr(arena->addType(IntersectionType{{getBuiltins()->booleanType, getBuiltins()->trueType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "boolean & (true | number | string | thread | function | table | class | buffer)")
|
||||
{
|
||||
TypeId truthy = arena->addType(UnionType{{
|
||||
builtinTypes->trueType,
|
||||
builtinTypes->numberType,
|
||||
builtinTypes->stringType,
|
||||
builtinTypes->threadType,
|
||||
builtinTypes->functionType,
|
||||
builtinTypes->tableType,
|
||||
builtinTypes->externType,
|
||||
builtinTypes->bufferType,
|
||||
getBuiltins()->trueType,
|
||||
getBuiltins()->numberType,
|
||||
getBuiltins()->stringType,
|
||||
getBuiltins()->threadType,
|
||||
getBuiltins()->functionType,
|
||||
getBuiltins()->tableType,
|
||||
getBuiltins()->externType,
|
||||
getBuiltins()->bufferType,
|
||||
}});
|
||||
|
||||
CHECK("true" == simplifyStr(arena->addType(IntersectionType{{builtinTypes->booleanType, truthy}})));
|
||||
CHECK("true" == simplifyStr(arena->addType(IntersectionType{{getBuiltins()->booleanType, truthy}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "boolean & ~(false?)")
|
||||
{
|
||||
CHECK("true" == simplifyStr(arena->addType(IntersectionType{{builtinTypes->booleanType, builtinTypes->truthyType}})));
|
||||
CHECK("true" == simplifyStr(arena->addType(IntersectionType{{getBuiltins()->booleanType, getBuiltins()->truthyType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "false & ~(false?)")
|
||||
{
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{builtinTypes->falseType, builtinTypes->truthyType}})));
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{getBuiltins()->falseType, getBuiltins()->truthyType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "(number) -> string & (number) -> string")
|
||||
|
@ -340,28 +340,28 @@ TEST_CASE_FIXTURE(ESFixture, "(number) -> string | (number) -> string")
|
|||
|
||||
TEST_CASE_FIXTURE(ESFixture, "(number) -> string & function")
|
||||
{
|
||||
CHECK("(number) -> string" == simplifyStr(arena->addType(IntersectionType{{numberToString, builtinTypes->functionType}})));
|
||||
CHECK("(number) -> string" == simplifyStr(arena->addType(IntersectionType{{numberToString, getBuiltins()->functionType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "(number) -> string & boolean")
|
||||
{
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{numberToString, builtinTypes->booleanType}})));
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{numberToString, getBuiltins()->booleanType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "(number) -> string & string")
|
||||
{
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{numberToString, builtinTypes->stringType}})));
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{numberToString, getBuiltins()->stringType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "(number) -> string & ~function")
|
||||
{
|
||||
TypeId notFunction = arena->addType(NegationType{builtinTypes->functionType});
|
||||
TypeId notFunction = arena->addType(NegationType{getBuiltins()->functionType});
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{numberToString, notFunction}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "(number) -> string | function")
|
||||
{
|
||||
CHECK("function" == simplifyStr(arena->addType(UnionType{{numberToString, builtinTypes->functionType}})));
|
||||
CHECK("function" == simplifyStr(arena->addType(UnionType{{numberToString, getBuiltins()->functionType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "(number) -> string & (string) -> number")
|
||||
|
@ -378,7 +378,7 @@ TEST_CASE_FIXTURE(ESFixture, "add<number, number>")
|
|||
{
|
||||
CHECK(
|
||||
"number" ==
|
||||
simplifyStr(arena->addType(TypeFunctionInstanceType{builtinTypeFunctions().addFunc, {builtinTypes->numberType, builtinTypes->numberType}}))
|
||||
simplifyStr(arena->addType(TypeFunctionInstanceType{builtinTypeFunctions().addFunc, {getBuiltins()->numberType, getBuiltins()->numberType}}))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -386,14 +386,14 @@ TEST_CASE_FIXTURE(ESFixture, "union<number, number>")
|
|||
{
|
||||
CHECK(
|
||||
"number" ==
|
||||
simplifyStr(arena->addType(TypeFunctionInstanceType{builtinTypeFunctions().unionFunc, {builtinTypes->numberType, builtinTypes->numberType}}))
|
||||
simplifyStr(arena->addType(TypeFunctionInstanceType{builtinTypeFunctions().unionFunc, {getBuiltins()->numberType, getBuiltins()->numberType}}))
|
||||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "never & ~string")
|
||||
{
|
||||
CHECK(
|
||||
"never" == simplifyStr(arena->addType(IntersectionType{{builtinTypes->neverType, arena->addType(NegationType{builtinTypes->stringType})}}))
|
||||
"never" == simplifyStr(arena->addType(IntersectionType{{getBuiltins()->neverType, arena->addType(NegationType{getBuiltins()->stringType})}}))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -401,15 +401,15 @@ TEST_CASE_FIXTURE(ESFixture, "blocked & never")
|
|||
{
|
||||
const TypeId blocked = arena->addType(BlockedType{});
|
||||
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{blocked, builtinTypes->neverType}})));
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{blocked, getBuiltins()->neverType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "blocked & ~number & function")
|
||||
{
|
||||
const TypeId blocked = arena->addType(BlockedType{});
|
||||
const TypeId notNumber = arena->addType(NegationType{builtinTypes->numberType});
|
||||
const TypeId notNumber = arena->addType(NegationType{getBuiltins()->numberType});
|
||||
|
||||
const TypeId ty = arena->addType(IntersectionType{{blocked, notNumber, builtinTypes->functionType}});
|
||||
const TypeId ty = arena->addType(IntersectionType{{blocked, notNumber, getBuiltins()->functionType}});
|
||||
|
||||
std::string expected = toString(blocked) + " & function";
|
||||
|
||||
|
@ -419,24 +419,24 @@ TEST_CASE_FIXTURE(ESFixture, "blocked & ~number & function")
|
|||
TEST_CASE_FIXTURE(ESFixture, "(number | boolean | string | nil | table) & (false | nil)")
|
||||
{
|
||||
const TypeId t1 = arena->addType(
|
||||
UnionType{{builtinTypes->numberType, builtinTypes->booleanType, builtinTypes->stringType, builtinTypes->nilType, builtinTypes->tableType}}
|
||||
UnionType{{getBuiltins()->numberType, getBuiltins()->booleanType, getBuiltins()->stringType, getBuiltins()->nilType, getBuiltins()->tableType}}
|
||||
);
|
||||
|
||||
CHECK("false?" == simplifyStr(arena->addType(IntersectionType{{t1, builtinTypes->falsyType}})));
|
||||
CHECK("false?" == simplifyStr(arena->addType(IntersectionType{{t1, getBuiltins()->falsyType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "(number | boolean | nil) & (false | nil)")
|
||||
{
|
||||
const TypeId t1 = arena->addType(UnionType{{builtinTypes->numberType, builtinTypes->booleanType, builtinTypes->nilType}});
|
||||
const TypeId t1 = arena->addType(UnionType{{getBuiltins()->numberType, getBuiltins()->booleanType, getBuiltins()->nilType}});
|
||||
|
||||
CHECK("false?" == simplifyStr(arena->addType(IntersectionType{{t1, builtinTypes->falsyType}})));
|
||||
CHECK("false?" == simplifyStr(arena->addType(IntersectionType{{t1, getBuiltins()->falsyType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "(boolean | nil) & (false | nil)")
|
||||
{
|
||||
const TypeId t1 = arena->addType(UnionType{{builtinTypes->booleanType, builtinTypes->nilType}});
|
||||
const TypeId t1 = arena->addType(UnionType{{getBuiltins()->booleanType, getBuiltins()->nilType}});
|
||||
|
||||
CHECK("false?" == simplifyStr(arena->addType(IntersectionType{{t1, builtinTypes->falsyType}})));
|
||||
CHECK("false?" == simplifyStr(arena->addType(IntersectionType{{t1, getBuiltins()->falsyType}})));
|
||||
}
|
||||
|
||||
// (('a & false) | ('a & nil)) | number
|
||||
|
@ -450,16 +450,16 @@ TEST_CASE_FIXTURE(ESFixture, "(boolean | nil) & (false | nil)")
|
|||
|
||||
TEST_CASE_FIXTURE(ESFixture, "free & string & number")
|
||||
{
|
||||
Scope scope{builtinTypes->anyTypePack};
|
||||
const TypeId freeTy = arena->freshType(builtinTypes, &scope);
|
||||
Scope scope{getBuiltins()->anyTypePack};
|
||||
const TypeId freeTy = arena->freshType(getBuiltins(), &scope);
|
||||
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{freeTy, builtinTypes->numberType, builtinTypes->stringType}})));
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{freeTy, getBuiltins()->numberType, getBuiltins()->stringType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "(blocked & number) | (blocked & number)")
|
||||
{
|
||||
const TypeId blocked = arena->addType(BlockedType{});
|
||||
const TypeId u = arena->addType(IntersectionType{{blocked, builtinTypes->numberType}});
|
||||
const TypeId u = arena->addType(IntersectionType{{blocked, getBuiltins()->numberType}});
|
||||
const TypeId ty = arena->addType(UnionType{{u, u}});
|
||||
|
||||
const std::string blockedStr = toString(blocked);
|
||||
|
@ -469,23 +469,23 @@ TEST_CASE_FIXTURE(ESFixture, "(blocked & number) | (blocked & number)")
|
|||
|
||||
TEST_CASE_FIXTURE(ESFixture, "{} & unknown")
|
||||
{
|
||||
CHECK("{ }" == simplifyStr(arena->addType(IntersectionType{{tbl({}), builtinTypes->unknownType}})));
|
||||
CHECK("{ }" == simplifyStr(arena->addType(IntersectionType{{tbl({}), getBuiltins()->unknownType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "{} & table")
|
||||
{
|
||||
CHECK("{ }" == simplifyStr(arena->addType(IntersectionType{{tbl({}), builtinTypes->tableType}})));
|
||||
CHECK("{ }" == simplifyStr(arena->addType(IntersectionType{{tbl({}), getBuiltins()->tableType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "{} & ~(false?)")
|
||||
{
|
||||
CHECK("{ }" == simplifyStr(arena->addType(IntersectionType{{tbl({}), builtinTypes->truthyType}})));
|
||||
CHECK("{ }" == simplifyStr(arena->addType(IntersectionType{{tbl({}), getBuiltins()->truthyType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "{x: number?} & {x: number}")
|
||||
{
|
||||
const TypeId hasOptionalX = tbl({{"x", builtinTypes->optionalNumberType}});
|
||||
const TypeId hasX = tbl({{"x", builtinTypes->numberType}});
|
||||
const TypeId hasOptionalX = tbl({{"x", getBuiltins()->optionalNumberType}});
|
||||
const TypeId hasX = tbl({{"x", getBuiltins()->numberType}});
|
||||
|
||||
const TypeId ty = arena->addType(IntersectionType{{hasOptionalX, hasX}});
|
||||
auto res = eqSatSimplify(NotNull{simplifier.get()}, ty);
|
||||
|
@ -498,8 +498,8 @@ TEST_CASE_FIXTURE(ESFixture, "{x: number?} & {x: number}")
|
|||
|
||||
TEST_CASE_FIXTURE(ESFixture, "{x: number?} & {x: ~(false?)}")
|
||||
{
|
||||
const TypeId hasOptionalX = tbl({{"x", builtinTypes->optionalNumberType}});
|
||||
const TypeId hasX = tbl({{"x", builtinTypes->truthyType}});
|
||||
const TypeId hasOptionalX = tbl({{"x", getBuiltins()->optionalNumberType}});
|
||||
const TypeId hasX = tbl({{"x", getBuiltins()->truthyType}});
|
||||
|
||||
const TypeId ty = arena->addType(IntersectionType{{hasOptionalX, hasX}});
|
||||
auto res = eqSatSimplify(NotNull{simplifier.get()}, ty);
|
||||
|
@ -510,10 +510,10 @@ TEST_CASE_FIXTURE(ESFixture, "{x: number?} & {x: ~(false?)}")
|
|||
TEST_CASE_FIXTURE(ESFixture, "(({ x: number? }?) & { x: ~(false?) }")
|
||||
{
|
||||
// {x: number?}?
|
||||
const TypeId xWithOptionalNumber = arena->addType(UnionType{{tbl({{"x", builtinTypes->optionalNumberType}}), builtinTypes->nilType}});
|
||||
const TypeId xWithOptionalNumber = arena->addType(UnionType{{tbl({{"x", getBuiltins()->optionalNumberType}}), getBuiltins()->nilType}});
|
||||
|
||||
// {x: ~(false?)}
|
||||
const TypeId xWithTruthy = tbl({{"x", builtinTypes->truthyType}});
|
||||
const TypeId xWithTruthy = tbl({{"x", getBuiltins()->truthyType}});
|
||||
|
||||
const TypeId ty = arena->addType(IntersectionType{{xWithOptionalNumber, xWithTruthy}});
|
||||
|
||||
|
@ -523,15 +523,15 @@ TEST_CASE_FIXTURE(ESFixture, "(({ x: number? }?) & { x: ~(false?) }")
|
|||
TEST_CASE_FIXTURE(ESFixture, "never | (({ x: number? }?) & { x: ~(false?) })")
|
||||
{
|
||||
// {x: number?}?
|
||||
const TypeId xWithOptionalNumber = arena->addType(UnionType{{tbl({{"x", builtinTypes->optionalNumberType}}), builtinTypes->nilType}});
|
||||
const TypeId xWithOptionalNumber = arena->addType(UnionType{{tbl({{"x", getBuiltins()->optionalNumberType}}), getBuiltins()->nilType}});
|
||||
|
||||
// {x: ~(false?)}
|
||||
const TypeId xWithTruthy = tbl({{"x", builtinTypes->truthyType}});
|
||||
const TypeId xWithTruthy = tbl({{"x", getBuiltins()->truthyType}});
|
||||
|
||||
// ({x: number?}?) & {x: ~(false?)}
|
||||
const TypeId intersectionTy = arena->addType(IntersectionType{{xWithOptionalNumber, xWithTruthy}});
|
||||
|
||||
const TypeId ty = arena->addType(UnionType{{builtinTypes->neverType, intersectionTy}});
|
||||
const TypeId ty = arena->addType(UnionType{{getBuiltins()->neverType, intersectionTy}});
|
||||
|
||||
CHECK("{ x: number }" == simplifyStr(ty));
|
||||
}
|
||||
|
@ -539,13 +539,13 @@ TEST_CASE_FIXTURE(ESFixture, "never | (({ x: number? }?) & { x: ~(false?) })")
|
|||
TEST_CASE_FIXTURE(ESFixture, "({ x: number? }?) & { x: ~(false?) } & ~(false?)")
|
||||
{
|
||||
// {x: number?}?
|
||||
const TypeId xWithOptionalNumber = arena->addType(UnionType{{tbl({{"x", builtinTypes->optionalNumberType}}), builtinTypes->nilType}});
|
||||
const TypeId xWithOptionalNumber = arena->addType(UnionType{{tbl({{"x", getBuiltins()->optionalNumberType}}), getBuiltins()->nilType}});
|
||||
|
||||
// {x: ~(false?)}
|
||||
const TypeId xWithTruthy = tbl({{"x", builtinTypes->truthyType}});
|
||||
const TypeId xWithTruthy = tbl({{"x", getBuiltins()->truthyType}});
|
||||
|
||||
// ({x: number?}?) & {x: ~(false?)} & ~(false?)
|
||||
const TypeId intersectionTy = arena->addType(IntersectionType{{xWithOptionalNumber, xWithTruthy, builtinTypes->truthyType}});
|
||||
const TypeId intersectionTy = arena->addType(IntersectionType{{xWithOptionalNumber, xWithTruthy, getBuiltins()->truthyType}});
|
||||
|
||||
CHECK("{ x: number }" == simplifyStr(intersectionTy));
|
||||
}
|
||||
|
@ -555,10 +555,10 @@ TEST_CASE_FIXTURE(ESFixture, "({ x: number? }?) & { x: ~(false?) } & ~(false?)")
|
|||
TEST_CASE_FIXTURE(ESFixture, "(({ x: number? }?) & { x: ~(false?) } & ~(false?)) | number")
|
||||
{
|
||||
// ({ x: number? }?) & { x: ~(false?) } & ~(false?)
|
||||
const TypeId xWithOptionalNumber = tbl({{"x", builtinTypes->optionalNumberType}});
|
||||
const TypeId xWithTruthy = tbl({{"x", builtinTypes->truthyType}});
|
||||
const TypeId intersectionTy = arena->addType(IntersectionType{{xWithOptionalNumber, xWithTruthy, builtinTypes->truthyType}});
|
||||
const TypeId ty = arena->addType(UnionType{{intersectionTy, builtinTypes->numberType}});
|
||||
const TypeId xWithOptionalNumber = tbl({{"x", getBuiltins()->optionalNumberType}});
|
||||
const TypeId xWithTruthy = tbl({{"x", getBuiltins()->truthyType}});
|
||||
const TypeId intersectionTy = arena->addType(IntersectionType{{xWithOptionalNumber, xWithTruthy, getBuiltins()->truthyType}});
|
||||
const TypeId ty = arena->addType(UnionType{{intersectionTy, getBuiltins()->numberType}});
|
||||
|
||||
CHECK("{ x: number } | number" == simplifyStr(ty));
|
||||
}
|
||||
|
@ -566,22 +566,22 @@ TEST_CASE_FIXTURE(ESFixture, "(({ x: number? }?) & { x: ~(false?) } & ~(false?))
|
|||
|
||||
TEST_CASE_FIXTURE(ESFixture, "number & no-refine")
|
||||
{
|
||||
CHECK("number" == simplifyStr(arena->addType(IntersectionType{{builtinTypes->numberType, builtinTypes->noRefineType}})));
|
||||
CHECK("number" == simplifyStr(arena->addType(IntersectionType{{getBuiltins()->numberType, getBuiltins()->noRefineType}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "{ x: number } & ~boolean")
|
||||
{
|
||||
const TypeId tblTy = tbl(TableType::Props{{"x", builtinTypes->numberType}});
|
||||
const TypeId tblTy = tbl(TableType::Props{{"x", getBuiltins()->numberType}});
|
||||
|
||||
const TypeId ty = arena->addType(IntersectionType{{tblTy, arena->addType(NegationType{builtinTypes->booleanType})}});
|
||||
const TypeId ty = arena->addType(IntersectionType{{tblTy, arena->addType(NegationType{getBuiltins()->booleanType})}});
|
||||
|
||||
CHECK("{ x: number }" == simplifyStr(ty));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "(nil & string)?")
|
||||
{
|
||||
const TypeId nilAndString = arena->addType(IntersectionType{{builtinTypes->nilType, builtinTypes->stringType}});
|
||||
const TypeId ty = arena->addType(UnionType{{nilAndString, builtinTypes->nilType}});
|
||||
const TypeId nilAndString = arena->addType(IntersectionType{{getBuiltins()->nilType, getBuiltins()->stringType}});
|
||||
const TypeId ty = arena->addType(UnionType{{nilAndString, getBuiltins()->nilType}});
|
||||
|
||||
CHECK("nil" == simplifyStr(ty));
|
||||
}
|
||||
|
@ -590,7 +590,7 @@ TEST_CASE_FIXTURE(ESFixture, "string & \"hi\"")
|
|||
{
|
||||
const TypeId hi = arena->addType(SingletonType{StringSingleton{"hi"}});
|
||||
|
||||
CHECK("\"hi\"" == simplifyStr(arena->addType(IntersectionType{{builtinTypes->stringType, hi}})));
|
||||
CHECK("\"hi\"" == simplifyStr(arena->addType(IntersectionType{{getBuiltins()->stringType, hi}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "string & (\"hi\" | \"bye\")")
|
||||
|
@ -598,7 +598,7 @@ TEST_CASE_FIXTURE(ESFixture, "string & (\"hi\" | \"bye\")")
|
|||
const TypeId hi = arena->addType(SingletonType{StringSingleton{"hi"}});
|
||||
const TypeId bye = arena->addType(SingletonType{StringSingleton{"bye"}});
|
||||
|
||||
CHECK("\"bye\" | \"hi\"" == simplifyStr(arena->addType(IntersectionType{{builtinTypes->stringType, arena->addType(UnionType{{hi, bye}})}})));
|
||||
CHECK("\"bye\" | \"hi\"" == simplifyStr(arena->addType(IntersectionType{{getBuiltins()->stringType, arena->addType(UnionType{{hi, bye}})}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "(\"err\" | \"ok\") & ~\"ok\"")
|
||||
|
@ -622,7 +622,7 @@ TEST_CASE_FIXTURE(ESFixture, "(Child | Unrelated) & ~Child")
|
|||
|
||||
TEST_CASE_FIXTURE(ESFixture, "string & ~Child")
|
||||
{
|
||||
CHECK("string" == simplifyStr(arena->addType(IntersectionType{{builtinTypes->stringType, arena->addType(NegationType{childClass})}})));
|
||||
CHECK("string" == simplifyStr(arena->addType(IntersectionType{{getBuiltins()->stringType, arena->addType(NegationType{childClass})}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "(Child | Unrelated) & Child")
|
||||
|
@ -637,22 +637,22 @@ TEST_CASE_FIXTURE(ESFixture, "(Child | AnotherChild) & ~Child")
|
|||
|
||||
TEST_CASE_FIXTURE(ESFixture, "{ tag: \"Part\", x: never }")
|
||||
{
|
||||
const TypeId ty = tbl({{"tag", arena->addType(SingletonType{StringSingleton{"Part"}})}, {"x", builtinTypes->neverType}});
|
||||
const TypeId ty = tbl({{"tag", arena->addType(SingletonType{StringSingleton{"Part"}})}, {"x", getBuiltins()->neverType}});
|
||||
|
||||
CHECK("never" == simplifyStr(ty));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "{ tag: \"Part\", x: number? } & { x: string }")
|
||||
{
|
||||
const TypeId leftTable = tbl({{"tag", arena->addType(SingletonType{StringSingleton{"Part"}})}, {"x", builtinTypes->optionalNumberType}});
|
||||
const TypeId rightTable = tbl({{"x", builtinTypes->stringType}});
|
||||
const TypeId leftTable = tbl({{"tag", arena->addType(SingletonType{StringSingleton{"Part"}})}, {"x", getBuiltins()->optionalNumberType}});
|
||||
const TypeId rightTable = tbl({{"x", getBuiltins()->stringType}});
|
||||
|
||||
CHECK("never" == simplifyStr(arena->addType(IntersectionType{{leftTable, rightTable}})));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ESFixture, "Child & add<Child | AnotherChild | string, Parent>")
|
||||
{
|
||||
const TypeId u = arena->addType(UnionType{{childClass, anotherChild, builtinTypes->stringType}});
|
||||
const TypeId u = arena->addType(UnionType{{childClass, anotherChild, getBuiltins()->stringType}});
|
||||
const TypeId intersectTf = arena->addType(TypeFunctionInstanceType{builtinTypeFunctions().addFunc, {u, parentClass}, {}});
|
||||
|
||||
const TypeId intersection = arena->addType(IntersectionType{{childClass, intersectTf}});
|
||||
|
@ -662,7 +662,7 @@ TEST_CASE_FIXTURE(ESFixture, "Child & add<Child | AnotherChild | string, Parent>
|
|||
|
||||
TEST_CASE_FIXTURE(ESFixture, "Child & intersect<Child | AnotherChild | string, Parent>")
|
||||
{
|
||||
const TypeId u = arena->addType(UnionType{{childClass, anotherChild, builtinTypes->stringType}});
|
||||
const TypeId u = arena->addType(UnionType{{childClass, anotherChild, getBuiltins()->stringType}});
|
||||
const TypeId intersectTf = arena->addType(TypeFunctionInstanceType{builtinTypeFunctions().intersectFunc, {u, parentClass}, {}});
|
||||
|
||||
const TypeId intersection = arena->addType(IntersectionType{{childClass, intersectTf}});
|
||||
|
@ -673,10 +673,10 @@ TEST_CASE_FIXTURE(ESFixture, "Child & intersect<Child | AnotherChild | string, P
|
|||
TEST_CASE_FIXTURE(ESFixture, "lt<number, _> == boolean")
|
||||
{
|
||||
std::vector<std::pair<TypeId, TypeId>> cases{
|
||||
{builtinTypes->numberType, arena->addType(BlockedType{})},
|
||||
{builtinTypes->stringType, arena->addType(BlockedType{})},
|
||||
{arena->addType(BlockedType{}), builtinTypes->numberType},
|
||||
{arena->addType(BlockedType{}), builtinTypes->stringType},
|
||||
{getBuiltins()->numberType, arena->addType(BlockedType{})},
|
||||
{getBuiltins()->stringType, arena->addType(BlockedType{})},
|
||||
{arena->addType(BlockedType{}), getBuiltins()->numberType},
|
||||
{arena->addType(BlockedType{}), getBuiltins()->stringType},
|
||||
};
|
||||
|
||||
for (const auto& [lhs, rhs] : cases)
|
||||
|
@ -689,7 +689,7 @@ TEST_CASE_FIXTURE(ESFixture, "lt<number, _> == boolean")
|
|||
TEST_CASE_FIXTURE(ESFixture, "unknown & ~string")
|
||||
{
|
||||
CHECK_EQ(
|
||||
"~string", simplifyStr(arena->addType(IntersectionType{{builtinTypes->unknownType, arena->addType(NegationType{builtinTypes->stringType})}}))
|
||||
"~string", simplifyStr(arena->addType(IntersectionType{{getBuiltins()->unknownType, arena->addType(NegationType{getBuiltins()->stringType})}}))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -698,7 +698,7 @@ TEST_CASE_FIXTURE(ESFixture, "string & ~\"foo\"")
|
|||
CHECK_EQ(
|
||||
"string & ~\"foo\"",
|
||||
simplifyStr(arena->addType(
|
||||
IntersectionType{{builtinTypes->stringType, arena->addType(NegationType{arena->addType(SingletonType{StringSingleton{"foo"}})})}}
|
||||
IntersectionType{{getBuiltins()->stringType, arena->addType(NegationType{arena->addType(SingletonType{StringSingleton{"foo"}})})}}
|
||||
))
|
||||
);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ TEST_CASE("TypeError_code_should_return_nonzero_code")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "metatable_names_show_instead_of_tables")
|
||||
{
|
||||
frontend.options.retainFullTypeGraphs = false;
|
||||
getFrontend().options.retainFullTypeGraphs = false;
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
@ -38,7 +38,7 @@ local x: Account = 5
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "binary_op_type_function_errors")
|
||||
{
|
||||
frontend.options.retainFullTypeGraphs = false;
|
||||
getFrontend().options.retainFullTypeGraphs = false;
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
@ -58,7 +58,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "binary_op_type_function_errors")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "unary_op_type_function_errors")
|
||||
{
|
||||
frontend.options.retainFullTypeGraphs = false;
|
||||
getFrontend().options.retainFullTypeGraphs = false;
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
|
|
@ -257,37 +257,8 @@ const Config& TestConfigResolver::getConfig(const ModuleName& name) const
|
|||
}
|
||||
|
||||
Fixture::Fixture(bool prepareAutocomplete)
|
||||
: frontend(
|
||||
&fileResolver,
|
||||
&configResolver,
|
||||
{/* retainFullTypeGraphs= */ true, /* forAutocomplete */ false, /* runLintChecks */ false, /* randomConstraintResolutionSeed */ randomSeed}
|
||||
)
|
||||
, builtinTypes(frontend.builtinTypes)
|
||||
: forAutocomplete(prepareAutocomplete)
|
||||
{
|
||||
configResolver.defaultConfig.mode = Mode::Strict;
|
||||
configResolver.defaultConfig.enabledLint.warningMask = ~0ull;
|
||||
configResolver.defaultConfig.parseOptions.captureComments = true;
|
||||
|
||||
Luau::freeze(frontend.globals.globalTypes);
|
||||
Luau::freeze(frontend.globalsForAutocomplete.globalTypes);
|
||||
|
||||
Luau::setPrintLine([](auto s) {});
|
||||
|
||||
if (FFlag::DebugLuauLogSolverToJsonFile)
|
||||
{
|
||||
frontend.writeJsonLog = [&](const Luau::ModuleName& moduleName, std::string log)
|
||||
{
|
||||
std::string path = moduleName + ".log.json";
|
||||
size_t pos = moduleName.find_last_of('/');
|
||||
if (pos != std::string::npos)
|
||||
path = moduleName.substr(pos + 1);
|
||||
|
||||
std::ofstream os(path);
|
||||
|
||||
os << log << std::endl;
|
||||
MESSAGE("Wrote JSON log to ", path);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Fixture::~Fixture()
|
||||
|
@ -318,27 +289,27 @@ AstStatBlock* Fixture::parse(const std::string& source, const ParseOptions& pars
|
|||
*sourceModule,
|
||||
mode,
|
||||
{},
|
||||
builtinTypes,
|
||||
getBuiltins(),
|
||||
NotNull{&ice},
|
||||
NotNull{&moduleResolver},
|
||||
NotNull{&fileResolver},
|
||||
frontend.globals.globalScope,
|
||||
frontend.globals.globalTypeFunctionScope,
|
||||
getFrontend().globals.globalScope,
|
||||
getFrontend().globals.globalTypeFunctionScope,
|
||||
/*prepareModuleScope*/ nullptr,
|
||||
frontend.options,
|
||||
getFrontend().options,
|
||||
{},
|
||||
false,
|
||||
{}
|
||||
);
|
||||
|
||||
Luau::lint(sourceModule->root, *sourceModule->names, frontend.globals.globalScope, module.get(), sourceModule->hotcomments, {});
|
||||
Luau::lint(sourceModule->root, *sourceModule->names, getFrontend().globals.globalScope, module.get(), sourceModule->hotcomments, {});
|
||||
}
|
||||
else
|
||||
{
|
||||
TypeChecker typeChecker(frontend.globals.globalScope, &moduleResolver, builtinTypes, &frontend.iceHandler);
|
||||
TypeChecker typeChecker(getFrontend().globals.globalScope, &moduleResolver, getBuiltins(), &getFrontend().iceHandler);
|
||||
ModulePtr module = typeChecker.check(*sourceModule, sourceModule->mode.value_or(Luau::Mode::Nonstrict), std::nullopt);
|
||||
|
||||
Luau::lint(sourceModule->root, *sourceModule->names, frontend.globals.globalScope, module.get(), sourceModule->hotcomments, {});
|
||||
Luau::lint(sourceModule->root, *sourceModule->names, getFrontend().globals.globalScope, module.get(), sourceModule->hotcomments, {});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -350,12 +321,14 @@ AstStatBlock* Fixture::parse(const std::string& source, const ParseOptions& pars
|
|||
|
||||
CheckResult Fixture::check(Mode mode, const std::string& source, std::optional<FrontendOptions> options)
|
||||
{
|
||||
// Force the frontend here
|
||||
getFrontend();
|
||||
ModuleName mm = fromString(mainModuleName);
|
||||
configResolver.defaultConfig.mode = mode;
|
||||
fileResolver.source[mm] = std::move(source);
|
||||
frontend.markDirty(mm);
|
||||
getFrontend().markDirty(mm);
|
||||
|
||||
CheckResult result = frontend.check(mm, options);
|
||||
CheckResult result = getFrontend().check(mm, options);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -370,18 +343,18 @@ LintResult Fixture::lint(const std::string& source, const std::optional<LintOpti
|
|||
ModuleName mm = fromString(mainModuleName);
|
||||
configResolver.defaultConfig.mode = Mode::Strict;
|
||||
fileResolver.source[mm] = std::move(source);
|
||||
frontend.markDirty(mm);
|
||||
getFrontend().markDirty(mm);
|
||||
|
||||
return lintModule(mm, lintOptions);
|
||||
}
|
||||
|
||||
LintResult Fixture::lintModule(const ModuleName& moduleName, const std::optional<LintOptions>& lintOptions)
|
||||
{
|
||||
FrontendOptions options = frontend.options;
|
||||
FrontendOptions options = getFrontend().options;
|
||||
options.runLintChecks = true;
|
||||
options.enabledLintWarnings = lintOptions;
|
||||
|
||||
CheckResult result = frontend.check(moduleName, options);
|
||||
CheckResult result = getFrontend().check(moduleName, options);
|
||||
|
||||
return result.lintResult;
|
||||
}
|
||||
|
@ -450,14 +423,14 @@ ParseResult Fixture::matchParseErrorPrefix(const std::string& source, const std:
|
|||
ModulePtr Fixture::getMainModule(bool forAutocomplete)
|
||||
{
|
||||
if (forAutocomplete && !FFlag::LuauSolverV2)
|
||||
return frontend.moduleResolverForAutocomplete.getModule(fromString(mainModuleName));
|
||||
return getFrontend().moduleResolverForAutocomplete.getModule(fromString(mainModuleName));
|
||||
|
||||
return frontend.moduleResolver.getModule(fromString(mainModuleName));
|
||||
return getFrontend().moduleResolver.getModule(fromString(mainModuleName));
|
||||
}
|
||||
|
||||
SourceModule* Fixture::getMainSourceModule()
|
||||
{
|
||||
return frontend.getSourceModule(fromString(mainModuleName));
|
||||
return getFrontend().getSourceModule(fromString(mainModuleName));
|
||||
}
|
||||
|
||||
std::optional<PrimitiveType::Type> Fixture::getPrimitiveType(TypeId ty)
|
||||
|
@ -497,7 +470,7 @@ TypeId Fixture::requireType(const std::string& name)
|
|||
|
||||
TypeId Fixture::requireType(const ModuleName& moduleName, const std::string& name)
|
||||
{
|
||||
ModulePtr module = frontend.moduleResolver.getModule(moduleName);
|
||||
ModulePtr module = getFrontend().moduleResolver.getModule(moduleName);
|
||||
REQUIRE(module);
|
||||
return requireType(module, name);
|
||||
}
|
||||
|
@ -573,7 +546,7 @@ TypeId Fixture::requireTypeAlias(const std::string& name)
|
|||
|
||||
TypeId Fixture::requireExportedType(const ModuleName& moduleName, const std::string& name)
|
||||
{
|
||||
ModulePtr module = frontend.moduleResolver.getModule(moduleName);
|
||||
ModulePtr module = getFrontend().moduleResolver.getModule(moduleName);
|
||||
REQUIRE(module);
|
||||
|
||||
auto it = module->exportedTypeBindings.find(name);
|
||||
|
@ -586,10 +559,10 @@ std::string Fixture::decorateWithTypes(const std::string& code)
|
|||
{
|
||||
fileResolver.source[mainModuleName] = code;
|
||||
|
||||
Luau::CheckResult typeInfo = frontend.check(mainModuleName);
|
||||
Luau::CheckResult typeInfo = getFrontend().check(mainModuleName);
|
||||
|
||||
SourceModule* sourceModule = frontend.getSourceModule(mainModuleName);
|
||||
attachTypeData(*sourceModule, *frontend.moduleResolver.getModule(mainModuleName));
|
||||
SourceModule* sourceModule = getFrontend().getSourceModule(mainModuleName);
|
||||
attachTypeData(*sourceModule, *getFrontend().moduleResolver.getModule(mainModuleName));
|
||||
|
||||
return transpileWithTypes(*sourceModule->root);
|
||||
}
|
||||
|
@ -621,9 +594,9 @@ void Fixture::dumpErrors(std::ostream& os, const std::vector<TypeError>& errors)
|
|||
|
||||
void Fixture::registerTestTypes()
|
||||
{
|
||||
addGlobalBinding(frontend.globals, "game", builtinTypes->anyType, "@luau");
|
||||
addGlobalBinding(frontend.globals, "workspace", builtinTypes->anyType, "@luau");
|
||||
addGlobalBinding(frontend.globals, "script", builtinTypes->anyType, "@luau");
|
||||
addGlobalBinding(getFrontend().globals, "game", getBuiltins()->anyType, "@luau");
|
||||
addGlobalBinding(getFrontend().globals, "workspace", getBuiltins()->anyType, "@luau");
|
||||
addGlobalBinding(getFrontend().globals, "script", getBuiltins()->anyType, "@luau");
|
||||
}
|
||||
|
||||
void Fixture::dumpErrors(const CheckResult& cr)
|
||||
|
@ -682,9 +655,9 @@ void Fixture::validateErrors(const std::vector<Luau::TypeError>& errors)
|
|||
|
||||
LoadDefinitionFileResult Fixture::loadDefinition(const std::string& source, bool forAutocomplete)
|
||||
{
|
||||
GlobalTypes& globals = forAutocomplete ? frontend.globalsForAutocomplete : frontend.globals;
|
||||
GlobalTypes& globals = forAutocomplete ? getFrontend().globalsForAutocomplete : getFrontend().globals;
|
||||
unfreeze(globals.globalTypes);
|
||||
LoadDefinitionFileResult result = frontend.loadDefinitionFile(
|
||||
LoadDefinitionFileResult result = getFrontend().loadDefinitionFile(
|
||||
globals, globals.globalScope, source, "@test", /* captureComments */ false, /* typecheckForAutocomplete */ forAutocomplete
|
||||
);
|
||||
freeze(globals.globalTypes);
|
||||
|
@ -695,19 +668,80 @@ LoadDefinitionFileResult Fixture::loadDefinition(const std::string& source, bool
|
|||
return result;
|
||||
}
|
||||
|
||||
NotNull<BuiltinTypes> Fixture::getBuiltins()
|
||||
{
|
||||
if (!builtinTypes)
|
||||
getFrontend();
|
||||
return NotNull{builtinTypes};
|
||||
}
|
||||
|
||||
Frontend& Fixture::getFrontend()
|
||||
{
|
||||
if (frontend)
|
||||
return *frontend;
|
||||
|
||||
Frontend& f = frontend.emplace(
|
||||
&fileResolver,
|
||||
&configResolver,
|
||||
FrontendOptions{
|
||||
/* retainFullTypeGraphs= */ true, /* forAutocomplete */ false, /* runLintChecks */ false, /* randomConstraintResolutionSeed */ randomSeed}
|
||||
);
|
||||
|
||||
builtinTypes = f.builtinTypes;
|
||||
// Fixture::Fixture begins here
|
||||
configResolver.defaultConfig.mode = Mode::Strict;
|
||||
configResolver.defaultConfig.enabledLint.warningMask = ~0ull;
|
||||
configResolver.defaultConfig.parseOptions.captureComments = true;
|
||||
|
||||
Luau::freeze(f.globals.globalTypes);
|
||||
Luau::freeze(f.globalsForAutocomplete.globalTypes);
|
||||
|
||||
Luau::setPrintLine([](auto s) {});
|
||||
|
||||
if (FFlag::DebugLuauLogSolverToJsonFile)
|
||||
{
|
||||
f.writeJsonLog = [&](const Luau::ModuleName& moduleName, std::string log)
|
||||
{
|
||||
std::string path = moduleName + ".log.json";
|
||||
size_t pos = moduleName.find_last_of('/');
|
||||
if (pos != std::string::npos)
|
||||
path = moduleName.substr(pos + 1);
|
||||
|
||||
std::ofstream os(path);
|
||||
|
||||
os << log << std::endl;
|
||||
MESSAGE("Wrote JSON log to ", path);
|
||||
};
|
||||
}
|
||||
return *frontend;
|
||||
}
|
||||
|
||||
|
||||
BuiltinsFixture::BuiltinsFixture(bool prepareAutocomplete)
|
||||
: Fixture(prepareAutocomplete)
|
||||
{
|
||||
Luau::unfreeze(frontend.globals.globalTypes);
|
||||
Luau::unfreeze(frontend.globalsForAutocomplete.globalTypes);
|
||||
|
||||
registerBuiltinGlobals(frontend, frontend.globals);
|
||||
if (prepareAutocomplete)
|
||||
registerBuiltinGlobals(frontend, frontend.globalsForAutocomplete, /*typeCheckForAutocomplete*/ true);
|
||||
}
|
||||
|
||||
Frontend& BuiltinsFixture::getFrontend()
|
||||
{
|
||||
if (frontend)
|
||||
return *frontend;
|
||||
|
||||
Frontend& f = Fixture::getFrontend();
|
||||
// Do builtins fixture things now
|
||||
Luau::unfreeze(f.globals.globalTypes);
|
||||
Luau::unfreeze(f.globalsForAutocomplete.globalTypes);
|
||||
|
||||
registerBuiltinGlobals(f, f.globals);
|
||||
if (forAutocomplete)
|
||||
registerBuiltinGlobals(f, f.globalsForAutocomplete, /*typeCheckForAutocomplete*/ true);
|
||||
registerTestTypes();
|
||||
|
||||
Luau::freeze(frontend.globals.globalTypes);
|
||||
Luau::freeze(frontend.globalsForAutocomplete.globalTypes);
|
||||
Luau::freeze(f.globals.globalTypes);
|
||||
Luau::freeze(f.globalsForAutocomplete.globalTypes);
|
||||
|
||||
return *frontend;
|
||||
}
|
||||
|
||||
static std::vector<std::string_view> parsePathExpr(const AstExpr& pathExpr)
|
||||
|
@ -831,9 +865,9 @@ std::optional<TypeId> linearSearchForBinding(Scope* scope, const char* name)
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
void registerHiddenTypes(Frontend* frontend)
|
||||
void registerHiddenTypes(Frontend& frontend)
|
||||
{
|
||||
GlobalTypes& globals = frontend->globals;
|
||||
GlobalTypes& globals = frontend.globals;
|
||||
|
||||
unfreeze(globals.globalTypes);
|
||||
|
||||
|
@ -846,24 +880,24 @@ void registerHiddenTypes(Frontend* frontend)
|
|||
ScopePtr globalScope = globals.globalScope;
|
||||
globalScope->exportedTypeBindings["Not"] = TypeFun{{genericT}, globals.globalTypes.addType(NegationType{t})};
|
||||
globalScope->exportedTypeBindings["Mt"] = TypeFun{{genericT, genericU}, globals.globalTypes.addType(MetatableType{t, u})};
|
||||
globalScope->exportedTypeBindings["fun"] = TypeFun{{}, frontend->builtinTypes->functionType};
|
||||
globalScope->exportedTypeBindings["cls"] = TypeFun{{}, frontend->builtinTypes->externType};
|
||||
globalScope->exportedTypeBindings["err"] = TypeFun{{}, frontend->builtinTypes->errorType};
|
||||
globalScope->exportedTypeBindings["tbl"] = TypeFun{{}, frontend->builtinTypes->tableType};
|
||||
globalScope->exportedTypeBindings["fun"] = TypeFun{{}, frontend.builtinTypes->functionType};
|
||||
globalScope->exportedTypeBindings["cls"] = TypeFun{{}, frontend.builtinTypes->externType};
|
||||
globalScope->exportedTypeBindings["err"] = TypeFun{{}, frontend.builtinTypes->errorType};
|
||||
globalScope->exportedTypeBindings["tbl"] = TypeFun{{}, frontend.builtinTypes->tableType};
|
||||
|
||||
freeze(globals.globalTypes);
|
||||
}
|
||||
|
||||
void createSomeExternTypes(Frontend* frontend)
|
||||
void createSomeExternTypes(Frontend& frontend)
|
||||
{
|
||||
GlobalTypes& globals = frontend->globals;
|
||||
GlobalTypes& globals = frontend.globals;
|
||||
|
||||
TypeArena& arena = globals.globalTypes;
|
||||
unfreeze(arena);
|
||||
|
||||
ScopePtr moduleScope = globals.globalScope;
|
||||
|
||||
TypeId parentType = arena.addType(ExternType{"Parent", {}, frontend->builtinTypes->externType, std::nullopt, {}, nullptr, "Test", {}});
|
||||
TypeId parentType = arena.addType(ExternType{"Parent", {}, frontend.builtinTypes->externType, std::nullopt, {}, nullptr, "Test", {}});
|
||||
|
||||
ExternType* parentExternType = getMutable<ExternType>(parentType);
|
||||
parentExternType->props["method"] = {makeFunction(arena, parentType, {}, {})};
|
||||
|
@ -883,7 +917,7 @@ void createSomeExternTypes(Frontend* frontend)
|
|||
addGlobalBinding(globals, "AnotherChild", {anotherChildType});
|
||||
moduleScope->exportedTypeBindings["AnotherChild"] = TypeFun{{}, anotherChildType};
|
||||
|
||||
TypeId unrelatedType = arena.addType(ExternType{"Unrelated", {}, frontend->builtinTypes->externType, std::nullopt, {}, nullptr, "Test", {}});
|
||||
TypeId unrelatedType = arena.addType(ExternType{"Unrelated", {}, frontend.builtinTypes->externType, std::nullopt, {}, nullptr, "Test", {}});
|
||||
|
||||
addGlobalBinding(globals, "Unrelated", {unrelatedType});
|
||||
moduleScope->exportedTypeBindings["Unrelated"] = TypeFun{{}, unrelatedType};
|
||||
|
|
|
@ -160,9 +160,8 @@ struct Fixture
|
|||
TestConfigResolver configResolver;
|
||||
NullModuleResolver moduleResolver;
|
||||
std::unique_ptr<SourceModule> sourceModule;
|
||||
Frontend frontend;
|
||||
InternalErrorReporter ice;
|
||||
NotNull<BuiltinTypes> builtinTypes;
|
||||
|
||||
|
||||
std::string decorateWithTypes(const std::string& code);
|
||||
|
||||
|
@ -179,9 +178,15 @@ struct Fixture
|
|||
void registerTestTypes();
|
||||
|
||||
LoadDefinitionFileResult loadDefinition(const std::string& source, bool forAutocomplete = false);
|
||||
|
||||
// TODO: test theory about dynamic dispatch
|
||||
NotNull<BuiltinTypes> getBuiltins();
|
||||
virtual Frontend& getFrontend();
|
||||
private:
|
||||
bool hasDumpedErrors = false;
|
||||
protected:
|
||||
bool forAutocomplete = false;
|
||||
std::optional<Frontend> frontend;
|
||||
BuiltinTypes* builtinTypes = nullptr;
|
||||
};
|
||||
|
||||
struct BuiltinsFixture : Fixture
|
||||
|
@ -190,6 +195,7 @@ struct BuiltinsFixture : Fixture
|
|||
|
||||
// For the purpose of our tests, we're always the latest version of type functions.
|
||||
ScopedFastFlag sff_optionalInTypeFunctionLib{FFlag::LuauTypeFunOptional, true};
|
||||
Frontend& getFrontend() override;
|
||||
};
|
||||
|
||||
std::optional<std::string> pathExprToModuleName(const ModuleName& currentModuleName, const std::vector<std::string_view>& segments);
|
||||
|
@ -220,8 +226,8 @@ std::optional<TypeId> lookupName(ScopePtr scope, const std::string& name); // Wa
|
|||
|
||||
std::optional<TypeId> linearSearchForBinding(Scope* scope, const char* name);
|
||||
|
||||
void registerHiddenTypes(Frontend* frontend);
|
||||
void createSomeExternTypes(Frontend* frontend);
|
||||
void registerHiddenTypes(Frontend& frontend);
|
||||
void createSomeExternTypes(Frontend& frontend);
|
||||
|
||||
template<typename E>
|
||||
const E* findError(const CheckResult& result)
|
||||
|
|
|
@ -51,7 +51,7 @@ static FrontendOptions getOptions()
|
|||
return options;
|
||||
}
|
||||
|
||||
static ModuleResolver& getModuleResolver(Luau::Frontend& frontend)
|
||||
static ModuleResolver& getModuleResolver(Frontend& frontend)
|
||||
{
|
||||
return FFlag::LuauSolverV2 ?frontend.moduleResolver : frontend.moduleResolverForAutocomplete;
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ struct FragmentAutocompleteFixtureImpl : BaseType
|
|||
)
|
||||
{
|
||||
ParseResult p = parseHelper(document);
|
||||
auto [_, result] = Luau::typecheckFragment(this->frontend, "MainModule", cursorPos, getOptions(), document, fragmentEndPosition, p.root);
|
||||
auto [_, result] = Luau::typecheckFragment(this->getFrontend(), "MainModule", cursorPos, getOptions(), document, fragmentEndPosition, p.root);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,7 @@ struct FragmentAutocompleteFixtureImpl : BaseType
|
|||
ParseResult parseResult = parseHelper(document);
|
||||
FrontendOptions options = getOptions();
|
||||
FragmentContext context{document, parseResult, options, fragmentEndPosition};
|
||||
return Luau::tryFragmentAutocomplete(this->frontend, "MainModule", cursorPos, context, nullCallback);
|
||||
return Luau::tryFragmentAutocomplete(this->getFrontend(), "MainModule", cursorPos, context, nullCallback);
|
||||
}
|
||||
|
||||
void autocompleteFragmentInNewSolver(
|
||||
|
@ -211,7 +211,7 @@ struct FragmentAutocompleteFixtureImpl : BaseType
|
|||
)
|
||||
{
|
||||
ParseResult pr = parseHelper(document);
|
||||
return Luau::typecheckFragment(this->frontend, module, cursorPos, getOptions(), document, fragmentEndPosition, pr.root);
|
||||
return Luau::typecheckFragment(this->getFrontend(), module, cursorPos, getOptions(), document, fragmentEndPosition, pr.root);
|
||||
}
|
||||
|
||||
FragmentAutocompleteStatusResult autocompleteFragmentForModule(
|
||||
|
@ -226,7 +226,7 @@ struct FragmentAutocompleteFixtureImpl : BaseType
|
|||
ParseResult parseResult = parseHelper(document);
|
||||
FrontendOptions options;
|
||||
FragmentContext context{document, parseResult, options, fragmentEndPosition};
|
||||
return Luau::tryFragmentAutocomplete(this->frontend, module, cursorPos, context, nullCallback);
|
||||
return Luau::tryFragmentAutocomplete(this->getFrontend(). module, cursorPos, context, nullCallback);
|
||||
}
|
||||
|
||||
SourceModule& getSource()
|
||||
|
@ -244,10 +244,10 @@ struct FragmentAutocompleteFixture : FragmentAutocompleteFixtureImpl<Fixture>
|
|||
FragmentAutocompleteFixture()
|
||||
: FragmentAutocompleteFixtureImpl<Fixture>()
|
||||
{
|
||||
addGlobalBinding(frontend.globals, "table", Binding{builtinTypes->anyType});
|
||||
addGlobalBinding(frontend.globals, "math", Binding{builtinTypes->anyType});
|
||||
addGlobalBinding(frontend.globalsForAutocomplete, "table", Binding{builtinTypes->anyType});
|
||||
addGlobalBinding(frontend.globalsForAutocomplete, "math", Binding{builtinTypes->anyType});
|
||||
addGlobalBinding(getFrontend().globals, "table", Binding{getBuiltins()->anyType});
|
||||
addGlobalBinding(getFrontend().globals, "math", Binding{getBuiltins()->anyType});
|
||||
addGlobalBinding(getFrontend().globalsForAutocomplete, "table", Binding{getBuiltins()->anyType});
|
||||
addGlobalBinding(getFrontend().globalsForAutocomplete, "math", Binding{getBuiltins()->anyType});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -272,8 +272,8 @@ end
|
|||
loadDefinition(fakeVecDecl);
|
||||
loadDefinition(fakeVecDecl, /* For Autocomplete Module */ true);
|
||||
|
||||
addGlobalBinding(frontend.globals, "game", Binding{builtinTypes->anyType});
|
||||
addGlobalBinding(frontend.globalsForAutocomplete, "game", Binding{builtinTypes->anyType});
|
||||
addGlobalBinding(getFrontend().globals, "game", Binding{getBuiltins()->anyType});
|
||||
addGlobalBinding(getFrontend().globalsForAutocomplete, "game", Binding{getBuiltins()->anyType});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1317,7 +1317,7 @@ abc("bar")
|
|||
CHECK_EQ(Position{3, 1}, parent->location.end);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "respects_frontend_options")
|
||||
TEST_CASE_FIXTURE(FragmentAutocompleteFixture, "respects_getFrontend().options")
|
||||
{
|
||||
DOES_NOT_PASS_NEW_SOLVER_GUARD();
|
||||
|
||||
|
@ -1330,21 +1330,21 @@ t
|
|||
FrontendOptions opts;
|
||||
opts.forAutocomplete = true;
|
||||
|
||||
frontend.check("game/A", opts);
|
||||
CHECK_NE(frontend.moduleResolverForAutocomplete.getModule("game/A"), nullptr);
|
||||
CHECK_EQ(frontend.moduleResolver.getModule("game/A"), nullptr);
|
||||
getFrontend().check("game/A", opts);
|
||||
CHECK_NE(getFrontend().moduleResolverForAutocomplete.getModule("game/A"), nullptr);
|
||||
CHECK_EQ(getFrontend().moduleResolver.getModule("game/A"), nullptr);
|
||||
ParseOptions parseOptions;
|
||||
parseOptions.captureComments = true;
|
||||
SourceModule sourceMod;
|
||||
ParseResult parseResult = Parser::parse(source.c_str(), source.length(), *sourceMod.names, *sourceMod.allocator, parseOptions);
|
||||
FragmentContext context{source, parseResult, opts, std::nullopt};
|
||||
|
||||
FragmentAutocompleteStatusResult frag = Luau::tryFragmentAutocomplete(frontend, "game/A", Position{2, 1}, context, nullCallback);
|
||||
FragmentAutocompleteStatusResult frag = Luau::tryFragmentAutocomplete(getFrontend(), "game/A", Position{2, 1}, context, nullCallback);
|
||||
REQUIRE(frag.result);
|
||||
REQUIRE(frag.result->incrementalModule);
|
||||
CHECK_EQ("game/A", frag.result->incrementalModule->name);
|
||||
CHECK_NE(frontend.moduleResolverForAutocomplete.getModule("game/A"), nullptr);
|
||||
CHECK_EQ(frontend.moduleResolver.getModule("game/A"), nullptr);
|
||||
CHECK_NE(getFrontend().moduleResolverForAutocomplete.getModule("game/A"), nullptr);
|
||||
CHECK_EQ(getFrontend().moduleResolver.getModule("game/A"), nullptr);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
@ -1496,16 +1496,16 @@ return { hello = B }
|
|||
const std::string sourceB = "game/Gui/Modules/B";
|
||||
fileResolver.source[sourceB] = R"(return {hello = "hello"})";
|
||||
|
||||
CheckResult result = frontend.check(sourceA, getOptions());
|
||||
CHECK(!frontend.isDirty(sourceA, getOptions().forAutocomplete));
|
||||
CheckResult result = getFrontend().check(sourceA, getOptions());
|
||||
CHECK(!getFrontend().isDirty(sourceA, getOptions().forAutocomplete));
|
||||
|
||||
std::weak_ptr<Module> weakModule = getModuleResolver(frontend).getModule(sourceB);
|
||||
std::weak_ptr<Module> weakModule = getModuleResolver(getFrontend()).getModule(sourceB);
|
||||
REQUIRE(!weakModule.expired());
|
||||
|
||||
frontend.markDirty(sourceB);
|
||||
CHECK(frontend.isDirty(sourceA, getOptions().forAutocomplete));
|
||||
getFrontend().markDirty(sourceB);
|
||||
CHECK(getFrontend().isDirty(sourceA, getOptions().forAutocomplete));
|
||||
|
||||
frontend.check(sourceB, getOptions());
|
||||
getFrontend().check(sourceB, getOptions());
|
||||
CHECK(weakModule.expired());
|
||||
|
||||
auto [status, _] = typecheckFragmentForModule(sourceA, fileResolver.source[sourceA], Luau::Position(0, 0));
|
||||
|
|
|
@ -17,7 +17,7 @@ LUAU_FASTFLAG(LuauSolverV2);
|
|||
LUAU_FASTFLAG(DebugLuauFreezeArena)
|
||||
LUAU_FASTFLAG(DebugLuauMagicTypes)
|
||||
LUAU_FASTFLAG(LuauNewNonStrictVisitTypes2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -59,8 +59,8 @@ struct FrontendFixture : BuiltinsFixture
|
|||
{
|
||||
FrontendFixture()
|
||||
{
|
||||
addGlobalBinding(frontend.globals, "game", builtinTypes->anyType, "@test");
|
||||
addGlobalBinding(frontend.globals, "script", builtinTypes->anyType, "@test");
|
||||
addGlobalBinding(getFrontend().globals, "game", getBuiltins()->anyType, "@test");
|
||||
addGlobalBinding(getFrontend().globals, "script", getBuiltins()->anyType, "@test");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -128,9 +128,9 @@ TEST_CASE_FIXTURE(FrontendFixture, "automatically_check_dependent_scripts")
|
|||
return {b_value = A.hello}
|
||||
)";
|
||||
|
||||
frontend.check("game/Gui/Modules/B");
|
||||
getFrontend().check("game/Gui/Modules/B");
|
||||
|
||||
ModulePtr bModule = frontend.moduleResolver.getModule("game/Gui/Modules/B");
|
||||
ModulePtr bModule = getFrontend().moduleResolver.getModule("game/Gui/Modules/B");
|
||||
REQUIRE(bModule != nullptr);
|
||||
CHECK(bModule->errors.empty());
|
||||
Luau::dumpErrors(bModule);
|
||||
|
@ -169,7 +169,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "automatically_check_cyclically_dependent_scr
|
|||
return {}
|
||||
)";
|
||||
|
||||
CheckResult result1 = frontend.check("game/Gui/Modules/B");
|
||||
CheckResult result1 = getFrontend().check("game/Gui/Modules/B");
|
||||
LUAU_REQUIRE_ERROR_COUNT(4, result1);
|
||||
|
||||
CHECK_MESSAGE(get<ModuleHasCyclicDependency>(result1.errors[0]), "Should have been a ModuleHasCyclicDependency: " << toString(result1.errors[0]));
|
||||
|
@ -178,7 +178,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "automatically_check_cyclically_dependent_scr
|
|||
|
||||
CHECK_MESSAGE(get<ModuleHasCyclicDependency>(result1.errors[2]), "Should have been a ModuleHasCyclicDependency: " << toString(result1.errors[2]));
|
||||
|
||||
CheckResult result2 = frontend.check("game/Gui/Modules/D");
|
||||
CheckResult result2 = getFrontend().check("game/Gui/Modules/D");
|
||||
LUAU_REQUIRE_ERROR_COUNT(0, result2);
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "any_annotation_breaks_cycle")
|
|||
return {hello = A.hello}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("game/Gui/Modules/A");
|
||||
CheckResult result = getFrontend().check("game/Gui/Modules/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
|
@ -218,16 +218,16 @@ TEST_CASE_FIXTURE(FrontendFixture, "nocheck_modules_are_typed")
|
|||
local five : A.Foo = 5
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("game/Gui/Modules/C");
|
||||
CheckResult result = getFrontend().check("game/Gui/Modules/C");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
ModulePtr aModule = frontend.moduleResolver.getModule("game/Gui/Modules/A");
|
||||
ModulePtr aModule = getFrontend().moduleResolver.getModule("game/Gui/Modules/A");
|
||||
REQUIRE(bool(aModule));
|
||||
|
||||
std::optional<TypeId> aExports = first(aModule->returnType);
|
||||
REQUIRE(bool(aExports));
|
||||
|
||||
ModulePtr bModule = frontend.moduleResolver.getModule("game/Gui/Modules/B");
|
||||
ModulePtr bModule = getFrontend().moduleResolver.getModule("game/Gui/Modules/B");
|
||||
REQUIRE(bool(bModule));
|
||||
|
||||
std::optional<TypeId> bExports = first(bModule->returnType);
|
||||
|
@ -250,7 +250,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_detection_between_check_and_nocheck")
|
|||
return {hello = A.hello}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("game/Gui/Modules/A");
|
||||
CheckResult result = getFrontend().check("game/Gui/Modules/A");
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
}
|
||||
|
||||
|
@ -276,10 +276,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "nocheck_cycle_used_by_checked")
|
|||
return {a=A, b=B}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("game/Gui/Modules/C");
|
||||
CheckResult result = getFrontend().check("game/Gui/Modules/C");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
ModulePtr cModule = frontend.moduleResolver.getModule("game/Gui/Modules/C");
|
||||
ModulePtr cModule = getFrontend().moduleResolver.getModule("game/Gui/Modules/C");
|
||||
REQUIRE(bool(cModule));
|
||||
|
||||
std::optional<TypeId> cExports = first(cModule->returnType);
|
||||
|
@ -306,7 +306,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_detection_disabled_in_nocheck")
|
|||
return {hello = A.hello}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("game/Gui/Modules/A");
|
||||
CheckResult result = getFrontend().check("game/Gui/Modules/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
|
@ -323,7 +323,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_errors_can_be_fixed")
|
|||
return {hello = A.hello}
|
||||
)";
|
||||
|
||||
CheckResult result1 = frontend.check("game/Gui/Modules/A");
|
||||
CheckResult result1 = getFrontend().check("game/Gui/Modules/A");
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result1);
|
||||
|
||||
CHECK_MESSAGE(get<ModuleHasCyclicDependency>(result1.errors[0]), "Should have been a ModuleHasCyclicDependency: " << toString(result1.errors[0]));
|
||||
|
@ -333,9 +333,9 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_errors_can_be_fixed")
|
|||
fileResolver.source["game/Gui/Modules/B"] = R"(
|
||||
return {hello = 42}
|
||||
)";
|
||||
frontend.markDirty("game/Gui/Modules/B");
|
||||
getFrontend().markDirty("game/Gui/Modules/B");
|
||||
|
||||
CheckResult result2 = frontend.check("game/Gui/Modules/A");
|
||||
CheckResult result2 = getFrontend().check("game/Gui/Modules/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(result2);
|
||||
}
|
||||
|
||||
|
@ -352,7 +352,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_error_paths")
|
|||
return {hello = A.hello}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("game/Gui/Modules/A");
|
||||
CheckResult result = getFrontend().check("game/Gui/Modules/A");
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
|
||||
auto ce1 = get<ModuleHasCyclicDependency>(result.errors[0]);
|
||||
|
@ -376,16 +376,16 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_incremental_type_surface")
|
|||
return {hello = 2}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("game/A");
|
||||
CheckResult result = getFrontend().check("game/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
fileResolver.source["game/A"] = R"(
|
||||
local me = require(game.A)
|
||||
return {hello = 2}
|
||||
)";
|
||||
frontend.markDirty("game/A");
|
||||
getFrontend().markDirty("game/A");
|
||||
|
||||
result = frontend.check("game/A");
|
||||
result = getFrontend().check("game/A");
|
||||
LUAU_REQUIRE_ERRORS(result);
|
||||
|
||||
auto ty = requireType("game/A", "me");
|
||||
|
@ -398,7 +398,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_incremental_type_surface_longer")
|
|||
return {mod_a = 2}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("game/A");
|
||||
CheckResult result = getFrontend().check("game/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
fileResolver.source["game/B"] = R"(
|
||||
|
@ -406,7 +406,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_incremental_type_surface_longer")
|
|||
return {mod_b = 4}
|
||||
)";
|
||||
|
||||
result = frontend.check("game/B");
|
||||
result = getFrontend().check("game/B");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
fileResolver.source["game/A"] = R"(
|
||||
|
@ -414,16 +414,16 @@ TEST_CASE_FIXTURE(FrontendFixture, "cycle_incremental_type_surface_longer")
|
|||
return {mod_a_prime = 3}
|
||||
)";
|
||||
|
||||
frontend.markDirty("game/A");
|
||||
frontend.markDirty("game/B");
|
||||
getFrontend().markDirty("game/A");
|
||||
getFrontend().markDirty("game/B");
|
||||
|
||||
result = frontend.check("game/A");
|
||||
result = getFrontend().check("game/A");
|
||||
LUAU_REQUIRE_ERRORS(result);
|
||||
|
||||
TypeId tyA = requireType("game/A", "me");
|
||||
CHECK_EQ(toString(tyA), "any");
|
||||
|
||||
result = frontend.check("game/B");
|
||||
result = getFrontend().check("game/B");
|
||||
LUAU_REQUIRE_ERRORS(result);
|
||||
|
||||
TypeId tyB = requireType("game/B", "me");
|
||||
|
@ -452,10 +452,10 @@ return {mod_b = 2}
|
|||
ToStringOptions opts;
|
||||
opts.exhaustive = true;
|
||||
|
||||
CheckResult resultA = frontend.check("game/A");
|
||||
CheckResult resultA = getFrontend().check("game/A");
|
||||
LUAU_REQUIRE_ERRORS(resultA);
|
||||
|
||||
CheckResult resultB = frontend.check("game/B");
|
||||
CheckResult resultB = getFrontend().check("game/B");
|
||||
LUAU_REQUIRE_ERRORS(resultB);
|
||||
|
||||
TypeId tyB = requireExportedType("game/B", "btype");
|
||||
|
@ -470,8 +470,8 @@ return {mod_b = 2}
|
|||
else
|
||||
CHECK_EQ(toString(tyA, opts), "{| x: any |}");
|
||||
|
||||
frontend.markDirty("game/B");
|
||||
resultB = frontend.check("game/B");
|
||||
getFrontend().markDirty("game/B");
|
||||
resultB = getFrontend().check("game/B");
|
||||
LUAU_REQUIRE_ERRORS(resultB);
|
||||
|
||||
tyB = requireExportedType("game/B", "btype");
|
||||
|
@ -522,14 +522,14 @@ TEST_CASE_FIXTURE(FrontendFixture, "dont_recheck_script_that_hasnt_been_marked_d
|
|||
return {b_value = A.hello}
|
||||
)";
|
||||
|
||||
frontend.check("game/Gui/Modules/B");
|
||||
getFrontend().check("game/Gui/Modules/B");
|
||||
|
||||
fileResolver.source["game/Gui/Modules/A"] =
|
||||
"Massively incorrect syntax haha oops! However! The frontend doesn't know that this file needs reparsing!";
|
||||
"Massively incorrect syntax haha oops! However! The getFrontend().doesn't know that this file needs reparsing!";
|
||||
|
||||
frontend.check("game/Gui/Modules/B");
|
||||
getFrontend().check("game/Gui/Modules/B");
|
||||
|
||||
ModulePtr bModule = frontend.moduleResolver.getModule("game/Gui/Modules/B");
|
||||
ModulePtr bModule = getFrontend().moduleResolver.getModule("game/Gui/Modules/B");
|
||||
CHECK(bModule->errors.empty());
|
||||
Luau::dumpErrors(bModule);
|
||||
}
|
||||
|
@ -543,14 +543,14 @@ TEST_CASE_FIXTURE(FrontendFixture, "recheck_if_dependent_script_is_dirty")
|
|||
return {b_value = A.hello}
|
||||
)";
|
||||
|
||||
frontend.check("game/Gui/Modules/B");
|
||||
getFrontend().check("game/Gui/Modules/B");
|
||||
|
||||
fileResolver.source["game/Gui/Modules/A"] = "return {hello='hi!'}";
|
||||
frontend.markDirty("game/Gui/Modules/A");
|
||||
getFrontend().markDirty("game/Gui/Modules/A");
|
||||
|
||||
frontend.check("game/Gui/Modules/B");
|
||||
getFrontend().check("game/Gui/Modules/B");
|
||||
|
||||
ModulePtr bModule = frontend.moduleResolver.getModule("game/Gui/Modules/B");
|
||||
ModulePtr bModule = getFrontend().moduleResolver.getModule("game/Gui/Modules/B");
|
||||
CHECK(bModule->errors.empty());
|
||||
Luau::dumpErrors(bModule);
|
||||
|
||||
|
@ -575,10 +575,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "mark_non_immediate_reverse_deps_as_dirty")
|
|||
return {c_value = B.hello}
|
||||
)";
|
||||
|
||||
frontend.check("game/Gui/Modules/C");
|
||||
getFrontend().check("game/Gui/Modules/C");
|
||||
|
||||
std::vector<Luau::ModuleName> markedDirty;
|
||||
frontend.markDirty("game/Gui/Modules/A", &markedDirty);
|
||||
getFrontend().markDirty("game/Gui/Modules/A", &markedDirty);
|
||||
|
||||
REQUIRE(markedDirty.size() == 3);
|
||||
CHECK(std::find(markedDirty.begin(), markedDirty.end(), "game/Gui/Modules/A") != markedDirty.end());
|
||||
|
@ -597,11 +597,11 @@ TEST_CASE_FIXTURE(FrontendFixture, "recheck_if_dependent_script_has_a_parse_erro
|
|||
return {}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Modules/B");
|
||||
CheckResult result = getFrontend().check("Modules/B");
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK_EQ("Modules/A", result.errors[0].moduleName);
|
||||
|
||||
CheckResult result2 = frontend.check("Modules/B");
|
||||
CheckResult result2 = getFrontend().check("Modules/B");
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result2);
|
||||
CHECK_EQ(result2.errors[0], result.errors[0]);
|
||||
}
|
||||
|
@ -611,8 +611,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "produce_errors_for_unchanged_file_with_a_syn
|
|||
{
|
||||
fileResolver.source["Modules/A"] = "oh no a blatant syntax error!!";
|
||||
|
||||
CheckResult one = frontend.check("Modules/A");
|
||||
CheckResult two = frontend.check("Modules/A");
|
||||
CheckResult one = getFrontend().check("Modules/A");
|
||||
CheckResult two = getFrontend().check("Modules/A");
|
||||
|
||||
CHECK(!one.errors.empty());
|
||||
CHECK(!two.errors.empty());
|
||||
|
@ -622,10 +622,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "produce_errors_for_unchanged_file_with_error
|
|||
{
|
||||
fileResolver.source["Modules/A"] = "local p: number = 'oh no a type error'";
|
||||
|
||||
frontend.check("Modules/A");
|
||||
getFrontend().check("Modules/A");
|
||||
|
||||
fileResolver.source["Modules/A"] = "local p = 4 -- We have fixed the problem, but we didn't tell the frontend, so it will not recheck this file!";
|
||||
CheckResult secondResult = frontend.check("Modules/A");
|
||||
fileResolver.source["Modules/A"] = "local p = 4 -- We have fixed the problem, but we didn't tell the getFrontend(). so it will not recheck this file!";
|
||||
CheckResult secondResult = getFrontend().check("Modules/A");
|
||||
|
||||
CHECK_EQ(1, secondResult.errors.size());
|
||||
}
|
||||
|
@ -643,7 +643,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "reports_errors_from_multiple_sources")
|
|||
local b: number = 'another one! This is quite distressing!'
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("game/Gui/Modules/B");
|
||||
CheckResult result = getFrontend().check("game/Gui/Modules/B");
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
|
||||
CHECK_EQ("game/Gui/Modules/A", result.errors[0].moduleName);
|
||||
|
@ -657,7 +657,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "report_require_to_nonexistent_file")
|
|||
local B = require(Modules.B)
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Modules/A");
|
||||
CheckResult result = getFrontend().check("Modules/A");
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
std::string s = toString(result.errors[0]);
|
||||
|
@ -671,7 +671,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "ignore_require_to_nonexistent_file")
|
|||
local B = require(Modules.B) :: any
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Modules/A");
|
||||
CheckResult result = getFrontend().check("Modules/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
|
@ -683,7 +683,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "report_syntax_error_in_required_file")
|
|||
local A = require(Modules.A)
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Modules/B");
|
||||
CheckResult result = getFrontend().check("Modules/B");
|
||||
LUAU_REQUIRE_ERRORS(result);
|
||||
|
||||
CHECK_EQ("Modules/A", result.errors[0].moduleName);
|
||||
|
@ -716,10 +716,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "re_report_type_error_in_required_file")
|
|||
print(A.n)
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Modules/B");
|
||||
CheckResult result = getFrontend().check("Modules/B");
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
CheckResult result2 = frontend.check("Modules/B");
|
||||
CheckResult result2 = getFrontend().check("Modules/B");
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result2);
|
||||
|
||||
CHECK_EQ("Modules/A", result.errors[0].moduleName);
|
||||
|
@ -739,14 +739,14 @@ TEST_CASE_FIXTURE(FrontendFixture, "accumulate_cached_errors")
|
|||
print(A, b)
|
||||
)";
|
||||
|
||||
CheckResult result1 = frontend.check("Modules/B");
|
||||
CheckResult result1 = getFrontend().check("Modules/B");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result1);
|
||||
|
||||
CHECK_EQ("Modules/A", result1.errors[0].moduleName);
|
||||
CHECK_EQ("Modules/B", result1.errors[1].moduleName);
|
||||
|
||||
CheckResult result2 = frontend.check("Modules/B");
|
||||
CheckResult result2 = getFrontend().check("Modules/B");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result2);
|
||||
|
||||
|
@ -769,7 +769,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "accumulate_cached_errors_in_consistent_order
|
|||
return {}
|
||||
)";
|
||||
|
||||
CheckResult result1 = frontend.check("Modules/A");
|
||||
CheckResult result1 = getFrontend().check("Modules/A");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(4, result1);
|
||||
|
||||
|
@ -779,7 +779,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "accumulate_cached_errors_in_consistent_order
|
|||
CHECK_EQ("Modules/B", result1.errors[0].moduleName);
|
||||
CHECK_EQ("Modules/B", result1.errors[1].moduleName);
|
||||
|
||||
CheckResult result2 = frontend.check("Modules/A");
|
||||
CheckResult result2 = getFrontend().check("Modules/A");
|
||||
CHECK_EQ(4, result2.errors.size());
|
||||
|
||||
for (size_t i = 0; i < result1.errors.size(); ++i)
|
||||
|
@ -817,7 +817,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_lint_uses_correct_config")
|
|||
CHECK_EQ(1, result.warnings.size());
|
||||
|
||||
configResolver.configFiles["Module/A"].enabledLint.disableWarning(LintWarning::Code_ForRange);
|
||||
frontend.markDirty("Module/A");
|
||||
getFrontend().markDirty("Module/A");
|
||||
|
||||
auto result2 = lintModule("Module/A");
|
||||
CHECK_EQ(0, result2.warnings.size());
|
||||
|
@ -825,13 +825,13 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_lint_uses_correct_config")
|
|||
LintOptions overrideOptions;
|
||||
|
||||
overrideOptions.enableWarning(LintWarning::Code_ForRange);
|
||||
frontend.markDirty("Module/A");
|
||||
getFrontend().markDirty("Module/A");
|
||||
|
||||
auto result3 = lintModule("Module/A", overrideOptions);
|
||||
CHECK_EQ(1, result3.warnings.size());
|
||||
|
||||
overrideOptions.disableWarning(LintWarning::Code_ForRange);
|
||||
frontend.markDirty("Module/A");
|
||||
getFrontend().markDirty("Module/A");
|
||||
|
||||
auto result4 = lintModule("Module/A", overrideOptions);
|
||||
CHECK_EQ(0, result4.warnings.size());
|
||||
|
@ -877,7 +877,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "discard_type_graphs")
|
|||
|
||||
TEST_CASE_FIXTURE(FrontendFixture, "it_should_be_safe_to_stringify_errors_when_full_type_graph_is_discarded")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
Frontend fe{&fileResolver, &configResolver, {false}};
|
||||
|
||||
|
@ -932,7 +932,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "trace_requires_in_nonstrict_mode")
|
|||
print(A.f(5)) -- OK
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Module/B");
|
||||
CheckResult result = getFrontend().check("Module/B");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
|
||||
|
@ -942,11 +942,11 @@ TEST_CASE_FIXTURE(FrontendFixture, "trace_requires_in_nonstrict_mode")
|
|||
|
||||
TEST_CASE_FIXTURE(FrontendFixture, "environments")
|
||||
{
|
||||
ScopePtr testScope = frontend.addEnvironment("test");
|
||||
ScopePtr testScope = getFrontend().addEnvironment("test");
|
||||
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
frontend.loadDefinitionFile(
|
||||
frontend.globals,
|
||||
unfreeze(getFrontend().globals.globalTypes);
|
||||
getFrontend().loadDefinitionFile(
|
||||
getFrontend().globals,
|
||||
testScope,
|
||||
R"(
|
||||
export type Foo = number | string
|
||||
|
@ -954,7 +954,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "environments")
|
|||
"@test",
|
||||
/* captureComments */ false
|
||||
);
|
||||
freeze(frontend.globals.globalTypes);
|
||||
freeze(getFrontend().globals.globalTypes);
|
||||
|
||||
fileResolver.source["A"] = R"(
|
||||
--!nonstrict
|
||||
|
@ -973,16 +973,16 @@ TEST_CASE_FIXTURE(FrontendFixture, "environments")
|
|||
|
||||
fileResolver.environments["A"] = "test";
|
||||
|
||||
CheckResult resultA = frontend.check("A");
|
||||
CheckResult resultA = getFrontend().check("A");
|
||||
LUAU_REQUIRE_NO_ERRORS(resultA);
|
||||
|
||||
CheckResult resultB = frontend.check("B");
|
||||
CheckResult resultB = getFrontend().check("B");
|
||||
if (FFlag::LuauSolverV2 && !FFlag::LuauNewNonStrictVisitTypes2)
|
||||
LUAU_REQUIRE_NO_ERRORS(resultB);
|
||||
else
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, resultB);
|
||||
|
||||
CheckResult resultC = frontend.check("C");
|
||||
CheckResult resultC = getFrontend().check("C");
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, resultC);
|
||||
}
|
||||
|
||||
|
@ -1021,18 +1021,18 @@ TEST_CASE_FIXTURE(FrontendFixture, "stats_are_not_reset_between_checks")
|
|||
return {foo = 1}
|
||||
)";
|
||||
|
||||
CheckResult r1 = frontend.check("Module/A");
|
||||
CheckResult r1 = getFrontend().check("Module/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(r1);
|
||||
|
||||
Frontend::Stats stats1 = frontend.stats;
|
||||
Frontend::Stats stats1 = getFrontend().stats;
|
||||
CHECK_EQ(2, stats1.files);
|
||||
|
||||
frontend.markDirty("Module/A");
|
||||
frontend.markDirty("Module/B");
|
||||
getFrontend().markDirty("Module/A");
|
||||
getFrontend().markDirty("Module/B");
|
||||
|
||||
CheckResult r2 = frontend.check("Module/A");
|
||||
CheckResult r2 = getFrontend().check("Module/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(r2);
|
||||
Frontend::Stats stats2 = frontend.stats;
|
||||
Frontend::Stats stats2 = getFrontend().stats;
|
||||
|
||||
CHECK_EQ(4, stats2.files);
|
||||
}
|
||||
|
@ -1050,19 +1050,19 @@ TEST_CASE_FIXTURE(FrontendFixture, "clearStats")
|
|||
return {foo = 1}
|
||||
)";
|
||||
|
||||
CheckResult r1 = frontend.check("Module/A");
|
||||
CheckResult r1 = getFrontend().check("Module/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(r1);
|
||||
|
||||
Frontend::Stats stats1 = frontend.stats;
|
||||
Frontend::Stats stats1 = getFrontend().stats;
|
||||
CHECK_EQ(2, stats1.files);
|
||||
|
||||
frontend.markDirty("Module/A");
|
||||
frontend.markDirty("Module/B");
|
||||
getFrontend().markDirty("Module/A");
|
||||
getFrontend().markDirty("Module/B");
|
||||
|
||||
frontend.clearStats();
|
||||
CheckResult r2 = frontend.check("Module/A");
|
||||
getFrontend().clearStats();
|
||||
CheckResult r2 = getFrontend().check("Module/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(r2);
|
||||
Frontend::Stats stats2 = frontend.stats;
|
||||
Frontend::Stats stats2 = getFrontend().stats;
|
||||
|
||||
CHECK_EQ(2, stats2.files);
|
||||
}
|
||||
|
@ -1073,9 +1073,9 @@ TEST_CASE_FIXTURE(FrontendFixture, "typecheck_twice_for_ast_types")
|
|||
local a = 1
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Module/A");
|
||||
CheckResult result = getFrontend().check("Module/A");
|
||||
|
||||
ModulePtr module = frontend.moduleResolver.getModule("Module/A");
|
||||
ModulePtr module = getFrontend().moduleResolver.getModule("Module/A");
|
||||
|
||||
REQUIRE_EQ(module->astTypes.size(), 1);
|
||||
auto it = module->astTypes.begin();
|
||||
|
@ -1088,7 +1088,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "imported_table_modification_2")
|
|||
if (FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
frontend.options.retainFullTypeGraphs = false;
|
||||
getFrontend().options.retainFullTypeGraphs = false;
|
||||
|
||||
fileResolver.source["Module/A"] = R"(
|
||||
--!nonstrict
|
||||
|
@ -1112,13 +1112,13 @@ local b = require(script.Parent.B)
|
|||
a:b() -- this should error, since A doesn't define a:b()
|
||||
)";
|
||||
|
||||
CheckResult resultA = frontend.check("Module/A");
|
||||
CheckResult resultA = getFrontend().check("Module/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(resultA);
|
||||
|
||||
CheckResult resultB = frontend.check("Module/B");
|
||||
CheckResult resultB = getFrontend().check("Module/B");
|
||||
LUAU_REQUIRE_ERRORS(resultB);
|
||||
|
||||
CheckResult resultC = frontend.check("Module/C");
|
||||
CheckResult resultC = getFrontend().check("Module/C");
|
||||
LUAU_REQUIRE_ERRORS(resultC);
|
||||
}
|
||||
|
||||
|
@ -1143,7 +1143,7 @@ return false;
|
|||
)";
|
||||
|
||||
// We don't care about the result. That we haven't crashed is enough.
|
||||
fix.frontend.check("Module/B");
|
||||
fix.getFrontend().check("Module/B");
|
||||
}
|
||||
|
||||
TEST_CASE("check_without_builtin_next")
|
||||
|
@ -1151,7 +1151,6 @@ TEST_CASE("check_without_builtin_next")
|
|||
TestFileResolver fileResolver;
|
||||
TestConfigResolver configResolver;
|
||||
Frontend frontend(&fileResolver, &configResolver);
|
||||
|
||||
fileResolver.source["Module/A"] = "for k,v in 2 do end";
|
||||
fileResolver.source["Module/B"] = "return next";
|
||||
|
||||
|
@ -1186,7 +1185,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "reexport_cyclic_type")
|
|||
}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Module/B");
|
||||
CheckResult result = getFrontend().check("Module/B");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
@ -1212,23 +1211,23 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "reexport_type_alias")
|
|||
export type TestFileEvent = A.TestFileEvent
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Module/B");
|
||||
CheckResult result = getFrontend().check("Module/B");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "module_scope_check")
|
||||
{
|
||||
frontend.prepareModuleScope = [this](const ModuleName& name, const ScopePtr& scope, bool forAutocomplete)
|
||||
getFrontend().prepareModuleScope = [this](const ModuleName& name, const ScopePtr& scope, bool forAutocomplete)
|
||||
{
|
||||
scope->bindings[Luau::AstName{"x"}] = Luau::Binding{frontend.globals.builtinTypes->numberType};
|
||||
scope->bindings[Luau::AstName{"x"}] = Luau::Binding{getFrontend().globals.builtinTypes->numberType};
|
||||
};
|
||||
|
||||
fileResolver.source["game/A"] = R"(
|
||||
local a = x
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("game/A");
|
||||
CheckResult result = getFrontend().check("game/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
auto ty = requireType("game/A", "a");
|
||||
|
@ -1248,18 +1247,18 @@ TEST_CASE_FIXTURE(FrontendFixture, "parse_only")
|
|||
local b: number = 2
|
||||
)";
|
||||
|
||||
frontend.parse("game/Gui/Modules/B");
|
||||
getFrontend().parse("game/Gui/Modules/B");
|
||||
|
||||
REQUIRE(frontend.sourceNodes.count("game/Gui/Modules/A"));
|
||||
REQUIRE(frontend.sourceNodes.count("game/Gui/Modules/B"));
|
||||
REQUIRE(getFrontend().sourceNodes.count("game/Gui/Modules/A"));
|
||||
REQUIRE(getFrontend().sourceNodes.count("game/Gui/Modules/B"));
|
||||
|
||||
auto node = frontend.sourceNodes["game/Gui/Modules/B"];
|
||||
auto node = getFrontend().sourceNodes["game/Gui/Modules/B"];
|
||||
CHECK(node->requireSet.contains("game/Gui/Modules/A"));
|
||||
REQUIRE_EQ(node->requireLocations.size(), 1);
|
||||
CHECK_EQ(node->requireLocations[0].second, Luau::Location(Position(2, 18), Position(2, 36)));
|
||||
|
||||
// Early parse doesn't cause typechecking to be skipped
|
||||
CheckResult result = frontend.check("game/Gui/Modules/B");
|
||||
CheckResult result = getFrontend().check("game/Gui/Modules/B");
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
CHECK_EQ("game/Gui/Modules/A", result.errors[0].moduleName);
|
||||
|
@ -1275,15 +1274,15 @@ TEST_CASE_FIXTURE(FrontendFixture, "markdirty_early_return")
|
|||
|
||||
{
|
||||
std::vector<ModuleName> markedDirty;
|
||||
frontend.markDirty(moduleName, &markedDirty);
|
||||
getFrontend().markDirty(moduleName, &markedDirty);
|
||||
CHECK(markedDirty.empty());
|
||||
}
|
||||
|
||||
frontend.parse(moduleName);
|
||||
getFrontend().parse(moduleName);
|
||||
|
||||
{
|
||||
std::vector<ModuleName> markedDirty;
|
||||
frontend.markDirty(moduleName, &markedDirty);
|
||||
getFrontend().markDirty(moduleName, &markedDirty);
|
||||
CHECK(!markedDirty.empty());
|
||||
}
|
||||
}
|
||||
|
@ -1302,7 +1301,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "attribute_ices_to_the_correct_module")
|
|||
|
||||
try
|
||||
{
|
||||
frontend.check("game/one");
|
||||
getFrontend().check("game/one");
|
||||
}
|
||||
catch (InternalCompilerError& err)
|
||||
{
|
||||
|
@ -1330,19 +1329,19 @@ TEST_CASE_FIXTURE(FrontendFixture, "checked_modules_have_the_correct_mode")
|
|||
local a = 10
|
||||
)";
|
||||
|
||||
frontend.check("game/A");
|
||||
frontend.check("game/B");
|
||||
frontend.check("game/C");
|
||||
getFrontend().check("game/A");
|
||||
getFrontend().check("game/B");
|
||||
getFrontend().check("game/C");
|
||||
|
||||
ModulePtr moduleA = frontend.moduleResolver.getModule("game/A");
|
||||
ModulePtr moduleA = getFrontend().moduleResolver.getModule("game/A");
|
||||
REQUIRE(moduleA);
|
||||
CHECK(moduleA->mode == Mode::NoCheck);
|
||||
|
||||
ModulePtr moduleB = frontend.moduleResolver.getModule("game/B");
|
||||
ModulePtr moduleB = getFrontend().moduleResolver.getModule("game/B");
|
||||
REQUIRE(moduleB);
|
||||
CHECK(moduleB->mode == Mode::Nonstrict);
|
||||
|
||||
ModulePtr moduleC = frontend.moduleResolver.getModule("game/C");
|
||||
ModulePtr moduleC = getFrontend().moduleResolver.getModule("game/C");
|
||||
REQUIRE(moduleC);
|
||||
CHECK(moduleC->mode == Mode::Strict);
|
||||
}
|
||||
|
@ -1361,17 +1360,17 @@ TEST_CASE_FIXTURE(FrontendFixture, "separate_caches_for_autocomplete")
|
|||
FrontendOptions opts;
|
||||
opts.forAutocomplete = true;
|
||||
|
||||
frontend.check("game/A", opts);
|
||||
getFrontend().check("game/A", opts);
|
||||
|
||||
CHECK(nullptr == frontend.moduleResolver.getModule("game/A"));
|
||||
CHECK(nullptr == getFrontend().moduleResolver.getModule("game/A"));
|
||||
|
||||
ModulePtr acModule = frontend.moduleResolverForAutocomplete.getModule("game/A");
|
||||
ModulePtr acModule = getFrontend().moduleResolverForAutocomplete.getModule("game/A");
|
||||
REQUIRE(acModule != nullptr);
|
||||
CHECK(acModule->mode == Mode::Strict);
|
||||
|
||||
frontend.check("game/A");
|
||||
getFrontend().check("game/A");
|
||||
|
||||
ModulePtr module = frontend.moduleResolver.getModule("game/A");
|
||||
ModulePtr module = getFrontend().moduleResolver.getModule("game/A");
|
||||
|
||||
REQUIRE(module != nullptr);
|
||||
CHECK(module->mode == Mode::Nonstrict);
|
||||
|
@ -1391,11 +1390,11 @@ TEST_CASE_FIXTURE(FrontendFixture, "no_separate_caches_with_the_new_solver")
|
|||
FrontendOptions opts;
|
||||
opts.forAutocomplete = true;
|
||||
|
||||
frontend.check("game/A", opts);
|
||||
getFrontend().check("game/A", opts);
|
||||
|
||||
CHECK(nullptr == frontend.moduleResolverForAutocomplete.getModule("game/A"));
|
||||
CHECK(nullptr == getFrontend().moduleResolverForAutocomplete.getModule("game/A"));
|
||||
|
||||
ModulePtr module = frontend.moduleResolver.getModule("game/A");
|
||||
ModulePtr module = getFrontend().moduleResolver.getModule("game/A");
|
||||
|
||||
REQUIRE(module != nullptr);
|
||||
CHECK(module->mode == Mode::Nonstrict);
|
||||
|
@ -1450,15 +1449,15 @@ TEST_CASE_FIXTURE(FrontendFixture, "get_required_scripts")
|
|||
)";
|
||||
|
||||
// isDirty(name) is true, getRequiredScripts should not hit the cache.
|
||||
frontend.markDirty("game/workspace/MyScript");
|
||||
std::vector<ModuleName> requiredScripts = frontend.getRequiredScripts("game/workspace/MyScript");
|
||||
getFrontend().markDirty("game/workspace/MyScript");
|
||||
std::vector<ModuleName> requiredScripts = getFrontend().getRequiredScripts("game/workspace/MyScript");
|
||||
REQUIRE(requiredScripts.size() == 2);
|
||||
CHECK(requiredScripts[0] == "game/workspace/MyModuleScript");
|
||||
CHECK(requiredScripts[1] == "game/workspace/MyModuleScript2");
|
||||
|
||||
// Call frontend.check first, then getRequiredScripts should hit the cache because isDirty(name) is false.
|
||||
frontend.check("game/workspace/MyScript");
|
||||
requiredScripts = frontend.getRequiredScripts("game/workspace/MyScript");
|
||||
// Call getFrontend().check first, then getRequiredScripts should hit the cache because isDirty(name) is false.
|
||||
getFrontend().check("game/workspace/MyScript");
|
||||
requiredScripts = getFrontend().getRequiredScripts("game/workspace/MyScript");
|
||||
REQUIRE(requiredScripts.size() == 2);
|
||||
CHECK(requiredScripts[0] == "game/workspace/MyModuleScript");
|
||||
CHECK(requiredScripts[1] == "game/workspace/MyModuleScript2");
|
||||
|
@ -1478,8 +1477,8 @@ TEST_CASE_FIXTURE(FrontendFixture, "get_required_scripts_dirty")
|
|||
return module
|
||||
)";
|
||||
|
||||
frontend.check("game/workspace/MyScript");
|
||||
std::vector<ModuleName> requiredScripts = frontend.getRequiredScripts("game/workspace/MyScript");
|
||||
getFrontend().check("game/workspace/MyScript");
|
||||
std::vector<ModuleName> requiredScripts = getFrontend().getRequiredScripts("game/workspace/MyScript");
|
||||
REQUIRE(requiredScripts.size() == 0);
|
||||
|
||||
fileResolver.source["game/workspace/MyScript"] = R"(
|
||||
|
@ -1487,11 +1486,11 @@ TEST_CASE_FIXTURE(FrontendFixture, "get_required_scripts_dirty")
|
|||
MyModuleScript.myPrint()
|
||||
)";
|
||||
|
||||
requiredScripts = frontend.getRequiredScripts("game/workspace/MyScript");
|
||||
requiredScripts = getFrontend().getRequiredScripts("game/workspace/MyScript");
|
||||
REQUIRE(requiredScripts.size() == 0);
|
||||
|
||||
frontend.markDirty("game/workspace/MyScript");
|
||||
requiredScripts = frontend.getRequiredScripts("game/workspace/MyScript");
|
||||
getFrontend().markDirty("game/workspace/MyScript");
|
||||
requiredScripts = getFrontend().getRequiredScripts("game/workspace/MyScript");
|
||||
REQUIRE(requiredScripts.size() == 1);
|
||||
CHECK(requiredScripts[0] == "game/workspace/MyModuleScript");
|
||||
}
|
||||
|
@ -1502,10 +1501,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "check_module_references_allocator")
|
|||
print("Hello World")
|
||||
)";
|
||||
|
||||
frontend.check("game/workspace/MyScript");
|
||||
getFrontend().check("game/workspace/MyScript");
|
||||
|
||||
ModulePtr module = frontend.moduleResolver.getModule("game/workspace/MyScript");
|
||||
SourceModule* source = frontend.getSourceModule("game/workspace/MyScript");
|
||||
ModulePtr module = getFrontend().moduleResolver.getModule("game/workspace/MyScript");
|
||||
SourceModule* source = getFrontend().getSourceModule("game/workspace/MyScript");
|
||||
CHECK(module);
|
||||
CHECK(source);
|
||||
|
||||
|
@ -1519,10 +1518,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "check_module_references_correct_ast_root")
|
|||
print("Hello World")
|
||||
)";
|
||||
|
||||
frontend.check("game/workspace/MyScript");
|
||||
getFrontend().check("game/workspace/MyScript");
|
||||
|
||||
ModulePtr module = frontend.moduleResolver.getModule("game/workspace/MyScript");
|
||||
SourceModule* source = frontend.getSourceModule("game/workspace/MyScript");
|
||||
ModulePtr module = getFrontend().moduleResolver.getModule("game/workspace/MyScript");
|
||||
SourceModule* source = getFrontend().getSourceModule("game/workspace/MyScript");
|
||||
CHECK(module);
|
||||
CHECK(source);
|
||||
|
||||
|
@ -1539,19 +1538,19 @@ local c = 3
|
|||
return {x = a, y = b, z = c}
|
||||
)";
|
||||
|
||||
frontend.options.retainFullTypeGraphs = true;
|
||||
frontend.check("game/A");
|
||||
getFrontend().options.retainFullTypeGraphs = true;
|
||||
getFrontend().check("game/A");
|
||||
|
||||
auto mod = frontend.moduleResolver.getModule("game/A");
|
||||
auto mod = getFrontend().moduleResolver.getModule("game/A");
|
||||
CHECK(!mod->defArena.allocator.empty());
|
||||
CHECK(!mod->keyArena.allocator.empty());
|
||||
|
||||
// We should check that the dfg arena is empty once retainFullTypeGraphs is unset
|
||||
frontend.options.retainFullTypeGraphs = false;
|
||||
frontend.markDirty("game/A");
|
||||
frontend.check("game/A");
|
||||
getFrontend().options.retainFullTypeGraphs = false;
|
||||
getFrontend().markDirty("game/A");
|
||||
getFrontend().check("game/A");
|
||||
|
||||
mod = frontend.moduleResolver.getModule("game/A");
|
||||
mod = getFrontend().moduleResolver.getModule("game/A");
|
||||
CHECK(mod->defArena.allocator.empty());
|
||||
CHECK(mod->keyArena.allocator.empty());
|
||||
}
|
||||
|
@ -1573,10 +1572,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_traverse_dependents")
|
|||
return {d_value = C.c_value}
|
||||
)";
|
||||
|
||||
frontend.check("game/Gui/Modules/D");
|
||||
getFrontend().check("game/Gui/Modules/D");
|
||||
|
||||
std::vector<ModuleName> visited;
|
||||
frontend.traverseDependents(
|
||||
getFrontend().traverseDependents(
|
||||
"game/Gui/Modules/B",
|
||||
[&visited](SourceNode& node)
|
||||
{
|
||||
|
@ -1600,10 +1599,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_traverse_dependents_early_exit")
|
|||
return {c_value = B.hello}
|
||||
)";
|
||||
|
||||
frontend.check("game/Gui/Modules/C");
|
||||
getFrontend().check("game/Gui/Modules/C");
|
||||
|
||||
std::vector<ModuleName> visited;
|
||||
frontend.traverseDependents(
|
||||
getFrontend().traverseDependents(
|
||||
"game/Gui/Modules/A",
|
||||
[&visited](SourceNode& node)
|
||||
{
|
||||
|
@ -1620,19 +1619,19 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_dependents_stored_on_node_as_graph_upda
|
|||
auto updateSource = [&](const std::string& name, const std::string& source)
|
||||
{
|
||||
fileResolver.source[name] = source;
|
||||
frontend.markDirty(name);
|
||||
getFrontend().markDirty(name);
|
||||
};
|
||||
|
||||
auto validateMatchesRequireLists = [&](const std::string& message)
|
||||
{
|
||||
DenseHashMap<ModuleName, std::vector<ModuleName>> dependents{{}};
|
||||
for (const auto& module : frontend.sourceNodes)
|
||||
for (const auto& module : getFrontend().sourceNodes)
|
||||
{
|
||||
for (const auto& dep : module.second->requireSet)
|
||||
dependents[dep].push_back(module.first);
|
||||
}
|
||||
|
||||
for (const auto& module : frontend.sourceNodes)
|
||||
for (const auto& module : getFrontend().sourceNodes)
|
||||
{
|
||||
Set<ModuleName>& dependentsForModule = module.second->dependents;
|
||||
for (const auto& dep : dependents[module.first])
|
||||
|
@ -1642,7 +1641,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_dependents_stored_on_node_as_graph_upda
|
|||
|
||||
auto validateSecondDependsOnFirst = [&](const std::string& from, const std::string& to, bool expected)
|
||||
{
|
||||
SourceNode& fromNode = *frontend.sourceNodes[from];
|
||||
SourceNode& fromNode = *getFrontend().sourceNodes[from];
|
||||
CHECK_MESSAGE(
|
||||
fromNode.dependents.count(to) == int(expected),
|
||||
"Expected " << from << " to " << (expected ? std::string() : std::string("not ")) << "have a reverse dependency on " << to
|
||||
|
@ -1660,7 +1659,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_dependents_stored_on_node_as_graph_upda
|
|||
local B = require(Modules.B)
|
||||
return {c_value = B}
|
||||
)");
|
||||
frontend.check("game/Gui/Modules/C");
|
||||
getFrontend().check("game/Gui/Modules/C");
|
||||
|
||||
validateMatchesRequireLists("Initial check");
|
||||
|
||||
|
@ -1674,7 +1673,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_dependents_stored_on_node_as_graph_upda
|
|||
updateSource("game/Gui/Modules/B", R"(
|
||||
return 1
|
||||
)");
|
||||
frontend.check("game/Gui/Modules/C");
|
||||
getFrontend().check("game/Gui/Modules/C");
|
||||
|
||||
validateMatchesRequireLists("Removing dependency B->A");
|
||||
validateSecondDependsOnFirst("game/Gui/Modules/A", "game/Gui/Modules/B", false);
|
||||
|
@ -1685,7 +1684,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_dependents_stored_on_node_as_graph_upda
|
|||
updateSource("game/Gui/Modules/B", R"(
|
||||
return require(game:GetService('Gui').Modules.A)
|
||||
)");
|
||||
frontend.check("game/Gui/Modules/C");
|
||||
getFrontend().check("game/Gui/Modules/C");
|
||||
|
||||
validateMatchesRequireLists("Adding back B->A");
|
||||
validateSecondDependsOnFirst("game/Gui/Modules/A", "game/Gui/Modules/B", true);
|
||||
|
@ -1699,7 +1698,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_dependents_stored_on_node_as_graph_upda
|
|||
local A = require(game:GetService('Gui').Modules.A)
|
||||
return {d_value = C.c_value}
|
||||
)");
|
||||
frontend.check("game/Gui/Modules/D");
|
||||
getFrontend().check("game/Gui/Modules/D");
|
||||
|
||||
validateMatchesRequireLists("Adding D->C, D->B, D->A");
|
||||
validateSecondDependsOnFirst("game/Gui/Modules/A", "game/Gui/Modules/D", true);
|
||||
|
@ -1711,7 +1710,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_dependents_stored_on_node_as_graph_upda
|
|||
{
|
||||
updateSource("game/Gui/Modules/D", "return require(game:GetService('Gui').Modules.C)");
|
||||
updateSource("game/Gui/Modules/C", "return require(game:GetService('Gui').Modules.D)");
|
||||
frontend.check("game/Gui/Modules/D");
|
||||
getFrontend().check("game/Gui/Modules/D");
|
||||
|
||||
validateMatchesRequireLists("Adding cycle D->C, C->D");
|
||||
validateSecondDependsOnFirst("game/Gui/Modules/C", "game/Gui/Modules/D", true);
|
||||
|
@ -1721,7 +1720,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_dependents_stored_on_node_as_graph_upda
|
|||
// B -> A, C -> D, D -> error
|
||||
{
|
||||
updateSource("game/Gui/Modules/D", "return require(game:GetService('Gui').Modules.C.)");
|
||||
frontend.check("game/Gui/Modules/D");
|
||||
getFrontend().check("game/Gui/Modules/D");
|
||||
|
||||
validateMatchesRequireLists("Adding error dependency D->C.");
|
||||
validateSecondDependsOnFirst("game/Gui/Modules/D", "game/Gui/Modules/C", true);
|
||||
|
@ -1739,17 +1738,17 @@ TEST_CASE_FIXTURE(FrontendFixture, "test_invalid_dependency_tracking_per_module_
|
|||
FrontendOptions opts;
|
||||
opts.forAutocomplete = false;
|
||||
|
||||
frontend.check("game/Gui/Modules/B", opts);
|
||||
CHECK(frontend.allModuleDependenciesValid("game/Gui/Modules/B", opts.forAutocomplete));
|
||||
CHECK(!frontend.allModuleDependenciesValid("game/Gui/Modules/B", !opts.forAutocomplete));
|
||||
getFrontend().check("game/Gui/Modules/B", opts);
|
||||
CHECK(getFrontend().allModuleDependenciesValid("game/Gui/Modules/B", opts.forAutocomplete));
|
||||
CHECK(!getFrontend().allModuleDependenciesValid("game/Gui/Modules/B", !opts.forAutocomplete));
|
||||
|
||||
opts.forAutocomplete = true;
|
||||
frontend.check("game/Gui/Modules/A", opts);
|
||||
getFrontend().check("game/Gui/Modules/A", opts);
|
||||
|
||||
CHECK(!frontend.allModuleDependenciesValid("game/Gui/Modules/B", opts.forAutocomplete));
|
||||
CHECK(frontend.allModuleDependenciesValid("game/Gui/Modules/B", !opts.forAutocomplete));
|
||||
CHECK(frontend.allModuleDependenciesValid("game/Gui/Modules/A", !opts.forAutocomplete));
|
||||
CHECK(frontend.allModuleDependenciesValid("game/Gui/Modules/A", opts.forAutocomplete));
|
||||
CHECK(!getFrontend().allModuleDependenciesValid("game/Gui/Modules/B", opts.forAutocomplete));
|
||||
CHECK(getFrontend().allModuleDependenciesValid("game/Gui/Modules/B", !opts.forAutocomplete));
|
||||
CHECK(getFrontend().allModuleDependenciesValid("game/Gui/Modules/A", !opts.forAutocomplete));
|
||||
CHECK(getFrontend().allModuleDependenciesValid("game/Gui/Modules/A", opts.forAutocomplete));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FrontendFixture, "queue_check_simple")
|
||||
|
@ -1765,10 +1764,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "queue_check_simple")
|
|||
return {b_value = A.hello}
|
||||
)";
|
||||
|
||||
frontend.queueModuleCheck("game/Gui/Modules/B");
|
||||
frontend.checkQueuedModules();
|
||||
getFrontend().queueModuleCheck("game/Gui/Modules/B");
|
||||
getFrontend().checkQueuedModules();
|
||||
|
||||
auto result = frontend.getCheckResult("game/Gui/Modules/B", true);
|
||||
auto result = getFrontend().getCheckResult("game/Gui/Modules/B", true);
|
||||
REQUIRE(result);
|
||||
LUAU_REQUIRE_NO_ERRORS(*result);
|
||||
}
|
||||
|
@ -1788,10 +1787,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "queue_check_cycle_instant")
|
|||
return {b_value = A.hello}
|
||||
)";
|
||||
|
||||
frontend.queueModuleCheck("game/Gui/Modules/B");
|
||||
frontend.checkQueuedModules();
|
||||
getFrontend().queueModuleCheck("game/Gui/Modules/B");
|
||||
getFrontend().checkQueuedModules();
|
||||
|
||||
auto result = frontend.getCheckResult("game/Gui/Modules/B", true);
|
||||
auto result = getFrontend().getCheckResult("game/Gui/Modules/B", true);
|
||||
REQUIRE(result);
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, *result);
|
||||
CHECK(toString(result->errors[0]) == "Cyclic module dependency: game/Gui/Modules/B -> game/Gui/Modules/A");
|
||||
|
@ -1819,10 +1818,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "queue_check_cycle_delayed")
|
|||
return {b_value = A.hello + C.c_value}
|
||||
)";
|
||||
|
||||
frontend.queueModuleCheck("game/Gui/Modules/B");
|
||||
frontend.checkQueuedModules();
|
||||
getFrontend().queueModuleCheck("game/Gui/Modules/B");
|
||||
getFrontend().checkQueuedModules();
|
||||
|
||||
auto result = frontend.getCheckResult("game/Gui/Modules/B", true);
|
||||
auto result = getFrontend().getCheckResult("game/Gui/Modules/B", true);
|
||||
REQUIRE(result);
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, *result);
|
||||
CHECK(toString(result->errors[0]) == "Cyclic module dependency: game/Gui/Modules/B -> game/Gui/Modules/A");
|
||||
|
@ -1838,10 +1837,10 @@ TEST_CASE_FIXTURE(FrontendFixture, "queue_check_propagates_ice")
|
|||
--!strict
|
||||
local a: _luau_ice = 55
|
||||
)";
|
||||
frontend.markDirty(mm);
|
||||
frontend.queueModuleCheck("MainModule");
|
||||
getFrontend().markDirty(mm);
|
||||
getFrontend().queueModuleCheck("MainModule");
|
||||
|
||||
CHECK_THROWS_AS(frontend.checkQueuedModules(), InternalCompilerError);
|
||||
CHECK_THROWS_AS(getFrontend().checkQueuedModules(), InternalCompilerError);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(DebugLuauForbidInternalTypes)
|
||||
LUAU_FASTFLAG(LuauAvoidGenericsLeakingDuringFunctionCallCheck)
|
||||
|
||||
|
@ -227,7 +227,7 @@ TEST_CASE_FIXTURE(GeneralizationFixture, "('a) -> 'a")
|
|||
|
||||
TEST_CASE_FIXTURE(GeneralizationFixture, "(t1, (t1 <: 'b)) -> () where t1 = ('a <: (t1 <: 'b) & {number} & {number})")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization3, true};
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization4, true};
|
||||
|
||||
TableType tt;
|
||||
tt.indexer = TableIndexer{builtinTypes.numberType, builtinTypes.numberType};
|
||||
|
@ -261,7 +261,7 @@ TEST_CASE_FIXTURE(GeneralizationFixture, "(('a <: number | string)) -> string?")
|
|||
|
||||
TEST_CASE_FIXTURE(GeneralizationFixture, "(('a <: {'b})) -> ()")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization3, true};
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization4, true};
|
||||
|
||||
auto [aTy, aFree] = freshType();
|
||||
auto [bTy, bFree] = freshType();
|
||||
|
@ -430,7 +430,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "avoid_cross_module_mutation_in_bidirectional
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauAvoidGenericsLeakingDuringFunctionCallCheck, true},
|
||||
{FFlag::LuauEagerGeneralization3, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
};
|
||||
|
||||
fileResolver.source["Module/ListFns"] = R"(
|
||||
|
@ -454,12 +454,12 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "avoid_cross_module_mutation_in_bidirectional
|
|||
return {}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Module/ListFns");
|
||||
auto modListFns = frontend.moduleResolver.getModule("Module/ListFns");
|
||||
CheckResult result = getFrontend().check("Module/ListFns");
|
||||
auto modListFns = getFrontend().moduleResolver.getModule("Module/ListFns");
|
||||
freeze(modListFns->interfaceTypes);
|
||||
freeze(modListFns->internalTypes);
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
CheckResult result2 = frontend.check("Module/B");
|
||||
CheckResult result2 = getFrontend().check("Module/B");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,16 +8,17 @@
|
|||
|
||||
using namespace Luau;
|
||||
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3);
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4);
|
||||
LUAU_FASTFLAG(LuauInferPolarityOfReadWriteProperties)
|
||||
|
||||
TEST_SUITE_BEGIN("InferPolarity");
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "T where T = { m: <a>(a) -> T }")
|
||||
{
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization3, true};
|
||||
ScopedFastFlag sff{FFlag::LuauEagerGeneralization4, true};
|
||||
|
||||
TypeArena arena;
|
||||
ScopePtr globalScope = std::make_shared<Scope>(builtinTypes->anyTypePack);
|
||||
ScopePtr globalScope = std::make_shared<Scope>(getBuiltins()->anyTypePack);
|
||||
|
||||
TypeId tType = arena.addType(BlockedType{});
|
||||
TypeId aType = arena.addType(GenericType{globalScope.get(), "a"});
|
||||
|
@ -48,4 +49,40 @@ TEST_CASE_FIXTURE(Fixture, "T where T = { m: <a>(a) -> T }")
|
|||
CHECK(aGeneric->polarity == Polarity::Negative);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "<a, b>({ read x: a, write x: b }) -> ()")
|
||||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
{FFlag::LuauInferPolarityOfReadWriteProperties, true},
|
||||
};
|
||||
|
||||
TypeArena arena;
|
||||
ScopePtr globalScope = std::make_shared<Scope>(getBuiltins()->anyTypePack);
|
||||
|
||||
TypeId aType = arena.addType(GenericType{globalScope.get(), "a"});
|
||||
TypeId bType = arena.addType(GenericType{globalScope.get(), "b"});
|
||||
|
||||
TableType ttv;
|
||||
ttv.state = TableState::Sealed;
|
||||
ttv.props["x"] = Property::create({aType}, {bType});
|
||||
|
||||
TypeId mType = arena.addType(FunctionType{
|
||||
TypeLevel{},
|
||||
/* generics */ {aType, bType},
|
||||
/* genericPacks */ {},
|
||||
/* argPack */ arena.addTypePack({arena.addType(std::move(ttv))}),
|
||||
/* retPack */ builtinTypes->emptyTypePack,
|
||||
});
|
||||
|
||||
inferGenericPolarities(NotNull{&arena}, NotNull{globalScope.get()}, mType);
|
||||
|
||||
const GenericType* aGeneric = get<GenericType>(aType);
|
||||
REQUIRE(aGeneric);
|
||||
CHECK(aGeneric->polarity == Polarity::Negative);
|
||||
|
||||
const GenericType* bGeneric = get<GenericType>(bType);
|
||||
REQUIRE(bGeneric);
|
||||
CHECK(bGeneric->polarity == Polarity::Positive);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -16,7 +16,7 @@ TEST_SUITE_BEGIN("Instantiation2Test");
|
|||
TEST_CASE_FIXTURE(Fixture, "weird_cyclic_instantiation")
|
||||
{
|
||||
TypeArena arena;
|
||||
Scope scope(builtinTypes->anyTypePack);
|
||||
Scope scope(getBuiltins()->anyTypePack);
|
||||
|
||||
TypeId genericT = arena.addType(GenericType{"T"});
|
||||
|
||||
|
@ -30,11 +30,11 @@ TEST_CASE_FIXTURE(Fixture, "weird_cyclic_instantiation")
|
|||
DenseHashMap<TypeId, TypeId> genericSubstitutions{nullptr};
|
||||
DenseHashMap<TypePackId, TypePackId> genericPackSubstitutions{nullptr};
|
||||
|
||||
TypeId freeTy = arena.freshType(builtinTypes, &scope);
|
||||
TypeId freeTy = arena.freshType(getBuiltins(), &scope);
|
||||
FreeType* ft = getMutable<FreeType>(freeTy);
|
||||
REQUIRE(ft);
|
||||
ft->lowerBound = idTy;
|
||||
ft->upperBound = builtinTypes->unknownType;
|
||||
ft->upperBound = getBuiltins()->unknownType;
|
||||
|
||||
genericSubstitutions[genericT] = freeTy;
|
||||
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
LUAU_FASTFLAG(LuauCodeGenSimplifyImport)
|
||||
|
||||
static void luauLibraryConstantLookup(const char* library, const char* member, Luau::CompileConstant* constant)
|
||||
{
|
||||
// While 'vector' library constants are a Luau built-in, their constant value depends on the embedder LUA_VECTOR_SIZE value
|
||||
|
@ -498,6 +500,8 @@ bb_bytecode_1:
|
|||
|
||||
TEST_CASE("DseInitialStackState")
|
||||
{
|
||||
ScopedFastFlag luauCodeGenSimplifyImport{FFlag::LuauCodeGenSimplifyImport, true};
|
||||
|
||||
CHECK_EQ(
|
||||
"\n" + getCodegenAssembly(R"(
|
||||
local function foo()
|
||||
|
@ -518,17 +522,11 @@ bb_bytecode_0:
|
|||
JUMP bb_2
|
||||
bb_2:
|
||||
CHECK_SAFE_ENV exit(3)
|
||||
JUMP_EQ_TAG K1 (nil), tnil, bb_fallback_4, bb_3
|
||||
bb_3:
|
||||
%9 = LOAD_TVALUE K1 (nil)
|
||||
STORE_TVALUE R1, %9
|
||||
JUMP bb_5
|
||||
bb_5:
|
||||
GET_CACHED_IMPORT R1, K1 (nil), 1073741824u ('_'), 4u
|
||||
SET_SAVEDPC 7u
|
||||
%21 = NEW_TABLE 0u, 0u
|
||||
STORE_POINTER R1, %21
|
||||
%14 = NEW_TABLE 0u, 0u
|
||||
STORE_POINTER R1, %14
|
||||
STORE_TAG R1, ttable
|
||||
CHECK_GC
|
||||
STORE_TAG R0, tnil
|
||||
INTERRUPT 9u
|
||||
JUMP bb_bytecode_0
|
||||
|
@ -1569,6 +1567,8 @@ end
|
|||
|
||||
TEST_CASE("ForInManualAnnotation")
|
||||
{
|
||||
ScopedFastFlag luauCodeGenSimplifyImport{FFlag::LuauCodeGenSimplifyImport, true};
|
||||
|
||||
CHECK_EQ(
|
||||
"\n" + getCodegenAssembly(
|
||||
R"(
|
||||
|
@ -1601,22 +1601,17 @@ bb_bytecode_1:
|
|||
STORE_DOUBLE R1, 0
|
||||
STORE_TAG R1, tnumber
|
||||
CHECK_SAFE_ENV exit(1)
|
||||
JUMP_EQ_TAG K1 (nil), tnil, bb_fallback_6, bb_5
|
||||
bb_5:
|
||||
%9 = LOAD_TVALUE K1 (nil)
|
||||
STORE_TVALUE R2, %9
|
||||
JUMP bb_7
|
||||
bb_7:
|
||||
%15 = LOAD_TVALUE R0
|
||||
STORE_TVALUE R3, %15
|
||||
GET_CACHED_IMPORT R2, K1 (nil), 1073741824u ('ipairs'), 2u
|
||||
%8 = LOAD_TVALUE R0
|
||||
STORE_TVALUE R3, %8
|
||||
INTERRUPT 4u
|
||||
SET_SAVEDPC 5u
|
||||
CALL R2, 1i, 3i
|
||||
CHECK_SAFE_ENV exit(5)
|
||||
CHECK_TAG R3, ttable, bb_fallback_8
|
||||
CHECK_TAG R4, tnumber, bb_fallback_8
|
||||
JUMP_CMP_NUM R4, 0, not_eq, bb_fallback_8, bb_9
|
||||
bb_9:
|
||||
CHECK_TAG R3, ttable, bb_fallback_5
|
||||
CHECK_TAG R4, tnumber, bb_fallback_5
|
||||
JUMP_CMP_NUM R4, 0, not_eq, bb_fallback_5, bb_6
|
||||
bb_6:
|
||||
STORE_TAG R2, tnil
|
||||
STORE_POINTER R4, 0i
|
||||
STORE_EXTRA R4, 128i
|
||||
|
@ -1624,41 +1619,41 @@ bb_9:
|
|||
JUMP bb_bytecode_3
|
||||
bb_bytecode_2:
|
||||
CHECK_TAG R6, ttable, exit(6)
|
||||
%35 = LOAD_POINTER R6
|
||||
%36 = GET_SLOT_NODE_ADDR %35, 6u, K2 ('pos')
|
||||
CHECK_SLOT_MATCH %36, K2 ('pos'), bb_fallback_10
|
||||
%38 = LOAD_TVALUE %36, 0i
|
||||
STORE_TVALUE R8, %38
|
||||
JUMP bb_11
|
||||
bb_11:
|
||||
%28 = LOAD_POINTER R6
|
||||
%29 = GET_SLOT_NODE_ADDR %28, 6u, K2 ('pos')
|
||||
CHECK_SLOT_MATCH %29, K2 ('pos'), bb_fallback_7
|
||||
%31 = LOAD_TVALUE %29, 0i
|
||||
STORE_TVALUE R8, %31
|
||||
JUMP bb_8
|
||||
bb_8:
|
||||
CHECK_TAG R8, tvector, exit(8)
|
||||
%45 = LOAD_FLOAT R8, 0i
|
||||
STORE_DOUBLE R7, %45
|
||||
%38 = LOAD_FLOAT R8, 0i
|
||||
STORE_DOUBLE R7, %38
|
||||
STORE_TAG R7, tnumber
|
||||
CHECK_TAG R1, tnumber, exit(10)
|
||||
%52 = LOAD_DOUBLE R1
|
||||
%54 = ADD_NUM %52, %45
|
||||
STORE_DOUBLE R1, %54
|
||||
%45 = LOAD_DOUBLE R1
|
||||
%47 = ADD_NUM %45, %38
|
||||
STORE_DOUBLE R1, %47
|
||||
JUMP bb_bytecode_3
|
||||
bb_bytecode_3:
|
||||
INTERRUPT 11u
|
||||
CHECK_TAG R2, tnil, bb_fallback_13
|
||||
%60 = LOAD_POINTER R3
|
||||
%61 = LOAD_INT R4
|
||||
%62 = GET_ARR_ADDR %60, %61
|
||||
CHECK_ARRAY_SIZE %60, %61, bb_12
|
||||
%64 = LOAD_TAG %62
|
||||
JUMP_EQ_TAG %64, tnil, bb_12, bb_14
|
||||
bb_14:
|
||||
%66 = ADD_INT %61, 1i
|
||||
STORE_INT R4, %66
|
||||
%68 = INT_TO_NUM %66
|
||||
STORE_DOUBLE R5, %68
|
||||
CHECK_TAG R2, tnil, bb_fallback_10
|
||||
%53 = LOAD_POINTER R3
|
||||
%54 = LOAD_INT R4
|
||||
%55 = GET_ARR_ADDR %53, %54
|
||||
CHECK_ARRAY_SIZE %53, %54, bb_9
|
||||
%57 = LOAD_TAG %55
|
||||
JUMP_EQ_TAG %57, tnil, bb_9, bb_11
|
||||
bb_11:
|
||||
%59 = ADD_INT %54, 1i
|
||||
STORE_INT R4, %59
|
||||
%61 = INT_TO_NUM %59
|
||||
STORE_DOUBLE R5, %61
|
||||
STORE_TAG R5, tnumber
|
||||
%71 = LOAD_TVALUE %62
|
||||
STORE_TVALUE R6, %71
|
||||
%64 = LOAD_TVALUE %55
|
||||
STORE_TVALUE R6, %64
|
||||
JUMP bb_bytecode_2
|
||||
bb_12:
|
||||
bb_9:
|
||||
INTERRUPT 13u
|
||||
RETURN R1, 1i
|
||||
)"
|
||||
|
|
|
@ -8,9 +8,7 @@
|
|||
#include "doctest.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauSolverV2);
|
||||
LUAU_FASTFLAG(LintRedundantNativeAttribute);
|
||||
LUAU_FASTFLAG(LuauDeprecatedAttribute);
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3);
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4);
|
||||
|
||||
using namespace Luau;
|
||||
|
||||
|
@ -51,7 +49,7 @@ TEST_CASE_FIXTURE(Fixture, "UnknownGlobal")
|
|||
TEST_CASE_FIXTURE(Fixture, "DeprecatedGlobal")
|
||||
{
|
||||
// Normally this would be defined externally, so hack it in for testing
|
||||
addGlobalBinding(frontend.globals, "Wait", Binding{builtinTypes->anyType, {}, true, "wait", "@test/global/Wait"});
|
||||
addGlobalBinding(getFrontend().globals, "Wait", Binding{getBuiltins()->anyType, {}, true, "wait", "@test/global/Wait"});
|
||||
|
||||
LintResult result = lint("Wait(5)");
|
||||
|
||||
|
@ -63,7 +61,7 @@ TEST_CASE_FIXTURE(Fixture, "DeprecatedGlobalNoReplacement")
|
|||
{
|
||||
// Normally this would be defined externally, so hack it in for testing
|
||||
const char* deprecationReplacementString = "";
|
||||
addGlobalBinding(frontend.globals, "Version", Binding{builtinTypes->anyType, {}, true, deprecationReplacementString});
|
||||
addGlobalBinding(getFrontend().globals, "Version", Binding{getBuiltins()->anyType, {}, true, deprecationReplacementString});
|
||||
|
||||
LintResult result = lint("Version()");
|
||||
|
||||
|
@ -390,7 +388,7 @@ return bar()
|
|||
TEST_CASE_FIXTURE(Fixture, "ImportUnused")
|
||||
{
|
||||
// Normally this would be defined externally, so hack it in for testing
|
||||
addGlobalBinding(frontend.globals, "game", builtinTypes->anyType, "@test");
|
||||
addGlobalBinding(getFrontend().globals, "game", getBuiltins()->anyType, "@test");
|
||||
|
||||
LintResult result = lint(R"(
|
||||
local Roact = require(game.Packages.Roact)
|
||||
|
@ -621,16 +619,16 @@ return foo1
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "UnknownType")
|
||||
{
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
unfreeze(getFrontend().globals.globalTypes);
|
||||
TableType::Props instanceProps{
|
||||
{"ClassName", {builtinTypes->anyType}},
|
||||
{"ClassName", {getBuiltins()->anyType}},
|
||||
};
|
||||
|
||||
TableType instanceTable{instanceProps, std::nullopt, frontend.globals.globalScope->level, Luau::TableState::Sealed};
|
||||
TypeId instanceType = frontend.globals.globalTypes.addType(instanceTable);
|
||||
TableType instanceTable{instanceProps, std::nullopt, getFrontend().globals.globalScope->level, Luau::TableState::Sealed};
|
||||
TypeId instanceType = getFrontend().globals.globalTypes.addType(instanceTable);
|
||||
TypeFun instanceTypeFun{{}, instanceType};
|
||||
|
||||
frontend.globals.globalScope->exportedTypeBindings["Part"] = instanceTypeFun;
|
||||
getFrontend().globals.globalScope->exportedTypeBindings["Part"] = instanceTypeFun;
|
||||
|
||||
LintResult result = lint(R"(
|
||||
local game = ...
|
||||
|
@ -1341,10 +1339,10 @@ TEST_CASE_FIXTURE(Fixture, "no_spurious_warning_after_a_function_type_alias")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "use_all_parent_scopes_for_globals")
|
||||
{
|
||||
ScopePtr testScope = frontend.addEnvironment("Test");
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
frontend.loadDefinitionFile(
|
||||
frontend.globals,
|
||||
ScopePtr testScope = getFrontend().addEnvironment("Test");
|
||||
unfreeze(getFrontend().globals.globalTypes);
|
||||
getFrontend().loadDefinitionFile(
|
||||
getFrontend().globals,
|
||||
testScope,
|
||||
R"(
|
||||
declare Foo: number
|
||||
|
@ -1352,7 +1350,7 @@ TEST_CASE_FIXTURE(Fixture, "use_all_parent_scopes_for_globals")
|
|||
"@test",
|
||||
/* captureComments */ false
|
||||
);
|
||||
freeze(frontend.globals.globalTypes);
|
||||
freeze(getFrontend().globals.globalTypes);
|
||||
|
||||
fileResolver.environments["A"] = "Test";
|
||||
|
||||
|
@ -1521,32 +1519,32 @@ TEST_CASE_FIXTURE(Fixture, "LintHygieneUAF")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "DeprecatedApiTyped")
|
||||
{
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
TypeId instanceType = frontend.globals.globalTypes.addType(ExternType{"Instance", {}, std::nullopt, std::nullopt, {}, {}, "Test", {}});
|
||||
unfreeze(getFrontend().globals.globalTypes);
|
||||
TypeId instanceType = getFrontend().globals.globalTypes.addType(ExternType{"Instance", {}, std::nullopt, std::nullopt, {}, {}, "Test", {}});
|
||||
persist(instanceType);
|
||||
frontend.globals.globalScope->exportedTypeBindings["Instance"] = TypeFun{{}, instanceType};
|
||||
getFrontend().globals.globalScope->exportedTypeBindings["Instance"] = TypeFun{{}, instanceType};
|
||||
|
||||
getMutable<ExternType>(instanceType)->props = {
|
||||
{"Name", {builtinTypes->stringType}},
|
||||
{"DataCost", {builtinTypes->numberType, /* deprecated= */ true}},
|
||||
{"Wait", {builtinTypes->anyType, /* deprecated= */ true}},
|
||||
{"Name", {getBuiltins()->stringType}},
|
||||
{"DataCost", {getBuiltins()->numberType, /* deprecated= */ true}},
|
||||
{"Wait", {getBuiltins()->anyType, /* deprecated= */ true}},
|
||||
};
|
||||
|
||||
TypeId colorType =
|
||||
frontend.globals.globalTypes.addType(TableType{{}, std::nullopt, frontend.globals.globalScope->level, Luau::TableState::Sealed});
|
||||
getFrontend().globals.globalTypes.addType(TableType{{}, std::nullopt, getFrontend().globals.globalScope->level, Luau::TableState::Sealed});
|
||||
|
||||
getMutable<TableType>(colorType)->props = {{"toHSV", {builtinTypes->anyType, /* deprecated= */ true, "Color3:ToHSV"}}};
|
||||
getMutable<TableType>(colorType)->props = {{"toHSV", {getBuiltins()->anyType, /* deprecated= */ true, "Color3:ToHSV"}}};
|
||||
|
||||
addGlobalBinding(frontend.globals, "Color3", Binding{colorType, {}});
|
||||
addGlobalBinding(getFrontend().globals, "Color3", Binding{colorType, {}});
|
||||
|
||||
if (TableType* ttv = getMutable<TableType>(getGlobalBinding(frontend.globals, "table")))
|
||||
if (TableType* ttv = getMutable<TableType>(getGlobalBinding(getFrontend().globals, "table")))
|
||||
{
|
||||
ttv->props["foreach"].deprecated = true;
|
||||
ttv->props["getn"].deprecated = true;
|
||||
ttv->props["getn"].deprecatedSuggestion = "#";
|
||||
}
|
||||
|
||||
freeze(frontend.globals.globalTypes);
|
||||
freeze(getFrontend().globals.globalTypes);
|
||||
|
||||
LintResult result = lint(R"(
|
||||
return function (i: Instance)
|
||||
|
@ -1571,7 +1569,7 @@ end
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "DeprecatedApiUntyped")
|
||||
{
|
||||
if (TableType* ttv = getMutable<TableType>(getGlobalBinding(frontend.globals, "table")))
|
||||
if (TableType* ttv = getMutable<TableType>(getGlobalBinding(getFrontend().globals, "table")))
|
||||
{
|
||||
ttv->props["foreach"].deprecated = true;
|
||||
ttv->props["getn"].deprecated = true;
|
||||
|
@ -2337,8 +2335,6 @@ local _ = a <= (b == 0)
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "RedundantNativeAttribute")
|
||||
{
|
||||
ScopedFastFlag sff[] = {{FFlag::LintRedundantNativeAttribute, true}};
|
||||
|
||||
LintResult result = lint(R"(
|
||||
--!native
|
||||
|
||||
|
|
|
@ -79,22 +79,22 @@ TEST_CASE_FIXTURE(Fixture, "is_within_comment_parse_result")
|
|||
TEST_CASE_FIXTURE(Fixture, "dont_clone_persistent_primitive")
|
||||
{
|
||||
TypeArena dest;
|
||||
CloneState cloneState{builtinTypes};
|
||||
CloneState cloneState{getBuiltins()};
|
||||
|
||||
// numberType is persistent. We leave it as-is.
|
||||
TypeId newNumber = clone(builtinTypes->numberType, dest, cloneState);
|
||||
CHECK_EQ(newNumber, builtinTypes->numberType);
|
||||
TypeId newNumber = clone(getBuiltins()->numberType, dest, cloneState);
|
||||
CHECK_EQ(newNumber, getBuiltins()->numberType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "deepClone_non_persistent_primitive")
|
||||
{
|
||||
TypeArena dest;
|
||||
CloneState cloneState{builtinTypes};
|
||||
CloneState cloneState{getBuiltins()};
|
||||
|
||||
// Create a new number type that isn't persistent
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
TypeId oldNumber = frontend.globals.globalTypes.addType(PrimitiveType{PrimitiveType::Number});
|
||||
freeze(frontend.globals.globalTypes);
|
||||
unfreeze(getFrontend().globals.globalTypes);
|
||||
TypeId oldNumber = getFrontend().globals.globalTypes.addType(PrimitiveType{PrimitiveType::Number});
|
||||
freeze(getFrontend().globals.globalTypes);
|
||||
TypeId newNumber = clone(oldNumber, dest, cloneState);
|
||||
|
||||
CHECK_NE(newNumber, oldNumber);
|
||||
|
@ -128,7 +128,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
|
|||
TypeId ty = requireType("Cyclic");
|
||||
|
||||
TypeArena dest;
|
||||
CloneState cloneState{builtinTypes};
|
||||
CloneState cloneState{getBuiltins()};
|
||||
TypeId cloneTy = clone(ty, dest, cloneState);
|
||||
|
||||
TableType* ttv = getMutable<TableType>(cloneTy);
|
||||
|
@ -164,7 +164,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table_2")
|
|||
|
||||
TypeArena dest;
|
||||
|
||||
CloneState cloneState{builtinTypes};
|
||||
CloneState cloneState{getBuiltins()};
|
||||
TypeId cloneTy = clone(tableTy, dest, cloneState);
|
||||
TableType* ctt = getMutable<TableType>(cloneTy);
|
||||
REQUIRE(ctt);
|
||||
|
@ -189,7 +189,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_point_into_globalTypes_arena")
|
|||
dumpErrors(result);
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
ModulePtr module = frontend.moduleResolver.getModule("MainModule");
|
||||
ModulePtr module = getFrontend().moduleResolver.getModule("MainModule");
|
||||
std::optional<TypeId> exports = first(module->returnType);
|
||||
REQUIRE(bool(exports));
|
||||
|
||||
|
@ -202,17 +202,17 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_point_into_globalTypes_arena")
|
|||
REQUIRE(signType != nullptr);
|
||||
|
||||
CHECK(!isInArena(signType, module->interfaceTypes));
|
||||
CHECK(isInArena(signType, frontend.globals.globalTypes));
|
||||
CHECK(isInArena(signType, getFrontend().globals.globalTypes));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "deepClone_union")
|
||||
{
|
||||
TypeArena dest;
|
||||
CloneState cloneState{builtinTypes};
|
||||
CloneState cloneState{getBuiltins()};
|
||||
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
TypeId oldUnion = frontend.globals.globalTypes.addType(UnionType{{builtinTypes->numberType, builtinTypes->stringType}});
|
||||
freeze(frontend.globals.globalTypes);
|
||||
unfreeze(getFrontend().globals.globalTypes);
|
||||
TypeId oldUnion = getFrontend().globals.globalTypes.addType(UnionType{{getBuiltins()->numberType, getBuiltins()->stringType}});
|
||||
freeze(getFrontend().globals.globalTypes);
|
||||
TypeId newUnion = clone(oldUnion, dest, cloneState);
|
||||
|
||||
CHECK_NE(newUnion, oldUnion);
|
||||
|
@ -223,11 +223,11 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_union")
|
|||
TEST_CASE_FIXTURE(Fixture, "deepClone_intersection")
|
||||
{
|
||||
TypeArena dest;
|
||||
CloneState cloneState{builtinTypes};
|
||||
CloneState cloneState{getBuiltins()};
|
||||
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
TypeId oldIntersection = frontend.globals.globalTypes.addType(IntersectionType{{builtinTypes->numberType, builtinTypes->stringType}});
|
||||
freeze(frontend.globals.globalTypes);
|
||||
unfreeze(getFrontend().globals.globalTypes);
|
||||
TypeId oldIntersection = getFrontend().globals.globalTypes.addType(IntersectionType{{getBuiltins()->numberType, getBuiltins()->stringType}});
|
||||
freeze(getFrontend().globals.globalTypes);
|
||||
TypeId newIntersection = clone(oldIntersection, dest, cloneState);
|
||||
|
||||
CHECK_NE(newIntersection, oldIntersection);
|
||||
|
@ -240,7 +240,7 @@ TEST_CASE_FIXTURE(Fixture, "clone_class")
|
|||
Type exampleMetaClass{ExternType{
|
||||
"ExampleClassMeta",
|
||||
{
|
||||
{"__add", {builtinTypes->anyType}},
|
||||
{"__add", {getBuiltins()->anyType}},
|
||||
},
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
|
@ -252,8 +252,8 @@ TEST_CASE_FIXTURE(Fixture, "clone_class")
|
|||
Type exampleClass{ExternType{
|
||||
"ExampleClass",
|
||||
{
|
||||
{"PropOne", {builtinTypes->numberType}},
|
||||
{"PropTwo", {builtinTypes->stringType}},
|
||||
{"PropOne", {getBuiltins()->numberType}},
|
||||
{"PropTwo", {getBuiltins()->stringType}},
|
||||
},
|
||||
std::nullopt,
|
||||
&exampleMetaClass,
|
||||
|
@ -264,7 +264,7 @@ TEST_CASE_FIXTURE(Fixture, "clone_class")
|
|||
}};
|
||||
|
||||
TypeArena dest;
|
||||
CloneState cloneState{builtinTypes};
|
||||
CloneState cloneState{getBuiltins()};
|
||||
|
||||
TypeId cloned = clone(&exampleClass, dest, cloneState);
|
||||
const ExternType* etv = get<ExternType>(cloned);
|
||||
|
@ -281,16 +281,16 @@ TEST_CASE_FIXTURE(Fixture, "clone_class")
|
|||
TEST_CASE_FIXTURE(Fixture, "clone_free_types")
|
||||
{
|
||||
TypeArena arena;
|
||||
TypeId freeTy = freshType(NotNull{&arena}, builtinTypes, nullptr);
|
||||
TypeId freeTy = freshType(NotNull{&arena}, getBuiltins(), nullptr);
|
||||
TypePackVar freeTp(FreeTypePack{TypeLevel{}});
|
||||
|
||||
TypeArena dest;
|
||||
CloneState cloneState{builtinTypes};
|
||||
CloneState cloneState{getBuiltins()};
|
||||
|
||||
TypeId clonedTy = clone(freeTy, dest, cloneState);
|
||||
CHECK(get<FreeType>(clonedTy));
|
||||
|
||||
cloneState = {builtinTypes};
|
||||
cloneState = {getBuiltins()};
|
||||
TypePackId clonedTp = clone(&freeTp, dest, cloneState);
|
||||
CHECK(get<FreeTypePack>(clonedTp));
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ TEST_CASE_FIXTURE(Fixture, "clone_free_tables")
|
|||
ttv->state = TableState::Free;
|
||||
|
||||
TypeArena dest;
|
||||
CloneState cloneState{builtinTypes};
|
||||
CloneState cloneState{getBuiltins()};
|
||||
|
||||
TypeId cloned = clone(&tableTy, dest, cloneState);
|
||||
const TableType* clonedTtv = get<TableType>(cloned);
|
||||
|
@ -323,7 +323,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "clone_self_property")
|
|||
return a;
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Module/A");
|
||||
CheckResult result = getFrontend().check("Module/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
fileResolver.source["Module/B"] = R"(
|
||||
|
@ -332,7 +332,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "clone_self_property")
|
|||
return a.foo(5)
|
||||
)";
|
||||
|
||||
result = frontend.check("Module/B");
|
||||
result = getFrontend().check("Module/B");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
|
@ -357,7 +357,7 @@ TEST_CASE_FIXTURE(Fixture, "clone_iteration_limit")
|
|||
}
|
||||
|
||||
TypeArena dest;
|
||||
CloneState cloneState{builtinTypes};
|
||||
CloneState cloneState{getBuiltins()};
|
||||
|
||||
TypeId ty = clone(table, dest, cloneState);
|
||||
CHECK(get<ErrorType>(ty));
|
||||
|
@ -373,14 +373,14 @@ TEST_CASE_FIXTURE(Fixture, "clone_cyclic_union")
|
|||
{
|
||||
TypeArena src;
|
||||
|
||||
TypeId u = src.addType(UnionType{{builtinTypes->numberType, builtinTypes->stringType}});
|
||||
TypeId u = src.addType(UnionType{{getBuiltins()->numberType, getBuiltins()->stringType}});
|
||||
UnionType* uu = getMutable<UnionType>(u);
|
||||
REQUIRE(uu);
|
||||
|
||||
uu->options.push_back(u);
|
||||
|
||||
TypeArena dest;
|
||||
CloneState cloneState{builtinTypes};
|
||||
CloneState cloneState{getBuiltins()};
|
||||
|
||||
TypeId cloned = clone(u, dest, cloneState);
|
||||
REQUIRE(cloned);
|
||||
|
@ -389,8 +389,8 @@ TEST_CASE_FIXTURE(Fixture, "clone_cyclic_union")
|
|||
REQUIRE(clonedUnion);
|
||||
REQUIRE(3 == clonedUnion->options.size());
|
||||
|
||||
CHECK(builtinTypes->numberType == clonedUnion->options[0]);
|
||||
CHECK(builtinTypes->stringType == clonedUnion->options[1]);
|
||||
CHECK(getBuiltins()->numberType == clonedUnion->options[0]);
|
||||
CHECK(getBuiltins()->stringType == clonedUnion->options[1]);
|
||||
CHECK(cloned == clonedUnion->options[2]);
|
||||
}
|
||||
|
||||
|
@ -403,10 +403,10 @@ type B = A
|
|||
|
||||
FrontendOptions opts;
|
||||
opts.retainFullTypeGraphs = false;
|
||||
CheckResult result = frontend.check("Module/A", opts);
|
||||
CheckResult result = getFrontend().check("Module/A", opts);
|
||||
LUAU_REQUIRE_ERRORS(result);
|
||||
|
||||
auto mod = frontend.moduleResolver.getModule("Module/A");
|
||||
auto mod = getFrontend().moduleResolver.getModule("Module/A");
|
||||
auto it = mod->exportedTypeBindings.find("A");
|
||||
REQUIRE(it != mod->exportedTypeBindings.end());
|
||||
|
||||
|
@ -429,11 +429,11 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_clone_reexports")
|
|||
return {}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Module/B");
|
||||
CheckResult result = getFrontend().check("Module/B");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
ModulePtr modA = frontend.moduleResolver.getModule("Module/A");
|
||||
ModulePtr modB = frontend.moduleResolver.getModule("Module/B");
|
||||
ModulePtr modA = getFrontend().moduleResolver.getModule("Module/A");
|
||||
ModulePtr modB = getFrontend().moduleResolver.getModule("Module/B");
|
||||
REQUIRE(modA);
|
||||
REQUIRE(modB);
|
||||
auto modAiter = modA->exportedTypeBindings.find("A");
|
||||
|
@ -460,12 +460,12 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_clone_types_of_reexported_values")
|
|||
return exports
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Module/B");
|
||||
CheckResult result = getFrontend().check("Module/B");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
ModulePtr modA = frontend.moduleResolver.getModule("Module/A");
|
||||
ModulePtr modA = getFrontend().moduleResolver.getModule("Module/A");
|
||||
REQUIRE(modA);
|
||||
ModulePtr modB = frontend.moduleResolver.getModule("Module/B");
|
||||
ModulePtr modB = getFrontend().moduleResolver.getModule("Module/B");
|
||||
REQUIRE(modB);
|
||||
|
||||
std::optional<TypeId> typeA = first(modA->returnType);
|
||||
|
@ -498,7 +498,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "clone_table_bound_to_table_bound_to_table")
|
|||
getMutable<TableType>(b)->boundTo = c;
|
||||
|
||||
TypeArena dest;
|
||||
CloneState state{builtinTypes};
|
||||
CloneState state{getBuiltins()};
|
||||
TypeId res = clone(a, dest, state);
|
||||
|
||||
REQUIRE(dest.types.size() == 1);
|
||||
|
@ -513,11 +513,11 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "clone_a_bound_type_to_a_persistent_type")
|
|||
{
|
||||
TypeArena arena;
|
||||
|
||||
TypeId boundTo = arena.addType(BoundType{builtinTypes->numberType});
|
||||
REQUIRE(builtinTypes->numberType->persistent);
|
||||
TypeId boundTo = arena.addType(BoundType{getBuiltins()->numberType});
|
||||
REQUIRE(getBuiltins()->numberType->persistent);
|
||||
|
||||
TypeArena dest;
|
||||
CloneState state{builtinTypes};
|
||||
CloneState state{getBuiltins()};
|
||||
TypeId res = clone(boundTo, dest, state);
|
||||
|
||||
REQUIRE(res == follow(boundTo));
|
||||
|
@ -527,11 +527,11 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "clone_a_bound_typepack_to_a_persistent_typep
|
|||
{
|
||||
TypeArena arena;
|
||||
|
||||
TypePackId boundTo = arena.addTypePack(BoundTypePack{builtinTypes->neverTypePack});
|
||||
REQUIRE(builtinTypes->neverTypePack->persistent);
|
||||
TypePackId boundTo = arena.addTypePack(BoundTypePack{getBuiltins()->neverTypePack});
|
||||
REQUIRE(getBuiltins()->neverTypePack->persistent);
|
||||
|
||||
TypeArena dest;
|
||||
CloneState state{builtinTypes};
|
||||
CloneState state{getBuiltins()};
|
||||
TypePackId res = clone(boundTo, dest, state);
|
||||
|
||||
REQUIRE(res == follow(boundTo));
|
||||
|
@ -556,7 +556,7 @@ for i,v in x do
|
|||
end
|
||||
)");
|
||||
|
||||
auto& module = frontend.moduleResolver.getModule("MainModule");
|
||||
auto& module = getFrontend().moduleResolver.getModule("MainModule");
|
||||
CHECK(module->getModuleScope()->children.size() == 7);
|
||||
}
|
||||
|
||||
|
|
|
@ -65,7 +65,9 @@ struct NonStrictTypeCheckerFixture : Fixture
|
|||
|
||||
NonStrictTypeCheckerFixture()
|
||||
{
|
||||
registerHiddenTypes(&frontend);
|
||||
// Force the frontend
|
||||
getFrontend();
|
||||
registerHiddenTypes(getFrontend());
|
||||
registerTestTypes();
|
||||
}
|
||||
|
||||
|
@ -86,7 +88,7 @@ struct NonStrictTypeCheckerFixture : Fixture
|
|||
};
|
||||
LoadDefinitionFileResult res = loadDefinition(definitions);
|
||||
LUAU_ASSERT(res.success);
|
||||
return frontend.check(moduleName);
|
||||
return getFrontend().check(moduleName);
|
||||
}
|
||||
|
||||
std::string definitions = R"BUILTIN_SRC(
|
||||
|
@ -639,14 +641,14 @@ buffer.readi8(b, 0)
|
|||
|
||||
TEST_CASE_FIXTURE(NonStrictTypeCheckerFixture, "nonstrict_method_calls")
|
||||
{
|
||||
Luau::unfreeze(frontend.globals.globalTypes);
|
||||
Luau::unfreeze(frontend.globalsForAutocomplete.globalTypes);
|
||||
Luau::unfreeze(getFrontend().globals.globalTypes);
|
||||
Luau::unfreeze(getFrontend().globalsForAutocomplete.globalTypes);
|
||||
|
||||
registerBuiltinGlobals(frontend, frontend.globals);
|
||||
registerBuiltinGlobals(getFrontend(), getFrontend().globals);
|
||||
registerTestTypes();
|
||||
|
||||
Luau::freeze(frontend.globals.globalTypes);
|
||||
Luau::freeze(frontend.globalsForAutocomplete.globalTypes);
|
||||
Luau::freeze(getFrontend().globals.globalTypes);
|
||||
Luau::freeze(getFrontend().globalsForAutocomplete.globalTypes);
|
||||
|
||||
CheckResult result = checkNonStrict(R"(
|
||||
local test = "test"
|
||||
|
@ -656,7 +658,7 @@ TEST_CASE_FIXTURE(NonStrictTypeCheckerFixture, "nonstrict_method_calls")
|
|||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "unknown_globals_in_non_strict")
|
||||
TEST_CASE_FIXTURE(Fixture, "unknown_globals_in_non_strict_1")
|
||||
{
|
||||
CheckResult result = check(Mode::Nonstrict, R"(
|
||||
foo = 5
|
||||
|
|
|
@ -67,7 +67,7 @@ TEST_CASE_FIXTURE(Fixture, "return_annotation_is_still_checked")
|
|||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
|
||||
REQUIRE_NE(*builtinTypes->anyType, *requireType("foo"));
|
||||
REQUIRE_NE(*getBuiltins()->anyType, *requireType("foo"));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -111,7 +111,7 @@ TEST_CASE_FIXTURE(Fixture, "locals_are_any_by_default")
|
|||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
CHECK_EQ(*builtinTypes->anyType, *requireType("m"));
|
||||
CHECK_EQ(*getBuiltins()->anyType, *requireType("m"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "parameters_having_type_any_are_optional")
|
||||
|
@ -180,7 +180,7 @@ TEST_CASE_FIXTURE(Fixture, "table_props_are_any")
|
|||
TypeId fooProp = ttv->props["foo"].type();
|
||||
REQUIRE(fooProp != nullptr);
|
||||
|
||||
CHECK_EQ(*fooProp, *builtinTypes->anyType);
|
||||
CHECK_EQ(*fooProp, *getBuiltins()->anyType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "inline_table_props_are_also_any")
|
||||
|
@ -200,8 +200,8 @@ TEST_CASE_FIXTURE(Fixture, "inline_table_props_are_also_any")
|
|||
TableType* ttv = getMutable<TableType>(requireType("T"));
|
||||
REQUIRE_MESSAGE(ttv, "Should be a table: " << toString(requireType("T")));
|
||||
|
||||
CHECK_EQ(*builtinTypes->anyType, *ttv->props["one"].type());
|
||||
CHECK_EQ(*builtinTypes->anyType, *ttv->props["two"].type());
|
||||
CHECK_EQ(*getBuiltins()->anyType, *ttv->props["one"].type());
|
||||
CHECK_EQ(*getBuiltins()->anyType, *ttv->props["two"].type());
|
||||
CHECK_MESSAGE(get<FunctionType>(follow(ttv->props["three"].type())), "Should be a function: " << *ttv->props["three"].type());
|
||||
}
|
||||
|
||||
|
|
|
@ -32,9 +32,9 @@ struct IsSubtypeFixture : Fixture
|
|||
if (!module->hasModuleScope())
|
||||
FAIL("isSubtype: module scope data is not available");
|
||||
|
||||
SimplifierPtr simplifier = newSimplifier(NotNull{&module->internalTypes}, builtinTypes);
|
||||
SimplifierPtr simplifier = newSimplifier(NotNull{&module->internalTypes}, getBuiltins());
|
||||
|
||||
return ::Luau::isSubtype(a, b, NotNull{module->getModuleScope().get()}, builtinTypes, NotNull{simplifier.get()}, ice);
|
||||
return ::Luau::isSubtype(a, b, NotNull{module->getModuleScope().get()}, getBuiltins(), NotNull{simplifier.get()}, ice);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
@ -325,13 +325,13 @@ TEST_CASE_FIXTURE(IsSubtypeFixture, "cyclic_table")
|
|||
|
||||
TEST_CASE_FIXTURE(IsSubtypeFixture, "extern_types")
|
||||
{
|
||||
createSomeExternTypes(&frontend);
|
||||
createSomeExternTypes(getFrontend());
|
||||
|
||||
check(""); // Ensure that we have a main Module.
|
||||
|
||||
TypeId p = frontend.globals.globalScope->lookupType("Parent")->type;
|
||||
TypeId c = frontend.globals.globalScope->lookupType("Child")->type;
|
||||
TypeId u = frontend.globals.globalScope->lookupType("Unrelated")->type;
|
||||
TypeId p = getFrontend().globals.globalScope->lookupType("Parent")->type;
|
||||
TypeId c = getFrontend().globals.globalScope->lookupType("Child")->type;
|
||||
TypeId u = getFrontend().globals.globalScope->lookupType("Unrelated")->type;
|
||||
|
||||
CHECK(isSubtype(c, p));
|
||||
CHECK(!isSubtype(p, c));
|
||||
|
@ -400,10 +400,10 @@ TEST_CASE_FIXTURE(IsSubtypeFixture, "error_suppression")
|
|||
{
|
||||
check("");
|
||||
|
||||
TypeId any = builtinTypes->anyType;
|
||||
TypeId err = builtinTypes->errorType;
|
||||
TypeId str = builtinTypes->stringType;
|
||||
TypeId unk = builtinTypes->unknownType;
|
||||
TypeId any = getBuiltins()->anyType;
|
||||
TypeId err = getBuiltins()->errorType;
|
||||
TypeId str = getBuiltins()->stringType;
|
||||
TypeId unk = getBuiltins()->unknownType;
|
||||
|
||||
CHECK(!isSubtype(any, err));
|
||||
CHECK(isSubtype(err, any));
|
||||
|
@ -447,12 +447,12 @@ struct NormalizeFixture : Fixture
|
|||
TypeArena arena;
|
||||
InternalErrorReporter iceHandler;
|
||||
UnifierSharedState unifierState{&iceHandler};
|
||||
Normalizer normalizer{&arena, builtinTypes, NotNull{&unifierState}};
|
||||
Scope globalScope{builtinTypes->anyTypePack};
|
||||
Normalizer normalizer{&arena, getBuiltins(), NotNull{&unifierState}};
|
||||
Scope globalScope{getBuiltins()->anyTypePack};
|
||||
|
||||
NormalizeFixture()
|
||||
{
|
||||
registerHiddenTypes(&frontend);
|
||||
registerHiddenTypes(getFrontend());
|
||||
}
|
||||
|
||||
std::shared_ptr<const NormalizedType> toNormalizedType(const std::string& annotation, int expectedErrors = 0)
|
||||
|
@ -698,7 +698,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "trivial_intersection_inhabited")
|
|||
{
|
||||
// this test was used to fix a bug in normalization when working with intersections/unions of the same type.
|
||||
|
||||
TypeId a = arena.addType(FunctionType{builtinTypes->emptyTypePack, builtinTypes->anyTypePack, std::nullopt, false});
|
||||
TypeId a = arena.addType(FunctionType{getBuiltins()->emptyTypePack, getBuiltins()->anyTypePack, std::nullopt, false});
|
||||
TypeId c = arena.addType(IntersectionType{{a, a}});
|
||||
|
||||
std::shared_ptr<const NormalizedType> n = normalizer.normalize(c);
|
||||
|
@ -760,7 +760,7 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_table_normalizes_sensibly")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "skip_force_normal_on_external_types")
|
||||
{
|
||||
createSomeExternTypes(&frontend);
|
||||
createSomeExternTypes(getFrontend());
|
||||
|
||||
CheckResult result = check(R"(
|
||||
export type t0 = { a: Child }
|
||||
|
@ -781,7 +781,7 @@ export type t0 = (((any)&({_:l0.t0,n0:t0,_G:any,}))&({_:any,}))&(((any)&({_:l0.t
|
|||
|
||||
TEST_CASE_FIXTURE(NormalizeFixture, "unions_of_extern_types")
|
||||
{
|
||||
createSomeExternTypes(&frontend);
|
||||
createSomeExternTypes(getFrontend());
|
||||
CHECK("Parent | Unrelated" == toString(normal("Parent | Unrelated")));
|
||||
CHECK("Parent" == toString(normal("Parent | Child")));
|
||||
CHECK("Parent | Unrelated" == toString(normal("Parent | Child | Unrelated")));
|
||||
|
@ -789,14 +789,14 @@ TEST_CASE_FIXTURE(NormalizeFixture, "unions_of_extern_types")
|
|||
|
||||
TEST_CASE_FIXTURE(NormalizeFixture, "intersections_of_extern_types")
|
||||
{
|
||||
createSomeExternTypes(&frontend);
|
||||
createSomeExternTypes(getFrontend());
|
||||
CHECK("Child" == toString(normal("Parent & Child")));
|
||||
CHECK("never" == toString(normal("Child & Unrelated")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(NormalizeFixture, "narrow_union_of_extern_types_with_intersection")
|
||||
{
|
||||
createSomeExternTypes(&frontend);
|
||||
createSomeExternTypes(getFrontend());
|
||||
CHECK("Child" == toString(normal("(Child | Unrelated) & Child")));
|
||||
}
|
||||
|
||||
|
@ -828,8 +828,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "cyclic_union")
|
|||
{
|
||||
// T where T = any & (number | T)
|
||||
TypeId t = arena.addType(BlockedType{});
|
||||
TypeId u = arena.addType(UnionType{{builtinTypes->numberType, t}});
|
||||
asMutable(t)->ty.emplace<IntersectionType>(IntersectionType{{builtinTypes->anyType, u}});
|
||||
TypeId u = arena.addType(UnionType{{getBuiltins()->numberType, t}});
|
||||
asMutable(t)->ty.emplace<IntersectionType>(IntersectionType{{getBuiltins()->anyType, u}});
|
||||
|
||||
std::shared_ptr<const NormalizedType> nt = normalizer.normalize(t);
|
||||
REQUIRE(nt);
|
||||
|
@ -841,8 +841,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "cyclic_union_of_intersection")
|
|||
{
|
||||
// t1 where t1 = (string & t1) | string
|
||||
TypeId boundTy = arena.addType(BlockedType{});
|
||||
TypeId intersectTy = arena.addType(IntersectionType{{builtinTypes->stringType, boundTy}});
|
||||
TypeId unionTy = arena.addType(UnionType{{builtinTypes->stringType, intersectTy}});
|
||||
TypeId intersectTy = arena.addType(IntersectionType{{getBuiltins()->stringType, boundTy}});
|
||||
TypeId unionTy = arena.addType(UnionType{{getBuiltins()->stringType, intersectTy}});
|
||||
asMutable(boundTy)->reassign(Type{BoundType{unionTy}});
|
||||
|
||||
std::shared_ptr<const NormalizedType> nt = normalizer.normalize(unionTy);
|
||||
|
@ -854,8 +854,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "cyclic_intersection_of_unions")
|
|||
{
|
||||
// t1 where t1 = (string & t1) | string
|
||||
TypeId boundTy = arena.addType(BlockedType{});
|
||||
TypeId unionTy = arena.addType(UnionType{{builtinTypes->stringType, boundTy}});
|
||||
TypeId intersectionTy = arena.addType(IntersectionType{{builtinTypes->stringType, unionTy}});
|
||||
TypeId unionTy = arena.addType(UnionType{{getBuiltins()->stringType, boundTy}});
|
||||
TypeId intersectionTy = arena.addType(IntersectionType{{getBuiltins()->stringType, unionTy}});
|
||||
asMutable(boundTy)->reassign(Type{BoundType{intersectionTy}});
|
||||
|
||||
std::shared_ptr<const NormalizedType> nt = normalizer.normalize(intersectionTy);
|
||||
|
@ -870,7 +870,7 @@ TEST_CASE_FIXTURE(NormalizeFixture, "crazy_metatable")
|
|||
|
||||
TEST_CASE_FIXTURE(NormalizeFixture, "negations_of_extern_types")
|
||||
{
|
||||
createSomeExternTypes(&frontend);
|
||||
createSomeExternTypes(getFrontend());
|
||||
CHECK("(Parent & ~Child) | Unrelated" == toString(normal("(Parent & Not<Child>) | Unrelated")));
|
||||
CHECK("((class & ~Child) | boolean | buffer | function | number | string | table | thread)?" == toString(normal("Not<Child>")));
|
||||
CHECK("never" == toString(normal("Not<Parent> & Child")));
|
||||
|
@ -885,13 +885,13 @@ TEST_CASE_FIXTURE(NormalizeFixture, "negations_of_extern_types")
|
|||
|
||||
TEST_CASE_FIXTURE(NormalizeFixture, "extern_types_and_unknown")
|
||||
{
|
||||
createSomeExternTypes(&frontend);
|
||||
createSomeExternTypes(getFrontend());
|
||||
CHECK("Parent" == toString(normal("Parent & unknown")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(NormalizeFixture, "extern_types_and_never")
|
||||
{
|
||||
createSomeExternTypes(&frontend);
|
||||
createSomeExternTypes(getFrontend());
|
||||
CHECK("never" == toString(normal("Parent & never")));
|
||||
}
|
||||
|
||||
|
@ -923,17 +923,17 @@ TEST_CASE_FIXTURE(NormalizeFixture, "normalize_blocked_types")
|
|||
|
||||
TEST_CASE_FIXTURE(NormalizeFixture, "normalize_is_exactly_number")
|
||||
{
|
||||
std::shared_ptr<const NormalizedType> number = normalizer.normalize(builtinTypes->numberType);
|
||||
std::shared_ptr<const NormalizedType> number = normalizer.normalize(getBuiltins()->numberType);
|
||||
// 1. all types for which Types::number say true for, NormalizedType::isExactlyNumber should say true as well
|
||||
CHECK(Luau::isNumber(builtinTypes->numberType) == number->isExactlyNumber());
|
||||
CHECK(Luau::isNumber(getBuiltins()->numberType) == number->isExactlyNumber());
|
||||
// 2. isExactlyNumber should handle cases like `number & number`
|
||||
TypeId intersection = arena.addType(IntersectionType{{builtinTypes->numberType, builtinTypes->numberType}});
|
||||
TypeId intersection = arena.addType(IntersectionType{{getBuiltins()->numberType, getBuiltins()->numberType}});
|
||||
std::shared_ptr<const NormalizedType> normIntersection = normalizer.normalize(intersection);
|
||||
CHECK(normIntersection->isExactlyNumber());
|
||||
|
||||
// 3. isExactlyNumber should reject things that are definitely not precisely numbers `number | any`
|
||||
|
||||
TypeId yoonion = arena.addType(UnionType{{builtinTypes->anyType, builtinTypes->numberType}});
|
||||
TypeId yoonion = arena.addType(UnionType{{getBuiltins()->anyType, getBuiltins()->numberType}});
|
||||
std::shared_ptr<const NormalizedType> unionIntersection = normalizer.normalize(yoonion);
|
||||
CHECK(!unionIntersection->isExactlyNumber());
|
||||
}
|
||||
|
@ -972,15 +972,15 @@ TEST_CASE_FIXTURE(NormalizeFixture, "read_only_props_3")
|
|||
|
||||
TEST_CASE_FIXTURE(NormalizeFixture, "final_types_are_cached")
|
||||
{
|
||||
std::shared_ptr<const NormalizedType> na1 = normalizer.normalize(builtinTypes->numberType);
|
||||
std::shared_ptr<const NormalizedType> na2 = normalizer.normalize(builtinTypes->numberType);
|
||||
std::shared_ptr<const NormalizedType> na1 = normalizer.normalize(getBuiltins()->numberType);
|
||||
std::shared_ptr<const NormalizedType> na2 = normalizer.normalize(getBuiltins()->numberType);
|
||||
|
||||
CHECK(na1 == na2);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(NormalizeFixture, "non_final_types_can_be_normalized_but_are_not_cached")
|
||||
{
|
||||
TypeId a = arena.freshType(builtinTypes, &globalScope);
|
||||
TypeId a = arena.freshType(getBuiltins(), &globalScope);
|
||||
|
||||
std::shared_ptr<const NormalizedType> na1 = normalizer.normalize(a);
|
||||
std::shared_ptr<const NormalizedType> na2 = normalizer.normalize(a);
|
||||
|
@ -990,8 +990,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "non_final_types_can_be_normalized_but_are_n
|
|||
|
||||
TEST_CASE_FIXTURE(NormalizeFixture, "intersect_with_not_unknown")
|
||||
{
|
||||
TypeId notUnknown = arena.addType(NegationType{builtinTypes->unknownType});
|
||||
TypeId type = arena.addType(IntersectionType{{builtinTypes->numberType, notUnknown}});
|
||||
TypeId notUnknown = arena.addType(NegationType{getBuiltins()->unknownType});
|
||||
TypeId type = arena.addType(IntersectionType{{getBuiltins()->numberType, notUnknown}});
|
||||
std::shared_ptr<const NormalizedType> normalized = normalizer.normalize(type);
|
||||
|
||||
CHECK("never" == toString(normalizer.typeFromNormal(*normalized.get())));
|
||||
|
@ -1030,12 +1030,12 @@ TEST_CASE_FIXTURE(NormalizeFixture, "truthy_table_property_and_optional_table_wi
|
|||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
// { x: ~(false?) }
|
||||
TypeId t1 = arena.addType(TableType{TableType::Props{{"x", builtinTypes->truthyType}}, std::nullopt, TypeLevel{}, TableState::Sealed});
|
||||
TypeId t1 = arena.addType(TableType{TableType::Props{{"x", getBuiltins()->truthyType}}, std::nullopt, TypeLevel{}, TableState::Sealed});
|
||||
|
||||
// { x: number? }?
|
||||
TypeId t2 = arena.addType(UnionType{
|
||||
{arena.addType(TableType{TableType::Props{{"x", builtinTypes->optionalNumberType}}, std::nullopt, TypeLevel{}, TableState::Sealed}),
|
||||
builtinTypes->nilType}
|
||||
{arena.addType(TableType{TableType::Props{{"x", getBuiltins()->optionalNumberType}}, std::nullopt, TypeLevel{}, TableState::Sealed}),
|
||||
getBuiltins()->nilType}
|
||||
});
|
||||
|
||||
TypeId intersection = arena.addType(IntersectionType{{t2, t1}});
|
||||
|
@ -1053,8 +1053,8 @@ TEST_CASE_FIXTURE(NormalizeFixture, "free_type_and_not_truthy")
|
|||
{FFlag::LuauSolverV2, true}, // Only because it affects the stringification of free types
|
||||
};
|
||||
|
||||
TypeId freeTy = arena.freshType(builtinTypes, &globalScope);
|
||||
TypeId notTruthy = arena.addType(NegationType{builtinTypes->truthyType}); // ~~(false?)
|
||||
TypeId freeTy = arena.freshType(getBuiltins(), &globalScope);
|
||||
TypeId notTruthy = arena.addType(NegationType{getBuiltins()->truthyType}); // ~~(false?)
|
||||
|
||||
TypeId intersectionTy = arena.addType(IntersectionType{{freeTy, notTruthy}}); // 'a & ~~(false?)
|
||||
|
||||
|
@ -1073,13 +1073,13 @@ TEST_CASE_FIXTURE(NormalizeFixture, "free_type_intersection_ordering")
|
|||
{FFlag::LuauNormalizationReorderFreeTypeIntersect, true},
|
||||
};
|
||||
|
||||
TypeId freeTy = arena.freshType(builtinTypes, &globalScope);
|
||||
TypeId orderA = arena.addType(IntersectionType{{freeTy, builtinTypes->stringType}});
|
||||
TypeId freeTy = arena.freshType(getBuiltins(), &globalScope);
|
||||
TypeId orderA = arena.addType(IntersectionType{{freeTy, getBuiltins()->stringType}});
|
||||
auto normA = normalizer.normalize(orderA);
|
||||
REQUIRE(normA);
|
||||
CHECK_EQ("'a & string", toString(normalizer.typeFromNormal(*normA)));
|
||||
|
||||
TypeId orderB = arena.addType(IntersectionType{{builtinTypes->stringType, freeTy}});
|
||||
TypeId orderB = arena.addType(IntersectionType{{getBuiltins()->stringType, freeTy}});
|
||||
auto normB = normalizer.normalize(orderB);
|
||||
REQUIRE(normB);
|
||||
// Prior to LuauNormalizationReorderFreeTypeIntersect this became `never` :skull:
|
||||
|
|
|
@ -21,30 +21,30 @@ struct SimplifyFixture : Fixture
|
|||
|
||||
ToStringOptions opts;
|
||||
|
||||
Scope scope{builtinTypes->anyTypePack};
|
||||
Scope scope{getBuiltins()->anyTypePack};
|
||||
|
||||
const TypeId anyTy = builtinTypes->anyType;
|
||||
const TypeId unknownTy = builtinTypes->unknownType;
|
||||
const TypeId neverTy = builtinTypes->neverType;
|
||||
const TypeId errorTy = builtinTypes->errorType;
|
||||
const TypeId anyTy = getBuiltins()->anyType;
|
||||
const TypeId unknownTy = getBuiltins()->unknownType;
|
||||
const TypeId neverTy = getBuiltins()->neverType;
|
||||
const TypeId errorTy = getBuiltins()->errorType;
|
||||
|
||||
const TypeId functionTy = builtinTypes->functionType;
|
||||
const TypeId tableTy = builtinTypes->tableType;
|
||||
const TypeId functionTy = getBuiltins()->functionType;
|
||||
const TypeId tableTy = getBuiltins()->tableType;
|
||||
|
||||
const TypeId numberTy = builtinTypes->numberType;
|
||||
const TypeId stringTy = builtinTypes->stringType;
|
||||
const TypeId booleanTy = builtinTypes->booleanType;
|
||||
const TypeId nilTy = builtinTypes->nilType;
|
||||
const TypeId numberTy = getBuiltins()->numberType;
|
||||
const TypeId stringTy = getBuiltins()->stringType;
|
||||
const TypeId booleanTy = getBuiltins()->booleanType;
|
||||
const TypeId nilTy = getBuiltins()->nilType;
|
||||
|
||||
const TypeId classTy = builtinTypes->externType;
|
||||
const TypeId classTy = getBuiltins()->externType;
|
||||
|
||||
const TypeId trueTy = builtinTypes->trueType;
|
||||
const TypeId falseTy = builtinTypes->falseType;
|
||||
const TypeId trueTy = getBuiltins()->trueType;
|
||||
const TypeId falseTy = getBuiltins()->falseType;
|
||||
|
||||
const TypeId truthyTy = builtinTypes->truthyType;
|
||||
const TypeId falsyTy = builtinTypes->falsyType;
|
||||
const TypeId truthyTy = getBuiltins()->truthyType;
|
||||
const TypeId falsyTy = getBuiltins()->falsyType;
|
||||
|
||||
const TypeId freeTy = freshType(arena, builtinTypes, &scope);
|
||||
const TypeId freeTy = freshType(arena, getBuiltins(), &scope);
|
||||
const TypeId genericTy = arena->addType(GenericType{});
|
||||
const TypeId blockedTy = arena->addType(BlockedType{});
|
||||
const TypeId pendingTy = arena->addType(PendingExpansionType{{}, {}, {}, {}});
|
||||
|
@ -55,7 +55,7 @@ struct SimplifyFixture : Fixture
|
|||
const TypePackId emptyTypePack = arena->addTypePack({});
|
||||
|
||||
const TypeId fn1Ty = arena->addType(FunctionType{emptyTypePack, emptyTypePack});
|
||||
const TypeId fn2Ty = arena->addType(FunctionType{builtinTypes->anyTypePack, emptyTypePack});
|
||||
const TypeId fn2Ty = arena->addType(FunctionType{getBuiltins()->anyTypePack, emptyTypePack});
|
||||
|
||||
TypeId parentClassTy = nullptr;
|
||||
TypeId childClassTy = nullptr;
|
||||
|
@ -66,17 +66,17 @@ struct SimplifyFixture : Fixture
|
|||
|
||||
SimplifyFixture()
|
||||
{
|
||||
createSomeExternTypes(&frontend);
|
||||
createSomeExternTypes(getFrontend());
|
||||
|
||||
parentClassTy = frontend.globals.globalScope->linearSearchForBinding("Parent")->typeId;
|
||||
childClassTy = frontend.globals.globalScope->linearSearchForBinding("Child")->typeId;
|
||||
anotherChildClassTy = frontend.globals.globalScope->linearSearchForBinding("AnotherChild")->typeId;
|
||||
unrelatedClassTy = frontend.globals.globalScope->linearSearchForBinding("Unrelated")->typeId;
|
||||
parentClassTy = getFrontend().globals.globalScope->linearSearchForBinding("Parent")->typeId;
|
||||
childClassTy = getFrontend().globals.globalScope->linearSearchForBinding("Child")->typeId;
|
||||
anotherChildClassTy = getFrontend().globals.globalScope->linearSearchForBinding("AnotherChild")->typeId;
|
||||
unrelatedClassTy = getFrontend().globals.globalScope->linearSearchForBinding("Unrelated")->typeId;
|
||||
}
|
||||
|
||||
TypeId intersect(TypeId a, TypeId b)
|
||||
{
|
||||
return simplifyIntersection(builtinTypes, arena, a, b).result;
|
||||
return simplifyIntersection(getBuiltins(), arena, a, b).result;
|
||||
}
|
||||
|
||||
std::string intersectStr(TypeId a, TypeId b)
|
||||
|
@ -110,7 +110,7 @@ struct SimplifyFixture : Fixture
|
|||
|
||||
TypeId union_(TypeId a, TypeId b)
|
||||
{
|
||||
return simplifyUnion(builtinTypes, arena, a, b).result;
|
||||
return simplifyUnion(getBuiltins(), arena, a, b).result;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -476,7 +476,7 @@ TEST_CASE_FIXTURE(SimplifyFixture, "union")
|
|||
CHECK(nilTy == intersect(t1, nilTy));
|
||||
// CHECK(nilTy == intersect(nilTy, t1)); // TODO?
|
||||
|
||||
CHECK(builtinTypes->stringType == intersect(builtinTypes->optionalStringType, truthyTy));
|
||||
CHECK(getBuiltins()->stringType == intersect(getBuiltins()->optionalStringType, truthyTy));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(SimplifyFixture, "two_unions")
|
||||
|
@ -611,12 +611,12 @@ TEST_CASE_FIXTURE(SimplifyFixture, "bound_intersected_by_itself_should_be_itself
|
|||
TEST_CASE_FIXTURE(SimplifyFixture, "cyclic_never_union_and_string")
|
||||
{
|
||||
// t1 where t1 = never | t1
|
||||
TypeId leftType = arena->addType(UnionType{{builtinTypes->neverType, builtinTypes->neverType}});
|
||||
TypeId leftType = arena->addType(UnionType{{getBuiltins()->neverType, getBuiltins()->neverType}});
|
||||
UnionType* leftUnion = getMutable<UnionType>(leftType);
|
||||
REQUIRE(leftUnion);
|
||||
leftUnion->options[0] = leftType;
|
||||
|
||||
CHECK(builtinTypes->stringType == union_(leftType, builtinTypes->stringType));
|
||||
CHECK(getBuiltins()->stringType == union_(leftType, getBuiltins()->stringType));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -15,7 +15,7 @@ struct ToDotClassFixture : Fixture
|
|||
{
|
||||
ToDotClassFixture()
|
||||
{
|
||||
TypeArena& arena = frontend.globals.globalTypes;
|
||||
TypeArena& arena = getFrontend().globals.globalTypes;
|
||||
|
||||
unfreeze(arena);
|
||||
|
||||
|
@ -23,17 +23,17 @@ struct ToDotClassFixture : Fixture
|
|||
|
||||
TypeId baseClassInstanceType = arena.addType(ExternType{"BaseClass", {}, std::nullopt, baseClassMetaType, {}, {}, "Test", {}});
|
||||
getMutable<ExternType>(baseClassInstanceType)->props = {
|
||||
{"BaseField", {builtinTypes->numberType}},
|
||||
{"BaseField", {getBuiltins()->numberType}},
|
||||
};
|
||||
frontend.globals.globalScope->exportedTypeBindings["BaseClass"] = TypeFun{{}, baseClassInstanceType};
|
||||
getFrontend().globals.globalScope->exportedTypeBindings["BaseClass"] = TypeFun{{}, baseClassInstanceType};
|
||||
|
||||
TypeId childClassInstanceType = arena.addType(ExternType{"ChildClass", {}, baseClassInstanceType, std::nullopt, {}, {}, "Test", {}});
|
||||
getMutable<ExternType>(childClassInstanceType)->props = {
|
||||
{"ChildField", {builtinTypes->stringType}},
|
||||
{"ChildField", {getBuiltins()->stringType}},
|
||||
};
|
||||
frontend.globals.globalScope->exportedTypeBindings["ChildClass"] = TypeFun{{}, childClassInstanceType};
|
||||
getFrontend().globals.globalScope->exportedTypeBindings["ChildClass"] = TypeFun{{}, childClassInstanceType};
|
||||
|
||||
for (const auto& [name, ty] : frontend.globals.globalScope->exportedTypeBindings)
|
||||
for (const auto& [name, ty] : getFrontend().globals.globalScope->exportedTypeBindings)
|
||||
persist(ty.type);
|
||||
|
||||
freeze(arena);
|
||||
|
@ -48,35 +48,35 @@ TEST_CASE_FIXTURE(Fixture, "primitive")
|
|||
R"(digraph graphname {
|
||||
n1 [label="nil"];
|
||||
})",
|
||||
toDot(builtinTypes->nilType)
|
||||
toDot(getBuiltins()->nilType)
|
||||
);
|
||||
|
||||
CHECK_EQ(
|
||||
R"(digraph graphname {
|
||||
n1 [label="number"];
|
||||
})",
|
||||
toDot(builtinTypes->numberType)
|
||||
toDot(getBuiltins()->numberType)
|
||||
);
|
||||
|
||||
CHECK_EQ(
|
||||
R"(digraph graphname {
|
||||
n1 [label="any"];
|
||||
})",
|
||||
toDot(builtinTypes->anyType)
|
||||
toDot(getBuiltins()->anyType)
|
||||
);
|
||||
|
||||
CHECK_EQ(
|
||||
R"(digraph graphname {
|
||||
n1 [label="unknown"];
|
||||
})",
|
||||
toDot(builtinTypes->unknownType)
|
||||
toDot(getBuiltins()->unknownType)
|
||||
);
|
||||
|
||||
CHECK_EQ(
|
||||
R"(digraph graphname {
|
||||
n1 [label="never"];
|
||||
})",
|
||||
toDot(builtinTypes->neverType)
|
||||
toDot(getBuiltins()->neverType)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -90,28 +90,28 @@ TEST_CASE_FIXTURE(Fixture, "no_duplicatePrimitives")
|
|||
R"(digraph graphname {
|
||||
n1 [label="PrimitiveType number"];
|
||||
})",
|
||||
toDot(builtinTypes->numberType, opts)
|
||||
toDot(getBuiltins()->numberType, opts)
|
||||
);
|
||||
|
||||
CHECK_EQ(
|
||||
R"(digraph graphname {
|
||||
n1 [label="AnyType 1"];
|
||||
})",
|
||||
toDot(builtinTypes->anyType, opts)
|
||||
toDot(getBuiltins()->anyType, opts)
|
||||
);
|
||||
|
||||
CHECK_EQ(
|
||||
R"(digraph graphname {
|
||||
n1 [label="UnknownType 1"];
|
||||
})",
|
||||
toDot(builtinTypes->unknownType, opts)
|
||||
toDot(getBuiltins()->unknownType, opts)
|
||||
);
|
||||
|
||||
CHECK_EQ(
|
||||
R"(digraph graphname {
|
||||
n1 [label="NeverType 1"];
|
||||
})",
|
||||
toDot(builtinTypes->neverType, opts)
|
||||
toDot(getBuiltins()->neverType, opts)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ TEST_CASE_FIXTURE(Fixture, "bound")
|
|||
{
|
||||
TypeArena arena;
|
||||
|
||||
TypeId ty = arena.addType(BoundType{builtinTypes->numberType});
|
||||
TypeId ty = arena.addType(BoundType{getBuiltins()->numberType});
|
||||
|
||||
ToDotOptions opts;
|
||||
opts.showPointers = false;
|
||||
|
@ -216,7 +216,7 @@ TEST_CASE_FIXTURE(Fixture, "intersection")
|
|||
{
|
||||
TypeArena arena;
|
||||
|
||||
TypeId ty = arena.addType(IntersectionType{{builtinTypes->stringType, builtinTypes->numberType}});
|
||||
TypeId ty = arena.addType(IntersectionType{{getBuiltins()->stringType, getBuiltins()->numberType}});
|
||||
|
||||
ToDotOptions opts;
|
||||
opts.showPointers = false;
|
||||
|
@ -322,7 +322,7 @@ n3 [label="TableType 3"];
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "free")
|
||||
{
|
||||
Type type{TypeVariant{FreeType{TypeLevel{0, 0}, builtinTypes->neverType, builtinTypes->unknownType}}};
|
||||
Type type{TypeVariant{FreeType{TypeLevel{0, 0}, getBuiltins()->neverType, getBuiltins()->unknownType}}};
|
||||
ToDotOptions opts;
|
||||
opts.showPointers = false;
|
||||
CHECK_EQ(
|
||||
|
@ -339,7 +339,7 @@ TEST_CASE_FIXTURE(Fixture, "free_with_constraints")
|
|||
{FFlag::LuauSolverV2, true},
|
||||
};
|
||||
|
||||
Type type{TypeVariant{FreeType{nullptr, builtinTypes->numberType, builtinTypes->optionalNumberType}}};
|
||||
Type type{TypeVariant{FreeType{nullptr, getBuiltins()->numberType, getBuiltins()->optionalNumberType}}};
|
||||
|
||||
ToDotOptions opts;
|
||||
opts.showPointers = false;
|
||||
|
@ -467,7 +467,7 @@ n1 [label="GenericTypePack T"];
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "bound_pack")
|
||||
{
|
||||
TypePackVar pack{TypePackVariant{TypePack{{builtinTypes->numberType}, {}}}};
|
||||
TypePackVar pack{TypePackVariant{TypePack{{getBuiltins()->numberType}, {}}}};
|
||||
TypePackVar bound{TypePackVariant{BoundTypePack{&pack}}};
|
||||
|
||||
ToDotOptions opts;
|
||||
|
@ -489,7 +489,7 @@ TEST_CASE_FIXTURE(Fixture, "bound_table")
|
|||
TypeArena arena;
|
||||
|
||||
TypeId ty = arena.addType(TableType{});
|
||||
getMutable<TableType>(ty)->props["x"] = {builtinTypes->numberType};
|
||||
getMutable<TableType>(ty)->props["x"] = {getBuiltins()->numberType};
|
||||
|
||||
TypeId boundTy = arena.addType(TableType{});
|
||||
getMutable<TableType>(boundTy)->boundTo = ty;
|
||||
|
@ -539,7 +539,7 @@ n5 [label="SingletonType boolean: false"];
|
|||
TEST_CASE_FIXTURE(Fixture, "negation")
|
||||
{
|
||||
TypeArena arena;
|
||||
TypeId t = arena.addType(NegationType{builtinTypes->stringType});
|
||||
TypeId t = arena.addType(NegationType{getBuiltins()->stringType});
|
||||
|
||||
ToDotOptions opts;
|
||||
opts.showPointers = false;
|
||||
|
|
|
@ -14,9 +14,8 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauRecursiveTypeParameterRestriction)
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauAttributeSyntax)
|
||||
LUAU_FASTFLAG(LuauFixEmptyTypePackStringification)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
|
||||
TEST_SUITE_BEGIN("ToString");
|
||||
|
||||
|
@ -232,27 +231,27 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "exhaustive_toString_of_cyclic_table")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "intersection_parenthesized_only_if_needed")
|
||||
{
|
||||
auto utv = Type{UnionType{{builtinTypes->numberType, builtinTypes->stringType}}};
|
||||
auto itv = Type{IntersectionType{{&utv, builtinTypes->booleanType}}};
|
||||
auto utv = Type{UnionType{{getBuiltins()->numberType, getBuiltins()->stringType}}};
|
||||
auto itv = Type{IntersectionType{{&utv, getBuiltins()->booleanType}}};
|
||||
|
||||
CHECK_EQ(toString(&itv), "(number | string) & boolean");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "union_parenthesized_only_if_needed")
|
||||
{
|
||||
auto itv = Type{IntersectionType{{builtinTypes->numberType, builtinTypes->stringType}}};
|
||||
auto utv = Type{UnionType{{&itv, builtinTypes->booleanType}}};
|
||||
auto itv = Type{IntersectionType{{getBuiltins()->numberType, getBuiltins()->stringType}}};
|
||||
auto utv = Type{UnionType{{&itv, getBuiltins()->booleanType}}};
|
||||
|
||||
CHECK_EQ(toString(&utv), "(number & string) | boolean");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "functions_are_always_parenthesized_in_unions_or_intersections")
|
||||
{
|
||||
auto stringAndNumberPack = TypePackVar{TypePack{{builtinTypes->stringType, builtinTypes->numberType}}};
|
||||
auto numberAndStringPack = TypePackVar{TypePack{{builtinTypes->numberType, builtinTypes->stringType}}};
|
||||
auto stringAndNumberPack = TypePackVar{TypePack{{getBuiltins()->stringType, getBuiltins()->numberType}}};
|
||||
auto numberAndStringPack = TypePackVar{TypePack{{getBuiltins()->numberType, getBuiltins()->stringType}}};
|
||||
|
||||
auto sn2ns = Type{FunctionType{&stringAndNumberPack, &numberAndStringPack}};
|
||||
auto ns2sn = Type{FunctionType(frontend.globals.globalScope->level, &numberAndStringPack, &stringAndNumberPack)};
|
||||
auto ns2sn = Type{FunctionType(getFrontend().globals.globalScope->level, &numberAndStringPack, &stringAndNumberPack)};
|
||||
|
||||
auto utv = Type{UnionType{{&ns2sn, &sn2ns}}};
|
||||
auto itv = Type{IntersectionType{{&ns2sn, &sn2ns}}};
|
||||
|
@ -341,7 +340,7 @@ TEST_CASE_FIXTURE(Fixture, "quit_stringifying_table_type_when_length_is_exceeded
|
|||
{
|
||||
TableType ttv{};
|
||||
for (char c : std::string("abcdefghijklmno"))
|
||||
ttv.props[std::string(1, c)] = {builtinTypes->numberType};
|
||||
ttv.props[std::string(1, c)] = {getBuiltins()->numberType};
|
||||
|
||||
Type tv{ttv};
|
||||
|
||||
|
@ -358,7 +357,7 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_is_still_capped_when_exhaust
|
|||
{
|
||||
TableType ttv{};
|
||||
for (char c : std::string("abcdefg"))
|
||||
ttv.props[std::string(1, c)] = {builtinTypes->numberType};
|
||||
ttv.props[std::string(1, c)] = {getBuiltins()->numberType};
|
||||
|
||||
Type tv{ttv};
|
||||
|
||||
|
@ -444,7 +443,7 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_correctly_use_matching_table
|
|||
{
|
||||
TableType ttv{TableState::Sealed, TypeLevel{}};
|
||||
for (char c : std::string("abcdefghij"))
|
||||
ttv.props[std::string(1, c)] = {builtinTypes->numberType};
|
||||
ttv.props[std::string(1, c)] = {getBuiltins()->numberType};
|
||||
|
||||
Type tv{ttv};
|
||||
|
||||
|
@ -458,7 +457,7 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_correctly_use_matching_table
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_union_type_bails_early")
|
||||
{
|
||||
Type tv{UnionType{{builtinTypes->stringType, builtinTypes->numberType}}};
|
||||
Type tv{UnionType{{getBuiltins()->stringType, getBuiltins()->numberType}}};
|
||||
UnionType* utv = getMutable<UnionType>(&tv);
|
||||
utv->options.push_back(&tv);
|
||||
utv->options.push_back(&tv);
|
||||
|
@ -479,11 +478,11 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_intersection_type_bails_early")
|
|||
TEST_CASE_FIXTURE(Fixture, "stringifying_array_uses_array_syntax")
|
||||
{
|
||||
TableType ttv{TableState::Sealed, TypeLevel{}};
|
||||
ttv.indexer = TableIndexer{builtinTypes->numberType, builtinTypes->stringType};
|
||||
ttv.indexer = TableIndexer{getBuiltins()->numberType, getBuiltins()->stringType};
|
||||
|
||||
CHECK_EQ("{string}", toString(Type{ttv}));
|
||||
|
||||
ttv.props["A"] = {builtinTypes->numberType};
|
||||
ttv.props["A"] = {getBuiltins()->numberType};
|
||||
if (FFlag::LuauSolverV2)
|
||||
CHECK_EQ("{ [number]: string, A: number }", toString(Type{ttv}));
|
||||
else
|
||||
|
@ -632,15 +631,15 @@ TEST_CASE_FIXTURE(Fixture, "toString_the_boundTo_table_type_contained_within_a_T
|
|||
Type tv1{TableType{}};
|
||||
TableType* ttv = getMutable<TableType>(&tv1);
|
||||
ttv->state = TableState::Sealed;
|
||||
ttv->props["hello"] = {builtinTypes->numberType};
|
||||
ttv->props["world"] = {builtinTypes->numberType};
|
||||
ttv->props["hello"] = {getBuiltins()->numberType};
|
||||
ttv->props["world"] = {getBuiltins()->numberType};
|
||||
|
||||
TypePackVar tpv1{TypePack{{&tv1}}};
|
||||
|
||||
Type tv2{TableType{}};
|
||||
TableType* bttv = getMutable<TableType>(&tv2);
|
||||
bttv->state = TableState::Free;
|
||||
bttv->props["hello"] = {builtinTypes->numberType};
|
||||
bttv->props["hello"] = {getBuiltins()->numberType};
|
||||
bttv->boundTo = &tv1;
|
||||
|
||||
TypePackVar tpv2{TypePack{{&tv2}}};
|
||||
|
@ -661,10 +660,10 @@ TEST_CASE_FIXTURE(Fixture, "toString_the_boundTo_table_type_contained_within_a_T
|
|||
TEST_CASE_FIXTURE(Fixture, "no_parentheses_around_return_type_if_pack_has_an_empty_head_link")
|
||||
{
|
||||
TypeArena arena;
|
||||
TypePackId realTail = arena.addTypePack({builtinTypes->stringType});
|
||||
TypePackId realTail = arena.addTypePack({getBuiltins()->stringType});
|
||||
TypePackId emptyTail = arena.addTypePack({}, realTail);
|
||||
|
||||
TypePackId argList = arena.addTypePack({builtinTypes->stringType});
|
||||
TypePackId argList = arena.addTypePack({getBuiltins()->stringType});
|
||||
|
||||
TypeId functionType = arena.addType(FunctionType{argList, emptyTail});
|
||||
|
||||
|
@ -878,7 +877,7 @@ TEST_CASE_FIXTURE(Fixture, "tostring_unsee_ttv_if_array")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "tostring_error_mismatch")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
|
@ -954,12 +953,12 @@ TEST_CASE_FIXTURE(Fixture, "cycle_rooted_in_a_pack")
|
|||
{
|
||||
TypeArena arena;
|
||||
|
||||
TypePackId thePack = arena.addTypePack({builtinTypes->numberType, builtinTypes->numberType});
|
||||
TypePackId thePack = arena.addTypePack({getBuiltins()->numberType, getBuiltins()->numberType});
|
||||
TypePack* packPtr = getMutable<TypePack>(thePack);
|
||||
REQUIRE(packPtr);
|
||||
|
||||
const TableType::Props theProps = {
|
||||
{"BaseField", Property::readonly(builtinTypes->unknownType)},
|
||||
{"BaseField", Property::readonly(getBuiltins()->unknownType)},
|
||||
{"BaseMethod", Property::readonly(arena.addType(FunctionType{thePack, arena.addTypePack({})}))}
|
||||
};
|
||||
|
||||
|
@ -978,7 +977,7 @@ TEST_CASE_FIXTURE(Fixture, "correct_stringification_user_defined_type_functions"
|
|||
TypeFunction user{"user", nullptr};
|
||||
TypeFunctionInstanceType tftt{
|
||||
NotNull{&user},
|
||||
std::vector<TypeId>{builtinTypes->numberType}, // Type Function Arguments
|
||||
std::vector<TypeId>{getBuiltins()->numberType}, // Type Function Arguments
|
||||
{},
|
||||
{AstName{"woohoo"}}, // Type Function Name
|
||||
{},
|
||||
|
|
|
@ -14,9 +14,9 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_DYNAMIC_FASTINT(LuauTypeFamilyApplicationCartesianProductLimit)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauErrorSuppressionTypeFunctionArgs)
|
||||
|
||||
struct TypeFunctionFixture : Fixture
|
||||
|
@ -55,14 +55,14 @@ struct TypeFunctionFixture : Fixture
|
|||
}
|
||||
};
|
||||
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
TypeId t = frontend.globals.globalTypes.addType(GenericType{"T"});
|
||||
unfreeze(getFrontend().globals.globalTypes);
|
||||
TypeId t = getFrontend().globals.globalTypes.addType(GenericType{"T"});
|
||||
GenericTypeDefinition genericT{t};
|
||||
|
||||
ScopePtr globalScope = frontend.globals.globalScope;
|
||||
ScopePtr globalScope = getFrontend().globals.globalScope;
|
||||
globalScope->exportedTypeBindings["Swap"] =
|
||||
TypeFun{{genericT}, frontend.globals.globalTypes.addType(TypeFunctionInstanceType{NotNull{&swapFunction}, {t}, {}})};
|
||||
freeze(frontend.globals.globalTypes);
|
||||
TypeFun{{genericT}, getFrontend().globals.globalTypes.addType(TypeFunctionInstanceType{NotNull{&swapFunction}, {t}, {}})};
|
||||
freeze(getFrontend().globals.globalTypes);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -349,7 +349,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_works")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type MyObject = { x: number, y: number, z: number }
|
||||
|
@ -372,7 +372,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_works_with_metatables")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local metatable = { __index = {w = 1} }
|
||||
|
@ -431,7 +431,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_errors_if_it_has_nontabl
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_string_indexer")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
@ -464,7 +464,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_function_common_subset_if_union_o
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type MyObject = { x: number, y: number, z: number }
|
||||
|
@ -502,7 +502,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_works")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type MyObject = { x: number, y: number, z: number }
|
||||
|
@ -525,7 +525,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_ignores_metatables")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local metatable = { __index = {w = 1} }
|
||||
|
@ -568,7 +568,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_function_common_subset_if_unio
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type MyObject = { x: number, y: number, z: number }
|
||||
|
@ -606,7 +606,7 @@ TEST_CASE_FIXTURE(ExternTypeFixture, "keyof_type_function_works_on_extern_types"
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type KeysOfMyObject = keyof<BaseClass>
|
||||
|
@ -1005,7 +1005,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "index_type_function_works")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type MyObject = {a: string, b: number, c: boolean}
|
||||
|
@ -1306,7 +1306,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawget_type_function_works")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type MyObject = {a: string, b: number, c: boolean}
|
||||
|
@ -1588,15 +1588,15 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "getmetatable_returns_correct_metatable_for_u
|
|||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
const PrimitiveType* stringType = get<PrimitiveType>(builtinTypes->stringType);
|
||||
const PrimitiveType* stringType = get<PrimitiveType>(getBuiltins()->stringType);
|
||||
REQUIRE(stringType->metatable);
|
||||
|
||||
TypeArena arena = TypeArena{};
|
||||
|
||||
std::string expected1 = toString(arena.addType(UnionType{{*stringType->metatable, builtinTypes->emptyTableType}}), {true});
|
||||
std::string expected1 = toString(arena.addType(UnionType{{*stringType->metatable, getBuiltins()->emptyTableType}}), {true});
|
||||
CHECK_EQ(toString(requireTypeAlias("Metatable"), {true}), expected1);
|
||||
|
||||
std::string expected2 = toString(arena.addType(IntersectionType{{*stringType->metatable, builtinTypes->emptyTableType}}), {true});
|
||||
std::string expected2 = toString(arena.addType(IntersectionType{{*stringType->metatable, getBuiltins()->emptyTableType}}), {true});
|
||||
CHECK_EQ(toString(requireTypeAlias("IntersectMetatable"), {true}), expected2);
|
||||
}
|
||||
|
||||
|
@ -1612,7 +1612,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "getmetatable_returns_correct_metatable_for_s
|
|||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
const PrimitiveType* stringType = get<PrimitiveType>(builtinTypes->stringType);
|
||||
const PrimitiveType* stringType = get<PrimitiveType>(getBuiltins()->stringType);
|
||||
REQUIRE(stringType->metatable);
|
||||
|
||||
std::string expected = toString(*stringType->metatable, {true});
|
||||
|
@ -1712,26 +1712,26 @@ struct TFFixture
|
|||
NotNull<TypeArena> arena{&arena_};
|
||||
|
||||
BuiltinTypes builtinTypes_;
|
||||
NotNull<BuiltinTypes> builtinTypes{&builtinTypes_};
|
||||
NotNull<BuiltinTypes> getBuiltins(){ return NotNull{&builtinTypes_};}
|
||||
|
||||
ScopePtr globalScope = std::make_shared<Scope>(builtinTypes->anyTypePack);
|
||||
ScopePtr globalScope = std::make_shared<Scope>(getBuiltins()->anyTypePack);
|
||||
|
||||
InternalErrorReporter ice;
|
||||
UnifierSharedState unifierState{&ice};
|
||||
SimplifierPtr simplifier = EqSatSimplification::newSimplifier(arena, builtinTypes);
|
||||
Normalizer normalizer{arena, builtinTypes, NotNull{&unifierState}};
|
||||
SimplifierPtr simplifier = EqSatSimplification::newSimplifier(arena, getBuiltins());
|
||||
Normalizer normalizer{arena, getBuiltins(), NotNull{&unifierState}};
|
||||
TypeCheckLimits limits;
|
||||
TypeFunctionRuntime runtime{NotNull{&ice}, NotNull{&limits}};
|
||||
|
||||
const ScopedFastFlag sff[1] = {
|
||||
{FFlag::LuauEagerGeneralization3, true},
|
||||
{FFlag::LuauEagerGeneralization4, true},
|
||||
};
|
||||
|
||||
BuiltinTypeFunctions builtinTypeFunctions;
|
||||
|
||||
TypeFunctionContext tfc{
|
||||
arena,
|
||||
builtinTypes,
|
||||
getBuiltins(),
|
||||
NotNull{globalScope.get()},
|
||||
NotNull{simplifier.get()},
|
||||
NotNull{&normalizer},
|
||||
|
@ -1745,7 +1745,7 @@ TEST_CASE_FIXTURE(TFFixture, "refine<G, ~(false?)>")
|
|||
{
|
||||
TypeId g = arena->addType(GenericType{globalScope.get(), Polarity::Negative});
|
||||
|
||||
TypeId refineTy = arena->addType(TypeFunctionInstanceType{builtinTypeFunctions.refineFunc, {g, builtinTypes->truthyType}});
|
||||
TypeId refineTy = arena->addType(TypeFunctionInstanceType{builtinTypeFunctions.refineFunc, {g, getBuiltins()->truthyType}});
|
||||
|
||||
FunctionGraphReductionResult res = reduceTypeFunctions(refineTy, Location{}, tfc);
|
||||
|
||||
|
@ -1758,8 +1758,8 @@ TEST_CASE_FIXTURE(TFFixture, "refine<G, ~(false?)>")
|
|||
|
||||
TEST_CASE_FIXTURE(TFFixture, "or<'a, 'b>")
|
||||
{
|
||||
TypeId aType = arena->freshType(builtinTypes, globalScope.get());
|
||||
TypeId bType = arena->freshType(builtinTypes, globalScope.get());
|
||||
TypeId aType = arena->freshType(getBuiltins(), globalScope.get());
|
||||
TypeId bType = arena->freshType(getBuiltins(), globalScope.get());
|
||||
|
||||
TypeId orType = arena->addType(TypeFunctionInstanceType{builtinTypeFunctions.orFunc, {aType, bType}});
|
||||
|
||||
|
|
|
@ -9,9 +9,11 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauUserTypeFunctionAliases)
|
||||
LUAU_FASTFLAG(LuauFollowTypeAlias)
|
||||
LUAU_FASTFLAG(LuauFollowExistingTypeFunction)
|
||||
|
||||
TEST_SUITE_BEGIN("UserDefinedTypeFunctionTests");
|
||||
|
||||
|
@ -351,7 +353,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_strsingleton_methods_work")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_union_serialization_works")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_union(arg)
|
||||
|
@ -371,7 +373,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_union_serialization_works")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_optional_works")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function numberhuh()
|
||||
|
@ -390,7 +392,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_optional_works")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_optional_works_on_unions")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function foobar()
|
||||
|
@ -412,7 +414,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_union_methods_work")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getunion()
|
||||
|
@ -441,7 +443,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_union_methods_work")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_intersection_serialization_works")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_intersection(arg)
|
||||
|
@ -463,7 +465,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_intersection_methods_work")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getintersection()
|
||||
|
@ -498,7 +500,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_intersection_methods_work")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_negation_methods_work")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getnegation()
|
||||
|
@ -547,7 +549,7 @@ local function notok(idx: fail<number>): never return idx end
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_table_serialization_works")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function serialize_table(arg)
|
||||
|
@ -567,7 +569,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_table_serialization_works")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_table_methods_work")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function gettable()
|
||||
|
@ -606,7 +608,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_table_methods_work")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_metatable_methods_work")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getmetatable()
|
||||
|
@ -656,7 +658,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_function_methods_work")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getfunction()
|
||||
|
@ -717,7 +719,7 @@ TEST_CASE_FIXTURE(ExternTypeFixture, "udtf_class_serialization_works2")
|
|||
TEST_CASE_FIXTURE(ExternTypeFixture, "udtf_class_methods_works")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getclass(arg)
|
||||
|
@ -739,7 +741,7 @@ TEST_CASE_FIXTURE(ExternTypeFixture, "udtf_class_methods_works")
|
|||
TEST_CASE_FIXTURE(ExternTypeFixture, "write_of_readonly_is_nil")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getclass(arg)
|
||||
|
@ -766,7 +768,7 @@ TEST_CASE_FIXTURE(ExternTypeFixture, "write_of_readonly_is_nil")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_check_mutability")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function checkmut()
|
||||
|
@ -798,7 +800,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_check_mutability")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_copy_works")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function getcopy()
|
||||
|
@ -984,7 +986,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_function_type_cant_call_get_props")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_calling_each_other")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function foo()
|
||||
|
@ -1005,7 +1007,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_calling_each_other")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_calling_each_other_2")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function first(arg)
|
||||
|
@ -1058,7 +1060,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_calling_each_other_3")
|
|||
TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_calling_each_other_unordered")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function bar()
|
||||
|
@ -1124,7 +1126,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_optionify")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function optionify(tbl)
|
||||
|
@ -1178,7 +1180,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_recursion_and_gc")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function foo(tbl)
|
||||
|
@ -1243,7 +1245,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_strip_indexer")
|
|||
if (!FFlag::LuauSolverV2)
|
||||
return;
|
||||
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function stripindexer(tbl)
|
||||
|
@ -1332,7 +1334,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tag_field")
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -1410,7 +1412,7 @@ local a: concat<'first', 'second'>
|
|||
return {}
|
||||
)";
|
||||
|
||||
CheckResult aResult = frontend.check("game/A");
|
||||
CheckResult aResult = getFrontend().check("game/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(aResult);
|
||||
|
||||
CHECK(toString(requireType("game/A", "a")) == R"("firstsecond")");
|
||||
|
@ -1463,7 +1465,7 @@ local a: concat<'first', 'second'>
|
|||
return {}
|
||||
)";
|
||||
|
||||
CheckResult aResult = frontend.check("game/A");
|
||||
CheckResult aResult = getFrontend().check("game/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(aResult);
|
||||
|
||||
CHECK(toString(requireType("game/A", "a")) == R"("firstsecond")");
|
||||
|
@ -2002,7 +2004,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_eqsat_opaque")
|
|||
)");
|
||||
TypeArena arena;
|
||||
auto ty = requireType("v");
|
||||
auto simplifier = EqSatSimplification::newSimplifier(NotNull{&arena}, frontend.builtinTypes);
|
||||
auto simplifier = EqSatSimplification::newSimplifier(NotNull{&arena}, getBuiltins());
|
||||
auto simplified = eqSatSimplify(NotNull{simplifier.get()}, ty);
|
||||
REQUIRE(simplified);
|
||||
CHECK_EQ("t0<number & string>", toString(simplified->result)); // NOLINT(bugprone-unchecked-optional-access)
|
||||
|
@ -2012,7 +2014,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_singleton_equality_bool")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
// FIXME: CLI-151985
|
||||
// This test breaks because we can't see that eq<type?, b> is already fully reduced.
|
||||
|
@ -2035,7 +2037,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "udtf_singleton_equality_string")
|
|||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
// FIXME: CLI-151985
|
||||
// This test breaks because we can't see that eq<type?, b> is already fully reduced.
|
||||
|
@ -2335,7 +2337,7 @@ local x: foo<{ a: number }> = 2
|
|||
return {}
|
||||
)";
|
||||
|
||||
CheckResult aResult = frontend.check("game/A");
|
||||
CheckResult aResult = getFrontend().check("game/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(aResult);
|
||||
|
||||
CHECK(toString(requireType("game/A", "x")) == R"(number)");
|
||||
|
@ -2449,4 +2451,37 @@ local x: foo<boolean>
|
|||
CHECK(toString(requireType("x"), ToStringOptions{true}) == "boolean | number");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "udtf_type_alias_registration_follows")
|
||||
{
|
||||
ScopedFastFlag luauFollowTypeAlias{FFlag::LuauFollowTypeAlias, true};
|
||||
|
||||
LUAU_REQUIRE_ERRORS(check(R"(
|
||||
export type t110 = ""type--"
|
||||
function _<t32...,t0...,t0...,t0...>(...):(any)&(any)
|
||||
end
|
||||
if _ then
|
||||
else
|
||||
export type t110 = ""type--"
|
||||
function _<t32...,t0...,t0...,t0...>(...):(any)&(any)
|
||||
end
|
||||
end
|
||||
)"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "udtf_double_definition")
|
||||
{
|
||||
ScopedFastFlag newSolver{FFlag::LuauSolverV2, true};
|
||||
ScopedFastFlag luauFollowExistingTypeFunction{FFlag::LuauFollowExistingTypeFunction, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
type function t0<A>()
|
||||
end
|
||||
type function t0<A>()
|
||||
end
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK(toString(result.errors[0]) == R"(Redefinition of type 't0', previously defined at line 2)");
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -13,7 +13,7 @@ LUAU_FASTFLAG(LuauSolverV2)
|
|||
LUAU_FASTFLAG(LuauNewNonStrictVisitTypes2)
|
||||
LUAU_FASTFLAG(LuauGuardAgainstMalformedTypeAliasExpansion2)
|
||||
LUAU_FASTFLAG(LuauSkipMalformedTypeAliases)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeAliases");
|
||||
|
||||
|
@ -84,8 +84,8 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias")
|
|||
Location{{1, 21}, {1, 26}},
|
||||
getMainSourceModule()->name,
|
||||
TypeMismatch{
|
||||
builtinTypes->numberType,
|
||||
builtinTypes->stringType,
|
||||
getBuiltins()->numberType,
|
||||
getBuiltins()->stringType,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
@ -98,8 +98,8 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias")
|
|||
Location{{1, 8}, {1, 26}},
|
||||
getMainSourceModule()->name,
|
||||
TypeMismatch{
|
||||
builtinTypes->numberType,
|
||||
builtinTypes->stringType,
|
||||
getBuiltins()->numberType,
|
||||
getBuiltins()->stringType,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
@ -188,7 +188,7 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_types_of_named_table_fields_do_not_expand_whe
|
|||
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
|
||||
REQUIRE_MESSAGE(tm, result.errors[0]);
|
||||
CHECK_EQ("Node?", toString(tm->wantedType));
|
||||
CHECK_EQ(builtinTypes->numberType, tm->givenType);
|
||||
CHECK_EQ(getBuiltins()->numberType, tm->givenType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "mutually_recursive_aliases")
|
||||
|
@ -210,7 +210,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_aliases")
|
|||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -229,7 +229,7 @@ TEST_CASE_FIXTURE(Fixture, "dependent_generic_aliases")
|
|||
{
|
||||
ScopedFastFlag sff[] = {
|
||||
{FFlag::LuauSolverV2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -274,9 +274,9 @@ TEST_CASE_FIXTURE(Fixture, "mutually_recursive_types_errors")
|
|||
LUAU_REQUIRE_ERRORS(result);
|
||||
|
||||
// We had a UAF in this example caused by not cloning type function arguments
|
||||
ModulePtr module = frontend.moduleResolver.getModule("MainModule");
|
||||
ModulePtr module = getFrontend().moduleResolver.getModule("MainModule");
|
||||
unfreeze(module->interfaceTypes);
|
||||
copyErrors(module->errors, module->interfaceTypes, builtinTypes);
|
||||
copyErrors(module->errors, module->interfaceTypes, getBuiltins());
|
||||
freeze(module->interfaceTypes);
|
||||
module->internalTypes.clear();
|
||||
module->astTypes.clear();
|
||||
|
@ -329,7 +329,7 @@ TEST_CASE_FIXTURE(Fixture, "stringify_type_alias_of_recursive_template_table_typ
|
|||
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
|
||||
REQUIRE(tm);
|
||||
CHECK_EQ("Wrapped", toString(tm->wantedType));
|
||||
CHECK_EQ(builtinTypes->numberType, tm->givenType);
|
||||
CHECK_EQ(getBuiltins()->numberType, tm->givenType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "stringify_type_alias_of_recursive_template_table_type2")
|
||||
|
@ -348,7 +348,7 @@ TEST_CASE_FIXTURE(Fixture, "stringify_type_alias_of_recursive_template_table_typ
|
|||
CHECK_EQ("t1 where t1 = ({ a: t1 }) -> string", toString(tm->wantedType));
|
||||
else
|
||||
CHECK_EQ("t1 where t1 = ({| a: t1 |}) -> string", toString(tm->wantedType));
|
||||
CHECK_EQ(builtinTypes->numberType, tm->givenType);
|
||||
CHECK_EQ(getBuiltins()->numberType, tm->givenType);
|
||||
}
|
||||
|
||||
// Check that recursive intersection type doesn't generate an OOM
|
||||
|
@ -508,7 +508,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "general_require_multi_assign")
|
|||
local b: Bar.myvec3
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("workspace/C");
|
||||
CheckResult result = getFrontend().check("workspace/C");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
TypeId aTypeId = requireType("workspace/C", "a");
|
||||
|
@ -527,7 +527,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_import_mutation")
|
|||
CheckResult result = check("type t10<x> = typeof(table)");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
TypeId ty = getGlobalBinding(frontend.globals, "table");
|
||||
TypeId ty = getGlobalBinding(getFrontend().globals, "table");
|
||||
|
||||
CHECK(toString(ty) == "typeof(table)");
|
||||
|
||||
|
@ -602,7 +602,7 @@ export type X = { a: number, b: X? }
|
|||
return {}
|
||||
)";
|
||||
|
||||
CheckResult aResult = frontend.check("game/A");
|
||||
CheckResult aResult = getFrontend().check("game/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(aResult);
|
||||
|
||||
CheckResult bResult = check(R"(
|
||||
|
@ -627,7 +627,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_of_an_imported_recursive_generic_
|
|||
return {}
|
||||
)";
|
||||
|
||||
CheckResult aResult = frontend.check("game/A");
|
||||
CheckResult aResult = getFrontend().check("game/A");
|
||||
LUAU_REQUIRE_NO_ERRORS(aResult);
|
||||
|
||||
CheckResult bResult = check(R"(
|
||||
|
@ -995,7 +995,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dont_lose_track_of_PendingExpansionTypes_aft
|
|||
end
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("game/React/React/ReactHooks");
|
||||
CheckResult result = getFrontend().check("game/React/React/ReactHooks");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
@ -1048,7 +1048,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "alias_expands_to_bare_reference_to_imported_
|
|||
end
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("game/B");
|
||||
CheckResult result = getFrontend().check("game/B");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
|
|
|
@ -181,7 +181,7 @@ TEST_CASE_FIXTURE(Fixture, "function_return_annotations_are_checked")
|
|||
|
||||
REQUIRE_EQ(1, tp->head.size());
|
||||
|
||||
REQUIRE_EQ(builtinTypes->anyType, follow(tp->head[0]));
|
||||
REQUIRE_EQ(getBuiltins()->anyType, follow(tp->head[0]));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "function_return_multret_annotations_are_checked")
|
||||
|
@ -271,18 +271,18 @@ TEST_CASE_FIXTURE(Fixture, "infer_type_of_value_a_via_typeof_with_assignment")
|
|||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK(
|
||||
result.errors[0] == (TypeError{Location{Position{2, 29}, Position{2, 30}}, TypeMismatch{builtinTypes->nilType, builtinTypes->numberType}})
|
||||
result.errors[0] == (TypeError{Location{Position{2, 29}, Position{2, 30}}, TypeMismatch{getBuiltins()->nilType, getBuiltins()->numberType}})
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_EQ(*builtinTypes->numberType, *requireType("a"));
|
||||
CHECK_EQ(*builtinTypes->numberType, *requireType("b"));
|
||||
CHECK_EQ(*getBuiltins()->numberType, *requireType("a"));
|
||||
CHECK_EQ(*getBuiltins()->numberType, *requireType("b"));
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK_EQ(
|
||||
result.errors[0],
|
||||
(TypeError{Location{Position{4, 12}, Position{4, 17}}, TypeMismatch{builtinTypes->numberType, builtinTypes->stringType}})
|
||||
(TypeError{Location{Position{4, 12}, Position{4, 17}}, TypeMismatch{getBuiltins()->numberType, getBuiltins()->stringType}})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -573,7 +573,7 @@ TEST_CASE_FIXTURE(Fixture, "type_alias_always_resolve_to_a_real_type")
|
|||
)");
|
||||
|
||||
TypeId fType = requireType("aa");
|
||||
REQUIRE(follow(fType) == builtinTypes->numberType);
|
||||
REQUIRE(follow(fType) == getBuiltins()->numberType);
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
|
@ -594,7 +594,7 @@ TEST_CASE_FIXTURE(Fixture, "interface_types_belong_to_interface_arena")
|
|||
const TypeFun& a = mod.exportedTypeBindings["A"];
|
||||
|
||||
CHECK(isInArena(a.type, mod.interfaceTypes));
|
||||
CHECK(!isInArena(a.type, frontend.globals.globalTypes));
|
||||
CHECK(!isInArena(a.type, getFrontend().globals.globalTypes));
|
||||
|
||||
std::optional<TypeId> exportsType = first(mod.returnType);
|
||||
REQUIRE(exportsType);
|
||||
|
@ -673,7 +673,7 @@ TEST_CASE_FIXTURE(Fixture, "cloned_interface_maintains_pointers_between_definiti
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "use_type_required_from_another_file")
|
||||
{
|
||||
addGlobalBinding(frontend.globals, "script", builtinTypes->anyType, "@test");
|
||||
addGlobalBinding(getFrontend().globals, "script", getBuiltins()->anyType, "@test");
|
||||
|
||||
fileResolver.source["Modules/Main"] = R"(
|
||||
--!strict
|
||||
|
@ -692,14 +692,14 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "use_type_required_from_another_file")
|
|||
return {}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Modules/Main");
|
||||
CheckResult result = getFrontend().check("Modules/Main");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_use_nonexported_type")
|
||||
{
|
||||
addGlobalBinding(frontend.globals, "script", builtinTypes->anyType, "@test");
|
||||
addGlobalBinding(getFrontend().globals, "script", getBuiltins()->anyType, "@test");
|
||||
|
||||
fileResolver.source["Modules/Main"] = R"(
|
||||
--!strict
|
||||
|
@ -718,14 +718,14 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_use_nonexported_type")
|
|||
return {}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Modules/Main");
|
||||
CheckResult result = getFrontend().check("Modules/Main");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_are_not_exported")
|
||||
{
|
||||
addGlobalBinding(frontend.globals, "script", builtinTypes->anyType, "@test");
|
||||
addGlobalBinding(getFrontend().globals, "script", getBuiltins()->anyType, "@test");
|
||||
|
||||
fileResolver.source["Modules/Main"] = R"(
|
||||
--!strict
|
||||
|
@ -742,7 +742,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_are_not_exported")
|
|||
return {}
|
||||
)";
|
||||
|
||||
CheckResult result = frontend.check("Modules/Main");
|
||||
CheckResult result = getFrontend().check("Modules/Main");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
}
|
||||
|
@ -796,7 +796,7 @@ TEST_CASE_FIXTURE(Fixture, "luau_ice_triggers_an_ice_exception_with_flag_handler
|
|||
|
||||
bool caught = false;
|
||||
|
||||
frontend.iceHandler.onInternalError = [&](const char*)
|
||||
getFrontend().iceHandler.onInternalError = [&](const char*)
|
||||
{
|
||||
caught = true;
|
||||
};
|
||||
|
@ -823,6 +823,10 @@ TEST_CASE_FIXTURE(Fixture, "luau_ice_is_not_special_without_the_flag")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "luau_print_is_magic_if_the_flag_is_set")
|
||||
{
|
||||
// Force the frontend on here
|
||||
// The Fixture constructor (now lazy)
|
||||
// initializes printline. If we do something after that, we'll override it with something empty
|
||||
getFrontend();
|
||||
static std::vector<std::string> output;
|
||||
output.clear();
|
||||
Luau::setPrintLine(
|
||||
|
|
|
@ -46,7 +46,7 @@ TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_returns_any")
|
|||
}
|
||||
}
|
||||
else
|
||||
CHECK(builtinTypes->anyType == requireType("a"));
|
||||
CHECK(getBuiltins()->anyType == requireType("a"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "for_in_loop_iterator_returns_any2")
|
||||
|
@ -308,7 +308,7 @@ TEST_CASE_FIXTURE(Fixture, "quantify_any_does_not_bind_to_itself")
|
|||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
TypeId aType = requireType("A");
|
||||
CHECK_EQ(aType, builtinTypes->anyType);
|
||||
CHECK_EQ(aType, getBuiltins()->anyType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "calling_error_type_yields_error")
|
||||
|
|
|
@ -11,9 +11,10 @@ using namespace Luau;
|
|||
|
||||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTFLAG(LuauTableCloneClonesType3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
LUAU_FASTFLAG(LuauStringFormatImprovements)
|
||||
LUAU_FASTFLAG(LuauWriteOnlyPropertyMangling)
|
||||
|
||||
TEST_SUITE_BEGIN("BuiltinTests");
|
||||
|
||||
|
@ -110,7 +111,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_concat_returns_string")
|
|||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
CHECK_EQ(*builtinTypes->stringType, *requireType("r"));
|
||||
CHECK_EQ(*getBuiltins()->stringType, *requireType("r"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "sort")
|
||||
|
@ -170,7 +171,7 @@ TEST_CASE_FIXTURE(Fixture, "strings_have_methods")
|
|||
)LUA");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
CHECK_EQ(*builtinTypes->stringType, *requireType("s"));
|
||||
CHECK_EQ(*getBuiltins()->stringType, *requireType("s"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "math_max_variatic")
|
||||
|
@ -180,7 +181,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "math_max_variatic")
|
|||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
CHECK_EQ(*builtinTypes->numberType, *requireType("n"));
|
||||
CHECK_EQ(*getBuiltins()->numberType, *requireType("n"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "math_max_checks_for_numbers")
|
||||
|
@ -397,7 +398,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_correctly_infers_type_of_array_
|
|||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
CHECK_EQ(builtinTypes->stringType, requireType("s"));
|
||||
CHECK_EQ(getBuiltins()->stringType, requireType("s"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "table_insert_correctly_infers_type_of_array_3_args_overload")
|
||||
|
@ -473,7 +474,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "gcinfo")
|
|||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
CHECK_EQ(*builtinTypes->numberType, *requireType("n"));
|
||||
CHECK_EQ(*getBuiltins()->numberType, *requireType("n"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "getfenv")
|
||||
|
@ -490,9 +491,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "os_time_takes_optional_date_table")
|
|||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
CHECK_EQ(*builtinTypes->numberType, *requireType("n1"));
|
||||
CHECK_EQ(*builtinTypes->numberType, *requireType("n2"));
|
||||
CHECK_EQ(*builtinTypes->numberType, *requireType("n3"));
|
||||
CHECK_EQ(*getBuiltins()->numberType, *requireType("n1"));
|
||||
CHECK_EQ(*getBuiltins()->numberType, *requireType("n2"));
|
||||
CHECK_EQ(*getBuiltins()->numberType, *requireType("n3"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "thread_is_a_type")
|
||||
|
@ -615,8 +616,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_correctly_ordered_types")
|
|||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
|
||||
REQUIRE(tm);
|
||||
CHECK_EQ(tm->wantedType, builtinTypes->stringType);
|
||||
CHECK_EQ(tm->givenType, builtinTypes->numberType);
|
||||
CHECK_EQ(tm->wantedType, getBuiltins()->stringType);
|
||||
CHECK_EQ(tm->givenType, getBuiltins()->numberType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_tostring_specifier")
|
||||
|
@ -809,8 +810,8 @@ TEST_CASE_FIXTURE(Fixture, "string_format_as_method")
|
|||
|
||||
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
|
||||
REQUIRE(tm);
|
||||
CHECK_EQ(tm->wantedType, builtinTypes->stringType);
|
||||
CHECK_EQ(tm->givenType, builtinTypes->numberType);
|
||||
CHECK_EQ(tm->wantedType, getBuiltins()->stringType);
|
||||
CHECK_EQ(tm->givenType, getBuiltins()->numberType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_trivial_arity")
|
||||
|
@ -959,9 +960,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_report_all_type_errors_at_corr
|
|||
string.format("%s%d%s", 1, "hello", true)
|
||||
)");
|
||||
|
||||
TypeId stringType = builtinTypes->stringType;
|
||||
TypeId numberType = builtinTypes->numberType;
|
||||
TypeId booleanType = builtinTypes->booleanType;
|
||||
TypeId stringType = getBuiltins()->stringType;
|
||||
TypeId numberType = getBuiltins()->numberType;
|
||||
TypeId booleanType = getBuiltins()->booleanType;
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(6, result);
|
||||
|
||||
|
@ -1308,7 +1309,7 @@ TEST_CASE_FIXTURE(Fixture, "typeof_unresolved_function")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "no_persistent_typelevel_change")
|
||||
{
|
||||
TypeId mathTy = requireType(frontend.globals.globalScope, "math");
|
||||
TypeId mathTy = requireType(getFrontend().globals.globalScope, "math");
|
||||
REQUIRE(mathTy);
|
||||
TableType* ttv = getMutable<TableType>(mathTy);
|
||||
REQUIRE(ttv);
|
||||
|
@ -1694,8 +1695,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "string_format_should_support_singleton_types
|
|||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
|
||||
REQUIRE(tm);
|
||||
CHECK_EQ(tm->wantedType, builtinTypes->stringType);
|
||||
CHECK_EQ(tm->givenType, builtinTypes->numberType);
|
||||
CHECK_EQ(tm->wantedType, getBuiltins()->stringType);
|
||||
CHECK_EQ(tm->givenType, getBuiltins()->numberType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "better_string_format_error_when_format_string_is_dynamic")
|
||||
|
@ -1717,4 +1718,19 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "better_string_format_error_when_format_strin
|
|||
);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "write_only_table_assertion")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauWriteOnlyPropertyMangling, true};
|
||||
|
||||
// CLI-157307: This currently errors as we claim the literal is not a
|
||||
// `{ write foo: number }`, which is wrong as every table literal is
|
||||
// trivially a write-only table.
|
||||
LUAU_REQUIRE_ERRORS(check(R"(
|
||||
local function accept(t: { write foo: number })
|
||||
end
|
||||
|
||||
accept({ foo = "lol", foo = true })
|
||||
)"));
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
|
|
@ -766,7 +766,7 @@ TEST_CASE_FIXTURE(Fixture, "read_write_class_properties")
|
|||
{
|
||||
ScopedFastFlag sff{FFlag::LuauSolverV2, true};
|
||||
|
||||
TypeArena& arena = frontend.globals.globalTypes;
|
||||
TypeArena& arena = getFrontend().globals.globalTypes;
|
||||
|
||||
unfreeze(arena);
|
||||
|
||||
|
@ -782,7 +782,7 @@ TEST_CASE_FIXTURE(Fixture, "read_write_class_properties")
|
|||
|
||||
TypeId partType = arena.addType(ExternType{
|
||||
"Part",
|
||||
{{"BrickColor", Property::rw(builtinTypes->stringType)}, {"Parent", Property::rw(workspaceType, instanceType)}},
|
||||
{{"BrickColor", Property::rw(getBuiltins()->stringType)}, {"Parent", Property::rw(workspaceType, instanceType)}},
|
||||
instanceType,
|
||||
nullopt,
|
||||
{},
|
||||
|
@ -793,7 +793,7 @@ TEST_CASE_FIXTURE(Fixture, "read_write_class_properties")
|
|||
|
||||
getMutable<ExternType>(workspaceType)->props = {{"Script", Property::readonly(scriptType)}, {"Part", Property::readonly(partType)}};
|
||||
|
||||
frontend.globals.globalScope->bindings[frontend.globals.globalNames.names->getOrAdd("script")] = Binding{scriptType};
|
||||
getFrontend().globals.globalScope->bindings[getFrontend().globals.globalNames.names->getOrAdd("script")] = Binding{scriptType};
|
||||
|
||||
freeze(arena);
|
||||
|
||||
|
@ -807,8 +807,8 @@ TEST_CASE_FIXTURE(Fixture, "read_write_class_properties")
|
|||
CHECK(Location{{1, 40}, {1, 48}} == result.errors[0].location);
|
||||
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
|
||||
REQUIRE(tm);
|
||||
CHECK(builtinTypes->stringType == tm->wantedType);
|
||||
CHECK(builtinTypes->numberType == tm->givenType);
|
||||
CHECK(getBuiltins()->stringType == tm->wantedType);
|
||||
CHECK(getBuiltins()->numberType == tm->givenType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ExternTypeFixture, "cannot_index_a_class_with_no_indexer")
|
||||
|
@ -826,7 +826,7 @@ TEST_CASE_FIXTURE(ExternTypeFixture, "cannot_index_a_class_with_no_indexer")
|
|||
"Expected DynamicPropertyLookupOnExternTypesUnsafe but got " << result.errors[0]
|
||||
);
|
||||
|
||||
CHECK(builtinTypes->errorType == requireType("c"));
|
||||
CHECK(getBuiltins()->errorType == requireType("c"));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(ExternTypeFixture, "cyclic_tables_are_assumed_to_be_compatible_with_extern_types")
|
||||
|
|
|
@ -22,13 +22,13 @@ TEST_CASE_FIXTURE(Fixture, "definition_file_simple")
|
|||
declare foo2: typeof(foo)
|
||||
)");
|
||||
|
||||
TypeId globalFooTy = getGlobalBinding(frontend.globals, "foo");
|
||||
TypeId globalFooTy = getGlobalBinding(getFrontend().globals, "foo");
|
||||
CHECK_EQ(toString(globalFooTy), "number");
|
||||
|
||||
TypeId globalBarTy = getGlobalBinding(frontend.globals, "bar");
|
||||
TypeId globalBarTy = getGlobalBinding(getFrontend().globals, "bar");
|
||||
CHECK_EQ(toString(globalBarTy), "(number) -> string");
|
||||
|
||||
TypeId globalFoo2Ty = getGlobalBinding(frontend.globals, "foo2");
|
||||
TypeId globalFoo2Ty = getGlobalBinding(getFrontend().globals, "foo2");
|
||||
CHECK_EQ(toString(globalFoo2Ty), "number");
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -51,20 +51,20 @@ TEST_CASE_FIXTURE(Fixture, "definition_file_loading")
|
|||
declare function var(...: any): string
|
||||
)");
|
||||
|
||||
TypeId globalFooTy = getGlobalBinding(frontend.globals, "foo");
|
||||
TypeId globalFooTy = getGlobalBinding(getFrontend().globals, "foo");
|
||||
CHECK_EQ(toString(globalFooTy), "number");
|
||||
|
||||
std::optional<TypeFun> globalAsdfTy = frontend.globals.globalScope->lookupType("Asdf");
|
||||
std::optional<TypeFun> globalAsdfTy = getFrontend().globals.globalScope->lookupType("Asdf");
|
||||
REQUIRE(bool(globalAsdfTy));
|
||||
CHECK_EQ(toString(globalAsdfTy->type), "number | string");
|
||||
|
||||
TypeId globalBarTy = getGlobalBinding(frontend.globals, "bar");
|
||||
TypeId globalBarTy = getGlobalBinding(getFrontend().globals, "bar");
|
||||
CHECK_EQ(toString(globalBarTy), "(number) -> string");
|
||||
|
||||
TypeId globalFoo2Ty = getGlobalBinding(frontend.globals, "foo2");
|
||||
TypeId globalFoo2Ty = getGlobalBinding(getFrontend().globals, "foo2");
|
||||
CHECK_EQ(toString(globalFoo2Ty), "number");
|
||||
|
||||
TypeId globalVarTy = getGlobalBinding(frontend.globals, "var");
|
||||
TypeId globalVarTy = getGlobalBinding(getFrontend().globals, "var");
|
||||
|
||||
CHECK_EQ(toString(globalVarTy), "(...any) -> string");
|
||||
|
||||
|
@ -80,25 +80,25 @@ TEST_CASE_FIXTURE(Fixture, "definition_file_loading")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "load_definition_file_errors_do_not_pollute_global_scope")
|
||||
{
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
LoadDefinitionFileResult parseFailResult = frontend.loadDefinitionFile(
|
||||
frontend.globals,
|
||||
frontend.globals.globalScope,
|
||||
unfreeze(getFrontend().globals.globalTypes);
|
||||
LoadDefinitionFileResult parseFailResult = getFrontend().loadDefinitionFile(
|
||||
getFrontend().globals,
|
||||
getFrontend().globals.globalScope,
|
||||
R"(
|
||||
declare foo
|
||||
)",
|
||||
"@test",
|
||||
/* captureComments */ false
|
||||
);
|
||||
freeze(frontend.globals.globalTypes);
|
||||
freeze(getFrontend().globals.globalTypes);
|
||||
|
||||
REQUIRE(!parseFailResult.success);
|
||||
std::optional<Binding> fooTy = tryGetGlobalBinding(frontend.globals, "foo");
|
||||
std::optional<Binding> fooTy = tryGetGlobalBinding(getFrontend().globals, "foo");
|
||||
CHECK(!fooTy.has_value());
|
||||
|
||||
LoadDefinitionFileResult checkFailResult = frontend.loadDefinitionFile(
|
||||
frontend.globals,
|
||||
frontend.globals.globalScope,
|
||||
LoadDefinitionFileResult checkFailResult = getFrontend().loadDefinitionFile(
|
||||
getFrontend().globals,
|
||||
getFrontend().globals.globalScope,
|
||||
R"(
|
||||
local foo: string = 123
|
||||
declare bar: typeof(foo)
|
||||
|
@ -108,7 +108,7 @@ TEST_CASE_FIXTURE(Fixture, "load_definition_file_errors_do_not_pollute_global_sc
|
|||
);
|
||||
|
||||
REQUIRE(!checkFailResult.success);
|
||||
std::optional<Binding> barTy = tryGetGlobalBinding(frontend.globals, "bar");
|
||||
std::optional<Binding> barTy = tryGetGlobalBinding(getFrontend().globals, "bar");
|
||||
CHECK(!barTy.has_value());
|
||||
}
|
||||
|
||||
|
@ -152,10 +152,10 @@ TEST_CASE_FIXTURE(Fixture, "definition_file_extern_types")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "class_definitions_cannot_overload_non_function")
|
||||
{
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
LoadDefinitionFileResult result = frontend.loadDefinitionFile(
|
||||
frontend.globals,
|
||||
frontend.globals.globalScope,
|
||||
unfreeze(getFrontend().globals.globalTypes);
|
||||
LoadDefinitionFileResult result = getFrontend().loadDefinitionFile(
|
||||
getFrontend().globals,
|
||||
getFrontend().globals.globalScope,
|
||||
R"(
|
||||
declare class A
|
||||
X: number
|
||||
|
@ -165,7 +165,7 @@ TEST_CASE_FIXTURE(Fixture, "class_definitions_cannot_overload_non_function")
|
|||
"@test",
|
||||
/* captureComments */ false
|
||||
);
|
||||
freeze(frontend.globals.globalTypes);
|
||||
freeze(getFrontend().globals.globalTypes);
|
||||
|
||||
REQUIRE(!result.success);
|
||||
CHECK_EQ(result.parseResult.errors.size(), 0);
|
||||
|
@ -178,10 +178,10 @@ TEST_CASE_FIXTURE(Fixture, "class_definitions_cannot_overload_non_function")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "class_definitions_cannot_extend_non_class")
|
||||
{
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
LoadDefinitionFileResult result = frontend.loadDefinitionFile(
|
||||
frontend.globals,
|
||||
frontend.globals.globalScope,
|
||||
unfreeze(getFrontend().globals.globalTypes);
|
||||
LoadDefinitionFileResult result = getFrontend().loadDefinitionFile(
|
||||
getFrontend().globals,
|
||||
getFrontend().globals.globalScope,
|
||||
R"(
|
||||
type NotAClass = {}
|
||||
|
||||
|
@ -191,7 +191,7 @@ TEST_CASE_FIXTURE(Fixture, "class_definitions_cannot_extend_non_class")
|
|||
"@test",
|
||||
/* captureComments */ false
|
||||
);
|
||||
freeze(frontend.globals.globalTypes);
|
||||
freeze(getFrontend().globals.globalTypes);
|
||||
|
||||
REQUIRE(!result.success);
|
||||
CHECK_EQ(result.parseResult.errors.size(), 0);
|
||||
|
@ -204,10 +204,10 @@ TEST_CASE_FIXTURE(Fixture, "class_definitions_cannot_extend_non_class")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "no_cyclic_defined_extern_types")
|
||||
{
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
LoadDefinitionFileResult result = frontend.loadDefinitionFile(
|
||||
frontend.globals,
|
||||
frontend.globals.globalScope,
|
||||
unfreeze(getFrontend().globals.globalTypes);
|
||||
LoadDefinitionFileResult result = getFrontend().loadDefinitionFile(
|
||||
getFrontend().globals,
|
||||
getFrontend().globals.globalScope,
|
||||
R"(
|
||||
declare class Foo extends Bar
|
||||
end
|
||||
|
@ -218,7 +218,7 @@ TEST_CASE_FIXTURE(Fixture, "no_cyclic_defined_extern_types")
|
|||
"@test",
|
||||
/* captureComments */ false
|
||||
);
|
||||
freeze(frontend.globals.globalTypes);
|
||||
freeze(getFrontend().globals.globalTypes);
|
||||
|
||||
REQUIRE(!result.success);
|
||||
}
|
||||
|
@ -317,16 +317,16 @@ TEST_CASE_FIXTURE(Fixture, "definitions_documentation_symbols")
|
|||
}
|
||||
)");
|
||||
|
||||
std::optional<Binding> xBinding = frontend.globals.globalScope->linearSearchForBinding("x");
|
||||
std::optional<Binding> xBinding = getFrontend().globals.globalScope->linearSearchForBinding("x");
|
||||
REQUIRE(bool(xBinding));
|
||||
// note: loadDefinition uses the @test package name.
|
||||
CHECK_EQ(xBinding->documentationSymbol, "@test/global/x");
|
||||
|
||||
std::optional<TypeFun> fooTy = frontend.globals.globalScope->lookupType("Foo");
|
||||
std::optional<TypeFun> fooTy = getFrontend().globals.globalScope->lookupType("Foo");
|
||||
REQUIRE(bool(fooTy));
|
||||
CHECK_EQ(fooTy->type->documentationSymbol, "@test/globaltype/Foo");
|
||||
|
||||
std::optional<TypeFun> barTy = frontend.globals.globalScope->lookupType("Bar");
|
||||
std::optional<TypeFun> barTy = getFrontend().globals.globalScope->lookupType("Bar");
|
||||
REQUIRE(bool(barTy));
|
||||
CHECK_EQ(barTy->type->documentationSymbol, "@test/globaltype/Bar");
|
||||
|
||||
|
@ -335,7 +335,7 @@ TEST_CASE_FIXTURE(Fixture, "definitions_documentation_symbols")
|
|||
REQUIRE_EQ(barClass->props.count("prop"), 1);
|
||||
CHECK_EQ(barClass->props["prop"].documentationSymbol, "@test/globaltype/Bar.prop");
|
||||
|
||||
std::optional<Binding> yBinding = frontend.globals.globalScope->linearSearchForBinding("y");
|
||||
std::optional<Binding> yBinding = getFrontend().globals.globalScope->linearSearchForBinding("y");
|
||||
REQUIRE(bool(yBinding));
|
||||
CHECK_EQ(yBinding->documentationSymbol, "@test/global/y");
|
||||
|
||||
|
@ -355,7 +355,7 @@ TEST_CASE_FIXTURE(Fixture, "definitions_symbols_are_generated_for_recursively_re
|
|||
declare function myFunc(): MyClass
|
||||
)");
|
||||
|
||||
std::optional<TypeFun> myClassTy = frontend.globals.globalScope->lookupType("MyClass");
|
||||
std::optional<TypeFun> myClassTy = getFrontend().globals.globalScope->lookupType("MyClass");
|
||||
REQUIRE(bool(myClassTy));
|
||||
CHECK_EQ(myClassTy->type->documentationSymbol, "@test/globaltype/MyClass");
|
||||
|
||||
|
@ -382,7 +382,7 @@ TEST_CASE_FIXTURE(Fixture, "documentation_symbols_dont_attach_to_persistent_type
|
|||
export type Evil = string
|
||||
)");
|
||||
|
||||
std::optional<TypeFun> ty = frontend.globals.globalScope->lookupType("Evil");
|
||||
std::optional<TypeFun> ty = getFrontend().globals.globalScope->lookupType("Evil");
|
||||
REQUIRE(bool(ty));
|
||||
CHECK_EQ(ty->type->documentationSymbol, std::nullopt);
|
||||
}
|
||||
|
@ -448,10 +448,10 @@ TEST_CASE_FIXTURE(Fixture, "class_definition_string_props")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "class_definition_malformed_string")
|
||||
{
|
||||
unfreeze(frontend.globals.globalTypes);
|
||||
LoadDefinitionFileResult result = frontend.loadDefinitionFile(
|
||||
frontend.globals,
|
||||
frontend.globals.globalScope,
|
||||
unfreeze(getFrontend().globals.globalTypes);
|
||||
LoadDefinitionFileResult result = getFrontend().loadDefinitionFile(
|
||||
getFrontend().globals,
|
||||
getFrontend().globals.globalScope,
|
||||
R"(
|
||||
declare class Foo
|
||||
["a\0property"]: string
|
||||
|
@ -460,7 +460,7 @@ TEST_CASE_FIXTURE(Fixture, "class_definition_malformed_string")
|
|||
"@test",
|
||||
/* captureComments */ false
|
||||
);
|
||||
freeze(frontend.globals.globalTypes);
|
||||
freeze(getFrontend().globals.globalTypes);
|
||||
|
||||
REQUIRE(!result.success);
|
||||
REQUIRE_EQ(result.parseResult.errors.size(), 1);
|
||||
|
@ -487,8 +487,8 @@ TEST_CASE_FIXTURE(Fixture, "class_definition_indexer")
|
|||
|
||||
REQUIRE(bool(etv->indexer));
|
||||
|
||||
CHECK_EQ(*etv->indexer->indexType, *builtinTypes->numberType);
|
||||
CHECK_EQ(*etv->indexer->indexResultType, *builtinTypes->stringType);
|
||||
CHECK_EQ(*etv->indexer->indexType, *getBuiltins()->numberType);
|
||||
CHECK_EQ(*etv->indexer->indexResultType, *getBuiltins()->stringType);
|
||||
|
||||
CHECK_EQ(toString(requireType("y")), "string");
|
||||
}
|
||||
|
@ -532,7 +532,7 @@ TEST_CASE_FIXTURE(Fixture, "definition_file_has_source_module_name_set")
|
|||
CHECK_EQ(result.sourceModule.name, "@test");
|
||||
CHECK_EQ(result.sourceModule.humanReadableName, "@test");
|
||||
|
||||
std::optional<TypeFun> fooTy = frontend.globals.globalScope->lookupType("Foo");
|
||||
std::optional<TypeFun> fooTy = getFrontend().globals.globalScope->lookupType("Foo");
|
||||
REQUIRE(fooTy);
|
||||
|
||||
const ExternType* etv = get<ExternType>(fooTy->type);
|
||||
|
|
|
@ -22,12 +22,12 @@ LUAU_FASTFLAG(LuauInstantiateInSubtyping)
|
|||
LUAU_FASTFLAG(LuauSolverV2)
|
||||
LUAU_FASTINT(LuauTarjanChildLimit)
|
||||
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization3)
|
||||
LUAU_FASTFLAG(LuauEagerGeneralization4)
|
||||
LUAU_FASTFLAG(LuauArityMismatchOnUndersaturatedUnknownArguments)
|
||||
LUAU_FASTFLAG(LuauFormatUseLastPosition)
|
||||
LUAU_FASTFLAG(LuauDoNotAddUpvalueTypesToLocalType)
|
||||
LUAU_FASTFLAG(LuauSimplifyOutOfLine2)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck)
|
||||
LUAU_FASTFLAG(LuauTableLiteralSubtypeSpecificCheck2)
|
||||
LUAU_FASTFLAG(LuauAvoidGenericsLeakingDuringFunctionCallCheck)
|
||||
|
||||
TEST_SUITE_BEGIN("TypeInferFunctions");
|
||||
|
@ -77,7 +77,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_function")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "check_function_bodies")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function myFunction(): number
|
||||
|
@ -103,8 +103,8 @@ TEST_CASE_FIXTURE(Fixture, "check_function_bodies")
|
|||
(TypeError{
|
||||
Location{Position{3, 16}, Position{3, 20}},
|
||||
TypeMismatch{
|
||||
builtinTypes->numberType,
|
||||
builtinTypes->booleanType,
|
||||
getBuiltins()->numberType,
|
||||
getBuiltins()->booleanType,
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -149,7 +149,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_return_type")
|
|||
std::vector<TypeId> retVec = flatten(takeFiveType->retTypes).first;
|
||||
REQUIRE(!retVec.empty());
|
||||
|
||||
REQUIRE_EQ(*follow(retVec[0]), *builtinTypes->numberType);
|
||||
REQUIRE_EQ(*follow(retVec[0]), *getBuiltins()->numberType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "infer_from_function_return_type")
|
||||
|
@ -157,7 +157,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_from_function_return_type")
|
|||
CheckResult result = check("function take_five() return 5 end local five = take_five()");
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
CHECK_EQ(*builtinTypes->numberType, *follow(requireType("five")));
|
||||
CHECK_EQ(*getBuiltins()->numberType, *follow(requireType("five")));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "infer_that_function_does_not_return_a_table")
|
||||
|
@ -171,7 +171,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_that_function_does_not_return_a_table")
|
|||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK_EQ(result.errors[0], (TypeError{Location{Position{5, 8}, Position{5, 24}}, NotATable{builtinTypes->numberType}}));
|
||||
CHECK_EQ(result.errors[0], (TypeError{Location{Position{5, 8}, Position{5, 24}}, NotATable{getBuiltins()->numberType}}));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "generalize_table_property")
|
||||
|
@ -258,8 +258,8 @@ TEST_CASE_FIXTURE(Fixture, "list_only_alternative_overloads_that_match_argument_
|
|||
{
|
||||
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
|
||||
REQUIRE(tm);
|
||||
CHECK_EQ(builtinTypes->numberType, tm->wantedType);
|
||||
CHECK_EQ(builtinTypes->stringType, tm->givenType);
|
||||
CHECK_EQ(getBuiltins()->numberType, tm->wantedType);
|
||||
CHECK_EQ(getBuiltins()->stringType, tm->givenType);
|
||||
}
|
||||
|
||||
ExtraInformation* ei = get<ExtraInformation>(result.errors[1]);
|
||||
|
@ -300,8 +300,8 @@ TEST_CASE_FIXTURE(Fixture, "dont_give_other_overloads_message_if_only_one_argume
|
|||
|
||||
TypeMismatch* tm = get<TypeMismatch>(result.errors[0]);
|
||||
REQUIRE(tm);
|
||||
CHECK_EQ(builtinTypes->numberType, tm->wantedType);
|
||||
CHECK_EQ(builtinTypes->stringType, tm->givenType);
|
||||
CHECK_EQ(getBuiltins()->numberType, tm->wantedType);
|
||||
CHECK_EQ(getBuiltins()->stringType, tm->givenType);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "infer_return_type_from_selected_overload")
|
||||
|
@ -991,8 +991,8 @@ TEST_CASE_FIXTURE(Fixture, "calling_function_with_incorrect_argument_type_yields
|
|||
(TypeError{
|
||||
Location{Position{3, 12}, Position{3, 18}},
|
||||
TypeMismatch{
|
||||
builtinTypes->numberType,
|
||||
builtinTypes->stringType,
|
||||
getBuiltins()->numberType,
|
||||
getBuiltins()->stringType,
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -1002,8 +1002,8 @@ TEST_CASE_FIXTURE(Fixture, "calling_function_with_incorrect_argument_type_yields
|
|||
(TypeError{
|
||||
Location{Position{3, 20}, Position{3, 23}},
|
||||
TypeMismatch{
|
||||
builtinTypes->stringType,
|
||||
builtinTypes->numberType,
|
||||
getBuiltins()->stringType,
|
||||
getBuiltins()->numberType,
|
||||
}
|
||||
})
|
||||
);
|
||||
|
@ -1485,7 +1485,7 @@ local a: TableWithFunc = { x = 3, y = 4, f = function(a, b) return a + b end }
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "infer_return_value_type")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function f(): {string|number}
|
||||
|
@ -1661,7 +1661,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "function_decl_non_self_sealed_overwrite")
|
|||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
|
||||
// if 'string' library property was replaced with an internal module type, it will be freed and the next check will crash
|
||||
frontend.clear();
|
||||
getFrontend().clear();
|
||||
|
||||
CheckResult result2 = check(R"(
|
||||
print(string.len('hello'))
|
||||
|
@ -1686,7 +1686,7 @@ t.f = function(x)
|
|||
end
|
||||
)");
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3 && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauEagerGeneralization4 && FFlag::LuauSolverV2)
|
||||
{
|
||||
// FIXME CLI-151985
|
||||
LUAU_CHECK_ERROR_COUNT(3, result);
|
||||
|
@ -1771,7 +1771,7 @@ t.f = function(x)
|
|||
end
|
||||
)");
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3 && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauEagerGeneralization4 && FFlag::LuauSolverV2)
|
||||
{
|
||||
// FIXME CLI-151985
|
||||
LUAU_CHECK_ERROR_COUNT(2, result);
|
||||
|
@ -1968,7 +1968,7 @@ TEST_CASE_FIXTURE(Fixture, "dont_infer_parameter_types_for_functions_from_their_
|
|||
|
||||
CHECK_EQ("<a>(a) -> a", toString(requireType("f")));
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3 && FFlag::LuauSolverV2)
|
||||
if (FFlag::LuauEagerGeneralization4 && FFlag::LuauSolverV2)
|
||||
{
|
||||
LUAU_CHECK_NO_ERRORS(result);
|
||||
CHECK("<a>({ read p: { read q: a } }) -> (a & ~(false?))?" == toString(requireType("g")));
|
||||
|
@ -2121,7 +2121,7 @@ z = y -- Not OK, so the line is colorable
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "function_is_supertype_of_concrete_functions")
|
||||
{
|
||||
registerHiddenTypes(&frontend);
|
||||
registerHiddenTypes(getFrontend());
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function foo(f: fun) end
|
||||
|
@ -2139,7 +2139,7 @@ TEST_CASE_FIXTURE(Fixture, "function_is_supertype_of_concrete_functions")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "concrete_functions_are_not_supertypes_of_function")
|
||||
{
|
||||
registerHiddenTypes(&frontend);
|
||||
registerHiddenTypes(getFrontend());
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local a: fun = function() end
|
||||
|
@ -2168,7 +2168,7 @@ TEST_CASE_FIXTURE(Fixture, "concrete_functions_are_not_supertypes_of_function")
|
|||
|
||||
TEST_CASE_FIXTURE(Fixture, "other_things_are_not_related_to_function")
|
||||
{
|
||||
registerHiddenTypes(&frontend);
|
||||
registerHiddenTypes(getFrontend());
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local a: fun = function() end
|
||||
|
@ -2429,7 +2429,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_packs_are_not_variadic")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "num_is_solved_before_num_or_str")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
function num()
|
||||
|
@ -2453,7 +2453,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "num_is_solved_before_num_or_str")
|
|||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "num_is_solved_after_num_or_str")
|
||||
{
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck, true};
|
||||
ScopedFastFlag _{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function num_or_str()
|
||||
|
@ -2643,7 +2643,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "tf_suggest_arg_type_2")
|
|||
return;
|
||||
|
||||
// Make sure the error types are cloned to module interface
|
||||
frontend.options.retainFullTypeGraphs = false;
|
||||
getFrontend().options.retainFullTypeGraphs = false;
|
||||
|
||||
CheckResult result = check(R"(
|
||||
local function escape_fslash(pre)
|
||||
|
@ -2912,7 +2912,7 @@ TEST_CASE_FIXTURE(Fixture, "unifier_should_not_bind_free_types")
|
|||
{
|
||||
ScopedFastFlag sffs[] = {
|
||||
{FFlag::LuauSimplifyOutOfLine2, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck, true},
|
||||
{FFlag::LuauTableLiteralSubtypeSpecificCheck2, true},
|
||||
};
|
||||
|
||||
CheckResult result = check(R"(
|
||||
|
@ -2932,7 +2932,7 @@ TEST_CASE_FIXTURE(Fixture, "unifier_should_not_bind_free_types")
|
|||
{
|
||||
// The new solver should ideally be able to do better here, but this is no worse than the old solver.
|
||||
|
||||
if (FFlag::LuauEagerGeneralization3)
|
||||
if (FFlag::LuauEagerGeneralization4)
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
auto tm1 = get<TypeMismatch>(result.errors[0]);
|
||||
|
@ -3062,7 +3062,7 @@ end
|
|||
local u,v = id(3), id(id(44))
|
||||
)");
|
||||
|
||||
CHECK_EQ(builtinTypes->numberType, requireType("v"));
|
||||
CHECK_EQ(getBuiltins()->numberType, requireType("v"));
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue