Skip to content
Merged
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.
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