2022-06-17 02:05:14 +01:00
|
|
|
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
|
|
|
#pragma once
|
|
|
|
|
2022-07-01 00:52:43 +01:00
|
|
|
#include "Luau/Ast.h" // Used for some of the enumerations
|
2022-12-09 19:57:01 +00:00
|
|
|
#include "Luau/DenseHash.h"
|
2022-06-17 02:05:14 +01:00
|
|
|
#include "Luau/NotNull.h"
|
2022-10-21 18:54:01 +01:00
|
|
|
#include "Luau/Variant.h"
|
2023-10-21 02:10:30 +01:00
|
|
|
#include "Luau/TypeFwd.h"
|
2022-06-17 02:05:14 +01:00
|
|
|
|
2022-06-24 02:56:00 +01:00
|
|
|
#include <string>
|
2022-06-17 02:05:14 +01:00
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace Luau
|
|
|
|
{
|
|
|
|
|
2022-07-29 05:24:07 +01:00
|
|
|
struct Scope;
|
|
|
|
|
2022-06-17 02:05:14 +01:00
|
|
|
// subType <: superType
|
|
|
|
struct SubtypeConstraint
|
|
|
|
{
|
|
|
|
TypeId subType;
|
|
|
|
TypeId superType;
|
|
|
|
};
|
|
|
|
|
|
|
|
// subPack <: superPack
|
|
|
|
struct PackSubtypeConstraint
|
|
|
|
{
|
|
|
|
TypePackId subPack;
|
|
|
|
TypePackId superPack;
|
2023-07-07 21:10:48 +01:00
|
|
|
|
|
|
|
// HACK!! TODO clip.
|
|
|
|
// We need to know which of `PackSubtypeConstraint` are emitted from `AstStatReturn` vs any others.
|
|
|
|
// Then we force these specific `PackSubtypeConstraint` to only dispatch in the order of the `return`s.
|
|
|
|
bool returns = false;
|
2022-06-17 02:05:14 +01:00
|
|
|
};
|
|
|
|
|
2022-08-25 22:53:50 +01:00
|
|
|
// generalizedType ~ gen sourceType
|
2022-06-17 02:05:14 +01:00
|
|
|
struct GeneralizationConstraint
|
|
|
|
{
|
|
|
|
TypeId generalizedType;
|
|
|
|
TypeId sourceType;
|
|
|
|
};
|
|
|
|
|
|
|
|
// subType ~ inst superType
|
|
|
|
struct InstantiationConstraint
|
|
|
|
{
|
|
|
|
TypeId subType;
|
|
|
|
TypeId superType;
|
|
|
|
};
|
|
|
|
|
2023-12-02 07:46:57 +00:00
|
|
|
// variables ~ iterate iterator
|
|
|
|
// Unpack the iterator, figure out what types it iterates over, and bind those types to variables.
|
2022-09-02 00:14:03 +01:00
|
|
|
struct IterableConstraint
|
|
|
|
{
|
|
|
|
TypePackId iterator;
|
|
|
|
TypePackId variables;
|
2023-05-25 22:36:34 +01:00
|
|
|
|
|
|
|
const AstNode* nextAstFragment;
|
2023-06-24 07:19:39 +01:00
|
|
|
DenseHashMap<const AstNode*, TypeId>* astForInNextTypes;
|
2022-09-02 00:14:03 +01:00
|
|
|
};
|
|
|
|
|
2022-06-24 02:56:00 +01:00
|
|
|
// name(namedType) = name
|
|
|
|
struct NameConstraint
|
|
|
|
{
|
|
|
|
TypeId namedType;
|
|
|
|
std::string name;
|
2023-01-27 22:28:31 +00:00
|
|
|
bool synthetic = false;
|
2023-02-17 23:41:51 +00:00
|
|
|
std::vector<TypeId> typeParameters;
|
|
|
|
std::vector<TypePackId> typePackParameters;
|
2022-06-24 02:56:00 +01:00
|
|
|
};
|
|
|
|
|
2022-08-04 23:35:33 +01:00
|
|
|
// target ~ inst target
|
|
|
|
struct TypeAliasExpansionConstraint
|
|
|
|
{
|
2023-01-04 20:53:17 +00:00
|
|
|
// Must be a PendingExpansionType.
|
2022-08-04 23:35:33 +01:00
|
|
|
TypeId target;
|
|
|
|
};
|
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
struct FunctionCallConstraint
|
|
|
|
{
|
|
|
|
TypeId fn;
|
2022-09-29 23:23:10 +01:00
|
|
|
TypePackId argsPack;
|
2022-09-02 00:14:03 +01:00
|
|
|
TypePackId result;
|
2023-07-07 21:10:48 +01:00
|
|
|
class AstExprCall* callSite = nullptr;
|
2023-02-10 19:40:38 +00:00
|
|
|
std::vector<std::optional<TypeId>> discriminantTypes;
|
2023-05-05 22:52:49 +01:00
|
|
|
|
|
|
|
// When we dispatch this constraint, we update the key at this map to record
|
|
|
|
// the overload that we selected.
|
2023-07-07 21:10:48 +01:00
|
|
|
DenseHashMap<const AstNode*, TypeId>* astOverloadResolvedTypes = nullptr;
|
2022-09-02 00:14:03 +01:00
|
|
|
};
|
|
|
|
|
2022-09-23 20:17:25 +01:00
|
|
|
// result ~ prim ExpectedType SomeSingletonType MultitonType
|
|
|
|
//
|
|
|
|
// If ExpectedType is potentially a singleton (an actual singleton or a union
|
|
|
|
// that contains a singleton), then result ~ SomeSingletonType
|
|
|
|
//
|
|
|
|
// else result ~ MultitonType
|
|
|
|
struct PrimitiveTypeConstraint
|
|
|
|
{
|
|
|
|
TypeId resultType;
|
|
|
|
TypeId expectedType;
|
|
|
|
TypeId singletonType;
|
|
|
|
TypeId multitonType;
|
|
|
|
};
|
|
|
|
|
|
|
|
// result ~ hasProp type "prop_name"
|
|
|
|
//
|
|
|
|
// If the subject is a table, bind the result to the named prop. If the table
|
|
|
|
// has an indexer, bind it to the index result type. If the subject is a union,
|
|
|
|
// bind the result to the union of its constituents' properties.
|
|
|
|
//
|
|
|
|
// It would be nice to get rid of this constraint and someday replace it with
|
|
|
|
//
|
|
|
|
// T <: {p: X}
|
|
|
|
//
|
|
|
|
// Where {} describes an inexact shape type.
|
|
|
|
struct HasPropConstraint
|
|
|
|
{
|
|
|
|
TypeId resultType;
|
|
|
|
TypeId subjectType;
|
|
|
|
std::string prop;
|
2023-05-19 20:37:30 +01:00
|
|
|
|
|
|
|
// HACK: We presently need types like true|false or string|"hello" when
|
|
|
|
// deciding whether a particular literal expression should have a singleton
|
|
|
|
// type. This boolean is set to true when extracting the property type of a
|
|
|
|
// value that may be a union of tables.
|
|
|
|
//
|
|
|
|
// For example, in the following code fragment, we want the lookup of the
|
|
|
|
// success property to yield true|false when extracting an expectedType in
|
|
|
|
// this expression:
|
|
|
|
//
|
|
|
|
// type Result<T, E> = {success:true, result: T} | {success:false, error: E}
|
|
|
|
//
|
|
|
|
// local r: Result<number, string> = {success=true, result=9}
|
|
|
|
//
|
|
|
|
// If we naively simplify the expectedType to boolean, we will erroneously
|
|
|
|
// compute the type boolean for the success property of the table literal.
|
|
|
|
// This causes type checking to fail.
|
|
|
|
bool suppressSimplification = false;
|
2022-09-23 20:17:25 +01:00
|
|
|
};
|
|
|
|
|
2022-11-18 19:47:21 +00:00
|
|
|
// result ~ setProp subjectType ["prop", "prop2", ...] propType
|
|
|
|
//
|
|
|
|
// If the subject is a table or table-like thing that already has the named
|
|
|
|
// property chain, we unify propType with that existing property type.
|
|
|
|
//
|
|
|
|
// If the subject is a free table, we augment it in place.
|
|
|
|
//
|
|
|
|
// If the subject is an unsealed table, result is an augmented table that
|
|
|
|
// includes that new prop.
|
|
|
|
struct SetPropConstraint
|
|
|
|
{
|
|
|
|
TypeId resultType;
|
|
|
|
TypeId subjectType;
|
|
|
|
std::vector<std::string> path;
|
|
|
|
TypeId propType;
|
|
|
|
};
|
|
|
|
|
2023-02-24 21:49:38 +00:00
|
|
|
// result ~ setIndexer subjectType indexType propType
|
|
|
|
//
|
|
|
|
// If the subject is a table or table-like thing that already has an indexer,
|
|
|
|
// unify its indexType and propType with those from this constraint.
|
|
|
|
//
|
|
|
|
// If the table is a free or unsealed table, we augment it with a new indexer.
|
|
|
|
struct SetIndexerConstraint
|
|
|
|
{
|
|
|
|
TypeId resultType;
|
|
|
|
TypeId subjectType;
|
|
|
|
TypeId indexType;
|
|
|
|
TypeId propType;
|
|
|
|
};
|
|
|
|
|
2022-12-02 18:09:59 +00:00
|
|
|
// if negation:
|
|
|
|
// result ~ if isSingleton D then ~D else unknown where D = discriminantType
|
|
|
|
// if not negation:
|
|
|
|
// result ~ if isSingleton D then D else unknown where D = discriminantType
|
2022-11-04 17:33:22 +00:00
|
|
|
struct SingletonOrTopTypeConstraint
|
2022-10-21 18:54:01 +01:00
|
|
|
{
|
2022-11-04 17:33:22 +00:00
|
|
|
TypeId resultType;
|
2022-10-21 18:54:01 +01:00
|
|
|
TypeId discriminantType;
|
2022-12-02 18:09:59 +00:00
|
|
|
bool negated;
|
2022-10-21 18:54:01 +01:00
|
|
|
};
|
|
|
|
|
2023-02-24 21:49:38 +00:00
|
|
|
// resultType ~ unpack sourceTypePack
|
|
|
|
//
|
|
|
|
// Similar to PackSubtypeConstraint, but with one important difference: If the
|
|
|
|
// sourcePack is blocked, this constraint blocks.
|
|
|
|
struct UnpackConstraint
|
|
|
|
{
|
|
|
|
TypePackId resultPack;
|
|
|
|
TypePackId sourcePack;
|
2023-11-17 18:46:18 +00:00
|
|
|
|
|
|
|
// UnpackConstraint is sometimes used to resolve the types of assignments.
|
|
|
|
// When this is the case, any LocalTypes in resultPack can have their
|
|
|
|
// domains extended by the corresponding type from sourcePack.
|
|
|
|
bool resultIsLValue = false;
|
2023-02-24 21:49:38 +00:00
|
|
|
};
|
|
|
|
|
2023-05-19 20:37:30 +01:00
|
|
|
// resultType ~ refine type mode discriminant
|
|
|
|
//
|
|
|
|
// Compute type & discriminant (or type | discriminant) as soon as possible (but
|
|
|
|
// no sooner), simplify, and bind resultType to that type.
|
|
|
|
struct RefineConstraint
|
|
|
|
{
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Intersection,
|
|
|
|
Union
|
|
|
|
} mode;
|
|
|
|
|
|
|
|
TypeId resultType;
|
|
|
|
|
|
|
|
TypeId type;
|
|
|
|
TypeId discriminant;
|
|
|
|
};
|
|
|
|
|
2023-10-21 02:10:30 +01:00
|
|
|
// resultType ~ T0 op T1 op ... op TN
|
|
|
|
//
|
|
|
|
// op is either union or intersection. If any of the input types are blocked,
|
|
|
|
// this constraint will block unless forced.
|
|
|
|
struct SetOpConstraint
|
|
|
|
{
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Intersection,
|
|
|
|
Union
|
|
|
|
} mode;
|
|
|
|
|
|
|
|
TypeId resultType;
|
|
|
|
std::vector<TypeId> types;
|
|
|
|
};
|
|
|
|
|
2023-05-12 18:50:47 +01:00
|
|
|
// ty ~ reduce ty
|
|
|
|
//
|
|
|
|
// Try to reduce ty, if it is a TypeFamilyInstanceType. Otherwise, do nothing.
|
|
|
|
struct ReduceConstraint
|
|
|
|
{
|
|
|
|
TypeId ty;
|
|
|
|
};
|
|
|
|
|
|
|
|
// tp ~ reduce tp
|
|
|
|
//
|
|
|
|
// Analogous to ReduceConstraint, but for type packs.
|
|
|
|
struct ReducePackConstraint
|
|
|
|
{
|
|
|
|
TypePackId tp;
|
|
|
|
};
|
|
|
|
|
2023-10-21 02:10:30 +01:00
|
|
|
using ConstraintV = Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, InstantiationConstraint, IterableConstraint,
|
|
|
|
NameConstraint, TypeAliasExpansionConstraint, FunctionCallConstraint, PrimitiveTypeConstraint, HasPropConstraint, SetPropConstraint,
|
|
|
|
SetIndexerConstraint, SingletonOrTopTypeConstraint, UnpackConstraint, RefineConstraint, SetOpConstraint, ReduceConstraint, ReducePackConstraint>;
|
2022-09-02 00:14:03 +01:00
|
|
|
|
2022-06-17 02:05:14 +01:00
|
|
|
struct Constraint
|
|
|
|
{
|
2022-09-02 00:14:03 +01:00
|
|
|
Constraint(NotNull<Scope> scope, const Location& location, ConstraintV&& c);
|
2022-06-17 02:05:14 +01:00
|
|
|
|
|
|
|
Constraint(const Constraint&) = delete;
|
|
|
|
Constraint& operator=(const Constraint&) = delete;
|
|
|
|
|
2022-09-02 00:14:03 +01:00
|
|
|
NotNull<Scope> scope;
|
2023-02-10 19:40:38 +00:00
|
|
|
Location location;
|
2022-06-17 02:05:14 +01:00
|
|
|
ConstraintV c;
|
2022-09-02 00:14:03 +01:00
|
|
|
|
2022-06-17 02:05:14 +01:00
|
|
|
std::vector<NotNull<Constraint>> dependencies;
|
2023-10-27 22:18:41 +01:00
|
|
|
|
|
|
|
DenseHashSet<TypeId> getFreeTypes() const;
|
2022-06-17 02:05:14 +01:00
|
|
|
};
|
|
|
|
|
2022-09-23 20:17:25 +01:00
|
|
|
using ConstraintPtr = std::unique_ptr<Constraint>;
|
|
|
|
|
2022-06-17 02:05:14 +01:00
|
|
|
inline Constraint& asMutable(const Constraint& c)
|
|
|
|
{
|
|
|
|
return const_cast<Constraint&>(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T* getMutable(Constraint& c)
|
|
|
|
{
|
|
|
|
return ::Luau::get_if<T>(&c.c);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
const T* get(const Constraint& c)
|
|
|
|
{
|
|
|
|
return getMutable<T>(asMutable(c));
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Luau
|