[Parse] Reorder precedence of '&' operator in type parsing

Now 'P1 & P2.Type' is parsed as (composition P1, (metatype P2))
instead of (metatype (composition P1, P2)).

For now, parsing inheritance clause accepts any TypeRepr, that is not allowed
in current Swift grammer. Diagnostic logic will be added in later commits.

Also, in Swift3, (composition P1, (metatype P2)) should be fixed to
(metatype (composition P1, P2)) for source compatibility.
This commit is contained in:
Rintaro Ishizaki
2016-10-16 09:56:33 +09:00
parent 3576b1480e
commit 17ebbae628
4 changed files with 81 additions and 58 deletions

View File

@@ -837,6 +837,11 @@ public:
parseTypeIdentifierWithRecovery(Diag<> MessageID, parseTypeIdentifierWithRecovery(Diag<> MessageID,
Diag<TypeLoc> NonIdentifierTypeMessageID); Diag<TypeLoc> NonIdentifierTypeMessageID);
ParserResult<TypeRepr> parseTypeSimpleOrComposition();
ParserResult<TypeRepr>
parseTypeSimpleOrComposition(Diag<> MessageID,
bool HandleCodeCompletion = true);
ParserResult<TypeRepr> parseTypeSimple(); ParserResult<TypeRepr> parseTypeSimple();
ParserResult<TypeRepr> parseTypeSimple(Diag<> MessageID, ParserResult<TypeRepr> parseTypeSimple(Diag<> MessageID,
bool HandleCodeCompletion = true); bool HandleCodeCompletion = true);
@@ -845,7 +850,6 @@ public:
SourceLoc &RAngleLoc); SourceLoc &RAngleLoc);
ParserResult<TypeRepr> parseTypeIdentifier(); ParserResult<TypeRepr> parseTypeIdentifier();
ParserResult<TypeRepr> parseTypeIdentifierOrTypeComposition();
ParserResult<TypeRepr> parseOldStyleProtocolComposition(); ParserResult<TypeRepr> parseOldStyleProtocolComposition();
ParserResult<CompositionTypeRepr> parseAnyType(); ParserResult<CompositionTypeRepr> parseAnyType();

View File

