// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once #include "Luau/NotNull.h" #include "Luau/Substitution.h" #include "Luau/TypeFwd.h" #include "Luau/Unifiable.h" #include "Luau/VisitType.h" namespace Luau { struct TxnLog; struct TypeArena; struct TypeCheckLimits; // A substitution which replaces generic types in a given set by free types. struct ReplaceGenerics : Substitution { ReplaceGenerics( const TxnLog* log, TypeArena* arena, NotNull builtinTypes, TypeLevel level, Scope* scope, const std::vector& generics, const std::vector& genericPacks ) : Substitution(log, arena) , builtinTypes(builtinTypes) , level(level) , scope(scope) , generics(generics) , genericPacks(genericPacks) { } void resetState( const TxnLog* log, TypeArena* arena, NotNull builtinTypes, TypeLevel level, Scope* scope, const std::vector& generics, const std::vector& genericPacks ); NotNull builtinTypes; TypeLevel level; Scope* scope; std::vector generics; std::vector genericPacks; bool ignoreChildren(TypeId ty) override; bool isDirty(TypeId ty) override; bool isDirty(TypePackId tp) override; TypeId clean(TypeId ty) override; TypePackId clean(TypePackId tp) override; }; // A substitution which replaces generic functions by monomorphic functions struct Instantiation : Substitution { Instantiation(const TxnLog* log, TypeArena* arena, NotNull builtinTypes, TypeLevel level, Scope* scope) : Substitution(log, arena) , builtinTypes(builtinTypes) , level(level) , scope(scope) , reusableReplaceGenerics(log, arena, builtinTypes, level, scope, {}, {}) { } void resetState(const TxnLog* log, TypeArena* arena, NotNull builtinTypes, TypeLevel level, Scope* scope); NotNull builtinTypes; TypeLevel level; Scope* scope; ReplaceGenerics reusableReplaceGenerics; bool ignoreChildren(TypeId ty) override; bool isDirty(TypeId ty) override; bool isDirty(TypePackId tp) override; TypeId clean(TypeId ty) override; TypePackId clean(TypePackId tp) override; }; // Used to find if a FunctionType requires generic type cleanup during instantiation struct GenericTypeFinder : TypeOnceVisitor { bool found = false; bool visit(TypeId ty) override { return !found; } bool visit(TypePackId ty) override { return !found; } bool visit(TypeId ty, const Luau::FunctionType& ftv) override { if (ftv.hasNoFreeOrGenericTypes) return false; if (!ftv.generics.empty() || !ftv.genericPacks.empty()) found = true; return !found; } bool visit(TypeId ty, const Luau::TableType& ttv) override { if (ttv.state == Luau::TableState::Generic) found = true; return !found; } bool visit(TypeId ty, const Luau::GenericType&) override { found = true; return false; } bool visit(TypePackId ty, const Luau::GenericTypePack&) override { found = true; return false; } bool visit(TypeId ty, const Luau::ClassType&) override { // During function instantiation, classes are not traversed even if they have generics return false; } }; /** Attempt to instantiate a type. Only used under local type inference. * * When given a generic function type, instantiate() will return a copy with the * generics replaced by fresh types. Instantiation will return the same TypeId * back if the function does not have any generics. * * All higher order generics are left as-is. For example, instantiation of * ((Y) -> (X, Y)) -> (X, Y) is ((Y) -> ('x, Y)) -> ('x, Y) * * We substitute the generic X for the free 'x, but leave the generic Y alone. * * Instantiation fails only when processing the type causes internal recursion * limits to be exceeded. */ std::optional instantiate( NotNull builtinTypes, NotNull arena, NotNull limits, NotNull scope, TypeId ty ); } // namespace Luau