Skip to content

Commit de9f5d6

Browse files
vegorov-rbxandyfriesenhgoldsteinVighnesh-V
authored
Sync to upstream/release/664 (#1715)
As always, a weekly Luau update! This week we have further improvements to new type solver, fixing a few of the popular issues reported. The fragment autocomplete is even more stable and we believe it's ready for broader use. Aside from that we have a few general fixes/improvements: * Fixed data race when multi-threaded typechecking is used, appearing as a random crash at the end of typechecking * AST data is now available from `Luau::Module` ## New Type Solver * Fixed type refinements made by function calls which could attach `nil` as an option of a type before (Fixes #1528) * Improved bidirectional typechecking in tables (Fixes #1596) * Fixed normalization of negated types * `getmetatable()` on `any` type should no longer report an error ## Fragment Autocomplete * Fixed auto-complete suggestions being provided inside multiline comments * Fixed an assertion failure that could happen when old type solver was used * Fixed issues with missing suggestions when multiple statements are on the same line * Fixed memory safety issues ## Internal Contributors Co-authored-by: Andy Friesen <[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 640ebbc commit de9f5d6

30 files changed

+1435
-308
lines changed

Analysis/include/Luau/Clone.h

+5
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,9 @@ TypeId clone(TypeId tp, TypeArena& dest, CloneState& cloneState);
4040
TypeFun clone(const TypeFun& typeFun, TypeArena& dest, CloneState& cloneState);
4141
Binding clone(const Binding& binding, TypeArena& dest, CloneState& cloneState);
4242

43+
TypePackId cloneIncremental(TypePackId tp, TypeArena& dest, CloneState& cloneState, Scope* freshScopeForFreeTypes);
44+
TypeId cloneIncremental(TypeId typeId, TypeArena& dest, CloneState& cloneState, Scope* freshScopeForFreeTypes);
45+
TypeFun cloneIncremental(const TypeFun& typeFun, TypeArena& dest, CloneState& cloneState, Scope* freshScopeForFreeTypes);
46+
Binding cloneIncremental(const Binding& binding, TypeArena& dest, CloneState& cloneState, Scope* freshScopeForFreeTypes);
47+
4348
} // namespace Luau

Analysis/include/Luau/FragmentAutocomplete.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ struct FragmentAutocompleteResult
5757
FragmentAutocompleteAncestryResult findAncestryForFragmentParse(AstStatBlock* root, const Position& cursorPos);
5858

5959
std::optional<FragmentParseResult> parseFragment(
60-
const SourceModule& srcModule,
60+
AstStatBlock* root,
61+
AstNameTable* names,
6162
std::string_view src,
6263
const Position& cursorPos,
6364
std::optional<Position> fragmentEndPosition
@@ -98,7 +99,7 @@ struct FragmentAutocompleteStatusResult
9899
struct FragmentContext
99100
{
100101
std::string_view newSrc;
101-
const ParseResult& newAstRoot;
102+
const ParseResult& freshParse;
102103
std::optional<FrontendOptions> opts;
103104
std::optional<Position> DEPRECATED_fragmentEndPosition;
104105
};

Analysis/include/Luau/Frontend.h

+9
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ struct ModuleResolver;
3232
struct ParseResult;
3333
struct HotComment;
3434
struct BuildQueueItem;
35+
struct BuildQueueWorkState;
3536
struct FrontendCancellationToken;
3637
struct AnyTypeSummary;
3738

@@ -216,6 +217,11 @@ struct Frontend
216217
std::function<void(std::function<void()> task)> executeTask = {},
217218
std::function<bool(size_t done, size_t total)> progress = {}
218219
);
220+
std::vector<ModuleName> checkQueuedModules_DEPRECATED(
221+
std::optional<FrontendOptions> optionOverride = {},
222+
std::function<void(std::function<void()> task)> executeTask = {},
223+
std::function<bool(size_t done, size_t total)> progress = {}
224+
);
219225

