Skip to content

Commit 4e83034

Browse files
authored
Merge pull request #5251 from rintaro/parse-protocol-any
[Parse] Fix parsing "protocol<Any>"
2 parents 7ba11dd + 202779d commit 4e83034

File tree

3 files changed

+38
-37
lines changed

3 files changed

+38
-37
lines changed

lib/Parse/ParseType.cpp

Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -410,30 +410,20 @@ ParserResult<TypeRepr> Parser::parseTypeIdentifierOrTypeComposition() {
410410
SourceLoc ProtocolLoc = consumeToken(tok::kw_protocol);
411411
SourceLoc LAngleLoc = consumeStartingLess();
412412

413-
// Check for empty protocol composition.
414-
if (startsWithGreater(Tok)) {
415-
SourceLoc RAngleLoc = consumeStartingGreater();
416-
auto AnyRange = SourceRange(ProtocolLoc, RAngleLoc);
417-
418-
// Warn that 'protocol<>' is deprecated and offer to
419-
// replace with the 'Any' keyword
420-
diagnose(LAngleLoc, diag::deprecated_any_composition)
421-
.fixItReplace(AnyRange, "Any");
422-
423-
return makeParserResult(
424-
ProtocolCompositionTypeRepr::createEmptyComposition(Context, ProtocolLoc));
425-
}
426-
427413
// Parse the type-composition-list.
428414
ParserStatus Status;
429415
SmallVector<IdentTypeRepr *, 4> Protocols;
430-
do {
431-
// Parse the type-identifier.
432-
ParserResult<TypeRepr> Protocol = parseTypeIdentifier();
433-
Status |= Protocol;
434-
if (auto *ident = dyn_cast_or_null<IdentTypeRepr>(Protocol.getPtrOrNull()))
435-
Protocols.push_back(ident);
436-
} while (consumeIf(tok::comma));
416+
bool IsEmpty = startsWithGreater(Tok);
417+
if (!IsEmpty) {
418+
do {
419+
// Parse the type-identifier.
420+
ParserResult<TypeRepr> Protocol = parseTypeIdentifier();
421+
Status |= Protocol;
422+
if (auto *ident = dyn_cast_or_null<IdentTypeRepr>(
423+
Protocol.getPtrOrNull()))
424+
Protocols.push_back(ident);
425+
} while (consumeIf(tok::comma));
426+
}
437427

438428
// Check for the terminating '>'.
439429
SourceLoc RAngleLoc = PreviousLoc;
@@ -456,33 +446,40 @@ ParserResult<TypeRepr> Parser::parseTypeIdentifierOrTypeComposition() {
456446
if (Status.isSuccess()) {
457447
// Only if we have complete protocol<...> construct, diagnose deprecated.
458448

459-
auto extractText = [&](IdentTypeRepr *Ty) -> StringRef {
460-
auto SourceRange = Ty->getSourceRange();
461-
return SourceMgr.extractText(
462-
Lexer::getCharSourceRangeFromSourceRange(SourceMgr, SourceRange));
463-
};
464449
SmallString<32> replacement;
465-
auto Begin = Protocols.begin();
466-
replacement += extractText(*Begin);
467-
while (++Begin != Protocols.end()) {
468-
replacement += " & ";
450+
if (Protocols.empty()) {
451+
replacement = "Any";
452+
} else {
453+
auto extractText = [&](IdentTypeRepr *Ty) -> StringRef {
454+
auto SourceRange = Ty->getSourceRange();
455+
return SourceMgr.extractText(
456+
Lexer::getCharSourceRangeFromSourceRange(SourceMgr, SourceRange));
457+
};
458+
auto Begin = Protocols.begin();
469459
replacement += extractText(*Begin);
460+
while (++Begin != Protocols.end()) {
461+
replacement += " & ";
462+
replacement += extractText(*Begin);
463+
}
470464
}
471465

472466
// Copy trailing content after '>' to the replacement string.
473467
// FIXME: lexer should smartly separate '>' and trailing contents like '?'.
474468
StringRef TrailingContent = L->getTokenAt(RAngleLoc).getRange().str().
475469
substr(1);
476470
if (!TrailingContent.empty()) {
477-
replacement.insert(replacement.begin(), '(');
478-
replacement += ")";
471+
if (Protocols.size() > 1) {
472+
replacement.insert(replacement.begin(), '(');
473+
replacement += ")";
474+
}
479475
replacement += TrailingContent;
480476
}
481477

482478
// Replace 'protocol<T1, T2>' with 'T1 & T2'
483479
diagnose(ProtocolLoc,
484-
Protocols.size() > 1 ? diag::deprecated_protocol_composition
485-
: diag::deprecated_protocol_composition_single)
480+
IsEmpty ? diag::deprecated_any_composition :
481+
Protocols.size() > 1 ? diag::deprecated_protocol_composition :
482+
diag::deprecated_protocol_composition_single)
486483
.highlight(composition->getSourceRange())
487484
.fixItReplace(composition->getSourceRange(), replacement);
488485
}

test/FixCode/fixits-apply.swift.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,4 +308,4 @@ func testBoolValue(a : BoolFoo) {
308308
protocol P1 {}
309309
protocol P2 {}
310310
var a : (P1 & P2)?
311-
var a2 : (P1)= 17 as! P1
311+
var a2 : P1= 17 as! P1

test/type/protocol_composition.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,17 @@ func testConversion() {
123123
}
124124

125125
// Test the parser's splitting of >= into > and =.
126-
var x : protocol<P5>= 17 // expected-warning {{'protocol<...>' composition syntax is deprecated and not needed here}} {{9-22=(P5)=}}
126+
var x : protocol<P5>= 17 // expected-warning {{'protocol<...>' composition syntax is deprecated and not needed here}} {{9-22=P5=}}
127+
var y : protocol<P5, P7>= 17 // expected-warning {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}} {{9-26=(P5 & P7)=}}
127128

128-
typealias A = protocol<> // expected-warning {{'protocol<>' syntax is deprecated; use 'Any' instead}} {{15-25=Any}}
129+
typealias A1 = protocol<> // expected-warning {{'protocol<>' syntax is deprecated; use 'Any' instead}} {{16-26=Any}}
130+
typealias A2 = protocol<>? // expected-warning {{'protocol<>' syntax is deprecated; use 'Any' instead}} {{16-27=Any?}}
129131
typealias B1 = protocol<P1,P2> // expected-warning {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}} {{16-31=P1 & P2}}
130132
typealias B2 = protocol<P1, P2> // expected-warning {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}} {{16-32=P1 & P2}}
131133
typealias B3 = protocol<P1 ,P2> // expected-warning {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}} {{16-32=P1 & P2}}
132134
typealias B4 = protocol<P1 , P2> // expected-warning {{'protocol<...>' composition syntax is deprecated; join the protocols using '&'}} {{16-33=P1 & P2}}
133135
typealias C1 = protocol<Any, P1> // expected-warning {{'protocol<...>' composition syntax is deprecated and not needed here}} {{16-33=P1}}
134136
typealias C2 = protocol<P1, Any> // expected-warning {{'protocol<...>' composition syntax is deprecated and not needed here}} {{16-33=P1}}
135137
typealias D = protocol<P1> // expected-warning {{'protocol<...>' composition syntax is deprecated and not needed here}} {{15-27=P1}}
138+
typealias E = protocol<Any> // expected-warning {{'protocol<...>' composition syntax is deprecated and not needed here}} {{15-28=Any}}
139+
typealias F = protocol<Any, Any> // expected-warning {{'protocol<...>' composition syntax is deprecated and not needed here}} {{15-33=Any}}

0 commit comments

Comments
 (0)