resultBuilder buildOptional issue

Normally, the following code cannot be compiled.

let a = 3
if let b = a { // ❌Error: Initializer for conditional binding must have Optional type, not 'Int'
...
}

But if we define a resultBuilder and implement buildOptional method, similar code can be compiled.

@resultBuilder
enum XBuilder {
    static func buildBlock(_: Int...) -> Int {
        0
    }

    static func buildOptional(_: Int?) -> Int {
        1
    }
}

func test(@XBuilder content: () -> Int) -> Int {
    content()
}

let a = 3
_ = test {
    if let b = a {
        b
    }
}

Is this the expected behavior of resultBuilder or a bug? Can anyone help me explain this grammar?

Test it on swift-5.6 and swift-5.7. (Unlikely to be related to SE0345)

Original Context

Found this strange grammar when coding with SwiftUI.

struct ContentView: View {
    @State var enable = true

    var body: some View {
        VStack {
            if let e = enable { // ✅ Working
                   Text("")
                    .onAppear {
                        test1() // ❌ Not working
                        test2 { // ✅ Working
                            if let e = $enable {
                                Text("1")
                            }
                        }
                    }
            }
        }
    }

    @ViewBuilder
    func test1() -> some View{
        if let e = $enable {
            Text("")
        }
    }
    
    func test2(@ViewBuilder content: () -> some View) -> some View{
        content()
    }
}
1 Like

The bug is confirmed to be fixed on Swift 5.8 with an error message "Initializer for conditional binding must have Optional type, not 'Int'" like the normal code.

Thanks you for the rewrite of ResultBuilder @xedin

See the post for more detail: Improved Result Builder Implementation in Swift 5.8 - #13 by xedin

And does it possible to add such code to the test case for ResultBuilder in case the bug regress on later Swift version?

And does it possible to add such code to the test case for ResultBuilder in case the bug regress on later Swift version?

Yeah, we do have test cases in the suite that make sure that we catch regressions with optional bindings in the future.

1 Like

Could you point which test case / test file covers this behavior?

Just do a quick search with the following 2 filters on Swift's main branch. I did not get the expected test case for it.

Filter 1: expected-error{{

// Expected test case

@resultBuilder
enum XBuilder {
    static func buildBlock(_: Int...) -> Int {
        0
    }

    static func buildOptional(_: Int?) -> Int {
        1
    }
}

func test(@XBuilder content: () -> Int) -> Int {
    content()
}

let a = 3
_ = test {
    if let b = a { //expected-error{{initializer for conditional binding must have Optional type, not 'Int'}}
        b
    }
}

validation-test/Sema/SwiftUI/mixed_swiftui_and_multistatement_closures.swift

New Filter: expected-error {{

Got it. I missed the space in it. Looks like both expected-error{{ and expected-error {{ are supported format for the test tool. I just searched the first one while ignored the second case :rofl:

Thank you for your reply.

No problem!