Skip to content

Commit

Permalink
Sync to upstream/release/606 (#1127)
Browse files Browse the repository at this point in the history
New Solver
* Improvements to data flow analysis

Native Code Generation
* Block limit is now per-function instead of per-module

Co-authored-by: Alexander McCord <[email protected]>
Co-authored-by: Andy Friesen <[email protected]>
Co-authored-by: Aviral Goel <[email protected]>
Co-authored-by: Vyacheslav Egorov <[email protected]>
  • Loading branch information
5 people authored Dec 8, 2023
1 parent 2ea7193 commit c26d820
Show file tree
Hide file tree
Showing 19 changed files with 546 additions and 214 deletions.
2 changes: 1 addition & 1 deletion Analysis/include/Luau/ConstraintGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ struct ConstraintGenerator
*/
ScopePtr childScope(AstNode* node, const ScopePtr& parent);

std::optional<TypeId> lookup(Scope* scope, DefId def);
std::optional<TypeId> lookup(Scope* scope, DefId def, bool prototype = true);

/**
* Adds a new constraint with no dependencies to a given scope.
Expand Down
31 changes: 24 additions & 7 deletions Analysis/include/Luau/DataFlowGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,15 @@ struct DataFlowGraph

struct DfgScope
{
enum ScopeType
{
Linear,
Loop,
Function,
};

DfgScope* parent;
bool isLoopScope;
ScopeType scopeType;

using Bindings = DenseHashMap<Symbol, const Def*>;
using Props = DenseHashMap<const Def*, std::unordered_map<std::string, const Def*>>;
Expand Down Expand Up @@ -117,7 +124,17 @@ struct DataFlowGraphBuilder

std::vector<std::unique_ptr<DfgScope>> scopes;

DfgScope* childScope(DfgScope* scope, bool isLoopScope = false);
struct FunctionCapture
{
std::vector<DefId> captureDefs;
std::vector<DefId> allVersions;
size_t versionOffset = 0;
};

DenseHashMap<Symbol, FunctionCapture> captures{Symbol{}};
void resolveCaptures();

DfgScope* childScope(DfgScope* scope, DfgScope::ScopeType scopeType = DfgScope::Linear);

void join(DfgScope* p, DfgScope* a, DfgScope* b);
void joinBindings(DfgScope::Bindings& p, const DfgScope::Bindings& a, const DfgScope::Bindings& b);
Expand Down Expand Up @@ -167,11 +184,11 @@ struct DataFlowGraphBuilder
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);
DefId visitLValue(DfgScope* scope, AstExprLocal* l, DefId incomingDef, bool isCompoundAssignment);
DefId visitLValue(DfgScope* scope, AstExprGlobal* g, DefId incomingDef, bool isCompoundAssignment);
DefId visitLValue(DfgScope* scope, AstExprIndexName* i, DefId incomingDef);
DefId visitLValue(DfgScope* scope, AstExprIndexExpr* i, DefId incomingDef);
DefId visitLValue(DfgScope* scope, AstExprError* e, DefId incomingDef);

void visitType(DfgScope* scope, AstType* t);
void visitType(DfgScope* scope, AstTypeReference* r);
Expand Down
1 change: 1 addition & 0 deletions Analysis/include/Luau/Def.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const T* get(DefId def)
}

bool containsSubscriptedDefinition(DefId def);
void collectOperands(DefId def, std::vector<DefId>* operands);

struct DefArena
{
Expand Down
44 changes: 27 additions & 17 deletions Analysis/src/ConstraintGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,30 +205,32 @@ ScopePtr ConstraintGenerator::childScope(AstNode* node, const ScopePtr& parent)
return scope;
}

std::optional<TypeId> ConstraintGenerator::lookup(Scope* scope, DefId def)
std::optional<TypeId> ConstraintGenerator::lookup(Scope* scope, DefId def, bool prototype)
{
if (get<Cell>(def))
return scope->lookup(def);
if (auto phi = get<Phi>(def))
{
if (auto found = scope->lookup(def))
return *found;
else if (!prototype)
return std::nullopt;

TypeId res = builtinTypes->neverType;

for (DefId operand : phi->operands)
{
// `scope->lookup(operand)` may return nothing because it could be a phi node of globals, but one of
// the operand of that global has never been assigned a type, and so it should be an error.
// e.g.
// ```
// if foo() then
// g = 5
// end
// -- `g` here is a phi node of the assignment to `g`, or the original revision of `g` before the branch.
// ```
TypeId ty = scope->lookup(operand).value_or(builtinTypes->errorRecoveryType());
res = simplifyUnion(builtinTypes, arena, res, ty).result;
// `scope->lookup(operand)` may return nothing because we only bind a type to that operand
// once we've seen that particular `DefId`. In this case, we need to prototype those types
// and use those at a later time.
std::optional<TypeId> ty = lookup(scope, operand, /*prototype*/false);
if (!ty)
{
ty = arena->addType(BlockedType{});
rootScope->lvalueTypes[operand] = *ty;
}

res = simplifyUnion(builtinTypes, arena, res, *ty).result;
}

scope->lvalueTypes[def] = res;
Expand Down Expand Up @@ -861,7 +863,7 @@ ControlFlow ConstraintGenerator::visit(const ScopePtr& scope, AstStatFunction* f
DenseHashSet<Constraint*> excludeList{nullptr};

DefId def = dfg->getDef(function->name);
std::optional<TypeId> existingFunctionTy = scope->lookup(def);
std::optional<TypeId> existingFunctionTy = lookup(scope.get(), def);

if (AstExprLocal* localName = function->name->as<AstExprLocal>())
{
Expand Down Expand Up @@ -1724,16 +1726,14 @@ Inference ConstraintGenerator::check(const ScopePtr& scope, AstExprGlobal* globa
/* prepopulateGlobalScope() has already added all global functions to the environment by this point, so any
* global that is not already in-scope is definitely an unknown symbol.
*/
if (auto ty = lookup(scope.get(), def))
return Inference{*ty, refinementArena.proposition(key, builtinTypes->truthyType)};
else if (auto ty = scope->lookup(global->name))
if (auto ty = lookup(scope.get(), def, /*prototype=*/false))
{
rootScope->lvalueTypes[def] = *ty;
return Inference{*ty, refinementArena.proposition(key, builtinTypes->truthyType)};
}
else
{
reportError(global->location, UnknownSymbol{global->name.value});
reportError(global->location, UnknownSymbol{global->name.value, UnknownSymbol::Binding});
return Inference{builtinTypes->errorRecoveryType()};
}
}
Expand Down Expand Up @@ -3110,6 +3110,16 @@ struct GlobalPrepopulator : AstVisitor

return true;
}

bool visit(AstType*) override
{
return true;
}

bool visit(class AstTypePack* node) override
{
return true;
}
};

void ConstraintGenerator::prepopulateGlobalScope(const ScopePtr& globalScope, AstStatBlock* program)
Expand Down
Loading

0 comments on commit c26d820

Please sign in to comment.