Skip to content

Incorrectly removing empty trailing closure parentheses in a curried call #1070

@a7medev

Description

@a7medev

Problem

When calling swift-format on the following code

func perform() -> (() -> Void) -> Void {
  return { body in
    body()
  }
}

perform()() {
  print("Hello world")
}

It produces the following code (notice the () removed at the perform call)

func perform() -> (() -> Void) -> Void {
  return { body in
    body()
  }
}

perform() {
  print("hi")
}

This code doesn't compile and produces the following diagnostic.

File.swift:7:11: error: extra trailing closure passed in call
 5 | }
 6 | 
 7 | perform() {
   |           `- error: extra trailing closure passed in call
 8 |   print("Hello world")
 9 | }

The above example is also easily reproducible with implicitly-curried instance methods as in the following example.

struct Executor {
  func execute(body: () throws -> Void) rethrows {
    body()
  }
}

let executor = Executor()

Executor.execute(executor)() { }

Proposed Solution

swift-format should only remove empty function arguments () before a trailing closure when the FunctionCallExpr's callee is not a FunctionCallExpr nor a SubscriptCallExpr to avoid incorrectly associating the trailing closure with the callee.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions