Skip to content

[Parse] Fix parsing "protocol<Any>" #5251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 12, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 31 additions & 34 deletions lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,30 +410,20 @@ ParserResult<TypeRepr> Parser::parseTypeIdentifierOrTypeComposition() {
SourceLoc ProtocolLoc = consumeToken(tok::kw_protocol);
SourceLoc LAngleLoc = consumeStartingLess();

// Check for empty protocol composition.
if (startsWithGreater(Tok)) {
SourceLoc RAngleLoc = consumeStartingGreater();
auto AnyRange = SourceRange(ProtocolLoc, RAngleLoc);

// Warn that 'protocol<>' is deprecated and offer to
// replace with the 'Any' keyword
diagnose(LAngleLoc, diag::deprecated_any_composition)
.fixItReplace(AnyRange, "Any");

return makeParserResult(
ProtocolCompositionTypeRepr::createEmptyComposition(Context, ProtocolLoc));
}

// Parse the type-composition-list.
ParserStatus Status;
SmallVector<IdentTypeRepr *, 4> Protocols;
do {
// Parse the type-identifier.
ParserResult<TypeRepr> Protocol = parseTypeIdentifier();
Status |= Protocol;
if (auto *ident = dyn_cast_or_null<IdentTypeRepr>(Protocol.getPtrOrNull()))
Protocols.push_back(ident);
} while (consumeIf(tok::comma));
bool IsEmpty = startsWithGreater(Tok);
if (!IsEmpty) {
do {
// Parse the type-identifier.
ParserResult<TypeRepr> Protocol = parseTypeIdentifier();
Status |= Protocol;
if (auto *ident = dyn_cast_or_null<IdentTypeRepr>(
Protocol.getPtrOrNull()))
Protocols.push_back(ident);
} while (consumeIf(tok::comma));
}

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

auto extractText = [&](IdentTypeRepr *Ty) -> StringRef {
auto SourceRange = Ty->getSourceRange();
return SourceMgr.extractText(
Lexer::getCharSourceRangeFromSourceRange(SourceMgr, SourceRange));
};
SmallString<32> replacement;
auto Begin = Protocols.begin();
replacement += extractText(*Begin);
while (++Begin != Protocols.end()) {
replacement += " & ";
if (Protocols.empty()) {
replacement = "Any";
} else {
auto extractText = [&](IdentTypeRepr *Ty) -> StringRef {
auto SourceRange = Ty->getSourceRange();
return SourceMgr.extractText(
Lexer::getCharSourceRangeFromSourceRange(SourceMgr, SourceRange));
};
auto Begin = Protocols.begin();
replacement += extractText(*Begin);
while (++Begin != Protocols.end()) {
replacement += " & ";
replacement += extractText(*Begin);
}
}

// Copy trailing content after '>' to the replacement string.
// FIXME: lexer should smartly separate '>' and trailing contents like '?'.
StringRef TrailingContent = L->getTokenAt(RAngleLoc).getRange().str().
substr(1);
if (!TrailingContent.empty()) {
replacement.insert(replacement.begin(), '(');
replacement += ")";
if (Protocols.size() > 1) {
replacement.insert(replacement.begin(), '(');
replacement += ")";
}
replacement += TrailingContent;
}

// Replace 'protocol<T1, T2>' with 'T1 & T2'
diagnose(ProtocolLoc,
Protocols.size() > 1 ? diag::deprecated_protocol_composition
: diag::deprecated_protocol_composition_single)
IsEmpty ? diag::deprecated_any_composition :
Protocols.size() > 1 ? diag::deprecated_protocol_composition :
diag::deprecated_protocol_composition_single)
.highlight(composition->getSourceRange())
.fixItReplace(composition->getSourceRange(), replacement);
}
Expand Down
2 changes: 1 addition & 1 deletion test/FixCode/fixits-apply.swift.result
Original file line number Diff line number Diff line change
Expand Up @@ -308,4 +308,4 @@ func testBoolValue(a : BoolFoo) {
protocol P1 {}
protocol P2 {}
var a : (P1 & P2)?
var a2 : (P1)= 17 as! P1
var a2 : P1= 17 as! P1
8 changes: 6 additions & 2 deletions test/type/protocol_composition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,17 @@ func testConversion() {
}

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

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