From 222f8f868a6ccc0a48fcf501c7ba9b8faf11b740 Mon Sep 17 00:00:00 2001 From: Florian3k Date: Fri, 24 May 2024 15:54:17 +0200 Subject: [PATCH] fix handling of right-assoc extension methods --- .../dotty/tools/dotc/printing/RefinedPrinter.scala | 4 +++- .../dotty/tools/pc/printer/ShortenedTypePrinter.scala | 4 +++- .../dotty/tools/pc/tests/hover/HoverTermSuite.scala | 11 +++++++++++ .../src/tests/rightAssocExtension.scala | 7 +++++++ .../dotty/tools/scaladoc/tasty/ClassLikeSupport.scala | 4 +++- .../signatures/TranslatableSignaturesTestCases.scala | 2 ++ 6 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 scaladoc-testcases/src/tests/rightAssocExtension.scala diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 1ff4c8cae339..0c6e36c8f18f 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -988,7 +988,9 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { // - trailingUsing = List(`(using D)`) // - rest = List(`(g: G)`, `(using H)`) // we need to swap (rightTyParams ++ rightParam) with (leftParam ++ trailingUsing) - val (leftTyParams, rest1) = tree.paramss.span(isTypeParamClause) + val (leftTyParams, rest1) = tree.paramss match + case fst :: tail if isTypeParamClause(fst) => (List(fst), tail) + case other => (List(), other) val (leadingUsing, rest2) = rest1.span(isUsingClause) val (rightTyParams, rest3) = rest2.span(isTypeParamClause) val (rightParam, rest4) = rest3.splitAt(1) diff --git a/presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala b/presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala index 559e199f3449..19d603fcbb3b 100644 --- a/presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala +++ b/presentation-compiler/src/main/dotty/tools/pc/printer/ShortenedTypePrinter.scala @@ -419,7 +419,9 @@ class ShortenedTypePrinter( if gsym.is(Flags.ExtensionMethod) then val filteredParams = if gsym.name.isRightAssocOperatorName then - val (leadingTyParamss, rest1) = paramss.span(isTypeParamClause) + val (leadingTyParamss, rest1) = paramss match + case fst :: tail if isTypeParamClause(fst) => (List(fst), tail) + case other => (List(), other) val (leadingUsing, rest2) = rest1.span(isUsingClause) val (rightTyParamss, rest3) = rest2.span(isTypeParamClause) val (rightParamss, rest4) = rest3.splitAt(1) diff --git a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala index b51974b00fb0..9ae37048caf7 100644 --- a/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala +++ b/presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala @@ -683,3 +683,14 @@ class HoverTermSuite extends BaseHoverSuite: |""".stripMargin, """yy: A{type T = Int}""".stripMargin.hover ) + + @Test def `right-assoc-extension`: Unit = + check( + """ + |case class Wrap[+T](x: T) + | + |extension [T](a: T) + | def <<*@@:>>[U <: Tuple](b: Wrap[U]): Wrap[T *: U] = Wrap(a *: b.x) + |""".stripMargin, + "extension [T](a: T) def *:[U <: Tuple](b: Wrap[U]): Wrap[T *: U]".hover + ) diff --git a/scaladoc-testcases/src/tests/rightAssocExtension.scala b/scaladoc-testcases/src/tests/rightAssocExtension.scala new file mode 100644 index 000000000000..a065ee765caf --- /dev/null +++ b/scaladoc-testcases/src/tests/rightAssocExtension.scala @@ -0,0 +1,7 @@ +package tests.rightAssocExtension + +case class Wrap[+T](x: T) + +extension [T](a: T) + def *:[U <: Tuple](b: Wrap[U]): Wrap[T *: U] + = Wrap(a *: b.x) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 88d57cdb9853..8823f6cb4e5e 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -359,7 +359,9 @@ trait ClassLikeSupport: if methodSymbol.isExtensionMethod && methodSymbol.isRightAssoc then // Taken from RefinedPrinter.scala // If you change the names of the clauses below, also change them in right-associative-extension-methods.md - val (leftTyParams, rest1) = memberInfo.paramLists.span(_.isType) + val (leftTyParams, rest1) = memberInfo.paramLists match + case fst :: tail if fst.isType => (List(fst), tail) + case other => (List(), other) val (leadingUsing, rest2) = rest1.span(_.isUsing) val (rightTyParams, rest3) = rest2.span(_.isType) val (rightParam, rest4) = rest3.splitAt(1) diff --git a/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala b/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala index d60a4d82ff44..bfa2a372827a 100644 --- a/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala +++ b/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala @@ -122,3 +122,5 @@ class InfixTypes extends SignatureTest("infixTypes", SignatureTest.all) class ExtendsCall extends SignatureTest("extendsCall", SignatureTest.all) class RefinedFunctionTypes extends SignatureTest("refinedFunctionTypes", SignatureTest.all) + +class RightAssocExtension extends SignatureTest("rightAssocExtension", SignatureTest.all)