Skip to content

Commit cadf3bf

Browse files
authored
Merge pull request #11920 from dotty-staging/fix-11774-v2
Only enable experimental features for snapshot and nightly (V2)
2 parents e7a6e31 + a9b808b commit cadf3bf

File tree

15 files changed

+92
-29
lines changed

15 files changed

+92
-29
lines changed

community-build/src/scala/dotty/communitybuild/projects.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ lazy val compilerVersion: String =
1010
val file = communitybuildDir.resolve("scala3-bootstrapped.version")
1111
new String(Files.readAllBytes(file), UTF_8)
1212

13+
lazy val compilerSupportExperimental: Boolean =
14+
compilerVersion.contains("SNAPSHOT") || compilerVersion.contains("NIGHTLY")
15+
1316
lazy val sbtPluginFilePath: String =
1417
// Workaround for https://github.com/sbt/sbt/issues/4395
1518
new File(sys.props("user.home") + "/.sbt/1.0/plugins").mkdirs()

community-build/test/scala/dotty/communitybuild/CommunityBuildTest.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ class CommunityBuildTestB extends CommunityBuildTest:
116116
@Test def disciplineSpecs2 = projects.disciplineSpecs2.run()
117117
@Test def munit = projects.munit.run()
118118
@Test def perspective = projects.perspective.run()
119-
@Test def scodec = projects.scodec.run()
120-
@Test def scodecBits = projects.scodecBits.run()
119+
@Test def scodec = if compilerSupportExperimental then projects.scodec.run()
120+
@Test def scodecBits = if compilerSupportExperimental then projects.scodecBits.run()
121121
@Test def simulacrumScalafixAnnotations = projects.simulacrumScalafixAnnotations.run()
122122
end CommunityBuildTestB
123123

@@ -134,7 +134,7 @@ class CommunityBuildTestC extends CommunityBuildTest:
134134
@Test def fansi = projects.fansi.run()
135135
@Test def fastparse = projects.fastparse.run()
136136
@Test def geny = projects.geny.run()
137-
@Test def intent = projects.intent.run()
137+
@Test def intent = if compilerSupportExperimental then projects.intent.run()
138138
@Test def minitest = projects.minitest.run()
139139
@Test def onnxScala = projects.onnxScala.run()
140140
@Test def oslib = projects.oslib.run()
@@ -151,7 +151,7 @@ class CommunityBuildTestC extends CommunityBuildTest:
151151
@Test def scalatestplusScalacheck = projects.scalatestplusScalacheck.run()
152152
@Test def scalaXml = projects.scalaXml.run()
153153
@Test def scalaz = projects.scalaz.run()
154-
@Test def scas = projects.scas.run()
154+
@Test def scas = if compilerSupportExperimental then projects.scas.run()
155155
@Test def sconfig = projects.sconfig.run()
156156
@Test def shapeless = projects.shapeless.run()
157157
@Test def sourcecode = projects.sourcecode.run()

