Skip to content

Commit 2849c1f

Browse files
committed
bugfix: Completions for named args in wrong order
1 parent 55c5864 commit 2849c1f

File tree

2 files changed

+114
-10
lines changed

2 files changed

+114
-10
lines changed

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

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ 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.*
78
import dotty.tools.dotc.core.Constants.Constant
@@ -12,7 +13,10 @@ import dotty.tools.dotc.core.Flags
1213
import dotty.tools.dotc.core.Flags.Method
1314
import dotty.tools.dotc.core.NameKinds.DefaultGetterName
1415
import dotty.tools.dotc.core.Names.Name
16+
import dotty.tools.dotc.core.StdNames.*
17+
import dotty.tools.dotc.core.SymDenotations.NoDenotation
1518
import dotty.tools.dotc.core.Symbols
19+
import dotty.tools.dotc.core.Symbols.NoSymbol
1620
import dotty.tools.dotc.core.Symbols.Symbol
1721
import dotty.tools.dotc.core.Types.AndType
1822
import dotty.tools.dotc.core.Types.AppliedType
@@ -34,7 +38,7 @@ object NamedArgCompletions:
3438
pos: SourcePosition,
3539
path: List[Tree],
3640
indexedContext: IndexedContext,
37-
clientSupportsSnippets: Boolean
41+
clientSupportsSnippets: Boolean,
3842
)(using ctx: Context): List[CompletionValue] =
3943
path match
4044
case (ident: Ident) :: ValDef(_, _, _) :: Block(_, app: Apply) :: _
@@ -43,7 +47,7 @@ object NamedArgCompletions:
4347
Some(ident),
4448
app,
4549
indexedContext,
46-
clientSupportsSnippets
50+
clientSupportsSnippets,
4751
)
4852
case (ident: Ident) :: rest =>
4953
def getApplyForContextFunctionParam(path: List[Tree]): Option[Apply] =
@@ -63,9 +67,29 @@ object NamedArgCompletions:
6367
Some(ident),
6468
app,
6569
indexedContext,
66-
clientSupportsSnippets
70+
clientSupportsSnippets,
6771
)
6872
contribution.getOrElse(Nil)
73+
case (app: Apply) :: _ =>
74+
/**
75+
* def foo(aaa: Int, bbb: Int, ccc: Int) = ???
76+
* val x = foo(
77+
* bbb = 123,
78+
* ccc = 123,
79+
* @@
80+
* )
81+
* In this case, typed path doesn't contain already provided arguments
82+
*/
83+
NavigateAST.untypedPath(pos.span) match
84+
case (ident: Ident) :: (app: Apply) :: _ =>
85+
contribute(
86+
Some(ident),
87+
app,
88+
indexedContext,
89+
clientSupportsSnippets,
90+
)
91+
case _ =>
92+
Nil
6993
case _ =>
7094
Nil
7195
end match
@@ -87,7 +111,7 @@ object NamedArgCompletions:
87111
ident: Option[Ident],
88112
apply: Apply,
89113
indexedContext: IndexedContext,
90-
clientSupportsSnippets: Boolean
114+
clientSupportsSnippets: Boolean,
91115
)(using context: Context): List[CompletionValue] =
92116
def isUselessLiteral(arg: Tree): Boolean =
93117
arg match
@@ -117,6 +141,11 @@ object NamedArgCompletions:
117141

118142
val argss = collectArgss(apply)
119143

144+
def fallbackFindApply(sym: Symbol) =
145+
sym.info.member(nme.apply) match
146+
case NoDenotation => Nil
147+
case den => List(den.symbol)
148+
120149
// fallback for when multiple overloaded methods match the supplied args
121150
def fallbackFindMatchingMethods() =
122151
def maybeNameAndIndexedContext(
@@ -182,7 +211,9 @@ object NamedArgCompletions:
182211
if foundPotential.contains(method.symbol) then foundPotential
183212
else method.symbol :: foundPotential
184213
else List(method.symbol)
185-
else fallbackFindMatchingMethods()
214+
else if method.symbol.is(Method) || method.symbol == NoSymbol then
215+
fallbackFindMatchingMethods()
216+
else fallbackFindApply(method.symbol)
186217
end if
187218
end matchingMethods
188219

@@ -227,8 +258,13 @@ object NamedArgCompletions:
227258
def refineParams(method: Tree, level: Int): List[ParamSymbol] =
228259
method match
229260
case Select(Apply(f, _), _) => refineParams(f, level + 1)
230-
case Select(h, v) => getRefinedParams(h.symbol.info, level)
231-
case _ => defaultBaseParams
261+
case Select(h, name) =>
262+
// for Select(foo, name = apply) we want `foo.symbol`
263+
if name == nme.apply then getRefinedParams(h.symbol.info, level)
264+
else getRefinedParams(method.symbol.info, level)
265+
case Apply(f, _) =>
266+
refineParams(f, level + 1)
267+
case _ => getRefinedParams(method.symbol.info, level)
232268
refineParams(method, 0)
233269
end baseParams
234270

@@ -329,15 +365,15 @@ object NamedArgCompletions:
329365
param.nameBackticked + " = " + memberName + " "
330366
CompletionValue.namedArg(
331367
label = editText,
332-
param
368+
param,
333369
)
334370
}
335371
}
336372

337373
params.map(p =>
338374
CompletionValue.namedArg(
339375
s"${p.nameBackticked} = ",
340-
p
376+
p,
341377
)
342378
) ::: findPossibleDefaults() ::: fillAllFields()
343379
end contribute
@@ -410,4 +446,4 @@ case class JustSymbol(symbol: Symbol)(using Context) extends ParamSymbol:
410446
def info: Type = symbol.info
411447

412448
case class RefinedSymbol(symbol: Symbol, name: Name, info: Type)
413-
extends ParamSymbol
449+
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)