Skip to content

Fix #11774: only enable experimental features for snapshot and nightly #11852

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Mar 25, 2021
2 changes: 1 addition & 1 deletion community-build/community-projects/stdLib213
3 changes: 3 additions & 0 deletions community-build/src/scala/dotty/communitybuild/projects.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ lazy val compilerVersion: String =
val file = communitybuildDir.resolve("scala3-bootstrapped.version")
new String(Files.readAllBytes(file), UTF_8)

lazy val compilerSupportExperimental: Boolean =
compilerVersion.contains("SNAPSHOT") || compilerVersion.contains("NIGHTLY")

lazy val sbtPluginFilePath: String =
// Workaround for https://github.com/sbt/sbt/issues/4395
new File(sys.props("user.home") + "/.sbt/1.0/plugins").mkdirs()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class CommunityBuildTestB extends CommunityBuildTest:
@Test def disciplineSpecs2 = projects.disciplineSpecs2.run()
@Test def munit = projects.munit.run()
@Test def perspective = projects.perspective.run()
@Test def scodec = projects.scodec.run()
@Test def scodec = if (compilerSupportExperimental) projects.scodec.run()
@Test def scodecBits = projects.scodecBits.run()
@Test def simulacrumScalafixAnnotations = projects.simulacrumScalafixAnnotations.run()
end CommunityBuildTestB
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/Driver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class Driver {
val ictx = rootCtx.fresh
val summary = command.distill(args, ictx.settings)(ictx.settingsState)(using ictx)
ictx.setSettings(summary.sstate)
Feature.checkExperimentalFlags(using ictx)
MacroClassLoader.init(ictx)
Positioned.init(using ictx)

Expand Down
5 changes: 5 additions & 0 deletions compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,11 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>

def isLanguageImport(path: Tree): Boolean = languageImport(path).isDefined

def isExperimentalImport(path: Tree): Boolean =
languageImport(path) match
case Some(nme.experimental) => true
case _ => false

/** The underlying pattern ignoring any bindings */
def unbind(x: Tree): Tree = unsplice(x) match {
case Bind(_, y) => unbind(y)
Expand Down
33 changes: 31 additions & 2 deletions compiler/src/dotty/tools/dotc/config/Feature.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,19 @@ object Feature:
val symbolLiterals = deprecated("symbolLiterals")
val fewerBraces = experimental("fewerBraces")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@odersky FYI, putting fewerBraces under experimental means that it will only available for nightly build of compilers after this PR. Normal releases cannot use the feature.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's understood.

/** Is `feature` enabled by by a command-line setting? The enabling setting is
val experimentalWarningMessage = "Experimental features may only be used with nightly or snapshot version of compiler."
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should refine the message by saying that Scala 3 macros are not experimental.


/** Experimental features are only enabled for snapshot and nightly compiler versions
*/
def experimentalEnabled(using Context): Boolean =
Properties.experimental && !ctx.settings.YnoExperimental.value

def isExperimental(feature: TermName): Boolean =
feature != scala2macros && feature.match
case QualifiedName(nme.experimental, _) => true
case _ => false

/** Is `feature` enabled by by a command-line setting? The enabling setting is
*
* -language:<prefix>feature
*
Expand Down Expand Up @@ -56,9 +68,12 @@ object Feature:
* @param feature The name of the feature
* @param owner The prefix symbol (nested in `scala.language`) where the
* feature is defined.
*
* Note: Experimental features are only enabled for snapshot and nightly version of compiler.
*/
def enabled(feature: TermName)(using Context): Boolean =
enabledBySetting(feature) || enabledByImport(feature)
(experimentalEnabled || !isExperimental(feature))
&& (enabledBySetting(feature) || enabledByImport(feature))

/** Is auto-tupling enabled? */
def autoTuplingEnabled(using Context): Boolean = !enabled(nme.noAutoTupling)
Expand All @@ -71,6 +86,8 @@ object Feature:

def genericNumberLiteralsEnabled(using Context) = enabled(genericNumberLiterals)

def erasedEnabled(using Context) = enabled(Feature.erasedDefinitions)

def scala2ExperimentalMacroEnabled(using Context) = enabled(scala2macros)

def sourceVersionSetting(using Context): SourceVersion =
Expand All @@ -97,4 +114,16 @@ object Feature:
else
false

/** Check that experimental compiler options are only set for snapshot or nightly compiler versions. */
def checkExperimentalFlags(using Context): Unit =
if !experimentalEnabled then
val features = ctx.settings.language.value.filter { feature =>
feature.contains(nme.experimental.toString) && !feature.contains("macros")
}
if features.nonEmpty then
report.error(
experimentalWarningMessage +
"\nThe experimental language features are enabled via -language:" + features.mkString(",")
)

end Feature
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/config/Properties.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import java.nio.charset.StandardCharsets
/** Loads `library.properties` from the jar. */
object Properties extends PropertiesTrait {
protected def propCategory: String = "compiler"
protected def pickJarBasedOn: Class[Option[?]] = classOf[Option[?]]
protected def pickJarBasedOn: Class[PropertiesTrait] = classOf[PropertiesTrait]

/** Scala manifest attributes.
*/
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ class ScalaSettings extends Settings.SettingGroup with CommonScalaSettings {
val YretainTrees: Setting[Boolean] = BooleanSetting("-Yretain-trees", "Retain trees for top-level classes, accessible from ClassSymbol#tree")
val YshowTreeIds: Setting[Boolean] = BooleanSetting("-Yshow-tree-ids", "Uniquely tag all tree nodes in debugging output.")
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")
val YnoExperimental: Setting[Boolean] = BooleanSetting("-Yno-experimental", "Disable experimental language features")

val YprofileEnabled: Setting[Boolean] = BooleanSetting("-Yprofile-enabled", "Enable profiling.")
val YprofileDestination: Setting[String] = StringSetting("-Yprofile-destination", "file", "Where to send profiling output - specify a file, default is to the console.", "")
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/StdNames.scala
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,7 @@ object StdNames {
val longHash: N = "longHash"
val macroThis : N = "_this"
val macroContext : N = "c"
val macros: N = "macros"
val main: N = "main"
val manifest: N = "manifest"
val ManifestFactory: N = "ManifestFactory"
Expand Down
6 changes: 6 additions & 0 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import config.Feature
import config.Feature.{sourceVersion, migrateTo3}
import config.SourceVersion._
import config.SourceVersion
import config.Properties

object Parsers {

Expand Down Expand Up @@ -3079,6 +3080,11 @@ object Parsers {
val imp = Import(tree, selectors)
if isLanguageImport(tree) then
in.languageImportContext = in.languageImportContext.importContext(imp, NoSymbol)
if isExperimentalImport(tree)
&& !Feature.experimentalEnabled
&& selectors.exists(_.name != nme.macros)
then
report.error(Feature.experimentalWarningMessage, imp.srcPos)
for
case ImportSelector(id @ Ident(imported), EmptyTree, _) <- selectors
if allSourceVersionNames.contains(imported)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ class BootstrappedOnlyCompilationTests {
aggregateTests(
compileFilesInDir("tests/run-macros", defaultOptions.and("-Xcheck-macros")),
compileFilesInDir("tests/run-custom-args/Yretain-trees", defaultOptions and "-Yretain-trees"),
compileFilesInDir("tests/run-custom-args/run-macros-erased", defaultOptions.and("-language:experimental.erasedDefinitions").and("-Xcheck-macros")),
)
}.checkRuns()

Expand Down Expand Up @@ -199,6 +198,24 @@ class BootstrappedOnlyCompilationTests {
compileFilesInDir("tests/plugins/neg").checkExpectedErrors()
compileDir("tests/plugins/custom/analyzer", withCompilerOptions.and("-Yretain-trees")).checkCompile()
}

// tests for experimental featuress ------------------------------------------

@Test def experimental: Unit =
implicit val testGroup: TestGroup = TestGroup("experimental")
val enableExperimental = defaultOptions.without("-Yno-experimental")
val enableErased = enableExperimental.and("-language:experimental.erasedDefinitions")
compileFilesInDir("tests/neg-custom-args/no-experimental", defaultOptions.and("-Yno-experimental")).checkExpectedErrors()
if config.Properties.experimental then
compileFilesInDir("tests/run-custom-args/experimental", enableExperimental).checkRuns()
compileFilesInDir("tests/neg-custom-args/experimental", enableExperimental).checkExpectedErrors()
compileFilesInDir("tests/pos-custom-args/experimental", enableExperimental).checkCompile()
compileFilesInDir("tests/run-staging-experimental", withStagingOptions.without("-Yno-experimental")).checkRuns()
compileFilesInDir("tests/neg-custom-args/erased", enableErased).checkExpectedErrors()
compileFilesInDir("tests/pos-custom-args/erased", enableErased).checkCompile()
compileFilesInDir("tests/run-custom-args/run-macros-erased", enableErased.and("-Xcheck-macros")).checkRuns()
compileFilesInDir("tests/run-custom-args/erased", enableErased)

}

object BootstrappedOnlyCompilationTests extends ParallelTesting {
Expand Down
6 changes: 0 additions & 6 deletions compiler/test/dotty/tools/dotc/CompilationTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ class CompilationTests {
compileFilesInDir("tests/pos-special/isInstanceOf", allowDeepSubtypes.and("-Xfatal-warnings")),
compileFilesInDir("tests/new", defaultOptions),
compileFilesInDir("tests/pos-scala2", scala2CompatMode),
compileFilesInDir("tests/pos-custom-args/erased", defaultOptions.and("-language:experimental.erasedDefinitions")),
compileFilesInDir("tests/pos", defaultOptions.and("-Ysafe-init")),
compileFilesInDir("tests/pos-deep-subtype", allowDeepSubtypes),
compileDir("tests/pos-special/java-param-names", defaultOptions.withJavacOnlyOptions("-parameters")),
Expand Down Expand Up @@ -125,7 +124,6 @@ class CompilationTests {
compileFilesInDir("tests/neg-no-kind-polymorphism", defaultOptions and "-Yno-kind-polymorphism"),
compileFilesInDir("tests/neg-custom-args/deprecation", defaultOptions.and("-Xfatal-warnings", "-deprecation")),
compileFilesInDir("tests/neg-custom-args/fatal-warnings", defaultOptions.and("-Xfatal-warnings")),
compileFilesInDir("tests/neg-custom-args/erased", defaultOptions.and("-language:experimental.erasedDefinitions")),
compileFilesInDir("tests/neg-custom-args/allow-double-bindings", allowDoubleBindings),
compileFilesInDir("tests/neg-custom-args/allow-deep-subtypes", allowDeepSubtypes),
compileFilesInDir("tests/neg-custom-args/explicit-nulls", defaultOptions.and("-Yexplicit-nulls")),
Expand Down Expand Up @@ -164,9 +162,7 @@ class CompilationTests {
compileDir("tests/neg-custom-args/adhoc-extension", defaultOptions.and("-source", "future", "-feature", "-Xfatal-warnings")),
compileFile("tests/neg/i7575.scala", defaultOptions.withoutLanguageFeatures.and("-language:_")),
compileFile("tests/neg-custom-args/kind-projector.scala", defaultOptions.and("-Ykind-projector")),
compileFile("tests/neg-custom-args/typeclass-derivation2.scala", defaultOptions.and("-language:experimental.erasedDefinitions")),
compileFile("tests/neg-custom-args/i5498-postfixOps.scala", defaultOptions withoutLanguageFeature "postfixOps"),
compileFile("tests/neg-custom-args/deptypes.scala", defaultOptions.and("-language:experimental.dependent")),
compileFile("tests/neg-custom-args/matchable.scala", defaultOptions.and("-Xfatal-warnings", "-source", "future")),
compileFile("tests/neg-custom-args/i7314.scala", defaultOptions.and("-Xfatal-warnings", "-source", "future")),
compileFile("tests/neg-custom-args/feature-shadowing.scala", defaultOptions.and("-Xfatal-warnings", "-feature")),
Expand All @@ -188,7 +184,6 @@ class CompilationTests {
compileFile("tests/run-custom-args/fors.scala", defaultOptions.and("-source", "future")),
compileFile("tests/run-custom-args/no-useless-forwarders.scala", defaultOptions and "-Xmixin-force-forwarders:false"),
compileFile("tests/run-custom-args/defaults-serizaliable-no-forwarders.scala", defaultOptions and "-Xmixin-force-forwarders:false"),
compileFilesInDir("tests/run-custom-args/erased", defaultOptions.and("-language:experimental.erasedDefinitions")),
compileFilesInDir("tests/run-deep-subtype", allowDeepSubtypes),
compileFilesInDir("tests/run", defaultOptions.and("-Ysafe-init"))
).checkRuns()
Expand Down Expand Up @@ -247,7 +242,6 @@ class CompilationTests {
val lib =
compileList("lib", librarySources,
defaultOptions.and("-Ycheck-reentrant",
"-language:experimental.erasedDefinitions", // support declaration of scala.compiletime.erasedValue
// "-source", "future", // TODO: re-enable once we allow : @unchecked in pattern definitions. Right now, lots of narrowing pattern definitions fail.
))(libGroup)

Expand Down
1 change: 1 addition & 0 deletions compiler/test/dotty/tools/vulpix/TestConfiguration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ object TestConfiguration {
val noCheckOptions = Array(
"-pagewidth", "120",
"-color:never",
"-Yno-experimental",
"-Xtarget", defaultTarget
)

Expand Down
6 changes: 6 additions & 0 deletions project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ object Build {

libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % Test,

// TODO: enable after bootstrap
// scalacOptions += "-Yno-experimental",

// If someone puts a source file at the root (e.g., for manual testing),
// don't pick it up as part of any project.
sourcesInBase := false,
Expand Down Expand Up @@ -445,6 +448,9 @@ object Build {
// Add git-hash used to package the distribution to the manifest to know it in runtime and report it in REPL
packageOptions += ManifestAttributes(("Git-Hash", VersionUtil.gitHash)),

// TODO: enable after bootstrap
// scalacOptions += "-Yno-experimental",

javaOptions ++= {
val managedSrcDir = {
// Populate the directory
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import language.experimental.erasedDefinitions

import scala.collection.mutable
import scala.annotation.tailrec

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,3 @@ object BigFloat extends App {
'{BigInt(${Expr(x.toString)})}
}
}

Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import language.experimental.dependent

type Vec[T] = (n: Int) =>> Array[T] // error: not yet implemented

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,3 @@ erased trait D

val x = new A{} // ok, x is erased
val y = new C with D{} // error


File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,3 @@ object d:
import language.experimental.genericNumberLiterals // ok
import scala.language.noAutoTupling // ok
import _root_.scala.language.strictEquality // ok

59 changes: 59 additions & 0 deletions tests/neg-custom-args/no-experimental/experimental.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
class Test0 {
import language.experimental.namedTypeArguments // error
object Foo {
inline def f[S, T](x: S): T = ???
def g(x: Int) = f[T = Any](x) // error
}
}

class Test1 {
import language.experimental.erasedDefinitions // error
import scala.compiletime.erasedValue
type UnivEq[A]
object UnivEq:
erased def force[A]: UnivEq[A] = erasedValue // error // error // error
extension [A](erased proof: UnivEq[A]) // error
inline def univEq(a: A, b: A): Boolean =
a == b
}

class Test2 {
import scala.language.experimental.genericNumberLiterals // error
val x: BigInt = 13232202002020202020202 // error
val y: BigInt = -0xaabb12345ACF12345AC // error
}

class Test3 {
import scala.language.experimental.namedTypeArguments // error
object Foo {
inline def f[S, T](x: S): T = ???
def g(x: Int) = f[T = Any](x) // error
}
}

class Test4 {
import scala.language.experimental.erasedDefinitions // error
import scala.compiletime.erasedValue
type UnivEq[A]
object UnivEq:
erased def force[A]: UnivEq[A] = erasedValue // error // error // error
extension [A](erased proof: UnivEq[A]) // error
inline def univEq(a: A, b: A): Boolean =
a == b
}

class Test5 {
import scala.language.experimental.genericNumberLiterals // error
val x: BigInt = 13232202002020202020202 // error
val y: BigInt = -0xaabb12345ACF12345AC // error
}

class Test6 {
import scala.language.experimental
}

class Test7 {
import scala.language.experimental
import experimental.genericNumberLiterals // error: no aliases can be used to refer to a language import
val x: BigInt = 13232202002020202020202 // error
}
19 changes: 0 additions & 19 deletions tests/neg-with-compiler/GenericNumLits/EvenFromDigitsImpl_1.scala

This file was deleted.

24 changes: 0 additions & 24 deletions tests/neg-with-compiler/GenericNumLits/Even_1.scala

This file was deleted.

6 changes: 0 additions & 6 deletions tests/neg-with-compiler/GenericNumLits/Test_2.scala

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
import language.experimental.erasedDefinitions
erased class A

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading