Skip to content

Commit b2ea4bc

Browse files
jkcieslukWojciechMazur
authored andcommitted
bugfix: Completions for named args in wrong order (#18702)
connected to scalameta/metals#5728 [Cherry-picked b9cd807]
1 parent 200ab6f commit b2ea4bc

File tree

3 files changed

+118
-11
lines changed

3 files changed

+118
-11
lines changed

presentation-compiler/src/main/dotty/tools/pc/completions/Completions.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ class Completions(
5555

5656
val coursierComplete = new CoursierComplete(BuildInfo.scalaVersion)
5757

58+
private lazy val adjustedPath = Completion.resolveTypedOrUntypedPath(path, pos)
5859
private lazy val completionMode =
59-
val adjustedPath = Completion.resolveTypedOrUntypedPath(path, pos)
6060
val mode = Completion.completionMode(adjustedPath, pos)
6161
path match
6262
case Literal(Constant(_: String)) :: _ => Mode.Term // literal completions
@@ -450,6 +450,7 @@ class Completions(
450450
val args = NamedArgCompletions.contribute(
451451
pos,
452452
path,
453+
adjustedPath,
453454
indexedContext,
454455
config.isCompletionSnippetsEnabled()
455456
)

presentation-compiler/src/main/dotty/tools/pc/completions/NamedArgCompletions.scala

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package dotty.tools.pc.completions
22

33
import scala.util.Try
44

5+
import dotty.tools.dotc.ast.NavigateAST
56
import dotty.tools.dotc.ast.Trees.ValDef
67
import dotty.tools.dotc.ast.tpd.*
8+
import dotty.tools.dotc.ast.untpd
79
import dotty.tools.dotc.core.Constants.Constant
810
import dotty.tools.dotc.core.ContextOps.localContext
911
import dotty.tools.dotc.core.Contexts.Context
@@ -12,7 +14,10 @@ import dotty.tools.dotc.core.Flags
1214
import dotty.tools.dotc.core.Flags.Method
1315
import dotty.tools.dotc.core.NameKinds.DefaultGetterName
1416
import dotty.tools.dotc.core.Names.Name
17+
import dotty.tools.dotc.core.StdNames.*
18+
import dotty.tools.dotc.core.SymDenotations.NoDenotation
1519
import dotty.tools.dotc.core.Symbols
20+
import dotty.tools.dotc.core.Symbols.NoSymbol
1621
import dotty.tools.dotc.core.Symbols.Symbol
1722
import dotty.tools.dotc.core.Types.AndType
1823
import dotty.tools.dotc.core.Types.AppliedType
@@ -33,8 +38,9 @@ object NamedArgCompletions:
3338
def contribute(
3439
pos: SourcePosition,
3540
path: List[Tree],
41+
untypedPath: => List[untpd.Tree],
3642
indexedContext: IndexedContext,
37-
clientSupportsSnippets: Boolean
43+
clientSupportsSnippets: Boolean,
3844
)(using ctx: Context): List[CompletionValue] =
3945
path match
4046
case (ident: Ident) :: ValDef(_, _, _) :: Block(_, app: Apply) :: _
@@ -43,7 +49,7 @@ object NamedArgCompletions:
4349
Some(ident),
4450
app,
4551
indexedContext,
46-
clientSupportsSnippets
52+
clientSupportsSnippets,
4753
)
4854
case (ident: Ident) :: rest =>
4955
def getApplyForContextFunctionParam(path: List[Tree]): Option[Apply] =
@@ -63,9 +69,29 @@ object NamedArgCompletions:
6369
Some(ident),
6470
app,
6571
indexedContext,
66-
clientSupportsSnippets
72+
clientSupportsSnippets,
6773
)
6874
contribution.getOrElse(Nil)
75+
case (app: Apply) :: _ =>
76+
/**
77+
* def foo(aaa: Int, bbb: Int, ccc: Int) = ???
78+
* val x = foo(
79+
* bbb = 123,
80+
* ccc = 123,
81+
* @@
82+
* )
83+
* In this case, typed path doesn't contain already provided arguments
84+
*/
85+
untypedPath match
86+
case (ident: Ident) :: (app: Apply) :: _ =>
87+
contribute(
88+
Some(ident),
89+
app,
90+
indexedContext,
91+
clientSupportsSnippets,
92+
)
93+
case _ =>
94+
Nil
6995
case _ =>
7096
Nil
7197
end match
@@ -75,7 +101,7 @@ object NamedArgCompletions:
75101
ident: Option[Ident],
76102
apply: Apply,
77103
indexedContext: IndexedContext,
78-
clientSupportsSnippets: Boolean
104+
clientSupportsSnippets: Boolean,
79105
)(using context: Context): List[CompletionValue] =
80106
def isUselessLiteral(arg: Tree): Boolean =
81107
arg match
@@ -105,6 +131,11 @@ object NamedArgCompletions:
105131

106132
val argss = collectArgss(apply)
107133

