Skip to content

Commit daf7932

Browse files
alexmccordaatxeandyfriesenVighnesh-VAviral Goel
authored
Sync to upstream/release/628 (#1278)
### 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 <aaronweiss@roblox.com> Co-authored-by: Alexander McCord <amccord@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Aaron Weiss <aaronweiss@roblox.com> Co-authored-by: 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>
1 parent c8fe77c commit daf7932

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1977
-1204
lines changed

Analysis/include/Luau/Constraint.h

Lines changed: 30 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -179,23 +179,6 @@ struct HasPropConstraint
179179
bool suppressSimplification = false;
180180
};
181181

182-
// result ~ setProp subjectType ["prop", "prop2", ...] propType
183-
//
184-
// If the subject is a table or table-like thing that already has the named
185-
// property chain, we unify propType with that existing property type.
186-
//
187-
// If the subject is a free table, we augment it in place.
188-
//
189-
// If the subject is an unsealed table, result is an augmented table that
190-
// includes that new prop.
191-
struct SetPropConstraint
192-
{
193-
TypeId resultType;
194-
TypeId subjectType;
195-
std::vector<std::string> path;
196-
TypeId propType;
197-
};
198-
199182
// resultType ~ hasIndexer subjectType indexType
200183
//
201184
// If the subject type is a table or table-like thing that supports indexing,
@@ -209,16 +192,37 @@ struct HasIndexerConstraint
209192
TypeId indexType;
210193
};
211194

212-
// result ~ setIndexer subjectType indexType propType
213-
//
214-
// If the subject is a table or table-like thing that already has an indexer,
215-
// unify its indexType and propType with those from this constraint.
195+
struct AssignConstraint
196+
{
197+
TypeId lhsType;
198+
TypeId rhsType;
199+
};
200+
201+
// assign lhsType propName rhsType
216202
//
217-
// If the table is a free or unsealed table, we augment it with a new indexer.
218-
struct SetIndexerConstraint
203+
// Assign a value of type rhsType into the named property of lhsType.
204+
205+
struct AssignPropConstraint
219206
{
220-
TypeId subjectType;
207+
TypeId lhsType;
208+
std::string propName;
209+
TypeId rhsType;
210+
211+
/// The canonical write type of the property. It is _solely_ used to
212+
/// populate astTypes during constraint resolution. Nothing should ever
213+
/// block on it.
214+
TypeId propType;
215+
};
216+
217+
struct AssignIndexConstraint
218+
{
219+
TypeId lhsType;
221220
TypeId indexType;
221+
TypeId rhsType;
222+
223+
/// The canonical write type of the property. It is _solely_ used to
224+
/// populate astTypes during constraint resolution. Nothing should ever
225+
/// block on it.
222226
TypeId propType;
223227
};
224228

@@ -230,25 +234,6 @@ struct UnpackConstraint
230234
{
231235
TypePackId resultPack;
232236
TypePackId sourcePack;
233-
234-
// UnpackConstraint is sometimes used to resolve the types of assignments.
235-
// When this is the case, any LocalTypes in resultPack can have their
236-
// domains extended by the corresponding type from sourcePack.
237-
bool resultIsLValue = false;
238-
};
239-
240-
// resultType ~ unpack sourceType
241-
//
242-
// The same as UnpackConstraint, but specialized for a pair of types as opposed to packs.
243-
struct Unpack1Constraint
244-
{
245-
TypeId resultType;
246-
TypeId sourceType;
247-
248-
// UnpackConstraint is sometimes used to resolve the types of assignments.
249-
// When this is the case, any LocalTypes in resultPack can have their
250-
// domains extended by the corresponding type from sourcePack.
251-
bool resultIsLValue = false;
252237
};
253238

254239
// ty ~ reduce ty
@@ -268,8 +253,8 @@ struct ReducePackConstraint
268253
};
269254

270255
using ConstraintV = Variant<SubtypeConstraint, PackSubtypeConstraint, GeneralizationConstraint, IterableConstraint, NameConstraint,
271-
TypeAliasExpansionConstraint, FunctionCallConstraint, FunctionCheckConstraint, PrimitiveTypeConstraint, HasPropConstraint, SetPropConstraint,
272-
HasIndexerConstraint, SetIndexerConstraint, UnpackConstraint, Unpack1Constraint, ReduceConstraint, ReducePackConstraint, EqualityConstraint>;
256+
TypeAliasExpansionConstraint, FunctionCallConstraint, FunctionCheckConstraint, PrimitiveTypeConstraint, HasPropConstraint, HasIndexerConstraint,
257+
AssignConstraint, AssignPropConstraint, AssignIndexConstraint, UnpackConstraint, ReduceConstraint, ReducePackConstraint, EqualityConstraint>;
273258

274259
struct Constraint
275260
{

Analysis/include/Luau/ConstraintGenerator.h

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -254,18 +254,11 @@ struct ConstraintGenerator
254254
Inference check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType);
255255
std::tuple<TypeId, TypeId, RefinementId> checkBinary(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType);
256256

