// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details1#pragma once23#include "Luau/Ast.h" // Used for some of the enumerations4#include "Luau/DenseHash.h"5#include "Luau/NotNull.h"6#include "Luau/Variant.h"7#include "Luau/TypeFwd.h"8#include "Luau/TypeIds.h"910#include <string>11#include <memory>12#include <vector>1314namespace Luau15{1617enum class ValueContext;18struct Scope;1920// if resultType is a freeType, assignmentType <: freeType <: resultType bounds21struct EqualityConstraint22{23TypeId resultType;24TypeId assignmentType;25};2627// subType <: superType28struct SubtypeConstraint29{30TypeId subType;31TypeId superType;32};3334// subPack <: superPack35struct PackSubtypeConstraint36{37TypePackId subPack;38TypePackId superPack;3940// HACK!! TODO clip.41// We need to know which of `PackSubtypeConstraint` are emitted from `AstStatReturn` vs any others.42// Then we force these specific `PackSubtypeConstraint` to only dispatch in the order of the `return`s.43bool returns = false;44};4546// generalizedType ~ gen sourceType47struct GeneralizationConstraint48{49TypeId generalizedType;50TypeId sourceType;5152std::vector<TypeId> interiorTypes;53bool hasDeprecatedAttribute = false;54AstAttr::DeprecatedInfo deprecatedInfo;5556/// If true, never introduce generics. Always replace free types by their57/// bounds or unknown. Presently used only to generalize the whole module.58bool noGenerics = false;59};6061// variables ~ iterate iterator62// Unpack the iterator, figure out what types it iterates over, and bind those types to variables.63struct IterableConstraint64{65TypePackId iterator;66std::vector<TypeId> variables;6768const AstNode* nextAstFragment;69DenseHashMap<const AstNode*, TypeId>* astForInNextTypes;70};7172// name(namedType) = name73struct NameConstraint74{75TypeId namedType;76std::string name;77bool synthetic = false;78std::vector<TypeId> typeParameters;79std::vector<TypePackId> typePackParameters;80};8182// target ~ inst target83struct TypeAliasExpansionConstraint84{85// Must be a PendingExpansionType.86TypeId target;87};8889struct FunctionCallConstraint90{91TypeId fn;92TypePackId argsPack;93TypePackId result;9495// callSite can be nullptr in the case that this constraint was96// synthetically generated from some other constraint. eg97// IterableConstraint.98class AstExprCall* callSite = nullptr;99std::vector<std::optional<TypeId>> discriminantTypes;100101std::vector<TypeId> typeArguments;102std::vector<TypePackId> typePackArguments;103104// When we dispatch this constraint, we update the key at this map to record105// the overload that we selected.106DenseHashMap<const AstNode*, TypeId>* astOverloadResolvedTypes = nullptr;107};108109// function_check fn argsPack110//111// If fn is a function type and argsPack is a partially solved112// pack of arguments to be supplied to the function, propagate the argument113// types of fn into the types of argsPack. This is used to implement114// bidirectional inference of lambda arguments.115struct FunctionCheckConstraint116{117TypeId fn;118TypePackId argsPack;119120class AstExprCall* callSite = nullptr;121NotNull<DenseHashMap<const AstExpr*, TypeId>> astTypes;122NotNull<DenseHashMap<const AstExpr*, TypeId>> astExpectedTypes;123};124125// prim FreeType ExpectedType PrimitiveType126//127// FreeType is bounded below by the singleton type and above by PrimitiveType128// initially. When this constraint is resolved, it will check that the bounds129// of the free type are well-formed by subtyping.130//131// If they are not well-formed, then FreeType is replaced by its lower bound132//133// If they are well-formed and ExpectedType is potentially a singleton (an134// actual singleton or a union that contains a singleton),135// then FreeType is replaced by its lower bound136//137// else FreeType is replaced by PrimitiveType138struct PrimitiveTypeConstraint139{140TypeId freeType;141142// potentially gets used to force the lower bound?143std::optional<TypeId> expectedType;144145// the primitive type to check against146TypeId primitiveType;147};148149// result ~ hasProp type "prop_name"150//151// If the subject is a table, bind the result to the named prop. If the table152// has an indexer, bind it to the index result type. If the subject is a union,153// bind the result to the union of its constituents' properties.154//155// It would be nice to get rid of this constraint and someday replace it with156//157// T <: {p: X}158//159// Where {} describes an inexact shape type.160struct HasPropConstraint161{162TypeId resultType;163TypeId subjectType;164std::string prop;165ValueContext context;166167// We want to track if this `HasPropConstraint` comes from a conditional.168// If it does, we're going to change the behavior of property look-up a bit.169// In particular, we're going to return `unknownType` for property lookups170// on `table` or inexact table types where the property is not present.171//172// This allows us to refine table types to have additional properties173// without reporting errors in typechecking on the property tests.174bool inConditional = false;175176// HACK: We presently need types like true|false or string|"hello" when177// deciding whether a particular literal expression should have a singleton178// type. This boolean is set to true when extracting the property type of a179// value that may be a union of tables.180//181// For example, in the following code fragment, we want the lookup of the182// success property to yield true|false when extracting an expectedType in183// this expression:184//185// type Result<T, E> = {success:true, result: T} | {success:false, error: E}186//187// local r: Result<number, string> = {success=true, result=9}188//189// If we naively simplify the expectedType to boolean, we will erroneously190// compute the type boolean for the success property of the table literal.191// This causes type checking to fail.192bool suppressSimplification = false;193};194195// resultType ~ hasIndexer subjectType indexType196//197// If the subject type is a table or table-like thing that supports indexing,198// populate the type result with the result type of such an index operation.199//200// If the subject is not indexable, resultType is bound to errorType.201struct HasIndexerConstraint202{203TypeId resultType;204TypeId subjectType;205TypeId indexType;206};207208// assignProp lhsType propName rhsType209//210// Assign a value of type rhsType into the named property of lhsType.211212struct AssignPropConstraint213{214TypeId lhsType;215std::string propName;216TypeId rhsType;217218/// If a new property is to be inserted into a table type, it will be219/// ascribed this location.220std::optional<Location> propLocation;221222/// The canonical write type of the property. It is _solely_ used to223/// populate astTypes during constraint resolution. Nothing should ever224/// block on it.225TypeId propType;226227// When we generate constraints, we increment the remaining prop count on228// the table if we are able. This flag informs the solver as to whether or229// not it should in turn decrement the prop count when this constraint is230// dispatched.231bool decrementPropCount = false;232};233234struct AssignIndexConstraint235{236TypeId lhsType;237TypeId indexType;238TypeId rhsType;239240/// The canonical write type of the property. It is _solely_ used to241/// populate astTypes during constraint resolution. Nothing should ever242/// block on it.243TypeId propType;244};245246// resultTypes ~ unpack sourceTypePack247//248// Similar to PackSubtypeConstraint, but with one important difference: If the249// sourcePack is blocked, this constraint blocks.250struct UnpackConstraint251{252std::vector<TypeId> resultPack;253TypePackId sourcePack;254};255256// ty ~ reduce ty257//258// Try to reduce ty, if it is a TypeFunctionInstanceType. Otherwise, do nothing.259struct ReduceConstraint260{261TypeId ty;262};263264// tp ~ reduce tp265//266// Analogous to ReduceConstraint, but for type packs.267struct ReducePackConstraint268{269TypePackId tp;270};271272// simplify ty273struct SimplifyConstraint274{275TypeId ty;276};277278// push_function_type_constraint expectedFunctionType => functionType279//280// Attempt to "push" the types of `expectedFunctionType` into `functionType`,281// assuming that `expr` is a lambda who's un-generalized type is `functionType`.282// Similar to `FunctionCheckConstraint`. For example:283//284// local Foo = {} :: { bar : (number) -> () }285//286// function Foo.bar(x) end287//288// This will force `x` to be inferred as `number`.289struct PushFunctionTypeConstraint290{291TypeId expectedFunctionType;292TypeId functionType;293NotNull<AstExprFunction> expr;294bool isSelf;295};296297// Binds the function to a set of explicitly specified types,298// for f<<T>>.299struct TypeInstantiationConstraint300{301TypeId functionType;302TypeId placeholderType;303std::vector<TypeId> typeArguments;304std::vector<TypePackId> typePackArguments;305};306307struct PushTypeConstraint308{309TypeId expectedType;310TypeId targetType;311NotNull<DenseHashMap<const AstExpr*, TypeId>> astTypes;312NotNull<DenseHashMap<const AstExpr*, TypeId>> astExpectedTypes;313NotNull<const AstExpr> expr;314};315316using ConstraintV = Variant<317SubtypeConstraint,318PackSubtypeConstraint,319GeneralizationConstraint,320IterableConstraint,321NameConstraint,322TypeAliasExpansionConstraint,323FunctionCallConstraint,324FunctionCheckConstraint,325PrimitiveTypeConstraint,326HasPropConstraint,327HasIndexerConstraint,328AssignPropConstraint,329AssignIndexConstraint,330UnpackConstraint,331ReduceConstraint,332ReducePackConstraint,333EqualityConstraint,334SimplifyConstraint,335PushFunctionTypeConstraint,336PushTypeConstraint,337TypeInstantiationConstraint>;338339struct Constraint340{341Constraint(NotNull<Scope> scope, const Location& location, ConstraintV&& c);342343Constraint(const Constraint&) = delete;344Constraint& operator=(const Constraint&) = delete;345346NotNull<Scope> scope;347Location location;348ConstraintV c;349350std::vector<NotNull<Constraint>> dependencies;351352TypeIds DEPRECATED_getMaybeMutatedFreeTypes() const;353354/**355* Return the types and type packs that may be mutated by this constraint.356* Currently we do not do anything with type packs.357*/358std::pair<TypeIds, TypePackIds> getMaybeMutatedTypes() const;359360};361362using ConstraintPtr = std::unique_ptr<Constraint>;363364bool isReferenceCountedType(TypePackId tp);365bool isReferenceCountedType(const TypeId typ);366367inline Constraint& asMutable(const Constraint& c)368{369return const_cast<Constraint&>(c);370}371372template<typename T>373T* getMutable(Constraint& c)374{375return ::Luau::get_if<T>(&c.c);376}377378template<typename T>379const T* get(const Constraint& c)380{381return getMutable<T>(asMutable(c));382}383384} // namespace Luau385386387