Skip to content

Commit

Permalink
Sync to upstream/release/560 (#810)
Browse files Browse the repository at this point in the history
* For autocomplete, additional information is included in Scope for type
alias name locations and names of imported modules
* Improved autocomplete suggestions in 'for' and 'while' loop headers
* String match functions return types are now optional strings and
numbers because match is not guaranteed at runtime
* Fixed build issue on gcc 11 and up (Fixes
#806)
  • Loading branch information
vegorov-rbx authored Jan 20, 2023
1 parent 729bc44 commit 4a2e801
Show file tree
Hide file tree
Showing 68 changed files with 3,089 additions and 1,242 deletions.
2 changes: 1 addition & 1 deletion Analysis/include/Luau/AstQuery.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ struct ExprOrLocal
};

std::vector<AstNode*> findAncestryAtPositionForAutocomplete(const SourceModule& source, Position pos);
std::vector<AstNode*> findAstAncestryOfPosition(const SourceModule& source, Position pos);
std::vector<AstNode*> findAstAncestryOfPosition(const SourceModule& source, Position pos, bool includeTypes = false);
AstNode* findNodeAtPosition(const SourceModule& source, Position pos);
AstExpr* findExprAtPosition(const SourceModule& source, Position pos);
ScopePtr findScopeAtPosition(const Module& module, Position pos);
Expand Down
16 changes: 12 additions & 4 deletions Analysis/include/Luau/ConstraintGraphBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,20 +240,28 @@ struct ConstraintGraphBuilder
* Resolves a type from its AST annotation.
* @param scope the scope that the type annotation appears within.
* @param ty the AST annotation to resolve.
* @param topLevel whether the annotation is a "top-level" annotation.
* @param inTypeArguments whether we are resolving a type that's contained within type arguments, `<...>`.
* @return the type of the AST annotation.
**/
TypeId resolveType(const ScopePtr& scope, AstType* ty, bool topLevel = false);
TypeId resolveType(const ScopePtr& scope, AstType* ty, bool inTypeArguments);

/**
* Resolves a type pack from its AST annotation.
* @param scope the scope that the type annotation appears within.
* @param tp the AST annotation to resolve.
* @param inTypeArguments whether we are resolving a type that's contained within type arguments, `<...>`.
* @return the type pack of the AST annotation.
**/
TypePackId resolveTypePack(const ScopePtr& scope, AstTypePack* tp);
TypePackId resolveTypePack(const ScopePtr& scope, AstTypePack* tp, bool inTypeArguments);

TypePackId resolveTypePack(const ScopePtr& scope, const AstTypeList& list);
/**
* Resolves a type pack from its AST annotation.
* @param scope the scope that the type annotation appears within.
* @param list the AST annotation to resolve.
* @param inTypeArguments whether we are resolving a type that's contained within type arguments, `<...>`.
* @return the type pack of the AST annotation.
**/
TypePackId resolveTypePack(const ScopePtr& scope, const AstTypeList& list, bool inTypeArguments);

std::vector<std::pair<Name, GenericTypeDefinition>> createGenerics(const ScopePtr& scope, AstArray<AstGenericType> generics);
std::vector<std::pair<Name, GenericTypePackDefinition>> createGenericPacks(const ScopePtr& scope, AstArray<AstGenericTypePack> packs);
Expand Down
2 changes: 1 addition & 1 deletion Analysis/include/Luau/ConstraintSolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ struct ConstraintSolver
bool tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const PrimitiveTypeConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const HasPropConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const SetPropConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const SetPropConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const SingletonOrTopTypeConstraint& c, NotNull<const Constraint> constraint);

// for a, ... in some_table do
Expand Down
2 changes: 2 additions & 0 deletions Analysis/include/Luau/Scope.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ struct Scope
std::unordered_map<Name, TypeFun> exportedTypeBindings;
std::unordered_map<Name, TypeFun> privateTypeBindings;
std::unordered_map<Name, Location> typeAliasLocations;
std::unordered_map<Name, Location> typeAliasNameLocations;
std::unordered_map<Name, ModuleName> importedModules; // Mapping from the name in the require statement to the internal moduleName.
std::unordered_map<Name, std::unordered_map<Name, TypeFun>> importedTypeBindings;