compiler/src/dotty/tools/dotc/Driver.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class Driver {
7777
val ictx = rootCtx.fresh
7878
val summary = command.distill(args, ictx.settings)(ictx.settingsState)(using ictx)
7979
ictx.setSettings(summary.sstate)
80+
Feature.checkExperimentalSettings(using ictx)
8081
MacroClassLoader.init(ictx)
8182
Positioned.init(using ictx)
8283

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,6 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
277277
case _ => None
278278
case _ => None
279279

280-
def isLanguageImport(path: Tree): Boolean = languageImport(path).isDefined
281-
282280
/** The underlying pattern ignoring any bindings */
283281
def unbind(x: Tree): Tree = unsplice(x) match {
284282
case Bind(_, y) => unbind(y)

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
package dotty.tools.dotc.config
2+
import annotation.internal.sharable
23

34
object Config {
45

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

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,29 @@ import core._
66
import Contexts._, Symbols._, Names._, NameOps._, Phases._
77
import StdNames.nme
88
import Decorators.{_, given}
9-
import util.SrcPos
9+
import util.{SrcPos, NoSourcePosition}
1010
import SourceVersion._
1111
import reporting.Message
1212
import NameKinds.QualifiedName
1313

1414
object Feature:
1515

16-
private def experimental(str: String): TermName =
16+
def experimental(str: PreName): TermName =
1717
QualifiedName(nme.experimental, str.toTermName)
1818

19-
private def deprecated(str: String): TermName =
19+
private def deprecated(str: PreName): TermName =
2020
QualifiedName(nme.deprecated, str.toTermName)
2121

2222
private val namedTypeArguments = experimental("namedTypeArguments")
2323
private val genericNumberLiterals = experimental("genericNumberLiterals")
24-
private val scala2macros = experimental("macros")
24+
val scala2macros = experimental("macros")
2525

2626
val dependent = experimental("dependent")
2727
val erasedDefinitions = experimental("erasedDefinitions")
2828
val symbolLiterals = deprecated("symbolLiterals")
2929
val fewerBraces = experimental("fewerBraces")
3030

31-
/** Is `feature` enabled by by a command-line setting? The enabling setting is
31+
/** Is `feature` enabled by by a command-line setting? The enabling setting is
3232
*
3333
* -language:<prefix>feature
3434
*
@@ -97,4 +97,22 @@ object Feature:
9797
else
9898
false
9999

100+
private val assumeExperimentalIn = Set("dotty.tools.vulpix.ParallelTesting")
101+
102+
def checkExperimentalFeature(which: String, srcPos: SrcPos = NoSourcePosition)(using Context) =
103+
def hasSpecialPermission =
104+
new Exception().getStackTrace.exists(elem =>
105+
assumeExperimentalIn.exists(elem.getClassName().startsWith(_)))
106+
if !(Properties.experimental || hasSpecialPermission)
107+
|| ctx.settings.YnoExperimental.value
108+
then
109+
//println(i"${new Exception().getStackTrace.map(_.getClassName).toList}%\n%")
110+
report.error(i"Experimental feature$which may only be used with nightly or snapshot version of compiler", srcPos)
111+
112+
/** Check that experimental compiler options are only set for snapshot or nightly compiler versions. */
113+
def checkExperimentalSettings(using Context): Unit =
114+
for setting <- ctx.settings.language.value
115+
if setting.startsWith("experimental.") && setting != "experimental.macros"
116+
do checkExperimentalFeature(s" $setting")
117+
100118
end Feature

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import java.nio.charset.StandardCharsets
1111
/** Loads `library.properties` from the jar. */
1212
object Properties extends PropertiesTrait {
1313
protected def propCategory: String = "compiler"
14-
protected def pickJarBasedOn: Class[Option[?]] = classOf[Option[?]]
14+
protected def pickJarBasedOn: Class[PropertiesTrait] = classOf[PropertiesTrait]
1515

1616
/** Scala manifest attributes.
1717
*/

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ class ScalaSettings extends Settings.SettingGroup with CommonScalaSettings {
215215
val YretainTrees: Setting[Boolean] = BooleanSetting("-Yretain-trees", "Retain trees for top-level classes, accessible from ClassSymbol#tree")
216216
val YshowTreeIds: Setting[Boolean] = BooleanSetting("-Yshow-tree-ids", "Uniquely tag all tree nodes in debugging output.")
217217
val YfromTastyIgnoreList: Setting[List[String]] = MultiStringSetting("-Yfrom-tasty-ignore-list", "file", "List of `tasty` files in jar files that will not be loaded when using -from-tasty")
218+
val YnoExperimental: Setting[Boolean] = BooleanSetting("-Yno-experimental", "Disable experimental language features")
218219

219220
val YprofileEnabled: Setting[Boolean] = BooleanSetting("-Yprofile-enabled", "Enable profiling.")
220221
val YprofileDestination: Setting[String] = StringSetting("-Yprofile-destination", "file", "Where to send profiling output - specify a file, default is to the console.", "")

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3077,18 +3077,24 @@ object Parsers {
30773077
/** Create an import node and handle source version imports */
30783078
def mkImport(outermost: Boolean = false): ImportConstr = (tree, selectors) =>
30793079
val imp = Import(tree, selectors)
3080-
if isLanguageImport(tree) then
3081-
in.languageImportContext = in.languageImportContext.importContext(imp, NoSymbol)
3082-
for
3083-
case ImportSelector(id @ Ident(imported), EmptyTree, _) <- selectors
3084-
if allSourceVersionNames.contains(imported)
3085-
do
3086-
if !outermost then
3087-
syntaxError(i"source version import is only allowed at the toplevel", id.span)
3088-
else if ctx.compilationUnit.sourceVersion.isDefined then
3089-
syntaxError(i"duplicate source version import", id.span)
3090-
else
3091-
ctx.compilationUnit.sourceVersion = Some(SourceVersion.valueOf(imported.toString))
3080+
languageImport(tree) match
3081+
case Some(prefix) =>
3082+
in.languageImportContext = in.languageImportContext.importContext(imp, NoSymbol)
3083+
if prefix == nme.experimental
3084+
&& selectors.exists(sel => Feature.experimental(sel.name) != Feature.scala2macros)
3085+
then
3086+
Feature.checkExperimentalFeature("s", imp.srcPos)
3087+
for
3088+
case ImportSelector(id @ Ident(imported), EmptyTree, _) <- selectors
3089+
if allSourceVersionNames.contains(imported)
3090+
do
3091+
if !outermost then
3092+
syntaxError(i"source version import is only allowed at the toplevel", id.span)
3093+
else if ctx.compilationUnit.sourceVersion.isDefined then
3094+
syntaxError(i"duplicate source version import", id.span)
3095+
else
3096+
ctx.compilationUnit.sourceVersion = Some(SourceVersion.valueOf(imported.toString))
3097+
case None =>
30923098
imp
30933099

30943100
/** ImportExpr ::= SimpleRef {‘.’ id} ‘.’ ImportSpec

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ class ImportInfo(symf: Context ?=> Symbol,
181181
assert(myUnimported != null)
182182
myUnimported
183183

184-
private val isLanguageImport: Boolean = untpd.isLanguageImport(qualifier)
184+
private val isLanguageImport: Boolean = untpd.languageImport(qualifier).isDefined
185185

186186
private var myUnimported: Symbol = _
187187

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class CompilationTests {
130130
compileFilesInDir("tests/neg-custom-args/allow-double-bindings", allowDoubleBindings),
131131
compileFilesInDir("tests/neg-custom-args/allow-deep-subtypes", allowDeepSubtypes),
132132
compileFilesInDir("tests/neg-custom-args/explicit-nulls", defaultOptions.and("-Yexplicit-nulls")),
133+
compileFilesInDir("tests/neg-custom-args/no-experimental", defaultOptions.and("-Yno-experimental")),
133134
compileDir("tests/neg-custom-args/impl-conv", defaultOptions.and("-Xfatal-warnings", "-feature")),
134135
compileFile("tests/neg-custom-args/implicit-conversions.scala", defaultOptions.and("-Xfatal-warnings", "-feature")),
135136
compileFile("tests/neg-custom-args/implicit-conversions-old.scala", defaultOptions.and("-Xfatal-warnings", "-feature")),
@@ -239,7 +240,7 @@ class CompilationTests {
239240
Properties.compilerInterface, Properties.scalaLibrary, Properties.scalaAsm,
240241
Properties.dottyInterfaces, Properties.jlineTerminal, Properties.jlineReader,
241242
).mkString(File.pathSeparator),
242-
Array("-Ycheck-reentrant", "-language:postfixOps", "-Xsemanticdb")
243+
Array("-Ycheck-reentrant", "-language:postfixOps", "-Xsemanticdb", "-Yno-experimental")
243244
)
244245

245246
val libraryDirs = List(Paths.get("library/src"), Paths.get("library/src-bootstrapped"))

compiler/test/dotty/tools/vulpix/ParallelTesting.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import dotc.report
2525
import dotc.interfaces.Diagnostic.ERROR
2626
import dotc.reporting.{Reporter, TestReporter}
2727
import dotc.reporting.Diagnostic
28+
import dotc.config.Config
2829
import dotc.util.DiffUtil
2930
import io.AbstractFile
3031
import dotty.tools.vulpix.TestConfiguration.defaultOptions
@@ -36,7 +37,6 @@ import dotty.tools.vulpix.TestConfiguration.defaultOptions
3637
* test suite itself runs with a high level of concurrency.
3738
*/
3839
trait ParallelTesting extends RunnerOrchestration { self =>
39-
4040
import ParallelTesting._
4141

4242
/** If the running environment supports an interactive terminal, each `Test`
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
class Test0 {
2+
import language.experimental.namedTypeArguments // error
3+
object Foo {
4+
inline def f[S, T](x: S): T = ???
5+
def g(x: Int) = f[T = Any](x)
6+
}
7+
}
8+
9+
class Test1 {
10+
import scala.language.experimental.erasedDefinitions // error
11+
import scala.compiletime.erasedValue
12+
type UnivEq[A]
13+
object UnivEq:
14+
erased def force[A]: UnivEq[A] = erasedValue
15+
extension [A](erased proof: UnivEq[A])
16+
inline def univEq(a: A, b: A): Boolean =
17+
a == b
18+
}
19+
20+
class Test2 {
21+
import _root_.scala.language.experimental.{genericNumberLiterals, namedTypeArguments => _} // error
22+
val x: BigInt = 13232202002020202020202
23+
val y: BigInt = -0xaabb12345ACF12345AC
24+
}
25+
26+
class Test6 {
27+
import scala.language.experimental // ok
28+
}
29+
30+
class Test7 {
31+
import scala.language.experimental
32+
import experimental.genericNumberLiterals // error: no aliases can be used to refer to a language import
33+
val x: BigInt = 13232202002020202020202 // error
34+
}

0 commit comments

Comments
 (0)