Kyle-Ye
(Kyle)
1
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
Kyle-Ye
(Kyle)
2
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?
xedin
(Pavel Yaskevich)
3
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
Kyle-Ye
(Kyle)
4
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
}
}
xedin
(Pavel Yaskevich)
5
validation-test/Sema/SwiftUI/mixed_swiftui_and_multistatement_closures.swift
Kyle-Ye
(Kyle)
6
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 
Thank you for your reply.