Skip to content

Add support for parsing designated protocols in operator declarations. #19145

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 2 commits into from
Sep 7, 2018
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
108 changes: 72 additions & 36 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -6256,22 +6256,49 @@ class OperatorDecl : public Decl {

Identifier name;

Identifier DesignatedProtocolName;
SourceLoc DesignatedProtocolNameLoc;
TypeLoc DesignatedProtocolTypeLoc;

public:
OperatorDecl(DeclKind kind,
DeclContext *DC,
SourceLoc OperatorLoc,
Identifier Name,
SourceLoc NameLoc)
: Decl(kind, DC),
OperatorLoc(OperatorLoc), NameLoc(NameLoc),
name(Name) {}

OperatorDecl(DeclKind kind, DeclContext *DC, SourceLoc OperatorLoc,
Identifier Name, SourceLoc NameLoc,
Identifier DesignatedProtocolName = Identifier(),
SourceLoc DesignatedProtocolNameLoc = SourceLoc())
: Decl(kind, DC), OperatorLoc(OperatorLoc), NameLoc(NameLoc), name(Name),
DesignatedProtocolName(DesignatedProtocolName),
DesignatedProtocolNameLoc(DesignatedProtocolNameLoc) {}

SourceLoc getLoc() const { return NameLoc; }

SourceLoc getOperatorLoc() const { return OperatorLoc; }
SourceLoc getNameLoc() const { return NameLoc; }
Identifier getName() const { return name; }


Identifier getDesignatedProtocolName() const {
return DesignatedProtocolName;
}

void setDesignatedProtocolName(Identifier name) {
DesignatedProtocolName = name;
}

SourceLoc getDesignatedProtocolNameLoc() const {
return DesignatedProtocolNameLoc;
}

void setDesignatedProtocolNameLoc(SourceLoc loc) {
DesignatedProtocolNameLoc = loc;
}

TypeLoc getDesignatedProtocolTypeLoc() const {
return DesignatedProtocolTypeLoc;
}

void setDesignatedProtocolTypeLoc(TypeLoc typeLoc) {
DesignatedProtocolTypeLoc = typeLoc;
}

static bool classof(const Decl *D) {
// Workaround: http://llvm.org/PR35906
if (DeclKind::Last_Decl == DeclKind::Last_OperatorDecl)
Expand All @@ -6284,39 +6311,42 @@ class OperatorDecl : public Decl {
/// Declares the behavior of an infix operator. For example:
///
/// \code
/// infix operator /+/ : AdditivePrecedence
/// infix operator /+/ : AdditionPrecedence, Numeric
/// \endcode
class InfixOperatorDecl : public OperatorDecl {
SourceLoc ColonLoc, PrecedenceGroupNameLoc;
Identifier PrecedenceGroupName;
SourceLoc ColonLoc, FirstIdentifierLoc, SecondIdentifierLoc;
Identifier FirstIdentifier, SecondIdentifier;
PrecedenceGroupDecl *PrecedenceGroup = nullptr;

public:
InfixOperatorDecl(DeclContext *DC,
SourceLoc operatorLoc,
Identifier name,
SourceLoc nameLoc,
SourceLoc colonLoc,
Identifier precedenceGroupName,
SourceLoc precedenceGroupNameLoc)
: OperatorDecl(DeclKind::InfixOperator, DC, operatorLoc, name, nameLoc),
ColonLoc(colonLoc), PrecedenceGroupNameLoc(precedenceGroupNameLoc),
PrecedenceGroupName(precedenceGroupName) {
}
InfixOperatorDecl(DeclContext *DC, SourceLoc operatorLoc, Identifier name,
SourceLoc nameLoc, SourceLoc colonLoc,
Identifier firstIdentifier, SourceLoc firstIdentifierLoc,
Identifier secondIdentifier = Identifier(),
SourceLoc secondIdentifierLoc = SourceLoc())
: OperatorDecl(DeclKind::InfixOperator, DC, operatorLoc, name, nameLoc),
ColonLoc(colonLoc), FirstIdentifierLoc(firstIdentifierLoc),
SecondIdentifierLoc(secondIdentifierLoc),
FirstIdentifier(firstIdentifier), SecondIdentifier(secondIdentifier) {}

SourceLoc getEndLoc() const {
if (PrecedenceGroupName.empty())
return getNameLoc();
return PrecedenceGroupNameLoc;
if (!SecondIdentifier.empty())
return SecondIdentifierLoc;
if (!FirstIdentifier.empty())
return FirstIdentifierLoc;
return getNameLoc();
}
SourceRange getSourceRange() const {
return { getOperatorLoc(), getEndLoc() };
}

SourceLoc getColonLoc() const { return ColonLoc; }
SourceLoc getPrecedenceGroupNameLoc() const { return PrecedenceGroupNameLoc; }
SourceLoc getFirstIdentifierLoc() const { return FirstIdentifierLoc; }
SourceLoc getSecondIdentifierLoc() const { return SecondIdentifierLoc; }

Identifier getFirstIdentifier() const { return FirstIdentifier; }
Identifier getSecondIdentifier() const { return SecondIdentifier; }

Identifier getPrecedenceGroupName() const { return PrecedenceGroupName; }
PrecedenceGroupDecl *getPrecedenceGroup() const { return PrecedenceGroup; }
void setPrecedenceGroup(PrecedenceGroupDecl *PGD) {
PrecedenceGroup = PGD;
Expand All @@ -6341,8 +6371,11 @@ class InfixOperatorDecl : public OperatorDecl {
class PrefixOperatorDecl : public OperatorDecl {
public:
PrefixOperatorDecl(DeclContext *DC, SourceLoc OperatorLoc, Identifier Name,
SourceLoc NameLoc)
: OperatorDecl(DeclKind::PrefixOperator, DC, OperatorLoc, Name, NameLoc) {}
SourceLoc NameLoc,
Identifier DesignatedProtocolName = Identifier(),
SourceLoc DesignatedProtocolNameLoc = SourceLoc())
: OperatorDecl(DeclKind::PrefixOperator, DC, OperatorLoc, Name, NameLoc,
DesignatedProtocolName, DesignatedProtocolNameLoc) {}

SourceRange getSourceRange() const {
return { getOperatorLoc(), getNameLoc() };
Expand All @@ -6367,9 +6400,12 @@ class PrefixOperatorDecl : public OperatorDecl {
class PostfixOperatorDecl : public OperatorDecl {
public:
PostfixOperatorDecl(DeclContext *DC, SourceLoc OperatorLoc, Identifier Name,
SourceLoc NameLoc)
: OperatorDecl(DeclKind::PostfixOperator, DC, OperatorLoc, Name, NameLoc) {}

SourceLoc NameLoc,
Identifier DesignatedProtocolName = Identifier(),
SourceLoc DesignatedProtocolNameLoc = SourceLoc())
: OperatorDecl(DeclKind::PostfixOperator, DC, OperatorLoc, Name, NameLoc,
DesignatedProtocolName, DesignatedProtocolNameLoc) {}

SourceRange getSourceRange() const {
return { getOperatorLoc(), getNameLoc() };
}
Expand Down
5 changes: 4 additions & 1 deletion include/swift/AST/DiagnosticsParse.def
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -427,6 +427,9 @@ ERROR(deprecated_operator_body_use_group,PointsToFirstBadToken,
ERROR(operator_decl_no_fixity,none,
"operator must be declared as 'prefix', 'postfix', or 'infix'", ())

ERROR(operator_decl_trailing_comma,none,
"expected designated protocol in operator declaration", ())

// PrecedenceGroup
ERROR(precedencegroup_not_infix,none,
"only infix operators may declare a precedence", ())
Expand Down
3 changes: 3 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,9 @@ ERROR(unspaced_unary_operator,none,
"unary operators must not be juxtaposed; parenthesize inner expression",
())

ERROR(operators_designated_protocol_not_a_protocol,none,
"type %0 unexpected; expected a protocol type",
(Type))

ERROR(use_unresolved_identifier,none,
"use of unresolved %select{identifier|operator}1 %0", (DeclName, bool))
Expand Down
3 changes: 3 additions & 0 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,9 @@ namespace swift {
/// \brief Enable experimental property behavior feature.
bool EnableExperimentalPropertyBehaviors = false;

/// \brief Enable experimental operator protocol designator feature.
bool EnableOperatorDesignatedProtocols = false;

/// \brief Staging flag for treating inout parameters as Thread Sanitizer
/// accesses.
bool DisableTsanInoutInstrumentation = false;
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,10 @@ def enable_experimental_property_behaviors :
Flag<["-"], "enable-experimental-property-behaviors">,
HelpText<"Enable experimental property behaviors">;

def enable_operator_designated_protocols :
Flag<["-"], "enable-operator-designated-protocols">,
HelpText<"Enable operator designated protocols">;

def enable_deserialization_recovery :
Flag<["-"], "enable-deserialization-recovery">,
HelpText<"Attempt to recover from missing xrefs (etc) in swiftmodules">;
Expand Down
12 changes: 9 additions & 3 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -1168,8 +1168,14 @@ namespace {
printCommon(IOD, "infix_operator_decl ");
OS << IOD->getName() << "\n";
OS.indent(Indent+2);
OS << "precedence " << IOD->getPrecedenceGroupName();
if (!IOD->getPrecedenceGroup()) OS << " <null>";
if (!IOD->getFirstIdentifier().empty())
OS << "first identifier " << IOD->getFirstIdentifier();
else
OS << "first identifier <null>";
if (!IOD->getSecondIdentifier().empty())
OS << "second identifier " << IOD->getSecondIdentifier();
else
OS << "second identifier <null>";
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}

Expand Down
11 changes: 8 additions & 3 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2803,9 +2803,10 @@ void PrintAST::visitInfixOperatorDecl(InfixOperatorDecl *decl) {
[&]{
Printer.printName(decl->getName());
});
if (!decl->getPrecedenceGroupName().empty()) {
Printer << " : " << decl->getPrecedenceGroupName();
}
if (!decl->getFirstIdentifier().empty())
Printer << " : " << decl->getFirstIdentifier();
if (!decl->getSecondIdentifier().empty())
Printer << ", " << decl->getSecondIdentifier();
}

void PrintAST::visitPrecedenceGroupDecl(PrecedenceGroupDecl *decl) {
Expand Down Expand Up @@ -2878,6 +2879,8 @@ void PrintAST::visitPrefixOperatorDecl(PrefixOperatorDecl *decl) {
[&]{
Printer.printName(decl->getName());
});
if (!decl->getDesignatedProtocolName().empty())
Printer << " : " << decl->getDesignatedProtocolName();
}

void PrintAST::visitPostfixOperatorDecl(PostfixOperatorDecl *decl) {
Expand All @@ -2887,6 +2890,8 @@ void PrintAST::visitPostfixOperatorDecl(PostfixOperatorDecl *decl) {
[&]{
Printer.printName(decl->getName());
});
if (!decl->getDesignatedProtocolName().empty())
Printer << " : " << decl->getDesignatedProtocolName();
}

void PrintAST::visitModuleDecl(ModuleDecl *decl) { }
Expand Down
3 changes: 3 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.EnableExperimentalPropertyBehaviors |=
Args.hasArg(OPT_enable_experimental_property_behaviors);

Opts.EnableOperatorDesignatedProtocols |=
Args.hasArg(OPT_enable_operator_designated_protocols);

if (auto A = Args.getLastArg(OPT_enable_deserialization_recovery,
OPT_disable_deserialization_recovery)) {
Opts.EnableDeserializationRecovery
Expand Down
62 changes: 42 additions & 20 deletions lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
Expand Down Expand Up @@ -6309,21 +6309,41 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name,
bool isPrefix = Attributes.hasAttribute<PrefixAttr>();
bool isInfix = Attributes.hasAttribute<InfixAttr>();
bool isPostfix = Attributes.hasAttribute<PostfixAttr>();

// Parse (or diagnose) a specified precedence group.

// Parse (or diagnose) a specified precedence group and/or
// designated protocol. These both look like identifiers, so we
// parse them both as identifiers here and sort it out in type
// checking.
SourceLoc colonLoc;
Identifier precedenceGroupName;
SourceLoc precedenceGroupNameLoc;
Identifier firstIdentifierName;
SourceLoc firstIdentifierNameLoc;
Identifier secondIdentifierName;
SourceLoc secondIdentifierNameLoc;
if (Tok.is(tok::colon)) {
SyntaxParsingContext GroupCtxt(SyntaxContext, SyntaxKind::InfixOperatorGroup);
colonLoc = consumeToken();
if (Tok.is(tok::identifier)) {
precedenceGroupName = Context.getIdentifier(Tok.getText());
precedenceGroupNameLoc = consumeToken(tok::identifier);

if (isPrefix || isPostfix)
firstIdentifierName = Context.getIdentifier(Tok.getText());
firstIdentifierNameLoc = consumeToken(tok::identifier);

if (Context.LangOpts.EnableOperatorDesignatedProtocols) {
if (consumeIf(tok::comma)) {
if (isPrefix || isPostfix)
diagnose(colonLoc, diag::precedencegroup_not_infix)
.fixItRemove({colonLoc, firstIdentifierNameLoc});

if (Tok.is(tok::identifier)) {
secondIdentifierName = Context.getIdentifier(Tok.getText());
secondIdentifierNameLoc = consumeToken(tok::identifier);
} else {
auto otherTokLoc = consumeToken();
diagnose(otherTokLoc, diag::operator_decl_trailing_comma);
}
}
} else if (isPrefix || isPostfix) {
diagnose(colonLoc, diag::precedencegroup_not_infix)
.fixItRemove({colonLoc, precedenceGroupNameLoc});
.fixItRemove({colonLoc, firstIdentifierNameLoc});
}
}
}

Expand All @@ -6335,7 +6355,7 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name,
} else {
auto Diag = diagnose(lBraceLoc, diag::deprecated_operator_body);
if (Tok.is(tok::r_brace)) {
SourceLoc lastGoodLoc = precedenceGroupNameLoc;
SourceLoc lastGoodLoc = firstIdentifierNameLoc;
if (lastGoodLoc.isInvalid())
lastGoodLoc = NameLoc;
SourceLoc lastGoodLocEnd = Lexer::getLocForEndOfToken(SourceMgr,
Expand All @@ -6351,17 +6371,19 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name,

OperatorDecl *res;
if (Attributes.hasAttribute<PrefixAttr>())
res = new (Context) PrefixOperatorDecl(CurDeclContext, OperatorLoc,
Name, NameLoc);
res = new (Context)
PrefixOperatorDecl(CurDeclContext, OperatorLoc, Name, NameLoc,
firstIdentifierName, firstIdentifierNameLoc);
else if (Attributes.hasAttribute<PostfixAttr>())
res = new (Context) PostfixOperatorDecl(CurDeclContext, OperatorLoc,
Name, NameLoc);
res = new (Context)
PostfixOperatorDecl(CurDeclContext, OperatorLoc, Name, NameLoc,
firstIdentifierName, firstIdentifierNameLoc);
else
res = new (Context) InfixOperatorDecl(CurDeclContext, OperatorLoc,
Name, NameLoc, colonLoc,
precedenceGroupName,
precedenceGroupNameLoc);
res = new (Context)
InfixOperatorDecl(CurDeclContext, OperatorLoc, Name, NameLoc, colonLoc,
firstIdentifierName, firstIdentifierNameLoc,
secondIdentifierName, secondIdentifierNameLoc);

diagnoseOperatorFixityAttributes(*this, Attributes, res);

res->getAttrs() = Attributes;
Expand Down
Loading