Sync to upstream/release/557

This commit is contained in:
Vyacheslav Egorov 2023-01-03 19:33:19 +02:00
parent abe6768a1d
commit 9958d23caa
117 changed files with 3811 additions and 2584 deletions

View file

@ -4,7 +4,7 @@
#include "Luau/NotNull.h" #include "Luau/NotNull.h"
#include "Luau/Substitution.h" #include "Luau/Substitution.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include <memory> #include <memory>
@ -19,12 +19,12 @@ using ScopePtr = std::shared_ptr<Scope>;
// A substitution which replaces free types by any // A substitution which replaces free types by any
struct Anyification : Substitution struct Anyification : Substitution
{ {
Anyification(TypeArena* arena, NotNull<Scope> scope, NotNull<SingletonTypes> singletonTypes, InternalErrorReporter* iceHandler, TypeId anyType, Anyification(TypeArena* arena, NotNull<Scope> scope, NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter* iceHandler, TypeId anyType,
TypePackId anyTypePack); TypePackId anyTypePack);
Anyification(TypeArena* arena, const ScopePtr& scope, NotNull<SingletonTypes> singletonTypes, InternalErrorReporter* iceHandler, TypeId anyType, Anyification(TypeArena* arena, const ScopePtr& scope, NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter* iceHandler, TypeId anyType,
TypePackId anyTypePack); TypePackId anyTypePack);
NotNull<Scope> scope; NotNull<Scope> scope;
NotNull<SingletonTypes> singletonTypes; NotNull<BuiltinTypes> builtinTypes;
InternalErrorReporter* iceHandler; InternalErrorReporter* iceHandler;
TypeId anyType; TypeId anyType;

View file

@ -3,7 +3,7 @@
#include "Luau/Substitution.h" #include "Luau/Substitution.h"
#include "Luau/TxnLog.h" #include "Luau/TxnLog.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
namespace Luau namespace Luau
{ {

View file

@ -13,8 +13,8 @@ struct Binding;
struct SourceModule; struct SourceModule;
struct Module; struct Module;
struct TypeVar; struct Type;
using TypeId = const TypeVar*; using TypeId = const Type*;
using ScopePtr = std::shared_ptr<struct Scope>; using ScopePtr = std::shared_ptr<struct Scope>;

View file

@ -2,7 +2,7 @@
#pragma once #pragma once
#include "Luau/Location.h" #include "Luau/Location.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
@ -65,7 +65,7 @@ struct AutocompleteEntry
// Set if this suggestion matches the type expected in the context // Set if this suggestion matches the type expected in the context
TypeCorrectKind typeCorrect = TypeCorrectKind::None; TypeCorrectKind typeCorrect = TypeCorrectKind::None;
std::optional<const ClassTypeVar*> containingClass = std::nullopt; std::optional<const ClassType*> containingClass = std::nullopt;
std::optional<const Property*> prop = std::nullopt; std::optional<const Property*> prop = std::nullopt;
std::optional<std::string> documentationSymbol = std::nullopt; std::optional<std::string> documentationSymbol = std::nullopt;
Tags tags; Tags tags;
@ -89,7 +89,7 @@ struct AutocompleteResult
}; };
using ModuleName = std::string; using ModuleName = std::string;
using StringCompletionCallback = std::function<std::optional<AutocompleteEntryMap>(std::string tag, std::optional<const ClassTypeVar*> ctx)>; using StringCompletionCallback = std::function<std::optional<AutocompleteEntryMap>(std::string tag, std::optional<const ClassType*> ctx)>;
AutocompleteResult autocomplete(Frontend& frontend, const ModuleName& moduleName, Position position, StringCompletionCallback callback); AutocompleteResult autocomplete(Frontend& frontend, const ModuleName& moduleName, Position position, StringCompletionCallback callback);

View file

@ -2,7 +2,7 @@
#pragma once #pragma once
#include "Luau/Scope.h" #include "Luau/Scope.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include <optional> #include <optional>
@ -48,7 +48,7 @@ void attachDcrMagicFunction(TypeId ty, DcrMagicFunction fn);
void attachDcrMagicRefinement(TypeId ty, DcrMagicRefinement fn); void attachDcrMagicRefinement(TypeId ty, DcrMagicRefinement fn);
Property makeProperty(TypeId ty, std::optional<std::string> documentationSymbol = std::nullopt); Property makeProperty(TypeId ty, std::optional<std::string> documentationSymbol = std::nullopt);
void assignPropDocumentationSymbols(TableTypeVar::Props& props, const std::string& baseName); void assignPropDocumentationSymbols(TableType::Props& props, const std::string& baseName);
std::string getBuiltinDefinitionSource(); std::string getBuiltinDefinitionSource();

View file

@ -3,7 +3,7 @@
#include <Luau/NotNull.h> #include <Luau/NotNull.h>
#include "Luau/TypeArena.h" #include "Luau/TypeArena.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include <unordered_map> #include <unordered_map>

View file

@ -10,8 +10,8 @@
namespace Luau namespace Luau
{ {
struct TypeVar; struct Type;
using TypeId = const TypeVar*; using TypeId = const Type*;
struct Negation; struct Negation;
struct Conjunction; struct Conjunction;

View file

@ -5,7 +5,7 @@
#include "Luau/Def.h" #include "Luau/Def.h"
#include "Luau/DenseHash.h" #include "Luau/DenseHash.h"
#include "Luau/NotNull.h" #include "Luau/NotNull.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/Variant.h" #include "Luau/Variant.h"
#include <string> #include <string>
@ -17,8 +17,8 @@ namespace Luau
struct Scope; struct Scope;
struct TypeVar; struct Type;
using TypeId = const TypeVar*; using TypeId = const Type*;
struct TypePackVar; struct TypePackVar;
using TypePackId = const TypePackVar*; using TypePackId = const TypePackVar*;
@ -94,7 +94,7 @@ struct NameConstraint
// target ~ inst target // target ~ inst target
struct TypeAliasExpansionConstraint struct TypeAliasExpansionConstraint
{ {
// Must be a PendingExpansionTypeVar. // Must be a PendingExpansionType.
TypeId target; TypeId target;
}; };

View file

@ -9,7 +9,7 @@
#include "Luau/ModuleResolver.h" #include "Luau/ModuleResolver.h"
#include "Luau/NotNull.h" #include "Luau/NotNull.h"
#include "Luau/Symbol.h" #include "Luau/Symbol.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/Variant.h" #include "Luau/Variant.h"
#include <memory> #include <memory>
@ -61,7 +61,7 @@ struct ConstraintGraphBuilder
ModuleName moduleName; ModuleName moduleName;
ModulePtr module; ModulePtr module;
NotNull<SingletonTypes> singletonTypes; NotNull<BuiltinTypes> builtinTypes;
const NotNull<TypeArena> arena; const NotNull<TypeArena> arena;
// The root scope of the module we're generating constraints for. // The root scope of the module we're generating constraints for.
// This is null when the CGB is initially constructed. // This is null when the CGB is initially constructed.
@ -114,7 +114,7 @@ struct ConstraintGraphBuilder
DcrLogger* logger; DcrLogger* logger;
ConstraintGraphBuilder(const ModuleName& moduleName, ModulePtr module, TypeArena* arena, NotNull<ModuleResolver> moduleResolver, ConstraintGraphBuilder(const ModuleName& moduleName, ModulePtr module, TypeArena* arena, NotNull<ModuleResolver> moduleResolver,
NotNull<SingletonTypes> singletonTypes, NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope, DcrLogger* logger, NotNull<BuiltinTypes> builtinTypes, NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope, DcrLogger* logger,
NotNull<DataFlowGraph> dfg); NotNull<DataFlowGraph> dfg);
/** /**

View file

@ -7,7 +7,7 @@
#include "Luau/Module.h" #include "Luau/Module.h"
#include "Luau/Normalize.h" #include "Luau/Normalize.h"
#include "Luau/ToString.h" #include "Luau/ToString.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/Variant.h" #include "Luau/Variant.h"
#include <vector> #include <vector>
@ -44,7 +44,7 @@ struct HashInstantiationSignature
struct ConstraintSolver struct ConstraintSolver
{ {
TypeArena* arena; TypeArena* arena;
NotNull<SingletonTypes> singletonTypes; NotNull<BuiltinTypes> builtinTypes;
InternalErrorReporter iceReporter; InternalErrorReporter iceReporter;
NotNull<Normalizer> normalizer; NotNull<Normalizer> normalizer;
// The entire set of constraints that the solver is trying to resolve. // The entire set of constraints that the solver is trying to resolve.
@ -126,13 +126,13 @@ struct ConstraintSolver
void block(NotNull<const Constraint> target, NotNull<const Constraint> constraint); void block(NotNull<const Constraint> target, NotNull<const Constraint> 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() * @returns false always. This is just to allow tryDispatch to return the result of block()
*/ */
bool block(TypeId target, NotNull<const Constraint> constraint); bool block(TypeId target, NotNull<const Constraint> constraint);
bool block(TypePackId target, NotNull<const Constraint> constraint); bool block(TypePackId target, NotNull<const Constraint> 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. // the constraint on them.
// //
// Returns false if a type blocks the constraint. // Returns false if a type blocks the constraint.

View file

@ -2,7 +2,7 @@
#pragma once #pragma once
#include "Luau/Location.h" #include "Luau/Location.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/Variant.h" #include "Luau/Variant.h"
namespace Luau namespace Luau

View file

@ -130,8 +130,8 @@ struct Frontend
Frontend(FileResolver* fileResolver, ConfigResolver* configResolver, const FrontendOptions& options = {}); Frontend(FileResolver* fileResolver, ConfigResolver* configResolver, const FrontendOptions& options = {});
CheckResult check(const ModuleName& name, std::optional<FrontendOptions> optionOverride = {}); // new shininess CheckResult check(const ModuleName& name, std::optional<FrontendOptions> optionOverride = {}); // new shininess
LintResult lint(const ModuleName& name, std::optional<LintOptions> enabledLintWarnings = {});
LintResult lint(const ModuleName& name, std::optional<LintOptions> enabledLintWarnings = {});
LintResult lint(const SourceModule& module, std::optional<LintOptions> enabledLintWarnings = {}); LintResult lint(const SourceModule& module, std::optional<LintOptions> enabledLintWarnings = {});
bool isDirty(const ModuleName& name, bool forAutocomplete = false) const; 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<RequireCycle> requireCycles, ModulePtr check(const SourceModule& sourceModule, Mode mode, const ScopePtr& environmentScope, std::vector<RequireCycle> requireCycles,
bool forAutocomplete = false); bool forAutocomplete = false);
std::pair<SourceNode*, SourceModule*> getSourceNode(CheckResult& checkResult, const ModuleName& name); std::pair<SourceNode*, SourceModule*> getSourceNode(const ModuleName& name);
SourceModule parse(const ModuleName& name, std::string_view src, const ParseOptions& parseOptions); SourceModule parse(const ModuleName& name, std::string_view src, const ParseOptions& parseOptions);
bool parseGraph(std::vector<ModuleName>& buildQueue, CheckResult& checkResult, const ModuleName& root, bool forAutocomplete); bool parseGraph(std::vector<ModuleName>& buildQueue, const ModuleName& root, bool forAutocomplete);
static LintResult classifyLints(const std::vector<LintWarning>& warnings, const Config& config); static LintResult classifyLints(const std::vector<LintWarning>& 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<std::string, ScopePtr> environments; std::unordered_map<std::string, ScopePtr> environments;
std::unordered_map<std::string, std::function<void(TypeChecker&, ScopePtr)>> builtinDefinitions; std::unordered_map<std::string, std::function<void(TypeChecker&, ScopePtr)>> builtinDefinitions;
SingletonTypes singletonTypes_; BuiltinTypes builtinTypes_;
public: public:
const NotNull<SingletonTypes> singletonTypes; const NotNull<BuiltinTypes> builtinTypes;
FileResolver* fileResolver; FileResolver* fileResolver;
FrontendModuleResolver moduleResolver; FrontendModuleResolver moduleResolver;

View file

@ -2,7 +2,7 @@
#pragma once #pragma once
#include "Luau/Substitution.h" #include "Luau/Substitution.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/Unifiable.h" #include "Luau/Unifiable.h"
namespace Luau namespace Luau

View file

@ -3,7 +3,7 @@
#include "Luau/Error.h" #include "Luau/Error.h"
#include "Luau/Location.h" #include "Luau/Location.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/Ast.h" #include "Luau/Ast.h"
#include <ostream> #include <ostream>
@ -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 TypesAreUnrelated& error);
std::ostream& operator<<(std::ostream& lhs, const TableState& tv); 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 TypePackVar& tv);
std::ostream& operator<<(std::ostream& lhs, const TypeErrorData& ted); std::ostream& operator<<(std::ostream& lhs, const TypeErrorData& ted);

View file

@ -10,8 +10,8 @@
namespace Luau namespace Luau
{ {
struct TypeVar; struct Type;
using TypeId = const TypeVar*; using TypeId = const Type*;
struct Field; struct Field;

View file

@ -89,8 +89,8 @@ struct Module
ScopePtr getModuleScope() const; ScopePtr getModuleScope() const;
// Once a module has been typechecked, we clone its public interface into a separate arena. // 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. // This helps us to force Type ownership into a DAG rather than a DCG.
void clonePublicInterface(NotNull<SingletonTypes> singletonTypes, InternalErrorReporter& ice); void clonePublicInterface(NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter& ice);
}; };
} // namespace Luau } // namespace Luau

View file

@ -2,7 +2,7 @@
#pragma once #pragma once
#include "Luau/NotNull.h" #include "Luau/NotNull.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/UnifierSharedState.h" #include "Luau/UnifierSharedState.h"
#include <memory> #include <memory>
@ -13,12 +13,12 @@ namespace Luau
struct InternalErrorReporter; struct InternalErrorReporter;
struct Module; struct Module;
struct Scope; struct Scope;
struct SingletonTypes; struct BuiltinTypes;
using ModulePtr = std::shared_ptr<Module>; using ModulePtr = std::shared_ptr<Module>;
bool isSubtype(TypeId subTy, TypeId superTy, NotNull<Scope> scope, NotNull<SingletonTypes> singletonTypes, InternalErrorReporter& ice); bool isSubtype(TypeId subTy, TypeId superTy, NotNull<Scope> scope, NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter& ice);
bool isSubtype(TypePackId subTy, TypePackId superTy, NotNull<Scope> scope, NotNull<SingletonTypes> singletonTypes, InternalErrorReporter& ice); bool isSubtype(TypePackId subTy, TypePackId superTy, NotNull<Scope> scope, NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter& ice);
class TypeIds class TypeIds
{ {
@ -31,7 +31,7 @@ public:
using iterator = std::vector<TypeId>::iterator; using iterator = std::vector<TypeId>::iterator;
using const_iterator = std::vector<TypeId>::const_iterator; using const_iterator = std::vector<TypeId>::const_iterator;
TypeIds(const TypeIds&) = delete; TypeIds(const TypeIds&) = default;
TypeIds(TypeIds&&) = default; TypeIds(TypeIds&&) = default;
TypeIds() = default; TypeIds() = default;
~TypeIds() = default; ~TypeIds() = default;
@ -155,6 +155,32 @@ struct NormalizedStringType
bool isSubtype(const NormalizedStringType& subStr, const NormalizedStringType& superStr); 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<TypeId, TypeIds> 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<TypeId> ordering;
void pushPair(TypeId ty, TypeIds negations);
void resetToNever();
bool isNever() const;
};
// A normalized function type can be `never`, the top function type `function`, // A normalized function type can be `never`, the top function type `function`,
// or an intersection of function types. // or an intersection of function types.
// //
@ -200,9 +226,11 @@ struct NormalizedType
// This type is either never, boolean type, or a boolean singleton. // This type is either never, boolean type, or a boolean singleton.
TypeId booleans; TypeId booleans;
NormalizedClassType classes;
// The class part of the type. // The class part of the type.
// Each element of this set is a class, and none of the classes are subclasses of each other. // 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. // The error part of the type.
// This type is either never or the error type. // This type is either never or the error type.
@ -234,7 +262,7 @@ struct NormalizedType
// The generic/free part of the type. // The generic/free part of the type.
NormalizedTyvars tyvars; NormalizedTyvars tyvars;
NormalizedType(NotNull<SingletonTypes> singletonTypes); NormalizedType(NotNull<BuiltinTypes> builtinTypes);
NormalizedType() = delete; NormalizedType() = delete;
~NormalizedType() = default; ~NormalizedType() = default;
@ -256,10 +284,10 @@ class Normalizer
public: public:
TypeArena* arena; TypeArena* arena;
NotNull<SingletonTypes> singletonTypes; NotNull<BuiltinTypes> builtinTypes;
NotNull<UnifierSharedState> sharedState; NotNull<UnifierSharedState> sharedState;
Normalizer(TypeArena* arena, NotNull<SingletonTypes> singletonTypes, NotNull<UnifierSharedState> sharedState); Normalizer(TypeArena* arena, NotNull<BuiltinTypes> builtinTypes, NotNull<UnifierSharedState> sharedState);
Normalizer(const Normalizer&) = delete; Normalizer(const Normalizer&) = delete;
Normalizer(Normalizer&&) = delete; Normalizer(Normalizer&&) = delete;
Normalizer() = delete; Normalizer() = delete;
@ -283,6 +311,8 @@ public:
TypeId unionOfBools(TypeId here, TypeId there); TypeId unionOfBools(TypeId here, TypeId there);
void unionClassesWithClass(TypeIds& heres, TypeId there); void unionClassesWithClass(TypeIds& heres, TypeId there);
void unionClasses(TypeIds& heres, const TypeIds& theres); 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); void unionStrings(NormalizedStringType& here, const NormalizedStringType& there);
std::optional<TypePackId> unionOfTypePacks(TypePackId here, TypePackId there); std::optional<TypePackId> unionOfTypePacks(TypePackId here, TypePackId there);
std::optional<TypeId> unionOfFunctions(TypeId here, TypeId there); std::optional<TypeId> unionOfFunctions(TypeId here, TypeId there);
@ -304,8 +334,10 @@ public:
// ------- Normalizing intersections // ------- Normalizing intersections
TypeId intersectionOfTops(TypeId here, TypeId there); TypeId intersectionOfTops(TypeId here, TypeId there);
TypeId intersectionOfBools(TypeId here, TypeId there); TypeId intersectionOfBools(TypeId here, TypeId there);
void intersectClasses(TypeIds& heres, const TypeIds& theres); void DEPRECATED_intersectClasses(TypeIds& heres, const TypeIds& theres);
void intersectClassesWithClass(TypeIds& heres, TypeId there); 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); void intersectStrings(NormalizedStringType& here, const NormalizedStringType& there);
std::optional<TypePackId> intersectionOfTypePacks(TypePackId here, TypePackId there); std::optional<TypePackId> intersectionOfTypePacks(TypePackId here, TypePackId there);
std::optional<TypeId> intersectionOfTables(TypeId here, TypeId there); std::optional<TypeId> intersectionOfTables(TypeId here, TypeId there);

View file

@ -10,8 +10,8 @@
namespace Luau namespace Luau
{ {
struct TypeVar; struct Type;
using TypeId = const TypeVar*; using TypeId = const Type*;
struct TruthyPredicate; struct TruthyPredicate;
struct IsAPredicate; struct IsAPredicate;

View file

@ -1,7 +1,7 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once #pragma once
#include "Luau/TypeVar.h" #include "Luau/Type.h"
namespace Luau namespace Luau
{ {

View file

@ -3,7 +3,7 @@
#include "Luau/Location.h" #include "Luau/Location.h"
#include "Luau/NotNull.h" #include "Luau/NotNull.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include <unordered_map> #include <unordered_map>
#include <optional> #include <optional>

View file

@ -3,7 +3,7 @@
#include "Luau/TypeArena.h" #include "Luau/TypeArena.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/DenseHash.h" #include "Luau/DenseHash.h"
// We provide an implementation of substitution on types, // We provide an implementation of substitution on types,

View file

@ -7,8 +7,8 @@
namespace Luau namespace Luau
{ {
struct TypeVar; struct Type;
using TypeId = const TypeVar*; using TypeId = const Type*;
struct TypePackVar; struct TypePackVar;
using TypePackId = const TypePackVar*; using TypePackId = const TypePackVar*;

View file

@ -19,13 +19,13 @@ class AstExpr;
struct Scope; struct Scope;
struct TypeVar; struct Type;
using TypeId = const TypeVar*; using TypeId = const Type*;
struct TypePackVar; struct TypePackVar;
using TypePackId = const TypePackVar*; using TypePackId = const TypePackVar*;
struct FunctionTypeVar; struct FunctionType;
struct Constraint; struct Constraint;
struct Position; struct Position;
@ -33,7 +33,7 @@ struct Location;
struct ToStringNameMap struct ToStringNameMap
{ {
std::unordered_map<TypeId, std::string> typeVars; std::unordered_map<TypeId, std::string> types;
std::unordered_map<TypePackId, std::string> typePacks; std::unordered_map<TypePackId, std::string> typePacks;
}; };
@ -46,7 +46,7 @@ struct ToStringOptions
bool hideNamedFunctionTypeParameters = false; // If true, type parameters of functions will be hidden at top-level. 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 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 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); size_t maxTypeLength = size_t(FInt::LuauTypeMaximumStringifierLength);
ToStringNameMap nameMap; ToStringNameMap nameMap;
std::shared_ptr<Scope> scope; // If present, module names will be added and types that are not available in scope will be marked as 'invalid' std::shared_ptr<Scope> 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{}); 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); std::string toString(const TypePackVar& tp, ToStringOptions& opts);
inline std::string toString(const TypeVar& tv) inline std::string toString(const Type& tv)
{ {
ToStringOptions opts; ToStringOptions opts;
return toString(tv, opts); return toString(tv, opts);
@ -120,9 +120,9 @@ inline std::string toString(const TypePackVar& tp)
return toString(tp, opts); 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; ToStringOptions opts;
return toStringNamedFunction(funcName, ftv, opts); return toStringNamedFunction(funcName, ftv, opts);

View file

@ -1,7 +1,7 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once #pragma once
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include <memory> #include <memory>
@ -12,14 +12,14 @@ namespace Luau
using TypeOrPackId = const void*; 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. // TxnLog::commit.
struct PendingType struct PendingType
{ {
// The pending TypeVar state. // The pending Type state.
TypeVar pending; Type pending;
explicit PendingType(TypeVar state) explicit PendingType(Type state)
: pending(std::move(state)) : pending(std::move(state))
{ {
} }
@ -163,7 +163,7 @@ struct TxnLog
// Queues a replacement of a type with another type. // Queues a replacement of a type with another type.
// //
// The pointer returned lives until `commit` or `clear` is called. // 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. // Queues a replacement of a type pack with another type pack.
// //
@ -225,7 +225,7 @@ struct TxnLog
template<typename T> template<typename T>
PendingType* replace(TypeId ty, T replacement) 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 // 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 // Returns whether a given type or type pack is a given state, respecting the
// log's pending state. // 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<typename T, typename TID> template<typename T, typename TID>
bool is(TID ty) const bool is(TID ty) const
{ {
// We do not use getMutable here because this method can be called on // 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); auto* pendingTy = pending(ty);
if (pendingTy) if (pendingTy)
return Luau::get_if<T>(&pendingTy->pending.ty) != nullptr; return Luau::get_if<T>(&pendingTy->pending.ty) != nullptr;

View file

@ -69,46 +69,45 @@ using ScopePtr = std::shared_ptr<Scope>;
struct TypePackVar; struct TypePackVar;
using TypePackId = const TypePackVar*; using TypePackId = const TypePackVar*;
// TODO: rename to Type? CLI-39100 struct Type;
struct TypeVar;
// Should never be null // Should never be null
using TypeId = const TypeVar*; using TypeId = const Type*;
using Name = std::string; using Name = std::string;
// A free type var is one whose exact shape has yet to be fully determined. // 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" // 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. // to that type var, indicating that the two types are actually the same type.
using BoundTypeVar = Unifiable::Bound<TypeId>; using BoundType = Unifiable::Bound<TypeId>;
using GenericTypeVar = Unifiable::Generic; using GenericType = Unifiable::Generic;
using Tags = std::vector<std::string>; using Tags = std::vector<std::string>;
using ModuleName = std::string; 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 * BlockedTypes essentially serve as a way to encode partial ordering on the
* constraint graph. Until a BlockedTypeVar is unblocked by its owning * constraint graph. Until a BlockedType is unblocked by its owning
* constraint, nothing at all can be said about it. Constraints that need to * 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. * that will eventually unblock it.
*/ */
struct BlockedTypeVar struct BlockedType
{ {
BlockedTypeVar(); BlockedType();
int index; int index;
static int nextIndex; static int nextIndex;
}; };
struct PrimitiveTypeVar struct PrimitiveType
{ {
enum Type enum Type
{ {
@ -123,12 +122,12 @@ struct PrimitiveTypeVar
Type type; Type type;
std::optional<TypeId> metatable; // string has a metatable std::optional<TypeId> metatable; // string has a metatable
explicit PrimitiveTypeVar(Type type) explicit PrimitiveType(Type type)
: type(type) : type(type)
{ {
} }
explicit PrimitiveTypeVar(Type type, TypeId metatable) explicit PrimitiveType(Type type, TypeId metatable)
: type(type) : type(type)
, metatable(metatable) , metatable(metatable)
{ {
@ -173,25 +172,25 @@ struct StringSingleton
using SingletonVariant = Luau::Variant<BooleanSingleton, StringSingleton>; using SingletonVariant = Luau::Variant<BooleanSingleton, StringSingleton>;
struct SingletonTypeVar struct SingletonType
{ {
explicit SingletonTypeVar(const SingletonVariant& variant) explicit SingletonType(const SingletonVariant& variant)
: variant(variant) : variant(variant)
{ {
} }
explicit SingletonTypeVar(SingletonVariant&& variant) explicit SingletonType(SingletonVariant&& variant)
: variant(std::move(variant)) : variant(std::move(variant))
{ {
} }
// Default operator== is C++20. // Default operator== is C++20.
bool operator==(const SingletonTypeVar& rhs) const bool operator==(const SingletonType& rhs) const
{ {
return variant == rhs.variant; return variant == rhs.variant;
} }
bool operator!=(const SingletonTypeVar& rhs) const bool operator!=(const SingletonType& rhs) const
{ {
return !(*this == rhs); return !(*this == rhs);
} }
@ -200,7 +199,7 @@ struct SingletonTypeVar
}; };
template<typename T> template<typename T>
const T* get(const SingletonTypeVar* stv) const T* get(const SingletonType* stv)
{ {
if (stv) if (stv)
return get_if<T>(&stv->variant); return get_if<T>(&stv->variant);
@ -240,7 +239,7 @@ struct FunctionDefinition
// TODO: Come up with a better name. // TODO: Come up with a better name.
// TODO: Do we actually need this? We'll find out later if we can delete this. // 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<typename T> template<typename T>
struct WithPredicate struct WithPredicate
{ {
@ -273,24 +272,24 @@ struct MagicRefinementContext
using DcrMagicRefinement = std::vector<ConnectiveId> (*)(const MagicRefinementContext&); using DcrMagicRefinement = std::vector<ConnectiveId> (*)(const MagicRefinementContext&);
struct FunctionTypeVar struct FunctionType
{ {
// Global monomorphic function // Global monomorphic function
FunctionTypeVar(TypePackId argTypes, TypePackId retTypes, std::optional<FunctionDefinition> defn = {}, bool hasSelf = false); FunctionType(TypePackId argTypes, TypePackId retTypes, std::optional<FunctionDefinition> defn = {}, bool hasSelf = false);
// Global polymorphic function // Global polymorphic function
FunctionTypeVar(std::vector<TypeId> generics, std::vector<TypePackId> genericPacks, TypePackId argTypes, TypePackId retTypes, FunctionType(std::vector<TypeId> generics, std::vector<TypePackId> genericPacks, TypePackId argTypes, TypePackId retTypes,
std::optional<FunctionDefinition> defn = {}, bool hasSelf = false); std::optional<FunctionDefinition> defn = {}, bool hasSelf = false);
// Local monomorphic function // Local monomorphic function
FunctionTypeVar(TypeLevel level, TypePackId argTypes, TypePackId retTypes, std::optional<FunctionDefinition> defn = {}, bool hasSelf = false); FunctionType(TypeLevel level, TypePackId argTypes, TypePackId retTypes, std::optional<FunctionDefinition> defn = {}, bool hasSelf = false);
FunctionTypeVar( FunctionType(
TypeLevel level, Scope* scope, TypePackId argTypes, TypePackId retTypes, std::optional<FunctionDefinition> defn = {}, bool hasSelf = false); TypeLevel level, Scope* scope, TypePackId argTypes, TypePackId retTypes, std::optional<FunctionDefinition> defn = {}, bool hasSelf = false);
// Local polymorphic function // Local polymorphic function
FunctionTypeVar(TypeLevel level, std::vector<TypeId> generics, std::vector<TypePackId> genericPacks, TypePackId argTypes, TypePackId retTypes, FunctionType(TypeLevel level, std::vector<TypeId> generics, std::vector<TypePackId> genericPacks, TypePackId argTypes, TypePackId retTypes,
std::optional<FunctionDefinition> defn = {}, bool hasSelf = false); std::optional<FunctionDefinition> defn = {}, bool hasSelf = false);
FunctionTypeVar(TypeLevel level, Scope* scope, std::vector<TypeId> generics, std::vector<TypePackId> genericPacks, TypePackId argTypes, FunctionType(TypeLevel level, Scope* scope, std::vector<TypeId> generics, std::vector<TypePackId> genericPacks, TypePackId argTypes,
TypePackId retTypes, std::optional<FunctionDefinition> defn = {}, bool hasSelf = false); TypePackId retTypes, std::optional<FunctionDefinition> defn = {}, bool hasSelf = false);
std::optional<FunctionDefinition> definition; std::optional<FunctionDefinition> definition;
@ -348,7 +347,7 @@ struct Property
std::optional<std::string> documentationSymbol; std::optional<std::string> documentationSymbol;
}; };
struct TableTypeVar struct TableType
{ {
// We choose std::map over unordered_map here just because we have unit tests that compare // 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 // 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. // If this shows up in a profile, we can revisit it.
using Props = std::map<Name, Property>; using Props = std::map<Name, Property>;
TableTypeVar() = default; TableType() = default;
explicit TableTypeVar(TableState state, TypeLevel level, Scope* scope = nullptr); explicit TableType(TableState state, TypeLevel level, Scope* scope = nullptr);
TableTypeVar(const Props& props, const std::optional<TableIndexer>& indexer, TypeLevel level, TableState state); TableType(const Props& props, const std::optional<TableIndexer>& indexer, TypeLevel level, TableState state);
TableTypeVar(const Props& props, const std::optional<TableIndexer>& indexer, TypeLevel level, Scope* scope, TableState state); TableType(const Props& props, const std::optional<TableIndexer>& indexer, TypeLevel level, Scope* scope, TableState state);
Props props; Props props;
std::optional<TableIndexer> indexer; std::optional<TableIndexer> indexer;
@ -384,12 +383,12 @@ struct TableTypeVar
std::optional<TypeId> selfTy; std::optional<TypeId> selfTy;
}; };
// Represents a metatable attached to a table typevar. Somewhat analogous to a bound typevar. // Represents a metatable attached to a table type. Somewhat analogous to a bound type.
struct MetatableTypeVar struct MetatableType
{ {
// Always points to a TableTypeVar. // Always points to a TableType.
TypeId table; TypeId table;
// Always points to either a TableTypeVar or a MetatableTypeVar. // Always points to either a TableType or a MetatableType.
TypeId metatable; TypeId metatable;
std::optional<std::string> syntheticName; std::optional<std::string> syntheticName;
@ -409,9 +408,9 @@ struct ClassUserData
* Classes optionally have a parent class. * Classes optionally have a parent class.
* Two different classes that share the same properties are nevertheless distinct and mutually incompatible. * 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; Name name;
Props props; Props props;
@ -421,7 +420,7 @@ struct ClassTypeVar
std::shared_ptr<ClassUserData> userData; std::shared_ptr<ClassUserData> userData;
ModuleName definitionModuleName; ModuleName definitionModuleName;
ClassTypeVar(Name name, Props props, std::optional<TypeId> parent, std::optional<TypeId> metatable, Tags tags, ClassType(Name name, Props props, std::optional<TypeId> parent, std::optional<TypeId> metatable, Tags tags,
std::shared_ptr<ClassUserData> userData, ModuleName definitionModuleName) std::shared_ptr<ClassUserData> userData, ModuleName definitionModuleName)
: name(name) : name(name)
, props(props) , props(props)
@ -474,13 +473,13 @@ struct TypeFun
* *
* In order to afford (co)recursive type aliases, we need to reason about a * In order to afford (co)recursive type aliases, we need to reason about a
* partially-complete instantiation. This requires encoding more information in * partially-complete instantiation. This requires encoding more information in
* a type variable than a BlockedTypeVar affords, hence this. Each * a type variable than a BlockedType affords, hence this. Each
* PendingExpansionTypeVar has a corresponding TypeAliasExpansionConstraint * PendingExpansionType has a corresponding TypeAliasExpansionConstraint
* enqueued in the solver to convert it to an actual instantiated type * enqueued in the solver to convert it to an actual instantiated type
*/ */
struct PendingExpansionTypeVar struct PendingExpansionType
{ {
PendingExpansionTypeVar(std::optional<AstName> prefix, AstName name, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments); PendingExpansionType(std::optional<AstName> prefix, AstName name, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments);
std::optional<AstName> prefix; std::optional<AstName> prefix;
AstName name; AstName name;
std::vector<TypeId> typeArguments; std::vector<TypeId> typeArguments;
@ -491,69 +490,68 @@ struct PendingExpansionTypeVar
}; };
// Anything! All static checking is off. // Anything! All static checking is off.
struct AnyTypeVar struct AnyType
{ {
}; };
// T | U // T | U
struct UnionTypeVar struct UnionType
{ {
std::vector<TypeId> options; std::vector<TypeId> options;
}; };
// T & U // T & U
struct IntersectionTypeVar struct IntersectionType
{ {
std::vector<TypeId> parts; std::vector<TypeId> parts;
}; };
struct LazyTypeVar struct LazyType
{ {
std::function<TypeId()> thunk; std::function<TypeId()> thunk;
}; };
struct UnknownTypeVar struct UnknownType
{ {
}; };
struct NeverTypeVar struct NeverType
{ {
}; };
// ~T // ~T
// TODO: Some simplification step that overwrites the type graph to make sure negation // 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 // types disappear from the user's view, and (?) a debug flag to disable that
struct NegationTypeVar struct NegationType
{ {
TypeId ty; TypeId ty;
}; };
using ErrorTypeVar = Unifiable::Error; using ErrorType = Unifiable::Error;
using TypeVariant = using TypeVariant = Unifiable::Variant<TypeId, PrimitiveType, BlockedType, PendingExpansionType, SingletonType, FunctionType, TableType,
Unifiable::Variant<TypeId, PrimitiveTypeVar, BlockedTypeVar, PendingExpansionTypeVar, SingletonTypeVar, FunctionTypeVar, TableTypeVar, MetatableType, ClassType, AnyType, UnionType, IntersectionType, LazyType, UnknownType, NeverType, NegationType>;
MetatableTypeVar, ClassTypeVar, AnyTypeVar, UnionTypeVar, IntersectionTypeVar, LazyTypeVar, UnknownTypeVar, NeverTypeVar, NegationTypeVar>;
struct TypeVar final struct Type final
{ {
explicit TypeVar(const TypeVariant& ty) explicit Type(const TypeVariant& ty)
: ty(ty) : ty(ty)
{ {
} }
explicit TypeVar(TypeVariant&& ty) explicit Type(TypeVariant&& ty)
: ty(std::move(ty)) : ty(std::move(ty))
{ {
} }
TypeVar(const TypeVariant& ty, bool persistent) Type(const TypeVariant& ty, bool persistent)
: ty(ty) : ty(ty)
, persistent(persistent) , persistent(persistent)
{ {
} }
// Re-assignes the content of the type, but doesn't change the owning arena and can't make type 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; ty = rhs.ty;
documentationSymbol = rhs.documentationSymbol; documentationSymbol = rhs.documentationSymbol;
@ -561,9 +559,9 @@ struct TypeVar final
TypeVariant ty; 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. // 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; bool persistent = false;
std::optional<std::string> documentationSymbol; std::optional<std::string> documentationSymbol;
@ -571,25 +569,25 @@ struct TypeVar final
// Pointer to the type arena that allocated this type. // Pointer to the type arena that allocated this type.
TypeArena* owningArena = nullptr; TypeArena* owningArena = nullptr;
bool operator==(const TypeVar& rhs) const; bool operator==(const Type& rhs) const;
bool operator!=(const TypeVar& rhs) const; bool operator!=(const Type& rhs) const;
TypeVar& operator=(const TypeVariant& rhs); Type& operator=(const TypeVariant& rhs);
TypeVar& operator=(TypeVariant&& rhs); Type& operator=(TypeVariant&& rhs);
TypeVar& operator=(const TypeVar& rhs); Type& operator=(const Type& rhs);
}; };
using SeenSet = std::set<std::pair<const void*, const void*>>; using SeenSet = std::set<std::pair<const void*, const void*>>;
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);
TypeId follow(TypeId t, std::function<TypeId(TypeId)> mapper); TypeId follow(TypeId t, std::function<TypeId(TypeId)> mapper);
std::vector<TypeId> flattenIntersection(TypeId ty); std::vector<TypeId> flattenIntersection(TypeId ty);
bool isPrim(TypeId ty, PrimitiveTypeVar::Type primType); bool isPrim(TypeId ty, PrimitiveType::Type primType);
bool isNil(TypeId ty); bool isNil(TypeId ty);
bool isBoolean(TypeId ty); bool isBoolean(TypeId ty);
bool isNumber(TypeId ty); bool isNumber(TypeId ty);
@ -602,9 +600,9 @@ bool isOverloadedFunction(TypeId ty);
// True when string is a subtype of ty // True when string is a subtype of ty
bool maybeString(TypeId ty); bool maybeString(TypeId ty);
std::optional<TypeId> getMetatable(TypeId type, NotNull<struct SingletonTypes> singletonTypes); std::optional<TypeId> getMetatable(TypeId type, NotNull<struct BuiltinTypes> builtinTypes);
TableTypeVar* getMutableTableType(TypeId type); TableType* getMutableTableType(TypeId type);
const TableTypeVar* getTableType(TypeId type); const TableType* getTableType(TypeId type);
// If the type has a name, return that. Else if it has a synthetic name, return that. // 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. // Returns nullptr if the type has no name.
@ -614,7 +612,7 @@ const std::string* getName(TypeId type);
std::optional<ModuleName> getDefinitionModuleName(TypeId type); std::optional<ModuleName> getDefinitionModuleName(TypeId type);
// Checks whether a union contains all types of another union. // 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 // Checks if a type contains generic type binders
bool isGeneric(const TypeId ty); 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 // Checks if the length operator can be applied on the value of type
bool hasLength(TypeId ty, DenseHashSet<TypeId>& seen, int* recursionCount); bool hasLength(TypeId ty, DenseHashSet<TypeId>& seen, int* recursionCount);
struct SingletonTypes struct BuiltinTypes
{ {
SingletonTypes(); BuiltinTypes();
~SingletonTypes(); ~BuiltinTypes();
SingletonTypes(const SingletonTypes&) = delete; BuiltinTypes(const BuiltinTypes&) = delete;
void operator=(const SingletonTypes&) = delete; void operator=(const BuiltinTypes&) = delete;
TypeId errorRecoveryType(TypeId guess); TypeId errorRecoveryType(TypeId guess);
TypePackId errorRecoveryTypePack(TypePackId guess); TypePackId errorRecoveryTypePack(TypePackId guess);
@ -653,6 +651,7 @@ public:
const TypeId booleanType; const TypeId booleanType;
const TypeId threadType; const TypeId threadType;
const TypeId functionType; const TypeId functionType;
const TypeId classType;
const TypeId trueType; const TypeId trueType;
const TypeId falseType; const TypeId falseType;
const TypeId anyType; const TypeId anyType;
@ -676,18 +675,18 @@ TypeLevel* getMutableLevel(TypeId ty);
std::optional<TypeLevel> getLevel(TypePackId tp); std::optional<TypeLevel> getLevel(TypePackId tp);
const Property* lookupClassProp(const ClassTypeVar* cls, const Name& name); const Property* lookupClassProp(const ClassType* cls, const Name& name);
bool isSubclass(const ClassTypeVar* cls, const ClassTypeVar* parent); bool isSubclass(const ClassType* cls, const ClassType* parent);
TypeVar* asMutable(TypeId ty); Type* asMutable(TypeId ty);
template<typename T> template<typename T>
const T* get(TypeId tv) const T* get(TypeId tv)
{ {
LUAU_ASSERT(tv); LUAU_ASSERT(tv);
if constexpr (!std::is_same_v<T, BoundTypeVar>) if constexpr (!std::is_same_v<T, BoundType>)
LUAU_ASSERT(get_if<BoundTypeVar>(&tv->ty) == nullptr); LUAU_ASSERT(get_if<BoundType>(&tv->ty) == nullptr);
return get_if<T>(&tv->ty); return get_if<T>(&tv->ty);
} }
@ -697,25 +696,25 @@ T* getMutable(TypeId tv)
{ {
LUAU_ASSERT(tv); LUAU_ASSERT(tv);
if constexpr (!std::is_same_v<T, BoundTypeVar>) if constexpr (!std::is_same_v<T, BoundType>)
LUAU_ASSERT(get_if<BoundTypeVar>(&tv->ty) == nullptr); LUAU_ASSERT(get_if<BoundType>(&tv->ty) == nullptr);
return get_if<T>(&asMutable(tv)->ty); return get_if<T>(&asMutable(tv)->ty);
} }
const std::vector<TypeId>& getTypes(const UnionTypeVar* utv); const std::vector<TypeId>& getTypes(const UnionType* utv);
const std::vector<TypeId>& getTypes(const IntersectionTypeVar* itv); const std::vector<TypeId>& getTypes(const IntersectionType* itv);
template<typename T> template<typename T>
struct TypeIterator; struct TypeIterator;
using UnionTypeVarIterator = TypeIterator<UnionTypeVar>; using UnionTypeIterator = TypeIterator<UnionType>;
UnionTypeVarIterator begin(const UnionTypeVar* utv); UnionTypeIterator begin(const UnionType* utv);
UnionTypeVarIterator end(const UnionTypeVar* utv); UnionTypeIterator end(const UnionType* utv);
using IntersectionTypeVarIterator = TypeIterator<IntersectionTypeVar>; using IntersectionTypeIterator = TypeIterator<IntersectionType>;
IntersectionTypeVarIterator begin(const IntersectionTypeVar* itv); IntersectionTypeIterator begin(const IntersectionType* itv);
IntersectionTypeVarIterator end(const IntersectionTypeVar* itv); IntersectionTypeIterator end(const IntersectionType* itv);
/* Traverses the type T yielding each TypeId. /* Traverses the type T yielding each TypeId.
* If the iterator encounters a nested type T, it will instead yield each TypeId within. * 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 // 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. // with templates portability in this area, so not worth it. Thanks MSVC.
friend UnionTypeVarIterator end(const UnionTypeVar*); friend UnionTypeIterator end(const UnionType*);
friend IntersectionTypeVarIterator end(const IntersectionTypeVar*); friend IntersectionTypeIterator end(const IntersectionType*);
private: private:
TypeIterator() = default; TypeIterator() = default;

View file

@ -2,7 +2,7 @@
#pragma once #pragma once
#include "Luau/TypedAllocator.h" #include "Luau/TypedAllocator.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include <vector> #include <vector>
@ -12,7 +12,7 @@ namespace Luau
struct TypeArena struct TypeArena
{ {
TypedAllocator<TypeVar> typeVars; TypedAllocator<Type> types;
TypedAllocator<TypePackVar> typePacks; TypedAllocator<TypePackVar> typePacks;
void clear(); void clear();
@ -20,13 +20,13 @@ struct TypeArena
template<typename T> template<typename T>
TypeId addType(T tv) TypeId addType(T tv)
{ {
if constexpr (std::is_same_v<T, UnionTypeVar>) if constexpr (std::is_same_v<T, UnionType>)
LUAU_ASSERT(tv.options.size() >= 2); 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(TypeLevel level);
TypeId freshType(Scope* scope); TypeId freshType(Scope* scope);

View file

@ -10,8 +10,8 @@ namespace Luau
{ {
struct DcrLogger; struct DcrLogger;
struct SingletonTypes; struct BuiltinTypes;
void check(NotNull<SingletonTypes> singletonTypes, DcrLogger* logger, const SourceModule& sourceModule, Module* module); void check(NotNull<BuiltinTypes> builtinTypes, DcrLogger* logger, const SourceModule& sourceModule, Module* module);
} // namespace Luau } // namespace Luau

View file

@ -9,7 +9,7 @@
#include "Luau/Substitution.h" #include "Luau/Substitution.h"
#include "Luau/TxnLog.h" #include "Luau/TxnLog.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/Unifier.h" #include "Luau/Unifier.h"
#include "Luau/UnifierSharedState.h" #include "Luau/UnifierSharedState.h"
@ -28,7 +28,7 @@ struct ModuleResolver;
using Name = std::string; using Name = std::string;
using ScopePtr = std::shared_ptr<Scope>; using ScopePtr = std::shared_ptr<Scope>;
using OverloadErrorEntry = std::tuple<std::vector<TypeError>, std::vector<TypeId>, const FunctionTypeVar*>; using OverloadErrorEntry = std::tuple<std::vector<TypeError>, std::vector<TypeId>, const FunctionType*>;
bool doesCallError(const AstExprCall* call); bool doesCallError(const AstExprCall* call);
bool hasBreak(AstStat* node); 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. // within a program are borrowed pointers into this set.
struct TypeChecker struct TypeChecker
{ {
explicit TypeChecker(ModuleResolver* resolver, NotNull<SingletonTypes> singletonTypes, InternalErrorReporter* iceHandler); explicit TypeChecker(ModuleResolver* resolver, NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter* iceHandler);
TypeChecker(const TypeChecker&) = delete; TypeChecker(const TypeChecker&) = delete;
TypeChecker& operator=(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. // Reports an error if the type is already some kind of non-table.
void tablify(TypeId type); 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; 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); TypeId unionOfTypes(TypeId a, TypeId b, const ScopePtr& scope, const Location& location, bool unifyFreeTypes = true);
// ex // ex
// TypeId id = addType(FreeTypeVar()); // TypeId id = addType(FreeType());
template<typename T> template<typename T>
TypeId addType(const T& tv) 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(TypePackVar&& tp);
TypePackId addTypePack(TypePack&& tp); TypePackId addTypePack(TypePack&& tp);
@ -343,7 +343,7 @@ public:
* Calling this function means submitting evidence that the pack must have the length provided. * 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. * 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 * 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<TypeId> unTypePack(const ScopePtr& scope, TypePackId pack, size_t expectedLength, const Location& location); std::vector<TypeId> unTypePack(const ScopePtr& scope, TypePackId pack, size_t expectedLength, const Location& location);
@ -356,7 +356,7 @@ public:
ModuleName currentModuleName; ModuleName currentModuleName;
std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope; std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope;
NotNull<SingletonTypes> singletonTypes; NotNull<BuiltinTypes> builtinTypes;
InternalErrorReporter* iceHandler; InternalErrorReporter* iceHandler;
UnifierSharedState unifierState; UnifierSharedState unifierState;

View file

@ -1,7 +1,7 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#pragma once #pragma once
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/Unifiable.h" #include "Luau/Unifiable.h"
#include "Luau/Variant.h" #include "Luau/Variant.h"
@ -45,7 +45,7 @@ struct VariadicTypePack
}; };
/** /**
* Analogous to a BlockedTypeVar. * Analogous to a BlockedType.
*/ */
struct BlockedTypePack struct BlockedTypePack
{ {
@ -83,7 +83,7 @@ struct TypePackVar
/* Walk the set of TypeIds in a TypePack. /* 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 * 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 * iterator a .tail() property that yields the tail-most TypePack in the

View file

@ -3,7 +3,7 @@
#include "Luau/Error.h" #include "Luau/Error.h"
#include "Luau/Location.h" #include "Luau/Location.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include <memory> #include <memory>
@ -18,16 +18,16 @@ struct TypeArena;
using ScopePtr = std::shared_ptr<struct Scope>; using ScopePtr = std::shared_ptr<struct Scope>;
std::optional<TypeId> findMetatableEntry( std::optional<TypeId> findMetatableEntry(
NotNull<SingletonTypes> singletonTypes, ErrorVec& errors, TypeId type, const std::string& entry, Location location); NotNull<BuiltinTypes> builtinTypes, ErrorVec& errors, TypeId type, const std::string& entry, Location location);
std::optional<TypeId> findTablePropertyRespectingMeta( std::optional<TypeId> findTablePropertyRespectingMeta(
NotNull<SingletonTypes> singletonTypes, ErrorVec& errors, TypeId ty, const std::string& name, Location location); NotNull<BuiltinTypes> builtinTypes, ErrorVec& errors, TypeId ty, const std::string& name, Location location);
// Returns the minimum and maximum number of types the argument list can accept. // Returns the minimum and maximum number of types the argument list can accept.
std::pair<size_t, std::optional<size_t>> getParameterExtents(const TxnLog* log, TypePackId tp, bool includeHiddenVariadics = false); std::pair<size_t, std::optional<size_t>> getParameterExtents(const TxnLog* log, TypePackId tp, bool includeHiddenVariadics = false);
// Extend the provided pack to at least `length` types. // Extend the provided pack to at least `length` types.
// Returns a temporary TypePack that contains those types plus a tail. // Returns a temporary TypePack that contains those types plus a tail.
TypePack extendTypePack(TypeArena& arena, NotNull<SingletonTypes> singletonTypes, TypePackId pack, size_t length); TypePack extendTypePack(TypeArena& arena, NotNull<BuiltinTypes> builtinTypes, TypePackId pack, size_t length);
/** /**
* Reduces a union by decomposing to the any/error type if it appears in the * Reduces a union by decomposing to the any/error type if it appears in the
@ -41,11 +41,11 @@ std::vector<TypeId> reduceUnion(const std::vector<TypeId>& types);
/** /**
* Tries to remove nil from a union type, if there's another option. T | nil * Tries to remove nil from a union type, if there's another option. T | nil
* reduces to T, but nil itself does not reduce. * 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 arena the type arena to allocate the new type in, if necessary
* @param ty the type to remove nil from * @param ty the type to remove nil from
* @returns a type with nil removed, or nil itself if that were the only option. * @returns a type with nil removed, or nil itself if that were the only option.
*/ */
TypeId stripNil(NotNull<SingletonTypes> singletonTypes, TypeArena& arena, TypeId ty); TypeId stripNil(NotNull<BuiltinTypes> builtinTypes, TypeArena& arena, TypeId ty);
} // namespace Luau } // namespace Luau

View file

@ -11,7 +11,7 @@ namespace Luau
struct Scope; 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 * 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 * We extend the idea by adding a "sub-level" which helps us to differentiate sibling scopes
@ -132,7 +132,7 @@ private:
struct Error 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. // but shouldn't be called directly. Please use errorRecoveryType() instead.
Error(); Error();

View file

@ -25,13 +25,13 @@ enum Variance
// A substitution which replaces singleton types by their wider types // A substitution which replaces singleton types by their wider types
struct Widen : Substitution struct Widen : Substitution
{ {
Widen(TypeArena* arena, NotNull<SingletonTypes> singletonTypes) Widen(TypeArena* arena, NotNull<BuiltinTypes> builtinTypes)
: Substitution(TxnLog::empty(), arena) : Substitution(TxnLog::empty(), arena)
, singletonTypes(singletonTypes) , builtinTypes(builtinTypes)
{ {
} }
NotNull<SingletonTypes> singletonTypes; NotNull<BuiltinTypes> builtinTypes;
bool isDirty(TypeId ty) override; bool isDirty(TypeId ty) override;
bool isDirty(TypePackId ty) override; bool isDirty(TypePackId ty) override;
@ -52,7 +52,7 @@ struct UnifierOptions
struct Unifier struct Unifier
{ {
TypeArena* const types; TypeArena* const types;
NotNull<SingletonTypes> singletonTypes; NotNull<BuiltinTypes> builtinTypes;
NotNull<Normalizer> normalizer; NotNull<Normalizer> normalizer;
Mode mode; Mode mode;
@ -82,10 +82,10 @@ struct Unifier
private: private:
void tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall = false, bool isIntersection = false); void tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall = false, bool isIntersection = false);
void tryUnifyUnionWithType(TypeId subTy, const UnionTypeVar* uv, TypeId superTy); void tryUnifyUnionWithType(TypeId subTy, const UnionType* uv, TypeId superTy);
void tryUnifyTypeWithUnion(TypeId subTy, TypeId superTy, const UnionTypeVar* uv, bool cacheEnabled, bool isFunctionCall); void tryUnifyTypeWithUnion(TypeId subTy, TypeId superTy, const UnionType* uv, bool cacheEnabled, bool isFunctionCall);
void tryUnifyTypeWithIntersection(TypeId subTy, TypeId superTy, const IntersectionTypeVar* uv); void tryUnifyTypeWithIntersection(TypeId subTy, TypeId superTy, const IntersectionType* uv);
void tryUnifyIntersectionWithType(TypeId subTy, const IntersectionTypeVar* uv, TypeId superTy, bool cacheEnabled, bool isFunctionCall); 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, void tryUnifyNormalizedTypes(TypeId subTy, TypeId superTy, const NormalizedType& subNorm, const NormalizedType& superNorm, std::string reason,
std::optional<TypeError> error = std::nullopt); std::optional<TypeError> error = std::nullopt);
void tryUnifyPrimitives(TypeId subTy, TypeId superTy); void tryUnifyPrimitives(TypeId subTy, TypeId superTy);

View file

@ -3,7 +3,7 @@
#include "Luau/DenseHash.h" #include "Luau/DenseHash.h"
#include "Luau/Error.h" #include "Luau/Error.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include <utility> #include <utility>

View file

@ -6,7 +6,7 @@
#include "Luau/DenseHash.h" #include "Luau/DenseHash.h"
#include "Luau/RecursionCounter.h" #include "Luau/RecursionCounter.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
LUAU_FASTINT(LuauVisitRecursionLimit) LUAU_FASTINT(LuauVisitRecursionLimit)
LUAU_FASTFLAG(LuauCompleteVisitor); 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) * 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<typename F, typename A, typename B, typename C> template<typename F, typename A, typename B, typename C>
auto apply(A tid, const B& t, C& c, F& f) -> decltype(f(tid, t, c)) 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<void*>& seen, const void* tv)
inline void unsee(DenseHashSet<void*>& seen, const void* tv) inline void unsee(DenseHashSet<void*>& 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 } // namespace visit_detail
template<typename S> template<typename S>
struct GenericTypeVarVisitor struct GenericTypeVisitor
{ {
using Set = S; using Set = S;
@ -72,9 +72,9 @@ struct GenericTypeVarVisitor
bool skipBoundTypes = false; bool skipBoundTypes = false;
int recursionCounter = 0; 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)) : seen(std::move(seen))
, skipBoundTypes(skipBoundTypes) , skipBoundTypes(skipBoundTypes)
{ {
@ -87,75 +87,75 @@ struct GenericTypeVarVisitor
{ {
return true; return true;
} }
virtual bool visit(TypeId ty, const BoundTypeVar& btv) virtual bool visit(TypeId ty, const BoundType& btv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const FreeTypeVar& ftv) virtual bool visit(TypeId ty, const FreeType& ftv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const GenericTypeVar& gtv) virtual bool visit(TypeId ty, const GenericType& gtv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const ErrorTypeVar& etv) virtual bool visit(TypeId ty, const ErrorType& etv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const PrimitiveTypeVar& ptv) virtual bool visit(TypeId ty, const PrimitiveType& ptv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const FunctionTypeVar& ftv) virtual bool visit(TypeId ty, const FunctionType& ftv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const TableTypeVar& ttv) virtual bool visit(TypeId ty, const TableType& ttv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const MetatableTypeVar& mtv) virtual bool visit(TypeId ty, const MetatableType& mtv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const ClassTypeVar& ctv) virtual bool visit(TypeId ty, const ClassType& ctv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const AnyTypeVar& atv) virtual bool visit(TypeId ty, const AnyType& atv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const UnknownTypeVar& utv) virtual bool visit(TypeId ty, const UnknownType& utv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const NeverTypeVar& ntv) virtual bool visit(TypeId ty, const NeverType& ntv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const UnionTypeVar& utv) virtual bool visit(TypeId ty, const UnionType& utv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const IntersectionTypeVar& itv) virtual bool visit(TypeId ty, const IntersectionType& itv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const BlockedTypeVar& btv) virtual bool visit(TypeId ty, const BlockedType& btv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const PendingExpansionTypeVar& petv) virtual bool visit(TypeId ty, const PendingExpansionType& petv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const SingletonTypeVar& stv) virtual bool visit(TypeId ty, const SingletonType& stv)
{ {
return visit(ty); return visit(ty);
} }
virtual bool visit(TypeId ty, const NegationTypeVar& ntv) virtual bool visit(TypeId ty, const NegationType& ntv)
{ {
return visit(ty); return visit(ty);
} }
@ -203,22 +203,22 @@ struct GenericTypeVarVisitor
return; return;
} }
if (auto btv = get<BoundTypeVar>(ty)) if (auto btv = get<BoundType>(ty))
{ {
if (skipBoundTypes) if (skipBoundTypes)
traverse(btv->boundTo); traverse(btv->boundTo);
else if (visit(ty, *btv)) else if (visit(ty, *btv))
traverse(btv->boundTo); traverse(btv->boundTo);
} }
else if (auto ftv = get<FreeTypeVar>(ty)) else if (auto ftv = get<FreeType>(ty))
visit(ty, *ftv); visit(ty, *ftv);
else if (auto gtv = get<GenericTypeVar>(ty)) else if (auto gtv = get<GenericType>(ty))
visit(ty, *gtv); visit(ty, *gtv);
else if (auto etv = get<ErrorTypeVar>(ty)) else if (auto etv = get<ErrorType>(ty))
visit(ty, *etv); visit(ty, *etv);
else if (auto ptv = get<PrimitiveTypeVar>(ty)) else if (auto ptv = get<PrimitiveType>(ty))
visit(ty, *ptv); visit(ty, *ptv);
else if (auto ftv = get<FunctionTypeVar>(ty)) else if (auto ftv = get<FunctionType>(ty))
{ {
if (visit(ty, *ftv)) if (visit(ty, *ftv))
{ {
@ -226,7 +226,7 @@ struct GenericTypeVarVisitor
traverse(ftv->retTypes); traverse(ftv->retTypes);
} }
} }
else if (auto ttv = get<TableTypeVar>(ty)) else if (auto ttv = get<TableType>(ty))
{ {
// Some visitors want to see bound tables, that's why we traverse the original type // Some visitors want to see bound tables, that's why we traverse the original type
if (skipBoundTypes && ttv->boundTo) if (skipBoundTypes && ttv->boundTo)
@ -252,7 +252,7 @@ struct GenericTypeVarVisitor
} }
} }
} }
else if (auto mtv = get<MetatableTypeVar>(ty)) else if (auto mtv = get<MetatableType>(ty))
{ {
if (visit(ty, *mtv)) if (visit(ty, *mtv))
{ {
@ -260,7 +260,7 @@ struct GenericTypeVarVisitor
traverse(mtv->metatable); traverse(mtv->metatable);
} }
} }
else if (auto ctv = get<ClassTypeVar>(ty)) else if (auto ctv = get<ClassType>(ty))
{ {
if (visit(ty, *ctv)) if (visit(ty, *ctv))
{ {
@ -274,9 +274,9 @@ struct GenericTypeVarVisitor
traverse(*ctv->metatable); traverse(*ctv->metatable);
} }
} }
else if (auto atv = get<AnyTypeVar>(ty)) else if (auto atv = get<AnyType>(ty))
visit(ty, *atv); visit(ty, *atv);
else if (auto utv = get<UnionTypeVar>(ty)) else if (auto utv = get<UnionType>(ty))
{ {
if (visit(ty, *utv)) if (visit(ty, *utv))
{ {
@ -284,7 +284,7 @@ struct GenericTypeVarVisitor
traverse(optTy); traverse(optTy);
} }
} }
else if (auto itv = get<IntersectionTypeVar>(ty)) else if (auto itv = get<IntersectionType>(ty))
{ {
if (visit(ty, *itv)) if (visit(ty, *itv))
{ {
@ -292,21 +292,21 @@ struct GenericTypeVarVisitor
traverse(partTy); traverse(partTy);
} }
} }
else if (get<LazyTypeVar>(ty)) else if (get<LazyType>(ty))
{ {
// Visiting into LazyTypeVar may necessarily cause infinite expansion, so we don't do that on purpose. // 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 ClassTypeVar // 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. // that doesn't need to be expanded.
} }
else if (auto stv = get<SingletonTypeVar>(ty)) else if (auto stv = get<SingletonType>(ty))
visit(ty, *stv); visit(ty, *stv);
else if (auto btv = get<BlockedTypeVar>(ty)) else if (auto btv = get<BlockedType>(ty))
visit(ty, *btv); visit(ty, *btv);
else if (auto utv = get<UnknownTypeVar>(ty)) else if (auto utv = get<UnknownType>(ty))
visit(ty, *utv); visit(ty, *utv);
else if (auto ntv = get<NeverTypeVar>(ty)) else if (auto ntv = get<NeverType>(ty))
visit(ty, *ntv); visit(ty, *ntv);
else if (auto petv = get<PendingExpansionTypeVar>(ty)) else if (auto petv = get<PendingExpansionType>(ty))
{ {
if (visit(ty, *petv)) if (visit(ty, *petv))
{ {
@ -317,12 +317,12 @@ struct GenericTypeVarVisitor
traverse(a); traverse(a);
} }
} }
else if (auto ntv = get<NegationTypeVar>(ty)) else if (auto ntv = get<NegationType>(ty))
visit(ty, *ntv); visit(ty, *ntv);
else if (!FFlag::LuauCompleteVisitor) else if (!FFlag::LuauCompleteVisitor)
return visit_detail::unsee(seen, ty); return visit_detail::unsee(seen, ty);
else else
LUAU_ASSERT(!"GenericTypeVarVisitor::traverse(TypeId) is not exhaustive!"); LUAU_ASSERT(!"GenericTypeVisitor::traverse(TypeId) is not exhaustive!");
visit_detail::unsee(seen, ty); visit_detail::unsee(seen, ty);
} }
@ -372,7 +372,7 @@ struct GenericTypeVarVisitor
visit(tp, *btp); visit(tp, *btp);
else else
LUAU_ASSERT(!"GenericTypeVarVisitor::traverse(TypePackId) is not exhaustive!"); LUAU_ASSERT(!"GenericTypeVisitor::traverse(TypePackId) is not exhaustive!");
visit_detail::unsee(seen, tp); 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. /** 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 * 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<std::unordered_set<void*>> struct TypeVisitor : GenericTypeVisitor<std::unordered_set<void*>>
{ {
explicit TypeVarVisitor(bool skipBoundTypes = false) explicit TypeVisitor(bool skipBoundTypes = false)
: GenericTypeVarVisitor{{}, skipBoundTypes} : GenericTypeVisitor{{}, skipBoundTypes}
{ {
} }
}; };
/// Visit each type under a given type. Each type will only be checked once even if there are multiple paths to it. /// 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<DenseHashSet<void*>> struct TypeOnceVisitor : GenericTypeVisitor<DenseHashSet<void*>>
{ {
explicit TypeVarOnceVisitor(bool skipBoundTypes = false) explicit TypeOnceVisitor(bool skipBoundTypes = false)
: GenericTypeVarVisitor{DenseHashSet<void*>{nullptr}, skipBoundTypes} : GenericTypeVisitor{DenseHashSet<void*>{nullptr}, skipBoundTypes}
{ {
} }
}; };

View file

@ -11,20 +11,20 @@ LUAU_FASTFLAG(LuauClassTypeVarsInSubstitution)
namespace Luau namespace Luau
{ {
Anyification::Anyification(TypeArena* arena, NotNull<Scope> scope, NotNull<SingletonTypes> singletonTypes, InternalErrorReporter* iceHandler, Anyification::Anyification(TypeArena* arena, NotNull<Scope> scope, NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter* iceHandler,
TypeId anyType, TypePackId anyTypePack) TypeId anyType, TypePackId anyTypePack)
: Substitution(TxnLog::empty(), arena) : Substitution(TxnLog::empty(), arena)
, scope(scope) , scope(scope)
, singletonTypes(singletonTypes) , builtinTypes(builtinTypes)
, iceHandler(iceHandler) , iceHandler(iceHandler)
, anyType(anyType) , anyType(anyType)
, anyTypePack(anyTypePack) , anyTypePack(anyTypePack)
{ {
} }
Anyification::Anyification(TypeArena* arena, const ScopePtr& scope, NotNull<SingletonTypes> singletonTypes, InternalErrorReporter* iceHandler, Anyification::Anyification(TypeArena* arena, const ScopePtr& scope, NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter* iceHandler,
TypeId anyType, TypePackId anyTypePack) 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) if (ty->persistent)
return false; return false;
if (const TableTypeVar* ttv = log->getMutable<TableTypeVar>(ty)) if (const TableType* ttv = log->getMutable<TableType>(ty))
return (ttv->state == TableState::Free || ttv->state == TableState::Unsealed); return (ttv->state == TableState::Free || ttv->state == TableState::Unsealed);
else if (log->getMutable<FreeTypeVar>(ty)) else if (log->getMutable<FreeType>(ty))
return true; return true;
else else
return false; return false;
@ -55,9 +55,9 @@ bool Anyification::isDirty(TypePackId tp)
TypeId Anyification::clean(TypeId ty) TypeId Anyification::clean(TypeId ty)
{ {
LUAU_ASSERT(isDirty(ty)); LUAU_ASSERT(isDirty(ty));
if (const TableTypeVar* ttv = log->getMutable<TableTypeVar>(ty)) if (const TableType* ttv = log->getMutable<TableType>(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.definitionModuleName = ttv->definitionModuleName;
clone.name = ttv->name; clone.name = ttv->name;
clone.syntheticName = ttv->syntheticName; clone.syntheticName = ttv->syntheticName;
@ -77,7 +77,7 @@ TypePackId Anyification::clean(TypePackId tp)
bool Anyification::ignoreChildren(TypeId ty) bool Anyification::ignoreChildren(TypeId ty)
{ {
if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassTypeVar>(ty)) if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassType>(ty))
return true; return true;
return ty->persistent; return ty->persistent;

View file

@ -11,7 +11,7 @@ bool ApplyTypeFunction::isDirty(TypeId ty)
{ {
if (typeArguments.count(ty)) if (typeArguments.count(ty))
return true; return true;
else if (const FreeTypeVar* ftv = get<FreeTypeVar>(ty)) else if (const FreeType* ftv = get<FreeType>(ty))
{ {
if (ftv->forwardedTypeAlias) if (ftv->forwardedTypeAlias)
encounteredForwardedType = true; encounteredForwardedType = true;
@ -31,9 +31,9 @@ bool ApplyTypeFunction::isDirty(TypePackId tp)
bool ApplyTypeFunction::ignoreChildren(TypeId ty) bool ApplyTypeFunction::ignoreChildren(TypeId ty)
{ {
if (get<GenericTypeVar>(ty)) if (get<GenericType>(ty))
return true; return true;
else if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassTypeVar>(ty)) else if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassType>(ty))
return true; return true;
else else
return false; return false;

View file

@ -4,7 +4,7 @@
#include "Luau/Module.h" #include "Luau/Module.h"
#include "Luau/Scope.h" #include "Luau/Scope.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/ToString.h" #include "Luau/ToString.h"
#include "Luau/Common.h" #include "Luau/Common.h"
@ -447,7 +447,7 @@ static std::optional<DocumentationSymbol> checkOverloadedDocumentationSymbol(
return std::nullopt; return std::nullopt;
// This might be an overloaded function. // This might be an overloaded function.
if (get<IntersectionTypeVar>(follow(ty))) if (get<IntersectionType>(follow(ty)))
{ {
TypeId matchingOverload = nullptr; TypeId matchingOverload = nullptr;
if (parentExpr && parentExpr->is<AstExprCall>()) if (parentExpr && parentExpr->is<AstExprCall>())
@ -487,12 +487,12 @@ std::optional<DocumentationSymbol> getDocumentationSymbolAtPosition(const Source
if (auto it = module.astTypes.find(indexName->expr)) if (auto it = module.astTypes.find(indexName->expr))
{ {
TypeId parentTy = follow(*it); TypeId parentTy = follow(*it);
if (const TableTypeVar* ttv = get<TableTypeVar>(parentTy)) if (const TableType* ttv = get<TableType>(parentTy))
{ {
if (auto propIt = ttv->props.find(indexName->index.value); propIt != ttv->props.end()) if (auto propIt = ttv->props.find(indexName->index.value); propIt != ttv->props.end())
return checkOverloadedDocumentationSymbol(module, propIt->second.type, parentExpr, propIt->second.documentationSymbol); return checkOverloadedDocumentationSymbol(module, propIt->second.type, parentExpr, propIt->second.documentationSymbol);
} }
else if (const ClassTypeVar* ctv = get<ClassTypeVar>(parentTy)) else if (const ClassType* ctv = get<ClassType>(parentTy))
{ {
if (auto propIt = ctv->props.find(indexName->index.value); propIt != ctv->props.end()) if (auto propIt = ctv->props.find(indexName->index.value); propIt != ctv->props.end())
return checkOverloadedDocumentationSymbol(module, propIt->second.type, parentExpr, propIt->second.documentationSymbol); return checkOverloadedDocumentationSymbol(module, propIt->second.type, parentExpr, propIt->second.documentationSymbol);

View file

@ -43,7 +43,7 @@ static bool alreadyHasParens(const std::vector<AstNode*>& nodes)
return false; return false;
} }
static ParenthesesRecommendation getParenRecommendationForFunc(const FunctionTypeVar* func, const std::vector<AstNode*>& nodes) static ParenthesesRecommendation getParenRecommendationForFunc(const FunctionType* func, const std::vector<AstNode*>& nodes)
{ {
if (alreadyHasParens(nodes)) if (alreadyHasParens(nodes))
{ {
@ -61,12 +61,12 @@ static ParenthesesRecommendation getParenRecommendationForFunc(const FunctionTyp
return noArgFunction ? ParenthesesRecommendation::CursorAfter : ParenthesesRecommendation::CursorInside; return noArgFunction ? ParenthesesRecommendation::CursorAfter : ParenthesesRecommendation::CursorInside;
} }
static ParenthesesRecommendation getParenRecommendationForIntersect(const IntersectionTypeVar* intersect, const std::vector<AstNode*>& nodes) static ParenthesesRecommendation getParenRecommendationForIntersect(const IntersectionType* intersect, const std::vector<AstNode*>& nodes)
{ {
ParenthesesRecommendation rec = ParenthesesRecommendation::None; ParenthesesRecommendation rec = ParenthesesRecommendation::None;
for (Luau::TypeId partId : intersect->parts) for (Luau::TypeId partId : intersect->parts)
{ {
if (auto partFunc = Luau::get<FunctionTypeVar>(partId)) if (auto partFunc = Luau::get<FunctionType>(partId))
{ {
rec = std::max(rec, getParenRecommendationForFunc(partFunc, nodes)); rec = std::max(rec, getParenRecommendationForFunc(partFunc, nodes));
} }
@ -85,11 +85,11 @@ static ParenthesesRecommendation getParenRecommendation(TypeId id, const std::ve
return ParenthesesRecommendation::None; return ParenthesesRecommendation::None;
id = Luau::follow(id); id = Luau::follow(id);
if (auto func = get<FunctionTypeVar>(id)) if (auto func = get<FunctionType>(id))
{ {
return getParenRecommendationForFunc(func, nodes); return getParenRecommendationForFunc(func, nodes);
} }
else if (auto intersect = get<IntersectionTypeVar>(id)) else if (auto intersect = get<IntersectionType>(id))
{ {
return getParenRecommendationForIntersect(intersect, nodes); return getParenRecommendationForIntersect(intersect, nodes);
} }
@ -113,7 +113,7 @@ static std::optional<TypeId> findExpectedTypeAt(const Module& module, AstNode* n
if (!it) if (!it)
return std::nullopt; return std::nullopt;
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(*it)); const FunctionType* ftv = get<FunctionType>(follow(*it));
if (!ftv) if (!ftv)
return std::nullopt; return std::nullopt;
@ -135,18 +135,18 @@ static std::optional<TypeId> findExpectedTypeAt(const Module& module, AstNode* n
return *it; return *it;
} }
static bool checkTypeMatch(TypeId subTy, TypeId superTy, NotNull<Scope> scope, TypeArena* typeArena, NotNull<SingletonTypes> singletonTypes) static bool checkTypeMatch(TypeId subTy, TypeId superTy, NotNull<Scope> scope, TypeArena* typeArena, NotNull<BuiltinTypes> builtinTypes)
{ {
InternalErrorReporter iceReporter; InternalErrorReporter iceReporter;
UnifierSharedState unifierState(&iceReporter); UnifierSharedState unifierState(&iceReporter);
Normalizer normalizer{typeArena, singletonTypes, NotNull{&unifierState}}; Normalizer normalizer{typeArena, builtinTypes, NotNull{&unifierState}};
Unifier unifier(NotNull<Normalizer>{&normalizer}, Mode::Strict, scope, Location(), Variance::Covariant); Unifier unifier(NotNull<Normalizer>{&normalizer}, Mode::Strict, scope, Location(), Variance::Covariant);
return unifier.canUnify(subTy, superTy).empty(); return unifier.canUnify(subTy, superTy).empty();
} }
static TypeCorrectKind checkTypeCorrectKind( static TypeCorrectKind checkTypeCorrectKind(
const Module& module, TypeArena* typeArena, NotNull<SingletonTypes> singletonTypes, AstNode* node, Position position, TypeId ty) const Module& module, TypeArena* typeArena, NotNull<BuiltinTypes> builtinTypes, AstNode* node, Position position, TypeId ty)
{ {
ty = follow(ty); ty = follow(ty);
@ -159,31 +159,31 @@ static TypeCorrectKind checkTypeCorrectKind(
TypeId expectedType = follow(*typeAtPosition); 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<TypeId> firstRetTy = first(ftv->retTypes)) if (std::optional<TypeId> firstRetTy = first(ftv->retTypes))
return checkTypeMatch(*firstRetTy, expectedType, moduleScope, typeArena, singletonTypes); return checkTypeMatch(*firstRetTy, expectedType, moduleScope, typeArena, builtinTypes);
return false; return false;
}; };
// We also want to suggest functions that return compatible result // We also want to suggest functions that return compatible result
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty); ftv && checkFunctionType(ftv)) if (const FunctionType* ftv = get<FunctionType>(ty); ftv && checkFunctionType(ftv))
{ {
return TypeCorrectKind::CorrectFunctionResult; return TypeCorrectKind::CorrectFunctionResult;
} }
else if (const IntersectionTypeVar* itv = get<IntersectionTypeVar>(ty)) else if (const IntersectionType* itv = get<IntersectionType>(ty))
{ {
for (TypeId id : itv->parts) for (TypeId id : itv->parts)
{ {
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(id); ftv && checkFunctionType(ftv)) if (const FunctionType* ftv = get<FunctionType>(id); ftv && checkFunctionType(ftv))
{ {
return TypeCorrectKind::CorrectFunctionResult; return TypeCorrectKind::CorrectFunctionResult;
} }
} }
} }
return checkTypeMatch(ty, expectedType, NotNull{module.getModuleScope().get()}, typeArena, singletonTypes) ? TypeCorrectKind::Correct return checkTypeMatch(ty, expectedType, NotNull{module.getModuleScope().get()}, typeArena, builtinTypes) ? TypeCorrectKind::Correct
: TypeCorrectKind::None; : TypeCorrectKind::None;
} }
enum class PropIndexType enum class PropIndexType
@ -193,9 +193,9 @@ enum class PropIndexType
Key, Key,
}; };
static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNull<SingletonTypes> singletonTypes, TypeId rootTy, TypeId ty, static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNull<BuiltinTypes> builtinTypes, TypeId rootTy, TypeId ty,
PropIndexType indexType, const std::vector<AstNode*>& nodes, AutocompleteEntryMap& result, std::unordered_set<TypeId>& seen, PropIndexType indexType, const std::vector<AstNode*>& nodes, AutocompleteEntryMap& result, std::unordered_set<TypeId>& seen,
std::optional<const ClassTypeVar*> containingClass = std::nullopt) std::optional<const ClassType*> containingClass = std::nullopt)
{ {
rootTy = follow(rootTy); rootTy = follow(rootTy);
ty = follow(ty); ty = follow(ty);
@ -204,41 +204,41 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
return; return;
seen.insert(ty); 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) if (indexType == PropIndexType::Key)
return false; return false;
bool calledWithSelf = indexType == PropIndexType::Colon; 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 // Strong match with definition is a success
if (calledWithSelf == ftv->hasSelf) if (calledWithSelf == ftv->hasSelf)
return true; return true;
// Calls on classes require strict match between how function is declared and how it's called // Calls on classes require strict match between how function is declared and how it's called
if (get<ClassTypeVar>(rootTy)) if (get<ClassType>(rootTy))
return false; 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 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 // When called with '.', but declared with 'self', it is considered invalid if first argument is compatible
if (std::optional<TypeId> firstArgTy = first(ftv->argTypes)) if (std::optional<TypeId> 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;
} }
return !calledWithSelf; return !calledWithSelf;
}; };
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(type)) if (const FunctionType* ftv = get<FunctionType>(type))
return !isCompatibleCall(ftv); return !isCompatibleCall(ftv);
// For intersections, any part that is successful makes the whole call successful // For intersections, any part that is successful makes the whole call successful
if (const IntersectionTypeVar* itv = get<IntersectionTypeVar>(type)) if (const IntersectionType* itv = get<IntersectionType>(type))
{ {
for (auto subType : itv->parts) for (auto subType : itv->parts)
{ {
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(Luau::follow(subType))) if (const FunctionType* ftv = get<FunctionType>(Luau::follow(subType)))
{ {
if (isCompatibleCall(ftv)) if (isCompatibleCall(ftv))
return false; return false;
@ -249,7 +249,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
return calledWithSelf; return calledWithSelf;
}; };
auto fillProps = [&](const ClassTypeVar::Props& props) { auto fillProps = [&](const ClassType::Props& props) {
for (const auto& [name, prop] : props) for (const auto& [name, prop] : props)
{ {
// We are walking up the class hierarchy, so if we encounter a property that we have // 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); Luau::TypeId type = Luau::follow(prop.type);
TypeCorrectKind typeCorrect = indexType == PropIndexType::Key TypeCorrectKind typeCorrect = indexType == PropIndexType::Key
? TypeCorrectKind::Correct ? TypeCorrectKind::Correct
: checkTypeCorrectKind(module, typeArena, singletonTypes, nodes.back(), {{}, {}}, type); : checkTypeCorrectKind(module, typeArena, builtinTypes, nodes.back(), {{}, {}}, type);
ParenthesesRecommendation parens = ParenthesesRecommendation parens =
indexType == PropIndexType::Key ? ParenthesesRecommendation::None : getParenRecommendation(type, nodes, typeCorrect); 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"); auto indexIt = mtable->props.find("__index");
if (indexIt != mtable->props.end()) if (indexIt != mtable->props.end())
{ {
TypeId followed = follow(indexIt->second.type); TypeId followed = follow(indexIt->second.type);
if (get<TableTypeVar>(followed) || get<MetatableTypeVar>(followed)) if (get<TableType>(followed) || get<MetatableType>(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<FunctionTypeVar>(followed)) else if (auto indexFunction = get<FunctionType>(followed))
{ {
std::optional<TypeId> indexFunctionResult = first(indexFunction->retTypes); std::optional<TypeId> indexFunctionResult = first(indexFunction->retTypes);
if (indexFunctionResult) 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<ClassTypeVar>(ty)) if (auto cls = get<ClassType>(ty))
{ {
containingClass = containingClass.value_or(cls); containingClass = containingClass.value_or(cls);
fillProps(cls->props); fillProps(cls->props);
if (cls->parent) 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<TableTypeVar>(ty)) else if (auto tbl = get<TableType>(ty))
fillProps(tbl->props); fillProps(tbl->props);
else if (auto mt = get<MetatableTypeVar>(ty)) else if (auto mt = get<MetatableType>(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<TableTypeVar>(mt->metatable)) if (auto mtable = get<TableType>(mt->metatable))
fillMetatableProps(mtable); fillMetatableProps(mtable);
} }
else if (auto i = get<IntersectionTypeVar>(ty)) else if (auto i = get<IntersectionType>(ty))
{ {
// Complete all properties in every variant // Complete all properties in every variant
for (TypeId ty : i->parts) for (TypeId ty : i->parts)
@ -321,13 +321,13 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
AutocompleteEntryMap inner; AutocompleteEntryMap inner;
std::unordered_set<TypeId> innerSeen = seen; std::unordered_set<TypeId> 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) for (auto& pair : inner)
result.insert(pair); result.insert(pair);
} }
} }
else if (auto u = get<UnionTypeVar>(ty)) else if (auto u = get<UnionType>(ty))
{ {
// Complete all properties common to all variants // Complete all properties common to all variants
auto iter = begin(u); auto iter = begin(u);
@ -344,7 +344,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
if (iter == endIter) if (iter == endIter)
return; return;
autocompleteProps(module, typeArena, singletonTypes, rootTy, *iter, indexType, nodes, result, seen); autocompleteProps(module, typeArena, builtinTypes, rootTy, *iter, indexType, nodes, result, seen);
++iter; ++iter;
@ -359,7 +359,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
continue; continue;
} }
autocompleteProps(module, typeArena, singletonTypes, rootTy, *iter, indexType, nodes, inner, innerSeen); autocompleteProps(module, typeArena, builtinTypes, rootTy, *iter, indexType, nodes, inner, innerSeen);
std::unordered_set<std::string> toRemove; std::unordered_set<std::string> toRemove;
@ -376,17 +376,17 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
++iter; ++iter;
} }
} }
else if (auto pt = get<PrimitiveTypeVar>(ty)) else if (auto pt = get<PrimitiveType>(ty))
{ {
if (pt->metatable) if (pt->metatable)
{ {
if (auto mtable = get<TableTypeVar>(*pt->metatable)) if (auto mtable = get<TableType>(*pt->metatable))
fillMetatableProps(mtable); fillMetatableProps(mtable);
} }
} }
else if (get<StringSingleton>(get<SingletonTypeVar>(ty))) else if (get<StringSingleton>(get<SingletonType>(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> singletonTypes, TypeId ty, PropIndexType indexType, static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNull<BuiltinTypes> builtinTypes, TypeId ty, PropIndexType indexType,
const std::vector<AstNode*>& nodes, AutocompleteEntryMap& result) const std::vector<AstNode*>& nodes, AutocompleteEntryMap& result)
{ {
std::unordered_set<TypeId> seen; std::unordered_set<TypeId> 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> singletonTypes, TypeId ty, AutocompleteEntryMap autocompleteProps(const Module& module, TypeArena* typeArena, NotNull<BuiltinTypes> builtinTypes, TypeId ty,
PropIndexType indexType, const std::vector<AstNode*>& nodes) PropIndexType indexType, const std::vector<AstNode*>& nodes)
{ {
AutocompleteEntryMap result; AutocompleteEntryMap result;
autocompleteProps(module, typeArena, singletonTypes, ty, indexType, nodes, result); autocompleteProps(module, typeArena, builtinTypes, ty, indexType, nodes, result);
return result; return result;
} }
@ -455,15 +455,15 @@ static void autocompleteStringSingleton(TypeId ty, bool addQuotes, AutocompleteE
ty = follow(ty); ty = follow(ty);
if (auto ss = get<StringSingleton>(get<SingletonTypeVar>(ty))) if (auto ss = get<StringSingleton>(get<SingletonType>(ty)))
{ {
result[formatKey(ss->value)] = AutocompleteEntry{AutocompleteEntryKind::String, ty, false, false, TypeCorrectKind::Correct}; result[formatKey(ss->value)] = AutocompleteEntry{AutocompleteEntryKind::String, ty, false, false, TypeCorrectKind::Correct};
} }
else if (auto uty = get<UnionTypeVar>(ty)) else if (auto uty = get<UnionType>(ty))
{ {
for (auto el : uty) for (auto el : uty)
{ {
if (auto ss = get<StringSingleton>(get<SingletonTypeVar>(el))) if (auto ss = get<StringSingleton>(get<SingletonType>(el)))
result[formatKey(ss->value)] = AutocompleteEntry{AutocompleteEntryKind::String, ty, false, false, TypeCorrectKind::Correct}; 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); ty = follow(ty);
// No point in suggesting 'any', invalid to suggest others // No point in suggesting 'any', invalid to suggest others
if (get<AnyTypeVar>(ty) || get<ErrorTypeVar>(ty) || get<GenericTypeVar>(ty) || get<FreeTypeVar>(ty)) if (get<AnyType>(ty) || get<ErrorType>(ty) || get<GenericType>(ty) || get<FreeType>(ty))
return false; return false;
// No syntax for unnamed tables with a metatable // No syntax for unnamed tables with a metatable
if (get<MetatableTypeVar>(ty)) if (get<MetatableType>(ty))
return false; return false;
if (const TableTypeVar* ttv = get<TableTypeVar>(ty)) if (const TableType* ttv = get<TableType>(ty))
{ {
if (ttv->name) if (ttv->name)
return true; return true;
@ -544,7 +544,7 @@ static std::optional<TypeId> findTypeElementAt(AstType* astType, TypeId ty, Posi
if (AstTypeFunction* type = astType->as<AstTypeFunction>()) if (AstTypeFunction* type = astType->as<AstTypeFunction>())
{ {
const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty); const FunctionType* ftv = get<FunctionType>(ty);
if (!ftv) if (!ftv)
return {}; return {};
@ -634,7 +634,7 @@ static std::optional<TypeId> tryGetTypePackTypeAt(TypePackId tp, size_t index)
} }
template<typename T> template<typename T>
std::optional<const T*> returnFirstNonnullOptionOfType(const UnionTypeVar* utv) std::optional<const T*> returnFirstNonnullOptionOfType(const UnionType* utv)
{ {
std::optional<const T*> ret; std::optional<const T*> ret;
for (TypeId subTy : utv) for (TypeId subTy : utv)
@ -667,18 +667,18 @@ static std::optional<bool> functionIsExpectedAt(const Module& module, AstNode* n
TypeId expectedType = follow(*typeAtPosition); TypeId expectedType = follow(*typeAtPosition);
if (get<FunctionTypeVar>(expectedType)) if (get<FunctionType>(expectedType))
return true; return true;
if (const IntersectionTypeVar* itv = get<IntersectionTypeVar>(expectedType)) if (const IntersectionType* itv = get<IntersectionType>(expectedType))
{ {
return std::all_of(begin(itv->parts), end(itv->parts), [](auto&& ty) { return std::all_of(begin(itv->parts), end(itv->parts), [](auto&& ty) {
return get<FunctionTypeVar>(Luau::follow(ty)) != nullptr; return get<FunctionType>(Luau::follow(ty)) != nullptr;
}); });
} }
if (const UnionTypeVar* utv = get<UnionTypeVar>(expectedType)) if (const UnionType* utv = get<UnionType>(expectedType))
return returnFirstNonnullOptionOfType<FunctionTypeVar>(utv).has_value(); return returnFirstNonnullOptionOfType<FunctionType>(utv).has_value();
return false; return false;
} }
@ -766,7 +766,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
{ {
if (auto it = module.astTypes.find(exprCall->func)) if (auto it = module.astTypes.find(exprCall->func))
{ {
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(*it))) if (const FunctionType* ftv = get<FunctionType>(follow(*it)))
{ {
if (auto ty = tryGetTypePackTypeAt(ftv->retTypes, tailPos)) if (auto ty = tryGetTypePackTypeAt(ftv->retTypes, tailPos))
inferredType = *ty; inferredType = *ty;
@ -792,7 +792,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
else if (AstExprFunction* node = parent->as<AstExprFunction>()) else if (AstExprFunction* node = parent->as<AstExprFunction>())
{ {
// For lookup inside expected function type if that's available // 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); auto it = module.astExpectedTypes.find(expr);
if (!it) if (!it)
@ -800,13 +800,13 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
TypeId ty = follow(*it); TypeId ty = follow(*it);
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty)) if (const FunctionType* ftv = get<FunctionType>(ty))
return ftv; return ftv;
// Handle optional function type // Handle optional function type
if (const UnionTypeVar* utv = get<UnionTypeVar>(ty)) if (const UnionType* utv = get<UnionType>(ty))
{ {
return returnFirstNonnullOptionOfType<FunctionTypeVar>(utv).value_or(nullptr); return returnFirstNonnullOptionOfType<FunctionType>(utv).value_or(nullptr);
} }
return nullptr; return nullptr;
@ -819,7 +819,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
if (arg->annotation && arg->annotation->location.containsClosed(position)) 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)) if (auto ty = tryGetTypePackTypeAt(ftv->argTypes, i))
tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position); tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position);
@ -840,7 +840,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
{ {
if (variadic->location.containsClosed(position)) 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)) if (auto ty = tryGetTypePackTypeAt(ftv->argTypes, ~0u))
tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position); tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position);
@ -858,7 +858,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
if (ret->location.containsClosed(position)) 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)) if (auto ty = tryGetTypePackTypeAt(ftv->retTypes, i))
tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position); tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position);
@ -875,7 +875,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
{ {
if (variadic->location.containsClosed(position)) 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)) if (auto ty = tryGetTypePackTypeAt(ftv->retTypes, ~0u))
tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position); tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position);
@ -1127,7 +1127,7 @@ static bool autocompleteIfElseExpression(
} }
} }
static AutocompleteContext autocompleteExpression(const SourceModule& sourceModule, const Module& module, NotNull<SingletonTypes> singletonTypes, static AutocompleteContext autocompleteExpression(const SourceModule& sourceModule, const Module& module, NotNull<BuiltinTypes> builtinTypes,
TypeArena* typeArena, const std::vector<AstNode*>& ancestry, Position position, AutocompleteEntryMap& result) TypeArena* typeArena, const std::vector<AstNode*>& ancestry, Position position, AutocompleteEntryMap& result)
{ {
LUAU_ASSERT(!ancestry.empty()); LUAU_ASSERT(!ancestry.empty());
@ -1137,7 +1137,7 @@ static AutocompleteContext autocompleteExpression(const SourceModule& sourceModu
if (node->is<AstExprIndexName>()) if (node->is<AstExprIndexName>())
{ {
if (auto it = module.astTypes.find(node->asExpr())) 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)) else if (autocompleteIfElseExpression(node, ancestry, position, result))
return AutocompleteContext::Keyword; return AutocompleteContext::Keyword;
@ -1161,7 +1161,7 @@ static AutocompleteContext autocompleteExpression(const SourceModule& sourceModu
std::string n = toString(name); std::string n = toString(name);
if (!result.count(n)) 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, result[n] = {AutocompleteEntryKind::Binding, binding.typeId, binding.deprecated, false, typeCorrect, std::nullopt, std::nullopt,
binding.documentationSymbol, {}, getParenRecommendation(binding.typeId, ancestry, typeCorrect)}; binding.documentationSymbol, {}, getParenRecommendation(binding.typeId, ancestry, typeCorrect)};
@ -1171,16 +1171,16 @@ static AutocompleteContext autocompleteExpression(const SourceModule& sourceModu
scope = scope->parent; scope = scope->parent;
} }
TypeCorrectKind correctForNil = checkTypeCorrectKind(module, typeArena, singletonTypes, node, position, singletonTypes->nilType); TypeCorrectKind correctForNil = checkTypeCorrectKind(module, typeArena, builtinTypes, node, position, builtinTypes->nilType);
TypeCorrectKind correctForTrue = checkTypeCorrectKind(module, typeArena, singletonTypes, node, position, singletonTypes->trueType); TypeCorrectKind correctForTrue = checkTypeCorrectKind(module, typeArena, builtinTypes, node, position, builtinTypes->trueType);
TypeCorrectKind correctForFalse = checkTypeCorrectKind(module, typeArena, singletonTypes, node, position, singletonTypes->falseType); TypeCorrectKind correctForFalse = checkTypeCorrectKind(module, typeArena, builtinTypes, node, position, builtinTypes->falseType);
TypeCorrectKind correctForFunction = TypeCorrectKind correctForFunction =
functionIsExpectedAt(module, node, position).value_or(false) ? TypeCorrectKind::Correct : TypeCorrectKind::None; functionIsExpectedAt(module, node, position).value_or(false) ? TypeCorrectKind::Correct : TypeCorrectKind::None;
result["if"] = {AutocompleteEntryKind::Keyword, std::nullopt, false, false}; result["if"] = {AutocompleteEntryKind::Keyword, std::nullopt, false, false};
result["true"] = {AutocompleteEntryKind::Keyword, singletonTypes->booleanType, false, false, correctForTrue}; result["true"] = {AutocompleteEntryKind::Keyword, builtinTypes->booleanType, false, false, correctForTrue};
result["false"] = {AutocompleteEntryKind::Keyword, singletonTypes->booleanType, false, false, correctForFalse}; result["false"] = {AutocompleteEntryKind::Keyword, builtinTypes->booleanType, false, false, correctForFalse};
result["nil"] = {AutocompleteEntryKind::Keyword, singletonTypes->nilType, false, false, correctForNil}; result["nil"] = {AutocompleteEntryKind::Keyword, builtinTypes->nilType, false, false, correctForNil};
result["not"] = {AutocompleteEntryKind::Keyword}; result["not"] = {AutocompleteEntryKind::Keyword};
result["function"] = {AutocompleteEntryKind::Keyword, std::nullopt, false, false, correctForFunction}; result["function"] = {AutocompleteEntryKind::Keyword, std::nullopt, false, false, correctForFunction};
@ -1191,15 +1191,15 @@ static AutocompleteContext autocompleteExpression(const SourceModule& sourceModu
return AutocompleteContext::Expression; return AutocompleteContext::Expression;
} }
static AutocompleteResult autocompleteExpression(const SourceModule& sourceModule, const Module& module, NotNull<SingletonTypes> singletonTypes, static AutocompleteResult autocompleteExpression(const SourceModule& sourceModule, const Module& module, NotNull<BuiltinTypes> builtinTypes,
TypeArena* typeArena, const std::vector<AstNode*>& ancestry, Position position) TypeArena* typeArena, const std::vector<AstNode*>& ancestry, Position position)
{ {
AutocompleteEntryMap result; 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}; return {result, ancestry, context};
} }
static std::optional<const ClassTypeVar*> getMethodContainingClass(const ModulePtr& module, AstExpr* funcExpr) static std::optional<const ClassType*> getMethodContainingClass(const ModulePtr& module, AstExpr* funcExpr)
{ {
AstExpr* parentExpr = nullptr; AstExpr* parentExpr = nullptr;
if (auto indexName = funcExpr->as<AstExprIndexName>()) if (auto indexName = funcExpr->as<AstExprIndexName>())
@ -1223,14 +1223,14 @@ static std::optional<const ClassTypeVar*> getMethodContainingClass(const ModuleP
Luau::TypeId parentType = Luau::follow(*parentIt); Luau::TypeId parentType = Luau::follow(*parentIt);
if (auto parentClass = Luau::get<ClassTypeVar>(parentType)) if (auto parentClass = Luau::get<ClassType>(parentType))
{ {
return parentClass; return parentClass;
} }
if (auto parentUnion = Luau::get<UnionTypeVar>(parentType)) if (auto parentUnion = Luau::get<UnionType>(parentType))
{ {
return returnFirstNonnullOptionOfType<ClassTypeVar>(parentUnion); return returnFirstNonnullOptionOfType<ClassType>(parentUnion);
} }
return std::nullopt; return std::nullopt;
@ -1281,7 +1281,7 @@ static std::optional<AutocompleteEntryMap> autocompleteStringParams(const Source
} }
// HACK: All current instances of 'magic string' params are the first parameter of their functions, // 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)) if (candidate->args.size > 1 && !candidate->args.data[0]->location.contains(position))
{ {
return std::nullopt; return std::nullopt;
@ -1293,7 +1293,7 @@ static std::optional<AutocompleteEntryMap> autocompleteStringParams(const Source
return std::nullopt; return std::nullopt;
} }
auto performCallback = [&](const FunctionTypeVar* funcType) -> std::optional<AutocompleteEntryMap> { auto performCallback = [&](const FunctionType* funcType) -> std::optional<AutocompleteEntryMap> {
for (const std::string& tag : funcType->tags) for (const std::string& tag : funcType->tags)
{ {
if (std::optional<AutocompleteEntryMap> ret = callback(tag, getMethodContainingClass(module, candidate->func))) if (std::optional<AutocompleteEntryMap> ret = callback(tag, getMethodContainingClass(module, candidate->func)))
@ -1305,16 +1305,16 @@ static std::optional<AutocompleteEntryMap> autocompleteStringParams(const Source
}; };
auto followedId = Luau::follow(*it); auto followedId = Luau::follow(*it);
if (auto functionType = Luau::get<FunctionTypeVar>(followedId)) if (auto functionType = Luau::get<FunctionType>(followedId))
{ {
return performCallback(functionType); return performCallback(functionType);
} }
if (auto intersect = Luau::get<IntersectionTypeVar>(followedId)) if (auto intersect = Luau::get<IntersectionType>(followedId))
{ {
for (TypeId part : intersect->parts) for (TypeId part : intersect->parts)
{ {
if (auto candidateFunctionType = Luau::get<FunctionTypeVar>(part)) if (auto candidateFunctionType = Luau::get<FunctionType>(part))
{ {
if (std::optional<AutocompleteEntryMap> ret = performCallback(candidateFunctionType)) if (std::optional<AutocompleteEntryMap> ret = performCallback(candidateFunctionType))
{ {
@ -1327,7 +1327,7 @@ static std::optional<AutocompleteEntryMap> autocompleteStringParams(const Source
return std::nullopt; return std::nullopt;
} }
static AutocompleteResult autocomplete(const SourceModule& sourceModule, const ModulePtr& module, NotNull<SingletonTypes> singletonTypes, static AutocompleteResult autocomplete(const SourceModule& sourceModule, const ModulePtr& module, NotNull<BuiltinTypes> builtinTypes,
Scope* globalScope, Position position, StringCompletionCallback callback) Scope* globalScope, Position position, StringCompletionCallback callback)
{ {
if (isWithinComment(sourceModule, position)) if (isWithinComment(sourceModule, position))
@ -1360,7 +1360,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
TypeId ty = follow(*it); TypeId ty = follow(*it);
PropIndexType indexType = indexName->op == ':' ? PropIndexType::Colon : PropIndexType::Point; 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<AstTypeReference>()) else if (auto typeReference = node->as<AstTypeReference>())
{ {
@ -1378,7 +1378,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
if (statLocal->vars.size == 1 && (!statLocal->equalsSignLocation || position < statLocal->equalsSignLocation->begin)) if (statLocal->vars.size == 1 && (!statLocal->equalsSignLocation || position < statLocal->equalsSignLocation->begin))
return {{{"function", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Unknown}; return {{{"function", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Unknown};
else if (statLocal->equalsSignLocation && position >= statLocal->equalsSignLocation->end) 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 else
return {}; return {};
} }
@ -1392,7 +1392,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
if (statFor->from->location.containsClosed(position) || statFor->to->location.containsClosed(position) || if (statFor->from->location.containsClosed(position) || statFor->to->location.containsClosed(position) ||
(statFor->step && statFor->step->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 {}; return {};
} }
@ -1422,7 +1422,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
AstExpr* lastExpr = statForIn->values.data[statForIn->values.size - 1]; AstExpr* lastExpr = statForIn->values.data[statForIn->values.size - 1];
if (lastExpr->location.containsClosed(position)) 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) if (position > lastExpr->location.end)
return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword}; 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}; return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
if (!statWhile->hasDo || position < statWhile->doLocation.begin) 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) if (statWhile->hasDo && position > statWhile->doLocation.end)
return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement}; 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<AstStatIf>(); statIf && node->is<AstStatBlock>()) else if (AstStatIf* statIf = parent->as<AstStatIf>(); statIf && node->is<AstStatBlock>())
{ {
if (statIf->condition->is<AstExprError>()) if (statIf->condition->is<AstExprError>())
return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position); return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
else if (!statIf->thenLocation || statIf->thenLocation->containsClosed(position)) else if (!statIf->thenLocation || statIf->thenLocation->containsClosed(position))
return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword}; 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))) statIf && (!statIf->thenLocation || statIf->thenLocation->containsClosed(position)))
return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword}; return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
else if (AstStatRepeat* statRepeat = node->as<AstStatRepeat>(); statRepeat && statRepeat->condition->is<AstExprError>()) else if (AstStatRepeat* statRepeat = node->as<AstStatRepeat>(); statRepeat && statRepeat->condition->is<AstExprError>())
return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position); return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
else if (AstStatRepeat* statRepeat = extractStat<AstStatRepeat>(ancestry); statRepeat) else if (AstStatRepeat* statRepeat = extractStat<AstStatRepeat>(ancestry); statRepeat)
return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement}; return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement};
else if (AstExprTable* exprTable = parent->as<AstExprTable>(); else if (AstExprTable* exprTable = parent->as<AstExprTable>();
@ -1484,7 +1484,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
{ {
if (auto it = module->astExpectedTypes.find(exprTable)) 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) 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, // If the key type is a union of singleton strings,
// suggest those too. // suggest those too.
if (auto ttv = get<TableTypeVar>(follow(*it)); ttv && ttv->indexer) if (auto ttv = get<TableType>(follow(*it)); ttv && ttv->indexer)
{ {
autocompleteStringSingleton(ttv->indexer->indexType, false, result); 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 we know for sure that a key is being written, do not offer general expression suggestions
if (!key) if (!key)
autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position, result); autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position, result);
return {result, ancestry, AutocompleteContext::Property}; 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<AstExprIndexExpr>()) if (auto idxExpr = ancestry.at(ancestry.size() - 2)->as<AstExprIndexExpr>())
{ {
if (auto it = module->astTypes.find(idxExpr->expr)) 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<AstExprBinary>()) else if (auto binExpr = ancestry.at(ancestry.size() - 2)->as<AstExprBinary>())
{ {
@ -1572,7 +1572,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
return {}; return {};
if (node->asExpr()) if (node->asExpr())
return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position); return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
else if (node->asStat()) else if (node->asStat())
return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement}; return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement};
@ -1596,10 +1596,10 @@ AutocompleteResult autocomplete(Frontend& frontend, const ModuleName& moduleName
if (!module) if (!module)
return {}; return {};
NotNull<SingletonTypes> singletonTypes = frontend.singletonTypes; NotNull<BuiltinTypes> builtinTypes = frontend.builtinTypes;
Scope* globalScope = frontend.typeCheckerForAutocomplete.globalScope.get(); 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; return autocompleteResult;
} }

View file

@ -10,7 +10,7 @@
#include "Luau/ConstraintGraphBuilder.h" #include "Luau/ConstraintGraphBuilder.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/TypeUtils.h" #include "Luau/TypeUtils.h"
#include <algorithm> #include <algorithm>
@ -51,12 +51,12 @@ static std::vector<ConnectiveId> dcrMagicRefinementAssert(const MagicRefinementC
TypeId makeUnion(TypeArena& arena, std::vector<TypeId>&& types) TypeId makeUnion(TypeArena& arena, std::vector<TypeId>&& types)
{ {
return arena.addType(UnionTypeVar{std::move(types)}); return arena.addType(UnionType{std::move(types)});
} }
TypeId makeIntersection(TypeArena& arena, std::vector<TypeId>&& types) TypeId makeIntersection(TypeArena& arena, std::vector<TypeId>&& types)
{ {
return arena.addType(IntersectionTypeVar{std::move(types)}); return arena.addType(IntersectionType{std::move(types)});
} }
TypeId makeOption(Frontend& frontend, TypeArena& arena, TypeId t) TypeId makeOption(Frontend& frontend, TypeArena& arena, TypeId t)
@ -99,7 +99,7 @@ TypeId makeFunction(TypeArena& arena, std::optional<TypeId> selfType, std::initi
TypePackId paramPack = arena.addTypePack(std::move(params)); TypePackId paramPack = arena.addTypePack(std::move(params));
TypePackId retPack = arena.addTypePack(std::vector<TypeId>(retTypes)); TypePackId retPack = arena.addTypePack(std::vector<TypeId>(retTypes));
FunctionTypeVar ftv{generics, genericPacks, paramPack, retPack, {}, selfType.has_value()}; FunctionType ftv{generics, genericPacks, paramPack, retPack, {}, selfType.has_value()};
if (selfType) if (selfType)
ftv.argNames.push_back(Luau::FunctionArgument{"self", {}}); ftv.argNames.push_back(Luau::FunctionArgument{"self", {}});
@ -121,7 +121,7 @@ TypeId makeFunction(TypeArena& arena, std::optional<TypeId> selfType, std::initi
void attachMagicFunction(TypeId ty, MagicFunction fn) void attachMagicFunction(TypeId ty, MagicFunction fn)
{ {
if (auto ftv = getMutable<FunctionTypeVar>(ty)) if (auto ftv = getMutable<FunctionType>(ty))
ftv->magicFunction = fn; ftv->magicFunction = fn;
else else
LUAU_ASSERT(!"Got a non functional type"); LUAU_ASSERT(!"Got a non functional type");
@ -129,7 +129,7 @@ void attachMagicFunction(TypeId ty, MagicFunction fn)
void attachDcrMagicFunction(TypeId ty, DcrMagicFunction fn) void attachDcrMagicFunction(TypeId ty, DcrMagicFunction fn)
{ {
if (auto ftv = getMutable<FunctionTypeVar>(ty)) if (auto ftv = getMutable<FunctionType>(ty))
ftv->dcrMagicFunction = fn; ftv->dcrMagicFunction = fn;
else else
LUAU_ASSERT(!"Got a non functional type"); LUAU_ASSERT(!"Got a non functional type");
@ -137,7 +137,7 @@ void attachDcrMagicFunction(TypeId ty, DcrMagicFunction fn)
void attachDcrMagicRefinement(TypeId ty, DcrMagicRefinement fn) void attachDcrMagicRefinement(TypeId ty, DcrMagicRefinement fn)
{ {
if (auto ftv = getMutable<FunctionTypeVar>(ty)) if (auto ftv = getMutable<FunctionType>(ty))
ftv->dcrMagicRefinement = fn; ftv->dcrMagicRefinement = fn;
else else
LUAU_ASSERT(!"Got a non functional type"); LUAU_ASSERT(!"Got a non functional type");
@ -239,7 +239,7 @@ Binding* tryGetGlobalBindingRef(TypeChecker& typeChecker, const std::string& nam
return nullptr; 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) for (auto& [name, prop] : props)
{ {
@ -249,39 +249,39 @@ void assignPropDocumentationSymbols(TableTypeVar::Props& props, const std::strin
void registerBuiltinTypes(Frontend& frontend) void registerBuiltinTypes(Frontend& frontend)
{ {
frontend.getGlobalScope()->addBuiltinTypeBinding("any", TypeFun{{}, frontend.singletonTypes->anyType}); frontend.getGlobalScope()->addBuiltinTypeBinding("any", TypeFun{{}, frontend.builtinTypes->anyType});
frontend.getGlobalScope()->addBuiltinTypeBinding("nil", TypeFun{{}, frontend.singletonTypes->nilType}); frontend.getGlobalScope()->addBuiltinTypeBinding("nil", TypeFun{{}, frontend.builtinTypes->nilType});
frontend.getGlobalScope()->addBuiltinTypeBinding("number", TypeFun{{}, frontend.singletonTypes->numberType}); frontend.getGlobalScope()->addBuiltinTypeBinding("number", TypeFun{{}, frontend.builtinTypes->numberType});
frontend.getGlobalScope()->addBuiltinTypeBinding("string", TypeFun{{}, frontend.singletonTypes->stringType}); frontend.getGlobalScope()->addBuiltinTypeBinding("string", TypeFun{{}, frontend.builtinTypes->stringType});
frontend.getGlobalScope()->addBuiltinTypeBinding("boolean", TypeFun{{}, frontend.singletonTypes->booleanType}); frontend.getGlobalScope()->addBuiltinTypeBinding("boolean", TypeFun{{}, frontend.builtinTypes->booleanType});
frontend.getGlobalScope()->addBuiltinTypeBinding("thread", TypeFun{{}, frontend.singletonTypes->threadType}); frontend.getGlobalScope()->addBuiltinTypeBinding("thread", TypeFun{{}, frontend.builtinTypes->threadType});
if (FFlag::LuauUnknownAndNeverType) if (FFlag::LuauUnknownAndNeverType)
{ {
frontend.getGlobalScope()->addBuiltinTypeBinding("unknown", TypeFun{{}, frontend.singletonTypes->unknownType}); frontend.getGlobalScope()->addBuiltinTypeBinding("unknown", TypeFun{{}, frontend.builtinTypes->unknownType});
frontend.getGlobalScope()->addBuiltinTypeBinding("never", TypeFun{{}, frontend.singletonTypes->neverType}); frontend.getGlobalScope()->addBuiltinTypeBinding("never", TypeFun{{}, frontend.builtinTypes->neverType});
} }
} }
void registerBuiltinGlobals(TypeChecker& typeChecker) void registerBuiltinGlobals(TypeChecker& typeChecker)
{ {
LUAU_ASSERT(!typeChecker.globalTypes.typeVars.isFrozen()); LUAU_ASSERT(!typeChecker.globalTypes.types.isFrozen());
LUAU_ASSERT(!typeChecker.globalTypes.typePacks.isFrozen()); LUAU_ASSERT(!typeChecker.globalTypes.typePacks.isFrozen());
TypeId nilType = typeChecker.nilType; TypeId nilType = typeChecker.nilType;
TypeArena& arena = typeChecker.globalTypes; TypeArena& arena = typeChecker.globalTypes;
NotNull<SingletonTypes> singletonTypes = typeChecker.singletonTypes; NotNull<BuiltinTypes> builtinTypes = typeChecker.builtinTypes;
LoadDefinitionFileResult loadResult = Luau::loadDefinitionFile(typeChecker, typeChecker.globalScope, getBuiltinDefinitionSource(), "@luau"); LoadDefinitionFileResult loadResult = Luau::loadDefinitionFile(typeChecker, typeChecker.globalScope, getBuiltinDefinitionSource(), "@luau");
LUAU_ASSERT(loadResult.success); LUAU_ASSERT(loadResult.success);
TypeId genericK = arena.addType(GenericTypeVar{"K"}); TypeId genericK = arena.addType(GenericType{"K"});
TypeId genericV = arena.addType(GenericTypeVar{"V"}); TypeId genericV = arena.addType(GenericType{"V"});
TypeId mapOfKtoV = arena.addType(TableTypeVar{{}, TableIndexer(genericK, genericV), typeChecker.globalScope->level, TableState::Generic}); TypeId mapOfKtoV = arena.addType(TableType{{}, TableIndexer(genericK, genericV), typeChecker.globalScope->level, TableState::Generic});
std::optional<TypeId> stringMetatableTy = getMetatable(singletonTypes->stringType, singletonTypes); std::optional<TypeId> stringMetatableTy = getMetatable(builtinTypes->stringType, builtinTypes);
LUAU_ASSERT(stringMetatableTy); LUAU_ASSERT(stringMetatableTy);
const TableTypeVar* stringMetatableTable = get<TableTypeVar>(follow(*stringMetatableTy)); const TableType* stringMetatableTable = get<TableType>(follow(*stringMetatableTy));
LUAU_ASSERT(stringMetatableTable); LUAU_ASSERT(stringMetatableTable);
auto it = stringMetatableTable->props.find("__index"); auto it = stringMetatableTable->props.find("__index");
@ -294,40 +294,40 @@ void registerBuiltinGlobals(TypeChecker& typeChecker)
// next<K, V>(t: Table<K, V>, i: K?) -> (K?, V) // next<K, V>(t: Table<K, V>, i: K?) -> (K?, V)
TypePackId nextArgsTypePack = arena.addTypePack(TypePack{{mapOfKtoV, makeOption(typeChecker, arena, genericK)}}); TypePackId nextArgsTypePack = arena.addTypePack(TypePack{{mapOfKtoV, makeOption(typeChecker, arena, genericK)}});
TypePackId nextRetsTypePack = arena.addTypePack(TypePack{{makeOption(typeChecker, arena, genericK), genericV}}); 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}); 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}}); TypePackId pairsReturnTypePack = arena.addTypePack(TypePack{{pairsNext, mapOfKtoV, nilType}});
// pairs<K, V>(t: Table<K, V>) -> ((Table<K, V>, K?) -> (K, V), Table<K, V>, nil) // pairs<K, V>(t: Table<K, V>) -> ((Table<K, V>, K?) -> (K, V), Table<K, V>, nil)
addGlobalBinding( addGlobalBinding(
typeChecker, "pairs", arena.addType(FunctionTypeVar{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau"); typeChecker, "pairs", arena.addType(FunctionType{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau");
} }
else else
{ {
// next<K, V>(t: Table<K, V>, i: K?) -> (K, V) // next<K, V>(t: Table<K, V>, i: K?) -> (K, V)
TypePackId nextArgsTypePack = arena.addTypePack(TypePack{{mapOfKtoV, makeOption(typeChecker, arena, genericK)}}); TypePackId nextArgsTypePack = arena.addTypePack(TypePack{{mapOfKtoV, makeOption(typeChecker, arena, genericK)}});
addGlobalBinding(typeChecker, "next", 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}); 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}}); TypePackId pairsReturnTypePack = arena.addTypePack(TypePack{{pairsNext, mapOfKtoV, nilType}});
// pairs<K, V>(t: Table<K, V>) -> ((Table<K, V>, K?) -> (K, V), Table<K, V>, nil) // pairs<K, V>(t: Table<K, V>) -> ((Table<K, V>, K?) -> (K, V), Table<K, V>, nil)
addGlobalBinding( 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 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"); addGlobalBinding(typeChecker, "getmetatable", makeFunction(arena, std::nullopt, {genericMT}, {}, {tableMetaMT}, {genericMT}), "@luau");
@ -335,7 +335,7 @@ void registerBuiltinGlobals(TypeChecker& typeChecker)
// setmetatable<T: {}, MT>(T, MT) -> { @metatable MT, T } // setmetatable<T: {}, MT>(T, MT) -> { @metatable MT, T }
addGlobalBinding(typeChecker, "setmetatable", addGlobalBinding(typeChecker, "setmetatable",
arena.addType( arena.addType(
FunctionTypeVar{ FunctionType{
{genericMT}, {genericMT},
{}, {},
arena.addTypePack(TypePack{{FFlag::LuauUnknownAndNeverType ? tabTy : tableMetaMT, genericMT}}), arena.addTypePack(TypePack{{FFlag::LuauUnknownAndNeverType ? tabTy : tableMetaMT, genericMT}}),
@ -349,7 +349,7 @@ void registerBuiltinGlobals(TypeChecker& typeChecker)
{ {
persist(pair.second.typeId); persist(pair.second.typeId);
if (TableTypeVar* ttv = getMutable<TableTypeVar>(pair.second.typeId)) if (TableType* ttv = getMutable<TableType>(pair.second.typeId))
{ {
if (!ttv->name) if (!ttv->name)
{ {
@ -366,7 +366,7 @@ void registerBuiltinGlobals(TypeChecker& typeChecker)
attachMagicFunction(getGlobalBinding(typeChecker, "select"), magicFunctionSelect); attachMagicFunction(getGlobalBinding(typeChecker, "select"), magicFunctionSelect);
attachDcrMagicFunction(getGlobalBinding(typeChecker, "select"), dcrMagicFunctionSelect); attachDcrMagicFunction(getGlobalBinding(typeChecker, "select"), dcrMagicFunctionSelect);
if (TableTypeVar* ttv = getMutable<TableTypeVar>(getGlobalBinding(typeChecker, "table"))) if (TableType* ttv = getMutable<TableType>(getGlobalBinding(typeChecker, "table")))
{ {
// tabTy is a generic table type which we can't express via declaration syntax yet // 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"); 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) void registerBuiltinGlobals(Frontend& frontend)
{ {
LUAU_ASSERT(!frontend.globalTypes.typeVars.isFrozen()); LUAU_ASSERT(!frontend.globalTypes.types.isFrozen());
LUAU_ASSERT(!frontend.globalTypes.typePacks.isFrozen()); LUAU_ASSERT(!frontend.globalTypes.typePacks.isFrozen());
if (FFlag::LuauReportShadowedTypeAlias) if (FFlag::LuauReportShadowedTypeAlias)
registerBuiltinTypes(frontend); registerBuiltinTypes(frontend);
TypeArena& arena = frontend.globalTypes; TypeArena& arena = frontend.globalTypes;
NotNull<SingletonTypes> singletonTypes = frontend.singletonTypes; NotNull<BuiltinTypes> builtinTypes = frontend.builtinTypes;
LoadDefinitionFileResult loadResult = frontend.loadDefinitionFile(getBuiltinDefinitionSource(), "@luau"); LoadDefinitionFileResult loadResult = frontend.loadDefinitionFile(getBuiltinDefinitionSource(), "@luau");
LUAU_ASSERT(loadResult.success); LUAU_ASSERT(loadResult.success);
TypeId genericK = arena.addType(GenericTypeVar{"K"}); TypeId genericK = arena.addType(GenericType{"K"});
TypeId genericV = arena.addType(GenericTypeVar{"V"}); TypeId genericV = arena.addType(GenericType{"V"});
TypeId mapOfKtoV = arena.addType(TableTypeVar{{}, TableIndexer(genericK, genericV), frontend.getGlobalScope()->level, TableState::Generic}); TypeId mapOfKtoV = arena.addType(TableType{{}, TableIndexer(genericK, genericV), frontend.getGlobalScope()->level, TableState::Generic});
std::optional<TypeId> stringMetatableTy = getMetatable(singletonTypes->stringType, singletonTypes); std::optional<TypeId> stringMetatableTy = getMetatable(builtinTypes->stringType, builtinTypes);
LUAU_ASSERT(stringMetatableTy); LUAU_ASSERT(stringMetatableTy);
const TableTypeVar* stringMetatableTable = get<TableTypeVar>(follow(*stringMetatableTy)); const TableType* stringMetatableTable = get<TableType>(follow(*stringMetatableTy));
LUAU_ASSERT(stringMetatableTable); LUAU_ASSERT(stringMetatableTable);
auto it = stringMetatableTable->props.find("__index"); auto it = stringMetatableTable->props.find("__index");
@ -413,40 +413,38 @@ void registerBuiltinGlobals(Frontend& frontend)
// next<K, V>(t: Table<K, V>, i: K?) -> (K?, V) // next<K, V>(t: Table<K, V>, i: K?) -> (K?, V)
TypePackId nextArgsTypePack = arena.addTypePack(TypePack{{mapOfKtoV, makeOption(frontend, arena, genericK)}}); TypePackId nextArgsTypePack = arena.addTypePack(TypePack{{mapOfKtoV, makeOption(frontend, arena, genericK)}});
TypePackId nextRetsTypePack = arena.addTypePack(TypePack{{makeOption(frontend, arena, genericK), genericV}}); 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}); 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, frontend.singletonTypes->nilType}}); TypePackId pairsReturnTypePack = arena.addTypePack(TypePack{{pairsNext, mapOfKtoV, frontend.builtinTypes->nilType}});
// pairs<K, V>(t: Table<K, V>) -> ((Table<K, V>, K?) -> (K?, V), Table<K, V>, nil) // pairs<K, V>(t: Table<K, V>) -> ((Table<K, V>, K?) -> (K?, V), Table<K, V>, nil)
addGlobalBinding( addGlobalBinding(frontend, "pairs", arena.addType(FunctionType{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau");
frontend, "pairs", arena.addType(FunctionTypeVar{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau");
} }
else else
{ {
// next<K, V>(t: Table<K, V>, i: K?) -> (K, V) // next<K, V>(t: Table<K, V>, i: K?) -> (K, V)
TypePackId nextArgsTypePack = arena.addTypePack(TypePack{{mapOfKtoV, makeOption(frontend, arena, genericK)}}); TypePackId nextArgsTypePack = arena.addTypePack(TypePack{{mapOfKtoV, makeOption(frontend, arena, genericK)}});
addGlobalBinding(frontend, "next", 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}); 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, frontend.singletonTypes->nilType}}); TypePackId pairsReturnTypePack = arena.addTypePack(TypePack{{pairsNext, mapOfKtoV, frontend.builtinTypes->nilType}});
// pairs<K, V>(t: Table<K, V>) -> ((Table<K, V>, K?) -> (K, V), Table<K, V>, nil) // pairs<K, V>(t: Table<K, V>) -> ((Table<K, V>, K?) -> (K, V), Table<K, V>, nil)
addGlobalBinding( addGlobalBinding(frontend, "pairs", arena.addType(FunctionType{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau");
frontend, "pairs", arena.addType(FunctionTypeVar{{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 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"); addGlobalBinding(frontend, "getmetatable", makeFunction(arena, std::nullopt, {genericMT}, {}, {tableMetaMT}, {genericMT}), "@luau");
@ -454,7 +452,7 @@ void registerBuiltinGlobals(Frontend& frontend)
// setmetatable<T: {}, MT>(T, MT) -> { @metatable MT, T } // setmetatable<T: {}, MT>(T, MT) -> { @metatable MT, T }
addGlobalBinding(frontend, "setmetatable", addGlobalBinding(frontend, "setmetatable",
arena.addType( arena.addType(
FunctionTypeVar{ FunctionType{
{genericMT}, {genericMT},
{}, {},
arena.addTypePack(TypePack{{FFlag::LuauUnknownAndNeverType ? tabTy : tableMetaMT, genericMT}}), arena.addTypePack(TypePack{{FFlag::LuauUnknownAndNeverType ? tabTy : tableMetaMT, genericMT}}),
@ -468,7 +466,7 @@ void registerBuiltinGlobals(Frontend& frontend)
{ {
persist(pair.second.typeId); persist(pair.second.typeId);
if (TableTypeVar* ttv = getMutable<TableTypeVar>(pair.second.typeId)) if (TableType* ttv = getMutable<TableType>(pair.second.typeId))
{ {
if (!ttv->name) if (!ttv->name)
{ {
@ -486,7 +484,7 @@ void registerBuiltinGlobals(Frontend& frontend)
attachMagicFunction(getGlobalBinding(frontend, "select"), magicFunctionSelect); attachMagicFunction(getGlobalBinding(frontend, "select"), magicFunctionSelect);
attachDcrMagicFunction(getGlobalBinding(frontend, "select"), dcrMagicFunctionSelect); attachDcrMagicFunction(getGlobalBinding(frontend, "select"), dcrMagicFunctionSelect);
if (TableTypeVar* ttv = getMutable<TableTypeVar>(getGlobalBinding(frontend, "table"))) if (TableType* ttv = getMutable<TableType>(getGlobalBinding(frontend, "table")))
{ {
// tabTy is a generic table type which we can't express via declaration syntax yet // 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"); 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] == '#') 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<BoundTypePack>(numberTypePack); asMutable(context.result)->ty.emplace<BoundTypePack>(numberTypePack);
return true; return true;
} }
@ -609,7 +607,7 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionSetMetaTable(
typechecker.tablify(mt); typechecker.tablify(mt);
} }
if (const auto& tab = get<TableTypeVar>(target)) if (const auto& tab = get<TableType>(target))
{ {
if (target->persistent) if (target->persistent)
{ {
@ -620,8 +618,8 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionSetMetaTable(
if (!FFlag::LuauUnknownAndNeverType) if (!FFlag::LuauUnknownAndNeverType)
typechecker.tablify(mt); typechecker.tablify(mt);
const TableTypeVar* mtTtv = get<TableTypeVar>(mt); const TableType* mtTtv = get<TableType>(mt);
MetatableTypeVar mtv{target, mt}; MetatableType mtv{target, mt};
if ((tab->name || tab->syntheticName) && (mtTtv && (mtTtv->name || mtTtv->syntheticName))) if ((tab->name || tab->syntheticName) && (mtTtv && (mtTtv->name || mtTtv->syntheticName)))
{ {
std::string tableName = tab->name ? *tab->name : *tab->syntheticName; std::string tableName = tab->name ? *tab->name : *tab->syntheticName;
@ -656,7 +654,7 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionSetMetaTable(
return WithPredicate<TypePackId>{arena.addTypePack({mtTy})}; return WithPredicate<TypePackId>{arena.addTypePack({mtTy})};
} }
} }
else if (get<AnyTypeVar>(target) || get<ErrorTypeVar>(target) || isTableIntersection(target)) else if (get<AnyType>(target) || get<ErrorType>(target) || isTableIntersection(target))
{ {
} }
else else
@ -687,10 +685,10 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionAssert(
if (head.size() > 0) 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 (FFlag::LuauUnknownAndNeverType)
{ {
if (get<NeverTypeVar>(*ty)) if (get<NeverType>(*ty))
head = {*ty}; head = {*ty};
else else
head[0] = *ty; head[0] = *ty;
@ -747,10 +745,10 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionPack(
else if (options.size() == 1) else if (options.size() == 1)
result = options[0]; result = options[0];
else else
result = arena.addType(UnionTypeVar{std::move(options)}); result = arena.addType(UnionType{std::move(options)});
TypeId packedTable = arena.addType( TypeId packedTable =
TableTypeVar{{{"n", {typechecker.numberType}}}, TableIndexer(typechecker.numberType, result), scope->level, TableState::Sealed}); arena.addType(TableType{{{"n", {typechecker.numberType}}}, TableIndexer(typechecker.numberType, result), scope->level, TableState::Sealed});
return WithPredicate<TypePackId>{arena.addTypePack({packedTable})}; return WithPredicate<TypePackId>{arena.addTypePack({packedTable})};
} }
@ -780,14 +778,14 @@ static bool dcrMagicFunctionPack(MagicFunctionCallContext context)
// table.pack(1, "foo") -> {| n: number, [number]: number | string |} // table.pack(1, "foo") -> {| n: number, [number]: number | string |}
TypeId result = nullptr; TypeId result = nullptr;
if (options.empty()) if (options.empty())
result = context.solver->singletonTypes->nilType; result = context.solver->builtinTypes->nilType;
else if (options.size() == 1) else if (options.size() == 1)
result = options[0]; result = options[0];
else else
result = arena->addType(UnionTypeVar{std::move(options)}); result = arena->addType(UnionType{std::move(options)});
TypeId numberType = context.solver->singletonTypes->numberType; TypeId numberType = context.solver->builtinTypes->numberType;
TypeId packedTable = arena->addType(TableTypeVar{{{"n", {numberType}}}, TableIndexer(numberType, result), {}, TableState::Sealed}); TypeId packedTable = arena->addType(TableType{{{"n", {numberType}}}, TableIndexer(numberType, result), {}, TableState::Sealed});
TypePackId tableTypePack = arena->addTypePack({packedTable}); TypePackId tableTypePack = arena->addTypePack({packedTable});
asMutable(context.result)->ty.emplace<BoundTypePack>(tableTypePack); asMutable(context.result)->ty.emplace<BoundTypePack>(tableTypePack);

View file

@ -48,21 +48,21 @@ struct TypeCloner
void operator()(const Unifiable::Generic& t); void operator()(const Unifiable::Generic& t);
void operator()(const Unifiable::Bound<TypeId>& t); void operator()(const Unifiable::Bound<TypeId>& t);
void operator()(const Unifiable::Error& t); void operator()(const Unifiable::Error& t);
void operator()(const BlockedTypeVar& t); void operator()(const BlockedType& t);
void operator()(const PendingExpansionTypeVar& t); void operator()(const PendingExpansionType& t);
void operator()(const PrimitiveTypeVar& t); void operator()(const PrimitiveType& t);
void operator()(const SingletonTypeVar& t); void operator()(const SingletonType& t);
void operator()(const FunctionTypeVar& t); void operator()(const FunctionType& t);
void operator()(const TableTypeVar& t); void operator()(const TableType& t);
void operator()(const MetatableTypeVar& t); void operator()(const MetatableType& t);
void operator()(const ClassTypeVar& t); void operator()(const ClassType& t);
void operator()(const AnyTypeVar& t); void operator()(const AnyType& t);
void operator()(const UnionTypeVar& t); void operator()(const UnionType& t);
void operator()(const IntersectionTypeVar& t); void operator()(const IntersectionType& t);
void operator()(const LazyTypeVar& t); void operator()(const LazyType& t);
void operator()(const UnknownTypeVar& t); void operator()(const UnknownType& t);
void operator()(const NeverTypeVar& t); void operator()(const NeverType& t);
void operator()(const NegationTypeVar& t); void operator()(const NegationType& t);
}; };
struct TypePackCloner struct TypePackCloner
@ -107,7 +107,7 @@ struct TypePackCloner
defaultClone(t); 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. // 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<TypePackId>& t) void operator()(const Unifiable::Bound<TypePackId>& t)
{ {
@ -159,7 +159,7 @@ void TypeCloner::operator()(const Unifiable::Bound<TypeId>& t)
{ {
TypeId boundTo = clone(t.boundTo, dest, cloneState); TypeId boundTo = clone(t.boundTo, dest, cloneState);
if (FFlag::DebugLuauCopyBeforeNormalizing) if (FFlag::DebugLuauCopyBeforeNormalizing)
boundTo = dest.addType(BoundTypeVar{boundTo}); boundTo = dest.addType(BoundType{boundTo});
seenTypes[typeId] = boundTo; seenTypes[typeId] = boundTo;
} }
@ -168,15 +168,15 @@ void TypeCloner::operator()(const Unifiable::Error& t)
defaultClone(t); defaultClone(t);
} }
void TypeCloner::operator()(const BlockedTypeVar& t) void TypeCloner::operator()(const BlockedType& t)
{ {
defaultClone(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}); TypeId res = dest.addType(PendingExpansionType{t.prefix, t.name, t.typeArguments, t.packArguments});
PendingExpansionTypeVar* petv = getMutable<PendingExpansionTypeVar>(res); PendingExpansionType* petv = getMutable<PendingExpansionType>(res);
LUAU_ASSERT(petv); LUAU_ASSERT(petv);
seenTypes[typeId] = res; seenTypes[typeId] = res;
@ -193,23 +193,23 @@ void TypeCloner::operator()(const PendingExpansionTypeVar& t)
petv->packArguments = std::move(packArguments); petv->packArguments = std::move(packArguments);
} }
void TypeCloner::operator()(const PrimitiveTypeVar& t) void TypeCloner::operator()(const PrimitiveType& t)
{ {
defaultClone(t); defaultClone(t);
} }
void TypeCloner::operator()(const SingletonTypeVar& t) void TypeCloner::operator()(const SingletonType& t)
{ {
defaultClone(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 // 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 // originally written so that we could copy a module's type surface into an
// export arena. This probably dates to that. // export arena. This probably dates to that.
TypeId result = dest.addType(FunctionTypeVar{TypeLevel{0, 0}, {}, {}, nullptr, nullptr, t.definition, t.hasSelf}); TypeId result = dest.addType(FunctionType{TypeLevel{0, 0}, {}, {}, nullptr, nullptr, t.definition, t.hasSelf});
FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(result); FunctionType* ftv = getMutable<FunctionType>(result);
LUAU_ASSERT(ftv != nullptr); LUAU_ASSERT(ftv != nullptr);
seenTypes[typeId] = result; seenTypes[typeId] = result;
@ -227,7 +227,7 @@ void TypeCloner::operator()(const FunctionTypeVar& t)
ftv->hasNoGenerics = t.hasNoGenerics; 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 table is now bound to another one, we ignore the content of the original
if (!FFlag::DebugLuauCopyBeforeNormalizing && t.boundTo) if (!FFlag::DebugLuauCopyBeforeNormalizing && t.boundTo)
@ -237,8 +237,8 @@ void TypeCloner::operator()(const TableTypeVar& t)
return; return;
} }
TypeId result = dest.addType(TableTypeVar{}); TypeId result = dest.addType(TableType{});
TableTypeVar* ttv = getMutable<TableTypeVar>(result); TableType* ttv = getMutable<TableType>(result);
LUAU_ASSERT(ttv != nullptr); LUAU_ASSERT(ttv != nullptr);
*ttv = t; *ttv = t;
@ -266,20 +266,20 @@ void TypeCloner::operator()(const TableTypeVar& t)
ttv->tags = t.tags; ttv->tags = t.tags;
} }
void TypeCloner::operator()(const MetatableTypeVar& t) void TypeCloner::operator()(const MetatableType& t)
{ {
TypeId result = dest.addType(MetatableTypeVar{}); TypeId result = dest.addType(MetatableType{});
MetatableTypeVar* mtv = getMutable<MetatableTypeVar>(result); MetatableType* mtv = getMutable<MetatableType>(result);
seenTypes[typeId] = result; seenTypes[typeId] = result;
mtv->table = clone(t.table, dest, cloneState); mtv->table = clone(t.table, dest, cloneState);
mtv->metatable = clone(t.metatable, 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}); TypeId result = dest.addType(ClassType{t.name, {}, std::nullopt, std::nullopt, t.tags, t.userData, t.definitionModuleName});
ClassTypeVar* ctv = getMutable<ClassTypeVar>(result); ClassType* ctv = getMutable<ClassType>(result);
seenTypes[typeId] = result; seenTypes[typeId] = result;
@ -293,12 +293,12 @@ void TypeCloner::operator()(const ClassTypeVar& t)
ctv->metatable = clone(*t.metatable, dest, cloneState); ctv->metatable = clone(*t.metatable, dest, cloneState);
} }
void TypeCloner::operator()(const AnyTypeVar& t) void TypeCloner::operator()(const AnyType& t)
{ {
defaultClone(t); defaultClone(t);
} }
void TypeCloner::operator()(const UnionTypeVar& t) void TypeCloner::operator()(const UnionType& t)
{ {
std::vector<TypeId> options; std::vector<TypeId> options;
options.reserve(t.options.size()); options.reserve(t.options.size());
@ -306,44 +306,44 @@ void TypeCloner::operator()(const UnionTypeVar& t)
for (TypeId ty : t.options) for (TypeId ty : t.options)
options.push_back(clone(ty, dest, cloneState)); 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; 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; seenTypes[typeId] = result;
IntersectionTypeVar* option = getMutable<IntersectionTypeVar>(result); IntersectionType* option = getMutable<IntersectionType>(result);
LUAU_ASSERT(option != nullptr); LUAU_ASSERT(option != nullptr);
for (TypeId ty : t.parts) for (TypeId ty : t.parts)
option->parts.push_back(clone(ty, dest, cloneState)); option->parts.push_back(clone(ty, dest, cloneState));
} }
void TypeCloner::operator()(const LazyTypeVar& t) void TypeCloner::operator()(const LazyType& t)
{ {
defaultClone(t); defaultClone(t);
} }
void TypeCloner::operator()(const UnknownTypeVar& t) void TypeCloner::operator()(const UnknownType& t)
{ {
defaultClone(t); defaultClone(t);
} }
void TypeCloner::operator()(const NeverTypeVar& t) void TypeCloner::operator()(const NeverType& t)
{ {
defaultClone(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; seenTypes[typeId] = result;
TypeId ty = clone(t.ty, dest, cloneState); TypeId ty = clone(t.ty, dest, cloneState);
asMutable(result)->ty = NegationTypeVar{ty}; asMutable(result)->ty = NegationType{ty};
} }
} // anonymous namespace } // anonymous namespace
@ -430,9 +430,9 @@ TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool alwaysCl
if (auto pty = log->pending(ty)) if (auto pty = log->pending(ty))
ty = &pty->pending; ty = &pty->pending;
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty)) if (const FunctionType* ftv = get<FunctionType>(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.generics = ftv->generics;
clone.genericPacks = ftv->genericPacks; clone.genericPacks = ftv->genericPacks;
clone.magicFunction = ftv->magicFunction; clone.magicFunction = ftv->magicFunction;
@ -441,10 +441,10 @@ TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool alwaysCl
clone.argNames = ftv->argNames; clone.argNames = ftv->argNames;
result = dest.addType(std::move(clone)); result = dest.addType(std::move(clone));
} }
else if (const TableTypeVar* ttv = get<TableTypeVar>(ty)) else if (const TableType* ttv = get<TableType>(ty))
{ {
LUAU_ASSERT(!ttv->boundTo); 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.definitionModuleName = ttv->definitionModuleName;
clone.name = ttv->name; clone.name = ttv->name;
clone.syntheticName = ttv->syntheticName; clone.syntheticName = ttv->syntheticName;
@ -453,41 +453,41 @@ TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool alwaysCl
clone.tags = ttv->tags; clone.tags = ttv->tags;
result = dest.addType(std::move(clone)); result = dest.addType(std::move(clone));
} }
else if (const MetatableTypeVar* mtv = get<MetatableTypeVar>(ty)) else if (const MetatableType* mtv = get<MetatableType>(ty))
{ {
MetatableTypeVar clone = MetatableTypeVar{mtv->table, mtv->metatable}; MetatableType clone = MetatableType{mtv->table, mtv->metatable};
clone.syntheticName = mtv->syntheticName; clone.syntheticName = mtv->syntheticName;
result = dest.addType(std::move(clone)); result = dest.addType(std::move(clone));
} }
else if (const UnionTypeVar* utv = get<UnionTypeVar>(ty)) else if (const UnionType* utv = get<UnionType>(ty))
{ {
UnionTypeVar clone; UnionType clone;
clone.options = utv->options; clone.options = utv->options;
result = dest.addType(std::move(clone)); result = dest.addType(std::move(clone));
} }
else if (const IntersectionTypeVar* itv = get<IntersectionTypeVar>(ty)) else if (const IntersectionType* itv = get<IntersectionType>(ty))
{ {
IntersectionTypeVar clone; IntersectionType clone;
clone.parts = itv->parts; clone.parts = itv->parts;
result = dest.addType(std::move(clone)); result = dest.addType(std::move(clone));
} }
else if (const PendingExpansionTypeVar* petv = get<PendingExpansionTypeVar>(ty)) else if (const PendingExpansionType* petv = get<PendingExpansionType>(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)); result = dest.addType(std::move(clone));
} }
else if (const ClassTypeVar* ctv = get<ClassTypeVar>(ty); FFlag::LuauClonePublicInterfaceLess && ctv && alwaysClone) else if (const ClassType* ctv = get<ClassType>(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)); result = dest.addType(std::move(clone));
} }
else if (FFlag::LuauClonePublicInterfaceLess && alwaysClone) else if (FFlag::LuauClonePublicInterfaceLess && alwaysClone)
{ {
result = dest.addType(*ty); result = dest.addType(*ty);
} }
else if (const NegationTypeVar* ntv = get<NegationTypeVar>(ty)) else if (const NegationType* ntv = get<NegationType>(ty))
{ {
result = dest.addType(NegationTypeVar{ntv->ty}); result = dest.addType(NegationType{ntv->ty});
} }
else else
return result; return result;

View file

@ -9,11 +9,12 @@
#include "Luau/RecursionCounter.h" #include "Luau/RecursionCounter.h"
#include "Luau/Scope.h" #include "Luau/Scope.h"
#include "Luau/TypeUtils.h" #include "Luau/TypeUtils.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
LUAU_FASTINT(LuauCheckRecursionLimit); LUAU_FASTINT(LuauCheckRecursionLimit);
LUAU_FASTFLAG(DebugLuauLogSolverToJson); LUAU_FASTFLAG(DebugLuauLogSolverToJson);
LUAU_FASTFLAG(DebugLuauMagicTypes); LUAU_FASTFLAG(DebugLuauMagicTypes);
LUAU_FASTFLAG(LuauNegatedClassTypes);
namespace Luau namespace Luau
{ {
@ -116,11 +117,11 @@ void forEachConstraint(const Checkpoint& start, const Checkpoint& end, const Con
} // namespace } // namespace
ConstraintGraphBuilder::ConstraintGraphBuilder(const ModuleName& moduleName, ModulePtr module, TypeArena* arena, ConstraintGraphBuilder::ConstraintGraphBuilder(const ModuleName& moduleName, ModulePtr module, TypeArena* arena,
NotNull<ModuleResolver> moduleResolver, NotNull<SingletonTypes> singletonTypes, NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope, NotNull<ModuleResolver> moduleResolver, NotNull<BuiltinTypes> builtinTypes, NotNull<InternalErrorReporter> ice, const ScopePtr& globalScope,
DcrLogger* logger, NotNull<DataFlowGraph> dfg) DcrLogger* logger, NotNull<DataFlowGraph> dfg)
: moduleName(moduleName) : moduleName(moduleName)
, module(module) , module(module)
, singletonTypes(singletonTypes) , builtinTypes(builtinTypes)
, arena(arena) , arena(arena)
, rootScope(nullptr) , rootScope(nullptr)
, dfg(dfg) , dfg(dfg)
@ -137,7 +138,7 @@ ConstraintGraphBuilder::ConstraintGraphBuilder(const ModuleName& moduleName, Mod
TypeId ConstraintGraphBuilder::freshType(const ScopePtr& scope) TypeId ConstraintGraphBuilder::freshType(const ScopePtr& scope)
{ {
return arena->addType(FreeTypeVar{scope.get()}); return arena->addType(FreeType{scope.get()});
} }
TypePackId ConstraintGraphBuilder::freshTypePack(const ScopePtr& scope) TypePackId ConstraintGraphBuilder::freshTypePack(const ScopePtr& scope)
@ -184,7 +185,7 @@ static void unionRefinements(const std::unordered_map<DefId, TypeId>& lhs, const
if (auto destIt = dest.find(def); destIt != dest.end()) if (auto destIt = dest.find(def); destIt != dest.end())
discriminants.push_back(destIt->second); 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; TypeId discriminantTy = proposition->discriminantTy;
if (!sense && !eq) if (!sense && !eq)
discriminantTy = arena->addType(NegationTypeVar{proposition->discriminantTy}); discriminantTy = arena->addType(NegationType{proposition->discriminantTy});
else if (eq) else if (eq)
{ {
discriminantTy = arena->addType(BlockedTypeVar{}); discriminantTy = arena->addType(BlockedType{});
constraints->push_back(SingletonOrTopTypeConstraint{discriminantTy, proposition->discriminantTy, !sense}); constraints->push_back(SingletonOrTopTypeConstraint{discriminantTy, proposition->discriminantTy, !sense});
} }
if (auto it = refis->find(proposition->def); it != refis->end()) 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 else
(*refis)[proposition->def] = discriminantTy; (*refis)[proposition->def] = discriminantTy;
} }
@ -251,8 +252,8 @@ static std::pair<DefId, TypeId> computeDiscriminantType(NotNull<TypeArena> arena
if (!current->field) if (!current->field)
break; break;
TableTypeVar::Props props{{current->field->propName, Property{discriminantTy}}}; TableType::Props props{{current->field->propName, Property{discriminantTy}}};
discriminantTy = arena->addType(TableTypeVar{std::move(props), std::nullopt, TypeLevel{}, scope.get(), TableState::Sealed}); discriminantTy = arena->addType(TableType{std::move(props), std::nullopt, TypeLevel{}, scope.get(), TableState::Sealed});
def = current->field->parent; def = current->field->parent;
current = get<Cell>(def); current = get<Cell>(def);
@ -277,7 +278,7 @@ void ConstraintGraphBuilder::applyRefinements(const ScopePtr& scope, Location lo
if (!defTy) if (!defTy)
ice->ice("Every DefId must map to a type!"); 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; scope->dcrRefinements[def2] = resultTy;
} }
@ -464,7 +465,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocal* local)
if (i < local->vars.size) 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 // fill out missing values in varTypes with values from exprPack
for (size_t j = i; j < varTypes.size(); ++j) for (size_t j = i; j < varTypes.size(); ++j)
@ -533,7 +534,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFor* for_)
return; return;
TypeId t = check(scope, expr).ty; 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); checkNumber(for_->from);
@ -541,7 +542,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFor* for_)
checkNumber(for_->step); checkNumber(for_->step);
ScopePtr forScope = childScope(for_, scope); 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); visit(forScope, for_->body);
} }
@ -603,7 +604,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatLocalFunction*
auto ty = scope->lookup(function->name); 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. 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}; scope->bindings[function->name] = Binding{functionType, function->name->location};
FunctionSignature sig = checkFunctionSignature(scope, function->func); FunctionSignature sig = checkFunctionSignature(scope, function->func);
@ -629,7 +630,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction* funct
// Name could be AstStatLocal, AstStatGlobal, AstStatIndexName. // Name could be AstStatLocal, AstStatGlobal, AstStatIndexName.
// With or without self // With or without self
TypeId generalizedType = arena->addType(BlockedTypeVar{}); TypeId generalizedType = arena->addType(BlockedType{});
FunctionSignature sig = checkFunctionSignature(scope, function->func); 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; TypeId containingTableType = check(scope, indexName->expr).ty;
// TODO look into stack utilization. This is probably ok because it scales with AST depth. // 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<TableTypeVar> prospectiveTable{getMutable<TableTypeVar>(prospectiveTableType)}; NotNull<TableType> prospectiveTable{getMutable<TableType>(prospectiveTableType)};
Property& prop = prospectiveTable->props[indexName->index.value]; Property& prop = prospectiveTable->props[indexName->index.value];
prop.type = generalizedType; prop.type = generalizedType;
@ -678,7 +679,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatFunction* funct
} }
else if (AstExprError* err = function->name->as<AstExprError>()) else if (AstExprError* err = function->name->as<AstExprError>())
{ {
generalizedType = singletonTypes->errorRecoveryType(); generalizedType = builtinTypes->errorRecoveryType();
} }
if (generalizedType == nullptr) if (generalizedType == nullptr)
@ -724,7 +725,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatAssign* assign)
{ {
TypePackId varPackId = checkLValues(scope, assign->vars); 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; TypePackId valuePack = checkPack(scope, assign->values, expectedTypes.head).tp;
addConstraint(scope, assign->location, PackSubtypeConstraint{valuePack, varPackId}); addConstraint(scope, assign->location, PackSubtypeConstraint{valuePack, varPackId});
@ -781,13 +782,13 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatTypeAlias* alia
scope->exportedTypeBindings[typeName] = TypeFun{ty}; scope->exportedTypeBindings[typeName] = TypeFun{ty};
} }
LUAU_ASSERT(get<FreeTypeVar>(bindingIt->second.type)); LUAU_ASSERT(get<FreeType>(bindingIt->second.type));
// Rather than using a subtype constraint, we instead directly bind // Rather than using a subtype constraint, we instead directly bind
// the free type we generated in the first pass to the resolved type. // the free type we generated in the first pass to the resolved type.
// This prevents a case where you could cause another constraint to // This prevents a case where you could cause another constraint to
// bind the free alias type to an unrelated type, causing havoc. // bind the free alias type to an unrelated type, causing havoc.
asMutable(bindingIt->second.type)->ty.emplace<BoundTypeVar>(ty); asMutable(bindingIt->second.type)->ty.emplace<BoundType>(ty);
addConstraint(scope, alias->location, NameConstraint{ty, alias->name.value}); 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) void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareClass* declaredClass)
{ {
std::optional<TypeId> superTy = std::nullopt; std::optional<TypeId> superTy = FFlag::LuauNegatedClassTypes ? std::make_optional(builtinTypes->classType) : std::nullopt;
if (declaredClass->superName) if (declaredClass->superName)
{ {
Name superName = Name(declaredClass->superName->value); 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); LUAU_ASSERT(lookupType->typeParams.size() == 0 && lookupType->typePackParams.size() == 0);
superTy = lookupType->type; superTy = lookupType->type;
if (!get<ClassTypeVar>(follow(*superTy))) if (!get<ClassType>(follow(*superTy)))
{ {
reportError(declaredClass->location, reportError(declaredClass->location,
GenericError{format("Cannot use non-class type '%s' as a superclass of class '%s'", superName.c_str(), declaredClass->name.value)}); 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); Name className(declaredClass->name.value);
TypeId classTy = arena->addType(ClassTypeVar(className, {}, superTy, std::nullopt, {}, {}, moduleName)); TypeId classTy = arena->addType(ClassType(className, {}, superTy, std::nullopt, {}, {}, moduleName));
ClassTypeVar* ctv = getMutable<ClassTypeVar>(classTy); ClassType* ctv = getMutable<ClassType>(classTy);
TypeId metaTy = arena->addType(TableTypeVar{TableState::Sealed, scope->level, scope.get()}); TypeId metaTy = arena->addType(TableType{TableState::Sealed, scope->level, scope.get()});
TableTypeVar* metatable = getMutable<TableTypeVar>(metaTy); TableType* metatable = getMutable<TableType>(metaTy);
ctv->metatable = metaTy; ctv->metatable = metaTy;
@ -860,7 +861,7 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareClass* d
// parsed annotation. Add it here. // parsed annotation. Add it here.
if (prop.isMethod) if (prop.isMethod)
{ {
if (FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(propTy)) if (FunctionType* ftv = getMutable<FunctionType>(propTy))
{ {
ftv->argNames.insert(ftv->argNames.begin(), FunctionArgument{"self", {}}); ftv->argNames.insert(ftv->argNames.begin(), FunctionArgument{"self", {}});
ftv->argTypes = arena->addTypePack(TypePack{{classTy}, ftv->argTypes}); 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 // We special-case this logic to keep the intersection flat; otherwise we
// would create a ton of nested intersection types. // would create a ton of nested intersection types.
if (const IntersectionTypeVar* itv = get<IntersectionTypeVar>(currentTy)) if (const IntersectionType* itv = get<IntersectionType>(currentTy))
{ {
std::vector<TypeId> options = itv->parts; std::vector<TypeId> options = itv->parts;
options.push_back(propTy); options.push_back(propTy);
TypeId newItv = arena->addType(IntersectionTypeVar{std::move(options)}); TypeId newItv = arena->addType(IntersectionType{std::move(options)});
if (assignToMetatable) if (assignToMetatable)
metatable->props[propName] = {newItv}; metatable->props[propName] = {newItv};
else else
ctv->props[propName] = {newItv}; ctv->props[propName] = {newItv};
} }
else if (get<FunctionTypeVar>(currentTy)) else if (get<FunctionType>(currentTy))
{ {
TypeId intersection = arena->addType(IntersectionTypeVar{{currentTy, propTy}}); TypeId intersection = arena->addType(IntersectionType{{currentTy, propTy}});
if (assignToMetatable) if (assignToMetatable)
metatable->props[propName] = {intersection}; metatable->props[propName] = {intersection};
@ -937,8 +938,8 @@ void ConstraintGraphBuilder::visit(const ScopePtr& scope, AstStatDeclareFunction
TypePackId paramPack = resolveTypePack(funScope, global->params); TypePackId paramPack = resolveTypePack(funScope, global->params);
TypePackId retPack = resolveTypePack(funScope, global->retTypes); TypePackId retPack = resolveTypePack(funScope, global->retTypes);
TypeId fnType = arena->addType(FunctionTypeVar{TypeLevel{}, funScope.get(), std::move(genericTys), std::move(genericTps), paramPack, retPack}); TypeId fnType = arena->addType(FunctionType{TypeLevel{}, funScope.get(), std::move(genericTys), std::move(genericTps), paramPack, retPack});
FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(fnType); FunctionType* ftv = getMutable<FunctionType>(fnType);
ftv->argNames.reserve(global->paramNames.size); ftv->argNames.reserve(global->paramNames.size);
for (const auto& el : global->paramNames) for (const auto& el : global->paramNames)
@ -995,7 +996,7 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExpr*
if (recursionCount >= FInt::LuauCheckRecursionLimit) if (recursionCount >= FInt::LuauCheckRecursionLimit)
{ {
reportCodeTooComplex(expr->location); reportCodeTooComplex(expr->location);
return InferencePack{singletonTypes->errorRecoveryTypePack()}; return InferencePack{builtinTypes->errorRecoveryTypePack()};
} }
InferencePack result; InferencePack result;
@ -1007,7 +1008,7 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExpr*
if (scope->varargPack) if (scope->varargPack)
result = InferencePack{*scope->varargPack}; result = InferencePack{*scope->varargPack};
else else
result = InferencePack{singletonTypes->errorRecoveryTypePack()}; result = InferencePack{builtinTypes->errorRecoveryTypePack()};
} }
else else
{ {
@ -1042,9 +1043,9 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa
TypePackId expectedArgPack = arena->freshTypePack(scope.get()); TypePackId expectedArgPack = arena->freshTypePack(scope.get());
TypePackId expectedRetPack = 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}); addConstraint(scope, call->location, InstantiationConstraint{instantiatedFnType, fnType});
NotNull<Constraint> extractArgsConstraint = addConstraint(scope, call->location, SubtypeConstraint{instantiatedFnType, expectedFunctionType}); NotNull<Constraint> extractArgsConstraint = addConstraint(scope, call->location, SubtypeConstraint{instantiatedFnType, expectedFunctionType});
@ -1060,9 +1061,9 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa
TypePack expectedArgs; TypePack expectedArgs;
if (!needTail) if (!needTail)
expectedArgs = extendTypePack(*arena, singletonTypes, expectedArgPack, exprArgs.size()); expectedArgs = extendTypePack(*arena, builtinTypes, expectedArgPack, exprArgs.size());
else else
expectedArgs = extendTypePack(*arena, singletonTypes, expectedArgPack, exprArgs.size() - 1); expectedArgs = extendTypePack(*arena, builtinTypes, expectedArgPack, exprArgs.size() - 1);
std::vector<TypeId> args; std::vector<TypeId> args;
std::optional<TypePackId> argTail; std::optional<TypePackId> argTail;
@ -1108,7 +1109,7 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa
}); });
std::vector<ConnectiveId> returnConnectives; std::vector<ConnectiveId> returnConnectives;
if (auto ftv = get<FunctionTypeVar>(follow(fnType)); ftv && ftv->dcrMagicRefinement) if (auto ftv = get<FunctionType>(follow(fnType)); ftv && ftv->dcrMagicRefinement)
{ {
MagicRefinementContext ctx{scope, NotNull{this}, dfg, NotNull{&connectiveArena}, std::move(argumentConnectives), call}; MagicRefinementContext ctx{scope, NotNull{this}, dfg, NotNull{&connectiveArena}, std::move(argumentConnectives), call};
returnConnectives = ftv->dcrMagicRefinement(ctx); returnConnectives = ftv->dcrMagicRefinement(ctx);
@ -1118,7 +1119,7 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa
{ {
TypePack argTailPack; TypePack argTailPack;
if (argTail && args.size() < 2) 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); 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]; AstExpr* targetExpr = call->args.data[0];
MetatableTypeVar mtv{target, mt}; MetatableType mtv{target, mt};
TypeId resultTy = arena->addType(mtv); TypeId resultTy = arena->addType(mtv);
if (AstExprLocal* targetLocal = targetExpr->as<AstExprLocal>()) if (AstExprLocal* targetLocal = targetExpr->as<AstExprLocal>())
@ -1139,11 +1140,11 @@ InferencePack ConstraintGraphBuilder::checkPack(const ScopePtr& scope, AstExprCa
{ {
astOriginalCallTypes[call->func] = fnType; astOriginalCallTypes[call->func] = fnType;
TypeId instantiatedType = arena->addType(BlockedTypeVar{}); TypeId instantiatedType = arena->addType(BlockedType{});
// TODO: How do expectedTypes play into this? Do they? // TODO: How do expectedTypes play into this? Do they?
TypePackId rets = arena->addTypePack(BlockedTypePack{}); TypePackId rets = arena->addTypePack(BlockedTypePack{});
TypePackId argPack = arena->addTypePack(TypePack{args, argTail}); 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); TypeId inferredFnType = arena->addType(ftv);
unqueuedConstraints.push_back( unqueuedConstraints.push_back(
@ -1183,7 +1184,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExpr* expr, st
if (recursionCount >= FInt::LuauCheckRecursionLimit) if (recursionCount >= FInt::LuauCheckRecursionLimit)
{ {
reportCodeTooComplex(expr->location); reportCodeTooComplex(expr->location);
return Inference{singletonTypes->errorRecoveryType()}; return Inference{builtinTypes->errorRecoveryType()};
} }
Inference result; Inference result;
@ -1193,11 +1194,11 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExpr* expr, st
else if (auto stringExpr = expr->as<AstExprConstantString>()) else if (auto stringExpr = expr->as<AstExprConstantString>())
result = check(scope, stringExpr, expectedType, forceSingleton); result = check(scope, stringExpr, expectedType, forceSingleton);
else if (expr->is<AstExprConstantNumber>()) else if (expr->is<AstExprConstantNumber>())
result = Inference{singletonTypes->numberType}; result = Inference{builtinTypes->numberType};
else if (auto boolExpr = expr->as<AstExprConstantBool>()) else if (auto boolExpr = expr->as<AstExprConstantBool>())
result = check(scope, boolExpr, expectedType, forceSingleton); result = check(scope, boolExpr, expectedType, forceSingleton);
else if (expr->is<AstExprConstantNil>()) else if (expr->is<AstExprConstantNil>())
result = Inference{singletonTypes->nilType}; result = Inference{builtinTypes->nilType};
else if (auto local = expr->as<AstExprLocal>()) else if (auto local = expr->as<AstExprLocal>())
result = check(scope, local); result = check(scope, local);
else if (auto global = expr->as<AstExprGlobal>()) else if (auto global = expr->as<AstExprGlobal>())
@ -1218,7 +1219,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExpr* expr, st
checkFunctionBody(sig.bodyScope, a); checkFunctionBody(sig.bodyScope, a);
Checkpoint endCheckpoint = checkpoint(this); Checkpoint endCheckpoint = checkpoint(this);
TypeId generalizedTy = arena->addType(BlockedTypeVar{}); TypeId generalizedTy = arena->addType(BlockedType{});
NotNull<Constraint> gc = addConstraint(scope, expr->location, GeneralizationConstraint{generalizedTy, sig.signature}); NotNull<Constraint> gc = addConstraint(scope, expr->location, GeneralizationConstraint{generalizedTy, sig.signature});
forEachConstraint(startCheckpoint, endCheckpoint, this, [gc](const ConstraintPtr& constraint) { 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) for (AstExpr* subExpr : err->expressions)
check(scope, subExpr); check(scope, subExpr);
result = Inference{singletonTypes->errorRecoveryType()}; result = Inference{builtinTypes->errorRecoveryType()};
} }
else else
{ {
@ -1263,30 +1264,30 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExpr* expr, st
Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprConstantString* string, std::optional<TypeId> expectedType, bool forceSingleton) Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprConstantString* string, std::optional<TypeId> expectedType, bool forceSingleton)
{ {
if (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) if (expectedType)
{ {
const TypeId expectedTy = follow(*expectedType); const TypeId expectedTy = follow(*expectedType);
if (get<BlockedTypeVar>(expectedTy) || get<PendingExpansionTypeVar>(expectedTy)) if (get<BlockedType>(expectedTy) || get<PendingExpansionType>(expectedTy))
{ {
TypeId ty = arena->addType(BlockedTypeVar{}); TypeId ty = arena->addType(BlockedType{});
TypeId singletonType = arena->addType(SingletonTypeVar(StringSingleton{std::string(string->value.data, string->value.size)})); TypeId singletonType = arena->addType(SingletonType(StringSingleton{std::string(string->value.data, string->value.size)}));
addConstraint(scope, string->location, PrimitiveTypeConstraint{ty, expectedTy, singletonType, singletonTypes->stringType}); addConstraint(scope, string->location, PrimitiveTypeConstraint{ty, expectedTy, singletonType, builtinTypes->stringType});
return Inference{ty}; return Inference{ty};
} }
else if (maybeSingleton(expectedTy)) 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<TypeId> expectedType, bool forceSingleton) Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprConstantBool* boolExpr, std::optional<TypeId> expectedType, bool forceSingleton)
{ {
const TypeId singletonType = boolExpr->value ? singletonTypes->trueType : singletonTypes->falseType; const TypeId singletonType = boolExpr->value ? builtinTypes->trueType : builtinTypes->falseType;
if (forceSingleton) if (forceSingleton)
return Inference{singletonType}; return Inference{singletonType};
@ -1294,19 +1295,19 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprConstantBo
{ {
const TypeId expectedTy = follow(*expectedType); const TypeId expectedTy = follow(*expectedType);
if (get<BlockedTypeVar>(expectedTy) || get<PendingExpansionTypeVar>(expectedTy)) if (get<BlockedType>(expectedTy) || get<PendingExpansionType>(expectedTy))
{ {
TypeId ty = arena->addType(BlockedTypeVar{}); TypeId ty = arena->addType(BlockedType{});
addConstraint(scope, boolExpr->location, PrimitiveTypeConstraint{ty, expectedTy, singletonType, singletonTypes->booleanType}); addConstraint(scope, boolExpr->location, PrimitiveTypeConstraint{ty, expectedTy, singletonType, builtinTypes->booleanType});
return Inference{ty}; return Inference{ty};
} }
else if (maybeSingleton(expectedTy)) else if (maybeSingleton(expectedTy))
return Inference{singletonType}; 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) Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprLocal* local)
@ -1323,10 +1324,10 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprLocal* loc
} }
if (!resultTy) 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) if (def)
return Inference{*resultTy, connectiveArena.proposition(*def, singletonTypes->truthyType)}; return Inference{*resultTy, connectiveArena.proposition(*def, builtinTypes->truthyType)};
else else
return Inference{*resultTy}; 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. * global that is not already in-scope is definitely an unknown symbol.
*/ */
reportError(global->location, UnknownSymbol{global->name.value}); reportError(global->location, UnknownSymbol{global->name.value});
return Inference{singletonTypes->errorRecoveryType()}; return Inference{builtinTypes->errorRecoveryType()};
} }
static std::optional<TypeId> lookupProp(TypeId ty, const std::string& propName, NotNull<TypeArena> arena) static std::optional<TypeId> lookupProp(TypeId ty, const std::string& propName, NotNull<TypeArena> arena)
{ {
ty = follow(ty); ty = follow(ty);
if (auto ctv = get<ClassTypeVar>(ty)) if (auto ctv = get<ClassType>(ty))
{ {
if (auto prop = lookupClassProp(ctv, propName)) if (auto prop = lookupClassProp(ctv, propName))
return prop->type; return prop->type;
} }
else if (auto ttv = get<TableTypeVar>(ty)) else if (auto ttv = get<TableType>(ty))
{ {
if (auto it = ttv->props.find(propName); it != ttv->props.end()) if (auto it = ttv->props.find(propName); it != ttv->props.end())
return it->second.type; return it->second.type;
} }
else if (auto utv = get<IntersectionTypeVar>(ty)) else if (auto utv = get<IntersectionType>(ty))
{ {
std::vector<TypeId> types; std::vector<TypeId> types;
@ -1375,9 +1376,9 @@ static std::optional<TypeId> lookupProp(TypeId ty, const std::string& propName,
if (types.size() == 1) if (types.size() == 1)
return types[0]; return types[0];
else else
return arena->addType(IntersectionTypeVar{std::move(types)}); return arena->addType(IntersectionType{std::move(types)});
} }
else if (auto utv = get<UnionTypeVar>(ty)) else if (auto utv = get<UnionType>(ty))
{ {
std::vector<TypeId> types; std::vector<TypeId> types;
@ -1395,7 +1396,7 @@ static std::optional<TypeId> lookupProp(TypeId ty, const std::string& propName,
if (types.size() == 1) if (types.size() == 1)
return types[0]; return types[0];
else else
return arena->addType(UnionTypeVar{std::move(types)}); return arena->addType(UnionType{std::move(types)});
} }
return std::nullopt; return std::nullopt;
@ -1416,21 +1417,21 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexName*
if (def) if (def)
{ {
if (auto ty = scope->lookup(*def)) if (auto ty = scope->lookup(*def))
return Inference{*ty, connectiveArena.proposition(*def, singletonTypes->truthyType)}; return Inference{*ty, connectiveArena.proposition(*def, builtinTypes->truthyType)};
else else
scope->dcrRefinements[*def] = result; scope->dcrRefinements[*def] = result;
} }
TableTypeVar::Props props{{indexName->index.value, Property{result}}}; TableType::Props props{{indexName->index.value, Property{result}}};
const std::optional<TableIndexer> indexer; const std::optional<TableIndexer> 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)); TypeId expectedTableType = arena->addType(std::move(ttv));
addConstraint(scope, indexName->expr->location, SubtypeConstraint{obj, expectedTableType}); addConstraint(scope, indexName->expr->location, SubtypeConstraint{obj, expectedTableType});
if (def) if (def)
return Inference{result, connectiveArena.proposition(*def, singletonTypes->truthyType)}; return Inference{result, connectiveArena.proposition(*def, builtinTypes->truthyType)};
else else
return Inference{result}; return Inference{result};
} }
@ -1443,8 +1444,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprIndexExpr*
TypeId result = freshType(scope); TypeId result = freshType(scope);
TableIndexer indexer{indexType, result}; TableIndexer indexer{indexType, result};
TypeId tableType = TypeId tableType = arena->addType(TableType{TableType::Props{}, TableIndexer{indexType, result}, TypeLevel{}, scope.get(), TableState::Free});
arena->addType(TableTypeVar{TableTypeVar::Props{}, TableIndexer{indexType, result}, TypeLevel{}, scope.get(), TableState::Free});
addConstraint(scope, indexExpr->expr->location, SubtypeConstraint{obj, tableType}); 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) Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprUnary* unary)
{ {
auto [operandType, connective] = check(scope, unary->expr); 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}); addConstraint(scope, unary->location, UnaryConstraint{unary->op, operandType, resultType});
if (unary->op == AstExprUnary::Not) 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); auto [leftType, rightType, connective] = checkBinary(scope, binary, expectedType);
TypeId resultType = arena->addType(BlockedTypeVar{}); TypeId resultType = arena->addType(BlockedType{});
addConstraint(scope, binary->location, BinaryConstraint{binary->op, leftType, rightType, resultType, binary, &astOriginalCallTypes, &astOverloadResolvedTypes}); addConstraint(scope, binary->location,
BinaryConstraint{binary->op, leftType, rightType, resultType, binary, &astOriginalCallTypes, &astOverloadResolvedTypes});
return Inference{resultType, std::move(connective)}; return Inference{resultType, std::move(connective)};
} }
@ -1534,34 +1535,34 @@ std::tuple<TypeId, TypeId, ConnectiveId> ConstraintGraphBuilder::checkBinary(
if (!def) if (!def)
return {leftType, rightType, nullptr}; return {leftType, rightType, nullptr};
TypeId discriminantTy = singletonTypes->neverType; TypeId discriminantTy = builtinTypes->neverType;
if (typeguard->type == "nil") if (typeguard->type == "nil")
discriminantTy = singletonTypes->nilType; discriminantTy = builtinTypes->nilType;
else if (typeguard->type == "string") else if (typeguard->type == "string")
discriminantTy = singletonTypes->stringType; discriminantTy = builtinTypes->stringType;
else if (typeguard->type == "number") else if (typeguard->type == "number")
discriminantTy = singletonTypes->numberType; discriminantTy = builtinTypes->numberType;
else if (typeguard->type == "boolean") else if (typeguard->type == "boolean")
discriminantTy = singletonTypes->threadType; discriminantTy = builtinTypes->threadType;
else if (typeguard->type == "table") 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") else if (typeguard->type == "function")
discriminantTy = singletonTypes->functionType; discriminantTy = builtinTypes->functionType;
else if (typeguard->type == "userdata") else if (typeguard->type == "userdata")
{ {
// For now, we don't really care about being accurate with userdata if the typeguard was using typeof // 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") 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) 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()) else if (auto typeFun = globalScope->lookupType(typeguard->type); typeFun && typeFun->typeParams.empty() && typeFun->typePackParams.empty())
{ {
TypeId ty = follow(typeFun->type); TypeId ty = follow(typeFun->type);
// We're only interested in the root class of any classes. // We're only interested in the root class of any classes.
if (auto ctv = get<ClassTypeVar>(ty); !ctv || !ctv->parent) if (auto ctv = get<ClassType>(ty); !ctv || !ctv->parent)
discriminantTy = ty; discriminantTy = ty;
} }
@ -1685,7 +1686,7 @@ TypeId ConstraintGraphBuilder::checkLValue(const ScopePtr& scope, AstExpr* expr)
std::vector<std::string> segmentStrings(begin(segments), end(segments)); std::vector<std::string> 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}); addConstraint(scope, expr->location, SetPropConstraint{updatedType, subjectType, std::move(segmentStrings), propTy});
std::optional<DefId> def = dfg->getDef(sym); std::optional<DefId> 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<TypeId> expectedType) Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType)
{ {
TypeId ty = arena->addType(TableTypeVar{}); TypeId ty = arena->addType(TableType{});
TableTypeVar* ttv = getMutable<TableTypeVar>(ty); TableType* ttv = getMutable<TableType>(ty);
LUAU_ASSERT(ttv); LUAU_ASSERT(ttv);
ttv->state = TableState::Unsealed; ttv->state = TableState::Unsealed;
@ -1729,12 +1730,12 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTable* exp
{ {
ErrorVec errorVec; ErrorVec errorVec;
std::optional<TypeId> propTy = std::optional<TypeId> 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) if (propTy)
expectedValueType = propTy; expectedValueType = propTy;
else else
{ {
expectedValueType = arena->addType(BlockedTypeVar{}); expectedValueType = arena->addType(BlockedType{});
addConstraint(scope, item.value->location, HasPropConstraint{*expectedValueType, *expectedType, stringKey->value.data}); addConstraint(scope, item.value->location, HasPropConstraint{*expectedValueType, *expectedType, stringKey->value.data});
} }
} }
@ -1760,7 +1761,7 @@ Inference ConstraintGraphBuilder::check(const ScopePtr& scope, AstExprTable* exp
} }
else else
{ {
TypeId numberType = singletonTypes->numberType; TypeId numberType = builtinTypes->numberType;
// FIXME? The location isn't quite right here. Not sure what is // FIXME? The location isn't quite right here. Not sure what is
// right. // right.
createIndexer(item.value->location, numberType, itemTy); createIndexer(item.value->location, numberType, itemTy);
@ -1821,11 +1822,11 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS
std::vector<TypeId> argTypes; std::vector<TypeId> argTypes;
TypePack expectedArgPack; TypePack expectedArgPack;
const FunctionTypeVar* expectedFunction = expectedType ? get<FunctionTypeVar>(*expectedType) : nullptr; const FunctionType* expectedFunction = expectedType ? get<FunctionType>(*expectedType) : nullptr;
if (expectedFunction) if (expectedFunction)
{ {
expectedArgPack = extendTypePack(*arena, singletonTypes, expectedFunction->argTypes, fn->args.size); expectedArgPack = extendTypePack(*arena, builtinTypes, expectedFunction->argTypes, fn->args.size);
genericTypes = expectedFunction->generics; genericTypes = expectedFunction->generics;
genericTypePacks = expectedFunction->genericPacks; genericTypePacks = expectedFunction->genericPacks;
@ -1870,14 +1871,14 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS
else if (expectedArgPack.tail && get<VariadicTypePack>(*expectedArgPack.tail)) else if (expectedArgPack.tail && get<VariadicTypePack>(*expectedArgPack.tail))
varargPack = *expectedArgPack.tail; varargPack = *expectedArgPack.tail;
else else
varargPack = singletonTypes->anyTypePack; varargPack = builtinTypes->anyTypePack;
signatureScope->varargPack = varargPack; signatureScope->varargPack = varargPack;
bodyScope->varargPack = varargPack; bodyScope->varargPack = varargPack;
} }
else 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 // We do not add to signatureScope->varargPack because ... is not valid
// in functions without an explicit ellipsis. // in functions without an explicit ellipsis.
@ -1906,7 +1907,7 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS
// TODO: Preserve argument names in the function's type. // 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.hasNoGenerics = !hasGenerics;
actualFunction.generics = std::move(genericTypes); actualFunction.generics = std::move(genericTypes);
actualFunction.genericPacks = std::move(genericTypePacks); actualFunction.genericPacks = std::move(genericTypePacks);
@ -1915,9 +1916,9 @@ ConstraintGraphBuilder::FunctionSignature ConstraintGraphBuilder::checkFunctionS
LUAU_ASSERT(actualFunctionType); LUAU_ASSERT(actualFunctionType);
astTypes[fn] = actualFunctionType; astTypes[fn] = actualFunctionType;
if (expectedType && get<FreeTypeVar>(*expectedType)) if (expectedType && get<FreeType>(*expectedType))
{ {
asMutable(*expectedType)->ty.emplace<BoundTypeVar>(actualFunctionType); asMutable(*expectedType)->ty.emplace<BoundType>(actualFunctionType);
} }
return { return {
@ -1955,7 +1956,7 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b
if (ref->parameters.size != 1 || !ref->parameters.data[0].type) if (ref->parameters.size != 1 || !ref->parameters.data[0].type)
{ {
reportError(ty->location, GenericError{"_luau_print requires one generic parameter"}); reportError(ty->location, GenericError{"_luau_print requires one generic parameter"});
return singletonTypes->errorRecoveryType(); return builtinTypes->errorRecoveryType();
} }
else else
return resolveType(scope, ref->parameters.data[0].type, topLevel); 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) if (topLevel)
{ {
@ -2021,12 +2022,12 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b
typeName = std::string(ref->prefix->value) + "."; typeName = std::string(ref->prefix->value) + ".";
typeName += ref->name.value; typeName += ref->name.value;
result = singletonTypes->errorRecoveryType(); result = builtinTypes->errorRecoveryType();
} }
} }
else if (auto tab = ty->as<AstTypeTable>()) else if (auto tab = ty->as<AstTypeTable>())
{ {
TableTypeVar::Props props; TableType::Props props;
std::optional<TableIndexer> indexer; std::optional<TableIndexer> indexer;
for (const AstTableProp& prop : tab->props) 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<AstTypeFunction>()) else if (auto fn = ty->as<AstTypeFunction>())
{ {
@ -2090,11 +2091,11 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b
TypePackId argTypes = resolveTypePack(signatureScope, fn->argTypes); TypePackId argTypes = resolveTypePack(signatureScope, fn->argTypes);
TypePackId returnTypes = resolveTypePack(signatureScope, fn->returnTypes); 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. // 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. // constructors.
ftv.hasNoGenerics = !hasGenerics; ftv.hasNoGenerics = !hasGenerics;
ftv.generics = std::move(genericTypes); 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)); parts.push_back(resolveType(scope, part, topLevel));
} }
result = arena->addType(UnionTypeVar{parts}); result = arena->addType(UnionType{parts});
} }
else if (auto intersectionAnnotation = ty->as<AstTypeIntersection>()) else if (auto intersectionAnnotation = ty->as<AstTypeIntersection>())
{ {
@ -2142,24 +2143,24 @@ TypeId ConstraintGraphBuilder::resolveType(const ScopePtr& scope, AstType* ty, b
parts.push_back(resolveType(scope, part, topLevel)); parts.push_back(resolveType(scope, part, topLevel));
} }
result = arena->addType(IntersectionTypeVar{parts}); result = arena->addType(IntersectionType{parts});
} }
else if (auto boolAnnotation = ty->as<AstTypeSingletonBool>()) else if (auto boolAnnotation = ty->as<AstTypeSingletonBool>())
{ {
result = arena->addType(SingletonTypeVar(BooleanSingleton{boolAnnotation->value})); result = arena->addType(SingletonType(BooleanSingleton{boolAnnotation->value}));
} }
else if (auto stringAnnotation = ty->as<AstTypeSingletonString>()) else if (auto stringAnnotation = ty->as<AstTypeSingletonString>())
{ {
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<AstTypeError>()) else if (ty->is<AstTypeError>())
{ {
result = singletonTypes->errorRecoveryType(); result = builtinTypes->errorRecoveryType();
} }
else else
{ {
LUAU_ASSERT(0); LUAU_ASSERT(0);
result = singletonTypes->errorRecoveryType(); result = builtinTypes->errorRecoveryType();
} }
astResolvedTypes[ty] = result; astResolvedTypes[ty] = result;
@ -2187,13 +2188,13 @@ TypePackId ConstraintGraphBuilder::resolveTypePack(const ScopePtr& scope, AstTyp
else else
{ {
reportError(tp->location, UnknownSymbol{gen->genericName.value, UnknownSymbol::Context::Type}); reportError(tp->location, UnknownSymbol{gen->genericName.value, UnknownSymbol::Context::Type});
result = singletonTypes->errorRecoveryTypePack(); result = builtinTypes->errorRecoveryTypePack();
} }
} }
else else
{ {
LUAU_ASSERT(0); LUAU_ASSERT(0);
result = singletonTypes->errorRecoveryTypePack(); result = builtinTypes->errorRecoveryTypePack();
} }
astResolvedTypePacks[tp] = result; astResolvedTypePacks[tp] = result;
@ -2223,7 +2224,7 @@ std::vector<std::pair<Name, GenericTypeDefinition>> ConstraintGraphBuilder::crea
std::vector<std::pair<Name, GenericTypeDefinition>> result; std::vector<std::pair<Name, GenericTypeDefinition>> result;
for (const auto& generic : generics) 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<TypeId> defaultTy = std::nullopt; std::optional<TypeId> defaultTy = std::nullopt;
if (generic.defaultValue) if (generic.defaultValue)
@ -2302,7 +2303,7 @@ struct GlobalPrepopulator : AstVisitor
bool visit(AstStatFunction* function) override bool visit(AstStatFunction* function) override
{ {
if (AstExprGlobal* g = function->name->as<AstExprGlobal>()) if (AstExprGlobal* g = function->name->as<AstExprGlobal>())
globalScope->bindings[g->name] = Binding{arena->addType(BlockedTypeVar{})}; globalScope->bindings[g->name] = Binding{arena->addType(BlockedType{})};
return true; return true;
} }

View file

@ -12,9 +12,9 @@
#include "Luau/Quantify.h" #include "Luau/Quantify.h"
#include "Luau/ToString.h" #include "Luau/ToString.h"
#include "Luau/TypeUtils.h" #include "Luau/TypeUtils.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/Unifier.h" #include "Luau/Unifier.h"
#include "Luau/VisitTypeVar.h" #include "Luau/VisitType.h"
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolver, false); LUAU_FASTFLAGVARIABLE(DebugLuauLogSolver, false);
LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson, false); LUAU_FASTFLAGVARIABLE(DebugLuauLogSolverToJson, false);
@ -34,7 +34,7 @@ namespace Luau
dumpBindings(child, opts); dumpBindings(child, opts);
} }
static std::pair<std::vector<TypeId>, std::vector<TypePackId>> saturateArguments(TypeArena* arena, NotNull<SingletonTypes> singletonTypes, static std::pair<std::vector<TypeId>, std::vector<TypePackId>> saturateArguments(TypeArena* arena, NotNull<BuiltinTypes> builtinTypes,
const TypeFun& fn, const std::vector<TypeId>& rawTypeArguments, const std::vector<TypePackId>& rawPackArguments) const TypeFun& fn, const std::vector<TypeId>& rawTypeArguments, const std::vector<TypePackId>& rawPackArguments)
{ {
std::vector<TypeId> saturatedTypeArguments; std::vector<TypeId> saturatedTypeArguments;
@ -115,7 +115,7 @@ static std::pair<std::vector<TypeId>, std::vector<TypePackId>> saturateArguments
if (!defaultTy) if (!defaultTy)
break; 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; atf.typeArguments[fn.typeParams[i].ty] = instantiatedDefault;
saturatedTypeArguments.push_back(instantiatedDefault); saturatedTypeArguments.push_back(instantiatedDefault);
} }
@ -133,7 +133,7 @@ static std::pair<std::vector<TypeId>, std::vector<TypePackId>> saturateArguments
if (!defaultTp) if (!defaultTp)
break; 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; atf.typePackArguments[fn.typePackParams[i].tp] = instantiatedDefault;
saturatedPackArguments.push_back(instantiatedDefault); saturatedPackArguments.push_back(instantiatedDefault);
} }
@ -151,12 +151,12 @@ static std::pair<std::vector<TypeId>, std::vector<TypePackId>> saturateArguments
// even if they're missing, so we use the error type as a filler. // even if they're missing, so we use the error type as a filler.
for (size_t i = saturatedTypeArguments.size(); i < typesRequired; ++i) 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) 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 // 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> normalizer, NotNull<Scope> rootScope, std::vector<NotNull<Constraint>> constraints, ConstraintSolver::ConstraintSolver(NotNull<Normalizer> normalizer, NotNull<Scope> rootScope, std::vector<NotNull<Constraint>> constraints,
ModuleName moduleName, NotNull<ModuleResolver> moduleResolver, std::vector<RequireCycle> requireCycles, DcrLogger* logger) ModuleName moduleName, NotNull<ModuleResolver> moduleResolver, std::vector<RequireCycle> requireCycles, DcrLogger* logger)
: arena(normalizer->arena) : arena(normalizer->arena)
, singletonTypes(normalizer->singletonTypes) , builtinTypes(normalizer->builtinTypes)
, normalizer(normalizer) , normalizer(normalizer)
, constraints(std::move(constraints)) , constraints(std::move(constraints))
, rootScope(rootScope) , rootScope(rootScope)
@ -373,12 +373,12 @@ bool ConstraintSolver::isDone()
void ConstraintSolver::finalizeModule() 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<TypePackId> returnType = a.substitute(rootScope->returnType); std::optional<TypePackId> returnType = a.substitute(rootScope->returnType);
if (!returnType) if (!returnType)
{ {
reportError(CodeTooComplex{}, Location{}); reportError(CodeTooComplex{}, Location{});
rootScope->returnType = singletonTypes->errorTypePack; rootScope->returnType = builtinTypes->errorTypePack;
} }
else else
rootScope->returnType = *returnType; rootScope->returnType = *returnType;
@ -470,7 +470,7 @@ bool ConstraintSolver::tryDispatch(const GeneralizationConstraint& c, NotNull<co
TypeId generalized = quantify(arena, c.sourceType, constraint->scope); TypeId generalized = quantify(arena, c.sourceType, constraint->scope);
if (isBlocked(c.generalizedType)) if (isBlocked(c.generalizedType))
asMutable(c.generalizedType)->ty.emplace<BoundTypeVar>(generalized); asMutable(c.generalizedType)->ty.emplace<BoundType>(generalized);
else else
unify(c.generalizedType, generalized, constraint->scope); unify(c.generalizedType, generalized, constraint->scope);
@ -491,7 +491,7 @@ bool ConstraintSolver::tryDispatch(const InstantiationConstraint& c, NotNull<con
LUAU_ASSERT(instantiated); // TODO FIXME HANDLE THIS LUAU_ASSERT(instantiated); // TODO FIXME HANDLE THIS
if (isBlocked(c.subType)) if (isBlocked(c.subType))
asMutable(c.subType)->ty.emplace<BoundTypeVar>(*instantiated); asMutable(c.subType)->ty.emplace<BoundType>(*instantiated);
else else
unify(c.subType, *instantiated, constraint->scope); unify(c.subType, *instantiated, constraint->scope);
@ -507,62 +507,62 @@ bool ConstraintSolver::tryDispatch(const UnaryConstraint& c, NotNull<const Const
if (isBlocked(operandType)) if (isBlocked(operandType))
return block(operandType, constraint); return block(operandType, constraint);
if (get<FreeTypeVar>(operandType)) if (get<FreeType>(operandType))
return block(operandType, constraint); return block(operandType, constraint);
LUAU_ASSERT(get<BlockedTypeVar>(c.resultType)); LUAU_ASSERT(get<BlockedType>(c.resultType));
switch (c.op) switch (c.op)
{ {
case AstExprUnary::Not: case AstExprUnary::Not:
{ {
asMutable(c.resultType)->ty.emplace<BoundTypeVar>(singletonTypes->booleanType); asMutable(c.resultType)->ty.emplace<BoundType>(builtinTypes->booleanType);
return true; return true;
} }
case AstExprUnary::Len: case AstExprUnary::Len:
{ {
// __len must return a number. // __len must return a number.
asMutable(c.resultType)->ty.emplace<BoundTypeVar>(singletonTypes->numberType); asMutable(c.resultType)->ty.emplace<BoundType>(builtinTypes->numberType);
return true; return true;
} }
case AstExprUnary::Minus: case AstExprUnary::Minus:
{ {
if (isNumber(operandType) || get<AnyTypeVar>(operandType) || get<ErrorTypeVar>(operandType)) if (isNumber(operandType) || get<AnyType>(operandType) || get<ErrorType>(operandType))
{ {
asMutable(c.resultType)->ty.emplace<BoundTypeVar>(c.operandType); asMutable(c.resultType)->ty.emplace<BoundType>(c.operandType);
} }
else if (std::optional<TypeId> mm = findMetatableEntry(singletonTypes, errors, operandType, "__unm", constraint->location)) else if (std::optional<TypeId> mm = findMetatableEntry(builtinTypes, errors, operandType, "__unm", constraint->location))
{ {
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(*mm)); const FunctionType* ftv = get<FunctionType>(follow(*mm));
if (!ftv) if (!ftv)
{ {
if (std::optional<TypeId> callMm = findMetatableEntry(singletonTypes, errors, follow(*mm), "__call", constraint->location)) if (std::optional<TypeId> callMm = findMetatableEntry(builtinTypes, errors, follow(*mm), "__call", constraint->location))
{ {
ftv = get<FunctionTypeVar>(follow(*callMm)); ftv = get<FunctionType>(follow(*callMm));
} }
} }
if (!ftv) if (!ftv)
{ {
asMutable(c.resultType)->ty.emplace<BoundTypeVar>(singletonTypes->errorRecoveryType()); asMutable(c.resultType)->ty.emplace<BoundType>(builtinTypes->errorRecoveryType());
return true; return true;
} }
TypePackId argsPack = arena->addTypePack({operandType}); TypePackId argsPack = arena->addTypePack({operandType});
unify(ftv->argTypes, argsPack, constraint->scope); unify(ftv->argTypes, argsPack, constraint->scope);
TypeId result = singletonTypes->errorRecoveryType(); TypeId result = builtinTypes->errorRecoveryType();
if (ftv) if (ftv)
{ {
result = first(ftv->retTypes).value_or(singletonTypes->errorRecoveryType()); result = first(ftv->retTypes).value_or(builtinTypes->errorRecoveryType());
} }
asMutable(c.resultType)->ty.emplace<BoundTypeVar>(result); asMutable(c.resultType)->ty.emplace<BoundType>(result);
} }
else else
{ {
asMutable(c.resultType)->ty.emplace<BoundTypeVar>(singletonTypes->errorRecoveryType()); asMutable(c.resultType)->ty.emplace<BoundType>(builtinTypes->errorRecoveryType());
} }
return true; return true;
@ -598,14 +598,14 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
if (!force) if (!force)
{ {
// Logical expressions may proceed if the LHS is free. // Logical expressions may proceed if the LHS is free.
if (get<FreeTypeVar>(leftType) && !isLogical) if (get<FreeType>(leftType) && !isLogical)
return block(leftType, constraint); return block(leftType, constraint);
} }
// Logical expressions may proceed if the LHS is free. // Logical expressions may proceed if the LHS is free.
if (isBlocked(leftType) || (get<FreeTypeVar>(leftType) && !isLogical)) if (isBlocked(leftType) || (get<FreeType>(leftType) && !isLogical))
{ {
asMutable(resultType)->ty.emplace<BoundTypeVar>(errorRecoveryType()); asMutable(resultType)->ty.emplace<BoundType>(errorRecoveryType());
unblock(resultType); unblock(resultType);
return true; return true;
} }
@ -615,10 +615,10 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
{ {
// Metatables are not the same. The metamethod will not be invoked. // Metatables are not the same. The metamethod will not be invoked.
if ((c.op == AstExprBinary::Op::CompareEq || c.op == AstExprBinary::Op::CompareNe) && if ((c.op == AstExprBinary::Op::CompareEq || c.op == AstExprBinary::Op::CompareNe) &&
getMetatable(leftType, singletonTypes) != getMetatable(rightType, singletonTypes)) getMetatable(leftType, builtinTypes) != getMetatable(rightType, builtinTypes))
{ {
// TODO: Boolean singleton false? The result is _always_ boolean false. // TODO: Boolean singleton false? The result is _always_ boolean false.
asMutable(resultType)->ty.emplace<BoundTypeVar>(singletonTypes->booleanType); asMutable(resultType)->ty.emplace<BoundType>(builtinTypes->booleanType);
unblock(resultType); unblock(resultType);
return true; return true;
} }
@ -627,9 +627,9 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
// The LHS metatable takes priority over the RHS metatable, where // The LHS metatable takes priority over the RHS metatable, where
// present. // present.
if (std::optional<TypeId> leftMm = findMetatableEntry(singletonTypes, errors, leftType, it->second, constraint->location)) if (std::optional<TypeId> leftMm = findMetatableEntry(builtinTypes, errors, leftType, it->second, constraint->location))
mm = leftMm; mm = leftMm;
else if (std::optional<TypeId> rightMm = findMetatableEntry(singletonTypes, errors, rightType, it->second, constraint->location)) else if (std::optional<TypeId> rightMm = findMetatableEntry(builtinTypes, errors, rightType, it->second, constraint->location))
mm = rightMm; mm = rightMm;
if (mm) if (mm)
@ -644,7 +644,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
// TODO: Is a table with __call legal here? // TODO: Is a table with __call legal here?
// TODO: Overloads // TODO: Overloads
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(*instantiatedMm))) if (const FunctionType* ftv = get<FunctionType>(follow(*instantiatedMm)))
{ {
TypePackId inferredArgs; TypePackId inferredArgs;
// For >= and > we invoke __lt and __le respectively with // For >= and > we invoke __lt and __le respectively with
@ -672,13 +672,13 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
case AstExprBinary::Op::CompareGt: case AstExprBinary::Op::CompareGt:
case AstExprBinary::Op::CompareLe: case AstExprBinary::Op::CompareLe:
case AstExprBinary::Op::CompareLt: case AstExprBinary::Op::CompareLt:
mmResult = singletonTypes->booleanType; mmResult = builtinTypes->booleanType;
break; break;
default: default:
mmResult = first(ftv->retTypes).value_or(errorRecoveryType()); mmResult = first(ftv->retTypes).value_or(errorRecoveryType());
} }
asMutable(resultType)->ty.emplace<BoundTypeVar>(mmResult); asMutable(resultType)->ty.emplace<BoundType>(mmResult);
unblock(resultType); unblock(resultType);
(*c.astOriginalCallTypes)[c.expr] = *mm; (*c.astOriginalCallTypes)[c.expr] = *mm;
@ -691,8 +691,8 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
} }
// If any is present, the expression must evaluate to any as well. // If any is present, the expression must evaluate to any as well.
bool leftAny = get<AnyTypeVar>(leftType) || get<ErrorTypeVar>(leftType); bool leftAny = get<AnyType>(leftType) || get<ErrorType>(leftType);
bool rightAny = get<AnyTypeVar>(rightType) || get<ErrorTypeVar>(rightType); bool rightAny = get<AnyType>(rightType) || get<ErrorType>(rightType);
bool anyPresent = leftAny || rightAny; bool anyPresent = leftAny || rightAny;
switch (c.op) switch (c.op)
@ -708,7 +708,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
if (isNumber(leftType)) if (isNumber(leftType))
{ {
unify(leftType, rightType, constraint->scope); unify(leftType, rightType, constraint->scope);
asMutable(resultType)->ty.emplace<BoundTypeVar>(anyPresent ? singletonTypes->anyType : leftType); asMutable(resultType)->ty.emplace<BoundType>(anyPresent ? builtinTypes->anyType : leftType);
unblock(resultType); unblock(resultType);
return true; return true;
} }
@ -720,7 +720,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
if (isString(leftType)) if (isString(leftType))
{ {
unify(leftType, rightType, constraint->scope); unify(leftType, rightType, constraint->scope);
asMutable(resultType)->ty.emplace<BoundTypeVar>(anyPresent ? singletonTypes->anyType : leftType); asMutable(resultType)->ty.emplace<BoundType>(anyPresent ? builtinTypes->anyType : leftType);
unblock(resultType); unblock(resultType);
return true; return true;
} }
@ -734,7 +734,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
case AstExprBinary::Op::CompareLt: case AstExprBinary::Op::CompareLt:
if ((isNumber(leftType) && isNumber(rightType)) || (isString(leftType) && isString(rightType))) if ((isNumber(leftType) && isNumber(rightType)) || (isString(leftType) && isString(rightType)))
{ {
asMutable(resultType)->ty.emplace<BoundTypeVar>(singletonTypes->booleanType); asMutable(resultType)->ty.emplace<BoundType>(builtinTypes->booleanType);
unblock(resultType); unblock(resultType);
return true; return true;
} }
@ -744,16 +744,16 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
// on their parameters. // on their parameters.
case AstExprBinary::Op::CompareEq: case AstExprBinary::Op::CompareEq:
case AstExprBinary::Op::CompareNe: case AstExprBinary::Op::CompareNe:
asMutable(resultType)->ty.emplace<BoundTypeVar>(singletonTypes->booleanType); asMutable(resultType)->ty.emplace<BoundType>(builtinTypes->booleanType);
unblock(resultType); unblock(resultType);
return true; return true;
// And evalutes to a boolean if the LHS is falsey, and the RHS type if LHS is // And evalutes to a boolean if the LHS is falsey, and the RHS type if LHS is
// truthy. // truthy.
case AstExprBinary::Op::And: case AstExprBinary::Op::And:
{ {
TypeId leftFilteredTy = arena->addType(IntersectionTypeVar{{singletonTypes->falsyType, leftType}}); TypeId leftFilteredTy = arena->addType(IntersectionType{{builtinTypes->falsyType, leftType}});
asMutable(resultType)->ty.emplace<BoundTypeVar>(arena->addType(UnionTypeVar{{leftFilteredTy, rightType}})); asMutable(resultType)->ty.emplace<BoundType>(arena->addType(UnionType{{leftFilteredTy, rightType}}));
unblock(resultType); unblock(resultType);
return true; return true;
} }
@ -761,9 +761,9 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
// LHS is falsey. // LHS is falsey.
case AstExprBinary::Op::Or: case AstExprBinary::Op::Or:
{ {
TypeId leftFilteredTy = arena->addType(IntersectionTypeVar{{singletonTypes->truthyType, leftType}}); TypeId leftFilteredTy = arena->addType(IntersectionType{{builtinTypes->truthyType, leftType}});
asMutable(resultType)->ty.emplace<BoundTypeVar>(arena->addType(UnionTypeVar{{leftFilteredTy, rightType}})); asMutable(resultType)->ty.emplace<BoundType>(arena->addType(UnionType{{leftFilteredTy, rightType}}));
unblock(resultType); unblock(resultType);
return true; return true;
} }
@ -775,7 +775,7 @@ bool ConstraintSolver::tryDispatch(const BinaryConstraint& c, NotNull<const Cons
// We failed to either evaluate a metamethod or invoke primitive behavior. // We failed to either evaluate a metamethod or invoke primitive behavior.
unify(leftType, errorRecoveryType(), constraint->scope); unify(leftType, errorRecoveryType(), constraint->scope);
unify(rightType, errorRecoveryType(), constraint->scope); unify(rightType, errorRecoveryType(), constraint->scope);
asMutable(resultType)->ty.emplace<BoundTypeVar>(errorRecoveryType()); asMutable(resultType)->ty.emplace<BoundType>(errorRecoveryType());
unblock(resultType); unblock(resultType);
return true; return true;
@ -840,7 +840,7 @@ bool ConstraintSolver::tryDispatch(const IterableConstraint& c, NotNull<const Co
if (0 == iteratorTypes.size()) if (0 == iteratorTypes.size())
{ {
Anyification anyify{arena, constraint->scope, singletonTypes, &iceReporter, errorRecoveryType(), errorRecoveryTypePack()}; Anyification anyify{arena, constraint->scope, builtinTypes, &iceReporter, errorRecoveryType(), errorRecoveryTypePack()};
std::optional<TypePackId> anyified = anyify.substitute(c.variables); std::optional<TypePackId> anyified = anyify.substitute(c.variables);
LUAU_ASSERT(anyified); LUAU_ASSERT(anyified);
unify(*anyified, c.variables, constraint->scope); unify(*anyified, c.variables, constraint->scope);
@ -849,16 +849,16 @@ bool ConstraintSolver::tryDispatch(const IterableConstraint& c, NotNull<const Co
} }
TypeId nextTy = follow(iteratorTypes[0]); TypeId nextTy = follow(iteratorTypes[0]);
if (get<FreeTypeVar>(nextTy)) if (get<FreeType>(nextTy))
return block_(nextTy); return block_(nextTy);
if (get<FunctionTypeVar>(nextTy)) if (get<FunctionType>(nextTy))
{ {
TypeId tableTy = singletonTypes->nilType; TypeId tableTy = builtinTypes->nilType;
if (iteratorTypes.size() >= 2) if (iteratorTypes.size() >= 2)
tableTy = iteratorTypes[1]; tableTy = iteratorTypes[1];
TypeId firstIndexTy = singletonTypes->nilType; TypeId firstIndexTy = builtinTypes->nilType;
if (iteratorTypes.size() >= 3) if (iteratorTypes.size() >= 3)
firstIndexTy = iteratorTypes[2]; firstIndexTy = iteratorTypes[2];
@ -881,11 +881,11 @@ bool ConstraintSolver::tryDispatch(const NameConstraint& c, NotNull<const Constr
if (target->persistent || target->owningArena != arena) if (target->persistent || target->owningArena != arena)
return true; return true;
if (TableTypeVar* ttv = getMutable<TableTypeVar>(target)) if (TableType* ttv = getMutable<TableType>(target))
ttv->name = c.name; ttv->name = c.name;
else if (MetatableTypeVar* mtv = getMutable<MetatableTypeVar>(target)) else if (MetatableType* mtv = getMutable<MetatableType>(target))
mtv->syntheticName = c.name; mtv->syntheticName = c.name;
else if (get<IntersectionTypeVar>(target) || get<UnionTypeVar>(target)) else if (get<IntersectionType>(target) || get<UnionType>(target))
{ {
// nothing (yet) // nothing (yet)
} }
@ -895,7 +895,7 @@ bool ConstraintSolver::tryDispatch(const NameConstraint& c, NotNull<const Constr
return true; return true;
} }
struct InfiniteTypeFinder : TypeVarOnceVisitor struct InfiniteTypeFinder : TypeOnceVisitor
{ {
ConstraintSolver* solver; ConstraintSolver* solver;
const InstantiationSignature& signature; const InstantiationSignature& signature;
@ -909,7 +909,7 @@ struct InfiniteTypeFinder : TypeVarOnceVisitor
{ {
} }
bool visit(TypeId ty, const PendingExpansionTypeVar& petv) override bool visit(TypeId ty, const PendingExpansionType& petv) override
{ {
std::optional<TypeFun> tf = std::optional<TypeFun> tf =
(petv.prefix) ? scope->lookupImportedType(petv.prefix->value, petv.name.value) : scope->lookupType(petv.name.value); (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()) if (!tf.has_value())
return true; 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)) 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; ConstraintSolver* solver;
const InstantiationSignature& signature; 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}); solver->pushConstraint(scope, location, TypeAliasExpansionConstraint{ty});
return false; return false;
@ -953,7 +953,7 @@ struct InstantiationQueuer : TypeVarOnceVisitor
bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNull<const Constraint> constraint) bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNull<const Constraint> constraint)
{ {
const PendingExpansionTypeVar* petv = get<PendingExpansionTypeVar>(follow(c.target)); const PendingExpansionType* petv = get<PendingExpansionType>(follow(c.target));
if (!petv) if (!petv)
{ {
unblock(c.target); unblock(c.target);
@ -961,7 +961,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
} }
auto bindResult = [this, &c](TypeId result) { auto bindResult = [this, &c](TypeId result) {
asMutable(c.target)->ty.emplace<BoundTypeVar>(result); asMutable(c.target)->ty.emplace<BoundType>(result);
unblock(c.target); unblock(c.target);
}; };
@ -983,7 +983,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
return true; 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) { bool sameTypes = std::equal(typeArguments.begin(), typeArguments.end(), tf->typeParams.begin(), tf->typeParams.end(), [](auto&& itp, auto&& p) {
return itp == p.ty; return itp == p.ty;
@ -1067,7 +1067,7 @@ bool ConstraintSolver::tryDispatch(const TypeAliasExpansionConstraint& c, NotNul
// there are e.g. generic saturatedTypeArguments that go unused. // there are e.g. generic saturatedTypeArguments that go unused.
bool needsClone = follow(tf->type) == target; bool needsClone = follow(tf->type) == target;
// Only tables have the properties we're trying to set. // Only tables have the properties we're trying to set.
TableTypeVar* ttv = getMutableTableType(target); TableType* ttv = getMutableTableType(target);
if (ttv) 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 // explicitly clone that table as well. If we don't, we will
// mutate another module's type surface and cause a // mutate another module's type surface and cause a
// use-after-free. // use-after-free.
if (get<MetatableTypeVar>(target)) if (get<MetatableType>(target))
{ {
instantiated = applyTypeFunction.clone(target); instantiated = applyTypeFunction.clone(target);
MetatableTypeVar* mtv = getMutable<MetatableTypeVar>(instantiated); MetatableType* mtv = getMutable<MetatableType>(instantiated);
mtv->table = applyTypeFunction.clone(mtv->table); mtv->table = applyTypeFunction.clone(mtv->table);
ttv = getMutable<TableTypeVar>(mtv->table); ttv = getMutable<TableType>(mtv->table);
} }
else if (get<TableTypeVar>(target)) else if (get<TableType>(target))
{ {
instantiated = applyTypeFunction.clone(target); instantiated = applyTypeFunction.clone(target);
ttv = getMutable<TableTypeVar>(instantiated); ttv = getMutable<TableType>(instantiated);
} }
target = follow(instantiated); target = follow(instantiated);
@ -1123,16 +1123,15 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
} }
// We don't support magic __call metamethods. // We don't support magic __call metamethods.
if (std::optional<TypeId> callMm = findMetatableEntry(singletonTypes, errors, fn, "__call", constraint->location)) if (std::optional<TypeId> callMm = findMetatableEntry(builtinTypes, errors, fn, "__call", constraint->location))
{ {
std::vector<TypeId> args{fn}; std::vector<TypeId> args{fn};
for (TypeId arg : c.argsPack) for (TypeId arg : c.argsPack)
args.push_back(arg); args.push_back(arg);
TypeId instantiatedType = arena->addType(BlockedTypeVar{}); TypeId instantiatedType = arena->addType(BlockedType{});
TypeId inferredFnType = TypeId inferredFnType = arena->addType(FunctionType(TypeLevel{}, constraint->scope.get(), arena->addTypePack(TypePack{args, {}}), c.result));
arena->addType(FunctionTypeVar(TypeLevel{}, constraint->scope.get(), arena->addTypePack(TypePack{args, {}}), c.result));
// Alter the inner constraints. // Alter the inner constraints.
LUAU_ASSERT(c.innerConstraints.size() == 2); LUAU_ASSERT(c.innerConstraints.size() == 2);
@ -1158,7 +1157,7 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
return true; return true;
} }
const FunctionTypeVar* ftv = get<FunctionTypeVar>(fn); const FunctionType* ftv = get<FunctionType>(fn);
bool usedMagic = false; bool usedMagic = false;
if (ftv && ftv->dcrMagicFunction != nullptr) if (ftv && ftv->dcrMagicFunction != nullptr)
@ -1203,11 +1202,11 @@ bool ConstraintSolver::tryDispatch(const FunctionCallConstraint& c, NotNull<cons
bool ConstraintSolver::tryDispatch(const PrimitiveTypeConstraint& c, NotNull<const Constraint> constraint) bool ConstraintSolver::tryDispatch(const PrimitiveTypeConstraint& c, NotNull<const Constraint> constraint)
{ {
TypeId expectedType = follow(c.expectedType); TypeId expectedType = follow(c.expectedType);
if (isBlocked(expectedType) || get<PendingExpansionTypeVar>(expectedType)) if (isBlocked(expectedType) || get<PendingExpansionType>(expectedType))
return block(expectedType, constraint); return block(expectedType, constraint);
TypeId bindTo = maybeSingleton(expectedType) ? c.singletonType : c.multitonType; TypeId bindTo = maybeSingleton(expectedType) ? c.singletonType : c.multitonType;
asMutable(c.resultType)->ty.emplace<BoundTypeVar>(bindTo); asMutable(c.resultType)->ty.emplace<BoundType>(bindTo);
return true; return true;
} }
@ -1216,14 +1215,14 @@ bool ConstraintSolver::tryDispatch(const HasPropConstraint& c, NotNull<const Con
{ {
TypeId subjectType = follow(c.subjectType); TypeId subjectType = follow(c.subjectType);
if (isBlocked(subjectType) || get<PendingExpansionTypeVar>(subjectType)) if (isBlocked(subjectType) || get<PendingExpansionType>(subjectType))
return block(subjectType, constraint); return block(subjectType, constraint);
if (get<FreeTypeVar>(subjectType)) if (get<FreeType>(subjectType))
{ {
TableTypeVar& ttv = asMutable(subjectType)->ty.emplace<TableTypeVar>(TableState::Free, TypeLevel{}, constraint->scope); TableType& ttv = asMutable(subjectType)->ty.emplace<TableType>(TableState::Free, TypeLevel{}, constraint->scope);
ttv.props[c.prop] = Property{c.resultType}; ttv.props[c.prop] = Property{c.resultType};
asMutable(c.resultType)->ty.emplace<FreeTypeVar>(constraint->scope); asMutable(c.resultType)->ty.emplace<FreeType>(constraint->scope);
unblock(c.resultType); unblock(c.resultType);
return true; return true;
} }
@ -1231,7 +1230,7 @@ bool ConstraintSolver::tryDispatch(const HasPropConstraint& c, NotNull<const Con
std::optional<TypeId> resultType = lookupTableProp(subjectType, c.prop); std::optional<TypeId> resultType = lookupTableProp(subjectType, c.prop);
if (!resultType) if (!resultType)
{ {
asMutable(c.resultType)->ty.emplace<BoundTypeVar>(singletonTypes->errorRecoveryType()); asMutable(c.resultType)->ty.emplace<BoundType>(builtinTypes->errorRecoveryType());
unblock(c.resultType); unblock(c.resultType);
return true; return true;
} }
@ -1242,14 +1241,14 @@ bool ConstraintSolver::tryDispatch(const HasPropConstraint& c, NotNull<const Con
return false; return false;
} }
asMutable(c.resultType)->ty.emplace<BoundTypeVar>(*resultType); asMutable(c.resultType)->ty.emplace<BoundType>(*resultType);
return true; return true;
} }
static bool isUnsealedTable(TypeId ty) static bool isUnsealedTable(TypeId ty)
{ {
ty = follow(ty); ty = follow(ty);
const TableTypeVar* ttv = get<TableTypeVar>(ty); const TableType* ttv = get<TableType>(ty);
return ttv && ttv->state == TableState::Unsealed; return ttv && ttv->state == TableState::Unsealed;
} }
@ -1278,7 +1277,7 @@ static std::optional<TypeId> updateTheTableType(NotNull<TypeArena> arena, TypeId
if (!isUnsealedTable(t)) if (!isUnsealedTable(t))
return std::nullopt; return std::nullopt;
const TableTypeVar* tbl = get<TableTypeVar>(t); const TableType* tbl = get<TableType>(t);
auto it = tbl->props.find(path[i]); auto it = tbl->props.find(path[i]);
if (it == tbl->props.end()) if (it == tbl->props.end())
return std::nullopt; return std::nullopt;
@ -1291,7 +1290,7 @@ static std::optional<TypeId> updateTheTableType(NotNull<TypeArena> arena, TypeId
// new property to be appended. // new property to be appended.
if (!isUnsealedTable(t)) if (!isUnsealedTable(t))
return std::nullopt; return std::nullopt;
const TableTypeVar* tbl = get<TableTypeVar>(t); const TableType* tbl = get<TableType>(t);
if (0 != tbl->props.count(path.back())) if (0 != tbl->props.count(path.back()))
return std::nullopt; return std::nullopt;
} }
@ -1303,7 +1302,7 @@ static std::optional<TypeId> updateTheTableType(NotNull<TypeArena> arena, TypeId
{ {
const std::string segment = path[i]; const std::string segment = path[i];
TableTypeVar* ttv = getMutable<TableTypeVar>(t); TableType* ttv = getMutable<TableType>(t);
LUAU_ASSERT(ttv); LUAU_ASSERT(ttv);
auto propIt = ttv->props.find(segment); auto propIt = ttv->props.find(segment);
@ -1317,7 +1316,7 @@ static std::optional<TypeId> updateTheTableType(NotNull<TypeArena> arena, TypeId
return std::nullopt; return std::nullopt;
} }
TableTypeVar* ttv = getMutable<TableTypeVar>(t); TableType* ttv = getMutable<TableType>(t);
LUAU_ASSERT(ttv); LUAU_ASSERT(ttv);
const std::string lastSegment = path.back(); const std::string lastSegment = path.back();
@ -1350,7 +1349,7 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Con
} }
auto bind = [](TypeId a, TypeId b) { auto bind = [](TypeId a, TypeId b) {
asMutable(a)->ty.emplace<BoundTypeVar>(b); asMutable(a)->ty.emplace<BoundType>(b);
}; };
if (existingPropType) if (existingPropType)
@ -1360,14 +1359,14 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Con
return true; return true;
} }
if (get<FreeTypeVar>(subjectType)) if (get<FreeType>(subjectType))
{ {
TypeId ty = arena->freshType(constraint->scope); TypeId ty = arena->freshType(constraint->scope);
// Mint a chain of free tables per c.path // Mint a chain of free tables per c.path
for (auto it = rbegin(c.path); it != rend(c.path); ++it) 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}; t.props[*it] = {ty};
ty = arena->addType(std::move(t)); ty = arena->addType(std::move(t));
@ -1379,7 +1378,7 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Con
bind(c.resultType, ty); bind(c.resultType, ty);
return true; return true;
} }
else if (auto ttv = getMutable<TableTypeVar>(subjectType)) else if (auto ttv = getMutable<TableType>(subjectType))
{ {
if (ttv->state == TableState::Free) if (ttv->state == TableState::Free)
{ {
@ -1399,7 +1398,7 @@ bool ConstraintSolver::tryDispatch(const SetPropConstraint& c, NotNull<const Con
return true; return true;
} }
} }
else if (get<AnyTypeVar>(subjectType) || get<ErrorTypeVar>(subjectType)) else if (get<AnyType>(subjectType) || get<ErrorType>(subjectType))
{ {
bind(c.resultType, subjectType); bind(c.resultType, subjectType);
return true; return true;
@ -1417,12 +1416,12 @@ bool ConstraintSolver::tryDispatch(const SingletonOrTopTypeConstraint& c, NotNul
TypeId followed = follow(c.discriminantType); TypeId followed = follow(c.discriminantType);
// `nil` is a singleton type too! There's only one value of type `nil`. // `nil` is a singleton type too! There's only one value of type `nil`.
if (c.negated && (get<SingletonTypeVar>(followed) || isNil(followed))) if (c.negated && (get<SingletonType>(followed) || isNil(followed)))
*asMutable(c.resultType) = NegationTypeVar{c.discriminantType}; *asMutable(c.resultType) = NegationType{c.discriminantType};
else if (!c.negated && get<SingletonTypeVar>(followed)) else if (!c.negated && get<SingletonType>(followed))
*asMutable(c.resultType) = BoundTypeVar{c.discriminantType}; *asMutable(c.resultType) = BoundType{c.discriminantType};
else else
*asMutable(c.resultType) = BoundTypeVar{singletonTypes->unknownType}; *asMutable(c.resultType) = BoundType{builtinTypes->unknownType};
return true; 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, // 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. // if it's a free table, if we don't know it has a metatable, and so on.
iteratorTy = follow(iteratorTy); iteratorTy = follow(iteratorTy);
if (get<FreeTypeVar>(iteratorTy)) if (get<FreeType>(iteratorTy))
return block_(iteratorTy); return block_(iteratorTy);
auto anyify = [&](auto ty) { 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); std::optional anyified = anyify.substitute(ty);
if (!anyified) if (!anyified)
reportError(CodeTooComplex{}, constraint->location); reportError(CodeTooComplex{}, constraint->location);
@ -1458,7 +1457,7 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl
}; };
auto errorify = [&](auto ty) { 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); std::optional errorified = anyify.substitute(ty);
if (!errorified) if (!errorified)
reportError(CodeTooComplex{}, constraint->location); reportError(CodeTooComplex{}, constraint->location);
@ -1466,13 +1465,13 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl
unify(*errorified, ty, constraint->scope); unify(*errorified, ty, constraint->scope);
}; };
if (get<AnyTypeVar>(iteratorTy)) if (get<AnyType>(iteratorTy))
{ {
anyify(c.variables); anyify(c.variables);
return true; return true;
} }
if (get<ErrorTypeVar>(iteratorTy)) if (get<ErrorType>(iteratorTy))
{ {
errorify(c.variables); errorify(c.variables);
return true; 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 // Irksome: I don't think we have any way to guarantee that this table
// type never has a metatable. // type never has a metatable.
if (auto iteratorTable = get<TableTypeVar>(iteratorTy)) if (auto iteratorTable = get<TableType>(iteratorTy))
{ {
if (iteratorTable->state == TableState::Free) if (iteratorTable->state == TableState::Free)
return block_(iteratorTy); return block_(iteratorTy);
@ -1494,7 +1493,7 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl
else else
errorify(c.variables); errorify(c.variables);
} }
else if (std::optional<TypeId> iterFn = findMetatableEntry(singletonTypes, errors, iteratorTy, "__iter", Location{})) else if (std::optional<TypeId> iterFn = findMetatableEntry(builtinTypes, errors, iteratorTy, "__iter", Location{}))
{ {
if (isBlocked(*iterFn)) if (isBlocked(*iterFn))
{ {
@ -1505,12 +1504,12 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl
if (std::optional<TypeId> instantiatedIterFn = instantiation.substitute(*iterFn)) if (std::optional<TypeId> instantiatedIterFn = instantiation.substitute(*iterFn))
{ {
if (auto iterFtv = get<FunctionTypeVar>(*instantiatedIterFn)) if (auto iterFtv = get<FunctionType>(*instantiatedIterFn))
{ {
TypePackId expectedIterArgs = arena->addTypePack({iteratorTy}); TypePackId expectedIterArgs = arena->addTypePack({iteratorTy});
unify(iterFtv->argTypes, expectedIterArgs, constraint->scope); 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) if (iterRets.head.size() < 1)
{ {
@ -1527,11 +1526,11 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl
const TypeId firstIndex = arena->freshType(constraint->scope); const TypeId firstIndex = arena->freshType(constraint->scope);
// nextTy : (iteratorTy, indexTy?) -> (indexTy, valueTailTy...) // 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 valueTailTy = arena->addTypePack(FreeTypePack{constraint->scope});
const TypePackId nextRetPack = arena->addTypePack(TypePack{{firstIndex}, valueTailTy}); 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); unify(*instantiatedNextFn, expectedNextTy, constraint->scope);
pushConstraint(constraint->scope, constraint->location, PackSubtypeConstraint{c.variables, nextRetPack}); pushConstraint(constraint->scope, constraint->location, PackSubtypeConstraint{c.variables, nextRetPack});
@ -1551,10 +1550,10 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl
reportError(UnificationTooComplex{}, constraint->location); reportError(UnificationTooComplex{}, constraint->location);
} }
} }
else if (auto iteratorMetatable = get<MetatableTypeVar>(iteratorTy)) else if (auto iteratorMetatable = get<MetatableType>(iteratorTy))
{ {
TypeId metaTy = follow(iteratorMetatable->metatable); TypeId metaTy = follow(iteratorMetatable->metatable);
if (get<FreeTypeVar>(metaTy)) if (get<FreeType>(metaTy))
return block_(metaTy); return block_(metaTy);
LUAU_ASSERT(false); LUAU_ASSERT(false);
@ -1571,7 +1570,7 @@ bool ConstraintSolver::tryDispatchIterableFunction(
// We need to know whether or not this type is nil or not. // We need to know whether or not this type is nil or not.
// If we don't know, block and reschedule ourselves. // If we don't know, block and reschedule ourselves.
firstIndexTy = follow(firstIndexTy); firstIndexTy = follow(firstIndexTy);
if (get<FreeTypeVar>(firstIndexTy)) if (get<FreeType>(firstIndexTy))
{ {
if (force) if (force)
LUAU_ASSERT(false); LUAU_ASSERT(false);
@ -1584,11 +1583,11 @@ bool ConstraintSolver::tryDispatchIterableFunction(
: firstIndexTy; : firstIndexTy;
// nextTy : (tableTy, indexTy?) -> (indexTy, valueTailTy...) // 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 valueTailTy = arena->addTypePack(FreeTypePack{constraint->scope});
const TypePackId nextRetPack = arena->addTypePack(TypePack{{firstIndex}, valueTailTy}); 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); unify(nextTy, expectedNextTy, constraint->scope);
pushConstraint(constraint->scope, constraint->location, PackSubtypeConstraint{c.variables, nextRetPack}); pushConstraint(constraint->scope, constraint->location, PackSubtypeConstraint{c.variables, nextRetPack});
@ -1605,9 +1604,9 @@ std::optional<TypeId> ConstraintSolver::lookupTableProp(TypeId subjectType, cons
for (TypeId expectedPart : unionOrIntersection) for (TypeId expectedPart : unionOrIntersection)
{ {
expectedPart = follow(expectedPart); expectedPart = follow(expectedPart);
if (isBlocked(expectedPart) || get<PendingExpansionTypeVar>(expectedPart)) if (isBlocked(expectedPart) || get<PendingExpansionType>(expectedPart))
blocked = expectedPart; blocked = expectedPart;
else if (const TableTypeVar* ttv = get<TableTypeVar>(follow(expectedPart))) else if (const TableType* ttv = get<TableType>(follow(expectedPart)))
{ {
if (auto prop = ttv->props.find(propName); prop != ttv->props.end()) if (auto prop = ttv->props.find(propName); prop != ttv->props.end())
parts.push_back(prop->second.type); parts.push_back(prop->second.type);
@ -1621,14 +1620,14 @@ std::optional<TypeId> ConstraintSolver::lookupTableProp(TypeId subjectType, cons
std::optional<TypeId> resultType; std::optional<TypeId> resultType;
if (auto ttv = get<TableTypeVar>(subjectType)) if (auto ttv = get<TableType>(subjectType))
{ {
if (auto prop = ttv->props.find(propName); prop != ttv->props.end()) if (auto prop = ttv->props.find(propName); prop != ttv->props.end())
resultType = prop->second.type; resultType = prop->second.type;
else if (ttv->indexer && maybeString(ttv->indexer->indexType)) else if (ttv->indexer && maybeString(ttv->indexer->indexType))
resultType = ttv->indexer->indexResultType; resultType = ttv->indexer->indexResultType;
} }
else if (auto utv = get<UnionTypeVar>(subjectType)) else if (auto utv = get<UnionType>(subjectType))
{ {
auto [blocked, parts] = collectParts(utv); auto [blocked, parts] = collectParts(utv);
@ -1637,11 +1636,11 @@ std::optional<TypeId> ConstraintSolver::lookupTableProp(TypeId subjectType, cons
else if (parts.size() == 1) else if (parts.size() == 1)
resultType = parts[0]; resultType = parts[0];
else if (parts.size() > 1) else if (parts.size() > 1)
resultType = arena->addType(UnionTypeVar{std::move(parts)}); resultType = arena->addType(UnionType{std::move(parts)});
else else
LUAU_ASSERT(false); // parts.size() == 0 LUAU_ASSERT(false); // parts.size() == 0
} }
else if (auto itv = get<IntersectionTypeVar>(subjectType)) else if (auto itv = get<IntersectionType>(subjectType))
{ {
auto [blocked, parts] = collectParts(itv); auto [blocked, parts] = collectParts(itv);
@ -1650,7 +1649,7 @@ std::optional<TypeId> ConstraintSolver::lookupTableProp(TypeId subjectType, cons
else if (parts.size() == 1) else if (parts.size() == 1)
resultType = parts[0]; resultType = parts[0];
else if (parts.size() > 1) else if (parts.size() > 1)
resultType = arena->addType(IntersectionTypeVar{std::move(parts)}); resultType = arena->addType(IntersectionType{std::move(parts)});
else else
LUAU_ASSERT(false); // parts.size() == 0 LUAU_ASSERT(false); // parts.size() == 0
} }
@ -1701,7 +1700,7 @@ bool ConstraintSolver::block(TypePackId target, NotNull<const Constraint> constr
return false; return false;
} }
struct Blocker : TypeVarOnceVisitor struct Blocker : TypeOnceVisitor
{ {
NotNull<ConstraintSolver> solver; NotNull<ConstraintSolver> solver;
NotNull<const Constraint> constraint; NotNull<const Constraint> constraint;
@ -1714,14 +1713,14 @@ struct Blocker : TypeVarOnceVisitor
{ {
} }
bool visit(TypeId ty, const BlockedTypeVar&) bool visit(TypeId ty, const BlockedType&)
{ {
blocked = true; blocked = true;
solver->block(ty, constraint); solver->block(ty, constraint);
return false; return false;
} }
bool visit(TypeId ty, const PendingExpansionTypeVar&) bool visit(TypeId ty, const PendingExpansionType&)
{ {
blocked = true; blocked = true;
solver->block(ty, constraint); solver->block(ty, constraint);
@ -1805,7 +1804,7 @@ void ConstraintSolver::unblock(const std::vector<TypePackId>& packs)
bool ConstraintSolver::isBlocked(TypeId ty) bool ConstraintSolver::isBlocked(TypeId ty)
{ {
return nullptr != get<BlockedTypeVar>(follow(ty)) || nullptr != get<PendingExpansionTypeVar>(follow(ty)); return nullptr != get<BlockedType>(follow(ty)) || nullptr != get<PendingExpansionType>(follow(ty));
} }
bool ConstraintSolver::isBlocked(TypePackId tp) bool ConstraintSolver::isBlocked(TypePackId tp)
@ -1878,7 +1877,7 @@ TypeId ConstraintSolver::resolveModule(const ModuleInfo& info, const Location& l
for (const auto& [location, path] : requireCycles) for (const auto& [location, path] : requireCycles)
{ {
if (!path.empty() && path.front() == humanReadableName) if (!path.empty() && path.front() == humanReadableName)
return singletonTypes->anyType; return builtinTypes->anyType;
} }
ModulePtr module = moduleResolver->getModule(info.name); ModulePtr module = moduleResolver->getModule(info.name);
@ -1924,12 +1923,12 @@ void ConstraintSolver::reportError(TypeError e)
TypeId ConstraintSolver::errorRecoveryType() const TypeId ConstraintSolver::errorRecoveryType() const
{ {
return singletonTypes->errorRecoveryType(); return builtinTypes->errorRecoveryType();
} }
TypePackId ConstraintSolver::errorRecoveryTypePack() const TypePackId ConstraintSolver::errorRecoveryTypePack() const
{ {
return singletonTypes->errorRecoveryTypePack(); return builtinTypes->errorRecoveryTypePack();
} }
TypeId ConstraintSolver::unionOfTypes(TypeId a, TypeId b, NotNull<Scope> scope, bool unifyFreeTypes) TypeId ConstraintSolver::unionOfTypes(TypeId a, TypeId b, NotNull<Scope> scope, bool unifyFreeTypes)
@ -1937,7 +1936,7 @@ TypeId ConstraintSolver::unionOfTypes(TypeId a, TypeId b, NotNull<Scope> scope,
a = follow(a); a = follow(a);
b = follow(b); b = follow(b);
if (unifyFreeTypes && (get<FreeTypeVar>(a) || get<FreeTypeVar>(b))) if (unifyFreeTypes && (get<FreeType>(a) || get<FreeType>(b)))
{ {
Unifier u{normalizer, Mode::Strict, scope, Location{}, Covariant}; Unifier u{normalizer, Mode::Strict, scope, Location{}, Covariant};
u.useScopes = true; u.useScopes = true;
@ -1950,7 +1949,7 @@ TypeId ConstraintSolver::unionOfTypes(TypeId a, TypeId b, NotNull<Scope> scope,
} }
else else
{ {
return singletonTypes->errorRecoveryType(singletonTypes->anyType); return builtinTypes->errorRecoveryType(builtinTypes->anyType);
} }
} }
@ -1959,12 +1958,12 @@ TypeId ConstraintSolver::unionOfTypes(TypeId a, TypeId b, NotNull<Scope> scope,
std::vector<TypeId> types = reduceUnion({a, b}); std::vector<TypeId> types = reduceUnion({a, b});
if (types.empty()) if (types.empty())
return singletonTypes->neverType; return builtinTypes->neverType;
if (types.size() == 1) if (types.size() == 1)
return types[0]; return types[0];
return arena->addType(UnionTypeVar{types}); return arena->addType(UnionType{types});
} }
} // namespace Luau } // namespace Luau

View file

@ -131,9 +131,9 @@ struct ErrorConverter
std::string operator()(const Luau::UnknownProperty& e) const std::string operator()(const Luau::UnknownProperty& e) const
{ {
TypeId t = follow(e.table); TypeId t = follow(e.table);
if (get<TableTypeVar>(t)) if (get<TableType>(t))
return "Key '" + e.key + "' not found in table '" + Luau::toString(t) + "'"; return "Key '" + e.key + "' not found in table '" + Luau::toString(t) + "'";
else if (get<ClassTypeVar>(t)) else if (get<ClassType>(t))
return "Key '" + e.key + "' not found in class '" + Luau::toString(t) + "'"; return "Key '" + e.key + "' not found in class '" + Luau::toString(t) + "'";
else else
return "Type '" + Luau::toString(e.table) + "' does not have key '" + e.key + "'"; 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 "; std::string s = "Key '" + e.key + "' not found in ";
TypeId t = follow(e.table); TypeId t = follow(e.table);
if (get<ClassTypeVar>(t)) if (get<ClassType>(t))
s += "class"; s += "class";
else else
s += "table"; s += "table";
@ -952,7 +952,7 @@ void copyErrors(ErrorVec& errors, TypeArena& destArena)
copyError(e, destArena, cloneState); copyError(e, destArena, cloneState);
}; };
LUAU_ASSERT(!destArena.typeVars.isFrozen()); LUAU_ASSERT(!destArena.types.isFrozen());
LUAU_ASSERT(!destArena.typePacks.isFrozen()); LUAU_ASSERT(!destArena.typePacks.isFrozen());
for (TypeError& error : errors) for (TypeError& error : errors)

View file

@ -65,14 +65,14 @@ static void generateDocumentationSymbols(TypeId ty, const std::string& rootName)
asMutable(ty)->documentationSymbol = rootName; asMutable(ty)->documentationSymbol = rootName;
if (TableTypeVar* ttv = getMutable<TableTypeVar>(ty)) if (TableType* ttv = getMutable<TableType>(ty))
{ {
for (auto& [name, prop] : ttv->props) for (auto& [name, prop] : ttv->props)
{ {
prop.documentationSymbol = rootName + "." + name; prop.documentationSymbol = rootName + "." + name;
} }
} }
else if (ClassTypeVar* ctv = getMutable<ClassTypeVar>(ty)) else if (ClassType* ctv = getMutable<ClassType>(ty))
{ {
for (auto& [name, prop] : ctv->props) for (auto& [name, prop] : ctv->props)
{ {
@ -408,12 +408,12 @@ double getTimestamp()
} // namespace } // namespace
Frontend::Frontend(FileResolver* fileResolver, ConfigResolver* configResolver, const FrontendOptions& options) Frontend::Frontend(FileResolver* fileResolver, ConfigResolver* configResolver, const FrontendOptions& options)
: singletonTypes(NotNull{&singletonTypes_}) : builtinTypes(NotNull{&builtinTypes_})
, fileResolver(fileResolver) , fileResolver(fileResolver)
, moduleResolver(this) , moduleResolver(this)
, moduleResolverForAutocomplete(this) , moduleResolverForAutocomplete(this)
, typeChecker(&moduleResolver, singletonTypes, &iceHandler) , typeChecker(&moduleResolver, builtinTypes, &iceHandler)
, typeCheckerForAutocomplete(&moduleResolverForAutocomplete, singletonTypes, &iceHandler) , typeCheckerForAutocomplete(&moduleResolverForAutocomplete, builtinTypes, &iceHandler)
, configResolver(configResolver) , configResolver(configResolver)
, options(options) , options(options)
, globalScope(typeChecker.globalScope) , globalScope(typeChecker.globalScope)
@ -455,12 +455,7 @@ CheckResult Frontend::check(const ModuleName& name, std::optional<FrontendOption
} }
std::vector<ModuleName> buildQueue; std::vector<ModuleName> buildQueue;
bool cycleDetected = parseGraph(buildQueue, checkResult, name, frontendOptions.forAutocomplete); bool cycleDetected = parseGraph(buildQueue, name, frontendOptions.forAutocomplete);
// Keep track of which AST nodes we've reported cycles in
std::unordered_set<AstNode*> reportedCycles;
double autocompleteTimeLimit = FInt::LuauAutocompleteCheckTimeoutMs / 1000.0;
for (const ModuleName& moduleName : buildQueue) for (const ModuleName& moduleName : buildQueue)
{ {
@ -499,6 +494,8 @@ CheckResult Frontend::check(const ModuleName& name, std::optional<FrontendOption
// to provide better type information for IDE features // to provide better type information for IDE features
typeCheckerForAutocomplete.requireCycles = requireCycles; typeCheckerForAutocomplete.requireCycles = requireCycles;
double autocompleteTimeLimit = FInt::LuauAutocompleteCheckTimeoutMs / 1000.0;
if (autocompleteTimeLimit != 0.0) if (autocompleteTimeLimit != 0.0)
typeCheckerForAutocomplete.finishTime = TimeTrace::getClock() + autocompleteTimeLimit; typeCheckerForAutocomplete.finishTime = TimeTrace::getClock() + autocompleteTimeLimit;
else else
@ -599,7 +596,7 @@ CheckResult Frontend::check(const ModuleName& name, std::optional<FrontendOption
return checkResult; return checkResult;
} }
bool Frontend::parseGraph(std::vector<ModuleName>& buildQueue, CheckResult& checkResult, const ModuleName& root, bool forAutocomplete) bool Frontend::parseGraph(std::vector<ModuleName>& buildQueue, const ModuleName& root, bool forAutocomplete)
{ {
LUAU_TIMETRACE_SCOPE("Frontend::parseGraph", "Frontend"); LUAU_TIMETRACE_SCOPE("Frontend::parseGraph", "Frontend");
LUAU_TIMETRACE_ARGUMENT("root", root.c_str()); LUAU_TIMETRACE_ARGUMENT("root", root.c_str());
@ -618,7 +615,7 @@ bool Frontend::parseGraph(std::vector<ModuleName>& buildQueue, CheckResult& chec
bool cyclic = false; bool cyclic = false;
{ {
auto [sourceNode, _] = getSourceNode(checkResult, root); auto [sourceNode, _] = getSourceNode(root);
if (sourceNode) if (sourceNode)
stack.push_back(sourceNode); stack.push_back(sourceNode);
} }
@ -682,7 +679,7 @@ bool Frontend::parseGraph(std::vector<ModuleName>& buildQueue, CheckResult& chec
} }
} }
auto [sourceNode, _] = getSourceNode(checkResult, dep); auto [sourceNode, _] = getSourceNode(dep);
if (sourceNode) if (sourceNode)
{ {
stack.push_back(sourceNode); stack.push_back(sourceNode);
@ -729,8 +726,7 @@ LintResult Frontend::lint(const ModuleName& name, std::optional<Luau::LintOption
LUAU_TIMETRACE_SCOPE("Frontend::lint", "Frontend"); LUAU_TIMETRACE_SCOPE("Frontend::lint", "Frontend");
LUAU_TIMETRACE_ARGUMENT("name", name.c_str()); LUAU_TIMETRACE_ARGUMENT("name", name.c_str());
CheckResult checkResult; auto [_sourceNode, sourceModule] = getSourceNode(name);
auto [_sourceNode, sourceModule] = getSourceNode(checkResult, name);
if (!sourceModule) if (!sourceModule)
return LintResult{}; // FIXME: We really should do something a bit more obvious when a file is too broken to lint. return LintResult{}; // FIXME: We really should do something a bit more obvious when a file is too broken to lint.
@ -761,7 +757,7 @@ LintResult Frontend::lint(const SourceModule& module, std::optional<Luau::LintOp
options.disableWarning(Luau::LintWarning::Code_ImplicitReturn); options.disableWarning(Luau::LintWarning::Code_ImplicitReturn);
} }
ScopePtr environmentScope = getModuleEnvironment(module, config); ScopePtr environmentScope = getModuleEnvironment(module, config, /*forAutocomplete*/ false);
ModulePtr modulePtr = moduleResolver.getModule(module.name); ModulePtr modulePtr = moduleResolver.getModule(module.name);
@ -873,14 +869,14 @@ ModulePtr Frontend::check(
const NotNull<ModuleResolver> mr{forAutocomplete ? &moduleResolverForAutocomplete : &moduleResolver}; const NotNull<ModuleResolver> mr{forAutocomplete ? &moduleResolverForAutocomplete : &moduleResolver};
const ScopePtr& globalScope{forAutocomplete ? typeCheckerForAutocomplete.globalScope : typeChecker.globalScope}; 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{ ConstraintGraphBuilder cgb{
sourceModule.name, sourceModule.name,
result, result,
&result->internalTypes, &result->internalTypes,
mr, mr,
singletonTypes, builtinTypes,
NotNull(&iceHandler), NotNull(&iceHandler),
globalScope, globalScope,
logger.get(), logger.get(),
@ -910,7 +906,12 @@ ModulePtr Frontend::check(
result->astResolvedTypePacks = std::move(cgb.astResolvedTypePacks); result->astResolvedTypePacks = std::move(cgb.astResolvedTypePacks);
result->type = sourceModule.type; 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) if (FFlag::DebugLuauLogSolverToJson)
{ {
@ -918,13 +919,11 @@ ModulePtr Frontend::check(
printf("%s\n", output.c_str()); printf("%s\n", output.c_str());
} }
result->clonePublicInterface(singletonTypes, iceHandler);
return result; return result;
} }
// Read AST into sourceModules if necessary. Trace require()s. Report parse errors. // Read AST into sourceModules if necessary. Trace require()s. Report parse errors.
std::pair<SourceNode*, SourceModule*> Frontend::getSourceNode(CheckResult& checkResult, const ModuleName& name) std::pair<SourceNode*, SourceModule*> Frontend::getSourceNode(const ModuleName& name)
{ {
LUAU_TIMETRACE_SCOPE("Frontend::getSourceNode", "Frontend"); LUAU_TIMETRACE_SCOPE("Frontend::getSourceNode", "Frontend");
LUAU_TIMETRACE_ARGUMENT("name", name.c_str()); LUAU_TIMETRACE_ARGUMENT("name", name.c_str());

View file

@ -11,7 +11,7 @@ namespace Luau
bool Instantiation::isDirty(TypeId ty) bool Instantiation::isDirty(TypeId ty)
{ {
if (const FunctionTypeVar* ftv = log->getMutable<FunctionTypeVar>(ty)) if (const FunctionType* ftv = log->getMutable<FunctionType>(ty))
{ {
if (ftv->hasNoGenerics) if (ftv->hasNoGenerics)
return false; return false;
@ -31,9 +31,9 @@ bool Instantiation::isDirty(TypePackId tp)
bool Instantiation::ignoreChildren(TypeId ty) bool Instantiation::ignoreChildren(TypeId ty)
{ {
if (log->getMutable<FunctionTypeVar>(ty)) if (log->getMutable<FunctionType>(ty))
return true; return true;
else if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassTypeVar>(ty)) else if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassType>(ty))
return true; return true;
else else
return false; return false;
@ -41,10 +41,10 @@ bool Instantiation::ignoreChildren(TypeId ty)
TypeId Instantiation::clean(TypeId ty) TypeId Instantiation::clean(TypeId ty)
{ {
const FunctionTypeVar* ftv = log->getMutable<FunctionTypeVar>(ty); const FunctionType* ftv = log->getMutable<FunctionType>(ty);
LUAU_ASSERT(ftv); 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.magicFunction = ftv->magicFunction;
clone.dcrMagicFunction = ftv->dcrMagicFunction; clone.dcrMagicFunction = ftv->dcrMagicFunction;
clone.tags = ftv->tags; clone.tags = ftv->tags;
@ -71,7 +71,7 @@ TypePackId Instantiation::clean(TypePackId tp)
bool ReplaceGenerics::ignoreChildren(TypeId ty) bool ReplaceGenerics::ignoreChildren(TypeId ty)
{ {
if (const FunctionTypeVar* ftv = log->getMutable<FunctionTypeVar>(ty)) if (const FunctionType* ftv = log->getMutable<FunctionType>(ty))
{ {
if (ftv->hasNoGenerics) if (ftv->hasNoGenerics)
return true; 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. // 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); return (!generics.empty() || !genericPacks.empty()) && (ftv->generics == generics) && (ftv->genericPacks == genericPacks);
} }
else if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassTypeVar>(ty)) else if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassType>(ty))
return true; return true;
else else
{ {
@ -93,9 +93,9 @@ bool ReplaceGenerics::ignoreChildren(TypeId ty)
bool ReplaceGenerics::isDirty(TypeId ty) bool ReplaceGenerics::isDirty(TypeId ty)
{ {
if (const TableTypeVar* ttv = log->getMutable<TableTypeVar>(ty)) if (const TableType* ttv = log->getMutable<TableType>(ty))
return ttv->state == TableState::Generic; return ttv->state == TableState::Generic;
else if (log->getMutable<GenericTypeVar>(ty)) else if (log->getMutable<GenericType>(ty))
return std::find(generics.begin(), generics.end(), ty) != generics.end(); return std::find(generics.begin(), generics.end(), ty) != generics.end();
else else
return false; return false;
@ -112,14 +112,14 @@ bool ReplaceGenerics::isDirty(TypePackId tp)
TypeId ReplaceGenerics::clean(TypeId ty) TypeId ReplaceGenerics::clean(TypeId ty)
{ {
LUAU_ASSERT(isDirty(ty)); LUAU_ASSERT(isDirty(ty));
if (const TableTypeVar* ttv = log->getMutable<TableTypeVar>(ty)) if (const TableType* ttv = log->getMutable<TableType>(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; clone.definitionModuleName = ttv->definitionModuleName;
return addType(std::move(clone)); return addType(std::move(clone));
} }
else else
return addType(FreeTypeVar{scope, level}); return addType(FreeType{scope, level});
} }
TypePackId ReplaceGenerics::clean(TypePackId tp) TypePackId ReplaceGenerics::clean(TypePackId tp)

View file

@ -215,7 +215,7 @@ std::ostream& operator<<(std::ostream& stream, const TableState& tv)
return stream << static_cast<std::underlying_type<TableState>::type>(tv); return stream << static_cast<std::underlying_type<TableState>::type>(tv);
} }
std::ostream& operator<<(std::ostream& stream, const TypeVar& tv) std::ostream& operator<<(std::ostream& stream, const Type& tv)
{ {
return stream << toString(tv); return stream << toString(tv);
} }

View file

@ -2144,14 +2144,14 @@ private:
if (!ty) if (!ty)
return true; return true;
if (const ClassTypeVar* cty = get<ClassTypeVar>(follow(*ty))) if (const ClassType* cty = get<ClassType>(follow(*ty)))
{ {
const Property* prop = lookupClassProp(cty, node->index.value); const Property* prop = lookupClassProp(cty, node->index.value);
if (prop && prop->deprecated) if (prop && prop->deprecated)
report(node->location, *prop, cty->name.c_str(), node->index.value); report(node->location, *prop, cty->name.c_str(), node->index.value);
} }
else if (const TableTypeVar* tty = get<TableTypeVar>(follow(*ty))) else if (const TableType* tty = get<TableType>(follow(*ty)))
{ {
auto prop = tty->props.find(node->index.value); auto prop = tty->props.find(node->index.value);
@ -2302,16 +2302,16 @@ private:
size_t getReturnCount(TypeId ty) size_t getReturnCount(TypeId ty)
{ {
if (auto ftv = get<FunctionTypeVar>(ty)) if (auto ftv = get<FunctionType>(ty))
return size(ftv->retTypes); return size(ftv->retTypes);
if (auto itv = get<IntersectionTypeVar>(ty)) if (auto itv = get<IntersectionType>(ty))
{ {
// We don't process the type recursively to avoid having to deal with self-recursive intersection types // We don't process the type recursively to avoid having to deal with self-recursive intersection types
size_t result = 0; size_t result = 0;
for (TypeId part : itv->parts) for (TypeId part : itv->parts)
if (auto ftv = get<FunctionTypeVar>(follow(part))) if (auto ftv = get<FunctionType>(follow(part)))
result = std::max(result, size(ftv->retTypes)); result = std::max(result, size(ftv->retTypes));
return result; return result;

View file

@ -9,8 +9,8 @@
#include "Luau/Scope.h" #include "Luau/Scope.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/VisitTypeVar.h" #include "Luau/VisitType.h"
#include <algorithm> #include <algorithm>
@ -60,12 +60,12 @@ bool isWithinComment(const SourceModule& sourceModule, Position pos)
struct ClonePublicInterface : Substitution struct ClonePublicInterface : Substitution
{ {
NotNull<SingletonTypes> singletonTypes; NotNull<BuiltinTypes> builtinTypes;
NotNull<Module> module; NotNull<Module> module;
ClonePublicInterface(const TxnLog* log, NotNull<SingletonTypes> singletonTypes, Module* module) ClonePublicInterface(const TxnLog* log, NotNull<BuiltinTypes> builtinTypes, Module* module)
: Substitution(log, &module->interfaceTypes) : Substitution(log, &module->interfaceTypes)
, singletonTypes(singletonTypes) , builtinTypes(builtinTypes)
, module(module) , module(module)
{ {
LUAU_ASSERT(module); LUAU_ASSERT(module);
@ -76,9 +76,9 @@ struct ClonePublicInterface : Substitution
if (ty->owningArena == &module->internalTypes) if (ty->owningArena == &module->internalTypes)
return true; return true;
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty)) if (const FunctionType* ftv = get<FunctionType>(ty))
return ftv->level.level != 0; return ftv->level.level != 0;
if (const TableTypeVar* ttv = get<TableTypeVar>(ty)) if (const TableType* ttv = get<TableType>(ty))
return ttv->level.level != 0; return ttv->level.level != 0;
return false; return false;
} }
@ -92,9 +92,9 @@ struct ClonePublicInterface : Substitution
{ {
TypeId result = clone(ty); TypeId result = clone(ty);
if (FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(result)) if (FunctionType* ftv = getMutable<FunctionType>(result))
ftv->level = TypeLevel{0, 0}; ftv->level = TypeLevel{0, 0};
else if (TableTypeVar* ttv = getMutable<TableTypeVar>(result)) else if (TableType* ttv = getMutable<TableType>(result))
ttv->level = TypeLevel{0, 0}; ttv->level = TypeLevel{0, 0};
return result; return result;
@ -117,7 +117,7 @@ struct ClonePublicInterface : Substitution
else else
{ {
module->errors.push_back(TypeError{module->scopes[0].first, UnificationTooComplex{}}); module->errors.push_back(TypeError{module->scopes[0].first, UnificationTooComplex{}});
return singletonTypes->errorRecoveryType(); return builtinTypes->errorRecoveryType();
} }
} }
@ -133,7 +133,7 @@ struct ClonePublicInterface : Substitution
else else
{ {
module->errors.push_back(TypeError{module->scopes[0].first, UnificationTooComplex{}}); module->errors.push_back(TypeError{module->scopes[0].first, UnificationTooComplex{}});
return singletonTypes->errorRecoveryTypePack(); return builtinTypes->errorRecoveryTypePack();
} }
} }
@ -178,9 +178,9 @@ Module::~Module()
unfreeze(internalTypes); unfreeze(internalTypes);
} }
void Module::clonePublicInterface(NotNull<SingletonTypes> singletonTypes, InternalErrorReporter& ice) void Module::clonePublicInterface(NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter& ice)
{ {
LUAU_ASSERT(interfaceTypes.typeVars.empty()); LUAU_ASSERT(interfaceTypes.types.empty());
LUAU_ASSERT(interfaceTypes.typePacks.empty()); LUAU_ASSERT(interfaceTypes.typePacks.empty());
CloneState cloneState; CloneState cloneState;
@ -192,7 +192,7 @@ void Module::clonePublicInterface(NotNull<SingletonTypes> singletonTypes, Intern
std::unordered_map<Name, TypeFun>* exportedTypeBindings = &moduleScope->exportedTypeBindings; std::unordered_map<Name, TypeFun>* exportedTypeBindings = &moduleScope->exportedTypeBindings;
TxnLog log; TxnLog log;
ClonePublicInterface clonePublicInterface{&log, singletonTypes, this}; ClonePublicInterface clonePublicInterface{&log, builtinTypes, this};
if (FFlag::LuauClonePublicInterfaceLess) if (FFlag::LuauClonePublicInterfaceLess)
returnType = clonePublicInterface.cloneTypePack(returnType); returnType = clonePublicInterface.cloneTypePack(returnType);

File diff suppressed because it is too large Load diff

View file

@ -5,8 +5,8 @@
#include "Luau/Scope.h" #include "Luau/Scope.h"
#include "Luau/Substitution.h" #include "Luau/Substitution.h"
#include "Luau/TxnLog.h" #include "Luau/TxnLog.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/VisitTypeVar.h" #include "Luau/VisitType.h"
LUAU_FASTFLAG(DebugLuauSharedSelf) LUAU_FASTFLAG(DebugLuauSharedSelf)
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution);
@ -15,7 +15,7 @@ LUAU_FASTFLAG(LuauClassTypeVarsInSubstitution)
namespace Luau namespace Luau
{ {
struct Quantifier final : TypeVarOnceVisitor struct Quantifier final : TypeOnceVisitor
{ {
TypeLevel level; TypeLevel level;
std::vector<TypeId> generics; std::vector<TypeId> generics;
@ -43,24 +43,24 @@ struct Quantifier final : TypeVarOnceVisitor
return false; return false;
} }
bool visit(TypeId ty, const FreeTypeVar& ftv) override bool visit(TypeId ty, const FreeType& ftv) override
{ {
seenMutableType = true; seenMutableType = true;
if (!level.subsumes(ftv.level)) if (!level.subsumes(ftv.level))
return false; return false;
*asMutable(ty) = GenericTypeVar{level}; *asMutable(ty) = GenericType{level};
generics.push_back(ty); generics.push_back(ty);
return false; return false;
} }
bool visit(TypeId ty, const TableTypeVar&) override bool visit(TypeId ty, const TableType&) override
{ {
LUAU_ASSERT(getMutable<TableTypeVar>(ty)); LUAU_ASSERT(getMutable<TableType>(ty));
TableTypeVar& ttv = *getMutable<TableTypeVar>(ty); TableType& ttv = *getMutable<TableType>(ty);
if (ttv.state == TableState::Generic) if (ttv.state == TableState::Generic)
seenGenericType = true; seenGenericType = true;
@ -117,7 +117,7 @@ void quantify(TypeId ty, TypeLevel level)
for (const auto& [_, prop] : ttv->props) for (const auto& [_, prop] : ttv->props)
{ {
auto ftv = getMutable<FunctionTypeVar>(follow(prop.type)); auto ftv = getMutable<FunctionType>(follow(prop.type));
if (!ftv || !ftv->hasSelf) if (!ftv || !ftv->hasSelf)
continue; continue;
@ -128,7 +128,7 @@ void quantify(TypeId ty, TypeLevel level)
} }
} }
} }
else if (auto ftv = getMutable<FunctionTypeVar>(ty)) else if (auto ftv = getMutable<FunctionType>(ty))
{ {
Quantifier q{level}; Quantifier q{level};
q.traverse(ty); q.traverse(ty);
@ -145,7 +145,7 @@ void quantify(TypeId ty, TypeLevel level)
Quantifier q{level}; Quantifier q{level};
q.traverse(ty); q.traverse(ty);
FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(ty); FunctionType* ftv = getMutable<FunctionType>(ty);
LUAU_ASSERT(ftv); LUAU_ASSERT(ftv);
ftv->generics.insert(ftv->generics.end(), q.generics.begin(), q.generics.end()); ftv->generics.insert(ftv->generics.end(), q.generics.begin(), q.generics.end());
ftv->genericPacks.insert(ftv->genericPacks.end(), q.genericPacks.begin(), q.genericPacks.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)); LUAU_ASSERT(ty == follow(ty));
if (auto ftv = get<FreeTypeVar>(ty)) if (auto ftv = get<FreeType>(ty))
{ {
return subsumes(scope, ftv->scope); return subsumes(scope, ftv->scope);
} }
else if (auto ttv = get<TableTypeVar>(ty)) else if (auto ttv = get<TableType>(ty))
{ {
return ttv->state == TableState::Free && subsumes(scope, ttv->scope); return ttv->state == TableState::Free && subsumes(scope, ttv->scope);
} }
@ -192,16 +192,16 @@ struct PureQuantifier : Substitution
TypeId clean(TypeId ty) override TypeId clean(TypeId ty) override
{ {
if (auto ftv = get<FreeTypeVar>(ty)) if (auto ftv = get<FreeType>(ty))
{ {
TypeId result = arena->addType(GenericTypeVar{scope}); TypeId result = arena->addType(GenericType{scope});
insertedGenerics.push_back(result); insertedGenerics.push_back(result);
return result; return result;
} }
else if (auto ttv = get<TableTypeVar>(ty)) else if (auto ttv = get<TableType>(ty))
{ {
TypeId result = arena->addType(TableTypeVar{}); TypeId result = arena->addType(TableType{});
TableTypeVar* resultTable = getMutable<TableTypeVar>(result); TableType* resultTable = getMutable<TableType>(result);
LUAU_ASSERT(resultTable); LUAU_ASSERT(resultTable);
*resultTable = *ttv; *resultTable = *ttv;
@ -229,7 +229,7 @@ struct PureQuantifier : Substitution
bool ignoreChildren(TypeId ty) override bool ignoreChildren(TypeId ty) override
{ {
if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassTypeVar>(ty)) if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassType>(ty))
return true; return true;
return ty->persistent; return ty->persistent;
@ -246,7 +246,7 @@ TypeId quantify(TypeArena* arena, TypeId ty, Scope* scope)
std::optional<TypeId> result = quantifier.substitute(ty); std::optional<TypeId> result = quantifier.substitute(ty);
LUAU_ASSERT(result); LUAU_ASSERT(result);
FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(*result); FunctionType* ftv = getMutable<FunctionType>(*result);
LUAU_ASSERT(ftv); LUAU_ASSERT(ftv);
ftv->scope = scope; ftv->scope = scope;
ftv->generics.insert(ftv->generics.end(), quantifier.insertedGenerics.begin(), quantifier.insertedGenerics.end()); ftv->generics.insert(ftv->generics.end(), quantifier.insertedGenerics.begin(), quantifier.insertedGenerics.end());

View file

@ -28,7 +28,7 @@ void Tarjan::visitChildren(TypeId ty, int index)
if (auto pty = log->pending(ty)) if (auto pty = log->pending(ty))
ty = &pty->pending; ty = &pty->pending;
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty)) if (const FunctionType* ftv = get<FunctionType>(ty))
{ {
if (FFlag::LuauSubstitutionFixMissingFields) if (FFlag::LuauSubstitutionFixMissingFields)
{ {
@ -41,7 +41,7 @@ void Tarjan::visitChildren(TypeId ty, int index)
visitChild(ftv->argTypes); visitChild(ftv->argTypes);
visitChild(ftv->retTypes); visitChild(ftv->retTypes);
} }
else if (const TableTypeVar* ttv = get<TableTypeVar>(ty)) else if (const TableType* ttv = get<TableType>(ty))
{ {
LUAU_ASSERT(!ttv->boundTo); LUAU_ASSERT(!ttv->boundTo);
for (const auto& [name, prop] : ttv->props) for (const auto& [name, prop] : ttv->props)
@ -58,22 +58,22 @@ void Tarjan::visitChildren(TypeId ty, int index)
for (TypePackId itp : ttv->instantiatedTypePackParams) for (TypePackId itp : ttv->instantiatedTypePackParams)
visitChild(itp); visitChild(itp);
} }
else if (const MetatableTypeVar* mtv = get<MetatableTypeVar>(ty)) else if (const MetatableType* mtv = get<MetatableType>(ty))
{ {
visitChild(mtv->table); visitChild(mtv->table);
visitChild(mtv->metatable); visitChild(mtv->metatable);
} }
else if (const UnionTypeVar* utv = get<UnionTypeVar>(ty)) else if (const UnionType* utv = get<UnionType>(ty))
{ {
for (TypeId opt : utv->options) for (TypeId opt : utv->options)
visitChild(opt); visitChild(opt);
} }
else if (const IntersectionTypeVar* itv = get<IntersectionTypeVar>(ty)) else if (const IntersectionType* itv = get<IntersectionType>(ty))
{ {
for (TypeId part : itv->parts) for (TypeId part : itv->parts)
visitChild(part); visitChild(part);
} }
else if (const PendingExpansionTypeVar* petv = get<PendingExpansionTypeVar>(ty)) else if (const PendingExpansionType* petv = get<PendingExpansionType>(ty))
{ {
for (TypeId a : petv->typeArguments) for (TypeId a : petv->typeArguments)
visitChild(a); visitChild(a);
@ -81,7 +81,7 @@ void Tarjan::visitChildren(TypeId ty, int index)
for (TypePackId a : petv->packArguments) for (TypePackId a : petv->packArguments)
visitChild(a); visitChild(a);
} }
else if (const ClassTypeVar* ctv = get<ClassTypeVar>(ty); FFlag::LuauClassTypeVarsInSubstitution && ctv) else if (const ClassType* ctv = get<ClassType>(ty); FFlag::LuauClassTypeVarsInSubstitution && ctv)
{ {
for (auto [name, prop] : ctv->props) for (auto [name, prop] : ctv->props)
visitChild(prop.type); visitChild(prop.type);
@ -92,7 +92,7 @@ void Tarjan::visitChildren(TypeId ty, int index)
if (ctv->metatable) if (ctv->metatable)
visitChild(*ctv->metatable); visitChild(*ctv->metatable);
} }
else if (const NegationTypeVar* ntv = get<NegationTypeVar>(ty)) else if (const NegationType* ntv = get<NegationType>(ty))
{ {
visitChild(ntv->ty); visitChild(ntv->ty);
} }
@ -559,7 +559,7 @@ void Substitution::replaceChildren(TypeId ty)
if (ty->owningArena != arena) if (ty->owningArena != arena)
return; return;
if (FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(ty)) if (FunctionType* ftv = getMutable<FunctionType>(ty))
{ {
if (FFlag::LuauSubstitutionFixMissingFields) if (FFlag::LuauSubstitutionFixMissingFields)
{ {
@ -572,7 +572,7 @@ void Substitution::replaceChildren(TypeId ty)
ftv->argTypes = replace(ftv->argTypes); ftv->argTypes = replace(ftv->argTypes);
ftv->retTypes = replace(ftv->retTypes); ftv->retTypes = replace(ftv->retTypes);
} }
else if (TableTypeVar* ttv = getMutable<TableTypeVar>(ty)) else if (TableType* ttv = getMutable<TableType>(ty))
{ {
LUAU_ASSERT(!ttv->boundTo); LUAU_ASSERT(!ttv->boundTo);
for (auto& [name, prop] : ttv->props) for (auto& [name, prop] : ttv->props)
@ -589,22 +589,22 @@ void Substitution::replaceChildren(TypeId ty)
for (TypePackId& itp : ttv->instantiatedTypePackParams) for (TypePackId& itp : ttv->instantiatedTypePackParams)
itp = replace(itp); itp = replace(itp);
} }
else if (MetatableTypeVar* mtv = getMutable<MetatableTypeVar>(ty)) else if (MetatableType* mtv = getMutable<MetatableType>(ty))
{ {
mtv->table = replace(mtv->table); mtv->table = replace(mtv->table);
mtv->metatable = replace(mtv->metatable); mtv->metatable = replace(mtv->metatable);
} }
else if (UnionTypeVar* utv = getMutable<UnionTypeVar>(ty)) else if (UnionType* utv = getMutable<UnionType>(ty))
{ {
for (TypeId& opt : utv->options) for (TypeId& opt : utv->options)
opt = replace(opt); opt = replace(opt);
} }
else if (IntersectionTypeVar* itv = getMutable<IntersectionTypeVar>(ty)) else if (IntersectionType* itv = getMutable<IntersectionType>(ty))
{ {
for (TypeId& part : itv->parts) for (TypeId& part : itv->parts)
part = replace(part); part = replace(part);
} }
else if (PendingExpansionTypeVar* petv = getMutable<PendingExpansionTypeVar>(ty)) else if (PendingExpansionType* petv = getMutable<PendingExpansionType>(ty))
{ {
for (TypeId& a : petv->typeArguments) for (TypeId& a : petv->typeArguments)
a = replace(a); a = replace(a);
@ -612,7 +612,7 @@ void Substitution::replaceChildren(TypeId ty)
for (TypePackId& a : petv->packArguments) for (TypePackId& a : petv->packArguments)
a = replace(a); a = replace(a);
} }
else if (ClassTypeVar* ctv = getMutable<ClassTypeVar>(ty); FFlag::LuauClassTypeVarsInSubstitution && ctv) else if (ClassType* ctv = getMutable<ClassType>(ty); FFlag::LuauClassTypeVarsInSubstitution && ctv)
{ {
for (auto& [name, prop] : ctv->props) for (auto& [name, prop] : ctv->props)
prop.type = replace(prop.type); prop.type = replace(prop.type);
@ -623,7 +623,7 @@ void Substitution::replaceChildren(TypeId ty)
if (ctv->metatable) if (ctv->metatable)
ctv->metatable = replace(*ctv->metatable); ctv->metatable = replace(*ctv->metatable);
} }
else if (NegationTypeVar* ntv = getMutable<NegationTypeVar>(ty)) else if (NegationType* ntv = getMutable<NegationType>(ty))
{ {
ntv->ty = replace(ntv->ty); ntv->ty = replace(ntv->ty);
} }

View file

@ -3,7 +3,7 @@
#include "Luau/ToString.h" #include "Luau/ToString.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/StringUtils.h" #include "Luau/StringUtils.h"
#include <unordered_map> #include <unordered_map>
@ -49,10 +49,10 @@ struct StateDot
bool StateDot::canDuplicatePrimitive(TypeId ty) bool StateDot::canDuplicatePrimitive(TypeId ty)
{ {
if (get<BoundTypeVar>(ty)) if (get<BoundType>(ty))
return false; return false;
return get<PrimitiveTypeVar>(ty) || get<AnyTypeVar>(ty); return get<PrimitiveType>(ty) || get<AnyType>(ty);
} }
void StateDot::visitChild(TypeId ty, int parentIndex, const char* linkName) 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 (opts.duplicatePrimitives && canDuplicatePrimitive(ty))
{ {
if (get<PrimitiveTypeVar>(ty)) if (get<PrimitiveType>(ty))
formatAppend(result, "n%d [label=\"%s\"];\n", index, toString(ty).c_str()); formatAppend(result, "n%d [label=\"%s\"];\n", index, toString(ty).c_str());
else if (get<AnyTypeVar>(ty)) else if (get<AnyType>(ty))
formatAppend(result, "n%d [label=\"any\"];\n", index); formatAppend(result, "n%d [label=\"any\"];\n", index);
} }
else else
@ -139,31 +139,31 @@ void StateDot::visitChildren(TypeId ty, int index)
startNode(index); startNode(index);
startNodeLabel(); startNodeLabel();
if (const BoundTypeVar* btv = get<BoundTypeVar>(ty)) if (const BoundType* btv = get<BoundType>(ty))
{ {
formatAppend(result, "BoundTypeVar %d", index); formatAppend(result, "BoundType %d", index);
finishNodeLabel(ty); finishNodeLabel(ty);
finishNode(); finishNode();
visitChild(btv->boundTo, index); visitChild(btv->boundTo, index);
} }
else if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty)) else if (const FunctionType* ftv = get<FunctionType>(ty))
{ {
formatAppend(result, "FunctionTypeVar %d", index); formatAppend(result, "FunctionType %d", index);
finishNodeLabel(ty); finishNodeLabel(ty);
finishNode(); finishNode();
visitChild(ftv->argTypes, index, "arg"); visitChild(ftv->argTypes, index, "arg");
visitChild(ftv->retTypes, index, "ret"); visitChild(ftv->retTypes, index, "ret");
} }
else if (const TableTypeVar* ttv = get<TableTypeVar>(ty)) else if (const TableType* ttv = get<TableType>(ty))
{ {
if (ttv->name) if (ttv->name)
formatAppend(result, "TableTypeVar %s", ttv->name->c_str()); formatAppend(result, "TableType %s", ttv->name->c_str());
else if (ttv->syntheticName) else if (ttv->syntheticName)
formatAppend(result, "TableTypeVar %s", ttv->syntheticName->c_str()); formatAppend(result, "TableType %s", ttv->syntheticName->c_str());
else else
formatAppend(result, "TableTypeVar %d", index); formatAppend(result, "TableType %d", index);
finishNodeLabel(ty); finishNodeLabel(ty);
finishNode(); finishNode();
@ -183,69 +183,69 @@ void StateDot::visitChildren(TypeId ty, int index)
for (TypePackId itp : ttv->instantiatedTypePackParams) for (TypePackId itp : ttv->instantiatedTypePackParams)
visitChild(itp, index, "typePackParam"); visitChild(itp, index, "typePackParam");
} }
else if (const MetatableTypeVar* mtv = get<MetatableTypeVar>(ty)) else if (const MetatableType* mtv = get<MetatableType>(ty))
{ {
formatAppend(result, "MetatableTypeVar %d", index); formatAppend(result, "MetatableType %d", index);
finishNodeLabel(ty); finishNodeLabel(ty);
finishNode(); finishNode();
visitChild(mtv->table, index, "table"); visitChild(mtv->table, index, "table");
visitChild(mtv->metatable, index, "metatable"); visitChild(mtv->metatable, index, "metatable");
} }
else if (const UnionTypeVar* utv = get<UnionTypeVar>(ty)) else if (const UnionType* utv = get<UnionType>(ty))
{ {
formatAppend(result, "UnionTypeVar %d", index); formatAppend(result, "UnionType %d", index);
finishNodeLabel(ty); finishNodeLabel(ty);
finishNode(); finishNode();
for (TypeId opt : utv->options) for (TypeId opt : utv->options)
visitChild(opt, index); visitChild(opt, index);
} }
else if (const IntersectionTypeVar* itv = get<IntersectionTypeVar>(ty)) else if (const IntersectionType* itv = get<IntersectionType>(ty))
{ {
formatAppend(result, "IntersectionTypeVar %d", index); formatAppend(result, "IntersectionType %d", index);
finishNodeLabel(ty); finishNodeLabel(ty);
finishNode(); finishNode();
for (TypeId part : itv->parts) for (TypeId part : itv->parts)
visitChild(part, index); visitChild(part, index);
} }
else if (const GenericTypeVar* gtv = get<GenericTypeVar>(ty)) else if (const GenericType* gtv = get<GenericType>(ty))
{ {
if (gtv->explicitName) if (gtv->explicitName)
formatAppend(result, "GenericTypeVar %s", gtv->name.c_str()); formatAppend(result, "GenericType %s", gtv->name.c_str());
else else
formatAppend(result, "GenericTypeVar %d", index); formatAppend(result, "GenericType %d", index);
finishNodeLabel(ty); finishNodeLabel(ty);
finishNode(); finishNode();
} }
else if (const FreeTypeVar* ftv = get<FreeTypeVar>(ty)) else if (const FreeType* ftv = get<FreeType>(ty))
{ {
formatAppend(result, "FreeTypeVar %d", index); formatAppend(result, "FreeType %d", index);
finishNodeLabel(ty); finishNodeLabel(ty);
finishNode(); finishNode();
} }
else if (get<AnyTypeVar>(ty)) else if (get<AnyType>(ty))
{ {
formatAppend(result, "AnyTypeVar %d", index); formatAppend(result, "AnyType %d", index);
finishNodeLabel(ty); finishNodeLabel(ty);
finishNode(); finishNode();
} }
else if (get<PrimitiveTypeVar>(ty)) else if (get<PrimitiveType>(ty))
{ {
formatAppend(result, "PrimitiveTypeVar %s", toString(ty).c_str()); formatAppend(result, "PrimitiveType %s", toString(ty).c_str());
finishNodeLabel(ty); finishNodeLabel(ty);
finishNode(); finishNode();
} }
else if (get<ErrorTypeVar>(ty)) else if (get<ErrorType>(ty))
{ {
formatAppend(result, "ErrorTypeVar %d", index); formatAppend(result, "ErrorType %d", index);
finishNodeLabel(ty); finishNodeLabel(ty);
finishNode(); finishNode();
} }
else if (const ClassTypeVar* ctv = get<ClassTypeVar>(ty)) else if (const ClassType* ctv = get<ClassType>(ty))
{ {
formatAppend(result, "ClassTypeVar %s", ctv->name.c_str()); formatAppend(result, "ClassType %s", ctv->name.c_str());
finishNodeLabel(ty); finishNodeLabel(ty);
finishNode(); finishNode();
@ -258,7 +258,7 @@ void StateDot::visitChildren(TypeId ty, int index)
if (ctv->metatable) if (ctv->metatable)
visitChild(*ctv->metatable, index, "[metatable]"); visitChild(*ctv->metatable, index, "[metatable]");
} }
else if (const SingletonTypeVar* stv = get<SingletonTypeVar>(ty)) else if (const SingletonType* stv = get<SingletonType>(ty))
{ {
std::string res; std::string res;
@ -276,7 +276,7 @@ void StateDot::visitChildren(TypeId ty, int index)
else else
LUAU_ASSERT(!"unknown singleton type"); LUAU_ASSERT(!"unknown singleton type");
formatAppend(result, "SingletonTypeVar %s", res.c_str()); formatAppend(result, "SingletonType %s", res.c_str());
finishNodeLabel(ty); finishNodeLabel(ty);
finishNode(); finishNode();
} }

View file

@ -4,10 +4,11 @@
#include "Luau/Constraint.h" #include "Luau/Constraint.h"
#include "Luau/Location.h" #include "Luau/Location.h"
#include "Luau/Scope.h" #include "Luau/Scope.h"
#include "Luau/TxnLog.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/VisitTypeVar.h" #include "Luau/VisitType.h"
#include <algorithm> #include <algorithm>
#include <stdexcept> #include <stdexcept>
@ -17,6 +18,7 @@ LUAU_FASTFLAG(LuauUnknownAndNeverType)
LUAU_FASTFLAGVARIABLE(LuauLineBreaksDetermineIndents, false) LUAU_FASTFLAGVARIABLE(LuauLineBreaksDetermineIndents, false)
LUAU_FASTFLAGVARIABLE(LuauFunctionReturnStringificationFixup, false) LUAU_FASTFLAGVARIABLE(LuauFunctionReturnStringificationFixup, false)
LUAU_FASTFLAGVARIABLE(LuauUnseeArrayTtv, false) LUAU_FASTFLAGVARIABLE(LuauUnseeArrayTtv, false)
LUAU_FASTFLAGVARIABLE(LuauSerializeNilUnionAsNil, false)
/* /*
* Prefix generic typenames with gen- * Prefix generic typenames with gen-
@ -31,7 +33,7 @@ namespace Luau
namespace namespace
{ {
struct FindCyclicTypes final : TypeVarVisitor struct FindCyclicTypes final : TypeVisitor
{ {
FindCyclicTypes() = default; FindCyclicTypes() = default;
FindCyclicTypes(const FindCyclicTypes&) = delete; FindCyclicTypes(const FindCyclicTypes&) = delete;
@ -63,7 +65,7 @@ struct FindCyclicTypes final : TypeVarVisitor
return visitedPacks.insert(tp).second; 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) if (!visited.insert(ty).second)
return false; return false;
@ -82,7 +84,7 @@ struct FindCyclicTypes final : TypeVarVisitor
return true; return true;
} }
bool visit(TypeId ty, const ClassTypeVar&) override bool visit(TypeId ty, const ClassType&) override
{ {
return false; return false;
} }
@ -136,7 +138,7 @@ struct StringifierState
, result(result) , result(result)
, exhaustive(opts.exhaustive) , exhaustive(opts.exhaustive)
{ {
for (const auto& [_, v] : opts.nameMap.typeVars) for (const auto& [_, v] : opts.nameMap.types)
usedNames.insert(v); usedNames.insert(v);
for (const auto& [_, v] : opts.nameMap.typePacks) for (const auto& [_, v] : opts.nameMap.typePacks)
usedNames.insert(v); usedNames.insert(v);
@ -162,8 +164,8 @@ struct StringifierState
std::string getName(TypeId ty) std::string getName(TypeId ty)
{ {
const size_t s = opts.nameMap.typeVars.size(); const size_t s = opts.nameMap.types.size();
std::string& n = opts.nameMap.typeVars[ty]; std::string& n = opts.nameMap.types[ty];
if (!n.empty()) if (!n.empty())
return n; return n;
@ -291,11 +293,11 @@ private:
} }
}; };
struct TypeVarStringifier struct TypeStringifier
{ {
StringifierState& state; StringifierState& state;
explicit TypeVarStringifier(StringifierState& state) explicit TypeStringifier(StringifierState& state)
: state(state) : state(state)
{ {
} }
@ -392,17 +394,17 @@ struct TypeVarStringifier
} }
} }
void operator()(TypeId, const BoundTypeVar& btv) void operator()(TypeId, const BoundType& btv)
{ {
stringify(btv.boundTo); stringify(btv.boundTo);
} }
void operator()(TypeId ty, const GenericTypeVar& gtv) void operator()(TypeId ty, const GenericType& gtv)
{ {
if (gtv.explicitName) if (gtv.explicitName)
{ {
state.usedNames.insert(gtv.name); state.usedNames.insert(gtv.name);
state.opts.nameMap.typeVars[ty] = gtv.name; state.opts.nameMap.types[ty] = gtv.name;
state.emit(gtv.name); state.emit(gtv.name);
} }
else else
@ -418,40 +420,40 @@ struct TypeVarStringifier
} }
} }
void operator()(TypeId, const BlockedTypeVar& btv) void operator()(TypeId, const BlockedType& btv)
{ {
state.emit("*blocked-"); state.emit("*blocked-");
state.emit(btv.index); state.emit(btv.index);
state.emit("*"); state.emit("*");
} }
void operator()(TypeId ty, const PendingExpansionTypeVar& petv) void operator()(TypeId ty, const PendingExpansionType& petv)
{ {
state.emit("*pending-expansion-"); state.emit("*pending-expansion-");
state.emit(petv.index); state.emit(petv.index);
state.emit("*"); state.emit("*");
} }
void operator()(TypeId, const PrimitiveTypeVar& ptv) void operator()(TypeId, const PrimitiveType& ptv)
{ {
switch (ptv.type) switch (ptv.type)
{ {
case PrimitiveTypeVar::NilType: case PrimitiveType::NilType:
state.emit("nil"); state.emit("nil");
return; return;
case PrimitiveTypeVar::Boolean: case PrimitiveType::Boolean:
state.emit("boolean"); state.emit("boolean");
return; return;
case PrimitiveTypeVar::Number: case PrimitiveType::Number:
state.emit("number"); state.emit("number");
return; return;
case PrimitiveTypeVar::String: case PrimitiveType::String:
state.emit("string"); state.emit("string");
return; return;
case PrimitiveTypeVar::Thread: case PrimitiveType::Thread:
state.emit("thread"); state.emit("thread");
return; return;
case PrimitiveTypeVar::Function: case PrimitiveType::Function:
state.emit("function"); state.emit("function");
return; return;
default: 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<BooleanSingleton>(&stv)) if (const BooleanSingleton* bs = Luau::get<BooleanSingleton>(&stv))
state.emit(bs->value ? "true" : "false"); 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)) if (state.hasSeen(&ftv))
{ {
@ -539,7 +541,7 @@ struct TypeVarStringifier
state.unsee(&ftv); state.unsee(&ftv);
} }
void operator()(TypeId, const TableTypeVar& ttv) void operator()(TypeId, const TableType& ttv)
{ {
if (ttv.boundTo) if (ttv.boundTo)
return stringify(*ttv.boundTo); return stringify(*ttv.boundTo);
@ -681,7 +683,7 @@ struct TypeVarStringifier
state.unsee(&ttv); state.unsee(&ttv);
} }
void operator()(TypeId, const MetatableTypeVar& mtv) void operator()(TypeId, const MetatableType& mtv)
{ {
state.result.invalid = true; state.result.invalid = true;
if (!state.exhaustive && mtv.syntheticName) if (!state.exhaustive && mtv.syntheticName)
@ -698,17 +700,17 @@ struct TypeVarStringifier
state.emit(" }"); state.emit(" }");
} }
void operator()(TypeId, const ClassTypeVar& ctv) void operator()(TypeId, const ClassType& ctv)
{ {
state.emit(ctv.name); state.emit(ctv.name);
} }
void operator()(TypeId, const AnyTypeVar&) void operator()(TypeId, const AnyType&)
{ {
state.emit("any"); state.emit("any");
} }
void operator()(TypeId, const UnionTypeVar& uv) void operator()(TypeId, const UnionType& uv)
{ {
if (state.hasSeen(&uv)) if (state.hasSeen(&uv))
{ {
@ -718,6 +720,7 @@ struct TypeVarStringifier
} }
bool optional = false; bool optional = false;
bool hasNonNilDisjunct = false;
std::vector<std::string> results = {}; std::vector<std::string> results = {};
for (auto el : &uv) for (auto el : &uv)
@ -729,10 +732,14 @@ struct TypeVarStringifier
optional = true; optional = true;
continue; continue;
} }
else
{
hasNonNilDisjunct = true;
}
std::string saved = std::move(state.result.name); std::string saved = std::move(state.result.name);
bool needParens = !state.cycleNames.count(el) && (get<IntersectionTypeVar>(el) || get<FunctionTypeVar>(el)); bool needParens = !state.cycleNames.count(el) && (get<IntersectionType>(el) || get<FunctionType>(el));
if (needParens) if (needParens)
state.emit("("); state.emit("(");
@ -771,11 +778,17 @@ struct TypeVarStringifier
if (results.size() > 1) if (results.size() > 1)
s = ")?"; s = ")?";
if (FFlag::LuauSerializeNilUnionAsNil)
{
if (!hasNonNilDisjunct)
s = "nil";
}
state.emit(s); state.emit(s);
} }
} }
void operator()(TypeId, const IntersectionTypeVar& uv) void operator()(TypeId, const IntersectionType& uv)
{ {
if (state.hasSeen(&uv)) if (state.hasSeen(&uv))
{ {
@ -791,7 +804,7 @@ struct TypeVarStringifier
std::string saved = std::move(state.result.name); std::string saved = std::move(state.result.name);
bool needParens = !state.cycleNames.count(el) && (get<UnionTypeVar>(el) || get<FunctionTypeVar>(el)); bool needParens = !state.cycleNames.count(el) && (get<UnionType>(el) || get<FunctionType>(el));
if (needParens) if (needParens)
state.emit("("); 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.result.error = true;
state.emit(FFlag::LuauUnknownAndNeverType ? "*error-type*" : "*unknown*"); state.emit(FFlag::LuauUnknownAndNeverType ? "*error-type*" : "*unknown*");
} }
void operator()(TypeId, const LazyTypeVar& ltv) void operator()(TypeId, const LazyType& ltv)
{ {
state.result.invalid = true; state.result.invalid = true;
state.emit("lazy?"); state.emit("lazy?");
} }
void operator()(TypeId, const UnknownTypeVar& ttv) void operator()(TypeId, const UnknownType& ttv)
{ {
state.emit("unknown"); state.emit("unknown");
} }
void operator()(TypeId, const NeverTypeVar& ttv) void operator()(TypeId, const NeverType& ttv)
{ {
state.emit("never"); state.emit("never");
} }
void operator()(TypeId, const NegationTypeVar& ntv) void operator()(TypeId, const NegationType& ntv)
{ {
state.emit("~"); state.emit("~");
// The precedence of `~` should be less than `|` and `&`. // The precedence of `~` should be less than `|` and `&`.
TypeId followed = follow(ntv.ty); TypeId followed = follow(ntv.ty);
bool parens = get<UnionTypeVar>(followed) || get<IntersectionTypeVar>(followed); bool parens = get<UnionType>(followed) || get<IntersectionType>(followed);
if (parens) if (parens)
state.emit("("); state.emit("(");
@ -884,7 +897,7 @@ struct TypePackStringifier
void stringify(TypeId tv) void stringify(TypeId tv)
{ {
TypeVarStringifier tvs{state}; TypeStringifier tvs{state};
tvs.stringify(tv); tvs.stringify(tv);
} }
@ -1033,13 +1046,13 @@ struct TypePackStringifier
} }
}; };
void TypeVarStringifier::stringify(TypePackId tp) void TypeStringifier::stringify(TypePackId tp)
{ {
TypePackStringifier tps(state); TypePackStringifier tps(state);
tps.stringify(tp); tps.stringify(tp);
} }
void TypeVarStringifier::stringify(TypePackId tpid, const std::vector<std::optional<FunctionArgument>>& names) void TypeStringifier::stringify(TypePackId tpid, const std::vector<std::optional<FunctionArgument>>& names)
{ {
TypePackStringifier tps(state, names); TypePackStringifier tps(state, names);
tps.stringify(tpid); tps.stringify(tpid);
@ -1055,7 +1068,7 @@ static void assignCycleNames(const std::set<TypeId>& cycles, const std::set<Type
std::string name; std::string name;
// TODO: use the stringified type list if there are no cycles // TODO: use the stringified type list if there are no cycles
if (auto ttv = get<TableTypeVar>(follow(cycleTy)); !exhaustive && ttv && (ttv->syntheticName || ttv->name)) if (auto ttv = get<TableType>(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 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) { if (std::find_if(ttv->instantiatedTypeParams.begin(), ttv->instantiatedTypeParams.end(), [&](auto&& el) {
@ -1083,13 +1096,12 @@ static void assignCycleNames(const std::set<TypeId>& cycles, const std::set<Type
ToStringResult toStringDetailed(TypeId ty, ToStringOptions& opts) ToStringResult toStringDetailed(TypeId ty, 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. * 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. * 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. * 4. Print out the root of the type using the same algorithm as step 3.
*/ */
ty = follow(ty); ty = follow(ty);
ToStringResult result; ToStringResult result;
StringifierState state{opts, result}; StringifierState state{opts, result};
@ -1101,11 +1113,11 @@ ToStringResult toStringDetailed(TypeId ty, ToStringOptions& opts)
assignCycleNames(cycles, cycleTPs, state.cycleNames, state.cycleTpNames, opts.exhaustive); assignCycleNames(cycles, cycleTPs, state.cycleNames, state.cycleTpNames, opts.exhaustive);
TypeVarStringifier tvs{state}; TypeStringifier tvs{state};
if (!opts.exhaustive) if (!opts.exhaustive)
{ {
if (auto ttv = get<TableTypeVar>(ty); ttv && (ttv->name || ttv->syntheticName)) if (auto ttv = get<TableType>(ty); ttv && (ttv->name || ttv->syntheticName))
{ {
if (ttv->syntheticName) if (ttv->syntheticName)
result.invalid = true; result.invalid = true;
@ -1128,7 +1140,7 @@ ToStringResult toStringDetailed(TypeId ty, ToStringOptions& opts)
return result; return result;
} }
else if (auto mtv = get<MetatableTypeVar>(ty); mtv && mtv->syntheticName) else if (auto mtv = get<MetatableType>(ty); mtv && mtv->syntheticName)
{ {
result.invalid = true; result.invalid = true;
result.name = *mtv->syntheticName; result.name = *mtv->syntheticName;
@ -1213,7 +1225,7 @@ ToStringResult toStringDetailed(TypeId ty, ToStringOptions& opts)
ToStringResult toStringDetailed(TypePackId tp, 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. * 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. * 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. * 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); 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. /* If the root itself is a cycle, we special case a little.
* We go out of our way to print the following: * 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; 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<TypeId>(&tv), opts); return toString(const_cast<TypeId>(&tv), opts);
} }
@ -1299,11 +1311,11 @@ std::string toString(const TypePackVar& tp, ToStringOptions& opts)
return toString(const_cast<TypePackId>(&tp), opts); return toString(const_cast<TypePackId>(&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; ToStringResult result;
StringifierState state{opts, result}; StringifierState state{opts, result};
TypeVarStringifier tvs{state}; TypeStringifier tvs{state};
state.emit(funcName); state.emit(funcName);

View file

@ -87,7 +87,7 @@ void TxnLog::concatAsIntersections(TxnLog rhs, NotNull<TypeArena> arena)
{ {
TypeId leftTy = arena->addType((*leftRep)->pending); TypeId leftTy = arena->addType((*leftRep)->pending);
TypeId rightTy = arena->addType(rightRep->pending); TypeId rightTy = arena->addType(rightRep->pending);
typeVarChanges[ty]->pending.ty = IntersectionTypeVar{{leftTy, rightTy}}; typeVarChanges[ty]->pending.ty = IntersectionType{{leftTy, rightTy}};
} }
else else
typeVarChanges[ty] = std::move(rightRep); typeVarChanges[ty] = std::move(rightRep);
@ -105,7 +105,7 @@ void TxnLog::concatAsUnion(TxnLog rhs, NotNull<TypeArena> arena)
{ {
TypeId leftTy = arena->addType((*leftRep)->pending); TypeId leftTy = arena->addType((*leftRep)->pending);
TypeId rightTy = arena->addType(rightRep->pending); TypeId rightTy = arena->addType(rightRep->pending);
typeVarChanges[ty]->pending.ty = UnionTypeVar{{leftTy, rightTy}}; typeVarChanges[ty]->pending.ty = UnionType{{leftTy, rightTy}};
} }
else else
typeVarChanges[ty] = std::move(rightRep); typeVarChanges[ty] = std::move(rightRep);
@ -261,7 +261,7 @@ PendingTypePack* TxnLog::pending(TypePackId tp) const
return nullptr; return nullptr;
} }
PendingType* TxnLog::replace(TypeId ty, TypeVar replacement) PendingType* TxnLog::replace(TypeId ty, Type replacement)
{ {
PendingType* newTy = queue(ty); PendingType* newTy = queue(ty);
newTy->pending.reassign(replacement); newTy->pending.reassign(replacement);
@ -277,10 +277,10 @@ PendingTypePack* TxnLog::replace(TypePackId tp, TypePackVar replacement)
PendingType* TxnLog::bindTable(TypeId ty, std::optional<TypeId> newBoundTo) PendingType* TxnLog::bindTable(TypeId ty, std::optional<TypeId> newBoundTo)
{ {
LUAU_ASSERT(get<TableTypeVar>(ty)); LUAU_ASSERT(get<TableType>(ty));
PendingType* newTy = queue(ty); PendingType* newTy = queue(ty);
if (TableTypeVar* ttv = Luau::getMutable<TableTypeVar>(newTy)) if (TableType* ttv = Luau::getMutable<TableType>(newTy))
ttv->boundTo = newBoundTo; ttv->boundTo = newBoundTo;
return newTy; return newTy;
@ -288,19 +288,19 @@ PendingType* TxnLog::bindTable(TypeId ty, std::optional<TypeId> newBoundTo)
PendingType* TxnLog::changeLevel(TypeId ty, TypeLevel newLevel) PendingType* TxnLog::changeLevel(TypeId ty, TypeLevel newLevel)
{ {
LUAU_ASSERT(get<FreeTypeVar>(ty) || get<TableTypeVar>(ty) || get<FunctionTypeVar>(ty)); LUAU_ASSERT(get<FreeType>(ty) || get<TableType>(ty) || get<FunctionType>(ty));
PendingType* newTy = queue(ty); PendingType* newTy = queue(ty);
if (FreeTypeVar* ftv = Luau::getMutable<FreeTypeVar>(newTy)) if (FreeType* ftv = Luau::getMutable<FreeType>(newTy))
{ {
ftv->level = newLevel; ftv->level = newLevel;
} }
else if (TableTypeVar* ttv = Luau::getMutable<TableTypeVar>(newTy)) else if (TableType* ttv = Luau::getMutable<TableType>(newTy))
{ {
LUAU_ASSERT(ttv->state == TableState::Free || ttv->state == TableState::Generic); LUAU_ASSERT(ttv->state == TableState::Free || ttv->state == TableState::Generic);
ttv->level = newLevel; ttv->level = newLevel;
} }
else if (FunctionTypeVar* ftv = Luau::getMutable<FunctionTypeVar>(newTy)) else if (FunctionType* ftv = Luau::getMutable<FunctionType>(newTy))
{ {
ftv->level = newLevel; ftv->level = newLevel;
} }
@ -323,19 +323,19 @@ PendingTypePack* TxnLog::changeLevel(TypePackId tp, TypeLevel newLevel)
PendingType* TxnLog::changeScope(TypeId ty, NotNull<Scope> newScope) PendingType* TxnLog::changeScope(TypeId ty, NotNull<Scope> newScope)
{ {
LUAU_ASSERT(get<FreeTypeVar>(ty) || get<TableTypeVar>(ty) || get<FunctionTypeVar>(ty)); LUAU_ASSERT(get<FreeType>(ty) || get<TableType>(ty) || get<FunctionType>(ty));
PendingType* newTy = queue(ty); PendingType* newTy = queue(ty);
if (FreeTypeVar* ftv = Luau::getMutable<FreeTypeVar>(newTy)) if (FreeType* ftv = Luau::getMutable<FreeType>(newTy))
{ {
ftv->scope = newScope; ftv->scope = newScope;
} }
else if (TableTypeVar* ttv = Luau::getMutable<TableTypeVar>(newTy)) else if (TableType* ttv = Luau::getMutable<TableType>(newTy))
{ {
LUAU_ASSERT(ttv->state == TableState::Free || ttv->state == TableState::Generic); LUAU_ASSERT(ttv->state == TableState::Free || ttv->state == TableState::Generic);
ttv->scope = newScope; ttv->scope = newScope;
} }
else if (FunctionTypeVar* ftv = Luau::getMutable<FunctionTypeVar>(newTy)) else if (FunctionType* ftv = Luau::getMutable<FunctionType>(newTy))
{ {
ftv->scope = newScope; ftv->scope = newScope;
} }
@ -358,10 +358,10 @@ PendingTypePack* TxnLog::changeScope(TypePackId tp, NotNull<Scope> newScope)
PendingType* TxnLog::changeIndexer(TypeId ty, std::optional<TableIndexer> indexer) PendingType* TxnLog::changeIndexer(TypeId ty, std::optional<TableIndexer> indexer)
{ {
LUAU_ASSERT(get<TableTypeVar>(ty)); LUAU_ASSERT(get<TableType>(ty));
PendingType* newTy = queue(ty); PendingType* newTy = queue(ty);
if (TableTypeVar* ttv = Luau::getMutable<TableTypeVar>(newTy)) if (TableType* ttv = Luau::getMutable<TableType>(newTy))
{ {
ttv->indexer = indexer; ttv->indexer = indexer;
} }
@ -371,11 +371,11 @@ PendingType* TxnLog::changeIndexer(TypeId ty, std::optional<TableIndexer> indexe
std::optional<TypeLevel> TxnLog::getLevel(TypeId ty) const std::optional<TypeLevel> TxnLog::getLevel(TypeId ty) const
{ {
if (FreeTypeVar* ftv = getMutable<FreeTypeVar>(ty)) if (FreeType* ftv = getMutable<FreeType>(ty))
return ftv->level; return ftv->level;
else if (TableTypeVar* ttv = getMutable<TableTypeVar>(ty); ttv && (ttv->state == TableState::Free || ttv->state == TableState::Generic)) else if (TableType* ttv = getMutable<TableType>(ty); ttv && (ttv->state == TableState::Free || ttv->state == TableState::Generic))
return ttv->level; return ttv->level;
else if (FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(ty)) else if (FunctionType* ftv = getMutable<FunctionType>(ty))
return ftv->level; return ftv->level;
return std::nullopt; 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 // 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<> // that normally apply. This is safe because follow will only call get<>
// on the returned pointer. // on the returned pointer.
return const_cast<const TypeVar*>(&state->pending); return const_cast<const Type*>(&state->pending);
}); });
} }

File diff suppressed because it is too large Load diff

View file

@ -9,13 +9,13 @@ namespace Luau
void TypeArena::clear() void TypeArena::clear()
{ {
typeVars.clear(); types.clear();
typePacks.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; asMutable(allocated)->owningArena = this;
@ -24,7 +24,7 @@ TypeId TypeArena::addTV(TypeVar&& tv)
TypeId TypeArena::freshType(TypeLevel level) TypeId TypeArena::freshType(TypeLevel level)
{ {
TypeId allocated = typeVars.allocate(FreeTypeVar{level}); TypeId allocated = types.allocate(FreeType{level});
asMutable(allocated)->owningArena = this; asMutable(allocated)->owningArena = this;
@ -33,7 +33,7 @@ TypeId TypeArena::freshType(TypeLevel level)
TypeId TypeArena::freshType(Scope* scope) TypeId TypeArena::freshType(Scope* scope)
{ {
TypeId allocated = typeVars.allocate(FreeTypeVar{scope}); TypeId allocated = types.allocate(FreeType{scope});
asMutable(allocated)->owningArena = this; asMutable(allocated)->owningArena = this;
@ -42,7 +42,7 @@ TypeId TypeArena::freshType(Scope* scope)
TypeId TypeArena::freshType(Scope* scope, TypeLevel level) 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; asMutable(allocated)->owningArena = this;
@ -99,7 +99,7 @@ void freeze(TypeArena& arena)
if (!FFlag::DebugLuauFreezeArena) if (!FFlag::DebugLuauFreezeArena)
return; return;
arena.typeVars.freeze(); arena.types.freeze();
arena.typePacks.freeze(); arena.typePacks.freeze();
} }
@ -108,7 +108,7 @@ void unfreeze(TypeArena& arena)
if (!FFlag::DebugLuauFreezeArena) if (!FFlag::DebugLuauFreezeArena)
return; return;
arena.typeVars.unfreeze(); arena.types.unfreeze();
arena.typePacks.unfreeze(); arena.typePacks.unfreeze();
} }

View file

@ -8,7 +8,7 @@
#include "Luau/ToString.h" #include "Luau/ToString.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypePack.h" #include "Luau/TypePack.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include <string> #include <string>
@ -75,36 +75,36 @@ public:
AstTypePack* rehydrate(TypePackId tp); AstTypePack* rehydrate(TypePackId tp);
AstType* operator()(const PrimitiveTypeVar& ptv) AstType* operator()(const PrimitiveType& ptv)
{ {
switch (ptv.type) switch (ptv.type)
{ {
case PrimitiveTypeVar::NilType: case PrimitiveType::NilType:
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("nil")); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("nil"));
case PrimitiveTypeVar::Boolean: case PrimitiveType::Boolean:
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("boolean")); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("boolean"));
case PrimitiveTypeVar::Number: case PrimitiveType::Number:
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("number")); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("number"));
case PrimitiveTypeVar::String: case PrimitiveType::String:
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("string")); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("string"));
case PrimitiveTypeVar::Thread: case PrimitiveType::Thread:
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("thread")); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("thread"));
default: default:
return nullptr; return nullptr;
} }
} }
AstType* operator()(const BlockedTypeVar& btv) AstType* operator()(const BlockedType& btv)
{ {
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("*blocked*")); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("*blocked*"));
} }
AstType* operator()(const PendingExpansionTypeVar& petv) AstType* operator()(const PendingExpansionType& petv)
{ {
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("*pending-expansion*")); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("*pending-expansion*"));
} }
AstType* operator()(const SingletonTypeVar& stv) AstType* operator()(const SingletonType& stv)
{ {
if (const BooleanSingleton* bs = get<BooleanSingleton>(&stv)) if (const BooleanSingleton* bs = get<BooleanSingleton>(&stv))
return allocator->alloc<AstTypeSingletonBool>(Location(), bs->value); return allocator->alloc<AstTypeSingletonBool>(Location(), bs->value);
@ -119,11 +119,11 @@ public:
return nullptr; return nullptr;
} }
AstType* operator()(const AnyTypeVar&) AstType* operator()(const AnyType&)
{ {
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("any")); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("any"));
} }
AstType* operator()(const TableTypeVar& ttv) AstType* operator()(const TableType& ttv)
{ {
RecursionCounter counter(&count); RecursionCounter counter(&count);
@ -182,12 +182,12 @@ public:
return allocator->alloc<AstTypeTable>(Location(), props, indexer); return allocator->alloc<AstTypeTable>(Location(), props, indexer);
} }
AstType* operator()(const MetatableTypeVar& mtv) AstType* operator()(const MetatableType& mtv)
{ {
return Luau::visit(*this, mtv.table->ty); return Luau::visit(*this, mtv.table->ty);
} }
AstType* operator()(const ClassTypeVar& ctv) AstType* operator()(const ClassType& ctv)
{ {
RecursionCounter counter(&count); RecursionCounter counter(&count);
@ -214,7 +214,7 @@ public:
return allocator->alloc<AstTypeTable>(Location(), props); return allocator->alloc<AstTypeTable>(Location(), props);
} }
AstType* operator()(const FunctionTypeVar& ftv) AstType* operator()(const FunctionType& ftv)
{ {
RecursionCounter counter(&count); RecursionCounter counter(&count);
@ -227,7 +227,7 @@ public:
size_t numGenerics = 0; size_t numGenerics = 0;
for (auto it = ftv.generics.begin(); it != ftv.generics.end(); ++it) for (auto it = ftv.generics.begin(); it != ftv.generics.end(); ++it)
{ {
if (auto gtv = get<GenericTypeVar>(*it)) if (auto gtv = get<GenericType>(*it))
generics.data[numGenerics++] = {AstName(gtv->name.c_str()), Location(), nullptr}; generics.data[numGenerics++] = {AstName(gtv->name.c_str()), Location(), nullptr};
} }
@ -237,7 +237,7 @@ public:
size_t numGenericPacks = 0; size_t numGenericPacks = 0;
for (auto it = ftv.genericPacks.begin(); it != ftv.genericPacks.end(); ++it) for (auto it = ftv.genericPacks.begin(); it != ftv.genericPacks.end(); ++it)
{ {
if (auto gtv = get<GenericTypeVar>(*it)) if (auto gtv = get<GenericType>(*it))
genericPacks.data[numGenericPacks++] = {AstName(gtv->name.c_str()), Location(), nullptr}; genericPacks.data[numGenericPacks++] = {AstName(gtv->name.c_str()), Location(), nullptr};
} }
@ -292,7 +292,7 @@ public:
{ {
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("Unifiable<Error>")); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("Unifiable<Error>"));
} }
AstType* operator()(const GenericTypeVar& gtv) AstType* operator()(const GenericType& gtv)
{ {
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName(getName(allocator, syntheticNames, gtv))); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName(getName(allocator, syntheticNames, gtv)));
} }
@ -300,11 +300,11 @@ public:
{ {
return Luau::visit(*this, bound.boundTo->ty); return Luau::visit(*this, bound.boundTo->ty);
} }
AstType* operator()(const FreeTypeVar& ftv) AstType* operator()(const FreeType& ftv)
{ {
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("free")); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("free"));
} }
AstType* operator()(const UnionTypeVar& uv) AstType* operator()(const UnionType& uv)
{ {
AstArray<AstType*> unionTypes; AstArray<AstType*> unionTypes;
unionTypes.size = uv.options.size(); unionTypes.size = uv.options.size();
@ -315,7 +315,7 @@ public:
} }
return allocator->alloc<AstTypeUnion>(Location(), unionTypes); return allocator->alloc<AstTypeUnion>(Location(), unionTypes);
} }
AstType* operator()(const IntersectionTypeVar& uv) AstType* operator()(const IntersectionType& uv)
{ {
AstArray<AstType*> intersectionTypes; AstArray<AstType*> intersectionTypes;
intersectionTypes.size = uv.parts.size(); intersectionTypes.size = uv.parts.size();
@ -326,22 +326,22 @@ public:
} }
return allocator->alloc<AstTypeIntersection>(Location(), intersectionTypes); return allocator->alloc<AstTypeIntersection>(Location(), intersectionTypes);
} }
AstType* operator()(const LazyTypeVar& ltv) AstType* operator()(const LazyType& ltv)
{ {
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("<Lazy?>")); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName("<Lazy?>"));
} }
AstType* operator()(const UnknownTypeVar& ttv) AstType* operator()(const UnknownType& ttv)
{ {
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName{"unknown"}); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName{"unknown"});
} }
AstType* operator()(const NeverTypeVar& ttv) AstType* operator()(const NeverType& ttv)
{ {
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName{"never"}); return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName{"never"});
} }
AstType* operator()(const NegationTypeVar& ntv) AstType* operator()(const NegationType& ntv)
{ {
// FIXME: do the same thing we do with ErrorTypeVar // FIXME: do the same thing we do with ErrorType
throw InternalCompilerError("Cannot convert NegationTypeVar into AstNode"); throw InternalCompilerError("Cannot convert NegationType into AstNode");
} }
private: private:

View file

@ -10,7 +10,7 @@
#include "Luau/ToString.h" #include "Luau/ToString.h"
#include "Luau/TxnLog.h" #include "Luau/TxnLog.h"
#include "Luau/TypeUtils.h" #include "Luau/TypeUtils.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/Unifier.h" #include "Luau/Unifier.h"
#include "Luau/ToString.h" #include "Luau/ToString.h"
#include "Luau/DcrLogger.h" #include "Luau/DcrLogger.h"
@ -19,6 +19,7 @@
LUAU_FASTFLAG(DebugLuauLogSolverToJson); LUAU_FASTFLAG(DebugLuauLogSolverToJson);
LUAU_FASTFLAG(DebugLuauMagicTypes); LUAU_FASTFLAG(DebugLuauMagicTypes);
LUAU_FASTFLAG(LuauNegatedClassTypes)
namespace Luau namespace Luau
{ {
@ -82,19 +83,20 @@ static std::optional<std::string> getIdentifierOfBaseVar(AstExpr* node)
struct TypeChecker2 struct TypeChecker2
{ {
NotNull<SingletonTypes> singletonTypes; NotNull<BuiltinTypes> builtinTypes;
DcrLogger* logger; DcrLogger* logger;
InternalErrorReporter ice; // FIXME accept a pointer from Frontend InternalErrorReporter ice; // FIXME accept a pointer from Frontend
const SourceModule* sourceModule; const SourceModule* sourceModule;
Module* module; Module* module;
TypeArena testArena;
std::vector<NotNull<Scope>> stack; std::vector<NotNull<Scope>> stack;
UnifierSharedState sharedState{&ice}; UnifierSharedState sharedState{&ice};
Normalizer normalizer{&module->internalTypes, singletonTypes, NotNull{&sharedState}}; Normalizer normalizer{&testArena, builtinTypes, NotNull{&sharedState}};
TypeChecker2(NotNull<SingletonTypes> singletonTypes, DcrLogger* logger, const SourceModule* sourceModule, Module* module) TypeChecker2(NotNull<BuiltinTypes> builtinTypes, DcrLogger* logger, const SourceModule* sourceModule, Module* module)
: singletonTypes(singletonTypes) : builtinTypes(builtinTypes)
, logger(logger) , logger(logger)
, sourceModule(sourceModule) , sourceModule(sourceModule)
, module(module) , module(module)
@ -120,7 +122,7 @@ struct TypeChecker2
if (tp) if (tp)
return follow(*tp); return follow(*tp);
else else
return singletonTypes->anyTypePack; return builtinTypes->anyTypePack;
} }
TypeId lookupType(AstExpr* expr) TypeId lookupType(AstExpr* expr)
@ -136,7 +138,7 @@ struct TypeChecker2
if (tp) if (tp)
return flattenPack(*tp); return flattenPack(*tp);
return singletonTypes->anyType; return builtinTypes->anyType;
} }
TypeId lookupAnnotation(AstType* annotation) TypeId lookupAnnotation(AstType* annotation)
@ -298,7 +300,7 @@ struct TypeChecker2
Scope* scope = findInnermostScope(ret->location); Scope* scope = findInnermostScope(ret->location);
TypePackId expectedRetType = scope->returnType; TypePackId expectedRetType = scope->returnType;
TypeArena* arena = &module->internalTypes; TypeArena* arena = &testArena;
TypePackId actualRetType = reconstructPack(ret->list, *arena); TypePackId actualRetType = reconstructPack(ret->list, *arena);
Unifier u{NotNull{&normalizer}, Mode::Strict, stack.back(), ret->location, Covariant}; Unifier u{NotNull{&normalizer}, Mode::Strict, stack.back(), ret->location, Covariant};
@ -346,6 +348,8 @@ struct TypeChecker2
if (!errors.empty()) if (!errors.empty())
reportErrors(std::move(errors)); reportErrors(std::move(errors));
} }
visit(var->annotation);
} }
} }
else else
@ -368,6 +372,8 @@ struct TypeChecker2
ErrorVec errors = tryUnify(stack.back(), value->location, *it, varType); ErrorVec errors = tryUnify(stack.back(), value->location, *it, varType);
if (!errors.empty()) if (!errors.empty())
reportErrors(std::move(errors)); reportErrors(std::move(errors));
visit(var->annotation);
} }
++it; ++it;
@ -406,7 +412,7 @@ struct TypeChecker2
return; return;
NotNull<Scope> scope = stack.back(); NotNull<Scope> scope = stack.back();
TypeArena& arena = module->internalTypes; TypeArena& arena = testArena;
std::vector<TypeId> variableTypes; std::vector<TypeId> variableTypes;
for (AstLocal* var : forInStatement->vars) for (AstLocal* var : forInStatement->vars)
@ -425,7 +431,7 @@ struct TypeChecker2
TypePackId iteratorPack = arena.addTypePack(valueTypes, iteratorTail); TypePackId iteratorPack = arena.addTypePack(valueTypes, iteratorTail);
// ... and then expand it out to 3 values (if possible) // ... 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()) if (iteratorTypes.head.empty())
{ {
reportError(GenericError{"for..in loops require at least one value to iterate over. Got zero"}, getLocation(forInStatement->values)); 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]); TypeId iteratorTy = follow(iteratorTypes.head[0]);
auto checkFunction = [this, &arena, &scope, &forInStatement, &variableTypes]( auto checkFunction = [this, &arena, &scope, &forInStatement, &variableTypes](
const FunctionTypeVar* iterFtv, std::vector<TypeId> iterTys, bool isMm) { const FunctionType* iterFtv, std::vector<TypeId> iterTys, bool isMm) {
if (iterTys.size() < 1 || iterTys.size() > 3) if (iterTys.size() < 1 || iterTys.size() > 3)
{ {
if (isMm) if (isMm)
@ -446,7 +452,7 @@ struct TypeChecker2
} }
// It is okay if there aren't enough iterators, but the iteratee must provide enough. // 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 (expectedVariableTypes.head.size() < variableTypes.size())
{ {
if (isMm) if (isMm)
@ -478,7 +484,7 @@ struct TypeChecker2
if (maxCount && *maxCount < 2) if (maxCount && *maxCount < 2)
reportError(CountMismatch{2, std::nullopt, *maxCount, CountMismatch::Arg}, forInStatement->vars.data[0]->location); 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 firstIterationArgCount = iterTys.empty() ? 0 : iterTys.size() - 1;
size_t actualArgCount = expectedVariableTypes.head.size(); size_t actualArgCount = expectedVariableTypes.head.size();
@ -515,11 +521,11 @@ struct TypeChecker2
* nil. * nil.
* * nextTy() must be callable with only 2 arguments. * * nextTy() must be callable with only 2 arguments.
*/ */
if (const FunctionTypeVar* nextFn = get<FunctionTypeVar>(iteratorTy)) if (const FunctionType* nextFn = get<FunctionType>(iteratorTy))
{ {
checkFunction(nextFn, iteratorTypes.head, false); checkFunction(nextFn, iteratorTypes.head, false);
} }
else if (const TableTypeVar* ttv = get<TableTypeVar>(iteratorTy)) else if (const TableType* ttv = get<TableType>(iteratorTy))
{ {
if ((forInStatement->vars.size == 1 || forInStatement->vars.size == 2) && ttv->indexer) if ((forInStatement->vars.size == 1 || forInStatement->vars.size == 2) && ttv->indexer)
{ {
@ -530,23 +536,23 @@ struct TypeChecker2
else else
reportError(GenericError{"Cannot iterate over a table without indexer"}, forInStatement->values.data[0]->location); reportError(GenericError{"Cannot iterate over a table without indexer"}, forInStatement->values.data[0]->location);
} }
else if (get<AnyTypeVar>(iteratorTy) || get<ErrorTypeVar>(iteratorTy)) else if (get<AnyType>(iteratorTy) || get<ErrorType>(iteratorTy))
{ {
// nothing // nothing
} }
else if (std::optional<TypeId> iterMmTy = else if (std::optional<TypeId> 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}; Instantiation instantiation{TxnLog::empty(), &arena, TypeLevel{}, scope};
if (std::optional<TypeId> instantiatedIterMmTy = instantiation.substitute(*iterMmTy)) if (std::optional<TypeId> instantiatedIterMmTy = instantiation.substitute(*iterMmTy))
{ {
if (const FunctionTypeVar* iterMmFtv = get<FunctionTypeVar>(*instantiatedIterMmTy)) if (const FunctionType* iterMmFtv = get<FunctionType>(*instantiatedIterMmTy))
{ {
TypePackId argPack = arena.addTypePack({iteratorTy}); TypePackId argPack = arena.addTypePack({iteratorTy});
reportErrors(tryUnify(scope, forInStatement->values.data[0]->location, argPack, iterMmFtv->argTypes)); 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) if (mmIteratorTypes.head.size() == 0)
{ {
@ -561,7 +567,7 @@ struct TypeChecker2
std::vector<TypeId> instantiatedIteratorTypes = mmIteratorTypes.head; std::vector<TypeId> instantiatedIteratorTypes = mmIteratorTypes.head;
instantiatedIteratorTypes[0] = *instantiatedNextFn; instantiatedIteratorTypes[0] = *instantiatedNextFn;
if (const FunctionTypeVar* nextFtv = get<FunctionTypeVar>(*instantiatedNextFn)) if (const FunctionType* nextFtv = get<FunctionType>(*instantiatedNextFn))
{ {
checkFunction(nextFtv, instantiatedIteratorTypes, true); checkFunction(nextFtv, instantiatedIteratorTypes, true);
} }
@ -760,7 +766,7 @@ struct TypeChecker2
void visit(AstExprConstantNumber* number) void visit(AstExprConstantNumber* number)
{ {
TypeId actualType = lookupType(number); TypeId actualType = lookupType(number);
TypeId numberType = singletonTypes->numberType; TypeId numberType = builtinTypes->numberType;
if (!isSubtype(numberType, actualType, stack.back())) if (!isSubtype(numberType, actualType, stack.back()))
{ {
@ -771,7 +777,7 @@ struct TypeChecker2
void visit(AstExprConstantString* string) void visit(AstExprConstantString* string)
{ {
TypeId actualType = lookupType(string); TypeId actualType = lookupType(string);
TypeId stringType = singletonTypes->stringType; TypeId stringType = builtinTypes->stringType;
if (!isSubtype(actualType, stringType, stack.back())) if (!isSubtype(actualType, stringType, stack.back()))
{ {
@ -801,7 +807,7 @@ struct TypeChecker2
for (AstExpr* arg : call->args) for (AstExpr* arg : call->args)
visit(arg); visit(arg);
TypeArena* arena = &module->internalTypes; TypeArena* arena = &testArena;
Instantiation instantiation{TxnLog::empty(), arena, TypeLevel{}, stack.back()}; Instantiation instantiation{TxnLog::empty(), arena, TypeLevel{}, stack.back()};
TypePackId expectedRetType = lookupPack(call); TypePackId expectedRetType = lookupPack(call);
@ -809,11 +815,11 @@ struct TypeChecker2
TypeId testFunctionType = functionType; TypeId testFunctionType = functionType;
TypePack args; TypePack args;
if (get<AnyTypeVar>(functionType) || get<ErrorTypeVar>(functionType)) if (get<AnyType>(functionType) || get<ErrorType>(functionType))
return; return;
else if (std::optional<TypeId> callMm = findMetatableEntry(singletonTypes, module->errors, functionType, "__call", call->func->location)) else if (std::optional<TypeId> callMm = findMetatableEntry(builtinTypes, module->errors, functionType, "__call", call->func->location))
{ {
if (get<FunctionTypeVar>(follow(*callMm))) if (get<FunctionType>(follow(*callMm)))
{ {
if (std::optional<TypeId> instantiatedCallMm = instantiation.substitute(*callMm)) if (std::optional<TypeId> instantiatedCallMm = instantiation.substitute(*callMm))
{ {
@ -834,7 +840,7 @@ struct TypeChecker2
return; return;
} }
} }
else if (get<FunctionTypeVar>(functionType)) else if (get<FunctionType>(functionType))
{ {
if (std::optional<TypeId> instantiatedFunctionType = instantiation.substitute(functionType)) if (std::optional<TypeId> instantiatedFunctionType = instantiation.substitute(functionType))
{ {
@ -846,7 +852,7 @@ struct TypeChecker2
return; return;
} }
} }
else if (auto utv = get<UnionTypeVar>(functionType)) else if (auto utv = get<UnionType>(functionType))
{ {
// Sometimes it's okay to call a union of functions, but only if all of the functions are the same. // Sometimes it's okay to call a union of functions, but only if all of the functions are the same.
std::optional<TypeId> fst; std::optional<TypeId> fst;
@ -862,7 +868,7 @@ struct TypeChecker2
} }
if (!fst) 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<TypeId> instantiatedFunctionType = instantiation.substitute(*fst)) if (std::optional<TypeId> instantiatedFunctionType = instantiation.substitute(*fst))
{ {
@ -901,20 +907,20 @@ struct TypeChecker2
if (argTail) if (argTail)
args.tail = *argTail; args.tail = *argTail;
else else
args.tail = singletonTypes->anyTypePack; args.tail = builtinTypes->anyTypePack;
} }
else else
args.head.push_back(singletonTypes->anyType); args.head.push_back(builtinTypes->anyType);
} }
TypePackId argsTp = arena->addTypePack(args); TypePackId argsTp = arena->addTypePack(args);
FunctionTypeVar ftv{argsTp, expectedRetType}; FunctionType ftv{argsTp, expectedRetType};
TypeId expectedType = arena->addType(ftv); TypeId expectedType = arena->addType(ftv);
if (!isSubtype(testFunctionType, expectedType, stack.back())) if (!isSubtype(testFunctionType, expectedType, stack.back()))
{ {
CloneState cloneState; CloneState cloneState;
expectedType = clone(expectedType, module->internalTypes, cloneState); expectedType = clone(expectedType, testArena, cloneState);
reportError(TypeMismatch{expectedType, functionType}, call->location); reportError(TypeMismatch{expectedType, functionType}, call->location);
} }
} }
@ -942,7 +948,7 @@ struct TypeChecker2
auto StackPusher = pushStack(fn); auto StackPusher = pushStack(fn);
TypeId inferredFnTy = lookupType(fn); TypeId inferredFnTy = lookupType(fn);
const FunctionTypeVar* inferredFtv = get<FunctionTypeVar>(inferredFnTy); const FunctionType* inferredFtv = get<FunctionType>(inferredFnTy);
LUAU_ASSERT(inferredFtv); LUAU_ASSERT(inferredFtv);
auto argIt = begin(inferredFtv->argTypes); auto argIt = begin(inferredFtv->argTypes);
@ -986,24 +992,24 @@ struct TypeChecker2
NotNull<Scope> scope = stack.back(); NotNull<Scope> scope = stack.back();
TypeId operandType = lookupType(expr->expr); TypeId operandType = lookupType(expr->expr);
if (get<AnyTypeVar>(operandType) || get<ErrorTypeVar>(operandType) || get<NeverTypeVar>(operandType)) if (get<AnyType>(operandType) || get<ErrorType>(operandType) || get<NeverType>(operandType))
return; return;
if (auto it = kUnaryOpMetamethods.find(expr->op); it != kUnaryOpMetamethods.end()) if (auto it = kUnaryOpMetamethods.find(expr->op); it != kUnaryOpMetamethods.end())
{ {
std::optional<TypeId> mm = findMetatableEntry(singletonTypes, module->errors, operandType, it->second, expr->location); std::optional<TypeId> mm = findMetatableEntry(builtinTypes, module->errors, operandType, it->second, expr->location);
if (mm) if (mm)
{ {
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(*mm))) if (const FunctionType* ftv = get<FunctionType>(follow(*mm)))
{ {
TypePackId expectedArgs = module->internalTypes.addTypePack({operandType}); TypePackId expectedArgs = testArena.addTypePack({operandType});
reportErrors(tryUnify(scope, expr->location, expectedArgs, ftv->argTypes)); reportErrors(tryUnify(scope, expr->location, expectedArgs, ftv->argTypes));
if (std::optional<TypeId> ret = first(ftv->retTypes)) if (std::optional<TypeId> ret = first(ftv->retTypes))
{ {
if (expr->op == AstExprUnary::Op::Len) 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 else
@ -1028,7 +1034,7 @@ struct TypeChecker2
} }
else if (expr->op == AstExprUnary::Op::Minus) 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) else if (expr->op == AstExprUnary::Op::Not)
{ {
@ -1055,15 +1061,15 @@ struct TypeChecker2
if (expr->op == AstExprBinary::Op::Or) if (expr->op == AstExprBinary::Op::Or)
{ {
leftType = stripNil(singletonTypes, module->internalTypes, leftType); leftType = stripNil(builtinTypes, testArena, leftType);
} }
bool isStringOperation = isString(leftType) && isString(rightType); bool isStringOperation = isString(leftType) && isString(rightType);
if (get<AnyTypeVar>(leftType) || get<ErrorTypeVar>(leftType) || get<AnyTypeVar>(rightType) || get<ErrorTypeVar>(rightType)) if (get<AnyType>(leftType) || get<ErrorType>(leftType) || get<AnyType>(rightType) || get<ErrorType>(rightType))
return; return;
if ((get<BlockedTypeVar>(leftType) || get<FreeTypeVar>(leftType)) && !isEquality && !isLogical) if ((get<BlockedType>(leftType) || get<FreeType>(leftType)) && !isEquality && !isLogical)
{ {
auto name = getIdentifierOfBaseVar(expr->left); auto name = getIdentifierOfBaseVar(expr->left);
reportError(CannotInferBinaryOperation{expr->op, name, reportError(CannotInferBinaryOperation{expr->op, name,
@ -1074,16 +1080,16 @@ struct TypeChecker2
if (auto it = kBinaryOpMetamethods.find(expr->op); it != kBinaryOpMetamethods.end()) if (auto it = kBinaryOpMetamethods.find(expr->op); it != kBinaryOpMetamethods.end())
{ {
std::optional<TypeId> leftMt = getMetatable(leftType, singletonTypes); std::optional<TypeId> leftMt = getMetatable(leftType, builtinTypes);
std::optional<TypeId> rightMt = getMetatable(rightType, singletonTypes); std::optional<TypeId> rightMt = getMetatable(rightType, builtinTypes);
bool matches = leftMt == rightMt; bool matches = leftMt == rightMt;
if (isEquality && !matches) if (isEquality && !matches)
{ {
auto testUnion = [&matches, singletonTypes = this->singletonTypes](const UnionTypeVar* utv, std::optional<TypeId> otherMt) { auto testUnion = [&matches, builtinTypes = this->builtinTypes](const UnionType* utv, std::optional<TypeId> otherMt) {
for (TypeId option : utv) for (TypeId option : utv)
{ {
if (getMetatable(follow(option), singletonTypes) == otherMt) if (getMetatable(follow(option), builtinTypes) == otherMt)
{ {
matches = true; matches = true;
break; break;
@ -1091,12 +1097,12 @@ struct TypeChecker2
} }
}; };
if (const UnionTypeVar* utv = get<UnionTypeVar>(leftType); utv && rightMt) if (const UnionType* utv = get<UnionType>(leftType); utv && rightMt)
{ {
testUnion(utv, rightMt); testUnion(utv, rightMt);
} }
if (const UnionTypeVar* utv = get<UnionTypeVar>(rightType); utv && leftMt && !matches) if (const UnionType* utv = get<UnionType>(rightType); utv && leftMt && !matches)
{ {
testUnion(utv, leftMt); testUnion(utv, leftMt);
} }
@ -1112,9 +1118,9 @@ struct TypeChecker2
} }
std::optional<TypeId> mm; std::optional<TypeId> mm;
if (std::optional<TypeId> leftMm = findMetatableEntry(singletonTypes, module->errors, leftType, it->second, expr->left->location)) if (std::optional<TypeId> leftMm = findMetatableEntry(builtinTypes, module->errors, leftType, it->second, expr->left->location))
mm = leftMm; mm = leftMm;
else if (std::optional<TypeId> rightMm = findMetatableEntry(singletonTypes, module->errors, rightType, it->second, expr->right->location)) else if (std::optional<TypeId> rightMm = findMetatableEntry(builtinTypes, module->errors, rightType, it->second, expr->right->location))
{ {
mm = rightMm; mm = rightMm;
std::swap(leftType, rightType); std::swap(leftType, rightType);
@ -1126,18 +1132,18 @@ struct TypeChecker2
if (!instantiatedMm) if (!instantiatedMm)
reportError(CodeTooComplex{}, expr->location); reportError(CodeTooComplex{}, expr->location);
else if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(instantiatedMm))) else if (const FunctionType* ftv = get<FunctionType>(follow(instantiatedMm)))
{ {
TypePackId expectedArgs; TypePackId expectedArgs;
// For >= and > we invoke __lt and __le respectively with // For >= and > we invoke __lt and __le respectively with
// swapped argument ordering. // swapped argument ordering.
if (expr->op == AstExprBinary::Op::CompareGe || expr->op == AstExprBinary::Op::CompareGt) if (expr->op == AstExprBinary::Op::CompareGe || expr->op == AstExprBinary::Op::CompareGt)
{ {
expectedArgs = module->internalTypes.addTypePack({rightType, leftType}); expectedArgs = testArena.addTypePack({rightType, leftType});
} }
else else
{ {
expectedArgs = module->internalTypes.addTypePack({leftType, rightType}); expectedArgs = testArena.addTypePack({leftType, rightType});
} }
reportErrors(tryUnify(scope, expr->location, ftv->argTypes, expectedArgs)); 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 || 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) 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)) if (!isSubtype(ftv->retTypes, expectedRets, scope))
{ {
reportError(GenericError{format("Metamethod '%s' must return type 'boolean'", it->second)}, expr->location); reportError(GenericError{format("Metamethod '%s' must return type 'boolean'", it->second)}, expr->location);
@ -1186,7 +1192,7 @@ struct TypeChecker2
return; return;
} }
else if (!leftMt && !rightMt && (get<TableTypeVar>(leftType) || get<TableTypeVar>(rightType))) else if (!leftMt && !rightMt && (get<TableType>(leftType) || get<TableType>(rightType)))
{ {
if (isComparison) if (isComparison)
{ {
@ -1214,13 +1220,13 @@ struct TypeChecker2
case AstExprBinary::Op::Div: case AstExprBinary::Op::Div:
case AstExprBinary::Op::Pow: case AstExprBinary::Op::Pow:
case AstExprBinary::Op::Mod: case AstExprBinary::Op::Mod:
reportErrors(tryUnify(scope, expr->left->location, leftType, singletonTypes->numberType)); reportErrors(tryUnify(scope, expr->left->location, leftType, builtinTypes->numberType));
reportErrors(tryUnify(scope, expr->right->location, rightType, singletonTypes->numberType)); reportErrors(tryUnify(scope, expr->right->location, rightType, builtinTypes->numberType));
break; break;
case AstExprBinary::Op::Concat: case AstExprBinary::Op::Concat:
reportErrors(tryUnify(scope, expr->left->location, leftType, singletonTypes->stringType)); reportErrors(tryUnify(scope, expr->left->location, leftType, builtinTypes->stringType));
reportErrors(tryUnify(scope, expr->right->location, rightType, singletonTypes->stringType)); reportErrors(tryUnify(scope, expr->right->location, rightType, builtinTypes->stringType));
break; break;
case AstExprBinary::Op::CompareGe: case AstExprBinary::Op::CompareGe:
@ -1228,9 +1234,9 @@ struct TypeChecker2
case AstExprBinary::Op::CompareLe: case AstExprBinary::Op::CompareLe:
case AstExprBinary::Op::CompareLt: case AstExprBinary::Op::CompareLt:
if (isNumber(leftType)) 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)) else if (isString(leftType))
reportErrors(tryUnify(scope, expr->right->location, rightType, singletonTypes->stringType)); reportErrors(tryUnify(scope, expr->right->location, rightType, builtinTypes->stringType));
else else
reportError(GenericError{format("Types '%s' and '%s' cannot be compared with relational operator %s", toString(leftType).c_str(), 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())}, toString(rightType).c_str(), toString(expr->op).c_str())},
@ -1304,8 +1310,8 @@ struct TypeChecker2
return vtp->ty; return vtp->ty;
else if (auto ftp = get<FreeTypePack>(pack)) else if (auto ftp = get<FreeTypePack>(pack))
{ {
TypeId result = module->internalTypes.addType(FreeTypeVar{ftp->scope}); TypeId result = testArena.addType(FreeType{ftp->scope});
TypePackId freeTail = module->internalTypes.addTypePack(FreeTypePack{ftp->scope}); TypePackId freeTail = testArena.addTypePack(FreeTypePack{ftp->scope});
TypePack& resultPack = asMutable(pack)->ty.emplace<TypePack>(); TypePack& resultPack = asMutable(pack)->ty.emplace<TypePack>();
resultPack.head.assign(1, result); resultPack.head.assign(1, result);
@ -1314,7 +1320,7 @@ struct TypeChecker2
return result; return result;
} }
else if (get<Unifiable::Error>(pack)) else if (get<Unifiable::Error>(pack))
return singletonTypes->errorRecoveryType(); return builtinTypes->errorRecoveryType();
else else
ice.ice("flattenPack got a weird pack!"); ice.ice("flattenPack got a weird pack!");
} }
@ -1337,6 +1343,11 @@ struct TypeChecker2
void visit(AstTypeReference* ty) 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) for (const AstTypeOrPack& param : ty->parameters)
{ {
if (param.type) if (param.type)
@ -1613,18 +1624,29 @@ struct TypeChecker2
fetch(norm.tops); fetch(norm.tops);
fetch(norm.booleans); 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.errors);
fetch(norm.nils); fetch(norm.nils);
fetch(norm.numbers); fetch(norm.numbers);
if (!norm.strings.isNever()) if (!norm.strings.isNever())
fetch(singletonTypes->stringType); fetch(builtinTypes->stringType);
fetch(norm.threads); fetch(norm.threads);
for (TypeId ty : norm.tables) for (TypeId ty : norm.tables)
fetch(ty); fetch(ty);
if (norm.functions.isTop) if (norm.functions.isTop)
fetch(singletonTypes->functionType); fetch(builtinTypes->functionType);
else if (!norm.functions.isNever()) else if (!norm.functions.isNever())
{ {
if (norm.functions.parts->size() == 1) if (norm.functions.parts->size() == 1)
@ -1633,15 +1655,15 @@ struct TypeChecker2
{ {
std::vector<TypeId> parts; std::vector<TypeId> parts;
parts.insert(parts.end(), norm.functions.parts->begin(), norm.functions.parts->end()); 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) for (const auto& [tyvar, intersect] : norm.tyvars)
{ {
if (get<NeverTypeVar>(intersect->tops)) if (get<NeverType>(intersect->tops))
{ {
TypeId ty = normalizer.typeFromNormal(*intersect); TypeId ty = normalizer.typeFromNormal(*intersect);
fetch(module->internalTypes.addType(IntersectionTypeVar{{tyvar, ty}})); fetch(testArena.addType(IntersectionType{{tyvar, ty}}));
} }
else else
fetch(tyvar); fetch(tyvar);
@ -1658,23 +1680,23 @@ struct TypeChecker2
bool hasIndexTypeFromType(TypeId ty, const std::string& prop, const Location& location) bool hasIndexTypeFromType(TypeId ty, const std::string& prop, const Location& location)
{ {
if (get<ErrorTypeVar>(ty) || get<AnyTypeVar>(ty) || get<NeverTypeVar>(ty)) if (get<ErrorType>(ty) || get<AnyType>(ty) || get<NeverType>(ty))
return true; return true;
if (isString(ty)) if (isString(ty))
{ {
std::optional<TypeId> mtIndex = Luau::findMetatableEntry(singletonTypes, module->errors, singletonTypes->stringType, "__index", location); std::optional<TypeId> mtIndex = Luau::findMetatableEntry(builtinTypes, module->errors, builtinTypes->stringType, "__index", location);
LUAU_ASSERT(mtIndex); LUAU_ASSERT(mtIndex);
ty = *mtIndex; ty = *mtIndex;
} }
if (getTableType(ty)) if (getTableType(ty))
return bool(findTablePropertyRespectingMeta(singletonTypes, module->errors, ty, prop, location)); return bool(findTablePropertyRespectingMeta(builtinTypes, module->errors, ty, prop, location));
else if (const ClassTypeVar* cls = get<ClassTypeVar>(ty)) else if (const ClassType* cls = get<ClassType>(ty))
return bool(lookupClassProp(cls, prop)); return bool(lookupClassProp(cls, prop));
else if (const UnionTypeVar* utv = get<UnionTypeVar>(ty)) else if (const UnionType* utv = get<UnionType>(ty))
ice.ice("getIndexTypeFromTypeHelper cannot take a UnionTypeVar"); ice.ice("getIndexTypeFromTypeHelper cannot take a UnionType");
else if (const IntersectionTypeVar* itv = get<IntersectionTypeVar>(ty)) else if (const IntersectionType* itv = get<IntersectionType>(ty))
return std::any_of(begin(itv), end(itv), [&](TypeId part) { return std::any_of(begin(itv), end(itv), [&](TypeId part) {
return hasIndexTypeFromType(part, prop, location); return hasIndexTypeFromType(part, prop, location);
}); });
@ -1683,11 +1705,15 @@ struct TypeChecker2
} }
}; };
void check(NotNull<SingletonTypes> singletonTypes, DcrLogger* logger, const SourceModule& sourceModule, Module* module) void check(NotNull<BuiltinTypes> builtinTypes, DcrLogger* logger, const SourceModule& sourceModule, Module* module)
{ {
TypeChecker2 typeChecker{singletonTypes, logger, &sourceModule, module}; TypeChecker2 typeChecker{builtinTypes, logger, &sourceModule, module};
typeChecker.visit(sourceModule.root); typeChecker.visit(sourceModule.root);
unfreeze(module->interfaceTypes);
copyErrors(module->errors, module->interfaceTypes);
freeze(module->interfaceTypes);
} }
} // namespace Luau } // namespace Luau

File diff suppressed because it is too large Load diff

View file

@ -237,7 +237,7 @@ TypePackId follow(TypePackId tp, std::function<TypePackId(TypePackId)> mapper)
cycleTester = nullptr; cycleTester = nullptr;
if (tp == cycleTester) 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) while (it != endIt)
{ {
if (get<NeverTypeVar>(follow(*it))) if (get<NeverType>(follow(*it)))
return true; return true;
++it; ++it;
} }
if (auto tail = it.tail()) if (auto tail = it.tail())
{ {
if (auto vtp = get<VariadicTypePack>(*tail); vtp && get<NeverTypeVar>(follow(vtp->ty))) if (auto vtp = get<VariadicTypePack>(*tail); vtp && get<NeverType>(follow(vtp->ty)))
return true; return true;
} }

View file

@ -12,20 +12,20 @@ namespace Luau
{ {
std::optional<TypeId> findMetatableEntry( std::optional<TypeId> findMetatableEntry(
NotNull<SingletonTypes> singletonTypes, ErrorVec& errors, TypeId type, const std::string& entry, Location location) NotNull<BuiltinTypes> builtinTypes, ErrorVec& errors, TypeId type, const std::string& entry, Location location)
{ {
type = follow(type); type = follow(type);
std::optional<TypeId> metatable = getMetatable(type, singletonTypes); std::optional<TypeId> metatable = getMetatable(type, builtinTypes);
if (!metatable) if (!metatable)
return std::nullopt; return std::nullopt;
TypeId unwrapped = follow(*metatable); TypeId unwrapped = follow(*metatable);
if (get<AnyTypeVar>(unwrapped)) if (get<AnyType>(unwrapped))
return singletonTypes->anyType; return builtinTypes->anyType;
const TableTypeVar* mtt = getTableType(unwrapped); const TableType* mtt = getTableType(unwrapped);
if (!mtt) if (!mtt)
{ {
errors.push_back(TypeError{location, GenericError{"Metatable was not a table"}}); errors.push_back(TypeError{location, GenericError{"Metatable was not a table"}});
@ -40,19 +40,19 @@ std::optional<TypeId> findMetatableEntry(
} }
std::optional<TypeId> findTablePropertyRespectingMeta( std::optional<TypeId> findTablePropertyRespectingMeta(
NotNull<SingletonTypes> singletonTypes, ErrorVec& errors, TypeId ty, const std::string& name, Location location) NotNull<BuiltinTypes> builtinTypes, ErrorVec& errors, TypeId ty, const std::string& name, Location location)
{ {
if (get<AnyTypeVar>(ty)) if (get<AnyType>(ty))
return ty; return ty;
if (const TableTypeVar* tableType = getTableType(ty)) if (const TableType* tableType = getTableType(ty))
{ {
const auto& it = tableType->props.find(name); const auto& it = tableType->props.find(name);
if (it != tableType->props.end()) if (it != tableType->props.end())
return it->second.type; return it->second.type;
} }
std::optional<TypeId> mtIndex = findMetatableEntry(singletonTypes, errors, ty, "__index", location); std::optional<TypeId> mtIndex = findMetatableEntry(builtinTypes, errors, ty, "__index", location);
int count = 0; int count = 0;
while (mtIndex) while (mtIndex)
{ {
@ -69,20 +69,20 @@ std::optional<TypeId> findTablePropertyRespectingMeta(
if (fit != itt->props.end()) if (fit != itt->props.end())
return fit->second.type; return fit->second.type;
} }
else if (const auto& itf = get<FunctionTypeVar>(index)) else if (const auto& itf = get<FunctionType>(index))
{ {
std::optional<TypeId> r = first(follow(itf->retTypes)); std::optional<TypeId> r = first(follow(itf->retTypes));
if (!r) if (!r)
return singletonTypes->nilType; return builtinTypes->nilType;
else else
return *r; return *r;
} }
else if (get<AnyTypeVar>(index)) else if (get<AnyType>(index))
return singletonTypes->anyType; return builtinTypes->anyType;
else else
errors.push_back(TypeError{location, GenericError{"__index should either be a function or table. Got " + toString(index)}}); 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; return std::nullopt;
@ -117,7 +117,7 @@ std::pair<size_t, std::optional<size_t>> getParameterExtents(const TxnLog* log,
return {minCount, minCount + optionalCount}; return {minCount, minCount + optionalCount};
} }
TypePack extendTypePack(TypeArena& arena, NotNull<SingletonTypes> singletonTypes, TypePackId pack, size_t length) TypePack extendTypePack(TypeArena& arena, NotNull<BuiltinTypes> builtinTypes, TypePackId pack, size_t length)
{ {
TypePack result; TypePack result;
@ -193,7 +193,7 @@ TypePack extendTypePack(TypeArena& arena, NotNull<SingletonTypes> singletonTypes
else if (const Unifiable::Error* etp = getMutable<Unifiable::Error>(pack)) else if (const Unifiable::Error* etp = getMutable<Unifiable::Error>(pack))
{ {
while (result.head.size() < length) while (result.head.size() < length)
result.head.push_back(singletonTypes->errorRecoveryType()); result.head.push_back(builtinTypes->errorRecoveryType());
result.tail = pack; result.tail = pack;
return result; return result;
@ -214,20 +214,20 @@ std::vector<TypeId> reduceUnion(const std::vector<TypeId>& types)
for (TypeId t : types) for (TypeId t : types)
{ {
t = follow(t); t = follow(t);
if (get<NeverTypeVar>(t)) if (get<NeverType>(t))
continue; continue;
if (get<ErrorTypeVar>(t) || get<AnyTypeVar>(t)) if (get<ErrorType>(t) || get<AnyType>(t))
return {t}; return {t};
if (const UnionTypeVar* utv = get<UnionTypeVar>(t)) if (const UnionType* utv = get<UnionType>(t))
{ {
for (TypeId ty : utv) for (TypeId ty : utv)
{ {
ty = follow(ty); ty = follow(ty);
if (get<NeverTypeVar>(ty)) if (get<NeverType>(ty))
continue; continue;
if (get<ErrorTypeVar>(ty) || get<AnyTypeVar>(ty)) if (get<ErrorType>(ty) || get<AnyType>(ty))
return {ty}; return {ty};
if (result.end() == std::find(result.begin(), result.end(), ty)) if (result.end() == std::find(result.begin(), result.end(), ty))
@ -243,7 +243,7 @@ std::vector<TypeId> reduceUnion(const std::vector<TypeId>& types)
static std::optional<TypeId> tryStripUnionFromNil(TypeArena& arena, TypeId ty) static std::optional<TypeId> tryStripUnionFromNil(TypeArena& arena, TypeId ty)
{ {
if (const UnionTypeVar* utv = get<UnionTypeVar>(ty)) if (const UnionType* utv = get<UnionType>(ty))
{ {
if (!std::any_of(begin(utv), end(utv), isNil)) if (!std::any_of(begin(utv), end(utv), isNil))
return ty; return ty;
@ -259,23 +259,23 @@ static std::optional<TypeId> tryStripUnionFromNil(TypeArena& arena, TypeId ty)
if (result.empty()) if (result.empty())
return std::nullopt; 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; return std::nullopt;
} }
TypeId stripNil(NotNull<SingletonTypes> singletonTypes, TypeArena& arena, TypeId ty) TypeId stripNil(NotNull<BuiltinTypes> builtinTypes, TypeArena& arena, TypeId ty)
{ {
ty = follow(ty); ty = follow(ty);
if (get<UnionTypeVar>(ty)) if (get<UnionType>(ty))
{ {
std::optional<TypeId> cleaned = tryStripUnionFromNil(arena, ty); std::optional<TypeId> cleaned = tryStripUnionFromNil(arena, ty);
// If there is no union option without 'nil' // If there is no union option without 'nil'
if (!cleaned) if (!cleaned)
return singletonTypes->nilType; return builtinTypes->nilType;
return follow(*cleaned); return follow(*cleaned);
} }

File diff suppressed because it is too large Load diff

View file

@ -5,8 +5,8 @@ namespace Luau
{ {
Position::Position(unsigned int line, unsigned int column) Position::Position(unsigned int line, unsigned int column)
: line(line) : line(line)
, column(column) , column(column)
{ {
} }

View file

@ -107,6 +107,8 @@ public:
void vmulsd(OperandX64 dst, OperandX64 src1, OperandX64 src2); void vmulsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
void vdivsd(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 vxorpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
void vucomisd(OperandX64 src1, OperandX64 src2); void vucomisd(OperandX64 src1, OperandX64 src2);
@ -129,6 +131,11 @@ public:
void vmovaps(OperandX64 dst, OperandX64 src); void vmovaps(OperandX64 dst, OperandX64 src);
void vmovupd(OperandX64 dst, OperandX64 src); void vmovupd(OperandX64 dst, OperandX64 src);
void vmovups(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 // Run final checks
void finalize(); void finalize();

View file

@ -614,6 +614,11 @@ void AssemblyBuilderX64::vdivsd(OperandX64 dst, OperandX64 src1, OperandX64 src2
placeAvx("vdivsd", dst, src1, src2, 0x5e, false, AVX_0F, AVX_F2); 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) void AssemblyBuilderX64::vxorpd(OperandX64 dst, OperandX64 src1, OperandX64 src2)
{ {
placeAvx("vxorpd", dst, src1, src2, 0x57, false, AVX_0F, AVX_66); 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); 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() void AssemblyBuilderX64::finalize()
{ {
code.resize(codePos - code.data()); code.resize(codePos - code.data());

View file

@ -5,6 +5,7 @@
#include "Luau/Bytecode.h" #include "Luau/Bytecode.h"
#include "EmitCommonX64.h" #include "EmitCommonX64.h"
#include "NativeState.h"
#include "lstate.h" #include "lstate.h"
@ -88,6 +89,341 @@ BuiltinImplResult emitBuiltinMathSqrt(AssemblyBuilderX64& build, int nparams, in
return {BuiltinImplType::UsesFallback, 1}; 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) BuiltinImplResult emitBuiltin(AssemblyBuilderX64& build, int bfid, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{ {
switch (bfid) switch (bfid)
@ -100,6 +436,46 @@ BuiltinImplResult emitBuiltin(AssemblyBuilderX64& build, int bfid, int nparams,
return emitBuiltinMathCeil(build, nparams, ra, arg, args, nresults, fallback); return emitBuiltinMathCeil(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_SQRT: case LBF_MATH_SQRT:
return emitBuiltinMathSqrt(build, nparams, ra, arg, args, nresults, fallback); 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: default:
return {BuiltinImplType::None, -1}; return {BuiltinImplType::None, -1};
} }

View file

@ -612,4 +612,3 @@ const Instruction* execute_LOP_BREAK(lua_State* L, const Instruction* pc, StkId
LUAU_ASSERT(!"Unsupported deprecated opcode"); LUAU_ASSERT(!"Unsupported deprecated opcode");
LUAU_UNREACHABLE(); LUAU_UNREACHABLE();
} }

View file

@ -80,7 +80,23 @@ void initHelperFunctions(NativeState& data)
data.context.luaF_close = luaF_close; data.context.luaF_close = luaF_close;
data.context.libm_exp = exp;
data.context.libm_pow = pow; 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.forgLoopNodeIter = forgLoopNodeIter;
data.context.forgLoopNonTableFallback = forgLoopNonTableFallback; data.context.forgLoopNonTableFallback = forgLoopNonTableFallback;

View file

@ -78,7 +78,22 @@ struct NativeContext
void (*luaF_close)(lua_State* L, StkId level) = nullptr; void (*luaF_close)(lua_State* L, StkId level) = nullptr;
double (*libm_exp)(double) = nullptr;
double (*libm_pow)(double, 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 // Helper functions
bool (*forgLoopNodeIter)(lua_State* L, Table* h, int index, TValue* ra) = nullptr; bool (*forgLoopNodeIter)(lua_State* L, Table* h, int index, TValue* ra) = nullptr;

View file

@ -350,7 +350,7 @@ struct Compiler
{ {
LUAU_ASSERT(!multRet || unsigned(target + targetCount) == regTop); 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); bytecode.emitABC(LOP_GETVARARGS, target, multRet ? 0 : uint8_t(targetCount + 1), 0);
} }

View file

@ -147,12 +147,12 @@ target_sources(Luau.Analysis PRIVATE
Analysis/include/Luau/TypeInfer.h Analysis/include/Luau/TypeInfer.h
Analysis/include/Luau/TypePack.h Analysis/include/Luau/TypePack.h
Analysis/include/Luau/TypeUtils.h Analysis/include/Luau/TypeUtils.h
Analysis/include/Luau/TypeVar.h Analysis/include/Luau/Type.h
Analysis/include/Luau/Unifiable.h Analysis/include/Luau/Unifiable.h
Analysis/include/Luau/Unifier.h Analysis/include/Luau/Unifier.h
Analysis/include/Luau/UnifierSharedState.h Analysis/include/Luau/UnifierSharedState.h
Analysis/include/Luau/Variant.h Analysis/include/Luau/Variant.h
Analysis/include/Luau/VisitTypeVar.h Analysis/include/Luau/VisitType.h
Analysis/src/Anyification.cpp Analysis/src/Anyification.cpp
Analysis/src/ApplyTypeFunction.cpp Analysis/src/ApplyTypeFunction.cpp
@ -196,7 +196,7 @@ target_sources(Luau.Analysis PRIVATE
Analysis/src/TypeInfer.cpp Analysis/src/TypeInfer.cpp
Analysis/src/TypePack.cpp Analysis/src/TypePack.cpp
Analysis/src/TypeUtils.cpp Analysis/src/TypeUtils.cpp
Analysis/src/TypeVar.cpp Analysis/src/Type.cpp
Analysis/src/Unifiable.cpp Analysis/src/Unifiable.cpp
Analysis/src/Unifier.cpp Analysis/src/Unifier.cpp
) )
@ -366,7 +366,7 @@ if(TARGET Luau.UnitTest)
tests/TypePack.test.cpp tests/TypePack.test.cpp
tests/TypeVar.test.cpp tests/TypeVar.test.cpp
tests/Variant.test.cpp tests/Variant.test.cpp
tests/VisitTypeVar.test.cpp tests/VisitType.test.cpp
tests/main.cpp) tests/main.cpp)
endif() endif()

View file

@ -101,32 +101,32 @@ int registerTypes(Luau::TypeChecker& env)
TypeArena& arena = env.globalTypes; TypeArena& arena = env.globalTypes;
// Vector3 stub // Vector3 stub
TypeId vector3MetaType = arena.addType(TableTypeVar{}); TypeId vector3MetaType = arena.addType(TableType{});
TypeId vector3InstanceType = arena.addType(ClassTypeVar{"Vector3", {}, nullopt, vector3MetaType, {}, {}, "Test"}); TypeId vector3InstanceType = arena.addType(ClassType{"Vector3", {}, nullopt, vector3MetaType, {}, {}, "Test"});
getMutable<ClassTypeVar>(vector3InstanceType)->props = { getMutable<ClassType>(vector3InstanceType)->props = {
{"X", {env.numberType}}, {"X", {env.numberType}},
{"Y", {env.numberType}}, {"Y", {env.numberType}},
{"Z", {env.numberType}}, {"Z", {env.numberType}},
}; };
getMutable<TableTypeVar>(vector3MetaType)->props = { getMutable<TableType>(vector3MetaType)->props = {
{"__add", {makeFunction(arena, nullopt, {vector3InstanceType, vector3InstanceType}, {vector3InstanceType})}}, {"__add", {makeFunction(arena, nullopt, {vector3InstanceType, vector3InstanceType}, {vector3InstanceType})}},
}; };
env.globalScope->exportedTypeBindings["Vector3"] = TypeFun{{}, vector3InstanceType}; env.globalScope->exportedTypeBindings["Vector3"] = TypeFun{{}, vector3InstanceType};
// Instance stub // Instance stub
TypeId instanceType = arena.addType(ClassTypeVar{"Instance", {}, nullopt, nullopt, {}, {}, "Test"}); TypeId instanceType = arena.addType(ClassType{"Instance", {}, nullopt, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(instanceType)->props = { getMutable<ClassType>(instanceType)->props = {
{"Name", {env.stringType}}, {"Name", {env.stringType}},
}; };
env.globalScope->exportedTypeBindings["Instance"] = TypeFun{{}, instanceType}; env.globalScope->exportedTypeBindings["Instance"] = TypeFun{{}, instanceType};
// Part stub // Part stub
TypeId partType = arena.addType(ClassTypeVar{"Part", {}, instanceType, nullopt, {}, {}, "Test"}); TypeId partType = arena.addType(ClassType{"Part", {}, instanceType, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(partType)->props = { getMutable<ClassType>(partType)->props = {
{"Position", {vector3InstanceType}}, {"Position", {vector3InstanceType}},
}; };

View file

@ -436,6 +436,11 @@ TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXBinaryInstructionForms")
SINGLE_COMPARE(vdivsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x5e, 0xc6); SINGLE_COMPARE(vdivsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x5e, 0xc6);
SINGLE_COMPARE(vxorpd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x29, 0x57, 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") 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(xmm8, xmmword[r9]), 0xc4, 0x41, 0x78, 0x10, 0x01);
SINGLE_COMPARE(vmovups(xmmword[r9], xmm10), 0xc4, 0x41, 0x78, 0x11, 0x11); SINGLE_COMPARE(vmovups(xmmword[r9], xmm10), 0xc4, 0x41, 0x78, 0x11, 0x11);
SINGLE_COMPARE(vmovups(ymm8, ymmword[r9]), 0xc4, 0x41, 0x7c, 0x10, 0x01); 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") TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXConversionInstructionForms")

View file

@ -2,8 +2,8 @@
#include "Luau/Autocomplete.h" #include "Luau/Autocomplete.h"
#include "Luau/BuiltinDefinitions.h" #include "Luau/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/VisitTypeVar.h" #include "Luau/VisitType.h"
#include "Luau/StringUtils.h" #include "Luau/StringUtils.h"
#include "Fixture.h" #include "Fixture.h"
@ -18,7 +18,7 @@ LUAU_FASTFLAG(LuauSetMetatableDoesNotTimeTravel)
using namespace Luau; using namespace Luau;
static std::optional<AutocompleteEntryMap> nullCallback(std::string tag, std::optional<const ClassTypeVar*> ptr) static std::optional<AutocompleteEntryMap> nullCallback(std::string tag, std::optional<const ClassType*> ptr)
{ {
return std::nullopt; return std::nullopt;
} }
@ -499,7 +499,7 @@ TEST_CASE_FIXTURE(ACFixture, "bias_toward_inner_scope")
CHECK_EQ(ac.context, AutocompleteContext::Statement); CHECK_EQ(ac.context, AutocompleteContext::Statement);
TypeId t = follow(*ac.entryMap["A"].type); TypeId t = follow(*ac.entryMap["A"].type);
const TableTypeVar* tt = get<TableTypeVar>(t); const TableType* tt = get<TableType>(t);
REQUIRE(tt); REQUIRE(tt);
CHECK(tt->props.count("two")); CHECK(tt->props.count("two"));
@ -1244,7 +1244,7 @@ end
REQUIRE(ac.entryMap.count("Table")); REQUIRE(ac.entryMap.count("Table"));
REQUIRE(ac.entryMap["Table"].type); REQUIRE(ac.entryMap["Table"].type);
const TableTypeVar* tv = get<TableTypeVar>(follow(*ac.entryMap["Table"].type)); const TableType* tv = get<TableType>(follow(*ac.entryMap["Table"].type));
REQUIRE(tv); REQUIRE(tv);
CHECK(tv->props.count("x")); CHECK(tv->props.count("x"));
} }

View file

@ -1,6 +1,6 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details // 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/BuiltinDefinitions.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Fixture.h" #include "Fixture.h"
@ -22,12 +22,12 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "lib_documentation_symbols")
CHECK_MESSAGE( CHECK_MESSAGE(
actualRootSymbol == expectedRootSymbol, "expected symbol ", expectedRootSymbol, " for global ", nameString, ", got ", actualRootSymbol); actualRootSymbol == expectedRootSymbol, "expected symbol ", expectedRootSymbol, " for global ", nameString, ", got ", actualRootSymbol);
const TableTypeVar::Props* props = nullptr; const TableType::Props* props = nullptr;
if (const TableTypeVar* ttv = get<TableTypeVar>(binding.typeId)) if (const TableType* ttv = get<TableType>(binding.typeId))
{ {
props = &ttv->props; props = &ttv->props;
} }
else if (const ClassTypeVar* ctv = get<ClassTypeVar>(binding.typeId)) else if (const ClassType* ctv = get<ClassType>(binding.typeId))
{ {
props = &ctv->props; props = &ctv->props;
} }

View file

@ -16,14 +16,14 @@ ClassFixture::ClassFixture()
unfreeze(arena); unfreeze(arena);
TypeId baseClassInstanceType = arena.addType(ClassTypeVar{"BaseClass", {}, nullopt, nullopt, {}, {}, "Test"}); TypeId baseClassInstanceType = arena.addType(ClassType{"BaseClass", {}, nullopt, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(baseClassInstanceType)->props = { getMutable<ClassType>(baseClassInstanceType)->props = {
{"BaseMethod", {makeFunction(arena, baseClassInstanceType, {numberType}, {})}}, {"BaseMethod", {makeFunction(arena, baseClassInstanceType, {numberType}, {})}},
{"BaseField", {numberType}}, {"BaseField", {numberType}},
}; };
TypeId baseClassType = arena.addType(ClassTypeVar{"BaseClass", {}, nullopt, nullopt, {}, {}, "Test"}); TypeId baseClassType = arena.addType(ClassType{"BaseClass", {}, nullopt, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(baseClassType)->props = { getMutable<ClassType>(baseClassType)->props = {
{"StaticMethod", {makeFunction(arena, nullopt, {}, {numberType})}}, {"StaticMethod", {makeFunction(arena, nullopt, {}, {numberType})}},
{"Clone", {makeFunction(arena, nullopt, {baseClassInstanceType}, {baseClassInstanceType})}}, {"Clone", {makeFunction(arena, nullopt, {baseClassInstanceType}, {baseClassInstanceType})}},
{"New", {makeFunction(arena, nullopt, {}, {baseClassInstanceType})}}, {"New", {makeFunction(arena, nullopt, {}, {baseClassInstanceType})}},
@ -31,75 +31,75 @@ ClassFixture::ClassFixture()
typeChecker.globalScope->exportedTypeBindings["BaseClass"] = TypeFun{{}, baseClassInstanceType}; typeChecker.globalScope->exportedTypeBindings["BaseClass"] = TypeFun{{}, baseClassInstanceType};
addGlobalBinding(frontend, "BaseClass", baseClassType, "@test"); addGlobalBinding(frontend, "BaseClass", baseClassType, "@test");
TypeId childClassInstanceType = arena.addType(ClassTypeVar{"ChildClass", {}, baseClassInstanceType, nullopt, {}, {}, "Test"}); TypeId childClassInstanceType = arena.addType(ClassType{"ChildClass", {}, baseClassInstanceType, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(childClassInstanceType)->props = { getMutable<ClassType>(childClassInstanceType)->props = {
{"Method", {makeFunction(arena, childClassInstanceType, {}, {typeChecker.stringType})}}, {"Method", {makeFunction(arena, childClassInstanceType, {}, {typeChecker.stringType})}},
}; };
TypeId childClassType = arena.addType(ClassTypeVar{"ChildClass", {}, baseClassType, nullopt, {}, {}, "Test"}); TypeId childClassType = arena.addType(ClassType{"ChildClass", {}, baseClassType, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(childClassType)->props = { getMutable<ClassType>(childClassType)->props = {
{"New", {makeFunction(arena, nullopt, {}, {childClassInstanceType})}}, {"New", {makeFunction(arena, nullopt, {}, {childClassInstanceType})}},
}; };
typeChecker.globalScope->exportedTypeBindings["ChildClass"] = TypeFun{{}, childClassInstanceType}; typeChecker.globalScope->exportedTypeBindings["ChildClass"] = TypeFun{{}, childClassInstanceType};
addGlobalBinding(frontend, "ChildClass", childClassType, "@test"); addGlobalBinding(frontend, "ChildClass", childClassType, "@test");
TypeId grandChildInstanceType = arena.addType(ClassTypeVar{"GrandChild", {}, childClassInstanceType, nullopt, {}, {}, "Test"}); TypeId grandChildInstanceType = arena.addType(ClassType{"GrandChild", {}, childClassInstanceType, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(grandChildInstanceType)->props = { getMutable<ClassType>(grandChildInstanceType)->props = {
{"Method", {makeFunction(arena, grandChildInstanceType, {}, {typeChecker.stringType})}}, {"Method", {makeFunction(arena, grandChildInstanceType, {}, {typeChecker.stringType})}},
}; };
TypeId grandChildType = arena.addType(ClassTypeVar{"GrandChild", {}, baseClassType, nullopt, {}, {}, "Test"}); TypeId grandChildType = arena.addType(ClassType{"GrandChild", {}, baseClassType, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(grandChildType)->props = { getMutable<ClassType>(grandChildType)->props = {
{"New", {makeFunction(arena, nullopt, {}, {grandChildInstanceType})}}, {"New", {makeFunction(arena, nullopt, {}, {grandChildInstanceType})}},
}; };
typeChecker.globalScope->exportedTypeBindings["GrandChild"] = TypeFun{{}, grandChildInstanceType}; typeChecker.globalScope->exportedTypeBindings["GrandChild"] = TypeFun{{}, grandChildInstanceType};
addGlobalBinding(frontend, "GrandChild", childClassType, "@test"); addGlobalBinding(frontend, "GrandChild", childClassType, "@test");
TypeId anotherChildInstanceType = arena.addType(ClassTypeVar{"AnotherChild", {}, baseClassInstanceType, nullopt, {}, {}, "Test"}); TypeId anotherChildInstanceType = arena.addType(ClassType{"AnotherChild", {}, baseClassInstanceType, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(anotherChildInstanceType)->props = { getMutable<ClassType>(anotherChildInstanceType)->props = {
{"Method", {makeFunction(arena, anotherChildInstanceType, {}, {typeChecker.stringType})}}, {"Method", {makeFunction(arena, anotherChildInstanceType, {}, {typeChecker.stringType})}},
}; };
TypeId anotherChildType = arena.addType(ClassTypeVar{"AnotherChild", {}, baseClassType, nullopt, {}, {}, "Test"}); TypeId anotherChildType = arena.addType(ClassType{"AnotherChild", {}, baseClassType, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(anotherChildType)->props = { getMutable<ClassType>(anotherChildType)->props = {
{"New", {makeFunction(arena, nullopt, {}, {anotherChildInstanceType})}}, {"New", {makeFunction(arena, nullopt, {}, {anotherChildInstanceType})}},
}; };
typeChecker.globalScope->exportedTypeBindings["AnotherChild"] = TypeFun{{}, anotherChildInstanceType}; typeChecker.globalScope->exportedTypeBindings["AnotherChild"] = TypeFun{{}, anotherChildInstanceType};
addGlobalBinding(frontend, "AnotherChild", childClassType, "@test"); 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"}); TypeId unrelatedClassType = arena.addType(ClassType{"UnrelatedClass", {}, nullopt, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(unrelatedClassType)->props = { getMutable<ClassType>(unrelatedClassType)->props = {
{"New", {makeFunction(arena, nullopt, {}, {unrelatedClassInstanceType})}}, {"New", {makeFunction(arena, nullopt, {}, {unrelatedClassInstanceType})}},
}; };
typeChecker.globalScope->exportedTypeBindings["UnrelatedClass"] = TypeFun{{}, unrelatedClassInstanceType}; typeChecker.globalScope->exportedTypeBindings["UnrelatedClass"] = TypeFun{{}, unrelatedClassInstanceType};
addGlobalBinding(frontend, "UnrelatedClass", unrelatedClassType, "@test"); addGlobalBinding(frontend, "UnrelatedClass", unrelatedClassType, "@test");
TypeId vector2MetaType = arena.addType(TableTypeVar{}); TypeId vector2MetaType = arena.addType(TableType{});
TypeId vector2InstanceType = arena.addType(ClassTypeVar{"Vector2", {}, nullopt, vector2MetaType, {}, {}, "Test"}); TypeId vector2InstanceType = arena.addType(ClassType{"Vector2", {}, nullopt, vector2MetaType, {}, {}, "Test"});
getMutable<ClassTypeVar>(vector2InstanceType)->props = { getMutable<ClassType>(vector2InstanceType)->props = {
{"X", {numberType}}, {"X", {numberType}},
{"Y", {numberType}}, {"Y", {numberType}},
}; };
TypeId vector2Type = arena.addType(ClassTypeVar{"Vector2", {}, nullopt, nullopt, {}, {}, "Test"}); TypeId vector2Type = arena.addType(ClassType{"Vector2", {}, nullopt, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(vector2Type)->props = { getMutable<ClassType>(vector2Type)->props = {
{"New", {makeFunction(arena, nullopt, {numberType, numberType}, {vector2InstanceType})}}, {"New", {makeFunction(arena, nullopt, {numberType, numberType}, {vector2InstanceType})}},
}; };
getMutable<TableTypeVar>(vector2MetaType)->props = { getMutable<TableType>(vector2MetaType)->props = {
{"__add", {makeFunction(arena, nullopt, {vector2InstanceType, vector2InstanceType}, {vector2InstanceType})}}, {"__add", {makeFunction(arena, nullopt, {vector2InstanceType, vector2InstanceType}, {vector2InstanceType})}},
}; };
typeChecker.globalScope->exportedTypeBindings["Vector2"] = TypeFun{{}, vector2InstanceType}; typeChecker.globalScope->exportedTypeBindings["Vector2"] = TypeFun{{}, vector2InstanceType};
addGlobalBinding(frontend, "Vector2", vector2Type, "@test"); addGlobalBinding(frontend, "Vector2", vector2Type, "@test");
TypeId callableClassMetaType = arena.addType(TableTypeVar{}); TypeId callableClassMetaType = arena.addType(TableType{});
TypeId callableClassType = arena.addType(ClassTypeVar{"CallableClass", {}, nullopt, callableClassMetaType, {}, {}, "Test"}); TypeId callableClassType = arena.addType(ClassType{"CallableClass", {}, nullopt, callableClassMetaType, {}, {}, "Test"});
getMutable<TableTypeVar>(callableClassMetaType)->props = { getMutable<TableType>(callableClassMetaType)->props = {
{"__call", {makeFunction(arena, nullopt, {callableClassType, typeChecker.stringType}, {typeChecker.numberType})}}, {"__call", {makeFunction(arena, nullopt, {callableClassType, typeChecker.stringType}, {typeChecker.numberType})}},
}; };
typeChecker.globalScope->exportedTypeBindings["CallableClass"] = TypeFun{{}, callableClassType}; typeChecker.globalScope->exportedTypeBindings["CallableClass"] = TypeFun{{}, callableClassType};

View file

@ -440,27 +440,27 @@ TEST_CASE("Vector")
static void populateRTTI(lua_State* L, Luau::TypeId type) static void populateRTTI(lua_State* L, Luau::TypeId type)
{ {
if (auto p = Luau::get<Luau::PrimitiveTypeVar>(type)) if (auto p = Luau::get<Luau::PrimitiveType>(type))
{ {
switch (p->type) switch (p->type)
{ {
case Luau::PrimitiveTypeVar::Boolean: case Luau::PrimitiveType::Boolean:
lua_pushstring(L, "boolean"); lua_pushstring(L, "boolean");
break; break;
case Luau::PrimitiveTypeVar::NilType: case Luau::PrimitiveType::NilType:
lua_pushstring(L, "nil"); lua_pushstring(L, "nil");
break; break;
case Luau::PrimitiveTypeVar::Number: case Luau::PrimitiveType::Number:
lua_pushstring(L, "number"); lua_pushstring(L, "number");
break; break;
case Luau::PrimitiveTypeVar::String: case Luau::PrimitiveType::String:
lua_pushstring(L, "string"); lua_pushstring(L, "string");
break; break;
case Luau::PrimitiveTypeVar::Thread: case Luau::PrimitiveType::Thread:
lua_pushstring(L, "thread"); lua_pushstring(L, "thread");
break; break;
@ -468,7 +468,7 @@ static void populateRTTI(lua_State* L, Luau::TypeId type)
LUAU_ASSERT(!"Unknown primitive type"); LUAU_ASSERT(!"Unknown primitive type");
} }
} }
else if (auto t = Luau::get<Luau::TableTypeVar>(type)) else if (auto t = Luau::get<Luau::TableType>(type))
{ {
lua_newtable(L); lua_newtable(L);
@ -478,18 +478,18 @@ static void populateRTTI(lua_State* L, Luau::TypeId type)
lua_setfield(L, -2, name.c_str()); lua_setfield(L, -2, name.c_str());
} }
} }
else if (Luau::get<Luau::FunctionTypeVar>(type)) else if (Luau::get<Luau::FunctionType>(type))
{ {
lua_pushstring(L, "function"); lua_pushstring(L, "function");
} }
else if (Luau::get<Luau::AnyTypeVar>(type)) else if (Luau::get<Luau::AnyType>(type))
{ {
lua_pushstring(L, "any"); lua_pushstring(L, "any");
} }
else if (auto i = Luau::get<Luau::IntersectionTypeVar>(type)) else if (auto i = Luau::get<Luau::IntersectionType>(type))
{ {
for (const auto& part : i->parts) for (const auto& part : i->parts)
LUAU_ASSERT(Luau::get<Luau::FunctionTypeVar>(part)); LUAU_ASSERT(Luau::get<Luau::FunctionType>(part));
lua_pushstring(L, "function"); lua_pushstring(L, "function");
} }
@ -504,8 +504,8 @@ TEST_CASE("Types")
runConformance("types.lua", [](lua_State* L) { runConformance("types.lua", [](lua_State* L) {
Luau::NullModuleResolver moduleResolver; Luau::NullModuleResolver moduleResolver;
Luau::InternalErrorReporter iceHandler; Luau::InternalErrorReporter iceHandler;
Luau::SingletonTypes singletonTypes; Luau::BuiltinTypes builtinTypes;
Luau::TypeChecker env(&moduleResolver, Luau::NotNull{&singletonTypes}, &iceHandler); Luau::TypeChecker env(&moduleResolver, Luau::NotNull{&builtinTypes}, &iceHandler);
Luau::registerBuiltinGlobals(env); Luau::registerBuiltinGlobals(env);
Luau::freeze(env.globalTypes); Luau::freeze(env.globalTypes);

View file

@ -9,7 +9,7 @@ ConstraintGraphBuilderFixture::ConstraintGraphBuilderFixture()
, mainModule(new Module) , mainModule(new Module)
, forceTheFlag{"DebugLuauDeferredConstraintResolution", true} , forceTheFlag{"DebugLuauDeferredConstraintResolution", true}
{ {
BlockedTypeVar::nextIndex = 0; BlockedType::nextIndex = 0;
BlockedTypePack::nextIndex = 0; BlockedTypePack::nextIndex = 0;
} }
@ -17,7 +17,7 @@ void ConstraintGraphBuilderFixture::generateConstraints(const std::string& code)
{ {
AstStatBlock* root = parse(code); AstStatBlock* root = parse(code);
dfg = std::make_unique<DataFlowGraph>(DataFlowGraphBuilder::build(root, NotNull{&ice})); dfg = std::make_unique<DataFlowGraph>(DataFlowGraphBuilder::build(root, NotNull{&ice}));
cgb = std::make_unique<ConstraintGraphBuilder>("MainModule", mainModule, &arena, NotNull(&moduleResolver), singletonTypes, NotNull(&ice), cgb = std::make_unique<ConstraintGraphBuilder>("MainModule", mainModule, &arena, NotNull(&moduleResolver), builtinTypes, NotNull(&ice),
frontend.getGlobalScope(), &logger, NotNull{dfg.get()}); frontend.getGlobalScope(), &logger, NotNull{dfg.get()});
cgb->visit(root); cgb->visit(root);
rootScope = cgb->rootScope; rootScope = cgb->rootScope;

View file

@ -19,7 +19,7 @@ struct ConstraintGraphBuilderFixture : Fixture
ModulePtr mainModule; ModulePtr mainModule;
DcrLogger logger; DcrLogger logger;
UnifierSharedState sharedState{&ice}; UnifierSharedState sharedState{&ice};
Normalizer normalizer{&arena, singletonTypes, NotNull{&sharedState}}; Normalizer normalizer{&arena, builtinTypes, NotNull{&sharedState}};
std::unique_ptr<DataFlowGraph> dfg; std::unique_ptr<DataFlowGraph> dfg;
std::unique_ptr<ConstraintGraphBuilder> cgb; std::unique_ptr<ConstraintGraphBuilder> cgb;

View file

@ -7,7 +7,7 @@
#include "Luau/ModuleResolver.h" #include "Luau/ModuleResolver.h"
#include "Luau/NotNull.h" #include "Luau/NotNull.h"
#include "Luau/Parser.h" #include "Luau/Parser.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/TypeAttach.h" #include "Luau/TypeAttach.h"
#include "Luau/Transpiler.h" #include "Luau/Transpiler.h"
@ -141,7 +141,7 @@ Fixture::Fixture(bool freeze, bool prepareAutocomplete)
, frontend(&fileResolver, &configResolver, , frontend(&fileResolver, &configResolver,
{/* retainFullTypeGraphs= */ true, /* forAutocomplete */ false, /* randomConstraintResolutionSeed */ randomSeed}) {/* retainFullTypeGraphs= */ true, /* forAutocomplete */ false, /* randomConstraintResolutionSeed */ randomSeed})
, typeChecker(frontend.typeChecker) , typeChecker(frontend.typeChecker)
, singletonTypes(frontend.singletonTypes) , builtinTypes(frontend.builtinTypes)
{ {
configResolver.defaultConfig.mode = Mode::Strict; configResolver.defaultConfig.mode = Mode::Strict;
configResolver.defaultConfig.enabledLint.warningMask = ~0ull; configResolver.defaultConfig.enabledLint.warningMask = ~0ull;
@ -293,14 +293,14 @@ SourceModule* Fixture::getMainSourceModule()
return frontend.getSourceModule(fromString(mainModuleName)); return frontend.getSourceModule(fromString(mainModuleName));
} }
std::optional<PrimitiveTypeVar::Type> Fixture::getPrimitiveType(TypeId ty) std::optional<PrimitiveType::Type> Fixture::getPrimitiveType(TypeId ty)
{ {
REQUIRE(ty != nullptr); REQUIRE(ty != nullptr);
TypeId aType = follow(ty); TypeId aType = follow(ty);
REQUIRE(aType != nullptr); REQUIRE(aType != nullptr);
const PrimitiveTypeVar* pt = get<PrimitiveTypeVar>(aType); const PrimitiveType* pt = get<PrimitiveType>(aType);
if (pt != nullptr) if (pt != nullptr)
return pt->type; return pt->type;
else else
@ -513,7 +513,7 @@ std::string rep(const std::string& s, size_t n)
bool isInArena(TypeId t, const TypeArena& arena) bool isInArena(TypeId t, const TypeArena& arena)
{ {
return arena.typeVars.contains(t); return arena.types.contains(t);
} }
void dumpErrors(const ModulePtr& module) void dumpErrors(const ModulePtr& module)
@ -554,12 +554,13 @@ std::optional<TypeId> linearSearchForBinding(Scope* scope, const char* name)
void registerHiddenTypes(Fixture& fixture, TypeArena& arena) void registerHiddenTypes(Fixture& fixture, TypeArena& arena)
{ {
TypeId t = arena.addType(GenericTypeVar{"T"}); TypeId t = arena.addType(GenericType{"T"});
GenericTypeDefinition genericT{t}; GenericTypeDefinition genericT{t};
ScopePtr moduleScope = fixture.frontend.getGlobalScope(); ScopePtr moduleScope = fixture.frontend.getGlobalScope();
moduleScope->exportedTypeBindings["Not"] = TypeFun{{genericT}, arena.addType(NegationTypeVar{t})}; moduleScope->exportedTypeBindings["Not"] = TypeFun{{genericT}, arena.addType(NegationType{t})};
moduleScope->exportedTypeBindings["fun"] = TypeFun{{}, fixture.singletonTypes->functionType}; moduleScope->exportedTypeBindings["fun"] = TypeFun{{}, fixture.builtinTypes->functionType};
moduleScope->exportedTypeBindings["cls"] = TypeFun{{}, fixture.builtinTypes->classType};
} }
void dump(const std::vector<Constraint>& constraints) void dump(const std::vector<Constraint>& constraints)

View file

@ -10,7 +10,7 @@
#include "Luau/ModuleResolver.h" #include "Luau/ModuleResolver.h"
#include "Luau/Scope.h" #include "Luau/Scope.h"
#include "Luau/ToString.h" #include "Luau/ToString.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "IostreamOptional.h" #include "IostreamOptional.h"
#include "ScopedFlags.h" #include "ScopedFlags.h"
@ -78,7 +78,7 @@ struct Fixture
ModulePtr getMainModule(); ModulePtr getMainModule();
SourceModule* getMainSourceModule(); SourceModule* getMainSourceModule();
std::optional<PrimitiveTypeVar::Type> getPrimitiveType(TypeId ty); std::optional<PrimitiveType::Type> getPrimitiveType(TypeId ty);
std::optional<TypeId> getType(const std::string& name); std::optional<TypeId> getType(const std::string& name);
TypeId requireType(const std::string& name); TypeId requireType(const std::string& name);
TypeId requireType(const ModuleName& moduleName, const std::string& name); TypeId requireType(const ModuleName& moduleName, const std::string& name);
@ -102,7 +102,7 @@ struct Fixture
Frontend frontend; Frontend frontend;
InternalErrorReporter ice; InternalErrorReporter ice;
TypeChecker& typeChecker; TypeChecker& typeChecker;
NotNull<SingletonTypes> singletonTypes; NotNull<BuiltinTypes> builtinTypes;
std::string decorateWithTypes(const std::string& code); std::string decorateWithTypes(const std::string& code);

View file

@ -791,7 +791,7 @@ TEST_CASE_FIXTURE(FrontendFixture, "discard_type_graphs")
ModulePtr module = fe.moduleResolver.getModule("Module/A"); 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->internalTypes.typePacks.size());
CHECK_EQ(0, module->astTypes.size()); CHECK_EQ(0, module->astTypes.size());
CHECK_EQ(0, module->astResolvedTypes.size()); CHECK_EQ(0, module->astResolvedTypes.size());

View file

@ -14,18 +14,18 @@ static void merge(TypeArena& arena, RefinementMap& l, const RefinementMap& r)
// TODO: normalize here also. // TODO: normalize here also.
std::unordered_set<TypeId> s; std::unordered_set<TypeId> s;
if (auto utv = get<UnionTypeVar>(follow(a))) if (auto utv = get<UnionType>(follow(a)))
s.insert(begin(utv), end(utv)); s.insert(begin(utv), end(utv));
else else
s.insert(a); s.insert(a);
if (auto utv = get<UnionTypeVar>(follow(b))) if (auto utv = get<UnionType>(follow(b)))
s.insert(begin(utv), end(utv)); s.insert(begin(utv), end(utv));
else else
s.insert(b); s.insert(b);
std::vector<TypeId> options(s.begin(), s.end()); std::vector<TypeId> 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 struct LValueFixture
{ {
SingletonTypes singletonTypes; BuiltinTypes builtinTypes;
}; };
TEST_SUITE_BEGIN("LValue"); TEST_SUITE_BEGIN("LValue");
@ -48,14 +48,14 @@ TEST_CASE_FIXTURE(LValueFixture, "Luau_merge_hashmap_order")
std::string c = "c"; std::string c = "c";
RefinementMap m{{ RefinementMap m{{
{mkSymbol(b), singletonTypes.stringType}, {mkSymbol(b), builtinTypes.stringType},
{mkSymbol(c), singletonTypes.numberType}, {mkSymbol(c), builtinTypes.numberType},
}}; }};
RefinementMap other{{ RefinementMap other{{
{mkSymbol(a), singletonTypes.stringType}, {mkSymbol(a), builtinTypes.stringType},
{mkSymbol(b), singletonTypes.stringType}, {mkSymbol(b), builtinTypes.stringType},
{mkSymbol(c), singletonTypes.booleanType}, {mkSymbol(c), builtinTypes.booleanType},
}}; }};
TypeArena arena; TypeArena arena;
@ -78,14 +78,14 @@ TEST_CASE_FIXTURE(LValueFixture, "Luau_merge_hashmap_order2")
std::string c = "c"; std::string c = "c";
RefinementMap m{{ RefinementMap m{{
{mkSymbol(a), singletonTypes.stringType}, {mkSymbol(a), builtinTypes.stringType},
{mkSymbol(b), singletonTypes.stringType}, {mkSymbol(b), builtinTypes.stringType},
{mkSymbol(c), singletonTypes.numberType}, {mkSymbol(c), builtinTypes.numberType},
}}; }};
RefinementMap other{{ RefinementMap other{{
{mkSymbol(b), singletonTypes.stringType}, {mkSymbol(b), builtinTypes.stringType},
{mkSymbol(c), singletonTypes.booleanType}, {mkSymbol(c), builtinTypes.booleanType},
}}; }};
TypeArena arena; TypeArena arena;
@ -110,15 +110,15 @@ TEST_CASE_FIXTURE(LValueFixture, "one_map_has_overlap_at_end_whereas_other_has_i
std::string e = "e"; std::string e = "e";
RefinementMap m{{ RefinementMap m{{
{mkSymbol(a), singletonTypes.stringType}, {mkSymbol(a), builtinTypes.stringType},
{mkSymbol(b), singletonTypes.numberType}, {mkSymbol(b), builtinTypes.numberType},
{mkSymbol(c), singletonTypes.booleanType}, {mkSymbol(c), builtinTypes.booleanType},
}}; }};
RefinementMap other{{ RefinementMap other{{
{mkSymbol(c), singletonTypes.stringType}, {mkSymbol(c), builtinTypes.stringType},
{mkSymbol(d), singletonTypes.numberType}, {mkSymbol(d), builtinTypes.numberType},
{mkSymbol(e), singletonTypes.booleanType}, {mkSymbol(e), builtinTypes.booleanType},
}}; }};
TypeArena arena; TypeArena arena;
@ -159,8 +159,8 @@ TEST_CASE_FIXTURE(LValueFixture, "hashing_lvalue_global_prop_access")
CHECK_EQ(LValueHasher{}(t_x2), LValueHasher{}(t_x2)); CHECK_EQ(LValueHasher{}(t_x2), LValueHasher{}(t_x2));
RefinementMap m; RefinementMap m;
m[t_x1] = singletonTypes.stringType; m[t_x1] = builtinTypes.stringType;
m[t_x2] = singletonTypes.numberType; m[t_x2] = builtinTypes.numberType;
CHECK_EQ(1, m.size()); 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)); CHECK_EQ(LValueHasher{}(t_x2), LValueHasher{}(t_x2));
RefinementMap m; RefinementMap m;
m[t_x1] = singletonTypes.stringType; m[t_x1] = builtinTypes.stringType;
m[t_x2] = singletonTypes.numberType; m[t_x2] = builtinTypes.numberType;
CHECK_EQ(2, m.size()); CHECK_EQ(2, m.size());
} }

View file

@ -610,11 +610,11 @@ return foo1
TEST_CASE_FIXTURE(Fixture, "UnknownType") TEST_CASE_FIXTURE(Fixture, "UnknownType")
{ {
unfreeze(typeChecker.globalTypes); unfreeze(typeChecker.globalTypes);
TableTypeVar::Props instanceProps{ TableType::Props instanceProps{
{"ClassName", {typeChecker.anyType}}, {"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); TypeId instanceType = typeChecker.globalTypes.addType(instanceTable);
TypeFun instanceTypeFun{{}, instanceType}; TypeFun instanceTypeFun{{}, instanceType};
@ -1448,19 +1448,19 @@ TEST_CASE_FIXTURE(Fixture, "LintHygieneUAF")
TEST_CASE_FIXTURE(Fixture, "DeprecatedApi") TEST_CASE_FIXTURE(Fixture, "DeprecatedApi")
{ {
unfreeze(typeChecker.globalTypes); 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); persist(instanceType);
typeChecker.globalScope->exportedTypeBindings["Instance"] = TypeFun{{}, instanceType}; typeChecker.globalScope->exportedTypeBindings["Instance"] = TypeFun{{}, instanceType};
getMutable<ClassTypeVar>(instanceType)->props = { getMutable<ClassType>(instanceType)->props = {
{"Name", {typeChecker.stringType}}, {"Name", {typeChecker.stringType}},
{"DataCost", {typeChecker.numberType, /* deprecated= */ true}}, {"DataCost", {typeChecker.numberType, /* deprecated= */ true}},
{"Wait", {typeChecker.anyType, /* 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<TableTypeVar>(colorType)->props = {{"toHSV", {typeChecker.anyType, /* deprecated= */ true, "Color3:ToHSV"}}}; getMutable<TableType>(colorType)->props = {{"toHSV", {typeChecker.anyType, /* deprecated= */ true, "Color3:ToHSV"}}};
addGlobalBinding(frontend, "Color3", Binding{colorType, {}}); addGlobalBinding(frontend, "Color3", Binding{colorType, {}});

View file

@ -59,14 +59,14 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_non_persistent_primitive")
// Create a new number type that isn't persistent // Create a new number type that isn't persistent
unfreeze(typeChecker.globalTypes); unfreeze(typeChecker.globalTypes);
TypeId oldNumber = typeChecker.globalTypes.addType(PrimitiveTypeVar{PrimitiveTypeVar::Number}); TypeId oldNumber = typeChecker.globalTypes.addType(PrimitiveType{PrimitiveType::Number});
freeze(typeChecker.globalTypes); freeze(typeChecker.globalTypes);
TypeId newNumber = clone(oldNumber, dest, cloneState); TypeId newNumber = clone(oldNumber, dest, cloneState);
CHECK_NE(newNumber, oldNumber); CHECK_NE(newNumber, oldNumber);
CHECK_EQ(*oldNumber, *newNumber); CHECK_EQ(*oldNumber, *newNumber);
CHECK_EQ("number", toString(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") TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
@ -91,7 +91,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
CloneState cloneState; CloneState cloneState;
TypeId counterCopy = clone(counterType, dest, cloneState); TypeId counterCopy = clone(counterType, dest, cloneState);
TableTypeVar* ttv = getMutable<TableTypeVar>(counterCopy); TableType* ttv = getMutable<TableType>(counterCopy);
REQUIRE(ttv != nullptr); REQUIRE(ttv != nullptr);
CHECK_EQ(std::optional<std::string>{"Cyclic"}, ttv->syntheticName); CHECK_EQ(std::optional<std::string>{"Cyclic"}, ttv->syntheticName);
@ -99,7 +99,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
TypeId methodType = ttv->props["get"].type; TypeId methodType = ttv->props["get"].type;
REQUIRE(methodType != nullptr); REQUIRE(methodType != nullptr);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(methodType); const FunctionType* ftv = get<FunctionType>(methodType);
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
std::optional<TypeId> methodReturnType = first(ftv->retTypes); std::optional<TypeId> methodReturnType = first(ftv->retTypes);
@ -107,7 +107,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
CHECK_EQ(methodReturnType, counterCopy); 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.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") 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)); REQUIRE(isInArena(*exports, module->interfaceTypes));
TableTypeVar* exportsTable = getMutable<TableTypeVar>(*exports); TableType* exportsTable = getMutable<TableType>(*exports);
REQUIRE(exportsTable != nullptr); REQUIRE(exportsTable != nullptr);
TypeId signType = exportsTable->props["sign"].type; TypeId signType = exportsTable->props["sign"].type;
@ -143,13 +143,13 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_union")
CloneState cloneState; CloneState cloneState;
unfreeze(typeChecker.globalTypes); 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); freeze(typeChecker.globalTypes);
TypeId newUnion = clone(oldUnion, dest, cloneState); TypeId newUnion = clone(oldUnion, dest, cloneState);
CHECK_NE(newUnion, oldUnion); CHECK_NE(newUnion, oldUnion);
CHECK_EQ("number | string", toString(newUnion)); CHECK_EQ("number | string", toString(newUnion));
CHECK_EQ(1, dest.typeVars.size()); CHECK_EQ(1, dest.types.size());
} }
TEST_CASE_FIXTURE(Fixture, "deepClone_intersection") TEST_CASE_FIXTURE(Fixture, "deepClone_intersection")
@ -158,23 +158,23 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_intersection")
CloneState cloneState; CloneState cloneState;
unfreeze(typeChecker.globalTypes); 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); freeze(typeChecker.globalTypes);
TypeId newIntersection = clone(oldIntersection, dest, cloneState); TypeId newIntersection = clone(oldIntersection, dest, cloneState);
CHECK_NE(newIntersection, oldIntersection); CHECK_NE(newIntersection, oldIntersection);
CHECK_EQ("number & string", toString(newIntersection)); CHECK_EQ("number & string", toString(newIntersection));
CHECK_EQ(1, dest.typeVars.size()); CHECK_EQ(1, dest.types.size());
} }
TEST_CASE_FIXTURE(Fixture, "clone_class") TEST_CASE_FIXTURE(Fixture, "clone_class")
{ {
TypeVar exampleMetaClass{ClassTypeVar{"ExampleClassMeta", Type exampleMetaClass{ClassType{"ExampleClassMeta",
{ {
{"__add", {typeChecker.anyType}}, {"__add", {typeChecker.anyType}},
}, },
std::nullopt, std::nullopt, {}, {}, "Test"}}; std::nullopt, std::nullopt, {}, {}, "Test"}};
TypeVar exampleClass{ClassTypeVar{"ExampleClass", Type exampleClass{ClassType{"ExampleClass",
{ {
{"PropOne", {typeChecker.numberType}}, {"PropOne", {typeChecker.numberType}},
{"PropTwo", {typeChecker.stringType}}, {"PropTwo", {typeChecker.stringType}},
@ -185,11 +185,11 @@ TEST_CASE_FIXTURE(Fixture, "clone_class")
CloneState cloneState; CloneState cloneState;
TypeId cloned = clone(&exampleClass, dest, cloneState); TypeId cloned = clone(&exampleClass, dest, cloneState);
const ClassTypeVar* ctv = get<ClassTypeVar>(cloned); const ClassType* ctv = get<ClassType>(cloned);
REQUIRE(ctv != nullptr); REQUIRE(ctv != nullptr);
REQUIRE(ctv->metatable); REQUIRE(ctv->metatable);
const ClassTypeVar* metatable = get<ClassTypeVar>(*ctv->metatable); const ClassType* metatable = get<ClassType>(*ctv->metatable);
REQUIRE(metatable); REQUIRE(metatable);
CHECK_EQ("ExampleClass", ctv->name); CHECK_EQ("ExampleClass", ctv->name);
@ -198,14 +198,14 @@ TEST_CASE_FIXTURE(Fixture, "clone_class")
TEST_CASE_FIXTURE(Fixture, "clone_free_types") TEST_CASE_FIXTURE(Fixture, "clone_free_types")
{ {
TypeVar freeTy(FreeTypeVar{TypeLevel{}}); Type freeTy(FreeType{TypeLevel{}});
TypePackVar freeTp(FreeTypePack{TypeLevel{}}); TypePackVar freeTp(FreeTypePack{TypeLevel{}});
TypeArena dest; TypeArena dest;
CloneState cloneState; CloneState cloneState;
TypeId clonedTy = clone(&freeTy, dest, cloneState); TypeId clonedTy = clone(&freeTy, dest, cloneState);
CHECK(get<FreeTypeVar>(clonedTy)); CHECK(get<FreeType>(clonedTy));
cloneState = {}; cloneState = {};
TypePackId clonedTp = clone(&freeTp, dest, 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") TEST_CASE_FIXTURE(Fixture, "clone_free_tables")
{ {
TypeVar tableTy{TableTypeVar{}}; Type tableTy{TableType{}};
TableTypeVar* ttv = getMutable<TableTypeVar>(&tableTy); TableType* ttv = getMutable<TableType>(&tableTy);
ttv->state = TableState::Free; ttv->state = TableState::Free;
TypeArena dest; TypeArena dest;
CloneState cloneState; CloneState cloneState;
TypeId cloned = clone(&tableTy, dest, cloneState); TypeId cloned = clone(&tableTy, dest, cloneState);
const TableTypeVar* clonedTtv = get<TableTypeVar>(cloned); const TableType* clonedTtv = get<TableType>(cloned);
CHECK_EQ(clonedTtv->state, TableState::Free); CHECK_EQ(clonedTtv->state, TableState::Free);
} }
@ -264,14 +264,14 @@ TEST_CASE_FIXTURE(Fixture, "clone_recursion_limit")
TypeArena src; TypeArena src;
TypeId table = src.addType(TableTypeVar{}); TypeId table = src.addType(TableType{});
TypeId nested = table; TypeId nested = table;
for (int i = 0; i < limit + 100; i++) for (int i = 0; i < limit + 100; i++)
{ {
TableTypeVar* ttv = getMutable<TableTypeVar>(nested); TableType* ttv = getMutable<TableType>(nested);
ttv->props["a"].type = src.addType(TableTypeVar{}); ttv->props["a"].type = src.addType(TableType{});
nested = ttv->props["a"].type; nested = ttv->props["a"].type;
} }
@ -332,7 +332,7 @@ return {}
REQUIRE(modBiter != modB->getModuleScope()->exportedTypeBindings.end()); REQUIRE(modBiter != modB->getModuleScope()->exportedTypeBindings.end());
TypeId typeA = modAiter->second.type; TypeId typeA = modAiter->second.type;
TypeId typeB = modBiter->second.type; TypeId typeB = modBiter->second.type;
TableTypeVar* tableB = getMutable<TableTypeVar>(typeB); TableType* tableB = getMutable<TableType>(typeB);
REQUIRE(tableB); REQUIRE(tableB);
CHECK(typeA == tableB->props["q"].type); CHECK(typeA == tableB->props["q"].type);
} }
@ -368,8 +368,8 @@ return exports
std::optional<TypeId> typeB = first(modB->getModuleScope()->returnType); std::optional<TypeId> typeB = first(modB->getModuleScope()->returnType);
REQUIRE(typeA); REQUIRE(typeA);
REQUIRE(typeB); REQUIRE(typeB);
TableTypeVar* tableA = getMutable<TableTypeVar>(*typeA); TableType* tableA = getMutable<TableType>(*typeA);
TableTypeVar* tableB = getMutable<TableTypeVar>(*typeB); TableType* tableB = getMutable<TableType>(*typeB);
CHECK(tableA->props["a"].type == tableB->props["b"].type); CHECK(tableA->props["a"].type == tableB->props["b"].type);
} }

View file

@ -1,7 +1,7 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details // 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/Scope.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Fixture.h" #include "Fixture.h"
@ -23,7 +23,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_nullary_function")
TypeId fooType = requireType("foo"); TypeId fooType = requireType("foo");
REQUIRE(fooType); REQUIRE(fooType);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(fooType); const FunctionType* ftv = get<FunctionType>(fooType);
REQUIRE_MESSAGE(ftv != nullptr, "Expected a function, got " << toString(fooType)); REQUIRE_MESSAGE(ftv != nullptr, "Expected a function, got " << toString(fooType));
auto args = flatten(ftv->argTypes).first; auto args = flatten(ftv->argTypes).first;
@ -165,7 +165,7 @@ TEST_CASE_FIXTURE(Fixture, "table_props_are_any")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
TableTypeVar* ttv = getMutable<TableTypeVar>(requireType("T")); TableType* ttv = getMutable<TableType>(requireType("T"));
REQUIRE(ttv != nullptr); REQUIRE(ttv != nullptr);
@ -189,12 +189,12 @@ TEST_CASE_FIXTURE(Fixture, "inline_table_props_are_also_any")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
TableTypeVar* ttv = getMutable<TableTypeVar>(requireType("T")); TableType* ttv = getMutable<TableType>(requireType("T"));
REQUIRE_MESSAGE(ttv, "Should be a table: " << toString(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["one"].type);
CHECK_EQ(*typeChecker.anyType, *ttv->props["two"].type); CHECK_EQ(*typeChecker.anyType, *ttv->props["two"].type);
CHECK_MESSAGE(get<FunctionTypeVar>(ttv->props["three"].type), "Should be a function: " << *ttv->props["three"].type); CHECK_MESSAGE(get<FunctionType>(ttv->props["three"].type), "Should be a function: " << *ttv->props["three"].type);
} }
TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_iterator_variables_are_any") TEST_CASE_FIXTURE(BuiltinsFixture, "for_in_iterator_variables_are_any")

View file

@ -3,7 +3,7 @@
#include "Fixture.h" #include "Fixture.h"
#include "Luau/Common.h" #include "Luau/Common.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "doctest.h" #include "doctest.h"
#include "Luau/Normalize.h" #include "Luau/Normalize.h"
@ -17,7 +17,7 @@ struct IsSubtypeFixture : Fixture
{ {
bool isSubtype(TypeId a, TypeId b) 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 } // namespace
@ -28,9 +28,9 @@ void createSomeClasses(Frontend& frontend)
unfreeze(arena); 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<ClassTypeVar>(parentType); ClassType* parentClass = getMutable<ClassType>(parentType);
parentClass->props["method"] = {makeFunction(arena, parentType, {}, {})}; parentClass->props["method"] = {makeFunction(arena, parentType, {}, {})};
parentClass->props["virtual_method"] = {makeFunction(arena, parentType, {}, {})}; parentClass->props["virtual_method"] = {makeFunction(arena, parentType, {}, {})};
@ -38,15 +38,15 @@ void createSomeClasses(Frontend& frontend)
addGlobalBinding(frontend, "Parent", {parentType}); addGlobalBinding(frontend, "Parent", {parentType});
frontend.getGlobalScope()->exportedTypeBindings["Parent"] = TypeFun{{}, 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<ClassTypeVar>(childType); ClassType* childClass = getMutable<ClassType>(childType);
childClass->props["virtual_method"] = {makeFunction(arena, childType, {}, {})}; childClass->props["virtual_method"] = {makeFunction(arena, childType, {}, {})};
addGlobalBinding(frontend, "Child", {childType}); addGlobalBinding(frontend, "Child", {childType});
frontend.getGlobalScope()->exportedTypeBindings["Child"] = TypeFun{{}, 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}); addGlobalBinding(frontend, "Unrelated", {unrelatedType});
frontend.getGlobalScope()->exportedTypeBindings["Unrelated"] = TypeFun{{}, unrelatedType}; frontend.getGlobalScope()->exportedTypeBindings["Unrelated"] = TypeFun{{}, unrelatedType};
@ -394,11 +394,12 @@ TEST_SUITE_END();
struct NormalizeFixture : Fixture struct NormalizeFixture : Fixture
{ {
ScopedFastFlag sff1{"LuauNegatedFunctionTypes", true}; ScopedFastFlag sff1{"LuauNegatedFunctionTypes", true};
ScopedFastFlag sff2{"LuauNegatedClassTypes", true};
TypeArena arena; TypeArena arena;
InternalErrorReporter iceHandler; InternalErrorReporter iceHandler;
UnifierSharedState unifierState{&iceHandler}; UnifierSharedState unifierState{&iceHandler};
Normalizer normalizer{&arena, singletonTypes, NotNull{&unifierState}}; Normalizer normalizer{&arena, builtinTypes, NotNull{&unifierState}};
NormalizeFixture() 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") 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<fun> Not<fun>
)"))); )")));
} }
@ -536,8 +539,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "specific_functions_cannot_be_negated")
TEST_CASE_FIXTURE(NormalizeFixture, "bare_negated_boolean") 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 // 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<boolean> Not<boolean>
)"))); )")));
} }
@ -603,4 +607,61 @@ export type t0 = (((any)&({_:l0.t0,n0:t0,_G:any,}))&({_:any,}))&(((any)&({_:l0.t
LUAU_REQUIRE_ERRORS(result); 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<Child>) | Unrelated")));
CHECK("((class & ~Child) | boolean | function | number | string | thread)?" == toString(normal("Not<Child>")));
CHECK("Child" == toString(normal("Not<Parent> & Child")));
CHECK("((class & ~Parent) | Child | boolean | function | number | string | thread)?" == toString(normal("Not<Parent> | Child")));
CHECK("(boolean | function | number | string | thread)?" == toString(normal("Not<cls>")));
CHECK("(Parent | Unrelated | boolean | function | number | string | thread)?" ==
toString(normal("Not<cls & Not<Parent> & Not<Child> & Not<Unrelated>>")));
}
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(); TEST_SUITE_END();

View file

@ -17,16 +17,16 @@ struct ToDotClassFixture : Fixture
unfreeze(arena); unfreeze(arena);
TypeId baseClassMetaType = arena.addType(TableTypeVar{}); TypeId baseClassMetaType = arena.addType(TableType{});
TypeId baseClassInstanceType = arena.addType(ClassTypeVar{"BaseClass", {}, std::nullopt, baseClassMetaType, {}, {}, "Test"}); TypeId baseClassInstanceType = arena.addType(ClassType{"BaseClass", {}, std::nullopt, baseClassMetaType, {}, {}, "Test"});
getMutable<ClassTypeVar>(baseClassInstanceType)->props = { getMutable<ClassType>(baseClassInstanceType)->props = {
{"BaseField", {typeChecker.numberType}}, {"BaseField", {typeChecker.numberType}},
}; };
typeChecker.globalScope->exportedTypeBindings["BaseClass"] = TypeFun{{}, baseClassInstanceType}; typeChecker.globalScope->exportedTypeBindings["BaseClass"] = TypeFun{{}, baseClassInstanceType};
TypeId childClassInstanceType = arena.addType(ClassTypeVar{"ChildClass", {}, baseClassInstanceType, std::nullopt, {}, {}, "Test"}); TypeId childClassInstanceType = arena.addType(ClassType{"ChildClass", {}, baseClassInstanceType, std::nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(childClassInstanceType)->props = { getMutable<ClassType>(childClassInstanceType)->props = {
{"ChildField", {typeChecker.stringType}}, {"ChildField", {typeChecker.stringType}},
}; };
typeChecker.globalScope->exportedTypeBindings["ChildClass"] = TypeFun{{}, childClassInstanceType}; typeChecker.globalScope->exportedTypeBindings["ChildClass"] = TypeFun{{}, childClassInstanceType};
@ -66,12 +66,12 @@ n1 [label="any"];
opts.duplicatePrimitives = false; opts.duplicatePrimitives = false;
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="PrimitiveTypeVar number"]; n1 [label="PrimitiveType number"];
})", })",
toDot(requireType("b"), opts)); toDot(requireType("b"), opts));
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="AnyTypeVar 1"]; n1 [label="AnyType 1"];
})", })",
toDot(requireType("c"), opts)); toDot(requireType("c"), opts));
} }
@ -90,7 +90,7 @@ local b = a()
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="BoundTypeVar 1"]; n1 [label="BoundType 1"];
n1 -> n2; n1 -> n2;
n2 [label="number"]; n2 [label="number"];
})", })",
@ -110,11 +110,11 @@ local function f(a, ...: string) return a end
opts.showPointers = false; opts.showPointers = false;
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="FunctionTypeVar 1"]; n1 [label="FunctionType 1"];
n1 -> n2 [label="arg"]; n1 -> n2 [label="arg"];
n2 [label="TypePack 2"]; n2 [label="TypePack 2"];
n2 -> n3; n2 -> n3;
n3 [label="GenericTypeVar 3"]; n3 [label="GenericType 3"];
n2 -> n4 [label="tail"]; n2 -> n4 [label="tail"];
n4 [label="VariadicTypePack 4"]; n4 [label="VariadicTypePack 4"];
n4 -> n5; n4 -> n5;
@ -138,7 +138,7 @@ local a: string | number
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="UnionTypeVar 1"]; n1 [label="UnionType 1"];
n1 -> n2; n1 -> n2;
n2 [label="string"]; n2 [label="string"];
n1 -> n3; n1 -> n3;
@ -157,7 +157,7 @@ local a: string & number -- uninhabited
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="IntersectionTypeVar 1"]; n1 [label="IntersectionType 1"];
n1 -> n2; n1 -> n2;
n2 [label="string"]; n2 [label="string"];
n1 -> n3; n1 -> n3;
@ -177,11 +177,11 @@ local a: A<number, ...string>
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="TableTypeVar A"]; n1 [label="TableType A"];
n1 -> n2 [label="x"]; n1 -> n2 [label="x"];
n2 [label="number"]; n2 [label="number"];
n1 -> n3 [label="y"]; n1 -> n3 [label="y"];
n3 [label="FunctionTypeVar 3"]; n3 [label="FunctionType 3"];
n3 -> n4 [label="arg"]; n3 -> n4 [label="arg"];
n4 [label="VariadicTypePack 4"]; n4 [label="VariadicTypePack 4"];
n4 -> n5; n4 -> n5;
@ -212,47 +212,47 @@ local a: typeof(setmetatable({}, {}))
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="MetatableTypeVar 1"]; n1 [label="MetatableType 1"];
n1 -> n2 [label="table"]; n1 -> n2 [label="table"];
n2 [label="TableTypeVar 2"]; n2 [label="TableType 2"];
n1 -> n3 [label="metatable"]; n1 -> n3 [label="metatable"];
n3 [label="TableTypeVar 3"]; n3 [label="TableType 3"];
})", })",
toDot(requireType("a"), opts)); toDot(requireType("a"), opts));
} }
TEST_CASE_FIXTURE(Fixture, "free") TEST_CASE_FIXTURE(Fixture, "free")
{ {
TypeVar type{TypeVariant{FreeTypeVar{TypeLevel{0, 0}}}}; Type type{TypeVariant{FreeType{TypeLevel{0, 0}}}};
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="FreeTypeVar 1"]; n1 [label="FreeType 1"];
})", })",
toDot(&type, opts)); toDot(&type, opts));
} }
TEST_CASE_FIXTURE(Fixture, "error") TEST_CASE_FIXTURE(Fixture, "error")
{ {
TypeVar type{TypeVariant{ErrorTypeVar{}}}; Type type{TypeVariant{ErrorType{}}};
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="ErrorTypeVar 1"]; n1 [label="ErrorType 1"];
})", })",
toDot(&type, opts)); toDot(&type, opts));
} }
TEST_CASE_FIXTURE(Fixture, "generic") TEST_CASE_FIXTURE(Fixture, "generic")
{ {
TypeVar type{TypeVariant{GenericTypeVar{"T"}}}; Type type{TypeVariant{GenericType{"T"}}};
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="GenericTypeVar T"]; n1 [label="GenericType T"];
})", })",
toDot(&type, opts)); toDot(&type, opts));
} }
@ -267,15 +267,15 @@ local a: ChildClass
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="ClassTypeVar ChildClass"]; n1 [label="ClassType ChildClass"];
n1 -> n2 [label="ChildField"]; n1 -> n2 [label="ChildField"];
n2 [label="string"]; n2 [label="string"];
n1 -> n3 [label="[parent]"]; n1 -> n3 [label="[parent]"];
n3 [label="ClassTypeVar BaseClass"]; n3 [label="ClassType BaseClass"];
n3 -> n4 [label="BaseField"]; n3 -> n4 [label="BaseField"];
n4 [label="number"]; n4 [label="number"];
n3 -> n5 [label="[metatable]"]; n3 -> n5 [label="[metatable]"];
n5 [label="TableTypeVar 5"]; n5 [label="TableType 5"];
})", })",
toDot(requireType("a"), opts)); toDot(requireType("a"), opts));
} }
@ -358,16 +358,16 @@ b = a
ToDotOptions opts; ToDotOptions opts;
opts.showPointers = false; opts.showPointers = false;
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="TableTypeVar 1"]; n1 [label="TableType 1"];
n1 -> n2 [label="boundTo"]; n1 -> n2 [label="boundTo"];
n2 [label="TableTypeVar a"]; n2 [label="TableType a"];
n2 -> n3 [label="x"]; n2 -> n3 [label="x"];
n3 [label="number"]; n3 [label="number"];
})", })",
toDot(*ty, opts)); toDot(*ty, opts));
} }
TEST_CASE_FIXTURE(Fixture, "singletontypes") TEST_CASE_FIXTURE(Fixture, "builtintypes")
{ {
CheckResult result = check(R"( CheckResult result = check(R"(
local x: "hi" | "\"hello\"" | true | false local x: "hi" | "\"hello\"" | true | false
@ -377,17 +377,17 @@ TEST_CASE_FIXTURE(Fixture, "singletontypes")
opts.showPointers = false; opts.showPointers = false;
CHECK_EQ(R"(digraph graphname { CHECK_EQ(R"(digraph graphname {
n1 [label="UnionTypeVar 1"]; n1 [label="UnionType 1"];
n1 -> n2; n1 -> n2;
n2 [label="SingletonTypeVar string: hi"]; n2 [label="SingletonType string: hi"];
n1 -> n3; n1 -> n3;
)" )"
"n3 [label=\"SingletonTypeVar string: \\\"hello\\\"\"];" "n3 [label=\"SingletonType string: \\\"hello\\\"\"];"
R"( R"(
n1 -> n4; n1 -> n4;
n4 [label="SingletonTypeVar boolean: true"]; n4 [label="SingletonType boolean: true"];
n1 -> n5; n1 -> n5;
n5 [label="SingletonTypeVar boolean: false"]; n5 [label="SingletonType boolean: false"];
})", })",
toDot(requireType("x"), opts)); toDot(requireType("x"), opts));
} }

View file

@ -5,6 +5,7 @@
#include "Fixture.h" #include "Fixture.h"
#include "ScopedFlags.h"
#include "doctest.h" #include "doctest.h"
using namespace Luau; using namespace Luau;
@ -44,8 +45,8 @@ TEST_CASE_FIXTURE(Fixture, "free_types")
TEST_CASE_FIXTURE(Fixture, "cyclic_table") TEST_CASE_FIXTURE(Fixture, "cyclic_table")
{ {
TypeVar cyclicTable{TypeVariant(TableTypeVar())}; Type cyclicTable{TypeVariant(TableType())};
TableTypeVar* tableOne = getMutable<TableTypeVar>(&cyclicTable); TableType* tableOne = getMutable<TableType>(&cyclicTable);
tableOne->props["self"] = {&cyclicTable}; tableOne->props["self"] = {&cyclicTable};
CHECK_EQ("t1 where t1 = { self: t1 }", toString(&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") TEST_CASE_FIXTURE(Fixture, "named_table")
{ {
TypeVar table{TypeVariant(TableTypeVar())}; Type table{TypeVariant(TableType())};
TableTypeVar* t = getMutable<TableTypeVar>(&table); TableType* t = getMutable<TableType>(&table);
t->name = "TheTable"; t->name = "TheTable";
CHECK_EQ("TheTable", toString(&table)); CHECK_EQ("TheTable", toString(&table));
@ -94,19 +95,43 @@ TEST_CASE_FIXTURE(Fixture, "table_respects_use_line_break")
//clang-format on //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") TEST_CASE_FIXTURE(Fixture, "metatable")
{ {
TypeVar table{TypeVariant(TableTypeVar())}; Type table{TypeVariant(TableType())};
TypeVar metatable{TypeVariant(TableTypeVar())}; Type metatable{TypeVariant(TableType())};
TypeVar mtv{TypeVariant(MetatableTypeVar{&table, &metatable})}; Type mtv{TypeVariant(MetatableType{&table, &metatable})};
CHECK_EQ("{ @metatable { }, { } }", toString(&mtv)); CHECK_EQ("{ @metatable { }, { } }", toString(&mtv));
} }
TEST_CASE_FIXTURE(Fixture, "named_metatable") TEST_CASE_FIXTURE(Fixture, "named_metatable")
{ {
TypeVar table{TypeVariant(TableTypeVar())}; Type table{TypeVariant(TableType())};
TypeVar metatable{TypeVariant(TableTypeVar())}; Type metatable{TypeVariant(TableType())};
TypeVar mtv{TypeVariant(MetatableTypeVar{&table, &metatable, "NamedMetatable"})}; Type mtv{TypeVariant(MetatableType{&table, &metatable, "NamedMetatable"})};
CHECK_EQ("NamedMetatable", toString(&mtv)); CHECK_EQ("NamedMetatable", toString(&mtv));
} }
@ -120,7 +145,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "named_metatable_toStringNamedFunction")
)"); )");
TypeId ty = requireType("createTbl"); TypeId ty = requireType("createTbl");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty)); const FunctionType* ftv = get<FunctionType>(follow(ty));
REQUIRE(ftv); REQUIRE(ftv);
CHECK_EQ("createTbl(): NamedMetatable", toStringNamedFunction("createTbl", *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") TEST_CASE_FIXTURE(Fixture, "intersection_parenthesized_only_if_needed")
{ {
auto utv = TypeVar{UnionTypeVar{{typeChecker.numberType, typeChecker.stringType}}}; auto utv = Type{UnionType{{typeChecker.numberType, typeChecker.stringType}}};
auto itv = TypeVar{IntersectionTypeVar{{&utv, typeChecker.booleanType}}}; auto itv = Type{IntersectionType{{&utv, typeChecker.booleanType}}};
CHECK_EQ(toString(&itv), "(number | string) & boolean"); CHECK_EQ(toString(&itv), "(number | string) & boolean");
} }
TEST_CASE_FIXTURE(Fixture, "union_parenthesized_only_if_needed") TEST_CASE_FIXTURE(Fixture, "union_parenthesized_only_if_needed")
{ {
auto itv = TypeVar{IntersectionTypeVar{{typeChecker.numberType, typeChecker.stringType}}}; auto itv = Type{IntersectionType{{typeChecker.numberType, typeChecker.stringType}}};
auto utv = TypeVar{UnionTypeVar{{&itv, typeChecker.booleanType}}}; auto utv = Type{UnionType{{&itv, typeChecker.booleanType}}};
CHECK_EQ(toString(&utv), "(number & string) | boolean"); 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 stringAndNumberPack = TypePackVar{TypePack{{typeChecker.stringType, typeChecker.numberType}}};
auto numberAndStringPack = TypePackVar{TypePack{{typeChecker.numberType, typeChecker.stringType}}}; auto numberAndStringPack = TypePackVar{TypePack{{typeChecker.numberType, typeChecker.stringType}}};
auto sn2ns = TypeVar{FunctionTypeVar{&stringAndNumberPack, &numberAndStringPack}}; auto sn2ns = Type{FunctionType{&stringAndNumberPack, &numberAndStringPack}};
auto ns2sn = TypeVar{FunctionTypeVar(typeChecker.globalScope->level, &numberAndStringPack, &stringAndNumberPack)}; auto ns2sn = Type{FunctionType(typeChecker.globalScope->level, &numberAndStringPack, &stringAndNumberPack)};
auto utv = TypeVar{UnionTypeVar{{&ns2sn, &sn2ns}}}; auto utv = Type{UnionType{{&ns2sn, &sn2ns}}};
auto itv = TypeVar{IntersectionTypeVar{{&ns2sn, &sn2ns}}}; auto itv = Type{IntersectionType{{&ns2sn, &sn2ns}}};
CHECK_EQ(toString(&utv), "((number, string) -> (string, number)) | ((string, number) -> (number, string))"); CHECK_EQ(toString(&utv), "((number, string) -> (string, number)) | ((string, number) -> (number, string))");
CHECK_EQ(toString(&itv), "((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") TEST_CASE_FIXTURE(Fixture, "quit_stringifying_table_type_when_length_is_exceeded")
{ {
TableTypeVar ttv{}; TableType ttv{};
for (char c : std::string("abcdefghijklmno")) for (char c : std::string("abcdefghijklmno"))
ttv.props[std::string(1, c)] = {typeChecker.numberType}; ttv.props[std::string(1, c)] = {typeChecker.numberType};
TypeVar tv{ttv}; Type tv{ttv};
ToStringOptions o; ToStringOptions o;
o.exhaustive = false; 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") TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_is_still_capped_when_exhaustive")
{ {
TableTypeVar ttv{}; TableType ttv{};
for (char c : std::string("abcdefg")) for (char c : std::string("abcdefg"))
ttv.props[std::string(1, c)] = {typeChecker.numberType}; ttv.props[std::string(1, c)] = {typeChecker.numberType};
TypeVar tv{ttv}; Type tv{ttv};
ToStringOptions o; ToStringOptions o;
o.exhaustive = true; 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") 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")) for (char c : std::string("abcdefghij"))
ttv.props[std::string(1, c)] = {typeChecker.numberType}; ttv.props[std::string(1, c)] = {typeChecker.numberType};
TypeVar tv{ttv}; Type tv{ttv};
ToStringOptions o; ToStringOptions o;
o.maxTableLength = 40; 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") TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_union_type_bails_early")
{ {
TypeVar tv{UnionTypeVar{{typeChecker.stringType, typeChecker.numberType}}}; Type tv{UnionType{{typeChecker.stringType, typeChecker.numberType}}};
UnionTypeVar* utv = getMutable<UnionTypeVar>(&tv); UnionType* utv = getMutable<UnionType>(&tv);
utv->options.push_back(&tv); utv->options.push_back(&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") TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_intersection_type_bails_early")
{ {
TypeVar tv{IntersectionTypeVar{}}; Type tv{IntersectionType{}};
IntersectionTypeVar* itv = getMutable<IntersectionTypeVar>(&tv); IntersectionType* itv = getMutable<IntersectionType>(&tv);
itv->parts.push_back(&tv); itv->parts.push_back(&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") 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}; ttv.indexer = TableIndexer{typeChecker.numberType, typeChecker.stringType};
CHECK_EQ("{string}", toString(TypeVar{ttv})); CHECK_EQ("{string}", toString(Type{ttv}));
ttv.props["A"] = {typeChecker.numberType}; 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.props.clear();
ttv.state = TableState::Unsealed; 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"}}; TypePackVar tpv{GenericTypePack{"a"}};
CHECK_EQ(toString(&tpv), "a..."); CHECK_EQ(toString(&tpv), "a...");
TypeVar tv{GenericTypeVar{"a"}}; Type tv{GenericType{"a"}};
CHECK_EQ(toString(&tv), "a"); CHECK_EQ(toString(&tv), "a");
} }
@ -444,11 +469,11 @@ TEST_CASE_FIXTURE(Fixture, "toStringDetailed")
TypeId id3Type = requireType("id3"); TypeId id3Type = requireType("id3");
ToStringResult nameData = toStringDetailed(id3Type, opts); 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) -> (a, b, c)", nameData.name); REQUIRE_EQ("<a, b, c>(a, b, c) -> (a, b, c)", nameData.name);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(id3Type)); const FunctionType* ftv = get<FunctionType>(follow(id3Type));
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
auto params = flatten(ftv->argTypes).first; auto params = flatten(ftv->argTypes).first;
@ -483,27 +508,27 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "toStringDetailed2")
TypeId tType = requireType("inst"); TypeId tType = requireType("inst");
ToStringResult r = toStringDetailed(tType, opts); ToStringResult r = toStringDetailed(tType, opts);
CHECK_EQ("{ @metatable { __index: { @metatable {| __index: base |}, child } }, inst }", r.name); 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<MetatableTypeVar>(tType); const MetatableType* tMeta = get<MetatableType>(tType);
REQUIRE(tMeta); REQUIRE(tMeta);
TableTypeVar* tMeta2 = getMutable<TableTypeVar>(tMeta->metatable); TableType* tMeta2 = getMutable<TableType>(tMeta->metatable);
REQUIRE(tMeta2); REQUIRE(tMeta2);
REQUIRE(tMeta2->props.count("__index")); REQUIRE(tMeta2->props.count("__index"));
const MetatableTypeVar* tMeta3 = get<MetatableTypeVar>(tMeta2->props["__index"].type); const MetatableType* tMeta3 = get<MetatableType>(tMeta2->props["__index"].type);
REQUIRE(tMeta3); REQUIRE(tMeta3);
TableTypeVar* tMeta4 = getMutable<TableTypeVar>(tMeta3->metatable); TableType* tMeta4 = getMutable<TableType>(tMeta3->metatable);
REQUIRE(tMeta4); REQUIRE(tMeta4);
REQUIRE(tMeta4->props.count("__index")); REQUIRE(tMeta4->props.count("__index"));
TableTypeVar* tMeta5 = getMutable<TableTypeVar>(tMeta4->props["__index"].type); TableType* tMeta5 = getMutable<TableType>(tMeta4->props["__index"].type);
REQUIRE(tMeta5); REQUIRE(tMeta5);
REQUIRE(tMeta5->props.count("one") > 0); REQUIRE(tMeta5->props.count("one") > 0);
TableTypeVar* tMeta6 = getMutable<TableTypeVar>(tMeta3->table); TableType* tMeta6 = getMutable<TableType>(tMeta3->table);
REQUIRE(tMeta6); REQUIRE(tMeta6);
REQUIRE(tMeta6->props.count("two") > 0); 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") TEST_CASE_FIXTURE(Fixture, "toString_the_boundTo_table_type_contained_within_a_TypePack")
{ {
TypeVar tv1{TableTypeVar{}}; Type tv1{TableType{}};
TableTypeVar* ttv = getMutable<TableTypeVar>(&tv1); TableType* ttv = getMutable<TableType>(&tv1);
ttv->state = TableState::Sealed; ttv->state = TableState::Sealed;
ttv->props["hello"] = {typeChecker.numberType}; ttv->props["hello"] = {typeChecker.numberType};
ttv->props["world"] = {typeChecker.numberType}; ttv->props["world"] = {typeChecker.numberType};
TypePackVar tpv1{TypePack{{&tv1}}}; TypePackVar tpv1{TypePack{{&tv1}}};
TypeVar tv2{TableTypeVar{}}; Type tv2{TableType{}};
TableTypeVar* bttv = getMutable<TableTypeVar>(&tv2); TableType* bttv = getMutable<TableType>(&tv2);
bttv->state = TableState::Free; bttv->state = TableState::Free;
bttv->props["hello"] = {typeChecker.numberType}; bttv->props["hello"] = {typeChecker.numberType};
bttv->boundTo = &tv1; 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") TEST_CASE_FIXTURE(Fixture, "no_parentheses_around_return_type_if_pack_has_an_empty_head_link")
{ {
TypeArena arena; TypeArena arena;
TypePackId realTail = arena.addTypePack({singletonTypes->stringType}); TypePackId realTail = arena.addTypePack({builtinTypes->stringType});
TypePackId emptyTail = arena.addTypePack({}, realTail); 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)); 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") TEST_CASE_FIXTURE(Fixture, "self_recursive_instantiated_param")
{ {
TypeVar tableTy{TableTypeVar{}}; Type tableTy{TableType{}};
TableTypeVar* ttv = getMutable<TableTypeVar>(&tableTy); TableType* ttv = getMutable<TableType>(&tableTy);
ttv->name = "Table"; ttv->name = "Table";
ttv->instantiatedTypeParams.push_back(&tableTy); ttv->instantiatedTypeParams.push_back(&tableTy);
@ -612,7 +637,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_id")
)"); )");
TypeId ty = requireType("id"); TypeId ty = requireType("id");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty)); const FunctionType* ftv = get<FunctionType>(follow(ty));
CHECK_EQ("id<a>(x: a): a", toStringNamedFunction("id", *ftv)); CHECK_EQ("id<a>(x: a): a", toStringNamedFunction("id", *ftv));
} }
@ -630,7 +655,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_map")
)"); )");
TypeId ty = requireType("map"); TypeId ty = requireType("map");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty)); const FunctionType* ftv = get<FunctionType>(follow(ty));
CHECK_EQ("map<a, b>(arr: {a}, fn: (a) -> b): {b}", toStringNamedFunction("map", *ftv)); CHECK_EQ("map<a, b>(arr: {a}, fn: (a) -> b): {b}", toStringNamedFunction("map", *ftv));
} }
@ -646,7 +671,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_generic_pack")
)"); )");
TypeId ty = requireType("test"); TypeId ty = requireType("test");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty)); const FunctionType* ftv = get<FunctionType>(follow(ty));
CHECK_EQ("test<T..., U...>(...: T...): U...", toStringNamedFunction("test", *ftv)); CHECK_EQ("test<T..., U...>(...: T...): U...", toStringNamedFunction("test", *ftv));
} }
@ -654,7 +679,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_generic_pack")
TEST_CASE("toStringNamedFunction_unit_f") TEST_CASE("toStringNamedFunction_unit_f")
{ {
TypePackVar empty{TypePack{}}; TypePackVar empty{TypePack{}};
FunctionTypeVar ftv{&empty, &empty, {}, false}; FunctionType ftv{&empty, &empty, {}, false};
CHECK_EQ("f(): ()", toStringNamedFunction("f", ftv)); CHECK_EQ("f(): ()", toStringNamedFunction("f", ftv));
} }
@ -667,7 +692,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics")
)"); )");
TypeId ty = requireType("f"); TypeId ty = requireType("f");
auto ftv = get<FunctionTypeVar>(follow(ty)); auto ftv = get<FunctionType>(follow(ty));
CHECK_EQ("f<a, b...>(x: a, ...: any): (a, a, b...)", toStringNamedFunction("f", *ftv)); CHECK_EQ("f<a, b...>(x: a, ...: any): (a, a, b...)", toStringNamedFunction("f", *ftv));
} }
@ -681,7 +706,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics2")
)"); )");
TypeId ty = requireType("f"); TypeId ty = requireType("f");
auto ftv = get<FunctionTypeVar>(follow(ty)); auto ftv = get<FunctionType>(follow(ty));
CHECK_EQ("f(): ...number", toStringNamedFunction("f", *ftv)); CHECK_EQ("f(): ...number", toStringNamedFunction("f", *ftv));
} }
@ -695,7 +720,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics3")
)"); )");
TypeId ty = requireType("f"); TypeId ty = requireType("f");
auto ftv = get<FunctionTypeVar>(follow(ty)); auto ftv = get<FunctionType>(follow(ty));
CHECK_EQ("f(): (string, ...number)", toStringNamedFunction("f", *ftv)); 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"); TypeId ty = requireType("f");
auto ftv = get<FunctionTypeVar>(follow(ty)); auto ftv = get<FunctionType>(follow(ty));
CHECK_EQ("f(_: number, y: number): number", toStringNamedFunction("f", *ftv)); 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"); TypeId ty = requireType("f");
auto ftv = get<FunctionTypeVar>(follow(ty)); auto ftv = get<FunctionType>(follow(ty));
ToStringOptions opts; ToStringOptions opts;
opts.hideNamedFunctionTypeParameters = true; opts.hideNamedFunctionTypeParameters = true;
@ -734,7 +759,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_overrides_param_names")
)"); )");
TypeId ty = requireType("test"); TypeId ty = requireType("test");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty)); const FunctionType* ftv = get<FunctionType>(follow(ty));
ToStringOptions opts; ToStringOptions opts;
opts.namedFunctionOverrideArgNames = {"first", "second", "third"}; opts.namedFunctionOverrideArgNames = {"first", "second", "third"};
@ -763,8 +788,8 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_include_self_param")
)"); )");
TypeId parentTy = requireType("foo"); TypeId parentTy = requireType("foo");
auto ttv = get<TableTypeVar>(follow(parentTy)); auto ttv = get<TableType>(follow(parentTy));
auto ftv = get<FunctionTypeVar>(ttv->props.at("method").type); auto ftv = get<FunctionType>(ttv->props.at("method").type);
CHECK_EQ("foo:method<a>(self: a, arg: string): ()", toStringNamedFunction("foo:method", *ftv)); CHECK_EQ("foo:method<a>(self: a, arg: string): ()", toStringNamedFunction("foo:method", *ftv));
} }
@ -782,8 +807,8 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_hide_self_param")
)"); )");
TypeId parentTy = requireType("foo"); TypeId parentTy = requireType("foo");
auto ttv = get<TableTypeVar>(follow(parentTy)); auto ttv = get<TableType>(follow(parentTy));
auto ftv = get<FunctionTypeVar>(ttv->props.at("method").type); auto ftv = get<FunctionType>(ttv->props.at("method").type);
ToStringOptions opts; ToStringOptions opts;
opts.hideFunctionSelfArgument = true; opts.hideFunctionSelfArgument = true;

View file

@ -2,7 +2,7 @@
#include "Luau/Parser.h" #include "Luau/Parser.h"
#include "Luau/TypeAttach.h" #include "Luau/TypeAttach.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/Transpiler.h" #include "Luau/Transpiler.h"
#include "Fixture.h" #include "Fixture.h"

View file

@ -78,8 +78,8 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias")
Location{{1, 21}, {1, 26}}, Location{{1, 21}, {1, 26}},
getMainSourceModule()->name, getMainSourceModule()->name,
TypeMismatch{ TypeMismatch{
singletonTypes->numberType, builtinTypes->numberType,
singletonTypes->stringType, builtinTypes->stringType,
}, },
}); });
} }
@ -89,8 +89,8 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias")
Location{{1, 8}, {1, 26}}, Location{{1, 8}, {1, 26}},
getMainSourceModule()->name, getMainSourceModule()->name,
TypeMismatch{ TypeMismatch{
singletonTypes->numberType, builtinTypes->numberType,
singletonTypes->stringType, builtinTypes->stringType,
}, },
}); });
} }
@ -512,13 +512,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "general_require_multi_assign")
std::optional<TypeId> aTypeId = lookupName(m->getModuleScope(), "a"); std::optional<TypeId> aTypeId = lookupName(m->getModuleScope(), "a");
REQUIRE(aTypeId); REQUIRE(aTypeId);
const Luau::TableTypeVar* aType = get<TableTypeVar>(follow(*aTypeId)); const Luau::TableType* aType = get<TableType>(follow(*aTypeId));
REQUIRE(aType); REQUIRE(aType);
REQUIRE(aType->props.size() == 2); REQUIRE(aType->props.size() == 2);
std::optional<TypeId> bTypeId = lookupName(m->getModuleScope(), "b"); std::optional<TypeId> bTypeId = lookupName(m->getModuleScope(), "b");
REQUIRE(bTypeId); REQUIRE(bTypeId);
const Luau::TableTypeVar* bType = get<TableTypeVar>(follow(*bTypeId)); const Luau::TableType* bType = get<TableType>(follow(*bTypeId));
REQUIRE(bType); REQUIRE(bType);
REQUIRE(bType->props.size() == 3); REQUIRE(bType->props.size() == 3);
} }
@ -535,7 +535,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_import_mutation")
else else
CHECK(toString(ty) == "table"); CHECK(toString(ty) == "table");
const TableTypeVar* ttv = get<TableTypeVar>(ty); const TableType* ttv = get<TableType>(ty);
REQUIRE(ttv); REQUIRE(ttv);
CHECK(ttv->instantiatedTypeParams.empty()); CHECK(ttv->instantiatedTypeParams.empty());
@ -554,7 +554,7 @@ type NotCool<x> = Cool
REQUIRE(ty); REQUIRE(ty);
CHECK_EQ(toString(*ty), "Cool"); CHECK_EQ(toString(*ty), "Cool");
const TableTypeVar* ttv = get<TableTypeVar>(*ty); const TableType* ttv = get<TableType>(*ty);
REQUIRE(ttv); REQUIRE(ttv);
CHECK(ttv->instantiatedTypeParams.empty()); CHECK(ttv->instantiatedTypeParams.empty());
@ -590,7 +590,7 @@ type Cool = typeof(c)
std::optional<TypeId> ty = requireType("c"); std::optional<TypeId> ty = requireType("c");
REQUIRE(ty); REQUIRE(ty);
const TableTypeVar* ttv = get<TableTypeVar>(*ty); const TableType* ttv = get<TableType>(*ty);
REQUIRE(ttv); REQUIRE(ttv);
CHECK_EQ(ttv->name, "Cool"); 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 * 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. * 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") 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. * 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 * 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<TypeId> t1 = lookupType("MyString"); std::optional<TypeId> t1 = lookupType("MyString");
REQUIRE(t1); REQUIRE(t1);
CHECK(isPrim(*t1, PrimitiveTypeVar::String)); CHECK(isPrim(*t1, PrimitiveType::String));
std::optional<TypeId> t2 = lookupType("string"); std::optional<TypeId> t2 = lookupType("string");
REQUIRE(t2); REQUIRE(t2);
CHECK(isPrim(*t2, PrimitiveTypeVar::String)); CHECK(isPrim(*t2, PrimitiveType::String));
} }
TEST_CASE_FIXTURE(Fixture, "it_is_ok_to_shadow_user_defined_alias") TEST_CASE_FIXTURE(Fixture, "it_is_ok_to_shadow_user_defined_alias")

View file

@ -1,7 +1,7 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details // 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/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Fixture.h" #include "Fixture.h"
@ -77,7 +77,7 @@ TEST_CASE_FIXTURE(Fixture, "function_return_annotations_are_checked")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
TypeId fiftyType = requireType("fifty"); TypeId fiftyType = requireType("fifty");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(fiftyType); const FunctionType* ftv = get<FunctionType>(fiftyType);
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
TypePackId retPack = follow(ftv->retTypes); TypePackId retPack = follow(ftv->retTypes);
@ -182,8 +182,8 @@ TEST_CASE_FIXTURE(Fixture, "table_annotation")
)"); )");
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(PrimitiveTypeVar::Number, getPrimitiveType(follow(requireType("y")))); CHECK_EQ(PrimitiveType::Number, getPrimitiveType(follow(requireType("y"))));
CHECK_EQ(PrimitiveTypeVar::String, getPrimitiveType(follow(requireType("z")))); CHECK_EQ(PrimitiveType::String, getPrimitiveType(follow(requireType("z"))));
} }
TEST_CASE_FIXTURE(Fixture, "function_annotation") TEST_CASE_FIXTURE(Fixture, "function_annotation")
@ -196,7 +196,7 @@ TEST_CASE_FIXTURE(Fixture, "function_annotation")
dumpErrors(result); dumpErrors(result);
TypeId fType = requireType("f"); TypeId fType = requireType("f");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(fType)); const FunctionType* ftv = get<FunctionType>(follow(fType));
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
} }
@ -208,7 +208,7 @@ TEST_CASE_FIXTURE(Fixture, "function_annotation_with_a_defined_function")
)"); )");
TypeId fType = requireType("f"); TypeId fType = requireType("f");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(fType)); const FunctionType* ftv = get<FunctionType>(follow(fType));
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
@ -323,13 +323,13 @@ TEST_CASE_FIXTURE(Fixture, "self_referential_type_alias")
REQUIRE(res); REQUIRE(res);
TypeId oType = follow(res->type); TypeId oType = follow(res->type);
const TableTypeVar* oTable = get<TableTypeVar>(oType); const TableType* oTable = get<TableType>(oType);
REQUIRE(oTable); REQUIRE(oTable);
std::optional<Property> incr = get(oTable->props, "incr"); std::optional<Property> incr = get(oTable->props, "incr");
REQUIRE(incr); REQUIRE(incr);
const FunctionTypeVar* incrFunc = get<FunctionTypeVar>(incr->type); const FunctionType* incrFunc = get<FunctionType>(incr->type);
REQUIRE(incrFunc); REQUIRE(incrFunc);
std::optional<TypeId> firstArg = first(incrFunc->argTypes); std::optional<TypeId> firstArg = first(incrFunc->argTypes);
@ -441,7 +441,7 @@ TEST_CASE_FIXTURE(Fixture, "corecursive_types_error_on_tight_loop")
)"); )");
TypeId fType = requireType("aa"); TypeId fType = requireType("aa");
const AnyTypeVar* ftv = get<AnyTypeVar>(follow(fType)); const AnyType* ftv = get<AnyType>(follow(fType));
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
REQUIRE(!result.errors.empty()); REQUIRE(!result.errors.empty());
} }
@ -483,7 +483,7 @@ TEST_CASE_FIXTURE(Fixture, "interface_types_belong_to_interface_arena")
std::optional<TypeId> exportsType = first(mod.getModuleScope()->returnType); std::optional<TypeId> exportsType = first(mod.getModuleScope()->returnType);
REQUIRE(exportsType); REQUIRE(exportsType);
TableTypeVar* exportsTable = getMutable<TableTypeVar>(*exportsType); TableType* exportsTable = getMutable<TableType>(*exportsType);
REQUIRE(exportsTable != nullptr); REQUIRE(exportsTable != nullptr);
TypeId n = exportsTable->props["n"].type; 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()); REQUIRE_EQ(1, array.typeParams.size());
const TableTypeVar* arrayTable = get<TableTypeVar>(array.type); const TableType* arrayTable = get<TableType>(array.type);
REQUIRE(arrayTable != nullptr); REQUIRE(arrayTable != nullptr);
CHECK_EQ(0, arrayTable->props.size()); CHECK_EQ(0, arrayTable->props.size());
@ -538,7 +538,7 @@ TEST_CASE_FIXTURE(Fixture, "cloned_interface_maintains_pointers_between_definiti
std::optional<TypeId> exportsType = first(mod.getModuleScope()->returnType); std::optional<TypeId> exportsType = first(mod.getModuleScope()->returnType);
REQUIRE(exportsType); REQUIRE(exportsType);
TableTypeVar* exportsTable = getMutable<TableTypeVar>(*exportsType); TableType* exportsTable = getMutable<TableType>(*exportsType);
REQUIRE(exportsTable != nullptr); REQUIRE(exportsTable != nullptr);
TypeId aType = exportsTable->props["a"].type; TypeId aType = exportsTable->props["a"].type;
@ -740,8 +740,8 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_type_fun_should_not_trip_rbxassert")
} }
#if 0 #if 0
// This is because, after visiting all nodes in a block, we check if each type alias still points to a FreeTypeVar. // 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 BoundTypeVar, with no luck. // 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. // Not important enough to fix today.
TEST_CASE_FIXTURE(Fixture, "pulling_a_type_from_value_dont_falsely_create_occurs_check_failed") 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 #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"( CheckResult result = check(R"(
type T = T | T type T = T | T
@ -767,7 +767,7 @@ TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_union_typevar")
REQUIRE(ocf); 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"( CheckResult result = check(R"(
type T = T & T type T = T & T

View file

@ -4,8 +4,8 @@
#include "Luau/BuiltinDefinitions.h" #include "Luau/BuiltinDefinitions.h"
#include "Luau/Scope.h" #include "Luau/Scope.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/VisitTypeVar.h" #include "Luau/VisitType.h"
#include "Fixture.h" #include "Fixture.h"
@ -175,7 +175,7 @@ TEST_CASE_FIXTURE(Fixture, "can_get_length_of_any")
LUAU_REQUIRE_NO_ERRORS(result); 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") 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); LUAU_REQUIRE_NO_ERRORS(result);
TableTypeVar* ttv = getMutable<TableTypeVar>(requireType("T")); TableType* ttv = getMutable<TableType>(requireType("T"));
REQUIRE(ttv); REQUIRE(ttv);
REQUIRE(ttv->props.count("prop")); REQUIRE(ttv->props.count("prop"));

View file

@ -185,7 +185,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_tables_sealed")
)LUA"); )LUA");
TypeId bit32 = requireType("b"); TypeId bit32 = requireType("b");
REQUIRE(bit32 != nullptr); REQUIRE(bit32 != nullptr);
const TableTypeVar* bit32t = get<TableTypeVar>(bit32); const TableType* bit32t = get<TableType>(bit32);
REQUIRE(bit32t != nullptr); REQUIRE(bit32t != nullptr);
CHECK_EQ(bit32t->state, TableState::Sealed); 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); LUAU_REQUIRE_ERROR_COUNT(1, result);
auto stringType = requireType("string"); auto stringType = requireType("string");
auto ttv = get<TableTypeVar>(stringType); auto ttv = get<TableType>(stringType);
REQUIRE(ttv); REQUIRE(ttv);
} }
@ -915,13 +915,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "dont_add_definitions_to_persistent_types")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
TypeId fType = requireType("f"); TypeId fType = requireType("f");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(fType); const FunctionType* ftv = get<FunctionType>(fType);
REQUIRE(fType); REQUIRE(fType);
REQUIRE(fType->persistent); REQUIRE(fType->persistent);
REQUIRE(!ftv->definition); REQUIRE(!ftv->definition);
TypeId gType = requireType("g"); TypeId gType = requireType("g");
const FunctionTypeVar* gtv = get<FunctionTypeVar>(gType); const FunctionType* gtv = get<FunctionType>(gType);
REQUIRE(gType); REQUIRE(gType);
REQUIRE(!gType->persistent); REQUIRE(!gType->persistent);
REQUIRE(gtv->definition); REQUIRE(gtv->definition);
@ -1029,9 +1029,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "no_persistent_typelevel_change")
{ {
TypeId mathTy = requireType(typeChecker.globalScope, "math"); TypeId mathTy = requireType(typeChecker.globalScope, "math");
REQUIRE(mathTy); REQUIRE(mathTy);
TableTypeVar* ttv = getMutable<TableTypeVar>(mathTy); TableType* ttv = getMutable<TableType>(mathTy);
REQUIRE(ttv); REQUIRE(ttv);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(ttv->props["frexp"].type); const FunctionType* ftv = get<FunctionType>(ttv->props["frexp"].type);
REQUIRE(ftv); REQUIRE(ftv);
auto original = ftv->level; auto original = ftv->level;

View file

@ -2,7 +2,7 @@
#include "Luau/BuiltinDefinitions.h" #include "Luau/BuiltinDefinitions.h"
#include "Luau/Common.h" #include "Luau/Common.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Fixture.h" #include "Fixture.h"
#include "ClassFixture.h" #include "ClassFixture.h"

View file

@ -1,7 +1,7 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details // 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/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Fixture.h" #include "Fixture.h"
@ -294,7 +294,7 @@ TEST_CASE_FIXTURE(Fixture, "definitions_documentation_symbols")
REQUIRE(bool(barTy)); REQUIRE(bool(barTy));
CHECK_EQ(barTy->type->documentationSymbol, "@test/globaltype/Bar"); CHECK_EQ(barTy->type->documentationSymbol, "@test/globaltype/Bar");
ClassTypeVar* barClass = getMutable<ClassTypeVar>(barTy->type); ClassType* barClass = getMutable<ClassType>(barTy->type);
REQUIRE(bool(barClass)); REQUIRE(bool(barClass));
REQUIRE_EQ(barClass->props.count("prop"), 1); REQUIRE_EQ(barClass->props.count("prop"), 1);
CHECK_EQ(barClass->props["prop"].documentationSymbol, "@test/globaltype/Bar.prop"); CHECK_EQ(barClass->props["prop"].documentationSymbol, "@test/globaltype/Bar.prop");
@ -303,7 +303,7 @@ TEST_CASE_FIXTURE(Fixture, "definitions_documentation_symbols")
REQUIRE(bool(yBinding)); REQUIRE(bool(yBinding));
CHECK_EQ(yBinding->documentationSymbol, "@test/global/y"); CHECK_EQ(yBinding->documentationSymbol, "@test/global/y");
TableTypeVar* yTtv = getMutable<TableTypeVar>(yBinding->typeId); TableType* yTtv = getMutable<TableType>(yBinding->typeId);
REQUIRE(bool(yTtv)); REQUIRE(bool(yTtv));
REQUIRE_EQ(yTtv->props.count("x"), 1); REQUIRE_EQ(yTtv->props.count("x"), 1);
CHECK_EQ(yTtv->props["x"].documentationSymbol, "@test/global/y.x"); CHECK_EQ(yTtv->props["x"].documentationSymbol, "@test/global/y.x");

View file

@ -5,8 +5,8 @@
#include "Luau/Error.h" #include "Luau/Error.h"
#include "Luau/Scope.h" #include "Luau/Scope.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/VisitTypeVar.h" #include "Luau/VisitType.h"
#include "Fixture.h" #include "Fixture.h"
@ -23,7 +23,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_function")
CheckResult result = check("function five() return 5 end"); CheckResult result = check("function five() return 5 end");
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* fiveType = get<FunctionTypeVar>(requireType("five")); const FunctionType* fiveType = get<FunctionType>(requireType("five"));
REQUIRE(fiveType != nullptr); REQUIRE(fiveType != nullptr);
} }
@ -64,7 +64,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_return_type")
CheckResult result = check("function take_five() return 5 end"); CheckResult result = check("function take_five() return 5 end");
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* takeFiveType = get<FunctionTypeVar>(requireType("take_five")); const FunctionType* takeFiveType = get<FunctionType>(requireType("take_five"));
REQUIRE(takeFiveType != nullptr); REQUIRE(takeFiveType != nullptr);
std::vector<TypeId> retVec = flatten(takeFiveType->retTypes).first; std::vector<TypeId> retVec = flatten(takeFiveType->retTypes).first;
@ -132,7 +132,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "vararg_function_is_quantified")
auto r = first(getMainModule()->getModuleScope()->returnType); auto r = first(getMainModule()->getModuleScope()->returnType);
REQUIRE(r); REQUIRE(r);
TableTypeVar* ttv = getMutable<TableTypeVar>(*r); TableType* ttv = getMutable<TableType>(*r);
REQUIRE(ttv); REQUIRE(ttv);
REQUIRE(ttv->props.count("f")); REQUIRE(ttv->props.count("f"));
@ -389,14 +389,14 @@ TEST_CASE_FIXTURE(Fixture, "local_function")
TypeId h = follow(requireType("h")); TypeId h = follow(requireType("h"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(h); const FunctionType* ftv = get<FunctionType>(h);
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
std::optional<TypeId> rt = first(ftv->retTypes); std::optional<TypeId> rt = first(ftv->retTypes);
REQUIRE(bool(rt)); REQUIRE(bool(rt));
TypeId retType = follow(*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") 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); LUAU_REQUIRE_NO_ERRORS(result);
const Luau::FunctionTypeVar* fn = get<FunctionTypeVar>(requireType("p")); const Luau::FunctionType* fn = get<FunctionType>(requireType("p"));
REQUIRE(fn); REQUIRE(fn);
auto ret = first(fn->retTypes); auto ret = first(fn->retTypes);
REQUIRE(ret); REQUIRE(ret);
REQUIRE(get<GenericTypeVar>(follow(*ret))); REQUIRE(get<GenericType>(follow(*ret)));
} }
TEST_CASE_FIXTURE(Fixture, "first_argument_can_be_optional") 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); LUAU_REQUIRE_NO_ERRORS(result);
TypeId ty = requireType("most_of_the_natural_numbers"); TypeId ty = requireType("most_of_the_natural_numbers");
const FunctionTypeVar* functionType = get<FunctionTypeVar>(ty); const FunctionType* functionType = get<FunctionType>(ty);
REQUIRE_MESSAGE(functionType, "Expected function but got " << toString(ty)); REQUIRE_MESSAGE(functionType, "Expected function but got " << toString(ty));
std::optional<TypeId> retType = first(functionType->retTypes); std::optional<TypeId> retType = first(functionType->retTypes);
REQUIRE(retType); REQUIRE(retType);
CHECK(get<UnionTypeVar>(*retType)); CHECK(get<UnionType>(*retType));
} }
TEST_CASE_FIXTURE(Fixture, "infer_higher_order_function") 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); LUAU_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(requireType("apply")); const FunctionType* ftv = get<FunctionType>(requireType("apply"));
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
std::vector<TypeId> argVec = flatten(ftv->argTypes).first; std::vector<TypeId> argVec = flatten(ftv->argTypes).first;
REQUIRE_EQ(2, argVec.size()); REQUIRE_EQ(2, argVec.size());
const FunctionTypeVar* fType = get<FunctionTypeVar>(follow(argVec[0])); const FunctionType* fType = get<FunctionType>(follow(argVec[0]));
REQUIRE_MESSAGE(fType != nullptr, "Expected a function but got " << toString(argVec[0])); REQUIRE_MESSAGE(fType != nullptr, "Expected a function but got " << toString(argVec[0]));
std::vector<TypeId> fArgs = flatten(fType->argTypes).first; std::vector<TypeId> fArgs = flatten(fType->argTypes).first;
@ -561,14 +561,14 @@ TEST_CASE_FIXTURE(Fixture, "higher_order_function_2")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(requireType("bottomupmerge")); const FunctionType* ftv = get<FunctionType>(requireType("bottomupmerge"));
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
std::vector<TypeId> argVec = flatten(ftv->argTypes).first; std::vector<TypeId> argVec = flatten(ftv->argTypes).first;
REQUIRE_EQ(6, argVec.size()); REQUIRE_EQ(6, argVec.size());
const FunctionTypeVar* fType = get<FunctionTypeVar>(follow(argVec[0])); const FunctionType* fType = get<FunctionType>(follow(argVec[0]));
REQUIRE(fType != nullptr); REQUIRE(fType != nullptr);
} }
@ -591,14 +591,14 @@ TEST_CASE_FIXTURE(Fixture, "higher_order_function_3")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(requireType("swapTwice")); const FunctionType* ftv = get<FunctionType>(requireType("swapTwice"));
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
std::vector<TypeId> argVec = flatten(ftv->argTypes).first; std::vector<TypeId> argVec = flatten(ftv->argTypes).first;
REQUIRE_EQ(1, argVec.size()); REQUIRE_EQ(1, argVec.size());
const TableTypeVar* argType = get<TableTypeVar>(follow(argVec[0])); const TableType* argType = get<TableType>(follow(argVec[0]));
REQUIRE(argType != nullptr); REQUIRE(argType != nullptr);
CHECK(bool(argType->indexer)); 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. * In other words, comp(arr[x], arr[y]) is well-typed.
*/ */
const FunctionTypeVar* ftv = get<FunctionTypeVar>(requireType("mergesort")); const FunctionType* ftv = get<FunctionType>(requireType("mergesort"));
REQUIRE(ftv != nullptr); REQUIRE(ftv != nullptr);
std::vector<TypeId> argVec = flatten(ftv->argTypes).first; std::vector<TypeId> argVec = flatten(ftv->argTypes).first;
REQUIRE_EQ(2, argVec.size()); REQUIRE_EQ(2, argVec.size());
const TableTypeVar* arg0 = get<TableTypeVar>(follow(argVec[0])); const TableType* arg0 = get<TableType>(follow(argVec[0]));
REQUIRE(arg0 != nullptr); REQUIRE(arg0 != nullptr);
REQUIRE(bool(arg0->indexer)); REQUIRE(bool(arg0->indexer));
const FunctionTypeVar* arg1 = get<FunctionTypeVar>(follow(argVec[1])); const FunctionType* arg1 = get<FunctionType>(follow(argVec[1]));
REQUIRE(arg1 != nullptr); REQUIRE(arg1 != nullptr);
REQUIRE_EQ(2, size(arg1->argTypes)); REQUIRE_EQ(2, size(arg1->argTypes));
@ -1003,7 +1003,7 @@ TEST_CASE_FIXTURE(Fixture, "no_lossy_function_type")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
TypeId type = requireTypeAtPosition(Position(6, 14)); TypeId type = requireTypeAtPosition(Position(6, 14));
CHECK_EQ("(tbl, number, number) -> number", toString(type)); CHECK_EQ("(tbl, number, number) -> number", toString(type));
auto ftv = get<FunctionTypeVar>(type); auto ftv = get<FunctionType>(type);
REQUIRE(ftv); REQUIRE(ftv);
CHECK(ftv->hasSelf); CHECK(ftv->hasSelf);
} }

View file

@ -1,6 +1,6 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details // 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/TypeInfer.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/Scope.h" #include "Luau/Scope.h"
#include <algorithm> #include <algorithm>
@ -224,7 +224,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_function")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
TypeId idType = requireType("id"); TypeId idType = requireType("id");
const FunctionTypeVar* idFun = get<FunctionTypeVar>(idType); const FunctionType* idFun = get<FunctionType>(idType);
REQUIRE(idFun); REQUIRE(idFun);
auto [args, varargs] = flatten(idFun->argTypes); auto [args, varargs] = flatten(idFun->argTypes);
auto [rets, varrets] = flatten(idFun->retTypes); auto [rets, varrets] = flatten(idFun->retTypes);
@ -247,7 +247,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_local_function")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
TypeId idType = requireType("id"); TypeId idType = requireType("id");
const FunctionTypeVar* idFun = get<FunctionTypeVar>(idType); const FunctionType* idFun = get<FunctionType>(idType);
REQUIRE(idFun); REQUIRE(idFun);
auto [args, varargs] = flatten(idFun->argTypes); auto [args, varargs] = flatten(idFun->argTypes);
auto [rets, varrets] = flatten(idFun->retTypes); auto [rets, varrets] = flatten(idFun->retTypes);
@ -854,14 +854,14 @@ TEST_CASE_FIXTURE(Fixture, "generic_table_method")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
TypeId tType = requireType("T"); TypeId tType = requireType("T");
TableTypeVar* tTable = getMutable<TableTypeVar>(tType); TableType* tTable = getMutable<TableType>(tType);
REQUIRE(tTable != nullptr); REQUIRE(tTable != nullptr);
REQUIRE(tTable->props.count("bar")); REQUIRE(tTable->props.count("bar"));
TypeId barType = tTable->props["bar"].type; TypeId barType = tTable->props["bar"].type;
REQUIRE(barType != nullptr); REQUIRE(barType != nullptr);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(barType)); const FunctionType* ftv = get<FunctionType>(follow(barType));
REQUIRE_MESSAGE(ftv != nullptr, "Should be a function: " << *barType); REQUIRE_MESSAGE(ftv != nullptr, "Should be a function: " << *barType);
std::vector<TypeId> args = flatten(ftv->argTypes).first; std::vector<TypeId> args = flatten(ftv->argTypes).first;
@ -887,20 +887,20 @@ TEST_CASE_FIXTURE(Fixture, "correctly_instantiate_polymorphic_member_functions")
LUAU_REQUIRE_NO_ERRORS(result); LUAU_REQUIRE_NO_ERRORS(result);
dumpErrors(result); dumpErrors(result);
const TableTypeVar* t = get<TableTypeVar>(requireType("T")); const TableType* t = get<TableType>(requireType("T"));
REQUIRE(t != nullptr); REQUIRE(t != nullptr);
std::optional<Property> fooProp = get(t->props, "foo"); std::optional<Property> fooProp = get(t->props, "foo");
REQUIRE(bool(fooProp)); REQUIRE(bool(fooProp));
const FunctionTypeVar* foo = get<FunctionTypeVar>(follow(fooProp->type)); const FunctionType* foo = get<FunctionType>(follow(fooProp->type));
REQUIRE(bool(foo)); REQUIRE(bool(foo));
std::optional<TypeId> ret_ = first(foo->retTypes); std::optional<TypeId> ret_ = first(foo->retTypes);
REQUIRE(bool(ret_)); REQUIRE(bool(ret_));
TypeId ret = follow(*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"); TypeId g = requireType("g");
const FunctionTypeVar* gFun = get<FunctionTypeVar>(g); const FunctionType* gFun = get<FunctionType>(g);
REQUIRE(gFun != nullptr); REQUIRE(gFun != nullptr);
auto optionArg = first(gFun->argTypes); auto optionArg = first(gFun->argTypes);
REQUIRE(bool(optionArg)); REQUIRE(bool(optionArg));
TypeId arg = follow(*optionArg); TypeId arg = follow(*optionArg);
const TableTypeVar* argTable = get<TableTypeVar>(arg); const TableType* argTable = get<TableType>(arg);
REQUIRE(argTable != nullptr); REQUIRE(argTable != nullptr);
std::optional<Property> methodProp = get(argTable->props, "method"); std::optional<Property> methodProp = get(argTable->props, "method");
REQUIRE(bool(methodProp)); REQUIRE(bool(methodProp));
const FunctionTypeVar* methodFunction = get<FunctionTypeVar>(methodProp->type); const FunctionType* methodFunction = get<FunctionType>(methodProp->type);
REQUIRE(methodFunction != nullptr); REQUIRE(methodFunction != nullptr);
std::optional<TypeId> methodArg = first(methodFunction->argTypes); std::optional<TypeId> methodArg = first(methodFunction->argTypes);

View file

@ -1,6 +1,6 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details // 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/TypeInfer.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Fixture.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); LUAU_REQUIRE_NO_ERRORS(result);
const IntersectionTypeVar* r = get<IntersectionTypeVar>(requireType("r")); const IntersectionType* r = get<IntersectionType>(requireType("r"));
REQUIRE(r); REQUIRE(r);
TableTypeVar* a = getMutable<TableTypeVar>(r->parts[0]); TableType* a = getMutable<TableType>(r->parts[0]);
REQUIRE(a); REQUIRE(a);
CHECK_EQ(typeChecker.numberType, a->props["y"].type); CHECK_EQ(typeChecker.numberType, a->props["y"].type);
TableTypeVar* b = getMutable<TableTypeVar>(r->parts[1]); TableType* b = getMutable<TableType>(r->parts[1]);
REQUIRE(b); REQUIRE(b);
CHECK_EQ(typeChecker.numberType, b->props["y"].type); CHECK_EQ(typeChecker.numberType, b->props["y"].type);
} }

View file

@ -4,8 +4,8 @@
#include "Luau/BuiltinDefinitions.h" #include "Luau/BuiltinDefinitions.h"
#include "Luau/Scope.h" #include "Luau/Scope.h"
#include "Luau/TypeInfer.h" #include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h" #include "Luau/Type.h"
#include "Luau/VisitTypeVar.h" #include "Luau/VisitType.h"
#include "Fixture.h" #include "Fixture.h"

Some files were not shown because too many files have changed in this diff Show more