Skip to content

Commit

Permalink
Sync to upstream/release/628 (#1278)
Browse files Browse the repository at this point in the history
### What's new?

* Remove a case of unsound `table.move` optimization
* Add Luau stack slot reservations that were missing in REPL (fixes
#1273)

### New Type Solver

* Assignments have been completely reworked to fix a case of cyclic
constraint dependency
* When indexing, if the fresh type's upper bound already contains a
compatible indexer, do not add another upper bound
* Distribute type arguments over all type families sans `eq`, `keyof`,
`rawkeyof`, and other internal type families
* Fix a case where `buffers` component weren't read in two places (fixes
#1267)
* Fix a case where things that constitutes a strong ref were slightly
incorrect
* Fix a case where constraint dependencies weren't setup wrt `for ...
in` statement

### Native Codegen

* Fix an optimization that splits TValue store only when its value and
its tag are compatible
* Implement a system to plug additional type information for custom host
userdata types

---

### Internal Contributors

Co-authored-by: Aaron Weiss <[email protected]>
Co-authored-by: Alexander McCord <[email protected]>
Co-authored-by: Andy Friesen <[email protected]>
Co-authored-by: Vighnesh Vijay <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>

---------

Co-authored-by: Aaron Weiss <[email protected]>
Co-authored-by: Andy Friesen <[email protected]>
Co-authored-by: Vighnesh <[email protected]>
Co-authored-by: Aviral Goel <[email protected]>
Co-authored-by: David Cope <[email protected]>
Co-authored-by: Lily Brown <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>
  • Loading branch information
8 people authored May 31, 2024
1 parent c8fe77c commit daf7932
Show file tree
Hide file tree
Showing 62 changed files with 1,977 additions and 1,204 deletions.
75 changes: 30 additions & 45 deletions Analysis/include/Luau/Constraint.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,23 +179,6 @@ struct HasPropConstraint
bool suppressSimplification = false;
};

// result ~ setProp subjectType ["prop", "prop2", ...] propType
//
// If the subject is a table or table-like thing that already has the named
// property chain, we unify propType with that existing property type.
//
// If the subject is a free table, we augment it in place.
//
// If the subject is an unsealed table, result is an augmented table that
// includes that new prop.
struct SetPropConstraint
{
TypeId resultType;
TypeId subjectType;
std::vector<std::string> path;
TypeId propType;
};

// resultType ~ hasIndexer subjectType indexType
//
// If the subject type is a table or table-like thing that supports indexing,
Expand All @@ -209,16 +192,37 @@ struct HasIndexerConstraint
TypeId indexType;
};

// result ~ setIndexer subjectType indexType propType
//
// If the subject is a table or table-like thing that already has an indexer,
// unify its indexType and propType with those from this constraint.
struct AssignConstraint
{
TypeId lhsType;
TypeId rhsType;
};

// assign lhsType propName rhsType
//
// If the table is a free or unsealed table, we augment it with a new indexer.
struct SetIndexerConstraint
// Assign a value of type rhsType into the named property of lhsType.

struct AssignPropConstraint
{
TypeId subjectType;
TypeId lhsType;
std::string propName;
TypeId rhsType;

/// The canonical write type of the property. It is _solely_ used to
/// populate astTypes during constraint resolution. Nothing should ever
/// block on it.
TypeId propType;
};

struct AssignIndexConstraint
{
TypeId lhsType;
TypeId indexType;
TypeId rhsType;

/// The canonical write type of the property. It is _solely_ used to
/// populate astTypes during constraint resolution. Nothing should ever
/// block on it.
TypeId propType;
};

Expand All @@ -230,25 +234,6 @@ struct UnpackConstraint
{
TypePackId resultPack;
TypePackId sourcePack;

// UnpackConstraint is sometimes used to resolve the types of assignments.
// When this is the case, any LocalTypes in resultPack can have their
// domains extended by the corresponding type from sourcePack.
bool resultIsLValue = false;
};

// resultType ~ unpack sourceType
//
// The same as UnpackConstraint, but specialized for a pair of types as opposed to packs.
struct Unpack1Constraint
{
TypeId resultType;
TypeId sourceType;

// UnpackConstraint is sometimes used to resolve the types of assignments.
// When this is the case, any LocalTypes in resultPack can have their
// domains extended by the corresponding type from sourcePack.
bool resultIsLValue = false;
};

// ty ~ reduce ty
Expand All @@ -268,8 +253,8 @@ struct ReducePackConstraint
};

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

struct Constraint
{
Expand Down
17 changes: 5 additions & 12 deletions Analysis/include/Luau/ConstraintGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,18 +254,11 @@ struct ConstraintGenerator
Inference check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType);
std::tuple<TypeId, TypeId, RefinementId> checkBinary(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType);

struct LValueBounds
{
std::optional<TypeId> annotationTy;
std::optional<TypeId> assignedTy;
};

LValueBounds checkLValue(const ScopePtr& scope, AstExpr* expr);
LValueBounds checkLValue(const ScopePtr& scope, AstExprLocal* local);
LValueBounds checkLValue(const ScopePtr& scope, AstExprGlobal* global);
LValueBounds checkLValue(const ScopePtr& scope, AstExprIndexName* indexName);
LValueBounds checkLValue(const ScopePtr& scope, AstExprIndexExpr* indexExpr);
LValueBounds updateProperty(const ScopePtr& scope, AstExpr* expr);
void visitLValue(const ScopePtr& scope, AstExpr* expr, TypeId rhsType);
void visitLValue(const ScopePtr& scope, AstExprLocal* local, TypeId rhsType);
void visitLValue(const ScopePtr& scope, AstExprGlobal* global, TypeId rhsType);
void visitLValue(const ScopePtr& scope, AstExprIndexName* indexName, TypeId rhsType);
void visitLValue(const ScopePtr& scope, AstExprIndexExpr* indexExpr, TypeId rhsType);

struct FunctionSignature
{
Expand Down
20 changes: 16 additions & 4 deletions Analysis/include/Luau/ConstraintSolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,19 +134,20 @@ struct ConstraintSolver
bool tryDispatch(const FunctionCheckConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const PrimitiveTypeConstraint& c, NotNull<const Constraint> constraint);
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 tryDispatch(const HasIndexerConstraint& c, NotNull<const Constraint> constraint);

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 tryDispatchUnpack1(NotNull<const Constraint> constraint, TypeId resultType, TypeId sourceType, bool resultIsLValue);
bool tryDispatch(const AssignConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const AssignPropConstraint& c, NotNull<const Constraint> constraint);
bool tryDispatch(const AssignIndexConstraint& c, NotNull<const Constraint> constraint);

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

bool tryDispatch(const ReduceConstraint& c, NotNull<const Constraint> constraint, bool force);
bool tryDispatch(const ReducePackConstraint& c, NotNull<const Constraint> constraint, bool force);
Expand All @@ -165,6 +166,17 @@ struct ConstraintSolver
std::pair<std::vector<TypeId>, std::optional<TypeId>> lookupTableProp(NotNull<const Constraint> constraint, TypeId subjectType,
const std::string& propName, ValueContext context, bool inConditional, bool suppressSimplification, DenseHashSet<TypeId>& seen);

/**
* Generate constraints to unpack the types of srcTypes and assign each
* value to the corresponding LocalType in destTypes.
*
* @param destTypes A finite TypePack comprised of LocalTypes.
* @param srcTypes A TypePack that represents rvalues to be assigned.
* @returns The underlying UnpackConstraint. There's a bit of code in
* iteration that needs to pass blocks on to this constraint.
*/
NotNull<const Constraint> unpackAndAssign(TypePackId destTypes, TypePackId srcTypes, NotNull<const Constraint> constraint);

void block(NotNull<const Constraint> target, NotNull<const Constraint> constraint);
/**
* Block a constraint on the resolution of a Type.
Expand Down
3 changes: 3 additions & 0 deletions Analysis/include/Luau/Simplify.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "Luau/DenseHash.h"
#include "Luau/NotNull.h"
#include "Luau/TypeFwd.h"
#include <set>

namespace Luau
{
Expand All @@ -19,6 +20,8 @@ struct SimplifyResult
};

SimplifyResult simplifyIntersection(NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, TypeId ty, TypeId discriminant);
SimplifyResult simplifyIntersection(NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, std::set<TypeId> parts);

SimplifyResult simplifyUnion(NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, TypeId ty, TypeId discriminant);

enum class Relation
Expand Down
21 changes: 2 additions & 19 deletions Analysis/include/Luau/TypeFamily.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include "Luau/NotNull.h"
#include "Luau/TypeCheckLimits.h"
#include "Luau/TypeFwd.h"
#include "Luau/Variant.h"

#include <functional>
#include <string>
Expand All @@ -19,22 +18,6 @@ struct TypeArena;
struct TxnLog;
class Normalizer;

struct TypeFamilyQueue
{
NotNull<VecDeque<TypeId>> queuedTys;
NotNull<VecDeque<TypePackId>> queuedTps;

void add(TypeId instanceTy);
void add(TypePackId instanceTp);

template<typename T>
void add(const std::vector<T>& ts)
{
for (const T& t : ts)
enqueue(t);
}
};

struct TypeFamilyContext
{
NotNull<TypeArena> arena;
Expand Down Expand Up @@ -99,8 +82,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, 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
3 changes: 3 additions & 0 deletions Analysis/include/Luau/TypeUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ struct InConditionalContext

using ScopePtr = std::shared_ptr<struct Scope>;

std::optional<Property> findTableProperty(
NotNull<BuiltinTypes> builtinTypes, ErrorVec& errors, TypeId ty, const std::string& name, Location location);

std::optional<TypeId> findMetatableEntry(
NotNull<BuiltinTypes> builtinTypes, ErrorVec& errors, TypeId type, const std::string& entry, Location location);
std::optional<TypeId> findTablePropertyRespectingMeta(
Expand Down
40 changes: 18 additions & 22 deletions Analysis/src/Constraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ bool isReferenceCountedType(const TypeId typ)

DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
{
// For the purpose of this function and reference counting in general, we are only considering
// mutations that affect the _bounds_ of the free type, and not something that may bind the free
// type itself to a new type. As such, `ReduceConstraint` and `GeneralizationConstraint` have no
// contribution to the output set here.

DenseHashSet<TypeId> types{{}};
ReferenceCountInitializer rci{&types};

Expand All @@ -74,11 +79,6 @@ DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
rci.traverse(psc->subPack);
rci.traverse(psc->superPack);
}
else if (auto gc = get<GeneralizationConstraint>(*this))
{
rci.traverse(gc->generalizedType);
// `GeneralizationConstraints` should not mutate `sourceType` or `interiorTypes`.
}
else if (auto itc = get<IterableConstraint>(*this))
{
rci.traverse(itc->variables);
Expand All @@ -101,35 +101,31 @@ DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
rci.traverse(hpc->resultType);
// `HasPropConstraints` should not mutate `subjectType`.
}
else if (auto spc = get<SetPropConstraint>(*this))
{
rci.traverse(spc->resultType);
// `SetPropConstraints` should not mutate `subjectType` or `propType`.
// TODO: is this true? it "unifies" with `propType`, so maybe mutates that one too?
}
else if (auto hic = get<HasIndexerConstraint>(*this))
{
rci.traverse(hic->resultType);
// `HasIndexerConstraint` should not mutate `subjectType` or `indexType`.
}
else if (auto sic = get<SetIndexerConstraint>(*this))
else if (auto ac = get<AssignConstraint>(*this))
{
rci.traverse(sic->propType);
// `SetIndexerConstraints` should not mutate `subjectType` or `indexType`.
rci.traverse(ac->lhsType);
rci.traverse(ac->rhsType);
}
else if (auto uc = get<UnpackConstraint>(*this))
else if (auto apc = get<AssignPropConstraint>(*this))
{
rci.traverse(uc->resultPack);
// `UnpackConstraint` should not mutate `sourcePack`.
rci.traverse(apc->lhsType);
rci.traverse(apc->rhsType);
}
else if (auto u1c = get<Unpack1Constraint>(*this))
else if (auto aic = get<AssignIndexConstraint>(*this))
{
rci.traverse(u1c->resultType);
// `Unpack1Constraint` should not mutate `sourceType`.
rci.traverse(aic->lhsType);
rci.traverse(aic->indexType);
rci.traverse(aic->rhsType);
}
else if (auto rc = get<ReduceConstraint>(*this))
else if (auto uc = get<UnpackConstraint>(*this))
{
rci.traverse(rc->ty);
rci.traverse(uc->resultPack);
// `UnpackConstraint` should not mutate `sourcePack`.
}
else if (auto rpc = get<ReducePackConstraint>(*this))
{
Expand Down
Loading

0 comments on commit daf7932

Please sign in to comment.