Skip to content

Commit c759cd5

Browse files
hgoldsteinaatxedcope-rbxVighnesh-Vvegorov-rbx
authored
Sync to upstream/release/656 (#1612)
# General All code has been re-formatted by `clang-format`; this is not mechanically enforced, so Luau may go out-of-sync over the course of the year. # New Solver * Track free types interior to a block of code on `Scope`, which should reduce the number of free types that remain un-generalized after type checking is complete (e.g.: less errors like `'a <: number is incompatible with number`). # Autocomplete * Fragment autocomplete now does *not* provide suggestions within comments (matching non-fragment autocomplete behavior). * Autocomplete now respects iteration and recursion limits (some hangs will now early exit with a "unification too complex error," some crashes will now become internal complier exceptions). # Runtime * Add a limit to how many Luau codegen slot nodes addresses can be in use at the same time (fixes #1605, fixes #1558). * Added constant folding for vector arithmetic (fixes #1553). * Added support for `buffer.readbits` and `buffer.writebits` (see: luau-lang/rfcs#18). --- Co-authored-by: Aaron Weiss <[email protected]> Co-authored-by: David Cope <[email protected]> Co-authored-by: Hunter Goldstein <[email protected]> Co-authored-by: Vighnesh Vijay <[email protected]> Co-authored-by: Vyacheslav Egorov <[email protected]>
1 parent 945c510 commit c759cd5

File tree

85 files changed

+1299
-701
lines changed

Some content is hidden

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

85 files changed

+1299
-701
lines changed

Analysis/include/Luau/FragmentAutocomplete.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ namespace Luau
1515
{
1616
struct FrontendOptions;
1717

18+
enum class FragmentTypeCheckStatus
19+
{
20+
Success,
21+
SkipAutocomplete,
22+
};
23+
1824
struct FragmentAutocompleteAncestryResult
1925
{
2026
DenseHashMap<AstName, AstLocal*> localMap{AstName()};
@@ -29,6 +35,7 @@ struct FragmentParseResult
2935
AstStatBlock* root = nullptr;
3036
std::vector<AstNode*> ancestry;
3137
AstStat* nearestStatement = nullptr;
38+
std::vector<Comment> commentLocations;
3239
std::unique_ptr<Allocator> alloc = std::make_unique<Allocator>();
3340
};
3441

@@ -56,7 +63,7 @@ FragmentParseResult parseFragment(
5663
std::optional<Position> fragmentEndPosition
5764
);
5865

59-
FragmentTypeCheckResult typecheckFragment(
66+
std::pair<FragmentTypeCheckStatus, FragmentTypeCheckResult> typecheckFragment(
6067
Frontend& frontend,
6168
const ModuleName& moduleName,
6269
const Position& cursorPos,

Analysis/include/Luau/Module.h

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#include <unordered_map>
1717
#include <optional>
1818

19+
LUAU_FASTFLAG(LuauIncrementalAutocompleteCommentDetection)
20+
1921
namespace Luau
2022
{
2123

@@ -55,6 +57,7 @@ struct SourceModule
5557
}
5658
};
5759

60+
bool isWithinComment(const std::vector<Comment>& commentLocations, Position pos);
5861
bool isWithinComment(const SourceModule& sourceModule, Position pos);
5962
bool isWithinComment(const ParseResult& result, Position pos);
6063

Analysis/include/Luau/Scope.h

+2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ struct Scope
9595
// we need that the generic type `T` in both cases is the same, so we use a cache.
9696
std::unordered_map<Name, TypeId> typeAliasTypeParameters;
9797
std::unordered_map<Name, TypePackId> typeAliasTypePackParameters;
98+
99+
std::optional<std::vector<TypeId>> interiorFreeTypes;
98100
};
99101

100102
// Returns true iff the left scope encloses the right scope. A Scope* equal to

Analysis/include/Luau/Type.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ struct TypeFunctionInstanceType
626626
std::vector<TypeId> typeArguments;
627627
std::vector<TypePackId> packArguments;
628628

629-
std::optional<AstName> userFuncName; // Name of the user-defined type function; only available for UDTFs
629+
std::optional<AstName> userFuncName; // Name of the user-defined type function; only available for UDTFs
630630
UserDefinedFunctionData userFuncData;
631631

632632
TypeFunctionInstanceType(

Analysis/include/Luau/TypeFunction.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ struct TypeFunctionContext
7171
// The constraint being reduced in this run of the reduction
7272
const Constraint* constraint;
7373

74-
std::optional<AstName> userFuncName; // Name of the user-defined type function; only available for UDTFs
74+
std::optional<AstName> userFuncName; // Name of the user-defined type function; only available for UDTFs
7575

7676
TypeFunctionContext(NotNull<ConstraintSolver> cs, NotNull<Scope> scope, NotNull<const Constraint> constraint);
7777

Analysis/include/Luau/TypeUtils.h

+11-2
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,8 @@ bool isLiteral(const AstExpr* expr);
269269
std::vector<TypeId> findBlockedTypesIn(AstExprTable* expr, NotNull<DenseHashMap<const AstExpr*, TypeId>> astTypes);
270270

271271
/**
272-
* Given a function call and a mapping from expression to type, determine
273-
* whether the type of any argument in said call in depends on a blocked types.
272+
* Given a function call and a mapping from expression to type, determine
273+
* whether the type of any argument in said call in depends on a blocked types.
274274
* This is used as a precondition for bidirectional inference: be warned that
275275
* the behavior of this algorithm is tightly coupled to that of bidirectional
276276
* inference.
@@ -280,4 +280,13 @@ std::vector<TypeId> findBlockedTypesIn(AstExprTable* expr, NotNull<DenseHashMap<
280280
*/
281281
std::vector<TypeId> findBlockedArgTypesIn(AstExprCall* expr, NotNull<DenseHashMap<const AstExpr*, TypeId>> astTypes);
282282

283+
/**
284+
* Given a scope and a free type, find the closest parent that has a present
285+
* `interiorFreeTypes` and append the given type to said list. This list will
286+
* be generalized when the requiste `GeneralizationConstraint` is resolved.
287+
* @param scope Initial scope this free type was attached to
288+
* @param ty Free type to track.
289+
*/
290+
void trackInteriorFreeType(Scope* scope, TypeId ty);
291+
283292
} // namespace Luau

Analysis/src/AnyTypeSummary.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,6 @@ void AnyTypeSummary::visit(const Scope* scope, AstStatReturn* ret, const Module*
177177
}
178178
}
179179
}
180-
181180
}
182181

