2021-10-29 16:25:12 -04:00
|
|
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "Luau/TypeVar.h"
|
|
|
|
#include "Luau/Unifiable.h"
|
|
|
|
#include "Luau/Variant.h"
|
|
|
|
|
|
|
|
#include <optional>
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
namespace Luau
|
|
|
|
{
|
|
|
|
|
|
|
|
struct TypeArena;
|
|
|
|
|
|
|
|
struct TypePack;
|
|
|
|
struct VariadicTypePack;
|
|
|
|
|
|
|
|
struct TypePackVar;
|
|
|
|
|
2022-01-06 17:10:07 -05:00
|
|
|
struct TxnLog;
|
|
|
|
|
2021-10-29 16:25:12 -04:00
|
|
|
using TypePackId = const TypePackVar*;
|
|
|
|
using FreeTypePack = Unifiable::Free;
|
|
|
|
using BoundTypePack = Unifiable::Bound<TypePackId>;
|
|
|
|
using GenericTypePack = Unifiable::Generic;
|
|
|
|
using TypePackVariant = Unifiable::Variant<TypePackId, TypePack, VariadicTypePack>;
|
|
|
|
|
|
|
|
/* A TypePack is a rope-like string of TypeIds. We use this structure to encode
|
|
|
|
* notions like packs of unknown length and packs of any length, as well as more
|
|
|
|
* nuanced compositions like "a pack which is a number prepended to this other pack,"
|
|
|
|
* or "a pack that is 2 numbers followed by any number of any other types."
|
|
|
|
*/
|
|
|
|
struct TypePack
|
|
|
|
{
|
|
|
|
std::vector<TypeId> head;
|
|
|
|
std::optional<TypePackId> tail;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct VariadicTypePack
|
|
|
|
{
|
|
|
|
TypeId ty;
|
2022-04-14 17:57:15 -04:00
|
|
|
bool hidden = false; // if true, we don't display this when toString()ing a pack with this variadic as its tail.
|
2021-10-29 16:25:12 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct TypePackVar
|
|
|
|
{
|
|
|
|
explicit TypePackVar(const TypePackVariant& ty);
|
|
|
|
explicit TypePackVar(TypePackVariant&& ty);
|
|
|
|
TypePackVar(TypePackVariant&& ty, bool persistent);
|
2022-06-16 20:52:23 -04:00
|
|
|
|
2021-10-29 16:25:12 -04:00
|
|
|
bool operator==(const TypePackVar& rhs) const;
|
2022-06-16 20:52:23 -04:00
|
|
|
|
2021-10-29 16:25:12 -04:00
|
|
|
TypePackVar& operator=(TypePackVariant&& tp);
|
|
|
|
|
2022-06-16 20:52:23 -04:00
|
|
|
TypePackVar& operator=(const TypePackVar& rhs);
|
|
|
|
|
|
|
|
// Re-assignes the content of the pack, but doesn't change the owning arena and can't make pack persistent.
|
|
|
|
void reassign(const TypePackVar& rhs)
|
|
|
|
{
|
|
|
|
ty = rhs.ty;
|
|
|
|
}
|
|
|
|
|
2021-10-29 16:25:12 -04:00
|
|
|
TypePackVariant ty;
|
2022-06-16 20:52:23 -04:00
|
|
|
|
2021-10-29 16:25:12 -04:00
|
|
|
bool persistent = false;
|
|
|
|
|
2022-06-16 20:52:23 -04:00
|
|
|
// Pointer to the type arena that allocated this pack.
|
2021-10-29 16:25:12 -04:00
|
|
|
TypeArena* owningArena = nullptr;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Walk the set of TypeIds in a TypePack.
|
|
|
|
*
|
|
|
|
* Like TypeVars, individual TypePacks can be free, generic, or any.
|
|
|
|
*
|
|
|
|
* We afford the ability to work with these kinds of packs by giving the
|
|
|
|
* iterator a .tail() property that yields the tail-most TypePack in the
|
|
|
|
* rope.
|
|
|
|
*
|
|
|
|
* It is very commonplace to want to walk each type in a pack, then handle
|
|
|
|
* the tail specially. eg when checking parameters, it might be the case
|
|
|
|
* that the parameter pack ends with a VariadicTypePack. In this case, we
|
|
|
|
* want to allow any number of extra arguments.
|
|
|
|
*
|
|
|
|
* The iterator obtained by calling end(tp) does not have a .tail(), but is
|
|
|
|
* equivalent with end(tp2) for any two type packs.
|
|
|
|
*/
|
|
|
|
struct TypePackIterator
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
TypePackIterator() = default;
|
|
|
|
explicit TypePackIterator(TypePackId tp);
|
2022-01-06 17:10:07 -05:00
|
|
|
TypePackIterator(TypePackId tp, const TxnLog* log);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
TypePackIterator& operator++();
|
|
|
|
TypePackIterator operator++(int);
|
|
|
|
bool operator!=(const TypePackIterator& rhs);
|
|
|
|
bool operator==(const TypePackIterator& rhs);
|
|
|
|
|
|
|
|
const TypeId& operator*();
|
|
|
|
|
|
|
|
/** Return the tail of a TypePack.
|
|
|
|
* This may *only* be called on an iterator that has been incremented to the end.
|
|
|
|
* Returns nullopt if the pack has fixed length.
|
|
|
|
*/
|
|
|
|
std::optional<TypePackId> tail();
|
|
|
|
|
|
|
|
friend TypePackIterator end(TypePackId tp);
|
|
|
|
|
|
|
|
private:
|
|
|
|
TypePackId currentTypePack = nullptr;
|
|
|
|
const TypePack* tp = nullptr;
|
|
|
|
size_t currentIndex = 0;
|
2022-01-06 17:10:07 -05:00
|
|
|
|
|
|
|
const TxnLog* log;
|
2021-10-29 16:25:12 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
TypePackIterator begin(TypePackId tp);
|
2022-04-14 17:57:15 -04:00
|
|
|
TypePackIterator begin(TypePackId tp, const TxnLog* log);
|
2021-10-29 16:25:12 -04:00
|
|
|
TypePackIterator end(TypePackId tp);
|
|
|
|
|
2022-04-14 17:57:15 -04:00
|
|
|
using SeenSet = std::set<std::pair<const void*, const void*>>;
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
bool areEqual(SeenSet& seen, const TypePackVar& lhs, const TypePackVar& rhs);
|
|
|
|
|
|
|
|
TypePackId follow(TypePackId tp);
|
2022-01-06 17:10:07 -05:00
|
|
|
TypePackId follow(TypePackId tp, std::function<TypePackId(TypePackId)> mapper);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
2022-03-24 17:49:08 -04:00
|
|
|
size_t size(TypePackId tp, TxnLog* log = nullptr);
|
|
|
|
bool finite(TypePackId tp, TxnLog* log = nullptr);
|
|
|
|
size_t size(const TypePack& tp, TxnLog* log = nullptr);
|
2022-04-14 17:57:15 -04:00
|
|
|
std::optional<TypeId> first(TypePackId tp, bool ignoreHiddenVariadics = true);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
TypePackVar* asMutable(TypePackId tp);
|
|
|
|
TypePack* asMutable(const TypePack* tp);
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
const T* get(TypePackId tp)
|
|
|
|
{
|
2021-11-11 21:12:39 -05:00
|
|
|
LUAU_ASSERT(tp);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
2021-11-11 21:12:39 -05:00
|
|
|
if constexpr (!std::is_same_v<T, BoundTypePack>)
|
|
|
|
LUAU_ASSERT(get_if<BoundTypePack>(&tp->ty) == nullptr);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
return get_if<T>(&(tp->ty));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T* getMutable(TypePackId tp)
|
|
|
|
{
|
2021-11-11 21:12:39 -05:00
|
|
|
LUAU_ASSERT(tp);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
2021-11-11 21:12:39 -05:00
|
|
|
if constexpr (!std::is_same_v<T, BoundTypePack>)
|
|
|
|
LUAU_ASSERT(get_if<BoundTypePack>(&tp->ty) == nullptr);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
return get_if<T>(&(asMutable(tp)->ty));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns true if the type pack is known to be empty (no types in the head and no/an empty tail).
|
|
|
|
bool isEmpty(TypePackId tp);
|
|
|
|
|
|
|
|
/// Flattens out a type pack. Also returns a valid TypePackId tail if the type pack's full size is not known
|
|
|
|
std::pair<std::vector<TypeId>, std::optional<TypePackId>> flatten(TypePackId tp);
|
2022-04-14 17:57:15 -04:00
|
|
|
std::pair<std::vector<TypeId>, std::optional<TypePackId>> flatten(TypePackId tp, const TxnLog& log);
|
|
|
|
|
|
|
|
/// Returs true if the type pack arose from a function that is declared to be variadic.
|
|
|
|
/// Returns *false* for function argument packs that are inferred to be safe to oversaturate!
|
|
|
|
bool isVariadic(TypePackId tp);
|
|
|
|
bool isVariadic(TypePackId tp, const TxnLog& log);
|
|
|
|
|
2022-07-07 21:05:31 -04:00
|
|
|
bool containsNever(TypePackId tp);
|
2021-10-29 16:25:12 -04:00
|
|
|
|
|
|
|
} // namespace Luau
|