Skip to content

Commit 30f45d4

Browse files
committed
Change to (using x: T) => E for context functions
Change syntax of context functions to `(using x: T) => E`. The previous syntax `(x: T) ?=> E` is still supported, but the docs have been changed to `using`.
1 parent 1681e2d commit 30f45d4

File tree

15 files changed

+70
-62
lines changed

15 files changed

+70
-62
lines changed

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1846,9 +1846,13 @@ object Parsers {
18461846

18471847
def expr(location: Location.Value): Tree = {
18481848
val start = in.offset
1849+
def isSpecialClosureStart =
1850+
val lookahead = in.LookaheadScanner()
1851+
lookahead.nextToken()
1852+
lookahead.isIdent(nme.using) || lookahead.token == ERASED
18491853
if in.token == IMPLICIT then
18501854
closure(start, location, modifiers(BitSet(IMPLICIT)))
1851-
else if in.token == LPAREN && in.lookaheadIn(funTypeArgMods) then
1855+
else if in.token == LPAREN && isSpecialClosureStart then
18521856
closure(start, location, Modifiers())
18531857
else {
18541858
val saved = placeholderParams
@@ -2060,7 +2064,7 @@ object Parsers {
20602064
/** FunParams ::= Bindings
20612065
* | id
20622066
* | `_'
2063-
* Bindings ::= `(' [[‘given’] [‘erased’] Binding {`,' Binding}] `)'
2067+
* Bindings ::= `(' [[using] [‘erased’] Binding {`,' Binding}] `)'
20642068
*/
20652069
def funParams(mods: Modifiers, location: Location.Value): List[Tree] =
20662070
if in.token == LPAREN then
@@ -2069,8 +2073,12 @@ object Parsers {
20692073
Nil
20702074
else
20712075
openParens.change(LPAREN, 1)
2072-
val mods1 = if mods.flags.isEmpty then modifiers(funTypeArgMods) else mods
2073-
try commaSeparated(() => binding(mods1))
2076+
var mods1 = mods
2077+
if mods.flags.isEmpty then
2078+
if isIdent(nme.using) then mods1 = addMod(mods1, atSpan(in.skipToken()) { Mod.Given() })
2079+
if in.token == ERASED then mods1 = addModifier(mods1)
2080+
try
2081+
commaSeparated(() => binding(mods1))
20742082
finally
20752083
accept(RPAREN)
20762084
openParens.change(LPAREN, -1)

docs/docs/reference/contextual/context-functions-spec.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ trait ContextFunctionN[-T1 , ... , -TN, +R] {
2828
Context function types erase to normal function types, so these classes are
2929
generated on the fly for typechecking, but not realized in actual code.
3030

31-
Context function literals `(x1: T1, ..., xn: Tn) ?=> e` map
31+
Context function literals `(using x1: T1, ..., xn: Tn) => e` map
3232
context parameters `xi` of types `Ti` to the result of evaluating the expression `e`.
3333
The scope of each context parameter `xi` is `e`. The parameters must have pairwise distinct names.
3434

@@ -54,7 +54,7 @@ Note: The closing paragraph of the
5454
[Anonymous Functions section](https://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#anonymous-functions)
5555
of Scala 2.12 is subsumed by context function types and should be removed.
5656

57-
Context function literals `(x1: T1, ..., xn: Tn) ?=> e` are
57+
Context function literals `(using x1: T1, ..., xn: Tn) => e` are
5858
automatically created for any expression `e` whose expected type is
5959
`scala.ContextFunctionN[T1, ..., Tn, R]`, unless `e` is
6060
itself a context function literal. This is analogous to the automatic

docs/docs/reference/contextual/context-functions.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Conversely, if the expected type of an expression `E` is a context function type
2424
`(T_1, ..., T_n) ?=> U` and `E` is not already an
2525
context function literal, `E` is converted to an context function literal by rewriting to
2626
```scala
27-
(x_1: T1, ..., x_n: Tn) ?=> E
27+
(using x_1: T1, ..., x_n: Tn) => E
2828
```
2929
where the names `x_1`, ..., `x_n` are arbitrary. This expansion is performed
3030
before the expression `E` is typechecked, which means that `x_1`, ..., `x_n`
@@ -36,11 +36,11 @@ For example, continuing with the previous definitions,
3636
```scala
3737
def g(arg: Executable[Int]) = ...
3838

39-
g(22) // is expanded to g((ev: ExecutionContext) ?=> 22)
39+
g(22) // is expanded to g((using ev: ExecutionContext) => 22)
4040

41-
g(f(2)) // is expanded to g((ev: ExecutionContext) ?=> f(2)(using ev))
41+
g(f(2)) // is expanded to g((using ev: ExecutionContext) => f(2)(using ev))
4242

43-
g((ctx: ExecutionContext) ?=> f(22)(using ctx)) // is left as it is
43+
g((using ctx: ExecutionContext) => f(22)(using ctx)) // is left as it is
4444
```
4545
### Example: Builder Pattern
4646

@@ -97,14 +97,14 @@ that would otherwise be necessary.
9797
```
9898
With that setup, the table construction code above compiles and expands to:
9999
```scala
100-
table { ($t: Table) ?=>
100+
table { (using $t: Table) =>
101101

102-
row { ($r: Row) ?=>
102+
row { (using $r: Row) =>
103103
cell("top left")(using $r)
104104
cell("top right")(using $r)
105105
}(using $t)
106106

107-
row { ($r: Row) ?=>
107+
row { (using $r: Row) =>
108108
cell("bottom left")(using $r)
109109
cell("bottom right")(using $r)
110110
}(using $t)

docs/docs/release-notes/syntax-changes-0.22.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,16 @@ Context bounds remain supported as a shorthand for one-parameter typeclass const
3939
def max[T: Ordering](x: T, y: T): T = ...
4040
given [T: Ordering] as Ordering[List[T]] { ... }
4141
```
42-
43-
## Context Functions
44-
45-
Implicit function types `implicit A => B` have been replaced with context function types, which are written `A ?=> B`. The syntax `(given A) => B` that was used in earlier Dotty versions is no longer supported.
46-
47-
The same change applies to context function values. It's now
42+
Parameters of context function values are also written with `using`. So it is
4843
```scala
49-
(x: A) ?=> E
44+
(using x: A) => E
5045
```
5146
instead of `(implicit x: A) => E` or `(given x: A) => E`.
5247

48+
## Context Functions Types
49+
50+
Implicit function types `implicit A => B` have been replaced with context function types, which are written `A ?=> B`. The syntax `(given A) => B` that was used in earlier Dotty versions is no longer supported.
51+
5352
## Given Imports
5453

5554
The syntax of wildcard given import selectors is now `given _`. Examples

staging/src/scala/quoted/staging/staging.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ package object staging {
2323
*
2424
* Usage:
2525
* ```
26-
* val e: T = withQuoteContext { // (qctx: QuoteContext) ?=>
26+
* val e: T = withQuoteContext { // (using qctx: QuoteContext) =>
2727
* thunk
2828
* }
2929
* ```

tests/neg/i2514a.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
object Foo {
22
def foo(): Int = {
3-
val f: Int ?=> Int = (x: Int) ?=> 2 * x
3+
val f: Int ?=> Int = (using x: Int) => 2 * x
44
f(using 2)
55
}
66

77
val f = implicit (x: Int) => x
88

9-
((x: Int) ?=> x): (Int ?=> Int) // error: no implicit argument found
9+
((using x: Int) => x): (Int ?=> Int) // error: no implicit argument found
1010
}
11+

tests/pos/i6862/lib_1.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
trait Ctx
2-
inline def foo(): Unit = (x: Ctx) ?=> ()
2+
inline def foo(): Unit = (using x: Ctx) => ()
33
def bar[T](b: Ctx ?=> Unit): Unit = ???

tests/run-custom-args/lambda-serialization-others.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ class C1 {
3636

3737
class C2
3838
extends Serializable /* Needed because of #5866 */ {
39-
val impfun: Int ?=> Int = x1 ?=> x1
39+
val impfun: Int ?=> Int = (using x1) => x1
4040

41-
val impdepfun: (x1: Int) ?=> List[x1.type] = x1 ?=> List(x1)
41+
val impdepfun: (x1: Int) ?=> List[x1.type] = (using x1) => List(x1)
4242

43-
val erasedimpfun: (erased Int) ?=> Int = (erased x1) ?=> 0
43+
val erasedimpfun: (erased Int) ?=> Int = (using erased x1) => 0
4444
}
4545

4646
object Test {

0 commit comments

Comments
 (0)