Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/Analysis/src/ConstraintGenerator.cpp
2725 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#include "Luau/ConstraintGenerator.h"
3
4
#include "Luau/Ast.h"
5
#include "Luau/BuiltinDefinitions.h"
6
#include "Luau/BuiltinTypeFunctions.h"
7
#include "Luau/Common.h"
8
#include "Luau/Constraint.h"
9
#include "Luau/ControlFlow.h"
10
#include "Luau/DcrLogger.h"
11
#include "Luau/Def.h"
12
#include "Luau/DenseHash.h"
13
#include "Luau/IterativeTypeVisitor.h"
14
#include "Luau/ModuleResolver.h"
15
#include "Luau/Normalize.h"
16
#include "Luau/NotNull.h"
17
#include "Luau/RecursionCounter.h"
18
#include "Luau/Refinement.h"
19
#include "Luau/Scope.h"
20
#include "Luau/Simplify.h"
21
#include "Luau/StringUtils.h"
22
#include "Luau/Subtyping.h"
23
#include "Luau/TimeTrace.h"
24
#include "Luau/Type.h"
25
#include "Luau/TypeFunction.h"
26
#include "Luau/TypeFunctionError.h"
27
#include "Luau/TypePack.h"
28
#include "Luau/TypeUtils.h"
29
#include "Luau/Unifier2.h"
30
#include "Luau/VisitType.h"
31
32
#include <algorithm>
33
#include <memory>
34
35
LUAU_DYNAMIC_FASTINTVARIABLE(LuauConstraintGeneratorRecursionLimit, 300)
36
37
LUAU_FASTINT(LuauCheckRecursionLimit)
38
LUAU_FASTFLAG(DebugLuauLogSolverToJson)
39
LUAU_FASTFLAG(DebugLuauMagicTypes)
40
LUAU_FASTINTVARIABLE(LuauPrimitiveInferenceInTableLimit, 500)
41
LUAU_FASTFLAG(LuauExplicitTypeInstantiationSupport)
42
LUAU_FASTFLAGVARIABLE(LuauPropagateTypeAnnotationsInForInLoops)
43
LUAU_FASTFLAGVARIABLE(LuauDontIncludeVarargWithAnnotation)
44
LUAU_FASTFLAGVARIABLE(LuauDisallowRedefiningBuiltinTypes)
45
LUAU_FASTFLAGVARIABLE(LuauUnpackRespectsAnnotations)
46
LUAU_FASTFLAG(LuauCaptureRecursiveCallsForTablesAndGlobals2)
47
LUAU_FASTFLAGVARIABLE(LuauForwardPolarityForFunctionTypes)
48
LUAU_FASTFLAG(LuauTypeFunctionStructuredErrors)
49
LUAU_FASTFLAGVARIABLE(LuauKeepExplicitMapForGlobalTypes2)
50
LUAU_FASTFLAGVARIABLE(LuauRefinementTypeVector)
51
LUAU_FASTFLAG(LuauExternReadWriteAttributes)
52
53
namespace Luau
54
{
55
56
bool doesCallError(const AstExprCall* call); // TypeInfer.cpp
57
const AstStat* getFallthrough(const AstStat* node); // TypeInfer.cpp
58
59
static std::optional<AstExpr*> matchRequire(const AstExprCall& call)
60
{
61
const char* require = "require";
62
63
if (call.args.size != 1)
64
return std::nullopt;
65
66
const AstExprGlobal* funcAsGlobal = call.func->as<AstExprGlobal>();
67
if (!funcAsGlobal || funcAsGlobal->name != require)
68
return std::nullopt;
69
70
if (call.args.size != 1)
71
return std::nullopt;
72
73
return call.args.data[0];
74
}
75
76
struct TypeGuard
77
{
78
bool isTypeof;
79
AstExpr* target;
80
std::string type;
81
};
82
83
static std::optional<TypeGuard> matchTypeGuard(const AstExprBinary::Op op, AstExpr* left, AstExpr* right)
84
{
85
if (op != AstExprBinary::CompareEq && op != AstExprBinary::CompareNe)
86
return std::nullopt;
87
88
if (right->is<AstExprCall>())
89
std::swap(left, right);
90
91
if (!right->is<AstExprConstantString>())
92
return std::nullopt;
93
94
AstExprCall* call = left->as<AstExprCall>();
95
AstExprConstantString* string = right->as<AstExprConstantString>();
96
if (!call || !string)
97
return std::nullopt;
98
99
AstExprGlobal* callee = call->func->as<AstExprGlobal>();
100
if (!callee)
101
return std::nullopt;
102
103
if (callee->name != "type" && callee->name != "typeof")
104
return std::nullopt;
105
106
if (call->args.size != 1)
107
return std::nullopt;
108
109
return TypeGuard{
110
/*isTypeof*/ callee->name == "typeof",
111
/*target*/ call->args.data[0],
112
/*type*/ std::string(string->value.data, string->value.size),
113
};
114
}
115
116
namespace
117
{
118
119
Checkpoint checkpoint(const ConstraintGenerator* cg)
120
{
121
return Checkpoint{cg->constraints.size()};
122
}
123
124
template<typename F>
125
void forEachConstraint(const Checkpoint& start, const Checkpoint& end, const ConstraintGenerator* cg, F f)
126
{
127
for (size_t i = start.offset; i < end.offset; ++i)
128
f(cg->constraints[i]);
129
}
130
131
struct HasFreeType : TypeOnceVisitor
132
{
133
bool result = false;
134
135
HasFreeType()
136
: TypeOnceVisitor("TypeOnceVisitor", /* skipBoundTypes */ true)
137
{
138
}
139
140
bool visit(TypeId ty) override
141
{
142
if (result || ty->persistent)
143
return false;
144
return true;
145
}
146
147
bool visit(TypePackId tp) override
148
{
149
if (result)
150
return false;
151
return true;
152
}
153
154
bool visit(TypeId ty, const ExternType&) override
155
{
156
return false;
157
}
158
159
bool visit(TypeId ty, const FreeType&) override
160
{
161
result = true;
162
return false;
163
}
164
165
bool visit(TypePackId ty, const FreeTypePack&) override
166
{
167
result = true;
168
return false;
169
}
170
};
171
172
bool hasFreeType(TypeId ty)
173
{
174
HasFreeType hft{};
175
hft.traverse(ty);
176
return hft.result;
177
}
178
179
struct GlobalNameCollector : public AstVisitor
180
{
181
DenseHashSet<AstName> names;
182
183
GlobalNameCollector()
184
: names(AstName())
185
{
186
}
187
188
bool visit(AstExprGlobal* node) override
189
{
190
names.insert(node->name);
191
return true;
192
}
193
};
194
195
} // namespace
196
197
ConstraintGenerator::ConstraintGenerator(
198
ModulePtr module,
199
NotNull<Normalizer> normalizer,
200
NotNull<TypeFunctionRuntime> typeFunctionRuntime,
201
NotNull<ModuleResolver> moduleResolver,
202
NotNull<BuiltinTypes> builtinTypes,
203
NotNull<InternalErrorReporter> ice,
204
ScopePtr globalScope,
205
ScopePtr typeFunctionScope,
206
std::function<void(const ModuleName&, const ScopePtr&)> prepareModuleScope,
207
DcrLogger* logger,
208
NotNull<DataFlowGraph> dfg,
209
std::vector<RequireCycle> requireCycles
210
)
211
: module(module)
212
, builtinTypes(builtinTypes)
213
, arena(normalizer->arena)
214
, rootScope(nullptr)
215
, dfg(dfg)
216
, normalizer(normalizer)
217
, typeFunctionRuntime(typeFunctionRuntime)
218
, moduleResolver(moduleResolver)
219
, ice(ice)
220
, globalScope(std::move(globalScope))
221
, typeFunctionScope(std::move(typeFunctionScope))
222
, prepareModuleScope(std::move(prepareModuleScope))
223
, requireCycles(std::move(requireCycles))
224
, logger(logger)
225
{
226
LUAU_ASSERT(module);
227
}
228
229
ConstraintSet ConstraintGenerator::run(AstStatBlock* block)
230
{
231
visitModuleRoot(block);
232
233
return ConstraintSet{NotNull{rootScope}, std::move(constraints), std::move(freeTypes), std::move(scopeToFunction), std::move(errors)};
234
}
235
236
ConstraintSet ConstraintGenerator::runOnFragment(const ScopePtr& resumeScope, AstStatBlock* block)
237
{
238
visitFragmentRoot(resumeScope, block);
239
240
return ConstraintSet{NotNull{rootScope}, std::move(constraints), std::move(freeTypes), std::move(scopeToFunction), std::move(errors)};
241
}
242
243
void ConstraintGenerator::visitModuleRoot(AstStatBlock* block)
244
{
245
LUAU_TIMETRACE_SCOPE("ConstraintGenerator::visitModuleRoot", "Typechecking");
246
247
LUAU_ASSERT(scopes.empty());
248
LUAU_ASSERT(rootScope == nullptr);
249
ScopePtr scope = std::make_shared<Scope>(globalScope);
250
rootScope = scope.get();
251
scopes.emplace_back(block->location, scope);
252
rootScope->location = block->location;
253
module->astScopes[block] = NotNull{scope.get()};
254
255
interiorFreeTypes.emplace_back();
256
257
// Create module-local scope for the type function environment
258
ScopePtr localTypeFunctionScope = std::make_shared<Scope>(typeFunctionScope);
259
localTypeFunctionScope->location = block->location;
260
typeFunctionRuntime->rootScope = localTypeFunctionScope;
261
262
rootScope->returnType = freshTypePack(scope, Polarity::Positive);
263
TypeId moduleFnTy = arena->addType(FunctionType{TypeLevel{}, builtinTypes->anyTypePack, rootScope->returnType});
264
265
prepopulateGlobalScope(scope, block);
266
267
Checkpoint start = checkpoint(this);
268
269
ControlFlow cf = visitBlockWithoutChildScope(scope, block);
270
if (cf == ControlFlow::None)
271
addConstraint(scope, block->location, PackSubtypeConstraint{builtinTypes->emptyTypePack, rootScope->returnType});
272
273
Checkpoint end = checkpoint(this);
274
275
TypeId result = arena->addType(BlockedType{});
276
NotNull<Constraint> genConstraint = addConstraint(
277
scope,
278
block->location,
279
GeneralizationConstraint{
280
result,
281
moduleFnTy,
282
/*interiorTypes*/ std::vector<TypeId>{},
283
/*hasDeprecatedAttribute*/ false,
284
/*deprecatedInfo*/ {},
285
/*noGenerics*/ true
286
}
287
);
288
289
scope->interiorFreeTypes = std::move(interiorFreeTypes.back().types);
290
scope->interiorFreeTypePacks = std::move(interiorFreeTypes.back().typePacks);
291
292
getMutable<BlockedType>(result)->setOwner(genConstraint);
293
forEachConstraint(
294
start,
295
end,
296
this,
297
[genConstraint](const ConstraintPtr& c)
298
{
299
genConstraint->dependencies.emplace_back(c.get());
300
}
301
);
302
303
interiorFreeTypes.pop_back();
304
305
fillInInferredBindings(scope, block);
306
307
if (logger)
308
logger->captureGenerationModule(module);
309
310
for (const auto& [ty, domain] : localTypes)
311
{
312
// FIXME: This isn't the most efficient thing.
313
TypeId domainTy = builtinTypes->neverType;
314
for (TypeId d : domain)
315
{
316
d = follow(d);
317
if (d == ty)
318
continue;
319
domainTy = simplifyUnion(scope, Location{}, domainTy, d);
320
}
321
322
LUAU_ASSERT(get<BlockedType>(ty));
323
asMutable(ty)->ty.emplace<BoundType>(domainTy);
324
}
325
326
for (TypeId ty : unionsToSimplify)
327
addConstraint(scope, block->location, SimplifyConstraint{ty});
328
}
329
330
void ConstraintGenerator::visitFragmentRoot(const ScopePtr& resumeScope, AstStatBlock* block)
331
{
332
// We prepopulate global data in the resumeScope to avoid writing data into the old modules scopes
333
prepopulateGlobalScopeForFragmentTypecheck(globalScope, resumeScope, block);
334
// Pre
335
interiorFreeTypes.emplace_back();
336
visitBlockWithoutChildScope(resumeScope, block);
337
// Post
338
interiorFreeTypes.pop_back();
339
340
fillInInferredBindings(resumeScope, block);
341
342
if (logger)
343
logger->captureGenerationModule(module);
344
345
for (const auto& [ty, domain] : localTypes)
346
{
347
// FIXME: This isn't the most efficient thing.
348
TypeId domainTy = builtinTypes->neverType;
349
for (TypeId d : domain)
350
{
351
d = follow(d);
352
if (d == ty)
353
continue;
354
domainTy = simplifyUnion(resumeScope, resumeScope->location, domainTy, d);
355
}
356
357
LUAU_ASSERT(get<BlockedType>(ty));
358
asMutable(ty)->ty.emplace<BoundType>(domainTy);
359
}
360
}
361
362
363
TypeId ConstraintGenerator::freshType(const ScopePtr& scope, Polarity polarity)
364
{
365
const TypeId ft = Luau::freshType(arena, builtinTypes, scope.get(), polarity);
366
interiorFreeTypes.back().types.push_back(ft);
367
freeTypes.insert(ft);
368
return ft;
369
}
370
371
TypePackId ConstraintGenerator::freshTypePack(const ScopePtr& scope, Polarity polarity)
372
{
373
FreeTypePack f{scope.get(), polarity};
374
TypePackId result = arena->addTypePack(TypePackVar{std::move(f)});
375
interiorFreeTypes.back().typePacks.push_back(result);
376
return result;
377
}
378
379
TypePackId ConstraintGenerator::addTypePack(std::vector<TypeId> head, std::optional<TypePackId> tail)
380
{
381
if (head.empty())
382
{
383
if (tail)
384
return *tail;
385
else
386
return builtinTypes->emptyTypePack;
387
}
388
else
389
return arena->addTypePack(TypePack{std::move(head), tail});
390
}
391
392
ScopePtr ConstraintGenerator::childScope(AstNode* node, const ScopePtr& parent)
393
{
394
auto scope = std::make_shared<Scope>(parent);
395
scopes.emplace_back(node->location, scope);
396
scope->location = node->location;
397
398
scope->returnType = parent->returnType;
399
scope->varargPack = parent->varargPack;
400
401
parent->children.emplace_back(scope.get());
402
module->astScopes[node] = scope.get();
403
404
return scope;
405
}
406
407
std::optional<TypeId> ConstraintGenerator::lookup(const ScopePtr& scope, Location location, DefId def, bool prototype)
408
{
409
if (get<Cell>(def))
410
return scope->lookup(def);
411
if (auto phi = get<Phi>(def))
412
{
413
if (auto found = scope->lookup(def))
414
return *found;
415
else if (!prototype && phi->operands.size() == 1)
416
return lookup(scope, location, phi->operands.at(0), prototype);
417
else if (!prototype)
418
return std::nullopt;
419
420
TypeId res = builtinTypes->neverType;
421
422
for (DefId operand : phi->operands)
423
{
424
// `scope->lookup(operand)` may return nothing because we only bind a type to that operand
425
// once we've seen that particular `DefId`. In this case, we need to prototype those typeArguments
426
// and use those at a later time.
427
std::optional<TypeId> ty = lookup(scope, location, operand, /*prototype*/ false);
428
if (!ty)
429
{
430
ty = arena->addType(BlockedType{});
431
localTypes.try_insert(*ty, {});
432
rootScope->lvalueTypes[operand] = *ty;
433
}
434
435
res = makeUnion(scope, location, res, *ty);
436
}
437
438
scope->lvalueTypes[def] = res;
439
return res;
440
}
441
else
442
ice->ice("ConstraintGenerator::lookup is inexhaustive?");
443
}
444
445
NotNull<Constraint> ConstraintGenerator::addConstraint(const ScopePtr& scope, const Location& location, ConstraintV cv)
446
{
447
return NotNull{constraints.emplace_back(new Constraint{NotNull{scope.get()}, location, std::move(cv)}).get()};
448
}
449
450
NotNull<Constraint> ConstraintGenerator::addConstraint(const ScopePtr& scope, std::unique_ptr<Constraint> c)
451
{
452
return NotNull{constraints.emplace_back(std::move(c)).get()};
453
}
454
455
void ConstraintGenerator::unionRefinements(
456
const ScopePtr& scope,
457
Location location,
458
const RefinementContext& lhs,
459
const RefinementContext& rhs,
460
RefinementContext& dest,
461
std::vector<ConstraintV>* constraints
462
)
463
{
464
const auto intersect = [&](const std::vector<TypeId>& types)
465
{
466
if (1 == types.size())
467
return types[0];
468
else if (2 == types.size())
469
return makeIntersect(scope, location, types[0], types[1]);
470
471
return arena->addType(IntersectionType{types});
472
};
473
474
for (auto& [def, partition] : lhs)
475
{
476
auto rhsIt = rhs.find(def);
477
if (rhsIt == rhs.end())
478
continue;
479
480
LUAU_ASSERT(!partition.discriminantTypes.empty());
481
LUAU_ASSERT(!rhsIt->second.discriminantTypes.empty());
482
483
TypeId leftDiscriminantTy = partition.discriminantTypes.size() == 1 ? partition.discriminantTypes[0] : intersect(partition.discriminantTypes);
484
485
TypeId rightDiscriminantTy =
486
rhsIt->second.discriminantTypes.size() == 1 ? rhsIt->second.discriminantTypes[0] : intersect(rhsIt->second.discriminantTypes);
487
488
dest.insert(def, {});
489
dest.get(def)->discriminantTypes.push_back(makeUnion(scope, location, leftDiscriminantTy, rightDiscriminantTy));
490
dest.get(def)->shouldAppendNilType |= partition.shouldAppendNilType || rhsIt->second.shouldAppendNilType;
491
}
492
}
493
494
void ConstraintGenerator::computeRefinement(
495
const ScopePtr& scope,
496
Location location,
497
RefinementId refinement,
498
RefinementContext* refis,
499
bool sense,
500
bool eq,
501
std::vector<ConstraintV>* constraints
502
)
503
{
504
if (!refinement)
505
return;
506
else if (auto variadic = get<Variadic>(refinement))
507
{
508
for (RefinementId refi : variadic->refinements)
509
computeRefinement(scope, location, refi, refis, sense, eq, constraints);
510
}
511
else if (auto negation = get<Negation>(refinement))
512
return computeRefinement(scope, location, negation->refinement, refis, !sense, eq, constraints);
513
else if (auto conjunction = get<Conjunction>(refinement))
514
{
515
RefinementContext lhsRefis;
516
RefinementContext rhsRefis;
517
518
computeRefinement(scope, location, conjunction->lhs, sense ? refis : &lhsRefis, sense, eq, constraints);
519
computeRefinement(scope, location, conjunction->rhs, sense ? refis : &rhsRefis, sense, eq, constraints);
520
521
if (!sense)
522
unionRefinements(scope, location, lhsRefis, rhsRefis, *refis, constraints);
523
}
524
else if (auto disjunction = get<Disjunction>(refinement))
525
{
526
RefinementContext lhsRefis;
527
RefinementContext rhsRefis;
528
529
computeRefinement(scope, location, disjunction->lhs, sense ? &lhsRefis : refis, sense, eq, constraints);
530
computeRefinement(scope, location, disjunction->rhs, sense ? &rhsRefis : refis, sense, eq, constraints);
531
532
if (sense)
533
unionRefinements(scope, location, lhsRefis, rhsRefis, *refis, constraints);
534
}
535
else if (auto equivalence = get<Equivalence>(refinement))
536
{
537
computeRefinement(scope, location, equivalence->lhs, refis, sense, true, constraints);
538
computeRefinement(scope, location, equivalence->rhs, refis, sense, true, constraints);
539
}
540
else if (auto proposition = get<Proposition>(refinement))
541
{
542
TypeId discriminantTy = proposition->discriminantTy;
543
544
// if we have a negative sense, then we need to negate the discriminant
545
if (!sense)
546
{
547
if (auto nt = get<NegationType>(follow(discriminantTy)))
548
discriminantTy = nt->ty;
549
else
550
discriminantTy = arena->addType(NegationType{discriminantTy});
551
}
552
553
if (eq)
554
discriminantTy = createTypeFunctionInstance(builtinTypes->typeFunctions->singletonFunc, {discriminantTy}, {}, scope, location);
555
556
for (const RefinementKey* key = proposition->key; key; key = key->parent)
557
{
558
refis->insert(key->def, {});
559
refis->get(key->def)->discriminantTypes.push_back(discriminantTy);
560
561
// Reached leaf node
562
if (!key->propName)
563
break;
564
565
TypeId nextDiscriminantTy = arena->addType(TableType{});
566
NotNull<TableType> table{getMutable<TableType>(nextDiscriminantTy)};
567
table->props[*key->propName] = Property::readonly(discriminantTy);
568
table->scope = scope.get();
569
table->state = TableState::Sealed;
570
571
discriminantTy = nextDiscriminantTy;
572
}
573
574
// When the top-level expression is `t[x]`, we want to refine it into `nil`, not `never`.
575
LUAU_ASSERT(refis->get(proposition->key->def));
576
refis->get(proposition->key->def)->shouldAppendNilType =
577
(sense || !eq) && containsSubscriptedDefinition(proposition->key->def) && !proposition->implicitFromCall;
578
}
579
}
580
581
namespace
582
{
583
584
/*
585
* Constraint generation may be called upon to simplify an intersection or union
586
* of typeArguments that are not sufficiently solved yet. We use
587
* FindSimplificationBlockers to recognize these typeArguments and defer the
588
* simplification until constraint solution.
589
*/
590
struct FindSimplificationBlockers : IterativeTypeVisitor
591
{
592
bool found = false;
593
594
FindSimplificationBlockers()
595
: IterativeTypeVisitor("FindSimplificationBlockers", /* skipBoundTypes */ true)
596
{
597
}
598
599
bool visit(TypeId) override
600
{
601
return !found;
602
}
603
604
bool visit(TypeId, const BlockedType&) override
605
{
606
found = true;
607
return false;
608
}
609
610
bool visit(TypeId, const FreeType&) override
611
{
612
found = true;
613
return false;
614
}
615
616
bool visit(TypeId, const PendingExpansionType&) override
617
{
618
found = true;
619
return false;
620
}
621
622
// We do not need to know anything at all about a function's argument or
623
// return typeArguments in order to simplify it in an intersection or union.
624
bool visit(TypeId, const FunctionType&) override
625
{
626
return false;
627
}
628
629
bool visit(TypeId, const ExternType&) override
630
{
631
return false;
632
}
633
};
634
635
bool mustDeferIntersection(TypeId ty)
636
{
637
FindSimplificationBlockers bts;
638
bts.run(ty);
639
return bts.found;
640
}
641
} // namespace
642
643
enum RefinementsOpKind
644
{
645
Intersect,
646
Refine,
647
None
648
};
649
650
void ConstraintGenerator::applyRefinements(const ScopePtr& scope, Location location, RefinementId refinement)
651
{
652
if (!refinement)
653
return;
654
655
RefinementContext refinements;
656
std::vector<ConstraintV> constraints;
657
computeRefinement(scope, location, refinement, &refinements, /*sense*/ true, /*eq*/ false, &constraints);
658
auto flushConstraints = [this, &scope, &location](RefinementsOpKind kind, TypeId ty, std::vector<TypeId>& discriminants)
659
{
660
if (discriminants.empty())
661
return ty;
662
if (kind == RefinementsOpKind::None)
663
{
664
LUAU_ASSERT(false);
665
return ty;
666
}
667
std::vector<TypeId> args = {ty};
668
const TypeFunction& func =
669
kind == RefinementsOpKind::Intersect ? builtinTypes->typeFunctions->intersectFunc : builtinTypes->typeFunctions->refineFunc;
670
LUAU_ASSERT(!func.name.empty());
671
args.insert(args.end(), discriminants.begin(), discriminants.end());
672
TypeId resultType = createTypeFunctionInstance(func, std::move(args), {}, scope, location);
673
discriminants.clear();
674
return resultType;
675
};
676
677
for (auto& [def, partition] : refinements)
678
{
679
if (std::optional<TypeId> defTy = lookup(scope, location, def))
680
{
681
TypeId ty = *defTy;
682
// Intersect ty with every discriminant type. If either type is not
683
// sufficiently solved, we queue the intersection up via an
684
// IntersectConstraint.
685
// For each discriminant ty, we accumulated it onto ty, creating a longer and longer
686
// sequence of refine constraints. On every loop of this we called mustDeferIntersection.
687
// For sufficiently large typeArguments, we would blow the stack.
688
// Instead, we record all the discriminant typeArguments in sequence
689
// and then dispatch a single refine constraint with multiple arguments. This helps us avoid
690
// the potentially expensive check on mustDeferIntersection
691
std::vector<TypeId> discriminants;
692
RefinementsOpKind kind = RefinementsOpKind::None;
693
bool mustDefer = mustDeferIntersection(ty);
694
for (TypeId dt : partition.discriminantTypes)
695
{
696
mustDefer = mustDefer || mustDeferIntersection(dt);
697
if (mustDefer)
698
{
699
if (kind == RefinementsOpKind::Intersect)
700
ty = flushConstraints(kind, ty, discriminants);
701
kind = RefinementsOpKind::Refine;
702
703
discriminants.push_back(dt);
704
}
705
else
706
{
707
ErrorSuppression status = shouldSuppressErrors(normalizer, ty);
708
if (status == ErrorSuppression::NormalizationFailed)
709
reportError(location, NormalizationTooComplex{});
710
if (kind == RefinementsOpKind::Refine)
711
ty = flushConstraints(kind, ty, discriminants);
712
kind = RefinementsOpKind::Intersect;
713
714
discriminants.push_back(dt);
715
716
if (status == ErrorSuppression::Suppress)
717
{
718
ty = flushConstraints(kind, ty, discriminants);
719
ty = makeUnion(scope, location, ty, builtinTypes->errorType);
720
}
721
}
722
}
723
724
// Finalize - if there are any discriminants left, make one big constraint for refining them
725
if (kind != RefinementsOpKind::None)
726
ty = flushConstraints(kind, ty, discriminants);
727
728
if (partition.shouldAppendNilType)
729
ty = createTypeFunctionInstance(builtinTypes->typeFunctions->weakoptionalFunc, {ty}, {}, scope, location);
730
updateRValueRefinements(scope, def, ty);
731
}
732
}
733
734
for (auto& c : constraints)
735
addConstraint(scope, location, c);
736
}
737
738
void ConstraintGenerator::checkAliases(const ScopePtr& scope, AstStatBlock* block)
739
{
740
std::unordered_map<Name, Location> aliasDefinitionLocations;
741
std::unordered_map<Name, Location> classDefinitionLocations;
742
743
bool hasTypeFunction = false;
744
ScopePtr typeFunctionEnvScope;
745
746
// In order to enable mutually-recursive type aliases, we need to
747
// populate the type bindings before we actually check any of the
748
// alias statements.
749
for (AstStat* stat : block->body)
750
{
751
if (auto alias = stat->as<AstStatTypeAlias>())
752
{
753
if (FFlag::LuauDisallowRedefiningBuiltinTypes && globalScope->builtinTypeNames.contains(alias->name.value))
754
{
755
reportError(alias->location, DuplicateTypeDefinition{alias->name.value});
756
continue;
757
}
758
759
if (scope->exportedTypeBindings.count(alias->name.value) || scope->privateTypeBindings.count(alias->name.value))
760
{
761
auto it = aliasDefinitionLocations.find(alias->name.value);
762
LUAU_ASSERT(it != aliasDefinitionLocations.end());
763
reportError(alias->location, DuplicateTypeDefinition{alias->name.value, it->second});
764
continue;
765
}
766
767
// A type alias might have no name if the code is syntactically
768
// illegal. We mustn't prepopulate anything in this case.
769
if (alias->name == kParseNameError || alias->name == "typeof")
770
continue;
771
772
ScopePtr defnScope = childScope(alias, scope);
773
774
TypeId initialType = arena->addType(BlockedType{});
775
TypeFun initialFun{initialType};
776
777
/* The boolean toggle `addTypes` decides whether or not to introduce the generic type/pack param into the privateType/Pack bindings.
778
This map is used by resolveType(Pack) to determine whether or not to produce an error for `F<T... = ...T>`. Because we are delaying
779
the the initialization of the generic default to the point at which we check the type alias, we need to ensure that we don't
780
prematurely add `T` as this will cause us to allow the above example (T is in the bindings so we return that as the resolved type).
781
Done this way, we can evaluate the default safely and then introduce the variable into the map again once the default has been
782
evaluated. Note, only generic type aliases support default generic parameters.
783
*/
784
785
for (const auto& [name, gen] : createGenerics(defnScope, alias->generics, /* useCache */ true, /* addTypes */ false))
786
{
787
initialFun.typeParams.push_back(gen);
788
}
789
790
for (const auto& [name, genPack] : createGenericPacks(defnScope, alias->genericPacks, /* useCache */ true, /* addTypes */ false))
791
{
792
initialFun.typePackParams.push_back(genPack);
793
}
794
initialFun.definitionLocation = alias->location;
795
796
if (alias->exported)
797
scope->exportedTypeBindings[alias->name.value] = std::move(initialFun);
798
else
799
scope->privateTypeBindings[alias->name.value] = std::move(initialFun);
800
801
astTypeAliasDefiningScopes[alias] = defnScope;
802
aliasDefinitionLocations[alias->name.value] = alias->location;
803
}
804
else if (auto function = stat->as<AstStatTypeFunction>())
805
{
806
hasTypeFunction = true;
807
808
// If a type function w/ same name has already been defined, error for having duplicates
809
if (scope->exportedTypeBindings.count(function->name.value) || scope->privateTypeBindings.count(function->name.value))
810
{
811
auto it = aliasDefinitionLocations.find(function->name.value);
812
LUAU_ASSERT(it != aliasDefinitionLocations.end());
813
reportError(function->location, DuplicateTypeDefinition{function->name.value, it->second});
814
continue;
815
}
816
817
// Create TypeFunctionInstanceType
818
std::vector<TypeId> typeParams;
819
typeParams.reserve(function->body->args.size);
820
821
std::vector<GenericTypeDefinition> quantifiedTypeParams;
822
quantifiedTypeParams.reserve(function->body->args.size);
823
824
for (size_t i = 0; i < function->body->args.size; i++)
825
{
826
std::string name = format("T%zu", i);
827
TypeId ty = arena->addType(GenericType{name, Polarity::Unknown});
828
typeParams.push_back(ty);
829
830
GenericTypeDefinition genericTy{ty};
831
quantifiedTypeParams.push_back(genericTy);
832
}
833
834
if (FFlag::LuauTypeFunctionStructuredErrors)
835
{
836
if (std::optional<TypeFunctionError> error = typeFunctionRuntime->registerFunction(function))
837
reportError(function->location, BuiltInTypeFunctionError{*error});
838
}
839
else
840
{
841
if (std::optional<std::string> error = typeFunctionRuntime->registerFunction_DEPRECATED(function))
842
reportError(function->location, GenericError{*error});
843
}
844
845
UserDefinedFunctionData udtfData;
846
847
udtfData.owner = module;
848
udtfData.definition = function;
849
850
TypeId typeFunctionTy = arena->addType(
851
TypeFunctionInstanceType{NotNull{&builtinTypes->typeFunctions->userFunc}, std::move(typeParams), {}, function->name, udtfData}
852
);
853
854
TypeFun typeFunction{std::move(quantifiedTypeParams), typeFunctionTy};
855
856
typeFunction.definitionLocation = function->location;
857
858
// Set type bindings and definition locations for this user-defined type function
859
if (function->exported)
860
scope->exportedTypeBindings[function->name.value] = std::move(typeFunction);
861
else
862
scope->privateTypeBindings[function->name.value] = std::move(typeFunction);
863
864
aliasDefinitionLocations[function->name.value] = function->location;
865
}
866
else if (auto classDeclaration = stat->as<AstStatDeclareExternType>())
867
{
868
if (scope->exportedTypeBindings.count(classDeclaration->name.value))
869
{
870
auto it = classDefinitionLocations.find(classDeclaration->name.value);
871
LUAU_ASSERT(it != classDefinitionLocations.end());
872
reportError(classDeclaration->location, DuplicateTypeDefinition{classDeclaration->name.value, it->second});
873
continue;
874
}
875
876
// A class might have no name if the code is syntactically
877
// illegal. We mustn't prepopulate anything in this case.
878
if (classDeclaration->name == kParseNameError)
879
continue;
880
881
ScopePtr defnScope = childScope(classDeclaration, scope);
882
883
TypeId initialType = arena->addType(BlockedType{});
884
TypeFun initialFun{initialType};
885
initialFun.definitionLocation = classDeclaration->location;
886
scope->exportedTypeBindings[classDeclaration->name.value] = std::move(initialFun);
887
888
classDefinitionLocations[classDeclaration->name.value] = classDeclaration->location;
889
}
890
}
891
892
if (hasTypeFunction)
893
typeFunctionEnvScope = std::make_shared<Scope>(typeFunctionRuntime->rootScope);
894
895
std::vector<TypeFunctionInstanceType*> createdTypeFunctions;
896
DenseHashMap<AstStatTypeFunction*, const TypeFunctionInstanceType*> referencedTypeFunctions{nullptr};
897
898
// Additional pass for user-defined type functions to fill in their environments completely
899
for (AstStat* stat : block->body)
900
{
901
if (auto function = stat->as<AstStatTypeFunction>())
902
{
903
// Similar to global pre-population, create a binding for each type function in the scope upfront
904
TypeId bt = arena->addType(BlockedType{});
905
typeFunctionEnvScope->bindings[function->name] = Binding{bt, function->location};
906
astTypeFunctionEnvironmentScopes[function] = typeFunctionEnvScope;
907
908
// Find the type function we have already created
909
TypeFunctionInstanceType* mainTypeFun = nullptr;
910
911
if (auto it = scope->privateTypeBindings.find(function->name.value); it != scope->privateTypeBindings.end())
912
mainTypeFun = getMutable<TypeFunctionInstanceType>(it->second.type);
913
914
if (!mainTypeFun)
915
{
916
if (auto it = scope->exportedTypeBindings.find(function->name.value); it != scope->exportedTypeBindings.end())
917
mainTypeFun = getMutable<TypeFunctionInstanceType>(it->second.type);
918
}
919
920
// Fill it with all visible type functions and referenced type aliases
921
if (mainTypeFun)
922
{
923
createdTypeFunctions.push_back(mainTypeFun);
924
925
GlobalNameCollector globalNameCollector;
926
stat->visit(&globalNameCollector);
927
928
UserDefinedFunctionData& userFuncData = mainTypeFun->userFuncData;
929
size_t level = 0;
930
931
auto addToEnvironment = [this, &globalNameCollector, &referencedTypeFunctions](
932
UserDefinedFunctionData& userFuncData, ScopePtr scope, const Name& name, TypeFun tf, size_t level
933
)
934
{
935
if (auto ty = get<TypeFunctionInstanceType>(follow(tf.type)); ty && ty->userFuncData.definition)
936
{
937
if (userFuncData.environmentFunction.find(name))
938
return;
939
940
userFuncData.environmentFunction[name] = std::make_pair(ty->userFuncData.definition, level);
941
942
referencedTypeFunctions[ty->userFuncData.definition] = ty;
943
944
if (auto it = astTypeFunctionEnvironmentScopes.find(ty->userFuncData.definition))
945
{
946
if (auto existing = (*it)->linearSearchForBinding(name, /* traverseScopeChain */ false))
947
scope->bindings[ty->userFuncData.definition->name] = Binding{existing->typeId, ty->userFuncData.definition->location};
948
}
949
}
950
else if (!get<TypeFunctionInstanceType>(follow(tf.type)))
951
{
952
if (userFuncData.environmentAlias.find(name))
953
return;
954
955
AstName astName = module->names->get(name.c_str());
956
957
// Only register globals that we have detected to be used
958
if (!globalNameCollector.names.find(astName))
959
return;
960
961
// Function evaluation environment needs a stable reference to the alias
962
module->typeFunctionAliases.push_back(std::make_unique<TypeFun>(tf));
963
964
userFuncData.environmentAlias[name] = std::make_pair(module->typeFunctionAliases.back().get(), level);
965
966
// TODO: create a specific type alias type
967
scope->bindings[astName] = Binding{builtinTypes->anyType, tf.definitionLocation.value_or(Location())};
968
}
969
};
970
971
// Go up the scopes to register type functions and aliases, but without reaching into the global scope
972
for (Scope* curr = scope.get(); curr && curr != globalScope.get(); curr = curr->parent.get())
973
{
974
for (auto& [name, tf] : curr->privateTypeBindings)
975
addToEnvironment(userFuncData, typeFunctionEnvScope, name, tf, level);
976
977
for (auto& [name, tf] : curr->exportedTypeBindings)
978
addToEnvironment(userFuncData, typeFunctionEnvScope, name, tf, level);
979
980
level++;
981
}
982
}
983
}
984
}
985
986
// Finally, we need to include aliases from functions we might call
987
for (TypeFunctionInstanceType* type : createdTypeFunctions)
988
{
989
UserDefinedFunctionData& sourceFuncData = type->userFuncData;
990
991
// Go over all functions in our environment
992
for (const auto& [targetFuncName, definitionAndLevel] : sourceFuncData.environmentFunction)
993
{
994
if (const TypeFunctionInstanceType** it = referencedTypeFunctions.find(definitionAndLevel.first))
995
{
996
const UserDefinedFunctionData& targetFuncData = (*it)->userFuncData;
997
998
for (const auto& [aliasName, typeAndLevel] : targetFuncData.environmentAlias)
999
{
1000
if (!sourceFuncData.environmentAlias.find(aliasName))
1001
{
1002
// Combine definition levels because we are viewing target function aliases from the perspective of the target function
1003
sourceFuncData.environmentAlias[aliasName] = {typeAndLevel.first, typeAndLevel.second + definitionAndLevel.second};
1004
}
1005
}
1006
}
1007
}
1008
}
1009
}
1010
1011
ControlFlow ConstraintGenerator::visitBlockWithoutChildScope(const ScopePtr& scope, AstStatBlock* block)
1012
{
1013
RecursionCounter counter{&recursionCount};
1014
1015
if (recursionCount >= DFInt::LuauConstraintGeneratorRecursionLimit)
1016
{
1017
reportCodeTooComplex(block->location);
1018
return ControlFlow::None;
1019
}
1020
1021
checkAliases(scope, block);
1022
1023
std::optional<ControlFlow> firstControlFlow;
1024
for (AstStat* stat : block->body)
1025
{
1026
ControlFlow cf = visit(scope, stat);
1027
if (cf != ControlFlow::None && !firstControlFlow)
1028
firstControlFlow = cf;
1029
}
1030
1031
return firstControlFlow.value_or(ControlFlow::None);
1032
}
1033
1034
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStat* stat)
1035
{
1036
RecursionCounter counter{&recursionCount};
1037
std::optional<RecursionLimiter> limiter;
1038
1039
if (recursionCount >= DFInt::LuauConstraintGeneratorRecursionLimit)
1040
{
1041
reportCodeTooComplex(stat->location);
1042
return ControlFlow::None;
1043
}
1044
1045
if (auto s = stat->as<AstStatBlock>())
1046
return visit(scope, s);
1047
else if (auto i = stat->as<AstStatIf>())
1048
return visit(scope, i);
1049
else if (auto s = stat->as<AstStatWhile>())
1050
return visit(scope, s);
1051
else if (auto s = stat->as<AstStatRepeat>())
1052
return visit(scope, s);
1053
else if (stat->is<AstStatBreak>())
1054
return ControlFlow::Breaks;
1055
else if (stat->is<AstStatContinue>())
1056
return ControlFlow::Continues;
1057
else if (auto r = stat->as<AstStatReturn>())
1058
return visit(scope, r);
1059
else if (auto e = stat->as<AstStatExpr>())
1060
{
1061
checkPack(scope, e->expr);
1062
1063
if (auto call = e->expr->as<AstExprCall>(); call && doesCallError(call))
1064
return ControlFlow::Throws;
1065
1066
return ControlFlow::None;
1067
}
1068
else if (auto s = stat->as<AstStatLocal>())
1069
return visit(scope, s);
1070
else if (auto s = stat->as<AstStatFor>())
1071
return visit(scope, s);
1072
else if (auto s = stat->as<AstStatForIn>())
1073
return visit(scope, s);
1074
else if (auto a = stat->as<AstStatAssign>())
1075
return visit(scope, a);
1076
else if (auto a = stat->as<AstStatCompoundAssign>())
1077
return visit(scope, a);
1078
else if (auto f = stat->as<AstStatFunction>())
1079
return visit(scope, f);
1080
else if (auto f = stat->as<AstStatLocalFunction>())
1081
return visit(scope, f);
1082
else if (auto a = stat->as<AstStatTypeAlias>())
1083
return visit(scope, a);
1084
else if (auto f = stat->as<AstStatTypeFunction>())
1085
return visit(scope, f);
1086
else if (auto s = stat->as<AstStatDeclareGlobal>())
1087
return visit(scope, s);
1088
else if (auto s = stat->as<AstStatDeclareFunction>())
1089
return visit(scope, s);
1090
else if (auto s = stat->as<AstStatDeclareExternType>())
1091
return visit(scope, s);
1092
else if (auto s = stat->as<AstStatError>())
1093
return visit(scope, s);
1094
else
1095
{
1096
LUAU_ASSERT(0 && "Internal error: Unknown AstStat type");
1097
return ControlFlow::None;
1098
}
1099
}
1100
1101
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatLocal* statLocal)
1102
{
1103
std::vector<TypeId> annotatedTypes;
1104
annotatedTypes.reserve(statLocal->vars.size);
1105
bool hasAnnotation = false;
1106
1107
std::vector<std::optional<TypeId>> expectedTypes;
1108
expectedTypes.reserve(statLocal->vars.size);
1109
1110
std::vector<TypeId> assignees;
1111
assignees.reserve(statLocal->vars.size);
1112
1113
// Used to name the first value type, even if it's not placed in varTypes,
1114
// for the purpose of synthetic name attribution.
1115
std::optional<TypeId> firstValueType;
1116
1117
for (AstLocal* local : statLocal->vars)
1118
{
1119
const Location location = local->location;
1120
1121
TypeId assignee = arena->addType(BlockedType{});
1122
localTypes.try_insert(assignee, {});
1123
1124
assignees.push_back(assignee);
1125
1126
if (!firstValueType)
1127
firstValueType = assignee;
1128
1129
if (local->annotation)
1130
{
1131
hasAnnotation = true;
1132
TypeId annotationTy = resolveType(scope, local->annotation, /* inTypeArguments */ false);
1133
annotatedTypes.push_back(annotationTy);
1134
expectedTypes.emplace_back(annotationTy);
1135
scope->bindings[local] = Binding{annotationTy, location};
1136
}
1137
else
1138
{
1139
// annotatedTypes must contain one type per local. If a particular
1140
// local has no annotation at, assume the most conservative thing.
1141
annotatedTypes.push_back(builtinTypes->unknownType);
1142
1143
expectedTypes.emplace_back(std::nullopt);
1144
scope->bindings[local] = Binding{builtinTypes->unknownType, location};
1145
1146
inferredBindings[local] = {scope.get(), location, {assignee}};
1147
}
1148
1149
DefId def = dfg->getDef(local);
1150
scope->lvalueTypes[def] = assignee;
1151
}
1152
1153
Checkpoint start = checkpoint(this);
1154
TypePackId rvaluePack = checkPack(scope, statLocal->values, expectedTypes).tp;
1155
Checkpoint end = checkpoint(this);
1156
1157
std::vector<TypeId> deferredTypes;
1158
auto [head, tail] = flatten(rvaluePack);
1159
1160
DenseHashSet<BlockedType*> freshBlockedTypes{nullptr};
1161
1162
for (size_t i = 0; i < statLocal->vars.size; ++i)
1163
{
1164
LUAU_ASSERT(get<BlockedType>(assignees[i]));
1165
TypeIds* localDomain = localTypes.find(assignees[i]);
1166
LUAU_ASSERT(localDomain);
1167
1168
if (statLocal->vars.data[i]->annotation)
1169
{
1170
localDomain->insert(annotatedTypes[i]);
1171
if (FFlag::LuauUnpackRespectsAnnotations && i >= head.size() && tail)
1172
deferredTypes.emplace_back(annotatedTypes[i]);
1173
}
1174
else
1175
{
1176
if (i < head.size())
1177
{
1178
localDomain->insert(head[i]);
1179
}
1180
else if (tail)
1181
{
1182
deferredTypes.push_back(arena->addType(BlockedType{}));
1183
localDomain->insert(deferredTypes.back());
1184
if (FFlag::LuauUnpackRespectsAnnotations)
1185
freshBlockedTypes.insert(getMutable<BlockedType>(deferredTypes.back()));
1186
}
1187
else
1188
{
1189
localDomain->insert(builtinTypes->nilType);
1190
}
1191
}
1192
}
1193
1194
if (hasAnnotation)
1195
{
1196
TypePackId annotatedPack = arena->addTypePack(std::move(annotatedTypes));
1197
addConstraint(scope, statLocal->location, PackSubtypeConstraint{rvaluePack, annotatedPack});
1198
}
1199
1200
if (!deferredTypes.empty())
1201
{
1202
LUAU_ASSERT(tail);
1203
NotNull<Constraint> uc = addConstraint(scope, statLocal->location, UnpackConstraint{deferredTypes, *tail});
1204
1205
forEachConstraint(
1206
start,
1207
end,
1208
this,
1209
[&uc](const ConstraintPtr& runBefore)
1210
{
1211
uc->dependencies.emplace_back(runBefore.get());
1212
}
1213
);
1214
1215
if (FFlag::LuauUnpackRespectsAnnotations)
1216
{
1217
// This is a separate set from `deferredTypes` to
1218
// distinguish between blocked types we just minted
1219
// and blocked types that correspond to annotations.
1220
for (BlockedType* bt : freshBlockedTypes)
1221
bt->setOwner(uc);
1222
}
1223
else
1224
{
1225
for (TypeId t : deferredTypes)
1226
getMutable<BlockedType>(t)->setOwner(uc);
1227
}
1228
}
1229
1230
if (statLocal->vars.size == 1 && statLocal->values.size == 1 && firstValueType && scope.get() == rootScope && !hasAnnotation)
1231
{
1232
AstLocal* var = statLocal->vars.data[0];
1233
AstExpr* value = statLocal->values.data[0];
1234
1235
if (value->is<AstExprTable>())
1236
addConstraint(scope, value->location, NameConstraint{*firstValueType, var->name.value, /*synthetic*/ true});
1237
else if (const AstExprCall* call = value->as<AstExprCall>())
1238
{
1239
if (matchSetMetatable(*call))
1240
addConstraint(scope, value->location, NameConstraint{*firstValueType, var->name.value, /*synthetic*/ true});
1241
}
1242
}
1243
1244
if (statLocal->values.size > 0)
1245
{
1246
// To correctly handle 'require', we need to import the exported type bindings into the variable 'namespace'.
1247
for (size_t i = 0; i < statLocal->values.size && i < statLocal->vars.size; ++i)
1248
{
1249
const AstExprCall* call = statLocal->values.data[i]->as<AstExprCall>();
1250
if (!call)
1251
continue;
1252
1253
auto maybeRequire = matchRequire(*call);
1254
if (!maybeRequire)
1255
continue;
1256
1257
AstExpr* require = *maybeRequire;
1258
1259
auto moduleInfo = moduleResolver->resolveModuleInfo(module->name, *require);
1260
if (!moduleInfo)
1261
continue;
1262
1263
ModulePtr module = moduleResolver->getModule(moduleInfo->name);
1264
if (!module)
1265
continue;
1266
1267
const Name name{statLocal->vars.data[i]->name.value};
1268
scope->importedTypeBindings[name] = module->exportedTypeBindings;
1269
scope->importedModules[name] = moduleInfo->name;
1270
1271
// Imported typeArguments of requires that transitively refer to current module have to be replaced with 'any'
1272
for (const auto& [location, path] : requireCycles)
1273
{
1274
if (path.empty() || path.front() != moduleInfo->name)
1275
continue;
1276
1277
for (auto& [name, tf] : scope->importedTypeBindings[name])
1278
tf = TypeFun{{}, {}, builtinTypes->anyType};
1279
}
1280
}
1281
}
1282
1283
return ControlFlow::None;
1284
}
1285
1286
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatFor* for_)
1287
{
1288
TypeId annotationTy = builtinTypes->numberType;
1289
if (for_->var->annotation)
1290
annotationTy = resolveType(scope, for_->var->annotation, /* inTypeArguments */ false);
1291
1292
auto inferNumber = [&](AstExpr* expr)
1293
{
1294
if (!expr)
1295
return;
1296
1297
TypeId t = check(scope, expr).ty;
1298
addConstraint(scope, expr->location, SubtypeConstraint{t, builtinTypes->numberType});
1299
};
1300
1301
inferNumber(for_->from);
1302
inferNumber(for_->to);
1303
inferNumber(for_->step);
1304
1305
ScopePtr forScope = childScope(for_, scope);
1306
forScope->bindings[for_->var] = Binding{annotationTy, for_->var->location};
1307
1308
DefId def = dfg->getDef(for_->var);
1309
forScope->lvalueTypes[def] = annotationTy;
1310
updateRValueRefinements(forScope, def, annotationTy);
1311
1312
visit(forScope, for_->body);
1313
1314
scope->inheritAssignments(forScope);
1315
1316
return ControlFlow::None;
1317
}
1318
1319
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatForIn* forIn)
1320
{
1321
ScopePtr loopScope = childScope(forIn, scope);
1322
TypePackId iterator = checkPack(scope, forIn->values).tp;
1323
1324
std::vector<TypeId> variableTypes;
1325
variableTypes.reserve(forIn->vars.size);
1326
1327
for (AstLocal* var : forIn->vars)
1328
{
1329
TypeId loopVar = arena->addType(BlockedType{});
1330
variableTypes.push_back(loopVar);
1331
1332
if (FFlag::LuauPropagateTypeAnnotationsInForInLoops)
1333
{
1334
DefId def = dfg->getDef(var);
1335
1336
if (var->annotation)
1337
{
1338
TypeId annotationTy = resolveType(loopScope, var->annotation, /*inTypeArguments*/ false);
1339
loopScope->bindings[var] = Binding{annotationTy, var->location};
1340
addConstraint(scope, var->location, SubtypeConstraint{loopVar, annotationTy});
1341
loopScope->lvalueTypes[def] = annotationTy;
1342
}
1343
else
1344
{
1345
loopScope->bindings[var] = Binding{loopVar, var->location};
1346
loopScope->lvalueTypes[def] = loopVar;
1347
}
1348
}
1349
else
1350
{
1351
if (var->annotation)
1352
{
1353
TypeId annotationTy = resolveType(loopScope, var->annotation, /*inTypeArguments*/ false);
1354
loopScope->bindings[var] = Binding{annotationTy, var->location};
1355
addConstraint(scope, var->location, SubtypeConstraint{loopVar, annotationTy});
1356
}
1357
else
1358
loopScope->bindings[var] = Binding{loopVar, var->location};
1359
1360
DefId def = dfg->getDef(var);
1361
loopScope->lvalueTypes[def] = loopVar;
1362
}
1363
}
1364
1365
auto iterable = addConstraint(
1366
loopScope, getLocation(forIn->values), IterableConstraint{iterator, variableTypes, forIn->values.data[0], &module->astForInNextTypes}
1367
);
1368
1369
// Add an intersection ReduceConstraint for the key variable to denote that it can't be nil
1370
AstLocal* keyVar = *forIn->vars.begin();
1371
const DefId keyDef = dfg->getDef(keyVar);
1372
const TypeId loopVar = loopScope->lvalueTypes[keyDef];
1373
1374
const TypeId intersectionTy =
1375
createTypeFunctionInstance(builtinTypes->typeFunctions->intersectFunc, {loopVar, builtinTypes->notNilType}, {}, loopScope, keyVar->location);
1376
1377
loopScope->bindings[keyVar] = Binding{intersectionTy, keyVar->location};
1378
loopScope->lvalueTypes[keyDef] = intersectionTy;
1379
1380
auto c = addConstraint(loopScope, keyVar->location, ReduceConstraint{intersectionTy});
1381
c->dependencies.push_back(iterable);
1382
1383
for (TypeId var : variableTypes)
1384
{
1385
auto bt = getMutable<BlockedType>(var);
1386
LUAU_ASSERT(bt);
1387
bt->setOwner(iterable);
1388
}
1389
1390
Checkpoint start = checkpoint(this);
1391
visit(loopScope, forIn->body);
1392
Checkpoint end = checkpoint(this);
1393
1394
scope->inheritAssignments(loopScope);
1395
1396
// This iter constraint must dispatch first.
1397
forEachConstraint(
1398
start,
1399
end,
1400
this,
1401
[&iterable](const ConstraintPtr& runLater)
1402
{
1403
runLater->dependencies.push_back(iterable);
1404
}
1405
);
1406
1407
return ControlFlow::None;
1408
}
1409
1410
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatWhile* while_)
1411
{
1412
RefinementId refinement = check(scope, while_->condition).refinement;
1413
1414
ScopePtr whileScope = childScope(while_, scope);
1415
applyRefinements(whileScope, while_->condition->location, refinement);
1416
1417
visit(whileScope, while_->body);
1418
1419
scope->inheritAssignments(whileScope);
1420
1421
return ControlFlow::None;
1422
}
1423
1424
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatRepeat* repeat)
1425
{
1426
ScopePtr repeatScope = childScope(repeat, scope);
1427
1428
visitBlockWithoutChildScope(repeatScope, repeat->body);
1429
1430
check(repeatScope, repeat->condition);
1431
1432
scope->inheritAssignments(repeatScope);
1433
1434
return ControlFlow::None;
1435
}
1436
1437
static void propagateDeprecatedAttributeToConstraint(ConstraintV& c, const AstExprFunction* func)
1438
{
1439
if (GeneralizationConstraint* genConstraint = c.get_if<GeneralizationConstraint>())
1440
{
1441
AstAttr* deprecatedAttribute = func->getAttribute(AstAttr::Type::Deprecated);
1442
genConstraint->hasDeprecatedAttribute = deprecatedAttribute != nullptr;
1443
if (deprecatedAttribute)
1444
{
1445
genConstraint->deprecatedInfo = deprecatedAttribute->deprecatedInfo();
1446
}
1447
}
1448
}
1449
1450
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatLocalFunction* function)
1451
{
1452
// Local
1453
// Global
1454
// Dotted path
1455
// Self?
1456
1457
TypeId functionType = nullptr;
1458
auto ty = scope->lookup(function->name);
1459
LUAU_ASSERT(!ty.has_value()); // The parser ensures that every local function has a distinct Symbol for its name.
1460
1461
functionType = arena->addType(BlockedType{});
1462
scope->bindings[function->name] = Binding{functionType, function->name->location};
1463
1464
FunctionSignature sig = checkFunctionSignature(scope, function->func, /* expectedType */ std::nullopt, function->name->location);
1465
sig.bodyScope->bindings[function->name] = Binding{sig.signature, function->name->location};
1466
1467
DefId def = dfg->getDef(function->name);
1468
scope->lvalueTypes[def] = functionType;
1469
updateRValueRefinements(scope, def, functionType);
1470
sig.bodyScope->lvalueTypes[def] = sig.signature;
1471
updateRValueRefinements(sig.bodyScope, def, sig.signature);
1472
1473
Checkpoint start = checkpoint(this);
1474
checkFunctionBody(sig.bodyScope, function->func);
1475
Checkpoint end = checkpoint(this);
1476
1477
NotNull<Scope> constraintScope{sig.signatureScope ? sig.signatureScope.get() : sig.bodyScope.get()};
1478
std::unique_ptr<Constraint> c =
1479
std::make_unique<Constraint>(constraintScope, function->name->location, GeneralizationConstraint{functionType, sig.signature});
1480
1481
propagateDeprecatedAttributeToConstraint(c->c, function->func);
1482
1483
Constraint* previous = nullptr;
1484
forEachConstraint(
1485
start,
1486
end,
1487
this,
1488
[&c, &previous](const ConstraintPtr& constraint)
1489
{
1490
c->dependencies.emplace_back(constraint.get());
1491
if (auto psc = get<PackSubtypeConstraint>(*constraint); psc && psc->returns)
1492
{
1493
if (previous)
1494
{
1495
constraint->dependencies.emplace_back(previous);
1496
}
1497
1498
previous = constraint.get();
1499
}
1500
}
1501
);
1502
1503
getMutable<BlockedType>(functionType)->setOwner(addConstraint(scope, std::move(c)));
1504
module->astTypes[function->func] = functionType;
1505
1506
return ControlFlow::None;
1507
}
1508
1509
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatFunction* function)
1510
{
1511
// Name could be AstStatLocal, AstStatGlobal, AstStatIndexName.
1512
// With or without self
1513
1514
Checkpoint start = checkpoint(this);
1515
FunctionSignature sig = checkFunctionSignature(scope, function->func, /* expectedType */ std::nullopt, function->name->location);
1516
1517
DefId def = dfg->getDef(function->name);
1518
1519
if (AstExprLocal* localName = function->name->as<AstExprLocal>())
1520
{
1521
sig.bodyScope->bindings[localName->local] = Binding{sig.signature, localName->location};
1522
sig.bodyScope->lvalueTypes[def] = sig.signature;
1523
updateRValueRefinements(sig.bodyScope, def, sig.signature);
1524
}
1525
else if (AstExprGlobal* globalName = function->name->as<AstExprGlobal>())
1526
{
1527
sig.bodyScope->bindings[globalName->name] = Binding{sig.signature, globalName->location};
1528
sig.bodyScope->lvalueTypes[def] = sig.signature;
1529
updateRValueRefinements(sig.bodyScope, def, sig.signature);
1530
}
1531
else if (function->name->is<AstExprIndexName>())
1532
{
1533
updateRValueRefinements(sig.bodyScope, def, sig.signature);
1534
}
1535
1536
if (auto indexName = function->name->as<AstExprIndexName>())
1537
{
1538
auto beginProp = checkpoint(this);
1539
auto [fn, _] = check(scope, indexName);
1540
auto endProp = checkpoint(this);
1541
auto pftc = addConstraint(
1542
sig.signatureScope,
1543
function->func->location,
1544
PushFunctionTypeConstraint{
1545
fn,
1546
sig.signature,
1547
NotNull{function->func},
1548
/* isSelf */ indexName->op == ':',
1549
}
1550
);
1551
forEachConstraint(
1552
beginProp,
1553
endProp,
1554
this,
1555
[pftc](const ConstraintPtr& c)
1556
{
1557
pftc->dependencies.emplace_back(c.get());
1558
}
1559
);
1560
auto beginBody = checkpoint(this);
1561
checkFunctionBody(sig.bodyScope, function->func);
1562
auto endBody = checkpoint(this);
1563
forEachConstraint(
1564
beginBody,
1565
endBody,
1566
this,
1567
[pftc](const ConstraintPtr& c)
1568
{
1569
c->dependencies.push_back(pftc);
1570
}
1571
);
1572
}
1573
else
1574
{
1575
checkFunctionBody(sig.bodyScope, function->func);
1576
}
1577
1578
Checkpoint end = checkpoint(this);
1579
1580
TypeId generalizedType = arena->addType(BlockedType{});
1581
const ScopePtr& constraintScope = sig.signatureScope ? sig.signatureScope : sig.bodyScope;
1582
1583
NotNull<Constraint> c = addConstraint(constraintScope, function->name->location, GeneralizationConstraint{generalizedType, sig.signature});
1584
getMutable<BlockedType>(generalizedType)->setOwner(c);
1585
1586
propagateDeprecatedAttributeToConstraint(c->c, function->func);
1587
1588
Constraint* previous = nullptr;
1589
forEachConstraint(
1590
start,
1591
end,
1592
this,
1593
[&c, &previous](const ConstraintPtr& constraint)
1594
{
1595
c->dependencies.emplace_back(constraint.get());
1596
if (auto psc = get<PackSubtypeConstraint>(*constraint); psc && psc->returns)
1597
{
1598
if (previous)
1599
{
1600
constraint->dependencies.emplace_back(previous);
1601
}
1602
1603
previous = constraint.get();
1604
}
1605
}
1606
);
1607
1608
std::optional<TypeId> existingFunctionTy = follow(lookup(scope, function->name->location, def));
1609
1610
if (AstExprLocal* localName = function->name->as<AstExprLocal>())
1611
{
1612
visitLValue(scope, localName, generalizedType);
1613
1614
scope->bindings[localName->local] = Binding{sig.signature, localName->location};
1615
scope->lvalueTypes[def] = sig.signature;
1616
}
1617
else if (AstExprGlobal* globalName = function->name->as<AstExprGlobal>())
1618
{
1619
if (!existingFunctionTy)
1620
ice->ice("prepopulateGlobalScope did not populate a global name", globalName->location);
1621
1622
if (FFlag::LuauKeepExplicitMapForGlobalTypes2)
1623
{
1624
if (auto bt = get<BlockedType>(*existingFunctionTy); bt && uninitializedGlobals.contains(globalName->name))
1625
{
1626
LUAU_ASSERT(bt->getOwner() == nullptr);
1627
uninitializedGlobals.erase(globalName->name);
1628
emplaceType<BoundType>(asMutable(*existingFunctionTy), generalizedType);
1629
}
1630
}
1631
else
1632
{
1633
// Sketchy: We're specifically looking for BlockedTypes that were
1634
// initially created by ConstraintGenerator::prepopulateGlobalScope.
1635
if (auto bt = get<BlockedType>(*existingFunctionTy); bt && nullptr == bt->getOwner())
1636
emplaceType<BoundType>(asMutable(*existingFunctionTy), generalizedType);
1637
}
1638
1639
1640
scope->bindings[globalName->name] = Binding{sig.signature, globalName->location};
1641
scope->lvalueTypes[def] = sig.signature;
1642
}
1643
else if (AstExprIndexName* indexName = function->name->as<AstExprIndexName>())
1644
{
1645
visitLValue(scope, indexName, generalizedType);
1646
}
1647
else if (function->name->is<AstExprError>())
1648
{
1649
generalizedType = builtinTypes->errorType;
1650
}
1651
1652
if (generalizedType == nullptr)
1653
ice->ice("generalizedType == nullptr", function->location);
1654
1655
updateRValueRefinements(scope, def, generalizedType);
1656
1657
return ControlFlow::None;
1658
}
1659
1660
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatReturn* ret)
1661
{
1662
// At this point, the only way scope->returnType should have anything
1663
// interesting in it is if the function has an explicit return annotation.
1664
// If this is the case, then we can expect that the return expression
1665
// conforms to that.
1666
std::vector<std::optional<TypeId>> expectedTypes;
1667
for (TypeId ty : scope->returnType)
1668
expectedTypes.emplace_back(ty);
1669
TypePackId exprTypes = checkPack(scope, ret->list, expectedTypes).tp;
1670
addConstraint(scope, ret->location, PackSubtypeConstraint{exprTypes, scope->returnType, /*returns*/ true});
1671
1672
return ControlFlow::Returns;
1673
}
1674
1675
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatBlock* block)
1676
{
1677
ScopePtr innerScope = childScope(block, scope);
1678
1679
ControlFlow flow = visitBlockWithoutChildScope(innerScope, block);
1680
1681
// An AstStatBlock has linear control flow, i.e. one entry and one exit, so we can inherit
1682
// all the changes to the environment occurred by the statements in that block.
1683
scope->inheritRefinements(innerScope);
1684
scope->inheritAssignments(innerScope);
1685
1686
return flow;
1687
}
1688
1689
// TODO Clip?
1690
static void bindFreeType(TypeId a, TypeId b)
1691
{
1692
FreeType* af = getMutable<FreeType>(a);
1693
FreeType* bf = getMutable<FreeType>(b);
1694
1695
LUAU_ASSERT(af || bf);
1696
1697
if (!bf)
1698
emplaceType<BoundType>(asMutable(a), b);
1699
else if (!af)
1700
emplaceType<BoundType>(asMutable(b), a);
1701
else if (subsumes(bf->scope, af->scope))
1702
emplaceType<BoundType>(asMutable(a), b);
1703
else if (subsumes(af->scope, bf->scope))
1704
emplaceType<BoundType>(asMutable(b), a);
1705
}
1706
1707
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatAssign* assign)
1708
{
1709
TypePackId resultPack = checkPack(scope, assign->values).tp;
1710
1711
std::vector<TypeId> valueTypes;
1712
valueTypes.reserve(assign->vars.size);
1713
1714
auto [head, tail] = flatten(resultPack);
1715
if (head.size() >= assign->vars.size)
1716
{
1717
// If the resultPack is definitely long enough for each variable, we can
1718
// skip the UnpackConstraint and use the result typeArguments directly.
1719
1720
for (size_t i = 0; i < assign->vars.size; ++i)
1721
valueTypes.push_back(head[i]);
1722
}
1723
else
1724
{
1725
// We're not sure how many typeArguments are produced by the right-side
1726
// expressions. We'll use an UnpackConstraint to defer this until
1727
// later.
1728
for (size_t i = 0; i < assign->vars.size; ++i)
1729
valueTypes.push_back(arena->addType(BlockedType{}));
1730
1731
auto uc = addConstraint(scope, assign->location, UnpackConstraint{valueTypes, resultPack});
1732
1733
for (TypeId t : valueTypes)
1734
getMutable<BlockedType>(t)->setOwner(uc);
1735
}
1736
1737
for (size_t i = 0; i < assign->vars.size; ++i)
1738
{
1739
visitLValue(scope, assign->vars.data[i], valueTypes[i]);
1740
}
1741
1742
return ControlFlow::None;
1743
}
1744
1745
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatCompoundAssign* assign)
1746
{
1747
TypeId resultTy = checkAstExprBinary(scope, assign->location, assign->op, assign->var, assign->value, std::nullopt).ty;
1748
module->astCompoundAssignResultTypes[assign] = resultTy;
1749
// NOTE: We do not update lvalues for compound assignments. This is
1750
// intentional.
1751
return ControlFlow::None;
1752
}
1753
1754
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatIf* ifStatement)
1755
{
1756
RefinementId refinement = [&]()
1757
{
1758
InConditionalContext flipper{&typeContext};
1759
return check(scope, ifStatement->condition, std::nullopt).refinement;
1760
}();
1761
1762
ScopePtr thenScope = childScope(ifStatement->thenbody, scope);
1763
applyRefinements(thenScope, ifStatement->condition->location, refinement);
1764
1765
ScopePtr elseScope = childScope(ifStatement->elsebody ? ifStatement->elsebody : ifStatement, scope);
1766
applyRefinements(elseScope, ifStatement->elseLocation.value_or(ifStatement->condition->location), refinementArena.negation(refinement));
1767
1768
ControlFlow thencf = visit(thenScope, ifStatement->thenbody);
1769
ControlFlow elsecf = ControlFlow::None;
1770
if (ifStatement->elsebody)
1771
elsecf = visit(elseScope, ifStatement->elsebody);
1772
1773
if (thencf != ControlFlow::None && elsecf == ControlFlow::None)
1774
scope->inheritRefinements(elseScope);
1775
else if (thencf == ControlFlow::None && elsecf != ControlFlow::None)
1776
scope->inheritRefinements(thenScope);
1777
1778
if (thencf == ControlFlow::None)
1779
scope->inheritAssignments(thenScope);
1780
if (elsecf == ControlFlow::None)
1781
scope->inheritAssignments(elseScope);
1782
1783
if (thencf == elsecf)
1784
return thencf;
1785
else if (matches(thencf, ControlFlow::Returns | ControlFlow::Throws) && matches(elsecf, ControlFlow::Returns | ControlFlow::Throws))
1786
return ControlFlow::Returns;
1787
else
1788
return ControlFlow::None;
1789
}
1790
1791
void ConstraintGenerator::resolveGenericDefaultParameters(const ScopePtr& defnScope, AstStatTypeAlias* alias, const TypeFun& fun)
1792
{
1793
LUAU_ASSERT(alias->generics.size == fun.typeParams.size());
1794
for (size_t i = 0; i < alias->generics.size; i++)
1795
{
1796
auto astTy = alias->generics.data[i];
1797
auto param = fun.typeParams[i];
1798
if (param.defaultValue && astTy->defaultValue != nullptr)
1799
{
1800
auto resolvesTo = astTy->defaultValue;
1801
auto toUnblock = *param.defaultValue;
1802
emplaceType<BoundType>(asMutable(toUnblock), resolveType(defnScope, resolvesTo, /* inTypeArguments */ false));
1803
}
1804
defnScope->privateTypeBindings[astTy->name.value] = TypeFun{param.ty};
1805
}
1806
1807
LUAU_ASSERT(alias->genericPacks.size == fun.typePackParams.size());
1808
for (size_t i = 0; i < alias->genericPacks.size; i++)
1809
{
1810
auto astPack = alias->genericPacks.data[i];
1811
auto param = fun.typePackParams[i];
1812
if (param.defaultValue && astPack->defaultValue != nullptr)
1813
{
1814
auto resolvesTo = astPack->defaultValue;
1815
auto toUnblock = *param.defaultValue;
1816
emplaceTypePack<BoundTypePack>(asMutable(toUnblock), resolveTypePack(defnScope, resolvesTo, /* inTypeArguments */ false));
1817
}
1818
defnScope->privateTypePackBindings[astPack->name.value] = param.tp;
1819
}
1820
}
1821
1822
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeAlias* alias)
1823
{
1824
if (alias->name == kParseNameError)
1825
return ControlFlow::None;
1826
1827
if (alias->name == "typeof")
1828
{
1829
reportError(alias->location, ReservedIdentifier{"typeof"});
1830
return ControlFlow::None;
1831
}
1832
1833
scope->typeAliasLocations[alias->name.value] = alias->location;
1834
scope->typeAliasNameLocations[alias->name.value] = alias->nameLocation;
1835
1836
ScopePtr* defnScopePtr = astTypeAliasDefiningScopes.find(alias);
1837
1838
std::unordered_map<Name, TypeFun>* typeBindings;
1839
if (alias->exported)
1840
typeBindings = &scope->exportedTypeBindings;
1841
else
1842
typeBindings = &scope->privateTypeBindings;
1843
1844
// These will be undefined if the alias was a duplicate definition, in which
1845
// case we just skip over it.
1846
auto bindingIt = typeBindings->find(alias->name.value);
1847
if (bindingIt == typeBindings->end() || defnScopePtr == nullptr)
1848
return ControlFlow::None;
1849
1850
ScopePtr defnScope = *defnScopePtr;
1851
resolveGenericDefaultParameters(defnScope, alias, bindingIt->second);
1852
1853
TypeId ty = resolveType(
1854
defnScope,
1855
alias->type,
1856
/* inTypeArguments */ false,
1857
/* replaceErrorWithFresh */ false
1858
);
1859
1860
TypeId aliasTy = bindingIt->second.type;
1861
LUAU_ASSERT(get<BlockedType>(aliasTy));
1862
if (occursCheck(aliasTy, ty))
1863
{
1864
emplaceType<BoundType>(asMutable(aliasTy), builtinTypes->anyType);
1865
reportError(alias->nameLocation, OccursCheckFailed{});
1866
}
1867
else
1868
emplaceType<BoundType>(asMutable(aliasTy), ty);
1869
1870
std::vector<TypeId> typeParams;
1871
for (const auto& tyParam : createGenerics(defnScope, alias->generics, /* useCache */ true, /* addTypes */ false))
1872
typeParams.push_back(tyParam.second.ty);
1873
1874
std::vector<TypePackId> typePackParams;
1875
for (const auto& tpParam : createGenericPacks(defnScope, alias->genericPacks, /* useCache */ true, /* addTypes */ false))
1876
typePackParams.push_back(tpParam.second.tp);
1877
1878
addConstraint(
1879
scope,
1880
alias->type->location,
1881
NameConstraint{
1882
ty,
1883
alias->name.value,
1884
/*synthetic=*/false,
1885
std::move(typeParams),
1886
std::move(typePackParams),
1887
}
1888
);
1889
1890
return ControlFlow::None;
1891
}
1892
1893
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatTypeFunction* function)
1894
{
1895
if (function->name == "typeof")
1896
{
1897
reportError(function->location, ReservedIdentifier{"typeof"});
1898
}
1899
1900
auto scopeIt = astTypeFunctionEnvironmentScopes.find(function);
1901
LUAU_ASSERT(scopeIt);
1902
1903
ScopePtr environmentScope = *scopeIt;
1904
1905
Checkpoint startCheckpoint = checkpoint(this);
1906
FunctionSignature sig = checkFunctionSignature(environmentScope, function->body, /* expectedType */ std::nullopt);
1907
1908
// Place this function as a child of the non-type function scope
1909
scope->children.emplace_back(sig.signatureScope.get());
1910
interiorFreeTypes.emplace_back();
1911
checkFunctionBody(sig.bodyScope, function->body);
1912
Checkpoint endCheckpoint = checkpoint(this);
1913
1914
TypeId generalizedTy = arena->addType(BlockedType{});
1915
NotNull<Constraint> gc = addConstraint(
1916
sig.signatureScope,
1917
function->location,
1918
GeneralizationConstraint{
1919
generalizedTy,
1920
sig.signature,
1921
std::vector<TypeId>{},
1922
}
1923
);
1924
1925
sig.signatureScope->interiorFreeTypes = std::move(interiorFreeTypes.back().types);
1926
sig.signatureScope->interiorFreeTypePacks = std::move(interiorFreeTypes.back().typePacks);
1927
1928
getMutable<BlockedType>(generalizedTy)->setOwner(gc);
1929
interiorFreeTypes.pop_back();
1930
1931
Constraint* previous = nullptr;
1932
forEachConstraint(
1933
startCheckpoint,
1934
endCheckpoint,
1935
this,
1936
[gc, &previous](const ConstraintPtr& constraint)
1937
{
1938
gc->dependencies.emplace_back(constraint.get());
1939
1940
if (auto psc = get<PackSubtypeConstraint>(*constraint); psc && psc->returns)
1941
{
1942
if (previous)
1943
{
1944
constraint->dependencies.emplace_back(previous);
1945
}
1946
1947
previous = constraint.get();
1948
}
1949
}
1950
);
1951
1952
std::optional<TypeId> existingFunctionTy = environmentScope->lookup(function->name);
1953
1954
if (!existingFunctionTy)
1955
ice->ice("checkAliases did not populate type function name", function->nameLocation);
1956
1957
TypeId unpackedTy = follow(*existingFunctionTy);
1958
1959
if (auto bt = get<BlockedType>(unpackedTy); bt && nullptr == bt->getOwner())
1960
emplaceType<BoundType>(asMutable(unpackedTy), generalizedTy);
1961
1962
return ControlFlow::None;
1963
}
1964
1965
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareGlobal* global)
1966
{
1967
LUAU_ASSERT(global->type);
1968
1969
TypeId globalTy = resolveType(scope, global->type, /* inTypeArguments */ false);
1970
Name globalName(global->name.value);
1971
1972
module->declaredGlobals[globalName] = globalTy;
1973
rootScope->bindings[global->name] = Binding{globalTy, global->location};
1974
1975
DefId def = dfg->getDef(global);
1976
rootScope->lvalueTypes[def] = globalTy;
1977
updateRValueRefinements(rootScope, def, globalTy);
1978
1979
return ControlFlow::None;
1980
}
1981
1982
static bool isMetamethod(const Name& name)
1983
{
1984
return name == "__index" || name == "__newindex" || name == "__call" || name == "__concat" || name == "__unm" || name == "__add" ||
1985
name == "__sub" || name == "__mul" || name == "__div" || name == "__mod" || name == "__pow" || name == "__tostring" ||
1986
name == "__metatable" || name == "__eq" || name == "__lt" || name == "__le" || name == "__mode" || name == "__iter" || name == "__len" ||
1987
name == "__idiv";
1988
}
1989
1990
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareExternType* declaredExternType)
1991
{
1992
// If a class with the same name was already defined, we skip over
1993
auto bindingIt = scope->exportedTypeBindings.find(declaredExternType->name.value);
1994
if (bindingIt == scope->exportedTypeBindings.end())
1995
return ControlFlow::None;
1996
1997
std::optional<TypeId> superTy = std::make_optional(builtinTypes->externType);
1998
if (declaredExternType->superName)
1999
{
2000
Name superName = Name(declaredExternType->superName->value);
2001
std::optional<TypeFun> lookupType = scope->lookupType(superName);
2002
2003
if (!lookupType)
2004
{
2005
reportError(declaredExternType->location, UnknownSymbol{std::move(superName), UnknownSymbol::Type});
2006
return ControlFlow::None;
2007
}
2008
2009
// We don't have generic extern typeArguments, so this assertion _should_ never be hit.
2010
LUAU_ASSERT(lookupType->typeParams.size() == 0 && lookupType->typePackParams.size() == 0);
2011
superTy = follow(lookupType->type);
2012
2013
if (!get<ExternType>(follow(*superTy)))
2014
{
2015
reportError(
2016
declaredExternType->location,
2017
GenericError{
2018
format("Cannot use non-class type '%s' as a superclass of class '%s'", superName.c_str(), declaredExternType->name.value)
2019
}
2020
);
2021
2022
// If we don't emplace an error type here, then later we'll be
2023
// exposing a blocked type in this file's type interface. This
2024
// is _normally_ harmless.
2025
emplaceType<BoundType>(asMutable(bindingIt->second.type), builtinTypes->errorType);
2026
2027
return ControlFlow::None;
2028
}
2029
}
2030
2031
Name className(declaredExternType->name.value);
2032
2033
TypeId externTy = arena->addType(ExternType(std::move(className), {}, superTy, std::nullopt, {}, {}, module->name, declaredExternType->location));
2034
ExternType* etv = getMutable<ExternType>(externTy);
2035
2036
TypeId metaTy = arena->addType(TableType{TableState::Sealed, scope->level, scope.get()});
2037
TableType* metatable = getMutable<TableType>(metaTy);
2038
2039
etv->metatable = metaTy;
2040
2041
TypeId classBindTy = bindingIt->second.type;
2042
emplaceType<BoundType>(asMutable(classBindTy), externTy);
2043
2044
if (declaredExternType->indexer)
2045
{
2046
if (recursionCount >= DFInt::LuauConstraintGeneratorRecursionLimit)
2047
{
2048
reportCodeTooComplex(declaredExternType->indexer->location);
2049
}
2050
else
2051
{
2052
// I don't think extern types can *be* generic, but if they
2053
// have an indexer over those generics, the polarity is
2054
// mixed.
2055
etv->indexer = TableIndexer{
2056
resolveType(
2057
scope,
2058
declaredExternType->indexer->indexType,
2059
/* inTypeArguments */ false,
2060
/* replaceErrorWithFresh */ false,
2061
/* initialPolarity */ Polarity::Mixed
2062
),
2063
resolveType(
2064
scope,
2065
declaredExternType->indexer->resultType,
2066
/* inTypeArguments */ false,
2067
/* replaceErrorWithFresh */ false,
2068
/* initialPolarity */ Polarity::Mixed
2069
),
2070
};
2071
}
2072
}
2073
2074
for (const AstDeclaredExternTypeProperty& externProp : declaredExternType->props)
2075
{
2076
Name propName(externProp.name.value);
2077
TypeId propTy = resolveType(scope, externProp.ty, /* inTypeArguments */ false, /* replaceErrorWithFresh */ false, /* initialPolarity */ Polarity::Mixed);
2078
2079
bool assignToMetatable = isMetamethod(propName);
2080
2081
// Function typeArguments always take 'self', but this isn't reflected in the
2082
// parsed annotation. Add it here.
2083
if (externProp.isMethod)
2084
{
2085
if (FunctionType* ftv = getMutable<FunctionType>(propTy))
2086
{
2087
ftv->argNames.insert(ftv->argNames.begin(), FunctionArgument{"self", {}});
2088
ftv->argTypes = addTypePack({externTy}, ftv->argTypes);
2089
2090
ftv->hasSelf = true;
2091
2092
FunctionDefinition defn;
2093
2094
defn.definitionModuleName = module->name;
2095
defn.definitionLocation = externProp.location;
2096
// No data is preserved for varargLocation
2097
defn.originalNameLocation = externProp.nameLocation;
2098
2099
ftv->definition = defn;
2100
}
2101
}
2102
2103
TableType::Props& props = assignToMetatable ? metatable->props : etv->props;
2104
2105
if (props.count(propName) == 0)
2106
{
2107
Property tableProp;
2108
2109
if (FFlag::LuauExternReadWriteAttributes)
2110
{
2111
if (externProp.access == AstTableAccess::Read)
2112
tableProp = Property::readonly(propTy);
2113
else if (externProp.access == AstTableAccess::Write)
2114
tableProp = Property::writeonly(propTy);
2115
else
2116
tableProp = Property::rw(propTy);
2117
2118
tableProp.location = externProp.location;
2119
}
2120
else
2121
{
2122
tableProp = {propTy, /*deprecated*/ false, /*deprecatedSuggestion*/ "", externProp.location};
2123
}
2124
2125
props[propName] = tableProp;
2126
}
2127
else
2128
{
2129
Luau::Property& prop = props[propName];
2130
bool addedWriteTypeByOverload = false;
2131
2132
if (auto readTy = prop.readTy)
2133
{
2134
// We special-case this logic to keep the intersection flat; otherwise we
2135
// would create a ton of nested intersection typeArguments.
2136
if (const IntersectionType* itv = get<IntersectionType>(*readTy))
2137
{
2138
std::vector<TypeId> options = itv->parts;
2139
options.push_back(propTy);
2140
TypeId newItv = arena->addType(IntersectionType{std::move(options)});
2141
2142
prop.readTy = newItv;
2143
}
2144
else if (get<FunctionType>(*readTy))
2145
{
2146
TypeId intersection = arena->addType(IntersectionType{{*readTy, propTy}});
2147
2148
prop.readTy = intersection;
2149
}
2150
else
2151
{
2152
if (FFlag::LuauExternReadWriteAttributes)
2153
{
2154
if (externProp.access == AstTableAccess::Write && !prop.writeTy.has_value())
2155
{
2156
prop.writeTy = propTy;
2157
addedWriteTypeByOverload = true;
2158
}
2159
else
2160
reportError(
2161
declaredExternType->location,
2162
GenericError{format("Cannot overload read type of non-function extern type member '%s'", propName.c_str())}
2163
);
2164
}
2165
else
2166
{
2167
reportError(
2168
declaredExternType->location,
2169
GenericError{format("Cannot overload read type of non-function extern type member '%s'", propName.c_str())}
2170
);
2171
}
2172
}
2173
}
2174
2175
if (auto writeTy = prop.writeTy; writeTy && !addedWriteTypeByOverload)
2176
{
2177
// We special-case this logic to keep the intersection flat; otherwise we
2178
// would create a ton of nested intersection typeArguments.
2179
if (const IntersectionType* itv = get<IntersectionType>(*writeTy))
2180
{
2181
std::vector<TypeId> options = itv->parts;
2182
options.push_back(propTy);
2183
TypeId newItv = arena->addType(IntersectionType{std::move(options)});
2184
2185
prop.writeTy = newItv;
2186
}
2187
else if (get<FunctionType>(*writeTy))
2188
{
2189
TypeId intersection = arena->addType(IntersectionType{{*writeTy, propTy}});
2190
2191
prop.writeTy = intersection;
2192
}
2193
else
2194
{
2195
if (FFlag::LuauExternReadWriteAttributes)
2196
{
2197
if (externProp.access == AstTableAccess::Read && !prop.readTy.has_value())
2198
prop.readTy = propTy;
2199
else
2200
reportError(
2201
declaredExternType->location,
2202
GenericError{format("Cannot overload write type of non-function extern type member '%s'", propName.c_str())}
2203
);
2204
}
2205
else
2206
{
2207
reportError(
2208
declaredExternType->location,
2209
GenericError{format("Cannot overload write type of non-function extern type member '%s'", propName.c_str())}
2210
);
2211
}
2212
}
2213
}
2214
}
2215
}
2216
2217
return ControlFlow::None;
2218
}
2219
2220
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatDeclareFunction* global)
2221
{
2222
std::vector<std::pair<Name, GenericTypeDefinition>> generics = createGenerics(scope, global->generics);
2223
std::vector<std::pair<Name, GenericTypePackDefinition>> genericPacks = createGenericPacks(scope, global->genericPacks);
2224
2225
std::vector<TypeId> genericTys;
2226
genericTys.reserve(generics.size());
2227
for (auto& [name, generic] : generics)
2228
{
2229
genericTys.push_back(generic.ty);
2230
}
2231
2232
std::vector<TypePackId> genericTps;
2233
genericTps.reserve(genericPacks.size());
2234
for (auto& [name, generic] : genericPacks)
2235
{
2236
genericTps.push_back(generic.tp);
2237
}
2238
2239
ScopePtr funScope = scope;
2240
if (!generics.empty() || !genericPacks.empty())
2241
funScope = childScope(global, scope);
2242
2243
TypePackId paramPack;
2244
TypePackId retPack;
2245
if (FFlag::LuauForwardPolarityForFunctionTypes)
2246
{
2247
paramPack = resolveTypePack(
2248
funScope, global->params, /* inTypeArguments */ false, /* replaceErrorWithFresh */ false, /* initialPolarity */ Polarity::Negative
2249
);
2250
retPack = resolveTypePack(
2251
funScope, global->retTypes, /* inTypeArguments */ false, /* replaceErrorWithFresh */ false, /* initialPolarity */ Polarity::Positive
2252
);
2253
}
2254
else
2255
{
2256
paramPack = resolveTypePack_DEPRECATED(
2257
funScope, global->params, /* inTypeArguments */ false, /* replaceErrorWithFresh */ false, /* initialPolarity */ Polarity::Negative
2258
);
2259
retPack = resolveTypePack(
2260
funScope, global->retTypes, /* inTypeArguments */ false, /* replaceErrorWithFresh */ false, /* initialPolarity */ Polarity::Positive
2261
);
2262
}
2263
2264
FunctionDefinition defn;
2265
2266
defn.definitionModuleName = module->name;
2267
defn.definitionLocation = global->location;
2268
defn.varargLocation = global->vararg ? std::make_optional(global->varargLocation) : std::nullopt;
2269
defn.originalNameLocation = global->nameLocation;
2270
2271
TypeId fnType = arena->addType(FunctionType{TypeLevel{}, std::move(genericTys), std::move(genericTps), paramPack, retPack, defn});
2272
2273
FunctionType* ftv = getMutable<FunctionType>(fnType);
2274
ftv->isCheckedFunction = global->isCheckedFunction();
2275
AstAttr* deprecatedAttr = global->getAttribute(AstAttr::Type::Deprecated);
2276
ftv->isDeprecatedFunction = deprecatedAttr != nullptr;
2277
if (deprecatedAttr)
2278
{
2279
ftv->deprecatedInfo = std::make_shared<AstAttr::DeprecatedInfo>(deprecatedAttr->deprecatedInfo());
2280
}
2281
2282
ftv->argNames.reserve(global->paramNames.size);
2283
for (const auto& el : global->paramNames)
2284
ftv->argNames.emplace_back(FunctionArgument{el.first.value, el.second});
2285
Name fnName(global->name.value);
2286
2287
module->declaredGlobals[fnName] = fnType;
2288
scope->bindings[global->name] = Binding{fnType, global->location};
2289
2290
DefId def = dfg->getDef(global);
2291
rootScope->lvalueTypes[def] = fnType;
2292
updateRValueRefinements(rootScope, def, fnType);
2293
2294
return ControlFlow::None;
2295
}
2296
2297
ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatError* error)
2298
{
2299
for (AstStat* stat : error->statements)
2300
visit(scope, stat);
2301
for (AstExpr* expr : error->expressions)
2302
check(scope, expr);
2303
2304
return ControlFlow::None;
2305
}
2306
2307
InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstArray<AstExpr*> exprs, const std::vector<std::optional<TypeId>>& expectedTypes)
2308
{
2309
std::vector<TypeId> head;
2310
std::optional<TypePackId> tail;
2311
2312
for (size_t i = 0; i < exprs.size; ++i)
2313
{
2314
AstExpr* expr = exprs.data[i];
2315
if (i < exprs.size - 1)
2316
{
2317
std::optional<TypeId> expectedType;
2318
if (i < expectedTypes.size())
2319
expectedType = expectedTypes[i];
2320
head.push_back(check(scope, expr, expectedType).ty);
2321
}
2322
else
2323
{
2324
std::vector<std::optional<TypeId>> expectedTailTypes;
2325
if (i < expectedTypes.size())
2326
expectedTailTypes.assign(begin(expectedTypes) + i, end(expectedTypes));
2327
tail = checkPack(scope, expr, expectedTailTypes).tp;
2328
}
2329
}
2330
2331
return InferencePack{addTypePack(std::move(head), tail)};
2332
}
2333
2334
InferencePack ConstraintGenerator::checkPack(
2335
const ScopePtr& scope,
2336
AstExpr* expr,
2337
const std::vector<std::optional<TypeId>>& expectedTypes,
2338
bool generalize
2339
)
2340
{
2341
RecursionCounter counter{&recursionCount};
2342
2343
if (recursionCount >= DFInt::LuauConstraintGeneratorRecursionLimit)
2344
{
2345
reportCodeTooComplex(expr->location);
2346
return InferencePack{builtinTypes->errorTypePack};
2347
}
2348
2349
InferencePack result;
2350
2351
if (AstExprCall* call = expr->as<AstExprCall>())
2352
result = checkPack(scope, call);
2353
else if (expr->is<AstExprVarargs>())
2354
{
2355
if (scope->varargPack)
2356
result = InferencePack{*scope->varargPack};
2357
else
2358
result = InferencePack{builtinTypes->errorTypePack};
2359
}
2360
else
2361
{
2362
std::optional<TypeId> expectedType;
2363
if (!expectedTypes.empty())
2364
expectedType = expectedTypes[0];
2365
TypeId t = check(scope, expr, expectedType, /*forceSingletons*/ false, generalize).ty;
2366
result = InferencePack{arena->addTypePack({t})};
2367
}
2368
2369
LUAU_ASSERT(result.tp);
2370
module->astTypePacks[expr] = result.tp;
2371
return result;
2372
}
2373
2374
InferencePack ConstraintGenerator::checkPack(const ScopePtr& scope, AstExprCall* call)
2375
{
2376
Checkpoint funcBeginCheckpoint = checkpoint(this);
2377
2378
TypeId fnType = nullptr;
2379
{
2380
InConditionalContext icc2{&typeContext, TypeContext::Default};
2381
fnType = check(scope, call->func).ty;
2382
}
2383
2384
Checkpoint funcEndCheckpoint = checkpoint(this);
2385
2386
return checkExprCall(scope, call, fnType, funcBeginCheckpoint, funcEndCheckpoint);
2387
}
2388
2389
InferencePack ConstraintGenerator::checkExprCall(
2390
const ScopePtr& scope,
2391
AstExprCall* call,
2392
TypeId fnType,
2393
Checkpoint funcBeginCheckpoint,
2394
Checkpoint funcEndCheckpoint
2395
)
2396
{
2397
std::vector<AstExpr*> exprArgs;
2398
2399
std::vector<RefinementId> returnRefinements;
2400
std::vector<std::optional<TypeId>> discriminantTypes;
2401
2402
if (call->self)
2403
{
2404
AstExprIndexName* indexExpr = call->func->as<AstExprIndexName>();
2405
if (!indexExpr)
2406
ice->ice("method call expression has no 'self'");
2407
2408
exprArgs.push_back(indexExpr->expr);
2409
2410
if (auto key = dfg->getRefinementKey(indexExpr->expr))
2411
{
2412
TypeId discriminantTy = arena->addType(BlockedType{});
2413
returnRefinements.push_back(refinementArena.implicitProposition(key, discriminantTy));
2414
discriminantTypes.emplace_back(discriminantTy);
2415
}
2416
else
2417
discriminantTypes.emplace_back(std::nullopt);
2418
}
2419
2420
for (AstExpr* arg : call->args)
2421
{
2422
exprArgs.push_back(arg);
2423
2424
if (auto key = dfg->getRefinementKey(arg))
2425
{
2426
TypeId discriminantTy = arena->addType(BlockedType{});
2427
returnRefinements.push_back(refinementArena.implicitProposition(key, discriminantTy));
2428
discriminantTypes.emplace_back(discriminantTy);
2429
}
2430
else
2431
discriminantTypes.emplace_back(std::nullopt);
2432
}
2433
2434
std::vector<std::optional<TypeId>> expectedTypesForCall = getExpectedCallTypesForFunctionOverloads(fnType);
2435
2436
module->astOriginalCallTypes[call->func] = fnType;
2437
2438
Checkpoint argBeginCheckpoint = checkpoint(this);
2439
2440
std::vector<TypeId> args;
2441
std::optional<TypePackId> argTail;
2442
std::vector<RefinementId> argumentRefinements;
2443
2444
for (size_t i = 0; i < exprArgs.size(); ++i)
2445
{
2446
AstExpr* arg = exprArgs[i];
2447
2448
if (i == 0 && call->self)
2449
{
2450
// The self type has already been computed as a side effect of
2451
// computing fnType. If computing that did not cause us to exceed a
2452
// recursion limit, we can fetch it from astTypes rather than
2453
// recomputing it.
2454
TypeId* selfTy = module->astTypes.find(exprArgs[0]);
2455
if (selfTy)
2456
args.push_back(*selfTy);
2457
else
2458
args.push_back(freshType(scope, Polarity::Negative));
2459
}
2460
else if (i < exprArgs.size() - 1 || !(arg->is<AstExprCall>() || arg->is<AstExprVarargs>()))
2461
{
2462
std::optional<TypeId> expectedType = std::nullopt;
2463
if (i < expectedTypesForCall.size())
2464
{
2465
expectedType = expectedTypesForCall[i];
2466
}
2467
if (i == 0 && matchAssert(*call))
2468
{
2469
InConditionalContext flipper{&typeContext};
2470
auto [ty, refinement] = check(scope, arg, expectedType, /*forceSingleton*/ false, /*generalize*/ false);
2471
args.push_back(ty);
2472
argumentRefinements.push_back(refinement);
2473
}
2474
else
2475
{
2476
auto [ty, refinement] = check(scope, arg, expectedType, /*forceSingleton*/ false, /*generalize*/ false);
2477
args.push_back(ty);
2478
argumentRefinements.push_back(refinement);
2479
}
2480
}
2481
else
2482
{
2483
std::vector<std::optional<Luau::TypeId>> expectedTypes = {};
2484
if (i < expectedTypesForCall.size())
2485
{
2486
expectedTypes.insert(expectedTypes.end(), expectedTypesForCall.begin() + int(i), expectedTypesForCall.end());
2487
}
2488
auto [tp, refis] = checkPack(scope, arg, expectedTypes);
2489
argTail = tp;
2490
argumentRefinements.insert(argumentRefinements.end(), refis.begin(), refis.end());
2491
}
2492
}
2493
2494
Checkpoint argEndCheckpoint = checkpoint(this);
2495
2496
if (matchSetMetatable(*call))
2497
{
2498
TypePack argTailPack;
2499
if (argTail && args.size() < 2)
2500
argTailPack = extendTypePack(*arena, builtinTypes, *argTail, 2 - args.size());
2501
2502
TypeId target = nullptr;
2503
TypeId mt = nullptr;
2504
2505
if (args.size() + argTailPack.head.size() == 2)
2506
{
2507
target = args.size() > 0 ? args[0] : argTailPack.head[0];
2508
mt = args.size() > 1 ? args[1] : argTailPack.head[args.size() == 0 ? 1 : 0];
2509
}
2510
else
2511
{
2512
std::vector<TypeId> unpackedTypes;
2513
if (args.size() > 0)
2514
target = follow(args[0]);
2515
else
2516
{
2517
target = arena->addType(BlockedType{});
2518
unpackedTypes.emplace_back(target);
2519
}
2520
2521
mt = arena->addType(BlockedType{});
2522
unpackedTypes.emplace_back(mt);
2523
2524
auto c = addConstraint(scope, call->location, UnpackConstraint{std::move(unpackedTypes), *argTail});
2525
getMutable<BlockedType>(mt)->setOwner(c);
2526
if (auto b = getMutable<BlockedType>(target); b && b->getOwner() == nullptr)
2527
b->setOwner(c);
2528
}
2529
2530
LUAU_ASSERT(target);
2531
LUAU_ASSERT(mt);
2532
2533
target = follow(target);
2534
2535
AstExpr* targetExpr = call->args.data[0];
2536
2537
TypeId resultTy = nullptr;
2538
2539
if (isTableUnion(target))
2540
{
2541
const UnionType* targetUnion = get<UnionType>(target);
2542
UnionBuilder ub{arena, builtinTypes};
2543
2544
for (TypeId ty : targetUnion)
2545
ub.add(arena->addType(MetatableType{ty, mt}));
2546
2547
resultTy = ub.build();
2548
}
2549
else
2550
resultTy = arena->addType(MetatableType{target, mt});
2551
2552
if (AstExprLocal* targetLocal = targetExpr->as<AstExprLocal>())
2553
{
2554
scope->bindings[targetLocal->local].typeId = resultTy;
2555
2556
DefId def = dfg->getDef(targetLocal);
2557
scope->lvalueTypes[def] = resultTy; // TODO: typestates: track this as an assignment
2558
updateRValueRefinements(scope, def, resultTy); // TODO: typestates: track this as an assignment
2559
2560
// HACK: If we have a targetLocal, it has already been added to the
2561
// inferredBindings table. We want to replace it so that we don't
2562
// infer a weird union like tbl | { @metatable something, tbl }
2563
if (InferredBinding* ib = inferredBindings.find(targetLocal->local))
2564
ib->types.erase(target);
2565
2566
recordInferredBinding(targetLocal->local, resultTy);
2567
}
2568
2569
return InferencePack{arena->addTypePack({resultTy}), {refinementArena.variadic(returnRefinements)}};
2570
}
2571
2572
if (shouldTypestateForFirstArgument(*call) && call->args.size > 0 && isLValue(call->args.data[0]))
2573
{
2574
AstExpr* targetExpr = call->args.data[0];
2575
auto resultTy = arena->addType(BlockedType{});
2576
2577
if (auto def = dfg->getDefOptional(targetExpr))
2578
{
2579
scope->lvalueTypes[*def] = resultTy;
2580
updateRValueRefinements(scope, *def, resultTy);
2581
}
2582
}
2583
2584
if (matchAssert(*call) && !argumentRefinements.empty())
2585
applyRefinements(scope, call->args.data[0]->location, argumentRefinements[0]);
2586
2587
// TODO: How do expectedTypes play into this? Do they?
2588
TypePackId rets = arena->addTypePack(BlockedTypePack{});
2589
TypePackId argPack = addTypePack(std::move(args), argTail);
2590
FunctionType ftv(TypeLevel{}, argPack, rets, std::nullopt, call->self);
2591
2592
auto [explicitTypeIds, explicitTypePackIds] = FFlag::LuauExplicitTypeInstantiationSupport && call->typeArguments.size
2593
? resolveTypeArguments(scope, call->typeArguments)
2594
: std::pair<std::vector<TypeId>, std::vector<TypePackId>>();
2595
2596
/*
2597
* To make bidirectional type checking work, we need to solve these constraints in a particular order:
2598
*
2599
* 1. Solve the function type
2600
* 2. Propagate type information from the function type to the argument typeArguments
2601
* 3. Solve the argument typeArguments
2602
* 4. Solve the call
2603
*/
2604
2605
NotNull<Constraint> checkConstraint = addConstraint(
2606
scope, call->func->location, FunctionCheckConstraint{fnType, argPack, call, NotNull{&module->astTypes}, NotNull{&module->astExpectedTypes}}
2607
);
2608
2609
forEachConstraint(
2610
funcBeginCheckpoint,
2611
funcEndCheckpoint,
2612
this,
2613
[checkConstraint](const ConstraintPtr& constraint)
2614
{
2615
checkConstraint->dependencies.emplace_back(constraint.get());
2616
}
2617
);
2618
2619
NotNull<Constraint> callConstraint = addConstraint(
2620
scope,
2621
call->func->location,
2622
FunctionCallConstraint{
2623
fnType,
2624
argPack,
2625
rets,
2626
call,
2627
std::move(discriminantTypes),
2628
std::move(explicitTypeIds),
2629
std::move(explicitTypePackIds),
2630
&module->astOverloadResolvedTypes,
2631
}
2632
);
2633
2634
getMutable<BlockedTypePack>(rets)->owner = callConstraint.get();
2635
2636
callConstraint->dependencies.push_back(checkConstraint);
2637
2638
forEachConstraint(
2639
argBeginCheckpoint,
2640
argEndCheckpoint,
2641
this,
2642
[checkConstraint, callConstraint](const ConstraintPtr& constraint)
2643
{
2644
constraint->dependencies.emplace_back(checkConstraint);
2645
callConstraint->dependencies.emplace_back(constraint.get());
2646
}
2647
);
2648
2649
return InferencePack{rets, {refinementArena.variadic(returnRefinements)}};
2650
}
2651
2652
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExpr* expr, std::optional<TypeId> expectedType, bool forceSingleton, bool generalize)
2653
{
2654
RecursionCounter counter{&recursionCount};
2655
2656
if (recursionCount >= DFInt::LuauConstraintGeneratorRecursionLimit)
2657
{
2658
reportCodeTooComplex(expr->location);
2659
return Inference{builtinTypes->errorType};
2660
}
2661
2662
// We may recurse a given expression more than once when checking compound
2663
// assignment, so we store and cache expressions here s.t. when we generate
2664
// constraints for something like:
2665
//
2666
// a[b] += c
2667
//
2668
// We only solve _one_ set of constraints for `b`.
2669
if (inferredExprCache.contains(expr))
2670
return inferredExprCache[expr];
2671
2672
Inference result;
2673
2674
if (auto group = expr->as<AstExprGroup>())
2675
result = check(scope, group->expr, expectedType, forceSingleton, generalize);
2676
else if (auto stringExpr = expr->as<AstExprConstantString>())
2677
result = check(scope, stringExpr, expectedType, forceSingleton);
2678
else if (expr->is<AstExprConstantNumber>())
2679
result = Inference{builtinTypes->numberType};
2680
else if (expr->is<AstExprConstantInteger>())
2681
result = Inference{builtinTypes->integerType};
2682
else if (auto boolExpr = expr->as<AstExprConstantBool>())
2683
result = check(scope, boolExpr, expectedType, forceSingleton);
2684
else if (expr->is<AstExprConstantNil>())
2685
result = Inference{builtinTypes->nilType};
2686
else if (auto local = expr->as<AstExprLocal>())
2687
result = check(scope, local);
2688
else if (auto global = expr->as<AstExprGlobal>())
2689
result = check(scope, global);
2690
else if (expr->is<AstExprVarargs>())
2691
result = flattenPack(scope, expr->location, checkPack(scope, expr));
2692
else if (auto call = expr->as<AstExprCall>())
2693
result = flattenPack(scope, expr->location, checkPack(scope, call)); // TODO: needs predicates too
2694
else if (auto a = expr->as<AstExprFunction>())
2695
result = check(scope, a, expectedType, generalize);
2696
else if (auto indexName = expr->as<AstExprIndexName>())
2697
result = check(scope, indexName);
2698
else if (auto indexExpr = expr->as<AstExprIndexExpr>())
2699
result = check(scope, indexExpr);
2700
else if (auto table = expr->as<AstExprTable>())
2701
result = check(scope, table, expectedType);
2702
else if (auto unary = expr->as<AstExprUnary>())
2703
result = check(scope, unary);
2704
else if (auto binary = expr->as<AstExprBinary>())
2705
result = check(scope, binary, expectedType);
2706
else if (auto ifElse = expr->as<AstExprIfElse>())
2707
result = check(scope, ifElse, expectedType);
2708
else if (auto typeAssert = expr->as<AstExprTypeAssertion>())
2709
result = check(scope, typeAssert);
2710
else if (auto interpString = expr->as<AstExprInterpString>())
2711
result = check(scope, interpString);
2712
else if (auto explicitTypeInstantiation = expr->as<AstExprInstantiate>())
2713
result = check(scope, explicitTypeInstantiation);
2714
else if (auto err = expr->as<AstExprError>())
2715
{
2716
// Open question: Should we traverse into this?
2717
for (AstExpr* subExpr : err->expressions)
2718
check(scope, subExpr);
2719
2720
result = Inference{builtinTypes->errorType};
2721
}
2722
else
2723
{
2724
LUAU_ASSERT(0);
2725
result = Inference{freshType(scope)};
2726
}
2727
2728
inferredExprCache[expr] = result;
2729
2730
LUAU_ASSERT(result.ty);
2731
module->astTypes[expr] = result.ty;
2732
if (expectedType)
2733
module->astExpectedTypes[expr] = *expectedType;
2734
return result;
2735
}
2736
2737
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprConstantString* string, std::optional<TypeId> expectedType, bool forceSingleton)
2738
{
2739
2740
if (forceSingleton)
2741
return Inference{arena->addType(SingletonType{StringSingleton{std::string{string->value.data, string->value.size}}})};
2742
2743
// Consider a table like:
2744
//
2745
// local DICTIONARY = { "aback", "abacus", "abandon", --[[ so on and so forth ]] }
2746
//
2747
// The intent is (probably) not for this to be an array-like table with a massive
2748
// union for the value, but instead a `{ string }`.
2749
if (largeTableDepth > 0)
2750
return Inference{builtinTypes->stringType};
2751
2752
TypeId freeTy = freshType(scope, Polarity::Positive);
2753
FreeType* ft = getMutable<FreeType>(freeTy);
2754
LUAU_ASSERT(ft);
2755
ft->lowerBound = arena->addType(SingletonType{StringSingleton{std::string{string->value.data, string->value.size}}});
2756
ft->upperBound = builtinTypes->stringType;
2757
2758
addConstraint(scope, string->location, PrimitiveTypeConstraint{freeTy, expectedType, builtinTypes->stringType});
2759
return Inference{freeTy};
2760
}
2761
2762
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprConstantBool* boolExpr, std::optional<TypeId> expectedType, bool forceSingleton)
2763
{
2764
const TypeId singletonType = boolExpr->value ? builtinTypes->trueType : builtinTypes->falseType;
2765
if (forceSingleton)
2766
return Inference{singletonType};
2767
2768
// Consider a table like:
2769
//
2770
// local FLAGS = {
2771
// Foo = true,
2772
// Bar = false,
2773
// Baz = true,
2774
// -- so on and so forth
2775
// }
2776
//
2777
// The intent is (probably) not for this to be a table where each element
2778
// is potentially `true` or `false` as a singleton, but just `boolean`.
2779
if (largeTableDepth > 0)
2780
return Inference{builtinTypes->booleanType};
2781
2782
TypeId freeTy = freshType(scope, Polarity::Positive);
2783
FreeType* ft = getMutable<FreeType>(freeTy);
2784
LUAU_ASSERT(ft);
2785
ft->lowerBound = singletonType;
2786
ft->upperBound = builtinTypes->booleanType;
2787
2788
addConstraint(scope, boolExpr->location, PrimitiveTypeConstraint{freeTy, expectedType, builtinTypes->booleanType});
2789
return Inference{freeTy};
2790
}
2791
2792
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprLocal* local)
2793
{
2794
const RefinementKey* key = dfg->getRefinementKey(local);
2795
LUAU_ASSERT(key);
2796
2797
std::optional<TypeId> maybeTy;
2798
2799
// if we have a refinement key, we can look up its type.
2800
if (key)
2801
maybeTy = lookup(scope, local->location, key->def);
2802
2803
if (maybeTy)
2804
{
2805
TypeId ty = follow(*maybeTy);
2806
2807
recordInferredBinding(local->local, ty);
2808
2809
return Inference{ty, refinementArena.proposition(key, builtinTypes->truthyType)};
2810
}
2811
else
2812
ice->ice("CG: AstExprLocal came before its declaration?");
2813
}
2814
2815
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprGlobal* global)
2816
{
2817
const RefinementKey* key = dfg->getRefinementKey(global);
2818
LUAU_ASSERT(key);
2819
2820
DefId def = key->def;
2821
2822
/* prepopulateGlobalScope() has already added all global functions to the environment by this point, so any
2823
* global that is not already in-scope is definitely an unknown symbol.
2824
*/
2825
if (auto ty = lookup(scope, global->location, def, /*prototype=*/false))
2826
{
2827
if (!FFlag::LuauCaptureRecursiveCallsForTablesAndGlobals2)
2828
rootScope->lvalueTypes[def] = *ty;
2829
return Inference{*ty, refinementArena.proposition(key, builtinTypes->truthyType)};
2830
}
2831
else
2832
return Inference{builtinTypes->errorType};
2833
}
2834
2835
Inference ConstraintGenerator::checkIndexName(
2836
const ScopePtr& scope,
2837
const RefinementKey* key,
2838
AstExpr* indexee,
2839
const std::string& index,
2840
Location indexLocation
2841
)
2842
{
2843
TypeId obj = check(scope, indexee).ty;
2844
TypeId result = nullptr;
2845
2846
// We optimize away the HasProp constraint in simple cases so that we can
2847
// reason about updates to unsealed tables more accurately.
2848
2849
const TableType* tt = getTableType(obj);
2850
2851
// This is a little bit iffy but I *believe* it is okay because, if the
2852
// local's domain is going to be extended at all, it will be someplace after
2853
// the current lexical position within the script.
2854
if (!tt)
2855
{
2856
if (TypeIds* localDomain = localTypes.find(obj); localDomain && 1 == localDomain->size())
2857
tt = getTableType(*localDomain->begin());
2858
}
2859
2860
if (tt)
2861
{
2862
auto it = tt->props.find(index);
2863
if (it != tt->props.end() && it->second.readTy.has_value())
2864
result = *it->second.readTy;
2865
}
2866
2867
if (auto cachedHasPropResult = propIndexPairsSeen.find({obj, index}))
2868
result = *cachedHasPropResult;
2869
2870
if (!result)
2871
{
2872
result = arena->addType(BlockedType{});
2873
2874
auto c = addConstraint(scope, indexee->location, HasPropConstraint{result, obj, index, ValueContext::RValue, inConditional(typeContext)});
2875
getMutable<BlockedType>(result)->setOwner(c);
2876
propIndexPairsSeen[{obj, index}] = result;
2877
}
2878
2879
if (key)
2880
{
2881
if (auto ty = lookup(scope, indexLocation, key->def, false))
2882
return Inference{*ty, refinementArena.proposition(key, builtinTypes->truthyType)};
2883
2884
updateRValueRefinements(scope, key->def, result);
2885
}
2886
2887
if (key)
2888
return Inference{result, refinementArena.proposition(key, builtinTypes->truthyType)};
2889
else
2890
return Inference{result};
2891
}
2892
2893
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIndexName* indexName)
2894
{
2895
const RefinementKey* key = dfg->getRefinementKey(indexName);
2896
return checkIndexName(scope, key, indexName->expr, indexName->index.value, indexName->indexLocation);
2897
}
2898
2899
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIndexExpr* indexExpr)
2900
{
2901
if (auto constantString = indexExpr->index->as<AstExprConstantString>())
2902
{
2903
module->astTypes[indexExpr->index] = builtinTypes->stringType;
2904
const RefinementKey* key = dfg->getRefinementKey(indexExpr);
2905
return checkIndexName(scope, key, indexExpr->expr, constantString->value.data, indexExpr->location);
2906
}
2907
2908
TypeId obj = check(scope, indexExpr->expr).ty;
2909
TypeId indexType = check(scope, indexExpr->index).ty;
2910
2911
TypeId result = arena->addType(BlockedType{});
2912
2913
const RefinementKey* key = dfg->getRefinementKey(indexExpr);
2914
if (key)
2915
{
2916
if (auto ty = lookup(scope, indexExpr->location, key->def))
2917
return Inference{*ty, refinementArena.proposition(key, builtinTypes->truthyType)};
2918
updateRValueRefinements(scope, key->def, result);
2919
}
2920
2921
auto c = addConstraint(scope, indexExpr->expr->location, HasIndexerConstraint{result, obj, indexType});
2922
getMutable<BlockedType>(result)->setOwner(c);
2923
2924
if (key)
2925
return Inference{result, refinementArena.proposition(key, builtinTypes->truthyType)};
2926
else
2927
return Inference{result};
2928
}
2929
2930
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprFunction* func, std::optional<TypeId> expectedType, bool generalize)
2931
{
2932
InConditionalContext inContext(&typeContext, TypeContext::Default);
2933
2934
Checkpoint startCheckpoint = checkpoint(this);
2935
FunctionSignature sig = checkFunctionSignature(scope, func, expectedType);
2936
2937
interiorFreeTypes.emplace_back();
2938
checkFunctionBody(sig.bodyScope, func);
2939
Checkpoint endCheckpoint = checkpoint(this);
2940
2941
TypeId generalizedTy = arena->addType(BlockedType{});
2942
NotNull<Constraint> gc = addConstraint(
2943
sig.signatureScope,
2944
func->location,
2945
GeneralizationConstraint{
2946
generalizedTy,
2947
sig.signature,
2948
std::vector<TypeId>{},
2949
}
2950
);
2951
2952
sig.signatureScope->interiorFreeTypes = std::move(interiorFreeTypes.back().types);
2953
sig.signatureScope->interiorFreeTypePacks = std::move(interiorFreeTypes.back().typePacks);
2954
interiorFreeTypes.pop_back();
2955
2956
getMutable<BlockedType>(generalizedTy)->setOwner(gc);
2957
2958
Constraint* previous = nullptr;
2959
forEachConstraint(
2960
startCheckpoint,
2961
endCheckpoint,
2962
this,
2963
[gc, &previous](const ConstraintPtr& constraint)
2964
{
2965
gc->dependencies.emplace_back(constraint.get());
2966
2967
if (auto psc = get<PackSubtypeConstraint>(*constraint); psc && psc->returns)
2968
{
2969
if (previous)
2970
{
2971
constraint->dependencies.emplace_back(previous);
2972
}
2973
2974
previous = constraint.get();
2975
}
2976
}
2977
);
2978
2979
if (generalize && hasFreeType(sig.signature))
2980
{
2981
return Inference{generalizedTy};
2982
}
2983
else
2984
{
2985
return Inference{sig.signature};
2986
}
2987
}
2988
2989
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprUnary* unary)
2990
{
2991
std::optional<InConditionalContext> inContext;
2992
if (unary->op != AstExprUnary::Op::Not)
2993
inContext.emplace(&typeContext, TypeContext::Default);
2994
2995
auto [operandType, refinement] = check(scope, unary->expr);
2996
2997
switch (unary->op)
2998
{
2999
case AstExprUnary::Op::Not:
3000
{
3001
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->notFunc, {operandType}, {}, scope, unary->location);
3002
return Inference{resultType, refinementArena.negation(refinement)};
3003
}
3004
case AstExprUnary::Op::Len:
3005
{
3006
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->lenFunc, {operandType}, {}, scope, unary->location);
3007
return Inference{resultType, std::move(refinement)};
3008
}
3009
case AstExprUnary::Op::Minus:
3010
{
3011
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->unmFunc, {operandType}, {}, scope, unary->location);
3012
return Inference{resultType, std::move(refinement)};
3013
}
3014
default: // msvc can't prove that this is exhaustive.
3015
LUAU_UNREACHABLE();
3016
}
3017
}
3018
3019
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprBinary* binary, std::optional<TypeId> expectedType)
3020
{
3021
return checkAstExprBinary(scope, binary->location, binary->op, binary->left, binary->right, expectedType);
3022
}
3023
3024
Inference ConstraintGenerator::checkAstExprBinary(
3025
const ScopePtr& scope,
3026
const Location& location,
3027
AstExprBinary::Op op,
3028
AstExpr* left,
3029
AstExpr* right,
3030
std::optional<TypeId> expectedType
3031
)
3032
{
3033
auto [leftType, rightType, refinement] = checkBinary(scope, op, left, right, expectedType);
3034
3035
switch (op)
3036
{
3037
case AstExprBinary::Op::Add:
3038
{
3039
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->addFunc, {leftType, rightType}, {}, scope, location);
3040
return Inference{resultType, std::move(refinement)};
3041
}
3042
case AstExprBinary::Op::Sub:
3043
{
3044
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->subFunc, {leftType, rightType}, {}, scope, location);
3045
return Inference{resultType, std::move(refinement)};
3046
}
3047
case AstExprBinary::Op::Mul:
3048
{
3049
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->mulFunc, {leftType, rightType}, {}, scope, location);
3050
return Inference{resultType, std::move(refinement)};
3051
}
3052
case AstExprBinary::Op::Div:
3053
{
3054
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->divFunc, {leftType, rightType}, {}, scope, location);
3055
return Inference{resultType, std::move(refinement)};
3056
}
3057
case AstExprBinary::Op::FloorDiv:
3058
{
3059
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->idivFunc, {leftType, rightType}, {}, scope, location);
3060
return Inference{resultType, std::move(refinement)};
3061
}
3062
case AstExprBinary::Op::Pow:
3063
{
3064
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->powFunc, {leftType, rightType}, {}, scope, location);
3065
return Inference{resultType, std::move(refinement)};
3066
}
3067
case AstExprBinary::Op::Mod:
3068
{
3069
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->modFunc, {leftType, rightType}, {}, scope, location);
3070
return Inference{resultType, std::move(refinement)};
3071
}
3072
case AstExprBinary::Op::Concat:
3073
{
3074
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->concatFunc, {leftType, rightType}, {}, scope, location);
3075
return Inference{resultType, std::move(refinement)};
3076
}
3077
case AstExprBinary::Op::And:
3078
{
3079
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->andFunc, {leftType, rightType}, {}, scope, location);
3080
return Inference{resultType, std::move(refinement)};
3081
}
3082
case AstExprBinary::Op::Or:
3083
{
3084
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->orFunc, {leftType, rightType}, {}, scope, location);
3085
return Inference{resultType, std::move(refinement)};
3086
}
3087
case AstExprBinary::Op::CompareLt:
3088
{
3089
addConstraint(scope, location, EqualityConstraint{leftType, rightType});
3090
return Inference{builtinTypes->booleanType, std::move(refinement)};
3091
}
3092
case AstExprBinary::Op::CompareGe:
3093
{
3094
addConstraint(scope, location, EqualityConstraint{leftType, rightType});
3095
return Inference{builtinTypes->booleanType, std::move(refinement)};
3096
}
3097
case AstExprBinary::Op::CompareLe:
3098
{
3099
addConstraint(scope, location, EqualityConstraint{leftType, rightType});
3100
return Inference{builtinTypes->booleanType, std::move(refinement)};
3101
}
3102
case AstExprBinary::Op::CompareGt:
3103
{
3104
addConstraint(scope, location, EqualityConstraint{leftType, rightType});
3105
return Inference{builtinTypes->booleanType, std::move(refinement)};
3106
}
3107
case AstExprBinary::Op::CompareEq:
3108
case AstExprBinary::Op::CompareNe:
3109
return Inference{builtinTypes->booleanType, std::move(refinement)};
3110
case AstExprBinary::Op::Op__Count:
3111
ice->ice("Op__Count should never be generated in an AST.");
3112
default: // msvc can't prove that this is exhaustive.
3113
LUAU_UNREACHABLE();
3114
}
3115
}
3116
3117
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprIfElse* ifElse, std::optional<TypeId> expectedType)
3118
{
3119
InConditionalContext inContext(&typeContext, TypeContext::Default);
3120
3121
RefinementId refinement = [&]()
3122
{
3123
InConditionalContext flipper{&typeContext};
3124
ScopePtr condScope = childScope(ifElse->condition, scope);
3125
return check(condScope, ifElse->condition).refinement;
3126
}();
3127
3128
ScopePtr thenScope = childScope(ifElse->trueExpr, scope);
3129
applyRefinements(thenScope, ifElse->trueExpr->location, refinement);
3130
TypeId thenType = check(thenScope, ifElse->trueExpr, expectedType).ty;
3131
3132
ScopePtr elseScope = childScope(ifElse->falseExpr, scope);
3133
applyRefinements(elseScope, ifElse->falseExpr->location, refinementArena.negation(refinement));
3134
TypeId elseType = check(elseScope, ifElse->falseExpr, expectedType).ty;
3135
3136
return Inference{makeUnion(scope, ifElse->location, thenType, elseType)};
3137
}
3138
3139
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTypeAssertion* typeAssert)
3140
{
3141
check(scope, typeAssert->expr, std::nullopt);
3142
return Inference{resolveType(scope, typeAssert->annotation, /* inTypeArguments */ false)};
3143
}
3144
3145
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprInterpString* interpString)
3146
{
3147
InConditionalContext inContext(&typeContext, TypeContext::Default);
3148
3149
for (AstExpr* expr : interpString->expressions)
3150
check(scope, expr);
3151
3152
return Inference{builtinTypes->stringType};
3153
}
3154
3155
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprInstantiate* explicitTypeInstantiation)
3156
{
3157
if (!FFlag::LuauExplicitTypeInstantiationSupport)
3158
return check(scope, explicitTypeInstantiation->expr);
3159
3160
TypeId functionType = check(scope, explicitTypeInstantiation->expr, std::nullopt).ty;
3161
3162
auto [explicitTypeIds, explicitTypePackIds] = resolveTypeArguments(scope, explicitTypeInstantiation->typeArguments);
3163
3164
TypeId placeholderType = arena->addType(BlockedType{});
3165
3166
NotNull<Constraint> constraint = addConstraint(
3167
scope,
3168
explicitTypeInstantiation->location,
3169
TypeInstantiationConstraint{functionType, placeholderType, std::move(explicitTypeIds), std::move(explicitTypePackIds)}
3170
);
3171
3172
getMutable<BlockedType>(placeholderType)->setOwner(constraint);
3173
3174
return Inference{placeholderType};
3175
}
3176
3177
std::pair<std::vector<TypeId>, std::vector<TypePackId>> ConstraintGenerator::resolveTypeArguments(
3178
const ScopePtr& scope,
3179
const AstArray<AstTypeOrPack>& typeArguments
3180
)
3181
{
3182
LUAU_ASSERT(FFlag::LuauExplicitTypeInstantiationSupport);
3183
3184
std::vector<TypeId> resolvedTypeArguments;
3185
std::vector<TypePackId> resolvedTypePackArguments;
3186
3187
for (const AstTypeOrPack& typeOrPack : typeArguments)
3188
{
3189
if (typeOrPack.type)
3190
{
3191
resolvedTypeArguments.push_back(resolveType(
3192
scope,
3193
typeOrPack.type,
3194
/* inTypeArguments = */ false
3195
));
3196
}
3197
else
3198
{
3199
LUAU_ASSERT(typeOrPack.typePack);
3200
resolvedTypePackArguments.push_back(resolveTypePack(
3201
scope,
3202
typeOrPack.typePack,
3203
/* inTypeArguments = */ false
3204
));
3205
}
3206
}
3207
3208
return {std::move(resolvedTypeArguments), std::move(resolvedTypePackArguments)};
3209
}
3210
3211
std::tuple<TypeId, TypeId, RefinementId> ConstraintGenerator::checkBinary(
3212
const ScopePtr& scope,
3213
AstExprBinary::Op op,
3214
AstExpr* left,
3215
AstExpr* right,
3216
std::optional<TypeId> expectedType
3217
)
3218
{
3219
std::optional<InConditionalContext> inContext;
3220
if (op != AstExprBinary::And && op != AstExprBinary::Or && op != AstExprBinary::CompareEq && op != AstExprBinary::CompareNe)
3221
inContext.emplace(&typeContext, TypeContext::Default);
3222
3223
if (op == AstExprBinary::And)
3224
{
3225
std::optional<TypeId> relaxedExpectedLhs;
3226
3227
if (expectedType)
3228
relaxedExpectedLhs = arena->addType(UnionType{{builtinTypes->falsyType, *expectedType}});
3229
3230
auto [leftType, leftRefinement] = check(scope, left, relaxedExpectedLhs);
3231
3232
ScopePtr rightScope = childScope(right, scope);
3233
applyRefinements(rightScope, right->location, leftRefinement);
3234
auto [rightType, rightRefinement] = check(rightScope, right, expectedType);
3235
3236
return {leftType, rightType, refinementArena.conjunction(leftRefinement, rightRefinement)};
3237
}
3238
else if (op == AstExprBinary::Or)
3239
{
3240
std::optional<TypeId> relaxedExpectedLhs;
3241
3242
if (expectedType)
3243
relaxedExpectedLhs = arena->addType(UnionType{{builtinTypes->falsyType, *expectedType}});
3244
3245
auto [leftType, leftRefinement] = check(scope, left, relaxedExpectedLhs);
3246
3247
ScopePtr rightScope = childScope(right, scope);
3248
applyRefinements(rightScope, right->location, refinementArena.negation(leftRefinement));
3249
auto [rightType, rightRefinement] = check(rightScope, right, expectedType);
3250
3251
return {leftType, rightType, refinementArena.disjunction(leftRefinement, rightRefinement)};
3252
}
3253
else if (auto typeguard = matchTypeGuard(op, left, right))
3254
{
3255
TypeId leftType = check(scope, left).ty;
3256
TypeId rightType = check(scope, right).ty;
3257
3258
const RefinementKey* key = dfg->getRefinementKey(typeguard->target);
3259
if (!key)
3260
return {leftType, rightType, nullptr};
3261
3262
TypeId discriminantTy = builtinTypes->neverType;
3263
if (typeguard->type == "nil")
3264
discriminantTy = builtinTypes->nilType;
3265
else if (typeguard->type == "string")
3266
discriminantTy = builtinTypes->stringType;
3267
else if (typeguard->type == "number")
3268
discriminantTy = builtinTypes->numberType;
3269
else if (typeguard->type == "integer")
3270
discriminantTy = builtinTypes->integerType;
3271
else if (typeguard->type == "boolean")
3272
discriminantTy = builtinTypes->booleanType;
3273
else if (typeguard->type == "thread")
3274
discriminantTy = builtinTypes->threadType;
3275
else if (typeguard->type == "buffer")
3276
discriminantTy = builtinTypes->bufferType;
3277
else if (typeguard->type == "table")
3278
discriminantTy = builtinTypes->tableType;
3279
else if (typeguard->type == "function")
3280
discriminantTy = builtinTypes->functionType;
3281
else if (typeguard->type == "userdata")
3282
{
3283
// For now, we don't really care about being accurate with userdata if the typeguard was using typeof.
3284
discriminantTy = builtinTypes->externType;
3285
}
3286
else if (typeguard->type == "vector" && !typeguard->isTypeof)
3287
{
3288
if (FFlag::LuauRefinementTypeVector)
3289
{
3290
// `vector` is defined in EmbeddedBultinDefinitions, not as an actual built-in type
3291
auto typeFun = globalScope->lookupType("vector");
3292
if (typeFun)
3293
discriminantTy = follow(typeFun->type);
3294
}
3295
else
3296
discriminantTy = builtinTypes->neverType; // TODO: figure out a way to deal with this quirky type
3297
}
3298
else if (!typeguard->isTypeof)
3299
discriminantTy = builtinTypes->neverType;
3300
else if (auto typeFun = globalScope->lookupType(typeguard->type); typeFun && typeFun->typeParams.empty() && typeFun->typePackParams.empty())
3301
{
3302
TypeId ty = follow(typeFun->type);
3303
3304
// We're only interested in the root type of any extern type.
3305
if (auto etv = get<ExternType>(ty); etv && (etv->parent == builtinTypes->externType || hasTag(ty, kTypeofRootTag)))
3306
discriminantTy = ty;
3307
}
3308
3309
RefinementId proposition = refinementArena.proposition(key, discriminantTy);
3310
if (op == AstExprBinary::CompareEq)
3311
return {leftType, rightType, proposition};
3312
else if (op == AstExprBinary::CompareNe)
3313
return {leftType, rightType, refinementArena.negation(proposition)};
3314
else
3315
ice->ice("matchTypeGuard should only return a Some under `==` or `~=`!");
3316
}
3317
else if (op == AstExprBinary::CompareEq || op == AstExprBinary::CompareNe)
3318
{
3319
// We are checking a binary expression of the form a op b
3320
// Just because a op b is expected to return a bool, doesn't mean a, b are expected to be bools too
3321
TypeId leftType = check(scope, left, {}, true).ty;
3322
TypeId rightType = check(scope, right, {}, true).ty;
3323
3324
RefinementId leftRefinement = refinementArena.proposition(dfg->getRefinementKey(left), rightType);
3325
RefinementId rightRefinement = refinementArena.proposition(dfg->getRefinementKey(right), leftType);
3326
3327
if (op == AstExprBinary::CompareNe)
3328
{
3329
leftRefinement = refinementArena.negation(leftRefinement);
3330
rightRefinement = refinementArena.negation(rightRefinement);
3331
}
3332
3333
return {leftType, rightType, refinementArena.equivalence(leftRefinement, rightRefinement)};
3334
}
3335
else
3336
{
3337
TypeId leftType = check(scope, left).ty;
3338
TypeId rightType = check(scope, right).ty;
3339
return {leftType, rightType, nullptr};
3340
}
3341
}
3342
3343
void ConstraintGenerator::visitLValue(const ScopePtr& scope, AstExpr* expr, TypeId rhsType)
3344
{
3345
if (auto e = expr->as<AstExprLocal>())
3346
visitLValue(scope, e, rhsType);
3347
else if (auto e = expr->as<AstExprGlobal>())
3348
visitLValue(scope, e, rhsType);
3349
else if (auto e = expr->as<AstExprIndexName>())
3350
visitLValue(scope, e, rhsType);
3351
else if (auto e = expr->as<AstExprIndexExpr>())
3352
visitLValue(scope, e, rhsType);
3353
else if (auto e = expr->as<AstExprError>())
3354
{
3355
// If we end up with some sort of error expression in an lvalue
3356
// position, at least go and check the expressions so that when
3357
// we visit them later, there aren't any invalid assumptions.
3358
for (auto subExpr : e->expressions)
3359
{
3360
check(scope, subExpr);
3361
}
3362
}
3363
else
3364
ice->ice("Unexpected lvalue expression", expr->location);
3365
}
3366
3367
void ConstraintGenerator::visitLValue(const ScopePtr& scope, AstExprLocal* local, TypeId rhsType)
3368
{
3369
std::optional<TypeId> annotatedTy = scope->lookup(local->local);
3370
LUAU_ASSERT(annotatedTy);
3371
3372
const DefId defId = dfg->getDef(local);
3373
std::optional<TypeId> ty = scope->lookupUnrefinedType(defId);
3374
3375
if (ty)
3376
{
3377
TypeIds* localDomain = localTypes.find(*ty);
3378
if (localDomain && !local->upvalue)
3379
localDomain->insert(rhsType);
3380
}
3381
else
3382
{
3383
ty = arena->addType(BlockedType{});
3384
localTypes[*ty].insert(rhsType);
3385
3386
if (annotatedTy)
3387
{
3388
switch (shouldSuppressErrors(normalizer, *annotatedTy))
3389
{
3390
case ErrorSuppression::DoNotSuppress:
3391
break;
3392
case ErrorSuppression::Suppress:
3393
ty = simplifyUnion(scope, local->location, *ty, builtinTypes->errorType);
3394
break;
3395
case ErrorSuppression::NormalizationFailed:
3396
reportError(local->local->annotation->location, NormalizationTooComplex{});
3397
break;
3398
}
3399
}
3400
3401
scope->lvalueTypes[defId] = *ty;
3402
}
3403
3404
recordInferredBinding(local->local, *ty);
3405
3406
if (annotatedTy)
3407
addConstraint(scope, local->location, SubtypeConstraint{rhsType, *annotatedTy});
3408
}
3409
3410
void ConstraintGenerator::visitLValue(const ScopePtr& scope, AstExprGlobal* global, TypeId rhsType)
3411
{
3412
std::optional<TypeId> annotatedTy = scope->lookup(Symbol{global->name});
3413
if (annotatedTy)
3414
{
3415
DefId def = dfg->getDef(global);
3416
rootScope->lvalueTypes[def] = rhsType;
3417
3418
// Ignore possible self-assignment, it doesn't create a new constraint
3419
if (annotatedTy == follow(rhsType))
3420
return;
3421
3422
if (FFlag::LuauKeepExplicitMapForGlobalTypes2)
3423
{
3424
auto followedAnnotation = follow(*annotatedTy);
3425
if (auto bt = get<BlockedType>(followedAnnotation); bt && uninitializedGlobals.contains(global->name))
3426
{
3427
LUAU_ASSERT(bt->getOwner() == nullptr);
3428
uninitializedGlobals.erase(global->name);
3429
emplaceType<BoundType>(asMutable(followedAnnotation), rhsType);
3430
}
3431
}
3432
else
3433
{
3434
// Sketchy: We're specifically looking for BlockedTypes that were
3435
// initially created by ConstraintGenerator::prepopulateGlobalScope.
3436
if (auto bt = get<BlockedType>(follow(*annotatedTy)); bt && !bt->getOwner())
3437
emplaceType<BoundType>(asMutable(*annotatedTy), rhsType);
3438
}
3439
3440
3441
addConstraint(scope, global->location, SubtypeConstraint{rhsType, *annotatedTy});
3442
}
3443
}
3444
3445
void ConstraintGenerator::visitLValue(const ScopePtr& scope, AstExprIndexName* expr, TypeId rhsType)
3446
{
3447
TypeId lhsTy = check(scope, expr->expr).ty;
3448
TypeId propTy = arena->addType(BlockedType{});
3449
module->astTypes[expr] = propTy;
3450
3451
bool incremented = recordPropertyAssignment(lhsTy);
3452
3453
auto apc =
3454
addConstraint(scope, expr->location, AssignPropConstraint{lhsTy, expr->index.value, rhsType, expr->indexLocation, propTy, incremented});
3455
getMutable<BlockedType>(propTy)->setOwner(apc);
3456
}
3457
3458
void ConstraintGenerator::visitLValue(const ScopePtr& scope, AstExprIndexExpr* expr, TypeId rhsType)
3459
{
3460
if (auto constantString = expr->index->as<AstExprConstantString>())
3461
{
3462
TypeId lhsTy = check(scope, expr->expr).ty;
3463
TypeId propTy = arena->addType(BlockedType{});
3464
module->astTypes[expr] = propTy;
3465
module->astTypes[expr->index] = builtinTypes->stringType; // FIXME? Singleton strings exist.
3466
std::string propName{constantString->value.data, constantString->value.size};
3467
3468
bool incremented = recordPropertyAssignment(lhsTy);
3469
3470
auto apc = addConstraint(
3471
scope, expr->location, AssignPropConstraint{lhsTy, std::move(propName), rhsType, expr->index->location, propTy, incremented}
3472
);
3473
getMutable<BlockedType>(propTy)->setOwner(apc);
3474
3475
return;
3476
}
3477
3478
TypeId lhsTy = check(scope, expr->expr).ty;
3479
TypeId indexTy = check(scope, expr->index).ty;
3480
TypeId propTy = arena->addType(BlockedType{});
3481
module->astTypes[expr] = propTy;
3482
auto aic = addConstraint(scope, expr->location, AssignIndexConstraint{lhsTy, indexTy, rhsType, propTy});
3483
getMutable<BlockedType>(propTy)->setOwner(aic);
3484
}
3485
3486
Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprTable* expr, std::optional<TypeId> expectedType)
3487
{
3488
InConditionalContext inContext(&typeContext, TypeContext::Default);
3489
3490
TypeId ty = arena->addType(TableType{});
3491
TableType* ttv = getMutable<TableType>(ty);
3492
LUAU_ASSERT(ttv);
3493
3494
ttv->state = TableState::Unsealed;
3495
ttv->definitionModuleName = module->name;
3496
ttv->definitionLocation = expr->location;
3497
ttv->scope = scope.get();
3498
3499
if (FInt::LuauPrimitiveInferenceInTableLimit > 0 && expr->items.size > size_t(FInt::LuauPrimitiveInferenceInTableLimit))
3500
largeTableDepth++;
3501
3502
interiorFreeTypes.back().types.push_back(ty);
3503
3504
TypeIds indexKeyLowerBound;
3505
TypeIds indexValueLowerBound;
3506
3507
auto createIndexer = [&indexKeyLowerBound, &indexValueLowerBound](const Location& location, TypeId currentIndexType, TypeId currentResultType)
3508
{
3509
indexKeyLowerBound.insert(follow(currentIndexType));
3510
indexValueLowerBound.insert(follow(currentResultType));
3511
};
3512
3513
TypeIds valuesLowerBound;
3514
3515
Checkpoint start = checkpoint(this);
3516
3517
for (const AstExprTable::Item& item : expr->items)
3518
{
3519
// Expected typeArguments are threaded through table literals separately via the
3520
// function matchLiteralType.
3521
3522
// generalize is false here as we want to be able to push typeArguments into lambdas in a situation like:
3523
//
3524
// type Callback = (string) -> ()
3525
//
3526
// local t: { Callback } = {
3527
// function (s)
3528
// -- s should have type `string` here
3529
// end
3530
// }
3531
TypeId itemTy = check(scope, item.value, /* expectedType */ std::nullopt, /* forceSingleton */ false, /* generalize */ false).ty;
3532
3533
if (item.key)
3534
{
3535
// Even though we don't need to use the type of the item's key if
3536
// it's a string constant, we still want to check it to populate
3537
// astTypes.
3538
TypeId keyTy = check(scope, item.key).ty;
3539
3540
if (AstExprConstantString* key = item.key->as<AstExprConstantString>())
3541
{
3542
std::string propName{key->value.data, key->value.size};
3543
ttv->props[propName] = {itemTy, /*deprecated*/ false, {}, key->location};
3544
}
3545
else
3546
{
3547
createIndexer(item.key->location, keyTy, itemTy);
3548
}
3549
}
3550
else
3551
{
3552
TypeId numberType = builtinTypes->numberType;
3553
// FIXME? The location isn't quite right here. Not sure what is
3554
// right.
3555
createIndexer(item.value->location, numberType, itemTy);
3556
}
3557
}
3558
3559
Checkpoint end = checkpoint(this);
3560
3561
if (!indexKeyLowerBound.empty())
3562
{
3563
LUAU_ASSERT(!indexValueLowerBound.empty());
3564
3565
TypeId indexKey = nullptr;
3566
TypeId indexValue = nullptr;
3567
3568
if (indexKeyLowerBound.size() == 1)
3569
{
3570
indexKey = *indexKeyLowerBound.begin();
3571
}
3572
else
3573
{
3574
indexKey = arena->addType(UnionType{std::vector(indexKeyLowerBound.begin(), indexKeyLowerBound.end())});
3575
unionsToSimplify.push_back(indexKey);
3576
}
3577
3578
if (indexValueLowerBound.size() == 1)
3579
{
3580
indexValue = *indexValueLowerBound.begin();
3581
}
3582
else
3583
{
3584
indexValue = arena->addType(UnionType{std::vector(indexValueLowerBound.begin(), indexValueLowerBound.end())});
3585
unionsToSimplify.push_back(indexValue);
3586
}
3587
3588
ttv->indexer = TableIndexer{indexKey, indexValue};
3589
}
3590
3591
if (expectedType)
3592
{
3593
auto ptc = addConstraint(
3594
scope,
3595
expr->location,
3596
PushTypeConstraint{
3597
/* expectedType */ *expectedType,
3598
/* targetType */ ty,
3599
/* astTypes */ NotNull{&module->astTypes},
3600
/* astExpectedTypes */ NotNull{&module->astExpectedTypes},
3601
/* expr */ NotNull{expr},
3602
}
3603
);
3604
forEachConstraint(
3605
start,
3606
end,
3607
this,
3608
[ptc](const ConstraintPtr& c)
3609
{
3610
c->dependencies.emplace_back(ptc.get());
3611
}
3612
);
3613
}
3614
3615
if (FInt::LuauPrimitiveInferenceInTableLimit > 0 && expr->items.size > size_t(FInt::LuauPrimitiveInferenceInTableLimit))
3616
largeTableDepth--;
3617
3618
return Inference{ty};
3619
}
3620
3621
ConstraintGenerator::FunctionSignature ConstraintGenerator::checkFunctionSignature(
3622
const ScopePtr& parent,
3623
AstExprFunction* fn,
3624
std::optional<TypeId> expectedType,
3625
std::optional<Location> originalName
3626
)
3627
{
3628
ScopePtr signatureScope = nullptr;
3629
ScopePtr bodyScope = nullptr;
3630
TypePackId returnType = nullptr;
3631
3632
std::vector<TypeId> genericTypes;
3633
std::vector<TypePackId> genericTypePacks;
3634
3635
if (expectedType)
3636
expectedType = follow(*expectedType);
3637
3638
bool hasGenerics = fn->generics.size > 0 || fn->genericPacks.size > 0;
3639
3640
signatureScope = childScope(fn, parent);
3641
3642
// We need to assign returnType before creating bodyScope so that the
3643
// return type gets propagated to bodyScope.
3644
returnType = freshTypePack(signatureScope, Polarity::Positive);
3645
signatureScope->returnType = returnType;
3646
3647
bodyScope = childScope(fn->body, signatureScope);
3648
3649
if (hasGenerics)
3650
{
3651
std::vector<std::pair<Name, GenericTypeDefinition>> genericDefinitions = createGenerics(signatureScope, fn->generics);
3652
std::vector<std::pair<Name, GenericTypePackDefinition>> genericPackDefinitions = createGenericPacks(signatureScope, fn->genericPacks);
3653
3654
// We do not support default values on function generics, so we only
3655
// care about the typeArguments involved.
3656
for (const auto& [name, g] : genericDefinitions)
3657
{
3658
genericTypes.push_back(g.ty);
3659
}
3660
3661
for (const auto& [name, g] : genericPackDefinitions)
3662
{
3663
genericTypePacks.push_back(g.tp);
3664
}
3665
3666
// Local variable works around an odd gcc 11.3 warning: <anonymous> may be used uninitialized
3667
std::optional<TypeId> none = std::nullopt;
3668
expectedType = none;
3669
}
3670
3671
std::vector<TypeId> argTypes;
3672
std::vector<std::optional<FunctionArgument>> argNames;
3673
TypePack expectedArgPack;
3674
3675
const FunctionType* expectedFunction = expectedType ? get<FunctionType>(*expectedType) : nullptr;
3676
// This check ensures that expectedType is precisely optional and not any (since any is also an optional type)
3677
if (expectedType && isOptional(*expectedType) && !get<AnyType>(*expectedType))
3678
{
3679
if (auto ut = get<UnionType>(*expectedType))
3680
{
3681
for (auto u : ut)
3682
{
3683
if (get<FunctionType>(u) && !isNil(u))
3684
{
3685
expectedFunction = get<FunctionType>(u);
3686
break;
3687
}
3688
}
3689
}
3690
}
3691
3692
if (expectedFunction)
3693
{
3694
expectedArgPack = extendTypePack(*arena, builtinTypes, expectedFunction->argTypes, fn->args.size);
3695
3696
genericTypes = expectedFunction->generics;
3697
genericTypePacks = expectedFunction->genericPacks;
3698
}
3699
3700
if (fn->self)
3701
{
3702
TypeId selfType = freshType(signatureScope, Polarity::Negative);
3703
argTypes.push_back(selfType);
3704
argNames.emplace_back(FunctionArgument{fn->self->name.value, fn->self->location});
3705
signatureScope->bindings[fn->self] = Binding{selfType, fn->self->location};
3706
3707
DefId def = dfg->getDef(fn->self);
3708
signatureScope->lvalueTypes[def] = selfType;
3709
updateRValueRefinements(signatureScope, def, selfType);
3710
}
3711
3712
for (size_t i = 0; i < fn->args.size; ++i)
3713
{
3714
AstLocal* local = fn->args.data[i];
3715
3716
TypeId argTy = nullptr;
3717
if (local->annotation)
3718
{
3719
argTy = resolveType(signatureScope, local->annotation, /* inTypeArguments */ false, /* replaceErrorWithFresh*/ true, Polarity::Negative);
3720
}
3721
else
3722
{
3723
if (i < expectedArgPack.head.size())
3724
argTy = expectedArgPack.head[i];
3725
else
3726
argTy = freshType(signatureScope, Polarity::Negative);
3727
}
3728
3729
argTypes.push_back(argTy);
3730
argNames.emplace_back(FunctionArgument{local->name.value, local->location});
3731
3732
signatureScope->bindings[local] = Binding{argTy, local->location};
3733
3734
DefId def = dfg->getDef(local);
3735
signatureScope->lvalueTypes[def] = argTy;
3736
updateRValueRefinements(signatureScope, def, argTy);
3737
}
3738
3739
TypePackId varargPack = nullptr;
3740
3741
if (fn->vararg)
3742
{
3743
if (fn->varargAnnotation)
3744
{
3745
TypePackId annotationType =
3746
resolveTypePack(signatureScope, fn->varargAnnotation, /* inTypeArguments */ false, /* replaceErrorWithFresh */ true);
3747
varargPack = annotationType;
3748
}
3749
else if (expectedArgPack.tail && get<VariadicTypePack>(*expectedArgPack.tail))
3750
varargPack = *expectedArgPack.tail;
3751
else
3752
varargPack = builtinTypes->anyTypePack;
3753
3754
signatureScope->varargPack = varargPack;
3755
bodyScope->varargPack = varargPack;
3756
}
3757
else
3758
{
3759
varargPack = arena->addTypePack(VariadicTypePack{builtinTypes->anyType, /*hidden*/ true});
3760
// We do not add to signatureScope->varargPack because ... is not valid
3761
// in functions without an explicit ellipsis.
3762
3763
signatureScope->varargPack = std::nullopt;
3764
bodyScope->varargPack = std::nullopt;
3765
}
3766
3767
LUAU_ASSERT(nullptr != varargPack);
3768
3769
// Some of the unannotated parameters in argTypes will eventually be
3770
// generics, and some will not. The ones that are not generic will be
3771
// pruned when GeneralizationConstraint dispatches.
3772
3773
// The self parameter never has an annotation and so could always become generic.
3774
if (fn->self)
3775
genericTypes.push_back(argTypes[0]);
3776
3777
size_t typeIndex = fn->self ? 1 : 0;
3778
for (auto astArg : fn->args)
3779
{
3780
TypeId argTy = argTypes.at(typeIndex);
3781
if (!astArg->annotation)
3782
genericTypes.push_back(argTy);
3783
3784
++typeIndex;
3785
}
3786
3787
varargPack = follow(varargPack);
3788
returnType = follow(returnType);
3789
if (!fn->varargAnnotation)
3790
genericTypePacks.push_back(varargPack);
3791
if (!fn->returnAnnotation)
3792
genericTypePacks.push_back(returnType);
3793
3794
// If there is both an annotation and an expected type, the annotation wins.
3795
// Type checking will sort out any discrepancies later.
3796
if (fn->returnAnnotation)
3797
{
3798
TypePackId annotatedRetType =
3799
resolveTypePack(signatureScope, fn->returnAnnotation, /* inTypeArguments */ false, /* replaceErrorWithFresh*/ true);
3800
// We bind the annotated type directly here so that, when we need to
3801
// generate constraints for return typeArguments, we have a guarantee that we
3802
// know the annotated return type already, if one was provided.
3803
LUAU_ASSERT(get<FreeTypePack>(returnType));
3804
emplaceTypePack<BoundTypePack>(asMutable(returnType), annotatedRetType);
3805
}
3806
else if (expectedFunction)
3807
{
3808
emplaceTypePack<BoundTypePack>(asMutable(returnType), expectedFunction->retTypes);
3809
}
3810
3811
// TODO: Preserve argument names in the function's type.
3812
3813
FunctionType actualFunction{TypeLevel{}, arena->addTypePack(std::move(argTypes), varargPack), returnType};
3814
actualFunction.generics = std::move(genericTypes);
3815
actualFunction.genericPacks = std::move(genericTypePacks);
3816
actualFunction.argNames = std::move(argNames);
3817
actualFunction.hasSelf = fn->self != nullptr;
3818
3819
FunctionDefinition defn;
3820
defn.definitionModuleName = module->name;
3821
defn.definitionLocation = fn->location;
3822
defn.varargLocation = fn->vararg ? std::make_optional(fn->varargLocation) : std::nullopt;
3823
defn.originalNameLocation = originalName.value_or(Location(fn->location.begin, 0));
3824
actualFunction.definition = defn;
3825
3826
TypeId actualFunctionType = arena->addType(std::move(actualFunction));
3827
LUAU_ASSERT(actualFunctionType);
3828
module->astTypes[fn] = actualFunctionType;
3829
3830
if (expectedType && get<FreeType>(*expectedType))
3831
bindFreeType(*expectedType, actualFunctionType);
3832
3833
scopeToFunction[signatureScope.get()] = actualFunctionType;
3834
3835
return {
3836
/* signature */ actualFunctionType,
3837
/* signatureScope */ std::move(signatureScope),
3838
/* bodyScope */ std::move(bodyScope),
3839
};
3840
}
3841
3842
void ConstraintGenerator::checkFunctionBody(const ScopePtr& scope, AstExprFunction* fn)
3843
{
3844
// If it is possible for execution to reach the end of the function, the return type must be compatible with ()
3845
ControlFlow cf = visitBlockWithoutChildScope(scope, fn->body);
3846
if (cf == ControlFlow::None)
3847
addConstraint(scope, fn->location, PackSubtypeConstraint{builtinTypes->emptyTypePack, scope->returnType});
3848
}
3849
3850
TypeId ConstraintGenerator::resolveReferenceType(
3851
const ScopePtr& scope,
3852
AstType* ty,
3853
AstTypeReference* ref,
3854
bool inTypeArguments,
3855
bool replaceErrorWithFresh
3856
)
3857
{
3858
TypeId result = nullptr;
3859
3860
if (FFlag::DebugLuauMagicTypes)
3861
{
3862
if (ref->name == "_luau_ice")
3863
ice->ice("_luau_ice encountered", ty->location);
3864
else if (ref->name == "_luau_print")
3865
{
3866
if (ref->parameters.size != 1 || !ref->parameters.data[0].type)
3867
{
3868
reportError(ty->location, GenericError{"_luau_print requires one generic parameter"});
3869
module->astResolvedTypes[ty] = builtinTypes->errorType;
3870
return builtinTypes->errorType;
3871
}
3872
else
3873
return resolveType_(scope, ref->parameters.data[0].type, inTypeArguments);
3874
}
3875
else if (ref->name == "_luau_blocked_type")
3876
{
3877
return arena->addType(BlockedType{});
3878
}
3879
}
3880
3881
std::optional<TypeFun> alias;
3882
3883
if (ref->prefix.has_value())
3884
{
3885
alias = scope->lookupImportedType(ref->prefix->value, ref->name.value);
3886
}
3887
else
3888
{
3889
alias = scope->lookupType(ref->name.value);
3890
}
3891
3892
if (alias.has_value())
3893
{
3894
// If the alias is not generic, we don't need to set up a blocked type and an instantiation constraint
3895
if (alias.has_value() && alias->typeParams.empty() && alias->typePackParams.empty() && !ref->hasParameterList)
3896
{
3897
result = alias->type;
3898
}
3899
else
3900
{
3901
std::vector<TypeId> parameters;
3902
std::vector<TypePackId> packParameters;
3903
3904
for (const AstTypeOrPack& p : ref->parameters)
3905
{
3906
// We do not enforce the ordering of typeArguments vs. type packs here;
3907
// that is done in the parser.
3908
if (p.type)
3909
{
3910
parameters.push_back(resolveType_(scope, p.type, /* inTypeArguments */ true));
3911
}
3912
else if (p.typePack)
3913
{
3914
TypePackId tp = resolveTypePack_(scope, p.typePack, /*inTypeArguments*/ true);
3915
3916
// If we need more regular typeArguments, we can use single element type packs to fill those in
3917
if (parameters.size() < alias->typeParams.size() && size(tp) == 1 && finite(tp) && first(tp))
3918
parameters.push_back(*first(tp));
3919
else
3920
packParameters.push_back(tp);
3921
}
3922
else
3923
{
3924
// This indicates a parser bug: one of these two pointers
3925
// should be set.
3926
LUAU_ASSERT(false);
3927
}
3928
}
3929
3930
result = arena->addType(PendingExpansionType{ref->prefix, ref->name, std::move(parameters), std::move(packParameters)});
3931
3932
// If we're not in a type argument context, we need to create a constraint that expands this.
3933
// The dispatching of the above constraint will queue up additional constraints for nested
3934
// type function applications.
3935
if (!inTypeArguments)
3936
addConstraint(scope, ty->location, TypeAliasExpansionConstraint{/* target */ result});
3937
}
3938
}
3939
else
3940
{
3941
result = builtinTypes->errorType;
3942
if (replaceErrorWithFresh)
3943
result = freshType(scope, Polarity::Mixed);
3944
}
3945
3946
if (is<TypeFunctionInstanceType>(follow(result)))
3947
{
3948
reportError(ty->location, UnappliedTypeFunction{});
3949
addConstraint(scope, ty->location, ReduceConstraint{result});
3950
}
3951
3952
if (auto genericType = getMutable<GenericType>(follow(result)))
3953
genericType->polarity = (genericType->polarity & Polarity::Mixed) | polarity;
3954
3955
return result;
3956
}
3957
3958
namespace
3959
{
3960
Polarity polarityOfAccess(AstTableAccess access, Polarity p)
3961
{
3962
switch (access)
3963
{
3964
case AstTableAccess::Read:
3965
return p;
3966
case AstTableAccess::Write:
3967
return invert(p);
3968
case AstTableAccess::ReadWrite:
3969
return Polarity::Mixed;
3970
default:
3971
return Polarity::Unknown;
3972
}
3973
}
3974
} // namespace
3975
3976
TypeId ConstraintGenerator::resolveTableType(const ScopePtr& scope, AstType* ty, AstTypeTable* tab, bool inTypeArguments, bool replaceErrorWithFresh)
3977
{
3978
TableType::Props props;
3979
std::optional<TableIndexer> indexer;
3980
3981
Polarity p = polarity;
3982
for (const AstTableProp& prop : tab->props)
3983
{
3984
Property& propRef = props[prop.name.value];
3985
3986
// Set the polarity for the inner type
3987
polarity = polarityOfAccess(prop.access, p);
3988
3989
TypeId propTy = resolveType_(scope, prop.type, inTypeArguments);
3990
3991
propRef.typeLocation = prop.location;
3992
3993
switch (prop.access)
3994
{
3995
case AstTableAccess::ReadWrite:
3996
propRef.readTy = propTy;
3997
propRef.writeTy = propTy;
3998
break;
3999
case AstTableAccess::Read:
4000
propRef.readTy = propTy;
4001
break;
4002
case AstTableAccess::Write:
4003
propRef.writeTy = propTy;
4004
break;
4005
default:
4006
ice->ice("Unexpected property access " + std::to_string(int(prop.access)));
4007
break;
4008
}
4009
}
4010
4011
if (AstTableIndexer* astIndexer = tab->indexer)
4012
{
4013
if (astIndexer->access == AstTableAccess::Read)
4014
reportError(astIndexer->accessLocation.value_or(Location{}), GenericError{"read keyword is illegal here"});
4015
else if (astIndexer->access == AstTableAccess::Write)
4016
reportError(astIndexer->accessLocation.value_or(Location{}), GenericError{"write keyword is illegal here"});
4017
else if (astIndexer->access == AstTableAccess::ReadWrite)
4018
{
4019
polarity = Polarity::Mixed;
4020
indexer = TableIndexer{
4021
resolveType_(scope, astIndexer->indexType, inTypeArguments),
4022
resolveType_(scope, astIndexer->resultType, inTypeArguments),
4023
};
4024
}
4025
else
4026
ice->ice("Unexpected property access " + std::to_string(int(astIndexer->access)));
4027
}
4028
4029
polarity = p;
4030
4031
4032
TypeId tableTy = arena->addType(TableType{props, indexer, scope->level, scope.get(), TableState::Sealed});
4033
TableType* ttv = getMutable<TableType>(tableTy);
4034
4035
ttv->definitionModuleName = module->name;
4036
ttv->definitionLocation = tab->location;
4037
4038
return tableTy;
4039
}
4040
4041
TypeId ConstraintGenerator::resolveFunctionType(
4042
const ScopePtr& scope,
4043
AstType* ty,
4044
AstTypeFunction* fn,
4045
bool inTypeArguments,
4046
bool replaceErrorWithFresh
4047
)
4048
{
4049
bool hasGenerics = fn->generics.size > 0 || fn->genericPacks.size > 0;
4050
ScopePtr signatureScope = nullptr;
4051
4052
std::vector<TypeId> genericTypes;
4053
std::vector<TypePackId> genericTypePacks;
4054
4055
// If we don't have generics, we do not need to generate a child scope
4056
// for the generic bindings to live on.
4057
if (hasGenerics)
4058
{
4059
signatureScope = childScope(fn, scope);
4060
4061
std::vector<std::pair<Name, GenericTypeDefinition>> genericDefinitions = createGenerics(signatureScope, fn->generics);
4062
std::vector<std::pair<Name, GenericTypePackDefinition>> genericPackDefinitions = createGenericPacks(signatureScope, fn->genericPacks);
4063
4064
for (const auto& [name, g] : genericDefinitions)
4065
{
4066
genericTypes.push_back(g.ty);
4067
}
4068
4069
for (const auto& [name, g] : genericPackDefinitions)
4070
{
4071
genericTypePacks.push_back(g.tp);
4072
}
4073
}
4074
else
4075
{
4076
// To eliminate the need to branch on hasGenerics below, we say that
4077
// the signature scope is the parent scope if we don't have
4078
// generics.
4079
signatureScope = scope;
4080
}
4081
4082
AstTypePackExplicit tempArgTypes{Location{}, fn->argTypes};
4083
4084
Polarity p = polarity;
4085
polarity = invert(polarity);
4086
TypePackId argTypes = resolveTypePack_(signatureScope, &tempArgTypes, inTypeArguments, replaceErrorWithFresh);
4087
polarity = p;
4088
TypePackId returnTypes = resolveTypePack_(signatureScope, fn->returnTypes, inTypeArguments, replaceErrorWithFresh);
4089
4090
// TODO: FunctionType needs a pointer to the scope so that we know
4091
// how to quantify/instantiate it.
4092
FunctionType ftv{TypeLevel{}, {}, {}, argTypes, returnTypes};
4093
ftv.isCheckedFunction = fn->isCheckedFunction();
4094
AstAttr* deprecatedAttr = fn->getAttribute(AstAttr::Type::Deprecated);
4095
ftv.isDeprecatedFunction = deprecatedAttr != nullptr;
4096
if (deprecatedAttr)
4097
{
4098
ftv.deprecatedInfo = std::make_shared<AstAttr::DeprecatedInfo>(deprecatedAttr->deprecatedInfo());
4099
}
4100
4101
4102
// This replicates the behavior of the appropriate FunctionType
4103
// constructors.
4104
ftv.generics = std::move(genericTypes);
4105
ftv.genericPacks = std::move(genericTypePacks);
4106
4107
ftv.argNames.reserve(fn->argNames.size);
4108
for (const auto& el : fn->argNames)
4109
{
4110
if (el)
4111
{
4112
const auto& [name, location] = *el;
4113
ftv.argNames.emplace_back(FunctionArgument{name.value, location});
4114
}
4115
else
4116
ftv.argNames.emplace_back(std::nullopt);
4117
}
4118
4119
return arena->addType(std::move(ftv));
4120
}
4121
4122
TypeId ConstraintGenerator::resolveType(
4123
const ScopePtr& scope,
4124
AstType* ty,
4125
bool inTypeArguments,
4126
bool replaceErrorWithFresh,
4127
Polarity initialPolarity
4128
)
4129
{
4130
// Reset the polarity
4131
polarity = initialPolarity;
4132
return resolveType_(scope, ty, inTypeArguments, replaceErrorWithFresh);
4133
}
4134
4135
TypeId ConstraintGenerator::resolveType_(const ScopePtr& scope, AstType* ty, bool inTypeArguments, bool replaceErrorWithFresh)
4136
{
4137
TypeId result = nullptr;
4138
4139
if (auto ref = ty->as<AstTypeReference>())
4140
{
4141
result = resolveReferenceType(scope, ty, ref, inTypeArguments, replaceErrorWithFresh);
4142
}
4143
else if (auto tab = ty->as<AstTypeTable>())
4144
{
4145
result = resolveTableType(scope, ty, tab, inTypeArguments, replaceErrorWithFresh);
4146
}
4147
else if (auto fn = ty->as<AstTypeFunction>())
4148
{
4149
result = resolveFunctionType(scope, ty, fn, inTypeArguments, replaceErrorWithFresh);
4150
}
4151
else if (auto tof = ty->as<AstTypeTypeof>())
4152
{
4153
TypeId exprType = check(scope, tof->expr).ty;
4154
result = exprType;
4155
}
4156
else if (ty->is<AstTypeOptional>())
4157
{
4158
result = builtinTypes->nilType;
4159
}
4160
else if (auto unionAnnotation = ty->as<AstTypeUnion>())
4161
{
4162
if (unionAnnotation->types.size == 1)
4163
result = resolveType_(scope, unionAnnotation->types.data[0], inTypeArguments);
4164
else
4165
{
4166
std::vector<TypeId> parts;
4167
for (AstType* part : unionAnnotation->types)
4168
{
4169
parts.push_back(resolveType_(scope, part, inTypeArguments));
4170
}
4171
4172
result = arena->addType(UnionType{std::move(parts)});
4173
}
4174
}
4175
else if (auto intersectionAnnotation = ty->as<AstTypeIntersection>())
4176
{
4177
if (intersectionAnnotation->types.size == 1)
4178
result = resolveType_(scope, intersectionAnnotation->types.data[0], inTypeArguments);
4179
else
4180
{
4181
std::vector<TypeId> parts;
4182
for (AstType* part : intersectionAnnotation->types)
4183
{
4184
parts.push_back(resolveType_(scope, part, inTypeArguments));
4185
}
4186
4187
result = arena->addType(IntersectionType{std::move(parts)});
4188
}
4189
}
4190
else if (auto typeGroupAnnotation = ty->as<AstTypeGroup>())
4191
{
4192
result = resolveType_(scope, typeGroupAnnotation->type, inTypeArguments);
4193
}
4194
else if (auto boolAnnotation = ty->as<AstTypeSingletonBool>())
4195
{
4196
if (boolAnnotation->value)
4197
result = builtinTypes->trueType;
4198
else
4199
result = builtinTypes->falseType;
4200
}
4201
else if (auto stringAnnotation = ty->as<AstTypeSingletonString>())
4202
{
4203
result = arena->addType(SingletonType(StringSingleton{std::string(stringAnnotation->value.data, stringAnnotation->value.size)}));
4204
}
4205
else if (ty->is<AstTypeError>())
4206
{
4207
result = builtinTypes->errorType;
4208
if (replaceErrorWithFresh)
4209
result = freshType(scope, polarity);
4210
}
4211
else
4212
{
4213
LUAU_ASSERT(0);
4214
result = builtinTypes->errorType;
4215
}
4216
4217
module->astResolvedTypes[ty] = result;
4218
return result;
4219
}
4220
4221
TypePackId ConstraintGenerator::resolveTypePack(
4222
const ScopePtr& scope,
4223
AstTypePack* tp,
4224
bool inTypeArgument,
4225
bool replaceErrorWithFresh,
4226
Polarity initialPolarity
4227
)
4228
{
4229
polarity = initialPolarity;
4230
return resolveTypePack_(scope, tp, inTypeArgument, replaceErrorWithFresh);
4231
}
4232
4233
TypePackId ConstraintGenerator::resolveTypePack_(const ScopePtr& scope, AstTypePack* tp, bool inTypeArgument, bool replaceErrorWithFresh)
4234
{
4235
TypePackId result;
4236
if (auto expl = tp->as<AstTypePackExplicit>())
4237
{
4238
result = FFlag::LuauForwardPolarityForFunctionTypes
4239
? resolveTypePack_(scope, expl->typeList, inTypeArgument, replaceErrorWithFresh)
4240
: resolveTypePack_DEPRECATED(scope, expl->typeList, inTypeArgument, replaceErrorWithFresh);
4241
}
4242
else if (auto var = tp->as<AstTypePackVariadic>())
4243
{
4244
TypeId ty = resolveType_(scope, var->variadicType, inTypeArgument, replaceErrorWithFresh);
4245
result = arena->addTypePack(TypePackVar{VariadicTypePack{ty}});
4246
}
4247
else if (auto gen = tp->as<AstTypePackGeneric>())
4248
{
4249
if (std::optional<TypePackId> lookup = scope->lookupPack(gen->genericName.value))
4250
{
4251
result = *lookup;
4252
}
4253
else
4254
{
4255
reportError(tp->location, UnknownSymbol{gen->genericName.value, UnknownSymbol::Context::Type});
4256
result = builtinTypes->errorTypePack;
4257
}
4258
}
4259
else
4260
{
4261
LUAU_ASSERT(0);
4262
result = builtinTypes->errorTypePack;
4263
}
4264
4265
if (auto gtp = getMutable<GenericTypePack>(follow(result)))
4266
{
4267
// The initial polarity is unknown, so we flip that bit off
4268
// by saying that we are at most Mixed, and then add in the
4269
// polarity we're currently processing.
4270
gtp->polarity = (gtp->polarity & Polarity::Mixed) | polarity;
4271
}
4272
4273
module->astResolvedTypePacks[tp] = result;
4274
return result;
4275
}
4276
4277
TypePackId ConstraintGenerator::resolveTypePack_DEPRECATED(
4278
const ScopePtr& scope,
4279
const AstTypeList& list,
4280
bool inTypeArguments,
4281
bool replaceErrorWithFresh,
4282
Polarity initialPolarity
4283
)
4284
{
4285
LUAU_ASSERT(!FFlag::LuauForwardPolarityForFunctionTypes);
4286
polarity = initialPolarity;
4287
4288
std::vector<TypeId> head;
4289
4290
for (AstType* headTy : list.types)
4291
{
4292
head.push_back(resolveType_(scope, headTy, inTypeArguments, replaceErrorWithFresh));
4293
}
4294
4295
std::optional<TypePackId> tail = std::nullopt;
4296
if (list.tailType)
4297
{
4298
tail = resolveTypePack_(scope, list.tailType, inTypeArguments, replaceErrorWithFresh);
4299
}
4300
4301
TypePackId result = addTypePack(std::move(head), tail);
4302
return result;
4303
}
4304
4305
TypePackId ConstraintGenerator::resolveTypePack_(const ScopePtr& scope, const AstTypeList& list, bool inTypeArguments, bool replaceErrorWithFresh)
4306
{
4307
LUAU_ASSERT(FFlag::LuauForwardPolarityForFunctionTypes);
4308
4309
std::vector<TypeId> head;
4310
4311
for (AstType* headTy : list.types)
4312
{
4313
head.push_back(resolveType_(scope, headTy, inTypeArguments, replaceErrorWithFresh));
4314
}
4315
4316
std::optional<TypePackId> tail = std::nullopt;
4317
if (list.tailType)
4318
{
4319
tail = resolveTypePack_(scope, list.tailType, inTypeArguments, replaceErrorWithFresh);
4320
}
4321
4322
return addTypePack(std::move(head), tail);
4323
}
4324
4325
TypePackId ConstraintGenerator::resolveTypePack(
4326
const ScopePtr& scope,
4327
const AstTypeList& list,
4328
bool inTypeArguments,
4329
bool replaceErrorWithFresh,
4330
Polarity initialPolarity
4331
)
4332
{
4333
LUAU_ASSERT(FFlag::LuauForwardPolarityForFunctionTypes);
4334
polarity = initialPolarity;
4335
return resolveTypePack_(scope, list, inTypeArguments, replaceErrorWithFresh);
4336
}
4337
4338
std::vector<std::pair<Name, GenericTypeDefinition>> ConstraintGenerator::createGenerics(
4339
const ScopePtr& scope,
4340
AstArray<AstGenericType*> generics,
4341
bool useCache,
4342
bool addTypes
4343
)
4344
{
4345
std::vector<std::pair<Name, GenericTypeDefinition>> result;
4346
for (const auto* generic : generics)
4347
{
4348
TypeId genericTy = nullptr;
4349
4350
if (auto it = scope->parent->typeAliasTypeParameters.find(generic->name.value);
4351
useCache && it != scope->parent->typeAliasTypeParameters.end())
4352
genericTy = it->second;
4353
else
4354
{
4355
genericTy = arena->addType(GenericType{scope.get(), generic->name.value, Polarity::None});
4356
scope->parent->typeAliasTypeParameters[generic->name.value] = genericTy;
4357
}
4358
4359
std::optional<TypeId> defaultTy = std::nullopt;
4360
4361
if (generic->defaultValue)
4362
defaultTy = arena->addType(BlockedType{});
4363
4364
if (addTypes)
4365
scope->privateTypeBindings[generic->name.value] = TypeFun{genericTy};
4366
4367
result.emplace_back(generic->name.value, GenericTypeDefinition{genericTy, defaultTy});
4368
}
4369
4370
return result;
4371
}
4372
4373
std::vector<std::pair<Name, GenericTypePackDefinition>> ConstraintGenerator::createGenericPacks(
4374
const ScopePtr& scope,
4375
AstArray<AstGenericTypePack*> generics,
4376
bool useCache,
4377
bool addTypes
4378
)
4379
{
4380
std::vector<std::pair<Name, GenericTypePackDefinition>> result;
4381
for (const auto* generic : generics)
4382
{
4383
TypePackId genericTy;
4384
4385
if (auto it = scope->parent->typeAliasTypePackParameters.find(generic->name.value);
4386
useCache && it != scope->parent->typeAliasTypePackParameters.end())
4387
genericTy = it->second;
4388
else
4389
{
4390
genericTy = arena->addTypePack(TypePackVar{GenericTypePack{scope.get(), generic->name.value, Polarity::None}});
4391
scope->parent->typeAliasTypePackParameters[generic->name.value] = genericTy;
4392
}
4393
4394
std::optional<TypePackId> defaultTy = std::nullopt;
4395
4396
if (generic->defaultValue)
4397
defaultTy = arena->addTypePack(BlockedTypePack{});
4398
4399
if (addTypes)
4400
scope->privateTypePackBindings[generic->name.value] = genericTy;
4401
4402
result.emplace_back(generic->name.value, GenericTypePackDefinition{genericTy, defaultTy});
4403
}
4404
4405
return result;
4406
}
4407
4408
Inference ConstraintGenerator::flattenPack(const ScopePtr& scope, Location location, InferencePack pack)
4409
{
4410
const auto& [tp, refinements] = pack;
4411
RefinementId refinement = nullptr;
4412
if (!refinements.empty())
4413
refinement = refinements[0];
4414
4415
if (auto f = first(tp))
4416
return Inference{*f, refinement};
4417
4418
TypeId typeResult = arena->addType(BlockedType{});
4419
auto c = addConstraint(scope, location, UnpackConstraint{{typeResult}, tp});
4420
getMutable<BlockedType>(typeResult)->setOwner(c);
4421
4422
return Inference{typeResult, refinement};
4423
}
4424
4425
void ConstraintGenerator::reportError(Location location, TypeErrorData err)
4426
{
4427
errors.emplace_back(location, module->name, std::move(err));
4428
if (logger)
4429
logger->captureGenerationError(errors.back());
4430
}
4431
4432
void ConstraintGenerator::reportCodeTooComplex(Location location)
4433
{
4434
errors.emplace_back(location, module->name, CodeTooComplex{});
4435
if (logger)
4436
logger->captureGenerationError(errors.back());
4437
4438
recursionLimitMet = true;
4439
}
4440
4441
TypeId ConstraintGenerator::makeUnion(const ScopePtr& scope, Location location, TypeId lhs, TypeId rhs)
4442
{
4443
if (get<NeverType>(follow(lhs)))
4444
return rhs;
4445
if (get<NeverType>(follow(rhs)))
4446
return lhs;
4447
4448
TypeId result = simplifyUnion(scope, location, lhs, rhs);
4449
if (is<UnionType>(follow(result)))
4450
unionsToSimplify.push_back(result);
4451
return result;
4452
}
4453
4454
TypeId ConstraintGenerator::makeUnion(std::vector<TypeId> options)
4455
{
4456
UnionBuilder ub{arena, builtinTypes};
4457
ub.reserve(options.size());
4458
4459
for (auto option : options)
4460
ub.add(option);
4461
4462
TypeId unionTy = ub.build();
4463
4464
if (is<UnionType>(unionTy))
4465
unionsToSimplify.push_back(unionTy);
4466
4467
return unionTy;
4468
}
4469
4470
TypeId ConstraintGenerator::makeIntersect(const ScopePtr& scope, Location location, TypeId lhs, TypeId rhs)
4471
{
4472
TypeId resultType = createTypeFunctionInstance(builtinTypes->typeFunctions->intersectFunc, {lhs, rhs}, {}, scope, location);
4473
4474
return resultType;
4475
}
4476
4477
struct GlobalPrepopulator : AstVisitor
4478
{
4479
const NotNull<Scope> globalScope;
4480
const NotNull<TypeArena> arena;
4481
const NotNull<const DataFlowGraph> dfg;
4482
4483
DenseHashSet<AstName> uninitializedGlobals{{}};
4484
4485
GlobalPrepopulator(NotNull<Scope> globalScope, NotNull<TypeArena> arena, NotNull<const DataFlowGraph> dfg)
4486
: globalScope(globalScope)
4487
, arena(arena)
4488
, dfg(dfg)
4489
{
4490
}
4491
4492
bool visit(AstExprGlobal* global) override
4493
{
4494
if (auto ty = globalScope->lookup(global->name))
4495
{
4496
DefId def = dfg->getDef(global);
4497
globalScope->lvalueTypes[def] = *ty;
4498
}
4499
4500
return true;
4501
}
4502
4503
bool visit(AstStatAssign* assign) override
4504
{
4505
for (const Luau::AstExpr* expr : assign->vars)
4506
{
4507
if (const AstExprGlobal* g = expr->as<AstExprGlobal>())
4508
{
4509
if (!globalScope->lookup(g->name))
4510
globalScope->globalsToWarn.insert(g->name.value);
4511
4512
if (globalScope->bindings.find(g->name) == globalScope->bindings.end())
4513
{
4514
TypeId bt = arena->addType(BlockedType{});
4515
if (FFlag::LuauKeepExplicitMapForGlobalTypes2)
4516
uninitializedGlobals.insert(g->name);
4517
globalScope->bindings[g->name] = Binding{bt, g->location};
4518
}
4519
}
4520
}
4521
4522
return true;
4523
}
4524
4525
bool visit(AstStatFunction* function) override
4526
{
4527
if (AstExprGlobal* g = function->name->as<AstExprGlobal>())
4528
{
4529
TypeId bt = arena->addType(BlockedType{});
4530
if (FFlag::LuauKeepExplicitMapForGlobalTypes2)
4531
uninitializedGlobals.insert(g->name);
4532
globalScope->bindings[g->name] = Binding{bt};
4533
}
4534
4535
return true;
4536
}
4537
4538
bool visit(AstType*) override
4539
{
4540
return true;
4541
}
4542
4543
bool visit(class AstTypePack* node) override
4544
{
4545
return true;
4546
}
4547
};
4548
4549
void ConstraintGenerator::prepopulateGlobalScopeForFragmentTypecheck(const ScopePtr& globalScope, const ScopePtr& resumeScope, AstStatBlock* program)
4550
{
4551
// Handle type function globals as well, without preparing a module scope since they have a separate environment
4552
GlobalPrepopulator tfgp{NotNull{typeFunctionRuntime->rootScope.get()}, arena, dfg};
4553
program->visit(&tfgp);
4554
4555
if (FFlag::LuauKeepExplicitMapForGlobalTypes2)
4556
{
4557
for (auto name : tfgp.uninitializedGlobals)
4558
uninitializedGlobals.insert(name);
4559
}
4560
}
4561
4562
void ConstraintGenerator::prepopulateGlobalScope(const ScopePtr& globalScope, AstStatBlock* program)
4563
{
4564
GlobalPrepopulator gp{NotNull{globalScope.get()}, arena, dfg};
4565
4566
if (prepareModuleScope)
4567
prepareModuleScope(module->name, globalScope);
4568
4569
program->visit(&gp);
4570
4571
if (FFlag::LuauKeepExplicitMapForGlobalTypes2)
4572
{
4573
for (auto name : gp.uninitializedGlobals)
4574
uninitializedGlobals.insert(name);
4575
}
4576
4577
// Handle type function globals as well, without preparing a module scope since they have a separate environment
4578
GlobalPrepopulator tfgp{NotNull{typeFunctionRuntime->rootScope.get()}, arena, dfg};
4579
program->visit(&tfgp);
4580
4581
if (FFlag::LuauKeepExplicitMapForGlobalTypes2)
4582
{
4583
for (auto name : tfgp.uninitializedGlobals)
4584
uninitializedGlobals.insert(name);
4585
}
4586
}
4587
4588
bool ConstraintGenerator::recordPropertyAssignment(TypeId ty)
4589
{
4590
DenseHashSet<TypeId> seen{nullptr};
4591
VecDeque<TypeId> queue;
4592
4593
queue.push_back(ty);
4594
4595
bool incremented = false;
4596
4597
while (!queue.empty())
4598
{
4599
const TypeId t = follow(queue.front());
4600
queue.pop_front();
4601
4602
if (seen.find(t))
4603
continue;
4604
seen.insert(t);
4605
4606
if (auto tt = getMutable<TableType>(t); tt && tt->state == TableState::Unsealed)
4607
{
4608
tt->remainingProps += 1;
4609
incremented = true;
4610
}
4611
else if (auto mt = get<MetatableType>(t))
4612
queue.push_back(mt->table);
4613
else if (TypeIds* localDomain = localTypes.find(t))
4614
{
4615
for (TypeId domainTy : *localDomain)
4616
queue.push_back(domainTy);
4617
}
4618
else if (auto ut = get<UnionType>(t))
4619
{
4620
for (TypeId part : ut)
4621
queue.push_back(part);
4622
}
4623
}
4624
4625
return incremented;
4626
}
4627
4628
void ConstraintGenerator::recordInferredBinding(AstLocal* local, TypeId ty)
4629
{
4630
if (InferredBinding* ib = inferredBindings.find(local))
4631
ib->types.insert(ty);
4632
}
4633
4634
void ConstraintGenerator::fillInInferredBindings(const ScopePtr& globalScope, AstStatBlock* block)
4635
{
4636
for (const auto& [symbol, p] : inferredBindings)
4637
{
4638
const auto& [scope, location, types] = p;
4639
4640
std::vector<TypeId> tys(types.begin(), types.end());
4641
if (tys.size() == 1)
4642
scope->bindings[symbol] = Binding{tys.front(), location};
4643
else
4644
{
4645
TypeId ty = makeUnion(std::move(tys));
4646
scope->bindings[symbol] = Binding{ty, location};
4647
}
4648
}
4649
}
4650
4651
std::vector<std::optional<TypeId>> ConstraintGenerator::getExpectedCallTypesForFunctionOverloads(const TypeId fnType)
4652
{
4653
std::vector<TypeId> funTys;
4654
if (auto it = get<IntersectionType>(follow(fnType)))
4655
{
4656
for (TypeId intersectionComponent : it)
4657
{
4658
funTys.push_back(intersectionComponent);
4659
}
4660
}
4661
4662
std::vector<std::optional<TypeId>> expectedTypes;
4663
// For a list of functions f_0 : e_0 -> r_0, ... f_n : e_n -> r_n,
4664
// emit a list of arguments that the function could take at each position
4665
// by unioning the arguments at each place
4666
auto assignOption = [this, &expectedTypes](size_t index, TypeId ty)
4667
{
4668
if (index == expectedTypes.size())
4669
{
4670
expectedTypes.emplace_back(ty);
4671
}
4672
else if (ty)
4673
{
4674
auto& el = expectedTypes[index];
4675
4676
if (!el)
4677
el = ty;
4678
else
4679
{
4680
std::vector<TypeId> result = reduceUnion({*el, ty});
4681
if (result.empty())
4682
el = builtinTypes->neverType;
4683
else if (result.size() == 1)
4684
el = result[0];
4685
else
4686
el = makeUnion(std::move(result));
4687
}
4688
}
4689
};
4690
4691
for (const TypeId overload : funTys)
4692
{
4693
if (const FunctionType* ftv = get<FunctionType>(follow(overload)))
4694
{
4695
auto [argsHead, argsTail] = flatten(ftv->argTypes);
4696
size_t start = ftv->hasSelf ? 1 : 0;
4697
size_t index = 0;
4698
for (size_t i = start; i < argsHead.size(); ++i)
4699
assignOption(index++, argsHead[i]);
4700
if (argsTail)
4701
{
4702
argsTail = follow(*argsTail);
4703
if (const VariadicTypePack* vtp = get<VariadicTypePack>(*argsTail))
4704
{
4705
while (index < funTys.size())
4706
assignOption(index++, vtp->ty);
4707
}
4708
}
4709
}
4710
}
4711
4712
// TODO vvijay Feb 24, 2023 apparently we have to demote the typeArguments here?
4713
4714
return expectedTypes;
4715
}
4716
4717
TypeId ConstraintGenerator::createTypeFunctionInstance(
4718
const TypeFunction& function,
4719
std::vector<TypeId> typeArguments,
4720
std::vector<TypePackId> packArguments,
4721
const ScopePtr& scope,
4722
Location location
4723
)
4724
{
4725
TypeId result = arena->addTypeFunction(function, std::move(typeArguments), std::move(packArguments));
4726
addConstraint(scope, location, ReduceConstraint{result});
4727
return result;
4728
}
4729
4730
TypeId ConstraintGenerator::simplifyUnion(const ScopePtr& scope, Location location, TypeId left, TypeId right)
4731
{
4732
return ::Luau::simplifyUnion(builtinTypes, arena, left, right).result;
4733
}
4734
4735
void ConstraintGenerator::updateRValueRefinements(const ScopePtr& scope, DefId def, TypeId ty) const
4736
{
4737
updateRValueRefinements(scope.get(), def, ty);
4738
}
4739
4740
void ConstraintGenerator::updateRValueRefinements(Scope* scope, DefId def, TypeId ty) const
4741
{
4742
scope->rvalueRefinements[def] = ty;
4743
if (auto sym = dfg->getSymbolFromDef(def))
4744
scope->refinements[*sym] = ty;
4745
}
4746
4747
4748
} // namespace Luau
4749
4750