DenseHashSet<Name> builtinTypeNames{""};
Expand Down
2 changes: 2 additions & 0 deletions Analysis/include/Luau/ToString.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ std::optional<std::string> getFunctionNameAsString(const AstExpr& expr);
// It could be useful to see the text representation of a type during a debugging session instead of exploring the content of the class
// These functions will dump the type to stdout and can be evaluated in Watch/Immediate windows or as gdb/lldb expression
std::string dump(TypeId ty);
std::string dump(const std::optional<TypeId>& ty);
std::string dump(TypePackId ty);
std::string dump(const std::optional<TypePackId>& ty);
std::string dump(const Constraint& c);

std::string dump(const std::shared_ptr<Scope>& scope, const char* name);
Expand Down
7 changes: 5 additions & 2 deletions Analysis/include/Luau/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -657,8 +657,11 @@ struct BuiltinTypes
const TypeId unknownType;
const TypeId neverType;
const TypeId errorType;
const TypeId falsyType; // No type binding!
const TypeId truthyType; // No type binding!
const TypeId falsyType;
const TypeId truthyType;

const TypeId optionalNumberType;
const TypeId optionalStringType;

const TypePackId anyTypePack;
const TypePackId neverTypePack;
Expand Down
31 changes: 23 additions & 8 deletions Analysis/include/Luau/TypeReduction.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,28 @@
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.
namespace detail
{
template<typename T>
struct ReductionContext
{
T type = nullptr;
bool irreducible = false;
};
} // namespace detail

struct TypeReductionOptions
{
/// If it's desirable for type reduction to allocate into a different arena than the TypeReduction instance you have, you will need
/// to create a temporary TypeReduction in that case, and set [`TypeReductionOptions::allowTypeReductionsFromOtherArenas`] to true.
/// This is because TypeReduction caches the reduced type.
bool allowTypeReductionsFromOtherArenas = false;
};

struct TypeReduction
{
explicit TypeReduction(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtinTypes, NotNull<InternalErrorReporter> handle);
explicit TypeReduction(
NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtinTypes, NotNull<InternalErrorReporter> handle, const TypeReductionOptions& opts = {});

std::optional<TypeId> reduce(TypeId ty);
std::optional<TypePackId> reduce(TypePackId tp);
Expand All @@ -23,12 +40,10 @@ struct TypeReduction
NotNull<TypeArena> arena;
NotNull<BuiltinTypes> builtinTypes;
NotNull<struct InternalErrorReporter> handle;
TypeReductionOptions options;

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

std::pair<std::optional<TypeId>, bool> reduceImpl(TypeId ty);
std::pair<std::optional<TypePackId>, bool> reduceImpl(TypePackId tp);
DenseHashMap<TypeId, detail::ReductionContext<TypeId>> memoizedTypes{nullptr};
DenseHashMap<TypePackId, detail::ReductionContext<TypePackId>> memoizedTypePacks{nullptr};

// Computes an *estimated length* of the cartesian product of the given type.
size_t cartesianProductSize(TypeId ty) const;
Expand Down
5 changes: 4 additions & 1 deletion Analysis/include/Luau/VisitType.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,10 @@ struct GenericTypeVisitor
}
}
else if (auto ntv = get<NegationType>(ty))
visit(ty, *ntv);
{
if (visit(ty, *ntv))
traverse(ntv->ty);
}
else if (!FFlag::LuauCompleteVisitor)
return visit_detail::unsee(seen, ty);
else
Expand Down
26 changes: 22 additions & 4 deletions Analysis/src/AstQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <algorithm>

LUAU_FASTFLAG(LuauCompleteTableKeysBetter);
LUAU_FASTFLAGVARIABLE(SupportTypeAliasGoToDeclaration, false);

