Skip to content

Commit 0dac4c3

Browse files
authored
Standardize how previously experimental features are handled (#21686)
If a feature was previously experimental and is now standard, we change any tests for that feature to be only dependent on the source version where the feature was standardized. Language imports in old source versions will no longer enable the feature. (And these language imports also come with a deprecation message). If a feature was previously experimental and is now dropped, the feature becomes unavailable also in old versions. The motivation to do it this way is to insist that experimental features are ephemeral. We should not be able to rely on an experimental feature forever in an old version. This commit implements this policy for fewerBraces and clauseInterleaving. Two implemented extensions (relaxedExtensionImports, betterMatchTypeExtractors) already implemented it before.
2 parents 417d542 + a03a2fc commit 0dac4c3

File tree

6 files changed

+18
-28
lines changed

6 files changed

+18
-28
lines changed

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

-10
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ object Feature:
2828
val dependent = experimental("dependent")
2929
val erasedDefinitions = experimental("erasedDefinitions")
3030
val symbolLiterals = deprecated("symbolLiterals")
31-
val fewerBraces = experimental("fewerBraces")
3231
val saferExceptions = experimental("saferExceptions")
33-
val clauseInterleaving = experimental("clauseInterleaving")
3432
val pureFunctions = experimental("pureFunctions")
3533
val captureChecking = experimental("captureChecking")
3634
val into = experimental("into")
@@ -60,9 +58,7 @@ object Feature:
6058
(dependent, "Allow dependent method types"),
6159
(erasedDefinitions, "Allow erased definitions"),
6260
(symbolLiterals, "Allow symbol literals"),
63-
(fewerBraces, "Enable support for using indentation for arguments"),
6461
(saferExceptions, "Enable safer exceptions"),
65-
(clauseInterleaving, "Enable clause interleaving"),
6662
(pureFunctions, "Enable pure functions for capture checking"),
6763
(captureChecking, "Enable experimental capture checking"),
6864
(into, "Allow into modifier on parameter types"),
@@ -124,9 +120,6 @@ object Feature:
124120

125121
def namedTypeArgsEnabled(using Context) = enabled(namedTypeArguments)
126122

127-
def clauseInterleavingEnabled(using Context) =
128-
sourceVersion.isAtLeast(`3.6`) || enabled(clauseInterleaving)
129-
130123
def betterForsEnabled(using Context) = enabled(betterFors)
131124

132125
def genericNumberLiteralsEnabled(using Context) = enabled(genericNumberLiterals)
@@ -169,9 +162,6 @@ object Feature:
169162
def migrateTo3(using Context): Boolean =
170163
sourceVersion == `3.0-migration`
171164

172-
def fewerBracesEnabled(using Context) =
173-
sourceVersion.isAtLeast(`3.3`) || enabled(fewerBraces)
174-
175165
/** If current source migrates to `version`, issue given warning message
176166
* and return `true`, otherwise return `false`.
177167
*/

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

+5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ enum SourceVersion:
3131

3232
def isAtMost(v: SourceVersion) = stable.ordinal <= v.ordinal
3333

34+
def enablesFewerBraces = isAtLeast(`3.3`)
35+
def enablesClauseInterleaving = isAtLeast(`3.6`)
36+
def enablesNewGivens = isAtLeast(`3.6`)
37+
def enablesNamedTuples = isAtLeast(`3.7`)
38+
3439
object SourceVersion extends Property.Key[SourceVersion]:
3540
def defaultSourceVersion = `3.7`
3641

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

+10-10
Original file line numberDiff line numberDiff line change
@@ -885,7 +885,7 @@ object Parsers {
885885
}
886886
})
887887
canRewrite &= (in.isAfterLineEnd || statCtdTokens.contains(in.token)) // test (5)
888-
if canRewrite && (!underColonSyntax || Feature.fewerBracesEnabled) then
888+
if canRewrite && (!underColonSyntax || sourceVersion.enablesFewerBraces) then
889889
val openingPatchStr =
890890
if !colonRequired then ""
891891
else if testChar(startOpening - 1, Chars.isOperatorPart(_)) then " :"
@@ -1011,7 +1011,7 @@ object Parsers {
10111011
skipParams()
10121012
lookahead.isColon
10131013
&& {
1014-
!sourceVersion.isAtLeast(`3.6`)
1014+
!sourceVersion.enablesNewGivens
10151015
|| { // in the new given syntax, a `:` at EOL after an identifier represents a single identifier given
10161016
// Example:
10171017
// given C:
@@ -1165,7 +1165,7 @@ object Parsers {
11651165
* body
11661166
*/
11671167
def isColonLambda =
1168-
Feature.fewerBracesEnabled && in.token == COLONfollow && followingIsLambdaAfterColon()
1168+
sourceVersion.enablesFewerBraces && in.token == COLONfollow && followingIsLambdaAfterColon()
11691169

11701170
/** operand { infixop operand | MatchClause } [postfixop],
11711171
*
@@ -1870,7 +1870,7 @@ object Parsers {
18701870
infixOps(t, canStartInfixTypeTokens, operand, Location.ElseWhere, ParseKind.Type,
18711871
isOperator = !followingIsVararg()
18721872
&& !isPureArrow
1873-
&& !(isIdent(nme.as) && sourceVersion.isAtLeast(`3.6`) && inContextBound)
1873+
&& !(isIdent(nme.as) && sourceVersion.enablesNewGivens && inContextBound)
18741874
&& nextCanFollowOperator(canStartInfixTypeTokens))
18751875

18761876
/** RefinedType ::= WithType {[nl] Refinement} [`^` CaptureSet]
@@ -2263,7 +2263,7 @@ object Parsers {
22632263
def contextBound(pname: TypeName): Tree =
22642264
val t = toplevelTyp(inContextBound = true)
22652265
val ownName =
2266-
if isIdent(nme.as) && sourceVersion.isAtLeast(`3.6`) then
2266+
if isIdent(nme.as) && sourceVersion.enablesNewGivens then
22672267
in.nextToken()
22682268
ident()
22692269
else EmptyTermName
@@ -2276,7 +2276,7 @@ object Parsers {
22762276
def contextBounds(pname: TypeName): List[Tree] =
22772277
if in.isColon then
22782278
in.nextToken()
2279-
if in.token == LBRACE && sourceVersion.isAtLeast(`3.6`)
2279+
if in.token == LBRACE && sourceVersion.enablesNewGivens
22802280
then inBraces(commaSeparated(() => contextBound(pname)))
22812281
else
22822282
val bound = contextBound(pname)
@@ -3500,7 +3500,7 @@ object Parsers {
35003500
val hkparams = typeParamClauseOpt(ParamOwner.Hk)
35013501
val bounds =
35023502
if paramOwner.acceptsCtxBounds then typeAndCtxBounds(name)
3503-
else if sourceVersion.isAtLeast(`3.6`) && paramOwner == ParamOwner.Type then typeAndCtxBounds(name)
3503+
else if sourceVersion.enablesNewGivens && paramOwner == ParamOwner.Type then typeAndCtxBounds(name)
35043504
else typeBounds()
35053505
TypeDef(name, lambdaAbstract(hkparams, bounds)).withMods(mods)
35063506
}
@@ -3969,7 +3969,7 @@ object Parsers {
39693969
val ident = termIdent()
39703970
var name = ident.name.asTermName
39713971
val paramss =
3972-
if Feature.clauseInterleavingEnabled(using in.languageImportContext) then
3972+
if sourceVersion.enablesClauseInterleaving then
39733973
typeOrTermParamClauses(ParamOwner.Def, numLeadParams)
39743974
else
39753975
val tparams = typeParamClauseOpt(ParamOwner.Def)
@@ -4069,7 +4069,7 @@ object Parsers {
40694069
case SEMI | NEWLINE | NEWLINES | COMMA | RBRACE | OUTDENT | EOF =>
40704070
makeTypeDef(typeAndCtxBounds(tname))
40714071
case _ if (staged & StageKind.QuotedPattern) != 0
4072-
|| sourceVersion.isAtLeast(`3.6`) && in.isColon =>
4072+
|| sourceVersion.enablesNewGivens && in.isColon =>
40734073
makeTypeDef(typeAndCtxBounds(tname))
40744074
case _ =>
40754075
syntaxErrorOrIncomplete(ExpectedTypeBoundOrEquals(in.token))
@@ -4244,7 +4244,7 @@ object Parsers {
42444244
def givenDef(start: Offset, mods: Modifiers, givenMod: Mod) = atSpan(start, nameStart) {
42454245
var mods1 = addMod(mods, givenMod)
42464246
val nameStart = in.offset
4247-
var newSyntaxAllowed = sourceVersion.isAtLeast(`3.6`)
4247+
var newSyntaxAllowed = sourceVersion.enablesNewGivens
42484248
val hasEmbeddedColon = !in.isColon && followingIsGivenDefWithColon()
42494249
val name = if isIdent && hasEmbeddedColon then ident() else EmptyTermName
42504250

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import scala.collection.mutable
1717
import scala.collection.immutable.SortedMap
1818
import rewrites.Rewrites.patch
1919
import config.Feature
20-
import config.Feature.{migrateTo3, fewerBracesEnabled}
20+
import config.Feature.migrateTo3
2121
import config.SourceVersion.{`3.0`, `3.0-migration`}
2222
import config.MigrationVersion
2323
import reporting.{NoProfile, Profile, Message}
@@ -664,7 +664,7 @@ object Scanners {
664664
if token == COLONop && inTemplate then
665665
report.deprecationWarning(em"`:` after symbolic operator is deprecated; use backticks around operator instead", sourcePos(offset))
666666
true
667-
else token == COLONfollow && (inTemplate || fewerBracesEnabled)
667+
else token == COLONfollow && (inTemplate || sourceVersion.enablesFewerBraces)
668668
if enabled then
669669
peekAhead()
670670
val atEOL = isAfterLineEnd || token == EOF

tests/pos/interleavingExperimental.scala

-5
This file was deleted.

0 commit comments

Comments
 (0)