Skip to content

Commit e99f5e5

Browse files
committed
Add message parameter to @experimental annotation
1 parent 6bb6b43 commit e99f5e5

File tree

15 files changed

+100
-27
lines changed

15 files changed

+100
-27
lines changed

compiler/src/dotty/tools/dotc/config/Feature.scala

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,7 @@ object Feature:
131131

132132
def checkExperimentalFeature(which: String, srcPos: SrcPos, note: => String = "")(using Context) =
133133
if !isExperimentalEnabled then
134-
report.error(
135-
em"""Experimental $which may only be used under experimental mode:
136-
| 1. in a definition marked as @experimental, or
137-
| 2. compiling with the -experimental compiler flag, or
138-
| 3. with a nightly or snapshot version of the compiler.$note
139-
""", srcPos)
134+
report.error(experimentalUseSite(which) + note, srcPos)
140135

141136
private def ccException(sym: Symbol)(using Context): Boolean =
142137
ccEnabled && defn.ccExperimental.contains(sym)
@@ -146,12 +141,25 @@ object Feature:
146141
if sym.hasAnnotation(defn.ExperimentalAnnot) then sym
147142
else if sym.owner.hasAnnotation(defn.ExperimentalAnnot) then sym.owner
148143
else NoSymbol
149-
if !ccException(experimentalSym) then
150-
val note =
144+
if !isExperimentalEnabled && !ccException(experimentalSym) then
145+
val msg =
146+
import ast.untpd.*
147+
import Constants.Constant
148+
experimentalSym.getAnnotation(defn.ExperimentalAnnot).map(_.tree).collect {
149+
case Apply(_, List(Literal(Constant(msg: String)))) => s": $msg"
150+
}.getOrElse("")
151+
val markedExperimental =
151152
if experimentalSym.exists
152-
then i"$experimentalSym is marked @experimental"
153-
else i"$sym inherits @experimental"
154-
checkExperimentalFeature("definition", srcPos, s"\n\n$note")
153+
then i"$experimentalSym is marked @experimental$msg"
154+
else i"$sym inherits @experimental$msg"
155+
report.error(markedExperimental + "\n\n" + experimentalUseSite("definition"), srcPos)
156+
157+
private def experimentalUseSite(which: String): String =
158+
s"""Experimental $which may only be used under experimental mode:
159+
| 1. in a definition marked as @experimental, or
160+
| 2. compiling with the -experimental compiler flag, or
161+
| 3. with a nightly or snapshot version of the compiler.
162+
|""".stripMargin
155163

156164
/** Check that experimental compiler options are only set for snapshot or nightly compiler versions. */
157165
def checkExperimentalSettings(using Context): Unit =

compiler/src/dotty/tools/dotc/transform/AccessProxies.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package dotc
33
package transform
44

55
import core.*
6+
import Annotations.Annotation
7+
import Constants.Constant
68
import Contexts.*
79
import Symbols.*
810
import Flags.*
@@ -84,8 +86,7 @@ abstract class AccessProxies {
8486
val sym = newSymbol(owner, name, Synthetic | Method, info, coord = accessed.span).entered
8587
if accessed.is(Private) then sym.setFlag(Final)
8688
else if sym.allOverriddenSymbols.exists(!_.is(Deferred)) then sym.setFlag(Override)
87-
if accessed.hasAnnotation(defn.ExperimentalAnnot) then
88-
sym.addAnnotation(defn.ExperimentalAnnot)
89+
accessed.getAnnotation(defn.ExperimentalAnnot).foreach(sym.addAnnotation)
8990
sym
9091
}
9192

compiler/src/dotty/tools/dotc/transform/PostTyper.scala

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -548,11 +548,10 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
548548
def isTopLevelDefinitionInSource(sym: Symbol) =
549549
!sym.is(Package) && !sym.name.isPackageObjectName &&
550550
(sym.owner.is(Package) || (sym.owner.isPackageObject && !sym.isConstructor))
551-
if !sym.hasAnnotation(defn.ExperimentalAnnot)
552-
&& (ctx.settings.experimental.value && isTopLevelDefinitionInSource(sym))
553-
|| (sym.is(Module) && sym.companionClass.hasAnnotation(defn.ExperimentalAnnot))
554-
then
555-
sym.addAnnotation(Annotation(defn.ExperimentalAnnot, sym.span))
551+
if sym.is(Module) then
552+
sym.companionClass.getAnnotation(defn.ExperimentalAnnot).foreach(sym.addAnnotation)
553+
if !sym.hasAnnotation(defn.ExperimentalAnnot) && ctx.settings.experimental.value && isTopLevelDefinitionInSource(sym) then
554+
sym.addAnnotation(Annotation(defn.ExperimentalAnnot, Literal(Constants.Constant("Added by -experimental")), sym.span))
556555

557556
private def scala2LibPatch(tree: TypeDef)(using Context) =
558557
val sym = tree.symbol

library/src/scala/annotation/experimental.scala renamed to library/src-bootstrapped/scala/annotation/experimental.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ package scala.annotation
66
* @syntax markdown
77
*/
88
@deprecatedInheritance("Scheduled for being final in the future", "3.4.0")
9-
class experimental extends StaticAnnotation
9+
class experimental(message: String) extends StaticAnnotation:
10+
def this() = this("")
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package scala.annotation
2+
3+
@deprecatedInheritance("Scheduled for being final in the future", "3.4.0")
4+
class experimental extends StaticAnnotation

library/src/scala/runtime/stdLibPatches/language.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ object language:
8484
object captureChecking
8585

