Skip to content

Commit

Permalink
libnixf/{Parse,Sema}: deduplicate lambda arg with it's formals (#386)
Browse files Browse the repository at this point in the history
  • Loading branch information
inclyc authored Apr 8, 2024
1 parent 1e23316 commit 1066132
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 13 deletions.
4 changes: 4 additions & 0 deletions libnixf/include/nixf/Sema/SemaActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ class Sema {
std::shared_ptr<ExprAttrs> onExprAttrs(LexerCursorRange Range,
std::shared_ptr<Binds> Binds,
std::shared_ptr<Misc> Rec);

std::shared_ptr<LambdaArg> onLambdaArg(LexerCursorRange Range,
std::shared_ptr<Identifier> ID,
std::shared_ptr<Formals> F);
};

} // namespace nixf
21 changes: 10 additions & 11 deletions libnixf/src/Parse/ParseLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ std::shared_ptr<LambdaArg> Parser::parseLambdaArg() {
auto ID =
std::make_shared<Identifier>(TokID.range(), std::string(TokID.view()));
if (peek().kind() != tok_at)
return std::make_shared<LambdaArg>(
LexerCursorRange{LCur, LastToken->rCur()}, std::move(ID), nullptr);
return Act.onLambdaArg(LexerCursorRange{LCur, LastToken->rCur()},
std::move(ID), nullptr);

consume(); // @
std::shared_ptr<Formals> Formals = parseFormals();
Expand All @@ -103,9 +103,8 @@ std::shared_ptr<LambdaArg> Parser::parseLambdaArg() {
D.fix("insert dummy formals")
.edit(TextEdit::mkInsertion(TokID.rCur(), R"({})"));
}
return std::make_shared<LambdaArg>(
LexerCursorRange{LCur, LastToken->rCur()}, std::move(ID),
std::move(Formals));
return Act.onLambdaArg(LexerCursorRange{LCur, LastToken->rCur()},
std::move(ID), std::move(Formals));
}

std::shared_ptr<Formals> Formals = parseFormals();
Expand All @@ -114,21 +113,21 @@ std::shared_ptr<LambdaArg> Parser::parseLambdaArg() {
assert(LastToken && "LastToken should be set after valid formals");
Token TokAt = peek();
if (TokAt.kind() != tok_at)
return std::make_shared<LambdaArg>(
LexerCursorRange{LCur, LastToken->rCur()}, nullptr, std::move(Formals));
return Act.onLambdaArg(LexerCursorRange{LCur, LastToken->rCur()}, nullptr,
std::move(Formals));
consume(); // @
ExpectResult ER = expect(tok_id);
if (!ER.ok()) {
ER.diag().note(Note::NK_ToMachThis, TokAt.range())
<< std::string(tok::spelling(tok_at));
return std::make_shared<LambdaArg>(
LexerCursorRange{LCur, LastToken->rCur()}, nullptr, std::move(Formals));
return Act.onLambdaArg(LexerCursorRange{LCur, LastToken->rCur()}, nullptr,
std::move(Formals));
}
consume(); // ID
auto ID = std::make_shared<Identifier>(ER.tok().range(),
std::string(ER.tok().view()));
return std::make_shared<LambdaArg>(LexerCursorRange{LCur, LastToken->rCur()},
std::move(ID), std::move(Formals));
return Act.onLambdaArg(LexerCursorRange{LCur, LastToken->rCur()},
std::move(ID), std::move(Formals));
}

std::shared_ptr<ExprLambda> Parser::parseExprLambda() {
Expand Down
16 changes: 16 additions & 0 deletions libnixf/src/Sema/SemaActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,4 +345,20 @@ std::shared_ptr<ExprAttrs> Sema::onExprAttrs(LexerCursorRange Range,
std::move(ESA));
}

std::shared_ptr<LambdaArg> Sema::onLambdaArg(LexerCursorRange Range,
std::shared_ptr<Identifier> ID,
std::shared_ptr<Formals> F) {
// Check that if lambda arguments duplicated to it's formal

if (ID && F) {
if (F->dedup().contains(ID->name())) {
// Report duplicated.
Diagnostic &D =
Diags.emplace_back(Diagnostic::DK_DuplicatedFormalToArg, ID->range());
D.note(Note::NK_DuplicateFormal, F->dedup().at(ID->name())->range());
}
}
return std::make_shared<LambdaArg>(Range, std::move(ID), std::move(F));
}

} // namespace nixf
8 changes: 6 additions & 2 deletions libnixf/src/Sema/VariableLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,12 @@ void VariableLookupAnalysis::dfs(const ExprLambda &Lambda,

// foo: body
// ^~~<------- add function argument.
if (Arg.id())
DBuilder.add(Arg.id()->name(), Arg.id());
if (Arg.id()) {
// Function arg cannot duplicate to it's formal.
// If it this unluckily happens, we would like to skip this definition.
if (!Arg.formals() || !Arg.formals()->dedup().contains(Arg.id()->name()))
DBuilder.add(Arg.id()->name(), Arg.id());
}

// { foo, bar, ... } : body
/// ^~~~~~~~~<-------------- add function formals.
Expand Down
12 changes: 12 additions & 0 deletions libnixf/test/Sema/VariableLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,16 @@ TEST_F(VLATest, LivenessNested) {
ASSERT_EQ(Diags[0].tags()[0], DiagnosticTag::Faded);
}

TEST_F(VLATest, LivenessDupSymbol) {
std::shared_ptr<Node> AST = parse("x @ {x, ...} : x + 1", Diags);
VariableLookupAnalysis VLA(Diags);
VLA.runOnAST(*AST);

ASSERT_EQ(Diags.size(), 1);

ASSERT_EQ(Diags[0].kind(), Diagnostic::DK_DuplicatedFormalToArg);
ASSERT_EQ(Diags[0].range().lCur().column(), 0);
ASSERT_EQ(Diags[0].tags().size(), 0);
}

} // namespace

0 comments on commit 1066132

Please sign in to comment.