Skip to content

Commit 039d10b

Browse files
committed
Add support for parsing designated protocols in operator declarations.
The support is gated by a frontend option, -enable-operator-designated-protocols. This means that in an operator declaration we can declare a protocol which has one or more requirements specifying this operator. The operators from that designated protocol will be the first ones we try when type checking an expression. If we successfully typecheck using the operators specified in that protocol, we do not attempt any other overloads of the same operator. This makes it possible to dramatically speed up successful typechecking.
1 parent ae84ac8 commit 039d10b

File tree

9 files changed

+298
-92
lines changed

9 files changed

+298
-92
lines changed

include/swift/AST/Decl.h

Lines changed: 72 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -6256,22 +6256,49 @@ class OperatorDecl : public Decl {
62566256

62576257
Identifier name;
62586258

6259+
Identifier DesignatedProtocolName;
6260+
SourceLoc DesignatedProtocolNameLoc;
6261+
TypeLoc DesignatedProtocolTypeLoc;
6262+
62596263
public:
6260-
OperatorDecl(DeclKind kind,
6261-
DeclContext *DC,
6262-
SourceLoc OperatorLoc,
6263-
Identifier Name,
6264-
SourceLoc NameLoc)
6265-
: Decl(kind, DC),
6266-
OperatorLoc(OperatorLoc), NameLoc(NameLoc),
6267-
name(Name) {}
6268-
6264+
OperatorDecl(DeclKind kind, DeclContext *DC, SourceLoc OperatorLoc,
6265+
Identifier Name, SourceLoc NameLoc,
6266+
Identifier DesignatedProtocolName = Identifier(),
6267+
SourceLoc DesignatedProtocolNameLoc = SourceLoc())
6268+
: Decl(kind, DC), OperatorLoc(OperatorLoc), NameLoc(NameLoc), name(Name),
6269+
DesignatedProtocolName(DesignatedProtocolName),
6270+
DesignatedProtocolNameLoc(DesignatedProtocolNameLoc) {}
6271+
62696272
SourceLoc getLoc() const { return NameLoc; }
62706273

62716274
SourceLoc getOperatorLoc() const { return OperatorLoc; }
62726275
SourceLoc getNameLoc() const { return NameLoc; }
62736276
Identifier getName() const { return name; }
6274-
6277+
6278+
Identifier getDesignatedProtocolName() const {
6279+
return DesignatedProtocolName;
6280+
}
6281+
6282+
void setDesignatedProtocolName(Identifier name) {
6283+
DesignatedProtocolName = name;
6284+
}
6285+
6286+
SourceLoc getDesignatedProtocolNameLoc() const {
6287+
return DesignatedProtocolNameLoc;
6288+
}
6289+
6290+
void setDesignatedProtocolNameLoc(SourceLoc loc) {
6291+
DesignatedProtocolNameLoc = loc;
6292+
}
6293+
6294+
TypeLoc getDesignatedProtocolTypeLoc() const {
6295+
return DesignatedProtocolTypeLoc;
6296+
}
6297+
6298+
void setDesignatedProtocolTypeLoc(TypeLoc typeLoc) {
6299+
DesignatedProtocolTypeLoc = typeLoc;
6300+
}
6301+
62756302
static bool classof(const Decl *D) {
62766303
// Workaround: http://llvm.org/PR35906
62776304
if (DeclKind::Last_Decl == DeclKind::Last_OperatorDecl)
@@ -6284,39 +6311,42 @@ class OperatorDecl : public Decl {
62846311
/// Declares the behavior of an infix operator. For example:
62856312
///
62866313
/// \code
6287-
/// infix operator /+/ : AdditivePrecedence
6314+
/// infix operator /+/ : AdditionPrecedence, Numeric
62886315
/// \endcode
62896316
class InfixOperatorDecl : public OperatorDecl {
6290-
SourceLoc ColonLoc, PrecedenceGroupNameLoc;
6291-
Identifier PrecedenceGroupName;
6317+
SourceLoc ColonLoc, FirstIdentifierLoc, SecondIdentifierLoc;
6318+
Identifier FirstIdentifier, SecondIdentifier;
62926319
PrecedenceGroupDecl *PrecedenceGroup = nullptr;
62936320

62946321
public:
6295-
InfixOperatorDecl(DeclContext *DC,
6296-
SourceLoc operatorLoc,
6297-
Identifier name,
6298-
SourceLoc nameLoc,
6299-
SourceLoc colonLoc,
6300-
Identifier precedenceGroupName,
6301-
SourceLoc precedenceGroupNameLoc)
6302-
: OperatorDecl(DeclKind::InfixOperator, DC, operatorLoc, name, nameLoc),
6303-
ColonLoc(colonLoc), PrecedenceGroupNameLoc(precedenceGroupNameLoc),
6304-
PrecedenceGroupName(precedenceGroupName) {
6305-
}
6322+
InfixOperatorDecl(DeclContext *DC, SourceLoc operatorLoc, Identifier name,
6323+
SourceLoc nameLoc, SourceLoc colonLoc,
6324+
Identifier firstIdentifier, SourceLoc firstIdentifierLoc,
6325+
Identifier secondIdentifier = Identifier(),
6326+
SourceLoc secondIdentifierLoc = SourceLoc())
6327+
: OperatorDecl(DeclKind::InfixOperator, DC, operatorLoc, name, nameLoc),
6328+
ColonLoc(colonLoc), FirstIdentifierLoc(firstIdentifierLoc),
6329+
SecondIdentifierLoc(secondIdentifierLoc),
6330+
FirstIdentifier(firstIdentifier), SecondIdentifier(secondIdentifier) {}
63066331

63076332
SourceLoc getEndLoc() const {
6308-
if (PrecedenceGroupName.empty())
6309-
return getNameLoc();
6310-
return PrecedenceGroupNameLoc;
6333+
if (!SecondIdentifier.empty())
6334+
return SecondIdentifierLoc;
6335+
if (!FirstIdentifier.empty())
6336+
return FirstIdentifierLoc;
6337+
return getNameLoc();
63116338
}
63126339
SourceRange getSourceRange() const {
63136340
return { getOperatorLoc(), getEndLoc() };
63146341
}
6315-
6342+
63166343
SourceLoc getColonLoc() const { return ColonLoc; }
6317-
SourceLoc getPrecedenceGroupNameLoc() const { return PrecedenceGroupNameLoc; }
6344+
SourceLoc getFirstIdentifierLoc() const { return FirstIdentifierLoc; }
6345+
SourceLoc getSecondIdentifierLoc() const { return SecondIdentifierLoc; }
6346+
6347+
Identifier getFirstIdentifier() const { return FirstIdentifier; }
6348+
Identifier getSecondIdentifier() const { return SecondIdentifier; }
63186349

6319-
Identifier getPrecedenceGroupName() const { return PrecedenceGroupName; }
63206350
PrecedenceGroupDecl *getPrecedenceGroup() const { return PrecedenceGroup; }
63216351
void setPrecedenceGroup(PrecedenceGroupDecl *PGD) {
63226352
PrecedenceGroup = PGD;
@@ -6341,8 +6371,11 @@ class InfixOperatorDecl : public OperatorDecl {
63416371
class PrefixOperatorDecl : public OperatorDecl {
63426372
public:
63436373
PrefixOperatorDecl(DeclContext *DC, SourceLoc OperatorLoc, Identifier Name,
6344-
SourceLoc NameLoc)
6345-
: OperatorDecl(DeclKind::PrefixOperator, DC, OperatorLoc, Name, NameLoc) {}
6374+
SourceLoc NameLoc,
6375+
Identifier DesignatedProtocolName = Identifier(),
6376+
SourceLoc DesignatedProtocolNameLoc = SourceLoc())
6377+
: OperatorDecl(DeclKind::PrefixOperator, DC, OperatorLoc, Name, NameLoc,
6378+
DesignatedProtocolName, DesignatedProtocolNameLoc) {}
63466379

63476380
SourceRange getSourceRange() const {
63486381
return { getOperatorLoc(), getNameLoc() };
@@ -6367,9 +6400,12 @@ class PrefixOperatorDecl : public OperatorDecl {
63676400
class PostfixOperatorDecl : public OperatorDecl {
63686401
public:
63696402
PostfixOperatorDecl(DeclContext *DC, SourceLoc OperatorLoc, Identifier Name,
6370-
SourceLoc NameLoc)
6371-
: OperatorDecl(DeclKind::PostfixOperator, DC, OperatorLoc, Name, NameLoc) {}
6372-
6403+
SourceLoc NameLoc,
6404+
Identifier DesignatedProtocolName = Identifier(),
6405+
SourceLoc DesignatedProtocolNameLoc = SourceLoc())
6406+
: OperatorDecl(DeclKind::PostfixOperator, DC, OperatorLoc, Name, NameLoc,
6407+
DesignatedProtocolName, DesignatedProtocolNameLoc) {}
6408+
63736409
SourceRange getSourceRange() const {
63746410
return { getOperatorLoc(), getNameLoc() };
63756411
}

include/swift/AST/DiagnosticsParse.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -427,6 +427,9 @@ ERROR(deprecated_operator_body_use_group,PointsToFirstBadToken,
427427
ERROR(operator_decl_no_fixity,none,
428428
"operator must be declared as 'prefix', 'postfix', or 'infix'", ())
429429

430+
ERROR(operator_decl_trailing_comma,none,
431+
"expected designated protocol in operator declaration", ())
432+
430433
// PrecedenceGroup
431434
ERROR(precedencegroup_not_infix,none,
432435
"only infix operators may declare a precedence", ())

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,9 @@ ERROR(unspaced_unary_operator,none,
706706
"unary operators must not be juxtaposed; parenthesize inner expression",
707707
())
708708

709+
ERROR(operators_designated_protocol_not_a_protocol,none,
710+
"type %0 unexpected; expected a protocol type",
711+
(Type))
709712

710713
ERROR(use_unresolved_identifier,none,
711714
"use of unresolved %select{identifier|operator}1 %0", (DeclName, bool))

lib/AST/ASTDumper.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -1168,8 +1168,14 @@ namespace {
11681168
printCommon(IOD, "infix_operator_decl ");
11691169
OS << IOD->getName() << "\n";
11701170
OS.indent(Indent+2);
1171-
OS << "precedence " << IOD->getPrecedenceGroupName();
1172-
if (!IOD->getPrecedenceGroup()) OS << " <null>";
1171+
if (!IOD->getFirstIdentifier().empty())
1172+
OS << "first identifier " << IOD->getFirstIdentifier();
1173+
else
1174+
OS << "first identifier <null>";
1175+
if (!IOD->getSecondIdentifier().empty())
1176+
OS << "second identifier " << IOD->getSecondIdentifier();
1177+
else
1178+
OS << "second identifier <null>";
11731179
PrintWithColorRAII(OS, ParenthesisColor) << ')';
11741180
}
11751181

lib/AST/ASTPrinter.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2803,9 +2803,10 @@ void PrintAST::visitInfixOperatorDecl(InfixOperatorDecl *decl) {
28032803
[&]{
28042804
Printer.printName(decl->getName());
28052805
});
2806-
if (!decl->getPrecedenceGroupName().empty()) {
2807-
Printer << " : " << decl->getPrecedenceGroupName();
2808-
}
2806+
if (!decl->getFirstIdentifier().empty())
2807+
Printer << " : " << decl->getFirstIdentifier();
2808+
if (!decl->getSecondIdentifier().empty())
2809+
Printer << ", " << decl->getSecondIdentifier();
28092810
}
28102811

28112812
void PrintAST::visitPrecedenceGroupDecl(PrecedenceGroupDecl *decl) {
@@ -2878,6 +2879,8 @@ void PrintAST::visitPrefixOperatorDecl(PrefixOperatorDecl *decl) {
28782879
[&]{
28792880
Printer.printName(decl->getName());
28802881
});
2882+
if (!decl->getDesignatedProtocolName().empty())
2883+
Printer << " : " << decl->getDesignatedProtocolName();
28812884
}
28822885

28832886
void PrintAST::visitPostfixOperatorDecl(PostfixOperatorDecl *decl) {
@@ -2887,6 +2890,8 @@ void PrintAST::visitPostfixOperatorDecl(PostfixOperatorDecl *decl) {
28872890
[&]{
28882891
Printer.printName(decl->getName());
28892892
});
2893+
if (!decl->getDesignatedProtocolName().empty())
2894+
Printer << " : " << decl->getDesignatedProtocolName();
28902895
}
28912896

28922897
void PrintAST::visitModuleDecl(ModuleDecl *decl) { }

lib/Parse/ParseDecl.cpp

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -6309,21 +6309,41 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name,
63096309
bool isPrefix = Attributes.hasAttribute<PrefixAttr>();
63106310
bool isInfix = Attributes.hasAttribute<InfixAttr>();
63116311
bool isPostfix = Attributes.hasAttribute<PostfixAttr>();
6312-
6313-
// Parse (or diagnose) a specified precedence group.
6312+
6313+
// Parse (or diagnose) a specified precedence group and/or
6314+
// designated protocol. These both look like identifiers, so we
6315+
// parse them both as identifiers here and sort it out in type
6316+
// checking.
63146317
SourceLoc colonLoc;
6315-
Identifier precedenceGroupName;
6316-
SourceLoc precedenceGroupNameLoc;
6318+
Identifier firstIdentifierName;
6319+
SourceLoc firstIdentifierNameLoc;
6320+
Identifier secondIdentifierName;
6321+
SourceLoc secondIdentifierNameLoc;
63176322
if (Tok.is(tok::colon)) {
63186323
SyntaxParsingContext GroupCtxt(SyntaxContext, SyntaxKind::InfixOperatorGroup);
63196324
colonLoc = consumeToken();
63206325
if (Tok.is(tok::identifier)) {
6321-
precedenceGroupName = Context.getIdentifier(Tok.getText());
6322-
precedenceGroupNameLoc = consumeToken(tok::identifier);
6323-
6324-
if (isPrefix || isPostfix)
6326+
firstIdentifierName = Context.getIdentifier(Tok.getText());
6327+
firstIdentifierNameLoc = consumeToken(tok::identifier);
6328+
6329+
if (Context.LangOpts.EnableOperatorDesignatedProtocols) {
6330+
if (consumeIf(tok::comma)) {
6331+
if (isPrefix || isPostfix)
6332+
diagnose(colonLoc, diag::precedencegroup_not_infix)
6333+
.fixItRemove({colonLoc, firstIdentifierNameLoc});
6334+
6335+
if (Tok.is(tok::identifier)) {
6336+
secondIdentifierName = Context.getIdentifier(Tok.getText());
6337+
secondIdentifierNameLoc = consumeToken(tok::identifier);
6338+
} else {
6339+
auto otherTokLoc = consumeToken();
6340+
diagnose(otherTokLoc, diag::operator_decl_trailing_comma);
6341+
}
6342+
}
6343+
} else if (isPrefix || isPostfix) {
63256344
diagnose(colonLoc, diag::precedencegroup_not_infix)
6326-
.fixItRemove({colonLoc, precedenceGroupNameLoc});
6345+
.fixItRemove({colonLoc, firstIdentifierNameLoc});
6346+
}
63276347
}
63286348
}
63296349

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

63526372
OperatorDecl *res;
63536373
if (Attributes.hasAttribute<PrefixAttr>())
6354-
res = new (Context) PrefixOperatorDecl(CurDeclContext, OperatorLoc,
6355-
Name, NameLoc);
6374+
res = new (Context)
6375+
PrefixOperatorDecl(CurDeclContext, OperatorLoc, Name, NameLoc,
6376+
firstIdentifierName, firstIdentifierNameLoc);
63566377
else if (Attributes.hasAttribute<PostfixAttr>())
6357-
res = new (Context) PostfixOperatorDecl(CurDeclContext, OperatorLoc,
6358-
Name, NameLoc);
6378+
res = new (Context)
6379+
PostfixOperatorDecl(CurDeclContext, OperatorLoc, Name, NameLoc,
6380+
firstIdentifierName, firstIdentifierNameLoc);
63596381
else
6360-
res = new (Context) InfixOperatorDecl(CurDeclContext, OperatorLoc,
6361-
Name, NameLoc, colonLoc,
6362-
precedenceGroupName,
6363-
precedenceGroupNameLoc);
6364-
6382+
res = new (Context)
6383+
InfixOperatorDecl(CurDeclContext, OperatorLoc, Name, NameLoc, colonLoc,
6384+
firstIdentifierName, firstIdentifierNameLoc,
6385+
secondIdentifierName, secondIdentifierNameLoc);
6386+
63656387
diagnoseOperatorFixityAttributes(*this, Attributes, res);
63666388

63676389
res->getAttrs() = Attributes;

0 commit comments

Comments
 (0)