Skip to content

Commit 55f3e00

Browse files
vegorov-rbxandyfriesenannieetangaatxehgoldstein
authored
Sync to upstream/release/687 (#1954)
## What's Changed? This week we have an update with an implementation for one of the RFCs we had approved before, an improvement of the new type solver and a small Lua 5.1 C API compatibility improvement. * `@deprecated` attribute can now have a custom suggestion for a replacement and a reason message as described in [deprecated attribute parameters RFC](https://rfcs.luau.org/syntax-attribute-functions-deprecated.html) For example: ```luau @[deprecated {reason = "foo suffers from performance issues", use = "bar"}] local function foo() ... end -- Function 'foo' is deprecated, use 'bar' instead. foo suffers from performance issues foo() ``` * `lua_cpcall` C API function has been restored both for compatibility with Lua 5.1 and as a safe way to enter protected call environment to work with Luau C API functions that may error Instead of ``` if (!lua_checkstack(L, 2)) return -1; lua_pushcfunction(L, test, nullptr); lua_pushlightuserdata(L, context); int status = lua_pcall(L, 1, 0, 0); ``` you can simply do ``` int status = lua_cpcall(L, test, context); ``` * In Luau CLI, required module return values can now have any type ## New Type Solver - Additional improvements on type refinements used with external types should fix some reported false positive errors where types refined to `never` - Fixed an issue in recursive refinement types in a form of `t1 where t1 = refine<t1, _>` getting 'stuck' - Fixed an issue in subtyping of generic functions, it is now possible to assign `<T>(T, (T) -> T) -> T` to `(number, <X>(X) -> X) -> number` - Fixed an ICE caused by recursive types (Fixes #1686) - Added additional iteration and recursion limits to stop the type solver before system resources are used up ## Internal Contributors Co-authored-by: Andy Friesen <[email protected]> Co-authored-by: Annie Tang <[email protected]> Co-authored-by: Ariel Weiss <[email protected]> Co-authored-by: Hunter Goldstein <[email protected]> Co-authored-by: Ilya Rezvov <[email protected]> Co-authored-by: Sora Kanosue <[email protected]> Co-authored-by: Vighnesh Vijay <[email protected]> Co-authored-by: Vyacheslav Egorov <[email protected]>
1 parent 8863bfc commit 55f3e00

File tree

99 files changed

+4041
-1427
lines changed

Some content is hidden

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

99 files changed

+4041
-1427
lines changed

Analysis/include/Luau/Constraint.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ struct GeneralizationConstraint
5252

5353
std::vector<TypeId> interiorTypes;
5454
bool hasDeprecatedAttribute = false;
55+
AstAttr::DeprecatedInfo deprecatedInfo;
5556

5657
/// If true, never introduce generics. Always replace free types by their
5758
/// bounds or unknown. Presently used only to generalize the whole module.

Analysis/include/Luau/Error.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,15 @@ struct MultipleNonviableOverloads
504504
bool operator==(const MultipleNonviableOverloads& rhs) const;
505505
};
506506

507+
// Error where a type alias violates the recursive restraint, ie when a type alias T<A> has T with different arguments on the RHS.
508+
struct RecursiveRestraintViolation
509+
{
510+
bool operator==(const RecursiveRestraintViolation& rhs) const
511+
{
512+
return true;
513+
}
514+
};
515+
507516
using TypeErrorData = Variant<
508517
TypeMismatch,
509518
UnknownSymbol,
@@ -559,7 +568,8 @@ using TypeErrorData = Variant<
559568
CannotCheckDynamicStringFormatCalls,
560569
GenericTypeCountMismatch,
561570
GenericTypePackCountMismatch,
562-
MultipleNonviableOverloads>;
571+
MultipleNonviableOverloads,
572+
RecursiveRestraintViolation>;
563573

