From a041f07452e1e855a1868fd8c8c5a3b7599a907e Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 5 Jul 2017 14:33:11 +0200 Subject: [PATCH 1/6] Unexpand names of type lambda params Otherwise we would print Foo[([+scala$Option$$A] => Option[+A])^] which is ugly and not even coherent --- compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala | 2 +- tests/repl/i2492.check | 2 +- tests/repl/names.check | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 tests/repl/names.check diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index e57177c355d9..220463f60b0c 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -174,7 +174,7 @@ class PlainPrinter(_ctx: Context) extends Printer { case tp: ExprType => changePrec(GlobalPrec) { "=> " ~ toText(tp.resultType) } case tp: TypeLambda => - def paramText(name: Name, bounds: TypeBounds): Text = name.toString ~ toText(bounds) + def paramText(name: Name, bounds: TypeBounds): Text = name.unexpandedName.toString ~ toText(bounds) changePrec(GlobalPrec) { "[" ~ Text((tp.paramNames, tp.paramInfos).zipped.map(paramText), ", ") ~ "]" ~ lambdaHash(tp) ~ (" => " provided !tp.resultType.isInstanceOf[MethodType]) ~ diff --git a/tests/repl/i2492.check b/tests/repl/i2492.check index f3bd52d48000..a9d3692989d7 100644 --- a/tests/repl/i2492.check +++ b/tests/repl/i2492.check @@ -4,5 +4,5 @@ scala> val s: Map {type Map$K =String;type Map$V = Int} = null -- [E055] Syntax Error: :5:7 ------------------------------------------ 5 |val s: Map {type Map$K =String;type Map$V = Int} = null | ^^^ - |missing type parameter for [line1$object$$iw$$iw$Map$$K, line1$object$$iw$$iw$Map$$V] => Map[K, V] + | missing type parameter for [K, V] => Map[K, V] scala> :quit diff --git a/tests/repl/names.check b/tests/repl/names.check new file mode 100644 index 000000000000..4c07178671a6 --- /dev/null +++ b/tests/repl/names.check @@ -0,0 +1,5 @@ +scala> case class Foo[M[_]](x: M[Int]) +defined class Foo +scala> Foo(Option(1)) +val res0: Foo[[+A] => Option[+A]] = Foo(Some(1)) +scala> :quit From 5aac2dc70c1db5ff40b72ee3e5b173f57466a286 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 5 Jul 2017 15:29:44 +0200 Subject: [PATCH 2/6] Add -Yprint-debug to hide pretty-printing debug info by default Currently, this flag only hides the "^" we display on inferred types, but in the future we can hide more stuff that shouldn't be seen by the user in error messages and in the IDE. --- compiler/src/dotty/tools/dotc/config/ScalaSettings.scala | 1 + compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 3a3cb512cc6b..33b2becb0b81 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -92,6 +92,7 @@ class ScalaSettings extends Settings.SettingGroup { val YnoDeepSubtypes = BooleanSetting("-Yno-deep-subtypes", "throw an exception on deep subtyping call stacks.") val YplainPrinter = BooleanSetting("-Yplain-printer", "Pretty-print using a plain printer.") val YprintSyms = BooleanSetting("-Yprint-syms", "when printing trees print info in symbols instead of corresponding info in trees.") + val YprintDebug = BooleanSetting("-Yprint-debug", "when printing trees, print some extra information useful for debugging.") val YtestPickler = BooleanSetting("-Ytest-pickler", "self-test for pickling functionality; should be used with -Ystop-after:pickler") val YcheckReentrant = BooleanSetting("-Ycheck-reentrant", "check that compiled program does not contain vars that can be accessed from a global root.") val YkeepComments = BooleanSetting("-Ykeep-comments", "Keep comments when scanning source files.") diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 220463f60b0c..a4556fa4559a 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -190,13 +190,13 @@ class PlainPrinter(_ctx: Context) extends Printer { toTextLocal(tycon) ~ "[" ~ Text(args.map(argText), ", ") ~ "]" case tp: TypeVar => if (tp.isInstantiated) - toTextLocal(tp.instanceOpt) ~ "^" // debug for now, so that we can see where the TypeVars are. + toTextLocal(tp.instanceOpt) ~ ("^" provided ctx.settings.YprintDebug.value) else { val constr = ctx.typerState.constraint val bounds = if (constr.contains(tp)) constr.fullBounds(tp.origin)(ctx.addMode(Mode.Printing)) else TypeBounds.empty - if (bounds.isAlias) toText(bounds.lo) ~ "^" + if (bounds.isAlias) toText(bounds.lo) ~ ("^" provided ctx.settings.YprintDebug.value) else if (ctx.settings.YshowVarBounds.value) "(" ~ toText(tp.origin) ~ "?" ~ toText(bounds) ~ ")" else toText(tp.origin) } From eb9952e17c81c5d925c49ae593a0198ee2d7394d Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 5 Jul 2017 15:33:31 +0200 Subject: [PATCH 3/6] Only pretty-print variance where it would be legal in code --- compiler/src/dotty/tools/dotc/core/NameOps.scala | 5 +++++ compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala | 2 +- tests/repl/names.check | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/NameOps.scala b/compiler/src/dotty/tools/dotc/core/NameOps.scala index 35522506bfaa..bb50c1928895 100644 --- a/compiler/src/dotty/tools/dotc/core/NameOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NameOps.scala @@ -124,6 +124,11 @@ object NameOps { name.rewrite { case ExpandedName(_, unexp) => unexp } } + /** Remove the variance from the name. */ + def invariantName: N = likeSpaced { + name.rewrite { case VariantName(invariant, _) => invariant } + } + def implClassName: N = likeSpaced(name ++ tpnme.IMPL_CLASS_SUFFIX) def errorName: N = likeSpaced(name ++ nme.ERROR) diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 6cfec7f16c1d..5595c5326dab 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -635,7 +635,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (tree.exists(!_.isEmpty)) encl(blockText(tree)) else "" override protected def ParamRefNameString(name: Name): String = - name.unexpandedName.toString + name.unexpandedName.invariantName.toString override protected def treatAsTypeParam(sym: Symbol): Boolean = sym is TypeParam diff --git a/tests/repl/names.check b/tests/repl/names.check index 4c07178671a6..ddb707c585a5 100644 --- a/tests/repl/names.check +++ b/tests/repl/names.check @@ -1,5 +1,5 @@ scala> case class Foo[M[_]](x: M[Int]) defined class Foo scala> Foo(Option(1)) -val res0: Foo[[+A] => Option[+A]] = Foo(Some(1)) +val res0: Foo[[+A] => Option[A]] = Foo(Some(1)) scala> :quit From a566635b1a1c1970ebad8c4cdbbeabfe5595a246 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 5 Jul 2017 15:48:48 +0200 Subject: [PATCH 4/6] Eta-reduce before pretty-printing if possible --- compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala | 2 ++ tests/repl/i2492.check | 2 +- tests/repl/names.check | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 5595c5326dab..28b41d00164c 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -156,6 +156,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (defn.isTupleClass(cls)) return toTextTuple(args) if (isInfixType(tp)) return toTextInfixType(tycon, args) return (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close + case EtaExpansion(tycon) => + return toText(tycon) case tp: TypeRef => val hideType = !ctx.settings.debugAlias.value && (tp.symbol.isAliasPreferred) if (hideType && !ctx.phase.erasedTypes && !tp.symbol.isCompleting) { diff --git a/tests/repl/i2492.check b/tests/repl/i2492.check index a9d3692989d7..31e4f836db7b 100644 --- a/tests/repl/i2492.check +++ b/tests/repl/i2492.check @@ -4,5 +4,5 @@ scala> val s: Map {type Map$K =String;type Map$V = Int} = null -- [E055] Syntax Error: :5:7 ------------------------------------------ 5 |val s: Map {type Map$K =String;type Map$V = Int} = null | ^^^ - | missing type parameter for [K, V] => Map[K, V] + | missing type parameter for Map scala> :quit diff --git a/tests/repl/names.check b/tests/repl/names.check index ddb707c585a5..55279b533ac7 100644 --- a/tests/repl/names.check +++ b/tests/repl/names.check @@ -1,5 +1,5 @@ scala> case class Foo[M[_]](x: M[Int]) defined class Foo scala> Foo(Option(1)) -val res0: Foo[[+A] => Option[A]] = Foo(Some(1)) +val res0: Foo[Option] = Foo(Some(1)) scala> :quit From dc8c5c3ea434dd9a0aee85ecfcd7520c5dd1623b Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Wed, 5 Jul 2017 15:54:28 +0200 Subject: [PATCH 5/6] Pretty-print method types with a ": " before a non-method return type --- compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala | 3 ++- .../test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index a4556fa4559a..fdcc154eedeb 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -169,7 +169,8 @@ class PlainPrinter(_ctx: Context) extends Printer { changePrec(GlobalPrec) { (if (tp.isImplicit) "(implicit " else "(") ~ Text((tp.paramNames, tp.paramInfos).zipped map paramText, ", ") ~ - ")" ~ toText(tp.resultType) + (if (tp.resultType.isInstanceOf[MethodType]) ")" else "): ") ~ + toText(tp.resultType) } case tp: ExprType => changePrec(GlobalPrec) { "=> " ~ toText(tp.resultType) } diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index 8f7398c9683e..5c4e86cff66e 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -384,7 +384,7 @@ class ErrorMessagesTests extends ErrorMessagesTest { val MethodDoesNotTakeParameters(tree, methodPart) :: Nil = messages assertEquals("Scope.foo(1)", tree.show) - assertEquals("((a: Int)Unit)(Scope.foo)", methodPart.show) + assertEquals("((a: Int): Unit)(Scope.foo)", methodPart.show) } @Test def ambiugousOverloadWithWildcard = @@ -408,7 +408,7 @@ class ErrorMessagesTests extends ErrorMessagesTest { assertMessageCount(1, messages) val AmbiguousOverload(tree, List(alt1, alt2), pt: WildcardType) :: Nil = messages assertEquals("method foo", alt1.show) - assertEquals("(s: String)String", alt1.info.show) + assertEquals("(s: String): String", alt1.info.show) assertEquals("method foo", alt2.show) } From f16b77a1000761501d555619358c4d7850577dcd Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Thu, 6 Jul 2017 12:09:53 +0200 Subject: [PATCH 6/6] Fix infinite recursion with -Yplain-printer Trying to print the type of `List(1,2)` in the repl launched with `-Yplain-printer` previously resulted in an infinite recursion (stopped by PlainPrinter#controlled) because `refinementChain(tp)` will return a list of only one argument for a RefinedType which is also an AppliedType. --- compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala | 2 ++ compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index fdcc154eedeb..8a10ef60ebbe 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -142,6 +142,8 @@ class PlainPrinter(_ctx: Context) extends Printer { toTextLocal(tp.underlying) ~ "(" ~ toTextRef(tp) ~ ")" case tp: TypeRef => toTextPrefix(tp.prefix) ~ selectionString(tp) + case AppliedType(tycon, args) => + (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close case tp: RefinedType => val parent :: (refined: List[RefinedType @unchecked]) = refinementChain(tp).reverse diff --git a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala index 28b41d00164c..c494110201e4 100644 --- a/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala @@ -155,7 +155,6 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) { if (defn.isFunctionClass(cls)) return toTextFunction(args, cls.name.isImplicitFunction) if (defn.isTupleClass(cls)) return toTextTuple(args) if (isInfixType(tp)) return toTextInfixType(tycon, args) - return (toTextLocal(tycon) ~ "[" ~ Text(args map argText, ", ") ~ "]").close case EtaExpansion(tycon) => return toText(tycon) case tp: TypeRef =>