From e7ad723937e62be432419a48b0df136458652e65 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Thu, 26 Aug 2021 15:39:33 +0200 Subject: [PATCH] Allow experimental erased in experimental scopes Closes #13392 --- .../src/dotty/tools/dotc/parsing/Parsers.scala | 2 +- .../tools/dotc/transform/PruneErasedDefs.scala | 11 +++++++++++ .../no-experimental/experimentalErased.scala | 17 +++++++++++++++++ tests/pos/experimentalErased.scala | 17 +++++++++++++++++ tests/pos/i13392.scala | 11 +++++++++++ 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tests/neg-custom-args/no-experimental/experimentalErased.scala create mode 100644 tests/pos/experimentalErased.scala create mode 100644 tests/pos/i13392.scala diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index effbfe22f0e4..da2ed12214df 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -3115,7 +3115,7 @@ object Parsers { case Some(prefix) => in.languageImportContext = in.languageImportContext.importContext(imp, NoSymbol) if prefix == nme.experimental - && selectors.exists(sel => Feature.experimental(sel.name) != Feature.scala2macros) + && selectors.exists(sel => Feature.experimental(sel.name) != Feature.scala2macros && Feature.experimental(sel.name) != Feature.erasedDefinitions) then Feature.checkExperimentalFeature("features", imp.srcPos) for diff --git a/compiler/src/dotty/tools/dotc/transform/PruneErasedDefs.scala b/compiler/src/dotty/tools/dotc/transform/PruneErasedDefs.scala index b8e7a7924a79..ea3dbe0fa652 100644 --- a/compiler/src/dotty/tools/dotc/transform/PruneErasedDefs.scala +++ b/compiler/src/dotty/tools/dotc/transform/PruneErasedDefs.scala @@ -12,6 +12,8 @@ import typer.RefChecks import MegaPhase.MiniPhase import StdNames.nme import ast.tpd +import SymUtils._ +import config.Feature /** This phase makes all erased term members of classes private so that they cannot * conflict with non-erased members. This is needed so that subsequent phases like @@ -39,13 +41,22 @@ class PruneErasedDefs extends MiniPhase with SymTransformer { thisTransform => else cpy.Apply(tree)(tree.fun, tree.args.map(trivialErasedTree)) override def transformValDef(tree: ValDef)(using Context): Tree = + checkErasedInExperimental(tree.symbol) if !tree.symbol.isEffectivelyErased || tree.rhs.isEmpty then tree else cpy.ValDef(tree)(rhs = trivialErasedTree(tree.rhs)) override def transformDefDef(tree: DefDef)(using Context): Tree = + checkErasedInExperimental(tree.symbol) if !tree.symbol.isEffectivelyErased || tree.rhs.isEmpty then tree else cpy.DefDef(tree)(rhs = trivialErasedTree(tree.rhs)) + override def transformTypeDef(tree: TypeDef)(using Context): Tree = + checkErasedInExperimental(tree.symbol) + tree + + def checkErasedInExperimental(sym: Symbol)(using Context): Unit = + if sym.is(Erased) && !sym.isInExperimentalScope then + Feature.checkExperimentalFeature("erased", sym.sourcePos) } object PruneErasedDefs { diff --git a/tests/neg-custom-args/no-experimental/experimentalErased.scala b/tests/neg-custom-args/no-experimental/experimentalErased.scala new file mode 100644 index 000000000000..171318e7eb97 --- /dev/null +++ b/tests/neg-custom-args/no-experimental/experimentalErased.scala @@ -0,0 +1,17 @@ +import language.experimental.erasedDefinitions +import annotation.experimental + +@experimental +erased class Foo + +erased class Bar // error + +@experimental +erased def foo = 2 + +erased def bar = 2 // error + +@experimental +erased val foo2 = 2 + +erased val bar2 = 2 // error \ No newline at end of file diff --git a/tests/pos/experimentalErased.scala b/tests/pos/experimentalErased.scala new file mode 100644 index 000000000000..e46a305ae302 --- /dev/null +++ b/tests/pos/experimentalErased.scala @@ -0,0 +1,17 @@ +import language.experimental.erasedDefinitions +import annotation.experimental + +@experimental +erased class Foo + +erased class Bar + +@experimental +erased def foo = 2 + +erased def bar = 2 + +@experimental +erased val foo2 = 2 + +erased val bar2 = 2 \ No newline at end of file diff --git a/tests/pos/i13392.scala b/tests/pos/i13392.scala new file mode 100644 index 000000000000..de489b9aa75a --- /dev/null +++ b/tests/pos/i13392.scala @@ -0,0 +1,11 @@ +package scala +import language.experimental.erasedDefinitions +import annotation.{implicitNotFound, experimental} + +@experimental +@implicitNotFound("The capability to throw exception ${E} is missing.\nThe capability can be provided by one of the following:\n - A using clause `(using CanThrow[${E}])`\n - A `throws` clause in a result type such as `X throws ${E}`\n - an enclosing `try` that catches ${E}") +erased class CanThrow[-E <: Exception] + +@experimental +object unsafeExceptions: + given canThrowAny: CanThrow[Exception] = ???