Skip to content

Commit

Permalink
Sync to upstream/release/558 (#796)
Browse files Browse the repository at this point in the history
* Fixed garbage data in module scopes when type graph is not retained
* LOP_MOVE with the same source and target registers is no longer
generated (Fixes #793)
  • Loading branch information
vegorov-rbx authored Jan 6, 2023
1 parent 685ca02 commit be52bd9
Show file tree
Hide file tree
Showing 45 changed files with 2,679 additions and 378 deletions.
6 changes: 3 additions & 3 deletions Analysis/include/Luau/Constraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ struct BinaryConstraint

// When we dispatch this constraint, we update the key at this map to record
// the overload that we selected.
AstExpr* expr;
DenseHashMap<const AstExpr*, TypeId>* astOriginalCallTypes;
DenseHashMap<const AstExpr*, TypeId>* astOverloadResolvedTypes;
const void* astFragment;
DenseHashMap<const void*, TypeId>* astOriginalCallTypes;
DenseHashMap<const void*, TypeId>* astOverloadResolvedTypes;
};

// iteratee is iterable
Expand Down
4 changes: 2 additions & 2 deletions Analysis/include/Luau/ConstraintGraphBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@ struct ConstraintGraphBuilder

// If the node was applied as a function, this is the unspecialized type of
// that expression.
DenseHashMap<const AstExpr*, TypeId> astOriginalCallTypes{nullptr};
DenseHashMap<const void*, TypeId> astOriginalCallTypes{nullptr};

// If overload resolution was performed on this element, this is the
// overload that was selected.
DenseHashMap<const AstExpr*, TypeId> astOverloadResolvedTypes{nullptr};
DenseHashMap<const void*, TypeId> astOverloadResolvedTypes{nullptr};

// Types resolved from type annotations. Analogous to astTypes.
DenseHashMap<const AstType*, TypeId> astResolvedTypes{nullptr};
Expand Down
15 changes: 13 additions & 2 deletions Analysis/include/Luau/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,30 @@ struct Module
DenseHashMap<const AstExpr*, TypeId> astTypes{nullptr};
DenseHashMap<const AstExpr*, TypePackId> astTypePacks{nullptr};
DenseHashMap<const AstExpr*, TypeId> astExpectedTypes{nullptr};
DenseHashMap<const AstExpr*, TypeId> astOriginalCallTypes{nullptr};
DenseHashMap<const AstExpr*, TypeId> astOverloadResolvedTypes{nullptr};

// Pointers are either AstExpr or AstStat.
DenseHashMap<const void*, TypeId> astOriginalCallTypes{nullptr};

// Pointers are either AstExpr or AstStat.
DenseHashMap<const void*, TypeId> astOverloadResolvedTypes{nullptr};

DenseHashMap<const AstType*, TypeId> astResolvedTypes{nullptr};
DenseHashMap<const AstTypePack*, TypePackId> astResolvedTypePacks{nullptr};
// Map AST nodes to the scope they create. Cannot be NotNull<Scope> because we need a sentinel value for the map.
DenseHashMap<const AstNode*, Scope*> astScopes{nullptr};

std::unique_ptr<struct TypeReduction> reduction;

std::unordered_map<Name, TypeId> declaredGlobals;
ErrorVec errors;
Mode mode;
SourceCode::Type type;
bool timeout = false;

TypePackId returnType = nullptr;
std::unordered_map<Name, TypeFun> exportedTypeBindings;

bool hasModuleScope() const;
ScopePtr getModuleScope() const;

// Once a module has been typechecked, we clone its public interface into a separate arena.
Expand Down
2 changes: 1 addition & 1 deletion Analysis/include/Luau/RecursionCounter.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ struct RecursionCounter
--(*count);
}

private:
protected:
int* count;
};

Expand Down
16 changes: 8 additions & 8 deletions Analysis/include/Luau/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -494,13 +494,13 @@ struct AnyType
{
};

// T | U
// `T | U`
struct UnionType
{
std::vector<TypeId> options;
};

