Skip to content

Commit

Permalink
Sync to upstream/release/622 (#1232)
Browse files Browse the repository at this point in the history
# What's changed?

* Improved the actual message for the type errors for `cannot call
non-function` when attempting to call a union of functions/callable
tables. The error now correctly explains the issue is an inability to
determine the return type of the call in this situation.
* Resolve an issue where tables and metatables were not correctly being
cloned during instantiation (fixes #1176).
* Refactor `luaM_getnextgcopage` to `luaM_getnextpage` (generally
removing `gco` prefix where appropriate).
* Optimize `table.move` between tables for large ranges of elements.
* Reformat a bunch of code automatically using `clang-format`.

### New Type Solver

* Clean up minimally-used or unused constraints in the constraint solver
(`InstantiationConstraint`, `SetOpConstraint`,
`SingletonOrTopTypeConstraint`).
* Add a builtin `singleton` type family to replace
`SingletonOrTopTypeConstraint` when inferring refinements.
* Fixed a crash involving type path reasoning by recording when type
family reduction has taken place in the path.
* Improved constraint ordering by blocking on unreduced types families
that are not yet proven uninhabitable.
* Improved the handling of `SetIndexerConstraints` for both better
inference quality and to resolve crashes.
* Fix a crash when normalizing cyclic unions of intersections.
* Fix a crash when normalizing an intersection with the negation of
`unknown`.
* Fix a number of crashes caused by missing `follow` calls on `TypeId`s.
* Changed type family reduction to correctly use a semantic notion of
uninhabited types, rather than checking for `never` types specifically.
* Refactor the `union` and `intersect` type families to be variadic.

### Native Code Generation

* Improve translation for userdata key get/set and userdata/vector
namecall.
* Provide `[top level]` and `[anonymous]` as function names to
`FunctionStats` as appropriate when no function name is available.
* Disable unwind support on Android platforms since it is unsupported.
*  

---

### Internal Contributors

Co-authored-by: Aaron Weiss <aaronweiss@roblox.com>
Co-authored-by: Alexander McCord <amccord@roblox.com>
Co-authored-by: Andy Friesen <afriesen@roblox.com>
Co-authored-by: Aviral Goel <agoel@roblox.com>
Co-authored-by: Vighnesh Vijay <vvijay@roblox.com>
Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>

---------

Co-authored-by: Alexander McCord <amccord@roblox.com>
Co-authored-by: Andy Friesen <afriesen@roblox.com>
Co-authored-by: Vighnesh <vvijay@roblox.com>
Co-authored-by: Aviral Goel <agoel@roblox.com>
Co-authored-by: David Cope <dcope@roblox.com>
Co-authored-by: Lily Brown <lbrown@roblox.com>
Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
  • Loading branch information
8 people committed Apr 19, 2024
1 parent 9c21462 commit 68bd1b2
Show file tree
Hide file tree
Showing 61 changed files with 1,404 additions and 753 deletions.
41 changes: 3 additions & 38 deletions Analysis/include/Luau/Constraint.h
Expand Up @@ -52,13 +52,6 @@ struct GeneralizationConstraint
std::vector<TypeId> interiorTypes;
};

// subType ~ inst superType
struct InstantiationConstraint
{
TypeId subType;
TypeId superType;
};

// variables ~ iterate iterator
// Unpack the iterator, figure out what types it iterates over, and bind those types to variables.
struct IterableConstraint
Expand Down Expand Up @@ -229,17 +222,6 @@ struct SetIndexerConstraint
TypeId propType;
};

// if negation:
// result ~ if isSingleton D then ~D else unknown where D = discriminantType
// if not negation:
// result ~ if isSingleton D then D else unknown where D = discriminantType
struct SingletonOrTopTypeConstraint
{
TypeId resultType;
TypeId discriminantType;
bool negated;
};

// resultType ~ unpack sourceTypePack
//
// Similar to PackSubtypeConstraint, but with one important difference: If the
Expand Down Expand Up @@ -269,22 +251,6 @@ struct Unpack1Constraint
bool resultIsLValue = false;
};

// resultType ~ T0 op T1 op ... op TN
//
// op is either union or intersection. If any of the input types are blocked,
// this constraint will block unless forced.
struct SetOpConstraint
{
enum
{
Intersection,
Union
} mode;

TypeId resultType;
std::vector<TypeId> types;
};

