diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index d3b9b655b65f..ff380a4b534d 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -355,12 +355,18 @@ class Definitions { lazy val Predef_undefinedR: TermRef = ScalaPredefModule.requiredMethodRef(nme.???) def Predef_undefined(implicit ctx: Context): Symbol = Predef_undefinedR.symbol - def SubTypeClass(implicit ctx: Context): Symbol = + def SubTypeClass(implicit ctx: Context): ClassSymbol = if (isNewCollections) ctx.requiredClass("scala.<:<") else ScalaPredefModule.requiredClass("<:<") + def DummyImplicitClass(implicit ctx: Context): ClassSymbol = + if (isNewCollections) + ctx.requiredClass("scala.DummyImplicit") + else + ScalaPredefModule.requiredClass("DummyImplicit") + lazy val ScalaRuntimeModuleRef: TermRef = ctx.requiredModuleRef("scala.runtime.ScalaRunTime") def ScalaRuntimeModule(implicit ctx: Context): Symbol = ScalaRuntimeModuleRef.symbol def ScalaRuntimeClass(implicit ctx: Context): ClassSymbol = ScalaRuntimeModule.moduleClass.asClass diff --git a/compiler/src/dotty/tools/dotc/util/Signatures.scala b/compiler/src/dotty/tools/dotc/util/Signatures.scala index 14dcddcb77dd..e782aeb43e84 100644 --- a/compiler/src/dotty/tools/dotc/util/Signatures.scala +++ b/compiler/src/dotty/tools/dotc/util/Signatures.scala @@ -80,27 +80,36 @@ object Signatures { val symbol = denot.symbol val docComment = ParsedComment.docOf(symbol) val classTree = symbol.topLevelClass.asClass.rootTree - val isImplicit: TermName => Boolean = tpd.defPath(symbol, classTree).lastOption match { - case Some(DefDef(_, _, paramss, _, _)) => - val flatParams = paramss.flatten - name => flatParams.find(_.name == name).map(_.symbol.is(Implicit)).getOrElse(false) - case _ => - _ => false + + def toParamss(tp: MethodType)(implicit ctx: Context): List[List[Param]] = { + val rest = tp.resType match { + case res: MethodType => + // Hide parameter lists consisting only of CanBuildFrom or DummyImplicit, + // we can remove the CanBuildFrom special-case once we switch to the 2.13 standard library. + if (res.resultType.isParameterless && + res.isImplicitMethod && + res.paramInfos.forall(info => + info.classSymbol.fullName.toString == "scala.collection.generic.CanBuildFrom" || + info.classSymbol.derivesFrom(ctx.definitions.DummyImplicitClass))) + Nil + else + toParamss(res) + case _ => + Nil + } + val params = tp.paramNames.zip(tp.paramInfos).map { case (name, info) => + Signatures.Param(name.show, + info.widenTermRefExpr.show, + docComment.flatMap(_.paramDoc(name)), + isImplicit = tp.isImplicitMethod) + } + + params :: rest } denot.info.stripPoly match { case tpe: MethodType => - val infos = { - tpe.paramInfoss.zip(tpe.paramNamess).map { case (infos, names) => - infos.zip(names).map { case (info, name) => - Signatures.Param(name.show, - info.widenTermRefExpr.show, - docComment.flatMap(_.paramDoc(name)), - isImplicit = isImplicit(name)) - } - } - } - + val paramss = toParamss(tpe) val typeParams = denot.info match { case poly: PolyType => poly.paramNames.zip(poly.paramInfos).map { case (x, y) => x.show + y.show } @@ -115,7 +124,7 @@ object Signatures { val signature = Signatures.Signature(name, typeParams, - infos, + paramss, returnType, docComment.map(_.mainDoc)) diff --git a/language-server/test/dotty/tools/languageserver/SignatureHelpTest.scala b/language-server/test/dotty/tools/languageserver/SignatureHelpTest.scala index aa90ce570d51..68fc0ebcefec 100644 --- a/language-server/test/dotty/tools/languageserver/SignatureHelpTest.scala +++ b/language-server/test/dotty/tools/languageserver/SignatureHelpTest.scala @@ -8,6 +8,56 @@ import dotty.tools.dotc.util.Signatures.{Param => P, Signature => S} class SignatureHelpTest { + @Test def fromJava: Unit = { + val signature = + S("codePointAt", Nil, List(List(P("x$0", "Int"))), Some("Int")) + code"""object O { + "hello".codePointAt($m1) + }""".withSource + .signatureHelp(m1, List(signature), Some(0), 0) + } + + @Test def fromScala2: Unit = { + val applySig = + S("apply[A]", Nil, List(List(P("xs", "A*"))), Some("List[A]")) + val mapSig = + S("map[B, That]", Nil, List(List(P("f", "A => B"))), Some("That")) + code"""object O { + List($m1) + List(1, 2, 3).map($m2) + }""".withSource + .signatureHelp(m1, List(applySig), Some(0), 0) + .signatureHelp(m2, List(mapSig), Some(0), 0) + } + + /** Implicit parameter lists consisting solely of DummyImplicits are hidden. */ + @Test def hiddenDummyParams: Unit = { + val foo1Sig = + S("foo1", Nil, List(List(P("param0", "Int"))), Some("Int")) + val foo2Sig = + S("foo2", Nil, List(List(P("param0", "Int"))), Some("Int")) + val foo3Sig = + S("foo3", Nil, List(List(P("param0", "Int")), + List(P("dummy", "DummyImplicit"))), Some("Int")) + val foo4Sig = + S("foo4", Nil, List(List(P("param0", "Int")), + List(P("x", "Int", isImplicit = true), P("dummy", "DummyImplicit", isImplicit = true))), Some("Int")) + code"""object O { + def foo1(param0: Int)(implicit dummy: DummyImplicit): Int = ??? + def foo2(param0: Int)(implicit dummy1: DummyImplicit, dummy2: DummyImplicit): Int = ??? + def foo3(param0: Int)(dummy: DummyImplicit): Int = ??? + def foo4(param0: Int)(implicit x: Int, dummy: DummyImplicit): Int = ??? + foo1($m1) + foo2($m2) + foo3($m3) + foo4($m4) + }""".withSource + .signatureHelp(m1, List(foo1Sig), Some(0), 0) + .signatureHelp(m2, List(foo2Sig), Some(0), 0) + .signatureHelp(m3, List(foo3Sig), Some(0), 0) + .signatureHelp(m4, List(foo4Sig), Some(0), 0) + } + @Test def singleParam: Unit = { val signature = S("foo", Nil, List(List(P("param0", "Int"))), Some("Int"))