luau/Analysis/src/DataFlowGraph.cpp

1052 lines
32 KiB
C++
Raw Normal View History

2022-10-22 01:33:43 +08:00
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2022-12-02 18:46:05 +08:00
#include "Luau/DataFlowGraph.h"
2022-10-22 01:33:43 +08:00
2023-10-14 03:38:31 +08:00
#include "Luau/Ast.h"
2023-10-21 04:36:26 +08:00
#include "Luau/Def.h"
#include "Luau/Common.h"
2022-10-22 01:33:43 +08:00
#include "Luau/Error.h"
2023-10-14 03:38:31 +08:00
#include <algorithm>
2023-10-21 04:36:26 +08:00
#include <optional>
2023-10-14 03:38:31 +08:00
2022-10-22 01:33:43 +08:00
LUAU_FASTFLAG(DebugLuauFreezeArena)
LUAU_FASTFLAG(DebugLuauDeferredConstraintResolution)
2023-11-11 02:05:48 +08:00
LUAU_FASTFLAG(LuauLoopControlFlowAnalysis)
2022-10-22 01:33:43 +08:00
namespace Luau
{
2023-11-11 02:05:48 +08:00
bool doesCallError(const AstExprCall* call); // TypeInfer.cpp
2023-10-21 04:36:26 +08:00
const RefinementKey* RefinementKeyArena::leaf(DefId def)
2022-10-22 01:33:43 +08:00
{
2023-10-21 04:36:26 +08:00
return allocator.allocate(RefinementKey{nullptr, def, std::nullopt});
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
const RefinementKey* RefinementKeyArena::node(const RefinementKey* parent, DefId def, const std::string& propName)
2022-10-22 01:33:43 +08:00
{
2023-10-21 04:36:26 +08:00
return allocator.allocate(RefinementKey{parent, def, propName});
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
DefId DataFlowGraph::getDef(const AstExpr* expr) const
2022-10-22 01:33:43 +08:00
{
2023-10-21 04:36:26 +08:00
auto def = astDefs.find(expr);
LUAU_ASSERT(def);
return NotNull{*def};
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
std::optional<DefId> DataFlowGraph::getRValueDefForCompoundAssign(const AstExpr* expr) const
2022-10-22 01:33:43 +08:00
{
2023-11-04 03:47:28 +08:00
auto def = compoundAssignDefs.find(expr);
2023-10-21 04:36:26 +08:00
return def ? std::optional<DefId>(*def) : std::nullopt;
2023-03-03 21:45:38 +08:00
}
2022-10-22 01:33:43 +08:00
2023-10-21 04:36:26 +08:00
DefId DataFlowGraph::getDef(const AstLocal* local) const
2023-03-03 21:45:38 +08:00
{
2023-10-21 04:36:26 +08:00
auto def = localDefs.find(local);
LUAU_ASSERT(def);
return NotNull{*def};
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
DefId DataFlowGraph::getDef(const AstStatDeclareGlobal* global) const
2022-10-22 01:33:43 +08:00
{
2023-10-21 04:36:26 +08:00
auto def = declaredDefs.find(global);
LUAU_ASSERT(def);
return NotNull{*def};
}
DefId DataFlowGraph::getDef(const AstStatDeclareFunction* func) const
{
auto def = declaredDefs.find(func);
LUAU_ASSERT(def);
return NotNull{*def};
}
const RefinementKey* DataFlowGraph::getRefinementKey(const AstExpr* expr) const
{
if (auto key = astRefinementKeys.find(expr))
return *key;
return nullptr;
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
std::optional<DefId> DfgScope::lookup(Symbol symbol) const
2022-10-22 01:33:43 +08:00
{
2023-03-03 21:45:38 +08:00
for (const DfgScope* current = this; current; current = current->parent)
2022-10-22 01:33:43 +08:00
{
2023-10-21 04:36:26 +08:00
if (auto def = current->bindings.find(symbol))
return NotNull{*def};
2023-03-03 21:45:38 +08:00
}
2023-10-21 04:36:26 +08:00
return std::nullopt;
2023-03-03 21:45:38 +08:00
}
2023-10-21 04:36:26 +08:00
std::optional<DefId> DfgScope::lookup(DefId def, const std::string& key) const
2023-03-03 21:45:38 +08:00
{
for (const DfgScope* current = this; current; current = current->parent)
{
2023-11-11 02:05:48 +08:00
if (auto props = current->props.find(def))
2022-10-22 01:33:43 +08:00
{
2023-11-11 02:05:48 +08:00
if (auto it = props->find(key); it != props->end())
2023-10-21 04:36:26 +08:00
return NotNull{it->second};
2022-10-22 01:33:43 +08:00
}
}
2023-10-21 04:36:26 +08:00
return std::nullopt;
2023-03-03 21:45:38 +08:00
}
2023-11-11 02:05:48 +08:00
void DfgScope::inherit(const DfgScope* childScope)
{
for (const auto& [k, a] : childScope->bindings)
{
if (lookup(k))
bindings[k] = a;
}
for (const auto& [k1, a1] : childScope->props)
{
for (const auto& [k2, a2] : a1)
props[k1][k2] = a2;
}
}
bool DfgScope::canUpdateDefinition(Symbol symbol) const
{
for (const DfgScope* current = this; current; current = current->parent)
{
if (current->bindings.find(symbol))
return true;
else if (current->isLoopScope)
return false;
}
return true;
}
bool DfgScope::canUpdateDefinition(DefId def, const std::string& key) const
{
for (const DfgScope* current = this; current; current = current->parent)
{
if (auto props = current->props.find(def))
return true;
else if (current->isLoopScope)
return false;
}
return true;
}
2023-03-03 21:45:38 +08:00
DataFlowGraph DataFlowGraphBuilder::build(AstStatBlock* block, NotNull<InternalErrorReporter> handle)
{
LUAU_ASSERT(FFlag::DebugLuauDeferredConstraintResolution);
DataFlowGraphBuilder builder;
builder.handle = handle;
builder.moduleScope = builder.childScope(nullptr); // nullptr is the root DFG scope.
builder.visitBlockWithoutChildScope(builder.moduleScope, block);
if (FFlag::DebugLuauFreezeArena)
{
2023-10-21 04:36:26 +08:00
builder.defArena->allocator.freeze();
builder.keyArena->allocator.freeze();
2023-03-03 21:45:38 +08:00
}
return std::move(builder.graph);
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
DfgScope* DataFlowGraphBuilder::childScope(DfgScope* scope, bool isLoopScope)
2022-12-02 18:46:05 +08:00
{
2023-11-11 02:05:48 +08:00
return scopes.emplace_back(new DfgScope{scope, isLoopScope}).get();
2022-12-02 18:46:05 +08:00
}
2023-11-11 02:05:48 +08:00
void DataFlowGraphBuilder::join(DfgScope* p, DfgScope* a, DfgScope* b)
{
2023-11-18 02:15:31 +08:00
joinBindings(p->bindings, a->bindings, b->bindings);
joinProps(p->props, a->props, b->props);
}
2023-11-11 02:05:48 +08:00
2023-11-18 02:15:31 +08:00
void DataFlowGraphBuilder::joinBindings(DfgScope::Bindings& p, const DfgScope::Bindings& a, const DfgScope::Bindings& b)
{
for (const auto& [sym, def1] : a)
2023-11-11 02:05:48 +08:00
{
2023-11-18 02:15:31 +08:00
if (auto def2 = b.find(sym))
p[sym] = defArena->phi(NotNull{def1}, NotNull{*def2});
else if (auto def2 = p.find(sym))
p[sym] = defArena->phi(NotNull{def1}, NotNull{*def2});
2023-11-11 02:05:48 +08:00
}
2023-11-18 02:15:31 +08:00
for (const auto& [sym, def1] : b)
2023-11-11 02:05:48 +08:00
{
2023-11-18 02:15:31 +08:00
if (auto def2 = p.find(sym))
p[sym] = defArena->phi(NotNull{def1}, NotNull{*def2});
}
}
void DataFlowGraphBuilder::joinProps(DfgScope::Props& p, const DfgScope::Props& a, const DfgScope::Props& b)
{
auto phinodify = [this](auto& p, const auto& a, const auto& b) mutable {
for (const auto& [k, defA] : a)
{
if (auto it = b.find(k); it != b.end())
p[k] = defArena->phi(NotNull{it->second}, NotNull{defA});
else if (auto it = p.find(k); it != p.end())
p[k] = defArena->phi(NotNull{it->second}, NotNull{defA});
else
p[k] = defA;
}
for (const auto& [k, defB] : b)
{
if (auto it = a.find(k); it != a.end())
continue;
else if (auto it = p.find(k); it != p.end())
p[k] = defArena->phi(NotNull{it->second}, NotNull{defB});
else
p[k] = defB;
}
};
for (const auto& [def, a1] : a)
{
p.try_insert(def, {});
if (auto a2 = b.find(def))
phinodify(p[def], a1, *a2);
else if (auto a2 = p.find(def))
phinodify(p[def], a1, *a2);
}
for (const auto& [def, a1] : b)
{
p.try_insert(def, {});
if (a.find(def))
2023-11-11 02:05:48 +08:00
continue;
2023-11-18 02:15:31 +08:00
else if (auto a2 = p.find(def))
phinodify(p[def], a1, *a2);
}
}
DefId DataFlowGraphBuilder::lookup(DfgScope* scope, Symbol symbol)
{
if (auto found = scope->lookup(symbol))
return *found;
else
{
DefId result = defArena->freshCell();
if (symbol.local)
scope->bindings[symbol] = result;
else
moduleScope->bindings[symbol] = result;
return result;
}
}
DefId DataFlowGraphBuilder::lookup(DfgScope* scope, DefId def, const std::string& key)
{
if (auto found = scope->lookup(def, key))
return *found;
else if (auto phi = get<Phi>(def))
{
std::vector<DefId> defs;
for (DefId operand : phi->operands)
defs.push_back(lookup(scope, operand, key));
DefId result = defArena->phi(defs);
scope->props[def][key] = result;
return result;
}
else if (get<Cell>(def))
{
DefId result = defArena->freshCell();
scope->props[def][key] = result;
return result;
2023-11-11 02:05:48 +08:00
}
2023-11-18 02:15:31 +08:00
else
handle->ice("Inexhaustive lookup cases in DataFlowGraphBuilder::lookup");
2023-11-11 02:05:48 +08:00
}
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatBlock* b)
2022-10-22 01:33:43 +08:00
{
DfgScope* child = childScope(scope);
2023-11-11 02:05:48 +08:00
ControlFlow cf = visitBlockWithoutChildScope(child, b);
scope->inherit(child);
return cf;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visitBlockWithoutChildScope(DfgScope* scope, AstStatBlock* b)
2022-10-22 01:33:43 +08:00
{
2023-11-11 02:05:48 +08:00
std::optional<ControlFlow> firstControlFlow;
for (AstStat* stat : b->body)
{
ControlFlow cf = visit(scope, stat);
if (cf != ControlFlow::None && !firstControlFlow)
firstControlFlow = cf;
}
return firstControlFlow.value_or(ControlFlow::None);
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStat* s)
2022-10-22 01:33:43 +08:00
{
if (auto b = s->as<AstStatBlock>())
return visit(scope, b);
else if (auto i = s->as<AstStatIf>())
return visit(scope, i);
else if (auto w = s->as<AstStatWhile>())
return visit(scope, w);
else if (auto r = s->as<AstStatRepeat>())
return visit(scope, r);
else if (auto b = s->as<AstStatBreak>())
return visit(scope, b);
else if (auto c = s->as<AstStatContinue>())
return visit(scope, c);
else if (auto r = s->as<AstStatReturn>())
return visit(scope, r);
else if (auto e = s->as<AstStatExpr>())
return visit(scope, e);
else if (auto l = s->as<AstStatLocal>())
return visit(scope, l);
else if (auto f = s->as<AstStatFor>())
return visit(scope, f);
else if (auto f = s->as<AstStatForIn>())
return visit(scope, f);
else if (auto a = s->as<AstStatAssign>())
return visit(scope, a);
else if (auto c = s->as<AstStatCompoundAssign>())
return visit(scope, c);
else if (auto f = s->as<AstStatFunction>())
return visit(scope, f);
else if (auto l = s->as<AstStatLocalFunction>())
return visit(scope, l);
else if (auto t = s->as<AstStatTypeAlias>())
2023-03-03 21:45:38 +08:00
return visit(scope, t);
2022-10-22 01:33:43 +08:00
else if (auto d = s->as<AstStatDeclareGlobal>())
2023-03-03 21:45:38 +08:00
return visit(scope, d);
2022-10-22 01:33:43 +08:00
else if (auto d = s->as<AstStatDeclareFunction>())
2023-03-03 21:45:38 +08:00
return visit(scope, d);
2022-10-22 01:33:43 +08:00
else if (auto d = s->as<AstStatDeclareClass>())
2023-03-03 21:45:38 +08:00
return visit(scope, d);
else if (auto error = s->as<AstStatError>())
return visit(scope, error);
2022-10-22 01:33:43 +08:00
else
2023-03-03 21:45:38 +08:00
handle->ice("Unknown AstStat in DataFlowGraphBuilder::visit");
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatIf* i)
2022-10-22 01:33:43 +08:00
{
2023-03-03 21:45:38 +08:00
visitExpr(scope, i->condition);
2023-11-11 02:05:48 +08:00
DfgScope* thenScope = childScope(scope);
DfgScope* elseScope = childScope(scope);
ControlFlow thencf = visit(thenScope, i->thenbody);
ControlFlow elsecf = ControlFlow::None;
2022-10-22 01:33:43 +08:00
if (i->elsebody)
2023-11-11 02:05:48 +08:00
elsecf = visit(elseScope, i->elsebody);
if (thencf != ControlFlow::None && elsecf == ControlFlow::None)
join(scope, scope, elseScope);
else if (thencf == ControlFlow::None && elsecf != ControlFlow::None)
join(scope, thenScope, scope);
else if ((thencf | elsecf) == ControlFlow::None)
join(scope, thenScope, elseScope);
if (FFlag::LuauLoopControlFlowAnalysis && thencf == elsecf)
return thencf;
else if (matches(thencf, ControlFlow::Returns | ControlFlow::Throws) && matches(elsecf, ControlFlow::Returns | ControlFlow::Throws))
return ControlFlow::Returns;
else
return ControlFlow::None;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatWhile* w)
2022-10-22 01:33:43 +08:00
{
// TODO(controlflow): entry point has a back edge from exit point
2023-11-11 02:05:48 +08:00
DfgScope* whileScope = childScope(scope, /*isLoopScope=*/true);
2022-10-22 01:33:43 +08:00
visitExpr(whileScope, w->condition);
visit(whileScope, w->body);
2023-11-11 02:05:48 +08:00
scope->inherit(whileScope);
return ControlFlow::None;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatRepeat* r)
2022-10-22 01:33:43 +08:00
{
// TODO(controlflow): entry point has a back edge from exit point
2023-11-11 02:05:48 +08:00
DfgScope* repeatScope = childScope(scope, /*isLoopScope=*/true);
2022-10-22 01:33:43 +08:00
visitBlockWithoutChildScope(repeatScope, r->body);
visitExpr(repeatScope, r->condition);
2023-11-11 02:05:48 +08:00
scope->inherit(repeatScope);
return ControlFlow::None;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatBreak* b)
2022-10-22 01:33:43 +08:00
{
2023-11-11 02:05:48 +08:00
return ControlFlow::Breaks;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatContinue* c)
2022-10-22 01:33:43 +08:00
{
2023-11-11 02:05:48 +08:00
return ControlFlow::Continues;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatReturn* r)
2022-10-22 01:33:43 +08:00
{
for (AstExpr* e : r->list)
visitExpr(scope, e);
2023-11-11 02:05:48 +08:00
return ControlFlow::Returns;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatExpr* e)
2022-10-22 01:33:43 +08:00
{
visitExpr(scope, e->expr);
2023-11-11 02:05:48 +08:00
if (auto call = e->expr->as<AstExprCall>(); call && doesCallError(call))
return ControlFlow::Throws;
else
return ControlFlow::None;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatLocal* l)
2022-10-22 01:33:43 +08:00
{
2023-03-03 21:45:38 +08:00
// We're gonna need a `visitExprList` and `visitVariadicExpr` (function calls and `...`)
2023-10-21 04:36:26 +08:00
std::vector<DefId> defs;
defs.reserve(l->values.size);
2022-10-22 01:33:43 +08:00
for (AstExpr* e : l->values)
2023-10-21 04:36:26 +08:00
defs.push_back(visitExpr(scope, e).def);
2022-10-22 01:33:43 +08:00
2023-03-03 21:45:38 +08:00
for (size_t i = 0; i < l->vars.size; ++i)
2022-10-22 01:33:43 +08:00
{
2023-03-03 21:45:38 +08:00
AstLocal* local = l->vars.data[i];
if (local->annotation)
visitType(scope, local->annotation);
2023-10-21 04:36:26 +08:00
// We need to create a new def to intentionally avoid alias tracking, but we'd like to
// make sure that the non-aliased defs are also marked as a subscript for refinements.
bool subscripted = i < defs.size() && containsSubscriptedDefinition(defs[i]);
DefId def = defArena->freshCell(subscripted);
graph.localDefs[local] = def;
scope->bindings[local] = def;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
return ControlFlow::None;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatFor* f)
2022-10-22 01:33:43 +08:00
{
2023-11-11 02:05:48 +08:00
DfgScope* forScope = childScope(scope, /*isLoopScope=*/true);
2023-03-03 21:45:38 +08:00
visitExpr(scope, f->from);
visitExpr(scope, f->to);
if (f->step)
visitExpr(scope, f->step);
if (f->var->annotation)
visitType(forScope, f->var->annotation);
2023-10-21 04:36:26 +08:00
DefId def = defArena->freshCell();
graph.localDefs[f->var] = def;
scope->bindings[f->var] = def;
2022-10-22 01:33:43 +08:00
// TODO(controlflow): entry point has a back edge from exit point
visit(forScope, f->body);
2023-11-11 02:05:48 +08:00
scope->inherit(forScope);
return ControlFlow::None;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatForIn* f)
2022-10-22 01:33:43 +08:00
{
2023-11-11 02:05:48 +08:00
DfgScope* forScope = childScope(scope, /*isLoopScope=*/true);
2022-10-22 01:33:43 +08:00
for (AstLocal* local : f->vars)
{
2023-03-03 21:45:38 +08:00
if (local->annotation)
visitType(forScope, local->annotation);
2023-10-21 04:36:26 +08:00
DefId def = defArena->freshCell();
graph.localDefs[local] = def;
forScope->bindings[local] = def;
2022-10-22 01:33:43 +08:00
}
// TODO(controlflow): entry point has a back edge from exit point
2023-03-03 21:45:38 +08:00
// We're gonna need a `visitExprList` and `visitVariadicExpr` (function calls and `...`)
2022-10-22 01:33:43 +08:00
for (AstExpr* e : f->values)
visitExpr(forScope, e);
visit(forScope, f->body);
2023-11-11 02:05:48 +08:00
scope->inherit(forScope);
return ControlFlow::None;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatAssign* a)
2022-10-22 01:33:43 +08:00
{
2023-10-21 04:36:26 +08:00
std::vector<DefId> defs;
defs.reserve(a->values.size);
for (AstExpr* e : a->values)
defs.push_back(visitExpr(scope, e).def);
for (size_t i = 0; i < a->vars.size; ++i)
2023-10-14 03:38:31 +08:00
{
2023-10-21 04:36:26 +08:00
AstExpr* v = a->vars.data[i];
visitLValue(scope, v, i < defs.size() ? defs[i] : defArena->freshCell());
2023-10-14 03:38:31 +08:00
}
2023-11-11 02:05:48 +08:00
return ControlFlow::None;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatCompoundAssign* c)
2022-10-22 01:33:43 +08:00
{
2023-03-03 21:45:38 +08:00
// TODO: This needs revisiting because this is incorrect. The `c->var` part is both being read and written to,
// but the `c->var` only has one pointer address, so we need to come up with a way to store both.
// For now, it's not important because we don't have type states, but it is going to be important, e.g.
//
2023-10-14 03:38:31 +08:00
// local a = 5 -- a-1
// a += 5 -- a-2 = a-1 + 5
2023-03-03 21:45:38 +08:00
// We can't just visit `c->var` as a rvalue and then separately traverse `c->var` as an lvalue, since that's O(n^2).
2023-10-21 04:36:26 +08:00
DefId def = visitExpr(scope, c->value).def;
visitLValue(scope, c->var, def, /* isCompoundAssignment */ true);
2023-11-11 02:05:48 +08:00
return ControlFlow::None;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatFunction* f)
2022-10-22 01:33:43 +08:00
{
2023-03-03 21:45:38 +08:00
// In the old solver, we assumed that the name of the function is always a function in the body
// but this isn't true, e.g. the following example will print `5`, not a function address.
//
// local function f() print(f) end
// local g = f
// f = 5
// g() --> 5
//
// which is evidence that references to variables must be a phi node of all possible definitions,
// but for bug compatibility, we'll assume the same thing here.
2023-10-21 04:36:26 +08:00
DefId prototype = defArena->freshCell();
visitLValue(scope, f->name, prototype);
visitExpr(scope, f->func);
2023-11-11 02:05:48 +08:00
return ControlFlow::None;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatLocalFunction* l)
2022-10-22 01:33:43 +08:00
{
2023-10-21 04:36:26 +08:00
DefId def = defArena->freshCell();
graph.localDefs[l->name] = def;
scope->bindings[l->name] = def;
visitExpr(scope, l->func);
2023-11-11 02:05:48 +08:00
return ControlFlow::None;
2022-10-22 01:33:43 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatTypeAlias* t)
2023-03-03 21:45:38 +08:00
{
DfgScope* unreachable = childScope(scope);
visitGenerics(unreachable, t->generics);
visitGenericPacks(unreachable, t->genericPacks);
visitType(unreachable, t->type);
2023-11-11 02:05:48 +08:00
return ControlFlow::None;
2023-03-03 21:45:38 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatDeclareGlobal* d)
2023-03-03 21:45:38 +08:00
{
2023-10-21 04:36:26 +08:00
DefId def = defArena->freshCell();
graph.declaredDefs[d] = def;
scope->bindings[d->name] = def;
2023-03-03 21:45:38 +08:00
visitType(scope, d->type);
2023-11-11 02:05:48 +08:00
return ControlFlow::None;
2023-03-03 21:45:38 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatDeclareFunction* d)
2023-03-03 21:45:38 +08:00
{
2023-10-21 04:36:26 +08:00
DefId def = defArena->freshCell();
graph.declaredDefs[d] = def;
scope->bindings[d->name] = def;
2023-03-03 21:45:38 +08:00
DfgScope* unreachable = childScope(scope);
visitGenerics(unreachable, d->generics);
visitGenericPacks(unreachable, d->genericPacks);
visitTypeList(unreachable, d->params);
visitTypeList(unreachable, d->retTypes);
2023-11-11 02:05:48 +08:00
return ControlFlow::None;
2023-03-03 21:45:38 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatDeclareClass* d)
2023-03-03 21:45:38 +08:00
{
// This declaration does not "introduce" any bindings in value namespace,
// so there's no symbolic value to begin with. We'll traverse the properties
// because their type annotations may depend on something in the value namespace.
DfgScope* unreachable = childScope(scope);
for (AstDeclaredClassProp prop : d->props)
visitType(unreachable, prop.ty);
2023-11-11 02:05:48 +08:00
return ControlFlow::None;
2023-03-03 21:45:38 +08:00
}
2023-11-11 02:05:48 +08:00
ControlFlow DataFlowGraphBuilder::visit(DfgScope* scope, AstStatError* error)
2023-03-03 21:45:38 +08:00
{
DfgScope* unreachable = childScope(scope);
for (AstStat* s : error->statements)
visit(unreachable, s);
for (AstExpr* e : error->expressions)
visitExpr(unreachable, e);
2023-11-11 02:05:48 +08:00
return ControlFlow::None;
2023-03-03 21:45:38 +08:00
}
2023-10-21 04:36:26 +08:00
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExpr* e)
{
2023-11-11 02:05:48 +08:00
// Some subexpressions could be visited two times. If we've already seen it, just extract it.
if (auto def = graph.astDefs.find(e))
{
auto key = graph.astRefinementKeys.find(e);
return {NotNull{*def}, key ? *key : nullptr};
}
2023-10-21 04:36:26 +08:00
auto go = [&]() -> DataFlowResult {
if (auto g = e->as<AstExprGroup>())
return visitExpr(scope, g);
else if (auto c = e->as<AstExprConstantNil>())
return {defArena->freshCell(), nullptr}; // ok
else if (auto c = e->as<AstExprConstantBool>())
return {defArena->freshCell(), nullptr}; // ok
else if (auto c = e->as<AstExprConstantNumber>())
return {defArena->freshCell(), nullptr}; // ok
else if (auto c = e->as<AstExprConstantString>())
return {defArena->freshCell(), nullptr}; // ok
else if (auto l = e->as<AstExprLocal>())
return visitExpr(scope, l);
else if (auto g = e->as<AstExprGlobal>())
return visitExpr(scope, g);
else if (auto v = e->as<AstExprVarargs>())
return {defArena->freshCell(), nullptr}; // ok
else if (auto c = e->as<AstExprCall>())
return visitExpr(scope, c);
else if (auto i = e->as<AstExprIndexName>())
return visitExpr(scope, i);
else if (auto i = e->as<AstExprIndexExpr>())
return visitExpr(scope, i);
else if (auto f = e->as<AstExprFunction>())
return visitExpr(scope, f);
else if (auto t = e->as<AstExprTable>())
return visitExpr(scope, t);
else if (auto u = e->as<AstExprUnary>())
return visitExpr(scope, u);
else if (auto b = e->as<AstExprBinary>())
return visitExpr(scope, b);
else if (auto t = e->as<AstExprTypeAssertion>())
return visitExpr(scope, t);
else if (auto i = e->as<AstExprIfElse>())
return visitExpr(scope, i);
else if (auto i = e->as<AstExprInterpString>())
return visitExpr(scope, i);
else if (auto error = e->as<AstExprError>())
return visitExpr(scope, error);
else
handle->ice("Unknown AstExpr in DataFlowGraphBuilder::visitExpr");
};
auto [def, key] = go();
graph.astDefs[e] = def;
if (key)
graph.astRefinementKeys[e] = key;
return {def, key};
}
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprGroup* group)
{
return visitExpr(scope, group->expr);
}
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprLocal* l)
{
2023-11-18 02:15:31 +08:00
// DfgScope::lookup is intentional here: we want to be able to ice.
2023-10-21 04:36:26 +08:00
if (auto def = scope->lookup(l->local))
{
const RefinementKey* key = keyArena->leaf(*def);
return {*def, key};
}
2023-03-03 21:45:38 +08:00
2023-10-21 04:36:26 +08:00
handle->ice("DFG: AstExprLocal came before its declaration?");
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprGlobal* g)
2022-10-22 01:33:43 +08:00
{
2023-11-18 02:15:31 +08:00
DefId def = lookup(scope, g->name);
2023-10-21 04:36:26 +08:00
return {def, keyArena->leaf(def)};
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprCall* c)
2022-10-22 01:33:43 +08:00
{
visitExpr(scope, c->func);
for (AstExpr* arg : c->args)
visitExpr(scope, arg);
2023-10-21 04:36:26 +08:00
return {defArena->freshCell(), nullptr};
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprIndexName* i)
2022-10-22 01:33:43 +08:00
{
2023-10-21 04:36:26 +08:00
auto [parentDef, parentKey] = visitExpr(scope, i->expr);
2022-10-22 01:33:43 +08:00
2023-10-21 04:36:26 +08:00
std::string index = i->index.value;
2023-11-18 02:15:31 +08:00
DefId def = lookup(scope, parentDef, index);
return {def, keyArena->node(parentKey, def, index)};
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprIndexExpr* i)
2022-10-22 01:33:43 +08:00
{
2023-10-21 04:36:26 +08:00
auto [parentDef, parentKey] = visitExpr(scope, i->expr);
visitExpr(scope, i->index);
2022-10-22 01:33:43 +08:00
2023-03-03 21:45:38 +08:00
if (auto string = i->index->as<AstExprConstantString>())
2022-10-22 01:33:43 +08:00
{
2023-10-21 04:36:26 +08:00
std::string index{string->value.data, string->value.size};
2023-11-18 02:15:31 +08:00
DefId def = lookup(scope, parentDef, index);
return {def, keyArena->node(parentKey, def, index)};
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
return {defArena->freshCell(/* subscripted= */true), nullptr};
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprFunction* f)
2022-10-22 01:33:43 +08:00
{
2023-03-03 21:45:38 +08:00
DfgScope* signatureScope = childScope(scope);
2022-10-22 01:33:43 +08:00
if (AstLocal* self = f->self)
{
2023-03-03 21:45:38 +08:00
// There's no syntax for `self` to have an annotation if using `function t:m()`
LUAU_ASSERT(!self->annotation);
2023-10-21 04:36:26 +08:00
DefId def = defArena->freshCell();
graph.localDefs[self] = def;
signatureScope->bindings[self] = def;
2022-10-22 01:33:43 +08:00
}
for (AstLocal* param : f->args)
{
2023-03-03 21:45:38 +08:00
if (param->annotation)
visitType(signatureScope, param->annotation);
2023-10-21 04:36:26 +08:00
DefId def = defArena->freshCell();
graph.localDefs[param] = def;
signatureScope->bindings[param] = def;
2022-10-22 01:33:43 +08:00
}
2023-03-03 21:45:38 +08:00
if (f->varargAnnotation)
visitTypePack(scope, f->varargAnnotation);
2022-10-22 01:33:43 +08:00
2023-03-03 21:45:38 +08:00
if (f->returnAnnotation)
visitTypeList(signatureScope, *f->returnAnnotation);
// TODO: function body can be re-entrant, as in mutations that occurs at the end of the function can also be
// visible to the beginning of the function, so statically speaking, the body of the function has an exit point
// that points back to itself, e.g.
//
// local function f() print(f) f = 5 end
// local g = f
// g() --> function: address
// g() --> 5
visit(signatureScope, f->body);
2023-10-21 04:36:26 +08:00
return {defArena->freshCell(), nullptr};
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprTable* t)
2022-10-22 01:33:43 +08:00
{
2023-02-17 22:53:37 +08:00
for (AstExprTable::Item item : t->items)
{
if (item.key)
visitExpr(scope, item.key);
visitExpr(scope, item.value);
}
2023-10-21 04:36:26 +08:00
return {defArena->freshCell(), nullptr};
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprUnary* u)
2022-10-22 01:33:43 +08:00
{
visitExpr(scope, u->expr);
2023-10-21 04:36:26 +08:00
return {defArena->freshCell(), nullptr};
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprBinary* b)
2022-10-22 01:33:43 +08:00
{
visitExpr(scope, b->left);
visitExpr(scope, b->right);
2023-10-21 04:36:26 +08:00
return {defArena->freshCell(), nullptr};
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprTypeAssertion* t)
2022-10-22 01:33:43 +08:00
{
2023-10-21 04:36:26 +08:00
auto [def, key] = visitExpr(scope, t->expr);
2023-03-03 21:45:38 +08:00
visitType(scope, t->annotation);
2023-10-21 04:36:26 +08:00
return {def, key};
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprIfElse* i)
2022-10-22 01:33:43 +08:00
{
2023-03-03 21:45:38 +08:00
visitExpr(scope, i->condition);
visitExpr(scope, i->trueExpr);
2022-10-22 01:33:43 +08:00
visitExpr(scope, i->falseExpr);
2023-10-21 04:36:26 +08:00
return {defArena->freshCell(), nullptr};
2022-10-22 01:33:43 +08:00
}
2023-10-21 04:36:26 +08:00
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprInterpString* i)
2022-10-22 01:33:43 +08:00
{
for (AstExpr* e : i->expressions)
visitExpr(scope, e);
2023-03-03 21:45:38 +08:00
2023-10-21 04:36:26 +08:00
return {defArena->freshCell(), nullptr};
2023-03-03 21:45:38 +08:00
}
2023-10-21 04:36:26 +08:00
DataFlowResult DataFlowGraphBuilder::visitExpr(DfgScope* scope, AstExprError* error)
2023-03-03 21:45:38 +08:00
{
DfgScope* unreachable = childScope(scope);
for (AstExpr* e : error->expressions)
visitExpr(unreachable, e);
2023-10-21 04:36:26 +08:00
return {defArena->freshCell(), nullptr};
2023-03-03 21:45:38 +08:00
}
2023-10-21 04:36:26 +08:00
void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExpr* e, DefId incomingDef, bool isCompoundAssignment)
2023-03-03 21:45:38 +08:00
{
if (auto l = e->as<AstExprLocal>())
2023-10-21 04:36:26 +08:00
return visitLValue(scope, l, incomingDef, isCompoundAssignment);
2023-03-03 21:45:38 +08:00
else if (auto g = e->as<AstExprGlobal>())
2023-10-21 04:36:26 +08:00
return visitLValue(scope, g, incomingDef, isCompoundAssignment);
2023-03-03 21:45:38 +08:00
else if (auto i = e->as<AstExprIndexName>())
2023-10-21 04:36:26 +08:00
return visitLValue(scope, i, incomingDef);
2023-03-03 21:45:38 +08:00
else if (auto i = e->as<AstExprIndexExpr>())
2023-10-21 04:36:26 +08:00
return visitLValue(scope, i, incomingDef);
2023-03-03 21:45:38 +08:00
else if (auto error = e->as<AstExprError>())
2023-10-21 04:36:26 +08:00
return visitLValue(scope, error, incomingDef);
2023-03-03 21:45:38 +08:00
else
handle->ice("Unknown AstExpr in DataFlowGraphBuilder::visitLValue");
}
2023-10-21 04:36:26 +08:00
void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprLocal* l, DefId incomingDef, bool isCompoundAssignment)
2023-03-03 21:45:38 +08:00
{
2023-11-04 03:47:28 +08:00
// We need to keep the previous def around for a compound assignment.
2023-10-21 04:36:26 +08:00
if (isCompoundAssignment)
{
if (auto def = scope->lookup(l->local))
2023-11-04 03:47:28 +08:00
graph.compoundAssignDefs[l] = *def;
2023-10-21 04:36:26 +08:00
}
// In order to avoid alias tracking, we need to clip the reference to the parent def.
2023-11-11 02:05:48 +08:00
if (scope->canUpdateDefinition(l->local))
{
DefId updated = defArena->freshCell(containsSubscriptedDefinition(incomingDef));
graph.astDefs[l] = updated;
scope->bindings[l->local] = updated;
}
else
visitExpr(scope, static_cast<AstExpr*>(l));
2023-03-03 21:45:38 +08:00
}
2023-10-21 04:36:26 +08:00
void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprGlobal* g, DefId incomingDef, bool isCompoundAssignment)
2023-03-03 21:45:38 +08:00
{
2023-11-04 03:47:28 +08:00
// We need to keep the previous def around for a compound assignment.
2023-10-21 04:36:26 +08:00
if (isCompoundAssignment)
{
2023-11-18 02:15:31 +08:00
DefId def = lookup(scope, g->name);
graph.compoundAssignDefs[g] = def;
2023-10-21 04:36:26 +08:00
}
// In order to avoid alias tracking, we need to clip the reference to the parent def.
2023-11-11 02:05:48 +08:00
if (scope->canUpdateDefinition(g->name))
{
DefId updated = defArena->freshCell(containsSubscriptedDefinition(incomingDef));
graph.astDefs[g] = updated;
scope->bindings[g->name] = updated;
}
else
visitExpr(scope, static_cast<AstExpr*>(g));
2023-03-03 21:45:38 +08:00
}
2023-10-21 04:36:26 +08:00
void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprIndexName* i, DefId incomingDef)
2023-03-03 21:45:38 +08:00
{
2023-10-21 04:36:26 +08:00
DefId parentDef = visitExpr(scope, i->expr).def;
2023-03-03 21:45:38 +08:00
2023-11-11 02:05:48 +08:00
if (scope->canUpdateDefinition(parentDef, i->index.value))
{
DefId updated = defArena->freshCell(containsSubscriptedDefinition(incomingDef));
graph.astDefs[i] = updated;
scope->props[parentDef][i->index.value] = updated;
}
else
visitExpr(scope, static_cast<AstExpr*>(i));
2023-03-03 21:45:38 +08:00
}
2023-10-21 04:36:26 +08:00
void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprIndexExpr* i, DefId incomingDef)
2023-03-03 21:45:38 +08:00
{
2023-10-21 04:36:26 +08:00
DefId parentDef = visitExpr(scope, i->expr).def;
2023-03-03 21:45:38 +08:00
visitExpr(scope, i->index);
if (auto string = i->index->as<AstExprConstantString>())
{
2023-11-11 02:05:48 +08:00
if (scope->canUpdateDefinition(parentDef, string->value.data))
{
DefId updated = defArena->freshCell(containsSubscriptedDefinition(incomingDef));
graph.astDefs[i] = updated;
scope->props[parentDef][string->value.data] = updated;
}
else
visitExpr(scope, static_cast<AstExpr*>(i));
2023-03-03 21:45:38 +08:00
}
2023-10-21 04:36:26 +08:00
graph.astDefs[i] = defArena->freshCell();
2023-03-03 21:45:38 +08:00
}
2023-10-21 04:36:26 +08:00
void DataFlowGraphBuilder::visitLValue(DfgScope* scope, AstExprError* error, DefId incomingDef)
2023-10-14 03:38:31 +08:00
{
2023-10-21 04:36:26 +08:00
DefId def = visitExpr(scope, error).def;
graph.astDefs[error] = def;
2023-10-14 03:38:31 +08:00
}
2023-03-03 21:45:38 +08:00
void DataFlowGraphBuilder::visitType(DfgScope* scope, AstType* t)
{
if (auto r = t->as<AstTypeReference>())
return visitType(scope, r);
else if (auto table = t->as<AstTypeTable>())
return visitType(scope, table);
else if (auto f = t->as<AstTypeFunction>())
return visitType(scope, f);
else if (auto tyof = t->as<AstTypeTypeof>())
return visitType(scope, tyof);
else if (auto u = t->as<AstTypeUnion>())
return visitType(scope, u);
else if (auto i = t->as<AstTypeIntersection>())
return visitType(scope, i);
else if (auto e = t->as<AstTypeError>())
return visitType(scope, e);
else if (auto s = t->as<AstTypeSingletonBool>())
return; // ok
else if (auto s = t->as<AstTypeSingletonString>())
return; // ok
else
handle->ice("Unknown AstType in DataFlowGraphBuilder::visitType");
}
void DataFlowGraphBuilder::visitType(DfgScope* scope, AstTypeReference* r)
{
for (AstTypeOrPack param : r->parameters)
{
if (param.type)
visitType(scope, param.type);
else
visitTypePack(scope, param.typePack);
}
}
void DataFlowGraphBuilder::visitType(DfgScope* scope, AstTypeTable* t)
{
for (AstTableProp p : t->props)
visitType(scope, p.type);
if (t->indexer)
{
visitType(scope, t->indexer->indexType);
visitType(scope, t->indexer->resultType);
}
}
void DataFlowGraphBuilder::visitType(DfgScope* scope, AstTypeFunction* f)
{
visitGenerics(scope, f->generics);
visitGenericPacks(scope, f->genericPacks);
visitTypeList(scope, f->argTypes);
visitTypeList(scope, f->returnTypes);
}
void DataFlowGraphBuilder::visitType(DfgScope* scope, AstTypeTypeof* t)
{
visitExpr(scope, t->expr);
}
void DataFlowGraphBuilder::visitType(DfgScope* scope, AstTypeUnion* u)
{
for (AstType* t : u->types)
visitType(scope, t);
}
void DataFlowGraphBuilder::visitType(DfgScope* scope, AstTypeIntersection* i)
{
for (AstType* t : i->types)
visitType(scope, t);
}
void DataFlowGraphBuilder::visitType(DfgScope* scope, AstTypeError* error)
{
for (AstType* t : error->types)
visitType(scope, t);
}
void DataFlowGraphBuilder::visitTypePack(DfgScope* scope, AstTypePack* p)
{
if (auto e = p->as<AstTypePackExplicit>())
return visitTypePack(scope, e);
else if (auto v = p->as<AstTypePackVariadic>())
return visitTypePack(scope, v);
else if (auto g = p->as<AstTypePackGeneric>())
return; // ok
else
handle->ice("Unknown AstTypePack in DataFlowGraphBuilder::visitTypePack");
}
void DataFlowGraphBuilder::visitTypePack(DfgScope* scope, AstTypePackExplicit* e)
{
visitTypeList(scope, e->typeList);
}
void DataFlowGraphBuilder::visitTypePack(DfgScope* scope, AstTypePackVariadic* v)
{
visitType(scope, v->variadicType);
}
void DataFlowGraphBuilder::visitTypeList(DfgScope* scope, AstTypeList l)
{
for (AstType* t : l.types)
visitType(scope, t);
if (l.tailType)
visitTypePack(scope, l.tailType);
}
void DataFlowGraphBuilder::visitGenerics(DfgScope* scope, AstArray<AstGenericType> g)
{
for (AstGenericType generic : g)
{
if (generic.defaultValue)
visitType(scope, generic.defaultValue);
}
}
void DataFlowGraphBuilder::visitGenericPacks(DfgScope* scope, AstArray<AstGenericTypePack> g)
{
for (AstGenericTypePack generic : g)
{
if (generic.defaultValue)
visitTypePack(scope, generic.defaultValue);
}
2022-10-22 01:33:43 +08:00
}
} // namespace Luau