Skip to content

Commit bdf9a60

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 4cbb932 commit bdf9a60

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
@@ -453,6 +453,8 @@ class RegexDSLTests: XCTestCase {
453453

454454
try _testDSLCaptures(
455455
("abcdef2", ("abcdef2", "f")),
456+
("2", ("2", nil)),
457+
("", ("", nil)),
456458
matchType: (Substring, Substring??).self, ==)
457459
{
458460
Optionally {
@@ -1254,6 +1256,25 @@ class RegexDSLTests: XCTestCase {
12541256

12551257
XCTAssertEqual(try replace("{bar}"), "foo")
12561258
}
1259+
1260+
func testOptionalNesting() throws {
1261+
let r = Regex {
1262+
Optionally {
1263+
Optionally {
1264+
Capture {
1265+
"a"
1266+
}
1267+
}
1268+
}
1269+
}
1270+
if let _ = try r.wholeMatch(in: "")!.output.1 {
1271+
XCTFail("Unexpected capture match")
1272+
}
1273+
if let _ = try r.wholeMatch(in: "a")!.output.1 {}
1274+
else {
1275+
XCTFail("Expected to match capture")
1276+
}
1277+
}
12571278
}
12581279

12591280
extension Unicode.Scalar {

0 commit comments

Comments
 (0)