564574
struct TypeErrorSummary
565575
{

Analysis/include/Luau/Frontend.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ struct Frontend
176176

177177
Frontend(FileResolver* fileResolver, ConfigResolver* configResolver, const FrontendOptions& options = {});
178178

179-
void setLuauSolverSelectionFromWorkspace(SolverMode mode);
179+
void setLuauSolverMode(SolverMode mode);
180180
SolverMode getLuauSolverMode() const;
181181
// The default value assuming there is no workspace setup yet
182182
std::atomic<SolverMode> useNewLuauSolver{FFlag::LuauSolverV2 ? SolverMode::New : SolverMode::Old};
@@ -330,7 +330,7 @@ ModulePtr check(
330330
NotNull<InternalErrorReporter> iceHandler,
331331
NotNull<ModuleResolver> moduleResolver,
332332
NotNull<FileResolver> fileResolver,
333-
const ScopePtr& globalScope,
333+
const ScopePtr& parentScope,
334334
const ScopePtr& typeFunctionScope,
335335
std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope,
336336
FrontendOptions options,

Analysis/include/Luau/Scope.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ struct Scope
102102
std::optional<std::vector<TypeId>> interiorFreeTypes;
103103
std::optional<std::vector<TypePackId>> interiorFreeTypePacks;
104104

105+
// A set of type alias names that are invalid because they violate the recursion restrictions of type aliases.
106+
DenseHashSet<std::string> invalidTypeAliasNames{""};
107+
bool isInvalidTypeAliasName(const std::string& name) const;
108+
105109
NotNull<Scope> findNarrowestScopeContaining(Location);
106110
};
107111

Analysis/include/Luau/Substitution.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ struct TarjanWorklistVertex
6666
int index;
6767
int currEdge;
6868
int lastEdge;
69+
70+
TarjanWorklistVertex(int index, int currEdge, int lastEdge)
71+
: index(index)
72+
, currEdge(currEdge)
73+
, lastEdge(lastEdge)
74+
{
75+
}
6976
};
7077

7178
struct TarjanNode
@@ -79,6 +86,15 @@ struct TarjanNode
7986
// Tarjan calculates the lowlink for each vertex,
8087
// which is the lowest ancestor index reachable from the vertex.
8188
int lowlink;
89+
90+
TarjanNode(TypeId ty, TypePackId tp, bool onStack, bool dirty, int lowlink)
91+
: ty(ty)
92+
, tp(tp)
93+
, onStack(onStack)
94+
, dirty(dirty)
95+
, lowlink(lowlink)
96+
{
97+
}
8298
};
8399

84100
// Tarjan's algorithm for finding the SCCs in a cyclic structure.

Analysis/include/Luau/Subtyping.h

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ struct SubtypingResult
8888
struct SubtypingEnvironment
8989
{
9090
struct GenericBounds
91+
{
92+
TypeIds lowerBound;
93+
TypeIds upperBound;
94+
};
95+
96+
// TODO: Clip with LuauSubtypingGenericsDoesntUseVariance
97+
struct GenericBounds_DEPRECATED
9198
{
9299
DenseHashSet<TypeId> lowerBound{nullptr};
93100
DenseHashSet<TypeId> upperBound{nullptr};
@@ -98,22 +105,36 @@ struct SubtypingEnvironment
98105

99106
/// Applies `mappedGenerics` to the given type.
100107
/// This is used specifically to substitute for generics in type function instances.
101-
std::optional<TypeId> applyMappedGenerics(NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, TypeId ty);
108+
std::optional<TypeId> applyMappedGenerics(
109+
NotNull<BuiltinTypes> builtinTypes,
110+
NotNull<TypeArena> arena,
111+
TypeId ty,
112+
NotNull<InternalErrorReporter> iceReporter
113+
);
114+
// TODO: Clip with LuauSubtypingGenericsDoesntUseVariance
115+
std::optional<TypeId> applyMappedGenerics_DEPRECATED(NotNull<BuiltinTypes> builtinTypes, NotNull<TypeArena> arena, TypeId ty);
102116

103117
const TypeId* tryFindSubstitution(TypeId ty) const;
118+
// TODO: Clip with LuauSubtypingGenericsDoesntUseVariance
104119
const SubtypingResult* tryFindSubtypingResult(std::pair<TypeId, TypeId> subAndSuper) const;
105120

106121
bool containsMappedType(TypeId ty) const;
107122
bool containsMappedPack(TypePackId tp) const;
108123

109-
GenericBounds& getMappedTypeBounds(TypeId ty);
124+
GenericBounds& getMappedTypeBounds(TypeId ty, NotNull<InternalErrorReporter> iceReporter);
125+
// TODO: Clip with LuauSubtypingGenericsDoesntUseVariance
126+
GenericBounds_DEPRECATED& getMappedTypeBounds_DEPRECATED(TypeId ty);
110127
TypePackId* getMappedPackBounds(TypePackId tp);
111128

112129
/*
113130
* When we encounter a generic over the course of a subtyping test, we need
114-
* to tentatively map that generic onto a type on the other side.
131+
* to tentatively map that generic onto a type on the other side. We map to a
132+
* vector of bounds, since generics may be shadowed by nested types. The back
133+
* of each vector represents the current scope.
115134
*/
116-
DenseHashMap<TypeId, GenericBounds> mappedGenerics{nullptr};
135+
DenseHashMap<TypeId, std::vector<GenericBounds>> mappedGenerics{nullptr};
136+
// TODO: Clip with LuauSubtypingGenericsDoesntUseVariance
137+
DenseHashMap<TypeId, GenericBounds_DEPRECATED> mappedGenerics_DEPRECATED{nullptr};
117138
DenseHashMap<TypePackId, TypePackId> mappedGenericPacks{nullptr};
118139

119140
/*
@@ -124,7 +145,14 @@ struct SubtypingEnvironment
124145
*/
125146
DenseHashMap<TypeId, TypeId> substitutions{nullptr};
126147

148+
// TODO: Clip with LuauSubtypingGenericsDoesntUseVariance
127149
DenseHashMap<std::pair<TypeId, TypeId>, SubtypingResult, TypePairHash> ephemeralCache{{}};
150+
151+
// We use this cache to track pairs of subtypes that we tried to subtype, and found them to be in the seen set at the time.
152+
// In those situations, we return True, but mark the result as not cacheable, because we don't want to cache broader results which
153+
// led to the seen pair. However, those results were previously being cache in the ephemeralCache, and we still want to cache them somewhere
154+
// for performance reasons.
155+
DenseHashMap<std::pair<TypeId, TypeId>, SubtypingResult, TypePairHash> seenSetCache{{}};
128156
};
129157

130158
struct Subtyping
@@ -144,6 +172,7 @@ struct Subtyping
144172
Contravariant
145173
};
146174