@@ -2415,10 +2415,10 @@ ParserStatus Parser::parseInheritance(SmallVectorImpl<TypeLoc> &Inherited,
bool usesDeprecatedCompositionSyntax = Tok.is(tok::kw_protocol) && startsWithLess(peekToken()); bool usesDeprecatedCompositionSyntax = Tok.is(tok::kw_protocol) && startsWithLess(peekToken());
bool isAny = Tok.is(tok::kw_Any); // We allow (redundant) inheritance from Any bool isAny = Tok.is(tok::kw_Any); // We allow (redundant) inheritance from Any
auto ParsedTypeResult = parseTypeIdentifierOrTypeComposition(); auto ParsedTypeResult = parseTypeSimpleOrComposition();
Status |= ParsedTypeResult; Status |= ParsedTypeResult;
// Cannot inherit from composition // Recover and emit nice diagnostic for composition.
if (auto Composition = dyn_cast_or_null<CompositionTypeRepr>( if (auto Composition = dyn_cast_or_null<CompositionTypeRepr>(
ParsedTypeResult.getPtrOrNull())) { ParsedTypeResult.getPtrOrNull())) {
// Record the protocols inside the composition. // Record the protocols inside the composition.

View File

@@ -71,7 +71,7 @@ Parser::parseGenericParameters(SourceLoc LAngleLoc) {
ParserResult<TypeRepr> Ty; ParserResult<TypeRepr> Ty;
if (Tok.isAny(tok::identifier, tok::code_complete, tok::kw_protocol, tok::kw_Any)) { if (Tok.isAny(tok::identifier, tok::code_complete, tok::kw_protocol, tok::kw_Any)) {
Ty = parseTypeIdentifierOrTypeComposition(); Ty = parseTypeSimpleOrComposition();
} else if (Tok.is(tok::kw_class)) { } else if (Tok.is(tok::kw_class)) {
diagnose(Tok, diag::unexpected_class_constraint); diagnose(Tok, diag::unexpected_class_constraint);
diagnose(Tok, diag::suggest_anyobject, Name) diagnose(Tok, diag::suggest_anyobject, Name)
@@ -267,7 +267,7 @@ ParserStatus Parser::parseGenericWhereClause(
SourceLoc ColonLoc = consumeToken(); SourceLoc ColonLoc = consumeToken();
// Parse the protocol or composition. // Parse the protocol or composition.
ParserResult<TypeRepr> Protocol = parseTypeIdentifierOrTypeComposition(); ParserResult<TypeRepr> Protocol = parseTypeSimpleOrComposition();
if (Protocol.isNull()) { if (Protocol.isNull()) {
Status.setIsParseError(); Status.setIsParseError();

View File

@@ -14,6 +14,7 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "swift/Basic/Fallthrough.h"
#include "swift/Parse/Parser.h" #include "swift/Parse/Parser.h"
#include "swift/AST/Attr.h" #include "swift/AST/Attr.h"
#include "swift/AST/TypeLoc.h" #include "swift/AST/TypeLoc.h"
@@ -42,13 +43,14 @@ ParserResult<TypeRepr> Parser::parseTypeSimple() {
/// type-simple: /// type-simple:
/// type-identifier /// type-identifier
/// type-tuple /// type-tuple
/// type-composition /// type-composition-deprecated
/// 'Any' /// 'Any'
/// type-simple '.Type' /// type-simple '.Type'
/// type-simple '.Protocol' /// type-simple '.Protocol'
/// type-simple '?' /// type-simple '?'
/// type-simple '!' /// type-simple '!'
/// type-collection /// type-collection
/// type-array
ParserResult<TypeRepr> Parser::parseTypeSimple(Diag<> MessageID, ParserResult<TypeRepr> Parser::parseTypeSimple(Diag<> MessageID,
bool HandleCodeCompletion) { bool HandleCodeCompletion) {
ParserResult<TypeRepr> ty; ParserResult<TypeRepr> ty;
@@ -57,13 +59,16 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(Diag<> MessageID,
consumeIf(tok::kw_inout, InOutLoc); consumeIf(tok::kw_inout, InOutLoc);
switch (Tok.getKind()) { switch (Tok.getKind()) {
case tok::kw_Self:
ty = parseTypeIdentifier();
break;
case tok::identifier:
case tok::kw_protocol: case tok::kw_protocol:
if (startsWithLess(peekToken())) {
ty = parseOldStyleProtocolComposition();
break;
}
SWIFT_FALLTHROUGH;
case tok::kw_Self:
case tok::kw_Any: case tok::kw_Any:
ty = parseTypeIdentifierOrTypeComposition(); case tok::identifier:
ty = parseTypeIdentifier();
break; break;
case tok::l_paren: case tok::l_paren:
ty = parseTypeTupleBody(); ty = parseTypeTupleBody();
@@ -89,12 +94,17 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(Diag<> MessageID,
ty = parseTypeCollection(); ty = parseTypeCollection();
break; break;
default: default:
checkForInputIncomplete();
diagnose(Tok, MessageID); diagnose(Tok, MessageID);
if (Tok.isKeyword() && !Tok.isAtStartOfLine()) {
ty = makeParserErrorResult(new (Context) ErrorTypeRepr(Tok.getLoc()));
consumeToken();
return ty;
}
checkForInputIncomplete();
return nullptr; return nullptr;
} }
// '.Type', '.Protocol', '?', and '!' still leave us with type-simple. // '.Type', '.Protocol', '?', '!', and '[]' still leave us with type-simple.
while (ty.isNonNull()) { while (ty.isNonNull()) {
if ((Tok.is(tok::period) || Tok.is(tok::period_prefix))) { if ((Tok.is(tok::period) || Tok.is(tok::period_prefix))) {
if (peekToken().isContextualKeyword("Type")) { if (peekToken().isContextualKeyword("Type")) {
@@ -122,6 +132,11 @@ ParserResult<TypeRepr> Parser::parseTypeSimple(Diag<> MessageID,
ty = parseTypeImplicitlyUnwrappedOptional(ty.get()); ty = parseTypeImplicitlyUnwrappedOptional(ty.get());
continue; continue;
} }
// Parse legacy array types for migration.
if (Tok.is(tok::l_square)) {
ty = parseTypeArray(ty.get());
continue;
}
} }
break; break;
} }
@@ -140,11 +155,11 @@ ParserResult<TypeRepr> Parser::parseType() {
/// parseType /// parseType
/// type: /// type:
/// attribute-list type-composition
/// attribute-list type-function /// attribute-list type-function
/// attribute-list type-array
/// ///
/// type-function: /// type-function:
/// type-simple '->' type /// type-composition '->' type
/// ///
ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID, ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,
bool HandleCodeCompletion) { bool HandleCodeCompletion) {
@@ -159,7 +174,8 @@ ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,
generics = maybeParseGenericParams().getPtrOrNull(); generics = maybeParseGenericParams().getPtrOrNull();
} }
ParserResult<TypeRepr> ty = parseTypeSimple(MessageID, HandleCodeCompletion); ParserResult<TypeRepr> ty =
parseTypeSimpleOrComposition(MessageID, HandleCodeCompletion);
if (ty.hasCodeCompletion()) if (ty.hasCodeCompletion())
return makeParserCodeCompletionResult<TypeRepr>(); return makeParserCodeCompletionResult<TypeRepr>();
@@ -215,15 +231,6 @@ ParserResult<TypeRepr> Parser::parseType(Diag<> MessageID,
diagnose(brackets.Start, diag::generic_non_function); diagnose(brackets.Start, diag::generic_non_function);
} }
// Parse legacy array types for migration.
while (ty.isNonNull() && !Tok.isAtStartOfLine()) {
if (Tok.is(tok::l_square)) {
ty = parseTypeArray(ty.get());
} else {
break;
}
}
if (ty.isNonNull() && !ty.hasCodeCompletion()) { if (ty.isNonNull() && !ty.hasCodeCompletion()) {
ty = makeParserResult(applyAttributeToType(ty.get(), attrs)); ty = makeParserResult(applyAttributeToType(ty.get(), attrs));
} }
@@ -392,47 +399,57 @@ ParserResult<TypeRepr> Parser::parseTypeIdentifier() {
return makeParserResult(Status, ITR); return makeParserResult(Status, ITR);
} }
/// parseTypeIdentifierOrTypeComposition ParserResult<TypeRepr> Parser::parseTypeSimpleOrComposition() {
/// - Identifiers and compositions both start with the same identifier return parseTypeSimpleOrComposition(diag::expected_identifier_for_type);
/// token, parse it and continue constructing a composition if the }
/// next token is '&'
/// parseTypeSimpleOrComposition
/// ///
/// type-composition: /// type-composition:
/// type-identifier ('&' type-identifier)* /// type-simple
/// type-composition-deprecated /// type-composition '&' type-simple
/// ParserResult<TypeRepr>
/// type-composition-list-deprecated: Parser::parseTypeSimpleOrComposition(Diag<> MessageID,
/// type-identifier (',' type-identifier)* bool HandleCodeCompletion) {
ParserResult<TypeRepr> Parser::parseTypeIdentifierOrTypeComposition() {
if (Tok.is(tok::kw_protocol) && startsWithLess(peekToken()))
return parseOldStyleProtocolComposition();
SourceLoc FirstTypeLoc = Tok.getLoc();
// Parse the first type // Parse the first type
ParserResult<TypeRepr> FirstType = parseTypeIdentifier(); ParserResult<TypeRepr> FirstType = parseTypeSimple(MessageID,
if (!Tok.isContextualPunctuator("&")) HandleCodeCompletion);
if (FirstType.hasCodeCompletion())
return makeParserCodeCompletionResult<TypeRepr>();
if (FirstType.isNull() || !Tok.isContextualPunctuator("&"))
return FirstType; return FirstType;
SmallVector<TypeRepr *, 4> Protocols; SmallVector<TypeRepr *, 4> Types;
ParserStatus Status; ParserStatus Status(FirstType);
SourceLoc FirstTypeLoc = FirstType.get()->getStartLoc();
SourceLoc FirstAmpersandLoc = Tok.getLoc();
// If it is not 'Any', add it to the protocol list auto addType = [&](TypeRepr *T) {
if (auto *ident = dyn_cast_or_null<IdentTypeRepr>(FirstType.getPtrOrNull())) if (!T) return;
Protocols.push_back(ident); if (auto Comp = dyn_cast<CompositionTypeRepr>(T)) {
Status |= FirstType; // Accept protocol<P1, P2> & P3; explode it.
auto FirstAmpersandLoc = Tok.getLoc(); auto TyRs = Comp->getTypes();
if (!TyRs.empty()) // If empty, is 'Any'; igone.
Types.append(TyRs.begin(), TyRs.end());
return;
}
Types.push_back(T);
};
addType(FirstType.get());
while (Tok.isContextualPunctuator("&")) { while (Tok.isContextualPunctuator("&")) {
consumeToken(); // consume '&' consumeToken(); // consume '&'
ParserResult<TypeRepr> Protocol = parseTypeIdentifier(); ParserResult<TypeRepr> ty =
Status |= Protocol; parseTypeSimple(diag::expected_identifier_for_type, HandleCodeCompletion);
if (auto *ident = dyn_cast_or_null<IdentTypeRepr>(Protocol.getPtrOrNull())) if (ty.hasCodeCompletion())
Protocols.push_back(ident); return makeParserCodeCompletionResult<TypeRepr>();
Status |= ty;
addType(ty.getPtrOrNull());
}; };
return makeParserResult(Status, CompositionTypeRepr::create( return makeParserResult(Status, CompositionTypeRepr::create(
Context, Protocols, FirstTypeLoc, {FirstAmpersandLoc, PreviousLoc})); Context, Types, FirstTypeLoc, {FirstAmpersandLoc, PreviousLoc}));
} }
ParserResult<CompositionTypeRepr> Parser::parseAnyType() { ParserResult<CompositionTypeRepr> Parser::parseAnyType() {
@@ -442,10 +459,12 @@ ParserResult<CompositionTypeRepr> Parser::parseAnyType() {
/// parseOldStyleProtocolComposition /// parseOldStyleProtocolComposition
/// type-composition-deprecated: /// type-composition-deprecated:
/// 'protocol' '<' type-composition-list-deprecated? '>' /// 'protocol' '<' '>'
/// 'protocol' '<' type-composition-list-deprecated '>'
/// ///
/// type-composition-list-deprecated: /// type-composition-list-deprecated:
/// type-identifier (',' type-identifier)* /// type-identifier
/// type-composition-list-deprecated ',' type-identifier
ParserResult<TypeRepr> Parser::parseOldStyleProtocolComposition() { ParserResult<TypeRepr> Parser::parseOldStyleProtocolComposition() {
assert(Tok.is(tok::kw_protocol) && startsWithLess(peekToken())); assert(Tok.is(tok::kw_protocol) && startsWithLess(peekToken()));
@@ -482,7 +501,7 @@ ParserResult<TypeRepr> Parser::parseOldStyleProtocolComposition() {
RAngleLoc = skipUntilGreaterInTypeList(/*protocolComposition=*/true); RAngleLoc = skipUntilGreaterInTypeList(/*protocolComposition=*/true);
} }
auto composition = ProtocolCompositionTypeRepr::create( auto composition = CompositionTypeRepr::create(
Context, Protocols, ProtocolLoc, {LAngleLoc, RAngleLoc}); Context, Protocols, ProtocolLoc, {LAngleLoc, RAngleLoc});
if (Status.isSuccess()) { if (Status.isSuccess()) {
@@ -491,7 +510,7 @@ ParserResult<TypeRepr> Parser::parseOldStyleProtocolComposition() {
if (Protocols.empty()) { if (Protocols.empty()) {
replacement = "Any"; replacement = "Any";
} else { } else {
auto extractText = [&](IdentTypeRepr *Ty) -> StringRef { auto extractText = [&](TypeRepr *Ty) -> StringRef {
auto SourceRange = Ty->getSourceRange(); auto SourceRange = Ty->getSourceRange();
return SourceMgr.extractText( return SourceMgr.extractText(
Lexer::getCharSourceRangeFromSourceRange(SourceMgr, SourceRange)); Lexer::getCharSourceRangeFromSourceRange(SourceMgr, SourceRange));