Skip to content

Commit 449d44e

Browse files
committed
Clean up printing of annotations
Always print annotation arguments if there are some, except for Body annotations
1 parent d8cf8a3 commit 449d44e

File tree

6 files changed

+50
-17
lines changed

6 files changed

+50
-17
lines changed

compiler/src/dotty/tools/dotc/core/Annotations.scala

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ import StdNames._
77
import dotty.tools.dotc.ast.tpd
88
import scala.util.Try
99
import util.Spans.Span
10+
import printing.{Showable, Printer}
11+
import printing.Texts.Text
1012

1113
object Annotations {
1214

1315
def annotClass(tree: Tree)(using Context) =
1416
if (tree.symbol.isConstructor) tree.symbol.owner
1517
else tree.tpe.typeSymbol
1618

17-
abstract class Annotation {
19+
abstract class Annotation extends Showable {
1820
def tree(using Context): Tree
1921

2022
def symbol(using Context): Symbol = annotClass(tree)
@@ -44,15 +46,18 @@ object Annotations {
4446
/** The tree evaluation has finished. */
4547
def isEvaluated: Boolean = true
4648

49+
/** A string representation of the annotation. Overridden in BodyAnnotation.
50+
*/
51+
def toText(printer: Printer): Text = printer.annotText(this)
52+
4753
def ensureCompleted(using Context): Unit = tree
4854

4955
def sameAnnotation(that: Annotation)(using Context): Boolean =
5056
symbol == that.symbol && tree.sameTree(that.tree)
5157
}
5258

53-
case class ConcreteAnnotation(t: Tree) extends Annotation {
59+
case class ConcreteAnnotation(t: Tree) extends Annotation:
5460
def tree(using Context): Tree = t
55-
}
5661

5762
abstract class LazyAnnotation extends Annotation {
5863
protected var mySym: Symbol | (Context ?=> Symbol)
@@ -98,6 +103,7 @@ object Annotations {
98103
if (tree eq this.tree) this else ConcreteBodyAnnotation(tree)
99104
override def arguments(using Context): List[Tree] = Nil
100105
override def ensureCompleted(using Context): Unit = ()
106+
override def toText(printer: Printer): Text = "@Body"
101107
}
102108

103109
class ConcreteBodyAnnotation(body: Tree) extends BodyAnnotation {

compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,10 @@ class PlainPrinter(_ctx: Context) extends Printer {
539539
case _ => literalText(String.valueOf(const.value))
540540
}
541541

542-
def toText(annot: Annotation): Text = s"@${annot.symbol.name}" // for now
542+
/** Usual target for `Annotation#toText`, overridden in RefinedPrinter */
543+
def annotText(annot: Annotation): Text = s"@${annot.symbol.name}"
544+
545+
def toText(annot: Annotation): Text = annot.toText(this)
543546

544547
def toText(param: LambdaParam): Text =
545548
varianceSign(param.paramVariance)
@@ -570,7 +573,7 @@ class PlainPrinter(_ctx: Context) extends Printer {
570573
Text()
571574

572575
nodeName ~ "(" ~ elems ~ tpSuffix ~ ")" ~ (Str(tree.sourcePos.toString) provided printDebug)
573-
}.close // todo: override in refined printer
576+
}.close
574577

575578
def toText(pos: SourcePosition): Text =
576579
if (!pos.exists) "<no position>"

compiler/src/dotty/tools/dotc/printing/Printer.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ abstract class Printer {
119119
/** A description of sym's location */
120120
def extendedLocationText(sym: Symbol): Text
121121

122+
/** Textual description of regular annotation in terms of its tree */
123+
def annotText(annot: Annotation): Text
124+
122125
/** Textual representation of denotation */
123126
def toText(denot: Denotation): Text
124127

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import typer.ProtoTypes._
2121
import Trees._
2222
import TypeApplications._
2323
import Decorators._
24-
import NameKinds.WildcardParamName
24+
import NameKinds.{WildcardParamName, DefaultGetterName}
2525
import util.Chars.isOperatorPart
2626
import transform.TypeUtils._
2727
import transform.SymUtils._
@@ -607,7 +607,7 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
607607
case tree: Template =>
608608
toTextTemplate(tree)
609609
case Annotated(arg, annot) =>
610-
toTextLocal(arg) ~~ annotText(annot)
610+
toTextLocal(arg) ~~ toText(annot)
611611
case EmptyTree =>
612612
"<empty>"
613613
case TypedSplice(t) =>
@@ -964,14 +964,18 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
964964
keywordStr("package ") ~ toTextPackageId(tree.pid) ~ bodyText
965965
}
966966

967+
/** Textual representation of an instance creation expression without the leading `new` */
967968
protected def constrText(tree: untpd.Tree): Text = toTextLocal(tree).stripPrefix(keywordStr("new ")) // DD
968969

969-
protected def annotText(tree: untpd.Tree): Text = "@" ~ constrText(tree) // DD
970-
971-
override def annotsText(sym: Symbol): Text =
972-
Text(sym.annotations.map(ann =>
973-
if ann.symbol == defn.BodyAnnot then Str(simpleNameString(ann.symbol))
974-
else annotText(ann.tree)))
970+
protected def annotText(sym: Symbol, tree: untpd.Tree): Text =
971+
def recur(t: untpd.Tree): Text = t match
972+
case Apply(fn, Nil) => recur(fn)
973+
case Apply(fn, args) =>
974+
val explicitArgs = args.filterNot(_.symbol.name.is(DefaultGetterName))
975+
recur(fn) ~ "(" ~ toTextGlobal(explicitArgs, ", ") ~ ")"
976+
case TypeApply(fn, args) => recur(fn) ~ "[" ~ toTextGlobal(args, ", ") ~ "]"
977+
case _ => s"@${sym.orElse(tree.symbol).name}"
978+
recur(tree)
975979

976980
protected def modText(mods: untpd.Modifiers, sym: Symbol, kw: String, isType: Boolean): Text = { // DD
977981
val suppressKw = if (enclDefIsClass) mods.isAllOf(LocalParam) else mods.is(Param)
@@ -984,12 +988,16 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
984988
if (rawFlags.is(Param)) flagMask = flagMask &~ Given &~ Erased
985989
val flags = rawFlags & flagMask
986990
var flagsText = toTextFlags(sym, flags)
987-
val annotations =
988-
if (sym.exists) sym.annotations.filterNot(ann => dropAnnotForModText(ann.symbol)).map(_.tree)
989-
else mods.annotations.filterNot(tree => dropAnnotForModText(tree.symbol))
990-
Text(annotations.map(annotText), " ") ~~ flagsText ~~ (Str(kw) provided !suppressKw)
991+
val annotTexts =
992+
if sym.exists then
993+
sym.annotations.filterNot(ann => dropAnnotForModText(ann.symbol)).map(toText)
994+
else
995+
mods.annotations.filterNot(tree => dropAnnotForModText(tree.symbol)).map(annotText(NoSymbol, _))
996+
Text(annotTexts, " ") ~~ flagsText ~~ (Str(kw) provided !suppressKw)
991997
}
992998

999+
override def annotText(annot: Annotation): Text = annotText(annot.symbol, annot.tree)
1000+
9931001
def optText(name: Name)(encl: Text => Text): Text =
9941002
if (name.isEmpty) "" else encl(toText(name))
9951003

tests/neg/annot-printing.check

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- [E007] Type Mismatch Error: tests/neg/annot-printing.scala:5:46 -----------------------------------------------------
2+
5 |def x: Int @nowarn @main @Foo @Bar("hello") = "abc" // error
3+
| ^^^^^
4+
| Found: ("abc" : String)
5+
| Required: Int @nowarn() @main @Foo @Bar("hello")
6+
7+
longer explanation available when compiling with `-explain`

tests/neg/annot-printing.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import scala.annotation.*
2+
class Foo() extends Annotation
3+
class Bar(s: String) extends Annotation
4+
5+
def x: Int @nowarn @main @Foo @Bar("hello") = "abc" // error
6+

0 commit comments

Comments
 (0)