diff --git a/Analysis/include/Luau/Constraint.h b/Analysis/include/Luau/Constraint.h index 6a86072d..79129f72 100644 --- a/Analysis/include/Luau/Constraint.h +++ b/Analysis/include/Luau/Constraint.h @@ -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; diff --git a/Analysis/include/Luau/ConstraintGenerator.h b/Analysis/include/Luau/ConstraintGenerator.h index 28cfb5aa..cb49eef3 100644 --- a/Analysis/include/Luau/ConstraintGenerator.h +++ b/Analysis/include/Luau/ConstraintGenerator.h @@ -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> getExpectedCallTypesForFunctionOverloads(const TypeId fnType); - TypeId createTypeFamilyInstance( - const TypeFamily& family, std::vector typeArguments, std::vector packArguments, const ScopePtr& scope, Location location); + TypeId createTypeFunctionInstance( + const TypeFunction& family, std::vector typeArguments, std::vector packArguments, const ScopePtr& scope, Location location); }; /** Borrow a vector of pointers from a vector of owning pointers to constraints. diff --git a/Analysis/include/Luau/Error.h b/Analysis/include/Luau/Error.h index 2ba284a1..06d08652 100644 --- a/Analysis/include/Luau/Error.h +++ b/Analysis/include/Luau/Error.h @@ -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>; diff --git a/Analysis/include/Luau/Instantiation.h b/Analysis/include/Luau/Instantiation.h index 58ba88ab..8b65dfe3 100644 --- a/Analysis/include/Luau/Instantiation.h +++ b/Analysis/include/Luau/Instantiation.h @@ -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 diff --git a/Analysis/include/Luau/Subtyping.h b/Analysis/include/Luau/Subtyping.h index 11e20976..4c1d23bd 100644 --- a/Analysis/include/Luau/Subtyping.h +++ b/Analysis/include/Luau/Subtyping.h @@ -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, 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 applyMappedGenerics(NotNull builtinTypes, NotNull 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 TypeId makeAggregateType(const Container& container, TypeId orElse); - std::pair handleTypeFamilyReductionResult(const TypeFamilyInstanceType* familyInstance); + std::pair handleTypeFunctionReductionResult(const TypeFunctionInstanceType* familyInstance); [[noreturn]] void unexpected(TypeId ty); [[noreturn]] void unexpected(TypePackId tp); diff --git a/Analysis/include/Luau/Type.h b/Analysis/include/Luau/Type.h index 881dc646..401784ae 100644 --- a/Analysis/include/Luau/Type.h +++ b/Analysis/include/Luau/Type.h @@ -32,7 +32,7 @@ struct TypeArena; struct Scope; using ScopePtr = std::shared_ptr; -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 family; + NotNull family; std::vector typeArguments; std::vector packArguments; - TypeFamilyInstanceType(NotNull family, std::vector typeArguments, std::vector packArguments) + TypeFunctionInstanceType(NotNull family, std::vector typeArguments, std::vector packArguments) : family(family) , typeArguments(typeArguments) , packArguments(packArguments) { } - TypeFamilyInstanceType(const TypeFamily& family, std::vector typeArguments) + TypeFunctionInstanceType(const TypeFunction& family, std::vector typeArguments) : family{&family} , typeArguments(typeArguments) , packArguments{} { } - TypeFamilyInstanceType(const TypeFamily& family, std::vector typeArguments, std::vector packArguments) + TypeFunctionInstanceType(const TypeFunction& family, std::vector typeArguments, std::vector packArguments) : family{&family} , typeArguments(typeArguments) , packArguments(packArguments) @@ -659,7 +659,7 @@ using ErrorType = Unifiable::Error; using TypeVariant = Unifiable::Variant; + MetatableType, ClassType, AnyType, UnionType, IntersectionType, LazyType, UnknownType, NeverType, NegationType, TypeFunctionInstanceType>; struct Type final { diff --git a/Analysis/include/Luau/TypeArena.h b/Analysis/include/Luau/TypeArena.h index 162fde96..5a28aa25 100644 --- a/Analysis/include/Luau/TypeArena.h +++ b/Analysis/include/Luau/TypeArena.h @@ -49,10 +49,10 @@ struct TypeArena return addTypePack(TypePackVar(std::move(tp))); } - TypeId addTypeFamily(const TypeFamily& family, std::initializer_list types); - TypeId addTypeFamily(const TypeFamily& family, std::vector typeArguments, std::vector packArguments = {}); - TypePackId addTypePackFamily(const TypePackFamily& family, std::initializer_list types); - TypePackId addTypePackFamily(const TypePackFamily& family, std::vector typeArguments, std::vector packArguments = {}); + TypeId addTypeFunction(const TypeFunction& family, std::initializer_list types); + TypeId addTypeFunction(const TypeFunction& family, std::vector typeArguments, std::vector packArguments = {}); + TypePackId addTypePackFunction(const TypePackFunction& family, std::initializer_list types); + TypePackId addTypePackFunction(const TypePackFunction& family, std::vector typeArguments, std::vector packArguments = {}); }; void freeze(TypeArena& arena); diff --git a/Analysis/include/Luau/TypeFamilyReductionGuesser.h b/Analysis/include/Luau/TypeFamilyReductionGuesser.h deleted file mode 100644 index 29114f72..00000000 --- a/Analysis/include/Luau/TypeFamilyReductionGuesser.h +++ /dev/null @@ -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> 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 operandInference; - TypeId familyResultInference; -}; - -struct TypeFamilyReductionGuesser -{ - // Tracks our hypothesis about what a type family reduces to - DenseHashMap familyReducesTo{nullptr}; - // Tracks our constraints on type family operands - DenseHashMap substitutable{nullptr}; - // List of instances to try progress - VecDeque toInfer; - DenseHashSet cyclicInstances{nullptr}; - - // Utilities - NotNull arena; - NotNull builtins; - NotNull normalizer; - - TypeFamilyReductionGuesser(NotNull arena, NotNull builtins, NotNull normalizer); - - std::optional guess(TypeId typ); - std::optional guess(TypePackId typ); - TypeFamilyReductionGuessResult guessTypeFamilyReductionForFunction(const AstExprFunction& expr, const FunctionType* ftv, TypeId retTy); - -private: - std::optional 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 tryAssignOperandType(TypeId ty); - - std::shared_ptr normalize(TypeId ty); - void step(); - void infer(); - bool done(); - - bool isFunctionGenericsSaturated(const FunctionType& ftv, DenseHashSet& 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 diff --git a/Analysis/include/Luau/TypeFamily.h b/Analysis/include/Luau/TypeFunction.h similarity index 63% rename from Analysis/include/Luau/TypeFamily.h rename to Analysis/include/Luau/TypeFunction.h index 9d2182df..f5ac22ad 100644 --- a/Analysis/include/Luau/TypeFamily.h +++ b/Analysis/include/Luau/TypeFunction.h @@ -18,7 +18,7 @@ struct TypeArena; struct TxnLog; class Normalizer; -struct TypeFamilyContext +struct TypeFunctionContext { NotNull arena; NotNull builtins; @@ -27,12 +27,12 @@ struct TypeFamilyContext NotNull ice; NotNull 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 cs, NotNull scope, NotNull constraint) + TypeFunctionContext(NotNull cs, NotNull scope, NotNull constraint) : arena(cs->arena) , builtins(cs->builtinTypes) , scope(scope) @@ -44,7 +44,7 @@ struct TypeFamilyContext { } - TypeFamilyContext(NotNull arena, NotNull builtins, NotNull scope, NotNull normalizer, + TypeFunctionContext(NotNull arena, NotNull builtins, NotNull scope, NotNull normalizer, NotNull ice, NotNull 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 -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 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 using ReducerFunction = - std::function(T, const std::vector&, const std::vector&, NotNull)>; + std::function(T, const std::vector&, const std::vector&, NotNull)>; /// 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 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 reducer; }; -struct FamilyGraphReductionResult +struct FunctionGraphReductionResult { ErrorVec errors; DenseHashSet 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 arena, NotNull scope) const; }; -const BuiltinTypeFamilies& builtinTypeFunctions(); +const BuiltinTypeFunctions& builtinTypeFunctions(); } // namespace Luau diff --git a/Analysis/include/Luau/TypeFunctionReductionGuesser.h b/Analysis/include/Luau/TypeFunctionReductionGuesser.h new file mode 100644 index 00000000..62206efc --- /dev/null +++ b/Analysis/include/Luau/TypeFunctionReductionGuesser.h @@ -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> 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 operandInference; + TypeId familyResultInference; +}; + +struct TypeFunctionReductionGuesser +{ + // Tracks our hypothesis about what a type function reduces to + DenseHashMap familyReducesTo{nullptr}; + // Tracks our constraints on type function operands + DenseHashMap substitutable{nullptr}; + // List of instances to try progress + VecDeque toInfer; + DenseHashSet cyclicInstances{nullptr}; + + // Utilities + NotNull arena; + NotNull builtins; + NotNull normalizer; + + TypeFunctionReductionGuesser(NotNull arena, NotNull builtins, NotNull normalizer); + + std::optional guess(TypeId typ); + std::optional guess(TypePackId typ); + TypeFunctionReductionGuessResult guessTypeFunctionReductionForFunctionExpr(const AstExprFunction& expr, const FunctionType* ftv, TypeId retTy); + +private: + std::optional 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 tryAssignOperandType(TypeId ty); + + std::shared_ptr normalize(TypeId ty); + void step(); + void infer(); + bool done(); + + bool isFunctionGenericsSaturated(const FunctionType& ftv, DenseHashSet& 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 diff --git a/Analysis/include/Luau/TypeFwd.h b/Analysis/include/Luau/TypeFwd.h index e4318156..42d582fe 100644 --- a/Analysis/include/Luau/TypeFwd.h +++ b/Analysis/include/Luau/TypeFwd.h @@ -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; diff --git a/Analysis/include/Luau/TypePack.h b/Analysis/include/Luau/TypePack.h index 691a8ed9..5d10454d 100644 --- a/Analysis/include/Luau/TypePack.h +++ b/Analysis/include/Luau/TypePack.h @@ -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; using ErrorTypePack = Unifiable::Error; using TypePackVariant = - Unifiable::Variant; + Unifiable::Variant; /* 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 family; + NotNull family; std::vector typeArguments; std::vector packArguments; diff --git a/Analysis/include/Luau/VisitType.h b/Analysis/include/Luau/VisitType.h index 8c0f5ed9..e588d06b 100644 --- a/Analysis/include/Luau/VisitType.h +++ b/Analysis/include/Luau/VisitType.h @@ -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& 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 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(ty)) + else if (auto tfit = get(ty)) { - TypeFamilyDepthCounter tfdc{&typeFamilyDepth}; + TypeFunctionDepthCounter tfdc{&typeFunctionDepth}; if (visit(ty, *tfit)) { @@ -477,9 +478,9 @@ struct GenericTypeVisitor } else if (auto btp = get(tp)) visit(tp, *btp); - else if (auto tfitp = get(tp)) + else if (auto tfitp = get(tp)) { - TypeFamilyDepthCounter tfdc{&typeFamilyDepth}; + TypeFunctionDepthCounter tfdc{&typeFunctionDepth}; if (visit(tp, *tfitp)) { diff --git a/Analysis/src/BuiltinDefinitions.cpp b/Analysis/src/BuiltinDefinitions.cpp index 582d5a7d..e7782150 100644 --- a/Analysis/src/BuiltinDefinitions.cpp +++ b/Analysis/src/BuiltinDefinitions.cpp @@ -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(value: T, errorMessage: string?): intersect 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}})}); diff --git a/Analysis/src/Clone.cpp b/Analysis/src/Clone.cpp index 371ace2e..76bf9233 100644 --- a/Analysis/src/Clone.cpp +++ b/Analysis/src/Clone.cpp @@ -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); diff --git a/Analysis/src/ConstraintGenerator.cpp b/Analysis/src/ConstraintGenerator.cpp index a449949a..aa5e4ca8 100644 --- a/Analysis/src/ConstraintGenerator.cpp +++ b/Analysis/src/ConstraintGenerator.cpp @@ -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(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> ConstraintGenerator::getExpectedCallTypesForF return expectedTypes; } -TypeId ConstraintGenerator::createTypeFamilyInstance( - const TypeFamily& family, std::vector typeArguments, std::vector packArguments, const ScopePtr& scope, Location location) +TypeId ConstraintGenerator::createTypeFunctionInstance( + const TypeFunction& family, std::vector typeArguments, std::vector 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; } diff --git a/Analysis/src/ConstraintSolver.cpp b/Analysis/src/ConstraintSolver.cpp index c77581a7..15f150e8 100644 --- a/Analysis/src/ConstraintSolver.cpp +++ b/Analysis/src/ConstraintSolver.cpp @@ -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(ty)) + if (get(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(resultType)); LUAU_ASSERT(canMutate(resultType, constraint)); - if (isBlocked(subjectType) || get(subjectType) || get(subjectType)) + if (isBlocked(subjectType) || get(subjectType) || get(subjectType)) return block(subjectType, constraint); if (const TableType* subjectTable = getTableType(subjectType)) @@ -1433,6 +1433,12 @@ bool ConstraintSolver::tryDispatchHasIndexer( LUAU_ASSERT(get(resultType)); LUAU_ASSERT(canMutate(resultType, constraint)); + if (get(subjectType)) + { + bind(constraint, resultType, builtinTypes->anyType); + return true; + } + if (auto ft = get(subjectType)) { if (auto tbl = get(follow(ft->upperBound)); tbl && tbl->indexer) @@ -1955,8 +1961,8 @@ bool ConstraintSolver::tryDispatch(const UnpackConstraint& c, NotNull 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(ty)) + // If we couldn't reduce this type function, stick it in the set! + if (get(ty)) typeFamiliesToFinalize[ty] = constraint; if (force || reductionFinished) @@ -1976,9 +1982,9 @@ bool ConstraintSolver::tryDispatch(const ReduceConstraint& c, NotNull(error)) + if (auto utf = get(error)) uninhabitedTypeFamilies.insert(utf->ty); - else if (auto utpf = get(error)) + else if (auto utpf = get(error)) uninhabitedTypeFamilies.insert(utpf->tp); } } @@ -1998,8 +2004,8 @@ bool ConstraintSolver::tryDispatch(const ReduceConstraint& c, NotNull 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(error)) + if (auto utf = get(error)) uninhabitedTypeFamilies.insert(utf->ty); - else if (auto utpf = get(error)) + else if (auto utpf = get(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, const Location { for (auto [_, newTy] : subst.newTypes) { - if (get(newTy)) + if (get(newTy)) pushConstraint(scope, location, ReduceConstraint{newTy}); } for (auto [_, newPack] : subst.newPacks) { - if (get(newPack)) + if (get(newPack)) pushConstraint(scope, location, ReducePackConstraint{newPack}); } } @@ -2728,7 +2734,7 @@ bool ConstraintSolver::isBlocked(TypeId ty) { ty = follow(ty); - if (auto tfit = get(ty)) + if (auto tfit = get(ty)) return uninhabitedTypeFamilies.contains(ty) == false; return nullptr != get(ty) || nullptr != get(ty); @@ -2738,7 +2744,7 @@ bool ConstraintSolver::isBlocked(TypePackId tp) { tp = follow(tp); - if (auto tfitp = get(tp)) + if (auto tfitp = get(tp)) return uninhabitedTypeFamilies.contains(tp) == false; return nullptr != get(tp); diff --git a/Analysis/src/Error.cpp b/Analysis/src/Error.cpp index 5a9e42a7..6e778e57 100644 --- a/Analysis/src/Error.cpp +++ b/Analysis/src/Error.cpp @@ -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 #include @@ -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 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 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 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 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(e.ty); - LUAU_ASSERT(tfit); // Luau analysis has actually done something wrong if this type is not a type family. + auto tfit = get(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(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) e.ty = clone(e.ty); - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) e.ty = clone(e.ty); else if constexpr (std::is_same_v) { @@ -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) + else if constexpr (std::is_same_v) e.tp = clone(e.tp); else if constexpr (std::is_same_v) e.ty = clone(e.ty); diff --git a/Analysis/src/Frontend.cpp b/Analysis/src/Frontend.cpp index fb7b8909..391ece8c 100644 --- a/Analysis/src/Frontend.cpp +++ b/Analysis/src/Frontend.cpp @@ -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; diff --git a/Analysis/src/Generalization.cpp b/Analysis/src/Generalization.cpp index 5020ea58..e6a8bda3 100644 --- a/Analysis/src/Generalization.cpp +++ b/Analysis/src/Generalization.cpp @@ -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; diff --git a/Analysis/src/IostreamHelpers.cpp b/Analysis/src/IostreamHelpers.cpp index 59aa577e..b6d50173 100644 --- a/Analysis/src/IostreamHelpers.cpp +++ b/Analysis/src/IostreamHelpers.cpp @@ -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) stream << "DynamicPropertyLookupOnClassesUnsafe { " << toString(err.ty) << " }"; - else if constexpr (std::is_same_v) - stream << "UninhabitedTypeFamily { " << toString(err.ty) << " }"; + else if constexpr (std::is_same_v) + stream << "UninhabitedTypeFunction { " << toString(err.ty) << " }"; else if constexpr (std::is_same_v) { 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) - stream << "UninhabitedTypePackFamily { " << toString(err.tp) << " }"; + else if constexpr (std::is_same_v) + stream << "UninhabitedTypePackFunction { " << toString(err.tp) << " }"; else if constexpr (std::is_same_v) stream << "WhereClauseNeeded { " << toString(err.ty) << " }"; else if constexpr (std::is_same_v) diff --git a/Analysis/src/Module.cpp b/Analysis/src/Module.cpp index 440b510b..9dab5123 100644 --- a/Analysis/src/Module.cpp +++ b/Analysis/src/Module.cpp @@ -15,6 +15,7 @@ #include LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution); +LUAU_FASTFLAGVARIABLE(LuauSkipEmptyInstantiations, false); namespace Luau { @@ -115,9 +116,22 @@ struct ClonePublicInterface : Substitution TypeId result = clone(ty); if (FunctionType* ftv = getMutable(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(result)) + { ttv->level = TypeLevel{0, 0}; + } return result; } diff --git a/Analysis/src/NonStrictTypeChecker.cpp b/Analysis/src/NonStrictTypeChecker.cpp index 2a1b3cc4..ea617279 100644 --- a/Analysis/src/NonStrictTypeChecker.cpp +++ b/Analysis/src/NonStrictTypeChecker.cpp @@ -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 dfg; - DenseHashSet noTypeFamilyErrors{nullptr}; + DenseHashSet noTypeFunctionErrors{nullptr}; std::vector> stack; DenseHashMap 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)); diff --git a/Analysis/src/Normalize.cpp b/Analysis/src/Normalize.cpp index 17be78a5..9585cdc7 100644 --- a/Analysis/src/Normalize.cpp +++ b/Analysis/src/Normalize.cpp @@ -816,7 +816,7 @@ static bool areNormalizedClasses(const NormalizedClassType& tys) static bool isPlainTyvar(TypeId ty) { - return (get(ty) || get(ty) || get(ty) || get(ty) || get(ty)); + return (get(ty) || get(ty) || get(ty) || get(ty) || get(ty)); } static bool isNormalizedTyvar(const NormalizedTyvars& tyvars) @@ -883,7 +883,7 @@ static bool isCacheable(TypePackId tp, Set& seen) if (auto tail = it.tail()) { - if (get(*tail) || get(*tail) || get(*tail)) + if (get(*tail) || get(*tail) || get(*tail)) return false; } @@ -901,7 +901,7 @@ static bool isCacheable(TypeId ty, Set& seen) if (get(ty) || get(ty) || get(ty)) return false; - if (auto tfi = get(ty)) + if (auto tfi = get(ty)) { for (TypeId t : tfi->typeArguments) { @@ -1795,7 +1795,7 @@ NormalizationResult Normalizer::unionNormalWithTy(NormalizedType& here, TypeId t else if (get(here.tops)) return NormalizationResult::True; else if (get(there) || get(there) || get(there) || get(there) || - get(there)) + get(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(there) || get(there)) + else if (get(there) || get(there)) { // nothing } @@ -3080,7 +3080,7 @@ NormalizationResult Normalizer::intersectNormalWithTy(NormalizedType& here, Type return NormalizationResult::True; } else if (get(there) || get(there) || get(there) || get(there) || - get(there)) + get(there)) { NormalizedType thereNorm{builtinTypes}; NormalizedType topNorm{builtinTypes}; diff --git a/Analysis/src/OverloadResolution.cpp b/Analysis/src/OverloadResolution.cpp index 8bbdfec4..3cc0bc64 100644 --- a/Analysis/src/OverloadResolution.cpp +++ b/Analysis/src/OverloadResolution.cpp @@ -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::checkOverload_( TypeId fnTy, const FunctionType* fn, const TypePack* args, AstExpr* fnExpr, const std::vector* 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::checkOverload_ if (const Luau::TypePath::Index* pathIndexComponent = get_if(&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 failedSubTy = traverseForType(fnTy, reason.subPath, builtinTypes); std::optional failedSuperTy = traverseForType(prospectiveFunction, reason.superPath, builtinTypes); diff --git a/Analysis/src/Substitution.cpp b/Analysis/src/Substitution.cpp index 91103ccb..fae4b60c 100644 --- a/Analysis/src/Substitution.cpp +++ b/Analysis/src/Substitution.cpp @@ -125,9 +125,9 @@ static TypeId shallowClone(TypeId ty, TypeArena& dest, const TxnLog* log, bool a } else if constexpr (std::is_same_v) return dest.addType(NegationType{a.ty}); - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) { - 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(ty)) + else if (const TypeFunctionInstanceType* tfit = get(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(tp)) + else if (const TypeFunctionInstanceTypePack* tfitp = get(tp)) { - TypeFamilyInstanceTypePack clone{ + TypeFunctionInstanceTypePack clone{ tfitp->family, std::vector(tfitp->typeArguments.size()), std::vector(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(ty)) + else if (TypeFunctionInstanceType* tfit = getMutable(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(tp)) + else if (TypeFunctionInstanceTypePack* tfitp = getMutable(tp)) { for (TypeId& t : tfitp->typeArguments) t = replace(t); diff --git a/Analysis/src/Subtyping.cpp b/Analysis/src/Subtyping.cpp index 040c3fc6..d6b4e31d 100644 --- a/Analysis/src/Subtyping.cpp +++ b/Analysis/src/Subtyping.cpp @@ -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(subTy)) + else if (auto subTypeFunctionInstance = get(subTy)) { if (auto substSubTy = env.applyMappedGenerics(builtinTypes, arena, subTy)) - subTypeFamilyInstance = get(*substSubTy); + subTypeFunctionInstance = get(*substSubTy); - result = isCovariantWith(env, subTypeFamilyInstance, superTy); + result = isCovariantWith(env, subTypeFunctionInstance, superTy); } - else if (auto superTypeFamilyInstance = get(superTy)) + else if (auto superTypeFunctionInstance = get(superTy)) { if (auto substSuperTy = env.applyMappedGenerics(builtinTypes, arena, superTy)) - superTypeFamilyInstance = get(*substSuperTy); + superTypeFunctionInstance = get(*substSuperTy); - result = isCovariantWith(env, subTy, superTypeFamilyInstance); + result = isCovariantWith(env, subTy, superTypeFunctionInstance); } else if (auto subGeneric = get(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(begin(container), end(container))}); } -std::pair Subtyping::handleTypeFamilyReductionResult(const TypeFamilyInstanceType* familyInstance) +std::pair 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)) diff --git a/Analysis/src/ToDot.cpp b/Analysis/src/ToDot.cpp index 17b595b1..055ed7ad 100644 --- a/Analysis/src/ToDot.cpp +++ b/Analysis/src/ToDot.cpp @@ -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 @@ -343,9 +343,9 @@ void StateDot::visitChildren(TypeId ty, int index) visitChild(t.ty, index, "[negated]"); } - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) { - 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(); diff --git a/Analysis/src/ToString.cpp b/Analysis/src/ToString.cpp index dca041a2..3440c3d7 100644 --- a/Analysis/src/ToString.cpp +++ b/Analysis/src/ToString.cpp @@ -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("<"); diff --git a/Analysis/src/Type.cpp b/Analysis/src/Type.cpp index 71cac6fd..6735e367 100644 --- a/Analysis/src/Type.cpp +++ b/Analysis/src/Type.cpp @@ -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(ty)) + if (const TypeFunctionInstanceType* tfit = get(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(t) || get(t) || get(t) || get(t) || get(t) || get(t)) { } - else if (auto tfit = get(t)) + else if (auto tfit = get(t)) { for (auto ty : tfit->typeArguments) queue.push_back(ty); @@ -1117,7 +1117,7 @@ void persist(TypePackId tp) else if (get(tp)) { } - else if (auto tfitp = get(tp)) + else if (auto tfitp = get(tp)) { for (auto ty : tfitp->typeArguments) persist(ty); diff --git a/Analysis/src/TypeArena.cpp b/Analysis/src/TypeArena.cpp index 03c1e99a..ef19196c 100644 --- a/Analysis/src/TypeArena.cpp +++ b/Analysis/src/TypeArena.cpp @@ -94,24 +94,24 @@ TypePackId TypeArena::addTypePack(TypePackVar tp) return allocated; } -TypeId TypeArena::addTypeFamily(const TypeFamily& family, std::initializer_list types) +TypeId TypeArena::addTypeFunction(const TypeFunction& family, std::initializer_list types) { - return addType(TypeFamilyInstanceType{family, std::move(types)}); + return addType(TypeFunctionInstanceType{family, std::move(types)}); } -TypeId TypeArena::addTypeFamily(const TypeFamily& family, std::vector typeArguments, std::vector packArguments) +TypeId TypeArena::addTypeFunction(const TypeFunction& family, std::vector typeArguments, std::vector 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 types) +TypePackId TypeArena::addTypePackFunction(const TypePackFunction& family, std::initializer_list 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 typeArguments, std::vector packArguments) +TypePackId TypeArena::addTypePackFunction(const TypePackFunction& family, std::vector typeArguments, std::vector 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) diff --git a/Analysis/src/TypeAttach.cpp b/Analysis/src/TypeAttach.cpp index c0294fc9..6dc5b02d 100644 --- a/Analysis/src/TypeAttach.cpp +++ b/Analysis/src/TypeAttach.cpp @@ -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 @@ -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(Location(), std::nullopt, AstName{tfit.family->name.c_str()}, std::nullopt, Location()); } @@ -454,7 +454,7 @@ public: return allocator->alloc(Location(), AstName("Unifiable")); } - AstTypePack* operator()(const TypeFamilyInstanceTypePack& tfitp) const + AstTypePack* operator()(const TypeFunctionInstanceTypePack& tfitp) const { return allocator->alloc(Location(), AstName(tfitp.family->name.c_str())); } diff --git a/Analysis/src/TypeChecker2.cpp b/Analysis/src/TypeChecker2.cpp index c53a5d30..97cec176 100644 --- a/Analysis/src/TypeChecker2.cpp +++ b/Analysis/src/TypeChecker2.cpp @@ -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 mentionedFamilies{nullptr}; DenseHashSet 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(mentioned); + const TypeFunctionInstanceType* mentionedTfit = get(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(mentioned); + const TypeFunctionInstanceTypePack* mentionedTfitp = get(mentioned); LUAU_ASSERT(mentionedTfitp); if (areEquivalent(tfitp, *mentionedTfitp)) { @@ -245,7 +245,7 @@ struct TypeChecker2 std::vector> stack; std::vector functionDeclStack; - DenseHashSet seenTypeFamilyInstances{nullptr}; + DenseHashSet 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(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(follow(retTy))) + if (get(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(expectedResult)) + if (get(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; } diff --git a/Analysis/src/TypeFamily.cpp b/Analysis/src/TypeFunction.cpp similarity index 83% rename from Analysis/src/TypeFamily.cpp rename to Analysis/src/TypeFunction.cpp index 816cf005..136eac69 100644 --- a/Analysis/src/TypeFamily.cpp +++ b/Analysis/src/TypeFunction.cpp @@ -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 -// 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` blows up into `mul | mul | mul | mul` LUAU_DYNAMIC_FASTINTVARIABLE(LuauTypeFamilyApplicationCartesianProductLimit, 5'000); @@ -49,7 +49,7 @@ struct InstanceCollector : TypeOnceVisitor TypeOrTypePackIdSet shouldGuess{nullptr}; std::vector 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 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(t)) + if (get(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 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 queuedTys; VecDeque queuedTps; TypeOrTypePackIdSet shouldGuess; std::vector cyclicTypeFamilies; TypeOrTypePackIdSet irreducible{nullptr}; - FamilyGraphReductionResult result; + FunctionGraphReductionResult result; bool force = false; // Local to the constraint being reduced. Location location; - FamilyReducer(VecDeque queuedTys, VecDeque queuedTps, TypeOrTypePackIdSet shouldGuess, std::vector cyclicTypes, - Location location, TypeFamilyContext ctx, bool force = false) + TypeFunctionReducer(VecDeque queuedTys, VecDeque queuedTps, TypeOrTypePackIdSet shouldGuess, std::vector 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(ty)) + if (is(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(ty)) + if (is(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 - void handleFamilyReduction(T subject, TypeFamilyReductionResult reduction) + void handleTypeFunctionReduction(T subject, TypeFunctionReductionResult 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) - result.errors.push_back(TypeError{location, UninhabitedTypeFamily{subject}}); + result.errors.push_back(TypeError{location, UninhabitedTypeFunction{subject}}); else if constexpr (std::is_same_v) - 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(subject)) + if (const TypeFunctionInstanceType* tfit = get(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 result = tfit->family->reducer(subject, tfit->typeArguments, tfit->packArguments, NotNull{&ctx}); - handleFamilyReduction(subject, result); + TypeFunctionReductionResult 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(subject)) + if (const TypeFunctionInstanceTypePack* tfit = get(subject)) { if (!testParameters(subject, tfit)) return; @@ -371,8 +371,8 @@ struct FamilyReducer if (tryGuessing(subject)) return; - TypeFamilyReductionResult result = tfit->family->reducer(subject, tfit->typeArguments, tfit->packArguments, NotNull{&ctx}); - handleFamilyReduction(subject, result); + TypeFunctionReductionResult result = tfit->family->reducer(subject, tfit->typeArguments, tfit->packArguments, NotNull{&ctx}); + handleTypeFunctionReduction(subject, result); } } @@ -385,10 +385,10 @@ struct FamilyReducer } }; -static FamilyGraphReductionResult reduceFamiliesInternal(VecDeque queuedTys, VecDeque queuedTps, TypeOrTypePackIdSet shouldGuess, - std::vector cyclics, Location location, TypeFamilyContext ctx, bool force) +static FunctionGraphReductionResult reduceFamiliesInternal(VecDeque queuedTys, VecDeque queuedTps, TypeOrTypePackIdSet shouldGuess, + std::vector 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 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(ty) || (solver && solver->hasUnresolvedConstraints(ty)); + return is(ty) || (solver && solver->hasUnresolvedConstraints(ty)); } template -static std::optional> tryDistributeTypeFamilyApp(F f, TypeId instance, const std::vector& typeParams, - const std::vector& packParams, NotNull ctx, Args&&... args) +static std::optional> tryDistributeTypeFunctionApp(F f, TypeId instance, const std::vector& typeParams, + const std::vector& packParams, NotNull 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> 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> tryDistributeTypeFamilyA { arguments[unionIndex] = option; - TypeFamilyReductionResult result = f(instance, arguments, packParams, ctx, args...); + TypeFunctionReductionResult 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> 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> tryDistributeTypeFamilyA return std::nullopt; } -TypeFamilyReductionResult notFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult notFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 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 lenFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult lenFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 lenFamilyFn( if (normTy->hasTopTable() || get(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 lenFamilyFn( return {ctx->builtins->numberType, false, {}, {}}; } -TypeFamilyReductionResult unmFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult unmFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 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 unmFamilyFn( return {std::nullopt, true, {}, {}}; } -NotNull TypeFamilyContext::pushConstraint(ConstraintV&& c) +NotNull TypeFunctionContext::pushConstraint(ConstraintV&& c) { LUAU_ASSERT(solver); NotNull newConstraint = solver->pushConstraint(scope, constraint ? constraint->location : Location{}, std::move(c)); @@ -744,12 +744,12 @@ NotNull TypeFamilyContext::pushConstraint(ConstraintV&& c) return newConstraint; } -TypeFamilyReductionResult numericBinopFamilyFn(TypeId instance, const std::vector& typeParams, - const std::vector& packParams, NotNull ctx, const std::string metamethod) +TypeFunctionReductionResult numericBinopFamilyFn(TypeId instance, const std::vector& typeParams, + const std::vector& packParams, NotNull 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 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 numericBinopFamilyFn(TypeId instance, const st return {extracted.head.front(), false, {}, {}}; } -TypeFamilyReductionResult addFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult addFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 subFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult subFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 mulFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult mulFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 divFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult divFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 idivFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult idivFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 powFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult powFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 modFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult modFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 concatFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult concatFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 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 concatFamilyFn( return {ctx->builtins->stringType, false, {}, {}}; } -TypeFamilyReductionResult andFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult andFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 andFamilyFn( return {overallResult.result, false, std::move(blockedTypes), {}}; } -TypeFamilyReductionResult orFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult orFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 orFamilyFn( return {overallResult.result, false, std::move(blockedTypes), {}}; } -static TypeFamilyReductionResult comparisonFamilyFn(TypeId instance, const std::vector& typeParams, - const std::vector& packParams, NotNull ctx, const std::string metamethod) +static TypeFunctionReductionResult comparisonFamilyFn(TypeId instance, const std::vector& typeParams, + const std::vector& packParams, NotNull 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 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 comparisonFamilyFn(TypeId instance, con return {ctx->builtins->booleanType, false, {}, {}}; } -TypeFamilyReductionResult ltFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult ltFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 leFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult leFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 eqFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult eqFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 refineFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult refineFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 refineFamilyFn( return {resultTy, false, {}, {}}; } -TypeFamilyReductionResult singletonFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult singletonFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 singletonFamilyFn( return {ctx->builtins->unknownType, false, {}, {}}; } -TypeFamilyReductionResult unionFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult unionFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 unionFamilyFn( } -TypeFamilyReductionResult intersectFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult intersectFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 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& result, DenseHashSet& seen, bool isRaw, NotNull ctx) +bool computeKeysOf(TypeId ty, Set& result, DenseHashSet& seen, bool isRaw, NotNull ctx) { // if the type is the top table type, the answer is just "all strings" if (get(ty)) @@ -1725,12 +1725,12 @@ bool computeKeysOf(TypeId ty, Set& result, DenseHashSet& se return false; } -TypeFamilyReductionResult keyofFamilyImpl( - const std::vector& typeParams, const std::vector& packParams, NotNull ctx, bool isRaw) +TypeFunctionReductionResult keyofFamilyImpl( + const std::vector& typeParams, const std::vector& packParams, NotNull 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 keyofFamilyImpl( return {ctx->arena->addType(UnionType{singletons}), false, {}, {}}; } -TypeFamilyReductionResult keyofFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult keyofFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 rawkeyofFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult rawkeyofFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 rawkeyofFamilyFn( If found, appends that property to `result` and returns true Else, returns false */ bool searchPropsAndIndexer( - TypeId ty, TableType::Props tblProps, std::optional tblIndexer, DenseHashSet& result, NotNull ctx) + TypeId ty, TableType::Props tblProps, std::optional tblIndexer, DenseHashSet& result, NotNull 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& result, NotNull ctx, bool isRaw) +bool tblIndexInto(TypeId indexer, TypeId indexee, DenseHashSet& result, NotNull ctx, bool isRaw) { indexer = follow(indexer); indexee = follow(indexee); @@ -1960,8 +1960,8 @@ bool tblIndexInto(TypeId indexer, TypeId indexee, DenseHashSet& 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` is the indexee and `"name"` is the indexer */ -TypeFamilyReductionResult indexFamilyImpl( - const std::vector& typeParams, const std::vector& packParams, NotNull ctx, bool isRaw) +TypeFunctionReductionResult indexFamilyImpl( + const std::vector& typeParams, const std::vector& packParams, NotNull ctx, bool isRaw) { TypeId indexeeTy = follow(typeParams.at(0)); std::shared_ptr indexeeNormTy = ctx->normalizer->normalize(indexeeTy); @@ -2064,104 +2064,104 @@ TypeFamilyReductionResult indexFamilyImpl( return {ctx->arena->addType(UnionType{std::vector(properties.begin(), properties.end())}), false, {}, {}}; } -TypeFamilyReductionResult indexFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult indexFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 rawgetFamilyFn( - TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull ctx) +TypeFunctionReductionResult rawgetFamilyFn( + TypeId instance, const std::vector& typeParams, const std::vector& packParams, NotNull 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 arena, NotNull scope) const +void BuiltinTypeFunctions::addToScope(NotNull arena, NotNull scope) const { - // make a type function for a one-argument type family - auto mkUnaryTypeFamily = [&](const TypeFamily* family) { + // make a type function for a one-argument type function + auto mkUnaryTypeFunction = [&](const TypeFunction* tf) { TypeId t = arena->addType(GenericType{"T"}); GenericTypeDefinition genericT{t}; - return TypeFun{{genericT}, arena->addType(TypeFamilyInstanceType{NotNull{family}, {t}, {}})}; + return TypeFun{{genericT}, arena->addType(TypeFunctionInstanceType{NotNull{tf}, {t}, {}})}; }; - // make a type function for a two-argument type family - auto mkBinaryTypeFamily = [&](const TypeFamily* family) { + // make a type function for a two-argument type function + auto mkBinaryTypeFunction = [&](const TypeFunction* tf) { TypeId t = arena->addType(GenericType{"T"}); TypeId u = arena->addType(GenericType{"U"}); GenericTypeDefinition genericT{t}; GenericTypeDefinition genericU{u, {t}}; - return TypeFun{{genericT, genericU}, arena->addType(TypeFamilyInstanceType{NotNull{family}, {t, u}, {}})}; + return TypeFun{{genericT, genericU}, arena->addType(TypeFunctionInstanceType{NotNull{tf}, {t, u}, {}})}; }; - scope->exportedTypeBindings[lenFamily.name] = mkUnaryTypeFamily(&lenFamily); - scope->exportedTypeBindings[unmFamily.name] = mkUnaryTypeFamily(&unmFamily); + scope->exportedTypeBindings[lenFunc.name] = mkUnaryTypeFunction(&lenFunc); + scope->exportedTypeBindings[unmFunc.name] = mkUnaryTypeFunction(&unmFunc); - scope->exportedTypeBindings[addFamily.name] = mkBinaryTypeFamily(&addFamily); - scope->exportedTypeBindings[subFamily.name] = mkBinaryTypeFamily(&subFamily); - scope->exportedTypeBindings[mulFamily.name] = mkBinaryTypeFamily(&mulFamily); - scope->exportedTypeBindings[divFamily.name] = mkBinaryTypeFamily(&divFamily); - scope->exportedTypeBindings[idivFamily.name] = mkBinaryTypeFamily(&idivFamily); - scope->exportedTypeBindings[powFamily.name] = mkBinaryTypeFamily(&powFamily); - scope->exportedTypeBindings[modFamily.name] = mkBinaryTypeFamily(&modFamily); - scope->exportedTypeBindings[concatFamily.name] = mkBinaryTypeFamily(&concatFamily); + scope->exportedTypeBindings[addFunc.name] = mkBinaryTypeFunction(&addFunc); + scope->exportedTypeBindings[subFunc.name] = mkBinaryTypeFunction(&subFunc); + scope->exportedTypeBindings[mulFunc.name] = mkBinaryTypeFunction(&mulFunc); + scope->exportedTypeBindings[divFunc.name] = mkBinaryTypeFunction(&divFunc); + scope->exportedTypeBindings[idivFunc.name] = mkBinaryTypeFunction(&idivFunc); + scope->exportedTypeBindings[powFunc.name] = mkBinaryTypeFunction(&powFunc); + scope->exportedTypeBindings[modFunc.name] = mkBinaryTypeFunction(&modFunc); + scope->exportedTypeBindings[concatFunc.name] = mkBinaryTypeFunction(&concatFunc); - scope->exportedTypeBindings[ltFamily.name] = mkBinaryTypeFamily(<Family); - scope->exportedTypeBindings[leFamily.name] = mkBinaryTypeFamily(&leFamily); - scope->exportedTypeBindings[eqFamily.name] = mkBinaryTypeFamily(&eqFamily); + scope->exportedTypeBindings[ltFunc.name] = mkBinaryTypeFunction(<Func); + scope->exportedTypeBindings[leFunc.name] = mkBinaryTypeFunction(&leFunc); + scope->exportedTypeBindings[eqFunc.name] = mkBinaryTypeFunction(&eqFunc); - scope->exportedTypeBindings[keyofFamily.name] = mkUnaryTypeFamily(&keyofFamily); - scope->exportedTypeBindings[rawkeyofFamily.name] = mkUnaryTypeFamily(&rawkeyofFamily); + scope->exportedTypeBindings[keyofFunc.name] = mkUnaryTypeFunction(&keyofFunc); + scope->exportedTypeBindings[rawkeyofFunc.name] = mkUnaryTypeFunction(&rawkeyofFunc); - scope->exportedTypeBindings[indexFamily.name] = mkBinaryTypeFamily(&indexFamily); - scope->exportedTypeBindings[rawgetFamily.name] = mkBinaryTypeFamily(&rawgetFamily); + scope->exportedTypeBindings[indexFunc.name] = mkBinaryTypeFunction(&indexFunc); + scope->exportedTypeBindings[rawgetFunc.name] = mkBinaryTypeFunction(&rawgetFunc); } -const BuiltinTypeFamilies& builtinTypeFunctions() +const BuiltinTypeFunctions& builtinTypeFunctions() { - static std::unique_ptr result = std::make_unique(); + static std::unique_ptr result = std::make_unique(); return *result; } diff --git a/Analysis/src/TypeFamilyReductionGuesser.cpp b/Analysis/src/TypeFunctionReductionGuesser.cpp similarity index 72% rename from Analysis/src/TypeFamilyReductionGuesser.cpp rename to Analysis/src/TypeFunctionReductionGuesser.cpp index 7f865998..9279c1d3 100644 --- a/Analysis/src/TypeFamilyReductionGuesser.cpp +++ b/Analysis/src/TypeFunctionReductionGuesser.cpp @@ -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 cyclicInstance{nullptr}; DenseHashSet 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(t)) + if (get(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 arena, NotNull builtins, NotNull normalizer) +TypeFunctionReductionGuesser::TypeFunctionReductionGuesser(NotNull arena, NotNull builtins, NotNull normalizer) : arena(arena) , builtins(builtins) , normalizer(normalizer) { } -bool TypeFamilyReductionGuesser::isFunctionGenericsSaturated(const FunctionType& ftv, DenseHashSet& argsUsed) +bool TypeFunctionReductionGuesser::isFunctionGenericsSaturated(const FunctionType& ftv, DenseHashSet& 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 TypeFamilyReductionGuesser::guess(TypeId typ) +std::optional TypeFunctionReductionGuesser::guess(TypeId typ) { std::optional guessedType = guessType(typ); @@ -97,13 +97,13 @@ std::optional TypeFamilyReductionGuesser::guess(TypeId typ) return {}; TypeId guess = follow(*guessedType); - if (get(guess)) + if (get(guess)) return {}; return guess; } -std::optional TypeFamilyReductionGuesser::guess(TypePackId tp) +std::optional TypeFunctionReductionGuesser::guess(TypePackId tp) { auto [head, tail] = flatten(tp); @@ -118,7 +118,7 @@ std::optional TypeFamilyReductionGuesser::guess(TypePackId tp) return {}; TypeId guess = follow(*guessedType); - if (get(guess)) + if (get(guess)) return {}; guessedHead.push_back(*guessedType); @@ -127,7 +127,7 @@ std::optional 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> results; @@ -157,7 +157,7 @@ TypeFamilyReductionGuessResult TypeFamilyReductionGuesser::guessTypeFamilyReduct if (!guessedType.has_value()) continue; TypeId guess = follow(*guessedType); - if (get(guess)) + if (get(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(recommendedAnnotation)) + if (auto t = get(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 TypeFamilyReductionGuesser::guessType(TypeId arg) +std::optional TypeFunctionReductionGuesser::guessType(TypeId arg) { TypeId t = follow(arg); if (substitutable.contains(t)) @@ -189,12 +189,12 @@ std::optional TypeFamilyReductionGuesser::guessType(TypeId arg) TypeId subst = follow(substitutable[t]); if (subst == t || substitutable.contains(subst)) return subst; - else if (!get(subst)) + else if (!get(subst)) return subst; else return guessType(subst); } - if (get(t)) + if (get(t)) { if (familyReducesTo.contains(t)) return familyReducesTo[t]; @@ -202,41 +202,41 @@ std::optional 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(ty)) + if (get(ty)) return true; if (get(ty)) return true; @@ -245,17 +245,17 @@ bool TypeFamilyReductionGuesser::operandIsAssignable(TypeId ty) return false; } -std::shared_ptr TypeFamilyReductionGuesser::normalize(TypeId ty) +std::shared_ptr TypeFunctionReductionGuesser::normalize(TypeId ty) { return normalizer->normalize(ty); } -std::optional TypeFamilyReductionGuesser::tryAssignOperandType(TypeId ty) +std::optional 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(ty)) + if (auto tfit = get(ty)) { if (familyReducesTo.contains(ty)) return {familyReducesTo[ty]}; @@ -272,30 +272,30 @@ std::optional 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(t)) - inferTypeFamilySubstitutions(t, tf); + if (auto tf = get(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(arg)) + if (auto tfit = get(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 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 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 lty = normalize(lhsTy); std::shared_ptr 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]); diff --git a/Analysis/src/Unifier.cpp b/Analysis/src/Unifier.cpp index 1802345d..90d9e92e 100644 --- a/Analysis/src/Unifier.cpp +++ b/Analysis/src/Unifier.cpp @@ -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(superTy)) - ice("Unexpected TypeFamilyInstanceType superTy"); + if (log.get(superTy)) + ice("Unexpected TypeFunctionInstanceType superTy"); - if (log.get(subTy)) - ice("Unexpected TypeFamilyInstanceType subTy"); + if (log.get(subTy)) + ice("Unexpected TypeFunctionInstanceType subTy"); auto superFree = log.getMutable(superTy); auto subFree = log.getMutable(subTy); diff --git a/Analysis/src/Unifier2.cpp b/Analysis/src/Unifier2.cpp index 6dcd7197..c43edbd1 100644 --- a/Analysis/src/Unifier2.cpp +++ b/Analysis/src/Unifier2.cpp @@ -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(ty) || get(ty); + return get(ty) || get(ty); } // returns `true` if `tp` is irressolvable and should be added to `incompleteSubtypes`. static bool isIrresolvable(TypePackId tp) { - return get(tp) || get(tp); + return get(tp) || get(tp); } Unifier2::Unifier2(NotNull arena, NotNull builtinTypes, NotNull scope, NotNull ice) diff --git a/CodeGen/src/IrAnalysis.cpp b/CodeGen/src/IrAnalysis.cpp index f78823df..73775bf9 100644 --- a/CodeGen/src/IrAnalysis.cpp +++ b/CodeGen/src/IrAnalysis.cpp @@ -13,8 +13,6 @@ #include -LUAU_FASTFLAGVARIABLE(LuauCodegenInstG, false) - namespace Luau { namespace CodeGen @@ -54,9 +52,7 @@ void updateUseCounts(IrFunction& function) checkOp(inst.d); checkOp(inst.e); checkOp(inst.f); - - if (FFlag::LuauCodegenInstG) - checkOp(inst.g); + checkOp(inst.g); } } @@ -100,9 +96,7 @@ void updateLastUseLocations(IrFunction& function, const std::vector& s checkOp(inst.d); checkOp(inst.e); checkOp(inst.f); - - if (FFlag::LuauCodegenInstG) - checkOp(inst.g); + checkOp(inst.g); } } } @@ -137,11 +131,8 @@ 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; - } + 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 @@ -179,9 +170,7 @@ std::pair getLiveInOutValueCount(IrFunction& function, IrBlo checkOp(inst.d); checkOp(inst.e); checkOp(inst.f); - - if (FFlag::LuauCodegenInstG) - checkOp(inst.g); + checkOp(inst.g); } return std::make_pair(liveIns, liveOuts); @@ -505,9 +494,7 @@ static void computeCfgBlockEdges(IrFunction& function) checkOp(inst.d); checkOp(inst.e); checkOp(inst.f); - - if (FFlag::LuauCodegenInstG) - checkOp(inst.g); + checkOp(inst.g); } } diff --git a/CodeGen/src/IrBuilder.cpp b/CodeGen/src/IrBuilder.cpp index 061bf388..73a1bdc2 100644 --- a/CodeGen/src/IrBuilder.cpp +++ b/CodeGen/src/IrBuilder.cpp @@ -13,7 +13,6 @@ #include -LUAU_FASTFLAG(LuauCodegenInstG) LUAU_FASTFLAG(LuauCodegenFastcall3) namespace Luau @@ -641,9 +640,7 @@ void IrBuilder::clone(const IrBlock& source, bool removeCurrentTerminator) redirect(clone.d); redirect(clone.e); redirect(clone.f); - - if (FFlag::LuauCodegenInstG) - redirect(clone.g); + redirect(clone.g); addUse(function, clone.a); addUse(function, clone.b); @@ -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); + 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); + inst(clone.cmd, clone.a, clone.b, clone.c, clone.d, clone.e, clone.f, clone.g); } } @@ -760,31 +752,11 @@ IrOp IrBuilder::inst(IrCmd cmd, IrOp a, IrOp b, IrOp c, IrOp d, IrOp e) IrOp IrBuilder::inst(IrCmd cmd, IrOp a, IrOp b, IrOp c, IrOp d, IrOp e, IrOp f) { - if (FFlag::LuauCodegenInstG) - { - return inst(cmd, a, b, c, d, e, f, {}); - } - else - { - uint32_t index = uint32_t(function.instructions.size()); - function.instructions.push_back({cmd, a, b, c, d, e, f}); - - CODEGEN_ASSERT(!inTerminatedBlock); - - if (isBlockTerminator(cmd)) - { - function.blocks[activeBlockIdx].finish = index; - inTerminatedBlock = true; - } - - return {IrOpKind::Inst, index}; - } + return inst(cmd, a, b, c, d, e, f, {}); } 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}); diff --git a/CodeGen/src/IrDump.cpp b/CodeGen/src/IrDump.cpp index e54c2661..ab20c28d 100644 --- a/CodeGen/src/IrDump.cpp +++ b/CodeGen/src/IrDump.cpp @@ -7,8 +7,6 @@ #include -LUAU_FASTFLAG(LuauCodegenInstG) - namespace Luau { namespace CodeGen @@ -419,9 +417,7 @@ 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, ", "); + checkOp(inst.g, ", "); } void toString(IrToStringContext& ctx, const IrBlock& block, uint32_t index) @@ -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,9 +893,7 @@ std::string toDot(const IrFunction& function, bool includeInst) checkOp(inst.d); checkOp(inst.e); checkOp(inst.f); - - if (FFlag::LuauCodegenInstG) - checkOp(inst.g); + checkOp(inst.g); } } diff --git a/CodeGen/src/IrRegAllocA64.cpp b/CodeGen/src/IrRegAllocA64.cpp index af63a2fc..522b0bc1 100644 --- a/CodeGen/src/IrRegAllocA64.cpp +++ b/CodeGen/src/IrRegAllocA64.cpp @@ -11,7 +11,6 @@ #include LUAU_FASTFLAGVARIABLE(DebugCodegenChaosA64, false) -LUAU_FASTFLAG(LuauCodegenInstG) namespace Luau { @@ -257,9 +256,7 @@ void IrRegAllocA64::freeLastUseRegs(const IrInst& inst, uint32_t index) checkOp(inst.d); checkOp(inst.e); checkOp(inst.f); - - if (FFlag::LuauCodegenInstG) - checkOp(inst.g); + checkOp(inst.g); } void IrRegAllocA64::freeTempRegs() diff --git a/CodeGen/src/IrRegAllocX64.cpp b/CodeGen/src/IrRegAllocX64.cpp index 60326074..12b9e379 100644 --- a/CodeGen/src/IrRegAllocX64.cpp +++ b/CodeGen/src/IrRegAllocX64.cpp @@ -6,8 +6,6 @@ #include "EmitCommonX64.h" -LUAU_FASTFLAG(LuauCodegenInstG) - namespace Luau { namespace CodeGen @@ -183,9 +181,7 @@ void IrRegAllocX64::freeLastUseRegs(const IrInst& inst, uint32_t instIdx) checkOp(inst.d); checkOp(inst.e); checkOp(inst.f); - - if (FFlag::LuauCodegenInstG) - checkOp(inst.g); + checkOp(inst.g); } bool IrRegAllocX64::isLastUseReg(const IrInst& target, uint32_t instIdx) const diff --git a/CodeGen/src/IrUtils.cpp b/CodeGen/src/IrUtils.cpp index 129945df..b5795ca1 100644 --- a/CodeGen/src/IrUtils.cpp +++ b/CodeGen/src/IrUtils.cpp @@ -12,8 +12,6 @@ #include #include -LUAU_FASTFLAG(LuauCodegenInstG) - namespace Luau { namespace CodeGen @@ -317,9 +315,7 @@ 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); + removeUse(function, inst.g); inst.a = {}; inst.b = {}; @@ -327,9 +323,7 @@ void kill(IrFunction& function, IrInst& inst) inst.d = {}; inst.e = {}; inst.f = {}; - - if (FFlag::LuauCodegenInstG) - inst.g = {}; + inst.g = {}; } void kill(IrFunction& function, uint32_t start, uint32_t end) @@ -378,9 +372,7 @@ 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); + addUse(function, replacement.g); // An extra reference is added so block will not remove itself block.useCount++; @@ -403,9 +395,7 @@ 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); + removeUse(function, inst.g); // Inherit existing use count (last use is skipped as it will be defined later) replacement.useCount = inst.useCount; @@ -431,9 +421,7 @@ 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); + removeUse(function, inst.g); inst.a = replacement; inst.b = {}; @@ -441,9 +429,7 @@ void substitute(IrFunction& function, IrInst& inst, IrOp replacement) inst.d = {}; inst.e = {}; inst.f = {}; - - if (FFlag::LuauCodegenInstG) - inst.g = {}; + inst.g = {}; } void applySubstitutions(IrFunction& function, IrOp& op) @@ -487,9 +473,7 @@ 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); + applySubstitutions(function, inst.g); } bool compare(double a, double b, IrCondition cond) diff --git a/Sources.cmake b/Sources.cmake index 4c5504b6..72038e70 100644 --- a/Sources.cmake +++ b/Sources.cmake @@ -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 diff --git a/tests/IrBuilder.test.cpp b/tests/IrBuilder.test.cpp index 611eb7b5..238cf161 100644 --- a/tests/IrBuilder.test.cpp +++ b/tests/IrBuilder.test.cpp @@ -13,7 +13,6 @@ #include 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); diff --git a/tests/Subtyping.test.cpp b/tests/Subtyping.test.cpp index afc22d0f..e70ec1ae 100644 --- a/tests/Subtyping.test.cpp +++ b/tests/Subtyping.test.cpp @@ -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 - 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 - 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 ~ 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 ~ 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") { // (x: T, x: U) -> add <: (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") diff --git a/tests/TypeFamily.test.cpp b/tests/TypeFunction.test.cpp similarity index 94% rename from tests/TypeFamily.test.cpp rename to tests/TypeFunction.test.cpp index 068e8684..9638b3ff 100644 --- a/tests/TypeFamily.test.cpp +++ b/tests/TypeFunction.test.cpp @@ -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& tys, const std::vector& tps, - NotNull ctx) -> TypeFamilyReductionResult { + NotNull ctx) -> TypeFunctionReductionResult { LUAU_ASSERT(tys.size() == 1); TypeId param = follow(tys.at(0)); if (isString(param)) { - return TypeFamilyReductionResult{ctx->builtins->numberType, false, {}, {}}; + return TypeFunctionReductionResult{ctx->builtins->numberType, false, {}, {}}; } else if (isNumber(param)) { - return TypeFamilyReductionResult{ctx->builtins->stringType, false, {}, {}}; + return TypeFunctionReductionResult{ctx->builtins->stringType, false, {}, {}}; } - else if (is(param) || is(param) || is(param) || + else if (is(param) || is(param) || is(param) || (ctx->solver && ctx->solver->hasUnresolvedConstraints(param))) { - return TypeFamilyReductionResult{std::nullopt, false, {param}, {}}; + return TypeFunctionReductionResult{std::nullopt, false, {param}, {}}; } else { - return TypeFamilyReductionResult{std::nullopt, true, {}, {}}; + return TypeFunctionReductionResult{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" == toString(requireTypeAlias("C"))); CHECK("string" == toString(requireType("y"))); - CHECK("Type family instance Swap is uninhabited" == toString(result.errors[0])); + CHECK("Type function instance Swap 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" == toString(requireType("c"))); - CHECK("Type family instance Swap is uninhabited" == toString(result.errors[0])); + CHECK("Type function instance Swap 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 is uninhabited" == toString(result.errors[0])); - CHECK("Type family instance Swap is uninhabited" == toString(result.errors[1])); + CHECK("Type function instance Swap is uninhabited" == toString(result.errors[0])); + CHECK("Type function instance Swap 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 is uninhabited"); + CHECK(toString(result.errors[i]) == "Type function instance Swap 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}"); - CHECK(toString(result.errors[0]) == "Type family instance Swap is uninhabited"); + CHECK(toString(result.errors[0]) == "Type function instance Swap 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"); - CHECK(toString(result.errors[0]) == "Type family instance Swap is uninhabited"); + CHECK(toString(result.errors[0]) == "Type function instance Swap 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"); CHECK(toString(requireType("c")) == "Add"); - CHECK(toString(result.errors[0]) == "Type family instance Add is uninhabited"); - CHECK(toString(result.errors[1]) == "Type family instance Add is uninhabited"); + CHECK(toString(result.errors[0]) == "Type function instance Add is uninhabited"); + CHECK(toString(result.errors[1]) == "Type function instance Add 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 depends on generic function parameters but does not appear in the function " + CHECK(toString(result.errors[0]) == "Type function instance Add 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' is invalid"); CHECK(toString(result.errors[1]) == "Type 'MyObject | boolean' does not have keys, so 'keyof' 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' is invalid"); CHECK(toString(result.errors[1]) == "Type 'MyObject | boolean' does not have keys, so 'rawkeyof' 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' is invalid"); CHECK(toString(result.errors[1]) == "Type 'BaseClass | boolean' does not have keys, so 'keyof' is invalid"); @@ -757,7 +757,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "exceeded_distributivity_limits") )"); LUAU_REQUIRE_ERROR_COUNT(1, result); - CHECK(get(result.errors[0])); + CHECK(get(result.errors[0])); } TEST_CASE_FIXTURE(BuiltinsFixture, "didnt_quite_exceed_distributivity_limits") @@ -1163,4 +1163,4 @@ TEST_CASE_FIXTURE(ClassFixture, "rawget_type_family_errors_w_classes") CHECK(toString(result.errors[0]) == "Property '\"BaseField\"' does not exist on type 'BaseClass'"); } -TEST_SUITE_END(); \ No newline at end of file +TEST_SUITE_END(); diff --git a/tests/TypeInfer.anyerror.test.cpp b/tests/TypeInfer.anyerror.test.cpp index c532c069..d1cbd048 100644 --- a/tests/TypeInfer.anyerror.test.cpp +++ b/tests/TypeInfer.anyerror.test.cpp @@ -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" diff --git a/tests/TypeInfer.functions.test.cpp b/tests/TypeInfer.functions.test.cpp index 410a9859..94b53cc5 100644 --- a/tests/TypeInfer.functions.test.cpp +++ b/tests/TypeInfer.functions.test.cpp @@ -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]: any} +local function captureDependencies( + saveToSet: Set, + callback: (...any) -> any, + ... +) + local data = table.pack(xpcall(callback, parseError, ...)) + end +)"); +} + TEST_SUITE_END(); diff --git a/tests/TypeInfer.operators.test.cpp b/tests/TypeInfer.operators.test.cpp index b8bb9795..929f8159 100644 --- a/tests/TypeInfer.operators.test.cpp +++ b/tests/TypeInfer.operators.test.cpp @@ -264,7 +264,7 @@ TEST_CASE_FIXTURE(Fixture, "cannot_indirectly_compare_types_that_do_not_have_a_m if (FFlag::DebugLuauDeferredConstraintResolution) { - UninhabitedTypeFamily* utf = get(result.errors[0]); + UninhabitedTypeFunction* utf = get(result.errors[0]); REQUIRE(utf); REQUIRE_EQ(toString(utf->ty), "lt"); } @@ -294,7 +294,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "cannot_indirectly_compare_types_that_do_not_ if (FFlag::DebugLuauDeferredConstraintResolution) { - UninhabitedTypeFamily* utf = get(result.errors[0]); + UninhabitedTypeFunction* utf = get(result.errors[0]); REQUIRE(utf); REQUIRE_EQ(toString(utf->ty), "lt"); } @@ -557,7 +557,7 @@ TEST_CASE_FIXTURE(BuiltinsFixture, "typecheck_unary_minus") { LUAU_REQUIRE_ERROR_COUNT(2, result); - UninhabitedTypeFamily* utf = get(result.errors[0]); + UninhabitedTypeFunction* utf = get(result.errors[0]); REQUIRE(utf); CHECK_EQ(toString(utf->ty), "unm"); @@ -786,7 +786,7 @@ TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operato if (FFlag::DebugLuauDeferredConstraintResolution) { - UninhabitedTypeFamily* utf = get(result.errors[0]); + UninhabitedTypeFunction* utf = get(result.errors[0]); REQUIRE(utf); REQUIRE_EQ(toString(utf->ty), "lt"); } @@ -817,7 +817,7 @@ TEST_CASE_FIXTURE(Fixture, "error_on_invalid_operand_types_to_relational_operato if (FFlag::DebugLuauDeferredConstraintResolution) { - UninhabitedTypeFamily* utf = get(result.errors[0]); + UninhabitedTypeFunction* utf = get(result.errors[0]); REQUIRE(utf); REQUIRE_EQ(toString(utf->ty), "lt"); } diff --git a/tools/faillist.txt b/tools/faillist.txt index 0ada384d..51f086ff 100644 --- a/tools/faillist.txt +++ b/tools/faillist.txt @@ -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