From 0560fa445dbeb301ea5a35c3798c87d729ffa0c2 Mon Sep 17 00:00:00 2001 From: Tomasz Godzik Date: Wed, 2 Jun 2021 19:52:13 +0200 Subject: [PATCH] Add support for Scala 3.0.1-RC1 This also includes a bunch of fixes that were kind of a chain reaction due to some tests failing for 3.0.1-RC1 - print outer type instead of singleton type for objects - make sure to take method signature into account when filtering or sorting symbols --- build.sbt | 3 +- .../meta/internal/pc/CompletionProvider.scala | 39 ++++- .../pc/ScalaPresentationCompiler.scala | 58 +++---- .../meta/internal/pc/SymbolPrinter.scala | 16 +- .../scala/tests/hover/HoverDefnSuite.scala | 2 +- .../tests/hover/HoverScala3TypeSuite.scala | 2 +- .../scala/tests/hover/HoverTermSuite.scala | 12 +- .../test/scala/tests/pc/CompletionSuite.scala | 148 ++++++++++++++---- .../scala/tests/BaseCompletionLspSuite.scala | 2 +- 9 files changed, 202 insertions(+), 80 deletions(-) diff --git a/build.sbt b/build.sbt index 431bf27e490..35b484c146c 100644 --- a/build.sbt +++ b/build.sbt @@ -198,6 +198,7 @@ lazy val V = new { val bsp = "2.0.0-M13" val bloop = "1.4.8-19-4d9f966b" val scala3 = "3.0.0" + val nextScala3RC = "3.0.1-RC1" val bloopNightly = bloop val sbtBloop = bloop val gradleBloop = bloop @@ -239,7 +240,7 @@ lazy val V = new { // Scala 3 def scala3RCVersions = Seq("3.0.0-RC3", "3.0.0-RC2", "3.0.0-RC1") def nonDeprecatedScala3Versions = - scala3 +: scala3RCVersions + scala3 +: scala3RCVersions :+ nextScala3RC def deprecatedScala3Versions = Seq() def scala3Versions = nonDeprecatedScala3Versions ++ deprecatedScala3Versions diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/CompletionProvider.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/CompletionProvider.scala index b33e73280f0..96ef33fad7d 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/CompletionProvider.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/CompletionProvider.scala @@ -34,13 +34,13 @@ class CompletionProvider( def completions(): (List[CompletionValue], SymbolSearch.Result) = { val (_, compilerCompletions) = Completion.completions(pos) - val (completions, result) = - compilerCompletions.map(CompletionValue.Compiler(_)).filterInteresting() + val completions = compilerCompletions.map(CompletionValue.Compiler(_)) val args = Completions.namedArgCompletions(pos, path) - val values = - (completions ++ args).sorted(completionOrdering) - (values, result) + val (values, result) = + (completions ::: args).filterInteresting() + + (values.sorted(completionOrdering), result) } private def description(sym: Symbol): String = { @@ -89,13 +89,34 @@ class CompletionProvider( s.sourcePos.exists && s1.sourcePos.exists && s.sourcePos.point > s1.sourcePos.point } + extension (sym: Symbol) { + def detailString: String = { + if (sym.is(Method)) { + val sig = sym.signature + val sigString = + if (sig.paramsSig.isEmpty) "()" + else + sig.paramsSig + .map(p => p.toString) + .mkString("(", ",", ")") + sym.showFullName + sigString + } else { + sym.showFullName + } + } + } extension (l: List[CompletionValue]) { def filterInteresting(): (List[CompletionValue], SymbolSearch.Result) = { val isSeen = mutable.Set.empty[String] val buf = List.newBuilder[CompletionValue] def visit(head: CompletionValue): Boolean = { val sym = head.value.sym - val id = sym.showFullName + val id = head match { + case _: CompletionValue.NamedArg => + sym.detailString + "=" + case _ => + sym.detailString + } def isNotLocalForwardReference: Boolean = !sym.isLocalToBlock || !sym.srcPos.isAfter(pos) || @@ -151,7 +172,9 @@ class CompletionProvider( def hasGetter = try { // isField returns true for some classes - sym.isField || sym.getter != NoSymbol + (sym.isField && !sym.is(JavaDefined) + && !sym.is(Module) && !sym.isClass) || + sym.getter != NoSymbol } catch { case _ => false } @@ -259,7 +282,7 @@ class CompletionProvider( ) if (byParamCount != 0) byParamCount else { - s1.show.compareTo(s2.show) + s1.detailString.compareTo(s2.detailString) } } } diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/ScalaPresentationCompiler.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/ScalaPresentationCompiler.scala index c698ea70354..76d5c66efc0 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/ScalaPresentationCompiler.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/ScalaPresentationCompiler.scala @@ -293,34 +293,33 @@ case class ScalaPresentationCompiler( val sourceFile = CompilerInterfaces.toSource(params.uri, params.text) driver.run(uri, sourceFile) - val ctx = driver.currentCtx + given ctx: Context = driver.currentCtx val pos = sourcePosition(driver, params, uri) val trees = driver.openedTrees(uri) - val path = Interactive.pathTo(trees, pos)(using ctx) - val tp = Interactive.enclosingType(trees, pos)(using ctx) - val tpw = tp.widenTermRefExpr(using ctx) + val path = Interactive.pathTo(trees, pos) + val tp = Interactive.enclosingType(trees, pos) + val tpw = tp.widenTermRefExpr - if (tp.isError(using ctx) || tpw == NoType || tpw.isError(using ctx)) + if (tp.isError || tpw == NoType || tpw.isError) ju.Optional.empty() else { - Interactive.enclosingSourceSymbols(path, pos)(using ctx) match { + Interactive.enclosingSourceSymbols(path, pos) match { case Nil => ju.Optional.empty() case symbols => - val printer = SymbolPrinter()(using ctx) + val printer = SymbolPrinter() val docComments = - symbols.flatMap(ParsedComment.docOf(_)(using ctx)) - val keywordName = symbols.headOption.map { symbol => - printer.fullDefinition( - symbol, - tpw - ) - } - val typeString = symbols.headOption.map { symbol => + symbols.flatMap(ParsedComment.docOf(_)) + val hoverString = symbols.headOption.map { symbol => tpw match { // https://github.com/lampepfl/dotty/issues/8891 - case _: ImportType => - printer.typeString(symbol.paramRef(using ctx)) + case tpw: ImportType => + val history = new ShortenedNames(ctx) + printer.hoverDetails( + symbol, + history, + symbol.paramRef + ) case _ => driver.compilationUnits.get(uri) match { case Some(unit) => @@ -333,16 +332,14 @@ case class ScalaPresentationCompiler( val context = Interactive.contextOfPath(tpdPath)(using newctx) val history = new ShortenedNames(context) - printer.infoString(symbol, history, tpw)(using context) - case None => printer.typeString(tpw) + printer.hoverDetails(symbol, history, tpw)(using context) + case None => + val history = new ShortenedNames(ctx) + printer.hoverDetails(symbol, history, tpw) } } } - val content = hoverContent( - keywordName, - typeString, - docComments - )(using ctx) + val content = hoverContent(hoverString, docComments) ju.Optional.of(new Hover(content)) } } @@ -488,7 +485,12 @@ case class ScalaPresentationCompiler( val printer = SymbolPrinter() s" ${printer.fullNameString(sym.owner)}" } else { - printer.infoString(sym, history, sym.info.widenTermRefExpr)(using ctx) + printer.hoverDetails( + sym, + history, + sym.info.widenTermRefExpr, + addFullDef = false + )(using ctx) } } @@ -554,7 +556,7 @@ case class ScalaPresentationCompiler( val documentation = ParsedComment.docOf(sym) if (documentation.nonEmpty) { - item.setDocumentation(hoverContent(None, None, documentation.toList)) + item.setDocumentation(hoverContent(None, documentation.toList)) } if (sym.isDeprecated) { @@ -629,15 +631,13 @@ case class ScalaPresentationCompiler( } private def hoverContent( - keywordName: Option[String], typeInfo: Option[String], comments: List[ParsedComment] )(using ctx: Context): MarkupContent = { val buf = new StringBuilder typeInfo.foreach { info => - val keyName = keywordName.getOrElse("") buf.append(s"""```scala - |$keyName$info + |$info |``` |""".stripMargin) } diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/SymbolPrinter.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/SymbolPrinter.scala index 62eacce3b56..b95cedd7370 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/SymbolPrinter.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/SymbolPrinter.scala @@ -61,18 +61,24 @@ class SymbolPrinter(using ctx: Context) extends RefinedPrinter(ctx) { * - otherwise: its shortened type * - e.g. ` java.lang.String` ` Symbols.Symbol` */ - def infoString( + def hoverDetails( sym: Symbol, history: ShortenedNames, - info: Type + info: Type, + addFullDef: Boolean = true )(using Context): String = { + val fullDef = if (addFullDef) fullDefinition(sym, info) else "" + // info is dealiased, while sym is not + val typeSymbol = info.typeSymbol sym match { + case p if p.is(Flags.Package) => fullDef + case p if typeSymbol.is(Flags.Module) => + fullDef.trim + " " + typeSymbol.owner.fullName.stripModuleClassSuffix.toString case m if m.is(Flags.Method) => - defaultMethodSignature(sym, history, info) - case p if p.is(Flags.Package) => "" + fullDef + defaultMethodSignature(m, history, info) case _ => val short = shortType(info, history) - s"${typeString(short)}" + fullDef + s"${typeString(short)}" } } diff --git a/tests/cross/src/test/scala/tests/hover/HoverDefnSuite.scala b/tests/cross/src/test/scala/tests/hover/HoverDefnSuite.scala index 9b10abba731..886ee210d7f 100644 --- a/tests/cross/src/test/scala/tests/hover/HoverDefnSuite.scala +++ b/tests/cross/src/test/scala/tests/hover/HoverDefnSuite.scala @@ -147,7 +147,7 @@ class HoverDefnSuite extends BaseHoverSuite { |""".stripMargin, "", compat = Map( - "3.0" -> "object MyObject: MyObject".hover + "3.0" -> "object MyObject: object".hover ) ) diff --git a/tests/cross/src/test/scala/tests/hover/HoverScala3TypeSuite.scala b/tests/cross/src/test/scala/tests/hover/HoverScala3TypeSuite.scala index 43e351c38e8..e8e0de5e9ad 100644 --- a/tests/cross/src/test/scala/tests/hover/HoverScala3TypeSuite.scala +++ b/tests/cross/src/test/scala/tests/hover/HoverScala3TypeSuite.scala @@ -52,7 +52,7 @@ class HoverScala3TypeSuite extends BaseHoverSuite { | case <>, Green, Blue | |""".stripMargin, - """|case Red: enums.SimpleEnum.Color.Red + """|case Red: Red |""".stripMargin.hover ) diff --git a/tests/cross/src/test/scala/tests/hover/HoverTermSuite.scala b/tests/cross/src/test/scala/tests/hover/HoverTermSuite.scala index 739ed964a61..a5c3740e513 100644 --- a/tests/cross/src/test/scala/tests/hover/HoverTermSuite.scala +++ b/tests/cross/src/test/scala/tests/hover/HoverTermSuite.scala @@ -56,7 +56,7 @@ class HoverTermSuite extends BaseHoverSuite { """|def apply(name: String): Person |""".stripMargin.hover, compat = Map( - "3.0" -> "case class Person: Person".hover + "3.0" -> "case class Person: case-apply".hover ) ) @@ -147,7 +147,7 @@ class HoverTermSuite extends BaseHoverSuite { |""".stripMargin.hover, compat = Map( // https://github.com/lampepfl/dotty/issues/8835 - "3.0" -> "object num: Xtension#num".hover + "3.0" -> "object num: interpolator-unapply.a$.Xtension".hover ) ) @@ -335,7 +335,7 @@ class HoverTermSuite extends BaseHoverSuite { |``` |""".stripMargin, compat = Map( - "3.0" -> "enum FileVisitResult: FileVisitResult".hover + "3.0" -> "enum FileVisitResult: java.nio.file".hover ) ) @@ -358,7 +358,7 @@ class HoverTermSuite extends BaseHoverSuite { |""".stripMargin, automaticPackage = false, compat = Map( - "3.0" -> "object Foo: Foo".hover + "3.0" -> "object Foo: app.Outer".hover ) ) @@ -403,7 +403,7 @@ class HoverTermSuite extends BaseHoverSuite { """|class java.nio.file.Files |""".stripMargin.hover, compat = Map( - "3.0" -> "object Files: java.nio.file.Files".hover + "3.0" -> "object Files: java.nio.file".hover ) ) @@ -415,7 +415,7 @@ class HoverTermSuite extends BaseHoverSuite { """|class java.nio.file.Paths |""".stripMargin.hover, compat = Map( - "3.0" -> "object Paths: java.nio.file.Paths".hover + "3.0" -> "object Paths: java.nio.file".hover ) ) diff --git a/tests/cross/src/test/scala/tests/pc/CompletionSuite.scala b/tests/cross/src/test/scala/tests/pc/CompletionSuite.scala index a447f0fbd8a..02858f5adc2 100644 --- a/tests/cross/src/test/scala/tests/pc/CompletionSuite.scala +++ b/tests/cross/src/test/scala/tests/pc/CompletionSuite.scala @@ -28,7 +28,7 @@ class CompletionSuite extends BaseCompletionSuite { |JList - javax.swing |""".stripMargin, "3.0" -> - """|List: collection.immutable.List.type + """|List scala.collection.immutable |List - java.awt |List - java.util |List - scala.collection.immutable @@ -127,8 +127,10 @@ class CompletionSuite extends BaseCompletionSuite { ) check( - // @tgodzik different results might be returned on each run for Scala 3 - "dot".tag(IgnoreScala3), + // before 3.0.1 completions with the same name were included in one completion in a random order + "dot".tag( + IgnoreScalaVersion(Set("3.0.0-RC1", "3.0.0-RC2", "3.0.0-RC3", "3.0.0")) + ), """ |object A { | List.@@ @@ -234,6 +236,50 @@ class CompletionSuite extends BaseCompletionSuite { |isInstanceOf[T0]: Boolean |synchronized[T0](x$1: T0): T0 |toString(): String + |""".stripMargin, + "3.0" -> + """|->[B](y: B): (A, B) + |apply[A](elems: A*): CC[A] + |concat[A](xss: Iterable[A]*): CC[A] + |empty[A]: List[A] + |ensuring(cond: Boolean): A + |ensuring(cond: Boolean, msg: => Any): A + |ensuring(cond: A => Boolean): A + |ensuring(cond: A => Boolean, msg: => Any): A + |fill[A](n1: Int, n2: Int)(elem: => A): CC[CC[A] @uncheckedVariance] + |fill[A](n1: Int, n2: Int, n3: Int)(elem: => A): CC[CC[CC[A]] @uncheckedVariance] + |fill[A](n1: Int, n2: Int, n3: Int, n4: Int)(elem: => A): CC[CC[CC[CC[A]]] @uncheckedVariance] + |fill[A](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(elem: => A): CC[CC[CC[CC[CC[A]]]] @uncheckedVariance] + |fill[A](n: Int)(elem: => A): CC[A] + |formatted(fmtstr: String): String + |from[B](coll: IterableOnce[B]): List[B] + |fromSpecific(from: From)(it: IterableOnce[A]): C + |fromSpecific(it: IterableOnce[A]): C + |iterate[A](start: A, len: Int)(f: A => A): CC[A] + |newBuilder[A]: Builder[A, List[A]] + |nn[T](x: T | Null): x.type & T + |range[A: Integral](start: A, end: A, step: A): CC[A] + |range[A: Integral](start: A, end: A): CC[A] + |tabulate[A](n1: Int, n2: Int)(f: (Int, Int) => A): CC[CC[A] @uncheckedVariance] + |tabulate[A](n1: Int, n2: Int, n3: Int)(f: (Int, Int, Int) => A): CC[CC[CC[A]] @uncheckedVariance] + |tabulate[A](n1: Int, n2: Int, n3: Int, n4: Int)(f: (Int, Int, Int, Int) => A): CC[CC[CC[CC[A]]] @uncheckedVariance] + |tabulate[A](n1: Int, n2: Int, n3: Int, n4: Int, n5: Int)(f: (Int, Int, Int, Int, Int) => A): CC[CC[CC[CC[CC[A]]]] @uncheckedVariance] + |tabulate[A](n: Int)(f: Int => A): CC[A] + |toFactory(from: From): Factory[A, C] + |unapplySeq[A](x: CC[A] @uncheckedVariance): UnapplySeqWrapper[A] + |unfold[A, S](init: S)(f: S => Option[(A, S)]): CC[A] + |→[B](y: B): (A, B) + |iterableFactory[A]: Factory[A, CC[A]] + |asInstanceOf[X0]: X0 + |equals(x$0: Any): Boolean + |getClass[X0 >: (Any.this : Any)]: Class[? <: X0] + |hashCode: Int + |isInstanceOf[X0]: Boolean + |synchronized[X0](x$0: X0): X0 + |toString: String + |wait: Unit + |wait(x$0: Long): Unit + |wait(x$0: Long, x$1: Int): Unit |""".stripMargin ) ) @@ -320,7 +366,7 @@ class CompletionSuite extends BaseCompletionSuite { ) check( - "import".tag(IgnoreScalaVersion(BuildInfoVersions.scala3Versions)), + "import", """ |import JavaCon@@ |""".stripMargin, @@ -344,7 +390,18 @@ class CompletionSuite extends BaseCompletionSuite { "2.11" -> """|JavaConverters - scala.collection |JavaConversions - scala.collection |JavaConversions - scala.concurrent - |""".stripMargin + |""".stripMargin, + "3" -> """|AsJavaConverters - scala.collection.convert + |JavaConverters - scala.collection + |JavaConversions - scala.concurrent + |AsJavaConsumer - scala.jdk.FunctionWrappers + |FromJavaConsumer - scala.jdk.FunctionWrappers + |AsJavaBiConsumer - scala.jdk.FunctionWrappers + |AsJavaIntConsumer - scala.jdk.FunctionWrappers + |AsJavaLongConsumer - scala.jdk.FunctionWrappers + |FromJavaBiConsumer - scala.jdk.FunctionWrappers + |FromJavaIntConsumer - scala.jdk.FunctionWrappers + |""".stripMargin ) ) @@ -528,7 +585,7 @@ class CompletionSuite extends BaseCompletionSuite { // Scala 2.13.5 adds additional completions that actually fit, but are not useful for this test topLines = Some(25), compat = Map( - "3" -> + "3.0.0" -> """|Function scala |Function0 scala |Function1 scala @@ -554,6 +611,32 @@ class CompletionSuite extends BaseCompletionSuite { |Function20 scala |Function21 scala |Function22 scala + |""".stripMargin, + "3" -> + """|Function scala + |Function0 scala + |Function1 scala + |Function2 scala + |Function3 scala + |Function4 scala + |Function5 scala + |Function6 scala + |Function7 scala + |Function8 scala + |Function9 scala + |Function10 scala + |Function11 scala + |Function12 scala + |Function13 scala + |Function14 scala + |Function15 scala + |Function16 scala + |Function17 scala + |Function18 scala + |Function19 scala + |Function20 scala + |Function21 scala + |Function22 scala |""".stripMargin ) ) @@ -870,7 +953,9 @@ class CompletionSuite extends BaseCompletionSuite { "3.0" -> """|Some scala |SomeToExpr[T: Type: ToExpr]: SomeToExpr[T] + |SomeToExpr - scala.quoted.ToExpr |SomeFromExpr[T](using Type[T], FromExpr[T]): SomeFromExpr[T] + |SomeFromExpr - scala.quoted.FromExpr |""".stripMargin ) ) @@ -888,7 +973,9 @@ class CompletionSuite extends BaseCompletionSuite { "3.0" -> """|Some scala |SomeToExpr[T: Type: ToExpr]: SomeToExpr[T] + |SomeToExpr - scala.quoted.ToExpr |SomeFromExpr[T](using Type[T], FromExpr[T]): SomeFromExpr[T] + |SomeFromExpr - scala.quoted.FromExpr |""".stripMargin ) ) @@ -906,8 +993,8 @@ class CompletionSuite extends BaseCompletionSuite { topLines = Some(2), compat = Map( "3.0" -> - """|NoClassDefFoundError java.lang - |NoManifest: reflect.NoManifest.type + """|NoManifest scala.reflect + |NoClassDefFoundError java.lang |""".stripMargin ) ) @@ -930,10 +1017,15 @@ class CompletionSuite extends BaseCompletionSuite { |Seq scala.collection.immutable |Set scala.collection.immutable |""".stripMargin, + "3.0.0-RC1" -> + """|Seq scala.collection.immutable + |Set scala.collection.immutable + |StringBuilder scala.collection.mutable + |""".stripMargin, "3.0" -> - """|SafeVarargs java.lang - |SecurityException java.lang - |SecurityManager java.lang + """|Seq scala.collection.immutable + |Set scala.collection.immutable + |Stream scala.collection.immutable |""".stripMargin ) ) @@ -956,15 +1048,15 @@ class CompletionSuite extends BaseCompletionSuite { |Seq scala.collection.immutable |Set scala.collection.immutable |""".stripMargin, - "3.0.0-RC1" -> - """|SafeVarargs java.lang - |SafeVarargs java.lang - |ScalaReflectionException scala + "3.0.1" -> + """|Seq scala.collection.immutable + |Set scala.collection.immutable + |Stream scala.collection.immutable |""".stripMargin, "3.0" -> - """|String java.lang - |StringIndexOutOfBoundsException java.lang + """|SafeVarargs java.lang |SafeVarargs java.lang + |ScalaReflectionException scala |""".stripMargin ) ) @@ -992,12 +1084,12 @@ class CompletionSuite extends BaseCompletionSuite { "3.0.0-RC1" -> """|NotString: Int |Number: Regex - |NegativeArraySizeException java.lang + |Nil scala.collection.immutable |""".stripMargin, "3.0" -> """|NotString: Int - |NegativeArraySizeException java.lang - |Nil: collection.immutable.Nil.type + |Nil scala.collection.immutable + |NoManifest scala.reflect |""".stripMargin ) ) @@ -1016,10 +1108,10 @@ class CompletionSuite extends BaseCompletionSuite { |""".stripMargin, topLines = Option(3), compat = Map( - "3.0" -> - """|Nil: collection.immutable.Nil.type - |NoManifest: reflect.NoManifest.type - |None scala + "3.0.0" -> + """|Nil scala.collection.immutable + |NoManifest scala.reflect + |NegativeArraySizeException java.lang |""".stripMargin ) ) @@ -1038,10 +1130,10 @@ class CompletionSuite extends BaseCompletionSuite { |""".stripMargin, topLines = Option(3), compat = Map( - "3.0" -> - """|Nil: collection.immutable.Nil.type - |NoManifest: reflect.NoManifest.type - |None scala + "3.0.0" -> + """|Nil scala.collection.immutable + |NoManifest scala.reflect + |NegativeArraySizeException java.lang |""".stripMargin ) ) diff --git a/tests/unit/src/main/scala/tests/BaseCompletionLspSuite.scala b/tests/unit/src/main/scala/tests/BaseCompletionLspSuite.scala index 7b2b6ef4a12..32323274201 100644 --- a/tests/unit/src/main/scala/tests/BaseCompletionLspSuite.scala +++ b/tests/unit/src/main/scala/tests/BaseCompletionLspSuite.scala @@ -145,7 +145,7 @@ abstract class BaseCompletionLspSuite(name: String) extends BaseLspSuite(name) { |PrintStream - java.io |Stream - java.util.stream |Stream - scala.collection.immutable - |Stream: collection.immutable.Stream.type + |Stream scala.collection.immutable |StreamFilter - javax.xml.stream |StreamResult - javax.xml.transform.stream |StreamShape - scala.collection.convert.StreamExtensions