183182
void AnyTypeSummary::visit(const Scope* scope, AstStatLocal* local, const Module* module, NotNull<BuiltinTypes> builtinTypes)

Analysis/src/AutocompleteCore.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ LUAU_FASTINT(LuauTypeInferIterationLimit)
2525
LUAU_FASTINT(LuauTypeInferRecursionLimit)
2626

2727
LUAU_FASTFLAGVARIABLE(LuauAutocompleteRefactorsForIncrementalAutocomplete)
28+
LUAU_FASTFLAGVARIABLE(LuauAutocompleteUseLimits)
2829

2930
static const std::unordered_set<std::string> kStatementStartingKeywords =
3031
{"while", "if", "local", "repeat", "function", "do", "for", "return", "break", "continue", "type", "export"};
@@ -177,6 +178,12 @@ static bool checkTypeMatch(TypeId subTy, TypeId superTy, NotNull<Scope> scope, T
177178
unifier.normalize = false;
178179
unifier.checkInhabited = false;
179180

181+
if (FFlag::LuauAutocompleteUseLimits)
182+
{
183+
unifierState.counters.recursionLimit = FInt::LuauTypeInferRecursionLimit;
184+
unifierState.counters.iterationLimit = FInt::LuauTypeInferIterationLimit;
185+
}
186+
180187
return unifier.canUnify(subTy, superTy).empty();
181188
}
182189
}

