mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
Reference in New Issue
Block a user