From 0ce5de51db6d657e3561b314a227114f70ba75e9 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Mon, 9 May 2022 17:49:59 +0200 Subject: [PATCH] Fix check experimental inline references We where not checking if the current scope was an experimental scope Fixes #15133 --- .../tools/dotc/typer/CrossVersionChecks.scala | 18 +++++++++++------- .../src/dotty/tools/dotc/typer/Inliner.scala | 5 ++--- .../no-experimental/i15133a.scala | 15 +++++++++++++++ .../no-experimental/i15133b.scala | 13 +++++++++++++ 4 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 tests/pos-custom-args/no-experimental/i15133a.scala create mode 100644 tests/pos-custom-args/no-experimental/i15133b.scala diff --git a/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala b/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala index c2b8c79666f4..a807d8299b41 100644 --- a/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala @@ -12,6 +12,7 @@ import ast.tpd class CrossVersionChecks extends MiniPhase: import tpd.* + import CrossVersionChecks.* override def phaseName: String = CrossVersionChecks.name @@ -27,7 +28,7 @@ class CrossVersionChecks extends MiniPhase: // arbitrarily choose one as more important than the other. private def checkUndesiredProperties(sym: Symbol, pos: SrcPos)(using Context): Unit = checkDeprecated(sym, pos) - checkExperimental(sym, pos) + checkExperimentalRef(sym, pos) checkSinceAnnot(sym, pos) val xMigrationValue = ctx.settings.Xmigration.value @@ -69,10 +70,6 @@ class CrossVersionChecks extends MiniPhase: val since = annot.argumentConstant(1).map(" since " + _.stringValue).getOrElse("") report.deprecationWarning(s"${sym.showLocated} is deprecated${since}${msg}", pos) - private def checkExperimental(sym: Symbol, pos: SrcPos)(using Context): Unit = - if sym.isExperimental && !ctx.owner.isInExperimentalScope then - Feature.checkExperimentalDef(sym, pos) - private def checkExperimentalSignature(sym: Symbol, pos: SrcPos)(using Context): Unit = class Checker extends TypeTraverser: def traverse(tp: Type): Unit = @@ -192,11 +189,11 @@ class CrossVersionChecks extends MiniPhase: tpe.foreachPart { case TypeRef(_, sym: Symbol) => checkDeprecated(sym, tree.srcPos) - checkExperimental(sym, tree.srcPos) + checkExperimentalRef(sym, tree.srcPos) checkSinceAnnot(sym, tree.srcPos) case TermRef(_, sym: Symbol) => checkDeprecated(sym, tree.srcPos) - checkExperimental(sym, tree.srcPos) + checkExperimentalRef(sym, tree.srcPos) checkSinceAnnot(sym, tree.srcPos) case _ => } @@ -214,3 +211,10 @@ end CrossVersionChecks object CrossVersionChecks: val name: String = "crossVersionChecks" val description: String = "check issues related to deprecated and experimental" + + /** Check that a reference to an experimental definition with symbol `sym` is only + * used in an experimental scope + */ + def checkExperimentalRef(sym: Symbol, pos: SrcPos)(using Context): Unit = + if sym.isExperimental && !ctx.owner.isInExperimentalScope then + Feature.checkExperimentalDef(sym, pos) diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index b1f4eb0b00ba..3421e633ac03 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -25,7 +25,7 @@ import ErrorReporting.errorTree import dotty.tools.dotc.util.{SimpleIdentityMap, SimpleIdentitySet, SourceFile, SourcePosition, SrcPos} import dotty.tools.dotc.parsing.Parsers.Parser import Nullables._ -import transform.{PostTyper, Inlining} +import transform.{PostTyper, Inlining, CrossVersionChecks} import collection.mutable import reporting.trace @@ -102,8 +102,7 @@ object Inliner { if (tree.symbol == defn.CompiletimeTesting_typeChecks) return Intrinsics.typeChecks(tree) if (tree.symbol == defn.CompiletimeTesting_typeCheckErrors) return Intrinsics.typeCheckErrors(tree) - if tree.symbol.isExperimental then - Feature.checkExperimentalDef(tree.symbol, tree) + CrossVersionChecks.checkExperimentalRef(tree.symbol, tree.srcPos) if tree.symbol.isConstructor then return tree // error already reported for the inline constructor definition diff --git a/tests/pos-custom-args/no-experimental/i15133a.scala b/tests/pos-custom-args/no-experimental/i15133a.scala new file mode 100644 index 000000000000..c7f55f7838c7 --- /dev/null +++ b/tests/pos-custom-args/no-experimental/i15133a.scala @@ -0,0 +1,15 @@ +import scala.annotation.experimental + +@experimental +inline def foo: Any = ??? + +@experimental +object Test { + val x = foo + + def bar() = { + foo + } + + foo +} diff --git a/tests/pos-custom-args/no-experimental/i15133b.scala b/tests/pos-custom-args/no-experimental/i15133b.scala new file mode 100644 index 000000000000..d14d6e84cf6e --- /dev/null +++ b/tests/pos-custom-args/no-experimental/i15133b.scala @@ -0,0 +1,13 @@ +import scala.annotation.experimental + +@experimental +inline def foo: Any = ??? + +object Test { + @experimental val x = foo + + @experimental + def bar() = { + foo + } +}