// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/LValue.h" #include "Luau/Ast.h" #include namespace Luau { bool Field::operator==(const Field& rhs) const { LUAU_ASSERT(parent && rhs.parent); return key == rhs.key && (parent == rhs.parent || *parent == *rhs.parent); } bool Field::operator!=(const Field& rhs) const { return !(*this == rhs); } size_t LValueHasher::operator()(const LValue& lvalue) const { // Most likely doesn't produce high quality hashes, but we're probably ok enough with it. // When an evidence is shown that operator==(LValue) is used more often than it should, we can have a look at improving the hash quality. size_t acc = 0; size_t offset = 0; const LValue* current = &lvalue; while (current) { if (auto field = get(*current)) acc ^= (std::hash{}(field->key) << 1) >> ++offset; else if (auto symbol = get(*current)) acc ^= std::hash{}(*symbol) << 1; else LUAU_ASSERT(!"Hash not accumulated for this new LValue alternative."); current = baseof(*current); } return acc; } const LValue* baseof(const LValue& lvalue) { if (auto field = get(lvalue)) return field->parent.get(); auto symbol = get(lvalue); LUAU_ASSERT(symbol); return nullptr; // Base of root is null. } std::optional tryGetLValue(const AstExpr& node) { const AstExpr* expr = &node; while (auto e = expr->as()) expr = e->expr; if (auto local = expr->as()) return Symbol{local->local}; else if (auto global = expr->as()) return Symbol{global->name}; else if (auto indexname = expr->as()) { if (auto lvalue = tryGetLValue(*indexname->expr)) return Field{std::make_shared(*lvalue), indexname->index.value}; } else if (auto indexexpr = expr->as()) { if (auto lvalue = tryGetLValue(*indexexpr->expr)) if (auto string = indexexpr->index->as()) return Field{std::make_shared(*lvalue), std::string(string->value.data, string->value.size)}; } return std::nullopt; } Symbol getBaseSymbol(const LValue& lvalue) { const LValue* current = &lvalue; while (auto field = get(*current)) current = baseof(*current); const Symbol* symbol = get(*current); LUAU_ASSERT(symbol); return *symbol; } void merge(RefinementMap& l, const RefinementMap& r, std::function f) { for (const auto& [k, a] : r) { if (auto it = l.find(k); it != l.end()) l[k] = f(it->second, a); else l[k] = a; } } void addRefinement(RefinementMap& refis, const LValue& lvalue, TypeId ty) { refis[lvalue] = ty; } } // namespace Luau