Skip to content

Commit 010ed5a

Browse files
authored
Stabilise SIP-47 (#20861)
Closes #20769 Initial implementation in #14019
2 parents e7fa3f6 + 36146eb commit 010ed5a

31 files changed

+38
-71
lines changed

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ object Feature:
121121

122122
def namedTypeArgsEnabled(using Context) = enabled(namedTypeArguments)
123123

124-
def clauseInterleavingEnabled(using Context) = enabled(clauseInterleaving)
124+
def clauseInterleavingEnabled(using Context) =
125+
sourceVersion.isAtLeast(`3.6`) || enabled(clauseInterleaving)
125126

126127
def genericNumberLiteralsEnabled(using Context) = enabled(genericNumberLiterals)
127128

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

+1-6
Original file line numberDiff line numberDiff line change
@@ -3836,9 +3836,6 @@ object Parsers {
38363836

38373837
/** DefDef ::= DefSig [‘:’ Type] [‘=’ Expr]
38383838
* | this TypelessClauses [DefImplicitClause] `=' ConstrExpr
3839-
* DefSig ::= id [DefTypeParamClause] DefTermParamClauses
3840-
*
3841-
* if clauseInterleaving is enabled:
38423839
* DefSig ::= id [DefParamClauses] [DefImplicitClause]
38433840
*/
38443841
def defDefOrDcl(start: Offset, mods: Modifiers, numLeadParams: Int = 0): DefDef = atSpan(start, nameStart) {
@@ -3878,13 +3875,11 @@ object Parsers {
38783875
val ident = termIdent()
38793876
var name = ident.name.asTermName
38803877
val paramss =
3881-
if in.featureEnabled(Feature.clauseInterleaving) then
3882-
// If you are making interleaving stable manually, please refer to the PR introducing it instead, section "How to make non-experimental"
3878+
if Feature.clauseInterleavingEnabled(using in.languageImportContext) then
38833879
typeOrTermParamClauses(ParamOwner.Def, numLeadParams)
38843880
else
38853881
val tparams = typeParamClauseOpt(ParamOwner.Def)
38863882
val vparamss = termParamClauses(ParamOwner.Def, numLeadParams)
3887-
38883883
joinParams(tparams, vparamss)
38893884

38903885
var tpt = fromWithinReturnType { typedOpt() }

docs/_docs/reference/experimental/generalized-method-syntax.md docs/_docs/reference/other-new-features/generalized-method-syntax.md

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,9 @@
11
---
22
layout: doc-page
33
title: "Generalized Method Syntax"
4-
nightlyOf: https://docs.scala-lang.org/scala3/reference/experimental/generalized-method-syntax.html
4+
nightlyOf: https://docs.scala-lang.org/scala3/reference/other-new-features/generalized-method-syntax.html
55
---
66

7-
This feature is not yet part of the Scala 3 language definition. It can be made available by a language import:
8-
9-
```scala
10-
import scala.language.experimental.clauseInterleaving
11-
```
12-
137
The inclusion of using clauses is not the only way in which methods have been updated, type parameter clauses are now allowed in any number and at any position.
148

159
## Syntax Changes
@@ -51,7 +45,7 @@ trait DB {
5145
}
5246
```
5347

54-
Note that simply replacing `V` by `k.Value` would not be equivalent. For example, if `k.Value` is `Some[Int]`, only the above allows:
48+
Note that simply replacing `V` by `k.Value` would not be equivalent. For example, if `k.Value` is `Some[Int]`, only the above allows:
5549
`getOrElse(k)[Option[Int]](None)`, which returns a `Number`.
5650

5751
## Details

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

+1
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ object language:
6767
* @see [[https://github.com/scala/improvement-proposals/blob/main/content/clause-interleaving.md]]
6868
*/
6969
@compileTimeOnly("`clauseInterleaving` can only be used at compile time in import statements")
70+
@deprecated("`clauseInterleaving` is now standard, no language import is needed", since = "3.6")
7071
object clauseInterleaving
7172

7273
/** Experimental support for pure function type syntax

presentation-compiler/test/dotty/tools/pc/tests/signaturehelp/SignatureHelpInterleavingSuite.scala

-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@ import java.nio.file.Path
88

99
class SignatureHelpInterleavingSuite extends BaseSignatureHelpSuite:
1010

11-
override protected def scalacOptions(classpath: Seq[Path]): Seq[String] =
12-
List("-language:experimental.clauseInterleaving")
13-
1411
@Test def `proper-position-1` =
1512
check(
1613
"""

scaladoc-testcases/src/tests/extensionParams.scala

-2
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ extension (using Unit)(a: Int)
6161
def f14(): Any
6262
= ???
6363

64-
import scala.language.experimental.clauseInterleaving
65-
6664
extension (using String)(using Int)(a: Animal)(using Unit)(using Number)
6765
def f16(b: Any)[T](c: T): T
6866
= ???

scaladoc-testcases/src/tests/methodsAndConstructors.scala

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package tests.methodsAndConstructors
22

3-
import scala.language.experimental.clauseInterleaving
4-
53
class A
64
class B extends A
75
class C

tests/neg/interleaving-ab.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
object Ab:
43
given String = ""
54
given Double = 0
65

76
def illegal[A][B](x: A)(using B): B = summon[B] // error: Type parameter lists must be separated by a term or using parameter list
8-
7+
98
def ab[A](x: A)[B](using B): B = summon[B]
109
def test =
1110
ab[Int](0: Int) // error

tests/neg/interleaving-params.scala

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
class Params{
43
def bar[T](x: T)[T]: String = ??? // error

tests/neg/interleaving-signatureCollision.scala

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
object signatureCollision:
43
def f[T](x: T)[U](y: U) = (x,y)

tests/neg/interleaving-typeApply.check

+14-14
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
1-
-- [E057] Type Mismatch Error: tests/neg/interleaving-typeApply.scala:10:11 --------------------------------------------
2-
10 | f3[String]() // error
3-
| ^
4-
| Type argument String does not conform to upper bound Int
5-
|
6-
| longer explanation available when compiling with `-explain`
7-
-- [E057] Type Mismatch Error: tests/neg/interleaving-typeApply.scala:11:16 --------------------------------------------
8-
11 | f5[Int][Unit] // error
1+
-- [E057] Type Mismatch Error: tests/neg/interleaving-typeApply.scala:9:11 ---------------------------------------------
2+
9 | f3[String]() // error
3+
| ^
4+
| Type argument String does not conform to upper bound Int
5+
|
6+
| longer explanation available when compiling with `-explain`
7+
-- [E057] Type Mismatch Error: tests/neg/interleaving-typeApply.scala:10:16 --------------------------------------------
8+
10 | f5[Int][Unit] // error
99
| ^
1010
| Type argument Unit does not conform to upper bound String
1111
|
1212
| longer explanation available when compiling with `-explain`
13-
-- [E057] Type Mismatch Error: tests/neg/interleaving-typeApply.scala:12:19 --------------------------------------------
14-
12 | f5[String][Unit] // error // error
13+
-- [E057] Type Mismatch Error: tests/neg/interleaving-typeApply.scala:11:19 --------------------------------------------
14+
11 | f5[String][Unit] // error // error
1515
| ^
1616
| Type argument Unit does not conform to upper bound String
1717
|
1818
| longer explanation available when compiling with `-explain`
19-
-- [E057] Type Mismatch Error: tests/neg/interleaving-typeApply.scala:12:11 --------------------------------------------
20-
12 | f5[String][Unit] // error // error
19+
-- [E057] Type Mismatch Error: tests/neg/interleaving-typeApply.scala:11:11 --------------------------------------------
20+
11 | f5[String][Unit] // error // error
2121
| ^
2222
| Type argument String does not conform to upper bound Int
2323
|
2424
| longer explanation available when compiling with `-explain`
25-
-- [E057] Type Mismatch Error: tests/neg/interleaving-typeApply.scala:13:11 --------------------------------------------
26-
13 | f7[String]()[Unit] // error
25+
-- [E057] Type Mismatch Error: tests/neg/interleaving-typeApply.scala:12:11 --------------------------------------------
26+
12 | f7[String]()[Unit] // error
2727
| ^
2828
| Type argument String does not conform to upper bound Int
2929
|

tests/neg/interleaving-typeApply.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
object typeApply:
4-
3+
54
def f3[T <: Int](using DummyImplicit)[U <: String](): T => T = ???
65
def f5[T <: Int](using DummyImplicit)[U <: String]: [X <: Unit] => X => X = ???
76
def f7[T <: Int](using DummyImplicit)[U <: String]()[X <: Unit]: X => X = ???

tests/neg/interleaving-unmatched.scala

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
object unmatched:
43
def f1[T (x: T)] = ??? // error
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- [E040] Syntax Error: tests/neg/interleavingExperimental.scala:3:15 --------------------------------------------------
2+
3 |def ba[A](x: A)[B](using B): B = summon[B] // error: clauseInterleaving was experimental until 3.6
3+
| ^
4+
| '=' expected, but '[' found
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
//> using options --source 3.5
2+
3+
def ba[A](x: A)[B](using B): B = summon[B] // error: clauseInterleaving was experimental until 3.6

tests/neg/namedTypeParams.check

+4-4
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,11 @@
9292
| illegal repeated type application
9393
| You might have meant something like:
9494
| Test.f[Y = String, Int]
95-
-- [E102] Syntax Error: tests/neg/namedTypeParams.scala:33:9 -----------------------------------------------------------
96-
33 | f2[Y = String][X = Int](1, "") // error: Y is undefined
95+
-- [E102] Syntax Error: tests/neg/namedTypeParams.scala:32:9 -----------------------------------------------------------
96+
32 | f2[Y = String][X = Int](1, "") // error: Y is undefined
9797
| ^^^^^^
9898
| Type parameter Y is undefined. Expected one of X.
99-
-- [E102] Syntax Error: tests/neg/namedTypeParams.scala:34:9 -----------------------------------------------------------
100-
34 | f2[Y = String](1, "") // error: Y is undefined
99+
-- [E102] Syntax Error: tests/neg/namedTypeParams.scala:33:9 -----------------------------------------------------------
100+
33 | f2[Y = String](1, "") // error: Y is undefined
101101
| ^^^^^^
102102
| Type parameter Y is undefined. Expected one of X.

tests/neg/namedTypeParams.scala

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ object Test:
2727

2828
object TestInterleaving:
2929
import language.experimental.namedTypeArguments
30-
import language.experimental.clauseInterleaving
3130
def f2[X](using DummyImplicit)[Y](x: X, y: Y): Int = ???
3231

3332
f2[Y = String][X = Int](1, "") // error: Y is undefined

tests/neg/overrides.scala

-6
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ class A[T] {
4444

4545
def next: T = ???
4646

47-
import scala.language.experimental.clauseInterleaving
48-
4947
def b[U <: T](x: Int)[V >: T](y: String) = false
5048
}
5149

@@ -57,8 +55,6 @@ class B extends A[Int] {
5755

5856
override def next(): Int = ??? // error: incompatible type
5957

60-
import scala.language.experimental.clauseInterleaving
61-
6258
override def b[T <: Int](x: Int)(y: String) = true // error
6359
}
6460

@@ -68,8 +64,6 @@ class C extends A[String] {
6864

6965
override def next: Int = ??? // error: incompatible type
7066

71-
import scala.language.experimental.clauseInterleaving
72-
7367
override def b[T <: String](x: Int)[U >: Int](y: String) = true // error: incompatible type
7468
}
7569

tests/pos/interleaving-ba.scala

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
object BA {
43
given String = ""

tests/pos/interleaving-chainedParams.scala

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
object chainedParams{
43

tests/pos/interleaving-classless.scala

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
def f1[T]()[U](x: T, y: U): (T, U) = (x, y)
43
def f2[T](x: T)[U](y: U): (T, U) = (x, y)

tests/pos/interleaving-functor.scala

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
object functorInterleaving:
43
//taken from https://dotty.epfl.ch/docs/reference/contextual/type-classes.html

tests/pos/interleaving-newline.scala

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
object newline {
43
def multipleLines

tests/pos/interleaving-overload.scala

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
class A{
43

tests/pos/interleaving-params.scala

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
class Params{
43
type U

tests/pos/interleaving-signatureCollision.scala

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.clauseInterleaving
21
import scala.annotation.targetName
32

43
object signatureCollision:

tests/pos/interleaving-typeApply.scala

-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
object typeApply:
43

@@ -12,7 +11,6 @@ object typeApply:
1211
def f7[T <: Int](using DummyImplicit)[U <: String]()[X <: Unit]: X => X = ???
1312

1413
@main def test = {
15-
import scala.language.experimental.namedTypeArguments
1614
f0[Int][String]
1715
f1[Int][String]
1816
f2[Int][String]()
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
//> using options --source 3.5
2+
3+
import scala.language.experimental.clauseInterleaving
4+
5+
def ba[A](x: A)[B](using B): B = summon[B]

tests/pos/namedTypeParams.scala

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ object Test {
1111
}
1212

1313
object TestInterleaving{
14-
import language.experimental.clauseInterleaving
1514
def f2[X](using DummyImplicit)[Y](x: X, y: Y): Int = ???
1615

1716
f2[X = Int][Y = String](1, "")

tests/pos/overrides.scala

-5
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ class A[T] {
44

55
def f(x: T)(y: T = x) = y
66

7-
import scala.language.experimental.clauseInterleaving
8-
97
def b[U <: T](x: Int)[V >: T](y: String) = false
108

119
}
@@ -15,9 +13,6 @@ class B extends A[Int] {
1513

1614
f(2)()
1715

18-
19-
import scala.language.experimental.clauseInterleaving
20-
2116
override def b[T <: Int](x: Int)[U >: Int](y: String) = true
2217

2318
}

tests/run/interleaving.scala

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import scala.language.experimental.clauseInterleaving
21

32
object Test extends App {
43
trait Key { type Value }

0 commit comments

Comments
 (0)