8686
/** Experimental support for automatic conversions of arguments, without requiring
87-
* a langauge import `import scala.language.implicitConversions`.
87+
* a language import `import scala.language.implicitConversions`.
8888
*
8989
* @see [[https://dotty.epfl.ch/docs/reference/experimental/into-modifier]]
9090
*/

project/MiMaFilters.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ object MiMaFilters {
88
val ForwardsBreakingChanges: Map[String, Seq[ProblemFilter]] = Map(
99
// Additions that require a new minor version of the library
1010
Build.previousDottyVersion -> Seq(
11+
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.annotation.experimental.this"),
1112
),
1213

1314
// Additions since last LTS

tests/neg-macros/i18677-a.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
|The tree does not conform to the compiler's tree invariants.
88
|
99
|Macro was:
10-
|@scala.annotation.internal.SourceFile("tests/neg-macros/i18677-a/Test_2.scala") @scala.annotation.experimental @extendFoo class AFoo()
10+
|@scala.annotation.internal.SourceFile("tests/neg-macros/i18677-a/Test_2.scala") @scala.annotation.experimental("Added by -experimental") @extendFoo class AFoo()
1111
|
1212
|The macro returned:
13-
|@scala.annotation.internal.SourceFile("tests/neg-macros/i18677-a/Test_2.scala") @scala.annotation.experimental @extendFoo class AFoo() extends Foo
13+
|@scala.annotation.internal.SourceFile("tests/neg-macros/i18677-a/Test_2.scala") @scala.annotation.experimental("Added by -experimental") @extendFoo class AFoo() extends Foo
1414
|
1515
|Error:
1616
|assertion failed: Parents of class symbol differs from the parents in the tree for class AFoo

tests/neg-macros/i18677-b.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
|The tree does not conform to the compiler's tree invariants.
88
|
99
|Macro was:
10-
|@scala.annotation.internal.SourceFile("tests/neg-macros/i18677-b/Test_2.scala") @scala.annotation.experimental @extendFoo class AFoo()
10+
|@scala.annotation.internal.SourceFile("tests/neg-macros/i18677-b/Test_2.scala") @scala.annotation.experimental("Added by -experimental") @extendFoo class AFoo()
1111
|
1212
|The macro returned:
13-
|@scala.annotation.internal.SourceFile("tests/neg-macros/i18677-b/Test_2.scala") @scala.annotation.experimental @extendFoo class AFoo() extends Foo
13+
|@scala.annotation.internal.SourceFile("tests/neg-macros/i18677-b/Test_2.scala") @scala.annotation.experimental("Added by -experimental") @extendFoo class AFoo() extends Foo
1414
|
1515
|Error:
1616
|assertion failed: Parents of class symbol differs from the parents in the tree for class AFoo
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
-- Error: tests/neg/experimental-message-experimental-flag/Test_2.scala:3:10 -------------------------------------------
3+
3 |def g() = f() // error
4+
| ^
5+
| method f is marked @experimental: Added by -experimental
6+
|
7+
| Experimental definition may only be used under experimental mode:
8+
| 1. in a definition marked as @experimental, or
9+
| 2. compiling with the -experimental compiler flag, or
10+
| 3. with a nightly or snapshot version of the compiler.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
//> using options -Yno-experimental -experimental
2+
3+
def f() = ???
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
//> using options -Yno-experimental
2+
3+
def g() = f() // error

tests/neg/experimental-message.check

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-- Error: tests/neg/experimental-message.scala:15:2 --------------------------------------------------------------------
2+
15 | f1() // error
3+
| ^^
4+
| method f1 is marked @experimental
5+
|
6+
| Experimental definition may only be used under experimental mode:
7+
| 1. in a definition marked as @experimental, or
8+
| 2. compiling with the -experimental compiler flag, or
9+
| 3. with a nightly or snapshot version of the compiler.
10+
-- Error: tests/neg/experimental-message.scala:16:2 --------------------------------------------------------------------
11+
16 | f2() // error
12+
| ^^
13+
| method f2 is marked @experimental
14+
|
15+
| Experimental definition may only be used under experimental mode:
16+
| 1. in a definition marked as @experimental, or
17+
| 2. compiling with the -experimental compiler flag, or
18+
| 3. with a nightly or snapshot version of the compiler.
19+
-- Error: tests/neg/experimental-message.scala:17:2 --------------------------------------------------------------------
20+
17 | f3() // error
21+
| ^^
22+
| method f3 is marked @experimental: not yet stable
23+
|
24+
| Experimental definition may only be used under experimental mode:
25+
| 1. in a definition marked as @experimental, or
26+
| 2. compiling with the -experimental compiler flag, or
27+
| 3. with a nightly or snapshot version of the compiler.

tests/neg/experimental-message.scala

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//> using options -Yno-experimental
2+
3+
import scala.annotation.experimental
4+
5+
@experimental
6+
def f1() = ???
7+
8+
@experimental()
9+
def f2() = ???
10+
11+
@experimental("not yet stable")
12+
def f3() = ???
13+
14+
def g() =
15+
f1() // error
16+
f2() // error
17+
f3() // error

tests/neg/use-experimental-def.check

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
-- Error: tests/neg/use-experimental-def.scala:7:15 --------------------------------------------------------------------
22
7 |def bar: Int = foo // error
33
| ^^^
4+
| method foo is marked @experimental
5+
|
46
| Experimental definition may only be used under experimental mode:
57
| 1. in a definition marked as @experimental, or
68
| 2. compiling with the -experimental compiler flag, or
79
| 3. with a nightly or snapshot version of the compiler.
8-
|
9-
| method foo is marked @experimental
10-
|

0 commit comments

Comments
 (0)