diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index acb28d357c283..db5c561ae650c 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -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 @@ -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) @@ -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; @@ -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() }; @@ -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() }; } diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index 556fe66810be4..781de009601e0 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -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 @@ -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", ()) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 8e1ce4877436e..2864d3362be35 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -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)) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 5fc305536af0a..2ec3dec14d48b 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -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; diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index fa834f1891cbe..eb5d8162a93d9 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -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">; diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index c01dfbccae459..8599f292d0fdc 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -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 @@ -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 << " "; + if (!IOD->getFirstIdentifier().empty()) + OS << "first identifier " << IOD->getFirstIdentifier(); + else + OS << "first identifier "; + if (!IOD->getSecondIdentifier().empty()) + OS << "second identifier " << IOD->getSecondIdentifier(); + else + OS << "second identifier "; PrintWithColorRAII(OS, ParenthesisColor) << ')'; } diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 032578f337c2a..623acd99e5660 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -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) { @@ -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) { @@ -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) { } diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index b432cda2af5e2..1da3f818ef2ed 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -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 diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index e26695cacc86f..988522080dc2c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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 @@ -6309,21 +6309,41 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name, bool isPrefix = Attributes.hasAttribute(); bool isInfix = Attributes.hasAttribute(); bool isPostfix = Attributes.hasAttribute(); - - // 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}); + } } } @@ -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, @@ -6351,17 +6371,19 @@ Parser::parseDeclOperatorImpl(SourceLoc OperatorLoc, Identifier Name, OperatorDecl *res; if (Attributes.hasAttribute()) - res = new (Context) PrefixOperatorDecl(CurDeclContext, OperatorLoc, - Name, NameLoc); + res = new (Context) + PrefixOperatorDecl(CurDeclContext, OperatorLoc, Name, NameLoc, + firstIdentifierName, firstIdentifierNameLoc); else if (Attributes.hasAttribute()) - 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; diff --git a/lib/Sema/TypeCheckDecl.cpp b/lib/Sema/TypeCheckDecl.cpp index 88a182b7c9f6a..3d626ed0751c9 100644 --- a/lib/Sema/TypeCheckDecl.cpp +++ b/lib/Sema/TypeCheckDecl.cpp @@ -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 @@ -2063,6 +2063,33 @@ PrecedenceGroupDecl *TypeChecker::lookupPrecedenceGroup(DeclContext *dc, return group; } +static void checkDesignatedProtocol(OperatorDecl *OD, Identifier name, + SourceLoc loc, TypeChecker &tc, + ASTContext &ctx) { + auto *dc = OD->getDeclContext(); + auto *TyR = new (ctx) SimpleIdentTypeRepr(loc, name); + TypeLoc typeLoc = TypeLoc(TyR); + + TypeResolutionOptions options = TypeResolverContext::TypeAliasDecl; + if (tc.validateType(typeLoc, TypeResolution::forContextual(dc), options)) { + typeLoc.setInvalidType(ctx); + } + + if (!typeLoc.isError()) { + OD->setDesignatedProtocolTypeLoc(typeLoc); + auto *decl = typeLoc.getType()->getNominalOrBoundGenericNominal(); + if (!decl || !isa(decl)) { + tc.diagnose(typeLoc.getLoc(), + diag::operators_designated_protocol_not_a_protocol, + typeLoc.getType()); + OD->setInvalid(); + } else { + // FIXME: verify this operator has a declaration within this + // protocol with the same arity and fixity + } + } +} + /// Validate the given operator declaration. /// /// This establishes key invariants, such as an InfixOperatorDecl's @@ -2072,39 +2099,66 @@ void TypeChecker::validateDecl(OperatorDecl *OD) { checkDeclAttributesEarly(OD); checkDeclAttributes(OD); - if (auto IOD = dyn_cast(OD)) { - if (!IOD->getPrecedenceGroup()) { - PrecedenceGroupDecl *group = nullptr; - - // If a name was given, try to look it up. - Identifier name = IOD->getPrecedenceGroupName(); - if (!name.empty()) { - auto loc = IOD->getPrecedenceGroupNameLoc(); - group = lookupPrecedenceGroupPrimitive(OD->getDeclContext(), name, loc); - if (!group && !IOD->isInvalid()) { - diagnose(loc, diag::unknown_precedence_group, name); - IOD->setInvalid(); - } - } + auto IOD = dyn_cast(OD); - // If that fails, or if a name was not given, use the default - // precedence group. - if (!group) { - group = lookupPrecedenceGroupPrimitive(OD->getDeclContext(), - Context.Id_DefaultPrecedence, - SourceLoc()); - if (!group && name.empty() && !IOD->isInvalid()) { - diagnose(OD->getLoc(), diag::missing_builtin_precedence_group, - Context.Id_DefaultPrecedence); - } + auto enableOperatorDesignatedProtocols = + getLangOpts().EnableOperatorDesignatedProtocols; + + // Pre- or post-fix operator? + if (!IOD) { + auto typeLoc = OD->getDesignatedProtocolTypeLoc(); + auto protocolId = OD->getDesignatedProtocolName(); + if (typeLoc.isNull() && !protocolId.empty() && + enableOperatorDesignatedProtocols) { + auto protocolIdLoc = OD->getDesignatedProtocolNameLoc(); + checkDesignatedProtocol(OD, protocolId, protocolIdLoc, *this, Context); + } + return; + } + + if (!IOD->getPrecedenceGroup()) { + PrecedenceGroupDecl *group = nullptr; + + auto firstId = IOD->getFirstIdentifier(); + auto firstIdLoc = IOD->getFirstIdentifierLoc(); + + // If a name was given, try to look it up. + if (!firstId.empty()) { + group = lookupPrecedenceGroupPrimitive(IOD->getDeclContext(), firstId, + firstIdLoc); + } + + auto secondId = IOD->getSecondIdentifier(); + auto typeLoc = IOD->getDesignatedProtocolTypeLoc(); + if (typeLoc.isNull() && enableOperatorDesignatedProtocols) { + auto secondIdLoc = IOD->getSecondIdentifierLoc(); + assert(secondId.empty() || !firstId.empty()); + + auto protocolId = group ? secondId : firstId; + auto protocolIdLoc = group ? secondIdLoc : firstIdLoc; + if (!protocolId.empty()) + checkDesignatedProtocol(IOD, protocolId, protocolIdLoc, *this, Context); + } + + if (!group && !IOD->isInvalid()) { + if (!firstId.empty() && + (!secondId.empty() || IOD->getDesignatedProtocolTypeLoc().isNull())) { + diagnose(firstIdLoc, diag::unknown_precedence_group, firstId); + IOD->setInvalid(); } - // Validate the precedence group. - if (group) { - validateDecl(group); - IOD->setPrecedenceGroup(group); + group = lookupPrecedenceGroupPrimitive( + IOD->getDeclContext(), Context.Id_DefaultPrecedence, SourceLoc()); + if (!group && firstId.empty() && !IOD->isInvalid()) { + diagnose(IOD->getLoc(), diag::missing_builtin_precedence_group, + Context.Id_DefaultPrecedence); } } + + if (group) { + validateDecl(group); + IOD->setPrecedenceGroup(group); + } } } diff --git a/test/Parse/operator_decl.swift b/test/Parse/operator_decl.swift index d7dbd952377a0..c3be1e5fb4576 100644 --- a/test/Parse/operator_decl.swift +++ b/test/Parse/operator_decl.swift @@ -85,3 +85,11 @@ precedencegroup CaretCaretCaret { class Foo { infix operator ||| // expected-error{{'operator' may only be declared at file scope}} } + +infix operator **<< : UndeclaredPrecedenceGroup +// expected-error@-1 {{unknown precedence group 'UndeclaredPrecedenceGroup'}} + +protocol Proto {} +infix operator *<*< : F, Proto +// expected-error@-1 {{consecutive statements on a line must be separated by ';'}} +// expected-error@-2 {{expected expression}} diff --git a/test/Parse/operator_decl_designated_protocols.swift b/test/Parse/operator_decl_designated_protocols.swift new file mode 100644 index 0000000000000..c449c047c39c4 --- /dev/null +++ b/test/Parse/operator_decl_designated_protocols.swift @@ -0,0 +1,69 @@ +// RUN: %target-typecheck-verify-swift -enable-operator-designated-protocols + +precedencegroup LowPrecedence { + associativity: right +} + +precedencegroup MediumPrecedence { + associativity: left + higherThan: LowPrecedence +} + +protocol PrefixMagicOperatorProtocol { +} + +protocol PostfixMagicOperatorProtocol { +} + +protocol InfixMagicOperatorProtocol { +} + +prefix operator ^^ : PrefixMagicOperatorProtocol +infix operator <*< : MediumPrecedence, InfixMagicOperatorProtocol +postfix operator ^^ : PostfixMagicOperatorProtocol + +infix operator ^*^ +prefix operator *^^ +postfix operator ^^* + +infix operator **>> : UndeclaredPrecedence +// expected-error@-1 {{unknown precedence group 'UndeclaredPrecedence'}} +// expected-error@-2 {{use of undeclared type 'UndeclaredPrecedence'}} + +infix operator **+> : MediumPrecedence, UndeclaredProtocol +// expected-error@-1 {{use of undeclared type 'UndeclaredProtocol'}} + +prefix operator *+*> : MediumPrecedence +// expected-error@-1 {{use of undeclared type 'MediumPrecedence'}} + +postfix operator ++*> : MediumPrecedence +// expected-error@-1 {{use of undeclared type 'MediumPrecedence'}} + +prefix operator *++> : UndeclaredProtocol +// expected-error@-1 {{use of undeclared type 'UndeclaredProtocol'}} +postfix operator +*+> : UndeclaredProtocol +// expected-error@-1 {{use of undeclared type 'UndeclaredProtocol'}} + +struct Struct {} +class Class {} +infix operator *>*> : Struct +// expected-error@-1 {{type 'Struct' unexpected; expected a protocol type}} + +infix operator >**> : Class +// expected-error@-1 {{type 'Class' unexpected; expected a protocol type}} + +prefix operator **>> : Struct +// expected-error@-1 {{type 'Struct' unexpected; expected a protocol type}} +prefix operator *>*> : Class +// expected-error@-1 {{type 'Class' unexpected; expected a protocol type}} + +postfix operator >*>* : Struct +// expected-error@-1 {{type 'Struct' unexpected; expected a protocol type}} +postfix operator >>** : Class +// expected-error@-1 {{type 'Class' unexpected; expected a protocol type}} + +infix operator <*<<< : MediumPrecedence, & +// expected-error@-1 {{expected designated protocol in operator declaration}} + +infix operator **^^ : MediumPrecedence // expected-note {{previous operator declaration here}} +infix operator **^^ : InfixMagicOperatorProtocol // expected-error {{operator redeclared}}