// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once #include "Luau/Error.h" #include "Luau/Location.h" #include "Luau/Type.h" #include "Luau/TypePack.h" #include #include namespace Luau { struct TxnLog; struct TypeArena; class Normalizer; enum class ValueContext { LValue, RValue }; /// the current context of the type checker enum class TypeContext { /// the default context Default, /// inside of a condition Condition, }; bool inConditional(const TypeContext& context); // sets the given type context to `Condition` and restores it to its original // value when the struct drops out of scope struct InConditionalContext { TypeContext* typeContext; TypeContext oldValue; InConditionalContext(TypeContext* c) : typeContext(c) , oldValue(*c) { *typeContext = TypeContext::Condition; } ~InConditionalContext() { *typeContext = oldValue; } }; using ScopePtr = std::shared_ptr; std::optional findTableProperty( NotNull builtinTypes, ErrorVec& errors, TypeId ty, const std::string& name, Location location); std::optional findMetatableEntry( NotNull builtinTypes, ErrorVec& errors, TypeId type, const std::string& entry, Location location); std::optional findTablePropertyRespectingMeta( NotNull builtinTypes, ErrorVec& errors, TypeId ty, const std::string& name, Location location); std::optional findTablePropertyRespectingMeta( NotNull builtinTypes, ErrorVec& errors, TypeId ty, const std::string& name, ValueContext context, Location location); bool occursCheck(TypeId needle, TypeId haystack); // Returns the minimum and maximum number of types the argument list can accept. std::pair> getParameterExtents(const TxnLog* log, TypePackId tp, bool includeHiddenVariadics = false); // Extend the provided pack to at least `length` types. // Returns a temporary TypePack that contains those types plus a tail. TypePack extendTypePack( TypeArena& arena, NotNull builtinTypes, TypePackId pack, size_t length, std::vector> overrides = {}); /** * Reduces a union by decomposing to the any/error type if it appears in the * type list, and by merging child unions. Also strips out duplicate (by pointer * identity) types. * @param types the input type list to reduce. * @returns the reduced type list. */ std::vector reduceUnion(const std::vector& types); /** * Tries to remove nil from a union type, if there's another option. T | nil * reduces to T, but nil itself does not reduce. * @param builtinTypes the singleton types to use * @param arena the type arena to allocate the new type in, if necessary * @param ty the type to remove nil from * @returns a type with nil removed, or nil itself if that were the only option. */ TypeId stripNil(NotNull builtinTypes, TypeArena& arena, TypeId ty); struct ErrorSuppression { enum Value { Suppress, DoNotSuppress, NormalizationFailed, }; ErrorSuppression() = default; constexpr ErrorSuppression(Value enumValue) : value(enumValue) { } constexpr operator Value() const { return value; } explicit operator bool() const = delete; ErrorSuppression orElse(const ErrorSuppression& other) const { switch (value) { case DoNotSuppress: return other; default: return *this; } } private: Value value; }; /** * Normalizes the given type using the normalizer to determine if the type * should suppress any errors that would be reported involving it. * @param normalizer the normalizer to use * @param ty the type to check for error suppression * @returns an enum indicating whether or not to suppress the error or to signal a normalization failure */ ErrorSuppression shouldSuppressErrors(NotNull normalizer, TypeId ty); /** * Flattens and normalizes the given typepack using the normalizer to determine if the type * should suppress any errors that would be reported involving it. * @param normalizer the normalizer to use * @param tp the typepack to check for error suppression * @returns an enum indicating whether or not to suppress the error or to signal a normalization failure */ ErrorSuppression shouldSuppressErrors(NotNull normalizer, TypePackId tp); /** * Normalizes the two given type using the normalizer to determine if either type * should suppress any errors that would be reported involving it. * @param normalizer the normalizer to use * @param ty1 the first type to check for error suppression * @param ty2 the second type to check for error suppression * @returns an enum indicating whether or not to suppress the error or to signal a normalization failure */ ErrorSuppression shouldSuppressErrors(NotNull normalizer, TypeId ty1, TypeId ty2); /** * Flattens and normalizes the two given typepacks using the normalizer to determine if either type * should suppress any errors that would be reported involving it. * @param normalizer the normalizer to use * @param tp1 the first typepack to check for error suppression * @param tp2 the second typepack to check for error suppression * @returns an enum indicating whether or not to suppress the error or to signal a normalization failure */ ErrorSuppression shouldSuppressErrors(NotNull normalizer, TypePackId tp1, TypePackId tp2); // Similar to `std::optional>`, but whose `sizeof()` is the same as `std::pair` // and cooperates with C++'s `if (auto p = ...)` syntax without the extra fatness of `std::optional`. template struct TryPair { A first; B second; explicit operator bool() const { return bool(first) && bool(second); } }; template TryPair get2(Ty one, Ty two) { static_assert(std::is_pointer_v, "argument must be a pointer type"); const A* a = get(one); const B* b = get(two); if (a && b) return {a, b}; else return {nullptr, nullptr}; } template const T* get(std::optional ty) { if (ty) return get(*ty); else return nullptr; } template T* getMutable(std::optional ty) { if (ty) return getMutable(*ty); else return nullptr; } template std::optional follow(std::optional ty) { if (ty) return follow(*ty); else return std::nullopt; } } // namespace Luau