Troubleshooting result builders

What techniques are there for figuring out errors with result builders? I'm working on a somewhat complex one using buildPartialBlock to enforce elements appearing in a certain order, and at the moment I'm having trouble with how that interacts with buildOptional. I anticipate running into more such issues as I flesh it out, so I'm looking for general result-builder-debugging pointers.

It's tricky because the compiler errors are based on the behind-the-scenes generated code, rather than on the code I'm looking at. Is it possible to see that generated code? Or does the compiler not quite work that way?

At the moment, I have an error right at the beginning of the call to the result builder saying "type of expression is ambiguous without more context". Right back at you, says I :sweat_smile:

5 Likes

As far as I know, there’s no way to see what’s generated. I spent a fair amount of time referring back to Becca Dax’s WWDC video (the visuals do a wonderful job of showing what gets generated).

There’s definitely a pattern to it that makes sense after a bit of time, but it took me some
time and experimentation to get the hang of how all the pieces hang together - and how to structure code to work with it.

1 Like

Try using -print-ast flag passed to swiftc, courtesy of @LouisD and @hamishknight.

Assuming your builders.swift contains this

import SwiftUI

struct V: View {
    var body: some View {
        HStack {
            Text("test1")
            Text("test2")
        }
    }
}

then swiftc -print-ast builders.swift will output this

import SwiftUI

internal struct V : View {
  @MainActor internal var body: some View {
    get {

      private var $__builder1: HStack<TupleView<(Text, Text)>>

      private var $__builder0: HStack<TupleView<(Text, Text)>> = HStack<TupleView<(Text, Text)>>()
      $__builder1 = ViewBuilder.buildBlock($__builder0)
      return $__builder1
    }
  }
  internal typealias Body = some View
  internal init() {

  }
}

As you can see, it applies substitutions for typealiases as well. This also works for checking what Codable, Hashable, and Equatable conformances were synthesized.

9 Likes

Yeah initial support for printing expressions through -print-ast was added in https://github.com/apple/swift/pull/40691. Not all expressions are currently handled (most notably the closure body for HStack in Max's example above), I've filed Fill out unimplemented expression cases in the ASTPrinter · Issue #61601 · apple/swift · GitHub to track the implementation of the rest of the expression nodes.

6 Likes

swift -print-ast unfortunately isn't working for me. The first problem is that it only prints the result if the processed result builder code actually compiles, and my issue is that often it doesn't compile and I'm trying to figure out why, which is why I want to see the code.

The other problem is that, once I got it compiling, it doesn't even print the result builder code anyway. For example, it turned this:

    let c1 = Context("examples only") {
        It("does the thing") {}
        It("does the thing") {}
    }

into simply this:

  @_hasInitialValue internal let c1: Context = Context("examples only", )

Is there something else I missed to get this to work?

1 Like

Could this be the consequence of some expression cases not implemented, as listed in this issue? Fill out unimplemented expression cases in the ASTPrinter · Issue #61601 · apple/swift · GitHub