From 65141abe9e4a1a69a937a40c3a6f9b0183144558 Mon Sep 17 00:00:00 2001 From: Hamza Remmal Date: Sun, 16 Nov 2025 22:47:52 +0100 Subject: [PATCH 1/2] feat: introduce `scala.annotation.meta.exportable` --- compiler/src/dotty/tools/dotc/core/Annotations.scala | 3 +++ compiler/src/dotty/tools/dotc/core/Definitions.scala | 1 + compiler/src/dotty/tools/dotc/typer/Namer.scala | 7 +------ library/src/scala/annotation/meta/exportable.scala | 3 +++ 4 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 library/src/scala/annotation/meta/exportable.scala diff --git a/compiler/src/dotty/tools/dotc/core/Annotations.scala b/compiler/src/dotty/tools/dotc/core/Annotations.scala index 1615679a036e..976dd793b303 100644 --- a/compiler/src/dotty/tools/dotc/core/Annotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Annotations.scala @@ -109,6 +109,9 @@ object Annotations { /** Operations for hash-consing, can be overridden */ def hash: Int = System.identityHashCode(this) def eql(that: Annotation) = this eq that + + final def isExportable(using Context): Boolean = + symbol.hasAnnotation(defn.ExportableAnnotation) } case class ConcreteAnnotation(t: Tree) extends Annotation: diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index d2e4348c96fc..83dffaf3a80a 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1098,6 +1098,7 @@ class Definitions { @tu lazy val GetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.getter") @tu lazy val ParamMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.param") @tu lazy val SetterMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.setter") + @tu lazy val ExportableAnnotation: ClassSymbol = requiredClass("scala.annotation.meta.exportable") @tu lazy val CompanionClassMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.companionClass") @tu lazy val CompanionMethodMetaAnnot: ClassSymbol = requiredClass("scala.annotation.meta.companionMethod") @tu lazy val ShowAsInfixAnnot: ClassSymbol = requiredClass("scala.annotation.showAsInfix") diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index fc7067c7b45e..79af3b9d8bf2 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1351,12 +1351,7 @@ class Namer { typer: Typer => forwarder.info = avoidPrivateLeaks(forwarder) // Add annotations at the member level - forwarder.addAnnotations(sym.annotations.filterConserve { annot => - annot.symbol != defn.BodyAnnot - && annot.symbol != defn.TailrecAnnot - && annot.symbol != defn.MainAnnot - && !annot.symbol.derivesFrom(defn.MacroAnnotationClass) - }) + forwarder.addAnnotations(sym.annotations.filterConserve(_.isExportable)) if forwarder.isType then buf += tpd.TypeDef(forwarder.asType).withSpan(span) diff --git a/library/src/scala/annotation/meta/exportable.scala b/library/src/scala/annotation/meta/exportable.scala new file mode 100644 index 000000000000..5407dca3d0cf --- /dev/null +++ b/library/src/scala/annotation/meta/exportable.scala @@ -0,0 +1,3 @@ +package scala.annotation.meta + +final class exportable extends scala.annotation.StaticAnnotation From b89b2fc83bfaf06c60b8638a51da8e29307716c9 Mon Sep 17 00:00:00 2001 From: Hamza Remmal Date: Sun, 16 Nov 2025 23:04:40 +0100 Subject: [PATCH 2/2] mark some annotations as `@exportable` --- library/src/scala/annotation/experimental.scala | 2 ++ library/src/scala/annotation/targetName.scala | 2 ++ library/src/scala/deprecated.scala | 1 + library/src/scala/throws.scala | 2 ++ 4 files changed, 7 insertions(+) diff --git a/library/src/scala/annotation/experimental.scala b/library/src/scala/annotation/experimental.scala index ee91a6408b4b..e68722bb0d38 100644 --- a/library/src/scala/annotation/experimental.scala +++ b/library/src/scala/annotation/experimental.scala @@ -1,11 +1,13 @@ package scala.annotation import language.experimental.captureChecking +import meta.exportable /** An annotation that can be used to mark a definition as experimental. * * @see [[https://dotty.epfl.ch/docs/reference/other-new-features/experimental-defs]] * @syntax markdown */ +@exportable final class experimental(message: String) extends StaticAnnotation: def this() = this("") diff --git a/library/src/scala/annotation/targetName.scala b/library/src/scala/annotation/targetName.scala index 17945fa86fb7..b71009958b0a 100644 --- a/library/src/scala/annotation/targetName.scala +++ b/library/src/scala/annotation/targetName.scala @@ -1,10 +1,12 @@ package scala.annotation import language.experimental.captureChecking +import meta.exportable /** An annotation that defines an external name for a definition. * If an `targetName(extname)` annotation is given for a method or some other * definition, its implementation will use the name `extname` instead of * the regular name. */ +@exportable final class targetName(name: String) extends StaticAnnotation diff --git a/library/src/scala/deprecated.scala b/library/src/scala/deprecated.scala index 181d25ebc37d..ec04a32c2b1f 100644 --- a/library/src/scala/deprecated.scala +++ b/library/src/scala/deprecated.scala @@ -60,6 +60,7 @@ import scala.annotation.meta._ * @see [[scala.deprecatedOverriding]] * @see [[scala.deprecatedName]] */ +@exportable @getter @setter @beanGetter @beanSetter @field @deprecatedInheritance("Scheduled for being final in the future", "2.13.0") class deprecated(message: String = "", since: String = "") extends scala.annotation.ConstantAnnotation diff --git a/library/src/scala/throws.scala b/library/src/scala/throws.scala index 898c745a4804..5b35c8a58be0 100644 --- a/library/src/scala/throws.scala +++ b/library/src/scala/throws.scala @@ -13,6 +13,7 @@ package scala import scala.language.`2.13` +import scala.annotation.meta.exportable /** * Annotation for specifying the exceptions thrown by a method. @@ -25,6 +26,7 @@ import scala.language.`2.13` * } * }}} */ +@exportable final class throws[T <: Throwable](cause: String = "") extends scala.annotation.StaticAnnotation { def this(clazz: Class[T]) = this("") }