Sync to upstream/release/506 (#270)
- Fix some cases where type checking would overflow the native stack - Improve autocomplete behavior when assigning a partially written function call (not currently exposed through command line tools) - Improve autocomplete type inference feedback for some expressions where previously the type would not be known - Improve quantification performance during type checking for large types - Improve type checking for table literals when the expected type of the table is known because of a type annotation - Fix type checking errors in cases where required module has errors in the resulting type - Fix debug line information for multi-line chained call sequences (Add function name information for "attempt to call a nil value" #255) - lua_newuserdata now takes 2 arguments to match Lua/LuaJIT APIs better; lua_newuserdatatagged should be used if the third argument was non-0. - lua_ref can no longer be used with LUA_REGISTRYINDEX to prevent mistakes when migrating Lua FFI (Inconsistency with lua_ref #247) - Fix assertions and possible crashes when executing script code indirectly via metatable dispatch from lua_equal/lua_lessthan/lua_getfield/etc. (Hitting a crash in an assert after lua_equal is called. #259) - Fix flamegraph scripts to run under Python 2
This commit is contained in:
parent
f5ec6df7ba
commit
32fb6d10a7
|
@ -51,13 +51,6 @@ struct FileResolver
|
|||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// DEPRECATED APIS
|
||||
// These are going to be removed with LuauNewRequireTrace2
|
||||
virtual bool moduleExists(const ModuleName& name) const = 0;
|
||||
virtual std::optional<ModuleName> fromAstFragment(AstExpr* expr) const = 0;
|
||||
virtual ModuleName concat(const ModuleName& lhs, std::string_view rhs) const = 0;
|
||||
virtual std::optional<ModuleName> getParentModuleName(const ModuleName& name) const = 0;
|
||||
};
|
||||
|
||||
struct NullFileResolver : FileResolver
|
||||
|
@ -66,22 +59,6 @@ struct NullFileResolver : FileResolver
|
|||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
bool moduleExists(const ModuleName& name) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
std::optional<ModuleName> fromAstFragment(AstExpr* expr) const override
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
ModuleName concat(const ModuleName& lhs, std::string_view rhs) const override
|
||||
{
|
||||
return lhs;
|
||||
}
|
||||
std::optional<ModuleName> getParentModuleName(const ModuleName& name) const override
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -78,9 +78,15 @@ void unfreeze(TypeArena& arena);
|
|||
using SeenTypes = std::unordered_map<TypeId, TypeId>;
|
||||
using SeenTypePacks = std::unordered_map<TypePackId, TypePackId>;
|
||||
|
||||
TypePackId clone(TypePackId tp, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, bool* encounteredFreeType = nullptr);
|
||||
TypeId clone(TypeId tp, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, bool* encounteredFreeType = nullptr);
|
||||
TypeFun clone(const TypeFun& typeFun, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, bool* encounteredFreeType = nullptr);
|
||||
struct CloneState
|
||||
{
|
||||
int recursionCount = 0;
|
||||
bool encounteredFreeType = false;
|
||||
};
|
||||
|
||||
TypePackId clone(TypePackId tp, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState& cloneState);
|
||||
TypeId clone(TypeId tp, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState& cloneState);
|
||||
TypeFun clone(const TypeFun& typeFun, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState& cloneState);
|
||||
|
||||
struct Module
|
||||
{
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
#pragma once
|
||||
|
||||
#include "Luau/Common.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
struct TypeVar;
|
||||
using TypeId = const TypeVar*;
|
||||
|
||||
struct TypePackVar;
|
||||
using TypePackId = const TypePackVar*;
|
||||
|
||||
struct ToDotOptions
|
||||
{
|
||||
bool showPointers = true; // Show pointer value in the node label
|
||||
bool duplicatePrimitives = true; // Display primitive types and 'any' as separate nodes
|
||||
};
|
||||
|
||||
std::string toDot(TypeId ty, const ToDotOptions& opts);
|
||||
std::string toDot(TypePackId tp, const ToDotOptions& opts);
|
||||
|
||||
std::string toDot(TypeId ty);
|
||||
std::string toDot(TypePackId tp);
|
||||
|
||||
void dumpDot(TypeId ty);
|
||||
void dumpDot(TypePackId tp);
|
||||
|
||||
} // namespace Luau
|
|
@ -25,15 +25,6 @@ struct TxnLog
|
|||
{
|
||||
}
|
||||
|
||||
explicit TxnLog(const std::vector<std::pair<TypeId, TypeId>>& ownedSeen)
|
||||
: originalSeenSize(ownedSeen.size())
|
||||
, ownedSeen(ownedSeen)
|
||||
, sharedSeen(nullptr)
|
||||
{
|
||||
// This is deprecated!
|
||||
LUAU_ASSERT(!FFlag::LuauShareTxnSeen);
|
||||
}
|
||||
|
||||
TxnLog(const TxnLog&) = delete;
|
||||
TxnLog& operator=(const TxnLog&) = delete;
|
||||
|
||||
|
|
|
@ -297,7 +297,6 @@ private:
|
|||
|
||||
private:
|
||||
Unifier mkUnifier(const Location& location);
|
||||
Unifier mkUnifier(const std::vector<std::pair<TypeId, TypeId>>& seen, const Location& location);
|
||||
|
||||
// These functions are only safe to call when we are in the process of typechecking a module.
|
||||
|
||||
|
|
|
@ -517,21 +517,6 @@ extern SingletonTypes singletonTypes;
|
|||
void persist(TypeId ty);
|
||||
void persist(TypePackId tp);
|
||||
|
||||
struct ToDotOptions
|
||||
{
|
||||
bool showPointers = true; // Show pointer value in the node label
|
||||
bool duplicatePrimitives = true; // Display primitive types and 'any' as separate nodes
|
||||
};
|
||||
|
||||
std::string toDot(TypeId ty, const ToDotOptions& opts);
|
||||
std::string toDot(TypePackId tp, const ToDotOptions& opts);
|
||||
|
||||
std::string toDot(TypeId ty);
|
||||
std::string toDot(TypePackId tp);
|
||||
|
||||
void dumpDot(TypeId ty);
|
||||
void dumpDot(TypePackId tp);
|
||||
|
||||
const TypeLevel* getLevel(TypeId ty);
|
||||
TypeLevel* getMutableLevel(TypeId ty);
|
||||
|
||||
|
|
|
@ -19,12 +19,6 @@ enum Variance
|
|||
Invariant
|
||||
};
|
||||
|
||||
struct UnifierCounters
|
||||
{
|
||||
int recursionCount = 0;
|
||||
int iterationCount = 0;
|
||||
};
|
||||
|
||||
struct Unifier
|
||||
{
|
||||
TypeArena* const types;
|
||||
|
@ -37,20 +31,11 @@ struct Unifier
|
|||
Variance variance = Covariant;
|
||||
CountMismatch::Context ctx = CountMismatch::Arg;
|
||||
|
||||
UnifierCounters* counters;
|
||||
UnifierCounters countersData;
|
||||
|
||||
std::shared_ptr<UnifierCounters> counters_DEPRECATED;
|
||||
|
||||
UnifierSharedState& sharedState;
|
||||
|
||||
Unifier(TypeArena* types, Mode mode, ScopePtr globalScope, const Location& location, Variance variance, UnifierSharedState& sharedState);
|
||||
Unifier(TypeArena* types, Mode mode, ScopePtr globalScope, const std::vector<std::pair<TypeId, TypeId>>& ownedSeen, const Location& location,
|
||||
Variance variance, UnifierSharedState& sharedState, const std::shared_ptr<UnifierCounters>& counters_DEPRECATED = nullptr,
|
||||
UnifierCounters* counters = nullptr);
|
||||
Unifier(TypeArena* types, Mode mode, ScopePtr globalScope, std::vector<std::pair<TypeId, TypeId>>* sharedSeen, const Location& location,
|
||||
Variance variance, UnifierSharedState& sharedState, const std::shared_ptr<UnifierCounters>& counters_DEPRECATED = nullptr,
|
||||
UnifierCounters* counters = nullptr);
|
||||
Variance variance, UnifierSharedState& sharedState);
|
||||
|
||||
// Test whether the two type vars unify. Never commits the result.
|
||||
ErrorVec canUnify(TypeId superTy, TypeId subTy);
|
||||
|
@ -92,9 +77,9 @@ private:
|
|||
public:
|
||||
// Report an "infinite type error" if the type "needle" already occurs within "haystack"
|
||||
void occursCheck(TypeId needle, TypeId haystack);
|
||||
void occursCheck(std::unordered_set<TypeId>& seen_DEPRECATED, DenseHashSet<TypeId>& seen, TypeId needle, TypeId haystack);
|
||||
void occursCheck(DenseHashSet<TypeId>& seen, TypeId needle, TypeId haystack);
|
||||
void occursCheck(TypePackId needle, TypePackId haystack);
|
||||
void occursCheck(std::unordered_set<TypePackId>& seen_DEPRECATED, DenseHashSet<TypePackId>& seen, TypePackId needle, TypePackId haystack);
|
||||
void occursCheck(DenseHashSet<TypePackId>& seen, TypePackId needle, TypePackId haystack);
|
||||
|
||||
Unifier makeChildUnifier();
|
||||
|
||||
|
@ -106,10 +91,6 @@ private:
|
|||
|
||||
[[noreturn]] void ice(const std::string& message, const Location& location);
|
||||
[[noreturn]] void ice(const std::string& message);
|
||||
|
||||
// Remove with FFlagLuauCacheUnifyTableResults
|
||||
DenseHashSet<TypeId> tempSeenTy_DEPRECATED{nullptr};
|
||||
DenseHashSet<TypePackId> tempSeenTp_DEPRECATED{nullptr};
|
||||
};
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -24,6 +24,12 @@ struct TypeIdPairHash
|
|||
}
|
||||
};
|
||||
|
||||
struct UnifierCounters
|
||||
{
|
||||
int recursionCount = 0;
|
||||
int iterationCount = 0;
|
||||
};
|
||||
|
||||
struct UnifierSharedState
|
||||
{
|
||||
UnifierSharedState(InternalErrorReporter* iceHandler)
|
||||
|
@ -39,6 +45,8 @@ struct UnifierSharedState
|
|||
|
||||
DenseHashSet<TypeId> tempSeenTy{nullptr};
|
||||
DenseHashSet<TypePackId> tempSeenTp{nullptr};
|
||||
|
||||
UnifierCounters counters;
|
||||
};
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
#include "Luau/TypeVar.h"
|
||||
#include "Luau/TypePack.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauCacheUnifyTableResults)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -101,7 +99,7 @@ void visit(TypeId ty, F& f, Set& seen)
|
|||
// Some visitors want to see bound tables, that's why we visit the original type
|
||||
if (apply(ty, *ttv, seen, f))
|
||||
{
|
||||
if (FFlag::LuauCacheUnifyTableResults && ttv->boundTo)
|
||||
if (ttv->boundTo)
|
||||
{
|
||||
visit(*ttv->boundTo, f, seen);
|
||||
}
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
#include <unordered_set>
|
||||
#include <utility>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(ElseElseIfCompletionImprovements, false);
|
||||
LUAU_FASTFLAG(LuauIfElseExpressionAnalysisSupport)
|
||||
LUAU_FASTFLAGVARIABLE(LuauAutocompleteAvoidMutation, false);
|
||||
LUAU_FASTFLAGVARIABLE(LuauAutocompletePreferToCallFunctions, false);
|
||||
|
||||
static const std::unordered_set<std::string> kStatementStartingKeywords = {
|
||||
"while", "if", "local", "repeat", "function", "do", "for", "return", "break", "continue", "type", "export"};
|
||||
|
@ -203,8 +203,9 @@ static TypeCorrectKind checkTypeCorrectKind(const Module& module, TypeArena* typ
|
|||
{
|
||||
SeenTypes seenTypes;
|
||||
SeenTypePacks seenTypePacks;
|
||||
expectedType = clone(expectedType, *typeArena, seenTypes, seenTypePacks, nullptr);
|
||||
actualType = clone(actualType, *typeArena, seenTypes, seenTypePacks, nullptr);
|
||||
CloneState cloneState;
|
||||
expectedType = clone(expectedType, *typeArena, seenTypes, seenTypePacks, cloneState);
|
||||
actualType = clone(actualType, *typeArena, seenTypes, seenTypePacks, cloneState);
|
||||
|
||||
auto errors = unifier.canUnify(expectedType, actualType);
|
||||
return errors.empty();
|
||||
|
@ -229,28 +230,51 @@ static TypeCorrectKind checkTypeCorrectKind(const Module& module, TypeArena* typ
|
|||
|
||||
TypeId expectedType = follow(*it);
|
||||
|
||||
if (canUnify(expectedType, ty))
|
||||
return TypeCorrectKind::Correct;
|
||||
|
||||
// We also want to suggest functions that return compatible result
|
||||
const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty);
|
||||
|
||||
if (!ftv)
|
||||
return TypeCorrectKind::None;
|
||||
|
||||
auto [retHead, retTail] = flatten(ftv->retType);
|
||||
|
||||
if (!retHead.empty())
|
||||
return canUnify(expectedType, retHead.front()) ? TypeCorrectKind::CorrectFunctionResult : TypeCorrectKind::None;
|
||||
|
||||
// We might only have a variadic tail pack, check if the element is compatible
|
||||
if (retTail)
|
||||
if (FFlag::LuauAutocompletePreferToCallFunctions)
|
||||
{
|
||||
if (const VariadicTypePack* vtp = get<VariadicTypePack>(follow(*retTail)))
|
||||
return canUnify(expectedType, vtp->ty) ? TypeCorrectKind::CorrectFunctionResult : TypeCorrectKind::None;
|
||||
}
|
||||
// We also want to suggest functions that return compatible result
|
||||
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty))
|
||||
{
|
||||
auto [retHead, retTail] = flatten(ftv->retType);
|
||||
|
||||
return TypeCorrectKind::None;
|
||||
if (!retHead.empty() && canUnify(expectedType, retHead.front()))
|
||||
return TypeCorrectKind::CorrectFunctionResult;
|
||||
|
||||
// We might only have a variadic tail pack, check if the element is compatible
|
||||
if (retTail)
|
||||
{
|
||||
if (const VariadicTypePack* vtp = get<VariadicTypePack>(follow(*retTail)); vtp && canUnify(expectedType, vtp->ty))
|
||||
return TypeCorrectKind::CorrectFunctionResult;
|
||||
}
|
||||
}
|
||||
|
||||
return canUnify(expectedType, ty) ? TypeCorrectKind::Correct : TypeCorrectKind::None;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (canUnify(expectedType, ty))
|
||||
return TypeCorrectKind::Correct;
|
||||
|
||||
// We also want to suggest functions that return compatible result
|
||||
const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty);
|
||||
|
||||
if (!ftv)
|
||||
return TypeCorrectKind::None;
|
||||
|
||||
auto [retHead, retTail] = flatten(ftv->retType);
|
||||
|
||||
if (!retHead.empty())
|
||||
return canUnify(expectedType, retHead.front()) ? TypeCorrectKind::CorrectFunctionResult : TypeCorrectKind::None;
|
||||
|
||||
// We might only have a variadic tail pack, check if the element is compatible
|
||||
if (retTail)
|
||||
{
|
||||
if (const VariadicTypePack* vtp = get<VariadicTypePack>(follow(*retTail)))
|
||||
return canUnify(expectedType, vtp->ty) ? TypeCorrectKind::CorrectFunctionResult : TypeCorrectKind::None;
|
||||
}
|
||||
|
||||
return TypeCorrectKind::None;
|
||||
}
|
||||
}
|
||||
|
||||
enum class PropIndexType
|
||||
|
@ -1413,7 +1437,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
|
|||
else if (AstStatWhile* statWhile = extractStat<AstStatWhile>(finder.ancestry); statWhile && !statWhile->hasDo)
|
||||
return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, finder.ancestry};
|
||||
|
||||
else if (AstStatIf* statIf = node->as<AstStatIf>(); FFlag::ElseElseIfCompletionImprovements && statIf && !statIf->hasElse)
|
||||
else if (AstStatIf* statIf = node->as<AstStatIf>(); statIf && !statIf->hasElse)
|
||||
{
|
||||
return {{{"else", AutocompleteEntry{AutocompleteEntryKind::Keyword}}, {"elseif", AutocompleteEntry{AutocompleteEntryKind::Keyword}}},
|
||||
finder.ancestry};
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
LUAU_FASTFLAG(LuauNewRequireTrace2)
|
||||
|
||||
/** FIXME: Many of these type definitions are not quite completely accurate.
|
||||
*
|
||||
* Some of them require richer generics than we have. For instance, we do not yet have a way to talk
|
||||
|
@ -473,9 +471,7 @@ static std::optional<ExprResult<TypePackId>> magicFunctionRequire(
|
|||
if (!checkRequirePath(typechecker, expr.args.data[0]))
|
||||
return std::nullopt;
|
||||
|
||||
const AstExpr* require = FFlag::LuauNewRequireTrace2 ? &expr : expr.args.data[0];
|
||||
|
||||
if (auto moduleInfo = typechecker.resolver->resolveModuleInfo(typechecker.currentModuleName, *require))
|
||||
if (auto moduleInfo = typechecker.resolver->resolveModuleInfo(typechecker.currentModuleName, expr))
|
||||
return ExprResult<TypePackId>{arena.addTypePack({typechecker.checkRequire(scope, *moduleInfo, expr.location)})};
|
||||
|
||||
return std::nullopt;
|
||||
|
|
|
@ -7,57 +7,14 @@
|
|||
|
||||
#include <stdexcept>
|
||||
|
||||
LUAU_FASTFLAG(LuauTypeAliasPacks)
|
||||
|
||||
static std::string wrongNumberOfArgsString_DEPRECATED(size_t expectedCount, size_t actualCount, bool isTypeArgs = false)
|
||||
{
|
||||
std::string s = "expects " + std::to_string(expectedCount) + " ";
|
||||
|
||||
if (isTypeArgs)
|
||||
s += "type ";
|
||||
|
||||
s += "argument";
|
||||
if (expectedCount != 1)
|
||||
s += "s";
|
||||
|
||||
s += ", but ";
|
||||
|
||||
if (actualCount == 0)
|
||||
{
|
||||
s += "none";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (actualCount < expectedCount)
|
||||
s += "only ";
|
||||
|
||||
s += std::to_string(actualCount);
|
||||
}
|
||||
|
||||
s += (actualCount == 1) ? " is" : " are";
|
||||
|
||||
s += " specified";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static std::string wrongNumberOfArgsString(size_t expectedCount, size_t actualCount, const char* argPrefix = nullptr, bool isVariadic = false)
|
||||
{
|
||||
std::string s;
|
||||
std::string s = "expects ";
|
||||
|
||||
if (FFlag::LuauTypeAliasPacks)
|
||||
{
|
||||
s = "expects ";
|
||||
if (isVariadic)
|
||||
s += "at least ";
|
||||
|
||||
if (isVariadic)
|
||||
s += "at least ";
|
||||
|
||||
s += std::to_string(expectedCount) + " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
s = "expects " + std::to_string(expectedCount) + " ";
|
||||
}
|
||||
s += std::to_string(expectedCount) + " ";
|
||||
|
||||
if (argPrefix)
|
||||
s += std::string(argPrefix) + " ";
|
||||
|
@ -188,10 +145,7 @@ struct ErrorConverter
|
|||
return "Function only returns " + std::to_string(e.expected) + " value" + expectedS + ". " + std::to_string(e.actual) +
|
||||
" are required here";
|
||||
case CountMismatch::Arg:
|
||||
if (FFlag::LuauTypeAliasPacks)
|
||||
return "Argument count mismatch. Function " + wrongNumberOfArgsString(e.expected, e.actual);
|
||||
else
|
||||
return "Argument count mismatch. Function " + wrongNumberOfArgsString_DEPRECATED(e.expected, e.actual);
|
||||
return "Argument count mismatch. Function " + wrongNumberOfArgsString(e.expected, e.actual);
|
||||
}
|
||||
|
||||
LUAU_ASSERT(!"Unknown context");
|
||||
|
@ -232,7 +186,7 @@ struct ErrorConverter
|
|||
std::string operator()(const Luau::IncorrectGenericParameterCount& e) const
|
||||
{
|
||||
std::string name = e.name;
|
||||
if (!e.typeFun.typeParams.empty() || (FFlag::LuauTypeAliasPacks && !e.typeFun.typePackParams.empty()))
|
||||
if (!e.typeFun.typeParams.empty() || !e.typeFun.typePackParams.empty())
|
||||
{
|
||||
name += "<";
|
||||
bool first = true;
|
||||
|
@ -246,36 +200,25 @@ struct ErrorConverter
|
|||
name += toString(t);
|
||||
}
|
||||
|
||||
if (FFlag::LuauTypeAliasPacks)
|
||||
for (TypePackId t : e.typeFun.typePackParams)
|
||||
{
|
||||
for (TypePackId t : e.typeFun.typePackParams)
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
name += ", ";
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
name += ", ";
|
||||
|
||||
name += toString(t);
|
||||
}
|
||||
name += toString(t);
|
||||
}
|
||||
|
||||
name += ">";
|
||||
}
|
||||
|
||||
if (FFlag::LuauTypeAliasPacks)
|
||||
{
|
||||
if (e.typeFun.typeParams.size() != e.actualParameters)
|
||||
return "Generic type '" + name + "' " +
|
||||
wrongNumberOfArgsString(e.typeFun.typeParams.size(), e.actualParameters, "type", !e.typeFun.typePackParams.empty());
|
||||
if (e.typeFun.typeParams.size() != e.actualParameters)
|
||||
return "Generic type '" + name + "' " +
|
||||
wrongNumberOfArgsString(e.typeFun.typeParams.size(), e.actualParameters, "type", !e.typeFun.typePackParams.empty());
|
||||
|
||||
return "Generic type '" + name + "' " +
|
||||
wrongNumberOfArgsString(e.typeFun.typePackParams.size(), e.actualPackParameters, "type pack", /*isVariadic*/ false);
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Generic type '" + name + "' " +
|
||||
wrongNumberOfArgsString_DEPRECATED(e.typeFun.typeParams.size(), e.actualParameters, /*isTypeArgs*/ true);
|
||||
}
|
||||
return "Generic type '" + name + "' " +
|
||||
wrongNumberOfArgsString(e.typeFun.typePackParams.size(), e.actualPackParameters, "type pack", /*isVariadic*/ false);
|
||||
}
|
||||
|
||||
std::string operator()(const Luau::SyntaxError& e) const
|
||||
|
@ -591,11 +534,8 @@ bool IncorrectGenericParameterCount::operator==(const IncorrectGenericParameterC
|
|||
if (typeFun.typeParams.size() != rhs.typeFun.typeParams.size())
|
||||
return false;
|
||||
|
||||
if (FFlag::LuauTypeAliasPacks)
|
||||
{
|
||||
if (typeFun.typePackParams.size() != rhs.typeFun.typePackParams.size())
|
||||
return false;
|
||||
}
|
||||
if (typeFun.typePackParams.size() != rhs.typeFun.typePackParams.size())
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < typeFun.typeParams.size(); ++i)
|
||||
{
|
||||
|
@ -603,13 +543,10 @@ bool IncorrectGenericParameterCount::operator==(const IncorrectGenericParameterC
|
|||
return false;
|
||||
}
|
||||
|
||||
if (FFlag::LuauTypeAliasPacks)
|
||||
for (size_t i = 0; i < typeFun.typePackParams.size(); ++i)
|
||||
{
|
||||
for (size_t i = 0; i < typeFun.typePackParams.size(); ++i)
|
||||
{
|
||||
if (typeFun.typePackParams[i] != rhs.typeFun.typePackParams[i])
|
||||
return false;
|
||||
}
|
||||
if (typeFun.typePackParams[i] != rhs.typeFun.typePackParams[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -733,14 +670,14 @@ bool containsParseErrorName(const TypeError& error)
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
void copyError(T& e, TypeArena& destArena, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks)
|
||||
void copyError(T& e, TypeArena& destArena, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState cloneState)
|
||||
{
|
||||
auto clone = [&](auto&& ty) {
|
||||
return ::Luau::clone(ty, destArena, seenTypes, seenTypePacks);
|
||||
return ::Luau::clone(ty, destArena, seenTypes, seenTypePacks, cloneState);
|
||||
};
|
||||
|
||||
auto visitErrorData = [&](auto&& e) {
|
||||
copyError(e, destArena, seenTypes, seenTypePacks);
|
||||
copyError(e, destArena, seenTypes, seenTypePacks, cloneState);
|
||||
};
|
||||
|
||||
if constexpr (false)
|
||||
|
@ -864,9 +801,10 @@ void copyErrors(ErrorVec& errors, TypeArena& destArena)
|
|||
{
|
||||
SeenTypes seenTypes;
|
||||
SeenTypePacks seenTypePacks;
|
||||
CloneState cloneState;
|
||||
|
||||
auto visitErrorData = [&](auto&& e) {
|
||||
copyError(e, destArena, seenTypes, seenTypePacks);
|
||||
copyError(e, destArena, seenTypes, seenTypePacks, cloneState);
|
||||
};
|
||||
|
||||
LUAU_ASSERT(!destArena.typeVars.isFrozen());
|
||||
|
|
|
@ -18,10 +18,7 @@
|
|||
LUAU_FASTFLAG(LuauInferInNoCheckMode)
|
||||
LUAU_FASTFLAGVARIABLE(LuauTypeCheckTwice, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauKnowsTheDataModel3, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauResolveModuleNameWithoutACurrentModule, false)
|
||||
LUAU_FASTFLAG(LuauTraceRequireLookupChild)
|
||||
LUAU_FASTFLAGVARIABLE(LuauPersistDefinitionFileTypes, false)
|
||||
LUAU_FASTFLAG(LuauNewRequireTrace2)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -96,10 +93,11 @@ LoadDefinitionFileResult loadDefinitionFile(TypeChecker& typeChecker, ScopePtr t
|
|||
|
||||
SeenTypes seenTypes;
|
||||
SeenTypePacks seenTypePacks;
|
||||
CloneState cloneState;
|
||||
|
||||
for (const auto& [name, ty] : checkedModule->declaredGlobals)
|
||||
{
|
||||
TypeId globalTy = clone(ty, typeChecker.globalTypes, seenTypes, seenTypePacks);
|
||||
TypeId globalTy = clone(ty, typeChecker.globalTypes, seenTypes, seenTypePacks, cloneState);
|
||||
std::string documentationSymbol = packageName + "/global/" + name;
|
||||
generateDocumentationSymbols(globalTy, documentationSymbol);
|
||||
targetScope->bindings[typeChecker.globalNames.names->getOrAdd(name.c_str())] = {globalTy, Location(), false, {}, documentationSymbol};
|
||||
|
@ -110,7 +108,7 @@ LoadDefinitionFileResult loadDefinitionFile(TypeChecker& typeChecker, ScopePtr t
|
|||
|
||||
for (const auto& [name, ty] : checkedModule->getModuleScope()->exportedTypeBindings)
|
||||
{
|
||||
TypeFun globalTy = clone(ty, typeChecker.globalTypes, seenTypes, seenTypePacks);
|
||||
TypeFun globalTy = clone(ty, typeChecker.globalTypes, seenTypes, seenTypePacks, cloneState);
|
||||
std::string documentationSymbol = packageName + "/globaltype/" + name;
|
||||
generateDocumentationSymbols(globalTy.type, documentationSymbol);
|
||||
targetScope->exportedTypeBindings[name] = globalTy;
|
||||
|
@ -427,15 +425,16 @@ CheckResult Frontend::check(const ModuleName& name)
|
|||
|
||||
SeenTypes seenTypes;
|
||||
SeenTypePacks seenTypePacks;
|
||||
CloneState cloneState;
|
||||
|
||||
for (const auto& [expr, strictTy] : strictModule->astTypes)
|
||||
module->astTypes[expr] = clone(strictTy, module->interfaceTypes, seenTypes, seenTypePacks);
|
||||
module->astTypes[expr] = clone(strictTy, module->interfaceTypes, seenTypes, seenTypePacks, cloneState);
|
||||
|
||||
for (const auto& [expr, strictTy] : strictModule->astOriginalCallTypes)
|
||||
module->astOriginalCallTypes[expr] = clone(strictTy, module->interfaceTypes, seenTypes, seenTypePacks);
|
||||
module->astOriginalCallTypes[expr] = clone(strictTy, module->interfaceTypes, seenTypes, seenTypePacks, cloneState);
|
||||
|
||||
for (const auto& [expr, strictTy] : strictModule->astExpectedTypes)
|
||||
module->astExpectedTypes[expr] = clone(strictTy, module->interfaceTypes, seenTypes, seenTypePacks);
|
||||
module->astExpectedTypes[expr] = clone(strictTy, module->interfaceTypes, seenTypes, seenTypePacks, cloneState);
|
||||
}
|
||||
|
||||
stats.timeCheck += getTimestamp() - timestamp;
|
||||
|
@ -885,16 +884,13 @@ std::optional<ModuleInfo> FrontendModuleResolver::resolveModuleInfo(const Module
|
|||
// If we can't find the current module name, that's because we bypassed the frontend's initializer
|
||||
// and called typeChecker.check directly. (This is done by autocompleteSource, for example).
|
||||
// In that case, requires will always fail.
|
||||
if (FFlag::LuauResolveModuleNameWithoutACurrentModule)
|
||||
return std::nullopt;
|
||||
else
|
||||
throw std::runtime_error("Frontend::resolveModuleName: Unknown currentModuleName '" + currentModuleName + "'");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto& exprs = it->second.exprs;
|
||||
|
||||
const ModuleInfo* info = exprs.find(&pathExpr);
|
||||
if (!info || (!FFlag::LuauNewRequireTrace2 && info->name.empty()))
|
||||
if (!info)
|
||||
return std::nullopt;
|
||||
|
||||
return *info;
|
||||
|
@ -911,10 +907,7 @@ const ModulePtr FrontendModuleResolver::getModule(const ModuleName& moduleName)
|
|||
|
||||
bool FrontendModuleResolver::moduleExists(const ModuleName& moduleName) const
|
||||
{
|
||||
if (FFlag::LuauNewRequireTrace2)
|
||||
return frontend->sourceNodes.count(moduleName) != 0;
|
||||
else
|
||||
return frontend->fileResolver->moduleExists(moduleName);
|
||||
return frontend->sourceNodes.count(moduleName) != 0;
|
||||
}
|
||||
|
||||
std::string FrontendModuleResolver::getHumanReadableModuleName(const ModuleName& moduleName) const
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
#include "Luau/IostreamHelpers.h"
|
||||
#include "Luau/ToString.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauTypeAliasPacks)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -94,7 +92,7 @@ std::ostream& operator<<(std::ostream& stream, const IncorrectGenericParameterCo
|
|||
{
|
||||
stream << "IncorrectGenericParameterCount { name = " << error.name;
|
||||
|
||||
if (!error.typeFun.typeParams.empty() || (FFlag::LuauTypeAliasPacks && !error.typeFun.typePackParams.empty()))
|
||||
if (!error.typeFun.typeParams.empty() || !error.typeFun.typePackParams.empty())
|
||||
{
|
||||
stream << "<";
|
||||
bool first = true;
|
||||
|
@ -108,17 +106,14 @@ std::ostream& operator<<(std::ostream& stream, const IncorrectGenericParameterCo
|
|||
stream << toString(t);
|
||||
}
|
||||
|
||||
if (FFlag::LuauTypeAliasPacks)
|
||||
for (TypePackId t : error.typeFun.typePackParams)
|
||||
{
|
||||
for (TypePackId t : error.typeFun.typePackParams)
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
stream << ", ";
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
stream << ", ";
|
||||
|
||||
stream << toString(t);
|
||||
}
|
||||
stream << toString(t);
|
||||
}
|
||||
|
||||
stream << ">";
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
#include "Luau/StringUtils.h"
|
||||
#include "Luau/Common.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauTypeAliasPacks)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -615,12 +613,7 @@ struct AstJsonEncoder : public AstVisitor
|
|||
writeNode(node, "AstStatTypeAlias", [&]() {
|
||||
PROP(name);
|
||||
PROP(generics);
|
||||
|
||||
if (FFlag::LuauTypeAliasPacks)
|
||||
{
|
||||
PROP(genericPacks);
|
||||
}
|
||||
|
||||
PROP(genericPacks);
|
||||
PROP(type);
|
||||
PROP(exported);
|
||||
});
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
#include "Luau/Module.h"
|
||||
|
||||
#include "Luau/Common.h"
|
||||
#include "Luau/RecursionCounter.h"
|
||||
#include "Luau/Scope.h"
|
||||
#include "Luau/TypeInfer.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/TypeVar.h"
|
||||
#include "Luau/VisitTypeVar.h"
|
||||
#include "Luau/Common.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauFreezeArena, false)
|
||||
LUAU_FASTFLAGVARIABLE(DebugLuauTrackOwningArena, false)
|
||||
LUAU_FASTFLAG(LuauCaptureBrokenCommentSpans)
|
||||
LUAU_FASTFLAG(LuauTypeAliasPacks)
|
||||
LUAU_FASTFLAGVARIABLE(LuauCloneBoundTables, false)
|
||||
LUAU_FASTINTVARIABLE(LuauTypeCloneRecursionLimit, 0)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
@ -120,12 +120,6 @@ TypePackId TypeArena::addTypePack(TypePackVar tp)
|
|||
return allocated;
|
||||
}
|
||||
|
||||
using SeenTypes = std::unordered_map<TypeId, TypeId>;
|
||||
using SeenTypePacks = std::unordered_map<TypePackId, TypePackId>;
|
||||
|
||||
TypePackId clone(TypePackId tp, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, bool* encounteredFreeType);
|
||||
TypeId clone(TypeId tp, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, bool* encounteredFreeType);
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
@ -138,11 +132,12 @@ struct TypePackCloner;
|
|||
|
||||
struct TypeCloner
|
||||
{
|
||||
TypeCloner(TypeArena& dest, TypeId typeId, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks)
|
||||
TypeCloner(TypeArena& dest, TypeId typeId, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState& cloneState)
|
||||
: dest(dest)
|
||||
, typeId(typeId)
|
||||
, seenTypes(seenTypes)
|
||||
, seenTypePacks(seenTypePacks)
|
||||
, cloneState(cloneState)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -150,8 +145,7 @@ struct TypeCloner
|
|||
TypeId typeId;
|
||||
SeenTypes& seenTypes;
|
||||
SeenTypePacks& seenTypePacks;
|
||||
|
||||
bool* encounteredFreeType = nullptr;
|
||||
CloneState& cloneState;
|
||||
|
||||
template<typename T>
|
||||
void defaultClone(const T& t);
|
||||
|
@ -178,13 +172,14 @@ struct TypePackCloner
|
|||
TypePackId typePackId;
|
||||
SeenTypes& seenTypes;
|
||||
SeenTypePacks& seenTypePacks;
|
||||
bool* encounteredFreeType = nullptr;
|
||||
CloneState& cloneState;
|
||||
|
||||
TypePackCloner(TypeArena& dest, TypePackId typePackId, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks)
|
||||
TypePackCloner(TypeArena& dest, TypePackId typePackId, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState& cloneState)
|
||||
: dest(dest)
|
||||
, typePackId(typePackId)
|
||||
, seenTypes(seenTypes)
|
||||
, seenTypePacks(seenTypePacks)
|
||||
, cloneState(cloneState)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -197,8 +192,7 @@ struct TypePackCloner
|
|||
|
||||
void operator()(const Unifiable::Free& t)
|
||||
{
|
||||
if (encounteredFreeType)
|
||||
*encounteredFreeType = true;
|
||||
cloneState.encounteredFreeType = true;
|
||||
|
||||
TypePackId err = singletonTypes.errorRecoveryTypePack(singletonTypes.anyTypePack);
|
||||
TypePackId cloned = dest.addTypePack(*err);
|
||||
|
@ -218,13 +212,13 @@ struct TypePackCloner
|
|||
// We just need to be sure that we rewrite pointers both to the binder and the bindee to the same pointer.
|
||||
void operator()(const Unifiable::Bound<TypePackId>& t)
|
||||
{
|
||||
TypePackId cloned = clone(t.boundTo, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
TypePackId cloned = clone(t.boundTo, dest, seenTypes, seenTypePacks, cloneState);
|
||||
seenTypePacks[typePackId] = cloned;
|
||||
}
|
||||
|
||||
void operator()(const VariadicTypePack& t)
|
||||
{
|
||||
TypePackId cloned = dest.addTypePack(TypePackVar{VariadicTypePack{clone(t.ty, dest, seenTypes, seenTypePacks, encounteredFreeType)}});
|
||||
TypePackId cloned = dest.addTypePack(TypePackVar{VariadicTypePack{clone(t.ty, dest, seenTypes, seenTypePacks, cloneState)}});
|
||||
seenTypePacks[typePackId] = cloned;
|
||||
}
|
||||
|
||||
|
@ -236,10 +230,10 @@ struct TypePackCloner
|
|||
seenTypePacks[typePackId] = cloned;
|
||||
|
||||
for (TypeId ty : t.head)
|
||||
destTp->head.push_back(clone(ty, dest, seenTypes, seenTypePacks, encounteredFreeType));
|
||||
destTp->head.push_back(clone(ty, dest, seenTypes, seenTypePacks, cloneState));
|
||||
|
||||
if (t.tail)
|
||||
destTp->tail = clone(*t.tail, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
destTp->tail = clone(*t.tail, dest, seenTypes, seenTypePacks, cloneState);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -252,8 +246,7 @@ void TypeCloner::defaultClone(const T& t)
|
|||
|
||||
void TypeCloner::operator()(const Unifiable::Free& t)
|
||||
{
|
||||
if (encounteredFreeType)
|
||||
*encounteredFreeType = true;
|
||||
cloneState.encounteredFreeType = true;
|
||||
TypeId err = singletonTypes.errorRecoveryType(singletonTypes.anyType);
|
||||
TypeId cloned = dest.addType(*err);
|
||||
seenTypes[typeId] = cloned;
|
||||
|
@ -266,7 +259,7 @@ void TypeCloner::operator()(const Unifiable::Generic& t)
|
|||
|
||||
void TypeCloner::operator()(const Unifiable::Bound<TypeId>& t)
|
||||
{
|
||||
TypeId boundTo = clone(t.boundTo, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
TypeId boundTo = clone(t.boundTo, dest, seenTypes, seenTypePacks, cloneState);
|
||||
seenTypes[typeId] = boundTo;
|
||||
}
|
||||
|
||||
|
@ -294,23 +287,23 @@ void TypeCloner::operator()(const FunctionTypeVar& t)
|
|||
seenTypes[typeId] = result;
|
||||
|
||||
for (TypeId generic : t.generics)
|
||||
ftv->generics.push_back(clone(generic, dest, seenTypes, seenTypePacks, encounteredFreeType));
|
||||
ftv->generics.push_back(clone(generic, dest, seenTypes, seenTypePacks, cloneState));
|
||||
|
||||
for (TypePackId genericPack : t.genericPacks)
|
||||
ftv->genericPacks.push_back(clone(genericPack, dest, seenTypes, seenTypePacks, encounteredFreeType));
|
||||
ftv->genericPacks.push_back(clone(genericPack, dest, seenTypes, seenTypePacks, cloneState));
|
||||
|
||||
ftv->tags = t.tags;
|
||||
ftv->argTypes = clone(t.argTypes, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
ftv->argTypes = clone(t.argTypes, dest, seenTypes, seenTypePacks, cloneState);
|
||||
ftv->argNames = t.argNames;
|
||||
ftv->retType = clone(t.retType, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
ftv->retType = clone(t.retType, dest, seenTypes, seenTypePacks, cloneState);
|
||||
}
|
||||
|
||||
void TypeCloner::operator()(const TableTypeVar& t)
|
||||
{
|
||||
// If table is now bound to another one, we ignore the content of the original
|
||||
if (FFlag::LuauCloneBoundTables && t.boundTo)
|
||||
if (t.boundTo)
|
||||
{
|
||||
TypeId boundTo = clone(*t.boundTo, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
TypeId boundTo = clone(*t.boundTo, dest, seenTypes, seenTypePacks, cloneState);
|
||||
seenTypes[typeId] = boundTo;
|
||||
return;
|
||||
}
|
||||
|
@ -326,34 +319,21 @@ void TypeCloner::operator()(const TableTypeVar& t)
|
|||
ttv->level = TypeLevel{0, 0};
|
||||
|
||||
for (const auto& [name, prop] : t.props)
|
||||
ttv->props[name] = {clone(prop.type, dest, seenTypes, seenTypePacks, encounteredFreeType), prop.deprecated, {}, prop.location, prop.tags};
|
||||
ttv->props[name] = {clone(prop.type, dest, seenTypes, seenTypePacks, cloneState), prop.deprecated, {}, prop.location, prop.tags};
|
||||
|
||||
if (t.indexer)
|
||||
ttv->indexer = TableIndexer{clone(t.indexer->indexType, dest, seenTypes, seenTypePacks, encounteredFreeType),
|
||||
clone(t.indexer->indexResultType, dest, seenTypes, seenTypePacks, encounteredFreeType)};
|
||||
|
||||
if (!FFlag::LuauCloneBoundTables)
|
||||
{
|
||||
if (t.boundTo)
|
||||
ttv->boundTo = clone(*t.boundTo, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
}
|
||||
ttv->indexer = TableIndexer{clone(t.indexer->indexType, dest, seenTypes, seenTypePacks, cloneState),
|
||||
clone(t.indexer->indexResultType, dest, seenTypes, seenTypePacks, cloneState)};
|
||||
|
||||
for (TypeId& arg : ttv->instantiatedTypeParams)
|
||||
arg = clone(arg, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
arg = clone(arg, dest, seenTypes, seenTypePacks, cloneState);
|
||||
|
||||
if (FFlag::LuauTypeAliasPacks)
|
||||
{
|
||||
for (TypePackId& arg : ttv->instantiatedTypePackParams)
|
||||
arg = clone(arg, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
}
|
||||
for (TypePackId& arg : ttv->instantiatedTypePackParams)
|
||||
arg = clone(arg, dest, seenTypes, seenTypePacks, cloneState);
|
||||
|
||||
if (ttv->state == TableState::Free)
|
||||
{
|
||||
if (FFlag::LuauCloneBoundTables || !t.boundTo)
|
||||
{
|
||||
if (encounteredFreeType)
|
||||
*encounteredFreeType = true;
|
||||
}
|
||||
cloneState.encounteredFreeType = true;
|
||||
|
||||
ttv->state = TableState::Sealed;
|
||||
}
|
||||
|
@ -369,8 +349,8 @@ void TypeCloner::operator()(const MetatableTypeVar& t)
|
|||
MetatableTypeVar* mtv = getMutable<MetatableTypeVar>(result);
|
||||
seenTypes[typeId] = result;
|
||||
|
||||
mtv->table = clone(t.table, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
mtv->metatable = clone(t.metatable, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
mtv->table = clone(t.table, dest, seenTypes, seenTypePacks, cloneState);
|
||||
mtv->metatable = clone(t.metatable, dest, seenTypes, seenTypePacks, cloneState);
|
||||
}
|
||||
|
||||
void TypeCloner::operator()(const ClassTypeVar& t)
|
||||
|
@ -381,13 +361,13 @@ void TypeCloner::operator()(const ClassTypeVar& t)
|
|||
seenTypes[typeId] = result;
|
||||
|
||||
for (const auto& [name, prop] : t.props)
|
||||
ctv->props[name] = {clone(prop.type, dest, seenTypes, seenTypePacks, encounteredFreeType), prop.deprecated, {}, prop.location, prop.tags};
|
||||
ctv->props[name] = {clone(prop.type, dest, seenTypes, seenTypePacks, cloneState), prop.deprecated, {}, prop.location, prop.tags};
|
||||
|
||||
if (t.parent)
|
||||
ctv->parent = clone(*t.parent, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
ctv->parent = clone(*t.parent, dest, seenTypes, seenTypePacks, cloneState);
|
||||
|
||||
if (t.metatable)
|
||||
ctv->metatable = clone(*t.metatable, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
ctv->metatable = clone(*t.metatable, dest, seenTypes, seenTypePacks, cloneState);
|
||||
}
|
||||
|
||||
void TypeCloner::operator()(const AnyTypeVar& t)
|
||||
|
@ -404,7 +384,7 @@ void TypeCloner::operator()(const UnionTypeVar& t)
|
|||
LUAU_ASSERT(option != nullptr);
|
||||
|
||||
for (TypeId ty : t.options)
|
||||
option->options.push_back(clone(ty, dest, seenTypes, seenTypePacks, encounteredFreeType));
|
||||
option->options.push_back(clone(ty, dest, seenTypes, seenTypePacks, cloneState));
|
||||
}
|
||||
|
||||
void TypeCloner::operator()(const IntersectionTypeVar& t)
|
||||
|
@ -416,7 +396,7 @@ void TypeCloner::operator()(const IntersectionTypeVar& t)
|
|||
LUAU_ASSERT(option != nullptr);
|
||||
|
||||
for (TypeId ty : t.parts)
|
||||
option->parts.push_back(clone(ty, dest, seenTypes, seenTypePacks, encounteredFreeType));
|
||||
option->parts.push_back(clone(ty, dest, seenTypes, seenTypePacks, cloneState));
|
||||
}
|
||||
|
||||
void TypeCloner::operator()(const LazyTypeVar& t)
|
||||
|
@ -426,17 +406,18 @@ void TypeCloner::operator()(const LazyTypeVar& t)
|
|||
|
||||
} // anonymous namespace
|
||||
|
||||
TypePackId clone(TypePackId tp, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, bool* encounteredFreeType)
|
||||
TypePackId clone(TypePackId tp, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState& cloneState)
|
||||
{
|
||||
if (tp->persistent)
|
||||
return tp;
|
||||
|
||||
RecursionLimiter _ra(&cloneState.recursionCount, FInt::LuauTypeCloneRecursionLimit);
|
||||
|
||||
TypePackId& res = seenTypePacks[tp];
|
||||
|
||||
if (res == nullptr)
|
||||
{
|
||||
TypePackCloner cloner{dest, tp, seenTypes, seenTypePacks};
|
||||
cloner.encounteredFreeType = encounteredFreeType;
|
||||
TypePackCloner cloner{dest, tp, seenTypes, seenTypePacks, cloneState};
|
||||
Luau::visit(cloner, tp->ty); // Mutates the storage that 'res' points into.
|
||||
}
|
||||
|
||||
|
@ -446,17 +427,18 @@ TypePackId clone(TypePackId tp, TypeArena& dest, SeenTypes& seenTypes, SeenTypeP
|
|||
return res;
|
||||
}
|
||||
|
||||
TypeId clone(TypeId typeId, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, bool* encounteredFreeType)
|
||||
TypeId clone(TypeId typeId, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState& cloneState)
|
||||
{
|
||||
if (typeId->persistent)
|
||||
return typeId;
|
||||
|
||||
RecursionLimiter _ra(&cloneState.recursionCount, FInt::LuauTypeCloneRecursionLimit);
|
||||
|
||||
TypeId& res = seenTypes[typeId];
|
||||
|
||||
if (res == nullptr)
|
||||
{
|
||||
TypeCloner cloner{dest, typeId, seenTypes, seenTypePacks};
|
||||
cloner.encounteredFreeType = encounteredFreeType;
|
||||
TypeCloner cloner{dest, typeId, seenTypes, seenTypePacks, cloneState};
|
||||
Luau::visit(cloner, typeId->ty); // Mutates the storage that 'res' points into.
|
||||
asMutable(res)->documentationSymbol = typeId->documentationSymbol;
|
||||
}
|
||||
|
@ -467,19 +449,16 @@ TypeId clone(TypeId typeId, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks
|
|||
return res;
|
||||
}
|
||||
|
||||
TypeFun clone(const TypeFun& typeFun, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, bool* encounteredFreeType)
|
||||
TypeFun clone(const TypeFun& typeFun, TypeArena& dest, SeenTypes& seenTypes, SeenTypePacks& seenTypePacks, CloneState& cloneState)
|
||||
{
|
||||
TypeFun result;
|
||||
for (TypeId ty : typeFun.typeParams)
|
||||
result.typeParams.push_back(clone(ty, dest, seenTypes, seenTypePacks, encounteredFreeType));
|
||||
result.typeParams.push_back(clone(ty, dest, seenTypes, seenTypePacks, cloneState));
|
||||
|
||||
if (FFlag::LuauTypeAliasPacks)
|
||||
{
|
||||
for (TypePackId tp : typeFun.typePackParams)
|
||||
result.typePackParams.push_back(clone(tp, dest, seenTypes, seenTypePacks, encounteredFreeType));
|
||||
}
|
||||
for (TypePackId tp : typeFun.typePackParams)
|
||||
result.typePackParams.push_back(clone(tp, dest, seenTypes, seenTypePacks, cloneState));
|
||||
|
||||
result.type = clone(typeFun.type, dest, seenTypes, seenTypePacks, encounteredFreeType);
|
||||
result.type = clone(typeFun.type, dest, seenTypes, seenTypePacks, cloneState);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -519,19 +498,18 @@ bool Module::clonePublicInterface()
|
|||
LUAU_ASSERT(interfaceTypes.typeVars.empty());
|
||||
LUAU_ASSERT(interfaceTypes.typePacks.empty());
|
||||
|
||||
bool encounteredFreeType = false;
|
||||
|
||||
SeenTypePacks seenTypePacks;
|
||||
SeenTypes seenTypes;
|
||||
SeenTypePacks seenTypePacks;
|
||||
CloneState cloneState;
|
||||
|
||||
ScopePtr moduleScope = getModuleScope();
|
||||
|
||||
moduleScope->returnType = clone(moduleScope->returnType, interfaceTypes, seenTypes, seenTypePacks, &encounteredFreeType);
|
||||
moduleScope->returnType = clone(moduleScope->returnType, interfaceTypes, seenTypes, seenTypePacks, cloneState);
|
||||
if (moduleScope->varargPack)
|
||||
moduleScope->varargPack = clone(*moduleScope->varargPack, interfaceTypes, seenTypes, seenTypePacks, &encounteredFreeType);
|
||||
moduleScope->varargPack = clone(*moduleScope->varargPack, interfaceTypes, seenTypes, seenTypePacks, cloneState);
|
||||
|
||||
for (auto& pair : moduleScope->exportedTypeBindings)
|
||||
pair.second = clone(pair.second, interfaceTypes, seenTypes, seenTypePacks, &encounteredFreeType);
|
||||
pair.second = clone(pair.second, interfaceTypes, seenTypes, seenTypePacks, cloneState);
|
||||
|
||||
for (TypeId ty : moduleScope->returnType)
|
||||
if (get<GenericTypeVar>(follow(ty)))
|
||||
|
@ -540,7 +518,7 @@ bool Module::clonePublicInterface()
|
|||
freeze(internalTypes);
|
||||
freeze(interfaceTypes);
|
||||
|
||||
return encounteredFreeType;
|
||||
return cloneState.encounteredFreeType;
|
||||
}
|
||||
|
||||
} // namespace Luau
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include "Luau/VisitTypeVar.h"
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauQuantifyVisitOnce, false)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
|
@ -79,7 +81,16 @@ struct Quantifier
|
|||
void quantify(ModulePtr module, TypeId ty, TypeLevel level)
|
||||
{
|
||||
Quantifier q{std::move(module), level};
|
||||
visitTypeVar(ty, q);
|
||||
|
||||
if (FFlag::LuauQuantifyVisitOnce)
|
||||
{
|
||||
DenseHashSet<void*> seen{nullptr};
|
||||
visitTypeVarOnce(ty, q, seen);
|
||||
}
|
||||
else
|
||||
{
|
||||
visitTypeVar(ty, q);
|
||||
}
|
||||
|
||||
FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(ty);
|
||||
LUAU_ASSERT(ftv);
|
||||
|
|
|
@ -4,182 +4,9 @@
|
|||
#include "Luau/Ast.h"
|
||||
#include "Luau/Module.h"
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauTraceRequireLookupChild, false)
|
||||
LUAU_FASTFLAGVARIABLE(LuauNewRequireTrace2, false)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct RequireTracerOld : AstVisitor
|
||||
{
|
||||
explicit RequireTracerOld(FileResolver* fileResolver, const ModuleName& currentModuleName)
|
||||
: fileResolver(fileResolver)
|
||||
, currentModuleName(currentModuleName)
|
||||
{
|
||||
LUAU_ASSERT(!FFlag::LuauNewRequireTrace2);
|
||||
}
|
||||
|
||||
FileResolver* const fileResolver;
|
||||
ModuleName currentModuleName;
|
||||
DenseHashMap<AstLocal*, ModuleName> locals{nullptr};
|
||||
RequireTraceResult result;
|
||||
|
||||
std::optional<ModuleName> fromAstFragment(AstExpr* expr)
|
||||
{
|
||||
if (auto g = expr->as<AstExprGlobal>(); g && g->name == "script")
|
||||
return currentModuleName;
|
||||
|
||||
return fileResolver->fromAstFragment(expr);
|
||||
}
|
||||
|
||||
bool visit(AstStatLocal* stat) override
|
||||
{
|
||||
for (size_t i = 0; i < stat->vars.size; ++i)
|
||||
{
|
||||
AstLocal* local = stat->vars.data[i];
|
||||
|
||||
if (local->annotation)
|
||||
{
|
||||
if (AstTypeTypeof* ann = local->annotation->as<AstTypeTypeof>())
|
||||
ann->expr->visit(this);
|
||||
}
|
||||
|
||||
if (i < stat->values.size)
|
||||
{
|
||||
AstExpr* expr = stat->values.data[i];
|
||||
expr->visit(this);
|
||||
|
||||
const ModuleInfo* info = result.exprs.find(expr);
|
||||
if (info)
|
||||
locals[local] = info->name;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(AstExprGlobal* global) override
|
||||
{
|
||||
std::optional<ModuleName> name = fromAstFragment(global);
|
||||
if (name)
|
||||
result.exprs[global] = {*name};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(AstExprLocal* local) override
|
||||
{
|
||||
const ModuleName* name = locals.find(local->local);
|
||||
if (name)
|
||||
result.exprs[local] = {*name};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(AstExprIndexName* indexName) override
|
||||
{
|
||||
indexName->expr->visit(this);
|
||||
|
||||
const ModuleInfo* info = result.exprs.find(indexName->expr);
|
||||
if (info)
|
||||
{
|
||||
if (indexName->index == "parent" || indexName->index == "Parent")
|
||||
{
|
||||
if (auto parent = fileResolver->getParentModuleName(info->name))
|
||||
result.exprs[indexName] = {*parent};
|
||||
}
|
||||
else
|
||||
result.exprs[indexName] = {fileResolver->concat(info->name, indexName->index.value)};
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(AstExprIndexExpr* indexExpr) override
|
||||
{
|
||||
indexExpr->expr->visit(this);
|
||||
|
||||
const ModuleInfo* info = result.exprs.find(indexExpr->expr);
|
||||
const AstExprConstantString* str = indexExpr->index->as<AstExprConstantString>();
|
||||
if (info && str)
|
||||
{
|
||||
result.exprs[indexExpr] = {fileResolver->concat(info->name, std::string_view(str->value.data, str->value.size))};
|
||||
}
|
||||
|
||||
indexExpr->index->visit(this);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||