// ty ~ reduce ty
//
// Try to reduce ty, if it is a TypeFamilyInstanceType. Otherwise, do nothing.
Expand All @@ -301,10 +267,9 @@ struct ReducePackConstraint
TypePackId tp;
};

using ConstraintV = Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, InstantiationConstraint, IterableConstraint,
NameConstraint, TypeAliasExpansionConstraint, FunctionCallConstraint, FunctionCheckConstraint, PrimitiveTypeConstraint, HasPropConstraint,
SetPropConstraint, HasIndexerConstraint, SetIndexerConstraint, SingletonOrTopTypeConstraint, UnpackConstraint, Unpack1Constraint,
SetOpConstraint, ReduceConstraint, ReducePackConstraint, EqualityConstraint>;
using ConstraintV = Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, IterableConstraint, NameConstraint,
TypeAliasExpansionConstraint, FunctionCallConstraint, FunctionCheckConstraint, PrimitiveTypeConstraint, HasPropConstraint, SetPropConstraint,
HasIndexerConstraint, SetIndexerConstraint, UnpackConstraint, Unpack1Constraint, ReduceConstraint, ReducePackConstraint, EqualityConstraint>;

struct Constraint
{
Expand Down
16 changes: 7 additions & 9 deletions Analysis/include/Luau/ConstraintSolver.h
Expand Up @@ -91,6 +91,9 @@ struct ConstraintSolver
// A mapping from free types to the number of unresolved constraints that mention them.
DenseHashMap<TypeId, size_t> unresolvedConstraints{{}};

// Irreducible/uninhabited type families or type pack families.
DenseHashSet<const void*> uninhabitedTypeFamilies{{}};

// Recorded errors that take place within the solver.
ErrorVec errors;

Expand Down Expand Up @@ -124,7 +127,6 @@ struct ConstraintSolver
bool tryDispatch(const SubtypeConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const PackSubtypeConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const GeneralizationConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const InstantiationConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const NameConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const TypeAliasExpansionConstraint& c, NotNull<const Constraint> constraint);
Expand All @@ -134,22 +136,18 @@ struct ConstraintSolver
bool tryDispatch(const HasPropConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const SetPropConstraint& c, NotNull<const Constraint> constraint);

bool tryDispatchHasIndexer(int& recursionDepth, NotNull<const Constraint> constraint, TypeId subjectType, TypeId indexType, TypeId resultType, Set<TypeId>& seen);
bool tryDispatchHasIndexer(
int& recursionDepth, NotNull<const Constraint> constraint, TypeId subjectType, TypeId indexType, TypeId resultType, Set<TypeId>& seen);
bool tryDispatch(const HasIndexerConstraint& c, NotNull<const Constraint> constraint);

/// (dispatched, found) where
/// - dispatched: this constraint can be considered having dispatched.
/// - found: true if adding an indexer for a particular type was allowed.
std::pair<bool, bool> tryDispatchSetIndexer(NotNull<const Constraint> constraint, TypeId subjectType, TypeId indexType, TypeId propType, bool expandFreeTypeBounds);
std::pair<bool, std::optional<TypeId>> tryDispatchSetIndexer(
NotNull<const Constraint> constraint, TypeId subjectType, TypeId indexType, TypeId propType, bool expandFreeTypeBounds);
bool tryDispatch(const SetIndexerConstraint& c, NotNull<const Constraint> constraint, bool force);

bool tryDispatch(const SingletonOrTopTypeConstraint& c, NotNull<const Constraint> constraint);

bool tryDispatchUnpack1(NotNull<const Constraint> constraint, TypeId resultType, TypeId sourceType, bool resultIsLValue);
bool tryDispatch(const UnpackConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const Unpack1Constraint& c, NotNull<const Constraint> constraint);

bool tryDispatch(const SetOpConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const ReduceConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const ReducePackConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const EqualityConstraint& c, NotNull<const Constraint> constraint, bool force);
Expand Down
17 changes: 5 additions & 12 deletions Analysis/include/Luau/OverloadResolution.h
Expand Up @@ -69,7 +69,8 @@ struct OverloadResolver

struct SolveResult
{
enum OverloadCallResult {
enum OverloadCallResult
{
Ok,
CodeTooComplex,
OccursCheckFailed,
Expand All @@ -87,16 +88,8 @@ struct SolveResult
// Helper utility, presently used for binary operator type families.
//
// Given a function and a set of arguments, select a suitable overload.
SolveResult solveFunctionCall(
NotNull<TypeArena> arena,
NotNull<BuiltinTypes> builtinTypes,
NotNull<Normalizer> normalizer,
NotNull<InternalErrorReporter> iceReporter,
NotNull<TypeCheckLimits> limits,
NotNull<Scope> scope,
const Location& location,
TypeId fn,
TypePackId argsPack
);
SolveResult solveFunctionCall(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtinTypes, NotNull<Normalizer> normalizer,
NotNull<InternalErrorReporter> iceReporter, NotNull<TypeCheckLimits> limits, NotNull<Scope> scope, const Location& location, TypeId fn,
TypePackId argsPack);

} // namespace Luau
3 changes: 2 additions & 1 deletion Analysis/include/Luau/Subtyping.h
Expand Up @@ -208,7 +208,8 @@ struct Subtyping
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const TableIndexer& subIndexer, const TableIndexer& superIndexer);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const Property& subProperty, const Property& superProperty, const std::string& name);

SubtypingResult isCovariantWith(SubtypingEnvironment& env, const std::shared_ptr<const NormalizedType>& subNorm, const std::shared_ptr<const NormalizedType>& superNorm);
SubtypingResult isCovariantWith(
SubtypingEnvironment& env, const std::shared_ptr<const NormalizedType>& subNorm, const std::shared_ptr<const NormalizedType>& superNorm);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedClassType& subClass, const NormalizedClassType& superClass);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedClassType& subClass, const TypeIds& superTables);
SubtypingResult isCovariantWith(SubtypingEnvironment& env, const NormalizedStringType& subString, const NormalizedStringType& superString);
Expand Down
2 changes: 1 addition & 1 deletion Analysis/include/Luau/TableLiteralInference.h
Expand Up @@ -17,4 +17,4 @@ class AstExpr;
TypeId matchLiteralType(NotNull<DenseHashMap<const AstExpr*, TypeId>> astTypes, NotNull<DenseHashMap<const AstExpr*, TypeId>> astExpectedTypes,
NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, NotNull<Unifier2> unifier, TypeId expectedType, TypeId exprType,
const AstExpr* expr, std::vector<TypeId>& toBlock);
}
} // namespace Luau
21 changes: 21 additions & 0 deletions Analysis/include/Luau/Type.h
Expand Up @@ -552,6 +552,27 @@ struct TypeFamilyInstanceType

