Skip to content

Commit 104b815

Browse files
committed
Use nil instead of .some(nil) for failed captures
Previously we would wrap a `nil` in `optionalCount - 1` outer layers of `.some(...)`. Change this to return an `optionalCount` nested optional with a top-level value of `nil`.
1 parent d5e6ad8 commit 104b815

File tree

2 files changed

+35
-13
lines changed

2 files changed

+35
-13
lines changed

Sources/_StringProcessing/Capture.swift

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,24 @@ func constructExistentialOutputComponent(
1717
component: (range: Range<String.Index>, value: Any?)?,
1818
optionalCount: Int
1919
) -> Any {
20-
let someCount: Int
21-
var underlying: Any
2220
if let component = component {
23-
underlying = component.value ?? input[component.range]
24-
someCount = optionalCount
21+
var underlying = component.value ?? input[component.range]
22+
for _ in 0 ..< optionalCount {
23+
func wrap<T>(_ x: T) {
24+
underlying = Optional(x) as Any
25+
}
26+
_openExistential(underlying, do: wrap)
27+
}
28+
return underlying
2529
} else {
26-
// Ok since we Any-box every step up the ladder
27-
underlying = Optional<Any>(nil) as Any
28-
someCount = optionalCount - 1
29-
}
30-
for _ in 0..<someCount {
31-
func wrap<T>(_ x: T) {
32-
underlying = Optional(x) as Any
30+
precondition(optionalCount > 0, "Must have optional type")
31+
func makeNil<T>(_ x: T.Type) -> Any {
32+
T?.none as Any
3333
}
34-
_openExistential(underlying, do: wrap)
34+
let underlyingTy = TypeConstruction.optionalType(
35+
of: Substring.self, depth: optionalCount - 1)
36+
return _openExistential(underlyingTy, do: makeNil)
3537
}
36-
return underlying
3738
}
3839

3940
@available(SwiftStdlib 5.7, *)

Tests/RegexBuilderTests/RegexDSLTests.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,8 @@ class RegexDSLTests: XCTestCase {
461461

462462
try _testDSLCaptures(
463463
("abcdef2", ("abcdef2", "f")),
464+
("2", ("2", nil)),
465+
("", ("", nil)),
464466
matchType: (Substring, Substring??).self, ==)
465467
{
466468
Optionally {
@@ -1262,6 +1264,25 @@ class RegexDSLTests: XCTestCase {
12621264

12631265
XCTAssertEqual(try replace("{bar}"), "foo")
12641266
}
1267+
1268+
func testOptionalNesting() throws {
1269+
let r = Regex {
1270+
Optionally {
1271+
Optionally {
1272+
Capture {
1273+
"a"
1274+
}
1275+
}
1276+
}
1277+
}
1278+
if let _ = try r.wholeMatch(in: "")!.output.1 {
1279+
XCTFail("Unexpected capture match")
1280+
}
1281+
if let _ = try r.wholeMatch(in: "a")!.output.1 {}
1282+
else {
1283+
XCTFail("Expected to match capture")
1284+
}
1285+
}
12651286
}
12661287

12671288
extension Unicode.Scalar {

0 commit comments

Comments
 (0)