Confusing compilation error with buildBlock with single argument

Why do I get that error? I use Xcode 11.1.

let result = Node(UIView()) {
    Node(UIView()) {
        // Referencing initializer 'init(_:subnodes:)' on 'Node' 
        // requires that 'Node<UIView, EmptySubnodes>' conform to '_Subnodes'
        Node(UIView())
    }
    Node(UIView())
    Node(UIView())
}

Builder implementation:

@_functionBuilder
class NodeBuilder {
    static func buildBlock() -> EmptySubnodes {
        return EmptySubnodes()
    }

    static func buildBlock<T0: _Node>(_ node0: T0) -> Subnodes1<T0> {
        return Subnodes1(node0: node0)
    }

    static func buildBlock<T0: _Node, T1: _Node>(_ node0: T0, _ node1: T1) -> Subnodes2<T0, T1> {
        return Subnodes2(node0: node0, node1: node1)
    }

    static func buildBlock<T0: _Node, T1: _Node, T2: _Node>(_ node0: T0, _ node1: T1, _ node2: T2) -> Subnodes3<T0, T1, T2> {
        return Subnodes3(node0: node0, node1: node1, node2: node2)
    }
}

protocol _Node {
    var nodeView: UIView { get }
}

struct Node<View: UIView, Subnodes: _Subnodes>: _Node {
    let view: View
    let subnodes: Subnodes

    var nodeView: UIView {
        for subview in subnodes.views {
            view.addSubview(subview)
        }
        return view
    }

    init(_ view: View, @NodeBuilder subnodes: () -> Subnodes) {
        self.view = view
        self.subnodes = subnodes()
    }

    func modify(_ closure: (View) -> Void) -> Self {
        closure(view)
        return self
    }
}

struct EmptySubnodes: _Subnodes {
    let views: [UIView] = []
}

extension Node where Subnodes == EmptySubnodes {
    init(_ view: View) {
        self.init(view) { EmptySubnodes() }
    }
}

extension Node where Subnodes: _Subnodes2 {
    func layout(_ closure: (View, Subnodes.N0, Subnodes.N1) -> Void) -> Self {
        closure(view, subnodes.node0, subnodes.node1)
        return self
    }
}

extension Node where Subnodes: _Subnodes3 {
    func layout(_ closure: (View, Subnodes.N0, Subnodes.N1, Subnodes.N2) -> Void) -> Self {
        closure(view, subnodes.node0, subnodes.node1, subnodes.node2)
        return self
    }
}


protocol _Subnodes {
    var views: [UIView] { get }
}

protocol _Subnodes1: _Subnodes {
    associatedtype N0: _Node

    var node0: N0 { get }
}

struct Subnodes1<N0: _Node>: _Subnodes1 {
    var node0: N0

    var views: [UIView] {
        [
            node0.nodeView
        ]
    }
}

protocol _Subnodes2: _Subnodes {
    associatedtype N0: _Node
    associatedtype N1: _Node

    var node0: N0 { get }
    var node1: N1 { get }
}

struct Subnodes2<N0: _Node, N1: _Node>: _Subnodes2 {
    var node0: N0
    var node1: N1

    var views: [UIView] {
        [
            node0.nodeView,
            node1.nodeView
        ]
    }
}

protocol _Subnodes3: _Subnodes {
    associatedtype N0: _Node
    associatedtype N1: _Node
    associatedtype N2: _Node

    var node0: N0 { get }
    var node1: N1 { get }
    var node2: N2 { get }
}

struct Subnodes3<N0: _Node, N1: _Node, N2: _Node>: _Subnodes3 {
    var node0: N0
    var node1: N1
    var node2: N2

    var views: [UIView] {
        [
            node0.nodeView,
            node1.nodeView,
            node2.nodeView
        ]
    }
}
1 Like

This

    Node(UIView()) {
        // Referencing initializer 'init(_:subnodes:)' on 'Node' 
        // requires that 'Node<UIView, EmptySubnodes>' conform to '_Subnodes'
        Node(UIView())
    }

seems to not be using function builder, but a single-expression function returning Node, which doesn't conform to Subnodes. Empty closure seems to have the same problem.

This could some weird interaction between (the current implementation of) function builder & SE-0255 Implicit returns from single-expression functions.

1 Like

Unfortunately, it does. Does it make sense to fill a bug about private feature? If so, where I can do this?

1 Like