Skip to content

Commit b9464b4

Browse files
committed
Make NamedTuples a standard feature again in 3.7
1 parent 133dcb3 commit b9464b4

File tree

70 files changed

+121
-329
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+121
-329
lines changed

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ object Feature:
3333
val pureFunctions = experimental("pureFunctions")
3434
val captureChecking = experimental("captureChecking")
3535
val into = experimental("into")
36-
val namedTuples = experimental("namedTuples")
3736
val modularity = experimental("modularity")
3837
val betterMatchTypeExtractors = experimental("betterMatchTypeExtractors")
3938
val quotedPatternsWithPolymorphicFunctions = experimental("quotedPatternsWithPolymorphicFunctions")
@@ -64,7 +63,6 @@ object Feature:
6463
(pureFunctions, "Enable pure functions for capture checking"),
6564
(captureChecking, "Enable experimental capture checking"),
6665
(into, "Allow into modifier on parameter types"),
67-
(namedTuples, "Allow named tuples"),
6866
(modularity, "Enable experimental modularity features"),
6967
(betterMatchTypeExtractors, "Enable better match type extractors"),
7068
(betterFors, "Enable improvements in `for` comprehensions")

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

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,7 @@ object Parsers {
671671
else leading :: Nil
672672

673673
def maybeNamed(op: () => Tree): () => Tree = () =>
674-
if isIdent && in.lookahead.token == EQUALS && in.featureEnabled(Feature.namedTuples) then
674+
if isIdent && in.lookahead.token == EQUALS && sourceVersion.enablesNamedTuples then
675675
atSpan(in.offset):
676676
val name = ident()
677677
in.nextToken()
@@ -1137,32 +1137,15 @@ object Parsers {
11371137
if (prec < opPrec || leftAssoc && prec == opPrec) {
11381138
opStack = opStack.tail
11391139
recur {
1140-
migrateInfixOp(opInfo, isType):
1141-
atSpan(opInfo.operator.span union opInfo.operand.span union top.span):
1142-
InfixOp(opInfo.operand, opInfo.operator, top)
1140+
atSpan(opInfo.operator.span union opInfo.operand.span union top.span):
1141+
InfixOp(opInfo.operand, opInfo.operator, top)
11431142
}
11441143
}
11451144
else top
11461145
}
11471146
recur(top)
11481147
}
11491148

