Skip to content

Commit

Permalink
Merge 42244b1 into dbcd5fb
Browse files Browse the repository at this point in the history
  • Loading branch information
zeux committed Jul 8, 2022
2 parents dbcd5fb + 42244b1 commit 8c151f5
Show file tree
Hide file tree
Showing 54 changed files with 1,858 additions and 584 deletions.
1 change: 1 addition & 0 deletions Analysis/include/Luau/AstQuery.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ struct ExprOrLocal
AstLocal* local = nullptr;
};

std::vector<AstNode*> findAncestryAtPositionForAutocomplete(const SourceModule& source, Position pos);
std::vector<AstNode*> findAstAncestryOfPosition(const SourceModule& source, Position pos);
AstNode* findNodeAtPosition(const SourceModule& source, Position pos);
AstExpr* findExprAtPosition(const SourceModule& source, Position pos);
Expand Down
24 changes: 17 additions & 7 deletions Analysis/include/Luau/TypeInfer.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ struct TypeChecker
const ScopePtr& scope, const AstExprBinary& expr, TypeId lhsType, TypeId rhsType, const PredicateVec& predicates = {});
TypeId checkBinaryOperation(
const ScopePtr& scope, const AstExprBinary& expr, TypeId lhsType, TypeId rhsType, const PredicateVec& predicates = {});
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprBinary& expr);
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprBinary& expr, std::optional<TypeId> expectedType = std::nullopt);
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprTypeAssertion& expr);
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprError& expr);
WithPredicate<TypeId> checkExpr(const ScopePtr& scope, const AstExprIfElse& expr, std::optional<TypeId> expectedType = std::nullopt);
Expand All @@ -180,8 +180,12 @@ struct TypeChecker
const ScopePtr& scope, Unifier& state, TypePackId paramPack, TypePackId argPack, const std::vector<Location>& argLocations);

WithPredicate<TypePackId> checkExprPack(const ScopePtr& scope, const AstExpr& expr);
WithPredicate<TypePackId> checkExprPack(const ScopePtr& scope, const AstExprCall& expr);

WithPredicate<TypePackId> checkExprPackHelper(const ScopePtr& scope, const AstExpr& expr);
WithPredicate<TypePackId> checkExprPackHelper(const ScopePtr& scope, const AstExprCall& expr);

std::vector<std::optional<TypeId>> getExpectedTypesForCall(const std::vector<TypeId>& overloads, size_t argumentCount, bool selfCall);

std::optional<WithPredicate<TypePackId>> checkCallOverload(const ScopePtr& scope, const AstExprCall& expr, TypeId fn, TypePackId retPack,
TypePackId argPack, TypePack* args, const std::vector<Location>* argLocations, const WithPredicate<TypePackId>& argListResult,
std::vector<TypeId>& overloadsThatMatchArgCount, std::vector<TypeId>& overloadsThatDont, std::vector<OverloadErrorEntry>& errors);
Expand Down Expand Up @@ -236,10 +240,11 @@ struct TypeChecker

void unifyLowerBound(TypePackId subTy, TypePackId superTy, TypeLevel demotedLevel, const Location& location);

std::optional<TypeId> findMetatableEntry(TypeId type, std::string entry, const Location& location);
std::optional<TypeId> findTablePropertyRespectingMeta(TypeId lhsType, Name name, const Location& location);
std::optional<TypeId> findMetatableEntry(TypeId type, std::string entry, const Location& location, bool addErrors);
std::optional<TypeId> findTablePropertyRespectingMeta(TypeId lhsType, Name name, const Location& location, bool addErrors);

std::optional<TypeId> getIndexTypeFromType(const ScopePtr& scope, TypeId type, const Name& name, const Location& location, bool addErrors);
std::optional<TypeId> getIndexTypeFromTypeImpl(const ScopePtr& scope, TypeId type, const Name& name, const Location& location, bool addErrors);

// Reduces the union to its simplest possible shape.
// (A | B) | B | C yields A | B | C
Expand Down Expand Up @@ -316,11 +321,12 @@ struct TypeChecker

TypeIdPredicate mkTruthyPredicate(bool sense);

