// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once #include "Luau/Constraint.h" #include "Luau/DenseHash.h" #include "Luau/NotNull.h" #include "Luau/TypeCheckLimits.h" #include "Luau/TypeFwd.h" #include "Luau/TypePairHash.h" #include #include #include namespace Luau { struct InternalErrorReporter; struct Scope; struct TypeArena; enum class OccursCheckResult { Pass, Fail }; struct Unifier2 { NotNull arena; NotNull builtinTypes; NotNull scope; NotNull ice; TypeCheckLimits limits; DenseHashSet, TypePairHash> seenTypePairings{{nullptr, nullptr}}; DenseHashSet, TypePairHash> seenTypePackPairings{{nullptr, nullptr}}; DenseHashMap> expandedFreeTypes{nullptr}; // Mapping from generic types to free types to be used in instantiation. DenseHashMap genericSubstitutions{nullptr}; // Mapping from generic type packs to `TypePack`s of free types to be used in instantiation. DenseHashMap genericPackSubstitutions{nullptr}; int recursionCount = 0; int recursionLimit = 0; std::vector incompleteSubtypes; // null if not in a constraint solving context DenseHashSet* uninhabitedTypeFunctions; Unifier2(NotNull arena, NotNull builtinTypes, NotNull scope, NotNull ice); Unifier2(NotNull arena, NotNull builtinTypes, NotNull scope, NotNull ice, DenseHashSet* uninhabitedTypeFunctions); /** Attempt to commit the subtype relation subTy <: superTy to the type * graph. * * @returns true if successful. * * Note that incoherent types can and will successfully be unified. We stop * when we *cannot know* how to relate the provided types, not when doing so * would narrow something down to never or broaden it to unknown. * * Presently, the only way unification can fail is if we attempt to bind one * free TypePack to another and encounter an occurs check violation. */ bool unify(TypeId subTy, TypeId superTy); bool unifyFreeWithType(TypeId subTy, TypeId superTy); bool unify(TypeId subTy, const FunctionType* superFn); bool unify(const UnionType* subUnion, TypeId superTy); bool unify(TypeId subTy, const UnionType* superUnion); bool unify(const IntersectionType* subIntersection, TypeId superTy); bool unify(TypeId subTy, const IntersectionType* superIntersection); bool unify(TableType* subTable, const TableType* superTable); bool unify(const MetatableType* subMetatable, const MetatableType* superMetatable); bool unify(const AnyType* subAny, const FunctionType* superFn); bool unify(const FunctionType* subFn, const AnyType* superAny); bool unify(const AnyType* subAny, const TableType* superTable); bool unify(const TableType* subTable, const AnyType* superAny); // TODO think about this one carefully. We don't do unions or intersections of type packs bool unify(TypePackId subTp, TypePackId superTp); std::optional generalize(TypeId ty); private: /** * @returns simplify(left | right) */ TypeId mkUnion(TypeId left, TypeId right); /** * @returns simplify(left & right) */ TypeId mkIntersection(TypeId left, TypeId right); // Returns true if needle occurs within haystack already. ie if we bound // needle to haystack, would a cyclic type result? OccursCheckResult occursCheck(DenseHashSet& seen, TypeId needle, TypeId haystack); // Returns true if needle occurs within haystack already. ie if we bound // needle to haystack, would a cyclic TypePack result? OccursCheckResult occursCheck(DenseHashSet& seen, TypePackId needle, TypePackId haystack); }; } // namespace Luau