diff --git a/Analysis/include/Luau/Anyification.h b/Analysis/include/Luau/Anyification.h index a6f3e2a9..7b6f7171 100644 --- a/Analysis/include/Luau/Anyification.h +++ b/Analysis/include/Luau/Anyification.h @@ -4,7 +4,7 @@ #include "Luau/NotNull.h" #include "Luau/Substitution.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include @@ -19,12 +19,12 @@ using ScopePtr = std::shared_ptr; // A substitution which replaces free types by any struct Anyification : Substitution { - Anyification(TypeArena* arena, NotNull scope, NotNull singletonTypes, InternalErrorReporter* iceHandler, TypeId anyType, + Anyification(TypeArena* arena, NotNull scope, NotNull builtinTypes, InternalErrorReporter* iceHandler, TypeId anyType, TypePackId anyTypePack); - Anyification(TypeArena* arena, const ScopePtr& scope, NotNull singletonTypes, InternalErrorReporter* iceHandler, TypeId anyType, + Anyification(TypeArena* arena, const ScopePtr& scope, NotNull builtinTypes, InternalErrorReporter* iceHandler, TypeId anyType, TypePackId anyTypePack); NotNull scope; - NotNull singletonTypes; + NotNull builtinTypes; InternalErrorReporter* iceHandler; TypeId anyType; diff --git a/Analysis/include/Luau/ApplyTypeFunction.h b/Analysis/include/Luau/ApplyTypeFunction.h index 8da3bc42..3f5f47fd 100644 --- a/Analysis/include/Luau/ApplyTypeFunction.h +++ b/Analysis/include/Luau/ApplyTypeFunction.h @@ -3,7 +3,7 @@ #include "Luau/Substitution.h" #include "Luau/TxnLog.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" namespace Luau { diff --git a/Analysis/include/Luau/AstQuery.h b/Analysis/include/Luau/AstQuery.h index 950a19da..bf738462 100644 --- a/Analysis/include/Luau/AstQuery.h +++ b/Analysis/include/Luau/AstQuery.h @@ -13,8 +13,8 @@ struct Binding; struct SourceModule; struct Module; -struct TypeVar; -using TypeId = const TypeVar*; +struct Type; +using TypeId = const Type*; using ScopePtr = std::shared_ptr; diff --git a/Analysis/include/Luau/Autocomplete.h b/Analysis/include/Luau/Autocomplete.h index f40f8b49..a4101e16 100644 --- a/Analysis/include/Luau/Autocomplete.h +++ b/Analysis/include/Luau/Autocomplete.h @@ -2,7 +2,7 @@ #pragma once #include "Luau/Location.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include #include @@ -65,7 +65,7 @@ struct AutocompleteEntry // Set if this suggestion matches the type expected in the context TypeCorrectKind typeCorrect = TypeCorrectKind::None; - std::optional containingClass = std::nullopt; + std::optional containingClass = std::nullopt; std::optional prop = std::nullopt; std::optional documentationSymbol = std::nullopt; Tags tags; @@ -89,7 +89,7 @@ struct AutocompleteResult }; using ModuleName = std::string; -using StringCompletionCallback = std::function(std::string tag, std::optional ctx)>; +using StringCompletionCallback = std::function(std::string tag, std::optional ctx)>; AutocompleteResult autocomplete(Frontend& frontend, const ModuleName& moduleName, Position position, StringCompletionCallback callback); diff --git a/Analysis/include/Luau/BuiltinDefinitions.h b/Analysis/include/Luau/BuiltinDefinitions.h index 16cccafe..0604b40e 100644 --- a/Analysis/include/Luau/BuiltinDefinitions.h +++ b/Analysis/include/Luau/BuiltinDefinitions.h @@ -2,7 +2,7 @@ #pragma once #include "Luau/Scope.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include @@ -48,7 +48,7 @@ void attachDcrMagicFunction(TypeId ty, DcrMagicFunction fn); void attachDcrMagicRefinement(TypeId ty, DcrMagicRefinement fn); Property makeProperty(TypeId ty, std::optional documentationSymbol = std::nullopt); -void assignPropDocumentationSymbols(TableTypeVar::Props& props, const std::string& baseName); +void assignPropDocumentationSymbols(TableType::Props& props, const std::string& baseName); std::string getBuiltinDefinitionSource(); diff --git a/Analysis/include/Luau/Clone.h b/Analysis/include/Luau/Clone.h index f003c242..51f1e7a6 100644 --- a/Analysis/include/Luau/Clone.h +++ b/Analysis/include/Luau/Clone.h @@ -3,7 +3,7 @@ #include #include "Luau/TypeArena.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include diff --git a/Analysis/include/Luau/Connective.h b/Analysis/include/Luau/Connective.h index 4a6be93c..d82bc4dd 100644 --- a/Analysis/include/Luau/Connective.h +++ b/Analysis/include/Luau/Connective.h @@ -10,8 +10,8 @@ namespace Luau { -struct TypeVar; -using TypeId = const TypeVar*; +struct Type; +using TypeId = const Type*; struct Negation; struct Conjunction; diff --git a/Analysis/include/Luau/Constraint.h b/Analysis/include/Luau/Constraint.h index 9eea9c28..b4132954 100644 --- a/Analysis/include/Luau/Constraint.h +++ b/Analysis/include/Luau/Constraint.h @@ -5,7 +5,7 @@ #include "Luau/Def.h" #include "Luau/DenseHash.h" #include "Luau/NotNull.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/Variant.h" #include @@ -17,8 +17,8 @@ namespace Luau struct Scope; -struct TypeVar; -using TypeId = const TypeVar*; +struct Type; +using TypeId = const Type*; struct TypePackVar; using TypePackId = const TypePackVar*; @@ -94,7 +94,7 @@ struct NameConstraint // target ~ inst target struct TypeAliasExpansionConstraint { - // Must be a PendingExpansionTypeVar. + // Must be a PendingExpansionType. TypeId target; }; diff --git a/Analysis/include/Luau/ConstraintGraphBuilder.h b/Analysis/include/Luau/ConstraintGraphBuilder.h index c25a5537..65ea5e09 100644 --- a/Analysis/include/Luau/ConstraintGraphBuilder.h +++ b/Analysis/include/Luau/ConstraintGraphBuilder.h @@ -9,7 +9,7 @@ #include "Luau/ModuleResolver.h" #include "Luau/NotNull.h" #include "Luau/Symbol.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/Variant.h" #include @@ -61,7 +61,7 @@ struct ConstraintGraphBuilder ModuleName moduleName; ModulePtr module; - NotNull singletonTypes; + NotNull builtinTypes; const NotNull arena; // The root scope of the module we're generating constraints for. // This is null when the CGB is initially constructed. @@ -114,7 +114,7 @@ struct ConstraintGraphBuilder DcrLogger* logger; ConstraintGraphBuilder(const ModuleName& moduleName, ModulePtr module, TypeArena* arena, NotNull moduleResolver, - NotNull singletonTypes, NotNull ice, const ScopePtr& globalScope, DcrLogger* logger, + NotNull builtinTypes, NotNull ice, const ScopePtr& globalScope, DcrLogger* logger, NotNull dfg); /** diff --git a/Analysis/include/Luau/ConstraintSolver.h b/Analysis/include/Luau/ConstraintSolver.h index c02cd4d5..5c235a35 100644 --- a/Analysis/include/Luau/ConstraintSolver.h +++ b/Analysis/include/Luau/ConstraintSolver.h @@ -7,7 +7,7 @@ #include "Luau/Module.h" #include "Luau/Normalize.h" #include "Luau/ToString.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/Variant.h" #include @@ -44,7 +44,7 @@ struct HashInstantiationSignature struct ConstraintSolver { TypeArena* arena; - NotNull singletonTypes; + NotNull builtinTypes; InternalErrorReporter iceReporter; NotNull normalizer; // The entire set of constraints that the solver is trying to resolve. @@ -126,13 +126,13 @@ struct ConstraintSolver void block(NotNull target, NotNull constraint); /** - * Block a constraint on the resolution of a TypeVar. + * Block a constraint on the resolution of a Type. * @returns false always. This is just to allow tryDispatch to return the result of block() */ bool block(TypeId target, NotNull constraint); bool block(TypePackId target, NotNull constraint); - // Traverse the type. If any blocked or pending typevars are found, block + // Traverse the type. If any blocked or pending types are found, block // the constraint on them. // // Returns false if a type blocks the constraint. diff --git a/Analysis/include/Luau/Error.h b/Analysis/include/Luau/Error.h index 739354f8..69d4cca3 100644 --- a/Analysis/include/Luau/Error.h +++ b/Analysis/include/Luau/Error.h @@ -2,7 +2,7 @@ #pragma once #include "Luau/Location.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/Variant.h" namespace Luau diff --git a/Analysis/include/Luau/Frontend.h b/Analysis/include/Luau/Frontend.h index b2662c68..dfb35cbd 100644 --- a/Analysis/include/Luau/Frontend.h +++ b/Analysis/include/Luau/Frontend.h @@ -130,8 +130,8 @@ struct Frontend Frontend(FileResolver* fileResolver, ConfigResolver* configResolver, const FrontendOptions& options = {}); CheckResult check(const ModuleName& name, std::optional optionOverride = {}); // new shininess - LintResult lint(const ModuleName& name, std::optional enabledLintWarnings = {}); + LintResult lint(const ModuleName& name, std::optional enabledLintWarnings = {}); LintResult lint(const SourceModule& module, std::optional enabledLintWarnings = {}); bool isDirty(const ModuleName& name, bool forAutocomplete = false) const; @@ -165,22 +165,22 @@ private: ModulePtr check(const SourceModule& sourceModule, Mode mode, const ScopePtr& environmentScope, std::vector requireCycles, bool forAutocomplete = false); - std::pair getSourceNode(CheckResult& checkResult, const ModuleName& name); + std::pair getSourceNode(const ModuleName& name); SourceModule parse(const ModuleName& name, std::string_view src, const ParseOptions& parseOptions); - bool parseGraph(std::vector& buildQueue, CheckResult& checkResult, const ModuleName& root, bool forAutocomplete); + bool parseGraph(std::vector& buildQueue, const ModuleName& root, bool forAutocomplete); static LintResult classifyLints(const std::vector& warnings, const Config& config); - ScopePtr getModuleEnvironment(const SourceModule& module, const Config& config, bool forAutocomplete = false); + ScopePtr getModuleEnvironment(const SourceModule& module, const Config& config, bool forAutocomplete); std::unordered_map environments; std::unordered_map> builtinDefinitions; - SingletonTypes singletonTypes_; + BuiltinTypes builtinTypes_; public: - const NotNull singletonTypes; + const NotNull builtinTypes; FileResolver* fileResolver; FrontendModuleResolver moduleResolver; diff --git a/Analysis/include/Luau/Instantiation.h b/Analysis/include/Luau/Instantiation.h index cd88d33a..c916f953 100644 --- a/Analysis/include/Luau/Instantiation.h +++ b/Analysis/include/Luau/Instantiation.h @@ -2,7 +2,7 @@ #pragma once #include "Luau/Substitution.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/Unifiable.h" namespace Luau diff --git a/Analysis/include/Luau/IostreamHelpers.h b/Analysis/include/Luau/IostreamHelpers.h index 05b94516..42b362be 100644 --- a/Analysis/include/Luau/IostreamHelpers.h +++ b/Analysis/include/Luau/IostreamHelpers.h @@ -3,7 +3,7 @@ #include "Luau/Error.h" #include "Luau/Location.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/Ast.h" #include @@ -43,7 +43,7 @@ std::ostream& operator<<(std::ostream& lhs, const MissingUnionProperty& error); std::ostream& operator<<(std::ostream& lhs, const TypesAreUnrelated& error); std::ostream& operator<<(std::ostream& lhs, const TableState& tv); -std::ostream& operator<<(std::ostream& lhs, const TypeVar& tv); +std::ostream& operator<<(std::ostream& lhs, const Type& tv); std::ostream& operator<<(std::ostream& lhs, const TypePackVar& tv); std::ostream& operator<<(std::ostream& lhs, const TypeErrorData& ted); diff --git a/Analysis/include/Luau/LValue.h b/Analysis/include/Luau/LValue.h index 518cbfaf..9a8b863b 100644 --- a/Analysis/include/Luau/LValue.h +++ b/Analysis/include/Luau/LValue.h @@ -10,8 +10,8 @@ namespace Luau { -struct TypeVar; -using TypeId = const TypeVar*; +struct Type; +using TypeId = const Type*; struct Field; diff --git a/Analysis/include/Luau/Module.h b/Analysis/include/Luau/Module.h index d22aad12..d6d9f841 100644 --- a/Analysis/include/Luau/Module.h +++ b/Analysis/include/Luau/Module.h @@ -89,8 +89,8 @@ struct Module ScopePtr getModuleScope() const; // Once a module has been typechecked, we clone its public interface into a separate arena. - // This helps us to force TypeVar ownership into a DAG rather than a DCG. - void clonePublicInterface(NotNull singletonTypes, InternalErrorReporter& ice); + // This helps us to force Type ownership into a DAG rather than a DCG. + void clonePublicInterface(NotNull builtinTypes, InternalErrorReporter& ice); }; } // namespace Luau diff --git a/Analysis/include/Luau/Normalize.h b/Analysis/include/Luau/Normalize.h index 39257315..865a9c4d 100644 --- a/Analysis/include/Luau/Normalize.h +++ b/Analysis/include/Luau/Normalize.h @@ -2,7 +2,7 @@ #pragma once #include "Luau/NotNull.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/UnifierSharedState.h" #include @@ -13,12 +13,12 @@ namespace Luau struct InternalErrorReporter; struct Module; struct Scope; -struct SingletonTypes; +struct BuiltinTypes; using ModulePtr = std::shared_ptr; -bool isSubtype(TypeId subTy, TypeId superTy, NotNull scope, NotNull singletonTypes, InternalErrorReporter& ice); -bool isSubtype(TypePackId subTy, TypePackId superTy, NotNull scope, NotNull singletonTypes, InternalErrorReporter& ice); +bool isSubtype(TypeId subTy, TypeId superTy, NotNull scope, NotNull builtinTypes, InternalErrorReporter& ice); +bool isSubtype(TypePackId subTy, TypePackId superTy, NotNull scope, NotNull builtinTypes, InternalErrorReporter& ice); class TypeIds { @@ -31,7 +31,7 @@ public: using iterator = std::vector::iterator; using const_iterator = std::vector::const_iterator; - TypeIds(const TypeIds&) = delete; + TypeIds(const TypeIds&) = default; TypeIds(TypeIds&&) = default; TypeIds() = default; ~TypeIds() = default; @@ -155,6 +155,32 @@ struct NormalizedStringType bool isSubtype(const NormalizedStringType& subStr, const NormalizedStringType& superStr); +struct NormalizedClassType +{ + /** Has the following structure: + * + * (C1 & ~N11 & ... & ~Nn) | (C2 & ~N21 & ... & ~N2n) | ... + * + * C2 is either not a subtype of any other Cm, or it is and is also a + * subtype of one of Nmn types within the same cluster. + * + * Each TypeId is a class type. + */ + std::unordered_map classes; + + /** + * In order to maintain a consistent insertion order, we use this vector to + * keep track of it. An ordered std::map will sort by pointer identity, + * which is undesirable. + */ + std::vector ordering; + + void pushPair(TypeId ty, TypeIds negations); + + void resetToNever(); + bool isNever() const; +}; + // A normalized function type can be `never`, the top function type `function`, // or an intersection of function types. // @@ -200,9 +226,11 @@ struct NormalizedType // This type is either never, boolean type, or a boolean singleton. TypeId booleans; + NormalizedClassType classes; + // The class part of the type. // Each element of this set is a class, and none of the classes are subclasses of each other. - TypeIds classes; + TypeIds DEPRECATED_classes; // The error part of the type. // This type is either never or the error type. @@ -234,7 +262,7 @@ struct NormalizedType // The generic/free part of the type. NormalizedTyvars tyvars; - NormalizedType(NotNull singletonTypes); + NormalizedType(NotNull builtinTypes); NormalizedType() = delete; ~NormalizedType() = default; @@ -256,10 +284,10 @@ class Normalizer public: TypeArena* arena; - NotNull singletonTypes; + NotNull builtinTypes; NotNull sharedState; - Normalizer(TypeArena* arena, NotNull singletonTypes, NotNull sharedState); + Normalizer(TypeArena* arena, NotNull builtinTypes, NotNull sharedState); Normalizer(const Normalizer&) = delete; Normalizer(Normalizer&&) = delete; Normalizer() = delete; @@ -283,6 +311,8 @@ public: TypeId unionOfBools(TypeId here, TypeId there); void unionClassesWithClass(TypeIds& heres, TypeId there); void unionClasses(TypeIds& heres, const TypeIds& theres); + void unionClassesWithClass(NormalizedClassType& heres, TypeId there); + void unionClasses(NormalizedClassType& heres, const NormalizedClassType& theres); void unionStrings(NormalizedStringType& here, const NormalizedStringType& there); std::optional unionOfTypePacks(TypePackId here, TypePackId there); std::optional unionOfFunctions(TypeId here, TypeId there); @@ -304,8 +334,10 @@ public: // ------- Normalizing intersections TypeId intersectionOfTops(TypeId here, TypeId there); TypeId intersectionOfBools(TypeId here, TypeId there); - void intersectClasses(TypeIds& heres, const TypeIds& theres); - void intersectClassesWithClass(TypeIds& heres, TypeId there); + void DEPRECATED_intersectClasses(TypeIds& heres, const TypeIds& theres); + void DEPRECATED_intersectClassesWithClass(TypeIds& heres, TypeId there); + void intersectClasses(NormalizedClassType& heres, const NormalizedClassType& theres); + void intersectClassesWithClass(NormalizedClassType& heres, TypeId there); void intersectStrings(NormalizedStringType& here, const NormalizedStringType& there); std::optional intersectionOfTypePacks(TypePackId here, TypePackId there); std::optional intersectionOfTables(TypeId here, TypeId there); diff --git a/Analysis/include/Luau/Predicate.h b/Analysis/include/Luau/Predicate.h index df93b4f4..8d486ad5 100644 --- a/Analysis/include/Luau/Predicate.h +++ b/Analysis/include/Luau/Predicate.h @@ -10,8 +10,8 @@ namespace Luau { -struct TypeVar; -using TypeId = const TypeVar*; +struct Type; +using TypeId = const Type*; struct TruthyPredicate; struct IsAPredicate; diff --git a/Analysis/include/Luau/Quantify.h b/Analysis/include/Luau/Quantify.h index 7edf23b8..b350fab5 100644 --- a/Analysis/include/Luau/Quantify.h +++ b/Analysis/include/Luau/Quantify.h @@ -1,7 +1,7 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once -#include "Luau/TypeVar.h" +#include "Luau/Type.h" namespace Luau { diff --git a/Analysis/include/Luau/Scope.h b/Analysis/include/Luau/Scope.h index 851ed1a7..797c9cb0 100644 --- a/Analysis/include/Luau/Scope.h +++ b/Analysis/include/Luau/Scope.h @@ -3,7 +3,7 @@ #include "Luau/Location.h" #include "Luau/NotNull.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include #include diff --git a/Analysis/include/Luau/Substitution.h b/Analysis/include/Luau/Substitution.h index 6ad38f9d..2efca2df 100644 --- a/Analysis/include/Luau/Substitution.h +++ b/Analysis/include/Luau/Substitution.h @@ -3,7 +3,7 @@ #include "Luau/TypeArena.h" #include "Luau/TypePack.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/DenseHash.h" // We provide an implementation of substitution on types, diff --git a/Analysis/include/Luau/ToDot.h b/Analysis/include/Luau/ToDot.h index ce518d3a..1a9c2811 100644 --- a/Analysis/include/Luau/ToDot.h +++ b/Analysis/include/Luau/ToDot.h @@ -7,8 +7,8 @@ namespace Luau { -struct TypeVar; -using TypeId = const TypeVar*; +struct Type; +using TypeId = const Type*; struct TypePackVar; using TypePackId = const TypePackVar*; diff --git a/Analysis/include/Luau/ToString.h b/Analysis/include/Luau/ToString.h index 71c0e359..dd8aef57 100644 --- a/Analysis/include/Luau/ToString.h +++ b/Analysis/include/Luau/ToString.h @@ -19,13 +19,13 @@ class AstExpr; struct Scope; -struct TypeVar; -using TypeId = const TypeVar*; +struct Type; +using TypeId = const Type*; struct TypePackVar; using TypePackId = const TypePackVar*; -struct FunctionTypeVar; +struct FunctionType; struct Constraint; struct Position; @@ -33,7 +33,7 @@ struct Location; struct ToStringNameMap { - std::unordered_map typeVars; + std::unordered_map types; std::unordered_map typePacks; }; @@ -46,7 +46,7 @@ struct ToStringOptions bool hideNamedFunctionTypeParameters = false; // If true, type parameters of functions will be hidden at top-level. bool hideFunctionSelfArgument = false; // If true, `self: X` will be omitted from the function signature if the function has self bool DEPRECATED_indent = false; // TODO Deprecated field, prune when clipping flag FFlagLuauLineBreaksDeterminIndents - size_t maxTableLength = size_t(FInt::LuauTableTypeMaximumStringifierLength); // Only applied to TableTypeVars + size_t maxTableLength = size_t(FInt::LuauTableTypeMaximumStringifierLength); // Only applied to TableTypes size_t maxTypeLength = size_t(FInt::LuauTypeMaximumStringifierLength); ToStringNameMap nameMap; std::shared_ptr scope; // If present, module names will be added and types that are not available in scope will be marked as 'invalid' @@ -105,10 +105,10 @@ inline std::string toString(const Constraint& c) return toString(c, ToStringOptions{}); } -std::string toString(const TypeVar& tv, ToStringOptions& opts); +std::string toString(const Type& tv, ToStringOptions& opts); std::string toString(const TypePackVar& tp, ToStringOptions& opts); -inline std::string toString(const TypeVar& tv) +inline std::string toString(const Type& tv) { ToStringOptions opts; return toString(tv, opts); @@ -120,9 +120,9 @@ inline std::string toString(const TypePackVar& tp) return toString(tp, opts); } -std::string toStringNamedFunction(const std::string& funcName, const FunctionTypeVar& ftv, ToStringOptions& opts); +std::string toStringNamedFunction(const std::string& funcName, const FunctionType& ftv, ToStringOptions& opts); -inline std::string toStringNamedFunction(const std::string& funcName, const FunctionTypeVar& ftv) +inline std::string toStringNamedFunction(const std::string& funcName, const FunctionType& ftv) { ToStringOptions opts; return toStringNamedFunction(funcName, ftv, opts); diff --git a/Analysis/include/Luau/TxnLog.h b/Analysis/include/Luau/TxnLog.h index 82605bff..0ed8a49a 100644 --- a/Analysis/include/Luau/TxnLog.h +++ b/Analysis/include/Luau/TxnLog.h @@ -1,7 +1,7 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/TypePack.h" #include @@ -12,14 +12,14 @@ namespace Luau using TypeOrPackId = const void*; -// Pending state for a TypeVar. Generated by a TxnLog and committed via +// Pending state for a Type. Generated by a TxnLog and committed via // TxnLog::commit. struct PendingType { - // The pending TypeVar state. - TypeVar pending; + // The pending Type state. + Type pending; - explicit PendingType(TypeVar state) + explicit PendingType(Type state) : pending(std::move(state)) { } @@ -163,7 +163,7 @@ struct TxnLog // Queues a replacement of a type with another type. // // The pointer returned lives until `commit` or `clear` is called. - PendingType* replace(TypeId ty, TypeVar replacement); + PendingType* replace(TypeId ty, Type replacement); // Queues a replacement of a type pack with another type pack. // @@ -225,7 +225,7 @@ struct TxnLog template PendingType* replace(TypeId ty, T replacement) { - return replace(ty, TypeVar(replacement)); + return replace(ty, Type(replacement)); } // Replaces a given type pack's state with a new variant. Returns the new @@ -262,12 +262,12 @@ struct TxnLog // Returns whether a given type or type pack is a given state, respecting the // log's pending state. // - // This method will not assert if called on a BoundTypeVar or BoundTypePack. + // This method will not assert if called on a BoundType or BoundTypePack. template bool is(TID ty) const { // We do not use getMutable here because this method can be called on - // BoundTypeVars, which triggers an assertion. + // BoundTypes, which triggers an assertion. auto* pendingTy = pending(ty); if (pendingTy) return Luau::get_if(&pendingTy->pending.ty) != nullptr; diff --git a/Analysis/include/Luau/TypeVar.h b/Analysis/include/Luau/Type.h similarity index 77% rename from Analysis/include/Luau/TypeVar.h rename to Analysis/include/Luau/Type.h index 852a4054..fcc073d8 100644 --- a/Analysis/include/Luau/TypeVar.h +++ b/Analysis/include/Luau/Type.h @@ -69,46 +69,45 @@ using ScopePtr = std::shared_ptr; struct TypePackVar; using TypePackId = const TypePackVar*; -// TODO: rename to Type? CLI-39100 -struct TypeVar; +struct Type; // Should never be null -using TypeId = const TypeVar*; +using TypeId = const Type*; using Name = std::string; // A free type var is one whose exact shape has yet to be fully determined. -using FreeTypeVar = Unifiable::Free; +using FreeType = Unifiable::Free; // When a free type var is unified with any other, it is then "bound" // to that type var, indicating that the two types are actually the same type. -using BoundTypeVar = Unifiable::Bound; +using BoundType = Unifiable::Bound; -using GenericTypeVar = Unifiable::Generic; +using GenericType = Unifiable::Generic; using Tags = std::vector; using ModuleName = std::string; -/** A TypeVar that cannot be computed. +/** A Type that cannot be computed. * - * BlockedTypeVars essentially serve as a way to encode partial ordering on the - * constraint graph. Until a BlockedTypeVar is unblocked by its owning + * BlockedTypes essentially serve as a way to encode partial ordering on the + * constraint graph. Until a BlockedType is unblocked by its owning * constraint, nothing at all can be said about it. Constraints that need to - * process a BlockedTypeVar cannot be dispatched. + * process a BlockedType cannot be dispatched. * - * Whenever a BlockedTypeVar is added to the graph, we also record a constraint + * Whenever a BlockedType is added to the graph, we also record a constraint * that will eventually unblock it. */ -struct BlockedTypeVar +struct BlockedType { - BlockedTypeVar(); + BlockedType(); int index; static int nextIndex; }; -struct PrimitiveTypeVar +struct PrimitiveType { enum Type { @@ -123,12 +122,12 @@ struct PrimitiveTypeVar Type type; std::optional metatable; // string has a metatable - explicit PrimitiveTypeVar(Type type) + explicit PrimitiveType(Type type) : type(type) { } - explicit PrimitiveTypeVar(Type type, TypeId metatable) + explicit PrimitiveType(Type type, TypeId metatable) : type(type) , metatable(metatable) { @@ -173,25 +172,25 @@ struct StringSingleton using SingletonVariant = Luau::Variant; -struct SingletonTypeVar +struct SingletonType { - explicit SingletonTypeVar(const SingletonVariant& variant) + explicit SingletonType(const SingletonVariant& variant) : variant(variant) { } - explicit SingletonTypeVar(SingletonVariant&& variant) + explicit SingletonType(SingletonVariant&& variant) : variant(std::move(variant)) { } // Default operator== is C++20. - bool operator==(const SingletonTypeVar& rhs) const + bool operator==(const SingletonType& rhs) const { return variant == rhs.variant; } - bool operator!=(const SingletonTypeVar& rhs) const + bool operator!=(const SingletonType& rhs) const { return !(*this == rhs); } @@ -200,7 +199,7 @@ struct SingletonTypeVar }; template -const T* get(const SingletonTypeVar* stv) +const T* get(const SingletonType* stv) { if (stv) return get_if(&stv->variant); @@ -240,7 +239,7 @@ struct FunctionDefinition // TODO: Come up with a better name. // TODO: Do we actually need this? We'll find out later if we can delete this. -// Does not exactly belong in TypeVar.h, but this is the only way to appease the compiler. +// Does not exactly belong in Type.h, but this is the only way to appease the compiler. template struct WithPredicate { @@ -273,24 +272,24 @@ struct MagicRefinementContext using DcrMagicRefinement = std::vector (*)(const MagicRefinementContext&); -struct FunctionTypeVar +struct FunctionType { // Global monomorphic function - FunctionTypeVar(TypePackId argTypes, TypePackId retTypes, std::optional defn = {}, bool hasSelf = false); + FunctionType(TypePackId argTypes, TypePackId retTypes, std::optional defn = {}, bool hasSelf = false); // Global polymorphic function - FunctionTypeVar(std::vector generics, std::vector genericPacks, TypePackId argTypes, TypePackId retTypes, + FunctionType(std::vector generics, std::vector genericPacks, TypePackId argTypes, TypePackId retTypes, std::optional defn = {}, bool hasSelf = false); // Local monomorphic function - FunctionTypeVar(TypeLevel level, TypePackId argTypes, TypePackId retTypes, std::optional defn = {}, bool hasSelf = false); - FunctionTypeVar( + FunctionType(TypeLevel level, TypePackId argTypes, TypePackId retTypes, std::optional defn = {}, bool hasSelf = false); + FunctionType( TypeLevel level, Scope* scope, TypePackId argTypes, TypePackId retTypes, std::optional defn = {}, bool hasSelf = false); // Local polymorphic function - FunctionTypeVar(TypeLevel level, std::vector generics, std::vector genericPacks, TypePackId argTypes, TypePackId retTypes, + FunctionType(TypeLevel level, std::vector generics, std::vector genericPacks, TypePackId argTypes, TypePackId retTypes, std::optional defn = {}, bool hasSelf = false); - FunctionTypeVar(TypeLevel level, Scope* scope, std::vector generics, std::vector genericPacks, TypePackId argTypes, + FunctionType(TypeLevel level, Scope* scope, std::vector generics, std::vector genericPacks, TypePackId argTypes, TypePackId retTypes, std::optional defn = {}, bool hasSelf = false); std::optional definition; @@ -348,7 +347,7 @@ struct Property std::optional documentationSymbol; }; -struct TableTypeVar +struct TableType { // We choose std::map over unordered_map here just because we have unit tests that compare // textual outputs. I don't want to spend the effort making them resilient in the case where @@ -356,10 +355,10 @@ struct TableTypeVar // If this shows up in a profile, we can revisit it. using Props = std::map; - TableTypeVar() = default; - explicit TableTypeVar(TableState state, TypeLevel level, Scope* scope = nullptr); - TableTypeVar(const Props& props, const std::optional& indexer, TypeLevel level, TableState state); - TableTypeVar(const Props& props, const std::optional& indexer, TypeLevel level, Scope* scope, TableState state); + TableType() = default; + explicit TableType(TableState state, TypeLevel level, Scope* scope = nullptr); + TableType(const Props& props, const std::optional& indexer, TypeLevel level, TableState state); + TableType(const Props& props, const std::optional& indexer, TypeLevel level, Scope* scope, TableState state); Props props; std::optional indexer; @@ -384,12 +383,12 @@ struct TableTypeVar std::optional selfTy; }; -// Represents a metatable attached to a table typevar. Somewhat analogous to a bound typevar. -struct MetatableTypeVar +// Represents a metatable attached to a table type. Somewhat analogous to a bound type. +struct MetatableType { - // Always points to a TableTypeVar. + // Always points to a TableType. TypeId table; - // Always points to either a TableTypeVar or a MetatableTypeVar. + // Always points to either a TableType or a MetatableType. TypeId metatable; std::optional syntheticName; @@ -409,9 +408,9 @@ struct ClassUserData * Classes optionally have a parent class. * Two different classes that share the same properties are nevertheless distinct and mutually incompatible. */ -struct ClassTypeVar +struct ClassType { - using Props = TableTypeVar::Props; + using Props = TableType::Props; Name name; Props props; @@ -421,7 +420,7 @@ struct ClassTypeVar std::shared_ptr userData; ModuleName definitionModuleName; - ClassTypeVar(Name name, Props props, std::optional parent, std::optional metatable, Tags tags, + ClassType(Name name, Props props, std::optional parent, std::optional metatable, Tags tags, std::shared_ptr userData, ModuleName definitionModuleName) : name(name) , props(props) @@ -474,13 +473,13 @@ struct TypeFun * * In order to afford (co)recursive type aliases, we need to reason about a * partially-complete instantiation. This requires encoding more information in - * a type variable than a BlockedTypeVar affords, hence this. Each - * PendingExpansionTypeVar has a corresponding TypeAliasExpansionConstraint + * a type variable than a BlockedType affords, hence this. Each + * PendingExpansionType has a corresponding TypeAliasExpansionConstraint * enqueued in the solver to convert it to an actual instantiated type */ -struct PendingExpansionTypeVar +struct PendingExpansionType { - PendingExpansionTypeVar(std::optional prefix, AstName name, std::vector typeArguments, std::vector packArguments); + PendingExpansionType(std::optional prefix, AstName name, std::vector typeArguments, std::vector packArguments); std::optional prefix; AstName name; std::vector typeArguments; @@ -491,69 +490,68 @@ struct PendingExpansionTypeVar }; // Anything! All static checking is off. -struct AnyTypeVar +struct AnyType { }; // T | U -struct UnionTypeVar +struct UnionType { std::vector options; }; // T & U -struct IntersectionTypeVar +struct IntersectionType { std::vector parts; }; -struct LazyTypeVar +struct LazyType { std::function thunk; }; -struct UnknownTypeVar +struct UnknownType { }; -struct NeverTypeVar +struct NeverType { }; // ~T // TODO: Some simplification step that overwrites the type graph to make sure negation // types disappear from the user's view, and (?) a debug flag to disable that -struct NegationTypeVar +struct NegationType { TypeId ty; }; -using ErrorTypeVar = Unifiable::Error; +using ErrorType = Unifiable::Error; -using TypeVariant = - Unifiable::Variant; +using TypeVariant = Unifiable::Variant; -struct TypeVar final +struct Type final { - explicit TypeVar(const TypeVariant& ty) + explicit Type(const TypeVariant& ty) : ty(ty) { } - explicit TypeVar(TypeVariant&& ty) + explicit Type(TypeVariant&& ty) : ty(std::move(ty)) { } - TypeVar(const TypeVariant& ty, bool persistent) + Type(const TypeVariant& ty, bool persistent) : ty(ty) , persistent(persistent) { } // Re-assignes the content of the type, but doesn't change the owning arena and can't make type persistent. - void reassign(const TypeVar& rhs) + void reassign(const Type& rhs) { ty = rhs.ty; documentationSymbol = rhs.documentationSymbol; @@ -561,9 +559,9 @@ struct TypeVar final TypeVariant ty; - // Kludge: A persistent TypeVar is one that belongs to the global scope. + // Kludge: A persistent Type is one that belongs to the global scope. // Global type bindings are immutable but are reused many times. - // Persistent TypeVars do not get cloned. + // Persistent Types do not get cloned. bool persistent = false; std::optional documentationSymbol; @@ -571,25 +569,25 @@ struct TypeVar final // Pointer to the type arena that allocated this type. TypeArena* owningArena = nullptr; - bool operator==(const TypeVar& rhs) const; - bool operator!=(const TypeVar& rhs) const; + bool operator==(const Type& rhs) const; + bool operator!=(const Type& rhs) const; - TypeVar& operator=(const TypeVariant& rhs); - TypeVar& operator=(TypeVariant&& rhs); + Type& operator=(const TypeVariant& rhs); + Type& operator=(TypeVariant&& rhs); - TypeVar& operator=(const TypeVar& rhs); + Type& operator=(const Type& rhs); }; using SeenSet = std::set>; -bool areEqual(SeenSet& seen, const TypeVar& lhs, const TypeVar& rhs); +bool areEqual(SeenSet& seen, const Type& lhs, const Type& rhs); -// Follow BoundTypeVars until we get to something real +// Follow BoundTypes until we get to something real TypeId follow(TypeId t); TypeId follow(TypeId t, std::function mapper); std::vector flattenIntersection(TypeId ty); -bool isPrim(TypeId ty, PrimitiveTypeVar::Type primType); +bool isPrim(TypeId ty, PrimitiveType::Type primType); bool isNil(TypeId ty); bool isBoolean(TypeId ty); bool isNumber(TypeId ty); @@ -602,9 +600,9 @@ bool isOverloadedFunction(TypeId ty); // True when string is a subtype of ty bool maybeString(TypeId ty); -std::optional getMetatable(TypeId type, NotNull singletonTypes); -TableTypeVar* getMutableTableType(TypeId type); -const TableTypeVar* getTableType(TypeId type); +std::optional getMetatable(TypeId type, NotNull builtinTypes); +TableType* getMutableTableType(TypeId type); +const TableType* getTableType(TypeId type); // If the type has a name, return that. Else if it has a synthetic name, return that. // Returns nullptr if the type has no name. @@ -614,7 +612,7 @@ const std::string* getName(TypeId type); std::optional getDefinitionModuleName(TypeId type); // Checks whether a union contains all types of another union. -bool isSubset(const UnionTypeVar& super, const UnionTypeVar& sub); +bool isSubset(const UnionType& super, const UnionType& sub); // Checks if a type contains generic type binders bool isGeneric(const TypeId ty); @@ -628,12 +626,12 @@ bool maybeSingleton(TypeId ty); // Checks if the length operator can be applied on the value of type bool hasLength(TypeId ty, DenseHashSet& seen, int* recursionCount); -struct SingletonTypes +struct BuiltinTypes { - SingletonTypes(); - ~SingletonTypes(); - SingletonTypes(const SingletonTypes&) = delete; - void operator=(const SingletonTypes&) = delete; + BuiltinTypes(); + ~BuiltinTypes(); + BuiltinTypes(const BuiltinTypes&) = delete; + void operator=(const BuiltinTypes&) = delete; TypeId errorRecoveryType(TypeId guess); TypePackId errorRecoveryTypePack(TypePackId guess); @@ -653,6 +651,7 @@ public: const TypeId booleanType; const TypeId threadType; const TypeId functionType; + const TypeId classType; const TypeId trueType; const TypeId falseType; const TypeId anyType; @@ -676,18 +675,18 @@ TypeLevel* getMutableLevel(TypeId ty); std::optional getLevel(TypePackId tp); -const Property* lookupClassProp(const ClassTypeVar* cls, const Name& name); -bool isSubclass(const ClassTypeVar* cls, const ClassTypeVar* parent); +const Property* lookupClassProp(const ClassType* cls, const Name& name); +bool isSubclass(const ClassType* cls, const ClassType* parent); -TypeVar* asMutable(TypeId ty); +Type* asMutable(TypeId ty); template const T* get(TypeId tv) { LUAU_ASSERT(tv); - if constexpr (!std::is_same_v) - LUAU_ASSERT(get_if(&tv->ty) == nullptr); + if constexpr (!std::is_same_v) + LUAU_ASSERT(get_if(&tv->ty) == nullptr); return get_if(&tv->ty); } @@ -697,25 +696,25 @@ T* getMutable(TypeId tv) { LUAU_ASSERT(tv); - if constexpr (!std::is_same_v) - LUAU_ASSERT(get_if(&tv->ty) == nullptr); + if constexpr (!std::is_same_v) + LUAU_ASSERT(get_if(&tv->ty) == nullptr); return get_if(&asMutable(tv)->ty); } -const std::vector& getTypes(const UnionTypeVar* utv); -const std::vector& getTypes(const IntersectionTypeVar* itv); +const std::vector& getTypes(const UnionType* utv); +const std::vector& getTypes(const IntersectionType* itv); template struct TypeIterator; -using UnionTypeVarIterator = TypeIterator; -UnionTypeVarIterator begin(const UnionTypeVar* utv); -UnionTypeVarIterator end(const UnionTypeVar* utv); +using UnionTypeIterator = TypeIterator; +UnionTypeIterator begin(const UnionType* utv); +UnionTypeIterator end(const UnionType* utv); -using IntersectionTypeVarIterator = TypeIterator; -IntersectionTypeVarIterator begin(const IntersectionTypeVar* itv); -IntersectionTypeVarIterator end(const IntersectionTypeVar* itv); +using IntersectionTypeIterator = TypeIterator; +IntersectionTypeIterator begin(const IntersectionType* itv); +IntersectionTypeIterator end(const IntersectionType* itv); /* Traverses the type T yielding each TypeId. * If the iterator encounters a nested type T, it will instead yield each TypeId within. @@ -788,8 +787,8 @@ struct TypeIterator // Normally, we'd have `begin` and `end` be a template but there's too much trouble // with templates portability in this area, so not worth it. Thanks MSVC. - friend UnionTypeVarIterator end(const UnionTypeVar*); - friend IntersectionTypeVarIterator end(const IntersectionTypeVar*); + friend UnionTypeIterator end(const UnionType*); + friend IntersectionTypeIterator end(const IntersectionType*); private: TypeIterator() = default; diff --git a/Analysis/include/Luau/TypeArena.h b/Analysis/include/Luau/TypeArena.h index c67f643b..0e69bb4a 100644 --- a/Analysis/include/Luau/TypeArena.h +++ b/Analysis/include/Luau/TypeArena.h @@ -2,7 +2,7 @@ #pragma once #include "Luau/TypedAllocator.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/TypePack.h" #include @@ -12,7 +12,7 @@ namespace Luau struct TypeArena { - TypedAllocator typeVars; + TypedAllocator types; TypedAllocator typePacks; void clear(); @@ -20,13 +20,13 @@ struct TypeArena template TypeId addType(T tv) { - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) LUAU_ASSERT(tv.options.size() >= 2); - return addTV(TypeVar(std::move(tv))); + return addTV(Type(std::move(tv))); } - TypeId addTV(TypeVar&& tv); + TypeId addTV(Type&& tv); TypeId freshType(TypeLevel level); TypeId freshType(Scope* scope); diff --git a/Analysis/include/Luau/TypeChecker2.h b/Analysis/include/Luau/TypeChecker2.h index a9cd6ec8..6045aecf 100644 --- a/Analysis/include/Luau/TypeChecker2.h +++ b/Analysis/include/Luau/TypeChecker2.h @@ -10,8 +10,8 @@ namespace Luau { struct DcrLogger; -struct SingletonTypes; +struct BuiltinTypes; -void check(NotNull singletonTypes, DcrLogger* logger, const SourceModule& sourceModule, Module* module); +void check(NotNull builtinTypes, DcrLogger* logger, const SourceModule& sourceModule, Module* module); } // namespace Luau diff --git a/Analysis/include/Luau/TypeInfer.h b/Analysis/include/Luau/TypeInfer.h index c6f153d1..4c2d38ad 100644 --- a/Analysis/include/Luau/TypeInfer.h +++ b/Analysis/include/Luau/TypeInfer.h @@ -9,7 +9,7 @@ #include "Luau/Substitution.h" #include "Luau/TxnLog.h" #include "Luau/TypePack.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/Unifier.h" #include "Luau/UnifierSharedState.h" @@ -28,7 +28,7 @@ struct ModuleResolver; using Name = std::string; using ScopePtr = std::shared_ptr; -using OverloadErrorEntry = std::tuple, std::vector, const FunctionTypeVar*>; +using OverloadErrorEntry = std::tuple, std::vector, const FunctionType*>; bool doesCallError(const AstExprCall* call); bool hasBreak(AstStat* node); @@ -57,11 +57,11 @@ public: } }; -// All TypeVars are retained via Environment::typeVars. All TypeIds +// All Types are retained via Environment::types. All TypeIds // within a program are borrowed pointers into this set. struct TypeChecker { - explicit TypeChecker(ModuleResolver* resolver, NotNull singletonTypes, InternalErrorReporter* iceHandler); + explicit TypeChecker(ModuleResolver* resolver, NotNull builtinTypes, InternalErrorReporter* iceHandler); TypeChecker(const TypeChecker&) = delete; TypeChecker& operator=(const TypeChecker&) = delete; @@ -163,7 +163,7 @@ struct TypeChecker // Reports an error if the type is already some kind of non-table. void tablify(TypeId type); - /** In nonstrict mode, many typevars need to be replaced by any. + /** In nonstrict mode, many types need to be replaced by any. */ TypeId anyIfNonstrict(TypeId ty) const; @@ -287,14 +287,14 @@ private: TypeId unionOfTypes(TypeId a, TypeId b, const ScopePtr& scope, const Location& location, bool unifyFreeTypes = true); // ex - // TypeId id = addType(FreeTypeVar()); + // TypeId id = addType(FreeType()); template TypeId addType(const T& tv) { - return addTV(TypeVar(tv)); + return addTV(Type(tv)); } - TypeId addTV(TypeVar&& tv); + TypeId addTV(Type&& tv); TypePackId addTypePack(TypePackVar&& tp); TypePackId addTypePack(TypePack&& tp); @@ -343,7 +343,7 @@ public: * Calling this function means submitting evidence that the pack must have the length provided. * If the pack is known not to have the correct length, an error will be reported. * The return vector is always of the exact requested length. In the event that the pack's length does - * not match up, excess TypeIds will be ErrorTypeVars. + * not match up, excess TypeIds will be ErrorTypes. */ std::vector unTypePack(const ScopePtr& scope, TypePackId pack, size_t expectedLength, const Location& location); @@ -356,7 +356,7 @@ public: ModuleName currentModuleName; std::function prepareModuleScope; - NotNull singletonTypes; + NotNull builtinTypes; InternalErrorReporter* iceHandler; UnifierSharedState unifierState; diff --git a/Analysis/include/Luau/TypePack.h b/Analysis/include/Luau/TypePack.h index 29688094..4831f233 100644 --- a/Analysis/include/Luau/TypePack.h +++ b/Analysis/include/Luau/TypePack.h @@ -1,7 +1,7 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/Unifiable.h" #include "Luau/Variant.h" @@ -45,7 +45,7 @@ struct VariadicTypePack }; /** - * Analogous to a BlockedTypeVar. + * Analogous to a BlockedType. */ struct BlockedTypePack { @@ -83,7 +83,7 @@ struct TypePackVar /* Walk the set of TypeIds in a TypePack. * - * Like TypeVars, individual TypePacks can be free, generic, or any. + * Like Types, individual TypePacks can be free, generic, or any. * * We afford the ability to work with these kinds of packs by giving the * iterator a .tail() property that yields the tail-most TypePack in the diff --git a/Analysis/include/Luau/TypeUtils.h b/Analysis/include/Luau/TypeUtils.h index 6ed70f46..3f535a03 100644 --- a/Analysis/include/Luau/TypeUtils.h +++ b/Analysis/include/Luau/TypeUtils.h @@ -3,7 +3,7 @@ #include "Luau/Error.h" #include "Luau/Location.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/TypePack.h" #include @@ -18,16 +18,16 @@ struct TypeArena; using ScopePtr = std::shared_ptr; std::optional findMetatableEntry( - NotNull singletonTypes, ErrorVec& errors, TypeId type, const std::string& entry, Location location); + NotNull builtinTypes, ErrorVec& errors, TypeId type, const std::string& entry, Location location); std::optional findTablePropertyRespectingMeta( - NotNull singletonTypes, ErrorVec& errors, TypeId ty, const std::string& name, Location location); + NotNull builtinTypes, ErrorVec& errors, TypeId ty, const std::string& name, Location location); // 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 singletonTypes, TypePackId pack, size_t length); +TypePack extendTypePack(TypeArena& arena, NotNull builtinTypes, TypePackId pack, size_t length); /** * Reduces a union by decomposing to the any/error type if it appears in the @@ -41,11 +41,11 @@ 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 singletonTypes the singleton types to use + * @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 singletonTypes, TypeArena& arena, TypeId ty); +TypeId stripNil(NotNull builtinTypes, TypeArena& arena, TypeId ty); } // namespace Luau diff --git a/Analysis/include/Luau/Unifiable.h b/Analysis/include/Luau/Unifiable.h index c43daa21..15e501f0 100644 --- a/Analysis/include/Luau/Unifiable.h +++ b/Analysis/include/Luau/Unifiable.h @@ -11,7 +11,7 @@ namespace Luau struct Scope; /** - * The 'level' of a TypeVar is an indirect way to talk about the scope that it 'belongs' too. + * The 'level' of a Type is an indirect way to talk about the scope that it 'belongs' too. * To start, read http://okmij.org/ftp/ML/generalization.html * * We extend the idea by adding a "sub-level" which helps us to differentiate sibling scopes @@ -132,7 +132,7 @@ private: struct Error { - // This constructor has to be public, since it's used in TypeVar and TypePack, + // This constructor has to be public, since it's used in Type and TypePack, // but shouldn't be called directly. Please use errorRecoveryType() instead. Error(); diff --git a/Analysis/include/Luau/Unifier.h b/Analysis/include/Luau/Unifier.h index af3864ea..cd3e856d 100644 --- a/Analysis/include/Luau/Unifier.h +++ b/Analysis/include/Luau/Unifier.h @@ -25,13 +25,13 @@ enum Variance // A substitution which replaces singleton types by their wider types struct Widen : Substitution { - Widen(TypeArena* arena, NotNull singletonTypes) + Widen(TypeArena* arena, NotNull builtinTypes) : Substitution(TxnLog::empty(), arena) - , singletonTypes(singletonTypes) + , builtinTypes(builtinTypes) { } - NotNull singletonTypes; + NotNull builtinTypes; bool isDirty(TypeId ty) override; bool isDirty(TypePackId ty) override; @@ -52,7 +52,7 @@ struct UnifierOptions struct Unifier { TypeArena* const types; - NotNull singletonTypes; + NotNull builtinTypes; NotNull normalizer; Mode mode; @@ -82,10 +82,10 @@ struct Unifier private: void tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall = false, bool isIntersection = false); - void tryUnifyUnionWithType(TypeId subTy, const UnionTypeVar* uv, TypeId superTy); - void tryUnifyTypeWithUnion(TypeId subTy, TypeId superTy, const UnionTypeVar* uv, bool cacheEnabled, bool isFunctionCall); - void tryUnifyTypeWithIntersection(TypeId subTy, TypeId superTy, const IntersectionTypeVar* uv); - void tryUnifyIntersectionWithType(TypeId subTy, const IntersectionTypeVar* uv, TypeId superTy, bool cacheEnabled, bool isFunctionCall); + void tryUnifyUnionWithType(TypeId subTy, const UnionType* uv, TypeId superTy); + void tryUnifyTypeWithUnion(TypeId subTy, TypeId superTy, const UnionType* uv, bool cacheEnabled, bool isFunctionCall); + void tryUnifyTypeWithIntersection(TypeId subTy, TypeId superTy, const IntersectionType* uv); + void tryUnifyIntersectionWithType(TypeId subTy, const IntersectionType* uv, TypeId superTy, bool cacheEnabled, bool isFunctionCall); void tryUnifyNormalizedTypes(TypeId subTy, TypeId superTy, const NormalizedType& subNorm, const NormalizedType& superNorm, std::string reason, std::optional error = std::nullopt); void tryUnifyPrimitives(TypeId subTy, TypeId superTy); diff --git a/Analysis/include/Luau/UnifierSharedState.h b/Analysis/include/Luau/UnifierSharedState.h index d4315d47..ada56ec5 100644 --- a/Analysis/include/Luau/UnifierSharedState.h +++ b/Analysis/include/Luau/UnifierSharedState.h @@ -3,7 +3,7 @@ #include "Luau/DenseHash.h" #include "Luau/Error.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/TypePack.h" #include diff --git a/Analysis/include/Luau/VisitTypeVar.h b/Analysis/include/Luau/VisitType.h similarity index 70% rename from Analysis/include/Luau/VisitTypeVar.h rename to Analysis/include/Luau/VisitType.h index 3dcddba1..fdac6585 100644 --- a/Analysis/include/Luau/VisitTypeVar.h +++ b/Analysis/include/Luau/VisitType.h @@ -6,7 +6,7 @@ #include "Luau/DenseHash.h" #include "Luau/RecursionCounter.h" #include "Luau/TypePack.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" LUAU_FASTINT(LuauVisitRecursionLimit) LUAU_FASTFLAG(LuauCompleteVisitor); @@ -19,7 +19,7 @@ namespace visit_detail /** * Apply f(tid, t, seen) if doing so would pass type checking, else apply f(tid, t) * - * We do this to permit (but not require) TypeVar visitors to accept the seen set as an argument. + * We do this to permit (but not require) Type visitors to accept the seen set as an argument. */ template auto apply(A tid, const B& t, C& c, F& f) -> decltype(f(tid, t, c)) @@ -58,13 +58,13 @@ inline void unsee(std::unordered_set& seen, const void* tv) inline void unsee(DenseHashSet& seen, const void* tv) { - // When DenseHashSet is used for 'visitTypeVarOnce', where don't forget visited elements + // When DenseHashSet is used for 'visitTypeOnce', where don't forget visited elements } } // namespace visit_detail template -struct GenericTypeVarVisitor +struct GenericTypeVisitor { using Set = S; @@ -72,9 +72,9 @@ struct GenericTypeVarVisitor bool skipBoundTypes = false; int recursionCounter = 0; - GenericTypeVarVisitor() = default; + GenericTypeVisitor() = default; - explicit GenericTypeVarVisitor(Set seen, bool skipBoundTypes = false) + explicit GenericTypeVisitor(Set seen, bool skipBoundTypes = false) : seen(std::move(seen)) , skipBoundTypes(skipBoundTypes) { @@ -87,75 +87,75 @@ struct GenericTypeVarVisitor { return true; } - virtual bool visit(TypeId ty, const BoundTypeVar& btv) + virtual bool visit(TypeId ty, const BoundType& btv) { return visit(ty); } - virtual bool visit(TypeId ty, const FreeTypeVar& ftv) + virtual bool visit(TypeId ty, const FreeType& ftv) { return visit(ty); } - virtual bool visit(TypeId ty, const GenericTypeVar& gtv) + virtual bool visit(TypeId ty, const GenericType& gtv) { return visit(ty); } - virtual bool visit(TypeId ty, const ErrorTypeVar& etv) + virtual bool visit(TypeId ty, const ErrorType& etv) { return visit(ty); } - virtual bool visit(TypeId ty, const PrimitiveTypeVar& ptv) + virtual bool visit(TypeId ty, const PrimitiveType& ptv) { return visit(ty); } - virtual bool visit(TypeId ty, const FunctionTypeVar& ftv) + virtual bool visit(TypeId ty, const FunctionType& ftv) { return visit(ty); } - virtual bool visit(TypeId ty, const TableTypeVar& ttv) + virtual bool visit(TypeId ty, const TableType& ttv) { return visit(ty); } - virtual bool visit(TypeId ty, const MetatableTypeVar& mtv) + virtual bool visit(TypeId ty, const MetatableType& mtv) { return visit(ty); } - virtual bool visit(TypeId ty, const ClassTypeVar& ctv) + virtual bool visit(TypeId ty, const ClassType& ctv) { return visit(ty); } - virtual bool visit(TypeId ty, const AnyTypeVar& atv) + virtual bool visit(TypeId ty, const AnyType& atv) { return visit(ty); } - virtual bool visit(TypeId ty, const UnknownTypeVar& utv) + virtual bool visit(TypeId ty, const UnknownType& utv) { return visit(ty); } - virtual bool visit(TypeId ty, const NeverTypeVar& ntv) + virtual bool visit(TypeId ty, const NeverType& ntv) { return visit(ty); } - virtual bool visit(TypeId ty, const UnionTypeVar& utv) + virtual bool visit(TypeId ty, const UnionType& utv) { return visit(ty); } - virtual bool visit(TypeId ty, const IntersectionTypeVar& itv) + virtual bool visit(TypeId ty, const IntersectionType& itv) { return visit(ty); } - virtual bool visit(TypeId ty, const BlockedTypeVar& btv) + virtual bool visit(TypeId ty, const BlockedType& btv) { return visit(ty); } - virtual bool visit(TypeId ty, const PendingExpansionTypeVar& petv) + virtual bool visit(TypeId ty, const PendingExpansionType& petv) { return visit(ty); } - virtual bool visit(TypeId ty, const SingletonTypeVar& stv) + virtual bool visit(TypeId ty, const SingletonType& stv) { return visit(ty); } - virtual bool visit(TypeId ty, const NegationTypeVar& ntv) + virtual bool visit(TypeId ty, const NegationType& ntv) { return visit(ty); } @@ -203,22 +203,22 @@ struct GenericTypeVarVisitor return; } - if (auto btv = get(ty)) + if (auto btv = get(ty)) { if (skipBoundTypes) traverse(btv->boundTo); else if (visit(ty, *btv)) traverse(btv->boundTo); } - else if (auto ftv = get(ty)) + else if (auto ftv = get(ty)) visit(ty, *ftv); - else if (auto gtv = get(ty)) + else if (auto gtv = get(ty)) visit(ty, *gtv); - else if (auto etv = get(ty)) + else if (auto etv = get(ty)) visit(ty, *etv); - else if (auto ptv = get(ty)) + else if (auto ptv = get(ty)) visit(ty, *ptv); - else if (auto ftv = get(ty)) + else if (auto ftv = get(ty)) { if (visit(ty, *ftv)) { @@ -226,7 +226,7 @@ struct GenericTypeVarVisitor traverse(ftv->retTypes); } } - else if (auto ttv = get(ty)) + else if (auto ttv = get(ty)) { // Some visitors want to see bound tables, that's why we traverse the original type if (skipBoundTypes && ttv->boundTo) @@ -252,7 +252,7 @@ struct GenericTypeVarVisitor } } } - else if (auto mtv = get(ty)) + else if (auto mtv = get(ty)) { if (visit(ty, *mtv)) { @@ -260,7 +260,7 @@ struct GenericTypeVarVisitor traverse(mtv->metatable); } } - else if (auto ctv = get(ty)) + else if (auto ctv = get(ty)) { if (visit(ty, *ctv)) { @@ -274,9 +274,9 @@ struct GenericTypeVarVisitor traverse(*ctv->metatable); } } - else if (auto atv = get(ty)) + else if (auto atv = get(ty)) visit(ty, *atv); - else if (auto utv = get(ty)) + else if (auto utv = get(ty)) { if (visit(ty, *utv)) { @@ -284,7 +284,7 @@ struct GenericTypeVarVisitor traverse(optTy); } } - else if (auto itv = get(ty)) + else if (auto itv = get(ty)) { if (visit(ty, *itv)) { @@ -292,21 +292,21 @@ struct GenericTypeVarVisitor traverse(partTy); } } - else if (get(ty)) + else if (get(ty)) { - // Visiting into LazyTypeVar may necessarily cause infinite expansion, so we don't do that on purpose. - // Asserting also makes no sense, because the type _will_ happen here, most likely as a property of some ClassTypeVar + // Visiting into LazyType may necessarily cause infinite expansion, so we don't do that on purpose. + // Asserting also makes no sense, because the type _will_ happen here, most likely as a property of some ClassType // that doesn't need to be expanded. } - else if (auto stv = get(ty)) + else if (auto stv = get(ty)) visit(ty, *stv); - else if (auto btv = get(ty)) + else if (auto btv = get(ty)) visit(ty, *btv); - else if (auto utv = get(ty)) + else if (auto utv = get(ty)) visit(ty, *utv); - else if (auto ntv = get(ty)) + else if (auto ntv = get(ty)) visit(ty, *ntv); - else if (auto petv = get(ty)) + else if (auto petv = get(ty)) { if (visit(ty, *petv)) { @@ -317,12 +317,12 @@ struct GenericTypeVarVisitor traverse(a); } } - else if (auto ntv = get(ty)) + else if (auto ntv = get(ty)) visit(ty, *ntv); else if (!FFlag::LuauCompleteVisitor) return visit_detail::unsee(seen, ty); else - LUAU_ASSERT(!"GenericTypeVarVisitor::traverse(TypeId) is not exhaustive!"); + LUAU_ASSERT(!"GenericTypeVisitor::traverse(TypeId) is not exhaustive!"); visit_detail::unsee(seen, ty); } @@ -372,7 +372,7 @@ struct GenericTypeVarVisitor visit(tp, *btp); else - LUAU_ASSERT(!"GenericTypeVarVisitor::traverse(TypePackId) is not exhaustive!"); + LUAU_ASSERT(!"GenericTypeVisitor::traverse(TypePackId) is not exhaustive!"); visit_detail::unsee(seen, tp); } @@ -381,21 +381,21 @@ struct GenericTypeVarVisitor /** Visit each type under a given type. Skips over cycles and keeps recursion depth under control. * * The same type may be visited multiple times if there are multiple distinct paths to it. If this is undesirable, use - * TypeVarOnceVisitor. + * TypeOnceVisitor. */ -struct TypeVarVisitor : GenericTypeVarVisitor> +struct TypeVisitor : GenericTypeVisitor> { - explicit TypeVarVisitor(bool skipBoundTypes = false) - : GenericTypeVarVisitor{{}, skipBoundTypes} + explicit TypeVisitor(bool skipBoundTypes = false) + : GenericTypeVisitor{{}, skipBoundTypes} { } }; /// Visit each type under a given type. Each type will only be checked once even if there are multiple paths to it. -struct TypeVarOnceVisitor : GenericTypeVarVisitor> +struct TypeOnceVisitor : GenericTypeVisitor> { - explicit TypeVarOnceVisitor(bool skipBoundTypes = false) - : GenericTypeVarVisitor{DenseHashSet{nullptr}, skipBoundTypes} + explicit TypeOnceVisitor(bool skipBoundTypes = false) + : GenericTypeVisitor{DenseHashSet{nullptr}, skipBoundTypes} { } }; diff --git a/Analysis/src/Anyification.cpp b/Analysis/src/Anyification.cpp index 5dd761c2..e0ddeacf 100644 --- a/Analysis/src/Anyification.cpp +++ b/Analysis/src/Anyification.cpp @@ -11,20 +11,20 @@ LUAU_FASTFLAG(LuauClassTypeVarsInSubstitution) namespace Luau { -Anyification::Anyification(TypeArena* arena, NotNull scope, NotNull singletonTypes, InternalErrorReporter* iceHandler, +Anyification::Anyification(TypeArena* arena, NotNull scope, NotNull builtinTypes, InternalErrorReporter* iceHandler, TypeId anyType, TypePackId anyTypePack) : Substitution(TxnLog::empty(), arena) , scope(scope) - , singletonTypes(singletonTypes) + , builtinTypes(builtinTypes) , iceHandler(iceHandler) , anyType(anyType) , anyTypePack(anyTypePack) { } -Anyification::Anyification(TypeArena* arena, const ScopePtr& scope, NotNull singletonTypes, InternalErrorReporter* iceHandler, +Anyification::Anyification(TypeArena* arena, const ScopePtr& scope, NotNull builtinTypes, InternalErrorReporter* iceHandler, TypeId anyType, TypePackId anyTypePack) - : Anyification(arena, NotNull{scope.get()}, singletonTypes, iceHandler, anyType, anyTypePack) + : Anyification(arena, NotNull{scope.get()}, builtinTypes, iceHandler, anyType, anyTypePack) { } @@ -33,9 +33,9 @@ bool Anyification::isDirty(TypeId ty) if (ty->persistent) return false; - if (const TableTypeVar* ttv = log->getMutable(ty)) + if (const TableType* ttv = log->getMutable(ty)) return (ttv->state == TableState::Free || ttv->state == TableState::Unsealed); - else if (log->getMutable(ty)) + else if (log->getMutable(ty)) return true; else return false; @@ -55,9 +55,9 @@ bool Anyification::isDirty(TypePackId tp) TypeId Anyification::clean(TypeId ty) { LUAU_ASSERT(isDirty(ty)); - if (const TableTypeVar* ttv = log->getMutable(ty)) + if (const TableType* ttv = log->getMutable(ty)) { - TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, ttv->level, TableState::Sealed}; + TableType clone = TableType{ttv->props, ttv->indexer, ttv->level, TableState::Sealed}; clone.definitionModuleName = ttv->definitionModuleName; clone.name = ttv->name; clone.syntheticName = ttv->syntheticName; @@ -77,7 +77,7 @@ TypePackId Anyification::clean(TypePackId tp) bool Anyification::ignoreChildren(TypeId ty) { - if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) + if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) return true; return ty->persistent; diff --git a/Analysis/src/ApplyTypeFunction.cpp b/Analysis/src/ApplyTypeFunction.cpp index b293ed3d..fe8cc8ac 100644 --- a/Analysis/src/ApplyTypeFunction.cpp +++ b/Analysis/src/ApplyTypeFunction.cpp @@ -11,7 +11,7 @@ bool ApplyTypeFunction::isDirty(TypeId ty) { if (typeArguments.count(ty)) return true; - else if (const FreeTypeVar* ftv = get(ty)) + else if (const FreeType* ftv = get(ty)) { if (ftv->forwardedTypeAlias) encounteredForwardedType = true; @@ -31,9 +31,9 @@ bool ApplyTypeFunction::isDirty(TypePackId tp) bool ApplyTypeFunction::ignoreChildren(TypeId ty) { - if (get(ty)) + if (get(ty)) return true; - else if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) + else if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) return true; else return false; diff --git a/Analysis/src/AstQuery.cpp b/Analysis/src/AstQuery.cpp index e6e7f3d9..39f613e5 100644 --- a/Analysis/src/AstQuery.cpp +++ b/Analysis/src/AstQuery.cpp @@ -4,7 +4,7 @@ #include "Luau/Module.h" #include "Luau/Scope.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/ToString.h" #include "Luau/Common.h" @@ -447,7 +447,7 @@ static std::optional checkOverloadedDocumentationSymbol( return std::nullopt; // This might be an overloaded function. - if (get(follow(ty))) + if (get(follow(ty))) { TypeId matchingOverload = nullptr; if (parentExpr && parentExpr->is()) @@ -487,12 +487,12 @@ std::optional getDocumentationSymbolAtPosition(const Source if (auto it = module.astTypes.find(indexName->expr)) { TypeId parentTy = follow(*it); - if (const TableTypeVar* ttv = get(parentTy)) + if (const TableType* ttv = get(parentTy)) { if (auto propIt = ttv->props.find(indexName->index.value); propIt != ttv->props.end()) return checkOverloadedDocumentationSymbol(module, propIt->second.type, parentExpr, propIt->second.documentationSymbol); } - else if (const ClassTypeVar* ctv = get(parentTy)) + else if (const ClassType* ctv = get(parentTy)) { if (auto propIt = ctv->props.find(indexName->index.value); propIt != ctv->props.end()) return checkOverloadedDocumentationSymbol(module, propIt->second.type, parentExpr, propIt->second.documentationSymbol); diff --git a/Analysis/src/Autocomplete.cpp b/Analysis/src/Autocomplete.cpp index 83a6f021..7a649546 100644 --- a/Analysis/src/Autocomplete.cpp +++ b/Analysis/src/Autocomplete.cpp @@ -43,7 +43,7 @@ static bool alreadyHasParens(const std::vector& nodes) return false; } -static ParenthesesRecommendation getParenRecommendationForFunc(const FunctionTypeVar* func, const std::vector& nodes) +static ParenthesesRecommendation getParenRecommendationForFunc(const FunctionType* func, const std::vector& nodes) { if (alreadyHasParens(nodes)) { @@ -61,12 +61,12 @@ static ParenthesesRecommendation getParenRecommendationForFunc(const FunctionTyp return noArgFunction ? ParenthesesRecommendation::CursorAfter : ParenthesesRecommendation::CursorInside; } -static ParenthesesRecommendation getParenRecommendationForIntersect(const IntersectionTypeVar* intersect, const std::vector& nodes) +static ParenthesesRecommendation getParenRecommendationForIntersect(const IntersectionType* intersect, const std::vector& nodes) { ParenthesesRecommendation rec = ParenthesesRecommendation::None; for (Luau::TypeId partId : intersect->parts) { - if (auto partFunc = Luau::get(partId)) + if (auto partFunc = Luau::get(partId)) { rec = std::max(rec, getParenRecommendationForFunc(partFunc, nodes)); } @@ -85,11 +85,11 @@ static ParenthesesRecommendation getParenRecommendation(TypeId id, const std::ve return ParenthesesRecommendation::None; id = Luau::follow(id); - if (auto func = get(id)) + if (auto func = get(id)) { return getParenRecommendationForFunc(func, nodes); } - else if (auto intersect = get(id)) + else if (auto intersect = get(id)) { return getParenRecommendationForIntersect(intersect, nodes); } @@ -113,7 +113,7 @@ static std::optional findExpectedTypeAt(const Module& module, AstNode* n if (!it) return std::nullopt; - const FunctionTypeVar* ftv = get(follow(*it)); + const FunctionType* ftv = get(follow(*it)); if (!ftv) return std::nullopt; @@ -135,18 +135,18 @@ static std::optional findExpectedTypeAt(const Module& module, AstNode* n return *it; } -static bool checkTypeMatch(TypeId subTy, TypeId superTy, NotNull scope, TypeArena* typeArena, NotNull singletonTypes) +static bool checkTypeMatch(TypeId subTy, TypeId superTy, NotNull scope, TypeArena* typeArena, NotNull builtinTypes) { InternalErrorReporter iceReporter; UnifierSharedState unifierState(&iceReporter); - Normalizer normalizer{typeArena, singletonTypes, NotNull{&unifierState}}; + Normalizer normalizer{typeArena, builtinTypes, NotNull{&unifierState}}; Unifier unifier(NotNull{&normalizer}, Mode::Strict, scope, Location(), Variance::Covariant); return unifier.canUnify(subTy, superTy).empty(); } static TypeCorrectKind checkTypeCorrectKind( - const Module& module, TypeArena* typeArena, NotNull singletonTypes, AstNode* node, Position position, TypeId ty) + const Module& module, TypeArena* typeArena, NotNull builtinTypes, AstNode* node, Position position, TypeId ty) { ty = follow(ty); @@ -159,31 +159,31 @@ static TypeCorrectKind checkTypeCorrectKind( TypeId expectedType = follow(*typeAtPosition); - auto checkFunctionType = [typeArena, singletonTypes, moduleScope, &expectedType](const FunctionTypeVar* ftv) { + auto checkFunctionType = [typeArena, builtinTypes, moduleScope, &expectedType](const FunctionType* ftv) { if (std::optional firstRetTy = first(ftv->retTypes)) - return checkTypeMatch(*firstRetTy, expectedType, moduleScope, typeArena, singletonTypes); + return checkTypeMatch(*firstRetTy, expectedType, moduleScope, typeArena, builtinTypes); return false; }; // We also want to suggest functions that return compatible result - if (const FunctionTypeVar* ftv = get(ty); ftv && checkFunctionType(ftv)) + if (const FunctionType* ftv = get(ty); ftv && checkFunctionType(ftv)) { return TypeCorrectKind::CorrectFunctionResult; } - else if (const IntersectionTypeVar* itv = get(ty)) + else if (const IntersectionType* itv = get(ty)) { for (TypeId id : itv->parts) { - if (const FunctionTypeVar* ftv = get(id); ftv && checkFunctionType(ftv)) + if (const FunctionType* ftv = get(id); ftv && checkFunctionType(ftv)) { return TypeCorrectKind::CorrectFunctionResult; } } } - return checkTypeMatch(ty, expectedType, NotNull{module.getModuleScope().get()}, typeArena, singletonTypes) ? TypeCorrectKind::Correct - : TypeCorrectKind::None; + return checkTypeMatch(ty, expectedType, NotNull{module.getModuleScope().get()}, typeArena, builtinTypes) ? TypeCorrectKind::Correct + : TypeCorrectKind::None; } enum class PropIndexType @@ -193,9 +193,9 @@ enum class PropIndexType Key, }; -static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNull singletonTypes, TypeId rootTy, TypeId ty, +static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNull builtinTypes, TypeId rootTy, TypeId ty, PropIndexType indexType, const std::vector& nodes, AutocompleteEntryMap& result, std::unordered_set& seen, - std::optional containingClass = std::nullopt) + std::optional containingClass = std::nullopt) { rootTy = follow(rootTy); ty = follow(ty); @@ -204,41 +204,41 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul return; seen.insert(ty); - auto isWrongIndexer = [typeArena, singletonTypes, &module, rootTy, indexType](Luau::TypeId type) { + auto isWrongIndexer = [typeArena, builtinTypes, &module, rootTy, indexType](Luau::TypeId type) { if (indexType == PropIndexType::Key) return false; bool calledWithSelf = indexType == PropIndexType::Colon; - auto isCompatibleCall = [typeArena, singletonTypes, &module, rootTy, calledWithSelf](const FunctionTypeVar* ftv) { + auto isCompatibleCall = [typeArena, builtinTypes, &module, rootTy, calledWithSelf](const FunctionType* ftv) { // Strong match with definition is a success if (calledWithSelf == ftv->hasSelf) return true; // Calls on classes require strict match between how function is declared and how it's called - if (get(rootTy)) + if (get(rootTy)) return false; // When called with ':', but declared without 'self', it is invalid if a function has incompatible first argument or no arguments at all // When called with '.', but declared with 'self', it is considered invalid if first argument is compatible if (std::optional firstArgTy = first(ftv->argTypes)) { - if (checkTypeMatch(rootTy, *firstArgTy, NotNull{module.getModuleScope().get()}, typeArena, singletonTypes)) + if (checkTypeMatch(rootTy, *firstArgTy, NotNull{module.getModuleScope().get()}, typeArena, builtinTypes)) return calledWithSelf; } return !calledWithSelf; }; - if (const FunctionTypeVar* ftv = get(type)) + if (const FunctionType* ftv = get(type)) return !isCompatibleCall(ftv); // For intersections, any part that is successful makes the whole call successful - if (const IntersectionTypeVar* itv = get(type)) + if (const IntersectionType* itv = get(type)) { for (auto subType : itv->parts) { - if (const FunctionTypeVar* ftv = get(Luau::follow(subType))) + if (const FunctionType* ftv = get(Luau::follow(subType))) { if (isCompatibleCall(ftv)) return false; @@ -249,7 +249,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul return calledWithSelf; }; - auto fillProps = [&](const ClassTypeVar::Props& props) { + auto fillProps = [&](const ClassType::Props& props) { for (const auto& [name, prop] : props) { // We are walking up the class hierarchy, so if we encounter a property that we have @@ -259,7 +259,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul Luau::TypeId type = Luau::follow(prop.type); TypeCorrectKind typeCorrect = indexType == PropIndexType::Key ? TypeCorrectKind::Correct - : checkTypeCorrectKind(module, typeArena, singletonTypes, nodes.back(), {{}, {}}, type); + : checkTypeCorrectKind(module, typeArena, builtinTypes, nodes.back(), {{}, {}}, type); ParenthesesRecommendation parens = indexType == PropIndexType::Key ? ParenthesesRecommendation::None : getParenRecommendation(type, nodes, typeCorrect); @@ -279,41 +279,41 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul } }; - auto fillMetatableProps = [&](const TableTypeVar* mtable) { + auto fillMetatableProps = [&](const TableType* mtable) { auto indexIt = mtable->props.find("__index"); if (indexIt != mtable->props.end()) { TypeId followed = follow(indexIt->second.type); - if (get(followed) || get(followed)) + if (get(followed) || get(followed)) { - autocompleteProps(module, typeArena, singletonTypes, rootTy, followed, indexType, nodes, result, seen); + autocompleteProps(module, typeArena, builtinTypes, rootTy, followed, indexType, nodes, result, seen); } - else if (auto indexFunction = get(followed)) + else if (auto indexFunction = get(followed)) { std::optional indexFunctionResult = first(indexFunction->retTypes); if (indexFunctionResult) - autocompleteProps(module, typeArena, singletonTypes, rootTy, *indexFunctionResult, indexType, nodes, result, seen); + autocompleteProps(module, typeArena, builtinTypes, rootTy, *indexFunctionResult, indexType, nodes, result, seen); } } }; - if (auto cls = get(ty)) + if (auto cls = get(ty)) { containingClass = containingClass.value_or(cls); fillProps(cls->props); if (cls->parent) - autocompleteProps(module, typeArena, singletonTypes, rootTy, *cls->parent, indexType, nodes, result, seen, containingClass); + autocompleteProps(module, typeArena, builtinTypes, rootTy, *cls->parent, indexType, nodes, result, seen, containingClass); } - else if (auto tbl = get(ty)) + else if (auto tbl = get(ty)) fillProps(tbl->props); - else if (auto mt = get(ty)) + else if (auto mt = get(ty)) { - autocompleteProps(module, typeArena, singletonTypes, rootTy, mt->table, indexType, nodes, result, seen); + autocompleteProps(module, typeArena, builtinTypes, rootTy, mt->table, indexType, nodes, result, seen); - if (auto mtable = get(mt->metatable)) + if (auto mtable = get(mt->metatable)) fillMetatableProps(mtable); } - else if (auto i = get(ty)) + else if (auto i = get(ty)) { // Complete all properties in every variant for (TypeId ty : i->parts) @@ -321,13 +321,13 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul AutocompleteEntryMap inner; std::unordered_set innerSeen = seen; - autocompleteProps(module, typeArena, singletonTypes, rootTy, ty, indexType, nodes, inner, innerSeen); + autocompleteProps(module, typeArena, builtinTypes, rootTy, ty, indexType, nodes, inner, innerSeen); for (auto& pair : inner) result.insert(pair); } } - else if (auto u = get(ty)) + else if (auto u = get(ty)) { // Complete all properties common to all variants auto iter = begin(u); @@ -344,7 +344,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul if (iter == endIter) return; - autocompleteProps(module, typeArena, singletonTypes, rootTy, *iter, indexType, nodes, result, seen); + autocompleteProps(module, typeArena, builtinTypes, rootTy, *iter, indexType, nodes, result, seen); ++iter; @@ -359,7 +359,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul continue; } - autocompleteProps(module, typeArena, singletonTypes, rootTy, *iter, indexType, nodes, inner, innerSeen); + autocompleteProps(module, typeArena, builtinTypes, rootTy, *iter, indexType, nodes, inner, innerSeen); std::unordered_set toRemove; @@ -376,17 +376,17 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul ++iter; } } - else if (auto pt = get(ty)) + else if (auto pt = get(ty)) { if (pt->metatable) { - if (auto mtable = get(*pt->metatable)) + if (auto mtable = get(*pt->metatable)) fillMetatableProps(mtable); } } - else if (get(get(ty))) + else if (get(get(ty))) { - autocompleteProps(module, typeArena, singletonTypes, rootTy, singletonTypes->stringType, indexType, nodes, result, seen); + autocompleteProps(module, typeArena, builtinTypes, rootTy, builtinTypes->stringType, indexType, nodes, result, seen); } } @@ -411,18 +411,18 @@ static void autocompleteKeywords( } } -static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNull singletonTypes, TypeId ty, PropIndexType indexType, +static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNull builtinTypes, TypeId ty, PropIndexType indexType, const std::vector& nodes, AutocompleteEntryMap& result) { std::unordered_set seen; - autocompleteProps(module, typeArena, singletonTypes, ty, ty, indexType, nodes, result, seen); + autocompleteProps(module, typeArena, builtinTypes, ty, ty, indexType, nodes, result, seen); } -AutocompleteEntryMap autocompleteProps(const Module& module, TypeArena* typeArena, NotNull singletonTypes, TypeId ty, +AutocompleteEntryMap autocompleteProps(const Module& module, TypeArena* typeArena, NotNull builtinTypes, TypeId ty, PropIndexType indexType, const std::vector& nodes) { AutocompleteEntryMap result; - autocompleteProps(module, typeArena, singletonTypes, ty, indexType, nodes, result); + autocompleteProps(module, typeArena, builtinTypes, ty, indexType, nodes, result); return result; } @@ -455,15 +455,15 @@ static void autocompleteStringSingleton(TypeId ty, bool addQuotes, AutocompleteE ty = follow(ty); - if (auto ss = get(get(ty))) + if (auto ss = get(get(ty))) { result[formatKey(ss->value)] = AutocompleteEntry{AutocompleteEntryKind::String, ty, false, false, TypeCorrectKind::Correct}; } - else if (auto uty = get(ty)) + else if (auto uty = get(ty)) { for (auto el : uty) { - if (auto ss = get(get(el))) + if (auto ss = get(get(el))) result[formatKey(ss->value)] = AutocompleteEntry{AutocompleteEntryKind::String, ty, false, false, TypeCorrectKind::Correct}; } } @@ -474,14 +474,14 @@ static bool canSuggestInferredType(ScopePtr scope, TypeId ty) ty = follow(ty); // No point in suggesting 'any', invalid to suggest others - if (get(ty) || get(ty) || get(ty) || get(ty)) + if (get(ty) || get(ty) || get(ty) || get(ty)) return false; // No syntax for unnamed tables with a metatable - if (get(ty)) + if (get(ty)) return false; - if (const TableTypeVar* ttv = get(ty)) + if (const TableType* ttv = get(ty)) { if (ttv->name) return true; @@ -544,7 +544,7 @@ static std::optional findTypeElementAt(AstType* astType, TypeId ty, Posi if (AstTypeFunction* type = astType->as()) { - const FunctionTypeVar* ftv = get(ty); + const FunctionType* ftv = get(ty); if (!ftv) return {}; @@ -634,7 +634,7 @@ static std::optional tryGetTypePackTypeAt(TypePackId tp, size_t index) } template -std::optional returnFirstNonnullOptionOfType(const UnionTypeVar* utv) +std::optional returnFirstNonnullOptionOfType(const UnionType* utv) { std::optional ret; for (TypeId subTy : utv) @@ -667,18 +667,18 @@ static std::optional functionIsExpectedAt(const Module& module, AstNode* n TypeId expectedType = follow(*typeAtPosition); - if (get(expectedType)) + if (get(expectedType)) return true; - if (const IntersectionTypeVar* itv = get(expectedType)) + if (const IntersectionType* itv = get(expectedType)) { return std::all_of(begin(itv->parts), end(itv->parts), [](auto&& ty) { - return get(Luau::follow(ty)) != nullptr; + return get(Luau::follow(ty)) != nullptr; }); } - if (const UnionTypeVar* utv = get(expectedType)) - return returnFirstNonnullOptionOfType(utv).has_value(); + if (const UnionType* utv = get(expectedType)) + return returnFirstNonnullOptionOfType(utv).has_value(); return false; } @@ -766,7 +766,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi { if (auto it = module.astTypes.find(exprCall->func)) { - if (const FunctionTypeVar* ftv = get(follow(*it))) + if (const FunctionType* ftv = get(follow(*it))) { if (auto ty = tryGetTypePackTypeAt(ftv->retTypes, tailPos)) inferredType = *ty; @@ -792,7 +792,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi else if (AstExprFunction* node = parent->as()) { // For lookup inside expected function type if that's available - auto tryGetExpectedFunctionType = [](const Module& module, AstExpr* expr) -> const FunctionTypeVar* { + auto tryGetExpectedFunctionType = [](const Module& module, AstExpr* expr) -> const FunctionType* { auto it = module.astExpectedTypes.find(expr); if (!it) @@ -800,13 +800,13 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi TypeId ty = follow(*it); - if (const FunctionTypeVar* ftv = get(ty)) + if (const FunctionType* ftv = get(ty)) return ftv; // Handle optional function type - if (const UnionTypeVar* utv = get(ty)) + if (const UnionType* utv = get(ty)) { - return returnFirstNonnullOptionOfType(utv).value_or(nullptr); + return returnFirstNonnullOptionOfType(utv).value_or(nullptr); } return nullptr; @@ -819,7 +819,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi if (arg->annotation && arg->annotation->location.containsClosed(position)) { - if (const FunctionTypeVar* ftv = tryGetExpectedFunctionType(module, node)) + if (const FunctionType* ftv = tryGetExpectedFunctionType(module, node)) { if (auto ty = tryGetTypePackTypeAt(ftv->argTypes, i)) tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position); @@ -840,7 +840,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi { if (variadic->location.containsClosed(position)) { - if (const FunctionTypeVar* ftv = tryGetExpectedFunctionType(module, node)) + if (const FunctionType* ftv = tryGetExpectedFunctionType(module, node)) { if (auto ty = tryGetTypePackTypeAt(ftv->argTypes, ~0u)) tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position); @@ -858,7 +858,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi if (ret->location.containsClosed(position)) { - if (const FunctionTypeVar* ftv = tryGetExpectedFunctionType(module, node)) + if (const FunctionType* ftv = tryGetExpectedFunctionType(module, node)) { if (auto ty = tryGetTypePackTypeAt(ftv->retTypes, i)) tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position); @@ -875,7 +875,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi { if (variadic->location.containsClosed(position)) { - if (const FunctionTypeVar* ftv = tryGetExpectedFunctionType(module, node)) + if (const FunctionType* ftv = tryGetExpectedFunctionType(module, node)) { if (auto ty = tryGetTypePackTypeAt(ftv->retTypes, ~0u)) tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position); @@ -1127,7 +1127,7 @@ static bool autocompleteIfElseExpression( } } -static AutocompleteContext autocompleteExpression(const SourceModule& sourceModule, const Module& module, NotNull singletonTypes, +static AutocompleteContext autocompleteExpression(const SourceModule& sourceModule, const Module& module, NotNull builtinTypes, TypeArena* typeArena, const std::vector& ancestry, Position position, AutocompleteEntryMap& result) { LUAU_ASSERT(!ancestry.empty()); @@ -1137,7 +1137,7 @@ static AutocompleteContext autocompleteExpression(const SourceModule& sourceModu if (node->is()) { if (auto it = module.astTypes.find(node->asExpr())) - autocompleteProps(module, typeArena, singletonTypes, *it, PropIndexType::Point, ancestry, result); + autocompleteProps(module, typeArena, builtinTypes, *it, PropIndexType::Point, ancestry, result); } else if (autocompleteIfElseExpression(node, ancestry, position, result)) return AutocompleteContext::Keyword; @@ -1161,7 +1161,7 @@ static AutocompleteContext autocompleteExpression(const SourceModule& sourceModu std::string n = toString(name); if (!result.count(n)) { - TypeCorrectKind typeCorrect = checkTypeCorrectKind(module, typeArena, singletonTypes, node, position, binding.typeId); + TypeCorrectKind typeCorrect = checkTypeCorrectKind(module, typeArena, builtinTypes, node, position, binding.typeId); result[n] = {AutocompleteEntryKind::Binding, binding.typeId, binding.deprecated, false, typeCorrect, std::nullopt, std::nullopt, binding.documentationSymbol, {}, getParenRecommendation(binding.typeId, ancestry, typeCorrect)}; @@ -1171,16 +1171,16 @@ static AutocompleteContext autocompleteExpression(const SourceModule& sourceModu scope = scope->parent; } - TypeCorrectKind correctForNil = checkTypeCorrectKind(module, typeArena, singletonTypes, node, position, singletonTypes->nilType); - TypeCorrectKind correctForTrue = checkTypeCorrectKind(module, typeArena, singletonTypes, node, position, singletonTypes->trueType); - TypeCorrectKind correctForFalse = checkTypeCorrectKind(module, typeArena, singletonTypes, node, position, singletonTypes->falseType); + TypeCorrectKind correctForNil = checkTypeCorrectKind(module, typeArena, builtinTypes, node, position, builtinTypes->nilType); + TypeCorrectKind correctForTrue = checkTypeCorrectKind(module, typeArena, builtinTypes, node, position, builtinTypes->trueType); + TypeCorrectKind correctForFalse = checkTypeCorrectKind(module, typeArena, builtinTypes, node, position, builtinTypes->falseType); TypeCorrectKind correctForFunction = functionIsExpectedAt(module, node, position).value_or(false) ? TypeCorrectKind::Correct : TypeCorrectKind::None; result["if"] = {AutocompleteEntryKind::Keyword, std::nullopt, false, false}; - result["true"] = {AutocompleteEntryKind::Keyword, singletonTypes->booleanType, false, false, correctForTrue}; - result["false"] = {AutocompleteEntryKind::Keyword, singletonTypes->booleanType, false, false, correctForFalse}; - result["nil"] = {AutocompleteEntryKind::Keyword, singletonTypes->nilType, false, false, correctForNil}; + result["true"] = {AutocompleteEntryKind::Keyword, builtinTypes->booleanType, false, false, correctForTrue}; + result["false"] = {AutocompleteEntryKind::Keyword, builtinTypes->booleanType, false, false, correctForFalse}; + result["nil"] = {AutocompleteEntryKind::Keyword, builtinTypes->nilType, false, false, correctForNil}; result["not"] = {AutocompleteEntryKind::Keyword}; result["function"] = {AutocompleteEntryKind::Keyword, std::nullopt, false, false, correctForFunction}; @@ -1191,15 +1191,15 @@ static AutocompleteContext autocompleteExpression(const SourceModule& sourceModu return AutocompleteContext::Expression; } -static AutocompleteResult autocompleteExpression(const SourceModule& sourceModule, const Module& module, NotNull singletonTypes, +static AutocompleteResult autocompleteExpression(const SourceModule& sourceModule, const Module& module, NotNull builtinTypes, TypeArena* typeArena, const std::vector& ancestry, Position position) { AutocompleteEntryMap result; - AutocompleteContext context = autocompleteExpression(sourceModule, module, singletonTypes, typeArena, ancestry, position, result); + AutocompleteContext context = autocompleteExpression(sourceModule, module, builtinTypes, typeArena, ancestry, position, result); return {result, ancestry, context}; } -static std::optional getMethodContainingClass(const ModulePtr& module, AstExpr* funcExpr) +static std::optional getMethodContainingClass(const ModulePtr& module, AstExpr* funcExpr) { AstExpr* parentExpr = nullptr; if (auto indexName = funcExpr->as()) @@ -1223,14 +1223,14 @@ static std::optional getMethodContainingClass(const ModuleP Luau::TypeId parentType = Luau::follow(*parentIt); - if (auto parentClass = Luau::get(parentType)) + if (auto parentClass = Luau::get(parentType)) { return parentClass; } - if (auto parentUnion = Luau::get(parentType)) + if (auto parentUnion = Luau::get(parentType)) { - return returnFirstNonnullOptionOfType(parentUnion); + return returnFirstNonnullOptionOfType(parentUnion); } return std::nullopt; @@ -1281,7 +1281,7 @@ static std::optional autocompleteStringParams(const Source } // HACK: All current instances of 'magic string' params are the first parameter of their functions, - // so we encode that here rather than putting a useless member on the FunctionTypeVar struct. + // so we encode that here rather than putting a useless member on the FunctionType struct. if (candidate->args.size > 1 && !candidate->args.data[0]->location.contains(position)) { return std::nullopt; @@ -1293,7 +1293,7 @@ static std::optional autocompleteStringParams(const Source return std::nullopt; } - auto performCallback = [&](const FunctionTypeVar* funcType) -> std::optional { + auto performCallback = [&](const FunctionType* funcType) -> std::optional { for (const std::string& tag : funcType->tags) { if (std::optional ret = callback(tag, getMethodContainingClass(module, candidate->func))) @@ -1305,16 +1305,16 @@ static std::optional autocompleteStringParams(const Source }; auto followedId = Luau::follow(*it); - if (auto functionType = Luau::get(followedId)) + if (auto functionType = Luau::get(followedId)) { return performCallback(functionType); } - if (auto intersect = Luau::get(followedId)) + if (auto intersect = Luau::get(followedId)) { for (TypeId part : intersect->parts) { - if (auto candidateFunctionType = Luau::get(part)) + if (auto candidateFunctionType = Luau::get(part)) { if (std::optional ret = performCallback(candidateFunctionType)) { @@ -1327,7 +1327,7 @@ static std::optional autocompleteStringParams(const Source return std::nullopt; } -static AutocompleteResult autocomplete(const SourceModule& sourceModule, const ModulePtr& module, NotNull singletonTypes, +static AutocompleteResult autocomplete(const SourceModule& sourceModule, const ModulePtr& module, NotNull builtinTypes, Scope* globalScope, Position position, StringCompletionCallback callback) { if (isWithinComment(sourceModule, position)) @@ -1360,7 +1360,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M TypeId ty = follow(*it); PropIndexType indexType = indexName->op == ':' ? PropIndexType::Colon : PropIndexType::Point; - return {autocompleteProps(*module, &typeArena, singletonTypes, ty, indexType, ancestry), ancestry, AutocompleteContext::Property}; + return {autocompleteProps(*module, &typeArena, builtinTypes, ty, indexType, ancestry), ancestry, AutocompleteContext::Property}; } else if (auto typeReference = node->as()) { @@ -1378,7 +1378,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M if (statLocal->vars.size == 1 && (!statLocal->equalsSignLocation || position < statLocal->equalsSignLocation->begin)) return {{{"function", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Unknown}; else if (statLocal->equalsSignLocation && position >= statLocal->equalsSignLocation->end) - return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position); + return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position); else return {}; } @@ -1392,7 +1392,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M if (statFor->from->location.containsClosed(position) || statFor->to->location.containsClosed(position) || (statFor->step && statFor->step->location.containsClosed(position))) - return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position); + return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position); return {}; } @@ -1422,7 +1422,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M AstExpr* lastExpr = statForIn->values.data[statForIn->values.size - 1]; if (lastExpr->location.containsClosed(position)) - return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position); + return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position); if (position > lastExpr->location.end) return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword}; @@ -1446,7 +1446,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword}; if (!statWhile->hasDo || position < statWhile->doLocation.begin) - return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position); + return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position); if (statWhile->hasDo && position > statWhile->doLocation.end) return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement}; @@ -1463,7 +1463,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M else if (AstStatIf* statIf = parent->as(); statIf && node->is()) { if (statIf->condition->is()) - return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position); + return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position); else if (!statIf->thenLocation || statIf->thenLocation->containsClosed(position)) return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword}; } @@ -1471,7 +1471,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M statIf && (!statIf->thenLocation || statIf->thenLocation->containsClosed(position))) return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword}; else if (AstStatRepeat* statRepeat = node->as(); statRepeat && statRepeat->condition->is()) - return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position); + return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position); else if (AstStatRepeat* statRepeat = extractStat(ancestry); statRepeat) return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement}; else if (AstExprTable* exprTable = parent->as(); @@ -1484,7 +1484,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M { if (auto it = module->astExpectedTypes.find(exprTable)) { - auto result = autocompleteProps(*module, &typeArena, singletonTypes, *it, PropIndexType::Key, ancestry); + auto result = autocompleteProps(*module, &typeArena, builtinTypes, *it, PropIndexType::Key, ancestry); if (FFlag::LuauCompleteTableKeysBetter) { @@ -1499,7 +1499,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M // // If the key type is a union of singleton strings, // suggest those too. - if (auto ttv = get(follow(*it)); ttv && ttv->indexer) + if (auto ttv = get(follow(*it)); ttv && ttv->indexer) { autocompleteStringSingleton(ttv->indexer->indexType, false, result); } @@ -1518,7 +1518,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M // If we know for sure that a key is being written, do not offer general expression suggestions if (!key) - autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position, result); + autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position, result); return {result, ancestry, AutocompleteContext::Property}; } @@ -1546,7 +1546,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M if (auto idxExpr = ancestry.at(ancestry.size() - 2)->as()) { if (auto it = module->astTypes.find(idxExpr->expr)) - autocompleteProps(*module, &typeArena, singletonTypes, follow(*it), PropIndexType::Point, ancestry, result); + autocompleteProps(*module, &typeArena, builtinTypes, follow(*it), PropIndexType::Point, ancestry, result); } else if (auto binExpr = ancestry.at(ancestry.size() - 2)->as()) { @@ -1572,7 +1572,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M return {}; if (node->asExpr()) - return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position); + return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position); else if (node->asStat()) return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement}; @@ -1596,10 +1596,10 @@ AutocompleteResult autocomplete(Frontend& frontend, const ModuleName& moduleName if (!module) return {}; - NotNull singletonTypes = frontend.singletonTypes; + NotNull builtinTypes = frontend.builtinTypes; Scope* globalScope = frontend.typeCheckerForAutocomplete.globalScope.get(); - AutocompleteResult autocompleteResult = autocomplete(*sourceModule, module, singletonTypes, globalScope, position, callback); + AutocompleteResult autocompleteResult = autocomplete(*sourceModule, module, builtinTypes, globalScope, position, callback); return autocompleteResult; } diff --git a/Analysis/src/BuiltinDefinitions.cpp b/Analysis/src/BuiltinDefinitions.cpp index 612812c5..81702ff6 100644 --- a/Analysis/src/BuiltinDefinitions.cpp +++ b/Analysis/src/BuiltinDefinitions.cpp @@ -10,7 +10,7 @@ #include "Luau/ConstraintGraphBuilder.h" #include "Luau/TypeInfer.h" #include "Luau/TypePack.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/TypeUtils.h" #include @@ -51,12 +51,12 @@ static std::vector dcrMagicRefinementAssert(const MagicRefinementC TypeId makeUnion(TypeArena& arena, std::vector&& types) { - return arena.addType(UnionTypeVar{std::move(types)}); + return arena.addType(UnionType{std::move(types)}); } TypeId makeIntersection(TypeArena& arena, std::vector&& types) { - return arena.addType(IntersectionTypeVar{std::move(types)}); + return arena.addType(IntersectionType{std::move(types)}); } TypeId makeOption(Frontend& frontend, TypeArena& arena, TypeId t) @@ -99,7 +99,7 @@ TypeId makeFunction(TypeArena& arena, std::optional selfType, std::initi TypePackId paramPack = arena.addTypePack(std::move(params)); TypePackId retPack = arena.addTypePack(std::vector(retTypes)); - FunctionTypeVar ftv{generics, genericPacks, paramPack, retPack, {}, selfType.has_value()}; + FunctionType ftv{generics, genericPacks, paramPack, retPack, {}, selfType.has_value()}; if (selfType) ftv.argNames.push_back(Luau::FunctionArgument{"self", {}}); @@ -121,7 +121,7 @@ TypeId makeFunction(TypeArena& arena, std::optional selfType, std::initi void attachMagicFunction(TypeId ty, MagicFunction fn) { - if (auto ftv = getMutable(ty)) + if (auto ftv = getMutable(ty)) ftv->magicFunction = fn; else LUAU_ASSERT(!"Got a non functional type"); @@ -129,7 +129,7 @@ void attachMagicFunction(TypeId ty, MagicFunction fn) void attachDcrMagicFunction(TypeId ty, DcrMagicFunction fn) { - if (auto ftv = getMutable(ty)) + if (auto ftv = getMutable(ty)) ftv->dcrMagicFunction = fn; else LUAU_ASSERT(!"Got a non functional type"); @@ -137,7 +137,7 @@ void attachDcrMagicFunction(TypeId ty, DcrMagicFunction fn) void attachDcrMagicRefinement(TypeId ty, DcrMagicRefinement fn) { - if (auto ftv = getMutable(ty)) + if (auto ftv = getMutable(ty)) ftv->dcrMagicRefinement = fn; else LUAU_ASSERT(!"Got a non functional type"); @@ -239,7 +239,7 @@ Binding* tryGetGlobalBindingRef(TypeChecker& typeChecker, const std::string& nam return nullptr; } -void assignPropDocumentationSymbols(TableTypeVar::Props& props, const std::string& baseName) +void assignPropDocumentationSymbols(TableType::Props& props, const std::string& baseName) { for (auto& [name, prop] : props) { @@ -249,39 +249,39 @@ void assignPropDocumentationSymbols(TableTypeVar::Props& props, const std::strin void registerBuiltinTypes(Frontend& frontend) { - frontend.getGlobalScope()->addBuiltinTypeBinding("any", TypeFun{{}, frontend.singletonTypes->anyType}); - frontend.getGlobalScope()->addBuiltinTypeBinding("nil", TypeFun{{}, frontend.singletonTypes->nilType}); - frontend.getGlobalScope()->addBuiltinTypeBinding("number", TypeFun{{}, frontend.singletonTypes->numberType}); - frontend.getGlobalScope()->addBuiltinTypeBinding("string", TypeFun{{}, frontend.singletonTypes->stringType}); - frontend.getGlobalScope()->addBuiltinTypeBinding("boolean", TypeFun{{}, frontend.singletonTypes->booleanType}); - frontend.getGlobalScope()->addBuiltinTypeBinding("thread", TypeFun{{}, frontend.singletonTypes->threadType}); + frontend.getGlobalScope()->addBuiltinTypeBinding("any", TypeFun{{}, frontend.builtinTypes->anyType}); + frontend.getGlobalScope()->addBuiltinTypeBinding("nil", TypeFun{{}, frontend.builtinTypes->nilType}); + frontend.getGlobalScope()->addBuiltinTypeBinding("number", TypeFun{{}, frontend.builtinTypes->numberType}); + frontend.getGlobalScope()->addBuiltinTypeBinding("string", TypeFun{{}, frontend.builtinTypes->stringType}); + frontend.getGlobalScope()->addBuiltinTypeBinding("boolean", TypeFun{{}, frontend.builtinTypes->booleanType}); + frontend.getGlobalScope()->addBuiltinTypeBinding("thread", TypeFun{{}, frontend.builtinTypes->threadType}); if (FFlag::LuauUnknownAndNeverType) { - frontend.getGlobalScope()->addBuiltinTypeBinding("unknown", TypeFun{{}, frontend.singletonTypes->unknownType}); - frontend.getGlobalScope()->addBuiltinTypeBinding("never", TypeFun{{}, frontend.singletonTypes->neverType}); + frontend.getGlobalScope()->addBuiltinTypeBinding("unknown", TypeFun{{}, frontend.builtinTypes->unknownType}); + frontend.getGlobalScope()->addBuiltinTypeBinding("never", TypeFun{{}, frontend.builtinTypes->neverType}); } } void registerBuiltinGlobals(TypeChecker& typeChecker) { - LUAU_ASSERT(!typeChecker.globalTypes.typeVars.isFrozen()); + LUAU_ASSERT(!typeChecker.globalTypes.types.isFrozen()); LUAU_ASSERT(!typeChecker.globalTypes.typePacks.isFrozen()); TypeId nilType = typeChecker.nilType; TypeArena& arena = typeChecker.globalTypes; - NotNull singletonTypes = typeChecker.singletonTypes; + NotNull builtinTypes = typeChecker.builtinTypes; LoadDefinitionFileResult loadResult = Luau::loadDefinitionFile(typeChecker, typeChecker.globalScope, getBuiltinDefinitionSource(), "@luau"); LUAU_ASSERT(loadResult.success); - TypeId genericK = arena.addType(GenericTypeVar{"K"}); - TypeId genericV = arena.addType(GenericTypeVar{"V"}); - TypeId mapOfKtoV = arena.addType(TableTypeVar{{}, TableIndexer(genericK, genericV), typeChecker.globalScope->level, TableState::Generic}); + TypeId genericK = arena.addType(GenericType{"K"}); + TypeId genericV = arena.addType(GenericType{"V"}); + TypeId mapOfKtoV = arena.addType(TableType{{}, TableIndexer(genericK, genericV), typeChecker.globalScope->level, TableState::Generic}); - std::optional stringMetatableTy = getMetatable(singletonTypes->stringType, singletonTypes); + std::optional stringMetatableTy = getMetatable(builtinTypes->stringType, builtinTypes); LUAU_ASSERT(stringMetatableTy); - const TableTypeVar* stringMetatableTable = get(follow(*stringMetatableTy)); + const TableType* stringMetatableTable = get(follow(*stringMetatableTy)); LUAU_ASSERT(stringMetatableTable); auto it = stringMetatableTable->props.find("__index"); @@ -294,40 +294,40 @@ void registerBuiltinGlobals(TypeChecker& typeChecker) // next(t: Table, i: K?) -> (K?, V) TypePackId nextArgsTypePack = arena.addTypePack(TypePack{{mapOfKtoV, makeOption(typeChecker, arena, genericK)}}); TypePackId nextRetsTypePack = arena.addTypePack(TypePack{{makeOption(typeChecker, arena, genericK), genericV}}); - addGlobalBinding(typeChecker, "next", arena.addType(FunctionTypeVar{{genericK, genericV}, {}, nextArgsTypePack, nextRetsTypePack}), "@luau"); + addGlobalBinding(typeChecker, "next", arena.addType(FunctionType{{genericK, genericV}, {}, nextArgsTypePack, nextRetsTypePack}), "@luau"); TypePackId pairsArgsTypePack = arena.addTypePack({mapOfKtoV}); - TypeId pairsNext = arena.addType(FunctionTypeVar{nextArgsTypePack, nextRetsTypePack}); + TypeId pairsNext = arena.addType(FunctionType{nextArgsTypePack, nextRetsTypePack}); TypePackId pairsReturnTypePack = arena.addTypePack(TypePack{{pairsNext, mapOfKtoV, nilType}}); // pairs(t: Table) -> ((Table, K?) -> (K, V), Table, nil) addGlobalBinding( - typeChecker, "pairs", arena.addType(FunctionTypeVar{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau"); + typeChecker, "pairs", arena.addType(FunctionType{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau"); } else { // next(t: Table, i: K?) -> (K, V) TypePackId nextArgsTypePack = arena.addTypePack(TypePack{{mapOfKtoV, makeOption(typeChecker, arena, genericK)}}); addGlobalBinding(typeChecker, "next", - arena.addType(FunctionTypeVar{{genericK, genericV}, {}, nextArgsTypePack, arena.addTypePack(TypePack{{genericK, genericV}})}), "@luau"); + arena.addType(FunctionType{{genericK, genericV}, {}, nextArgsTypePack, arena.addTypePack(TypePack{{genericK, genericV}})}), "@luau"); TypePackId pairsArgsTypePack = arena.addTypePack({mapOfKtoV}); - TypeId pairsNext = arena.addType(FunctionTypeVar{nextArgsTypePack, arena.addTypePack(TypePack{{genericK, genericV}})}); + TypeId pairsNext = arena.addType(FunctionType{nextArgsTypePack, arena.addTypePack(TypePack{{genericK, genericV}})}); TypePackId pairsReturnTypePack = arena.addTypePack(TypePack{{pairsNext, mapOfKtoV, nilType}}); // pairs(t: Table) -> ((Table, K?) -> (K, V), Table, nil) addGlobalBinding( - typeChecker, "pairs", arena.addType(FunctionTypeVar{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau"); + typeChecker, "pairs", arena.addType(FunctionType{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau"); } - TypeId genericMT = arena.addType(GenericTypeVar{"MT"}); + TypeId genericMT = arena.addType(GenericType{"MT"}); - TableTypeVar tab{TableState::Generic, typeChecker.globalScope->level}; + TableType tab{TableState::Generic, typeChecker.globalScope->level}; TypeId tabTy = arena.addType(tab); - TypeId tableMetaMT = arena.addType(MetatableTypeVar{tabTy, genericMT}); + TypeId tableMetaMT = arena.addType(MetatableType{tabTy, genericMT}); addGlobalBinding(typeChecker, "getmetatable", makeFunction(arena, std::nullopt, {genericMT}, {}, {tableMetaMT}, {genericMT}), "@luau"); @@ -335,7 +335,7 @@ void registerBuiltinGlobals(TypeChecker& typeChecker) // setmetatable(T, MT) -> { @metatable MT, T } addGlobalBinding(typeChecker, "setmetatable", arena.addType( - FunctionTypeVar{ + FunctionType{ {genericMT}, {}, arena.addTypePack(TypePack{{FFlag::LuauUnknownAndNeverType ? tabTy : tableMetaMT, genericMT}}), @@ -349,7 +349,7 @@ void registerBuiltinGlobals(TypeChecker& typeChecker) { persist(pair.second.typeId); - if (TableTypeVar* ttv = getMutable(pair.second.typeId)) + if (TableType* ttv = getMutable(pair.second.typeId)) { if (!ttv->name) { @@ -366,7 +366,7 @@ void registerBuiltinGlobals(TypeChecker& typeChecker) attachMagicFunction(getGlobalBinding(typeChecker, "select"), magicFunctionSelect); attachDcrMagicFunction(getGlobalBinding(typeChecker, "select"), dcrMagicFunctionSelect); - if (TableTypeVar* ttv = getMutable(getGlobalBinding(typeChecker, "table"))) + if (TableType* ttv = getMutable(getGlobalBinding(typeChecker, "table"))) { // tabTy is a generic table type which we can't express via declaration syntax yet ttv->props["freeze"] = makeProperty(makeFunction(arena, std::nullopt, {tabTy}, {tabTy}), "@luau/global/table.freeze"); @@ -382,25 +382,25 @@ void registerBuiltinGlobals(TypeChecker& typeChecker) void registerBuiltinGlobals(Frontend& frontend) { - LUAU_ASSERT(!frontend.globalTypes.typeVars.isFrozen()); + LUAU_ASSERT(!frontend.globalTypes.types.isFrozen()); LUAU_ASSERT(!frontend.globalTypes.typePacks.isFrozen()); if (FFlag::LuauReportShadowedTypeAlias) registerBuiltinTypes(frontend); TypeArena& arena = frontend.globalTypes; - NotNull singletonTypes = frontend.singletonTypes; + NotNull builtinTypes = frontend.builtinTypes; LoadDefinitionFileResult loadResult = frontend.loadDefinitionFile(getBuiltinDefinitionSource(), "@luau"); LUAU_ASSERT(loadResult.success); - TypeId genericK = arena.addType(GenericTypeVar{"K"}); - TypeId genericV = arena.addType(GenericTypeVar{"V"}); - TypeId mapOfKtoV = arena.addType(TableTypeVar{{}, TableIndexer(genericK, genericV), frontend.getGlobalScope()->level, TableState::Generic}); + TypeId genericK = arena.addType(GenericType{"K"}); + TypeId genericV = arena.addType(GenericType{"V"}); + TypeId mapOfKtoV = arena.addType(TableType{{}, TableIndexer(genericK, genericV), frontend.getGlobalScope()->level, TableState::Generic}); - std::optional stringMetatableTy = getMetatable(singletonTypes->stringType, singletonTypes); + std::optional stringMetatableTy = getMetatable(builtinTypes->stringType, builtinTypes); LUAU_ASSERT(stringMetatableTy); - const TableTypeVar* stringMetatableTable = get(follow(*stringMetatableTy)); + const TableType* stringMetatableTable = get(follow(*stringMetatableTy)); LUAU_ASSERT(stringMetatableTable); auto it = stringMetatableTable->props.find("__index"); @@ -413,40 +413,38 @@ void registerBuiltinGlobals(Frontend& frontend) // next(t: Table, i: K?) -> (K?, V) TypePackId nextArgsTypePack = arena.addTypePack(TypePack{{mapOfKtoV, makeOption(frontend, arena, genericK)}}); TypePackId nextRetsTypePack = arena.addTypePack(TypePack{{makeOption(frontend, arena, genericK), genericV}}); - addGlobalBinding(frontend, "next", arena.addType(FunctionTypeVar{{genericK, genericV}, {}, nextArgsTypePack, nextRetsTypePack}), "@luau"); + addGlobalBinding(frontend, "next", arena.addType(FunctionType{{genericK, genericV}, {}, nextArgsTypePack, nextRetsTypePack}), "@luau"); TypePackId pairsArgsTypePack = arena.addTypePack({mapOfKtoV}); - TypeId pairsNext = arena.addType(FunctionTypeVar{nextArgsTypePack, nextRetsTypePack}); - TypePackId pairsReturnTypePack = arena.addTypePack(TypePack{{pairsNext, mapOfKtoV, frontend.singletonTypes->nilType}}); + TypeId pairsNext = arena.addType(FunctionType{nextArgsTypePack, nextRetsTypePack}); + TypePackId pairsReturnTypePack = arena.addTypePack(TypePack{{pairsNext, mapOfKtoV, frontend.builtinTypes->nilType}}); // pairs(t: Table) -> ((Table, K?) -> (K?, V), Table, nil) - addGlobalBinding( - frontend, "pairs", arena.addType(FunctionTypeVar{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau"); + addGlobalBinding(frontend, "pairs", arena.addType(FunctionType{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau"); } else { // next(t: Table, i: K?) -> (K, V) TypePackId nextArgsTypePack = arena.addTypePack(TypePack{{mapOfKtoV, makeOption(frontend, arena, genericK)}}); addGlobalBinding(frontend, "next", - arena.addType(FunctionTypeVar{{genericK, genericV}, {}, nextArgsTypePack, arena.addTypePack(TypePack{{genericK, genericV}})}), "@luau"); + arena.addType(FunctionType{{genericK, genericV}, {}, nextArgsTypePack, arena.addTypePack(TypePack{{genericK, genericV}})}), "@luau"); TypePackId pairsArgsTypePack = arena.addTypePack({mapOfKtoV}); - TypeId pairsNext = arena.addType(FunctionTypeVar{nextArgsTypePack, arena.addTypePack(TypePack{{genericK, genericV}})}); - TypePackId pairsReturnTypePack = arena.addTypePack(TypePack{{pairsNext, mapOfKtoV, frontend.singletonTypes->nilType}}); + TypeId pairsNext = arena.addType(FunctionType{nextArgsTypePack, arena.addTypePack(TypePack{{genericK, genericV}})}); + TypePackId pairsReturnTypePack = arena.addTypePack(TypePack{{pairsNext, mapOfKtoV, frontend.builtinTypes->nilType}}); // pairs(t: Table) -> ((Table, K?) -> (K, V), Table, nil) - addGlobalBinding( - frontend, "pairs", arena.addType(FunctionTypeVar{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau"); + addGlobalBinding(frontend, "pairs", arena.addType(FunctionType{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau"); } - TypeId genericMT = arena.addType(GenericTypeVar{"MT"}); + TypeId genericMT = arena.addType(GenericType{"MT"}); - TableTypeVar tab{TableState::Generic, frontend.getGlobalScope()->level}; + TableType tab{TableState::Generic, frontend.getGlobalScope()->level}; TypeId tabTy = arena.addType(tab); - TypeId tableMetaMT = arena.addType(MetatableTypeVar{tabTy, genericMT}); + TypeId tableMetaMT = arena.addType(MetatableType{tabTy, genericMT}); addGlobalBinding(frontend, "getmetatable", makeFunction(arena, std::nullopt, {genericMT}, {}, {tableMetaMT}, {genericMT}), "@luau"); @@ -454,7 +452,7 @@ void registerBuiltinGlobals(Frontend& frontend) // setmetatable(T, MT) -> { @metatable MT, T } addGlobalBinding(frontend, "setmetatable", arena.addType( - FunctionTypeVar{ + FunctionType{ {genericMT}, {}, arena.addTypePack(TypePack{{FFlag::LuauUnknownAndNeverType ? tabTy : tableMetaMT, genericMT}}), @@ -468,7 +466,7 @@ void registerBuiltinGlobals(Frontend& frontend) { persist(pair.second.typeId); - if (TableTypeVar* ttv = getMutable(pair.second.typeId)) + if (TableType* ttv = getMutable(pair.second.typeId)) { if (!ttv->name) { @@ -486,7 +484,7 @@ void registerBuiltinGlobals(Frontend& frontend) attachMagicFunction(getGlobalBinding(frontend, "select"), magicFunctionSelect); attachDcrMagicFunction(getGlobalBinding(frontend, "select"), dcrMagicFunctionSelect); - if (TableTypeVar* ttv = getMutable(getGlobalBinding(frontend, "table"))) + if (TableType* ttv = getMutable(getGlobalBinding(frontend, "table"))) { // tabTy is a generic table type which we can't express via declaration syntax yet ttv->props["freeze"] = makeProperty(makeFunction(arena, std::nullopt, {tabTy}, {tabTy}), "@luau/global/table.freeze"); @@ -576,7 +574,7 @@ static bool dcrMagicFunctionSelect(MagicFunctionCallContext context) { if (str->value.size == 1 && str->value.data[0] == '#') { - TypePackId numberTypePack = context.solver->arena->addTypePack({context.solver->singletonTypes->numberType}); + TypePackId numberTypePack = context.solver->arena->addTypePack({context.solver->builtinTypes->numberType}); asMutable(context.result)->ty.emplace(numberTypePack); return true; } @@ -609,7 +607,7 @@ static std::optional> magicFunctionSetMetaTable( typechecker.tablify(mt); } - if (const auto& tab = get(target)) + if (const auto& tab = get(target)) { if (target->persistent) { @@ -620,8 +618,8 @@ static std::optional> magicFunctionSetMetaTable( if (!FFlag::LuauUnknownAndNeverType) typechecker.tablify(mt); - const TableTypeVar* mtTtv = get(mt); - MetatableTypeVar mtv{target, mt}; + const TableType* mtTtv = get(mt); + MetatableType mtv{target, mt}; if ((tab->name || tab->syntheticName) && (mtTtv && (mtTtv->name || mtTtv->syntheticName))) { std::string tableName = tab->name ? *tab->name : *tab->syntheticName; @@ -656,7 +654,7 @@ static std::optional> magicFunctionSetMetaTable( return WithPredicate{arena.addTypePack({mtTy})}; } } - else if (get(target) || get(target) || isTableIntersection(target)) + else if (get(target) || get(target) || isTableIntersection(target)) { } else @@ -687,10 +685,10 @@ static std::optional> magicFunctionAssert( if (head.size() > 0) { - auto [ty, ok] = typechecker.pickTypesFromSense(head[0], true, typechecker.singletonTypes->nilType); + auto [ty, ok] = typechecker.pickTypesFromSense(head[0], true, typechecker.builtinTypes->nilType); if (FFlag::LuauUnknownAndNeverType) { - if (get(*ty)) + if (get(*ty)) head = {*ty}; else head[0] = *ty; @@ -747,10 +745,10 @@ static std::optional> magicFunctionPack( else if (options.size() == 1) result = options[0]; else - result = arena.addType(UnionTypeVar{std::move(options)}); + result = arena.addType(UnionType{std::move(options)}); - TypeId packedTable = arena.addType( - TableTypeVar{{{"n", {typechecker.numberType}}}, TableIndexer(typechecker.numberType, result), scope->level, TableState::Sealed}); + TypeId packedTable = + arena.addType(TableType{{{"n", {typechecker.numberType}}}, TableIndexer(typechecker.numberType, result), scope->level, TableState::Sealed}); return WithPredicate{arena.addTypePack({packedTable})}; } @@ -780,14 +778,14 @@ static bool dcrMagicFunctionPack(MagicFunctionCallContext context) // table.pack(1, "foo") -> {| n: number, [number]: number | string |} TypeId result = nullptr; if (options.empty()) - result = context.solver->singletonTypes->nilType; + result = context.solver->builtinTypes->nilType; else if (options.size() == 1) result = options[0]; else - result = arena->addType(UnionTypeVar{std::move(options)}); + result = arena->addType(UnionType{std::move(options)}); - TypeId numberType = context.solver->singletonTypes->numberType; - TypeId packedTable = arena->addType(TableTypeVar{{{"n", {numberType}}}, TableIndexer(numberType, result), {}, TableState::Sealed}); + TypeId numberType = context.solver->builtinTypes->numberType; + TypeId packedTable = arena->addType(TableType{{{"n", {numberType}}}, TableIndexer(numberType, result), {}, TableState::Sealed}); TypePackId tableTypePack = arena->addTypePack({packedTable}); asMutable(context.result)->ty.emplace(tableTypePack); diff --git a/Analysis/src/Clone.cpp b/Analysis/src/Clone.cpp index 86e1c7fc..870d2949 100644 --- a/Analysis/src/Clone.cpp +++ b/Analysis/src/Clone.cpp @@ -48,21 +48,21 @@ struct TypeCloner void operator()(const Unifiable::Generic& t); void operator()(const Unifiable::Bound& t); void operator()(const Unifiable::Error& t); - void operator()(const BlockedTypeVar& t); - void operator()(const PendingExpansionTypeVar& t); - void operator()(const PrimitiveTypeVar& t); - void operator()(const SingletonTypeVar& t); - void operator()(const FunctionTypeVar& t); - void operator()(const TableTypeVar& t); - void operator()(const MetatableTypeVar& t); - void operator()(const ClassTypeVar& t); - void operator()(const AnyTypeVar& t); - void operator()(const UnionTypeVar& t); - void operator()(const IntersectionTypeVar& t); - void operator()(const LazyTypeVar& t); - void operator()(const UnknownTypeVar& t); - void operator()(const NeverTypeVar& t); - void operator()(const NegationTypeVar& t); + void operator()(const BlockedType& t); + void operator()(const PendingExpansionType& t); + void operator()(const PrimitiveType& t); + void operator()(const SingletonType& t); + void operator()(const FunctionType& t); + void operator()(const TableType& t); + void operator()(const MetatableType& t); + void operator()(const ClassType& t); + void operator()(const AnyType& t); + void operator()(const UnionType& t); + void operator()(const IntersectionType& t); + void operator()(const LazyType& t); + void operator()(const UnknownType& t); + void operator()(const NeverType& t); + void operator()(const NegationType& t); }; struct TypePackCloner @@ -107,7 +107,7 @@ struct TypePackCloner defaultClone(t); } - // While we are a-cloning, we can flatten out bound TypeVars and make things a bit tighter. + // While we are a-cloning, we can flatten out bound Types and make things a bit tighter. // We just need to be sure that we rewrite pointers both to the binder and the bindee to the same pointer. void operator()(const Unifiable::Bound& t) { @@ -159,7 +159,7 @@ void TypeCloner::operator()(const Unifiable::Bound& t) { TypeId boundTo = clone(t.boundTo, dest, cloneState); if (FFlag::DebugLuauCopyBeforeNormalizing) - boundTo = dest.addType(BoundTypeVar{boundTo}); + boundTo = dest.addType(BoundType{boundTo}); seenTypes[typeId] = boundTo; } @@ -168,15 +168,15 @@ void TypeCloner::operator()(const Unifiable::Error& t) defaultClone(t); } -void TypeCloner::operator()(const BlockedTypeVar& t) +void TypeCloner::operator()(const BlockedType& t) { defaultClone(t); } -void TypeCloner::operator()(const PendingExpansionTypeVar& t) +void TypeCloner::operator()(const PendingExpansionType& t) { - TypeId res = dest.addType(PendingExpansionTypeVar{t.prefix, t.name, t.typeArguments, t.packArguments}); - PendingExpansionTypeVar* petv = getMutable(res); + TypeId res = dest.addType(PendingExpansionType{t.prefix, t.name, t.typeArguments, t.packArguments}); + PendingExpansionType* petv = getMutable(res); LUAU_ASSERT(petv); seenTypes[typeId] = res; @@ -193,23 +193,23 @@ void TypeCloner::operator()(const PendingExpansionTypeVar& t) petv->packArguments = std::move(packArguments); } -void TypeCloner::operator()(const PrimitiveTypeVar& t) +void TypeCloner::operator()(const PrimitiveType& t) { defaultClone(t); } -void TypeCloner::operator()(const SingletonTypeVar& t) +void TypeCloner::operator()(const SingletonType& t) { defaultClone(t); } -void TypeCloner::operator()(const FunctionTypeVar& t) +void TypeCloner::operator()(const FunctionType& t) { // FISHY: We always erase the scope when we clone things. clone() was // originally written so that we could copy a module's type surface into an // export arena. This probably dates to that. - TypeId result = dest.addType(FunctionTypeVar{TypeLevel{0, 0}, {}, {}, nullptr, nullptr, t.definition, t.hasSelf}); - FunctionTypeVar* ftv = getMutable(result); + TypeId result = dest.addType(FunctionType{TypeLevel{0, 0}, {}, {}, nullptr, nullptr, t.definition, t.hasSelf}); + FunctionType* ftv = getMutable(result); LUAU_ASSERT(ftv != nullptr); seenTypes[typeId] = result; @@ -227,7 +227,7 @@ void TypeCloner::operator()(const FunctionTypeVar& t) ftv->hasNoGenerics = t.hasNoGenerics; } -void TypeCloner::operator()(const TableTypeVar& t) +void TypeCloner::operator()(const TableType& t) { // If table is now bound to another one, we ignore the content of the original if (!FFlag::DebugLuauCopyBeforeNormalizing && t.boundTo) @@ -237,8 +237,8 @@ void TypeCloner::operator()(const TableTypeVar& t) return; } - TypeId result = dest.addType(TableTypeVar{}); - TableTypeVar* ttv = getMutable(result); + TypeId result = dest.addType(TableType{}); + TableType* ttv = getMutable(result); LUAU_ASSERT(ttv != nullptr); *ttv = t; @@ -266,20 +266,20 @@ void TypeCloner::operator()(const TableTypeVar& t) ttv->tags = t.tags; } -void TypeCloner::operator()(const MetatableTypeVar& t) +void TypeCloner::operator()(const MetatableType& t) { - TypeId result = dest.addType(MetatableTypeVar{}); - MetatableTypeVar* mtv = getMutable(result); + TypeId result = dest.addType(MetatableType{}); + MetatableType* mtv = getMutable(result); seenTypes[typeId] = result; mtv->table = clone(t.table, dest, cloneState); mtv->metatable = clone(t.metatable, dest, cloneState); } -void TypeCloner::operator()(const ClassTypeVar& t) +void TypeCloner::operator()(const ClassType& t) { - TypeId result = dest.addType(ClassTypeVar{t.name, {}, std::nullopt, std::nullopt, t.tags, t.userData, t.definitionModuleName}); - ClassTypeVar* ctv = getMutable(result); + TypeId result = dest.addType(ClassType{t.name, {}, std::nullopt, std::nullopt, t.tags, t.userData, t.definitionModuleName}); + ClassType* ctv = getMutable(result); seenTypes[typeId] = result; @@ -293,12 +293,12 @@ void TypeCloner::operator()(const ClassTypeVar& t) ctv->metatable = clone(*t.metatable, dest, cloneState); } -void TypeCloner::operator()(const AnyTypeVar& t) +void TypeCloner::operator()(const AnyType& t) { defaultClone(t); } -void TypeCloner::operator()(const UnionTypeVar& t) +void TypeCloner::operator()(const UnionType& t) { std::vector options; options.reserve(t.options.size()); @@ -306,44 +306,44 @@ void TypeCloner::operator()(const UnionTypeVar& t) for (TypeId ty : t.options) options.push_back(clone(ty, dest, cloneState)); - TypeId result = dest.addType(UnionTypeVar{std::move(options)}); + TypeId result = dest.addType(UnionType{std::move(options)}); seenTypes[typeId] = result; } -void TypeCloner::operator()(const IntersectionTypeVar& t) +void TypeCloner::operator()(const IntersectionType& t) { - TypeId result = dest.addType(IntersectionTypeVar{}); + TypeId result = dest.addType(IntersectionType{}); seenTypes[typeId] = result; - IntersectionTypeVar* option = getMutable(result); + IntersectionType* option = getMutable(result); LUAU_ASSERT(option != nullptr); for (TypeId ty : t.parts) option->parts.push_back(clone(ty, dest, cloneState)); } -void TypeCloner::operator()(const LazyTypeVar& t) +void TypeCloner::operator()(const LazyType& t) { defaultClone(t); } -void TypeCloner::operator()(const UnknownTypeVar& t) +void TypeCloner::operator()(const UnknownType& t) { defaultClone(t); } -void TypeCloner::operator()(const NeverTypeVar& t) +void TypeCloner::operator()(const NeverType& t) { defaultClone(t); } -void TypeCloner::operator()(const NegationTypeVar& t) +void TypeCloner::operator()(const NegationType& t) { - TypeId result = dest.addType(AnyTypeVar{}); + TypeId result = dest.addType(AnyType{}); seenTypes[typeId] = result; TypeId ty = clone(t.ty, dest, cloneState); - asMutable(result)->ty = NegationTypeVar{ty}; + asMutable(result)->ty = NegationType{ty}; } } // anonymous namespace @@ -430,9 +430,9 @@ TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool alwaysCl if (auto pty = log->pending(ty)) ty = &pty->pending; - if (const FunctionTypeVar* ftv = get(ty)) + if (const FunctionType* ftv = get(ty)) { - FunctionTypeVar clone = FunctionTypeVar{ftv->level, ftv->scope, ftv->argTypes, ftv->retTypes, ftv->definition, ftv->hasSelf}; + FunctionType clone = FunctionType{ftv->level, ftv->scope, ftv->argTypes, ftv->retTypes, ftv->definition, ftv->hasSelf}; clone.generics = ftv->generics; clone.genericPacks = ftv->genericPacks; clone.magicFunction = ftv->magicFunction; @@ -441,10 +441,10 @@ TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool alwaysCl clone.argNames = ftv->argNames; result = dest.addType(std::move(clone)); } - else if (const TableTypeVar* ttv = get(ty)) + else if (const TableType* ttv = get(ty)) { LUAU_ASSERT(!ttv->boundTo); - TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, ttv->level, ttv->scope, ttv->state}; + TableType clone = TableType{ttv->props, ttv->indexer, ttv->level, ttv->scope, ttv->state}; clone.definitionModuleName = ttv->definitionModuleName; clone.name = ttv->name; clone.syntheticName = ttv->syntheticName; @@ -453,41 +453,41 @@ TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool alwaysCl clone.tags = ttv->tags; result = dest.addType(std::move(clone)); } - else if (const MetatableTypeVar* mtv = get(ty)) + else if (const MetatableType* mtv = get(ty)) { - MetatableTypeVar clone = MetatableTypeVar{mtv->table, mtv->metatable}; + MetatableType clone = MetatableType{mtv->table, mtv->metatable}; clone.syntheticName = mtv->syntheticName; result = dest.addType(std::move(clone)); } - else if (const UnionTypeVar* utv = get(ty)) + else if (const UnionType* utv = get(ty)) { - UnionTypeVar clone; + UnionType clone; clone.options = utv->options; result = dest.addType(std::move(clone)); } - else if (const IntersectionTypeVar* itv = get(ty)) + else if (const IntersectionType* itv = get(ty)) { - IntersectionTypeVar clone; + IntersectionType clone; clone.parts = itv->parts; result = dest.addType(std::move(clone)); } - else if (const PendingExpansionTypeVar* petv = get(ty)) + else if (const PendingExpansionType* petv = get(ty)) { - PendingExpansionTypeVar clone{petv->prefix, petv->name, petv->typeArguments, petv->packArguments}; + PendingExpansionType clone{petv->prefix, petv->name, petv->typeArguments, petv->packArguments}; result = dest.addType(std::move(clone)); } - else if (const ClassTypeVar* ctv = get(ty); FFlag::LuauClonePublicInterfaceLess && ctv && alwaysClone) + else if (const ClassType* ctv = get(ty); FFlag::LuauClonePublicInterfaceLess && ctv && alwaysClone) { - ClassTypeVar clone{ctv->name, ctv->props, ctv->parent, ctv->metatable, ctv->tags, ctv->userData, ctv->definitionModuleName}; + ClassType clone{ctv->name, ctv->props, ctv->parent, ctv->metatable, ctv->tags, ctv->userData, ctv->definitionModuleName}; result = dest.addType(std::move(clone)); } else if (FFlag::LuauClonePublicInterfaceLess && alwaysClone) { result = dest.addType(*ty); } - else if (const NegationTypeVar* ntv = get(ty)) + else if (const NegationType* ntv = get(ty)) { - result = dest.addType(NegationTypeVar{ntv->ty}); + result = dest.addType(NegationType{ntv->ty}); } else return result; diff --git a/Analysis/src/ConstraintGraphBuilder.cpp b/Analysis/src/ConstraintGraphBuilder.cpp index f0bd958c..256eba54 100644 --- a/Analysis/src/ConstraintGraphBuilder.cpp +++ b/Analysis/src/ConstraintGraphBuilder.cpp @@ -9,11 +9,12 @@ #include "Luau/RecursionCounter.h" #include "Luau/Scope.h" #include "Luau/TypeUtils.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" LUAU_FASTINT(LuauCheckRecursionLimit); LUAU_FASTFLAG(DebugLuauLogSolverToJson); LUAU_FASTFLAG(DebugLuauMagicTypes); +LUAU_FASTFLAG(LuauNegatedClassTypes); namespace Luau { @@ -116,11 +117,11 @@ void forEachConstraint(const Checkpoint& start, const Checkpoint& end, const Con } // namespace ConstraintGraphBuilder::ConstraintGraphBuilder(const ModuleName& moduleName, ModulePtr module, TypeArena* arena, - NotNull moduleResolver, NotNull singletonTypes, NotNull ice, const ScopePtr& globalScope, + NotNull moduleResolver, NotNull builtinTypes, NotNull ice, const ScopePtr& globalScope, DcrLogger* logger, NotNull dfg) : moduleName(moduleName) , module(module) - , singletonTypes(singletonTypes) + , builtinTypes(builtinTypes) , arena(arena) , rootScope(nullptr) , dfg(dfg) @@ -137,7 +138,7 @@ ConstraintGraphBuilder::ConstraintGraphBuilder(const ModuleName& moduleName, Mod TypeId ConstraintGraphBuilder::freshType(const ScopePtr& scope) { - return arena->addType(FreeTypeVar{scope.get()}); + return arena->addType(FreeType{scope.get()}); } TypePackId ConstraintGraphBuilder::freshTypePack(const ScopePtr& scope) @@ -184,7 +185,7 @@ static void unionRefinements(const std::unordered_map& lhs, const if (auto destIt = dest.find(def); destIt != dest.end()) discriminants.push_back(destIt->second); - dest[def] = arena->addType(UnionTypeVar{std::move(discriminants)}); + dest[def] = arena->addType(UnionType{std::move(discriminants)}); } } @@ -228,15 +229,15 @@ static void computeRefinement(const ScopePtr& scope, ConnectiveId connective, st { TypeId discriminantTy = proposition->discriminantTy; if (!sense && !eq) - discriminantTy = arena->addType(NegationTypeVar{proposition->discriminantTy}); + discriminantTy = arena->addType(NegationType{proposition->discriminantTy}); else if (eq) { - discriminantTy = arena->addType(BlockedTypeVar{}); + discriminantTy = arena->addType(BlockedType{}); constraints->push_back(SingletonOrTopTypeConstraint{discriminantTy, proposition->discriminantTy, !sense}); } if (auto it = refis->find(proposition->def); it != refis->end()) - (*refis)[proposition->def] = arena->addType(IntersectionTypeVar{{discriminantTy, it->second}}); + (*refis)[proposition->def] = arena->addType(IntersectionType{{discriminantTy, it->second}}); else (*refis)[proposition->def] = discriminantTy; } @@ -251,8 +252,8 @@ static std::pair computeDiscriminantType(NotNull arena if (!current->field) break; - TableTypeVar::Props props{{current->field->propName, Property{discriminantTy}}}; - discriminantTy = arena->addType(TableTypeVar{std::move(props), std::nullopt, TypeLevel{}, scope.get(), TableState::Sealed}); + TableType::Props props{{current->field->propName, Property{discriminantTy}}}; + discriminantTy = arena->addType(TableType{std::move(props), std::nullopt, TypeLevel{}, scope.get(), TableState::Sealed}); def = current->field->parent; current = get(def); @@ -277,7 +278,7 @@ void ConstraintGraphBuilder::applyRefinements(const ScopePtr& scope, Location lo if (!defTy) ice->ice("Every DefId must map to a type!"); - TypeId resultTy = arena->addType(IntersectionTypeVar{{*defTy, discriminantTy2}}); + TypeId resultTy = arena->addType(IntersectionType{{*defTy, discriminantTy2}}); scope->dcrRefinements[def2] = resultTy; } @@ -464,7 +465,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocal* local) if (i < local->vars.size) { - TypePack packTypes = extendTypePack(*arena, singletonTypes, exprPack, varTypes.size() - i); + TypePack packTypes = extendTypePack(*arena, builtinTypes, exprPack, varTypes.size() - i); // fill out missing values in varTypes with values from exprPack for (size_t j = i; j < varTypes.size(); ++j) @@ -533,7 +534,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFor* for_) return; TypeId t = check(scope, expr).ty; - addConstraint(scope, expr->location, SubtypeConstraint{t, singletonTypes->numberType}); + addConstraint(scope, expr->location, SubtypeConstraint{t, builtinTypes->numberType}); }; checkNumber(for_->from); @@ -541,7 +542,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFor* for_) checkNumber(for_->step); ScopePtr forScope = childScope(for_, scope); - forScope->bindings[for_->var] = Binding{singletonTypes->numberType, for_->var->location}; + forScope->bindings[for_->var] = Binding{builtinTypes->numberType, for_->var->location}; visit(forScope, for_->body); } @@ -603,7 +604,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocalFunction* auto ty = scope->lookup(function->name); LUAU_ASSERT(!ty.has_value()); // The parser ensures that every local function has a distinct Symbol for its name. - functionType = arena->addType(BlockedTypeVar{}); + functionType = arena->addType(BlockedType{}); scope->bindings[function->name] = Binding{functionType, function->name->location}; FunctionSignature sig = checkFunctionSignature(scope, function->func); @@ -629,7 +630,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction* funct // Name could be AstStatLocal, AstStatGlobal, AstStatIndexName. // With or without self - TypeId generalizedType = arena->addType(BlockedTypeVar{}); + TypeId generalizedType = arena->addType(BlockedType{}); FunctionSignature sig = checkFunctionSignature(scope, function->func); @@ -666,9 +667,9 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction* funct TypeId containingTableType = check(scope, indexName->expr).ty; // TODO look into stack utilization. This is probably ok because it scales with AST depth. - TypeId prospectiveTableType = arena->addType(TableTypeVar{TableState::Unsealed, TypeLevel{}, scope.get()}); + TypeId prospectiveTableType = arena->addType(TableType{TableState::Unsealed, TypeLevel{}, scope.get()}); - NotNull prospectiveTable{getMutable(prospectiveTableType)}; + NotNull prospectiveTable{getMutable(prospectiveTableType)}; Property& prop = prospectiveTable->props[indexName->index.value]; prop.type = generalizedType; @@ -678,7 +679,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction* funct } else if (AstExprError* err = function->name->as()) { - generalizedType = singletonTypes->errorRecoveryType(); + generalizedType = builtinTypes->errorRecoveryType(); } if (generalizedType == nullptr) @@ -724,7 +725,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatAssign* assign) { TypePackId varPackId = checkLValues(scope, assign->vars); - TypePack expectedTypes = extendTypePack(*arena, singletonTypes, varPackId, assign->values.size); + TypePack expectedTypes = extendTypePack(*arena, builtinTypes, varPackId, assign->values.size); TypePackId valuePack = checkPack(scope, assign->values, expectedTypes.head).tp; addConstraint(scope, assign->location, PackSubtypeConstraint{valuePack, varPackId}); @@ -781,13 +782,13 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatTypeAlias* alia scope->exportedTypeBindings[typeName] = TypeFun{ty}; } - LUAU_ASSERT(get(bindingIt->second.type)); + LUAU_ASSERT(get(bindingIt->second.type)); // Rather than using a subtype constraint, we instead directly bind // the free type we generated in the first pass to the resolved type. // This prevents a case where you could cause another constraint to // bind the free alias type to an unrelated type, causing havoc. - asMutable(bindingIt->second.type)->ty.emplace(ty); + asMutable(bindingIt->second.type)->ty.emplace(ty); addConstraint(scope, alias->location, NameConstraint{ty, alias->name.value}); } @@ -812,7 +813,7 @@ static bool isMetamethod(const Name& name) void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareClass* declaredClass) { - std::optional superTy = std::nullopt; + std::optional superTy = FFlag::LuauNegatedClassTypes ? std::make_optional(builtinTypes->classType) : std::nullopt; if (declaredClass->superName) { Name superName = Name(declaredClass->superName->value); @@ -828,7 +829,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareClass* d LUAU_ASSERT(lookupType->typeParams.size() == 0 && lookupType->typePackParams.size() == 0); superTy = lookupType->type; - if (!get(follow(*superTy))) + if (!get(follow(*superTy))) { reportError(declaredClass->location, GenericError{format("Cannot use non-class type '%s' as a superclass of class '%s'", superName.c_str(), declaredClass->name.value)}); @@ -839,11 +840,11 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareClass* d Name className(declaredClass->name.value); - TypeId classTy = arena->addType(ClassTypeVar(className, {}, superTy, std::nullopt, {}, {}, moduleName)); - ClassTypeVar* ctv = getMutable(classTy); + TypeId classTy = arena->addType(ClassType(className, {}, superTy, std::nullopt, {}, {}, moduleName)); + ClassType* ctv = getMutable(classTy); - TypeId metaTy = arena->addType(TableTypeVar{TableState::Sealed, scope->level, scope.get()}); - TableTypeVar* metatable = getMutable(metaTy); + TypeId metaTy = arena->addType(TableType{TableState::Sealed, scope->level, scope.get()}); + TableType* metatable = getMutable(metaTy); ctv->metatable = metaTy; @@ -860,7 +861,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareClass* d // parsed annotation. Add it here. if (prop.isMethod) { - if (FunctionTypeVar* ftv = getMutable(propTy)) + if (FunctionType* ftv = getMutable(propTy)) { ftv->argNames.insert(ftv->argNames.begin(), FunctionArgument{"self", {}}); ftv->argTypes = arena->addTypePack(TypePack{{classTy}, ftv->argTypes}); @@ -882,20 +883,20 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareClass* d // We special-case this logic to keep the intersection flat; otherwise we // would create a ton of nested intersection types. - if (const IntersectionTypeVar* itv = get(currentTy)) + if (const IntersectionType* itv = get(currentTy)) { std::vector options = itv->parts; options.push_back(propTy); - TypeId newItv = arena->addType(IntersectionTypeVar{std::move(options)}); + TypeId newItv = arena->addType(IntersectionType{std::move(options)}); if (assignToMetatable) metatable->props[propName] = {newItv}; else ctv->props[propName] = {newItv}; } - else if (get(currentTy)) + else if (get(currentTy)) { - TypeId intersection = arena->addType(IntersectionTypeVar{{currentTy, propTy}}); + TypeId intersection = arena->addType(IntersectionType{{currentTy, propTy}}); if (assignToMetatable) metatable->props[propName] = {intersection}; @@ -937,8 +938,8 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareFunction TypePackId paramPack = resolveTypePack(funScope, global->params); TypePackId retPack = resolveTypePack(funScope, global->retTypes); - TypeId fnType = arena->addType(FunctionTypeVar{TypeLevel{}, funScope.get(), std::move(genericTys), std::move(genericTps), paramPack, retPack}); - FunctionTypeVar* ftv = getMutable(fnType); + TypeId fnType = arena->addType(FunctionType{TypeLevel{}, funScope.get(), std::move(genericTys), std::move(genericTps), paramPack, retPack}); + FunctionType* ftv = getMutable(fnType); ftv->argNames.reserve(global->paramNames.size); for (const auto& el : global->paramNames) @@ -995,7 +996,7 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExpr* if (recursionCount >= FInt::LuauCheckRecursionLimit) { reportCodeTooComplex(expr->location); - return InferencePack{singletonTypes->errorRecoveryTypePack()}; + return InferencePack{builtinTypes->errorRecoveryTypePack()}; } InferencePack result; @@ -1007,7 +1008,7 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExpr* if (scope->varargPack) result = InferencePack{*scope->varargPack}; else - result = InferencePack{singletonTypes->errorRecoveryTypePack()}; + result = InferencePack{builtinTypes->errorRecoveryTypePack()}; } else { @@ -1042,9 +1043,9 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa TypePackId expectedArgPack = arena->freshTypePack(scope.get()); TypePackId expectedRetPack = arena->freshTypePack(scope.get()); - TypeId expectedFunctionType = arena->addType(FunctionTypeVar{expectedArgPack, expectedRetPack}); + TypeId expectedFunctionType = arena->addType(FunctionType{expectedArgPack, expectedRetPack}); - TypeId instantiatedFnType = arena->addType(BlockedTypeVar{}); + TypeId instantiatedFnType = arena->addType(BlockedType{}); addConstraint(scope, call->location, InstantiationConstraint{instantiatedFnType, fnType}); NotNull extractArgsConstraint = addConstraint(scope, call->location, SubtypeConstraint{instantiatedFnType, expectedFunctionType}); @@ -1060,9 +1061,9 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa TypePack expectedArgs; if (!needTail) - expectedArgs = extendTypePack(*arena, singletonTypes, expectedArgPack, exprArgs.size()); + expectedArgs = extendTypePack(*arena, builtinTypes, expectedArgPack, exprArgs.size()); else - expectedArgs = extendTypePack(*arena, singletonTypes, expectedArgPack, exprArgs.size() - 1); + expectedArgs = extendTypePack(*arena, builtinTypes, expectedArgPack, exprArgs.size() - 1); std::vector args; std::optional argTail; @@ -1108,7 +1109,7 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa }); std::vector returnConnectives; - if (auto ftv = get(follow(fnType)); ftv && ftv->dcrMagicRefinement) + if (auto ftv = get(follow(fnType)); ftv && ftv->dcrMagicRefinement) { MagicRefinementContext ctx{scope, NotNull{this}, dfg, NotNull{&connectiveArena}, std::move(argumentConnectives), call}; returnConnectives = ftv->dcrMagicRefinement(ctx); @@ -1118,7 +1119,7 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa { TypePack argTailPack; if (argTail && args.size() < 2) - argTailPack = extendTypePack(*arena, singletonTypes, *argTail, 2 - args.size()); + argTailPack = extendTypePack(*arena, builtinTypes, *argTail, 2 - args.size()); LUAU_ASSERT(args.size() + argTailPack.head.size() == 2); @@ -1127,7 +1128,7 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa AstExpr* targetExpr = call->args.data[0]; - MetatableTypeVar mtv{target, mt}; + MetatableType mtv{target, mt}; TypeId resultTy = arena->addType(mtv); if (AstExprLocal* targetLocal = targetExpr->as()) @@ -1139,11 +1140,11 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa { astOriginalCallTypes[call->func] = fnType; - TypeId instantiatedType = arena->addType(BlockedTypeVar{}); + TypeId instantiatedType = arena->addType(BlockedType{}); // TODO: How do expectedTypes play into this? Do they? TypePackId rets = arena->addTypePack(BlockedTypePack{}); TypePackId argPack = arena->addTypePack(TypePack{args, argTail}); - FunctionTypeVar ftv(TypeLevel{}, scope.get(), argPack, rets); + FunctionType ftv(TypeLevel{}, scope.get(), argPack, rets); TypeId inferredFnType = arena->addType(ftv); unqueuedConstraints.push_back( @@ -1183,7 +1184,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExpr* expr, st if (recursionCount >= FInt::LuauCheckRecursionLimit) { reportCodeTooComplex(expr->location); - return Inference{singletonTypes->errorRecoveryType()}; + return Inference{builtinTypes->errorRecoveryType()}; } Inference result; @@ -1193,11 +1194,11 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExpr* expr, st else if (auto stringExpr = expr->as()) result = check(scope, stringExpr, expectedType, forceSingleton); else if (expr->is()) - result = Inference{singletonTypes->numberType}; + result = Inference{builtinTypes->numberType}; else if (auto boolExpr = expr->as()) result = check(scope, boolExpr, expectedType, forceSingleton); else if (expr->is()) - result = Inference{singletonTypes->nilType}; + result = Inference{builtinTypes->nilType}; else if (auto local = expr->as()) result = check(scope, local); else if (auto global = expr->as()) @@ -1218,7 +1219,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExpr* expr, st checkFunctionBody(sig.bodyScope, a); Checkpoint endCheckpoint = checkpoint(this); - TypeId generalizedTy = arena->addType(BlockedTypeVar{}); + TypeId generalizedTy = arena->addType(BlockedType{}); NotNull gc = addConstraint(scope, expr->location, GeneralizationConstraint{generalizedTy, sig.signature}); forEachConstraint(startCheckpoint, endCheckpoint, this, [gc](const ConstraintPtr& constraint) { @@ -1247,7 +1248,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExpr* expr, st for (AstExpr* subExpr : err->expressions) check(scope, subExpr); - result = Inference{singletonTypes->errorRecoveryType()}; + result = Inference{builtinTypes->errorRecoveryType()}; } else { @@ -1263,30 +1264,30 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExpr* expr, st Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprConstantString* string, std::optional expectedType, bool forceSingleton) { if (forceSingleton) - return Inference{arena->addType(SingletonTypeVar{StringSingleton{std::string{string->value.data, string->value.size}}})}; + return Inference{arena->addType(SingletonType{StringSingleton{std::string{string->value.data, string->value.size}}})}; if (expectedType) { const TypeId expectedTy = follow(*expectedType); - if (get(expectedTy) || get(expectedTy)) + if (get(expectedTy) || get(expectedTy)) { - TypeId ty = arena->addType(BlockedTypeVar{}); - TypeId singletonType = arena->addType(SingletonTypeVar(StringSingleton{std::string(string->value.data, string->value.size)})); - addConstraint(scope, string->location, PrimitiveTypeConstraint{ty, expectedTy, singletonType, singletonTypes->stringType}); + TypeId ty = arena->addType(BlockedType{}); + TypeId singletonType = arena->addType(SingletonType(StringSingleton{std::string(string->value.data, string->value.size)})); + addConstraint(scope, string->location, PrimitiveTypeConstraint{ty, expectedTy, singletonType, builtinTypes->stringType}); return Inference{ty}; } else if (maybeSingleton(expectedTy)) - return Inference{arena->addType(SingletonTypeVar{StringSingleton{std::string{string->value.data, string->value.size}}})}; + return Inference{arena->addType(SingletonType{StringSingleton{std::string{string->value.data, string->value.size}}})}; - return Inference{singletonTypes->stringType}; + return Inference{builtinTypes->stringType}; } - return Inference{singletonTypes->stringType}; + return Inference{builtinTypes->stringType}; } Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprConstantBool* boolExpr, std::optional expectedType, bool forceSingleton) { - const TypeId singletonType = boolExpr->value ? singletonTypes->trueType : singletonTypes->falseType; + const TypeId singletonType = boolExpr->value ? builtinTypes->trueType : builtinTypes->falseType; if (forceSingleton) return Inference{singletonType}; @@ -1294,19 +1295,19 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprConstantBo { const TypeId expectedTy = follow(*expectedType); - if (get(expectedTy) || get(expectedTy)) + if (get(expectedTy) || get(expectedTy)) { - TypeId ty = arena->addType(BlockedTypeVar{}); - addConstraint(scope, boolExpr->location, PrimitiveTypeConstraint{ty, expectedTy, singletonType, singletonTypes->booleanType}); + TypeId ty = arena->addType(BlockedType{}); + addConstraint(scope, boolExpr->location, PrimitiveTypeConstraint{ty, expectedTy, singletonType, builtinTypes->booleanType}); return Inference{ty}; } else if (maybeSingleton(expectedTy)) return Inference{singletonType}; - return Inference{singletonTypes->booleanType}; + return Inference{builtinTypes->booleanType}; } - return Inference{singletonTypes->booleanType}; + return Inference{builtinTypes->booleanType}; } Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprLocal* local) @@ -1323,10 +1324,10 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprLocal* loc } if (!resultTy) - return Inference{singletonTypes->errorRecoveryType()}; // TODO: replace with ice, locals should never exist before its definition. + return Inference{builtinTypes->errorRecoveryType()}; // TODO: replace with ice, locals should never exist before its definition. if (def) - return Inference{*resultTy, connectiveArena.proposition(*def, singletonTypes->truthyType)}; + return Inference{*resultTy, connectiveArena.proposition(*def, builtinTypes->truthyType)}; else return Inference{*resultTy}; } @@ -1340,24 +1341,24 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprGlobal* gl * global that is not already in-scope is definitely an unknown symbol. */ reportError(global->location, UnknownSymbol{global->name.value}); - return Inference{singletonTypes->errorRecoveryType()}; + return Inference{builtinTypes->errorRecoveryType()}; } static std::optional lookupProp(TypeId ty, const std::string& propName, NotNull arena) { ty = follow(ty); - if (auto ctv = get(ty)) + if (auto ctv = get(ty)) { if (auto prop = lookupClassProp(ctv, propName)) return prop->type; } - else if (auto ttv = get(ty)) + else if (auto ttv = get(ty)) { if (auto it = ttv->props.find(propName); it != ttv->props.end()) return it->second.type; } - else if (auto utv = get(ty)) + else if (auto utv = get(ty)) { std::vector types; @@ -1375,9 +1376,9 @@ static std::optional lookupProp(TypeId ty, const std::string& propName, if (types.size() == 1) return types[0]; else - return arena->addType(IntersectionTypeVar{std::move(types)}); + return arena->addType(IntersectionType{std::move(types)}); } - else if (auto utv = get(ty)) + else if (auto utv = get(ty)) { std::vector types; @@ -1395,7 +1396,7 @@ static std::optional lookupProp(TypeId ty, const std::string& propName, if (types.size() == 1) return types[0]; else - return arena->addType(UnionTypeVar{std::move(types)}); + return arena->addType(UnionType{std::move(types)}); } return std::nullopt; @@ -1416,21 +1417,21 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexName* if (def) { if (auto ty = scope->lookup(*def)) - return Inference{*ty, connectiveArena.proposition(*def, singletonTypes->truthyType)}; + return Inference{*ty, connectiveArena.proposition(*def, builtinTypes->truthyType)}; else scope->dcrRefinements[*def] = result; } - TableTypeVar::Props props{{indexName->index.value, Property{result}}}; + TableType::Props props{{indexName->index.value, Property{result}}}; const std::optional indexer; - TableTypeVar ttv{std::move(props), indexer, TypeLevel{}, scope.get(), TableState::Free}; + TableType ttv{std::move(props), indexer, TypeLevel{}, scope.get(), TableState::Free}; TypeId expectedTableType = arena->addType(std::move(ttv)); addConstraint(scope, indexName->expr->location, SubtypeConstraint{obj, expectedTableType}); if (def) - return Inference{result, connectiveArena.proposition(*def, singletonTypes->truthyType)}; + return Inference{result, connectiveArena.proposition(*def, builtinTypes->truthyType)}; else return Inference{result}; } @@ -1443,8 +1444,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexExpr* TypeId result = freshType(scope); TableIndexer indexer{indexType, result}; - TypeId tableType = - arena->addType(TableTypeVar{TableTypeVar::Props{}, TableIndexer{indexType, result}, TypeLevel{}, scope.get(), TableState::Free}); + TypeId tableType = arena->addType(TableType{TableType::Props{}, TableIndexer{indexType, result}, TypeLevel{}, scope.get(), TableState::Free}); addConstraint(scope, indexExpr->expr->location, SubtypeConstraint{obj, tableType}); @@ -1454,7 +1454,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexExpr* Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprUnary* unary) { auto [operandType, connective] = check(scope, unary->expr); - TypeId resultType = arena->addType(BlockedTypeVar{}); + TypeId resultType = arena->addType(BlockedType{}); addConstraint(scope, unary->location, UnaryConstraint{unary->op, operandType, resultType}); if (unary->op == AstExprUnary::Not) @@ -1467,8 +1467,9 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprBinary* bi { auto [leftType, rightType, connective] = checkBinary(scope, binary, expectedType); - TypeId resultType = arena->addType(BlockedTypeVar{}); - addConstraint(scope, binary->location, BinaryConstraint{binary->op, leftType, rightType, resultType, binary, &astOriginalCallTypes, &astOverloadResolvedTypes}); + TypeId resultType = arena->addType(BlockedType{}); + addConstraint(scope, binary->location, + BinaryConstraint{binary->op, leftType, rightType, resultType, binary, &astOriginalCallTypes, &astOverloadResolvedTypes}); return Inference{resultType, std::move(connective)}; } @@ -1534,34 +1535,34 @@ std::tuple ConstraintGraphBuilder::checkBinary( if (!def) return {leftType, rightType, nullptr}; - TypeId discriminantTy = singletonTypes->neverType; + TypeId discriminantTy = builtinTypes->neverType; if (typeguard->type == "nil") - discriminantTy = singletonTypes->nilType; + discriminantTy = builtinTypes->nilType; else if (typeguard->type == "string") - discriminantTy = singletonTypes->stringType; + discriminantTy = builtinTypes->stringType; else if (typeguard->type == "number") - discriminantTy = singletonTypes->numberType; + discriminantTy = builtinTypes->numberType; else if (typeguard->type == "boolean") - discriminantTy = singletonTypes->threadType; + discriminantTy = builtinTypes->threadType; else if (typeguard->type == "table") - discriminantTy = singletonTypes->neverType; // TODO: replace with top table type + discriminantTy = builtinTypes->neverType; // TODO: replace with top table type else if (typeguard->type == "function") - discriminantTy = singletonTypes->functionType; + discriminantTy = builtinTypes->functionType; else if (typeguard->type == "userdata") { // For now, we don't really care about being accurate with userdata if the typeguard was using typeof - discriminantTy = singletonTypes->neverType; // TODO: replace with top class type + discriminantTy = builtinTypes->neverType; // TODO: replace with top class type } else if (!typeguard->isTypeof && typeguard->type == "vector") - discriminantTy = singletonTypes->neverType; // TODO: figure out a way to deal with this quirky type + discriminantTy = builtinTypes->neverType; // TODO: figure out a way to deal with this quirky type else if (!typeguard->isTypeof) - discriminantTy = singletonTypes->neverType; + discriminantTy = builtinTypes->neverType; else if (auto typeFun = globalScope->lookupType(typeguard->type); typeFun && typeFun->typeParams.empty() && typeFun->typePackParams.empty()) { TypeId ty = follow(typeFun->type); // We're only interested in the root class of any classes. - if (auto ctv = get(ty); !ctv || !ctv->parent) + if (auto ctv = get(ty); !ctv || !ctv->parent) discriminantTy = ty; } @@ -1685,7 +1686,7 @@ TypeId ConstraintGraphBuilder::checkLValue(const ScopePtr& scope, AstExpr* expr) std::vector segmentStrings(begin(segments), end(segments)); - TypeId updatedType = arena->addType(BlockedTypeVar{}); + TypeId updatedType = arena->addType(BlockedType{}); addConstraint(scope, expr->location, SetPropConstraint{updatedType, subjectType, std::move(segmentStrings), propTy}); std::optional def = dfg->getDef(sym); @@ -1700,8 +1701,8 @@ TypeId ConstraintGraphBuilder::checkLValue(const ScopePtr& scope, AstExpr* expr) Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTable* expr, std::optional expectedType) { - TypeId ty = arena->addType(TableTypeVar{}); - TableTypeVar* ttv = getMutable(ty); + TypeId ty = arena->addType(TableType{}); + TableType* ttv = getMutable(ty); LUAU_ASSERT(ttv); ttv->state = TableState::Unsealed; @@ -1729,12 +1730,12 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTable* exp { ErrorVec errorVec; std::optional propTy = - findTablePropertyRespectingMeta(singletonTypes, errorVec, follow(*expectedType), stringKey->value.data, item.value->location); + findTablePropertyRespectingMeta(builtinTypes, errorVec, follow(*expectedType), stringKey->value.data, item.value->location); if (propTy) expectedValueType = propTy; else { - expectedValueType = arena->addType(BlockedTypeVar{}); + expectedValueType = arena->addType(BlockedType{}); addConstraint(scope, item.value->location, HasPropConstraint{*expectedValueType, *expectedType, stringKey->value.data}); } } @@ -1760,7 +1761,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTable* exp } else { - TypeId numberType = singletonTypes->numberType; + TypeId numberType = builtinTypes->numberType; // FIXME? The location isn't quite right here. Not sure what is // right. createIndexer(item.value->location, numberType, itemTy); @@ -1821,11 +1822,11 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS std::vector argTypes; TypePack expectedArgPack; - const FunctionTypeVar* expectedFunction = expectedType ? get(*expectedType) : nullptr; + const FunctionType* expectedFunction = expectedType ? get(*expectedType) : nullptr; if (expectedFunction) { - expectedArgPack = extendTypePack(*arena, singletonTypes, expectedFunction->argTypes, fn->args.size); + expectedArgPack = extendTypePack(*arena, builtinTypes, expectedFunction->argTypes, fn->args.size); genericTypes = expectedFunction->generics; genericTypePacks = expectedFunction->genericPacks; @@ -1870,14 +1871,14 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS else if (expectedArgPack.tail && get(*expectedArgPack.tail)) varargPack = *expectedArgPack.tail; else - varargPack = singletonTypes->anyTypePack; + varargPack = builtinTypes->anyTypePack; signatureScope->varargPack = varargPack; bodyScope->varargPack = varargPack; } else { - varargPack = arena->addTypePack(VariadicTypePack{singletonTypes->anyType, /*hidden*/ true}); + varargPack = arena->addTypePack(VariadicTypePack{builtinTypes->anyType, /*hidden*/ true}); // We do not add to signatureScope->varargPack because ... is not valid // in functions without an explicit ellipsis. @@ -1906,7 +1907,7 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS // TODO: Preserve argument names in the function's type. - FunctionTypeVar actualFunction{TypeLevel{}, parent.get(), arena->addTypePack(argTypes, varargPack), returnType}; + FunctionType actualFunction{TypeLevel{}, parent.get(), arena->addTypePack(argTypes, varargPack), returnType}; actualFunction.hasNoGenerics = !hasGenerics; actualFunction.generics = std::move(genericTypes); actualFunction.genericPacks = std::move(genericTypePacks); @@ -1915,9 +1916,9 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS LUAU_ASSERT(actualFunctionType); astTypes[fn] = actualFunctionType; - if (expectedType && get(*expectedType)) + if (expectedType && get(*expectedType)) { - asMutable(*expectedType)->ty.emplace(actualFunctionType); + asMutable(*expectedType)->ty.emplace(actualFunctionType); } return { @@ -1955,7 +1956,7 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b if (ref->parameters.size != 1 || !ref->parameters.data[0].type) { reportError(ty->location, GenericError{"_luau_print requires one generic parameter"}); - return singletonTypes->errorRecoveryType(); + return builtinTypes->errorRecoveryType(); } else return resolveType(scope, ref->parameters.data[0].type, topLevel); @@ -2006,7 +2007,7 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b } } - result = arena->addType(PendingExpansionTypeVar{ref->prefix, ref->name, parameters, packParameters}); + result = arena->addType(PendingExpansionType{ref->prefix, ref->name, parameters, packParameters}); if (topLevel) { @@ -2021,12 +2022,12 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b typeName = std::string(ref->prefix->value) + "."; typeName += ref->name.value; - result = singletonTypes->errorRecoveryType(); + result = builtinTypes->errorRecoveryType(); } } else if (auto tab = ty->as()) { - TableTypeVar::Props props; + TableType::Props props; std::optional indexer; for (const AstTableProp& prop : tab->props) @@ -2047,7 +2048,7 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b }; } - result = arena->addType(TableTypeVar{props, indexer, scope->level, scope.get(), TableState::Sealed}); + result = arena->addType(TableType{props, indexer, scope->level, scope.get(), TableState::Sealed}); } else if (auto fn = ty->as()) { @@ -2090,11 +2091,11 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b TypePackId argTypes = resolveTypePack(signatureScope, fn->argTypes); TypePackId returnTypes = resolveTypePack(signatureScope, fn->returnTypes); - // TODO: FunctionTypeVar needs a pointer to the scope so that we know + // TODO: FunctionType needs a pointer to the scope so that we know // how to quantify/instantiate it. - FunctionTypeVar ftv{TypeLevel{}, scope.get(), {}, {}, argTypes, returnTypes}; + FunctionType ftv{TypeLevel{}, scope.get(), {}, {}, argTypes, returnTypes}; - // This replicates the behavior of the appropriate FunctionTypeVar + // This replicates the behavior of the appropriate FunctionType // constructors. ftv.hasNoGenerics = !hasGenerics; ftv.generics = std::move(genericTypes); @@ -2131,7 +2132,7 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b parts.push_back(resolveType(scope, part, topLevel)); } - result = arena->addType(UnionTypeVar{parts}); + result = arena->addType(UnionType{parts}); } else if (auto intersectionAnnotation = ty->as()) { @@ -2142,24 +2143,24 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b parts.push_back(resolveType(scope, part, topLevel)); } - result = arena->addType(IntersectionTypeVar{parts}); + result = arena->addType(IntersectionType{parts}); } else if (auto boolAnnotation = ty->as()) { - result = arena->addType(SingletonTypeVar(BooleanSingleton{boolAnnotation->value})); + result = arena->addType(SingletonType(BooleanSingleton{boolAnnotation->value})); } else if (auto stringAnnotation = ty->as()) { - result = arena->addType(SingletonTypeVar(StringSingleton{std::string(stringAnnotation->value.data, stringAnnotation->value.size)})); + result = arena->addType(SingletonType(StringSingleton{std::string(stringAnnotation->value.data, stringAnnotation->value.size)})); } else if (ty->is()) { - result = singletonTypes->errorRecoveryType(); + result = builtinTypes->errorRecoveryType(); } else { LUAU_ASSERT(0); - result = singletonTypes->errorRecoveryType(); + result = builtinTypes->errorRecoveryType(); } astResolvedTypes[ty] = result; @@ -2187,13 +2188,13 @@ TypePackId ConstraintGraphBuilder::resolveTypePack(const ScopePtr& scope, AstTyp else { reportError(tp->location, UnknownSymbol{gen->genericName.value, UnknownSymbol::Context::Type}); - result = singletonTypes->errorRecoveryTypePack(); + result = builtinTypes->errorRecoveryTypePack(); } } else { LUAU_ASSERT(0); - result = singletonTypes->errorRecoveryTypePack(); + result = builtinTypes->errorRecoveryTypePack(); } astResolvedTypePacks[tp] = result; @@ -2223,7 +2224,7 @@ std::vector> ConstraintGraphBuilder::crea std::vector> result; for (const auto& generic : generics) { - TypeId genericTy = arena->addType(GenericTypeVar{scope.get(), generic.name.value}); + TypeId genericTy = arena->addType(GenericType{scope.get(), generic.name.value}); std::optional defaultTy = std::nullopt; if (generic.defaultValue) @@ -2302,7 +2303,7 @@ struct GlobalPrepopulator : AstVisitor bool visit(AstStatFunction* function) override { if (AstExprGlobal* g = function->name->as()) - globalScope->bindings[g->name] = Binding{arena->addType(BlockedTypeVar{})}; + globalScope->bindings[g->name] = Binding{arena->addType(BlockedType{})}; return true; } diff --git a/Analysis/src/ConstraintSolver.cpp b/Analysis/src/ConstraintSolver.cpp index d73c14a6..67c1732c 100644 --- a/Analysis/src/ConstraintSolver.cpp +++ b/Analysis/src/ConstraintSolver.cpp @@ -12,9 +12,9 @@ #include "Luau/Quantify.h" #include "Luau/ToString.h" #include "Luau/TypeUtils.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/Unifier.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/VisitType.h" LUAU_FASTFLAGVARIABLE(DebugLuauLogSolver, false); LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson, false); @@ -34,7 +34,7 @@ namespace Luau dumpBindings(child, opts); } -static std::pair, std::vector> saturateArguments(TypeArena* arena, NotNull singletonTypes, +static std::pair, std::vector> saturateArguments(TypeArena* arena, NotNull builtinTypes, const TypeFun& fn, const std::vector& rawTypeArguments, const std::vector& rawPackArguments) { std::vector saturatedTypeArguments; @@ -115,7 +115,7 @@ static std::pair, std::vector> saturateArguments if (!defaultTy) break; - TypeId instantiatedDefault = atf.substitute(defaultTy).value_or(singletonTypes->errorRecoveryType()); + TypeId instantiatedDefault = atf.substitute(defaultTy).value_or(builtinTypes->errorRecoveryType()); atf.typeArguments[fn.typeParams[i].ty] = instantiatedDefault; saturatedTypeArguments.push_back(instantiatedDefault); } @@ -133,7 +133,7 @@ static std::pair, std::vector> saturateArguments if (!defaultTp) break; - TypePackId instantiatedDefault = atf.substitute(defaultTp).value_or(singletonTypes->errorRecoveryTypePack()); + TypePackId instantiatedDefault = atf.substitute(defaultTp).value_or(builtinTypes->errorRecoveryTypePack()); atf.typePackArguments[fn.typePackParams[i].tp] = instantiatedDefault; saturatedPackArguments.push_back(instantiatedDefault); } @@ -151,12 +151,12 @@ static std::pair, std::vector> saturateArguments // even if they're missing, so we use the error type as a filler. for (size_t i = saturatedTypeArguments.size(); i < typesRequired; ++i) { - saturatedTypeArguments.push_back(singletonTypes->errorRecoveryType()); + saturatedTypeArguments.push_back(builtinTypes->errorRecoveryType()); } for (size_t i = saturatedPackArguments.size(); i < packsRequired; ++i) { - saturatedPackArguments.push_back(singletonTypes->errorRecoveryTypePack()); + saturatedPackArguments.push_back(builtinTypes->errorRecoveryTypePack()); } // At this point, these two conditions should be true. If they aren't we @@ -229,7 +229,7 @@ void dump(ConstraintSolver* cs, ToStringOptions& opts) ConstraintSolver::ConstraintSolver(NotNull normalizer, NotNull rootScope, std::vector> constraints, ModuleName moduleName, NotNull moduleResolver, std::vector requireCycles, DcrLogger* logger) : arena(normalizer->arena) - , singletonTypes(normalizer->singletonTypes) + , builtinTypes(normalizer->builtinTypes) , normalizer(normalizer) , constraints(std::move(constraints)) , rootScope(rootScope) @@ -373,12 +373,12 @@ bool ConstraintSolver::isDone() void ConstraintSolver::finalizeModule() { - Anyification a{arena, rootScope, singletonTypes, &iceReporter, singletonTypes->anyType, singletonTypes->anyTypePack}; + Anyification a{arena, rootScope, builtinTypes, &iceReporter, builtinTypes->anyType, builtinTypes->anyTypePack}; std::optional returnType = a.substitute(rootScope->returnType); if (!returnType) { reportError(CodeTooComplex{}, Location{}); - rootScope->returnType = singletonTypes->errorTypePack; + rootScope->returnType = builtinTypes->errorTypePack; } else rootScope->returnType = *returnType; @@ -470,7 +470,7 @@ bool ConstraintSolver::tryDispatch(const GeneralizationConstraint& c, NotNullscope); if (isBlocked(c.generalizedType)) - asMutable(c.generalizedType)->ty.emplace(generalized); + asMutable(c.generalizedType)->ty.emplace(generalized); else unify(c.generalizedType, generalized, constraint->scope); @@ -491,7 +491,7 @@ bool ConstraintSolver::tryDispatch(const InstantiationConstraint& c, NotNullty.emplace(*instantiated); + asMutable(c.subType)->ty.emplace(*instantiated); else unify(c.subType, *instantiated, constraint->scope); @@ -507,62 +507,62 @@ bool ConstraintSolver::tryDispatch(const UnaryConstraint& c, NotNull(operandType)) + if (get(operandType)) return block(operandType, constraint); - LUAU_ASSERT(get(c.resultType)); + LUAU_ASSERT(get(c.resultType)); switch (c.op) { case AstExprUnary::Not: { - asMutable(c.resultType)->ty.emplace(singletonTypes->booleanType); + asMutable(c.resultType)->ty.emplace(builtinTypes->booleanType); return true; } case AstExprUnary::Len: { // __len must return a number. - asMutable(c.resultType)->ty.emplace(singletonTypes->numberType); + asMutable(c.resultType)->ty.emplace(builtinTypes->numberType); return true; } case AstExprUnary::Minus: { - if (isNumber(operandType) || get(operandType) || get(operandType)) + if (isNumber(operandType) || get(operandType) || get(operandType)) { - asMutable(c.resultType)->ty.emplace(c.operandType); + asMutable(c.resultType)->ty.emplace(c.operandType); } - else if (std::optional mm = findMetatableEntry(singletonTypes, errors, operandType, "__unm", constraint->location)) + else if (std::optional mm = findMetatableEntry(builtinTypes, errors, operandType, "__unm", constraint->location)) { - const FunctionTypeVar* ftv = get(follow(*mm)); + const FunctionType* ftv = get(follow(*mm)); if (!ftv) { - if (std::optional callMm = findMetatableEntry(singletonTypes, errors, follow(*mm), "__call", constraint->location)) + if (std::optional callMm = findMetatableEntry(builtinTypes, errors, follow(*mm), "__call", constraint->location)) { - ftv = get(follow(*callMm)); + ftv = get(follow(*callMm)); } } if (!ftv) { - asMutable(c.resultType)->ty.emplace(singletonTypes->errorRecoveryType()); + asMutable(c.resultType)->ty.emplace(builtinTypes->errorRecoveryType()); return true; } TypePackId argsPack = arena->addTypePack({operandType}); unify(ftv->argTypes, argsPack, constraint->scope); - TypeId result = singletonTypes->errorRecoveryType(); + TypeId result = builtinTypes->errorRecoveryType(); if (ftv) { - result = first(ftv->retTypes).value_or(singletonTypes->errorRecoveryType()); + result = first(ftv->retTypes).value_or(builtinTypes->errorRecoveryType()); } - asMutable(c.resultType)->ty.emplace(result); + asMutable(c.resultType)->ty.emplace(result); } else { - asMutable(c.resultType)->ty.emplace(singletonTypes->errorRecoveryType()); + asMutable(c.resultType)->ty.emplace(builtinTypes->errorRecoveryType()); } return true; @@ -598,14 +598,14 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull(leftType) && !isLogical) + if (get(leftType) && !isLogical) return block(leftType, constraint); } // Logical expressions may proceed if the LHS is free. - if (isBlocked(leftType) || (get(leftType) && !isLogical)) + if (isBlocked(leftType) || (get(leftType) && !isLogical)) { - asMutable(resultType)->ty.emplace(errorRecoveryType()); + asMutable(resultType)->ty.emplace(errorRecoveryType()); unblock(resultType); return true; } @@ -615,10 +615,10 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNullty.emplace(singletonTypes->booleanType); + asMutable(resultType)->ty.emplace(builtinTypes->booleanType); unblock(resultType); return true; } @@ -627,9 +627,9 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull leftMm = findMetatableEntry(singletonTypes, errors, leftType, it->second, constraint->location)) + if (std::optional leftMm = findMetatableEntry(builtinTypes, errors, leftType, it->second, constraint->location)) mm = leftMm; - else if (std::optional rightMm = findMetatableEntry(singletonTypes, errors, rightType, it->second, constraint->location)) + else if (std::optional rightMm = findMetatableEntry(builtinTypes, errors, rightType, it->second, constraint->location)) mm = rightMm; if (mm) @@ -644,7 +644,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull(follow(*instantiatedMm))) + if (const FunctionType* ftv = get(follow(*instantiatedMm))) { TypePackId inferredArgs; // For >= and > we invoke __lt and __le respectively with @@ -672,13 +672,13 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNullbooleanType; + mmResult = builtinTypes->booleanType; break; default: mmResult = first(ftv->retTypes).value_or(errorRecoveryType()); } - asMutable(resultType)->ty.emplace(mmResult); + asMutable(resultType)->ty.emplace(mmResult); unblock(resultType); (*c.astOriginalCallTypes)[c.expr] = *mm; @@ -691,8 +691,8 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull(leftType) || get(leftType); - bool rightAny = get(rightType) || get(rightType); + bool leftAny = get(leftType) || get(leftType); + bool rightAny = get(rightType) || get(rightType); bool anyPresent = leftAny || rightAny; switch (c.op) @@ -708,7 +708,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNullscope); - asMutable(resultType)->ty.emplace(anyPresent ? singletonTypes->anyType : leftType); + asMutable(resultType)->ty.emplace(anyPresent ? builtinTypes->anyType : leftType); unblock(resultType); return true; } @@ -720,7 +720,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNullscope); - asMutable(resultType)->ty.emplace(anyPresent ? singletonTypes->anyType : leftType); + asMutable(resultType)->ty.emplace(anyPresent ? builtinTypes->anyType : leftType); unblock(resultType); return true; } @@ -734,7 +734,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNullty.emplace(singletonTypes->booleanType); + asMutable(resultType)->ty.emplace(builtinTypes->booleanType); unblock(resultType); return true; } @@ -744,16 +744,16 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNullty.emplace(singletonTypes->booleanType); + asMutable(resultType)->ty.emplace(builtinTypes->booleanType); unblock(resultType); return true; // And evalutes to a boolean if the LHS is falsey, and the RHS type if LHS is // truthy. case AstExprBinary::Op::And: { - TypeId leftFilteredTy = arena->addType(IntersectionTypeVar{{singletonTypes->falsyType, leftType}}); + TypeId leftFilteredTy = arena->addType(IntersectionType{{builtinTypes->falsyType, leftType}}); - asMutable(resultType)->ty.emplace(arena->addType(UnionTypeVar{{leftFilteredTy, rightType}})); + asMutable(resultType)->ty.emplace(arena->addType(UnionType{{leftFilteredTy, rightType}})); unblock(resultType); return true; } @@ -761,9 +761,9 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNulladdType(IntersectionTypeVar{{singletonTypes->truthyType, leftType}}); + TypeId leftFilteredTy = arena->addType(IntersectionType{{builtinTypes->truthyType, leftType}}); - asMutable(resultType)->ty.emplace(arena->addType(UnionTypeVar{{leftFilteredTy, rightType}})); + asMutable(resultType)->ty.emplace(arena->addType(UnionType{{leftFilteredTy, rightType}})); unblock(resultType); return true; } @@ -775,7 +775,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNullscope); unify(rightType, errorRecoveryType(), constraint->scope); - asMutable(resultType)->ty.emplace(errorRecoveryType()); + asMutable(resultType)->ty.emplace(errorRecoveryType()); unblock(resultType); return true; @@ -840,7 +840,7 @@ bool ConstraintSolver::tryDispatch(const IterableConstraint& c, NotNullscope, singletonTypes, &iceReporter, errorRecoveryType(), errorRecoveryTypePack()}; + Anyification anyify{arena, constraint->scope, builtinTypes, &iceReporter, errorRecoveryType(), errorRecoveryTypePack()}; std::optional anyified = anyify.substitute(c.variables); LUAU_ASSERT(anyified); unify(*anyified, c.variables, constraint->scope); @@ -849,16 +849,16 @@ bool ConstraintSolver::tryDispatch(const IterableConstraint& c, NotNull(nextTy)) + if (get(nextTy)) return block_(nextTy); - if (get(nextTy)) + if (get(nextTy)) { - TypeId tableTy = singletonTypes->nilType; + TypeId tableTy = builtinTypes->nilType; if (iteratorTypes.size() >= 2) tableTy = iteratorTypes[1]; - TypeId firstIndexTy = singletonTypes->nilType; + TypeId firstIndexTy = builtinTypes->nilType; if (iteratorTypes.size() >= 3) firstIndexTy = iteratorTypes[2]; @@ -881,11 +881,11 @@ bool ConstraintSolver::tryDispatch(const NameConstraint& c, NotNullpersistent || target->owningArena != arena) return true; - if (TableTypeVar* ttv = getMutable(target)) + if (TableType* ttv = getMutable(target)) ttv->name = c.name; - else if (MetatableTypeVar* mtv = getMutable(target)) + else if (MetatableType* mtv = getMutable(target)) mtv->syntheticName = c.name; - else if (get(target) || get(target)) + else if (get(target) || get(target)) { // nothing (yet) } @@ -895,7 +895,7 @@ bool ConstraintSolver::tryDispatch(const NameConstraint& c, NotNull tf = (petv.prefix) ? scope->lookupImportedType(petv.prefix->value, petv.name.value) : scope->lookupType(petv.name.value); @@ -917,7 +917,7 @@ struct InfiniteTypeFinder : TypeVarOnceVisitor if (!tf.has_value()) return true; - auto [typeArguments, packArguments] = saturateArguments(solver->arena, solver->singletonTypes, *tf, petv.typeArguments, petv.packArguments); + auto [typeArguments, packArguments] = saturateArguments(solver->arena, solver->builtinTypes, *tf, petv.typeArguments, petv.packArguments); if (follow(tf->type) == follow(signature.fn.type) && (signature.arguments != typeArguments || signature.packArguments != packArguments)) { @@ -929,7 +929,7 @@ struct InfiniteTypeFinder : TypeVarOnceVisitor } }; -struct InstantiationQueuer : TypeVarOnceVisitor +struct InstantiationQueuer : TypeOnceVisitor { ConstraintSolver* solver; const InstantiationSignature& signature; @@ -944,7 +944,7 @@ struct InstantiationQueuer : TypeVarOnceVisitor { } - bool visit(TypeId ty, const PendingExpansionTypeVar& petv) override + bool visit(TypeId ty, const PendingExpansionType& petv) override { solver->pushConstraint(scope, location, TypeAliasExpansionConstraint{ty}); return false; @@ -953,7 +953,7 @@ struct InstantiationQueuer : TypeVarOnceVisitor bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNull constraint) { - const PendingExpansionTypeVar* petv = get(follow(c.target)); + const PendingExpansionType* petv = get(follow(c.target)); if (!petv) { unblock(c.target); @@ -961,7 +961,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul } auto bindResult = [this, &c](TypeId result) { - asMutable(c.target)->ty.emplace(result); + asMutable(c.target)->ty.emplace(result); unblock(c.target); }; @@ -983,7 +983,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul return true; } - auto [typeArguments, packArguments] = saturateArguments(arena, singletonTypes, *tf, petv->typeArguments, petv->packArguments); + auto [typeArguments, packArguments] = saturateArguments(arena, builtinTypes, *tf, petv->typeArguments, petv->packArguments); bool sameTypes = std::equal(typeArguments.begin(), typeArguments.end(), tf->typeParams.begin(), tf->typeParams.end(), [](auto&& itp, auto&& p) { return itp == p.ty; @@ -1067,7 +1067,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul // there are e.g. generic saturatedTypeArguments that go unused. bool needsClone = follow(tf->type) == target; // Only tables have the properties we're trying to set. - TableTypeVar* ttv = getMutableTableType(target); + TableType* ttv = getMutableTableType(target); if (ttv) { @@ -1078,17 +1078,17 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul // explicitly clone that table as well. If we don't, we will // mutate another module's type surface and cause a // use-after-free. - if (get(target)) + if (get(target)) { instantiated = applyTypeFunction.clone(target); - MetatableTypeVar* mtv = getMutable(instantiated); + MetatableType* mtv = getMutable(instantiated); mtv->table = applyTypeFunction.clone(mtv->table); - ttv = getMutable(mtv->table); + ttv = getMutable(mtv->table); } - else if (get(target)) + else if (get(target)) { instantiated = applyTypeFunction.clone(target); - ttv = getMutable(instantiated); + ttv = getMutable(instantiated); } target = follow(instantiated); @@ -1123,16 +1123,15 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull callMm = findMetatableEntry(singletonTypes, errors, fn, "__call", constraint->location)) + if (std::optional callMm = findMetatableEntry(builtinTypes, errors, fn, "__call", constraint->location)) { std::vector args{fn}; for (TypeId arg : c.argsPack) args.push_back(arg); - TypeId instantiatedType = arena->addType(BlockedTypeVar{}); - TypeId inferredFnType = - arena->addType(FunctionTypeVar(TypeLevel{}, constraint->scope.get(), arena->addTypePack(TypePack{args, {}}), c.result)); + TypeId instantiatedType = arena->addType(BlockedType{}); + TypeId inferredFnType = arena->addType(FunctionType(TypeLevel{}, constraint->scope.get(), arena->addTypePack(TypePack{args, {}}), c.result)); // Alter the inner constraints. LUAU_ASSERT(c.innerConstraints.size() == 2); @@ -1158,7 +1157,7 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull(fn); + const FunctionType* ftv = get(fn); bool usedMagic = false; if (ftv && ftv->dcrMagicFunction != nullptr) @@ -1203,11 +1202,11 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull constraint) { TypeId expectedType = follow(c.expectedType); - if (isBlocked(expectedType) || get(expectedType)) + if (isBlocked(expectedType) || get(expectedType)) return block(expectedType, constraint); TypeId bindTo = maybeSingleton(expectedType) ? c.singletonType : c.multitonType; - asMutable(c.resultType)->ty.emplace(bindTo); + asMutable(c.resultType)->ty.emplace(bindTo); return true; } @@ -1216,14 +1215,14 @@ bool ConstraintSolver::tryDispatch(const HasPropConstraint& c, NotNull(subjectType)) + if (isBlocked(subjectType) || get(subjectType)) return block(subjectType, constraint); - if (get(subjectType)) + if (get(subjectType)) { - TableTypeVar& ttv = asMutable(subjectType)->ty.emplace(TableState::Free, TypeLevel{}, constraint->scope); + TableType& ttv = asMutable(subjectType)->ty.emplace(TableState::Free, TypeLevel{}, constraint->scope); ttv.props[c.prop] = Property{c.resultType}; - asMutable(c.resultType)->ty.emplace(constraint->scope); + asMutable(c.resultType)->ty.emplace(constraint->scope); unblock(c.resultType); return true; } @@ -1231,7 +1230,7 @@ bool ConstraintSolver::tryDispatch(const HasPropConstraint& c, NotNull resultType = lookupTableProp(subjectType, c.prop); if (!resultType) { - asMutable(c.resultType)->ty.emplace(singletonTypes->errorRecoveryType()); + asMutable(c.resultType)->ty.emplace(builtinTypes->errorRecoveryType()); unblock(c.resultType); return true; } @@ -1242,14 +1241,14 @@ bool ConstraintSolver::tryDispatch(const HasPropConstraint& c, NotNullty.emplace(*resultType); + asMutable(c.resultType)->ty.emplace(*resultType); return true; } static bool isUnsealedTable(TypeId ty) { ty = follow(ty); - const TableTypeVar* ttv = get(ty); + const TableType* ttv = get(ty); return ttv && ttv->state == TableState::Unsealed; } @@ -1278,7 +1277,7 @@ static std::optional updateTheTableType(NotNull arena, TypeId if (!isUnsealedTable(t)) return std::nullopt; - const TableTypeVar* tbl = get(t); + const TableType* tbl = get(t); auto it = tbl->props.find(path[i]); if (it == tbl->props.end()) return std::nullopt; @@ -1291,7 +1290,7 @@ static std::optional updateTheTableType(NotNull arena, TypeId // new property to be appended. if (!isUnsealedTable(t)) return std::nullopt; - const TableTypeVar* tbl = get(t); + const TableType* tbl = get(t); if (0 != tbl->props.count(path.back())) return std::nullopt; } @@ -1303,7 +1302,7 @@ static std::optional updateTheTableType(NotNull arena, TypeId { const std::string segment = path[i]; - TableTypeVar* ttv = getMutable(t); + TableType* ttv = getMutable(t); LUAU_ASSERT(ttv); auto propIt = ttv->props.find(segment); @@ -1317,7 +1316,7 @@ static std::optional updateTheTableType(NotNull arena, TypeId return std::nullopt; } - TableTypeVar* ttv = getMutable(t); + TableType* ttv = getMutable(t); LUAU_ASSERT(ttv); const std::string lastSegment = path.back(); @@ -1350,7 +1349,7 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNullty.emplace(b); + asMutable(a)->ty.emplace(b); }; if (existingPropType) @@ -1360,14 +1359,14 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull(subjectType)) + if (get(subjectType)) { TypeId ty = arena->freshType(constraint->scope); // Mint a chain of free tables per c.path for (auto it = rbegin(c.path); it != rend(c.path); ++it) { - TableTypeVar t{TableState::Free, TypeLevel{}, constraint->scope}; + TableType t{TableState::Free, TypeLevel{}, constraint->scope}; t.props[*it] = {ty}; ty = arena->addType(std::move(t)); @@ -1379,7 +1378,7 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull(subjectType)) + else if (auto ttv = getMutable(subjectType)) { if (ttv->state == TableState::Free) { @@ -1399,7 +1398,7 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull(subjectType) || get(subjectType)) + else if (get(subjectType) || get(subjectType)) { bind(c.resultType, subjectType); return true; @@ -1417,12 +1416,12 @@ bool ConstraintSolver::tryDispatch(const SingletonOrTopTypeConstraint& c, NotNul TypeId followed = follow(c.discriminantType); // `nil` is a singleton type too! There's only one value of type `nil`. - if (c.negated && (get(followed) || isNil(followed))) - *asMutable(c.resultType) = NegationTypeVar{c.discriminantType}; - else if (!c.negated && get(followed)) - *asMutable(c.resultType) = BoundTypeVar{c.discriminantType}; + if (c.negated && (get(followed) || isNil(followed))) + *asMutable(c.resultType) = NegationType{c.discriminantType}; + else if (!c.negated && get(followed)) + *asMutable(c.resultType) = BoundType{c.discriminantType}; else - *asMutable(c.resultType) = BoundTypeVar{singletonTypes->unknownType}; + *asMutable(c.resultType) = BoundType{builtinTypes->unknownType}; return true; } @@ -1445,11 +1444,11 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl // We may have to block here if we don't know what the iteratee type is, // if it's a free table, if we don't know it has a metatable, and so on. iteratorTy = follow(iteratorTy); - if (get(iteratorTy)) + if (get(iteratorTy)) return block_(iteratorTy); auto anyify = [&](auto ty) { - Anyification anyify{arena, constraint->scope, singletonTypes, &iceReporter, singletonTypes->anyType, singletonTypes->anyTypePack}; + Anyification anyify{arena, constraint->scope, builtinTypes, &iceReporter, builtinTypes->anyType, builtinTypes->anyTypePack}; std::optional anyified = anyify.substitute(ty); if (!anyified) reportError(CodeTooComplex{}, constraint->location); @@ -1458,7 +1457,7 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl }; auto errorify = [&](auto ty) { - Anyification anyify{arena, constraint->scope, singletonTypes, &iceReporter, errorRecoveryType(), errorRecoveryTypePack()}; + Anyification anyify{arena, constraint->scope, builtinTypes, &iceReporter, errorRecoveryType(), errorRecoveryTypePack()}; std::optional errorified = anyify.substitute(ty); if (!errorified) reportError(CodeTooComplex{}, constraint->location); @@ -1466,13 +1465,13 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl unify(*errorified, ty, constraint->scope); }; - if (get(iteratorTy)) + if (get(iteratorTy)) { anyify(c.variables); return true; } - if (get(iteratorTy)) + if (get(iteratorTy)) { errorify(c.variables); return true; @@ -1481,7 +1480,7 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl // Irksome: I don't think we have any way to guarantee that this table // type never has a metatable. - if (auto iteratorTable = get(iteratorTy)) + if (auto iteratorTable = get(iteratorTy)) { if (iteratorTable->state == TableState::Free) return block_(iteratorTy); @@ -1494,7 +1493,7 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl else errorify(c.variables); } - else if (std::optional iterFn = findMetatableEntry(singletonTypes, errors, iteratorTy, "__iter", Location{})) + else if (std::optional iterFn = findMetatableEntry(builtinTypes, errors, iteratorTy, "__iter", Location{})) { if (isBlocked(*iterFn)) { @@ -1505,12 +1504,12 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl if (std::optional instantiatedIterFn = instantiation.substitute(*iterFn)) { - if (auto iterFtv = get(*instantiatedIterFn)) + if (auto iterFtv = get(*instantiatedIterFn)) { TypePackId expectedIterArgs = arena->addTypePack({iteratorTy}); unify(iterFtv->argTypes, expectedIterArgs, constraint->scope); - TypePack iterRets = extendTypePack(*arena, singletonTypes, iterFtv->retTypes, 2); + TypePack iterRets = extendTypePack(*arena, builtinTypes, iterFtv->retTypes, 2); if (iterRets.head.size() < 1) { @@ -1527,11 +1526,11 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl const TypeId firstIndex = arena->freshType(constraint->scope); // nextTy : (iteratorTy, indexTy?) -> (indexTy, valueTailTy...) - const TypePackId nextArgPack = arena->addTypePack({table, arena->addType(UnionTypeVar{{firstIndex, singletonTypes->nilType}})}); + const TypePackId nextArgPack = arena->addTypePack({table, arena->addType(UnionType{{firstIndex, builtinTypes->nilType}})}); const TypePackId valueTailTy = arena->addTypePack(FreeTypePack{constraint->scope}); const TypePackId nextRetPack = arena->addTypePack(TypePack{{firstIndex}, valueTailTy}); - const TypeId expectedNextTy = arena->addType(FunctionTypeVar{nextArgPack, nextRetPack}); + const TypeId expectedNextTy = arena->addType(FunctionType{nextArgPack, nextRetPack}); unify(*instantiatedNextFn, expectedNextTy, constraint->scope); pushConstraint(constraint->scope, constraint->location, PackSubtypeConstraint{c.variables, nextRetPack}); @@ -1551,10 +1550,10 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl reportError(UnificationTooComplex{}, constraint->location); } } - else if (auto iteratorMetatable = get(iteratorTy)) + else if (auto iteratorMetatable = get(iteratorTy)) { TypeId metaTy = follow(iteratorMetatable->metatable); - if (get(metaTy)) + if (get(metaTy)) return block_(metaTy); LUAU_ASSERT(false); @@ -1571,7 +1570,7 @@ bool ConstraintSolver::tryDispatchIterableFunction( // We need to know whether or not this type is nil or not. // If we don't know, block and reschedule ourselves. firstIndexTy = follow(firstIndexTy); - if (get(firstIndexTy)) + if (get(firstIndexTy)) { if (force) LUAU_ASSERT(false); @@ -1584,11 +1583,11 @@ bool ConstraintSolver::tryDispatchIterableFunction( : firstIndexTy; // nextTy : (tableTy, indexTy?) -> (indexTy, valueTailTy...) - const TypePackId nextArgPack = arena->addTypePack({tableTy, arena->addType(UnionTypeVar{{firstIndex, singletonTypes->nilType}})}); + const TypePackId nextArgPack = arena->addTypePack({tableTy, arena->addType(UnionType{{firstIndex, builtinTypes->nilType}})}); const TypePackId valueTailTy = arena->addTypePack(FreeTypePack{constraint->scope}); const TypePackId nextRetPack = arena->addTypePack(TypePack{{firstIndex}, valueTailTy}); - const TypeId expectedNextTy = arena->addType(FunctionTypeVar{TypeLevel{}, constraint->scope, nextArgPack, nextRetPack}); + const TypeId expectedNextTy = arena->addType(FunctionType{TypeLevel{}, constraint->scope, nextArgPack, nextRetPack}); unify(nextTy, expectedNextTy, constraint->scope); pushConstraint(constraint->scope, constraint->location, PackSubtypeConstraint{c.variables, nextRetPack}); @@ -1605,9 +1604,9 @@ std::optional ConstraintSolver::lookupTableProp(TypeId subjectType, cons for (TypeId expectedPart : unionOrIntersection) { expectedPart = follow(expectedPart); - if (isBlocked(expectedPart) || get(expectedPart)) + if (isBlocked(expectedPart) || get(expectedPart)) blocked = expectedPart; - else if (const TableTypeVar* ttv = get(follow(expectedPart))) + else if (const TableType* ttv = get(follow(expectedPart))) { if (auto prop = ttv->props.find(propName); prop != ttv->props.end()) parts.push_back(prop->second.type); @@ -1621,14 +1620,14 @@ std::optional ConstraintSolver::lookupTableProp(TypeId subjectType, cons std::optional resultType; - if (auto ttv = get(subjectType)) + if (auto ttv = get(subjectType)) { if (auto prop = ttv->props.find(propName); prop != ttv->props.end()) resultType = prop->second.type; else if (ttv->indexer && maybeString(ttv->indexer->indexType)) resultType = ttv->indexer->indexResultType; } - else if (auto utv = get(subjectType)) + else if (auto utv = get(subjectType)) { auto [blocked, parts] = collectParts(utv); @@ -1637,11 +1636,11 @@ std::optional ConstraintSolver::lookupTableProp(TypeId subjectType, cons else if (parts.size() == 1) resultType = parts[0]; else if (parts.size() > 1) - resultType = arena->addType(UnionTypeVar{std::move(parts)}); + resultType = arena->addType(UnionType{std::move(parts)}); else LUAU_ASSERT(false); // parts.size() == 0 } - else if (auto itv = get(subjectType)) + else if (auto itv = get(subjectType)) { auto [blocked, parts] = collectParts(itv); @@ -1650,7 +1649,7 @@ std::optional ConstraintSolver::lookupTableProp(TypeId subjectType, cons else if (parts.size() == 1) resultType = parts[0]; else if (parts.size() > 1) - resultType = arena->addType(IntersectionTypeVar{std::move(parts)}); + resultType = arena->addType(IntersectionType{std::move(parts)}); else LUAU_ASSERT(false); // parts.size() == 0 } @@ -1701,7 +1700,7 @@ bool ConstraintSolver::block(TypePackId target, NotNull constr return false; } -struct Blocker : TypeVarOnceVisitor +struct Blocker : TypeOnceVisitor { NotNull solver; NotNull constraint; @@ -1714,14 +1713,14 @@ struct Blocker : TypeVarOnceVisitor { } - bool visit(TypeId ty, const BlockedTypeVar&) + bool visit(TypeId ty, const BlockedType&) { blocked = true; solver->block(ty, constraint); return false; } - bool visit(TypeId ty, const PendingExpansionTypeVar&) + bool visit(TypeId ty, const PendingExpansionType&) { blocked = true; solver->block(ty, constraint); @@ -1805,7 +1804,7 @@ void ConstraintSolver::unblock(const std::vector& packs) bool ConstraintSolver::isBlocked(TypeId ty) { - return nullptr != get(follow(ty)) || nullptr != get(follow(ty)); + return nullptr != get(follow(ty)) || nullptr != get(follow(ty)); } bool ConstraintSolver::isBlocked(TypePackId tp) @@ -1878,7 +1877,7 @@ TypeId ConstraintSolver::resolveModule(const ModuleInfo& info, const Location& l for (const auto& [location, path] : requireCycles) { if (!path.empty() && path.front() == humanReadableName) - return singletonTypes->anyType; + return builtinTypes->anyType; } ModulePtr module = moduleResolver->getModule(info.name); @@ -1924,12 +1923,12 @@ void ConstraintSolver::reportError(TypeError e) TypeId ConstraintSolver::errorRecoveryType() const { - return singletonTypes->errorRecoveryType(); + return builtinTypes->errorRecoveryType(); } TypePackId ConstraintSolver::errorRecoveryTypePack() const { - return singletonTypes->errorRecoveryTypePack(); + return builtinTypes->errorRecoveryTypePack(); } TypeId ConstraintSolver::unionOfTypes(TypeId a, TypeId b, NotNull scope, bool unifyFreeTypes) @@ -1937,7 +1936,7 @@ TypeId ConstraintSolver::unionOfTypes(TypeId a, TypeId b, NotNull scope, a = follow(a); b = follow(b); - if (unifyFreeTypes && (get(a) || get(b))) + if (unifyFreeTypes && (get(a) || get(b))) { Unifier u{normalizer, Mode::Strict, scope, Location{}, Covariant}; u.useScopes = true; @@ -1950,7 +1949,7 @@ TypeId ConstraintSolver::unionOfTypes(TypeId a, TypeId b, NotNull scope, } else { - return singletonTypes->errorRecoveryType(singletonTypes->anyType); + return builtinTypes->errorRecoveryType(builtinTypes->anyType); } } @@ -1959,12 +1958,12 @@ TypeId ConstraintSolver::unionOfTypes(TypeId a, TypeId b, NotNull scope, std::vector types = reduceUnion({a, b}); if (types.empty()) - return singletonTypes->neverType; + return builtinTypes->neverType; if (types.size() == 1) return types[0]; - return arena->addType(UnionTypeVar{types}); + return arena->addType(UnionType{types}); } } // namespace Luau diff --git a/Analysis/src/Error.cpp b/Analysis/src/Error.cpp index 748cf20f..a527b244 100644 --- a/Analysis/src/Error.cpp +++ b/Analysis/src/Error.cpp @@ -131,9 +131,9 @@ struct ErrorConverter std::string operator()(const Luau::UnknownProperty& e) const { TypeId t = follow(e.table); - if (get(t)) + if (get(t)) return "Key '" + e.key + "' not found in table '" + Luau::toString(t) + "'"; - else if (get(t)) + else if (get(t)) return "Key '" + e.key + "' not found in class '" + Luau::toString(t) + "'"; else return "Type '" + Luau::toString(e.table) + "' does not have key '" + e.key + "'"; @@ -301,7 +301,7 @@ struct ErrorConverter std::string s = "Key '" + e.key + "' not found in "; TypeId t = follow(e.table); - if (get(t)) + if (get(t)) s += "class"; else s += "table"; @@ -952,7 +952,7 @@ void copyErrors(ErrorVec& errors, TypeArena& destArena) copyError(e, destArena, cloneState); }; - LUAU_ASSERT(!destArena.typeVars.isFrozen()); + LUAU_ASSERT(!destArena.types.isFrozen()); LUAU_ASSERT(!destArena.typePacks.isFrozen()); for (TypeError& error : errors) diff --git a/Analysis/src/Frontend.cpp b/Analysis/src/Frontend.cpp index e21e42e1..5d2c1587 100644 --- a/Analysis/src/Frontend.cpp +++ b/Analysis/src/Frontend.cpp @@ -65,14 +65,14 @@ static void generateDocumentationSymbols(TypeId ty, const std::string& rootName) asMutable(ty)->documentationSymbol = rootName; - if (TableTypeVar* ttv = getMutable(ty)) + if (TableType* ttv = getMutable(ty)) { for (auto& [name, prop] : ttv->props) { prop.documentationSymbol = rootName + "." + name; } } - else if (ClassTypeVar* ctv = getMutable(ty)) + else if (ClassType* ctv = getMutable(ty)) { for (auto& [name, prop] : ctv->props) { @@ -408,12 +408,12 @@ double getTimestamp() } // namespace Frontend::Frontend(FileResolver* fileResolver, ConfigResolver* configResolver, const FrontendOptions& options) - : singletonTypes(NotNull{&singletonTypes_}) + : builtinTypes(NotNull{&builtinTypes_}) , fileResolver(fileResolver) , moduleResolver(this) , moduleResolverForAutocomplete(this) - , typeChecker(&moduleResolver, singletonTypes, &iceHandler) - , typeCheckerForAutocomplete(&moduleResolverForAutocomplete, singletonTypes, &iceHandler) + , typeChecker(&moduleResolver, builtinTypes, &iceHandler) + , typeCheckerForAutocomplete(&moduleResolverForAutocomplete, builtinTypes, &iceHandler) , configResolver(configResolver) , options(options) , globalScope(typeChecker.globalScope) @@ -455,12 +455,7 @@ CheckResult Frontend::check(const ModuleName& name, std::optional buildQueue; - bool cycleDetected = parseGraph(buildQueue, checkResult, name, frontendOptions.forAutocomplete); - - // Keep track of which AST nodes we've reported cycles in - std::unordered_set reportedCycles; - - double autocompleteTimeLimit = FInt::LuauAutocompleteCheckTimeoutMs / 1000.0; + bool cycleDetected = parseGraph(buildQueue, name, frontendOptions.forAutocomplete); for (const ModuleName& moduleName : buildQueue) { @@ -499,6 +494,8 @@ CheckResult Frontend::check(const ModuleName& name, std::optional& buildQueue, CheckResult& checkResult, const ModuleName& root, bool forAutocomplete) +bool Frontend::parseGraph(std::vector& buildQueue, const ModuleName& root, bool forAutocomplete) { LUAU_TIMETRACE_SCOPE("Frontend::parseGraph", "Frontend"); LUAU_TIMETRACE_ARGUMENT("root", root.c_str()); @@ -618,7 +615,7 @@ bool Frontend::parseGraph(std::vector& buildQueue, CheckResult& chec bool cyclic = false; { - auto [sourceNode, _] = getSourceNode(checkResult, root); + auto [sourceNode, _] = getSourceNode(root); if (sourceNode) stack.push_back(sourceNode); } @@ -682,7 +679,7 @@ bool Frontend::parseGraph(std::vector& buildQueue, CheckResult& chec } } - auto [sourceNode, _] = getSourceNode(checkResult, dep); + auto [sourceNode, _] = getSourceNode(dep); if (sourceNode) { stack.push_back(sourceNode); @@ -729,8 +726,7 @@ LintResult Frontend::lint(const ModuleName& name, std::optional mr{forAutocomplete ? &moduleResolverForAutocomplete : &moduleResolver}; const ScopePtr& globalScope{forAutocomplete ? typeCheckerForAutocomplete.globalScope : typeChecker.globalScope}; - Normalizer normalizer{&result->internalTypes, singletonTypes, NotNull{&typeChecker.unifierState}}; + Normalizer normalizer{&result->internalTypes, builtinTypes, NotNull{&typeChecker.unifierState}}; ConstraintGraphBuilder cgb{ sourceModule.name, result, &result->internalTypes, mr, - singletonTypes, + builtinTypes, NotNull(&iceHandler), globalScope, logger.get(), @@ -910,7 +906,12 @@ ModulePtr Frontend::check( result->astResolvedTypePacks = std::move(cgb.astResolvedTypePacks); result->type = sourceModule.type; - Luau::check(singletonTypes, logger.get(), sourceModule, result.get()); + result->clonePublicInterface(builtinTypes, iceHandler); + + freeze(result->internalTypes); + freeze(result->interfaceTypes); + + Luau::check(builtinTypes, logger.get(), sourceModule, result.get()); if (FFlag::DebugLuauLogSolverToJson) { @@ -918,13 +919,11 @@ ModulePtr Frontend::check( printf("%s\n", output.c_str()); } - result->clonePublicInterface(singletonTypes, iceHandler); - return result; } // Read AST into sourceModules if necessary. Trace require()s. Report parse errors. -std::pair Frontend::getSourceNode(CheckResult& checkResult, const ModuleName& name) +std::pair Frontend::getSourceNode(const ModuleName& name) { LUAU_TIMETRACE_SCOPE("Frontend::getSourceNode", "Frontend"); LUAU_TIMETRACE_ARGUMENT("name", name.c_str()); diff --git a/Analysis/src/Instantiation.cpp b/Analysis/src/Instantiation.cpp index 3d0cd0d1..209ba7e9 100644 --- a/Analysis/src/Instantiation.cpp +++ b/Analysis/src/Instantiation.cpp @@ -11,7 +11,7 @@ namespace Luau bool Instantiation::isDirty(TypeId ty) { - if (const FunctionTypeVar* ftv = log->getMutable(ty)) + if (const FunctionType* ftv = log->getMutable(ty)) { if (ftv->hasNoGenerics) return false; @@ -31,9 +31,9 @@ bool Instantiation::isDirty(TypePackId tp) bool Instantiation::ignoreChildren(TypeId ty) { - if (log->getMutable(ty)) + if (log->getMutable(ty)) return true; - else if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) + else if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) return true; else return false; @@ -41,10 +41,10 @@ bool Instantiation::ignoreChildren(TypeId ty) TypeId Instantiation::clean(TypeId ty) { - const FunctionTypeVar* ftv = log->getMutable(ty); + const FunctionType* ftv = log->getMutable(ty); LUAU_ASSERT(ftv); - FunctionTypeVar clone = FunctionTypeVar{level, scope, ftv->argTypes, ftv->retTypes, ftv->definition, ftv->hasSelf}; + FunctionType clone = FunctionType{level, scope, ftv->argTypes, ftv->retTypes, ftv->definition, ftv->hasSelf}; clone.magicFunction = ftv->magicFunction; clone.dcrMagicFunction = ftv->dcrMagicFunction; clone.tags = ftv->tags; @@ -71,7 +71,7 @@ TypePackId Instantiation::clean(TypePackId tp) bool ReplaceGenerics::ignoreChildren(TypeId ty) { - if (const FunctionTypeVar* ftv = log->getMutable(ty)) + if (const FunctionType* ftv = log->getMutable(ty)) { if (ftv->hasNoGenerics) return true; @@ -83,7 +83,7 @@ bool ReplaceGenerics::ignoreChildren(TypeId ty) // whenever we quantify, so the vectors overlap if and only if they are equal. return (!generics.empty() || !genericPacks.empty()) && (ftv->generics == generics) && (ftv->genericPacks == genericPacks); } - else if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) + else if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) return true; else { @@ -93,9 +93,9 @@ bool ReplaceGenerics::ignoreChildren(TypeId ty) bool ReplaceGenerics::isDirty(TypeId ty) { - if (const TableTypeVar* ttv = log->getMutable(ty)) + if (const TableType* ttv = log->getMutable(ty)) return ttv->state == TableState::Generic; - else if (log->getMutable(ty)) + else if (log->getMutable(ty)) return std::find(generics.begin(), generics.end(), ty) != generics.end(); else return false; @@ -112,14 +112,14 @@ bool ReplaceGenerics::isDirty(TypePackId tp) TypeId ReplaceGenerics::clean(TypeId ty) { LUAU_ASSERT(isDirty(ty)); - if (const TableTypeVar* ttv = log->getMutable(ty)) + if (const TableType* ttv = log->getMutable(ty)) { - TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, level, scope, TableState::Free}; + TableType clone = TableType{ttv->props, ttv->indexer, level, scope, TableState::Free}; clone.definitionModuleName = ttv->definitionModuleName; return addType(std::move(clone)); } else - return addType(FreeTypeVar{scope, level}); + return addType(FreeType{scope, level}); } TypePackId ReplaceGenerics::clean(TypePackId tp) diff --git a/Analysis/src/IostreamHelpers.cpp b/Analysis/src/IostreamHelpers.cpp index cd59fdfb..43580da4 100644 --- a/Analysis/src/IostreamHelpers.cpp +++ b/Analysis/src/IostreamHelpers.cpp @@ -215,7 +215,7 @@ std::ostream& operator<<(std::ostream& stream, const TableState& tv) return stream << static_cast::type>(tv); } -std::ostream& operator<<(std::ostream& stream, const TypeVar& tv) +std::ostream& operator<<(std::ostream& stream, const Type& tv) { return stream << toString(tv); } diff --git a/Analysis/src/Linter.cpp b/Analysis/src/Linter.cpp index d5578446..4250b311 100644 --- a/Analysis/src/Linter.cpp +++ b/Analysis/src/Linter.cpp @@ -2144,14 +2144,14 @@ private: if (!ty) return true; - if (const ClassTypeVar* cty = get(follow(*ty))) + if (const ClassType* cty = get(follow(*ty))) { const Property* prop = lookupClassProp(cty, node->index.value); if (prop && prop->deprecated) report(node->location, *prop, cty->name.c_str(), node->index.value); } - else if (const TableTypeVar* tty = get(follow(*ty))) + else if (const TableType* tty = get(follow(*ty))) { auto prop = tty->props.find(node->index.value); @@ -2302,16 +2302,16 @@ private: size_t getReturnCount(TypeId ty) { - if (auto ftv = get(ty)) + if (auto ftv = get(ty)) return size(ftv->retTypes); - if (auto itv = get(ty)) + if (auto itv = get(ty)) { // We don't process the type recursively to avoid having to deal with self-recursive intersection types size_t result = 0; for (TypeId part : itv->parts) - if (auto ftv = get(follow(part))) + if (auto ftv = get(follow(part))) result = std::max(result, size(ftv->retTypes)); return result; diff --git a/Analysis/src/Module.cpp b/Analysis/src/Module.cpp index 62674aa8..a73b928b 100644 --- a/Analysis/src/Module.cpp +++ b/Analysis/src/Module.cpp @@ -9,8 +9,8 @@ #include "Luau/Scope.h" #include "Luau/TypeInfer.h" #include "Luau/TypePack.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" #include @@ -60,12 +60,12 @@ bool isWithinComment(const SourceModule& sourceModule, Position pos) struct ClonePublicInterface : Substitution { - NotNull singletonTypes; + NotNull builtinTypes; NotNull module; - ClonePublicInterface(const TxnLog* log, NotNull singletonTypes, Module* module) + ClonePublicInterface(const TxnLog* log, NotNull builtinTypes, Module* module) : Substitution(log, &module->interfaceTypes) - , singletonTypes(singletonTypes) + , builtinTypes(builtinTypes) , module(module) { LUAU_ASSERT(module); @@ -76,9 +76,9 @@ struct ClonePublicInterface : Substitution if (ty->owningArena == &module->internalTypes) return true; - if (const FunctionTypeVar* ftv = get(ty)) + if (const FunctionType* ftv = get(ty)) return ftv->level.level != 0; - if (const TableTypeVar* ttv = get(ty)) + if (const TableType* ttv = get(ty)) return ttv->level.level != 0; return false; } @@ -92,9 +92,9 @@ struct ClonePublicInterface : Substitution { TypeId result = clone(ty); - if (FunctionTypeVar* ftv = getMutable(result)) + if (FunctionType* ftv = getMutable(result)) ftv->level = TypeLevel{0, 0}; - else if (TableTypeVar* ttv = getMutable(result)) + else if (TableType* ttv = getMutable(result)) ttv->level = TypeLevel{0, 0}; return result; @@ -117,7 +117,7 @@ struct ClonePublicInterface : Substitution else { module->errors.push_back(TypeError{module->scopes[0].first, UnificationTooComplex{}}); - return singletonTypes->errorRecoveryType(); + return builtinTypes->errorRecoveryType(); } } @@ -133,7 +133,7 @@ struct ClonePublicInterface : Substitution else { module->errors.push_back(TypeError{module->scopes[0].first, UnificationTooComplex{}}); - return singletonTypes->errorRecoveryTypePack(); + return builtinTypes->errorRecoveryTypePack(); } } @@ -178,9 +178,9 @@ Module::~Module() unfreeze(internalTypes); } -void Module::clonePublicInterface(NotNull singletonTypes, InternalErrorReporter& ice) +void Module::clonePublicInterface(NotNull builtinTypes, InternalErrorReporter& ice) { - LUAU_ASSERT(interfaceTypes.typeVars.empty()); + LUAU_ASSERT(interfaceTypes.types.empty()); LUAU_ASSERT(interfaceTypes.typePacks.empty()); CloneState cloneState; @@ -192,7 +192,7 @@ void Module::clonePublicInterface(NotNull singletonTypes, Intern std::unordered_map* exportedTypeBindings = &moduleScope->exportedTypeBindings; TxnLog log; - ClonePublicInterface clonePublicInterface{&log, singletonTypes, this}; + ClonePublicInterface clonePublicInterface{&log, builtinTypes, this}; if (FFlag::LuauClonePublicInterfaceLess) returnType = clonePublicInterface.cloneTypePack(returnType); diff --git a/Analysis/src/Normalize.cpp b/Analysis/src/Normalize.cpp index 09f0595d..b6654659 100644 --- a/Analysis/src/Normalize.cpp +++ b/Analysis/src/Normalize.cpp @@ -8,7 +8,7 @@ #include "Luau/Clone.h" #include "Luau/Common.h" #include "Luau/RecursionCounter.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/Unifier.h" LUAU_FASTFLAGVARIABLE(DebugLuauCopyBeforeNormalizing, false) @@ -19,6 +19,7 @@ LUAU_FASTINTVARIABLE(LuauNormalizeIterationLimit, 1200); LUAU_FASTINTVARIABLE(LuauNormalizeCacheLimit, 100000); LUAU_FASTFLAGVARIABLE(LuauNormalizeCombineTableFix, false); LUAU_FASTFLAGVARIABLE(LuauTypeNormalization2, false); +LUAU_FASTFLAGVARIABLE(LuauNegatedClassTypes, false); LUAU_FASTFLAGVARIABLE(LuauNegatedFunctionTypes, false); LUAU_FASTFLAG(LuauUnknownAndNeverType) LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) @@ -115,8 +116,7 @@ bool TypeIds::operator==(const TypeIds& there) const return hash == there.hash && types == there.types; } -NormalizedStringType::NormalizedStringType() -{} +NormalizedStringType::NormalizedStringType() {} NormalizedStringType::NormalizedStringType(bool isCofinite, std::map singletons) : isCofinite(isCofinite) @@ -186,6 +186,23 @@ bool isSubtype(const NormalizedStringType& subStr, const NormalizedStringType& s return true; } +void NormalizedClassType::pushPair(TypeId ty, TypeIds negations) +{ + ordering.push_back(ty); + classes.insert(std::make_pair(ty, std::move(negations))); +} + +void NormalizedClassType::resetToNever() +{ + ordering.clear(); + classes.clear(); +} + +bool NormalizedClassType::isNever() const +{ + return classes.empty(); +} + NormalizedFunctionType::NormalizedFunctionType() : parts(FFlag::LuauNegatedFunctionTypes ? std::optional{TypeIds{}} : std::nullopt) { @@ -208,22 +225,29 @@ bool NormalizedFunctionType::isNever() const return !isTop && (!parts || parts->empty()); } -NormalizedType::NormalizedType(NotNull singletonTypes) - : tops(singletonTypes->neverType) - , booleans(singletonTypes->neverType) - , errors(singletonTypes->neverType) - , nils(singletonTypes->neverType) - , numbers(singletonTypes->neverType) +NormalizedType::NormalizedType(NotNull builtinTypes) + : tops(builtinTypes->neverType) + , booleans(builtinTypes->neverType) + , errors(builtinTypes->neverType) + , nils(builtinTypes->neverType) + , numbers(builtinTypes->neverType) , strings{NormalizedStringType::never} - , threads(singletonTypes->neverType) + , threads(builtinTypes->neverType) { } static bool isShallowInhabited(const NormalizedType& norm) { + bool inhabitedClasses; + + if (FFlag::LuauNegatedClassTypes) + inhabitedClasses = !norm.classes.isNever(); + else + inhabitedClasses = !norm.DEPRECATED_classes.empty(); + // This test is just a shallow check, for example it returns `true` for `{ p : never }` - return !get(norm.tops) || !get(norm.booleans) || !norm.classes.empty() || !get(norm.errors) || - !get(norm.nils) || !get(norm.numbers) || !norm.strings.isNever() || !get(norm.threads) || + return !get(norm.tops) || !get(norm.booleans) || inhabitedClasses || !get(norm.errors) || + !get(norm.nils) || !get(norm.numbers) || !norm.strings.isNever() || !get(norm.threads) || !norm.functions.isNever() || !norm.tables.empty() || !norm.tyvars.empty(); } @@ -239,9 +263,15 @@ bool Normalizer::isInhabited(const NormalizedType* norm, std::unordered_set(norm->tops) || !get(norm->booleans) || !get(norm->errors) || - !get(norm->nils) || !get(norm->numbers) || !get(norm->threads) || - !norm->classes.empty() || !norm->strings.isNever() || !norm->functions.isNever()) + bool inhabitedClasses; + if (FFlag::LuauNegatedClassTypes) + inhabitedClasses = !norm->classes.isNever(); + else + inhabitedClasses = !norm->DEPRECATED_classes.empty(); + + if (!get(norm->tops) || !get(norm->booleans) || !get(norm->errors) || !get(norm->nils) || + !get(norm->numbers) || !get(norm->threads) || inhabitedClasses || !norm->strings.isNever() || + !norm->functions.isNever()) return true; for (const auto& [_, intersect] : norm->tyvars) @@ -264,10 +294,10 @@ bool Normalizer::isInhabited(TypeId ty, std::unordered_set seen) // TODO: use log.follow(ty), CLI-64291 ty = follow(ty); - if (get(ty)) + if (get(ty)) return false; - if (!get(ty) && !get(ty) && !get(ty) && !get(ty)) + if (!get(ty) && !get(ty) && !get(ty) && !get(ty)) return true; if (seen.count(ty)) @@ -275,7 +305,7 @@ bool Normalizer::isInhabited(TypeId ty, std::unordered_set seen) seen.insert(ty); - if (const TableTypeVar* ttv = get(ty)) + if (const TableType* ttv = get(ty)) { for (const auto& [_, prop] : ttv->props) { @@ -285,7 +315,7 @@ bool Normalizer::isInhabited(TypeId ty, std::unordered_set seen) return true; } - if (const MetatableTypeVar* mtv = get(ty)) + if (const MetatableType* mtv = get(ty)) return isInhabited(mtv->table, seen) && isInhabited(mtv->metatable, seen); const NormalizedType* norm = normalize(ty); @@ -294,28 +324,50 @@ bool Normalizer::isInhabited(TypeId ty, std::unordered_set seen) static int tyvarIndex(TypeId ty) { - if (const GenericTypeVar* gtv = get(ty)) + if (const GenericType* gtv = get(ty)) return gtv->index; - else if (const FreeTypeVar* ftv = get(ty)) + else if (const FreeType* ftv = get(ty)) return ftv->index; else return 0; } +static bool isTop(NotNull builtinTypes, const NormalizedClassType& classes) +{ + if (classes.classes.size() != 1) + return false; + + auto first = classes.classes.begin(); + if (first->first != builtinTypes->classType) + return false; + + if (!first->second.empty()) + return false; + + return true; +} + +static void resetToTop(NotNull builtinTypes, NormalizedClassType& classes) +{ + classes.ordering.clear(); + classes.classes.clear(); + classes.pushPair(builtinTypes->classType, TypeIds{}); +} + #ifdef LUAU_ASSERTENABLED static bool isNormalizedTop(TypeId ty) { - return get(ty) || get(ty) || get(ty); + return get(ty) || get(ty) || get(ty); } static bool isNormalizedBoolean(TypeId ty) { - if (get(ty)) + if (get(ty)) return true; - else if (const PrimitiveTypeVar* ptv = get(ty)) - return ptv->type == PrimitiveTypeVar::Boolean; - else if (const SingletonTypeVar* stv = get(ty)) + else if (const PrimitiveType* ptv = get(ty)) + return ptv->type == PrimitiveType::Boolean; + else if (const SingletonType* stv = get(ty)) return get(stv); else return false; @@ -323,7 +375,7 @@ static bool isNormalizedBoolean(TypeId ty) static bool isNormalizedError(TypeId ty) { - if (get(ty) || get(ty)) + if (get(ty) || get(ty)) return true; else return false; @@ -331,20 +383,20 @@ static bool isNormalizedError(TypeId ty) static bool isNormalizedNil(TypeId ty) { - if (get(ty)) + if (get(ty)) return true; - else if (const PrimitiveTypeVar* ptv = get(ty)) - return ptv->type == PrimitiveTypeVar::NilType; + else if (const PrimitiveType* ptv = get(ty)) + return ptv->type == PrimitiveType::NilType; else return false; } static bool isNormalizedNumber(TypeId ty) { - if (get(ty)) + if (get(ty)) return true; - else if (const PrimitiveTypeVar* ptv = get(ty)) - return ptv->type == PrimitiveTypeVar::Number; + else if (const PrimitiveType* ptv = get(ty)) + return ptv->type == PrimitiveType::Number; else return false; } @@ -356,7 +408,7 @@ static bool isNormalizedString(const NormalizedStringType& ty) for (auto& [str, ty] : ty.singletons) { - if (const SingletonTypeVar* stv = get(ty)) + if (const SingletonType* stv = get(ty)) { if (const StringSingleton* sstv = get(stv)) { @@ -375,10 +427,10 @@ static bool isNormalizedString(const NormalizedStringType& ty) static bool isNormalizedThread(TypeId ty) { - if (get(ty)) + if (get(ty)) return true; - else if (const PrimitiveTypeVar* ptv = get(ty)) - return ptv->type == PrimitiveTypeVar::Thread; + else if (const PrimitiveType* ptv = get(ty)) + return ptv->type == PrimitiveType::Thread; else return false; } @@ -389,7 +441,7 @@ static bool areNormalizedFunctions(const NormalizedFunctionType& tys) { for (TypeId ty : *tys.parts) { - if (!get(ty) && !get(ty)) + if (!get(ty) && !get(ty)) return false; } } @@ -399,7 +451,7 @@ static bool areNormalizedFunctions(const NormalizedFunctionType& tys) static bool areNormalizedTables(const TypeIds& tys) { for (TypeId ty : tys) - if (!get(ty) && !get(ty)) + if (!get(ty) && !get(ty)) return false; return true; } @@ -407,14 +459,68 @@ static bool areNormalizedTables(const TypeIds& tys) static bool areNormalizedClasses(const TypeIds& tys) { for (TypeId ty : tys) - if (!get(ty)) + if (!get(ty)) return false; return true; } +static bool areNormalizedClasses(const NormalizedClassType& tys) +{ + for (const auto& [ty, negations] : tys.classes) + { + const ClassType* ctv = get(ty); + if (!ctv) + { + return false; + } + + for (TypeId negation : negations) + { + const ClassType* nctv = get(negation); + if (!nctv) + { + return false; + } + + if (!isSubclass(nctv, ctv)) + { + return false; + } + } + + for (const auto& [otherTy, otherNegations] : tys.classes) + { + if (otherTy == ty) + continue; + + const ClassType* octv = get(otherTy); + if (!octv) + { + return false; + } + + if (isSubclass(ctv, octv)) + { + auto iss = [ctv](TypeId t) { + const ClassType* c = get(t); + if (!c) + return false; + + return isSubclass(ctv, c); + }; + + if (!std::any_of(otherNegations.begin(), otherNegations.end(), iss)) + return false; + } + } + } + + return true; +} + static bool isPlainTyvar(TypeId ty) { - return (get(ty) || get(ty)); + return (get(ty) || get(ty)); } static bool isNormalizedTyvar(const NormalizedTyvars& tyvars) @@ -442,6 +548,7 @@ static void assertInvariant(const NormalizedType& norm) LUAU_ASSERT(isNormalizedTop(norm.tops)); LUAU_ASSERT(isNormalizedBoolean(norm.booleans)); + LUAU_ASSERT(areNormalizedClasses(norm.DEPRECATED_classes)); LUAU_ASSERT(areNormalizedClasses(norm.classes)); LUAU_ASSERT(isNormalizedError(norm.errors)); LUAU_ASSERT(isNormalizedNil(norm.nils)); @@ -456,9 +563,9 @@ static void assertInvariant(const NormalizedType& norm) #endif } -Normalizer::Normalizer(TypeArena* arena, NotNull singletonTypes, NotNull sharedState) +Normalizer::Normalizer(TypeArena* arena, NotNull builtinTypes, NotNull sharedState) : arena(arena) - , singletonTypes(singletonTypes) + , builtinTypes(builtinTypes) , sharedState(sharedState) { } @@ -472,7 +579,7 @@ const NormalizedType* Normalizer::normalize(TypeId ty) if (found != cachedNormals.end()) return found->second.get(); - NormalizedType norm{singletonTypes}; + NormalizedType norm{builtinTypes}; if (!unionNormalWithTy(norm, ty)) return nullptr; std::unique_ptr uniq = std::make_unique(std::move(norm)); @@ -483,14 +590,15 @@ const NormalizedType* Normalizer::normalize(TypeId ty) void Normalizer::clearNormal(NormalizedType& norm) { - norm.tops = singletonTypes->neverType; - norm.booleans = singletonTypes->neverType; - norm.classes.clear(); - norm.errors = singletonTypes->neverType; - norm.nils = singletonTypes->neverType; - norm.numbers = singletonTypes->neverType; + norm.tops = builtinTypes->neverType; + norm.booleans = builtinTypes->neverType; + norm.classes.resetToNever(); + norm.DEPRECATED_classes.clear(); + norm.errors = builtinTypes->neverType; + norm.nils = builtinTypes->neverType; + norm.numbers = builtinTypes->neverType; norm.strings.resetToNever(); - norm.threads = singletonTypes->neverType; + norm.threads = builtinTypes->neverType; norm.tables.clear(); norm.functions.resetToNever(); norm.tyvars.clear(); @@ -516,14 +624,14 @@ TypeId Normalizer::unionType(TypeId here, TypeId there) if (here == there) return here; - if (get(here) || get(there)) + if (get(here) || get(there)) return there; - if (get(there) || get(here)) + if (get(there) || get(here)) return here; TypeIds tmps; - if (const UnionTypeVar* utv = get(here)) + if (const UnionType* utv = get(here)) { TypeIds heres; heres.insert(begin(utv), end(utv)); @@ -533,7 +641,7 @@ TypeId Normalizer::unionType(TypeId here, TypeId there) else tmps.insert(here); - if (const UnionTypeVar* utv = get(there)) + if (const UnionType* utv = get(there)) { TypeIds theres; theres.insert(begin(utv), end(utv)); @@ -549,7 +657,7 @@ TypeId Normalizer::unionType(TypeId here, TypeId there) std::vector parts; parts.insert(parts.end(), tmps.begin(), tmps.end()); - TypeId result = arena->addType(UnionTypeVar{std::move(parts)}); + TypeId result = arena->addType(UnionType{std::move(parts)}); cachedUnions[cacheTypeIds(std::move(tmps))] = result; return result; @@ -562,14 +670,14 @@ TypeId Normalizer::intersectionType(TypeId here, TypeId there) if (here == there) return here; - if (get(here) || get(there)) + if (get(here) || get(there)) return here; - if (get(there) || get(here)) + if (get(there) || get(here)) return there; TypeIds tmps; - if (const IntersectionTypeVar* utv = get(here)) + if (const IntersectionType* utv = get(here)) { TypeIds heres; heres.insert(begin(utv), end(utv)); @@ -579,7 +687,7 @@ TypeId Normalizer::intersectionType(TypeId here, TypeId there) else tmps.insert(here); - if (const IntersectionTypeVar* utv = get(there)) + if (const IntersectionType* utv = get(there)) { TypeIds theres; theres.insert(begin(utv), end(utv)); @@ -598,7 +706,7 @@ TypeId Normalizer::intersectionType(TypeId here, TypeId there) std::vector parts; parts.insert(parts.end(), tmps.begin(), tmps.end()); - TypeId result = arena->addType(IntersectionTypeVar{std::move(parts)}); + TypeId result = arena->addType(IntersectionType{std::move(parts)}); cachedIntersections[cacheTypeIds(std::move(tmps))] = result; return result; @@ -615,7 +723,7 @@ void Normalizer::clearCaches() // ------- Normalizing unions TypeId Normalizer::unionOfTops(TypeId here, TypeId there) { - if (get(here) || get(there)) + if (get(here) || get(there)) return there; else return here; @@ -623,15 +731,15 @@ TypeId Normalizer::unionOfTops(TypeId here, TypeId there) TypeId Normalizer::unionOfBools(TypeId here, TypeId there) { - if (get(here)) + if (get(here)) return there; - if (get(there)) + if (get(there)) return here; - if (const BooleanSingleton* hbool = get(get(here))) - if (const BooleanSingleton* tbool = get(get(there))) + if (const BooleanSingleton* hbool = get(get(here))) + if (const BooleanSingleton* tbool = get(get(there))) if (hbool->value == tbool->value) return here; - return singletonTypes->booleanType; + return builtinTypes->booleanType; } void Normalizer::unionClassesWithClass(TypeIds& heres, TypeId there) @@ -639,12 +747,12 @@ void Normalizer::unionClassesWithClass(TypeIds& heres, TypeId there) if (heres.count(there)) return; - const ClassTypeVar* tctv = get(there); + const ClassType* tctv = get(there); for (auto it = heres.begin(); it != heres.end();) { TypeId here = *it; - const ClassTypeVar* hctv = get(here); + const ClassType* hctv = get(here); if (isSubclass(tctv, hctv)) return; else if (isSubclass(hctv, tctv)) @@ -662,6 +770,184 @@ void Normalizer::unionClasses(TypeIds& heres, const TypeIds& theres) unionClassesWithClass(heres, there); } +static bool isSubclass(TypeId test, TypeId parent) +{ + const ClassType* testCtv = get(test); + const ClassType* parentCtv = get(parent); + + LUAU_ASSERT(testCtv); + LUAU_ASSERT(parentCtv); + + return isSubclass(testCtv, parentCtv); +} + +void Normalizer::unionClassesWithClass(NormalizedClassType& heres, TypeId there) +{ + for (auto it = heres.ordering.begin(); it != heres.ordering.end();) + { + TypeId hereTy = *it; + TypeIds& hereNegations = heres.classes.at(hereTy); + + // If the incoming class is a subclass of another class in the map, we + // must ensure that it is negated by one of the negations in the same + // cluster. If it isn't, we do not need to insert it - the subtyping + // relationship is already handled by this entry. If it is, we must + // insert it, to capture the presence of this particular subtype. + if (isSubclass(there, hereTy)) + { + for (auto nIt = hereNegations.begin(); nIt != hereNegations.end();) + { + TypeId hereNegation = *nIt; + + // If the incoming class is a subclass of one of the negations, + // we must insert it into the class map. + if (isSubclass(there, hereNegation)) + { + heres.pushPair(there, TypeIds{}); + return; + } + // If the incoming class is a superclass of one of the + // negations, then the negation no longer applies and must be + // removed. This is also true if they are equal. Since classes + // are, at this time, entirely persistent (we do not clone + // them), a pointer identity check is sufficient. + else if (isSubclass(hereNegation, there)) + { + nIt = hereNegations.erase(nIt); + } + // If the incoming class is unrelated to the negation, we move + // on to the next item. + else + { + ++nIt; + } + } + + // If, at the end of the above loop, we haven't returned, that means + // that the class is not a subclass of one of the negations, and is + // covered by the existing subtype relationship. We can return now. + return; + } + // If the incoming class is a superclass of another class in the map, we + // need to replace the existing class with the incoming class, + // preserving the relevant negations. + else if (isSubclass(hereTy, there)) + { + TypeIds negations = std::move(hereNegations); + it = heres.ordering.erase(it); + heres.classes.erase(hereTy); + + heres.pushPair(there, std::move(negations)); + return; + } + + // If the incoming class is unrelated to the class in the map, we move + // on. If we do not otherwise exit from this method body, we will + // eventually fall out of this loop and insert the incoming class, which + // we have proven to be completely unrelated to any class in the map, + // into the map itself. + ++it; + } + + heres.pushPair(there, TypeIds{}); +} + +void Normalizer::unionClasses(NormalizedClassType& heres, const NormalizedClassType& theres) +{ + // This method bears much similarity with unionClassesWithClass, but is + // solving a more general problem. In unionClassesWithClass, we are dealing + // with a singular positive type. Since it's one type, we can use early + // returns as control flow. Since it's guaranteed to be positive, we do not + // have negations to worry about combining. The two aspects combine to make + // the tasks this method must perform different enough to warrant a separate + // implementation. + + for (const TypeId thereTy : theres.ordering) + { + const TypeIds& thereNegations = theres.classes.at(thereTy); + + // If it happens that there are _no_ classes in the current map, or the + // incoming class is completely unrelated to any class in the current + // map, we must insert the incoming pair as-is. + bool insert = true; + + for (auto it = heres.ordering.begin(); it != heres.ordering.end();) + { + TypeId hereTy = *it; + TypeIds& hereNegations = heres.classes.at(hereTy); + + if (isSubclass(thereTy, hereTy)) + { + bool inserted = false; + for (auto nIt = hereNegations.begin(); nIt != hereNegations.end();) + { + TypeId hereNegateTy = *nIt; + + // If the incoming class is a subclass of one of the negations, + // we must insert it into the class map. + if (isSubclass(thereTy, hereNegateTy)) + { + // We do not concern ourselves with iterator + // invalidation here because we will break out of the + // loop over `heres` when `inserted` is set, and we do + // not read from the iterator after this point. + inserted = true; + heres.pushPair(thereTy, thereNegations); + break; + } + // If the incoming class is a superclass of one of the + // negations, then the negation no longer applies and must + // be removed. This is also true if they are equal. Since + // classes are, at this time, entirely persistent (we do not + // clone them), a pointer identity check is sufficient. + else if (isSubclass(hereNegateTy, thereTy)) + { + inserted = true; + nIt = hereNegations.erase(nIt); + break; + } + // If the incoming class is unrelated to the negation, we + // move on to the next item. + else + { + ++nIt; + } + } + + if (inserted) + { + insert = false; + break; + } + } + else if (isSubclass(hereTy, thereTy)) + { + TypeIds negations = std::move(hereNegations); + unionClasses(negations, thereNegations); + + it = heres.ordering.erase(it); + heres.classes.erase(hereTy); + heres.pushPair(thereTy, std::move(negations)); + insert = false; + break; + } + else if (hereTy == thereTy) + { + unionClasses(hereNegations, thereNegations); + insert = false; + break; + } + + ++it; + } + + if (insert) + { + heres.pushPair(thereTy, thereNegations); + } + } +} + void Normalizer::unionStrings(NormalizedStringType& here, const NormalizedStringType& there) { if (there.isString()) @@ -738,7 +1024,7 @@ std::optional Normalizer::unionOfTypePacks(TypePackId here, TypePack bool& thereSubHere) { if (ith != end(here)) { - TypeId tty = singletonTypes->nilType; + TypeId tty = builtinTypes->nilType; if (std::optional ttail = itt.tail()) { if (const VariadicTypePack* tvtp = get(*ttail)) @@ -834,15 +1120,15 @@ std::optional Normalizer::unionOfTypePacks(TypePackId here, TypePack std::optional Normalizer::unionOfFunctions(TypeId here, TypeId there) { - if (get(here)) + if (get(here)) return here; - if (get(there)) + if (get(there)) return there; - const FunctionTypeVar* hftv = get(here); + const FunctionType* hftv = get(here); LUAU_ASSERT(hftv); - const FunctionTypeVar* tftv = get(there); + const FunctionType* tftv = get(there); LUAU_ASSERT(tftv); if (hftv->generics != tftv->generics) @@ -863,7 +1149,7 @@ std::optional Normalizer::unionOfFunctions(TypeId here, TypeId there) if (*argTypes == tftv->argTypes && *retTypes == tftv->retTypes) return there; - FunctionTypeVar result{*argTypes, *retTypes}; + FunctionType result{*argTypes, *retTypes}; result.generics = hftv->generics; result.genericPacks = hftv->genericPacks; return arena->addType(std::move(result)); @@ -897,7 +1183,7 @@ void Normalizer::unionFunctions(NormalizedFunctionType& heres, const NormalizedF if (std::optional fun = unionOfFunctions(here, there)) tmps.insert(*fun); else - tmps.insert(singletonTypes->errorRecoveryType(there)); + tmps.insert(builtinTypes->errorRecoveryType(there)); } heres.parts = std::move(tmps); @@ -919,7 +1205,7 @@ void Normalizer::unionFunctionsWithFunction(NormalizedFunctionType& heres, TypeI if (std::optional fun = unionOfFunctions(here, there)) tmps.insert(*fun); else - tmps.insert(singletonTypes->errorRecoveryType(there)); + tmps.insert(builtinTypes->errorRecoveryType(there)); } heres.parts = std::move(tmps); } @@ -958,7 +1244,7 @@ void Normalizer::unionTables(TypeIds& heres, const TypeIds& theres) bool Normalizer::unionNormals(NormalizedType& here, const NormalizedType& there, int ignoreSmallerTyvars) { TypeId tops = unionOfTops(here.tops, there.tops); - if (!get(tops)) + if (!get(tops)) { clearNormal(here); here.tops = tops; @@ -972,7 +1258,7 @@ bool Normalizer::unionNormals(NormalizedType& here, const NormalizedType& there, int index = tyvarIndex(tyvar); if (index <= ignoreSmallerTyvars) continue; - auto [emplaced, fresh] = here.tyvars.emplace(tyvar, std::make_unique(NormalizedType{singletonTypes})); + auto [emplaced, fresh] = here.tyvars.emplace(tyvar, std::make_unique(NormalizedType{builtinTypes})); if (fresh) if (!unionNormals(*emplaced->second, here, index)) return false; @@ -981,12 +1267,16 @@ bool Normalizer::unionNormals(NormalizedType& here, const NormalizedType& there, } here.booleans = unionOfBools(here.booleans, there.booleans); - unionClasses(here.classes, there.classes); - here.errors = (get(there.errors) ? here.errors : there.errors); - here.nils = (get(there.nils) ? here.nils : there.nils); - here.numbers = (get(there.numbers) ? here.numbers : there.numbers); + if (FFlag::LuauNegatedClassTypes) + unionClasses(here.classes, there.classes); + else + unionClasses(here.DEPRECATED_classes, there.DEPRECATED_classes); + + here.errors = (get(there.errors) ? here.errors : there.errors); + here.nils = (get(there.nils) ? here.nils : there.nils); + here.numbers = (get(there.numbers) ? here.numbers : there.numbers); unionStrings(here.strings, there.strings); - here.threads = (get(there.threads) ? here.threads : there.threads); + here.threads = (get(there.threads) ? here.threads : there.threads); unionFunctions(here.functions, there.functions); unionTables(here.tables, there.tables); return true; @@ -1021,60 +1311,69 @@ bool Normalizer::unionNormalWithTy(NormalizedType& here, TypeId there, int ignor return false; there = follow(there); - if (get(there) || get(there)) + if (get(there) || get(there)) { TypeId tops = unionOfTops(here.tops, there); clearNormal(here); here.tops = tops; return true; } - else if (get(there) || !get(here.tops)) + else if (get(there) || !get(here.tops)) return true; - else if (const UnionTypeVar* utv = get(there)) + else if (const UnionType* utv = get(there)) { - for (UnionTypeVarIterator it = begin(utv); it != end(utv); ++it) + for (UnionTypeIterator it = begin(utv); it != end(utv); ++it) if (!unionNormalWithTy(here, *it)) return false; return true; } - else if (const IntersectionTypeVar* itv = get(there)) + else if (const IntersectionType* itv = get(there)) { - NormalizedType norm{singletonTypes}; - norm.tops = singletonTypes->anyType; - for (IntersectionTypeVarIterator it = begin(itv); it != end(itv); ++it) + NormalizedType norm{builtinTypes}; + norm.tops = builtinTypes->anyType; + for (IntersectionTypeIterator it = begin(itv); it != end(itv); ++it) if (!intersectNormalWithTy(norm, *it)) return false; return unionNormals(here, norm); } - else if (get(there) || get(there)) + else if (get(there) || get(there)) { if (tyvarIndex(there) <= ignoreSmallerTyvars) return true; - NormalizedType inter{singletonTypes}; - inter.tops = singletonTypes->unknownType; + NormalizedType inter{builtinTypes}; + inter.tops = builtinTypes->unknownType; here.tyvars.insert_or_assign(there, std::make_unique(std::move(inter))); } - else if (get(there)) + else if (get(there)) unionFunctionsWithFunction(here.functions, there); - else if (get(there) || get(there)) + else if (get(there) || get(there)) unionTablesWithTable(here.tables, there); - else if (get(there)) - unionClassesWithClass(here.classes, there); - else if (get(there)) - here.errors = there; - else if (const PrimitiveTypeVar* ptv = get(there)) + else if (get(there)) { - if (ptv->type == PrimitiveTypeVar::Boolean) + if (FFlag::LuauNegatedClassTypes) + { + unionClassesWithClass(here.classes, there); + } + else + { + unionClassesWithClass(here.DEPRECATED_classes, there); + } + } + else if (get(there)) + here.errors = there; + else if (const PrimitiveType* ptv = get(there)) + { + if (ptv->type == PrimitiveType::Boolean) here.booleans = there; - else if (ptv->type == PrimitiveTypeVar::NilType) + else if (ptv->type == PrimitiveType::NilType) here.nils = there; - else if (ptv->type == PrimitiveTypeVar::Number) + else if (ptv->type == PrimitiveType::Number) here.numbers = there; - else if (ptv->type == PrimitiveTypeVar::String) + else if (ptv->type == PrimitiveType::String) here.strings.resetToString(); - else if (ptv->type == PrimitiveTypeVar::Thread) + else if (ptv->type == PrimitiveType::Thread) here.threads = there; - else if (ptv->type == PrimitiveTypeVar::Function) + else if (ptv->type == PrimitiveType::Function) { LUAU_ASSERT(FFlag::LuauNegatedFunctionTypes); here.functions.resetToTop(); @@ -1082,7 +1381,7 @@ bool Normalizer::unionNormalWithTy(NormalizedType& here, TypeId there, int ignor else LUAU_ASSERT(!"Unreachable"); } - else if (const SingletonTypeVar* stv = get(there)) + else if (const SingletonType* stv = get(there)) { if (get(stv)) here.booleans = unionOfBools(here.booleans, there); @@ -1100,7 +1399,7 @@ bool Normalizer::unionNormalWithTy(NormalizedType& here, TypeId there, int ignor else LUAU_ASSERT(!"Unreachable"); } - else if (const NegationTypeVar* ntv = get(there)) + else if (const NegationType* ntv = get(there)) { const NormalizedType* thereNormal = normalize(ntv->ty); std::optional tn = negateNormal(*thereNormal); @@ -1125,42 +1424,73 @@ bool Normalizer::unionNormalWithTy(NormalizedType& here, TypeId there, int ignor std::optional Normalizer::negateNormal(const NormalizedType& here) { - NormalizedType result{singletonTypes}; - if (!get(here.tops)) + NormalizedType result{builtinTypes}; + if (!get(here.tops)) { // The negation of unknown or any is never. Easy. return result; } - if (!get(here.errors)) + if (!get(here.errors)) { // Negating an error yields the same error. result.errors = here.errors; return result; } - if (get(here.booleans)) - result.booleans = singletonTypes->booleanType; - else if (get(here.booleans)) - result.booleans = singletonTypes->neverType; - else if (auto stv = get(here.booleans)) + if (get(here.booleans)) + result.booleans = builtinTypes->booleanType; + else if (get(here.booleans)) + result.booleans = builtinTypes->neverType; + else if (auto stv = get(here.booleans)) { auto boolean = get(stv); LUAU_ASSERT(boolean != nullptr); if (boolean->value) - result.booleans = singletonTypes->falseType; + result.booleans = builtinTypes->falseType; else - result.booleans = singletonTypes->trueType; + result.booleans = builtinTypes->trueType; } - result.classes = negateAll(here.classes); - result.nils = get(here.nils) ? singletonTypes->nilType : singletonTypes->neverType; - result.numbers = get(here.numbers) ? singletonTypes->numberType : singletonTypes->neverType; + if (FFlag::LuauNegatedClassTypes) + { + if (here.classes.isNever()) + { + resetToTop(builtinTypes, result.classes); + } + else if (isTop(builtinTypes, result.classes)) + { + result.classes.resetToNever(); + } + else + { + TypeIds rootNegations{}; + + for (const auto& [hereParent, hereNegations] : here.classes.classes) + { + if (hereParent != builtinTypes->classType) + rootNegations.insert(hereParent); + + for (TypeId hereNegation : hereNegations) + unionClassesWithClass(result.classes, hereNegation); + } + + if (!rootNegations.empty()) + result.classes.pushPair(builtinTypes->classType, rootNegations); + } + } + else + { + result.DEPRECATED_classes = negateAll(here.DEPRECATED_classes); + } + + result.nils = get(here.nils) ? builtinTypes->nilType : builtinTypes->neverType; + result.numbers = get(here.numbers) ? builtinTypes->numberType : builtinTypes->neverType; result.strings = here.strings; result.strings.isCofinite = !result.strings.isCofinite; - result.threads = get(here.threads) ? singletonTypes->threadType : singletonTypes->neverType; + result.threads = get(here.threads) ? builtinTypes->threadType : builtinTypes->neverType; /* * Things get weird and so, so complicated if we allow negations of @@ -1194,27 +1524,27 @@ TypeIds Normalizer::negateAll(const TypeIds& theres) TypeId Normalizer::negate(TypeId there) { there = follow(there); - if (get(there)) + if (get(there)) return there; - else if (get(there)) - return singletonTypes->neverType; - else if (get(there)) - return singletonTypes->unknownType; - else if (auto ntv = get(there)) + else if (get(there)) + return builtinTypes->neverType; + else if (get(there)) + return builtinTypes->unknownType; + else if (auto ntv = get(there)) return ntv->ty; // TODO: do we want to normalize this? - else if (auto utv = get(there)) + else if (auto utv = get(there)) { std::vector parts; for (TypeId option : utv) parts.push_back(negate(option)); - return arena->addType(IntersectionTypeVar{std::move(parts)}); + return arena->addType(IntersectionType{std::move(parts)}); } - else if (auto itv = get(there)) + else if (auto itv = get(there)) { std::vector options; for (TypeId part : itv) options.push_back(negate(part)); - return arena->addType(UnionTypeVar{std::move(options)}); + return arena->addType(UnionType{std::move(options)}); } else return there; @@ -1222,26 +1552,26 @@ TypeId Normalizer::negate(TypeId there) void Normalizer::subtractPrimitive(NormalizedType& here, TypeId ty) { - const PrimitiveTypeVar* ptv = get(follow(ty)); + const PrimitiveType* ptv = get(follow(ty)); LUAU_ASSERT(ptv); switch (ptv->type) { - case PrimitiveTypeVar::NilType: - here.nils = singletonTypes->neverType; + case PrimitiveType::NilType: + here.nils = builtinTypes->neverType; break; - case PrimitiveTypeVar::Boolean: - here.booleans = singletonTypes->neverType; + case PrimitiveType::Boolean: + here.booleans = builtinTypes->neverType; break; - case PrimitiveTypeVar::Number: - here.numbers = singletonTypes->neverType; + case PrimitiveType::Number: + here.numbers = builtinTypes->neverType; break; - case PrimitiveTypeVar::String: + case PrimitiveType::String: here.strings.resetToNever(); break; - case PrimitiveTypeVar::Thread: - here.threads = singletonTypes->neverType; + case PrimitiveType::Thread: + here.threads = builtinTypes->neverType; break; - case PrimitiveTypeVar::Function: + case PrimitiveType::Function: here.functions.resetToNever(); break; } @@ -1249,7 +1579,7 @@ void Normalizer::subtractPrimitive(NormalizedType& here, TypeId ty) void Normalizer::subtractSingleton(NormalizedType& here, TypeId ty) { - const SingletonTypeVar* stv = get(ty); + const SingletonType* stv = get(ty); LUAU_ASSERT(stv); if (const StringSingleton* ss = get(stv)) @@ -1265,13 +1595,13 @@ void Normalizer::subtractSingleton(NormalizedType& here, TypeId ty) } else if (const BooleanSingleton* bs = get(stv)) { - if (get(here.booleans)) + if (get(here.booleans)) { // Nothing } - else if (get(here.booleans)) - here.booleans = bs->value ? singletonTypes->falseType : singletonTypes->trueType; - else if (auto hereSingleton = get(here.booleans)) + else if (get(here.booleans)) + here.booleans = bs->value ? builtinTypes->falseType : builtinTypes->trueType; + else if (auto hereSingleton = get(here.booleans)) { const BooleanSingleton* hereBooleanSingleton = get(hereSingleton); LUAU_ASSERT(hereBooleanSingleton); @@ -1280,7 +1610,7 @@ void Normalizer::subtractSingleton(NormalizedType& here, TypeId ty) // negated out. We therefore reduce to never when the values match, // rather than when they differ. if (bs->value == hereBooleanSingleton->value) - here.booleans = singletonTypes->neverType; + here.booleans = builtinTypes->neverType; } else LUAU_ASSERT(!"Unreachable"); @@ -1292,7 +1622,7 @@ void Normalizer::subtractSingleton(NormalizedType& here, TypeId ty) // ------- Normalizing intersections TypeId Normalizer::intersectionOfTops(TypeId here, TypeId there) { - if (get(here) || get(there)) + if (get(here) || get(there)) return here; else return there; @@ -1300,30 +1630,30 @@ TypeId Normalizer::intersectionOfTops(TypeId here, TypeId there) TypeId Normalizer::intersectionOfBools(TypeId here, TypeId there) { - if (get(here)) + if (get(here)) return here; - if (get(there)) + if (get(there)) return there; - if (const BooleanSingleton* hbool = get(get(here))) - if (const BooleanSingleton* tbool = get(get(there))) - return (hbool->value == tbool->value ? here : singletonTypes->neverType); + if (const BooleanSingleton* hbool = get(get(here))) + if (const BooleanSingleton* tbool = get(get(there))) + return (hbool->value == tbool->value ? here : builtinTypes->neverType); else return here; else return there; } -void Normalizer::intersectClasses(TypeIds& heres, const TypeIds& theres) +void Normalizer::DEPRECATED_intersectClasses(TypeIds& heres, const TypeIds& theres) { TypeIds tmp; for (auto it = heres.begin(); it != heres.end();) { - const ClassTypeVar* hctv = get(*it); + const ClassType* hctv = get(*it); LUAU_ASSERT(hctv); bool keep = false; for (TypeId there : theres) { - const ClassTypeVar* tctv = get(there); + const ClassType* tctv = get(there); LUAU_ASSERT(tctv); if (isSubclass(hctv, tctv)) { @@ -1345,14 +1675,14 @@ void Normalizer::intersectClasses(TypeIds& heres, const TypeIds& theres) heres.insert(tmp.begin(), tmp.end()); } -void Normalizer::intersectClassesWithClass(TypeIds& heres, TypeId there) +void Normalizer::DEPRECATED_intersectClassesWithClass(TypeIds& heres, TypeId there) { bool foundSuper = false; - const ClassTypeVar* tctv = get(there); + const ClassType* tctv = get(there); LUAU_ASSERT(tctv); for (auto it = heres.begin(); it != heres.end();) { - const ClassTypeVar* hctv = get(*it); + const ClassType* hctv = get(*it); LUAU_ASSERT(hctv); if (isSubclass(hctv, tctv)) it++; @@ -1371,6 +1701,157 @@ void Normalizer::intersectClassesWithClass(TypeIds& heres, TypeId there) } } +void Normalizer::intersectClasses(NormalizedClassType& heres, const NormalizedClassType& theres) +{ + if (theres.isNever()) + { + heres.resetToNever(); + return; + } + else if (isTop(builtinTypes, theres)) + { + return; + } + + // For intersections of two distinct class sets, we must normalize to a map + // where, for each entry, one of the following is true: + // - The class is the superclass of all other classes in the map + // - The class is a subclass of another class B in the map _and_ a subclass + // of one of B's negations. + // + // Once we have identified the common superclass, we proceed down the list + // of class types. For each class and negation pair in the incoming set, we + // check each entry in the current set. + // - If the incoming class is exactly identical to a class in the current + // set, we union the negations together and move on. + // - If the incoming class is a subclass of a class in the current set, we + // replace the current class with the incoming class. We keep negations + // that are a subclass of the incoming class, and discard ones that + // aren't. + // - If the incoming class is a superclass of a class in the current set, we + // take the negations that are a subclass of the current class and union + // them with the negations for the current class. + // - If the incoming class is unrelated to any class in the current set, we + // declare the result of the intersection operation to be never. + for (const TypeId thereTy : theres.ordering) + { + const TypeIds& thereNegations = theres.classes.at(thereTy); + + for (auto it = heres.ordering.begin(); it != heres.ordering.end();) + { + TypeId hereTy = *it; + TypeIds& hereNegations = heres.classes.at(hereTy); + + if (isSubclass(thereTy, hereTy)) + { + TypeIds negations = std::move(hereNegations); + + for (auto nIt = negations.begin(); nIt != negations.end();) + { + if (!isSubclass(*nIt, thereTy)) + { + nIt = negations.erase(nIt); + } + else + { + ++nIt; + } + } + + unionClasses(negations, thereNegations); + + it = heres.ordering.erase(it); + heres.classes.erase(hereTy); + heres.pushPair(thereTy, std::move(negations)); + break; + } + else if (isSubclass(hereTy, thereTy)) + { + TypeIds negations = thereNegations; + + for (auto nIt = negations.begin(); nIt != negations.end();) + { + if (!isSubclass(*nIt, hereTy)) + { + nIt = negations.erase(nIt); + } + else + { + ++nIt; + } + } + + unionClasses(hereNegations, negations); + break; + } + else if (hereTy == thereTy) + { + unionClasses(hereNegations, thereNegations); + break; + } + else + { + it = heres.ordering.erase(it); + heres.classes.erase(hereTy); + } + } + } +} + +void Normalizer::intersectClassesWithClass(NormalizedClassType& heres, TypeId there) +{ + for (auto it = heres.ordering.begin(); it != heres.ordering.end();) + { + TypeId hereTy = *it; + const TypeIds& hereNegations = heres.classes.at(hereTy); + + // If the incoming class _is_ the current class, we skip it. Maybe + // another entry will have a different story. We check for this first + // because isSubclass will be true if the types are equal, and entering + // either of those branches below will trigger wrong behaviors. + if (hereTy == there) + { + ++it; + } + // If the incoming class is a subclass of this type, we replace the + // current class with the incoming class. We preserve negations that are + // a subclass of the incoming class, and discard ones that aren't. + else if (isSubclass(there, hereTy)) + { + TypeIds negations = std::move(hereNegations); + + for (auto nIt = negations.begin(); nIt != negations.end();) + { + if (!isSubclass(*nIt, there)) + { + nIt = negations.erase(nIt); + } + else + { + ++nIt; + } + } + + it = heres.ordering.erase(it); + heres.classes.erase(hereTy); + heres.pushPair(there, std::move(negations)); + } + // If the incoming class is a superclass of the current class, we don't + // insert it into the map. + else if (isSubclass(hereTy, there)) + { + return; + } + // If the incoming class is completely unrelated to the current class, + // we drop the current class from the map. + else + { + it = heres.ordering.erase(it); + heres.classes.erase(hereTy); + } + } +} + void Normalizer::intersectStrings(NormalizedStringType& here, const NormalizedStringType& there) { if (there.isString()) @@ -1419,7 +1900,7 @@ std::optional Normalizer::intersectionOfTypePacks(TypePackId here, T bool& thereSubHere) { if (ith != end(here)) { - TypeId tty = singletonTypes->nilType; + TypeId tty = builtinTypes->nilType; if (std::optional ttail = itt.tail()) { if (const VariadicTypePack* tvtp = get(*ttail)) @@ -1518,22 +1999,22 @@ std::optional Normalizer::intersectionOfTables(TypeId here, TypeId there TypeId htable = here; TypeId hmtable = nullptr; - if (const MetatableTypeVar* hmtv = get(here)) + if (const MetatableType* hmtv = get(here)) { htable = hmtv->table; hmtable = hmtv->metatable; } TypeId ttable = there; TypeId tmtable = nullptr; - if (const MetatableTypeVar* tmtv = get(there)) + if (const MetatableType* tmtv = get(there)) { ttable = tmtv->table; tmtable = tmtv->metatable; } - const TableTypeVar* httv = get(htable); + const TableType* httv = get(htable); LUAU_ASSERT(httv); - const TableTypeVar* tttv = get(ttable); + const TableType* tttv = get(ttable); LUAU_ASSERT(tttv); if (httv->state == TableState::Free || tttv->state == TableState::Free) @@ -1546,7 +2027,7 @@ std::optional Normalizer::intersectionOfTables(TypeId here, TypeId there state = tttv->state; TypeLevel level = max(httv->level, tttv->level); - TableTypeVar result{state, level}; + TableType result{state, level}; bool hereSubThere = true; bool thereSubHere = true; @@ -1616,7 +2097,7 @@ std::optional Normalizer::intersectionOfTables(TypeId here, TypeId there else if (table == ttable && *mtable == tmtable) return there; else - return arena->addType(MetatableTypeVar{table, *mtable}); + return arena->addType(MetatableType{table, *mtable}); } else return std::nullopt; @@ -1626,14 +2107,14 @@ std::optional Normalizer::intersectionOfTables(TypeId here, TypeId there if (table == htable) return here; else - return arena->addType(MetatableTypeVar{table, hmtable}); + return arena->addType(MetatableType{table, hmtable}); } else if (tmtable) { if (table == ttable) return there; else - return arena->addType(MetatableTypeVar{table, tmtable}); + return arena->addType(MetatableType{table, tmtable}); } else return table; @@ -1662,9 +2143,9 @@ void Normalizer::intersectTables(TypeIds& heres, const TypeIds& theres) std::optional Normalizer::intersectionOfFunctions(TypeId here, TypeId there) { - const FunctionTypeVar* hftv = get(here); + const FunctionType* hftv = get(here); LUAU_ASSERT(hftv); - const FunctionTypeVar* tftv = get(there); + const FunctionType* tftv = get(there); LUAU_ASSERT(tftv); if (hftv->generics != tftv->generics) @@ -1699,7 +2180,7 @@ std::optional Normalizer::intersectionOfFunctions(TypeId here, TypeId th if (argTypes == tftv->argTypes && retTypes == tftv->retTypes) return there; - FunctionTypeVar result{argTypes, retTypes}; + FunctionType result{argTypes, retTypes}; result.generics = hftv->generics; result.genericPacks = hftv->genericPacks; return arena->addType(std::move(result)); @@ -1796,10 +2277,10 @@ std::optional Normalizer::unionSaturatedFunctions(TypeId here, TypeId th // Proc. Principles and practice of declarative programming 2005, pp 198–208 // https://doi.org/10.1145/1069774.1069793 - const FunctionTypeVar* hftv = get(here); + const FunctionType* hftv = get(here); if (!hftv) return std::nullopt; - const FunctionTypeVar* tftv = get(there); + const FunctionType* tftv = get(there); if (!tftv) return std::nullopt; @@ -1815,7 +2296,7 @@ std::optional Normalizer::unionSaturatedFunctions(TypeId here, TypeId th if (!retTypes) return std::nullopt; - FunctionTypeVar result{*argTypes, *retTypes}; + FunctionType result{*argTypes, *retTypes}; result.generics = hftv->generics; result.genericPacks = hftv->genericPacks; return arena->addType(std::move(result)); @@ -1831,7 +2312,7 @@ void Normalizer::intersectFunctionsWithFunction(NormalizedFunctionType& heres, T for (auto it = heres.parts->begin(); it != heres.parts->end();) { TypeId here = *it; - if (get(here)) + if (get(here)) it++; else if (std::optional tmp = intersectionOfFunctions(here, there)) { @@ -1887,24 +2368,33 @@ bool Normalizer::intersectTyvarsWithTy(NormalizedTyvars& here, TypeId there) // See above for an explaination of `ignoreSmallerTyvars`. bool Normalizer::intersectNormals(NormalizedType& here, const NormalizedType& there, int ignoreSmallerTyvars) { - if (!get(there.tops)) + if (!get(there.tops)) { here.tops = intersectionOfTops(here.tops, there.tops); return true; } - else if (!get(here.tops)) + else if (!get(here.tops)) { clearNormal(here); return unionNormals(here, there, ignoreSmallerTyvars); } here.booleans = intersectionOfBools(here.booleans, there.booleans); - intersectClasses(here.classes, there.classes); - here.errors = (get(there.errors) ? there.errors : here.errors); - here.nils = (get(there.nils) ? there.nils : here.nils); - here.numbers = (get(there.numbers) ? there.numbers : here.numbers); + + if (FFlag::LuauNegatedClassTypes) + { + intersectClasses(here.classes, there.classes); + } + else + { + DEPRECATED_intersectClasses(here.DEPRECATED_classes, there.DEPRECATED_classes); + } + + here.errors = (get(there.errors) ? there.errors : here.errors); + here.nils = (get(there.nils) ? there.nils : here.nils); + here.numbers = (get(there.numbers) ? there.numbers : here.numbers); intersectStrings(here.strings, there.strings); - here.threads = (get(there.threads) ? there.threads : here.threads); + here.threads = (get(there.threads) ? there.threads : here.threads); intersectFunctions(here.functions, there.functions); intersectTables(here.tables, there.tables); @@ -1913,7 +2403,7 @@ bool Normalizer::intersectNormals(NormalizedType& here, const NormalizedType& th int index = tyvarIndex(tyvar); if (ignoreSmallerTyvars < index) { - auto [found, fresh] = here.tyvars.emplace(tyvar, std::make_unique(NormalizedType{singletonTypes})); + auto [found, fresh] = here.tyvars.emplace(tyvar, std::make_unique(NormalizedType{builtinTypes})); if (fresh) { if (!unionNormals(*found->second, here, index)) @@ -1953,70 +2443,80 @@ bool Normalizer::intersectNormalWithTy(NormalizedType& here, TypeId there) return false; there = follow(there); - if (get(there) || get(there)) + if (get(there) || get(there)) { here.tops = intersectionOfTops(here.tops, there); return true; } - else if (!get(here.tops)) + else if (!get(here.tops)) { clearNormal(here); return unionNormalWithTy(here, there); } - else if (const UnionTypeVar* utv = get(there)) + else if (const UnionType* utv = get(there)) { - NormalizedType norm{singletonTypes}; - for (UnionTypeVarIterator it = begin(utv); it != end(utv); ++it) + NormalizedType norm{builtinTypes}; + for (UnionTypeIterator it = begin(utv); it != end(utv); ++it) if (!unionNormalWithTy(norm, *it)) return false; return intersectNormals(here, norm); } - else if (const IntersectionTypeVar* itv = get(there)) + else if (const IntersectionType* itv = get(there)) { - for (IntersectionTypeVarIterator it = begin(itv); it != end(itv); ++it) + for (IntersectionTypeIterator it = begin(itv); it != end(itv); ++it) if (!intersectNormalWithTy(here, *it)) return false; return true; } - else if (get(there) || get(there)) + else if (get(there) || get(there)) { - NormalizedType thereNorm{singletonTypes}; - NormalizedType topNorm{singletonTypes}; - topNorm.tops = singletonTypes->unknownType; + NormalizedType thereNorm{builtinTypes}; + NormalizedType topNorm{builtinTypes}; + topNorm.tops = builtinTypes->unknownType; thereNorm.tyvars.insert_or_assign(there, std::make_unique(std::move(topNorm))); return intersectNormals(here, thereNorm); } NormalizedTyvars tyvars = std::move(here.tyvars); - if (const FunctionTypeVar* utv = get(there)) + if (const FunctionType* utv = get(there)) { NormalizedFunctionType functions = std::move(here.functions); clearNormal(here); intersectFunctionsWithFunction(functions, there); here.functions = std::move(functions); } - else if (get(there) || get(there)) + else if (get(there) || get(there)) { TypeIds tables = std::move(here.tables); clearNormal(here); intersectTablesWithTable(tables, there); here.tables = std::move(tables); } - else if (get(there)) + else if (get(there)) { - TypeIds classes = std::move(here.classes); - clearNormal(here); - intersectClassesWithClass(classes, there); - here.classes = std::move(classes); + if (FFlag::LuauNegatedClassTypes) + { + NormalizedClassType nct = std::move(here.classes); + clearNormal(here); + intersectClassesWithClass(nct, there); + here.classes = std::move(nct); + } + else + { + TypeIds classes = std::move(here.DEPRECATED_classes); + clearNormal(here); + DEPRECATED_intersectClassesWithClass(classes, there); + here.DEPRECATED_classes = std::move(classes); + } } - else if (get(there)) + else if (get(there)) { TypeId errors = here.errors; clearNormal(here); here.errors = errors; } - else if (const PrimitiveTypeVar* ptv = get(there)) + else if (const PrimitiveType* ptv = get(there)) { TypeId booleans = here.booleans; TypeId nils = here.nils; @@ -2027,17 +2527,17 @@ bool Normalizer::intersectNormalWithTy(NormalizedType& here, TypeId there) clearNormal(here); - if (ptv->type == PrimitiveTypeVar::Boolean) + if (ptv->type == PrimitiveType::Boolean) here.booleans = booleans; - else if (ptv->type == PrimitiveTypeVar::NilType) + else if (ptv->type == PrimitiveType::NilType) here.nils = nils; - else if (ptv->type == PrimitiveTypeVar::Number) + else if (ptv->type == PrimitiveType::Number) here.numbers = numbers; - else if (ptv->type == PrimitiveTypeVar::String) + else if (ptv->type == PrimitiveType::String) here.strings = std::move(strings); - else if (ptv->type == PrimitiveTypeVar::Thread) + else if (ptv->type == PrimitiveType::Thread) here.threads = threads; - else if (ptv->type == PrimitiveTypeVar::Function) + else if (ptv->type == PrimitiveType::Function) { LUAU_ASSERT(FFlag::LuauNegatedFunctionTypes); here.functions = std::move(functions); @@ -2045,7 +2545,7 @@ bool Normalizer::intersectNormalWithTy(NormalizedType& here, TypeId there) else LUAU_ASSERT(!"Unreachable"); } - else if (const SingletonTypeVar* stv = get(there)) + else if (const SingletonType* stv = get(there)) { TypeId booleans = here.booleans; NormalizedStringType strings = std::move(here.strings); @@ -2062,14 +2562,22 @@ bool Normalizer::intersectNormalWithTy(NormalizedType& here, TypeId there) else LUAU_ASSERT(!"Unreachable"); } - else if (const NegationTypeVar* ntv = get(there)) + else if (const NegationType* ntv = get(there)) { TypeId t = follow(ntv->ty); - if (const PrimitiveTypeVar* ptv = get(t)) + if (const PrimitiveType* ptv = get(t)) subtractPrimitive(here, ntv->ty); - else if (const SingletonTypeVar* stv = get(t)) + else if (const SingletonType* stv = get(t)) subtractSingleton(here, follow(ntv->ty)); - else if (const UnionTypeVar* itv = get(t)) + else if (get(t) && FFlag::LuauNegatedClassTypes) + { + const NormalizedType* normal = normalize(t); + std::optional negated = negateNormal(*normal); + if (!negated) + return false; + intersectNormals(here, *negated); + } + else if (const UnionType* itv = get(t)) { for (TypeId part : itv->options) { @@ -2087,6 +2595,10 @@ bool Normalizer::intersectNormalWithTy(NormalizedType& here, TypeId there) LUAU_ASSERT(!"Unimplemented"); } } + else if (get(there) && FFlag::LuauNegatedClassTypes) + { + here.classes.resetToNever(); + } else LUAU_ASSERT(!"Unreachable"); @@ -2101,18 +2613,67 @@ bool Normalizer::intersectNormalWithTy(NormalizedType& here, TypeId there) TypeId Normalizer::typeFromNormal(const NormalizedType& norm) { assertInvariant(norm); - if (!get(norm.tops)) + if (!get(norm.tops)) return norm.tops; std::vector result; - if (!get(norm.booleans)) + if (!get(norm.booleans)) result.push_back(norm.booleans); - result.insert(result.end(), norm.classes.begin(), norm.classes.end()); - if (!get(norm.errors)) + + if (FFlag::LuauNegatedClassTypes) + { + if (isTop(builtinTypes, norm.classes)) + { + result.push_back(builtinTypes->classType); + } + else if (!norm.classes.isNever()) + { + std::vector parts; + parts.reserve(norm.classes.classes.size()); + + for (const TypeId normTy : norm.classes.ordering) + { + const TypeIds& normNegations = norm.classes.classes.at(normTy); + + if (normNegations.empty()) + { + parts.push_back(normTy); + } + else + { + std::vector intersection; + intersection.reserve(normNegations.size() + 1); + + intersection.push_back(normTy); + for (TypeId negation : normNegations) + { + intersection.push_back(arena->addType(NegationType{negation})); + } + + parts.push_back(arena->addType(IntersectionType{std::move(intersection)})); + } + } + + if (parts.size() == 1) + { + result.push_back(parts.at(0)); + } + else if (parts.size() > 1) + { + result.push_back(arena->addType(UnionType{std::move(parts)})); + } + } + } + else + { + result.insert(result.end(), norm.DEPRECATED_classes.begin(), norm.DEPRECATED_classes.end()); + } + + if (!get(norm.errors)) result.push_back(norm.errors); if (FFlag::LuauNegatedFunctionTypes && norm.functions.isTop) - result.push_back(singletonTypes->functionType); + result.push_back(builtinTypes->functionType); else if (!norm.functions.isNever()) { if (norm.functions.parts->size() == 1) @@ -2121,15 +2682,15 @@ TypeId Normalizer::typeFromNormal(const NormalizedType& norm) { std::vector parts; parts.insert(parts.end(), norm.functions.parts->begin(), norm.functions.parts->end()); - result.push_back(arena->addType(IntersectionTypeVar{std::move(parts)})); + result.push_back(arena->addType(IntersectionType{std::move(parts)})); } } - if (!get(norm.nils)) + if (!get(norm.nils)) result.push_back(norm.nils); - if (!get(norm.numbers)) + if (!get(norm.numbers)) result.push_back(norm.numbers); if (norm.strings.isString()) - result.push_back(singletonTypes->stringType); + result.push_back(builtinTypes->stringType); else if (norm.strings.isUnion()) { for (auto& [_, ty] : norm.strings.singletons) @@ -2138,40 +2699,40 @@ TypeId Normalizer::typeFromNormal(const NormalizedType& norm) else if (norm.strings.isIntersection()) { std::vector parts; - parts.push_back(singletonTypes->stringType); + parts.push_back(builtinTypes->stringType); for (const auto& [name, ty] : norm.strings.singletons) - parts.push_back(arena->addType(NegationTypeVar{ty})); + parts.push_back(arena->addType(NegationType{ty})); - result.push_back(arena->addType(IntersectionTypeVar{std::move(parts)})); + result.push_back(arena->addType(IntersectionType{std::move(parts)})); } - if (!get(norm.threads)) - result.push_back(singletonTypes->threadType); + if (!get(norm.threads)) + result.push_back(builtinTypes->threadType); result.insert(result.end(), norm.tables.begin(), norm.tables.end()); for (auto& [tyvar, intersect] : norm.tyvars) { - if (get(intersect->tops)) + if (get(intersect->tops)) { TypeId ty = typeFromNormal(*intersect); - result.push_back(arena->addType(IntersectionTypeVar{{tyvar, ty}})); + result.push_back(arena->addType(IntersectionType{{tyvar, ty}})); } else result.push_back(tyvar); } if (result.size() == 0) - return singletonTypes->neverType; + return builtinTypes->neverType; else if (result.size() == 1) return result[0]; else - return arena->addType(UnionTypeVar{std::move(result)}); + return arena->addType(UnionType{std::move(result)}); } -bool isSubtype(TypeId subTy, TypeId superTy, NotNull scope, NotNull singletonTypes, InternalErrorReporter& ice) +bool isSubtype(TypeId subTy, TypeId superTy, NotNull scope, NotNull builtinTypes, InternalErrorReporter& ice) { UnifierSharedState sharedState{&ice}; TypeArena arena; - Normalizer normalizer{&arena, singletonTypes, NotNull{&sharedState}}; + Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}}; Unifier u{NotNull{&normalizer}, Mode::Strict, scope, Location{}, Covariant}; u.tryUnify(subTy, superTy); @@ -2179,11 +2740,11 @@ bool isSubtype(TypeId subTy, TypeId superTy, NotNull scope, NotNull scope, NotNull singletonTypes, InternalErrorReporter& ice) +bool isSubtype(TypePackId subPack, TypePackId superPack, NotNull scope, NotNull builtinTypes, InternalErrorReporter& ice) { UnifierSharedState sharedState{&ice}; TypeArena arena; - Normalizer normalizer{&arena, singletonTypes, NotNull{&sharedState}}; + Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}}; Unifier u{NotNull{&normalizer}, Mode::Strict, scope, Location{}, Covariant}; u.tryUnify(subPack, superPack); diff --git a/Analysis/src/Quantify.cpp b/Analysis/src/Quantify.cpp index e9de094b..22c5875b 100644 --- a/Analysis/src/Quantify.cpp +++ b/Analysis/src/Quantify.cpp @@ -5,8 +5,8 @@ #include "Luau/Scope.h" #include "Luau/Substitution.h" #include "Luau/TxnLog.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" LUAU_FASTFLAG(DebugLuauSharedSelf) LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); @@ -15,7 +15,7 @@ LUAU_FASTFLAG(LuauClassTypeVarsInSubstitution) namespace Luau { -struct Quantifier final : TypeVarOnceVisitor +struct Quantifier final : TypeOnceVisitor { TypeLevel level; std::vector generics; @@ -43,24 +43,24 @@ struct Quantifier final : TypeVarOnceVisitor return false; } - bool visit(TypeId ty, const FreeTypeVar& ftv) override + bool visit(TypeId ty, const FreeType& ftv) override { seenMutableType = true; if (!level.subsumes(ftv.level)) return false; - *asMutable(ty) = GenericTypeVar{level}; + *asMutable(ty) = GenericType{level}; generics.push_back(ty); return false; } - bool visit(TypeId ty, const TableTypeVar&) override + bool visit(TypeId ty, const TableType&) override { - LUAU_ASSERT(getMutable(ty)); - TableTypeVar& ttv = *getMutable(ty); + LUAU_ASSERT(getMutable(ty)); + TableType& ttv = *getMutable(ty); if (ttv.state == TableState::Generic) seenGenericType = true; @@ -117,7 +117,7 @@ void quantify(TypeId ty, TypeLevel level) for (const auto& [_, prop] : ttv->props) { - auto ftv = getMutable(follow(prop.type)); + auto ftv = getMutable(follow(prop.type)); if (!ftv || !ftv->hasSelf) continue; @@ -128,7 +128,7 @@ void quantify(TypeId ty, TypeLevel level) } } } - else if (auto ftv = getMutable(ty)) + else if (auto ftv = getMutable(ty)) { Quantifier q{level}; q.traverse(ty); @@ -145,7 +145,7 @@ void quantify(TypeId ty, TypeLevel level) Quantifier q{level}; q.traverse(ty); - FunctionTypeVar* ftv = getMutable(ty); + FunctionType* ftv = getMutable(ty); LUAU_ASSERT(ftv); ftv->generics.insert(ftv->generics.end(), q.generics.begin(), q.generics.end()); ftv->genericPacks.insert(ftv->genericPacks.end(), q.genericPacks.begin(), q.genericPacks.end()); @@ -168,11 +168,11 @@ struct PureQuantifier : Substitution { LUAU_ASSERT(ty == follow(ty)); - if (auto ftv = get(ty)) + if (auto ftv = get(ty)) { return subsumes(scope, ftv->scope); } - else if (auto ttv = get(ty)) + else if (auto ttv = get(ty)) { return ttv->state == TableState::Free && subsumes(scope, ttv->scope); } @@ -192,16 +192,16 @@ struct PureQuantifier : Substitution TypeId clean(TypeId ty) override { - if (auto ftv = get(ty)) + if (auto ftv = get(ty)) { - TypeId result = arena->addType(GenericTypeVar{scope}); + TypeId result = arena->addType(GenericType{scope}); insertedGenerics.push_back(result); return result; } - else if (auto ttv = get(ty)) + else if (auto ttv = get(ty)) { - TypeId result = arena->addType(TableTypeVar{}); - TableTypeVar* resultTable = getMutable(result); + TypeId result = arena->addType(TableType{}); + TableType* resultTable = getMutable(result); LUAU_ASSERT(resultTable); *resultTable = *ttv; @@ -229,7 +229,7 @@ struct PureQuantifier : Substitution bool ignoreChildren(TypeId ty) override { - if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) + if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) return true; return ty->persistent; @@ -246,7 +246,7 @@ TypeId quantify(TypeArena* arena, TypeId ty, Scope* scope) std::optional result = quantifier.substitute(ty); LUAU_ASSERT(result); - FunctionTypeVar* ftv = getMutable(*result); + FunctionType* ftv = getMutable(*result); LUAU_ASSERT(ftv); ftv->scope = scope; ftv->generics.insert(ftv->generics.end(), quantifier.insertedGenerics.begin(), quantifier.insertedGenerics.end()); diff --git a/Analysis/src/Substitution.cpp b/Analysis/src/Substitution.cpp index 20ed34f6..2469152e 100644 --- a/Analysis/src/Substitution.cpp +++ b/Analysis/src/Substitution.cpp @@ -28,7 +28,7 @@ void Tarjan::visitChildren(TypeId ty, int index) if (auto pty = log->pending(ty)) ty = &pty->pending; - if (const FunctionTypeVar* ftv = get(ty)) + if (const FunctionType* ftv = get(ty)) { if (FFlag::LuauSubstitutionFixMissingFields) { @@ -41,7 +41,7 @@ void Tarjan::visitChildren(TypeId ty, int index) visitChild(ftv->argTypes); visitChild(ftv->retTypes); } - else if (const TableTypeVar* ttv = get(ty)) + else if (const TableType* ttv = get(ty)) { LUAU_ASSERT(!ttv->boundTo); for (const auto& [name, prop] : ttv->props) @@ -58,22 +58,22 @@ void Tarjan::visitChildren(TypeId ty, int index) for (TypePackId itp : ttv->instantiatedTypePackParams) visitChild(itp); } - else if (const MetatableTypeVar* mtv = get(ty)) + else if (const MetatableType* mtv = get(ty)) { visitChild(mtv->table); visitChild(mtv->metatable); } - else if (const UnionTypeVar* utv = get(ty)) + else if (const UnionType* utv = get(ty)) { for (TypeId opt : utv->options) visitChild(opt); } - else if (const IntersectionTypeVar* itv = get(ty)) + else if (const IntersectionType* itv = get(ty)) { for (TypeId part : itv->parts) visitChild(part); } - else if (const PendingExpansionTypeVar* petv = get(ty)) + else if (const PendingExpansionType* petv = get(ty)) { for (TypeId a : petv->typeArguments) visitChild(a); @@ -81,7 +81,7 @@ void Tarjan::visitChildren(TypeId ty, int index) for (TypePackId a : petv->packArguments) visitChild(a); } - else if (const ClassTypeVar* ctv = get(ty); FFlag::LuauClassTypeVarsInSubstitution && ctv) + else if (const ClassType* ctv = get(ty); FFlag::LuauClassTypeVarsInSubstitution && ctv) { for (auto [name, prop] : ctv->props) visitChild(prop.type); @@ -92,7 +92,7 @@ void Tarjan::visitChildren(TypeId ty, int index) if (ctv->metatable) visitChild(*ctv->metatable); } - else if (const NegationTypeVar* ntv = get(ty)) + else if (const NegationType* ntv = get(ty)) { visitChild(ntv->ty); } @@ -559,7 +559,7 @@ void Substitution::replaceChildren(TypeId ty) if (ty->owningArena != arena) return; - if (FunctionTypeVar* ftv = getMutable(ty)) + if (FunctionType* ftv = getMutable(ty)) { if (FFlag::LuauSubstitutionFixMissingFields) { @@ -572,7 +572,7 @@ void Substitution::replaceChildren(TypeId ty) ftv->argTypes = replace(ftv->argTypes); ftv->retTypes = replace(ftv->retTypes); } - else if (TableTypeVar* ttv = getMutable(ty)) + else if (TableType* ttv = getMutable(ty)) { LUAU_ASSERT(!ttv->boundTo); for (auto& [name, prop] : ttv->props) @@ -589,22 +589,22 @@ void Substitution::replaceChildren(TypeId ty) for (TypePackId& itp : ttv->instantiatedTypePackParams) itp = replace(itp); } - else if (MetatableTypeVar* mtv = getMutable(ty)) + else if (MetatableType* mtv = getMutable(ty)) { mtv->table = replace(mtv->table); mtv->metatable = replace(mtv->metatable); } - else if (UnionTypeVar* utv = getMutable(ty)) + else if (UnionType* utv = getMutable(ty)) { for (TypeId& opt : utv->options) opt = replace(opt); } - else if (IntersectionTypeVar* itv = getMutable(ty)) + else if (IntersectionType* itv = getMutable(ty)) { for (TypeId& part : itv->parts) part = replace(part); } - else if (PendingExpansionTypeVar* petv = getMutable(ty)) + else if (PendingExpansionType* petv = getMutable(ty)) { for (TypeId& a : petv->typeArguments) a = replace(a); @@ -612,7 +612,7 @@ void Substitution::replaceChildren(TypeId ty) for (TypePackId& a : petv->packArguments) a = replace(a); } - else if (ClassTypeVar* ctv = getMutable(ty); FFlag::LuauClassTypeVarsInSubstitution && ctv) + else if (ClassType* ctv = getMutable(ty); FFlag::LuauClassTypeVarsInSubstitution && ctv) { for (auto& [name, prop] : ctv->props) prop.type = replace(prop.type); @@ -623,7 +623,7 @@ void Substitution::replaceChildren(TypeId ty) if (ctv->metatable) ctv->metatable = replace(*ctv->metatable); } - else if (NegationTypeVar* ntv = getMutable(ty)) + else if (NegationType* ntv = getMutable(ty)) { ntv->ty = replace(ntv->ty); } diff --git a/Analysis/src/ToDot.cpp b/Analysis/src/ToDot.cpp index 68fa5393..117d39d2 100644 --- a/Analysis/src/ToDot.cpp +++ b/Analysis/src/ToDot.cpp @@ -3,7 +3,7 @@ #include "Luau/ToString.h" #include "Luau/TypePack.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/StringUtils.h" #include @@ -49,10 +49,10 @@ struct StateDot bool StateDot::canDuplicatePrimitive(TypeId ty) { - if (get(ty)) + if (get(ty)) return false; - return get(ty) || get(ty); + return get(ty) || get(ty); } void StateDot::visitChild(TypeId ty, int parentIndex, const char* linkName) @@ -72,9 +72,9 @@ void StateDot::visitChild(TypeId ty, int parentIndex, const char* linkName) if (opts.duplicatePrimitives && canDuplicatePrimitive(ty)) { - if (get(ty)) + if (get(ty)) formatAppend(result, "n%d [label=\"%s\"];\n", index, toString(ty).c_str()); - else if (get(ty)) + else if (get(ty)) formatAppend(result, "n%d [label=\"any\"];\n", index); } else @@ -139,31 +139,31 @@ void StateDot::visitChildren(TypeId ty, int index) startNode(index); startNodeLabel(); - if (const BoundTypeVar* btv = get(ty)) + if (const BoundType* btv = get(ty)) { - formatAppend(result, "BoundTypeVar %d", index); + formatAppend(result, "BoundType %d", index); finishNodeLabel(ty); finishNode(); visitChild(btv->boundTo, index); } - else if (const FunctionTypeVar* ftv = get(ty)) + else if (const FunctionType* ftv = get(ty)) { - formatAppend(result, "FunctionTypeVar %d", index); + formatAppend(result, "FunctionType %d", index); finishNodeLabel(ty); finishNode(); visitChild(ftv->argTypes, index, "arg"); visitChild(ftv->retTypes, index, "ret"); } - else if (const TableTypeVar* ttv = get(ty)) + else if (const TableType* ttv = get(ty)) { if (ttv->name) - formatAppend(result, "TableTypeVar %s", ttv->name->c_str()); + formatAppend(result, "TableType %s", ttv->name->c_str()); else if (ttv->syntheticName) - formatAppend(result, "TableTypeVar %s", ttv->syntheticName->c_str()); + formatAppend(result, "TableType %s", ttv->syntheticName->c_str()); else - formatAppend(result, "TableTypeVar %d", index); + formatAppend(result, "TableType %d", index); finishNodeLabel(ty); finishNode(); @@ -183,69 +183,69 @@ void StateDot::visitChildren(TypeId ty, int index) for (TypePackId itp : ttv->instantiatedTypePackParams) visitChild(itp, index, "typePackParam"); } - else if (const MetatableTypeVar* mtv = get(ty)) + else if (const MetatableType* mtv = get(ty)) { - formatAppend(result, "MetatableTypeVar %d", index); + formatAppend(result, "MetatableType %d", index); finishNodeLabel(ty); finishNode(); visitChild(mtv->table, index, "table"); visitChild(mtv->metatable, index, "metatable"); } - else if (const UnionTypeVar* utv = get(ty)) + else if (const UnionType* utv = get(ty)) { - formatAppend(result, "UnionTypeVar %d", index); + formatAppend(result, "UnionType %d", index); finishNodeLabel(ty); finishNode(); for (TypeId opt : utv->options) visitChild(opt, index); } - else if (const IntersectionTypeVar* itv = get(ty)) + else if (const IntersectionType* itv = get(ty)) { - formatAppend(result, "IntersectionTypeVar %d", index); + formatAppend(result, "IntersectionType %d", index); finishNodeLabel(ty); finishNode(); for (TypeId part : itv->parts) visitChild(part, index); } - else if (const GenericTypeVar* gtv = get(ty)) + else if (const GenericType* gtv = get(ty)) { if (gtv->explicitName) - formatAppend(result, "GenericTypeVar %s", gtv->name.c_str()); + formatAppend(result, "GenericType %s", gtv->name.c_str()); else - formatAppend(result, "GenericTypeVar %d", index); + formatAppend(result, "GenericType %d", index); finishNodeLabel(ty); finishNode(); } - else if (const FreeTypeVar* ftv = get(ty)) + else if (const FreeType* ftv = get(ty)) { - formatAppend(result, "FreeTypeVar %d", index); + formatAppend(result, "FreeType %d", index); finishNodeLabel(ty); finishNode(); } - else if (get(ty)) + else if (get(ty)) { - formatAppend(result, "AnyTypeVar %d", index); + formatAppend(result, "AnyType %d", index); finishNodeLabel(ty); finishNode(); } - else if (get(ty)) + else if (get(ty)) { - formatAppend(result, "PrimitiveTypeVar %s", toString(ty).c_str()); + formatAppend(result, "PrimitiveType %s", toString(ty).c_str()); finishNodeLabel(ty); finishNode(); } - else if (get(ty)) + else if (get(ty)) { - formatAppend(result, "ErrorTypeVar %d", index); + formatAppend(result, "ErrorType %d", index); finishNodeLabel(ty); finishNode(); } - else if (const ClassTypeVar* ctv = get(ty)) + else if (const ClassType* ctv = get(ty)) { - formatAppend(result, "ClassTypeVar %s", ctv->name.c_str()); + formatAppend(result, "ClassType %s", ctv->name.c_str()); finishNodeLabel(ty); finishNode(); @@ -258,7 +258,7 @@ void StateDot::visitChildren(TypeId ty, int index) if (ctv->metatable) visitChild(*ctv->metatable, index, "[metatable]"); } - else if (const SingletonTypeVar* stv = get(ty)) + else if (const SingletonType* stv = get(ty)) { std::string res; @@ -276,7 +276,7 @@ void StateDot::visitChildren(TypeId ty, int index) else LUAU_ASSERT(!"unknown singleton type"); - formatAppend(result, "SingletonTypeVar %s", res.c_str()); + formatAppend(result, "SingletonType %s", res.c_str()); finishNodeLabel(ty); finishNode(); } diff --git a/Analysis/src/ToString.cpp b/Analysis/src/ToString.cpp index ed7c682d..e8008508 100644 --- a/Analysis/src/ToString.cpp +++ b/Analysis/src/ToString.cpp @@ -4,10 +4,11 @@ #include "Luau/Constraint.h" #include "Luau/Location.h" #include "Luau/Scope.h" +#include "Luau/TxnLog.h" #include "Luau/TypeInfer.h" #include "Luau/TypePack.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" #include #include @@ -17,6 +18,7 @@ LUAU_FASTFLAG(LuauUnknownAndNeverType) LUAU_FASTFLAGVARIABLE(LuauLineBreaksDetermineIndents, false) LUAU_FASTFLAGVARIABLE(LuauFunctionReturnStringificationFixup, false) LUAU_FASTFLAGVARIABLE(LuauUnseeArrayTtv, false) +LUAU_FASTFLAGVARIABLE(LuauSerializeNilUnionAsNil, false) /* * Prefix generic typenames with gen- @@ -31,7 +33,7 @@ namespace Luau namespace { -struct FindCyclicTypes final : TypeVarVisitor +struct FindCyclicTypes final : TypeVisitor { FindCyclicTypes() = default; FindCyclicTypes(const FindCyclicTypes&) = delete; @@ -63,7 +65,7 @@ struct FindCyclicTypes final : TypeVarVisitor return visitedPacks.insert(tp).second; } - bool visit(TypeId ty, const TableTypeVar& ttv) override + bool visit(TypeId ty, const TableType& ttv) override { if (!visited.insert(ty).second) return false; @@ -82,7 +84,7 @@ struct FindCyclicTypes final : TypeVarVisitor return true; } - bool visit(TypeId ty, const ClassTypeVar&) override + bool visit(TypeId ty, const ClassType&) override { return false; } @@ -136,7 +138,7 @@ struct StringifierState , result(result) , exhaustive(opts.exhaustive) { - for (const auto& [_, v] : opts.nameMap.typeVars) + for (const auto& [_, v] : opts.nameMap.types) usedNames.insert(v); for (const auto& [_, v] : opts.nameMap.typePacks) usedNames.insert(v); @@ -162,8 +164,8 @@ struct StringifierState std::string getName(TypeId ty) { - const size_t s = opts.nameMap.typeVars.size(); - std::string& n = opts.nameMap.typeVars[ty]; + const size_t s = opts.nameMap.types.size(); + std::string& n = opts.nameMap.types[ty]; if (!n.empty()) return n; @@ -291,11 +293,11 @@ private: } }; -struct TypeVarStringifier +struct TypeStringifier { StringifierState& state; - explicit TypeVarStringifier(StringifierState& state) + explicit TypeStringifier(StringifierState& state) : state(state) { } @@ -392,17 +394,17 @@ struct TypeVarStringifier } } - void operator()(TypeId, const BoundTypeVar& btv) + void operator()(TypeId, const BoundType& btv) { stringify(btv.boundTo); } - void operator()(TypeId ty, const GenericTypeVar& gtv) + void operator()(TypeId ty, const GenericType& gtv) { if (gtv.explicitName) { state.usedNames.insert(gtv.name); - state.opts.nameMap.typeVars[ty] = gtv.name; + state.opts.nameMap.types[ty] = gtv.name; state.emit(gtv.name); } else @@ -418,40 +420,40 @@ struct TypeVarStringifier } } - void operator()(TypeId, const BlockedTypeVar& btv) + void operator()(TypeId, const BlockedType& btv) { state.emit("*blocked-"); state.emit(btv.index); state.emit("*"); } - void operator()(TypeId ty, const PendingExpansionTypeVar& petv) + void operator()(TypeId ty, const PendingExpansionType& petv) { state.emit("*pending-expansion-"); state.emit(petv.index); state.emit("*"); } - void operator()(TypeId, const PrimitiveTypeVar& ptv) + void operator()(TypeId, const PrimitiveType& ptv) { switch (ptv.type) { - case PrimitiveTypeVar::NilType: + case PrimitiveType::NilType: state.emit("nil"); return; - case PrimitiveTypeVar::Boolean: + case PrimitiveType::Boolean: state.emit("boolean"); return; - case PrimitiveTypeVar::Number: + case PrimitiveType::Number: state.emit("number"); return; - case PrimitiveTypeVar::String: + case PrimitiveType::String: state.emit("string"); return; - case PrimitiveTypeVar::Thread: + case PrimitiveType::Thread: state.emit("thread"); return; - case PrimitiveTypeVar::Function: + case PrimitiveType::Function: state.emit("function"); return; default: @@ -460,7 +462,7 @@ struct TypeVarStringifier } } - void operator()(TypeId, const SingletonTypeVar& stv) + void operator()(TypeId, const SingletonType& stv) { if (const BooleanSingleton* bs = Luau::get(&stv)) state.emit(bs->value ? "true" : "false"); @@ -477,7 +479,7 @@ struct TypeVarStringifier } } - void operator()(TypeId, const FunctionTypeVar& ftv) + void operator()(TypeId, const FunctionType& ftv) { if (state.hasSeen(&ftv)) { @@ -539,7 +541,7 @@ struct TypeVarStringifier state.unsee(&ftv); } - void operator()(TypeId, const TableTypeVar& ttv) + void operator()(TypeId, const TableType& ttv) { if (ttv.boundTo) return stringify(*ttv.boundTo); @@ -681,7 +683,7 @@ struct TypeVarStringifier state.unsee(&ttv); } - void operator()(TypeId, const MetatableTypeVar& mtv) + void operator()(TypeId, const MetatableType& mtv) { state.result.invalid = true; if (!state.exhaustive && mtv.syntheticName) @@ -698,17 +700,17 @@ struct TypeVarStringifier state.emit(" }"); } - void operator()(TypeId, const ClassTypeVar& ctv) + void operator()(TypeId, const ClassType& ctv) { state.emit(ctv.name); } - void operator()(TypeId, const AnyTypeVar&) + void operator()(TypeId, const AnyType&) { state.emit("any"); } - void operator()(TypeId, const UnionTypeVar& uv) + void operator()(TypeId, const UnionType& uv) { if (state.hasSeen(&uv)) { @@ -718,6 +720,7 @@ struct TypeVarStringifier } bool optional = false; + bool hasNonNilDisjunct = false; std::vector results = {}; for (auto el : &uv) @@ -729,10 +732,14 @@ struct TypeVarStringifier optional = true; continue; } + else + { + hasNonNilDisjunct = true; + } std::string saved = std::move(state.result.name); - bool needParens = !state.cycleNames.count(el) && (get(el) || get(el)); + bool needParens = !state.cycleNames.count(el) && (get(el) || get(el)); if (needParens) state.emit("("); @@ -771,11 +778,17 @@ struct TypeVarStringifier if (results.size() > 1) s = ")?"; + if (FFlag::LuauSerializeNilUnionAsNil) + { + if (!hasNonNilDisjunct) + s = "nil"; + } + state.emit(s); } } - void operator()(TypeId, const IntersectionTypeVar& uv) + void operator()(TypeId, const IntersectionType& uv) { if (state.hasSeen(&uv)) { @@ -791,7 +804,7 @@ struct TypeVarStringifier std::string saved = std::move(state.result.name); - bool needParens = !state.cycleNames.count(el) && (get(el) || get(el)); + bool needParens = !state.cycleNames.count(el) && (get(el) || get(el)); if (needParens) state.emit("("); @@ -822,35 +835,35 @@ struct TypeVarStringifier } } - void operator()(TypeId, const ErrorTypeVar& tv) + void operator()(TypeId, const ErrorType& tv) { state.result.error = true; state.emit(FFlag::LuauUnknownAndNeverType ? "*error-type*" : "*unknown*"); } - void operator()(TypeId, const LazyTypeVar& ltv) + void operator()(TypeId, const LazyType& ltv) { state.result.invalid = true; state.emit("lazy?"); } - void operator()(TypeId, const UnknownTypeVar& ttv) + void operator()(TypeId, const UnknownType& ttv) { state.emit("unknown"); } - void operator()(TypeId, const NeverTypeVar& ttv) + void operator()(TypeId, const NeverType& ttv) { state.emit("never"); } - void operator()(TypeId, const NegationTypeVar& ntv) + void operator()(TypeId, const NegationType& ntv) { state.emit("~"); // The precedence of `~` should be less than `|` and `&`. TypeId followed = follow(ntv.ty); - bool parens = get(followed) || get(followed); + bool parens = get(followed) || get(followed); if (parens) state.emit("("); @@ -884,7 +897,7 @@ struct TypePackStringifier void stringify(TypeId tv) { - TypeVarStringifier tvs{state}; + TypeStringifier tvs{state}; tvs.stringify(tv); } @@ -1033,13 +1046,13 @@ struct TypePackStringifier } }; -void TypeVarStringifier::stringify(TypePackId tp) +void TypeStringifier::stringify(TypePackId tp) { TypePackStringifier tps(state); tps.stringify(tp); } -void TypeVarStringifier::stringify(TypePackId tpid, const std::vector>& names) +void TypeStringifier::stringify(TypePackId tpid, const std::vector>& names) { TypePackStringifier tps(state, names); tps.stringify(tpid); @@ -1055,7 +1068,7 @@ static void assignCycleNames(const std::set& cycles, const std::set(follow(cycleTy)); !exhaustive && ttv && (ttv->syntheticName || ttv->name)) + if (auto ttv = get(follow(cycleTy)); !exhaustive && ttv && (ttv->syntheticName || ttv->name)) { // If we have a cycle type in type parameters, assign a cycle name for this named table if (std::find_if(ttv->instantiatedTypeParams.begin(), ttv->instantiatedTypeParams.end(), [&](auto&& el) { @@ -1083,13 +1096,12 @@ static void assignCycleNames(const std::set& cycles, const std::set(ty); ttv && (ttv->name || ttv->syntheticName)) + if (auto ttv = get(ty); ttv && (ttv->name || ttv->syntheticName)) { if (ttv->syntheticName) result.invalid = true; @@ -1128,7 +1140,7 @@ ToStringResult toStringDetailed(TypeId ty, ToStringOptions& opts) return result; } - else if (auto mtv = get(ty); mtv && mtv->syntheticName) + else if (auto mtv = get(ty); mtv && mtv->syntheticName) { result.invalid = true; result.name = *mtv->syntheticName; @@ -1213,7 +1225,7 @@ ToStringResult toStringDetailed(TypeId ty, ToStringOptions& opts) ToStringResult toStringDetailed(TypePackId tp, ToStringOptions& opts) { /* - * 1. Walk the TypeVar and track seen TypeIds. When you reencounter a TypeId, add it to a set of seen cycles. + * 1. Walk the Type and track seen TypeIds. When you reencounter a TypeId, add it to a set of seen cycles. * 2. Generate some names for each cycle. For a starting point, we can just call them t0, t1 and so on. * 3. For each seen cycle, stringify it like we do now, but replace each known cycle with its name. * 4. Print out the root of the type using the same algorithm as step 3. @@ -1228,7 +1240,7 @@ ToStringResult toStringDetailed(TypePackId tp, ToStringOptions& opts) assignCycleNames(cycles, cycleTPs, state.cycleNames, state.cycleTpNames, opts.exhaustive); - TypeVarStringifier tvs{state}; + TypeStringifier tvs{state}; /* If the root itself is a cycle, we special case a little. * We go out of our way to print the following: @@ -1289,7 +1301,7 @@ std::string toString(TypePackId tp, ToStringOptions& opts) return toStringDetailed(tp, opts).name; } -std::string toString(const TypeVar& tv, ToStringOptions& opts) +std::string toString(const Type& tv, ToStringOptions& opts) { return toString(const_cast(&tv), opts); } @@ -1299,11 +1311,11 @@ std::string toString(const TypePackVar& tp, ToStringOptions& opts) return toString(const_cast(&tp), opts); } -std::string toStringNamedFunction(const std::string& funcName, const FunctionTypeVar& ftv, ToStringOptions& opts) +std::string toStringNamedFunction(const std::string& funcName, const FunctionType& ftv, ToStringOptions& opts) { ToStringResult result; StringifierState state{opts, result}; - TypeVarStringifier tvs{state}; + TypeStringifier tvs{state}; state.emit(funcName); diff --git a/Analysis/src/TxnLog.cpp b/Analysis/src/TxnLog.cpp index 18596a63..dacd82dc 100644 --- a/Analysis/src/TxnLog.cpp +++ b/Analysis/src/TxnLog.cpp @@ -87,7 +87,7 @@ void TxnLog::concatAsIntersections(TxnLog rhs, NotNull arena) { TypeId leftTy = arena->addType((*leftRep)->pending); TypeId rightTy = arena->addType(rightRep->pending); - typeVarChanges[ty]->pending.ty = IntersectionTypeVar{{leftTy, rightTy}}; + typeVarChanges[ty]->pending.ty = IntersectionType{{leftTy, rightTy}}; } else typeVarChanges[ty] = std::move(rightRep); @@ -105,7 +105,7 @@ void TxnLog::concatAsUnion(TxnLog rhs, NotNull arena) { TypeId leftTy = arena->addType((*leftRep)->pending); TypeId rightTy = arena->addType(rightRep->pending); - typeVarChanges[ty]->pending.ty = UnionTypeVar{{leftTy, rightTy}}; + typeVarChanges[ty]->pending.ty = UnionType{{leftTy, rightTy}}; } else typeVarChanges[ty] = std::move(rightRep); @@ -261,7 +261,7 @@ PendingTypePack* TxnLog::pending(TypePackId tp) const return nullptr; } -PendingType* TxnLog::replace(TypeId ty, TypeVar replacement) +PendingType* TxnLog::replace(TypeId ty, Type replacement) { PendingType* newTy = queue(ty); newTy->pending.reassign(replacement); @@ -277,10 +277,10 @@ PendingTypePack* TxnLog::replace(TypePackId tp, TypePackVar replacement) PendingType* TxnLog::bindTable(TypeId ty, std::optional newBoundTo) { - LUAU_ASSERT(get(ty)); + LUAU_ASSERT(get(ty)); PendingType* newTy = queue(ty); - if (TableTypeVar* ttv = Luau::getMutable(newTy)) + if (TableType* ttv = Luau::getMutable(newTy)) ttv->boundTo = newBoundTo; return newTy; @@ -288,19 +288,19 @@ PendingType* TxnLog::bindTable(TypeId ty, std::optional newBoundTo) PendingType* TxnLog::changeLevel(TypeId ty, TypeLevel newLevel) { - LUAU_ASSERT(get(ty) || get(ty) || get(ty)); + LUAU_ASSERT(get(ty) || get(ty) || get(ty)); PendingType* newTy = queue(ty); - if (FreeTypeVar* ftv = Luau::getMutable(newTy)) + if (FreeType* ftv = Luau::getMutable(newTy)) { ftv->level = newLevel; } - else if (TableTypeVar* ttv = Luau::getMutable(newTy)) + else if (TableType* ttv = Luau::getMutable(newTy)) { LUAU_ASSERT(ttv->state == TableState::Free || ttv->state == TableState::Generic); ttv->level = newLevel; } - else if (FunctionTypeVar* ftv = Luau::getMutable(newTy)) + else if (FunctionType* ftv = Luau::getMutable(newTy)) { ftv->level = newLevel; } @@ -323,19 +323,19 @@ PendingTypePack* TxnLog::changeLevel(TypePackId tp, TypeLevel newLevel) PendingType* TxnLog::changeScope(TypeId ty, NotNull newScope) { - LUAU_ASSERT(get(ty) || get(ty) || get(ty)); + LUAU_ASSERT(get(ty) || get(ty) || get(ty)); PendingType* newTy = queue(ty); - if (FreeTypeVar* ftv = Luau::getMutable(newTy)) + if (FreeType* ftv = Luau::getMutable(newTy)) { ftv->scope = newScope; } - else if (TableTypeVar* ttv = Luau::getMutable(newTy)) + else if (TableType* ttv = Luau::getMutable(newTy)) { LUAU_ASSERT(ttv->state == TableState::Free || ttv->state == TableState::Generic); ttv->scope = newScope; } - else if (FunctionTypeVar* ftv = Luau::getMutable(newTy)) + else if (FunctionType* ftv = Luau::getMutable(newTy)) { ftv->scope = newScope; } @@ -358,10 +358,10 @@ PendingTypePack* TxnLog::changeScope(TypePackId tp, NotNull newScope) PendingType* TxnLog::changeIndexer(TypeId ty, std::optional indexer) { - LUAU_ASSERT(get(ty)); + LUAU_ASSERT(get(ty)); PendingType* newTy = queue(ty); - if (TableTypeVar* ttv = Luau::getMutable(newTy)) + if (TableType* ttv = Luau::getMutable(newTy)) { ttv->indexer = indexer; } @@ -371,11 +371,11 @@ PendingType* TxnLog::changeIndexer(TypeId ty, std::optional indexe std::optional TxnLog::getLevel(TypeId ty) const { - if (FreeTypeVar* ftv = getMutable(ty)) + if (FreeType* ftv = getMutable(ty)) return ftv->level; - else if (TableTypeVar* ttv = getMutable(ty); ttv && (ttv->state == TableState::Free || ttv->state == TableState::Generic)) + else if (TableType* ttv = getMutable(ty); ttv && (ttv->state == TableState::Free || ttv->state == TableState::Generic)) return ttv->level; - else if (FunctionTypeVar* ftv = getMutable(ty)) + else if (FunctionType* ftv = getMutable(ty)) return ftv->level; return std::nullopt; @@ -392,7 +392,7 @@ TypeId TxnLog::follow(TypeId ty) const // Ugly: Fabricate a TypeId that doesn't adhere to most of the invariants // that normally apply. This is safe because follow will only call get<> // on the returned pointer. - return const_cast(&state->pending); + return const_cast(&state->pending); }); } diff --git a/Analysis/src/TypeVar.cpp b/Analysis/src/Type.cpp similarity index 71% rename from Analysis/src/TypeVar.cpp rename to Analysis/src/Type.cpp index 159e7712..aba6bddc 100644 --- a/Analysis/src/TypeVar.cpp +++ b/Analysis/src/Type.cpp @@ -1,5 +1,5 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/BuiltinDefinitions.h" #include "Luau/Common.h" @@ -11,7 +11,7 @@ #include "Luau/ToString.h" #include "Luau/TypeInfer.h" #include "Luau/TypePack.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/VisitType.h" #include #include @@ -60,20 +60,20 @@ TypeId follow(TypeId t, std::function mapper) auto advance = [&mapper](TypeId ty) -> std::optional { if (auto btv = get>(mapper(ty))) return btv->boundTo; - else if (auto ttv = get(mapper(ty))) + else if (auto ttv = get(mapper(ty))) return ttv->boundTo; else return std::nullopt; }; auto force = [&mapper](TypeId ty) { - if (auto ltv = get_if(&mapper(ty)->ty)) + if (auto ltv = get_if(&mapper(ty)->ty)) { TypeId res = ltv->thunk(); - if (get(res)) - throw InternalCompilerError("Lazy TypeVar cannot resolve to another Lazy TypeVar"); + if (get(res)) + throw InternalCompilerError("Lazy Type cannot resolve to another Lazy Type"); - *asMutable(ty) = BoundTypeVar(res); + *asMutable(ty) = BoundType(res); } }; @@ -109,14 +109,14 @@ TypeId follow(TypeId t, std::function mapper) cycleTester = nullptr; if (t == cycleTester) - throw InternalCompilerError("Luau::follow detected a TypeVar cycle!!"); + throw InternalCompilerError("Luau::follow detected a Type cycle!!"); } } } std::vector flattenIntersection(TypeId ty) { - if (!get(follow(ty))) + if (!get(follow(ty))) return {ty}; std::unordered_set seen; @@ -134,7 +134,7 @@ std::vector flattenIntersection(TypeId ty) seen.insert(current); - if (auto itv = get(current)) + if (auto itv = get(current)) { for (TypeId ty : itv->parts) queue.push_back(ty); @@ -146,23 +146,23 @@ std::vector flattenIntersection(TypeId ty) return result; } -bool isPrim(TypeId ty, PrimitiveTypeVar::Type primType) +bool isPrim(TypeId ty, PrimitiveType::Type primType) { - auto p = get(follow(ty)); + auto p = get(follow(ty)); return p && p->type == primType; } bool isNil(TypeId ty) { - return isPrim(ty, PrimitiveTypeVar::NilType); + return isPrim(ty, PrimitiveType::NilType); } bool isBoolean(TypeId ty) { - if (isPrim(ty, PrimitiveTypeVar::Boolean) || get(get(follow(ty)))) + if (isPrim(ty, PrimitiveType::Boolean) || get(get(follow(ty)))) return true; - if (auto utv = get(follow(ty))) + if (auto utv = get(follow(ty))) return std::all_of(begin(utv), end(utv), isBoolean); return false; @@ -170,7 +170,7 @@ bool isBoolean(TypeId ty) bool isNumber(TypeId ty) { - return isPrim(ty, PrimitiveTypeVar::Number); + return isPrim(ty, PrimitiveType::Number); } // Returns true when ty is a subtype of string @@ -178,10 +178,10 @@ bool isString(TypeId ty) { ty = follow(ty); - if (isPrim(ty, PrimitiveTypeVar::String) || get(get(ty))) + if (isPrim(ty, PrimitiveType::String) || get(get(ty))) return true; - if (auto utv = get(ty)) + if (auto utv = get(ty)) return std::all_of(begin(utv), end(utv), isString); return false; @@ -192,10 +192,10 @@ bool maybeString(TypeId ty) { ty = follow(ty); - if (isPrim(ty, PrimitiveTypeVar::String) || get(ty)) + if (isPrim(ty, PrimitiveType::String) || get(ty)) return true; - if (auto utv = get(ty)) + if (auto utv = get(ty)) return std::any_of(begin(utv), end(utv), maybeString); return false; @@ -203,7 +203,7 @@ bool maybeString(TypeId ty) bool isThread(TypeId ty) { - return isPrim(ty, PrimitiveTypeVar::Thread); + return isPrim(ty, PrimitiveType::Thread); } bool isOptional(TypeId ty) @@ -213,10 +213,10 @@ bool isOptional(TypeId ty) ty = follow(ty); - if (get(ty) || (FFlag::LuauUnknownAndNeverType && get(ty))) + if (get(ty) || (FFlag::LuauUnknownAndNeverType && get(ty))) return true; - auto utv = get(ty); + auto utv = get(ty); if (!utv) return false; @@ -225,7 +225,7 @@ bool isOptional(TypeId ty) bool isTableIntersection(TypeId ty) { - if (!get(follow(ty))) + if (!get(follow(ty))) return false; std::vector parts = flattenIntersection(ty); @@ -234,28 +234,28 @@ bool isTableIntersection(TypeId ty) bool isOverloadedFunction(TypeId ty) { - if (!get(follow(ty))) + if (!get(follow(ty))) return false; auto isFunction = [](TypeId part) -> bool { - return get(part); + return get(part); }; std::vector parts = flattenIntersection(ty); return std::all_of(parts.begin(), parts.end(), isFunction); } -std::optional getMetatable(TypeId type, NotNull singletonTypes) +std::optional getMetatable(TypeId type, NotNull builtinTypes) { type = follow(type); - if (const MetatableTypeVar* mtType = get(type)) + if (const MetatableType* mtType = get(type)) return mtType->metatable; - else if (const ClassTypeVar* classType = get(type)) + else if (const ClassType* classType = get(type)) return classType->metatable; else if (isString(type)) { - auto ptv = get(singletonTypes->stringType); + auto ptv = get(builtinTypes->stringType); LUAU_ASSERT(ptv && ptv->metatable); return ptv->metatable; } @@ -263,34 +263,34 @@ std::optional getMetatable(TypeId type, NotNull singleto return std::nullopt; } -const TableTypeVar* getTableType(TypeId type) +const TableType* getTableType(TypeId type) { type = follow(type); - if (const TableTypeVar* ttv = get(type)) + if (const TableType* ttv = get(type)) return ttv; - else if (const MetatableTypeVar* mtv = get(type)) - return get(follow(mtv->table)); + else if (const MetatableType* mtv = get(type)) + return get(follow(mtv->table)); else return nullptr; } -TableTypeVar* getMutableTableType(TypeId type) +TableType* getMutableTableType(TypeId type) { - return const_cast(getTableType(type)); + return const_cast(getTableType(type)); } const std::string* getName(TypeId type) { type = follow(type); - if (auto mtv = get(type)) + if (auto mtv = get(type)) { if (mtv->syntheticName) return &*mtv->syntheticName; type = follow(mtv->table); } - if (auto ttv = get(type)) + if (auto ttv = get(type)) { if (ttv->name) return &*ttv->name; @@ -305,17 +305,17 @@ std::optional getDefinitionModuleName(TypeId type) { type = follow(type); - if (auto ttv = get(type)) + if (auto ttv = get(type)) { if (!ttv->definitionModuleName.empty()) return ttv->definitionModuleName; } - else if (auto ftv = get(type)) + else if (auto ftv = get(type)) { if (ftv->definition) return ftv->definition->definitionModuleName; } - else if (auto ctv = get(type)) + else if (auto ctv = get(type)) { if (!ctv->definitionModuleName.empty()) return ctv->definitionModuleName; @@ -324,7 +324,7 @@ std::optional getDefinitionModuleName(TypeId type) return std::nullopt; } -bool isSubset(const UnionTypeVar& super, const UnionTypeVar& sub) +bool isSubset(const UnionType& super, const UnionType& sub) { std::unordered_set superTypes; @@ -347,7 +347,7 @@ bool isGeneric(TypeId ty) LUAU_ASSERT(!FFlag::LuauInstantiateInSubtyping); ty = follow(ty); - if (auto ftv = get(ty)) + if (auto ftv = get(ty)) return ftv->generics.size() > 0 || ftv->genericPacks.size() > 0; else // TODO: recurse on type synonyms CLI-39914 @@ -363,17 +363,17 @@ bool maybeGeneric(TypeId ty) { ty = follow(ty); - if (get(ty)) + if (get(ty)) return true; - if (auto ttv = get(ty)) + if (auto ttv = get(ty)) { // TODO: recurse on table types CLI-39914 (void)ttv; return true; } - if (auto itv = get(ty)) + if (auto itv = get(ty)) { return std::any_of(begin(itv), end(itv), maybeGeneric); } @@ -382,9 +382,9 @@ bool maybeGeneric(TypeId ty) } ty = follow(ty); - if (get(ty)) + if (get(ty)) return true; - else if (auto ttv = get(ty)) + else if (auto ttv = get(ty)) { // TODO: recurse on table types CLI-39914 (void)ttv; @@ -397,11 +397,11 @@ bool maybeGeneric(TypeId ty) bool maybeSingleton(TypeId ty) { ty = follow(ty); - if (get(ty)) + if (get(ty)) return true; - if (const UnionTypeVar* utv = get(ty)) + if (const UnionType* utv = get(ty)) for (TypeId option : utv) - if (get(follow(option))) + if (get(follow(option))) return true; return false; } @@ -415,10 +415,10 @@ bool hasLength(TypeId ty, DenseHashSet& seen, int* recursionCount) if (seen.contains(ty)) return true; - if (isString(ty) || get(ty) || get(ty) || get(ty)) + if (isString(ty) || get(ty) || get(ty) || get(ty)) return true; - if (auto uty = get(ty)) + if (auto uty = get(ty)) { seen.insert(ty); @@ -431,7 +431,7 @@ bool hasLength(TypeId ty, DenseHashSet& seen, int* recursionCount) return true; } - if (auto ity = get(ty)) + if (auto ity = get(ty)) { seen.insert(ty); @@ -447,14 +447,14 @@ bool hasLength(TypeId ty, DenseHashSet& seen, int* recursionCount) return false; } -BlockedTypeVar::BlockedTypeVar() +BlockedType::BlockedType() : index(++nextIndex) { } -int BlockedTypeVar::nextIndex = 0; +int BlockedType::nextIndex = 0; -PendingExpansionTypeVar::PendingExpansionTypeVar( +PendingExpansionType::PendingExpansionType( std::optional prefix, AstName name, std::vector typeArguments, std::vector packArguments) : prefix(prefix) , name(name) @@ -464,9 +464,9 @@ PendingExpansionTypeVar::PendingExpansionTypeVar( { } -size_t PendingExpansionTypeVar::nextIndex = 0; +size_t PendingExpansionType::nextIndex = 0; -FunctionTypeVar::FunctionTypeVar(TypePackId argTypes, TypePackId retTypes, std::optional defn, bool hasSelf) +FunctionType::FunctionType(TypePackId argTypes, TypePackId retTypes, std::optional defn, bool hasSelf) : definition(std::move(defn)) , argTypes(argTypes) , retTypes(retTypes) @@ -474,7 +474,7 @@ FunctionTypeVar::FunctionTypeVar(TypePackId argTypes, TypePackId retTypes, std:: { } -FunctionTypeVar::FunctionTypeVar(TypeLevel level, TypePackId argTypes, TypePackId retTypes, std::optional defn, bool hasSelf) +FunctionType::FunctionType(TypeLevel level, TypePackId argTypes, TypePackId retTypes, std::optional defn, bool hasSelf) : definition(std::move(defn)) , level(level) , argTypes(argTypes) @@ -483,7 +483,7 @@ FunctionTypeVar::FunctionTypeVar(TypeLevel level, TypePackId argTypes, TypePackI { } -FunctionTypeVar::FunctionTypeVar( +FunctionType::FunctionType( TypeLevel level, Scope* scope, TypePackId argTypes, TypePackId retTypes, std::optional defn, bool hasSelf) : definition(std::move(defn)) , level(level) @@ -494,7 +494,7 @@ FunctionTypeVar::FunctionTypeVar( { } -FunctionTypeVar::FunctionTypeVar(std::vector generics, std::vector genericPacks, TypePackId argTypes, TypePackId retTypes, +FunctionType::FunctionType(std::vector generics, std::vector genericPacks, TypePackId argTypes, TypePackId retTypes, std::optional defn, bool hasSelf) : definition(std::move(defn)) , generics(generics) @@ -505,7 +505,7 @@ FunctionTypeVar::FunctionTypeVar(std::vector generics, std::vector generics, std::vector genericPacks, TypePackId argTypes, +FunctionType::FunctionType(TypeLevel level, std::vector generics, std::vector genericPacks, TypePackId argTypes, TypePackId retTypes, std::optional defn, bool hasSelf) : definition(std::move(defn)) , generics(generics) @@ -517,8 +517,8 @@ FunctionTypeVar::FunctionTypeVar(TypeLevel level, std::vector generics, { } -FunctionTypeVar::FunctionTypeVar(TypeLevel level, Scope* scope, std::vector generics, std::vector genericPacks, - TypePackId argTypes, TypePackId retTypes, std::optional defn, bool hasSelf) +FunctionType::FunctionType(TypeLevel level, Scope* scope, std::vector generics, std::vector genericPacks, TypePackId argTypes, + TypePackId retTypes, std::optional defn, bool hasSelf) : definition(std::move(defn)) , generics(generics) , genericPacks(genericPacks) @@ -530,14 +530,14 @@ FunctionTypeVar::FunctionTypeVar(TypeLevel level, Scope* scope, std::vector& indexer, TypeLevel level, TableState state) +TableType::TableType(const Props& props, const std::optional& indexer, TypeLevel level, TableState state) : props(props) , indexer(indexer) , state(state) @@ -545,7 +545,7 @@ TableTypeVar::TableTypeVar(const Props& props, const std::optional { } -TableTypeVar::TableTypeVar(const Props& props, const std::optional& indexer, TypeLevel level, Scope* scope, TableState state) +TableType::TableType(const Props& props, const std::optional& indexer, TypeLevel level, Scope* scope, TableState state) : props(props) , indexer(indexer) , state(state) @@ -554,8 +554,8 @@ TableTypeVar::TableTypeVar(const Props& props, const std::optional { } -// Test TypeVars for equivalence -// More complex than we'd like because TypeVars can self-reference. +// Test Types for equivalence +// More complex than we'd like because Types can self-reference. bool areSeen(SeenSet& seen, const void* lhs, const void* rhs) { @@ -570,7 +570,7 @@ bool areSeen(SeenSet& seen, const void* lhs, const void* rhs) return false; } -bool areEqual(SeenSet& seen, const FunctionTypeVar& lhs, const FunctionTypeVar& rhs) +bool areEqual(SeenSet& seen, const FunctionType& lhs, const FunctionType& rhs) { if (areSeen(seen, &lhs, &rhs)) return true; @@ -586,7 +586,7 @@ bool areEqual(SeenSet& seen, const FunctionTypeVar& lhs, const FunctionTypeVar& return true; } -bool areEqual(SeenSet& seen, const TableTypeVar& lhs, const TableTypeVar& rhs) +bool areEqual(SeenSet& seen, const TableType& lhs, const TableType& rhs) { if (areSeen(seen, &lhs, &rhs)) return true; @@ -626,7 +626,7 @@ bool areEqual(SeenSet& seen, const TableTypeVar& lhs, const TableTypeVar& rhs) return true; } -static bool areEqual(SeenSet& seen, const MetatableTypeVar& lhs, const MetatableTypeVar& rhs) +static bool areEqual(SeenSet& seen, const MetatableType& lhs, const MetatableType& rhs) { if (areSeen(seen, &lhs, &rhs)) return true; @@ -634,110 +634,110 @@ static bool areEqual(SeenSet& seen, const MetatableTypeVar& lhs, const Metatable return areEqual(seen, *lhs.table, *rhs.table) && areEqual(seen, *lhs.metatable, *rhs.metatable); } -bool areEqual(SeenSet& seen, const TypeVar& lhs, const TypeVar& rhs) +bool areEqual(SeenSet& seen, const Type& lhs, const Type& rhs) { - if (auto bound = get_if(&lhs.ty)) + if (auto bound = get_if(&lhs.ty)) return areEqual(seen, *bound->boundTo, rhs); - if (auto bound = get_if(&rhs.ty)) + if (auto bound = get_if(&rhs.ty)) return areEqual(seen, lhs, *bound->boundTo); if (lhs.ty.index() != rhs.ty.index()) return false; { - const FreeTypeVar* lf = get_if(&lhs.ty); - const FreeTypeVar* rf = get_if(&rhs.ty); + const FreeType* lf = get_if(&lhs.ty); + const FreeType* rf = get_if(&rhs.ty); if (lf && rf) return lf->index == rf->index; } { - const GenericTypeVar* lg = get_if(&lhs.ty); - const GenericTypeVar* rg = get_if(&rhs.ty); + const GenericType* lg = get_if(&lhs.ty); + const GenericType* rg = get_if(&rhs.ty); if (lg && rg) return lg->index == rg->index; } { - const PrimitiveTypeVar* lp = get_if(&lhs.ty); - const PrimitiveTypeVar* rp = get_if(&rhs.ty); + const PrimitiveType* lp = get_if(&lhs.ty); + const PrimitiveType* rp = get_if(&rhs.ty); if (lp && rp) return lp->type == rp->type; } { - const GenericTypeVar* lg = get_if(&lhs.ty); - const GenericTypeVar* rg = get_if(&rhs.ty); + const GenericType* lg = get_if(&lhs.ty); + const GenericType* rg = get_if(&rhs.ty); if (lg && rg) return lg->index == rg->index; } { - const ErrorTypeVar* le = get_if(&lhs.ty); - const ErrorTypeVar* re = get_if(&rhs.ty); + const ErrorType* le = get_if(&lhs.ty); + const ErrorType* re = get_if(&rhs.ty); if (le && re) return le->index == re->index; } { - const FunctionTypeVar* lf = get_if(&lhs.ty); - const FunctionTypeVar* rf = get_if(&rhs.ty); + const FunctionType* lf = get_if(&lhs.ty); + const FunctionType* rf = get_if(&rhs.ty); if (lf && rf) return areEqual(seen, *lf, *rf); } { - const TableTypeVar* lt = get_if(&lhs.ty); - const TableTypeVar* rt = get_if(&rhs.ty); + const TableType* lt = get_if(&lhs.ty); + const TableType* rt = get_if(&rhs.ty); if (lt && rt) return areEqual(seen, *lt, *rt); } { - const MetatableTypeVar* lmt = get_if(&lhs.ty); - const MetatableTypeVar* rmt = get_if(&rhs.ty); + const MetatableType* lmt = get_if(&lhs.ty); + const MetatableType* rmt = get_if(&rhs.ty); if (lmt && rmt) return areEqual(seen, *lmt, *rmt); } - if (get_if(&lhs.ty) && get_if(&rhs.ty)) + if (get_if(&lhs.ty) && get_if(&rhs.ty)) return true; return false; } -TypeVar* asMutable(TypeId ty) +Type* asMutable(TypeId ty) { - return const_cast(ty); + return const_cast(ty); } -bool TypeVar::operator==(const TypeVar& rhs) const +bool Type::operator==(const Type& rhs) const { SeenSet seen; return areEqual(seen, *this, rhs); } -bool TypeVar::operator!=(const TypeVar& rhs) const +bool Type::operator!=(const Type& rhs) const { SeenSet seen; return !areEqual(seen, *this, rhs); } -TypeVar& TypeVar::operator=(const TypeVariant& rhs) +Type& Type::operator=(const TypeVariant& rhs) { ty = rhs; return *this; } -TypeVar& TypeVar::operator=(TypeVariant&& rhs) +Type& Type::operator=(TypeVariant&& rhs) { ty = std::move(rhs); return *this; } -TypeVar& TypeVar::operator=(const TypeVar& rhs) +Type& Type::operator=(const Type& rhs) { LUAU_ASSERT(owningArena == rhs.owningArena); LUAU_ASSERT(!rhs.persistent); @@ -751,37 +751,38 @@ TypeId makeFunction(TypeArena& arena, std::optional selfType, std::initi std::initializer_list genericPacks, std::initializer_list paramTypes, std::initializer_list paramNames, std::initializer_list retTypes); -SingletonTypes::SingletonTypes() +BuiltinTypes::BuiltinTypes() : arena(new TypeArena) , debugFreezeArena(FFlag::DebugLuauFreezeArena) - , nilType(arena->addType(TypeVar{PrimitiveTypeVar{PrimitiveTypeVar::NilType}, /*persistent*/ true})) - , numberType(arena->addType(TypeVar{PrimitiveTypeVar{PrimitiveTypeVar::Number}, /*persistent*/ true})) - , stringType(arena->addType(TypeVar{PrimitiveTypeVar{PrimitiveTypeVar::String}, /*persistent*/ true})) - , booleanType(arena->addType(TypeVar{PrimitiveTypeVar{PrimitiveTypeVar::Boolean}, /*persistent*/ true})) - , threadType(arena->addType(TypeVar{PrimitiveTypeVar{PrimitiveTypeVar::Thread}, /*persistent*/ true})) - , functionType(arena->addType(TypeVar{PrimitiveTypeVar{PrimitiveTypeVar::Function}, /*persistent*/ true})) - , trueType(arena->addType(TypeVar{SingletonTypeVar{BooleanSingleton{true}}, /*persistent*/ true})) - , falseType(arena->addType(TypeVar{SingletonTypeVar{BooleanSingleton{false}}, /*persistent*/ true})) - , anyType(arena->addType(TypeVar{AnyTypeVar{}, /*persistent*/ true})) - , unknownType(arena->addType(TypeVar{UnknownTypeVar{}, /*persistent*/ true})) - , neverType(arena->addType(TypeVar{NeverTypeVar{}, /*persistent*/ true})) - , errorType(arena->addType(TypeVar{ErrorTypeVar{}, /*persistent*/ true})) - , falsyType(arena->addType(TypeVar{UnionTypeVar{{falseType, nilType}}, /*persistent*/ true})) - , truthyType(arena->addType(TypeVar{NegationTypeVar{falsyType}, /*persistent*/ true})) + , nilType(arena->addType(Type{PrimitiveType{PrimitiveType::NilType}, /*persistent*/ true})) + , numberType(arena->addType(Type{PrimitiveType{PrimitiveType::Number}, /*persistent*/ true})) + , stringType(arena->addType(Type{PrimitiveType{PrimitiveType::String}, /*persistent*/ true})) + , booleanType(arena->addType(Type{PrimitiveType{PrimitiveType::Boolean}, /*persistent*/ true})) + , threadType(arena->addType(Type{PrimitiveType{PrimitiveType::Thread}, /*persistent*/ true})) + , functionType(arena->addType(Type{PrimitiveType{PrimitiveType::Function}, /*persistent*/ true})) + , classType(arena->addType(Type{ClassType{"class", {}, std::nullopt, std::nullopt, {}, {}, {}}, /*persistent*/ true})) + , trueType(arena->addType(Type{SingletonType{BooleanSingleton{true}}, /*persistent*/ true})) + , falseType(arena->addType(Type{SingletonType{BooleanSingleton{false}}, /*persistent*/ true})) + , anyType(arena->addType(Type{AnyType{}, /*persistent*/ true})) + , unknownType(arena->addType(Type{UnknownType{}, /*persistent*/ true})) + , neverType(arena->addType(Type{NeverType{}, /*persistent*/ true})) + , errorType(arena->addType(Type{ErrorType{}, /*persistent*/ true})) + , falsyType(arena->addType(Type{UnionType{{falseType, nilType}}, /*persistent*/ true})) + , truthyType(arena->addType(Type{NegationType{falsyType}, /*persistent*/ true})) , anyTypePack(arena->addTypePack(TypePackVar{VariadicTypePack{anyType}, /*persistent*/ true})) , neverTypePack(arena->addTypePack(TypePackVar{VariadicTypePack{neverType}, /*persistent*/ true})) , uninhabitableTypePack(arena->addTypePack({neverType}, neverTypePack)) , errorTypePack(arena->addTypePack(TypePackVar{Unifiable::Error{}, /*persistent*/ true})) { TypeId stringMetatable = makeStringMetatable(); - asMutable(stringType)->ty = PrimitiveTypeVar{PrimitiveTypeVar::String, stringMetatable}; + asMutable(stringType)->ty = PrimitiveType{PrimitiveType::String, stringMetatable}; persist(stringMetatable); persist(uninhabitableTypePack); freeze(*arena); } -SingletonTypes::~SingletonTypes() +BuiltinTypes::~BuiltinTypes() { // Destroy the arena with the same memory management flags it was created with bool prevFlag = FFlag::DebugLuauFreezeArena; @@ -793,16 +794,16 @@ SingletonTypes::~SingletonTypes() FFlag::DebugLuauFreezeArena.value = prevFlag; } -TypeId SingletonTypes::makeStringMetatable() +TypeId BuiltinTypes::makeStringMetatable() { - const TypeId optionalNumber = arena->addType(UnionTypeVar{{nilType, numberType}}); - const TypeId optionalString = arena->addType(UnionTypeVar{{nilType, stringType}}); - const TypeId optionalBoolean = arena->addType(UnionTypeVar{{nilType, booleanType}}); + const TypeId optionalNumber = arena->addType(UnionType{{nilType, numberType}}); + const TypeId optionalString = arena->addType(UnionType{{nilType, stringType}}); + const TypeId optionalBoolean = arena->addType(UnionType{{nilType, booleanType}}); const TypePackId oneStringPack = arena->addTypePack({stringType}); const TypePackId anyTypePack = arena->addTypePack(TypePackVar{VariadicTypePack{anyType}, true}); - FunctionTypeVar formatFTV{arena->addTypePack(TypePack{{stringType}, anyTypePack}), oneStringPack}; + FunctionType formatFTV{arena->addTypePack(TypePack{{stringType}, anyTypePack}), oneStringPack}; formatFTV.magicFunction = &magicFunctionFormat; const TypeId formatFn = arena->addType(formatFTV); attachDcrMagicFunction(formatFn, dcrMagicFunctionFormat); @@ -813,28 +814,28 @@ TypeId SingletonTypes::makeStringMetatable() const TypeId stringToStringType = makeFunction(*arena, std::nullopt, {}, {}, {stringType}, {}, {stringType}); - const TypeId replArgType = arena->addType( - UnionTypeVar{{stringType, arena->addType(TableTypeVar({}, TableIndexer(stringType, stringType), TypeLevel{}, TableState::Generic)), + const TypeId replArgType = + arena->addType(UnionType{{stringType, arena->addType(TableType({}, TableIndexer(stringType, stringType), TypeLevel{}, TableState::Generic)), makeFunction(*arena, std::nullopt, {}, {}, {stringType}, {}, {stringType})}}); const TypeId gsubFunc = makeFunction(*arena, stringType, {}, {}, {stringType, replArgType, optionalNumber}, {}, {stringType, numberType}); const TypeId gmatchFunc = - makeFunction(*arena, stringType, {}, {}, {stringType}, {}, {arena->addType(FunctionTypeVar{emptyPack, stringVariadicList})}); + makeFunction(*arena, stringType, {}, {}, {stringType}, {}, {arena->addType(FunctionType{emptyPack, stringVariadicList})}); attachMagicFunction(gmatchFunc, magicFunctionGmatch); attachDcrMagicFunction(gmatchFunc, dcrMagicFunctionGmatch); const TypeId matchFunc = arena->addType( - FunctionTypeVar{arena->addTypePack({stringType, stringType, optionalNumber}), arena->addTypePack(TypePackVar{VariadicTypePack{stringType}})}); + FunctionType{arena->addTypePack({stringType, stringType, optionalNumber}), arena->addTypePack(TypePackVar{VariadicTypePack{stringType}})}); attachMagicFunction(matchFunc, magicFunctionMatch); attachDcrMagicFunction(matchFunc, dcrMagicFunctionMatch); - const TypeId findFunc = arena->addType(FunctionTypeVar{arena->addTypePack({stringType, stringType, optionalNumber, optionalBoolean}), + const TypeId findFunc = arena->addType(FunctionType{arena->addTypePack({stringType, stringType, optionalNumber, optionalBoolean}), arena->addTypePack(TypePack{{optionalNumber, optionalNumber}, stringVariadicList})}); attachMagicFunction(findFunc, magicFunctionFind); attachDcrMagicFunction(findFunc, dcrMagicFunctionFind); - TableTypeVar::Props stringLib = { - {"byte", {arena->addType(FunctionTypeVar{arena->addTypePack({stringType, optionalNumber, optionalNumber}), numberVariadicList})}}, - {"char", {arena->addType(FunctionTypeVar{numberVariadicList, arena->addTypePack({stringType})})}}, + TableType::Props stringLib = { + {"byte", {arena->addType(FunctionType{arena->addTypePack({stringType, optionalNumber, optionalNumber}), numberVariadicList})}}, + {"char", {arena->addType(FunctionType{numberVariadicList, arena->addTypePack({stringType})})}}, {"find", {findFunc}}, {"format", {formatFn}}, // FIXME {"gmatch", {gmatchFunc}}, @@ -847,13 +848,13 @@ TypeId SingletonTypes::makeStringMetatable() {"sub", {makeFunction(*arena, stringType, {}, {}, {numberType, optionalNumber}, {}, {stringType})}}, {"upper", {stringToStringType}}, {"split", {makeFunction(*arena, stringType, {}, {}, {optionalString}, {}, - {arena->addType(TableTypeVar{{}, TableIndexer{numberType, stringType}, TypeLevel{}, TableState::Sealed})})}}, - {"pack", {arena->addType(FunctionTypeVar{ + {arena->addType(TableType{{}, TableIndexer{numberType, stringType}, TypeLevel{}, TableState::Sealed})})}}, + {"pack", {arena->addType(FunctionType{ arena->addTypePack(TypePack{{stringType}, anyTypePack}), oneStringPack, })}}, {"packsize", {makeFunction(*arena, stringType, {}, {}, {}, {}, {numberType})}}, - {"unpack", {arena->addType(FunctionTypeVar{ + {"unpack", {arena->addType(FunctionType{ arena->addTypePack(TypePack{{stringType, stringType, optionalNumber}}), anyTypePack, })}}, @@ -861,30 +862,30 @@ TypeId SingletonTypes::makeStringMetatable() assignPropDocumentationSymbols(stringLib, "@luau/global/string"); - TypeId tableType = arena->addType(TableTypeVar{std::move(stringLib), std::nullopt, TypeLevel{}, TableState::Sealed}); + TypeId tableType = arena->addType(TableType{std::move(stringLib), std::nullopt, TypeLevel{}, TableState::Sealed}); - if (TableTypeVar* ttv = getMutable(tableType)) + if (TableType* ttv = getMutable(tableType)) ttv->name = FFlag::LuauNewLibraryTypeNames ? "typeof(string)" : "string"; - return arena->addType(TableTypeVar{{{{"__index", {tableType}}}}, std::nullopt, TypeLevel{}, TableState::Sealed}); + return arena->addType(TableType{{{{"__index", {tableType}}}}, std::nullopt, TypeLevel{}, TableState::Sealed}); } -TypeId SingletonTypes::errorRecoveryType() +TypeId BuiltinTypes::errorRecoveryType() { return errorType; } -TypePackId SingletonTypes::errorRecoveryTypePack() +TypePackId BuiltinTypes::errorRecoveryTypePack() { return errorTypePack; } -TypeId SingletonTypes::errorRecoveryType(TypeId guess) +TypeId BuiltinTypes::errorRecoveryType(TypeId guess) { return guess; } -TypePackId SingletonTypes::errorRecoveryTypePack(TypePackId guess) +TypePackId BuiltinTypes::errorRecoveryTypePack(TypePackId guess) { return guess; } @@ -903,14 +904,14 @@ void persist(TypeId ty) asMutable(t)->persistent = true; - if (auto btv = get(t)) + if (auto btv = get(t)) queue.push_back(btv->boundTo); - else if (auto ftv = get(t)) + else if (auto ftv = get(t)) { persist(ftv->argTypes); persist(ftv->retTypes); } - else if (auto ttv = get(t)) + else if (auto ttv = get(t)) { LUAU_ASSERT(ttv->state != TableState::Free && ttv->state != TableState::Unsealed); @@ -923,28 +924,27 @@ void persist(TypeId ty) queue.push_back(ttv->indexer->indexResultType); } } - else if (auto ctv = get(t)) + else if (auto ctv = get(t)) { for (const auto& [_name, prop] : ctv->props) queue.push_back(prop.type); } - else if (auto utv = get(t)) + else if (auto utv = get(t)) { for (TypeId opt : utv->options) queue.push_back(opt); } - else if (auto itv = get(t)) + else if (auto itv = get(t)) { for (TypeId opt : itv->parts) queue.push_back(opt); } - else if (auto mtv = get(t)) + else if (auto mtv = get(t)) { queue.push_back(mtv->table); queue.push_back(mtv->metatable); } - else if (get(t) || get(t) || get(t) || get(t) || get(t) || - get(t)) + else if (get(t) || get(t) || get(t) || get(t) || get(t) || get(t)) { } else @@ -987,9 +987,9 @@ const TypeLevel* getLevel(TypeId ty) if (auto ftv = get(ty)) return &ftv->level; - else if (auto ttv = get(ty)) + else if (auto ttv = get(ty)) return &ttv->level; - else if (auto ftv = get(ty)) + else if (auto ftv = get(ty)) return &ftv->level; else return nullptr; @@ -1010,7 +1010,7 @@ std::optional getLevel(TypePackId tp) return std::nullopt; } -const Property* lookupClassProp(const ClassTypeVar* cls, const Name& name) +const Property* lookupClassProp(const ClassType* cls, const Name& name) { while (cls) { @@ -1019,7 +1019,7 @@ const Property* lookupClassProp(const ClassTypeVar* cls, const Name& name) return &it->second; if (cls->parent) - cls = get(*cls->parent); + cls = get(*cls->parent); else return nullptr; @@ -1029,7 +1029,7 @@ const Property* lookupClassProp(const ClassTypeVar* cls, const Name& name) return nullptr; } -bool isSubclass(const ClassTypeVar* cls, const ClassTypeVar* parent) +bool isSubclass(const ClassType* cls, const ClassType* parent) { while (cls) { @@ -1038,44 +1038,44 @@ bool isSubclass(const ClassTypeVar* cls, const ClassTypeVar* parent) else if (!cls->parent) return false; - cls = get(*cls->parent); + cls = get(*cls->parent); LUAU_ASSERT(cls); } return false; } -const std::vector& getTypes(const UnionTypeVar* utv) +const std::vector& getTypes(const UnionType* utv) { return utv->options; } -const std::vector& getTypes(const IntersectionTypeVar* itv) +const std::vector& getTypes(const IntersectionType* itv) { return itv->parts; } -UnionTypeVarIterator begin(const UnionTypeVar* utv) +UnionTypeIterator begin(const UnionType* utv) { - return UnionTypeVarIterator{utv}; + return UnionTypeIterator{utv}; } -UnionTypeVarIterator end(const UnionTypeVar* utv) +UnionTypeIterator end(const UnionType* utv) { - return UnionTypeVarIterator{}; + return UnionTypeIterator{}; } -IntersectionTypeVarIterator begin(const IntersectionTypeVar* itv) +IntersectionTypeIterator begin(const IntersectionType* itv) { - return IntersectionTypeVarIterator{itv}; + return IntersectionTypeIterator{itv}; } -IntersectionTypeVarIterator end(const IntersectionTypeVar* itv) +IntersectionTypeIterator end(const IntersectionType* itv) { - return IntersectionTypeVarIterator{}; + return IntersectionTypeIterator{}; } -static std::vector parseFormatString(NotNull singletonTypes, const char* data, size_t size) +static std::vector parseFormatString(NotNull builtinTypes, const char* data, size_t size) { const char* options = "cdiouxXeEfgGqs*"; @@ -1098,13 +1098,13 @@ static std::vector parseFormatString(NotNull singletonTy break; if (data[i] == 'q' || data[i] == 's') - result.push_back(singletonTypes->stringType); + result.push_back(builtinTypes->stringType); else if (data[i] == '*') - result.push_back(singletonTypes->unknownType); + result.push_back(builtinTypes->unknownType); else if (strchr(options, data[i])) - result.push_back(singletonTypes->numberType); + result.push_back(builtinTypes->numberType); else - result.push_back(singletonTypes->errorRecoveryType(singletonTypes->anyType)); + result.push_back(builtinTypes->errorRecoveryType(builtinTypes->anyType)); } } @@ -1133,7 +1133,7 @@ std::optional> magicFunctionFormat( if (!fmt) return std::nullopt; - std::vector expected = parseFormatString(typechecker.singletonTypes, fmt->value.data, fmt->value.size); + std::vector expected = parseFormatString(typechecker.builtinTypes, fmt->value.data, fmt->value.size); const auto& [params, tail] = flatten(paramPack); size_t paramOffset = 1; @@ -1176,7 +1176,7 @@ static bool dcrMagicFunctionFormat(MagicFunctionCallContext context) if (!fmt) return false; - std::vector expected = parseFormatString(context.solver->singletonTypes, fmt->value.data, fmt->value.size); + std::vector expected = parseFormatString(context.solver->builtinTypes, fmt->value.data, fmt->value.size); const auto& [params, tail] = flatten(context.arguments); size_t paramOffset = 1; @@ -1194,13 +1194,13 @@ static bool dcrMagicFunctionFormat(MagicFunctionCallContext context) if (numExpectedParams != numActualParams && (!tail || numExpectedParams < numActualParams)) context.solver->reportError(TypeError{context.callSite->location, CountMismatch{numExpectedParams, std::nullopt, numActualParams}}); - TypePackId resultPack = arena->addTypePack({context.solver->singletonTypes->stringType}); + TypePackId resultPack = arena->addTypePack({context.solver->builtinTypes->stringType}); asMutable(context.result)->ty.emplace(resultPack); return true; } -static std::vector parsePatternString(NotNull singletonTypes, const char* data, size_t size) +static std::vector parsePatternString(NotNull builtinTypes, const char* data, size_t size) { std::vector result; int depth = 0; @@ -1232,12 +1232,12 @@ static std::vector parsePatternString(NotNull singletonT if (i + 1 < size && data[i + 1] == ')') { i++; - result.push_back(singletonTypes->numberType); + result.push_back(builtinTypes->numberType); continue; } ++depth; - result.push_back(singletonTypes->stringType); + result.push_back(builtinTypes->stringType); } else if (data[i] == ')') { @@ -1255,7 +1255,7 @@ static std::vector parsePatternString(NotNull singletonT return std::vector(); if (result.empty()) - result.push_back(singletonTypes->stringType); + result.push_back(builtinTypes->stringType); return result; } @@ -1279,7 +1279,7 @@ static std::optional> magicFunctionGmatch( if (!pattern) return std::nullopt; - std::vector returnTypes = parsePatternString(typechecker.singletonTypes, pattern->value.data, pattern->value.size); + std::vector returnTypes = parsePatternString(typechecker.builtinTypes, pattern->value.data, pattern->value.size); if (returnTypes.empty()) return std::nullopt; @@ -1288,7 +1288,7 @@ static std::optional> magicFunctionGmatch( const TypePackId emptyPack = arena.addTypePack({}); const TypePackId returnList = arena.addTypePack(returnTypes); - const TypeId iteratorType = arena.addType(FunctionTypeVar{emptyPack, returnList}); + const TypeId iteratorType = arena.addType(FunctionType{emptyPack, returnList}); return WithPredicate{arena.addTypePack({iteratorType})}; } @@ -1309,16 +1309,16 @@ static bool dcrMagicFunctionGmatch(MagicFunctionCallContext context) if (!pattern) return false; - std::vector returnTypes = parsePatternString(context.solver->singletonTypes, pattern->value.data, pattern->value.size); + std::vector returnTypes = parsePatternString(context.solver->builtinTypes, pattern->value.data, pattern->value.size); if (returnTypes.empty()) return false; - context.solver->unify(params[0], context.solver->singletonTypes->stringType, context.solver->rootScope); + context.solver->unify(params[0], context.solver->builtinTypes->stringType, context.solver->rootScope); const TypePackId emptyPack = arena->addTypePack({}); const TypePackId returnList = arena->addTypePack(returnTypes); - const TypeId iteratorType = arena->addType(FunctionTypeVar{emptyPack, returnList}); + const TypeId iteratorType = arena->addType(FunctionType{emptyPack, returnList}); const TypePackId resTypePack = arena->addTypePack({iteratorType}); asMutable(context.result)->ty.emplace(resTypePack); @@ -1344,14 +1344,14 @@ static std::optional> magicFunctionMatch( if (!pattern) return std::nullopt; - std::vector returnTypes = parsePatternString(typechecker.singletonTypes, pattern->value.data, pattern->value.size); + std::vector returnTypes = parsePatternString(typechecker.builtinTypes, pattern->value.data, pattern->value.size); if (returnTypes.empty()) return std::nullopt; typechecker.unify(params[0], typechecker.stringType, scope, expr.args.data[0]->location); - const TypeId optionalNumber = arena.addType(UnionTypeVar{{typechecker.nilType, typechecker.numberType}}); + const TypeId optionalNumber = arena.addType(UnionType{{typechecker.nilType, typechecker.numberType}}); size_t initIndex = expr.self ? 1 : 2; if (params.size() == 3 && expr.args.size > initIndex) @@ -1378,14 +1378,14 @@ static bool dcrMagicFunctionMatch(MagicFunctionCallContext context) if (!pattern) return false; - std::vector returnTypes = parsePatternString(context.solver->singletonTypes, pattern->value.data, pattern->value.size); + std::vector returnTypes = parsePatternString(context.solver->builtinTypes, pattern->value.data, pattern->value.size); if (returnTypes.empty()) return false; - context.solver->unify(params[0], context.solver->singletonTypes->stringType, context.solver->rootScope); + context.solver->unify(params[0], context.solver->builtinTypes->stringType, context.solver->rootScope); - const TypeId optionalNumber = arena->addType(UnionTypeVar{{context.solver->singletonTypes->nilType, context.solver->singletonTypes->numberType}}); + const TypeId optionalNumber = arena->addType(UnionType{{context.solver->builtinTypes->nilType, context.solver->builtinTypes->numberType}}); size_t initIndex = context.callSite->self ? 1 : 2; if (params.size() == 3 && context.callSite->args.size > initIndex) @@ -1427,7 +1427,7 @@ static std::optional> magicFunctionFind( std::vector returnTypes; if (!plain) { - returnTypes = parsePatternString(typechecker.singletonTypes, pattern->value.data, pattern->value.size); + returnTypes = parsePatternString(typechecker.builtinTypes, pattern->value.data, pattern->value.size); if (returnTypes.empty()) return std::nullopt; @@ -1435,8 +1435,8 @@ static std::optional> magicFunctionFind( typechecker.unify(params[0], typechecker.stringType, scope, expr.args.data[0]->location); - const TypeId optionalNumber = arena.addType(UnionTypeVar{{typechecker.nilType, typechecker.numberType}}); - const TypeId optionalBoolean = arena.addType(UnionTypeVar{{typechecker.nilType, typechecker.booleanType}}); + const TypeId optionalNumber = arena.addType(UnionType{{typechecker.nilType, typechecker.numberType}}); + const TypeId optionalBoolean = arena.addType(UnionType{{typechecker.nilType, typechecker.booleanType}}); size_t initIndex = expr.self ? 1 : 2; if (params.size() >= 3 && expr.args.size > initIndex) @@ -1459,7 +1459,7 @@ static bool dcrMagicFunctionFind(MagicFunctionCallContext context) return false; TypeArena* arena = context.solver->arena; - NotNull singletonTypes = context.solver->singletonTypes; + NotNull builtinTypes = context.solver->builtinTypes; AstExprConstantString* pattern = nullptr; size_t patternIndex = context.callSite->self ? 0 : 1; @@ -1480,16 +1480,16 @@ static bool dcrMagicFunctionFind(MagicFunctionCallContext context) std::vector returnTypes; if (!plain) { - returnTypes = parsePatternString(singletonTypes, pattern->value.data, pattern->value.size); + returnTypes = parsePatternString(builtinTypes, pattern->value.data, pattern->value.size); if (returnTypes.empty()) return false; } - context.solver->unify(params[0], singletonTypes->stringType, context.solver->rootScope); + context.solver->unify(params[0], builtinTypes->stringType, context.solver->rootScope); - const TypeId optionalNumber = arena->addType(UnionTypeVar{{singletonTypes->nilType, singletonTypes->numberType}}); - const TypeId optionalBoolean = arena->addType(UnionTypeVar{{singletonTypes->nilType, singletonTypes->booleanType}}); + const TypeId optionalNumber = arena->addType(UnionType{{builtinTypes->nilType, builtinTypes->numberType}}); + const TypeId optionalBoolean = arena->addType(UnionType{{builtinTypes->nilType, builtinTypes->booleanType}}); size_t initIndex = context.callSite->self ? 1 : 2; if (params.size() >= 3 && context.callSite->args.size > initIndex) @@ -1509,7 +1509,7 @@ std::vector filterMap(TypeId type, TypeIdPredicate predicate) { type = follow(type); - if (auto utv = get(type)) + if (auto utv = get(type)) { std::set options; for (TypeId option : utv) @@ -1528,11 +1528,11 @@ static Tags* getTags(TypeId ty) { ty = follow(ty); - if (auto ftv = getMutable(ty)) + if (auto ftv = getMutable(ty)) return &ftv->tags; - else if (auto ttv = getMutable(ty)) + else if (auto ttv = getMutable(ty)) return &ttv->tags; - else if (auto ctv = getMutable(ty)) + else if (auto ctv = getMutable(ty)) return &ctv->tags; return nullptr; @@ -1565,7 +1565,7 @@ bool hasTag(TypeId ty, const std::string& tagName) // We special case classes because getTags only returns a pointer to one vector of tags. // But classes has multiple vector of tags, represented throughout the hierarchy. - if (auto ctv = get(ty)) + if (auto ctv = get(ty)) { while (ctv) { @@ -1574,7 +1574,7 @@ bool hasTag(TypeId ty, const std::string& tagName) else if (!ctv->parent) return false; - ctv = get(*ctv->parent); + ctv = get(*ctv->parent); LUAU_ASSERT(ctv); } } diff --git a/Analysis/src/TypeArena.cpp b/Analysis/src/TypeArena.cpp index 666ab867..ed51517e 100644 --- a/Analysis/src/TypeArena.cpp +++ b/Analysis/src/TypeArena.cpp @@ -9,13 +9,13 @@ namespace Luau void TypeArena::clear() { - typeVars.clear(); + types.clear(); typePacks.clear(); } -TypeId TypeArena::addTV(TypeVar&& tv) +TypeId TypeArena::addTV(Type&& tv) { - TypeId allocated = typeVars.allocate(std::move(tv)); + TypeId allocated = types.allocate(std::move(tv)); asMutable(allocated)->owningArena = this; @@ -24,7 +24,7 @@ TypeId TypeArena::addTV(TypeVar&& tv) TypeId TypeArena::freshType(TypeLevel level) { - TypeId allocated = typeVars.allocate(FreeTypeVar{level}); + TypeId allocated = types.allocate(FreeType{level}); asMutable(allocated)->owningArena = this; @@ -33,7 +33,7 @@ TypeId TypeArena::freshType(TypeLevel level) TypeId TypeArena::freshType(Scope* scope) { - TypeId allocated = typeVars.allocate(FreeTypeVar{scope}); + TypeId allocated = types.allocate(FreeType{scope}); asMutable(allocated)->owningArena = this; @@ -42,7 +42,7 @@ TypeId TypeArena::freshType(Scope* scope) TypeId TypeArena::freshType(Scope* scope, TypeLevel level) { - TypeId allocated = typeVars.allocate(FreeTypeVar{scope, level}); + TypeId allocated = types.allocate(FreeType{scope, level}); asMutable(allocated)->owningArena = this; @@ -99,7 +99,7 @@ void freeze(TypeArena& arena) if (!FFlag::DebugLuauFreezeArena) return; - arena.typeVars.freeze(); + arena.types.freeze(); arena.typePacks.freeze(); } @@ -108,7 +108,7 @@ void unfreeze(TypeArena& arena) if (!FFlag::DebugLuauFreezeArena) return; - arena.typeVars.unfreeze(); + arena.types.unfreeze(); arena.typePacks.unfreeze(); } diff --git a/Analysis/src/TypeAttach.cpp b/Analysis/src/TypeAttach.cpp index e483c047..d1d89b25 100644 --- a/Analysis/src/TypeAttach.cpp +++ b/Analysis/src/TypeAttach.cpp @@ -8,7 +8,7 @@ #include "Luau/ToString.h" #include "Luau/TypeInfer.h" #include "Luau/TypePack.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include @@ -75,36 +75,36 @@ public: AstTypePack* rehydrate(TypePackId tp); - AstType* operator()(const PrimitiveTypeVar& ptv) + AstType* operator()(const PrimitiveType& ptv) { switch (ptv.type) { - case PrimitiveTypeVar::NilType: + case PrimitiveType::NilType: return allocator->alloc(Location(), std::nullopt, AstName("nil")); - case PrimitiveTypeVar::Boolean: + case PrimitiveType::Boolean: return allocator->alloc(Location(), std::nullopt, AstName("boolean")); - case PrimitiveTypeVar::Number: + case PrimitiveType::Number: return allocator->alloc(Location(), std::nullopt, AstName("number")); - case PrimitiveTypeVar::String: + case PrimitiveType::String: return allocator->alloc(Location(), std::nullopt, AstName("string")); - case PrimitiveTypeVar::Thread: + case PrimitiveType::Thread: return allocator->alloc(Location(), std::nullopt, AstName("thread")); default: return nullptr; } } - AstType* operator()(const BlockedTypeVar& btv) + AstType* operator()(const BlockedType& btv) { return allocator->alloc(Location(), std::nullopt, AstName("*blocked*")); } - AstType* operator()(const PendingExpansionTypeVar& petv) + AstType* operator()(const PendingExpansionType& petv) { return allocator->alloc(Location(), std::nullopt, AstName("*pending-expansion*")); } - AstType* operator()(const SingletonTypeVar& stv) + AstType* operator()(const SingletonType& stv) { if (const BooleanSingleton* bs = get(&stv)) return allocator->alloc(Location(), bs->value); @@ -119,11 +119,11 @@ public: return nullptr; } - AstType* operator()(const AnyTypeVar&) + AstType* operator()(const AnyType&) { return allocator->alloc(Location(), std::nullopt, AstName("any")); } - AstType* operator()(const TableTypeVar& ttv) + AstType* operator()(const TableType& ttv) { RecursionCounter counter(&count); @@ -182,12 +182,12 @@ public: return allocator->alloc(Location(), props, indexer); } - AstType* operator()(const MetatableTypeVar& mtv) + AstType* operator()(const MetatableType& mtv) { return Luau::visit(*this, mtv.table->ty); } - AstType* operator()(const ClassTypeVar& ctv) + AstType* operator()(const ClassType& ctv) { RecursionCounter counter(&count); @@ -214,7 +214,7 @@ public: return allocator->alloc(Location(), props); } - AstType* operator()(const FunctionTypeVar& ftv) + AstType* operator()(const FunctionType& ftv) { RecursionCounter counter(&count); @@ -227,7 +227,7 @@ public: size_t numGenerics = 0; for (auto it = ftv.generics.begin(); it != ftv.generics.end(); ++it) { - if (auto gtv = get(*it)) + if (auto gtv = get(*it)) generics.data[numGenerics++] = {AstName(gtv->name.c_str()), Location(), nullptr}; } @@ -237,7 +237,7 @@ public: size_t numGenericPacks = 0; for (auto it = ftv.genericPacks.begin(); it != ftv.genericPacks.end(); ++it) { - if (auto gtv = get(*it)) + if (auto gtv = get(*it)) genericPacks.data[numGenericPacks++] = {AstName(gtv->name.c_str()), Location(), nullptr}; } @@ -292,7 +292,7 @@ public: { return allocator->alloc(Location(), std::nullopt, AstName("Unifiable")); } - AstType* operator()(const GenericTypeVar& gtv) + AstType* operator()(const GenericType& gtv) { return allocator->alloc(Location(), std::nullopt, AstName(getName(allocator, syntheticNames, gtv))); } @@ -300,11 +300,11 @@ public: { return Luau::visit(*this, bound.boundTo->ty); } - AstType* operator()(const FreeTypeVar& ftv) + AstType* operator()(const FreeType& ftv) { return allocator->alloc(Location(), std::nullopt, AstName("free")); } - AstType* operator()(const UnionTypeVar& uv) + AstType* operator()(const UnionType& uv) { AstArray unionTypes; unionTypes.size = uv.options.size(); @@ -315,7 +315,7 @@ public: } return allocator->alloc(Location(), unionTypes); } - AstType* operator()(const IntersectionTypeVar& uv) + AstType* operator()(const IntersectionType& uv) { AstArray intersectionTypes; intersectionTypes.size = uv.parts.size(); @@ -326,22 +326,22 @@ public: } return allocator->alloc(Location(), intersectionTypes); } - AstType* operator()(const LazyTypeVar& ltv) + AstType* operator()(const LazyType& ltv) { return allocator->alloc(Location(), std::nullopt, AstName("")); } - AstType* operator()(const UnknownTypeVar& ttv) + AstType* operator()(const UnknownType& ttv) { return allocator->alloc(Location(), std::nullopt, AstName{"unknown"}); } - AstType* operator()(const NeverTypeVar& ttv) + AstType* operator()(const NeverType& ttv) { return allocator->alloc(Location(), std::nullopt, AstName{"never"}); } - AstType* operator()(const NegationTypeVar& ntv) + AstType* operator()(const NegationType& ntv) { - // FIXME: do the same thing we do with ErrorTypeVar - throw InternalCompilerError("Cannot convert NegationTypeVar into AstNode"); + // FIXME: do the same thing we do with ErrorType + throw InternalCompilerError("Cannot convert NegationType into AstNode"); } private: diff --git a/Analysis/src/TypeChecker2.cpp b/Analysis/src/TypeChecker2.cpp index 8c44f90a..5451a454 100644 --- a/Analysis/src/TypeChecker2.cpp +++ b/Analysis/src/TypeChecker2.cpp @@ -10,7 +10,7 @@ #include "Luau/ToString.h" #include "Luau/TxnLog.h" #include "Luau/TypeUtils.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/Unifier.h" #include "Luau/ToString.h" #include "Luau/DcrLogger.h" @@ -19,6 +19,7 @@ LUAU_FASTFLAG(DebugLuauLogSolverToJson); LUAU_FASTFLAG(DebugLuauMagicTypes); +LUAU_FASTFLAG(LuauNegatedClassTypes) namespace Luau { @@ -82,19 +83,20 @@ static std::optional getIdentifierOfBaseVar(AstExpr* node) struct TypeChecker2 { - NotNull singletonTypes; + NotNull builtinTypes; DcrLogger* logger; InternalErrorReporter ice; // FIXME accept a pointer from Frontend const SourceModule* sourceModule; Module* module; + TypeArena testArena; std::vector> stack; UnifierSharedState sharedState{&ice}; - Normalizer normalizer{&module->internalTypes, singletonTypes, NotNull{&sharedState}}; + Normalizer normalizer{&testArena, builtinTypes, NotNull{&sharedState}}; - TypeChecker2(NotNull singletonTypes, DcrLogger* logger, const SourceModule* sourceModule, Module* module) - : singletonTypes(singletonTypes) + TypeChecker2(NotNull builtinTypes, DcrLogger* logger, const SourceModule* sourceModule, Module* module) + : builtinTypes(builtinTypes) , logger(logger) , sourceModule(sourceModule) , module(module) @@ -120,7 +122,7 @@ struct TypeChecker2 if (tp) return follow(*tp); else - return singletonTypes->anyTypePack; + return builtinTypes->anyTypePack; } TypeId lookupType(AstExpr* expr) @@ -136,7 +138,7 @@ struct TypeChecker2 if (tp) return flattenPack(*tp); - return singletonTypes->anyType; + return builtinTypes->anyType; } TypeId lookupAnnotation(AstType* annotation) @@ -298,7 +300,7 @@ struct TypeChecker2 Scope* scope = findInnermostScope(ret->location); TypePackId expectedRetType = scope->returnType; - TypeArena* arena = &module->internalTypes; + TypeArena* arena = &testArena; TypePackId actualRetType = reconstructPack(ret->list, *arena); Unifier u{NotNull{&normalizer}, Mode::Strict, stack.back(), ret->location, Covariant}; @@ -346,6 +348,8 @@ struct TypeChecker2 if (!errors.empty()) reportErrors(std::move(errors)); } + + visit(var->annotation); } } else @@ -368,6 +372,8 @@ struct TypeChecker2 ErrorVec errors = tryUnify(stack.back(), value->location, *it, varType); if (!errors.empty()) reportErrors(std::move(errors)); + + visit(var->annotation); } ++it; @@ -406,7 +412,7 @@ struct TypeChecker2 return; NotNull scope = stack.back(); - TypeArena& arena = module->internalTypes; + TypeArena& arena = testArena; std::vector variableTypes; for (AstLocal* var : forInStatement->vars) @@ -425,7 +431,7 @@ struct TypeChecker2 TypePackId iteratorPack = arena.addTypePack(valueTypes, iteratorTail); // ... and then expand it out to 3 values (if possible) - TypePack iteratorTypes = extendTypePack(arena, singletonTypes, iteratorPack, 3); + TypePack iteratorTypes = extendTypePack(arena, builtinTypes, iteratorPack, 3); if (iteratorTypes.head.empty()) { reportError(GenericError{"for..in loops require at least one value to iterate over. Got zero"}, getLocation(forInStatement->values)); @@ -434,7 +440,7 @@ struct TypeChecker2 TypeId iteratorTy = follow(iteratorTypes.head[0]); auto checkFunction = [this, &arena, &scope, &forInStatement, &variableTypes]( - const FunctionTypeVar* iterFtv, std::vector iterTys, bool isMm) { + const FunctionType* iterFtv, std::vector iterTys, bool isMm) { if (iterTys.size() < 1 || iterTys.size() > 3) { if (isMm) @@ -446,7 +452,7 @@ struct TypeChecker2 } // It is okay if there aren't enough iterators, but the iteratee must provide enough. - TypePack expectedVariableTypes = extendTypePack(arena, singletonTypes, iterFtv->retTypes, variableTypes.size()); + TypePack expectedVariableTypes = extendTypePack(arena, builtinTypes, iterFtv->retTypes, variableTypes.size()); if (expectedVariableTypes.head.size() < variableTypes.size()) { if (isMm) @@ -478,7 +484,7 @@ struct TypeChecker2 if (maxCount && *maxCount < 2) reportError(CountMismatch{2, std::nullopt, *maxCount, CountMismatch::Arg}, forInStatement->vars.data[0]->location); - TypePack flattenedArgTypes = extendTypePack(arena, singletonTypes, iterFtv->argTypes, 2); + TypePack flattenedArgTypes = extendTypePack(arena, builtinTypes, iterFtv->argTypes, 2); size_t firstIterationArgCount = iterTys.empty() ? 0 : iterTys.size() - 1; size_t actualArgCount = expectedVariableTypes.head.size(); @@ -515,11 +521,11 @@ struct TypeChecker2 * nil. * * nextTy() must be callable with only 2 arguments. */ - if (const FunctionTypeVar* nextFn = get(iteratorTy)) + if (const FunctionType* nextFn = get(iteratorTy)) { checkFunction(nextFn, iteratorTypes.head, false); } - else if (const TableTypeVar* ttv = get(iteratorTy)) + else if (const TableType* ttv = get(iteratorTy)) { if ((forInStatement->vars.size == 1 || forInStatement->vars.size == 2) && ttv->indexer) { @@ -530,23 +536,23 @@ struct TypeChecker2 else reportError(GenericError{"Cannot iterate over a table without indexer"}, forInStatement->values.data[0]->location); } - else if (get(iteratorTy) || get(iteratorTy)) + else if (get(iteratorTy) || get(iteratorTy)) { // nothing } else if (std::optional iterMmTy = - findMetatableEntry(singletonTypes, module->errors, iteratorTy, "__iter", forInStatement->values.data[0]->location)) + findMetatableEntry(builtinTypes, module->errors, iteratorTy, "__iter", forInStatement->values.data[0]->location)) { Instantiation instantiation{TxnLog::empty(), &arena, TypeLevel{}, scope}; if (std::optional instantiatedIterMmTy = instantiation.substitute(*iterMmTy)) { - if (const FunctionTypeVar* iterMmFtv = get(*instantiatedIterMmTy)) + if (const FunctionType* iterMmFtv = get(*instantiatedIterMmTy)) { TypePackId argPack = arena.addTypePack({iteratorTy}); reportErrors(tryUnify(scope, forInStatement->values.data[0]->location, argPack, iterMmFtv->argTypes)); - TypePack mmIteratorTypes = extendTypePack(arena, singletonTypes, iterMmFtv->retTypes, 3); + TypePack mmIteratorTypes = extendTypePack(arena, builtinTypes, iterMmFtv->retTypes, 3); if (mmIteratorTypes.head.size() == 0) { @@ -561,7 +567,7 @@ struct TypeChecker2 std::vector instantiatedIteratorTypes = mmIteratorTypes.head; instantiatedIteratorTypes[0] = *instantiatedNextFn; - if (const FunctionTypeVar* nextFtv = get(*instantiatedNextFn)) + if (const FunctionType* nextFtv = get(*instantiatedNextFn)) { checkFunction(nextFtv, instantiatedIteratorTypes, true); } @@ -760,7 +766,7 @@ struct TypeChecker2 void visit(AstExprConstantNumber* number) { TypeId actualType = lookupType(number); - TypeId numberType = singletonTypes->numberType; + TypeId numberType = builtinTypes->numberType; if (!isSubtype(numberType, actualType, stack.back())) { @@ -771,7 +777,7 @@ struct TypeChecker2 void visit(AstExprConstantString* string) { TypeId actualType = lookupType(string); - TypeId stringType = singletonTypes->stringType; + TypeId stringType = builtinTypes->stringType; if (!isSubtype(actualType, stringType, stack.back())) { @@ -801,7 +807,7 @@ struct TypeChecker2 for (AstExpr* arg : call->args) visit(arg); - TypeArena* arena = &module->internalTypes; + TypeArena* arena = &testArena; Instantiation instantiation{TxnLog::empty(), arena, TypeLevel{}, stack.back()}; TypePackId expectedRetType = lookupPack(call); @@ -809,11 +815,11 @@ struct TypeChecker2 TypeId testFunctionType = functionType; TypePack args; - if (get(functionType) || get(functionType)) + if (get(functionType) || get(functionType)) return; - else if (std::optional callMm = findMetatableEntry(singletonTypes, module->errors, functionType, "__call", call->func->location)) + else if (std::optional callMm = findMetatableEntry(builtinTypes, module->errors, functionType, "__call", call->func->location)) { - if (get(follow(*callMm))) + if (get(follow(*callMm))) { if (std::optional instantiatedCallMm = instantiation.substitute(*callMm)) { @@ -834,7 +840,7 @@ struct TypeChecker2 return; } } - else if (get(functionType)) + else if (get(functionType)) { if (std::optional instantiatedFunctionType = instantiation.substitute(functionType)) { @@ -846,7 +852,7 @@ struct TypeChecker2 return; } } - else if (auto utv = get(functionType)) + else if (auto utv = get(functionType)) { // Sometimes it's okay to call a union of functions, but only if all of the functions are the same. std::optional fst; @@ -862,7 +868,7 @@ struct TypeChecker2 } if (!fst) - ice.ice("UnionTypeVar had no elements, so fst is nullopt?"); + ice.ice("UnionType had no elements, so fst is nullopt?"); if (std::optional instantiatedFunctionType = instantiation.substitute(*fst)) { @@ -901,20 +907,20 @@ struct TypeChecker2 if (argTail) args.tail = *argTail; else - args.tail = singletonTypes->anyTypePack; + args.tail = builtinTypes->anyTypePack; } else - args.head.push_back(singletonTypes->anyType); + args.head.push_back(builtinTypes->anyType); } TypePackId argsTp = arena->addTypePack(args); - FunctionTypeVar ftv{argsTp, expectedRetType}; + FunctionType ftv{argsTp, expectedRetType}; TypeId expectedType = arena->addType(ftv); if (!isSubtype(testFunctionType, expectedType, stack.back())) { CloneState cloneState; - expectedType = clone(expectedType, module->internalTypes, cloneState); + expectedType = clone(expectedType, testArena, cloneState); reportError(TypeMismatch{expectedType, functionType}, call->location); } } @@ -942,7 +948,7 @@ struct TypeChecker2 auto StackPusher = pushStack(fn); TypeId inferredFnTy = lookupType(fn); - const FunctionTypeVar* inferredFtv = get(inferredFnTy); + const FunctionType* inferredFtv = get(inferredFnTy); LUAU_ASSERT(inferredFtv); auto argIt = begin(inferredFtv->argTypes); @@ -986,24 +992,24 @@ struct TypeChecker2 NotNull scope = stack.back(); TypeId operandType = lookupType(expr->expr); - if (get(operandType) || get(operandType) || get(operandType)) + if (get(operandType) || get(operandType) || get(operandType)) return; if (auto it = kUnaryOpMetamethods.find(expr->op); it != kUnaryOpMetamethods.end()) { - std::optional mm = findMetatableEntry(singletonTypes, module->errors, operandType, it->second, expr->location); + std::optional mm = findMetatableEntry(builtinTypes, module->errors, operandType, it->second, expr->location); if (mm) { - if (const FunctionTypeVar* ftv = get(follow(*mm))) + if (const FunctionType* ftv = get(follow(*mm))) { - TypePackId expectedArgs = module->internalTypes.addTypePack({operandType}); + TypePackId expectedArgs = testArena.addTypePack({operandType}); reportErrors(tryUnify(scope, expr->location, expectedArgs, ftv->argTypes)); if (std::optional ret = first(ftv->retTypes)) { if (expr->op == AstExprUnary::Op::Len) { - reportErrors(tryUnify(scope, expr->location, follow(*ret), singletonTypes->numberType)); + reportErrors(tryUnify(scope, expr->location, follow(*ret), builtinTypes->numberType)); } } else @@ -1028,7 +1034,7 @@ struct TypeChecker2 } else if (expr->op == AstExprUnary::Op::Minus) { - reportErrors(tryUnify(scope, expr->location, operandType, singletonTypes->numberType)); + reportErrors(tryUnify(scope, expr->location, operandType, builtinTypes->numberType)); } else if (expr->op == AstExprUnary::Op::Not) { @@ -1055,15 +1061,15 @@ struct TypeChecker2 if (expr->op == AstExprBinary::Op::Or) { - leftType = stripNil(singletonTypes, module->internalTypes, leftType); + leftType = stripNil(builtinTypes, testArena, leftType); } bool isStringOperation = isString(leftType) && isString(rightType); - if (get(leftType) || get(leftType) || get(rightType) || get(rightType)) + if (get(leftType) || get(leftType) || get(rightType) || get(rightType)) return; - if ((get(leftType) || get(leftType)) && !isEquality && !isLogical) + if ((get(leftType) || get(leftType)) && !isEquality && !isLogical) { auto name = getIdentifierOfBaseVar(expr->left); reportError(CannotInferBinaryOperation{expr->op, name, @@ -1074,16 +1080,16 @@ struct TypeChecker2 if (auto it = kBinaryOpMetamethods.find(expr->op); it != kBinaryOpMetamethods.end()) { - std::optional leftMt = getMetatable(leftType, singletonTypes); - std::optional rightMt = getMetatable(rightType, singletonTypes); + std::optional leftMt = getMetatable(leftType, builtinTypes); + std::optional rightMt = getMetatable(rightType, builtinTypes); bool matches = leftMt == rightMt; if (isEquality && !matches) { - auto testUnion = [&matches, singletonTypes = this->singletonTypes](const UnionTypeVar* utv, std::optional otherMt) { + auto testUnion = [&matches, builtinTypes = this->builtinTypes](const UnionType* utv, std::optional otherMt) { for (TypeId option : utv) { - if (getMetatable(follow(option), singletonTypes) == otherMt) + if (getMetatable(follow(option), builtinTypes) == otherMt) { matches = true; break; @@ -1091,12 +1097,12 @@ struct TypeChecker2 } }; - if (const UnionTypeVar* utv = get(leftType); utv && rightMt) + if (const UnionType* utv = get(leftType); utv && rightMt) { testUnion(utv, rightMt); } - if (const UnionTypeVar* utv = get(rightType); utv && leftMt && !matches) + if (const UnionType* utv = get(rightType); utv && leftMt && !matches) { testUnion(utv, leftMt); } @@ -1112,9 +1118,9 @@ struct TypeChecker2 } std::optional mm; - if (std::optional leftMm = findMetatableEntry(singletonTypes, module->errors, leftType, it->second, expr->left->location)) + if (std::optional leftMm = findMetatableEntry(builtinTypes, module->errors, leftType, it->second, expr->left->location)) mm = leftMm; - else if (std::optional rightMm = findMetatableEntry(singletonTypes, module->errors, rightType, it->second, expr->right->location)) + else if (std::optional rightMm = findMetatableEntry(builtinTypes, module->errors, rightType, it->second, expr->right->location)) { mm = rightMm; std::swap(leftType, rightType); @@ -1126,18 +1132,18 @@ struct TypeChecker2 if (!instantiatedMm) reportError(CodeTooComplex{}, expr->location); - else if (const FunctionTypeVar* ftv = get(follow(instantiatedMm))) + else if (const FunctionType* ftv = get(follow(instantiatedMm))) { TypePackId expectedArgs; // For >= and > we invoke __lt and __le respectively with // swapped argument ordering. if (expr->op == AstExprBinary::Op::CompareGe || expr->op == AstExprBinary::Op::CompareGt) { - expectedArgs = module->internalTypes.addTypePack({rightType, leftType}); + expectedArgs = testArena.addTypePack({rightType, leftType}); } else { - expectedArgs = module->internalTypes.addTypePack({leftType, rightType}); + expectedArgs = testArena.addTypePack({leftType, rightType}); } reportErrors(tryUnify(scope, expr->location, ftv->argTypes, expectedArgs)); @@ -1145,7 +1151,7 @@ struct TypeChecker2 if (expr->op == AstExprBinary::CompareEq || expr->op == AstExprBinary::CompareNe || expr->op == AstExprBinary::CompareGe || expr->op == AstExprBinary::CompareGt || expr->op == AstExprBinary::Op::CompareLe || expr->op == AstExprBinary::Op::CompareLt) { - TypePackId expectedRets = module->internalTypes.addTypePack({singletonTypes->booleanType}); + TypePackId expectedRets = testArena.addTypePack({builtinTypes->booleanType}); if (!isSubtype(ftv->retTypes, expectedRets, scope)) { reportError(GenericError{format("Metamethod '%s' must return type 'boolean'", it->second)}, expr->location); @@ -1186,7 +1192,7 @@ struct TypeChecker2 return; } - else if (!leftMt && !rightMt && (get(leftType) || get(rightType))) + else if (!leftMt && !rightMt && (get(leftType) || get(rightType))) { if (isComparison) { @@ -1214,13 +1220,13 @@ struct TypeChecker2 case AstExprBinary::Op::Div: case AstExprBinary::Op::Pow: case AstExprBinary::Op::Mod: - reportErrors(tryUnify(scope, expr->left->location, leftType, singletonTypes->numberType)); - reportErrors(tryUnify(scope, expr->right->location, rightType, singletonTypes->numberType)); + reportErrors(tryUnify(scope, expr->left->location, leftType, builtinTypes->numberType)); + reportErrors(tryUnify(scope, expr->right->location, rightType, builtinTypes->numberType)); break; case AstExprBinary::Op::Concat: - reportErrors(tryUnify(scope, expr->left->location, leftType, singletonTypes->stringType)); - reportErrors(tryUnify(scope, expr->right->location, rightType, singletonTypes->stringType)); + reportErrors(tryUnify(scope, expr->left->location, leftType, builtinTypes->stringType)); + reportErrors(tryUnify(scope, expr->right->location, rightType, builtinTypes->stringType)); break; case AstExprBinary::Op::CompareGe: @@ -1228,9 +1234,9 @@ struct TypeChecker2 case AstExprBinary::Op::CompareLe: case AstExprBinary::Op::CompareLt: if (isNumber(leftType)) - reportErrors(tryUnify(scope, expr->right->location, rightType, singletonTypes->numberType)); + reportErrors(tryUnify(scope, expr->right->location, rightType, builtinTypes->numberType)); else if (isString(leftType)) - reportErrors(tryUnify(scope, expr->right->location, rightType, singletonTypes->stringType)); + reportErrors(tryUnify(scope, expr->right->location, rightType, builtinTypes->stringType)); else reportError(GenericError{format("Types '%s' and '%s' cannot be compared with relational operator %s", toString(leftType).c_str(), toString(rightType).c_str(), toString(expr->op).c_str())}, @@ -1304,8 +1310,8 @@ struct TypeChecker2 return vtp->ty; else if (auto ftp = get(pack)) { - TypeId result = module->internalTypes.addType(FreeTypeVar{ftp->scope}); - TypePackId freeTail = module->internalTypes.addTypePack(FreeTypePack{ftp->scope}); + TypeId result = testArena.addType(FreeType{ftp->scope}); + TypePackId freeTail = testArena.addTypePack(FreeTypePack{ftp->scope}); TypePack& resultPack = asMutable(pack)->ty.emplace(); resultPack.head.assign(1, result); @@ -1314,7 +1320,7 @@ struct TypeChecker2 return result; } else if (get(pack)) - return singletonTypes->errorRecoveryType(); + return builtinTypes->errorRecoveryType(); else ice.ice("flattenPack got a weird pack!"); } @@ -1337,6 +1343,11 @@ struct TypeChecker2 void visit(AstTypeReference* ty) { + // No further validation is necessary in this case. The main logic for + // _luau_print is contained in lookupAnnotation. + if (FFlag::DebugLuauMagicTypes && ty->name == "_luau_print" && ty->parameters.size > 0) + return; + for (const AstTypeOrPack& param : ty->parameters) { if (param.type) @@ -1613,18 +1624,29 @@ struct TypeChecker2 fetch(norm.tops); fetch(norm.booleans); - for (TypeId ty : norm.classes) - fetch(ty); + + if (FFlag::LuauNegatedClassTypes) + { + for (const auto& [ty, _negations] : norm.classes.classes) + { + fetch(ty); + } + } + else + { + for (TypeId ty : norm.DEPRECATED_classes) + fetch(ty); + } fetch(norm.errors); fetch(norm.nils); fetch(norm.numbers); if (!norm.strings.isNever()) - fetch(singletonTypes->stringType); + fetch(builtinTypes->stringType); fetch(norm.threads); for (TypeId ty : norm.tables) fetch(ty); if (norm.functions.isTop) - fetch(singletonTypes->functionType); + fetch(builtinTypes->functionType); else if (!norm.functions.isNever()) { if (norm.functions.parts->size() == 1) @@ -1633,15 +1655,15 @@ struct TypeChecker2 { std::vector parts; parts.insert(parts.end(), norm.functions.parts->begin(), norm.functions.parts->end()); - fetch(module->internalTypes.addType(IntersectionTypeVar{std::move(parts)})); + fetch(testArena.addType(IntersectionType{std::move(parts)})); } } for (const auto& [tyvar, intersect] : norm.tyvars) { - if (get(intersect->tops)) + if (get(intersect->tops)) { TypeId ty = normalizer.typeFromNormal(*intersect); - fetch(module->internalTypes.addType(IntersectionTypeVar{{tyvar, ty}})); + fetch(testArena.addType(IntersectionType{{tyvar, ty}})); } else fetch(tyvar); @@ -1658,23 +1680,23 @@ struct TypeChecker2 bool hasIndexTypeFromType(TypeId ty, const std::string& prop, const Location& location) { - if (get(ty) || get(ty) || get(ty)) + if (get(ty) || get(ty) || get(ty)) return true; if (isString(ty)) { - std::optional mtIndex = Luau::findMetatableEntry(singletonTypes, module->errors, singletonTypes->stringType, "__index", location); + std::optional mtIndex = Luau::findMetatableEntry(builtinTypes, module->errors, builtinTypes->stringType, "__index", location); LUAU_ASSERT(mtIndex); ty = *mtIndex; } if (getTableType(ty)) - return bool(findTablePropertyRespectingMeta(singletonTypes, module->errors, ty, prop, location)); - else if (const ClassTypeVar* cls = get(ty)) + return bool(findTablePropertyRespectingMeta(builtinTypes, module->errors, ty, prop, location)); + else if (const ClassType* cls = get(ty)) return bool(lookupClassProp(cls, prop)); - else if (const UnionTypeVar* utv = get(ty)) - ice.ice("getIndexTypeFromTypeHelper cannot take a UnionTypeVar"); - else if (const IntersectionTypeVar* itv = get(ty)) + else if (const UnionType* utv = get(ty)) + ice.ice("getIndexTypeFromTypeHelper cannot take a UnionType"); + else if (const IntersectionType* itv = get(ty)) return std::any_of(begin(itv), end(itv), [&](TypeId part) { return hasIndexTypeFromType(part, prop, location); }); @@ -1683,11 +1705,15 @@ struct TypeChecker2 } }; -void check(NotNull singletonTypes, DcrLogger* logger, const SourceModule& sourceModule, Module* module) +void check(NotNull builtinTypes, DcrLogger* logger, const SourceModule& sourceModule, Module* module) { - TypeChecker2 typeChecker{singletonTypes, logger, &sourceModule, module}; + TypeChecker2 typeChecker{builtinTypes, logger, &sourceModule, module}; typeChecker.visit(sourceModule.root); + + unfreeze(module->interfaceTypes); + copyErrors(module->errors, module->interfaceTypes); + freeze(module->interfaceTypes); } } // namespace Luau diff --git a/Analysis/src/TypeInfer.cpp b/Analysis/src/TypeInfer.cpp index aa738ad9..f31ea938 100644 --- a/Analysis/src/TypeInfer.cpp +++ b/Analysis/src/TypeInfer.cpp @@ -18,8 +18,8 @@ #include "Luau/ToString.h" #include "Luau/TypePack.h" #include "Luau/TypeUtils.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" #include #include @@ -50,6 +50,7 @@ LUAU_FASTFLAGVARIABLE(LuauReportShadowedTypeAlias, false) LUAU_FASTFLAGVARIABLE(LuauBetterMessagingOnCountMismatch, false) LUAU_FASTFLAGVARIABLE(LuauIntersectionTestForEquality, false) LUAU_FASTFLAGVARIABLE(LuauImplicitElseRefinement, false) +LUAU_FASTFLAG(LuauNegatedClassTypes) LUAU_FASTFLAGVARIABLE(LuauAllowIndexClassParameters, false) LUAU_FASTFLAGVARIABLE(LuauDeclareClassPrototype, false) LUAU_FASTFLAG(LuauUninhabitedSubAnything2) @@ -60,7 +61,7 @@ namespace Luau static bool typeCouldHaveMetatable(TypeId ty) { - return get(follow(ty)) || get(follow(ty)) || get(follow(ty)); + return get(follow(ty)) || get(follow(ty)) || get(follow(ty)); } static void defaultLuauPrintLine(const std::string& s) @@ -222,23 +223,23 @@ size_t HashBoolNamePair::operator()(const std::pair& pair) const return std::hash()(pair.first) ^ std::hash()(pair.second); } -TypeChecker::TypeChecker(ModuleResolver* resolver, NotNull singletonTypes, InternalErrorReporter* iceHandler) +TypeChecker::TypeChecker(ModuleResolver* resolver, NotNull builtinTypes, InternalErrorReporter* iceHandler) : resolver(resolver) - , singletonTypes(singletonTypes) + , builtinTypes(builtinTypes) , iceHandler(iceHandler) , unifierState(iceHandler) - , normalizer(nullptr, singletonTypes, NotNull{&unifierState}) - , nilType(singletonTypes->nilType) - , numberType(singletonTypes->numberType) - , stringType(singletonTypes->stringType) - , booleanType(singletonTypes->booleanType) - , threadType(singletonTypes->threadType) - , anyType(singletonTypes->anyType) - , unknownType(singletonTypes->unknownType) - , neverType(singletonTypes->neverType) - , anyTypePack(singletonTypes->anyTypePack) - , neverTypePack(singletonTypes->neverTypePack) - , uninhabitableTypePack(singletonTypes->uninhabitableTypePack) + , normalizer(nullptr, builtinTypes, NotNull{&unifierState}) + , nilType(builtinTypes->nilType) + , numberType(builtinTypes->numberType) + , stringType(builtinTypes->stringType) + , booleanType(builtinTypes->booleanType) + , threadType(builtinTypes->threadType) + , anyType(builtinTypes->anyType) + , unknownType(builtinTypes->unknownType) + , neverType(builtinTypes->neverType) + , anyTypePack(builtinTypes->anyTypePack) + , neverTypePack(builtinTypes->neverTypePack) + , uninhabitableTypePack(builtinTypes->uninhabitableTypePack) , duplicateTypeAliases{{false, {}}} { globalScope = std::make_shared(globalTypes.addTypePack(TypePackVar{FreeTypePack{TypeLevel{}}})); @@ -338,7 +339,7 @@ ModulePtr TypeChecker::checkWithoutRecursionCheck(const SourceModule& module, Mo normalizer.arena = nullptr; } - currentModule->clonePublicInterface(singletonTypes, *iceHandler); + currentModule->clonePublicInterface(builtinTypes, *iceHandler); // Clear unifier cache since it's keyed off internal types that get deallocated // This avoids fake cross-module cache hits and keeps cache size at bay when typechecking large module graphs. @@ -447,13 +448,13 @@ void TypeChecker::checkBlock(const ScopePtr& scope, const AstStatBlock& block) } } -struct InplaceDemoter : TypeVarOnceVisitor +struct InplaceDemoter : TypeOnceVisitor { TypeLevel newLevel; TypeArena* arena; InplaceDemoter(TypeLevel level, TypeArena* arena) - : TypeVarOnceVisitor(/* skipBoundTypes= */ true) + : TypeOnceVisitor(/* skipBoundTypes= */ true) , newLevel(level) , arena(arena) { @@ -670,9 +671,9 @@ LUAU_NOINLINE void TypeChecker::checkBlockTypeAliases(const ScopePtr& scope, std continue; TypeId type = bindings[name].type; - if (get(follow(type))) + if (get(follow(type))) { - TypeVar* mty = asMutable(follow(type)); + Type* mty = asMutable(follow(type)); mty->reassign(*errorRecoveryType(anyType)); reportError(TypeError{typealias->location, OccursCheckFailed{}}); @@ -785,7 +786,7 @@ struct Demoter : Substitution bool isDirty(TypeId ty) override { - return get(ty); + return get(ty); } bool isDirty(TypePackId tp) override @@ -795,7 +796,7 @@ struct Demoter : Substitution bool ignoreChildren(TypeId ty) override { - if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) + if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) return true; return false; @@ -803,9 +804,9 @@ struct Demoter : Substitution TypeId clean(TypeId ty) override { - auto ftv = get(ty); + auto ftv = get(ty); LUAU_ASSERT(ftv); - return addType(FreeTypeVar{demotedLevel(ftv->level)}); + return addType(FreeType{demotedLevel(ftv->level)}); } TypePackId clean(TypePackId tp) override @@ -987,14 +988,14 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatAssign& assign) } // Setting a table entry to nil doesn't mean nil is the type of the indexer, it is just deleting the entry - const TableTypeVar* destTableTypeReceivingNil = nullptr; + const TableType* destTableTypeReceivingNil = nullptr; if (auto indexExpr = dest->as(); isNil(right) && indexExpr) destTableTypeReceivingNil = getTableType(checkExpr(scope, *indexExpr->expr).type); if (!destTableTypeReceivingNil || !destTableTypeReceivingNil->indexer) { - // In nonstrict mode, any assignments where the lhs is free and rhs isn't a function, we give it any typevar. - if (isNonstrictMode() && get(follow(left)) && !get(follow(right))) + // In nonstrict mode, any assignments where the lhs is free and rhs isn't a function, we give it any type. + if (isNonstrictMode() && get(follow(left)) && !get(follow(right))) unify(anyType, left, scope, loc); else unify(right, left, scope, loc); @@ -1046,7 +1047,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatLocal& local) ty = resolveType(scope, *annotation); // If the annotation type has an error, treat it as if there was no annotation - if (get(follow(ty))) + if (get(follow(ty))) ty = nullptr; } @@ -1102,7 +1103,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatLocal& local) { if (rhs->is()) { - TableTypeVar* ttv = getMutable(follow(*ty)); + TableType* ttv = getMutable(follow(*ty)); if (ttv && !ttv->name && scope == currentModule->getModuleScope()) ttv->syntheticName = vars[0]->name.value; } @@ -1110,7 +1111,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatLocal& local) { if (const AstExprGlobal* global = call->func->as(); global && global->name == "setmetatable") { - MetatableTypeVar* mtv = getMutable(follow(*ty)); + MetatableType* mtv = getMutable(follow(*ty)); if (mtv) mtv->syntheticName = vars[0]->name.value; } @@ -1261,7 +1262,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatForIn& forin) return check(loopScope, *forin.body); } - if (const TableTypeVar* iterTable = get(iterTy)) + if (const TableType* iterTable = get(iterTy)) { // TODO: note that this doesn't cleanly handle iteration over mixed tables and tables without an indexer // this behavior is more or less consistent with what we do for pairs(), but really both are pretty wrong and need revisiting @@ -1294,15 +1295,15 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatForIn& forin) return check(loopScope, *forin.body); } - const FunctionTypeVar* iterFunc = get(iterTy); + const FunctionType* iterFunc = get(iterTy); if (!iterFunc) { - TypeId varTy = get(iterTy) ? anyType : errorRecoveryType(loopScope); + TypeId varTy = get(iterTy) ? anyType : errorRecoveryType(loopScope); for (TypeId var : varTypes) unify(varTy, var, scope, forin.location); - if (!get(iterTy) && !get(iterTy) && !get(iterTy) && !get(iterTy)) + if (!get(iterTy) && !get(iterTy) && !get(iterTy) && !get(iterTy)) reportError(firstValue->location, CannotCallNonFunction{iterTy}); return check(loopScope, *forin.body); @@ -1354,7 +1355,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatForIn& forin) { TypeId keyTy = follow(*fty); - if (get(keyTy)) + if (get(keyTy)) { if (std::optional ty = tryStripUnionFromNil(keyTy)) keyTy = *ty; @@ -1432,7 +1433,7 @@ void TypeChecker::check(const ScopePtr& scope, TypeId ty, const ScopePtr& funSco else if (auto name = function.name->as()) { TypeId exprTy = checkExpr(scope, *name->expr).type; - TableTypeVar* ttv = getMutableTableType(exprTy); + TableType* ttv = getMutableTableType(exprTy); if (!getIndexTypeFromType(scope, exprTy, name->index.value, name->indexLocation, /* addErrors= */ false)) { @@ -1449,7 +1450,7 @@ void TypeChecker::check(const ScopePtr& scope, TypeId ty, const ScopePtr& funSco if (function.func->self) { - const FunctionTypeVar* funTy = get(ty); + const FunctionType* funTy = get(ty); if (!funTy) ice("Methods should be functions"); @@ -1520,7 +1521,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatTypeAlias& typealias for (auto param : binding->typeParams) { - auto generic = get(param.ty); + auto generic = get(param.ty); LUAU_ASSERT(generic); aliasScope->privateTypeBindings[generic->name] = TypeFun{{}, param.ty}; } @@ -1533,7 +1534,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatTypeAlias& typealias } TypeId ty = resolveType(aliasScope, *typealias.type); - if (auto ttv = getMutable(follow(ty))) + if (auto ttv = getMutable(follow(ty))) { // If the table is already named and we want to rename the type function, we have to bind new alias to a copy // Additionally, we can't modify types that come from other modules @@ -1552,7 +1553,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatTypeAlias& typealias if (!ttv->name || ttv->name != name || !sameTys || !sameTps) { // This is a shallow clone, original recursive links to self are not updated - TableTypeVar clone = TableTypeVar{ttv->props, ttv->indexer, ttv->level, ttv->state}; + TableType clone = TableType{ttv->props, ttv->indexer, ttv->level, ttv->state}; clone.definitionModuleName = ttv->definitionModuleName; clone.name = name; @@ -1578,7 +1579,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatTypeAlias& typealias ttv->instantiatedTypePackParams.push_back(param.tp); } } - else if (auto mtv = getMutable(follow(ty))) + else if (auto mtv = getMutable(follow(ty))) { // We can't modify types that come from other modules if (follow(ty)->owningArena == ¤tModule->internalTypes) @@ -1634,7 +1635,7 @@ void TypeChecker::prototype(const ScopePtr& scope, const AstStatTypeAlias& typea createGenericTypes(aliasScope, scope->level, typealias, typealias.generics, typealias.genericPacks, /* useCache = */ true); TypeId ty = freshType(aliasScope); - FreeTypeVar* ftv = getMutable(ty); + FreeType* ftv = getMutable(ty); LUAU_ASSERT(ftv); ftv->forwardedTypeAlias = true; bindingsMap[name] = {std::move(generics), std::move(genericPacks), ty}; @@ -1652,7 +1653,7 @@ void TypeChecker::prototype(const ScopePtr& scope, const AstStatTypeAlias& typea createGenericTypes(aliasScope, scope->level, typealias, typealias.generics, typealias.genericPacks, /* useCache = */ true); TypeId ty = freshType(aliasScope); - FreeTypeVar* ftv = getMutable(ty); + FreeType* ftv = getMutable(ty); LUAU_ASSERT(ftv); ftv->forwardedTypeAlias = true; bindingsMap[name] = {std::move(generics), std::move(genericPacks), ty}; @@ -1664,8 +1665,7 @@ void TypeChecker::prototype(const ScopePtr& scope, const AstStatTypeAlias& typea void TypeChecker::prototype(const ScopePtr& scope, const AstStatDeclareClass& declaredClass) { LUAU_ASSERT(FFlag::LuauDeclareClassPrototype); - - std::optional superTy = std::nullopt; + std::optional superTy = FFlag::LuauNegatedClassTypes ? std::make_optional(builtinTypes->classType) : std::nullopt; if (declaredClass.superName) { Name superName = Name(declaredClass.superName->value); @@ -1682,7 +1682,7 @@ void TypeChecker::prototype(const ScopePtr& scope, const AstStatDeclareClass& de LUAU_ASSERT(lookupType->typeParams.size() == 0 && lookupType->typePackParams.size() == 0); superTy = lookupType->type; - if (!get(follow(*superTy))) + if (!get(follow(*superTy))) { reportError(declaredClass.location, GenericError{format("Cannot use non-class type '%s' as a superclass of class '%s'", superName.c_str(), declaredClass.name.value)}); @@ -1693,9 +1693,9 @@ void TypeChecker::prototype(const ScopePtr& scope, const AstStatDeclareClass& de Name className(declaredClass.name.value); - TypeId classTy = addType(ClassTypeVar(className, {}, superTy, std::nullopt, {}, {}, currentModuleName)); - ClassTypeVar* ctv = getMutable(classTy); - TypeId metaTy = addType(TableTypeVar{TableState::Sealed, scope->level}); + TypeId classTy = addType(ClassType(className, {}, superTy, std::nullopt, {}, {}, currentModuleName)); + ClassType* ctv = getMutable(classTy); + TypeId metaTy = addType(TableType{TableState::Sealed, scope->level}); ctv->metatable = metaTy; scope->exportedTypeBindings[className] = TypeFun{{}, classTy}; @@ -1720,25 +1720,25 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declar ice("Class not predeclared"); TypeId classTy = binding->type; - ClassTypeVar* ctv = getMutable(classTy); + ClassType* ctv = getMutable(classTy); if (!ctv->metatable) ice("No metatable for declared class"); - TableTypeVar* metatable = getMutable(*ctv->metatable); + TableType* metatable = getMutable(*ctv->metatable); for (const AstDeclaredClassProp& prop : declaredClass.props) { Name propName(prop.name.value); TypeId propTy = resolveType(scope, *prop.ty); bool assignToMetatable = isMetamethod(propName); - Luau::ClassTypeVar::Props& assignTo = assignToMetatable ? metatable->props : ctv->props; + Luau::ClassType::Props& assignTo = assignToMetatable ? metatable->props : ctv->props; // Function types always take 'self', but this isn't reflected in the // parsed annotation. Add it here. if (prop.isMethod) { - if (FunctionTypeVar* ftv = getMutable(propTy)) + if (FunctionType* ftv = getMutable(propTy)) { ftv->argNames.insert(ftv->argNames.begin(), FunctionArgument{"self", {}}); ftv->argTypes = addTypePack(TypePack{{classTy}, ftv->argTypes}); @@ -1756,17 +1756,17 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declar // We special-case this logic to keep the intersection flat; otherwise we // would create a ton of nested intersection types. - if (const IntersectionTypeVar* itv = get(currentTy)) + if (const IntersectionType* itv = get(currentTy)) { std::vector options = itv->parts; options.push_back(propTy); - TypeId newItv = addType(IntersectionTypeVar{std::move(options)}); + TypeId newItv = addType(IntersectionType{std::move(options)}); assignTo[propName] = {newItv}; } - else if (get(currentTy)) + else if (get(currentTy)) { - TypeId intersection = addType(IntersectionTypeVar{{currentTy, propTy}}); + TypeId intersection = addType(IntersectionType{{currentTy, propTy}}); assignTo[propName] = {intersection}; } @@ -1779,7 +1779,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declar } else { - std::optional superTy = std::nullopt; + std::optional superTy = FFlag::LuauNegatedClassTypes ? std::make_optional(builtinTypes->classType) : std::nullopt; if (declaredClass.superName) { Name superName = Name(declaredClass.superName->value); @@ -1795,7 +1795,7 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declar LUAU_ASSERT(lookupType->typeParams.size() == 0 && lookupType->typePackParams.size() == 0); superTy = lookupType->type; - if (!get(follow(*superTy))) + if (!get(follow(*superTy))) { reportError(declaredClass.location, GenericError{format("Cannot use non-class type '%s' as a superclass of class '%s'", superName.c_str(), declaredClass.name.value)}); @@ -1805,11 +1805,11 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declar Name className(declaredClass.name.value); - TypeId classTy = addType(ClassTypeVar(className, {}, superTy, std::nullopt, {}, {}, currentModuleName)); + TypeId classTy = addType(ClassType(className, {}, superTy, std::nullopt, {}, {}, currentModuleName)); - ClassTypeVar* ctv = getMutable(classTy); - TypeId metaTy = addType(TableTypeVar{TableState::Sealed, scope->level}); - TableTypeVar* metatable = getMutable(metaTy); + ClassType* ctv = getMutable(classTy); + TypeId metaTy = addType(TableType{TableState::Sealed, scope->level}); + TableType* metatable = getMutable(metaTy); ctv->metatable = metaTy; @@ -1821,13 +1821,13 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declar TypeId propTy = resolveType(scope, *prop.ty); bool assignToMetatable = isMetamethod(propName); - Luau::ClassTypeVar::Props& assignTo = assignToMetatable ? metatable->props : ctv->props; + Luau::ClassType::Props& assignTo = assignToMetatable ? metatable->props : ctv->props; // Function types always take 'self', but this isn't reflected in the // parsed annotation. Add it here. if (prop.isMethod) { - if (FunctionTypeVar* ftv = getMutable(propTy)) + if (FunctionType* ftv = getMutable(propTy)) { ftv->argNames.insert(ftv->argNames.begin(), FunctionArgument{"self", {}}); ftv->argTypes = addTypePack(TypePack{{classTy}, ftv->argTypes}); @@ -1845,17 +1845,17 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareClass& declar // We special-case this logic to keep the intersection flat; otherwise we // would create a ton of nested intersection types. - if (const IntersectionTypeVar* itv = get(currentTy)) + if (const IntersectionType* itv = get(currentTy)) { std::vector options = itv->parts; options.push_back(propTy); - TypeId newItv = addType(IntersectionTypeVar{std::move(options)}); + TypeId newItv = addType(IntersectionType{std::move(options)}); assignTo[propName] = {newItv}; } - else if (get(currentTy)) + else if (get(currentTy)) { - TypeId intersection = addType(IntersectionTypeVar{{currentTy, propTy}}); + TypeId intersection = addType(IntersectionType{{currentTy, propTy}}); assignTo[propName] = {intersection}; } @@ -1888,8 +1888,8 @@ void TypeChecker::check(const ScopePtr& scope, const AstStatDeclareFunction& glo TypePackId argPack = resolveTypePack(funScope, global.params); TypePackId retPack = resolveTypePack(funScope, global.retTypes); - TypeId fnType = addType(FunctionTypeVar{funScope->level, std::move(genericTys), std::move(genericTps), argPack, retPack}); - FunctionTypeVar* ftv = getMutable(fnType); + TypeId fnType = addType(FunctionType{funScope->level, std::move(genericTys), std::move(genericTps), argPack, retPack}); + FunctionType* ftv = getMutable(fnType); ftv->argNames.reserve(global.paramNames.size); for (const auto& el : global.paramNames) @@ -2018,7 +2018,7 @@ WithPredicate TypeChecker::checkExpr(const ScopePtr& scope, const AstExp *asMutable(varargPack) = TypePack{{head}, tail}; return {head}; } - if (get(varargPack)) + if (get(varargPack)) return {errorRecoveryType(scope)}; else if (auto vtp = get(varargPack)) return {vtp->ty}; @@ -2085,7 +2085,7 @@ WithPredicate TypeChecker::checkExpr(const ScopePtr& scope, const AstExp std::optional TypeChecker::findTablePropertyRespectingMeta(TypeId lhsType, Name name, const Location& location, bool addErrors) { ErrorVec errors; - auto result = Luau::findTablePropertyRespectingMeta(singletonTypes, errors, lhsType, name, location); + auto result = Luau::findTablePropertyRespectingMeta(builtinTypes, errors, lhsType, name, location); if (addErrors) reportErrors(errors); return result; @@ -2094,7 +2094,7 @@ std::optional TypeChecker::findTablePropertyRespectingMeta(TypeId lhsTyp std::optional TypeChecker::findMetatableEntry(TypeId type, std::string entry, const Location& location, bool addErrors) { ErrorVec errors; - auto result = Luau::findMetatableEntry(singletonTypes, errors, type, entry, location); + auto result = Luau::findMetatableEntry(builtinTypes, errors, type, entry, location); if (addErrors) reportErrors(errors); return result; @@ -2118,7 +2118,7 @@ std::optional TypeChecker::getIndexTypeFromTypeImpl( { type = follow(type); - if (get(type) || get(type) || get(type)) + if (get(type) || get(type) || get(type)) return type; tablify(type); @@ -2130,7 +2130,7 @@ std::optional TypeChecker::getIndexTypeFromTypeImpl( type = *mtIndex; } - if (TableTypeVar* tableType = getMutableTableType(type)) + if (TableType* tableType = getMutableTableType(type)) { if (auto it = tableType->props.find(name); it != tableType->props.end()) return it->second.type; @@ -2157,13 +2157,13 @@ std::optional TypeChecker::getIndexTypeFromTypeImpl( if (auto found = findTablePropertyRespectingMeta(type, name, location, addErrors)) return *found; } - else if (const ClassTypeVar* cls = get(type)) + else if (const ClassType* cls = get(type)) { const Property* prop = lookupClassProp(cls, name); if (prop) return prop->type; } - else if (const UnionTypeVar* utv = get(type)) + else if (const UnionType* utv = get(type)) { std::vector goodOptions; std::vector badOptions; @@ -2173,7 +2173,7 @@ std::optional TypeChecker::getIndexTypeFromTypeImpl( RecursionLimiter _rl(&recursionCount, FInt::LuauTypeInferRecursionLimit); // Not needed when we normalize types. - if (get(follow(t))) + if (get(follow(t))) return t; if (std::optional ty = getIndexTypeFromType(scope, t, name, location, /* addErrors= */ false)) @@ -2201,9 +2201,9 @@ std::optional TypeChecker::getIndexTypeFromTypeImpl( if (result.size() == 1) return result[0]; - return addType(UnionTypeVar{std::move(result)}); + return addType(UnionType{std::move(result)}); } - else if (const IntersectionTypeVar* itv = get(type)) + else if (const IntersectionType* itv = get(type)) { std::vector parts; @@ -2226,7 +2226,7 @@ std::optional TypeChecker::getIndexTypeFromTypeImpl( if (parts.size() == 1) return parts[0]; - return addType(IntersectionTypeVar{std::move(parts)}); // Not at all correct. + return addType(IntersectionType{std::move(parts)}); // Not at all correct. } if (addErrors) @@ -2237,7 +2237,7 @@ std::optional TypeChecker::getIndexTypeFromTypeImpl( std::optional TypeChecker::tryStripUnionFromNil(TypeId ty) { - if (const UnionTypeVar* utv = get(ty)) + if (const UnionType* utv = get(ty)) { if (!std::any_of(begin(utv), end(utv), isNil)) return ty; @@ -2253,7 +2253,7 @@ std::optional TypeChecker::tryStripUnionFromNil(TypeId ty) if (result.empty()) return std::nullopt; - return result.size() == 1 ? result[0] : addType(UnionTypeVar{std::move(result)}); + return result.size() == 1 ? result[0] : addType(UnionType{std::move(result)}); } return std::nullopt; @@ -2263,7 +2263,7 @@ TypeId TypeChecker::stripFromNilAndReport(TypeId ty, const Location& location) { ty = follow(ty); - if (auto utv = get(ty)) + if (auto utv = get(ty)) { if (!std::any_of(begin(utv), end(utv), isNil)) return ty; @@ -2301,14 +2301,14 @@ WithPredicate TypeChecker::checkExpr(const ScopePtr& scope, const AstExp TypeId TypeChecker::checkExprTable( const ScopePtr& scope, const AstExprTable& expr, const std::vector>& fieldTypes, std::optional expectedType) { - TableTypeVar::Props props; + TableType::Props props; std::optional indexer; - const TableTypeVar* expectedTable = nullptr; + const TableType* expectedTable = nullptr; if (expectedType) { - if (auto ttv = get(follow(*expectedType))) + if (auto ttv = get(follow(*expectedType))) { if (ttv->state == TableState::Sealed) expectedTable = ttv; @@ -2342,7 +2342,7 @@ TypeId TypeChecker::checkExprTable( if (auto key = k->as()) { TypeId exprType = follow(valueType); - if (isNonstrictMode() && !getTableType(exprType) && !get(exprType)) + if (isNonstrictMode() && !getTableType(exprType) && !get(exprType)) exprType = anyType; if (expectedTable) @@ -2388,7 +2388,7 @@ TypeId TypeChecker::checkExprTable( } TableState state = TableState::Unsealed; - TableTypeVar table = TableTypeVar{std::move(props), indexer, scope->level, state}; + TableType table = TableType{std::move(props), indexer, scope->level, state}; table.definitionModuleName = currentModuleName; return addType(table); } @@ -2404,14 +2404,14 @@ WithPredicate TypeChecker::checkExpr(const ScopePtr& scope, const AstExp std::vector> fieldTypes(expr.items.size); - const TableTypeVar* expectedTable = nullptr; - const UnionTypeVar* expectedUnion = nullptr; + const TableType* expectedTable = nullptr; + const UnionType* expectedUnion = nullptr; std::optional expectedIndexType; std::optional expectedIndexResultType; if (expectedType) { - if (auto ttv = get(follow(*expectedType))) + if (auto ttv = get(follow(*expectedType))) { if (ttv->state == TableState::Sealed) { @@ -2424,7 +2424,7 @@ WithPredicate TypeChecker::checkExpr(const ScopePtr& scope, const AstExp } } } - else if (const UnionTypeVar* utv = get(follow(*expectedType))) + else if (const UnionType* utv = get(follow(*expectedType))) expectedUnion = utv; } @@ -2455,7 +2455,7 @@ WithPredicate TypeChecker::checkExpr(const ScopePtr& scope, const AstExp std::vector expectedResultTypes; for (TypeId expectedOption : expectedUnion) { - if (const TableTypeVar* ttv = get(follow(expectedOption))) + if (const TableType* ttv = get(follow(expectedOption))) { if (auto prop = ttv->props.find(key->value.data); prop != ttv->props.end()) expectedResultTypes.push_back(prop->second.type); @@ -2467,7 +2467,7 @@ WithPredicate TypeChecker::checkExpr(const ScopePtr& scope, const AstExp if (expectedResultTypes.size() == 1) expectedResultType = expectedResultTypes[0]; else if (expectedResultTypes.size() > 1) - expectedResultType = addType(UnionTypeVar{expectedResultTypes}); + expectedResultType = addType(UnionType{expectedResultTypes}); } } else @@ -2500,7 +2500,7 @@ WithPredicate TypeChecker::checkExpr(const ScopePtr& scope, const AstExp return {booleanType, {NotPredicate{std::move(result.predicates)}}}; case AstExprUnary::Minus: { - const bool operandIsAny = get(operandType) || get(operandType) || get(operandType); + const bool operandIsAny = get(operandType) || get(operandType) || get(operandType); if (operandIsAny) return {operandType}; @@ -2512,7 +2512,7 @@ WithPredicate TypeChecker::checkExpr(const ScopePtr& scope, const AstExp TypeId actualFunctionType = instantiate(scope, *fnt, expr.location); TypePackId arguments = addTypePack({operandType}); TypePackId retTypePack = freshTypePack(scope); - TypeId expectedFunctionType = addType(FunctionTypeVar(scope->level, arguments, retTypePack)); + TypeId expectedFunctionType = addType(FunctionType(scope->level, arguments, retTypePack)); Unifier state = mkUnifier(scope, expr.location); state.tryUnify(actualFunctionType, expectedFunctionType, /*isFunctionCall*/ true); @@ -2542,8 +2542,7 @@ WithPredicate TypeChecker::checkExpr(const ScopePtr& scope, const AstExp operandType = stripFromNilAndReport(operandType, expr.location); // # operator is guaranteed to return number - if ((FFlag::LuauNeverTypesAndOperatorsInference && get(operandType)) || get(operandType) || - get(operandType)) + if ((FFlag::LuauNeverTypesAndOperatorsInference && get(operandType)) || get(operandType) || get(operandType)) { if (FFlag::LuauNeverTypesAndOperatorsInference) return {numberType}; @@ -2560,7 +2559,7 @@ WithPredicate TypeChecker::checkExpr(const ScopePtr& scope, const AstExp TypeId actualFunctionType = instantiate(scope, *fnt, expr.location); TypePackId arguments = addTypePack({operandType}); TypePackId retTypePack = addTypePack({numberType}); - TypeId expectedFunctionType = addType(FunctionTypeVar(scope->level, arguments, retTypePack)); + TypeId expectedFunctionType = addType(FunctionType(scope->level, arguments, retTypePack)); Unifier state = mkUnifier(scope, expr.location); state.tryUnify(actualFunctionType, expectedFunctionType, /*isFunctionCall*/ true); @@ -2617,7 +2616,7 @@ TypeId TypeChecker::unionOfTypes(TypeId a, TypeId b, const ScopePtr& scope, cons a = follow(a); b = follow(b); - if (unifyFreeTypes && (get(a) || get(b))) + if (unifyFreeTypes && (get(a) || get(b))) { if (unify(b, a, scope, location)) return a; @@ -2635,7 +2634,7 @@ TypeId TypeChecker::unionOfTypes(TypeId a, TypeId b, const ScopePtr& scope, cons if (types.size() == 1) return types[0]; - return addType(UnionTypeVar{types}); + return addType(UnionType{types}); } static std::optional getIdentifierOfBaseVar(AstExpr* node) @@ -2663,7 +2662,7 @@ static std::optional getIdentifierOfBaseVar(AstExpr* node) * types have any overlap at all. * * In order to make things work smoothly with the greedy solver, this function - * exempts any and FreeTypeVars from this requirement. + * exempts any and FreeTypes from this requirement. * * This function does not (yet?) take into account extra Lua restrictions like * that two tables can only be compared if they have the same metatable. That @@ -2680,13 +2679,13 @@ static std::optional areEqComparable(NotNull arena, NotNull(t); + return isNil(t) || get(t); }; if (isExempt(a) || isExempt(b)) return true; - TypeId c = arena->addType(IntersectionTypeVar{{a, b}}); + TypeId c = arena->addType(IntersectionType{{a, b}}); const NormalizedType* n = normalizer->normalize(c); if (!n) return std::nullopt; @@ -2705,7 +2704,7 @@ TypeId TypeChecker::checkRelationalOperation( if (!isNonstrictMode() && !isOrOp) return ty; - if (get(ty)) + if (get(ty)) { std::optional cleaned = tryStripUnionFromNil(ty); @@ -2726,7 +2725,7 @@ TypeId TypeChecker::checkRelationalOperation( // If we know nothing at all about the lhs type, we can usually say nothing about the result. // The notable exception to this is the equality and inequality operators, which always produce a boolean. - const bool lhsIsAny = get(lhsType) || get(lhsType) || get(lhsType); + const bool lhsIsAny = get(lhsType) || get(lhsType) || get(lhsType); // Peephole check for `cond and a or b -> type(a)|type(b)` // TODO: Kill this when singleton types arrive. :( @@ -2749,7 +2748,7 @@ TypeId TypeChecker::checkRelationalOperation( if (isNonstrictMode() && (isNil(lhsType) || isNil(rhsType))) return booleanType; - const bool rhsIsAny = get(rhsType) || get(rhsType) || get(rhsType); + const bool rhsIsAny = get(rhsType) || get(rhsType) || get(rhsType); if (lhsIsAny || rhsIsAny) return booleanType; @@ -2763,7 +2762,7 @@ TypeId TypeChecker::checkRelationalOperation( if (FFlag::LuauNeverTypesAndOperatorsInference) { // If one of the operand is never, it doesn't make sense to unify these. - if (get(lhsType) || get(rhsType)) + if (get(lhsType) || get(rhsType)) return booleanType; } @@ -2804,11 +2803,11 @@ TypeId TypeChecker::checkRelationalOperation( const bool needsMetamethod = !isEquality; TypeId leftType = follow(lhsType); - if (get(leftType) || get(leftType) || get(leftType) || get(leftType)) + if (get(leftType) || get(leftType) || get(leftType) || get(leftType)) { reportErrors(state.errors); - if (!isEquality && state.errors.empty() && (get(leftType) || isBoolean(leftType))) + if (!isEquality && state.errors.empty() && (get(leftType) || isBoolean(leftType))) { reportError(expr.location, GenericError{format("Type '%s' cannot be compared with relational operator %s", toString(leftType).c_str(), toString(expr.op).c_str())}); @@ -2819,19 +2818,19 @@ TypeId TypeChecker::checkRelationalOperation( std::string metamethodName = opToMetaTableEntry(expr.op); - std::optional leftMetatable = isString(lhsType) ? std::nullopt : getMetatable(follow(lhsType), singletonTypes); - std::optional rightMetatable = isString(rhsType) ? std::nullopt : getMetatable(follow(rhsType), singletonTypes); + std::optional leftMetatable = isString(lhsType) ? std::nullopt : getMetatable(follow(lhsType), builtinTypes); + std::optional rightMetatable = isString(rhsType) ? std::nullopt : getMetatable(follow(rhsType), builtinTypes); if (leftMetatable != rightMetatable) { bool matches = false; if (isEquality) { - if (const UnionTypeVar* utv = get(leftType); utv && rightMetatable) + if (const UnionType* utv = get(leftType); utv && rightMetatable) { for (TypeId leftOption : utv) { - if (getMetatable(follow(leftOption), singletonTypes) == rightMetatable) + if (getMetatable(follow(leftOption), builtinTypes) == rightMetatable) { matches = true; break; @@ -2841,11 +2840,11 @@ TypeId TypeChecker::checkRelationalOperation( if (!matches) { - if (const UnionTypeVar* utv = get(rhsType); utv && leftMetatable) + if (const UnionType* utv = get(rhsType); utv && leftMetatable) { for (TypeId rightOption : utv) { - if (getMetatable(follow(rightOption), singletonTypes) == leftMetatable) + if (getMetatable(follow(rightOption), builtinTypes) == leftMetatable) { matches = true; break; @@ -2869,7 +2868,7 @@ TypeId TypeChecker::checkRelationalOperation( std::optional metamethod = findMetatableEntry(lhsType, metamethodName, expr.location, /* addErrors= */ true); if (metamethod) { - if (const FunctionTypeVar* ftv = get(*metamethod)) + if (const FunctionType* ftv = get(*metamethod)) { if (isEquality) { @@ -2888,7 +2887,7 @@ TypeId TypeChecker::checkRelationalOperation( reportErrors(state.errors); - TypeId actualFunctionType = addType(FunctionTypeVar(scope->level, addTypePack({lhsType, rhsType}), addTypePack({booleanType}))); + TypeId actualFunctionType = addType(FunctionType(scope->level, addTypePack({lhsType, rhsType}), addTypePack({booleanType}))); state.tryUnify( instantiate(scope, actualFunctionType, expr.location), instantiate(scope, *metamethod, expr.location), /*isFunctionCall*/ true); @@ -2905,7 +2904,7 @@ TypeId TypeChecker::checkRelationalOperation( } } - if (get(follow(lhsType)) && !isEquality) + if (get(follow(lhsType)) && !isEquality) { auto name = getIdentifierOfBaseVar(expr.left); reportError(expr.location, CannotInferBinaryOperation{expr.op, name, CannotInferBinaryOperation::Comparison}); @@ -2930,8 +2929,8 @@ TypeId TypeChecker::checkRelationalOperation( else if (FFlag::LuauTryhardAnd) { // If lhs is free, we can't tell which 'falsy' components it has, if any - if (get(lhsType)) - return unionOfTypes(addType(UnionTypeVar{{nilType, singletonType(false)}}), rhsType, scope, expr.location, false); + if (get(lhsType)) + return unionOfTypes(addType(UnionType{{nilType, singletonType(false)}}), rhsType, scope, expr.location, false); auto [oty, notNever] = pickTypesFromSense(lhsType, false, neverType); // Filter out falsy types @@ -2999,7 +2998,7 @@ TypeId TypeChecker::checkBinaryOperation( lhsType = follow(lhsType); rhsType = follow(rhsType); - if (!isNonstrictMode() && get(lhsType)) + if (!isNonstrictMode() && get(lhsType)) { auto name = getIdentifierOfBaseVar(expr.left); reportError(expr.location, CannotInferBinaryOperation{expr.op, name, CannotInferBinaryOperation::Operation}); @@ -3008,17 +3007,17 @@ TypeId TypeChecker::checkBinaryOperation( // If we know nothing at all about the lhs type, we can usually say nothing about the result. // The notable exception to this is the equality and inequality operators, which always produce a boolean. - const bool lhsIsAny = get(lhsType) || get(lhsType) || - (FFlag::LuauUnknownAndNeverType && FFlag::LuauNeverTypesAndOperatorsInference && get(lhsType)); - const bool rhsIsAny = get(rhsType) || get(rhsType) || - (FFlag::LuauUnknownAndNeverType && FFlag::LuauNeverTypesAndOperatorsInference && get(rhsType)); + const bool lhsIsAny = get(lhsType) || get(lhsType) || + (FFlag::LuauUnknownAndNeverType && FFlag::LuauNeverTypesAndOperatorsInference && get(lhsType)); + const bool rhsIsAny = get(rhsType) || get(rhsType) || + (FFlag::LuauUnknownAndNeverType && FFlag::LuauNeverTypesAndOperatorsInference && get(rhsType)); if (lhsIsAny) return lhsType; if (rhsIsAny) return rhsType; - if (get(lhsType)) + if (get(lhsType)) { // Inferring this accurately will get a bit weird. // If the lhs type is not known, it could be assumed that it is a table or class that has a metatable @@ -3027,7 +3026,7 @@ TypeId TypeChecker::checkBinaryOperation( return anyType; } - if (get(rhsType)) + if (get(rhsType)) unify(rhsType, lhsType, scope, expr.location); if (typeCouldHaveMetatable(lhsType) || typeCouldHaveMetatable(rhsType)) @@ -3036,7 +3035,7 @@ TypeId TypeChecker::checkBinaryOperation( TypeId actualFunctionType = instantiate(scope, fnt, expr.location); TypePackId arguments = addTypePack({lhst, rhst}); TypePackId retTypePack = freshTypePack(scope); - TypeId expectedFunctionType = addType(FunctionTypeVar(scope->level, arguments, retTypePack)); + TypeId expectedFunctionType = addType(FunctionType(scope->level, arguments, retTypePack)); Unifier state = mkUnifier(scope, expr.location); state.tryUnify(actualFunctionType, expectedFunctionType, /*isFunctionCall*/ true); @@ -3049,7 +3048,7 @@ TypeId TypeChecker::checkBinaryOperation( // If there are unification errors, the return type may still be unknown // so we loosen the argument types to see if that helps. TypePackId fallbackArguments = freshTypePack(scope); - TypeId fallbackFunctionType = addType(FunctionTypeVar(scope->level, fallbackArguments, retTypePack)); + TypeId fallbackFunctionType = addType(FunctionType(scope->level, fallbackArguments, retTypePack)); state.errors.clear(); state.log.clear(); @@ -3088,8 +3087,8 @@ TypeId TypeChecker::checkBinaryOperation( switch (expr.op) { case AstExprBinary::Concat: - reportErrors(tryUnify(lhsType, addType(UnionTypeVar{{stringType, numberType}}), scope, expr.left->location)); - reportErrors(tryUnify(rhsType, addType(UnionTypeVar{{stringType, numberType}}), scope, expr.right->location)); + reportErrors(tryUnify(lhsType, addType(UnionType{{stringType, numberType}}), scope, expr.left->location)); + reportErrors(tryUnify(rhsType, addType(UnionType{{stringType, numberType}}), scope, expr.right->location)); return stringType; case AstExprBinary::Add: case AstExprBinary::Sub: @@ -3215,7 +3214,7 @@ WithPredicate TypeChecker::checkExpr(const ScopePtr& scope, const AstExp std::vector types = reduceUnion({trueType.type, falseType.type}); if (FFlag::LuauUnknownAndNeverType && types.empty()) return {neverType}; - return {types.size() == 1 ? types[0] : addType(UnionTypeVar{std::move(types)})}; + return {types.size() == 1 ? types[0] : addType(UnionType{std::move(types)})}; } WithPredicate TypeChecker::checkExpr(const ScopePtr& scope, const AstExprInterpString& expr) @@ -3256,7 +3255,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprLocal if (std::optional ty = scope->lookup(expr.local)) { ty = follow(*ty); - return get(*ty) ? unknownType : *ty; + return get(*ty) ? unknownType : *ty; } reportError(expr.location, UnknownSymbol{expr.local->name.value, UnknownSymbol::Binding}); @@ -3273,7 +3272,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprGloba if (it != moduleScope->bindings.end()) { TypeId ty = follow(it->second.typeId); - return get(ty) ? unknownType : ty; + return get(ty) ? unknownType : ty; } TypeId result = freshType(scope); @@ -3292,10 +3291,10 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex { TypeId lhs = checkExpr(scope, *expr.expr).type; - if (get(lhs) || get(lhs)) + if (get(lhs) || get(lhs)) return lhs; - if (get(lhs)) + if (get(lhs)) return unknownType; tablify(lhs); @@ -3304,7 +3303,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex lhs = stripFromNilAndReport(lhs, expr.expr->location); - if (TableTypeVar* lhsTable = getMutableTableType(lhs)) + if (TableType* lhsTable = getMutableTableType(lhs)) { const auto& it = lhsTable->props.find(name); if (it != lhsTable->props.end()) @@ -3346,7 +3345,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex return errorRecoveryType(scope); } } - else if (const ClassTypeVar* lhsClass = get(lhs)) + else if (const ClassType* lhsClass = get(lhs)) { const Property* prop = lookupClassProp(lhsClass, name); if (!prop) @@ -3357,7 +3356,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex return prop->type; } - else if (get(lhs)) + else if (get(lhs)) { if (std::optional ty = getIndexTypeFromType(scope, lhs, name, expr.location, /* addErrors= */ false)) return *ty; @@ -3386,17 +3385,17 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex if (FFlag::LuauFollowInLvalueIndexCheck) exprType = follow(exprType); - if (get(exprType) || get(exprType)) + if (get(exprType) || get(exprType)) return exprType; - if (get(exprType)) + if (get(exprType)) return unknownType; AstExprConstantString* value = expr.index->as(); if (value) { - if (const ClassTypeVar* exprClass = get(exprType)) + if (const ClassType* exprClass = get(exprType)) { const Property* prop = lookupClassProp(exprClass, value->value.data); if (!prop) @@ -3409,7 +3408,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex } else if (FFlag::LuauAllowIndexClassParameters) { - if (const ClassTypeVar* exprClass = get(exprType)) + if (const ClassType* exprClass = get(exprType)) { if (isNonstrictMode()) return unknownType; @@ -3418,7 +3417,7 @@ TypeId TypeChecker::checkLValueBinding(const ScopePtr& scope, const AstExprIndex } } - TableTypeVar* exprTable = getMutableTableType(exprType); + TableType* exprTable = getMutableTableType(exprType); if (!exprTable) { @@ -3504,7 +3503,7 @@ TypeId TypeChecker::checkFunctionName(const ScopePtr& scope, AstExpr& funName, T else if (auto indexName = funName.as()) { TypeId lhsType = checkExpr(scope, *indexName->expr).type; - TableTypeVar* ttv = getMutableTableType(lhsType); + TableType* ttv = getMutableTableType(lhsType); if (!ttv || ttv->state == TableState::Sealed) { @@ -3549,22 +3548,22 @@ std::pair TypeChecker::checkFunctionSignature(const ScopePtr& { ScopePtr funScope = childFunctionScope(scope, expr.location, subLevel); - const FunctionTypeVar* expectedFunctionType = nullptr; + const FunctionType* expectedFunctionType = nullptr; if (expectedType) { LUAU_ASSERT(!expr.self); - if (auto ftv = get(follow(*expectedType))) + if (auto ftv = get(follow(*expectedType))) { expectedFunctionType = ftv; } - else if (auto utv = get(follow(*expectedType))) + else if (auto utv = get(follow(*expectedType))) { // Look for function type in a union. Other types can be ignored since current expression is a function for (auto option : utv) { - if (auto ftv = get(follow(option))) + if (auto ftv = get(follow(option))) { if (!expectedFunctionType) { @@ -3677,7 +3676,7 @@ std::pair TypeChecker::checkFunctionSignature(const ScopePtr& argType = resolveType(funScope, *local->annotation); // If the annotation type has an error, treat it as if there was no annotation - if (get(follow(argType))) + if (get(follow(argType))) argType = anyIfNonstrict(freshType(funScope)); } else @@ -3741,9 +3740,9 @@ std::pair TypeChecker::checkFunctionSignature(const ScopePtr& } TypeId funTy = - addType(FunctionTypeVar(funScope->level, std::move(genericTys), std::move(genericTps), argPack, retPack, std::move(defn), bool(expr.self))); + addType(FunctionType(funScope->level, std::move(genericTys), std::move(genericTps), argPack, retPack, std::move(defn), bool(expr.self))); - FunctionTypeVar* ftv = getMutable(funTy); + FunctionType* ftv = getMutable(funTy); ftv->argNames.reserve(expr.args.size + (expr.self ? 1 : 0)); @@ -3760,7 +3759,7 @@ static bool allowsNoReturnValues(const TypePackId tp) { for (TypeId ty : tp) { - if (!get(follow(ty))) + if (!get(follow(ty))) { return false; } @@ -3791,7 +3790,7 @@ void TypeChecker::checkFunctionBody(const ScopePtr& scope, TypeId ty, const AstE else LUAU_TIMETRACE_ARGUMENT("line", std::to_string(function.location.begin.line).c_str()); - if (FunctionTypeVar* funTy = getMutable(ty)) + if (FunctionType* funTy = getMutable(ty)) { check(scope, *function.body); @@ -3970,7 +3969,7 @@ void TypeChecker::checkArgumentList(const ScopePtr& scope, const AstExpr& funNam if (isOptional(t)) { } // ok - else if (state.log.getMutable(t)) + else if (state.log.getMutable(t)) { } // ok else @@ -4117,11 +4116,11 @@ WithPredicate TypeChecker::checkExprPackHelper(const ScopePtr& scope } TypePackId retPack; - if (auto free = get(actualFunctionType)) + if (auto free = get(actualFunctionType)) { retPack = freshTypePack(free->level); TypePackId freshArgPack = freshTypePack(free->level); - asMutable(actualFunctionType)->ty.emplace(free->level, freshArgPack, retPack); + asMutable(actualFunctionType)->ty.emplace(free->level, freshArgPack, retPack); } else retPack = freshTypePack(scope->level); @@ -4188,11 +4187,11 @@ WithPredicate TypeChecker::checkExprPackHelper(const ScopePtr& scope reportOverloadResolutionError(scope, expr, retPack, argPack, argLocations, overloads, overloadsThatMatchArgCount, errors); - const FunctionTypeVar* overload = nullptr; + const FunctionType* overload = nullptr; if (!overloadsThatMatchArgCount.empty()) - overload = get(overloadsThatMatchArgCount[0]); + overload = get(overloadsThatMatchArgCount[0]); if (!overload && !overloadsThatDont.empty()) - overload = get(overloadsThatDont[0]); + overload = get(overloadsThatDont[0]); if (overload) return {errorRecoveryTypePack(overload->retTypes)}; @@ -4222,14 +4221,14 @@ std::vector> TypeChecker::getExpectedTypesForCall(const st if (FFlag::LuauUnknownAndNeverType && result.empty()) el = neverType; else - el = result.size() == 1 ? result[0] : addType(UnionTypeVar{std::move(result)}); + el = result.size() == 1 ? result[0] : addType(UnionType{std::move(result)}); } } }; for (const TypeId overload : overloads) { - if (const FunctionTypeVar* ftv = get(overload)) + if (const FunctionType* ftv = get(overload)) { auto [argsHead, argsTail] = flatten(ftv->argTypes); @@ -4265,26 +4264,26 @@ std::optional> TypeChecker::checkCallOverload(const Sc fn = stripFromNilAndReport(fn, expr.func->location); - if (get(fn)) + if (get(fn)) { unify(anyTypePack, argPack, scope, expr.location); return {{anyTypePack}}; } - if (get(fn)) + if (get(fn)) { return {{errorRecoveryTypePack(scope)}}; } - if (get(fn)) + if (get(fn)) return {{uninhabitableTypePack}}; - if (auto ftv = get(fn)) + if (auto ftv = get(fn)) { // fn is one of the overloads of actualFunctionType, which // has been instantiated, so is a monotype. We can therefore // unify it with a monomorphic function. - TypeId r = addType(FunctionTypeVar(scope->level, argPack, retPack)); + TypeId r = addType(FunctionType(scope->level, argPack, retPack)); UnifierOptions options; options.isFunctionCall = true; @@ -4297,11 +4296,11 @@ std::optional> TypeChecker::checkCallOverload(const Sc // Might be a callable table or class std::optional callTy = std::nullopt; - if (const MetatableTypeVar* mttv = get(fn)) + if (const MetatableType* mttv = get(fn)) { callTy = getIndexTypeFromType(scope, mttv->metatable, "__call", expr.func->location, /* addErrors= */ false); } - else if (const ClassTypeVar* ctv = get(fn); FFlag::LuauCallableClasses && ctv && ctv->metatable) + else if (const ClassType* ctv = get(fn); FFlag::LuauCallableClasses && ctv && ctv->metatable) { callTy = getIndexTypeFromType(scope, *ctv->metatable, "__call", expr.func->location, /* addErrors= */ false); } @@ -4324,7 +4323,7 @@ std::optional> TypeChecker::checkCallOverload(const Sc argLocations = &metaArgLocations; } - const FunctionTypeVar* ftv = get(fn); + const FunctionType* ftv = get(fn); if (!ftv) { reportError(TypeError{expr.func->location, CannotCallNonFunction{fn}}); @@ -4481,7 +4480,7 @@ void TypeChecker::reportOverloadResolutionError(const ScopePtr& scope, const Ast // Remove the overload we are reporting errors about, from the list of alternative overloadTypes.erase(std::remove(overloadTypes.begin(), overloadTypes.end(), overload), overloadTypes.end()); - const FunctionTypeVar* ftv = get(overload); + const FunctionType* ftv = get(overload); auto error = std::find_if(errors.begin(), errors.end(), [ftv](const OverloadErrorEntry& e) { return ftv == std::get<2>(e); @@ -4502,7 +4501,7 @@ void TypeChecker::reportOverloadResolutionError(const ScopePtr& scope, const Ast Unifier state = mkUnifier(scope, expr.location); // Unify return types - if (const FunctionTypeVar* ftv = get(overload)) + if (const FunctionType* ftv = get(overload)) { checkArgumentList(scope, *expr.func, state, retPack, ftv->retTypes, {}); checkArgumentList(scope, *expr.func, state, argPack, ftv->argTypes, argLocations); @@ -4586,7 +4585,7 @@ WithPredicate TypeChecker::checkExprList(const ScopePtr& scope, cons auto [type, exprPredicates] = checkExpr(scope, *expr, expectedType); insert(exprPredicates); - if (FFlag::LuauUnknownAndNeverType && get(type)) + if (FFlag::LuauUnknownAndNeverType && get(type)) { // f(), g() where f() returns (never, string) or (string, never) means this whole TypePackId is uninhabitable, so return (never, // ...never) @@ -4705,8 +4704,8 @@ void TypeChecker::tablify(TypeId type) { type = follow(type); - if (auto f = get(type)) - *asMutable(type) = TableTypeVar{TableState::Free, f->level}; + if (auto f = get(type)) + *asMutable(type) = TableType{TableState::Free, f->level}; } TypeId TypeChecker::anyIfNonstrict(TypeId ty) const @@ -4807,14 +4806,14 @@ TypeId TypeChecker::quantify(const ScopePtr& scope, TypeId ty, Location location if (FFlag::DebugLuauSharedSelf) { - if (auto ftv = get(ty)) + if (auto ftv = get(ty)) Luau::quantify(ty, scope->level); else if (auto ttv = getTableType(ty); ttv && ttv->selfTy) Luau::quantify(ty, scope->level); } else { - const FunctionTypeVar* ftv = get(ty); + const FunctionType* ftv = get(ty); if (ftv) Luau::quantify(ty, scope->level); @@ -4827,7 +4826,7 @@ TypeId TypeChecker::instantiate(const ScopePtr& scope, TypeId ty, Location locat { ty = follow(ty); - const FunctionTypeVar* ftv = get(ty); + const FunctionType* ftv = get(ty); if (ftv && ftv->hasNoGenerics) return ty; @@ -4848,7 +4847,7 @@ TypeId TypeChecker::instantiate(const ScopePtr& scope, TypeId ty, Location locat TypeId TypeChecker::anyify(const ScopePtr& scope, TypeId ty, Location location) { - Anyification anyification{¤tModule->internalTypes, scope, singletonTypes, iceHandler, anyType, anyTypePack}; + Anyification anyification{¤tModule->internalTypes, scope, builtinTypes, iceHandler, anyType, anyTypePack}; std::optional any = anyification.substitute(ty); if (anyification.normalizationTooComplex) reportError(location, NormalizationTooComplex{}); @@ -4863,7 +4862,7 @@ TypeId TypeChecker::anyify(const ScopePtr& scope, TypeId ty, Location location) TypePackId TypeChecker::anyify(const ScopePtr& scope, TypePackId ty, Location location) { - Anyification anyification{¤tModule->internalTypes, scope, singletonTypes, iceHandler, anyType, anyTypePack}; + Anyification anyification{¤tModule->internalTypes, scope, builtinTypes, iceHandler, anyType, anyTypePack}; std::optional any = anyification.substitute(ty); if (any.has_value()) return *any; @@ -4881,7 +4880,7 @@ TypePackId TypeChecker::anyifyModuleReturnTypePackGenerics(TypePackId tp) if (const VariadicTypePack* vtp = get(tp)) { TypeId ty = FFlag::LuauTypeInferMissingFollows ? follow(vtp->ty) : vtp->ty; - return get(ty) ? anyTypePack : tp; + return get(ty) ? anyTypePack : tp; } if (!get(follow(tp))) @@ -4895,7 +4894,7 @@ TypePackId TypeChecker::anyifyModuleReturnTypePackGenerics(TypePackId tp) for (TypePackIterator e = end(tp); it != e; ++it) { TypeId ty = follow(*it); - resultTypes.push_back(get(ty) ? anyType : ty); + resultTypes.push_back(get(ty) ? anyType : ty); } if (std::optional tail = it.tail()) @@ -4954,7 +4953,7 @@ void TypeChecker::diagnoseMissingTableKey(UnknownProperty* utk, TypeErrorData& d std::string_view sv(utk->key); std::set candidates; - auto accumulate = [&](const TableTypeVar::Props& props) { + auto accumulate = [&](const TableType::Props& props) { for (const auto& [name, ty] : props) { if (sv != name && equalsLower(sv, name)) @@ -4964,7 +4963,7 @@ void TypeChecker::diagnoseMissingTableKey(UnknownProperty* utk, TypeErrorData& d if (auto ttv = getTableType(utk->table)) accumulate(ttv->props); - else if (auto ctv = get(follow(utk->table))) + else if (auto ctv = get(follow(utk->table))) { while (ctv) { @@ -4973,7 +4972,7 @@ void TypeChecker::diagnoseMissingTableKey(UnknownProperty* utk, TypeErrorData& d if (!ctv->parent) break; - ctv = get(*ctv->parent); + ctv = get(*ctv->parent); LUAU_ASSERT(ctv); } } @@ -5009,15 +5008,15 @@ ScopePtr TypeChecker::childScope(const ScopePtr& parent, const Location& locatio void TypeChecker::merge(RefinementMap& l, const RefinementMap& r) { Luau::merge(l, r, [this](TypeId a, TypeId b) { - // TODO: normalize(UnionTypeVar{{a, b}}) + // TODO: normalize(UnionType{{a, b}}) std::unordered_set set; - if (auto utv = get(follow(a))) + if (auto utv = get(follow(a))) set.insert(begin(utv), end(utv)); else set.insert(a); - if (auto utv = get(follow(b))) + if (auto utv = get(follow(b))) set.insert(begin(utv), end(utv)); else set.insert(b); @@ -5025,7 +5024,7 @@ void TypeChecker::merge(RefinementMap& l, const RefinementMap& r) std::vector options(set.begin(), set.end()); if (set.size() == 1) return options[0]; - return addType(UnionTypeVar{std::move(options)}); + return addType(UnionType{std::move(options)}); }); } @@ -5041,53 +5040,53 @@ TypeId TypeChecker::freshType(const ScopePtr& scope) TypeId TypeChecker::freshType(TypeLevel level) { - return currentModule->internalTypes.addType(TypeVar(FreeTypeVar(level))); + return currentModule->internalTypes.addType(Type(FreeType(level))); } TypeId TypeChecker::singletonType(bool value) { - return value ? singletonTypes->trueType : singletonTypes->falseType; + return value ? builtinTypes->trueType : builtinTypes->falseType; } TypeId TypeChecker::singletonType(std::string value) { // TODO: cache singleton types - return currentModule->internalTypes.addType(TypeVar(SingletonTypeVar(StringSingleton{std::move(value)}))); + return currentModule->internalTypes.addType(Type(SingletonType(StringSingleton{std::move(value)}))); } TypeId TypeChecker::errorRecoveryType(const ScopePtr& scope) { - return singletonTypes->errorRecoveryType(); + return builtinTypes->errorRecoveryType(); } TypeId TypeChecker::errorRecoveryType(TypeId guess) { - return singletonTypes->errorRecoveryType(guess); + return builtinTypes->errorRecoveryType(guess); } TypePackId TypeChecker::errorRecoveryTypePack(const ScopePtr& scope) { - return singletonTypes->errorRecoveryTypePack(); + return builtinTypes->errorRecoveryTypePack(); } TypePackId TypeChecker::errorRecoveryTypePack(TypePackId guess) { - return singletonTypes->errorRecoveryTypePack(guess); + return builtinTypes->errorRecoveryTypePack(guess); } TypeIdPredicate TypeChecker::mkTruthyPredicate(bool sense, TypeId emptySetTy) { return [this, sense, emptySetTy](TypeId ty) -> std::optional { // any/error/free gets a special pass unconditionally because they can't be decided. - if (get(ty) || get(ty) || get(ty)) + if (get(ty) || get(ty) || get(ty)) return ty; // maps boolean primitive to the corresponding singleton equal to sense - if (isPrim(ty, PrimitiveTypeVar::Boolean)) + if (isPrim(ty, PrimitiveType::Boolean)) return singletonType(sense); // if we have boolean singleton, eliminate it if the sense doesn't match with that singleton - if (auto boolean = get(get(ty))) + if (auto boolean = get(get(ty))) return boolean->value == sense ? std::optional(ty) : std::nullopt; // if we have nil, eliminate it if sense is true, otherwise take it @@ -5103,7 +5102,7 @@ std::optional TypeChecker::filterMapImpl(TypeId type, TypeIdPredicate pr { std::vector types = Luau::filterMap(type, predicate); if (!types.empty()) - return types.size() == 1 ? types[0] : addType(UnionTypeVar{std::move(types)}); + return types.size() == 1 ? types[0] : addType(UnionType{std::move(types)}); return std::nullopt; } @@ -5112,7 +5111,7 @@ std::pair, bool> TypeChecker::filterMap(TypeId type, TypeI if (FFlag::LuauUnknownAndNeverType) { TypeId ty = filterMapImpl(type, predicate).value_or(neverType); - return {ty, !bool(get(ty))}; + return {ty, !bool(get(ty))}; } else { @@ -5126,7 +5125,7 @@ std::pair, bool> TypeChecker::pickTypesFromSense(TypeId ty return filterMap(type, mkTruthyPredicate(sense, emptySetTy)); } -TypeId TypeChecker::addTV(TypeVar&& tv) +TypeId TypeChecker::addTV(Type&& tv) { return currentModule->internalTypes.addType(std::move(tv)); } @@ -5381,7 +5380,7 @@ TypeId TypeChecker::resolveTypeWorker(const ScopePtr& scope, const AstType& anno } else if (const auto& table = annotation.as()) { - TableTypeVar::Props props; + TableType::Props props; std::optional tableIndexer; for (const auto& prop : table->props) @@ -5390,7 +5389,7 @@ TypeId TypeChecker::resolveTypeWorker(const ScopePtr& scope, const AstType& anno if (const auto& indexer = table->indexer) tableIndexer = TableIndexer(resolveType(scope, *indexer->indexType), resolveType(scope, *indexer->resultType)); - TableTypeVar ttv{props, tableIndexer, scope->level, TableState::Sealed}; + TableType ttv{props, tableIndexer, scope->level, TableState::Sealed}; ttv.definitionModuleName = currentModuleName; return addType(std::move(ttv)); } @@ -5416,9 +5415,9 @@ TypeId TypeChecker::resolveTypeWorker(const ScopePtr& scope, const AstType& anno return el.tp; }); - TypeId fnType = addType(FunctionTypeVar{funcScope->level, std::move(genericTys), std::move(genericTps), argTypes, retTypes}); + TypeId fnType = addType(FunctionType{funcScope->level, std::move(genericTys), std::move(genericTps), argTypes, retTypes}); - FunctionTypeVar* ftv = getMutable(fnType); + FunctionType* ftv = getMutable(fnType); ftv->argNames.reserve(func->argNames.size); for (const auto& el : func->argNames) @@ -5442,7 +5441,7 @@ TypeId TypeChecker::resolveTypeWorker(const ScopePtr& scope, const AstType& anno for (AstType* ann : un->types) types.push_back(resolveType(scope, *ann)); - return addType(UnionTypeVar{types}); + return addType(UnionType{types}); } else if (const auto& un = annotation.as()) { @@ -5450,7 +5449,7 @@ TypeId TypeChecker::resolveTypeWorker(const ScopePtr& scope, const AstType& anno for (AstType* ann : un->types) types.push_back(resolveType(scope, *ann)); - return addType(IntersectionTypeVar{types}); + return addType(IntersectionType{types}); } else if (const auto& tsb = annotation.as()) { @@ -5566,7 +5565,7 @@ TypeId TypeChecker::instantiateTypeFun(const ScopePtr& scope, const TypeFun& tf, TypeId target = follow(instantiated); bool needsClone = follow(tf.type) == target; bool shouldMutate = getTableType(tf.type); - TableTypeVar* ttv = getMutableTableType(target); + TableType* ttv = getMutableTableType(target); if (shouldMutate && ttv && needsClone) { @@ -5574,17 +5573,17 @@ TypeId TypeChecker::instantiateTypeFun(const ScopePtr& scope, const TypeFun& tf, // want to mutate its table, so we need to explicitly clone that table as // well. If we don't, we will mutate another module's type surface and cause // a use-after-free. - if (get(target)) + if (get(target)) { instantiated = applyTypeFunction.clone(tf.type); - MetatableTypeVar* mtv = getMutable(instantiated); + MetatableType* mtv = getMutable(instantiated); mtv->table = applyTypeFunction.clone(mtv->table); - ttv = getMutable(mtv->table); + ttv = getMutable(mtv->table); } - if (get(target)) + if (get(target)) { instantiated = applyTypeFunction.clone(tf.type); - ttv = getMutable(instantiated); + ttv = getMutable(instantiated); } } @@ -5617,7 +5616,7 @@ GenericTypeDefinitions TypeChecker::createGenericTypes(const ScopePtr& scope, st Name n = generic.name.value; // These generics are the only thing that will ever be added to scope, so we can be certain that - // a collision can only occur when two generic typevars have the same name. + // a collision can only occur when two generic types have the same name. if (scope->privateTypeBindings.count(n) || scope->privateTypePackBindings.count(n)) { // TODO(jhuelsman): report the exact span of the generic type parameter whose name is a duplicate. @@ -5629,7 +5628,7 @@ GenericTypeDefinitions TypeChecker::createGenericTypes(const ScopePtr& scope, st { TypeId& cached = scope->parent->typeAliasTypeParameters[n]; if (!cached) - cached = addType(GenericTypeVar{level, n}); + cached = addType(GenericType{level, n}); g = cached; } else @@ -5653,7 +5652,7 @@ GenericTypeDefinitions TypeChecker::createGenericTypes(const ScopePtr& scope, st Name n = genericPack.name.value; // These generics are the only thing that will ever be added to scope, so we can be certain that - // a collision can only occur when two generic typevars have the same name. + // a collision can only occur when two generic types have the same name. if (scope->privateTypePackBindings.count(n) || scope->privateTypeBindings.count(n)) { // TODO(jhuelsman): report the exact span of the generic type parameter whose name is a duplicate. @@ -5685,7 +5684,7 @@ void TypeChecker::refineLValue(const LValue& lvalue, RefinementMap& refis, const if (auto base = baseof(lvalue)) { std::optional baseTy = resolveLValue(scope, *base); - if (baseTy && get(follow(*baseTy))) + if (baseTy && get(follow(*baseTy))) { ty = baseTy; target = base; @@ -5713,7 +5712,7 @@ void TypeChecker::refineLValue(const LValue& lvalue, RefinementMap& refis, const } // Otherwise, we'll want to walk each option of ty, get its index type, and filter that. - auto utv = get(follow(*ty)); + auto utv = get(follow(*ty)); LUAU_ASSERT(utv); std::unordered_set viableTargetOptions; @@ -5733,7 +5732,7 @@ void TypeChecker::refineLValue(const LValue& lvalue, RefinementMap& refis, const auto [result, ok] = filterMap(*discriminantTy, predicate); if (FFlag::LuauUnknownAndNeverType) { - if (!get(*result)) + if (!get(*result)) { viableTargetOptions.insert(option); viableChildOptions.insert(*result); @@ -5753,12 +5752,12 @@ void TypeChecker::refineLValue(const LValue& lvalue, RefinementMap& refis, const if (s.empty()) return std::nullopt; - // TODO: allocate UnionTypeVar and just normalize. + // TODO: allocate UnionType and just normalize. std::vector options(s.begin(), s.end()); if (options.size() == 1) return options[0]; - return addType(UnionTypeVar{std::move(options)}); + return addType(UnionType{std::move(options)}); }; if (std::optional viableTargetType = intoType(viableTargetOptions)) @@ -5852,7 +5851,7 @@ std::optional TypeChecker::resolveLValue(const RefinementMap& refis, con static bool isUndecidable(TypeId ty) { ty = follow(ty); - return get(ty) || get(ty) || get(ty); + return get(ty) || get(ty) || get(ty); } void TypeChecker::resolve(const PredicateVec& predicates, const ScopePtr& scope, bool sense) @@ -5964,7 +5963,7 @@ void TypeChecker::resolve(const IsAPredicate& isaP, RefinementMap& refis, const // So we can just return the right hand side immediately. // typeof(x) == "Instance" where x : any - auto ttv = get(option); + auto ttv = get(option); if (isUndecidable(option) || (ttv && ttv->state == TableState::Free)) return sense ? isaP.ty : option; @@ -6001,7 +6000,7 @@ void TypeChecker::resolve(const TypeGuardPredicate& typeguardP, RefinementMap& r auto refine = [this, &lvalue = typeguardP.lvalue, &refis, &scope, sense](bool(f)(TypeId), std::optional mapsTo = std::nullopt) { TypeIdPredicate predicate = [f, mapsTo, sense](TypeId ty) -> std::optional { - if (FFlag::LuauUnknownAndNeverType && sense && get(ty)) + if (FFlag::LuauUnknownAndNeverType && sense && get(ty)) return mapsTo.value_or(ty); if (f(ty) == sense) @@ -6030,20 +6029,20 @@ void TypeChecker::resolve(const TypeGuardPredicate& typeguardP, RefinementMap& r else if (typeguardP.kind == "table") { return refine([](TypeId ty) -> bool { - return isTableIntersection(ty) || get(ty) || get(ty); + return isTableIntersection(ty) || get(ty) || get(ty); }); } else if (typeguardP.kind == "function") { return refine([](TypeId ty) -> bool { - return isOverloadedFunction(ty) || get(ty); + return isOverloadedFunction(ty) || get(ty); }); } else if (typeguardP.kind == "userdata") { // For now, we don't really care about being accurate with userdata if the typeguard was using typeof. return refine([](TypeId ty) -> bool { - return get(ty); + return get(ty); }); } @@ -6056,8 +6055,18 @@ void TypeChecker::resolve(const TypeGuardPredicate& typeguardP, RefinementMap& r TypeId type = follow(typeFun->type); + // You cannot refine to the top class type. + if (FFlag::LuauNegatedClassTypes) + { + if (type == builtinTypes->classType) + { + return addRefinement(refis, typeguardP.lvalue, errorRecoveryType(scope)); + } + } + // We're only interested in the root class of any classes. - if (auto ctv = get(type); !ctv || ctv->parent) + if (auto ctv = get(type); + !ctv || (FFlag::LuauNegatedClassTypes ? (ctv->parent != builtinTypes->classType) : (ctv->parent != std::nullopt))) return addRefinement(refis, typeguardP.lvalue, errorRecoveryType(scope)); // This probably hints at breaking out type filtering functions from the predicate solver so that typeof is not tightly coupled with IsA. @@ -6069,7 +6078,7 @@ void TypeChecker::resolve(const EqPredicate& eqP, RefinementMap& refis, const Sc { // This refinement will require success typing to do everything correctly. For now, we can get most of the way there. auto options = [](TypeId ty) -> std::vector { - if (auto utv = get(follow(ty))) + if (auto utv = get(follow(ty))) return std::vector(begin(utv), end(utv)); return {ty}; }; @@ -6120,7 +6129,7 @@ void TypeChecker::resolve(const EqPredicate& eqP, RefinementMap& refis, const Sc } else { - bool isOptionSingleton = get(option); + bool isOptionSingleton = get(option); if (!isOptionSingleton) return option; else if (optionIsSubtype && targetIsSubtype) diff --git a/Analysis/src/TypePack.cpp b/Analysis/src/TypePack.cpp index 0f75c3ef..e41bf2fe 100644 --- a/Analysis/src/TypePack.cpp +++ b/Analysis/src/TypePack.cpp @@ -237,7 +237,7 @@ TypePackId follow(TypePackId tp, std::function mapper) cycleTester = nullptr; if (tp == cycleTester) - throw InternalCompilerError("Luau::follow detected a TypeVar cycle!!"); + throw InternalCompilerError("Luau::follow detected a Type cycle!!"); } } } @@ -381,14 +381,14 @@ bool containsNever(TypePackId tp) while (it != endIt) { - if (get(follow(*it))) + if (get(follow(*it))) return true; ++it; } if (auto tail = it.tail()) { - if (auto vtp = get(*tail); vtp && get(follow(vtp->ty))) + if (auto vtp = get(*tail); vtp && get(follow(vtp->ty))) return true; } diff --git a/Analysis/src/TypeUtils.cpp b/Analysis/src/TypeUtils.cpp index 7478ac22..f8f51bcf 100644 --- a/Analysis/src/TypeUtils.cpp +++ b/Analysis/src/TypeUtils.cpp @@ -12,20 +12,20 @@ namespace Luau { std::optional findMetatableEntry( - NotNull singletonTypes, ErrorVec& errors, TypeId type, const std::string& entry, Location location) + NotNull builtinTypes, ErrorVec& errors, TypeId type, const std::string& entry, Location location) { type = follow(type); - std::optional metatable = getMetatable(type, singletonTypes); + std::optional metatable = getMetatable(type, builtinTypes); if (!metatable) return std::nullopt; TypeId unwrapped = follow(*metatable); - if (get(unwrapped)) - return singletonTypes->anyType; + if (get(unwrapped)) + return builtinTypes->anyType; - const TableTypeVar* mtt = getTableType(unwrapped); + const TableType* mtt = getTableType(unwrapped); if (!mtt) { errors.push_back(TypeError{location, GenericError{"Metatable was not a table"}}); @@ -40,19 +40,19 @@ std::optional findMetatableEntry( } std::optional findTablePropertyRespectingMeta( - NotNull singletonTypes, ErrorVec& errors, TypeId ty, const std::string& name, Location location) + NotNull builtinTypes, ErrorVec& errors, TypeId ty, const std::string& name, Location location) { - if (get(ty)) + if (get(ty)) return ty; - if (const TableTypeVar* tableType = getTableType(ty)) + if (const TableType* tableType = getTableType(ty)) { const auto& it = tableType->props.find(name); if (it != tableType->props.end()) return it->second.type; } - std::optional mtIndex = findMetatableEntry(singletonTypes, errors, ty, "__index", location); + std::optional mtIndex = findMetatableEntry(builtinTypes, errors, ty, "__index", location); int count = 0; while (mtIndex) { @@ -69,20 +69,20 @@ std::optional findTablePropertyRespectingMeta( if (fit != itt->props.end()) return fit->second.type; } - else if (const auto& itf = get(index)) + else if (const auto& itf = get(index)) { std::optional r = first(follow(itf->retTypes)); if (!r) - return singletonTypes->nilType; + return builtinTypes->nilType; else return *r; } - else if (get(index)) - return singletonTypes->anyType; + else if (get(index)) + return builtinTypes->anyType; else errors.push_back(TypeError{location, GenericError{"__index should either be a function or table. Got " + toString(index)}}); - mtIndex = findMetatableEntry(singletonTypes, errors, *mtIndex, "__index", location); + mtIndex = findMetatableEntry(builtinTypes, errors, *mtIndex, "__index", location); } return std::nullopt; @@ -117,7 +117,7 @@ std::pair> getParameterExtents(const TxnLog* log, return {minCount, minCount + optionalCount}; } -TypePack extendTypePack(TypeArena& arena, NotNull singletonTypes, TypePackId pack, size_t length) +TypePack extendTypePack(TypeArena& arena, NotNull builtinTypes, TypePackId pack, size_t length) { TypePack result; @@ -193,7 +193,7 @@ TypePack extendTypePack(TypeArena& arena, NotNull singletonTypes else if (const Unifiable::Error* etp = getMutable(pack)) { while (result.head.size() < length) - result.head.push_back(singletonTypes->errorRecoveryType()); + result.head.push_back(builtinTypes->errorRecoveryType()); result.tail = pack; return result; @@ -214,20 +214,20 @@ std::vector reduceUnion(const std::vector& types) for (TypeId t : types) { t = follow(t); - if (get(t)) + if (get(t)) continue; - if (get(t) || get(t)) + if (get(t) || get(t)) return {t}; - if (const UnionTypeVar* utv = get(t)) + if (const UnionType* utv = get(t)) { for (TypeId ty : utv) { ty = follow(ty); - if (get(ty)) + if (get(ty)) continue; - if (get(ty) || get(ty)) + if (get(ty) || get(ty)) return {ty}; if (result.end() == std::find(result.begin(), result.end(), ty)) @@ -243,7 +243,7 @@ std::vector reduceUnion(const std::vector& types) static std::optional tryStripUnionFromNil(TypeArena& arena, TypeId ty) { - if (const UnionTypeVar* utv = get(ty)) + if (const UnionType* utv = get(ty)) { if (!std::any_of(begin(utv), end(utv), isNil)) return ty; @@ -259,23 +259,23 @@ static std::optional tryStripUnionFromNil(TypeArena& arena, TypeId ty) if (result.empty()) return std::nullopt; - return result.size() == 1 ? result[0] : arena.addType(UnionTypeVar{std::move(result)}); + return result.size() == 1 ? result[0] : arena.addType(UnionType{std::move(result)}); } return std::nullopt; } -TypeId stripNil(NotNull singletonTypes, TypeArena& arena, TypeId ty) +TypeId stripNil(NotNull builtinTypes, TypeArena& arena, TypeId ty) { ty = follow(ty); - if (get(ty)) + if (get(ty)) { std::optional cleaned = tryStripUnionFromNil(arena, ty); // If there is no union option without 'nil' if (!cleaned) - return singletonTypes->nilType; + return builtinTypes->nilType; return follow(*cleaned); } diff --git a/Analysis/src/Unifier.cpp b/Analysis/src/Unifier.cpp index 42882005..d35e3771 100644 --- a/Analysis/src/Unifier.cpp +++ b/Analysis/src/Unifier.cpp @@ -10,8 +10,8 @@ #include "Luau/ToString.h" #include "Luau/TypePack.h" #include "Luau/TypeUtils.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" #include @@ -29,11 +29,12 @@ LUAU_FASTFLAG(LuauClassTypeVarsInSubstitution) LUAU_FASTFLAG(LuauTxnLogTypePackIterator) LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) LUAU_FASTFLAG(LuauNegatedFunctionTypes) +LUAU_FASTFLAG(LuauNegatedClassTypes) namespace Luau { -struct PromoteTypeLevels final : TypeVarOnceVisitor +struct PromoteTypeLevels final : TypeOnceVisitor { TxnLog& log; const TypeArena* typeArena = nullptr; @@ -91,18 +92,18 @@ struct PromoteTypeLevels final : TypeVarOnceVisitor return true; } - bool visit(TypeId ty, const FreeTypeVar&) override + bool visit(TypeId ty, const FreeType&) override { - // Surprise, it's actually a BoundTypeVar that hasn't been committed yet. + // Surprise, it's actually a BoundType that hasn't been committed yet. // Calling getMutable on this will trigger an assertion. - if (!log.is(ty)) + if (!log.is(ty)) return true; - promote(ty, log.getMutable(ty)); + promote(ty, log.getMutable(ty)); return true; } - bool visit(TypeId ty, const FunctionTypeVar&) override + bool visit(TypeId ty, const FunctionType&) override { // Type levels of types from other modules are already global, so we don't need to promote anything inside if (ty->owningArena != typeArena) @@ -110,14 +111,14 @@ struct PromoteTypeLevels final : TypeVarOnceVisitor // Surprise, it's actually a BoundTypePack that hasn't been committed yet. // Calling getMutable on this will trigger an assertion. - if (FFlag::LuauScalarShapeUnifyToMtOwner2 && !log.is(ty)) + if (FFlag::LuauScalarShapeUnifyToMtOwner2 && !log.is(ty)) return true; - promote(ty, log.getMutable(ty)); + promote(ty, log.getMutable(ty)); return true; } - bool visit(TypeId ty, const TableTypeVar& ttv) override + bool visit(TypeId ty, const TableType& ttv) override { // Type levels of types from other modules are already global, so we don't need to promote anything inside if (ty->owningArena != typeArena) @@ -128,10 +129,10 @@ struct PromoteTypeLevels final : TypeVarOnceVisitor // Surprise, it's actually a BoundTypePack that hasn't been committed yet. // Calling getMutable on this will trigger an assertion. - if (FFlag::LuauScalarShapeUnifyToMtOwner2 && !log.is(ty)) + if (FFlag::LuauScalarShapeUnifyToMtOwner2 && !log.is(ty)) return true; - promote(ty, log.getMutable(ty)); + promote(ty, log.getMutable(ty)); return true; } @@ -167,7 +168,7 @@ void promoteTypeLevels(TxnLog& log, const TypeArena* typeArena, TypeLevel minLev ptl.traverse(tp); } -struct SkipCacheForType final : TypeVarOnceVisitor +struct SkipCacheForType final : TypeOnceVisitor { SkipCacheForType(const DenseHashMap& skipCacheForType, const TypeArena* typeArena) : skipCacheForType(skipCacheForType) @@ -175,31 +176,31 @@ struct SkipCacheForType final : TypeVarOnceVisitor { } - bool visit(TypeId, const FreeTypeVar&) override + bool visit(TypeId, const FreeType&) override { result = true; return false; } - bool visit(TypeId, const BoundTypeVar&) override + bool visit(TypeId, const BoundType&) override { result = true; return false; } - bool visit(TypeId, const GenericTypeVar&) override + bool visit(TypeId, const GenericType&) override { result = true; return false; } - bool visit(TypeId ty, const TableTypeVar&) override + bool visit(TypeId ty, const TableType&) override { // Types from other modules don't contain mutable elements and are ok to cache if (ty->owningArena != typeArena) return false; - TableTypeVar& ttv = *getMutable(ty); + TableType& ttv = *getMutable(ty); if (ttv.boundTo) { @@ -267,7 +268,7 @@ struct SkipCacheForType final : TypeVarOnceVisitor bool Widen::isDirty(TypeId ty) { - return log->is(ty); + return log->is(ty); } bool Widen::isDirty(TypePackId) @@ -278,16 +279,16 @@ bool Widen::isDirty(TypePackId) TypeId Widen::clean(TypeId ty) { LUAU_ASSERT(isDirty(ty)); - auto stv = log->getMutable(ty); + auto stv = log->getMutable(ty); LUAU_ASSERT(stv); if (get(stv)) - return singletonTypes->stringType; + return builtinTypes->stringType; else { // If this assert trips, it's likely we now have number singletons. LUAU_ASSERT(get(stv)); - return singletonTypes->booleanType; + return builtinTypes->booleanType; } } @@ -298,10 +299,10 @@ TypePackId Widen::clean(TypePackId) bool Widen::ignoreChildren(TypeId ty) { - if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) + if (FFlag::LuauClassTypeVarsInSubstitution && get(ty)) return true; - return !log->is(ty); + return !log->is(ty); } TypeId Widen::operator()(TypeId ty) @@ -328,13 +329,13 @@ static std::optional hasUnificationTooComplex(const ErrorVec& errors) } // Used for tagged union matching heuristic, returns first singleton type field -static std::optional> getTableMatchTag(TypeId type) +static std::optional> getTableMatchTag(TypeId type) { if (auto ttv = getTableType(type)) { for (auto&& [name, prop] : ttv->props) { - if (auto sing = get(follow(prop.type))) + if (auto sing = get(follow(prop.type))) return {{name, sing}}; } } @@ -368,7 +369,7 @@ TypeMismatch::Context Unifier::mismatchContext() Unifier::Unifier(NotNull normalizer, Mode mode, NotNull scope, const Location& location, Variance variance, TxnLog* parentLog) : types(normalizer->arena) - , singletonTypes(normalizer->singletonTypes) + , builtinTypes(normalizer->builtinTypes) , normalizer(normalizer) , mode(mode) , scope(scope) @@ -406,13 +407,13 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool if (superTy == subTy) return; - auto superFree = log.getMutable(superTy); - auto subFree = log.getMutable(subTy); + auto superFree = log.getMutable(superTy); + auto subFree = log.getMutable(subTy); if (superFree && subFree && subsumes(useScopes, superFree, subFree)) { if (!occursCheck(subTy, superTy)) - log.replace(subTy, BoundTypeVar(superTy)); + log.replace(subTy, BoundType(superTy)); return; } @@ -425,7 +426,7 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool log.changeLevel(subTy, superFree->level); } - log.replace(superTy, BoundTypeVar(subTy)); + log.replace(superTy, BoundType(subTy)); } return; @@ -433,7 +434,7 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool else if (superFree) { // Unification can't change the level of a generic. - auto subGeneric = log.getMutable(subTy); + auto subGeneric = log.getMutable(subTy); if (subGeneric && !subsumes(useScopes, subGeneric, superFree)) { // TODO: a more informative error message? CLI-39912 @@ -445,8 +446,8 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool { promoteTypeLevels(log, types, superFree->level, superFree->scope, useScopes, subTy); - Widen widen{types, singletonTypes}; - log.replace(superTy, BoundTypeVar(widen(subTy))); + Widen widen{types, builtinTypes}; + log.replace(superTy, BoundType(widen(subTy))); } return; @@ -457,12 +458,12 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool { // Normally, if the subtype is free, it should not be bound to any, unknown, or error types. // But for bug compatibility, we'll only apply this rule to unknown. Doing this will silence cascading type errors. - if (log.get(superTy)) + if (log.get(superTy)) return; } // Unification can't change the level of a generic. - auto superGeneric = log.getMutable(superTy); + auto superGeneric = log.getMutable(superTy); if (superGeneric && !subsumes(useScopes, superGeneric, subFree)) { // TODO: a more informative error message? CLI-39912 @@ -473,22 +474,22 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool if (!occursCheck(subTy, superTy)) { promoteTypeLevels(log, types, subFree->level, subFree->scope, useScopes, superTy); - log.replace(subTy, BoundTypeVar(superTy)); + log.replace(subTy, BoundType(superTy)); } return; } - if (get(superTy) || get(superTy) || get(superTy)) + if (get(superTy) || get(superTy) || get(superTy)) return tryUnifyWithAny(subTy, superTy); - if (get(subTy)) + if (get(subTy)) return tryUnifyWithAny(superTy, subTy); - if (log.get(subTy)) + if (log.get(subTy)) return tryUnifyWithAny(superTy, subTy); - if (log.get(subTy)) + if (log.get(subTy)) return tryUnifyWithAny(superTy, subTy); auto& cache = sharedState.cachedUnify; @@ -519,78 +520,77 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool size_t errorCount = errors.size(); - if (const UnionTypeVar* subUnion = log.getMutable(subTy)) + if (const UnionType* subUnion = log.getMutable(subTy)) { tryUnifyUnionWithType(subTy, subUnion, superTy); } - else if (const UnionTypeVar* uv = (FFlag::LuauSubtypeNormalizer ? nullptr : log.getMutable(superTy))) + else if (const UnionType* uv = (FFlag::LuauSubtypeNormalizer ? nullptr : log.getMutable(superTy))) { tryUnifyTypeWithUnion(subTy, superTy, uv, cacheEnabled, isFunctionCall); } - else if (const IntersectionTypeVar* uv = log.getMutable(superTy)) + else if (const IntersectionType* uv = log.getMutable(superTy)) { tryUnifyTypeWithIntersection(subTy, superTy, uv); } - else if (const UnionTypeVar* uv = log.getMutable(superTy)) + else if (const UnionType* uv = log.getMutable(superTy)) { tryUnifyTypeWithUnion(subTy, superTy, uv, cacheEnabled, isFunctionCall); } - else if (const IntersectionTypeVar* uv = log.getMutable(subTy)) + else if (const IntersectionType* uv = log.getMutable(subTy)) { tryUnifyIntersectionWithType(subTy, uv, superTy, cacheEnabled, isFunctionCall); } - else if (log.getMutable(superTy) && log.getMutable(subTy)) + else if (log.getMutable(superTy) && log.getMutable(subTy)) tryUnifyPrimitives(subTy, superTy); - else if ((log.getMutable(superTy) || log.getMutable(superTy)) && log.getMutable(subTy)) + else if ((log.getMutable(superTy) || log.getMutable(superTy)) && log.getMutable(subTy)) tryUnifySingletons(subTy, superTy); - else if (auto ptv = get(superTy); - FFlag::LuauNegatedFunctionTypes && ptv && ptv->type == PrimitiveTypeVar::Function && get(subTy)) + else if (auto ptv = get(superTy); + FFlag::LuauNegatedFunctionTypes && ptv && ptv->type == PrimitiveType::Function && get(subTy)) { // Ok. Do nothing. forall functions F, F <: function } - else if (log.getMutable(superTy) && log.getMutable(subTy)) + else if (log.getMutable(superTy) && log.getMutable(subTy)) tryUnifyFunctions(subTy, superTy, isFunctionCall); - else if (log.getMutable(superTy) && log.getMutable(subTy)) + else if (log.getMutable(superTy) && log.getMutable(subTy)) { tryUnifyTables(subTy, superTy, isIntersection); } - else if (FFlag::LuauScalarShapeSubtyping && log.get(superTy) && - (log.get(subTy) || log.get(subTy))) + else if (FFlag::LuauScalarShapeSubtyping && log.get(superTy) && (log.get(subTy) || log.get(subTy))) { tryUnifyScalarShape(subTy, superTy, /*reversed*/ false); } - else if (FFlag::LuauScalarShapeSubtyping && log.get(subTy) && - (log.get(superTy) || log.get(superTy))) + else if (FFlag::LuauScalarShapeSubtyping && log.get(subTy) && (log.get(superTy) || log.get(superTy))) { tryUnifyScalarShape(subTy, superTy, /*reversed*/ true); } - // tryUnifyWithMetatable assumes its first argument is a MetatableTypeVar. The check is otherwise symmetrical. - else if (log.getMutable(superTy)) + // tryUnifyWithMetatable assumes its first argument is a MetatableType. The check is otherwise symmetrical. + else if (log.getMutable(superTy)) tryUnifyWithMetatable(subTy, superTy, /*reversed*/ false); - else if (log.getMutable(subTy)) + else if (log.getMutable(subTy)) tryUnifyWithMetatable(superTy, subTy, /*reversed*/ true); - else if (log.getMutable(superTy)) + else if (log.getMutable(superTy)) tryUnifyWithClass(subTy, superTy, /*reversed*/ false); // Unification of nonclasses with classes is almost, but not quite symmetrical. // The order in which we perform this test is significant in the case that both types are classes. - else if (log.getMutable(subTy)) + else if (log.getMutable(subTy)) tryUnifyWithClass(subTy, superTy, /*reversed*/ true); - else if (log.get(superTy)) + else if (log.get(superTy)) tryUnifyTypeWithNegation(subTy, superTy); - else if (log.get(subTy)) + else if (log.get(subTy)) tryUnifyNegationWithType(subTy, superTy); else if (FFlag::LuauUninhabitedSubAnything2 && !normalizer->isInhabited(subTy)) - {} + { + } else reportError(location, TypeMismatch{superTy, subTy, mismatchContext()}); @@ -601,7 +601,7 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool log.popSeen(superTy, subTy); } -void Unifier::tryUnifyUnionWithType(TypeId subTy, const UnionTypeVar* subUnion, TypeId superTy) +void Unifier::tryUnifyUnionWithType(TypeId subTy, const UnionType* subUnion, TypeId superTy) { // A | B <: T if and only if A <: T and B <: T bool failed = false; @@ -639,13 +639,13 @@ void Unifier::tryUnifyUnionWithType(TypeId subTy, const UnionTypeVar* subUnion, superOption = log.follow(superOption); // just skip if the superOption is not free-ish. - auto ttv = log.getMutable(superOption); - if (!log.is(superOption) && (!ttv || ttv->state != TableState::Free)) + auto ttv = log.getMutable(superOption); + if (!log.is(superOption) && (!ttv || ttv->state != TableState::Free)) return; // If superOption is already present in subTy, do nothing. Nothing new has been learned, but the subtype // test is successful. - if (auto subUnion = get(subTy)) + if (auto subUnion = get(subTy)) { if (end(subUnion) != std::find(begin(subUnion), end(subUnion), superOption)) return; @@ -656,14 +656,14 @@ void Unifier::tryUnifyUnionWithType(TypeId subTy, const UnionTypeVar* subUnion, if (log.haveSeen(subTy, superOption)) { // TODO: would it be nice for TxnLog::replace to do this? - if (log.is(superOption)) + if (log.is(superOption)) log.bindTable(superOption, subTy); else log.replace(superOption, *subTy); } }; - if (auto superUnion = log.getMutable(superTy)) + if (auto superUnion = log.getMutable(superTy)) { for (TypeId ty : superUnion) tryBind(ty); @@ -683,7 +683,7 @@ void Unifier::tryUnifyUnionWithType(TypeId subTy, const UnionTypeVar* subUnion, } } -void Unifier::tryUnifyTypeWithUnion(TypeId subTy, TypeId superTy, const UnionTypeVar* uv, bool cacheEnabled, bool isFunctionCall) +void Unifier::tryUnifyTypeWithUnion(TypeId subTy, TypeId superTy, const UnionType* uv, bool cacheEnabled, bool isFunctionCall) { // T <: A | B if T <: A or T <: B bool found = false; @@ -803,7 +803,7 @@ void Unifier::tryUnifyTypeWithUnion(TypeId subTy, TypeId superTy, const UnionTyp } } -void Unifier::tryUnifyTypeWithIntersection(TypeId subTy, TypeId superTy, const IntersectionTypeVar* uv) +void Unifier::tryUnifyTypeWithIntersection(TypeId subTy, TypeId superTy, const IntersectionType* uv) { std::optional unificationTooComplex; std::optional firstFailedOption; @@ -839,7 +839,7 @@ void Unifier::tryUnifyTypeWithIntersection(TypeId subTy, TypeId superTy, const I reportError(location, TypeMismatch{superTy, subTy, "Not all intersection parts are compatible.", *firstFailedOption, mismatchContext()}); } -void Unifier::tryUnifyIntersectionWithType(TypeId subTy, const IntersectionTypeVar* uv, TypeId superTy, bool cacheEnabled, bool isFunctionCall) +void Unifier::tryUnifyIntersectionWithType(TypeId subTy, const IntersectionType* uv, TypeId superTy, bool cacheEnabled, bool isFunctionCall) { // A & B <: T if A <: T or B <: T bool found = false; @@ -917,56 +917,99 @@ void Unifier::tryUnifyNormalizedTypes( { LUAU_ASSERT(FFlag::LuauSubtypeNormalizer); - if (get(superNorm.tops) || get(superNorm.tops) || get(subNorm.tops)) + if (get(superNorm.tops) || get(superNorm.tops) || get(subNorm.tops)) return; - else if (get(subNorm.tops)) + else if (get(subNorm.tops)) return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()}); - if (get(subNorm.errors)) - if (!get(superNorm.errors)) + if (get(subNorm.errors)) + if (!get(superNorm.errors)) return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()}); - if (get(subNorm.booleans)) + if (get(subNorm.booleans)) { - if (!get(superNorm.booleans)) + if (!get(superNorm.booleans)) return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()}); } - else if (const SingletonTypeVar* stv = get(subNorm.booleans)) + else if (const SingletonType* stv = get(subNorm.booleans)) { - if (!get(superNorm.booleans) && stv != get(superNorm.booleans)) + if (!get(superNorm.booleans) && stv != get(superNorm.booleans)) return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()}); } - if (get(subNorm.nils)) - if (!get(superNorm.nils)) + if (get(subNorm.nils)) + if (!get(superNorm.nils)) return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()}); - if (get(subNorm.numbers)) - if (!get(superNorm.numbers)) + if (get(subNorm.numbers)) + if (!get(superNorm.numbers)) return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()}); if (!isSubtype(subNorm.strings, superNorm.strings)) return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()}); - if (get(subNorm.threads)) - if (!get(superNorm.errors)) + if (get(subNorm.threads)) + if (!get(superNorm.errors)) return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()}); - for (TypeId subClass : subNorm.classes) + if (FFlag::LuauNegatedClassTypes) { - bool found = false; - const ClassTypeVar* subCtv = get(subClass); - for (TypeId superClass : superNorm.classes) + for (const auto& [subClass, _] : subNorm.classes.classes) { - const ClassTypeVar* superCtv = get(superClass); - if (isSubclass(subCtv, superCtv)) + bool found = false; + const ClassType* subCtv = get(subClass); + LUAU_ASSERT(subCtv); + + for (const auto& [superClass, superNegations] : superNorm.classes.classes) { - found = true; - break; + const ClassType* superCtv = get(superClass); + LUAU_ASSERT(superCtv); + + if (isSubclass(subCtv, superCtv)) + { + found = true; + + for (TypeId negation : superNegations) + { + const ClassType* negationCtv = get(negation); + LUAU_ASSERT(negationCtv); + + if (isSubclass(subCtv, negationCtv)) + { + found = false; + break; + } + } + + if (found) + break; + } + } + + if (!found) + { + return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()}); } } - if (!found) - return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()}); + } + else + { + for (TypeId subClass : subNorm.DEPRECATED_classes) + { + bool found = false; + const ClassType* subCtv = get(subClass); + for (TypeId superClass : superNorm.DEPRECATED_classes) + { + const ClassType* superCtv = get(superClass); + if (isSubclass(subCtv, superCtv)) + { + found = true; + break; + } + } + if (!found) + return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()}); + } } for (TypeId subTable : subNorm.tables) @@ -975,9 +1018,9 @@ void Unifier::tryUnifyNormalizedTypes( for (TypeId superTable : superNorm.tables) { Unifier innerState = makeChildUnifier(); - if (get(superTable)) + if (get(superTable)) innerState.tryUnifyWithMetatable(subTable, superTable, /* reversed */ false); - else if (get(subTable)) + else if (get(subTable)) innerState.tryUnifyWithMetatable(superTable, subTable, /* reversed */ true); else innerState.tryUnifyTables(subTable, superTable); @@ -1001,7 +1044,7 @@ void Unifier::tryUnifyNormalizedTypes( for (TypeId superFun : *superNorm.functions.parts) { Unifier innerState = makeChildUnifier(); - const FunctionTypeVar* superFtv = get(superFun); + const FunctionType* superFtv = get(superFun); if (!superFtv) return reportError(location, TypeMismatch{superTy, subTy, reason, error, mismatchContext()}); TypePackId tgt = innerState.tryApplyOverloadedFunction(subTy, subNorm.functions, superFtv->argTypes); @@ -1032,14 +1075,14 @@ TypePackId Unifier::tryApplyOverloadedFunction(TypeId function, const Normalized if (overloads.isNever()) { reportError(location, CannotCallNonFunction{function}); - return singletonTypes->errorRecoveryTypePack(); + return builtinTypes->errorRecoveryTypePack(); } std::optional result; - const FunctionTypeVar* firstFun = nullptr; + const FunctionType* firstFun = nullptr; for (TypeId overload : *overloads.parts) { - if (const FunctionTypeVar* ftv = get(overload)) + if (const FunctionType* ftv = get(overload)) { // TODO: instantiate generics? if (ftv->generics.empty() && ftv->genericPacks.empty()) @@ -1072,7 +1115,7 @@ TypePackId Unifier::tryApplyOverloadedFunction(TypeId function, const Normalized else if (auto e = hasUnificationTooComplex(innerState.errors)) { reportError(*e); - return singletonTypes->errorRecoveryTypePack(args); + return builtinTypes->errorRecoveryTypePack(args); } } } @@ -1086,12 +1129,12 @@ TypePackId Unifier::tryApplyOverloadedFunction(TypeId function, const Normalized // The logic for error reporting overload resolution // is currently over in TypeInfer.cpp, should we move it? reportError(location, GenericError{"No matching overload."}); - return singletonTypes->errorRecoveryTypePack(firstFun->retTypes); + return builtinTypes->errorRecoveryTypePack(firstFun->retTypes); } else { reportError(location, CannotCallNonFunction{function}); - return singletonTypes->errorRecoveryTypePack(); + return builtinTypes->errorRecoveryTypePack(); } } @@ -1302,7 +1345,7 @@ void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCal { if (!occursCheck(superTp, subTp)) { - Widen widen{types, singletonTypes}; + Widen widen{types, builtinTypes}; log.replace(superTp, Unifiable::Bound(widen(subTp))); } } @@ -1463,13 +1506,13 @@ void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCal while (superIter.good()) { - tryUnify_(*superIter, singletonTypes->errorRecoveryType()); + tryUnify_(*superIter, builtinTypes->errorRecoveryType()); superIter.advance(); } while (subIter.good()) { - tryUnify_(*subIter, singletonTypes->errorRecoveryType()); + tryUnify_(*subIter, builtinTypes->errorRecoveryType()); subIter.advance(); } @@ -1489,8 +1532,8 @@ void Unifier::tryUnify_(TypePackId subTp, TypePackId superTp, bool isFunctionCal void Unifier::tryUnifyPrimitives(TypeId subTy, TypeId superTy) { - const PrimitiveTypeVar* superPrim = get(superTy); - const PrimitiveTypeVar* subPrim = get(subTy); + const PrimitiveType* superPrim = get(superTy); + const PrimitiveType* subPrim = get(subTy); if (!superPrim || !subPrim) ice("passed non primitive types to unifyPrimitives"); @@ -1500,9 +1543,9 @@ void Unifier::tryUnifyPrimitives(TypeId subTy, TypeId superTy) void Unifier::tryUnifySingletons(TypeId subTy, TypeId superTy) { - const PrimitiveTypeVar* superPrim = get(superTy); - const SingletonTypeVar* superSingleton = get(superTy); - const SingletonTypeVar* subSingleton = get(subTy); + const PrimitiveType* superPrim = get(superTy); + const SingletonType* superSingleton = get(superTy); + const SingletonType* subSingleton = get(subTy); if ((!superPrim && !superSingleton) || !subSingleton) ice("passed non singleton/primitive types to unifySingletons"); @@ -1510,10 +1553,10 @@ void Unifier::tryUnifySingletons(TypeId subTy, TypeId superTy) if (superSingleton && *superSingleton == *subSingleton) return; - if (superPrim && superPrim->type == PrimitiveTypeVar::Boolean && get(subSingleton) && variance == Covariant) + if (superPrim && superPrim->type == PrimitiveType::Boolean && get(subSingleton) && variance == Covariant) return; - if (superPrim && superPrim->type == PrimitiveTypeVar::String && get(subSingleton) && variance == Covariant) + if (superPrim && superPrim->type == PrimitiveType::String && get(subSingleton) && variance == Covariant) return; reportError(location, TypeMismatch{superTy, subTy, mismatchContext()}); @@ -1521,8 +1564,8 @@ void Unifier::tryUnifySingletons(TypeId subTy, TypeId superTy) void Unifier::tryUnifyFunctions(TypeId subTy, TypeId superTy, bool isFunctionCall) { - FunctionTypeVar* superFunction = log.getMutable(superTy); - FunctionTypeVar* subFunction = log.getMutable(subTy); + FunctionType* superFunction = log.getMutable(superTy); + FunctionType* subFunction = log.getMutable(subTy); if (!superFunction || !subFunction) ice("passed non-function types to unifyFunction"); @@ -1542,7 +1585,7 @@ void Unifier::tryUnifyFunctions(TypeId subTy, TypeId superTy, bool isFunctionCal std::optional instantiated = instantiation.substitute(subTy); if (instantiated.has_value()) { - subFunction = log.getMutable(*instantiated); + subFunction = log.getMutable(*instantiated); if (!subFunction) ice("instantiation made a function type into a non-function type in unifyFunction"); @@ -1626,8 +1669,8 @@ void Unifier::tryUnifyFunctions(TypeId subTy, TypeId superTy, bool isFunctionCal } // Updating the log may have invalidated the function pointers - superFunction = log.getMutable(superTy); - subFunction = log.getMutable(subTy); + superFunction = log.getMutable(superTy); + subFunction = log.getMutable(subTy); ctx = context; @@ -1666,9 +1709,9 @@ struct Resetter void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection) { - TableTypeVar* superTable = log.getMutable(superTy); - TableTypeVar* subTable = log.getMutable(subTy); - TableTypeVar* instantiatedSubTable = subTable; + TableType* superTable = log.getMutable(superTy); + TableType* subTable = log.getMutable(subTy); + TableType* instantiatedSubTable = subTable; if (!superTable || !subTable) ice("passed non-table types to unifyTables"); @@ -1685,7 +1728,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection) std::optional instantiated = instantiation.substitute(subTy); if (instantiated.has_value()) { - subTable = log.getMutable(*instantiated); + subTable = log.getMutable(*instantiated); instantiatedSubTable = subTable; if (!subTable) @@ -1777,7 +1820,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection) else if (subTable->state == TableState::Free) { PendingType* pendingSub = log.queue(subTy); - TableTypeVar* ttv = getMutable(pendingSub); + TableType* ttv = getMutable(pendingSub); LUAU_ASSERT(ttv); ttv->props[name] = prop; subTable = ttv; @@ -1799,8 +1842,8 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection) } // Otherwise, restart only the table unification - TableTypeVar* newSuperTable = log.getMutable(superTyNew); - TableTypeVar* newSubTable = log.getMutable(subTyNew); + TableType* newSuperTable = log.getMutable(superTyNew); + TableType* newSubTable = log.getMutable(subTyNew); if (superTable != newSuperTable || (subTable != newSubTable && subTable != instantiatedSubTable)) { @@ -1842,7 +1885,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection) clone.type = deeplyOptional(clone.type); PendingType* pendingSuper = log.queue(superTy); - TableTypeVar* pendingSuperTtv = getMutable(pendingSuper); + TableType* pendingSuperTtv = getMutable(pendingSuper); pendingSuperTtv->props[name] = clone; superTable = pendingSuperTtv; } @@ -1852,7 +1895,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection) else if (superTable->state == TableState::Free) { PendingType* pendingSuper = log.queue(superTy); - TableTypeVar* pendingSuperTtv = getMutable(pendingSuper); + TableType* pendingSuperTtv = getMutable(pendingSuper); pendingSuperTtv->props[name] = prop; superTable = pendingSuperTtv; } @@ -1872,8 +1915,8 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection) // Recursive unification can change the txn log, and invalidate the old // table. If we detect that this has happened, we start over, with the updated // txn log. - TableTypeVar* newSuperTable = log.getMutable(superTyNew); - TableTypeVar* newSubTable = log.getMutable(subTyNew); + TableType* newSuperTable = log.getMutable(superTyNew); + TableType* newSubTable = log.getMutable(subTyNew); if (superTable != newSuperTable || (subTable != newSubTable && subTable != instantiatedSubTable)) { if (errors.empty()) @@ -1929,16 +1972,16 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection) // Changing the indexer can invalidate the table pointers. if (FFlag::LuauScalarShapeUnifyToMtOwner2) { - superTable = log.getMutable(log.follow(superTy)); - subTable = log.getMutable(log.follow(subTy)); + superTable = log.getMutable(log.follow(superTy)); + subTable = log.getMutable(log.follow(subTy)); if (!superTable || !subTable) return; } else { - superTable = log.getMutable(superTy); - subTable = log.getMutable(subTy); + superTable = log.getMutable(superTy); + subTable = log.getMutable(subTy); } if (!missingProperties.empty()) @@ -1954,7 +1997,7 @@ void Unifier::tryUnifyTables(TypeId subTy, TypeId superTy, bool isIntersection) } /* - * TypeVars are commonly cyclic, so it is entirely possible + * Types are commonly cyclic, so it is entirely possible * for unifying a property of a table to change the table itself! * We need to check for this and start over if we notice this occurring. * @@ -1987,7 +2030,7 @@ void Unifier::tryUnifyScalarShape(TypeId subTy, TypeId superTy, bool reversed) if (reversed) std::swap(subTy, superTy); - TableTypeVar* superTable = log.getMutable(superTy); + TableType* superTable = log.getMutable(superTy); if (!superTable || superTable->state != TableState::Free) return reportError(location, TypeMismatch{osuperTy, osubTy, mismatchContext()}); @@ -2002,9 +2045,9 @@ void Unifier::tryUnifyScalarShape(TypeId subTy, TypeId superTy, bool reversed) // Given t1 where t1 = { lower: (t1) -> (a, b...) } // It should be the case that `string <: t1` iff `(subtype's metatable).__index <: t1` - if (auto metatable = getMetatable(subTy, singletonTypes)) + if (auto metatable = getMetatable(subTy, builtinTypes)) { - auto mttv = log.get(*metatable); + auto mttv = log.get(*metatable); if (!mttv) fail(std::nullopt); @@ -2023,7 +2066,7 @@ void Unifier::tryUnifyScalarShape(TypeId subTy, TypeId superTy, bool reversed) if (superTy != newSuperTy && canUnify(subTy, newSuperTy).empty()) { - log.replace(superTy, BoundTypeVar{subTy}); + log.replace(superTy, BoundType{subTy}); return; } } @@ -2040,7 +2083,7 @@ void Unifier::tryUnifyScalarShape(TypeId subTy, TypeId superTy, bool reversed) // To perform subtype <: free table unification, we have tried to unify (subtype's metatable) <: free table // We return success because subtype <: free table which means that correct unification is to replace free table with the subtype if (child.errors.empty()) - log.replace(superTy, BoundTypeVar{subTy}); + log.replace(superTy, BoundType{subTy}); } return; @@ -2060,30 +2103,30 @@ TypeId Unifier::deeplyOptional(TypeId ty, std::unordered_map see ty = follow(ty); if (isOptional(ty)) return ty; - else if (const TableTypeVar* ttv = get(ty)) + else if (const TableType* ttv = get(ty)) { TypeId& result = seen[ty]; if (result) return result; result = types->addType(*ttv); - TableTypeVar* resultTtv = getMutable(result); + TableType* resultTtv = getMutable(result); for (auto& [name, prop] : resultTtv->props) prop.type = deeplyOptional(prop.type, seen); - return types->addType(UnionTypeVar{{singletonTypes->nilType, result}}); + return types->addType(UnionType{{builtinTypes->nilType, result}}); } else - return types->addType(UnionTypeVar{{singletonTypes->nilType, ty}}); + return types->addType(UnionType{{builtinTypes->nilType, ty}}); } void Unifier::tryUnifyWithMetatable(TypeId subTy, TypeId superTy, bool reversed) { - const MetatableTypeVar* superMetatable = get(superTy); + const MetatableType* superMetatable = get(superTy); if (!superMetatable) - ice("tryUnifyMetatable invoked with non-metatable TypeVar"); + ice("tryUnifyMetatable invoked with non-metatable Type"); TypeError mismatchError = TypeError{location, TypeMismatch{reversed ? subTy : superTy, reversed ? superTy : subTy, mismatchContext()}}; - if (const MetatableTypeVar* subMetatable = log.getMutable(subTy)) + if (const MetatableType* subMetatable = log.getMutable(subTy)) { Unifier innerState = makeChildUnifier(); innerState.tryUnify_(subMetatable->table, superMetatable->table); @@ -2097,7 +2140,7 @@ void Unifier::tryUnifyWithMetatable(TypeId subTy, TypeId superTy, bool reversed) log.concat(std::move(innerState.log)); } - else if (TableTypeVar* subTable = log.getMutable(subTy)) + else if (TableType* subTable = log.getMutable(subTy)) { switch (subTable->state) { @@ -2122,7 +2165,7 @@ void Unifier::tryUnifyWithMetatable(TypeId subTy, TypeId superTy, bool reversed) } } - if (const TableTypeVar* superTable = log.get(log.follow(superMetatable->table))) + if (const TableType* superTable = log.get(log.follow(superMetatable->table))) { // TODO: Unify indexers. } @@ -2153,7 +2196,7 @@ void Unifier::tryUnifyWithMetatable(TypeId subTy, TypeId superTy, bool reversed) reportError(mismatchError); } } - else if (log.getMutable(subTy) || log.getMutable(subTy)) + else if (log.getMutable(subTy) || log.getMutable(subTy)) { } else @@ -2175,11 +2218,11 @@ void Unifier::tryUnifyWithClass(TypeId subTy, TypeId superTy, bool reversed) reportError(location, TypeMismatch{subTy, superTy, mismatchContext()}); }; - const ClassTypeVar* superClass = get(superTy); + const ClassType* superClass = get(superTy); if (!superClass) - ice("tryUnifyClass invoked with non-class TypeVar"); + ice("tryUnifyClass invoked with non-class Type"); - if (const ClassTypeVar* subClass = get(subTy)) + if (const ClassType* subClass = get(subTy)) { switch (variance) { @@ -2194,7 +2237,7 @@ void Unifier::tryUnifyWithClass(TypeId subTy, TypeId superTy, bool reversed) } ice("Illegal variance setting!"); } - else if (TableTypeVar* subTable = getMutable(subTy)) + else if (TableType* subTable = getMutable(subTy)) { /** * A free table is something whose shape we do not exactly know yet. @@ -2255,7 +2298,7 @@ void Unifier::tryUnifyWithClass(TypeId subTy, TypeId superTy, bool reversed) void Unifier::tryUnifyTypeWithNegation(TypeId subTy, TypeId superTy) { - const NegationTypeVar* ntv = get(superTy); + const NegationType* ntv = get(superTy); if (!ntv) ice("tryUnifyTypeWithNegation superTy must be a negation type"); @@ -2273,7 +2316,7 @@ void Unifier::tryUnifyTypeWithNegation(TypeId subTy, TypeId superTy) void Unifier::tryUnifyNegationWithType(TypeId subTy, TypeId superTy) { - const NegationTypeVar* ntv = get(subTy); + const NegationType* ntv = get(subTy); if (!ntv) ice("tryUnifyNegationWithType subTy must be a negation type"); @@ -2378,17 +2421,17 @@ static void tryUnifyWithAny(std::vector& queue, Unifier& state, DenseHas seen.insert(ty); - if (state.log.getMutable(ty)) + if (state.log.getMutable(ty)) { // TODO: Only bind if the anyType isn't any, unknown, or error (?) - state.log.replace(ty, BoundTypeVar{anyType}); + state.log.replace(ty, BoundType{anyType}); } - else if (auto fun = state.log.getMutable(ty)) + else if (auto fun = state.log.getMutable(ty)) { queueTypePack(queue, seenTypePacks, state, fun->argTypes, anyTypePack); queueTypePack(queue, seenTypePacks, state, fun->retTypes, anyTypePack); } - else if (auto table = state.log.getMutable(ty)) + else if (auto table = state.log.getMutable(ty)) { for (const auto& [_name, prop] : table->props) queue.push_back(prop.type); @@ -2399,18 +2442,18 @@ static void tryUnifyWithAny(std::vector& queue, Unifier& state, DenseHas queue.push_back(table->indexer->indexResultType); } } - else if (auto mt = state.log.getMutable(ty)) + else if (auto mt = state.log.getMutable(ty)) { queue.push_back(mt->table); queue.push_back(mt->metatable); } - else if (state.log.getMutable(ty)) + else if (state.log.getMutable(ty)) { - // ClassTypeVars never contain free typevars. + // ClassTypes never contain free types. } - else if (auto union_ = state.log.getMutable(ty)) + else if (auto union_ = state.log.getMutable(ty)) queue.insert(queue.end(), union_->options.begin(), union_->options.end()); - else if (auto intersection = state.log.getMutable(ty)) + else if (auto intersection = state.log.getMutable(ty)) queue.insert(queue.end(), intersection->parts.begin(), intersection->parts.end()); else { @@ -2420,10 +2463,10 @@ static void tryUnifyWithAny(std::vector& queue, Unifier& state, DenseHas void Unifier::tryUnifyWithAny(TypeId subTy, TypeId anyTy) { - LUAU_ASSERT(get(anyTy) || get(anyTy) || get(anyTy) || get(anyTy)); + LUAU_ASSERT(get(anyTy) || get(anyTy) || get(anyTy) || get(anyTy)); // These types are not visited in general loop below - if (get(subTy) || get(subTy) || get(subTy)) + if (get(subTy) || get(subTy) || get(subTy)) return; TypePackId anyTp; @@ -2431,8 +2474,8 @@ void Unifier::tryUnifyWithAny(TypeId subTy, TypeId anyTy) anyTp = types->addTypePack(TypePackVar{VariadicTypePack{anyTy}}); else { - const TypePackId anyTypePack = types->addTypePack(TypePackVar{VariadicTypePack{singletonTypes->anyType}}); - anyTp = get(anyTy) ? anyTypePack : types->addTypePack(TypePackVar{Unifiable::Error{}}); + const TypePackId anyTypePack = types->addTypePack(TypePackVar{VariadicTypePack{builtinTypes->anyType}}); + anyTp = get(anyTy) ? anyTypePack : types->addTypePack(TypePackVar{Unifiable::Error{}}); } std::vector queue = {subTy}; @@ -2441,14 +2484,14 @@ void Unifier::tryUnifyWithAny(TypeId subTy, TypeId anyTy) sharedState.tempSeenTp.clear(); Luau::tryUnifyWithAny( - queue, *this, sharedState.tempSeenTy, sharedState.tempSeenTp, types, FFlag::LuauUnknownAndNeverType ? anyTy : singletonTypes->anyType, anyTp); + queue, *this, sharedState.tempSeenTy, sharedState.tempSeenTp, types, FFlag::LuauUnknownAndNeverType ? anyTy : builtinTypes->anyType, anyTp); } void Unifier::tryUnifyWithAny(TypePackId subTy, TypePackId anyTp) { LUAU_ASSERT(get(anyTp)); - const TypeId anyTy = singletonTypes->errorRecoveryType(); + const TypeId anyTy = builtinTypes->errorRecoveryType(); std::vector queue; @@ -2462,7 +2505,7 @@ void Unifier::tryUnifyWithAny(TypePackId subTy, TypePackId anyTp) std::optional Unifier::findTablePropertyRespectingMeta(TypeId lhsType, Name name) { - return Luau::findTablePropertyRespectingMeta(singletonTypes, errors, lhsType, name, location); + return Luau::findTablePropertyRespectingMeta(builtinTypes, errors, lhsType, name, location); } TxnLog Unifier::combineLogsIntoIntersection(std::vector logs) @@ -2518,19 +2561,19 @@ bool Unifier::occursCheck(DenseHashSet& seen, TypeId needle, TypeId hays if (needle == haystack) { reportError(location, OccursCheckFailed{}); - log.replace(needle, *singletonTypes->errorRecoveryType()); + log.replace(needle, *builtinTypes->errorRecoveryType()); return true; } - if (log.getMutable(haystack)) + if (log.getMutable(haystack)) return false; - else if (auto a = log.getMutable(haystack)) + else if (auto a = log.getMutable(haystack)) { for (TypeId ty : a->options) check(ty); } - else if (auto a = log.getMutable(haystack)) + else if (auto a = log.getMutable(haystack)) { for (TypeId ty : a->parts) check(ty); @@ -2564,12 +2607,12 @@ bool Unifier::occursCheck(DenseHashSet& seen, TypePackId needle, Typ RecursionLimiter _ra(&sharedState.counters.recursionCount, sharedState.counters.recursionLimit); - while (!log.getMutable(haystack)) + while (!log.getMutable(haystack)) { if (needle == haystack) { reportError(location, OccursCheckFailed{}); - log.replace(needle, *singletonTypes->errorRecoveryTypePack()); + log.replace(needle, *builtinTypes->errorRecoveryTypePack()); return true; } diff --git a/Ast/src/Location.cpp b/Ast/src/Location.cpp index 67c2dd4b..d01d8a18 100644 --- a/Ast/src/Location.cpp +++ b/Ast/src/Location.cpp @@ -5,8 +5,8 @@ namespace Luau { Position::Position(unsigned int line, unsigned int column) - : line(line) - , column(column) + : line(line) + , column(column) { } diff --git a/CodeGen/include/Luau/AssemblyBuilderX64.h b/CodeGen/include/Luau/AssemblyBuilderX64.h index 59f2c14a..dbb366b2 100644 --- a/CodeGen/include/Luau/AssemblyBuilderX64.h +++ b/CodeGen/include/Luau/AssemblyBuilderX64.h @@ -107,6 +107,8 @@ public: void vmulsd(OperandX64 dst, OperandX64 src1, OperandX64 src2); void vdivsd(OperandX64 dst, OperandX64 src1, OperandX64 src2); + void vandpd(OperandX64 dst, OperandX64 src1, OperandX64 src2); + void vxorpd(OperandX64 dst, OperandX64 src1, OperandX64 src2); void vucomisd(OperandX64 src1, OperandX64 src2); @@ -129,6 +131,11 @@ public: void vmovaps(OperandX64 dst, OperandX64 src); void vmovupd(OperandX64 dst, OperandX64 src); void vmovups(OperandX64 dst, OperandX64 src); + void vmovq(OperandX64 lhs, OperandX64 rhs); + + void vmaxsd(OperandX64 dst, OperandX64 src1, OperandX64 src2); + void vminsd(OperandX64 dst, OperandX64 src1, OperandX64 src2); + // Run final checks void finalize(); diff --git a/CodeGen/src/AssemblyBuilderX64.cpp b/CodeGen/src/AssemblyBuilderX64.cpp index c17fab6b..f23fe463 100644 --- a/CodeGen/src/AssemblyBuilderX64.cpp +++ b/CodeGen/src/AssemblyBuilderX64.cpp @@ -614,6 +614,11 @@ void AssemblyBuilderX64::vdivsd(OperandX64 dst, OperandX64 src1, OperandX64 src2 placeAvx("vdivsd", dst, src1, src2, 0x5e, false, AVX_0F, AVX_F2); } +void AssemblyBuilderX64::vandpd(OperandX64 dst, OperandX64 src1, OperandX64 src2) +{ + placeAvx("vandpd", dst, src1, src2, 0x54, false, AVX_0F, AVX_66); +} + void AssemblyBuilderX64::vxorpd(OperandX64 dst, OperandX64 src1, OperandX64 src2) { placeAvx("vxorpd", dst, src1, src2, 0x57, false, AVX_0F, AVX_66); @@ -699,6 +704,36 @@ void AssemblyBuilderX64::vmovups(OperandX64 dst, OperandX64 src) placeAvx("vmovups", dst, src, 0x10, 0x11, false, AVX_0F, AVX_NP); } +void AssemblyBuilderX64::vmovq(OperandX64 dst, OperandX64 src) +{ + if (dst.base.size == SizeX64::xmmword) + { + LUAU_ASSERT(dst.cat == CategoryX64::reg); + LUAU_ASSERT(src.base.size == SizeX64::qword); + placeAvx("vmovq", dst, src, 0x6e, true, AVX_0F, AVX_66); + } + else if (dst.base.size == SizeX64::qword) + { + LUAU_ASSERT(src.cat == CategoryX64::reg); + LUAU_ASSERT(src.base.size == SizeX64::xmmword); + placeAvx("vmovq", src, dst, 0x7e, true, AVX_0F, AVX_66); + } + else + { + LUAU_ASSERT(!"No encoding for left operand of this category"); + } +} + +void AssemblyBuilderX64::vmaxsd(OperandX64 dst, OperandX64 src1, OperandX64 src2) +{ + placeAvx("vmaxsd", dst, src1, src2, 0x5f, false, AVX_0F, AVX_F2); +} + +void AssemblyBuilderX64::vminsd(OperandX64 dst, OperandX64 src1, OperandX64 src2) +{ + placeAvx("vminsd", dst, src1, src2, 0x5d, false, AVX_0F, AVX_F2); +} + void AssemblyBuilderX64::finalize() { code.resize(codePos - code.data()); diff --git a/CodeGen/src/EmitBuiltinsX64.cpp b/CodeGen/src/EmitBuiltinsX64.cpp index 04bd43aa..41a2c260 100644 --- a/CodeGen/src/EmitBuiltinsX64.cpp +++ b/CodeGen/src/EmitBuiltinsX64.cpp @@ -5,6 +5,7 @@ #include "Luau/Bytecode.h" #include "EmitCommonX64.h" +#include "NativeState.h" #include "lstate.h" @@ -88,6 +89,341 @@ BuiltinImplResult emitBuiltinMathSqrt(AssemblyBuilderX64& build, int nparams, in return {BuiltinImplType::UsesFallback, 1}; } +BuiltinImplResult emitBuiltinMathAbs(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + if (nparams < 1 || nresults > 1) + return {BuiltinImplType::None, -1}; + + if (build.logText) + build.logAppend("; inlined LBF_MATH_ABS\n"); + + jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback); + + build.vmovsd(xmm0, luauRegValue(arg)); + build.vandpd(xmm0, xmm0, build.i64(~(1LL << 63))); + build.vmovsd(luauRegValue(ra), xmm0); + + if (ra != arg) + build.mov(luauRegTag(ra), LUA_TNUMBER); + + return {BuiltinImplType::UsesFallback, 1}; +} + +static BuiltinImplResult emitBuiltinMathSingleArgFunc( + AssemblyBuilderX64& build, int nparams, int ra, int arg, int nresults, Label& fallback, const char* name, int32_t offset) +{ + if (nparams < 1 || nresults > 1) + return {BuiltinImplType::None, -1}; + + if (build.logText) + build.logAppend("; inlined %s\n", name); + + jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback); + + build.vmovsd(xmm0, luauRegValue(arg)); + build.call(qword[rNativeContext + offset]); + + build.vmovsd(luauRegValue(ra), xmm0); + + if (ra != arg) + build.mov(luauRegTag(ra), LUA_TNUMBER); + + return {BuiltinImplType::UsesFallback, 1}; +} + +BuiltinImplResult emitBuiltinMathExp(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_EXP", offsetof(NativeContext, libm_exp)); +} + +BuiltinImplResult emitBuiltinMathDeg(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + if (nparams < 1 || nresults > 1) + return {BuiltinImplType::None, -1}; + + if (build.logText) + build.logAppend("; inlined LBF_MATH_DEG\n"); + + jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback); + + const double rpd = (3.14159265358979323846 / 180.0); + + build.vmovsd(xmm0, luauRegValue(arg)); + build.vdivsd(xmm0, xmm0, build.f64(rpd)); + build.vmovsd(luauRegValue(ra), xmm0); + + if (ra != arg) + build.mov(luauRegTag(ra), LUA_TNUMBER); + + return {BuiltinImplType::UsesFallback, 1}; +} + +BuiltinImplResult emitBuiltinMathRad(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + if (nparams < 1 || nresults > 1) + return {BuiltinImplType::None, -1}; + + if (build.logText) + build.logAppend("; inlined LBF_MATH_RAD\n"); + + jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback); + + const double rpd = (3.14159265358979323846 / 180.0); + + build.vmovsd(xmm0, luauRegValue(arg)); + build.vmulsd(xmm0, xmm0, build.f64(rpd)); + build.vmovsd(luauRegValue(ra), xmm0); + + if (ra != arg) + build.mov(luauRegTag(ra), LUA_TNUMBER); + + return {BuiltinImplType::UsesFallback, 1}; +} + +BuiltinImplResult emitBuiltinMathFmod(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + if (nparams < 2 || nresults > 1) + return {BuiltinImplType::None, -1}; + + if (build.logText) + build.logAppend("; inlined LBF_MATH_FMOD\n"); + + jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback); + + // TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though + build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER); + build.jcc(ConditionX64::NotEqual, fallback); + + build.vmovsd(xmm0, luauRegValue(arg)); + build.vmovsd(xmm1, qword[args + offsetof(TValue, value)]); + build.call(qword[rNativeContext + offsetof(NativeContext, libm_fmod)]); + + build.vmovsd(luauRegValue(ra), xmm0); + + if (ra != arg) + build.mov(luauRegTag(ra), LUA_TNUMBER); + + return {BuiltinImplType::UsesFallback, 1}; +} + +BuiltinImplResult emitBuiltinMathPow(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + if (nparams < 2 || nresults > 1) + return {BuiltinImplType::None, -1}; + + if (build.logText) + build.logAppend("; inlined LBF_MATH_POW\n"); + + jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback); + + // TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though + build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER); + build.jcc(ConditionX64::NotEqual, fallback); + + build.vmovsd(xmm0, luauRegValue(arg)); + build.vmovsd(xmm1, qword[args + offsetof(TValue, value)]); + build.call(qword[rNativeContext + offsetof(NativeContext, libm_pow)]); + + build.vmovsd(luauRegValue(ra), xmm0); + + if (ra != arg) + build.mov(luauRegTag(ra), LUA_TNUMBER); + + return {BuiltinImplType::UsesFallback, 1}; +} + +BuiltinImplResult emitBuiltinMathMin(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + if (nparams != 2 || nresults > 1) + return {BuiltinImplType::None, -1}; + + if (build.logText) + build.logAppend("; inlined LBF_MATH_MIN\n"); + + jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback); + + // TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though + build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER); + build.jcc(ConditionX64::NotEqual, fallback); + + build.vmovsd(xmm0, qword[args + offsetof(TValue, value)]); + build.vminsd(xmm0, xmm0, luauRegValue(arg)); + + build.vmovsd(luauRegValue(ra), xmm0); + + if (ra != arg) + build.mov(luauRegTag(ra), LUA_TNUMBER); + + return {BuiltinImplType::UsesFallback, 1}; +} + +BuiltinImplResult emitBuiltinMathMax(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + if (nparams != 2 || nresults > 1) + return {BuiltinImplType::None, -1}; + + if (build.logText) + build.logAppend("; inlined LBF_MATH_MAX\n"); + + jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback); + + // TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though + build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER); + build.jcc(ConditionX64::NotEqual, fallback); + + build.vmovsd(xmm0, qword[args + offsetof(TValue, value)]); + build.vmaxsd(xmm0, xmm0, luauRegValue(arg)); + + build.vmovsd(luauRegValue(ra), xmm0); + + if (ra != arg) + build.mov(luauRegTag(ra), LUA_TNUMBER); + + return {BuiltinImplType::UsesFallback, 1}; +} + +BuiltinImplResult emitBuiltinMathAsin(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_ASIN", offsetof(NativeContext, libm_asin)); +} + +BuiltinImplResult emitBuiltinMathSin(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_SIN", offsetof(NativeContext, libm_sin)); +} + +BuiltinImplResult emitBuiltinMathSinh(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_SINH", offsetof(NativeContext, libm_sinh)); +} + +BuiltinImplResult emitBuiltinMathAcos(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_ACOS", offsetof(NativeContext, libm_acos)); +} + +BuiltinImplResult emitBuiltinMathCos(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_COS", offsetof(NativeContext, libm_cos)); +} + +BuiltinImplResult emitBuiltinMathCosh(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_COSH", offsetof(NativeContext, libm_cosh)); +} + +BuiltinImplResult emitBuiltinMathAtan(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_ATAN", offsetof(NativeContext, libm_atan)); +} + +BuiltinImplResult emitBuiltinMathTan(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_TAN", offsetof(NativeContext, libm_tan)); +} + +BuiltinImplResult emitBuiltinMathTanh(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_TANH", offsetof(NativeContext, libm_tanh)); +} + +BuiltinImplResult emitBuiltinMathAtan2(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + if (nparams < 2 || nresults > 1) + return {BuiltinImplType::None, -1}; + + if (build.logText) + build.logAppend("; inlined LBF_MATH_ATAN2\n"); + + jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback); + + // TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though + build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER); + build.jcc(ConditionX64::NotEqual, fallback); + + build.vmovsd(xmm0, luauRegValue(arg)); + build.vmovsd(xmm1, qword[args + offsetof(TValue, value)]); + build.call(qword[rNativeContext + offsetof(NativeContext, libm_atan2)]); + + build.vmovsd(luauRegValue(ra), xmm0); + + if (ra != arg) + build.mov(luauRegTag(ra), LUA_TNUMBER); + + return {BuiltinImplType::UsesFallback, 1}; +} + +BuiltinImplResult emitBuiltinMathLog10(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_LOG10", offsetof(NativeContext, libm_log10)); +} + +BuiltinImplResult emitBuiltinMathLog(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) +{ + if (nparams < 1 || nresults > 1) + return {BuiltinImplType::None, -1}; + + if (build.logText) + build.logAppend("; inlined LBF_MATH_LOG\n"); + + jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback); + + build.vmovsd(xmm0, luauRegValue(arg)); + + if (nparams == 1) + { + build.call(qword[rNativeContext + offsetof(NativeContext, libm_log)]); + } + else + { + Label log10check, logdivlog, exit; + + // Using 'rbx' for non-volatile temporary storage of log(arg1) result + RegisterX64 tmp = rbx; + OperandX64 arg2value = qword[args + offsetof(TValue, value)]; + + // TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though + build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER); + build.jcc(ConditionX64::NotEqual, fallback); + + build.vmovsd(xmm1, arg2value); + + jumpOnNumberCmp(build, noreg, build.f64(2.0), xmm1, ConditionX64::NotEqual, log10check); + + build.call(qword[rNativeContext + offsetof(NativeContext, libm_log2)]); + build.jmp(exit); + + build.setLabel(log10check); + jumpOnNumberCmp(build, noreg, build.f64(10.0), xmm1, ConditionX64::NotEqual, logdivlog); + + build.call(qword[rNativeContext + offsetof(NativeContext, libm_log10)]); + build.jmp(exit); + + build.setLabel(logdivlog); + + // log(arg1) + build.call(qword[rNativeContext + offsetof(NativeContext, libm_log)]); + build.vmovq(tmp, xmm0); + + // log(arg2) + build.vmovsd(xmm0, arg2value); + build.call(qword[rNativeContext + offsetof(NativeContext, libm_log)]); + + // log(arg1) / log(arg2) + build.vmovq(xmm1, tmp); + build.vdivsd(xmm0, xmm1, xmm0); + + build.setLabel(exit); + } + + build.vmovsd(luauRegValue(ra), xmm0); + + if (ra != arg) + build.mov(luauRegTag(ra), LUA_TNUMBER); + + return {BuiltinImplType::UsesFallback, 1}; +} + BuiltinImplResult emitBuiltin(AssemblyBuilderX64& build, int bfid, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback) { switch (bfid) @@ -100,6 +436,46 @@ BuiltinImplResult emitBuiltin(AssemblyBuilderX64& build, int bfid, int nparams, return emitBuiltinMathCeil(build, nparams, ra, arg, args, nresults, fallback); case LBF_MATH_SQRT: return emitBuiltinMathSqrt(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_ABS: + return emitBuiltinMathAbs(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_EXP: + return emitBuiltinMathExp(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_DEG: + return emitBuiltinMathDeg(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_RAD: + return emitBuiltinMathRad(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_FMOD: + return emitBuiltinMathFmod(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_POW: + return emitBuiltinMathPow(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_MIN: + return emitBuiltinMathMin(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_MAX: + return emitBuiltinMathMax(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_ASIN: + return emitBuiltinMathAsin(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_SIN: + return emitBuiltinMathSin(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_SINH: + return emitBuiltinMathSinh(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_ACOS: + return emitBuiltinMathAcos(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_COS: + return emitBuiltinMathCos(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_COSH: + return emitBuiltinMathCosh(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_ATAN: + return emitBuiltinMathAtan(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_TAN: + return emitBuiltinMathTan(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_TANH: + return emitBuiltinMathTanh(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_ATAN2: + return emitBuiltinMathAtan2(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_LOG10: + return emitBuiltinMathLog10(build, nparams, ra, arg, args, nresults, fallback); + case LBF_MATH_LOG: + return emitBuiltinMathLog(build, nparams, ra, arg, args, nresults, fallback); default: return {BuiltinImplType::None, -1}; } diff --git a/CodeGen/src/Fallbacks.cpp b/CodeGen/src/Fallbacks.cpp index a458c4eb..41f2bc8c 100644 --- a/CodeGen/src/Fallbacks.cpp +++ b/CodeGen/src/Fallbacks.cpp @@ -612,4 +612,3 @@ const Instruction* execute_LOP_BREAK(lua_State* L, const Instruction* pc, StkId LUAU_ASSERT(!"Unsupported deprecated opcode"); LUAU_UNREACHABLE(); } - diff --git a/CodeGen/src/NativeState.cpp b/CodeGen/src/NativeState.cpp index 54220375..62974fe3 100644 --- a/CodeGen/src/NativeState.cpp +++ b/CodeGen/src/NativeState.cpp @@ -80,7 +80,23 @@ void initHelperFunctions(NativeState& data) data.context.luaF_close = luaF_close; + data.context.libm_exp = exp; data.context.libm_pow = pow; + data.context.libm_fmod = fmod; + data.context.libm_log = log; + data.context.libm_log2 = log2; + data.context.libm_log10 = log10; + + data.context.libm_asin = asin; + data.context.libm_sin = sin; + data.context.libm_sinh = sinh; + data.context.libm_acos = acos; + data.context.libm_cos = cos; + data.context.libm_cosh = cosh; + data.context.libm_atan = atan; + data.context.libm_atan2 = atan2; + data.context.libm_tan = tan; + data.context.libm_tanh = tanh; data.context.forgLoopNodeIter = forgLoopNodeIter; data.context.forgLoopNonTableFallback = forgLoopNonTableFallback; diff --git a/CodeGen/src/NativeState.h b/CodeGen/src/NativeState.h index e5a24416..9138ba47 100644 --- a/CodeGen/src/NativeState.h +++ b/CodeGen/src/NativeState.h @@ -78,7 +78,22 @@ struct NativeContext void (*luaF_close)(lua_State* L, StkId level) = nullptr; + double (*libm_exp)(double) = nullptr; double (*libm_pow)(double, double) = nullptr; + double (*libm_fmod)(double, double) = nullptr; + double (*libm_asin)(double) = nullptr; + double (*libm_sin)(double) = nullptr; + double (*libm_sinh)(double) = nullptr; + double (*libm_acos)(double) = nullptr; + double (*libm_cos)(double) = nullptr; + double (*libm_cosh)(double) = nullptr; + double (*libm_atan)(double) = nullptr; + double (*libm_atan2)(double, double) = nullptr; + double (*libm_tan)(double) = nullptr; + double (*libm_tanh)(double) = nullptr; + double (*libm_log)(double) = nullptr; + double (*libm_log2)(double) = nullptr; + double (*libm_log10)(double) = nullptr; // Helper functions bool (*forgLoopNodeIter)(lua_State* L, Table* h, int index, TValue* ra) = nullptr; diff --git a/Compiler/src/Compiler.cpp b/Compiler/src/Compiler.cpp index 5d672366..b4dea4f5 100644 --- a/Compiler/src/Compiler.cpp +++ b/Compiler/src/Compiler.cpp @@ -350,7 +350,7 @@ struct Compiler { LUAU_ASSERT(!multRet || unsigned(target + targetCount) == regTop); - setDebugLine(expr); // normally compileExpr sets up line info, but compileExprCall can be called directly + setDebugLine(expr); // normally compileExpr sets up line info, but compileExprVarargs can be called directly bytecode.emitABC(LOP_GETVARARGS, target, multRet ? 0 : uint8_t(targetCount + 1), 0); } diff --git a/Sources.cmake b/Sources.cmake index e243ea74..437ff993 100644 --- a/Sources.cmake +++ b/Sources.cmake @@ -147,12 +147,12 @@ target_sources(Luau.Analysis PRIVATE Analysis/include/Luau/TypeInfer.h Analysis/include/Luau/TypePack.h Analysis/include/Luau/TypeUtils.h - Analysis/include/Luau/TypeVar.h + Analysis/include/Luau/Type.h Analysis/include/Luau/Unifiable.h Analysis/include/Luau/Unifier.h Analysis/include/Luau/UnifierSharedState.h Analysis/include/Luau/Variant.h - Analysis/include/Luau/VisitTypeVar.h + Analysis/include/Luau/VisitType.h Analysis/src/Anyification.cpp Analysis/src/ApplyTypeFunction.cpp @@ -196,7 +196,7 @@ target_sources(Luau.Analysis PRIVATE Analysis/src/TypeInfer.cpp Analysis/src/TypePack.cpp Analysis/src/TypeUtils.cpp - Analysis/src/TypeVar.cpp + Analysis/src/Type.cpp Analysis/src/Unifiable.cpp Analysis/src/Unifier.cpp ) @@ -366,7 +366,7 @@ if(TARGET Luau.UnitTest) tests/TypePack.test.cpp tests/TypeVar.test.cpp tests/Variant.test.cpp - tests/VisitTypeVar.test.cpp + tests/VisitType.test.cpp tests/main.cpp) endif() diff --git a/fuzz/proto.cpp b/fuzz/proto.cpp index 9e0a6829..c8ba2268 100644 --- a/fuzz/proto.cpp +++ b/fuzz/proto.cpp @@ -101,32 +101,32 @@ int registerTypes(Luau::TypeChecker& env) TypeArena& arena = env.globalTypes; // Vector3 stub - TypeId vector3MetaType = arena.addType(TableTypeVar{}); + TypeId vector3MetaType = arena.addType(TableType{}); - TypeId vector3InstanceType = arena.addType(ClassTypeVar{"Vector3", {}, nullopt, vector3MetaType, {}, {}, "Test"}); - getMutable(vector3InstanceType)->props = { + TypeId vector3InstanceType = arena.addType(ClassType{"Vector3", {}, nullopt, vector3MetaType, {}, {}, "Test"}); + getMutable(vector3InstanceType)->props = { {"X", {env.numberType}}, {"Y", {env.numberType}}, {"Z", {env.numberType}}, }; - getMutable(vector3MetaType)->props = { + getMutable(vector3MetaType)->props = { {"__add", {makeFunction(arena, nullopt, {vector3InstanceType, vector3InstanceType}, {vector3InstanceType})}}, }; env.globalScope->exportedTypeBindings["Vector3"] = TypeFun{{}, vector3InstanceType}; // Instance stub - TypeId instanceType = arena.addType(ClassTypeVar{"Instance", {}, nullopt, nullopt, {}, {}, "Test"}); - getMutable(instanceType)->props = { + TypeId instanceType = arena.addType(ClassType{"Instance", {}, nullopt, nullopt, {}, {}, "Test"}); + getMutable(instanceType)->props = { {"Name", {env.stringType}}, }; env.globalScope->exportedTypeBindings["Instance"] = TypeFun{{}, instanceType}; // Part stub - TypeId partType = arena.addType(ClassTypeVar{"Part", {}, instanceType, nullopt, {}, {}, "Test"}); - getMutable(partType)->props = { + TypeId partType = arena.addType(ClassType{"Part", {}, instanceType, nullopt, {}, {}, "Test"}); + getMutable(partType)->props = { {"Position", {vector3InstanceType}}, }; diff --git a/tests/AssemblyBuilderX64.test.cpp b/tests/AssemblyBuilderX64.test.cpp index 1af03e4f..b5dbf583 100644 --- a/tests/AssemblyBuilderX64.test.cpp +++ b/tests/AssemblyBuilderX64.test.cpp @@ -436,6 +436,11 @@ TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXBinaryInstructionForms") SINGLE_COMPARE(vdivsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x5e, 0xc6); SINGLE_COMPARE(vxorpd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x29, 0x57, 0xc6); + + SINGLE_COMPARE(vandpd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x29, 0x54, 0xc6); + + SINGLE_COMPARE(vmaxsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x5f, 0xc6); + SINGLE_COMPARE(vminsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x5d, 0xc6); } TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXUnaryMergeInstructionForms") @@ -475,6 +480,10 @@ TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXMoveInstructionForms") SINGLE_COMPARE(vmovups(xmm8, xmmword[r9]), 0xc4, 0x41, 0x78, 0x10, 0x01); SINGLE_COMPARE(vmovups(xmmword[r9], xmm10), 0xc4, 0x41, 0x78, 0x11, 0x11); SINGLE_COMPARE(vmovups(ymm8, ymmword[r9]), 0xc4, 0x41, 0x7c, 0x10, 0x01); + SINGLE_COMPARE(vmovq(xmm1, rbx), 0xc4, 0xe1, 0xf9, 0x6e, 0xcb); + SINGLE_COMPARE(vmovq(rbx, xmm1), 0xc4, 0xe1, 0xf9, 0x7e, 0xcb); + SINGLE_COMPARE(vmovq(xmm1, qword[r9]), 0xc4, 0xc1, 0xf9, 0x6e, 0x09); + SINGLE_COMPARE(vmovq(qword[r9], xmm1), 0xc4, 0xc1, 0xf9, 0x7e, 0x09); } TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXConversionInstructionForms") diff --git a/tests/Autocomplete.test.cpp b/tests/Autocomplete.test.cpp index 123708ca..10582947 100644 --- a/tests/Autocomplete.test.cpp +++ b/tests/Autocomplete.test.cpp @@ -2,8 +2,8 @@ #include "Luau/Autocomplete.h" #include "Luau/BuiltinDefinitions.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" #include "Luau/StringUtils.h" #include "Fixture.h" @@ -18,7 +18,7 @@ LUAU_FASTFLAG(LuauSetMetatableDoesNotTimeTravel) using namespace Luau; -static std::optional nullCallback(std::string tag, std::optional ptr) +static std::optional nullCallback(std::string tag, std::optional ptr) { return std::nullopt; } @@ -499,7 +499,7 @@ TEST_CASE_FIXTURE(ACFixture, "bias_toward_inner_scope") CHECK_EQ(ac.context, AutocompleteContext::Statement); TypeId t = follow(*ac.entryMap["A"].type); - const TableTypeVar* tt = get(t); + const TableType* tt = get(t); REQUIRE(tt); CHECK(tt->props.count("two")); @@ -1244,7 +1244,7 @@ end REQUIRE(ac.entryMap.count("Table")); REQUIRE(ac.entryMap["Table"].type); - const TableTypeVar* tv = get(follow(*ac.entryMap["Table"].type)); + const TableType* tv = get(follow(*ac.entryMap["Table"].type)); REQUIRE(tv); CHECK(tv->props.count("x")); } diff --git a/tests/BuiltinDefinitions.test.cpp b/tests/BuiltinDefinitions.test.cpp index 496df4b4..188f2190 100644 --- a/tests/BuiltinDefinitions.test.cpp +++ b/tests/BuiltinDefinitions.test.cpp @@ -1,6 +1,6 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/BuiltinDefinitions.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Fixture.h" @@ -22,12 +22,12 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "lib_documentation_symbols") CHECK_MESSAGE( actualRootSymbol == expectedRootSymbol, "expected symbol ", expectedRootSymbol, " for global ", nameString, ", got ", actualRootSymbol); - const TableTypeVar::Props* props = nullptr; - if (const TableTypeVar* ttv = get(binding.typeId)) + const TableType::Props* props = nullptr; + if (const TableType* ttv = get(binding.typeId)) { props = &ttv->props; } - else if (const ClassTypeVar* ctv = get(binding.typeId)) + else if (const ClassType* ctv = get(binding.typeId)) { props = &ctv->props; } diff --git a/tests/ClassFixture.cpp b/tests/ClassFixture.cpp index 18939e24..087b88d5 100644 --- a/tests/ClassFixture.cpp +++ b/tests/ClassFixture.cpp @@ -16,14 +16,14 @@ ClassFixture::ClassFixture() unfreeze(arena); - TypeId baseClassInstanceType = arena.addType(ClassTypeVar{"BaseClass", {}, nullopt, nullopt, {}, {}, "Test"}); - getMutable(baseClassInstanceType)->props = { + TypeId baseClassInstanceType = arena.addType(ClassType{"BaseClass", {}, nullopt, nullopt, {}, {}, "Test"}); + getMutable(baseClassInstanceType)->props = { {"BaseMethod", {makeFunction(arena, baseClassInstanceType, {numberType}, {})}}, {"BaseField", {numberType}}, }; - TypeId baseClassType = arena.addType(ClassTypeVar{"BaseClass", {}, nullopt, nullopt, {}, {}, "Test"}); - getMutable(baseClassType)->props = { + TypeId baseClassType = arena.addType(ClassType{"BaseClass", {}, nullopt, nullopt, {}, {}, "Test"}); + getMutable(baseClassType)->props = { {"StaticMethod", {makeFunction(arena, nullopt, {}, {numberType})}}, {"Clone", {makeFunction(arena, nullopt, {baseClassInstanceType}, {baseClassInstanceType})}}, {"New", {makeFunction(arena, nullopt, {}, {baseClassInstanceType})}}, @@ -31,75 +31,75 @@ ClassFixture::ClassFixture() typeChecker.globalScope->exportedTypeBindings["BaseClass"] = TypeFun{{}, baseClassInstanceType}; addGlobalBinding(frontend, "BaseClass", baseClassType, "@test"); - TypeId childClassInstanceType = arena.addType(ClassTypeVar{"ChildClass", {}, baseClassInstanceType, nullopt, {}, {}, "Test"}); + TypeId childClassInstanceType = arena.addType(ClassType{"ChildClass", {}, baseClassInstanceType, nullopt, {}, {}, "Test"}); - getMutable(childClassInstanceType)->props = { + getMutable(childClassInstanceType)->props = { {"Method", {makeFunction(arena, childClassInstanceType, {}, {typeChecker.stringType})}}, }; - TypeId childClassType = arena.addType(ClassTypeVar{"ChildClass", {}, baseClassType, nullopt, {}, {}, "Test"}); - getMutable(childClassType)->props = { + TypeId childClassType = arena.addType(ClassType{"ChildClass", {}, baseClassType, nullopt, {}, {}, "Test"}); + getMutable(childClassType)->props = { {"New", {makeFunction(arena, nullopt, {}, {childClassInstanceType})}}, }; typeChecker.globalScope->exportedTypeBindings["ChildClass"] = TypeFun{{}, childClassInstanceType}; addGlobalBinding(frontend, "ChildClass", childClassType, "@test"); - TypeId grandChildInstanceType = arena.addType(ClassTypeVar{"GrandChild", {}, childClassInstanceType, nullopt, {}, {}, "Test"}); + TypeId grandChildInstanceType = arena.addType(ClassType{"GrandChild", {}, childClassInstanceType, nullopt, {}, {}, "Test"}); - getMutable(grandChildInstanceType)->props = { + getMutable(grandChildInstanceType)->props = { {"Method", {makeFunction(arena, grandChildInstanceType, {}, {typeChecker.stringType})}}, }; - TypeId grandChildType = arena.addType(ClassTypeVar{"GrandChild", {}, baseClassType, nullopt, {}, {}, "Test"}); - getMutable(grandChildType)->props = { + TypeId grandChildType = arena.addType(ClassType{"GrandChild", {}, baseClassType, nullopt, {}, {}, "Test"}); + getMutable(grandChildType)->props = { {"New", {makeFunction(arena, nullopt, {}, {grandChildInstanceType})}}, }; typeChecker.globalScope->exportedTypeBindings["GrandChild"] = TypeFun{{}, grandChildInstanceType}; addGlobalBinding(frontend, "GrandChild", childClassType, "@test"); - TypeId anotherChildInstanceType = arena.addType(ClassTypeVar{"AnotherChild", {}, baseClassInstanceType, nullopt, {}, {}, "Test"}); + TypeId anotherChildInstanceType = arena.addType(ClassType{"AnotherChild", {}, baseClassInstanceType, nullopt, {}, {}, "Test"}); - getMutable(anotherChildInstanceType)->props = { + getMutable(anotherChildInstanceType)->props = { {"Method", {makeFunction(arena, anotherChildInstanceType, {}, {typeChecker.stringType})}}, }; - TypeId anotherChildType = arena.addType(ClassTypeVar{"AnotherChild", {}, baseClassType, nullopt, {}, {}, "Test"}); - getMutable(anotherChildType)->props = { + TypeId anotherChildType = arena.addType(ClassType{"AnotherChild", {}, baseClassType, nullopt, {}, {}, "Test"}); + getMutable(anotherChildType)->props = { {"New", {makeFunction(arena, nullopt, {}, {anotherChildInstanceType})}}, }; typeChecker.globalScope->exportedTypeBindings["AnotherChild"] = TypeFun{{}, anotherChildInstanceType}; addGlobalBinding(frontend, "AnotherChild", childClassType, "@test"); - TypeId unrelatedClassInstanceType = arena.addType(ClassTypeVar{"UnrelatedClass", {}, nullopt, nullopt, {}, {}, "Test"}); + TypeId unrelatedClassInstanceType = arena.addType(ClassType{"UnrelatedClass", {}, nullopt, nullopt, {}, {}, "Test"}); - TypeId unrelatedClassType = arena.addType(ClassTypeVar{"UnrelatedClass", {}, nullopt, nullopt, {}, {}, "Test"}); - getMutable(unrelatedClassType)->props = { + TypeId unrelatedClassType = arena.addType(ClassType{"UnrelatedClass", {}, nullopt, nullopt, {}, {}, "Test"}); + getMutable(unrelatedClassType)->props = { {"New", {makeFunction(arena, nullopt, {}, {unrelatedClassInstanceType})}}, }; typeChecker.globalScope->exportedTypeBindings["UnrelatedClass"] = TypeFun{{}, unrelatedClassInstanceType}; addGlobalBinding(frontend, "UnrelatedClass", unrelatedClassType, "@test"); - TypeId vector2MetaType = arena.addType(TableTypeVar{}); + TypeId vector2MetaType = arena.addType(TableType{}); - TypeId vector2InstanceType = arena.addType(ClassTypeVar{"Vector2", {}, nullopt, vector2MetaType, {}, {}, "Test"}); - getMutable(vector2InstanceType)->props = { + TypeId vector2InstanceType = arena.addType(ClassType{"Vector2", {}, nullopt, vector2MetaType, {}, {}, "Test"}); + getMutable(vector2InstanceType)->props = { {"X", {numberType}}, {"Y", {numberType}}, }; - TypeId vector2Type = arena.addType(ClassTypeVar{"Vector2", {}, nullopt, nullopt, {}, {}, "Test"}); - getMutable(vector2Type)->props = { + TypeId vector2Type = arena.addType(ClassType{"Vector2", {}, nullopt, nullopt, {}, {}, "Test"}); + getMutable(vector2Type)->props = { {"New", {makeFunction(arena, nullopt, {numberType, numberType}, {vector2InstanceType})}}, }; - getMutable(vector2MetaType)->props = { + getMutable(vector2MetaType)->props = { {"__add", {makeFunction(arena, nullopt, {vector2InstanceType, vector2InstanceType}, {vector2InstanceType})}}, }; typeChecker.globalScope->exportedTypeBindings["Vector2"] = TypeFun{{}, vector2InstanceType}; addGlobalBinding(frontend, "Vector2", vector2Type, "@test"); - TypeId callableClassMetaType = arena.addType(TableTypeVar{}); - TypeId callableClassType = arena.addType(ClassTypeVar{"CallableClass", {}, nullopt, callableClassMetaType, {}, {}, "Test"}); - getMutable(callableClassMetaType)->props = { + TypeId callableClassMetaType = arena.addType(TableType{}); + TypeId callableClassType = arena.addType(ClassType{"CallableClass", {}, nullopt, callableClassMetaType, {}, {}, "Test"}); + getMutable(callableClassMetaType)->props = { {"__call", {makeFunction(arena, nullopt, {callableClassType, typeChecker.stringType}, {typeChecker.numberType})}}, }; typeChecker.globalScope->exportedTypeBindings["CallableClass"] = TypeFun{{}, callableClassType}; diff --git a/tests/Conformance.test.cpp b/tests/Conformance.test.cpp index 6be838dd..c32f2870 100644 --- a/tests/Conformance.test.cpp +++ b/tests/Conformance.test.cpp @@ -440,27 +440,27 @@ TEST_CASE("Vector") static void populateRTTI(lua_State* L, Luau::TypeId type) { - if (auto p = Luau::get(type)) + if (auto p = Luau::get(type)) { switch (p->type) { - case Luau::PrimitiveTypeVar::Boolean: + case Luau::PrimitiveType::Boolean: lua_pushstring(L, "boolean"); break; - case Luau::PrimitiveTypeVar::NilType: + case Luau::PrimitiveType::NilType: lua_pushstring(L, "nil"); break; - case Luau::PrimitiveTypeVar::Number: + case Luau::PrimitiveType::Number: lua_pushstring(L, "number"); break; - case Luau::PrimitiveTypeVar::String: + case Luau::PrimitiveType::String: lua_pushstring(L, "string"); break; - case Luau::PrimitiveTypeVar::Thread: + case Luau::PrimitiveType::Thread: lua_pushstring(L, "thread"); break; @@ -468,7 +468,7 @@ static void populateRTTI(lua_State* L, Luau::TypeId type) LUAU_ASSERT(!"Unknown primitive type"); } } - else if (auto t = Luau::get(type)) + else if (auto t = Luau::get(type)) { lua_newtable(L); @@ -478,18 +478,18 @@ static void populateRTTI(lua_State* L, Luau::TypeId type) lua_setfield(L, -2, name.c_str()); } } - else if (Luau::get(type)) + else if (Luau::get(type)) { lua_pushstring(L, "function"); } - else if (Luau::get(type)) + else if (Luau::get(type)) { lua_pushstring(L, "any"); } - else if (auto i = Luau::get(type)) + else if (auto i = Luau::get(type)) { for (const auto& part : i->parts) - LUAU_ASSERT(Luau::get(part)); + LUAU_ASSERT(Luau::get(part)); lua_pushstring(L, "function"); } @@ -504,8 +504,8 @@ TEST_CASE("Types") runConformance("types.lua", [](lua_State* L) { Luau::NullModuleResolver moduleResolver; Luau::InternalErrorReporter iceHandler; - Luau::SingletonTypes singletonTypes; - Luau::TypeChecker env(&moduleResolver, Luau::NotNull{&singletonTypes}, &iceHandler); + Luau::BuiltinTypes builtinTypes; + Luau::TypeChecker env(&moduleResolver, Luau::NotNull{&builtinTypes}, &iceHandler); Luau::registerBuiltinGlobals(env); Luau::freeze(env.globalTypes); diff --git a/tests/ConstraintGraphBuilderFixture.cpp b/tests/ConstraintGraphBuilderFixture.cpp index 30e1b2e6..64e6baaf 100644 --- a/tests/ConstraintGraphBuilderFixture.cpp +++ b/tests/ConstraintGraphBuilderFixture.cpp @@ -9,7 +9,7 @@ ConstraintGraphBuilderFixture::ConstraintGraphBuilderFixture() , mainModule(new Module) , forceTheFlag{"DebugLuauDeferredConstraintResolution", true} { - BlockedTypeVar::nextIndex = 0; + BlockedType::nextIndex = 0; BlockedTypePack::nextIndex = 0; } @@ -17,7 +17,7 @@ void ConstraintGraphBuilderFixture::generateConstraints(const std::string& code) { AstStatBlock* root = parse(code); dfg = std::make_unique(DataFlowGraphBuilder::build(root, NotNull{&ice})); - cgb = std::make_unique("MainModule", mainModule, &arena, NotNull(&moduleResolver), singletonTypes, NotNull(&ice), + cgb = std::make_unique("MainModule", mainModule, &arena, NotNull(&moduleResolver), builtinTypes, NotNull(&ice), frontend.getGlobalScope(), &logger, NotNull{dfg.get()}); cgb->visit(root); rootScope = cgb->rootScope; diff --git a/tests/ConstraintGraphBuilderFixture.h b/tests/ConstraintGraphBuilderFixture.h index 9785a838..5e7fedab 100644 --- a/tests/ConstraintGraphBuilderFixture.h +++ b/tests/ConstraintGraphBuilderFixture.h @@ -19,7 +19,7 @@ struct ConstraintGraphBuilderFixture : Fixture ModulePtr mainModule; DcrLogger logger; UnifierSharedState sharedState{&ice}; - Normalizer normalizer{&arena, singletonTypes, NotNull{&sharedState}}; + Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}}; std::unique_ptr dfg; std::unique_ptr cgb; diff --git a/tests/Fixture.cpp b/tests/Fixture.cpp index eb77ce52..41629281 100644 --- a/tests/Fixture.cpp +++ b/tests/Fixture.cpp @@ -7,7 +7,7 @@ #include "Luau/ModuleResolver.h" #include "Luau/NotNull.h" #include "Luau/Parser.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/TypeAttach.h" #include "Luau/Transpiler.h" @@ -141,7 +141,7 @@ Fixture::Fixture(bool freeze, bool prepareAutocomplete) , frontend(&fileResolver, &configResolver, {/* retainFullTypeGraphs= */ true, /* forAutocomplete */ false, /* randomConstraintResolutionSeed */ randomSeed}) , typeChecker(frontend.typeChecker) - , singletonTypes(frontend.singletonTypes) + , builtinTypes(frontend.builtinTypes) { configResolver.defaultConfig.mode = Mode::Strict; configResolver.defaultConfig.enabledLint.warningMask = ~0ull; @@ -293,14 +293,14 @@ SourceModule* Fixture::getMainSourceModule() return frontend.getSourceModule(fromString(mainModuleName)); } -std::optional Fixture::getPrimitiveType(TypeId ty) +std::optional Fixture::getPrimitiveType(TypeId ty) { REQUIRE(ty != nullptr); TypeId aType = follow(ty); REQUIRE(aType != nullptr); - const PrimitiveTypeVar* pt = get(aType); + const PrimitiveType* pt = get(aType); if (pt != nullptr) return pt->type; else @@ -513,7 +513,7 @@ std::string rep(const std::string& s, size_t n) bool isInArena(TypeId t, const TypeArena& arena) { - return arena.typeVars.contains(t); + return arena.types.contains(t); } void dumpErrors(const ModulePtr& module) @@ -554,12 +554,13 @@ std::optional linearSearchForBinding(Scope* scope, const char* name) void registerHiddenTypes(Fixture& fixture, TypeArena& arena) { - TypeId t = arena.addType(GenericTypeVar{"T"}); + TypeId t = arena.addType(GenericType{"T"}); GenericTypeDefinition genericT{t}; ScopePtr moduleScope = fixture.frontend.getGlobalScope(); - moduleScope->exportedTypeBindings["Not"] = TypeFun{{genericT}, arena.addType(NegationTypeVar{t})}; - moduleScope->exportedTypeBindings["fun"] = TypeFun{{}, fixture.singletonTypes->functionType}; + moduleScope->exportedTypeBindings["Not"] = TypeFun{{genericT}, arena.addType(NegationType{t})}; + moduleScope->exportedTypeBindings["fun"] = TypeFun{{}, fixture.builtinTypes->functionType}; + moduleScope->exportedTypeBindings["cls"] = TypeFun{{}, fixture.builtinTypes->classType}; } void dump(const std::vector& constraints) diff --git a/tests/Fixture.h b/tests/Fixture.h index 5d838b16..3edd6b4c 100644 --- a/tests/Fixture.h +++ b/tests/Fixture.h @@ -10,7 +10,7 @@ #include "Luau/ModuleResolver.h" #include "Luau/Scope.h" #include "Luau/ToString.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "IostreamOptional.h" #include "ScopedFlags.h" @@ -78,7 +78,7 @@ struct Fixture ModulePtr getMainModule(); SourceModule* getMainSourceModule(); - std::optional getPrimitiveType(TypeId ty); + std::optional getPrimitiveType(TypeId ty); std::optional getType(const std::string& name); TypeId requireType(const std::string& name); TypeId requireType(const ModuleName& moduleName, const std::string& name); @@ -102,7 +102,7 @@ struct Fixture Frontend frontend; InternalErrorReporter ice; TypeChecker& typeChecker; - NotNull singletonTypes; + NotNull builtinTypes; std::string decorateWithTypes(const std::string& code); diff --git a/tests/Frontend.test.cpp b/tests/Frontend.test.cpp index 6f92b655..93df5605 100644 --- a/tests/Frontend.test.cpp +++ b/tests/Frontend.test.cpp @@ -791,7 +791,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "discard_type_graphs") ModulePtr module = fe.moduleResolver.getModule("Module/A"); - CHECK_EQ(0, module->internalTypes.typeVars.size()); + CHECK_EQ(0, module->internalTypes.types.size()); CHECK_EQ(0, module->internalTypes.typePacks.size()); CHECK_EQ(0, module->astTypes.size()); CHECK_EQ(0, module->astResolvedTypes.size()); diff --git a/tests/LValue.test.cpp b/tests/LValue.test.cpp index 0bb91ece..c71d97d1 100644 --- a/tests/LValue.test.cpp +++ b/tests/LValue.test.cpp @@ -14,18 +14,18 @@ static void merge(TypeArena& arena, RefinementMap& l, const RefinementMap& r) // TODO: normalize here also. std::unordered_set s; - if (auto utv = get(follow(a))) + if (auto utv = get(follow(a))) s.insert(begin(utv), end(utv)); else s.insert(a); - if (auto utv = get(follow(b))) + if (auto utv = get(follow(b))) s.insert(begin(utv), end(utv)); else s.insert(b); std::vector options(s.begin(), s.end()); - return options.size() == 1 ? options[0] : arena.addType(UnionTypeVar{std::move(options)}); + return options.size() == 1 ? options[0] : arena.addType(UnionType{std::move(options)}); }); } @@ -36,7 +36,7 @@ static LValue mkSymbol(const std::string& s) struct LValueFixture { - SingletonTypes singletonTypes; + BuiltinTypes builtinTypes; }; TEST_SUITE_BEGIN("LValue"); @@ -48,14 +48,14 @@ TEST_CASE_FIXTURE(LValueFixture, "Luau_merge_hashmap_order") std::string c = "c"; RefinementMap m{{ - {mkSymbol(b), singletonTypes.stringType}, - {mkSymbol(c), singletonTypes.numberType}, + {mkSymbol(b), builtinTypes.stringType}, + {mkSymbol(c), builtinTypes.numberType}, }}; RefinementMap other{{ - {mkSymbol(a), singletonTypes.stringType}, - {mkSymbol(b), singletonTypes.stringType}, - {mkSymbol(c), singletonTypes.booleanType}, + {mkSymbol(a), builtinTypes.stringType}, + {mkSymbol(b), builtinTypes.stringType}, + {mkSymbol(c), builtinTypes.booleanType}, }}; TypeArena arena; @@ -78,14 +78,14 @@ TEST_CASE_FIXTURE(LValueFixture, "Luau_merge_hashmap_order2") std::string c = "c"; RefinementMap m{{ - {mkSymbol(a), singletonTypes.stringType}, - {mkSymbol(b), singletonTypes.stringType}, - {mkSymbol(c), singletonTypes.numberType}, + {mkSymbol(a), builtinTypes.stringType}, + {mkSymbol(b), builtinTypes.stringType}, + {mkSymbol(c), builtinTypes.numberType}, }}; RefinementMap other{{ - {mkSymbol(b), singletonTypes.stringType}, - {mkSymbol(c), singletonTypes.booleanType}, + {mkSymbol(b), builtinTypes.stringType}, + {mkSymbol(c), builtinTypes.booleanType}, }}; TypeArena arena; @@ -110,15 +110,15 @@ TEST_CASE_FIXTURE(LValueFixture, "one_map_has_overlap_at_end_whereas_other_has_i std::string e = "e"; RefinementMap m{{ - {mkSymbol(a), singletonTypes.stringType}, - {mkSymbol(b), singletonTypes.numberType}, - {mkSymbol(c), singletonTypes.booleanType}, + {mkSymbol(a), builtinTypes.stringType}, + {mkSymbol(b), builtinTypes.numberType}, + {mkSymbol(c), builtinTypes.booleanType}, }}; RefinementMap other{{ - {mkSymbol(c), singletonTypes.stringType}, - {mkSymbol(d), singletonTypes.numberType}, - {mkSymbol(e), singletonTypes.booleanType}, + {mkSymbol(c), builtinTypes.stringType}, + {mkSymbol(d), builtinTypes.numberType}, + {mkSymbol(e), builtinTypes.booleanType}, }}; TypeArena arena; @@ -159,8 +159,8 @@ TEST_CASE_FIXTURE(LValueFixture, "hashing_lvalue_global_prop_access") CHECK_EQ(LValueHasher{}(t_x2), LValueHasher{}(t_x2)); RefinementMap m; - m[t_x1] = singletonTypes.stringType; - m[t_x2] = singletonTypes.numberType; + m[t_x1] = builtinTypes.stringType; + m[t_x2] = builtinTypes.numberType; CHECK_EQ(1, m.size()); } @@ -188,8 +188,8 @@ TEST_CASE_FIXTURE(LValueFixture, "hashing_lvalue_local_prop_access") CHECK_EQ(LValueHasher{}(t_x2), LValueHasher{}(t_x2)); RefinementMap m; - m[t_x1] = singletonTypes.stringType; - m[t_x2] = singletonTypes.numberType; + m[t_x1] = builtinTypes.stringType; + m[t_x2] = builtinTypes.numberType; CHECK_EQ(2, m.size()); } diff --git a/tests/Linter.test.cpp b/tests/Linter.test.cpp index 78ff85c3..426b520c 100644 --- a/tests/Linter.test.cpp +++ b/tests/Linter.test.cpp @@ -610,11 +610,11 @@ return foo1 TEST_CASE_FIXTURE(Fixture, "UnknownType") { unfreeze(typeChecker.globalTypes); - TableTypeVar::Props instanceProps{ + TableType::Props instanceProps{ {"ClassName", {typeChecker.anyType}}, }; - TableTypeVar instanceTable{instanceProps, std::nullopt, typeChecker.globalScope->level, Luau::TableState::Sealed}; + TableType instanceTable{instanceProps, std::nullopt, typeChecker.globalScope->level, Luau::TableState::Sealed}; TypeId instanceType = typeChecker.globalTypes.addType(instanceTable); TypeFun instanceTypeFun{{}, instanceType}; @@ -1448,19 +1448,19 @@ TEST_CASE_FIXTURE(Fixture, "LintHygieneUAF") TEST_CASE_FIXTURE(Fixture, "DeprecatedApi") { unfreeze(typeChecker.globalTypes); - TypeId instanceType = typeChecker.globalTypes.addType(ClassTypeVar{"Instance", {}, std::nullopt, std::nullopt, {}, {}, "Test"}); + TypeId instanceType = typeChecker.globalTypes.addType(ClassType{"Instance", {}, std::nullopt, std::nullopt, {}, {}, "Test"}); persist(instanceType); typeChecker.globalScope->exportedTypeBindings["Instance"] = TypeFun{{}, instanceType}; - getMutable(instanceType)->props = { + getMutable(instanceType)->props = { {"Name", {typeChecker.stringType}}, {"DataCost", {typeChecker.numberType, /* deprecated= */ true}}, {"Wait", {typeChecker.anyType, /* deprecated= */ true}}, }; - TypeId colorType = typeChecker.globalTypes.addType(TableTypeVar{{}, std::nullopt, typeChecker.globalScope->level, Luau::TableState::Sealed}); + TypeId colorType = typeChecker.globalTypes.addType(TableType{{}, std::nullopt, typeChecker.globalScope->level, Luau::TableState::Sealed}); - getMutable(colorType)->props = {{"toHSV", {typeChecker.anyType, /* deprecated= */ true, "Color3:ToHSV"}}}; + getMutable(colorType)->props = {{"toHSV", {typeChecker.anyType, /* deprecated= */ true, "Color3:ToHSV"}}}; addGlobalBinding(frontend, "Color3", Binding{colorType, {}}); diff --git a/tests/Module.test.cpp b/tests/Module.test.cpp index 33d9c75a..5f97fb6c 100644 --- a/tests/Module.test.cpp +++ b/tests/Module.test.cpp @@ -59,14 +59,14 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_non_persistent_primitive") // Create a new number type that isn't persistent unfreeze(typeChecker.globalTypes); - TypeId oldNumber = typeChecker.globalTypes.addType(PrimitiveTypeVar{PrimitiveTypeVar::Number}); + TypeId oldNumber = typeChecker.globalTypes.addType(PrimitiveType{PrimitiveType::Number}); freeze(typeChecker.globalTypes); TypeId newNumber = clone(oldNumber, dest, cloneState); CHECK_NE(newNumber, oldNumber); CHECK_EQ(*oldNumber, *newNumber); CHECK_EQ("number", toString(newNumber)); - CHECK_EQ(1, dest.typeVars.size()); + CHECK_EQ(1, dest.types.size()); } TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table") @@ -91,7 +91,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table") CloneState cloneState; TypeId counterCopy = clone(counterType, dest, cloneState); - TableTypeVar* ttv = getMutable(counterCopy); + TableType* ttv = getMutable(counterCopy); REQUIRE(ttv != nullptr); CHECK_EQ(std::optional{"Cyclic"}, ttv->syntheticName); @@ -99,7 +99,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table") TypeId methodType = ttv->props["get"].type; REQUIRE(methodType != nullptr); - const FunctionTypeVar* ftv = get(methodType); + const FunctionType* ftv = get(methodType); REQUIRE(ftv != nullptr); std::optional methodReturnType = first(ftv->retTypes); @@ -107,7 +107,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table") CHECK_EQ(methodReturnType, counterCopy); CHECK_EQ(2, dest.typePacks.size()); // one for the function args, and another for its return type - CHECK_EQ(2, dest.typeVars.size()); // One table and one function + CHECK_EQ(2, dest.types.size()); // One table and one function } TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_point_into_globalTypes_arena") @@ -124,7 +124,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_point_into_globalTypes_arena") REQUIRE(isInArena(*exports, module->interfaceTypes)); - TableTypeVar* exportsTable = getMutable(*exports); + TableType* exportsTable = getMutable(*exports); REQUIRE(exportsTable != nullptr); TypeId signType = exportsTable->props["sign"].type; @@ -143,13 +143,13 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_union") CloneState cloneState; unfreeze(typeChecker.globalTypes); - TypeId oldUnion = typeChecker.globalTypes.addType(UnionTypeVar{{typeChecker.numberType, typeChecker.stringType}}); + TypeId oldUnion = typeChecker.globalTypes.addType(UnionType{{typeChecker.numberType, typeChecker.stringType}}); freeze(typeChecker.globalTypes); TypeId newUnion = clone(oldUnion, dest, cloneState); CHECK_NE(newUnion, oldUnion); CHECK_EQ("number | string", toString(newUnion)); - CHECK_EQ(1, dest.typeVars.size()); + CHECK_EQ(1, dest.types.size()); } TEST_CASE_FIXTURE(Fixture, "deepClone_intersection") @@ -158,23 +158,23 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_intersection") CloneState cloneState; unfreeze(typeChecker.globalTypes); - TypeId oldIntersection = typeChecker.globalTypes.addType(IntersectionTypeVar{{typeChecker.numberType, typeChecker.stringType}}); + TypeId oldIntersection = typeChecker.globalTypes.addType(IntersectionType{{typeChecker.numberType, typeChecker.stringType}}); freeze(typeChecker.globalTypes); TypeId newIntersection = clone(oldIntersection, dest, cloneState); CHECK_NE(newIntersection, oldIntersection); CHECK_EQ("number & string", toString(newIntersection)); - CHECK_EQ(1, dest.typeVars.size()); + CHECK_EQ(1, dest.types.size()); } TEST_CASE_FIXTURE(Fixture, "clone_class") { - TypeVar exampleMetaClass{ClassTypeVar{"ExampleClassMeta", + Type exampleMetaClass{ClassType{"ExampleClassMeta", { {"__add", {typeChecker.anyType}}, }, std::nullopt, std::nullopt, {}, {}, "Test"}}; - TypeVar exampleClass{ClassTypeVar{"ExampleClass", + Type exampleClass{ClassType{"ExampleClass", { {"PropOne", {typeChecker.numberType}}, {"PropTwo", {typeChecker.stringType}}, @@ -185,11 +185,11 @@ TEST_CASE_FIXTURE(Fixture, "clone_class") CloneState cloneState; TypeId cloned = clone(&exampleClass, dest, cloneState); - const ClassTypeVar* ctv = get(cloned); + const ClassType* ctv = get(cloned); REQUIRE(ctv != nullptr); REQUIRE(ctv->metatable); - const ClassTypeVar* metatable = get(*ctv->metatable); + const ClassType* metatable = get(*ctv->metatable); REQUIRE(metatable); CHECK_EQ("ExampleClass", ctv->name); @@ -198,14 +198,14 @@ TEST_CASE_FIXTURE(Fixture, "clone_class") TEST_CASE_FIXTURE(Fixture, "clone_free_types") { - TypeVar freeTy(FreeTypeVar{TypeLevel{}}); + Type freeTy(FreeType{TypeLevel{}}); TypePackVar freeTp(FreeTypePack{TypeLevel{}}); TypeArena dest; CloneState cloneState; TypeId clonedTy = clone(&freeTy, dest, cloneState); - CHECK(get(clonedTy)); + CHECK(get(clonedTy)); cloneState = {}; TypePackId clonedTp = clone(&freeTp, dest, cloneState); @@ -214,15 +214,15 @@ TEST_CASE_FIXTURE(Fixture, "clone_free_types") TEST_CASE_FIXTURE(Fixture, "clone_free_tables") { - TypeVar tableTy{TableTypeVar{}}; - TableTypeVar* ttv = getMutable(&tableTy); + Type tableTy{TableType{}}; + TableType* ttv = getMutable(&tableTy); ttv->state = TableState::Free; TypeArena dest; CloneState cloneState; TypeId cloned = clone(&tableTy, dest, cloneState); - const TableTypeVar* clonedTtv = get(cloned); + const TableType* clonedTtv = get(cloned); CHECK_EQ(clonedTtv->state, TableState::Free); } @@ -264,14 +264,14 @@ TEST_CASE_FIXTURE(Fixture, "clone_recursion_limit") TypeArena src; - TypeId table = src.addType(TableTypeVar{}); + TypeId table = src.addType(TableType{}); TypeId nested = table; for (int i = 0; i < limit + 100; i++) { - TableTypeVar* ttv = getMutable(nested); + TableType* ttv = getMutable(nested); - ttv->props["a"].type = src.addType(TableTypeVar{}); + ttv->props["a"].type = src.addType(TableType{}); nested = ttv->props["a"].type; } @@ -332,7 +332,7 @@ return {} REQUIRE(modBiter != modB->getModuleScope()->exportedTypeBindings.end()); TypeId typeA = modAiter->second.type; TypeId typeB = modBiter->second.type; - TableTypeVar* tableB = getMutable(typeB); + TableType* tableB = getMutable(typeB); REQUIRE(tableB); CHECK(typeA == tableB->props["q"].type); } @@ -368,8 +368,8 @@ return exports std::optional typeB = first(modB->getModuleScope()->returnType); REQUIRE(typeA); REQUIRE(typeB); - TableTypeVar* tableA = getMutable(*typeA); - TableTypeVar* tableB = getMutable(*typeB); + TableType* tableA = getMutable(*typeA); + TableType* tableB = getMutable(*typeB); CHECK(tableA->props["a"].type == tableB->props["b"].type); } diff --git a/tests/NonstrictMode.test.cpp b/tests/NonstrictMode.test.cpp index 89aab5ee..8a25a5e5 100644 --- a/tests/NonstrictMode.test.cpp +++ b/tests/NonstrictMode.test.cpp @@ -1,7 +1,7 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/Scope.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Fixture.h" @@ -23,7 +23,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_nullary_function") TypeId fooType = requireType("foo"); REQUIRE(fooType); - const FunctionTypeVar* ftv = get(fooType); + const FunctionType* ftv = get(fooType); REQUIRE_MESSAGE(ftv != nullptr, "Expected a function, got " << toString(fooType)); auto args = flatten(ftv->argTypes).first; @@ -165,7 +165,7 @@ TEST_CASE_FIXTURE(Fixture, "table_props_are_any") LUAU_REQUIRE_NO_ERRORS(result); - TableTypeVar* ttv = getMutable(requireType("T")); + TableType* ttv = getMutable(requireType("T")); REQUIRE(ttv != nullptr); @@ -189,12 +189,12 @@ TEST_CASE_FIXTURE(Fixture, "inline_table_props_are_also_any") LUAU_REQUIRE_NO_ERRORS(result); - TableTypeVar* ttv = getMutable(requireType("T")); + TableType* ttv = getMutable(requireType("T")); REQUIRE_MESSAGE(ttv, "Should be a table: " << toString(requireType("T"))); CHECK_EQ(*typeChecker.anyType, *ttv->props["one"].type); CHECK_EQ(*typeChecker.anyType, *ttv->props["two"].type); - CHECK_MESSAGE(get(ttv->props["three"].type), "Should be a function: " << *ttv->props["three"].type); + CHECK_MESSAGE(get(ttv->props["three"].type), "Should be a function: " << *ttv->props["three"].type); } TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_iterator_variables_are_any") diff --git a/tests/Normalize.test.cpp b/tests/Normalize.test.cpp index e6bf00a1..ba9f5c52 100644 --- a/tests/Normalize.test.cpp +++ b/tests/Normalize.test.cpp @@ -3,7 +3,7 @@ #include "Fixture.h" #include "Luau/Common.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "doctest.h" #include "Luau/Normalize.h" @@ -17,7 +17,7 @@ struct IsSubtypeFixture : Fixture { bool isSubtype(TypeId a, TypeId b) { - return ::Luau::isSubtype(a, b, NotNull{getMainModule()->getModuleScope().get()}, singletonTypes, ice); + return ::Luau::isSubtype(a, b, NotNull{getMainModule()->getModuleScope().get()}, builtinTypes, ice); } }; } // namespace @@ -28,9 +28,9 @@ void createSomeClasses(Frontend& frontend) unfreeze(arena); - TypeId parentType = arena.addType(ClassTypeVar{"Parent", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}); + TypeId parentType = arena.addType(ClassType{"Parent", {}, frontend.builtinTypes->classType, std::nullopt, {}, nullptr, "Test"}); - ClassTypeVar* parentClass = getMutable(parentType); + ClassType* parentClass = getMutable(parentType); parentClass->props["method"] = {makeFunction(arena, parentType, {}, {})}; parentClass->props["virtual_method"] = {makeFunction(arena, parentType, {}, {})}; @@ -38,15 +38,15 @@ void createSomeClasses(Frontend& frontend) addGlobalBinding(frontend, "Parent", {parentType}); frontend.getGlobalScope()->exportedTypeBindings["Parent"] = TypeFun{{}, parentType}; - TypeId childType = arena.addType(ClassTypeVar{"Child", {}, parentType, std::nullopt, {}, nullptr, "Test"}); + TypeId childType = arena.addType(ClassType{"Child", {}, parentType, std::nullopt, {}, nullptr, "Test"}); - ClassTypeVar* childClass = getMutable(childType); + ClassType* childClass = getMutable(childType); childClass->props["virtual_method"] = {makeFunction(arena, childType, {}, {})}; addGlobalBinding(frontend, "Child", {childType}); frontend.getGlobalScope()->exportedTypeBindings["Child"] = TypeFun{{}, childType}; - TypeId unrelatedType = arena.addType(ClassTypeVar{"Unrelated", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}); + TypeId unrelatedType = arena.addType(ClassType{"Unrelated", {}, frontend.builtinTypes->classType, std::nullopt, {}, nullptr, "Test"}); addGlobalBinding(frontend, "Unrelated", {unrelatedType}); frontend.getGlobalScope()->exportedTypeBindings["Unrelated"] = TypeFun{{}, unrelatedType}; @@ -394,11 +394,12 @@ TEST_SUITE_END(); struct NormalizeFixture : Fixture { ScopedFastFlag sff1{"LuauNegatedFunctionTypes", true}; + ScopedFastFlag sff2{"LuauNegatedClassTypes", true}; TypeArena arena; InternalErrorReporter iceHandler; UnifierSharedState unifierState{&iceHandler}; - Normalizer normalizer{&arena, singletonTypes, NotNull{&unifierState}}; + Normalizer normalizer{&arena, builtinTypes, NotNull{&unifierState}}; NormalizeFixture() { @@ -524,7 +525,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "union_function_and_top_function") TEST_CASE_FIXTURE(NormalizeFixture, "negated_function_is_anything_except_a_function") { - CHECK("(boolean | number | string | thread)?" == toString(normal(R"( + ScopedFastFlag{"LuauNegatedClassTypes", true}; + + CHECK("(boolean | class | number | string | thread)?" == toString(normal(R"( Not )"))); } @@ -536,8 +539,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "specific_functions_cannot_be_negated") TEST_CASE_FIXTURE(NormalizeFixture, "bare_negated_boolean") { + ScopedFastFlag{"LuauNegatedClassTypes", true}; // TODO: We don't yet have a way to say number | string | thread | nil | Class | Table | Function - CHECK("(function | number | string | thread)?" == toString(normal(R"( + CHECK("(class | function | number | string | thread)?" == toString(normal(R"( Not )"))); } @@ -603,4 +607,61 @@ export type t0 = (((any)&({_:l0.t0,n0:t0,_G:any,}))&({_:any,}))&(((any)&({_:l0.t LUAU_REQUIRE_ERRORS(result); } +TEST_CASE_FIXTURE(NormalizeFixture, "unions_of_classes") +{ + ScopedFastFlag sff{"LuauNegatedClassTypes", true}; + + createSomeClasses(frontend); + CHECK("Parent | Unrelated" == toString(normal("Parent | Unrelated"))); + CHECK("Parent" == toString(normal("Parent | Child"))); + CHECK("Parent | Unrelated" == toString(normal("Parent | Child | Unrelated"))); +} + +TEST_CASE_FIXTURE(NormalizeFixture, "intersections_of_classes") +{ + ScopedFastFlag sff{"LuauNegatedClassTypes", true}; + + createSomeClasses(frontend); + CHECK("Child" == toString(normal("Parent & Child"))); + CHECK("never" == toString(normal("Child & Unrelated"))); +} + +TEST_CASE_FIXTURE(NormalizeFixture, "narrow_union_of_classes_with_intersection") +{ + ScopedFastFlag sff{"LuauNegatedClassTypes", true}; + + createSomeClasses(frontend); + CHECK("Child" == toString(normal("(Child | Unrelated) & Child"))); +} + +TEST_CASE_FIXTURE(NormalizeFixture, "negations_of_classes") +{ + ScopedFastFlag sff{"LuauNegatedClassTypes", true}; + + createSomeClasses(frontend); + CHECK("(Parent & ~Child) | Unrelated" == toString(normal("(Parent & Not) | Unrelated"))); + CHECK("((class & ~Child) | boolean | function | number | string | thread)?" == toString(normal("Not"))); + CHECK("Child" == toString(normal("Not & Child"))); + CHECK("((class & ~Parent) | Child | boolean | function | number | string | thread)?" == toString(normal("Not | Child"))); + CHECK("(boolean | function | number | string | thread)?" == toString(normal("Not"))); + CHECK("(Parent | Unrelated | boolean | function | number | string | thread)?" == + toString(normal("Not & Not & Not>"))); +} + +TEST_CASE_FIXTURE(NormalizeFixture, "classes_and_unknown") +{ + ScopedFastFlag sff{"LuauNegatedClassTypes", true}; + + createSomeClasses(frontend); + CHECK("Parent" == toString(normal("Parent & unknown"))); +} + +TEST_CASE_FIXTURE(NormalizeFixture, "classes_and_never") +{ + ScopedFastFlag sff{"LuauNegatedClassTypes", true}; + + createSomeClasses(frontend); + CHECK("never" == toString(normal("Parent & never"))); +} + TEST_SUITE_END(); diff --git a/tests/ToDot.test.cpp b/tests/ToDot.test.cpp index 26c9a1ee..dc08ae1c 100644 --- a/tests/ToDot.test.cpp +++ b/tests/ToDot.test.cpp @@ -17,16 +17,16 @@ struct ToDotClassFixture : Fixture unfreeze(arena); - TypeId baseClassMetaType = arena.addType(TableTypeVar{}); + TypeId baseClassMetaType = arena.addType(TableType{}); - TypeId baseClassInstanceType = arena.addType(ClassTypeVar{"BaseClass", {}, std::nullopt, baseClassMetaType, {}, {}, "Test"}); - getMutable(baseClassInstanceType)->props = { + TypeId baseClassInstanceType = arena.addType(ClassType{"BaseClass", {}, std::nullopt, baseClassMetaType, {}, {}, "Test"}); + getMutable(baseClassInstanceType)->props = { {"BaseField", {typeChecker.numberType}}, }; typeChecker.globalScope->exportedTypeBindings["BaseClass"] = TypeFun{{}, baseClassInstanceType}; - TypeId childClassInstanceType = arena.addType(ClassTypeVar{"ChildClass", {}, baseClassInstanceType, std::nullopt, {}, {}, "Test"}); - getMutable(childClassInstanceType)->props = { + TypeId childClassInstanceType = arena.addType(ClassType{"ChildClass", {}, baseClassInstanceType, std::nullopt, {}, {}, "Test"}); + getMutable(childClassInstanceType)->props = { {"ChildField", {typeChecker.stringType}}, }; typeChecker.globalScope->exportedTypeBindings["ChildClass"] = TypeFun{{}, childClassInstanceType}; @@ -66,12 +66,12 @@ n1 [label="any"]; opts.duplicatePrimitives = false; CHECK_EQ(R"(digraph graphname { -n1 [label="PrimitiveTypeVar number"]; +n1 [label="PrimitiveType number"]; })", toDot(requireType("b"), opts)); CHECK_EQ(R"(digraph graphname { -n1 [label="AnyTypeVar 1"]; +n1 [label="AnyType 1"]; })", toDot(requireType("c"), opts)); } @@ -90,7 +90,7 @@ local b = a() ToDotOptions opts; opts.showPointers = false; CHECK_EQ(R"(digraph graphname { -n1 [label="BoundTypeVar 1"]; +n1 [label="BoundType 1"]; n1 -> n2; n2 [label="number"]; })", @@ -110,11 +110,11 @@ local function f(a, ...: string) return a end opts.showPointers = false; CHECK_EQ(R"(digraph graphname { -n1 [label="FunctionTypeVar 1"]; +n1 [label="FunctionType 1"]; n1 -> n2 [label="arg"]; n2 [label="TypePack 2"]; n2 -> n3; -n3 [label="GenericTypeVar 3"]; +n3 [label="GenericType 3"]; n2 -> n4 [label="tail"]; n4 [label="VariadicTypePack 4"]; n4 -> n5; @@ -138,7 +138,7 @@ local a: string | number ToDotOptions opts; opts.showPointers = false; CHECK_EQ(R"(digraph graphname { -n1 [label="UnionTypeVar 1"]; +n1 [label="UnionType 1"]; n1 -> n2; n2 [label="string"]; n1 -> n3; @@ -157,7 +157,7 @@ local a: string & number -- uninhabited ToDotOptions opts; opts.showPointers = false; CHECK_EQ(R"(digraph graphname { -n1 [label="IntersectionTypeVar 1"]; +n1 [label="IntersectionType 1"]; n1 -> n2; n2 [label="string"]; n1 -> n3; @@ -177,11 +177,11 @@ local a: A ToDotOptions opts; opts.showPointers = false; CHECK_EQ(R"(digraph graphname { -n1 [label="TableTypeVar A"]; +n1 [label="TableType A"]; n1 -> n2 [label="x"]; n2 [label="number"]; n1 -> n3 [label="y"]; -n3 [label="FunctionTypeVar 3"]; +n3 [label="FunctionType 3"]; n3 -> n4 [label="arg"]; n4 [label="VariadicTypePack 4"]; n4 -> n5; @@ -212,47 +212,47 @@ local a: typeof(setmetatable({}, {})) ToDotOptions opts; opts.showPointers = false; CHECK_EQ(R"(digraph graphname { -n1 [label="MetatableTypeVar 1"]; +n1 [label="MetatableType 1"]; n1 -> n2 [label="table"]; -n2 [label="TableTypeVar 2"]; +n2 [label="TableType 2"]; n1 -> n3 [label="metatable"]; -n3 [label="TableTypeVar 3"]; +n3 [label="TableType 3"]; })", toDot(requireType("a"), opts)); } TEST_CASE_FIXTURE(Fixture, "free") { - TypeVar type{TypeVariant{FreeTypeVar{TypeLevel{0, 0}}}}; + Type type{TypeVariant{FreeType{TypeLevel{0, 0}}}}; ToDotOptions opts; opts.showPointers = false; CHECK_EQ(R"(digraph graphname { -n1 [label="FreeTypeVar 1"]; +n1 [label="FreeType 1"]; })", toDot(&type, opts)); } TEST_CASE_FIXTURE(Fixture, "error") { - TypeVar type{TypeVariant{ErrorTypeVar{}}}; + Type type{TypeVariant{ErrorType{}}}; ToDotOptions opts; opts.showPointers = false; CHECK_EQ(R"(digraph graphname { -n1 [label="ErrorTypeVar 1"]; +n1 [label="ErrorType 1"]; })", toDot(&type, opts)); } TEST_CASE_FIXTURE(Fixture, "generic") { - TypeVar type{TypeVariant{GenericTypeVar{"T"}}}; + Type type{TypeVariant{GenericType{"T"}}}; ToDotOptions opts; opts.showPointers = false; CHECK_EQ(R"(digraph graphname { -n1 [label="GenericTypeVar T"]; +n1 [label="GenericType T"]; })", toDot(&type, opts)); } @@ -267,15 +267,15 @@ local a: ChildClass ToDotOptions opts; opts.showPointers = false; CHECK_EQ(R"(digraph graphname { -n1 [label="ClassTypeVar ChildClass"]; +n1 [label="ClassType ChildClass"]; n1 -> n2 [label="ChildField"]; n2 [label="string"]; n1 -> n3 [label="[parent]"]; -n3 [label="ClassTypeVar BaseClass"]; +n3 [label="ClassType BaseClass"]; n3 -> n4 [label="BaseField"]; n4 [label="number"]; n3 -> n5 [label="[metatable]"]; -n5 [label="TableTypeVar 5"]; +n5 [label="TableType 5"]; })", toDot(requireType("a"), opts)); } @@ -358,16 +358,16 @@ b = a ToDotOptions opts; opts.showPointers = false; CHECK_EQ(R"(digraph graphname { -n1 [label="TableTypeVar 1"]; +n1 [label="TableType 1"]; n1 -> n2 [label="boundTo"]; -n2 [label="TableTypeVar a"]; +n2 [label="TableType a"]; n2 -> n3 [label="x"]; n3 [label="number"]; })", toDot(*ty, opts)); } -TEST_CASE_FIXTURE(Fixture, "singletontypes") +TEST_CASE_FIXTURE(Fixture, "builtintypes") { CheckResult result = check(R"( local x: "hi" | "\"hello\"" | true | false @@ -377,17 +377,17 @@ TEST_CASE_FIXTURE(Fixture, "singletontypes") opts.showPointers = false; CHECK_EQ(R"(digraph graphname { -n1 [label="UnionTypeVar 1"]; +n1 [label="UnionType 1"]; n1 -> n2; -n2 [label="SingletonTypeVar string: hi"]; +n2 [label="SingletonType string: hi"]; n1 -> n3; )" - "n3 [label=\"SingletonTypeVar string: \\\"hello\\\"\"];" + "n3 [label=\"SingletonType string: \\\"hello\\\"\"];" R"( n1 -> n4; -n4 [label="SingletonTypeVar boolean: true"]; +n4 [label="SingletonType boolean: true"]; n1 -> n5; -n5 [label="SingletonTypeVar boolean: false"]; +n5 [label="SingletonType boolean: false"]; })", toDot(requireType("x"), opts)); } diff --git a/tests/ToString.test.cpp b/tests/ToString.test.cpp index 05f49422..7ccda8de 100644 --- a/tests/ToString.test.cpp +++ b/tests/ToString.test.cpp @@ -5,6 +5,7 @@ #include "Fixture.h" +#include "ScopedFlags.h" #include "doctest.h" using namespace Luau; @@ -44,8 +45,8 @@ TEST_CASE_FIXTURE(Fixture, "free_types") TEST_CASE_FIXTURE(Fixture, "cyclic_table") { - TypeVar cyclicTable{TypeVariant(TableTypeVar())}; - TableTypeVar* tableOne = getMutable(&cyclicTable); + Type cyclicTable{TypeVariant(TableType())}; + TableType* tableOne = getMutable(&cyclicTable); tableOne->props["self"] = {&cyclicTable}; CHECK_EQ("t1 where t1 = { self: t1 }", toString(&cyclicTable)); @@ -53,8 +54,8 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_table") TEST_CASE_FIXTURE(Fixture, "named_table") { - TypeVar table{TypeVariant(TableTypeVar())}; - TableTypeVar* t = getMutable(&table); + Type table{TypeVariant(TableType())}; + TableType* t = getMutable(&table); t->name = "TheTable"; CHECK_EQ("TheTable", toString(&table)); @@ -94,19 +95,43 @@ TEST_CASE_FIXTURE(Fixture, "table_respects_use_line_break") //clang-format on } +TEST_CASE_FIXTURE(Fixture, "nil_or_nil_is_nil_not_question_mark") +{ + ScopedFastFlag sff("LuauSerializeNilUnionAsNil", true); + CheckResult result = check(R"( + type nil_ty = nil | nil + local a : nil_ty = nil + )"); + ToStringOptions opts; + opts.useLineBreaks = false; + CHECK_EQ("nil", toString(requireType("a"), opts)); +} + +TEST_CASE_FIXTURE(Fixture, "long_disjunct_of_nil_is_nil_not_question_mark") +{ + ScopedFastFlag sff("LuauSerializeNilUnionAsNil", true); + CheckResult result = check(R"( + type nil_ty = nil | nil | nil | nil | nil + local a : nil_ty = nil + )"); + ToStringOptions opts; + opts.useLineBreaks = false; + CHECK_EQ("nil", toString(requireType("a"), opts)); +} + TEST_CASE_FIXTURE(Fixture, "metatable") { - TypeVar table{TypeVariant(TableTypeVar())}; - TypeVar metatable{TypeVariant(TableTypeVar())}; - TypeVar mtv{TypeVariant(MetatableTypeVar{&table, &metatable})}; + Type table{TypeVariant(TableType())}; + Type metatable{TypeVariant(TableType())}; + Type mtv{TypeVariant(MetatableType{&table, &metatable})}; CHECK_EQ("{ @metatable { }, { } }", toString(&mtv)); } TEST_CASE_FIXTURE(Fixture, "named_metatable") { - TypeVar table{TypeVariant(TableTypeVar())}; - TypeVar metatable{TypeVariant(TableTypeVar())}; - TypeVar mtv{TypeVariant(MetatableTypeVar{&table, &metatable, "NamedMetatable"})}; + Type table{TypeVariant(TableType())}; + Type metatable{TypeVariant(TableType())}; + Type mtv{TypeVariant(MetatableType{&table, &metatable, "NamedMetatable"})}; CHECK_EQ("NamedMetatable", toString(&mtv)); } @@ -120,7 +145,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "named_metatable_toStringNamedFunction") )"); TypeId ty = requireType("createTbl"); - const FunctionTypeVar* ftv = get(follow(ty)); + const FunctionType* ftv = get(follow(ty)); REQUIRE(ftv); CHECK_EQ("createTbl(): NamedMetatable", toStringNamedFunction("createTbl", *ftv)); } @@ -162,16 +187,16 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "exhaustive_toString_of_cyclic_table") TEST_CASE_FIXTURE(Fixture, "intersection_parenthesized_only_if_needed") { - auto utv = TypeVar{UnionTypeVar{{typeChecker.numberType, typeChecker.stringType}}}; - auto itv = TypeVar{IntersectionTypeVar{{&utv, typeChecker.booleanType}}}; + auto utv = Type{UnionType{{typeChecker.numberType, typeChecker.stringType}}}; + auto itv = Type{IntersectionType{{&utv, typeChecker.booleanType}}}; CHECK_EQ(toString(&itv), "(number | string) & boolean"); } TEST_CASE_FIXTURE(Fixture, "union_parenthesized_only_if_needed") { - auto itv = TypeVar{IntersectionTypeVar{{typeChecker.numberType, typeChecker.stringType}}}; - auto utv = TypeVar{UnionTypeVar{{&itv, typeChecker.booleanType}}}; + auto itv = Type{IntersectionType{{typeChecker.numberType, typeChecker.stringType}}}; + auto utv = Type{UnionType{{&itv, typeChecker.booleanType}}}; CHECK_EQ(toString(&utv), "(number & string) | boolean"); } @@ -181,11 +206,11 @@ TEST_CASE_FIXTURE(Fixture, "functions_are_always_parenthesized_in_unions_or_inte auto stringAndNumberPack = TypePackVar{TypePack{{typeChecker.stringType, typeChecker.numberType}}}; auto numberAndStringPack = TypePackVar{TypePack{{typeChecker.numberType, typeChecker.stringType}}}; - auto sn2ns = TypeVar{FunctionTypeVar{&stringAndNumberPack, &numberAndStringPack}}; - auto ns2sn = TypeVar{FunctionTypeVar(typeChecker.globalScope->level, &numberAndStringPack, &stringAndNumberPack)}; + auto sn2ns = Type{FunctionType{&stringAndNumberPack, &numberAndStringPack}}; + auto ns2sn = Type{FunctionType(typeChecker.globalScope->level, &numberAndStringPack, &stringAndNumberPack)}; - auto utv = TypeVar{UnionTypeVar{{&ns2sn, &sn2ns}}}; - auto itv = TypeVar{IntersectionTypeVar{{&ns2sn, &sn2ns}}}; + auto utv = Type{UnionType{{&ns2sn, &sn2ns}}}; + auto itv = Type{IntersectionType{{&ns2sn, &sn2ns}}}; CHECK_EQ(toString(&utv), "((number, string) -> (string, number)) | ((string, number) -> (number, string))"); CHECK_EQ(toString(&itv), "((number, string) -> (string, number)) & ((string, number) -> (number, string))"); @@ -226,11 +251,11 @@ TEST_CASE_FIXTURE(Fixture, "unions_respects_use_line_breaks") TEST_CASE_FIXTURE(Fixture, "quit_stringifying_table_type_when_length_is_exceeded") { - TableTypeVar ttv{}; + TableType ttv{}; for (char c : std::string("abcdefghijklmno")) ttv.props[std::string(1, c)] = {typeChecker.numberType}; - TypeVar tv{ttv}; + Type tv{ttv}; ToStringOptions o; o.exhaustive = false; @@ -240,11 +265,11 @@ TEST_CASE_FIXTURE(Fixture, "quit_stringifying_table_type_when_length_is_exceeded TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_is_still_capped_when_exhaustive") { - TableTypeVar ttv{}; + TableType ttv{}; for (char c : std::string("abcdefg")) ttv.props[std::string(1, c)] = {typeChecker.numberType}; - TypeVar tv{ttv}; + Type tv{ttv}; ToStringOptions o; o.exhaustive = true; @@ -315,11 +340,11 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_type_is_still_capped_when_exhaustive") TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_correctly_use_matching_table_state_braces") { - TableTypeVar ttv{TableState::Sealed, TypeLevel{}}; + TableType ttv{TableState::Sealed, TypeLevel{}}; for (char c : std::string("abcdefghij")) ttv.props[std::string(1, c)] = {typeChecker.numberType}; - TypeVar tv{ttv}; + Type tv{ttv}; ToStringOptions o; o.maxTableLength = 40; @@ -328,8 +353,8 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_correctly_use_matching_table TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_union_type_bails_early") { - TypeVar tv{UnionTypeVar{{typeChecker.stringType, typeChecker.numberType}}}; - UnionTypeVar* utv = getMutable(&tv); + Type tv{UnionType{{typeChecker.stringType, typeChecker.numberType}}}; + UnionType* utv = getMutable(&tv); utv->options.push_back(&tv); utv->options.push_back(&tv); @@ -338,8 +363,8 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_union_type_bails_early") TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_intersection_type_bails_early") { - TypeVar tv{IntersectionTypeVar{}}; - IntersectionTypeVar* itv = getMutable(&tv); + Type tv{IntersectionType{}}; + IntersectionType* itv = getMutable(&tv); itv->parts.push_back(&tv); itv->parts.push_back(&tv); @@ -348,17 +373,17 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_intersection_type_bails_early") TEST_CASE_FIXTURE(Fixture, "stringifying_array_uses_array_syntax") { - TableTypeVar ttv{TableState::Sealed, TypeLevel{}}; + TableType ttv{TableState::Sealed, TypeLevel{}}; ttv.indexer = TableIndexer{typeChecker.numberType, typeChecker.stringType}; - CHECK_EQ("{string}", toString(TypeVar{ttv})); + CHECK_EQ("{string}", toString(Type{ttv})); ttv.props["A"] = {typeChecker.numberType}; - CHECK_EQ("{| [number]: string, A: number |}", toString(TypeVar{ttv})); + CHECK_EQ("{| [number]: string, A: number |}", toString(Type{ttv})); ttv.props.clear(); ttv.state = TableState::Unsealed; - CHECK_EQ("{string}", toString(TypeVar{ttv})); + CHECK_EQ("{string}", toString(Type{ttv})); } @@ -367,7 +392,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_packs_are_stringified_differently_from_gener TypePackVar tpv{GenericTypePack{"a"}}; CHECK_EQ(toString(&tpv), "a..."); - TypeVar tv{GenericTypeVar{"a"}}; + Type tv{GenericType{"a"}}; CHECK_EQ(toString(&tv), "a"); } @@ -444,11 +469,11 @@ TEST_CASE_FIXTURE(Fixture, "toStringDetailed") TypeId id3Type = requireType("id3"); ToStringResult nameData = toStringDetailed(id3Type, opts); - REQUIRE(3 == opts.nameMap.typeVars.size()); + REQUIRE(3 == opts.nameMap.types.size()); REQUIRE_EQ("(a, b, c) -> (a, b, c)", nameData.name); - const FunctionTypeVar* ftv = get(follow(id3Type)); + const FunctionType* ftv = get(follow(id3Type)); REQUIRE(ftv != nullptr); auto params = flatten(ftv->argTypes).first; @@ -483,27 +508,27 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "toStringDetailed2") TypeId tType = requireType("inst"); ToStringResult r = toStringDetailed(tType, opts); CHECK_EQ("{ @metatable { __index: { @metatable {| __index: base |}, child } }, inst }", r.name); - CHECK(0 == opts.nameMap.typeVars.size()); + CHECK(0 == opts.nameMap.types.size()); - const MetatableTypeVar* tMeta = get(tType); + const MetatableType* tMeta = get(tType); REQUIRE(tMeta); - TableTypeVar* tMeta2 = getMutable(tMeta->metatable); + TableType* tMeta2 = getMutable(tMeta->metatable); REQUIRE(tMeta2); REQUIRE(tMeta2->props.count("__index")); - const MetatableTypeVar* tMeta3 = get(tMeta2->props["__index"].type); + const MetatableType* tMeta3 = get(tMeta2->props["__index"].type); REQUIRE(tMeta3); - TableTypeVar* tMeta4 = getMutable(tMeta3->metatable); + TableType* tMeta4 = getMutable(tMeta3->metatable); REQUIRE(tMeta4); REQUIRE(tMeta4->props.count("__index")); - TableTypeVar* tMeta5 = getMutable(tMeta4->props["__index"].type); + TableType* tMeta5 = getMutable(tMeta4->props["__index"].type); REQUIRE(tMeta5); REQUIRE(tMeta5->props.count("one") > 0); - TableTypeVar* tMeta6 = getMutable(tMeta3->table); + TableType* tMeta6 = getMutable(tMeta3->table); REQUIRE(tMeta6); REQUIRE(tMeta6->props.count("two") > 0); @@ -537,16 +562,16 @@ function foo(a, b) return a(b) end TEST_CASE_FIXTURE(Fixture, "toString_the_boundTo_table_type_contained_within_a_TypePack") { - TypeVar tv1{TableTypeVar{}}; - TableTypeVar* ttv = getMutable(&tv1); + Type tv1{TableType{}}; + TableType* ttv = getMutable(&tv1); ttv->state = TableState::Sealed; ttv->props["hello"] = {typeChecker.numberType}; ttv->props["world"] = {typeChecker.numberType}; TypePackVar tpv1{TypePack{{&tv1}}}; - TypeVar tv2{TableTypeVar{}}; - TableTypeVar* bttv = getMutable(&tv2); + Type tv2{TableType{}}; + TableType* bttv = getMutable(&tv2); bttv->state = TableState::Free; bttv->props["hello"] = {typeChecker.numberType}; bttv->boundTo = &tv1; @@ -560,12 +585,12 @@ TEST_CASE_FIXTURE(Fixture, "toString_the_boundTo_table_type_contained_within_a_T TEST_CASE_FIXTURE(Fixture, "no_parentheses_around_return_type_if_pack_has_an_empty_head_link") { TypeArena arena; - TypePackId realTail = arena.addTypePack({singletonTypes->stringType}); + TypePackId realTail = arena.addTypePack({builtinTypes->stringType}); TypePackId emptyTail = arena.addTypePack({}, realTail); - TypePackId argList = arena.addTypePack({singletonTypes->stringType}); + TypePackId argList = arena.addTypePack({builtinTypes->stringType}); - TypeId functionType = arena.addType(FunctionTypeVar{argList, emptyTail}); + TypeId functionType = arena.addType(FunctionType{argList, emptyTail}); CHECK("(string) -> string" == toString(functionType)); } @@ -597,8 +622,8 @@ TEST_CASE_FIXTURE(Fixture, "no_parentheses_around_cyclic_function_type_in_inters TEST_CASE_FIXTURE(Fixture, "self_recursive_instantiated_param") { - TypeVar tableTy{TableTypeVar{}}; - TableTypeVar* ttv = getMutable(&tableTy); + Type tableTy{TableType{}}; + TableType* ttv = getMutable(&tableTy); ttv->name = "Table"; ttv->instantiatedTypeParams.push_back(&tableTy); @@ -612,7 +637,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_id") )"); TypeId ty = requireType("id"); - const FunctionTypeVar* ftv = get(follow(ty)); + const FunctionType* ftv = get(follow(ty)); CHECK_EQ("id(x: a): a", toStringNamedFunction("id", *ftv)); } @@ -630,7 +655,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_map") )"); TypeId ty = requireType("map"); - const FunctionTypeVar* ftv = get(follow(ty)); + const FunctionType* ftv = get(follow(ty)); CHECK_EQ("map(arr: {a}, fn: (a) -> b): {b}", toStringNamedFunction("map", *ftv)); } @@ -646,7 +671,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_generic_pack") )"); TypeId ty = requireType("test"); - const FunctionTypeVar* ftv = get(follow(ty)); + const FunctionType* ftv = get(follow(ty)); CHECK_EQ("test(...: T...): U...", toStringNamedFunction("test", *ftv)); } @@ -654,7 +679,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_generic_pack") TEST_CASE("toStringNamedFunction_unit_f") { TypePackVar empty{TypePack{}}; - FunctionTypeVar ftv{&empty, &empty, {}, false}; + FunctionType ftv{&empty, &empty, {}, false}; CHECK_EQ("f(): ()", toStringNamedFunction("f", ftv)); } @@ -667,7 +692,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics") )"); TypeId ty = requireType("f"); - auto ftv = get(follow(ty)); + auto ftv = get(follow(ty)); CHECK_EQ("f(x: a, ...: any): (a, a, b...)", toStringNamedFunction("f", *ftv)); } @@ -681,7 +706,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics2") )"); TypeId ty = requireType("f"); - auto ftv = get(follow(ty)); + auto ftv = get(follow(ty)); CHECK_EQ("f(): ...number", toStringNamedFunction("f", *ftv)); } @@ -695,7 +720,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics3") )"); TypeId ty = requireType("f"); - auto ftv = get(follow(ty)); + auto ftv = get(follow(ty)); CHECK_EQ("f(): (string, ...number)", toStringNamedFunction("f", *ftv)); } @@ -707,7 +732,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_type_annotation_has_partial_ar )"); TypeId ty = requireType("f"); - auto ftv = get(follow(ty)); + auto ftv = get(follow(ty)); CHECK_EQ("f(_: number, y: number): number", toStringNamedFunction("f", *ftv)); } @@ -720,7 +745,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_hide_type_params") )"); TypeId ty = requireType("f"); - auto ftv = get(follow(ty)); + auto ftv = get(follow(ty)); ToStringOptions opts; opts.hideNamedFunctionTypeParameters = true; @@ -734,7 +759,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_overrides_param_names") )"); TypeId ty = requireType("test"); - const FunctionTypeVar* ftv = get(follow(ty)); + const FunctionType* ftv = get(follow(ty)); ToStringOptions opts; opts.namedFunctionOverrideArgNames = {"first", "second", "third"}; @@ -763,8 +788,8 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_include_self_param") )"); TypeId parentTy = requireType("foo"); - auto ttv = get(follow(parentTy)); - auto ftv = get(ttv->props.at("method").type); + auto ttv = get(follow(parentTy)); + auto ftv = get(ttv->props.at("method").type); CHECK_EQ("foo:method(self: a, arg: string): ()", toStringNamedFunction("foo:method", *ftv)); } @@ -782,8 +807,8 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_hide_self_param") )"); TypeId parentTy = requireType("foo"); - auto ttv = get(follow(parentTy)); - auto ftv = get(ttv->props.at("method").type); + auto ttv = get(follow(parentTy)); + auto ftv = get(ttv->props.at("method").type); ToStringOptions opts; opts.hideFunctionSelfArgument = true; diff --git a/tests/Transpiler.test.cpp b/tests/Transpiler.test.cpp index e79bc9b7..bcaf088e 100644 --- a/tests/Transpiler.test.cpp +++ b/tests/Transpiler.test.cpp @@ -2,7 +2,7 @@ #include "Luau/Parser.h" #include "Luau/TypeAttach.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/Transpiler.h" #include "Fixture.h" diff --git a/tests/TypeInfer.aliases.test.cpp b/tests/TypeInfer.aliases.test.cpp index 38e246c8..4dd82269 100644 --- a/tests/TypeInfer.aliases.test.cpp +++ b/tests/TypeInfer.aliases.test.cpp @@ -78,8 +78,8 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias") Location{{1, 21}, {1, 26}}, getMainSourceModule()->name, TypeMismatch{ - singletonTypes->numberType, - singletonTypes->stringType, + builtinTypes->numberType, + builtinTypes->stringType, }, }); } @@ -89,8 +89,8 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias") Location{{1, 8}, {1, 26}}, getMainSourceModule()->name, TypeMismatch{ - singletonTypes->numberType, - singletonTypes->stringType, + builtinTypes->numberType, + builtinTypes->stringType, }, }); } @@ -512,13 +512,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "general_require_multi_assign") std::optional aTypeId = lookupName(m->getModuleScope(), "a"); REQUIRE(aTypeId); - const Luau::TableTypeVar* aType = get(follow(*aTypeId)); + const Luau::TableType* aType = get(follow(*aTypeId)); REQUIRE(aType); REQUIRE(aType->props.size() == 2); std::optional bTypeId = lookupName(m->getModuleScope(), "b"); REQUIRE(bTypeId); - const Luau::TableTypeVar* bType = get(follow(*bTypeId)); + const Luau::TableType* bType = get(follow(*bTypeId)); REQUIRE(bType); REQUIRE(bType->props.size() == 3); } @@ -535,7 +535,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_import_mutation") else CHECK(toString(ty) == "table"); - const TableTypeVar* ttv = get(ty); + const TableType* ttv = get(ty); REQUIRE(ttv); CHECK(ttv->instantiatedTypeParams.empty()); @@ -554,7 +554,7 @@ type NotCool = Cool REQUIRE(ty); CHECK_EQ(toString(*ty), "Cool"); - const TableTypeVar* ttv = get(*ty); + const TableType* ttv = get(*ty); REQUIRE(ttv); CHECK(ttv->instantiatedTypeParams.empty()); @@ -590,7 +590,7 @@ type Cool = typeof(c) std::optional ty = requireType("c"); REQUIRE(ty); - const TableTypeVar* ttv = get(*ty); + const TableType* ttv = get(*ty); REQUIRE(ttv); CHECK_EQ(ttv->name, "Cool"); } @@ -801,9 +801,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_quantify_unresolved_aliases") } /* - * We keep a cache of type alias onto TypeVar to prevent infinite types from + * We keep a cache of type alias onto Type to prevent infinite types from * being constructed via recursive or corecursive aliases. We have to adjust - * the TypeLevels of those generic TypeVars so that the unifier doesn't think + * the TypeLevels of those generic Types so that the unifier doesn't think * they have improperly leaked out of their scope. */ TEST_CASE_FIXTURE(Fixture, "generic_typevars_are_not_considered_to_escape_their_scope_if_they_are_reused_in_multiple_aliases") @@ -817,7 +817,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_typevars_are_not_considered_to_escape_their_ } /* - * The two-pass alias definition system starts by ascribing a free TypeVar to each alias. It then + * The two-pass alias definition system starts by ascribing a free Type to each alias. It then * circles back to fill in the actual type later on. * * If this free type is unified with something degenerate like `any`, we need to take extra care @@ -913,11 +913,11 @@ TEST_CASE_FIXTURE(Fixture, "report_shadowed_aliases") std::optional t1 = lookupType("MyString"); REQUIRE(t1); - CHECK(isPrim(*t1, PrimitiveTypeVar::String)); + CHECK(isPrim(*t1, PrimitiveType::String)); std::optional t2 = lookupType("string"); REQUIRE(t2); - CHECK(isPrim(*t2, PrimitiveTypeVar::String)); + CHECK(isPrim(*t2, PrimitiveType::String)); } TEST_CASE_FIXTURE(Fixture, "it_is_ok_to_shadow_user_defined_alias") diff --git a/tests/TypeInfer.annotations.test.cpp b/tests/TypeInfer.annotations.test.cpp index b94e1df0..bf66ecbc 100644 --- a/tests/TypeInfer.annotations.test.cpp +++ b/tests/TypeInfer.annotations.test.cpp @@ -1,7 +1,7 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/BuiltinDefinitions.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Fixture.h" @@ -77,7 +77,7 @@ TEST_CASE_FIXTURE(Fixture, "function_return_annotations_are_checked") LUAU_REQUIRE_NO_ERRORS(result); TypeId fiftyType = requireType("fifty"); - const FunctionTypeVar* ftv = get(fiftyType); + const FunctionType* ftv = get(fiftyType); REQUIRE(ftv != nullptr); TypePackId retPack = follow(ftv->retTypes); @@ -182,8 +182,8 @@ TEST_CASE_FIXTURE(Fixture, "table_annotation") )"); LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ(PrimitiveTypeVar::Number, getPrimitiveType(follow(requireType("y")))); - CHECK_EQ(PrimitiveTypeVar::String, getPrimitiveType(follow(requireType("z")))); + CHECK_EQ(PrimitiveType::Number, getPrimitiveType(follow(requireType("y")))); + CHECK_EQ(PrimitiveType::String, getPrimitiveType(follow(requireType("z")))); } TEST_CASE_FIXTURE(Fixture, "function_annotation") @@ -196,7 +196,7 @@ TEST_CASE_FIXTURE(Fixture, "function_annotation") dumpErrors(result); TypeId fType = requireType("f"); - const FunctionTypeVar* ftv = get(follow(fType)); + const FunctionType* ftv = get(follow(fType)); REQUIRE(ftv != nullptr); } @@ -208,7 +208,7 @@ TEST_CASE_FIXTURE(Fixture, "function_annotation_with_a_defined_function") )"); TypeId fType = requireType("f"); - const FunctionTypeVar* ftv = get(follow(fType)); + const FunctionType* ftv = get(follow(fType)); REQUIRE(ftv != nullptr); LUAU_REQUIRE_NO_ERRORS(result); @@ -323,13 +323,13 @@ TEST_CASE_FIXTURE(Fixture, "self_referential_type_alias") REQUIRE(res); TypeId oType = follow(res->type); - const TableTypeVar* oTable = get(oType); + const TableType* oTable = get(oType); REQUIRE(oTable); std::optional incr = get(oTable->props, "incr"); REQUIRE(incr); - const FunctionTypeVar* incrFunc = get(incr->type); + const FunctionType* incrFunc = get(incr->type); REQUIRE(incrFunc); std::optional firstArg = first(incrFunc->argTypes); @@ -441,7 +441,7 @@ TEST_CASE_FIXTURE(Fixture, "corecursive_types_error_on_tight_loop") )"); TypeId fType = requireType("aa"); - const AnyTypeVar* ftv = get(follow(fType)); + const AnyType* ftv = get(follow(fType)); REQUIRE(ftv != nullptr); REQUIRE(!result.errors.empty()); } @@ -483,7 +483,7 @@ TEST_CASE_FIXTURE(Fixture, "interface_types_belong_to_interface_arena") std::optional exportsType = first(mod.getModuleScope()->returnType); REQUIRE(exportsType); - TableTypeVar* exportsTable = getMutable(*exportsType); + TableType* exportsTable = getMutable(*exportsType); REQUIRE(exportsTable != nullptr); TypeId n = exportsTable->props["n"].type; @@ -509,7 +509,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_aliases_are_cloned_properly") REQUIRE_EQ(1, array.typeParams.size()); - const TableTypeVar* arrayTable = get(array.type); + const TableType* arrayTable = get(array.type); REQUIRE(arrayTable != nullptr); CHECK_EQ(0, arrayTable->props.size()); @@ -538,7 +538,7 @@ TEST_CASE_FIXTURE(Fixture, "cloned_interface_maintains_pointers_between_definiti std::optional exportsType = first(mod.getModuleScope()->returnType); REQUIRE(exportsType); - TableTypeVar* exportsTable = getMutable(*exportsType); + TableType* exportsTable = getMutable(*exportsType); REQUIRE(exportsTable != nullptr); TypeId aType = exportsTable->props["a"].type; @@ -740,8 +740,8 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_type_fun_should_not_trip_rbxassert") } #if 0 -// This is because, after visiting all nodes in a block, we check if each type alias still points to a FreeTypeVar. -// Doing it that way is wrong, but I also tried to make typeof(x) return a BoundTypeVar, with no luck. +// This is because, after visiting all nodes in a block, we check if each type alias still points to a FreeType. +// Doing it that way is wrong, but I also tried to make typeof(x) return a BoundType, with no luck. // Not important enough to fix today. TEST_CASE_FIXTURE(Fixture, "pulling_a_type_from_value_dont_falsely_create_occurs_check_failed") { @@ -755,7 +755,7 @@ TEST_CASE_FIXTURE(Fixture, "pulling_a_type_from_value_dont_falsely_create_occurs } #endif -TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_union_typevar") +TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_union_type") { CheckResult result = check(R"( type T = T | T @@ -767,7 +767,7 @@ TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_union_typevar") REQUIRE(ocf); } -TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_intersection_typevar") +TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_intersection_type") { CheckResult result = check(R"( type T = T & T diff --git a/tests/TypeInfer.anyerror.test.cpp b/tests/TypeInfer.anyerror.test.cpp index 91201812..9988a1fc 100644 --- a/tests/TypeInfer.anyerror.test.cpp +++ b/tests/TypeInfer.anyerror.test.cpp @@ -4,8 +4,8 @@ #include "Luau/BuiltinDefinitions.h" #include "Luau/Scope.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" #include "Fixture.h" @@ -175,7 +175,7 @@ TEST_CASE_FIXTURE(Fixture, "can_get_length_of_any") LUAU_REQUIRE_NO_ERRORS(result); - CHECK_EQ(PrimitiveTypeVar::Number, getPrimitiveType(requireType("bar"))); + CHECK_EQ(PrimitiveType::Number, getPrimitiveType(requireType("bar"))); } TEST_CASE_FIXTURE(Fixture, "assign_prop_to_table_by_calling_any_yields_any") @@ -191,7 +191,7 @@ TEST_CASE_FIXTURE(Fixture, "assign_prop_to_table_by_calling_any_yields_any") LUAU_REQUIRE_NO_ERRORS(result); - TableTypeVar* ttv = getMutable(requireType("T")); + TableType* ttv = getMutable(requireType("T")); REQUIRE(ttv); REQUIRE(ttv->props.count("prop")); diff --git a/tests/TypeInfer.builtins.test.cpp b/tests/TypeInfer.builtins.test.cpp index 32e31e16..6c2d3108 100644 --- a/tests/TypeInfer.builtins.test.cpp +++ b/tests/TypeInfer.builtins.test.cpp @@ -185,7 +185,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_tables_sealed") )LUA"); TypeId bit32 = requireType("b"); REQUIRE(bit32 != nullptr); - const TableTypeVar* bit32t = get(bit32); + const TableType* bit32t = get(bit32); REQUIRE(bit32t != nullptr); CHECK_EQ(bit32t->state, TableState::Sealed); } @@ -508,7 +508,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "setmetatable_should_not_mutate_persisted_typ LUAU_REQUIRE_ERROR_COUNT(1, result); auto stringType = requireType("string"); - auto ttv = get(stringType); + auto ttv = get(stringType); REQUIRE(ttv); } @@ -915,13 +915,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dont_add_definitions_to_persistent_types") LUAU_REQUIRE_NO_ERRORS(result); TypeId fType = requireType("f"); - const FunctionTypeVar* ftv = get(fType); + const FunctionType* ftv = get(fType); REQUIRE(fType); REQUIRE(fType->persistent); REQUIRE(!ftv->definition); TypeId gType = requireType("g"); - const FunctionTypeVar* gtv = get(gType); + const FunctionType* gtv = get(gType); REQUIRE(gType); REQUIRE(!gType->persistent); REQUIRE(gtv->definition); @@ -1029,9 +1029,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_persistent_typelevel_change") { TypeId mathTy = requireType(typeChecker.globalScope, "math"); REQUIRE(mathTy); - TableTypeVar* ttv = getMutable(mathTy); + TableType* ttv = getMutable(mathTy); REQUIRE(ttv); - const FunctionTypeVar* ftv = get(ttv->props["frexp"].type); + const FunctionType* ftv = get(ttv->props["frexp"].type); REQUIRE(ftv); auto original = ftv->level; diff --git a/tests/TypeInfer.classes.test.cpp b/tests/TypeInfer.classes.test.cpp index 07dfc33f..28315b67 100644 --- a/tests/TypeInfer.classes.test.cpp +++ b/tests/TypeInfer.classes.test.cpp @@ -2,7 +2,7 @@ #include "Luau/BuiltinDefinitions.h" #include "Luau/Common.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Fixture.h" #include "ClassFixture.h" diff --git a/tests/TypeInfer.definitions.test.cpp b/tests/TypeInfer.definitions.test.cpp index 26115046..93b405c2 100644 --- a/tests/TypeInfer.definitions.test.cpp +++ b/tests/TypeInfer.definitions.test.cpp @@ -1,7 +1,7 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/BuiltinDefinitions.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Fixture.h" @@ -294,7 +294,7 @@ TEST_CASE_FIXTURE(Fixture, "definitions_documentation_symbols") REQUIRE(bool(barTy)); CHECK_EQ(barTy->type->documentationSymbol, "@test/globaltype/Bar"); - ClassTypeVar* barClass = getMutable(barTy->type); + ClassType* barClass = getMutable(barTy->type); REQUIRE(bool(barClass)); REQUIRE_EQ(barClass->props.count("prop"), 1); CHECK_EQ(barClass->props["prop"].documentationSymbol, "@test/globaltype/Bar.prop"); @@ -303,7 +303,7 @@ TEST_CASE_FIXTURE(Fixture, "definitions_documentation_symbols") REQUIRE(bool(yBinding)); CHECK_EQ(yBinding->documentationSymbol, "@test/global/y"); - TableTypeVar* yTtv = getMutable(yBinding->typeId); + TableType* yTtv = getMutable(yBinding->typeId); REQUIRE(bool(yTtv)); REQUIRE_EQ(yTtv->props.count("x"), 1); CHECK_EQ(yTtv->props["x"].documentationSymbol, "@test/global/y.x"); diff --git a/tests/TypeInfer.functions.test.cpp b/tests/TypeInfer.functions.test.cpp index 55218040..a97cea21 100644 --- a/tests/TypeInfer.functions.test.cpp +++ b/tests/TypeInfer.functions.test.cpp @@ -5,8 +5,8 @@ #include "Luau/Error.h" #include "Luau/Scope.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" #include "Fixture.h" @@ -23,7 +23,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_function") CheckResult result = check("function five() return 5 end"); LUAU_REQUIRE_NO_ERRORS(result); - const FunctionTypeVar* fiveType = get(requireType("five")); + const FunctionType* fiveType = get(requireType("five")); REQUIRE(fiveType != nullptr); } @@ -64,7 +64,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_return_type") CheckResult result = check("function take_five() return 5 end"); LUAU_REQUIRE_NO_ERRORS(result); - const FunctionTypeVar* takeFiveType = get(requireType("take_five")); + const FunctionType* takeFiveType = get(requireType("take_five")); REQUIRE(takeFiveType != nullptr); std::vector retVec = flatten(takeFiveType->retTypes).first; @@ -132,7 +132,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "vararg_function_is_quantified") auto r = first(getMainModule()->getModuleScope()->returnType); REQUIRE(r); - TableTypeVar* ttv = getMutable(*r); + TableType* ttv = getMutable(*r); REQUIRE(ttv); REQUIRE(ttv->props.count("f")); @@ -389,14 +389,14 @@ TEST_CASE_FIXTURE(Fixture, "local_function") TypeId h = follow(requireType("h")); - const FunctionTypeVar* ftv = get(h); + const FunctionType* ftv = get(h); REQUIRE(ftv != nullptr); std::optional rt = first(ftv->retTypes); REQUIRE(bool(rt)); TypeId retType = follow(*rt); - CHECK_EQ(PrimitiveTypeVar::String, getPrimitiveType(retType)); + CHECK_EQ(PrimitiveType::String, getPrimitiveType(retType)); } TEST_CASE_FIXTURE(Fixture, "func_expr_doesnt_leak_free") @@ -406,11 +406,11 @@ TEST_CASE_FIXTURE(Fixture, "func_expr_doesnt_leak_free") )"); LUAU_REQUIRE_NO_ERRORS(result); - const Luau::FunctionTypeVar* fn = get(requireType("p")); + const Luau::FunctionType* fn = get(requireType("p")); REQUIRE(fn); auto ret = first(fn->retTypes); REQUIRE(ret); - REQUIRE(get(follow(*ret))); + REQUIRE(get(follow(*ret))); } TEST_CASE_FIXTURE(Fixture, "first_argument_can_be_optional") @@ -506,12 +506,12 @@ TEST_CASE_FIXTURE(Fixture, "complicated_return_types_require_an_explicit_annotat LUAU_REQUIRE_NO_ERRORS(result); TypeId ty = requireType("most_of_the_natural_numbers"); - const FunctionTypeVar* functionType = get(ty); + const FunctionType* functionType = get(ty); REQUIRE_MESSAGE(functionType, "Expected function but got " << toString(ty)); std::optional retType = first(functionType->retTypes); REQUIRE(retType); - CHECK(get(*retType)); + CHECK(get(*retType)); } TEST_CASE_FIXTURE(Fixture, "infer_higher_order_function") @@ -524,14 +524,14 @@ TEST_CASE_FIXTURE(Fixture, "infer_higher_order_function") LUAU_REQUIRE_NO_ERRORS(result); - const FunctionTypeVar* ftv = get(requireType("apply")); + const FunctionType* ftv = get(requireType("apply")); REQUIRE(ftv != nullptr); std::vector argVec = flatten(ftv->argTypes).first; REQUIRE_EQ(2, argVec.size()); - const FunctionTypeVar* fType = get(follow(argVec[0])); + const FunctionType* fType = get(follow(argVec[0])); REQUIRE_MESSAGE(fType != nullptr, "Expected a function but got " << toString(argVec[0])); std::vector fArgs = flatten(fType->argTypes).first; @@ -561,14 +561,14 @@ TEST_CASE_FIXTURE(Fixture, "higher_order_function_2") LUAU_REQUIRE_NO_ERRORS(result); - const FunctionTypeVar* ftv = get(requireType("bottomupmerge")); + const FunctionType* ftv = get(requireType("bottomupmerge")); REQUIRE(ftv != nullptr); std::vector argVec = flatten(ftv->argTypes).first; REQUIRE_EQ(6, argVec.size()); - const FunctionTypeVar* fType = get(follow(argVec[0])); + const FunctionType* fType = get(follow(argVec[0])); REQUIRE(fType != nullptr); } @@ -591,14 +591,14 @@ TEST_CASE_FIXTURE(Fixture, "higher_order_function_3") LUAU_REQUIRE_NO_ERRORS(result); - const FunctionTypeVar* ftv = get(requireType("swapTwice")); + const FunctionType* ftv = get(requireType("swapTwice")); REQUIRE(ftv != nullptr); std::vector argVec = flatten(ftv->argTypes).first; REQUIRE_EQ(1, argVec.size()); - const TableTypeVar* argType = get(follow(argVec[0])); + const TableType* argType = get(follow(argVec[0])); REQUIRE(argType != nullptr); CHECK(bool(argType->indexer)); @@ -648,18 +648,18 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "higher_order_function_4") * In other words, comp(arr[x], arr[y]) is well-typed. */ - const FunctionTypeVar* ftv = get(requireType("mergesort")); + const FunctionType* ftv = get(requireType("mergesort")); REQUIRE(ftv != nullptr); std::vector argVec = flatten(ftv->argTypes).first; REQUIRE_EQ(2, argVec.size()); - const TableTypeVar* arg0 = get(follow(argVec[0])); + const TableType* arg0 = get(follow(argVec[0])); REQUIRE(arg0 != nullptr); REQUIRE(bool(arg0->indexer)); - const FunctionTypeVar* arg1 = get(follow(argVec[1])); + const FunctionType* arg1 = get(follow(argVec[1])); REQUIRE(arg1 != nullptr); REQUIRE_EQ(2, size(arg1->argTypes)); @@ -1003,7 +1003,7 @@ TEST_CASE_FIXTURE(Fixture, "no_lossy_function_type") LUAU_REQUIRE_NO_ERRORS(result); TypeId type = requireTypeAtPosition(Position(6, 14)); CHECK_EQ("(tbl, number, number) -> number", toString(type)); - auto ftv = get(type); + auto ftv = get(type); REQUIRE(ftv); CHECK(ftv->hasSelf); } diff --git a/tests/TypeInfer.generics.test.cpp b/tests/TypeInfer.generics.test.cpp index c25f8e5f..7b417621 100644 --- a/tests/TypeInfer.generics.test.cpp +++ b/tests/TypeInfer.generics.test.cpp @@ -1,6 +1,6 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Luau/Scope.h" #include @@ -224,7 +224,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_function") LUAU_REQUIRE_NO_ERRORS(result); TypeId idType = requireType("id"); - const FunctionTypeVar* idFun = get(idType); + const FunctionType* idFun = get(idType); REQUIRE(idFun); auto [args, varargs] = flatten(idFun->argTypes); auto [rets, varrets] = flatten(idFun->retTypes); @@ -247,7 +247,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_local_function") LUAU_REQUIRE_NO_ERRORS(result); TypeId idType = requireType("id"); - const FunctionTypeVar* idFun = get(idType); + const FunctionType* idFun = get(idType); REQUIRE(idFun); auto [args, varargs] = flatten(idFun->argTypes); auto [rets, varrets] = flatten(idFun->retTypes); @@ -854,14 +854,14 @@ TEST_CASE_FIXTURE(Fixture, "generic_table_method") LUAU_REQUIRE_NO_ERRORS(result); TypeId tType = requireType("T"); - TableTypeVar* tTable = getMutable(tType); + TableType* tTable = getMutable(tType); REQUIRE(tTable != nullptr); REQUIRE(tTable->props.count("bar")); TypeId barType = tTable->props["bar"].type; REQUIRE(barType != nullptr); - const FunctionTypeVar* ftv = get(follow(barType)); + const FunctionType* ftv = get(follow(barType)); REQUIRE_MESSAGE(ftv != nullptr, "Should be a function: " << *barType); std::vector args = flatten(ftv->argTypes).first; @@ -887,20 +887,20 @@ TEST_CASE_FIXTURE(Fixture, "correctly_instantiate_polymorphic_member_functions") LUAU_REQUIRE_NO_ERRORS(result); dumpErrors(result); - const TableTypeVar* t = get(requireType("T")); + const TableType* t = get(requireType("T")); REQUIRE(t != nullptr); std::optional fooProp = get(t->props, "foo"); REQUIRE(bool(fooProp)); - const FunctionTypeVar* foo = get(follow(fooProp->type)); + const FunctionType* foo = get(follow(fooProp->type)); REQUIRE(bool(foo)); std::optional ret_ = first(foo->retTypes); REQUIRE(bool(ret_)); TypeId ret = follow(*ret_); - REQUIRE_EQ(getPrimitiveType(ret), PrimitiveTypeVar::Number); + REQUIRE_EQ(getPrimitiveType(ret), PrimitiveType::Number); } /* @@ -927,20 +927,20 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_cyclic_generic_function") )"); TypeId g = requireType("g"); - const FunctionTypeVar* gFun = get(g); + const FunctionType* gFun = get(g); REQUIRE(gFun != nullptr); auto optionArg = first(gFun->argTypes); REQUIRE(bool(optionArg)); TypeId arg = follow(*optionArg); - const TableTypeVar* argTable = get(arg); + const TableType* argTable = get(arg); REQUIRE(argTable != nullptr); std::optional methodProp = get(argTable->props, "method"); REQUIRE(bool(methodProp)); - const FunctionTypeVar* methodFunction = get(methodProp->type); + const FunctionType* methodFunction = get(methodProp->type); REQUIRE(methodFunction != nullptr); std::optional methodArg = first(methodFunction->argTypes); diff --git a/tests/TypeInfer.intersectionTypes.test.cpp b/tests/TypeInfer.intersectionTypes.test.cpp index 188be63c..b57d8820 100644 --- a/tests/TypeInfer.intersectionTypes.test.cpp +++ b/tests/TypeInfer.intersectionTypes.test.cpp @@ -1,6 +1,6 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Fixture.h" @@ -162,14 +162,14 @@ TEST_CASE_FIXTURE(Fixture, "index_on_an_intersection_type_with_property_guarante LUAU_REQUIRE_NO_ERRORS(result); - const IntersectionTypeVar* r = get(requireType("r")); + const IntersectionType* r = get(requireType("r")); REQUIRE(r); - TableTypeVar* a = getMutable(r->parts[0]); + TableType* a = getMutable(r->parts[0]); REQUIRE(a); CHECK_EQ(typeChecker.numberType, a->props["y"].type); - TableTypeVar* b = getMutable(r->parts[1]); + TableType* b = getMutable(r->parts[1]); REQUIRE(b); CHECK_EQ(typeChecker.numberType, b->props["y"].type); } diff --git a/tests/TypeInfer.loops.test.cpp b/tests/TypeInfer.loops.test.cpp index 40912a95..7a89df96 100644 --- a/tests/TypeInfer.loops.test.cpp +++ b/tests/TypeInfer.loops.test.cpp @@ -4,8 +4,8 @@ #include "Luau/BuiltinDefinitions.h" #include "Luau/Scope.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" #include "Fixture.h" diff --git a/tests/TypeInfer.modules.test.cpp b/tests/TypeInfer.modules.test.cpp index b06c80e9..fe52d168 100644 --- a/tests/TypeInfer.modules.test.cpp +++ b/tests/TypeInfer.modules.test.cpp @@ -4,7 +4,7 @@ #include "Luau/BuiltinDefinitions.h" #include "Luau/Scope.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Fixture.h" @@ -105,7 +105,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require_types") REQUIRE(b != nullptr); TypeId hType = requireType(b, "h"); - REQUIRE_MESSAGE(bool(get(hType)), "Expected table but got " << toString(hType)); + REQUIRE_MESSAGE(bool(get(hType)), "Expected table but got " << toString(hType)); } TEST_CASE_FIXTURE(BuiltinsFixture, "require_a_variadic_function") @@ -128,7 +128,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "require_a_variadic_function") TypeId f = follow(requireType(bModule, "f")); - const FunctionTypeVar* ftv = get(f); + const FunctionType* ftv = get(f); REQUIRE(ftv); auto iter = begin(ftv->argTypes); @@ -351,7 +351,7 @@ local arrayops = require(game.A) local tbl = {} tbl.a = 2 function tbl:foo(b: number, c: number) - -- introduce BoundTypeVar to imported type + -- introduce BoundType to imported type arrayops.foo(self._regions) end -- this alias decreases function type level and causes a demotion of its type @@ -376,7 +376,7 @@ local arrayops = require(game.A) local tbl = {} tbl.a = 2 function tbl:foo(b: number, c: number) - -- introduce boundTo TableTypeVar to imported type + -- introduce boundTo TableType to imported type self.x.a = 2 arrayops.foo(self.x) end diff --git a/tests/TypeInfer.negations.test.cpp b/tests/TypeInfer.negations.test.cpp index 0e7fb03d..02350a72 100644 --- a/tests/TypeInfer.negations.test.cpp +++ b/tests/TypeInfer.negations.test.cpp @@ -10,6 +10,7 @@ using namespace Luau; namespace { + struct NegationFixture : Fixture { TypeArena arena; @@ -22,6 +23,7 @@ struct NegationFixture : Fixture registerHiddenTypes(*this, arena); } }; + } // namespace TEST_SUITE_BEGIN("Negations"); diff --git a/tests/TypeInfer.oop.test.cpp b/tests/TypeInfer.oop.test.cpp index 41690704..088b4d56 100644 --- a/tests/TypeInfer.oop.test.cpp +++ b/tests/TypeInfer.oop.test.cpp @@ -4,8 +4,8 @@ #include "Luau/BuiltinDefinitions.h" #include "Luau/Scope.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" #include "Fixture.h" @@ -93,8 +93,8 @@ TEST_CASE_FIXTURE(Fixture, "methods_are_topologically_sorted") LUAU_REQUIRE_NO_ERRORS(result); dumpErrors(result); - CHECK_EQ(PrimitiveTypeVar::Number, getPrimitiveType(requireType("a"))); - CHECK_EQ(PrimitiveTypeVar::String, getPrimitiveType(requireType("b"))); + CHECK_EQ(PrimitiveType::Number, getPrimitiveType(requireType("a"))); + CHECK_EQ(PrimitiveType::String, getPrimitiveType(requireType("b"))); } TEST_CASE_FIXTURE(Fixture, "quantify_methods_defined_using_dot_syntax_and_explicit_self_parameter") @@ -139,7 +139,7 @@ TEST_CASE_FIXTURE(Fixture, "inferring_hundreds_of_self_calls_should_not_suffocat )"); ModulePtr module = getMainModule(); - CHECK_GE(50, module->internalTypes.typeVars.size()); + CHECK_GE(50, module->internalTypes.types.size()); } TEST_CASE_FIXTURE(BuiltinsFixture, "object_constructor_can_refer_to_method_of_self") diff --git a/tests/TypeInfer.operators.test.cpp b/tests/TypeInfer.operators.test.cpp index 93d7361b..0196666a 100644 --- a/tests/TypeInfer.operators.test.cpp +++ b/tests/TypeInfer.operators.test.cpp @@ -4,8 +4,8 @@ #include "Luau/BuiltinDefinitions.h" #include "Luau/Scope.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" #include "Fixture.h" #include "ClassFixture.h" @@ -125,7 +125,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "primitive_arith_no_metatable") LUAU_REQUIRE_NO_ERRORS(result); - const FunctionTypeVar* functionType = get(requireType("add")); + const FunctionType* functionType = get(requireType("add")); std::optional retType = first(functionType->retTypes); REQUIRE(retType.has_value()); @@ -1017,7 +1017,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "mm_ops_must_return_a_value") LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK(requireType("y") == singletonTypes->errorRecoveryType()); + CHECK(requireType("y") == builtinTypes->errorRecoveryType()); const GenericError* ge = get(result.errors[0]); REQUIRE(ge); @@ -1051,8 +1051,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "mm_comparisons_must_return_a_boolean") LUAU_REQUIRE_ERROR_COUNT(2, result); - CHECK(requireType("v1") == singletonTypes->booleanType); - CHECK(requireType("v2") == singletonTypes->booleanType); + CHECK(requireType("v1") == builtinTypes->booleanType); + CHECK(requireType("v2") == builtinTypes->booleanType); CHECK(toString(result.errors[0]) == "Metamethod '__lt' must return type 'boolean'"); CHECK(toString(result.errors[1]) == "Metamethod '__lt' must return type 'boolean'"); diff --git a/tests/TypeInfer.primitives.test.cpp b/tests/TypeInfer.primitives.test.cpp index 3c2c8781..7e99f0b0 100644 --- a/tests/TypeInfer.primitives.test.cpp +++ b/tests/TypeInfer.primitives.test.cpp @@ -4,8 +4,8 @@ #include "Luau/BuiltinDefinitions.h" #include "Luau/Scope.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" #include "Fixture.h" diff --git a/tests/TypeInfer.provisional.test.cpp b/tests/TypeInfer.provisional.test.cpp index b7408f87..cf969f2d 100644 --- a/tests/TypeInfer.provisional.test.cpp +++ b/tests/TypeInfer.provisional.test.cpp @@ -456,7 +456,7 @@ TEST_CASE_FIXTURE(Fixture, "dcr_can_partially_dispatch_a_constraint") // // (*blocked*) -> () <: (number) -> (b...) // - // We solve this by searching both types for BlockedTypeVars and block the + // We solve this by searching both types for BlockedTypes and block the // constraint on any we find. It also gets the job done, but I'm worried // about the efficiency of doing so many deep type traversals and it may // make us more prone to getting stuck on constraint cycles. @@ -473,19 +473,19 @@ TEST_CASE_FIXTURE(Fixture, "dcr_can_partially_dispatch_a_constraint") TEST_CASE_FIXTURE(Fixture, "free_options_cannot_be_unified_together") { TypeArena arena; - TypeId nilType = singletonTypes->nilType; + TypeId nilType = builtinTypes->nilType; - std::unique_ptr scope = std::make_unique(singletonTypes->anyTypePack); + std::unique_ptr scope = std::make_unique(builtinTypes->anyTypePack); TypeId free1 = arena.addType(FreeTypePack{scope.get()}); - TypeId option1 = arena.addType(UnionTypeVar{{nilType, free1}}); + TypeId option1 = arena.addType(UnionType{{nilType, free1}}); TypeId free2 = arena.addType(FreeTypePack{scope.get()}); - TypeId option2 = arena.addType(UnionTypeVar{{nilType, free2}}); + TypeId option2 = arena.addType(UnionType{{nilType, free2}}); InternalErrorReporter iceHandler; UnifierSharedState sharedState{&iceHandler}; - Normalizer normalizer{&arena, singletonTypes, NotNull{&sharedState}}; + Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}}; Unifier u{NotNull{&normalizer}, Mode::Strict, NotNull{scope.get()}, Location{}, Variance::Covariant}; u.tryUnify(option1, option2); @@ -550,7 +550,7 @@ return wrapStrictTable(Constants, "Constants") std::optional result = first(m->getModuleScope()->returnType); REQUIRE(result); - CHECK(get(*result)); + CHECK(get(*result)); } TEST_CASE_FIXTURE(BuiltinsFixture, "generic_type_leak_to_module_interface_variadic") @@ -589,7 +589,7 @@ return wrapStrictTable(Constants, "Constants") std::optional result = first(m->getModuleScope()->returnType); REQUIRE(result); - CHECK(get(*result)); + CHECK(get(*result)); } // We need a simplification step to make this do the right thing. ("normalization-lite") @@ -620,7 +620,7 @@ struct IsSubtypeFixture : Fixture { bool isSubtype(TypeId a, TypeId b) { - return ::Luau::isSubtype(a, b, NotNull{getMainModule()->getModuleScope().get()}, singletonTypes, ice); + return ::Luau::isSubtype(a, b, NotNull{getMainModule()->getModuleScope().get()}, builtinTypes, ice); } }; } // namespace diff --git a/tests/TypeInfer.refinements.test.cpp b/tests/TypeInfer.refinements.test.cpp index 5a7c8432..f77cacfa 100644 --- a/tests/TypeInfer.refinements.test.cpp +++ b/tests/TypeInfer.refinements.test.cpp @@ -8,6 +8,7 @@ #include "doctest.h" LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution) +LUAU_FASTFLAG(LuauNegatedClassTypes) using namespace Luau; @@ -63,30 +64,32 @@ struct RefinementClassFixture : BuiltinsFixture TypeArena& arena = typeChecker.globalTypes; NotNull scope{typeChecker.globalScope.get()}; + std::optional rootSuper = FFlag::LuauNegatedClassTypes ? std::make_optional(typeChecker.builtinTypes->classType) : std::nullopt; + unfreeze(arena); - TypeId vec3 = arena.addType(ClassTypeVar{"Vector3", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}); - getMutable(vec3)->props = { + TypeId vec3 = arena.addType(ClassType{"Vector3", {}, rootSuper, std::nullopt, {}, nullptr, "Test"}); + getMutable(vec3)->props = { {"X", Property{typeChecker.numberType}}, {"Y", Property{typeChecker.numberType}}, {"Z", Property{typeChecker.numberType}}, }; - TypeId inst = arena.addType(ClassTypeVar{"Instance", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}); + TypeId inst = arena.addType(ClassType{"Instance", {}, rootSuper, std::nullopt, {}, nullptr, "Test"}); TypePackId isAParams = arena.addTypePack({inst, typeChecker.stringType}); TypePackId isARets = arena.addTypePack({typeChecker.booleanType}); - TypeId isA = arena.addType(FunctionTypeVar{isAParams, isARets}); - getMutable(isA)->magicFunction = magicFunctionInstanceIsA; - getMutable(isA)->dcrMagicRefinement = dcrMagicRefinementInstanceIsA; + TypeId isA = arena.addType(FunctionType{isAParams, isARets}); + getMutable(isA)->magicFunction = magicFunctionInstanceIsA; + getMutable(isA)->dcrMagicRefinement = dcrMagicRefinementInstanceIsA; - getMutable(inst)->props = { + getMutable(inst)->props = { {"Name", Property{typeChecker.stringType}}, {"IsA", Property{isA}}, }; - TypeId folder = typeChecker.globalTypes.addType(ClassTypeVar{"Folder", {}, inst, std::nullopt, {}, nullptr, "Test"}); - TypeId part = typeChecker.globalTypes.addType(ClassTypeVar{"Part", {}, inst, std::nullopt, {}, nullptr, "Test"}); - getMutable(part)->props = { + TypeId folder = typeChecker.globalTypes.addType(ClassType{"Folder", {}, inst, std::nullopt, {}, nullptr, "Test"}); + TypeId part = typeChecker.globalTypes.addType(ClassType{"Part", {}, inst, std::nullopt, {}, nullptr, "Test"}); + getMutable(part)->props = { {"Position", Property{vec3}}, }; diff --git a/tests/TypeInfer.tables.test.cpp b/tests/TypeInfer.tables.test.cpp index c379559d..e2aa01f9 100644 --- a/tests/TypeInfer.tables.test.cpp +++ b/tests/TypeInfer.tables.test.cpp @@ -4,7 +4,7 @@ #include "Luau/Frontend.h" #include "Luau/ToString.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Fixture.h" @@ -27,20 +27,20 @@ TEST_CASE_FIXTURE(Fixture, "basic") CheckResult result = check("local t = {foo = \"bar\", baz = 9, quux = nil}"); LUAU_REQUIRE_NO_ERRORS(result); - const TableTypeVar* tType = get(requireType("t")); + const TableType* tType = get(requireType("t")); REQUIRE(tType != nullptr); std::optional fooProp = get(tType->props, "foo"); REQUIRE(bool(fooProp)); - CHECK_EQ(PrimitiveTypeVar::String, getPrimitiveType(fooProp->type)); + CHECK_EQ(PrimitiveType::String, getPrimitiveType(fooProp->type)); std::optional bazProp = get(tType->props, "baz"); REQUIRE(bool(bazProp)); - CHECK_EQ(PrimitiveTypeVar::Number, getPrimitiveType(bazProp->type)); + CHECK_EQ(PrimitiveType::Number, getPrimitiveType(bazProp->type)); std::optional quuxProp = get(tType->props, "quux"); REQUIRE(bool(quuxProp)); - CHECK_EQ(PrimitiveTypeVar::NilType, getPrimitiveType(quuxProp->type)); + CHECK_EQ(PrimitiveType::NilType, getPrimitiveType(quuxProp->type)); } TEST_CASE_FIXTURE(Fixture, "augment_table") @@ -48,7 +48,7 @@ TEST_CASE_FIXTURE(Fixture, "augment_table") CheckResult result = check("local t = {} t.foo = 'bar'"); LUAU_REQUIRE_NO_ERRORS(result); - const TableTypeVar* tType = get(requireType("t")); + const TableType* tType = get(requireType("t")); REQUIRE(tType != nullptr); CHECK("{ foo: string }" == toString(requireType("t"), {true})); @@ -59,11 +59,11 @@ TEST_CASE_FIXTURE(Fixture, "augment_nested_table") CheckResult result = check("local t = { p = {} } t.p.foo = 'bar'"); LUAU_REQUIRE_NO_ERRORS(result); - TableTypeVar* tType = getMutable(requireType("t")); + TableType* tType = getMutable(requireType("t")); REQUIRE(tType != nullptr); REQUIRE(tType->props.find("p") != tType->props.end()); - const TableTypeVar* pType = get(tType->props["p"].type); + const TableType* pType = get(tType->props["p"].type); REQUIRE(pType != nullptr); CHECK("{ p: { foo: string } }" == toString(requireType("t"), {true})); @@ -142,13 +142,13 @@ TEST_CASE_FIXTURE(Fixture, "tc_member_function") CheckResult result = check("local T = {} function T:foo() return 5 end"); LUAU_REQUIRE_NO_ERRORS(result); - const TableTypeVar* tableType = get(requireType("T")); + const TableType* tableType = get(requireType("T")); REQUIRE(tableType != nullptr); std::optional fooProp = get(tableType->props, "foo"); REQUIRE(bool(fooProp)); - const FunctionTypeVar* methodType = get(follow(fooProp->type)); + const FunctionType* methodType = get(follow(fooProp->type)); REQUIRE(methodType != nullptr); } @@ -157,20 +157,20 @@ TEST_CASE_FIXTURE(Fixture, "tc_member_function_2") CheckResult result = check("local T = {U={}} function T.U:foo() return 5 end"); LUAU_REQUIRE_NO_ERRORS(result); - const TableTypeVar* tableType = get(requireType("T")); + const TableType* tableType = get(requireType("T")); REQUIRE(tableType != nullptr); std::optional uProp = get(tableType->props, "U"); REQUIRE(bool(uProp)); TypeId uType = uProp->type; - const TableTypeVar* uTable = get(uType); + const TableType* uTable = get(uType); REQUIRE(uTable != nullptr); std::optional fooProp = get(uTable->props, "foo"); REQUIRE(bool(fooProp)); - const FunctionTypeVar* methodType = get(follow(fooProp->type)); + const FunctionType* methodType = get(follow(fooProp->type)); REQUIRE(methodType != nullptr); std::vector methodArgs = flatten(methodType->argTypes).first; @@ -324,7 +324,7 @@ TEST_CASE_FIXTURE(Fixture, "open_table_unification_3") )"); TypeId fooType = requireType("foo"); - const FunctionTypeVar* fooFn = get(fooType); + const FunctionType* fooFn = get(fooType); REQUIRE(fooFn != nullptr); std::vector fooArgs = flatten(fooFn->argTypes).first; @@ -332,7 +332,7 @@ TEST_CASE_FIXTURE(Fixture, "open_table_unification_3") REQUIRE_EQ(1, fooArgs.size()); TypeId arg0 = fooArgs[0]; - const TableTypeVar* arg0Table = get(follow(arg0)); + const TableType* arg0Table = get(follow(arg0)); REQUIRE(arg0Table != nullptr); REQUIRE(arg0Table->props.find("bar") != arg0Table->props.end()); @@ -433,7 +433,7 @@ TEST_CASE_FIXTURE(Fixture, "table_param_row_polymorphism_2") std::cout << "Error: " << e << std::endl; TypeId qType = requireType("q"); - const TableTypeVar* qTable = get(qType); + const TableType* qTable = get(qType); REQUIRE(qType != nullptr); CHECK(qTable->props.find("x") != qTable->props.end()); @@ -442,7 +442,7 @@ TEST_CASE_FIXTURE(Fixture, "table_param_row_polymorphism_2") CHECK(qTable->props.find("w") != qTable->props.end()); TypeId wType = requireType("w"); - const TableTypeVar* wTable = get(wType); + const TableType* wTable = get(wType); REQUIRE(wTable != nullptr); CHECK(wTable->props.find("x") != wTable->props.end()); @@ -553,7 +553,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_array") LUAU_REQUIRE_NO_ERRORS(result); - const TableTypeVar* ttv = get(requireType("t")); + const TableType* ttv = get(requireType("t")); REQUIRE(ttv != nullptr); REQUIRE(bool(ttv->indexer)); @@ -603,14 +603,14 @@ TEST_CASE_FIXTURE(Fixture, "indexers_get_quantified_too") LUAU_REQUIRE_NO_ERRORS(result); - const FunctionTypeVar* ftv = get(requireType("swap")); + const FunctionType* ftv = get(requireType("swap")); REQUIRE(ftv != nullptr); std::vector argVec = flatten(ftv->argTypes).first; REQUIRE_EQ(1, argVec.size()); - const TableTypeVar* ttv = get(follow(argVec[0])); + const TableType* ttv = get(follow(argVec[0])); REQUIRE(ttv != nullptr); REQUIRE(bool(ttv->indexer)); @@ -619,7 +619,7 @@ TEST_CASE_FIXTURE(Fixture, "indexers_get_quantified_too") REQUIRE_EQ(indexer.indexType, typeChecker.numberType); - REQUIRE(nullptr != get(follow(indexer.indexResultType))); + REQUIRE(nullptr != get(follow(indexer.indexResultType))); } TEST_CASE_FIXTURE(Fixture, "indexers_quantification_2") @@ -633,19 +633,19 @@ TEST_CASE_FIXTURE(Fixture, "indexers_quantification_2") LUAU_REQUIRE_NO_ERRORS(result); - const FunctionTypeVar* ftv = get(requireType("mergesort")); + const FunctionType* ftv = get(requireType("mergesort")); REQUIRE(ftv != nullptr); std::vector argVec = flatten(ftv->argTypes).first; REQUIRE_EQ(1, argVec.size()); - const TableTypeVar* argType = get(follow(argVec[0])); + const TableType* argType = get(follow(argVec[0])); REQUIRE(argType != nullptr); std::vector retVec = flatten(ftv->retTypes).first; - const TableTypeVar* retType = get(follow(retVec[0])); + const TableType* retType = get(follow(retVec[0])); REQUIRE(retType != nullptr); CHECK_EQ(argType->state, retType->state); @@ -661,7 +661,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_indexer_from_array_like_table") LUAU_REQUIRE_NO_ERRORS(result); - const TableTypeVar* ttv = get(requireType("t")); + const TableType* ttv = get(requireType("t")); REQUIRE(ttv != nullptr); REQUIRE(bool(ttv->indexer)); @@ -689,13 +689,13 @@ TEST_CASE_FIXTURE(Fixture, "infer_indexer_from_value_property_in_literal") LUAU_REQUIRE_NO_ERRORS(result); - const FunctionTypeVar* fType = get(requireType("f")); + const FunctionType* fType = get(requireType("f")); REQUIRE(fType != nullptr); auto retType_ = first(fType->retTypes); REQUIRE(bool(retType_)); - auto retType = get(follow(*retType_)); + auto retType = get(follow(*retType_)); REQUIRE(retType != nullptr); CHECK(bool(retType->indexer)); @@ -718,7 +718,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_indexer_from_its_variable_type_and_unifiable") TypeMismatch* tm = get(result.errors[0]); REQUIRE(tm != nullptr); - const TableTypeVar* tTy = get(requireType("t2")); + const TableType* tTy = get(requireType("t2")); REQUIRE(tTy != nullptr); REQUIRE(tTy->indexer); @@ -742,8 +742,8 @@ TEST_CASE_FIXTURE(Fixture, "indexer_mismatch") TypeMismatch* tm = get(result.errors[0]); REQUIRE(tm != nullptr); - CHECK_EQ(tm->wantedType, t2); - CHECK_EQ(tm->givenType, t1); + CHECK(toString(tm->wantedType) == "{number}"); + CHECK(toString(tm->givenType) == "{| [string]: string |}"); CHECK_NE(*t1, *t2); } @@ -871,7 +871,7 @@ TEST_CASE_FIXTURE(Fixture, "assigning_to_an_unsealed_table_with_string_literal_s CHECK("string" == toString(*typeChecker.stringType)); - TableTypeVar* tableType = getMutable(requireType("t")); + TableType* tableType = getMutable(requireType("t")); REQUIRE(tableType != nullptr); REQUIRE(tableType->indexer == std::nullopt); REQUIRE(0 != tableType->props.count("a")); @@ -998,11 +998,11 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "unification_of_unions_in_a_self_referential_ LUAU_REQUIRE_NO_ERRORS(result); - const MetatableTypeVar* amtv = get(requireType("a")); + const MetatableType* amtv = get(requireType("a")); REQUIRE(amtv); CHECK_EQ(amtv->metatable, requireType("amt")); - const MetatableTypeVar* bmtv = get(requireType("b")); + const MetatableType* bmtv = get(requireType("b")); REQUIRE(bmtv); CHECK_EQ(bmtv->metatable, requireType("bmt")); } @@ -1408,10 +1408,10 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "missing_metatable_for_sealed_tables_do_not_g CHECK_EQ(tm->wantedType, t); CHECK_EQ(tm->givenType, a); - const MetatableTypeVar* aTy = get(a); + const MetatableType* aTy = get(a); REQUIRE(aTy); - const TableTypeVar* tTy = get(t); + const TableType* tTy = get(t); REQUIRE(tTy); } @@ -1621,7 +1621,7 @@ TEST_CASE_FIXTURE(Fixture, "type_mismatch_on_massive_table_is_cut_short") TypeMismatch* tm = get(result.errors[0]); REQUIRE(tm); - CHECK_EQ(requireType("t"), tm->wantedType); + CHECK("{ a: number, b: number, c: number, d: number, e: number, ... 1 more ... }" == toString(requireType("t"))); CHECK_EQ("number", toString(tm->givenType)); CHECK_EQ("Type 'number' could not be converted into '{ a: number, b: number, c: number, d: number, e: number, ... 1 more ... }'", @@ -1755,7 +1755,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "persistent_sealed_table_is_immutable") else CHECK_EQ("Cannot add property 'bad' to table 'os'", toString(result.errors[0])); - const TableTypeVar* osType = get(requireType("os")); + const TableType* osType = get(requireType("os")); REQUIRE(osType != nullptr); CHECK(osType->props.find("bad") == osType->props.end()); } @@ -1865,19 +1865,19 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "quantifying_a_bound_var_works") LUAU_REQUIRE_NO_ERRORS(result); TypeId ty = requireType("clazz"); - TableTypeVar* ttv = getMutable(ty); + TableType* ttv = getMutable(ty); REQUIRE(ttv); REQUIRE(ttv->props.count("new")); Property& prop = ttv->props["new"]; REQUIRE(prop.type); - const FunctionTypeVar* ftv = get(follow(prop.type)); + const FunctionType* ftv = get(follow(prop.type)); REQUIRE(ftv); const TypePack* res = get(follow(ftv->retTypes)); REQUIRE(res); REQUIRE(res->head.size() == 1); - const MetatableTypeVar* mtv = get(follow(res->head[0])); + const MetatableType* mtv = get(follow(res->head[0])); REQUIRE(mtv); - ttv = getMutable(follow(mtv->table)); + ttv = getMutable(follow(mtv->table)); REQUIRE(ttv); REQUIRE_EQ(ttv->state, TableState::Sealed); } @@ -2424,7 +2424,7 @@ TEST_CASE_FIXTURE(Fixture, "table_length") LUAU_REQUIRE_NO_ERRORS(result); - CHECK(nullptr != get(requireType("t"))); + CHECK(nullptr != get(requireType("t"))); CHECK_EQ(*typeChecker.numberType, *requireType("s")); } @@ -2535,13 +2535,13 @@ TEST_CASE_FIXTURE(Fixture, "generalize_table_argument") LUAU_REQUIRE_NO_ERRORS(result); dumpErrors(result); - const FunctionTypeVar* fooType = get(requireType("foo")); + const FunctionType* fooType = get(requireType("foo")); REQUIRE(fooType); std::optional fooArg1 = first(fooType->argTypes); REQUIRE(fooArg1); - const TableTypeVar* fooArg1Table = get(*fooArg1); + const TableType* fooArg1Table = get(*fooArg1); REQUIRE(fooArg1Table); CHECK_EQ(fooArg1Table->state, TableState::Generic); @@ -2549,13 +2549,13 @@ TEST_CASE_FIXTURE(Fixture, "generalize_table_argument") /* * This test case exposed an oversight in the treatment of free tables. - * Free tables, like free TypeVars, need to record the scope depth where they were created so that + * Free tables, like free Types, need to record the scope depth where they were created so that * we do not erroneously let-generalize them when they are used in a nested lambda. * * For more information about let-generalization, see * * The important idea here is that the return type of Counter.new is a table with some metatable. - * That metatable *must* be the same TypeVar as the type of Counter. If it is a copy (produced by + * That metatable *must* be the same Type as the type of Counter. If it is a copy (produced by * the generalization process), then it loses the knowledge that its metatable will have an :incr() * method. */ @@ -2581,20 +2581,20 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dont_quantify_table_that_belongs_to_outer_sc LUAU_REQUIRE_NO_ERRORS(result); - TableTypeVar* counterType = getMutable(requireType("Counter")); + TableType* counterType = getMutable(requireType("Counter")); REQUIRE(counterType); REQUIRE(counterType->props.count("new")); - const FunctionTypeVar* newType = get(follow(counterType->props["new"].type)); + const FunctionType* newType = get(follow(counterType->props["new"].type)); REQUIRE(newType); std::optional newRetType = *first(newType->retTypes); REQUIRE(newRetType); - const MetatableTypeVar* newRet = get(follow(*newRetType)); + const MetatableType* newRet = get(follow(*newRetType)); REQUIRE(newRet); - const TableTypeVar* newRetMeta = get(newRet->metatable); + const TableType* newRetMeta = get(newRet->metatable); REQUIRE(newRetMeta); CHECK(newRetMeta->props.count("incr")); @@ -2627,7 +2627,7 @@ TEST_CASE_FIXTURE(Fixture, "inferring_crazy_table_should_also_be_quick") )"); ModulePtr module = getMainModule(); - CHECK_GE(100, module->internalTypes.typeVars.size()); + CHECK_GE(100, module->internalTypes.types.size()); } TEST_CASE_FIXTURE(Fixture, "MixedPropertiesAndIndexers") @@ -2703,7 +2703,7 @@ type t0 = any std::optional ty = requireType("math"); REQUIRE(ty); - const TableTypeVar* ttv = get(*ty); + const TableType* ttv = get(*ty); REQUIRE(ttv); CHECK(ttv->instantiatedTypeParams.empty()); } @@ -2720,7 +2720,7 @@ type K = X std::optional ty = requireType("math"); REQUIRE(ty); - const TableTypeVar* ttv = get(*ty); + const TableType* ttv = get(*ty); REQUIRE(ttv); CHECK(ttv->instantiatedTypeParams.empty()); } @@ -2742,7 +2742,7 @@ c = b std::optional ty = requireType("a"); REQUIRE(ty); - const TableTypeVar* ttv = get(*ty); + const TableType* ttv = get(*ty); REQUIRE(ttv); CHECK(ttv->instantiatedTypeParams.empty()); } @@ -2778,7 +2778,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_call_metamethod_basic") )"); LUAU_REQUIRE_NO_ERRORS(result); - CHECK(requireType("foo") == singletonTypes->numberType); + CHECK(requireType("foo") == builtinTypes->numberType); } TEST_CASE_FIXTURE(BuiltinsFixture, "table_call_metamethod_must_be_callable") @@ -2794,7 +2794,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_call_metamethod_must_be_callable") LUAU_REQUIRE_ERROR_COUNT(1, result); CHECK(result.errors[0] == TypeError{ Location{{5, 20}, {5, 21}}, - CannotCallNonFunction{singletonTypes->numberType}, + CannotCallNonFunction{builtinTypes->numberType}, }); } @@ -2812,8 +2812,8 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "table_call_metamethod_generic") )"); LUAU_REQUIRE_NO_ERRORS(result); - CHECK(requireType("foo") == singletonTypes->numberType); - CHECK(requireType("bar") == singletonTypes->stringType); + CHECK(requireType("foo") == builtinTypes->numberType); + CHECK(requireType("bar") == builtinTypes->stringType); } TEST_CASE_FIXTURE(BuiltinsFixture, "table_simple_call") diff --git a/tests/TypeInfer.test.cpp b/tests/TypeInfer.test.cpp index e42cea63..f6279fa2 100644 --- a/tests/TypeInfer.test.cpp +++ b/tests/TypeInfer.test.cpp @@ -4,8 +4,8 @@ #include "Luau/BuiltinDefinitions.h" #include "Luau/Scope.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" #include "Fixture.h" #include "ScopedFlags.h" @@ -28,7 +28,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_hello_world") LUAU_REQUIRE_NO_ERRORS(result); TypeId aType = requireType("a"); - CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::Number); + CHECK_EQ(getPrimitiveType(aType), PrimitiveType::Number); } TEST_CASE_FIXTURE(Fixture, "tc_propagation") @@ -37,7 +37,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_propagation") LUAU_REQUIRE_NO_ERRORS(result); TypeId bType = requireType("b"); - CHECK_EQ(getPrimitiveType(bType), PrimitiveTypeVar::Number); + CHECK_EQ(getPrimitiveType(bType), PrimitiveType::Number); } TEST_CASE_FIXTURE(Fixture, "tc_error") @@ -65,7 +65,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_locals_with_nil_value") LUAU_REQUIRE_NO_ERRORS(result); TypeId ty = requireType("f"); - CHECK_EQ(getPrimitiveType(ty), PrimitiveTypeVar::String); + CHECK_EQ(getPrimitiveType(ty), PrimitiveType::String); } TEST_CASE_FIXTURE(Fixture, "infer_locals_via_assignment_from_its_call_site") @@ -213,7 +213,7 @@ TEST_CASE_FIXTURE(Fixture, "crazy_complexity") A:A():A():A():A():A():A():A():A():A():A():A() )"); - std::cout << "OK! Allocated " << typeChecker.typeVars.size() << " typevars" << std::endl; + std::cout << "OK! Allocated " << typeChecker.types.size() << " types" << std::endl; } #endif @@ -294,7 +294,7 @@ TEST_CASE_FIXTURE(Fixture, "exponential_blowup_from_copying_types") // If we're not careful about copying, this ends up with O(2^N) types rather than O(N) // (in this case 5 vs 31). - CHECK_GE(5, module->interfaceTypes.typeVars.size()); + CHECK_GE(5, module->interfaceTypes.types.size()); } // In these tests, a successful parse is required, so we need the parser to return the AST and then we can test the recursion depth limit in type @@ -455,7 +455,7 @@ end )"); } -struct FindFreeTypeVars +struct FindFreeTypes { bool foundOne = false; @@ -487,7 +487,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_after_error_recovery") LUAU_REQUIRE_ERRORS(result); TypeId aType = requireType("a"); - CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::Number); + CHECK_EQ(getPrimitiveType(aType), PrimitiveType::Number); } // Check that type checker knows about error expressions @@ -758,7 +758,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions1") CheckResult result = check(R"(local a = if true then "true" else "false")"); LUAU_REQUIRE_NO_ERRORS(result); TypeId aType = requireType("a"); - CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::String); + CHECK_EQ(getPrimitiveType(aType), PrimitiveType::String); } TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions2") @@ -769,7 +769,7 @@ local a = if false then "a" elseif false then "b" else "c" )"); LUAU_REQUIRE_NO_ERRORS(result); TypeId aType = requireType("a"); - CHECK_EQ(getPrimitiveType(aType), PrimitiveTypeVar::String); + CHECK_EQ(getPrimitiveType(aType), PrimitiveType::String); } TEST_CASE_FIXTURE(Fixture, "tc_if_else_expressions_type_union") @@ -854,11 +854,11 @@ TEST_CASE_FIXTURE(Fixture, "tc_interpolated_string_constant_type") * * We had an issue here where the scope for the `if` block here would * have an elevated TypeLevel even though there is no function nesting going on. - * This would result in a free typevar for the type of _ that was much higher than + * This would result in a free type for the type of _ that was much higher than * it should be. This type would be erroneously quantified in the definition of `aaa`. * This in turn caused an ice when evaluating `_()` in the while loop. */ -TEST_CASE_FIXTURE(Fixture, "free_typevars_introduced_within_control_flow_constructs_do_not_get_an_elevated_TypeLevel") +TEST_CASE_FIXTURE(Fixture, "free_types_introduced_within_control_flow_constructs_do_not_get_an_elevated_TypeLevel") { check(R"( --!strict diff --git a/tests/TypeInfer.tryUnify.test.cpp b/tests/TypeInfer.tryUnify.test.cpp index b1abdf7c..80c7ab57 100644 --- a/tests/TypeInfer.tryUnify.test.cpp +++ b/tests/TypeInfer.tryUnify.test.cpp @@ -1,7 +1,7 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/Scope.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Fixture.h" @@ -15,7 +15,7 @@ struct TryUnifyFixture : Fixture ScopePtr globalScope{new Scope{arena.addTypePack({TypeId{}})}}; InternalErrorReporter iceHandler; UnifierSharedState unifierState{&iceHandler}; - Normalizer normalizer{&arena, singletonTypes, NotNull{&unifierState}}; + Normalizer normalizer{&arena, builtinTypes, NotNull{&unifierState}}; Unifier state{NotNull{&normalizer}, Mode::Strict, NotNull{globalScope.get()}, Location{}, Variance::Covariant}; }; @@ -23,8 +23,8 @@ TEST_SUITE_BEGIN("TryUnifyTests"); TEST_CASE_FIXTURE(TryUnifyFixture, "primitives_unify") { - TypeVar numberOne{TypeVariant{PrimitiveTypeVar{PrimitiveTypeVar::Number}}}; - TypeVar numberTwo = numberOne; + Type numberOne{TypeVariant{PrimitiveType{PrimitiveType::Number}}}; + Type numberTwo = numberOne; state.tryUnify(&numberTwo, &numberOne); @@ -33,11 +33,11 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "primitives_unify") TEST_CASE_FIXTURE(TryUnifyFixture, "compatible_functions_are_unified") { - TypeVar functionOne{ - TypeVariant{FunctionTypeVar(arena.addTypePack({arena.freshType(globalScope->level)}), arena.addTypePack({typeChecker.numberType}))}}; + Type functionOne{ + TypeVariant{FunctionType(arena.addTypePack({arena.freshType(globalScope->level)}), arena.addTypePack({typeChecker.numberType}))}}; - TypeVar functionTwo{TypeVariant{ - FunctionTypeVar(arena.addTypePack({arena.freshType(globalScope->level)}), arena.addTypePack({arena.freshType(globalScope->level)}))}}; + Type functionTwo{TypeVariant{ + FunctionType(arena.addTypePack({arena.freshType(globalScope->level)}), arena.addTypePack({arena.freshType(globalScope->level)}))}}; state.tryUnify(&functionTwo, &functionOne); CHECK(state.errors.empty()); @@ -50,16 +50,16 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "compatible_functions_are_unified") TEST_CASE_FIXTURE(TryUnifyFixture, "incompatible_functions_are_preserved") { TypePackVar argPackOne{TypePack{{arena.freshType(globalScope->level)}, std::nullopt}}; - TypeVar functionOne{ - TypeVariant{FunctionTypeVar(arena.addTypePack({arena.freshType(globalScope->level)}), arena.addTypePack({typeChecker.numberType}))}}; + Type functionOne{ + TypeVariant{FunctionType(arena.addTypePack({arena.freshType(globalScope->level)}), arena.addTypePack({typeChecker.numberType}))}}; - TypeVar functionOneSaved = functionOne; + Type functionOneSaved = functionOne; TypePackVar argPackTwo{TypePack{{arena.freshType(globalScope->level)}, std::nullopt}}; - TypeVar functionTwo{ - TypeVariant{FunctionTypeVar(arena.addTypePack({arena.freshType(globalScope->level)}), arena.addTypePack({typeChecker.stringType}))}}; + Type functionTwo{ + TypeVariant{FunctionType(arena.addTypePack({arena.freshType(globalScope->level)}), arena.addTypePack({typeChecker.stringType}))}}; - TypeVar functionTwoSaved = functionTwo; + Type functionTwoSaved = functionTwo; state.tryUnify(&functionTwo, &functionOne); CHECK(!state.errors.empty()); @@ -70,15 +70,15 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "incompatible_functions_are_preserved") TEST_CASE_FIXTURE(TryUnifyFixture, "tables_can_be_unified") { - TypeVar tableOne{TypeVariant{ - TableTypeVar{{{"foo", {arena.freshType(globalScope->level)}}}, std::nullopt, globalScope->level, TableState::Unsealed}, + Type tableOne{TypeVariant{ + TableType{{{"foo", {arena.freshType(globalScope->level)}}}, std::nullopt, globalScope->level, TableState::Unsealed}, }}; - TypeVar tableTwo{TypeVariant{ - TableTypeVar{{{"foo", {arena.freshType(globalScope->level)}}}, std::nullopt, globalScope->level, TableState::Unsealed}, + Type tableTwo{TypeVariant{ + TableType{{{"foo", {arena.freshType(globalScope->level)}}}, std::nullopt, globalScope->level, TableState::Unsealed}, }}; - CHECK_NE(*getMutable(&tableOne)->props["foo"].type, *getMutable(&tableTwo)->props["foo"].type); + CHECK_NE(*getMutable(&tableOne)->props["foo"].type, *getMutable(&tableTwo)->props["foo"].type); state.tryUnify(&tableTwo, &tableOne); @@ -86,28 +86,28 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "tables_can_be_unified") state.log.commit(); - CHECK_EQ(*getMutable(&tableOne)->props["foo"].type, *getMutable(&tableTwo)->props["foo"].type); + CHECK_EQ(*getMutable(&tableOne)->props["foo"].type, *getMutable(&tableTwo)->props["foo"].type); } TEST_CASE_FIXTURE(TryUnifyFixture, "incompatible_tables_are_preserved") { - TypeVar tableOne{TypeVariant{ - TableTypeVar{{{"foo", {arena.freshType(globalScope->level)}}, {"bar", {typeChecker.numberType}}}, std::nullopt, globalScope->level, + Type tableOne{TypeVariant{ + TableType{{{"foo", {arena.freshType(globalScope->level)}}, {"bar", {typeChecker.numberType}}}, std::nullopt, globalScope->level, TableState::Unsealed}, }}; - TypeVar tableTwo{TypeVariant{ - TableTypeVar{{{"foo", {arena.freshType(globalScope->level)}}, {"bar", {typeChecker.stringType}}}, std::nullopt, globalScope->level, + Type tableTwo{TypeVariant{ + TableType{{{"foo", {arena.freshType(globalScope->level)}}, {"bar", {typeChecker.stringType}}}, std::nullopt, globalScope->level, TableState::Unsealed}, }}; - CHECK_NE(*getMutable(&tableOne)->props["foo"].type, *getMutable(&tableTwo)->props["foo"].type); + CHECK_NE(*getMutable(&tableOne)->props["foo"].type, *getMutable(&tableTwo)->props["foo"].type); state.tryUnify(&tableTwo, &tableOne); CHECK_EQ(1, state.errors.size()); - CHECK_NE(*getMutable(&tableOne)->props["foo"].type, *getMutable(&tableTwo)->props["foo"].type); + CHECK_NE(*getMutable(&tableOne)->props["foo"].type, *getMutable(&tableTwo)->props["foo"].type); } TEST_CASE_FIXTURE(TryUnifyFixture, "uninhabited_intersection_sub_never") @@ -282,11 +282,11 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "free_tail_is_grown_properly") TEST_CASE_FIXTURE(TryUnifyFixture, "recursive_metatable_getmatchtag") { - TypeVar redirect{FreeTypeVar{TypeLevel{}}}; - TypeVar table{TableTypeVar{}}; - TypeVar metatable{MetatableTypeVar{&redirect, &table}}; - redirect = BoundTypeVar{&metatable}; // Now we have a metatable that is recursive on the table type - TypeVar variant{UnionTypeVar{{&metatable, typeChecker.numberType}}}; + Type redirect{FreeType{TypeLevel{}}}; + Type table{TableType{}}; + Type metatable{MetatableType{&redirect, &table}}; + redirect = BoundType{&metatable}; // Now we have a metatable that is recursive on the table type + Type variant{UnionType{{&metatable, typeChecker.numberType}}}; state.tryUnify(&metatable, &variant); } @@ -296,7 +296,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "cli_50320_follow_in_any_unification") TypePackVar free{FreeTypePack{TypeLevel{}}}; TypePackVar target{TypePack{}}; - TypeVar func{FunctionTypeVar{&free, &free}}; + Type func{FunctionType{&free, &free}}; state.tryUnify(&free, &target); // Shouldn't assert or error. @@ -305,7 +305,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "cli_50320_follow_in_any_unification") TEST_CASE_FIXTURE(TryUnifyFixture, "txnlog_preserves_type_owner") { - TypeId a = arena.addType(TypeVar{FreeTypeVar{TypeLevel{}}}); + TypeId a = arena.addType(Type{FreeType{TypeLevel{}}}); TypeId b = typeChecker.numberType; state.tryUnify(a, b); @@ -329,26 +329,26 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "metatables_unify_against_shape_of_free_table { ScopedFastFlag sff("DebugLuauDeferredConstraintResolution", true); - TableTypeVar::Props freeProps{ + TableType::Props freeProps{ {"foo", {typeChecker.numberType}}, }; - TypeId free = arena.addType(TableTypeVar{freeProps, std::nullopt, TypeLevel{}, TableState::Free}); + TypeId free = arena.addType(TableType{freeProps, std::nullopt, TypeLevel{}, TableState::Free}); - TableTypeVar::Props indexProps{ + TableType::Props indexProps{ {"foo", {typeChecker.stringType}}, }; - TypeId index = arena.addType(TableTypeVar{indexProps, std::nullopt, TypeLevel{}, TableState::Sealed}); + TypeId index = arena.addType(TableType{indexProps, std::nullopt, TypeLevel{}, TableState::Sealed}); - TableTypeVar::Props mtProps{ + TableType::Props mtProps{ {"__index", {index}}, }; - TypeId mt = arena.addType(TableTypeVar{mtProps, std::nullopt, TypeLevel{}, TableState::Sealed}); + TypeId mt = arena.addType(TableType{mtProps, std::nullopt, TypeLevel{}, TableState::Sealed}); - TypeId target = arena.addType(TableTypeVar{TableState::Unsealed, TypeLevel{}}); - TypeId metatable = arena.addType(MetatableTypeVar{target, mt}); + TypeId target = arena.addType(TableType{TableState::Unsealed, TypeLevel{}}); + TypeId metatable = arena.addType(MetatableType{target, mt}); state.tryUnify(metatable, free); state.log.commit(); @@ -369,7 +369,7 @@ TEST_CASE_FIXTURE(TryUnifyFixture, "fuzz_tail_unification_issue") TypePackVar packTmp{TypePack{{typeChecker.anyType}, &variadicAny}}; TypePackVar packSub{TypePack{{typeChecker.anyType, typeChecker.anyType}, &packTmp}}; - TypeVar freeTy{FreeTypeVar{TypeLevel{}}}; + Type freeTy{FreeType{TypeLevel{}}}; TypePackVar freeTp{FreeTypePack{TypeLevel{}}}; TypePackVar packSuper{TypePack{{&freeTy}, &freeTp}}; diff --git a/tests/TypeInfer.typePacks.cpp b/tests/TypeInfer.typePacks.cpp index 0e4074f7..b753d30e 100644 --- a/tests/TypeInfer.typePacks.cpp +++ b/tests/TypeInfer.typePacks.cpp @@ -1,7 +1,7 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/BuiltinDefinitions.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Fixture.h" @@ -21,7 +21,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_multi_return") LUAU_REQUIRE_NO_ERRORS(result); - const FunctionTypeVar* takeTwoType = get(requireType("take_two")); + const FunctionType* takeTwoType = get(requireType("take_two")); REQUIRE(takeTwoType != nullptr); const auto& [returns, tail] = flatten(takeTwoType->retTypes); @@ -68,7 +68,7 @@ TEST_CASE_FIXTURE(Fixture, "last_element_of_return_statement_can_itself_be_a_pac LUAU_REQUIRE_NO_ERRORS(result); dumpErrors(result); - const FunctionTypeVar* takeOneMoreType = get(requireType("take_three")); + const FunctionType* takeOneMoreType = get(requireType("take_three")); REQUIRE(takeOneMoreType != nullptr); const auto& [rets, tail] = flatten(takeOneMoreType->retTypes); @@ -101,10 +101,10 @@ TEST_CASE_FIXTURE(Fixture, "return_type_should_be_empty_if_nothing_is_returned") function g() return end )"); LUAU_REQUIRE_NO_ERRORS(result); - const FunctionTypeVar* fTy = get(requireType("f")); + const FunctionType* fTy = get(requireType("f")); REQUIRE(fTy != nullptr); CHECK_EQ(0, size(fTy->retTypes)); - const FunctionTypeVar* gTy = get(requireType("g")); + const FunctionType* gTy = get(requireType("g")); REQUIRE(gTy != nullptr); CHECK_EQ(0, size(gTy->retTypes)); } @@ -121,15 +121,15 @@ TEST_CASE_FIXTURE(Fixture, "no_return_size_should_be_zero") )"); LUAU_REQUIRE_NO_ERRORS(result); - const FunctionTypeVar* fTy = get(requireType("f")); + const FunctionType* fTy = get(requireType("f")); REQUIRE(fTy != nullptr); CHECK_EQ(1, size(follow(fTy->retTypes))); - const FunctionTypeVar* gTy = get(requireType("g")); + const FunctionType* gTy = get(requireType("g")); REQUIRE(gTy != nullptr); CHECK_EQ(0, size(gTy->retTypes)); - const FunctionTypeVar* hTy = get(requireType("h")); + const FunctionType* hTy = get(requireType("h")); REQUIRE(hTy != nullptr); CHECK_EQ(0, size(hTy->retTypes)); } @@ -194,7 +194,7 @@ TEST_CASE_FIXTURE(Fixture, "variadic_packs") // clang-format off addGlobalBinding(frontend, "foo", arena.addType( - FunctionTypeVar{ + FunctionType{ listOfNumbers, arena.addTypePack({typeChecker.numberType}) } @@ -203,7 +203,7 @@ TEST_CASE_FIXTURE(Fixture, "variadic_packs") ); addGlobalBinding(frontend, "bar", arena.addType( - FunctionTypeVar{ + FunctionType{ arena.addTypePack({{typeChecker.numberType}, listOfStrings}), arena.addTypePack({typeChecker.numberType}) } @@ -306,7 +306,7 @@ local c: Packed CHECK_EQ(toString(*tf), "Packed"); CHECK_EQ(toString(*tf, {true}), "{| f: (T, U...) -> (T, U...) |}"); - auto ttvA = get(requireType("a")); + auto ttvA = get(requireType("a")); REQUIRE(ttvA); CHECK_EQ(toString(requireType("a")), "Packed"); CHECK_EQ(toString(requireType("a"), {true}), "{| f: (number) -> number |}"); @@ -315,7 +315,7 @@ local c: Packed CHECK_EQ(toString(ttvA->instantiatedTypeParams[0], {true}), "number"); CHECK_EQ(toString(ttvA->instantiatedTypePackParams[0], {true}), ""); - auto ttvB = get(requireType("b")); + auto ttvB = get(requireType("b")); REQUIRE(ttvB); CHECK_EQ(toString(requireType("b")), "Packed"); CHECK_EQ(toString(requireType("b"), {true}), "{| f: (string, number) -> (string, number) |}"); @@ -324,7 +324,7 @@ local c: Packed CHECK_EQ(toString(ttvB->instantiatedTypeParams[0], {true}), "string"); CHECK_EQ(toString(ttvB->instantiatedTypePackParams[0], {true}), "number"); - auto ttvC = get(requireType("c")); + auto ttvC = get(requireType("c")); REQUIRE(ttvC); CHECK_EQ(toString(requireType("c")), "Packed"); CHECK_EQ(toString(requireType("c"), {true}), "{| f: (string, number, boolean) -> (string, number, boolean) |}"); diff --git a/tests/TypeInfer.unionTypes.test.cpp b/tests/TypeInfer.unionTypes.test.cpp index adfc61b6..d3022095 100644 --- a/tests/TypeInfer.unionTypes.test.cpp +++ b/tests/TypeInfer.unionTypes.test.cpp @@ -1,6 +1,6 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Fixture.h" @@ -26,7 +26,7 @@ TEST_CASE_FIXTURE(Fixture, "return_types_can_be_disjoint") LUAU_REQUIRE_NO_ERRORS(result); - const FunctionTypeVar* utv = get(requireType("most_of_the_natural_numbers")); + const FunctionType* utv = get(requireType("most_of_the_natural_numbers")); REQUIRE(utv != nullptr); } diff --git a/tests/TypePack.test.cpp b/tests/TypePack.test.cpp index 1087a24c..20404434 100644 --- a/tests/TypePack.test.cpp +++ b/tests/TypePack.test.cpp @@ -1,6 +1,6 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" +#include "Luau/Type.h" #include "Fixture.h" @@ -14,10 +14,10 @@ struct TypePackFixture { TypePackFixture() { - typeVars.emplace_back(new TypeVar(PrimitiveTypeVar(PrimitiveTypeVar::NilType))); - typeVars.emplace_back(new TypeVar(PrimitiveTypeVar(PrimitiveTypeVar::Boolean))); - typeVars.emplace_back(new TypeVar(PrimitiveTypeVar(PrimitiveTypeVar::Number))); - typeVars.emplace_back(new TypeVar(PrimitiveTypeVar(PrimitiveTypeVar::String))); + typeVars.emplace_back(new Type(PrimitiveType(PrimitiveType::NilType))); + typeVars.emplace_back(new Type(PrimitiveType(PrimitiveType::Boolean))); + typeVars.emplace_back(new Type(PrimitiveType(PrimitiveType::Number))); + typeVars.emplace_back(new Type(PrimitiveType(PrimitiveType::String))); for (const auto& ptr : typeVars) types.push_back(ptr.get()); @@ -37,7 +37,7 @@ struct TypePackFixture std::vector> typePacks; - std::vector> typeVars; + std::vector> typeVars; std::vector types; }; @@ -54,7 +54,7 @@ TEST_CASE_FIXTURE(TypePackFixture, "type_pack_hello") TEST_CASE_FIXTURE(TypePackFixture, "first_chases_Bound_TypePackVars") { - TypeVar nilType{PrimitiveTypeVar{PrimitiveTypeVar::NilType}}; + Type nilType{PrimitiveType{PrimitiveType::NilType}}; auto tp1 = TypePackVar{TypePack{{&nilType}, std::nullopt}}; @@ -206,7 +206,7 @@ TEST_CASE("content_reassignment") TypePackId futureError = arena.addTypePack(TypePackVar{FreeTypePack{TypeLevel{}}}); asMutable(futureError)->reassign(myError); - CHECK(get(futureError) != nullptr); + CHECK(get(futureError) != nullptr); CHECK(!futureError->persistent); CHECK(futureError->owningArena == &arena); } diff --git a/tests/TypeVar.test.cpp b/tests/TypeVar.test.cpp index 5dd1b1bc..ec0a2473 100644 --- a/tests/TypeVar.test.cpp +++ b/tests/TypeVar.test.cpp @@ -1,8 +1,8 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/Scope.h" #include "Luau/TypeInfer.h" -#include "Luau/TypeVar.h" -#include "Luau/VisitTypeVar.h" +#include "Luau/Type.h" +#include "Luau/VisitType.h" #include "Fixture.h" #include "ScopedFlags.h" @@ -11,7 +11,7 @@ using namespace Luau; -TEST_SUITE_BEGIN("TypeVarTests"); +TEST_SUITE_BEGIN("TypeTests"); TEST_CASE_FIXTURE(Fixture, "primitives_are_equal") { @@ -20,18 +20,18 @@ TEST_CASE_FIXTURE(Fixture, "primitives_are_equal") TEST_CASE_FIXTURE(Fixture, "bound_type_is_equal_to_that_which_it_is_bound") { - TypeVar bound(BoundTypeVar(typeChecker.booleanType)); + Type bound(BoundType(typeChecker.booleanType)); REQUIRE_EQ(bound, *typeChecker.booleanType); } TEST_CASE_FIXTURE(Fixture, "equivalent_cyclic_tables_are_equal") { - TypeVar cycleOne{TypeVariant(TableTypeVar())}; - TableTypeVar* tableOne = getMutable(&cycleOne); + Type cycleOne{TypeVariant(TableType())}; + TableType* tableOne = getMutable(&cycleOne); tableOne->props["self"] = {&cycleOne}; - TypeVar cycleTwo{TypeVariant(TableTypeVar())}; - TableTypeVar* tableTwo = getMutable(&cycleTwo); + Type cycleTwo{TypeVariant(TableType())}; + TableType* tableTwo = getMutable(&cycleTwo); tableTwo->props["self"] = {&cycleTwo}; CHECK_EQ(cycleOne, cycleTwo); @@ -39,12 +39,12 @@ TEST_CASE_FIXTURE(Fixture, "equivalent_cyclic_tables_are_equal") TEST_CASE_FIXTURE(Fixture, "different_cyclic_tables_are_not_equal") { - TypeVar cycleOne{TypeVariant(TableTypeVar())}; - TableTypeVar* tableOne = getMutable(&cycleOne); + Type cycleOne{TypeVariant(TableType())}; + TableType* tableOne = getMutable(&cycleOne); tableOne->props["self"] = {&cycleOne}; - TypeVar cycleTwo{TypeVariant(TableTypeVar())}; - TableTypeVar* tableTwo = getMutable(&cycleTwo); + Type cycleTwo{TypeVariant(TableType())}; + TableType* tableTwo = getMutable(&cycleTwo); tableTwo->props["this"] = {&cycleTwo}; CHECK_NE(cycleOne, cycleTwo); @@ -54,7 +54,7 @@ TEST_CASE_FIXTURE(Fixture, "return_type_of_function_is_not_parenthesized_if_just { auto emptyArgumentPack = TypePackVar{TypePack{}}; auto returnPack = TypePackVar{TypePack{{typeChecker.numberType}}}; - auto returnsTwo = TypeVar(FunctionTypeVar(typeChecker.globalScope->level, &emptyArgumentPack, &returnPack)); + auto returnsTwo = Type(FunctionType(typeChecker.globalScope->level, &emptyArgumentPack, &returnPack)); std::string res = toString(&returnsTwo); CHECK_EQ("() -> number", res); @@ -64,7 +64,7 @@ TEST_CASE_FIXTURE(Fixture, "return_type_of_function_is_parenthesized_if_not_just { auto emptyArgumentPack = TypePackVar{TypePack{}}; auto returnPack = TypePackVar{TypePack{{typeChecker.numberType, typeChecker.numberType}}}; - auto returnsTwo = TypeVar(FunctionTypeVar(typeChecker.globalScope->level, &emptyArgumentPack, &returnPack)); + auto returnsTwo = Type(FunctionType(typeChecker.globalScope->level, &emptyArgumentPack, &returnPack)); std::string res = toString(&returnsTwo); CHECK_EQ("() -> (number, number)", res); @@ -76,7 +76,7 @@ TEST_CASE_FIXTURE(Fixture, "return_type_of_function_is_parenthesized_if_tail_is_ auto free = Unifiable::Free(TypeLevel()); auto freePack = TypePackVar{TypePackVariant{free}}; auto returnPack = TypePackVar{TypePack{{typeChecker.numberType}, &freePack}}; - auto returnsTwo = TypeVar(FunctionTypeVar(typeChecker.globalScope->level, &emptyArgumentPack, &returnPack)); + auto returnsTwo = Type(FunctionType(typeChecker.globalScope->level, &emptyArgumentPack, &returnPack)); std::string res = toString(&returnsTwo); CHECK_EQ(res, "() -> (number, a...)"); @@ -84,7 +84,7 @@ TEST_CASE_FIXTURE(Fixture, "return_type_of_function_is_parenthesized_if_tail_is_ TEST_CASE_FIXTURE(Fixture, "subset_check") { - UnionTypeVar super, sub, notSub; + UnionType super, sub, notSub; super.options = {typeChecker.numberType, typeChecker.stringType, typeChecker.booleanType}; sub.options = {typeChecker.numberType, typeChecker.stringType}; notSub.options = {typeChecker.numberType, typeChecker.nilType}; @@ -93,9 +93,9 @@ TEST_CASE_FIXTURE(Fixture, "subset_check") CHECK(!isSubset(super, notSub)); } -TEST_CASE_FIXTURE(Fixture, "iterate_over_UnionTypeVar") +TEST_CASE_FIXTURE(Fixture, "iterate_over_UnionType") { - UnionTypeVar utv; + UnionType utv; utv.options = {typeChecker.numberType, typeChecker.stringType, typeChecker.anyType}; std::vector result; @@ -105,13 +105,13 @@ TEST_CASE_FIXTURE(Fixture, "iterate_over_UnionTypeVar") CHECK(result == utv.options); } -TEST_CASE_FIXTURE(Fixture, "iterating_over_nested_UnionTypeVars") +TEST_CASE_FIXTURE(Fixture, "iterating_over_nested_UnionTypes") { - TypeVar subunion{UnionTypeVar{}}; - UnionTypeVar* innerUtv = getMutable(&subunion); + Type subunion{UnionType{}}; + UnionType* innerUtv = getMutable(&subunion); innerUtv->options = {typeChecker.numberType, typeChecker.stringType}; - UnionTypeVar utv; + UnionType utv; utv.options = {typeChecker.anyType, &subunion}; std::vector result; @@ -124,13 +124,13 @@ TEST_CASE_FIXTURE(Fixture, "iterating_over_nested_UnionTypeVars") CHECK_EQ(result[1], typeChecker.numberType); } -TEST_CASE_FIXTURE(Fixture, "iterator_detects_cyclic_UnionTypeVars_and_skips_over_them") +TEST_CASE_FIXTURE(Fixture, "iterator_detects_cyclic_UnionTypes_and_skips_over_them") { - TypeVar atv{UnionTypeVar{}}; - UnionTypeVar* utv1 = getMutable(&atv); + Type atv{UnionType{}}; + UnionType* utv1 = getMutable(&atv); - TypeVar btv{UnionTypeVar{}}; - UnionTypeVar* utv2 = getMutable(&btv); + Type btv{UnionType{}}; + UnionType* utv2 = getMutable(&btv); utv2->options.push_back(typeChecker.numberType); utv2->options.push_back(typeChecker.stringType); utv2->options.push_back(&atv); @@ -148,9 +148,9 @@ TEST_CASE_FIXTURE(Fixture, "iterator_detects_cyclic_UnionTypeVars_and_skips_over TEST_CASE_FIXTURE(Fixture, "iterator_descends_on_nested_in_first_operator*") { - TypeVar tv1{UnionTypeVar{{typeChecker.stringType, typeChecker.numberType}}}; - TypeVar tv2{UnionTypeVar{{&tv1, typeChecker.booleanType}}}; - auto utv = get(&tv2); + Type tv1{UnionType{{typeChecker.stringType, typeChecker.numberType}}}; + Type tv2{UnionType{{&tv1, typeChecker.booleanType}}}; + auto utv = get(&tv2); std::vector result; for (TypeId ty : utv) @@ -162,30 +162,30 @@ TEST_CASE_FIXTURE(Fixture, "iterator_descends_on_nested_in_first_operator*") CHECK_EQ(result[2], typeChecker.booleanType); } -TEST_CASE_FIXTURE(Fixture, "UnionTypeVarIterator_with_vector_iter_ctor") +TEST_CASE_FIXTURE(Fixture, "UnionTypeIterator_with_vector_iter_ctor") { - TypeVar tv1{UnionTypeVar{{typeChecker.stringType, typeChecker.numberType}}}; - TypeVar tv2{UnionTypeVar{{&tv1, typeChecker.booleanType}}}; - auto utv = get(&tv2); + Type tv1{UnionType{{typeChecker.stringType, typeChecker.numberType}}}; + Type tv2{UnionType{{&tv1, typeChecker.booleanType}}}; + auto utv = get(&tv2); std::vector actual(begin(utv), end(utv)); std::vector expected{typeChecker.stringType, typeChecker.numberType, typeChecker.booleanType}; CHECK_EQ(actual, expected); } -TEST_CASE_FIXTURE(Fixture, "UnionTypeVarIterator_with_empty_union") +TEST_CASE_FIXTURE(Fixture, "UnionTypeIterator_with_empty_union") { - TypeVar tv{UnionTypeVar{}}; - auto utv = get(&tv); + Type tv{UnionType{}}; + auto utv = get(&tv); std::vector actual(begin(utv), end(utv)); CHECK(actual.empty()); } -TEST_CASE_FIXTURE(Fixture, "UnionTypeVarIterator_with_only_cyclic_union") +TEST_CASE_FIXTURE(Fixture, "UnionTypeIterator_with_only_cyclic_union") { - TypeVar tv{UnionTypeVar{}}; - auto utv = getMutable(&tv); + Type tv{UnionType{}}; + auto utv = getMutable(&tv); utv->options.push_back(&tv); utv->options.push_back(&tv); @@ -200,44 +200,44 @@ TEST_CASE_FIXTURE(Fixture, "UnionTypeVarIterator_with_only_cyclic_union") */ TEST_CASE_FIXTURE(Fixture, "substitution_skip_failure") { - TypeVar ftv11{FreeTypeVar{TypeLevel{}}}; + Type ftv11{FreeType{TypeLevel{}}}; TypePackVar tp24{TypePack{{&ftv11}}}; TypePackVar tp17{TypePack{}}; - TypeVar ftv23{FunctionTypeVar{&tp24, &tp17}}; + Type ftv23{FunctionType{&tp24, &tp17}}; - TypeVar ttvConnection2{TableTypeVar{}}; - TableTypeVar* ttvConnection2_ = getMutable(&ttvConnection2); + Type ttvConnection2{TableType{}}; + TableType* ttvConnection2_ = getMutable(&ttvConnection2); ttvConnection2_->instantiatedTypeParams.push_back(&ftv11); ttvConnection2_->props["f"] = {&ftv23}; TypePackVar tp21{TypePack{{&ftv11}}}; TypePackVar tp20{TypePack{}}; - TypeVar ftv19{FunctionTypeVar{&tp21, &tp20}}; + Type ftv19{FunctionType{&tp21, &tp20}}; - TypeVar ttvSignal{TableTypeVar{}}; - TableTypeVar* ttvSignal_ = getMutable(&ttvSignal); + Type ttvSignal{TableType{}}; + TableType* ttvSignal_ = getMutable(&ttvSignal); ttvSignal_->instantiatedTypeParams.push_back(&ftv11); ttvSignal_->props["f"] = {&ftv19}; // Back edge ttvConnection2_->props["signal"] = {&ttvSignal}; - TypeVar gtvK2{GenericTypeVar{}}; - TypeVar gtvV2{GenericTypeVar{}}; + Type gtvK2{GenericType{}}; + Type gtvV2{GenericType{}}; - TypeVar ttvTweenResult2{TableTypeVar{}}; - TableTypeVar* ttvTweenResult2_ = getMutable(&ttvTweenResult2); + Type ttvTweenResult2{TableType{}}; + TableType* ttvTweenResult2_ = getMutable(&ttvTweenResult2); ttvTweenResult2_->instantiatedTypeParams.push_back(>vK2); ttvTweenResult2_->instantiatedTypeParams.push_back(>vV2); TypePackVar tp13{TypePack{{&ttvTweenResult2}}}; - TypeVar ftv12{FunctionTypeVar{&tp13, &tp17}}; + Type ftv12{FunctionType{&tp13, &tp17}}; - TypeVar ttvConnection{TableTypeVar{}}; - TableTypeVar* ttvConnection_ = getMutable(&ttvConnection); + Type ttvConnection{TableType{}}; + TableType* ttvConnection_ = getMutable(&ttvConnection); ttvConnection_->instantiatedTypeParams.push_back(&ttvTweenResult2); ttvConnection_->props["f"] = {&ftv12}; ttvConnection_->props["signal"] = {&ttvSignal}; @@ -245,10 +245,10 @@ TEST_CASE_FIXTURE(Fixture, "substitution_skip_failure") TypePackVar tp9{TypePack{}}; TypePackVar tp10{TypePack{{&ttvConnection}}}; - TypeVar ftv8{FunctionTypeVar{&tp9, &tp10}}; + Type ftv8{FunctionType{&tp9, &tp10}}; - TypeVar ttvTween{TableTypeVar{}}; - TableTypeVar* ttvTween_ = getMutable(&ttvTween); + Type ttvTween{TableType{}}; + TableType* ttvTween_ = getMutable(&ttvTween); ttvTween_->instantiatedTypeParams.push_back(>vK2); ttvTween_->instantiatedTypeParams.push_back(>vV2); ttvTween_->props["f"] = {&ftv8}; @@ -256,16 +256,16 @@ TEST_CASE_FIXTURE(Fixture, "substitution_skip_failure") TypePackVar tp4{TypePack{}}; TypePackVar tp5{TypePack{{&ttvTween}}}; - TypeVar ftv3{FunctionTypeVar{&tp4, &tp5}}; + Type ftv3{FunctionType{&tp4, &tp5}}; // Back edge ttvTweenResult2_->props["f"] = {&ftv3}; - TypeVar gtvK{GenericTypeVar{}}; - TypeVar gtvV{GenericTypeVar{}}; + Type gtvK{GenericType{}}; + Type gtvV{GenericType{}}; - TypeVar ttvTweenResult{TableTypeVar{}}; - TableTypeVar* ttvTweenResult_ = getMutable(&ttvTweenResult); + Type ttvTweenResult{TableType{}}; + TableType* ttvTweenResult_ = getMutable(&ttvTweenResult); ttvTweenResult_->instantiatedTypeParams.push_back(>vK); ttvTweenResult_->instantiatedTypeParams.push_back(>vV); ttvTweenResult_->props["f"] = {&ftv3}; @@ -273,7 +273,7 @@ TEST_CASE_FIXTURE(Fixture, "substitution_skip_failure") TypeId root = &ttvTweenResult; typeChecker.currentModule = std::make_shared(); - typeChecker.currentModule->scopes.emplace_back(Location{}, std::make_shared(singletonTypes->anyTypePack)); + typeChecker.currentModule->scopes.emplace_back(Location{}, std::make_shared(builtinTypes->anyTypePack)); TypeId result = typeChecker.anyify(typeChecker.globalScope, root, Location{}); @@ -282,7 +282,7 @@ TEST_CASE_FIXTURE(Fixture, "substitution_skip_failure") TEST_CASE("tagging_tables") { - TypeVar ttv{TableTypeVar{}}; + Type ttv{TableType{}}; CHECK(!Luau::hasTag(&ttv, "foo")); Luau::attachTag(&ttv, "foo"); CHECK(Luau::hasTag(&ttv, "foo")); @@ -290,7 +290,7 @@ TEST_CASE("tagging_tables") TEST_CASE("tagging_classes") { - TypeVar base{ClassTypeVar{"Base", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}}; + Type base{ClassType{"Base", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}}; CHECK(!Luau::hasTag(&base, "foo")); Luau::attachTag(&base, "foo"); CHECK(Luau::hasTag(&base, "foo")); @@ -298,8 +298,8 @@ TEST_CASE("tagging_classes") TEST_CASE("tagging_subclasses") { - TypeVar base{ClassTypeVar{"Base", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}}; - TypeVar derived{ClassTypeVar{"Derived", {}, &base, std::nullopt, {}, nullptr, "Test"}}; + Type base{ClassType{"Base", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"}}; + Type derived{ClassType{"Derived", {}, &base, std::nullopt, {}, nullptr, "Test"}}; CHECK(!Luau::hasTag(&base, "foo")); CHECK(!Luau::hasTag(&derived, "foo")); @@ -316,7 +316,7 @@ TEST_CASE("tagging_subclasses") TEST_CASE("tagging_functions") { TypePackVar empty{TypePack{}}; - TypeVar ftv{FunctionTypeVar{&empty, &empty}}; + Type ftv{FunctionType{&empty, &empty}}; CHECK(!Luau::hasTag(&ftv, "foo")); Luau::attachTag(&ftv, "foo"); CHECK(Luau::hasTag(&ftv, "foo")); @@ -330,7 +330,7 @@ TEST_CASE("tagging_props") CHECK(Luau::hasTag(prop, "foo")); } -struct VisitCountTracker final : TypeVarOnceVisitor +struct VisitCountTracker final : TypeOnceVisitor { std::unordered_map tyVisits; std::unordered_map tpVisits; @@ -385,65 +385,65 @@ local b: (T, T, T) -> T TEST_CASE("isString_on_string_singletons") { - TypeVar helloString{SingletonTypeVar{StringSingleton{"hello"}}}; + Type helloString{SingletonType{StringSingleton{"hello"}}}; CHECK(isString(&helloString)); } TEST_CASE("isString_on_unions_of_various_string_singletons") { - TypeVar helloString{SingletonTypeVar{StringSingleton{"hello"}}}; - TypeVar byeString{SingletonTypeVar{StringSingleton{"bye"}}}; - TypeVar union_{UnionTypeVar{{&helloString, &byeString}}}; + Type helloString{SingletonType{StringSingleton{"hello"}}}; + Type byeString{SingletonType{StringSingleton{"bye"}}}; + Type union_{UnionType{{&helloString, &byeString}}}; CHECK(isString(&union_)); } TEST_CASE("proof_that_isString_uses_all_of") { - TypeVar helloString{SingletonTypeVar{StringSingleton{"hello"}}}; - TypeVar byeString{SingletonTypeVar{StringSingleton{"bye"}}}; - TypeVar booleanType{PrimitiveTypeVar{PrimitiveTypeVar::Boolean}}; - TypeVar union_{UnionTypeVar{{&helloString, &byeString, &booleanType}}}; + Type helloString{SingletonType{StringSingleton{"hello"}}}; + Type byeString{SingletonType{StringSingleton{"bye"}}}; + Type booleanType{PrimitiveType{PrimitiveType::Boolean}}; + Type union_{UnionType{{&helloString, &byeString, &booleanType}}}; CHECK(!isString(&union_)); } TEST_CASE("isBoolean_on_boolean_singletons") { - TypeVar trueBool{SingletonTypeVar{BooleanSingleton{true}}}; + Type trueBool{SingletonType{BooleanSingleton{true}}}; CHECK(isBoolean(&trueBool)); } TEST_CASE("isBoolean_on_unions_of_true_or_false_singletons") { - TypeVar trueBool{SingletonTypeVar{BooleanSingleton{true}}}; - TypeVar falseBool{SingletonTypeVar{BooleanSingleton{false}}}; - TypeVar union_{UnionTypeVar{{&trueBool, &falseBool}}}; + Type trueBool{SingletonType{BooleanSingleton{true}}}; + Type falseBool{SingletonType{BooleanSingleton{false}}}; + Type union_{UnionType{{&trueBool, &falseBool}}}; CHECK(isBoolean(&union_)); } TEST_CASE("proof_that_isBoolean_uses_all_of") { - TypeVar trueBool{SingletonTypeVar{BooleanSingleton{true}}}; - TypeVar falseBool{SingletonTypeVar{BooleanSingleton{false}}}; - TypeVar stringType{PrimitiveTypeVar{PrimitiveTypeVar::String}}; - TypeVar union_{UnionTypeVar{{&trueBool, &falseBool, &stringType}}}; + Type trueBool{SingletonType{BooleanSingleton{true}}}; + Type falseBool{SingletonType{BooleanSingleton{false}}}; + Type stringType{PrimitiveType{PrimitiveType::String}}; + Type union_{UnionType{{&trueBool, &falseBool, &stringType}}}; CHECK(!isBoolean(&union_)); } TEST_CASE("content_reassignment") { - TypeVar myAny{AnyTypeVar{}, /*presistent*/ true}; + Type myAny{AnyType{}, /*presistent*/ true}; myAny.documentationSymbol = "@global/any"; TypeArena arena; - TypeId futureAny = arena.addType(FreeTypeVar{TypeLevel{}}); + TypeId futureAny = arena.addType(FreeType{TypeLevel{}}); asMutable(futureAny)->reassign(myAny); - CHECK(get(futureAny) != nullptr); + CHECK(get(futureAny) != nullptr); CHECK(!futureAny->persistent); CHECK(futureAny->documentationSymbol == "@global/any"); CHECK(futureAny->owningArena == &arena); diff --git a/tests/VisitTypeVar.test.cpp b/tests/VisitType.test.cpp similarity index 100% rename from tests/VisitTypeVar.test.cpp rename to tests/VisitType.test.cpp diff --git a/tools/faillist.txt b/tools/faillist.txt index 5d6779f4..233c75c1 100644 --- a/tools/faillist.txt +++ b/tools/faillist.txt @@ -4,11 +4,10 @@ AnnotationTests.for_loop_counter_annotation_is_checked AnnotationTests.generic_aliases_are_cloned_properly AnnotationTests.instantiation_clone_has_to_follow AnnotationTests.luau_print_is_not_special_without_the_flag -AnnotationTests.occurs_check_on_cyclic_intersection_typevar -AnnotationTests.occurs_check_on_cyclic_union_typevar +AnnotationTests.occurs_check_on_cyclic_intersection_type +AnnotationTests.occurs_check_on_cyclic_union_type AnnotationTests.too_many_type_params AnnotationTests.two_type_params -AnnotationTests.unknown_type_reference_generates_error AstQuery.last_argument_function_call_type AstQuery::getDocumentationSymbolAtPosition.overloaded_class_method AstQuery::getDocumentationSymbolAtPosition.overloaded_fn diff --git a/tools/natvis/Analysis.natvis b/tools/natvis/Analysis.natvis index 7d03dd3f..ca66cbe2 100644 --- a/tools/natvis/Analysis.natvis +++ b/tools/natvis/Analysis.natvis @@ -1,8 +1,8 @@ - - AnyTypeVar + + AnyType