// Returns nullopt if the predicate filters down the TypeId to 0 options.
std::optional<TypeId> filterMap(TypeId type, TypeIdPredicate predicate);
// TODO: Return TypeId only.
std::optional<TypeId> filterMapImpl(TypeId type, TypeIdPredicate predicate);
std::pair<std::optional<TypeId>, bool> filterMap(TypeId type, TypeIdPredicate predicate);

public:
std::optional<TypeId> pickTypesFromSense(TypeId type, bool sense);
std::pair<std::optional<TypeId>, bool> pickTypesFromSense(TypeId type, bool sense);

private:
TypeId unionOfTypes(TypeId a, TypeId b, const Location& location, bool unifyFreeTypes = true);
Expand Down Expand Up @@ -413,8 +419,12 @@ struct TypeChecker
const TypeId booleanType;
const TypeId threadType;
const TypeId anyType;
const TypeId unknownType;
const TypeId neverType;

const TypePackId anyTypePack;
const TypePackId neverTypePack;
const TypePackId uninhabitableTypePack;

private:
int checkRecursionCount = 0;
Expand Down
1 change: 1 addition & 0 deletions Analysis/include/Luau/TypePack.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,5 +173,6 @@ std::pair<std::vector<TypeId>, std::optional<TypePackId>> flatten(TypePackId tp,
bool isVariadic(TypePackId tp);
bool isVariadic(TypePackId tp, const TxnLog& log);

bool containsNever(TypePackId tp);

} // namespace Luau
157 changes: 135 additions & 22 deletions Analysis/include/Luau/TypeVar.h
Original file line number Diff line number Diff line change
Expand Up @@ -460,10 +460,18 @@ struct LazyTypeVar
std::function<TypeId()> thunk;
};

struct UnknownTypeVar
{
};

struct NeverTypeVar
{
};

using ErrorTypeVar = Unifiable::Error;

using TypeVariant = Unifiable::Variant<TypeId, PrimitiveTypeVar, ConstrainedTypeVar, BlockedTypeVar, SingletonTypeVar, FunctionTypeVar, TableTypeVar,
MetatableTypeVar, ClassTypeVar, AnyTypeVar, UnionTypeVar, IntersectionTypeVar, LazyTypeVar>;
MetatableTypeVar, ClassTypeVar, AnyTypeVar, UnionTypeVar, IntersectionTypeVar, LazyTypeVar, UnknownTypeVar, NeverTypeVar>;

struct TypeVar final
{
Expand Down Expand Up @@ -575,8 +583,12 @@ struct SingletonTypes
const TypeId trueType;
const TypeId falseType;
const TypeId anyType;
const TypeId unknownType;
const TypeId neverType;

const TypePackId anyTypePack;
const TypePackId neverTypePack;
const TypePackId uninhabitableTypePack;

SingletonTypes();
~SingletonTypes();
Expand Down Expand Up @@ -632,45 +644,146 @@ T* getMutable(TypeId tv)
return get_if<T>(&asMutable(tv)->ty);
}

