Skip to content

Commit

Permalink
Sequre scoping fix (#121)
Browse files Browse the repository at this point in the history
* Fix ABI incompatibilities

* Fix codon-jit on macOS

* Fix scoping bugs
  • Loading branch information
inumanag committed Dec 18, 2022
1 parent ef4ff45 commit a2158ad
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 4 deletions.
7 changes: 7 additions & 0 deletions codon/parser/visitors/simplify/assign.cpp
Expand Up @@ -18,6 +18,8 @@ namespace codon::ast {
void SimplifyVisitor::visit(AssignExpr *expr) {
seqassert(expr->var->getId(), "only simple assignment expression are supported");
StmtPtr s = N<AssignStmt>(clone(expr->var), expr->expr);
auto avoidDomination = false; // walruses always leak
std::swap(avoidDomination, ctx->avoidDomination);
if (ctx->isConditionalExpr) {
// Make sure to transform both suite _AND_ the expression in the same scope
ctx->enterConditionalBlock();
Expand All @@ -33,6 +35,7 @@ void SimplifyVisitor::visit(AssignExpr *expr) {
s = transform(s);
transform(expr->var);
}
std::swap(avoidDomination, ctx->avoidDomination);
resultExpr = N<StmtExpr>(std::vector<StmtPtr>{s}, expr->var);
}

Expand Down Expand Up @@ -155,7 +158,11 @@ StmtPtr SimplifyVisitor::transformAssignment(ExprPtr lhs, ExprPtr rhs, ExprPtr t
val = ctx->addVar(e->value, canonical, lhs->getSrcInfo());
if (auto st = getStaticGeneric(type.get()))
val->staticType = st;
if (ctx->avoidDomination)
val->avoidDomination = true;
}
// Clean up seen tags if shadowing a name
ctx->seenGlobalIdentifiers[ctx->getBaseName()].erase(e->value);

// Register all toplevel variables as global in JIT mode
bool isGlobal = (ctx->cache->isJit && val->isGlobal() && !val->isGeneric()) ||
Expand Down
9 changes: 8 additions & 1 deletion codon/parser/visitors/simplify/collections.cpp
Expand Up @@ -65,6 +65,8 @@ void SimplifyVisitor::visit(GeneratorExpr *expr) {
}

SuiteStmt *prev = nullptr;
auto avoidDomination = true;
std::swap(avoidDomination, ctx->avoidDomination);
auto suite = transformGeneratorBody(loops, prev);
ExprPtr var = N<IdExpr>(ctx->cache->getTemporaryVar("gen"));
if (expr->kind == GeneratorExpr::ListGenerator) {
Expand Down Expand Up @@ -94,6 +96,7 @@ void SimplifyVisitor::visit(GeneratorExpr *expr) {
stmts.push_back(suite);
resultExpr = N<CallExpr>(N<DotExpr>(N<CallExpr>(makeAnonFn(stmts)), "__iter__"));
}
std::swap(avoidDomination, ctx->avoidDomination);
}

/// Transform a dictionary comprehension to the corresponding statement expression.
Expand All @@ -102,6 +105,8 @@ void SimplifyVisitor::visit(GeneratorExpr *expr) {
/// for i in j: if a: gen.__setitem__(i+a, j+1)```
void SimplifyVisitor::visit(DictGeneratorExpr *expr) {
SuiteStmt *prev = nullptr;
auto avoidDomination = true;
std::swap(avoidDomination, ctx->avoidDomination);
auto suite = transformGeneratorBody(expr->loops, prev);

std::vector<StmtPtr> stmts;
Expand All @@ -111,6 +116,7 @@ void SimplifyVisitor::visit(DictGeneratorExpr *expr) {
clone(expr->key), clone(expr->expr))));
stmts.push_back(transform(suite));
resultExpr = N<StmtExpr>(stmts, transform(var));
std::swap(avoidDomination, ctx->avoidDomination);
}

/// Transforms a list of @c GeneratorBody loops to the corresponding set of for loops.
Expand All @@ -127,7 +133,8 @@ StmtPtr SimplifyVisitor::transformGeneratorBody(const std::vector<GeneratorBody>
newSuite = N<SuiteStmt>();
auto nextPrev = dynamic_cast<SuiteStmt *>(newSuite.get());

prev->stmts.push_back(N<ForStmt>(l.vars->clone(), l.gen->clone(), newSuite));
auto forStmt = N<ForStmt>(l.vars->clone(), l.gen->clone(), newSuite);
prev->stmts.push_back(forStmt);
prev = nextPrev;
for (auto &cond : l.conds) {
newSuite = N<SuiteStmt>();
Expand Down
2 changes: 2 additions & 0 deletions codon/parser/visitors/simplify/ctx.cpp
Expand Up @@ -171,6 +171,8 @@ SimplifyContext::Item SimplifyContext::findDominatingBinding(const std::string &
for (auto i = it->second.begin(); i != it->second.end(); i++) {
if (i == lastGood)
break;
if (!(*i)->canDominate())
continue;
// These bindings (and their canonical identifiers) will be replaced by the
// dominating binding during the type checking pass.
cache->replacements[(*i)->canonicalName] = {canonicalName, hasUsed};
Expand Down
7 changes: 7 additions & 0 deletions codon/parser/visitors/simplify/ctx.h
Expand Up @@ -44,6 +44,9 @@ struct SimplifyItem : public SrcObject {
bool generic = false;
/// Set if an identifier is a static variable.
char staticType = 0;
/// Set if an identifier should not be dominated
/// (e.g., a loop variable in a comprehension).
bool avoidDomination = false;

public:
SimplifyItem(Kind kind, std::string baseName, std::string canonicalName,
Expand All @@ -66,6 +69,8 @@ struct SimplifyItem : public SrcObject {
bool isConditional() const { return scope.size() > 1; }
bool isGeneric() const { return generic; }
char isStatic() const { return staticType; }
/// True if an identifier is a loop variable in a comprehension
bool canDominate() const { return !avoidDomination; }
};

/** Context class that tracks identifiers during the simplification. **/
Expand Down Expand Up @@ -159,6 +164,8 @@ struct SimplifyContext : public Context<SimplifyItem> {
/// Allow type() expressions. Currently used to disallow type() in class
/// and function definitions.
bool allowTypeOf;
/// Set if all assignments should not be dominated later on.
bool avoidDomination = false;

public:
SimplifyContext(std::string filename, Cache *cache);
Expand Down
7 changes: 4 additions & 3 deletions codon/parser/visitors/simplify/loops.cpp
Expand Up @@ -98,13 +98,14 @@ void SimplifyVisitor::visit(ForStmt *stmt) {
ctx->getBase()->loops.push_back({breakVar, ctx->scope.blocks, {}});
std::string varName;
if (auto i = stmt->var->getId()) {
ctx->addVar(i->value, varName = ctx->generateCanonicalName(i->value),
stmt->var->getSrcInfo());
auto val = ctx->addVar(i->value, varName = ctx->generateCanonicalName(i->value),
stmt->var->getSrcInfo());
val->avoidDomination = ctx->avoidDomination;
transform(stmt->var);
stmt->suite = transform(N<SuiteStmt>(stmt->suite));
} else {
varName = ctx->cache->getTemporaryVar("for");
ctx->addVar(varName, varName, stmt->var->getSrcInfo());
auto val = ctx->addVar(varName, varName, stmt->var->getSrcInfo());
auto var = N<IdExpr>(varName);
std::vector<StmtPtr> stmts;
// Add for_var = [for variables]
Expand Down
1 change: 1 addition & 0 deletions codon/parser/visitors/typecheck/infer.cpp
Expand Up @@ -325,6 +325,7 @@ types::TypePtr TypecheckVisitor::realizeFunc(types::FuncType *type, bool force)
// Lambda typecheck failures are "ignored" as they are treated as statements,
// not functions.
// TODO: generalize this further.
// LOG("{}", ast->suite->toString(2));
error("cannot typecheck the program");
}
ctx->realizationBases.pop_back();
Expand Down
13 changes: 13 additions & 0 deletions test/parser/simplify_stmt.codon
Expand Up @@ -1209,6 +1209,19 @@ for i in range(2):
#: 1
#: 1

def comprehension_test(x):
for n in range(3):
print('>', n)
l = ['1', '2', str(x)]
x = [n for n in l]
print(x, n)
comprehension_test(5)
#: > 0
#: > 1
#: > 2
#: ['1', '2', '5'] 2


#%% block_unroll,barebones
# Ensure that block unrolling is done in RAII manner on error
def foo():
Expand Down

0 comments on commit a2158ad

Please sign in to comment.