// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once // Do not include LValue. It should never be used here. #include "Luau/Ast.h" #include "Luau/DenseHash.h" #include "Luau/Def.h" #include "Luau/Symbol.h" #include "Luau/TypedAllocator.h" #include namespace Luau { struct RefinementKey { const RefinementKey* parent = nullptr; DefId def; std::optional propName; }; struct RefinementKeyArena { TypedAllocator allocator; const RefinementKey* leaf(DefId def); const RefinementKey* node(const RefinementKey* parent, DefId def, const std::string& propName); }; struct DataFlowGraph { DataFlowGraph(DataFlowGraph&&) = default; DataFlowGraph& operator=(DataFlowGraph&&) = default; DefId getDef(const AstExpr* expr) const; // Look up for the rvalue breadcrumb for a compound assignment. std::optional getRValueDefForCompoundAssign(const AstExpr* expr) const; DefId getDef(const AstLocal* local) const; DefId getDef(const AstStatDeclareGlobal* global) const; DefId getDef(const AstStatDeclareFunction* func) const; const RefinementKey* getRefinementKey(const AstExpr* expr) const; private: DataFlowGraph() = default; DataFlowGraph(const DataFlowGraph&) = delete; DataFlowGraph& operator=(const DataFlowGraph&) = delete; DefArena defArena; RefinementKeyArena keyArena; DenseHashMap astDefs{nullptr}; // Sometimes we don't have the AstExprLocal* but we have AstLocal*, and sometimes we need to extract that DefId. DenseHashMap localDefs{nullptr}; // There's no AstStatDeclaration, and it feels useless to introduce it just to enforce an invariant in one place. // All keys in this maps are really only statements that ambiently declares a symbol. DenseHashMap declaredDefs{nullptr}; // Compound assignments are in a weird situation where the local being assigned to is also being used at its // previous type implicitly in an rvalue position. This map provides the previous binding. DenseHashMap compoundAssignBreadcrumbs{nullptr}; DenseHashMap astRefinementKeys{nullptr}; friend struct DataFlowGraphBuilder; }; struct DfgScope { DfgScope* parent; DenseHashMap bindings{Symbol{}}; DenseHashMap> props{nullptr}; std::optional lookup(Symbol symbol) const; std::optional lookup(DefId def, const std::string& key) const; }; struct DataFlowResult { DefId def; const RefinementKey* parent = nullptr; }; struct DataFlowGraphBuilder { static DataFlowGraph build(AstStatBlock* root, NotNull handle); private: DataFlowGraphBuilder() = default; DataFlowGraphBuilder(const DataFlowGraphBuilder&) = delete; DataFlowGraphBuilder& operator=(const DataFlowGraphBuilder&) = delete; DataFlowGraph graph; NotNull defArena{&graph.defArena}; NotNull keyArena{&graph.keyArena}; struct InternalErrorReporter* handle = nullptr; DfgScope* moduleScope = nullptr; std::vector> scopes; DfgScope* childScope(DfgScope* scope); void visit(DfgScope* scope, AstStatBlock* b); void visitBlockWithoutChildScope(DfgScope* scope, AstStatBlock* b); void visit(DfgScope* scope, AstStat* s); void visit(DfgScope* scope, AstStatIf* i); void visit(DfgScope* scope, AstStatWhile* w); void visit(DfgScope* scope, AstStatRepeat* r); void visit(DfgScope* scope, AstStatBreak* b); void visit(DfgScope* scope, AstStatContinue* c); void visit(DfgScope* scope, AstStatReturn* r); void visit(DfgScope* scope, AstStatExpr* e); void visit(DfgScope* scope, AstStatLocal* l); void visit(DfgScope* scope, AstStatFor* f); void visit(DfgScope* scope, AstStatForIn* f); void visit(DfgScope* scope, AstStatAssign* a); void visit(DfgScope* scope, AstStatCompoundAssign* c); void visit(DfgScope* scope, AstStatFunction* f); void visit(DfgScope* scope, AstStatLocalFunction* l); void visit(DfgScope* scope, AstStatTypeAlias* t); void visit(DfgScope* scope, AstStatDeclareGlobal* d); void visit(DfgScope* scope, AstStatDeclareFunction* d); void visit(DfgScope* scope, AstStatDeclareClass* d); void visit(DfgScope* scope, AstStatError* error); DataFlowResult visitExpr(DfgScope* scope, AstExpr* e); DataFlowResult visitExpr(DfgScope* scope, AstExprGroup* group); DataFlowResult visitExpr(DfgScope* scope, AstExprLocal* l); DataFlowResult visitExpr(DfgScope* scope, AstExprGlobal* g); DataFlowResult visitExpr(DfgScope* scope, AstExprCall* c); DataFlowResult visitExpr(DfgScope* scope, AstExprIndexName* i); DataFlowResult visitExpr(DfgScope* scope, AstExprIndexExpr* i); DataFlowResult visitExpr(DfgScope* scope, AstExprFunction* f); DataFlowResult visitExpr(DfgScope* scope, AstExprTable* t); DataFlowResult visitExpr(DfgScope* scope, AstExprUnary* u); DataFlowResult visitExpr(DfgScope* scope, AstExprBinary* b); DataFlowResult visitExpr(DfgScope* scope, AstExprTypeAssertion* t); DataFlowResult visitExpr(DfgScope* scope, AstExprIfElse* i); DataFlowResult visitExpr(DfgScope* scope, AstExprInterpString* i); DataFlowResult visitExpr(DfgScope* scope, AstExprError* error); void visitLValue(DfgScope* scope, AstExpr* e, DefId incomingDef, bool isCompoundAssignment = false); void visitLValue(DfgScope* scope, AstExprLocal* l, DefId incomingDef, bool isCompoundAssignment); void visitLValue(DfgScope* scope, AstExprGlobal* g, DefId incomingDef, bool isCompoundAssignment); void visitLValue(DfgScope* scope, AstExprIndexName* i, DefId incomingDef); void visitLValue(DfgScope* scope, AstExprIndexExpr* i, DefId incomingDef); void visitLValue(DfgScope* scope, AstExprError* e, DefId incomingDef); void visitType(DfgScope* scope, AstType* t); void visitType(DfgScope* scope, AstTypeReference* r); void visitType(DfgScope* scope, AstTypeTable* t); void visitType(DfgScope* scope, AstTypeFunction* f); void visitType(DfgScope* scope, AstTypeTypeof* t); void visitType(DfgScope* scope, AstTypeUnion* u); void visitType(DfgScope* scope, AstTypeIntersection* i); void visitType(DfgScope* scope, AstTypeError* error); void visitTypePack(DfgScope* scope, AstTypePack* p); void visitTypePack(DfgScope* scope, AstTypePackExplicit* e); void visitTypePack(DfgScope* scope, AstTypePackVariadic* v); void visitTypePack(DfgScope* scope, AstTypePackGeneric* g); void visitTypeList(DfgScope* scope, AstTypeList l); void visitGenerics(DfgScope* scope, AstArray g); void visitGenericPacks(DfgScope* scope, AstArray g); }; } // namespace Luau