Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync to upstream/release/606 #1127

Merged
merged 19 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading