Skip to content

Scaladoc: type rendering fixes and improvements #17213

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions scaladoc-testcases/src/tests/exports1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ class A: //unexpected
= 1
var aVar1: 1
= 1
type HKT[T[_], X] //expected: final type HKT = [T[_], X] =>> HKT[T, X]
type HKT[T[_], X] //expected: final type HKT = [T[_], X] =>> a.HKT[T, X]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand why we need the a/A in theses, could you explain ?

Copy link
Contributor Author

@Florian3k Florian3k Apr 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is part of test consisting of 2 files: exports1.scala and exports2.scala

The test:
https://github.com/lampepfl/dotty/blob/ef974367932cb148bda152ed056183f319a9a2fc/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala#L96

exports2.scala for reference:
https://github.com/lampepfl/dotty/blob/ef974367932cb148bda152ed056183f319a9a2fc/scaladoc-testcases/src/tests/exports2.scala#L1-L12

So it's testing for exported member signatures in class B.

Signatures are rendered based on TypeRepr from Tasty.
For example TypeRepr for val x: HKT[List, Int] rendered in class B looks like this (not valid scala, this is slightly formatted output from println):

AppliedType(
  TypeRef(
    ThisType(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class tests)),object exports1),class A)), // TypeRepr for class A
    type HKT
  ),
  List(
    TypeRef(TermRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),object scala),package),List), // TypeRepr for List
    TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class <root>)),object scala),Int) // TypeRepr for Int
  )
)

Based solely on this representation, signature that should be rendered is A#HKT[List, Int]

To be honest, I'm not entirely sure whether this is correct way to render signatures of exported members.
If this is not correct, we may want to add some additional logic for checking if current signature is of an exported member and render it in a different way, but I'm probably gonna need some help with that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sjrd or @bishabosha, you are very familiar with tasty, what do you think ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a.HKT[T, X] seems absolutely correct to me. Otherwise you would be defining B.HKT in terms of itself.

The A#HKT[List, Int] seem a bit suspicious to me. this prefix substitution (the so-called asSeenFrom operation) should be replacing this.HKT[List, Int] from A by a.HKT[List, Int] when created by an export a._.

In fact, the TypeRef seems even more suspicious. As is, it means A.this.HKT, not really A#HKT. But that's quite bad if that's the type given to a member of B, since such a type is only valid when you're inside A. It seems the compiler is doing something wrong here.

From the point of view of Scaladoc, I think it should display A.this.HKT for the TypeRef(ThisType(A), type HKT).

= T[X]
type SomeRandomType = (List[_] | Seq[_]) & String //expected: final type SomeRandomType = SomeRandomType
def x[T[_], X](x: X): HKT[T, X]
type SomeRandomType = (List[_] | Seq[_]) & String //expected: final type SomeRandomType = a.SomeRandomType
def x[T[_], X](x: X): HKT[T, X] //expected: def x[T[_], X](x: X): A.this.HKT[T, X]
= ???
def fn[T, U]: T => U
= ???
object Object //expected: val Obj: Object.type
val x: HKT[List, Int]
val x: HKT[List, Int] //expected: val x: A.this.HKT[List, Int]
= ???
class Class(val a: Int, val b: Int) extends Serializable //expected: final type Class = Class
enum Enum: //expected: final type Enum = Enum
class Class(val a: Int, val b: Int) extends Serializable //expected: final type Class = a.Class
enum Enum: //expected: final type Enum = a.Enum
case A
case B(i: Int)
case C[T]() extends Enum
Expand Down
6 changes: 6 additions & 0 deletions scaladoc-testcases/src/tests/functionTypeSignatures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ type A = ((Int, Int)) => Int

type B = (Int | String) => Int

type B1 = Int | String => Int //expected: type B1 = (Int | String) => Int

type C = (Int & String) => Int

type C1 = Int & String => Int //expected: type C1 = (Int & String) => Int

type D = Int | (String => Int)

type E = (A => B) => B

141 changes: 141 additions & 0 deletions scaladoc-testcases/src/tests/infixTypes.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package tests
package infixTypes

import annotation.showAsInfix

@showAsInfix
trait SomeTrait[A, B]

trait SomeTrait2[A, B]

def someTrait1[C, D]: C SomeTrait D
= ???

def someTrait2[E, F]: SomeTrait[E, F] //expected: def someTrait2[E, F]: E SomeTrait F
= ???

def someTrait3[G, H]: G SomeTrait2 H //expected: def someTrait3[G, H]: SomeTrait2[G, H]
= ???

trait +++[A, B]

trait ++*[A, B]

trait ++:[A, B]

trait +*:[A, B]

trait ***[A, B]

trait **:[A, B]

def foo[A, B, C, D]: (A SomeTrait B) +++ (C SomeTrait2 D) //expected: def foo[A, B, C, D]: (A SomeTrait B) +++ SomeTrait2[C, D]
= ???

// left-associative, same precedence

def a0[X, Y, Z]: X +++ Y +++ Z
= a1

def a1[X, Y, Z]: (X +++ Y) +++ Z //expected: def a1[X, Y, Z]: X +++ Y +++ Z
= a0

def a2[X, Y, Z]: X +++ (Y +++ Z)
= ???