1150-
private def migrateInfixOp(opInfo: OpInfo, isType: Boolean)(infixOp: InfixOp): Tree = {
1151-
def isNamedTupleOperator = opInfo.operator.name match
1152-
case nme.EQ | nme.NE | nme.eq | nme.ne | nme.`++` | nme.zip => true
1153-
case _ => false
1154-
if isType then infixOp
1155-
else infixOp.right match
1156-
case Tuple(args) if args.exists(_.isInstanceOf[NamedArg]) && !isNamedTupleOperator =>
1157-
report.errorOrMigrationWarning(DeprecatedInfixNamedArgumentSyntax(), infixOp.right.srcPos, MigrationVersion.AmbiguousNamedTupleSyntax)
1158-
if MigrationVersion.AmbiguousNamedTupleSyntax.needsPatch then
1159-
val asApply = cpy.Apply(infixOp)(Select(opInfo.operand, opInfo.operator.name), args)
1160-
patch(source, infixOp.span, asApply.show(using ctx.withoutColors))
1161-
asApply // allow to use pre-3.6 syntax in migration mode
1162-
else infixOp
1163-
case _ => infixOp
1164-
}
1165-
11661149
/** True if we are seeing a lambda argument after a colon of the form:
11671150
* : (params) =>
11681151
* body
@@ -2177,7 +2160,7 @@ object Parsers {
21772160

21782161
if namedOK && isIdent && in.lookahead.token == EQUALS then
21792162
commaSeparated(() => namedArgType())
2180-
else if tupleOK && isIdent && in.lookahead.isColon && in.featureEnabled(Feature.namedTuples) then
2163+
else if tupleOK && isIdent && in.lookahead.isColon && sourceVersion.enablesNamedTuples then
21812164
commaSeparated(() => namedElem())
21822165
else
21832166
commaSeparated(() => argType())

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
825825
def tryNamedTupleSelection() =
826826
val namedTupleElems = qual.tpe.widenDealias.namedTupleElementTypes(true)
827827
val nameIdx = namedTupleElems.indexWhere(_._1 == selName)
828-
if nameIdx >= 0 && Feature.enabled(Feature.namedTuples) then
828+
if nameIdx >= 0 && sourceVersion.enablesNamedTuples then
829829
typed(
830830
untpd.Apply(
831831
untpd.Select(untpd.TypedSplice(qual), nme.apply),

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ class CompilationTests {
7979
compileFile("tests/rewrites/i20002.scala", defaultOptions.and("-indent", "-rewrite")),
8080
compileDir("tests/rewrites/annotation-named-pararamters", defaultOptions.and("-rewrite", "-source:3.6-migration")),
8181
compileFile("tests/rewrites/i21418.scala", unindentOptions.and("-rewrite", "-source:3.5-migration")),
82-
compileFile("tests/rewrites/infix-named-args.scala", defaultOptions.and("-rewrite", "-source:3.6-migration")),
83-
compileFile("tests/rewrites/ambiguous-named-tuple-assignment.scala", defaultOptions.and("-rewrite", "-source:3.6-migration")),
8482
compileFile("tests/rewrites/i21382.scala", defaultOptions.and("-indent", "-rewrite")),
8583
compileFile("tests/rewrites/unused.scala", defaultOptions.and("-rewrite", "-Wunused:all")),
8684
compileFile("tests/rewrites/i22440.scala", defaultOptions.and("-rewrite"))

docs/_docs/reference/experimental/named-tuples.md renamed to docs/_docs/reference/other-new-features/named-tuples.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
---
22
layout: doc-page
33
title: "Named Tuples"
4-
nightlyOf: https://docs.scala-lang.org/scala3/reference/experimental/named-tuples.html
4+
nightlyOf: https://docs.scala-lang.org/scala3/reference/other-new-features/named-tuples.html
55
---
66

7-
The elements of a tuple can now be named. Example:
7+
Starting in Scala 3.7, the elements of a tuple can be named.
8+
Example:
89
```scala
910
type Person = (name: String, age: Int)
1011
val Bob: Person = (name = "Bob", age = 33)

docs/sidebar.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ subsection:
7272
- page: reference/other-new-features/export.md
7373
- page: reference/other-new-features/opaques.md
7474
- page: reference/other-new-features/opaques-details.md
75+
- page: reference/other-new-features/named-tuples.md
7576
- page: reference/other-new-features/open-classes.md
7677
- page: reference/other-new-features/parameter-untupling.md
7778
- page: reference/other-new-features/parameter-untupling-spec.md
@@ -158,7 +159,6 @@ subsection:
158159
- page: reference/experimental/cc.md
159160
- page: reference/experimental/purefuns.md
160161
- page: reference/experimental/tupled-function.md
161-
- page: reference/experimental/named-tuples.md
162162
- page: reference/experimental/modularity.md
163163
- page: reference/experimental/typeclasses.md
164164
- page: reference/experimental/runtimeChecked.md

language-server/test/dotty/tools/languageserver/CompletionTest.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,8 +1725,7 @@ class CompletionTest {
17251725
.completion(m6, Set())
17261726

17271727
@Test def namedTupleCompletion: Unit =
1728-
code"""|import scala.language.experimental.namedTuples
1729-
|
1728+
code"""|
17301729
|val person: (name: String, city: String) =
17311730
| (name = "Jamie", city = "Lausanne")
17321731
|

library/src/scala/NamedTuple.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package scala
2-
import annotation.experimental
32
import compiletime.ops.boolean.*
43

5-
@experimental
64
object NamedTuple:
75

86
/** The type to which named tuples get mapped to. For instance,
@@ -133,7 +131,6 @@ object NamedTuple:
133131
end NamedTuple
134132

135133
/** Separate from NamedTuple object so that we can match on the opaque type NamedTuple. */
136-
@experimental
137134
object NamedTupleDecomposition:
138135
import NamedTuple.*
139136
extension [N <: Tuple, V <: Tuple](x: NamedTuple[N, V])

