GH-725: fix logic for finding a lambda's usage of outer IDs

This commit is contained in:
Jon Siwek 2020-03-26 17:05:59 -07:00
parent f032885085
commit 1ca11f11c7
6 changed files with 43 additions and 22 deletions

View file

@ -419,32 +419,25 @@ void begin_func(ID* id, const char* module_name, function_flavor flavor,
class OuterIDBindingFinder : public TraversalCallback {
public:
OuterIDBindingFinder(Scope* s)
: scope(s) { }
{
scopes.emplace_back(s);
}
virtual TraversalCode PreExpr(const Expr*);
virtual TraversalCode PostExpr(const Expr*);
Scope* scope;
std::vector<Scope*> scopes;
vector<const NameExpr*> outer_id_references;
int lambda_depth = 0;
// Note: think we really ought to toggle this to false to prevent
// considering locals within inner-lambdas as "outer", but other logic
// for "selective cloning" and locating IDs in the closure chain may
// depend on current behavior and also needs to be changed.
bool search_inner_lambdas = true;
};
TraversalCode OuterIDBindingFinder::PreExpr(const Expr* expr)
{
if ( expr->Tag() == EXPR_LAMBDA )
++lambda_depth;
if ( lambda_depth > 0 && ! search_inner_lambdas )
// Don't inspect the bodies of inner lambdas as they will have their
// own traversal to find outer IDs and we don't want to detect
// references to local IDs inside and accidentally treat them as
// "outer" since they can't be found in current scope.
{
auto le = static_cast<const LambdaExpr*>(expr);
scopes.emplace_back(le->GetScope());
return TC_CONTINUE;
}
if ( expr->Tag() != EXPR_NAME )
return TC_CONTINUE;
@ -454,8 +447,11 @@ TraversalCode OuterIDBindingFinder::PreExpr(const Expr* expr)
if ( e->Id()->IsGlobal() )
return TC_CONTINUE;
if ( scope->Lookup(e->Id()->Name()) )
return TC_CONTINUE;
for ( const auto& scope : scopes )
if ( scope->Lookup(e->Id()->Name()) )
// Shadowing is not allowed, so if it's found at inner scope, it's
// not something we have to worry about also being at outer scope.
return TC_CONTINUE;
outer_id_references.push_back(e);
return TC_CONTINUE;
@ -464,10 +460,7 @@ TraversalCode OuterIDBindingFinder::PreExpr(const Expr* expr)
TraversalCode OuterIDBindingFinder::PostExpr(const Expr* expr)
{
if ( expr->Tag() == EXPR_LAMBDA )
{
--lambda_depth;
assert(lambda_depth >= 0);
}
scopes.pop_back();
return TC_CONTINUE;
}