Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/Compiler/src/Types.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 "Types.h"
3
4
#include "Luau/BytecodeBuilder.h"
5
6
LUAU_FASTFLAGVARIABLE(LuauCompileExtraTypes)
7
LUAU_FASTFLAG(LuauIntegerFastcalls)
8
9
namespace Luau
10
{
11
12
static bool isGeneric(AstName name, const AstArray<AstGenericType*>& generics)
13
{
14
for (const AstGenericType* gt : generics)
15
if (gt->name == name)
16
return true;
17
18
return false;
19
}
20
21
static LuauBytecodeType getPrimitiveType(AstName name)
22
{
23
if (name == "nil")
24
return LBC_TYPE_NIL;
25
else if (name == "boolean")
26
return LBC_TYPE_BOOLEAN;
27
else if (name == "number")
28
return LBC_TYPE_NUMBER;
29
else if (name == "integer")
30
return LBC_TYPE_INTEGER;
31
else if (name == "string")
32
return LBC_TYPE_STRING;
33
else if (name == "thread")
34
return LBC_TYPE_THREAD;
35
else if (name == "buffer")
36
return LBC_TYPE_BUFFER;
37
else if (name == "vector")
38
return LBC_TYPE_VECTOR;
39
else if (name == "any" || name == "unknown")
40
return LBC_TYPE_ANY;
41
else
42
return LBC_TYPE_INVALID;
43
}
44
45
static LuauBytecodeType getType(
46
const AstType* ty,
47
const AstArray<AstGenericType*>& generics,
48
const DenseHashMap<AstName, AstStatTypeAlias*>& typeAliases,
49
bool resolveAliases,
50
const char* hostVectorType,
51
const DenseHashMap<AstName, uint8_t>& userdataTypes,
52
BytecodeBuilder& bytecode
53
)
54
{
55
if (const AstTypeReference* ref = ty->as<AstTypeReference>())
56
{
57
if (ref->prefix)
58
return LBC_TYPE_ANY;
59
60
if (AstStatTypeAlias* const* alias = typeAliases.find(ref->name); alias && *alias)
61
{
62
// note: we only resolve aliases to the depth of 1 to avoid dealing with recursive aliases
63
if (resolveAliases)
64
return getType((*alias)->type, (*alias)->generics, typeAliases, /* resolveAliases= */ false, hostVectorType, userdataTypes, bytecode);
65
else
66
return LBC_TYPE_ANY;
67
}
68
69
if (isGeneric(ref->name, generics))
70
return LBC_TYPE_ANY;
71
72
if (hostVectorType && ref->name == hostVectorType)
73
return LBC_TYPE_VECTOR;
74
75
if (LuauBytecodeType prim = getPrimitiveType(ref->name); prim != LBC_TYPE_INVALID)
76
return prim;
77
78
if (const uint8_t* userdataIndex = userdataTypes.find(ref->name))
79
{
80
bytecode.useUserdataType(*userdataIndex);
81
return LuauBytecodeType(LBC_TYPE_TAGGED_USERDATA_BASE + *userdataIndex);
82
}
83
84
// not primitive or alias or generic => host-provided, we assume userdata for now
85
return LBC_TYPE_USERDATA;
86
}
87
else if (const AstTypeTable* table = ty->as<AstTypeTable>())
88
{
89
return LBC_TYPE_TABLE;
90
}
91
else if (const AstTypeFunction* func = ty->as<AstTypeFunction>())
92
{
93
return LBC_TYPE_FUNCTION;
94
}
95
else if (const AstTypeUnion* un = ty->as<AstTypeUnion>())
96
{
97
bool optional = false;
98
LuauBytecodeType type = LBC_TYPE_INVALID;
99
100
for (AstType* ty : un->types)
101
{
102
LuauBytecodeType et = getType(ty, generics, typeAliases, resolveAliases, hostVectorType, userdataTypes, bytecode);
103
104
if (et == LBC_TYPE_NIL)
105
{
106
optional = true;
107
continue;
108
}
109
110
if (type == LBC_TYPE_INVALID)
111
{
112
type = et;
113
continue;
114
}
115
116
if (type != et)
117
return LBC_TYPE_ANY;
118
}
119
120
if (type == LBC_TYPE_INVALID)
121
return LBC_TYPE_ANY;
122
123
return LuauBytecodeType(type | (optional && (type != LBC_TYPE_ANY) ? LBC_TYPE_OPTIONAL_BIT : 0));
124
}
125
else if (const AstTypeIntersection* inter = ty->as<AstTypeIntersection>())
126
{
127
return LBC_TYPE_ANY;
128
}
129
else if (const AstTypeGroup* group = ty->as<AstTypeGroup>())
130
{
131
return getType(group->type, generics, typeAliases, resolveAliases, hostVectorType, userdataTypes, bytecode);
132
}
133
else if (const AstTypeOptional* optional = ty->as<AstTypeOptional>())
134
{
135
return LBC_TYPE_NIL;
136
}
137
else if (FFlag::LuauCompileExtraTypes && ty->is<AstTypeSingletonBool>())
138
{
139
return LBC_TYPE_BOOLEAN;
140
}
141
else if (FFlag::LuauCompileExtraTypes && ty->is<AstTypeSingletonString>())
142
{
143
return LBC_TYPE_STRING;
144
}
145
146
return LBC_TYPE_ANY;
147
}
148
149
static std::string getFunctionType(
150
const AstExprFunction* func,
151
const DenseHashMap<AstName, AstStatTypeAlias*>& typeAliases,
152
const char* hostVectorType,
153
const DenseHashMap<AstName, uint8_t>& userdataTypes,
154
BytecodeBuilder& bytecode
155
)
156
{
157
bool self = func->self != 0;
158
159
std::string typeInfo;
160
typeInfo.reserve(func->args.size + self + 2);
161
162
typeInfo.push_back(LBC_TYPE_FUNCTION);
163
typeInfo.push_back(uint8_t(self + func->args.size));
164
165
if (self)
166
typeInfo.push_back(LBC_TYPE_TABLE);
167
168
bool haveNonAnyParam = false;
169
for (AstLocal* arg : func->args)
170
{
171
LuauBytecodeType ty =
172
arg->annotation
173
? getType(arg->annotation, func->generics, typeAliases, /* resolveAliases= */ true, hostVectorType, userdataTypes, bytecode)
174
: LBC_TYPE_ANY;
175
176
if (ty != LBC_TYPE_ANY)
177
haveNonAnyParam = true;
178
179
typeInfo.push_back(ty);
180
}
181
182
// If all parameters simplify to any, we can just omit type info for this function
183
if (!haveNonAnyParam)
184
return {};
185
186
return typeInfo;
187
}
188
189
static bool isMatchingGlobal(const DenseHashMap<AstName, Compile::Global>& globals, AstExpr* node, const char* name)
190
{
191
if (AstExprGlobal* expr = node->as<AstExprGlobal>())
192
return Compile::getGlobalState(globals, expr->name) == Compile::Global::Default && expr->name == name;
193
194
return false;
195
}
196
197
static bool isMatchingGlobalMember(
198
const DenseHashMap<AstName, Compile::Global>& globals,
199
AstExprIndexName* expr,
200
const char* library,
201
const char* member
202
)
203
{
204
if (AstExprGlobal* object = expr->expr->as<AstExprGlobal>())
205
return getGlobalState(globals, object->name) == Compile::Global::Default && object->name == library && expr->index == member;
206
207
return false;
208
}
209
210
struct TypeMapVisitor : AstVisitor
211
{
212
DenseHashMap<AstExprFunction*, std::string>& functionTypes;
213
DenseHashMap<AstLocal*, LuauBytecodeType>& localTypes;
214
DenseHashMap<AstExpr*, LuauBytecodeType>& exprTypes;
215
const char* hostVectorType = nullptr;
216
const DenseHashMap<AstName, uint8_t>& userdataTypes;
217
const BuiltinAstTypes& builtinTypes;
218
const DenseHashMap<AstExprCall*, int>& builtinCalls;
219
const DenseHashMap<AstName, Compile::Global>& globals;
220
LibraryMemberTypeCallback libraryMemberTypeCb = nullptr;
221
BytecodeBuilder& bytecode;
222
223
DenseHashMap<AstName, AstStatTypeAlias*> typeAliases;
224
std::vector<std::pair<AstName, AstStatTypeAlias*>> typeAliasStack;
225
DenseHashMap<AstLocal*, const AstType*> resolvedLocals;
226
DenseHashMap<AstExpr*, const AstType*> resolvedExprs;
227
DenseHashMap<AstLocal*, const AstType*> functionReturnTypes{nullptr};
228
229
TypeMapVisitor(
230
DenseHashMap<AstExprFunction*, std::string>& functionTypes,
231
DenseHashMap<AstLocal*, LuauBytecodeType>& localTypes,
232
DenseHashMap<AstExpr*, LuauBytecodeType>& exprTypes,
233
const char* hostVectorType,
234
const DenseHashMap<AstName, uint8_t>& userdataTypes,
235
const BuiltinAstTypes& builtinTypes,
236
const DenseHashMap<AstExprCall*, int>& builtinCalls,
237
const DenseHashMap<AstName, Compile::Global>& globals,
238
LibraryMemberTypeCallback libraryMemberTypeCb,
239
BytecodeBuilder& bytecode
240
)
241
: functionTypes(functionTypes)
242
, localTypes(localTypes)
243
, exprTypes(exprTypes)
244
, hostVectorType(hostVectorType)
245
, userdataTypes(userdataTypes)
246
, builtinTypes(builtinTypes)
247
, builtinCalls(builtinCalls)
248
, globals(globals)
249
, libraryMemberTypeCb(libraryMemberTypeCb)
250
, bytecode(bytecode)
251
, typeAliases(AstName())
252
, resolvedLocals(nullptr)
253
, resolvedExprs(nullptr)
254
{
255
}
256
257
size_t pushTypeAliases(AstStatBlock* block)
258
{
259
size_t aliasStackTop = typeAliasStack.size();
260
261
for (AstStat* stat : block->body)
262
if (AstStatTypeAlias* alias = stat->as<AstStatTypeAlias>())
263
{
264
AstStatTypeAlias*& prevAlias = typeAliases[alias->name];
265
266
typeAliasStack.push_back(std::make_pair(alias->name, prevAlias));
267
prevAlias = alias;
268
}
269
270
return aliasStackTop;
271
}
272
273
void popTypeAliases(size_t aliasStackTop)
274
{
275
while (typeAliasStack.size() > aliasStackTop)
276
{
277
std::pair<AstName, AstStatTypeAlias*>& top = typeAliasStack.back();
278
279
typeAliases[top.first] = top.second;
280
typeAliasStack.pop_back();
281
}
282
}
283
284
const AstType* resolveAliases(const AstType* ty)
285
{
286
if (const AstTypeReference* ref = ty->as<AstTypeReference>())
287
{
288
if (ref->prefix)
289
return ty;
290
291
if (AstStatTypeAlias* const* alias = typeAliases.find(ref->name); alias && *alias)
292
return (*alias)->type;
293
}
294
295
return ty;
296
}
297
298
const AstTableIndexer* tryGetTableIndexer(AstExpr* expr)
299
{
300
if (const AstType** typePtr = resolvedExprs.find(expr))
301
{
302
if (const AstTypeTable* tableTy = (*typePtr)->as<AstTypeTable>())
303
return tableTy->indexer;
304
}
305
306
return nullptr;
307
}
308
309
LuauBytecodeType recordResolvedType(AstExpr* expr, const AstType* ty)
310
{
311
ty = resolveAliases(ty);
312
313
resolvedExprs[expr] = ty;
314
315
LuauBytecodeType bty = getType(ty, {}, typeAliases, /* resolveAliases= */ true, hostVectorType, userdataTypes, bytecode);
316
exprTypes[expr] = bty;
317
return bty;
318
}
319
320
LuauBytecodeType recordResolvedType(AstLocal* local, const AstType* ty)
321
{
322
ty = resolveAliases(ty);
323
324
resolvedLocals[local] = ty;
325
326
LuauBytecodeType bty = getType(ty, {}, typeAliases, /* resolveAliases= */ true, hostVectorType, userdataTypes, bytecode);
327
328
if (bty != LBC_TYPE_ANY)
329
localTypes[local] = bty;
330
331
return bty;
332
}
333
334
bool visit(AstStatBlock* node) override
335
{
336
size_t aliasStackTop = pushTypeAliases(node);
337
338
for (AstStat* stat : node->body)
339
stat->visit(this);
340
341
popTypeAliases(aliasStackTop);
342
343
return false;
344
}
345
346
// repeat..until scoping rules are such that condition (along with any possible functions declared in it) has aliases from repeat body in scope
347
bool visit(AstStatRepeat* node) override
348
{
349
size_t aliasStackTop = pushTypeAliases(node->body);
350
351
for (AstStat* stat : node->body->body)
352
stat->visit(this);
353
354
node->condition->visit(this);
355
356
popTypeAliases(aliasStackTop);
357
358
return false;
359
}
360
361
bool visit(AstStatFor* node) override
362
{
363
if (FFlag::LuauCompileExtraTypes)
364
recordResolvedType(node->var, &builtinTypes.numberType);
365
366
return true; // Let generic visitor step into all expressions
367
}
368
369
// for...in statement can contain type annotations on locals (we might even infer some for ipairs/pairs/generalized iteration)
370
bool visit(AstStatForIn* node) override
371
{
372
for (AstExpr* expr : node->values)
373
expr->visit(this);
374
375
// This is similar to how Compiler matches builtin iteration, but we also handle generalized iteration case
376
if (node->vars.size == 2 && node->values.size == 1)
377
{
378
if (AstExprCall* call = node->values.data[0]->as<AstExprCall>(); call && call->args.size == 1)
379
{
380
AstExpr* func = call->func;
381
AstExpr* arg = call->args.data[0];
382
383
if (isMatchingGlobal(globals, func, "ipairs"))
384
{
385
if (const AstTableIndexer* indexer = tryGetTableIndexer(arg))
386
{
387
recordResolvedType(node->vars.data[0], &builtinTypes.numberType);
388
recordResolvedType(node->vars.data[1], indexer->resultType);
389
}
390
}
391
else if (isMatchingGlobal(globals, func, "pairs"))
392
{
393
if (const AstTableIndexer* indexer = tryGetTableIndexer(arg))
394
{
395
recordResolvedType(node->vars.data[0], indexer->indexType);
396
recordResolvedType(node->vars.data[1], indexer->resultType);
397
}
398
}
399
}
400
else if (const AstTableIndexer* indexer = tryGetTableIndexer(node->values.data[0]))
401
{
402
recordResolvedType(node->vars.data[0], indexer->indexType);
403
recordResolvedType(node->vars.data[1], indexer->resultType);
404
}
405
}
406
407
for (size_t i = 0; i < node->vars.size; i++)
408
{
409
AstLocal* var = node->vars.data[i];
410
411
if (AstType* annotation = var->annotation)
412
recordResolvedType(var, annotation);
413
}
414
415
node->body->visit(this);
416
417
return false;
418
}
419
420
bool visit(AstStatLocalFunction* node) override
421
{
422
if (FFlag::LuauCompileExtraTypes && node->func->returnAnnotation != nullptr)
423
{
424
if (AstTypePackExplicit* type = node->func->returnAnnotation->as<AstTypePackExplicit>())
425
{
426
if (type->typeList.types.size >= 1)
427
functionReturnTypes[node->name] = type->typeList.types.data[0];
428
}
429
}
430
431
return true; // Let generic visitor step into all expressions
432
}
433
434
bool visit(AstExprFunction* node) override
435
{
436
std::string type = getFunctionType(node, typeAliases, hostVectorType, userdataTypes, bytecode);
437
438
if (!type.empty())
439
functionTypes[node] = std::move(type);
440
441
return true; // Let generic visitor step into all expressions
442
}
443
444
bool visit(AstExprLocal* node) override
445
{
446
AstLocal* local = node->local;
447
448
if (AstType* annotation = local->annotation)
449
{
450
LuauBytecodeType ty = recordResolvedType(node, annotation);
451
452
if (ty != LBC_TYPE_ANY)
453
localTypes[local] = ty;
454
}
455
else if (const AstType** typePtr = resolvedLocals.find(local))
456
{
457
localTypes[local] = recordResolvedType(node, *typePtr);
458
}
459
460
return false;
461
}
462
463
bool visit(AstStatLocal* node) override
464
{
465
for (AstExpr* expr : node->values)
466
expr->visit(this);
467
468
for (size_t i = 0; i < node->vars.size; i++)
469
{
470
AstLocal* var = node->vars.data[i];
471
472
// Propagate from the value that's being assigned
473
// This simple propagation doesn't handle type packs in tail position
474
if (var->annotation == nullptr)
475
{
476
if (i < node->values.size)
477
{
478
if (const AstType** typePtr = resolvedExprs.find(node->values.data[i]))
479
resolvedLocals[var] = *typePtr;
480
}
481
}
482
}
483
484
return false;
485
}
486
487
bool visit(AstExprIndexExpr* node) override
488
{
489
node->expr->visit(this);
490
node->index->visit(this);
491
492
if (const AstTableIndexer* indexer = tryGetTableIndexer(node->expr))
493
recordResolvedType(node, indexer->resultType);
494
495
return false;
496
}
497
498
bool visit(AstExprIndexName* node) override
499
{
500
node->expr->visit(this);
501
502
if (const AstType** typePtr = resolvedExprs.find(node->expr))
503
{
504
if (const AstTypeTable* tableTy = (*typePtr)->as<AstTypeTable>())
505
{
506
for (const AstTableProp& prop : tableTy->props)
507
{
508
if (prop.name == node->index)
509
{
510
recordResolvedType(node, prop.type);
511
return false;
512
}
513
}
514
}
515
}
516
517
if (LuauBytecodeType* typeBcPtr = exprTypes.find(node->expr))
518
{
519
if (*typeBcPtr == LBC_TYPE_VECTOR)
520
{
521
if (node->index == "X" || node->index == "Y" || node->index == "Z")
522
{
523
recordResolvedType(node, &builtinTypes.numberType);
524
return false;
525
}
526
else if (FFlag::LuauCompileExtraTypes && (node->index == "x" || node->index == "y" || node->index == "z"))
527
{
528
recordResolvedType(node, &builtinTypes.numberType);
529
return false;
530
}
531
}
532
}
533
534
if (isMatchingGlobalMember(globals, node, "vector", "zero") || isMatchingGlobalMember(globals, node, "vector", "one"))
535
{
536
recordResolvedType(node, &builtinTypes.vectorType);
537
return false;
538
}
539
540
if (libraryMemberTypeCb)
541
{
542
if (AstExprGlobal* object = node->expr->as<AstExprGlobal>())
543
{
544
if (LuauBytecodeType ty = LuauBytecodeType(libraryMemberTypeCb(object->name.value, node->index.value)); ty != LBC_TYPE_ANY)
545
{
546
// TODO: 'resolvedExprs' is more limited than 'exprTypes' which limits full inference of more complex types that a user
547
// callback can return
548
switch (ty)
549
{
550
case LBC_TYPE_BOOLEAN:
551
resolvedExprs[node] = &builtinTypes.booleanType;
552
break;
553
case LBC_TYPE_NUMBER:
554
resolvedExprs[node] = &builtinTypes.numberType;
555
break;
556
case LBC_TYPE_INTEGER:
557
resolvedExprs[node] = &builtinTypes.integerType;
558
break;
559
case LBC_TYPE_STRING:
560
resolvedExprs[node] = &builtinTypes.stringType;
561
break;
562
case LBC_TYPE_VECTOR:
563
resolvedExprs[node] = &builtinTypes.vectorType;
564
break;
565
default:
566
break;
567
}
568
569
exprTypes[node] = ty;
570
return false;
571
}
572
}
573
}
574
575
return false;
576
}
577
578
bool visit(AstExprUnary* node) override
579
{
580
node->expr->visit(this);
581
582
switch (node->op)
583
{
584
case AstExprUnary::Not:
585
recordResolvedType(node, &builtinTypes.booleanType);
586
break;
587
case AstExprUnary::Minus:
588
{
589
const AstType** typePtr = resolvedExprs.find(node->expr);
590
LuauBytecodeType* bcTypePtr = exprTypes.find(node->expr);
591
592
if (!typePtr || !bcTypePtr)
593
return false;
594
595
if (*bcTypePtr == LBC_TYPE_VECTOR)
596
recordResolvedType(node, *typePtr);
597
else if (*bcTypePtr == LBC_TYPE_NUMBER)
598
recordResolvedType(node, *typePtr);
599
600
break;
601
}
602
case AstExprUnary::Len:
603
recordResolvedType(node, &builtinTypes.numberType);
604
break;
605
}
606
607
return false;
608
}
609
610
bool visit(AstExprBinary* node) override
611
{
612
node->left->visit(this);
613
node->right->visit(this);
614
615
// Comparisons result in a boolean
616
if (node->op == AstExprBinary::CompareNe || node->op == AstExprBinary::CompareEq || node->op == AstExprBinary::CompareLt ||
617
node->op == AstExprBinary::CompareLe || node->op == AstExprBinary::CompareGt || node->op == AstExprBinary::CompareGe)
618
{
619
recordResolvedType(node, &builtinTypes.booleanType);
620
return false;
621
}
622
623
if (node->op == AstExprBinary::Concat || node->op == AstExprBinary::And || node->op == AstExprBinary::Or)
624
return false;
625
626
const AstType** leftTypePtr = resolvedExprs.find(node->left);
627
LuauBytecodeType* leftBcTypePtr = exprTypes.find(node->left);
628
629
if (!leftTypePtr || !leftBcTypePtr)
630
return false;
631
632
const AstType** rightTypePtr = resolvedExprs.find(node->right);
633
LuauBytecodeType* rightBcTypePtr = exprTypes.find(node->right);
634
635
if (!rightTypePtr || !rightBcTypePtr)
636
return false;
637
638
if (*leftBcTypePtr == LBC_TYPE_VECTOR)
639
recordResolvedType(node, *leftTypePtr);
640
else if (*rightBcTypePtr == LBC_TYPE_VECTOR)
641
recordResolvedType(node, *rightTypePtr);
642
else if (*leftBcTypePtr == LBC_TYPE_NUMBER && *rightBcTypePtr == LBC_TYPE_NUMBER)
643
recordResolvedType(node, *leftTypePtr);
644
645
return false;
646
}
647
648
bool visit(AstExprGroup* node) override
649
{
650
node->expr->visit(this);
651
652
if (const AstType** typePtr = resolvedExprs.find(node->expr))
653
recordResolvedType(node, *typePtr);
654
655
return false;
656
}
657
658
bool visit(AstExprTypeAssertion* node) override
659
{
660
node->expr->visit(this);
661
662
recordResolvedType(node, node->annotation);
663
664
return false;
665
}
666
667
bool visit(AstExprConstantBool* node) override
668
{
669
recordResolvedType(node, &builtinTypes.booleanType);
670
671
return false;
672
}
673
674
bool visit(AstExprConstantNumber* node) override
675
{
676
recordResolvedType(node, &builtinTypes.numberType);
677
678
return false;
679
}
680
681
bool visit(AstExprConstantInteger* node) override
682
{
683
recordResolvedType(node, &builtinTypes.integerType);
684
685
return false;
686
}
687
688
bool visit(AstExprConstantString* node) override
689
{
690
recordResolvedType(node, &builtinTypes.stringType);
691
692
return false;
693
}
694
695
bool visit(AstExprInterpString* node) override
696
{
697
recordResolvedType(node, &builtinTypes.stringType);
698
699
return false;
700
}
701
702
bool visit(AstExprIfElse* node) override
703
{
704
node->condition->visit(this);
705
node->trueExpr->visit(this);
706
node->falseExpr->visit(this);
707
708
const AstType** trueTypePtr = resolvedExprs.find(node->trueExpr);
709
LuauBytecodeType* trueBcTypePtr = exprTypes.find(node->trueExpr);
710
LuauBytecodeType* falseBcTypePtr = exprTypes.find(node->falseExpr);
711
712
// Optimistic check that both expressions are of the same kind, as AstType* cannot be compared
713
if (trueTypePtr && trueBcTypePtr && falseBcTypePtr && *trueBcTypePtr == *falseBcTypePtr)
714
recordResolvedType(node, *trueTypePtr);
715
716
return false;
717
}
718
719
bool visit(AstExprCall* node) override
720
{
721
if (const int* bfid = builtinCalls.find(node))
722
{
723
switch (LuauBuiltinFunction(*bfid))
724
{
725
case LBF_NONE:
726
case LBF_ASSERT:
727
case LBF_RAWSET:
728
case LBF_RAWGET:
729
case LBF_TABLE_INSERT:
730
case LBF_TABLE_UNPACK:
731
case LBF_SELECT_VARARG:
732
case LBF_GETMETATABLE:
733
case LBF_SETMETATABLE:
734
case LBF_BUFFER_WRITEU8:
735
case LBF_BUFFER_WRITEU16:
736
case LBF_BUFFER_WRITEU32:
737
case LBF_BUFFER_WRITEF32:
738
case LBF_BUFFER_WRITEF64:
739
break;
740
case LBF_MATH_ABS:
741
case LBF_MATH_ACOS:
742
case LBF_MATH_ASIN:
743
case LBF_MATH_ATAN2:
744
case LBF_MATH_ATAN:
745
case LBF_MATH_CEIL:
746
case LBF_MATH_COSH:
747
case LBF_MATH_COS:
748
case LBF_MATH_DEG:
749
case LBF_MATH_EXP:
750
case LBF_MATH_FLOOR:
751
case LBF_MATH_FMOD:
752
case LBF_MATH_FREXP:
753
case LBF_MATH_LDEXP:
754
case LBF_MATH_LOG10:
755
case LBF_MATH_LOG:
756
case LBF_MATH_MAX:
757
case LBF_MATH_MIN:
758
case LBF_MATH_MODF:
759
case LBF_MATH_POW:
760
case LBF_MATH_RAD:
761
case LBF_MATH_SINH:
762
case LBF_MATH_SIN:
763
case LBF_MATH_SQRT:
764
case LBF_MATH_TANH:
765
case LBF_MATH_TAN:
766
case LBF_BIT32_ARSHIFT:
767
case LBF_BIT32_BAND:
768
case LBF_BIT32_BNOT:
769
case LBF_BIT32_BOR:
770
case LBF_BIT32_BXOR:
771
case LBF_BIT32_BTEST:
772
case LBF_BIT32_EXTRACT:
773
case LBF_BIT32_LROTATE:
774
case LBF_BIT32_LSHIFT:
775
case LBF_BIT32_REPLACE:
776
case LBF_BIT32_RROTATE:
777
case LBF_BIT32_RSHIFT:
778
case LBF_STRING_BYTE:
779
case LBF_STRING_LEN:
780
case LBF_MATH_CLAMP:
781
case LBF_MATH_SIGN:
782
case LBF_MATH_ROUND:
783
case LBF_BIT32_COUNTLZ:
784
case LBF_BIT32_COUNTRZ:
785
case LBF_RAWLEN:
786
case LBF_BIT32_EXTRACTK:
787
case LBF_TONUMBER:
788
case LBF_BIT32_BYTESWAP:
789
case LBF_BUFFER_READI8:
790
case LBF_BUFFER_READU8:
791
case LBF_BUFFER_READI16:
792
case LBF_BUFFER_READU16:
793
case LBF_BUFFER_READI32:
794
case LBF_BUFFER_READU32:
795
case LBF_BUFFER_READF32:
796
case LBF_BUFFER_READF64:
797
case LBF_VECTOR_MAGNITUDE:
798
case LBF_VECTOR_DOT:
799
case LBF_MATH_LERP:
800
recordResolvedType(node, &builtinTypes.numberType);
801
break;
802
803
case LBF_TYPE:
804
case LBF_STRING_CHAR:
805
case LBF_TYPEOF:
806
case LBF_STRING_SUB:
807
case LBF_TOSTRING:
808
recordResolvedType(node, &builtinTypes.stringType);
809
break;
810
811
case LBF_MATH_ISNAN:
812
case LBF_MATH_ISINF:
813
case LBF_MATH_ISFINITE:
814
case LBF_RAWEQUAL:
815
recordResolvedType(node, &builtinTypes.booleanType);
816
break;
817
818
case LBF_VECTOR:
819
case LBF_VECTOR_NORMALIZE:
820
case LBF_VECTOR_CROSS:
821
case LBF_VECTOR_FLOOR:
822
case LBF_VECTOR_CEIL:
823
case LBF_VECTOR_ABS:
824
case LBF_VECTOR_SIGN:
825
case LBF_VECTOR_CLAMP:
826
case LBF_VECTOR_MIN:
827
case LBF_VECTOR_MAX:
828
case LBF_VECTOR_LERP:
829
recordResolvedType(node, &builtinTypes.vectorType);
830
break;
831
832
case LBF_INTEGER_ADD:
833
case LBF_INTEGER_SUB:
834
case LBF_INTEGER_MOD:
835
case LBF_INTEGER_MUL:
836
case LBF_INTEGER_DIV:
837
case LBF_INTEGER_IDIV:
838
case LBF_INTEGER_UDIV:
839
case LBF_INTEGER_REM:
840
case LBF_INTEGER_UREM:
841
case LBF_INTEGER_MAX:
842
case LBF_INTEGER_MIN:
843
case LBF_INTEGER_BAND:
844
case LBF_INTEGER_BOR:
845
case LBF_INTEGER_BNOT:
846
case LBF_INTEGER_BXOR:
847
case LBF_INTEGER_LSHIFT:
848
case LBF_INTEGER_RSHIFT:
849
case LBF_INTEGER_ARSHIFT:
850
case LBF_INTEGER_LROTATE:
851
case LBF_INTEGER_RROTATE:
852
case LBF_INTEGER_EXTRACT:
853
case LBF_INTEGER_COUNTLZ:
854
case LBF_INTEGER_COUNTRZ:
855
case LBF_INTEGER_BSWAP:
856
case LBF_INTEGER_CLAMP:
857
case LBF_INTEGER_NEG:
858
case LBF_INTEGER_CREATE:
859
if (!FFlag::LuauIntegerFastcalls)
860
return true;
861
recordResolvedType(node, &builtinTypes.integerType);
862
break;
863
864
case LBF_INTEGER_TONUMBER:
865
if (!FFlag::LuauIntegerFastcalls)
866
return true;
867
recordResolvedType(node, &builtinTypes.numberType);
868
break;
869
870
case LBF_INTEGER_LT:
871
case LBF_INTEGER_LE:
872
case LBF_INTEGER_GT:
873
case LBF_INTEGER_GE:
874
case LBF_INTEGER_ULT:
875
case LBF_INTEGER_ULE:
876
case LBF_INTEGER_UGT:
877
case LBF_INTEGER_UGE:
878
case LBF_INTEGER_BTEST:
879
if (!FFlag::LuauIntegerFastcalls)
880
return true;
881
recordResolvedType(node, &builtinTypes.booleanType);
882
break;
883
}
884
}
885
else if (FFlag::LuauCompileExtraTypes)
886
{
887
if (AstExprLocal* local = node->func->as<AstExprLocal>())
888
{
889
if (const AstType** typePtr = functionReturnTypes.find(local->local))
890
recordResolvedType(node, *typePtr);
891
}
892
}
893
894
return true; // Let generic visitor step into all expressions
895
}
896
897
// AstExpr classes that are not covered:
898
// * AstExprConstantNil is not resolved to 'nil' because that doesn't help codegen operations and often used as an initializer before real value
899
// * AstExprGlobal is not supported as we don't have info on globals
900
// * AstExprVarargs cannot be resolved to a testable type
901
// * AstExprTable cannot be reconstructed into a specific AstTypeTable and table annotations don't really help codegen
902
// * AstExprCall is very complex (especially if builtins and registered globals are included), will be extended in the future
903
};
904
905
void buildTypeMap(
906
DenseHashMap<AstExprFunction*, std::string>& functionTypes,
907
DenseHashMap<AstLocal*, LuauBytecodeType>& localTypes,
908
DenseHashMap<AstExpr*, LuauBytecodeType>& exprTypes,
909
AstNode* root,
910
const char* hostVectorType,
911
const DenseHashMap<AstName, uint8_t>& userdataTypes,
912
const BuiltinAstTypes& builtinTypes,
913
const DenseHashMap<AstExprCall*, int>& builtinCalls,
914
const DenseHashMap<AstName, Compile::Global>& globals,
915
LibraryMemberTypeCallback libraryMemberTypeCb,
916
BytecodeBuilder& bytecode
917
)
918
{
919
TypeMapVisitor visitor(
920
functionTypes, localTypes, exprTypes, hostVectorType, userdataTypes, builtinTypes, builtinCalls, globals, libraryMemberTypeCb, bytecode
921
);
922
root->visit(&visitor);
923
}
924
925
} // namespace Luau
926
927