Skip to content

Commit 2b554d4

Browse files
committed
Small tweaks
1 parent 8732b28 commit 2b554d4

File tree

5 files changed

+38
-17
lines changed

5 files changed

+38
-17
lines changed

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

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,9 +1085,19 @@ object Parsers {
10851085
}
10861086

10871087
/** Is the token sequence following the current `:` token classified as a lambda?
1088-
* This is the case if the input starts with an identifier, a wildcard, or
1089-
* something enclosed in (...) or [...], and this is followed by a `=>` or `?=>`
1090-
* and an INDENT.
1088+
* If yes return a defined parsing function to parse the lambda body, if not
1089+
* return None. The case is triggered in two :if the input starts with an identifier,
1090+
* a wildcard, or something enclosed in (...) or [...], this is followed by a
1091+
* `=>` or `?=>`, one one of the following two cases applies:
1092+
* 1. The next token is an indent. In this case the return parsing function parses
1093+
* an Expr in location Location.InColonArg.
1094+
* 2. The next token is on the same line and the enclosing region is not `(...)`.
1095+
* In this case the parsing function parses an Expr in location Location.InColonArg
1096+
* enclosed in a SingleLineLambda region, and then eats the ENDlambda token
1097+
* generated by the Scanner at the end of that region.
1098+
* The reason for excluding (2) in regions enclosed in parentheses is to avoid
1099+
* an ambiguity with type ascription `(x: A => B)`, where function types are only
1100+
* allowed inside parentheses.
10911101
*/
10921102
def followingIsLambdaAfterColon(): Option[() => Tree] =
10931103
val lookahead = in.LookaheadScanner(allowIndent = true)
@@ -1101,7 +1111,7 @@ object Parsers {
11011111
Some: () =>
11021112
val t = inSepRegion(SingleLineLambda(_)):
11031113
expr(Location.InColonArg)
1104-
accept(ENDLAMBDA)
1114+
accept(ENDlambda)
11051115
t
11061116
else None
11071117
else None
@@ -1178,11 +1188,14 @@ object Parsers {
11781188
case _ => infixOp
11791189
}
11801190

1181-
/** True if we are seeing a lambda argument after a colon of the form:
1191+
/** Optionally, if we are seeing a lambda argument after a colon of the form
11821192
* : (params) =>
11831193
* body
1194+
* or a single-line lambda
1195+
* : (params) => body
1196+
* then return the function used to parse `body`.
11841197
*/
1185-
def isColonLambda: Option[() => Tree] =
1198+
def detectColonLambda: Option[() => Tree] =
11861199
if sourceVersion.enablesFewerBraces && in.token == COLONfollow
11871200
then followingIsLambdaAfterColon()
11881201
else None
@@ -1209,7 +1222,7 @@ object Parsers {
12091222
opStack = OpInfo(top1, op, in.offset) :: opStack
12101223
colonAtEOLOpt()
12111224
newLineOptWhenFollowing(canStartOperand)
1212-
isColonLambda match
1225+
detectColonLambda match
12131226
case Some(parseExpr) =>
12141227
in.nextToken()
12151228
recur(parseExpr())
@@ -2778,6 +2791,7 @@ object Parsers {
27782791
* | SimpleExpr1 ColonArgument
27792792
* ColonArgument ::= colon [LambdaStart]
27802793
* indent (CaseClauses | Block) outdent
2794+
* | colon LambdaStart expr ENDlambda -- under experimental.relaxedLambdaSyntax
27812795
* LambdaStart ::= FunParams (‘=>’ | ‘?=>’)
27822796
* | TypTypeParamClause ‘=>’
27832797
* ColonArgBody ::= indent (CaseClauses | Block) outdent
@@ -2860,7 +2874,7 @@ object Parsers {
28602874
makeParameter(name.asTermName, typedOpt(), Modifiers(), isBackquoted = isBackquoted(id))
28612875
}
28622876
case _ => t
2863-
else isColonLambda match
2877+
else detectColonLambda match
28642878
case Some(parseExpr) =>
28652879
val app =
28662880
atSpan(startOffset(t), in.skipToken()):

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -617,8 +617,8 @@ object Scanners {
617617
&& !statCtdTokens.contains(lastToken)
618618
&& !isTrailingBlankLine
619619

620-
if currentRegion.closedBy == ENDLAMBDA then
621-
insert(ENDLAMBDA, lineOffset)
620+
if currentRegion.closedBy == ENDlambda then
621+
insert(ENDlambda, lineOffset)
622622
else if newlineIsSeparating
623623
&& canEndStatTokens.contains(lastToken)
624624
&& canStartStatTokens.contains(token)
@@ -1685,7 +1685,7 @@ object Scanners {
16851685
case class InParens(prefix: Token, outer: Region) extends Region(prefix + 1)
16861686
case class InBraces(outer: Region) extends Region(RBRACE)
16871687
case class InCase(outer: Region) extends Region(OUTDENT)
1688-
case class SingleLineLambda(outer: Region) extends Region(ENDLAMBDA)
1688+
case class SingleLineLambda(outer: Region) extends Region(ENDlambda)
16891689

16901690
/** A class describing an indentation region.
16911691
* @param width The principal indentation width

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ object Tokens extends TokensCommon {
203203
// A `:` recognized as starting an indentation block
204204
inline val SELFARROW = 90; enter(SELFARROW, "=>") // reclassified ARROW following self-type
205205

206-
inline val ENDLAMBDA = 99; enter(ENDLAMBDA, "end of single-line lambda")
206+
inline val ENDlambda = 99; enter(ENDlambda, "end of single-line lambda")
207207

208208
/** XML mode */
209209
inline val XMLSTART = 100; enter(XMLSTART, "$XMLSTART$<") // TODO: deprecate
@@ -269,7 +269,7 @@ object Tokens extends TokensCommon {
269269
final val canStartStatTokens3: TokenSet = canStartExprTokens3 | mustStartStatTokens | BitSet(
270270
AT, CASE, END)
271271

272-
final val canEndStatTokens: TokenSet = atomicExprTokens | BitSet(TYPE, GIVEN, RPAREN, RBRACE, RBRACKET, OUTDENT, ENDLAMBDA)
272+
final val canEndStatTokens: TokenSet = atomicExprTokens | BitSet(TYPE, GIVEN, RPAREN, RBRACE, RBRACKET, OUTDENT, ENDlambda)
273273

274274
/** Tokens that stop a lookahead scan search for a `<-`, `then`, or `do`.
275275
* Used for disambiguating between old and new syntax.

tests/neg/closure-args.check

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,16 @@
1414
| Illegal start of toplevel definition
1515
|
1616
| longer explanation available when compiling with `-explain`
17-
-- [E018] Syntax Error: tests/neg/closure-args.scala:18:46 -------------------------------------------------------------
18-
18 |val fs: List[List[Int] => Int] = xs.map: x => case y :: ys => y case Nil => -1 // error
19-
| ^^^^
20-
| expression expected but case found
17+
-- [E018] Syntax Error: tests/neg/closure-args.scala:18:20 -------------------------------------------------------------
18+
18 |val e = xs.map: y => // error
19+
| ^
20+
| expression expected but end of single-line lambda found
2121
|
2222
| longer explanation available when compiling with `-explain`
23+
-- [E040] Syntax Error: tests/neg/closure-args.scala:21:64 -------------------------------------------------------------
24+
21 |val fs: List[List[Int] => Int] = xs.map: x => case y :: ys => y case Nil => -1 // error
25+
| ^^^^
26+
| end of single-line lambda expected, but 'case' found
2327
-- [E008] Not Found Error: tests/neg/closure-args.scala:10:4 -----------------------------------------------------------
2428
8 |val b: Int = xs
2529
9 | .map: x => x

tests/neg/closure-args.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,7 @@ val d = xs
1515

1616
val c = List(xs.map: y => y + y) // error // error // error // error
1717

18+
val e = xs.map: y => // error
19+
y + 1
20+
1821
val fs: List[List[Int] => Int] = xs.map: x => case y :: ys => y case Nil => -1 // error

0 commit comments

Comments
 (0)