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.path
and allowing abbreviation in\.path
again!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
CombineReducers
problem (based onbuilder-updates
branch):Adding this indirection for State/Action generic parameter makes sure that when
CombineReducers()
is wrapped inbuildExpression
declared as:State
Action
could be infer for it based on the “builder self”:ReducerBuilder<State, Action>.builderExpression(CombineReducers())
whereState
andAction
are 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.