Skip to content

Commit b160bbb

Browse files
authored
Update syntax.md (#19670)
1. Add missing soft modifiers 2. Port changes from multiple type parameter sections to reference. Now that multiple type parameter sections are merged, this is the official syntax. This also covers extension method declarations. Fixes #19667 Fixes #19668
2 parents 8776677 + f2f5051 commit b160bbb

File tree

9 files changed

+151
-140
lines changed

9 files changed

+151
-140
lines changed

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

Lines changed: 88 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,13 +1532,15 @@ object Parsers {
15321532
* PolyFunType ::= HKTypeParamClause '=>' Type
15331533
* | HKTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions
15341534
* FunTypeArgs ::= InfixType
1535-
* | `(' [ [ ‘['erased'] FunArgType {`,' FunArgType } ] `)'
1536-
* | '(' [ ‘['erased'] TypedFunParam {',' TypedFunParam } ')'
1535+
* | `(' [ FunArgType {`,' FunArgType } ] `)'
1536+
* | '(' [ TypedFunParam {',' TypedFunParam } ')'
1537+
* MatchType ::= InfixType `match` <<< TypeCaseClauses >>>
15371538
*/
15381539
def typ(): Tree =
15391540
val start = in.offset
15401541
var imods = Modifiers()
1541-
var erasedArgs: ListBuffer[Boolean] = ListBuffer()
1542+
val erasedArgs: ListBuffer[Boolean] = ListBuffer()
1543+
15421544
def functionRest(params: List[Tree]): Tree =
15431545
val paramSpan = Span(start, in.lastOffset)
15441546
atSpan(start, in.offset) {
@@ -1567,7 +1569,8 @@ object Parsers {
15671569
else
15681570
accept(ARROW)
15691571

1570-
val resultType = if isPure then capturesAndResult(typ) else typ()
1572+
val resultType =
1573+
if isPure then capturesAndResult(typ) else typ()
15711574
if token == TLARROW then
15721575
for case ValDef(_, tpt, _) <- params do
15731576
if isByNameType(tpt) then
@@ -1585,98 +1588,93 @@ object Parsers {
15851588
Function(params, resultType)
15861589
}
15871590

1588-
var isValParamList = false
1591+
def typeRest(t: Tree) = in.token match
1592+
case ARROW | CTXARROW =>
1593+
erasedArgs.addOne(false)
1594+
functionRest(t :: Nil)
1595+
case MATCH =>
1596+
matchType(t)
1597+
case FORSOME =>
1598+
syntaxError(ExistentialTypesNoLongerSupported())
1599+
t
1600+
case _ if isPureArrow =>
1601+
erasedArgs.addOne(false)
1602+
functionRest(t :: Nil)
1603+
case _ =>
1604+
if erasedArgs.contains(true) && !t.isInstanceOf[FunctionWithMods] then
1605+
syntaxError(ErasedTypesCanOnlyBeFunctionTypes(), implicitKwPos(start))
1606+
t
15891607

1590-
val t =
1591-
if (in.token == LPAREN) {
1608+
var isValParamList = false
1609+
if in.token == LPAREN then
1610+
in.nextToken()
1611+
if in.token == RPAREN then
15921612
in.nextToken()
1593-
if (in.token == RPAREN) {
1594-
in.nextToken()
1595-
functionRest(Nil)
1596-
}
1597-
else {
1598-
val paramStart = in.offset
1599-
def addErased() =
1600-
erasedArgs.addOne(isErasedKw)
1601-
if isErasedKw then { in.skipToken(); }
1602-
addErased()
1603-
val ts = in.currentRegion.withCommasExpected {
1613+
functionRest(Nil)
1614+
else
1615+
val paramStart = in.offset
1616+
def addErased() =
1617+
erasedArgs.addOne(isErasedKw)
1618+
if isErasedKw then in.skipToken()
1619+
addErased()
1620+
val args =
1621+
in.currentRegion.withCommasExpected:
16041622
funArgType() match
16051623
case Ident(name) if name != tpnme.WILDCARD && in.isColon =>
16061624
isValParamList = true
1607-
def funParam(start: Offset, mods: Modifiers) = {
1608-
atSpan(start) {
1625+
def funParam(start: Offset, mods: Modifiers) =
1626+
atSpan(start):
16091627
addErased()
16101628
typedFunParam(in.offset, ident(), imods)
1611-
}
1612-
}
16131629
commaSeparatedRest(
16141630
typedFunParam(paramStart, name.toTermName, imods),
16151631
() => funParam(in.offset, imods))
16161632
case t =>
1617-
def funParam() = {
1618-
addErased()
1619-
funArgType()
1620-
}
1621-
commaSeparatedRest(t, funParam)
1622-
}
1623-
accept(RPAREN)
1624-
if isValParamList || in.isArrow || isPureArrow then
1625-
functionRest(ts)
1626-
else {
1627-
val ts1 = ts.mapConserve { t =>
1628-
if isByNameType(t) then
1629-
syntaxError(ByNameParameterNotSupported(t), t.span)
1630-
stripByNameType(t)
1631-
else
1632-
t
1633-
}
1634-
val tuple = atSpan(start) { makeTupleOrParens(ts1) }
1635-
infixTypeRest(
1636-
refinedTypeRest(
1637-
withTypeRest(
1638-
annotTypeRest(
1639-
simpleTypeRest(tuple)))))
1640-
}
1641-
}
1642-
}
1643-
else if (in.token == LBRACKET) {
1644-
val start = in.offset
1645-
val tparams = typeParamClause(ParamOwner.TypeParam)
1646-
if (in.token == TLARROW)
1647-
atSpan(start, in.skipToken())(LambdaTypeTree(tparams, toplevelTyp()))
1648-
else if (in.token == ARROW || isPureArrow(nme.PUREARROW)) {
1649-
val arrowOffset = in.skipToken()
1650-
val body = toplevelTyp()
1651-
atSpan(start, arrowOffset) {
1652-
getFunction(body) match {
1653-
case Some(f) =>
1654-
PolyFunction(tparams, body)
1655-
case None =>
1656-
syntaxError(em"Implementation restriction: polymorphic function types must have a value parameter", arrowOffset)
1657-
Ident(nme.ERROR.toTypeName)
1658-
}
1659-
}
1660-
}
1661-
else { accept(TLARROW); typ() }
1662-
}
1663-
else if (in.token == INDENT) enclosed(INDENT, typ())
1664-
else infixType()
1665-
1666-
in.token match
1667-
case ARROW | CTXARROW =>
1668-
erasedArgs.addOne(false)
1669-
functionRest(t :: Nil)
1670-
case MATCH => matchType(t)
1671-
case FORSOME => syntaxError(ExistentialTypesNoLongerSupported()); t
1672-
case _ =>
1673-
if isPureArrow then
1674-
erasedArgs.addOne(false)
1675-
functionRest(t :: Nil)
1633+
def funArg() =
1634+
erasedArgs.addOne(false)
1635+
funArgType()
1636+
commaSeparatedRest(t, funArg)
1637+
accept(RPAREN)
1638+
if isValParamList || in.isArrow || isPureArrow then
1639+
functionRest(args)
16761640
else
1677-
if (erasedArgs.contains(true) && !t.isInstanceOf[FunctionWithMods])
1678-
syntaxError(ErasedTypesCanOnlyBeFunctionTypes(), implicitKwPos(start))
1679-
t
1641+
val args1 = args.mapConserve: t =>
1642+
if isByNameType(t) then
1643+
syntaxError(ByNameParameterNotSupported(t), t.span)
1644+
stripByNameType(t)
1645+
else
1646+
t
1647+
val tuple = atSpan(start):
1648+
makeTupleOrParens(args1)
1649+
typeRest:
1650+
infixTypeRest:
1651+
refinedTypeRest:
1652+
withTypeRest:
1653+
annotTypeRest:
1654+
simpleTypeRest(tuple)
1655+
else if in.token == LBRACKET then
1656+
val start = in.offset
1657+
val tparams = typeParamClause(ParamOwner.TypeParam)
1658+
if in.token == TLARROW then
1659+
atSpan(start, in.skipToken()):
1660+
LambdaTypeTree(tparams, toplevelTyp())
1661+
else if in.token == ARROW || isPureArrow(nme.PUREARROW) then
1662+
val arrowOffset = in.skipToken()
1663+
val body = toplevelTyp()
1664+
atSpan(start, arrowOffset):
1665+
getFunction(body) match
1666+
case Some(f) =>
1667+
PolyFunction(tparams, body)
1668+
case None =>
1669+
syntaxError(em"Implementation restriction: polymorphic function types must have a value parameter", arrowOffset)
1670+
Ident(nme.ERROR.toTypeName)
1671+
else
1672+
accept(TLARROW)
1673+
typ()
1674+
else if in.token == INDENT then
1675+
enclosed(INDENT, typ())
1676+
else
1677+
typeRest(infixType())
16801678
end typ
16811679

16821680
private def makeKindProjectorTypeDef(name: TypeName): TypeDef = {
@@ -1713,7 +1711,7 @@ object Parsers {
17131711
private def implicitKwPos(start: Int): Span =
17141712
Span(start, start + nme.IMPLICITkw.asSimpleName.length)
17151713

1716-
/** TypedFunParam ::= id ':' Type */
1714+
/** TypedFunParam ::= [`erased`] id ':' Type */
17171715
def typedFunParam(start: Offset, name: TermName, mods: Modifiers = EmptyModifiers): ValDef =
17181716
atSpan(start) {
17191717
acceptColon()
@@ -2068,7 +2066,7 @@ object Parsers {
20682066
*/
20692067
def paramType(): Tree = paramTypeOf(paramValueType)
20702068

2071-
/** ParamValueType ::= [`into`] Type [`*']
2069+
/** ParamValueType ::= Type [`*']
20722070
*/
20732071
def paramValueType(): Tree = {
20742072
val t = maybeInto(toplevelTyp)
@@ -2425,7 +2423,7 @@ object Parsers {
24252423
Match(t, inBracesOrIndented(caseClauses(() => caseClause())))
24262424
}
24272425

2428-
/** `match' `{' TypeCaseClauses `}'
2426+
/** `match' <<< TypeCaseClauses >>>
24292427
*/
24302428
def matchType(t: Tree): MatchTypeTree =
24312429
atSpan(startOffset(t), accept(MATCH)) {
@@ -2435,7 +2433,7 @@ object Parsers {
24352433
/** FunParams ::= Bindings
24362434
* | id
24372435
* | `_'
2438-
* Bindings ::= `(' [[‘erased’] Binding {`,' Binding}] `)'
2436+
* Bindings ::= `(' [Binding {`,' Binding}] `)'
24392437
*/
24402438
def funParams(mods: Modifiers, location: Location): List[Tree] =
24412439
if in.token == LPAREN then
@@ -3173,7 +3171,7 @@ object Parsers {
31733171
* | AccessModifier
31743172
* | override
31753173
* | opaque
3176-
* LocalModifier ::= abstract | final | sealed | open | implicit | lazy | erased | inline | transparent
3174+
* LocalModifier ::= abstract | final | sealed | open | implicit | lazy | inline | transparent | infix | erased
31773175
*/
31783176
def modifiers(allowed: BitSet = modifierTokens, start: Modifiers = Modifiers()): Modifiers = {
31793177
@tailrec
@@ -3326,7 +3324,7 @@ object Parsers {
33263324
/** ClsTermParamClause ::= ‘(’ ClsParams ‘)’ | UsingClsTermParamClause
33273325
* UsingClsTermParamClause::= ‘(’ ‘using’ [‘erased’] (ClsParams | ContextTypes) ‘)’
33283326
* ClsParams ::= ClsParam {‘,’ ClsParam}
3329-
* ClsParam ::= {Annotation}
3327+
* ClsParam ::= {Annotation} [{Modifier} (‘val’ | ‘var’)] Param
33303328
*
33313329
* TypelessClause ::= DefTermParamClause
33323330
* | UsingParamClause

compiler/src/dotty/tools/dotc/transform/Recheck.scala

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ import ast.*
99
import Names.Name
1010
import Phases.Phase
1111
import DenotTransformers.{DenotTransformer, IdentityDenotTransformer, SymTransformer}
12-
import NamerOps.{methodType, linkConstructorParams}
12+
import NamerOps.linkConstructorParams
1313
import NullOpsDecorator.stripNull
1414
import typer.ErrorReporting.err
1515
import typer.ProtoTypes.*
1616
import typer.TypeAssigner.seqLitType
1717
import typer.ConstFold
1818
import typer.ErrorReporting.{Addenda, NothingToAdd}
19-
import NamerOps.methodType
2019
import config.Printers.recheckr
2120
import util.Property
2221
import StdNames.nme

docs/_docs/internals/syntax.md

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ productions map to AST nodes.
2020
The following description of Scala tokens uses literal characters `‘c’` when
2121
referring to the ASCII fragment `\u0000``\u007F`.
2222

23+
Informal descriptions are typeset as `“some comment”`.
24+
2325
## Lexical Syntax
2426

2527
The lexical syntax of Scala is given by the following grammar in EBNF form:
@@ -99,7 +101,10 @@ semi ::= ‘;’ | nl {nl}
99101

100102
## Optional Braces
101103

102-
The lexical analyzer also inserts `indent` and `outdent` tokens that represent regions of indented code [at certain points](../reference/other-new-features/indentation.md)
104+
The principle of optional braces is that any keyword that can be followed by `{` can also be followed by an indented block, without needing an intervening `:`.
105+
(Allowing an optional `:` would be counterproductive since it would introduce several ways to do the same thing.)
106+
107+
The lexical analyzer inserts `indent` and `outdent` tokens that represent regions of indented code [at certain points](../reference/other-new-features/indentation.md).
103108

104109
In the context-free productions below we use the notation `<<< ts >>>`
105110
to indicate a token sequence `ts` that is either enclosed in a pair of braces `{ ts }` or that constitutes an indented region `indent ts outdent`. Analogously, the
@@ -201,14 +206,13 @@ SimpleType1 ::= id
201206
Singleton ::= SimpleRef
202207
| SimpleLiteral
203208
| Singleton ‘.’ id
204-
FunArgType ::= [`erased`] Type
205-
| [`erased`] ‘=>’ Type PrefixOp(=>, t)
209+
FunArgType ::= Type
210+
| ‘=>’ Type PrefixOp(=>, t)
206211
FunArgTypes ::= FunArgType { ‘,’ FunArgType }
207212
ParamType ::= [‘=>’] ParamValueType
208-
ParamValueType ::= [‘into’] ExactParamType Into(t)
209-
ExactParamType ::= ParamValueType [‘*’] PostfixOp(t, "*")
213+
ParamValueType ::= Type [‘*’] PostfixOp(t, "*")
210214
TypeArgs ::= ‘[’ Types ‘]’ ts
211-
Refinement ::= :<<< [RefineDef] {semi [RefineDef]} >>> ds
215+
Refinement ::= :<<< [RefineDcl] {semi [RefineDcl]} >>> ds
212216
TypeBounds ::= [‘>:’ Type] [‘<:’ Type] TypeBoundsTree(lo, hi)
213217
TypeParamBounds ::= TypeBounds {‘:’ Type} ContextBounds(typeBounds, tps)
214218
Types ::= Type {‘,’ Type}
@@ -223,7 +227,7 @@ BlockResult ::= FunParams (‘=>’ | ‘?=>’) Block
223227
| HkTypeParamClause ‘=>’ Block
224228
| Expr1
225229
FunParams ::= Bindings
226-
| [`erased`] id
230+
| id
227231
| ‘_’
228232
Expr1 ::= [‘inline’] ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[semi] ‘else’ Expr] If(Parens(cond), thenp, elsep?)
229233
| [‘inline’] ‘if’ Expr ‘then’ Expr [[semi] ‘else’ Expr] If(cond, thenp, elsep?)
@@ -272,7 +276,7 @@ ColonArgument ::= colon [LambdaStart]
272276
LambdaStart ::= FunParams (‘=>’ | ‘?=>’)
273277
| HkTypeParamClause ‘=>’
274278
Quoted ::= ‘'’ ‘{’ Block ‘}’
275-
| ‘'’ ‘[’ Type ‘]’
279+
| ‘'’ ‘[’ TypeBlock ‘]’
276280
ExprSplice ::= spliceId -- if inside quoted block
277281
| ‘$’ ‘{’ Block ‘}’ -- unless inside quoted pattern
278282
| ‘$’ ‘{’ Pattern ‘}’ -- when inside quoted pattern
@@ -294,6 +298,8 @@ BlockStat ::= Import
294298
| Extension
295299
| Expr1
296300
| EndMarker
301+
TypeBlock ::= {TypeBlockStat semi} Type
302+
TypeBlockStat ::= ‘type’ {nl} TypeDef
297303
298304
ForExpr ::= ‘for’ ‘(’ Enumerators0 ‘)’ {nl} [‘do‘ | ‘yield’] Expr ForYield(enums, expr) / ForDo(enums, expr)
299305
| ‘for’ ‘{’ Enumerators0 ‘}’ {nl} [‘do‘ | ‘yield’] Expr
@@ -353,7 +359,7 @@ ClsParamClause ::= [nl] ‘(’ ClsParams ‘)’
353359
| [nl] ‘(’ ‘using’ (ClsParams | FunArgTypes) ‘)’
354360
ClsParams ::= ClsParam {‘,’ ClsParam}
355361
ClsParam ::= {Annotation} ValDef(mods, id, tpe, expr) -- point of mods on val/var
356-
[{Modifier} (‘val’ | ‘var’) | ‘inline’] Param
362+
[{Modifier} (‘val’ | ‘var’)] Param
357363
358364
DefParamClauses ::= DefParamClause { DefParamClause } -- and two DefTypeParamClause cannot be adjacent
359365
DefParamClause ::= DefTypeParamClause
@@ -376,8 +382,8 @@ Param ::= id ‘:’ ParamType [‘=’ Expr]
376382

377383
### Bindings and Imports
378384
```ebnf
379-
Bindings ::= ‘(’[`erased`] [Binding {‘,’ [`erased`] Binding}] ‘)’
380-
Binding ::= (id | ‘_’) [‘:’ Type] ValDef(_, id, tpe, EmptyTree)
385+
Bindings ::= ‘(’ [Binding {‘,’ Binding}] ‘)’
386+
Binding ::= [`erased`] (id | ‘_’) [‘:’ Type] ValDef(_, id, tpe, EmptyTree)
381387
382388
Modifier ::= LocalModifier
383389
| AccessModifier
@@ -390,6 +396,10 @@ LocalModifier ::= ‘abstract’
390396
| ‘implicit’
391397
| ‘lazy’
392398
| ‘inline’
399+
| ‘transparent’
400+
| ‘infix’
401+
| ‘erased’
402+
393403
AccessModifier ::= (‘private’ | ‘protected’) [AccessQualifier]
394404
AccessQualifier ::= ‘[’ id ‘]’
395405
@@ -414,9 +424,11 @@ EndMarkerTag ::= id | ‘if’ | ‘while’ | ‘for’ | ‘match’ |
414424

415425
### Definitions
416426
```ebnf
417-
RefineDef ::= ‘val’ ValDef
418-
| ‘def’ DefDef
427+
RefineDcl ::= ‘val’ ValDcl
428+
| ‘def’ DefDcl
419429
| ‘type’ {nl} TypeDef
430+
ValDcl ::= ids ‘:’ Type
431+
DefDcl ::= DefSig ‘:’ Type
420432
421433
Def ::= ‘val’ PatDef
422434
| ‘var’ PatDef
@@ -461,7 +473,6 @@ TemplateBody ::= :<<< [SelfType] TemplateStat {semi TemplateStat} >>>
461473
TemplateStat ::= Import
462474
| Export
463475
| {Annotation [nl]} {Modifier} Def
464-
| {Annotation [nl]} {Modifier} Dcl
465476
| Extension
466477
| Expr1
467478
| EndMarker

0 commit comments

Comments
 (0)