Sync to upstream/release/557 (#794)

* Fixed unions of `nil` types displaying as `?`
* Internal normalization now handles class types which can make
previously failing (incorrectly) sub-typing checks to succeed
This commit is contained in:
vegorov-rbx 2023-01-04 12:53:17 -08:00 committed by GitHub
parent fb2f146123
commit 75a2e95714
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
117 changed files with 3813 additions and 2584 deletions

View file

@ -4,7 +4,7 @@
#include "Luau/NotNull.h"
#include "Luau/Substitution.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include <memory>
@ -19,12 +19,12 @@ using ScopePtr = std::shared_ptr<Scope>;
// A substitution which replaces free types by any
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);
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);
NotNull<Scope> scope;
NotNull<SingletonTypes> singletonTypes;
NotNull<BuiltinTypes> builtinTypes;
InternalErrorReporter* iceHandler;
TypeId anyType;

View file

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

View file

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

View file

@ -2,7 +2,7 @@
#pragma once
#include "Luau/Location.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include <unordered_map>
#include <string>
@ -65,7 +65,7 @@ struct AutocompleteEntry
// Set if this suggestion matches the type expected in the context
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<std::string> documentationSymbol = std::nullopt;
Tags tags;
@ -89,7 +89,7 @@ struct AutocompleteResult
};
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);

View file

@ -2,7 +2,7 @@
#pragma once
#include "Luau/Scope.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include <optional>
@ -48,7 +48,7 @@ void attachDcrMagicFunction(TypeId ty, DcrMagicFunction fn);
void attachDcrMagicRefinement(TypeId ty, DcrMagicRefinement fn);
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();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -130,8 +130,8 @@ struct Frontend
Frontend(FileResolver* fileResolver, ConfigResolver* configResolver, const FrontendOptions& options = {});
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 = {});
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,
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);
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);
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, std::function<void(TypeChecker&, ScopePtr)>> builtinDefinitions;
SingletonTypes singletonTypes_;
BuiltinTypes builtinTypes_;
public:
const NotNull<SingletonTypes> singletonTypes;
const NotNull<BuiltinTypes> builtinTypes;
FileResolver* fileResolver;
FrontendModuleResolver moduleResolver;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,8 +10,8 @@
namespace Luau
{
struct TypeVar;
using TypeId = const TypeVar*;
struct Type;
using TypeId = const Type*;
struct TruthyPredicate;
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
#pragma once
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
namespace Luau
{

View file

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

View file

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

View file

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

View file

@ -19,13 +19,13 @@ class AstExpr;
struct Scope;
struct TypeVar;
using TypeId = const TypeVar*;
struct Type;
using TypeId = const Type*;
struct TypePackVar;
using TypePackId = const TypePackVar*;
struct FunctionTypeVar;
struct FunctionType;
struct Constraint;
struct Position;
@ -33,7 +33,7 @@ struct Location;
struct ToStringNameMap
{
std::unordered_map<TypeId, std::string> typeVars;
std::unordered_map<TypeId, std::string> types;
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 hideFunctionSelfArgument = false; // If true, `self: X` will be omitted from the function signature if the function has self
bool DEPRECATED_indent = false; // TODO Deprecated field, prune when clipping flag FFlagLuauLineBreaksDeterminIndents
size_t maxTableLength = size_t(FInt::LuauTableTypeMaximumStringifierLength); // Only applied to TableTypeVars
size_t maxTableLength = size_t(FInt::LuauTableTypeMaximumStringifierLength); // Only applied to TableTypes
size_t maxTypeLength = size_t(FInt::LuauTypeMaximumStringifierLength);
ToStringNameMap nameMap;
std::shared_ptr<Scope> scope; // If present, module names will be added and types that are not available in scope will be marked as 'invalid'
@ -105,10 +105,10 @@ inline std::string toString(const Constraint& c)
return toString(c, ToStringOptions{});
}
std::string toString(const TypeVar& tv, ToStringOptions& opts);
std::string toString(const Type& tv, ToStringOptions& opts);
std::string toString(const TypePackVar& tp, ToStringOptions& opts);
inline std::string toString(const TypeVar& tv)
inline std::string toString(const Type& tv)
{
ToStringOptions opts;
return toString(tv, opts);
@ -120,9 +120,9 @@ inline std::string toString(const TypePackVar& tp)
return toString(tp, opts);
}
std::string toStringNamedFunction(const std::string& funcName, const FunctionTypeVar& ftv, ToStringOptions& opts);
std::string toStringNamedFunction(const std::string& funcName, const FunctionType& ftv, ToStringOptions& opts);
inline std::string toStringNamedFunction(const std::string& funcName, const FunctionTypeVar& ftv)
inline std::string toStringNamedFunction(const std::string& funcName, const FunctionType& ftv)
{
ToStringOptions opts;
return toStringNamedFunction(funcName, ftv, opts);

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
#pragma once
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "Luau/TypePack.h"
#include <memory>
@ -12,14 +12,14 @@ namespace Luau
using TypeOrPackId = const void*;
// Pending state for a TypeVar. Generated by a TxnLog and committed via
// Pending state for a Type. Generated by a TxnLog and committed via
// TxnLog::commit.
struct PendingType
{
// The pending TypeVar state.
TypeVar pending;
// The pending Type state.
Type pending;
explicit PendingType(TypeVar state)
explicit PendingType(Type state)
: pending(std::move(state))
{
}
@ -163,7 +163,7 @@ struct TxnLog
// Queues a replacement of a type with another type.
//
// The pointer returned lives until `commit` or `clear` is called.
PendingType* replace(TypeId ty, TypeVar replacement);
PendingType* replace(TypeId ty, Type replacement);
// Queues a replacement of a type pack with another type pack.
//
@ -225,7 +225,7 @@ struct TxnLog
template<typename T>
PendingType* replace(TypeId ty, T replacement)
{
return replace(ty, TypeVar(replacement));
return replace(ty, Type(replacement));
}
// Replaces a given type pack's state with a new variant. Returns the new
@ -262,12 +262,12 @@ struct TxnLog
// Returns whether a given type or type pack is a given state, respecting the
// log's pending state.
//
// This method will not assert if called on a BoundTypeVar or BoundTypePack.
// This method will not assert if called on a BoundType or BoundTypePack.
template<typename T, typename TID>
bool is(TID ty) const
{
// We do not use getMutable here because this method can be called on
// BoundTypeVars, which triggers an assertion.
// BoundTypes, which triggers an assertion.
auto* pendingTy = pending(ty);
if (pendingTy)
return Luau::get_if<T>(&pendingTy->pending.ty) != nullptr;

View file

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

View file

@ -2,7 +2,7 @@
#pragma once
#include "Luau/TypedAllocator.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "Luau/TypePack.h"
#include <vector>
@ -12,7 +12,7 @@ namespace Luau
struct TypeArena
{
TypedAllocator<TypeVar> typeVars;
TypedAllocator<Type> types;
TypedAllocator<TypePackVar> typePacks;
void clear();
@ -20,13 +20,13 @@ struct TypeArena
template<typename T>
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);
return addTV(TypeVar(std::move(tv)));
return addTV(Type(std::move(tv)));
}
TypeId addTV(TypeVar&& tv);
TypeId addTV(Type&& tv);
TypeId freshType(TypeLevel level);
TypeId freshType(Scope* scope);

View file

@ -10,8 +10,8 @@ namespace Luau
{
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

View file

@ -9,7 +9,7 @@
#include "Luau/Substitution.h"
#include "Luau/TxnLog.h"
#include "Luau/TypePack.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "Luau/Unifier.h"
#include "Luau/UnifierSharedState.h"
@ -28,7 +28,7 @@ struct ModuleResolver;
using Name = std::string;
using ScopePtr = std::shared_ptr<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 hasBreak(AstStat* node);
@ -57,11 +57,11 @@ public:
}
};
// All TypeVars are retained via Environment::typeVars. All TypeIds
// All Types are retained via Environment::types. All TypeIds
// within a program are borrowed pointers into this set.
struct TypeChecker
{
explicit TypeChecker(ModuleResolver* resolver, NotNull<SingletonTypes> singletonTypes, InternalErrorReporter* iceHandler);
explicit TypeChecker(ModuleResolver* resolver, NotNull<BuiltinTypes> builtinTypes, InternalErrorReporter* iceHandler);
TypeChecker(const TypeChecker&) = delete;
TypeChecker& operator=(const TypeChecker&) = delete;
@ -163,7 +163,7 @@ struct TypeChecker
// Reports an error if the type is already some kind of non-table.
void tablify(TypeId type);
/** In nonstrict mode, many typevars need to be replaced by any.
/** In nonstrict mode, many types need to be replaced by any.
*/
TypeId anyIfNonstrict(TypeId ty) const;
@ -287,14 +287,14 @@ private:
TypeId unionOfTypes(TypeId a, TypeId b, const ScopePtr& scope, const Location& location, bool unifyFreeTypes = true);
// ex
// TypeId id = addType(FreeTypeVar());
// TypeId id = addType(FreeType());
template<typename T>
TypeId addType(const T& tv)
{
return addTV(TypeVar(tv));
return addTV(Type(tv));
}
TypeId addTV(TypeVar&& tv);
TypeId addTV(Type&& tv);
TypePackId addTypePack(TypePackVar&& tp);
TypePackId addTypePack(TypePack&& tp);
@ -343,7 +343,7 @@ public:
* Calling this function means submitting evidence that the pack must have the length provided.
* If the pack is known not to have the correct length, an error will be reported.
* The return vector is always of the exact requested length. In the event that the pack's length does
* not match up, excess TypeIds will be ErrorTypeVars.
* not match up, excess TypeIds will be ErrorTypes.
*/
std::vector<TypeId> unTypePack(const ScopePtr& scope, TypePackId pack, size_t expectedLength, const Location& location);
@ -356,7 +356,7 @@ public:
ModuleName currentModuleName;
std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope;
NotNull<SingletonTypes> singletonTypes;
NotNull<BuiltinTypes> builtinTypes;
InternalErrorReporter* iceHandler;
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
#pragma once
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "Luau/Unifiable.h"
#include "Luau/Variant.h"
@ -45,7 +45,7 @@ struct VariadicTypePack
};
/**
* Analogous to a BlockedTypeVar.
* Analogous to a BlockedType.
*/
struct BlockedTypePack
{
@ -83,7 +83,7 @@ struct TypePackVar
/* Walk the set of TypeIds in a TypePack.
*
* Like TypeVars, individual TypePacks can be free, generic, or any.
* Like Types, individual TypePacks can be free, generic, or any.
*
* We afford the ability to work with these kinds of packs by giving the
* iterator a .tail() property that yields the tail-most TypePack in the

View file

@ -3,7 +3,7 @@
#include "Luau/Error.h"
#include "Luau/Location.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "Luau/TypePack.h"
#include <memory>
@ -18,16 +18,16 @@ struct TypeArena;
using ScopePtr = std::shared_ptr<struct Scope>;
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(
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.
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.
// 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
@ -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
* reduces to T, but nil itself does not reduce.
* @param singletonTypes the singleton types to use
* @param builtinTypes the singleton types to use
* @param arena the type arena to allocate the new type in, if necessary
* @param ty the type to remove nil from
* @returns a type with nil removed, or nil itself if that were the only option.
*/
TypeId stripNil(NotNull<SingletonTypes> singletonTypes, TypeArena& arena, TypeId ty);
TypeId stripNil(NotNull<BuiltinTypes> builtinTypes, TypeArena& arena, TypeId ty);
} // namespace Luau

View file

@ -11,7 +11,7 @@ namespace Luau
struct Scope;
/**
* The 'level' of a TypeVar is an indirect way to talk about the scope that it 'belongs' too.
* The 'level' of a Type is an indirect way to talk about the scope that it 'belongs' too.
* To start, read http://okmij.org/ftp/ML/generalization.html
*
* We extend the idea by adding a "sub-level" which helps us to differentiate sibling scopes
@ -132,7 +132,7 @@ private:
struct Error
{
// This constructor has to be public, since it's used in TypeVar and TypePack,
// This constructor has to be public, since it's used in Type and TypePack,
// but shouldn't be called directly. Please use errorRecoveryType() instead.
Error();

View file

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

View file

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

View file

@ -6,7 +6,7 @@
#include "Luau/DenseHash.h"
#include "Luau/RecursionCounter.h"
#include "Luau/TypePack.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
LUAU_FASTINT(LuauVisitRecursionLimit)
LUAU_FASTFLAG(LuauCompleteVisitor);
@ -19,7 +19,7 @@ namespace visit_detail
/**
* Apply f(tid, t, seen) if doing so would pass type checking, else apply f(tid, t)
*
* We do this to permit (but not require) TypeVar visitors to accept the seen set as an argument.
* We do this to permit (but not require) Type visitors to accept the seen set as an argument.
*/
template<typename F, typename A, typename B, typename 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)
{
// When DenseHashSet is used for 'visitTypeVarOnce', where don't forget visited elements
// When DenseHashSet is used for 'visitTypeOnce', where don't forget visited elements
}
} // namespace visit_detail
template<typename S>
struct GenericTypeVarVisitor
struct GenericTypeVisitor
{
using Set = S;
@ -72,9 +72,9 @@ struct GenericTypeVarVisitor
bool skipBoundTypes = false;
int recursionCounter = 0;
GenericTypeVarVisitor() = default;
GenericTypeVisitor() = default;
explicit GenericTypeVarVisitor(Set seen, bool skipBoundTypes = false)
explicit GenericTypeVisitor(Set seen, bool skipBoundTypes = false)
: seen(std::move(seen))
, skipBoundTypes(skipBoundTypes)
{
@ -87,75 +87,75 @@ struct GenericTypeVarVisitor
{
return true;
}
virtual bool visit(TypeId ty, const BoundTypeVar& btv)
virtual bool visit(TypeId ty, const BoundType& btv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const FreeTypeVar& ftv)
virtual bool visit(TypeId ty, const FreeType& ftv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const GenericTypeVar& gtv)
virtual bool visit(TypeId ty, const GenericType& gtv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const ErrorTypeVar& etv)
virtual bool visit(TypeId ty, const ErrorType& etv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const PrimitiveTypeVar& ptv)
virtual bool visit(TypeId ty, const PrimitiveType& ptv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const FunctionTypeVar& ftv)
virtual bool visit(TypeId ty, const FunctionType& ftv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const TableTypeVar& ttv)
virtual bool visit(TypeId ty, const TableType& ttv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const MetatableTypeVar& mtv)
virtual bool visit(TypeId ty, const MetatableType& mtv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const ClassTypeVar& ctv)
virtual bool visit(TypeId ty, const ClassType& ctv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const AnyTypeVar& atv)
virtual bool visit(TypeId ty, const AnyType& atv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const UnknownTypeVar& utv)
virtual bool visit(TypeId ty, const UnknownType& utv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const NeverTypeVar& ntv)
virtual bool visit(TypeId ty, const NeverType& ntv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const UnionTypeVar& utv)
virtual bool visit(TypeId ty, const UnionType& utv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const IntersectionTypeVar& itv)
virtual bool visit(TypeId ty, const IntersectionType& itv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const BlockedTypeVar& btv)
virtual bool visit(TypeId ty, const BlockedType& btv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const PendingExpansionTypeVar& petv)
virtual bool visit(TypeId ty, const PendingExpansionType& petv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const SingletonTypeVar& stv)
virtual bool visit(TypeId ty, const SingletonType& stv)
{
return visit(ty);
}
virtual bool visit(TypeId ty, const NegationTypeVar& ntv)
virtual bool visit(TypeId ty, const NegationType& ntv)
{
return visit(ty);
}
@ -203,22 +203,22 @@ struct GenericTypeVarVisitor
return;
}
if (auto btv = get<BoundTypeVar>(ty))
if (auto btv = get<BoundType>(ty))
{
if (skipBoundTypes)
traverse(btv->boundTo);
else if (visit(ty, *btv))
traverse(btv->boundTo);
}
else if (auto ftv = get<FreeTypeVar>(ty))
else if (auto ftv = get<FreeType>(ty))
visit(ty, *ftv);
else if (auto gtv = get<GenericTypeVar>(ty))
else if (auto gtv = get<GenericType>(ty))
visit(ty, *gtv);
else if (auto etv = get<ErrorTypeVar>(ty))
else if (auto etv = get<ErrorType>(ty))
visit(ty, *etv);
else if (auto ptv = get<PrimitiveTypeVar>(ty))
else if (auto ptv = get<PrimitiveType>(ty))
visit(ty, *ptv);
else if (auto ftv = get<FunctionTypeVar>(ty))
else if (auto ftv = get<FunctionType>(ty))
{
if (visit(ty, *ftv))
{
@ -226,7 +226,7 @@ struct GenericTypeVarVisitor
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
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))
{
@ -260,7 +260,7 @@ struct GenericTypeVarVisitor
traverse(mtv->metatable);
}
}
else if (auto ctv = get<ClassTypeVar>(ty))
else if (auto ctv = get<ClassType>(ty))
{
if (visit(ty, *ctv))
{
@ -274,9 +274,9 @@ struct GenericTypeVarVisitor
traverse(*ctv->metatable);
}
}
else if (auto atv = get<AnyTypeVar>(ty))
else if (auto atv = get<AnyType>(ty))
visit(ty, *atv);
else if (auto utv = get<UnionTypeVar>(ty))
else if (auto utv = get<UnionType>(ty))
{
if (visit(ty, *utv))
{
@ -284,7 +284,7 @@ struct GenericTypeVarVisitor
traverse(optTy);
}
}
else if (auto itv = get<IntersectionTypeVar>(ty))
else if (auto itv = get<IntersectionType>(ty))
{
if (visit(ty, *itv))
{
@ -292,21 +292,21 @@ struct GenericTypeVarVisitor
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.
// Asserting also makes no sense, because the type _will_ happen here, most likely as a property of some ClassTypeVar
// Visiting into LazyType may necessarily cause infinite expansion, so we don't do that on purpose.
// Asserting also makes no sense, because the type _will_ happen here, most likely as a property of some ClassType
// that doesn't need to be expanded.
}
else if (auto stv = get<SingletonTypeVar>(ty))
else if (auto stv = get<SingletonType>(ty))
visit(ty, *stv);
else if (auto btv = get<BlockedTypeVar>(ty))
else if (auto btv = get<BlockedType>(ty))
visit(ty, *btv);
else if (auto utv = get<UnknownTypeVar>(ty))
else if (auto utv = get<UnknownType>(ty))
visit(ty, *utv);
else if (auto ntv = get<NeverTypeVar>(ty))
else if (auto ntv = get<NeverType>(ty))
visit(ty, *ntv);
else if (auto petv = get<PendingExpansionTypeVar>(ty))
else if (auto petv = get<PendingExpansionType>(ty))
{
if (visit(ty, *petv))
{
@ -317,12 +317,12 @@ struct GenericTypeVarVisitor
traverse(a);
}
}
else if (auto ntv = get<NegationTypeVar>(ty))
else if (auto ntv = get<NegationType>(ty))
visit(ty, *ntv);
else if (!FFlag::LuauCompleteVisitor)
return visit_detail::unsee(seen, ty);
else
LUAU_ASSERT(!"GenericTypeVarVisitor::traverse(TypeId) is not exhaustive!");
LUAU_ASSERT(!"GenericTypeVisitor::traverse(TypeId) is not exhaustive!");
visit_detail::unsee(seen, ty);
}
@ -372,7 +372,7 @@ struct GenericTypeVarVisitor
visit(tp, *btp);
else
LUAU_ASSERT(!"GenericTypeVarVisitor::traverse(TypePackId) is not exhaustive!");
LUAU_ASSERT(!"GenericTypeVisitor::traverse(TypePackId) is not exhaustive!");
visit_detail::unsee(seen, tp);
}
@ -381,21 +381,21 @@ struct GenericTypeVarVisitor
/** Visit each type under a given type. Skips over cycles and keeps recursion depth under control.
*
* The same type may be visited multiple times if there are multiple distinct paths to it. If this is undesirable, use
* TypeVarOnceVisitor.
* TypeOnceVisitor.
*/
struct TypeVarVisitor : GenericTypeVarVisitor<std::unordered_set<void*>>
struct TypeVisitor : GenericTypeVisitor<std::unordered_set<void*>>
{
explicit TypeVarVisitor(bool skipBoundTypes = false)
: GenericTypeVarVisitor{{}, skipBoundTypes}
explicit TypeVisitor(bool skipBoundTypes = false)
: GenericTypeVisitor{{}, skipBoundTypes}
{
}
};
/// Visit each type under a given type. Each type will only be checked once even if there are multiple paths to it.
struct TypeVarOnceVisitor : GenericTypeVarVisitor<DenseHashSet<void*>>
struct TypeOnceVisitor : GenericTypeVisitor<DenseHashSet<void*>>
{
explicit TypeVarOnceVisitor(bool skipBoundTypes = false)
: GenericTypeVarVisitor{DenseHashSet<void*>{nullptr}, skipBoundTypes}
explicit TypeOnceVisitor(bool skipBoundTypes = false)
: GenericTypeVisitor{DenseHashSet<void*>{nullptr}, skipBoundTypes}
{
}
};

