Skip to content

Commit 09e6599

Browse files
Merge pull request #4676 from dotty-staging/fix-decompiler-annots
Print annotation in decompiler
2 parents 6781480 + 40fffc1 commit 09e6599

9 files changed

+132
-25
lines changed

compiler/test/dotty/tools/dotc/FromTastyTests.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ class FromTastyTests extends ParallelTesting {
3838
"t3612.scala",
3939
),
4040
recompilationBlacklist = Set(
41-
"simpleCaseObject",
4241
"annot-bootstrap.scala",
4342
)
4443
).checkCompile()

library/src/scala/tasty/util/ShowSourceCode.scala

Lines changed: 105 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
6565
printImportSelectors(selectors)
6666

6767
case cdef @ ClassDef(name, DefDef(_, targs, argss, _, _), parents, self, stats) =>
68+
printDefAnnotations(cdef)
69+
6870
val flags = cdef.flags
6971
if (flags.isFinal && !flags.isObject) this += "final "
7072
if (flags.isCase) this += "case "
@@ -146,11 +148,14 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
146148
}
147149
this
148150

149-
case tdef@TypeDef(name, rhs) =>
151+
case tdef @ TypeDef(name, rhs) =>
152+
printDefAnnotations(tdef)
150153
this += "type "
151154
printTargDef(tdef, isMember = true)
152155

153-
case vdef@ValDef(name, tpt, rhs) =>
156+
case vdef @ ValDef(name, tpt, rhs) =>
157+
printDefAnnotations(vdef)
158+
154159
val flags = vdef.flags
155160
if (flags.isOverride) this += "override "
156161

@@ -201,7 +206,9 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
201206
printTree(cond)
202207
this += ")"
203208

204-
case ddef@DefDef(name, targs, argss, tpt, rhs) =>
209+
case ddef @ DefDef(name, targs, argss, tpt, rhs) =>
210+
printDefAnnotations(ddef)
211+
205212
val flags = ddef.flags
206213
if (flags.isOverride) sb.append("override ")
207214

@@ -220,8 +227,16 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
220227
}
221228
this
222229

223-
case tree@Term.Ident(name) =>
224-
printType(tree.tpe)
230+
case tree @ Term.Ident(name) =>
231+
tree.tpe match {
232+
case Type.SymRef(_, Types.EmptyPrefix()) | Type.TermRef(_, Types.EmptyPrefix()) => this += name
233+
case Type.SymRef(_, prefix) =>
234+
printTypeOrBound(prefix)
235+
this += "." += name
236+
case Type.TermRef(_, prefix) =>
237+
printTypeOrBound(prefix)
238+
this += "." += name
239+
}
225240

226241
case Term.Select(qual, name, sig) =>
227242
printTree(qual)
@@ -272,7 +287,17 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
272287
this += "("
273288
printTree(term)
274289
this += ": "
275-
printTypeTree(tpt)
290+
def printTypeOrAnnots(tpe: Type): Unit = tpe match {
291+
case Type.AnnotatedType(tp, annot) if tp == term.tpe =>
292+
printAnnotation(annot)
293+
case Type.AnnotatedType(tp, annot) =>
294+
printTypeOrAnnots(tp)
295+
this += " "
296+
printAnnotation(annot)
297+
case tpe =>
298+
printType(tpe)
299+
}
300+
printTypeOrAnnots(tpt.tpe)
276301
this += ")"
277302
}
278303

@@ -538,6 +563,19 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
538563
this += ")"
539564
}
540565

