Skip to content

Commit 5965818

Browse files
vrn-snhgoldsteinayoungbloodrbxmenarulalamaviralg
authored
Sync to upstream/release/675 (#1845)
## General - Introduce `Frontend::parseModules` for parsing a group of modules at once. - Support chained function types in the CST. ## New Type Solver - Enable write-only table properties (described in [this RFC](https://rfcs.luau.org/property-writeonly.html)). - Disable singleton inference for large tables to improve performance. - Fix a bug that occurs when we try to expand a type alias to itself. - Catch cancelation during the type-checking phase in addition to during constraint solving. - Fix stringification of the empty type pack: `()`. - Improve errors for calls being rejected on the primitive `function` type. - Rework generalization: We now generalize types as soon as the last constraint relating to them is finished. We think this will reduce the number of cases where type inference fails to complete and reduce the number of instances where `*blocked*` types appear in the inference result. ## VM/Runtime - Dynamically disable native execution for functions that incur a slowdown (relative to bytecode execution). - Improve names for `thread`/`closure`/`proto` in the Luau heap dump. --- Co-authored-by: Andy Friesen <afriesen@roblox.com> Co-authored-by: Ariel Weiss <aaronweiss@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com> Co-authored-by: Talha Pathan <tpathan@roblox.com> Co-authored-by: Varun Saini <vsaini@roblox.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> --------- Co-authored-by: Hunter Goldstein <hgoldstein@roblox.com> Co-authored-by: Alexander Youngblood <ayoungblood@roblox.com> Co-authored-by: Menarul Alam <malam@roblox.com> Co-authored-by: Aviral Goel <agoel@roblox.com> Co-authored-by: Vighnesh <vvijay@roblox.com> Co-authored-by: Vyacheslav Egorov <vegorov@roblox.com> Co-authored-by: Ariel Weiss <aaronweiss@roblox.com> Co-authored-by: Andy Friesen <afriesen@roblox.com>
1 parent 92cce57 commit 5965818

Some content is hidden

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

70 files changed

+3259
-1031
lines changed

Analysis/include/Luau/ConstraintGenerator.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ struct ConstraintGenerator
175175

176176
std::vector<TypeId> unionsToSimplify;
177177

178+
// Used to keep track of when we are inside a large table and should
179+
// opt *not* to do type inference for singletons.
180+
size_t largeTableDepth = 0;
181+
178182
/**
179183
* Fabricates a new free type belonging to a given scope.
180184
* @param scope the scope the free type belongs to.

Analysis/include/Luau/ConstraintSolver.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ struct ConstraintSolver
225225
bool tryDispatch(const IterableConstraint& c, NotNull<const Constraint> constraint, bool force);
226226
bool tryDispatch(const NameConstraint& c, NotNull<const Constraint> constraint);
227227
bool tryDispatch(const TypeAliasExpansionConstraint& c, NotNull<const Constraint> constraint);
228-
bool tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint);
228+
bool tryDispatch(const FunctionCallConstraint& c, NotNull<const Constraint> constraint, bool force);
229229
bool tryDispatch(const TableCheckConstraint& c, NotNull<const Constraint> constraint);
230230
bool tryDispatch(const FunctionCheckConstraint& c, NotNull<const Constraint> constraint);
231231
bool tryDispatch(const PrimitiveTypeConstraint& c, NotNull<const Constraint> constraint);

Analysis/include/Luau/Frontend.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ struct Frontend
166166

167167
// Parse module graph and prepare SourceNode/SourceModule data, including required dependencies without running typechecking
168168
void parse(const ModuleName& name);
169+
void parseModules(const std::vector<ModuleName>& name);
169170

170171
// Parse and typecheck module graph
171172
CheckResult check(const ModuleName& name, std::optional<FrontendOptions> optionOverride = {}); // new shininess

Analysis/include/Luau/OverloadResolution.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ struct OverloadResolver
6363
InsertionOrderedMap<TypeId, std::pair<OverloadResolver::Analysis, size_t>> resolution;
6464

6565

66-
std::pair<OverloadResolver::Analysis, TypeId> selectOverload(TypeId ty, TypePackId args);
66+
std::pair<OverloadResolver::Analysis, TypeId> selectOverload(TypeId ty, TypePackId args, bool useFreeTypeBounds);
6767
void resolve(TypeId fnTy, const TypePack* args, AstExpr* selfExpr, const std::vector<AstExpr*>* argExprs);
6868

6969
private:

Analysis/include/Luau/Subtyping.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ struct SubtypingResult
7272
/// isSubtype is false, depending on the input types.
7373
SubtypingReasonings reasoning{kEmptyReasoning};
7474

75+
// If this subtype result required testing free types, we might be making
76+
// assumptions about what the free type eventually resolves to. If so,
77+
// those assumptions are recorded here.
78+
std::vector<SubtypeConstraint> assumedConstraints;
79+
7580
SubtypingResult& andAlso(const SubtypingResult& other);
7681
SubtypingResult& orElse(const SubtypingResult& other);
7782
SubtypingResult& withBothComponent(TypePath::Component component);

Analysis/src/AutocompleteCore.cpp

Lines changed: 27 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ LUAU_FASTFLAG(LuauSolverV2)
2424
LUAU_FASTINT(LuauTypeInferIterationLimit)
2525
LUAU_FASTINT(LuauTypeInferRecursionLimit)
2626
LUAU_FASTFLAGVARIABLE(DebugLuauMagicVariableNames)
27-
LUAU_FASTFLAGVARIABLE(LuauAutocompleteUsesModuleForTypeCompatibility)
2827
LUAU_FASTFLAGVARIABLE(LuauAutocompleteMissingFollows)
2928
LUAU_FASTFLAG(LuauStoreReturnTypesAsPackOnAst)
3029

@@ -163,78 +162,39 @@ static bool checkTypeMatch(
163162
UnifierSharedState unifierState(&iceReporter);
164163
SimplifierPtr simplifier = newSimplifier(NotNull{typeArena}, builtinTypes);
165164
Normalizer normalizer{typeArena, builtinTypes, NotNull{&unifierState}};
166-
if (FFlag::LuauAutocompleteUsesModuleForTypeCompatibility)
167-
{
168-
if (module.checkedInNewSolver)
169-
{
170-
TypeCheckLimits limits;
171-
TypeFunctionRuntime typeFunctionRuntime{
172-
NotNull{&iceReporter}, NotNull{&limits}
173-
}; // TODO: maybe subtyping checks should not invoke user-defined type function runtime
174-
175-
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
176-
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
177-
178-
Subtyping subtyping{
179-
builtinTypes,
180-
NotNull{typeArena},
181-
NotNull{simplifier.get()},
182-
NotNull{&normalizer},
183-
NotNull{&typeFunctionRuntime},
184-
NotNull{&iceReporter}
185-
};
186-
187-
return subtyping.isSubtype(subTy, superTy, scope).isSubtype;
188-
}
189-
else
190-
{
191-
Unifier unifier(NotNull<Normalizer>{&normalizer}, scope, Location(), Variance::Covariant);
192-
193-
// Cost of normalization can be too high for autocomplete response time requirements
194-
unifier.normalize = false;
195-
unifier.checkInhabited = false;
196-
197-
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
198-
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
165+
if (module.checkedInNewSolver)
166+
{
167+
TypeCheckLimits limits;
168+
TypeFunctionRuntime typeFunctionRuntime{
169+
NotNull{&iceReporter}, NotNull{&limits}
170+
}; // TODO: maybe subtyping checks should not invoke user-defined type function runtime
171+
172+
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
173+
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
174+
175+
Subtyping subtyping{
176+
builtinTypes,
177+
NotNull{typeArena},
178+
NotNull{simplifier.get()},
179+
NotNull{&normalizer},
180+
NotNull{&typeFunctionRuntime},
181+
NotNull{&iceReporter}
182+
};
199183

200-
return unifier.canUnify(subTy, superTy).empty();
201-
}
184+
return subtyping.isSubtype(subTy, superTy, scope).isSubtype;
202185
}
203186
else
204187
{
205-
if (FFlag::LuauSolverV2)
206-
{
207-
TypeCheckLimits limits;
208-
TypeFunctionRuntime typeFunctionRuntime{
209-
NotNull{&iceReporter}, NotNull{&limits}
210-
}; // TODO: maybe subtyping checks should not invoke user-defined type function runtime
211-
212-
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
213-
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
214-
215-
Subtyping subtyping{
216-
builtinTypes,
217-
NotNull{typeArena},
218-
NotNull{simplifier.get()},
219-
NotNull{&normalizer},
220-
NotNull{&typeFunctionRuntime},
221-
NotNull{&iceReporter}
222-
};
223-
224-
return subtyping.isSubtype(subTy, superTy, scope).isSubtype;
225-
}
226-
else
227-
{
228-
Unifier unifier(NotNull<Normalizer>{&normalizer}, scope, Location(), Variance::Covariant);
188+
Unifier unifier(NotNull<Normalizer>{&normalizer}, scope, Location(), Variance::Covariant);
229189

230-
// Cost of normalization can be too high for autocomplete response time requirements
231-
unifier.normalize = false;
232-
unifier.checkInhabited = false;
233-
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
234-
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
190+
// Cost of normalization can be too high for autocomplete response time requirements
191+
unifier.normalize = false;
192+
unifier.checkInhabited = false;
235193

236-
return unifier.canUnify(subTy, superTy).empty();
237-
}
194+
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
195+
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
196+
197+
return unifier.canUnify(subTy, superTy).empty();
238198
}
239199
}
240200

Analysis/src/BuiltinDefinitions.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
*/
3131

3232
LUAU_FASTFLAG(LuauSolverV2)
33-
LUAU_FASTFLAG(LuauNonReentrantGeneralization3)
33+
LUAU_FASTFLAG(LuauEagerGeneralization)
3434
LUAU_FASTFLAGVARIABLE(LuauTableCloneClonesType3)
3535
LUAU_FASTFLAGVARIABLE(LuauMagicFreezeCheckBlocked2)
3636
LUAU_FASTFLAGVARIABLE(LuauFormatUseLastPosition)
@@ -310,8 +310,8 @@ void registerBuiltinGlobals(Frontend& frontend, GlobalTypes& globals, bool typeC
310310

311311
TypeArena& arena = globals.globalTypes;
312312
NotNull<BuiltinTypes> builtinTypes = globals.builtinTypes;
313-
Scope* globalScope = nullptr; // NotNull<Scope> when removing FFlag::LuauNonReentrantGeneralization3
314-
if (FFlag::LuauNonReentrantGeneralization3)
313+
Scope* globalScope = nullptr; // NotNull<Scope> when removing FFlag::LuauEagerGeneralization
314+
if (FFlag::LuauEagerGeneralization)
315315
globalScope = globals.globalScope.get();
316316

317317
if (FFlag::LuauSolverV2)

Analysis/src/Clone.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ LUAU_FASTFLAG(LuauSolverV2)
1212

1313
// For each `Luau::clone` call, we will clone only up to N amount of types _and_ packs, as controlled by this limit.
1414
LUAU_FASTINTVARIABLE(LuauTypeCloneIterationLimit, 100'000)
15-
LUAU_FASTFLAGVARIABLE(LuauClonedTableAndFunctionTypesMustHaveScopes)
16-
LUAU_FASTFLAGVARIABLE(LuauDoNotClonePersistentBindings)
1715
namespace Luau
1816
{
1917

@@ -514,10 +512,7 @@ class FragmentAutocompleteTypeCloner final : public TypeCloner
514512
free->scope = replacementForNullScope;
515513
}
516514
else if (auto tt = getMutable<TableType>(target))
517-
{
518-
if (FFlag::LuauClonedTableAndFunctionTypesMustHaveScopes)
519-
tt->scope = replacementForNullScope;
520-
}
515+
tt->scope = replacementForNullScope;
521516

522517
(*types)[ty] = target;
523518
queue.emplace_back(target);
@@ -733,7 +728,7 @@ Binding cloneIncremental(const Binding& binding, TypeArena& dest, CloneState& cl
733728
b.deprecatedSuggestion = binding.deprecatedSuggestion;
734729
b.documentationSymbol = binding.documentationSymbol;
735730
b.location = binding.location;
736-
b.typeId = FFlag::LuauDoNotClonePersistentBindings && binding.typeId->persistent ? binding.typeId : cloner.clone(binding.typeId);
731+
b.typeId = binding.typeId->persistent ? binding.typeId : cloner.clone(binding.typeId);
737732

738733
return b;
739734
}

Analysis/src/Constraint.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include "Luau/Constraint.h"
44
#include "Luau/VisitType.h"
55

6-
LUAU_FASTFLAG(DebugLuauGreedyGeneralization)
6+
LUAU_FASTFLAG(LuauEagerGeneralization)
77

88
namespace Luau
99
{
@@ -17,8 +17,8 @@ Constraint::Constraint(NotNull<Scope> scope, const Location& location, Constrain
1717

1818
struct ReferenceCountInitializer : TypeOnceVisitor
1919
{
20-
2120
DenseHashSet<TypeId>* result;
21+
bool traverseIntoTypeFunctions = true;
2222

2323
explicit ReferenceCountInitializer(DenseHashSet<TypeId>* result)
2424
: result(result)
@@ -51,7 +51,7 @@ struct ReferenceCountInitializer : TypeOnceVisitor
5151

5252
bool visit(TypeId, const TypeFunctionInstanceType&) override
5353
{
54-
return FFlag::DebugLuauGreedyGeneralization;
54+
return FFlag::LuauEagerGeneralization && traverseIntoTypeFunctions;
5555
}
5656
};
5757

@@ -104,10 +104,12 @@ DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
104104
{
105105
rci.traverse(fchc->argsPack);
106106
}
107-
else if (auto fcc = get<FunctionCallConstraint>(*this); fcc && FFlag::DebugLuauGreedyGeneralization)
107+
else if (auto fcc = get<FunctionCallConstraint>(*this); fcc && FFlag::LuauEagerGeneralization)
108108
{
109+
rci.traverseIntoTypeFunctions = false;
109110
rci.traverse(fcc->fn);
110111
rci.traverse(fcc->argsPack);
112+
rci.traverseIntoTypeFunctions = true;
111113
}
112114
else if (auto ptc = get<PrimitiveTypeConstraint>(*this))
113115
{
@@ -116,12 +118,12 @@ DenseHashSet<TypeId> Constraint::getMaybeMutatedFreeTypes() const
116118
else if (auto hpc = get<HasPropConstraint>(*this))
117119
{
118120
rci.traverse(hpc->resultType);
119-
if (FFlag::DebugLuauGreedyGeneralization)
121+
if (FFlag::LuauEagerGeneralization)
120122
rci.traverse(hpc->subjectType);
121123
}
122124
else if (auto hic = get<HasIndexerConstraint>(*this))
123125
{
124-
if (FFlag::DebugLuauGreedyGeneralization)
126+
if (FFlag::LuauEagerGeneralization)
125127
rci.traverse(hic->subjectType);
126128
rci.traverse(hic->resultType);
127129
// `HasIndexerConstraint` should not mutate `indexType`.

0 commit comments

Comments
 (0)