Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/Analysis/include/Luau/ConstraintGenerator.h
2727 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#pragma once
3
4
#include "Luau/Ast.h"
5
#include "Luau/Constraint.h"
6
#include "Luau/ConstraintSet.h"
7
#include "Luau/ControlFlow.h"
8
#include "Luau/DataFlowGraph.h"
9
#include "Luau/HashUtil.h"
10
#include "Luau/InsertionOrderedMap.h"
11
#include "Luau/Module.h"
12
#include "Luau/ModuleResolver.h"
13
#include "Luau/NotNull.h"
14
#include "Luau/Polarity.h"
15
#include "Luau/Refinement.h"
16
#include "Luau/Set.h"
17
#include "Luau/Symbol.h"
18
#include "Luau/TypeFwd.h"
19
#include "Luau/TypeIds.h"
20
#include "Luau/TypeUtils.h"
21
22
#include <memory>
23
#include <vector>
24
25
namespace Luau
26
{
27
28
struct Scope;
29
using ScopePtr = std::shared_ptr<Scope>;
30
31
struct DcrLogger;
32
struct TypeFunctionRuntime;
33
34
struct Inference
35
{
36
TypeId ty = nullptr;
37
RefinementId refinement = nullptr;
38
39
Inference() = default;
40
41
explicit Inference(TypeId ty, RefinementId refinement = nullptr)
42
: ty(ty)
43
, refinement(refinement)
44
{
45
}
46
};
47
48
struct InferencePack
49
{
50
TypePackId tp = nullptr;
51
std::vector<RefinementId> refinements;
52
53
InferencePack() = default;
54
55
explicit InferencePack(TypePackId tp, const std::vector<RefinementId>& refinements = {})
56
: tp(tp)
57
, refinements(refinements)
58
{
59
}
60
};
61
62
struct Checkpoint
63
{
64
size_t offset = 0;
65
};
66
67
struct ConstraintGenerator
68
{
69
// A list of all the scopes in the module. This vector holds ownership of the
70
// scope pointers; the scopes themselves borrow pointers to other scopes to
71
// define the scope hierarchy.
72
std::vector<std::pair<Location, ScopePtr>> scopes;
73
74
ModulePtr module;
75
NotNull<BuiltinTypes> builtinTypes;
76
const NotNull<TypeArena> arena;
77
// The root scope of the module we're generating constraints for.
78
// This is null when the CG is initially constructed.
79
Scope* rootScope;
80
81
TypeContext typeContext = TypeContext::Default;
82
83
struct InferredBinding
84
{
85
Scope* scope;
86
Location location;
87
TypeIds types;
88
};
89
90
// Some locals have multiple type states. We wish for Scope::bindings to
91
// map each local name onto the union of every type that the local can have
92
// over its lifetime, so we use this map to accumulate the set of types it
93
// might have.
94
//
95
// See the functions recordInferredBinding and fillInInferredBindings.
96
DenseHashMap<Symbol, InferredBinding> inferredBindings{{}};
97
98
// Constraints that go straight to the solver.
99
std::vector<ConstraintPtr> constraints;
100
101
// The set of all free types introduced during constraint generation.
102
TypeIds freeTypes;
103
104
// Map a function's signature scope back to its signature type.
105
DenseHashMap<Scope*, TypeId> scopeToFunction{nullptr};
106
107
// The private scope of type aliases for which the type parameters belong to.
108
DenseHashMap<const AstStatTypeAlias*, ScopePtr> astTypeAliasDefiningScopes{nullptr};
109
110
NotNull<const DataFlowGraph> dfg;
111
RefinementArena refinementArena;
112
113
int recursionCount = 0;
114
115
// It is pretty uncommon for constraint generation to itself produce errors, but it can happen.
116
std::vector<TypeError> errors;
117
118
// Needed to be able to enable error-suppression preservation for immediate refinements.
119
NotNull<Normalizer> normalizer;
120
121
// Needed to register all available type functions for execution at later stages.
122
NotNull<TypeFunctionRuntime> typeFunctionRuntime;
123
DenseHashMap<const AstStatTypeFunction*, ScopePtr> astTypeFunctionEnvironmentScopes{nullptr};
124
125
// Needed to resolve modules to make 'require' import types properly.
126
NotNull<ModuleResolver> moduleResolver;
127
// Occasionally constraint generation needs to produce an ICE.
128
const NotNull<InternalErrorReporter> ice;
129
130
ScopePtr globalScope;
131
ScopePtr typeFunctionScope;
132
133
std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope;
134
std::vector<RequireCycle> requireCycles;
135
136
DenseHashMap<TypeId, TypeIds> localTypes{nullptr};
137
138
DenseHashMap<AstExpr*, Inference> inferredExprCache{nullptr};
139
140
DcrLogger* logger;
141
142
bool recursionLimitMet = false;
143
144
ConstraintGenerator(
145
ModulePtr module,
146
NotNull<Normalizer> normalizer,
147
NotNull<TypeFunctionRuntime> typeFunctionRuntime,
148
NotNull<ModuleResolver> moduleResolver,
149
NotNull<BuiltinTypes> builtinTypes,
150
NotNull<InternalErrorReporter> ice,
151
ScopePtr globalScope,
152
ScopePtr typeFunctionScope,
153
std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope,
154
DcrLogger* logger,
155
NotNull<DataFlowGraph> dfg,
156
std::vector<RequireCycle> requireCycles
157
);
158
159
ConstraintSet run(AstStatBlock* block);
160
ConstraintSet runOnFragment(const ScopePtr& resumeScope, AstStatBlock* block);
161
162
/**
163
* The entry point to the ConstraintGenerator. This will construct a set
164
* of scopes, constraints, and free types that can be solved later.
165
* @param block the root block to generate constraints for.
166
*/
167
void visitModuleRoot(AstStatBlock* block);
168
169
void visitFragmentRoot(const ScopePtr& resumeScope, AstStatBlock* block);
170
171
private:
172
struct InteriorFreeTypes
173
{
174
std::vector<TypeId> types;
175
std::vector<TypePackId> typePacks;
176
};
177
178
std::vector<InteriorFreeTypes> interiorFreeTypes;
179
180
std::vector<TypeId> unionsToSimplify;
181
182
Set<AstName> uninitializedGlobals{{}};
183
184
Polarity polarity = Polarity::None;
185
186
DenseHashMap<std::pair<TypeId, std::string>, TypeId, PairHash<TypeId, std::string>> propIndexPairsSeen{{nullptr, ""}};
187
188
// Used to keep track of when we are inside a large table and should
189
// opt *not* to do type inference for singletons.
190
size_t largeTableDepth = 0;
191
192
/**
193
* Fabricates a new free type belonging to a given scope.
194
* @param scope the scope the free type belongs to.
195
*/
196
TypeId freshType(const ScopePtr& scope, Polarity polarity = Polarity::Unknown);
197
198
/**
199
* Fabricates a new free type pack belonging to a given scope.
200
* @param scope the scope the free type pack belongs to.
201
*/
202
TypePackId freshTypePack(const ScopePtr& scope, Polarity polarity = Polarity::Unknown);
203
204
/**
205
* Allocate a new TypePack with the given head and tail.
206
*
207
* Avoids allocating 0-length type packs:
208
*
209
* If the head is non-empty, allocate and return a type pack with the given
210
* head and tail.
211
* If the head is empty and tail is non-empty, return *tail.
212
* If both the head and tail are empty, return an empty type pack.
213
*/
214
TypePackId addTypePack(std::vector<TypeId> head, std::optional<TypePackId> tail);
215
216
/**
217
* Fabricates a scope that is a child of another scope.
218
* @param node the lexical node that the scope belongs to.
219
* @param parent the parent scope of the new scope. Must not be null.
220
*/
221
ScopePtr childScope(AstNode* node, const ScopePtr& parent);
222
223
std::optional<TypeId> lookup(const ScopePtr& scope, Location location, DefId def, bool prototype = true);
224
225
/**
226
* Adds a new constraint with no dependencies to a given scope.
227
* @param scope the scope to add the constraint to.
228
* @param cv the constraint variant to add.
229
* @return the pointer to the inserted constraint
230
*/
231
NotNull<Constraint> addConstraint(const ScopePtr& scope, const Location& location, ConstraintV cv);
232
233
/**
234
* Adds a constraint to a given scope.
235
* @param scope the scope to add the constraint to. Must not be null.
236
* @param c the constraint to add.
237
* @return the pointer to the inserted constraint
238
*/
239
NotNull<Constraint> addConstraint(const ScopePtr& scope, std::unique_ptr<Constraint> c);
240
241
struct RefinementPartition
242
{
243
// Types that we want to intersect against the type of the expression.
244
std::vector<TypeId> discriminantTypes;
245
246
// Sometimes the type we're discriminating against is implicitly nil.
247
bool shouldAppendNilType = false;
248
};
249
250
using RefinementContext = InsertionOrderedMap<DefId, RefinementPartition>;
251
void unionRefinements(
252
const ScopePtr& scope,
253
Location location,
254
const RefinementContext& lhs,
255
const RefinementContext& rhs,
256
RefinementContext& dest,
257
std::vector<ConstraintV>* constraints
258
);
259
void computeRefinement(
260
const ScopePtr& scope,
261
Location location,
262
RefinementId refinement,
263
RefinementContext* refis,
264
bool sense,
265
bool eq,
266
std::vector<ConstraintV>* constraints
267
);
268
void applyRefinements(const ScopePtr& scope, Location location, RefinementId refinement);
269
270
LUAU_NOINLINE void checkAliases(const ScopePtr& scope, AstStatBlock* block);
271
272
ControlFlow visitBlockWithoutChildScope(const ScopePtr& scope, AstStatBlock* block);
273
274
ControlFlow visit(const ScopePtr& scope, AstStat* stat);
275
ControlFlow visit(const ScopePtr& scope, AstStatBlock* block);
276
ControlFlow visit(const ScopePtr& scope, AstStatLocal* local);
277
ControlFlow visit(const ScopePtr& scope, AstStatFor* for_);
278
ControlFlow visit(const ScopePtr& scope, AstStatForIn* forIn);
279
ControlFlow visit(const ScopePtr& scope, AstStatWhile* while_);
280
ControlFlow visit(const ScopePtr& scope, AstStatRepeat* repeat);
281
ControlFlow visit(const ScopePtr& scope, AstStatLocalFunction* function);
282
ControlFlow visit(const ScopePtr& scope, AstStatFunction* function);
283
ControlFlow visit(const ScopePtr& scope, AstStatReturn* ret);
284
ControlFlow visit(const ScopePtr& scope, AstStatAssign* assign);
285
ControlFlow visit(const ScopePtr& scope, AstStatCompoundAssign* assign);
286
ControlFlow visit(const ScopePtr& scope, AstStatIf* ifStatement);
287
ControlFlow visit(const ScopePtr& scope, AstStatTypeAlias* alias);
288
ControlFlow visit(const ScopePtr& scope, AstStatTypeFunction* function);
289
ControlFlow visit(const ScopePtr& scope, AstStatDeclareGlobal* declareGlobal);
290
ControlFlow visit(const ScopePtr& scope, AstStatDeclareExternType* declareExternType);
291
ControlFlow visit(const ScopePtr& scope, AstStatDeclareFunction* declareFunction);
292
ControlFlow visit(const ScopePtr& scope, AstStatError* error);
293
294
InferencePack checkPack(const ScopePtr& scope, AstArray<AstExpr*> exprs, const std::vector<std::optional<TypeId>>& expectedTypes = {});
295
InferencePack checkPack(
296
const ScopePtr& scope,
297
AstExpr* expr,
298
const std::vector<std::optional<TypeId>>& expectedTypes = {},
299
bool generalize = true
300
);
301
302
InferencePack checkPack(const ScopePtr& scope, AstExprCall* call);
303
InferencePack checkExprCall(
304
const ScopePtr& scope,
305
AstExprCall* call,
306
TypeId fnType,
307
Checkpoint funcBeginCheckpoint,
308
Checkpoint funcEndCheckpoint
309
);
310
311
/**
312
* Checks an expression that is expected to evaluate to one type.
313
* @param scope the scope the expression is contained within.
314
* @param expr the expression to check.
315
* @param expectedType the type of the expression that is expected from its
316
* surrounding context. Used to implement bidirectional type checking.
317
* @param generalize If true, generalize any lambdas that are encountered.
318
* @return the type of the expression.
319
*/
320
Inference check(
321
const ScopePtr& scope,
322
AstExpr* expr,
323
std::optional<TypeId> expectedType = {},
324
bool forceSingleton = false,
325
bool generalize = true
326
);
327
328
Inference check(const ScopePtr& scope, AstExprConstantString* string, std::optional<TypeId> expectedType, bool forceSingleton);
329
Inference check(const ScopePtr& scope, AstExprConstantBool* boolExpr, std::optional<TypeId> expectedType, bool forceSingleton);
330
Inference check(const ScopePtr& scope, AstExprLocal* local);
331
Inference check(const ScopePtr& scope, AstExprGlobal* global);
332
Inference checkIndexName(const ScopePtr& scope, const RefinementKey* key, AstExpr* indexee, const std::string& index, Location indexLocation);
333
Inference check(const ScopePtr& scope, AstExprIndexName* indexName);
334
Inference check(const ScopePtr& scope, AstExprIndexExpr* indexExpr);
335
Inference check(const ScopePtr& scope, AstExprFunction* func, std::optional<TypeId> expectedType, bool generalize);
336
Inference check(const ScopePtr& scope, AstExprUnary* unary);
337
Inference check(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType);
338
Inference checkAstExprBinary(
339
const ScopePtr& scope,
340
const Location& location,
341
AstExprBinary::Op op,
342
AstExpr* left,
343
AstExpr* right,
344
std::optional<TypeId> expectedType
345
);
346
Inference check(const ScopePtr& scope, AstExprIfElse* ifElse, std::optional<TypeId> expectedType);
347
Inference check(const ScopePtr& scope, AstExprTypeAssertion* typeAssert);
348
Inference check(const ScopePtr& scope, AstExprInterpString* interpString);
349
Inference check(const ScopePtr& scope, AstExprInstantiate* explicitTypeInstantiation);
350
Inference check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType);
351
std::tuple<TypeId, TypeId, RefinementId> checkBinary(
352
const ScopePtr& scope,
353
AstExprBinary::Op op,
354
AstExpr* left,
355
AstExpr* right,
356
std::optional<TypeId> expectedType
357
);
358
359
void visitLValue(const ScopePtr& scope, AstExpr* expr, TypeId rhsType);
360
void visitLValue(const ScopePtr& scope, AstExprLocal* local, TypeId rhsType);
361
void visitLValue(const ScopePtr& scope, AstExprGlobal* global, TypeId rhsType);
362
void visitLValue(const ScopePtr& scope, AstExprIndexName* indexName, TypeId rhsType);
363
void visitLValue(const ScopePtr& scope, AstExprIndexExpr* indexExpr, TypeId rhsType);
364
365
struct FunctionSignature
366
{
367
// The type of the function.
368
TypeId signature;
369
// The scope that encompasses the function's signature. May be nullptr
370
// if there was no need for a signature scope (the function has no
371
// generics).
372
ScopePtr signatureScope;
373
// The scope that encompasses the function's body. Is a child scope of
374
// signatureScope, if present.
375
ScopePtr bodyScope;
376
};
377
378
FunctionSignature checkFunctionSignature(
379
const ScopePtr& parent,
380
AstExprFunction* fn,
381
std::optional<TypeId> expectedType = {},
382
std::optional<Location> originalName = {}
383
);
384
385
/**
386
* Checks the body of a function expression.
387
* @param scope the interior scope of the body of the function.
388
* @param fn the function expression to check.
389
*/
390
void checkFunctionBody(const ScopePtr& scope, AstExprFunction* fn);
391
392
// Specializations of 'resolveType' below
393
TypeId resolveReferenceType(const ScopePtr& scope, AstType* ty, AstTypeReference* ref, bool inTypeArguments, bool replaceErrorWithFresh);
394
TypeId resolveTableType(const ScopePtr& scope, AstType* ty, AstTypeTable* tab, bool inTypeArguments, bool replaceErrorWithFresh);
395
TypeId resolveFunctionType(const ScopePtr& scope, AstType* ty, AstTypeFunction* fn, bool inTypeArguments, bool replaceErrorWithFresh);
396
397
public:
398
/**
399
* Resolves a type from its AST annotation.
400
* @param scope the scope that the type annotation appears within.
401
* @param ty the AST annotation to resolve.
402
* @param inTypeArguments whether we are resolving a type that's contained within type arguments, `<...>`.
403
* @return the type of the AST annotation.
404
**/
405
TypeId resolveType(
406
const ScopePtr& scope,
407
AstType* ty,
408
bool inTypeArguments,
409
bool replaceErrorWithFresh = false,
410
Polarity initialPolarity = Polarity::Positive
411
);
412
413
private:
414
// resolveType() is recursive, but we only want to invoke
415
// inferGenericPolarities() once at the very end. We thus isolate the
416
// recursive part of the algorithm to this internal helper.
417
TypeId resolveType_(const ScopePtr& scope, AstType* ty, bool inTypeArguments, bool replaceErrorWithFresh = false);
418
419
/**
420
* Resolves a type pack from its AST annotation.
421
* @param scope the scope that the type annotation appears within.
422
* @param tp the AST annotation to resolve.
423
* @param inTypeArguments whether we are resolving a type that's contained within type arguments, `<...>`.
424
* @return the type pack of the AST annotation.
425
**/
426
TypePackId resolveTypePack(
427
const ScopePtr& scope,
428
AstTypePack* tp,
429
bool inTypeArguments,
430
bool replaceErrorWithFresh = false,
431
Polarity initialPolarity = Polarity::Positive
432
);
433
434
// Inner helper for resolveTypePack
435
TypePackId resolveTypePack_(const ScopePtr& scope, AstTypePack* tp, bool inTypeArguments, bool replaceErrorWithFresh = false);
436
437
/**
438
* Resolves a type pack from its AST annotation.
439
* @param scope the scope that the type annotation appears within.
440
* @param list the AST annotation to resolve.
441
* @param inTypeArguments whether we are resolving a type that's contained within type arguments, `<...>`.
442
* @return the type pack of the AST annotation.
443
**/
444
TypePackId resolveTypePack(
445
const ScopePtr& scope,
446
const AstTypeList& list,
447
bool inTypeArguments,
448
bool replaceErrorWithFresh = false,
449
Polarity initialPolarity = Polarity::Positive
450
);
451
452
// Clip with LuauForwardPolarityForFunctionTypes
453
TypePackId resolveTypePack_DEPRECATED(
454
const ScopePtr& scope,
455
const AstTypeList& list,
456
bool inTypeArguments,
457
bool replaceErrorWithFresh = false,
458
Polarity initialPolarity = Polarity::Positive
459
);
460
461
TypePackId resolveTypePack_(const ScopePtr& scope, const AstTypeList& list, bool inTypeArguments, bool replaceErrorWithFresh);
462
463
/**
464
* Creates generic types given a list of AST definitions, resolving default
465
* types as required.
466
* @param scope the scope that the generics should belong to.
467
* @param generics the AST generics to create types for.
468
* @param useCache whether to use the generic type cache for the given
469
* scope.
470
* @param addTypes whether to add the types to the scope's
471
* privateTypeBindings map.
472
**/
473
std::vector<std::pair<Name, GenericTypeDefinition>> createGenerics(
474
const ScopePtr& scope,
475
AstArray<AstGenericType*> generics,
476
bool useCache = false,
477
bool addTypes = true
478
);
479
480
/**
481
* Creates generic type packs given a list of AST definitions, resolving
482
* default type packs as required.
483
* @param scope the scope that the generic packs should belong to.
484
* @param generics the AST generics to create type packs for.
485
* @param useCache whether to use the generic type pack cache for the given
486
* scope.
487
* @param addTypes whether to add the types to the scope's
488
* privateTypePackBindings map.
489
**/
490
std::vector<std::pair<Name, GenericTypePackDefinition>> createGenericPacks(
491
const ScopePtr& scope,
492
AstArray<AstGenericTypePack*> generics,
493
bool useCache = false,
494
bool addTypes = true
495
);
496
497
Inference flattenPack(const ScopePtr& scope, Location location, InferencePack pack);
498
499
void reportError(Location location, TypeErrorData err);
500
void reportCodeTooComplex(Location location);
501
502
// make a union type function of these two types
503
TypeId makeUnion(const ScopePtr& scope, Location location, TypeId lhs, TypeId rhs);
504
505
// Make a union type and add it to `unionsToSimplify`, ensuring that
506
// later we will attempt to simplify this union in order to keep types
507
// small.
508
TypeId makeUnion(std::vector<TypeId> options);
509
510
// make an intersect type function of these two types
511
TypeId makeIntersect(const ScopePtr& scope, Location location, TypeId lhs, TypeId rhs);
512
void prepopulateGlobalScopeForFragmentTypecheck(const ScopePtr& globalScope, const ScopePtr& resumeScope, AstStatBlock* program);
513
514
/** Scan the program for global definitions.
515
*
516
* ConstraintGenerator needs to differentiate between globals and accesses to undefined symbols. Doing this "for
517
* real" in a general way is going to be pretty hard, so we are choosing not to tackle that yet. For now, we do an
518
* initial scan of the AST and note what globals are defined.
519
*/
520
void prepopulateGlobalScope(const ScopePtr& globalScope, AstStatBlock* program);
521
522
bool recordPropertyAssignment(TypeId ty);
523
524
// Record the fact that a particular local has a particular type in at least
525
// one of its states.
526
void recordInferredBinding(AstLocal* local, TypeId ty);
527
528
void fillInInferredBindings(const ScopePtr& globalScope, AstStatBlock* block);
529
530
std::pair<std::vector<TypeId>, std::vector<TypePackId>> resolveTypeArguments(const ScopePtr& scope, const AstArray<AstTypeOrPack>& typeArguments);
531
532
/** Given a function type annotation, return a vector describing the expected types of the calls to the function
533
* For example, calling a function with annotation ((number) -> string & ((string) -> number))
534
* yields a vector of size 1, with value: [number | string]
535
*/
536
std::vector<std::optional<TypeId>> getExpectedCallTypesForFunctionOverloads(const TypeId fnType);
537
538
TypeId createTypeFunctionInstance(
539
const TypeFunction& function,
540
std::vector<TypeId> typeArguments,
541
std::vector<TypePackId> packArguments,
542
const ScopePtr& scope,
543
Location location
544
);
545
546
TypeId simplifyUnion(const ScopePtr& scope, Location location, TypeId left, TypeId right);
547
548
void updateRValueRefinements(const ScopePtr& scope, DefId def, TypeId ty) const;
549
void updateRValueRefinements(Scope* scope, DefId def, TypeId ty) const;
550
void resolveGenericDefaultParameters(const ScopePtr& defnScope, AstStatTypeAlias* alias, const TypeFun& fun);
551
};
552
553
} // namespace Luau
554
555