diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index f2dd79b1c33..133557e90db 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1016,6 +1016,14 @@ ERROR(expected_type_after_as,none, ERROR(string_interpolation_extra,none, "extra tokens after interpolated string expression", ()) +// Selector expressions. +ERROR(expr_selector_expected_lparen,PointsToFirstBadToken, + "expected '(' following '#selector'", ()) +ERROR(expr_selector_expected_expr,PointsToFirstBadToken, + "expected expression naming a method within '#selector(...)'", ()) +ERROR(expr_selector_expected_rparen,PointsToFirstBadToken, + "expected ')' to complete '#selector' expression", ()) + //------------------------------------------------------------------------------ // Attribute-parsing diagnostics //------------------------------------------------------------------------------ diff --git a/include/swift/AST/DiagnosticsSIL.def b/include/swift/AST/DiagnosticsSIL.def index 598ce732acf..318747c6884 100644 --- a/include/swift/AST/DiagnosticsSIL.def +++ b/include/swift/AST/DiagnosticsSIL.def @@ -88,6 +88,10 @@ ERROR(unsupported_c_function_pointer_conversion,none, "C function pointer signature %0 is not compatible with expected type %1", (Type, Type)) +ERROR(unsupported_objc_selector,none, + "code generation for #selector is unsupported", + ()) + // Definite initialization diagnostics. NOTE(variable_defined_here,none, "%select{variable|constant}0 defined here", (bool)) diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 51a59eac897..ad60d6dfd01 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -353,7 +353,24 @@ ERROR(noescape_functiontype_mismatch,none, "potentially escaping function type %1", (Type, Type)) - +// Selector expressions. +ERROR(expr_selector_no_objc_runtime,none, + "'#selector' can only be used with the Objective-C runtime", ()) +ERROR(expr_selector_module_missing,none, + "import the 'ObjectiveC' module to use '#selector'", ()) +ERROR(expr_selector_no_declaration,none, + "argument of '#selector' does not refer to an initializer or method", ()) +ERROR(expr_selector_property,none, + "argument of '#selector' cannot refer to a property", ()) +ERROR(expr_selector_not_method_or_init,none, + "argument of '#selector' does not refer to a method or initializer", ()) +ERROR(expr_selector_not_objc,none, + "argument of '#selector' refers to %select{a method|an initializer}0 " + "that is not exposed to Objective-C", + (bool)) +NOTE(expr_selector_make_objc,none, + "add '@objc' to expose this %select{method|initializer}0 to Objective-C", + (bool)) ERROR(cannot_return_value_from_void_func,none, "unexpected non-void return value in void function", ()) diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index c9a29dfc9c9..bd93bf77dab 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -3695,6 +3695,44 @@ public: void setSemanticExpr(Expr *SE) { SemanticExpr = SE; } }; +/// Produces the Objective-C selector of the referenced method. +/// +/// \code +/// #selector(UIView.insertSubview(_:aboveSubview:)) +/// \endcode +class ObjCSelectorExpr : public Expr { + SourceLoc KeywordLoc; + SourceLoc LParenLoc; + Expr *SubExpr; + SourceLoc RParenLoc; + AbstractFunctionDecl *Method = nullptr; + +public: + ObjCSelectorExpr(SourceLoc keywordLoc, SourceLoc lParenLoc, + Expr *subExpr, SourceLoc rParenLoc) + : Expr(ExprKind::ObjCSelector, /*Implicit=*/false), + KeywordLoc(keywordLoc), LParenLoc(lParenLoc), SubExpr(subExpr), + RParenLoc(rParenLoc) { } + + Expr *getSubExpr() const { return SubExpr; } + void setSubExpr(Expr *expr) { SubExpr = expr; } + + /// Retrieve the Objective-C method to which this expression refers. + AbstractFunctionDecl *getMethod() const { return Method; } + + /// Set the Objective-C method to which this expression refers. + void setMethod(AbstractFunctionDecl *method) { Method = method; } + + SourceLoc getLoc() const { return KeywordLoc; } + SourceRange getSourceRange() const { + return SourceRange(KeywordLoc, RParenLoc); + } + + static bool classof(const Expr *E) { + return E->getKind() == ExprKind::ObjCSelector; + } +}; + #undef SWIFT_FORWARD_SOURCE_LOCS_TO } // end namespace swift diff --git a/include/swift/AST/ExprNodes.def b/include/swift/AST/ExprNodes.def index f3789302dbe..66387b96400 100644 --- a/include/swift/AST/ExprNodes.def +++ b/include/swift/AST/ExprNodes.def @@ -155,6 +155,7 @@ EXPR(DefaultValue, Expr) EXPR(CodeCompletion, Expr) UNCHECKED_EXPR(UnresolvedPattern, Expr) EXPR(EditorPlaceholder, Expr) +EXPR(ObjCSelector, Expr) #undef EXPR_RANGE #undef UNCHECKED_EXPR diff --git a/include/swift/AST/KnownIdentifiers.def b/include/swift/AST/KnownIdentifiers.def index 98613f97a1a..419c3582016 100644 --- a/include/swift/AST/KnownIdentifiers.def +++ b/include/swift/AST/KnownIdentifiers.def @@ -51,6 +51,7 @@ IDENTIFIER_(OptionalNilComparisonType) IDENTIFIER(Protocol) IDENTIFIER(rawValue) IDENTIFIER(RawValue) +IDENTIFIER(Selector) IDENTIFIER(self) IDENTIFIER(Self) IDENTIFIER(setObject) diff --git a/include/swift/Parse/Parser.h b/include/swift/Parse/Parser.h index 1b6a5a7da03..bc0e4176c3e 100644 --- a/include/swift/Parse/Parser.h +++ b/include/swift/Parse/Parser.h @@ -1097,6 +1097,7 @@ public: bool isExprBasic); ParserResult parseExprPostfix(Diag<> ID, bool isExprBasic); ParserResult parseExprUnary(Diag<> ID, bool isExprBasic); + ParserResult parseExprSelector(); ParserResult parseExprSuper(); ParserResult parseExprConfiguration(); Expr *parseExprStringLiteral(); diff --git a/include/swift/Parse/Token.h b/include/swift/Parse/Token.h index 8c7a6630b84..833b7f7aaf2 100644 --- a/include/swift/Parse/Token.h +++ b/include/swift/Parse/Token.h @@ -44,6 +44,7 @@ enum class tok { pound_endif, pound_line, pound_available, + pound_selector, comment, #define KEYWORD(X) kw_ ## X, diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 1a87a7155e4..ef7292eec67 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -2170,6 +2170,16 @@ public: } OS << ')'; } + void visitObjCSelectorExpr(ObjCSelectorExpr *E) { + printCommon(E, "objc_selector_expr") << " decl="; + if (auto method = E->getMethod()) + method->dumpRef(OS); + else + OS << ""; + OS << '\n'; + printRec(E->getSubExpr()); + OS << ')'; + } }; } // end anonymous namespace. diff --git a/lib/AST/ASTWalker.cpp b/lib/AST/ASTWalker.cpp index 722a89d92d9..9784445f290 100644 --- a/lib/AST/ASTWalker.cpp +++ b/lib/AST/ASTWalker.cpp @@ -803,6 +803,14 @@ class Traversal : public ASTVisitorgetSubExpr()); + if (!sub) return nullptr; + + E->setSubExpr(sub); + return E; + } + //===--------------------------------------------------------------------===// // Everything Else //===--------------------------------------------------------------------===// diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 937ee47784c..1e5b2f23b8c 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -314,6 +314,7 @@ void Expr::propagateLValueAccessKind(AccessKind accessKind, NON_LVALUE_EXPR(Assign) NON_LVALUE_EXPR(DefaultValue) NON_LVALUE_EXPR(CodeCompletion) + NON_LVALUE_EXPR(ObjCSelector) #define UNCHECKED_EXPR(KIND, BASE) \ NON_LVALUE_EXPR(KIND) @@ -487,6 +488,7 @@ bool Expr::canAppendCallParentheses() const { case ExprKind::StringLiteral: case ExprKind::InterpolatedStringLiteral: case ExprKind::MagicIdentifierLiteral: + case ExprKind::ObjCSelector: return true; case ExprKind::ObjectLiteral: diff --git a/lib/IDE/SyntaxModel.cpp b/lib/IDE/SyntaxModel.cpp index 73f75e426d3..70ab7e7bff6 100644 --- a/lib/IDE/SyntaxModel.cpp +++ b/lib/IDE/SyntaxModel.cpp @@ -98,6 +98,7 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile) #define KEYWORD(X) case tok::kw_##X: Kind = SyntaxNodeKind::Keyword; break; #include "swift/Parse/Tokens.def" #undef KEYWORD + case tok::pound_selector: Kind = SyntaxNodeKind::Keyword; break; case tok::pound_line: case tok::pound_available: Kind = SyntaxNodeKind::BuildConfigKeyword; break; diff --git a/lib/Parse/Lexer.cpp b/lib/Parse/Lexer.cpp index 94f883290b0..385f38f913b 100644 --- a/lib/Parse/Lexer.cpp +++ b/lib/Parse/Lexer.cpp @@ -1619,6 +1619,11 @@ Restart: return formToken(tok::pound_available, TokStart); } + if (getSubstring(TokStart + 1, 8).equals("selector")) { + CurPtr += 8; + return formToken(tok::pound_selector, TokStart); + } + // Allow a hashbang #! line at the beginning of the file. if (CurPtr - 1 == BufferStart && *CurPtr == '!') { CurPtr--; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index a5090287b85..ee5174c1258 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -434,6 +434,7 @@ ParserResult Parser::parseExprSequenceElement(Diag<> message, /// expr-postfix(Mode) /// operator-prefix expr-unary(Mode) /// '&' expr-unary(Mode) +/// expr-selector /// ParserResult Parser::parseExprUnary(Diag<> Message, bool isExprBasic) { UnresolvedDeclRefExpr *Operator; @@ -454,6 +455,9 @@ ParserResult Parser::parseExprUnary(Diag<> Message, bool isExprBasic) { new (Context) InOutExpr(Loc, SubExpr.get(), Type())); } + case tok::pound_selector: + return parseExprSelector(); + case tok::oper_postfix: // Postfix operators cannot start a subexpression, but can happen // syntactically because the operator may just follow whatever precedes this @@ -499,6 +503,50 @@ ParserResult Parser::parseExprUnary(Diag<> Message, bool isExprBasic) { new (Context) PrefixUnaryExpr(Operator, SubExpr.get())); } +/// parseExprSelector +/// +/// expr-selector: +/// '#selector' '(' expr ')' +/// +ParserResult Parser::parseExprSelector() { + // Consume '#selector'. + SourceLoc keywordLoc = consumeToken(tok::pound_selector); + + // Parse the leading '('. + if (!Tok.is(tok::l_paren)) { + diagnose(Tok, diag::expr_selector_expected_lparen); + return makeParserError(); + } + SourceLoc lParenLoc = consumeToken(tok::l_paren); + + // Parse the subexpression. + ParserResult subExpr = parseExpr(diag::expr_selector_expected_expr); + if (subExpr.hasCodeCompletion()) + return subExpr; + + // Parse the closing ')' + SourceLoc rParenLoc; + if (subExpr.isParseError()) { + skipUntilDeclStmtRBrace(tok::r_paren); + if (Tok.is(tok::r_paren)) + rParenLoc = consumeToken(); + else + rParenLoc = Tok.getLoc(); + } else { + parseMatchingToken(tok::r_paren, rParenLoc, + diag::expr_selector_expected_rparen, lParenLoc); + } + + // If the subexpression was in error, just propagate the error. + if (subExpr.isParseError()) + return makeParserResult( + new (Context) ErrorExpr(SourceRange(keywordLoc, rParenLoc))); + + return makeParserResult( + new (Context) ObjCSelectorExpr(keywordLoc, lParenLoc, subExpr.get(), + rParenLoc)); +} + static DeclRefKind getDeclRefKindForOperator(tok kind) { switch (kind) { case tok::oper_binary_spaced: diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 8b1cc92e0c6..b4e6108a9f9 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -197,6 +197,7 @@ namespace { SGFContext C); RValue visitObjectLiteralExpr(ObjectLiteralExpr *E, SGFContext C); RValue visitEditorPlaceholderExpr(EditorPlaceholderExpr *E, SGFContext C); + RValue visitObjCSelectorExpr(ObjCSelectorExpr *E, SGFContext C); RValue visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E, SGFContext C); RValue visitCollectionExpr(CollectionExpr *E, SGFContext C); @@ -1942,6 +1943,13 @@ visitEditorPlaceholderExpr(EditorPlaceholderExpr *E, SGFContext C) { return visit(E->getSemanticExpr(), C); } +RValue RValueEmitter::visitObjCSelectorExpr(ObjCSelectorExpr *e, SGFContext C) { + SILType loweredSelectorTy = SGF.getLoweredType(e->getType()); + + SGF.SGM.diagnose(e, diag::unsupported_objc_selector); + return RValue(SGF, e, SGF.emitUndef(e, loweredSelectorTy)); +} + static StringRef getMagicFunctionString(SILGenFunction &gen) { assert(gen.MagicFunctionName diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 5d1698aff9c..c918ceec567 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -3242,6 +3242,151 @@ namespace { return E; } + Expr *visitObjCSelectorExpr(ObjCSelectorExpr *E) { + // Dig out the reference to a declaration. + Expr *subExpr = E->getSubExpr(); + ValueDecl *foundDecl = nullptr; + while (subExpr) { + // Declaration reference. + if (auto declRef = dyn_cast(subExpr)) { + foundDecl = declRef->getDecl(); + break; + } + + // Constructor reference. + if (auto ctorRef = dyn_cast(subExpr)) { + foundDecl = ctorRef->getDecl(); + break; + } + + // Member reference. + if (auto memberRef = dyn_cast(subExpr)) { + foundDecl = memberRef->getMember().getDecl(); + break; + } + + // Dynamic member reference. + if (auto dynMemberRef = dyn_cast(subExpr)) { + foundDecl = dynMemberRef->getMember().getDecl(); + break; + } + + // Look through parentheses. + if (auto paren = dyn_cast(subExpr)) { + subExpr = paren->getSubExpr(); + continue; + } + + // Look through "a.b" to "b". + if (auto dotSyntax = dyn_cast(subExpr)) { + subExpr = dotSyntax->getRHS(); + continue; + } + + // Look through self-rebind expression. + if (auto rebindSelf = dyn_cast(subExpr)) { + subExpr = rebindSelf->getSubExpr(); + continue; + } + + // Look through optional binding within the monadic "?". + if (auto bind = dyn_cast(subExpr)) { + subExpr = bind->getSubExpr(); + continue; + } + + // Look through optional evaluation of the monadic "?". + if (auto optEval = dyn_cast(subExpr)) { + subExpr = optEval->getSubExpr(); + continue; + } + + // Look through an implicit force-value. + if (auto force = dyn_cast(subExpr)) { + if (force->isImplicit()) { + subExpr = force->getSubExpr(); + continue; + } + + break; + } + + // Look through implicit open-existential operations. + if (auto open = dyn_cast(subExpr)) { + if (open->isImplicit()) { + subExpr = open->getSubExpr(); + continue; + } + break; + } + + // Look to the referenced member in a self-application. + if (auto selfApply = dyn_cast(subExpr)) { + subExpr = selfApply->getFn(); + continue; + } + + // Look through implicit conversions. + if (auto conversion = dyn_cast(subExpr)) { + subExpr = conversion->getSubExpr(); + continue; + } + + // Look through explicit coercions. + if (auto coercion = dyn_cast(subExpr)) { + subExpr = coercion->getSubExpr(); + continue; + } + + break; + } + + if (!subExpr) return nullptr; + + // If we didn't find any declaration at all, we're stuck. + auto &tc = cs.getTypeChecker(); + if (!foundDecl) { + tc.diagnose(E->getLoc(), diag::expr_selector_no_declaration) + .highlight(subExpr->getSourceRange()); + return E; + } + + // If the declaration we found was not a method or initializer, + // complain. + auto func = dyn_cast(foundDecl); + if (!func) { + tc.diagnose(E->getLoc(), + isa(foundDecl) + ? diag::expr_selector_property + : diag::expr_selector_not_method_or_init) + .highlight(subExpr->getSourceRange()); + tc.diagnose(foundDecl, diag::decl_declared_here, + foundDecl->getFullName()); + return E; + } + + // The declaration we found must be exposed to Objective-C. + if (!func->isObjC()) { + tc.diagnose(E->getLoc(), diag::expr_selector_not_objc, + isa(func)) + .highlight(subExpr->getSourceRange()); + if (foundDecl->getLoc().isValid()) { + tc.diagnose(foundDecl, + diag::expr_selector_make_objc, + isa(func)) + .fixItInsert(foundDecl->getAttributeInsertionLoc(false), + "@objc "); + } else { + tc.diagnose(foundDecl, diag::decl_declared_here, + foundDecl->getFullName()); + } + return E; + } + + E->setMethod(func); + return E; + } + /// Interface for ExprWalker void walkToExprPre(Expr *expr) { ExprStack.push_back(expr); diff --git a/lib/Sema/CSGen.cpp b/lib/Sema/CSGen.cpp index 2cd65b5b102..daa22432f8e 100644 --- a/lib/Sema/CSGen.cpp +++ b/lib/Sema/CSGen.cpp @@ -2738,6 +2738,26 @@ namespace { // case we return the null type. return E->getType(); } + + Type visitObjCSelectorExpr(ObjCSelectorExpr *E) { + // #selector only makes sense when we have the Objective-C + // #runtime. + auto &tc = CS.getTypeChecker(); + if (!tc.Context.LangOpts.EnableObjCInterop) { + tc.diagnose(E->getLoc(), diag::expr_selector_no_objc_runtime); + return nullptr; + } + + // Make sure we can reference ObjectiveC.Selector. + // FIXME: Fix-It to add the import? + auto type = CS.getTypeChecker().getObjCSelectorType(CS.DC); + if (!type) { + tc.diagnose(E->getLoc(), diag::expr_selector_module_missing); + return nullptr; + } + + return type; + } }; /// \brief AST walker that "sanitizes" an expression for the diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 4d1ed09f642..3a542522e0c 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -111,11 +111,11 @@ Type TypeChecker::getExceptionType(DeclContext *dc, SourceLoc loc) { return Type(); } -static Type getObjectiveCClassType(TypeChecker &TC, - Type &cache, - Identifier ModuleName, - Identifier TypeName, - DeclContext *dc) { +static Type getObjectiveCNominalType(TypeChecker &TC, + Type &cache, + Identifier ModuleName, + Identifier TypeName, + DeclContext *dc) { if (cache) return cache; @@ -142,17 +142,24 @@ static Type getObjectiveCClassType(TypeChecker &TC, } Type TypeChecker::getNSObjectType(DeclContext *dc) { - return getObjectiveCClassType(*this, NSObjectType, Context.Id_ObjectiveC, + return getObjectiveCNominalType(*this, NSObjectType, Context.Id_ObjectiveC, Context.getSwiftId( KnownFoundationEntity::NSObject), dc); } Type TypeChecker::getNSErrorType(DeclContext *dc) { - return getObjectiveCClassType(*this, NSObjectType, Context.Id_Foundation, - Context.getSwiftId( - KnownFoundationEntity::NSError), - dc); + return getObjectiveCNominalType(*this, NSObjectType, Context.Id_Foundation, + Context.getSwiftId( + KnownFoundationEntity::NSError), + dc); +} + +Type TypeChecker::getObjCSelectorType(DeclContext *dc) { + return getObjectiveCNominalType(*this, ObjCSelectorType, + Context.Id_ObjectiveC, + Context.Id_Selector, + dc); } Type TypeChecker::getBridgedToObjC(const DeclContext *dc, Type type) { diff --git a/lib/Sema/TypeChecker.h b/lib/Sema/TypeChecker.h index c692487d0d0..1ff7f4f8030 100644 --- a/lib/Sema/TypeChecker.h +++ b/lib/Sema/TypeChecker.h @@ -515,6 +515,7 @@ private: Type UInt8Type; Type NSObjectType; Type NSErrorType; + Type ObjCSelectorType; Type ExceptionType; /// The \c Swift.UnsafeMutablePointer declaration. @@ -589,6 +590,7 @@ public: Type getUInt8Type(DeclContext *dc); Type getNSObjectType(DeclContext *dc); Type getNSErrorType(DeclContext *dc); + Type getObjCSelectorType(DeclContext *dc); Type getExceptionType(DeclContext *dc, SourceLoc loc); /// \brief Try to resolve an IdentTypeRepr, returning either the referenced diff --git a/test/expr/unary/selector/selector.swift b/test/expr/unary/selector/selector.swift new file mode 100644 index 00000000000..2c7f5c5f98c --- /dev/null +++ b/test/expr/unary/selector/selector.swift @@ -0,0 +1,83 @@ +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -disable-objc-attr-requires-foundation-module -parse %s -verify +import ObjectiveC + +// REQUIRES: objc_interop + +@objc class A { } +@objc class B { } + +class C1 { + @objc func method1(a: A, b: B) { } + @objc(someMethodWithA:B:) func method2(a: A, b: B) { } + + @objc class func method3(a: A, b: B) { } // expected-note{{found this candidate}} + @objc class func method3(a a: A, b: B) { } // expected-note{{found this candidate}} + + @objc var a: A = A() // expected-note{{'a' declared here}} +} + +@objc protocol P1 { + func method4(a: A, b: B) + static func method5(a: B, b: B) +} + +extension C1 { + final func method6() { } // expected-note{{add '@objc' to expose this method to Objective-C}}{{3-3=@objc }} +} + +func testSelector(c1: C1, p1: P1) { + // Instance methods on an instance + let sel1 = #selector(c1.method1) + _ = #selector(c1.method1(_:b:)) + _ = #selector(c1.method2) + + // Instance methods on a class. + _ = #selector(C1.method1) + _ = #selector(C1.method1(_:b:)) + _ = #selector(C1.method2) + + // Class methods on a class. + _ = #selector(C1.method3(_:b:)) + _ = #selector(C1.method3(a:b:)) + + // Methods on a protocol. + _ = #selector(P1.method4) + _ = #selector(P1.method4(_:b:)) + _ = #selector(P1.method5) // FIXME: expected-error{{static member 'method5' cannot be used on instance of type 'P1.Protocol'}} + _ = #selector(P1.method5(_:b:)) // FIXME: expected-error{{static member 'method5(_:b:)' cannot be used on instance of type 'P1.Protocol'}} + _ = #selector(p1.method4) + _ = #selector(p1.method4(_:b:)) + _ = #selector(p1.dynamicType.method5) + _ = #selector(p1.dynamicType.method5(_:b:)) + + // Make sure the result has type "ObjectiveC.Selector" + let sel2: Selector + sel2 = sel1 + _ = sel2 +} + +func testAmbiguity() { + _ = #selector(C1.method3) // expected-error{{ambiguous use of 'method3(_:b:)'}} +} + +func testProperties(c1: C1) { + _ = #selector(c1.a) // expected-error{{argument of '#selector' cannot refer to a property}} + _ = #selector(C1.a) // expected-error{{instance member 'a' cannot be used on type 'C1'}} +} + +func testNonObjC(c1: C1) { + _ = #selector(c1.method6) // expected-error{{argument of '#selector' refers to a method that is not exposed to Objective-C}} +} + +func testParseErrors1() { + #selector foo // expected-error{{expected '(' following '#selector'}} +} + +func testParseErrors2() { + #selector( // expected-error{{expected expression naming a method within '#selector(...)'}} +} + +func testParseErrors3(c1: C1) { + #selector( // expected-note{{to match this opening '('}} + c1.method1(_:b:) // expected-error{{expected ')' to complete '#selector' expression}} +}