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
}
}