Skip to content

Commit 004d88f

Browse files
aatxevegorov-rbx
andauthored
Sync to upstream/release/711 (#2280)
Hi there, folks! We're back with another weekly Luau release! # Language * Adds the `const` keyword for defining constant bindings that are statically forbidden to be reassigned to. This implements [luau-lang/rfcs#166](luau-lang/rfcs#166). * Adds a collection of new math constants to Luau's `math` library per [luau-lang/rfcs#169](luau-lang/rfcs#169). # Analysis * Fixes a class of bugs where Luau would not retain reasonable upper or lower bounds on free types, resulting in types snapping to `never` or `unknown` despite having bounds. ```luau --!strict -- `lines` will be inferred to be of `{ string }` now, and prior -- was local lines = {} table.insert(lines, table.concat({}, "")) print(table.concat(lines, "\n")) ``` ```luau --!strict -- `buttons` will be inferred to be of type `{ { a: number } }` local buttons = {} table.insert(buttons, { a = 1 }) table.insert(buttons, { a = 2, b = true }) table.insert(buttons, { a = 3 }) ``` * Disables the type error from `string.format` when called with a dynamically-determined format string (i.e. a non-literal string argument with the type `string`) in response to user feedback about it being too noisy. * Resolves an ICE that could occur when type checking curried generic functions. Fixes #2061! * Fixes false positive type errors from doing equality or inequality against `nil` when indexing from a table * In #2256, adds a state parameter to the `useratom` callback for consistency with other callbacks. # Compiler - Improves the compiler's type inference for vector component access, numerical for loops, function return types and singleton type annotations, fixing #2244 #2235 and #2255. # Native Code Generation - Fixes a bug where some operations on x86_64 would produce integers that would take up more than 32-bits when a 32-bit integer is expected. We resolve these issues by properly truncating to 32-bits in these situations. - Improves dead store elimination for conditional jumps and fastcalls arguments, improving overall native codegen performance by about 2% on average in benchmarks, with some benchmarks as high as 25%. --------- Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com>
1 parent 9645801 commit 004d88f

114 files changed

Lines changed: 4441 additions & 3426 deletions

File tree

Some content is hidden

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

Analysis/include/Luau/ConstraintGenerator.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,17 @@ struct ConstraintGenerator
446446
Polarity initialPolarity = Polarity::Positive
447447
);
448448

449+
// Clip with LuauForwardPolarityForFunctionTypes
450+
TypePackId resolveTypePack_DEPRECATED(
451+
const ScopePtr& scope,
452+
const AstTypeList& list,
453+
bool inTypeArguments,
454+
bool replaceErrorWithFresh = false,
455+
Polarity initialPolarity = Polarity::Positive
456+
);
457+
458+
TypePackId resolveTypePack_(const ScopePtr& scope, const AstTypeList& list, bool inTypeArguments, bool replaceErrorWithFresh);
459+
449460
/**
450461
* Creates generic types given a list of AST definitions, resolving default
451462
* types as required.

Analysis/include/Luau/Frontend.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,13 @@ struct Frontend
174174

175175
size_t dynamicConstraintsCreated = 0;
176176
};
177-
177+
Frontend(SolverMode mode, FileResolver* fileResolver, ConfigResolver* configResolver, FrontendOptions options = {});
178178
Frontend(FileResolver* fileResolver, ConfigResolver* configResolver, const FrontendOptions& options = {});
179179

180180
void setLuauSolverMode(SolverMode mode);
181181
SolverMode getLuauSolverMode() const;
182182
// The default value assuming there is no workspace setup yet
183-
std::atomic<SolverMode> useNewLuauSolver{FFlag::LuauSolverV2 ? SolverMode::New : SolverMode::Old};
183+
std::atomic<SolverMode> useNewLuauSolver;
184184
// Parse module graph and prepare SourceNode/SourceModule data, including required dependencies without running typechecking
185185
void parse(const ModuleName& name);
186186
void parseModules(const std::vector<ModuleName>& name);

Analysis/include/Luau/Generalization.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ struct GeneralizationResult
3232
}
3333
};
3434

35-
// Replace a single free type by its bounds according to the polarity provided.
3635
GeneralizationResult<TypeId> generalizeType(
3736
NotNull<TypeArena> arena,
3837
NotNull<BuiltinTypes> builtinTypes,
@@ -41,6 +40,15 @@ GeneralizationResult<TypeId> generalizeType(
4140
const GeneralizationParams<TypeId>& params
4241
);
4342

43+
// Replace a single free type by its bounds according to the polarity provided.
44+
GeneralizationResult<TypeId> generalizeType_DEPRECATED(
45+
NotNull<TypeArena> arena,
46+
NotNull<BuiltinTypes> builtinTypes,
47+
NotNull<Scope> scope,
48+
TypeId freeTy,
49+
const GeneralizationParams<TypeId>& params
50+
);
51+
4452
// Generalize one type pack
4553
GeneralizationResult<TypePackId> generalizeTypePack(
4654
NotNull<TypeArena> arena,
@@ -52,6 +60,7 @@ GeneralizationResult<TypePackId> generalizeTypePack(
5260

5361
void sealTable(NotNull<Scope> scope, TypeId ty);
5462

63+
5564
/** Attempt to generalize a type.
5665
*
5766
* If generalizationTarget is set, then only that type will be replaced by its

Analysis/include/Luau/InferPolarity.h

Lines changed: 0 additions & 19 deletions
This file was deleted.

Analysis/include/Luau/Instantiation2.h

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ namespace Luau
1414
struct TypeArena;
1515
struct TypeCheckLimits;
1616

17-
struct Replacer : Substitution
17+
struct Replacer_DEPRECATED : Substitution
1818
{
1919
DenseHashMap<TypeId, TypeId> replacements;
2020
DenseHashMap<TypePackId, TypePackId> replacementPacks;
2121

22-
Replacer(NotNull<TypeArena> arena, DenseHashMap<TypeId, TypeId> replacements, DenseHashMap<TypePackId, TypePackId> replacementPacks)
22+
Replacer_DEPRECATED(NotNull<TypeArena> arena, DenseHashMap<TypeId, TypeId> replacements, DenseHashMap<TypePackId, TypePackId> replacementPacks)
2323
: Substitution(TxnLog::empty(), arena)
2424
, replacements(std::move(replacements))
2525
, replacementPacks(std::move(replacementPacks))
@@ -53,6 +53,33 @@ struct Replacer : Substitution
5353
}
5454
};
5555

56+
struct Replacer : Substitution
57+
{
58+
NotNull<DenseHashMap<TypeId, TypeId>> replacements;
59+
NotNull<DenseHashMap<TypePackId, TypePackId>> replacementPacks;
60+
61+
Replacer(NotNull<TypeArena> arena, NotNull<DenseHashMap<TypeId, TypeId>> replacements, NotNull<DenseHashMap<TypePackId, TypePackId>> replacementPacks);
62+
63+
bool isDirty(TypeId ty) override;
64+
65+
bool isDirty(TypePackId tp) override;
66+
67+
TypeId clean(TypeId ty) override;
68+
69+
TypePackId clean(TypePackId tp) override;
70+
71+
bool ignoreChildren(TypeId ty) override;
72+
73+
private:
74+
/**
75+
* It is *very* easy to create the world's worst bug by using a bound type
76+
* as key: this is a helper function we run in debug mode to confirm this
77+
* isn't the case.
78+
*/
79+
bool checkReplacementKeys() const;
80+
81+
};
82+
5683
// A substitution which replaces generic functions by monomorphic functions
5784
struct Instantiation2 final : Substitution
5885
{
@@ -94,22 +121,6 @@ struct Instantiation2 final : Substitution
94121
TypePackId clean(TypePackId tp) override;
95122
};
96123

