mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
SE-0022: Implement parsing, AST, and semantic analysis for #selector.
This commit is contained in:
@@ -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
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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", ())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -51,6 +51,7 @@ IDENTIFIER_(OptionalNilComparisonType)
|
||||
IDENTIFIER(Protocol)
|
||||
IDENTIFIER(rawValue)
|
||||
IDENTIFIER(RawValue)
|
||||
IDENTIFIER(Selector)
|
||||
IDENTIFIER(self)
|
||||
IDENTIFIER(Self)
|
||||
IDENTIFIER(setObject)
|
||||
|
||||
@@ -1097,6 +1097,7 @@ public:
|
||||
bool isExprBasic);
|
||||
ParserResult<Expr> parseExprPostfix(Diag<> ID, bool isExprBasic);
|
||||
ParserResult<Expr> parseExprUnary(Diag<> ID, bool isExprBasic);
|
||||
ParserResult<Expr> parseExprSelector();
|
||||
ParserResult<Expr> parseExprSuper();
|
||||
ParserResult<Expr> parseExprConfiguration();
|
||||
Expr *parseExprStringLiteral();
|
||||
|
||||
@@ -44,6 +44,7 @@ enum class tok {
|
||||
pound_endif,
|
||||
pound_line,
|
||||
pound_available,
|
||||
pound_selector,
|
||||
comment,
|
||||
|
||||
#define KEYWORD(X) kw_ ## X,
|
||||
|
||||
@@ -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 << "<unresolved>";
|
||||
OS << '\n';
|
||||
printRec(E->getSubExpr());
|
||||
OS << ')';
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace.
|
||||
|
||||
@@ -803,6 +803,14 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
|
||||
return E;
|
||||
}
|
||||
|
||||
Expr *visitObjCSelectorExpr(ObjCSelectorExpr *E) {
|
||||
Expr *sub = doIt(E->getSubExpr());
|
||||
if (!sub) return nullptr;
|
||||
|
||||
E->setSubExpr(sub);
|
||||
return E;
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Everything Else
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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--;
|
||||
|
||||
@@ -434,6 +434,7 @@ ParserResult<Expr> Parser::parseExprSequenceElement(Diag<> message,
|
||||
/// expr-postfix(Mode)
|
||||
/// operator-prefix expr-unary(Mode)
|
||||
/// '&' expr-unary(Mode)
|
||||
/// expr-selector
|
||||
///
|
||||
ParserResult<Expr> Parser::parseExprUnary(Diag<> Message, bool isExprBasic) {
|
||||
UnresolvedDeclRefExpr *Operator;
|
||||
@@ -454,6 +455,9 @@ ParserResult<Expr> 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<Expr> Parser::parseExprUnary(Diag<> Message, bool isExprBasic) {
|
||||
new (Context) PrefixUnaryExpr(Operator, SubExpr.get()));
|
||||
}
|
||||
|
||||
/// parseExprSelector
|
||||
///
|
||||
/// expr-selector:
|
||||
/// '#selector' '(' expr ')'
|
||||
///
|
||||
ParserResult<Expr> 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<Expr> 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<Expr>(
|
||||
new (Context) ErrorExpr(SourceRange(keywordLoc, rParenLoc)));
|
||||
|
||||
return makeParserResult<Expr>(
|
||||
new (Context) ObjCSelectorExpr(keywordLoc, lParenLoc, subExpr.get(),
|
||||
rParenLoc));
|
||||
}
|
||||
|
||||
static DeclRefKind getDeclRefKindForOperator(tok kind) {
|
||||
switch (kind) {
|
||||
case tok::oper_binary_spaced:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<DeclRefExpr>(subExpr)) {
|
||||
foundDecl = declRef->getDecl();
|
||||
break;
|
||||
}
|
||||
|
||||
// Constructor reference.
|
||||
if (auto ctorRef = dyn_cast<OtherConstructorDeclRefExpr>(subExpr)) {
|
||||
foundDecl = ctorRef->getDecl();
|
||||
break;
|
||||
}
|
||||
|
||||
// Member reference.
|
||||
if (auto memberRef = dyn_cast<MemberRefExpr>(subExpr)) {
|
||||
foundDecl = memberRef->getMember().getDecl();
|
||||
break;
|
||||
}
|
||||
|
||||
// Dynamic member reference.
|
||||
if (auto dynMemberRef = dyn_cast<DynamicMemberRefExpr>(subExpr)) {
|
||||
foundDecl = dynMemberRef->getMember().getDecl();
|
||||
break;
|
||||
}
|
||||
|
||||
// Look through parentheses.
|
||||
if (auto paren = dyn_cast<ParenExpr>(subExpr)) {
|
||||
subExpr = paren->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look through "a.b" to "b".
|
||||
if (auto dotSyntax = dyn_cast<DotSyntaxBaseIgnoredExpr>(subExpr)) {
|
||||
subExpr = dotSyntax->getRHS();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look through self-rebind expression.
|
||||
if (auto rebindSelf = dyn_cast<RebindSelfInConstructorExpr>(subExpr)) {
|
||||
subExpr = rebindSelf->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look through optional binding within the monadic "?".
|
||||
if (auto bind = dyn_cast<BindOptionalExpr>(subExpr)) {
|
||||
subExpr = bind->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look through optional evaluation of the monadic "?".
|
||||
if (auto optEval = dyn_cast<OptionalEvaluationExpr>(subExpr)) {
|
||||
subExpr = optEval->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look through an implicit force-value.
|
||||
if (auto force = dyn_cast<ForceValueExpr>(subExpr)) {
|
||||
if (force->isImplicit()) {
|
||||
subExpr = force->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Look through implicit open-existential operations.
|
||||
if (auto open = dyn_cast<OpenExistentialExpr>(subExpr)) {
|
||||
if (open->isImplicit()) {
|
||||
subExpr = open->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Look to the referenced member in a self-application.
|
||||
if (auto selfApply = dyn_cast<SelfApplyExpr>(subExpr)) {
|
||||
subExpr = selfApply->getFn();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look through implicit conversions.
|
||||
if (auto conversion = dyn_cast<ImplicitConversionExpr>(subExpr)) {
|
||||
subExpr = conversion->getSubExpr();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Look through explicit coercions.
|
||||
if (auto coercion = dyn_cast<CoerceExpr>(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<AbstractFunctionDecl>(foundDecl);
|
||||
if (!func) {
|
||||
tc.diagnose(E->getLoc(),
|
||||
isa<VarDecl>(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<ConstructorDecl>(func))
|
||||
.highlight(subExpr->getSourceRange());
|
||||
if (foundDecl->getLoc().isValid()) {
|
||||
tc.diagnose(foundDecl,
|
||||
diag::expr_selector_make_objc,
|
||||
isa<ConstructorDecl>(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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -515,6 +515,7 @@ private:
|
||||
Type UInt8Type;
|
||||
Type NSObjectType;
|
||||
Type NSErrorType;
|
||||
Type ObjCSelectorType;
|
||||
Type ExceptionType;
|
||||
|
||||
/// The \c Swift.UnsafeMutablePointer<T> 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
|
||||
|
||||
83
test/expr/unary/selector/selector.swift
Normal file
83
test/expr/unary/selector/selector.swift
Normal file
@@ -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}}
|
||||
}
|
||||
Reference in New Issue
Block a user