/* NSC -- new Scala compiler * Copyright 2005-2013 LAMP/EPFL * @author Paul Phillips */ package scala package reflect package internal import util._ trait TypeDebugging { self: SymbolTable => import definitions._ /** There's a whole lot of implementation detail which is nothing but noise when * you are trying to see what's going on. This is my attempt to filter it out. */ object noPrint extends (Tree => Boolean) { def skipScalaName(name: Name) = name match { case tpnme.Any | tpnme.Nothing | tpnme.AnyRef => true case _ => false } def skipRefTree(t: RefTree) = t match { case Select(Select(Ident(nme.ROOTPKG), nme.scala_), name) if skipScalaName(name) => true case Select(sel, name) if sel.symbol == ScalaPackage && skipScalaName(name) => true case Select(Super(This(tpnme.EMPTY), tpnme.EMPTY), nme.CONSTRUCTOR) => true case Ident(nme.ROOTPKG) => true case _ => skipSym(t.symbol) } def skipSym(sym: Symbol): Boolean = sym match { case null => false case NothingClass | AnyClass => true case PredefModule => true case ObjectClass => true case _ => sym.hasPackageFlag } def skipType(tpe: Type): Boolean = (tpe eq null) || skipSym(tpe.typeSymbolDirect) def skip(t: Tree): Boolean = t match { case EmptyTree => true case PackageDef(_, _) => true case t: RefTree => skipRefTree(t) case TypeBoundsTree(lo, hi) => skip(lo) && skip(hi) case Block(Nil, expr) => skip(expr) case Apply(fn, Nil) => skip(fn) case Block(stmt :: Nil, expr) => skip(stmt) && skip(expr) case DefDef(_, nme.CONSTRUCTOR, Nil, ListOfNil, _, rhs) => skip(rhs) case Literal(Constant(())) => true case tt @ TypeTree() => skipType(tt.tpe) case _ => skipSym(t.symbol) } def apply(t: Tree) = skip(t) } /** Light color wrappers. */ object typeDebug { import scala.Console._ private val colorsOk = sys.props contains "scala.color" private def inColor(s: String, color: String) = if (colorsOk && s != "") color + s + RESET else s private def inBold(s: String, color: String) = if (colorsOk && s != "") color + BOLD + s + RESET else s def inLightRed(s: String) = inColor(s, RED) def inLightGreen(s: String) = inColor(s, GREEN) def inLightMagenta(s: String) = inColor(s, MAGENTA) def inLightCyan(s: String): String = inColor(s, CYAN) def inGreen(s: String): String = inBold(s, GREEN) def inRed(s: String): String = inBold(s, RED) def inBlue(s: String): String = inBold(s, BLUE) def inCyan(s: String): String = inBold(s, CYAN) def inMagenta(s: String) = inBold(s, MAGENTA) def resetColor(s: String): String = if (colorsOk) s + RESET else s private def to_s(x: Any): String = x match { // otherwise case classes are caught looking like products case _: Tree | _: Type => "" + x case x: TraversableOnce[_] => x mkString ", " case x: Product => x.productIterator mkString ("(", ", ", ")") case _ => "" + x } def ptBlock(label: String, pairs: (String, Any)*): String = { if (pairs.isEmpty) label + "{ }" else { val width = (pairs map (_._1.length)).max val fmt = "%-" + (width + 1) + "s %s" val strs = pairs map { case (k, v) => fmt.format(k, to_s(v)) } strs.mkString(label + " {\n ", "\n ", "\n}") } } def ptLine(pairs: (String, Any)*): String = ( pairs map { case (k, v) => (k, to_s(v)) } filterNot { case (_, v) => v == "" } map { case ("", v) => v ; case (k, v) => s"$k=$v" } mkString ", " ) def ptTree(t: Tree): String = t match { case PackageDef(pid, _) => s"package $pid" case ModuleDef(_, name, _) => s"object $name" case DefDef(_, name, tparams, _, _, _) => "def " + name + ptTypeParams(tparams) case ClassDef(_, name, Nil, _) if t.symbol != null && t.symbol.isModuleClass => s"module class $name" case ClassDef(_, name, tparams, _) => "class " + name + ptTypeParams(tparams) case td: TypeDef => ptTypeParam(td) case TypeBoundsTree(lo, hi) => val lo_s = if (noPrint(lo)) "" else " >: " + ptTree(lo) val hi_s = if (noPrint(hi)) "" else " <: " + ptTree(hi) lo_s + hi_s case _ if (t.symbol eq null) || (t.symbol eq NoSymbol) => to_s(t) case _ => if (t.symbol.hasCompleteInfo) "" + t.symbol.tpe else "" } def ptTypeParam(td: TypeDef): String = { val TypeDef(_, name, tparams, rhs) = td name + ptTypeParams(tparams) + ptTree(rhs) } def ptTypeParams(tparams: List[TypeDef]): String = str brackets (tparams map ptTypeParam) object str { def parentheses(xs: List[_]): String = xs.mkString("(", ", ", ")") def brackets(xs: List[_]): String = if (xs.isEmpty) "" else xs.mkString("[", ", ", "]") def tparams(tparams: List[Type]): String = brackets(tparams map debug) def parents(ps: List[Type]): String = (ps map debug).mkString(" with ") def refine(defs: Scope): String = defs.toList.mkString("{", " ;\n ", "}") def bounds(lo: Type, hi: Type): String = { val lo_s = if (typeIsNothing(lo)) "" else s" >: $lo" val hi_s = if (typeIsAny(hi)) "" else s" <: $hi" lo_s + hi_s } } import str._ private def debug(tp: Type): String = tp match { case TypeRef(pre, sym, args) => s"${debug(pre)}.${sym.nameString}.${tparams(args)}" case ThisType(sym) => s"${sym.nameString}.this" case SingleType(pre, sym) => s"${debug(pre)}.${sym.nameString}.type" case RefinedType(ps, decls) => s"${parents(ps)} ${refine(decls)}" case ClassInfoType(ps, decls, clazz) => s"class ${clazz.nameString} ${parents(ps)} ${refine(decls)}" case PolyType(tparams, result) => s"${brackets(tparams)}${debug(result)}" case TypeBounds(lo, hi) => bounds(lo, hi) case tv @ TypeVar(_, _) => "" + tv case ExistentialType(tparams, qtpe) => s"forSome ${brackets(tparams)} ${debug(qtpe)}" case _ => s"?${shortClassOfInstance(tp)}?" // tp.toString might produce cyclic error... } def debugString(tp: Type) = debug(tp) } def paramString(tp: Type) = typeDebug.str parentheses (tp.params map (_.defString)) def typeParamsString(tp: Type) = typeDebug.str brackets (tp.typeParams map (_.defString)) def debugString(tp: Type) = typeDebug debugString tp }