97-
// Clip with LuauInstantiationUsesGenericPolarity
98-
std::optional<TypeId> instantiate2_DEPRECATED(
99-
TypeArena* arena,
100-
DenseHashMap<TypeId, TypeId> genericSubstitutions,
101-
DenseHashMap<TypePackId, TypePackId> genericPackSubstitutions,
102-
TypeId ty
103-
);
104-
105-
// Clip with LuauInstantiationUsesGenericPolarity
106-
std::optional<TypePackId> instantiate2_DEPRECATED(
107-
TypeArena* arena,
108-
DenseHashMap<TypeId, TypeId> genericSubstitutions,
109-
DenseHashMap<TypePackId, TypePackId> genericPackSubstitutions,
110-
TypePackId tp
111-
);
112-
113124
std::optional<TypeId> instantiate2(
114125
TypeArena* arena,
115126
DenseHashMap<TypeId, TypeId> genericSubstitutions,

Analysis/include/Luau/TableLiteralInference.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,6 @@ struct PushTypeResult
2525
std::vector<IncompleteInference> incompleteTypes;
2626
};
2727

28-
// Clip with LuauPushTypeConstraintLambdas3
29-
PushTypeResult pushTypeInto_DEPRECATED(
30-
NotNull<DenseHashMap<const AstExpr*, TypeId>> astTypes,
31-
NotNull<DenseHashMap<const AstExpr*, TypeId>> astExpectedTypes,
32-
NotNull<ConstraintSolver> solver,
33-
NotNull<const Constraint> constraint,
34-
NotNull<Unifier2> unifier,
35-
NotNull<Subtyping> subtyping,
36-
TypeId expectedType,
37-
const AstExpr* expr
38-
);
39-
4028
PushTypeResult pushTypeInto(
4129
NotNull<DenseHashMap<const AstExpr*, TypeId>> astTypes,
4230
NotNull<DenseHashMap<const AstExpr*, TypeId>> astExpectedTypes,

Analysis/include/Luau/Unifier2.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ struct Unifier2
122122
UnifyResult unify_(const MetatableType* subMetatable, const AnyType*);
123123
UnifyResult unify_(const AnyType*, const MetatableType* superMetatable);
124124

125+
UnifyResult unify_DEPRECATED(TypePackId subTp, TypePackId superTp);
126+
125127
UnifyResult unify_(TypePackId subTp, TypePackId superTp);
126128

127129
std::optional<TypeId> generalize(TypeId ty);

Analysis/src/AstJsonEncoder.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include <math.h>
1010

11+
LUAU_FASTFLAG(LuauConst)
12+
1113
namespace Luau
1214
{
1315

@@ -241,6 +243,8 @@ struct AstJsonEncoder : public AstVisitor
241243
else
242244
write("luauType", nullptr);
243245
write("name", local->name);
246+
if (FFlag::LuauConst)
247+
write("isConst", local->isConst);
244248
writeType("AstLocal");
245249
write("location", local->location);
246250
popComma(c);

Analysis/src/AutocompleteCore.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,11 @@ static void autocompleteProps(
399399
auto indexIt = mtable->props.find("__index");
400400
if (indexIt != mtable->props.end())
401401
{
402+
#ifndef __EMSCRIPTEN__
403+
// EMSDK cannot compile the flag-off branch, so force the flag on with defines here.
404+
// Delete these conditionals when this flag is removed.
402405
if (FFlag::LuauACOnMTTWriteOnlyPropNoCrash)
406+
#endif
403407
{
404408
TypeId followed = indexIt->second.readTy.value_or(nullptr);
405409
if (followed == nullptr)
@@ -418,6 +422,7 @@ static void autocompleteProps(
418422
autocompleteProps(module, typeArena, builtinTypes, rootTy, *indexFunctionResult, indexType, nodes, result, seen);
419423
}
420424
}
425+
#ifndef __EMSCRIPTEN__
421426
else
422427
{
423428
TypeId followed;
@@ -436,6 +441,7 @@ static void autocompleteProps(
436441
autocompleteProps(module, typeArena, builtinTypes, rootTy, *indexFunctionResult, indexType, nodes, result, seen);
437442
}
438443
}
444+
#endif
439445
}
440446
};
441447

Analysis/src/BuiltinDefinitions.cpp

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
#include "Luau/DenseHash.h"
1111
#include "Luau/Error.h"
1212
#include "Luau/Frontend.h"
13-
#include "Luau/InferPolarity.h"
1413
#include "Luau/Module.h"
1514
#include "Luau/NotNull.h"
1615
#include "Luau/Subtyping.h"
@@ -34,9 +33,9 @@
3433
LUAU_FASTFLAG(LuauSolverV2)
3534
LUAU_FASTFLAGVARIABLE(LuauTableCloneClonesType4)
3635
LUAU_FASTFLAGVARIABLE(LuauCloneForIntersectionsUnions)
37-
LUAU_FASTFLAG(LuauStorePolarityInline)
3836
LUAU_FASTFLAGVARIABLE(LuauTableFreezeCheckIsSubtype)
3937
LUAU_FASTFLAG(LuauAnalysisUsesSolverMode)
38+
LUAU_FASTFLAGVARIABLE(LuauSilenceDynamicFormatStringErrors)
4039

4140
namespace Luau
4241
{
@@ -297,8 +296,6 @@ void addGlobalBinding(GlobalTypes& globals, const ScopePtr& scope, const std::st
297296

298297
void addGlobalBinding(GlobalTypes& globals, const ScopePtr& scope, const std::string& name, Binding binding)
299298
{
300-
if (!FFlag::LuauStorePolarityInline)
301-
inferGenericPolarities_DEPRECATED(NotNull{&globals.globalTypes}, NotNull{scope.get()}, binding.typeId);
302299
scope->bindings[globals.globalNames.names->getOrAdd(name.c_str())] = binding;
303300
}
304301

@@ -372,10 +369,8 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
372369
);
373370
LUAU_ASSERT(loadResult.success);
374371

375-
TypeId genericK =
376-
FFlag::LuauStorePolarityInline ? arena.addType(GenericType{globalScope, "K", Polarity::Mixed}) : arena.addType(GenericType{globalScope, "K"});
377-
TypeId genericV =
378-
FFlag::LuauStorePolarityInline ? arena.addType(GenericType{globalScope, "V", Polarity::Mixed}) : arena.addType(GenericType{globalScope, "V"});
372+
TypeId genericK = arena.addType(GenericType{globalScope, "K", Polarity::Mixed});
373+
TypeId genericV = arena.addType(GenericType{globalScope, "V", Polarity::Mixed});
379374
TypeId mapOfKtoV = arena.addType(TableType{{}, TableIndexer(genericK, genericV), globals.globalScope->level, TableState::Generic});
380375

381376
std::optional<TypeId> stringMetatableTy = getMetatable(builtinTypes->stringType, builtinTypes);
@@ -424,16 +419,14 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
424419
// pairs<K, V>(t: Table<K, V>) -> ((Table<K, V>, K?) -> (K, V), Table<K, V>, nil)
425420
addGlobalBinding(globals, "pairs", arena.addType(FunctionType{{genericK, genericV}, {}, pairsArgsTypePack, pairsReturnTypePack}), "@luau");
426421

427-
TypeId genericMT = FFlag::LuauStorePolarityInline ? arena.addType(GenericType{globalScope, "MT", Polarity::Mixed})
428-
: arena.addType(GenericType{globalScope, "MT"});
422+
TypeId genericMT = arena.addType(GenericType{globalScope, "MT", Polarity::Mixed});
429423

430424
TableType tab{TableState::Generic, globals.globalScope->level};
431425
TypeId tabTy = arena.addType(std::move(tab));
432426

433427
TypeId tableMetaMT = arena.addType(MetatableType{tabTy, genericMT});
434428

435-
TypeId genericT =
436-
FFlag::LuauStorePolarityInline ? arena.addType(GenericType{globalScope, "T", Polarity::Mixed}) : arena.addType(GenericType{globalScope, "T"});
429+
TypeId genericT = arena.addType(GenericType{globalScope, "T", Polarity::Mixed});
437430

438431
if (frontend.getLuauSolverMode() == SolverMode::New)
439432
{
@@ -479,8 +472,7 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
479472
if (frontend.getLuauSolverMode() == SolverMode::New)
480473
{
481474
// declare function assert<T>(value: T, errorMessage: string?): intersect<T, ~(false?)>
482-
TypeId genericT = FFlag::LuauStorePolarityInline ? arena.addType(GenericType{globalScope, "T", Polarity::Mixed})
483-
: arena.addType(GenericType{globalScope, "T"});
475+
TypeId genericT = arena.addType(GenericType{globalScope, "T", Polarity::Mixed});
484476

485477
TypeId refinedTy = arena.addType(
486478
TypeFunctionInstanceType{
@@ -508,20 +500,13 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
508500
// the top table type. We do the best we can by modelling these
509501
// functions using unconstrained generics. It's not quite right,
510502
// but it'll be ok for now.
511-
TypeId genericTy = FFlag::LuauStorePolarityInline ? arena.addType(GenericType{globalScope, "T", Polarity::Mixed})
512-
: arena.addType(GenericType{globalScope, "T"});
503+
TypeId genericTy = arena.addType(GenericType{globalScope, "T", Polarity::Mixed});
513504
TypePackId thePack = arena.addTypePack({genericTy});
514505
TypeId idTyWithMagic = arena.addType(FunctionType{{genericTy}, {}, thePack, thePack});
515506
ttv->props["freeze"] = makeProperty(idTyWithMagic, "@luau/global/table.freeze");
516507

517-
if (!FFlag::LuauStorePolarityInline)
518-
inferGenericPolarities_DEPRECATED(NotNull{&globals.globalTypes}, NotNull{globalScope}, idTyWithMagic);
519-
520508
TypeId idTy = arena.addType(FunctionType{{genericTy}, {}, thePack, thePack});
521509

522-
if (!FFlag::LuauStorePolarityInline)
523-
inferGenericPolarities_DEPRECATED(NotNull{&globals.globalTypes}, NotNull{globalScope}, idTy);
524-
525510
ttv->props["clone"] = makeProperty(idTy, "@luau/global/table.clone");
526511
}
527512
else
@@ -773,10 +758,18 @@ bool MagicFormat::typeCheck(const MagicFunctionTypeCheckContext& context)
773758
formatString = {stringSingleton->value};
774759
}
775760

776-
if (!formatString)
761+
if (FFlag::LuauSilenceDynamicFormatStringErrors)
777762
{
778-
context.typechecker->reportError(CannotCheckDynamicStringFormatCalls{}, context.callSite->location);
779-
return true;
763+
if (!formatString)
764+
return true;
765+
}
766+
else
767+
{
768+
if (!formatString)
769+
{
770+
context.typechecker->reportError(CannotCheckDynamicStringFormatCalls{}, context.callSite->location);
771+
return true;
772+
}
780773
}
781774

782775
// CLI-150726: The block below effectively constructs a type pack and then type checks it by going parameter-by-parameter.

0 commit comments

Comments
 (0)