// T & U
// `T & U`
struct IntersectionType
{
std::vector<TypeId> parts;
Expand All @@ -519,9 +519,7 @@ struct NeverType
{
};

// ~T
// TODO: Some simplification step that overwrites the type graph to make sure negation
// types disappear from the user's view, and (?) a debug flag to disable that
// `~T`
struct NegationType
{
TypeId ty;
Expand Down Expand Up @@ -676,6 +674,8 @@ TypeLevel* getMutableLevel(TypeId ty);
std::optional<TypeLevel> getLevel(TypePackId tp);

const Property* lookupClassProp(const ClassType* cls, const Name& name);

// Whether `cls` is a subclass of `parent`
bool isSubclass(const ClassType* cls, const ClassType* parent);

Type* asMutable(TypeId ty);
Expand Down Expand Up @@ -767,7 +767,7 @@ struct TypeIterator
return !(*this == rhs);
}

const TypeId& operator*()
TypeId operator*()
{
descend();

Expand All @@ -779,8 +779,8 @@ struct TypeIterator
const std::vector<TypeId>& types = getTypes(t);
LUAU_ASSERT(currentIndex < types.size());

const TypeId& ty = types[currentIndex];
LUAU_ASSERT(!get<T>(follow(ty)));
TypeId ty = follow(types[currentIndex]);
LUAU_ASSERT(!get<T>(ty));

return ty;
}
Expand Down
40 changes: 40 additions & 0 deletions Analysis/include/Luau/TypeReduction.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once

#include "Luau/Type.h"
#include "Luau/TypeArena.h"
#include "Luau/TypePack.h"
#include "Luau/Variant.h"

namespace Luau
{

/// If it's desirable to allocate into a different arena than the TypeReduction instance you have, you will need
/// to create a temporary TypeReduction in that case. This is because TypeReduction caches the reduced type.
struct TypeReduction
{
explicit TypeReduction(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtinTypes, NotNull<InternalErrorReporter> handle);

std::optional<TypeId> reduce(TypeId ty);
std::optional<TypePackId> reduce(TypePackId tp);
std::optional<TypeFun> reduce(const TypeFun& fun);

private:
NotNull<TypeArena> arena;
NotNull<BuiltinTypes> builtinTypes;
NotNull<struct InternalErrorReporter> handle;

DenseHashMap<TypeId, TypeId> cachedTypes{nullptr};
DenseHashMap<TypePackId, TypePackId> cachedTypePacks{nullptr};

std::optional<TypeId> reduceImpl(TypeId ty);
std::optional<TypePackId> reduceImpl(TypePackId tp);

// Computes an *estimated length* of the cartesian product of the given type.
size_t cartesianProductSize(TypeId ty) const;

bool hasExceededCartesianProductLimit(TypeId ty) const;
bool hasExceededCartesianProductLimit(TypePackId tp) const;
};

} // namespace Luau
4 changes: 2 additions & 2 deletions Analysis/src/AstQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,8 @@ AstExpr* findExprAtPosition(const SourceModule& source, Position pos)

ScopePtr findScopeAtPosition(const Module& module, Position pos)
{
LUAU_ASSERT(!module.scopes.empty());
if (module.scopes.empty())
return nullptr;

Location scopeLocation = module.scopes.front().first;
ScopePtr scope = module.scopes.front().second;
Expand Down Expand Up @@ -320,7 +321,6 @@ std::optional<Binding> findBindingAtPosition(const Module& module, const SourceM
return std::nullopt;

ScopePtr currentScope = findScopeAtPosition(module, pos);
LUAU_ASSERT(currentScope);

while (currentScope)
{
Expand Down
36 changes: 17 additions & 19 deletions Analysis/src/Autocomplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ static TypeCorrectKind checkTypeCorrectKind(
{
ty = follow(ty);

LUAU_ASSERT(module.hasModuleScope());

NotNull<Scope> moduleScope{module.getModuleScope().get()};

auto typeAtPosition = findExpectedTypeAt(module, node, position);
Expand Down Expand Up @@ -182,8 +184,7 @@ static TypeCorrectKind checkTypeCorrectKind(
}
}

return checkTypeMatch(ty, expectedType, NotNull{module.getModuleScope().get()}, typeArena, builtinTypes) ? TypeCorrectKind::Correct
: TypeCorrectKind::None;
return checkTypeMatch(ty, expectedType, moduleScope, typeArena, builtinTypes) ? TypeCorrectKind::Correct : TypeCorrectKind::None;
}

enum class PropIndexType
Expand Down Expand Up @@ -1328,13 +1329,11 @@ static std::optional<AutocompleteEntryMap> autocompleteStringParams(const Source
}

static AutocompleteResult autocomplete(const SourceModule& sourceModule, const ModulePtr& module, NotNull<BuiltinTypes> builtinTypes,
Scope* globalScope, Position position, StringCompletionCallback callback)
TypeArena* typeArena, Scope* globalScope, Position position, StringCompletionCallback callback)
{
if (isWithinComment(sourceModule, position))
return {};

TypeArena typeArena;

std::vector<AstNode*> ancestry = findAncestryAtPositionForAutocomplete(sourceModule, position);
LUAU_ASSERT(!ancestry.empty());
AstNode* node = ancestry.back();
Expand All @@ -1360,7 +1359,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
TypeId ty = follow(*it);
PropIndexType indexType = indexName->op == ':' ? PropIndexType::Colon : PropIndexType::Point;

return {autocompleteProps(*module, &typeArena, builtinTypes, ty, indexType, ancestry), ancestry, AutocompleteContext::Property};
return {autocompleteProps(*module, typeArena, builtinTypes, ty, indexType, ancestry), ancestry, AutocompleteContext::Property};
}
else if (auto typeReference = node->as<AstTypeReference>())
{
Expand All @@ -1378,7 +1377,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
if (statLocal->vars.size == 1 && (!statLocal->equalsSignLocation || position < statLocal->equalsSignLocation->begin))
return {{{"function", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Unknown};
else if (statLocal->equalsSignLocation && position >= statLocal->equalsSignLocation->end)
return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
return autocompleteExpression(sourceModule, *module, builtinTypes, typeArena, ancestry, position);
else
return {};
}
Expand All @@ -1392,7 +1391,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M

if (statFor->from->location.containsClosed(position) || statFor->to->location.containsClosed(position) ||
(statFor->step && statFor->step->location.containsClosed(position)))
return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
return autocompleteExpression(sourceModule, *module, builtinTypes, typeArena, ancestry, position);

return {};
}
Expand Down Expand Up @@ -1422,7 +1421,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
AstExpr* lastExpr = statForIn->values.data[statForIn->values.size - 1];

if (lastExpr->location.containsClosed(position))
return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
return autocompleteExpression(sourceModule, *module, builtinTypes, typeArena, ancestry, position);

if (position > lastExpr->location.end)
return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
Expand All @@ -1446,7 +1445,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};

if (!statWhile->hasDo || position < statWhile->doLocation.begin)
return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
return autocompleteExpression(sourceModule, *module, builtinTypes, typeArena, ancestry, position);

if (statWhile->hasDo && position > statWhile->doLocation.end)
return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement};
Expand All @@ -1463,15 +1462,15 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
else if (AstStatIf* statIf = parent->as<AstStatIf>(); statIf && node->is<AstStatBlock>())
{
if (statIf->condition->is<AstExprError>())
return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
return autocompleteExpression(sourceModule, *module, builtinTypes, typeArena, ancestry, position);
else if (!statIf->thenLocation || statIf->thenLocation->containsClosed(position))
return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
}
else if (AstStatIf* statIf = extractStat<AstStatIf>(ancestry);
statIf && (!statIf->thenLocation || statIf->thenLocation->containsClosed(position)))
return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
else if (AstStatRepeat* statRepeat = node->as<AstStatRepeat>(); statRepeat && statRepeat->condition->is<AstExprError>())
return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
return autocompleteExpression(sourceModule, *module, builtinTypes, typeArena, ancestry, position);
else if (AstStatRepeat* statRepeat = extractStat<AstStatRepeat>(ancestry); statRepeat)
return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement};
else if (AstExprTable* exprTable = parent->as<AstExprTable>();
Expand All @@ -1484,7 +1483,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
{
if (auto it = module->astExpectedTypes.find(exprTable))
{
auto result = autocompleteProps(*module, &typeArena, builtinTypes, *it, PropIndexType::Key, ancestry);
auto result = autocompleteProps(*module, typeArena, builtinTypes, *it, PropIndexType::Key, ancestry);

if (FFlag::LuauCompleteTableKeysBetter)
{
Expand Down Expand Up @@ -1518,7 +1517,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M

// If we know for sure that a key is being written, do not offer general expression suggestions
if (!key)
autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position, result);
autocompleteExpression(sourceModule, *module, builtinTypes, typeArena, ancestry, position, result);

return {result, ancestry, AutocompleteContext::Property};
}
Expand Down Expand Up @@ -1546,7 +1545,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
if (auto idxExpr = ancestry.at(ancestry.size() - 2)->as<AstExprIndexExpr>())
{
if (auto it = module->astTypes.find(idxExpr->expr))
autocompleteProps(*module, &typeArena, builtinTypes, follow(*it), PropIndexType::Point, ancestry, result);
autocompleteProps(*module, typeArena, builtinTypes, follow(*it), PropIndexType::Point, ancestry, result);
}
else if (auto binExpr = ancestry.at(ancestry.size() - 2)->as<AstExprBinary>())
{
Expand All @@ -1572,7 +1571,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
return {};

if (node->asExpr())
return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
return autocompleteExpression(sourceModule, *module, builtinTypes, typeArena, ancestry, position);
else if (node->asStat())
return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement};

Expand All @@ -1599,9 +1598,8 @@ AutocompleteResult autocomplete(Frontend& frontend, const ModuleName& moduleName
NotNull<BuiltinTypes> builtinTypes = frontend.builtinTypes;
Scope* globalScope = frontend.typeCheckerForAutocomplete.globalScope.get();

AutocompleteResult autocompleteResult = autocomplete(*sourceModule, module, builtinTypes, globalScope, position, callback);

return autocompleteResult;
TypeArena typeArena;
return autocomplete(*sourceModule, module, builtinTypes, &typeArena, globalScope, position, callback);
}

} // namespace Luau
Loading

0 comments on commit be52bd9

Please sign in to comment.