Skip to content

Print decompiled refinements #4698

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 102 additions & 43 deletions library/src/scala/tasty/util/ShowSourceCode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sealed, final and access modifiers are missing here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

final is a few lines above. I will add sealed .


if (!flags.isObject) {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 += "."
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems it is also OK to print the prefix here? For hygiene, we do need to print the prefix for local members as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to not print prefixes in references inside the parents of a class.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please explain what do you mean by prefixes in references inside the parents of a class? I see in the code C.this.T becomes T, which may be unhygienic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will reprint the prefix and add test cases where this fails

}
printDefinitionName(sym)

Expand All @@ -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)
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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 }
Expand Down
4 changes: 2 additions & 2 deletions tests/pos/i2104b.decompiled
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions tests/pos/simpleCaseClass-3.decompiled
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
49 changes: 49 additions & 0 deletions tests/pos/simpleRefinement.decompiled
Original file line number Diff line number Diff line change
@@ -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
})
}
}
26 changes: 26 additions & 0 deletions tests/pos/simpleRefinement.scala
Original file line number Diff line number Diff line change
@@ -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
}
4 changes: 3 additions & 1 deletion tests/run-with-compiler/i3876-c.check
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}