Skip to content

Commit b9e1386

Browse files
Backport "Update syntax.md" to LTS (#20917)
Backports #19670 to the LTS branch. PR submitted by the release tooling. [skip ci]
2 parents 6ccc786 + 889e274 commit b9e1386

File tree

6 files changed

+137
-126
lines changed

6 files changed

+137
-126
lines changed

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

Lines changed: 89 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,13 +1521,15 @@ object Parsers {
15211521
* PolyFunType ::= HKTypeParamClause '=>' Type
15221522
* | HKTypeParamClause ‘->’ [CaptureSet] Type -- under pureFunctions
15231523
* FunTypeArgs ::= InfixType
1524-
* | `(' [ [ ‘['erased'] FunArgType {`,' FunArgType } ] `)'
1525-
* | '(' [ ‘['erased'] TypedFunParam {',' TypedFunParam } ')'
1524+
* | `(' [ FunArgType {`,' FunArgType } ] `)'
1525+
* | '(' [ TypedFunParam {',' TypedFunParam } ')'
1526+
* MatchType ::= InfixType `match` <<< TypeCaseClauses >>>
15261527
*/
15271528
def typ(): Tree =
15281529
val start = in.offset
15291530
var imods = Modifiers()
1530-
var erasedArgs: ListBuffer[Boolean] = ListBuffer()
1531+
val erasedArgs: ListBuffer[Boolean] = ListBuffer()
1532+
15311533
def functionRest(params: List[Tree]): Tree =
15321534
val paramSpan = Span(start, in.lastOffset)
15331535
atSpan(start, in.offset) {
@@ -1556,7 +1558,8 @@ object Parsers {
15561558
else
15571559
accept(ARROW)
15581560

1559-
val resultType = if isPure then capturesAndResult(typ) else typ()
1561+
val resultType =
1562+
if isPure then capturesAndResult(typ) else typ()
15601563
if token == TLARROW then
15611564
for case ValDef(_, tpt, _) <- params do
15621565
if isByNameType(tpt) then
@@ -1573,99 +1576,94 @@ object Parsers {
15731576
Function(params, resultType)
15741577
}
15751578

1576-
var isValParamList = false
1579+
def typeRest(t: Tree) = in.token match
1580+
case ARROW | CTXARROW =>
1581+
erasedArgs.addOne(false)
1582+
functionRest(t :: Nil)
1583+
case MATCH =>
1584+
matchType(t)
1585+
case FORSOME =>
1586+
syntaxError(ExistentialTypesNoLongerSupported())
1587+
t
1588+
case _ if isPureArrow =>
1589+
erasedArgs.addOne(false)
1590+
functionRest(t :: Nil)
1591+
case _ =>
1592+
if erasedArgs.contains(true) && !t.isInstanceOf[FunctionWithMods] then
1593+
syntaxError(ErasedTypesCanOnlyBeFunctionTypes(), implicitKwPos(start))
1594+
t
15771595

1578-
val t =
1579-
if (in.token == LPAREN) {
1596+
var isValParamList = false
1597+
if in.token == LPAREN then
1598+
in.nextToken()
1599+
if in.token == RPAREN then
15801600
in.nextToken()
1581-
if (in.token == RPAREN) {
1582-
in.nextToken()
1583-
functionRest(Nil)
1584-
}
1585-
else {
1586-
val paramStart = in.offset
1587-
def addErased() =
1588-
erasedArgs.addOne(isErasedKw)
1589-
if isErasedKw then { in.skipToken(); }
1590-
addErased()
1591-
val ts = in.currentRegion.withCommasExpected {
1601+
functionRest(Nil)
1602+
else
1603+
val paramStart = in.offset
1604+
def addErased() =
1605+
erasedArgs.addOne(isErasedKw)
1606+
if isErasedKw then in.skipToken()
1607+
addErased()
1608+
val args =
1609+
in.currentRegion.withCommasExpected:
15921610
funArgType() match
15931611
case Ident(name) if name != tpnme.WILDCARD && in.isColon =>
15941612
isValParamList = true
1595-
def funParam(start: Offset, mods: Modifiers) = {
1596-
atSpan(start) {
1613+
def funParam(start: Offset, mods: Modifiers) =
1614+
atSpan(start):
15971615
addErased()
15981616
typedFunParam(in.offset, ident(), imods)
1599-
}
1600-
}
16011617
commaSeparatedRest(
16021618
typedFunParam(paramStart, name.toTermName, imods),
16031619
() => funParam(in.offset, imods))
16041620
case t =>
1605-
def funParam() = {
1606-
addErased()
1607-
funArgType()
1608-
}
1609-
commaSeparatedRest(t, funParam)
1610-
}
1611-
accept(RPAREN)
1612-
if isValParamList || in.isArrow || isPureArrow then
1613-
functionRest(ts)
1614-
else {
1615-
val ts1 = ts.mapConserve { t =>
1616-
if isByNameType(t) then
1617-
syntaxError(ByNameParameterNotSupported(t), t.span)
1618-
stripByNameType(t)
1619-
else
1620-
t
1621-
}
1622-
val tuple = atSpan(start) { makeTupleOrParens(ts1) }
1623-
infixTypeRest(
1624-
refinedTypeRest(
1625-
withTypeRest(
1626-
annotTypeRest(
1627-
simpleTypeRest(tuple)))))
1628-
}
1629-
}
1630-
}
1631-
else if (in.token == LBRACKET) {
1632-
val start = in.offset
1633-
val tparams = typeParamClause(ParamOwner.TypeParam)
1634-
if (in.token == TLARROW)
1635-
atSpan(start, in.skipToken())(LambdaTypeTree(tparams, toplevelTyp()))
1636-
else if (in.token == ARROW || isPureArrow(nme.PUREARROW)) {
1637-
val arrowOffset = in.skipToken()
1638-
val body = toplevelTyp()
1639-
atSpan(start, arrowOffset) {
1640-
getFunction(body) match {
1641-
case Some(f) =>
1642-
checkFunctionNotErased(f, "poly function")
1643-
PolyFunction(tparams, body)
1644-
case None =>
1645-
syntaxError(em"Implementation restriction: polymorphic function types must have a value parameter", arrowOffset)
1646-
Ident(nme.ERROR.toTypeName)
1647-
}
1648-
}
1649-
}
1650-
else { accept(TLARROW); typ() }
1651-
}
1652-
else if (in.token == INDENT) enclosed(INDENT, typ())
1653-
else infixType()
1654-
1655-
in.token match
1656-
case ARROW | CTXARROW =>
1657-
erasedArgs.addOne(false)
1658-
functionRest(t :: Nil)
1659-
case MATCH => matchType(t)
1660-
case FORSOME => syntaxError(ExistentialTypesNoLongerSupported()); t
1661-
case _ =>
1662-
if isPureArrow then
1663-
erasedArgs.addOne(false)
1664-
functionRest(t :: Nil)
1621+
def funArg() =
1622+
erasedArgs.addOne(false)
1623+
funArgType()
1624+
commaSeparatedRest(t, funArg)
1625+
accept(RPAREN)
1626+
if isValParamList || in.isArrow || isPureArrow then
1627+
functionRest(args)
16651628
else
1666-
if (erasedArgs.contains(true) && !t.isInstanceOf[FunctionWithMods])
1667-
syntaxError(ErasedTypesCanOnlyBeFunctionTypes(), implicitKwPos(start))
1668-
t
1629+
val args1 = args.mapConserve: t =>
1630+
if isByNameType(t) then
1631+
syntaxError(ByNameParameterNotSupported(t), t.span)
1632+
stripByNameType(t)
1633+
else
1634+
t
1635+
val tuple = atSpan(start):
1636+
makeTupleOrParens(args1)
1637+
typeRest:
1638+
infixTypeRest:
1639+
refinedTypeRest:
1640+
withTypeRest:
1641+
annotTypeRest:
1642+
simpleTypeRest(tuple)
1643+
else if in.token == LBRACKET then
1644+
val start = in.offset
1645+
val tparams = typeParamClause(ParamOwner.TypeParam)
1646+
if in.token == TLARROW then
1647+
atSpan(start, in.skipToken()):
1648+
LambdaTypeTree(tparams, toplevelTyp())
1649+
else if in.token == ARROW || isPureArrow(nme.PUREARROW) then
1650+
val arrowOffset = in.skipToken()
1651+
val body = toplevelTyp()
1652+
atSpan(start, arrowOffset):
1653+
getFunction(body) match
1654+
case Some(f) =>
1655+
checkFunctionNotErased(f, "poly function")
1656+
PolyFunction(tparams, body)
1657+
case None =>
1658+
syntaxError(em"Implementation restriction: polymorphic function types must have a value parameter", arrowOffset)
1659+
Ident(nme.ERROR.toTypeName)
1660+
else
1661+
accept(TLARROW)
1662+
typ()
1663+
else if in.token == INDENT then
1664+
enclosed(INDENT, typ())
1665+
else
1666+
typeRest(infixType())
16691667
end typ
16701668

16711669
private def makeKindProjectorTypeDef(name: TypeName): TypeDef = {
@@ -1702,7 +1700,7 @@ object Parsers {
17021700
private def implicitKwPos(start: Int): Span =
17031701
Span(start, start + nme.IMPLICITkw.asSimpleName.length)
17041702

1705-
/** TypedFunParam ::= id ':' Type */
1703+
/** TypedFunParam ::= [`erased`] id ':' Type */
17061704
def typedFunParam(start: Offset, name: TermName, mods: Modifiers = EmptyModifiers): ValDef =
17071705
atSpan(start) {
17081706
acceptColon()
@@ -2016,7 +2014,7 @@ object Parsers {
20162014
*/
20172015
def paramType(): Tree = paramTypeOf(paramValueType)
20182016

2019-
/** ParamValueType ::= [`into`] Type [`*']
2017+
/** ParamValueType ::= Type [`*']
20202018
*/
20212019
def paramValueType(): Tree = {
20222020
val t = maybeInto(toplevelTyp)
@@ -2374,7 +2372,7 @@ object Parsers {
23742372
Match(t, inBracesOrIndented(caseClauses(() => caseClause())))
23752373
}
23762374

2377-
/** `match' `{' TypeCaseClauses `}'
2375+
/** `match' <<< TypeCaseClauses >>>
23782376
*/
23792377
def matchType(t: Tree): MatchTypeTree =
23802378
atSpan(startOffset(t), accept(MATCH)) {
@@ -2384,7 +2382,7 @@ object Parsers {
23842382
/** FunParams ::= Bindings
23852383
* | id
23862384
* | `_'
2387-
* Bindings ::= `(' [[‘erased’] Binding {`,' Binding}] `)'
2385+
* Bindings ::= `(' [Binding {`,' Binding}] `)'
23882386
*/
23892387
def funParams(mods: Modifiers, location: Location): List[Tree] =
23902388
if in.token == LPAREN then
@@ -3126,7 +3124,7 @@ object Parsers {
31263124
* | AccessModifier
31273125
* | override
31283126
* | opaque
3129-
* LocalModifier ::= abstract | final | sealed | open | implicit | lazy | erased | inline | transparent
3127+
* LocalModifier ::= abstract | final | sealed | open | implicit | lazy | inline | transparent | infix | erased
31303128
*/
31313129
def modifiers(allowed: BitSet = modifierTokens, start: Modifiers = Modifiers()): Modifiers = {
31323130
@tailrec
@@ -3283,7 +3281,7 @@ object Parsers {
32833281
/** ClsTermParamClause ::= ‘(’ ClsParams ‘)’ | UsingClsTermParamClause
32843282
* UsingClsTermParamClause::= ‘(’ ‘using’ [‘erased’] (ClsParams | ContextTypes) ‘)’
32853283
* ClsParams ::= ClsParam {‘,’ ClsParam}
3286-
* ClsParam ::= {Annotation}
3284+
* ClsParam ::= {Annotation} [{Modifier} (‘val’ | ‘var’)] Param
32873285
*
32883286
* TypelessClause ::= DefTermParamClause
32893287
* | UsingParamClause

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@ 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
18-
import NamerOps.methodType
1918
import config.Printers.recheckr
2019
import util.Property
2120
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)