From c64a35895a139c3ed91d39150025bc8864aad732 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Fri, 25 Aug 2017 15:36:23 +0200 Subject: [PATCH] Properly strip REPL wrapper object path from nested types This commit allows the UserFacingPrinter to remove a part of the full path of the type it is printing. This means that despite types being deeply nested, they should not leak REPL names --- .../dotty/tools/repl/UserFacingPrinter.scala | 23 +++++++++++++------ repl/test-resources/repl/i2554 | 9 ++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 repl/test-resources/repl/i2554 diff --git a/repl/src/dotty/tools/repl/UserFacingPrinter.scala b/repl/src/dotty/tools/repl/UserFacingPrinter.scala index ac2c3f48e5e5..55ec71f633e7 100644 --- a/repl/src/dotty/tools/repl/UserFacingPrinter.scala +++ b/repl/src/dotty/tools/repl/UserFacingPrinter.scala @@ -33,13 +33,17 @@ class UserFacingPrinter(_ctx: Context) extends PlainPrinter(_ctx) { private lazy val scalaPkg = defn.ScalaPackageClass private lazy val javaLangPkg = defn.JavaLangPackageVal.moduleClass.asClass - def wellKnownPkg(pkgSym: Symbol) = pkgSym match { + def standardPkg(pkgSym: Symbol) = pkgSym match { case `scalaPkg` | `collectionPkg` | `immutablePkg` | `javaLangPkg` => true - case pkgSym => - pkgSym.name.toTermName == nme.EMPTY_PACKAGE || - pkgSym.name.isReplWrapperName + case _ => false } + def wrappedName(pkgSym: Symbol) = + pkgSym.name.toTermName == nme.EMPTY_PACKAGE || + pkgSym.name.isReplWrapperName + + def wellKnownPkg(pkgSym: Symbol) = standardPkg(pkgSym) || wrappedName(pkgSym) + override protected def keyString(sym: Symbol): String = { val flags = sym.flags if (flags is Package) "" @@ -48,6 +52,7 @@ class UserFacingPrinter(_ctx: Context) extends PlainPrinter(_ctx) { else if (sym.isClass && flags.is(Case)) "case class" else if (flags.is(Lazy)) "lazy val" else if (flags is Module) "object" + else if (sym.isTerm && !flags.is(Param) && flags.is(Implicit)) "implicit val" else super.keyString(sym) } @@ -86,7 +91,9 @@ class UserFacingPrinter(_ctx: Context) extends PlainPrinter(_ctx) { case tp: ConstantType => toText(tp.value) case tp: TypeAlias => toText(tp.underlying) case ExprType(result) => ":" ~~ toText(result) - case TypeBounds(lo, hi) => "_" + case TypeBounds(lo, hi) => + { if (lo != defn.NothingType) toText(lo) ~~ ">: _" else Str("_") } ~~ + { if (hi != defn.AnyType) "<:" ~~ toText(hi) else Text() } case tp: TypeRef => tp.info match { case TypeAlias(alias) => toText(alias) case _ => toText(tp.info) @@ -127,8 +134,10 @@ class UserFacingPrinter(_ctx: Context) extends PlainPrinter(_ctx) { nameString(tp.cls.name) else { def printPkg(sym: ClassSymbol): Text = - if (sym.owner == defn.RootClass) toText(sym) - else printPkg(sym.owner.asClass) ~ "." ~ toText(sym) + if (sym.owner == defn.RootClass || wrappedName(sym.owner)) + nameString(sym.name.stripModuleClassSuffix) + else + printPkg(sym.owner.asClass) ~ "." ~ toText(sym) printPkg(tp.cls.owner.asClass) ~ "." ~ nameString(tp.cls.name) } diff --git a/repl/test-resources/repl/i2554 b/repl/test-resources/repl/i2554 new file mode 100644 index 000000000000..2830056997be --- /dev/null +++ b/repl/test-resources/repl/i2554 @@ -0,0 +1,9 @@ +scala> object foo { trait ShapeLevel; trait FlatShapeLevel extends ShapeLevel; trait ColumnsShapeLevel extends FlatShapeLevel; abstract class Shape[Level <: ShapeLevel, -Mixed, Unpacked, Packed]; object Shape extends TupleShapeImplicits { }; trait TupleShapeImplicits { implicit final def tuple2Shape[Level <: ShapeLevel, M1,M2, U1,U2, P1,P2](implicit u1: Shape[_ <: Level, M1, U1, P1], u2: Shape[_ <: Level, M2, U2, P2]): Shape[Level, (M1,M2), (U1,U2), (P1,P2)] = ???; }; } +// defined object foo +scala> import foo._ +scala> implicit val shape: Shape[_ <: FlatShapeLevel, Int, Int, _] = null +implicit val shape: foo.Shape[_ <: foo.FlatShapeLevel, Int, Int, _] = null +scala> def hint = Shape.tuple2Shape(shape, shape) +def hint: foo.Shape[foo.FlatShapeLevel, Tuple2[Int, Int], Tuple2[Int, Int], + Tuple2 +[_, _]]