diff --git a/library/src/scala/tasty/util/ShowSourceCode.scala b/library/src/scala/tasty/util/ShowSourceCode.scala index d57cb8233f2c..3ad84cbf880d 100644 --- a/library/src/scala/tasty/util/ShowSourceCode.scala +++ b/library/src/scala/tasty/util/ShowSourceCode.scala @@ -69,11 +69,13 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty val flags = cdef.flags if (flags.isImplicit) this += "implicit " + if (flags.isSealed) this += "sealed " if (flags.isFinal && !flags.isObject) this += "final " if (flags.isCase) this += "case " if (flags.isObject) this += "object " += name.stripSuffix("$") else if (flags.isTrait) this += "trait " += name + else if (flags.isAbstract) this += "abstract class " += name else this += "class " += name if (!flags.isObject) { @@ -504,29 +506,14 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty def printTargDef(arg: TypeDef, isMember: Boolean = false): Buffer = { val TypeDef(name, rhs) = arg - def printBounds(bounds: TypeBoundsTree): Buffer = { - val TypeBoundsTree(lo, hi) = bounds - lo match { - case TypeTree.Synthetic() => - case _ => - this += " >: " - printTypeTree(lo) - } - hi match { - case TypeTree.Synthetic() => this - case _ => - this += " <: " - printTypeTree(hi) - } - } this += name rhs match { - case rhs @ TypeBoundsTree(lo, hi) => printBounds(rhs) + case rhs @ TypeBoundsTree(lo, hi) => printBoundsTree(rhs) case rhs @ SyntheticBounds() => printTypeOrBound(rhs.tpe) case rhs @ TypeTree.TypeLambdaTree(tparams, body) => def printParam(t: TypeOrBoundsTree): Unit = t match { - case t @ TypeBoundsTree(_, _) => printBounds(t) + case t @ TypeBoundsTree(_, _) => printBoundsTree(t) case t @ TypeTree() => printTypeTree(t) } def printSeparated(list: List[TypeDef]): Unit = list match { @@ -793,12 +780,14 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty case Type.SymRef(sym, prefix) => prefix match { case Types.EmptyPrefix() => - case prefix@Type.SymRef(ClassDef(_, _, _, _, _), _) => + case prefix @ Type.SymRef(ClassDef(_, _, _, _, _), _) => printType(prefix) this += "#" - case prefix@Type() => - printType(prefix) - this += "." + case prefix @ Type() => + if (!sym.flags.isLocal) { + printType(prefix) + this += "." + } } printDefinitionName(sym) @@ -822,9 +811,8 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty } this += name.stripSuffix("$") - case Type.Refinement(parent, name, info) => - printType(parent) - // TODO add refinements + case tpe @ Type.Refinement(_, _, _) => + printRefinement(tpe) case Type.AppliedType(tp, args) => printType(tp) @@ -861,25 +849,7 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty case Type.TypeLambda(paramNames, tparams, body) => this += "[" - def printBounds(bounds: TypeBounds): Buffer = { - val TypeBounds(lo, hi) = bounds - this += " >: " - printType(lo) - this += " <: " - printType(hi) - } - def printSeparated(list: List[(String, TypeBounds)]): Unit = list match { - case Nil => - case (name, bounds) :: Nil => - this += name - printBounds(bounds) - case (name, bounds) :: xs => - this += name - printBounds(bounds) - this += ", " - printSeparated(xs) - } - printSeparated(paramNames.zip(tparams)) + printMethodicTypeParams(paramNames, tparams) this += "] => " printTypeOrBound(body) @@ -932,6 +902,95 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty else this } + def printRefinement(tpe: Type): Buffer = { + def printMethodicType(tp: TypeOrBounds): Unit = tp match { + case tp @ Type.MethodType(paramNames, params, res) => + this += "(" + printMethodicTypeParams(paramNames, params) + this += ")" + printMethodicType(res) + case tp @ Type.TypeLambda(paramNames, params, res) => + this += "[" + printMethodicTypeParams(paramNames, params) + this += "]" + printMethodicType(res) + case Type.ByNameType(t) => + this += ": " + printType(t) + case tp @ Type() => + this += ": " + printType(tp) + } + def rec(tp: Type): Unit = tp match { + case Type.Refinement(parent, name, info) => + rec(parent) + indented { + this += lineBreak() + info match { + case info @ TypeBounds(_, _) => + this += "type " += name + printBounds(info) + case Type.ByNameType(_) | Type.MethodType(_, _, _) | Type.TypeLambda(_, _, _) => + this += "def " += name + printMethodicType(info) + case info @ Type() => + this += "val " += name + printMethodicType(info) + } + } + case tp => + printType(tp) + this += " {" + } + rec(tpe) + this += lineBreak() += "}" + } + + def printMethodicTypeParams(paramNames: List[String], params: List[TypeOrBounds]): Unit = { + def printInfo(info: TypeOrBounds) = info match { + case info @ TypeBounds(_, _) => printBounds(info) + case info @ Type() => + this += ": " + printType(info) + } + def printSeparated(list: List[(String, TypeOrBounds)]): Unit = list match { + case Nil => + case (name, info) :: Nil => + this += name + printInfo(info) + case (name, info) :: xs => + this += name + printInfo(info) + this += ", " + printSeparated(xs) + } + printSeparated(paramNames.zip(params)) + } + + def printBoundsTree(bounds: TypeBoundsTree): Buffer = { + val TypeBoundsTree(lo, hi) = bounds + lo match { + case TypeTree.Synthetic() => + case _ => + this += " >: " + printTypeTree(lo) + } + hi match { + case TypeTree.Synthetic() => this + case _ => + this += " <: " + printTypeTree(hi) + } + } + + def printBounds(bounds: TypeBounds): Buffer = { + val TypeBounds(lo, hi) = bounds + this += " >: " + printType(lo) + this += " <: " + printType(hi) + } + def +=(x: Boolean): this.type = { sb.append(x); this } def +=(x: Byte): this.type = { sb.append(x); this } def +=(x: Short): this.type = { sb.append(x); this } diff --git a/tests/pos/i2104b.decompiled b/tests/pos/i2104b.decompiled index 782d80666748..ead2eb68cd7c 100644 --- a/tests/pos/i2104b.decompiled +++ b/tests/pos/i2104b.decompiled @@ -13,13 +13,13 @@ case class Pair[A, B](_1: A, _2: B) { scala.runtime.Statics.finalizeHash(acc, 2) } override def equals(x$0: scala.Any): scala.Boolean = this.eq(x$0.asInstanceOf[java.lang.Object]).||(x$0 match { - case x$0: Pair[Pair.this.A, Pair.this.B] @scala.unchecked() => + case x$0: Pair[A, B] @scala.unchecked() => this._1.==(x$0._1).&&(this._2.==(x$0._2)) case _ => false }) override def toString(): java.lang.String = scala.runtime.ScalaRunTime._toString(this) - override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[Pair[Pair.this.A, Pair.this.B] @scala.unchecked()] + override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[Pair[A, B] @scala.unchecked()] override def productArity: scala.Int = 2 override def productPrefix: java.lang.String = "Pair" override def productElement(n: scala.Int): scala.Any = n match { diff --git a/tests/pos/simpleCaseClass-3.decompiled b/tests/pos/simpleCaseClass-3.decompiled index f41807b184c5..cf6fe29cf6c5 100644 --- a/tests/pos/simpleCaseClass-3.decompiled +++ b/tests/pos/simpleCaseClass-3.decompiled @@ -6,13 +6,13 @@ case class A[T](x: T) { scala.runtime.Statics.finalizeHash(acc, 1) } override def equals(x$0: scala.Any): scala.Boolean = this.eq(x$0.asInstanceOf[java.lang.Object]).||(x$0 match { - case x$0: A[A.this.T] @scala.unchecked() => + case x$0: A[T] @scala.unchecked() => this.x.==(x$0.x) case _ => false }) override def toString(): java.lang.String = scala.runtime.ScalaRunTime._toString(this) - override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A[A.this.T] @scala.unchecked()] + override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A[T] @scala.unchecked()] override def productArity: scala.Int = 1 override def productPrefix: java.lang.String = "A" override def productElement(n: scala.Int): scala.Any = n match { diff --git a/tests/pos/simpleRefinement.decompiled b/tests/pos/simpleRefinement.decompiled new file mode 100644 index 000000000000..72cb06c43840 --- /dev/null +++ b/tests/pos/simpleRefinement.decompiled @@ -0,0 +1,49 @@ +/** Decompiled from out/posTestFromTasty/pos/simpleRefinement/Bar.class */ +trait Bar() extends java.lang.Object { + type S + type T + type U <: [X] => scala.Any + val x: scala.Any + def y: scala.Any + def z(): scala.Any + def z2()(): scala.Any + def w[T]: scala.Any + def w2[T](a: scala.Null)(b: scala.Null): scala.Any +} +/** Decompiled from out/posTestFromTasty/pos/simpleRefinement/Foo.class */ +class Foo() { + val bar: Bar { + type S >: scala.Int <: scala.Int + type T >: scala.Function1[scala.Int, scala.Int] <: scala.Function1[scala.Int, scala.Int] + type U >: [X >: scala.Nothing <: scala.Any] => scala.Int <: [X >: scala.Nothing <: scala.Any] => scala.Int + val x: scala.Long + def y: scala.Boolean + def z(): scala.Char + def z2()(): scala.Char + def w[T >: scala.Nothing <: scala.Any]: scala.Predef.String + def w2[T >: scala.Nothing <: scala.Any](a: scala.Null)(b: scala.Null): scala.Null + } = { + final class $anon() extends Bar { + type S = scala.Int + type T = scala.Function1[scala.Int, scala.Int] + type U[X] = scala.Int + val x: scala.Long = 2L + def y: scala.Boolean = true + def z(): scala.Char = 'f' + def z2()(): scala.Char = 'g' + def w[T]: scala.Predef.String = "a" + def w2[T](a: scala.Null)(b: scala.Null): scala.Null = null + } + (new $anon(): Bar { + type S >: scala.Int <: scala.Int + type T >: scala.Function1[scala.Int, scala.Int] <: scala.Function1[scala.Int, scala.Int] + type U >: [X >: scala.Nothing <: scala.Any] => scala.Int <: [X >: scala.Nothing <: scala.Any] => scala.Int + val x: scala.Long + def y: scala.Boolean + def z(): scala.Char + def z2()(): scala.Char + def w[T >: scala.Nothing <: scala.Any]: scala.Predef.String + def w2[T >: scala.Nothing <: scala.Any](a: scala.Null)(b: scala.Null): scala.Null + }) + } +} diff --git a/tests/pos/simpleRefinement.scala b/tests/pos/simpleRefinement.scala new file mode 100644 index 000000000000..3b6500feddd3 --- /dev/null +++ b/tests/pos/simpleRefinement.scala @@ -0,0 +1,26 @@ + +class Foo { + val bar = new Bar { + type S = Int + type T = Int => Int + type U = [X] => Int + val x: Long = 2L + def y: Boolean = true + def z(): Char = 'f' + def z2()(): Char = 'g' + def w[T]: String = "a" + def w2[T](a: Null)(b: Null): Null = null + } +} + +trait Bar { + type S + type T + type U <: [X] => Any + val x: Any + def y: Any + def z(): Any + def z2()(): Any + def w[T]: Any + def w2[T](a: Null)(b: Null): Any +} diff --git a/tests/run-with-compiler/i3876-c.check b/tests/run-with-compiler/i3876-c.check index e298ecc3f648..54c77aeb94e6 100644 --- a/tests/run-with-compiler/i3876-c.check +++ b/tests/run-with-compiler/i3876-c.check @@ -4,5 +4,7 @@ val f: scala.Function1[scala.Int, scala.Int] { def apply(x: scala.Int): scala.Int } = ((x: scala.Int) => x.+(x)) - (f: scala.Function1[scala.Int, scala.Int]).apply(x$1) + (f: scala.Function1[scala.Int, scala.Int] { + def apply(x: scala.Int): scala.Int + }).apply(x$1) }