luau/Analysis/include/Luau/ConstraintSolver.h

396 lines
15 KiB
C
Raw Normal View History

2022-06-04 04:32:20 +08:00
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once
2022-06-17 08:54:42 +08:00
#include "Luau/Constraint.h"
2023-11-11 02:05:48 +08:00
#include "Luau/DenseHash.h"
2022-12-10 02:07:25 +08:00
#include "Luau/Error.h"
2023-11-11 02:05:48 +08:00
#include "Luau/Location.h"
2022-12-10 02:07:25 +08:00
#include "Luau/Module.h"
2022-10-07 07:55:58 +08:00
#include "Luau/Normalize.h"
2024-02-24 02:40:00 +08:00
#include "Luau/Substitution.h"
2022-12-10 02:07:25 +08:00
#include "Luau/ToString.h"
2023-01-04 01:33:19 +08:00
#include "Luau/Type.h"
2023-07-28 19:37:00 +08:00
#include "Luau/TypeCheckLimits.h"
2024-09-28 01:11:46 +08:00
#include "Luau/TypeFunction.h"
2023-11-11 02:05:48 +08:00
#include "Luau/TypeFwd.h"
2022-12-10 02:07:25 +08:00
#include "Luau/Variant.h"
2022-06-04 04:32:20 +08:00
2023-11-11 02:05:48 +08:00
#include <utility>
2022-06-04 04:32:20 +08:00
#include <vector>
namespace Luau
{
2024-02-24 02:40:00 +08:00
enum class ValueContext;
2022-09-09 05:44:50 +08:00
struct DcrLogger;
2024-03-31 06:49:03 +08:00
class AstExpr;
2022-06-04 04:32:20 +08:00
// TypeId, TypePackId, or Constraint*. It is impossible to know which, but we
// never dereference this pointer.
2023-02-25 02:24:22 +08:00
using BlockedConstraintId = Variant<TypeId, TypePackId, const Constraint*>;
struct HashBlockedConstraintId
{
size_t operator()(const BlockedConstraintId& bci) const;
};
2022-06-04 04:32:20 +08:00
2022-09-02 07:00:14 +08:00
struct ModuleResolver;
2022-08-05 05:27:28 +08:00
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;
};
2022-06-04 04:32:20 +08:00
struct ConstraintSolver
{
2023-04-22 05:41:03 +08:00
NotNull<TypeArena> arena;
2023-01-04 01:33:19 +08:00
NotNull<BuiltinTypes> builtinTypes;
2022-06-04 04:32:20 +08:00
InternalErrorReporter iceReporter;
2022-10-07 07:55:58 +08:00
NotNull<Normalizer> normalizer;
2024-09-28 01:11:46 +08:00
NotNull<TypeFunctionRuntime> typeFunctionRuntime;
2022-08-05 05:27:28 +08:00
// The entire set of constraints that the solver is trying to resolve.
std::vector<NotNull<Constraint>> constraints;
2022-07-29 11:41:13 +08:00
NotNull<Scope> rootScope;
2022-09-02 07:00:14 +08:00
ModuleName currentModuleName;
2022-06-04 04:32:20 +08:00
2022-08-05 05:27:28 +08:00
// Constraints that the solver has generated, rather than sourcing from the
// scope tree.
std::vector<std::unique_ptr<Constraint>> solverConstraints;
2022-06-04 04:32:20 +08:00
// This includes every constraint that has not been fully solved.
// A constraint can be both blocked and unsolved, for instance.
2022-06-17 08:54:42 +08:00
std::vector<NotNull<const Constraint>> unsolvedConstraints;
2022-06-04 04:32:20 +08:00
// A mapping of constraint pointer to how many things the constraint is
// blocked on. Can be empty or 0 for constraints that are not blocked on
// anything.
2022-06-17 08:54:42 +08:00
std::unordered_map<NotNull<const Constraint>, size_t> blockedConstraints;
2022-06-04 04:32:20 +08:00
// A mapping of type/pack pointers to the constraints they block.
2024-01-27 10:30:40 +08:00
std::unordered_map<BlockedConstraintId, DenseHashSet<const Constraint*>, HashBlockedConstraintId> blocked;
2022-08-05 05:27:28 +08:00
// Memoized instantiations of type aliases.
DenseHashMap<InstantiationSignature, TypeId, HashInstantiationSignature> instantiatedAliases{{}};
2023-11-11 02:05:48 +08:00
// Breadcrumbs for where a free type's upper bound was expanded. We use
// these to provide more helpful error messages when a free type is solved
// as never unexpectedly.
DenseHashMap<TypeId, std::vector<std::pair<Location, TypeId>>> upperBoundContributors{nullptr};
2022-06-17 08:54:42 +08:00
2023-10-28 03:33:36 +08:00
// A mapping from free types to the number of unresolved constraints that mention them.
DenseHashMap<TypeId, size_t> unresolvedConstraints{{}};
2024-07-20 01:21:40 +08:00
// Irreducible/uninhabited type functions or type pack functions.
DenseHashSet<const void*> uninhabitedTypeFunctions{{}};
2024-04-20 05:04:30 +08:00
2024-06-15 00:38:56 +08:00
// The set of types that will definitely be unchanged by generalization.
DenseHashSet<TypeId> generalizedTypes_{nullptr};
const NotNull<DenseHashSet<TypeId>> generalizedTypes{&generalizedTypes_};
2022-08-19 05:04:33 +08:00
// Recorded errors that take place within the solver.
ErrorVec errors;
2022-09-02 07:00:14 +08:00
NotNull<ModuleResolver> moduleResolver;
std::vector<RequireCycle> requireCycles;
2022-09-09 05:44:50 +08:00
DcrLogger* logger;
2023-07-28 19:37:00 +08:00
TypeCheckLimits limits;
2022-06-04 04:32:20 +08:00
2024-07-20 01:21:40 +08:00
DenseHashMap<TypeId, const Constraint*> typeFunctionsToFinalize{nullptr};
2024-06-15 00:38:56 +08:00
2024-08-02 07:25:12 +08:00
explicit ConstraintSolver(
NotNull<Normalizer> normalizer,
2024-09-28 01:11:46 +08:00
NotNull<TypeFunctionRuntime> typeFunctionRuntime,
2024-08-02 07:25:12 +08:00
NotNull<Scope> rootScope,
std::vector<NotNull<Constraint>> constraints,
ModuleName moduleName,
NotNull<ModuleResolver> moduleResolver,
std::vector<RequireCycle> requireCycles,
DcrLogger* logger,
TypeCheckLimits limits
);
2022-06-04 04:32:20 +08:00
2022-10-07 07:55:58 +08:00
// Randomize the order in which to dispatch constraints
void randomize(unsigned seed);
2022-06-04 04:32:20 +08:00
/**
* Attempts to dispatch all pending constraints and reach a type solution
2022-06-17 08:54:42 +08:00
* that satisfies all of the constraints.
2022-06-04 04:32:20 +08:00
**/
void run();
2024-06-15 00:38:56 +08:00
/**
2024-07-20 01:21:40 +08:00
* Attempts to perform one final reduction on type functions after every constraint has been completed
2024-06-15 00:38:56 +08:00
*
**/
2024-07-20 01:21:40 +08:00
void finalizeTypeFunctions();
2024-06-15 00:38:56 +08:00
2022-10-14 06:59:53 +08:00
bool isDone();
2024-06-15 00:38:56 +08:00
private:
/**
* Bind a type variable to another type.
*
* A constraint is required and will validate that blockedTy is owned by this
* constraint. This prevents one constraint from interfering with another's
* blocked types.
*
* Bind will also unblock the type variable for you.
*/
void bind(NotNull<const Constraint> constraint, TypeId ty, TypeId boundTo);
void bind(NotNull<const Constraint> constraint, TypePackId tp, TypePackId boundTo);
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:
2022-10-07 07:55:58 +08:00
/** Attempt to dispatch a constraint. Returns true if it was successful. If
* tryDispatch() returns false, the constraint remains in the unsolved set
* and will be retried later.
2022-07-01 07:29:02 +08:00
*/
2022-06-17 08:54:42 +08:00
bool tryDispatch(NotNull<const Constraint> c, bool force);
2022-07-01 07:29:02 +08:00
2022-06-17 08:54:42 +08:00
bool tryDispatch(const SubtypeConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const PackSubtypeConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const GeneralizationConstraint& c, NotNull<const Constraint> constraint, bool force);
2022-09-02 07:00:14 +08:00
bool tryDispatch(const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);
2022-06-24 09:44:07 +08:00
bool tryDispatch(const NameConstraint& c, NotNull<const Constraint> constraint);
2022-08-05 05:27:28 +08:00
bool tryDispatch(const TypeAliasExpansionConstraint& c, NotNull<const Constraint> constraint);
2022-09-02 07:00:14 +08:00
bool tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint);
2024-01-27 10:30:40 +08:00
bool tryDispatch(const FunctionCheckConstraint& c, NotNull<const Constraint> constraint);
2022-09-24 02:32:10 +08:00
bool tryDispatch(const PrimitiveTypeConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const HasPropConstraint& c, NotNull<const Constraint> constraint);
2024-03-16 05:01:00 +08:00
2024-06-15 00:38:56 +08:00
2024-04-20 05:04:30 +08:00
bool tryDispatchHasIndexer(
2024-08-02 07:25:12 +08:00
int& recursionDepth,
NotNull<const Constraint> constraint,
TypeId subjectType,
TypeId indexType,
TypeId resultType,
Set<TypeId>& seen
);
2024-03-16 05:01:00 +08:00
bool tryDispatch(const HasIndexerConstraint& c, NotNull<const Constraint> constraint);
2024-06-01 01:46:33 +08:00
bool tryDispatch(const AssignPropConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const AssignIndexConstraint& c, NotNull<const Constraint> constraint);
2023-02-25 02:24:22 +08:00
bool tryDispatch(const UnpackConstraint& c, NotNull<const Constraint> constraint);
2023-05-12 20:15:01 +08:00
bool tryDispatch(const ReduceConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const ReducePackConstraint& c, NotNull<const Constraint> constraint, bool force);
2024-02-24 02:40:00 +08:00
bool tryDispatch(const EqualityConstraint& c, NotNull<const Constraint> constraint, bool force);
2022-09-02 07:00:14 +08:00
// for a, ... in some_table do
2022-09-30 06:11:54 +08:00
// also handles __iter metamethod
2022-09-02 07:00:14 +08:00
bool tryDispatchIterableTable(TypeId iteratorTy, const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);
// for a, ... in next_function, t, ... do
2024-06-08 01:09:03 +08:00
bool tryDispatchIterableFunction(TypeId nextTy, TypeId tableTy, const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);
2022-06-04 04:32:20 +08:00
2024-08-02 07:25:12 +08:00
std::pair<std::vector<TypeId>, std::optional<TypeId>> lookupTableProp(
NotNull<const Constraint> constraint,
TypeId subjectType,
const std::string& propName,
ValueContext context,
bool inConditional = false,
bool suppressSimplification = false
);
std::pair<std::vector<TypeId>, std::optional<TypeId>> lookupTableProp(
NotNull<const Constraint> constraint,
TypeId subjectType,
const std::string& propName,
ValueContext context,
bool inConditional,
bool suppressSimplification,
DenseHashSet<TypeId>& seen
);
2022-11-19 02:45:14 +08:00
2024-06-01 01:46:33 +08:00
/**
* Generate constraints to unpack the types of srcTypes and assign each
2024-06-08 01:09:03 +08:00
* value to the corresponding BlockedType in destTypes.
2024-06-01 01:46:33 +08:00
*
2024-06-08 01:09:03 +08:00
* This function also overwrites the owners of each BlockedType. This is
* okay because this function is only used to decompose IterableConstraint
* into an UnpackConstraint.
*
* @param destTypes A vector of types comprised of BlockedTypes.
2024-06-01 01:46:33 +08:00
* @param srcTypes A TypePack that represents rvalues to be assigned.
* @returns The underlying UnpackConstraint. There's a bit of code in
* iteration that needs to pass blocks on to this constraint.
*/
2024-06-08 01:09:03 +08:00
NotNull<const Constraint> unpackAndAssign(const std::vector<TypeId> destTypes, TypePackId srcTypes, NotNull<const Constraint> constraint);
2024-06-01 01:46:33 +08:00
2022-06-17 08:54:42 +08:00
void block(NotNull<const Constraint> target, NotNull<const Constraint> constraint);
2022-06-04 04:32:20 +08:00
/**
2023-01-04 01:33:19 +08:00
* Block a constraint on the resolution of a Type.
2022-06-17 08:54:42 +08:00
* @returns false always. This is just to allow tryDispatch to return the result of block()
*/
bool block(TypeId target, NotNull<const Constraint> constraint);
bool block(TypePackId target, NotNull<const Constraint> constraint);
2022-06-04 04:32:20 +08:00
2023-05-20 02:59:59 +08:00
// Block on every target
template<typename T>
bool block(const T& targets, NotNull<const Constraint> constraint)
{
for (TypeId target : targets)
block(target, constraint);
return false;
}
2023-03-17 22:59:30 +08:00
/**
* For all constraints that are blocked on one constraint, make them block
* on a new constraint.
* @param source the constraint to copy blocks from.
* @param addition the constraint that other constraints should now block on.
*/
void inheritBlocks(NotNull<const Constraint> source, NotNull<const Constraint> addition);
2023-05-20 02:59:59 +08:00
// Traverse the type. If any pending types are found, block the constraint
// on them.
2022-09-24 02:32:10 +08:00
//
// Returns false if a type blocks the constraint.
//
// FIXME: This use of a boolean for the return result is an appalling
// interface.
2023-05-20 02:59:59 +08:00
bool blockOnPendingTypes(TypeId target, NotNull<const Constraint> constraint);
bool blockOnPendingTypes(TypePackId target, NotNull<const Constraint> constraint);
2022-09-24 02:32:10 +08:00
2022-06-17 08:54:42 +08:00
void unblock(NotNull<const Constraint> progressed);
2023-06-17 01:01:18 +08:00
void unblock(TypeId progressed, 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);
2022-06-04 04:32:20 +08:00
2022-06-17 08:54:42 +08:00
/**
* @returns true if the TypeId is in a blocked state.
*/
2024-09-28 01:11:46 +08:00
bool isBlocked(TypeId ty) const;
2022-06-17 08:54:42 +08:00
2022-09-02 07:00:14 +08:00
/**
* @returns true if the TypePackId is in a blocked state.
*/
2024-09-28 01:11:46 +08:00
bool isBlocked(TypePackId tp) const;
2022-09-02 07:00:14 +08:00
2022-06-04 04:32:20 +08:00
/**
* Returns whether the constraint is blocked on anything.
* @param constraint the constraint to check.
*/
2024-09-28 01:11:46 +08:00
bool isBlocked(NotNull<const Constraint> constraint) const;
2022-06-04 04:32:20 +08:00
2022-08-05 05:27:28 +08:00
/** Pushes a new solver constraint to the solver.
* @param cv the body of the constraint.
**/
2023-02-17 22:53:37 +08:00
NotNull<Constraint> pushConstraint(NotNull<Scope> scope, const Location& location, ConstraintV cv);
2022-09-02 07:00:14 +08:00
/**
* Attempts to resolve a module from its module information. Returns the
* module-level return type of the module, or the error type if one cannot
* be found. Reports errors to the solver if the module cannot be found or
* the require is illegal.
* @param module the module information to look up.
* @param location the location where the require is taking place; used for
* error locations.
**/
TypeId resolveModule(const ModuleInfo& module, const Location& location);
2022-08-05 05:27:28 +08:00
2022-08-19 05:04:33 +08:00
void reportError(TypeErrorData&& data, const Location& location);
void reportError(TypeError e);
2022-09-02 07:00:14 +08:00
2024-05-11 00:17:09 +08:00
/**
* Shifts the count of references from `source` to `target`. This should be paired
* with any instance of binding a free type in order to maintain accurate refcounts.
* If `target` is not a free type, this is a noop.
* @param source the free type which is being bound
* @param target the type which the free type is being bound to
*/
void shiftReferences(TypeId source, TypeId target);
/**
* Generalizes the given free type if the reference counting allows it.
* @param the scope to generalize in
* @param type the free type we want to generalize
* @returns a non-free type that generalizes the argument, or `std::nullopt` if one
* does not exist
*/
2024-06-21 06:23:57 +08:00
std::optional<TypeId> generalizeFreeType(NotNull<Scope> scope, TypeId type, bool avoidSealingTables = false);
2024-05-11 00:17:09 +08:00
2023-09-23 02:10:49 +08:00
/**
* Checks the existing set of constraints to see if there exist any that contain
* the provided free type, indicating that it is not yet ready to be replaced by
* one of its bounds.
* @param ty the free type that to check for related constraints
* @returns whether or not it is unsafe to replace the free type by one of its bounds
*/
bool hasUnresolvedConstraints(TypeId ty);
2024-02-24 02:40:00 +08:00
/** Attempts to unify subTy with superTy. If doing so would require unifying
2023-03-31 20:21:14 +08:00
* BlockedTypes, fail and block the constraint on those BlockedTypes.
*
2024-02-24 02:40:00 +08:00
* Note: TID can only be TypeId or TypePackId.
*
2023-03-31 20:21:14 +08:00
* If unification fails, replace all free types with errorType.
*
* If unification succeeds, unblock every type changed by the unification.
2024-02-24 02:40:00 +08:00
*
* @returns true if the unification succeeded. False if the unification was
* too complex.
2023-03-31 20:21:14 +08:00
*/
2024-02-03 02:20:03 +08:00
template<typename TID>
2024-02-24 02:40:00 +08:00
bool unify(NotNull<const Constraint> constraint, TID subTy, TID superTy);
2023-03-31 20:21:14 +08:00
2022-06-17 08:54:42 +08:00
/**
* Marks a constraint as being blocked on a type or type pack. The constraint
* solver will not attempt to dispatch blocked constraints until their
* dependencies have made progress.
* @param target the type or type pack pointer that the constraint is blocked on.
* @param constraint the constraint to block.
**/
2024-01-27 10:30:40 +08:00
bool block_(BlockedConstraintId target, NotNull<const Constraint> constraint);
2022-06-17 08:54:42 +08:00
/**
* Informs the solver that progress has been made on a type or type pack. The
* solver will wake up all constraints that are blocked on the type or type pack,
* and will resume attempting to dispatch them.
* @param progressed the type or type pack pointer that has progressed.
**/
void unblock_(BlockedConstraintId progressed);
2022-09-02 07:00:14 +08:00
2024-02-24 02:40:00 +08:00
/**
* Reproduces any constraints necessary for new types that are copied when applying a substitution.
2024-07-20 01:21:40 +08:00
* At the time of writing, this pertains only to type functions.
2024-02-24 02:40:00 +08:00
* @param subst the substitution that was applied
**/
void reproduceConstraints(NotNull<Scope> scope, const Location& location, const Substitution& subst);
2022-09-16 06:13:58 +08:00
TypeId errorRecoveryType() const;
TypePackId errorRecoveryTypePack() const;
2023-05-20 02:59:59 +08:00
TypePackId anyifyModuleReturnTypePackGenerics(TypePackId tp);
2024-09-28 01:11:46 +08:00
void throwTimeLimitError() const;
void throwUserCancelError() const;
2023-07-28 19:37:00 +08:00
2022-09-02 07:00:14 +08:00
ToStringOptions opts;
2022-06-04 04:32:20 +08:00
};
2022-07-29 11:41:13 +08:00
void dump(NotNull<Scope> rootScope, struct ToStringOptions& opts);
2022-06-04 04:32:20 +08:00
} // namespace Luau