Skip to content

Commit f9e0918

Browse files
committed
Generalize syntax for implicit function values
- allow more than one implicit binding - harmonize syntax in expressions and blocks
1 parent 7c31ad1 commit f9e0918

File tree

3 files changed

+81
-50
lines changed

3 files changed

+81
-50
lines changed

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

Lines changed: 74 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ object Parsers {
146146
def isNumericLit = numericLitTokens contains in.token
147147
def isModifier = modifierTokens contains in.token
148148
def isExprIntro = canStartExpressionTokens contains in.token
149+
def isBindingIntro = canStartBindingTokens contains in.token
149150
def isTemplateIntro = templateIntroTokens contains in.token
150151
def isDclIntro = dclIntroTokens contains in.token
151152
def isStatSeqEnd = in.token == RBRACE || in.token == EOF
@@ -947,14 +948,14 @@ object Parsers {
947948
}
948949
}
949950

950-
/** Expr ::= FunParams `=>' Expr
951+
/** Expr ::= [`implicit'] FunParams `=>' Expr
951952
* | Expr1
952953
* FunParams ::= Bindings
953-
* | [`implicit'] Id
954+
* | Id
954955
* | `_'
955956
* ExprInParens ::= PostfixExpr `:' Type
956957
* | Expr
957-
* BlockResult ::= (FunParams | [`implicit'] Id `:' InfixType) => Block
958+
* BlockResult ::= [`implicit'] FunParams `=>' Block
958959
* | Expr1
959960
* Expr1 ::= `if' `(' Expr `)' {nl} Expr [[semi] else Expr]
960961
* | `if' Expr `then' Expr [[semi] else Expr]
@@ -981,22 +982,27 @@ object Parsers {
981982
def expr(): Tree = expr(Location.ElseWhere)
982983

983984
def expr(location: Location.Value): Tree = {
984-
val saved = placeholderParams
985-
placeholderParams = Nil
986-
val t = expr1(location)
987-
if (in.token == ARROW) {
988-
placeholderParams = saved
989-
closureRest(startOffset(t), location, convertToParams(t))
990-
}
991-
else if (isWildcard(t)) {
992-
placeholderParams = placeholderParams ::: saved
993-
t
985+
val start = in.offset
986+
if (in.token == IMPLICIT)
987+
implicitClosure(start, location, implicitMods())
988+
else {
989+
val saved = placeholderParams
990+
placeholderParams = Nil
991+
val t = expr1(location)
992+
if (in.token == ARROW) {
993+
placeholderParams = saved
994+
closureRest(start, location, convertToParams(t))
995+
}
996+
else if (isWildcard(t)) {
997+
placeholderParams = placeholderParams ::: saved
998+
t
999+
}
1000+
else
1001+
try
1002+
if (placeholderParams.isEmpty) t
1003+
else new WildcardFunction(placeholderParams.reverse, t)
1004+
finally placeholderParams = saved
9941005
}
995-
else
996-
try
997-
if (placeholderParams.isEmpty) t
998-
else new WildcardFunction(placeholderParams.reverse, t)
999-
finally placeholderParams = saved
10001006
}
10011007

10021008
def expr1(location: Location.Value = Location.ElseWhere): Tree = in.token match {
@@ -1062,8 +1068,6 @@ object Parsers {
10621068
atPos(in.skipToken()) { Return(if (isExprIntro) expr() else EmptyTree, EmptyTree) }
10631069
case FOR =>
10641070
forExpr()
1065-
case IMPLICIT =>
1066-
implicitClosure(in.offset, location, atPos(in.skipToken()) { Mod.Implicit() })
10671071
case _ =>
10681072
expr1Rest(postfixExpr(), location)
10691073
}
@@ -1111,19 +1115,43 @@ object Parsers {
11111115
}
11121116
}
11131117

1118+
/** FunParams ::= Bindings
1119+
* | Id
1120+
* | `_'
1121+
* Bindings ::= `(' [Binding {`,' Binding}] `)'
1122+
*/
1123+
def funParams(mods: Modifiers, location: Location.Value): List[Tree] =
1124+
if (in.token == LPAREN)
1125+
inParens(if (in.token == RPAREN) Nil else commaSeparated(() => binding(mods)))
1126+
else {
1127+
val start = in.offset
1128+
val name = bindingName()
1129+
val t =
1130+
if (in.token == COLON && location == Location.InBlock) {
1131+
in.nextToken()
1132+
infixType()
1133+
}
1134+
else TypeTree()
1135+
(atPos(start) { makeParameter(name, t, mods) }) :: Nil
1136+
}
1137+
1138+
/** Binding ::= (Id | `_') [`:' Type]
1139+
*/
1140+
def binding(mods: Modifiers): Tree =
1141+
atPos(in.offset) { makeParameter(bindingName(), typedOpt(), mods) }
1142+
1143+
def bindingName(): TermName =
1144+
if (in.token == USCORE) {
1145+
in.nextToken()
1146+
ctx.freshName(nme.USCORE_PARAM_PREFIX).toTermName
1147+
}
1148+
else ident()
1149+
11141150
/** Expr ::= implicit Id `=>' Expr
1115-
* BlockResult ::= implicit Id [`:' InfixType] `=>' Block
1116-
*/
1117-
def implicitClosure(start: Int, location: Location.Value, implicitMod: Mod): Tree = {
1118-
val mods = Modifiers(Implicit).withAddedMod(implicitMod)
1119-
val id = termIdent()
1120-
val paramExpr =
1121-
if (location == Location.InBlock && in.token == COLON)
1122-
atPos(startOffset(id), in.skipToken()) { Typed(id, infixType()) }
1123-
else
1124-
id
1125-
closureRest(start, location, convertToParam(paramExpr, mods) :: Nil)
1126-
}
1151+
* BlockResult ::= implicit Id [`:' InfixType] `=>' Block // Scala2 only
1152+
*/
1153+
def implicitClosure(start: Int, location: Location.Value, implicitMods: Modifiers): Tree =
1154+
closureRest(start, location, funParams(implicitMods, location))
11271155

11281156
def closureRest(start: Int, location: Location.Value, params: List[Tree]): Tree =
11291157
atPos(start, in.offset) {
@@ -1577,6 +1605,9 @@ object Parsers {
15771605
normalize(loop(start))
15781606
}
15791607

1608+
def implicitMods(): Modifiers =
1609+
addMod(EmptyModifiers, atPos(accept(IMPLICIT)) { Mod.Implicit() })
1610+
15801611
/** Wrap annotation or constructor in New(...).<init> */
15811612
def wrapNew(tpt: Tree) = Select(New(tpt), nme.CONSTRUCTOR)
15821613

@@ -1682,9 +1713,9 @@ object Parsers {
16821713
* Param ::= id `:' ParamType [`=' Expr]
16831714
*/
16841715
def paramClauses(owner: Name, ofCaseClass: Boolean = false): List[List[ValDef]] = {
1685-
var implicitMod: Mod = null
1686-
var firstClauseOfCaseClass = ofCaseClass
1716+
var imods: Modifiers = EmptyModifiers
16871717
var implicitOffset = -1 // use once
1718+
var firstClauseOfCaseClass = ofCaseClass
16881719
def param(): ValDef = {
16891720
val start = in.offset
16901721
var mods = annotsAsMods()
@@ -1719,7 +1750,7 @@ object Parsers {
17191750
if (in.token == ARROW) {
17201751
if (owner.isTypeName && !(mods is Local))
17211752
syntaxError(s"${if (mods is Mutable) "`var'" else "`val'"} parameters may not be call-by-name")
1722-
else if (implicitMod != null)
1753+
else if (imods.hasFlags)
17231754
syntaxError("implicit parameters may not be call-by-name")
17241755
}
17251756
paramType()
@@ -1731,7 +1762,7 @@ object Parsers {
17311762
mods = mods.withPos(mods.pos.union(Position(implicitOffset, implicitOffset)))
17321763
implicitOffset = -1
17331764
}
1734-
if (implicitMod != null) mods = addMod(mods, implicitMod)
1765+
for (imod <- imods.mods) mods = addMod(mods, imod)
17351766
ValDef(name, tpt, default).withMods(mods)
17361767
}
17371768
}
@@ -1740,7 +1771,7 @@ object Parsers {
17401771
else {
17411772
if (in.token == IMPLICIT) {
17421773
implicitOffset = in.offset
1743-
implicitMod = atPos(in.skipToken()) { Mod.Implicit() }
1774+
imods = implicitMods()
17441775
}
17451776
commaSeparated(param)
17461777
}
@@ -1750,7 +1781,7 @@ object Parsers {
17501781
if (in.token == LPAREN)
17511782
paramClause() :: {
17521783
firstClauseOfCaseClass = false
1753-
if (implicitMod == null) clauses() else Nil
1784+
if (imods.hasFlags) Nil else clauses()
17541785
}
17551786
else Nil
17561787
}
@@ -2213,9 +2244,9 @@ object Parsers {
22132244
stats.toList
22142245
}
22152246

2216-
def localDef(start: Int, implicitMod: Option[Mod] = None): Tree = {
2247+
def localDef(start: Int, implicitMods: Modifiers = EmptyModifiers): Tree = {
22172248
var mods = defAnnotsMods(localModifierTokens)
2218-
for (imod <- implicitMod) mods = (mods | ImplicitCommon).withAddedMod(imod)
2249+
for (imod <- implicitMods.mods) mods = addMod(mods, imod)
22192250
defOrDcl(start, mods)
22202251
}
22212252

@@ -2238,9 +2269,9 @@ object Parsers {
22382269
else if (isDefIntro(localModifierTokens))
22392270
if (in.token == IMPLICIT) {
22402271
val start = in.offset
2241-
val mod = atPos(in.skipToken()) { Mod.Implicit() }
2242-
if (isIdent) stats += implicitClosure(start, Location.InBlock, mod)
2243-
else stats += localDef(start, Some(mod))
2272+
val imods = implicitMods()
2273+
if (isBindingIntro) stats += implicitClosure(start, Location.InBlock, imods)
2274+
else stats += localDef(start, imods)
22442275
} else {
22452276
stats += localDef(in.offset)
22462277
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ object Tokens extends TokensCommon {
209209
final val canStartTypeTokens = literalTokens | identifierTokens | BitSet(
210210
THIS, SUPER, USCORE, LPAREN, AT)
211211

212+
final val canStartBindingTokens = identifierTokens | BitSet(USCORE, LPAREN)
213+
212214
final val templateIntroTokens = BitSet(CLASS, TRAIT, OBJECT, CASECLASS, CASEOBJECT)
213215

214216
final val dclIntroTokens = BitSet(DEF, VAL, VAR, TYPE)

docs/syntax-summary.txt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,13 @@ grammar.
125125
TypeBounds ::= [`>:' Type] [`<: Type] | INT TypeBoundsTree(lo, hi)
126126
TypeParamBounds ::= TypeBounds {`<%' Type} {`:' Type} ContextBounds(typeBounds, tps)
127127

128-
Expr ::= FunParams `=>' Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr)
128+
Expr ::= [`implicit'] FunParams `=>' Expr Function(args, expr), Function(ValDef([implicit], id, TypeTree(), EmptyTree), expr)
129129
FunParams ::= Bindings
130-
| [`implicit'] id
130+
| id
131131
| `_'
132132
ExprInParens ::= PostfixExpr `:' Type
133133
| Expr
134-
BlockResult ::= (FunParams | [`implicit'] id `:' InfixType) `=>' Block
134+
BlockResult ::= [`implicit'] FunParams `=>' Block
135135
| Expr1
136136
Expr1 ::= `if' `(' Expr `)' {nl} Expr [[semi] else Expr] If(Parens(cond), thenp, elsep?)
137137
| `if' Expr `then' Expr [[semi] else Expr] If(cond, thenp, elsep?)
@@ -178,9 +178,7 @@ grammar.
178178
| {Annotation} {LocalModifier} TmplDef
179179
| Expr1
180180
|
181-
ResultExpr ::= Expr1
182-
| (Bindings | ([`implicit'] id | `_') `:' ) `=>' Block
183-
Function(args, block) // block starts at =>
181+
184182
ForExpr ::= `for' (`(' Enumerators `)' | `{' Enumerators `}') ForYield(enums, expr)
185183
{nl} [`yield'] Expr ForDo(enums, expr)
186184
| `for' Enumerators (`do' Expr | `yield' Expr)
@@ -241,7 +239,7 @@ grammar.
241239
DefParams ::= DefParam {`,' DefParam}
242240
DefParam ::= {Annotation} [`inline'] Param ValDef(mods, id, tpe, expr) -- point of mods at id.
243241

244-
Bindings ::= `(' Binding {`,' Binding `)' bindings
242+
Bindings ::= `(' Binding {`,' Binding}] `)'
245243
Binding ::= (id | `_') [`:' Type] ValDef(_, id, tpe, EmptyTree)
246244

247245
Modifier ::= LocalModifier

0 commit comments

Comments
 (0)