namespace Luau
{
Expand Down Expand Up @@ -183,14 +184,31 @@ struct FindFullAncestry final : public AstVisitor
std::vector<AstNode*> nodes;
Position pos;
Position documentEnd;
bool includeTypes = false;

explicit FindFullAncestry(Position pos, Position documentEnd)
explicit FindFullAncestry(Position pos, Position documentEnd, bool includeTypes = false)
: pos(pos)
, documentEnd(documentEnd)
, includeTypes(includeTypes)
{
}

bool visit(AstNode* node)
bool visit(AstType* type) override
{
if (FFlag::SupportTypeAliasGoToDeclaration)
{
if (includeTypes)
return visit(static_cast<AstNode*>(type));
else
return false;
}
else
{
return AstVisitor::visit(type);
}
}

bool visit(AstNode* node) override
{
if (node->location.contains(pos))
{
Expand Down Expand Up @@ -220,13 +238,13 @@ std::vector<AstNode*> findAncestryAtPositionForAutocomplete(const SourceModule&
return finder.ancestry;
}

std::vector<AstNode*> findAstAncestryOfPosition(const SourceModule& source, Position pos)
std::vector<AstNode*> findAstAncestryOfPosition(const SourceModule& source, Position pos, bool includeTypes)
{
const Position end = source.root->location.end;
if (pos > end)
pos = end;

FindFullAncestry finder(pos, end);
FindFullAncestry finder(pos, end, includeTypes);
source.root->visit(&finder);
return finder.nodes;
}
Expand Down
69 changes: 57 additions & 12 deletions Analysis/src/Autocomplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

LUAU_FASTFLAGVARIABLE(LuauCompleteTableKeysBetter, false);
LUAU_FASTFLAGVARIABLE(LuauFixAutocompleteInIf, false);
LUAU_FASTFLAGVARIABLE(LuauFixAutocompleteInWhile, false);
LUAU_FASTFLAGVARIABLE(LuauFixAutocompleteInFor, false);
LUAU_FASTFLAGVARIABLE(LuauAutocompleteStringContent, false);

static const std::unordered_set<std::string> kStatementStartingKeywords = {
"while", "if", "local", "repeat", "function", "do", "for", "return", "break", "continue", "type", "export"};
Expand Down Expand Up @@ -1265,6 +1268,9 @@ static bool isSimpleInterpolatedString(const AstNode* node)

static std::optional<std::string> getStringContents(const AstNode* node)
{
if (!FFlag::LuauAutocompleteStringContent)
return std::nullopt;

if (const AstExprConstantString* string = node->as<AstExprConstantString>())
{
return std::string(string->value.data, string->value.size);
Expand Down Expand Up @@ -1314,8 +1320,7 @@ static std::optional<AutocompleteEntryMap> autocompleteStringParams(const Source

std::optional<std::string> candidateString = getStringContents(nodes.back());

auto performCallback = [&](const FunctionType* funcType) -> std::optional<AutocompleteEntryMap>
{
auto performCallback = [&](const FunctionType* funcType) -> std::optional<AutocompleteEntryMap> {
for (const std::string& tag : funcType->tags)
{
if (std::optional<AutocompleteEntryMap> ret = callback(tag, getMethodContainingClass(module, candidate->func), candidateString))
Expand Down Expand Up @@ -1349,6 +1354,15 @@ static std::optional<AutocompleteEntryMap> autocompleteStringParams(const Source
return std::nullopt;
}

static AutocompleteResult autocompleteWhileLoopKeywords(std::vector<AstNode*> ancestry)
{
AutocompleteEntryMap ret;
ret["do"] = {AutocompleteEntryKind::Keyword};
ret["and"] = {AutocompleteEntryKind::Keyword};
ret["or"] = {AutocompleteEntryKind::Keyword};
return {std::move(ret), std::move(ancestry), AutocompleteContext::Keyword};
}

static AutocompleteResult autocomplete(const SourceModule& sourceModule, const ModulePtr& module, NotNull<BuiltinTypes> builtinTypes,
TypeArena* typeArena, Scope* globalScope, Position position, StringCompletionCallback callback)
{
Expand Down Expand Up @@ -1407,13 +1421,24 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
{
if (!statFor->hasDo || position < statFor->doLocation.begin)
{
if (!statFor->from->is<AstExprError>() && !statFor->to->is<AstExprError>() && (!statFor->step || !statFor->step->is<AstExprError>()))
return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
if (FFlag::LuauFixAutocompleteInFor)
{
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);

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);
if (!statFor->from->is<AstExprError>() && !statFor->to->is<AstExprError>() && (!statFor->step || !statFor->step->is<AstExprError>()))
return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
}
else
{
if (!statFor->from->is<AstExprError>() && !statFor->to->is<AstExprError>() && (!statFor->step || !statFor->step->is<AstExprError>()))
return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};

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 {};
}

Expand Down Expand Up @@ -1463,7 +1488,16 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
else if (AstStatWhile* statWhile = parent->as<AstStatWhile>(); node->is<AstStatBlock>() && statWhile)
{
if (!statWhile->hasDo && !statWhile->condition->is<AstStatError>() && position > statWhile->condition->location.end)
return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
{
if (FFlag::LuauFixAutocompleteInWhile)
{
return autocompleteWhileLoopKeywords(ancestry);
}
else
{
return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
}
}

if (!statWhile->hasDo || position < statWhile->doLocation.begin)
return autocompleteExpression(sourceModule, *module, builtinTypes, typeArena, ancestry, position);
Expand All @@ -1472,9 +1506,20 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement};
}

else if (AstStatWhile* statWhile = extractStat<AstStatWhile>(ancestry); statWhile && !statWhile->hasDo)
return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};

else if (AstStatWhile* statWhile = extractStat<AstStatWhile>(ancestry);
FFlag::LuauFixAutocompleteInWhile ? (statWhile && (!statWhile->hasDo || statWhile->doLocation.containsClosed(position)) &&
statWhile->condition && !statWhile->condition->location.containsClosed(position))
: (statWhile && !statWhile->hasDo))
{
if (FFlag::LuauFixAutocompleteInWhile)
{
return autocompleteWhileLoopKeywords(ancestry);
}
else
{
return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
}
}
else if (AstStatIf* statIf = node->as<AstStatIf>(); statIf && !statIf->elseLocation.has_value())
{
return {{{"else", AutocompleteEntry{AutocompleteEntryKind::Keyword}}, {"elseif", AutocompleteEntry{AutocompleteEntryKind::Keyword}}},
Expand All @@ -1488,7 +1533,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
}
else if (AstStatIf* statIf = extractStat<AstStatIf>(ancestry);
statIf && (!statIf->thenLocation || statIf->thenLocation->containsClosed(position)) &&
statIf && (!statIf->thenLocation || statIf->thenLocation->containsClosed(position)) &&
(!FFlag::LuauFixAutocompleteInIf || (statIf->condition && !statIf->condition->location.containsClosed(position))))
{
if (FFlag::LuauFixAutocompleteInIf)
Expand Down
5 changes: 2 additions & 3 deletions Analysis/src/BuiltinDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

#include <algorithm>

LUAU_FASTFLAGVARIABLE(LuauSetMetaTableArgsCheck, false)
LUAU_FASTFLAG(LuauUnknownAndNeverType)
LUAU_FASTFLAGVARIABLE(LuauBuiltInMetatableNoBadSynthetic, false)
LUAU_FASTFLAG(LuauReportShadowedTypeAlias)
Expand Down Expand Up @@ -583,15 +582,15 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionSetMetaTable(

TypeId mtTy = arena.addType(mtv);

if (FFlag::LuauSetMetaTableArgsCheck && expr.args.size < 1)
if (expr.args.size < 1)
{
if (FFlag::LuauUnknownAndNeverType)
return std::nullopt;
else
return WithPredicate<TypePackId>{};
}

if (!FFlag::LuauSetMetaTableArgsCheck || !expr.self)
if (!expr.self)
{
AstExpr* targetExpr = expr.args.data[0];
if (AstExprLocal* targetLocal = targetExpr->as<AstExprLocal>())
Expand Down
Loading

0 comments on commit 4a2e801

Please sign in to comment.