Skip to content

Commit 4274f48

Browse files
authored
Provide signature help for unapply methods (#14611)
Related to scalameta/metals#1687
1 parent b0e7265 commit 4274f48

File tree

3 files changed

+100
-20
lines changed

3 files changed

+100
-20
lines changed

compiler/src/dotty/tools/dotc/util/Signatures.scala

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import util.Spans.Span
1010
import core.Types.{ErrorType, MethodType, PolyType}
1111
import reporting._
1212

13+
import dotty.tools.dotc.core.Types.Type
1314

1415
object Signatures {
1516

@@ -48,31 +49,39 @@ object Signatures {
4849
*/
4950
def callInfo(path: List[tpd.Tree], span: Span)(using Context): (Int, Int, List[SingleDenotation]) =
5051
path match {
52+
case UnApply(fun, _, patterns) :: _ =>
53+
callInfo(span, patterns, fun, Signatures.countParams(fun))
5154
case Apply(fun, params) :: _ =>
52-
val alreadyAppliedCount = Signatures.countParams(fun)
53-
val paramIndex = params.indexWhere(_.span.contains(span)) match {
54-
case -1 => (params.length - 1 max 0) + alreadyAppliedCount
55-
case n => n + alreadyAppliedCount
56-
}
57-
58-
val (alternativeIndex, alternatives) = fun.tpe match {
59-
case err: ErrorType =>
60-
val (alternativeIndex, alternatives) = alternativesFromError(err, params)
61-
(alternativeIndex, alternatives)
55+
callInfo(span, params, fun, Signatures.countParams(fun))
56+
case _ =>
57+
(0, 0, Nil)
58+
}
6259

63-
case _ =>
64-
val funSymbol = fun.symbol
65-
val alternatives = funSymbol.owner.info.member(funSymbol.name).alternatives
66-
val alternativeIndex = alternatives.map(_.symbol).indexOf(funSymbol) max 0
67-
(alternativeIndex, alternatives)
68-
}
60+
def callInfo(
61+
span: Span,
62+
params: List[Tree[Type]],
63+
fun: Tree[Type],
64+
alreadyAppliedCount : Int
65+
)(using Context): (Int, Int, List[SingleDenotation]) =
66+
val paramIndex = params.indexWhere(_.span.contains(span)) match {
67+
case -1 => (params.length - 1 max 0) + alreadyAppliedCount
68+
case n => n + alreadyAppliedCount
69+
}
6970

70-
(paramIndex, alternativeIndex, alternatives)
71+
val (alternativeIndex, alternatives) = fun.tpe match {
72+
case err: ErrorType =>
73+
val (alternativeIndex, alternatives) = alternativesFromError(err, params)
74+
(alternativeIndex, alternatives)
7175

7276
case _ =>
73-
(0, 0, Nil)
77+
val funSymbol = fun.symbol
78+
val alternatives = funSymbol.owner.info.member(funSymbol.name).alternatives
79+
val alternativeIndex = alternatives.map(_.symbol).indexOf(funSymbol) max 0
80+
(alternativeIndex, alternatives)
7481
}
7582

83+
(paramIndex, alternativeIndex, alternatives)
84+
7685
def toSignature(denot: SingleDenotation)(using Context): Option[Signature] = {
7786
val symbol = denot.symbol
7887
val docComment = ParsedComment.docOf(symbol)

language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,8 +556,7 @@ class DottyLanguageServer extends LanguageServer
556556

557557
val pos = sourcePosition(driver, uri, params.getPosition)
558558
val trees = driver.openedTrees(uri)
559-
val path = Interactive.pathTo(trees, pos).dropWhile(!_.isInstanceOf[Apply])
560-
559+
val path = Interactive.pathTo(trees, pos).dropWhile(t => !t.isInstanceOf[Apply | UnApply])
561560
val (paramN, callableN, alternatives) = Signatures.callInfo(path, pos.span)
562561
val signatureInfos = alternatives.flatMap(Signatures.toSignature)
563562

language-server/test/dotty/tools/languageserver/SignatureHelpTest.scala

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,4 +361,76 @@ class SignatureHelpTest {
361361
)), Some("Int"), Some("Buzzes a fizz up to bar"))
362362
), None, 0)
363363
}
364+
365+
@Test def unapplyMethod: Unit = {
366+
code"""|object Main {
367+
| Option(1) match {
368+
| case Some(${m1}) =>
369+
| }
370+
|}"""
371+
.withSource
372+
.signatureHelp(m1, List(
373+
S("unapply[A]", Nil, List(List(
374+
P("x$0", "Some[A]", None),
375+
)), Some("Option[A]"), None)
376+
), None, 0)
377+
}
378+
379+
@Test def unapplyMethodImplicits: Unit = {
380+
code"""|
381+
|object Opt:
382+
| def unapply[A](using String)(a: Option[A])(using Int) = a
383+
|
384+
|object Main {
385+
| given String = ""
386+
| given Int = 0
387+
| Option(1) match {
388+
| case Opt(${m1}) =>
389+
| }
390+
|}"""
391+
.withSource
392+
.signatureHelp(m1, List(
393+
S("unapply[A]", Nil, List(
394+
List(
395+
P("x$1", "String", None, isImplicit = true)
396+
),
397+
List(
398+
P("a", "Option[A]", None),
399+
),
400+
List(
401+
P("x$3", "Int", None, isImplicit = true)
402+
)
403+
),
404+
Some("Option[A]"), None)
405+
), None, 1)
406+
}
407+
408+
@Test def unapplyMethodImplicitsMultiple: Unit = {
409+
code"""|
410+
|object Opt:
411+
| def unapply[A](using String)(using Int)(a: Option[A]) = a
412+
|
413+
|object Main {
414+
| given String = ""
415+
| given Int = 0
416+
| Option(1) match {
417+
| case Opt(${m1}) =>
418+
| }
419+
|}"""
420+
.withSource
421+
.signatureHelp(m1, List(
422+
S("unapply[A]", Nil, List(
423+
List(
424+
P("x$1", "String", None, isImplicit = true)
425+
),
426+
List(
427+
P("x$2", "Int", None, isImplicit = true)
428+
),
429+
List(
430+
P("a", "Option[A]", None),
431+
)
432+
),
433+
Some("Option[A]"), None)
434+
), None, 2)
435+
}
364436
}

0 commit comments

Comments
 (0)