#pragma once
#include "Luau/Constraint.h"
#include "Luau/ConstraintSet.h"
#include "Luau/DataFlowGraph.h"
#include "Luau/DenseHash.h"
#include "Luau/Error.h"
#include "Luau/Location.h"
#include "Luau/Module.h"
#include "Luau/Normalize.h"
#include "Luau/OrderedSet.h"
#include "Luau/Substitution.h"
#include "Luau/SubtypingVariance.h"
#include "Luau/ToString.h"
#include "Luau/Type.h"
#include "Luau/TypeCheckLimits.h"
#include "Luau/TypeFunction.h"
#include "Luau/TypeFwd.h"
#include "Luau/Variant.h"
#include <utility>
#include <vector>
namespace Luau
{
enum class ValueContext;
struct DcrLogger;
class AstExpr;
using BlockedConstraintId = Variant<TypeId, TypePackId, const Constraint*>;
struct HashBlockedConstraintId
{
size_t operator()(const BlockedConstraintId& bci) const;
};
struct SubtypeConstraintRecord
{
TypeId subTy = nullptr;
TypeId superTy = nullptr;
SubtypingVariance variance = SubtypingVariance::Invalid;
bool operator==(const SubtypeConstraintRecord& other) const;
};
struct HashSubtypeConstraintRecord
{
size_t operator()(const SubtypeConstraintRecord& c) const;
};
struct ModuleResolver;
struct InstantiationSignature
{
TypeFun fn;
std::vector<TypeId> arguments;
std::vector<TypePackId> packArguments;
bool operator==(const InstantiationSignature& rhs) const;
bool operator!=(const InstantiationSignature& rhs) const
{
return !((*this) == rhs);
}
};
struct HashInstantiationSignature
{
size_t operator()(const InstantiationSignature& signature) const;
};
struct TablePropLookupResult
{
std::vector<TypeId> blockedTypes;
std::optional<TypeId> propType;
bool isIndex = false;
};
struct ConstraintSolver
{
NotNull<TypeArena> arena;
NotNull<BuiltinTypes> builtinTypes;
InternalErrorReporter iceReporter;
NotNull<Normalizer> normalizer;
NotNull<TypeFunctionRuntime> typeFunctionRuntime;
ConstraintSet constraintSet;
std::vector<NotNull<Constraint>> constraints;
NotNull<DenseHashMap<Scope*, TypeId>> scopeToFunction;
NotNull<Scope> rootScope;
ModulePtr module;
NotNull<const DataFlowGraph> dfg;
std::vector<std::unique_ptr<Constraint>> solverConstraints;
size_t solverConstraintLimit = 0;
std::vector<NotNull<const Constraint>> unsolvedConstraints;
std::unordered_map<NotNull<const Constraint>, size_t> blockedConstraints;
std::unordered_map<BlockedConstraintId, DenseHashSet<const Constraint*>, HashBlockedConstraintId> blocked;
DenseHashMap<InstantiationSignature, TypeId, HashInstantiationSignature> instantiatedAliases{{}};
DenseHashMap<TypeId, std::vector<std::pair<Location, TypeId>>> upperBoundContributors{nullptr};
DenseHashMap<TypeId, size_t> DEPRECATED_unresolvedConstraints{{}};
std::unordered_map<NotNull<const Constraint>, TypeIds> DEPRECATED_maybeMutatedFreeTypes;
std::unordered_map<TypeId, OrderedSet<const Constraint*>> DEPRECATED_mutatedFreeTypeToConstraint;
std::unordered_map<TypeId, Set<const Constraint*>> typeToConstraintSet;
DenseHashMap<const Constraint*, TypeIds> constraintToMutatedTypes{nullptr};
DenseHashSet<const void*> uninhabitedTypeFunctions{{}};
DenseHashMap<SubtypeConstraintRecord, Constraint*, HashSubtypeConstraintRecord> seenConstraints{{}};
DenseHashSet<TypeId> generalizedTypes_{nullptr};
const NotNull<DenseHashSet<TypeId>> generalizedTypes{&generalizedTypes_};
ErrorVec errors;
NotNull<ModuleResolver> moduleResolver;
std::vector<RequireCycle> requireCycles;
DcrLogger* logger;
TypeCheckLimits limits;
DenseHashMap<TypeId, const Constraint*> typeFunctionsToFinalize{nullptr};
explicit ConstraintSolver(
NotNull<Normalizer> normalizer,
NotNull<TypeFunctionRuntime> typeFunctionRuntime,
ModulePtr module,
NotNull<ModuleResolver> moduleResolver,
std::vector<RequireCycle> requireCycles,
DcrLogger* logger,
NotNull<const DataFlowGraph> dfg,
TypeCheckLimits limits,
ConstraintSet constraintSet
);
explicit ConstraintSolver(
NotNull<Normalizer> normalizer,
NotNull<TypeFunctionRuntime> typeFunctionRuntime,
NotNull<Scope> rootScope,
std::vector<NotNull<Constraint>> constraints,
NotNull<DenseHashMap<Scope*, TypeId>> scopeToFunction,
ModulePtr module,
NotNull<ModuleResolver> moduleResolver,
std::vector<RequireCycle> requireCycles,
DcrLogger* logger,
NotNull<const DataFlowGraph> dfg,
TypeCheckLimits limits
);
void randomize(unsigned seed);
void run();
void finalizeTypeFunctions();
bool isDone() const;
private:
void initFreeTypeTracking();
void generalizeOneType(TypeId ty);
template<typename T, typename... Args>
void emplace(NotNull<const Constraint> constraint, TypeId ty, Args&&... args);
template<typename T, typename... Args>
void emplace(NotNull<const Constraint> constraint, TypePackId tp, Args&&... args);
public:
bool tryDispatch(NotNull<const Constraint> c, bool force);
bool tryDispatch(const SubtypeConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const PackSubtypeConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const GeneralizationConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const NameConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const TypeAliasExpansionConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const FunctionCheckConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const PrimitiveTypeConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const HasPropConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const TypeInstantiationConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatchHasIndexer(
int& recursionDepth,
NotNull<const Constraint> constraint,
TypeId subjectType,
TypeId indexType,
TypeId resultType,
Set<TypeId>& seen
);
bool tryDispatch(const HasIndexerConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const AssignPropConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const AssignIndexConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const UnpackConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const ReduceConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const ReducePackConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const EqualityConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const SimplifyConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const PushFunctionTypeConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const PushTypeConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatchIterableTable(TypeId iteratorTy, const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatchIterableFunction(TypeId nextTy, TypeId tableTy, const IterableConstraint& c, NotNull<const Constraint> constraint);
TablePropLookupResult lookupTableProp(
NotNull<const Constraint> constraint,
TypeId subjectType,
const std::string& propName,
ValueContext context,
bool inConditional = false,
bool suppressSimplification = false
);
TablePropLookupResult lookupTableProp(
NotNull<const Constraint> constraint,
TypeId subjectType,
const std::string& propName,
ValueContext context,
bool inConditional,
bool suppressSimplification,
Set<TypeId>& seen
);
NotNull<const Constraint> unpackAndAssign(const std::vector<TypeId> destTypes, TypePackId srcTypes, NotNull<const Constraint> constraint);
void block(NotNull<const Constraint> target, NotNull<const Constraint> constraint);
bool block(TypeId target, NotNull<const Constraint> constraint);
bool block(TypePackId target, NotNull<const Constraint> constraint);
template<typename T>
bool block(const T& targets, NotNull<const Constraint> constraint)
{
for (TypeId target : targets)
block(target, constraint);
return false;
}
void inheritBlocks(NotNull<const Constraint> source, NotNull<const Constraint> addition);
bool blockOnPendingTypes(TypeId target, NotNull<const Constraint> constraint);
bool blockOnPendingTypes(TypePackId targetPack, NotNull<const Constraint> constraint);
void unblock(NotNull<const Constraint> progressed);
void unblock(TypeId ty, Location location);
void unblock(TypePackId progressed, Location location);
void unblock(const std::vector<TypeId>& types, Location location);
void unblock(const std::vector<TypePackId>& packs, Location location);
bool isBlocked(TypeId ty) const;
bool isBlocked(TypePackId tp) const;
bool isBlocked(NotNull<const Constraint> constraint) const;
NotNull<Constraint> pushConstraint(NotNull<Scope> scope, const Location& location, ConstraintV cv);
TypeId resolveModule(const ModuleInfo& info, const Location& location);
void reportError(TypeErrorData&& data, const Location& location);
void reportError(TypeError e);
void shiftReferences(TypeId source, TypeId target);
void bind(NotNull<const Constraint> constraint, TypeId ty, TypeId boundTo);
void bind(NotNull<const Constraint> constraint, TypePackId tp, TypePackId boundTo);
bool hasUnresolvedConstraints(TypeId ty);
template<typename TID>
bool unify(NotNull<const Constraint> constraint, TID subTy, TID superTy);
bool block_(BlockedConstraintId target, NotNull<const Constraint> constraint);
void unblock_(BlockedConstraintId progressed);
void reproduceConstraints(NotNull<Scope> scope, const Location& location, const Substitution& subst);
TypeId simplifyIntersection(NotNull<Scope> scope, Location location, TypeId left, TypeId right);
TypeId simplifyIntersection(NotNull<Scope> scope, Location location, TypeIds parts);
TypeId simplifyUnion(NotNull<Scope> scope, Location location, TypeId left, TypeId right);
TypeId instantiateFunctionType(
TypeId functionTypeId,
const std::vector<TypeId>& typeArguments,
const std::vector<TypePackId>& typePackArguments,
NotNull<Scope> scope,
const Location& location
);
TypePackId anyifyModuleReturnTypePackGenerics(TypePackId tp);
void throwTimeLimitError() const;
void throwUserCancelError() const;
ToStringOptions opts;
void fillInDiscriminantTypes(NotNull<const Constraint> constraint, const std::vector<std::optional<TypeId>>& discriminantTypes);
};
std::vector<NotNull<Constraint>> borrowConstraints(const std::vector<ConstraintPtr>& constraints);
std::pair<std::vector<TypeId>, std::vector<TypePackId>> saturateArguments(
TypeArena* arena,
NotNull<BuiltinTypes> builtinTypes,
const TypeFun& fn,
const std::vector<TypeId>& rawTypeArguments,
const std::vector<TypePackId>& rawPackArguments
);
void dump(NotNull<Scope> rootScope, struct ToStringOptions& opts);
}