175+
// TODO: Clip this along with LuauSubtypingGenericsDoesntUseVariance?
147176
Variance variance = Variance::Covariant;
148177

149178
using SeenSet = Set<std::pair<TypeId, TypeId>, TypePairHash>;
@@ -178,7 +207,12 @@ struct Subtyping
178207
// TODO recursion limits
179208

180209
SubtypingResult isSubtype(TypeId subTy, TypeId superTy, NotNull<Scope> scope);
181-
SubtypingResult isSubtype(TypePackId subTy, TypePackId superTy, NotNull<Scope> scope);
210+
SubtypingResult isSubtype(
211+
TypePackId subTp,
212+
TypePackId superTp,
213+
NotNull<Scope> scope,
214+
std::optional<std::vector<TypeId>> bindableGenerics = std::nullopt
215+
);
182216

183217
private:
184218
DenseHashMap<std::pair<TypeId, TypeId>, SubtypingResult, TypePairHash> resultCache{{}};
@@ -323,6 +357,16 @@ struct Subtyping
323357
TypeId superTy,
324358
NotNull<Scope> scope,
325359
SubtypingResult& original);
360+
361+
SubtypingResult checkGenericBounds(const SubtypingEnvironment::GenericBounds& bounds, SubtypingEnvironment& env, NotNull<Scope> scope);
362+
363+
static void maybeUpdateBounds(
364+
TypeId here,
365+
TypeId there,
366+
TypeIds& boundsToUpdate,
367+
const TypeIds& firstBoundsToCheck,
368+
const TypeIds& secondBoundsToCheck
369+
);
326370
};
327371

328372
} // namespace Luau

Analysis/include/Luau/SubtypingVariance.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,9 @@ namespace Luau
77

88
enum class SubtypingVariance
99
{
10-
// Used for an empty key. Should never appear in actual code.
10+
// Useful for an empty hash table key. Should never arise from actual code.
1111
Invalid,
1212
Covariant,
13-
// This is used to identify cases where we have a covariant + a
14-
// contravariant reason and we need to merge them.
1513
Contravariant,
1614
Invariant,
1715
};

Analysis/include/Luau/Transpiler.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "Luau/Location.h"
55
#include "Luau/ParseOptions.h"
6+
#include "Luau/ParseResult.h"
67

78
#include <string>
89

@@ -24,6 +25,7 @@ void dump(AstNode* node);
2425
// Never fails on a well-formed AST
2526
std::string transpile(AstStatBlock& ast);
2627
std::string transpileWithTypes(AstStatBlock& block);
28+
std::string transpileWithTypes(AstStatBlock &block, const CstNodeMap& cstNodeMap);
2729

2830
// Only fails when parsing fails
2931
TranspileResult transpile(std::string_view source, ParseOptions options = ParseOptions{}, bool withTypes = false);

Analysis/include/Luau/Type.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ struct FunctionType
391391
bool hasNoFreeOrGenericTypes = false;
392392
bool isCheckedFunction = false;
393393
bool isDeprecatedFunction = false;
394+
std::shared_ptr<AstAttr::DeprecatedInfo> deprecatedInfo;
394395
};
395396

396397
enum class TableState

Analysis/include/Luau/TypeIds.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class TypeIds
5252
bool empty() const;
5353
size_t count(TypeId ty) const;
5454

55+
void reserve(size_t n);
56+
5557
template<class Iterator>
5658
void insert(Iterator begin, Iterator end)
5759
{

0 commit comments

Comments
 (0)