566+
def printAnnotations(trees: List[Term]): Buffer = {
567+
def printSeparated(list: List[Term]): Unit = list match {
568+
case Nil =>
569+
case x :: Nil => printAnnotation(x)
570+
case x :: xs =>
571+
printAnnotation(x)
572+
this += " "
573+
printSeparated(xs)
574+
}
575+
printSeparated(trees)
576+
this
577+
}
578+
541579
def printArgDef(arg: ValDef): Unit = {
542580
val ValDef(name, tpt, rhs) = arg
543581
this += name += ": "
@@ -638,11 +676,23 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
638676

639677
def printTypeTree(tree: TypeTree): Buffer = tree match {
640678
case TypeTree.Synthetic() =>
641-
printType(tree.tpe)
642-
tree.tpe match {
643-
case tpe @ Type.TypeRef(name, _) if name.endsWith("$") => this += ".type"
644-
case tpe => this
645-
}
679+
def printTypeAndAnnots(tpe: Type): Buffer = tpe match {
680+
case Type.AnnotatedType(tp, annot) =>
681+
printTypeAndAnnots(tp)
682+
this += " "
683+
printAnnotation(annot)
684+
case tpe @ Type.TypeRef(name, _) if name.endsWith("$") =>
685+
printType(tpe)
686+
this += ".type"
687+
case Type.SymRef(ClassDef("Null$" | "Nothing$", _, _, _, _), Type.ThisType(Type.SymRef(PackageDef("runtime", _), NoPrefix()))) =>
688+
// scala.runtime.Null$ and scala.runtime.Nothing$ are not modules, those are their actual names
689+
printType(tpe)
690+
case tpe @ Type.SymRef(ClassDef(name, _, _, _, _), _) if name.endsWith("$") =>
691+
printType(tpe)
692+
this += ".type"
693+
case tpe => printType(tpe)
694+
}
695+
printTypeAndAnnots(tree.tpe)
646696

647697
case TypeTree.TypeIdent(name) =>
648698
printType(tree.tpe)
@@ -676,9 +726,11 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
676726
printTypeTrees(args, ", ")
677727
this += "]"
678728

679-
case TypeTree.Annotated(tpt, annots) =>
729+
case TypeTree.Annotated(tpt, annot) =>
730+
val Annotation(ref, args) = annot
680731
printTypeTree(tpt)
681-
// TODO print annots
732+
this += " "
733+
printAnnotation(annot)
682734

683735
case TypeTree.And(left, right) =>
684736
printTypeTree(left)
@@ -719,14 +771,13 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
719771

720772
case Type.SymRef(sym, prefix) =>
721773
prefix match {
722-
case Type.ThisType(Types.EmptyPackage() | Types.RootPackage()) =>
774+
case Types.EmptyPrefix() =>
723775
case prefix@Type.SymRef(ClassDef(_, _, _, _, _), _) =>
724776
printType(prefix)
725777
this += "#"
726778
case prefix@Type() =>
727779
printType(prefix)
728780
this += "."
729-
case prefix@NoPrefix() =>
730781
}
731782
printDefinitionName(sym)
732783

@@ -761,7 +812,10 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
761812
this += "]"
762813

763814
case Type.AnnotatedType(tp, annot) =>
815+
val Annotation(ref, args) = annot
764816
printType(tp)
817+
this += " "
818+
printAnnotation(annot)
765819

766820
case Type.AndType(left, right) =>
767821
printType(left)
@@ -826,6 +880,28 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
826880
case PackageDef(name, _) => this += name
827881
}
828882

883+
def printAnnotation(annot: Term): Buffer = {
884+
val Annotation(ref, args) = annot
885+
this += "@"
886+
printTypeTree(ref)
887+
this += "("
888+
printTrees(args, ", ")
889+
this += ")"
890+
}
891+
892+
def printDefAnnotations(definition: Definition): Buffer = {
893+
val annots = definition.annots.filter {
894+
case Annotation(annot, _) =>
895+
annot.tpe match {
896+
case Type.TypeRef(_, Type.SymRef(PackageDef("internal", _), Type.ThisType(Type.SymRef(PackageDef("annotation", _), NoPrefix())))) => false
897+
case _ => true
898+
}
899+
}
900+
printAnnotations(annots)
901+
if (annots.nonEmpty) this += " "
902+
else this
903+
}
904+
829905
def +=(x: Boolean): this.type = { sb.append(x); this }
830906
def +=(x: Byte): this.type = { sb.append(x); this }
831907
def +=(x: Short): this.type = { sb.append(x); this }
@@ -880,6 +956,13 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
880956
}
881957
}
882958

959+
private object Annotation {
960+
def unapply(arg: Tree)(implicit ctx: Context): Option[(TypeTree, List[Term])] = arg match {
961+
case Term.Apply(Term.Select(Term.New(annot), "<init>", _), args) => Some((annot, args))
962+
case _ => None
963+
}
964+
}
965+
883966
// TODO Provide some of these in scala.tasty.Tasty.scala and implement them using checks on symbols for performance
884967
private object Types {
885968

@@ -917,6 +1000,13 @@ class ShowSourceCode[T <: Tasty with Singleton](tasty0: T) extends Show[T](tasty
9171000
case _ => false
9181001
}
9191002
}
1003+
1004+
object EmptyPrefix {
1005+
def unapply(tpe: TypeOrBounds)(implicit ctx: Context): Boolean = tpe match {
1006+
case NoPrefix() | Type.ThisType(Types.EmptyPackage() | Types.RootPackage()) => true
1007+
case _ => false
1008+
}
1009+
}
9201010
}
9211011

9221012

