Skip to content

Commit

Permalink
Sync to upstream/release/592 (luau-lang#1018)
Browse files Browse the repository at this point in the history
* AST queries at position where function name is will now return
AstExprLocal
* Lexer performance has been slightly improved
* Fixed incorrect string singleton autocomplete suggestions (fixes luau-lang#858)
* Improved parsing error messages
* Fixed crash on null pointer access in unification (fixes luau-lang#1017)
* Native code support is enabled by default and `native=1`
(make)/`LUAU_NATIVE` (CMake)/`-DLUA_CUSTOM_EXECUTION` configuration is
no longer required

New typechecker:
* New subtyping check can now handle generic functions and tables
(including those that contain cycles)

Native code generation:
* Loops with non-numeric parameters are now handled by VM to streamline
native code
* Array size check can be optimized away in SETLIST
* On failure, CodeGen::compile returns a reason
* Fixed clobbering of non-volatile xmm registers on Windows
  • Loading branch information
vegorov-rbx authored Aug 25, 2023
1 parent c3fc0d7 commit ce9414c
Show file tree
Hide file tree
Showing 59 changed files with 1,682 additions and 465 deletions.
79 changes: 60 additions & 19 deletions Analysis/include/Luau/Subtyping.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#pragma once

#include "Luau/Type.h"
#include "Luau/UnifierSharedState.h"

#include <vector>
#include <optional>
Expand All @@ -11,11 +12,12 @@ namespace Luau

template<typename A, typename B>
struct TryPair;
struct InternalErrorReporter;

class Normalizer;
struct NormalizedType;

struct SubtypingGraph
struct SubtypingResult
{
// Did the test succeed?
bool isSubtype = false;
Expand All @@ -25,39 +27,78 @@ struct SubtypingGraph
// If so, what constraints are implied by this relation?
// If not, what happened?

SubtypingGraph and_(const SubtypingGraph& other);
SubtypingGraph or_(const SubtypingGraph& other);
void andAlso(const SubtypingResult& other);
void orElse(const SubtypingResult& other);

static SubtypingGraph and_(const std::vector<SubtypingGraph>& results);
static SubtypingGraph or_(const std::vector<SubtypingGraph>& results);
static SubtypingResult all(const std::vector<SubtypingResult>& results);
static SubtypingResult any(const std::vector<SubtypingResult>& results);
};

struct Subtyping
{
NotNull<BuiltinTypes> builtinTypes;
NotNull<TypeArena> arena;
NotNull<Normalizer> normalizer;
NotNull<InternalErrorReporter> iceReporter;

enum class Variance
{
Covariant,
Contravariant
};

Variance variance = Variance::Covariant;

struct GenericBounds
{
DenseHashSet<TypeId> lowerBound{nullptr};
DenseHashSet<TypeId> upperBound{nullptr};
};

/*
* When we encounter a generic over the course of a subtyping test, we need
* to tentatively map that generic onto a type on the other side.
*/
DenseHashMap<TypeId, GenericBounds> mappedGenerics{nullptr};
DenseHashMap<TypePackId, TypePackId> mappedGenericPacks{nullptr};

using SeenSet = std::unordered_set<std::pair<TypeId, TypeId>, TypeIdPairHash>;

SeenSet seenTypes;

// TODO cache
// TODO cyclic types
// TODO recursion limits

SubtypingGraph isSubtype(TypeId subTy, TypeId superTy);
SubtypingGraph isSubtype(TypePackId subTy, TypePackId superTy);
SubtypingResult isSubtype(TypeId subTy, TypeId superTy);
SubtypingResult isSubtype(TypePackId subTy, TypePackId superTy);

private:
SubtypingResult isSubtype_(TypeId subTy, TypeId superTy);
SubtypingResult isSubtype_(TypePackId subTy, TypePackId superTy);

template<typename SubTy, typename SuperTy>
SubtypingGraph isSubtype(const TryPair<const SubTy*, const SuperTy*>& pair);

SubtypingGraph isSubtype(TypeId subTy, const UnionType* superUnion);
SubtypingGraph isSubtype(const UnionType* subUnion, TypeId superTy);
SubtypingGraph isSubtype(TypeId subTy, const IntersectionType* superIntersection);
SubtypingGraph isSubtype(const IntersectionType* subIntersection, TypeId superTy);
SubtypingGraph isSubtype(const PrimitiveType* subPrim, const PrimitiveType* superPrim);
SubtypingGraph isSubtype(const SingletonType* subSingleton, const PrimitiveType* superPrim);
SubtypingGraph isSubtype(const SingletonType* subSingleton, const SingletonType* superSingleton);
SubtypingGraph isSubtype(const FunctionType* subFunction, const FunctionType* superFunction);

SubtypingGraph isSubtype(const NormalizedType* subNorm, const NormalizedType* superNorm);
SubtypingResult isSubtype_(const TryPair<const SubTy*, const SuperTy*>& pair);

SubtypingResult isSubtype_(TypeId subTy, const UnionType* superUnion);
SubtypingResult isSubtype_(const UnionType* subUnion, TypeId superTy);
SubtypingResult isSubtype_(TypeId subTy, const IntersectionType* superIntersection);
SubtypingResult isSubtype_(const IntersectionType* subIntersection, TypeId superTy);
SubtypingResult isSubtype_(const PrimitiveType* subPrim, const PrimitiveType* superPrim);
SubtypingResult isSubtype_(const SingletonType* subSingleton, const PrimitiveType* superPrim);
SubtypingResult isSubtype_(const SingletonType* subSingleton, const SingletonType* superSingleton);
SubtypingResult isSubtype_(const TableType* subTable, const TableType* superTable);
SubtypingResult isSubtype_(const FunctionType* subFunction, const FunctionType* superFunction);
SubtypingResult isSubtype_(const NormalizedType* subNorm, const NormalizedType* superNorm);

bool bindGeneric(TypeId subTp, TypeId superTp);
bool bindGeneric(TypePackId subTp, TypePackId superTp);

template <typename T, typename Container>
TypeId makeAggregateType(const Container& container, TypeId orElse);

[[noreturn]]
void unexpected(TypePackId tp);
};

} // namespace Luau
2 changes: 1 addition & 1 deletion Analysis/include/Luau/TypeUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ struct TryPair {
A first;
B second;

operator bool() const
explicit operator bool() const
{
return bool(first) && bool(second);
}
Expand Down
35 changes: 35 additions & 0 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(DebugLuauReadWriteProperties)
LUAU_FASTFLAGVARIABLE(FixFindBindingAtFunctionName, false);

namespace Luau
{
Expand Down Expand Up @@ -148,6 +149,23 @@ struct FindNode : public AstVisitor
return false;
}

bool visit(AstStatFunction* node) override
{
if (FFlag::FixFindBindingAtFunctionName)
{
visit(static_cast<AstNode*>(node));
if (node->name->location.contains(pos))
node->name->visit(this);
else if (node->func->location.contains(pos))
node->func->visit(this);
return false;
}
else
{
return AstVisitor::visit(node);
}
}

bool visit(AstStatBlock* block) override
{
visit(static_cast<AstNode*>(block));
Expand Down Expand Up @@ -188,6 +206,23 @@ struct FindFullAncestry final : public AstVisitor
return false;
}

bool visit(AstStatFunction* node) override
{
if (FFlag::FixFindBindingAtFunctionName)
{
visit(static_cast<AstNode*>(node));
if (node->name->location.contains(pos))
node->name->visit(this);
else if (node->func->location.contains(pos))
node->func->visit(this);
return false;
}
else
{
return AstVisitor::visit(node);
}
}

bool visit(AstNode* node) override
{
if (node->location.contains(pos))
Expand Down
71 changes: 32 additions & 39 deletions Analysis/src/Autocomplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
LUAU_FASTFLAG(DebugLuauReadWriteProperties)
LUAU_FASTFLAGVARIABLE(LuauAnonymousAutofilled1, false);
LUAU_FASTFLAGVARIABLE(LuauAutocompleteLastTypecheck, false)
LUAU_FASTFLAGVARIABLE(LuauAutocompleteHideSelfArg, false)
LUAU_FASTFLAGVARIABLE(LuauAutocompleteStringLiteralBounds, 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 @@ -283,38 +283,20 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
ParenthesesRecommendation parens =
indexType == PropIndexType::Key ? ParenthesesRecommendation::None : getParenRecommendation(type, nodes, typeCorrect);

if (FFlag::LuauAutocompleteHideSelfArg)
{
result[name] = AutocompleteEntry{
AutocompleteEntryKind::Property,
type,
prop.deprecated,
isWrongIndexer(type),
typeCorrect,
containingClass,
&prop,
prop.documentationSymbol,
{},
parens,
{},
indexType == PropIndexType::Colon
};
}
else
{
result[name] = AutocompleteEntry{
AutocompleteEntryKind::Property,
type,
prop.deprecated,
isWrongIndexer(type),
typeCorrect,
containingClass,
&prop,
prop.documentationSymbol,
{},
parens
};
}
result[name] = AutocompleteEntry{
AutocompleteEntryKind::Property,
type,
prop.deprecated,
isWrongIndexer(type),
typeCorrect,
containingClass,
&prop,
prop.documentationSymbol,
{},
parens,
{},
indexType == PropIndexType::Colon
};
}
}
};
Expand Down Expand Up @@ -484,8 +466,19 @@ AutocompleteEntryMap autocompleteModuleTypes(const Module& module, Position posi
return result;
}

static void autocompleteStringSingleton(TypeId ty, bool addQuotes, AutocompleteEntryMap& result)
static void autocompleteStringSingleton(TypeId ty, bool addQuotes, AstNode* node, Position position, AutocompleteEntryMap& result)
{
if (FFlag::LuauAutocompleteStringLiteralBounds)
{
if (position == node->location.begin || position == node->location.end)
{
if (auto str = node->as<AstExprConstantString>(); str && str->quoteStyle == AstExprConstantString::Quoted)
return;
else if (node->is<AstExprInterpString>())
return;
}
}

auto formatKey = [addQuotes](const std::string& key) {
if (addQuotes)
return "\"" + escape(key) + "\"";
Expand Down Expand Up @@ -1238,7 +1231,7 @@ static AutocompleteContext autocompleteExpression(const SourceModule& sourceModu
result["function"] = {AutocompleteEntryKind::Keyword, std::nullopt, false, false, correctForFunction};

if (auto ty = findExpectedTypeAt(module, node, position))
autocompleteStringSingleton(*ty, true, result);
autocompleteStringSingleton(*ty, true, node, position, result);
}

return AutocompleteContext::Expression;
Expand Down Expand Up @@ -1719,7 +1712,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
auto result = autocompleteProps(*module, typeArena, builtinTypes, *it, PropIndexType::Key, ancestry);

if (auto nodeIt = module->astExpectedTypes.find(node->asExpr()))
autocompleteStringSingleton(*nodeIt, !node->is<AstExprConstantString>(), result);
autocompleteStringSingleton(*nodeIt, !node->is<AstExprConstantString>(), node, position, result);

if (!key)
{
Expand All @@ -1731,7 +1724,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
// suggest those too.
if (auto ttv = get<TableType>(follow(*it)); ttv && ttv->indexer)
{
autocompleteStringSingleton(ttv->indexer->indexType, false, result);
autocompleteStringSingleton(ttv->indexer->indexType, false, node, position, result);
}
}

Expand Down Expand Up @@ -1768,7 +1761,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
AutocompleteEntryMap result;

if (auto it = module->astExpectedTypes.find(node->asExpr()))
autocompleteStringSingleton(*it, false, result);
autocompleteStringSingleton(*it, false, node, position, result);

if (ancestry.size() >= 2)
{
Expand All @@ -1782,7 +1775,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
if (binExpr->op == AstExprBinary::CompareEq || binExpr->op == AstExprBinary::CompareNe)
{
if (auto it = module->astTypes.find(node == binExpr->left ? binExpr->right : binExpr->left))
autocompleteStringSingleton(*it, false, result);
autocompleteStringSingleton(*it, false, node, position, result);
}
}
}
Expand Down
Loading

0 comments on commit ce9414c

Please sign in to comment.