std::vector<TypeId> typeArguments;
std::vector<TypePackId> packArguments;

TypeFamilyInstanceType(NotNull<const TypeFamily> family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments)
: family(family)
, typeArguments(typeArguments)
, packArguments(packArguments)
{
}

TypeFamilyInstanceType(const TypeFamily& family, std::vector<TypeId> typeArguments)
: family{&family}
, typeArguments(typeArguments)
, packArguments{}
{
}

TypeFamilyInstanceType(const TypeFamily& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments)
: family{&family}
, typeArguments(typeArguments)
, packArguments(packArguments)
{
}
};

/** Represents a pending type alias instantiation.
Expand Down
5 changes: 5 additions & 0 deletions Analysis/include/Luau/TypeArena.h
Expand Up @@ -48,6 +48,11 @@ struct TypeArena
{
return addTypePack(TypePackVar(std::move(tp)));
}

TypeId addTypeFamily(const TypeFamily& family, std::initializer_list<TypeId> types);
TypeId addTypeFamily(const TypeFamily& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments = {});
TypePackId addTypePackFamily(const TypePackFamily& family, std::initializer_list<TypeId> types);
TypePackId addTypePackFamily(const TypePackFamily& family, std::vector<TypeId> typeArguments, std::vector<TypePackId> packArguments = {});
};

void freeze(TypeArena& arena);
Expand Down
5 changes: 3 additions & 2 deletions Analysis/include/Luau/TypeFamily.h
Expand Up @@ -99,8 +99,8 @@ struct TypeFamilyReductionResult
};

template<typename T>
using ReducerFunction =
std::function<TypeFamilyReductionResult<T>(T, NotNull<TypeFamilyQueue>, const std::vector<TypeId>&, const std::vector<TypePackId>&, NotNull<TypeFamilyContext>)>;
using ReducerFunction = std::function<TypeFamilyReductionResult<T>(
T, NotNull<TypeFamilyQueue>, const std::vector<TypeId>&, const std::vector<TypePackId>&, NotNull<TypeFamilyContext>)>;

/// Represents a type function that may be applied to map a series of types and
/// type packs to a single output type.
Expand Down Expand Up @@ -189,6 +189,7 @@ struct BuiltinTypeFamilies
TypeFamily eqFamily;

TypeFamily refineFamily;
TypeFamily singletonFamily;
TypeFamily unionFamily;
TypeFamily intersectFamily;

Expand Down
2 changes: 1 addition & 1 deletion Analysis/include/Luau/TypePack.h
Expand Up @@ -92,7 +92,7 @@ struct BlockedTypePack
*/
struct TypeFamilyInstanceTypePack
{
NotNull<TypePackFamily> family;
NotNull<const TypePackFamily> family;

std::vector<TypeId> typeArguments;
std::vector<TypePackId> packArguments;
Expand Down
12 changes: 11 additions & 1 deletion Analysis/include/Luau/TypePath.h
Expand Up @@ -79,9 +79,18 @@ enum class PackField
Tail,
};

