swift: Partial block result builder fails to pick correct overload and generates compiler error
Description
Partial block result builder fails to pick correct overload and generates a compiler error Ambiguous use of 'parser(of:)'
Steps to reproduce Paste the following code into a new project (This issue is a reduction of trying to compile an example (final 4 lines of the code below) of the swift-parsing package)
//MARK: Parsers
@rethrows public protocol Parser<Input> {
associatedtype Input
}
extension String: Parser {
public typealias Input = Substring
}
extension Int {
static func parser(
of inputType: Substring.Type = Substring.self
) -> FromSubstringToUTF8<IntParser<Substring.UTF8View>> {
FromSubstringToUTF8 { IntParser<Substring.UTF8View>() }
}
static func parser(
of inputType: Substring.UTF8View.Type = Substring.UTF8View.self
) -> IntParser<Substring.UTF8View> {
.init()
}
}
struct FromSubstringToUTF8<P: Parser>: Parser where P.Input == Substring.UTF8View {
typealias Input = Substring
let parser: P
init(@ParserBuilder _ build: () -> P) { self.parser = build() }
}
struct IntParser<Input: Collection>: Parser where Input.SubSequence == Input, Input.Element == UTF8.CodeUnit {
public init() { }
}
//MARK: ParserBuilder
struct Parse<Parsers: Parser>: Parser {
typealias Input = Parsers.Input
let parsers: Parsers
init(@ParserBuilder with build: () -> Parsers) { self.parsers = build() }
}
@resultBuilder
struct ParserBuilder {
public static func buildPartialBlock<P: Parser>(first: P) -> P { first }
public static func buildPartialBlock<P0, P1>(accumulated: P0, next: P1) -> SkipFirst<P0, P1> {
.init(p0: accumulated, p1: next)
}
}
struct SkipFirst<P0: Parser, P1: Parser>: Parser where P0.Input == P1.Input {
typealias Input = P0.Input
let p0: P0
let p1: P1
}
//MARK: main
let first = ParserBuilder.buildPartialBlock(first: ",")
let second = ParserBuilder.buildPartialBlock(accumulated: first, next: Int.parser())
let parser = Parse {
","
Int.parser() // Ambiguous use of 'parser(of:)'
}
Expected behavior
This compiles for toolchain 2023-01-02 but breaks from 2023-01-07.
Expected to compile and choose the correct overload (in this case static func parser(of inputType: Substring.Type = Substring.self))
Since the first parser passed to the resultBuilder closure is of type String therefore the Parser associated type Input is of type Substring. Therefore the compiler should be able to infer that the parser returned by Int.parser() should have an Input of Substring as well.
Calling the individual partialBuildBlock functions does compile works:
let first = ParserBuilder.buildPartialBlock(first: ",")
let second = ParserBuilder.buildPartialBlock(accumulated: first, next: Int.parser())
fails:
let parser = Parse {
","
Int.parser() // Ambiguous use of 'parser(of:)'
}
Environment
- Swift compiler version info Swift Development Snapshot 2023-01-09
- Xcode version info Xcode 13.4.1 Build version 13F100
- Deployment target: M1 running macOS 12.5
About this issue
- Original URL
- State: closed
- Created a year ago
- Comments: 81 (81 by maintainers)
@xedin Wow! Thanks! That actually gets the one regression in our test suite building again without needing to be explicit with
\State.pathand allowing abbreviation in\.pathagain!https://github.com/pointfreeco/swift-composable-architecture/commit/feae99aa459f47962a01289682ee8468e2dc969a
The implementation is https://github.com/apple/swift/pull/60065 and there are a few smaller follow-up PRs. Enablement is https://github.com/apple/swift/pull/62734. I’m also working on a forums post to announce the change and describe some of the situations that were allowed before but wouldn’t be now.
@stephencelis I actually found a solution for
CombineReducersproblem (based onbuilder-updatesbranch):Adding this indirection for State/Action generic parameter makes sure that when
CombineReducers()is wrapped inbuildExpressiondeclared as:StateActioncould be infer for it based on the “builder self”:ReducerBuilder<State, Action>.builderExpression(CombineReducers())whereStateandActionare struct and enum from your example.Example you have posted previously type-checks with these changes.
This is definitely helpful! While we knew a lot of changes we needed to make based off more recent result builder projects we’ve taken on, this thread provided a lot of additional food for thought. Thanks, @xedin!
No problem! I’m going to resolve this one, feel free to reach out on forums as well if you need more help with result builders.