library/src/scala/runtime/stdLibPatches/language.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ object language:
9797
* @see [[https://dotty.epfl.ch/docs/reference/experimental/named-tuples]]
9898
*/
9999
@compileTimeOnly("`namedTuples` can only be used at compile time in import statements")
100+
@deprecated("The experimental.namedTuples language import is no longer needed since the feature is now standard", since = "3.7")
100101
object namedTuples
101102

102103
/** Experimental support for new features for better modularity, including

presentation-compiler/test/dotty/tools/pc/tests/completion/CompletionSuite.scala

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2032,8 +2032,7 @@ class CompletionSuite extends BaseCompletionSuite:
20322032

20332033
@Test def `namedTuple completions` =
20342034
check(
2035-
"""|import scala.language.experimental.namedTuples
2036-
|import scala.NamedTuple.*
2035+
"""|import scala.NamedTuple.*
20372036
|
20382037
|val person = (name = "Jamie", city = "Lausanne")
20392038
|
@@ -2044,8 +2043,7 @@ class CompletionSuite extends BaseCompletionSuite:
20442043

20452044
@Test def `Selectable with namedTuple Fields member` =
20462045
check(
2047-
"""|import scala.language.experimental.namedTuples
2048-
|import scala.NamedTuple.*
2046+
"""|import scala.NamedTuple.*
20492047
|
20502048
|class NamedTupleSelectable extends Selectable {
20512049
| type Fields <: AnyNamedTuple

presentation-compiler/test/dotty/tools/pc/tests/definition/PcDefinitionSuite.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -507,8 +507,7 @@ class PcDefinitionSuite extends BasePcDefinitionSuite:
507507

508508
@Test def `named-tuples` =
509509
check(
510-
"""|import scala.language.experimental.namedTuples
511-
|
510+
"""|
512511
|val <<foo>> = (name = "Bob", age = 42, height = 1.9d)
513512
|val foo_name = foo.na@@me
514513
|""".stripMargin

presentation-compiler/test/dotty/tools/pc/tests/hover/HoverTermSuite.scala

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -720,8 +720,7 @@ class HoverTermSuite extends BaseHoverSuite:
720720

721721
@Test def `named-tuples`: Unit =
722722
check(
723-
"""import scala.language.experimental.namedTuples
724-
|
723+
"""
725724
|val foo = (name = "Bob", age = 42, height = 1.9d)
726725
|val foo_name = foo.na@@me
727726
|""".stripMargin,
@@ -730,9 +729,7 @@ class HoverTermSuite extends BaseHoverSuite:
730729

731730
@Test def `named-tuples2`: Unit =
732731
check(
733-
"""|import scala.language.experimental.namedTuples
734-
|
735-
|import NamedTuple.*
732+
"""|import NamedTuple.*
736733
|
737734
|class NamedTupleSelectable extends Selectable {
738735
| type Fields <: AnyNamedTuple

tests/neg/i20517.check

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
-- [E007] Type Mismatch Error: tests/neg/i20517.scala:10:43 ------------------------------------------------------------
2-
10 | def dep(foo: Foo[Any]): From[foo.type] = (elem = "") // error
3-
| ^^^^^^^^^^^
4-
| Found: (elem : String)
5-
| Required: NamedTuple.From[(foo : Foo[Any])]
6-
|
7-
| longer explanation available when compiling with `-explain`
1+
-- [E007] Type Mismatch Error: tests/neg/i20517.scala:9:43 -------------------------------------------------------------
2+
9 | def dep(foo: Foo[Any]): From[foo.type] = (elem = "") // error
3+
| ^^^^^^^^^^^
4+
| Found: (elem : String)
5+
| Required: NamedTuple.From[(foo : Foo[Any])]
6+
|
7+
| longer explanation available when compiling with `-explain`

tests/neg/i20517.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.namedTuples
21
import NamedTuple.From
32

43
case class Foo[+T](elem: T)

tests/neg/i22192.check

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
1-
-- Error: tests/neg/i22192.scala:6:12 ----------------------------------------------------------------------------------
2-
6 | case City(iam = n, confused = p) => // error // error
1+
-- Error: tests/neg/i22192.scala:4:12 ----------------------------------------------------------------------------------
2+
4 | case City(iam = n, confused = p) => // error // error
33
| ^^^^^^^
44
| No element named `iam` is defined in selector type City
5-
-- Error: tests/neg/i22192.scala:6:21 ----------------------------------------------------------------------------------
6-
6 | case City(iam = n, confused = p) => // error // error
5+
-- Error: tests/neg/i22192.scala:4:21 ----------------------------------------------------------------------------------
6+
4 | case City(iam = n, confused = p) => // error // error
77
| ^^^^^^^^^^^^
88
| No element named `confused` is defined in selector type City
9-
-- [E006] Not Found Error: tests/neg/i22192.scala:7:7 ------------------------------------------------------------------
10-
7 | s"$n has a population of $p" // error // error
9+
-- [E006] Not Found Error: tests/neg/i22192.scala:5:7 ------------------------------------------------------------------
10+
5 | s"$n has a population of $p" // error // error
1111
| ^
1212
| Not found: n
1313
|
1414
| longer explanation available when compiling with `-explain`
15-
-- [E006] Not Found Error: tests/neg/i22192.scala:7:30 -----------------------------------------------------------------
16-
7 | s"$n has a population of $p" // error // error
15+
-- [E006] Not Found Error: tests/neg/i22192.scala:5:30 -----------------------------------------------------------------
16+
5 | s"$n has a population of $p" // error // error
1717
| ^
1818
| Not found: p
1919
|
2020
| longer explanation available when compiling with `-explain`
21-
-- Error: tests/neg/i22192.scala:10:12 ---------------------------------------------------------------------------------
22-
10 | case Some(iam = n) => // error
23-
| ^^^^^^^
24-
| No element named `iam` is defined in selector type City
25-
-- [E006] Not Found Error: tests/neg/i22192.scala:11:4 -----------------------------------------------------------------
26-
11 | n // error
27-
| ^
28-
| Not found: n
29-
|
30-
| longer explanation available when compiling with `-explain`
21+
-- Error: tests/neg/i22192.scala:8:12 ----------------------------------------------------------------------------------
22+
8 | case Some(iam = n) => // error
23+
| ^^^^^^^
24+
| No element named `iam` is defined in selector type City
25+
-- [E006] Not Found Error: tests/neg/i22192.scala:9:4 ------------------------------------------------------------------
26+
9 | n // error
27+
| ^
28+
| Not found: n
29+
|
30+
| longer explanation available when compiling with `-explain`

tests/neg/i22192.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import scala.language.experimental.namedTuples
2-
31
case class City(name: String, population: Int)
42

53
def getCityInfo(city: City) = city match

tests/neg/i22192a.check

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
-- Error: tests/neg/i22192a.scala:6:12 ---------------------------------------------------------------------------------
2-
6 | case Some(iam = n) => // error
1+
-- Error: tests/neg/i22192a.scala:4:12 ---------------------------------------------------------------------------------
2+
4 | case Some(iam = n) => // error
33
| ^^^^^^^
44
| No element named `iam` is defined in selector type (name : String)
5-
-- [E006] Not Found Error: tests/neg/i22192a.scala:7:4 -----------------------------------------------------------------
6-
7 | n // error
5+
-- [E006] Not Found Error: tests/neg/i22192a.scala:5:4 -----------------------------------------------------------------
6+
5 | n // error
77
| ^
88
| Not found: n
99
|
1010
| longer explanation available when compiling with `-explain`
11-
-- Error: tests/neg/i22192a.scala:11:12 --------------------------------------------------------------------------------
12-
11 | case Some(iam = n) => // error
13-
| ^^^^^^^
14-
| No element named `iam` is defined in selector type (name : String, population : Int)
15-
-- [E006] Not Found Error: tests/neg/i22192a.scala:12:4 ----------------------------------------------------------------
16-
12 | n // error
11+
-- Error: tests/neg/i22192a.scala:9:12 ---------------------------------------------------------------------------------
12+
9 | case Some(iam = n) => // error
13+
| ^^^^^^^
14+
| No element named `iam` is defined in selector type (name : String, population : Int)
15+
-- [E006] Not Found Error: tests/neg/i22192a.scala:10:4 ----------------------------------------------------------------
16+
10 | n // error
1717
| ^
1818
| Not found: n
1919
|

tests/neg/i22192a.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import scala.language.experimental.namedTuples
2-
31
type City = (name: String)
42

53
def getCityInfo(city: Option[City]) = city match

tests/neg/infix-named-args.check

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
-- [E134] Type Error: tests/neg/infix-named-args.scala:4:13 ------------------------------------------------------------
2-
4 | def f = 42 + (x = 1) // error // werror
1+
-- [E134] Type Error: tests/neg/infix-named-args.scala:2:13 ------------------------------------------------------------
2+
2 | def f = 42 + (x = 1) // error // werror
33
| ^^^^
44
| None of the overloaded alternatives of method + in class Int with types
55
| (x: Double): Double
@@ -11,27 +11,3 @@
1111
| (x: Byte): Int
1212
| (x: String): String
1313
| match arguments ((x : Int)) (a named tuple)
14-
-- [E204] Syntax Warning: tests/neg/infix-named-args.scala:4:15 --------------------------------------------------------
15-
4 | def f = 42 + (x = 1) // error // werror
16-
| ^^^^^^^
17-
|Deprecated syntax: infix named arguments lists are deprecated; in the future it would be interpreted as a single name tuple argument.
18-
|To avoid this warning, either remove the argument names or use dotted selection.
19-
|This can be rewritten automatically under -rewrite -source 3.6-migration.
20-
-- [E204] Syntax Warning: tests/neg/infix-named-args.scala:7:26 --------------------------------------------------------
21-
7 | def g = new C() `multi` (x = 42, y = 27) // werror
22-
| ^^^^^^^^^^^^^^^^
23-
|Deprecated syntax: infix named arguments lists are deprecated; in the future it would be interpreted as a single name tuple argument.
24-
|To avoid this warning, either remove the argument names or use dotted selection.
25-
|This can be rewritten automatically under -rewrite -source 3.6-migration.
26-
-- [E204] Syntax Warning: tests/neg/infix-named-args.scala:8:21 --------------------------------------------------------
27-
8 | def h = new C() ** (x = 42, y = 27) // werror
28-
| ^^^^^^^^^^^^^^^^
29-
|Deprecated syntax: infix named arguments lists are deprecated; in the future it would be interpreted as a single name tuple argument.
30-
|To avoid this warning, either remove the argument names or use dotted selection.
31-
|This can be rewritten automatically under -rewrite -source 3.6-migration.
32-
-- [E204] Syntax Warning: tests/neg/infix-named-args.scala:15:18 -------------------------------------------------------
33-
15 | def f = this ** (x = 2) // werror
34-
| ^^^^^^^
35-
|Deprecated syntax: infix named arguments lists are deprecated; in the future it would be interpreted as a single name tuple argument.
36-
|To avoid this warning, either remove the argument names or use dotted selection.
37-
|This can be rewritten automatically under -rewrite -source 3.6-migration.

tests/neg/infix-named-args.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import scala.language.experimental.namedTuples
2-
31
class C:
42
def f = 42 + (x = 1) // error // werror
53
def multi(x: Int, y: Int): Int = x + y

tests/neg/named-tuple-selectable.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import scala.language.experimental.namedTuples
2-
31
class FromFields extends Selectable:
42
type Fields = (i: Int)
53
def selectDynamic(key: String) =

tests/neg/named-tuples-2.check

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
-- Error: tests/neg/named-tuples-2.scala:5:9 ---------------------------------------------------------------------------
2-
5 | case (name, age) => () // error
1+
-- Error: tests/neg/named-tuples-2.scala:4:9 ---------------------------------------------------------------------------
2+
4 | case (name, age) => () // error
33
| ^
44
| this case is unreachable since type (String, Int, Boolean) is not a subclass of class Tuple2
5-
-- Error: tests/neg/named-tuples-2.scala:6:9 ---------------------------------------------------------------------------
6-
6 | case (n, a, m, x) => () // error
5+
-- Error: tests/neg/named-tuples-2.scala:5:9 ---------------------------------------------------------------------------
6+
5 | case (n, a, m, x) => () // error
77
| ^
88
| this case is unreachable since type (String, Int, Boolean) is not a subclass of class Tuple4

tests/neg/named-tuples-2.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import language.experimental.namedTuples
21
def Test =
32
val person = (name = "Bob", age = 33, married = true)
43
person match

tests/neg/named-tuples-3.check

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
-- [E007] Type Mismatch Error: tests/neg/named-tuples-3.scala:7:16 -----------------------------------------------------
2-
7 |val p: Person = f // error
1+
-- [E007] Type Mismatch Error: tests/neg/named-tuples-3.scala:5:16 -----------------------------------------------------
2+
5 |val p: Person = f // error
33
| ^
44
| Found: NamedTuple.NamedTuple[(Int, Any), (Int, String)]
55
| Required: Person

tests/neg/named-tuples-3.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import language.experimental.namedTuples
2-
31
def f: NamedTuple.NamedTuple[(Int, Any), (Int, String)] = ???
42

53
type Person = (name: Int, age: String)

0 commit comments

Comments
 (0)