Skip to content

Commit dc9a84d

Browse files
committed
Parse module selectors on operator references
1 parent 1b49a11 commit dc9a84d

File tree

5 files changed

+30
-31
lines changed

5 files changed

+30
-31
lines changed

include/swift/Parse/Parser.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -487,9 +487,8 @@ class Parser {
487487
/// \returns the value returned by \c f
488488
/// \note When calling, you may need to specify the \c Val type
489489
/// explicitly as a type parameter.
490-
template <typename Val>
491-
Val lookahead(unsigned char K,
492-
llvm::function_ref<Val(CancellableBacktrackingScope &)> f) {
490+
template <typename Fn>
491+
decltype(auto) lookahead(unsigned char K, Fn f) {
493492
CancellableBacktrackingScope backtrackScope(*this);
494493

495494
for (unsigned char i = 0; i < K; ++i)

lib/Parse/ParseExpr.cpp

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3247,19 +3247,26 @@ Parser::parseArgumentList(tok leftTok, tok rightTok, bool isExprBasic,
32473247
return makeParserResult(status, argList);
32483248
}
32493249

3250+
/// See if we have an operator decl ref '(<op>)'. The operator token in
3251+
/// this case lexes as a binary operator because it neither leads nor
3252+
/// follows a proper subexpression.
3253+
bool listElementIsBinaryOperator(Parser &P, tok rightTok) {
3254+
// Look past a module selector, if present.
3255+
if (P.Tok.is(tok::identifier) && P.peekToken().is(tok::colon_colon)) {
3256+
return P.lookahead(2, [&](auto &scope) {
3257+
return listElementIsBinaryOperator(P, rightTok);
3258+
});
3259+
}
3260+
3261+
return P.Tok.isBinaryOperator() && P.peekToken().isAny(rightTok, tok::comma);
3262+
}
3263+
32503264
ParserStatus Parser::parseExprListElement(tok rightTok, bool isArgumentList, SourceLoc leftLoc, SmallVectorImpl<ExprListElt> &elts) {
32513265
Identifier FieldName;
32523266
SourceLoc FieldNameLoc;
32533267
parseOptionalArgumentLabel(FieldName, FieldNameLoc);
32543268

3255-
// See if we have an operator decl ref '(<op>)'. The operator token in
3256-
// this case lexes as a binary operator because it neither leads nor
3257-
// follows a proper subexpression.
3258-
auto isUnappliedOperator = [&]() {
3259-
return Tok.isBinaryOperator() && peekToken().isAny(rightTok, tok::comma);
3260-
};
3261-
3262-
if (isUnappliedOperator()) {
3269+
if (listElementIsBinaryOperator(*this, rightTok)) {
32633270
// Check to see if we have the start of a regex literal `/.../`. We need
32643271
// to do this for an unapplied operator reference, as e.g `(/, /)` might
32653272
// be a regex literal.
@@ -3268,10 +3275,8 @@ ParserStatus Parser::parseExprListElement(tok rightTok, bool isArgumentList, Sou
32683275

32693276
ParserStatus Status;
32703277
Expr *SubExpr = nullptr;
3271-
if (isUnappliedOperator()) {
3278+
if (listElementIsBinaryOperator(*this, rightTok)) {
32723279
DeclNameLoc Loc;
3273-
// FIXME: We would like to allow module selectors on binary operators, but
3274-
// the condition above won't let us reach this code.
32753280
auto OperName =
32763281
parseDeclNameRef(Loc, diag::expected_operator_ref,
32773282
DeclNameFlag::AllowOperators |

lib/Parse/ParsePattern.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ bool Parser::startsParameterName(bool isClosure) {
122122
// contextual keywords, so look ahead one more token (two total) and see
123123
// if we have a ':' that would
124124
// indicate that this is an argument label.
125-
return lookahead<bool>(2, [&](CancellableBacktrackingScope &) {
125+
return lookahead(2, [&](CancellableBacktrackingScope &) {
126126
if (Tok.is(tok::colon))
127127
return true; // isolated :
128128

@@ -235,7 +235,7 @@ Parser::parseParameterClause(SourceLoc &leftParenLoc,
235235
// is this token the identifier of an argument label? `inout` is a
236236
// reserved keyword but the other modifiers are not.
237237
if (!Tok.is(tok::kw_inout)) {
238-
bool partOfArgumentLabel = lookahead<bool>(1, [&](CancellableBacktrackingScope &) {
238+
bool partOfArgumentLabel = lookahead(1, [&](CancellableBacktrackingScope &) {
239239
if (Tok.is(tok::colon))
240240
return true; // isolated :
241241

test/NameLookup/module_selector.swift

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@ extension A: @retroactive Swift::Equatable {
2424

2525
@_dynamicReplacement(for: ModuleSelectorTestingKit::negate())
2626
mutating func myNegate() {
27-
let fn: (Swift::Int, Swift::Int) -> Swift::Int =
28-
(+)
29-
// FIXME: it'd be nice to handle module selectors on operators.
27+
let fn: (Swift::Int, Swift::Int) -> Swift::Int = (Swift::+)
3028

3129
let magnitude: Int.Swift::Magnitude = main::magnitude
3230

@@ -69,10 +67,6 @@ extension B: @retroactive main::Equatable {
6967
mutating func myNegate() {
7068
let fn: (main::Int, main::Int) -> main::Int =
7169
(main::+)
72-
// FIXME: it'd be nice to handle module selectors on operators.
73-
// expected-error@-2 {{cannot convert value of type '()' to specified type '(Int, Int) -> Int'}}
74-
// expected-error@-3 {{expected expression}}
75-
// expected-error@-4 {{expected expression after operator}}
7670

7771
let magnitude: Int.main::Magnitude = main::magnitude
7872

@@ -117,10 +111,6 @@ extension C: @retroactive ModuleSelectorTestingKit::Equatable {
117111
mutating func myNegate() {
118112
let fn: (ModuleSelectorTestingKit::Int, ModuleSelectorTestingKit::Int) -> ModuleSelectorTestingKit::Int =
119113
(ModuleSelectorTestingKit::+)
120-
// FIXME: it'd be nice to handle module selectors on operators.
121-
// expected-error@-2 {{cannot convert value of type '()' to specified type '(Int, Int) -> Int'}}
122-
// expected-error@-3 {{expected expression}}
123-
// expected-error@-4 {{expected expression after operator}}
124114

125115
let magnitude: Int.ModuleSelectorTestingKit::Magnitude = ModuleSelectorTestingKit::magnitude
126116

@@ -165,10 +155,6 @@ extension D: @retroactive Swift::Equatable {
165155
mutating func myNegate() {
166156
let fn: (Swift::Int, Swift::Int) -> Swift::Int =
167157
(Swift::+)
168-
// FIXME: it'd be nice to handle module selectors on operators.
169-
// expected-error@-2 {{cannot convert value of type '()' to specified type '(Int, Int) -> Int'}}
170-
// expected-error@-3 {{expected expression}}
171-
// expected-error@-4 {{expected expression after operator}}
172158

173159
let magnitude: Int.Swift::Magnitude = Swift::magnitude
174160

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
func fn() {
4+
_ = 1.description
5+
_ = 1.5.description
6+
7+
print(1.description)
8+
print(1.5.description)
9+
}

0 commit comments

Comments
 (0)