Analysis/src/BuiltinDefinitions.cpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,9 @@ static void dcrMagicFunctionTypeCheckFormat(MagicFunctionTypeCheckContext contex
611611
if (!fmt)
612612
{
613613
if (FFlag::LuauStringFormatArityFix)
614-
context.typechecker->reportError(CountMismatch{1, std::nullopt, 0, CountMismatch::Arg, true, "string.format"}, context.callSite->location);
614+
context.typechecker->reportError(
615+
CountMismatch{1, std::nullopt, 0, CountMismatch::Arg, true, "string.format"}, context.callSite->location
616+
);
615617
return;
616618
}
617619

Analysis/src/Constraint.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ struct ReferenceCountInitializer : TypeOnceVisitor
6262
// of this type, hence:
6363
return !FFlag::LuauDontRefCountTypesInTypeFunctions;
6464
}
65-
6665
};
6766

6867
bool isReferenceCountedType(const TypeId typ)

Analysis/src/ConstraintGenerator.cpp

+41-26
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@
3131
LUAU_FASTINT(LuauCheckRecursionLimit)
3232
LUAU_FASTFLAG(DebugLuauLogSolverToJson)
3333
LUAU_FASTFLAG(DebugLuauMagicTypes)
34-
LUAU_FASTFLAG(DebugLuauEqSatSimplification)
3534
LUAU_FASTFLAG(LuauTypestateBuiltins2)
3635
LUAU_FASTFLAG(LuauUserTypeFunUpdateAllEnvs)
3736

3837
LUAU_FASTFLAGVARIABLE(LuauNewSolverVisitErrorExprLvalues)
39-
LUAU_FASTFLAGVARIABLE(LuauNewSolverPrePopulateClasses)
4038
LUAU_FASTFLAGVARIABLE(LuauUserTypeFunExportedAndLocal)
39+
LUAU_FASTFLAGVARIABLE(LuauNewSolverPrePopulateClasses)
4140
LUAU_FASTFLAGVARIABLE(LuauNewSolverPopulateTableLocations)
4241
LUAU_FASTFLAGVARIABLE(LuauUserTypeFunNoExtraConstraint)
42+
LUAU_FASTFLAGVARIABLE(LuauTrackInteriorFreeTypesOnScope)
4343

4444
LUAU_FASTFLAGVARIABLE(InferGlobalTypes)
4545

@@ -233,8 +233,17 @@ void ConstraintGenerator::visitModuleRoot(AstStatBlock* block)
233233
Checkpoint end = checkpoint(this);
234234

235235
TypeId result = arena->addType(BlockedType{});
236-
NotNull<Constraint> genConstraint =
237-
addConstraint(scope, block->location, GeneralizationConstraint{result, moduleFnTy, std::move(interiorTypes.back())});
236+
NotNull<Constraint> genConstraint = addConstraint(
237+
scope,
238+
block->location,
239+
GeneralizationConstraint{
240+
result, moduleFnTy, FFlag::LuauTrackInteriorFreeTypesOnScope ? std::vector<TypeId>{} : std::move(interiorTypes.back())
241+
}
242+
);
243+
244+
if (FFlag::LuauTrackInteriorFreeTypesOnScope)
245+
scope->interiorFreeTypes = std::move(interiorTypes.back());
246+
238247
getMutable<BlockedType>(result)->setOwner(genConstraint);
239248
forEachConstraint(
240249
start,
@@ -303,9 +312,19 @@ void ConstraintGenerator::visitFragmentRoot(const ScopePtr& resumeScope, AstStat
303312
}
304313
}
305314

315+
306316
TypeId ConstraintGenerator::freshType(const ScopePtr& scope)
307317
{
308-
return Luau::freshType(arena, builtinTypes, scope.get());
318+
if (FFlag::LuauTrackInteriorFreeTypesOnScope)
319+
{
320+
auto ft = Luau::freshType(arena, builtinTypes, scope.get());
321+
interiorTypes.back().push_back(ft);
322+
return ft;
323+
}
324+
else
325+
{
326+
return Luau::freshType(arena, builtinTypes, scope.get());
327+
}
309328
}
310329