/* Traverses the UnionTypeVar yielding each TypeId.
* If the iterator encounters a nested UnionTypeVar, it will instead yield each TypeId within.
*
* Beware: the iterator does not currently filter for unique TypeIds. This may change in the future.
const std::vector<TypeId>& getTypes(const UnionTypeVar* utv);
const std::vector<TypeId>& getTypes(const IntersectionTypeVar* itv);
const std::vector<TypeId>& getTypes(const ConstrainedTypeVar* ctv);

template<typename T>
struct TypeIterator;

using UnionTypeVarIterator = TypeIterator<UnionTypeVar>;
UnionTypeVarIterator begin(const UnionTypeVar* utv);
UnionTypeVarIterator end(const UnionTypeVar* utv);

using IntersectionTypeVarIterator = TypeIterator<IntersectionTypeVar>;
IntersectionTypeVarIterator begin(const IntersectionTypeVar* itv);
IntersectionTypeVarIterator end(const IntersectionTypeVar* itv);

using ConstrainedTypeVarIterator = TypeIterator<ConstrainedTypeVar>;
ConstrainedTypeVarIterator begin(const ConstrainedTypeVar* ctv);
ConstrainedTypeVarIterator end(const ConstrainedTypeVar* ctv);

/* Traverses the type T yielding each TypeId.
* If the iterator encounters a nested type T, it will instead yield each TypeId within.
*/
struct UnionTypeVarIterator
template<typename T>
struct TypeIterator
{
using value_type = Luau::TypeId;
using pointer = value_type*;
using reference = value_type&;
using difference_type = size_t;
using iterator_category = std::input_iterator_tag;

explicit UnionTypeVarIterator(const UnionTypeVar* utv);
explicit TypeIterator(const T* t)
{
LUAU_ASSERT(t);

const std::vector<TypeId>& types = getTypes(t);
if (!types.empty())
stack.push_front({t, 0});

seen.insert(t);
}

TypeIterator<T>& operator++()
{
advance();
descend();
return *this;
}

TypeIterator<T> operator++(int)
{
TypeIterator<T> copy = *this;
++copy;
return copy;
}

bool operator==(const TypeIterator<T>& rhs) const
{
if (!stack.empty() && !rhs.stack.empty())
return stack.front() == rhs.stack.front();

return stack.empty() && rhs.stack.empty();
}

bool operator!=(const TypeIterator<T>& rhs) const
{
return !(*this == rhs);
}

UnionTypeVarIterator& operator++();
UnionTypeVarIterator operator++(int);
bool operator!=(const UnionTypeVarIterator& rhs);
bool operator==(const UnionTypeVarIterator& rhs);
const TypeId& operator*()
{
LUAU_ASSERT(!stack.empty());

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

friend UnionTypeVarIterator end(const UnionTypeVar* utv);
auto [t, currentIndex] = stack.front();
LUAU_ASSERT(t);
const std::vector<TypeId>& types = getTypes(t);
LUAU_ASSERT(currentIndex < types.size());

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

// Normally, we'd have `begin` and `end` be a template but there's too much trouble
// with templates portability in this area, so not worth it. Thanks MSVC.
friend UnionTypeVarIterator end(const UnionTypeVar*);
friend IntersectionTypeVarIterator end(const IntersectionTypeVar*);
friend ConstrainedTypeVarIterator end(const ConstrainedTypeVar*);

private:
UnionTypeVarIterator() = default;
TypeIterator() = default;

// (UnionTypeVar* utv, size_t currentIndex)
using SavedIterInfo = std::pair<const UnionTypeVar*, size_t>;
// (T* t, size_t currentIndex)
using SavedIterInfo = std::pair<const T*, size_t>;

std::deque<SavedIterInfo> stack;
std::unordered_set<const UnionTypeVar*> seen; // Only needed to protect the iterator from hanging the thread.
std::unordered_set<const T*> seen; // Only needed to protect the iterator from hanging the thread.

void advance();
void descend();
};
void advance()
{
while (!stack.empty())
{
auto& [t, currentIndex] = stack.front();
++currentIndex;

const std::vector<TypeId>& types = getTypes(t);
if (currentIndex >= types.size())
stack.pop_front();
else
break;
}
}

UnionTypeVarIterator begin(const UnionTypeVar* utv);
UnionTypeVarIterator end(const UnionTypeVar* utv);
void descend()
{
while (!stack.empty())
{
auto [current, currentIndex] = stack.front();
const std::vector<TypeId>& types = getTypes(current);
if (auto inner = get<T>(follow(types[currentIndex])))
{
// If we're about to descend into a cyclic type, we should skip over this.
// Ideally this should never happen, but alas it does from time to time. :(
if (seen.find(inner) != seen.end())
advance();
else
{
seen.insert(inner);
stack.push_front({inner, 0});
}

continue;
}

break;
}
}
};

using TypeIdPredicate = std::function<std::optional<TypeId>(TypeId)>;
std::vector<TypeId> filterMap(TypeId type, TypeIdPredicate predicate);
Expand Down
8 changes: 8 additions & 0 deletions Analysis/include/Luau/VisitTypeVar.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ struct GenericTypeVarVisitor
{
return visit(ty);
}
virtual bool visit(TypeId ty, const UnknownTypeVar& atv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const NeverTypeVar& atv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const UnionTypeVar& utv)
{
return visit(ty);
Expand Down
Loading

0 comments on commit 8c151f5

Please sign in to comment.