tests/pos/i2104b.decompiled

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ case class Pair[A, B](_1: A, _2: B) {
1313
scala.runtime.Statics.finalizeHash(acc, 2)
1414
}
1515
override def equals(x$0: scala.Any): scala.Boolean = this.eq(x$0.asInstanceOf[java.lang.Object]).||(x$0 match {
16-
case x$0: Pair[Pair.this.A, Pair.this.B] =>
16+
case x$0: Pair[Pair.this.A, Pair.this.B] @scala.unchecked() =>
1717
this._1.==(x$0._1).&&(this._2.==(x$0._2))
1818
case _ =>
1919
false
2020
})
2121
override def toString(): java.lang.String = scala.runtime.ScalaRunTime._toString(this)
22-
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[Pair[Pair.this.A, Pair.this.B]]
22+
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[Pair[Pair.this.A, Pair.this.B] @scala.unchecked()]
2323
override def productArity: scala.Int = 2
2424
override def productPrefix: java.lang.String = "Pair"
2525
override def productElement(n: scala.Int): scala.Any = n match {

tests/pos/simpleAnnot.decompiled

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/** Decompiled from out/posTestFromTasty/pos/simpleAnnot/Foo.class */
2+
class Foo() {
3+
@annot() type A = scala.Int
4+
@annot() val a: scala.Int = scala.Predef.???
5+
val b: scala.Int @annot() = scala.Predef.???
6+
def c(x: scala.Int): scala.Int = (x: @annot())
7+
}
8+
/** Decompiled from out/posTestFromTasty/pos/simpleAnnot/annot.class */
9+
class annot() extends scala.annotation.Annotation

tests/pos/simpleAnnot.scala

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
class Foo {
3+
@annot type A = Int
4+
@annot val a: Int = ???
5+
val b: Int @annot = ???
6+
def c(x: Int) = (x : @annot)
7+
}
8+
9+
class annot extends scala.annotation.Annotation

tests/pos/simpleCaseClass-1.decompiled

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
case class A() {
33
override def hashCode(): scala.Int = 1914112431
44
override def equals(x$0: scala.Any): scala.Boolean = this.eq(x$0.asInstanceOf[java.lang.Object]).||(x$0 match {
5-
case x$0: A =>
5+
case x$0: A @scala.unchecked() =>
66
true
77
case _ =>
88
false
99
})
1010
override def toString(): java.lang.String = scala.runtime.ScalaRunTime._toString(this)
11-
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A]
11+
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A @scala.unchecked()]
1212
override def productArity: scala.Int = 0
1313
override def productPrefix: java.lang.String = "A"
1414
override def productElement(n: scala.Int): scala.Any = n match {

tests/pos/simpleCaseClass-2.decompiled

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ case class A(x: scala.Int) {
66
scala.runtime.Statics.finalizeHash(acc, 1)
77
}
88
override def equals(x$0: scala.Any): scala.Boolean = this.eq(x$0.asInstanceOf[java.lang.Object]).||(x$0 match {
9-
case x$0: A =>
9+
case x$0: A @scala.unchecked() =>
1010
this.x.==(x$0.x)
1111
case _ =>
1212
false
1313
})
1414
override def toString(): java.lang.String = scala.runtime.ScalaRunTime._toString(this)
15-
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A]
15+
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A @scala.unchecked()]
1616
override def productArity: scala.Int = 1
1717
override def productPrefix: java.lang.String = "A"
1818
override def productElement(n: scala.Int): scala.Any = n match {

tests/pos/simpleCaseClass-3.decompiled

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ case class A[T](x: T) {
66
scala.runtime.Statics.finalizeHash(acc, 1)
77
}
88
override def equals(x$0: scala.Any): scala.Boolean = this.eq(x$0.asInstanceOf[java.lang.Object]).||(x$0 match {
9-
case x$0: A[A.this.T] =>
9+
case x$0: A[A.this.T] @scala.unchecked() =>
1010
this.x.==(x$0.x)
1111
case _ =>
1212
false
1313
})
1414
override def toString(): java.lang.String = scala.runtime.ScalaRunTime._toString(this)
15-
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A[A.this.T]]
15+
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[A[A.this.T] @scala.unchecked()]
1616
override def productArity: scala.Int = 1
1717
override def productPrefix: java.lang.String = "A"
1818
override def productElement(n: scala.Int): scala.Any = n match {

tests/pos/simpleCaseObject.decompiled

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package foo {
33
case object Foo {
44
override def hashCode(): scala.Int = 1045991777
55
override def toString(): java.lang.String = "Foo"
6-
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[foo.Foo]
6+
override def canEqual(that: scala.Any): scala.Boolean = that.isInstanceOf[foo.Foo.type @scala.unchecked()]
77
override def productArity: scala.Int = 0
88
override def productPrefix: java.lang.String = "Foo"
99
override def productElement(n: scala.Int): scala.Any = n match {

0 commit comments

Comments
 (0)