311330
TypePackId ConstraintGenerator::freshTypePack(const ScopePtr& scope)
@@ -2408,8 +2427,17 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprFunction* fun
24082427
Checkpoint endCheckpoint = checkpoint(this);
24092428

24102429
TypeId generalizedTy = arena->addType(BlockedType{});
2411-
NotNull<Constraint> gc =
2412-
addConstraint(sig.signatureScope, func->location, GeneralizationConstraint{generalizedTy, sig.signature, std::move(interiorTypes.back())});
2430+
NotNull<Constraint> gc = addConstraint(
2431+
sig.signatureScope,
2432+
func->location,
2433+
GeneralizationConstraint{
2434+
generalizedTy, sig.signature, FFlag::LuauTrackInteriorFreeTypesOnScope ? std::vector<TypeId>{} : std::move(interiorTypes.back())
2435+
}
2436+
);
2437+
2438+
if (FFlag::LuauTrackInteriorFreeTypesOnScope)
2439+
sig.signatureScope->interiorFreeTypes = std::move(interiorTypes.back());
2440+
24132441
getMutable<BlockedType>(generalizedTy)->setOwner(gc);
24142442
interiorTypes.pop_back();
24152443

@@ -2975,11 +3003,11 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr,
29753003
ty,
29763004
expr,
29773005
toBlock
2978-
);
2979-
// The visitor we ran prior should ensure that there are no
2980-
// blocked types that we would encounter while matching on
2981-
// this expression.
2982-
LUAU_ASSERT(toBlock.empty());
3006+
);
3007+
// The visitor we ran prior should ensure that there are no
3008+
// blocked types that we would encounter while matching on
3009+
// this expression.
3010+
LUAU_ASSERT(toBlock.empty());
29833011
}
29843012
}
29853013

