From 5671d26590b4cd9bc7a8f0858022e6947f622fea Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Fri, 21 Jan 2022 21:17:02 +0100 Subject: [PATCH 1/8] Add failing test --- .../src/tests/extensionParams.scala | 38 +++++++++++++++---- .../TranslatableSignaturesTestCases.scala | 4 ++ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/scaladoc-testcases/src/tests/extensionParams.scala b/scaladoc-testcases/src/tests/extensionParams.scala index 231a8a1fefbf..31747e3d9f63 100644 --- a/scaladoc-testcases/src/tests/extensionParams.scala +++ b/scaladoc-testcases/src/tests/extensionParams.scala @@ -1,22 +1,44 @@ package tests.extensionParams extension [A](thiz: A) - def toTuple2[B](that: B): (A, B) = thiz -> that - + def toTuple2[B](that: B): (A, B) + = thiz -> that extension [A](a: A)(using Int) - def f[B](b: B): (A, B) = ??? + def f1[B](b: B): (A, B) + = ??? extension [A](a: A)(using Int) - def ff(b: A): (A, A) = ??? + def f2(b: A): (A, A) + = ??? extension [A](a: A)(using Int) - def fff(using String)(b: A): (A, A) = ??? + def f3(using String)(b: A): (A, A) + = ??? extension (a: Char)(using Int) - def ffff(using String)(b: Int): Unit = ??? + def f4(using String)(b: Int): Unit + = ??? extension (a: Char)(using Int) - def fffff[B](using String)(b: B): Unit = ??? + def f5[B](using String)(b: B): Unit + = ??? extension [A <: List[Char]](a: A)(using Int) - def ffffff[B](b: B): (A, B) = ??? + def f6[B](b: B): (A, B) + = ??? + +extension [A <: List[Char]](using String)(using Unit)(a: A)(using Int)(using Number) + def f7[B, C](b: B)(c: C): (A, B) + = ??? + +extension [A <: List[Char]](using String)(using Unit)(a: A)(using Int)(using Number) + def f8(b: Any)(c: Any): Any + = ??? + +extension [A <: List[Char]](using String)(using Unit)(a: A)(using Int)(using Number) + def f9[B, C](using Int)(b: B)(c: C): (A, B) + = ??? + +extension [A <: List[Char]](using String)(using Unit)(a: A)(using Int)(using Number) + def f10(using Int)(b: Any)(c: Any): Any + = ??? diff --git a/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala b/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala index d85d2d960d2c..5daff1a63e55 100644 --- a/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala +++ b/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala @@ -1,5 +1,7 @@ package dotty.tools.scaladoc.signatures +import java.security.Signature + class GenericSignaftures extends SignatureTest("genericSignatures", Seq("class")) class ObjectSignatures extends SignatureTest("objectSignatures", Seq("object")) @@ -22,6 +24,8 @@ class GenericMethodsTest extends SignatureTest("genericMethods", Seq("def")) class MethodsAndConstructors extends SignatureTest("methodsAndConstructors", Seq("def")) +class ExtensionParams extends SignatureTest("extensionParams", SignatureTest.all) + class TypesSignatures extends SignatureTest("typesSignatures", SignatureTest.all) class FieldsSignatures extends SignatureTest("fieldsSignatures", SignatureTest.all.filterNot(_ == "object")) From d0f7300b20bbd9ec3700156f8b4d8b2a81d87423 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Fri, 21 Jan 2022 21:29:35 +0100 Subject: [PATCH 2/8] Add new heuristic for extension methods Uses the assumption that there is the following "pos hierachy": extension paramss < DefDef < extMethod paramss --- .../dotty/tools/scaladoc/tasty/SymOps.scala | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala index e412475cbf2c..743c0ffea513 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala @@ -142,7 +142,15 @@ object SymOps: import reflect._ sym.flags.is(Flags.Artifact) - def isLeftAssoc: Boolean = !sym.name.endsWith(":") + /** + * note that this is not the right criterion: + * An extension method is treated as a right-associative operator (as in SLS ยง6.12.3) + * if it has a name ending in : and is immediately followed by a single parameter. + * https://docs.scala-lang.org/scala3/reference/contextual/right-associative-extension-methods.html + */ + def isRightAssoc: Boolean = sym.name.endsWith(":") + + def isLeftAssoc: Boolean = !sym.isRightAssoc def extendedSymbol: Option[reflect.ValDef] = import reflect.* @@ -152,6 +160,45 @@ object SymOps: else termParamss(1).params(0) } + def splitExtensionParamLists: (List[reflect.ParamClause], List[reflect.ParamClause]) = + if sym.isRightAssoc && sym.isExtensionMethod then + val unswapped@(extPart, defPart) = sym.splitExtensionParamListsAssumingLeftAssoc + def nonUsingClauses(clauses: List[reflect.ParamClause]) = clauses.zipWithIndex.collect{case (terms: reflect.TermParamClause, i) if !terms.isGiven => (terms, i)} + val extNonUsingClause = nonUsingClauses(extPart) + val defNonUsingClauses = nonUsingClauses(defPart) + assert(extNonUsingClause.size == 1) + + if defNonUsingClauses.lift(0).map(_._1.params.size != 1).getOrElse(true) // was not really right associative, see comment of isRightAssoc + then unswapped + else + val (first, i1) = extNonUsingClause(0) + val (second, i2) = defNonUsingClauses(0) // since cond is false, we know lift(0) returned Some(_) + (extPart.updated(i1, second), defPart.updated(i2, first)) + else + sym.splitExtensionParamListsAssumingLeftAssoc + + /** + * This uses the assumption that there is the following "pos hierachy": extension paramss < DefDef < extMethod paramss + * /!\ where DefDef is the tree containing the paramss + * It wouldn't really make sense for the Def's position not to be either the "def" or the method name, + * but is not enforced + */ + def splitExtensionParamListsAssumingLeftAssoc: (List[reflect.ParamClause], List[reflect.ParamClause]) = + val method = sym.tree.asInstanceOf[reflect.DefDef] + val paramss = method.paramss //List[ParamClause[T]] //ParamClause[T] = List[ValDef[T]] | List[TypeDef[T]] + val defCoord = method.symbol.pos.get.start //.span.point + + val res = paramss.span{ + case reflect.TypeParamClause(params) => params.head.symbol.pos.get.start < defCoord //.span.start + case reflect.TermParamClause(params) => + params.headOption + .map(_.symbol.pos.get.start < defCoord) //.span.start + .getOrElse(false) // () is only allowed on the RHS of extensions + } + //println(method.name) + //println(res._1.map(_.params.map(_.show)).mkString("ExtensionPart:\n","\n","\n")) + //println(res._2.map(_.params.map(_.show)).mkString("NonExtensionPart:\n","\n","\n")) + res def extendedTypeParams: List[reflect.TypeDef] = import reflect.* val method = sym.tree.asInstanceOf[DefDef] From 43a1a261f0cf546627f108e06a73cac6ae301465 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Fri, 21 Jan 2022 21:30:46 +0100 Subject: [PATCH 3/8] Refactor existing methods using new heuristic --- .../dotty/tools/scaladoc/tasty/SymOps.scala | 52 ++++++------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala index 743c0ffea513..b7796372aa92 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala @@ -199,52 +199,30 @@ object SymOps: //println(res._1.map(_.params.map(_.show)).mkString("ExtensionPart:\n","\n","\n")) //println(res._2.map(_.params.map(_.show)).mkString("NonExtensionPart:\n","\n","\n")) res + + def extendedParamLists: List[reflect.ParamClause] = + sym.splitExtensionParamLists._1 + def extendedTypeParams: List[reflect.TypeDef] = - import reflect.* - val method = sym.tree.asInstanceOf[DefDef] - method.leadingTypeParams + val typeParamss: List[reflect.TypeParamClause] = sym.extendedParamLists.collect{case types: reflect.TypeParamClause => types} + typeParamss.headOption.map(_.params).getOrElse(List()) // only one type param clause on LHS + + def extendedTermParamLists: List[reflect.TermParamClause] = - import reflect.* - if sym.nonExtensionLeadingTypeParams.nonEmpty then - sym.nonExtensionParamLists.takeWhile { - case _: TypeParamClause => false - case _ => true - }.collect { - case tpc: TermParamClause => tpc - } - else - List.empty + sym.extendedParamLists.collect{case terms: reflect.TermParamClause => terms} def nonExtensionTermParamLists: List[reflect.TermParamClause] = - import reflect.* - if sym.nonExtensionLeadingTypeParams.nonEmpty then - sym.nonExtensionParamLists.dropWhile { - case _: TypeParamClause => false - case _ => true - }.drop(1).collect { - case tpc: TermParamClause => tpc - } - else - sym.nonExtensionParamLists.collect { - case tpc: TermParamClause => tpc - } + sym.nonExtensionParamLists.collect{case terms: reflect.TermParamClause => terms} def nonExtensionParamLists: List[reflect.ParamClause] = - import reflect.* - val method = sym.tree.asInstanceOf[DefDef] - if sym.isExtensionMethod then - val params = method.paramss - val toDrop = if method.leadingTypeParams.nonEmpty then 2 else 1 - if sym.isLeftAssoc || params.size == 1 then params.drop(toDrop) - else params.head :: params.tail.drop(toDrop) - else method.paramss + sym.splitExtensionParamLists._2 + def nonExtensionLeadingTypeParams: List[reflect.TypeDef] = - import reflect.* - sym.nonExtensionParamLists.collectFirst { - case TypeParamClause(params) => params - }.toList.flatten + val typeParamss: List[reflect.TypeParamClause] = sym.nonExtensionParamLists.collect{case types: reflect.TypeParamClause => types} + typeParamss.headOption.map(_.params).getOrElse(List()) // only one type param clause on RHS + end extension From 36b5c8a200c5b84f90fe3d94ad83298cd42a398a Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Fri, 21 Jan 2022 21:44:54 +0100 Subject: [PATCH 4/8] Reorder and Rename methods for consistency --- .../scaladoc/tasty/ClassLikeSupport.scala | 7 +++++-- .../dotty/tools/scaladoc/tasty/SymOps.scala | 19 +++++++++---------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 31e27e234332..ff866be1491b 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -130,7 +130,10 @@ trait ClassLikeSupport: case dd: DefDef if isDocumentableExtension(dd.symbol) => dd.symbol.extendedSymbol.map { extSym => val memberInfo = unwrapMemberInfo(c, dd.symbol) - val typeParams = dd.symbol.extendedTypeParams.map(mkTypeArgument(_, memberInfo.genericTypes)) + val typeParams = dd.symbol.extendedTypeParamList.map(mkTypeArgument(_, memberInfo.genericTypes)) + //println(dd.name) + //println("MemberInfo:\n" + memberInfo.paramLists) + //println("extended...:\n" + dd.symbol.extendedTermParamLists) val termParams = dd.symbol.extendedTermParamLists.zipWithIndex.flatMap { case (paramList, index) => memberInfo.paramLists(index) match case EvidenceOnlyParameterList => Nil @@ -328,7 +331,7 @@ trait ClassLikeSupport: ): Member = val method = methodSymbol.tree.asInstanceOf[DefDef] val paramLists: List[TermParamClause] = methodSymbol.nonExtensionTermParamLists - val genericTypes: List[TypeDef] = if (methodSymbol.isClassConstructor) Nil else methodSymbol.nonExtensionLeadingTypeParams + val genericTypes: List[TypeDef] = if (methodSymbol.isClassConstructor) Nil else methodSymbol.nonExtensionTypeParamList val memberInfo = unwrapMemberInfo(c, methodSymbol) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala index b7796372aa92..17367418aef7 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala @@ -200,26 +200,25 @@ object SymOps: //println(res._2.map(_.params.map(_.show)).mkString("NonExtensionPart:\n","\n","\n")) res + def extendedParamLists: List[reflect.ParamClause] = sym.splitExtensionParamLists._1 - - def extendedTypeParams: List[reflect.TypeDef] = - val typeParamss: List[reflect.TypeParamClause] = sym.extendedParamLists.collect{case types: reflect.TypeParamClause => types} - typeParamss.headOption.map(_.params).getOrElse(List()) // only one type param clause on LHS - - def extendedTermParamLists: List[reflect.TermParamClause] = sym.extendedParamLists.collect{case terms: reflect.TermParamClause => terms} - def nonExtensionTermParamLists: List[reflect.TermParamClause] = - sym.nonExtensionParamLists.collect{case terms: reflect.TermParamClause => terms} + def extendedTypeParamList: List[reflect.TypeDef] = + val typeParamss: List[reflect.TypeParamClause] = sym.extendedParamLists.collect{case types: reflect.TypeParamClause => types} + typeParamss.headOption.map(_.params).getOrElse(List()) // only one type param clause on LHS + def nonExtensionParamLists: List[reflect.ParamClause] = sym.splitExtensionParamLists._2 - - def nonExtensionLeadingTypeParams: List[reflect.TypeDef] = + def nonExtensionTermParamLists: List[reflect.TermParamClause] = + sym.nonExtensionParamLists.collect{case terms: reflect.TermParamClause => terms} + + def nonExtensionTypeParamList: List[reflect.TypeDef] = val typeParamss: List[reflect.TypeParamClause] = sym.nonExtensionParamLists.collect{case types: reflect.TypeParamClause => types} typeParamss.headOption.map(_.params).getOrElse(List()) // only one type param clause on RHS From 43a79d53c4e0360ec1a6ac62a3512adcc52a4321 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Sat, 19 Feb 2022 18:38:35 +0100 Subject: [PATCH 5/8] Merge useful changes from scaladoc-typeInterweaving-new --- scaladoc/src/dotty/tools/scaladoc/api.scala | 23 ++++-- .../scaladoc/tasty/ClassLikeSupport.scala | 81 +++++++++++++------ .../ImplicitMembersExtensionTransformer.scala | 2 +- .../translators/ScalaSignatureProvider.scala | 19 ++--- .../translators/ScalaSignatureUtils.scala | 19 ++++- 5 files changed, 97 insertions(+), 47 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/api.scala b/scaladoc/src/dotty/tools/scaladoc/api.scala index 314dcc3c7261..98f60036ed8c 100644 --- a/scaladoc/src/dotty/tools/scaladoc/api.scala +++ b/scaladoc/src/dotty/tools/scaladoc/api.scala @@ -43,7 +43,7 @@ enum Modifier(val name: String, val prefix: Boolean): case Transparent extends Modifier("transparent", true) case Infix extends Modifier("infix", true) -case class ExtensionTarget(name: String, typeParams: Seq[TypeParameter], argsLists: Seq[ParametersList], signature: Signature, dri: DRI, position: Long) +case class ExtensionTarget(name: String, typeParams: Seq[TypeParameter], argsLists: Seq[TermParametersList], signature: Signature, dri: DRI, position: Long) case class ImplicitConversion(from: DRI, to: DRI) trait ImplicitConversionProvider { def conversion: Option[ImplicitConversion] } trait Classlike @@ -51,14 +51,14 @@ trait Classlike enum Kind(val name: String): case RootPackage extends Kind("") case Package extends Kind("package") - case Class(typeParams: Seq[TypeParameter], argsLists: Seq[ParametersList]) + case Class(typeParams: Seq[TypeParameter], argsLists: Seq[TermParametersList]) extends Kind("class") with Classlike case Object extends Kind("object") with Classlike - case Trait(typeParams: Seq[TypeParameter], argsLists: Seq[ParametersList]) + case Trait(typeParams: Seq[TypeParameter], argsLists: Seq[TermParametersList]) extends Kind("trait") with Classlike - case Enum(typeParams: Seq[TypeParameter], argsLists: Seq[ParametersList]) extends Kind("enum") with Classlike + case Enum(typeParams: Seq[TypeParameter], argsLists: Seq[TermParametersList]) extends Kind("enum") with Classlike case EnumCase(kind: Object.type | Kind.Type | Val.type | Class) extends Kind("case") - case Def(typeParams: Seq[TypeParameter], argsLists: Seq[ParametersList]) + case Def(params: Seq[TypeParametersList | TermParametersList]) // TODO: sc extends Kind("def") case Extension(on: ExtensionTarget, m: Kind.Def) extends Kind("def") case Constructor(base: Kind.Def) extends Kind("def") @@ -94,12 +94,15 @@ object Annotation: case class LinkParameter(name: Option[String] = None, dri: DRI, value: String) extends AnnotationParameter case class UnresolvedParameter(name: Option[String] = None, unresolvedText: String) extends AnnotationParameter -case class ParametersList( - parameters: Seq[Parameter], + +// type ParametersList = TermParametersList | TypeParametersList // TODO: sc + +case class TermParametersList( + parameters: Seq[TermParameter], modifiers: String ) -case class Parameter( +case class TermParameter( annotations: Seq[Annotation], modifiers: String, name: Option[String], @@ -109,6 +112,10 @@ case class Parameter( isGrouped: Boolean = false ) +case class TypeParametersList( + parameters: Seq[TypeParameter] +) + case class TypeParameter( annotations: Seq[Annotation], variance: "" | "+" | "-", diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index ff866be1491b..928ccb4b4f86 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -45,7 +45,7 @@ trait ClassLikeSupport: .filter(s => s.exists && !s.isHiddenByVisibility) .map( _.tree.asInstanceOf[DefDef]) constr.fold(Nil)( - _.termParamss.map(pList => ParametersList(pList.params.map(p => mkParameter(p, parameterModifier)), paramListModifier(pList.params))) + _.termParamss.map(pList => TermParametersList(pList.params.map(p => mkParameter(p, parameterModifier)), paramListModifier(pList.params))) ) if classDef.symbol.flags.is(Flags.Module) then Kind.Object @@ -138,7 +138,7 @@ trait ClassLikeSupport: memberInfo.paramLists(index) match case EvidenceOnlyParameterList => Nil case info: RegularParameterList => - Seq(ParametersList(paramList.params.map(mkParameter(_, memberInfo = info)), paramListModifier(paramList.params))) + Seq(TermParametersList(paramList.params.map(mkParameter(_, memberInfo = info)), paramListModifier(paramList.params))) } val target = ExtensionTarget( extSym.symbol.normalizedName, @@ -330,32 +330,62 @@ trait ClassLikeSupport: specificKind: (Kind.Def => Kind) = identity ): Member = val method = methodSymbol.tree.asInstanceOf[DefDef] - val paramLists: List[TermParamClause] = methodSymbol.nonExtensionTermParamLists - val genericTypes: List[TypeDef] = if (methodSymbol.isClassConstructor) Nil else methodSymbol.nonExtensionTypeParamList + val allParamss: List[ParamClause] = method.paramss + val nonExtensionParamss: List[ParamClause] = methodSymbol.nonExtensionParamLists + //val paramLists: List[TermParamClause] = methodSymbol.nonExtensionTermParamLists + //val genericTypes: List[TypeDef] = if (methodSymbol.isClassConstructor) Nil else methodSymbol.nonExtensionTypeParamList val memberInfo = unwrapMemberInfo(c, methodSymbol) + assert(allParamss.size == memberInfo.paramLists.size) + + // assumes method is left-associative + // finds indices in memberInfo.paramLists corresponding to nonExtensionParamss + // probably not going to work, as they are related but not == + val nonExtensionParamssWithIndices = allParamss.zipWithIndex.dropWhile(_._1 != nonExtensionParamss.head) + val basicKind: Kind.Def = Kind.Def( + nonExtensionParamssWithIndices map ( (clause, i) => (clause, memberInfo.paramLists(i)) ) flatMap { + case (terms: TermParamClause, EvidenceOnlyParameterList) => None + case (terms: TermParamClause, info: RegularParameterList) => + Some( TermParametersList( + terms.params.map( + mkParameter(_, paramPrefix, memberInfo = info) + ), + paramListModifier(terms.params) + )) + case (types: TypeParamClause, info: TypeParameterList) => + Some( TypeParametersList( + types.params.map( + mkTypeArgument(_, info, memberInfo.contextBounds) + ) + )) + + } + ) + /* + val basicKind: Kind.Def = Kind.Def( // TODO: sc genericTypes.map(mkTypeArgument(_, memberInfo.genericTypes, memberInfo.contextBounds)), paramLists.zipWithIndex.flatMap { (pList, index) => memberInfo.paramLists(index) match - case EvidenceOnlyParameterList => Nil - case info: RegularParameterList => - Seq(ParametersList(pList.params.map( - mkParameter(_, paramPrefix, memberInfo = info)), paramListModifier(pList.params) - )) + } ) + */ + + val numberOfTermParams = paramss.zipWithIndex.findLast{case _: TermParamClause => true case _ => false}.map((_, i) => i+1).getOrElse(0) + val firstTermParams: Option[TermParamClause] = paramss.collectFirst{case tpc: TermParamClause => tpc } + val firstTermParamsCount = firstTermParams.map(_.params.size).getOrElse(0) val methodKind = if methodSymbol.isClassConstructor then Kind.Constructor(basicKind) else if methodSymbol.flags.is(Flags.Implicit) then extractImplicitConversion(method.returnTpt.tpe) match - case Some(conversion) if paramLists.size == 0 || (paramLists.size == 1 && paramLists.head.params.size == 0) => + case Some(conversion) if numberOfTermParams == 0 || (numberOfTermParams == 1 && firstTermParamsCount == 0) => Kind.Implicit(basicKind, Some(conversion)) - case None if paramLists.size == 1 && paramLists(0).params.size == 1 => + case None if numberOfTermParams == 1 && firstTermParamsCount == 1 => Kind.Implicit(basicKind, Some( ImplicitConversion( - paramLists(0).params(0).tpt.tpe.typeSymbol.dri, + firstTermParams.get.params(0).tpt.tpe.typeSymbol.dri, method.returnTpt.tpe.typeSymbol.dri ) )) @@ -379,7 +409,7 @@ trait ClassLikeSupport: val inlinePrefix = if argument.symbol.flags.is(Flags.Inline) then "inline " else "" val nameIfNotSynthetic = Option.when(!argument.symbol.flags.is(Flags.Synthetic))(argument.symbol.normalizedName) val name = argument.symbol.normalizedName - Parameter( + TermParameter( argument.symbol.getAnnotations(), inlinePrefix + prefix(argument.symbol), nameIfNotSynthetic, @@ -474,10 +504,11 @@ trait ClassLikeSupport: object EvidenceOnlyParameterList type RegularParameterList = Map[String, TypeRepr] - type ParameterList = RegularParameterList | EvidenceOnlyParameterList.type + type TermParameterList = RegularParameterList | EvidenceOnlyParameterList.type + type TypeParameterList = Map[String, TypeBounds] + type ParameterList = TypeParameterList | TermParameterList case class MemberInfo( - genericTypes: Map[String, TypeBounds], paramLists: List[ParameterList], res: TypeRepr, contextBounds: Map[String, DSignature] = Map.empty, @@ -485,7 +516,6 @@ trait ClassLikeSupport: def unwrapMemberInfo(c: ClassDef, symbol: Symbol): MemberInfo = - val baseTypeRepr = memberInfo(c, symbol) def isSyntheticEvidence(name: String) = if !name.startsWith(NameKinds.EvidenceParamName.separator) then false else @@ -498,12 +528,12 @@ trait ClassLikeSupport: // Documenting method slightly different then its definition is withing the 'undefiend behaviour'. symbol.paramSymss.flatten.find(_.name == name).exists(_.flags.is(Flags.Implicit)) - def handlePolyType(polyType: PolyType): MemberInfo = - MemberInfo(polyType.paramNames.zip(polyType.paramBounds).toMap, List.empty, polyType.resType) + def handlePolyType(memberInfo: MemberInfo, polyType: PolyType): MemberInfo = + MemberInfo(memberInfo.paramLists :+ polyType.paramNames.zip(polyType.paramBounds).toMap, polyType.resType, memberInfo.contextBounds) def handleMethodType(memberInfo: MemberInfo, methodType: MethodType): MemberInfo = val rawParams = methodType.paramNames.zip(methodType.paramTypes).toMap - val (evidences, notEvidences) = rawParams.partition(e => isSyntheticEvidence(e._1)) + val (evidences, notEvidences) = rawParams.partition(e => isSyntheticEvidence(e._1)) def findParamRefs(t: TypeRepr): Seq[ParamRef] = t match @@ -532,22 +562,23 @@ trait ClassLikeSupport: val newParams = notEvidences ++ paramsThatLookLikeContextBounds - val newLists: List[ParameterList] = if newParams.isEmpty && contextBounds.nonEmpty + val newLists: List[TermParameterList] = if newParams.isEmpty && contextBounds.nonEmpty then memberInfo.paramLists ++ Seq(EvidenceOnlyParameterList) else memberInfo.paramLists ++ Seq(newParams) - - MemberInfo(memberInfo.genericTypes, newLists , methodType.resType, contextBounds.toMap) + + val baseTypeRepr: TypeRepr = memberInfo(c, symbol) + MemberInfo(newLists, methodType.resType, contextBounds.toMap) def handleByNameType(memberInfo: MemberInfo, byNameType: ByNameType): MemberInfo = - MemberInfo(memberInfo.genericTypes, memberInfo.paramLists, byNameType.underlying) + MemberInfo(memberInfo.paramLists, byNameType.underlying) def recursivelyCalculateMemberInfo(memberInfo: MemberInfo): MemberInfo = memberInfo.res match - case p: PolyType => recursivelyCalculateMemberInfo(handlePolyType(p)) + case p: PolyType => recursivelyCalculateMemberInfo(handlePolyType(memberInfo, p)) case m: MethodType => recursivelyCalculateMemberInfo(handleMethodType(memberInfo, m)) case b: ByNameType => handleByNameType(memberInfo, b) case _ => memberInfo - recursivelyCalculateMemberInfo(MemberInfo(Map.empty, List.empty, baseTypeRepr)) + recursivelyCalculateMemberInfo(MemberInfo(List.empty, baseTypeRepr)) private def paramListModifier(parameters: Seq[ValDef]): String = if parameters.size > 0 then diff --git a/scaladoc/src/dotty/tools/scaladoc/transformers/ImplicitMembersExtensionTransformer.scala b/scaladoc/src/dotty/tools/scaladoc/transformers/ImplicitMembersExtensionTransformer.scala index 0fa6b9c5d3cf..0e5de09ff0f6 100644 --- a/scaladoc/src/dotty/tools/scaladoc/transformers/ImplicitMembersExtensionTransformer.scala +++ b/scaladoc/src/dotty/tools/scaladoc/transformers/ImplicitMembersExtensionTransformer.scala @@ -29,7 +29,7 @@ class ImplicitMembersExtensionTransformer(using DocContext) extends(Module => Mo case m @ Member(_, _, _, Kind.Extension(ExtensionTarget(_, _, _, _, MyDri, _), _), Origin.RegularlyDefined) => val kind = m.kind match case d: Kind.Def => d - case _ => Kind.Def(Nil, Nil) + case _ => Kind.Def(Nil) Seq(m.withOrigin(Origin.ExtensionFrom(source.name, source.dri)).withKind(kind)) case m @ Member(_, _, _, conversionProvider: ImplicitConversionProvider, Origin.RegularlyDefined) => diff --git a/scaladoc/src/dotty/tools/scaladoc/translators/ScalaSignatureProvider.scala b/scaladoc/src/dotty/tools/scaladoc/translators/ScalaSignatureProvider.scala index 0639b5af09bd..4ba448f0b075 100644 --- a/scaladoc/src/dotty/tools/scaladoc/translators/ScalaSignatureProvider.scala +++ b/scaladoc/src/dotty/tools/scaladoc/translators/ScalaSignatureProvider.scala @@ -118,28 +118,25 @@ object ScalaSignatureProvider: parentsSignature(clazz, selfSignature) - private def extensionSignature(extension: Member, fun: Kind.Def, builder: SignatureBuilder): SignatureBuilder = + private def extensionSignature(extension: Member, fun: Kind.Def, builder: SignatureBuilder): SignatureBuilder = // TODO: sc val withSignature = builder .modifiersAndVisibility(extension, "def") .name(extension.name, extension.dri) - .generics(fun.typeParams) - .functionParameters(fun.argsLists) + .functionParameters2(fun.params) withSignature.plain(":").plain(" ").signature(extension.signature) - private def givenMethodSignature(method: Member, body: Kind.Def, builder: SignatureBuilder): SignatureBuilder = method.kind match + private def givenMethodSignature(method: Member, body: Kind.Def, builder: SignatureBuilder): SignatureBuilder = method.kind match // TODO: sc case Kind.Given(_, Some(instance), _) => builder.keyword("given ") .name(method.name, method.dri) - .generics(body.typeParams) - .functionParameters(body.argsLists) + .functionParameters2(body.params) .plain(": ") .signature(instance) case _ => builder.keyword("given ") .name(method.name, method.dri) - .generics(body.typeParams) - .functionParameters(body.argsLists) + .functionParameters2(body.params) private def givenValSignature(field: Member, builder: SignatureBuilder): SignatureBuilder = field.kind match case Kind.Given(_, Some(instance), _) => @@ -150,12 +147,12 @@ object ScalaSignatureProvider: case _ => builder.keyword("given ").name(field.name, field.dri) - private def methodSignature(method: Member, cls: Kind.Def, builder: SignatureBuilder): SignatureBuilder = + private def methodSignature(method: Member, cls: Kind.Def, builder: SignatureBuilder): SignatureBuilder = // TODO: sc val bdr = builder .modifiersAndVisibility(method, "def") .name(method.name, method.dri) - .generics(cls.typeParams) - .functionParameters(cls.argsLists) + .functionParameters2(cls.params) + if !method.kind.isInstanceOf[Kind.Constructor] then bdr.plain(": ").signature(method.signature) else bdr diff --git a/scaladoc/src/dotty/tools/scaladoc/translators/ScalaSignatureUtils.scala b/scaladoc/src/dotty/tools/scaladoc/translators/ScalaSignatureUtils.scala index 7a5dc2310c0e..28b082e1f7ff 100644 --- a/scaladoc/src/dotty/tools/scaladoc/translators/ScalaSignatureUtils.scala +++ b/scaladoc/src/dotty/tools/scaladoc/translators/ScalaSignatureUtils.scala @@ -44,7 +44,7 @@ trait SignatureBuilder extends ScalaSignatureUtils { def annotationsBlock(d: Member): SignatureBuilder = d.annotations.foldLeft(this){ (bdr, annotation) => bdr.buildAnnotation(annotation)} - def annotationsInline(d: Parameter): SignatureBuilder = + def annotationsInline(d: TermParameter): SignatureBuilder = d.annotations.foldLeft(this){ (bdr, annotation) => bdr.buildAnnotation(annotation) } def annotationsInline(t: TypeParameter): SignatureBuilder = @@ -87,7 +87,7 @@ trait SignatureBuilder extends ScalaSignatureUtils { bdr.annotationsInline(e).keyword(e.variance).tpe(e.name, Some(e.dri)).signature(e.signature) } - def functionParameters(params: Seq[ParametersList]) = + def functionParameters(params: Seq[TermParametersList]) = if params.isEmpty then this.plain("") else if params.size == 1 && params(0).parameters == Nil then this.plain("()") else this.list(params, separator = List(Plain(""))) { (bld, pList) => @@ -98,8 +98,23 @@ trait SignatureBuilder extends ScalaSignatureUtils { name.signature(p.signature) } } + /* + def functionParameter = + (bdr: SignatureBuilder, param: TypeParametersList | TermParametersList) => param match { + case types: TypeParameterList => generics(ts) + case terms: TermParametersList => functionParameters(terms) + } */ + + def functionParameters2(params: Seq[TypeParametersList | TermParametersList]) = params.foldLeft(this){ (bdr, params) => params match { + case types: TypeParametersList => bdr.generics(types.parameters) + case terms: TermParametersList => bdr.functionParameters(Seq(terms)) + }} // TODO: sc + + } + + trait ScalaSignatureUtils: extension (tokens: Seq[String]) def toSignatureString(): String = tokens.filter(_.trim.nonEmpty).mkString(""," "," ") From efd499f176b5dc1fe46f400f68a22a3e6d24bc91 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Sat, 26 Feb 2022 19:43:50 +0100 Subject: [PATCH 6/8] Almost working --- .../scaladoc/tasty/ClassLikeSupport.scala | 100 ++++++++++++------ 1 file changed, 68 insertions(+), 32 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 928ccb4b4f86..1effda639775 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -9,7 +9,7 @@ import scala.quoted._ import SymOps._ import NameNormalizer._ -import SyntheticsSupport._ +import SyntheticsSupport.{memberInfo => ssMemberInfo, _} import dotty.tools.dotc.core.NameKinds trait ClassLikeSupport: @@ -130,20 +130,34 @@ trait ClassLikeSupport: case dd: DefDef if isDocumentableExtension(dd.symbol) => dd.symbol.extendedSymbol.map { extSym => val memberInfo = unwrapMemberInfo(c, dd.symbol) - val typeParams = dd.symbol.extendedTypeParamList.map(mkTypeArgument(_, memberInfo.genericTypes)) + //val typeParams = dd.symbol.extendedTypeParamList.map(mkTypeArgument(_, memberInfo.typeParamLists.headOption.getOrElse(Map()))) //assumes provided type param is always LHS y //println(dd.name) //println("MemberInfo:\n" + memberInfo.paramLists) //println("extended...:\n" + dd.symbol.extendedTermParamLists) - val termParams = dd.symbol.extendedTermParamLists.zipWithIndex.flatMap { case (paramList, index) => + /*val termParams = dd.symbol.extendedTermParamLists.zipWithIndex.flatMap { case (paramList, index) => memberInfo.paramLists(index) match - case EvidenceOnlyParameterList => Nil - case info: RegularParameterList => - Seq(TermParametersList(paramList.params.map(mkParameter(_, memberInfo = info)), paramListModifier(paramList.params))) + case Right(EvidenceOnlyParameterList) => Nil + case Right(info: RegularParameterList) => + Seq(TermParametersList(paramList.params.map(mkParameter(_, memberMap = info)), paramListModifier(paramList.params))) + case Left(types: TypeParameterList) => + throw new Error(s"Mismatch between extendedTermParamLists and memberInfo.paramLists: \n ${dd.symbol.extendedTermParamLists.mkString("extendedTermParamLists:\n ","\n ", "\n")} \n ${memberInfo.paramLists.mkString("memberInfo.paramLists:\n ","\n ", "\n")}") + }*/ + assert(dd.symbol.extendedParamLists.length == memberInfo.extendedParamLists.length) + val paramss: List[Either[List[TypeParameter], TermParametersList]] = (dd.symbol.extendedParamLists zip memberInfo.extendedParamLists).flatMap{ + case (terms: TermParamClause, Right(EvidenceOnlyParameterList)) => None + case (terms: TermParamClause, Right(info: RegularParameterList)) => + Some(Right(TermParametersList(terms.params.map(mkParameter(_, memberMap = info)), paramListModifier(terms.params)))) + case (TypeParamClause(types), Left(info: TypeParameterList)) => + Some(Left(types.map(mkTypeArgument(_, info)))) + case _ => + throw new Error(s"Mismatch between extendedParamLists and memberInfo.paramLists: \n ${dd.symbol.extendedParamLists.mkString("extendedParamLists:\n ","\n ", "\n")} \n ${memberInfo.paramLists.mkString("memberInfo.paramLists:\n ","\n ", "\n")}") } + val typeParams = paramss.collect{case Left(types: List[TypeParameter]) => types}.lift(0).getOrElse(List()) + val termParamss = paramss.collect{case Right(terms: TermParametersList) => terms} val target = ExtensionTarget( extSym.symbol.normalizedName, typeParams, - termParams, + termParamss, extSym.tpt.asSignature, extSym.tpt.symbol.dri, extSym.symbol.pos.get.start @@ -337,7 +351,7 @@ trait ClassLikeSupport: val memberInfo = unwrapMemberInfo(c, methodSymbol) - assert(allParamss.size == memberInfo.paramLists.size) + assert(allParamss.length == memberInfo.paramLists.length) // assumes method is left-associative // finds indices in memberInfo.paramLists corresponding to nonExtensionParamss @@ -346,20 +360,23 @@ trait ClassLikeSupport: val basicKind: Kind.Def = Kind.Def( nonExtensionParamssWithIndices map ( (clause, i) => (clause, memberInfo.paramLists(i)) ) flatMap { - case (terms: TermParamClause, EvidenceOnlyParameterList) => None - case (terms: TermParamClause, info: RegularParameterList) => + case (terms: TermParamClause, Right(EvidenceOnlyParameterList)) => None + case (terms: TermParamClause, Right(info: RegularParameterList)) => Some( TermParametersList( terms.params.map( - mkParameter(_, paramPrefix, memberInfo = info) + mkParameter(_, paramPrefix, memberMap = info) ), paramListModifier(terms.params) )) - case (types: TypeParamClause, info: TypeParameterList) => + case (types: TypeParamClause, Left(info: TypeParameterList)) => Some( TypeParametersList( types.params.map( mkTypeArgument(_, info, memberInfo.contextBounds) ) )) + case (_, _) => + throw new Error(s"Mismatch between nonExtensionParamssWithIndices and memberInfo.paramLists: \n $nonExtensionParamssWithIndices \n ${memberInfo.paramLists}") + } ) @@ -373,8 +390,8 @@ trait ClassLikeSupport: ) */ - val numberOfTermParams = paramss.zipWithIndex.findLast{case _: TermParamClause => true case _ => false}.map((_, i) => i+1).getOrElse(0) - val firstTermParams: Option[TermParamClause] = paramss.collectFirst{case tpc: TermParamClause => tpc } + val numberOfTermParams = nonExtensionParamss.zipWithIndex.findLast{case (_: TermParamClause, _) => true case _ => false}.map((_, i) => i+1).getOrElse(0) + val firstTermParams: Option[TermParamClause] = nonExtensionParamss.collectFirst{case tpc: TermParamClause => tpc } val firstTermParamsCount = firstTermParams.map(_.params.size).getOrElse(0) val methodKind = @@ -405,7 +422,7 @@ trait ClassLikeSupport: prefix: Symbol => String = _ => "", isExtendedSymbol: Boolean = false, isGrouped: Boolean = false, - memberInfo: Map[String, TypeRepr] = Map.empty) = + memberMap: Map[String, TypeRepr] = Map.empty) = val inlinePrefix = if argument.symbol.flags.is(Flags.Inline) then "inline " else "" val nameIfNotSynthetic = Option.when(!argument.symbol.flags.is(Flags.Synthetic))(argument.symbol.normalizedName) val name = argument.symbol.normalizedName @@ -414,14 +431,14 @@ trait ClassLikeSupport: inlinePrefix + prefix(argument.symbol), nameIfNotSynthetic, argument.symbol.dri, - memberInfo.get(name).fold(argument.tpt.asSignature)(_.asSignature), + memberMap.get(name).fold(argument.tpt.asSignature)(_.asSignature), isExtendedSymbol, isGrouped ) def mkTypeArgument( argument: TypeDef, - memberInfo: Map[String, TypeBounds] = Map.empty, + memberMap: Map[String, TypeBounds] = Map.empty, contextBounds: Map[String, DSignature] = Map.empty ): TypeParameter = val variancePrefix: "+" | "-" | "" = @@ -431,7 +448,7 @@ trait ClassLikeSupport: val name = argument.symbol.normalizedName val normalizedName = if name.matches("_\\$\\d*") then "_" else name - val boundsSignature = memberInfo.get(name).fold(argument.rhs.asSignature)(_.asSignature) + val boundsSignature = memberMap.get(name).fold(argument.rhs.asSignature)(_.asSignature) val signature = contextBounds.get(name) match case None => boundsSignature case Some(contextBoundsSignature) => @@ -506,16 +523,24 @@ trait ClassLikeSupport: type RegularParameterList = Map[String, TypeRepr] type TermParameterList = RegularParameterList | EvidenceOnlyParameterList.type type TypeParameterList = Map[String, TypeBounds] - type ParameterList = TypeParameterList | TermParameterList + type ParameterList = Either[TypeParameterList, TermParameterList] case class MemberInfo( - paramLists: List[ParameterList], + extendedParamLists: List[ParameterList], + nonExtensionParamLists: List[ParameterList], res: TypeRepr, contextBounds: Map[String, DSignature] = Map.empty, - ) + ){ + def typeParamLists: List[TypeParameterList] = paramLists.collect{case Left(tps) => tps} + def paramLists = extendedParamLists ++ nonExtensionParamLists + } def unwrapMemberInfo(c: ClassDef, symbol: Symbol): MemberInfo = + + val defCoord = symbol.pos.get.start + // Incomplete: doesn't handle right assos + def isExtensionTarget(t: MethodType | PolyType) = t.typeSymbol.pos.map(_.start < defCoord).getOrElse{println(t.show); true} def isSyntheticEvidence(name: String) = if !name.startsWith(NameKinds.EvidenceParamName.separator) then false else @@ -529,7 +554,13 @@ trait ClassLikeSupport: symbol.paramSymss.flatten.find(_.name == name).exists(_.flags.is(Flags.Implicit)) def handlePolyType(memberInfo: MemberInfo, polyType: PolyType): MemberInfo = - MemberInfo(memberInfo.paramLists :+ polyType.paramNames.zip(polyType.paramBounds).toMap, polyType.resType, memberInfo.contextBounds) + val paramList = Left(polyType.paramNames.zip(polyType.paramBounds).toMap) + + if(isExtensionTarget(polyType)){ + memberInfo.copy(extendedParamLists = memberInfo.extendedParamLists :+ paramList, res = polyType.resType) + }else{ + memberInfo.copy(nonExtensionParamLists = memberInfo.nonExtensionParamLists :+ paramList, res = polyType.resType) + } def handleMethodType(memberInfo: MemberInfo, methodType: MethodType): MemberInfo = val rawParams = methodType.paramNames.zip(methodType.paramTypes).toMap @@ -547,7 +578,7 @@ trait ClassLikeSupport: val PolyType(names, _, _) = ref.binder names(ref.paramNum) - val (paramsThatLookLikeContextBounds, contextBounds) = + val (paramsThatLookLikeContextBounds, newContextBounds) = evidences.partitionMap { case (_, AppliedType(tpe, List(typeParam: ParamRef))) => Right(nameForRef(typeParam) -> tpe.asSignature) @@ -562,23 +593,28 @@ trait ClassLikeSupport: val newParams = notEvidences ++ paramsThatLookLikeContextBounds - val newLists: List[TermParameterList] = if newParams.isEmpty && contextBounds.nonEmpty - then memberInfo.paramLists ++ Seq(EvidenceOnlyParameterList) - else memberInfo.paramLists ++ Seq(newParams) - - val baseTypeRepr: TypeRepr = memberInfo(c, symbol) - MemberInfo(newLists, methodType.resType, contextBounds.toMap) + val paramList: ParameterList = Right(if newParams.isEmpty && newContextBounds.nonEmpty + then EvidenceOnlyParameterList + else newParams + ) + + if(isExtensionTarget(methodType)){ + memberInfo.copy(extendedParamLists = memberInfo.extendedParamLists :+ paramList, res = methodType.resType, contextBounds = newContextBounds.toMap) + }else{ + memberInfo.copy(nonExtensionParamLists = memberInfo.nonExtensionParamLists :+ paramList, res = methodType.resType, contextBounds = newContextBounds.toMap) + } def handleByNameType(memberInfo: MemberInfo, byNameType: ByNameType): MemberInfo = - MemberInfo(memberInfo.paramLists, byNameType.underlying) + memberInfo.copy(res = byNameType.underlying) def recursivelyCalculateMemberInfo(memberInfo: MemberInfo): MemberInfo = memberInfo.res match case p: PolyType => recursivelyCalculateMemberInfo(handlePolyType(memberInfo, p)) case m: MethodType => recursivelyCalculateMemberInfo(handleMethodType(memberInfo, m)) case b: ByNameType => handleByNameType(memberInfo, b) case _ => memberInfo - - recursivelyCalculateMemberInfo(MemberInfo(List.empty, baseTypeRepr)) + + val baseTypeRepr: TypeRepr = ssMemberInfo(c, symbol) + recursivelyCalculateMemberInfo(MemberInfo(List.empty, List.empty, res = baseTypeRepr)) private def paramListModifier(parameters: Seq[ValDef]): String = if parameters.size > 0 then From 322aa13454c4789034d016905200fd9680e38356 Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Thu, 7 Apr 2022 17:12:27 +0200 Subject: [PATCH 7/8] Works again when no type params --- .../scaladoc/tasty/ClassLikeSupport.scala | 82 ++++++++++++++----- 1 file changed, 61 insertions(+), 21 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 1effda639775..bb646700e93e 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -126,6 +126,8 @@ trait ClassLikeSupport: private def isDocumentableExtension(s: Symbol) = !s.isHiddenByVisibility && !s.isSyntheticFunc && s.isExtensionMethod + private def _debugStringParamLists(name: String, l: List[Any]) = l.mkString(s"$name:\n ","\n ", "\n") + private def parseMember(c: ClassDef)(s: Tree): Option[Member] = processTreeOpt(s) { s match case dd: DefDef if isDocumentableExtension(dd.symbol) => dd.symbol.extendedSymbol.map { extSym => @@ -142,16 +144,66 @@ trait ClassLikeSupport: case Left(types: TypeParameterList) => throw new Error(s"Mismatch between extendedTermParamLists and memberInfo.paramLists: \n ${dd.symbol.extendedTermParamLists.mkString("extendedTermParamLists:\n ","\n ", "\n")} \n ${memberInfo.paramLists.mkString("memberInfo.paramLists:\n ","\n ", "\n")}") }*/ - assert(dd.symbol.extendedParamLists.length == memberInfo.extendedParamLists.length) - val paramss: List[Either[List[TypeParameter], TermParametersList]] = (dd.symbol.extendedParamLists zip memberInfo.extendedParamLists).flatMap{ + val mismatchString = s"""Mismatch between extendedParamLists and memberInfo.extendedParamLists: + |${dd.symbol.extendedParamLists.mkString("extendedParamLists:\n ","\n ", "\n")} + |${memberInfo.paramLists.mkString("memberInfo.paramLists:\n ","\n ", "\n")} + |""".stripMargin + // We match clauses in dd.symbol.extendedParamLists and X by the'r first element (which we call the representative) + // TODO: handle the case EvidenceOnlyParameterList + val paramss: List[Either[List[TypeParameter], TermParametersList]] = dd.symbol.extendedParamLists.map{ + case TermParamClause(terms) => + val representative: ValDef = terms.head // RegularParameterList = Map[String, TypeRepr] + val ValDef(name: String, _, _) = representative + + val candidates = memberInfo.paramLists.collect{ case Right(info: RegularParameterList) => info }.filter( _ contains name ) + val extradebug = s""" + |representative: $representative + |name: $name + |candidates: $candidates + |size: ${candidates.size} + | + |""" + if(candidates.size != 1){ + throw new Error(extradebug + mismatchString) + }else{ + val info = candidates.head + Right(TermParametersList(terms.map(mkParameter(_, memberMap = info)), paramListModifier(terms))) + } + + case TypeParamClause(types) => + val representative = types.head + val TypeDef(name: String, _) = representative + + ??? + } + + /* + extendedParamLists: + List(TypeDef(A,TypeBoundsTree(TypeTree[TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class )),object scala),Nothing)],TypeTree[TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class )),object scala),Any)],EmptyTree))) + List(ValDef(a,Ident(A),EmptyTree)) + List(ValDef(x$2,Ident(Int),EmptyTree)) + + memberInfo.paramLists: + Left(Map(A -> TypeBounds(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class )),object scala),Nothing),TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class )),object scala),Any)))) + Right(Map(a -> TypeParamRef(A))) + Right(Map(x$2 -> TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class )),object scala),Int))) + Left(Map(B -> TypeBounds(TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class )),object scala),Nothing),TypeRef(TermRef(ThisType(TypeRef(NoPrefix,module class )),object scala),Any)))) + Right(Map(b -> TypeParamRef(B))) + */ + + // not valid assumption, will have to find members with the same name ! + //assert(dd.symbol.extendedParamLists.length == memberInfo.paramLists.length, mismatchString) + /* + val paramss: List[Either[List[TypeParameter], TermParametersList]] = (dd.symbol.extendedParamLists zip memberInfo.paramLists).flatMap{ case (terms: TermParamClause, Right(EvidenceOnlyParameterList)) => None case (terms: TermParamClause, Right(info: RegularParameterList)) => Some(Right(TermParametersList(terms.params.map(mkParameter(_, memberMap = info)), paramListModifier(terms.params)))) case (TypeParamClause(types), Left(info: TypeParameterList)) => Some(Left(types.map(mkTypeArgument(_, info)))) case _ => - throw new Error(s"Mismatch between extendedParamLists and memberInfo.paramLists: \n ${dd.symbol.extendedParamLists.mkString("extendedParamLists:\n ","\n ", "\n")} \n ${memberInfo.paramLists.mkString("memberInfo.paramLists:\n ","\n ", "\n")}") + throw new Error(mismatchString) } + */ val typeParams = paramss.collect{case Left(types: List[TypeParameter]) => types}.lift(0).getOrElse(List()) val termParamss = paramss.collect{case Right(terms: TermParametersList) => terms} val target = ExtensionTarget( @@ -526,21 +578,17 @@ trait ClassLikeSupport: type ParameterList = Either[TypeParameterList, TermParameterList] case class MemberInfo( - extendedParamLists: List[ParameterList], - nonExtensionParamLists: List[ParameterList], + paramLists: List[ParameterList], res: TypeRepr, contextBounds: Map[String, DSignature] = Map.empty, ){ - def typeParamLists: List[TypeParameterList] = paramLists.collect{case Left(tps) => tps} - def paramLists = extendedParamLists ++ nonExtensionParamLists + //def typeParamLists: List[TypeParameterList] = paramLists.collect{case Left(tps) => tps} } def unwrapMemberInfo(c: ClassDef, symbol: Symbol): MemberInfo = val defCoord = symbol.pos.get.start - // Incomplete: doesn't handle right assos - def isExtensionTarget(t: MethodType | PolyType) = t.typeSymbol.pos.map(_.start < defCoord).getOrElse{println(t.show); true} def isSyntheticEvidence(name: String) = if !name.startsWith(NameKinds.EvidenceParamName.separator) then false else @@ -556,11 +604,7 @@ trait ClassLikeSupport: def handlePolyType(memberInfo: MemberInfo, polyType: PolyType): MemberInfo = val paramList = Left(polyType.paramNames.zip(polyType.paramBounds).toMap) - if(isExtensionTarget(polyType)){ - memberInfo.copy(extendedParamLists = memberInfo.extendedParamLists :+ paramList, res = polyType.resType) - }else{ - memberInfo.copy(nonExtensionParamLists = memberInfo.nonExtensionParamLists :+ paramList, res = polyType.resType) - } + memberInfo.copy(memberInfo.paramLists :+ paramList, polyType.resType) def handleMethodType(memberInfo: MemberInfo, methodType: MethodType): MemberInfo = val rawParams = methodType.paramNames.zip(methodType.paramTypes).toMap @@ -597,12 +641,8 @@ trait ClassLikeSupport: then EvidenceOnlyParameterList else newParams ) - - if(isExtensionTarget(methodType)){ - memberInfo.copy(extendedParamLists = memberInfo.extendedParamLists :+ paramList, res = methodType.resType, contextBounds = newContextBounds.toMap) - }else{ - memberInfo.copy(nonExtensionParamLists = memberInfo.nonExtensionParamLists :+ paramList, res = methodType.resType, contextBounds = newContextBounds.toMap) - } + + memberInfo.copy(memberInfo.paramLists :+ paramList, methodType.resType, contextBounds = newContextBounds.toMap) def handleByNameType(memberInfo: MemberInfo, byNameType: ByNameType): MemberInfo = memberInfo.copy(res = byNameType.underlying) @@ -614,7 +654,7 @@ trait ClassLikeSupport: case _ => memberInfo val baseTypeRepr: TypeRepr = ssMemberInfo(c, symbol) - recursivelyCalculateMemberInfo(MemberInfo(List.empty, List.empty, res = baseTypeRepr)) + recursivelyCalculateMemberInfo(MemberInfo(List.empty, baseTypeRepr)) private def paramListModifier(parameters: Seq[ValDef]): String = if parameters.size > 0 then From 4682644c57d57a0a72f70b87339f8efdb04403ff Mon Sep 17 00:00:00 2001 From: Quentin Bernet Date: Thu, 7 Apr 2022 17:44:49 +0200 Subject: [PATCH 8/8] It works ! --- .../scaladoc/tasty/ClassLikeSupport.scala | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index bb646700e93e..798d95b27cd4 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -150,7 +150,7 @@ trait ClassLikeSupport: |""".stripMargin // We match clauses in dd.symbol.extendedParamLists and X by the'r first element (which we call the representative) // TODO: handle the case EvidenceOnlyParameterList - val paramss: List[Either[List[TypeParameter], TermParametersList]] = dd.symbol.extendedParamLists.map{ + val paramss: List[Either[List[TypeParameter], TermParametersList]] = dd.symbol.extendedParamLists.flatMap{ case TermParamClause(terms) => val representative: ValDef = terms.head // RegularParameterList = Map[String, TypeRepr] val ValDef(name: String, _, _) = representative @@ -163,18 +163,31 @@ trait ClassLikeSupport: |size: ${candidates.size} | |""" + if(candidates.size != 1){ - throw new Error(extradebug + mismatchString) + if(candidates.size == 0 && memberInfo.paramLists.exists{ case Right(EvidenceOnlyParameterList) => true; case _ => false}){ + // In this case it is possible the matching info was actually the EvidenceOnlyParameterList + None + } else{ + throw new Error(extradebug + mismatchString) + } }else{ val info = candidates.head - Right(TermParametersList(terms.map(mkParameter(_, memberMap = info)), paramListModifier(terms))) + Some(Right(TermParametersList(terms.map(mkParameter(_, memberMap = info)), paramListModifier(terms)))) } case TypeParamClause(types) => val representative = types.head val TypeDef(name: String, _) = representative - ??? + val candidates = memberInfo.paramLists.collect{ case Left(info: TypeParameterList) => info }.filter( _ contains name ) // TypeBounds + + if(candidates.size != 1){ + throw new Error(mismatchString) + }else{ + val info = candidates.head + Some(Left(types.map(mkTypeArgument(_, info)))) + } } /*