View file

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

View file

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

View file

@ -4,7 +4,7 @@
#include "Luau/Module.h"
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "Luau/ToString.h"
#include "Luau/Common.h"
@ -447,7 +447,7 @@ static std::optional<DocumentationSymbol> checkOverloadedDocumentationSymbol(
return std::nullopt;
// This might be an overloaded function.
if (get<IntersectionTypeVar>(follow(ty)))
if (get<IntersectionType>(follow(ty)))
{
TypeId matchingOverload = nullptr;
if (parentExpr && parentExpr->is<AstExprCall>())
@ -487,12 +487,12 @@ std::optional<DocumentationSymbol> getDocumentationSymbolAtPosition(const Source
if (auto it = module.astTypes.find(indexName->expr))
{
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())
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())
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;
}
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))
{
@ -61,12 +61,12 @@ static ParenthesesRecommendation getParenRecommendationForFunc(const FunctionTyp
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;
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));
}
@ -85,11 +85,11 @@ static ParenthesesRecommendation getParenRecommendation(TypeId id, const std::ve
return ParenthesesRecommendation::None;
id = Luau::follow(id);
if (auto func = get<FunctionTypeVar>(id))
if (auto func = get<FunctionType>(id))
{
return getParenRecommendationForFunc(func, nodes);
}
else if (auto intersect = get<IntersectionTypeVar>(id))
else if (auto intersect = get<IntersectionType>(id))
{
return getParenRecommendationForIntersect(intersect, nodes);
}
@ -113,7 +113,7 @@ static std::optional<TypeId> findExpectedTypeAt(const Module& module, AstNode* n
if (!it)
return std::nullopt;
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(*it));
const FunctionType* ftv = get<FunctionType>(follow(*it));
if (!ftv)
return std::nullopt;
@ -135,18 +135,18 @@ static std::optional<TypeId> findExpectedTypeAt(const Module& module, AstNode* n
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;
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);
return unifier.canUnify(subTy, superTy).empty();
}
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);
@ -159,31 +159,31 @@ static TypeCorrectKind checkTypeCorrectKind(
TypeId expectedType = follow(*typeAtPosition);
auto checkFunctionType = [typeArena, singletonTypes, moduleScope, &expectedType](const FunctionTypeVar* ftv) {
auto checkFunctionType = [typeArena, builtinTypes, moduleScope, &expectedType](const FunctionType* ftv) {
if (std::optional<TypeId> firstRetTy = first(ftv->retTypes))
return checkTypeMatch(*firstRetTy, expectedType, moduleScope, typeArena, singletonTypes);
return checkTypeMatch(*firstRetTy, expectedType, moduleScope, typeArena, builtinTypes);
return false;
};
// We also want to suggest functions that return compatible result
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty); ftv && checkFunctionType(ftv))
if (const FunctionType* ftv = get<FunctionType>(ty); ftv && checkFunctionType(ftv))
{
return TypeCorrectKind::CorrectFunctionResult;
}
else if (const IntersectionTypeVar* itv = get<IntersectionTypeVar>(ty))
else if (const IntersectionType* itv = get<IntersectionType>(ty))
{
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 checkTypeMatch(ty, expectedType, NotNull{module.getModuleScope().get()}, typeArena, singletonTypes) ? TypeCorrectKind::Correct
: TypeCorrectKind::None;
return checkTypeMatch(ty, expectedType, NotNull{module.getModuleScope().get()}, typeArena, builtinTypes) ? TypeCorrectKind::Correct
: TypeCorrectKind::None;
}
enum class PropIndexType
@ -193,9 +193,9 @@ enum class PropIndexType
Key,
};
static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNull<SingletonTypes> 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,
std::optional<const ClassTypeVar*> containingClass = std::nullopt)
std::optional<const ClassType*> containingClass = std::nullopt)
{
rootTy = follow(rootTy);
ty = follow(ty);
@ -204,41 +204,41 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
return;
seen.insert(ty);
auto isWrongIndexer = [typeArena, singletonTypes, &module, rootTy, indexType](Luau::TypeId type) {
auto isWrongIndexer = [typeArena, builtinTypes, &module, rootTy, indexType](Luau::TypeId type) {
if (indexType == PropIndexType::Key)
return false;
bool calledWithSelf = indexType == PropIndexType::Colon;
auto isCompatibleCall = [typeArena, singletonTypes, &module, rootTy, calledWithSelf](const FunctionTypeVar* ftv) {
auto isCompatibleCall = [typeArena, builtinTypes, &module, rootTy, calledWithSelf](const FunctionType* ftv) {
// Strong match with definition is a success
if (calledWithSelf == ftv->hasSelf)
return true;
// Calls on classes require strict match between how function is declared and how it's called
if (get<ClassTypeVar>(rootTy))
if (get<ClassType>(rootTy))
return false;
// When called with ':', but declared without 'self', it is invalid if a function has incompatible first argument or no arguments at all
// When called with '.', but declared with 'self', it is considered invalid if first argument is compatible
if (std::optional<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;
};
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(type))
if (const FunctionType* ftv = get<FunctionType>(type))
return !isCompatibleCall(ftv);
// 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)
{
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(Luau::follow(subType)))
if (const FunctionType* ftv = get<FunctionType>(Luau::follow(subType)))
{
if (isCompatibleCall(ftv))
return false;
@ -249,7 +249,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
return calledWithSelf;
};
auto fillProps = [&](const ClassTypeVar::Props& props) {
auto fillProps = [&](const ClassType::Props& props) {
for (const auto& [name, prop] : props)
{
// We are walking up the class hierarchy, so if we encounter a property that we have
@ -259,7 +259,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
Luau::TypeId type = Luau::follow(prop.type);
TypeCorrectKind typeCorrect = indexType == PropIndexType::Key
? TypeCorrectKind::Correct
: checkTypeCorrectKind(module, typeArena, singletonTypes, nodes.back(), {{}, {}}, type);
: checkTypeCorrectKind(module, typeArena, builtinTypes, nodes.back(), {{}, {}}, type);
ParenthesesRecommendation parens =
indexType == PropIndexType::Key ? ParenthesesRecommendation::None : getParenRecommendation(type, nodes, typeCorrect);
@ -279,41 +279,41 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
}
};
auto fillMetatableProps = [&](const TableTypeVar* mtable) {
auto fillMetatableProps = [&](const TableType* mtable) {
auto indexIt = mtable->props.find("__index");
if (indexIt != mtable->props.end())
{
TypeId followed = follow(indexIt->second.type);
if (get<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);
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);
fillProps(cls->props);
if (cls->parent)
autocompleteProps(module, typeArena, singletonTypes, rootTy, *cls->parent, indexType, nodes, result, seen, containingClass);
autocompleteProps(module, typeArena, builtinTypes, rootTy, *cls->parent, indexType, nodes, result, seen, containingClass);
}
else if (auto tbl = get<TableTypeVar>(ty))
else if (auto tbl = get<TableType>(ty))
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);
}
else if (auto i = get<IntersectionTypeVar>(ty))
else if (auto i = get<IntersectionType>(ty))
{
// Complete all properties in every variant
for (TypeId ty : i->parts)
@ -321,13 +321,13 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
AutocompleteEntryMap inner;
std::unordered_set<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)
result.insert(pair);
}
}
else if (auto u = get<UnionTypeVar>(ty))
else if (auto u = get<UnionType>(ty))
{
// Complete all properties common to all variants
auto iter = begin(u);
@ -344,7 +344,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
if (iter == endIter)
return;
autocompleteProps(module, typeArena, singletonTypes, rootTy, *iter, indexType, nodes, result, seen);
autocompleteProps(module, typeArena, builtinTypes, rootTy, *iter, indexType, nodes, result, seen);
++iter;
@ -359,7 +359,7 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
continue;
}
autocompleteProps(module, typeArena, singletonTypes, rootTy, *iter, indexType, nodes, inner, innerSeen);
autocompleteProps(module, typeArena, builtinTypes, rootTy, *iter, indexType, nodes, inner, innerSeen);
std::unordered_set<std::string> toRemove;
@ -376,17 +376,17 @@ static void autocompleteProps(const Module& module, TypeArena* typeArena, NotNul
++iter;
}
}
else if (auto pt = get<PrimitiveTypeVar>(ty))
else if (auto pt = get<PrimitiveType>(ty))
{
if (pt->metatable)
{
if (auto mtable = get<TableTypeVar>(*pt->metatable))
if (auto mtable = get<TableType>(*pt->metatable))
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)
{
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)
{
AutocompleteEntryMap result;
autocompleteProps(module, typeArena, singletonTypes, ty, indexType, nodes, result);
autocompleteProps(module, typeArena, builtinTypes, ty, indexType, nodes, result);
return result;
}
@ -455,15 +455,15 @@ static void autocompleteStringSingleton(TypeId ty, bool addQuotes, AutocompleteE
ty = follow(ty);
if (auto ss = get<StringSingleton>(get<SingletonTypeVar>(ty)))
if (auto ss = get<StringSingleton>(get<SingletonType>(ty)))
{
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)
{
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};
}
}
@ -474,14 +474,14 @@ static bool canSuggestInferredType(ScopePtr scope, TypeId ty)
ty = follow(ty);
// No point in suggesting 'any', invalid to suggest others
if (get<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;
// No syntax for unnamed tables with a metatable
if (get<MetatableTypeVar>(ty))
if (get<MetatableType>(ty))
return false;
if (const TableTypeVar* ttv = get<TableTypeVar>(ty))
if (const TableType* ttv = get<TableType>(ty))
{
if (ttv->name)
return true;
@ -544,7 +544,7 @@ static std::optional<TypeId> findTypeElementAt(AstType* astType, TypeId ty, Posi
if (AstTypeFunction* type = astType->as<AstTypeFunction>())
{
const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty);
const FunctionType* ftv = get<FunctionType>(ty);
if (!ftv)
return {};
@ -634,7 +634,7 @@ static std::optional<TypeId> tryGetTypePackTypeAt(TypePackId tp, size_t index)
}
template<typename T>
std::optional<const T*> returnFirstNonnullOptionOfType(const UnionTypeVar* utv)
std::optional<const T*> returnFirstNonnullOptionOfType(const UnionType* utv)
{
std::optional<const T*> ret;
for (TypeId subTy : utv)
@ -667,18 +667,18 @@ static std::optional<bool> functionIsExpectedAt(const Module& module, AstNode* n
TypeId expectedType = follow(*typeAtPosition);
if (get<FunctionTypeVar>(expectedType))
if (get<FunctionType>(expectedType))
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 get<FunctionTypeVar>(Luau::follow(ty)) != nullptr;
return get<FunctionType>(Luau::follow(ty)) != nullptr;
});
}
if (const UnionTypeVar* utv = get<UnionTypeVar>(expectedType))
return returnFirstNonnullOptionOfType<FunctionTypeVar>(utv).has_value();
if (const UnionType* utv = get<UnionType>(expectedType))
return returnFirstNonnullOptionOfType<FunctionType>(utv).has_value();
return false;
}
@ -766,7 +766,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
{
if (auto it = module.astTypes.find(exprCall->func))
{
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(*it)))
if (const FunctionType* ftv = get<FunctionType>(follow(*it)))
{
if (auto ty = tryGetTypePackTypeAt(ftv->retTypes, tailPos))
inferredType = *ty;
@ -792,7 +792,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
else if (AstExprFunction* node = parent->as<AstExprFunction>())
{
// For lookup inside expected function type if that's available
auto tryGetExpectedFunctionType = [](const Module& module, AstExpr* expr) -> const FunctionTypeVar* {
auto tryGetExpectedFunctionType = [](const Module& module, AstExpr* expr) -> const FunctionType* {
auto it = module.astExpectedTypes.find(expr);
if (!it)
@ -800,13 +800,13 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
TypeId ty = follow(*it);
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty))
if (const FunctionType* ftv = get<FunctionType>(ty))
return ftv;
// 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;
@ -819,7 +819,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
if (arg->annotation && arg->annotation->location.containsClosed(position))
{
if (const FunctionTypeVar* ftv = tryGetExpectedFunctionType(module, node))
if (const FunctionType* ftv = tryGetExpectedFunctionType(module, node))
{
if (auto ty = tryGetTypePackTypeAt(ftv->argTypes, i))
tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position);
@ -840,7 +840,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
{
if (variadic->location.containsClosed(position))
{
if (const FunctionTypeVar* ftv = tryGetExpectedFunctionType(module, node))
if (const FunctionType* ftv = tryGetExpectedFunctionType(module, node))
{
if (auto ty = tryGetTypePackTypeAt(ftv->argTypes, ~0u))
tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position);
@ -858,7 +858,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
if (ret->location.containsClosed(position))
{
if (const FunctionTypeVar* ftv = tryGetExpectedFunctionType(module, node))
if (const FunctionType* ftv = tryGetExpectedFunctionType(module, node))
{
if (auto ty = tryGetTypePackTypeAt(ftv->retTypes, i))
tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position);
@ -875,7 +875,7 @@ AutocompleteEntryMap autocompleteTypeNames(const Module& module, Position positi
{
if (variadic->location.containsClosed(position))
{
if (const FunctionTypeVar* ftv = tryGetExpectedFunctionType(module, node))
if (const FunctionType* ftv = tryGetExpectedFunctionType(module, node))
{
if (auto ty = tryGetTypePackTypeAt(ftv->retTypes, ~0u))
tryAddTypeCorrectSuggestion(result, startScope, topType, *ty, position);
@ -1127,7 +1127,7 @@ static bool autocompleteIfElseExpression(
}
}
static AutocompleteContext autocompleteExpression(const SourceModule& sourceModule, const Module& module, NotNull<SingletonTypes> singletonTypes,
static AutocompleteContext autocompleteExpression(const SourceModule& sourceModule, const Module& module, NotNull<BuiltinTypes> builtinTypes,
TypeArena* typeArena, const std::vector<AstNode*>& ancestry, Position position, AutocompleteEntryMap& result)
{
LUAU_ASSERT(!ancestry.empty());
@ -1137,7 +1137,7 @@ static AutocompleteContext autocompleteExpression(const SourceModule& sourceModu
if (node->is<AstExprIndexName>())
{
if (auto it = module.astTypes.find(node->asExpr()))
autocompleteProps(module, typeArena, singletonTypes, *it, PropIndexType::Point, ancestry, result);
autocompleteProps(module, typeArena, builtinTypes, *it, PropIndexType::Point, ancestry, result);
}
else if (autocompleteIfElseExpression(node, ancestry, position, result))
return AutocompleteContext::Keyword;
@ -1161,7 +1161,7 @@ static AutocompleteContext autocompleteExpression(const SourceModule& sourceModu
std::string n = toString(name);
if (!result.count(n))
{
TypeCorrectKind typeCorrect = checkTypeCorrectKind(module, typeArena, singletonTypes, node, position, binding.typeId);
TypeCorrectKind typeCorrect = checkTypeCorrectKind(module, typeArena, builtinTypes, node, position, binding.typeId);
result[n] = {AutocompleteEntryKind::Binding, binding.typeId, binding.deprecated, false, typeCorrect, std::nullopt, std::nullopt,
binding.documentationSymbol, {}, getParenRecommendation(binding.typeId, ancestry, typeCorrect)};
@ -1171,16 +1171,16 @@ static AutocompleteContext autocompleteExpression(const SourceModule& sourceModu
scope = scope->parent;
}
TypeCorrectKind correctForNil = checkTypeCorrectKind(module, typeArena, singletonTypes, node, position, singletonTypes->nilType);
TypeCorrectKind correctForTrue = checkTypeCorrectKind(module, typeArena, singletonTypes, node, position, singletonTypes->trueType);
TypeCorrectKind correctForFalse = checkTypeCorrectKind(module, typeArena, singletonTypes, node, position, singletonTypes->falseType);
TypeCorrectKind correctForNil = checkTypeCorrectKind(module, typeArena, builtinTypes, node, position, builtinTypes->nilType);
TypeCorrectKind correctForTrue = checkTypeCorrectKind(module, typeArena, builtinTypes, node, position, builtinTypes->trueType);
TypeCorrectKind correctForFalse = checkTypeCorrectKind(module, typeArena, builtinTypes, node, position, builtinTypes->falseType);
TypeCorrectKind correctForFunction =
functionIsExpectedAt(module, node, position).value_or(false) ? TypeCorrectKind::Correct : TypeCorrectKind::None;
result["if"] = {AutocompleteEntryKind::Keyword, std::nullopt, false, false};
result["true"] = {AutocompleteEntryKind::Keyword, singletonTypes->booleanType, false, false, correctForTrue};
result["false"] = {AutocompleteEntryKind::Keyword, singletonTypes->booleanType, false, false, correctForFalse};
result["nil"] = {AutocompleteEntryKind::Keyword, singletonTypes->nilType, false, false, correctForNil};
result["true"] = {AutocompleteEntryKind::Keyword, builtinTypes->booleanType, false, false, correctForTrue};
result["false"] = {AutocompleteEntryKind::Keyword, builtinTypes->booleanType, false, false, correctForFalse};
result["nil"] = {AutocompleteEntryKind::Keyword, builtinTypes->nilType, false, false, correctForNil};
result["not"] = {AutocompleteEntryKind::Keyword};
result["function"] = {AutocompleteEntryKind::Keyword, std::nullopt, false, false, correctForFunction};
@ -1191,15 +1191,15 @@ static AutocompleteContext autocompleteExpression(const SourceModule& sourceModu
return AutocompleteContext::Expression;
}
static AutocompleteResult autocompleteExpression(const SourceModule& sourceModule, const Module& module, NotNull<SingletonTypes> singletonTypes,
static AutocompleteResult autocompleteExpression(const SourceModule& sourceModule, const Module& module, NotNull<BuiltinTypes> builtinTypes,
TypeArena* typeArena, const std::vector<AstNode*>& ancestry, Position position)
{
AutocompleteEntryMap result;
AutocompleteContext context = autocompleteExpression(sourceModule, module, singletonTypes, typeArena, ancestry, position, result);
AutocompleteContext context = autocompleteExpression(sourceModule, module, builtinTypes, typeArena, ancestry, position, result);
return {result, ancestry, context};
}
static std::optional<const ClassTypeVar*> getMethodContainingClass(const ModulePtr& module, AstExpr* funcExpr)
static std::optional<const ClassType*> getMethodContainingClass(const ModulePtr& module, AstExpr* funcExpr)
{
AstExpr* parentExpr = nullptr;
if (auto indexName = funcExpr->as<AstExprIndexName>())
@ -1223,14 +1223,14 @@ static std::optional<const ClassTypeVar*> getMethodContainingClass(const ModuleP
Luau::TypeId parentType = Luau::follow(*parentIt);
if (auto parentClass = Luau::get<ClassTypeVar>(parentType))
if (auto parentClass = Luau::get<ClassType>(parentType))
{
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;
@ -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,
// so we encode that here rather than putting a useless member on the FunctionTypeVar struct.
// so we encode that here rather than putting a useless member on the FunctionType struct.
if (candidate->args.size > 1 && !candidate->args.data[0]->location.contains(position))
{
return std::nullopt;
@ -1293,7 +1293,7 @@ static std::optional<AutocompleteEntryMap> autocompleteStringParams(const Source
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)
{
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);
if (auto functionType = Luau::get<FunctionTypeVar>(followedId))
if (auto functionType = Luau::get<FunctionType>(followedId))
{
return performCallback(functionType);
}
if (auto intersect = Luau::get<IntersectionTypeVar>(followedId))
if (auto intersect = Luau::get<IntersectionType>(followedId))
{
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))
{
@ -1327,7 +1327,7 @@ static std::optional<AutocompleteEntryMap> autocompleteStringParams(const Source
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)
{
if (isWithinComment(sourceModule, position))
@ -1360,7 +1360,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
TypeId ty = follow(*it);
PropIndexType indexType = indexName->op == ':' ? PropIndexType::Colon : PropIndexType::Point;
return {autocompleteProps(*module, &typeArena, singletonTypes, ty, indexType, ancestry), ancestry, AutocompleteContext::Property};
return {autocompleteProps(*module, &typeArena, builtinTypes, ty, indexType, ancestry), ancestry, AutocompleteContext::Property};
}
else if (auto typeReference = node->as<AstTypeReference>())
{
@ -1378,7 +1378,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
if (statLocal->vars.size == 1 && (!statLocal->equalsSignLocation || position < statLocal->equalsSignLocation->begin))
return {{{"function", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Unknown};
else if (statLocal->equalsSignLocation && position >= statLocal->equalsSignLocation->end)
return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position);
return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
else
return {};
}
@ -1392,7 +1392,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
if (statFor->from->location.containsClosed(position) || statFor->to->location.containsClosed(position) ||
(statFor->step && statFor->step->location.containsClosed(position)))
return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position);
return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
return {};
}
@ -1422,7 +1422,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
AstExpr* lastExpr = statForIn->values.data[statForIn->values.size - 1];
if (lastExpr->location.containsClosed(position))
return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position);
return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
if (position > lastExpr->location.end)
return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
@ -1446,7 +1446,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
return {{{"do", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
if (!statWhile->hasDo || position < statWhile->doLocation.begin)
return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position);
return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
if (statWhile->hasDo && position > statWhile->doLocation.end)
return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement};
@ -1463,7 +1463,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
else if (AstStatIf* statIf = parent->as<AstStatIf>(); statIf && node->is<AstStatBlock>())
{
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))
return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
}
@ -1471,7 +1471,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
statIf && (!statIf->thenLocation || statIf->thenLocation->containsClosed(position)))
return {{{"then", AutocompleteEntry{AutocompleteEntryKind::Keyword}}}, ancestry, AutocompleteContext::Keyword};
else if (AstStatRepeat* statRepeat = node->as<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)
return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement};
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))
{
auto result = autocompleteProps(*module, &typeArena, singletonTypes, *it, PropIndexType::Key, ancestry);
auto result = autocompleteProps(*module, &typeArena, builtinTypes, *it, PropIndexType::Key, ancestry);
if (FFlag::LuauCompleteTableKeysBetter)
{
@ -1499,7 +1499,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
//
// If the key type is a union of singleton strings,
// suggest those too.
if (auto ttv = get<TableTypeVar>(follow(*it)); ttv && ttv->indexer)
if (auto ttv = get<TableType>(follow(*it)); ttv && ttv->indexer)
{
autocompleteStringSingleton(ttv->indexer->indexType, false, result);
}
@ -1518,7 +1518,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
// If we know for sure that a key is being written, do not offer general expression suggestions
if (!key)
autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position, result);
autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position, result);
return {result, ancestry, AutocompleteContext::Property};
}
@ -1546,7 +1546,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
if (auto idxExpr = ancestry.at(ancestry.size() - 2)->as<AstExprIndexExpr>())
{
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>())
{
@ -1572,7 +1572,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M
return {};
if (node->asExpr())
return autocompleteExpression(sourceModule, *module, singletonTypes, &typeArena, ancestry, position);
return autocompleteExpression(sourceModule, *module, builtinTypes, &typeArena, ancestry, position);
else if (node->asStat())
return {autocompleteStatement(sourceModule, *module, ancestry, position), ancestry, AutocompleteContext::Statement};
@ -1596,10 +1596,10 @@ AutocompleteResult autocomplete(Frontend& frontend, const ModuleName& moduleName
if (!module)
return {};
NotNull<SingletonTypes> singletonTypes = frontend.singletonTypes;
NotNull<BuiltinTypes> builtinTypes = frontend.builtinTypes;
Scope* globalScope = frontend.typeCheckerForAutocomplete.globalScope.get();
AutocompleteResult autocompleteResult = autocomplete(*sourceModule, module, singletonTypes, globalScope, position, callback);
AutocompleteResult autocompleteResult = autocomplete(*sourceModule, module, builtinTypes, globalScope, position, callback);
return autocompleteResult;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -65,14 +65,14 @@ static void generateDocumentationSymbols(TypeId ty, const std::string& rootName)
asMutable(ty)->documentationSymbol = rootName;
if (TableTypeVar* ttv = getMutable<TableTypeVar>(ty))
if (TableType* ttv = getMutable<TableType>(ty))
{
for (auto& [name, prop] : ttv->props)
{
prop.documentationSymbol = rootName + "." + name;
}
}
else if (ClassTypeVar* ctv = getMutable<ClassTypeVar>(ty))
else if (ClassType* ctv = getMutable<ClassType>(ty))
{
for (auto& [name, prop] : ctv->props)
{
@ -408,12 +408,12 @@ double getTimestamp()
} // namespace
Frontend::Frontend(FileResolver* fileResolver, ConfigResolver* configResolver, const FrontendOptions& options)
: singletonTypes(NotNull{&singletonTypes_})
: builtinTypes(NotNull{&builtinTypes_})
, fileResolver(fileResolver)
, moduleResolver(this)
, moduleResolverForAutocomplete(this)
, typeChecker(&moduleResolver, singletonTypes, &iceHandler)
, typeCheckerForAutocomplete(&moduleResolverForAutocomplete, singletonTypes, &iceHandler)
, typeChecker(&moduleResolver, builtinTypes, &iceHandler)
, typeCheckerForAutocomplete(&moduleResolverForAutocomplete, builtinTypes, &iceHandler)
, configResolver(configResolver)
, options(options)
, globalScope(typeChecker.globalScope)
@ -455,12 +455,7 @@ CheckResult Frontend::check(const ModuleName& name, std::optional<FrontendOption
}
std::vector<ModuleName> buildQueue;
bool cycleDetected = parseGraph(buildQueue, checkResult, 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;
bool cycleDetected = parseGraph(buildQueue, name, frontendOptions.forAutocomplete);
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
typeCheckerForAutocomplete.requireCycles = requireCycles;
double autocompleteTimeLimit = FInt::LuauAutocompleteCheckTimeoutMs / 1000.0;
if (autocompleteTimeLimit != 0.0)
typeCheckerForAutocomplete.finishTime = TimeTrace::getClock() + autocompleteTimeLimit;
else
@ -599,7 +596,7 @@ CheckResult Frontend::check(const ModuleName& name, std::optional<FrontendOption
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_ARGUMENT("root", root.c_str());
@ -618,7 +615,7 @@ bool Frontend::parseGraph(std::vector<ModuleName>& buildQueue, CheckResult& chec
bool cyclic = false;
{
auto [sourceNode, _] = getSourceNode(checkResult, root);
auto [sourceNode, _] = getSourceNode(root);
if (sourceNode)
stack.push_back(sourceNode);
}
@ -682,7 +679,7 @@ bool Frontend::parseGraph(std::vector<ModuleName>& buildQueue, CheckResult& chec
}
}
auto [sourceNode, _] = getSourceNode(checkResult, dep);
auto [sourceNode, _] = getSourceNode(dep);
if (sourceNode)
{
stack.push_back(sourceNode);
@ -729,8 +726,7 @@ LintResult Frontend::lint(const ModuleName& name, std::optional<Luau::LintOption
LUAU_TIMETRACE_SCOPE("Frontend::lint", "Frontend");
LUAU_TIMETRACE_ARGUMENT("name", name.c_str());
CheckResult checkResult;
auto [_sourceNode, sourceModule] = getSourceNode(checkResult, name);
auto [_sourceNode, sourceModule] = getSourceNode(name);
if (!sourceModule)
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);
}
ScopePtr environmentScope = getModuleEnvironment(module, config);
ScopePtr environmentScope = getModuleEnvironment(module, config, /*forAutocomplete*/ false);
ModulePtr modulePtr = moduleResolver.getModule(module.name);
@ -873,14 +869,14 @@ ModulePtr Frontend::check(
const NotNull<ModuleResolver> mr{forAutocomplete ? &moduleResolverForAutocomplete : &moduleResolver};
const ScopePtr& globalScope{forAutocomplete ? typeCheckerForAutocomplete.globalScope : typeChecker.globalScope};
Normalizer normalizer{&result->internalTypes, singletonTypes, NotNull{&typeChecker.unifierState}};
Normalizer normalizer{&result->internalTypes, builtinTypes, NotNull{&typeChecker.unifierState}};
ConstraintGraphBuilder cgb{
sourceModule.name,
result,
&result->internalTypes,
mr,
singletonTypes,
builtinTypes,
NotNull(&iceHandler),
globalScope,
logger.get(),
@ -910,7 +906,12 @@ ModulePtr Frontend::check(
result->astResolvedTypePacks = std::move(cgb.astResolvedTypePacks);
result->type = sourceModule.type;
Luau::check(singletonTypes, logger.get(), sourceModule, result.get());
result->clonePublicInterface(builtinTypes, iceHandler);
freeze(result->internalTypes);
freeze(result->interfaceTypes);
Luau::check(builtinTypes, logger.get(), sourceModule, result.get());
if (FFlag::DebugLuauLogSolverToJson)
{
@ -918,13 +919,11 @@ ModulePtr Frontend::check(
printf("%s\n", output.c_str());
}
result->clonePublicInterface(singletonTypes, iceHandler);
return result;
}
// Read AST into sourceModules if necessary. Trace require()s. Report parse errors.
std::pair<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_ARGUMENT("name", name.c_str());

View file

@ -11,7 +11,7 @@ namespace Luau
bool Instantiation::isDirty(TypeId ty)
{
if (const FunctionTypeVar* ftv = log->getMutable<FunctionTypeVar>(ty))
if (const FunctionType* ftv = log->getMutable<FunctionType>(ty))
{
if (ftv->hasNoGenerics)
return false;
@ -31,9 +31,9 @@ bool Instantiation::isDirty(TypePackId tp)
bool Instantiation::ignoreChildren(TypeId ty)
{
if (log->getMutable<FunctionTypeVar>(ty))
if (log->getMutable<FunctionType>(ty))
return true;
else if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassTypeVar>(ty))
else if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassType>(ty))
return true;
else
return false;
@ -41,10 +41,10 @@ bool Instantiation::ignoreChildren(TypeId ty)
TypeId Instantiation::clean(TypeId ty)
{
const FunctionTypeVar* ftv = log->getMutable<FunctionTypeVar>(ty);
const FunctionType* ftv = log->getMutable<FunctionType>(ty);
LUAU_ASSERT(ftv);
FunctionTypeVar clone = FunctionTypeVar{level, scope, ftv->argTypes, ftv->retTypes, ftv->definition, ftv->hasSelf};
FunctionType clone = FunctionType{level, scope, ftv->argTypes, ftv->retTypes, ftv->definition, ftv->hasSelf};
clone.magicFunction = ftv->magicFunction;
clone.dcrMagicFunction = ftv->dcrMagicFunction;
clone.tags = ftv->tags;
@ -71,7 +71,7 @@ TypePackId Instantiation::clean(TypePackId tp)
bool ReplaceGenerics::ignoreChildren(TypeId ty)
{
if (const FunctionTypeVar* ftv = log->getMutable<FunctionTypeVar>(ty))
if (const FunctionType* ftv = log->getMutable<FunctionType>(ty))
{
if (ftv->hasNoGenerics)
return true;
@ -83,7 +83,7 @@ bool ReplaceGenerics::ignoreChildren(TypeId ty)
// whenever we quantify, so the vectors overlap if and only if they are equal.
return (!generics.empty() || !genericPacks.empty()) && (ftv->generics == generics) && (ftv->genericPacks == genericPacks);
}
else if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassTypeVar>(ty))
else if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassType>(ty))
return true;
else
{
@ -93,9 +93,9 @@ bool ReplaceGenerics::ignoreChildren(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;
else if (log->getMutable<GenericTypeVar>(ty))
else if (log->getMutable<GenericType>(ty))
return std::find(generics.begin(), generics.end(), ty) != generics.end();
else
return false;
@ -112,14 +112,14 @@ bool ReplaceGenerics::isDirty(TypePackId tp)
TypeId ReplaceGenerics::clean(TypeId ty)
{
LUAU_ASSERT(isDirty(ty));
if (const TableTypeVar* ttv = log->getMutable<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;
return addType(std::move(clone));
}
else
return addType(FreeTypeVar{scope, level});
return addType(FreeType{scope, level});
}
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);
}
std::ostream& operator<<(std::ostream& stream, const TypeVar& tv)
std::ostream& operator<<(std::ostream& stream, const Type& tv)
{
return stream << toString(tv);
}

View file

@ -2144,14 +2144,14 @@ private:
if (!ty)
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);
if (prop && prop->deprecated)
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);
@ -2302,16 +2302,16 @@ private:
size_t getReturnCount(TypeId ty)
{
if (auto ftv = get<FunctionTypeVar>(ty))
if (auto ftv = get<FunctionType>(ty))
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
size_t result = 0;
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));
return result;

View file

@ -9,8 +9,8 @@
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypePack.h"
#include "Luau/TypeVar.h"
#include "Luau/VisitTypeVar.h"
#include "Luau/Type.h"
#include "Luau/VisitType.h"
#include <algorithm>
@ -60,12 +60,12 @@ bool isWithinComment(const SourceModule& sourceModule, Position pos)
struct ClonePublicInterface : Substitution
{
NotNull<SingletonTypes> singletonTypes;
NotNull<BuiltinTypes> builtinTypes;
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)
, singletonTypes(singletonTypes)
, builtinTypes(builtinTypes)
, module(module)
{
LUAU_ASSERT(module);
@ -76,9 +76,9 @@ struct ClonePublicInterface : Substitution
if (ty->owningArena == &module->internalTypes)
return true;
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty))
if (const FunctionType* ftv = get<FunctionType>(ty))
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 false;
}
@ -92,9 +92,9 @@ struct ClonePublicInterface : Substitution
{
TypeId result = clone(ty);
if (FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(result))
if (FunctionType* ftv = getMutable<FunctionType>(result))
ftv->level = TypeLevel{0, 0};
else if (TableTypeVar* ttv = getMutable<TableTypeVar>(result))
else if (TableType* ttv = getMutable<TableType>(result))
ttv->level = TypeLevel{0, 0};
return result;
@ -117,7 +117,7 @@ struct ClonePublicInterface : Substitution
else
{
module->errors.push_back(TypeError{module->scopes[0].first, UnificationTooComplex{}});
return singletonTypes->errorRecoveryType();
return builtinTypes->errorRecoveryType();
}
}
@ -133,7 +133,7 @@ struct ClonePublicInterface : Substitution
else
{
module->errors.push_back(TypeError{module->scopes[0].first, UnificationTooComplex{}});
return singletonTypes->errorRecoveryTypePack();
return builtinTypes->errorRecoveryTypePack();
}
}
@ -178,9 +178,9 @@ Module::~Module()
unfreeze(internalTypes);
}
void Module::clonePublicInterface(NotNull<SingletonTypes> 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());
CloneState cloneState;
@ -192,7 +192,7 @@ void Module::clonePublicInterface(NotNull<SingletonTypes> singletonTypes, Intern
std::unordered_map<Name, TypeFun>* exportedTypeBindings = &moduleScope->exportedTypeBindings;
TxnLog log;
ClonePublicInterface clonePublicInterface{&log, singletonTypes, this};
ClonePublicInterface clonePublicInterface{&log, builtinTypes, this};
if (FFlag::LuauClonePublicInterfaceLess)
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/Substitution.h"
#include "Luau/TxnLog.h"
#include "Luau/TypeVar.h"
#include "Luau/VisitTypeVar.h"
#include "Luau/Type.h"
#include "Luau/VisitType.h"
LUAU_FASTFLAG(DebugLuauSharedSelf)
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution);
@ -15,7 +15,7 @@ LUAU_FASTFLAG(LuauClassTypeVarsInSubstitution)
namespace Luau
{
struct Quantifier final : TypeVarOnceVisitor
struct Quantifier final : TypeOnceVisitor
{
TypeLevel level;
std::vector<TypeId> generics;
@ -43,24 +43,24 @@ struct Quantifier final : TypeVarOnceVisitor
return false;
}
bool visit(TypeId ty, const FreeTypeVar& ftv) override
bool visit(TypeId ty, const FreeType& ftv) override
{
seenMutableType = true;
if (!level.subsumes(ftv.level))
return false;
*asMutable(ty) = GenericTypeVar{level};
*asMutable(ty) = GenericType{level};
generics.push_back(ty);
return false;
}
bool visit(TypeId ty, const TableTypeVar&) override
bool visit(TypeId ty, const TableType&) override
{
LUAU_ASSERT(getMutable<TableTypeVar>(ty));
TableTypeVar& ttv = *getMutable<TableTypeVar>(ty);
LUAU_ASSERT(getMutable<TableType>(ty));
TableType& ttv = *getMutable<TableType>(ty);
if (ttv.state == TableState::Generic)
seenGenericType = true;
@ -117,7 +117,7 @@ void quantify(TypeId ty, TypeLevel level)
for (const auto& [_, prop] : ttv->props)
{
auto ftv = getMutable<FunctionTypeVar>(follow(prop.type));
auto ftv = getMutable<FunctionType>(follow(prop.type));
if (!ftv || !ftv->hasSelf)
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};
q.traverse(ty);
@ -145,7 +145,7 @@ void quantify(TypeId ty, TypeLevel level)
Quantifier q{level};
q.traverse(ty);
FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(ty);
FunctionType* ftv = getMutable<FunctionType>(ty);
LUAU_ASSERT(ftv);
ftv->generics.insert(ftv->generics.end(), q.generics.begin(), q.generics.end());
ftv->genericPacks.insert(ftv->genericPacks.end(), q.genericPacks.begin(), q.genericPacks.end());
@ -168,11 +168,11 @@ struct PureQuantifier : Substitution
{
LUAU_ASSERT(ty == follow(ty));
if (auto ftv = get<FreeTypeVar>(ty))
if (auto ftv = get<FreeType>(ty))
{
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);
}
@ -192,16 +192,16 @@ struct PureQuantifier : Substitution
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);
return result;
}
else if (auto ttv = get<TableTypeVar>(ty))
else if (auto ttv = get<TableType>(ty))
{
TypeId result = arena->addType(TableTypeVar{});
TableTypeVar* resultTable = getMutable<TableTypeVar>(result);
TypeId result = arena->addType(TableType{});
TableType* resultTable = getMutable<TableType>(result);
LUAU_ASSERT(resultTable);
*resultTable = *ttv;
@ -229,7 +229,7 @@ struct PureQuantifier : Substitution
bool ignoreChildren(TypeId ty) override
{
if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassTypeVar>(ty))
if (FFlag::LuauClassTypeVarsInSubstitution && get<ClassType>(ty))
return true;
return ty->persistent;
@ -246,7 +246,7 @@ TypeId quantify(TypeArena* arena, TypeId ty, Scope* scope)
std::optional<TypeId> result = quantifier.substitute(ty);
LUAU_ASSERT(result);
FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(*result);
FunctionType* ftv = getMutable<FunctionType>(*result);
LUAU_ASSERT(ftv);
ftv->scope = scope;
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))
ty = &pty->pending;
if (const FunctionTypeVar* ftv = get<FunctionTypeVar>(ty))
if (const FunctionType* ftv = get<FunctionType>(ty))
{
if (FFlag::LuauSubstitutionFixMissingFields)
{
@ -41,7 +41,7 @@ void Tarjan::visitChildren(TypeId ty, int index)
visitChild(ftv->argTypes);
visitChild(ftv->retTypes);
}
else if (const TableTypeVar* ttv = get<TableTypeVar>(ty))
else if (const TableType* ttv = get<TableType>(ty))
{
LUAU_ASSERT(!ttv->boundTo);
for (const auto& [name, prop] : ttv->props)
@ -58,22 +58,22 @@ void Tarjan::visitChildren(TypeId ty, int index)
for (TypePackId itp : ttv->instantiatedTypePackParams)
visitChild(itp);
}
else if (const MetatableTypeVar* mtv = get<MetatableTypeVar>(ty))
else if (const MetatableType* mtv = get<MetatableType>(ty))
{
visitChild(mtv->table);
visitChild(mtv->metatable);
}
else if (const UnionTypeVar* utv = get<UnionTypeVar>(ty))
else if (const UnionType* utv = get<UnionType>(ty))
{
for (TypeId opt : utv->options)
visitChild(opt);
}
else if (const IntersectionTypeVar* itv = get<IntersectionTypeVar>(ty))
else if (const IntersectionType* itv = get<IntersectionType>(ty))
{
for (TypeId part : itv->parts)
visitChild(part);
}
else if (const PendingExpansionTypeVar* petv = get<PendingExpansionTypeVar>(ty))
else if (const PendingExpansionType* petv = get<PendingExpansionType>(ty))
{
for (TypeId a : petv->typeArguments)
visitChild(a);
@ -81,7 +81,7 @@ void Tarjan::visitChildren(TypeId ty, int index)
for (TypePackId a : petv->packArguments)
visitChild(a);
}
else if (const ClassTypeVar* ctv = get<ClassTypeVar>(ty); FFlag::LuauClassTypeVarsInSubstitution && ctv)
else if (const ClassType* ctv = get<ClassType>(ty); FFlag::LuauClassTypeVarsInSubstitution && ctv)
{
for (auto [name, prop] : ctv->props)
visitChild(prop.type);
@ -92,7 +92,7 @@ void Tarjan::visitChildren(TypeId ty, int index)
if (ctv->metatable)
visitChild(*ctv->metatable);
}
else if (const NegationTypeVar* ntv = get<NegationTypeVar>(ty))
else if (const NegationType* ntv = get<NegationType>(ty))
{
visitChild(ntv->ty);
}
@ -559,7 +559,7 @@ void Substitution::replaceChildren(TypeId ty)
if (ty->owningArena != arena)
return;
if (FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(ty))
if (FunctionType* ftv = getMutable<FunctionType>(ty))
{
if (FFlag::LuauSubstitutionFixMissingFields)
{
@ -572,7 +572,7 @@ void Substitution::replaceChildren(TypeId ty)
ftv->argTypes = replace(ftv->argTypes);
ftv->retTypes = replace(ftv->retTypes);
}
else if (TableTypeVar* ttv = getMutable<TableTypeVar>(ty))
else if (TableType* ttv = getMutable<TableType>(ty))
{
LUAU_ASSERT(!ttv->boundTo);
for (auto& [name, prop] : ttv->props)
@ -589,22 +589,22 @@ void Substitution::replaceChildren(TypeId ty)
for (TypePackId& itp : ttv->instantiatedTypePackParams)
itp = replace(itp);
}
else if (MetatableTypeVar* mtv = getMutable<MetatableTypeVar>(ty))
else if (MetatableType* mtv = getMutable<MetatableType>(ty))
{
mtv->table = replace(mtv->table);
mtv->metatable = replace(mtv->metatable);
}
else if (UnionTypeVar* utv = getMutable<UnionTypeVar>(ty))
else if (UnionType* utv = getMutable<UnionType>(ty))
{
for (TypeId& opt : utv->options)
opt = replace(opt);
}
else if (IntersectionTypeVar* itv = getMutable<IntersectionTypeVar>(ty))
else if (IntersectionType* itv = getMutable<IntersectionType>(ty))
{
for (TypeId& part : itv->parts)
part = replace(part);
}
else if (PendingExpansionTypeVar* petv = getMutable<PendingExpansionTypeVar>(ty))
else if (PendingExpansionType* petv = getMutable<PendingExpansionType>(ty))
{
for (TypeId& a : petv->typeArguments)
a = replace(a);
@ -612,7 +612,7 @@ void Substitution::replaceChildren(TypeId ty)
for (TypePackId& a : petv->packArguments)
a = replace(a);
}
else if (ClassTypeVar* ctv = getMutable<ClassTypeVar>(ty); FFlag::LuauClassTypeVarsInSubstitution && ctv)
else if (ClassType* ctv = getMutable<ClassType>(ty); FFlag::LuauClassTypeVarsInSubstitution && ctv)
{
for (auto& [name, prop] : ctv->props)
prop.type = replace(prop.type);
@ -623,7 +623,7 @@ void Substitution::replaceChildren(TypeId ty)
if (ctv->metatable)
ctv->metatable = replace(*ctv->metatable);
}
else if (NegationTypeVar* ntv = getMutable<NegationTypeVar>(ty))
else if (NegationType* ntv = getMutable<NegationType>(ty))
{
ntv->ty = replace(ntv->ty);
}

View file

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

View file

@ -4,10 +4,11 @@
#include "Luau/Constraint.h"
#include "Luau/Location.h"
#include "Luau/Scope.h"
#include "Luau/TxnLog.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypePack.h"
#include "Luau/TypeVar.h"
#include "Luau/VisitTypeVar.h"
#include "Luau/Type.h"
#include "Luau/VisitType.h"
#include <algorithm>
#include <stdexcept>
@ -17,6 +18,7 @@ LUAU_FASTFLAG(LuauUnknownAndNeverType)
LUAU_FASTFLAGVARIABLE(LuauLineBreaksDetermineIndents, false)
LUAU_FASTFLAGVARIABLE(LuauFunctionReturnStringificationFixup, false)
LUAU_FASTFLAGVARIABLE(LuauUnseeArrayTtv, false)
LUAU_FASTFLAGVARIABLE(LuauSerializeNilUnionAsNil, false)
/*
* Prefix generic typenames with gen-
@ -31,7 +33,7 @@ namespace Luau
namespace
{
struct FindCyclicTypes final : TypeVarVisitor
struct FindCyclicTypes final : TypeVisitor
{
FindCyclicTypes() = default;
FindCyclicTypes(const FindCyclicTypes&) = delete;
@ -63,7 +65,7 @@ struct FindCyclicTypes final : TypeVarVisitor
return visitedPacks.insert(tp).second;
}
bool visit(TypeId ty, const TableTypeVar& ttv) override
bool visit(TypeId ty, const TableType& ttv) override
{
if (!visited.insert(ty).second)
return false;
@ -82,7 +84,7 @@ struct FindCyclicTypes final : TypeVarVisitor
return true;
}
bool visit(TypeId ty, const ClassTypeVar&) override
bool visit(TypeId ty, const ClassType&) override
{
return false;
}
@ -136,7 +138,7 @@ struct StringifierState
, result(result)
, exhaustive(opts.exhaustive)
{
for (const auto& [_, v] : opts.nameMap.typeVars)
for (const auto& [_, v] : opts.nameMap.types)
usedNames.insert(v);
for (const auto& [_, v] : opts.nameMap.typePacks)
usedNames.insert(v);
@ -162,8 +164,8 @@ struct StringifierState
std::string getName(TypeId ty)
{
const size_t s = opts.nameMap.typeVars.size();
std::string& n = opts.nameMap.typeVars[ty];
const size_t s = opts.nameMap.types.size();
std::string& n = opts.nameMap.types[ty];
if (!n.empty())
return n;
@ -291,11 +293,11 @@ private:
}
};
struct TypeVarStringifier
struct TypeStringifier
{
StringifierState& state;
explicit TypeVarStringifier(StringifierState& state)
explicit TypeStringifier(StringifierState& state)
: state(state)
{
}
@ -393,17 +395,17 @@ struct TypeVarStringifier
}
}
void operator()(TypeId, const BoundTypeVar& btv)
void operator()(TypeId, const BoundType& btv)
{
stringify(btv.boundTo);
}
void operator()(TypeId ty, const GenericTypeVar& gtv)
void operator()(TypeId ty, const GenericType& gtv)
{
if (gtv.explicitName)
{
state.usedNames.insert(gtv.name);
state.opts.nameMap.typeVars[ty] = gtv.name;
state.opts.nameMap.types[ty] = gtv.name;
state.emit(gtv.name);
}
else
@ -419,40 +421,40 @@ struct TypeVarStringifier
}
}
void operator()(TypeId, const BlockedTypeVar& btv)
void operator()(TypeId, const BlockedType& btv)
{
state.emit("*blocked-");
state.emit(btv.index);
state.emit("*");
}
void operator()(TypeId ty, const PendingExpansionTypeVar& petv)
void operator()(TypeId ty, const PendingExpansionType& petv)
{
state.emit("*pending-expansion-");
state.emit(petv.index);
state.emit("*");
}
void operator()(TypeId, const PrimitiveTypeVar& ptv)
void operator()(TypeId, const PrimitiveType& ptv)
{
switch (ptv.type)
{
case PrimitiveTypeVar::NilType:
case PrimitiveType::NilType:
state.emit("nil");
return;
case PrimitiveTypeVar::Boolean:
case PrimitiveType::Boolean:
state.emit("boolean");
return;
case PrimitiveTypeVar::Number:
case PrimitiveType::Number:
state.emit("number");
return;
case PrimitiveTypeVar::String:
case PrimitiveType::String:
state.emit("string");
return;
case PrimitiveTypeVar::Thread:
case PrimitiveType::Thread:
state.emit("thread");
return;
case PrimitiveTypeVar::Function:
case PrimitiveType::Function:
state.emit("function");
return;
default:
@ -461,7 +463,7 @@ struct TypeVarStringifier
}
}
void operator()(TypeId, const SingletonTypeVar& stv)
void operator()(TypeId, const SingletonType& stv)
{
if (const BooleanSingleton* bs = Luau::get<BooleanSingleton>(&stv))
state.emit(bs->value ? "true" : "false");
@ -478,7 +480,7 @@ struct TypeVarStringifier
}
}
void operator()(TypeId, const FunctionTypeVar& ftv)
void operator()(TypeId, const FunctionType& ftv)
{
if (state.hasSeen(&ftv))
{
@ -540,7 +542,7 @@ struct TypeVarStringifier
state.unsee(&ftv);
}
void operator()(TypeId, const TableTypeVar& ttv)
void operator()(TypeId, const TableType& ttv)
{
if (ttv.boundTo)
return stringify(*ttv.boundTo);
@ -682,7 +684,7 @@ struct TypeVarStringifier
state.unsee(&ttv);
}
void operator()(TypeId, const MetatableTypeVar& mtv)
void operator()(TypeId, const MetatableType& mtv)
{
state.result.invalid = true;
if (!state.exhaustive && mtv.syntheticName)
@ -699,17 +701,17 @@ struct TypeVarStringifier
state.emit(" }");
}
void operator()(TypeId, const ClassTypeVar& ctv)
void operator()(TypeId, const ClassType& ctv)
{
state.emit(ctv.name);
}
void operator()(TypeId, const AnyTypeVar&)
void operator()(TypeId, const AnyType&)
{
state.emit("any");
}
void operator()(TypeId, const UnionTypeVar& uv)
void operator()(TypeId, const UnionType& uv)
{
if (state.hasSeen(&uv))
{
@ -719,6 +721,7 @@ struct TypeVarStringifier
}
bool optional = false;
bool hasNonNilDisjunct = false;
std::vector<std::string> results = {};
for (auto el : &uv)
@ -730,10 +733,14 @@ struct TypeVarStringifier
optional = true;
continue;
}
else
{
hasNonNilDisjunct = true;
}
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)
state.emit("(");
@ -772,11 +779,17 @@ struct TypeVarStringifier
if (results.size() > 1)
s = ")?";
if (FFlag::LuauSerializeNilUnionAsNil)
{
if (!hasNonNilDisjunct)
s = "nil";
}
state.emit(s);
}
}
void operator()(TypeId, const IntersectionTypeVar& uv)
void operator()(TypeId, const IntersectionType& uv)
{
if (state.hasSeen(&uv))
{
@ -792,7 +805,7 @@ struct TypeVarStringifier
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)
state.emit("(");
@ -823,35 +836,35 @@ struct TypeVarStringifier
}
}
void operator()(TypeId, const ErrorTypeVar& tv)
void operator()(TypeId, const ErrorType& tv)
{
state.result.error = true;
state.emit(FFlag::LuauUnknownAndNeverType ? "*error-type*" : "*unknown*");
}
void operator()(TypeId, const LazyTypeVar& ltv)
void operator()(TypeId, const LazyType& ltv)
{
state.result.invalid = true;
state.emit("lazy?");
}
void operator()(TypeId, const UnknownTypeVar& ttv)
void operator()(TypeId, const UnknownType& ttv)
{
state.emit("unknown");
}
void operator()(TypeId, const NeverTypeVar& ttv)
void operator()(TypeId, const NeverType& ttv)
{
state.emit("never");
}
void operator()(TypeId, const NegationTypeVar& ntv)
void operator()(TypeId, const NegationType& ntv)
{
state.emit("~");
// The precedence of `~` should be less than `|` and `&`.
TypeId followed = follow(ntv.ty);
bool parens = get<UnionTypeVar>(followed) || get<IntersectionTypeVar>(followed);
bool parens = get<UnionType>(followed) || get<IntersectionType>(followed);
if (parens)
state.emit("(");
@ -885,7 +898,7 @@ struct TypePackStringifier
void stringify(TypeId tv)
{
TypeVarStringifier tvs{state};
TypeStringifier tvs{state};
tvs.stringify(tv);
}
@ -1035,13 +1048,13 @@ struct TypePackStringifier
}
};
void TypeVarStringifier::stringify(TypePackId tp)
void TypeStringifier::stringify(TypePackId tp)
{
TypePackStringifier tps(state);
tps.stringify(tp);
}
void TypeVarStringifier::stringify(TypePackId tpid, const std::vector<std::optional<FunctionArgument>>& names)
void TypeStringifier::stringify(TypePackId tpid, const std::vector<std::optional<FunctionArgument>>& names)
{
TypePackStringifier tps(state, names);
tps.stringify(tpid);
@ -1057,7 +1070,7 @@ static void assignCycleNames(const std::set<TypeId>& cycles, const std::set<Type
std::string name;
// 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 (std::find_if(ttv->instantiatedTypeParams.begin(), ttv->instantiatedTypeParams.end(),
@ -1087,13 +1100,12 @@ static void assignCycleNames(const std::set<TypeId>& cycles, const std::set<Type
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.
* 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.
*/
ty = follow(ty);
ToStringResult result;
StringifierState state{opts, result};
@ -1105,11 +1117,11 @@ ToStringResult toStringDetailed(TypeId ty, ToStringOptions& opts)
assignCycleNames(cycles, cycleTPs, state.cycleNames, state.cycleTpNames, opts.exhaustive);
TypeVarStringifier tvs{state};
TypeStringifier tvs{state};
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)
result.invalid = true;
@ -1132,7 +1144,7 @@ ToStringResult toStringDetailed(TypeId ty, ToStringOptions& opts)
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.name = *mtv->syntheticName;
@ -1220,7 +1232,7 @@ ToStringResult toStringDetailed(TypeId ty, ToStringOptions& opts)
ToStringResult toStringDetailed(TypePackId tp, ToStringOptions& opts)
{
/*
* 1. Walk the TypeVar and track seen TypeIds. When you reencounter a TypeId, add it to a set of seen cycles.
* 1. Walk the Type and track seen TypeIds. When you reencounter a TypeId, add it to a set of seen cycles.
* 2. Generate some names for each cycle. For a starting point, we can just call them t0, t1 and so on.
* 3. For each seen cycle, stringify it like we do now, but replace each known cycle with its name.
* 4. Print out the root of the type using the same algorithm as step 3.
@ -1235,7 +1247,7 @@ ToStringResult toStringDetailed(TypePackId tp, ToStringOptions& opts)
assignCycleNames(cycles, cycleTPs, state.cycleNames, state.cycleTpNames, opts.exhaustive);
TypeVarStringifier tvs{state};
TypeStringifier tvs{state};
/* If the root itself is a cycle, we special case a little.
* We go out of our way to print the following:
@ -1299,7 +1311,7 @@ std::string toString(TypePackId tp, ToStringOptions& opts)
return toStringDetailed(tp, opts).name;
}
std::string toString(const TypeVar& tv, ToStringOptions& opts)
std::string toString(const Type& tv, ToStringOptions& opts)
{
return toString(const_cast<TypeId>(&tv), opts);
}
@ -1309,11 +1321,11 @@ std::string toString(const TypePackVar& tp, ToStringOptions& 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;
StringifierState state{opts, result};
TypeVarStringifier tvs{state};
TypeStringifier tvs{state};
state.emit(funcName);

View file

@ -87,7 +87,7 @@ void TxnLog::concatAsIntersections(TxnLog rhs, NotNull<TypeArena> arena)
{
TypeId leftTy = arena->addType((*leftRep)->pending);
TypeId rightTy = arena->addType(rightRep->pending);
typeVarChanges[ty]->pending.ty = IntersectionTypeVar{{leftTy, rightTy}};
typeVarChanges[ty]->pending.ty = IntersectionType{{leftTy, rightTy}};
}
else
typeVarChanges[ty] = std::move(rightRep);
@ -105,7 +105,7 @@ void TxnLog::concatAsUnion(TxnLog rhs, NotNull<TypeArena> arena)
{
TypeId leftTy = arena->addType((*leftRep)->pending);
TypeId rightTy = arena->addType(rightRep->pending);
typeVarChanges[ty]->pending.ty = UnionTypeVar{{leftTy, rightTy}};
typeVarChanges[ty]->pending.ty = UnionType{{leftTy, rightTy}};
}
else
typeVarChanges[ty] = std::move(rightRep);
@ -261,7 +261,7 @@ PendingTypePack* TxnLog::pending(TypePackId tp) const
return nullptr;
}
PendingType* TxnLog::replace(TypeId ty, TypeVar replacement)
PendingType* TxnLog::replace(TypeId ty, Type replacement)
{
PendingType* newTy = queue(ty);
newTy->pending.reassign(replacement);
@ -277,10 +277,10 @@ PendingTypePack* TxnLog::replace(TypePackId tp, TypePackVar replacement)
PendingType* TxnLog::bindTable(TypeId ty, std::optional<TypeId> newBoundTo)
{
LUAU_ASSERT(get<TableTypeVar>(ty));
LUAU_ASSERT(get<TableType>(ty));
PendingType* newTy = queue(ty);
if (TableTypeVar* ttv = Luau::getMutable<TableTypeVar>(newTy))
if (TableType* ttv = Luau::getMutable<TableType>(newTy))
ttv->boundTo = newBoundTo;
return newTy;
@ -288,19 +288,19 @@ PendingType* TxnLog::bindTable(TypeId ty, std::optional<TypeId> newBoundTo)
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);
if (FreeTypeVar* ftv = Luau::getMutable<FreeTypeVar>(newTy))
if (FreeType* ftv = Luau::getMutable<FreeType>(newTy))
{
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);
ttv->level = newLevel;
}
else if (FunctionTypeVar* ftv = Luau::getMutable<FunctionTypeVar>(newTy))
else if (FunctionType* ftv = Luau::getMutable<FunctionType>(newTy))
{
ftv->level = newLevel;
}
@ -323,19 +323,19 @@ PendingTypePack* TxnLog::changeLevel(TypePackId tp, TypeLevel newLevel)
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);
if (FreeTypeVar* ftv = Luau::getMutable<FreeTypeVar>(newTy))
if (FreeType* ftv = Luau::getMutable<FreeType>(newTy))
{
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);
ttv->scope = newScope;
}
else if (FunctionTypeVar* ftv = Luau::getMutable<FunctionTypeVar>(newTy))
else if (FunctionType* ftv = Luau::getMutable<FunctionType>(newTy))
{
ftv->scope = newScope;
}
@ -358,10 +358,10 @@ PendingTypePack* TxnLog::changeScope(TypePackId tp, NotNull<Scope> newScope)
PendingType* TxnLog::changeIndexer(TypeId ty, std::optional<TableIndexer> indexer)
{
LUAU_ASSERT(get<TableTypeVar>(ty));
LUAU_ASSERT(get<TableType>(ty));
PendingType* newTy = queue(ty);
if (TableTypeVar* ttv = Luau::getMutable<TableTypeVar>(newTy))
if (TableType* ttv = Luau::getMutable<TableType>(newTy))
{
ttv->indexer = indexer;
}
@ -371,11 +371,11 @@ PendingType* TxnLog::changeIndexer(TypeId ty, std::optional<TableIndexer> indexe
std::optional<TypeLevel> TxnLog::getLevel(TypeId ty) const
{
if (FreeTypeVar* ftv = getMutable<FreeTypeVar>(ty))
if (FreeType* ftv = getMutable<FreeType>(ty))
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;
else if (FunctionTypeVar* ftv = getMutable<FunctionTypeVar>(ty))
else if (FunctionType* ftv = getMutable<FunctionType>(ty))
return ftv->level;
return std::nullopt;
@ -392,7 +392,7 @@ TypeId TxnLog::follow(TypeId ty) const
// Ugly: Fabricate a TypeId that doesn't adhere to most of the invariants
// that normally apply. This is safe because follow will only call get<>
// on the returned pointer.
return const_cast<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()
{
typeVars.clear();
types.clear();
typePacks.clear();
}
TypeId TypeArena::addTV(TypeVar&& tv)
TypeId TypeArena::addTV(Type&& tv)
{
TypeId allocated = typeVars.allocate(std::move(tv));
TypeId allocated = types.allocate(std::move(tv));
asMutable(allocated)->owningArena = this;
@ -24,7 +24,7 @@ TypeId TypeArena::addTV(TypeVar&& tv)
TypeId TypeArena::freshType(TypeLevel level)
{
TypeId allocated = typeVars.allocate(FreeTypeVar{level});
TypeId allocated = types.allocate(FreeType{level});
asMutable(allocated)->owningArena = this;
@ -33,7 +33,7 @@ TypeId TypeArena::freshType(TypeLevel level)
TypeId TypeArena::freshType(Scope* scope)
{
TypeId allocated = typeVars.allocate(FreeTypeVar{scope});
TypeId allocated = types.allocate(FreeType{scope});
asMutable(allocated)->owningArena = this;
@ -42,7 +42,7 @@ TypeId TypeArena::freshType(Scope* scope)
TypeId TypeArena::freshType(Scope* scope, TypeLevel level)
{
TypeId allocated = typeVars.allocate(FreeTypeVar{scope, level});
TypeId allocated = types.allocate(FreeType{scope, level});
asMutable(allocated)->owningArena = this;
@ -99,7 +99,7 @@ void freeze(TypeArena& arena)
if (!FFlag::DebugLuauFreezeArena)
return;
arena.typeVars.freeze();
arena.types.freeze();
arena.typePacks.freeze();
}
@ -108,7 +108,7 @@ void unfreeze(TypeArena& arena)
if (!FFlag::DebugLuauFreezeArena)
return;
arena.typeVars.unfreeze();
arena.types.unfreeze();
arena.typePacks.unfreeze();
}

View file

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

View file

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

View file

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

View file

@ -107,6 +107,8 @@ public:
void vmulsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
void vdivsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
void vandpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
void vxorpd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
void vucomisd(OperandX64 src1, OperandX64 src2);
@ -129,6 +131,11 @@ public:
void vmovaps(OperandX64 dst, OperandX64 src);
void vmovupd(OperandX64 dst, OperandX64 src);
void vmovups(OperandX64 dst, OperandX64 src);
void vmovq(OperandX64 lhs, OperandX64 rhs);
void vmaxsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
void vminsd(OperandX64 dst, OperandX64 src1, OperandX64 src2);
// Run final checks
void finalize();

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);
}
void AssemblyBuilderX64::vandpd(OperandX64 dst, OperandX64 src1, OperandX64 src2)
{
placeAvx("vandpd", dst, src1, src2, 0x54, false, AVX_0F, AVX_66);
}
void AssemblyBuilderX64::vxorpd(OperandX64 dst, OperandX64 src1, OperandX64 src2)
{
placeAvx("vxorpd", dst, src1, src2, 0x57, false, AVX_0F, AVX_66);
@ -699,6 +704,36 @@ void AssemblyBuilderX64::vmovups(OperandX64 dst, OperandX64 src)
placeAvx("vmovups", dst, src, 0x10, 0x11, false, AVX_0F, AVX_NP);
}
void AssemblyBuilderX64::vmovq(OperandX64 dst, OperandX64 src)
{
if (dst.base.size == SizeX64::xmmword)
{
LUAU_ASSERT(dst.cat == CategoryX64::reg);
LUAU_ASSERT(src.base.size == SizeX64::qword);
placeAvx("vmovq", dst, src, 0x6e, true, AVX_0F, AVX_66);
}
else if (dst.base.size == SizeX64::qword)
{
LUAU_ASSERT(src.cat == CategoryX64::reg);
LUAU_ASSERT(src.base.size == SizeX64::xmmword);
placeAvx("vmovq", src, dst, 0x7e, true, AVX_0F, AVX_66);
}
else
{
LUAU_ASSERT(!"No encoding for left operand of this category");
}
}
void AssemblyBuilderX64::vmaxsd(OperandX64 dst, OperandX64 src1, OperandX64 src2)
{
placeAvx("vmaxsd", dst, src1, src2, 0x5f, false, AVX_0F, AVX_F2);
}
void AssemblyBuilderX64::vminsd(OperandX64 dst, OperandX64 src1, OperandX64 src2)
{
placeAvx("vminsd", dst, src1, src2, 0x5d, false, AVX_0F, AVX_F2);
}
void AssemblyBuilderX64::finalize()
{
code.resize(codePos - code.data());

View file

@ -5,6 +5,7 @@
#include "Luau/Bytecode.h"
#include "EmitCommonX64.h"
#include "NativeState.h"
#include "lstate.h"
@ -88,6 +89,341 @@ BuiltinImplResult emitBuiltinMathSqrt(AssemblyBuilderX64& build, int nparams, in
return {BuiltinImplType::UsesFallback, 1};
}
BuiltinImplResult emitBuiltinMathAbs(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
if (nparams < 1 || nresults > 1)
return {BuiltinImplType::None, -1};
if (build.logText)
build.logAppend("; inlined LBF_MATH_ABS\n");
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
build.vmovsd(xmm0, luauRegValue(arg));
build.vandpd(xmm0, xmm0, build.i64(~(1LL << 63)));
build.vmovsd(luauRegValue(ra), xmm0);
if (ra != arg)
build.mov(luauRegTag(ra), LUA_TNUMBER);
return {BuiltinImplType::UsesFallback, 1};
}
static BuiltinImplResult emitBuiltinMathSingleArgFunc(
AssemblyBuilderX64& build, int nparams, int ra, int arg, int nresults, Label& fallback, const char* name, int32_t offset)
{
if (nparams < 1 || nresults > 1)
return {BuiltinImplType::None, -1};
if (build.logText)
build.logAppend("; inlined %s\n", name);
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
build.vmovsd(xmm0, luauRegValue(arg));
build.call(qword[rNativeContext + offset]);
build.vmovsd(luauRegValue(ra), xmm0);
if (ra != arg)
build.mov(luauRegTag(ra), LUA_TNUMBER);
return {BuiltinImplType::UsesFallback, 1};
}
BuiltinImplResult emitBuiltinMathExp(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_EXP", offsetof(NativeContext, libm_exp));
}
BuiltinImplResult emitBuiltinMathDeg(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
if (nparams < 1 || nresults > 1)
return {BuiltinImplType::None, -1};
if (build.logText)
build.logAppend("; inlined LBF_MATH_DEG\n");
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
const double rpd = (3.14159265358979323846 / 180.0);
build.vmovsd(xmm0, luauRegValue(arg));
build.vdivsd(xmm0, xmm0, build.f64(rpd));
build.vmovsd(luauRegValue(ra), xmm0);
if (ra != arg)
build.mov(luauRegTag(ra), LUA_TNUMBER);
return {BuiltinImplType::UsesFallback, 1};
}
BuiltinImplResult emitBuiltinMathRad(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
if (nparams < 1 || nresults > 1)
return {BuiltinImplType::None, -1};
if (build.logText)
build.logAppend("; inlined LBF_MATH_RAD\n");
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
const double rpd = (3.14159265358979323846 / 180.0);
build.vmovsd(xmm0, luauRegValue(arg));
build.vmulsd(xmm0, xmm0, build.f64(rpd));
build.vmovsd(luauRegValue(ra), xmm0);
if (ra != arg)
build.mov(luauRegTag(ra), LUA_TNUMBER);
return {BuiltinImplType::UsesFallback, 1};
}
BuiltinImplResult emitBuiltinMathFmod(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
if (nparams < 2 || nresults > 1)
return {BuiltinImplType::None, -1};
if (build.logText)
build.logAppend("; inlined LBF_MATH_FMOD\n");
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
build.jcc(ConditionX64::NotEqual, fallback);
build.vmovsd(xmm0, luauRegValue(arg));
build.vmovsd(xmm1, qword[args + offsetof(TValue, value)]);
build.call(qword[rNativeContext + offsetof(NativeContext, libm_fmod)]);
build.vmovsd(luauRegValue(ra), xmm0);
if (ra != arg)
build.mov(luauRegTag(ra), LUA_TNUMBER);
return {BuiltinImplType::UsesFallback, 1};
}
BuiltinImplResult emitBuiltinMathPow(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
if (nparams < 2 || nresults > 1)
return {BuiltinImplType::None, -1};
if (build.logText)
build.logAppend("; inlined LBF_MATH_POW\n");
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
build.jcc(ConditionX64::NotEqual, fallback);
build.vmovsd(xmm0, luauRegValue(arg));
build.vmovsd(xmm1, qword[args + offsetof(TValue, value)]);
build.call(qword[rNativeContext + offsetof(NativeContext, libm_pow)]);
build.vmovsd(luauRegValue(ra), xmm0);
if (ra != arg)
build.mov(luauRegTag(ra), LUA_TNUMBER);
return {BuiltinImplType::UsesFallback, 1};
}
BuiltinImplResult emitBuiltinMathMin(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
if (nparams != 2 || nresults > 1)
return {BuiltinImplType::None, -1};
if (build.logText)
build.logAppend("; inlined LBF_MATH_MIN\n");
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
build.jcc(ConditionX64::NotEqual, fallback);
build.vmovsd(xmm0, qword[args + offsetof(TValue, value)]);
build.vminsd(xmm0, xmm0, luauRegValue(arg));
build.vmovsd(luauRegValue(ra), xmm0);
if (ra != arg)
build.mov(luauRegTag(ra), LUA_TNUMBER);
return {BuiltinImplType::UsesFallback, 1};
}
BuiltinImplResult emitBuiltinMathMax(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
if (nparams != 2 || nresults > 1)
return {BuiltinImplType::None, -1};
if (build.logText)
build.logAppend("; inlined LBF_MATH_MAX\n");
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
build.jcc(ConditionX64::NotEqual, fallback);
build.vmovsd(xmm0, qword[args + offsetof(TValue, value)]);
build.vmaxsd(xmm0, xmm0, luauRegValue(arg));
build.vmovsd(luauRegValue(ra), xmm0);
if (ra != arg)
build.mov(luauRegTag(ra), LUA_TNUMBER);
return {BuiltinImplType::UsesFallback, 1};
}
BuiltinImplResult emitBuiltinMathAsin(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_ASIN", offsetof(NativeContext, libm_asin));
}
BuiltinImplResult emitBuiltinMathSin(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_SIN", offsetof(NativeContext, libm_sin));
}
BuiltinImplResult emitBuiltinMathSinh(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_SINH", offsetof(NativeContext, libm_sinh));
}
BuiltinImplResult emitBuiltinMathAcos(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_ACOS", offsetof(NativeContext, libm_acos));
}
BuiltinImplResult emitBuiltinMathCos(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_COS", offsetof(NativeContext, libm_cos));
}
BuiltinImplResult emitBuiltinMathCosh(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_COSH", offsetof(NativeContext, libm_cosh));
}
BuiltinImplResult emitBuiltinMathAtan(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_ATAN", offsetof(NativeContext, libm_atan));
}
BuiltinImplResult emitBuiltinMathTan(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_TAN", offsetof(NativeContext, libm_tan));
}
BuiltinImplResult emitBuiltinMathTanh(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_TANH", offsetof(NativeContext, libm_tanh));
}
BuiltinImplResult emitBuiltinMathAtan2(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
if (nparams < 2 || nresults > 1)
return {BuiltinImplType::None, -1};
if (build.logText)
build.logAppend("; inlined LBF_MATH_ATAN2\n");
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
build.jcc(ConditionX64::NotEqual, fallback);
build.vmovsd(xmm0, luauRegValue(arg));
build.vmovsd(xmm1, qword[args + offsetof(TValue, value)]);
build.call(qword[rNativeContext + offsetof(NativeContext, libm_atan2)]);
build.vmovsd(luauRegValue(ra), xmm0);
if (ra != arg)
build.mov(luauRegTag(ra), LUA_TNUMBER);
return {BuiltinImplType::UsesFallback, 1};
}
BuiltinImplResult emitBuiltinMathLog10(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
return emitBuiltinMathSingleArgFunc(build, nparams, ra, arg, nresults, fallback, "LBF_MATH_LOG10", offsetof(NativeContext, libm_log10));
}
BuiltinImplResult emitBuiltinMathLog(AssemblyBuilderX64& build, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
if (nparams < 1 || nresults > 1)
return {BuiltinImplType::None, -1};
if (build.logText)
build.logAppend("; inlined LBF_MATH_LOG\n");
jumpIfTagIsNot(build, arg, LUA_TNUMBER, fallback);
build.vmovsd(xmm0, luauRegValue(arg));
if (nparams == 1)
{
build.call(qword[rNativeContext + offsetof(NativeContext, libm_log)]);
}
else
{
Label log10check, logdivlog, exit;
// Using 'rbx' for non-volatile temporary storage of log(arg1) result
RegisterX64 tmp = rbx;
OperandX64 arg2value = qword[args + offsetof(TValue, value)];
// TODO: jumpIfTagIsNot can be generalized to take OperandX64 and then we can use it here; let's wait until we see this more though
build.cmp(dword[args + offsetof(TValue, tt)], LUA_TNUMBER);
build.jcc(ConditionX64::NotEqual, fallback);
build.vmovsd(xmm1, arg2value);
jumpOnNumberCmp(build, noreg, build.f64(2.0), xmm1, ConditionX64::NotEqual, log10check);
build.call(qword[rNativeContext + offsetof(NativeContext, libm_log2)]);
build.jmp(exit);
build.setLabel(log10check);
jumpOnNumberCmp(build, noreg, build.f64(10.0), xmm1, ConditionX64::NotEqual, logdivlog);
build.call(qword[rNativeContext + offsetof(NativeContext, libm_log10)]);
build.jmp(exit);
build.setLabel(logdivlog);
// log(arg1)
build.call(qword[rNativeContext + offsetof(NativeContext, libm_log)]);
build.vmovq(tmp, xmm0);
// log(arg2)
build.vmovsd(xmm0, arg2value);
build.call(qword[rNativeContext + offsetof(NativeContext, libm_log)]);
// log(arg1) / log(arg2)
build.vmovq(xmm1, tmp);
build.vdivsd(xmm0, xmm1, xmm0);
build.setLabel(exit);
}
build.vmovsd(luauRegValue(ra), xmm0);
if (ra != arg)
build.mov(luauRegTag(ra), LUA_TNUMBER);
return {BuiltinImplType::UsesFallback, 1};
}
BuiltinImplResult emitBuiltin(AssemblyBuilderX64& build, int bfid, int nparams, int ra, int arg, OperandX64 args, int nresults, Label& fallback)
{
switch (bfid)
@ -100,6 +436,46 @@ BuiltinImplResult emitBuiltin(AssemblyBuilderX64& build, int bfid, int nparams,
return emitBuiltinMathCeil(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_SQRT:
return emitBuiltinMathSqrt(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_ABS:
return emitBuiltinMathAbs(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_EXP:
return emitBuiltinMathExp(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_DEG:
return emitBuiltinMathDeg(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_RAD:
return emitBuiltinMathRad(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_FMOD:
return emitBuiltinMathFmod(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_POW:
return emitBuiltinMathPow(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_MIN:
return emitBuiltinMathMin(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_MAX:
return emitBuiltinMathMax(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_ASIN:
return emitBuiltinMathAsin(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_SIN:
return emitBuiltinMathSin(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_SINH:
return emitBuiltinMathSinh(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_ACOS:
return emitBuiltinMathAcos(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_COS:
return emitBuiltinMathCos(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_COSH:
return emitBuiltinMathCosh(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_ATAN:
return emitBuiltinMathAtan(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_TAN:
return emitBuiltinMathTan(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_TANH:
return emitBuiltinMathTanh(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_ATAN2:
return emitBuiltinMathAtan2(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_LOG10:
return emitBuiltinMathLog10(build, nparams, ra, arg, args, nresults, fallback);
case LBF_MATH_LOG:
return emitBuiltinMathLog(build, nparams, ra, arg, args, nresults, fallback);
default:
return {BuiltinImplType::None, -1};
}

View file

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

View file

@ -80,7 +80,23 @@ void initHelperFunctions(NativeState& data)
data.context.luaF_close = luaF_close;
data.context.libm_exp = exp;
data.context.libm_pow = pow;
data.context.libm_fmod = fmod;
data.context.libm_log = log;
data.context.libm_log2 = log2;
data.context.libm_log10 = log10;
data.context.libm_asin = asin;
data.context.libm_sin = sin;
data.context.libm_sinh = sinh;
data.context.libm_acos = acos;
data.context.libm_cos = cos;
data.context.libm_cosh = cosh;
data.context.libm_atan = atan;
data.context.libm_atan2 = atan2;
data.context.libm_tan = tan;
data.context.libm_tanh = tanh;
data.context.forgLoopNodeIter = forgLoopNodeIter;
data.context.forgLoopNonTableFallback = forgLoopNonTableFallback;

View file

@ -78,7 +78,22 @@ struct NativeContext
void (*luaF_close)(lua_State* L, StkId level) = nullptr;
double (*libm_exp)(double) = nullptr;
double (*libm_pow)(double, double) = nullptr;
double (*libm_fmod)(double, double) = nullptr;
double (*libm_asin)(double) = nullptr;
double (*libm_sin)(double) = nullptr;
double (*libm_sinh)(double) = nullptr;
double (*libm_acos)(double) = nullptr;
double (*libm_cos)(double) = nullptr;
double (*libm_cosh)(double) = nullptr;
double (*libm_atan)(double) = nullptr;
double (*libm_atan2)(double, double) = nullptr;
double (*libm_tan)(double) = nullptr;
double (*libm_tanh)(double) = nullptr;
double (*libm_log)(double) = nullptr;
double (*libm_log2)(double) = nullptr;
double (*libm_log10)(double) = nullptr;
// Helper functions
bool (*forgLoopNodeIter)(lua_State* L, Table* h, int index, TValue* ra) = nullptr;

View file

@ -350,7 +350,7 @@ struct Compiler
{
LUAU_ASSERT(!multRet || unsigned(target + targetCount) == regTop);
setDebugLine(expr); // normally compileExpr sets up line info, but compileExprCall can be called directly
setDebugLine(expr); // normally compileExpr sets up line info, but compileExprVarargs can be called directly
bytecode.emitABC(LOP_GETVARARGS, target, multRet ? 0 : uint8_t(targetCount + 1), 0);
}

View file

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

View file

@ -101,32 +101,32 @@ int registerTypes(Luau::TypeChecker& env)
TypeArena& arena = env.globalTypes;
// Vector3 stub
TypeId vector3MetaType = arena.addType(TableTypeVar{});
TypeId vector3MetaType = arena.addType(TableType{});
TypeId vector3InstanceType = arena.addType(ClassTypeVar{"Vector3", {}, nullopt, vector3MetaType, {}, {}, "Test"});
getMutable<ClassTypeVar>(vector3InstanceType)->props = {
TypeId vector3InstanceType = arena.addType(ClassType{"Vector3", {}, nullopt, vector3MetaType, {}, {}, "Test"});
getMutable<ClassType>(vector3InstanceType)->props = {
{"X", {env.numberType}},
{"Y", {env.numberType}},
{"Z", {env.numberType}},
};
getMutable<TableTypeVar>(vector3MetaType)->props = {
getMutable<TableType>(vector3MetaType)->props = {
{"__add", {makeFunction(arena, nullopt, {vector3InstanceType, vector3InstanceType}, {vector3InstanceType})}},
};
env.globalScope->exportedTypeBindings["Vector3"] = TypeFun{{}, vector3InstanceType};
// Instance stub
TypeId instanceType = arena.addType(ClassTypeVar{"Instance", {}, nullopt, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(instanceType)->props = {
TypeId instanceType = arena.addType(ClassType{"Instance", {}, nullopt, nullopt, {}, {}, "Test"});
getMutable<ClassType>(instanceType)->props = {
{"Name", {env.stringType}},
};
env.globalScope->exportedTypeBindings["Instance"] = TypeFun{{}, instanceType};
// Part stub
TypeId partType = arena.addType(ClassTypeVar{"Part", {}, instanceType, nullopt, {}, {}, "Test"});
getMutable<ClassTypeVar>(partType)->props = {
TypeId partType = arena.addType(ClassType{"Part", {}, instanceType, nullopt, {}, {}, "Test"});
getMutable<ClassType>(partType)->props = {
{"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(vxorpd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x29, 0x57, 0xc6);
SINGLE_COMPARE(vandpd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x29, 0x54, 0xc6);
SINGLE_COMPARE(vmaxsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x5f, 0xc6);
SINGLE_COMPARE(vminsd(xmm8, xmm10, xmm14), 0xc4, 0x41, 0x2b, 0x5d, 0xc6);
}
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXUnaryMergeInstructionForms")
@ -475,6 +480,10 @@ TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXMoveInstructionForms")
SINGLE_COMPARE(vmovups(xmm8, xmmword[r9]), 0xc4, 0x41, 0x78, 0x10, 0x01);
SINGLE_COMPARE(vmovups(xmmword[r9], xmm10), 0xc4, 0x41, 0x78, 0x11, 0x11);
SINGLE_COMPARE(vmovups(ymm8, ymmword[r9]), 0xc4, 0x41, 0x7c, 0x10, 0x01);
SINGLE_COMPARE(vmovq(xmm1, rbx), 0xc4, 0xe1, 0xf9, 0x6e, 0xcb);
SINGLE_COMPARE(vmovq(rbx, xmm1), 0xc4, 0xe1, 0xf9, 0x7e, 0xcb);
SINGLE_COMPARE(vmovq(xmm1, qword[r9]), 0xc4, 0xc1, 0xf9, 0x6e, 0x09);
SINGLE_COMPARE(vmovq(qword[r9], xmm1), 0xc4, 0xc1, 0xf9, 0x7e, 0x09);
}
TEST_CASE_FIXTURE(AssemblyBuilderX64Fixture, "AVXConversionInstructionForms")

View file

@ -2,8 +2,8 @@
#include "Luau/Autocomplete.h"
#include "Luau/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/VisitTypeVar.h"
#include "Luau/Type.h"
#include "Luau/VisitType.h"
#include "Luau/StringUtils.h"
#include "Fixture.h"
@ -18,7 +18,7 @@ LUAU_FASTFLAG(LuauSetMetatableDoesNotTimeTravel)
using namespace Luau;
static std::optional<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;
}
@ -499,7 +499,7 @@ TEST_CASE_FIXTURE(ACFixture, "bias_toward_inner_scope")
CHECK_EQ(ac.context, AutocompleteContext::Statement);
TypeId t = follow(*ac.entryMap["A"].type);
const TableTypeVar* tt = get<TableTypeVar>(t);
const TableType* tt = get<TableType>(t);
REQUIRE(tt);
CHECK(tt->props.count("two"));
@ -1244,7 +1244,7 @@ end
REQUIRE(ac.entryMap.count("Table"));
REQUIRE(ac.entryMap["Table"].type);
const TableTypeVar* tv = get<TableTypeVar>(follow(*ac.entryMap["Table"].type));
const TableType* tv = get<TableType>(follow(*ac.entryMap["Table"].type));
REQUIRE(tv);
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
#include "Luau/BuiltinDefinitions.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "Fixture.h"
@ -22,12 +22,12 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "lib_documentation_symbols")
CHECK_MESSAGE(
actualRootSymbol == expectedRootSymbol, "expected symbol ", expectedRootSymbol, " for global ", nameString, ", got ", actualRootSymbol);
const TableTypeVar::Props* props = nullptr;
if (const TableTypeVar* ttv = get<TableTypeVar>(binding.typeId))
const TableType::Props* props = nullptr;
if (const TableType* ttv = get<TableType>(binding.typeId))
{
props = &ttv->props;
}
else if (const ClassTypeVar* ctv = get<ClassTypeVar>(binding.typeId))
else if (const ClassType* ctv = get<ClassType>(binding.typeId))
{
props = &ctv->props;
}

View file

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

View file

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

View file

@ -9,7 +9,7 @@ ConstraintGraphBuilderFixture::ConstraintGraphBuilderFixture()
, mainModule(new Module)
, forceTheFlag{"DebugLuauDeferredConstraintResolution", true}
{
BlockedTypeVar::nextIndex = 0;
BlockedType::nextIndex = 0;
BlockedTypePack::nextIndex = 0;
}
@ -17,7 +17,7 @@ void ConstraintGraphBuilderFixture::generateConstraints(const std::string& code)
{
AstStatBlock* root = parse(code);
dfg = std::make_unique<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()});
cgb->visit(root);
rootScope = cgb->rootScope;

View file

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

View file

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

View file

@ -10,7 +10,7 @@
#include "Luau/ModuleResolver.h"
#include "Luau/Scope.h"
#include "Luau/ToString.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "IostreamOptional.h"
#include "ScopedFlags.h"
@ -78,7 +78,7 @@ struct Fixture
ModulePtr getMainModule();
SourceModule* getMainSourceModule();
std::optional<PrimitiveTypeVar::Type> getPrimitiveType(TypeId ty);
std::optional<PrimitiveType::Type> getPrimitiveType(TypeId ty);
std::optional<TypeId> getType(const std::string& name);
TypeId requireType(const std::string& name);
TypeId requireType(const ModuleName& moduleName, const std::string& name);
@ -102,7 +102,7 @@ struct Fixture
Frontend frontend;
InternalErrorReporter ice;
TypeChecker& typeChecker;
NotNull<SingletonTypes> singletonTypes;
NotNull<BuiltinTypes> builtinTypes;
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");
CHECK_EQ(0, module->internalTypes.typeVars.size());
CHECK_EQ(0, module->internalTypes.types.size());
CHECK_EQ(0, module->internalTypes.typePacks.size());
CHECK_EQ(0, module->astTypes.size());
CHECK_EQ(0, module->astResolvedTypes.size());

View file

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

View file

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

View file

@ -59,14 +59,14 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_non_persistent_primitive")
// Create a new number type that isn't persistent
unfreeze(typeChecker.globalTypes);
TypeId oldNumber = typeChecker.globalTypes.addType(PrimitiveTypeVar{PrimitiveTypeVar::Number});
TypeId oldNumber = typeChecker.globalTypes.addType(PrimitiveType{PrimitiveType::Number});
freeze(typeChecker.globalTypes);
TypeId newNumber = clone(oldNumber, dest, cloneState);
CHECK_NE(newNumber, oldNumber);
CHECK_EQ(*oldNumber, *newNumber);
CHECK_EQ("number", toString(newNumber));
CHECK_EQ(1, dest.typeVars.size());
CHECK_EQ(1, dest.types.size());
}
TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
@ -91,7 +91,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
CloneState cloneState;
TypeId counterCopy = clone(counterType, dest, cloneState);
TableTypeVar* ttv = getMutable<TableTypeVar>(counterCopy);
TableType* ttv = getMutable<TableType>(counterCopy);
REQUIRE(ttv != nullptr);
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;
REQUIRE(methodType != nullptr);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(methodType);
const FunctionType* ftv = get<FunctionType>(methodType);
REQUIRE(ftv != nullptr);
std::optional<TypeId> methodReturnType = first(ftv->retTypes);
@ -107,7 +107,7 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_cyclic_table")
CHECK_EQ(methodReturnType, counterCopy);
CHECK_EQ(2, dest.typePacks.size()); // one for the function args, and another for its return type
CHECK_EQ(2, dest.typeVars.size()); // One table and one function
CHECK_EQ(2, dest.types.size()); // One table and one function
}
TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_point_into_globalTypes_arena")
@ -124,7 +124,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "builtin_types_point_into_globalTypes_arena")
REQUIRE(isInArena(*exports, module->interfaceTypes));
TableTypeVar* exportsTable = getMutable<TableTypeVar>(*exports);
TableType* exportsTable = getMutable<TableType>(*exports);
REQUIRE(exportsTable != nullptr);
TypeId signType = exportsTable->props["sign"].type;
@ -143,13 +143,13 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_union")
CloneState cloneState;
unfreeze(typeChecker.globalTypes);
TypeId oldUnion = typeChecker.globalTypes.addType(UnionTypeVar{{typeChecker.numberType, typeChecker.stringType}});
TypeId oldUnion = typeChecker.globalTypes.addType(UnionType{{typeChecker.numberType, typeChecker.stringType}});
freeze(typeChecker.globalTypes);
TypeId newUnion = clone(oldUnion, dest, cloneState);
CHECK_NE(newUnion, oldUnion);
CHECK_EQ("number | string", toString(newUnion));
CHECK_EQ(1, dest.typeVars.size());
CHECK_EQ(1, dest.types.size());
}
TEST_CASE_FIXTURE(Fixture, "deepClone_intersection")
@ -158,23 +158,23 @@ TEST_CASE_FIXTURE(Fixture, "deepClone_intersection")
CloneState cloneState;
unfreeze(typeChecker.globalTypes);
TypeId oldIntersection = typeChecker.globalTypes.addType(IntersectionTypeVar{{typeChecker.numberType, typeChecker.stringType}});
TypeId oldIntersection = typeChecker.globalTypes.addType(IntersectionType{{typeChecker.numberType, typeChecker.stringType}});
freeze(typeChecker.globalTypes);
TypeId newIntersection = clone(oldIntersection, dest, cloneState);
CHECK_NE(newIntersection, oldIntersection);
CHECK_EQ("number & string", toString(newIntersection));
CHECK_EQ(1, dest.typeVars.size());
CHECK_EQ(1, dest.types.size());
}
TEST_CASE_FIXTURE(Fixture, "clone_class")
{
TypeVar exampleMetaClass{ClassTypeVar{"ExampleClassMeta",
Type exampleMetaClass{ClassType{"ExampleClassMeta",
{
{"__add", {typeChecker.anyType}},
},
std::nullopt, std::nullopt, {}, {}, "Test"}};
TypeVar exampleClass{ClassTypeVar{"ExampleClass",
Type exampleClass{ClassType{"ExampleClass",
{
{"PropOne", {typeChecker.numberType}},
{"PropTwo", {typeChecker.stringType}},
@ -185,11 +185,11 @@ TEST_CASE_FIXTURE(Fixture, "clone_class")
CloneState cloneState;
TypeId cloned = clone(&exampleClass, dest, cloneState);
const ClassTypeVar* ctv = get<ClassTypeVar>(cloned);
const ClassType* ctv = get<ClassType>(cloned);
REQUIRE(ctv != nullptr);
REQUIRE(ctv->metatable);
const ClassTypeVar* metatable = get<ClassTypeVar>(*ctv->metatable);
const ClassType* metatable = get<ClassType>(*ctv->metatable);
REQUIRE(metatable);
CHECK_EQ("ExampleClass", ctv->name);
@ -198,14 +198,14 @@ TEST_CASE_FIXTURE(Fixture, "clone_class")
TEST_CASE_FIXTURE(Fixture, "clone_free_types")
{
TypeVar freeTy(FreeTypeVar{TypeLevel{}});
Type freeTy(FreeType{TypeLevel{}});
TypePackVar freeTp(FreeTypePack{TypeLevel{}});
TypeArena dest;
CloneState cloneState;
TypeId clonedTy = clone(&freeTy, dest, cloneState);
CHECK(get<FreeTypeVar>(clonedTy));
CHECK(get<FreeType>(clonedTy));
cloneState = {};
TypePackId clonedTp = clone(&freeTp, dest, cloneState);
@ -214,15 +214,15 @@ TEST_CASE_FIXTURE(Fixture, "clone_free_types")
TEST_CASE_FIXTURE(Fixture, "clone_free_tables")
{
TypeVar tableTy{TableTypeVar{}};
TableTypeVar* ttv = getMutable<TableTypeVar>(&tableTy);
Type tableTy{TableType{}};
TableType* ttv = getMutable<TableType>(&tableTy);
ttv->state = TableState::Free;
TypeArena dest;
CloneState 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);
}
@ -264,14 +264,14 @@ TEST_CASE_FIXTURE(Fixture, "clone_recursion_limit")
TypeArena src;
TypeId table = src.addType(TableTypeVar{});
TypeId table = src.addType(TableType{});
TypeId nested = table;
for (int i = 0; i < limit + 100; i++)
{
TableTypeVar* ttv = getMutable<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;
}
@ -332,7 +332,7 @@ return {}
REQUIRE(modBiter != modB->getModuleScope()->exportedTypeBindings.end());
TypeId typeA = modAiter->second.type;
TypeId typeB = modBiter->second.type;
TableTypeVar* tableB = getMutable<TableTypeVar>(typeB);
TableType* tableB = getMutable<TableType>(typeB);
REQUIRE(tableB);
CHECK(typeA == tableB->props["q"].type);
}
@ -368,8 +368,8 @@ return exports
std::optional<TypeId> typeB = first(modB->getModuleScope()->returnType);
REQUIRE(typeA);
REQUIRE(typeB);
TableTypeVar* tableA = getMutable<TableTypeVar>(*typeA);
TableTypeVar* tableB = getMutable<TableTypeVar>(*typeB);
TableType* tableA = getMutable<TableType>(*typeA);
TableType* tableB = getMutable<TableType>(*typeB);
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
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "Fixture.h"
@ -23,7 +23,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_nullary_function")
TypeId fooType = requireType("foo");
REQUIRE(fooType);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(fooType);
const FunctionType* ftv = get<FunctionType>(fooType);
REQUIRE_MESSAGE(ftv != nullptr, "Expected a function, got " << toString(fooType));
auto args = flatten(ftv->argTypes).first;
@ -165,7 +165,7 @@ TEST_CASE_FIXTURE(Fixture, "table_props_are_any")
LUAU_REQUIRE_NO_ERRORS(result);
TableTypeVar* ttv = getMutable<TableTypeVar>(requireType("T"));
TableType* ttv = getMutable<TableType>(requireType("T"));
REQUIRE(ttv != nullptr);
@ -189,12 +189,12 @@ TEST_CASE_FIXTURE(Fixture, "inline_table_props_are_also_any")
LUAU_REQUIRE_NO_ERRORS(result);
TableTypeVar* ttv = getMutable<TableTypeVar>(requireType("T"));
TableType* ttv = getMutable<TableType>(requireType("T"));
REQUIRE_MESSAGE(ttv, "Should be a table: " << toString(requireType("T")));
CHECK_EQ(*typeChecker.anyType, *ttv->props["one"].type);
CHECK_EQ(*typeChecker.anyType, *ttv->props["two"].type);
CHECK_MESSAGE(get<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")

View file

@ -3,7 +3,7 @@
#include "Fixture.h"
#include "Luau/Common.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "doctest.h"
#include "Luau/Normalize.h"
@ -17,7 +17,7 @@ struct IsSubtypeFixture : Fixture
{
bool isSubtype(TypeId a, TypeId b)
{
return ::Luau::isSubtype(a, b, NotNull{getMainModule()->getModuleScope().get()}, singletonTypes, ice);
return ::Luau::isSubtype(a, b, NotNull{getMainModule()->getModuleScope().get()}, builtinTypes, ice);
}
};
} // namespace
@ -28,9 +28,9 @@ void createSomeClasses(Frontend& frontend)
unfreeze(arena);
TypeId parentType = arena.addType(ClassTypeVar{"Parent", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"});
TypeId parentType = arena.addType(ClassType{"Parent", {}, frontend.builtinTypes->classType, std::nullopt, {}, nullptr, "Test"});
ClassTypeVar* parentClass = getMutable<ClassTypeVar>(parentType);
ClassType* parentClass = getMutable<ClassType>(parentType);
parentClass->props["method"] = {makeFunction(arena, parentType, {}, {})};
parentClass->props["virtual_method"] = {makeFunction(arena, parentType, {}, {})};
@ -38,15 +38,15 @@ void createSomeClasses(Frontend& frontend)
addGlobalBinding(frontend, "Parent", {parentType});
frontend.getGlobalScope()->exportedTypeBindings["Parent"] = TypeFun{{}, parentType};
TypeId childType = arena.addType(ClassTypeVar{"Child", {}, parentType, std::nullopt, {}, nullptr, "Test"});
TypeId childType = arena.addType(ClassType{"Child", {}, parentType, std::nullopt, {}, nullptr, "Test"});
ClassTypeVar* childClass = getMutable<ClassTypeVar>(childType);
ClassType* childClass = getMutable<ClassType>(childType);
childClass->props["virtual_method"] = {makeFunction(arena, childType, {}, {})};
addGlobalBinding(frontend, "Child", {childType});
frontend.getGlobalScope()->exportedTypeBindings["Child"] = TypeFun{{}, childType};
TypeId unrelatedType = arena.addType(ClassTypeVar{"Unrelated", {}, std::nullopt, std::nullopt, {}, nullptr, "Test"});
TypeId unrelatedType = arena.addType(ClassType{"Unrelated", {}, frontend.builtinTypes->classType, std::nullopt, {}, nullptr, "Test"});
addGlobalBinding(frontend, "Unrelated", {unrelatedType});
frontend.getGlobalScope()->exportedTypeBindings["Unrelated"] = TypeFun{{}, unrelatedType};
@ -394,11 +394,12 @@ TEST_SUITE_END();
struct NormalizeFixture : Fixture
{
ScopedFastFlag sff1{"LuauNegatedFunctionTypes", true};
ScopedFastFlag sff2{"LuauNegatedClassTypes", true};
TypeArena arena;
InternalErrorReporter iceHandler;
UnifierSharedState unifierState{&iceHandler};
Normalizer normalizer{&arena, singletonTypes, NotNull{&unifierState}};
Normalizer normalizer{&arena, builtinTypes, NotNull{&unifierState}};
NormalizeFixture()
{
@ -407,6 +408,7 @@ struct NormalizeFixture : Fixture
const NormalizedType* toNormalizedType(const std::string& annotation)
{
normalizer.clearCaches();
CheckResult result = check("type _Res = " + annotation);
LUAU_REQUIRE_NO_ERRORS(result);
std::optional<TypeId> ty = lookupType("_Res");
@ -524,7 +526,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "union_function_and_top_function")
TEST_CASE_FIXTURE(NormalizeFixture, "negated_function_is_anything_except_a_function")
{
CHECK("(boolean | number | string | thread)?" == toString(normal(R"(
ScopedFastFlag{"LuauNegatedClassTypes", true};
CHECK("(boolean | class | number | string | thread)?" == toString(normal(R"(
Not<fun>
)")));
}
@ -536,8 +540,9 @@ TEST_CASE_FIXTURE(NormalizeFixture, "specific_functions_cannot_be_negated")
TEST_CASE_FIXTURE(NormalizeFixture, "bare_negated_boolean")
{
ScopedFastFlag{"LuauNegatedClassTypes", true};
// TODO: We don't yet have a way to say number | string | thread | nil | Class | Table | Function
CHECK("(function | number | string | thread)?" == toString(normal(R"(
CHECK("(class | function | number | string | thread)?" == toString(normal(R"(
Not<boolean>
)")));
}
@ -603,4 +608,61 @@ export type t0 = (((any)&({_:l0.t0,n0:t0,_G:any,}))&({_:any,}))&(((any)&({_:l0.t
LUAU_REQUIRE_ERRORS(result);
}
TEST_CASE_FIXTURE(NormalizeFixture, "unions_of_classes")
{
ScopedFastFlag sff{"LuauNegatedClassTypes", true};
createSomeClasses(frontend);
CHECK("Parent | Unrelated" == toString(normal("Parent | Unrelated")));
CHECK("Parent" == toString(normal("Parent | Child")));
CHECK("Parent | Unrelated" == toString(normal("Parent | Child | Unrelated")));
}
TEST_CASE_FIXTURE(NormalizeFixture, "intersections_of_classes")
{
ScopedFastFlag sff{"LuauNegatedClassTypes", true};
createSomeClasses(frontend);
CHECK("Child" == toString(normal("Parent & Child")));
CHECK("never" == toString(normal("Child & Unrelated")));
}
TEST_CASE_FIXTURE(NormalizeFixture, "narrow_union_of_classes_with_intersection")
{
ScopedFastFlag sff{"LuauNegatedClassTypes", true};
createSomeClasses(frontend);
CHECK("Child" == toString(normal("(Child | Unrelated) & Child")));
}
TEST_CASE_FIXTURE(NormalizeFixture, "negations_of_classes")
{
ScopedFastFlag sff{"LuauNegatedClassTypes", true};
createSomeClasses(frontend);
CHECK("(Parent & ~Child) | Unrelated" == toString(normal("(Parent & Not<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();

View file

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

View file

@ -5,6 +5,7 @@
#include "Fixture.h"
#include "ScopedFlags.h"
#include "doctest.h"
using namespace Luau;
@ -44,8 +45,8 @@ TEST_CASE_FIXTURE(Fixture, "free_types")
TEST_CASE_FIXTURE(Fixture, "cyclic_table")
{
TypeVar cyclicTable{TypeVariant(TableTypeVar())};
TableTypeVar* tableOne = getMutable<TableTypeVar>(&cyclicTable);
Type cyclicTable{TypeVariant(TableType())};
TableType* tableOne = getMutable<TableType>(&cyclicTable);
tableOne->props["self"] = {&cyclicTable};
CHECK_EQ("t1 where t1 = { self: t1 }", toString(&cyclicTable));
@ -53,8 +54,8 @@ TEST_CASE_FIXTURE(Fixture, "cyclic_table")
TEST_CASE_FIXTURE(Fixture, "named_table")
{
TypeVar table{TypeVariant(TableTypeVar())};
TableTypeVar* t = getMutable<TableTypeVar>(&table);
Type table{TypeVariant(TableType())};
TableType* t = getMutable<TableType>(&table);
t->name = "TheTable";
CHECK_EQ("TheTable", toString(&table));
@ -94,19 +95,43 @@ TEST_CASE_FIXTURE(Fixture, "table_respects_use_line_break")
//clang-format on
}
TEST_CASE_FIXTURE(Fixture, "nil_or_nil_is_nil_not_question_mark")
{
ScopedFastFlag sff("LuauSerializeNilUnionAsNil", true);
CheckResult result = check(R"(
type nil_ty = nil | nil
local a : nil_ty = nil
)");
ToStringOptions opts;
opts.useLineBreaks = false;
CHECK_EQ("nil", toString(requireType("a"), opts));
}
TEST_CASE_FIXTURE(Fixture, "long_disjunct_of_nil_is_nil_not_question_mark")
{
ScopedFastFlag sff("LuauSerializeNilUnionAsNil", true);
CheckResult result = check(R"(
type nil_ty = nil | nil | nil | nil | nil
local a : nil_ty = nil
)");
ToStringOptions opts;
opts.useLineBreaks = false;
CHECK_EQ("nil", toString(requireType("a"), opts));
}
TEST_CASE_FIXTURE(Fixture, "metatable")
{
TypeVar table{TypeVariant(TableTypeVar())};
TypeVar metatable{TypeVariant(TableTypeVar())};
TypeVar mtv{TypeVariant(MetatableTypeVar{&table, &metatable})};
Type table{TypeVariant(TableType())};
Type metatable{TypeVariant(TableType())};
Type mtv{TypeVariant(MetatableType{&table, &metatable})};
CHECK_EQ("{ @metatable { }, { } }", toString(&mtv));
}
TEST_CASE_FIXTURE(Fixture, "named_metatable")
{
TypeVar table{TypeVariant(TableTypeVar())};
TypeVar metatable{TypeVariant(TableTypeVar())};
TypeVar mtv{TypeVariant(MetatableTypeVar{&table, &metatable, "NamedMetatable"})};
Type table{TypeVariant(TableType())};
Type metatable{TypeVariant(TableType())};
Type mtv{TypeVariant(MetatableType{&table, &metatable, "NamedMetatable"})};
CHECK_EQ("NamedMetatable", toString(&mtv));
}
@ -120,7 +145,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "named_metatable_toStringNamedFunction")
)");
TypeId ty = requireType("createTbl");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
const FunctionType* ftv = get<FunctionType>(follow(ty));
REQUIRE(ftv);
CHECK_EQ("createTbl(): NamedMetatable", toStringNamedFunction("createTbl", *ftv));
}
@ -162,16 +187,16 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "exhaustive_toString_of_cyclic_table")
TEST_CASE_FIXTURE(Fixture, "intersection_parenthesized_only_if_needed")
{
auto utv = TypeVar{UnionTypeVar{{typeChecker.numberType, typeChecker.stringType}}};
auto itv = TypeVar{IntersectionTypeVar{{&utv, typeChecker.booleanType}}};
auto utv = Type{UnionType{{typeChecker.numberType, typeChecker.stringType}}};
auto itv = Type{IntersectionType{{&utv, typeChecker.booleanType}}};
CHECK_EQ(toString(&itv), "(number | string) & boolean");
}
TEST_CASE_FIXTURE(Fixture, "union_parenthesized_only_if_needed")
{
auto itv = TypeVar{IntersectionTypeVar{{typeChecker.numberType, typeChecker.stringType}}};
auto utv = TypeVar{UnionTypeVar{{&itv, typeChecker.booleanType}}};
auto itv = Type{IntersectionType{{typeChecker.numberType, typeChecker.stringType}}};
auto utv = Type{UnionType{{&itv, typeChecker.booleanType}}};
CHECK_EQ(toString(&utv), "(number & string) | boolean");
}
@ -181,11 +206,11 @@ TEST_CASE_FIXTURE(Fixture, "functions_are_always_parenthesized_in_unions_or_inte
auto stringAndNumberPack = TypePackVar{TypePack{{typeChecker.stringType, typeChecker.numberType}}};
auto numberAndStringPack = TypePackVar{TypePack{{typeChecker.numberType, typeChecker.stringType}}};
auto sn2ns = TypeVar{FunctionTypeVar{&stringAndNumberPack, &numberAndStringPack}};
auto ns2sn = TypeVar{FunctionTypeVar(typeChecker.globalScope->level, &numberAndStringPack, &stringAndNumberPack)};
auto sn2ns = Type{FunctionType{&stringAndNumberPack, &numberAndStringPack}};
auto ns2sn = Type{FunctionType(typeChecker.globalScope->level, &numberAndStringPack, &stringAndNumberPack)};
auto utv = TypeVar{UnionTypeVar{{&ns2sn, &sn2ns}}};
auto itv = TypeVar{IntersectionTypeVar{{&ns2sn, &sn2ns}}};
auto utv = Type{UnionType{{&ns2sn, &sn2ns}}};
auto itv = Type{IntersectionType{{&ns2sn, &sn2ns}}};
CHECK_EQ(toString(&utv), "((number, string) -> (string, number)) | ((string, number) -> (number, string))");
CHECK_EQ(toString(&itv), "((number, string) -> (string, number)) & ((string, number) -> (number, string))");
@ -226,11 +251,11 @@ TEST_CASE_FIXTURE(Fixture, "unions_respects_use_line_breaks")
TEST_CASE_FIXTURE(Fixture, "quit_stringifying_table_type_when_length_is_exceeded")
{
TableTypeVar ttv{};
TableType ttv{};
for (char c : std::string("abcdefghijklmno"))
ttv.props[std::string(1, c)] = {typeChecker.numberType};
TypeVar tv{ttv};
Type tv{ttv};
ToStringOptions o;
o.exhaustive = false;
@ -240,11 +265,11 @@ TEST_CASE_FIXTURE(Fixture, "quit_stringifying_table_type_when_length_is_exceeded
TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_is_still_capped_when_exhaustive")
{
TableTypeVar ttv{};
TableType ttv{};
for (char c : std::string("abcdefg"))
ttv.props[std::string(1, c)] = {typeChecker.numberType};
TypeVar tv{ttv};
Type tv{ttv};
ToStringOptions o;
o.exhaustive = true;
@ -315,11 +340,11 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_type_is_still_capped_when_exhaustive")
TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_correctly_use_matching_table_state_braces")
{
TableTypeVar ttv{TableState::Sealed, TypeLevel{}};
TableType ttv{TableState::Sealed, TypeLevel{}};
for (char c : std::string("abcdefghij"))
ttv.props[std::string(1, c)] = {typeChecker.numberType};
TypeVar tv{ttv};
Type tv{ttv};
ToStringOptions o;
o.maxTableLength = 40;
@ -328,8 +353,8 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_table_type_correctly_use_matching_table
TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_union_type_bails_early")
{
TypeVar tv{UnionTypeVar{{typeChecker.stringType, typeChecker.numberType}}};
UnionTypeVar* utv = getMutable<UnionTypeVar>(&tv);
Type tv{UnionType{{typeChecker.stringType, typeChecker.numberType}}};
UnionType* utv = getMutable<UnionType>(&tv);
utv->options.push_back(&tv);
utv->options.push_back(&tv);
@ -338,8 +363,8 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_union_type_bails_early")
TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_intersection_type_bails_early")
{
TypeVar tv{IntersectionTypeVar{}};
IntersectionTypeVar* itv = getMutable<IntersectionTypeVar>(&tv);
Type tv{IntersectionType{}};
IntersectionType* itv = getMutable<IntersectionType>(&tv);
itv->parts.push_back(&tv);
itv->parts.push_back(&tv);
@ -348,17 +373,17 @@ TEST_CASE_FIXTURE(Fixture, "stringifying_cyclic_intersection_type_bails_early")
TEST_CASE_FIXTURE(Fixture, "stringifying_array_uses_array_syntax")
{
TableTypeVar ttv{TableState::Sealed, TypeLevel{}};
TableType ttv{TableState::Sealed, TypeLevel{}};
ttv.indexer = TableIndexer{typeChecker.numberType, typeChecker.stringType};
CHECK_EQ("{string}", toString(TypeVar{ttv}));
CHECK_EQ("{string}", toString(Type{ttv}));
ttv.props["A"] = {typeChecker.numberType};
CHECK_EQ("{| [number]: string, A: number |}", toString(TypeVar{ttv}));
CHECK_EQ("{| [number]: string, A: number |}", toString(Type{ttv}));
ttv.props.clear();
ttv.state = TableState::Unsealed;
CHECK_EQ("{string}", toString(TypeVar{ttv}));
CHECK_EQ("{string}", toString(Type{ttv}));
}
@ -367,7 +392,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_packs_are_stringified_differently_from_gener
TypePackVar tpv{GenericTypePack{"a"}};
CHECK_EQ(toString(&tpv), "a...");
TypeVar tv{GenericTypeVar{"a"}};
Type tv{GenericType{"a"}};
CHECK_EQ(toString(&tv), "a");
}
@ -444,11 +469,11 @@ TEST_CASE_FIXTURE(Fixture, "toStringDetailed")
TypeId id3Type = requireType("id3");
ToStringResult nameData = toStringDetailed(id3Type, opts);
REQUIRE(3 == opts.nameMap.typeVars.size());
REQUIRE(3 == opts.nameMap.types.size());
REQUIRE_EQ("<a, b, c>(a, b, c) -> (a, b, c)", nameData.name);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(id3Type));
const FunctionType* ftv = get<FunctionType>(follow(id3Type));
REQUIRE(ftv != nullptr);
auto params = flatten(ftv->argTypes).first;
@ -483,27 +508,27 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "toStringDetailed2")
TypeId tType = requireType("inst");
ToStringResult r = toStringDetailed(tType, opts);
CHECK_EQ("{ @metatable { __index: { @metatable {| __index: base |}, child } }, inst }", r.name);
CHECK(0 == opts.nameMap.typeVars.size());
CHECK(0 == opts.nameMap.types.size());
const MetatableTypeVar* tMeta = get<MetatableTypeVar>(tType);
const MetatableType* tMeta = get<MetatableType>(tType);
REQUIRE(tMeta);
TableTypeVar* tMeta2 = getMutable<TableTypeVar>(tMeta->metatable);
TableType* tMeta2 = getMutable<TableType>(tMeta->metatable);
REQUIRE(tMeta2);
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);
TableTypeVar* tMeta4 = getMutable<TableTypeVar>(tMeta3->metatable);
TableType* tMeta4 = getMutable<TableType>(tMeta3->metatable);
REQUIRE(tMeta4);
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->props.count("one") > 0);
TableTypeVar* tMeta6 = getMutable<TableTypeVar>(tMeta3->table);
TableType* tMeta6 = getMutable<TableType>(tMeta3->table);
REQUIRE(tMeta6);
REQUIRE(tMeta6->props.count("two") > 0);
@ -537,16 +562,16 @@ function foo(a, b) return a(b) end
TEST_CASE_FIXTURE(Fixture, "toString_the_boundTo_table_type_contained_within_a_TypePack")
{
TypeVar tv1{TableTypeVar{}};
TableTypeVar* ttv = getMutable<TableTypeVar>(&tv1);
Type tv1{TableType{}};
TableType* ttv = getMutable<TableType>(&tv1);
ttv->state = TableState::Sealed;
ttv->props["hello"] = {typeChecker.numberType};
ttv->props["world"] = {typeChecker.numberType};
TypePackVar tpv1{TypePack{{&tv1}}};
TypeVar tv2{TableTypeVar{}};
TableTypeVar* bttv = getMutable<TableTypeVar>(&tv2);
Type tv2{TableType{}};
TableType* bttv = getMutable<TableType>(&tv2);
bttv->state = TableState::Free;
bttv->props["hello"] = {typeChecker.numberType};
bttv->boundTo = &tv1;
@ -560,12 +585,12 @@ TEST_CASE_FIXTURE(Fixture, "toString_the_boundTo_table_type_contained_within_a_T
TEST_CASE_FIXTURE(Fixture, "no_parentheses_around_return_type_if_pack_has_an_empty_head_link")
{
TypeArena arena;
TypePackId realTail = arena.addTypePack({singletonTypes->stringType});
TypePackId realTail = arena.addTypePack({builtinTypes->stringType});
TypePackId emptyTail = arena.addTypePack({}, realTail);
TypePackId argList = arena.addTypePack({singletonTypes->stringType});
TypePackId argList = arena.addTypePack({builtinTypes->stringType});
TypeId functionType = arena.addType(FunctionTypeVar{argList, emptyTail});
TypeId functionType = arena.addType(FunctionType{argList, emptyTail});
CHECK("(string) -> string" == toString(functionType));
}
@ -597,8 +622,8 @@ TEST_CASE_FIXTURE(Fixture, "no_parentheses_around_cyclic_function_type_in_inters
TEST_CASE_FIXTURE(Fixture, "self_recursive_instantiated_param")
{
TypeVar tableTy{TableTypeVar{}};
TableTypeVar* ttv = getMutable<TableTypeVar>(&tableTy);
Type tableTy{TableType{}};
TableType* ttv = getMutable<TableType>(&tableTy);
ttv->name = "Table";
ttv->instantiatedTypeParams.push_back(&tableTy);
@ -612,7 +637,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_id")
)");
TypeId ty = requireType("id");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
const FunctionType* ftv = get<FunctionType>(follow(ty));
CHECK_EQ("id<a>(x: a): a", toStringNamedFunction("id", *ftv));
}
@ -630,7 +655,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_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));
}
@ -646,7 +671,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_generic_pack")
)");
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));
}
@ -654,7 +679,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_generic_pack")
TEST_CASE("toStringNamedFunction_unit_f")
{
TypePackVar empty{TypePack{}};
FunctionTypeVar ftv{&empty, &empty, {}, false};
FunctionType ftv{&empty, &empty, {}, false};
CHECK_EQ("f(): ()", toStringNamedFunction("f", ftv));
}
@ -667,7 +692,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics")
)");
TypeId ty = requireType("f");
auto ftv = get<FunctionTypeVar>(follow(ty));
auto ftv = get<FunctionType>(follow(ty));
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");
auto ftv = get<FunctionTypeVar>(follow(ty));
auto ftv = get<FunctionType>(follow(ty));
CHECK_EQ("f(): ...number", toStringNamedFunction("f", *ftv));
}
@ -695,7 +720,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_variadics3")
)");
TypeId ty = requireType("f");
auto ftv = get<FunctionTypeVar>(follow(ty));
auto ftv = get<FunctionType>(follow(ty));
CHECK_EQ("f(): (string, ...number)", toStringNamedFunction("f", *ftv));
}
@ -707,7 +732,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_type_annotation_has_partial_ar
)");
TypeId ty = requireType("f");
auto ftv = get<FunctionTypeVar>(follow(ty));
auto ftv = get<FunctionType>(follow(ty));
CHECK_EQ("f(_: number, y: number): number", toStringNamedFunction("f", *ftv));
}
@ -720,7 +745,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_hide_type_params")
)");
TypeId ty = requireType("f");
auto ftv = get<FunctionTypeVar>(follow(ty));
auto ftv = get<FunctionType>(follow(ty));
ToStringOptions opts;
opts.hideNamedFunctionTypeParameters = true;
@ -734,7 +759,7 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_overrides_param_names")
)");
TypeId ty = requireType("test");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(ty));
const FunctionType* ftv = get<FunctionType>(follow(ty));
ToStringOptions opts;
opts.namedFunctionOverrideArgNames = {"first", "second", "third"};
@ -763,8 +788,8 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_include_self_param")
)");
TypeId parentTy = requireType("foo");
auto ttv = get<TableTypeVar>(follow(parentTy));
auto ftv = get<FunctionTypeVar>(ttv->props.at("method").type);
auto ttv = get<TableType>(follow(parentTy));
auto ftv = get<FunctionType>(ttv->props.at("method").type);
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");
auto ttv = get<TableTypeVar>(follow(parentTy));
auto ftv = get<FunctionTypeVar>(ttv->props.at("method").type);
auto ttv = get<TableType>(follow(parentTy));
auto ftv = get<FunctionType>(ttv->props.at("method").type);
ToStringOptions opts;
opts.hideFunctionSelfArgument = true;

View file

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

View file

@ -78,8 +78,8 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias")
Location{{1, 21}, {1, 26}},
getMainSourceModule()->name,
TypeMismatch{
singletonTypes->numberType,
singletonTypes->stringType,
builtinTypes->numberType,
builtinTypes->stringType,
},
});
}
@ -89,8 +89,8 @@ TEST_CASE_FIXTURE(Fixture, "cannot_steal_hoisted_type_alias")
Location{{1, 8}, {1, 26}},
getMainSourceModule()->name,
TypeMismatch{
singletonTypes->numberType,
singletonTypes->stringType,
builtinTypes->numberType,
builtinTypes->stringType,
},
});
}
@ -512,13 +512,13 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "general_require_multi_assign")
std::optional<TypeId> aTypeId = lookupName(m->getModuleScope(), "a");
REQUIRE(aTypeId);
const Luau::TableTypeVar* aType = get<TableTypeVar>(follow(*aTypeId));
const Luau::TableType* aType = get<TableType>(follow(*aTypeId));
REQUIRE(aType);
REQUIRE(aType->props.size() == 2);
std::optional<TypeId> bTypeId = lookupName(m->getModuleScope(), "b");
REQUIRE(bTypeId);
const Luau::TableTypeVar* bType = get<TableTypeVar>(follow(*bTypeId));
const Luau::TableType* bType = get<TableType>(follow(*bTypeId));
REQUIRE(bType);
REQUIRE(bType->props.size() == 3);
}
@ -535,7 +535,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_alias_import_mutation")
else
CHECK(toString(ty) == "table");
const TableTypeVar* ttv = get<TableTypeVar>(ty);
const TableType* ttv = get<TableType>(ty);
REQUIRE(ttv);
CHECK(ttv->instantiatedTypeParams.empty());
@ -554,7 +554,7 @@ type NotCool<x> = Cool
REQUIRE(ty);
CHECK_EQ(toString(*ty), "Cool");
const TableTypeVar* ttv = get<TableTypeVar>(*ty);
const TableType* ttv = get<TableType>(*ty);
REQUIRE(ttv);
CHECK(ttv->instantiatedTypeParams.empty());
@ -590,7 +590,7 @@ type Cool = typeof(c)
std::optional<TypeId> ty = requireType("c");
REQUIRE(ty);
const TableTypeVar* ttv = get<TableTypeVar>(*ty);
const TableType* ttv = get<TableType>(*ty);
REQUIRE(ttv);
CHECK_EQ(ttv->name, "Cool");
}
@ -801,9 +801,9 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "do_not_quantify_unresolved_aliases")
}
/*
* We keep a cache of type alias onto TypeVar to prevent infinite types from
* We keep a cache of type alias onto Type to prevent infinite types from
* being constructed via recursive or corecursive aliases. We have to adjust
* the TypeLevels of those generic TypeVars so that the unifier doesn't think
* the TypeLevels of those generic Types so that the unifier doesn't think
* they have improperly leaked out of their scope.
*/
TEST_CASE_FIXTURE(Fixture, "generic_typevars_are_not_considered_to_escape_their_scope_if_they_are_reused_in_multiple_aliases")
@ -817,7 +817,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_typevars_are_not_considered_to_escape_their_
}
/*
* The two-pass alias definition system starts by ascribing a free TypeVar to each alias. It then
* The two-pass alias definition system starts by ascribing a free Type to each alias. It then
* circles back to fill in the actual type later on.
*
* If this free type is unified with something degenerate like `any`, we need to take extra care
@ -913,11 +913,11 @@ TEST_CASE_FIXTURE(Fixture, "report_shadowed_aliases")
std::optional<TypeId> t1 = lookupType("MyString");
REQUIRE(t1);
CHECK(isPrim(*t1, PrimitiveTypeVar::String));
CHECK(isPrim(*t1, PrimitiveType::String));
std::optional<TypeId> t2 = lookupType("string");
REQUIRE(t2);
CHECK(isPrim(*t2, PrimitiveTypeVar::String));
CHECK(isPrim(*t2, PrimitiveType::String));
}
TEST_CASE_FIXTURE(Fixture, "it_is_ok_to_shadow_user_defined_alias")

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
#include "Luau/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "Fixture.h"
@ -77,7 +77,7 @@ TEST_CASE_FIXTURE(Fixture, "function_return_annotations_are_checked")
LUAU_REQUIRE_NO_ERRORS(result);
TypeId fiftyType = requireType("fifty");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(fiftyType);
const FunctionType* ftv = get<FunctionType>(fiftyType);
REQUIRE(ftv != nullptr);
TypePackId retPack = follow(ftv->retTypes);
@ -182,8 +182,8 @@ TEST_CASE_FIXTURE(Fixture, "table_annotation")
)");
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(PrimitiveTypeVar::Number, getPrimitiveType(follow(requireType("y"))));
CHECK_EQ(PrimitiveTypeVar::String, getPrimitiveType(follow(requireType("z"))));
CHECK_EQ(PrimitiveType::Number, getPrimitiveType(follow(requireType("y"))));
CHECK_EQ(PrimitiveType::String, getPrimitiveType(follow(requireType("z"))));
}
TEST_CASE_FIXTURE(Fixture, "function_annotation")
@ -196,7 +196,7 @@ TEST_CASE_FIXTURE(Fixture, "function_annotation")
dumpErrors(result);
TypeId fType = requireType("f");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(fType));
const FunctionType* ftv = get<FunctionType>(follow(fType));
REQUIRE(ftv != nullptr);
}
@ -208,7 +208,7 @@ TEST_CASE_FIXTURE(Fixture, "function_annotation_with_a_defined_function")
)");
TypeId fType = requireType("f");
const FunctionTypeVar* ftv = get<FunctionTypeVar>(follow(fType));
const FunctionType* ftv = get<FunctionType>(follow(fType));
REQUIRE(ftv != nullptr);
LUAU_REQUIRE_NO_ERRORS(result);
@ -323,13 +323,13 @@ TEST_CASE_FIXTURE(Fixture, "self_referential_type_alias")
REQUIRE(res);
TypeId oType = follow(res->type);
const TableTypeVar* oTable = get<TableTypeVar>(oType);
const TableType* oTable = get<TableType>(oType);
REQUIRE(oTable);
std::optional<Property> incr = get(oTable->props, "incr");
REQUIRE(incr);
const FunctionTypeVar* incrFunc = get<FunctionTypeVar>(incr->type);
const FunctionType* incrFunc = get<FunctionType>(incr->type);
REQUIRE(incrFunc);
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");
const AnyTypeVar* ftv = get<AnyTypeVar>(follow(fType));
const AnyType* ftv = get<AnyType>(follow(fType));
REQUIRE(ftv != nullptr);
REQUIRE(!result.errors.empty());
}
@ -483,7 +483,7 @@ TEST_CASE_FIXTURE(Fixture, "interface_types_belong_to_interface_arena")
std::optional<TypeId> exportsType = first(mod.getModuleScope()->returnType);
REQUIRE(exportsType);
TableTypeVar* exportsTable = getMutable<TableTypeVar>(*exportsType);
TableType* exportsTable = getMutable<TableType>(*exportsType);
REQUIRE(exportsTable != nullptr);
TypeId n = exportsTable->props["n"].type;
@ -509,7 +509,7 @@ TEST_CASE_FIXTURE(Fixture, "generic_aliases_are_cloned_properly")
REQUIRE_EQ(1, array.typeParams.size());
const TableTypeVar* arrayTable = get<TableTypeVar>(array.type);
const TableType* arrayTable = get<TableType>(array.type);
REQUIRE(arrayTable != nullptr);
CHECK_EQ(0, arrayTable->props.size());
@ -538,7 +538,7 @@ TEST_CASE_FIXTURE(Fixture, "cloned_interface_maintains_pointers_between_definiti
std::optional<TypeId> exportsType = first(mod.getModuleScope()->returnType);
REQUIRE(exportsType);
TableTypeVar* exportsTable = getMutable<TableTypeVar>(*exportsType);
TableType* exportsTable = getMutable<TableType>(*exportsType);
REQUIRE(exportsTable != nullptr);
TypeId aType = exportsTable->props["a"].type;
@ -740,8 +740,8 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_type_fun_should_not_trip_rbxassert")
}
#if 0
// This is because, after visiting all nodes in a block, we check if each type alias still points to a FreeTypeVar.
// Doing it that way is wrong, but I also tried to make typeof(x) return a BoundTypeVar, with no luck.
// This is because, after visiting all nodes in a block, we check if each type alias still points to a FreeType.
// Doing it that way is wrong, but I also tried to make typeof(x) return a BoundType, with no luck.
// Not important enough to fix today.
TEST_CASE_FIXTURE(Fixture, "pulling_a_type_from_value_dont_falsely_create_occurs_check_failed")
{
@ -755,7 +755,7 @@ TEST_CASE_FIXTURE(Fixture, "pulling_a_type_from_value_dont_falsely_create_occurs
}
#endif
TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_union_typevar")
TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_union_type")
{
CheckResult result = check(R"(
type T = T | T
@ -767,7 +767,7 @@ TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_union_typevar")
REQUIRE(ocf);
}
TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_intersection_typevar")
TEST_CASE_FIXTURE(Fixture, "occurs_check_on_cyclic_intersection_type")
{
CheckResult result = check(R"(
type T = T & T

View file

@ -4,8 +4,8 @@
#include "Luau/BuiltinDefinitions.h"
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/VisitTypeVar.h"
#include "Luau/Type.h"
#include "Luau/VisitType.h"
#include "Fixture.h"
@ -175,7 +175,7 @@ TEST_CASE_FIXTURE(Fixture, "can_get_length_of_any")
LUAU_REQUIRE_NO_ERRORS(result);
CHECK_EQ(PrimitiveTypeVar::Number, getPrimitiveType(requireType("bar")));
CHECK_EQ(PrimitiveType::Number, getPrimitiveType(requireType("bar")));
}
TEST_CASE_FIXTURE(Fixture, "assign_prop_to_table_by_calling_any_yields_any")
@ -191,7 +191,7 @@ TEST_CASE_FIXTURE(Fixture, "assign_prop_to_table_by_calling_any_yields_any")
LUAU_REQUIRE_NO_ERRORS(result);
TableTypeVar* ttv = getMutable<TableTypeVar>(requireType("T"));
TableType* ttv = getMutable<TableType>(requireType("T"));
REQUIRE(ttv);
REQUIRE(ttv->props.count("prop"));

View file

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

View file

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

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
#include "Luau/BuiltinDefinitions.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "Fixture.h"
@ -294,7 +294,7 @@ TEST_CASE_FIXTURE(Fixture, "definitions_documentation_symbols")
REQUIRE(bool(barTy));
CHECK_EQ(barTy->type->documentationSymbol, "@test/globaltype/Bar");
ClassTypeVar* barClass = getMutable<ClassTypeVar>(barTy->type);
ClassType* barClass = getMutable<ClassType>(barTy->type);
REQUIRE(bool(barClass));
REQUIRE_EQ(barClass->props.count("prop"), 1);
CHECK_EQ(barClass->props["prop"].documentationSymbol, "@test/globaltype/Bar.prop");
@ -303,7 +303,7 @@ TEST_CASE_FIXTURE(Fixture, "definitions_documentation_symbols")
REQUIRE(bool(yBinding));
CHECK_EQ(yBinding->documentationSymbol, "@test/global/y");
TableTypeVar* yTtv = getMutable<TableTypeVar>(yBinding->typeId);
TableType* yTtv = getMutable<TableType>(yBinding->typeId);
REQUIRE(bool(yTtv));
REQUIRE_EQ(yTtv->props.count("x"), 1);
CHECK_EQ(yTtv->props["x"].documentationSymbol, "@test/global/y.x");

View file

@ -5,8 +5,8 @@
#include "Luau/Error.h"
#include "Luau/Scope.h"
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/VisitTypeVar.h"
#include "Luau/Type.h"
#include "Luau/VisitType.h"
#include "Fixture.h"
@ -23,7 +23,7 @@ TEST_CASE_FIXTURE(Fixture, "tc_function")
CheckResult result = check("function five() return 5 end");
LUAU_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* fiveType = get<FunctionTypeVar>(requireType("five"));
const FunctionType* fiveType = get<FunctionType>(requireType("five"));
REQUIRE(fiveType != nullptr);
}
@ -64,7 +64,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_return_type")
CheckResult result = check("function take_five() return 5 end");
LUAU_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* takeFiveType = get<FunctionTypeVar>(requireType("take_five"));
const FunctionType* takeFiveType = get<FunctionType>(requireType("take_five"));
REQUIRE(takeFiveType != nullptr);
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);
REQUIRE(r);
TableTypeVar* ttv = getMutable<TableTypeVar>(*r);
TableType* ttv = getMutable<TableType>(*r);
REQUIRE(ttv);
REQUIRE(ttv->props.count("f"));
@ -389,14 +389,14 @@ TEST_CASE_FIXTURE(Fixture, "local_function")
TypeId h = follow(requireType("h"));
const FunctionTypeVar* ftv = get<FunctionTypeVar>(h);
const FunctionType* ftv = get<FunctionType>(h);
REQUIRE(ftv != nullptr);
std::optional<TypeId> rt = first(ftv->retTypes);
REQUIRE(bool(rt));
TypeId retType = follow(*rt);
CHECK_EQ(PrimitiveTypeVar::String, getPrimitiveType(retType));
CHECK_EQ(PrimitiveType::String, getPrimitiveType(retType));
}
TEST_CASE_FIXTURE(Fixture, "func_expr_doesnt_leak_free")
@ -406,11 +406,11 @@ TEST_CASE_FIXTURE(Fixture, "func_expr_doesnt_leak_free")
)");
LUAU_REQUIRE_NO_ERRORS(result);
const Luau::FunctionTypeVar* fn = get<FunctionTypeVar>(requireType("p"));
const Luau::FunctionType* fn = get<FunctionType>(requireType("p"));
REQUIRE(fn);
auto ret = first(fn->retTypes);
REQUIRE(ret);
REQUIRE(get<GenericTypeVar>(follow(*ret)));
REQUIRE(get<GenericType>(follow(*ret)));
}
TEST_CASE_FIXTURE(Fixture, "first_argument_can_be_optional")
@ -506,12 +506,12 @@ TEST_CASE_FIXTURE(Fixture, "complicated_return_types_require_an_explicit_annotat
LUAU_REQUIRE_NO_ERRORS(result);
TypeId ty = requireType("most_of_the_natural_numbers");
const FunctionTypeVar* functionType = get<FunctionTypeVar>(ty);
const FunctionType* functionType = get<FunctionType>(ty);
REQUIRE_MESSAGE(functionType, "Expected function but got " << toString(ty));
std::optional<TypeId> retType = first(functionType->retTypes);
REQUIRE(retType);
CHECK(get<UnionTypeVar>(*retType));
CHECK(get<UnionType>(*retType));
}
TEST_CASE_FIXTURE(Fixture, "infer_higher_order_function")
@ -524,14 +524,14 @@ TEST_CASE_FIXTURE(Fixture, "infer_higher_order_function")
LUAU_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(requireType("apply"));
const FunctionType* ftv = get<FunctionType>(requireType("apply"));
REQUIRE(ftv != nullptr);
std::vector<TypeId> argVec = flatten(ftv->argTypes).first;
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]));
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);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(requireType("bottomupmerge"));
const FunctionType* ftv = get<FunctionType>(requireType("bottomupmerge"));
REQUIRE(ftv != nullptr);
std::vector<TypeId> argVec = flatten(ftv->argTypes).first;
REQUIRE_EQ(6, argVec.size());
const FunctionTypeVar* fType = get<FunctionTypeVar>(follow(argVec[0]));
const FunctionType* fType = get<FunctionType>(follow(argVec[0]));
REQUIRE(fType != nullptr);
}
@ -591,14 +591,14 @@ TEST_CASE_FIXTURE(Fixture, "higher_order_function_3")
LUAU_REQUIRE_NO_ERRORS(result);
const FunctionTypeVar* ftv = get<FunctionTypeVar>(requireType("swapTwice"));
const FunctionType* ftv = get<FunctionType>(requireType("swapTwice"));
REQUIRE(ftv != nullptr);
std::vector<TypeId> argVec = flatten(ftv->argTypes).first;
REQUIRE_EQ(1, argVec.size());
const TableTypeVar* argType = get<TableTypeVar>(follow(argVec[0]));
const TableType* argType = get<TableType>(follow(argVec[0]));
REQUIRE(argType != nullptr);
CHECK(bool(argType->indexer));
@ -648,18 +648,18 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "higher_order_function_4")
* In other words, comp(arr[x], arr[y]) is well-typed.
*/
const FunctionTypeVar* ftv = get<FunctionTypeVar>(requireType("mergesort"));
const FunctionType* ftv = get<FunctionType>(requireType("mergesort"));
REQUIRE(ftv != nullptr);
std::vector<TypeId> argVec = flatten(ftv->argTypes).first;
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(bool(arg0->indexer));
const FunctionTypeVar* arg1 = get<FunctionTypeVar>(follow(argVec[1]));
const FunctionType* arg1 = get<FunctionType>(follow(argVec[1]));
REQUIRE(arg1 != nullptr);
REQUIRE_EQ(2, size(arg1->argTypes));
@ -1003,7 +1003,7 @@ TEST_CASE_FIXTURE(Fixture, "no_lossy_function_type")
LUAU_REQUIRE_NO_ERRORS(result);
TypeId type = requireTypeAtPosition(Position(6, 14));
CHECK_EQ("(tbl, number, number) -> number", toString(type));
auto ftv = get<FunctionTypeVar>(type);
auto ftv = get<FunctionType>(type);
REQUIRE(ftv);
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
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "Luau/Scope.h"
#include <algorithm>
@ -224,7 +224,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_function")
LUAU_REQUIRE_NO_ERRORS(result);
TypeId idType = requireType("id");
const FunctionTypeVar* idFun = get<FunctionTypeVar>(idType);
const FunctionType* idFun = get<FunctionType>(idType);
REQUIRE(idFun);
auto [args, varargs] = flatten(idFun->argTypes);
auto [rets, varrets] = flatten(idFun->retTypes);
@ -247,7 +247,7 @@ TEST_CASE_FIXTURE(Fixture, "infer_generic_local_function")
LUAU_REQUIRE_NO_ERRORS(result);
TypeId idType = requireType("id");
const FunctionTypeVar* idFun = get<FunctionTypeVar>(idType);
const FunctionType* idFun = get<FunctionType>(idType);
REQUIRE(idFun);
auto [args, varargs] = flatten(idFun->argTypes);
auto [rets, varrets] = flatten(idFun->retTypes);
@ -854,14 +854,14 @@ TEST_CASE_FIXTURE(Fixture, "generic_table_method")
LUAU_REQUIRE_NO_ERRORS(result);
TypeId tType = requireType("T");
TableTypeVar* tTable = getMutable<TableTypeVar>(tType);
TableType* tTable = getMutable<TableType>(tType);
REQUIRE(tTable != nullptr);
REQUIRE(tTable->props.count("bar"));
TypeId barType = tTable->props["bar"].type;
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);
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);
dumpErrors(result);
const TableTypeVar* t = get<TableTypeVar>(requireType("T"));
const TableType* t = get<TableType>(requireType("T"));
REQUIRE(t != nullptr);
std::optional<Property> fooProp = get(t->props, "foo");
REQUIRE(bool(fooProp));
const FunctionTypeVar* foo = get<FunctionTypeVar>(follow(fooProp->type));
const FunctionType* foo = get<FunctionType>(follow(fooProp->type));
REQUIRE(bool(foo));
std::optional<TypeId> ret_ = first(foo->retTypes);
REQUIRE(bool(ret_));
TypeId ret = follow(*ret_);
REQUIRE_EQ(getPrimitiveType(ret), PrimitiveTypeVar::Number);
REQUIRE_EQ(getPrimitiveType(ret), PrimitiveType::Number);
}
/*
@ -927,20 +927,20 @@ TEST_CASE_FIXTURE(Fixture, "instantiate_cyclic_generic_function")
)");
TypeId g = requireType("g");
const FunctionTypeVar* gFun = get<FunctionTypeVar>(g);
const FunctionType* gFun = get<FunctionType>(g);
REQUIRE(gFun != nullptr);
auto optionArg = first(gFun->argTypes);
REQUIRE(bool(optionArg));
TypeId arg = follow(*optionArg);
const TableTypeVar* argTable = get<TableTypeVar>(arg);
const TableType* argTable = get<TableType>(arg);
REQUIRE(argTable != nullptr);
std::optional<Property> methodProp = get(argTable->props, "method");
REQUIRE(bool(methodProp));
const FunctionTypeVar* methodFunction = get<FunctionTypeVar>(methodProp->type);
const FunctionType* methodFunction = get<FunctionType>(methodProp->type);
REQUIRE(methodFunction != nullptr);
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
#include "Luau/TypeInfer.h"
#include "Luau/TypeVar.h"
#include "Luau/Type.h"
#include "Fixture.h"
@ -162,14 +162,14 @@ TEST_CASE_FIXTURE(Fixture, "index_on_an_intersection_type_with_property_guarante
LUAU_REQUIRE_NO_ERRORS(result);
const IntersectionTypeVar* r = get<IntersectionTypeVar>(requireType("r"));
const IntersectionType* r = get<IntersectionType>(requireType("r"));
REQUIRE(r);
TableTypeVar* a = getMutable<TableTypeVar>(r->parts[0]);
TableType* a = getMutable<TableType>(r->parts[0]);
REQUIRE(a);
CHECK_EQ(typeChecker.numberType, a->props["y"].type);
TableTypeVar* b = getMutable<TableTypeVar>(r->parts[1]);
TableType* b = getMutable<TableType>(r->parts[1]);
REQUIRE(b);
CHECK_EQ(typeChecker.numberType, b->props["y"].type);
}

View file

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

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