From 0a6bddc34dbfc9a667c7d63c1dc4de6ae04d7343 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 7 Mar 2013 10:57:58 +0100 Subject: Some refinements for prining Made trees printable in plain mode (refined mode still missing). --- src/dotty/tools/dotc/core/Constants.scala | 2 +- src/dotty/tools/dotc/core/Contexts.scala | 9 ++- src/dotty/tools/dotc/core/Definitions.scala | 3 +- src/dotty/tools/dotc/core/Names.scala | 11 +--- src/dotty/tools/dotc/core/Phases.scala | 6 +- src/dotty/tools/dotc/core/Printers.scala | 70 ++++++++++++++-------- src/dotty/tools/dotc/core/Scopes.scala | 6 +- src/dotty/tools/dotc/core/Showable.scala | 9 +++ src/dotty/tools/dotc/core/SymDenotations.scala | 2 +- src/dotty/tools/dotc/core/Symbols.scala | 2 +- src/dotty/tools/dotc/core/Trees.scala | 7 ++- src/dotty/tools/dotc/core/Types.scala | 2 +- src/dotty/tools/dotc/core/pickling/UnPickler.scala | 2 +- 13 files changed, 84 insertions(+), 47 deletions(-) create mode 100644 src/dotty/tools/dotc/core/Showable.scala (limited to 'src/dotty') diff --git a/src/dotty/tools/dotc/core/Constants.scala b/src/dotty/tools/dotc/core/Constants.scala index 825ce60f1..9dd5a2627 100644 --- a/src/dotty/tools/dotc/core/Constants.scala +++ b/src/dotty/tools/dotc/core/Constants.scala @@ -21,7 +21,7 @@ object Constants { // For supporting java enumerations inside java annotations (see ClassfileParser) final val EnumTag = 13 - case class Constant(value: Any) { + case class Constant(value: Any) extends Showable { import java.lang.Double.doubleToRawLongBits import java.lang.Float.floatToRawIntBits diff --git a/src/dotty/tools/dotc/core/Contexts.scala b/src/dotty/tools/dotc/core/Contexts.scala index 05188fb78..d33c93a3a 100644 --- a/src/dotty/tools/dotc/core/Contexts.scala +++ b/src/dotty/tools/dotc/core/Contexts.scala @@ -197,7 +197,6 @@ object Contexts { */ abstract class FreshContext extends CondensedContext { def withPeriod(period: Period): this.type = { this.period = period; this } - def withPhase(pid: PhaseId): this.type = withPeriod(Period(runId, pid)) def withConstraints(constraints: Constraints): this.type = { this.constraints = constraints; this } def withPosition(position: Position): this.type = { this.position = position; this } def withPlainPrinter(printer: Context => Printer): this.type = { this.plainPrinter = printer; this } @@ -207,6 +206,14 @@ object Contexts { def withTree(tree: Tree): this.type = { this.tree = tree; this } def withReporter(reporter: Reporter): this.type = { this.reporter = reporter; this } def withDiagnostics(diagnostics: Option[StringBuilder]): this.type = { this.diagnostics = diagnostics; this } + + def withPhase(pid: PhaseId): this.type = withPeriod(Period(runId, pid)) + + def withSetting[T](setting: Setting[T], value: T): this.type = + withSettings(setting.updateIn(sstate, value)) + + def withDebug = withSetting(base.settings.debug, true) + } /** A class defining the initial context with given context base diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 878cec877..bdc95ff16 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -172,11 +172,12 @@ class Definitions(implicit ctx: Context) { if (ctx.phase.erasedTypes) ctype else ctype.appliedTo(arg) } + /** The enumeration type, goven a value of the enumeration */ def EnumType(sym: Symbol)(implicit ctx: Context) = // given (in java): "class A { enum E { VAL1 } }" // - sym: the symbol of the actual enumeration value (VAL1) // - .owner: the ModuleClassSymbol of the enumeration (object E) - // - .linkedClassOfClass: the ClassSymbol of the enumeration (class E) + // - .linkedClass: the ClassSymbol of the enumeration (class E) sym.owner.linkedClass.typeConstructor def FunctionType(args: List[Type], resultType: Type) = diff --git a/src/dotty/tools/dotc/core/Names.scala b/src/dotty/tools/dotc/core/Names.scala index 3b9a78dc5..8a345fcc8 100644 --- a/src/dotty/tools/dotc/core/Names.scala +++ b/src/dotty/tools/dotc/core/Names.scala @@ -4,6 +4,7 @@ package core import scala.io.Codec import util.NameTransformer import Decorators._ +import Contexts.Context import collection.IndexedSeqOptimized import collection.generic.CanBuildFrom import collection.mutable.{ Builder, StringBuilder } @@ -32,6 +33,7 @@ object Names { */ abstract class Name extends DotClass with PreName + with Showable with Seq[Char] with IndexedSeqOptimized[Char, Name] { @@ -80,14 +82,7 @@ object Names { override def toString = new String(chrs, start, length) - /** Show name with namespace suffix: /L for local names, - * /V for other term names, /T for type names - */ - def showDetailed: String = toString + { - (if (isLocalName) "/L" - else if (isTypeName) "/T" - else "/V") - } + def show(implicit ctx: Context): String = ctx.show(this) /** Write to UTF8 representation of this name to given character array. * Start copying to index `to`. Return index of next free byte in array. diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala index 02d9c9749..039bba164 100644 --- a/src/dotty/tools/dotc/core/Phases.scala +++ b/src/dotty/tools/dotc/core/Phases.scala @@ -33,12 +33,12 @@ object Phases { def name = "" def run() { throw new Error("NoPhase.run") } } -/* - object SomePhase extends Phase { + + object SomePhase extends Phase(initialCtx) { def name = "" def run() { throw new Error("SomePhase.run") } } -*/ + def phaseNamed(name: String) = allPhases.find(_.name == name).getOrElse(NoPhase) diff --git a/src/dotty/tools/dotc/core/Printers.scala b/src/dotty/tools/dotc/core/Printers.scala index 761900c5c..25fa2ca01 100644 --- a/src/dotty/tools/dotc/core/Printers.scala +++ b/src/dotty/tools/dotc/core/Printers.scala @@ -2,7 +2,7 @@ package dotty.tools.dotc package core import Types._, Symbols._, Contexts._, Scopes._, Names._, NameOps._, Flags._ -import Constants._, Annotations._, StdNames._, Denotations._ +import Constants._, Annotations._, StdNames._, Denotations._, Trees._ import java.lang.Integer.toOctalString import scala.annotation.switch @@ -30,12 +30,11 @@ object Printers { abstract class Printer { - /** Show name, same as name.toString + kind suffix if plain printer */ + /** Show name with namespace suffix: /L for local names, + * /V for other term names, /T for type names + */ def show(name: Name): String - /** Show name with "type" or "term" prefix */ - def showDetailed(name: Name): String - /** Show type in context with given precedence */ def show(tp: Type, precedence: Precedence): String @@ -61,7 +60,7 @@ object Printers { /** Show symbol's declaration */ def showDcl(sym: Symbol): String - /** If symbol's owner is printable class C, the string "in C", otherwise "" */ + /** If symbol's owner is a printable class C, the string "in C", otherwise "" */ def showLocation(sym: Symbol): String /** Show symbol and its location */ @@ -71,16 +70,19 @@ object Printers { def show(denot: Denotation): String /** Show constant */ - def show(const: Constant) + def show(const: Constant): String /** Show annotation */ def show(annot: Annotation): String /** Show all symbols in given list separated by `sep`, using `showDcl` for each */ - def show(syms: List[Symbol], sep: String): String + def showDcls(syms: List[Symbol], sep: String): String - /** Show all definitions in a scope usng `showDcl` for each */ + /** Show all definitions in a scope using `showDcl` for each */ def show(sc: Scope): String + + /** Show tree */ + def show[T](tree: Tree[T]): String } class PlainPrinter(_ctx: Context) extends Printer { @@ -105,7 +107,7 @@ object Printers { } /** Concatenate strings separated by spaces */ - protected def compose(ss: String*) = ss filter (_.nonEmpty) mkString " " + protected def compose(ss: String*) = ss.filter(_.nonEmpty).mkString(" ") /** If the name of the symbol's owner should be used when you care about * seeing an interesting name: in such cases this symbol is e.g. a method @@ -119,10 +121,11 @@ object Printers { || (sym.name == nme.PACKAGE) // package ) - def show(name: Name): String = name.showDetailed - - def showDetailed(name: Name): String = - (if (name.isTypeName) "type " else "term ") + name + def show(name: Name): String = name.toString + { + (if (name.isLocalName) "/L" + else if (name.isTypeName) "/T" + else "/V") + } /** String representation of a name used in a refinement * In refined printing this undoes type parameter expansion @@ -133,7 +136,7 @@ object Printers { protected def showRefinement(rt: RefinedType) = showRefinementName(rt) + showRHS(rt.refinedInfo) - /** The longest sequence refinement types, starting at given type + /** The longest sequence of refinement types, starting at given type * and following parents. */ private def refinementChain(tp: Type): List[Type] = @@ -149,7 +152,7 @@ object Printers { case tp: SingletonType => val str = showPrefix(tp) if (str.endsWith(".")) str + "type" - else showFullName(tp.underlying.typeSymbol.skipPackageObject) + ".type" + else showFullName(tp.typeSymbol.skipPackageObject) + ".type" case TypeRef(pre, name) => showPrefix(pre) + showName(tp.typeSymbol) case tp: RefinedType => @@ -225,12 +228,6 @@ object Printers { protected def trimPrefix(str: String) = str.stripPrefix(objectPrefix).stripPrefix(packagePrefix) - protected def isOmittablePrefix(sym: Symbol) = - (defn.UnqualifiedOwners contains sym) || isEmptyPrefix(sym) - - protected def isEmptyPrefix(sym: Symbol) = - sym.isEffectiveRoot || sym.isAnonymousClass || sym.name.isReplWrapperName - /** The string representation of this type used as a prefix */ protected def showPrefix(tp: Type): String = controlled { tp match { @@ -253,6 +250,12 @@ object Printers { } } + protected def isOmittablePrefix(sym: Symbol) = + (defn.UnqualifiedOwners contains sym) || isEmptyPrefix(sym) + + protected def isEmptyPrefix(sym: Symbol) = + sym.isEffectiveRoot || sym.isAnonymousClass || sym.name.isReplWrapperName + /** String representation of a definition's type following its name */ protected def showRHS(tp: Type): String = controlled { tp match { @@ -270,7 +273,7 @@ object Printers { val parentsStr = cparents.map(show(_, WithPrec)).mkString(" with ") val declsStr = if (decls.isEmpty) "" - else "\n " + show(decls.toList, "\n ") + else "\n " + showDcls(decls.toList, "\n ") s"""$parentsStr { $selfStr$declsStr |} at $preStr""".stripMargin case _ => ": " + showGlobal(tp) @@ -367,11 +370,28 @@ object Printers { def show(annot: Annotation): String = s"@${annot.symbol.name}" // for now - def show(syms: List[Symbol], sep: String): String = + def showDcls(syms: List[Symbol], sep: String): String = syms map (_.showDcl) mkString sep def show(sc: Scope): String = - "Scope{\n" + show(sc.toList, ";\n ") + "\n}" + "Scope{\n" + showDcls(sc.toList, ";\n ") + "\n}" + + def show[T](tree: Tree[T]): String = tree match { + case node: Product => + def showElem(elem: Any) = elem match { + case elem: Showable => elem.show + case elem => elem.toString + } + val nodeName = node.productPrefix + val elems = node.productIterator.map(showElem).mkString(", ") + val tpSuffix = + if (ctx.settings.printtypes.value && tree.hasType) s" | ${tree.tpe}" + else "" + + s"$nodeName($elems$tpSuffix)" + case _ => + tree.toString + } // todo: override in refined printer } class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { diff --git a/src/dotty/tools/dotc/core/Scopes.scala b/src/dotty/tools/dotc/core/Scopes.scala index 0253cd60b..f8a125a3b 100644 --- a/src/dotty/tools/dotc/core/Scopes.scala +++ b/src/dotty/tools/dotc/core/Scopes.scala @@ -48,7 +48,7 @@ object Scopes { * or to delete them. These methods are provided by subclass * MutableScope. */ - abstract class Scope extends Iterable[Symbol] { + abstract class Scope extends Showable with Iterable[Symbol] { /** The last scope-entry from which all others are reachable via `prev` */ private[dotc] def lastEntry: ScopeEntry @@ -109,6 +109,8 @@ object Scopes { /** Cast this scope to a mutable scope */ final def openForMutations: MutableScope = this.asInstanceOf[MutableScope] + + final def show(implicit ctx: Context): String = ctx.show(this) } /** A subclass of Scope that defines methods for entering and @@ -293,8 +295,6 @@ object Scopes { if (filtered eq unfiltered) this else newScopeWith(filtered: _*) } - - final def show(implicit ctx: Context): String = ctx.show(this) } /** Create a new scope */ diff --git a/src/dotty/tools/dotc/core/Showable.scala b/src/dotty/tools/dotc/core/Showable.scala new file mode 100644 index 000000000..770b3c818 --- /dev/null +++ b/src/dotty/tools/dotc/core/Showable.scala @@ -0,0 +1,9 @@ +package dotty.tools.dotc.core + +import Contexts._ + +trait Showable { + + def show(implicit ctx: Context): String + +} \ No newline at end of file diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 8ad63229e..2b20e4c16 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -947,7 +947,7 @@ object SymDenotations { if (file != null) (s" in $file", file.toString) else ("", "the signature") cctx.error( - s"""|bad symbolic reference. A signature$location refers to ${cctx.showDetailed(denot.name)} + s"""|bad symbolic reference. A signature$location refers to ${cctx.fresh.withDebug.show(denot.name)} |in ${denot.owner.showKind} ${denot.owner.showFullName} which is not available. |It may be completely missing from the current classpath, or the version on |the classpath might be incompatible with the version used when compiling $src.""".stripMargin) diff --git a/src/dotty/tools/dotc/core/Symbols.scala b/src/dotty/tools/dotc/core/Symbols.scala index e307328e1..fa4e6f75d 100644 --- a/src/dotty/tools/dotc/core/Symbols.scala +++ b/src/dotty/tools/dotc/core/Symbols.scala @@ -267,7 +267,7 @@ object Symbols { /** A Symbol represents a Scala definition/declaration or a package. */ - class Symbol private[Symbols] (val coord: Coord) extends DotClass { + class Symbol private[Symbols] (val coord: Coord) extends DotClass with Showable { type ThisName <: Name diff --git a/src/dotty/tools/dotc/core/Trees.scala b/src/dotty/tools/dotc/core/Trees.scala index 8d297d5df..1140eb088 100644 --- a/src/dotty/tools/dotc/core/Trees.scala +++ b/src/dotty/tools/dotc/core/Trees.scala @@ -30,7 +30,7 @@ object Trees { * - Type checking an untyped tree will remove all embedded `TypedSplice` * nodes. */ - abstract class Tree[T] extends DotClass { + abstract class Tree[T] extends DotClass with Showable { /** The tree's position. Except * for SharedTree nodes, it is always ensured that a tree's position @@ -71,6 +71,9 @@ object Trees { tree.asInstanceOf[ThisTree[Type]] } + /** Does the tree have it's type field set? */ + def hasType: Boolean = _tpe != null + /** The denotation referred to by this tree, NoDenotation where not applicable */ def denot(implicit ctx: Context): Denotation = NoDenotation @@ -92,6 +95,8 @@ object Trees { /** Is this tree either the empty tree or the empty ValDef? */ def isEmpty: Boolean = false + override def show(implicit ctx: Context) = ctx.show(this) + override def hashCode(): Int = System.identityHashCode(this) override def equals(that: Any) = this eq that.asInstanceOf[AnyRef] } diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 45a8ad157..ab43a793d 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -60,7 +60,7 @@ object Types { * +- ErrorType * +- WildcardType */ - abstract class Type extends DotClass { + abstract class Type extends DotClass with Showable { // ----- Tests ----------------------------------------------------- diff --git a/src/dotty/tools/dotc/core/pickling/UnPickler.scala b/src/dotty/tools/dotc/core/pickling/UnPickler.scala index b036a8170..27cc10ee6 100644 --- a/src/dotty/tools/dotc/core/pickling/UnPickler.scala +++ b/src/dotty/tools/dotc/core/pickling/UnPickler.scala @@ -457,7 +457,7 @@ class UnPickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleRoot: Clas if (tp1 exists isBound) { val tp2 = tp1.subst(boundSyms, boundSyms map (_ => defn.AnyType)) cctx.warning(s"""failure to eliminate existential - |original type : $tp forSome {${cctx.show(boundSyms, "; ")}} + |original type : $tp forSome {${cctx.showDcls(boundSyms, "; ")}} |reduces to : $tp1 |type used instead: $tp2 |proceed at own risk.""".stripMargin) -- cgit v1.2.3