Skip to content

Commit 7683220

Browse files
authored
libnixf/Sema: mark nested with expressions alive (#617)
Fixes: #606
1 parent b95940c commit 7683220

File tree

2 files changed

+38
-21
lines changed

2 files changed

+38
-21
lines changed

libnixf/src/Sema/VariableLookup.cpp

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -76,41 +76,44 @@ void VariableLookupAnalysis::emitEnvLivenessWarning(
7676

7777
void VariableLookupAnalysis::lookupVar(const ExprVar &Var,
7878
const std::shared_ptr<EnvNode> &Env) {
79-
const std::string &Name = Var.id().name();
80-
81-
bool EnclosedWith = false; // If there is a "With" enclosed this var name.
82-
EnvNode *WithEnv = nullptr;
83-
EnvNode *CurEnv = Env.get();
79+
const auto &Name = Var.id().name();
80+
const auto *CurEnv = Env.get();
8481
std::shared_ptr<Definition> Def;
82+
std::vector<const EnvNode *> WithEnvs;
8583
for (; CurEnv; CurEnv = CurEnv->parent()) {
8684
if (CurEnv->defs().contains(Name)) {
8785
Def = CurEnv->defs().at(Name);
8886
break;
8987
}
90-
// Find the most nested `with` expression, and set uses.
91-
if (CurEnv->isWith() && !EnclosedWith) {
92-
EnclosedWith = true;
93-
WithEnv = CurEnv;
88+
// Find all nested "with" expression, variables potentially come from those.
89+
// For example
90+
// with lib;
91+
// with builtins;
92+
// generators <--- this variable may come from "lib" | "builtins"
93+
//
94+
// We cannot determine where it precisely come from, thus mark all Envs
95+
// alive.
96+
if (CurEnv->isWith()) {
97+
WithEnvs.emplace_back(CurEnv);
9498
}
9599
}
96100

97101
if (Def) {
98102
Def->usedBy(Var);
99103
Results.insert({&Var, LookupResult{LookupResultKind::Defined, Def}});
100-
return;
101-
}
102-
if (EnclosedWith) {
103-
Def = WithDefs.at(WithEnv->syntax());
104-
Def->usedBy(Var);
104+
} else if (!WithEnvs.empty()) { // comes from enclosed "with" expressions.
105+
for (const auto *WithEnv : WithEnvs) {
106+
Def = WithDefs.at(WithEnv->syntax());
107+
Def->usedBy(Var);
108+
}
105109
Results.insert({&Var, LookupResult{LookupResultKind::FromWith, Def}});
106-
return;
110+
} else {
111+
// Otherwise, this variable is undefined.
112+
Results.insert({&Var, LookupResult{LookupResultKind::Undefined, nullptr}});
113+
Diagnostic &Diag =
114+
Diags.emplace_back(Diagnostic::DK_UndefinedVariable, Var.range());
115+
Diag << Var.id().name();
107116
}
108-
109-
// Otherwise, this variable is undefined.
110-
Results.insert({&Var, LookupResult{LookupResultKind::Undefined, nullptr}});
111-
Diagnostic &Diag =
112-
Diags.emplace_back(Diagnostic::DK_UndefinedVariable, Var.range());
113-
Diag << Var.id().name();
114117
}
115118

116119
void VariableLookupAnalysis::dfs(const ExprLambda &Lambda,

libnixf/test/Sema/VariableLookup.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,4 +324,18 @@ in 1
324324
ASSERT_EQ(Diags.size(), 1);
325325
}
326326

327+
TEST_F(VLATest, Issue606_NestedWith) {
328+
const char *Src = R"(
329+
with builtins;
330+
with builtins;
331+
concatLists
332+
)";
333+
334+
std::shared_ptr<Node> AST = parse(Src, Diags);
335+
VariableLookupAnalysis VLA(Diags);
336+
VLA.runOnAST(*AST);
337+
338+
ASSERT_EQ(Diags.size(), 0);
339+
}
340+
327341
} // namespace

0 commit comments

Comments
 (0)