From 3e66f02c6c678fc5827828151aeca367e1f939a3 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 10 Jun 2024 09:08:00 -0700 Subject: [PATCH 1/6] Handle complex literals Signed-off-by: Danila Fedorin --- .../src/chpl-language-server.py | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/tools/chpl-language-server/src/chpl-language-server.py b/tools/chpl-language-server/src/chpl-language-server.py index aba5c43f14d3..b1ac5e44ef17 100755 --- a/tools/chpl-language-server/src/chpl-language-server.py +++ b/tools/chpl-language-server/src/chpl-language-server.py @@ -142,6 +142,50 @@ import argparse import configargparse +def is_basic_literal_like(node: chapel.AstNode) -> Optional[chapel.Literal]: + """ + Check for "basic" literals: basically, 1, "hello", -42, etc. + Returns the "underlying" literal removing surrounding AST (1, "hello", 42). + This helps do type comparisons in more complex checks. If the node is + not a basic literal, returns None. + """ + if isinstance(node, chapel.Literal): + return node + + if isinstance(node, chapel.OpCall) and node.op() == "-" and node.num_actuals() == 1: + # Do not recurse; do not consider --42 as a basic literal. + act = node.actual(0) + if isinstance(act, chapel.Literal): + return act + + return None + +def is_literal_like(node: chapel.AstNode) -> bool: + if is_basic_literal_like(node): + return True + + if isinstance(node, chapel.OpCall): + # A complex number is far from a literal in the AST; in fact, it + # potentially has as many as 4 AST nodes: -1 - 2i has a unary negation, + # an addition, and two "pure" literals. + op = node.op() + if (op == "+" or op == "-") and node.num_actuals() == 2: + # The left element can be a 'basic literal-like', like 1 or -42i. + # But the right element shouldn't have any operators, otherwise + # we'd get somethig that looks like 1 - -42i. So we just + # use the right argument directly. + left = is_basic_literal_like(node.actual(0)) + right = node.actual(1) + + real_number = (chapel.RealLiteral, chapel.IntLiteral) + imag_number = chapel.ImagLiteral + if isinstance(left, real_number) and isinstance(right, imag_number): + return True + if isinstance(left, imag_number) and isinstance(right, real_number): + return True + + return False + def decl_kind(decl: chapel.NamedDecl) -> Optional[SymbolKind]: if isinstance(decl, chapel.Module) and decl.kind() != "implicit": @@ -1222,7 +1266,7 @@ def get_call_inlays( # tuples. We don't need hints for those. continue - if not isinstance(act, chapel.core.Literal): + if not is_literal_like(act): # Only show named arguments for literals. continue From dd4ec4f030051db834a7d9119c38beba4de93f7a Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 10 Jun 2024 09:09:50 -0700 Subject: [PATCH 2/6] Update complex numbers tests and un-futurize it. Signed-off-by: Danila Fedorin --- tools/chpl-language-server/test/call_inlays.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tools/chpl-language-server/test/call_inlays.py b/tools/chpl-language-server/test/call_inlays.py index 26e0f1924681..dd2786da9a49 100644 --- a/tools/chpl-language-server/test/call_inlays.py +++ b/tools/chpl-language-server/test/call_inlays.py @@ -75,7 +75,6 @@ async def test_call_inlays(client: LanguageClient): @pytest.mark.asyncio -@pytest.mark.xfail async def test_call_inlays_complex(client: LanguageClient): """ Ensure that call inlays are shown for complex literals in call expressions. @@ -84,9 +83,21 @@ async def test_call_inlays_complex(client: LanguageClient): file = """ proc foo(a) {} foo(3i+10); + foo(3i+10.0); + foo(3.0i+10.0); + foo(3.0i+10); + foo(10+3i); + foo(10.0+3i); + foo(10.0+3.0i); + foo(10+3.0i); + + // Not 'literals' in our sense: + foo(3i + 4i); + foo(1 + 1); + foo((-1) - (-i)); """ - inlays = [(pos((1, 4)), "a = ", None)] + inlays = [(pos((i, 4)), "a = ", None) for i in range(1, 9)] async with source_file(client, file) as doc: await check_inlay_hints(client, doc, rng((0, 0), endpos(file)), inlays) From 26e3a2786e8c83f10c877324e20f312cd6037f25 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 10 Jun 2024 09:12:33 -0700 Subject: [PATCH 3/6] Add another test for complex numbers Signed-off-by: Danila Fedorin --- .../chpl-language-server/test/call_inlays.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tools/chpl-language-server/test/call_inlays.py b/tools/chpl-language-server/test/call_inlays.py index dd2786da9a49..96319914bda9 100644 --- a/tools/chpl-language-server/test/call_inlays.py +++ b/tools/chpl-language-server/test/call_inlays.py @@ -103,6 +103,29 @@ async def test_call_inlays_complex(client: LanguageClient): await check_inlay_hints(client, doc, rng((0, 0), endpos(file)), inlays) +@pytest.mark.asyncio +async def test_call_inlays_negative(client: LanguageClient): + """ + Ensure that call inlays are shown for negative literals in call expressions. + """ + + file = """ + proc foo(a) {} + foo(-42); + foo(-42.0); + foo(-42i); + foo(-42.0i); + + // Not 'literals' in our sense: + foo(- -42); + """ + + inlays = [(pos((i, 4)), "a = ", None) for i in range(1, 5)] + + async with source_file(client, file) as doc: + await check_inlay_hints(client, doc, rng((0, 0), endpos(file)), inlays) + + @pytest.mark.asyncio async def test_nested_call_inlays(client: LanguageClient): """ From 8541ba3688223e34b768135bbae8632c27d928c8 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 10 Jun 2024 09:15:24 -0700 Subject: [PATCH 4/6] Strengthen the condition to disallow literals like -"hello" Signed-off-by: Danila Fedorin --- tools/chpl-language-server/src/chpl-language-server.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/chpl-language-server/src/chpl-language-server.py b/tools/chpl-language-server/src/chpl-language-server.py index b1ac5e44ef17..aaecb03a3d0d 100755 --- a/tools/chpl-language-server/src/chpl-language-server.py +++ b/tools/chpl-language-server/src/chpl-language-server.py @@ -142,6 +142,9 @@ import argparse import configargparse +REAL_NUMBERIC = (chapel.RealLiteral, chapel.IntLiteral, chapel.UintLiteral) +NUMERIC = REAL_NUMBERIC + (chapel.ImagLiteral,) + def is_basic_literal_like(node: chapel.AstNode) -> Optional[chapel.Literal]: """ Check for "basic" literals: basically, 1, "hello", -42, etc. @@ -155,7 +158,7 @@ def is_basic_literal_like(node: chapel.AstNode) -> Optional[chapel.Literal]: if isinstance(node, chapel.OpCall) and node.op() == "-" and node.num_actuals() == 1: # Do not recurse; do not consider --42 as a basic literal. act = node.actual(0) - if isinstance(act, chapel.Literal): + if isinstance(act, NUMERIC): return act return None @@ -177,7 +180,7 @@ def is_literal_like(node: chapel.AstNode) -> bool: left = is_basic_literal_like(node.actual(0)) right = node.actual(1) - real_number = (chapel.RealLiteral, chapel.IntLiteral) + real_number = REAL_NUMBERIC imag_number = chapel.ImagLiteral if isinstance(left, real_number) and isinstance(right, imag_number): return True From 3f02de973856e6d1e285d60e015c05a5a590afbf Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 10 Jun 2024 09:16:47 -0700 Subject: [PATCH 5/6] Fix comment Signed-off-by: Danila Fedorin --- tools/chpl-language-server/src/chpl-language-server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/chpl-language-server/src/chpl-language-server.py b/tools/chpl-language-server/src/chpl-language-server.py index aaecb03a3d0d..d4863e6f66f9 100755 --- a/tools/chpl-language-server/src/chpl-language-server.py +++ b/tools/chpl-language-server/src/chpl-language-server.py @@ -169,7 +169,7 @@ def is_literal_like(node: chapel.AstNode) -> bool: if isinstance(node, chapel.OpCall): # A complex number is far from a literal in the AST; in fact, it - # potentially has as many as 4 AST nodes: -1 - 2i has a unary negation, + # potentially has as many as 4 AST nodes: -1 + 2i has a unary negation, # an addition, and two "pure" literals. op = node.op() if (op == "+" or op == "-") and node.num_actuals() == 2: From 20c47e3468d4cdd92859702cbacf034ce076e6e2 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 10 Jun 2024 09:17:07 -0700 Subject: [PATCH 6/6] Apply black. Node, Jade, I did not get bitten by the CI check :^) Signed-off-by: Danila Fedorin --- tools/chpl-language-server/src/chpl-language-server.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/chpl-language-server/src/chpl-language-server.py b/tools/chpl-language-server/src/chpl-language-server.py index d4863e6f66f9..6cdea80286eb 100755 --- a/tools/chpl-language-server/src/chpl-language-server.py +++ b/tools/chpl-language-server/src/chpl-language-server.py @@ -145,6 +145,7 @@ REAL_NUMBERIC = (chapel.RealLiteral, chapel.IntLiteral, chapel.UintLiteral) NUMERIC = REAL_NUMBERIC + (chapel.ImagLiteral,) + def is_basic_literal_like(node: chapel.AstNode) -> Optional[chapel.Literal]: """ Check for "basic" literals: basically, 1, "hello", -42, etc. @@ -155,7 +156,11 @@ def is_basic_literal_like(node: chapel.AstNode) -> Optional[chapel.Literal]: if isinstance(node, chapel.Literal): return node - if isinstance(node, chapel.OpCall) and node.op() == "-" and node.num_actuals() == 1: + if ( + isinstance(node, chapel.OpCall) + and node.op() == "-" + and node.num_actuals() == 1 + ): # Do not recurse; do not consider --42 as a basic literal. act = node.actual(0) if isinstance(act, NUMERIC): @@ -163,6 +168,7 @@ def is_basic_literal_like(node: chapel.AstNode) -> Optional[chapel.Literal]: return None + def is_literal_like(node: chapel.AstNode) -> bool: if is_basic_literal_like(node): return True