From 37d18c1415d3e2dbbe5fde43495386dc6427c63f Mon Sep 17 00:00:00 2001 From: aleksana Date: Thu, 1 Aug 2024 22:48:44 +0800 Subject: [PATCH] libnixf: split sema-unused-def into let, arg and formal --- libnixf/include/nixf/Sema/VariableLookup.h | 5 +++- libnixf/src/Basic/diagnostic.py | 24 +++++++++++++-- libnixf/src/Sema/VariableLookup.cpp | 34 +++++++++++++++++----- libnixf/test/Sema/VariableLookup.cpp | 25 +++++++++++----- 4 files changed, 70 insertions(+), 18 deletions(-) diff --git a/libnixf/include/nixf/Sema/VariableLookup.h b/libnixf/include/nixf/Sema/VariableLookup.h index e470415cd..8b0116172 100644 --- a/libnixf/include/nixf/Sema/VariableLookup.h +++ b/libnixf/include/nixf/Sema/VariableLookup.h @@ -39,9 +39,12 @@ class Definition { /// \brief From lambda formal, e.g. { a }: a + 1 DS_LambdaFormal, - /// \brief From lambda arg with formal, e.g. { foo, bar }@a: a + 1 + /// \brief From lambda arg with formal, e.g. `a` in `{ foo }@a: foo + 1` DS_LambdaArgWithFormal, + /// \brief From lambda formal with arg, e.g. `foo` in `{ foo }@a: foo + 1` + DS_LambdaFormalWithArg, + /// \brief From recursive attribute set. e.g. rec { } DS_Rec, diff --git a/libnixf/src/Basic/diagnostic.py b/libnixf/src/Basic/diagnostic.py index 57d4fe837..a24c6ab34 100644 --- a/libnixf/src/Basic/diagnostic.py +++ b/libnixf/src/Basic/diagnostic.py @@ -184,10 +184,28 @@ class Diagnostic(TypedDict): "message": "undefined variable `{}`", }, { - "sname": "sema-def-not-used", - "cname": "DefinitionNotUsed", + "sname": "sema-unused-def-let", + "cname": "UnusedDefLet", + "severity": "Warning", + "message": "variable `{}` in let-expression is not used", + }, + { + "sname": "sema-unused-def-formal", + "cname": "UnusedDefFormal", + "severity": "Warning", + "message": "attribute `{}` of argument is not used", + }, + { + "sname": "sema-unused-def-arg-with-formal", + "cname": "UnusedDefArgWithFormal", + "severity": "Warning", + "message": "argument `{}` in `@`-pattern is not used", + }, + { + "sname": "sema-unused-def-formal-with-arg", + "cname": "UnusedDefFormalWithArg", "severity": "Hint", - "message": "definition `{}` is not used", + "message": "attribute `{}` of `@`-pattern argument is not used, but may be referenced from the argument", }, { "sname": "sema-extra-rec", diff --git a/libnixf/src/Sema/VariableLookup.cpp b/libnixf/src/Sema/VariableLookup.cpp index d25d3c3d4..c39bca727 100644 --- a/libnixf/src/Sema/VariableLookup.cpp +++ b/libnixf/src/Sema/VariableLookup.cpp @@ -52,8 +52,24 @@ void VariableLookupAnalysis::emitEnvLivenessWarning( if (!Def->syntax()) continue; if (Def->uses().empty()) { - Diagnostic &D = Diags.emplace_back(Diagnostic::DK_DefinitionNotUsed, - Def->syntax()->range()); + Diagnostic::DiagnosticKind kind; + switch (Def->source()) { + case Definition::DS_Let: + kind = Diagnostic::DK_UnusedDefLet; + break; + case Definition::DS_LambdaFormal: + kind = Diagnostic::DK_UnusedDefFormal; + break; + case Definition::DS_LambdaFormalWithArg: + kind = Diagnostic::DK_UnusedDefFormalWithArg; + break; + case Definition::DS_LambdaArgWithFormal: + kind = Diagnostic::DK_UnusedDefArgWithFormal; + break; + default: + break; + } + Diagnostic &D = Diags.emplace_back(kind, Def->syntax()->range()); D << Name; D.tag(DiagnosticTag::Faded); } @@ -128,6 +144,9 @@ void VariableLookupAnalysis::dfs(const ExprLambda &Lambda, // foo: body // ^~~<------- add function argument. + // { foo, bar, ... } : body + // ^~~~~~~~~<-------------- add function formals. + if (Arg.id()) { if (!Arg.formals()) { ToDef.insert_or_assign(Arg.id(), DBuilder.add(Arg.id()->name(), Arg.id(), @@ -138,16 +157,17 @@ void VariableLookupAnalysis::dfs(const ExprLambda &Lambda, ToDef.insert_or_assign(Arg.id(), DBuilder.add(Arg.id()->name(), Arg.id(), Definition::DS_LambdaArgWithFormal)); + for (const auto &[Name, Formal] : Arg.formals()->dedup()) + ToDef.insert_or_assign( + Formal->id(), DBuilder.add(Name, Formal->id(), + Definition::DS_LambdaFormalWithArg)); } - } - - // { foo, bar, ... } : body - /// ^~~~~~~~~<-------------- add function formals. - if (Arg.formals()) + } else if (Arg.formals()) { for (const auto &[Name, Formal] : Arg.formals()->dedup()) ToDef.insert_or_assign( Formal->id(), DBuilder.add(Name, Formal->id(), Definition::DS_LambdaFormal)); + } auto NewEnv = std::make_shared(Env, DBuilder.finish(), &Lambda); diff --git a/libnixf/test/Sema/VariableLookup.cpp b/libnixf/test/Sema/VariableLookup.cpp index 4e1b0f409..963640e79 100644 --- a/libnixf/test/Sema/VariableLookup.cpp +++ b/libnixf/test/Sema/VariableLookup.cpp @@ -135,29 +135,27 @@ TEST_F(VLATest, LivenessRec) { ASSERT_EQ(Diags[0].kind(), Diagnostic::DK_ExtraRecursive); } -TEST_F(VLATest, LivenessArg) { +TEST_F(VLATest, LivenessFormal) { std::shared_ptr AST = parse("{ foo }: 1", Diags); VariableLookupAnalysis VLA(Diags); VLA.runOnAST(*AST); ASSERT_EQ(Diags.size(), 1); - ASSERT_EQ(Diags[0].kind(), Diagnostic::DK_DefinitionNotUsed); + ASSERT_EQ(Diags[0].kind(), Diagnostic::DK_UnusedDefFormal); ASSERT_EQ(Diags[0].tags().size(), 1); - ASSERT_EQ(Diags[0].tags()[0], DiagnosticTag::Faded); } -TEST_F(VLATest, LivenessNested) { +TEST_F(VLATest, LivenessLet) { std::shared_ptr AST = parse("let y = 1; in x: y: x + y", Diags); VariableLookupAnalysis VLA(Diags); VLA.runOnAST(*AST); ASSERT_EQ(Diags.size(), 1); - ASSERT_EQ(Diags[0].kind(), Diagnostic::DK_DefinitionNotUsed); + ASSERT_EQ(Diags[0].kind(), Diagnostic::DK_UnusedDefLet); ASSERT_EQ(Diags[0].range().lCur().column(), 4); ASSERT_EQ(Diags[0].tags().size(), 1); - ASSERT_EQ(Diags[0].tags()[0], DiagnosticTag::Faded); } TEST_F(VLATest, LivenessDupSymbol) { @@ -179,12 +177,25 @@ TEST_F(VLATest, LivenessArgWithFormal) { ASSERT_EQ(Diags.size(), 1); - ASSERT_EQ(Diags[0].kind(), Diagnostic::DK_DefinitionNotUsed); + ASSERT_EQ(Diags[0].kind(), Diagnostic::DK_UnusedDefArgWithFormal); ASSERT_EQ(Diags[0].range().lCur().column(), 8); ASSERT_EQ(Diags[0].tags().size(), 1); +} + +TEST_F(VLATest, LivenessFormalWithArg) { + std::shared_ptr AST = parse("{ foo }@bar: bar", Diags); + VariableLookupAnalysis VLA(Diags); + VLA.runOnAST(*AST); + + ASSERT_EQ(Diags.size(), 1); + + ASSERT_EQ(Diags[0].kind(), Diagnostic::DK_UnusedDefFormalWithArg); + ASSERT_EQ(Diags[0].range().lCur().column(), 2); + ASSERT_EQ(Diags[0].tags().size(), 1); ASSERT_EQ(Diags[0].tags()[0], DiagnosticTag::Faded); } + TEST_F(VLATest, ToDefAttrs) { std::shared_ptr AST = parse("rec { x = 1; y = x; z = x; }", Diags); VariableLookupAnalysis VLA(Diags);