diff --git a/include/swift/Parse/ASTGen.h b/include/swift/Parse/ASTGen.h index fe5551570653a..551432f97ad73 100644 --- a/include/swift/Parse/ASTGen.h +++ b/include/swift/Parse/ASTGen.h @@ -16,6 +16,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/Decl.h" #include "swift/AST/Expr.h" +#include "swift/AST/TypeRepr.h" #include "swift/Parse/PersistentParserState.h" #include "swift/Syntax/SyntaxNodes.h" #include "llvm/ADT/DenseMap.h" @@ -46,6 +47,30 @@ class ASTGen { SourceLoc generate(const syntax::TokenSyntax &Tok, const SourceLoc Loc); + SourceLoc generateIdentifierDeclName(const syntax::TokenSyntax &Tok, + const SourceLoc, Identifier &Identifier); + +public: + //===--------------------------------------------------------------------===// + // Decls. + + Decl *generate(const syntax::DeclSyntax &Decl, const SourceLoc Loc); + TypeDecl *generate(const syntax::AssociatedtypeDeclSyntax &Decl, + const SourceLoc Loc); + + TrailingWhereClause *generate(const syntax::GenericWhereClauseSyntax &syntax, + const SourceLoc Loc); + MutableArrayRef + generate(const syntax::TypeInheritanceClauseSyntax &syntax, + const SourceLoc Loc, bool allowClassRequirement); + +private: + DeclAttributes + generateDeclAttributes(const syntax::DeclSyntax &D, + const Optional &attrs, + const Optional &modifiers, + SourceLoc Loc, bool includeComments); + public: //===--------------------------------------------------------------------===// // Expressions. @@ -100,6 +125,8 @@ class ASTGen { const SourceLoc Loc); TypeRepr *generate(const syntax::ImplicitlyUnwrappedOptionalTypeSyntax &Type, const SourceLoc Loc); + TypeRepr *generate(const syntax::ClassRestrictionTypeSyntax &Type, + const SourceLoc Loc); TypeRepr *generate(const syntax::CodeCompletionTypeSyntax &Type, const SourceLoc Loc); TypeRepr *generate(const syntax::UnknownTypeSyntax &Type, diff --git a/include/swift/Parse/LibSyntaxGenerator.h b/include/swift/Parse/LibSyntaxGenerator.h index 1333ed74af219..1e8dc2b74b60c 100644 --- a/include/swift/Parse/LibSyntaxGenerator.h +++ b/include/swift/Parse/LibSyntaxGenerator.h @@ -38,13 +38,14 @@ class LibSyntaxGenerator { assert(Node.isDeferredToken()); auto Kind = Node.getTokenKind(); - auto Range = Node.getDeferredTokenRangeWithTrivia(); + auto Range = Node.getDeferredTokenRange(); auto LeadingTriviaPieces = Node.getDeferredLeadingTriviaPieces(); auto TrailingTriviaPieces = Node.getDeferredTrailingTriviaPieces(); auto Recorded = Recorder.recordToken(Kind, Range, LeadingTriviaPieces, TrailingTriviaPieces); - auto Raw = static_cast(Recorded.takeOpaqueNode()); + RC Raw{static_cast(Recorded.takeOpaqueNode())}; + Raw->Release(); // -1 since it's transfer of ownership. return make(Raw); } @@ -55,7 +56,7 @@ class LibSyntaxGenerator { auto Children = Node.getDeferredChildren(); auto Recorded = Recorder.recordRawSyntax(Kind, Children); - RC Raw {static_cast(Recorded.takeOpaqueNode()) }; + RC Raw{static_cast(Recorded.takeOpaqueNode())}; Raw->Release(); // -1 since it's transfer of ownership. return make(Raw); } diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 840b0dac37ed1..2e36cc1abbff7 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1004,12 +1004,23 @@ class Parser { bool delayParsingDeclList(SourceLoc LBLoc, SourceLoc &RBLoc, IterableDeclContext *IDC); + ParsedSyntaxResult + parseTypeInheritanceClauseSyntax(bool allowClassRequirement, + bool allowAnyObject); + + ParsedSyntaxResult + parseDeclAssociatedTypeSyntax(ParseDeclOptions flags, + Optional attrs, + Optional modifiers); + ParserResult parseDeclTypeAlias(ParseDeclOptions Flags, - DeclAttributes &Attributes); + DeclAttributes &Attributes, + SourceLoc leadingLoc); ParserResult parseDeclAssociatedType(ParseDeclOptions Flags, - DeclAttributes &Attributes); - + DeclAttributes &Attributes, + SourceLoc leadingLoc); + /// Parse a #if ... #endif directive. /// Delegate callback function to parse elements in the blocks. ParserResult parseIfConfig( @@ -1091,7 +1102,7 @@ class Parser { ParserResult parseDeclImport(ParseDeclOptions Flags, DeclAttributes &Attributes); - ParserStatus parseInheritance(SmallVectorImpl &Inherited, + ParserStatus parseInheritance(MutableArrayRef &Inherited, bool allowClassRequirement, bool allowAnyObject); ParserStatus parseDeclItem(bool &PreviousHadSemi, diff --git a/include/swift/Parse/SyntaxParsingContext.h b/include/swift/Parse/SyntaxParsingContext.h index 6df76bebca037..96d4d57924429 100644 --- a/include/swift/Parse/SyntaxParsingContext.h +++ b/include/swift/Parse/SyntaxParsingContext.h @@ -279,17 +279,9 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext { } /// Returns the topmost Syntax node. - template SyntaxNode topNode() { - ParsedRawSyntaxNode &TopNode = getStorage().back(); - if (TopNode.isRecorded()) { - OpaqueSyntaxNode OpaqueNode = TopNode.getOpaqueNode(); - return getSyntaxCreator().getLibSyntaxNodeFor(OpaqueNode); - } - return getSyntaxCreator().createNode(TopNode.copyDeferred()); - } + template SyntaxNode topNode(); - template - llvm::Optional popIf() { + template llvm::Optional popIf() { auto &Storage = getStorage(); if (Storage.size() <= Offset) return llvm::None; @@ -376,5 +368,24 @@ class alignas(1 << SyntaxAlignInBits) SyntaxParsingContext { "Only meant for use in the debugger"); }; +template +inline SyntaxNode SyntaxParsingContext::topNode() { + ParsedRawSyntaxNode &TopNode = getStorage().back(); + if (TopNode.isRecorded()) { + OpaqueSyntaxNode OpaqueNode = TopNode.getOpaqueNode(); + return getSyntaxCreator().getLibSyntaxNodeFor(OpaqueNode); + } + return getSyntaxCreator().createNode(TopNode.copyDeferred()); +} + +template <> inline TokenSyntax SyntaxParsingContext::topNode() { + ParsedRawSyntaxNode &TopNode = getStorage().back(); + if (TopNode.isRecorded()) { + OpaqueSyntaxNode OpaqueNode = TopNode.getOpaqueNode(); + return getSyntaxCreator().getLibSyntaxNodeFor(OpaqueNode); + } + return getSyntaxCreator().createToken(TopNode.copyDeferred()); +} + } // namespace swift #endif // SWIFT_SYNTAX_PARSING_CONTEXT_H diff --git a/include/swift/Syntax/Syntax.h b/include/swift/Syntax/Syntax.h index c4b2d8f227dc3..31fac98aa9a16 100644 --- a/include/swift/Syntax/Syntax.h +++ b/include/swift/Syntax/Syntax.h @@ -83,7 +83,7 @@ class Syntax { SyntaxKind getKind() const; /// Get the shared raw syntax. - RC getRaw() const; + const RC &getRaw() const; /// Get an ID for this node that is stable across incremental parses SyntaxNodeId getId() const { return getRaw()->getId(); } diff --git a/include/swift/Syntax/SyntaxData.h b/include/swift/Syntax/SyntaxData.h index aa6a69f1369ee..6159f2e01e2d8 100644 --- a/include/swift/Syntax/SyntaxData.h +++ b/include/swift/Syntax/SyntaxData.h @@ -186,7 +186,7 @@ class SyntaxData final CursorIndex IndexInParent = 0); /// Returns the raw syntax node for this syntax node. - const RC getRaw() const { + const RC &getRaw() const { return Raw; } diff --git a/lib/Parse/ASTGen.cpp b/lib/Parse/ASTGen.cpp index 9681134650daa..104fdacce74c8 100644 --- a/lib/Parse/ASTGen.cpp +++ b/lib/Parse/ASTGen.cpp @@ -14,6 +14,7 @@ #include "swift/AST/TypeRepr.h" #include "swift/Basic/SourceManager.h" +#include "DebuggerContextChange.h" #include "swift/Basic/SourceManager.h" #include "swift/Parse/CodeCompletionCallbacks.h" #include "swift/Parse/Parser.h" @@ -25,6 +26,132 @@ SourceLoc ASTGen::generate(const TokenSyntax &Tok, const SourceLoc Loc) { return advanceLocBegin(Loc, Tok); } +SourceLoc ASTGen::generateIdentifierDeclName(const syntax::TokenSyntax &Tok, + const SourceLoc Loc, + Identifier &Id) { + StringRef text; + if (Tok.getText() == "Any") + // Special handle 'Any' because we don't want to accidantaly declare 'Any' + // type in any way. + text = "#Any"; + else + text = Tok.getIdentifierText(); + + Id = Context.getIdentifier(text); + return advanceLocBegin(Loc, Tok); +} + +Decl *ASTGen::generate(const DeclSyntax &D, const SourceLoc Loc) { + Decl *DeclAST = nullptr; + + if (auto associatedTypeDecl = D.getAs()) { + DeclAST = generate(*associatedTypeDecl, Loc); + } else { + llvm_unreachable("unsupported decl kind"); + } + + return DeclAST; +} + +DeclAttributes +ASTGen::generateDeclAttributes(const DeclSyntax &D, + const Optional &attrs, + const Optional &modifiers, + SourceLoc Loc, bool includeComments) { + SourceLoc attrsLoc; + if (attrs) { + attrsLoc = advanceLocBegin(Loc, *attrs->getFirstToken()); + } else if (modifiers) { + attrsLoc = advanceLocBegin(Loc, *modifiers->getFirstToken()); + } else { + // We might have comment attributes. + attrsLoc = advanceLocBegin(Loc, *D.getFirstToken()); + } + if (hasDeclAttributes(attrsLoc)) + return getDeclAttributes(attrsLoc); + return DeclAttributes(); +} + +MutableArrayRef +ASTGen::generate(const TypeInheritanceClauseSyntax &clause, SourceLoc Loc, + bool allowClassRequirement) { + SmallVector inherited; + + bool hasClass = false; + for (const auto elem : clause.getInheritedTypeCollection()) { + const auto &tySyntax = elem.getTypeName(); + if (tySyntax.is()) { + // Accept 'class' only if it's allowed and it's the first one. + if (!allowClassRequirement || hasClass) + continue; + hasClass = true; + } + if (auto ty = generate(tySyntax, Loc)) + inherited.emplace_back(ty); + } + + return Context.AllocateCopy(inherited); +} + +TypeDecl *ASTGen::generate(const AssociatedtypeDeclSyntax &D, + const SourceLoc Loc) { + if (!isa(P.CurDeclContext)) { + // This is already diagnosed in Parser. + return nullptr; + } + + auto idToken = D.getIdentifier(); + if (idToken.isMissing()) + return nullptr; + + auto keywordLoc = advanceLocBegin(Loc, D.getAssociatedtypeKeyword()); + auto name = Context.getIdentifier(idToken.getIdentifierText()); + auto nameLoc = advanceLocBegin(Loc, idToken); + + DeclAttributes attrs = + generateDeclAttributes(D, D.getAttributes(), D.getModifiers(), Loc, true); + + DebuggerContextChange DCC(P, name, DeclKind::AssociatedType); + + ArrayRef inherited; + if (const auto inheritanceClause = D.getInheritanceClause()) + inherited = + generate(*inheritanceClause, Loc, /*allowClassRequirement=*/true); + + TypeRepr *defaultTy = nullptr; + if (const auto init = D.getInitializer()) + defaultTy = generate(init->getValue(), Loc); + + TrailingWhereClause *trailingWhere = nullptr; + if (auto whereClause = D.getGenericWhereClause()) + trailingWhere = generate(*whereClause, Loc); + + auto assocType = new (Context) + AssociatedTypeDecl(P.CurDeclContext, keywordLoc, name, nameLoc, defaultTy, + trailingWhere); + assocType->getAttrs() = attrs; + if (!inherited.empty()) + assocType->setInherited(Context.AllocateCopy(inherited)); + addToScope(assocType); + return assocType; +} + +TrailingWhereClause *ASTGen::generate(const GenericWhereClauseSyntax &syntax, + const SourceLoc Loc) { + SourceLoc whereLoc = advanceLocBegin(Loc, syntax.getWhereKeyword()); + + SmallVector requirements; + requirements.reserve(syntax.getRequirementList().size()); + for (auto elem : syntax.getRequirementList()) { + if (auto req = generate(elem, Loc)) + requirements.push_back(*req); + } + + if (requirements.empty()) + return nullptr; + return TrailingWhereClause::create(Context, whereLoc, requirements); +} + Expr *ASTGen::generate(const IntegerLiteralExprSyntax &Expr, const SourceLoc Loc) { auto Digits = Expr.getDigits(); @@ -126,6 +253,8 @@ TypeRepr *ASTGen::generate(const TypeSyntax &Type, const SourceLoc Loc) { TypeAST = generate(*Unwrapped, Loc); else if (auto Attributed = Type.getAs()) TypeAST = generate(*Attributed, Loc); + else if (auto ClassRestriction = Type.getAs()) + TypeAST = generate(*ClassRestriction, Loc); else if (auto CompletionTy = Type.getAs()) TypeAST = generate(*CompletionTy, Loc); else if (auto Unknown = Type.getAs()) @@ -386,11 +515,6 @@ TypeRepr *ASTGen::generate(const SimpleTypeIdentifierSyntax &Type, auto AnyLoc = advanceLocBegin(Loc, Type.getName()); return CompositionTypeRepr::createEmptyComposition(Context, AnyLoc); } - if (Type.getName().getText() == "class") { - auto classLoc = advanceLocBegin(Loc, Type.getName()); - return new (Context) - SimpleIdentTypeRepr(classLoc, Context.getIdentifier("AnyObject")); - } return generateSimpleOrMemberIdentifier(Type, Loc); } @@ -450,6 +574,13 @@ TypeRepr *ASTGen::generate(const ImplicitlyUnwrappedOptionalTypeSyntax &Type, ImplicitlyUnwrappedOptionalTypeRepr(WrappedType, ExclamationLoc); } +TypeRepr * +ASTGen::generate(const ClassRestrictionTypeSyntax &Type, const SourceLoc Loc) { + auto classLoc = advanceLocBegin(Loc, Type); + return new (Context) + SimpleIdentTypeRepr(classLoc, Context.getIdentifier("AnyObject")); +} + TypeRepr *ASTGen::generate(const CodeCompletionTypeSyntax &Type, const SourceLoc Loc) { auto base = Type.getBase(); @@ -594,7 +725,7 @@ GenericParamList *ASTGen::generate(const GenericParameterClauseSyntax &clause, if (auto inherited = elem.getInheritedType()) { if (auto ty = generate(*inherited, Loc)) { - SmallVector constraints = {generate(*inherited, Loc)}; + SmallVector constraints = {ty}; param->setInherited(Context.AllocateCopy(constraints)); } } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 15ff71a34df9d..a49c14e9365ba 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2692,6 +2692,7 @@ Parser::parseDecl(ParseDeclOptions Flags, SyntaxParsingContext DeclParsingContext(SyntaxContext, SyntaxContextKind::Decl); + SourceLoc leadingLoc = leadingTriviaLoc(); // Note that we're parsing a declaration. StructureMarkerRAII ParsingDecl(*this, Tok.getLoc(), @@ -2709,6 +2710,13 @@ Parser::parseDecl(ParseDeclOptions Flags, StaticSpellingKind StaticSpelling = StaticSpellingKind::None; parseDeclModifierList(Attributes, StaticLoc, StaticSpelling); + if (!Attributes.isEmpty()) { + auto startLoc = Attributes.getStartLoc(); + if (startLoc.isInvalid()) + startLoc = Tok.getLoc(); + Generator.addDeclAttributes(Attributes, startLoc); + } + // We emit diagnostics for 'try let ...' in parseDeclVar(). SourceLoc tryLoc; if (Tok.is(tok::kw_try) && peekToken().isAny(tok::kw_let, tok::kw_var)) @@ -2760,12 +2768,11 @@ Parser::parseDecl(ParseDeclOptions Flags, } case tok::kw_typealias: DeclParsingContext.setCreateSyntax(SyntaxKind::TypealiasDecl); - DeclResult = parseDeclTypeAlias(Flags, Attributes); + DeclResult = parseDeclTypeAlias(Flags, Attributes, leadingLoc); MayNeedOverrideCompletion = true; break; case tok::kw_associatedtype: - DeclParsingContext.setCreateSyntax(SyntaxKind::AssociatedtypeDecl); - DeclResult = parseDeclAssociatedType(Flags, Attributes); + DeclResult = parseDeclAssociatedType(Flags, Attributes, leadingLoc); break; case tok::kw_enum: DeclParsingContext.setCreateSyntax(SyntaxKind::EnumDecl); @@ -3304,100 +3311,107 @@ ParserResult Parser::parseDeclImport(ParseDeclOptions Flags, /// 'class' /// type-identifier /// \endverbatim -ParserStatus Parser::parseInheritance(SmallVectorImpl &Inherited, - bool allowClassRequirement, - bool allowAnyObject) { - SyntaxParsingContext InheritanceContext(SyntaxContext, - SyntaxKind::TypeInheritanceClause); - Scope S(this, ScopeKind::InheritanceClause); - consumeToken(tok::colon); +ParsedSyntaxResult +Parser::parseTypeInheritanceClauseSyntax(bool allowClassRequirement, + bool allowAnyObject) { + ParsedTypeInheritanceClauseSyntaxBuilder builder(*SyntaxContext); + ParserStatus status; - SyntaxParsingContext TypeListContext(SyntaxContext, - SyntaxKind::InheritedTypeList); - SourceLoc classRequirementLoc; + builder.useColon(consumeTokenSyntax(tok::colon)); - ParserStatus Status; - SourceLoc prevComma; - bool HasNextType; + SourceLoc startLoc = Tok.getLoc(); + SourceLoc classRequirementLoc, prevCommaLoc; + bool hasNext = true; do { - SyntaxParsingContext TypeContext(SyntaxContext, SyntaxKind::InheritedType); - SWIFT_DEFER { - // Check for a ',', which indicates that there are more protocols coming. - HasNextType = consumeIf(tok::comma, prevComma); - }; + ParsedInheritedTypeSyntaxBuilder elemBuilder(*SyntaxContext); + // Parse the 'class' keyword for a class requirement. if (Tok.is(tok::kw_class)) { - SyntaxParsingContext ClassTypeContext(SyntaxContext, - SyntaxKind::ClassRestrictionType); - // If we aren't allowed to have a class requirement here, complain. - auto classLoc = consumeToken(); + auto classLoc = Tok.getLoc(); + auto classTok = consumeTokenSyntax(tok::kw_class); + auto restriction = ParsedSyntaxRecorder::makeClassRestrictionType( + std::move(classTok), *SyntaxContext); + elemBuilder.useTypeName(std::move(restriction)); + if (!allowClassRequirement) { + // If we aren't allowed to have a class requirement here, complain. diagnose(classLoc, diag::unexpected_class_constraint); - // Note that it makes no sense to suggest fixing - // 'struct S : class' to 'struct S : AnyObject' for - // example; in that case we just complain about - // 'class' being invalid here. + // Note that it makes no sense to suggest fixing 'struct S : class' to + // 'struct S : AnyObject' for example; in that case we just complain + // about 'class' being invalid here. if (allowAnyObject) { diagnose(classLoc, diag::suggest_anyobject) - .fixItReplace(classLoc, "AnyObject"); + .fixItReplace(classLoc, "AnyObject"); } - continue; - } - // If we already saw a class requirement, complain. - if (classRequirementLoc.isValid()) { - diagnose(classLoc, diag::redundant_class_requirement) + } else if (classRequirementLoc.isValid()) { + // If we already saw a class requirement, complain. + diagnose(Tok.getLoc(), diag::redundant_class_requirement) .highlight(classRequirementLoc) - .fixItRemove(SourceRange(prevComma, classLoc)); - continue; - } + .fixItRemove(SourceRange(prevCommaLoc, classLoc)); - // If the class requirement was not the first requirement, complain. - if (!Inherited.empty()) { - SourceLoc properLoc = Inherited[0].getSourceRange().Start; + } else if (prevCommaLoc.isValid()) { + // If the class requirement was not the first requirement, complain. diagnose(classLoc, diag::late_class_requirement) - .fixItInsert(properLoc, "class, ") - .fixItRemove(SourceRange(prevComma, classLoc)); + .fixItInsert(startLoc, "class, ") + .fixItRemove(SourceRange(prevCommaLoc, classLoc)); } // Record the location of the 'class' keyword. - classRequirementLoc = classLoc; + if (!classRequirementLoc.isValid()) + classRequirementLoc = classLoc; + } else { + // Parse inherited type. + auto inheritedType = parseTypeSyntax(); + status |= inheritedType.getStatus(); + if (!inheritedType.isNull()) + elemBuilder.useTypeName(inheritedType.get()); + else + elemBuilder.useTypeName( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + } - // Add 'AnyObject' to the inherited list. - Inherited.push_back( - new (Context) SimpleIdentTypeRepr(classLoc, - Context.getIdentifier("AnyObject"))); - continue; + // Parse ','. + if (Tok.is(tok::comma)) { + prevCommaLoc = Tok.getLoc(); + elemBuilder.useTrailingComma(consumeTokenSyntax(tok::comma)); + } else { + hasNext = false; } - auto ParsedTypeResult = parseType(); - Status |= ParsedTypeResult; + builder.addInheritedTypeCollectionMember(elemBuilder.build()); + } while (hasNext); - // Record the type if its a single type. - if (ParsedTypeResult.isNonNull()) - Inherited.push_back(ParsedTypeResult.get()); - } while (HasNextType); + return makeParsedResult(builder.build(), status); +} - return Status; +ParserStatus Parser::parseInheritance(MutableArrayRef &Inherited, + bool allowClassRequirement, + bool allowAnyObject) { + auto leadingLoc = leadingTriviaLoc(); + auto parsed = parseTypeInheritanceClauseSyntax(allowClassRequirement, + allowAnyObject); + SyntaxContext->addSyntax(parsed.get()); + auto clause = SyntaxContext->topNode(); + Inherited = Generator.generate(clause, leadingLoc, allowClassRequirement); + return parsed.getStatus(); } -static ParserStatus -parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, - StringRef DeclKindName, - llvm::function_ref canRecover) { +static ParsedSyntaxResult +parseIdentifierDeclNameSyntax(Parser &P, StringRef DeclKindName, + llvm::function_ref canRecover) { if (P.Tok.is(tok::identifier)) { - Loc = P.consumeIdentifier(&Result); + auto text = P.Tok.getText(); + auto loc = P.Tok.getLoc(); - // We parsed an identifier for the declaration. If we see another - // identifier, it might've been a single identifier that got broken by a - // space or newline accidentally. + auto tok = P.consumeIdentifierSyntax(); if (P.Tok.isIdentifierOrUnderscore() && !P.Tok.isContextualDeclKeyword()) - P.diagnoseConsecutiveIDs(Result.str(), Loc, DeclKindName); + P.diagnoseConsecutiveIDs(text, loc, DeclKindName); // Return success anyway - return makeParserSuccess(); + return makeParsedResult(std::move(tok)); } P.checkForInputIncomplete(); @@ -3411,12 +3425,8 @@ parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, // Pretend this works as an identifier, which shouldn't be observable since // actual uses of it will hit random other errors, e.g. `1()` won't be // callable. - Result = P.Context.getIdentifier(P.Tok.getText()); - Loc = P.Tok.getLoc(); - P.consumeToken(); - - // We recovered, so this is a success. - return makeParserSuccess(); + P.Tok.setKind(tok::identifier); + return makeParsedResult(P.consumeTokenSyntax()); } if (P.Tok.isKeyword()) { @@ -3426,14 +3436,8 @@ parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, // Recover if the next token is one of the expected tokens. if (canRecover(P.peekToken())) { - llvm::SmallString<32> Name(P.Tok.getText()); - // Append an invalid character so that nothing can resolve to this name. - Name += "#"; - Result = P.Context.getIdentifier(Name.str()); - Loc = P.Tok.getLoc(); - P.consumeToken(); - // Return success because we recovered. - return makeParserSuccess(); + P.Tok.setKind(tok::identifier); + return makeParsedResult(P.consumeTokenSyntax()); } return makeParserError(); } @@ -3442,6 +3446,20 @@ parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, return makeParserError(); } +static ParserStatus +parseIdentifierDeclName(Parser &P, Identifier &Result, SourceLoc &Loc, + StringRef DeclKindName, + llvm::function_ref canRecover) { + auto leadingLoc = P.leadingTriviaLoc(); + auto parsed = parseIdentifierDeclNameSyntax(P, DeclKindName, canRecover); + if (!parsed.isNull()) { + P.SyntaxContext->addSyntax(parsed.get()); + auto syntax = P.SyntaxContext->topNode(); + Loc = P.Generator.generateIdentifierDeclName(syntax, leadingLoc, Result); + } + return parsed.getStatus(); +} + /// Add a fix-it to remove the space in consecutive identifiers. /// Add a camel-cased option if it is different than the first option. void Parser::diagnoseConsecutiveIDs(StringRef First, SourceLoc FirstLoc, @@ -3450,7 +3468,8 @@ void Parser::diagnoseConsecutiveIDs(StringRef First, SourceLoc FirstLoc, diagnose(Tok, diag::repeated_identifier, DeclKindName); auto Second = Tok.getText(); - auto SecondLoc = consumeToken(); + auto SecondLoc = Tok.getLoc(); + ignoreToken(); SourceRange FixRange(FirstLoc, SecondLoc); // Provide two fix-its: a direct concatenation of the two identifiers @@ -3650,7 +3669,7 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) { status |= extendedType; // Parse optional inheritance clause. - SmallVector Inherited; + MutableArrayRef Inherited; if (Tok.is(tok::colon)) status |= parseInheritance(Inherited, /*allowClassRequirement=*/false, @@ -3677,7 +3696,7 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) { ExtensionDecl *ext = ExtensionDecl::create(Context, ExtensionLoc, extendedType.getPtrOrNull(), - Context.AllocateCopy(Inherited), + Inherited, CurDeclContext, trailingWhereClause); ext->getAttrs() = Attributes; @@ -3947,8 +3966,9 @@ ParserStatus Parser::parseLineDirective(bool isLine) { /// decl-typealias: /// 'typealias' identifier generic-params? '=' type requirement-clause? /// \endverbatim -ParserResult Parser:: -parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) { +ParserResult +Parser::parseDeclTypeAlias(Parser::ParseDeclOptions Flags, + DeclAttributes &Attributes, SourceLoc leadingLoc) { ParserPosition startPosition = getParserPosition(); llvm::Optional TmpCtxt; TmpCtxt.emplace(SyntaxContext); @@ -3967,7 +3987,7 @@ parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) { TmpCtxt->setTransparent(); return nullptr; } - + DebuggerContextChange DCC(*this, Id, DeclKind::TypeAlias); Optional GenericsScope; @@ -3996,7 +4016,7 @@ parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) { // If we're in a protocol and don't see an '=' this looks like leftover Swift 2 // code intending to be an associatedtype. backtrackToPosition(startPosition); - return parseDeclAssociatedType(Flags, Attributes); + return parseDeclAssociatedType(Flags, Attributes, leadingLoc); } TmpCtxt->setTransparent(); TmpCtxt.reset(); @@ -4055,95 +4075,116 @@ parseDeclTypeAlias(Parser::ParseDeclOptions Flags, DeclAttributes &Attributes) { /// Parse an associatedtype decl. /// -/// \verbatim /// decl-associatedtype: -/// 'associatedtype' identifier inheritance? ('=' type)? where-clause? -/// \endverbatim +/// 'associatedtype' identifier type-inheritance-clause? +/// ('=' type)? where-clause? +ParsedSyntaxResult +Parser::parseDeclAssociatedTypeSyntax(ParseDeclOptions flags, + Optional attrs, + Optional modifiers) { + ParsedAssociatedtypeDeclSyntaxBuilder builder(*SyntaxContext); + ParserStatus status; -ParserResult Parser::parseDeclAssociatedType(Parser::ParseDeclOptions Flags, - DeclAttributes &Attributes) { - SourceLoc AssociatedTypeLoc; - ParserStatus Status; - Identifier Id; - SourceLoc IdLoc; - - // Look for 'typealias' here and diagnose a fixit because parseDeclTypeAlias can - // ask us to fix up leftover Swift 2 code intending to be an associatedtype. + if (attrs) + builder.useAttributes(std::move(*attrs)); + if (modifiers) + builder.useModifiers(std::move(*modifiers)); + + // Parse 'associatedtype' keyword. + // Look for 'typealias' here and diagnose a fixit because parseDeclTypeAlias + // can ask us to fix up leftover Swift 2 code intending to be an + // associatedtype. + auto keywordLoc = Tok.getLoc(); if (Tok.is(tok::kw_typealias)) { - AssociatedTypeLoc = consumeToken(tok::kw_typealias); - diagnose(AssociatedTypeLoc, diag::typealias_inside_protocol_without_type) - .fixItReplace(AssociatedTypeLoc, "associatedtype"); + diagnose(Tok.getLoc(), diag::typealias_inside_protocol_without_type) + .fixItReplace(Tok.getLoc(), "associatedtype"); + ignoreToken(tok::kw_typealias); } else { - AssociatedTypeLoc = consumeToken(tok::kw_associatedtype); + builder.useAssociatedtypeKeyword( + consumeTokenSyntax(tok::kw_associatedtype)); } - Status = parseIdentifierDeclName( - *this, Id, IdLoc, "associatedtype", - [](const Token &next) { return next.isAny(tok::colon, tok::equal); }); - if (Status.isError()) - return nullptr; - - DebuggerContextChange DCC(*this, Id, DeclKind::AssociatedType); - - // Reject generic parameters with a specific error. + // Parse the name. + auto name = parseIdentifierDeclNameSyntax( + *this, "associatedtype", + [&](const Token &next) { return next.isAny(tok::colon, tok::equal); }); + if (name.isNull()) + return makeParsedResult(builder.build(), name.getStatus()); + assert(name.isSuccess()); + builder.useIdentifier(name.get()); + + // Diagnose generic parameters. if (startsWithLess(Tok)) { - // Introduce a throwaway scope to capture the generic parameters. We - // don't want them visible anywhere! - Scope S(this, ScopeKind::Generics); + auto loc = Tok.getLoc(); + ignoreToken(); + if (ignoreUntilGreaterInTypeList()) + ignoreToken(); - if (auto genericParams = parseGenericParameters().getPtrOrNull()) { - diagnose(genericParams->getLAngleLoc(), - diag::associated_type_generic_parameter_list) - .fixItRemove(genericParams->getSourceRange()); - } + diagnose(loc, diag::associated_type_generic_parameter_list) + .fixItRemove({loc, PreviousLoc}); } - + // Parse optional inheritance clause. - // FIXME: Allow class requirements here. - SmallVector Inherited; - if (Tok.is(tok::colon)) - Status |= parseInheritance(Inherited, - /*allowClassRequirement=*/false, - /*allowAnyObject=*/true); - - ParserResult UnderlyingTy; + if (Tok.is(tok::colon)) { + auto inheritance = parseTypeInheritanceClauseSyntax( + /*allowClassRequirement=*/false, /*allowAnyObject=*/true); + status |= inheritance.getStatus(); + if (!inheritance.isNull()) + builder.useInheritanceClause(inheritance.get()); + } + + // Parse optional default type. if (Tok.is(tok::equal)) { - SyntaxParsingContext InitContext(SyntaxContext, - SyntaxKind::TypeInitializerClause); - consumeToken(tok::equal); - UnderlyingTy = parseType(diag::expected_type_in_associatedtype); - Status |= UnderlyingTy; - if (UnderlyingTy.isNull()) - return Status; + ParsedTypeInitializerClauseSyntaxBuilder initBuilder(*SyntaxContext); + initBuilder.useEqual(consumeTokenSyntax(tok::equal)); + + // Parse type. + auto type = parseTypeSyntax(diag::expected_type_in_associatedtype); + status |= type.getStatus(); + if (!type.isNull()) + initBuilder.useValue(type.get()); + else + initBuilder.useValue( + ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext)); + + builder.useInitializer(initBuilder.build()); } - TrailingWhereClause *TrailingWhere = nullptr; - // Parse a 'where' clause if present. + // Parse optional 'where' clause. if (Tok.is(tok::kw_where)) { - auto whereStatus = parseProtocolOrAssociatedTypeWhereClause( - TrailingWhere, /*isProtocol=*/false); - Status |= whereStatus; - if (whereStatus.hasCodeCompletion() && !CodeCompletion) { - // Trigger delayed parsing, no need to continue. - return whereStatus; - } + bool firstTypeInComplete = false; + auto where = parseGenericWhereClauseSyntax(firstTypeInComplete); + status |= where.getStatus(); + if (!where.isNull()) + builder.useGenericWhereClause(where.get()); + } + + // Diagnose if it's not in protocol decl. + // TODO: Move this to ASTGen. + if (!flags.contains(PD_InProtocol)) { + diagnose(keywordLoc, diag::associatedtype_outside_protocol) + .fixItReplace(keywordLoc, "typealias"); + status.setIsParseError(); } - if (!Flags.contains(PD_InProtocol)) { - diagnose(AssociatedTypeLoc, diag::associatedtype_outside_protocol) - .fixItReplace(AssociatedTypeLoc, "typealias"); - Status.setIsParseError(); - return Status; - } + return makeParsedResult(builder.build(), status); +} - auto assocType = new (Context) - AssociatedTypeDecl(CurDeclContext, AssociatedTypeLoc, Id, IdLoc, - UnderlyingTy.getPtrOrNull(), TrailingWhere); - assocType->getAttrs() = Attributes; - if (!Inherited.empty()) - assocType->setInherited(Context.AllocateCopy(Inherited)); - addToScope(assocType); - return makeParserResult(Status, assocType); +ParserResult +Parser::parseDeclAssociatedType(Parser::ParseDeclOptions Flags, + DeclAttributes &Attributes, + SourceLoc leadingLoc) { + auto modifiers = SyntaxContext->popIf(); + auto attrs = SyntaxContext->popIf(); + + auto parsed = parseDeclAssociatedTypeSyntax(Flags, std::move(attrs), + std::move(modifiers)); + assert(!parsed.isNull()); + + SyntaxContext->addSyntax(parsed.get()); + auto syntax = SyntaxContext->topNode(); + auto result = Generator.generate(syntax, leadingLoc); + return makeParserResult(parsed.getStatus(), result); } /// This function creates an accessor function (with no body) for a computed @@ -5574,11 +5615,11 @@ ParserResult Parser::parseDeclEnum(ParseDeclOptions Flags, // Parse optional inheritance clause within the context of the enum. if (Tok.is(tok::colon)) { - SmallVector Inherited; + MutableArrayRef Inherited; Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false, /*allowAnyObject=*/false); - ED->setInherited(Context.AllocateCopy(Inherited)); + ED->setInherited(Inherited); } diagnoseWhereClauseInGenericParamList(GenericParams); @@ -5860,11 +5901,11 @@ ParserResult Parser::parseDeclStruct(ParseDeclOptions Flags, // Parse optional inheritance clause within the context of the struct. if (Tok.is(tok::colon)) { - SmallVector Inherited; + MutableArrayRef Inherited; Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false, /*allowAnyObject=*/false); - SD->setInherited(Context.AllocateCopy(Inherited)); + SD->setInherited(Inherited); } diagnoseWhereClauseInGenericParamList(GenericParams); @@ -5953,11 +5994,11 @@ ParserResult Parser::parseDeclClass(ParseDeclOptions Flags, // Parse optional inheritance clause within the context of the class. if (Tok.is(tok::colon)) { - SmallVector Inherited; + MutableArrayRef Inherited; Status |= parseInheritance(Inherited, /*allowClassRequirement=*/false, /*allowAnyObject=*/false); - CD->setInherited(Context.AllocateCopy(Inherited)); + CD->setInherited(Inherited); // Parse python style inheritance clause and replace parentheses with a colon } else if (Tok.is(tok::l_paren)) { @@ -6059,7 +6100,7 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) { DebuggerContextChange DCC (*this); // Parse optional inheritance clause. - SmallVector InheritedProtocols; + MutableArrayRef InheritedProtocols; SourceLoc colonLoc; if (Tok.is(tok::colon)) { colonLoc = Tok.getLoc(); @@ -6079,7 +6120,7 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) { ProtocolDecl *Proto = new (Context) ProtocolDecl(CurDeclContext, ProtocolLoc, NameLoc, ProtocolName, - Context.AllocateCopy(InheritedProtocols), TrailingWhere); + InheritedProtocols, TrailingWhere); // No need to setLocalDiscriminator: protocols can't appear in local contexts. Proto->getAttrs() = Attributes; diff --git a/lib/Parse/ParseGeneric.cpp b/lib/Parse/ParseGeneric.cpp index b2edfebb3d10f..26dc22d7475d8 100644 --- a/lib/Parse/ParseGeneric.cpp +++ b/lib/Parse/ParseGeneric.cpp @@ -110,9 +110,8 @@ Parser::parseGenericParameterClauseSyntax() { diagnose(Tok, diag::unexpected_class_constraint); diagnose(Tok, diag::suggest_anyobject) .fixItReplace(Tok.getLoc(), "AnyObject"); - Tok.setKind(tok::identifier); - auto ty = ParsedSyntaxRecorder::makeSimpleTypeIdentifier( - consumeTokenSyntax(), None, *SyntaxContext); + auto ty = ParsedSyntaxRecorder::makeClassRestrictionType( + consumeTokenSyntax(tok::kw_class), *SyntaxContext); paramBuilder.useInheritedType(std::move(ty)); } else { diagnose(Tok, diag::expected_generics_type_restriction, ident); diff --git a/lib/Syntax/Syntax.cpp b/lib/Syntax/Syntax.cpp index 57aa313597c7b..850fb9ecbf082 100644 --- a/lib/Syntax/Syntax.cpp +++ b/lib/Syntax/Syntax.cpp @@ -18,7 +18,7 @@ using namespace swift; using namespace swift::syntax; -RC Syntax::getRaw() const { +const RC &Syntax::getRaw() const { return Data->getRaw(); } diff --git a/test/Syntax/round_trip_misc.swift b/test/Syntax/round_trip_misc.swift index 78b0c0a3ae8be..faec3efc3603b 100644 --- a/test/Syntax/round_trip_misc.swift +++ b/test/Syntax/round_trip_misc.swift @@ -28,6 +28,9 @@ do { do { typealias Alias = A & B & C.D<> } +do { + typealias boo bar = Int +} // Orphan '}' at top level } diff --git a/test/Syntax/serialize_tupletype.swift.result b/test/Syntax/serialize_tupletype.swift.result index c186b51c93d6b..fcccca1cb3731 100644 --- a/test/Syntax/serialize_tupletype.swift.result +++ b/test/Syntax/serialize_tupletype.swift.result @@ -1,23 +1,23 @@ { - "id": 39, + "id": 40, "kind": "SourceFile", "layout": [ { - "id": 38, + "id": 39, "kind": "CodeBlockItemList", "layout": [ { - "id": 36, + "id": 37, "kind": "CodeBlockItem", "layout": [ { - "id": 35, + "id": 36, "kind": "TypealiasDecl", "layout": [ null, null, { - "id": 33, + "id": 34, "tokenKind": { "kind": "kw_typealias" }, @@ -48,7 +48,7 @@ "presence": "Present" }, { - "id": 34, + "id": 35, "tokenKind": { "kind": "identifier", "text": "x" @@ -64,11 +64,11 @@ }, null, { - "id": 32, + "id": 33, "kind": "TypeInitializerClause", "layout": [ { - "id": 1, + "id": 2, "tokenKind": { "kind": "equal" }, @@ -82,11 +82,11 @@ "presence": "Present" }, { - "id": 31, + "id": 32, "kind": "TupleType", "layout": [ { - "id": 18, + "id": 19, "tokenKind": { "kind": "l_paren" }, @@ -95,16 +95,16 @@ "presence": "Present" }, { - "id": 29, + "id": 30, "kind": "TupleTypeElementList", "layout": [ { - "id": 24, + "id": 25, "kind": "TupleTypeElement", "layout": [ null, { - "id": 19, + "id": 20, "tokenKind": { "kind": "identifier", "text": "b" @@ -115,7 +115,7 @@ }, null, { - "id": 20, + "id": 21, "tokenKind": { "kind": "colon" }, @@ -129,11 +129,11 @@ "presence": "Present" }, { - "id": 22, + "id": 23, "kind": "SimpleTypeIdentifier", "layout": [ { - "id": 21, + "id": 22, "tokenKind": { "kind": "identifier", "text": "Int" @@ -149,7 +149,7 @@ null, null, { - "id": 23, + "id": 24, "tokenKind": { "kind": "comma" }, @@ -166,12 +166,12 @@ "presence": "Present" }, { - "id": 28, + "id": 29, "kind": "TupleTypeElement", "layout": [ null, { - "id": 25, + "id": 26, "tokenKind": { "kind": "kw__" }, @@ -181,7 +181,7 @@ }, null, { - "id": 20, + "id": 21, "tokenKind": { "kind": "colon" }, @@ -195,11 +195,11 @@ "presence": "Present" }, { - "id": 27, + "id": 28, "kind": "SimpleTypeIdentifier", "layout": [ { - "id": 26, + "id": 27, "tokenKind": { "kind": "identifier", "text": "String" @@ -222,7 +222,7 @@ "presence": "Present" }, { - "id": 30, + "id": 31, "tokenKind": { "kind": "r_paren" }, @@ -249,7 +249,7 @@ "presence": "Present" }, { - "id": 37, + "id": 38, "tokenKind": { "kind": "eof", "text": "" diff --git a/utils/gyb_syntax_support/AttributeNodes.py b/utils/gyb_syntax_support/AttributeNodes.py index c185a1da30031..a663f92fae5d0 100644 --- a/utils/gyb_syntax_support/AttributeNodes.py +++ b/utils/gyb_syntax_support/AttributeNodes.py @@ -79,6 +79,7 @@ # attribute-list -> attribute attribute-list? Node('AttributeList', kind='SyntaxCollection', + omit_when_empty=True, element='Syntax', element_name='Attribute', element_choices=[ 'Attribute', diff --git a/utils/gyb_syntax_support/DeclNodes.py b/utils/gyb_syntax_support/DeclNodes.py index 6741725b51072..14111b3b45a7c 100644 --- a/utils/gyb_syntax_support/DeclNodes.py +++ b/utils/gyb_syntax_support/DeclNodes.py @@ -374,6 +374,7 @@ # | 'weak' # mutation-modifier -> 'mutating' | 'nonmutating' Node('ModifierList', kind='SyntaxCollection', + omit_when_empty=True, element='DeclModifier', element_name='Modifier'),