-
Notifications
You must be signed in to change notification settings - Fork 391
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Support `["prop"]` syntax on class definitions in definition files. (#704) * Improve type checking performance for complex overloaded functions * Fix rare cases of incorrect stack traces for out of memory errors at runtime
- Loading branch information
1 parent
12ee140
commit 5432486
Showing
104 changed files
with
4,200 additions
and
2,256 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
// 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 <unordered_map> | ||
|
||
namespace Luau | ||
{ | ||
|
||
struct DataFlowGraph | ||
{ | ||
DataFlowGraph(DataFlowGraph&&) = default; | ||
DataFlowGraph& operator=(DataFlowGraph&&) = default; | ||
|
||
// TODO: AstExprLocal, AstExprGlobal, and AstLocal* are guaranteed never to return nullopt. | ||
// We leave them to return an optional as we build it out, but the end state is for them to return a non-optional DefId. | ||
std::optional<DefId> getDef(const AstExpr* expr) const; | ||
std::optional<DefId> getDef(const AstLocal* local) const; | ||
|
||
/// Retrieve the Def that corresponds to the given Symbol. | ||
/// | ||
/// We do not perform dataflow analysis on globals, so this function always | ||
/// yields nullopt when passed a global Symbol. | ||
std::optional<DefId> getDef(const Symbol& symbol) const; | ||
|
||
private: | ||
DataFlowGraph() = default; | ||
|
||
DataFlowGraph(const DataFlowGraph&) = delete; | ||
DataFlowGraph& operator=(const DataFlowGraph&) = delete; | ||
|
||
DefArena arena; | ||
DenseHashMap<const AstExpr*, const Def*> astDefs{nullptr}; | ||
DenseHashMap<const AstLocal*, const Def*> localDefs{nullptr}; | ||
|
||
friend struct DataFlowGraphBuilder; | ||
}; | ||
|
||
struct DfgScope | ||
{ | ||
DfgScope* parent; | ||
DenseHashMap<Symbol, const Def*> bindings{Symbol{}}; | ||
}; | ||
|
||
struct ExpressionFlowGraph | ||
{ | ||
std::optional<DefId> def; | ||
}; | ||
|
||
// Currently unsound. We do not presently track the control flow of the program. | ||
// Additionally, we do not presently track assignments. | ||
struct DataFlowGraphBuilder | ||
{ | ||
static DataFlowGraph build(AstStatBlock* root, NotNull<struct InternalErrorReporter> handle); | ||
|
||
private: | ||
DataFlowGraphBuilder() = default; | ||
|
||
DataFlowGraphBuilder(const DataFlowGraphBuilder&) = delete; | ||
DataFlowGraphBuilder& operator=(const DataFlowGraphBuilder&) = delete; | ||
|
||
DataFlowGraph graph; | ||
NotNull<DefArena> arena{&graph.arena}; | ||
struct InternalErrorReporter* handle; | ||
std::vector<std::unique_ptr<DfgScope>> scopes; | ||
|
||
DfgScope* childScope(DfgScope* scope); | ||
|
||
std::optional<DefId> use(DfgScope* scope, Symbol symbol, AstExpr* e); | ||
|
||
void visit(DfgScope* scope, AstStatBlock* b); | ||
void visitBlockWithoutChildScope(DfgScope* scope, AstStatBlock* b); | ||
|
||
// TODO: visit type aliases | ||
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); | ||
|
||
ExpressionFlowGraph visitExpr(DfgScope* scope, AstExpr* e); | ||
ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprLocal* l); | ||
ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprGlobal* g); | ||
ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprCall* c); | ||
ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprIndexName* i); | ||
ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprIndexExpr* i); | ||
ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprFunction* f); | ||
ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprTable* t); | ||
ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprUnary* u); | ||
ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprBinary* b); | ||
ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprTypeAssertion* t); | ||
ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprIfElse* i); | ||
ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprInterpString* i); | ||
|
||
// TODO: visitLValue | ||
// TODO: visitTypes (because of typeof which has access to values namespace, needs unreachable scope) | ||
// TODO: visitTypePacks (because of typeof which has access to values namespace, needs unreachable scope) | ||
}; | ||
|
||
} // namespace Luau |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details | ||
#pragma once | ||
|
||
#include "Luau/NotNull.h" | ||
#include "Luau/TypedAllocator.h" | ||
#include "Luau/Variant.h" | ||
|
||
namespace Luau | ||
{ | ||
|
||
using Def = Variant<struct Undefined, struct Phi>; | ||
|
||
/** | ||
* We statically approximate a value at runtime using a symbolic value, which we call a Def. | ||
* | ||
* DataFlowGraphBuilder will allocate these defs as a stand-in for some Luau values, and bind them to places that | ||
* can hold a Luau value, and then observes how those defs will commute as it statically evaluate the program. | ||
* | ||
* It must also be noted that defs are a cyclic graph, so it is not safe to recursively traverse into it expecting it to terminate. | ||
*/ | ||
using DefId = NotNull<const Def>; | ||
|
||
/** | ||
* A "single-object" value. | ||
* | ||
* Leaky implementation note: sometimes "multiple-object" values, but none of which were interesting enough to warrant creating a phi node instead. | ||
* That can happen because there's no point in creating a phi node that points to either resultant in `if math.random() > 0.5 then 5 else "hello"`. | ||
* This might become of utmost importance if we wanted to do some backward reasoning, e.g. if `5` is taken, then `cond` must be `truthy`. | ||
*/ | ||
struct Undefined | ||
{ | ||
}; | ||
|
||
/** | ||
* A phi node is a union of defs. | ||
* | ||
* We need this because we're statically evaluating a program, and sometimes a place may be assigned with | ||
* different defs, and when that happens, we need a special data type that merges in all the defs | ||
* that will flow into that specific place. For example, consider this simple program: | ||
* | ||
* ``` | ||
* x-1 | ||
* if cond() then | ||
* x-2 = 5 | ||
* else | ||
* x-3 = "hello" | ||
* end | ||
* x-4 : {x-2, x-3} | ||
* ``` | ||
* | ||
* At x-4, we know for a fact statically that either `5` or `"hello"` can flow into the variable `x` after the branch, but | ||
* we cannot make any definitive decisions about which one, so we just take in both. | ||
*/ | ||
struct Phi | ||
{ | ||
std::vector<DefId> operands; | ||
}; | ||
|
||
template<typename T> | ||
T* getMutable(DefId def) | ||
{ | ||
return get_if<T>(def.get()); | ||
} | ||
|
||
template<typename T> | ||
const T* get(DefId def) | ||
{ | ||
return getMutable<T>(def); | ||
} | ||
|
||
struct DefArena | ||
{ | ||
TypedAllocator<Def> allocator; | ||
|
||
DefId freshDef(); | ||
}; | ||
|
||
} // namespace Luau |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details | ||
#pragma once | ||
|
||
#include "Luau/Ast.h" | ||
|
||
#include <unordered_map> | ||
|
||
namespace Luau | ||
{ | ||
|
||
static const std::unordered_map<AstExprBinary::Op, const char*> kBinaryOpMetamethods{ | ||
{AstExprBinary::Op::CompareEq, "__eq"}, | ||
{AstExprBinary::Op::CompareNe, "__eq"}, | ||
{AstExprBinary::Op::CompareGe, "__lt"}, | ||
{AstExprBinary::Op::CompareGt, "__le"}, | ||
{AstExprBinary::Op::CompareLe, "__le"}, | ||
{AstExprBinary::Op::CompareLt, "__lt"}, | ||
{AstExprBinary::Op::Add, "__add"}, | ||
{AstExprBinary::Op::Sub, "__sub"}, | ||
{AstExprBinary::Op::Mul, "__mul"}, | ||
{AstExprBinary::Op::Div, "__div"}, | ||
{AstExprBinary::Op::Pow, "__pow"}, | ||
{AstExprBinary::Op::Mod, "__mod"}, | ||
{AstExprBinary::Op::Concat, "__concat"}, | ||
}; | ||
|
||
static const std::unordered_map<AstExprUnary::Op, const char*> kUnaryOpMetamethods{ | ||
{AstExprUnary::Op::Minus, "__unm"}, | ||
{AstExprUnary::Op::Len, "__len"}, | ||
}; | ||
|
||
} // namespace Luau |
Oops, something went wrong.