diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 8d77a26b572..0d335b3a56a 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -837,6 +837,11 @@ public: parseTypeIdentifierWithRecovery(Diag<> MessageID, Diag NonIdentifierTypeMessageID); + ParserResult parseTypeSimpleOrComposition(); + ParserResult + parseTypeSimpleOrComposition(Diag<> MessageID, + bool HandleCodeCompletion = true); + ParserResult parseTypeSimple(); ParserResult parseTypeSimple(Diag<> MessageID, bool HandleCodeCompletion = true); @@ -845,7 +850,6 @@ public: SourceLoc &RAngleLoc); ParserResult parseTypeIdentifier(); - ParserResult parseTypeIdentifierOrTypeComposition(); ParserResult parseOldStyleProtocolComposition(); ParserResult parseAnyType(); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 4ff137b6313..d4c6e0432a6 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2415,10 +2415,10 @@ ParserStatus Parser::parseInheritance(SmallVectorImpl &Inherited, bool usesDeprecatedCompositionSyntax = Tok.is(tok::kw_protocol) && startsWithLess(peekToken()); bool isAny = Tok.is(tok::kw_Any); // We allow (redundant) inheritance from Any - auto ParsedTypeResult = parseTypeIdentifierOrTypeComposition(); + auto ParsedTypeResult = parseTypeSimpleOrComposition(); Status |= ParsedTypeResult; - // Cannot inherit from composition + // Recover and emit nice diagnostic for composition. if (auto Composition = dyn_cast_or_null( ParsedTypeResult.getPtrOrNull())) { // Record the protocols inside the composition. diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp index 60340164030..77e99557512 100644 --- a/lib/Parse/ParseGeneric.cpp +++ b/lib/Parse/ParseGeneric.cpp @@ -71,7 +71,7 @@ Parser::parseGenericParameters(SourceLoc LAngleLoc) { ParserResult Ty; 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)) { diagnose(Tok, diag::unexpected_class_constraint); diagnose(Tok, diag::suggest_anyobject, Name) @@ -267,7 +267,7 @@ ParserStatus Parser::parseGenericWhereClause( SourceLoc ColonLoc = consumeToken(); // Parse the protocol or composition. - ParserResult Protocol = parseTypeIdentifierOrTypeComposition(); + ParserResult Protocol = parseTypeSimpleOrComposition(); if (Protocol.isNull()) { Status.setIsParseError(); diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index bc92f81c026..53b6d0a4649 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -14,6 +14,7 @@ // //===----------------------------------------------------------------------===// +#include "swift/Basic/Fallthrough.h" #include "swift/Parse/Parser.h" #include "swift/AST/Attr.h" #include "swift/AST/TypeLoc.h" @@ -42,13 +43,14 @@ ParserResult Parser::parseTypeSimple() { /// type-simple: /// type-identifier /// type-tuple -/// type-composition +/// type-composition-deprecated /// 'Any' /// type-simple '.Type' /// type-simple '.Protocol' /// type-simple '?' /// type-simple '!' /// type-collection +/// type-array ParserResult Parser::parseTypeSimple(Diag<> MessageID, bool HandleCodeCompletion) { ParserResult ty; @@ -57,13 +59,16 @@ ParserResult Parser::parseTypeSimple(Diag<> MessageID, consumeIf(tok::kw_inout, InOutLoc); switch (Tok.getKind()) { - case tok::kw_Self: - ty = parseTypeIdentifier(); - break; - case tok::identifier: case tok::kw_protocol: + if (startsWithLess(peekToken())) { + ty = parseOldStyleProtocolComposition(); + break; + } + SWIFT_FALLTHROUGH; + case tok::kw_Self: case tok::kw_Any: - ty = parseTypeIdentifierOrTypeComposition(); + case tok::identifier: + ty = parseTypeIdentifier(); break; case tok::l_paren: ty = parseTypeTupleBody(); @@ -89,12 +94,17 @@ ParserResult Parser::parseTypeSimple(Diag<> MessageID, ty = parseTypeCollection(); break; default: - checkForInputIncomplete(); diagnose(Tok, MessageID); + if (Tok.isKeyword() && !Tok.isAtStartOfLine()) { + ty = makeParserErrorResult(new (Context) ErrorTypeRepr(Tok.getLoc())); + consumeToken(); + return ty; + } + checkForInputIncomplete(); return nullptr; } - // '.Type', '.Protocol', '?', and '!' still leave us with type-simple. + // '.Type', '.Protocol', '?', '!', and '[]' still leave us with type-simple. while (ty.isNonNull()) { if ((Tok.is(tok::period) || Tok.is(tok::period_prefix))) { if (peekToken().isContextualKeyword("Type")) { @@ -122,6 +132,11 @@ ParserResult Parser::parseTypeSimple(Diag<> MessageID, ty = parseTypeImplicitlyUnwrappedOptional(ty.get()); continue; } + // Parse legacy array types for migration. + if (Tok.is(tok::l_square)) { + ty = parseTypeArray(ty.get()); + continue; + } } break; } @@ -140,11 +155,11 @@ ParserResult Parser::parseType() { /// parseType /// type: +/// attribute-list type-composition /// attribute-list type-function -/// attribute-list type-array /// /// type-function: -/// type-simple '->' type +/// type-composition '->' type /// ParserResult Parser::parseType(Diag<> MessageID, bool HandleCodeCompletion) { @@ -159,7 +174,8 @@ ParserResult Parser::parseType(Diag<> MessageID, generics = maybeParseGenericParams().getPtrOrNull(); } - ParserResult ty = parseTypeSimple(MessageID, HandleCodeCompletion); + ParserResult ty = + parseTypeSimpleOrComposition(MessageID, HandleCodeCompletion); if (ty.hasCodeCompletion()) return makeParserCodeCompletionResult(); @@ -215,15 +231,6 @@ ParserResult Parser::parseType(Diag<> MessageID, 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()) { ty = makeParserResult(applyAttributeToType(ty.get(), attrs)); } @@ -392,47 +399,57 @@ ParserResult Parser::parseTypeIdentifier() { return makeParserResult(Status, ITR); } -/// parseTypeIdentifierOrTypeComposition -/// - Identifiers and compositions both start with the same identifier -/// token, parse it and continue constructing a composition if the -/// next token is '&' +ParserResult Parser::parseTypeSimpleOrComposition() { + return parseTypeSimpleOrComposition(diag::expected_identifier_for_type); +} + +/// parseTypeSimpleOrComposition /// /// type-composition: -/// type-identifier ('&' type-identifier)* -/// type-composition-deprecated -/// -/// type-composition-list-deprecated: -/// type-identifier (',' type-identifier)* -ParserResult Parser::parseTypeIdentifierOrTypeComposition() { - if (Tok.is(tok::kw_protocol) && startsWithLess(peekToken())) - return parseOldStyleProtocolComposition(); - - SourceLoc FirstTypeLoc = Tok.getLoc(); - +/// type-simple +/// type-composition '&' type-simple +ParserResult +Parser::parseTypeSimpleOrComposition(Diag<> MessageID, + bool HandleCodeCompletion) { // Parse the first type - ParserResult FirstType = parseTypeIdentifier(); - if (!Tok.isContextualPunctuator("&")) + ParserResult FirstType = parseTypeSimple(MessageID, + HandleCodeCompletion); + if (FirstType.hasCodeCompletion()) + return makeParserCodeCompletionResult(); + if (FirstType.isNull() || !Tok.isContextualPunctuator("&")) return FirstType; - SmallVector Protocols; - ParserStatus Status; + SmallVector Types; + ParserStatus Status(FirstType); + SourceLoc FirstTypeLoc = FirstType.get()->getStartLoc(); + SourceLoc FirstAmpersandLoc = Tok.getLoc(); - // If it is not 'Any', add it to the protocol list - if (auto *ident = dyn_cast_or_null(FirstType.getPtrOrNull())) - Protocols.push_back(ident); - Status |= FirstType; - auto FirstAmpersandLoc = Tok.getLoc(); + auto addType = [&](TypeRepr *T) { + if (!T) return; + if (auto Comp = dyn_cast(T)) { + // Accept protocol & P3; explode it. + 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("&")) { consumeToken(); // consume '&' - ParserResult Protocol = parseTypeIdentifier(); - Status |= Protocol; - if (auto *ident = dyn_cast_or_null(Protocol.getPtrOrNull())) - Protocols.push_back(ident); + ParserResult ty = + parseTypeSimple(diag::expected_identifier_for_type, HandleCodeCompletion); + if (ty.hasCodeCompletion()) + return makeParserCodeCompletionResult(); + Status |= ty; + addType(ty.getPtrOrNull()); }; return makeParserResult(Status, CompositionTypeRepr::create( - Context, Protocols, FirstTypeLoc, {FirstAmpersandLoc, PreviousLoc})); + Context, Types, FirstTypeLoc, {FirstAmpersandLoc, PreviousLoc})); } ParserResult Parser::parseAnyType() { @@ -442,10 +459,12 @@ ParserResult Parser::parseAnyType() { /// parseOldStyleProtocolComposition /// type-composition-deprecated: -/// 'protocol' '<' type-composition-list-deprecated? '>' +/// 'protocol' '<' '>' +/// 'protocol' '<' type-composition-list-deprecated '>' /// /// type-composition-list-deprecated: -/// type-identifier (',' type-identifier)* +/// type-identifier +/// type-composition-list-deprecated ',' type-identifier ParserResult Parser::parseOldStyleProtocolComposition() { assert(Tok.is(tok::kw_protocol) && startsWithLess(peekToken())); @@ -482,7 +501,7 @@ ParserResult Parser::parseOldStyleProtocolComposition() { RAngleLoc = skipUntilGreaterInTypeList(/*protocolComposition=*/true); } - auto composition = ProtocolCompositionTypeRepr::create( + auto composition = CompositionTypeRepr::create( Context, Protocols, ProtocolLoc, {LAngleLoc, RAngleLoc}); if (Status.isSuccess()) { @@ -491,7 +510,7 @@ ParserResult Parser::parseOldStyleProtocolComposition() { if (Protocols.empty()) { replacement = "Any"; } else { - auto extractText = [&](IdentTypeRepr *Ty) -> StringRef { + auto extractText = [&](TypeRepr *Ty) -> StringRef { auto SourceRange = Ty->getSourceRange(); return SourceMgr.extractText( Lexer::getCharSourceRangeFromSourceRange(SourceMgr, SourceRange));