From 27454f7d047990e72c5d93cbd53dcca6b3329d60 Mon Sep 17 00:00:00 2001 From: Jakub Ciesluk <323892@uwr.edu.pl> Date: Mon, 9 Oct 2023 15:13:56 +0200 Subject: [PATCH] bugfix: Completions for named args in wrong order --- .../pc/completions/NamedArgCompletions.scala | 42 ++++++++++- .../scala/tests/pc/CompletionArgSuite.scala | 69 +++++++++++++++++++ 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/completions/NamedArgCompletions.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/completions/NamedArgCompletions.scala index a18e7c3ffa1..26bd9633029 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/completions/NamedArgCompletions.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/completions/NamedArgCompletions.scala @@ -6,6 +6,7 @@ import scala.util.Try import scala.meta.internal.mtags.MtagsEnrichments.* import scala.meta.internal.pc.IndexedContext +import dotty.tools.dotc.ast.NavigateAST import dotty.tools.dotc.ast.Trees.ValDef import dotty.tools.dotc.ast.tpd.* import dotty.tools.dotc.core.Constants.Constant @@ -15,7 +16,10 @@ import dotty.tools.dotc.core.Flags import dotty.tools.dotc.core.Flags.Method import dotty.tools.dotc.core.NameKinds.DefaultGetterName import dotty.tools.dotc.core.Names.Name +import dotty.tools.dotc.core.StdNames.* +import dotty.tools.dotc.core.SymDenotations.NoDenotation import dotty.tools.dotc.core.Symbols +import dotty.tools.dotc.core.Symbols.NoSymbol import dotty.tools.dotc.core.Symbols.Symbol import dotty.tools.dotc.core.Types.AndType import dotty.tools.dotc.core.Types.AppliedType @@ -66,6 +70,26 @@ object NamedArgCompletions: clientSupportsSnippets, ) contribution.getOrElse(Nil) + case (app: Apply) :: _ => + /** + * def foo(aaa: Int, bbb: Int, ccc: Int) = ??? + * val x = foo( + * bbb = 123, + * ccc = 123, + * @@ + * ) + * In this case, typed path doesn't contain already provided arguments + */ + NavigateAST.untypedPath(pos.span) match + case (ident: Ident) :: (app: Apply) :: _ => + contribute( + Some(ident), + app, + indexedContext, + clientSupportsSnippets, + ) + case _ => + Nil case _ => Nil end match @@ -117,6 +141,11 @@ object NamedArgCompletions: val argss = collectArgss(apply) + def fallbackFindApply(sym: Symbol) = + sym.info.member(nme.apply) match + case NoDenotation => Nil + case den => List(den.symbol) + // fallback for when multiple overloaded methods match the supplied args def fallbackFindMatchingMethods() = def maybeNameAndIndexedContext( @@ -182,7 +211,9 @@ object NamedArgCompletions: if foundPotential.contains(method.symbol) then foundPotential else method.symbol :: foundPotential else List(method.symbol) - else fallbackFindMatchingMethods() + else if method.symbol.is(Method) || method.symbol == NoSymbol then + fallbackFindMatchingMethods() + else fallbackFindApply(method.symbol) end if end matchingMethods @@ -227,8 +258,13 @@ object NamedArgCompletions: def refineParams(method: Tree, level: Int): List[ParamSymbol] = method match case Select(Apply(f, _), _) => refineParams(f, level + 1) - case Select(h, v) => getRefinedParams(h.symbol.info, level) - case _ => defaultBaseParams + case Select(h, name) => + // for Select(foo, name = apply) we want `foo.symbol` + if name == nme.apply then getRefinedParams(h.symbol.info, level) + else getRefinedParams(method.symbol.info, level) + case Apply(f, _) => + refineParams(f, level + 1) + case _ => getRefinedParams(method.symbol.info, level) refineParams(method, 0) end baseParams diff --git a/tests/cross/src/test/scala/tests/pc/CompletionArgSuite.scala b/tests/cross/src/test/scala/tests/pc/CompletionArgSuite.scala index 58c0018f9a1..fd13a60cb8b 100644 --- a/tests/cross/src/test/scala/tests/pc/CompletionArgSuite.scala +++ b/tests/cross/src/test/scala/tests/pc/CompletionArgSuite.scala @@ -1147,4 +1147,73 @@ class CompletionArgSuite extends BaseCompletionSuite { |""".stripMargin, topLines = Some(1), ) + + check( + "second-first".tag(IgnoreForScala3CompilerPC), + """|object Main { + | def foo(aaa: Int, bbb: Int, ccc: Int) = aaa + bbb + ccc + | val k = foo ( + | bbb = 123, + | aa@@ + | ) + |} + |""".stripMargin, + """|aaa = : Int + |""".stripMargin, + topLines = Some(1), + ) + + check( + "second-first2".tag(IgnoreForScala3CompilerPC), + """|object Main { + | def foo(aaa: Int, bbb: Int, ccc: Int) = aaa + bbb + ccc + | val k = foo ( + | bbb = 123, + | ccc = 123, + | aa@@ + | ) + |} + |""".stripMargin, + """|aaa = : Int + |""".stripMargin, + topLines = Some(1), + ) + + check( + "second-first3".tag(IgnoreForScala3CompilerPC), + """|object Main { + | def foo(ddd: Int)(aaa: Int, bbb: Int, ccc: Int) = aaa + bbb + ccc + | val k = foo(123)( + | bbb = 123, + | ccc = 123, + | aa@@ + | ) + |} + |""".stripMargin, + """|aaa = : Int + |""".stripMargin, + topLines = Some(1), + ) + + check( + "second-first4".tag(IgnoreScala2).tag(IgnoreForScala3CompilerPC), + """|object O: + | val hello: (x: Int, y: Int) => Unit = (x, _) => println(x) + |val k = O.hello(y = 1, @@) + |""".stripMargin, + """|x = : Int + |""".stripMargin, + topLines = Some(1), + ) + + check( + "second-first5".tag(IgnoreScala2).tag(IgnoreForScala3CompilerPC), + """|val hello: (x: Int) => Int => (str: String, ccc: String) => Unit = x => j => (str, _) => println(str) + |val k = hello(x = 1)(2)(ccc = "abc", @@) + |""".stripMargin, + """|str = : String + |""".stripMargin, + topLines = Some(1), + ) + }