Skip to content

Commit 3227926

Browse files
Scala: fix parsing _ as lambda syntactic sugar (#7395)
1 parent d74f908 commit 3227926

2 files changed

Lines changed: 47 additions & 30 deletions

File tree

rewrite-scala/src/main/scala/org/openrewrite/scala/internal/ScalaTreeVisitor.scala

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6415,60 +6415,62 @@ class ScalaTreeVisitor(
64156415
// If we have synthetic params and underscore in source, it's likely a placeholder lambda
64166416
// These should be treated as regular lambdas but we skip the synthetic param
64176417
if (hasUnderscorePlaceholder) {
6418-
func.body match {
6419-
case app: Trees.Apply[?] =>
6420-
// This might be a partially applied function like add(5, _)
6421-
// Check if it's a method invocation with underscore arguments
6422-
var hasPartialApplication = false
6423-
app.args.foreach {
6424-
case id: Trees.Ident[?] if syntheticParams.contains(id.name.toString) =>
6425-
hasPartialApplication = true
6426-
case _ =>
6427-
}
6428-
6429-
if (hasPartialApplication) {
6430-
// Partially applied function - return the method invocation
6431-
val prefix = extractPrefix(func.span)
6432-
val result = visitApply(app)
6433-
result match {
6434-
case mi: J.MethodInvocation => return mi.withPrefix(prefix)
6435-
case _ => return result
6436-
}
6418+
// Detect partial application like `add(5, _)` where the synthetic param
6419+
// appears as a *direct argument* of an Apply. The placeholder being the
6420+
// receiver of an Apply (e.g. `_.substring(0, 1)`) is NOT partial application
6421+
// and must be handled as a regular underscore placeholder lambda.
6422+
val partialApplication: Option[Trees.Apply[?]] = func.body match {
6423+
case app: Trees.Apply[?] if app.args.exists {
6424+
case id: Trees.Ident[?] => syntheticParams.contains(id.name.toString)
6425+
case _ => false
6426+
} => Some(app)
6427+
case _ => None
6428+
}
6429+
6430+
partialApplication match {
6431+
case Some(app) =>
6432+
// Partially applied function - return the method invocation
6433+
val prefix = extractPrefix(func.span)
6434+
val result = visitApply(app)
6435+
result match {
6436+
case mi: J.MethodInvocation => return mi.withPrefix(prefix)
6437+
case _ => return result
64376438
}
6438-
case _ =>
6439-
// For other cases like `_ * 2`, this is an underscore placeholder lambda
6440-
// We need to create a proper lambda with S.Wildcard in the body
6439+
case None =>
6440+
// For all other cases (like `_ * 2` or `_.substring(0, 1)`),
6441+
// this is an underscore placeholder lambda.
6442+
// We need to create a proper lambda with S.Wildcard in the body.
64416443
val prefix = extractPrefix(func.span)
6442-
6444+
64436445
// Set a flag to indicate we're in an underscore placeholder context
64446446
val oldSyntheticParams = currentSyntheticParams
64456447
currentSyntheticParams = syntheticParams
6446-
6448+
64476449
// Visit the body - the visitIdent method will now create S.Wildcard for synthetic params
64486450
val body = visitTree(func.body)
6449-
6451+
64506452
// Restore the flag
64516453
currentSyntheticParams = oldSyntheticParams
6452-
6454+
64536455
// Create a wildcard parameter for the lambda parameter list
64546456
val wildcard = new S.Wildcard(
64556457
Tree.randomId(),
64566458
Space.EMPTY,
64576459
Markers.EMPTY,
64586460
null
64596461
)
6460-
6462+
64616463
val params = new util.ArrayList[JRightPadded[J]]()
64626464
params.add(JRightPadded.build(wildcard))
6463-
6465+
64646466
val parameters = new J.Lambda.Parameters(
64656467
Tree.randomId(),
64666468
Space.EMPTY,
64676469
Markers.EMPTY,
64686470
false, // no parentheses for underscore syntax
64696471
params
64706472
)
6471-
6473+
64726474
// Create lambda with the underscore placeholder marker
64736475
val lambda = new J.Lambda(
64746476
Tree.randomId(),
@@ -6479,7 +6481,7 @@ class ScalaTreeVisitor(
64796481
body,
64806482
null
64816483
)
6482-
6484+
64836485
return lambda
64846486
}
64856487
}

rewrite-scala/src/test/java/org/openrewrite/scala/tree/LambdaTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,21 @@ void lambdaWithUnderscore() {
7676
);
7777
}
7878

79+
@Test
80+
void lambdaWithUnderscoreMethodCall() {
81+
rewriteRun(
82+
scala(
83+
"""
84+
object Test {
85+
val xs: List[String] = Nil
86+
xs.map(_.substring(0, 1))
87+
xs.map(_.substring(0, 1)).mkString
88+
}
89+
"""
90+
)
91+
);
92+
}
93+
7994
@Test
8095
void lambdaWithBlock() {
8196
rewriteRun(

0 commit comments

Comments
 (0)