def a0x[X, Y, Z]: X +++ Y ++* Z //expected: def a0x[X, Y, Z]: (X +++ Y) ++* Z
= a1x

def a1x[X, Y, Z]: (X +++ Y) ++* Z
= a0x

def a2x[X, Y, Z]: X +++ (Y ++* Z)
= ???

// right-associative, same precedence

def a3[X, Y, Z]: X ++: Y ++: Z
= a5

def a4[X, Y, Z]: (X ++: Y) ++: Z
= ???

def a5[X, Y, Z]: X ++: (Y ++: Z) //expected: def a5[X, Y, Z]: X ++: Y ++: Z
= a3

def a3x[X, Y, Z]: X ++: Y +*: Z //expected: def a3x[X, Y, Z]: X ++: (Y +*: Z)
= a5x

def a4x[X, Y, Z]: (X ++: Y) +*: Z
= ???

def a5x[X, Y, Z]: X ++: (Y +*: Z)
= a3x

// left and right associative, same precedence

def a6[X, Y, Z]: (X +++ Y) ++: Z
= ???

def a7[X, Y, Z]: X +++ (Y ++: Z)
= ???

// left-associative, mixed precedence

def b0[X, Y, Z]: X +++ Y *** Z //expected: def b0[X, Y, Z]: X +++ (Y *** Z)
= ???

def b1[X, Y, Z]: (X +++ Y) *** Z
= ???

def b2[X, Y, Z]: X +++ (Y *** Z)
= ???

def b3[X, Y, Z]: X *** Y +++ Z //expected: def b3[X, Y, Z]: (X *** Y) +++ Z
= ???

def b4[X, Y, Z]: (X *** Y) +++ Z
= ???

def b5[X, Y, Z]: X *** (Y +++ Z)
= ???

// right-associative, mixed precedence

def c0[X, Y, Z]: X ++: Y **: Z //expected: def c0[X, Y, Z]: X ++: (Y **: Z)
= ???

def c1[X, Y, Z]: (X ++: Y) **: Z
= ???

def c2[X, Y, Z]: X ++: (Y **: Z)
= ???

def c3[X, Y, Z]: X **: Y ++: Z //expected: def c3[X, Y, Z]: (X **: Y) ++: Z
= ???

def c4[X, Y, Z]: (X **: Y) ++: Z
= ???

def c5[X, Y, Z]: X **: (Y ++: Z)
= ???

// left and right associative, mixed precedence

def d0[X, Y, Z]: X +++ Y **: Z //expected: def d0[X, Y, Z]: X +++ (Y **: Z)
= ???

def d1[X, Y, Z]: (X +++ Y) **: Z
= ???

def d2[X, Y, Z]: X +++ (Y **: Z)
= ???

def d3[X, Y, Z]: X *** Y ++: Z //expected: def d3[X, Y, Z]: (X *** Y) ++: Z
= ???

def d4[X, Y, Z]: (X *** Y) ++: Z
= ???

def d5[X, Y, Z]: X *** (Y ++: Z)
= ???
10 changes: 10 additions & 0 deletions scaladoc-testcases/src/tests/matchTypeTuple.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package tests
package matchTypeTuple

// issue 16084

sealed trait TupleTest[Take[_, _], Drop[_, _]]:
type Split[T <: Tuple, N <: Int] = (Take[T, N], Drop[T, N])

inline def splitAt[This <: Tuple](n: Int): Split[This, n.type]
= ???
20 changes: 20 additions & 0 deletions scaladoc-testcases/src/tests/pathDependentTypes.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package tests
package pathDependentTypes

import deriving.Mirror.ProductOf

// issue 16143

trait Foo[A]:
type Out

trait Bar[A]:
type Out

def foo[A](using f: Foo[A])(using b: Bar[f.Out]): b.Out
= ???

// issue 16057

def fromProductTyped[P <: Product](p: P)(using m: ProductOf[P]): m.MirroredElemTypes
= ???
20 changes: 20 additions & 0 deletions scaladoc-testcases/src/tests/supertypeParamsSubstitution.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package tests
package supertypeParamsSubstitution

class MyIter[A, CC[_], C]:
def foo: A
= ???
def bar: CC[CC[A]]
= ???
def baz: C
= ???

class MyList[T] extends MyIter[T, MyList, MyList[T]]
//expected: def foo: T
//expected: def bar: MyList[MyList[T]]
//expected: def baz: MyList[T]

class MyListInt extends MyList[Int]
//expected: def foo: Int
//expected: def bar: MyList[MyList[Int]]
//expected: def baz: MyList[Int]
8 changes: 8 additions & 0 deletions scaladoc-testcases/src/tests/thisType.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package tests
package thisType

// issue 16024

class X[Map[_, _[_]]]:
inline def map[F[_]](f: [t] => t => F[t]): Map[this.type, F] = //expected: inline def map[F[_]](f: [t] => (x$1: t) => F[t]): Map[this.type, F]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More nitpicking:
Would it be possible to only print the identifier (x$1) if it is required ?

Ex: [t] => (x: t) => t

I see two ways of doing so:

  1. Look at whether the name is synthetic/mangled: ex prints as [t] => (x: t) => t
  2. Look at whether the name is used on the rhs: ex prints as [t] => t => t

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll look into that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's leave that for future improvements.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you open an issue for it ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: #17756

???
Loading