/// Component that represents the result of a reduction
/// `resultType` is `never` if the reduction could not proceed
struct Reduction
{
TypeId resultType;

bool operator==(const Reduction& other) const;
};

/// A single component of a path, representing one inner type or type pack to
/// traverse into.
using Component = Luau::Variant<Property, Index, TypeField, PackField>;
using Component = Luau::Variant<Property, Index, TypeField, PackField, Reduction>;

/// A path through a type or type pack accessing a particular type or type pack
/// contained within.
Expand Down Expand Up @@ -156,6 +165,7 @@ struct PathHash
size_t operator()(const Index& idx) const;
size_t operator()(const TypeField& field) const;
size_t operator()(const PackField& field) const;
size_t operator()(const Reduction& reduction) const;
size_t operator()(const Component& component) const;
size_t operator()(const Path& path) const;
};
Expand Down
4 changes: 4 additions & 0 deletions Analysis/include/Luau/Unifier2.h
Expand Up @@ -48,8 +48,12 @@ struct Unifier2
int recursionLimit = 0;

std::vector<ConstraintV> incompleteSubtypes;
// null if not in a constraint solving context
DenseHashSet<const void*>* uninhabitedTypeFamilies;

Unifier2(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtinTypes, NotNull<Scope> scope, NotNull<InternalErrorReporter> ice);
Unifier2(NotNull<TypeArena> arena, NotNull<BuiltinTypes> builtinTypes, NotNull<Scope> scope, NotNull<InternalErrorReporter> ice,
DenseHashSet<const void*>* uninhabitedTypeFamilies);

/** Attempt to commit the subtype relation subTy <: superTy to the type
* graph.
Expand Down
3 changes: 1 addition & 2 deletions Analysis/src/BuiltinDefinitions.cpp
Expand Up @@ -24,7 +24,6 @@
*/

LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution);
LUAU_FASTFLAGVARIABLE(LuauSetMetatableOnUnionsOfTables, false);
LUAU_FASTFLAGVARIABLE(LuauMakeStringMethodsChecked, false);

namespace Luau
Expand Down Expand Up @@ -1067,7 +1066,7 @@ static std::optional<WithPredicate<TypePackId>> magicFunctionSetMetaTable(
else if (get<AnyType>(target) || get<ErrorType>(target) || isTableIntersection(target))
{
}
else if (FFlag::LuauSetMetatableOnUnionsOfTables && isTableUnion(target))
else if (isTableUnion(target))
{
const UnionType* ut = get<UnionType>(target);
LUAU_ASSERT(ut);
Expand Down

0 comments on commit 68bd1b2

Please sign in to comment.