Skip to content

Commit 9c04baa

Browse files
Merge pull request #10487 from dotty-staging/change-ift-params
Fix #10484: Switch back to old context function closure syntax
2 parents 8059fce + 1ec425a commit 9c04baa

30 files changed

+101
-108
lines changed

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

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -443,35 +443,35 @@ object Parsers {
443443

444444
/** Convert tree to formal parameter list
445445
*/
446-
def convertToParams(tree: Tree): List[ValDef] = tree match {
446+
def convertToParams(tree: Tree, mods: Modifiers): List[ValDef] = tree match {
447447
case Parens(t) =>
448-
convertToParam(t) :: Nil
448+
convertToParam(t, mods) :: Nil
449449
case Tuple(ts) =>
450-
ts.map(convertToParam(_))
450+
ts.map(convertToParam(_, mods))
451451
case t: Typed =>
452452
report.errorOrMigrationWarning(
453453
em"parentheses are required around the parameter of a lambda${rewriteNotice()}",
454454
in.sourcePos())
455455
if migrateTo3 then
456456
patch(source, t.span.startPos, "(")
457457
patch(source, t.span.endPos, ")")
458-
convertToParam(t) :: Nil
458+
convertToParam(t, mods) :: Nil
459459
case t =>
460-
convertToParam(t) :: Nil
460+
convertToParam(t, mods) :: Nil
461461
}
462462

463463
/** Convert tree to formal parameter
464464
*/
465-
def convertToParam(tree: Tree, expected: String = "formal parameter"): ValDef = tree match {
465+
def convertToParam(tree: Tree, mods: Modifiers, expected: String = "formal parameter"): ValDef = tree match {
466466
case id @ Ident(name) =>
467-
makeParameter(name.asTermName, TypeTree(), EmptyModifiers, isBackquoted = isBackquoted(id)).withSpan(tree.span)
467+
makeParameter(name.asTermName, TypeTree(), mods, isBackquoted = isBackquoted(id)).withSpan(tree.span)
468468
case Typed(id @ Ident(name), tpt) =>
469-
makeParameter(name.asTermName, tpt, EmptyModifiers, isBackquoted = isBackquoted(id)).withSpan(tree.span)
469+
makeParameter(name.asTermName, tpt, mods, isBackquoted = isBackquoted(id)).withSpan(tree.span)
470470
case Typed(Splice(Ident(name)), tpt) =>
471-
makeParameter(("$" + name).toTermName, tpt, EmptyModifiers).withSpan(tree.span)
471+
makeParameter(("$" + name).toTermName, tpt, mods).withSpan(tree.span)
472472
case _ =>
473473
syntaxError(s"not a legal $expected", tree.span)
474-
makeParameter(nme.ERROR, tree, EmptyModifiers)
474+
makeParameter(nme.ERROR, tree, mods)
475475
}
476476

477477
/** Convert (qual)ident to type identifier
@@ -1864,14 +1864,14 @@ object Parsers {
18641864
accept(altToken)
18651865
t
18661866

1867-
/** Expr ::= [`implicit'] FunParams ‘=>’ Expr
1867+
/** Expr ::= [`implicit'] FunParams (‘=>’ | ‘?=>’) Expr
18681868
* | Expr1
18691869
* FunParams ::= Bindings
18701870
* | id
18711871
* | `_'
18721872
* ExprInParens ::= PostfixExpr `:' Type
18731873
* | Expr
1874-
* BlockResult ::= [‘implicit’] FunParams ‘=>’ Block
1874+
* BlockResult ::= [‘implicit’] FunParams (‘=>’ | ‘?=>’) Block
18751875
* | Expr1
18761876
* Expr1 ::= [‘inline’] `if' `(' Expr `)' {nl} Expr [[semi] else Expr]
18771877
* | [‘inline’] `if' Expr `then' Expr [[semi] else Expr]
@@ -1920,9 +1920,10 @@ object Parsers {
19201920
finally placeholderParams = saved
19211921

19221922
val t = expr1(location)
1923-
if (in.token == ARROW) {
1923+
if (in.token == ARROW || in.token == CTXARROW) {
19241924
placeholderParams = Nil // don't interpret `_' to the left of `=>` as placeholder
1925-
wrapPlaceholders(closureRest(start, location, convertToParams(t)))
1925+
val paramMods = if in.token == CTXARROW then Modifiers(Given) else EmptyModifiers
1926+
wrapPlaceholders(closureRest(start, location, convertToParams(t, paramMods)))
19261927
}
19271928
else if (isWildcard(t)) {
19281929
placeholderParams = placeholderParams ::: saved
@@ -2124,7 +2125,7 @@ object Parsers {
21242125
/** FunParams ::= Bindings
21252126
* | id
21262127
* | `_'
2127-
* Bindings ::= `(' [[‘using’] [‘erased’] Binding {`,' Binding}] `)'
2128+
* Bindings ::= `(' [[‘erased’] Binding {`,' Binding}] `)'
21282129
*/
21292130
def funParams(mods: Modifiers, location: Location): List[Tree] =
21302131
if in.token == LPAREN then
@@ -2185,7 +2186,7 @@ object Parsers {
21852186

21862187
def closureRest(start: Int, location: Location, params: List[Tree]): Tree =
21872188
atSpan(start, in.offset) {
2188-
accept(ARROW)
2189+
if in.token == CTXARROW then in.nextToken() else accept(ARROW)
21892190
Function(params, if (location == Location.InBlock) block() else expr())
21902191
}
21912192

@@ -2309,7 +2310,7 @@ object Parsers {
23092310
possibleTemplateStart()
23102311
val parents =
23112312
if in.isNestedStart then Nil
2312-
else constrApps(commaOK = false, templateCanFollow = true)
2313+
else constrApps(commaOK = false)
23132314
colonAtEOLOpt()
23142315
possibleTemplateStart(isNew = true)
23152316
parents match {
@@ -3492,7 +3493,7 @@ object Parsers {
34923493
val parents =
34933494
if (in.token == EXTENDS) {
34943495
in.nextToken()
3495-
constrApps(commaOK = true, templateCanFollow = false)
3496+
constrApps(commaOK = true)
34963497
}
34973498
else Nil
34983499
Template(constr, parents, Nil, EmptyValDef, Nil)
@@ -3536,7 +3537,7 @@ object Parsers {
35363537
val noParams = tparams.isEmpty && vparamss.isEmpty
35373538
if !(name.isEmpty && noParams) then
35383539
accept(nme.as)
3539-
val parents = constrApps(commaOK = true, templateCanFollow = true)
3540+
val parents = constrApps(commaOK = true)
35403541
if in.token == EQUALS && parents.length == 1 && parents.head.isType then
35413542
accept(EQUALS)
35423543
mods1 |= Final
@@ -3616,19 +3617,12 @@ object Parsers {
36163617

36173618
/** ConstrApps ::= ConstrApp {(‘,’ | ‘with’) ConstrApp}
36183619
*/
3619-
def constrApps(commaOK: Boolean, templateCanFollow: Boolean): List[Tree] =
3620+
def constrApps(commaOK: Boolean): List[Tree] =
36203621
val t = constrApp()
36213622
val ts =
3622-
if in.token == WITH then
3623-
in.nextToken()
3624-
newLineOptWhenFollowedBy(LBRACE)
3625-
if templateCanFollow && (in.token == LBRACE || in.token == INDENT) then
3626-
Nil
3627-
else
3628-
constrApps(commaOK, templateCanFollow)
3629-
else if commaOK && in.token == COMMA then
3623+
if in.token == WITH || commaOK && in.token == COMMA then
36303624
in.nextToken()
3631-
constrApps(commaOK, templateCanFollow)
3625+
constrApps(commaOK)
36323626
else Nil
36333627
t :: ts
36343628

@@ -3645,7 +3639,7 @@ object Parsers {
36453639
in.sourcePos())
36463640
Nil
36473641
}
3648-
else constrApps(commaOK = true, templateCanFollow = true)
3642+
else constrApps(commaOK = true)
36493643
}
36503644
else Nil
36513645
newLinesOptWhenFollowedBy(nme.derives)
@@ -3772,7 +3766,7 @@ object Parsers {
37723766
case Typed(tree @ This(EmptyTypeIdent), tpt) =>
37733767
self = makeSelfDef(nme.WILDCARD, tpt).withSpan(first.span)
37743768
case _ =>
3775-
val ValDef(name, tpt, _) = convertToParam(first, "self type clause")
3769+
val ValDef(name, tpt, _) = convertToParam(first, EmptyModifiers, "self type clause")
37763770
if (name != nme.ERROR)
37773771
self = makeSelfDef(name, tpt).withSpan(first.span)
37783772
}

docs/docs/internals/syntax.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,9 @@ Types ::= Type {‘,’ Type}
185185

186186
### Expressions
187187
```ebnf
188-
Expr ::= FunParams ‘=>’ Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr)
188+
Expr ::= FunParams (‘=>’ | ‘?=>’) Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr)
189189
| Expr1
190-
BlockResult ::= FunParams ‘=>’ Block
190+
BlockResult ::= FunParams (‘=>’ | ‘?=>’) Block
191191
| Expr1
192192
FunParams ::= Bindings
193193
| id
@@ -322,7 +322,7 @@ ClosureMods ::= { ‘implicit’ | ‘given’}
322322

323323
### Bindings and Imports
324324
```ebnf
325-
Bindings ::= ‘(’ [[‘using’] Binding {‘,’ Binding}] ‘)’
325+
Bindings ::= ‘(’ [Binding {‘,’ Binding}] ‘)’
326326
Binding ::= (id | ‘_’) [‘:’ Type] ValDef(_, id, tpe, EmptyTree)
327327
328328
Modifier ::= LocalModifier

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 `(using x1: T1, ..., xn: Tn) => e` map
31+
Context function literals `(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 `(using x1: T1, ..., xn: Tn) => e` are
57+
Context function literals `(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: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Conversely, if the expected type of an expression `E` is a context function type
2727
`(T_1, ..., T_n) ?=> U` and `E` is not already an
2828
context function literal, `E` is converted to a context function literal by rewriting it to
2929
```scala
30-
(using x_1: T1, ..., x_n: Tn) => E
30+
(x_1: T1, ..., x_n: Tn) ?=> E
3131
```
3232
where the names `x_1`, ..., `x_n` are arbitrary. This expansion is performed
3333
before the expression `E` is typechecked, which means that `x_1`, ..., `x_n`
@@ -39,12 +39,12 @@ For example, continuing with the previous definitions,
3939
```scala
4040
def g(arg: Executable[Int]) = ...
4141

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

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

46-
g(ExecutionContext ?=> f(3)) // is expanded to g((using ev: ExecutionContext) => f(3)(using ev))
47-
g((using ctx: ExecutionContext) => f(22)(using ctx)) // is left as it is
46+
g((ctx: ExecutionContext) ?=> f(3)) // is expanded to g((ctx: ExecutionContext) ?=> f(3)(using ctx))
47+
g((ctx: ExecutionContext) ?=> f(3)(using ctx)) // is left as it is
4848
```
4949

5050
### Example: Builder Pattern
@@ -102,14 +102,14 @@ that would otherwise be necessary.
102102
```
103103
With that setup, the table construction code above compiles and expands to:
104104
```scala
105-
table { (using $t: Table) =>
105+
table { ($t: Table) ?=>
106106

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

112-
row { (using $r: Row) =>
112+
row { ($r: Row) ?=>
113113
cell("bottom left")(using $r)
114114
cell("bottom right")(using $r)
115115
}(using $t)

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ package object staging:
77
*
88
* Usage:
99
* ```
10-
* val e: T = run { // (using Quotes) =>
10+
* val e: T = run { // (quotes: Quotes) ?=>
1111
* expr
1212
* }
1313
* ```
@@ -23,7 +23,7 @@ package object staging:
2323
*
2424
* Usage:
2525
* ```
26-
* val e: T = withQuotes { // (using Quotes) =>
26+
* val e: T = withQuotes { // (quotes: Quotes) ?=>
2727
* thunk
2828
* }
2929
* ```

tests/disabled/run/tupled-function-extension-method.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ object Test {
1717
println(f3(1, 2, 3))
1818
println(f25(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25))
1919

20-
val if1 = new Expr((using i: Int) => Tuple1(i))
21-
val if2 = new Expr((using i: Int, j: Int) => (i, i + j))
22-
val if3 = new Expr((using i: Int, j: Int, k: Int) => (i, i + j, i + j + k))
20+
val if1 = new Expr((i: Int) ?=> Tuple1(i))
21+
val if2 = new Expr((i: Int, j: Int) ?=> (i, i + j))
22+
val if3 = new Expr((i: Int, j: Int, k: Int) ?=> (i, i + j, i + j + k))
2323
val if25 = new Expr(
24-
(using x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int, x25: Int) =>
24+
(x1: Int, x2: Int, x3: Int, x4: Int, x5: Int, x6: Int, x7: Int, x8: Int, x9: Int, x10: Int, x11: Int, x12: Int, x13: Int, x14: Int, x15: Int, x16: Int, x17: Int, x18: Int, x19: Int, x20: Int, x21: Int, x22: Int, x23: Int, x24: Int, x25: Int) ?=>
2525
(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25)
2626
)
2727

tests/neg/i2006.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ object Test {
44
inline def bar(f: Int ?=> Int) = f // error
55

66
def main(args: Array[String]) = {
7-
foo((using thisTransaction) => 43)
8-
bar((using thisTransaction) => 44)
7+
foo(thisTransaction ?=> 43)
8+
bar(thisTransaction ?=> 44)
99
}
1010
}

tests/neg/i2146.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class Test {
2-
def foo[A, B]: A ?=> B ?=> Int = { (using b: B) => // error: found Int, required: A ?=> B ?=> Int
2+
def foo[A, B]: A ?=> B ?=> Int = { (b: B) ?=> // error: found Int, required: A ?=> B ?=> Int
33
42
44
}
55
}

tests/neg/i2514a.scala

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

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

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

tests/neg/i4668.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ trait Functor[F[_]] { def map[A,B](x: F[A])(f: A => B): F[B] }
88
object Functor { implicit object listFun extends Functor[List] { def map[A,B](ls: List[A])(f: A => B) = ls.map(f) } }
99

1010
val map: (A:Type,B:Type,F:Type1) ?=> (Functor[F.T]) ?=> (F.T[A.T]) => (A.T => B.T) => F.T[B.T] =
11-
(using fun) => (using x) => f => fun.map(x)(f) // error
11+
fun ?=> x => f => fun.map(x)(f) // error

tests/neg/scoped-quoted-expr-proto.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ package b {
6969
}
7070
}
7171

72-
r { (using qctx) =>
72+
r { qctx ?=>
7373
var escaped: qctx.Expr[Double] = ???
7474
q{ (x: Double) =>
7575
s{
@@ -127,7 +127,7 @@ package c {
127127
}
128128
}
129129

130-
r { (using qctx) =>
130+
r { qctx ?=>
131131
var escaped: qctx.Expr[Double] = ???
132132
q{ (x: Double) =>
133133
s{

tests/pos/case-getters.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
case class Foo(x: 1, y: Int ?=> Int)
22
object Test {
3-
val f = Foo(1, (using i: Int) => i)
3+
val f = Foo(1, (i: Int) ?=> i)
44
val fx1: 1 = f.x
55
val fx2: 1 = f._1
66
val fy1: Int = f.y(using 1)

tests/pos/i5966.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
object Test {
2-
def foo = (using v: Int) => (x: Int) => v + x
2+
def foo = (v: Int) ?=> (x: Int) => v + x
33
given myInt as Int = 4
44

55
foo.apply(1)

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 = (using x: Ctx) => ()
2+
inline def foo(): Unit = (x: Ctx) ?=> ()
33
def bar[T](b: Ctx ?=> Unit): Unit = ???

tests/pos/i6863/lib_1.scala

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

tests/pos/ift-assign.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class Context
22

33
object Test {
4-
var f: Context ?=> String = ((using _) => "")
4+
var f: Context ?=> String = (_ ?=> "")
55

66
f = f
77

tests/pos/inline-apply.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ object Test {
55
def transform()(implicit ctx: Context) = {
66
inline def withLocalOwner[T](op: Context ?=> T) = op(using ctx)
77

8-
withLocalOwner { (using ctx) => }
8+
withLocalOwner { ctx ?=> }
99

1010
}
1111
}

tests/pos/reference/delegates.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,12 @@ object Instances extends Common:
7878
println(minimum(xs))
7979

8080
case class Context(value: String)
81-
val c0: Context ?=> String = (using ctx) => ctx.value
82-
val c1: Context ?=> String = (using ctx: Context) => ctx.value
81+
val c0: Context ?=> String = ctx ?=> ctx.value
82+
val c1: Context ?=> String = (ctx: Context) ?=> ctx.value
8383

8484
class A
8585
class B
86-
val ab: (x: A, y: B) ?=> Int = (using a: A, b: B) => 22
86+
val ab: (x: A, y: B) ?=> Int = (a: A, b: B) ?=> 22
8787

8888
trait TastyAPI:
8989
type Symbol

0 commit comments

Comments
 (0)