Skip to content

Commit 2df2c2d

Browse files
committed
Make preview private[scala], enable all preview features globally using flag only
1 parent b712369 commit 2df2c2d

File tree

21 files changed

+56
-106
lines changed

21 files changed

+56
-106
lines changed

Diff for: compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ trait TreeInfo[T <: Untyped] { self: Trees.Instance[T] =>
297297
case TypeDefs(_) => true
298298
case _ => false
299299

300-
private val languageSubCategories = Set(nme.experimental, nme.preview, nme.deprecated)
300+
private val languageSubCategories = Set(nme.experimental, nme.deprecated)
301301

302302
/** If `path` looks like a language import, `Some(name)` where name
303303
* is `experimental` if that sub-module is imported, and the empty

Diff for: compiler/src/dotty/tools/dotc/config/Feature.scala

+8-21
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ object Feature:
1818

1919
def experimental(str: PreName): TermName =
2020
QualifiedName(nme.experimental, str.toTermName)
21-
22-
def preview(str: PreName): TermName =
23-
QualifiedName(nme.preview, str.toTermName)
2421

2522
private def deprecated(str: PreName): TermName =
2623
QualifiedName(nme.deprecated, str.toTermName)
@@ -48,10 +45,6 @@ object Feature:
4845
defn.languageExperimentalFeatures
4946
.map(sym => experimental(sym.name))
5047
.filterNot(_ == captureChecking) // TODO is this correct?
51-
52-
def previewAutoEnableFeatures(using Context): List[TermName] =
53-
defn.languagePreviewFeatures
54-
.map(sym => preview(sym.name))
5548

5649
val values = List(
5750
(nme.help, "Display all available features"),
@@ -232,7 +225,7 @@ object Feature:
232225

233226
def isExperimentalEnabledByImport(using Context): Boolean =
234227
experimentalAutoEnableFeatures.exists(enabledByImport)
235-
228+
236229
/** Handle language import `import language.<prefix>.<imported>` if it is one
237230
* of the global imports `pureFunctions` or `captureChecking`. In this case
238231
* make the compilation unit's and current run's fields accordingly.
@@ -250,15 +243,14 @@ object Feature:
250243
true
251244
else
252245
false
253-
254-
def isPreviewEnabled(using Context): Boolean =
255-
ctx.settings.preview.value ||
256-
previewAutoEnableFeatures.exists(enabled)
257-
246+
247+
def isPreviewEnabled(using Context): Boolean =
248+
ctx.settings.preview.value
249+
258250
def checkPreviewFeature(which: String, srcPos: SrcPos, note: => String = "")(using Context) =
259251
if !isPreviewEnabled then
260252
report.error(previewUseSite(which) + note, srcPos)
261-
253+
262254
def checkPreviewDef(sym: Symbol, srcPos: SrcPos)(using Context) = if !isPreviewEnabled then
263255
val previewSym =
264256
if sym.hasAnnotation(defn.PreviewAnnot) then sym
@@ -273,12 +265,7 @@ object Feature:
273265
then i"$previewSym is marked @preview$msg"
274266
else i"$sym inherits @preview$msg"
275267
report.error(markedPreview + "\n\n" + previewUseSite("definition"), srcPos)
276-
268+
277269
private def previewUseSite(which: String): String =
278-
s"""Preview $which may only be used under preview mode:
279-
| 1. in a definition marked as @preview, or
280-
| 2. a preview feature is imported at the package level, or
281-
| 3. compiling with the -preview compiler flag.
282-
|""".stripMargin
270+
s"Preview $which may only be used when compiling with the `-preview` compiler flag"
283271
end Feature
284-

Diff for: compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ trait CommonScalaSettings:
117117
val language: Setting[List[ChoiceWithHelp[String]]] = MultiChoiceHelpSetting(RootSetting, "language", "feature", "Enable one or more language features.", choices = ScalaSettingsProperties.supportedLanguageFeatures, legacyChoices = ScalaSettingsProperties.legacyLanguageFeatures, default = Nil, aliases = List("--language"))
118118
val experimental: Setting[Boolean] = BooleanSetting(RootSetting, "experimental", "Annotate all top-level definitions with @experimental. This enables the use of experimental features anywhere in the project.")
119119
val preview: Setting[Boolean] = BooleanSetting(RootSetting, "preview", "Enable the use of preview features anywhere in the project.")
120-
120+
121121
/* Coverage settings */
122122
val coverageOutputDir = PathSetting(RootSetting, "coverage-out", "Destination for coverage classfiles and instrumentation data.", "", aliases = List("--coverage-out"))
123123
val coverageExcludeClasslikes: Setting[List[String]] = MultiStringSetting(RootSetting, "coverage-exclude-classlikes", "packages, classes and modules", "List of regexes for packages, classes and modules to exclude from coverage.", aliases = List("--coverage-exclude-classlikes"))

Diff for: compiler/src/dotty/tools/dotc/core/Definitions.scala

+1-6
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,6 @@ class Definitions {
808808
@tu lazy val LanguageModule: Symbol = requiredModule("scala.language")
809809
@tu lazy val LanguageModuleClass: Symbol = LanguageModule.moduleClass.asClass
810810
@tu lazy val LanguageExperimentalModule: Symbol = requiredModule("scala.language.experimental")
811-
@tu lazy val LanguagePreviewModule: Symbol = requiredModule("scala.language.preview")
812811
@tu lazy val LanguageDeprecatedModule: Symbol = requiredModule("scala.language.deprecated")
813812
@tu lazy val NonLocalReturnControlClass: ClassSymbol = requiredClass("scala.runtime.NonLocalReturnControl")
814813
@tu lazy val SelectableClass: ClassSymbol = requiredClass("scala.Selectable")
@@ -1053,7 +1052,7 @@ class Definitions {
10531052
@tu lazy val CompileTimeOnlyAnnot: ClassSymbol = requiredClass("scala.annotation.compileTimeOnly")
10541053
@tu lazy val SwitchAnnot: ClassSymbol = requiredClass("scala.annotation.switch")
10551054
@tu lazy val ExperimentalAnnot: ClassSymbol = requiredClass("scala.annotation.experimental")
1056-
@tu lazy val PreviewAnnot: ClassSymbol = requiredClass("scala.annotation.preview")
1055+
@tu lazy val PreviewAnnot: ClassSymbol = requiredClass("scala.annotation.internal.preview")
10571056
@tu lazy val ThrowsAnnot: ClassSymbol = requiredClass("scala.throws")
10581057
@tu lazy val TransientAnnot: ClassSymbol = requiredClass("scala.transient")
10591058
@tu lazy val UncheckedAnnot: ClassSymbol = requiredClass("scala.unchecked")
@@ -2065,10 +2064,6 @@ class Definitions {
20652064
@tu lazy val languageExperimentalFeatures: List[TermSymbol] =
20662065
LanguageExperimentalModule.moduleClass.info.decls.toList.filter(_.isAllOf(Lazy | Module)).map(_.asTerm)
20672066

2068-
/** Preview language features defined in `scala.runtime.stdLibPatches.language.preview` */
2069-
@tu lazy val languagePreviewFeatures: List[TermSymbol] =
2070-
LanguagePreviewModule.moduleClass.info.decls.toList.filter(_.isAllOf(Lazy | Module)).map(_.asTerm)
2071-
20722067
// ----- primitive value class machinery ------------------------------------------
20732068

20742069
class PerRun[T](generate: Context ?=> T) {

Diff for: compiler/src/dotty/tools/dotc/core/StdNames.scala

-1
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,6 @@ object StdNames {
579579
val parts: N = "parts"
580580
val postfixOps: N = "postfixOps"
581581
val prefix : N = "prefix"
582-
val preview: N = "preview"
583582
val processEscapes: N = "processEscapes"
584583
val productArity: N = "productArity"
585584
val productElement: N = "productElement"

Diff for: compiler/src/dotty/tools/dotc/core/SymUtils.scala

+5-5
Original file line numberDiff line numberDiff line change
@@ -370,13 +370,13 @@ class SymUtils:
370370
def isInExperimentalScope(using Context): Boolean = isInFeatureScope(defn.ExperimentalAnnot, _.isExperimental, _.isInExperimentalScope)
371371

372372
/** Is symbol declared or inherits @preview? */
373-
def isPreview(using Context): Boolean = isFeatureAnnotated(defn.PreviewAnnot)
373+
def isPreview(using Context): Boolean = isFeatureAnnotated(defn.PreviewAnnot)
374374
def isInPreviewScope(using Context): Boolean = isInFeatureScope(defn.PreviewAnnot, _.isPreview, _.isInPreviewScope)
375-
376-
private inline def isFeatureAnnotated(checkAnnotaton: ClassSymbol)(using Context): Boolean =
375+
376+
private inline def isFeatureAnnotated(checkAnnotaton: ClassSymbol)(using Context): Boolean =
377377
self.hasAnnotation(checkAnnotaton)
378378
|| (self.maybeOwner.isClass && self.owner.hasAnnotation(checkAnnotaton))
379-
379+
380380
private inline def isInFeatureScope(checkAnnotation: ClassSymbol, checkSymbol: Symbol => Boolean, checkOwner: Symbol => Boolean)(using Context): Boolean =
381381
def isDefaultArgumentOfCheckedMethod =
382382
self.name.is(DefaultGetterName)
@@ -390,7 +390,7 @@ class SymUtils:
390390
self.hasAnnotation(checkAnnotation)
391391
|| isDefaultArgumentOfCheckedMethod
392392
|| (!self.is(Package) && checkOwner(self.owner))
393-
393+
394394
/** The declared self type of this class, as seen from `site`, stripping
395395
* all refinements for opaque types.
396396
*/

Diff for: compiler/src/dotty/tools/dotc/typer/Checking.scala

-2
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,6 @@ trait Checking {
10561056
case Some(prefix) =>
10571057
val required =
10581058
if prefix == nme.experimental then defn.LanguageExperimentalModule
1059-
else if prefix == nme.preview then defn.LanguagePreviewModule
10601059
else if prefix == nme.deprecated then defn.LanguageDeprecatedModule
10611060
else defn.LanguageModule
10621061
if path.symbol != required then
@@ -1065,7 +1064,6 @@ trait Checking {
10651064
val foundClasses = path.tpe.classSymbols
10661065
if foundClasses.contains(defn.LanguageModule.moduleClass)
10671066
|| foundClasses.contains(defn.LanguageExperimentalModule.moduleClass)
1068-
|| foundClasses.contains(defn.LanguagePreviewModule.moduleClass)
10691067
then
10701068
report.error(em"no aliases can be used to refer to a language import", path.srcPos)
10711069

Diff for: compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class CrossVersionChecks extends MiniPhase:
3636
if sym.exists && !sym.isInExperimentalScope then
3737
for annot <- sym.annotations if annot.symbol.isExperimental do
3838
Feature.checkExperimentalDef(annot.symbol, annot.tree)
39-
39+
4040
/** If @migration is present (indicating that the symbol has changed semantics between versions),
4141
* emit a warning.
4242
*/
@@ -164,7 +164,7 @@ object CrossVersionChecks:
164164
private[CrossVersionChecks] def checkExperimentalRef(sym: Symbol, pos: SrcPos)(using Context): Unit =
165165
if sym.isExperimental && !ctx.owner.isInExperimentalScope then
166166
Feature.checkExperimentalDef(sym, pos)
167-
167+
168168
/** Check that a reference to a preview definition with symbol `sym` is only
169169
* used in a preview mode.
170170
*/

Diff for: compiler/src/dotty/tools/dotc/typer/RefChecks.scala

+4-4
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ object RefChecks {
306306
* that passes its value on to O.
307307
* 1.13. If O is non-experimental, M must be non-experimental.
308308
* 1.14. If O has @publicInBinary, M must have @publicInBinary.
309-
* 1.15. If O is non-preview, M must be non-preview
309+
* 1.15. If O is non-preview, M must be non-preview
310310
* 2. Check that only abstract classes have deferred members
311311
* 3. Check that concrete classes do not have deferred definitions
312312
* that are not implemented in a subclass.
@@ -644,10 +644,10 @@ object RefChecks {
644644
MigrationVersion.OverrideValParameter)
645645
else if !other.isExperimental && member.hasAnnotation(defn.ExperimentalAnnot) then // (1.13)
646646
overrideError("may not override non-experimental member")
647-
else if !member.hasAnnotation(defn.PublicInBinaryAnnot) && other.hasAnnotation(defn.PublicInBinaryAnnot) then // (1.14)
647+
else if !member.hasAnnotation(defn.PublicInBinaryAnnot) && other.hasAnnotation(defn.PublicInBinaryAnnot) then // (1.14)
648648
overrideError("also needs to be declared with @publicInBinary")
649-
else if !other.isPreview && member.hasAnnotation(defn.PreviewAnnot) then // (1.15)
650-
overrideError("may not override non-preview member")
649+
else if !other.isPreview && member.hasAnnotation(defn.PreviewAnnot) then // (1.15)
650+
overrideError("may not override non-preview member")
651651
else if other.hasAnnotation(defn.DeprecatedOverridingAnnot) then
652652
overrideDeprecation("", member, other, "removed or renamed")
653653
end checkOverride

Diff for: docs/_docs/reference/other-new-features/preview-defs.md

+13-17
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@ title: "Preview Definitions"
44
nightlyOf: https://docs.scala-lang.org/scala3/reference/other-new-features/preview-defs.html
55
---
66

7-
The [`@preview`](https://scala-lang.org/api/3.x/scala/annotation/preview.html) annotation allows the definition of an API that is not guaranteed backward binary, but might become stable in next minor version of the compiler.
7+
New Scala language features or standard library APIs are initially introduced as experimental, but once they become fully implemented and acceppted by the [SIP](https://docs.scala-lang.org/sips/) these can become a preview features.
8+
Preview language features and APIs are guaranteed to be standarized in some next Scala minor release, but allow compiler team to introduce small, possibly binary incompatible, changes based on the community feedback.
9+
These can be used by early adopters who can accept possibility of binary compatibility breakage. As an example these can be used for project internal tools and applications, but are discouraged to be used by libraries.
810

9-
New Scala language features or standard library APIs initially introduced as experimental can become a preview features when they have become fully implemented and acceppted by the [SIP](https://docs.scala-lang.org/sips/) before they're accepted as standard features.
10-
Such definitions can be used by early adopters that can accept possibility of binary compatibility breakage, for example these can be used for project internal tools and applications, but are discouraged to be used by libraries.
11-
12-
The [`@preview`](https://scala-lang.org/api/3.x/scala/annotation/preview.html) definitions follows similar rules as the [`@experimental`](https://scala-lang.org/api/3.x/scala/annotation/experimental.html) - to enable access to preview feature or API in given compilation unit Scala compiler requires either:
13-
14-
- explicit `-preview` flag passed to the compiler,
15-
- top level import for explicit `scala.language.preview.<feature>`,
16-
- annotating defintion that referes to preview feature with `@preview`
11+
Users can enable access to preview features and definitions by compiling with `-preview` flag. The flag would enable all preview features and definitions. There is no way for enabling only a subset of preview features.
1712

1813
The biggest difference of preview features when compared with experimental features is their non-viral behaviour.
19-
Any defintion that was compiles in the preview scope (using `-preview` flag or `scala.language.preview` top-level import) is not annotated as `@preview` defintion itself. It behaviour allows to use preview features transitively in other compilation units without enabled preview mode.
14+
Any defintion compiled in the preview mode (using `-preview` flag) is not marked as preview defintion itself.
15+
This behaviour allows to use preview features transitively in other compilation units without explicitlly enabled preview mode, as long as it does not directly reference APIs or features marked as preview.
16+
17+
The [`@preview`](https://scala-lang.org/api/3.x/scala/annotation/internal/preview.html) annotations are used to mark Scala 3 standard library APIs currently available under enabled preview mode.
18+
The definitions follows similar rules as the [`@experimental`](https://scala-lang.org/api/3.x/scala/annotation/experimental.html) when it comes to accessing, subtyping, overriding or overloading definitions marked with this annotation - all of these can only be performed in compilation unit that enables preview mode.
2019

2120
```scala
2221
//> using options -preview
23-
import scala.annotation.preview
22+
package scala.stdlib
23+
import scala.annotation.internal.preview
2424

2525
@preview def previewFeature: Unit = ()
2626

@@ -29,10 +29,6 @@ def usePreviewFeature = previewFeature
2929
```
3030

3131
```scala
32-
def usePreviewFeatureTransitively = usePreviewFeature
33-
def usePreviewFeatureDirectly = previewFeature // error - refering to preview definition outside preview scope
34-
def useWrappedPreviewFeature = wrappedPreviewFeature // error - refering to preview definition outside preview scope
35-
36-
@scala.annotation.preview
37-
def wrappedPreviewFeature = previewFeature
32+
def usePreviewFeatureTransitively = scala.stdlib.usePreviewFeature
33+
def usePreviewFeatureDirectly = scala.stdlib.previewFeature // error - refering to preview definition outside preview scope
3834
```

Diff for: docs/sidebar.yml

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ subsection:
8585
- page: reference/other-new-features/safe-initialization.md
8686
- page: reference/other-new-features/type-test.md
8787
- page: reference/other-new-features/experimental-defs.md
88+
- page: reference/other-new-features/preview-defs.md
8889
- page: reference/other-new-features/binary-literals.md
8990
- title: Other Changed Features
9091
directory: changed-features
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package scala.annotation
2+
package internal
3+
24

35
/** An annotation that can be used to mark a definition as preview.
46
*
57
* @see [[https://dotty.epfl.ch/docs/reference/other-new-features/preview-defs]]
68
* @syntax markdown
79
*/
8-
final class preview(message: String) extends StaticAnnotation:
10+
private[scala] final class preview(message: String) extends StaticAnnotation:
911
def this() = this("")

Diff for: library/src/scala/runtime/stdLibPatches/language.scala

-15
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,6 @@ import scala.annotation.compileTimeOnly
55
/** Scala 3 additions and replacements to the `scala.language` object.
66
*/
77
object language:
8-
9-
/** The preview object contains previously experimental features that are fully implemented
10-
* but are awaiting to be stablized as a standard features.
11-
*
12-
* Preview features '''may undergo binary compatibility changes''' in future releases,
13-
* but their API is unlikely to change. These can be used by early adopters that do don't care
14-
* about the binary breakage, i.e. applications, but not libraries.
15-
*
16-
* Programmers are encouraged to try out preview features and
17-
* [[https://github.com/scala/scala3/issues report any bugs or API inconsistencies]]
18-
* they encounter so they can be improved in future releases.
19-
*
20-
* @group preview
21-
*/
22-
object preview
238

249
/** The experimental object contains features that have been recently added but have not
2510
* been thoroughly tested in production yet.

Diff for: project/MiMaFilters.scala

+1-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ object MiMaFilters {
1313
ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.stdLibPatches.language#experimental.quotedPatternsWithPolymorphicFunctions"),
1414
ProblemFilters.exclude[MissingClassProblem]("scala.runtime.stdLibPatches.language$experimental$quotedPatternsWithPolymorphicFunctions$"),
1515
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.quoted.runtime.Patterns.higherOrderHoleWithTypes"),
16-
ProblemFilters.exclude[MissingClassProblem]("scala.annotation.preview"),
17-
ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.stdLibPatches.language.preview"),
18-
ProblemFilters.exclude[MissingClassProblem]("scala.runtime.stdLibPatches.language$preview$"),
16+
ProblemFilters.exclude[MissingClassProblem]("scala.annotation.internal.preview"),
1917
),
2018

2119
// Additions since last LTS

Diff for: tests/neg/preview-message.check

+3-12
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,16 @@
33
| ^^
44
| method f1 is marked @preview
55
|
6-
| Preview definition may only be used under preview mode:
7-
| 1. in a definition marked as @preview, or
8-
| 2. a preview feature is imported at the package level, or
9-
| 3. compiling with the -preview compiler flag.
6+
| Preview definition may only be used when compiling with the `-preview` compiler flag
107
-- Error: tests/neg/preview-message.scala:16:2 -------------------------------------------------------------------------
118
16 | f2() // error
129
| ^^
1310
| method f2 is marked @preview
1411
|
15-
| Preview definition may only be used under preview mode:
16-
| 1. in a definition marked as @preview, or
17-
| 2. a preview feature is imported at the package level, or
18-
| 3. compiling with the -preview compiler flag.
12+
| Preview definition may only be used when compiling with the `-preview` compiler flag
1913
-- Error: tests/neg/preview-message.scala:17:2 -------------------------------------------------------------------------
2014
17 | f3() // error
2115
| ^^
2216
| method f3 is marked @preview: not yet stable
2317
|
24-
| Preview definition may only be used under preview mode:
25-
| 1. in a definition marked as @preview, or
26-
| 2. a preview feature is imported at the package level, or
27-
| 3. compiling with the -preview compiler flag.
18+
| Preview definition may only be used when compiling with the `-preview` compiler flag

Diff for: tests/neg/preview-message.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
package scala // @preview in private[scala]
12

2-
3-
import scala.annotation.preview
3+
import scala.annotation.internal.preview
44

55
@preview
66
def f1() = ???

Diff for: tests/neg/preview-non-viral/defs_1.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//> using options -preview
2-
import scala.annotation.preview
2+
package scala // @preview in private[scala]
3+
import scala.annotation.internal.preview
34

45
@preview def previewFeature = 42
56

Diff for: tests/neg/preview-non-viral/usage_2.scala

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,2 @@
1-
def usePreviewFeatureTransitively = usePreviewFeature
2-
def usePreviewFeatureDirectly = previewFeature // error
3-
4-
@scala.annotation.preview
5-
def wrappedPreviewFeature = previewFeature
1+
def usePreviewFeatureTransitively = scala.usePreviewFeature
2+
def usePreviewFeatureDirectly = scala.previewFeature // error

0 commit comments

Comments
 (0)