Skip to content

Commit 3933284

Browse files
committed
Implement new syntax for implicit closures
1 parent 23ca102 commit 3933284

File tree

4 files changed

+53
-28
lines changed

4 files changed

+53
-28
lines changed

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

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,16 +1247,16 @@ object Parsers {
12471247
* | HkTypeParamClause ‘=>>’ Type
12481248
* | MatchType
12491249
* | InfixType
1250-
* FunType ::= { 'erased' | 'given' } (MonoFunType | PolyFunType)
1250+
* FunType ::= (MonoFunType | PolyFunType)
12511251
* MonoFunType ::= FunArgTypes ‘=>’ Type
12521252
* PolyFunType ::= HKTypeParamClause '=>' Type
12531253
* FunArgTypes ::= InfixType
1254-
* | `(' [ FunArgType {`,' FunArgType } ] `)'
1255-
* | '(' TypedFunParam {',' TypedFunParam } ')'
1254+
* | `(' [ [ ‘[given]’ ‘['erased'] FunArgType {`,' FunArgType } ] `)'
1255+
* | '(' [ ‘[given]’ ‘['erased'] TypedFunParam {',' TypedFunParam } ')'
12561256
*/
12571257
def typ(): Tree = {
12581258
val start = in.offset
1259-
val imods = modifiers(funTypeMods)
1259+
var imods = Modifiers()
12601260
def functionRest(params: List[Tree]): Tree =
12611261
atSpan(start, accept(ARROW)) {
12621262
val t = typ()
@@ -1282,6 +1282,7 @@ object Parsers {
12821282
}
12831283
else {
12841284
openParens.change(LPAREN, 1)
1285+
imods = modifiers(funTypeArgMods)
12851286
val paramStart = in.offset
12861287
val ts = funArgType() match {
12871288
case Ident(name) if name != tpnme.WILDCARD && in.token == COLON =>
@@ -1683,8 +1684,10 @@ object Parsers {
16831684

16841685
def expr(location: Location.Value): Tree = {
16851686
val start = in.offset
1686-
if (closureMods.contains(in.token))
1687+
if closureMods.contains(in.token) && allowOldGiven then
16871688
implicitClosure(start, location, modifiers(closureMods))
1689+
else if in.token == LPAREN && in.lookaheadIn(funTypeArgMods) then
1690+
implicitClosure(start, location, modifiers())
16881691
else {
16891692
val saved = placeholderParams
16901693
placeholderParams = Nil
@@ -1896,11 +1899,20 @@ object Parsers {
18961899
/** FunParams ::= Bindings
18971900
* | id
18981901
* | `_'
1899-
* Bindings ::= `(' [Binding {`,' Binding}] `)'
1902+
* Bindings ::= `(' [[‘given’] [‘erased’] Binding {`,' Binding}] `)'
19001903
*/
19011904
def funParams(mods: Modifiers, location: Location.Value): List[Tree] =
1902-
if (in.token == LPAREN)
1903-
inParens(if (in.token == RPAREN) Nil else commaSeparated(() => binding(mods)))
1905+
if in.token == LPAREN then
1906+
in.nextToken()
1907+
if in.token == RPAREN then
1908+
Nil
1909+
else
1910+
openParens.change(LPAREN, 1)
1911+
val mods1 = if mods.flags.isEmpty then modifiers(funTypeArgMods) else mods
1912+
try commaSeparated(() => binding(mods1))
1913+
finally
1914+
accept(RPAREN)
1915+
openParens.change(LPAREN, -1)
19041916
else {
19051917
val start = in.offset
19061918
val name = bindingName()
@@ -2591,11 +2603,11 @@ object Parsers {
25912603
*/
25922604
val closureMods: BitSet =
25932605
if allowOldGiven then BitSet(GIVEN, IMPLIED, IMPLICIT, ERASED)
2594-
else BitSet(IMPLICIT)
2606+
else BitSet(IMPLICIT, ERASED)
2607+
2608+
val funTypeMods: BitSet = BitSet(IMPLIED, ERASED)
25952609

2596-
val funTypeMods: BitSet =
2597-
if allowOldGiven then BitSet(IMPLIED, ERASED)
2598-
else BitSet()
2610+
val funTypeArgMods: BitSet = BitSet(GIVEN, ERASED)
25992611

26002612
/** Wrap annotation or constructor in New(...).<init> */
26012613
def wrapNew(tpt: Tree): Select = Select(New(tpt), nme.CONSTRUCTOR)

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,19 +138,27 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
138138
def toTextFunction(args: List[Type], isContextual: Boolean, isErased: Boolean): Text =
139139
changePrec(GlobalPrec) {
140140
val argStr: Text =
141-
if (args.length == 2 && !defn.isTupleType(args.head))
141+
if args.length == 2
142+
&& !defn.isTupleType(args.head)
143+
&& !isContextual && !isErased
144+
then
142145
atPrec(InfixPrec) { argText(args.head) }
143146
else
144-
toTextTuple(args.init)
145-
(keywordText("given ") provided isContextual) ~
146-
(keywordText("erased ") provided isErased) ~
147+
"("
148+
~ (keywordText("given ") provided isContextual)
149+
~ (keywordText("erased ") provided isErased)
150+
~ argsText(args.init)
151+
~ ")"
147152
argStr ~ " => " ~ argText(args.last)
148153
}
149154

150155
def toTextDependentFunction(appType: MethodType): Text =
151-
(keywordText("given ") provided appType.isImplicitMethod) ~
152-
(keywordText("erased ") provided appType.isErasedMethod) ~
153-
"(" ~ paramsText(appType) ~ ") => " ~ toText(appType.resultType)
156+
"("
157+
~ (keywordText("given ") provided appType.isImplicitMethod)
158+
~ (keywordText("erased ") provided appType.isErasedMethod)
159+
~ paramsText(appType)
160+
~ ") => "
161+
~ toText(appType.resultType)
154162

155163
def isInfixType(tp: Type): Boolean = tp match {
156164
case AppliedType(tycon, args) =>
@@ -238,7 +246,13 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
238246
case dummyTreeOfType(tp) :: Nil if !(tp isRef defn.NullClass) => "null: " ~ toText(tp)
239247
case _ => toTextGlobal(args, ", ")
240248
}
241-
"[applied to " ~ (Str("given ") provided tp.isContextualMethod) ~ (Str("erased ") provided tp.isErasedMethod) ~ "(" ~ argsText ~ ") returning " ~ toText(resultType) ~ "]"
249+
"[applied to ("
250+
~ (Str("given ") provided tp.isContextualMethod)
251+
~ (Str("erased ") provided tp.isErasedMethod)
252+
~ argsText
253+
~ ") returning "
254+
~ toText(resultType)
255+
~ "]"
242256
case IgnoredProto(ignored) =>
243257
"?" ~ (("(ignored: " ~ toText(ignored) ~ ")") provided printDebug)
244258
case tp @ PolyProto(targs, resType) =>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,9 @@ object PrepareInlineable {
259259
case Block(DefDef(nme.ANON_FUN, _, _, _, _) :: Nil, Closure(_, fn, _)) if fn.symbol.info.isImplicitMethod =>
260260
// TODO Support this pattern
261261
ctx.error(
262-
"""Macros using a return type of the form `foo(): given X => Y` are not yet supported.
262+
"""Macros using a return type of the form `foo(): (given X) => Y` are not yet supported.
263263
|
264-
|Place the implicit as an argument (`foo() given X: Y`) to overcome this limitation.
264+
|Place the implicit as an argument (`foo()(given X): Y`) to overcome this limitation.
265265
|""".stripMargin, tree.sourcePos)
266266
case _ =>
267267
ctx.error(

docs/docs/internals/syntax.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,11 @@ Type ::= FunType
144144
| HkTypeParamClause ‘=>>’ Type TypeLambda(ps, t)
145145
| MatchType
146146
| InfixType
147-
FunType ::= ['given'] (MonoFunType | PolyFunType)
148-
MonoFunType ::= FunArgTypes ‘=>’ Type Function(ts, t)
149-
PolyFunType :: = HKTypeParamClause '=>' Type PolyFunction(ps, t)
147+
FunType ::= FunArgTypes ‘=>’ Type Function(ts, t)
148+
| HKTypeParamClause '=>' Type PolyFunction(ps, t)
150149
FunArgTypes ::= InfixType
151-
| ‘(’ [ FunArgType {‘,’ FunArgType } ] ‘)’
152-
| ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’
150+
| ‘(’ [ ‘[given]’ FunArgType {‘,’ FunArgType } ] ‘)’
151+
| ‘(’ ‘[given]’ TypedFunParam {‘,’ TypedFunParam } ‘)’
153152
TypedFunParam ::= id ‘:’ Type
154153
MatchType ::= InfixType `match` TypeCaseClauses
155154
InfixType ::= RefinedType {id [cnl] RefinedType} InfixOp(t1, op, t2)
@@ -318,7 +317,7 @@ ClosureMods ::= { ‘implicit’ | ‘given’}
318317

319318
### Bindings and Imports
320319
```ebnf
321-
Bindings ::= ‘(’ Binding {‘,’ Binding} ‘)’
320+
Bindings ::= ‘(’ [[‘given’] Binding {‘,’ Binding}] ‘)’
322321
Binding ::= (id | ‘_’) [‘:’ Type] ValDef(_, id, tpe, EmptyTree)
323322
324323
Modifier ::= LocalModifier

0 commit comments

Comments
 (0)