220226
std::optional<CheckResult> getCheckResult(const ModuleName& name, bool accumulateNested, bool forAutocomplete = false);
221227
std::vector<ModuleName> getRequiredScripts(const ModuleName& name);
@@ -251,6 +257,9 @@ struct Frontend
251257
void checkBuildQueueItem(BuildQueueItem& item);
252258
void checkBuildQueueItems(std::vector<BuildQueueItem>& items);
253259
void recordItemResult(const BuildQueueItem& item);
260+
void performQueueItemTask(std::shared_ptr<BuildQueueWorkState> state, size_t itemPos);
261+
void sendQueueItemTask(std::shared_ptr<BuildQueueWorkState> state, size_t itemPos);
262+
void sendQueueCycleItemTask(std::shared_ptr<BuildQueueWorkState> state);
254263

255264
static LintResult classifyLints(const std::vector<LintWarning>& warnings, const Config& config);
256265

Analysis/include/Luau/Module.h

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ struct Module
9393
// Scopes and AST types refer to parse data, so we need to keep that alive
9494
std::shared_ptr<Allocator> allocator;
9595
std::shared_ptr<AstNameTable> names;
96+
AstStatBlock* root = nullptr;
9697

9798
std::vector<std::pair<Location, ScopePtr>> scopes; // never empty
9899

Analysis/include/Luau/Refinement.h

+2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct Proposition
5353
{
5454
const RefinementKey* key;
5555
TypeId discriminantTy;
56+
bool implicitFromCall;
5657
};
5758

5859
template<typename T>
@@ -69,6 +70,7 @@ struct RefinementArena
6970
RefinementId disjunction(RefinementId lhs, RefinementId rhs);
7071
RefinementId equivalence(RefinementId lhs, RefinementId rhs);
7172
RefinementId proposition(const RefinementKey* key, TypeId discriminantTy);
73+
RefinementId implicitProposition(const RefinementKey* key, TypeId discriminantTy);
7274

7375
private:
7476
TypedAllocator<Refinement> allocator;

Analysis/include/Luau/TableLiteralInference.h

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace Luau
1414
struct TypeArena;
1515
struct BuiltinTypes;
1616
struct Unifier2;
17+
struct Subtyping;
1718
class AstExpr;
1819

