Skip to content

Commit 844754f

Browse files
authored
Merge pull request #5927 from dotty-staging/fix/ide-signature-exception
IDE: fix signature help for Java and Scala 2 methods
2 parents 1e74e9d + 37ec52c commit 844754f

File tree

3 files changed

+84
-19
lines changed

3 files changed

+84
-19
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,12 +355,18 @@ class Definitions {
355355
lazy val Predef_undefinedR: TermRef = ScalaPredefModule.requiredMethodRef(nme.???)
356356
def Predef_undefined(implicit ctx: Context): Symbol = Predef_undefinedR.symbol
357357

358-
def SubTypeClass(implicit ctx: Context): Symbol =
358+
def SubTypeClass(implicit ctx: Context): ClassSymbol =
359359
if (isNewCollections)
360360
ctx.requiredClass("scala.<:<")
361361
else
362362
ScalaPredefModule.requiredClass("<:<")
363363

364+
def DummyImplicitClass(implicit ctx: Context): ClassSymbol =
365+
if (isNewCollections)
366+
ctx.requiredClass("scala.DummyImplicit")
367+
else
368+
ScalaPredefModule.requiredClass("DummyImplicit")
369+
364370
lazy val ScalaRuntimeModuleRef: TermRef = ctx.requiredModuleRef("scala.runtime.ScalaRunTime")
365371
def ScalaRuntimeModule(implicit ctx: Context): Symbol = ScalaRuntimeModuleRef.symbol
366372
def ScalaRuntimeClass(implicit ctx: Context): ClassSymbol = ScalaRuntimeModule.moduleClass.asClass

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

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -80,27 +80,36 @@ object Signatures {
8080
val symbol = denot.symbol
8181
val docComment = ParsedComment.docOf(symbol)
8282
val classTree = symbol.topLevelClass.asClass.rootTree
83-
val isImplicit: TermName => Boolean = tpd.defPath(symbol, classTree).lastOption match {
84-
case Some(DefDef(_, _, paramss, _, _)) =>
85-
val flatParams = paramss.flatten
86-
name => flatParams.find(_.name == name).map(_.symbol.is(Implicit)).getOrElse(false)
87-
case _ =>
88-
_ => false
83+
84+
def toParamss(tp: MethodType)(implicit ctx: Context): List[List[Param]] = {
85+
val rest = tp.resType match {
86+
case res: MethodType =>
87+
// Hide parameter lists consisting only of CanBuildFrom or DummyImplicit,
88+
// we can remove the CanBuildFrom special-case once we switch to the 2.13 standard library.
89+
if (res.resultType.isParameterless &&
90+
res.isImplicitMethod &&
91+
res.paramInfos.forall(info =>
92+
info.classSymbol.fullName.toString == "scala.collection.generic.CanBuildFrom" ||
93+
info.classSymbol.derivesFrom(ctx.definitions.DummyImplicitClass)))
94+
Nil
95+
else
96+
toParamss(res)
97+
case _ =>
98+
Nil
99+
}
100+
val params = tp.paramNames.zip(tp.paramInfos).map { case (name, info) =>
101+
Signatures.Param(name.show,
102+
info.widenTermRefExpr.show,
103+
docComment.flatMap(_.paramDoc(name)),
104+
isImplicit = tp.isImplicitMethod)
105+
}
106+
107+
params :: rest
89108
}
90109

91110
denot.info.stripPoly match {
92111
case tpe: MethodType =>
93-
val infos = {
94-
tpe.paramInfoss.zip(tpe.paramNamess).map { case (infos, names) =>
95-
infos.zip(names).map { case (info, name) =>
96-
Signatures.Param(name.show,
97-
info.widenTermRefExpr.show,
98-
docComment.flatMap(_.paramDoc(name)),
99-
isImplicit = isImplicit(name))
100-
}
101-
}
102-
}
103-
112+
val paramss = toParamss(tpe)
104113
val typeParams = denot.info match {
105114
case poly: PolyType =>
106115
poly.paramNames.zip(poly.paramInfos).map { case (x, y) => x.show + y.show }
@@ -115,7 +124,7 @@ object Signatures {
115124
val signature =
116125
Signatures.Signature(name,
117126
typeParams,
118-
infos,
127+
paramss,
119128
returnType,
120129
docComment.map(_.mainDoc))
121130

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,56 @@ import dotty.tools.dotc.util.Signatures.{Param => P, Signature => S}
88

99
class SignatureHelpTest {
1010

11+
@Test def fromJava: Unit = {
12+
val signature =
13+
S("codePointAt", Nil, List(List(P("x$0", "Int"))), Some("Int"))
14+
code"""object O {
15+
"hello".codePointAt($m1)
16+
}""".withSource
17+
.signatureHelp(m1, List(signature), Some(0), 0)
18+
}
19+
20+
@Test def fromScala2: Unit = {
21+
val applySig =
22+
S("apply[A]", Nil, List(List(P("xs", "A*"))), Some("List[A]"))
23+
val mapSig =
24+
S("map[B, That]", Nil, List(List(P("f", "A => B"))), Some("That"))
25+
code"""object O {
26+
List($m1)
27+
List(1, 2, 3).map($m2)
28+
}""".withSource
29+
.signatureHelp(m1, List(applySig), Some(0), 0)
30+
.signatureHelp(m2, List(mapSig), Some(0), 0)
31+
}
32+
33+
/** Implicit parameter lists consisting solely of DummyImplicits are hidden. */
34+
@Test def hiddenDummyParams: Unit = {
35+
val foo1Sig =
36+
S("foo1", Nil, List(List(P("param0", "Int"))), Some("Int"))
37+
val foo2Sig =
38+
S("foo2", Nil, List(List(P("param0", "Int"))), Some("Int"))
39+
val foo3Sig =
40+
S("foo3", Nil, List(List(P("param0", "Int")),
41+
List(P("dummy", "DummyImplicit"))), Some("Int"))
42+
val foo4Sig =
43+
S("foo4", Nil, List(List(P("param0", "Int")),
44+
List(P("x", "Int", isImplicit = true), P("dummy", "DummyImplicit", isImplicit = true))), Some("Int"))
45+
code"""object O {
46+
def foo1(param0: Int)(implicit dummy: DummyImplicit): Int = ???
47+
def foo2(param0: Int)(implicit dummy1: DummyImplicit, dummy2: DummyImplicit): Int = ???
48+
def foo3(param0: Int)(dummy: DummyImplicit): Int = ???
49+
def foo4(param0: Int)(implicit x: Int, dummy: DummyImplicit): Int = ???
50+
foo1($m1)
51+
foo2($m2)
52+
foo3($m3)
53+
foo4($m4)
54+
}""".withSource
55+
.signatureHelp(m1, List(foo1Sig), Some(0), 0)
56+
.signatureHelp(m2, List(foo2Sig), Some(0), 0)
57+
.signatureHelp(m3, List(foo3Sig), Some(0), 0)
58+
.signatureHelp(m4, List(foo4Sig), Some(0), 0)
59+
}
60+
1161
@Test def singleParam: Unit = {
1262
val signature =
1363
S("foo", Nil, List(List(P("param0", "Int"))), Some("Int"))

0 commit comments

Comments
 (0)