257-
struct LValueBounds
258-
{
259-
std::optional<TypeId> annotationTy;
260-
std::optional<TypeId> assignedTy;
261-
};
262-
263-
LValueBounds checkLValue(const ScopePtr& scope, AstExpr* expr);
264-
LValueBounds checkLValue(const ScopePtr& scope, AstExprLocal* local);
265-
LValueBounds checkLValue(const ScopePtr& scope, AstExprGlobal* global);
266-
LValueBounds checkLValue(const ScopePtr& scope, AstExprIndexName* indexName);
267-
LValueBounds checkLValue(const ScopePtr& scope, AstExprIndexExpr* indexExpr);
268-
LValueBounds updateProperty(const ScopePtr& scope, AstExpr* expr);
257+
void visitLValue(const ScopePtr& scope, AstExpr* expr, TypeId rhsType);
258+
void visitLValue(const ScopePtr& scope, AstExprLocal* local, TypeId rhsType);
259+
void visitLValue(const ScopePtr& scope, AstExprGlobal* global, TypeId rhsType);
260+
void visitLValue(const ScopePtr& scope, AstExprIndexName* indexName, TypeId rhsType);
261+
void visitLValue(const ScopePtr& scope, AstExprIndexExpr* indexExpr, TypeId rhsType);
269262

