Skip to content

[SyntaxParse] Parse typealias declaration #27485

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 1 commit into from
Oct 3, 2019
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
7 changes: 7 additions & 0 deletions include/swift/Parse/ASTGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class ASTGen {
Decl *generate(const syntax::DeclSyntax &Decl, const SourceLoc Loc);
TypeDecl *generate(const syntax::AssociatedtypeDeclSyntax &Decl,
const SourceLoc Loc);
TypeDecl *generate(const syntax::TypealiasDeclSyntax &Decl,
const SourceLoc Loc);

TrailingWhereClause *generate(const syntax::GenericWhereClauseSyntax &syntax,
const SourceLoc Loc);
Expand All @@ -70,6 +72,11 @@ class ASTGen {
const Optional<syntax::ModifierListSyntax> &modifiers,
SourceLoc Loc, bool includeComments);

void generateFreeStandingGenericWhereClause(
const syntax::GenericWhereClauseSyntax &syntax,
const SourceLoc Loc,
GenericParamList *genericParams);

public:
//===--------------------------------------------------------------------===//
// Expressions.
Expand Down
8 changes: 8 additions & 0 deletions include/swift/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,11 @@ class Parser {
Optional<ParsedAttributeListSyntax> attrs,
Optional<ParsedModifierListSyntax> modifiers);

ParsedSyntaxResult<ParsedDeclSyntax>
parseDeclTypeAliasSyntax(ParseDeclOptions flags,
Optional<ParsedAttributeListSyntax> attrs,
Optional<ParsedModifierListSyntax> modifiers);

ParserResult<TypeDecl> parseDeclTypeAlias(ParseDeclOptions Flags,
DeclAttributes &Attributes,
SourceLoc leadingLoc);
Expand Down Expand Up @@ -1628,6 +1633,9 @@ class Parser {
SmallVectorImpl<GenericTypeParamDecl *> &GenericParams);
ParserResult<GenericParamList> maybeParseGenericParams();
void
diagnoseWhereClauseInGenericParamList(const GenericParamList *GenericParams,
SourceLoc whereLoc);
void
diagnoseWhereClauseInGenericParamList(const GenericParamList *GenericParams);

enum class WhereClauseKind : unsigned {
Expand Down
90 changes: 88 additions & 2 deletions lib/Parse/ASTGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "swift/Basic/SourceManager.h"
#include "swift/Parse/CodeCompletionCallbacks.h"
#include "swift/Parse/Parser.h"
#include "swift/Parse/Scope.h"

using namespace swift;
using namespace swift::syntax;
Expand Down Expand Up @@ -46,6 +47,8 @@ Decl *ASTGen::generate(const DeclSyntax &D, const SourceLoc Loc) {

if (auto associatedTypeDecl = D.getAs<AssociatedtypeDeclSyntax>()) {
DeclAST = generate(*associatedTypeDecl, Loc);
} else if (auto typealiasDecl = D.getAs<TypealiasDeclSyntax>()) {
DeclAST = generate(*typealiasDecl, Loc);
} else {
llvm_unreachable("unsupported decl kind");
}
Expand Down Expand Up @@ -105,8 +108,8 @@ TypeDecl *ASTGen::generate(const AssociatedtypeDeclSyntax &D,
return nullptr;

auto keywordLoc = advanceLocBegin(Loc, D.getAssociatedtypeKeyword());
auto name = Context.getIdentifier(idToken.getIdentifierText());
auto nameLoc = advanceLocBegin(Loc, idToken);
Identifier name;
SourceLoc nameLoc = generateIdentifierDeclName(idToken, Loc, name);

DeclAttributes attrs =
generateDeclAttributes(D, D.getAttributes(), D.getModifiers(), Loc, true);
Expand Down Expand Up @@ -136,6 +139,89 @@ TypeDecl *ASTGen::generate(const AssociatedtypeDeclSyntax &D,
return assocType;
}

TypeDecl *ASTGen::generate(const TypealiasDeclSyntax &D, const SourceLoc Loc) {
auto idToken = D.getIdentifier();
if (idToken.isMissing())
return nullptr;

auto keywordLoc = advanceLocBegin(Loc, D.getTypealiasKeyword());
Identifier name;
SourceLoc nameLoc = generateIdentifierDeclName(idToken, Loc, name);
auto attrs =
generateDeclAttributes(D, D.getAttributes(), D.getModifiers(), Loc, true);
SourceLoc equalLoc;

DebuggerContextChange DCC(P, name, DeclKind::TypeAlias);

Optional<Scope> GenericScope;
GenericParamList *genericParams = nullptr;
GenericScope.emplace(&P, ScopeKind::Generics);
if (auto clause = D.getGenericParameterClause())
genericParams = generate(*clause, Loc);

auto *TAD = new (Context) TypeAliasDecl(keywordLoc, equalLoc, name, nameLoc,
genericParams, P.CurDeclContext);
P.setLocalDiscriminator(TAD);
TAD->getAttrs() = attrs;

TypeRepr *underlyingType = nullptr;
SourceLoc typeEndLoc;
if (auto init = D.getInitializer()) {
Parser::ContextChange CC(P, TAD);
equalLoc = generate(init->getEqual(), Loc);
underlyingType = generate(init->getValue(), Loc);
if (auto lastToken = init->getLastToken())
typeEndLoc = generate(*lastToken, Loc);
}
TAD->setUnderlyingTypeRepr(underlyingType);

SourceLoc whereLoc;
if (auto clause = D.getGenericWhereClause()) {
whereLoc = advanceLocBegin(Loc, clause->getWhereKeyword());
Parser::ContextChange CC(P, TAD);
generateFreeStandingGenericWhereClause(*clause, Loc, genericParams);
}
P.diagnoseWhereClauseInGenericParamList(genericParams, whereLoc);

if (equalLoc.isInvalid())
return nullptr;

GenericScope.reset();

addToScope(TAD);
return DCC.fixupParserResult(TAD).getPtrOrNull();
}

void ASTGen::generateFreeStandingGenericWhereClause(
const syntax::GenericWhereClauseSyntax &syntax, const SourceLoc Loc,
GenericParamList *genericParams) {

SourceLoc whereLoc = generate(syntax.getWhereKeyword(), Loc);

if (!genericParams) {
P.diagnose(whereLoc, diag::where_without_generic_params,
unsigned(Parser::WhereClauseKind::Declaration));
return;
}

// Push the generic parameters back into a local scope so that references
// will find them.
Scope S(&P, ScopeKind::Generics);
for (auto pd : genericParams->getParams())
addToScope(pd);

SmallVector<RequirementRepr, 4> 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;

genericParams->addTrailingWhereClause(Context, whereLoc, requirements);
}

TrailingWhereClause *ASTGen::generate(const GenericWhereClauseSyntax &syntax,
const SourceLoc Loc) {
SourceLoc whereLoc = advanceLocBegin(Loc, syntax.getWhereKeyword());
Expand Down
156 changes: 83 additions & 73 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2782,7 +2782,6 @@ Parser::parseDecl(ParseDeclOptions Flags,
break;
}
case tok::kw_typealias:
DeclParsingContext.setCreateSyntax(SyntaxKind::TypealiasDecl);
DeclResult = parseDeclTypeAlias(Flags, Attributes, leadingLoc);
MayNeedOverrideCompletion = true;
break;
Expand Down Expand Up @@ -3977,115 +3976,126 @@ ParserStatus Parser::parseLineDirective(bool isLine) {

/// Parse a typealias decl.
///
/// \verbatim
/// decl-typealias:
/// 'typealias' identifier generic-params? '=' type requirement-clause?
/// \endverbatim
ParserResult<TypeDecl>
Parser::parseDeclTypeAlias(Parser::ParseDeclOptions Flags,
DeclAttributes &Attributes, SourceLoc leadingLoc) {
/// 'typealias' identifier generic-params? '=' type
/// generic-where-clause?
ParsedSyntaxResult<ParsedDeclSyntax>
Parser::parseDeclTypeAliasSyntax(Parser::ParseDeclOptions Flags,
Optional<ParsedAttributeListSyntax> attrs,
Optional<ParsedModifierListSyntax> modifiers) {
ParserPosition startPosition = getParserPosition();
llvm::Optional<SyntaxParsingContext> TmpCtxt;
TmpCtxt.emplace(SyntaxContext);
TmpCtxt->setBackTracking();

SourceLoc TypeAliasLoc = consumeToken(tok::kw_typealias);
SourceLoc EqualLoc;
Identifier Id;
SourceLoc IdLoc;
ParserStatus Status;
auto typealiasKeyword = consumeTokenSyntax(tok::kw_typealias);

Status |= parseIdentifierDeclName(
*this, Id, IdLoc, "typealias",
[](const Token &next) { return next.isAny(tok::colon, tok::equal); });
if (Status.isError()) {
TmpCtxt->setTransparent();
return nullptr;
}
ParserStatus status;

DebuggerContextChange DCC(*this, Id, DeclKind::TypeAlias);
auto applyIntroducer = [&](ParsedTypealiasDeclSyntaxBuilder &builder) {
if (attrs)
builder.useAttributes(std::move(*attrs));
if (modifiers)
builder.useModifiers(std::move(*modifiers));
builder.useTypealiasKeyword(std::move(typealiasKeyword));
};

Optional<Scope> GenericsScope;
GenericsScope.emplace(this, ScopeKind::Generics);
// Parse the name.
auto name =
parseIdentifierDeclNameSyntax(*this, "typealias", [](const Token &next) {
return next.isAny(tok::colon, tok::equal);
});
if (name.isNull()) {
TmpCtxt->setTransparent();
TmpCtxt.reset();
ParsedTypealiasDeclSyntaxBuilder builder(*SyntaxContext);
applyIntroducer(builder);
return makeParsedError(builder.build());
}

// Parse a generic parameter list if it is present.
GenericParamList *genericParams = nullptr;
// Parse optional generic parameters.
Optional<ParsedGenericParameterClauseSyntax> genericParams;
if (startsWithLess(Tok)) {
auto Result = parseGenericParameters();
if (Result.hasCodeCompletion() && !CodeCompletion)
return makeParserCodeCompletionStatus();
genericParams = Result.getPtrOrNull();

if (!genericParams) {
// If the parser returned null, it is an already diagnosed parse error.
} else if (!genericParams->getRequirements().empty()) {
// Reject a where clause.
diagnose(genericParams->getWhereLoc(),
diag::associated_type_generic_parameter_list)
.highlight(genericParams->getWhereClauseSourceRange());
}
auto result = parseGenericParameterClauseSyntax();
status |= result.getStatus();
if (!result.isNull())
genericParams = result.get();
}

if (Flags.contains(PD_InProtocol) && !genericParams && !Tok.is(tok::equal)) {
// If we're in a protocol and don't see an '=' this looks like leftover
// Swift 2 code intending to be an associatedtype.
TmpCtxt.reset();
// 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, leadingLoc);
return parseDeclAssociatedTypeSyntax(Flags, std::move(attrs),
std::move(modifiers));
}

TmpCtxt->setTransparent();
TmpCtxt.reset();

auto *TAD = new (Context) TypeAliasDecl(TypeAliasLoc, EqualLoc, Id, IdLoc,
genericParams, CurDeclContext);
setLocalDiscriminator(TAD);
ParserResult<TypeRepr> UnderlyingTy;
ParsedTypealiasDeclSyntaxBuilder builder(*SyntaxContext);
applyIntroducer(builder);
builder.useIdentifier(name.get());
if (genericParams)
builder.useGenericParameterClause(std::move(*genericParams));

if (Tok.is(tok::colon) || Tok.is(tok::equal)) {
ContextChange CC(*this, TAD);
// Parse underlying type clause.
if (Tok.isAny(tok::equal, tok::colon)) {
ParsedTypeInitializerClauseSyntaxBuilder initBuilder(*SyntaxContext);

SyntaxParsingContext InitCtx(SyntaxContext,
SyntaxKind::TypeInitializerClause);
// Parse '='.
if (Tok.is(tok::colon)) {
// It is a common mistake to write "typealias A : Int" instead of = Int.
// Recognize this and produce a fixit.
diagnose(Tok, diag::expected_equal_in_typealias)
.fixItReplace(Tok.getLoc(), " = ");
EqualLoc = consumeToken(tok::colon);
ignoreToken(tok::colon);
} else {
EqualLoc = consumeToken(tok::equal);
initBuilder.useEqual(consumeTokenSyntax());
}

UnderlyingTy = parseType(diag::expected_type_in_typealias);
TAD->setTypeEndLoc(PreviousLoc);
Status |= UnderlyingTy;
// Parse the underlying type.
auto underlyingType = parseTypeSyntax(diag::expected_type_in_typealias);
status |= underlyingType.getStatus();
if (!underlyingType.isNull()) {
initBuilder.useValue(underlyingType.get());
} else {
initBuilder.useValue(
ParsedSyntaxRecorder::makeUnknownType({}, *SyntaxContext));
}
builder.useInitializer(initBuilder.build());
} else {
diagnose(Tok, diag::expected_equal_in_typealias);
status.setIsParseError();
}

TAD->setUnderlyingTypeRepr(UnderlyingTy.getPtrOrNull());
TAD->getAttrs() = Attributes;

// Parse a 'where' clause if present, adding it to our GenericParamList.
// Parse optional where clause.
if (Tok.is(tok::kw_where)) {
ContextChange CC(*this, TAD);
Status |= parseFreestandingGenericWhereClause(genericParams);
bool FirstTypeInComplete = false;
auto whereClause = parseGenericWhereClauseSyntax(FirstTypeInComplete);
status |= whereClause.getStatus();
builder.useGenericWhereClause(whereClause.get());
}

if (UnderlyingTy.isNull()) {
// If there is an attempt to do code completion
// inside of typealias type, let's just return
// because we've seen required '=' token.
if (EqualLoc.isInvalid()) {
diagnose(Tok, diag::expected_equal_in_typealias);
Status.setIsParseError();
return Status;
}
}
return makeParsedResult(builder.build(), status);
}

// Exit the scope introduced for the generic parameters.
GenericsScope.reset();
ParserResult<TypeDecl>
Parser::parseDeclTypeAlias(Parser::ParseDeclOptions Flags,
DeclAttributes &Attributes, SourceLoc leadingLoc) {
auto modifiers = SyntaxContext->popIf<ParsedModifierListSyntax>();
auto attrs = SyntaxContext->popIf<ParsedAttributeListSyntax>();

auto parsed =
parseDeclTypeAliasSyntax(Flags, std::move(attrs), std::move(modifiers));
assert(!parsed.isNull());

addToScope(TAD);
return DCC.fixupParserResult(Status, TAD);
SyntaxContext->addSyntax(parsed.get());
auto syntax = SyntaxContext->topNode<DeclSyntax>();
TypeDecl *result =
cast_or_null<TypeDecl>(Generator.generate(syntax, leadingLoc));
return makeParserResult(parsed.getStatus(), result);
}

/// Parse an associatedtype decl.
Expand Down
Loading