Skip to content

Commit 92cce57

Browse files
hgoldsteinandyfriesenaatxeJamesMcNellisskanosue
authored
Sync to upstream/release/674 (#1832)
# General * Expose an optional `get_alias` API as an alternative to `get_config` in Luau.Require and Luau.RequireNavigator. * Improve the Luau CLI's virtual filesystem implementation to fix bugs related to `init.luau`. Fixes #1816 # New Type Solver * Avoid double reporting errors when erroneous arguments are provided to type functions. * Fix some instances of unresovable cyclic type functions in loops by only considering the first loop cycles. This results in some type inference inaccuracies when the type of a variable in loop through multiple iterations. Fixes #1413. * Better generalize free types that have meaningful lower and upper bounds, especially for table indexers. * Report more specific errors when assigning or returning table literal types, instead of citing the *entire* table type. * Inference for functions with generic type packs is greatly improved. * Fix some internal compiler exceptions when using type-stating functions like `table.freeze` in `if _ then _ else _` expressions and short circuiting binary operations. * More consistently simplify unions of primitive types, especially in array-like and dictionary-like tables. * Fix a crash when type checking an erroneous type alias containing `typeof` with a type assertion expression, as in: ``` type MyTable = {} -- This will error at type checking time as it's a duplicate type MyTable = typeof(setmetatable(SomeTable :: {}, SomeMetaTable)); ``` * Fix a crash when inferring the type of an index expression where the indexee is invalid (e.g. `nil`). # Runtime * Avoid throwing an exception from `luau_load` if we run out of memory. * Type functions are no longer compiled and included in bytecode. Fixes #1817. * Fix some instances of Luau C API functions reading invalid debug information (generally when the first or last instruction of a block was being inspected). Fixes #1369. * Avoid potential signed integer overflow when doing bounds checks on tables. * Support 16 byte aligned userdata objects when system allocation alignment is also 16 bytes. * Fix memory leaks in `Luau.Require` when using VM build with no exceptions. Fixes #1827. --------- Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Ariel Weiss <aaronweiss@roblox.com> Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com> Co-authored-by: James McNellis <jmcnellis@roblox.com> Co-authored-by: Sora Kanosue <skanosue@roblox.com> Co-authored-by: Talha Pathan <tpathan@roblox.com> Co-authored-by: Varun Saini <vsaini@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
1 parent 3eb0c13 commit 92cce57

File tree

129 files changed

+4711
-4679
lines changed

Some content is hidden

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

129 files changed

+4711
-4679
lines changed

Analysis/include/Luau/BuiltinDefinitions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
namespace Luau
1010
{
1111

12-
static constexpr char kRequireTagName[] = "require";
12+
inline constexpr char kRequireTagName[] = "require";
1313

1414
struct Frontend;
1515
struct GlobalTypes;

Analysis/include/Luau/Constraint.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,12 @@ struct ReducePackConstraint
276276
TypePackId tp;
277277
};
278278

279+
// simplify ty
280+
struct SimplifyConstraint
281+
{
282+
TypeId ty;
283+
};
284+
279285
using ConstraintV = Variant<
280286
SubtypeConstraint,
281287
PackSubtypeConstraint,
@@ -294,7 +300,8 @@ using ConstraintV = Variant<
294300
ReduceConstraint,
295301
ReducePackConstraint,
296302
EqualityConstraint,
297-
TableCheckConstraint>;
303+
TableCheckConstraint,
304+
SimplifyConstraint>;
298305

299306
struct Constraint
300307
{

Analysis/include/Luau/ConstraintGenerator.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ struct ConstraintGenerator
173173
std::vector<std::vector<TypeId>> DEPRECATED_interiorTypes;
174174
std::vector<InteriorFreeTypes> interiorFreeTypes;
175175

176+
std::vector<TypeId> unionsToSimplify;
177+
176178
/**
177179
* Fabricates a new free type belonging to a given scope.
178180
* @param scope the scope the free type belongs to.
@@ -447,6 +449,12 @@ struct ConstraintGenerator
447449

448450
// make a union type function of these two types
449451
TypeId makeUnion(const ScopePtr& scope, Location location, TypeId lhs, TypeId rhs);
452+
453+
// Make a union type and add it to `unionsToSimplify`, ensuring that
454+
// later we will attempt to simplify this union in order to keep types
455+
// small.
456+
TypeId makeUnion(std::vector<TypeId> options);
457+
450458
// make an intersect type function of these two types
451459
TypeId makeIntersect(const ScopePtr& scope, Location location, TypeId lhs, TypeId rhs);
452460
void prepopulateGlobalScopeForFragmentTypecheck(const ScopePtr& globalScope, const ScopePtr& resumeScope, AstStatBlock* program);

Analysis/include/Luau/ConstraintSolver.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,8 @@ struct ConstraintSolver
249249
bool tryDispatch(const ReducePackConstraint& c, NotNull<const Constraint> constraint, bool force);
250250
bool tryDispatch(const EqualityConstraint& c, NotNull<const Constraint> constraint);
251251

252+
bool tryDispatch(const SimplifyConstraint& c, NotNull<const Constraint> constraint);
253+
252254
// for a, ... in some_table do
253255
// also handles __iter metamethod
254256
bool tryDispatchIterableTable(TypeId iteratorTy, const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);

Analysis/include/Luau/Error.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,11 @@ struct ReservedIdentifier
462462
bool operator==(const ReservedIdentifier& rhs) const;
463463
};
464464

465+
struct UnexpectedArrayLikeTableItem
466+
{
467+
bool operator==(const UnexpectedArrayLikeTableItem&) const { return true; }
468+
};
469+
465470
using TypeErrorData = Variant<
466471
TypeMismatch,
467472
UnknownSymbol,
@@ -512,7 +517,8 @@ using TypeErrorData = Variant<
512517
UnexpectedTypePackInSubtyping,
513518
ExplicitFunctionAnnotationRecommended,
514519
UserDefinedTypeFunctionError,
515-
ReservedIdentifier>;
520+
ReservedIdentifier,
521+
UnexpectedArrayLikeTableItem>;
516522

517523
struct TypeErrorSummary
518524
{

Analysis/include/Luau/Metamethods.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
namespace Luau
99
{
1010

11-
static const std::unordered_map<AstExprBinary::Op, const char*> kBinaryOpMetamethods{
11+
inline const std::unordered_map<AstExprBinary::Op, const char*> kBinaryOpMetamethods{
1212
{AstExprBinary::Op::CompareEq, "__eq"},
1313
{AstExprBinary::Op::CompareNe, "__eq"},
1414
{AstExprBinary::Op::CompareGe, "__lt"},
@@ -25,7 +25,7 @@ static const std::unordered_map<AstExprBinary::Op, const char*> kBinaryOpMetamet
2525
{AstExprBinary::Op::Concat, "__concat"},
2626
};
2727

28-
static const std::unordered_map<AstExprUnary::Op, const char*> kUnaryOpMetamethods{
28+
inline const std::unordered_map<AstExprUnary::Op, const char*> kUnaryOpMetamethods{
2929
{AstExprUnary::Op::Minus, "__unm"},
3030
{AstExprUnary::Op::Len, "__len"},
3131
};

Analysis/include/Luau/Subtyping.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ struct SubtypingReasoningHash
6060
};
6161

6262
using SubtypingReasonings = DenseHashSet<SubtypingReasoning, SubtypingReasoningHash>;
63-
static const SubtypingReasoning kEmptyReasoning = SubtypingReasoning{TypePath::kEmpty, TypePath::kEmpty, SubtypingVariance::Invalid};
63+
inline const SubtypingReasoning kEmptyReasoning = SubtypingReasoning{TypePath::kEmpty, TypePath::kEmpty, SubtypingVariance::Invalid};
6464

6565
struct SubtypingResult
6666
{

Analysis/include/Luau/Type.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,7 @@ std::vector<TypeId> filterMap(TypeId type, TypeIdPredicate predicate);
12061206

12071207
// A tag to mark a type which doesn't derive directly from the root type as overriding the return of `typeof`.
12081208
// Any classes which derive from this type will have typeof return this type.
1209-
static constexpr char kTypeofRootTag[] = "typeofRoot";
1209+
inline constexpr char kTypeofRootTag[] = "typeofRoot";
12101210

12111211
void attachTag(TypeId ty, const std::string& tagName);
12121212
void attachTag(Property& prop, const std::string& tagName);

Analysis/include/Luau/TypeChecker2.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ struct TypeChecker2
193193

194194
void explainError(TypeId subTy, TypeId superTy, Location location, const SubtypingResult& result);
195195
void explainError(TypePackId subTy, TypePackId superTy, Location location, const SubtypingResult& result);
196+
197+
bool testPotentialLiteralIsSubtype(AstExpr* expr, TypeId expectedTy);
198+
196199
bool testIsSubtype(TypeId subTy, TypeId superTy, Location location);
197200
bool testIsSubtype(TypePackId subTy, TypePackId superTy, Location location);
198201
void reportError(TypeError e);

Analysis/include/Luau/TypeFunctionRuntime.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,6 @@ struct TypeFunctionExternType
216216

217217
std::optional<TypeFunctionTypeId> metatable; // metaclass?
218218

219-
// this was mistaken, and we should actually be keeping separate read/write types here.
220-
std::optional<TypeFunctionTypeId> parent_DEPRECATED;
221-
222219
std::optional<TypeFunctionTypeId> readParent;
223220
std::optional<TypeFunctionTypeId> writeParent;
224221

Analysis/include/Luau/TypePath.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ struct PathHash
183183
};
184184

185185
/// The canonical "empty" Path, meaning a Path with no components.
186-
static const Path kEmpty{};
186+
inline const Path kEmpty{};
187187

188188
struct PathBuilder
189189
{

Analysis/include/Luau/TypeUtils.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,4 +291,14 @@ void trackInteriorFreeType(Scope* scope, TypeId ty);
291291

292292
void trackInteriorFreeTypePack(Scope* scope, TypePackId tp);
293293

294+
// A fast approximation of subTy <: superTy
295+
bool fastIsSubtype(TypeId subTy, TypeId superTy);
296+
297+
/**
298+
* @param tables A list of potential table parts of a union
299+
* @param exprType Type of the expression to match
300+
* @return An element of `tables` that best matches `exprType`.
301+
*/
302+
std::optional<TypeId> extractMatchingTableType(std::vector<TypeId>& tables, TypeId exprType, NotNull<BuiltinTypes> builtinTypes);
303+
294304
} // namespace Luau

Analysis/src/AutocompleteCore.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ LUAU_FASTINT(LuauTypeInferIterationLimit)
2525
LUAU_FASTINT(LuauTypeInferRecursionLimit)
2626
LUAU_FASTFLAGVARIABLE(DebugLuauMagicVariableNames)
2727
LUAU_FASTFLAGVARIABLE(LuauAutocompleteUsesModuleForTypeCompatibility)
28-
LUAU_FASTFLAGVARIABLE(LuauAutocompleteUnionCopyPreviousSeen)
2928
LUAU_FASTFLAGVARIABLE(LuauAutocompleteMissingFollows)
3029
LUAU_FASTFLAG(LuauStoreReturnTypesAsPackOnAst)
3130

@@ -490,13 +489,10 @@ static void autocompleteProps(
490489
// t1 where t1 = t1 | ExternType
491490
//
492491
// Then we are on a one way journey to a stack overflow.
493-
if (FFlag::LuauAutocompleteUnionCopyPreviousSeen)
492+
for (auto ty : seen)
494493
{
495-
for (auto ty : seen)
496-
{
497-
if (is<UnionType, IntersectionType>(ty))
498-
innerSeen.insert(ty);
499-
}
494+
if (is<UnionType, IntersectionType>(ty))
495+
innerSeen.insert(ty);
500496
}
501497

502498
if (isNil(*iter))

Analysis/src/BuiltinDefinitions.cpp

Lines changed: 49 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,8 @@
3030
*/
3131

3232
LUAU_FASTFLAG(LuauSolverV2)
33-
LUAU_FASTFLAG(LuauNonReentrantGeneralization2)
33+
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
3434
LUAU_FASTFLAGVARIABLE(LuauTableCloneClonesType3)
35-
LUAU_FASTFLAGVARIABLE(LuauUserTypeFunTypecheck)
3635
LUAU_FASTFLAGVARIABLE(LuauMagicFreezeCheckBlocked2)
3736
LUAU_FASTFLAGVARIABLE(LuauFormatUseLastPosition)
3837

@@ -292,8 +291,6 @@ void assignPropDocumentationSymbols(TableType::Props& props, const std::string&
292291

293292
static void finalizeGlobalBindings(ScopePtr scope)
294293
{
295-
LUAU_ASSERT(FFlag::LuauUserTypeFunTypecheck);
296-
297294
for (const auto& pair : scope->bindings)
298295
{
299296
persist(pair.second.typeId);
@@ -313,8 +310,8 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
313310

314311
TypeArena& arena = globals.globalTypes;
315312
NotNull<BuiltinTypes> builtinTypes = globals.builtinTypes;
316-
Scope* globalScope = nullptr; // NotNull<Scope> when removing FFlag::LuauNonReentrantGeneralization2
317-
if (FFlag::LuauNonReentrantGeneralization2)
313+
Scope* globalScope = nullptr; // NotNull<Scope> when removing FFlag::LuauNonReentrantGeneralization3
314+
if (FFlag::LuauNonReentrantGeneralization3)
318315
globalScope = globals.globalScope.get();
319316

320317
if (FFlag::LuauSolverV2)
@@ -420,23 +417,7 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
420417
// clang-format on
421418
}
422419

423-
if (FFlag::LuauUserTypeFunTypecheck)
424-
{
425-
finalizeGlobalBindings(globals.globalScope);
426-
}
427-
else
428-
{
429-
for (const auto& pair : globals.globalScope->bindings)
430-
{
431-
persist(pair.second.typeId);
432-
433-
if (TableType* ttv = getMutable<TableType>(pair.second.typeId))
434-
{
435-
if (!ttv->name)
436-
ttv->name = "typeof(" + toString(pair.first) + ")";
437-
}
438-
}
439-
}
420+
finalizeGlobalBindings(globals.globalScope);
440421

441422
attachMagicFunction(getGlobalBinding(globals, "assert"), std::make_shared<MagicAssert>());
442423

@@ -500,58 +481,55 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
500481
attachTag(requireTy, kRequireTagName);
501482
attachMagicFunction(requireTy, std::make_shared<MagicRequire>());
502483

503-
if (FFlag::LuauUserTypeFunTypecheck)
504-
{
505-
// Global scope cannot be the parent of the type checking environment because it can be changed by the embedder
506-
globals.globalTypeFunctionScope->exportedTypeBindings = globals.globalScope->exportedTypeBindings;
507-
globals.globalTypeFunctionScope->builtinTypeNames = globals.globalScope->builtinTypeNames;
508-
509-
// Type function runtime also removes a few standard libraries and globals, so we will take only the ones that are defined
510-
static const char* typeFunctionRuntimeBindings[] = {
511-
// Libraries
512-
"math",
513-
"table",
514-
"string",
515-
"bit32",
516-
"utf8",
517-
"buffer",
518-
519-
// Globals
520-
"assert",
521-
"error",
522-
"print",
523-
"next",
524-
"ipairs",
525-
"pairs",
526-
"select",
527-
"unpack",
528-
"getmetatable",
529-
"setmetatable",
530-
"rawget",
531-
"rawset",
532-
"rawlen",
533-
"rawequal",
534-
"tonumber",
535-
"tostring",
536-
"type",
537-
"typeof",
538-
};
484+
// Global scope cannot be the parent of the type checking environment because it can be changed by the embedder
485+
globals.globalTypeFunctionScope->exportedTypeBindings = globals.globalScope->exportedTypeBindings;
486+
globals.globalTypeFunctionScope->builtinTypeNames = globals.globalScope->builtinTypeNames;
487+
488+
// Type function runtime also removes a few standard libraries and globals, so we will take only the ones that are defined
489+
static const char* typeFunctionRuntimeBindings[] = {
490+
// Libraries
491+
"math",
492+
"table",
493+
"string",
494+
"bit32",
495+
"utf8",
496+
"buffer",
497+
498+
// Globals
499+
"assert",
500+
"error",
501+
"print",
502+
"next",
503+
"ipairs",
504+
"pairs",
505+
"select",
506+
"unpack",
507+
"getmetatable",
508+
"setmetatable",
509+
"rawget",
510+
"rawset",
511+
"rawlen",
512+
"rawequal",
513+
"tonumber",
514+
"tostring",
515+
"type",
516+
"typeof",
517+
};
539518

540-
for (auto& name : typeFunctionRuntimeBindings)
541-
{
542-
AstName astName = globals.globalNames.names->get(name);
543-
LUAU_ASSERT(astName.value);
519+
for (auto& name : typeFunctionRuntimeBindings)
520+
{
521+
AstName astName = globals.globalNames.names->get(name);
522+
LUAU_ASSERT(astName.value);
544523

545-
globals.globalTypeFunctionScope->bindings[astName] = globals.globalScope->bindings[astName];
546-
}
524+
globals.globalTypeFunctionScope->bindings[astName] = globals.globalScope->bindings[astName];
525+
}
547526

548-
LoadDefinitionFileResult typeFunctionLoadResult = frontend.loadDefinitionFile(
549-
globals, globals.globalTypeFunctionScope, getTypeFunctionDefinitionSource(), "@luau", /* captureComments */ false, false
550-
);
551-
LUAU_ASSERT(typeFunctionLoadResult.success);
527+
LoadDefinitionFileResult typeFunctionLoadResult = frontend.loadDefinitionFile(
528+
globals, globals.globalTypeFunctionScope, getTypeFunctionDefinitionSource(), "@luau", /* captureComments */ false, false
529+
);
530+
LUAU_ASSERT(typeFunctionLoadResult.success);
552531

553-
finalizeGlobalBindings(globals.globalTypeFunctionScope);
554-
}
532+
finalizeGlobalBindings(globals.globalTypeFunctionScope);
555533
}
556534

557535
static std::vector<TypeId> parseFormatString(NotNull<BuiltinTypes> builtinTypes, const char* data, size_t size)

Analysis/src/Constraint.cpp

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,6 @@ DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
143143
rci.traverse(ty);
144144
// `UnpackConstraint` should not mutate `sourcePack`.
145145
}
146-
else if (auto rpc = get<ReduceConstraint>(*this); FFlag::DebugLuauGreedyGeneralization && rpc)
147-
{
148-
rci.traverse(rpc->ty);
149-
}
150146
else if (auto rpc = get<ReducePackConstraint>(*this))
151147
{
152148
rci.traverse(rpc->tp);

0 commit comments

Comments
 (0)