I just read the result builder proposal and had a question about how if-else
statements are transformed. I understand a variable vMerged
is declared before the statement and is then initialised from within the if-else
transform so it can be used as a partial result in the enclosing block. However, I came across a strange situation and I wasn't able to figure out how the transform would look.
typealias CSC = CustomStringConvertible
struct ConditionalString<T: CSC, F: CSC>: CSC {
var condition: Condition
var description: String { "would be self.condition.assocVal" }
enum Condition {
case isTrue(T)
case isFalse(F)
}
}
@resultBuilder
struct ConditionalStringBuilder {
static func buildBlock<T: CSC>(_ component: T) -> T {
return component
}
static func buildEither<A: CSC, B: CSC>(first component: A) -> ConditionalString<A, B> {
return ConditionalString(condition: .isTrue(component))
}
static func buildEither<C: CSC, D: CSC>(second component: D) -> ConditionalString<C, D> {
return ConditionalString(condition: .isFalse(component))
}
}
@ConditionalStringBuilder
func test() -> some CSC {
if Bool.random() {
false
} else {
"asdf"
}
}
let conditionalString = test()
print(type(of: conditionalString)) // Prints ConditionalString<Bool, String> to my surprise
I was expecting this to error. This is because I don't think it's possible for vMerged
to be given a type. Based on the proposal, this is what this transform would look like:
let vMerged: PartialResult // What is the type of PartialResult? It can't be (T || F). That's not valid
if Bool.random() {
var firstVar = false
var firstBlock = BuilderType.buildBlock(firstVar)
vMerged = BuilderType.buildEither(first: firstBlock). // What is the type of `B` here?
} else {
var elseVar = "asdf"
var elseBlock = BuilderType.buildBlock(elseVar)
vMerged = BuilderType.buildEither(second: elseBlock) // What is the type of `C` here?
}
return vMerged
According to the compiler, each buildEither
function could be returning a completely different type. So how is it inferring the type of vMerged
? Additionally, does it know the type at compile time or at run time? If someone can please explain a step-by-step process of how this all works it'll really clear up a lot.
Thanks.