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:
Junseo Yoo 2024-07-12 10:03:36 -07:00 committed by GitHub
parent 6bfc38e61a
commit b6b74b4425
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
51 changed files with 812 additions and 771 deletions

View File

@ -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;

View File

@ -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.

View File

@ -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>;

View File

@ -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

View File

@ -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);

View File

@ -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
{

View File

@ -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);

View File

@ -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

View File

@ -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

View 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

View File

@ -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;

View File

@ -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;

View File

@ -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))
{

View File

@ -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}})});

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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>)

View File

@ -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;
}

View File

@ -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));

View File

@ -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};

View File

@ -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);

View File

@ -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);

View File

@ -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))

View File

@ -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();

View File

@ -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("<");

View File

@ -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);

View File

@ -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)

View File

@ -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()));
}

View File

@ -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;
}

View File

@ -1,6 +1,6 @@
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Luau/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(&ltFamily);
scope->exportedTypeBindings[leFamily.name] = mkBinaryTypeFamily(&leFamily);
scope->exportedTypeBindings[eqFamily.name] = mkBinaryTypeFamily(&eqFamily);
scope->exportedTypeBindings[ltFunc.name] = mkBinaryTypeFunction(&ltFunc);
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;
}

View File

@ -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]);

View File

@ -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);

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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);
}
}
@ -759,32 +751,12 @@ 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});

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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")

View File

@ -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")

View File

@ -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"

View File

@ -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();

View File

@ -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>");
}

View File

@ -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