Skip to content

Commit

Permalink
Scaladoc: add support for named tuples
Browse files Browse the repository at this point in the history
  • Loading branch information
Florian3k committed Dec 23, 2024
1 parent c61897d commit e464c18
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 29 deletions.
23 changes: 23 additions & 0 deletions scaladoc-testcases/src/tests/namedTuples.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package tests.namedTuples

import language.experimental.namedTuples
import NamedTuple.*

type Person = (name: String, age: Int)

type Person2 = NamedTuple[("age2", "name2"), (Int, String)] //expected: type Person2 = (age2: Int, name2: String)

val x = (name = "Bob", age = 25) //expected: val x: (name: String, age: Int)

def foo(p1: (age: Int, name: String), p2: (name: String, age: Int)): Nothing
= ???

def invalid1: NamedTuple[("age", String), (Int, Int)]
= ???

def invalid2: NamedTuple[("age", "name"), (Int, Int, Int)]
= ???

def invalid3: NamedTuple[("age", "name", "something"), (Int, Int)]
= ???

65 changes: 36 additions & 29 deletions scaladoc/src/dotty/tools/scaladoc/tasty/TypesSupport.scala
Original file line number Diff line number Diff line change
Expand Up @@ -204,36 +204,43 @@ trait TypesSupport:
prefix ++ plain("{ ").l ++ refinedElems.flatMap(e => parseRefinedElem(e.name, e.info)) ++ plain(" }").l
}
}

case AppliedType(tpe, args) if defn.isTupleClass(tpe.typeSymbol) && args.length > 1 =>
inParens(commas(args.map(inner(_))))

case AppliedType(namedTuple, List(AppliedType(tuple1, names), AppliedType(tuple2, types)))
if namedTuple.typeSymbol == Symbol.requiredModule("scala.NamedTuple").typeMember("NamedTuple")
&& defn.isTupleClass(tuple1.typeSymbol) && defn.isTupleClass(tuple2.typeSymbol) && names.length == types.length
&& names.forall { case ConstantType(StringConstant(_)) => true case _ => false } =>
val elems = names
.collect { case ConstantType(StringConstant(s)) => s }
.zip(types)
.map((name, tpe) => plain(name) +: plain(": ") +: inner(tpe))
inParens(commas(elems))

case t @ AppliedType(tpe, List(lhs, rhs)) if isInfix(t) =>
inParens(inner(lhs), shouldWrapInParens(lhs, t, true))
++ plain(" ").l
++ inner(tpe)
++ plain(" ").l
++ inParens(inner(rhs), shouldWrapInParens(rhs, t, false))

case t @ AppliedType(tpe, args) if t.isFunctionType =>
val arrow = if t.isContextFunctionType then " ?=> " else " => "
args match
case Nil => Nil
case List(rtpe) => plain("()").l ++ keyword(arrow).l ++ inner(rtpe)
case List(arg, rtpe) =>
val wrapInParens = stripAnnotated(arg) match
case _: TermRef | _: TypeRef | _: ConstantType | _: ParamRef => false
case at: AppliedType if !isInfix(at) && !at.isFunctionType && !at.isTupleN => false
case _ => true
inParens(inner(arg), wrapInParens) ++ keyword(arrow).l ++ inner(rtpe)
case _ =>
plain("(").l ++ commas(args.init.map(inner(_))) ++ plain(")").l ++ keyword(arrow).l ++ inner(args.last)

case t @ AppliedType(tpe, typeList) =>
import dotty.tools.dotc.util.Chars._
if defn.isTupleClass(tpe.typeSymbol) && typeList.length != 1 then
typeList match
case Nil => Nil
case args => inParens(commas(args.map(inner(_))))
else if isInfix(t) then
val lhs = typeList.head
val rhs = typeList.last
inParens(inner(lhs), shouldWrapInParens(lhs, t, true))
++ plain(" ").l
++ inner(tpe)
++ plain(" ").l
++ inParens(inner(rhs), shouldWrapInParens(rhs, t, false))
else if t.isFunctionType then
val arrow = if t.isContextFunctionType then " ?=> " else " => "
typeList match
case Nil =>
Nil
case Seq(rtpe) =>
plain("()").l ++ keyword(arrow).l ++ inner(rtpe)
case Seq(arg, rtpe) =>
val partOfSignature = stripAnnotated(arg) match
case _: TermRef | _: TypeRef | _: ConstantType | _: ParamRef => inner(arg)
case at: AppliedType if !isInfix(at) && !at.isFunctionType && !at.isTupleN => inner(arg)
case _ => inParens(inner(arg))
partOfSignature ++ keyword(arrow).l ++ inner(rtpe)
case args =>
plain("(").l ++ commas(args.init.map(inner(_))) ++ plain(")").l ++ keyword(arrow).l ++ inner(args.last)
else inner(tpe) ++ plain("[").l ++ commas(typeList.map { t => t match
inner(tpe) ++ plain("[").l ++ commas(typeList.map { t => t match
case _: TypeBounds => keyword("_").l ++ inner(t)
case _ => topLevelProcess(t)
}) ++ plain("]").l
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,5 @@ class ExtendsCall extends SignatureTest("extendsCall", SignatureTest.all)
class RefinedFunctionTypes extends SignatureTest("refinedFunctionTypes", SignatureTest.all)

class RightAssocExtension extends SignatureTest("rightAssocExtension", SignatureTest.all)

class NamedTuples extends SignatureTest("namedTuples", SignatureTest.all)

0 comments on commit e464c18

Please sign in to comment.