134+
def fallbackFindApply(sym: Symbol) =
135+
sym.info.member(nme.apply) match
136+
case NoDenotation => Nil
137+
case den => List(den.symbol)
138+
108139
// fallback for when multiple overloaded methods match the supplied args
109140
def fallbackFindMatchingMethods() =
110141
def maybeNameAndIndexedContext(
@@ -170,7 +201,9 @@ object NamedArgCompletions:
170201
if foundPotential.contains(method.symbol) then foundPotential
171202
else method.symbol :: foundPotential
172203
else List(method.symbol)
173-
else fallbackFindMatchingMethods()
204+
else if method.symbol.is(Method) || method.symbol == NoSymbol then
205+
fallbackFindMatchingMethods()
206+
else fallbackFindApply(method.symbol)
174207
end if
175208
end matchingMethods
176209

@@ -215,8 +248,13 @@ object NamedArgCompletions:
215248
def refineParams(method: Tree, level: Int): List[ParamSymbol] =
216249
method match
217250
case Select(Apply(f, _), _) => refineParams(f, level + 1)
218-
case Select(h, v) => getRefinedParams(h.symbol.info, level)
219-
case _ => defaultBaseParams
251+
case Select(h, name) =>
252+
// for Select(foo, name = apply) we want `foo.symbol`
253+
if name == nme.apply then getRefinedParams(h.symbol.info, level)
254+
else getRefinedParams(method.symbol.info, level)
255+
case Apply(f, _) =>
256+
refineParams(f, level + 1)
257+
case _ => getRefinedParams(method.symbol.info, level)
220258
refineParams(method, 0)
221259
end baseParams
222260

@@ -318,15 +356,15 @@ object NamedArgCompletions:
318356
param.nameBackticked + " = " + memberName + " "
319357
CompletionValue.namedArg(
320358
label = editText,
321-
param
359+
param,
322360
)
323361
}
324362
}
325363

326364
params.map(p =>
327365
CompletionValue.namedArg(
328366
s"${p.nameBackticked} = ",
329-
p
367+
p,
330368
)
331369
) ::: findPossibleDefaults() ::: fillAllFields()
332370
end contribute
@@ -399,4 +437,4 @@ case class JustSymbol(symbol: Symbol)(using Context) extends ParamSymbol:
399437
def info: Type = symbol.info
400438

401439
case class RefinedSymbol(symbol: Symbol, name: Name, info: Type)
402-
extends ParamSymbol
440+
extends ParamSymbol

presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionArgSuite.scala

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,3 +1038,71 @@ class CompletionArgSuite extends BaseCompletionSuite:
10381038
|""".stripMargin,
10391039
topLines = Some(1),
10401040
)
1041+
1042+
@Test def `second-first` =
1043+
check(
1044+
"""|object Main {
1045+
| def foo(aaa: Int, bbb: Int, ccc: Int) = aaa + bbb + ccc
1046+
| val k = foo (
1047+
| bbb = 123,
1048+
| aa@@
1049+
| )
1050+
|}
1051+
|""".stripMargin,
1052+
"""|aaa = : Int
1053+
|""".stripMargin,
1054+
topLines = Some(1),
1055+
)
1056+
1057+
@Test def `second-first2` =
1058+
check(
1059+
"""|object Main {
1060+
| def foo(aaa: Int, bbb: Int, ccc: Int) = aaa + bbb + ccc
1061+
| val k = foo (
1062+
| bbb = 123,
1063+
| ccc = 123,
1064+
| aa@@
1065+
| )
1066+
|}
1067+
|""".stripMargin,
1068+
"""|aaa = : Int
1069+
|""".stripMargin,
1070+
topLines = Some(1),
1071+
)
1072+
1073+
@Test def `second-first3` =
1074+
check(
1075+
"""|object Main {
1076+
| def foo(ddd: Int)(aaa: Int, bbb: Int, ccc: Int) = aaa + bbb + ccc
1077+
| val k = foo(123)(
1078+
| bbb = 123,
1079+
| ccc = 123,
1080+
| aa@@
1081+
| )
1082+
|}
1083+
|""".stripMargin,
1084+
"""|aaa = : Int
1085+
|""".stripMargin,
1086+
topLines = Some(1),
1087+
)
1088+
1089+
@Test def `second-first4` =
1090+
check(
1091+
"""|object O:
1092+
| val hello: (x: Int, y: Int) => Unit = (x, _) => println(x)
1093+
|val k = O.hello(y = 1, @@)
1094+
|""".stripMargin,
1095+
"""|x = : Int
1096+
|""".stripMargin,
1097+
topLines = Some(1),
1098+
)
1099+
1100+
@Test def `second-first5` =
1101+
check(
1102+
"""|val hello: (x: Int) => Int => (str: String, ccc: String) => Unit = x => j => (str, _) => println(str)
1103+
|val k = hello(x = 1)(2)(ccc = "abc", @@)
1104+
|""".stripMargin,
1105+
"""|str = : String
1106+
| """.stripMargin,
1107+
topLines = Some(1),
1108+
)

0 commit comments

Comments
 (0)