luau/Compiler/src/Types.cpp

765 lines
23 KiB
C++
Raw Normal View History

2023-06-16 18:01:18 +01:00
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
#include "Types.h"
2023-08-11 13:55:30 +01:00
#include "Luau/BytecodeBuilder.h"
2024-04-25 21:57:23 +01:00
LUAU_FASTFLAG(LuauCompileTypeInfo)
2024-05-03 17:38:34 +01:00
LUAU_FASTFLAG(LuauCompileTempTypeInfo)
2024-04-25 21:57:23 +01:00
2023-06-16 18:01:18 +01:00
namespace Luau
{
2023-07-07 18:14:35 +01:00
static bool isGeneric(AstName name, const AstArray<AstGenericType>& generics)
{
for (const AstGenericType& gt : generics)
if (gt.name == name)
return true;
return false;
}
2023-07-14 16:57:16 +01:00
static LuauBytecodeType getPrimitiveType(AstName name)
2023-07-07 18:14:35 +01:00
{
if (name == "nil")
return LBC_TYPE_NIL;
else if (name == "boolean")
return LBC_TYPE_BOOLEAN;
else if (name == "number")
return LBC_TYPE_NUMBER;
else if (name == "string")
return LBC_TYPE_STRING;
else if (name == "thread")
return LBC_TYPE_THREAD;
2024-01-12 19:16:39 +00:00
else if (name == "buffer")
2023-10-27 20:33:36 +01:00
return LBC_TYPE_BUFFER;
2023-07-07 18:14:35 +01:00
else if (name == "any" || name == "unknown")
return LBC_TYPE_ANY;
else
return LBC_TYPE_INVALID;
}
2024-05-03 17:38:34 +01:00
static LuauBytecodeType getType(const AstType* ty, const AstArray<AstGenericType>& generics,
const DenseHashMap<AstName, AstStatTypeAlias*>& typeAliases, bool resolveAliases, const char* vectorType)
2023-06-16 18:01:18 +01:00
{
2024-05-03 17:38:34 +01:00
if (const AstTypeReference* ref = ty->as<AstTypeReference>())
2023-06-16 18:01:18 +01:00
{
2023-07-07 18:14:35 +01:00
if (ref->prefix)
2023-06-16 18:01:18 +01:00
return LBC_TYPE_ANY;
2023-07-07 18:14:35 +01:00
if (AstStatTypeAlias* const* alias = typeAliases.find(ref->name); alias && *alias)
{
// note: we only resolve aliases to the depth of 1 to avoid dealing with recursive aliases
if (resolveAliases)
2023-07-14 16:57:16 +01:00
return getType((*alias)->type, (*alias)->generics, typeAliases, /* resolveAliases= */ false, vectorType);
2023-07-07 18:14:35 +01:00
else
return LBC_TYPE_ANY;
}
if (isGeneric(ref->name, generics))
return LBC_TYPE_ANY;
2023-07-14 16:57:16 +01:00
if (vectorType && ref->name == vectorType)
return LBC_TYPE_VECTOR;
if (LuauBytecodeType prim = getPrimitiveType(ref->name); prim != LBC_TYPE_INVALID)
2023-07-07 18:14:35 +01:00
return prim;
// not primitive or alias or generic => host-provided, we assume userdata for now
return LBC_TYPE_USERDATA;
2023-06-16 18:01:18 +01:00
}
2024-05-03 17:38:34 +01:00
else if (const AstTypeTable* table = ty->as<AstTypeTable>())
2023-06-16 18:01:18 +01:00
{
return LBC_TYPE_TABLE;
}
2024-05-03 17:38:34 +01:00
else if (const AstTypeFunction* func = ty->as<AstTypeFunction>())
2023-06-16 18:01:18 +01:00
{
return LBC_TYPE_FUNCTION;
}
2024-05-03 17:38:34 +01:00
else if (const AstTypeUnion* un = ty->as<AstTypeUnion>())
2023-06-16 18:01:18 +01:00
{
bool optional = false;
2023-07-14 16:57:16 +01:00
LuauBytecodeType type = LBC_TYPE_INVALID;
2023-06-16 18:01:18 +01:00
for (AstType* ty : un->types)
{
2023-07-14 16:57:16 +01:00
LuauBytecodeType et = getType(ty, generics, typeAliases, resolveAliases, vectorType);
2023-06-16 18:01:18 +01:00
if (et == LBC_TYPE_NIL)
{
optional = true;
continue;
}
if (type == LBC_TYPE_INVALID)
{
type = et;
continue;
}
if (type != et)
return LBC_TYPE_ANY;
}
if (type == LBC_TYPE_INVALID)
return LBC_TYPE_ANY;
2023-07-14 16:57:16 +01:00
return LuauBytecodeType(type | (optional && (type != LBC_TYPE_ANY) ? LBC_TYPE_OPTIONAL_BIT : 0));
2023-06-16 18:01:18 +01:00
}
2024-05-03 17:38:34 +01:00
else if (const AstTypeIntersection* inter = ty->as<AstTypeIntersection>())
2023-06-16 18:01:18 +01:00
{
return LBC_TYPE_ANY;
}
return LBC_TYPE_ANY;
}
2023-07-14 16:57:16 +01:00
static std::string getFunctionType(const AstExprFunction* func, const DenseHashMap<AstName, AstStatTypeAlias*>& typeAliases, const char* vectorType)
2023-06-16 18:01:18 +01:00
{
bool self = func->self != 0;
std::string typeInfo;
typeInfo.reserve(func->args.size + self + 2);
typeInfo.push_back(LBC_TYPE_FUNCTION);
typeInfo.push_back(uint8_t(self + func->args.size));
if (self)
typeInfo.push_back(LBC_TYPE_TABLE);
bool haveNonAnyParam = false;
for (AstLocal* arg : func->args)
{
2023-07-14 16:57:16 +01:00
LuauBytecodeType ty =
arg->annotation ? getType(arg->annotation, func->generics, typeAliases, /* resolveAliases= */ true, vectorType) : LBC_TYPE_ANY;
2023-06-16 18:01:18 +01:00
if (ty != LBC_TYPE_ANY)
haveNonAnyParam = true;
typeInfo.push_back(ty);
}
// If all parameters simplify to any, we can just omit type info for this function
if (!haveNonAnyParam)
return {};
return typeInfo;
}
2024-05-03 17:38:34 +01:00
static bool isMatchingGlobal(const DenseHashMap<AstName, Compile::Global>& globals, AstExpr* node, const char* name)
{
LUAU_ASSERT(FFlag::LuauCompileTempTypeInfo);
if (AstExprGlobal* expr = node->as<AstExprGlobal>())
return Compile::getGlobalState(globals, expr->name) == Compile::Global::Default && expr->name == name;
return false;
}
2023-07-07 18:14:35 +01:00
struct TypeMapVisitor : AstVisitor
{
2024-04-25 21:57:23 +01:00
DenseHashMap<AstExprFunction*, std::string>& functionTypes;
DenseHashMap<AstLocal*, LuauBytecodeType>& localTypes;
2024-05-03 17:38:34 +01:00
DenseHashMap<AstExpr*, LuauBytecodeType>& exprTypes;
2023-07-14 16:57:16 +01:00
const char* vectorType;
2024-05-03 17:38:34 +01:00
const BuiltinTypes& builtinTypes;
const DenseHashMap<AstExprCall*, int>& builtinCalls;
const DenseHashMap<AstName, Compile::Global>& globals;
2023-07-07 18:14:35 +01:00
DenseHashMap<AstName, AstStatTypeAlias*> typeAliases;
std::vector<std::pair<AstName, AstStatTypeAlias*>> typeAliasStack;
2024-05-03 17:38:34 +01:00
DenseHashMap<AstLocal*, const AstType*> resolvedLocals;
DenseHashMap<AstExpr*, const AstType*> resolvedExprs;
2023-07-07 18:14:35 +01:00
2024-05-03 17:38:34 +01:00
TypeMapVisitor(DenseHashMap<AstExprFunction*, std::string>& functionTypes, DenseHashMap<AstLocal*, LuauBytecodeType>& localTypes,
DenseHashMap<AstExpr*, LuauBytecodeType>& exprTypes, const char* vectorType, const BuiltinTypes& builtinTypes,
const DenseHashMap<AstExprCall*, int>& builtinCalls, const DenseHashMap<AstName, Compile::Global>& globals)
2024-04-25 21:57:23 +01:00
: functionTypes(functionTypes)
, localTypes(localTypes)
2024-05-03 17:38:34 +01:00
, exprTypes(exprTypes)
2023-07-14 16:57:16 +01:00
, vectorType(vectorType)
2024-05-03 17:38:34 +01:00
, builtinTypes(builtinTypes)
, builtinCalls(builtinCalls)
, globals(globals)
2023-07-07 18:14:35 +01:00
, typeAliases(AstName())
2024-05-03 17:38:34 +01:00
, resolvedLocals(nullptr)
, resolvedExprs(nullptr)
2023-07-07 18:14:35 +01:00
{
}
size_t pushTypeAliases(AstStatBlock* block)
{
size_t aliasStackTop = typeAliasStack.size();
for (AstStat* stat : block->body)
if (AstStatTypeAlias* alias = stat->as<AstStatTypeAlias>())
{
AstStatTypeAlias*& prevAlias = typeAliases[alias->name];
typeAliasStack.push_back(std::make_pair(alias->name, prevAlias));
prevAlias = alias;
}
return aliasStackTop;
}
void popTypeAliases(size_t aliasStackTop)
{
while (typeAliasStack.size() > aliasStackTop)
{
std::pair<AstName, AstStatTypeAlias*>& top = typeAliasStack.back();
typeAliases[top.first] = top.second;
typeAliasStack.pop_back();
}
}
2024-05-03 17:38:34 +01:00
const AstType* resolveAliases(const AstType* ty)
{
LUAU_ASSERT(FFlag::LuauCompileTempTypeInfo);
if (const AstTypeReference* ref = ty->as<AstTypeReference>())
{
if (ref->prefix)
return ty;
if (AstStatTypeAlias* const* alias = typeAliases.find(ref->name); alias && *alias)
return (*alias)->type;
}
return ty;
}
const AstTableIndexer* tryGetTableIndexer(AstExpr* expr)
{
LUAU_ASSERT(FFlag::LuauCompileTempTypeInfo);
if (const AstType** typePtr = resolvedExprs.find(expr))
{
if (const AstTypeTable* tableTy = (*typePtr)->as<AstTypeTable>())
return tableTy->indexer;
}
return nullptr;
}
LuauBytecodeType recordResolvedType(AstExpr* expr, const AstType* ty)
{
LUAU_ASSERT(FFlag::LuauCompileTempTypeInfo);
ty = resolveAliases(ty);
resolvedExprs[expr] = ty;
LuauBytecodeType bty = getType(ty, {}, typeAliases, /* resolveAliases= */ true, vectorType);
exprTypes[expr] = bty;
return bty;
}
LuauBytecodeType recordResolvedType(AstLocal* local, const AstType* ty)
{
LUAU_ASSERT(FFlag::LuauCompileTempTypeInfo);
ty = resolveAliases(ty);
resolvedLocals[local] = ty;
LuauBytecodeType bty = getType(ty, {}, typeAliases, /* resolveAliases= */ true, vectorType);
if (bty != LBC_TYPE_ANY)
localTypes[local] = bty;
return bty;
}
2023-07-07 18:14:35 +01:00
bool visit(AstStatBlock* node) override
{
size_t aliasStackTop = pushTypeAliases(node);
for (AstStat* stat : node->body)
stat->visit(this);
popTypeAliases(aliasStackTop);
return false;
}
// repeat..until scoping rules are such that condition (along with any possible functions declared in it) has aliases from repeat body in scope
bool visit(AstStatRepeat* node) override
{
size_t aliasStackTop = pushTypeAliases(node->body);
for (AstStat* stat : node->body->body)
stat->visit(this);
node->condition->visit(this);
popTypeAliases(aliasStackTop);
return false;
}
2024-05-03 17:38:34 +01:00
// for...in statement can contain type annotations on locals (we might even infer some for ipairs/pairs/generalized iteration)
bool visit(AstStatForIn* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
for (AstExpr* expr : node->values)
expr->visit(this);
// This is similar to how Compiler matches builtin iteration, but we also handle generalized iteration case
if (node->vars.size == 2 && node->values.size == 1)
{
if (AstExprCall* call = node->values.data[0]->as<AstExprCall>(); call && call->args.size == 1)
{
AstExpr* func = call->func;
AstExpr* arg = call->args.data[0];
if (isMatchingGlobal(globals, func, "ipairs"))
{
if (const AstTableIndexer* indexer = tryGetTableIndexer(arg))
{
recordResolvedType(node->vars.data[0], &builtinTypes.numberType);
recordResolvedType(node->vars.data[1], indexer->resultType);
}
}
else if (isMatchingGlobal(globals, func, "pairs"))
{
if (const AstTableIndexer* indexer = tryGetTableIndexer(arg))
{
recordResolvedType(node->vars.data[0], indexer->indexType);
recordResolvedType(node->vars.data[1], indexer->resultType);
}
}
}
else if (const AstTableIndexer* indexer = tryGetTableIndexer(node->values.data[0]))
{
recordResolvedType(node->vars.data[0], indexer->indexType);
recordResolvedType(node->vars.data[1], indexer->resultType);
}
}
for (size_t i = 0; i < node->vars.size; i++)
{
AstLocal* var = node->vars.data[i];
if (AstType* annotation = var->annotation)
recordResolvedType(var, annotation);
}
node->body->visit(this);
return false;
}
2023-07-07 18:14:35 +01:00
bool visit(AstExprFunction* node) override
{
2023-07-14 16:57:16 +01:00
std::string type = getFunctionType(node, typeAliases, vectorType);
2023-07-07 18:14:35 +01:00
if (!type.empty())
2024-04-25 21:57:23 +01:00
functionTypes[node] = std::move(type);
2024-05-03 17:38:34 +01:00
return true; // Let generic visitor step into all expressions
2024-04-25 21:57:23 +01:00
}
bool visit(AstExprLocal* node) override
{
2024-05-03 17:38:34 +01:00
if (FFlag::LuauCompileTempTypeInfo)
{
if (FFlag::LuauCompileTypeInfo)
{
AstLocal* local = node->local;
if (AstType* annotation = local->annotation)
{
LuauBytecodeType ty = recordResolvedType(node, annotation);
if (ty != LBC_TYPE_ANY)
localTypes[local] = ty;
}
else if (const AstType** typePtr = resolvedLocals.find(local))
{
localTypes[local] = recordResolvedType(node, *typePtr);
}
}
return false;
}
else
{
if (FFlag::LuauCompileTypeInfo)
{
AstLocal* local = node->local;
if (AstType* annotation = local->annotation)
{
LuauBytecodeType ty = getType(annotation, {}, typeAliases, /* resolveAliases= */ true, vectorType);
if (ty != LBC_TYPE_ANY)
localTypes[local] = ty;
}
}
return true;
}
}
bool visit(AstStatLocal* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
for (AstExpr* expr : node->values)
expr->visit(this);
for (size_t i = 0; i < node->vars.size; i++)
{
AstLocal* var = node->vars.data[i];
// Propagate from the value that's being assigned
// This simple propagation doesn't handle type packs in tail position
if (var->annotation == nullptr)
{
if (i < node->values.size)
{
if (const AstType** typePtr = resolvedExprs.find(node->values.data[i]))
resolvedLocals[var] = *typePtr;
}
}
}
return false;
}
bool visit(AstExprIndexExpr* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
node->expr->visit(this);
node->index->visit(this);
if (const AstTableIndexer* indexer = tryGetTableIndexer(node->expr))
recordResolvedType(node, indexer->resultType);
return false;
}
bool visit(AstExprIndexName* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
node->expr->visit(this);
if (const AstType** typePtr = resolvedExprs.find(node->expr))
2024-04-25 21:57:23 +01:00
{
2024-05-03 17:38:34 +01:00
if (const AstTypeTable* tableTy = (*typePtr)->as<AstTypeTable>())
{
for (const AstTableProp& prop : tableTy->props)
{
if (prop.name == node->index)
{
recordResolvedType(node, prop.type);
return false;
}
}
}
}
2024-04-25 21:57:23 +01:00
2024-05-03 17:38:34 +01:00
if (LuauBytecodeType* typeBcPtr = exprTypes.find(node->expr))
{
if (*typeBcPtr == LBC_TYPE_VECTOR)
2024-04-25 21:57:23 +01:00
{
2024-05-03 17:38:34 +01:00
if (node->index == "X" || node->index == "Y" || node->index == "Z")
recordResolvedType(node, &builtinTypes.numberType);
}
}
return false;
}
bool visit(AstExprUnary* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
node->expr->visit(this);
switch (node->op)
{
case AstExprUnary::Not:
recordResolvedType(node, &builtinTypes.booleanType);
break;
case AstExprUnary::Minus:
{
const AstType** typePtr = resolvedExprs.find(node->expr);
LuauBytecodeType* bcTypePtr = exprTypes.find(node->expr);
if (!typePtr || !bcTypePtr)
return false;
if (*bcTypePtr == LBC_TYPE_VECTOR)
recordResolvedType(node, *typePtr);
else if (*bcTypePtr == LBC_TYPE_NUMBER)
recordResolvedType(node, *typePtr);
break;
}
case AstExprUnary::Len:
recordResolvedType(node, &builtinTypes.numberType);
break;
}
return false;
}
bool visit(AstExprBinary* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
node->left->visit(this);
node->right->visit(this);
// Comparisons result in a boolean
if (node->op == AstExprBinary::CompareNe || node->op == AstExprBinary::CompareEq || node->op == AstExprBinary::CompareLt ||
node->op == AstExprBinary::CompareLe || node->op == AstExprBinary::CompareGt || node->op == AstExprBinary::CompareGe)
{
recordResolvedType(node, &builtinTypes.booleanType);
return false;
}
if (node->op == AstExprBinary::Concat || node->op == AstExprBinary::And || node->op == AstExprBinary::Or)
return false;
const AstType** leftTypePtr = resolvedExprs.find(node->left);
LuauBytecodeType* leftBcTypePtr = exprTypes.find(node->left);
if (!leftTypePtr || !leftBcTypePtr)
return false;
const AstType** rightTypePtr = resolvedExprs.find(node->right);
LuauBytecodeType* rightBcTypePtr = exprTypes.find(node->right);
if (!rightTypePtr || !rightBcTypePtr)
return false;
if (*leftBcTypePtr == LBC_TYPE_VECTOR)
recordResolvedType(node, *leftTypePtr);
else if (*rightBcTypePtr == LBC_TYPE_VECTOR)
recordResolvedType(node, *rightTypePtr);
else if (*leftBcTypePtr == LBC_TYPE_NUMBER && *rightBcTypePtr == LBC_TYPE_NUMBER)
recordResolvedType(node, *leftTypePtr);
return false;
}
bool visit(AstExprGroup* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
node->expr->visit(this);
if (const AstType** typePtr = resolvedExprs.find(node->expr))
recordResolvedType(node, *typePtr);
return false;
}
bool visit(AstExprTypeAssertion* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
node->expr->visit(this);
2024-04-25 21:57:23 +01:00
2024-05-03 17:38:34 +01:00
recordResolvedType(node, node->annotation);
return false;
}
bool visit(AstExprConstantBool* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
recordResolvedType(node, &builtinTypes.booleanType);
return false;
}
bool visit(AstExprConstantNumber* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
recordResolvedType(node, &builtinTypes.numberType);
return false;
}
bool visit(AstExprConstantString* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
recordResolvedType(node, &builtinTypes.stringType);
return false;
}
bool visit(AstExprInterpString* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
recordResolvedType(node, &builtinTypes.stringType);
return false;
}
bool visit(AstExprIfElse* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
node->condition->visit(this);
node->trueExpr->visit(this);
node->falseExpr->visit(this);
const AstType** trueTypePtr = resolvedExprs.find(node->trueExpr);
LuauBytecodeType* trueBcTypePtr = exprTypes.find(node->trueExpr);
LuauBytecodeType* falseBcTypePtr = exprTypes.find(node->falseExpr);
// Optimistic check that both expressions are of the same kind, as AstType* cannot be compared
if (trueTypePtr && trueBcTypePtr && falseBcTypePtr && *trueBcTypePtr == *falseBcTypePtr)
recordResolvedType(node, *trueTypePtr);
return false;
}
bool visit(AstExprCall* node) override
{
if (!FFlag::LuauCompileTempTypeInfo)
return true;
if (const int* bfid = builtinCalls.find(node))
{
switch (LuauBuiltinFunction(*bfid))
{
case LBF_NONE:
case LBF_ASSERT:
case LBF_RAWSET:
case LBF_RAWGET:
case LBF_TABLE_INSERT:
case LBF_TABLE_UNPACK:
case LBF_SELECT_VARARG:
case LBF_GETMETATABLE:
case LBF_SETMETATABLE:
case LBF_BUFFER_WRITEU8:
case LBF_BUFFER_WRITEU16:
case LBF_BUFFER_WRITEU32:
case LBF_BUFFER_WRITEF32:
case LBF_BUFFER_WRITEF64:
break;
case LBF_MATH_ABS:
case LBF_MATH_ACOS:
case LBF_MATH_ASIN:
case LBF_MATH_ATAN2:
case LBF_MATH_ATAN:
case LBF_MATH_CEIL:
case LBF_MATH_COSH:
case LBF_MATH_COS:
case LBF_MATH_DEG:
case LBF_MATH_EXP:
case LBF_MATH_FLOOR:
case LBF_MATH_FMOD:
case LBF_MATH_FREXP:
case LBF_MATH_LDEXP:
case LBF_MATH_LOG10:
case LBF_MATH_LOG:
case LBF_MATH_MAX:
case LBF_MATH_MIN:
case LBF_MATH_MODF:
case LBF_MATH_POW:
case LBF_MATH_RAD:
case LBF_MATH_SINH:
case LBF_MATH_SIN:
case LBF_MATH_SQRT:
case LBF_MATH_TANH:
case LBF_MATH_TAN:
case LBF_BIT32_ARSHIFT:
case LBF_BIT32_BAND:
case LBF_BIT32_BNOT:
case LBF_BIT32_BOR:
case LBF_BIT32_BXOR:
case LBF_BIT32_BTEST:
case LBF_BIT32_EXTRACT:
case LBF_BIT32_LROTATE:
case LBF_BIT32_LSHIFT:
case LBF_BIT32_REPLACE:
case LBF_BIT32_RROTATE:
case LBF_BIT32_RSHIFT:
case LBF_STRING_BYTE:
case LBF_STRING_LEN:
case LBF_MATH_CLAMP:
case LBF_MATH_SIGN:
case LBF_MATH_ROUND:
case LBF_BIT32_COUNTLZ:
case LBF_BIT32_COUNTRZ:
case LBF_RAWLEN:
case LBF_BIT32_EXTRACTK:
case LBF_TONUMBER:
case LBF_BIT32_BYTESWAP:
case LBF_BUFFER_READI8:
case LBF_BUFFER_READU8:
case LBF_BUFFER_READI16:
case LBF_BUFFER_READU16:
case LBF_BUFFER_READI32:
case LBF_BUFFER_READU32:
case LBF_BUFFER_READF32:
case LBF_BUFFER_READF64:
recordResolvedType(node, &builtinTypes.numberType);
break;
case LBF_TYPE:
case LBF_STRING_CHAR:
case LBF_TYPEOF:
case LBF_STRING_SUB:
case LBF_TOSTRING:
recordResolvedType(node, &builtinTypes.stringType);
break;
case LBF_RAWEQUAL:
recordResolvedType(node, &builtinTypes.booleanType);
break;
case LBF_VECTOR:
recordResolvedType(node, &builtinTypes.vectorType);
break;
2024-04-25 21:57:23 +01:00
}
}
2023-07-07 18:14:35 +01:00
2024-05-03 17:38:34 +01:00
return true; // Let generic visitor step into all expressions
2023-07-07 18:14:35 +01:00
}
2024-05-03 17:38:34 +01:00
// AstExpr classes that are not covered:
// * AstExprConstantNil is not resolved to 'nil' because that doesn't help codegen operations and often used as an initializer before real value
// * AstExprGlobal is not supported as we don't have info on globals
// * AstExprVarargs cannot be resolved to a testable type
// * AstExprTable cannot be reconstructed into a specific AstTypeTable and table annotations don't really help codegen
// * AstExprCall is very complex (especially if builtins and registered globals are included), will be extended in the future
2023-07-07 18:14:35 +01:00
};
2024-05-03 17:38:34 +01:00
void buildTypeMap(DenseHashMap<AstExprFunction*, std::string>& functionTypes, DenseHashMap<AstLocal*, LuauBytecodeType>& localTypes,
DenseHashMap<AstExpr*, LuauBytecodeType>& exprTypes, AstNode* root, const char* vectorType, const BuiltinTypes& builtinTypes,
const DenseHashMap<AstExprCall*, int>& builtinCalls, const DenseHashMap<AstName, Compile::Global>& globals)
2023-07-07 18:14:35 +01:00
{
2024-05-03 17:38:34 +01:00
TypeMapVisitor visitor(functionTypes, localTypes, exprTypes, vectorType, builtinTypes, builtinCalls, globals);
2023-07-07 18:14:35 +01:00
root->visit(&visitor);
}
} // namespace Luau