Match.subscript fails to properly cast non-matched Capture
jasonbobier opened this issue · comments
This code should produce an Optional<Int>
. Instead it produces an Optional<Substring>
and crashes.
import RegexBuilder
let ref = Reference(Int.self)
let regex = Regex {
"test"
Optionally {
TryCapture(as: ref) {
OneOrMore(.digit)
} transform: {
Int($0)
}
}
"a"
}
let match = "testa".wholeMatch(of: regex)
print("Int \(match![ref])")
This aborts with:
Could not cast value of type 'Swift.Optional<Swift.Substring>' (0x1f2db92c0) to 'Swift.Int' (0x1f3da0bf0).
There a few things to notice here:
- By capture of
Int
beingOptionally
that means that anInt
for the capture may not happen at all, rendering the resultnil
so I think what you want is a reference for an optionalInt?
e.g.let ref = Reference(Int?.self)
which makes total sense meaning for "testa" for example no digit(which is optional) was captured meaningnil
. - Perhaps what you want instead of
Optionally
withTryCapture/OneOrMore
is simplyTryCapture/ZeroOrMore
With that said, I don't think there is a bug here(perhaps a better runtime error message), but I'm don't know much about regex feature so I'll let @hamishknight, @natecook1000, @Azoy take a look.
Nevermind... it works... I had tried:
let ref = Reference(Optional(Int).self)
and it didn't work.
Notice the typo... Sorry for the false bug. Grrrr...
@LucianoPAlmeida but it won't compile for Substring. For example this fails to compile:
import RegexBuilder
let ref = Reference(Substring?.self)
let regex = Regex {
"test"
Optionally {
Capture(as: ref) {
OneOrMore(.digit)
}
}
"a"
}
let match = "testa".wholeMatch(of: regex)
print("Substring \(match![ref])")
with an error of:
error: initializer 'init(as:_:)' requires the types 'Substring?' and 'Regex<OneOrMore<Substring>.RegexOutput>.RegexOutput' (aka 'Substring') be equivalent
and if I change the ref to:
let ref = Reference(Substring.self)
I get a runtime casting error:
Could not cast value of type 'Swift.Optional<Swift.Substring>' (0x1f2db10e0) to 'Swift.Substring' (0x1f3d9f530).
@LucianoPAlmeida but it won't compile for Substring. For example this fails to compile:
import RegexBuilder let ref = Reference(Substring?.self) let regex = Regex { "test" Optionally { Capture(as: ref) { OneOrMore(.digit) } } "a" } let match = "testa".wholeMatch(of: regex) print("Substring \(match![ref])")with an error of:
error: initializer 'init(as:_:)' requires the types 'Substring?' and 'Regex<OneOrMore<Substring>.RegexOutput>.RegexOutput' (aka 'Substring') be equivalent
and if I change the ref to:
let ref = Reference(Substring.self)
I get a runtime casting error:
Could not cast value of type 'Swift.Optional<Swift.Substring>' (0x1f2db10e0) to 'Swift.Substring' (0x1f3d9f530).
Have to look in more depth into it but initially applying a transform hack makes it compile.
import RegexBuilder
let ref = Reference(Substring?.self)
let regex = Regex {
"test"
Optionally {
Capture(as: ref) {
OneOrMore(.digit)
} transform: { $0 }
}
"a"
}
let match = "testa".wholeMatch(of: regex)
print("Substring \(match![ref])")
Looks like a type checker problem on matching Substring
and Substring?
.
This still fails on Xcode Version 15.0 beta (15A5160n).
This still fails with Xcode 15 final.