def printType()

in scala/decompiler/src/org/jetbrains/plugins/scala/decompiler/scalasig/ScalaSigPrinter.scala [619:807]


  def printType(sym: SymbolInfoSymbol)(implicit flags: TypeFlags): Unit = printType(sym.infoType)(flags)

  def printType(t: Type)(implicit flags: TypeFlags): Unit = print(toString(t)(flags))

  def printType(t: Type, sep: String)(implicit flags: TypeFlags): Unit = print(toString(t, sep)(flags))

  def toString(t: Type)(implicit flags: TypeFlags): String = toString(t, "")(flags)

  def toString(t: Type, level: Int)(implicit flags: TypeFlags): String = toString(t, "", level)(flags)

  private val SingletonTypePattern = """(.*?)\.type""".r

  //TODO: this passing of 'level' look awful;
  def toString(t: Type, sep: String, level: Int = 0, parens: Int = 0)(implicit flags: TypeFlags): String = {

    // print type itself
    t match {
      case ThisType(Ref(classSymbol: ClassSymbol)) if refinementClass(classSymbol) => sep + "this.type"
      case ThisType(Ref(symbol)) => sep + processName(symbol.name) + ".this.type"
      case SingleType(Ref(ThisType(Ref(thisSymbol: ClassSymbol))), symbol) =>
        val thisSymbolName: String =
          thisSymbol.name match {
            case "package" => thisSymbol.symbolInfo.owner match {
              case Ref(ex: ExternalSymbol) => "_root_." + processName(ex.path)
              case _ => "this"
            }
            case name if thisSymbol.isModule => if (thisSymbol.isStableObject) "_root_." + processName(thisSymbol.path).stripPrefix("<empty>.") else processName(name)
            case name => if (name == "<refinement>") "this" else processName(name) + ".this"
          }
        sep + thisSymbolName + "." + processName(symbol.name) + ".type"
      case SingleType(Ref(ThisType(Ref(exSymbol: ExternalSymbol))), symbol) if exSymbol.name == "<root>" =>
        sep + "_root_." + processName(symbol.name) + ".type"
      case SingleType(Ref(ThisType(Ref(exSymbol: ExternalSymbol))), Ref(symbol)) =>
        sep + "_root_." + processName(exSymbol.path).stripPrefix("<empty>.").removeDotPackage + "." +
          processName(symbol.name) + ".type"
      case SingleType(Ref(NoPrefixType), Ref(symbol)) =>
        sep + processName(symbol.name) + ".type"
      case SingleType(typeRef, symbol) =>
        var typeRefString = toString(typeRef, level)
        if (typeRefString.endsWith(".type")) typeRefString = typeRefString.dropRight(5)
        typeRefString = typeRefString.removeDotPackage
        sep + typeRefString + "." + processName(symbol.name) + ".type"
      case ConstantType(Ref(c)) =>
        sep + Constants.typeText(c)
      case TypeRefType(Ref(NoPrefixType), Ref(symbol: TypeSymbol), typeArgs) if currentTypeParameters.isDefinedAt(symbol) =>
        sep + processName(currentTypeParameters.getOrElse(symbol, symbol.name)) + typeArgString(typeArgs, level)
      case TypeRefType(prefix, symbol, typeArgs) => sep + (symbol.path match {
        case "scala.<repeated>" => flags match {
          case TypeFlags(true) => toString(typeArgs.head, "", level, 1) + "*"
          case _ => "_root_.scala.Seq" + typeArgString(typeArgs, level)
        }
        case "scala.<byname>" =>
          val s = "=> " + toString(typeArgs.head, level)
          if (parens > 1) "(" + s + ")" else s
        case _ =>
          def checkContainsSelf(self: Option[Type], parent: Symbol): Boolean = {
            self match {
              case Some(tp) =>
                tp match {
                  case ThisType(Ref(sym)) => sym == parent
                  case SingleType(_, Ref(sym)) => sym == parent
                  case _: ConstantType => false
                  case TypeRefType(_, Ref(sym), _) => sym == parent
                  case _: TypeBoundsType => false
                  case RefinedType(Ref(sym), refs) => sym == parent || refs.exists(tp => checkContainsSelf(Some(tp), parent))
                  case ClassInfoType(Ref(sym), refs) => sym == parent || refs.exists(tp => checkContainsSelf(Some(tp), parent))
                  case ClassInfoTypeWithCons(Ref(sym), refs, _) => sym == parent || refs.exists(tp => checkContainsSelf(Some(tp), parent))
                  case ImplicitMethodType(_, _) => false
                  case MethodType(_, _) => false
                  case NullaryMethodType(_) => false
                  case PolyType(typeRef, symbols) =>
                    checkContainsSelf(Some(typeRef), parent) || symbols.exists(_.get == parent)
                  case PolyTypeWithCons(typeRef, symbols, _, _) =>
                    checkContainsSelf(Some(typeRef), parent) || symbols.exists(_.get == parent)
                  case AnnotatedType(typeRef) => checkContainsSelf(Some(typeRef), parent)
                  case AnnotatedWithSelfType(typeRef, Ref(sym), _) =>
                    checkContainsSelf(Some(typeRef), parent) || sym == parent
                  case ExistentialType(typeRef, symbols) =>
                    checkContainsSelf(Some(typeRef), parent) || symbols.exists(_.get == parent)
                  case _ => false
                }
              case None => false
            }
          }
          val prefixStr = (prefix.get, symbol.get, toString(prefix.get, level)) match {
            case (NoPrefixType, _, _) => ""
            case (ThisType(Ref(objectSymbol)), _, _) if objectSymbol.isModule =>
              objectSymbol match {
                case classSymbol: ClassSymbol if objectSymbol.name == "package" =>
                  "_root_." + processName(classSymbol.symbolInfo.owner.path) + "."
                case _ =>
                  (if (objectSymbol.isStableObject) "_root_." + processName(objectSymbol.path) else processName(objectSymbol.name)) + "."
              }
            case (ThisType(packSymbol), _, _) if !packSymbol.isType =>
              val s = packSymbol.path.stripPrefix("<root>")
              "_root_." + (if (s.nonEmpty) processName(s) + "." else "")
            case (ThisType(Ref(classSymbol: ClassSymbol)), _, _) if refinementClass(classSymbol) => ""
            case (ThisType(Ref(typeSymbol: ClassSymbol)), ExternalSymbol(_, Some(parent), _), _)
              if typeSymbol.path != parent.path && checkContainsSelf(typeSymbol.thisTypeRef, parent) =>
              processName(typeSymbol.name) + ".this."
            case (ThisType(typeSymbol), ExternalSymbol(_, Some(parent), _), _) if typeSymbol.path != parent.path =>
              processName(typeSymbol.name) + ".super[" + processName(parent.name) + "/*"+ parent.path +"*/]."
            case (_, _, SingletonTypePattern(a)) => a + "."
            case (_, _, a) => a + "#"
          }
          //remove package object reference
          val path = prefixStr.removeDotPackage
          val name = processName(symbol.name)
          val res = path + name + (if (symbol.isModule) ".type" else "")
          val suffix =
            if (name == "_") {
              symbol.get match {
                case ts: TypeSymbol =>
                  ts.infoType match {
                    case t: TypeBoundsType =>
                      if (visitedTypeBoundsType.contains(t)) ""
                      else {
                        visitedTypeBoundsType += t
                        try     toString(t, level)
                        finally visitedTypeBoundsType -= t
                      }
                    case _ => ""
                  }
                case _ => ""
              }
            } else symbol.get match {
                case ex: ExternalSymbol if ex.isObject => ".type"
                case _                                 => ""
              }
          val base = res.stripPrefix("_root_.<empty>.")
          // Canonical presentation (add a class parameter?)
          val isInfix = false // base.nonEmpty && base.forall(!_.isLetterOrDigit) && typeArgs.length == 2
          val result = if (isInfix) {
            typeArgs.map(toString(_, "", level, 1)).mkString(" " + base + " ")
          } else if (typeArgs.nonEmpty && base.startsWith("_root_.scala.Tuple") && base != "_root_.scala.Tuple1" && !base.substring(18).contains(".")) {
            val s = typeArgs.map(toString(_, level)).mkString("(", ", ", ")")
            if (parens > 1) "(" + s + ")" else s
          } else if (typeArgs.nonEmpty && base.startsWith("_root_.scala.Function")) {
            val params = if (typeArgs.length == 2) toString(typeArgs.head, "", level, 2) else typeArgs.init.map(toString(_, level)).mkString("(", ", ", ")")
            val s = params + " => " + toString(typeArgs.last, level)
            if (parens > 0) "(" + s + ")" else s
          } else {
            base + typeArgString(typeArgs, level)
          }
          result + suffix
      })
      case TypeBoundsType(lower, upper) =>
        val lb = toString(lower, level)
        val ub = toString(upper, level)
        val lbs = if (!lb.equals("_root_.scala.Nothing")) " >: " + lb else ""
        val ubs = if (!ub.equals("_root_.scala.Any")) " <: " + ub else ""
        lbs + ubs
      case RefinedType(Ref(classSym: ClassSymbol), typeRefs) =>
        val classStr = {
          val text = getClassString(level + 1, classSym)
          if (text.trim.stripPrefix("{").stripSuffix("}").trim.isEmpty) ""
          else text
        }
        val parents = {
          val parents0 = typeRefs.map(toString(_, "", level, 1))
          if (classStr.nonEmpty && parents0 == Seq("_root_.scala.AnyRef")) "" else parents0.mkString("", " with ", "")
        }
        if (parents.nonEmpty) sep + parents + classStr else sep + classStr.stripPrefix(" ")
      case RefinedType(_, typeRefs) => sep + typeRefs.map(toString(_, "", level, 1)).mkString("", " with ", "")
      case ClassInfoType(symbol, typeRefs) =>
        val parents = simplify(symbol, typeRefs.map(toString(_, "", level, 1)))
        if (parents.nonEmpty) sep + parents.mkString(" extends ", " with ", "") else sep
      case ClassInfoTypeWithCons(symbol, typeRefs, cons) =>
        val parents = simplify(symbol, typeRefs.map(toString(_, "", level, 1)))
        if (parents.nonEmpty) sep + parents.mkString(cons + " extends ", " with ", "") else sep + cons

      case ImplicitMethodType(resultType, _) => toString(resultType, sep, level)
      case MethodType(resultType, _) => toString(resultType, sep, level)
      case NullaryMethodType(resultType) => toString(resultType, sep, level)

      case PolyType(typeRef, symbols) =>
        "({ type λ" + typeParamString(symbols, contextBoundsIn(typeRef.get)) + " = " + toString(typeRef, sep, level) + " })#λ"
      case PolyTypeWithCons(typeRef, symbols, cons, contextBounds) =>
        typeParamString(symbols, contextBounds) + cons + toString(typeRef, sep, level)
      case AnnotatedType(typeRef) =>
        toString(typeRef, sep, level)
      case AnnotatedWithSelfType(typeRef, _, _) => toString(typeRef, sep, level)
      //case DeBruijnIndexType(typeLevel, typeIndex) =>
      case ExistentialType(typeRef, symbols) =>
        val refs = symbols.map(_.get).map(toString).filter(!_.startsWith("_")).map("type " + _).distinct
        toString(typeRef, sep, level) + (if (refs.nonEmpty) refs.mkString(" forSome {", "; ", "}") else "")
      case _ => sep + t.toString
    }
  }