270263
struct FunctionSignature
271264
{

Analysis/include/Luau/ConstraintSolver.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,20 @@ struct ConstraintSolver
134134
bool tryDispatch(const FunctionCheckConstraint& c, NotNull<const Constraint> constraint);
135135
bool tryDispatch(const PrimitiveTypeConstraint& c, NotNull<const Constraint> constraint);
136136
bool tryDispatch(const HasPropConstraint& c, NotNull<const Constraint> constraint);
137-
bool tryDispatch(const SetPropConstraint& c, NotNull<const Constraint> constraint);
138137

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

143142
std::pair<bool, std::optional<TypeId>> tryDispatchSetIndexer(
144143
NotNull<const Constraint> constraint, TypeId subjectType, TypeId indexType, TypeId propType, bool expandFreeTypeBounds);
145-
bool tryDispatch(const SetIndexerConstraint& c, NotNull<const Constraint> constraint, bool force);
146144

147-
bool tryDispatchUnpack1(NotNull<const Constraint> constraint, TypeId resultType, TypeId sourceType, bool resultIsLValue);
145+
bool tryDispatch(const AssignConstraint& c, NotNull<const Constraint> constraint);
146+
bool tryDispatch(const AssignPropConstraint& c, NotNull<const Constraint> constraint);
147+
bool tryDispatch(const AssignIndexConstraint& c, NotNull<const Constraint> constraint);
148+
149+
bool tryDispatchUnpack1(NotNull<const Constraint> constraint, TypeId resultType, TypeId sourceType);
148150
bool tryDispatch(const UnpackConstraint& c, NotNull<const Constraint> constraint);
149-
bool tryDispatch(const Unpack1Constraint& c, NotNull<const Constraint> constraint);
150151

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

169+
/**
170+
* Generate constraints to unpack the types of srcTypes and assign each
171+
* value to the corresponding LocalType in destTypes.
172+
*
173+
* @param destTypes A finite TypePack comprised of LocalTypes.
174+
* @param srcTypes A TypePack that represents rvalues to be assigned.
175+
* @returns The underlying UnpackConstraint. There's a bit of code in
176+
* iteration that needs to pass blocks on to this constraint.
177+
*/
178+
NotNull<const Constraint> unpackAndAssign(TypePackId destTypes, TypePackId srcTypes, NotNull<const Constraint> constraint);
179+
168180
void block(NotNull<const Constraint> target, NotNull<const Constraint> constraint);
169181
/**
170182
* Block a constraint on the resolution of a Type.

Analysis/include/Luau/Simplify.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "Luau/DenseHash.h"
66
#include "Luau/NotNull.h"
77
#include "Luau/TypeFwd.h"
8+
#include <set>
89

910
namespace Luau
1011
{
@@ -19,6 +20,8 @@ struct SimplifyResult
1920
};
2021

2122
SimplifyResult simplifyIntersection(NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, TypeId ty, TypeId discriminant);
23+
SimplifyResult simplifyIntersection(NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, std::set<TypeId> parts);
24+
2225
SimplifyResult simplifyUnion(NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, TypeId ty, TypeId discriminant);
2326

2427
enum class Relation

Analysis/include/Luau/TypeFamily.h

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
#include "Luau/NotNull.h"
77
#include "Luau/TypeCheckLimits.h"
88
#include "Luau/TypeFwd.h"
9-
#include "Luau/Variant.h"
109

1110
#include <functional>
1211
#include <string>
@@ -19,22 +18,6 @@ struct TypeArena;
1918
struct TxnLog;
2019
class Normalizer;
2120

22-
struct TypeFamilyQueue
23-
{
24-
NotNull<VecDeque<TypeId>> queuedTys;
25-
NotNull<VecDeque<TypePackId>> queuedTps;
26-
27-
void add(TypeId instanceTy);
28-
void add(TypePackId instanceTp);
29-
30-
template<typename T>
31-
void add(const std::vector<T>& ts)
32-
{
33-
for (const T& t : ts)
34-
enqueue(t);
35-
}
36-
};
37-
3821
struct TypeFamilyContext
3922
{
4023
NotNull<TypeArena> arena;
@@ -99,8 +82,8 @@ struct TypeFamilyReductionResult
9982
};
10083

10184
template<typename T>
102-
using ReducerFunction = std::function<TypeFamilyReductionResult<T>(
103-
T, NotNull<TypeFamilyQueue>, const std::vector<TypeId>&, const std::vector<TypePackId>&, NotNull<TypeFamilyContext>)>;
85+
using ReducerFunction = std::function<TypeFamilyReductionResult<T>(T, const std::vector<TypeId>&, const std::vector<TypePackId>&,
86+
NotNull<TypeFamilyContext>)>;
10487

10588
/// Represents a type function that may be applied to map a series of types and
10689
/// type packs to a single output type.

Analysis/include/Luau/TypeUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ struct InConditionalContext
5555

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

58+
std::optional<Property> findTableProperty(
59+
NotNull<BuiltinTypes> builtinTypes, ErrorVec& errors, TypeId ty, const std::string& name, Location location);
60+
5861
std::optional<TypeId> findMetatableEntry(
5962
NotNull<BuiltinTypes> builtinTypes, ErrorVec& errors, TypeId type, const std::string& entry, Location location);
6063
std::optional<TypeId> findTablePropertyRespectingMeta(

Analysis/src/Constraint.cpp

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ bool isReferenceCountedType(const TypeId typ)
5656

5757
DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
5858
{
59+
// For the purpose of this function and reference counting in general, we are only considering
60+
// mutations that affect the _bounds_ of the free type, and not something that may bind the free
61+
// type itself to a new type. As such, `ReduceConstraint` and `GeneralizationConstraint` have no
62+
// contribution to the output set here.
63+
5964
DenseHashSet<TypeId> types{{}};
6065
ReferenceCountInitializer rci{&types};
6166

@@ -74,11 +79,6 @@ DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
7479
rci.traverse(psc->subPack);
7580
rci.traverse(psc->superPack);
7681
}
77-
else if (auto gc = get<GeneralizationConstraint>(*this))
78-
{
79-
rci.traverse(gc->generalizedType);
80-
// `GeneralizationConstraints` should not mutate `sourceType` or `interiorTypes`.
81-
}
8282
else if (auto itc = get<IterableConstraint>(*this))
8383
{
8484
rci.traverse(itc->variables);
@@ -101,35 +101,31 @@ DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
101101
rci.traverse(hpc->resultType);
102102
// `HasPropConstraints` should not mutate `subjectType`.
103103
}
104-
else if (auto spc = get<SetPropConstraint>(*this))
105-
{
106-
rci.traverse(spc->resultType);
107-
// `SetPropConstraints` should not mutate `subjectType` or `propType`.
108-
// TODO: is this true? it "unifies" with `propType`, so maybe mutates that one too?
109-
}
110104
else if (auto hic = get<HasIndexerConstraint>(*this))
111105
{
112106
rci.traverse(hic->resultType);
113107
// `HasIndexerConstraint` should not mutate `subjectType` or `indexType`.
114108
}
115-
else if (auto sic = get<SetIndexerConstraint>(*this))
109+
else if (auto ac = get<AssignConstraint>(*this))
116110
{
117-
rci.traverse(sic->propType);
118-
// `SetIndexerConstraints` should not mutate `subjectType` or `indexType`.
111+
rci.traverse(ac->lhsType);
112+
rci.traverse(ac->rhsType);
119113
}
120-
else if (auto uc = get<UnpackConstraint>(*this))
114+
else if (auto apc = get<AssignPropConstraint>(*this))
121115
{
122-
rci.traverse(uc->resultPack);
123-
// `UnpackConstraint` should not mutate `sourcePack`.
116+
rci.traverse(apc->lhsType);
117+
rci.traverse(apc->rhsType);
124118
}
125-
else if (auto u1c = get<Unpack1Constraint>(*this))
119+
else if (auto aic = get<AssignIndexConstraint>(*this))
126120
{
127-
rci.traverse(u1c->resultType);
128-
// `Unpack1Constraint` should not mutate `sourceType`.
121+
rci.traverse(aic->lhsType);
122+
rci.traverse(aic->indexType);
123+
rci.traverse(aic->rhsType);
129124
}
130-
else if (auto rc = get<ReduceConstraint>(*this))
125+
else if (auto uc = get<UnpackConstraint>(*this))
131126
{
132-
rci.traverse(rc->ty);
127+
rci.traverse(uc->resultPack);
128+
// `UnpackConstraint` should not mutate `sourcePack`.
133129
}
134130
else if (auto rpc = get<ReducePackConstraint>(*this))
135131
{

0 commit comments

Comments
 (0)