Skip to content

Commit 262d5f9

Browse files
committed
Change syntax of implicit function types and closures
It's `given A => B` instead of `A |=> B`.
1 parent 3a28833 commit 262d5f9

Some content is hidden

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

61 files changed

+210
-214
lines changed

compiler/src/dotty/tools/dotc/ast/untpd.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
132132

133133
case class Implicit()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.ImplicitCommon)
134134

135+
case class Given()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.ImplicitCommon | Flags.Contextual)
136+
135137
case class Erased()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Erased)
136138

137139
case class Final()(implicit @constructorOnly src: SourceFile) extends Mod(Flags.Final)

compiler/src/dotty/tools/dotc/core/Definitions.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class Definitions {
100100
* ImplicitFunctionN traits follow this template:
101101
*
102102
* trait ImplicitFunctionN[T0,...,T{N-1}, R] extends Object {
103-
* def apply with ($x0: T0, ..., $x{N_1}: T{N-1}): R
103+
* def apply given ($x0: T0, ..., $x{N_1}: T{N-1}): R
104104
* }
105105
*
106106
* ErasedFunctionN traits follow this template:
@@ -112,7 +112,7 @@ class Definitions {
112112
* ErasedImplicitFunctionN traits follow this template:
113113
*
114114
* trait ErasedImplicitFunctionN[T0,...,T{N-1}, R] extends Object {
115-
* def apply with (erased $x0: T0, ..., $x{N_1}: T{N-1}): R
115+
* def apply given (erased $x0: T0, ..., $x{N_1}: T{N-1}): R
116116
* }
117117
*
118118
* ErasedFunctionN and ErasedImplicitFunctionN erase to Function0.

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

Lines changed: 34 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -364,22 +364,22 @@ object Parsers {
364364

365365
/** Convert tree to formal parameter list
366366
*/
367-
def convertToParams(tree: Tree, mods: Modifiers): List[ValDef] = tree match {
368-
case Parens(t) => convertToParam(t, mods) :: Nil
369-
case Tuple(ts) => ts map (convertToParam(_, mods))
370-
case t => convertToParam(t, mods) :: Nil
367+
def convertToParams(tree: Tree): List[ValDef] = tree match {
368+
case Parens(t) => convertToParam(t) :: Nil
369+
case Tuple(ts) => ts map (convertToParam(_))
370+
case t => convertToParam(t) :: Nil
371371
}
372372

373373
/** Convert tree to formal parameter
374374
*/
375-
def convertToParam(tree: Tree, mods: Modifiers, expected: String = "formal parameter"): ValDef = tree match {
375+
def convertToParam(tree: Tree, expected: String = "formal parameter"): ValDef = tree match {
376376
case Ident(name) =>
377-
makeParameter(name.asTermName, TypeTree(), mods).withSpan(tree.span)
377+
makeParameter(name.asTermName, TypeTree()).withSpan(tree.span)
378378
case Typed(Ident(name), tpt) =>
379-
makeParameter(name.asTermName, tpt, mods).withSpan(tree.span)
379+
makeParameter(name.asTermName, tpt).withSpan(tree.span)
380380
case _ =>
381381
syntaxError(s"not a legal $expected", tree.span)
382-
makeParameter(nme.ERROR, tree, mods)
382+
makeParameter(nme.ERROR, tree)
383383
}
384384

385385
/** Convert (qual)ident to type identifier
@@ -770,7 +770,7 @@ object Parsers {
770770
*/
771771
def toplevelTyp(): Tree = checkWildcard(typ())
772772

773-
/** Type ::= [‘erased’] FunArgTypes (‘=>’ | ‘|=>’) Type
773+
/** Type ::= FunTypeMods FunArgTypes `=>' Type
774774
* | HkTypeParamClause `->' Type
775775
* | InfixType
776776
* FunArgTypes ::= InfixType
@@ -779,20 +779,11 @@ object Parsers {
779779
*/
780780
def typ(): Tree = {
781781
val start = in.offset
782-
val imods = modifiers(BitSet(ERASED))
782+
val imods = modifiers(funTypeMods)
783783
def functionRest(params: List[Tree]): Tree =
784-
atSpan(start, in.offset) {
785-
val pmods =
786-
if (in.token == CARROW) {
787-
in.nextToken()
788-
imods | (Contextual | Implicit)
789-
}
790-
else {
791-
accept(ARROW)
792-
imods
793-
}
784+
atSpan(start, accept(ARROW)) {
794785
val t = typ()
795-
if (pmods.flags.is(Implicit | Contextual | Erased)) new FunctionWithMods(params, t, pmods)
786+
if (imods.is(Implicit | Contextual | Erased)) new FunctionWithMods(params, t, imods)
796787
else Function(params, t)
797788
}
798789
def funArgTypesRest(first: Tree, following: () => Tree) = {
@@ -826,7 +817,7 @@ object Parsers {
826817
}
827818
openParens.change(LPAREN, -1)
828819
accept(RPAREN)
829-
if (imods.is(Implicit) || isValParamList || in.token == ARROW || in.token == CARROW)
820+
if (imods.is(Implicit) || isValParamList || in.token == ARROW)
830821
functionRest(ts)
831822
else {
832823
val ts1 =
@@ -858,7 +849,7 @@ object Parsers {
858849
else infixType()
859850

860851
in.token match {
861-
case ARROW | CARROW => functionRest(t :: Nil)
852+
case ARROW => functionRest(t :: Nil)
862853
case MATCH => matchType(EmptyTree, t)
863854
case FORSOME => syntaxError(ExistentialTypesNoLongerSupported()); t
864855
case _ =>
@@ -1134,15 +1125,14 @@ object Parsers {
11341125
}
11351126
}
11361127

1137-
/** Expr ::= [FunArgMods] FunParams =>' Expr
1138-
* | [‘erased’] FunParams ‘|=>’ Expr
1128+
/** Expr ::= [ClosureMods] FunParams =>' Expr
11391129
* | Expr1
11401130
* FunParams ::= Bindings
11411131
* | id
11421132
* | `_'
11431133
* ExprInParens ::= PostfixExpr `:' Type
11441134
* | Expr
1145-
* BlockResult ::= [FunArgMods] FunParams =>' Block
1135+
* BlockResult ::= [ClosureMods] FunParams =>' Block
11461136
* | Expr1
11471137
* Expr1 ::= [‘inline’] `if' `(' Expr `)' {nl} Expr [[semi] else Expr]
11481138
* | [‘inline’] `if' Expr `then' Expr [[semi] else Expr]
@@ -1171,8 +1161,8 @@ object Parsers {
11711161

11721162
def expr(location: Location.Value): Tree = {
11731163
val start = in.offset
1174-
if (in.token == IMPLICIT || in.token == ERASED) {
1175-
val imods = modifiers(funArgMods)
1164+
if (in.token == IMPLICIT || in.token == ERASED || in.token == GIVEN) {
1165+
val imods = modifiers(closureMods)
11761166
if (in.token == MATCH) implicitMatch(start, imods)
11771167
else implicitClosure(start, location, imods)
11781168
} else {
@@ -1185,11 +1175,9 @@ object Parsers {
11851175
finally placeholderParams = saved
11861176

11871177
val t = expr1(location)
1188-
if (in.token == ARROW || in.token == CARROW) {
1178+
if (in.token == ARROW) {
11891179
placeholderParams = Nil // don't interpret `_' to the left of `=>` as placeholder
1190-
val impliedMods =
1191-
if (in.token == CARROW) Modifiers(Implicit | Contextual) else EmptyModifiers
1192-
wrapPlaceholders(closureRest(start, location, convertToParams(t, impliedMods)))
1180+
wrapPlaceholders(closureRest(start, location, convertToParams(t)))
11931181
}
11941182
else if (isWildcard(t)) {
11951183
placeholderParams = placeholderParams ::: saved
@@ -1407,28 +1395,16 @@ object Parsers {
14071395
}
14081396
else ident()
14091397

1410-
/** Expr ::= FunArgMods FunParams `=>' Expr
1411-
* | [‘erased’] FunParams ‘|=>’ Expr
1398+
/** Expr ::= ClosureMods FunParams `=>' Expr
14121399
* BlockResult ::= implicit id [`:' InfixType] `=>' Block // Scala2 only
14131400
*/
14141401
def implicitClosure(start: Int, location: Location.Value, implicitMods: Modifiers): Tree =
14151402
closureRest(start, location, funParams(implicitMods, location))
14161403

14171404
def closureRest(start: Int, location: Location.Value, params: List[Tree]): Tree =
14181405
atSpan(start, in.offset) {
1419-
val params1 =
1420-
if (in.token == CARROW) {
1421-
in.nextToken()
1422-
params.map {
1423-
case param: ValDef => param.withMods(param.mods | (Implicit | Contextual))
1424-
case param => param
1425-
}
1426-
}
1427-
else {
1428-
accept(ARROW)
1429-
params
1430-
}
1431-
Function(params1, if (location == Location.InBlock) block() else expr())
1406+
accept(ARROW)
1407+
Function(params, if (location == Location.InBlock) block() else expr())
14321408
}
14331409

14341410
/** PostfixExpr ::= InfixExpr [id [nl]]
@@ -1853,6 +1829,7 @@ object Parsers {
18531829
case ABSTRACT => Mod.Abstract()
18541830
case FINAL => Mod.Final()
18551831
case IMPLICIT => Mod.Implicit()
1832+
case GIVEN => Mod.Given()
18561833
case ERASED => Mod.Erased()
18571834
case LAZY => Mod.Lazy()
18581835
case OVERRIDE => Mod.Override()
@@ -1949,9 +1926,13 @@ object Parsers {
19491926
normalize(loop(start))
19501927
}
19511928

1952-
/** FunArgMods ::= { `implicit` | `erased` }
1929+
/** FunArgMods ::= { `implicit` | `erased` }
1930+
* ClosureMods ::= { ‘implicit’ | ‘erased’ | ‘given’}
1931+
* FunTypeMods ::= { ‘erased’ | ‘given’}
19531932
*/
1954-
def funArgMods: BitSet = BitSet(IMPLICIT, ERASED)
1933+
val funArgMods: BitSet = BitSet(IMPLICIT, ERASED)
1934+
val closureMods: BitSet = BitSet(GIVEN, IMPLICIT, ERASED)
1935+
val funTypeMods: BitSet = BitSet(GIVEN, ERASED)
19551936

19561937
/** Wrap annotation or constructor in New(...).<init> */
19571938
def wrapNew(tpt: Tree): Select = Select(New(tpt), nme.CONSTRUCTOR)
@@ -2748,7 +2729,7 @@ object Parsers {
27482729
case Typed(tree @ This(EmptyTypeIdent), tpt) =>
27492730
self = makeSelfDef(nme.WILDCARD, tpt).withSpan(first.span)
27502731
case _ =>
2751-
val ValDef(name, tpt, _) = convertToParam(first, EmptyModifiers, "self type clause")
2732+
val ValDef(name, tpt, _) = convertToParam(first, "self type clause")
27522733
if (name != nme.ERROR)
27532734
self = makeSelfDef(name, tpt).withSpan(first.span)
27542735
}
@@ -2837,10 +2818,10 @@ object Parsers {
28372818
stats ++= importClause()
28382819
else if (isExprIntro)
28392820
stats += expr(Location.InBlock)
2840-
else if (isDefIntro(localModifierTokens))
2841-
if (in.token == IMPLICIT || in.token == ERASED) {
2821+
else if (isDefIntro(localModifierTokens) || in.token == GIVEN) // !!!!
2822+
if (in.token == IMPLICIT || in.token == ERASED || in.token == GIVEN) {
28422823
val start = in.offset
2843-
var imods = modifiers(funArgMods)
2824+
var imods = modifiers(closureMods)
28442825
if (isBindingIntro)
28452826
stats += implicitClosure(start, Location.InBlock, imods)
28462827
else if (in.token == MATCH)

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

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,7 @@ abstract class TokensCommon {
112112
//final val SUPERTYPE = 81; enter(SUPERTYPE, ">:")
113113
//final val HASH = 82; enter(HASH, "#")
114114
final val AT = 83; enter(AT, "@")
115-
//final val CARROW = 84;
116-
//final val VIEWBOUND = 85; enter(VIEWBOUND, "<%") // TODO: deprecate
115+
//final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") // TODO: deprecate
117116

118117
val keywords: TokenSet
119118

@@ -193,11 +192,10 @@ object Tokens extends TokensCommon {
193192
final val SUBTYPE = 80; enter(SUBTYPE, "<:")
194193
final val SUPERTYPE = 81; enter(SUPERTYPE, ">:")
195194
final val HASH = 82; enter(HASH, "#")
196-
final val CARROW = 84; enter(CARROW, "|=>")
197-
final val VIEWBOUND = 85; enter(VIEWBOUND, "<%") // TODO: deprecate
198-
final val QPAREN = 86; enter(QPAREN, "'(")
199-
final val QBRACE = 87; enter(QBRACE, "'{")
200-
final val QBRACKET = 88; enter(QBRACKET, "'[")
195+
final val VIEWBOUND = 84; enter(VIEWBOUND, "<%") // TODO: deprecate
196+
final val QPAREN = 85; enter(QPAREN, "'(")
197+
final val QBRACE = 86; enter(QBRACE, "'{")
198+
final val QBRACKET = 87; enter(QBRACKET, "'[")
201199

202200
/** XML mode */
203201
final val XMLSTART = 96; enter(XMLSTART, "$XMLSTART$<") // TODO: deprecate

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,25 +125,25 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
125125
else simpleNameString(tsym)
126126
}
127127

128-
protected def arrowText(contextual: Boolean): Text = if (contextual) " |=> " else " => "
129-
130128
override def toText(tp: Type): Text = controlled {
131129
def toTextTuple(args: List[Type]): Text =
132130
"(" ~ argsText(args) ~ ")"
133131

134-
def toTextFunction(args: List[Type], contextual: Boolean, isErased: Boolean): Text =
132+
def toTextFunction(args: List[Type], isContextual: Boolean, isErased: Boolean): Text =
135133
changePrec(GlobalPrec) {
136134
val argStr: Text =
137135
if (args.length == 2 && !defn.isTupleType(args.head))
138136
atPrec(InfixPrec) { argText(args.head) }
139137
else
140138
toTextTuple(args.init)
141139
(keywordText("erased ") provided isErased) ~
142-
argStr ~ arrowText(contextual) ~ argText(args.last)
140+
(keywordText("given ") provided isContextual) ~
141+
argStr ~ " => " ~ argText(args.last)
143142
}
144143

145-
def toTextDependentFunction(appType: MethodType): Text =
146-
"(" ~ paramsText(appType) ~ ")" ~ arrowText(appType.isContextual) ~ toText(appType.resultType)
144+
def toTextDependentFunction(appType: MethodType): Text = // !!!!
145+
(keywordText("given ") provided appType.isImplicitMethod) ~
146+
"(" ~ paramsText(appType) ~ ") => " ~ toText(appType.resultType)
147147

148148
def isInfixType(tp: Type): Boolean = tp match {
149149
case AppliedType(tycon, args) =>
@@ -530,7 +530,10 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
530530
case (arg @ ValDef(_, tpt, _)) :: Nil if tpt.isEmpty => argToText(arg)
531531
case _ => "(" ~ Text(args map argToText, ", ") ~ ")"
532532
}
533-
changePrec(GlobalPrec) { argsText ~ arrowText(contextual) ~ toText(body) }
533+
changePrec(GlobalPrec) {
534+
(keywordText("given ") provided contextual) ~
535+
argsText ~ " => " ~ toText(body)
536+
}
534537
case InfixOp(l, op, r) =>
535538
val opPrec = parsing.precedence(op.name)
536539
changePrec(opPrec) { toText(l) ~ " " ~ toText(op) ~ " " ~ toText(r) }

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,10 @@ object EtaExpansion extends LiftImpure {
178178
* { val xs = es; (x1: T1, ..., xn: Tn) => expr(x1, ..., xn) _ }
179179
*
180180
* where `T1, ..., Tn` are the paremeter types of the expanded method.
181-
* If `expr` has a contectual function type, the arguments are passed with `with`.
181+
* If `expr` has implicit function type, the arguments are passed with `given`.
182182
* E.g. for (1):
183183
*
184-
* { val xs = es; (x1, ..., xn) => expr with (x1, ..., xn) }
184+
* { val xs = es; (x1, ..., xn) => expr given (x1, ..., xn) }
185185
*
186186
* Case (3) applies if the method is curried, i.e. its result type is again a method
187187
* type. Case (2) applies if the expected arity of the function type `xarity` differs

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2536,8 +2536,9 @@ class Typer extends Namer
25362536
ctx.warning(ex"${tree.symbol} is eta-expanded even though $pt does not have the @FunctionalInterface annotation.", tree.sourcePos)
25372537
case _ =>
25382538
}
2539-
simplify(typed(etaExpand(tree, wtp, arity), pt), pt, locked)
2540-
} else if (wtp.paramInfos.isEmpty && isAutoApplied(tree.symbol))
2539+
simplify(typed(etaExpand(tree, wtp, arity), pt), pt, locked)
2540+
}
2541+
else if (wtp.paramInfos.isEmpty && isAutoApplied(tree.symbol))
25412542
readaptSimplified(tpd.Apply(tree, Nil))
25422543
else if (wtp.isImplicitMethod)
25432544
err.typeMismatch(tree, pt)

docs/docs/internals/syntax.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,10 @@ ClassQualifier ::= ‘[’ id ‘]’
137137

138138
### Types
139139
```ebnf
140-
Type ::= [‘erased’] FunArgTypes (‘=>’ | ‘|=>’) Type Function(ts, t)
140+
Type ::= { ‘erased’ | ‘given’} FunArgTypes ‘=>’ Type Function(ts, t)
141141
| HkTypeParamClause ‘=>’ Type TypeLambda(ps, t)
142142
| MatchType
143143
| InfixType
144-
FunArgMods ::= { ‘implicit’ | ‘erased’ }
145144
FunArgTypes ::= InfixType
146145
| ‘(’ [ FunArgType {‘,’ FunArgType } ] ‘)’
147146
| ‘(’ TypedFunParam {‘,’ TypedFunParam } ‘)’
@@ -176,10 +175,9 @@ TypeParamBounds ::= TypeBounds {‘<%’ Type} {‘:’ Type}
176175

177176
### Expressions
178177
```ebnf
179-
Expr ::= [FunArgMods] FunParams ‘=>’ Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr)
180-
| [‘erased’] FunParams ‘|=>’ Expr
178+
Expr ::= [ClosureMods] FunParams ‘=>’ Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr)
181179
| Expr1
182-
BlockResult ::= [FunArgMods] FunParams ‘=>’ Block
180+
BlockResult ::= [ClosureMods] FunParams ‘=>’ Block
183181
| Expr1
184182
FunParams ::= Bindings
185183
| id
@@ -304,6 +302,8 @@ InstParamClause ::= ‘given’ (‘(’ [DefParams] ‘)’ | ContextTypes)
304302
DefParams ::= DefParam {‘,’ DefParam}
305303
DefParam ::= {Annotation} [‘inline’] Param ValDef(mods, id, tpe, expr) -- point of mods at id.
306304
ContextTypes ::= RefinedType {‘,’ RefinedType}
305+
FunArgMods ::= { ‘implicit’ | ‘erased’ }
306+
ClosureMods ::= { ‘implicit’ | ‘erased’ | ‘given’}
307307
```
308308

309309
### Bindings and Imports

0 commit comments

Comments
 (0)