mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 06:15:44 +08:00
Sync to upstream/release/634 (#1325)
# What's Changed? - Performance improvement in the old solver - Bugfixes in the new solver ## Old Solver - Mark types that do not need instantiation when being exported to prevent unnecessary work from being done ## New Solver - Refactored instances of "type family" with "type function" - Index-out-of-bounds bug fix in the resolution resolver - Subtyping reasonings are merged only if all failed --- ### Internal Contributors Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Vighnesh <vvijay@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: David Cope <dcope@roblox.com> Co-authored-by: Lily Brown <lbrown@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
This commit is contained in:
parent
6bfc38e61a
commit
b6b74b4425
@ -242,7 +242,7 @@ struct UnpackConstraint
|
||||
|
||||
// ty ~ reduce ty
|
||||
//
|
||||
// Try to reduce ty, if it is a TypeFamilyInstanceType. Otherwise, do nothing.
|
||||
// Try to reduce ty, if it is a TypeFunctionInstanceType. Otherwise, do nothing.
|
||||
struct ReduceConstraint
|
||||
{
|
||||
TypeId ty;
|
||||
|
@ -343,9 +343,9 @@ private:
|
||||
void reportError(Location location, TypeErrorData err);
|
||||
void reportCodeTooComplex(Location location);
|
||||
|
||||
// make a union type family of these two types
|
||||
// make a union type function of these two types
|
||||
TypeId makeUnion(const ScopePtr& scope, Location location, TypeId lhs, TypeId rhs);
|
||||
// make an intersect type family of these two types
|
||||
// make an intersect type function of these two types
|
||||
TypeId makeIntersect(const ScopePtr& scope, Location location, TypeId lhs, TypeId rhs);
|
||||
|
||||
/** Scan the program for global definitions.
|
||||
@ -370,8 +370,8 @@ private:
|
||||
*/
|
||||
std::vector<std::optional<TypeId>> getExpectedCallTypesForFunctionOverloads(const TypeId fnType);
|
||||
|
||||
TypeId createTypeFamilyInstance(
|
||||
const TypeFamily& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments, const ScopePtr& scope, Location location);
|
||||
TypeId createTypeFunctionInstance(
|
||||
const TypeFunction& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments, const ScopePtr& scope, Location location);
|
||||
};
|
||||
|
||||
/** Borrow a vector of pointers from a vector of owning pointers to constraints.
|
||||
|
@ -334,11 +334,11 @@ struct DynamicPropertyLookupOnClassesUnsafe
|
||||
bool operator==(const DynamicPropertyLookupOnClassesUnsafe& rhs) const;
|
||||
};
|
||||
|
||||
struct UninhabitedTypeFamily
|
||||
struct UninhabitedTypeFunction
|
||||
{
|
||||
TypeId ty;
|
||||
|
||||
bool operator==(const UninhabitedTypeFamily& rhs) const;
|
||||
bool operator==(const UninhabitedTypeFunction& rhs) const;
|
||||
};
|
||||
|
||||
struct ExplicitFunctionAnnotationRecommended
|
||||
@ -348,11 +348,11 @@ struct ExplicitFunctionAnnotationRecommended
|
||||
bool operator==(const ExplicitFunctionAnnotationRecommended& rhs) const;
|
||||
};
|
||||
|
||||
struct UninhabitedTypePackFamily
|
||||
struct UninhabitedTypePackFunction
|
||||
{
|
||||
TypePackId tp;
|
||||
|
||||
bool operator==(const UninhabitedTypePackFamily& rhs) const;
|
||||
bool operator==(const UninhabitedTypePackFunction& rhs) const;
|
||||
};
|
||||
|
||||
struct WhereClauseNeeded
|
||||
@ -449,7 +449,7 @@ using TypeErrorData =
|
||||
CodeTooComplex, UnificationTooComplex, UnknownPropButFoundLikeProp, GenericError, InternalError, CannotCallNonFunction, ExtraInformation,
|
||||
DeprecatedApiUsed, ModuleHasCyclicDependency, IllegalRequire, FunctionExitsWithoutReturning, DuplicateGenericParameter, CannotAssignToNever,
|
||||
CannotInferBinaryOperation, MissingProperties, SwappedGenericTypeParameter, OptionalValueAccess, MissingUnionProperty, TypesAreUnrelated,
|
||||
NormalizationTooComplex, TypePackMismatch, DynamicPropertyLookupOnClassesUnsafe, UninhabitedTypeFamily, UninhabitedTypePackFamily,
|
||||
NormalizationTooComplex, TypePackMismatch, DynamicPropertyLookupOnClassesUnsafe, UninhabitedTypeFunction, UninhabitedTypePackFunction,
|
||||
WhereClauseNeeded, PackWhereClauseNeeded, CheckedFunctionCallError, NonStrictFunctionDefinitionError, PropertyAccessViolation,
|
||||
CheckedFunctionIncorrectArgs, UnexpectedTypeInSubtyping, UnexpectedTypePackInSubtyping, ExplicitFunctionAnnotationRecommended>;
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "Luau/Substitution.h"
|
||||
#include "Luau/TypeFwd.h"
|
||||
#include "Luau/Unifiable.h"
|
||||
#include "Luau/VisitType.h"
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
@ -72,6 +73,59 @@ struct Instantiation : Substitution
|
||||
TypePackId clean(TypePackId tp) override;
|
||||
};
|
||||
|
||||
// Used to find if a FunctionType requires generic type cleanup during instantiation
|
||||
struct GenericTypeFinder : TypeOnceVisitor
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
bool visit(TypeId ty) override
|
||||
{
|
||||
return !found;
|
||||
}
|
||||
|
||||
bool visit(TypePackId ty) override
|
||||
{
|
||||
return !found;
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const Luau::FunctionType& ftv) override
|
||||
{
|
||||
if (ftv.hasNoFreeOrGenericTypes)
|
||||
return false;
|
||||
|
||||
if (!ftv.generics.empty() || !ftv.genericPacks.empty())
|
||||
found = true;
|
||||
|
||||
return !found;
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const Luau::TableType& ttv) override
|
||||
{
|
||||
if (ttv.state == Luau::TableState::Generic)
|
||||
found = true;
|
||||
|
||||
return !found;
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const Luau::GenericType&) override
|
||||
{
|
||||
found = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypePackId ty, const Luau::GenericTypePack&) override
|
||||
{
|
||||
found = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const Luau::ClassType&) override
|
||||
{
|
||||
// During function instantiation, classes are not traversed even if they have generics
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/** Attempt to instantiate a type. Only used under local type inference.
|
||||
*
|
||||
* When given a generic function type, instantiate() will return a copy with the
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "Luau/TypeFwd.h"
|
||||
#include "Luau/TypePairHash.h"
|
||||
#include "Luau/TypePath.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/TypeCheckLimits.h"
|
||||
#include "Luau/DenseHash.h"
|
||||
|
||||
@ -114,7 +114,7 @@ struct SubtypingEnvironment
|
||||
DenseHashMap<std::pair<TypeId, TypeId>, SubtypingResult, TypePairHash> ephemeralCache{{}};
|
||||
|
||||
/// Applies `mappedGenerics` to the given type.
|
||||
/// This is used specifically to substitute for generics in type family instances.
|
||||
/// This is used specifically to substitute for generics in type function instances.
|
||||
std::optional<TypeId> applyMappedGenerics(NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, TypeId ty);
|
||||
};
|
||||
|
||||
@ -219,8 +219,8 @@ private:
|
||||
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeIds& subTypes, const TypeIds& superTypes);
|
||||
|
||||
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const VariadicTypePack* subVariadic, const VariadicTypePack* superVariadic);
|
||||
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeFamilyInstanceType* subFamilyInstance, const TypeId superTy);
|
||||
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeId subTy, const TypeFamilyInstanceType* superFamilyInstance);
|
||||
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeFunctionInstanceType* subFamilyInstance, const TypeId superTy);
|
||||
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TypeId subTy, const TypeFunctionInstanceType* superFamilyInstance);
|
||||
|
||||
bool bindGeneric(SubtypingEnvironment& env, TypeId subTp, TypeId superTp);
|
||||
bool bindGeneric(SubtypingEnvironment& env, TypePackId subTp, TypePackId superTp);
|
||||
@ -228,7 +228,7 @@ private:
|
||||
template<typename T, typename Container>
|
||||
TypeId makeAggregateType(const Container& container, TypeId orElse);
|
||||
|
||||
std::pair<TypeId, ErrorVec> handleTypeFamilyReductionResult(const TypeFamilyInstanceType* familyInstance);
|
||||
std::pair<TypeId, ErrorVec> handleTypeFunctionReductionResult(const TypeFunctionInstanceType* familyInstance);
|
||||
|
||||
[[noreturn]] void unexpected(TypeId ty);
|
||||
[[noreturn]] void unexpected(TypePackId tp);
|
||||
|
@ -32,7 +32,7 @@ struct TypeArena;
|
||||
struct Scope;
|
||||
using ScopePtr = std::shared_ptr<Scope>;
|
||||
|
||||
struct TypeFamily;
|
||||
struct TypeFunction;
|
||||
struct Constraint;
|
||||
|
||||
/**
|
||||
@ -528,34 +528,34 @@ struct ClassType
|
||||
};
|
||||
|
||||
/**
|
||||
* An instance of a type family that has not yet been reduced to a more concrete
|
||||
* An instance of a type function that has not yet been reduced to a more concrete
|
||||
* type. The constraint solver receives a constraint to reduce each
|
||||
* TypeFamilyInstanceType to a concrete type. A design detail is important to
|
||||
* note here: the parameters for this instantiation of the type family are
|
||||
* TypeFunctionInstanceType to a concrete type. A design detail is important to
|
||||
* note here: the parameters for this instantiation of the type function are
|
||||
* contained within this type, so that they can be substituted.
|
||||
*/
|
||||
struct TypeFamilyInstanceType
|
||||
struct TypeFunctionInstanceType
|
||||
{
|
||||
NotNull<const TypeFamily> family;
|
||||
NotNull<const TypeFunction> family;
|
||||
|
||||
std::vector<TypeId> typeArguments;
|
||||
std::vector<TypePackId> packArguments;
|
||||
|
||||
TypeFamilyInstanceType(NotNull<const TypeFamily> family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments)
|
||||
TypeFunctionInstanceType(NotNull<const TypeFunction> family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments)
|
||||
: family(family)
|
||||
, typeArguments(typeArguments)
|
||||
, packArguments(packArguments)
|
||||
{
|
||||
}
|
||||
|
||||
TypeFamilyInstanceType(const TypeFamily& family, std::vector<TypeId> typeArguments)
|
||||
TypeFunctionInstanceType(const TypeFunction& family, std::vector<TypeId> typeArguments)
|
||||
: family{&family}
|
||||
, typeArguments(typeArguments)
|
||||
, packArguments{}
|
||||
{
|
||||
}
|
||||
|
||||
TypeFamilyInstanceType(const TypeFamily& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments)
|
||||
TypeFunctionInstanceType(const TypeFunction& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments)
|
||||
: family{&family}
|
||||
, typeArguments(typeArguments)
|
||||
, packArguments(packArguments)
|
||||
@ -659,7 +659,7 @@ using ErrorType = Unifiable::Error;
|
||||
|
||||
using TypeVariant =
|
||||
Unifiable::Variant<TypeId, FreeType, GenericType, PrimitiveType, SingletonType, BlockedType, PendingExpansionType, FunctionType, TableType,
|
||||
MetatableType, ClassType, AnyType, UnionType, IntersectionType, LazyType, UnknownType, NeverType, NegationType, TypeFamilyInstanceType>;
|
||||
MetatableType, ClassType, AnyType, UnionType, IntersectionType, LazyType, UnknownType, NeverType, NegationType, TypeFunctionInstanceType>;
|
||||
|
||||
struct Type final
|
||||
{
|
||||
|
@ -49,10 +49,10 @@ struct TypeArena
|
||||
return addTypePack(TypePackVar(std::move(tp)));
|
||||
}
|
||||
|
||||
TypeId addTypeFamily(const TypeFamily& family, std::initializer_list<TypeId> types);
|
||||
TypeId addTypeFamily(const TypeFamily& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments = {});
|
||||
TypePackId addTypePackFamily(const TypePackFamily& family, std::initializer_list<TypeId> types);
|
||||
TypePackId addTypePackFamily(const TypePackFamily& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments = {});
|
||||
TypeId addTypeFunction(const TypeFunction& family, std::initializer_list<TypeId> types);
|
||||
TypeId addTypeFunction(const TypeFunction& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments = {});
|
||||
TypePackId addTypePackFunction(const TypePackFunction& family, std::initializer_list<TypeId> types);
|
||||
TypePackId addTypePackFunction(const TypePackFunction& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments = {});
|
||||
};
|
||||
|
||||
void freeze(TypeArena& arena);
|
||||
|
@ -1,85 +0,0 @@
|
||||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Luau/Ast.h"
|
||||
#include "Luau/VecDeque.h"
|
||||
#include "Luau/DenseHash.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/TypeUtils.h"
|
||||
#include "Luau/Normalize.h"
|
||||
#include "Luau/TypeFwd.h"
|
||||
#include "Luau/VisitType.h"
|
||||
#include "Luau/NotNull.h"
|
||||
#include "TypeArena.h"
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
struct TypeFamilyReductionGuessResult
|
||||
{
|
||||
std::vector<std::pair<std::string, TypeId>> guessedFunctionAnnotations;
|
||||
TypeId guessedReturnType;
|
||||
bool shouldRecommendAnnotation = true;
|
||||
};
|
||||
|
||||
// An Inference result for a type family is a list of types corresponding to the guessed argument types, followed by a type for the result
|
||||
struct TypeFamilyInferenceResult
|
||||
{
|
||||
std::vector<TypeId> operandInference;
|
||||
TypeId familyResultInference;
|
||||
};
|
||||
|
||||
struct TypeFamilyReductionGuesser
|
||||
{
|
||||
// Tracks our hypothesis about what a type family reduces to
|
||||
DenseHashMap<TypeId, TypeId> familyReducesTo{nullptr};
|
||||
// Tracks our constraints on type family operands
|
||||
DenseHashMap<TypeId, TypeId> substitutable{nullptr};
|
||||
// List of instances to try progress
|
||||
VecDeque<TypeId> toInfer;
|
||||
DenseHashSet<TypeId> cyclicInstances{nullptr};
|
||||
|
||||
// Utilities
|
||||
NotNull<TypeArena> arena;
|
||||
NotNull<BuiltinTypes> builtins;
|
||||
NotNull<Normalizer> normalizer;
|
||||
|
||||
TypeFamilyReductionGuesser(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtins, NotNull<Normalizer> normalizer);
|
||||
|
||||
std::optional<TypeId> guess(TypeId typ);
|
||||
std::optional<TypePackId> guess(TypePackId typ);
|
||||
TypeFamilyReductionGuessResult guessTypeFamilyReductionForFunction(const AstExprFunction& expr, const FunctionType* ftv, TypeId retTy);
|
||||
|
||||
private:
|
||||
std::optional<TypeId> guessType(TypeId arg);
|
||||
void dumpGuesses();
|
||||
|
||||
bool isNumericBinopFamily(const TypeFamilyInstanceType& instance);
|
||||
bool isComparisonFamily(const TypeFamilyInstanceType& instance);
|
||||
bool isOrAndFamily(const TypeFamilyInstanceType& instance);
|
||||
bool isNotFamily(const TypeFamilyInstanceType& instance);
|
||||
bool isLenFamily(const TypeFamilyInstanceType& instance);
|
||||
bool isUnaryMinus(const TypeFamilyInstanceType& instance);
|
||||
|
||||
// Operand is assignable if it looks like a cyclic family instance, or a generic type
|
||||
bool operandIsAssignable(TypeId ty);
|
||||
std::optional<TypeId> tryAssignOperandType(TypeId ty);
|
||||
|
||||
std::shared_ptr<const NormalizedType> normalize(TypeId ty);
|
||||
void step();
|
||||
void infer();
|
||||
bool done();
|
||||
|
||||
bool isFunctionGenericsSaturated(const FunctionType& ftv, DenseHashSet<TypeId>& instanceArgs);
|
||||
void inferTypeFamilySubstitutions(TypeId ty, const TypeFamilyInstanceType* instance);
|
||||
TypeFamilyInferenceResult inferNumericBinopFamily(const TypeFamilyInstanceType* instance);
|
||||
TypeFamilyInferenceResult inferComparisonFamily(const TypeFamilyInstanceType* instance);
|
||||
TypeFamilyInferenceResult inferOrAndFamily(const TypeFamilyInstanceType* instance);
|
||||
TypeFamilyInferenceResult inferNotFamily(const TypeFamilyInstanceType* instance);
|
||||
TypeFamilyInferenceResult inferLenFamily(const TypeFamilyInstanceType* instance);
|
||||
TypeFamilyInferenceResult inferUnaryMinusFamily(const TypeFamilyInstanceType* instance);
|
||||
};
|
||||
} // namespace Luau
|
@ -18,7 +18,7 @@ struct TypeArena;
|
||||
struct TxnLog;
|
||||
class Normalizer;
|
||||
|
||||
struct TypeFamilyContext
|
||||
struct TypeFunctionContext
|
||||
{
|
||||
NotNull<TypeArena> arena;
|
||||
NotNull<BuiltinTypes> builtins;
|
||||
@ -27,12 +27,12 @@ struct TypeFamilyContext
|
||||
NotNull<InternalErrorReporter> ice;
|
||||
NotNull<TypeCheckLimits> limits;
|
||||
|
||||
// nullptr if the type family is being reduced outside of the constraint solver.
|
||||
// nullptr if the type function is being reduced outside of the constraint solver.
|
||||
ConstraintSolver* solver;
|
||||
// The constraint being reduced in this run of the reduction
|
||||
const Constraint* constraint;
|
||||
|
||||
TypeFamilyContext(NotNull<ConstraintSolver> cs, NotNull<Scope> scope, NotNull<const Constraint> constraint)
|
||||
TypeFunctionContext(NotNull<ConstraintSolver> cs, NotNull<Scope> scope, NotNull<const Constraint> constraint)
|
||||
: arena(cs->arena)
|
||||
, builtins(cs->builtinTypes)
|
||||
, scope(scope)
|
||||
@ -44,7 +44,7 @@ struct TypeFamilyContext
|
||||
{
|
||||
}
|
||||
|
||||
TypeFamilyContext(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtins, NotNull<Scope> scope, NotNull<Normalizer> normalizer,
|
||||
TypeFunctionContext(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtins, NotNull<Scope> scope, NotNull<Normalizer> normalizer,
|
||||
NotNull<InternalErrorReporter> ice, NotNull<TypeCheckLimits> limits)
|
||||
: arena(arena)
|
||||
, builtins(builtins)
|
||||
@ -64,13 +64,13 @@ struct TypeFamilyContext
|
||||
/// may have concretely failed to reduce the type, or may simply be stuck
|
||||
/// without more information.
|
||||
template<typename Ty>
|
||||
struct TypeFamilyReductionResult
|
||||
struct TypeFunctionReductionResult
|
||||
{
|
||||
/// The result of the reduction, if any. If this is nullopt, the family
|
||||
/// The result of the reduction, if any. If this is nullopt, the type function
|
||||
/// could not be reduced.
|
||||
std::optional<Ty> result;
|
||||
/// Whether the result is uninhabited: whether we know, unambiguously and
|
||||
/// permanently, whether this type family reduction results in an
|
||||
/// permanently, whether this type function reduction results in an
|
||||
/// uninhabitable type. This will trigger an error to be reported.
|
||||
bool uninhabited;
|
||||
/// Any types that need to be progressed or mutated before the reduction may
|
||||
@ -83,33 +83,33 @@ struct TypeFamilyReductionResult
|
||||
|
||||
template<typename T>
|
||||
using ReducerFunction =
|
||||
std::function<TypeFamilyReductionResult<T>(T, const std::vector<TypeId>&, const std::vector<TypePackId>&, NotNull<TypeFamilyContext>)>;
|
||||
std::function<TypeFunctionReductionResult<T>(T, const std::vector<TypeId>&, const std::vector<TypePackId>&, NotNull<TypeFunctionContext>)>;
|
||||
|
||||
/// Represents a type function that may be applied to map a series of types and
|
||||
/// type packs to a single output type.
|
||||
struct TypeFamily
|
||||
struct TypeFunction
|
||||
{
|
||||
/// The human-readable name of the type family. Used to stringify instance
|
||||
/// The human-readable name of the type function. Used to stringify instance
|
||||
/// types.
|
||||
std::string name;
|
||||
|
||||
/// The reducer function for the type family.
|
||||
/// The reducer function for the type function.
|
||||
ReducerFunction<TypeId> reducer;
|
||||
};
|
||||
|
||||
/// Represents a type function that may be applied to map a series of types and
|
||||
/// type packs to a single output type pack.
|
||||
struct TypePackFamily
|
||||
struct TypePackFunction
|
||||
{
|
||||
/// The human-readable name of the type pack family. Used to stringify
|
||||
/// The human-readable name of the type pack function. Used to stringify
|
||||
/// instance packs.
|
||||
std::string name;
|
||||
|
||||
/// The reducer function for the type pack family.
|
||||
/// The reducer function for the type pack function.
|
||||
ReducerFunction<TypePackId> reducer;
|
||||
};
|
||||
|
||||
struct FamilyGraphReductionResult
|
||||
struct FunctionGraphReductionResult
|
||||
{
|
||||
ErrorVec errors;
|
||||
DenseHashSet<TypeId> blockedTypes{nullptr};
|
||||
@ -119,7 +119,7 @@ struct FamilyGraphReductionResult
|
||||
};
|
||||
|
||||
/**
|
||||
* Attempt to reduce all instances of any type or type pack family in the type
|
||||
* Attempt to reduce all instances of any type or type pack functions in the type
|
||||
* graph provided.
|
||||
*
|
||||
* @param entrypoint the entry point to the type graph.
|
||||
@ -130,10 +130,10 @@ struct FamilyGraphReductionResult
|
||||
* @param normalizer the normalizer to use when normalizing types
|
||||
* @param ice the internal error reporter to use for ICEs
|
||||
*/
|
||||
FamilyGraphReductionResult reduceFamilies(TypeId entrypoint, Location location, TypeFamilyContext, bool force = false);
|
||||
FunctionGraphReductionResult reduceTypeFunctions(TypeId entrypoint, Location location, TypeFunctionContext, bool force = false);
|
||||
|
||||
/**
|
||||
* Attempt to reduce all instances of any type or type pack family in the type
|
||||
* Attempt to reduce all instances of any type or type pack functions in the type
|
||||
* graph provided.
|
||||
*
|
||||
* @param entrypoint the entry point to the type graph.
|
||||
@ -144,47 +144,46 @@ FamilyGraphReductionResult reduceFamilies(TypeId entrypoint, Location location,
|
||||
* @param normalizer the normalizer to use when normalizing types
|
||||
* @param ice the internal error reporter to use for ICEs
|
||||
*/
|
||||
FamilyGraphReductionResult reduceFamilies(TypePackId entrypoint, Location location, TypeFamilyContext, bool force = false);
|
||||
FunctionGraphReductionResult reduceTypeFunctions(TypePackId entrypoint, Location location, TypeFunctionContext, bool force = false);
|
||||
|
||||
struct BuiltinTypeFamilies
|
||||
struct BuiltinTypeFunctions
|
||||
{
|
||||
BuiltinTypeFamilies();
|
||||
BuiltinTypeFunctions();
|
||||
|
||||
TypeFamily notFamily;
|
||||
TypeFamily lenFamily;
|
||||
TypeFamily unmFamily;
|
||||
TypeFunction notFunc;
|
||||
TypeFunction lenFunc;
|
||||
TypeFunction unmFunc;
|
||||
|
||||
TypeFamily addFamily;
|
||||
TypeFamily subFamily;
|
||||
TypeFamily mulFamily;
|
||||
TypeFamily divFamily;
|
||||
TypeFamily idivFamily;
|
||||
TypeFamily powFamily;
|
||||
TypeFamily modFamily;
|
||||
TypeFunction addFunc;
|
||||
TypeFunction subFunc;
|
||||
TypeFunction mulFunc;
|
||||
TypeFunction divFunc;
|
||||
TypeFunction idivFunc;
|
||||
TypeFunction powFunc;
|
||||
TypeFunction modFunc;
|
||||
|
||||
TypeFamily concatFamily;
|
||||
TypeFunction concatFunc;
|
||||
|
||||
TypeFamily andFamily;
|
||||
TypeFamily orFamily;
|
||||
TypeFunction andFunc;
|
||||
TypeFunction orFunc;
|
||||
|
||||
TypeFamily ltFamily;
|
||||
TypeFamily leFamily;
|
||||
TypeFamily eqFamily;
|
||||
TypeFunction ltFunc;
|
||||
TypeFunction leFunc;
|
||||
TypeFunction eqFunc;
|
||||
|
||||
TypeFamily refineFamily;
|
||||
TypeFamily singletonFamily;
|
||||
TypeFamily unionFamily;
|
||||
TypeFamily intersectFamily;
|
||||
TypeFunction refineFunc;
|
||||
TypeFunction singletonFunc;
|
||||
TypeFunction unionFunc;
|
||||
TypeFunction intersectFunc;
|
||||
|
||||
TypeFamily keyofFamily;
|
||||
TypeFamily rawkeyofFamily;
|
||||
|
||||
TypeFamily indexFamily;
|
||||
TypeFamily rawgetFamily;
|
||||
TypeFunction keyofFunc;
|
||||
TypeFunction rawkeyofFunc;
|
||||
TypeFunction indexFunc;
|
||||
TypeFunction rawgetFunc;
|
||||
|
||||
void addToScope(NotNull<TypeArena> arena, NotNull<Scope> scope) const;
|
||||
};
|
||||
|
||||
const BuiltinTypeFamilies& builtinTypeFunctions();
|
||||
const BuiltinTypeFunctions& builtinTypeFunctions();
|
||||
|
||||
} // namespace Luau
|
85
Analysis/include/Luau/TypeFunctionReductionGuesser.h
Normal file
85
Analysis/include/Luau/TypeFunctionReductionGuesser.h
Normal file
@ -0,0 +1,85 @@
|
||||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Luau/Ast.h"
|
||||
#include "Luau/VecDeque.h"
|
||||
#include "Luau/DenseHash.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/TypeUtils.h"
|
||||
#include "Luau/Normalize.h"
|
||||
#include "Luau/TypeFwd.h"
|
||||
#include "Luau/VisitType.h"
|
||||
#include "Luau/NotNull.h"
|
||||
#include "TypeArena.h"
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
struct TypeFunctionReductionGuessResult
|
||||
{
|
||||
std::vector<std::pair<std::string, TypeId>> guessedFunctionAnnotations;
|
||||
TypeId guessedReturnType;
|
||||
bool shouldRecommendAnnotation = true;
|
||||
};
|
||||
|
||||
// An Inference result for a type function is a list of types corresponding to the guessed argument types, followed by a type for the result
|
||||
struct TypeFunctionInferenceResult
|
||||
{
|
||||
std::vector<TypeId> operandInference;
|
||||
TypeId familyResultInference;
|
||||
};
|
||||
|
||||
struct TypeFunctionReductionGuesser
|
||||
{
|
||||
// Tracks our hypothesis about what a type function reduces to
|
||||
DenseHashMap<TypeId, TypeId> familyReducesTo{nullptr};
|
||||
// Tracks our constraints on type function operands
|
||||
DenseHashMap<TypeId, TypeId> substitutable{nullptr};
|
||||
// List of instances to try progress
|
||||
VecDeque<TypeId> toInfer;
|
||||
DenseHashSet<TypeId> cyclicInstances{nullptr};
|
||||
|
||||
// Utilities
|
||||
NotNull<TypeArena> arena;
|
||||
NotNull<BuiltinTypes> builtins;
|
||||
NotNull<Normalizer> normalizer;
|
||||
|
||||
TypeFunctionReductionGuesser(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtins, NotNull<Normalizer> normalizer);
|
||||
|
||||
std::optional<TypeId> guess(TypeId typ);
|
||||
std::optional<TypePackId> guess(TypePackId typ);
|
||||
TypeFunctionReductionGuessResult guessTypeFunctionReductionForFunctionExpr(const AstExprFunction& expr, const FunctionType* ftv, TypeId retTy);
|
||||
|
||||
private:
|
||||
std::optional<TypeId> guessType(TypeId arg);
|
||||
void dumpGuesses();
|
||||
|
||||
bool isNumericBinopFamily(const TypeFunctionInstanceType& instance);
|
||||
bool isComparisonFamily(const TypeFunctionInstanceType& instance);
|
||||
bool isOrAndFamily(const TypeFunctionInstanceType& instance);
|
||||
bool isNotFamily(const TypeFunctionInstanceType& instance);
|
||||
bool isLenFamily(const TypeFunctionInstanceType& instance);
|
||||
bool isUnaryMinus(const TypeFunctionInstanceType& instance);
|
||||
|
||||
// Operand is assignable if it looks like a cyclic family instance, or a generic type
|
||||
bool operandIsAssignable(TypeId ty);
|
||||
std::optional<TypeId> tryAssignOperandType(TypeId ty);
|
||||
|
||||
std::shared_ptr<const NormalizedType> normalize(TypeId ty);
|
||||
void step();
|
||||
void infer();
|
||||
bool done();
|
||||
|
||||
bool isFunctionGenericsSaturated(const FunctionType& ftv, DenseHashSet<TypeId>& instanceArgs);
|
||||
void inferTypeFunctionSubstitutions(TypeId ty, const TypeFunctionInstanceType* instance);
|
||||
TypeFunctionInferenceResult inferNumericBinopFamily(const TypeFunctionInstanceType* instance);
|
||||
TypeFunctionInferenceResult inferComparisonFamily(const TypeFunctionInstanceType* instance);
|
||||
TypeFunctionInferenceResult inferOrAndFamily(const TypeFunctionInstanceType* instance);
|
||||
TypeFunctionInferenceResult inferNotFamily(const TypeFunctionInstanceType* instance);
|
||||
TypeFunctionInferenceResult inferLenFamily(const TypeFunctionInstanceType* instance);
|
||||
TypeFunctionInferenceResult inferUnaryMinusFamily(const TypeFunctionInstanceType* instance);
|
||||
};
|
||||
} // namespace Luau
|
@ -37,7 +37,7 @@ struct LazyType;
|
||||
struct UnknownType;
|
||||
struct NeverType;
|
||||
struct NegationType;
|
||||
struct TypeFamilyInstanceType;
|
||||
struct TypeFunctionInstanceType;
|
||||
|
||||
struct TypePackVar;
|
||||
using TypePackId = const TypePackVar*;
|
||||
@ -47,7 +47,7 @@ struct GenericTypePack;
|
||||
struct TypePack;
|
||||
struct VariadicTypePack;
|
||||
struct BlockedTypePack;
|
||||
struct TypeFamilyInstanceTypePack;
|
||||
struct TypeFunctionInstanceTypePack;
|
||||
|
||||
using Name = std::string;
|
||||
using ModuleName = std::string;
|
||||
|
@ -15,13 +15,13 @@ namespace Luau
|
||||
{
|
||||
|
||||
struct TypeArena;
|
||||
struct TypePackFamily;
|
||||
struct TypePackFunction;
|
||||
struct TxnLog;
|
||||
|
||||
struct TypePack;
|
||||
struct VariadicTypePack;
|
||||
struct BlockedTypePack;
|
||||
struct TypeFamilyInstanceTypePack;
|
||||
struct TypeFunctionInstanceTypePack;
|
||||
|
||||
struct FreeTypePack
|
||||
{
|
||||
@ -55,7 +55,7 @@ using BoundTypePack = Unifiable::Bound<TypePackId>;
|
||||
using ErrorTypePack = Unifiable::Error;
|
||||
|
||||
using TypePackVariant =
|
||||
Unifiable::Variant<TypePackId, FreeTypePack, GenericTypePack, TypePack, VariadicTypePack, BlockedTypePack, TypeFamilyInstanceTypePack>;
|
||||
Unifiable::Variant<TypePackId, FreeTypePack, GenericTypePack, TypePack, VariadicTypePack, BlockedTypePack, TypeFunctionInstanceTypePack>;
|
||||
|
||||
/* A TypePack is a rope-like string of TypeIds. We use this structure to encode
|
||||
* notions like packs of unknown length and packs of any length, as well as more
|
||||
@ -88,11 +88,11 @@ struct BlockedTypePack
|
||||
};
|
||||
|
||||
/**
|
||||
* Analogous to a TypeFamilyInstanceType.
|
||||
* Analogous to a TypeFunctionInstanceType.
|
||||
*/
|
||||
struct TypeFamilyInstanceTypePack
|
||||
struct TypeFunctionInstanceTypePack
|
||||
{
|
||||
NotNull<const TypePackFamily> family;
|
||||
NotNull<const TypePackFunction> family;
|
||||
|
||||
std::vector<TypeId> typeArguments;
|
||||
std::vector<TypePackId> packArguments;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "Luau/RecursionCounter.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Type.h"
|
||||
|
||||
LUAU_FASTINT(LuauVisitRecursionLimit)
|
||||
LUAU_FASTFLAG(LuauBoundLazyTypes2)
|
||||
@ -65,7 +66,7 @@ inline void unsee(DenseHashSet<void*>& seen, const void* tv)
|
||||
} // namespace visit_detail
|
||||
|
||||
// recursion counter is equivalent here, but we'd like a better name to express the intent.
|
||||
using TypeFamilyDepthCounter = RecursionCounter;
|
||||
using TypeFunctionDepthCounter = RecursionCounter;
|
||||
|
||||
template<typename S>
|
||||
struct GenericTypeVisitor
|
||||
@ -75,7 +76,7 @@ struct GenericTypeVisitor
|
||||
Set seen;
|
||||
bool skipBoundTypes = false;
|
||||
int recursionCounter = 0;
|
||||
int typeFamilyDepth = 0;
|
||||
int typeFunctionDepth = 0;
|
||||
|
||||
GenericTypeVisitor() = default;
|
||||
|
||||
@ -164,7 +165,7 @@ struct GenericTypeVisitor
|
||||
{
|
||||
return visit(ty);
|
||||
}
|
||||
virtual bool visit(TypeId ty, const TypeFamilyInstanceType& tfit)
|
||||
virtual bool visit(TypeId ty, const TypeFunctionInstanceType& tfit)
|
||||
{
|
||||
return visit(ty);
|
||||
}
|
||||
@ -201,7 +202,7 @@ struct GenericTypeVisitor
|
||||
{
|
||||
return visit(tp);
|
||||
}
|
||||
virtual bool visit(TypePackId tp, const TypeFamilyInstanceTypePack& tfitp)
|
||||
virtual bool visit(TypePackId tp, const TypeFunctionInstanceTypePack& tfitp)
|
||||
{
|
||||
return visit(tp);
|
||||
}
|
||||
@ -415,9 +416,9 @@ struct GenericTypeVisitor
|
||||
if (visit(ty, *ntv))
|
||||
traverse(ntv->ty);
|
||||
}
|
||||
else if (auto tfit = get<TypeFamilyInstanceType>(ty))
|
||||
else if (auto tfit = get<TypeFunctionInstanceType>(ty))
|
||||
{
|
||||
TypeFamilyDepthCounter tfdc{&typeFamilyDepth};
|
||||
TypeFunctionDepthCounter tfdc{&typeFunctionDepth};
|
||||
|
||||
if (visit(ty, *tfit))
|
||||
{
|
||||
@ -477,9 +478,9 @@ struct GenericTypeVisitor
|
||||
}
|
||||
else if (auto btp = get<BlockedTypePack>(tp))
|
||||
visit(tp, *btp);
|
||||
else if (auto tfitp = get<TypeFamilyInstanceTypePack>(tp))
|
||||
else if (auto tfitp = get<TypeFunctionInstanceTypePack>(tp))
|
||||
{
|
||||
TypeFamilyDepthCounter tfdc{&typeFamilyDepth};
|
||||
TypeFunctionDepthCounter tfdc{&typeFunctionDepth};
|
||||
|
||||
if (visit(tp, *tfitp))
|
||||
{
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "Luau/ConstraintGenerator.h"
|
||||
#include "Luau/NotNull.h"
|
||||
#include "Luau/TypeInfer.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeUtils.h"
|
||||
@ -312,8 +312,8 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
|
||||
{
|
||||
// declare function assert<T>(value: T, errorMessage: string?): intersect<T, ~(false?)>
|
||||
TypeId genericT = arena.addType(GenericType{"T"});
|
||||
TypeId refinedTy = arena.addType(TypeFamilyInstanceType{
|
||||
NotNull{&builtinTypeFunctions().intersectFamily}, {genericT, arena.addType(NegationType{builtinTypes->falsyType})}, {}});
|
||||
TypeId refinedTy = arena.addType(TypeFunctionInstanceType{
|
||||
NotNull{&builtinTypeFunctions().intersectFunc}, {genericT, arena.addType(NegationType{builtinTypes->falsyType})}, {}});
|
||||
|
||||
TypeId assertTy = arena.addType(FunctionType{
|
||||
{genericT}, {}, arena.addTypePack(TypePack{{genericT, builtinTypes->optionalStringType}}), arena.addTypePack(TypePack{{refinedTy}})});
|
||||
|
@ -388,7 +388,7 @@ private:
|
||||
t->ty = shallowClone(t->ty);
|
||||
}
|
||||
|
||||
void cloneChildren(TypeFamilyInstanceType* t)
|
||||
void cloneChildren(TypeFunctionInstanceType* t)
|
||||
{
|
||||
for (TypeId& ty : t->typeArguments)
|
||||
ty = shallowClone(ty);
|
||||
@ -432,7 +432,7 @@ private:
|
||||
t->tail = shallowClone(*t->tail);
|
||||
}
|
||||
|
||||
void cloneChildren(TypeFamilyInstanceTypePack* t)
|
||||
void cloneChildren(TypeFunctionInstanceTypePack* t)
|
||||
{
|
||||
for (TypeId& ty : t->typeArguments)
|
||||
ty = shallowClone(ty);
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "Luau/StringUtils.h"
|
||||
#include "Luau/TableLiteralInference.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/TypeUtils.h"
|
||||
#include "Luau/Unifier2.h"
|
||||
@ -432,7 +432,7 @@ void ConstraintGenerator::computeRefinement(const ScopePtr& scope, Location loca
|
||||
discriminantTy = arena->addType(NegationType{discriminantTy});
|
||||
|
||||
if (eq)
|
||||
discriminantTy = createTypeFamilyInstance(builtinTypeFunctions().singletonFamily, {discriminantTy}, {}, scope, location);
|
||||
discriminantTy = createTypeFunctionInstance(builtinTypeFunctions().singletonFunc, {discriminantTy}, {}, scope, location);
|
||||
|
||||
for (const RefinementKey* key = proposition->key; key; key = key->parent)
|
||||
{
|
||||
@ -544,7 +544,7 @@ void ConstraintGenerator::applyRefinements(const ScopePtr& scope, Location locat
|
||||
{
|
||||
if (mustDeferIntersection(ty) || mustDeferIntersection(dt))
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().refineFamily, {ty, dt}, {}, scope, location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().refineFunc, {ty, dt}, {}, scope, location);
|
||||
|
||||
ty = resultType;
|
||||
}
|
||||
@ -2090,17 +2090,17 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprUnary* unary)
|
||||
{
|
||||
case AstExprUnary::Op::Not:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().notFamily, {operandType}, {}, scope, unary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().notFunc, {operandType}, {}, scope, unary->location);
|
||||
return Inference{resultType, refinementArena.negation(refinement)};
|
||||
}
|
||||
case AstExprUnary::Op::Len:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().lenFamily, {operandType}, {}, scope, unary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().lenFunc, {operandType}, {}, scope, unary->location);
|
||||
return Inference{resultType, refinementArena.negation(refinement)};
|
||||
}
|
||||
case AstExprUnary::Op::Minus:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().unmFamily, {operandType}, {}, scope, unary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().unmFunc, {operandType}, {}, scope, unary->location);
|
||||
return Inference{resultType, refinementArena.negation(refinement)};
|
||||
}
|
||||
default: // msvc can't prove that this is exhaustive.
|
||||
@ -2116,75 +2116,75 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprBinary* binar
|
||||
{
|
||||
case AstExprBinary::Op::Add:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().addFamily, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().addFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Sub:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().subFamily, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().subFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Mul:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().mulFamily, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().mulFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Div:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().divFamily, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().divFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::FloorDiv:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().idivFamily, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().idivFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Pow:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().powFamily, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().powFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Mod:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().modFamily, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().modFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Concat:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().concatFamily, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().concatFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::And:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().andFamily, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().andFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Or:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().orFamily, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().orFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::CompareLt:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().ltFamily, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().ltFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::CompareGe:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().ltFamily,
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().ltFunc,
|
||||
{rightType, leftType}, // lua decided that `__ge(a, b)` is instead just `__lt(b, a)`
|
||||
{}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::CompareLe:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().leFamily, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().leFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::CompareGt:
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(
|
||||
builtinTypeFunctions().leFamily,
|
||||
TypeId resultType = createTypeFunctionInstance(
|
||||
builtinTypeFunctions().leFunc,
|
||||
{rightType, leftType}, // lua decided that `__gt(a, b)` is instead just `__le(b, a)`
|
||||
{}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
@ -2206,7 +2206,7 @@ builtinTypeFunctions().leFamily,
|
||||
else if (rightSubscripted)
|
||||
rightType = makeUnion(scope, binary->location, rightType, builtinTypes->nilType);
|
||||
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().eqFamily, {leftType, rightType}, {}, scope, binary->location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().eqFunc, {leftType, rightType}, {}, scope, binary->location);
|
||||
return Inference{resultType, std::move(refinement)};
|
||||
}
|
||||
case AstExprBinary::Op::Op__Count:
|
||||
@ -3160,14 +3160,14 @@ TypeId ConstraintGenerator::makeUnion(const ScopePtr& scope, Location location,
|
||||
if (get<NeverType>(follow(rhs)))
|
||||
return lhs;
|
||||
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().unionFamily, {lhs, rhs}, {}, scope, location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().unionFunc, {lhs, rhs}, {}, scope, location);
|
||||
|
||||
return resultType;
|
||||
}
|
||||
|
||||
TypeId ConstraintGenerator::makeIntersect(const ScopePtr& scope, Location location, TypeId lhs, TypeId rhs)
|
||||
{
|
||||
TypeId resultType = createTypeFamilyInstance(builtinTypeFunctions().intersectFamily, {lhs, rhs}, {}, scope, location);
|
||||
TypeId resultType = createTypeFunctionInstance(builtinTypeFunctions().intersectFunc, {lhs, rhs}, {}, scope, location);
|
||||
|
||||
return resultType;
|
||||
}
|
||||
@ -3285,7 +3285,7 @@ void ConstraintGenerator::fillInInferredBindings(const ScopePtr& globalScope, As
|
||||
scope->bindings[symbol] = Binding{tys.front(), location};
|
||||
else
|
||||
{
|
||||
TypeId ty = createTypeFamilyInstance(builtinTypeFunctions().unionFamily, std::move(tys), {}, globalScope, location);
|
||||
TypeId ty = createTypeFunctionInstance(builtinTypeFunctions().unionFunc, std::move(tys), {}, globalScope, location);
|
||||
|
||||
scope->bindings[symbol] = Binding{ty, location};
|
||||
}
|
||||
@ -3355,10 +3355,10 @@ std::vector<std::optional<TypeId>> ConstraintGenerator::getExpectedCallTypesForF
|
||||
return expectedTypes;
|
||||
}
|
||||
|
||||
TypeId ConstraintGenerator::createTypeFamilyInstance(
|
||||
const TypeFamily& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments, const ScopePtr& scope, Location location)
|
||||
TypeId ConstraintGenerator::createTypeFunctionInstance(
|
||||
const TypeFunction& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments, const ScopePtr& scope, Location location)
|
||||
{
|
||||
TypeId result = arena->addTypeFamily(family, typeArguments, packArguments);
|
||||
TypeId result = arena->addTypeFunction(family, typeArguments, packArguments);
|
||||
addConstraint(scope, location, ReduceConstraint{result});
|
||||
return result;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "Luau/TimeTrace.h"
|
||||
#include "Luau/ToString.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/TypeFwd.h"
|
||||
#include "Luau/TypeUtils.h"
|
||||
#include "Luau/Unifier2.h"
|
||||
@ -298,7 +298,7 @@ struct InstantiationQueuer : TypeOnceVisitor
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const TypeFamilyInstanceType&) override
|
||||
bool visit(TypeId ty, const TypeFunctionInstanceType&) override
|
||||
{
|
||||
solver->pushConstraint(scope, location, ReduceConstraint{ty});
|
||||
return true;
|
||||
@ -510,10 +510,10 @@ void ConstraintSolver::finalizeTypeFamilies()
|
||||
for (auto [t, constraint] : typeFamiliesToFinalize)
|
||||
{
|
||||
TypeId ty = follow(t);
|
||||
if (get<TypeFamilyInstanceType>(ty))
|
||||
if (get<TypeFunctionInstanceType>(ty))
|
||||
{
|
||||
FamilyGraphReductionResult result =
|
||||
reduceFamilies(t, constraint->location, TypeFamilyContext{NotNull{this}, constraint->scope, NotNull{constraint}}, true);
|
||||
FunctionGraphReductionResult result =
|
||||
reduceTypeFunctions(t, constraint->location, TypeFunctionContext{NotNull{this}, constraint->scope, NotNull{constraint}}, true);
|
||||
|
||||
for (TypeId r : result.reducedTypes)
|
||||
unblock(r, constraint->location);
|
||||
@ -1394,7 +1394,7 @@ bool ConstraintSolver::tryDispatch(const HasPropConstraint& c, NotNull<const Con
|
||||
LUAU_ASSERT(get<BlockedType>(resultType));
|
||||
LUAU_ASSERT(canMutate(resultType, constraint));
|
||||
|
||||
if (isBlocked(subjectType) || get<PendingExpansionType>(subjectType) || get<TypeFamilyInstanceType>(subjectType))
|
||||
if (isBlocked(subjectType) || get<PendingExpansionType>(subjectType) || get<TypeFunctionInstanceType>(subjectType))
|
||||
return block(subjectType, constraint);
|
||||
|
||||
if (const TableType* subjectTable = getTableType(subjectType))
|
||||
@ -1433,6 +1433,12 @@ bool ConstraintSolver::tryDispatchHasIndexer(
|
||||
LUAU_ASSERT(get<BlockedType>(resultType));
|
||||
LUAU_ASSERT(canMutate(resultType, constraint));
|
||||
|
||||
if (get<AnyType>(subjectType))
|
||||
{
|
||||
bind(constraint, resultType, builtinTypes->anyType);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (auto ft = get<FreeType>(subjectType))
|
||||
{
|
||||
if (auto tbl = get<TableType>(follow(ft->upperBound)); tbl && tbl->indexer)
|
||||
@ -1955,8 +1961,8 @@ bool ConstraintSolver::tryDispatch(const UnpackConstraint& c, NotNull<const Cons
|
||||
bool ConstraintSolver::tryDispatch(const ReduceConstraint& c, NotNull<const Constraint> constraint, bool force)
|
||||
{
|
||||
TypeId ty = follow(c.ty);
|
||||
FamilyGraphReductionResult result =
|
||||
reduceFamilies(ty, constraint->location, TypeFamilyContext{NotNull{this}, constraint->scope, constraint}, force);
|
||||
FunctionGraphReductionResult result =
|
||||
reduceTypeFunctions(ty, constraint->location, TypeFunctionContext{NotNull{this}, constraint->scope, constraint}, force);
|
||||
|
||||
for (TypeId r : result.reducedTypes)
|
||||
unblock(r, constraint->location);
|
||||
@ -1967,8 +1973,8 @@ bool ConstraintSolver::tryDispatch(const ReduceConstraint& c, NotNull<const Cons
|
||||
bool reductionFinished = result.blockedTypes.empty() && result.blockedPacks.empty();
|
||||
|
||||
ty = follow(ty);
|
||||
// If we couldn't reduce this type family, stick it in the set!
|
||||
if (get<TypeFamilyInstanceType>(ty))
|
||||
// If we couldn't reduce this type function, stick it in the set!
|
||||
if (get<TypeFunctionInstanceType>(ty))
|
||||
typeFamiliesToFinalize[ty] = constraint;
|
||||
|
||||
if (force || reductionFinished)
|
||||
@ -1976,9 +1982,9 @@ bool ConstraintSolver::tryDispatch(const ReduceConstraint& c, NotNull<const Cons
|
||||
// if we're completely dispatching this constraint, we want to record any uninhabited type families to unblock.
|
||||
for (auto error : result.errors)
|
||||
{
|
||||
if (auto utf = get<UninhabitedTypeFamily>(error))
|
||||
if (auto utf = get<UninhabitedTypeFunction>(error))
|
||||
uninhabitedTypeFamilies.insert(utf->ty);
|
||||
else if (auto utpf = get<UninhabitedTypePackFamily>(error))
|
||||
else if (auto utpf = get<UninhabitedTypePackFunction>(error))
|
||||
uninhabitedTypeFamilies.insert(utpf->tp);
|
||||
}
|
||||
}
|
||||
@ -1998,8 +2004,8 @@ bool ConstraintSolver::tryDispatch(const ReduceConstraint& c, NotNull<const Cons
|
||||
bool ConstraintSolver::tryDispatch(const ReducePackConstraint& c, NotNull<const Constraint> constraint, bool force)
|
||||
{
|
||||
TypePackId tp = follow(c.tp);
|
||||
FamilyGraphReductionResult result =
|
||||
reduceFamilies(tp, constraint->location, TypeFamilyContext{NotNull{this}, constraint->scope, constraint}, force);
|
||||
FunctionGraphReductionResult result =
|
||||
reduceTypeFunctions(tp, constraint->location, TypeFunctionContext{NotNull{this}, constraint->scope, constraint}, force);
|
||||
|
||||
for (TypeId r : result.reducedTypes)
|
||||
unblock(r, constraint->location);
|
||||
@ -2014,9 +2020,9 @@ bool ConstraintSolver::tryDispatch(const ReducePackConstraint& c, NotNull<const
|
||||
// if we're completely dispatching this constraint, we want to record any uninhabited type families to unblock.
|
||||
for (auto error : result.errors)
|
||||
{
|
||||
if (auto utf = get<UninhabitedTypeFamily>(error))
|
||||
if (auto utf = get<UninhabitedTypeFunction>(error))
|
||||
uninhabitedTypeFamilies.insert(utf->ty);
|
||||
else if (auto utpf = get<UninhabitedTypePackFamily>(error))
|
||||
else if (auto utpf = get<UninhabitedTypePackFunction>(error))
|
||||
uninhabitedTypeFamilies.insert(utpf->tp);
|
||||
}
|
||||
}
|
||||
@ -2103,7 +2109,7 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl
|
||||
* it's possible that there are other constraints on the table that will
|
||||
* clarify what we should do.
|
||||
*
|
||||
* We should eventually introduce a type family to talk about iteration.
|
||||
* We should eventually introduce a type function to talk about iteration.
|
||||
*/
|
||||
if (iteratorTable->state == TableState::Free && !force)
|
||||
return block(iteratorTy, constraint);
|
||||
@ -2713,13 +2719,13 @@ void ConstraintSolver::reproduceConstraints(NotNull<Scope> scope, const Location
|
||||
{
|
||||
for (auto [_, newTy] : subst.newTypes)
|
||||
{
|
||||
if (get<TypeFamilyInstanceType>(newTy))
|
||||
if (get<TypeFunctionInstanceType>(newTy))
|
||||
pushConstraint(scope, location, ReduceConstraint{newTy});
|
||||
}
|
||||
|
||||
for (auto [_, newPack] : subst.newPacks)
|
||||
{
|
||||
if (get<TypeFamilyInstanceTypePack>(newPack))
|
||||
if (get<TypeFunctionInstanceTypePack>(newPack))
|
||||
pushConstraint(scope, location, ReducePackConstraint{newPack});
|
||||
}
|
||||
}
|
||||
@ -2728,7 +2734,7 @@ bool ConstraintSolver::isBlocked(TypeId ty)
|
||||
{
|
||||
ty = follow(ty);
|
||||
|
||||
if (auto tfit = get<TypeFamilyInstanceType>(ty))
|
||||
if (auto tfit = get<TypeFunctionInstanceType>(ty))
|
||||
return uninhabitedTypeFamilies.contains(ty) == false;
|
||||
|
||||
return nullptr != get<BlockedType>(ty) || nullptr != get<PendingExpansionType>(ty);
|
||||
@ -2738,7 +2744,7 @@ bool ConstraintSolver::isBlocked(TypePackId tp)
|
||||
{
|
||||
tp = follow(tp);
|
||||
|
||||
if (auto tfitp = get<TypeFamilyInstanceTypePack>(tp))
|
||||
if (auto tfitp = get<TypeFunctionInstanceTypePack>(tp))
|
||||
return uninhabitedTypeFamilies.contains(tp) == false;
|
||||
|
||||
return nullptr != get<BlockedTypePack>(tp);
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "Luau/StringUtils.h"
|
||||
#include "Luau/ToString.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
@ -64,16 +64,16 @@ static std::string wrongNumberOfArgsString(
|
||||
namespace Luau
|
||||
{
|
||||
|
||||
// this list of binary operator type families is used for better stringification of type families errors
|
||||
// this list of binary operator type functions is used for better stringification of type functions errors
|
||||
static const std::unordered_map<std::string, const char*> kBinaryOps{{"add", "+"}, {"sub", "-"}, {"mul", "*"}, {"div", "/"}, {"idiv", "//"},
|
||||
{"pow", "^"}, {"mod", "%"}, {"concat", ".."}, {"and", "and"}, {"or", "or"}, {"lt", "< or >="}, {"le", "<= or >"}, {"eq", "== or ~="}};
|
||||
|
||||
// this list of unary operator type families is used for better stringification of type families errors
|
||||
// this list of unary operator type functions is used for better stringification of type functions errors
|
||||
static const std::unordered_map<std::string, const char*> kUnaryOps{{"unm", "-"}, {"len", "#"}, {"not", "not"}};
|
||||
|
||||
// this list of type families will receive a special error indicating that the user should file a bug on the GitHub repository
|
||||
// putting a type family in this list indicates that it is expected to _always_ reduce
|
||||
static const std::unordered_set<std::string> kUnreachableTypeFamilies{"refine", "singleton", "union", "intersect"};
|
||||
// this list of type functions will receive a special error indicating that the user should file a bug on the GitHub repository
|
||||
// putting a type function in this list indicates that it is expected to _always_ reduce
|
||||
static const std::unordered_set<std::string> kUnreachableTypeFunctions{"refine", "singleton", "union", "intersect"};
|
||||
|
||||
struct ErrorConverter
|
||||
{
|
||||
@ -577,12 +577,12 @@ struct ErrorConverter
|
||||
return "Attempting a dynamic property access on type '" + Luau::toString(e.ty) + "' is unsafe and may cause exceptions at runtime";
|
||||
}
|
||||
|
||||
std::string operator()(const UninhabitedTypeFamily& e) const
|
||||
std::string operator()(const UninhabitedTypeFunction& e) const
|
||||
{
|
||||
auto tfit = get<TypeFamilyInstanceType>(e.ty);
|
||||
LUAU_ASSERT(tfit); // Luau analysis has actually done something wrong if this type is not a type family.
|
||||
auto tfit = get<TypeFunctionInstanceType>(e.ty);
|
||||
LUAU_ASSERT(tfit); // Luau analysis has actually done something wrong if this type is not a type function.
|
||||
if (!tfit)
|
||||
return "Unexpected type " + Luau::toString(e.ty) + " flagged as an uninhabited type family.";
|
||||
return "Unexpected type " + Luau::toString(e.ty) + " flagged as an uninhabited type function.";
|
||||
|
||||
// unary operators
|
||||
if (auto unaryString = kUnaryOps.find(tfit->family->name); unaryString != kUnaryOps.end())
|
||||
@ -658,13 +658,13 @@ struct ErrorConverter
|
||||
if (tfit->typeArguments.size() == 1 && tfit->packArguments.empty())
|
||||
return "Type '" + toString(tfit->typeArguments[0]) + "' does not have keys, so '" + Luau::toString(e.ty) + "' is invalid";
|
||||
else
|
||||
return "Type family instance " + Luau::toString(e.ty) + " is ill-formed, and thus invalid";
|
||||
return "Type function instance " + Luau::toString(e.ty) + " is ill-formed, and thus invalid";
|
||||
}
|
||||
|
||||
if ("index" == tfit->family->name || "rawget" == tfit->family->name)
|
||||
{
|
||||
if (tfit->typeArguments.size() != 2)
|
||||
return "Type family instance " + Luau::toString(e.ty) + " is ill-formed, and thus invalid";
|
||||
return "Type function instance " + Luau::toString(e.ty) + " is ill-formed, and thus invalid";
|
||||
|
||||
if (auto errType = get<ErrorType>(tfit->typeArguments[1])) // Second argument to (index | rawget)<_,_> is not a type
|
||||
return "Second argument to " + tfit->family->name + "<" + Luau::toString(tfit->typeArguments[0]) + ", _> is not a valid index type";
|
||||
@ -673,15 +673,15 @@ struct ErrorConverter
|
||||
"'";
|
||||
}
|
||||
|
||||
if (kUnreachableTypeFamilies.count(tfit->family->name))
|
||||
if (kUnreachableTypeFunctions.count(tfit->family->name))
|
||||
{
|
||||
return "Type family instance " + Luau::toString(e.ty) + " is uninhabited\n" +
|
||||
return "Type function instance " + Luau::toString(e.ty) + " is uninhabited\n" +
|
||||
"This is likely to be a bug, please report it at https://github.com/luau-lang/luau/issues";
|
||||
}
|
||||
|
||||
// Everything should be specialized above to report a more descriptive error that hopefully does not mention "type families" explicitly.
|
||||
// Everything should be specialized above to report a more descriptive error that hopefully does not mention "type functions" explicitly.
|
||||
// If we produce this message, it's an indication that we've missed a specialization and it should be fixed!
|
||||
return "Type family instance " + Luau::toString(e.ty) + " is uninhabited";
|
||||
return "Type function instance " + Luau::toString(e.ty) + " is uninhabited";
|
||||
}
|
||||
|
||||
std::string operator()(const ExplicitFunctionAnnotationRecommended& r) const
|
||||
@ -704,14 +704,14 @@ struct ErrorConverter
|
||||
return "Consider placing the following annotations on the arguments: " + argAnnotations + " or instead annotating the return as " + toReturn;
|
||||
}
|
||||
|
||||
std::string operator()(const UninhabitedTypePackFamily& e) const
|
||||
std::string operator()(const UninhabitedTypePackFunction& e) const
|
||||
{
|
||||
return "Type pack family instance " + Luau::toString(e.tp) + " is uninhabited";
|
||||
}
|
||||
|
||||
std::string operator()(const WhereClauseNeeded& e) const
|
||||
{
|
||||
return "Type family instance " + Luau::toString(e.ty) +
|
||||
return "Type function instance " + Luau::toString(e.ty) +
|
||||
" depends on generic function parameters but does not appear in the function signature; this construct cannot be type-checked at this "
|
||||
"time";
|
||||
}
|
||||
@ -1092,7 +1092,7 @@ bool DynamicPropertyLookupOnClassesUnsafe::operator==(const DynamicPropertyLooku
|
||||
return ty == rhs.ty;
|
||||
}
|
||||
|
||||
bool UninhabitedTypeFamily::operator==(const UninhabitedTypeFamily& rhs) const
|
||||
bool UninhabitedTypeFunction::operator==(const UninhabitedTypeFunction& rhs) const
|
||||
{
|
||||
return ty == rhs.ty;
|
||||
}
|
||||
@ -1103,7 +1103,7 @@ bool ExplicitFunctionAnnotationRecommended::operator==(const ExplicitFunctionAnn
|
||||
return recommendedReturn == rhs.recommendedReturn && recommendedArgs == rhs.recommendedArgs;
|
||||
}
|
||||
|
||||
bool UninhabitedTypePackFamily::operator==(const UninhabitedTypePackFamily& rhs) const
|
||||
bool UninhabitedTypePackFunction::operator==(const UninhabitedTypePackFunction& rhs) const
|
||||
{
|
||||
return tp == rhs.tp;
|
||||
}
|
||||
@ -1316,7 +1316,7 @@ void copyError(T& e, TypeArena& destArena, CloneState& cloneState)
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, DynamicPropertyLookupOnClassesUnsafe>)
|
||||
e.ty = clone(e.ty);
|
||||
else if constexpr (std::is_same_v<T, UninhabitedTypeFamily>)
|
||||
else if constexpr (std::is_same_v<T, UninhabitedTypeFunction>)
|
||||
e.ty = clone(e.ty);
|
||||
else if constexpr (std::is_same_v<T, ExplicitFunctionAnnotationRecommended>)
|
||||
{
|
||||
@ -1324,7 +1324,7 @@ void copyError(T& e, TypeArena& destArena, CloneState& cloneState)
|
||||
for (auto& [_, t] : e.recommendedArgs)
|
||||
t = clone(t);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, UninhabitedTypePackFamily>)
|
||||
else if constexpr (std::is_same_v<T, UninhabitedTypePackFunction>)
|
||||
e.tp = clone(e.tp);
|
||||
else if constexpr (std::is_same_v<T, WhereClauseNeeded>)
|
||||
e.ty = clone(e.ty);
|
||||
|
@ -131,9 +131,10 @@ static ParseResult parseSourceForModule(std::string_view source, Luau::SourceMod
|
||||
|
||||
if (FFlag::LuauStoreCommentsForDefinitionFiles && options.captureComments)
|
||||
{
|
||||
sourceModule.hotcomments = std::move(parseResult.hotcomments);
|
||||
sourceModule.commentLocations = std::move(parseResult.commentLocations);
|
||||
sourceModule.hotcomments = parseResult.hotcomments;
|
||||
sourceModule.commentLocations = parseResult.commentLocations;
|
||||
}
|
||||
|
||||
return parseResult;
|
||||
}
|
||||
|
||||
@ -1236,7 +1237,7 @@ struct InternalTypeFinder : TypeOnceVisitor
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypePackId, const TypeFamilyInstanceTypePack&) override
|
||||
bool visit(TypePackId, const TypeFunctionInstanceTypePack&) override
|
||||
{
|
||||
LUAU_ASSERT(false);
|
||||
return false;
|
||||
|
@ -804,7 +804,7 @@ struct TypeCacher : TypeOnceVisitor
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const TypeFamilyInstanceType& tfit) override
|
||||
bool visit(TypeId ty, const TypeFunctionInstanceType& tfit) override
|
||||
{
|
||||
if (isCached(ty) || isUncacheable(ty))
|
||||
return false;
|
||||
@ -860,7 +860,7 @@ struct TypeCacher : TypeOnceVisitor
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypePackId tp, const TypeFamilyInstanceTypePack&) override
|
||||
bool visit(TypePackId tp, const TypeFunctionInstanceTypePack&) override
|
||||
{
|
||||
markUncacheable(tp);
|
||||
return false;
|
||||
|
@ -193,8 +193,8 @@ static void errorToString(std::ostream& stream, const T& err)
|
||||
stream << "TypePackMismatch { wanted = '" + toString(err.wantedTp) + "', given = '" + toString(err.givenTp) + "' }";
|
||||
else if constexpr (std::is_same_v<T, DynamicPropertyLookupOnClassesUnsafe>)
|
||||
stream << "DynamicPropertyLookupOnClassesUnsafe { " << toString(err.ty) << " }";
|
||||
else if constexpr (std::is_same_v<T, UninhabitedTypeFamily>)
|
||||
stream << "UninhabitedTypeFamily { " << toString(err.ty) << " }";
|
||||
else if constexpr (std::is_same_v<T, UninhabitedTypeFunction>)
|
||||
stream << "UninhabitedTypeFunction { " << toString(err.ty) << " }";
|
||||
else if constexpr (std::is_same_v<T, ExplicitFunctionAnnotationRecommended>)
|
||||
{
|
||||
std::string recArgs = "[";
|
||||
@ -204,8 +204,8 @@ static void errorToString(std::ostream& stream, const T& err)
|
||||
stream << "ExplicitFunctionAnnotationRecommended { recommmendedReturn = '" + toString(err.recommendedReturn) +
|
||||
"', recommmendedArgs = " + recArgs + "}";
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, UninhabitedTypePackFamily>)
|
||||
stream << "UninhabitedTypePackFamily { " << toString(err.tp) << " }";
|
||||
else if constexpr (std::is_same_v<T, UninhabitedTypePackFunction>)
|
||||
stream << "UninhabitedTypePackFunction { " << toString(err.tp) << " }";
|
||||
else if constexpr (std::is_same_v<T, WhereClauseNeeded>)
|
||||
stream << "WhereClauseNeeded { " << toString(err.ty) << " }";
|
||||
else if constexpr (std::is_same_v<T, PackWhereClauseNeeded>)
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution);
|
||||
LUAU_FASTFLAGVARIABLE(LuauSkipEmptyInstantiations, false);
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
@ -115,9 +116,22 @@ struct ClonePublicInterface : Substitution
|
||||
TypeId result = clone(ty);
|
||||
|
||||
if (FunctionType* ftv = getMutable<FunctionType>(result))
|
||||
{
|
||||
if (FFlag::LuauSkipEmptyInstantiations && ftv->generics.empty() && ftv->genericPacks.empty())
|
||||
{
|
||||
GenericTypeFinder marker;
|
||||
marker.traverse(result);
|
||||
|
||||
if (!marker.found)
|
||||
ftv->hasNoFreeOrGenericTypes = true;
|
||||
}
|
||||
|
||||
ftv->level = TypeLevel{0, 0};
|
||||
}
|
||||
else if (TableType* ttv = getMutable<TableType>(result))
|
||||
{
|
||||
ttv->level = TypeLevel{0, 0};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "Luau/Normalize.h"
|
||||
#include "Luau/Error.h"
|
||||
#include "Luau/TypeArena.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/Def.h"
|
||||
#include "Luau/ToString.h"
|
||||
#include "Luau/TypeFwd.h"
|
||||
@ -153,7 +153,7 @@ struct NonStrictTypeChecker
|
||||
Normalizer normalizer;
|
||||
Subtyping subtyping;
|
||||
NotNull<const DataFlowGraph> dfg;
|
||||
DenseHashSet<TypeId> noTypeFamilyErrors{nullptr};
|
||||
DenseHashSet<TypeId> noTypeFunctionErrors{nullptr};
|
||||
std::vector<NotNull<Scope>> stack;
|
||||
DenseHashMap<TypeId, TypeId> cachedNegations{nullptr};
|
||||
|
||||
@ -208,14 +208,14 @@ struct NonStrictTypeChecker
|
||||
|
||||
TypeId checkForFamilyInhabitance(TypeId instance, Location location)
|
||||
{
|
||||
if (noTypeFamilyErrors.find(instance))
|
||||
if (noTypeFunctionErrors.find(instance))
|
||||
return instance;
|
||||
|
||||
ErrorVec errors =
|
||||
reduceFamilies(instance, location, TypeFamilyContext{arena, builtinTypes, stack.back(), NotNull{&normalizer}, ice, limits}, true).errors;
|
||||
reduceTypeFunctions(instance, location, TypeFunctionContext{arena, builtinTypes, stack.back(), NotNull{&normalizer}, ice, limits}, true).errors;
|
||||
|
||||
if (errors.empty())
|
||||
noTypeFamilyErrors.insert(instance);
|
||||
noTypeFunctionErrors.insert(instance);
|
||||
// TODO??
|
||||
// if (!isErrorSuppressing(location, instance))
|
||||
// reportErrors(std::move(errors));
|
||||
|
@ -816,7 +816,7 @@ static bool areNormalizedClasses(const NormalizedClassType& tys)
|
||||
|
||||
static bool isPlainTyvar(TypeId ty)
|
||||
{
|
||||
return (get<FreeType>(ty) || get<GenericType>(ty) || get<BlockedType>(ty) || get<PendingExpansionType>(ty) || get<TypeFamilyInstanceType>(ty));
|
||||
return (get<FreeType>(ty) || get<GenericType>(ty) || get<BlockedType>(ty) || get<PendingExpansionType>(ty) || get<TypeFunctionInstanceType>(ty));
|
||||
}
|
||||
|
||||
static bool isNormalizedTyvar(const NormalizedTyvars& tyvars)
|
||||
@ -883,7 +883,7 @@ static bool isCacheable(TypePackId tp, Set<TypeId>& seen)
|
||||
|
||||
if (auto tail = it.tail())
|
||||
{
|
||||
if (get<FreeTypePack>(*tail) || get<BlockedTypePack>(*tail) || get<TypeFamilyInstanceTypePack>(*tail))
|
||||
if (get<FreeTypePack>(*tail) || get<BlockedTypePack>(*tail) || get<TypeFunctionInstanceTypePack>(*tail))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -901,7 +901,7 @@ static bool isCacheable(TypeId ty, Set<TypeId>& seen)
|
||||
if (get<FreeType>(ty) || get<BlockedType>(ty) || get<PendingExpansionType>(ty))
|
||||
return false;
|
||||
|
||||
if (auto tfi = get<TypeFamilyInstanceType>(ty))
|
||||
if (auto tfi = get<TypeFunctionInstanceType>(ty))
|
||||
{
|
||||
for (TypeId t : tfi->typeArguments)
|
||||
{
|
||||
@ -1795,7 +1795,7 @@ NormalizationResult Normalizer::unionNormalWithTy(NormalizedType& here, TypeId t
|
||||
else if (get<UnknownType>(here.tops))
|
||||
return NormalizationResult::True;
|
||||
else if (get<GenericType>(there) || get<FreeType>(there) || get<BlockedType>(there) || get<PendingExpansionType>(there) ||
|
||||
get<TypeFamilyInstanceType>(there))
|
||||
get<TypeFunctionInstanceType>(there))
|
||||
{
|
||||
if (tyvarIndex(there) <= ignoreSmallerTyvars)
|
||||
return NormalizationResult::True;
|
||||
@ -1872,7 +1872,7 @@ NormalizationResult Normalizer::unionNormalWithTy(NormalizedType& here, TypeId t
|
||||
if (res != NormalizationResult::True)
|
||||
return res;
|
||||
}
|
||||
else if (get<PendingExpansionType>(there) || get<TypeFamilyInstanceType>(there))
|
||||
else if (get<PendingExpansionType>(there) || get<TypeFunctionInstanceType>(there))
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
@ -3080,7 +3080,7 @@ NormalizationResult Normalizer::intersectNormalWithTy(NormalizedType& here, Type
|
||||
return NormalizationResult::True;
|
||||
}
|
||||
else if (get<GenericType>(there) || get<FreeType>(there) || get<BlockedType>(there) || get<PendingExpansionType>(there) ||
|
||||
get<TypeFamilyInstanceType>(there))
|
||||
get<TypeFunctionInstanceType>(there))
|
||||
{
|
||||
NormalizedType thereNorm{builtinTypes};
|
||||
NormalizedType topNorm{builtinTypes};
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "Luau/Subtyping.h"
|
||||
#include "Luau/TxnLog.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/TypeUtils.h"
|
||||
#include "Luau/Unifier2.h"
|
||||
@ -175,14 +175,15 @@ bool OverloadResolver::isLiteral(AstExpr* expr)
|
||||
std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_(
|
||||
TypeId fnTy, const FunctionType* fn, const TypePack* args, AstExpr* fnExpr, const std::vector<AstExpr*>* argExprs)
|
||||
{
|
||||
FamilyGraphReductionResult result =
|
||||
reduceFamilies(fnTy, callLoc, TypeFamilyContext{arena, builtinTypes, scope, normalizer, ice, limits}, /*force=*/true);
|
||||
FunctionGraphReductionResult result =
|
||||
reduceTypeFunctions(fnTy, callLoc, TypeFunctionContext{arena, builtinTypes, scope, normalizer, ice, limits}, /*force=*/true);
|
||||
if (!result.errors.empty())
|
||||
return {OverloadIsNonviable, result.errors};
|
||||
|
||||
ErrorVec argumentErrors;
|
||||
TypePackId typ = arena->addTypePack(*args);
|
||||
|
||||
TypeId prospectiveFunction = arena->addType(FunctionType{arena->addTypePack(*args), builtinTypes->anyTypePack});
|
||||
TypeId prospectiveFunction = arena->addType(FunctionType{typ, builtinTypes->anyTypePack});
|
||||
SubtypingResult sr = subtyping.isSubtype(fnTy, prospectiveFunction);
|
||||
|
||||
if (sr.isSubtype)
|
||||
@ -253,7 +254,14 @@ std::pair<OverloadResolver::Analysis, ErrorVec> OverloadResolver::checkOverload_
|
||||
if (const Luau::TypePath::Index* pathIndexComponent = get_if<Luau::TypePath::Index>(&reason.superPath.components.at(1)))
|
||||
{
|
||||
size_t nthArgument = pathIndexComponent->index;
|
||||
argLocation = argExprs->at(nthArgument)->location;
|
||||
// if the nth type argument to the function is less than the number of ast expressions we passed to the function
|
||||
// we should be able to pull out the location of the argument
|
||||
// If the nth type argument to the function is out of range of the ast expressions we passed to the function
|
||||
// e.g. table.pack(functionThatReturnsMultipleArguments(arg1, arg2, ....)), default to the location of the last passed expression
|
||||
// If we passed no expression arguments to the call, default to the location of the function expression.
|
||||
argLocation = nthArgument < argExprs->size() ? argExprs->at(nthArgument)->location
|
||||
: argExprs->size() != 0 ? argExprs->back()->location
|
||||
: fnExpr->location;
|
||||
|
||||
std::optional<TypeId> failedSubTy = traverseForType(fnTy, reason.subPath, builtinTypes);
|
||||
std::optional<TypeId> failedSuperTy = traverseForType(prospectiveFunction, reason.superPath, builtinTypes);
|
||||
|
@ -125,9 +125,9 @@ static TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool a
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, NegationType>)
|
||||
return dest.addType(NegationType{a.ty});
|
||||
else if constexpr (std::is_same_v<T, TypeFamilyInstanceType>)
|
||||
else if constexpr (std::is_same_v<T, TypeFunctionInstanceType>)
|
||||
{
|
||||
TypeFamilyInstanceType clone{a.family, a.typeArguments, a.packArguments};
|
||||
TypeFunctionInstanceType clone{a.family, a.typeArguments, a.packArguments};
|
||||
return dest.addType(std::move(clone));
|
||||
}
|
||||
else
|
||||
@ -226,7 +226,7 @@ void Tarjan::visitChildren(TypeId ty, int index)
|
||||
for (TypePackId a : petv->packArguments)
|
||||
visitChild(a);
|
||||
}
|
||||
else if (const TypeFamilyInstanceType* tfit = get<TypeFamilyInstanceType>(ty))
|
||||
else if (const TypeFunctionInstanceType* tfit = get<TypeFunctionInstanceType>(ty))
|
||||
{
|
||||
for (TypeId a : tfit->typeArguments)
|
||||
visitChild(a);
|
||||
@ -669,9 +669,9 @@ TypePackId Substitution::clone(TypePackId tp)
|
||||
clone.hidden = vtp->hidden;
|
||||
return addTypePack(std::move(clone));
|
||||
}
|
||||
else if (const TypeFamilyInstanceTypePack* tfitp = get<TypeFamilyInstanceTypePack>(tp))
|
||||
else if (const TypeFunctionInstanceTypePack* tfitp = get<TypeFunctionInstanceTypePack>(tp))
|
||||
{
|
||||
TypeFamilyInstanceTypePack clone{
|
||||
TypeFunctionInstanceTypePack clone{
|
||||
tfitp->family, std::vector<TypeId>(tfitp->typeArguments.size()), std::vector<TypePackId>(tfitp->packArguments.size())};
|
||||
clone.typeArguments.assign(tfitp->typeArguments.begin(), tfitp->typeArguments.end());
|
||||
clone.packArguments.assign(tfitp->packArguments.begin(), tfitp->packArguments.end());
|
||||
@ -798,7 +798,7 @@ void Substitution::replaceChildren(TypeId ty)
|
||||
for (TypePackId& a : petv->packArguments)
|
||||
a = replace(a);
|
||||
}
|
||||
else if (TypeFamilyInstanceType* tfit = getMutable<TypeFamilyInstanceType>(ty))
|
||||
else if (TypeFunctionInstanceType* tfit = getMutable<TypeFunctionInstanceType>(ty))
|
||||
{
|
||||
for (TypeId& a : tfit->typeArguments)
|
||||
a = replace(a);
|
||||
@ -850,7 +850,7 @@ void Substitution::replaceChildren(TypePackId tp)
|
||||
{
|
||||
vtp->ty = replace(vtp->ty);
|
||||
}
|
||||
else if (TypeFamilyInstanceTypePack* tfitp = getMutable<TypeFamilyInstanceTypePack>(tp))
|
||||
else if (TypeFunctionInstanceTypePack* tfitp = getMutable<TypeFunctionInstanceTypePack>(tp))
|
||||
{
|
||||
for (TypeId& t : tfitp->typeArguments)
|
||||
t = replace(t);
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeArena.h"
|
||||
#include "Luau/TypeCheckLimits.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/TypePath.h"
|
||||
#include "Luau/TypeUtils.h"
|
||||
@ -121,9 +121,9 @@ SubtypingResult& SubtypingResult::andAlso(const SubtypingResult& other)
|
||||
{
|
||||
// If the other result is not a subtype, we want to join all of its
|
||||
// reasonings to this one. If this result already has reasonings of its own,
|
||||
// those need to be attributed here.
|
||||
// those need to be attributed here whenever this _also_ failed.
|
||||
if (!other.isSubtype)
|
||||
reasoning = mergeReasonings(reasoning, other.reasoning);
|
||||
reasoning = isSubtype ? std::move(other.reasoning) : mergeReasonings(reasoning, other.reasoning);
|
||||
|
||||
isSubtype &= other.isSubtype;
|
||||
normalizationTooComplex |= other.normalizationTooComplex;
|
||||
@ -579,19 +579,19 @@ SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, TypeId sub
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (auto subTypeFamilyInstance = get<TypeFamilyInstanceType>(subTy))
|
||||
else if (auto subTypeFunctionInstance = get<TypeFunctionInstanceType>(subTy))
|
||||
{
|
||||
if (auto substSubTy = env.applyMappedGenerics(builtinTypes, arena, subTy))
|
||||
subTypeFamilyInstance = get<TypeFamilyInstanceType>(*substSubTy);
|
||||
subTypeFunctionInstance = get<TypeFunctionInstanceType>(*substSubTy);
|
||||
|
||||
result = isCovariantWith(env, subTypeFamilyInstance, superTy);
|
||||
result = isCovariantWith(env, subTypeFunctionInstance, superTy);
|
||||
}
|
||||
else if (auto superTypeFamilyInstance = get<TypeFamilyInstanceType>(superTy))
|
||||
else if (auto superTypeFunctionInstance = get<TypeFunctionInstanceType>(superTy))
|
||||
{
|
||||
if (auto substSuperTy = env.applyMappedGenerics(builtinTypes, arena, superTy))
|
||||
superTypeFamilyInstance = get<TypeFamilyInstanceType>(*substSuperTy);
|
||||
superTypeFunctionInstance = get<TypeFunctionInstanceType>(*substSuperTy);
|
||||
|
||||
result = isCovariantWith(env, subTy, superTypeFamilyInstance);
|
||||
result = isCovariantWith(env, subTy, superTypeFunctionInstance);
|
||||
}
|
||||
else if (auto subGeneric = get<GenericType>(subTy); subGeneric && variance == Variance::Covariant)
|
||||
{
|
||||
@ -1584,19 +1584,19 @@ bool Subtyping::bindGeneric(SubtypingEnvironment& env, TypeId subTy, TypeId supe
|
||||
return true;
|
||||
}
|
||||
|
||||
SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TypeFamilyInstanceType* subFamilyInstance, const TypeId superTy)
|
||||
SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TypeFunctionInstanceType* subFamilyInstance, const TypeId superTy)
|
||||
{
|
||||
// Reduce the typefamily instance
|
||||
auto [ty, errors] = handleTypeFamilyReductionResult(subFamilyInstance);
|
||||
// Reduce the type function instance
|
||||
auto [ty, errors] = handleTypeFunctionReductionResult(subFamilyInstance);
|
||||
|
||||
// If we return optional, that means the type family was irreducible - we can reduce that to never
|
||||
// If we return optional, that means the type function was irreducible - we can reduce that to never
|
||||
return isCovariantWith(env, ty, superTy).withErrors(errors).withSubComponent(TypePath::Reduction{ty});
|
||||
}
|
||||
|
||||
SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TypeId subTy, const TypeFamilyInstanceType* superFamilyInstance)
|
||||
SubtypingResult Subtyping::isCovariantWith(SubtypingEnvironment& env, const TypeId subTy, const TypeFunctionInstanceType* superFamilyInstance)
|
||||
{
|
||||
// Reduce the typefamily instance
|
||||
auto [ty, errors] = handleTypeFamilyReductionResult(superFamilyInstance);
|
||||
// Reduce the type function instance
|
||||
auto [ty, errors] = handleTypeFunctionReductionResult(superFamilyInstance);
|
||||
return isCovariantWith(env, subTy, ty).withErrors(errors).withSuperComponent(TypePath::Reduction{ty});
|
||||
}
|
||||
|
||||
@ -1632,15 +1632,15 @@ TypeId Subtyping::makeAggregateType(const Container& container, TypeId orElse)
|
||||
return arena->addType(T{std::vector<TypeId>(begin(container), end(container))});
|
||||
}
|
||||
|
||||
std::pair<TypeId, ErrorVec> Subtyping::handleTypeFamilyReductionResult(const TypeFamilyInstanceType* familyInstance)
|
||||
std::pair<TypeId, ErrorVec> Subtyping::handleTypeFunctionReductionResult(const TypeFunctionInstanceType* familyInstance)
|
||||
{
|
||||
TypeFamilyContext context{arena, builtinTypes, scope, normalizer, iceReporter, NotNull{&limits}};
|
||||
TypeFunctionContext context{arena, builtinTypes, scope, normalizer, iceReporter, NotNull{&limits}};
|
||||
TypeId family = arena->addType(*familyInstance);
|
||||
FamilyGraphReductionResult result = reduceFamilies(family, {}, context, true);
|
||||
FunctionGraphReductionResult result = reduceTypeFunctions(family, {}, context, true);
|
||||
ErrorVec errors;
|
||||
if (result.blockedTypes.size() != 0 || result.blockedPacks.size() != 0)
|
||||
{
|
||||
errors.push_back(TypeError{{}, UninhabitedTypeFamily{family}});
|
||||
errors.push_back(TypeError{{}, UninhabitedTypeFunction{family}});
|
||||
return {builtinTypes->neverType, errors};
|
||||
}
|
||||
if (result.reducedTypes.contains(family))
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "Luau/ToString.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/StringUtils.h"
|
||||
|
||||
#include <unordered_map>
|
||||
@ -343,9 +343,9 @@ void StateDot::visitChildren(TypeId ty, int index)
|
||||
|
||||
visitChild(t.ty, index, "[negated]");
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, TypeFamilyInstanceType>)
|
||||
else if constexpr (std::is_same_v<T, TypeFunctionInstanceType>)
|
||||
{
|
||||
formatAppend(result, "TypeFamilyInstanceType %s %d", t.family->name.c_str(), index);
|
||||
formatAppend(result, "TypeFunctionInstanceType %s %d", t.family->name.c_str(), index);
|
||||
finishNodeLabel(ty);
|
||||
finishNode();
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include "Luau/TypeInfer.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/VisitType.h"
|
||||
#include "Luau/TypeOrPack.h"
|
||||
|
||||
@ -1031,7 +1031,7 @@ struct TypeStringifier
|
||||
state.emit(")");
|
||||
}
|
||||
|
||||
void operator()(TypeId, const TypeFamilyInstanceType& tfitv)
|
||||
void operator()(TypeId, const TypeFunctionInstanceType& tfitv)
|
||||
{
|
||||
state.emit(tfitv.family->name);
|
||||
state.emit("<");
|
||||
@ -1232,7 +1232,7 @@ struct TypePackStringifier
|
||||
state.emit("*");
|
||||
}
|
||||
|
||||
void operator()(TypePackId, const TypeFamilyInstanceTypePack& tfitp)
|
||||
void operator()(TypePackId, const TypeFunctionInstanceTypePack& tfitp)
|
||||
{
|
||||
state.emit(tfitp.family->name);
|
||||
state.emit("<");
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "Luau/RecursionCounter.h"
|
||||
#include "Luau/StringUtils.h"
|
||||
#include "Luau/ToString.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/TypeInfer.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/VecDeque.h"
|
||||
@ -423,7 +423,7 @@ bool maybeSingleton(TypeId ty)
|
||||
for (TypeId part : itv)
|
||||
if (maybeSingleton(part)) // will i regret this?
|
||||
return true;
|
||||
if (const TypeFamilyInstanceType* tfit = get<TypeFamilyInstanceType>(ty))
|
||||
if (const TypeFunctionInstanceType* tfit = get<TypeFunctionInstanceType>(ty))
|
||||
if (tfit->family->name == "keyof" || tfit->family->name == "rawkeyof")
|
||||
return true;
|
||||
return false;
|
||||
@ -1081,7 +1081,7 @@ void persist(TypeId ty)
|
||||
else if (get<GenericType>(t) || get<AnyType>(t) || get<FreeType>(t) || get<SingletonType>(t) || get<PrimitiveType>(t) || get<NegationType>(t))
|
||||
{
|
||||
}
|
||||
else if (auto tfit = get<TypeFamilyInstanceType>(t))
|
||||
else if (auto tfit = get<TypeFunctionInstanceType>(t))
|
||||
{
|
||||
for (auto ty : tfit->typeArguments)
|
||||
queue.push_back(ty);
|
||||
@ -1117,7 +1117,7 @@ void persist(TypePackId tp)
|
||||
else if (get<GenericTypePack>(tp))
|
||||
{
|
||||
}
|
||||
else if (auto tfitp = get<TypeFamilyInstanceTypePack>(tp))
|
||||
else if (auto tfitp = get<TypeFunctionInstanceTypePack>(tp))
|
||||
{
|
||||
for (auto ty : tfitp->typeArguments)
|
||||
persist(ty);
|
||||
|
@ -94,24 +94,24 @@ TypePackId TypeArena::addTypePack(TypePackVar tp)
|
||||
return allocated;
|
||||
}
|
||||
|
||||
TypeId TypeArena::addTypeFamily(const TypeFamily& family, std::initializer_list<TypeId> types)
|
||||
TypeId TypeArena::addTypeFunction(const TypeFunction& family, std::initializer_list<TypeId> types)
|
||||
{
|
||||
return addType(TypeFamilyInstanceType{family, std::move(types)});
|
||||
return addType(TypeFunctionInstanceType{family, std::move(types)});
|
||||
}
|
||||
|
||||
TypeId TypeArena::addTypeFamily(const TypeFamily& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments)
|
||||
TypeId TypeArena::addTypeFunction(const TypeFunction& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments)
|
||||
{
|
||||
return addType(TypeFamilyInstanceType{family, std::move(typeArguments), std::move(packArguments)});
|
||||
return addType(TypeFunctionInstanceType{family, std::move(typeArguments), std::move(packArguments)});
|
||||
}
|
||||
|
||||
TypePackId TypeArena::addTypePackFamily(const TypePackFamily& family, std::initializer_list<TypeId> types)
|
||||
TypePackId TypeArena::addTypePackFunction(const TypePackFunction& family, std::initializer_list<TypeId> types)
|
||||
{
|
||||
return addTypePack(TypeFamilyInstanceTypePack{NotNull{&family}, std::move(types)});
|
||||
return addTypePack(TypeFunctionInstanceTypePack{NotNull{&family}, std::move(types)});
|
||||
}
|
||||
|
||||
TypePackId TypeArena::addTypePackFamily(const TypePackFamily& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments)
|
||||
TypePackId TypeArena::addTypePackFunction(const TypePackFunction& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments)
|
||||
{
|
||||
return addTypePack(TypeFamilyInstanceTypePack{NotNull{&family}, std::move(typeArguments), std::move(packArguments)});
|
||||
return addTypePack(TypeFunctionInstanceTypePack{NotNull{&family}, std::move(typeArguments), std::move(packArguments)});
|
||||
}
|
||||
|
||||
void freeze(TypeArena& arena)
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "Luau/TypeInfer.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
@ -380,7 +380,7 @@ public:
|
||||
// FIXME: do the same thing we do with ErrorType
|
||||
throw InternalCompilerError("Cannot convert NegationType into AstNode");
|
||||
}
|
||||
AstType* operator()(const TypeFamilyInstanceType& tfit)
|
||||
AstType* operator()(const TypeFunctionInstanceType& tfit)
|
||||
{
|
||||
return allocator->alloc<AstTypeReference>(Location(), std::nullopt, AstName{tfit.family->name.c_str()}, std::nullopt, Location());
|
||||
}
|
||||
@ -454,7 +454,7 @@ public:
|
||||
return allocator->alloc<AstTypePackGeneric>(Location(), AstName("Unifiable<Error>"));
|
||||
}
|
||||
|
||||
AstTypePack* operator()(const TypeFamilyInstanceTypePack& tfitp) const
|
||||
AstTypePack* operator()(const TypeFunctionInstanceTypePack& tfitp) const
|
||||
{
|
||||
return allocator->alloc<AstTypePackGeneric>(Location(), AstName(tfitp.family->name.c_str()));
|
||||
}
|
||||
|
@ -16,8 +16,8 @@
|
||||
#include "Luau/ToString.h"
|
||||
#include "Luau/TxnLog.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFamilyReductionGuesser.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/TypeFunctionReductionGuesser.h"
|
||||
#include "Luau/TypeFwd.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/TypePath.h"
|
||||
@ -121,13 +121,13 @@ struct FamilyFinder : TypeOnceVisitor
|
||||
DenseHashSet<TypeId> mentionedFamilies{nullptr};
|
||||
DenseHashSet<TypePackId> mentionedFamilyPacks{nullptr};
|
||||
|
||||
bool visit(TypeId ty, const TypeFamilyInstanceType&) override
|
||||
bool visit(TypeId ty, const TypeFunctionInstanceType&) override
|
||||
{
|
||||
mentionedFamilies.insert(ty);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visit(TypePackId tp, const TypeFamilyInstanceTypePack&) override
|
||||
bool visit(TypePackId tp, const TypeFunctionInstanceTypePack&) override
|
||||
{
|
||||
mentionedFamilyPacks.insert(tp);
|
||||
return true;
|
||||
@ -151,7 +151,7 @@ struct InternalFamilyFinder : TypeOnceVisitor
|
||||
mentionedFamilyPacks = std::move(f.mentionedFamilyPacks);
|
||||
}
|
||||
|
||||
bool visit(TypeId ty, const TypeFamilyInstanceType& tfit) override
|
||||
bool visit(TypeId ty, const TypeFunctionInstanceType& tfit) override
|
||||
{
|
||||
bool hasGeneric = false;
|
||||
|
||||
@ -177,7 +177,7 @@ struct InternalFamilyFinder : TypeOnceVisitor
|
||||
{
|
||||
for (TypeId mentioned : mentionedFamilies)
|
||||
{
|
||||
const TypeFamilyInstanceType* mentionedTfit = get<TypeFamilyInstanceType>(mentioned);
|
||||
const TypeFunctionInstanceType* mentionedTfit = get<TypeFunctionInstanceType>(mentioned);
|
||||
LUAU_ASSERT(mentionedTfit);
|
||||
if (areEquivalent(tfit, *mentionedTfit))
|
||||
{
|
||||
@ -191,7 +191,7 @@ struct InternalFamilyFinder : TypeOnceVisitor
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visit(TypePackId tp, const TypeFamilyInstanceTypePack& tfitp) override
|
||||
bool visit(TypePackId tp, const TypeFunctionInstanceTypePack& tfitp) override
|
||||
{
|
||||
bool hasGeneric = false;
|
||||
|
||||
@ -217,7 +217,7 @@ struct InternalFamilyFinder : TypeOnceVisitor
|
||||
{
|
||||
for (TypePackId mentioned : mentionedFamilyPacks)
|
||||
{
|
||||
const TypeFamilyInstanceTypePack* mentionedTfitp = get<TypeFamilyInstanceTypePack>(mentioned);
|
||||
const TypeFunctionInstanceTypePack* mentionedTfitp = get<TypeFunctionInstanceTypePack>(mentioned);
|
||||
LUAU_ASSERT(mentionedTfitp);
|
||||
if (areEquivalent(tfitp, *mentionedTfitp))
|
||||
{
|
||||
@ -245,7 +245,7 @@ struct TypeChecker2
|
||||
std::vector<NotNull<Scope>> stack;
|
||||
std::vector<TypeId> functionDeclStack;
|
||||
|
||||
DenseHashSet<TypeId> seenTypeFamilyInstances{nullptr};
|
||||
DenseHashSet<TypeId> seenTypeFunctionInstances{nullptr};
|
||||
|
||||
Normalizer normalizer;
|
||||
Subtyping _subtyping;
|
||||
@ -437,12 +437,12 @@ struct TypeChecker2
|
||||
|
||||
TypeId checkForFamilyInhabitance(TypeId instance, Location location)
|
||||
{
|
||||
if (seenTypeFamilyInstances.find(instance))
|
||||
if (seenTypeFunctionInstances.find(instance))
|
||||
return instance;
|
||||
seenTypeFamilyInstances.insert(instance);
|
||||
seenTypeFunctionInstances.insert(instance);
|
||||
|
||||
ErrorVec errors = reduceFamilies(instance, location,
|
||||
TypeFamilyContext{NotNull{&module->internalTypes}, builtinTypes, stack.back(), NotNull{&normalizer}, ice, limits}, true)
|
||||
ErrorVec errors = reduceTypeFunctions(instance, location,
|
||||
TypeFunctionContext{NotNull{&module->internalTypes}, builtinTypes, stack.back(), NotNull{&normalizer}, ice, limits}, true)
|
||||
.errors;
|
||||
if (!isErrorSuppressing(location, instance))
|
||||
reportErrors(std::move(errors));
|
||||
@ -1731,12 +1731,12 @@ struct TypeChecker2
|
||||
const FunctionType* inferredFtv = get<FunctionType>(normalizedFnTy->functions.parts.front());
|
||||
LUAU_ASSERT(inferredFtv);
|
||||
|
||||
TypeFamilyReductionGuesser guesser{NotNull{&module->internalTypes}, builtinTypes, NotNull{&normalizer}};
|
||||
TypeFunctionReductionGuesser guesser{NotNull{&module->internalTypes}, builtinTypes, NotNull{&normalizer}};
|
||||
for (TypeId retTy : inferredFtv->retTypes)
|
||||
{
|
||||
if (get<TypeFamilyInstanceType>(follow(retTy)))
|
||||
if (get<TypeFunctionInstanceType>(follow(retTy)))
|
||||
{
|
||||
TypeFamilyReductionGuessResult result = guesser.guessTypeFamilyReductionForFunction(*fn, inferredFtv, retTy);
|
||||
TypeFunctionReductionGuessResult result = guesser.guessTypeFunctionReductionForFunctionExpr(*fn, inferredFtv, retTy);
|
||||
if (result.shouldRecommendAnnotation)
|
||||
reportError(ExplicitFunctionAnnotationRecommended{std::move(result.guessedFunctionAnnotations), result.guessedReturnType},
|
||||
fn->location);
|
||||
@ -1853,7 +1853,7 @@ struct TypeChecker2
|
||||
TypeId rightType = follow(lookupType(expr->right));
|
||||
TypeId expectedResult = follow(lookupType(expr));
|
||||
|
||||
if (get<TypeFamilyInstanceType>(expectedResult))
|
||||
if (get<TypeFunctionInstanceType>(expectedResult))
|
||||
{
|
||||
checkForInternalFamily(expectedResult, expr->location);
|
||||
return expectedResult;
|
||||
@ -1954,7 +1954,7 @@ struct TypeChecker2
|
||||
if (!selectedOverloadTy)
|
||||
{
|
||||
// reportError(CodeTooComplex{}, expr->location);
|
||||
// was handled by a type family
|
||||
// was handled by a type function
|
||||
return expectedResult;
|
||||
}
|
||||
|
||||
|
@ -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/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
|
||||
#include "Luau/Common.h"
|
||||
#include "Luau/ConstraintSolver.h"
|
||||
@ -15,7 +15,7 @@
|
||||
#include "Luau/ToString.h"
|
||||
#include "Luau/TxnLog.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeFamilyReductionGuesser.h"
|
||||
#include "Luau/TypeFunctionReductionGuesser.h"
|
||||
#include "Luau/TypeFwd.h"
|
||||
#include "Luau/TypeUtils.h"
|
||||
#include "Luau/Unifier2.h"
|
||||
@ -24,10 +24,10 @@
|
||||
|
||||
#include <iterator>
|
||||
|
||||
// used to control emitting CodeTooComplex warnings on type family reduction
|
||||
// used to control emitting CodeTooComplex warnings on type function reduction
|
||||
LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFamilyGraphReductionMaximumSteps, 1'000'000);
|
||||
|
||||
// used to control the limits of type family application over union type arguments
|
||||
// used to control the limits of type function application over union type arguments
|
||||
// e.g. `mul<a | b, c | d>` blows up into `mul<a, c> | mul<a, d> | mul<b, c> | mul<b, d>`
|
||||
LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFamilyApplicationCartesianProductLimit, 5'000);
|
||||
|
||||
@ -49,7 +49,7 @@ struct InstanceCollector : TypeOnceVisitor
|
||||
TypeOrTypePackIdSet shouldGuess{nullptr};
|
||||
std::vector<TypeId> cyclicInstance;
|
||||
|
||||
bool visit(TypeId ty, const TypeFamilyInstanceType&) override
|
||||
bool visit(TypeId ty, const TypeFunctionInstanceType&) override
|
||||
{
|
||||
// TypeOnceVisitor performs a depth-first traversal in the absence of
|
||||
// cycles. This means that by pushing to the front of the queue, we will
|
||||
@ -58,7 +58,7 @@ struct InstanceCollector : TypeOnceVisitor
|
||||
// we want to reduce the innermost Add<number, number> instantiation
|
||||
// first.
|
||||
|
||||
if (DFInt::LuauTypeFamilyUseGuesserDepth >= 0 && typeFamilyDepth > DFInt::LuauTypeFamilyUseGuesserDepth)
|
||||
if (DFInt::LuauTypeFamilyUseGuesserDepth >= 0 && typeFunctionDepth > DFInt::LuauTypeFamilyUseGuesserDepth)
|
||||
shouldGuess.insert(ty);
|
||||
|
||||
tys.push_front(ty);
|
||||
@ -70,7 +70,7 @@ struct InstanceCollector : TypeOnceVisitor
|
||||
{
|
||||
/// Detected cyclic type pack
|
||||
TypeId t = follow(ty);
|
||||
if (get<TypeFamilyInstanceType>(t))
|
||||
if (get<TypeFunctionInstanceType>(t))
|
||||
cyclicInstance.push_back(t);
|
||||
}
|
||||
|
||||
@ -79,7 +79,7 @@ struct InstanceCollector : TypeOnceVisitor
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypePackId tp, const TypeFamilyInstanceTypePack&) override
|
||||
bool visit(TypePackId tp, const TypeFunctionInstanceTypePack&) override
|
||||
{
|
||||
// TypeOnceVisitor performs a depth-first traversal in the absence of
|
||||
// cycles. This means that by pushing to the front of the queue, we will
|
||||
@ -88,7 +88,7 @@ struct InstanceCollector : TypeOnceVisitor
|
||||
// we want to reduce the innermost Add<number, number> instantiation
|
||||
// first.
|
||||
|
||||
if (DFInt::LuauTypeFamilyUseGuesserDepth >= 0 && typeFamilyDepth > DFInt::LuauTypeFamilyUseGuesserDepth)
|
||||
if (DFInt::LuauTypeFamilyUseGuesserDepth >= 0 && typeFunctionDepth > DFInt::LuauTypeFamilyUseGuesserDepth)
|
||||
shouldGuess.insert(tp);
|
||||
|
||||
tps.push_front(tp);
|
||||
@ -97,23 +97,23 @@ struct InstanceCollector : TypeOnceVisitor
|
||||
}
|
||||
};
|
||||
|
||||
struct FamilyReducer
|
||||
struct TypeFunctionReducer
|
||||
{
|
||||
TypeFamilyContext ctx;
|
||||
TypeFunctionContext ctx;
|
||||
|
||||
VecDeque<TypeId> queuedTys;
|
||||
VecDeque<TypePackId> queuedTps;
|
||||
TypeOrTypePackIdSet shouldGuess;
|
||||
std::vector<TypeId> cyclicTypeFamilies;
|
||||
TypeOrTypePackIdSet irreducible{nullptr};
|
||||
FamilyGraphReductionResult result;
|
||||
FunctionGraphReductionResult result;
|
||||
bool force = false;
|
||||
|
||||
// Local to the constraint being reduced.
|
||||
Location location;
|
||||
|
||||
FamilyReducer(VecDeque<TypeId> queuedTys, VecDeque<TypePackId> queuedTps, TypeOrTypePackIdSet shouldGuess, std::vector<TypeId> cyclicTypes,
|
||||
Location location, TypeFamilyContext ctx, bool force = false)
|
||||
TypeFunctionReducer(VecDeque<TypeId> queuedTys, VecDeque<TypePackId> queuedTps, TypeOrTypePackIdSet shouldGuess, std::vector<TypeId> cyclicTypes,
|
||||
Location location, TypeFunctionContext ctx, bool force = false)
|
||||
: ctx(ctx)
|
||||
, queuedTys(std::move(queuedTys))
|
||||
, queuedTps(std::move(queuedTps))
|
||||
@ -126,7 +126,7 @@ struct FamilyReducer
|
||||
|
||||
enum class SkipTestResult
|
||||
{
|
||||
CyclicTypeFamily,
|
||||
CyclicTypeFunction,
|
||||
Irreducible,
|
||||
Defer,
|
||||
Okay,
|
||||
@ -136,12 +136,12 @@ struct FamilyReducer
|
||||
{
|
||||
ty = follow(ty);
|
||||
|
||||
if (is<TypeFamilyInstanceType>(ty))
|
||||
if (is<TypeFunctionInstanceType>(ty))
|
||||
{
|
||||
for (auto t : cyclicTypeFamilies)
|
||||
{
|
||||
if (ty == t)
|
||||
return SkipTestResult::CyclicTypeFamily;
|
||||
return SkipTestResult::CyclicTypeFunction;
|
||||
}
|
||||
|
||||
if (!irreducible.contains(ty))
|
||||
@ -161,7 +161,7 @@ struct FamilyReducer
|
||||
{
|
||||
ty = follow(ty);
|
||||
|
||||
if (is<TypeFamilyInstanceTypePack>(ty))
|
||||
if (is<TypeFunctionInstanceTypePack>(ty))
|
||||
{
|
||||
if (!irreducible.contains(ty))
|
||||
return SkipTestResult::Defer;
|
||||
@ -181,7 +181,7 @@ struct FamilyReducer
|
||||
{
|
||||
if (subject->owningArena != ctx.arena.get())
|
||||
{
|
||||
result.errors.emplace_back(location, InternalError{"Attempting to modify a type family instance from another arena"});
|
||||
result.errors.emplace_back(location, InternalError{"Attempting to modify a type function instance from another arena"});
|
||||
return;
|
||||
}
|
||||
|
||||
@ -197,7 +197,7 @@ struct FamilyReducer
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void handleFamilyReduction(T subject, TypeFamilyReductionResult<T> reduction)
|
||||
void handleTypeFunctionReduction(T subject, TypeFunctionReductionResult<T> reduction)
|
||||
{
|
||||
if (reduction.result)
|
||||
replace(subject, *reduction.result);
|
||||
@ -211,9 +211,9 @@ struct FamilyReducer
|
||||
printf("%s is uninhabited\n", toString(subject, {true}).c_str());
|
||||
|
||||
if constexpr (std::is_same_v<T, TypeId>)
|
||||
result.errors.push_back(TypeError{location, UninhabitedTypeFamily{subject}});
|
||||
result.errors.push_back(TypeError{location, UninhabitedTypeFunction{subject}});
|
||||
else if constexpr (std::is_same_v<T, TypePackId>)
|
||||
result.errors.push_back(TypeError{location, UninhabitedTypePackFamily{subject}});
|
||||
result.errors.push_back(TypeError{location, UninhabitedTypePackFunction{subject}});
|
||||
}
|
||||
else if (!reduction.uninhabited && !force)
|
||||
{
|
||||
@ -301,7 +301,7 @@ struct FamilyReducer
|
||||
if (FFlag::DebugLuauLogTypeFamilies)
|
||||
printf("Flagged %s for reduction with guesser.\n", toString(subject, {true}).c_str());
|
||||
|
||||
TypeFamilyReductionGuesser guesser{ctx.arena, ctx.builtins, ctx.normalizer};
|
||||
TypeFunctionReductionGuesser guesser{ctx.arena, ctx.builtins, ctx.normalizer};
|
||||
auto guessed = guesser.guess(subject);
|
||||
|
||||
if (guessed)
|
||||
@ -332,11 +332,11 @@ struct FamilyReducer
|
||||
if (FFlag::DebugLuauLogTypeFamilies)
|
||||
printf("Trying to reduce %s\n", toString(subject, {true}).c_str());
|
||||
|
||||
if (const TypeFamilyInstanceType* tfit = get<TypeFamilyInstanceType>(subject))
|
||||
if (const TypeFunctionInstanceType* tfit = get<TypeFunctionInstanceType>(subject))
|
||||
{
|
||||
SkipTestResult testCyclic = testForSkippability(subject);
|
||||
|
||||
if (!testParameters(subject, tfit) && testCyclic != SkipTestResult::CyclicTypeFamily)
|
||||
if (!testParameters(subject, tfit) && testCyclic != SkipTestResult::CyclicTypeFunction)
|
||||
{
|
||||
if (FFlag::DebugLuauLogTypeFamilies)
|
||||
printf("Irreducible due to irreducible/pending and a non-cyclic family\n");
|
||||
@ -347,8 +347,8 @@ struct FamilyReducer
|
||||
if (tryGuessing(subject))
|
||||
return;
|
||||
|
||||
TypeFamilyReductionResult<TypeId> result = tfit->family->reducer(subject, tfit->typeArguments, tfit->packArguments, NotNull{&ctx});
|
||||
handleFamilyReduction(subject, result);
|
||||
TypeFunctionReductionResult<TypeId> result = tfit->family->reducer(subject, tfit->typeArguments, tfit->packArguments, NotNull{&ctx});
|
||||
handleTypeFunctionReduction(subject, result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -363,7 +363,7 @@ struct FamilyReducer
|
||||
if (FFlag::DebugLuauLogTypeFamilies)
|
||||
printf("Trying to reduce %s\n", toString(subject, {true}).c_str());
|
||||
|
||||
if (const TypeFamilyInstanceTypePack* tfit = get<TypeFamilyInstanceTypePack>(subject))
|
||||
if (const TypeFunctionInstanceTypePack* tfit = get<TypeFunctionInstanceTypePack>(subject))
|
||||
{
|
||||
if (!testParameters(subject, tfit))
|
||||
return;
|
||||
@ -371,8 +371,8 @@ struct FamilyReducer
|
||||
if (tryGuessing(subject))
|
||||
return;
|
||||
|
||||
TypeFamilyReductionResult<TypePackId> result = tfit->family->reducer(subject, tfit->typeArguments, tfit->packArguments, NotNull{&ctx});
|
||||
handleFamilyReduction(subject, result);
|
||||
TypeFunctionReductionResult<TypePackId> result = tfit->family->reducer(subject, tfit->typeArguments, tfit->packArguments, NotNull{&ctx});
|
||||
handleTypeFunctionReduction(subject, result);
|
||||
}
|
||||
}
|
||||
|
||||
@ -385,10 +385,10 @@ struct FamilyReducer
|
||||
}
|
||||
};
|
||||
|
||||
static FamilyGraphReductionResult reduceFamiliesInternal(VecDeque<TypeId> queuedTys, VecDeque<TypePackId> queuedTps, TypeOrTypePackIdSet shouldGuess,
|
||||
std::vector<TypeId> cyclics, Location location, TypeFamilyContext ctx, bool force)
|
||||
static FunctionGraphReductionResult reduceFamiliesInternal(VecDeque<TypeId> queuedTys, VecDeque<TypePackId> queuedTps, TypeOrTypePackIdSet shouldGuess,
|
||||
std::vector<TypeId> cyclics, Location location, TypeFunctionContext ctx, bool force)
|
||||
{
|
||||
FamilyReducer reducer{std::move(queuedTys), std::move(queuedTps), std::move(shouldGuess), std::move(cyclics), location, ctx, force};
|
||||
TypeFunctionReducer reducer{std::move(queuedTys), std::move(queuedTps), std::move(shouldGuess), std::move(cyclics), location, ctx, force};
|
||||
int iterationCount = 0;
|
||||
|
||||
while (!reducer.done())
|
||||
@ -406,7 +406,7 @@ static FamilyGraphReductionResult reduceFamiliesInternal(VecDeque<TypeId> queued
|
||||
return std::move(reducer.result);
|
||||
}
|
||||
|
||||
FamilyGraphReductionResult reduceFamilies(TypeId entrypoint, Location location, TypeFamilyContext ctx, bool force)
|
||||
FunctionGraphReductionResult reduceTypeFunctions(TypeId entrypoint, Location location, TypeFunctionContext ctx, bool force)
|
||||
{
|
||||
InstanceCollector collector;
|
||||
|
||||
@ -416,7 +416,7 @@ FamilyGraphReductionResult reduceFamilies(TypeId entrypoint, Location location,
|
||||
}
|
||||
catch (RecursionLimitException&)
|
||||
{
|
||||
return FamilyGraphReductionResult{};
|
||||
return FunctionGraphReductionResult{};
|
||||
}
|
||||
|
||||
if (collector.tys.empty() && collector.tps.empty())
|
||||
@ -426,7 +426,7 @@ FamilyGraphReductionResult reduceFamilies(TypeId entrypoint, Location location,
|
||||
std::move(collector.cyclicInstance), location, ctx, force);
|
||||
}
|
||||
|
||||
FamilyGraphReductionResult reduceFamilies(TypePackId entrypoint, Location location, TypeFamilyContext ctx, bool force)
|
||||
FunctionGraphReductionResult reduceTypeFunctions(TypePackId entrypoint, Location location, TypeFunctionContext ctx, bool force)
|
||||
{
|
||||
InstanceCollector collector;
|
||||
|
||||
@ -436,7 +436,7 @@ FamilyGraphReductionResult reduceFamilies(TypePackId entrypoint, Location locati
|
||||
}
|
||||
catch (RecursionLimitException&)
|
||||
{
|
||||
return FamilyGraphReductionResult{};
|
||||
return FunctionGraphReductionResult{};
|
||||
}
|
||||
|
||||
if (collector.tys.empty() && collector.tps.empty())
|
||||
@ -448,12 +448,12 @@ FamilyGraphReductionResult reduceFamilies(TypePackId entrypoint, Location locati
|
||||
|
||||
bool isPending(TypeId ty, ConstraintSolver* solver)
|
||||
{
|
||||
return is<BlockedType, PendingExpansionType, TypeFamilyInstanceType>(ty) || (solver && solver->hasUnresolvedConstraints(ty));
|
||||
return is<BlockedType, PendingExpansionType, TypeFunctionInstanceType>(ty) || (solver && solver->hasUnresolvedConstraints(ty));
|
||||
}
|
||||
|
||||
template<typename F, typename... Args>
|
||||
static std::optional<TypeFamilyReductionResult<TypeId>> tryDistributeTypeFamilyApp(F f, TypeId instance, const std::vector<TypeId>& typeParams,
|
||||
const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx, Args&&... args)
|
||||
static std::optional<TypeFunctionReductionResult<TypeId>> tryDistributeTypeFunctionApp(F f, TypeId instance, const std::vector<TypeId>& typeParams,
|
||||
const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx, Args&&... args)
|
||||
{
|
||||
// op (a | b) (c | d) ~ (op a (c | d)) | (op b (c | d)) ~ (op a c) | (op a d) | (op b c) | (op b d)
|
||||
bool uninhabited = false;
|
||||
@ -483,7 +483,7 @@ static std::optional<TypeFamilyReductionResult<TypeId>> tryDistributeTypeFamilyA
|
||||
|
||||
cartesianProductSize *= std::distance(begin(ut), end(ut));
|
||||
|
||||
// TODO: We'd like to report that the type family application is too complex here.
|
||||
// TODO: We'd like to report that the type function application is too complex here.
|
||||
if (size_t(DFInt::LuauTypeFamilyApplicationCartesianProductLimit) <= cartesianProductSize)
|
||||
return {{std::nullopt, true, {}, {}}};
|
||||
}
|
||||
@ -498,7 +498,7 @@ static std::optional<TypeFamilyReductionResult<TypeId>> tryDistributeTypeFamilyA
|
||||
{
|
||||
arguments[unionIndex] = option;
|
||||
|
||||
TypeFamilyReductionResult<TypeId> result = f(instance, arguments, packParams, ctx, args...);
|
||||
TypeFunctionReductionResult<TypeId> result = f(instance, arguments, packParams, ctx, args...);
|
||||
blockedTypes.insert(blockedTypes.end(), result.blockedTypes.begin(), result.blockedTypes.end());
|
||||
uninhabited |= result.uninhabited;
|
||||
|
||||
@ -516,8 +516,8 @@ static std::optional<TypeFamilyReductionResult<TypeId>> tryDistributeTypeFamilyA
|
||||
if (results.size() == 1)
|
||||
return {{results[0], false, {}, {}}};
|
||||
|
||||
TypeId resultTy = ctx->arena->addType(TypeFamilyInstanceType{
|
||||
NotNull{&builtinTypeFunctions().unionFamily},
|
||||
TypeId resultTy = ctx->arena->addType(TypeFunctionInstanceType{
|
||||
NotNull{&builtinTypeFunctions().unionFunc},
|
||||
std::move(results),
|
||||
{},
|
||||
});
|
||||
@ -528,12 +528,12 @@ static std::optional<TypeFamilyReductionResult<TypeId>> tryDistributeTypeFamilyA
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> notFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> notFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 1 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("not type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("not type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -545,19 +545,19 @@ TypeFamilyReductionResult<TypeId> notFamilyFn(
|
||||
if (isPending(ty, ctx->solver))
|
||||
return {std::nullopt, false, {ty}, {}};
|
||||
|
||||
if (auto result = tryDistributeTypeFamilyApp(notFamilyFn, instance, typeParams, packParams, ctx))
|
||||
if (auto result = tryDistributeTypeFunctionApp(notFamilyFn, instance, typeParams, packParams, ctx))
|
||||
return *result;
|
||||
|
||||
// `not` operates on anything and returns a `boolean` always.
|
||||
return {ctx->builtins->booleanType, false, {}, {}};
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> lenFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> lenFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 1 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("len type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("len type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -604,7 +604,7 @@ TypeFamilyReductionResult<TypeId> lenFamilyFn(
|
||||
if (normTy->hasTopTable() || get<TableType>(normalizedOperand))
|
||||
return {ctx->builtins->numberType, false, {}, {}};
|
||||
|
||||
if (auto result = tryDistributeTypeFamilyApp(notFamilyFn, instance, typeParams, packParams, ctx))
|
||||
if (auto result = tryDistributeTypeFunctionApp(notFamilyFn, instance, typeParams, packParams, ctx))
|
||||
return *result;
|
||||
|
||||
// findMetatableEntry demands the ability to emit errors, so we must give it
|
||||
@ -644,12 +644,12 @@ TypeFamilyReductionResult<TypeId> lenFamilyFn(
|
||||
return {ctx->builtins->numberType, false, {}, {}};
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> unmFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> unmFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 1 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("unm type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("unm type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -689,7 +689,7 @@ TypeFamilyReductionResult<TypeId> unmFamilyFn(
|
||||
if (normTy->isExactlyNumber())
|
||||
return {ctx->builtins->numberType, false, {}, {}};
|
||||
|
||||
if (auto result = tryDistributeTypeFamilyApp(notFamilyFn, instance, typeParams, packParams, ctx))
|
||||
if (auto result = tryDistributeTypeFunctionApp(notFamilyFn, instance, typeParams, packParams, ctx))
|
||||
return *result;
|
||||
|
||||
// findMetatableEntry demands the ability to emit errors, so we must give it
|
||||
@ -731,7 +731,7 @@ TypeFamilyReductionResult<TypeId> unmFamilyFn(
|
||||
return {std::nullopt, true, {}, {}};
|
||||
}
|
||||
|
||||
NotNull<Constraint> TypeFamilyContext::pushConstraint(ConstraintV&& c)
|
||||
NotNull<Constraint> TypeFunctionContext::pushConstraint(ConstraintV&& c)
|
||||
{
|
||||
LUAU_ASSERT(solver);
|
||||
NotNull<Constraint> newConstraint = solver->pushConstraint(scope, constraint ? constraint->location : Location{}, std::move(c));
|
||||
@ -744,12 +744,12 @@ NotNull<Constraint> TypeFamilyContext::pushConstraint(ConstraintV&& c)
|
||||
return newConstraint;
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> numericBinopFamilyFn(TypeId instance, const std::vector<TypeId>& typeParams,
|
||||
const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx, const std::string metamethod)
|
||||
TypeFunctionReductionResult<TypeId> numericBinopFamilyFn(TypeId instance, const std::vector<TypeId>& typeParams,
|
||||
const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx, const std::string metamethod)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -803,7 +803,7 @@ TypeFamilyReductionResult<TypeId> numericBinopFamilyFn(TypeId instance, const st
|
||||
if (normLhsTy->isExactlyNumber() && normRhsTy->isExactlyNumber())
|
||||
return {ctx->builtins->numberType, false, {}, {}};
|
||||
|
||||
if (auto result = tryDistributeTypeFamilyApp(numericBinopFamilyFn, instance, typeParams, packParams, ctx, metamethod))
|
||||
if (auto result = tryDistributeTypeFunctionApp(numericBinopFamilyFn, instance, typeParams, packParams, ctx, metamethod))
|
||||
return *result;
|
||||
|
||||
// findMetatableEntry demands the ability to emit errors, so we must give it
|
||||
@ -847,96 +847,96 @@ TypeFamilyReductionResult<TypeId> numericBinopFamilyFn(TypeId instance, const st
|
||||
return {extracted.head.front(), false, {}, {}};
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> addFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> addFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("add type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("add type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
return numericBinopFamilyFn(instance, typeParams, packParams, ctx, "__add");
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> subFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> subFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("sub type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("sub type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
return numericBinopFamilyFn(instance, typeParams, packParams, ctx, "__sub");
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> mulFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> mulFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("mul type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("mul type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
return numericBinopFamilyFn(instance, typeParams, packParams, ctx, "__mul");
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> divFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> divFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("div type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("div type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
return numericBinopFamilyFn(instance, typeParams, packParams, ctx, "__div");
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> idivFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> idivFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("integer div type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("integer div type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
return numericBinopFamilyFn(instance, typeParams, packParams, ctx, "__idiv");
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> powFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> powFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("pow type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("pow type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
return numericBinopFamilyFn(instance, typeParams, packParams, ctx, "__pow");
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> modFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> modFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("modulo type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("modulo type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
return numericBinopFamilyFn(instance, typeParams, packParams, ctx, "__mod");
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> concatFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> concatFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("concat type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("concat type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -987,7 +987,7 @@ TypeFamilyReductionResult<TypeId> concatFamilyFn(
|
||||
if ((normLhsTy->isSubtypeOfString() || normLhsTy->isExactlyNumber()) && (normRhsTy->isSubtypeOfString() || normRhsTy->isExactlyNumber()))
|
||||
return {ctx->builtins->stringType, false, {}, {}};
|
||||
|
||||
if (auto result = tryDistributeTypeFamilyApp(concatFamilyFn, instance, typeParams, packParams, ctx))
|
||||
if (auto result = tryDistributeTypeFunctionApp(concatFamilyFn, instance, typeParams, packParams, ctx))
|
||||
return *result;
|
||||
|
||||
// findMetatableEntry demands the ability to emit errors, so we must give it
|
||||
@ -1039,12 +1039,12 @@ TypeFamilyReductionResult<TypeId> concatFamilyFn(
|
||||
return {ctx->builtins->stringType, false, {}, {}};
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> andFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> andFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("and type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("and type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -1090,12 +1090,12 @@ TypeFamilyReductionResult<TypeId> andFamilyFn(
|
||||
return {overallResult.result, false, std::move(blockedTypes), {}};
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> orFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> orFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("or type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("or type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -1141,13 +1141,13 @@ TypeFamilyReductionResult<TypeId> orFamilyFn(
|
||||
return {overallResult.result, false, std::move(blockedTypes), {}};
|
||||
}
|
||||
|
||||
static TypeFamilyReductionResult<TypeId> comparisonFamilyFn(TypeId instance, const std::vector<TypeId>& typeParams,
|
||||
const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx, const std::string metamethod)
|
||||
static TypeFunctionReductionResult<TypeId> comparisonFamilyFn(TypeId instance, const std::vector<TypeId>& typeParams,
|
||||
const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx, const std::string metamethod)
|
||||
{
|
||||
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -1238,7 +1238,7 @@ static TypeFamilyReductionResult<TypeId> comparisonFamilyFn(TypeId instance, con
|
||||
if (normLhsTy->isExactlyNumber() && normRhsTy->isExactlyNumber())
|
||||
return {ctx->builtins->booleanType, false, {}, {}};
|
||||
|
||||
if (auto result = tryDistributeTypeFamilyApp(comparisonFamilyFn, instance, typeParams, packParams, ctx, metamethod))
|
||||
if (auto result = tryDistributeTypeFunctionApp(comparisonFamilyFn, instance, typeParams, packParams, ctx, metamethod))
|
||||
return *result;
|
||||
|
||||
// findMetatableEntry demands the ability to emit errors, so we must give it
|
||||
@ -1280,36 +1280,36 @@ static TypeFamilyReductionResult<TypeId> comparisonFamilyFn(TypeId instance, con
|
||||
return {ctx->builtins->booleanType, false, {}, {}};
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> ltFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> ltFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("lt type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("lt type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
return comparisonFamilyFn(instance, typeParams, packParams, ctx, "__lt");
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> leFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> leFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("le type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("le type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
return comparisonFamilyFn(instance, typeParams, packParams, ctx, "__le");
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> eqFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> eqFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("eq type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("eq type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -1435,12 +1435,12 @@ struct FindRefinementBlockers : TypeOnceVisitor
|
||||
};
|
||||
|
||||
|
||||
TypeFamilyReductionResult<TypeId> refineFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> refineFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("refine type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("refine type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -1520,12 +1520,12 @@ TypeFamilyReductionResult<TypeId> refineFamilyFn(
|
||||
return {resultTy, false, {}, {}};
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> singletonFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> singletonFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 1 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("singleton type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("singleton type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -1557,12 +1557,12 @@ TypeFamilyReductionResult<TypeId> singletonFamilyFn(
|
||||
return {ctx->builtins->unknownType, false, {}, {}};
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> unionFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> unionFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (!packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("union type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("union type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -1618,12 +1618,12 @@ TypeFamilyReductionResult<TypeId> unionFamilyFn(
|
||||
}
|
||||
|
||||
|
||||
TypeFamilyReductionResult<TypeId> intersectFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> intersectFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (!packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("intersect type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("intersect type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -1673,7 +1673,7 @@ TypeFamilyReductionResult<TypeId> intersectFamilyFn(
|
||||
// computes the keys of `ty` into `result`
|
||||
// `isRaw` parameter indicates whether or not we should follow __index metamethods
|
||||
// returns `false` if `result` should be ignored because the answer is "all strings"
|
||||
bool computeKeysOf(TypeId ty, Set<std::string>& result, DenseHashSet<TypeId>& seen, bool isRaw, NotNull<TypeFamilyContext> ctx)
|
||||
bool computeKeysOf(TypeId ty, Set<std::string>& result, DenseHashSet<TypeId>& seen, bool isRaw, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
// if the type is the top table type, the answer is just "all strings"
|
||||
if (get<PrimitiveType>(ty))
|
||||
@ -1725,12 +1725,12 @@ bool computeKeysOf(TypeId ty, Set<std::string>& result, DenseHashSet<TypeId>& se
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> keyofFamilyImpl(
|
||||
const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx, bool isRaw)
|
||||
TypeFunctionReductionResult<TypeId> keyofFamilyImpl(
|
||||
const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx, bool isRaw)
|
||||
{
|
||||
if (typeParams.size() != 1 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("keyof type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("keyof type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -1842,24 +1842,24 @@ TypeFamilyReductionResult<TypeId> keyofFamilyImpl(
|
||||
return {ctx->arena->addType(UnionType{singletons}), false, {}, {}};
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> keyofFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> keyofFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 1 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("keyof type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("keyof type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
return keyofFamilyImpl(typeParams, packParams, ctx, /* isRaw */ false);
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> rawkeyofFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> rawkeyofFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 1 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("rawkeyof type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("rawkeyof type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
@ -1870,7 +1870,7 @@ TypeFamilyReductionResult<TypeId> rawkeyofFamilyFn(
|
||||
If found, appends that property to `result` and returns true
|
||||
Else, returns false */
|
||||
bool searchPropsAndIndexer(
|
||||
TypeId ty, TableType::Props tblProps, std::optional<TableIndexer> tblIndexer, DenseHashSet<TypeId>& result, NotNull<TypeFamilyContext> ctx)
|
||||
TypeId ty, TableType::Props tblProps, std::optional<TableIndexer> tblIndexer, DenseHashSet<TypeId>& result, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
ty = follow(ty);
|
||||
|
||||
@ -1920,7 +1920,7 @@ bool searchPropsAndIndexer(
|
||||
/* Handles recursion / metamethods of tables/classes
|
||||
`isRaw` parameter indicates whether or not we should follow __index metamethods
|
||||
returns false if property of `ty` could not be found */
|
||||
bool tblIndexInto(TypeId indexer, TypeId indexee, DenseHashSet<TypeId>& result, NotNull<TypeFamilyContext> ctx, bool isRaw)
|
||||
bool tblIndexInto(TypeId indexer, TypeId indexee, DenseHashSet<TypeId>& result, NotNull<TypeFunctionContext> ctx, bool isRaw)
|
||||
{
|
||||
indexer = follow(indexer);
|
||||
indexee = follow(indexee);
|
||||
@ -1960,8 +1960,8 @@ bool tblIndexInto(TypeId indexer, TypeId indexee, DenseHashSet<TypeId>& result,
|
||||
/* Vocabulary note: indexee refers to the type that contains the properties,
|
||||
indexer refers to the type that is used to access indexee
|
||||
Example: index<Person, "name"> => `Person` is the indexee and `"name"` is the indexer */
|
||||
TypeFamilyReductionResult<TypeId> indexFamilyImpl(
|
||||
const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx, bool isRaw)
|
||||
TypeFunctionReductionResult<TypeId> indexFamilyImpl(
|
||||
const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx, bool isRaw)
|
||||
{
|
||||
TypeId indexeeTy = follow(typeParams.at(0));
|
||||
std::shared_ptr<const NormalizedType> indexeeNormTy = ctx->normalizer->normalize(indexeeTy);
|
||||
@ -2064,104 +2064,104 @@ TypeFamilyReductionResult<TypeId> indexFamilyImpl(
|
||||
return {ctx->arena->addType(UnionType{std::vector<TypeId>(properties.begin(), properties.end())}), false, {}, {}};
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> indexFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> indexFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("index type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("index type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
return indexFamilyImpl(typeParams, packParams, ctx, /* isRaw */ false);
|
||||
}
|
||||
|
||||
TypeFamilyReductionResult<TypeId> rawgetFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFamilyContext> ctx)
|
||||
TypeFunctionReductionResult<TypeId> rawgetFamilyFn(
|
||||
TypeId instance, const std::vector<TypeId>& typeParams, const std::vector<TypePackId>& packParams, NotNull<TypeFunctionContext> ctx)
|
||||
{
|
||||
if (typeParams.size() != 2 || !packParams.empty())
|
||||
{
|
||||
ctx->ice->ice("rawget type family: encountered a type family instance without the required argument structure");
|
||||
ctx->ice->ice("rawget type function: encountered a type function instance without the required argument structure");
|
||||
LUAU_ASSERT(false);
|
||||
}
|
||||
|
||||
return indexFamilyImpl(typeParams, packParams, ctx, /* isRaw */ true);
|
||||
}
|
||||
|
||||
BuiltinTypeFamilies::BuiltinTypeFamilies()
|
||||
: notFamily{"not", notFamilyFn}
|
||||
, lenFamily{"len", lenFamilyFn}
|
||||
, unmFamily{"unm", unmFamilyFn}
|
||||
, addFamily{"add", addFamilyFn}
|
||||
, subFamily{"sub", subFamilyFn}
|
||||
, mulFamily{"mul", mulFamilyFn}
|
||||
, divFamily{"div", divFamilyFn}
|
||||
, idivFamily{"idiv", idivFamilyFn}
|
||||
, powFamily{"pow", powFamilyFn}
|
||||
, modFamily{"mod", modFamilyFn}
|
||||
, concatFamily{"concat", concatFamilyFn}
|
||||
, andFamily{"and", andFamilyFn}
|
||||
, orFamily{"or", orFamilyFn}
|
||||
, ltFamily{"lt", ltFamilyFn}
|
||||
, leFamily{"le", leFamilyFn}
|
||||
, eqFamily{"eq", eqFamilyFn}
|
||||
, refineFamily{"refine", refineFamilyFn}
|
||||
, singletonFamily{"singleton", singletonFamilyFn}
|
||||
, unionFamily{"union", unionFamilyFn}
|
||||
, intersectFamily{"intersect", intersectFamilyFn}
|
||||
, keyofFamily{"keyof", keyofFamilyFn}
|
||||
, rawkeyofFamily{"rawkeyof", rawkeyofFamilyFn}
|
||||
, indexFamily{"index", indexFamilyFn}
|
||||
, rawgetFamily{"rawget", rawgetFamilyFn}
|
||||
BuiltinTypeFunctions::BuiltinTypeFunctions()
|
||||
: notFunc{"not", notFamilyFn}
|
||||
, lenFunc{"len", lenFamilyFn}
|
||||
, unmFunc{"unm", unmFamilyFn}
|
||||
, addFunc{"add", addFamilyFn}
|
||||
, subFunc{"sub", subFamilyFn}
|
||||
, mulFunc{"mul", mulFamilyFn}
|
||||
, divFunc{"div", divFamilyFn}
|
||||
, idivFunc{"idiv", idivFamilyFn}
|
||||
, powFunc{"pow", powFamilyFn}
|
||||
, modFunc{"mod", modFamilyFn}
|
||||
, concatFunc{"concat", concatFamilyFn}
|
||||
, andFunc{"and", andFamilyFn}
|
||||
, orFunc{"or", orFamilyFn}
|
||||
, ltFunc{"lt", ltFamilyFn}
|
||||
, leFunc{"le", leFamilyFn}
|
||||
, eqFunc{"eq", eqFamilyFn}
|
||||
, refineFunc{"refine", refineFamilyFn}
|
||||
, singletonFunc{"singleton", singletonFamilyFn}
|
||||
, unionFunc{"union", unionFamilyFn}
|
||||
, intersectFunc{"intersect", intersectFamilyFn}
|
||||
, keyofFunc{"keyof", keyofFamilyFn}
|
||||
, rawkeyofFunc{"rawkeyof", rawkeyofFamilyFn}
|
||||
, indexFunc{"index", indexFamilyFn}
|
||||
, rawgetFunc{"rawget", rawgetFamilyFn}
|
||||
{
|
||||
}
|
||||
|
||||
void BuiltinTypeFamilies::addToScope(NotNull<TypeArena> arena, NotNull<Scope> scope) const
|
||||
void BuiltinTypeFunctions::addToScope(NotNull<TypeArena> arena, NotNull<Scope> scope) const
|
||||
{
|
||||
// make a type function for a one-argument type family
|
||||
auto mkUnaryTypeFamily = [&](const TypeFamily* family) {
|
||||
// make a type function for a one-argument type function
|
||||
auto mkUnaryTypeFunction = [&](const TypeFunction* tf) {
|
||||
TypeId t = arena->addType(GenericType{"T"});
|
||||
GenericTypeDefinition genericT{t};
|
||||
|
||||
return TypeFun{{genericT}, arena->addType(TypeFamilyInstanceType{NotNull{family}, {t}, {}})};
|
||||
return TypeFun{{genericT}, arena->addType(TypeFunctionInstanceType{NotNull{tf}, {t}, {}})};
|
||||
};
|
||||
|
||||
// make a type function for a two-argument type family
|
||||
auto mkBinaryTypeFamily = [&](const TypeFamily* family) {
|
||||
// make a type function for a two-argument type function
|
||||
auto mkBinaryTypeFunction = [&](const TypeFunction* tf) {
|
||||
TypeId t = arena->addType(GenericType{"T"});
|
||||
TypeId u = arena->addType(GenericType{"U"});
|
||||
GenericTypeDefinition genericT{t};
|
||||
GenericTypeDefinition genericU{u, {t}};
|
||||
|
||||
return TypeFun{{genericT, genericU}, arena->addType(TypeFamilyInstanceType{NotNull{family}, {t, u}, {}})};
|
||||
return TypeFun{{genericT, genericU}, arena->addType(TypeFunctionInstanceType{NotNull{tf}, {t, u}, {}})};
|
||||
};
|
||||
|
||||
scope->exportedTypeBindings[lenFamily.name] = mkUnaryTypeFamily(&lenFamily);
|
||||
scope->exportedTypeBindings[unmFamily.name] = mkUnaryTypeFamily(&unmFamily);
|
||||
scope->exportedTypeBindings[lenFunc.name] = mkUnaryTypeFunction(&lenFunc);
|
||||
scope->exportedTypeBindings[unmFunc.name] = mkUnaryTypeFunction(&unmFunc);
|
||||
|
||||
scope->exportedTypeBindings[addFamily.name] = mkBinaryTypeFamily(&addFamily);
|
||||
scope->exportedTypeBindings[subFamily.name] = mkBinaryTypeFamily(&subFamily);
|
||||
scope->exportedTypeBindings[mulFamily.name] = mkBinaryTypeFamily(&mulFamily);
|
||||
scope->exportedTypeBindings[divFamily.name] = mkBinaryTypeFamily(&divFamily);
|
||||
scope->exportedTypeBindings[idivFamily.name] = mkBinaryTypeFamily(&idivFamily);
|
||||
scope->exportedTypeBindings[powFamily.name] = mkBinaryTypeFamily(&powFamily);
|
||||
scope->exportedTypeBindings[modFamily.name] = mkBinaryTypeFamily(&modFamily);
|
||||
scope->exportedTypeBindings[concatFamily.name] = mkBinaryTypeFamily(&concatFamily);
|
||||
scope->exportedTypeBindings[addFunc.name] = mkBinaryTypeFunction(&addFunc);
|
||||
scope->exportedTypeBindings[subFunc.name] = mkBinaryTypeFunction(&subFunc);
|
||||
scope->exportedTypeBindings[mulFunc.name] = mkBinaryTypeFunction(&mulFunc);
|
||||
scope->exportedTypeBindings[divFunc.name] = mkBinaryTypeFunction(&divFunc);
|
||||
scope->exportedTypeBindings[idivFunc.name] = mkBinaryTypeFunction(&idivFunc);
|
||||
scope->exportedTypeBindings[powFunc.name] = mkBinaryTypeFunction(&powFunc);
|
||||
scope->exportedTypeBindings[modFunc.name] = mkBinaryTypeFunction(&modFunc);
|
||||
scope->exportedTypeBindings[concatFunc.name] = mkBinaryTypeFunction(&concatFunc);
|
||||
|
||||
scope->exportedTypeBindings[ltFamily.name] = mkBinaryTypeFamily(<Family);
|
||||
scope->exportedTypeBindings[leFamily.name] = mkBinaryTypeFamily(&leFamily);
|
||||
scope->exportedTypeBindings[eqFamily.name] = mkBinaryTypeFamily(&eqFamily);
|
||||
scope->exportedTypeBindings[ltFunc.name] = mkBinaryTypeFunction(<Func);
|
||||
scope->exportedTypeBindings[leFunc.name] = mkBinaryTypeFunction(&leFunc);
|
||||
scope->exportedTypeBindings[eqFunc.name] = mkBinaryTypeFunction(&eqFunc);
|
||||
|
||||
scope->exportedTypeBindings[keyofFamily.name] = mkUnaryTypeFamily(&keyofFamily);
|
||||
scope->exportedTypeBindings[rawkeyofFamily.name] = mkUnaryTypeFamily(&rawkeyofFamily);
|
||||
scope->exportedTypeBindings[keyofFunc.name] = mkUnaryTypeFunction(&keyofFunc);
|
||||
scope->exportedTypeBindings[rawkeyofFunc.name] = mkUnaryTypeFunction(&rawkeyofFunc);
|
||||
|
||||
scope->exportedTypeBindings[indexFamily.name] = mkBinaryTypeFamily(&indexFamily);
|
||||
scope->exportedTypeBindings[rawgetFamily.name] = mkBinaryTypeFamily(&rawgetFamily);
|
||||
scope->exportedTypeBindings[indexFunc.name] = mkBinaryTypeFunction(&indexFunc);
|
||||
scope->exportedTypeBindings[rawgetFunc.name] = mkBinaryTypeFunction(&rawgetFunc);
|
||||
}
|
||||
|
||||
const BuiltinTypeFamilies& builtinTypeFunctions()
|
||||
const BuiltinTypeFunctions& builtinTypeFunctions()
|
||||
{
|
||||
static std::unique_ptr<const BuiltinTypeFamilies> result = std::make_unique<BuiltinTypeFamilies>();
|
||||
static std::unique_ptr<const BuiltinTypeFunctions> result = std::make_unique<BuiltinTypeFunctions>();
|
||||
|
||||
return *result;
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
#include "Luau/TypeFamilyReductionGuesser.h"
|
||||
#include "Luau/TypeFunctionReductionGuesser.h"
|
||||
|
||||
#include "Luau/DenseHash.h"
|
||||
#include "Luau/Normalize.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/TypeUtils.h"
|
||||
@ -23,7 +23,7 @@ struct InstanceCollector2 : TypeOnceVisitor
|
||||
DenseHashSet<TypeId> cyclicInstance{nullptr};
|
||||
DenseHashSet<TypeId> instanceArguments{nullptr};
|
||||
|
||||
bool visit(TypeId ty, const TypeFamilyInstanceType& it) override
|
||||
bool visit(TypeId ty, const TypeFunctionInstanceType& it) override
|
||||
{
|
||||
// TypeOnceVisitor performs a depth-first traversal in the absence of
|
||||
// cycles. This means that by pushing to the front of the queue, we will
|
||||
@ -41,7 +41,7 @@ struct InstanceCollector2 : TypeOnceVisitor
|
||||
{
|
||||
/// Detected cyclic type pack
|
||||
TypeId t = follow(ty);
|
||||
if (get<TypeFamilyInstanceType>(t))
|
||||
if (get<TypeFunctionInstanceType>(t))
|
||||
cyclicInstance.insert(t);
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ struct InstanceCollector2 : TypeOnceVisitor
|
||||
return false;
|
||||
}
|
||||
|
||||
bool visit(TypePackId tp, const TypeFamilyInstanceTypePack&) override
|
||||
bool visit(TypePackId tp, const TypeFunctionInstanceTypePack&) override
|
||||
{
|
||||
// TypeOnceVisitor performs a depth-first traversal in the absence of
|
||||
// cycles. This means that by pushing to the front of the queue, we will
|
||||
@ -65,14 +65,14 @@ struct InstanceCollector2 : TypeOnceVisitor
|
||||
|
||||
|
||||
|
||||
TypeFamilyReductionGuesser::TypeFamilyReductionGuesser(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtins, NotNull<Normalizer> normalizer)
|
||||
TypeFunctionReductionGuesser::TypeFunctionReductionGuesser(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtins, NotNull<Normalizer> normalizer)
|
||||
: arena(arena)
|
||||
, builtins(builtins)
|
||||
, normalizer(normalizer)
|
||||
{
|
||||
}
|
||||
|
||||
bool TypeFamilyReductionGuesser::isFunctionGenericsSaturated(const FunctionType& ftv, DenseHashSet<TypeId>& argsUsed)
|
||||
bool TypeFunctionReductionGuesser::isFunctionGenericsSaturated(const FunctionType& ftv, DenseHashSet<TypeId>& argsUsed)
|
||||
{
|
||||
bool sameSize = ftv.generics.size() == argsUsed.size();
|
||||
bool allGenericsAppear = true;
|
||||
@ -81,7 +81,7 @@ bool TypeFamilyReductionGuesser::isFunctionGenericsSaturated(const FunctionType&
|
||||
return sameSize && allGenericsAppear;
|
||||
}
|
||||
|
||||
void TypeFamilyReductionGuesser::dumpGuesses()
|
||||
void TypeFunctionReductionGuesser::dumpGuesses()
|
||||
{
|
||||
for (auto [tf, t] : familyReducesTo)
|
||||
printf("Type family %s ~~> %s\n", toString(tf).c_str(), toString(t).c_str());
|
||||
@ -89,7 +89,7 @@ void TypeFamilyReductionGuesser::dumpGuesses()
|
||||
printf("Substitute %s for %s\n", toString(t).c_str(), toString(t_).c_str());
|
||||
}
|
||||
|
||||
std::optional<TypeId> TypeFamilyReductionGuesser::guess(TypeId typ)
|
||||
std::optional<TypeId> TypeFunctionReductionGuesser::guess(TypeId typ)
|
||||
{
|
||||
std::optional<TypeId> guessedType = guessType(typ);
|
||||
|
||||
@ -97,13 +97,13 @@ std::optional<TypeId> TypeFamilyReductionGuesser::guess(TypeId typ)
|
||||
return {};
|
||||
|
||||
TypeId guess = follow(*guessedType);
|
||||
if (get<TypeFamilyInstanceType>(guess))
|
||||
if (get<TypeFunctionInstanceType>(guess))
|
||||
return {};
|
||||
|
||||
return guess;
|
||||
}
|
||||
|
||||
std::optional<TypePackId> TypeFamilyReductionGuesser::guess(TypePackId tp)
|
||||
std::optional<TypePackId> TypeFunctionReductionGuesser::guess(TypePackId tp)
|
||||
{
|
||||
auto [head, tail] = flatten(tp);
|
||||
|
||||
@ -118,7 +118,7 @@ std::optional<TypePackId> TypeFamilyReductionGuesser::guess(TypePackId tp)
|
||||
return {};
|
||||
|
||||
TypeId guess = follow(*guessedType);
|
||||
if (get<TypeFamilyInstanceType>(guess))
|
||||
if (get<TypeFunctionInstanceType>(guess))
|
||||
return {};
|
||||
|
||||
guessedHead.push_back(*guessedType);
|
||||
@ -127,7 +127,7 @@ std::optional<TypePackId> TypeFamilyReductionGuesser::guess(TypePackId tp)
|
||||
return arena->addTypePack(TypePack{guessedHead, tail});
|
||||
}
|
||||
|
||||
TypeFamilyReductionGuessResult TypeFamilyReductionGuesser::guessTypeFamilyReductionForFunction(
|
||||
TypeFunctionReductionGuessResult TypeFunctionReductionGuesser::guessTypeFunctionReductionForFunctionExpr(
|
||||
const AstExprFunction& expr, const FunctionType* ftv, TypeId retTy)
|
||||
{
|
||||
InstanceCollector2 collector;
|
||||
@ -136,7 +136,7 @@ TypeFamilyReductionGuessResult TypeFamilyReductionGuesser::guessTypeFamilyReduct
|
||||
cyclicInstances = std::move(collector.cyclicInstance);
|
||||
|
||||
if (isFunctionGenericsSaturated(*ftv, collector.instanceArguments))
|
||||
return TypeFamilyReductionGuessResult{{}, nullptr, false};
|
||||
return TypeFunctionReductionGuessResult{{}, nullptr, false};
|
||||
infer();
|
||||
|
||||
std::vector<std::pair<std::string, TypeId>> results;
|
||||
@ -157,7 +157,7 @@ TypeFamilyReductionGuessResult TypeFamilyReductionGuesser::guessTypeFamilyReduct
|
||||
if (!guessedType.has_value())
|
||||
continue;
|
||||
TypeId guess = follow(*guessedType);
|
||||
if (get<TypeFamilyInstanceType>(guess))
|
||||
if (get<TypeFunctionInstanceType>(guess))
|
||||
continue;
|
||||
|
||||
results.push_back({local->name.value, guess});
|
||||
@ -170,7 +170,7 @@ TypeFamilyReductionGuessResult TypeFamilyReductionGuesser::guessTypeFamilyReduct
|
||||
recommendedAnnotation = builtins->unknownType;
|
||||
else
|
||||
recommendedAnnotation = follow(*guessedReturnType);
|
||||
if (auto t = get<TypeFamilyInstanceType>(recommendedAnnotation))
|
||||
if (auto t = get<TypeFunctionInstanceType>(recommendedAnnotation))
|
||||
recommendedAnnotation = builtins->unknownType;
|
||||
|
||||
toInfer.clear();
|
||||
@ -178,10 +178,10 @@ TypeFamilyReductionGuessResult TypeFamilyReductionGuesser::guessTypeFamilyReduct
|
||||
familyReducesTo.clear();
|
||||
substitutable.clear();
|
||||
|
||||
return TypeFamilyReductionGuessResult{results, recommendedAnnotation};
|
||||
return TypeFunctionReductionGuessResult{results, recommendedAnnotation};
|
||||
}
|
||||
|
||||
std::optional<TypeId> TypeFamilyReductionGuesser::guessType(TypeId arg)
|
||||
std::optional<TypeId> TypeFunctionReductionGuesser::guessType(TypeId arg)
|
||||
{
|
||||
TypeId t = follow(arg);
|
||||
if (substitutable.contains(t))
|
||||
@ -189,12 +189,12 @@ std::optional<TypeId> TypeFamilyReductionGuesser::guessType(TypeId arg)
|
||||
TypeId subst = follow(substitutable[t]);
|
||||
if (subst == t || substitutable.contains(subst))
|
||||
return subst;
|
||||
else if (!get<TypeFamilyInstanceType>(subst))
|
||||
else if (!get<TypeFunctionInstanceType>(subst))
|
||||
return subst;
|
||||
else
|
||||
return guessType(subst);
|
||||
}
|
||||
if (get<TypeFamilyInstanceType>(t))
|
||||
if (get<TypeFunctionInstanceType>(t))
|
||||
{
|
||||
if (familyReducesTo.contains(t))
|
||||
return familyReducesTo[t];
|
||||
@ -202,41 +202,41 @@ std::optional<TypeId> TypeFamilyReductionGuesser::guessType(TypeId arg)
|
||||
return {};
|
||||
}
|
||||
|
||||
bool TypeFamilyReductionGuesser::isNumericBinopFamily(const TypeFamilyInstanceType& instance)
|
||||
bool TypeFunctionReductionGuesser::isNumericBinopFamily(const TypeFunctionInstanceType& instance)
|
||||
{
|
||||
return instance.family->name == "add" || instance.family->name == "sub" || instance.family->name == "mul" || instance.family->name == "div" ||
|
||||
instance.family->name == "idiv" || instance.family->name == "pow" || instance.family->name == "mod";
|
||||
}
|
||||
|
||||
bool TypeFamilyReductionGuesser::isComparisonFamily(const TypeFamilyInstanceType& instance)
|
||||
bool TypeFunctionReductionGuesser::isComparisonFamily(const TypeFunctionInstanceType& instance)
|
||||
{
|
||||
return instance.family->name == "lt" || instance.family->name == "le" || instance.family->name == "eq";
|
||||
}
|
||||
|
||||
bool TypeFamilyReductionGuesser::isOrAndFamily(const TypeFamilyInstanceType& instance)
|
||||
bool TypeFunctionReductionGuesser::isOrAndFamily(const TypeFunctionInstanceType& instance)
|
||||
{
|
||||
return instance.family->name == "or" || instance.family->name == "and";
|
||||
}
|
||||
|
||||
bool TypeFamilyReductionGuesser::isNotFamily(const TypeFamilyInstanceType& instance)
|
||||
bool TypeFunctionReductionGuesser::isNotFamily(const TypeFunctionInstanceType& instance)
|
||||
{
|
||||
return instance.family->name == "not";
|
||||
}
|
||||
|
||||
bool TypeFamilyReductionGuesser::isLenFamily(const TypeFamilyInstanceType& instance)
|
||||
bool TypeFunctionReductionGuesser::isLenFamily(const TypeFunctionInstanceType& instance)
|
||||
{
|
||||
return instance.family->name == "len";
|
||||
}
|
||||
|
||||
bool TypeFamilyReductionGuesser::isUnaryMinus(const TypeFamilyInstanceType& instance)
|
||||
bool TypeFunctionReductionGuesser::isUnaryMinus(const TypeFunctionInstanceType& instance)
|
||||
{
|
||||
return instance.family->name == "unm";
|
||||
}
|
||||
|
||||
// Operand is assignable if it looks like a cyclic family instance, or a generic type
|
||||
bool TypeFamilyReductionGuesser::operandIsAssignable(TypeId ty)
|
||||
bool TypeFunctionReductionGuesser::operandIsAssignable(TypeId ty)
|
||||
{
|
||||
if (get<TypeFamilyInstanceType>(ty))
|
||||
if (get<TypeFunctionInstanceType>(ty))
|
||||
return true;
|
||||
if (get<GenericType>(ty))
|
||||
return true;
|
||||
@ -245,17 +245,17 @@ bool TypeFamilyReductionGuesser::operandIsAssignable(TypeId ty)
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<const NormalizedType> TypeFamilyReductionGuesser::normalize(TypeId ty)
|
||||
std::shared_ptr<const NormalizedType> TypeFunctionReductionGuesser::normalize(TypeId ty)
|
||||
{
|
||||
return normalizer->normalize(ty);
|
||||
}
|
||||
|
||||
|
||||
std::optional<TypeId> TypeFamilyReductionGuesser::tryAssignOperandType(TypeId ty)
|
||||
std::optional<TypeId> TypeFunctionReductionGuesser::tryAssignOperandType(TypeId ty)
|
||||
{
|
||||
// Because we collect innermost instances first, if we see a typefamily instance as an operand,
|
||||
// Because we collect innermost instances first, if we see a type function instance as an operand,
|
||||
// We try to check if we guessed a type for it
|
||||
if (auto tfit = get<TypeFamilyInstanceType>(ty))
|
||||
if (auto tfit = get<TypeFunctionInstanceType>(ty))
|
||||
{
|
||||
if (familyReducesTo.contains(ty))
|
||||
return {familyReducesTo[ty]};
|
||||
@ -272,30 +272,30 @@ std::optional<TypeId> TypeFamilyReductionGuesser::tryAssignOperandType(TypeId ty
|
||||
return {};
|
||||
}
|
||||
|
||||
void TypeFamilyReductionGuesser::step()
|
||||
void TypeFunctionReductionGuesser::step()
|
||||
{
|
||||
TypeId t = toInfer.front();
|
||||
toInfer.pop_front();
|
||||
t = follow(t);
|
||||
if (auto tf = get<TypeFamilyInstanceType>(t))
|
||||
inferTypeFamilySubstitutions(t, tf);
|
||||
if (auto tf = get<TypeFunctionInstanceType>(t))
|
||||
inferTypeFunctionSubstitutions(t, tf);
|
||||
}
|
||||
|
||||
void TypeFamilyReductionGuesser::infer()
|
||||
void TypeFunctionReductionGuesser::infer()
|
||||
{
|
||||
while (!done())
|
||||
step();
|
||||
}
|
||||
|
||||
bool TypeFamilyReductionGuesser::done()
|
||||
bool TypeFunctionReductionGuesser::done()
|
||||
{
|
||||
return toInfer.empty();
|
||||
}
|
||||
|
||||
void TypeFamilyReductionGuesser::inferTypeFamilySubstitutions(TypeId ty, const TypeFamilyInstanceType* instance)
|
||||
void TypeFunctionReductionGuesser::inferTypeFunctionSubstitutions(TypeId ty, const TypeFunctionInstanceType* instance)
|
||||
{
|
||||
|
||||
TypeFamilyInferenceResult result;
|
||||
TypeFunctionInferenceResult result;
|
||||
LUAU_ASSERT(instance);
|
||||
// TODO: Make an inexhaustive version of this warn in the compiler?
|
||||
if (isNumericBinopFamily(*instance))
|
||||
@ -323,7 +323,7 @@ void TypeFamilyReductionGuesser::inferTypeFamilySubstitutions(TypeId ty, const T
|
||||
{
|
||||
TypeId arg = follow(instance->typeArguments[i]);
|
||||
TypeId inference = follow(result.operandInference[i]);
|
||||
if (auto tfit = get<TypeFamilyInstanceType>(arg))
|
||||
if (auto tfit = get<TypeFunctionInstanceType>(arg))
|
||||
{
|
||||
if (!familyReducesTo.contains(arg))
|
||||
familyReducesTo.try_insert(arg, inference);
|
||||
@ -334,14 +334,14 @@ void TypeFamilyReductionGuesser::inferTypeFamilySubstitutions(TypeId ty, const T
|
||||
}
|
||||
}
|
||||
|
||||
TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferNumericBinopFamily(const TypeFamilyInstanceType* instance)
|
||||
TypeFunctionInferenceResult TypeFunctionReductionGuesser::inferNumericBinopFamily(const TypeFunctionInstanceType* instance)
|
||||
{
|
||||
LUAU_ASSERT(instance->typeArguments.size() == 2);
|
||||
TypeFamilyInferenceResult defaultNumericBinopInference{{builtins->numberType, builtins->numberType}, builtins->numberType};
|
||||
TypeFunctionInferenceResult defaultNumericBinopInference{{builtins->numberType, builtins->numberType}, builtins->numberType};
|
||||
return defaultNumericBinopInference;
|
||||
}
|
||||
|
||||
TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferComparisonFamily(const TypeFamilyInstanceType* instance)
|
||||
TypeFunctionInferenceResult TypeFunctionReductionGuesser::inferComparisonFamily(const TypeFunctionInstanceType* instance)
|
||||
{
|
||||
LUAU_ASSERT(instance->typeArguments.size() == 2);
|
||||
// Comparison families are lt/le/eq.
|
||||
@ -350,8 +350,8 @@ TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferComparisonFamily(cons
|
||||
TypeId lhsTy = follow(instance->typeArguments[0]);
|
||||
TypeId rhsTy = follow(instance->typeArguments[1]);
|
||||
|
||||
auto comparisonInference = [&](TypeId op) -> TypeFamilyInferenceResult {
|
||||
return TypeFamilyInferenceResult{{op, op}, builtins->booleanType};
|
||||
auto comparisonInference = [&](TypeId op) -> TypeFunctionInferenceResult {
|
||||
return TypeFunctionInferenceResult{{op, op}, builtins->booleanType};
|
||||
};
|
||||
|
||||
if (std::optional<TypeId> ty = tryAssignOperandType(lhsTy))
|
||||
@ -365,7 +365,7 @@ TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferComparisonFamily(cons
|
||||
return comparisonInference(builtins->numberType);
|
||||
}
|
||||
|
||||
TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferOrAndFamily(const TypeFamilyInstanceType* instance)
|
||||
TypeFunctionInferenceResult TypeFunctionReductionGuesser::inferOrAndFamily(const TypeFunctionInstanceType* instance)
|
||||
{
|
||||
|
||||
LUAU_ASSERT(instance->typeArguments.size() == 2);
|
||||
@ -377,7 +377,7 @@ TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferOrAndFamily(const Typ
|
||||
lhsTy = follow(*ty);
|
||||
if (std::optional<TypeId> ty = tryAssignOperandType(rhsTy))
|
||||
rhsTy = follow(*ty);
|
||||
TypeFamilyInferenceResult defaultAndOrInference{{builtins->unknownType, builtins->unknownType}, builtins->booleanType};
|
||||
TypeFunctionInferenceResult defaultAndOrInference{{builtins->unknownType, builtins->unknownType}, builtins->booleanType};
|
||||
|
||||
std::shared_ptr<const NormalizedType> lty = normalize(lhsTy);
|
||||
std::shared_ptr<const NormalizedType> rty = normalize(lhsTy);
|
||||
@ -389,9 +389,9 @@ TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferOrAndFamily(const Typ
|
||||
if (operandIsAssignable(lhsTy) && operandIsAssignable(rhsTy))
|
||||
return defaultAndOrInference;
|
||||
if (operandIsAssignable(lhsTy))
|
||||
return TypeFamilyInferenceResult{{builtins->unknownType, rhsTy}, rhsTy};
|
||||
return TypeFunctionInferenceResult{{builtins->unknownType, rhsTy}, rhsTy};
|
||||
if (operandIsAssignable(rhsTy))
|
||||
return TypeFamilyInferenceResult{{lhsTy, builtins->unknownType}, lhsTy};
|
||||
return TypeFunctionInferenceResult{{lhsTy, builtins->unknownType}, lhsTy};
|
||||
if (lhsTruthy)
|
||||
return {{lhsTy, rhsTy}, lhsTy};
|
||||
if (rhsTruthy)
|
||||
@ -404,9 +404,9 @@ TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferOrAndFamily(const Typ
|
||||
if (operandIsAssignable(lhsTy) && operandIsAssignable(rhsTy))
|
||||
return defaultAndOrInference;
|
||||
if (operandIsAssignable(lhsTy))
|
||||
return TypeFamilyInferenceResult{{}, rhsTy};
|
||||
return TypeFunctionInferenceResult{{}, rhsTy};
|
||||
if (operandIsAssignable(rhsTy))
|
||||
return TypeFamilyInferenceResult{{}, lhsTy};
|
||||
return TypeFunctionInferenceResult{{}, lhsTy};
|
||||
if (lhsTruthy)
|
||||
return {{lhsTy, rhsTy}, rhsTy};
|
||||
else
|
||||
@ -416,7 +416,7 @@ TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferOrAndFamily(const Typ
|
||||
return defaultAndOrInference;
|
||||
}
|
||||
|
||||
TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferNotFamily(const TypeFamilyInstanceType* instance)
|
||||
TypeFunctionInferenceResult TypeFunctionReductionGuesser::inferNotFamily(const TypeFunctionInstanceType* instance)
|
||||
{
|
||||
LUAU_ASSERT(instance->typeArguments.size() == 1);
|
||||
TypeId opTy = follow(instance->typeArguments[0]);
|
||||
@ -425,7 +425,7 @@ TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferNotFamily(const TypeF
|
||||
return {{opTy}, builtins->booleanType};
|
||||
}
|
||||
|
||||
TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferLenFamily(const TypeFamilyInstanceType* instance)
|
||||
TypeFunctionInferenceResult TypeFunctionReductionGuesser::inferLenFamily(const TypeFunctionInstanceType* instance)
|
||||
{
|
||||
LUAU_ASSERT(instance->typeArguments.size() == 1);
|
||||
TypeId opTy = follow(instance->typeArguments[0]);
|
||||
@ -434,7 +434,7 @@ TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferLenFamily(const TypeF
|
||||
return {{opTy}, builtins->numberType};
|
||||
}
|
||||
|
||||
TypeFamilyInferenceResult TypeFamilyReductionGuesser::inferUnaryMinusFamily(const TypeFamilyInstanceType* instance)
|
||||
TypeFunctionInferenceResult TypeFunctionReductionGuesser::inferUnaryMinusFamily(const TypeFunctionInstanceType* instance)
|
||||
{
|
||||
LUAU_ASSERT(instance->typeArguments.size() == 1);
|
||||
TypeId opTy = follow(instance->typeArguments[0]);
|
@ -454,11 +454,11 @@ void Unifier::tryUnify_(TypeId subTy, TypeId superTy, bool isFunctionCall, bool
|
||||
else if (isBlocked(log, superTy))
|
||||
blockedTypes.push_back(superTy);
|
||||
|
||||
if (log.get<TypeFamilyInstanceType>(superTy))
|
||||
ice("Unexpected TypeFamilyInstanceType superTy");
|
||||
if (log.get<TypeFunctionInstanceType>(superTy))
|
||||
ice("Unexpected TypeFunctionInstanceType superTy");
|
||||
|
||||
if (log.get<TypeFamilyInstanceType>(subTy))
|
||||
ice("Unexpected TypeFamilyInstanceType subTy");
|
||||
if (log.get<TypeFunctionInstanceType>(subTy))
|
||||
ice("Unexpected TypeFunctionInstanceType subTy");
|
||||
|
||||
auto superFree = log.getMutable<FreeType>(superTy);
|
||||
auto subFree = log.getMutable<FreeType>(subTy);
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypeArena.h"
|
||||
#include "Luau/TypeCheckLimits.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
#include "Luau/TypeFwd.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/TypeUtils.h"
|
||||
@ -76,13 +76,13 @@ static bool areCompatible(TypeId left, TypeId right)
|
||||
// returns `true` if `ty` is irressolvable and should be added to `incompleteSubtypes`.
|
||||
static bool isIrresolvable(TypeId ty)
|
||||
{
|
||||
return get<BlockedType>(ty) || get<TypeFamilyInstanceType>(ty);
|
||||
return get<BlockedType>(ty) || get<TypeFunctionInstanceType>(ty);
|
||||
}
|
||||
|
||||
// returns `true` if `tp` is irressolvable and should be added to `incompleteSubtypes`.
|
||||
static bool isIrresolvable(TypePackId tp)
|
||||
{
|
||||
return get<BlockedTypePack>(tp) || get<TypeFamilyInstanceTypePack>(tp);
|
||||
return get<BlockedTypePack>(tp) || get<TypeFunctionInstanceTypePack>(tp);
|
||||
}
|
||||
|
||||
Unifier2::Unifier2(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtinTypes, NotNull<Scope> scope, NotNull<InternalErrorReporter> ice)
|
||||
|
@ -13,8 +13,6 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(LuauCodegenInstG, false)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
@ -54,8 +52,6 @@ void updateUseCounts(IrFunction& function)
|
||||
checkOp(inst.d);
|
||||
checkOp(inst.e);
|
||||
checkOp(inst.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
checkOp(inst.g);
|
||||
}
|
||||
}
|
||||
@ -100,8 +96,6 @@ void updateLastUseLocations(IrFunction& function, const std::vector<uint32_t>& s
|
||||
checkOp(inst.d);
|
||||
checkOp(inst.e);
|
||||
checkOp(inst.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
checkOp(inst.g);
|
||||
}
|
||||
}
|
||||
@ -137,12 +131,9 @@ uint32_t getNextInstUse(IrFunction& function, uint32_t targetInstIdx, uint32_t s
|
||||
if (inst.f.kind == IrOpKind::Inst && inst.f.index == targetInstIdx)
|
||||
return i;
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
{
|
||||
if (inst.g.kind == IrOpKind::Inst && inst.g.index == targetInstIdx)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// There must be a next use since there is the last use location
|
||||
CODEGEN_ASSERT(!"Failed to find next use");
|
||||
@ -179,8 +170,6 @@ std::pair<uint32_t, uint32_t> getLiveInOutValueCount(IrFunction& function, IrBlo
|
||||
checkOp(inst.d);
|
||||
checkOp(inst.e);
|
||||
checkOp(inst.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
checkOp(inst.g);
|
||||
}
|
||||
|
||||
@ -505,8 +494,6 @@ static void computeCfgBlockEdges(IrFunction& function)
|
||||
checkOp(inst.d);
|
||||
checkOp(inst.e);
|
||||
checkOp(inst.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
checkOp(inst.g);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
LUAU_FASTFLAG(LuauCodegenInstG)
|
||||
LUAU_FASTFLAG(LuauCodegenFastcall3)
|
||||
|
||||
namespace Luau
|
||||
@ -641,8 +640,6 @@ void IrBuilder::clone(const IrBlock& source, bool removeCurrentTerminator)
|
||||
redirect(clone.d);
|
||||
redirect(clone.e);
|
||||
redirect(clone.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
redirect(clone.g);
|
||||
|
||||
addUse(function, clone.a);
|
||||
@ -651,18 +648,13 @@ void IrBuilder::clone(const IrBlock& source, bool removeCurrentTerminator)
|
||||
addUse(function, clone.d);
|
||||
addUse(function, clone.e);
|
||||
addUse(function, clone.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
addUse(function, clone.g);
|
||||
|
||||
// Instructions that referenced the original will have to be adjusted to use the clone
|
||||
instRedir[index] = uint32_t(function.instructions.size());
|
||||
|
||||
// Reconstruct the fresh clone
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
inst(clone.cmd, clone.a, clone.b, clone.c, clone.d, clone.e, clone.f, clone.g);
|
||||
else
|
||||
inst(clone.cmd, clone.a, clone.b, clone.c, clone.d, clone.e, clone.f);
|
||||
}
|
||||
}
|
||||
|
||||
@ -760,31 +752,11 @@ IrOp IrBuilder::inst(IrCmd cmd, IrOp a, IrOp b, IrOp c, IrOp d, IrOp e)
|
||||
|
||||
IrOp IrBuilder::inst(IrCmd cmd, IrOp a, IrOp b, IrOp c, IrOp d, IrOp e, IrOp f)
|
||||
{
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
{
|
||||
return inst(cmd, a, b, c, d, e, f, {});
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t index = uint32_t(function.instructions.size());
|
||||
function.instructions.push_back({cmd, a, b, c, d, e, f});
|
||||
|
||||
CODEGEN_ASSERT(!inTerminatedBlock);
|
||||
|
||||
if (isBlockTerminator(cmd))
|
||||
{
|
||||
function.blocks[activeBlockIdx].finish = index;
|
||||
inTerminatedBlock = true;
|
||||
}
|
||||
|
||||
return {IrOpKind::Inst, index};
|
||||
}
|
||||
}
|
||||
|
||||
IrOp IrBuilder::inst(IrCmd cmd, IrOp a, IrOp b, IrOp c, IrOp d, IrOp e, IrOp f, IrOp g)
|
||||
{
|
||||
CODEGEN_ASSERT(FFlag::LuauCodegenInstG);
|
||||
|
||||
uint32_t index = uint32_t(function.instructions.size());
|
||||
function.instructions.push_back({cmd, a, b, c, d, e, f, g});
|
||||
|
||||
|
@ -7,8 +7,6 @@
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
LUAU_FASTFLAG(LuauCodegenInstG)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
@ -419,8 +417,6 @@ void toString(IrToStringContext& ctx, const IrInst& inst, uint32_t index)
|
||||
checkOp(inst.d, ", ");
|
||||
checkOp(inst.e, ", ");
|
||||
checkOp(inst.f, ", ");
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
checkOp(inst.g, ", ");
|
||||
}
|
||||
|
||||
@ -611,7 +607,7 @@ static RegisterSet getJumpTargetExtraLiveIn(IrToStringContext& ctx, const IrBloc
|
||||
op = inst.e;
|
||||
else if (inst.f.kind == IrOpKind::Block)
|
||||
op = inst.f;
|
||||
else if (FFlag::LuauCodegenInstG && inst.g.kind == IrOpKind::Block)
|
||||
else if (inst.g.kind == IrOpKind::Block)
|
||||
op = inst.g;
|
||||
|
||||
if (op.kind == IrOpKind::Block && op.index < ctx.cfg.in.size())
|
||||
@ -897,8 +893,6 @@ std::string toDot(const IrFunction& function, bool includeInst)
|
||||
checkOp(inst.d);
|
||||
checkOp(inst.e);
|
||||
checkOp(inst.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
checkOp(inst.g);
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include <string.h>
|
||||
|
||||
LUAU_FASTFLAGVARIABLE(DebugCodegenChaosA64, false)
|
||||
LUAU_FASTFLAG(LuauCodegenInstG)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
@ -257,8 +256,6 @@ void IrRegAllocA64::freeLastUseRegs(const IrInst& inst, uint32_t index)
|
||||
checkOp(inst.d);
|
||||
checkOp(inst.e);
|
||||
checkOp(inst.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
checkOp(inst.g);
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,6 @@
|
||||
|
||||
#include "EmitCommonX64.h"
|
||||
|
||||
LUAU_FASTFLAG(LuauCodegenInstG)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
@ -183,8 +181,6 @@ void IrRegAllocX64::freeLastUseRegs(const IrInst& inst, uint32_t instIdx)
|
||||
checkOp(inst.d);
|
||||
checkOp(inst.e);
|
||||
checkOp(inst.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
checkOp(inst.g);
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,6 @@
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
||||
LUAU_FASTFLAG(LuauCodegenInstG)
|
||||
|
||||
namespace Luau
|
||||
{
|
||||
namespace CodeGen
|
||||
@ -317,8 +315,6 @@ void kill(IrFunction& function, IrInst& inst)
|
||||
removeUse(function, inst.d);
|
||||
removeUse(function, inst.e);
|
||||
removeUse(function, inst.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
removeUse(function, inst.g);
|
||||
|
||||
inst.a = {};
|
||||
@ -327,8 +323,6 @@ void kill(IrFunction& function, IrInst& inst)
|
||||
inst.d = {};
|
||||
inst.e = {};
|
||||
inst.f = {};
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
inst.g = {};
|
||||
}
|
||||
|
||||
@ -378,8 +372,6 @@ void replace(IrFunction& function, IrBlock& block, uint32_t instIdx, IrInst repl
|
||||
addUse(function, replacement.d);
|
||||
addUse(function, replacement.e);
|
||||
addUse(function, replacement.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
addUse(function, replacement.g);
|
||||
|
||||
// An extra reference is added so block will not remove itself
|
||||
@ -403,8 +395,6 @@ void replace(IrFunction& function, IrBlock& block, uint32_t instIdx, IrInst repl
|
||||
removeUse(function, inst.d);
|
||||
removeUse(function, inst.e);
|
||||
removeUse(function, inst.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
removeUse(function, inst.g);
|
||||
|
||||
// Inherit existing use count (last use is skipped as it will be defined later)
|
||||
@ -431,8 +421,6 @@ void substitute(IrFunction& function, IrInst& inst, IrOp replacement)
|
||||
removeUse(function, inst.d);
|
||||
removeUse(function, inst.e);
|
||||
removeUse(function, inst.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
removeUse(function, inst.g);
|
||||
|
||||
inst.a = replacement;
|
||||
@ -441,8 +429,6 @@ void substitute(IrFunction& function, IrInst& inst, IrOp replacement)
|
||||
inst.d = {};
|
||||
inst.e = {};
|
||||
inst.f = {};
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
inst.g = {};
|
||||
}
|
||||
|
||||
@ -487,8 +473,6 @@ void applySubstitutions(IrFunction& function, IrInst& inst)
|
||||
applySubstitutions(function, inst.d);
|
||||
applySubstitutions(function, inst.e);
|
||||
applySubstitutions(function, inst.f);
|
||||
|
||||
if (FFlag::LuauCodegenInstG)
|
||||
applySubstitutions(function, inst.g);
|
||||
}
|
||||
|
||||
|
@ -219,8 +219,8 @@ target_sources(Luau.Analysis PRIVATE
|
||||
Analysis/include/Luau/TypeChecker2.h
|
||||
Analysis/include/Luau/TypeCheckLimits.h
|
||||
Analysis/include/Luau/TypedAllocator.h
|
||||
Analysis/include/Luau/TypeFamily.h
|
||||
Analysis/include/Luau/TypeFamilyReductionGuesser.h
|
||||
Analysis/include/Luau/TypeFunction.h
|
||||
Analysis/include/Luau/TypeFunctionReductionGuesser.h
|
||||
Analysis/include/Luau/TypeFwd.h
|
||||
Analysis/include/Luau/TypeInfer.h
|
||||
Analysis/include/Luau/TypeOrPack.h
|
||||
@ -283,8 +283,8 @@ target_sources(Luau.Analysis PRIVATE
|
||||
Analysis/src/TypeAttach.cpp
|
||||
Analysis/src/TypeChecker2.cpp
|
||||
Analysis/src/TypedAllocator.cpp
|
||||
Analysis/src/TypeFamily.cpp
|
||||
Analysis/src/TypeFamilyReductionGuesser.cpp
|
||||
Analysis/src/TypeFunction.cpp
|
||||
Analysis/src/TypeFunctionReductionGuesser.cpp
|
||||
Analysis/src/TypeInfer.cpp
|
||||
Analysis/src/TypeOrPack.cpp
|
||||
Analysis/src/TypePack.cpp
|
||||
@ -454,7 +454,7 @@ if(TARGET Luau.UnitTest)
|
||||
tests/ToString.test.cpp
|
||||
tests/Transpiler.test.cpp
|
||||
tests/TxnLog.test.cpp
|
||||
tests/TypeFamily.test.cpp
|
||||
tests/TypeFunction.test.cpp
|
||||
tests/TypeInfer.aliases.test.cpp
|
||||
tests/TypeInfer.annotations.test.cpp
|
||||
tests/TypeInfer.anyerror.test.cpp
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <limits.h>
|
||||
|
||||
LUAU_FASTFLAG(DebugLuauAbortingChecks)
|
||||
LUAU_FASTFLAG(LuauCodegenInstG)
|
||||
LUAU_FASTFLAG(LuauCodegenFastcall3)
|
||||
LUAU_FASTFLAG(LuauCodegenMathSign)
|
||||
|
||||
@ -1123,8 +1122,6 @@ bb_0:
|
||||
|
||||
TEST_CASE_FIXTURE(IrBuilderFixture, "BuiltinFastcallsMayInvalidateMemory")
|
||||
{
|
||||
ScopedFastFlag luauCodegenInstG{FFlag::LuauCodegenInstG, true};
|
||||
|
||||
IrOp block = build.block(IrBlockKind::Internal);
|
||||
IrOp fallback = build.block(IrBlockKind::Fallback);
|
||||
|
||||
@ -2814,7 +2811,6 @@ bb_1:
|
||||
|
||||
TEST_CASE_FIXTURE(IrBuilderFixture, "ExplicitUseOfRegisterInVarargSequence")
|
||||
{
|
||||
ScopedFastFlag luauCodegenInstG{FFlag::LuauCodegenInstG, true};
|
||||
ScopedFastFlag luauCodegenFastcall3{FFlag::LuauCodegenFastcall3, true};
|
||||
|
||||
IrOp entry = build.block(IrBlockKind::Internal);
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "Luau/Subtyping.h"
|
||||
#include "Luau/Type.h"
|
||||
#include "Luau/TypePack.h"
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
|
||||
#include "doctest.h"
|
||||
#include "Fixture.h"
|
||||
@ -73,7 +73,7 @@ struct SubtypeFixture : Fixture
|
||||
ScopePtr moduleScope{new Scope(rootScope)};
|
||||
|
||||
Subtyping subtyping = mkSubtyping(rootScope);
|
||||
BuiltinTypeFamilies builtinTypeFamilies{};
|
||||
BuiltinTypeFunctions builtinTypeFunctions{};
|
||||
|
||||
Subtyping mkSubtyping(const ScopePtr& scope)
|
||||
{
|
||||
@ -398,51 +398,51 @@ TEST_SUITE_BEGIN("Subtyping");
|
||||
TEST_IS_SUBTYPE(builtinTypes->numberType, builtinTypes->anyType);
|
||||
TEST_IS_NOT_SUBTYPE(builtinTypes->numberType, builtinTypes->stringType);
|
||||
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "basic_reducible_sub_typefamily")
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "basic_reducible_sub_type_function")
|
||||
{
|
||||
// add<number, number> <: number
|
||||
TypeId typeFamilyNum =
|
||||
arena.addType(TypeFamilyInstanceType{NotNull{&builtinTypeFamilies.addFamily}, {builtinTypes->numberType, builtinTypes->numberType}, {}});
|
||||
TypeId typeFunctionNum =
|
||||
arena.addType(TypeFunctionInstanceType{NotNull{&builtinTypeFunctions.addFunc}, {builtinTypes->numberType, builtinTypes->numberType}, {}});
|
||||
TypeId superTy = builtinTypes->numberType;
|
||||
SubtypingResult result = isSubtype(typeFamilyNum, superTy);
|
||||
SubtypingResult result = isSubtype(typeFunctionNum, superTy);
|
||||
CHECK(result.isSubtype);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "basic_reducible_super_typefamily")
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "basic_reducible_super_type_function")
|
||||
{
|
||||
// number <: add<number, number> ~ number
|
||||
TypeId typeFamilyNum =
|
||||
arena.addType(TypeFamilyInstanceType{NotNull{&builtinTypeFamilies.addFamily}, {builtinTypes->numberType, builtinTypes->numberType}, {}});
|
||||
TypeId typeFunctionNum =
|
||||
arena.addType(TypeFunctionInstanceType{NotNull{&builtinTypeFunctions.addFunc}, {builtinTypes->numberType, builtinTypes->numberType}, {}});
|
||||
TypeId subTy = builtinTypes->numberType;
|
||||
SubtypingResult result = isSubtype(subTy, typeFamilyNum);
|
||||
SubtypingResult result = isSubtype(subTy, typeFunctionNum);
|
||||
CHECK(result.isSubtype);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "basic_irreducible_sub_typefamily")
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "basic_irreducible_sub_type_function")
|
||||
{
|
||||
// add<string, boolean> ~ never <: number
|
||||
TypeId typeFamilyNum =
|
||||
arena.addType(TypeFamilyInstanceType{NotNull{&builtinTypeFamilies.addFamily}, {builtinTypes->stringType, builtinTypes->booleanType}, {}});
|
||||
TypeId typeFunctionNum =
|
||||
arena.addType(TypeFunctionInstanceType{NotNull{&builtinTypeFunctions.addFunc}, {builtinTypes->stringType, builtinTypes->booleanType}, {}});
|
||||
TypeId superTy = builtinTypes->numberType;
|
||||
SubtypingResult result = isSubtype(typeFamilyNum, superTy);
|
||||
SubtypingResult result = isSubtype(typeFunctionNum, superTy);
|
||||
CHECK(result.isSubtype);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "basic_irreducible_super_typefamily")
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "basic_irreducible_super_type_function")
|
||||
{
|
||||
// number <\: add<string, boolean> ~ irreducible/never
|
||||
TypeId typeFamilyNum =
|
||||
arena.addType(TypeFamilyInstanceType{NotNull{&builtinTypeFamilies.addFamily}, {builtinTypes->stringType, builtinTypes->booleanType}, {}});
|
||||
TypeId typeFunctionNum =
|
||||
arena.addType(TypeFunctionInstanceType{NotNull{&builtinTypeFunctions.addFunc}, {builtinTypes->stringType, builtinTypes->booleanType}, {}});
|
||||
TypeId subTy = builtinTypes->numberType;
|
||||
SubtypingResult result = isSubtype(subTy, typeFamilyNum);
|
||||
SubtypingResult result = isSubtype(subTy, typeFunctionNum);
|
||||
CHECK(!result.isSubtype);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "basic_typefamily_with_generics")
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "basic_type_function_with_generics")
|
||||
{
|
||||
// <T,U>(x: T, x: U) -> add<T,U> <: (number, number) -> number
|
||||
TypeId addFamily = arena.addType(TypeFamilyInstanceType{NotNull{&builtinTypeFamilies.addFamily}, {genericT, genericU}, {}});
|
||||
FunctionType ft{{genericT, genericU}, {}, arena.addTypePack({genericT, genericU}), arena.addTypePack({addFamily})};
|
||||
TypeId addTypeFunction = arena.addType(TypeFunctionInstanceType{NotNull{&builtinTypeFunctions.addFunc}, {genericT, genericU}, {}});
|
||||
FunctionType ft{{genericT, genericU}, {}, arena.addTypePack({genericT, genericU}), arena.addTypePack({addTypeFunction})};
|
||||
TypeId functionType = arena.addType(std::move(ft));
|
||||
FunctionType superFt{arena.addTypePack({builtinTypes->numberType, builtinTypes->numberType}), arena.addTypePack({builtinTypes->numberType})};
|
||||
TypeId superFunction = arena.addType(std::move(superFt));
|
||||
@ -1292,7 +1292,7 @@ TEST_CASE_FIXTURE(SubtypeFixture, "subtyping_reasonings_to_follow_a_reduced_type
|
||||
builtinTypes->numberType, builtinTypes->stringType, builtinTypes->tableType, builtinTypes->threadType}});
|
||||
TypeId tblTy = tbl({{"depth", builtinTypes->unknownType}});
|
||||
TypeId combined = meet(longTy, tblTy);
|
||||
TypeId subTy = arena.addType(TypeFamilyInstanceType{NotNull{&builtinTypeFamilies.unionFamily}, {combined, builtinTypes->neverType}, {}});
|
||||
TypeId subTy = arena.addType(TypeFunctionInstanceType{NotNull{&builtinTypeFunctions.unionFunc}, {combined, builtinTypes->neverType}, {}});
|
||||
TypeId superTy = builtinTypes->neverType;
|
||||
SubtypingResult result = isSubtype(subTy, superTy);
|
||||
CHECK(!result.isSubtype);
|
||||
@ -1321,9 +1321,10 @@ TEST_CASE_FIXTURE(SubtypeFixture, "table_property")
|
||||
|
||||
SubtypingResult result = isSubtype(subTy, superTy);
|
||||
CHECK(!result.isSubtype);
|
||||
CHECK(result.reasoning == std::vector{SubtypingReasoning{/* subPath */ Path(TypePath::Property::read("X")),
|
||||
REQUIRE(result.reasoning.size() == 1);
|
||||
CHECK(*result.reasoning.begin() == SubtypingReasoning{/* subPath */ Path(TypePath::Property::read("X")),
|
||||
/* superPath */ Path(TypePath::Property::read("X")),
|
||||
/* variance */ SubtypingVariance::Invariant}});
|
||||
/* variance */ SubtypingVariance::Invariant});
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "table_indexers")
|
||||
@ -1394,10 +1395,11 @@ TEST_CASE_FIXTURE(SubtypeFixture, "fn_rets")
|
||||
|
||||
SubtypingResult result = isSubtype(subTy, superTy);
|
||||
CHECK(!result.isSubtype);
|
||||
CHECK(result.reasoning == std::vector{SubtypingReasoning{
|
||||
REQUIRE(result.reasoning.size() == 1);
|
||||
CHECK(*result.reasoning.begin() == SubtypingReasoning{
|
||||
/* subPath */ TypePath::PathBuilder().rets().index(0).build(),
|
||||
/* superPath */ TypePath::PathBuilder().rets().index(0).build(),
|
||||
}});
|
||||
});
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "fn_rets_tail")
|
||||
@ -1407,10 +1409,11 @@ TEST_CASE_FIXTURE(SubtypeFixture, "fn_rets_tail")
|
||||
|
||||
SubtypingResult result = isSubtype(subTy, superTy);
|
||||
CHECK(!result.isSubtype);
|
||||
CHECK(result.reasoning == std::vector{SubtypingReasoning{
|
||||
REQUIRE(result.reasoning.size() == 1);
|
||||
CHECK(*result.reasoning.begin() == SubtypingReasoning{
|
||||
/* subPath */ TypePath::PathBuilder().rets().tail().variadic().build(),
|
||||
/* superPath */ TypePath::PathBuilder().rets().tail().variadic().build(),
|
||||
}});
|
||||
});
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "nested_table_properties")
|
||||
@ -1420,11 +1423,12 @@ TEST_CASE_FIXTURE(SubtypeFixture, "nested_table_properties")
|
||||
|
||||
SubtypingResult result = isSubtype(subTy, superTy);
|
||||
CHECK(!result.isSubtype);
|
||||
CHECK(result.reasoning == std::vector{SubtypingReasoning{
|
||||
REQUIRE(result.reasoning.size() == 1);
|
||||
CHECK(*result.reasoning.begin() == SubtypingReasoning{
|
||||
/* subPath */ TypePath::PathBuilder().readProp("X").readProp("Y").readProp("Z").build(),
|
||||
/* superPath */ TypePath::PathBuilder().readProp("X").readProp("Y").readProp("Z").build(),
|
||||
/* variance */ SubtypingVariance::Invariant,
|
||||
}});
|
||||
});
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(SubtypeFixture, "string_table_mt")
|
||||
|
@ -1,5 +1,5 @@
|
||||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
|
||||
#include "Luau/TypeFamily.h"
|
||||
#include "Luau/TypeFunction.h"
|
||||
|
||||
#include "Luau/ConstraintSolver.h"
|
||||
#include "Luau/NotNull.h"
|
||||
@ -17,34 +17,34 @@ LUAU_DYNAMIC_FASTINT(LuauTypeFamilyApplicationCartesianProductLimit)
|
||||
|
||||
struct FamilyFixture : Fixture
|
||||
{
|
||||
TypeFamily swapFamily;
|
||||
TypeFunction swapFamily;
|
||||
|
||||
FamilyFixture()
|
||||
: Fixture(true, false)
|
||||
{
|
||||
swapFamily = TypeFamily{/* name */ "Swap",
|
||||
swapFamily = TypeFunction{/* name */ "Swap",
|
||||
/* reducer */
|
||||
[](TypeId instance, const std::vector<TypeId>& tys, const std::vector<TypePackId>& tps,
|
||||
NotNull<TypeFamilyContext> ctx) -> TypeFamilyReductionResult<TypeId> {
|
||||
NotNull<TypeFunctionContext> ctx) -> TypeFunctionReductionResult<TypeId> {
|
||||
LUAU_ASSERT(tys.size() == 1);
|
||||
TypeId param = follow(tys.at(0));
|
||||
|
||||
if (isString(param))
|
||||
{
|
||||
return TypeFamilyReductionResult<TypeId>{ctx->builtins->numberType, false, {}, {}};
|
||||
return TypeFunctionReductionResult<TypeId>{ctx->builtins->numberType, false, {}, {}};
|
||||
}
|
||||
else if (isNumber(param))
|
||||
{
|
||||
return TypeFamilyReductionResult<TypeId>{ctx->builtins->stringType, false, {}, {}};
|
||||
return TypeFunctionReductionResult<TypeId>{ctx->builtins->stringType, false, {}, {}};
|
||||
}
|
||||
else if (is<BlockedType>(param) || is<PendingExpansionType>(param) || is<TypeFamilyInstanceType>(param) ||
|
||||
else if (is<BlockedType>(param) || is<PendingExpansionType>(param) || is<TypeFunctionInstanceType>(param) ||
|
||||
(ctx->solver && ctx->solver->hasUnresolvedConstraints(param)))
|
||||
{
|
||||
return TypeFamilyReductionResult<TypeId>{std::nullopt, false, {param}, {}};
|
||||
return TypeFunctionReductionResult<TypeId>{std::nullopt, false, {param}, {}};
|
||||
}
|
||||
else
|
||||
{
|
||||
return TypeFamilyReductionResult<TypeId>{std::nullopt, true, {}, {}};
|
||||
return TypeFunctionReductionResult<TypeId>{std::nullopt, true, {}, {}};
|
||||
}
|
||||
}};
|
||||
|
||||
@ -54,12 +54,12 @@ struct FamilyFixture : Fixture
|
||||
|
||||
ScopePtr globalScope = frontend.globals.globalScope;
|
||||
globalScope->exportedTypeBindings["Swap"] =
|
||||
TypeFun{{genericT}, frontend.globals.globalTypes.addType(TypeFamilyInstanceType{NotNull{&swapFamily}, {t}, {}})};
|
||||
TypeFun{{genericT}, frontend.globals.globalTypes.addType(TypeFunctionInstanceType{NotNull{&swapFamily}, {t}, {}})};
|
||||
freeze(frontend.globals.globalTypes);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_SUITE_BEGIN("TypeFamilyTests");
|
||||
TEST_SUITE_BEGIN("TypeFunctionTests");
|
||||
|
||||
TEST_CASE_FIXTURE(FamilyFixture, "basic_type_family")
|
||||
{
|
||||
@ -80,7 +80,7 @@ TEST_CASE_FIXTURE(FamilyFixture, "basic_type_family")
|
||||
CHECK("number" == toString(requireTypeAlias("B")));
|
||||
CHECK("Swap<boolean>" == toString(requireTypeAlias("C")));
|
||||
CHECK("string" == toString(requireType("y")));
|
||||
CHECK("Type family instance Swap<boolean> is uninhabited" == toString(result.errors[0]));
|
||||
CHECK("Type function instance Swap<boolean> is uninhabited" == toString(result.errors[0]));
|
||||
};
|
||||
|
||||
TEST_CASE_FIXTURE(FamilyFixture, "family_as_fn_ret")
|
||||
@ -99,7 +99,7 @@ TEST_CASE_FIXTURE(FamilyFixture, "family_as_fn_ret")
|
||||
CHECK("string" == toString(requireType("a")));
|
||||
CHECK("number" == toString(requireType("b")));
|
||||
CHECK("Swap<boolean>" == toString(requireType("c")));
|
||||
CHECK("Type family instance Swap<boolean> is uninhabited" == toString(result.errors[0]));
|
||||
CHECK("Type function instance Swap<boolean> is uninhabited" == toString(result.errors[0]));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FamilyFixture, "family_as_fn_arg")
|
||||
@ -117,8 +117,8 @@ TEST_CASE_FIXTURE(FamilyFixture, "family_as_fn_arg")
|
||||
// FIXME: Can we constrain these to `never` or `unknown`?
|
||||
CHECK("a" == toString(requireType("a")));
|
||||
CHECK("a" == toString(requireType("b")));
|
||||
CHECK("Type family instance Swap<a> is uninhabited" == toString(result.errors[0]));
|
||||
CHECK("Type family instance Swap<a> is uninhabited" == toString(result.errors[1]));
|
||||
CHECK("Type function instance Swap<a> is uninhabited" == toString(result.errors[0]));
|
||||
CHECK("Type function instance Swap<a> is uninhabited" == toString(result.errors[1]));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FamilyFixture, "resolve_deep_families")
|
||||
@ -148,7 +148,7 @@ TEST_CASE_FIXTURE(FamilyFixture, "unsolvable_family")
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
for (size_t i = 0; i < 2; ++i)
|
||||
{
|
||||
CHECK(toString(result.errors[i]) == "Type family instance Swap<a> is uninhabited");
|
||||
CHECK(toString(result.errors[i]) == "Type function instance Swap<a> is uninhabited");
|
||||
}
|
||||
}
|
||||
|
||||
@ -169,7 +169,7 @@ TEST_CASE_FIXTURE(FamilyFixture, "table_internal_families")
|
||||
CHECK(toString(requireType("b")) == "{number}");
|
||||
// FIXME: table types are constructing a trivial union here.
|
||||
CHECK(toString(requireType("c")) == "{Swap<boolean | boolean | boolean>}");
|
||||
CHECK(toString(result.errors[0]) == "Type family instance Swap<boolean | boolean | boolean> is uninhabited");
|
||||
CHECK(toString(result.errors[0]) == "Type function instance Swap<boolean | boolean | boolean> is uninhabited");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(FamilyFixture, "function_internal_families")
|
||||
@ -190,7 +190,7 @@ TEST_CASE_FIXTURE(FamilyFixture, "function_internal_families")
|
||||
CHECK(toString(requireType("a")) == "() -> string");
|
||||
CHECK(toString(requireType("b")) == "() -> number");
|
||||
CHECK(toString(requireType("c")) == "() -> Swap<boolean>");
|
||||
CHECK(toString(result.errors[0]) == "Type family instance Swap<boolean> is uninhabited");
|
||||
CHECK(toString(result.errors[0]) == "Type function instance Swap<boolean> is uninhabited");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "add_family_at_work")
|
||||
@ -212,8 +212,8 @@ TEST_CASE_FIXTURE(Fixture, "add_family_at_work")
|
||||
CHECK(toString(requireType("a")) == "number");
|
||||
CHECK(toString(requireType("b")) == "Add<number, string>");
|
||||
CHECK(toString(requireType("c")) == "Add<string, number>");
|
||||
CHECK(toString(result.errors[0]) == "Type family instance Add<number, string> is uninhabited");
|
||||
CHECK(toString(result.errors[1]) == "Type family instance Add<string, number> is uninhabited");
|
||||
CHECK(toString(result.errors[0]) == "Type function instance Add<number, string> is uninhabited");
|
||||
CHECK(toString(result.errors[1]) == "Type function instance Add<string, number> is uninhabited");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "cyclic_add_family_at_work")
|
||||
@ -284,7 +284,7 @@ TEST_CASE_FIXTURE(Fixture, "internal_families_raise_errors")
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK(toString(result.errors[0]) == "Type family instance Add<a, b> depends on generic function parameters but does not appear in the function "
|
||||
CHECK(toString(result.errors[0]) == "Type function instance Add<a, b> depends on generic function parameters but does not appear in the function "
|
||||
"signature; this construct cannot be type-checked at this time");
|
||||
}
|
||||
|
||||
@ -301,7 +301,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "type_families_can_be_shadowed")
|
||||
return string.format("hi %s", f)
|
||||
end
|
||||
|
||||
-- this should still work totally fine (and use the real type family)
|
||||
-- this should still work totally fine (and use the real type function)
|
||||
function plus(a, b)
|
||||
return a + b
|
||||
end
|
||||
@ -387,7 +387,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "keyof_type_family_errors_if_it_has_nontable_
|
||||
local function err(idx: KeysOfMyObject): "x" | "y" | "z" return idx end
|
||||
)");
|
||||
|
||||
// FIXME(CLI-95289): we should actually only report the type family being uninhabited error at its first use, I think?
|
||||
// FIXME(CLI-95289): we should actually only report the type function being uninhabited error at its first use, I think?
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
CHECK(toString(result.errors[0]) == "Type 'MyObject | boolean' does not have keys, so 'keyof<MyObject | boolean>' is invalid");
|
||||
CHECK(toString(result.errors[1]) == "Type 'MyObject | boolean' does not have keys, so 'keyof<MyObject | boolean>' is invalid");
|
||||
@ -513,7 +513,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "rawkeyof_type_family_errors_if_it_has_nontab
|
||||
local function err(idx: KeysOfMyObject): "x" | "y" | "z" return idx end
|
||||
)");
|
||||
|
||||
// FIXME(CLI-95289): we should actually only report the type family being uninhabited error at its first use, I think?
|
||||
// FIXME(CLI-95289): we should actually only report the type function being uninhabited error at its first use, I think?
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
CHECK(toString(result.errors[0]) == "Type 'MyObject | boolean' does not have keys, so 'rawkeyof<MyObject | boolean>' is invalid");
|
||||
CHECK(toString(result.errors[1]) == "Type 'MyObject | boolean' does not have keys, so 'rawkeyof<MyObject | boolean>' is invalid");
|
||||
@ -586,7 +586,7 @@ TEST_CASE_FIXTURE(ClassFixture, "keyof_type_family_errors_if_it_has_nonclass_par
|
||||
local function err(idx: KeysOfMyObject): "BaseMethod" | "BaseField" return idx end
|
||||
)");
|
||||
|
||||
// FIXME(CLI-95289): we should actually only report the type family being uninhabited error at its first use, I think?
|
||||
// FIXME(CLI-95289): we should actually only report the type function being uninhabited error at its first use, I think?
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
CHECK(toString(result.errors[0]) == "Type 'BaseClass | boolean' does not have keys, so 'keyof<BaseClass | boolean>' is invalid");
|
||||
CHECK(toString(result.errors[1]) == "Type 'BaseClass | boolean' does not have keys, so 'keyof<BaseClass | boolean>' is invalid");
|
||||
@ -757,7 +757,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "exceeded_distributivity_limits")
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_ERROR_COUNT(1, result);
|
||||
CHECK(get<UninhabitedTypeFamily>(result.errors[0]));
|
||||
CHECK(get<UninhabitedTypeFunction>(result.errors[0]));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "didnt_quite_exceed_distributivity_limits")
|
@ -386,6 +386,20 @@ stat = stat and tonumber(stat) or stat
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "table_of_any_calls")
|
||||
{
|
||||
CheckResult result = check(R"(
|
||||
local function testFunc(input: {any})
|
||||
end
|
||||
|
||||
local v = {true}
|
||||
|
||||
testFunc(v)
|
||||
)");
|
||||
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(Fixture, "intersection_of_any_can_have_props")
|
||||
{
|
||||
// *blocked-130* ~ hasProp any & ~(false?), "_status"
|
||||
|
@ -2262,7 +2262,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "regex_benchmark_string_format_minimization")
|
||||
LUAU_REQUIRE_NO_ERRORS(result);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "subgeneric_typefamily_super_monomorphic")
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "subgeneric_type_function_super_monomorphic")
|
||||
{
|
||||
CheckResult result = check(R"(
|
||||
local a: (number, number) -> number = function(a, b) return a - b end
|
||||
@ -2747,5 +2747,21 @@ _ = _,{}
|
||||
)");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(BuiltinsFixture, "overload_resolution_crash_when_argExprs_is_smaller_than_type_args")
|
||||
{
|
||||
CheckResult result = check(R"(
|
||||
--!strict
|
||||
local parseError
|
||||
type Set<T> = {[T]: any}
|
||||
local function captureDependencies(
|
||||
saveToSet: Set<PubTypes.Dependency>,
|
||||
callback: (...any) -> any,
|
||||
...
|
||||
)
|
||||
local data = table.pack(xpcall(callback, parseError, ...))
|
||||
end
|
||||
)");
|
||||
}
|
||||
|
||||
|
||||
TEST_SUITE_END();
|
||||
|
@ -264,7 +264,7 @@ TEST_CASE_FIXTURE(Fixture, "cannot_indirectly_compare_types_that_do_not_have_a_m
|
||||
|
||||
if (FFlag::DebugLuauDeferredConstraintResolution)
|
||||
{
|
||||
UninhabitedTypeFamily* utf = get<UninhabitedTypeFamily>(result.errors[0]);
|
||||
UninhabitedTypeFunction* utf = get<UninhabitedTypeFunction>(result.errors[0]);
|
||||
REQUIRE(utf);
|
||||
REQUIRE_EQ(toString(utf->ty), "lt<a, b>");
|
||||
}
|
||||
@ -294,7 +294,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_indirectly_compare_types_that_do_not_
|
||||
|
||||
if (FFlag::DebugLuauDeferredConstraintResolution)
|
||||
{
|
||||
UninhabitedTypeFamily* utf = get<UninhabitedTypeFamily>(result.errors[0]);
|
||||
UninhabitedTypeFunction* utf = get<UninhabitedTypeFunction>(result.errors[0]);
|
||||
REQUIRE(utf);
|
||||
REQUIRE_EQ(toString(utf->ty), "lt<M, M>");
|
||||
}
|
||||
@ -557,7 +557,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus")
|
||||
{
|
||||
LUAU_REQUIRE_ERROR_COUNT(2, result);
|
||||
|
||||
UninhabitedTypeFamily* utf = get<UninhabitedTypeFamily>(result.errors[0]);
|
||||
UninhabitedTypeFunction* utf = get<UninhabitedTypeFunction>(result.errors[0]);
|
||||
REQUIRE(utf);
|
||||
CHECK_EQ(toString(utf->ty), "unm<bar>");
|
||||
|
||||
@ -786,7 +786,7 @@ TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operato
|
||||
|
||||
if (FFlag::DebugLuauDeferredConstraintResolution)
|
||||
{
|
||||
UninhabitedTypeFamily* utf = get<UninhabitedTypeFamily>(result.errors[0]);
|
||||
UninhabitedTypeFunction* utf = get<UninhabitedTypeFunction>(result.errors[0]);
|
||||
REQUIRE(utf);
|
||||
REQUIRE_EQ(toString(utf->ty), "lt<boolean, boolean>");
|
||||
}
|
||||
@ -817,7 +817,7 @@ TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operato
|
||||
|
||||
if (FFlag::DebugLuauDeferredConstraintResolution)
|
||||
{
|
||||
UninhabitedTypeFamily* utf = get<UninhabitedTypeFamily>(result.errors[0]);
|
||||
UninhabitedTypeFunction* utf = get<UninhabitedTypeFunction>(result.errors[0]);
|
||||
REQUIRE(utf);
|
||||
REQUIRE_EQ(toString(utf->ty), "lt<number | string, number | string>");
|
||||
}
|
||||
|
@ -246,18 +246,18 @@ TypeAliases.report_shadowed_aliases
|
||||
TypeAliases.type_alias_local_mutation
|
||||
TypeAliases.type_alias_local_rename
|
||||
TypeAliases.type_alias_of_an_imported_recursive_generic_type
|
||||
TypeFamilyTests.add_family_at_work
|
||||
TypeFamilyTests.cyclic_add_family_at_work
|
||||
TypeFamilyTests.cyclic_concat_family_at_work
|
||||
TypeFamilyTests.didnt_quite_exceed_distributivity_limits
|
||||
TypeFamilyTests.ensure_equivalence_with_distributivity
|
||||
TypeFamilyTests.family_as_fn_arg
|
||||
TypeFamilyTests.index_type_family_works_w_generic_types
|
||||
TypeFamilyTests.internal_families_raise_errors
|
||||
TypeFamilyTests.keyof_oss_crash_gh1161
|
||||
TypeFamilyTests.mul_family_with_union_of_multiplicatives
|
||||
TypeFamilyTests.mul_family_with_union_of_multiplicatives_2
|
||||
TypeFamilyTests.unsolvable_family
|
||||
TypeFunctionTests.add_family_at_work
|
||||
TypeFunctionTests.cyclic_add_family_at_work
|
||||
TypeFunctionTests.cyclic_concat_family_at_work
|
||||
TypeFunctionTests.didnt_quite_exceed_distributivity_limits
|
||||
TypeFunctionTests.ensure_equivalence_with_distributivity
|
||||
TypeFunctionTests.family_as_fn_arg
|
||||
TypeFunctionTests.index_type_family_works_w_generic_types
|
||||
TypeFunctionTests.internal_families_raise_errors
|
||||
TypeFunctionTests.keyof_oss_crash_gh1161
|
||||
TypeFunctionTests.mul_family_with_union_of_multiplicatives
|
||||
TypeFunctionTests.mul_family_with_union_of_multiplicatives_2
|
||||
TypeFunctionTests.unsolvable_family
|
||||
TypeInfer.be_sure_to_use_active_txnlog_when_evaluating_a_variadic_overload
|
||||
TypeInfer.check_type_infer_recursion_count
|
||||
TypeInfer.checking_should_not_ice
|
||||
@ -277,7 +277,6 @@ TypeInfer.tc_if_else_expressions_expected_type_3
|
||||
TypeInfer.type_infer_recursion_limit_no_ice
|
||||
TypeInfer.type_infer_recursion_limit_normalizer
|
||||
TypeInfer.unify_nearly_identical_recursive_types
|
||||
TypeInferAnyError.can_subscript_any
|
||||
TypeInferAnyError.for_in_loop_iterator_is_any
|
||||
TypeInferAnyError.for_in_loop_iterator_is_any2
|
||||
TypeInferAnyError.for_in_loop_iterator_is_any_pack
|
||||
@ -290,7 +289,6 @@ TypeInferClasses.class_type_mismatch_with_name_conflict
|
||||
TypeInferClasses.detailed_class_unification_error
|
||||
TypeInferClasses.indexable_classes
|
||||
TypeInferClasses.table_class_unification_reports_sane_errors_for_missing_properties
|
||||
TypeInferClasses.table_indexers_are_invariant
|
||||
TypeInferClasses.we_can_report_when_someone_is_trying_to_use_a_table_rather_than_a_class
|
||||
TypeInferFunctions.another_other_higher_order_function
|
||||
TypeInferFunctions.bidirectional_checking_of_callback_property
|
||||
|
Loading…
Reference in New Issue
Block a user