@@ -10,6 +10,7 @@ import scala.quoted._
1010import SymOps ._
1111import NameNormalizer ._
1212import SyntheticsSupport ._
13+ import dotty .tools .dotc .core .NameKinds
1314
1415trait ClassLikeSupport :
1516 self : TastyParser =>
@@ -476,9 +477,14 @@ trait ClassLikeSupport:
476477 val memberInfo = unwrapMemberInfo(c, methodSymbol)
477478
478479 val basicKind : Kind .Def = Kind .Def (
479- genericTypes.map(mkTypeArgument(_, memberInfo.genericTypes)),
480- paramLists.zipWithIndex.map { (pList, index) =>
481- ParametersList (pList.params.map(mkParameter(_, paramPrefix, memberInfo = memberInfo.paramLists(index))), paramListModifier(pList.params))
480+ genericTypes.map(mkTypeArgument(_, memberInfo.genericTypes, memberInfo.contextBounds)),
481+ paramLists.zipWithIndex.flatMap { (pList, index) =>
482+ memberInfo.paramLists(index) match
483+ case EvidenceOnlyParameterList => Nil
484+ case info : RegularParameterList =>
485+ Seq (ParametersList (pList.params.map(
486+ mkParameter(_, paramPrefix, memberInfo = info)), paramListModifier(pList.params)
487+ ))
482488 }
483489 )
484490
@@ -523,20 +529,30 @@ trait ClassLikeSupport:
523529 isGrouped
524530 )
525531
526- def mkTypeArgument (argument : TypeDef , memberInfo : Map [String , TypeBounds ] = Map .empty): TypeParameter =
532+ def mkTypeArgument (
533+ argument : TypeDef ,
534+ memberInfo : Map [String , TypeBounds ] = Map .empty,
535+ contextBounds : Map [String , DSignature ] = Map .empty
536+ ): TypeParameter =
527537 val variancePrefix : " +" | " -" | " " =
528538 if argument.symbol.flags.is(Flags .Covariant ) then " +"
529539 else if argument.symbol.flags.is(Flags .Contravariant ) then " -"
530540 else " "
531541
532542 val name = argument.symbol.normalizedName
533543 val normalizedName = if name.matches(" _\\ $\\ d*" ) then " _" else name
544+ val boundsSignature = memberInfo.get(name).fold(argument.rhs.asSignature)(_.asSignature)
545+ val signature = contextBounds.get(name) match
546+ case None => boundsSignature
547+ case Some (contextBoundsSignature) =>
548+ boundsSignature ++ DSignature (" : " ) ++ contextBoundsSignature
549+
534550 TypeParameter (
535551 argument.symbol.getAnnotations(),
536552 variancePrefix,
537553 normalizedName,
538554 argument.symbol.dri,
539- memberInfo.get(name).fold(argument.rhs.asSignature)(_.asSignature)
555+ signature
540556 )
541557
542558 def parseTypeDef (typeDef : TypeDef ): Member =
@@ -586,16 +602,71 @@ trait ClassLikeSupport:
586602 deprecated = deprecated
587603 )
588604
589- case class MemberInfo (genericTypes : Map [String , TypeBounds ], paramLists : List [Map [String , TypeRepr ]], res : TypeRepr )
605+ object EvidenceOnlyParameterList
606+ type RegularParameterList = Map [String , TypeRepr ]
607+ type ParameterList = RegularParameterList | EvidenceOnlyParameterList .type
608+
609+ case class MemberInfo (
610+ genericTypes : Map [String , TypeBounds ],
611+ paramLists : List [ParameterList ],
612+ res : TypeRepr ,
613+ contextBounds : Map [String , DSignature ] = Map .empty,
614+ )
615+
590616
591617 def unwrapMemberInfo (c : ClassDef , symbol : Symbol ): MemberInfo =
592618 val baseTypeRepr = memberInfo(c, symbol)
593619
620+ def isSyntheticEvidence (name : String ) =
621+ if ! name.startsWith(NameKinds .EvidenceParamName .separator) then false else
622+ // This assumes that every parameter that starts with `evidence$` and is implicit is generated by compiler to desugar context bound.
623+ // Howrever, this is just a heuristic, so
624+ // `def foo[A](evidence$1: ClassTag[A]) = 1`
625+ // will be documented as
626+ // `def foo[A: ClassTag] = 1`.
627+ // Scala spec states that `$` should not be used in names and behaviour may be undefiend in such case.
628+ // Documenting method slightly different then its definition is withing the 'undefiend behaviour'.
629+ symbol.paramSymss.flatten.find(_.name == name).exists(_.flags.is(Flags .Implicit ))
630+
594631 def handlePolyType (polyType : PolyType ): MemberInfo =
595632 MemberInfo (polyType.paramNames.zip(polyType.paramBounds).toMap, List .empty, polyType.resType)
596633
597634 def handleMethodType (memberInfo : MemberInfo , methodType : MethodType ): MemberInfo =
598- MemberInfo (memberInfo.genericTypes, memberInfo.paramLists ++ List (methodType.paramNames.zip(methodType.paramTypes).toMap), methodType.resType)
635+ val rawParams = methodType.paramNames.zip(methodType.paramTypes).toMap
636+ val (evidences, notEvidences) = rawParams.partition(e => isSyntheticEvidence(e._1))
637+
638+
639+ def findParamRefs (t : TypeRepr ): Seq [ParamRef ] = t match
640+ case paramRef : ParamRef => Seq (paramRef)
641+ case AppliedType (_, args) => args.flatMap(findParamRefs)
642+ case MatchType (bound, scrutinee, cases) =>
643+ findParamRefs(bound) ++ findParamRefs(scrutinee)
644+ case _ => Nil
645+
646+ def nameForRef (ref : ParamRef ): String =
647+ val PolyType (names, _, _) = ref.binder
648+ names(ref.paramNum)
649+
650+ val (paramsThatLookLikeContextBounds, contextBounds) =
651+ evidences.partitionMap {
652+ case (_, AppliedType (tpe, List (typeParam : ParamRef ))) =>
653+ Right (nameForRef(typeParam) -> tpe.asSignature)
654+ case (name, original) =>
655+ findParamRefs(original) match
656+ case Nil => Left ((name, original))
657+ case typeParam :: _ =>
658+ val name = nameForRef(typeParam)
659+ val signature = Seq (s " ([ $name] =>> " ) ++ original.asSignature ++ Seq (" )" )
660+ Right (name -> signature)
661+ }
662+
663+ val newParams = notEvidences ++ paramsThatLookLikeContextBounds
664+
665+ val newLists : List [ParameterList ] = if newParams.isEmpty && contextBounds.nonEmpty
666+ then memberInfo.paramLists ++ Seq (EvidenceOnlyParameterList )
667+ else memberInfo.paramLists ++ Seq (newParams)
668+
669+ MemberInfo (memberInfo.genericTypes, newLists , methodType.resType, contextBounds.toMap)
599670
600671 def handleByNameType (memberInfo : MemberInfo , byNameType : ByNameType ): MemberInfo =
601672 MemberInfo (memberInfo.genericTypes, memberInfo.paramLists, byNameType.underlying)
0 commit comments