Skip to content

Commit 0bfacde

Browse files
committedDec 17, 2015
Fix: <rdar://problem/16230507> Cannot use a negative constant as the second operator of ... operator
This is a case that the operator splitting code didn't handle because of the bizarre lexer code for handling operators with periods in them. We had accreted some weird special case logic for what is valid in an operator (but which even had a special case hack for ..<). The policy is now very simple: if an operator name starts with a dot, it is allowed to include other dots in its name. If it doesn't, it doesn't. This allows us to get lexer level operator splitting in cases like x=.Foo, allowing our existing operator set that have dots in them without hacks, and provides a superior QoI experience due to operator splitting. This is technically a language change, but the TSPL operator grammar was incorrect for it anyway. I will file an internal radar to get TSPL updated with the actual behavior (now that it is defensible).
1 parent 997f6d4 commit 0bfacde

File tree

4 files changed

+19
-27
lines changed

4 files changed

+19
-27
lines changed
 

‎include/swift/AST/Identifier.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,6 @@ class Identifier {
109109
/// isOperatorContinuationCodePoint - Return true if the specified code point
110110
/// is a valid operator code point.
111111
static bool isOperatorContinuationCodePoint(uint32_t C) {
112-
// '.' is a special case. It can only appear in '..'.
113-
if (C == '.')
114-
return false;
115112
if (isOperatorStartCodePoint(C))
116113
return true;
117114

‎lib/Parse/Lexer.cpp

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -607,30 +607,23 @@ static bool isRightBound(const char *tokEnd, bool isLeftBound) {
607607
/// lexOperatorIdentifier - Match identifiers formed out of punctuation.
608608
void Lexer::lexOperatorIdentifier() {
609609
const char *TokStart = CurPtr-1;
610+
CurPtr = TokStart;
611+
bool didStart = advanceIfValidStartOfOperator(CurPtr, BufferEnd);
612+
assert(didStart && "unexpected operator start");
613+
(void) didStart;
614+
615+
do {
616+
if (CurPtr != BufferEnd && InSILBody &&
617+
(*CurPtr == '!' || *CurPtr == '?'))
618+
// When parsing SIL body, '!' and '?' are special token and can't be
619+
// in the middle of an operator.
620+
break;
610621

611-
// We only allow '.' in a series.
612-
if (*TokStart == '.') {
613-
while (*CurPtr == '.')
614-
++CurPtr;
615-
616-
// Lex ..< as an identifier.
617-
if (*CurPtr == '<' && CurPtr-TokStart == 2)
618-
++CurPtr;
619-
620-
} else {
621-
CurPtr = TokStart;
622-
bool didStart = advanceIfValidStartOfOperator(CurPtr, BufferEnd);
623-
assert(didStart && "unexpected operator start");
624-
(void) didStart;
625-
626-
do {
627-
if (CurPtr != BufferEnd && InSILBody &&
628-
(*CurPtr == '!' || *CurPtr == '?'))
629-
// When parsing SIL body, '!' and '?' are special token and can't be
630-
// in the middle of an operator.
631-
break;
632-
} while (advanceIfValidContinuationOfOperator(CurPtr, BufferEnd));
633-
}
622+
// '.' cannot appear in the middle of an operator unless the operator
623+
// started with a '.'.
624+
if (*CurPtr == '.' && *TokStart != '.')
625+
break;
626+
} while (advanceIfValidContinuationOfOperator(CurPtr, BufferEnd));
634627

635628
// Decide between the binary, prefix, and postfix cases.
636629
// It's binary if either both sides are bound or both sides are not bound.

‎test/Parse/identifiers.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class 你好 {
1717
你好.שלום.வணக்கம்.Γειά.привет()
1818

1919
// Identifiers cannot start with combining chars.
20-
_ = .́duh() // expected-error {{an identifier cannot begin with this character}} // expected-error{{expected identifier after '.' expression}}
20+
_ = .́duh() // expected-error {{use of unresolved operator '.́'}} // expected-error{{use of unresolved identifier 'duh'}}
2121

2222
// Combining characters can be used within identifiers.
2323
func s̈pin̈al_tap̈() {}

‎test/decl/operators.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,6 @@ _ = ~!n // expected-error {{unary operators may not be juxtaposed; parenthesize
193193
_ = -+n // expected-error {{unary operators may not be juxtaposed; parenthesize inner expression}}
194194
_ = -++n // expected-error {{unary operators may not be juxtaposed; parenthesize inner expression}}
195195

196+
// <rdar://problem/16230507> Cannot use a negative constant as the second operator of ... operator
197+
_ = 3...-5 // expected-error {{missing whitespace between '...' and '-' operators}}
196198

0 commit comments

Comments
 (0)
Please sign in to comment.