Disable the ability to use '$' as an identifier harder

When in Swift 3 Compatibility Mode we now acceptable a standalone
'$' as an identifier.  In all other cases this is now disallowed
and must be surrounded by backticks.
This commit is contained in:
Robert Widmann
2016-10-13 11:47:05 -04:00
parent 23525d984a
commit 6accc5989e
5 changed files with 80 additions and 22 deletions

View File

@@ -994,7 +994,9 @@ ERROR(expected_dollar_numeric,none,
ERROR(dollar_numeric_too_large,none,
"numeric value following '$' is too large", ())
ERROR(numeric_literal_numeric_member,none,
"expected named member of numeric literal", ())
"expected named member of numeric literal", ())
ERROR(standalone_dollar_identifier,none,
"'$' is not an identifier; use backticks to escape it", ())
ERROR(anon_closure_arg_not_in_closure,none,
"anonymous closure argument not contained in a closure", ())

View File

@@ -28,7 +28,8 @@ using namespace swift;
using namespace camel_case;
bool swift::canBeArgumentLabel(StringRef identifier) {
if (identifier == "var" || identifier == "let" || identifier == "inout")
if (identifier == "var" || identifier == "let" || identifier == "inout" ||
identifier == "$")
return false;
return true;

View File

@@ -474,7 +474,7 @@ static bool isValidIdentifierContinuationCodePoint(uint32_t c) {
static bool isValidIdentifierStartCodePoint(uint32_t c) {
if (!isValidIdentifierContinuationCodePoint(c))
return false;
if (c < 0x80 && (isDigit(c) || c == '$'))
if (c < 0x80 && isDigit(c))
return false;
// N1518: Recommendations for extended identifier characters for C and C++
@@ -819,10 +819,15 @@ void Lexer::lexDollarIdent() {
}
}
// It's always an error to see a standalone $
if (CurPtr == tokStart + 1) {
diagnose(tokStart, diag::expected_dollar_numeric);
return formToken(tok::unknown, tokStart);
// It is always an error to see a standalone '$' when not in Swift 3
// compatibility mode.
if (!LangOpts.isSwiftVersion3()) {
// Offer to replace '$' with '`$`'.
diagnose(tokStart, diag::standalone_dollar_identifier)
.fixItReplaceChars(getSourceLoc(tokStart), getSourceLoc(CurPtr), "`$`");
}
return formToken(tok::identifier, tokStart);
}
// We reserve $nonNumeric for persistent bindings in the debugger.

View File

@@ -0,0 +1,23 @@
// RUN: %target-parse-verify-swift -swift-version 3
// Dollar is allowed as an identifier head in Swift 3.
func dollarVar() {
var $ : Int = 42 // No error
$ += 1
print($)
}
func dollarLet() {
let $ = 42 // No error
print($)
}
func dollarClass() {
class $ {} // No error
}
func dollarEnum() {
enum $ {} // No error
}
func dollarStruct() {
struct $ {} // No error
}

View File

@@ -1,29 +1,56 @@
// RUN: %target-parse-verify-swift
// RUN: %target-parse-verify-swift -swift-version 4
// SR-1661: Dollar was accidentally allowed as an identifier and identifier head.
// SR-1661: Dollar was accidentally allowed as an identifier in Swift 3.
// SE-0144: Reject this behavior in the future.
func dollarVar() {
var $ : Int = 42 // expected-error {{expected numeric value following '$'}} expected-error {{expected pattern}}
var $ : Int = 42 // expected-error {{'$' is not an identifier; use backticks to escape it}} {{7-8=`$`}}
$ += 1 // expected-error {{'$' is not an identifier; use backticks to escape it}} {{3-4=`$`}}
print($) // expected-error {{'$' is not an identifier; use backticks to escape it}} {{9-10=`$`}}
}
func dollarLet() {
let $ = 42 // expected-error {{expected numeric value following '$'}} expected-error {{expected pattern}}
let $ = 42 // expected-error {{'$' is not an identifier; use backticks to escape it}} {{7-8=`$`}}
print($) // expected-error {{'$' is not an identifier; use backticks to escape it}} {{9-10=`$`}}
}
func dollarClass() {
class $ {} // expected-error {{expected numeric value following '$'}}
// expected-error@-1 {{expression resolves to an unused function}}
// expected-error@-2 {{expected identifier in class declaration}}
// expected-error@-3 {{braced block of statements is an unused closure}}
class $ {} // expected-error {{'$' is not an identifier; use backticks to escape it}} {{9-10=`$`}}
}
func dollarEnum() {
enum $ {} // expected-error {{expected numeric value following '$'}}
// expected-error@-1 {{expected identifier in enum declaration}}
// expected-error@-2 {{expression resolves to an unused function}}
// expected-error@-3 {{braced block of statements is an unused closure}}
enum $ {} // expected-error {{'$' is not an identifier; use backticks to escape it}} {{8-9=`$`}}
}
func dollarStruct() {
struct $ {} // expected-error {{expected numeric value following '$'}}
// expected-error@-1 {{expected identifier in struct declaration}}
// expected-error@-2 {{braced block of statements is an unused closure}}
// expected-error@-3 {{expression resolves to an unused function}}
struct $ {} // expected-error {{'$' is not an identifier; use backticks to escape it}} {{10-11=`$`}}
}
func dollarFunc() {
func $($ dollarParam: Int) {}
// expected-error@-1 {{'$' is not an identifier; use backticks to escape it}} {{8-9=`$`}}
// expected-error@-2 {{'$' is not an identifier; use backticks to escape it}} {{10-11=`$`}}
$($: 24)
// expected-error@-1 {{'$' is not an identifier; use backticks to escape it}} {{3-4=`$`}}
// expected-error@-2 {{'$' is not an identifier; use backticks to escape it}} {{5-6=`$`}}
}
func escapedDollarVar() {
var `$` : Int = 42 // no error
`$` += 1
print(`$`)
}
func escapedDollarLet() {
let `$` = 42 // no error
print(`$`)
}
func escapedDollarClass() {
class `$` {} // no error
}
func escapedDollarEnum() {
enum `$` {} // no error
}
func escapedDollarStruct() {
struct `$` {} // no error
}
func escapedDollarFunc() {
func `$`(`$`: Int) {} // no error
`$`(`$`: 25) // no error
}