@@ -246,8 +246,14 @@ object Signatures {
246246
247247 val pre = treeQualifier(fun)
248248 val alternativesWithTypes = alternatives.map(_.asSeenFrom(pre.tpe))
249+ val typeArgs = extractTypeArgs(fun)
250+ def isBoring (tp : Type ) =
251+ val t = tp.widenTermRefExpr
252+ t.isRef(ctx.definitions.AnyClass ) || t.isRef(ctx.definitions.NothingClass ) || t.isRef(ctx.definitions.NullClass )
253+
254+ val usefulTypeArgs = if typeArgs.flatten.exists(! isBoring(_)) then typeArgs else Nil
249255 val alternativeSignatures = alternativesWithTypes
250- .flatMap(toApplySignature(_ , findOutermostCurriedApply(untpdPath), safeParamssListIndex ))
256+ .flatMap(denot => toApplySignature(denot , findOutermostCurriedApply(untpdPath), usefulTypeArgs ))
251257
252258 val totalParamCount = alternativeSymbol.paramSymss.foldLeft(0 )(_ + _.length)
253259 val finalParamIndex =
@@ -471,12 +477,9 @@ object Signatures {
471477 *
472478 * @return Signature if denot is a function, None otherwise
473479 */
474- private def toApplySignature (
475- denot : SingleDenotation ,
476- untpdFun : Option [untpd.GenericApply ],
477- paramssIndex : Int
478- )(using Context ): Option [Signature ] = {
480+ private def toApplySignature (denot : SingleDenotation , untpdFun : Option [untpd.GenericApply ], typeArgs : List [List [Type ]] = Nil )(using Context ): Option [Signatures .Signature ] = {
479481 val symbol = denot.symbol
482+ val info = denot.info
480483 val docComment = ParsedComment .docOf(symbol)
481484
482485 def isDummyImplicit (res : MethodType ): Boolean =
@@ -495,11 +498,6 @@ object Signatures {
495498 case untpd.GenericApply (fun : untpd.GenericApply , args) => toApplyList(fun) :+ tree
496499 case _ => List (tree)
497500
498- def toMethodTypeList (tpe : Type ): List [Type ] =
499- tpe.resultType match
500- case res : MethodOrPoly => toMethodTypeList(res) :+ tpe
501- case res => List (tpe)
502-
503501 def isSyntheticEvidence (name : String ) =
504502 name.startsWith(NameKinds .ContextBoundParamName .separator)
505503 && symbol.paramSymss.flatten.find(_.name.show == name).exists(_.flags.isOneOf(Flags .GivenOrImplicit ))
@@ -518,33 +516,49 @@ object Signatures {
518516 case Some (evidenceTypeName) => TypeParam (s " ${name.show}: ${evidenceTypeName}" )
519517 case None => TypeParam (name.show + info.show)
520518
521- def toParamss (tp : Type , fun : Option [untpd.GenericApply ])(using Context ): List [List [Param ]] =
519+ def toParamss (tp : Type , fun : Option [untpd.GenericApply ], typeArgs : List [ List [ Type ]] )(using Context ): List [List [Param ]] =
522520 val paramSymss = symbol.paramSymss
521+ val applies = fun.map(toApplyList).getOrElse(Nil )
523522
524- def reduceToParamss (applies : List [untpd.Tree ], types : List [Type ], paramList : Int = 0 ): List [List [Param ]] =
525- applies -> types match
526- case ((_ : untpd.TypeApply ) :: restTrees, (poly : PolyType ) :: restTypes) =>
527- toTypeParam(poly) :: reduceToParamss(restTrees, restTypes, paramList + 1 )
528- case (restTrees, (poly : PolyType ) :: restTypes) =>
529- toTypeParam(poly) :: reduceToParamss(restTrees, restTypes, paramList + 1 )
530- case ((apply : untpd.GenericApply ) :: other, tpe :: otherType) =>
531- toParams(tpe, Some (apply), paramList) :: reduceToParamss(other, otherType, paramList + 1 )
532- case (other, (tpe @ MethodTpe (names, _, _)) :: otherType) if ! isDummyImplicit(tpe) =>
533- toParams(tpe, None , paramList) :: reduceToParamss(other, otherType, paramList + 1 )
534- case _ => Nil
523+ def loop (tp : Type , applies : List [untpd.Tree ], typeArgs : List [List [Type ]], paramListIndex : Int ): List [List [Param ]] = tp match
524+ case pt : PolyType =>
525+ val (visualParams, nextTp, nextTypeArgs) = typeArgs match
526+ case head :: tail =>
527+ (head.map(arg => TypeParam (arg.show)), pt.appliedTo(head), tail)
528+ case _ =>
529+ (toTypeParam(pt), pt.resType, Nil )
530+
531+ val nextApplies = applies match
532+ case (head : untpd.TypeApply ) :: tail => tail
533+ case _ => applies
534+
535+ visualParams :: loop(nextTp, nextApplies, nextTypeArgs, paramListIndex + 1 )
536+
537+ case mt : MethodType =>
538+ if isDummyImplicit(mt) then
539+ loop(mt.resType, applies, typeArgs, paramListIndex + 1 )
540+ else
541+ val (currentApply, nextApplies) = applies match
542+ case (head : untpd.GenericApply ) :: tail => (Some (head), tail)
543+ case _ => (None , applies)
544+
545+ toParams(mt, currentApply, paramListIndex) :: loop(mt.resType, nextApplies, typeArgs, paramListIndex + 1 )
546+
547+ case _ => Nil
535548
536549 def toParams (tp : Type , apply : Option [untpd.GenericApply ], paramList : Int )(using Context ): List [Param ] =
537550 val currentParams = (paramSymss.lift(paramList), tp.paramInfoss.headOption) match
538551 case (Some (params), Some (infos)) => params zip infos
539552 case _ => Nil
540553
541- val params = currentParams.map: (symbol, info) =>
554+ val params = currentParams.zipWithIndex.map: (p, index) =>
555+ val (symbol, info) = p
542556 // TODO after we migrate ShortenedTypePrinter into the compiler, it should rely on its api
543557 val name = if symbol.isAllOf(Flags .Given | Flags .Param ) && symbol.name.startsWith(" x$" ) then nme.EMPTY else symbol.name.asTermName
544558
545559 Signatures .MethodParam (
546560 name.show,
547- info .widenTermRefExpr.show,
561+ tp.paramInfoss.head(index) .widenTermRefExpr.show,
548562 docComment.flatMap(_.paramDoc(name)),
549563 isImplicit = tp.isImplicitMethod,
550564 )
@@ -586,23 +600,42 @@ object Signatures {
586600 finalParams.getOrElse(params)
587601 end toParams
588602
589- val applies = untpdFun.map(toApplyList).getOrElse(Nil )
590- val types = toMethodTypeList(tp).reverse
603+ loop(tp, applies, typeArgs, 0 )
604+ end toParamss
605+
606+ val paramss = toParamss(info, untpdFun, typeArgs)
607+
608+ // Compute instantiated return type
609+ var instantiatedInfo = info
610+ var remainingTypeArgs = typeArgs
611+ while (remainingTypeArgs.nonEmpty && instantiatedInfo.isInstanceOf [PolyType ]) {
612+ instantiatedInfo = instantiatedInfo.asInstanceOf [PolyType ].appliedTo(remainingTypeArgs.head)
613+ remainingTypeArgs = remainingTypeArgs.tail
614+ }
591615
592- reduceToParamss(applies, types)
593616
594- val paramss = toParamss(denot.info, untpdFun)
595617 val (name, returnType) =
596618 if (symbol.isConstructor) then
597619 (symbol.owner.name.show, None )
598620 else
599621 denot.symbol.defTree match
600622 // if there is an error in denotation type, we will fallback to source tree
601623 case defn : tpd.DefDef if denot.info.isErroneous => (denot.name.show, Some (defn.tpt.show))
602- case _ => (denot.name.show, Some (denot.info .finalResultType.widenTermRefExpr.show))
624+ case _ => (denot.name.show, Some (instantiatedInfo .finalResultType.widenTermRefExpr.show))
603625 Some (Signatures .Signature (name, paramss, returnType, docComment.map(_.mainDoc), Some (denot)))
604626 }
605627
628+ private def extractTypeArgs (tree : tpd.Tree )(using Context ): List [List [Type ]] = {
629+ tree match {
630+ case tpd.TypeApply (fun, args) =>
631+ extractTypeArgs(fun) :+ args.map(_.tpe)
632+ case tpd.Apply (fun, _) =>
633+ extractTypeArgs(fun)
634+ case _ =>
635+ Nil
636+ }
637+ }
638+
606639 /**
607640 * Creates signature for unapply method. It is different from apply one as it should not show function name,
608641 * return type and type parameters. Instead we show function in the following pattern (_$1: T1, _$2: T2, _$n: Tn),
0 commit comments