From 89d61044a166b842febee7e7584cc6b09a0761ed Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 26 Feb 2024 12:55:14 +0100 Subject: [PATCH] Improve error message when using experimental definitions When an experimental definition is used, the error message shows how to enable the experimental mode. Previously we only did this for experimental language features, but not for experimental definitions. --- .../src/dotty/tools/dotc/config/Feature.scala | 27 +++++++++---------- tests/neg/use-experimental-def.check | 10 +++++++ tests/neg/use-experimental-def.scala | 7 +++++ 3 files changed, 30 insertions(+), 14 deletions(-) create mode 100644 tests/neg/use-experimental-def.check create mode 100644 tests/neg/use-experimental-def.scala diff --git a/compiler/src/dotty/tools/dotc/config/Feature.scala b/compiler/src/dotty/tools/dotc/config/Feature.scala index f2ed58a5c8ca..448473a57885 100644 --- a/compiler/src/dotty/tools/dotc/config/Feature.scala +++ b/compiler/src/dotty/tools/dotc/config/Feature.scala @@ -135,26 +135,25 @@ object Feature: if !isExperimentalEnabled then report.error( em"""Experimental $which may only be used under experimental mode: - | 1. In a definition marked as @experimental - | 2. Compiling with the -experimental compiler flag - | 3. With a nightly or snapshot version of the compiler$note + | 1. in a definition marked as @experimental, or + | 2. compiling with the -experimental compiler flag, or + | 3. with a nightly or snapshot version of the compiler.$note """, srcPos) private def ccException(sym: Symbol)(using Context): Boolean = ccEnabled && defn.ccExperimental.contains(sym) def checkExperimentalDef(sym: Symbol, srcPos: SrcPos)(using Context) = - if !isExperimentalEnabled then - val experimentalSym = - if sym.hasAnnotation(defn.ExperimentalAnnot) then sym - else if sym.owner.hasAnnotation(defn.ExperimentalAnnot) then sym.owner - else NoSymbol - if !ccException(experimentalSym) then - val symMsg = - if experimentalSym.exists - then i"$experimentalSym is marked @experimental" - else i"$sym inherits @experimental" - report.error(em"$symMsg and therefore may only be used in an experimental scope.", srcPos) + val experimentalSym = + if sym.hasAnnotation(defn.ExperimentalAnnot) then sym + else if sym.owner.hasAnnotation(defn.ExperimentalAnnot) then sym.owner + else NoSymbol + if !ccException(experimentalSym) then + val note = + if experimentalSym.exists + then i"$experimentalSym is marked @experimental" + else i"$sym inherits @experimental" + checkExperimentalFeature("definition", srcPos, s"\n\n$note") /** Check that experimental compiler options are only set for snapshot or nightly compiler versions. */ def checkExperimentalSettings(using Context): Unit = diff --git a/tests/neg/use-experimental-def.check b/tests/neg/use-experimental-def.check new file mode 100644 index 000000000000..66c4a7a305b5 --- /dev/null +++ b/tests/neg/use-experimental-def.check @@ -0,0 +1,10 @@ +-- Error: tests/neg/use-experimental-def.scala:7:15 -------------------------------------------------------------------- +7 |def bar: Int = foo // error + | ^^^ + | Experimental definition may only be used under experimental mode: + | 1. in a definition marked as @experimental, or + | 2. compiling with the -experimental compiler flag, or + | 3. with a nightly or snapshot version of the compiler. + | + | method foo is marked @experimental + | diff --git a/tests/neg/use-experimental-def.scala b/tests/neg/use-experimental-def.scala new file mode 100644 index 000000000000..68ce0d6987ab --- /dev/null +++ b/tests/neg/use-experimental-def.scala @@ -0,0 +1,7 @@ +//> using options -Yno-experimental + +import scala.annotation.experimental + +@experimental def foo: Int = 1 + +def bar: Int = foo // error