[Parse] Ban trailing space for /.../ regex literals

Ban space and tab as the last character of a
`/.../` regex literal, unless escaped with a
backslash. This matches the banning of space and
tab as the first character, and helps avoid breaking
source in even more cases.
This commit is contained in:
Hamish Knight
2022-06-23 20:38:28 +01:00
parent 91e27adb7c
commit 8d59eb08df
8 changed files with 229 additions and 116 deletions

View File

@@ -1,4 +1,4 @@
// RUN: %target-typecheck-verify-swift -enable-bare-slash-regex -disable-availability-checking
// RUN: %target-typecheck-verify-swift -enable-bare-slash-regex -disable-availability-checking -typo-correction-limit 0
// REQUIRES: swift_in_compiler
// REQUIRES: concurrency
@@ -6,7 +6,7 @@ prefix operator /
prefix operator ^/
prefix operator /^/
prefix func ^/ <T> (_ x: T) -> T { x } // expected-note {{'^/' declared here}}
prefix func ^/ <T> (_ x: T) -> T { x }
prefix operator !!
prefix func !! <T>(_ x: T) -> T { x }
@@ -93,16 +93,31 @@ _ = /x/!.blah
// expected-error@-1 {{cannot force unwrap value of non-optional type 'Regex<Substring>'}}
// expected-error@-2 {{value of type 'Regex<Substring>' has no member 'blah'}}
_ = /x /? // expected-error {{cannot use optional chaining on non-optional value of type 'Regex<Substring>'}}
do {
_ = /x /?
.blah
// expected-error@-2 {{cannot find operator '/?' in scope}}
// expected-error@-3 {{'/' is not a prefix unary operator}}
}
_ = /x/? // expected-error {{cannot use optional chaining on non-optional value of type 'Regex<Substring>'}}
.blah // expected-error {{value of type 'Regex<Substring>' has no member 'blah'}}
_ = 0; /x / // expected-warning {{regular expression literal is unused}}
_ = 0; /x/ // expected-warning {{regular expression literal is unused}}
_ = /x / ? 0 : 1 // expected-error {{cannot convert value of type 'Regex<Substring>' to expected condition type 'Bool'}}
_ = .random() ? /x / : .blah // expected-error {{type 'Regex<Substring>' has no member 'blah'}}
do {
_ = 0; /x /
} // expected-error {{expected expression after operator}}
_ = /x/ ? 0 : 1 // expected-error {{cannot convert value of type 'Regex<Substring>' to expected condition type 'Bool'}}
do {
_ = /x / ? 0 : 1 // expected-error@:12 {{expected expression after operator}}
}
_ = .random() ? /x/ : .blah // expected-error {{type 'Regex<Substring>' has no member 'blah'}}
_ = /x/ ?? /x/ // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'Regex<Substring>', so the right side is never used}}
_ = /x / ?? /x / // expected-warning {{left side of nil coalescing operator '??' has non-optional type 'Regex<Substring>', so the right side is never used}}
do {
_ = /x / ?? /x / // expected-error {{unary operator cannot be separated from its operand}}
} // expected-error {{expected expression after operator}}
_ = /x/??/x/ // expected-error {{'/' is not a postfix unary operator}}
@@ -112,10 +127,17 @@ _ = /x/.../y/
// expected-error@-1 {{missing whitespace between '...' and '/' operators}}
// expected-error@-2 {{'/' is not a postfix unary operator}}
_ = /x /...
_ = /x/...
// expected-error@-1 {{unary operator '...' cannot be applied to an operand of type 'Regex<Substring>'}}
// expected-note@-2 {{overloads for '...' exist with these partially matching parameter lists}}
do {
_ = /x /...
// expected-error@-1 {{'/' is not a prefix unary operator}}
// expected-error@-2 {{consecutive statements on a line must be separated by ';'}}
// expected-error@-3 {{operator with postfix spacing cannot start a subexpression}}
} // expected-error {{expected expression}}
do {
_ = true / false /; // expected-error {{expected expression after operator}}
}
@@ -124,19 +146,30 @@ _ = "\(/x/)"
func defaulted(x: Regex<Substring> = /x/) {}
func foo<T>(_ x: T, y: T) {}
func foo<T>(_ x: T, y: T) {} // expected-note {{'foo(_:y:)' declared here}}
foo(/abc/, y: /abc/)
// TODO: The parser ought to have better recovery in cases where a binary
// operator chain is missing an operand, currently we throw everything away.
foo(/abc/, y: /abc /)
// expected-error@-1:21 {{expected expression after operator}}
// expected-error@-2 {{missing argument for parameter 'y' in call}}
func bar<T>(_ x: inout T) {}
bar(&/x/) // expected-error {{cannot pass immutable value as inout argument: literals are not mutable}}
struct S {
subscript(x: Regex<Substring>) -> Void { () }
subscript(x: Regex<Substring>) -> Void { () } // expected-note {{'subscript(_:)' declared here}}
subscript(fn: (Int, Int) -> Int) -> Int { 0 }
}
func testSubscript(_ x: S) {
x[/x/]
x[/x /]
// expected-error@-1:9 {{expected expression after operator}}
// expected-error@-2 {{missing argument for parameter #1 in call}}
_ = x[/] / 2
}
func testReturn() -> Regex<Substring> {
@@ -144,19 +177,30 @@ func testReturn() -> Regex<Substring> {
return /x/
}
return /x /
}
} // expected-error {{expected expression after operator}}
func testThrow() throws {
throw /x / // expected-error {{thrown expression type 'Regex<Substring>' does not conform to 'Error'}}
throw /x/ // expected-error {{thrown expression type 'Regex<Substring>' does not conform to 'Error'}}
}
_ = [/abc/, /abc /]
do {
_ = [/abc/, /abc /] // expected-error@:21 {{expected expression after operator}}
}
do {
_ = [/abc /: /abc /]
// expected-error@-1:14 {{expected expression after operator}}
}
_ = [/abc/:/abc/] // expected-error {{generic struct 'Dictionary' requires that 'Regex<Substring>' conform to 'Hashable'}}
_ = [/abc/ : /abc/] // expected-error {{generic struct 'Dictionary' requires that 'Regex<Substring>' conform to 'Hashable'}}
_ = [/abc /:/abc /] // expected-error {{generic struct 'Dictionary' requires that 'Regex<Substring>' conform to 'Hashable'}}
_ = [/abc /: /abc /] // expected-error {{generic struct 'Dictionary' requires that 'Regex<Substring>' conform to 'Hashable'}}
_ = (/abc/, /abc /)
_ = ((/abc /))
_ = [/abc/:/abc/] // expected-error {{generic struct 'Dictionary' requires that 'Regex<Substring>' conform to 'Hashable'}}
_ = [/abc/: /abc/] // expected-error {{generic struct 'Dictionary' requires that 'Regex<Substring>' conform to 'Hashable'}}
_ = (/abc/, /abc/)
_ = ((/abc/))
do {
_ = ((/abc /))
// expected-error@-1:15 {{expected expression after operator}}
}
_ = { /abc/ }
_ = {
@@ -169,9 +213,15 @@ let _: () -> Int = {
2
}
let _: () -> Int = {
0
/1 / // expected-error {{'/' is not a prefix unary operator}}
2
}
_ = {
0 // expected-warning {{integer literal is unused}}
/1 / // expected-warning {{regular expression literal is unused}}
/1/ // expected-warning {{regular expression literal is unused}}
2 // expected-warning {{integer literal is unused}}
}
@@ -188,7 +238,11 @@ _ = 2
_ = 2
/1 /
.bitWidth // expected-error {{value of type 'Regex<Substring>' has no member 'bitWidth'}}
.bitWidth
// expected-error@-2 {{'/' is not a prefix unary operator}}
_ = !!/1/ .bitWidth // expected-error {{value of type 'Regex<Substring>' has no member 'bitWidth'}}
_ = !!/1 / .bitWidth // expected-error {{cannot find operator '!!/' in scope}}
let z =
/y/
@@ -201,25 +255,25 @@ _ = 0 . / 1 / 2 // expected-error {{expected member name following '.'}}
switch "" {
case /x/:
break
case _ where /x /:
case _ where /x/:
// expected-error@-1 {{cannot convert value of type 'Regex<Substring>' to expected condition type 'Bool'}}
break
default:
break
}
do {} catch /x / {}
do {} catch /x/ {}
// expected-error@-1 {{expression pattern of type 'Regex<Substring>' cannot match values of type 'any Error'}}
// expected-error@-2 {{binary operator '~=' cannot be applied to two 'any Error' operands}}
// expected-warning@-3 {{'catch' block is unreachable because no errors are thrown in 'do' block}}
switch /x / {
switch /x/ {
default:
break
}
if /x / {} // expected-error {{cannot convert value of type 'Regex<Substring>' to expected condition type 'Bool'}}
if /x /.smth {} // expected-error {{value of type 'Regex<Substring>' has no member 'smth'}}
if /x/ {} // expected-error {{cannot convert value of type 'Regex<Substring>' to expected condition type 'Bool'}}
if /x/.smth {} // expected-error {{value of type 'Regex<Substring>' has no member 'smth'}}
func testGuard() {
guard /x/ else { return } // expected-error {{cannot convert value of type 'Regex<Substring>' to expected condition type 'Bool'}}
@@ -231,20 +285,26 @@ typealias Magic<T> = T
_ = /x/ as Magic
_ = /x/ as! String // expected-warning {{cast from 'Regex<Substring>' to unrelated type 'String' always fails}}
_ = type(of: /x /)
_ = type(of: /x/)
do {
let /x / // expected-error {{expected pattern}}
let /x/ // expected-error {{expected pattern}}
}
_ = try /x/; _ = try /x /
// expected-warning@-1 2{{no calls to throwing functions occur within 'try' expression}}
_ = try? /x/; _ = try? /x /
// expected-warning@-1 2{{no calls to throwing functions occur within 'try' expression}}
_ = try! /x/; _ = try! /x /
// expected-warning@-1 2{{no calls to throwing functions occur within 'try' expression}}
do {
_ = try /x/; _ = try /x /
// expected-warning@-1 {{no calls to throwing functions occur within 'try' expression}}
} // expected-error {{expected expression after operator}}
do {
_ = try? /x/; _ = try? /x /
// expected-warning@-1 {{no calls to throwing functions occur within 'try' expression}}
} // expected-error {{expected expression after operator}}
do {
_ = try! /x/; _ = try! /x /
// expected-warning@-1 {{no calls to throwing functions occur within 'try' expression}}
} // expected-error {{expected expression after operator}}
_ = await /x / // expected-warning {{no 'async' operations occur within 'await' expression}}
_ = await /x/ // expected-warning {{no 'async' operations occur within 'await' expression}}
/x/ = 0 // expected-error {{cannot assign to value: literals are not mutable}}
/x/() // expected-error {{cannot call value of non-function type 'Regex<Substring>'}}
@@ -263,23 +323,24 @@ _ = /x/*comment*/
// MARK: Unapplied operators
// These become regex literals, unless surrounded in parens.
func baz(_ x: (Int, Int) -> Int, _ y: (Int, Int) -> Int) {} // expected-note 4{{'baz' declared here}}
// These become regex literals, unless last character is space, or are surrounded in parens.
func baz(_ x: (Int, Int) -> Int, _ y: (Int, Int) -> Int) {} // expected-note 3{{'baz' declared here}}
baz(/, /)
// expected-error@-1 {{cannot convert value of type 'Regex<Substring>' to expected argument type '(Int, Int) -> Int'}}
// expected-error@-2 {{missing argument for parameter #2 in call}}
baz(/,/)
// expected-error@-1 {{cannot convert value of type 'Regex<Substring>' to expected argument type '(Int, Int) -> Int'}}
// expected-error@-2 {{missing argument for parameter #2 in call}}
baz((/), /)
baz(/^, /)
baz(/^,/)
// expected-error@-1 {{cannot convert value of type 'Regex<Substring>' to expected argument type '(Int, Int) -> Int'}}
// expected-error@-2 {{missing argument for parameter #2 in call}}
baz((/^), /)
baz(^^/, /) // expected-error {{missing argument for parameter #2 in call}}
baz(^^/, /)
baz(^^/,/) // expected-error {{missing argument for parameter #2 in call}}
baz((^^/), /)
func bazbaz(_ x: (Int, Int) -> Int, _ y: Int) {}
@@ -290,8 +351,10 @@ func qux<T>(_ x: (Int, Int) -> Int, _ y: T) -> Int { 0 }
_ = qux(/, 1) / 2
do {
_ = qux(/, "(") / 2
_ = qux(/, "(")/2
// expected-error@-1 {{cannot convert value of type 'Regex<(Substring, Substring)>' to expected argument type '(Int, Int) -> Int'}}
// expected-error@-2:21 {{expected ',' separator}}
// expected-error@-2:19 {{expected ',' separator}}
}
_ = qux((/), "(") / 2
_ = qux(/, 1) // this comment tests to make sure we don't try and end the regex on the starting '/' of '//'.
@@ -396,6 +459,21 @@ _ = /./
// You need to escape if you want a regex literal to start with these characters.
_ = /\ /
_ = / / // expected-error {{regex literal may not start with space; add backslash to escape}} {{6-6=\}}
_ = / /
// expected-error@-1 {{regex literal may not start with space; add backslash to escape}} {{6-6=\}}
// expected-error@-2 {{regex literal may not end with space; use extended literal instead}} {{5-5=#}} {{9-9=#}}
_ = #/ /#
_ = /x\ /
_ = /\ \ /
// There are intentionally trailing spaces here
_ = /
// expected-error@-1 {{unterminated regex literal}}
// expected-error@-2 {{regex literal may not start with space; add backslash to escape}} {{6-6=\}}
// There are intentionally trailing spaces here
_ = /^
// expected-error@-1 {{unterminated regex literal}}
_ = /\)/
_ = /)/ // expected-error {{closing ')' does not balance any groups openings}}