@@ -3941,20 +3969,7 @@ TypeId ConstraintGenerator::createTypeFunctionInstance(
39413969

39423970
TypeId ConstraintGenerator::simplifyUnion(const ScopePtr& scope, Location location, TypeId left, TypeId right)
39433971
{
3944-
if (FFlag::DebugLuauEqSatSimplification)
3945-
{
3946-
TypeId ty = arena->addType(UnionType{{left, right}});
3947-
std::optional<EqSatSimplificationResult> res = eqSatSimplify(simplifier, ty);
3948-
if (!res)
3949-
return ty;
3950-
3951-
for (TypeId tyFun : res->newTypeFunctions)
3952-
addConstraint(scope, location, ReduceConstraint{tyFun});
3953-
3954-
return res->result;
3955-
}
3956-
else
3957-
return ::Luau::simplifyUnion(builtinTypes, arena, left, right).result;
3972+
return ::Luau::simplifyUnion(builtinTypes, arena, left, right).result;
39583973
}
39593974

39603975
std::vector<NotNull<Constraint>> borrowConstraints(const std::vector<ConstraintPtr>& constraints)

Analysis/src/ConstraintSolver.cpp

+32-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ LUAU_FASTFLAGVARIABLE(DebugLuauEqSatSimplification)
3636
LUAU_FASTFLAG(LuauNewSolverPopulateTableLocations)
3737
LUAU_FASTFLAGVARIABLE(LuauAllowNilAssignmentToIndexer)
3838
LUAU_FASTFLAG(LuauUserTypeFunNoExtraConstraint)
39+
LUAU_FASTFLAG(LuauTrackInteriorFreeTypesOnScope)
3940

4041
namespace Luau
4142
{
@@ -724,8 +725,20 @@ bool ConstraintSolver::tryDispatch(const GeneralizationConstraint& c, NotNull<co
724725
bind(constraint, c.generalizedType, builtinTypes->errorRecoveryType());
725726
}
726727

727-
for (TypeId ty : c.interiorTypes)
728-
generalize(NotNull{arena}, builtinTypes, constraint->scope, generalizedTypes, ty, /* avoidSealingTables */ false);
728+
if (FFlag::LuauTrackInteriorFreeTypesOnScope)
729+
{
730+
// We check if this member is initialized and then access it, but
731+
// clang-tidy doesn't understand this is safe.
732+
if (constraint->scope->interiorFreeTypes)
733+
for (TypeId ty : *constraint->scope->interiorFreeTypes) // NOLINT(bugprone-unchecked-optional-access)
734+
generalize(NotNull{arena}, builtinTypes, constraint->scope, generalizedTypes, ty, /* avoidSealingTables */ false);
735+
}
736+
else
737+
{
738+
for (TypeId ty : c.interiorTypes)
739+
generalize(NotNull{arena}, builtinTypes, constraint->scope, generalizedTypes, ty, /* avoidSealingTables */ false);
740+
}
741+
729742

730743
return true;
731744
}
@@ -801,6 +814,11 @@ bool ConstraintSolver::tryDispatch(const IterableConstraint& c, NotNull<const Co
801814
{
802815
TypeId keyTy = freshType(arena, builtinTypes, constraint->scope);
803816
TypeId valueTy = freshType(arena, builtinTypes, constraint->scope);
817+
if (FFlag::LuauTrackInteriorFreeTypesOnScope)
818+
{
819+
trackInteriorFreeType(constraint->scope, keyTy);
820+
trackInteriorFreeType(constraint->scope, valueTy);
821+
}
804822
TypeId tableTy =
805823
arena->addType(TableType{TableType::Props{}, TableIndexer{keyTy, valueTy}, TypeLevel{}, constraint->scope, TableState::Free});
806824

@@ -2062,6 +2080,8 @@ bool ConstraintSolver::tryDispatch(const UnpackConstraint& c, NotNull<const Cons
20622080
// constitute any meaningful constraint, so we replace it
20632081
// with a free type.
20642082
TypeId f = freshType(arena, builtinTypes, constraint->scope);
2083+
if (FFlag::LuauTrackInteriorFreeTypesOnScope)
2084+
trackInteriorFreeType(constraint->scope, f);
20652085
shiftReferences(resultTy, f);
20662086
emplaceType<BoundType>(asMutable(resultTy), f);
20672087
}
@@ -2197,6 +2217,11 @@ bool ConstraintSolver::tryDispatchIterableTable(TypeId iteratorTy, const Iterabl
21972217
{
21982218
TypeId keyTy = freshType(arena, builtinTypes, constraint->scope);
21992219
TypeId valueTy = freshType(arena, builtinTypes, constraint->scope);
2220+
if (FFlag::LuauTrackInteriorFreeTypesOnScope)
2221+
{
2222+
trackInteriorFreeType(constraint->scope, keyTy);
2223+
trackInteriorFreeType(constraint->scope, valueTy);
2224+
}
22002225
TypeId tableTy = arena->addType(TableType{TableState::Sealed, {}, constraint->scope});
22012226
getMutable<TableType>(tableTy)->indexer = TableIndexer{keyTy, valueTy};
22022227

@@ -2453,6 +2478,8 @@ TablePropLookupResult ConstraintSolver::lookupTableProp(
24532478
if (ttv->state == TableState::Free)
24542479
{
24552480
TypeId result = freshType(arena, builtinTypes, ttv->scope);
2481+
if (FFlag::LuauTrackInteriorFreeTypesOnScope)
2482+
trackInteriorFreeType(ttv->scope, result);
24562483
switch (context)
24572484
{
24582485
case ValueContext::RValue:
@@ -2562,6 +2589,9 @@ TablePropLookupResult ConstraintSolver::lookupTableProp(
25622589
LUAU_ASSERT(tt);
25632590
TypeId propType = freshType(arena, builtinTypes, scope);
25642591

2592+
if (FFlag::LuauTrackInteriorFreeTypesOnScope)
2593+
trackInteriorFreeType(scope, propType);
2594+
25652595
switch (context)
25662596
{
25672597
case ValueContext::RValue:

0 commit comments

Comments
 (0)