From e6f38966d13dcef90e7b640e7c09daa29aff77a8 Mon Sep 17 00:00:00 2001 From: Richard Wei Date: Mon, 20 Jun 2022 00:13:31 -0700 Subject: [PATCH] Make unary builder return `Regex` type consistently. Currently, unary regex component builder simply forwards the component's base type. However, this is inconsistent with non-unary builder results. The current behavior may lead to surprising results when the user marks a property with `@RegexComponentBuilder`. This patch makes `RegexComponentBuilder.buildPartialBlock(first: R)` return a `Regex` rather than `R` itself. --- Before: ```swift // error: cannot convert value of type 'OneOrMore' to specified type 'Regex' @RegexComponentBuilder var r: Regex { OneOrMore("a") // Adding other components below will make the error go away. } struct MyCustomRegex: RegexComponent { // error: cannot convert value of type 'OneOrMore' to specified type 'Regex' var regex: Regex { OneOrMore("a") } } ``` After: No errors. --- Sources/RegexBuilder/Builder.swift | 6 ++++-- Tests/RegexBuilderTests/RegexDSLTests.swift | 22 ++++++++++++++++++++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/Sources/RegexBuilder/Builder.swift b/Sources/RegexBuilder/Builder.swift index a50f069ec..dfafd3803 100644 --- a/Sources/RegexBuilder/Builder.swift +++ b/Sources/RegexBuilder/Builder.swift @@ -18,8 +18,10 @@ public enum RegexComponentBuilder { .init(node: .empty) } - public static func buildPartialBlock(first: R ) -> R { - first + public static func buildPartialBlock( + first component: R + ) -> Regex { + component.regex } public static func buildExpression(_ regex: R) -> R { diff --git a/Tests/RegexBuilderTests/RegexDSLTests.swift b/Tests/RegexBuilderTests/RegexDSLTests.swift index 5b3914e3b..fc31e575f 100644 --- a/Tests/RegexBuilderTests/RegexDSLTests.swift +++ b/Tests/RegexBuilderTests/RegexDSLTests.swift @@ -1015,7 +1015,7 @@ class RegexDSLTests: XCTestCase { XCTAssertEqual(str.wholeMatch(of: parser)?.1, version) } } - + func testZeroWidthConsumer() throws { struct Trace: CustomConsumingRegexComponent { typealias RegexOutput = Void @@ -1051,6 +1051,26 @@ class RegexDSLTests: XCTestCase { """) } + + func testRegexComponentBuilderResultType() { + // Test that the user can declare a closure or computed property marked with + // `@RegexComponentBuilder` with `Regex` as the result type. + @RegexComponentBuilder + var unaryWithSingleNonRegex: Regex { + OneOrMore("a") + } + @RegexComponentBuilder + var multiComponent: Regex { + OneOrMore("a") + "b" + } + struct MyCustomRegex: RegexComponent { + @RegexComponentBuilder + var regex: Regex { + OneOrMore("a") + } + } + } } extension Unicode.Scalar {