diff --git a/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala b/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala index db92772291b4..0251f06e75ea 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/PcInlayHintsProvider.scala @@ -17,6 +17,8 @@ import scala.meta.pc.SymbolSearch import dotty.tools.dotc.ast.tpd.* import dotty.tools.dotc.core.Contexts.Context import dotty.tools.dotc.core.Flags +import dotty.tools.dotc.core.NameOps.fieldName +import dotty.tools.dotc.core.Names.Name import dotty.tools.dotc.core.StdNames.* import dotty.tools.dotc.core.Symbols.* import dotty.tools.dotc.core.Types.* @@ -116,28 +118,44 @@ class PcInlayHintsProvider( InlayHintKind.Type, ) .addDefinition(adjustedPos.start) - case ByNameParameters(byNameParams) => - def adjustByNameParameterPos(pos: SourcePosition): SourcePosition = - val adjusted = adjustPos(pos) - val start = text.indexWhere(!_.isWhitespace, adjusted.start) - val end = text.lastIndexWhere(!_.isWhitespace, adjusted.end - 1) + case Parameters(isInfixFun, args) => + def isNamedParam(pos: SourcePosition): Boolean = + val start = text.indexWhere(!_.isWhitespace, pos.start) + val end = text.lastIndexWhere(!_.isWhitespace, pos.end - 1) + text.slice(start, end).contains('=') + + def isBlockParam(pos: SourcePosition): Boolean = + val start = text.indexWhere(!_.isWhitespace, pos.start) + val end = text.lastIndexWhere(!_.isWhitespace, pos.end - 1) val startsWithBrace = text.lift(start).contains('{') val endsWithBrace = text.lift(end).contains('}') - if startsWithBrace && endsWithBrace then - adjusted.withStart(start + 1) - else - adjusted - - byNameParams.foldLeft(inlayHints) { - case (ih, pos) => - val adjusted = adjustByNameParameterPos(pos) - ih.add( - adjusted.startPos.toLsp, - List(LabelPart("=> ")), - InlayHintKind.Parameter - ) + startsWithBrace && endsWithBrace + + def adjustBlockParamPos(pos: SourcePosition): SourcePosition = + pos.withStart(pos.start + 1) + + + args.foldLeft(inlayHints) { + case (ih, (name, pos0, isByName)) => + val pos = adjustPos(pos0) + val isBlock = isBlockParam(pos) + val namedLabel = + if params.namedParameters() && !isInfixFun && !isBlock && !isNamedParam(pos) then s"${name} = " else "" + val byNameLabel = + if params.byNameParameters() && isByName && (!isInfixFun || isBlock) then "=> " else "" + + val labelStr = s"${namedLabel}${byNameLabel}" + val hintPos = if isBlock then adjustBlockParamPos(pos) else pos + + if labelStr.nonEmpty then + ih.add( + hintPos.startPos.toLsp, + List(LabelPart(labelStr)), + InlayHintKind.Parameter, + ) + else ih } case _ => inlayHints @@ -412,27 +430,55 @@ object InferredType: end InferredType -object ByNameParameters: - def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context): Option[List[SourcePosition]] = - def shouldSkipSelect(sel: Select) = - isForComprehensionMethod(sel) || sel.symbol.name == nme.unapply +object Parameters: + def unapply(tree: Tree)(using params: InlayHintsParams, ctx: Context): Option[(Boolean, List[(Name, SourcePosition, Boolean)])] = + def shouldSkipFun(fun: Tree)(using Context): Boolean = + fun match + case sel: Select => isForComprehensionMethod(sel) || sel.symbol.name == nme.unapply + case _ => false + + def isInfixFun(fun: Tree, args: List[Tree])(using Context): Boolean = + val isInfixSelect = fun match + case Select(sel, _) => sel.isInfix + case _ => false + val source = fun.source + if args.isEmpty then isInfixSelect + else + (!(fun.span.end until args.head.span.start) + .map(source.apply) + .contains('.') && fun.symbol.is(Flags.ExtensionMethod)) || isInfixSelect + + def isRealApply(tree: Tree) = + !tree.symbol.isOneOf(Flags.GivenOrImplicit) && !tree.span.isZeroExtent + + def getUnderlyingFun(tree: Tree): Tree = + tree match + case Apply(fun, _) => getUnderlyingFun(fun) + case TypeApply(fun, _) => getUnderlyingFun(fun) + case t => t - if (params.byNameParameters()){ + if (params.namedParameters() || params.byNameParameters()) then tree match - case Apply(TypeApply(sel: Select, _), _) if shouldSkipSelect(sel) => - None - case Apply(sel: Select, _) if shouldSkipSelect(sel) => - None - case Apply(fun, args) => - val funTp = fun.typeOpt.widenTermRefExpr - val params = funTp.paramInfoss.flatten - Some( - args - .zip(params) - .collect { - case (tree, param) if param.isByName => tree.sourcePos - } - ) + case Apply(fun, args) if isRealApply(fun) => + val underlyingFun = getUnderlyingFun(fun) + if shouldSkipFun(underlyingFun) then + None + else + val funTp = fun.typeOpt.widenTermRefExpr + val paramNames = funTp.paramNamess.flatten + val paramInfos = funTp.paramInfoss.flatten + Some( + // Check if the function is an infix function or the underlying function is an infix function + isInfixFun(fun, args) || underlyingFun.isInfix, + ( + args + .zip(paramNames) + .zip(paramInfos) + .collect { + case ((arg, paramName), paramInfo) if !arg.span.isZeroExtent => (paramName.fieldName, arg.sourcePos, paramInfo.isByName) + } + ) + ) case _ => None - } else None -end ByNameParameters + else None +end Parameters diff --git a/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala index ca4c0d81af07..845a2582c54b 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/inlayHints/InlayHintsSuite.scala @@ -19,7 +19,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { | 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)>>)*/ + | val x/*: Int<>*/ = addOne(/*x = */1)/*(using imp<<(3:17)>>)*/ | } |} |""".stripMargin @@ -34,7 +34,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |""".stripMargin, """|object Main { | def hello[T](t: T)/*: T<<(2:12)>>*/ = t - | val x/*: List<>[Int<>]*/ = hello/*[List<>[Int<>]]*/(List/*[Int<>]*/(1)) + | val x/*: List<>[Int<>]*/ = hello/*[List<>[Int<>]]*/(/*t = */List/*[Int<>]*/(/*elems = */1)) |} |""".stripMargin ) @@ -48,7 +48,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |""".stripMargin, """|object Main { | def hello[T](t: T)/*: T<<(2:12)>>*/ = t - | val x/*: Map<>[Int<>, String<>]*/ = hello/*[Map<>[Int<>, String<>]]*/(Map/*[Int<>, String<>]*/((1,"abc"))) + | val x/*: Map<>[Int<>, String<>]*/ = hello/*[Map<>[Int<>, String<>]]*/(/*t = */Map/*[Int<>, String<>]*/(/*elems = */(1,"abc"))) |} |""".stripMargin, ) @@ -66,7 +66,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |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)>>)*/ + | val x/*: Int<>*/ = addOne(/*x = */1)/*(using imp<<(3:15)>>)*/ |} |""".stripMargin ) @@ -81,7 +81,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |""".stripMargin, """|case class User(name: String) |object Main { - | implicit def intToUser(x: Int): User = new User(x.toString) + | implicit def intToUser(x: Int): User = new User(/*name = */x.toString) | val y: User = /*intToUser<<(3:15)>>(*/1/*)*/ |} |""".stripMargin @@ -100,7 +100,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)/*(using imp<<(3:15)>>)*/ + | val x/*: Int<>*/ = addOne(/*x = */1)/*(using imp<<(3:15)>>)*/ |} |""".stripMargin ) @@ -115,7 +115,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |""".stripMargin, """|case class User(name: String) |object Main { - | given intToUser: Conversion[Int, User] = User(_.toString) + | given intToUser: Conversion[Int, User] = User(/*name = */_.toString) | val y: User = /*intToUser<<(3:8)>>(*/1/*)*/ |} |""".stripMargin @@ -158,7 +158,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |} |""".stripMargin, """|object Main { - | val foo/*: List<>[Int<>]*/ = List[Int](123) + | val foo/*: List<>[Int<>]*/ = List[Int](/*elems = */123) |} |""".stripMargin ) @@ -170,7 +170,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |} |""".stripMargin, """|object O { - | def m/*: List<>[Int<>]*/ = 1 :: List/*[Int<>]*/(1) + | def m/*: List<>[Int<>]*/ = 1 :: List/*[Int<>]*/(/*elems = */1) |} |""".stripMargin ) @@ -182,7 +182,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |} |""".stripMargin, """|object Main { - | val foo/*: Map<>[Int<>, String<>]*/ = Map/*[Int<>, String<>]*/((1, "abc")) + | val foo/*: Map<>[Int<>, String<>]*/ = Map/*[Int<>, String<>]*/(/*elems = */(1, "abc")) |} |""".stripMargin, ) @@ -206,7 +206,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |} |""".stripMargin, """|object Main { - | val foo/*: Buffer<>[String<>]*/ = List[String]("").toBuffer[String] + | val foo/*: Buffer<>[String<>]*/ = List[String](/*elems = */"").toBuffer[String] |} |""".stripMargin, ) @@ -398,7 +398,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |} |""".stripMargin, """|object Main { - | val x/*: (Int<>, Int<>)*/ = Tuple2.apply/*[Int<>, Int<>]*/(1, 2) + | val x/*: (Int<>, Int<>)*/ = Tuple2.apply/*[Int<>, Int<>]*/(/*_1 = */1, /*_2 = */2) |} |""".stripMargin ) @@ -410,7 +410,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |} |""".stripMargin, """|object Main { - | val x/*: (Int<>, Int<>)*/ = Tuple2/*[Int<>, Int<>]*/(1, 2) + | val x/*: (Int<>, Int<>)*/ = Tuple2/*[Int<>, Int<>]*/(/*_1 = */1, /*_2 = */2) |} |""".stripMargin ) @@ -437,7 +437,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |} |""".stripMargin, """|object Main { - | val hd :: tail = List/*[Int<>]*/(1, 2) + | val hd :: tail = List/*[Int<>]*/(/*elems = */1, 2) |} |""".stripMargin, ) @@ -451,7 +451,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |} |""".stripMargin, """|object Main { - | val x/*: Int<>*/ = List/*[Int<>]*/(1, 2) match { + | val x/*: Int<>*/ = List/*[Int<>]*/(/*elems = */1, 2) match { | case hd :: tail => hd | } |} @@ -467,7 +467,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |""".stripMargin, """|object Main { |case class Foo[A](x: A, y: A) - | val Foo(fst/*: Int<>*/, snd/*: Int<>*/) = Foo/*[Int<>]*/(1, 2) + | val Foo(fst/*: Int<>*/, snd/*: Int<>*/) = Foo/*[Int<>]*/(/*x = */1, /*y = */2) |} |""".stripMargin, hintsInPatternMatch = true @@ -521,7 +521,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |} |""".stripMargin, """|object Main { - | List/*[Int<>]*/(1).collect/*[Int<>]*/ { case x => x } + | List/*[Int<>]*/(/*elems = */1).collect/*[Int<>]*/ { case x => x } | val x: PartialFunction[Int, Int] = { | case 1 => 2 | } @@ -651,11 +651,11 @@ class InlayHintsSuite extends BaseInlayHintsSuite { | |object Main { | def test(d: S[Int], f: S[Char]): AB[Int, String] = { - | val x/*: S<>[String<>]*/ = d.map/*[String<>]*/(_.toString) + | val x/*: S<>[String<>]*/ = d.map/*[String<>]*/(/*f = */_.toString) | val y/*: S<>[Char<>]*/ = f | ??? | } - | val x/*: AB<>[Int<>, String<>]*/ = test(Set/*[Int<>]*/(1), Set/*[Char<>]*/('a')) + | val x/*: AB<>[Int<>, String<>]*/ = test(/*d = */Set/*[Int<>]*/(/*elems = */1), /*f = */Set/*[Char<>]*/(/*elems = */'a')) |} |""".stripMargin, ) @@ -697,7 +697,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { | |given Ord[String] with | def compare(x: String, y: String)/*: Int<>*/ = - | /*augmentString<>(*/x/*)*/.compare(y) + | /*augmentString<>(*/x/*)*/.compare(/*that = */y) | |""".stripMargin ) @@ -715,7 +715,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |object O { | given Int = 1 | def test[T: Ordering](x: T)(using Int)/*: Nothing<>*/ = ??? - | test/*[Int<>]*/(1)/*(using Int<>, given_Int<<(2:8)>>)*/ + | test/*[Int<>]*/(/*x = */1)/*(using Int<>, given_Int<<(2:8)>>)*/ |} |""".stripMargin ) @@ -731,7 +731,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { """|package example |object O { | def test[T: Ordering](x: T)/*: Nothing<>*/ = ??? - | test/*[Int<>]*/(1)/*(using Int<>)*/ + | test/*[Int<>]*/(/*x = */1)/*(using Int<>)*/ |} |""".stripMargin ) @@ -747,7 +747,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { """|package example |object O { | def test[T: Ordering](x: T)(using Int)/*: Nothing<>*/ = ??? - | test/*[Int<>]*/(1)/*(using Int<>)*/ + | test/*[Int<>]*/(/*x = */1)/*(using Int<>)*/ |} |""".stripMargin ) @@ -765,7 +765,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |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)>>)*/ + | test/*[Int<>]*/(/*x = */1)/*(using Int<>, i<<(2:15)>>)*/ |} |""".stripMargin ) @@ -795,19 +795,19 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |""".stripMargin, """|package example |object O { - | val head :: tail = List/*[Int<>]*/(1) - | List/*[Int<>]*/(1) match { + | val head :: tail = List/*[Int<>]*/(/*elems = */1) + | List/*[Int<>]*/(/*elems = */1) match { | case head :: next => | case Nil => | } - | Option/*[Option<>[Int<>]]*/(Option/*[Int<>]*/(1)) match { + | Option/*[Option<>[Int<>]]*/(/*x = */Option/*[Int<>]*/(/*x = */1)) match { | case Some(Some(value)) => | case None => | } | val (local, _) = ("", 1.0) - | val Some(x) = Option/*[Int<>]*/(1) + | val Some(x) = Option/*[Int<>]*/(/*x = */1) | for { - | x <- List/*[(Int<>, Int<>)]*/((1,2)) + | x <- List/*[(Int<>, Int<>)]*/(/*elems = */(1,2)) | (z, y) = x | } yield { | x @@ -842,19 +842,19 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |""".stripMargin, """|package example |object O { - | val head/*: Int<>*/ :: tail/*: List<>[Int<>]*/ = List/*[Int<>]*/(1) - | List/*[Int<>]*/(1) match { + | val head/*: Int<>*/ :: tail/*: List<>[Int<>]*/ = List/*[Int<>]*/(/*elems = */1) + | List/*[Int<>]*/(/*elems = */1) match { | case head/*: Int<>*/ :: next/*: List<>[Int<>]*/ => | case Nil => | } - | Option/*[Option<>[Int<>]]*/(Option/*[Int<>]*/(1)) match { + | Option/*[Option<>[Int<>]]*/(/*x = */Option/*[Int<>]*/(/*x = */1)) match { | case Some(Some(value/*: Int<>*/)) => | case None => | } | val (local/*: String<>*/, _) = ("", 1.0) - | val Some(x/*: Int<>*/) = Option/*[Int<>]*/(1) + | val Some(x/*: Int<>*/) = Option/*[Int<>]*/(/*x = */1) | for { - | x/*: (Int<>, Int<>)*/ <- List/*[(Int<>, Int<>)]*/((1,2)) + | x/*: (Int<>, Int<>)*/ <- List/*[(Int<>, Int<>)]*/(/*elems = */(1,2)) | (z/*: Int<>*/, y/*: Int<>*/) = x | } yield { | x @@ -956,7 +956,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { | case class B() | implicit val theA: A = A() | def foo(b: B)(implicit a: A): String = "aaa" - | val g: String = foo(B())/*(using theA<<(4:15)>>)*/ + | val g: String = foo(/*b = */B())/*(using theA<<(4:15)>>)*/ |} |""".stripMargin, ) @@ -975,7 +975,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |""".stripMargin, """|object Main{ | def hello()(implicit string: String, integer: Int, long: Long): String = { - | println(s"Hello $string, $long, $integer!") + | println(/*x = */s"Hello $string, $long, $integer!") | } | implicit def theString(implicit i: Int): String = i.toString | implicit def theInt(implicit l: Long): Int = l @@ -999,7 +999,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |""".stripMargin, """|object Main{ | def hello()(implicit string: String, integer: Int, long: Long): String = { - | println(s"Hello $string, $long, $integer!") + | println(/*x = */s"Hello $string, $long, $integer!") | } | implicit def theString(implicit i: Int): String = i.toString | implicit def theInt: Int = 43 @@ -1076,6 +1076,20 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |""".stripMargin ) + @Test def `named-tuple-false-negative` = + check( + """|def hello(test: Int) = (path = ".", num = test) + | + |@main def test2 = + | val x = hello(7) + |""".stripMargin, + """|def hello(test: Int)/*: (path : String<>, num : Int<>)*/ = (path = ".", num = test)/*[(String<>, Int<>)]*/ + | + |@main def test2/*: Unit<>*/ = + | val x/*: (path : String<>, num : Int<>)*/ = hello(/*test = */7) + |""".stripMargin + ) + @Test def `by-name-regular` = check( """|object Main: @@ -1084,7 +1098,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |""".stripMargin, """|object Main: | def foo(x: => Int, y: Int, z: => Int)(w: Int, v: => Int): Unit = () - | foo(/*=> */1, 2, /*=> */3)(4, /*=> */5) + | foo(/*x = => */1, /*y = */2, /*z = => */3)(/*w = */4, /*v = => */5) |""".stripMargin ) @@ -1111,7 +1125,7 @@ class InlayHintsSuite extends BaseInlayHintsSuite { """|object Main: | def Future[A](arg: => A): A = arg | - | Future/*[Int<>]*/(/*=> */1 + 2) + | Future/*[Int<>]*/(/*arg = => */1 + 2) | Future/*[Int<>]*/ {/*=> */ | 1 + 2 | } @@ -1120,9 +1134,9 @@ class InlayHintsSuite extends BaseInlayHintsSuite { | val y/*: Int<>*/ = 2 | x + y | } - | Some/*[Int<> | Option<>[Int<>]]*/(Option/*[Int<>]*/(2) + | Some/*[Int<> | Option<>[Int<>]]*/(/*value = */Option/*[Int<>]*/(/*x = */2) | .getOrElse/*[Int<> | Option<>[Int<>]]*/ {/*=> */ - | List/*[Int<>]*/(1,2) + | List/*[Int<>]*/(/*elems = */1,2) | .headOption | }) |""".stripMargin @@ -1144,13 +1158,13 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |""".stripMargin, """|object Main: | case class Test[A](v: A): - | def flatMap(f: => (A => Test[Int])): Test[Int] = f(v) - | def map(f: => (A => Int)): Test[Int] = Test/*[Int<>]*/(f(v)) + | def flatMap(f: => (A => Test[Int])): Test[Int] = f(/*v1 = */v) + | def map(f: => (A => Int)): Test[Int] = Test/*[Int<>]*/(/*v = */f(/*v1 = */v)) | | def main(args: Array[String]): Unit = | val result: Test[Int] = for { - | a <- Test/*[Int<>]*/(10) - | b <- Test/*[Int<>]*/(20) + | a <- Test/*[Int<>]*/(/*v = */10) + | b <- Test/*[Int<>]*/(/*v = */20) | } yield a + b | |""".stripMargin, @@ -1172,16 +1186,79 @@ class InlayHintsSuite extends BaseInlayHintsSuite { |""".stripMargin, """|object Main: | case class Test[A](v: A): - | def flatMap[B](f: => (A => Test[B])): Test[B] = f(v) - | def map[B](f: => (A => B)): Test[B] = Test/*[B<<(4:13)>>]*/(f(v)) + | def flatMap[B](f: => (A => Test[B])): Test[B] = f(/*v1 = */v) + | def map[B](f: => (A => B)): Test[B] = Test/*[B<<(4:13)>>]*/(/*v = */f(/*v1 = */v)) | | def main(args: Array[String]): Unit = | val result: Test[Int] = for { - | a <- Test/*[Int<>]*/(10) - | b <- Test/*[Int<>]*/(20) + | a <- Test/*[Int<>]*/(/*v = */10) + | b <- Test/*[Int<>]*/(/*v = */20) | } yield a + b | |""".stripMargin, ) + @Test def `by-name-method-infix-extension` = + check( + """|case class A[T, U](dummy: Int, name: U): + | def compute: Int = 1 + | + |object A: + | extension [T, U](a: A[T, U]) + | def ++(other: => A[T, U]): Int = a.dummy + other.dummy + a.compute + | + |object Main: + | val a = A[Int, String](0, "foo") + | val res = a ++ a + |""".stripMargin, + """|case class A[T, U](dummy: Int, name: U): + | def compute: Int = 1 + | + |object A: + | extension [T, U](a: A[T, U]) + | def ++(other: => A[T, U]): Int = a.dummy + other.dummy + a.compute + | + |object Main: + | val a/*: A<<(1:11)>>[Int<>, String<>]*/ = A[Int, String](/*dummy = */0, /*name = */"foo") + | val res/*: Int<>*/ = a ++/*[Int<>, String<>]*/ a + |""".stripMargin + ) + + @Test def `by-name-method-infix-extension-2` = + check( + """|case class A[T, U](dummy: Int, name: U): + | def compute: Int = 1 + | + |extension [T, U](a: A[T, U]) + | def ++(other: => A[T, U]): Int = a.dummy + other.dummy + a.compute + | + |object Main: + | val a = A[Int, String](0, "foo") + | val res = a ++ a + |""".stripMargin, + """|case class A[T, U](dummy: Int, name: U): + | def compute: Int = 1 + | + |extension [T, U](a: A[T, U]) + | def ++(other: => A[T, U]): Int = a.dummy + other.dummy + a.compute + | + |object Main: + | val a/*: A<<(1:11)>>[Int<>, String<>]*/ = A[Int, String](/*dummy = */0, /*name = */"foo") + | val res/*: Int<>*/ = a ++/*[Int<>, String<>]*/ a + |""".stripMargin + ) + + @Test def `named-parameter` = + check( + """|object Main{ + | def hello[T](arg: T) = arg + | val x = hello(arg = List(1)) + |} + |""".stripMargin, + """|object Main{ + | def hello[T](arg: T)/*: T<<(2:12)>>*/ = arg + | val x/*: List<>[Int<>]*/ = hello/*[List<>[Int<>]]*/(arg = List/*[Int<>]*/(/*elems = */1)) + |} + |""".stripMargin + ) }