Multiline closure is not inferring the return type

Hi Guys,
I noticed a strange behaviour in the complier. It seems like the compiler is not able to infer the return type if the closure contains multiple lines of code.

Heres my class and methods looks like,

public class SnapshotWorkItem<V> where V: UIResponder {
    let content: () -> V
    private(set) var visible: (V -> Void)?

    public init(_ content: @escaping () -> V) {
        self.content = content
    }

    public func onVisible(_ visible: @escaping (V) -> Void) -> Self {
        self.visible = visible
        return self
    }
}

// Snapshot base class
extension BaseTestCase {
    func snapshot<C>(_ item: () -> SnapshotWorkItem<C>) where C: UIResponder {
        // create snapshot
    }
}

I am using the above in my unite test like below,

func testDetailsView() {
    snapshot {
        SnapshotWorkItem {
            let view = DetailedAnnouncementView(frame: frame)
            view.configure(model)
            return view
        }.onVisible  { view in
            🛑 // ERROR: Value of type 'UIResponder' has no member 'announcementScrollView'
            print(view.announcementScrollView.frame)
        }
    }
}

The above code throws a compiler error on .onVisible { }, as it is not able to infer the return type.

However, the compiler seems to be happy if I use implicit return in the first closer, something like this,

func testDetailsView() {
    snapshot {
        SnapshotWorkItem {
            DetailedAnnouncementView(frame: frame)
        }.onVisible  { view in
             ✅ // Works fine
            print(view.announcementScrollView.frame)
        }
    }
}

It looks like the compiler is not able to infer the return type from multiline closures. I don't know if i am doing something wrong, can some please help with this :slight_smile:. Thanks in advance.

To add to that,

I have created a helper method the chain the mutation of my view's properties,

// Helper method
extension DetailedAnnouncementView {
    func setModel(_ model: AnnouncementModel) -> Self {
        self.configure(model)
        return self
    }
}

// Updated Test
func testDetailsView() {
    snapshot {
        SnapshotWorkItem {
            DetailedAnnouncementView(frame: frame)
                .setModel(model)
        }.onVisible  { view in
             ✅ // Works fine
            print(view.announcementScrollView.frame)
        }
    }
}

This seems to be working fine. This compiler seems to be happy.

That is correct; you are doing nothing wrong. This may change in a future version of Swift. See here for more details:

1 Like

Hi Xiaodi Wu,
Thanks for the response. Good to know that I am not doing something wrong. I might go with "chaining helper method" approach which I mentioned in my second comment.

Also it is good to know that, "giving the closure an explicit signature" works too.

1 Like

There is also some information in this older discussion: Streamlining closures, e.g. from Jordan Rose:

Swift's type inference is currently statement-oriented, so there's no easy way to do this inference. This is at least partly a compilation-time concern: Swift's type system allows many more possible conversions than, say, Haskell or OCaml, so solving the types for an entire multi-statement function is not a trivial problem, possibly not a tractable problem.