1920
TypeId matchLiteralType(
@@ -22,6 +23,7 @@ TypeId matchLiteralType(
2223
NotNull<BuiltinTypes> builtinTypes,
2324
NotNull<TypeArena> arena,
2425
NotNull<Unifier2> unifier,
26+
NotNull<Subtyping> subtyping,
2527
TypeId expectedType,
2628
TypeId exprType,
2729
const AstExpr* expr,

Analysis/include/Luau/Unifier2.h

+3
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ struct Unifier2
8787
bool unify(const AnyType* subAny, const TableType* superTable);
8888
bool unify(const TableType* subTable, const AnyType* superAny);
8989

90+
bool unify(const MetatableType* subMetatable, const AnyType*);
91+
bool unify(const AnyType*, const MetatableType* superMetatable);
92+
9093
// TODO think about this one carefully. We don't do unions or intersections of type packs
9194
bool unify(TypePackId subTp, TypePackId superTp);
9295

Analysis/src/AutocompleteCore.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
LUAU_FASTFLAG(LuauSolverV2)
2424
LUAU_FASTINT(LuauTypeInferIterationLimit)
2525
LUAU_FASTINT(LuauTypeInferRecursionLimit)
26+
LUAU_FASTFLAGVARIABLE(DebugLuauMagicVariableNames)
2627

2728
LUAU_FASTFLAGVARIABLE(LuauAutocompleteRefactorsForIncrementalAutocomplete)
2829

@@ -1343,6 +1344,15 @@ static AutocompleteContext autocompleteExpression(
13431344

13441345
AstNode* node = ancestry.rbegin()[0];
13451346

1347+
if (FFlag::DebugLuauMagicVariableNames)
1348+
{
1349+
InternalErrorReporter ice;
1350+
if (auto local = node->as<AstExprLocal>(); local && local->local->name == "_luau_autocomplete_ice")
1351+
ice.ice("_luau_autocomplete_ice encountered", local->location);
1352+
if (auto global = node->as<AstExprGlobal>(); global && global->name == "_luau_autocomplete_ice")
1353+
ice.ice("_luau_autocomplete_ice encountered", global->location);
1354+
}
1355+
13461356
if (node->is<AstExprIndexName>())
13471357
{
13481358
if (auto it = module.astTypes.find(node->asExpr()))

Analysis/src/Clone.cpp

+172-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "Luau/Type.h"
66
#include "Luau/TypePack.h"
77
#include "Luau/Unifiable.h"
8+
#include "Luau/VisitType.h"
89

910
LUAU_FASTFLAG(LuauSolverV2)
1011
LUAU_FASTFLAG(LuauFreezeIgnorePersistent)
@@ -28,6 +29,8 @@ const T* get(const Kind& kind)
2829

2930
class TypeCloner
3031
{
32+
33+
protected:
3134
NotNull<TypeArena> arena;
3235
NotNull<BuiltinTypes> builtinTypes;
3336

@@ -62,6 +65,8 @@ class TypeCloner
6265
{
6366
}
6467

68+
virtual ~TypeCloner() = default;
69+
6570
TypeId clone(TypeId ty)
6671
{
6772
shallowClone(ty);
@@ -120,6 +125,7 @@ class TypeCloner
120125
}
121126
}
122127

128+
protected:
123129
std::optional<TypeId> find(TypeId ty) const
124130
{
125131
ty = follow(ty, FollowOption::DisableLazyTypeThunks);
@@ -154,7 +160,7 @@ class TypeCloner
154160
}
155161

156162
public:
157-
TypeId shallowClone(TypeId ty)
163+
virtual TypeId shallowClone(TypeId ty)
158164
{
159165
// We want to [`Luau::follow`] but without forcing the expansion of [`LazyType`]s.
160166
ty = follow(ty, FollowOption::DisableLazyTypeThunks);
@@ -181,7 +187,7 @@ class TypeCloner
181187
return target;
182188
}
183189

184-
TypePackId shallowClone(TypePackId tp)
190+
virtual TypePackId shallowClone(TypePackId tp)
185191
{
186192
tp = follow(tp);
187193

@@ -469,6 +475,78 @@ class TypeCloner
469475
}
470476
};
471477

478+
class FragmentAutocompleteTypeCloner final : public TypeCloner
479+
{
480+
Scope* freeTypeReplacementScope = nullptr;
481+
482+
public:
483+
FragmentAutocompleteTypeCloner(
484+
NotNull<TypeArena> arena,
485+
NotNull<BuiltinTypes> builtinTypes,
486+
NotNull<SeenTypes> types,
487+
NotNull<SeenTypePacks> packs,
488+
TypeId forceTy,
489+
TypePackId forceTp,
490+
Scope* freeTypeReplacementScope
491+
)
492+
: TypeCloner(arena, builtinTypes, types, packs, forceTy, forceTp)
493+
, freeTypeReplacementScope(freeTypeReplacementScope)
494+
{
495+
LUAU_ASSERT(freeTypeReplacementScope);
496+
}
497+
498+
TypeId shallowClone(TypeId ty) override
499+
{
500+
// We want to [`Luau::follow`] but without forcing the expansion of [`LazyType`]s.
501+
ty = follow(ty, FollowOption::DisableLazyTypeThunks);
502+
503+
if (auto clone = find(ty))
504+
return *clone;
505+
else if (ty->persistent && (!FFlag::LuauFreezeIgnorePersistent || ty != forceTy))
506+
return ty;
507+
508+
TypeId target = arena->addType(ty->ty);
509+
asMutable(target)->documentationSymbol = ty->documentationSymbol;
510+
511+
if (auto generic = getMutable<GenericType>(target))
512+
generic->scope = nullptr;
513+
else if (auto free = getMutable<FreeType>(target))
514+
{
515+
free->scope = freeTypeReplacementScope;
516+
}
517+
else if (auto fn = getMutable<FunctionType>(target))
518+
fn->scope = nullptr;
519+
else if (auto table = getMutable<TableType>(target))
520+
table->scope = nullptr;
521+
522+
(*types)[ty] = target;
523+
queue.emplace_back(target);
524+
return target;
525+
}
526+
527+
TypePackId shallowClone(TypePackId tp) override
528+
{
529+
tp = follow(tp);
530+
531+
if (auto clone = find(tp))
532+
return *clone;
533+
else if (tp->persistent && (!FFlag::LuauFreezeIgnorePersistent || tp != forceTp))
534+
return tp;
535+
536+
TypePackId target = arena->addTypePack(tp->ty);
537+
538+
if (auto generic = getMutable<GenericTypePack>(target))
539+
generic->scope = nullptr;
540+
else if (auto free = getMutable<FreeTypePack>(target))
541+
free->scope = freeTypeReplacementScope;
542+
543+
(*packs)[tp] = target;
544+
queue.emplace_back(target);
545+
return target;
546+
}
547+
};
548+
549+
472550
} // namespace
473551

474552
TypePackId shallowClone(TypePackId tp, TypeArena& dest, CloneState& cloneState, bool ignorePersistent)
@@ -564,4 +642,96 @@ Binding clone(const Binding& binding, TypeArena& dest, CloneState& cloneState)
564642
return b;
565643
}
566644

645+
TypePackId cloneIncremental(TypePackId tp, TypeArena& dest, CloneState& cloneState, Scope* freshScopeForFreeTypes)
646+
{
647+
if (tp->persistent)
648+
return tp;
649+
650+
FragmentAutocompleteTypeCloner cloner{
651+
NotNull{&dest},
652+
cloneState.builtinTypes,
653+
NotNull{&cloneState.seenTypes},
654+
NotNull{&cloneState.seenTypePacks},
655+
nullptr,
656+
nullptr,
657+
freshScopeForFreeTypes
658+
};
659+
return cloner.clone(tp);
660+
}
661+
662+
TypeId cloneIncremental(TypeId typeId, TypeArena& dest, CloneState& cloneState, Scope* freshScopeForFreeTypes)
663+
{
664+
if (typeId->persistent)
665+
return typeId;
666+
667+
FragmentAutocompleteTypeCloner cloner{
668+
NotNull{&dest},
669+
cloneState.builtinTypes,
670+
NotNull{&cloneState.seenTypes},
671+
NotNull{&cloneState.seenTypePacks},
672+
nullptr,
673+
nullptr,
674+
freshScopeForFreeTypes
675+
};
676+
return cloner.clone(typeId);
677+
}
678+
679+
TypeFun cloneIncremental(const TypeFun& typeFun, TypeArena& dest, CloneState& cloneState, Scope* freshScopeForFreeTypes)
680+
{
681+
FragmentAutocompleteTypeCloner cloner{
682+
NotNull{&dest},
683+
cloneState.builtinTypes,
684+
NotNull{&cloneState.seenTypes},
685+
NotNull{&cloneState.seenTypePacks},
686+
nullptr,
687+
nullptr,
688+
freshScopeForFreeTypes
689+
};
690+
691+
TypeFun copy = typeFun;
692+
693+
for (auto& param : copy.typeParams)
694+
{
695+
param.ty = cloner.clone(param.ty);
696+
697+
if (param.defaultValue)
698+
param.defaultValue = cloner.clone(*param.defaultValue);
699+
}
700+
701+
for (auto& param : copy.typePackParams)
702+
{
703+
param.tp = cloner.clone(param.tp);
704+
705+
if (param.defaultValue)
706+
param.defaultValue = cloner.clone(*param.defaultValue);
707+
}
708+
709+
copy.type = cloner.clone(copy.type);
710+
711+
return copy;
712+
}
713+
714+
Binding cloneIncremental(const Binding& binding, TypeArena& dest, CloneState& cloneState, Scope* freshScopeForFreeTypes)
715+
{
716+
FragmentAutocompleteTypeCloner cloner{
717+
NotNull{&dest},
718+
cloneState.builtinTypes,
719+
NotNull{&cloneState.seenTypes},
720+
NotNull{&cloneState.seenTypePacks},
721+
nullptr,
722+
nullptr,
723+
freshScopeForFreeTypes
724+
};
725+
726+
Binding b;
727+
b.deprecated = binding.deprecated;
728+
b.deprecatedSuggestion = binding.deprecatedSuggestion;
729+
b.documentationSymbol = binding.documentationSymbol;
730+
b.location = binding.location;
731+
b.typeId = cloner.clone(binding.typeId);
732+
733+
return b;
734+
}
735+
736+
567737
} // namespace Luau

0 commit comments

Comments
 (0)