Skip to content

Commit 59a2f32

Browse files
committed
Improve error messages for @experimental on case classes
1 parent c950006 commit 59a2f32

File tree

4 files changed

+45
-6
lines changed

4 files changed

+45
-6
lines changed

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,16 @@ object Feature:
105105

106106
def checkExperimentalDef(sym: Symbol, srcPos: SrcPos)(using Context) =
107107
if !isExperimentalEnabled then
108-
report.error(i"$sym is marked @experimental and therefore may only be used with a nightly or snapshot version of the compiler", srcPos)
108+
val symMsg =
109+
if sym eq defn.ExperimentalAnnot then
110+
i"use of @experimental is experimental"
111+
else if sym.hasAnnotation(defn.ExperimentalAnnot) then
112+
i"$sym is marked @experimental"
113+
else if sym.owner.hasAnnotation(defn.ExperimentalAnnot) then
114+
i"${sym.owner} is marked @experimental"
115+
else
116+
i"$sym inherits @experimental"
117+
report.error(s"$symMsg and therefore may only be used with a nightly or snapshot version of the compiler", srcPos)
109118

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

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,10 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
447447
if (sym.isEffectivelyErased) dropInlines.transform(rhs) else rhs
448448

449449
private def annotateExperimental(sym: Symbol)(using Context): Unit =
450+
if sym.is(Module) && sym.companionClass.hasAnnotation(defn.ExperimentalAnnot) then
451+
sym.addAnnotation(defn.ExperimentalAnnot)
452+
sym.companionModule.addAnnotation(defn.ExperimentalAnnot)
453+
450454
if sym.is(Enum) && sym.hasAnnotation(defn.ExperimentalAnnot) then
451455
// Add @experimental annotation to enum class definitions
452456
val compMod = sym.companionModule.moduleClass

compiler/src/dotty/tools/dotc/typer/RefChecks.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -978,15 +978,15 @@ object RefChecks {
978978
then
979979
Feature.checkExperimentalDef(sym, pos)
980980

981-
private def checkExperimentalTypes(tpe: Type, pos: SrcPos)(using Context): Unit =
981+
private def checkExperimentalSignature(sym: Symbol, pos: SrcPos)(using Context): Unit =
982982
val checker = new TypeTraverser:
983983
def traverse(tp: Type): Unit =
984984
if tp.typeSymbol.isExperimental then
985985
Feature.checkExperimentalDef(tp.typeSymbol, pos)
986986
else
987987
traverseChildren(tp)
988-
if !pos.span.isSynthetic then // avoid double errors
989-
checker.traverse(tpe)
988+
if !sym.owner.isExperimental && !pos.span.isSynthetic then // avoid double errors
989+
checker.traverse(sym.info)
990990

991991
private def checkExperimentalAnnots(sym: Symbol)(using Context): Unit =
992992
for annot <- sym.annotations if annot.symbol.isExperimental && annot.tree.span.exists do
@@ -1230,7 +1230,7 @@ class RefChecks extends MiniPhase { thisPhase =>
12301230
checkNoPrivateOverrides(tree)
12311231
checkDeprecatedOvers(tree)
12321232
checkExperimentalAnnots(tree.symbol)
1233-
checkExperimentalTypes(tree.symbol.info, tree)
1233+
checkExperimentalSignature(tree.symbol, tree)
12341234
val sym = tree.symbol
12351235
if (sym.exists && sym.owner.isTerm) {
12361236
tree.rhs match {
@@ -1252,7 +1252,7 @@ class RefChecks extends MiniPhase { thisPhase =>
12521252
checkNoPrivateOverrides(tree)
12531253
checkDeprecatedOvers(tree)
12541254
checkExperimentalAnnots(tree.symbol)
1255-
checkExperimentalTypes(tree.symbol.info, tree)
1255+
checkExperimentalSignature(tree.symbol, tree)
12561256
checkImplicitNotFoundAnnotation.defDef(tree.symbol.denot)
12571257
tree
12581258
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import scala.annotation.experimental
2+
3+
@experimental // error
4+
case class Foo(a: Int)
5+
6+
@experimental // error
7+
case class Bar(a: Int)
8+
9+
object Bar:
10+
def f(): Unit = ()
11+
12+
def test: Unit =
13+
Foo(2) // error
14+
val x: Foo = ??? // error
15+
16+
x match
17+
case Foo(a) => // error
18+
19+
20+
Bar(2) // error
21+
val y: Bar = ??? // error
22+
23+
y match
24+
case Bar(a) => // error
25+
26+
Bar.f() // error

0 commit comments

Comments
 (0)