mirror of
https://github.com/luau-lang/luau.git
synced 2024-12-12 13:00:38 +00:00
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:
parent
fb2f146123
commit
75a2e95714
117 changed files with 3813 additions and 2584 deletions
|
@ -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;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "Luau/Substitution.h"
|
||||
#include "Luau/TxnLog.h"
|
||||
#include "Luau/TypeVar.h"
|
||||
#include "Luau/Type.h"
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
|
|
@ -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>;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <Luau/NotNull.h>
|
||||
#include "Luau/TypeArena.h"
|
||||
#include "Luau/TypeVar.h"
|
||||
#include "Luau/Type.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
namespace Luau
|
||||
{
|
||||
|
||||
struct TypeVar;
|
||||
using TypeId = const TypeVar*;
|
||||
struct Type;
|
||||
using TypeId = const Type*;
|
||||
|
||||
struct Negation;
|
||||
struct Conjunction;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Luau/Location.h"
|
||||
#include "Luau/TypeVar.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/Variant.h"
|
||||
|
||||
namespace Luau
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Luau/Substitution.h"
|
||||
#include "Luau/TypeVar.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/Unifiable.h"
|
||||
|
||||
namespace Luau
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
namespace Luau
|
||||
{
|
||||
|
||||
struct TypeVar;
|
||||
using TypeId = const TypeVar*;
|
||||
struct Type;
|
||||
using TypeId = const Type*;
|
||||
|
||||
struct Field;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
namespace Luau
|
||||
{
|
||||
|
||||
struct TypeVar;
|
||||
using TypeId = const TypeVar*;
|
||||
struct Type;
|
||||
using TypeId = const Type*;
|
||||
|
||||
struct TruthyPredicate;
|
||||
struct IsAPredicate;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
namespace Luau
|
||||
{
|
||||
struct TypeVar;
|
||||
using TypeId = const TypeVar*;
|
||||
struct Type;
|
||||
using TypeId = const Type*;
|
||||
|
||||
struct TypePackVar;
|
||||
using TypePackId = const TypePackVar*;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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}
|
||||
{
|
||||
}
|
||||
};
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
@ -5,8 +5,8 @@ namespace Luau
|
|||
{
|
||||
|
||||
Position::Position(unsigned int line, unsigned int column)
|
||||
: line(line)
|
||||
, column(column)
|
||||
: line(line)
|
||||
, column(column)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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};
|
||||
}
|
||||
|
|
|
@ -612,4 +612,3 @@ const Instruction* execute_LOP_BREAK(lua_State* L, const Instruction* pc, StkId
|
|||
LUAU_ASSERT(!"Unsupported deprecated opcode");
|
||||
LUAU_UNREACHABLE();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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}},
|
||||
};
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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, {}});
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"));
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue