Skip to content

Commit

Permalink
Sync to upstream/release/524 (#462)
Browse files Browse the repository at this point in the history
  • Loading branch information
zeux committed Apr 21, 2022
1 parent 5bb9f37 commit e0a6461
Show file tree
Hide file tree
Showing 53 changed files with 1,593 additions and 352 deletions.
2 changes: 1 addition & 1 deletion Analysis/include/Luau/Clone.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct CloneState
SeenTypePacks seenTypePacks;

int recursionCount = 0;
bool encounteredFreeType = false;
bool encounteredFreeType = false; // TODO: Remove with LuauLosslessClone.
};

TypePackId clone(TypePackId tp, TypeArena& dest, CloneState& cloneState);
Expand Down
21 changes: 15 additions & 6 deletions Analysis/include/Luau/Frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <optional>

LUAU_FASTFLAG(LuauSeparateTypechecks)
LUAU_FASTFLAG(LuauDirtySourceModule)

namespace Luau
{
Expand Down Expand Up @@ -57,19 +58,27 @@ std::optional<ModuleName> pathExprToModuleName(const ModuleName& currentModuleNa

struct SourceNode
{
bool isDirty(bool forAutocomplete) const
bool hasDirtySourceModule() const
{
LUAU_ASSERT(FFlag::LuauDirtySourceModule);

return dirtySourceModule;
}

bool hasDirtyModule(bool forAutocomplete) const
{
if (FFlag::LuauSeparateTypechecks)
return forAutocomplete ? dirtyAutocomplete : dirty;
return forAutocomplete ? dirtyModuleForAutocomplete : dirtyModule;
else
return dirty;
return dirtyModule;
}

ModuleName name;
std::unordered_set<ModuleName> requires;
std::vector<std::pair<ModuleName, Location>> requireLocations;
bool dirty = true;
bool dirtyAutocomplete = true;
bool dirtySourceModule = true;
bool dirtyModule = true;
bool dirtyModuleForAutocomplete = true;
double autocompleteLimitsMult = 1.0;
};

Expand Down Expand Up @@ -163,7 +172,7 @@ struct Frontend
void applyBuiltinDefinitionToEnvironment(const std::string& environmentName, const std::string& definitionName);

private:
std::pair<SourceNode*, SourceModule*> getSourceNode(CheckResult& checkResult, const ModuleName& name, bool forAutocomplete);
std::pair<SourceNode*, SourceModule*> getSourceNode(CheckResult& checkResult, const ModuleName& name, bool forAutocomplete_DEPRECATED);
SourceModule parse(const ModuleName& name, std::string_view src, const ParseOptions& parseOptions);

bool parseGraph(std::vector<ModuleName>& buildQueue, CheckResult& checkResult, const ModuleName& root, bool forAutocomplete);
Expand Down
6 changes: 4 additions & 2 deletions Analysis/include/Luau/TypeVar.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,15 +373,17 @@ struct ClassTypeVar
std::optional<TypeId> metatable; // metaclass?
Tags tags;
std::shared_ptr<ClassUserData> userData;
ModuleName definitionModuleName;

ClassTypeVar(
Name name, Props props, std::optional<TypeId> parent, std::optional<TypeId> metatable, Tags tags, std::shared_ptr<ClassUserData> userData)
ClassTypeVar(Name name, Props props, std::optional<TypeId> parent, std::optional<TypeId> metatable, Tags tags,
std::shared_ptr<ClassUserData> userData, ModuleName definitionModuleName)
: name(name)
, props(props)
, parent(parent)
, metatable(metatable)
, tags(tags)
, userData(userData)
, definitionModuleName(definitionModuleName)
{
}
};
Expand Down
1 change: 0 additions & 1 deletion Analysis/include/Luau/Unifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ struct Unifier

bool canCacheResult(TypeId subTy, TypeId superTy);
void cacheResult(TypeId subTy, TypeId superTy, size_t prevErrorCount);
void cacheResult_DEPRECATED(TypeId subTy, TypeId superTy);

public:
void tryUnify(TypePackId subTy, TypePackId superTy, bool isFunctionCall = false);
Expand Down
2 changes: 1 addition & 1 deletion Analysis/include/Luau/VisitTypeVar.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ inline void unsee(std::unordered_set<void*>& seen, const void* tv)

inline void unsee(DenseHashSet<void*>& seen, const void* tv)
{
// When DenseHashSet is used for 'visitOnce', where don't forget visited elements
// When DenseHashSet is used for 'visitTypeVarOnce', where don't forget visited elements
}

template<typename F, typename Set>
Expand Down
4 changes: 3 additions & 1 deletion Analysis/src/Autocomplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

LUAU_FASTFLAGVARIABLE(LuauIfElseExprFixCompletionIssue, false);
LUAU_FASTFLAGVARIABLE(LuauAutocompleteSingletonTypes, false);
LUAU_FASTFLAGVARIABLE(LuauFixAutocompleteClassSecurityLevel, false);
LUAU_FASTFLAG(LuauSelfCallAutocompleteFix)

static const std::unordered_set<std::string> kStatementStartingKeywords = {
Expand Down Expand Up @@ -462,7 +463,8 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, TypeId
containingClass = containingClass.value_or(cls);
fillProps(cls->props);
if (cls->parent)
autocompleteProps(module, typeArena, rootTy, *cls->parent, indexType, nodes, result, seen, cls);
autocompleteProps(module, typeArena, rootTy, *cls->parent, indexType, nodes, result, seen,
FFlag::LuauFixAutocompleteClassSecurityLevel ? containingClass : cls);
}
else if (auto tbl = get<TableTypeVar>(ty))
fillProps(tbl->props);
Expand Down
44 changes: 32 additions & 12 deletions Analysis/src/Clone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ LUAU_FASTFLAG(DebugLuauCopyBeforeNormalizing)

LUAU_FASTINTVARIABLE(LuauTypeCloneRecursionLimit, 300)
LUAU_FASTFLAG(LuauTypecheckOptPass)
LUAU_FASTFLAGVARIABLE(LuauLosslessClone, false)

namespace Luau
{
Expand Down Expand Up @@ -87,11 +88,18 @@ struct TypePackCloner

void operator()(const Unifiable::Free& t)
{
cloneState.encounteredFreeType = true;

TypePackId err = getSingletonTypes().errorRecoveryTypePack(getSingletonTypes().anyTypePack);
TypePackId cloned = dest.addTypePack(*err);
seenTypePacks[typePackId] = cloned;
if (FFlag::LuauLosslessClone)
{
defaultClone(t);
}
else
{
cloneState.encounteredFreeType = true;

TypePackId err = getSingletonTypes().errorRecoveryTypePack(getSingletonTypes().anyTypePack);
TypePackId cloned = dest.addTypePack(*err);
seenTypePacks[typePackId] = cloned;
}
}

void operator()(const Unifiable::Generic& t)
Expand Down Expand Up @@ -143,10 +151,18 @@ void TypeCloner::defaultClone(const T& t)

void TypeCloner::operator()(const Unifiable::Free& t)
{
cloneState.encounteredFreeType = true;
TypeId err = getSingletonTypes().errorRecoveryType(getSingletonTypes().anyType);
TypeId cloned = dest.addType(*err);
seenTypes[typeId] = cloned;
if (FFlag::LuauLosslessClone)
{
defaultClone(t);
}
else
{
cloneState.encounteredFreeType = true;

TypeId err = getSingletonTypes().errorRecoveryType(getSingletonTypes().anyType);
TypeId cloned = dest.addType(*err);
seenTypes[typeId] = cloned;
}
}

void TypeCloner::operator()(const Unifiable::Generic& t)
Expand Down Expand Up @@ -174,7 +190,8 @@ void TypeCloner::operator()(const PrimitiveTypeVar& t)

void TypeCloner::operator()(const ConstrainedTypeVar& t)
{
cloneState.encounteredFreeType = true;
if (!FFlag::LuauLosslessClone)
cloneState.encounteredFreeType = true;

TypeId res = dest.addType(ConstrainedTypeVar{t.level});
ConstrainedTypeVar* ctv = getMutable<ConstrainedTypeVar>(res);
Expand Down Expand Up @@ -252,7 +269,7 @@ void TypeCloner::operator()(const TableTypeVar& t)
for (TypePackId& arg : ttv->instantiatedTypePackParams)
arg = clone(arg, dest, cloneState);

if (ttv->state == TableState::Free)
if (!FFlag::LuauLosslessClone && ttv->state == TableState::Free)
{
cloneState.encounteredFreeType = true;

Expand All @@ -276,7 +293,7 @@ void TypeCloner::operator()(const MetatableTypeVar& t)

void TypeCloner::operator()(const ClassTypeVar& t)
{
TypeId result = dest.addType(ClassTypeVar{t.name, {}, std::nullopt, std::nullopt, t.tags, t.userData});
TypeId result = dest.addType(ClassTypeVar{t.name, {}, std::nullopt, std::nullopt, t.tags, t.userData, t.definitionModuleName});
ClassTypeVar* ctv = getMutable<ClassTypeVar>(result);

seenTypes[typeId] = result;
Expand Down Expand Up @@ -361,7 +378,10 @@ TypeId clone(TypeId typeId, TypeArena& dest, CloneState& cloneState)

// Persistent types are not being cloned and we get the original type back which might be read-only
if (!res->persistent)
{
asMutable(res)->documentationSymbol = typeId->documentationSymbol;
asMutable(res)->normal = typeId->normal;
}
}

return res;
Expand Down
23 changes: 7 additions & 16 deletions Analysis/src/Error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

#include <stdexcept>

LUAU_FASTFLAGVARIABLE(LuauTypeMismatchModuleName, false);

static std::string wrongNumberOfArgsString(size_t expectedCount, size_t actualCount, const char* argPrefix = nullptr, bool isVariadic = false)
{
std::string s = "expects ";
Expand Down Expand Up @@ -59,27 +57,20 @@ struct ErrorConverter

std::string result;

if (FFlag::LuauTypeMismatchModuleName)
if (givenTypeName == wantedTypeName)
{
if (givenTypeName == wantedTypeName)
if (auto givenDefinitionModule = getDefinitionModuleName(tm.givenType))
{
if (auto givenDefinitionModule = getDefinitionModuleName(tm.givenType))
if (auto wantedDefinitionModule = getDefinitionModuleName(tm.wantedType))
{
if (auto wantedDefinitionModule = getDefinitionModuleName(tm.wantedType))
{
result = "Type '" + givenTypeName + "' from '" + *givenDefinitionModule + "' could not be converted into '" + wantedTypeName +
"' from '" + *wantedDefinitionModule + "'";
}
result = "Type '" + givenTypeName + "' from '" + *givenDefinitionModule + "' could not be converted into '" + wantedTypeName +
"' from '" + *wantedDefinitionModule + "'";
}
}

if (result.empty())
result = "Type '" + givenTypeName + "' could not be converted into '" + wantedTypeName + "'";
}
else
{

if (result.empty())
result = "Type '" + givenTypeName + "' could not be converted into '" + wantedTypeName + "'";
}

if (tm.error)
{
Expand Down
50 changes: 33 additions & 17 deletions Analysis/src/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ LUAU_FASTFLAG(LuauInferInNoCheckMode)
LUAU_FASTFLAGVARIABLE(LuauKnowsTheDataModel3, false)
LUAU_FASTFLAGVARIABLE(LuauSeparateTypechecks, false)
LUAU_FASTFLAGVARIABLE(LuauAutocompleteDynamicLimits, false)
LUAU_FASTFLAGVARIABLE(LuauDirtySourceModule, false)
LUAU_FASTINTVARIABLE(LuauAutocompleteCheckTimeoutMs, 0)

namespace Luau
Expand Down Expand Up @@ -358,7 +359,7 @@ CheckResult Frontend::check(const ModuleName& name, std::optional<FrontendOption
CheckResult checkResult;

auto it = sourceNodes.find(name);
if (it != sourceNodes.end() && !it->second.isDirty(frontendOptions.forAutocomplete))
if (it != sourceNodes.end() && !it->second.hasDirtyModule(frontendOptions.forAutocomplete))
{
// No recheck required.
if (FFlag::LuauSeparateTypechecks)
Expand Down Expand Up @@ -402,7 +403,7 @@ CheckResult Frontend::check(const ModuleName& name, std::optional<FrontendOption
LUAU_ASSERT(sourceNodes.count(moduleName));
SourceNode& sourceNode = sourceNodes[moduleName];

if (!sourceNode.isDirty(frontendOptions.forAutocomplete))
if (!sourceNode.hasDirtyModule(frontendOptions.forAutocomplete))
continue;

LUAU_ASSERT(sourceModules.count(moduleName));
Expand Down Expand Up @@ -478,7 +479,7 @@ CheckResult Frontend::check(const ModuleName& name, std::optional<FrontendOption
stats.timeCheck += duration;
stats.filesStrict += 1;

sourceNode.dirtyAutocomplete = false;
sourceNode.dirtyModuleForAutocomplete = false;
continue;
}

Expand Down Expand Up @@ -541,7 +542,7 @@ CheckResult Frontend::check(const ModuleName& name, std::optional<FrontendOption
checkResult.errors.insert(checkResult.errors.end(), module->errors.begin(), module->errors.end());

moduleResolver.modules[moduleName] = std::move(module);
sourceNode.dirty = false;
sourceNode.dirtyModule = false;
}

return checkResult;
Expand Down Expand Up @@ -618,7 +619,7 @@ bool Frontend::parseGraph(std::vector<ModuleName>& buildQueue, CheckResult& chec
// this relies on the fact that markDirty marks reverse-dependencies dirty as well
// thus if a node is not dirty, all its transitive deps aren't dirty, which means that they won't ever need
// to be built, *and* can't form a cycle with any nodes we did process.
if (!it->second.isDirty(forAutocomplete))
if (!it->second.hasDirtyModule(forAutocomplete))
continue;

// note: this check is technically redundant *except* that getSourceNode has somewhat broken memoization
Expand Down Expand Up @@ -768,7 +769,7 @@ LintResult Frontend::lint(const SourceModule& module, std::optional<Luau::LintOp
bool Frontend::isDirty(const ModuleName& name, bool forAutocomplete) const
{
auto it = sourceNodes.find(name);
return it == sourceNodes.end() || it->second.isDirty(forAutocomplete);
return it == sourceNodes.end() || it->second.hasDirtyModule(forAutocomplete);
}

/*
Expand Down Expand Up @@ -810,20 +811,31 @@ void Frontend::markDirty(const ModuleName& name, std::vector<ModuleName>* marked
if (markedDirty)
markedDirty->push_back(next);

if (FFlag::LuauSeparateTypechecks)
if (FFlag::LuauDirtySourceModule)
{
if (sourceNode.dirty && sourceNode.dirtyAutocomplete)
LUAU_ASSERT(FFlag::LuauSeparateTypechecks);

if (sourceNode.dirtySourceModule && sourceNode.dirtyModule && sourceNode.dirtyModuleForAutocomplete)
continue;

sourceNode.dirty = true;
sourceNode.dirtyAutocomplete = true;
sourceNode.dirtySourceModule = true;
sourceNode.dirtyModule = true;
sourceNode.dirtyModuleForAutocomplete = true;
}
else if (FFlag::LuauSeparateTypechecks)
{
if (sourceNode.dirtyModule && sourceNode.dirtyModuleForAutocomplete)
continue;

sourceNode.dirtyModule = true;
sourceNode.dirtyModuleForAutocomplete = true;
}
else
{
if (sourceNode.dirty)
if (sourceNode.dirtyModule)
continue;

sourceNode.dirty = true;
sourceNode.dirtyModule = true;
}

if (0 == reverseDeps.count(name))
Expand Down Expand Up @@ -851,13 +863,14 @@ const SourceModule* Frontend::getSourceModule(const ModuleName& moduleName) cons
}

// Read AST into sourceModules if necessary. Trace require()s. Report parse errors.
std::pair<SourceNode*, SourceModule*> Frontend::getSourceNode(CheckResult& checkResult, const ModuleName& name, bool forAutocomplete)
std::pair<SourceNode*, SourceModule*> Frontend::getSourceNode(CheckResult& checkResult, const ModuleName& name, bool forAutocomplete_DEPRECATED)
{
LUAU_TIMETRACE_SCOPE("Frontend::getSourceNode", "Frontend");
LUAU_TIMETRACE_ARGUMENT("name", name.c_str());

auto it = sourceNodes.find(name);
if (it != sourceNodes.end() && !it->second.isDirty(forAutocomplete))
if (it != sourceNodes.end() &&
(FFlag::LuauDirtySourceModule ? !it->second.hasDirtySourceModule() : !it->second.hasDirtyModule(forAutocomplete_DEPRECATED)))
{
auto moduleIt = sourceModules.find(name);
if (moduleIt != sourceModules.end())
Expand Down Expand Up @@ -901,17 +914,20 @@ std::pair<SourceNode*, SourceModule*> Frontend::getSourceNode(CheckResult& check
sourceNode.requires.clear();
sourceNode.requireLocations.clear();

if (FFlag::LuauDirtySourceModule)
sourceNode.dirtySourceModule = false;

if (FFlag::LuauSeparateTypechecks)
{
if (it == sourceNodes.end())
{
sourceNode.dirty = true;
sourceNode.dirtyAutocomplete = true;
sourceNode.dirtyModule = true;
sourceNode.dirtyModuleForAutocomplete = true;
}
}
else
{
sourceNode.dirty = true;
sourceNode.dirtyModule = true;
}

for (const auto& [moduleName, location] : requireTrace.requires)
Expand Down
Loading

0 comments on commit e0a6461

Please sign in to comment.