diff --git a/mtags/src/main/scala-3/scala/meta/internal/pc/PcInlayHintsProvider.scala b/mtags/src/main/scala-3/scala/meta/internal/pc/PcInlayHintsProvider.scala index 818745746cf..958591ccc75 100644 --- a/mtags/src/main/scala-3/scala/meta/internal/pc/PcInlayHintsProvider.scala +++ b/mtags/src/main/scala-3/scala/meta/internal/pc/PcInlayHintsProvider.scala @@ -23,7 +23,6 @@ import dotty.tools.dotc.util.SourcePosition import dotty.tools.dotc.util.Spans.Span import org.eclipse.lsp4j.InlayHint import org.eclipse.lsp4j.InlayHintKind -import org.eclipse.{lsp4j as l} class PcInlayHintsProvider( driver: InteractiveDriver, @@ -77,7 +76,7 @@ class PcInlayHintsProvider( if params.implicitParameters() => val labelParts = symbols.map(s => List(labelPart(s, s.decodedName))) val label = - if allImplicit then labelParts.separated("(", ", ", ")") + if allImplicit then labelParts.separated("(using ", ", ", ")") else labelParts.separated(", ") inlayHints.add( adjustPos(pos).toLsp, @@ -215,7 +214,10 @@ object ImplicitParameters: case Apply(fun, args) if args.exists(isSyntheticArg) && !tree.sourcePos.span.isZeroExtent => val (implicitArgs, providedArgs) = args.partition(isSyntheticArg) - val allImplicit = providedArgs.isEmpty + val allImplicit = providedArgs.isEmpty || providedArgs.forall { + case Ident(name) => name == nme.MISSING + case _ => false + } val pos = implicitArgs.head.sourcePos Some(implicitArgs.map(_.symbol), pos, allImplicit) case _ => None diff --git a/tests/cross/src/test/scala/tests/pc/InlayHintsSuite.scala b/tests/cross/src/test/scala/tests/pc/InlayHintsSuite.scala index 6b3949e6d10..7118bcff537 100644 --- a/tests/cross/src/test/scala/tests/pc/InlayHintsSuite.scala +++ b/tests/cross/src/test/scala/tests/pc/InlayHintsSuite.scala @@ -9,7 +9,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { ) check( - "local", + "local".tag(IgnoreForScala3CompilerPC), """|object Main { | def foo() = { | implicit val imp: Int = 2 @@ -25,7 +25,18 @@ class InlayHintsSuite extends BaseInlayHintsSuite { | val x/*: Int<>*/ = addOne(1)/*(imp<<(3:17)>>)*/ | } |} - |""".stripMargin + |""".stripMargin, + compat = Map( + "3" -> + """|object Main { + | def foo()/*: Unit<>*/ = { + | implicit val imp: Int = 2 + | def addOne(x: Int)(implicit one: Int)/*: Int<>*/ = x + one + | val x/*: Int<>*/ = addOne(1)/*(using imp<<(3:17)>>)*/ + | } + |} + |""".stripMargin + ) ) check( @@ -65,7 +76,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { ) check( - "implicit-param", + "implicit-param".tag(IgnoreForScala3CompilerPC), """|case class User(name: String) |object Main { | implicit val imp: Int = 2 @@ -79,7 +90,17 @@ class InlayHintsSuite extends BaseInlayHintsSuite { | def addOne(x: Int)(implicit one: Int)/*: Int<>*/ = x + one | val x/*: Int<>*/ = addOne(1)/*(imp<<(3:15)>>)*/ |} - |""".stripMargin + |""".stripMargin, + compat = Map( + "3" -> + """|case class User(name: String) + |object Main { + | implicit val imp: Int = 2 + | def addOne(x: Int)(implicit one: Int)/*: Int<>*/ = x + one + | val x/*: Int<>*/ = addOne(1)/*(using imp<<(3:15)>>)*/ + |} + |""".stripMargin + ) ) check( @@ -99,7 +120,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { ) check( - "using-param".tag(IgnoreScala2), + "using-param".tag(IgnoreScala2.and(IgnoreForScala3CompilerPC)), """|case class User(name: String) |object Main { | implicit val imp: Int = 2 @@ -111,7 +132,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |object Main { | implicit val imp: Int = 2 | def addOne(x: Int)(using one: Int)/*: Int<>*/ = x + one - | val x/*: Int<>*/ = addOne(1)/*(imp<<(3:15)>>)*/ + | val x/*: Int<>*/ = addOne(1)/*(using imp<<(3:15)>>)*/ |} |""".stripMargin ) @@ -545,7 +566,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { ) check( - "ord", + "ord".tag(IgnoreForScala3CompilerPC), """|object Main { | val ordered = "acb".sorted |} @@ -553,7 +574,14 @@ class InlayHintsSuite extends BaseInlayHintsSuite { """|object Main { | val ordered/*: String<>*/ = /*augmentString<>(*/"acb"/*)*/.sorted/*[Char<>]*//*(Char<>)*/ |} - |""".stripMargin + |""".stripMargin, + compat = Map( + "3" -> + """|object Main { + | val ordered/*: String<>*/ = /*augmentString<>(*/"acb"/*)*/.sorted/*[Char<>]*//*(using Char<>)*/ + |} + |""".stripMargin + ) ) check( @@ -599,7 +627,9 @@ class InlayHintsSuite extends BaseInlayHintsSuite { ) check( - "complex".tag(IgnoreScalaVersion.forLessThan("2.12.16")), + "complex".tag( + IgnoreScalaVersion.forLessThan("2.12.16").and(IgnoreForScala3CompilerPC) + ), """|object ScalatestMock { | class SRF | implicit val subjectRegistrationFunction: SRF = new SRF() @@ -673,7 +703,47 @@ class InlayHintsSuite extends BaseInlayHintsSuite { | def checkThing1[A](implicit ev: Eq[A])/*: Nothing<>*/ = ??? | def checkThing2[A](implicit ev: Eq[A], sem: Semigroup[A])/*: Nothing<>*/ = ??? |} - |""".stripMargin + |""".stripMargin, + compat = Map( + "3" -> + """|object ScalatestMock { + | class SRF + | implicit val subjectRegistrationFunction: SRF = new SRF() + | class Position + | implicit val here: Position = new Position() + | implicit class StringTestOps(name: String) { + | def should(right: => Unit)(implicit config: SRF): Unit = () + | def in(f: => Unit)(implicit pos: Position): Unit = () + | } + | implicit def instancesString: Eq[String] with Semigroup[String] = ??? + |} + | + |trait Eq[A] + |trait Semigroup[A] + | + |class DemoSpec { + | import ScalatestMock._ + | + | /*StringTestOps<<(6:17)>>(*/"foo"/*)*/ should { + | /*StringTestOps<<(6:17)>>(*/"checkThing1"/*)*/ in { + | checkThing1[String]/*(using instancesString<<(10:15)>>)*/ + | }/*(using here<<(5:15)>>)*/ + | /*StringTestOps<<(6:17)>>(*/"checkThing2"/*)*/ in { + | checkThing2[String]/*(using instancesString<<(10:15)>>, instancesString<<(10:15)>>)*/ + | }/*(using here<<(5:15)>>)*/ + | }/*(using subjectRegistrationFunction<<(3:15)>>)*/ + | + | /*StringTestOps<<(6:17)>>(*/"bar"/*)*/ should { + | /*StringTestOps<<(6:17)>>(*/"checkThing1"/*)*/ in { + | checkThing1[String]/*(using instancesString<<(10:15)>>)*/ + | }/*(using here<<(5:15)>>)*/ + | }/*(using subjectRegistrationFunction<<(3:15)>>)*/ + | + | def checkThing1[A](implicit ev: Eq[A])/*: Nothing<>*/ = ??? + | def checkThing2[A](implicit ev: Eq[A], sem: Semigroup[A])/*: Nothing<>*/ = ??? + |} + |""".stripMargin + ) ) check( @@ -744,4 +814,123 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |case class ErrorMessage(error) |""".stripMargin ) + + // NOTE: We don't show inlayHints for anonymous given instances + check( + "anonymous-given".tag(IgnoreScala2.and(IgnoreForScala3CompilerPC)), + """|package example + | + |trait Ord[T]: + | def compare(x: T, y: T): Int + | + |given intOrd: Ord[Int] with + | def compare(x: Int, y: Int) = + | if x < y then -1 else if x > y then +1 else 0 + | + |given Ord[String] with + | def compare(x: String, y: String) = + | x.compare(y) + | + |""".stripMargin, + """|package example + | + |trait Ord[T]: + | def compare(x: T, y: T): Int + | + |given intOrd: Ord[Int] with + | def compare(x: Int, y: Int)/*: Int<>*/ = + | if x < y then -1 else if x > y then +1 else 0 + | + |given Ord[String] with + | def compare(x: String, y: String)/*: Int<>*/ = + | /*augmentString<>(*/x/*)*/.compare(y) + | + |""".stripMargin + ) + + // TODO: Add a separate option for hints for context bounds + check( + "context-bounds1".tag(IgnoreScala2.and(IgnoreForScala3CompilerPC)), + """|package example + |object O { + | given Int = 1 + | def test[T: Ordering](x: T)(using Int) = ??? + | test(1) + |} + |""".stripMargin, + """|package example + |object O { + | given Int = 1 + | def test[T: Ordering](x: T)(using Int)/*: Nothing<>*/ = ??? + | test/*[Int<>]*/(1)/*(using Int<>, given_Int<<(2:8)>>)*/ + |} + |""".stripMargin + ) + + check( + "context-bounds2".tag(IgnoreForScala3CompilerPC), + """|package example + |object O { + | def test[T: Ordering](x: T) = ??? + | test(1) + |} + |""".stripMargin, + """|package example + |object O { + | def test[T: Ordering](x: T)/*: Nothing<>*/ = ??? + | test/*[Int<>]*/(1)/*(Int<>)*/ + |} + |""".stripMargin, + compat = Map( + "3" -> """|package example + |object O { + | def test[T: Ordering](x: T)/*: Nothing<>*/ = ??? + | test/*[Int<>]*/(1)/*(using Int<>)*/ + |} + |""".stripMargin + ) + ) + + check( + "context-bounds3".tag(IgnoreScala2.and(IgnoreForScala3CompilerPC)), + """|package example + |object O { + | def test[T: Ordering](x: T)(using Int) = ??? + | test(1) + |} + |""".stripMargin, + """|package example + |object O { + | def test[T: Ordering](x: T)(using Int)/*: Nothing<>*/ = ??? + | test/*[Int<>]*/(1)/*(using Int<>)*/ + |} + |""".stripMargin + ) + + check( + "context-bounds4".tag(IgnoreForScala3CompilerPC), + """|package example + |object O { + | implicit val i: Int = 123 + | def test[T: Ordering](x: T)(implicit v: Int) = ??? + | test(1) + |} + |""".stripMargin, + """|package example + |object O { + | implicit val i: Int = 123 + | def test[T: Ordering](x: T)(implicit v: Int)/*: Nothing<>*/ = ??? + | test/*[Int<>]*/(1)/*(Int<>, i<<(2:15)>>)*/ + |} + |""".stripMargin, + compat = Map( + "3" -> """|package example + |object O { + | implicit val i: Int = 123 + | def test[T: Ordering](x: T)(implicit v: Int)/*: Nothing<>*/ = ??? + | test/*[Int<>]*/(1)/*(using Int<>, i<<(2:15)>>)*/ + |} + |""".stripMargin + ) + ) } diff --git a/tests/unit/src/test/resources/expect/toplevels-scala3.expect b/tests/unit/src/test/resources/expect/toplevels-scala3.expect index eec168dc759..10b24a39e44 100644 --- a/tests/unit/src/test/resources/expect/toplevels-scala3.expect +++ b/tests/unit/src/test/resources/expect/toplevels-scala3.expect @@ -57,4 +57,4 @@ example/nested/LocalClass.scala -> example/nested/LocalClass# example/nested/package.scala -> example/PackageObjectSibling# example/nested/package.scala -> example/nested/package. example/package.scala -> example/package. -example/type/Backtick.scala -> example/type/Backtick# +example/type/Backtick.scala -> example/type/Backtick# \ No newline at end of file diff --git a/tests/unit/src/test/resources/inlayHints3/example/GivenAlias.scala b/tests/unit/src/test/resources/inlayHints3/example/GivenAlias.scala index 693c4e2af29..14fcb47465a 100644 --- a/tests/unit/src/test/resources/inlayHints3/example/GivenAlias.scala +++ b/tests/unit/src/test/resources/inlayHints3/example/GivenAlias.scala @@ -43,5 +43,5 @@ val f/*: Float<>*/ = given_Float val g/*: Long<>*/ = `* *` val i/*: Option<>[Int<>]*/ = X.of[Int] val x/*: given_Xg<<(27:6)>>.type*/ = given_Xg -val y/*: given_Yg<<(30:6)>>*/ = given_Yg/*(given_Xg<<(27:0)>>)*/ +val y/*: given_Yg<<(30:6)>>*/ = given_Yg/*(using given_Xg<<(27:0)>>)*/ val z/*: given_Zg_T<<(33:6)>>[String<>]*/ = given_Zg_T[String] \ No newline at end of file diff --git a/tests/unit/src/test/resources/inlayHints3/example/dotted.filename.scala b/tests/unit/src/test/resources/inlayHints3/example/dotted.filename.scala index 876bde134d4..a9d2a7fb4a0 100644 --- a/tests/unit/src/test/resources/inlayHints3/example/dotted.filename.scala +++ b/tests/unit/src/test/resources/inlayHints3/example/dotted.filename.scala @@ -1,3 +1,3 @@ package example -type Toplevel = Int +type Toplevel = Int \ No newline at end of file diff --git a/tests/unit/src/test/resources/semanticTokens3/example/dotted.filename.scala b/tests/unit/src/test/resources/semanticTokens3/example/dotted.filename.scala index b704249be2a..ab449098dcc 100644 --- a/tests/unit/src/test/resources/semanticTokens3/example/dotted.filename.scala +++ b/tests/unit/src/test/resources/semanticTokens3/example/dotted.filename.scala @@ -1,3 +1,3 @@ <>/*keyword*/ <>/*namespace*/ -<>/*keyword*/ <>/*type,definition*/ = <>/*class,abstract*/ +<>/*keyword*/ <>/*type,definition*/ = <>/*class,abstract*/ \ No newline at end of file