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,
|
ERROR(string_interpolation_extra,none,
|
||||||
"extra tokens after interpolated string expression", ())
|
"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
|
// 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",
|
"C function pointer signature %0 is not compatible with expected type %1",
|
||||||
(Type, Type))
|
(Type, Type))
|
||||||
|
|
||||||
|
ERROR(unsupported_objc_selector,none,
|
||||||
|
"code generation for #selector is unsupported",
|
||||||
|
())
|
||||||
|
|
||||||
// Definite initialization diagnostics.
|
// Definite initialization diagnostics.
|
||||||
NOTE(variable_defined_here,none,
|
NOTE(variable_defined_here,none,
|
||||||
"%select{variable|constant}0 defined here", (bool))
|
"%select{variable|constant}0 defined here", (bool))
|
||||||
|
|||||||
@@ -353,7 +353,24 @@ ERROR(noescape_functiontype_mismatch,none,
|
|||||||
"potentially escaping function type %1", (Type, Type))
|
"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,
|
ERROR(cannot_return_value_from_void_func,none,
|
||||||
"unexpected non-void return value in void function", ())
|
"unexpected non-void return value in void function", ())
|
||||||
|
|||||||
@@ -3695,6 +3695,44 @@ public:
|
|||||||
void setSemanticExpr(Expr *SE) { SemanticExpr = SE; }
|
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
|
#undef SWIFT_FORWARD_SOURCE_LOCS_TO
|
||||||
|
|
||||||
} // end namespace swift
|
} // end namespace swift
|
||||||
|
|||||||
@@ -155,6 +155,7 @@ EXPR(DefaultValue, Expr)
|
|||||||
EXPR(CodeCompletion, Expr)
|
EXPR(CodeCompletion, Expr)
|
||||||
UNCHECKED_EXPR(UnresolvedPattern, Expr)
|
UNCHECKED_EXPR(UnresolvedPattern, Expr)
|
||||||
EXPR(EditorPlaceholder, Expr)
|
EXPR(EditorPlaceholder, Expr)
|
||||||
|
EXPR(ObjCSelector, Expr)
|
||||||
|
|
||||||
#undef EXPR_RANGE
|
#undef EXPR_RANGE
|
||||||
#undef UNCHECKED_EXPR
|
#undef UNCHECKED_EXPR
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ IDENTIFIER_(OptionalNilComparisonType)
|
|||||||
IDENTIFIER(Protocol)
|
IDENTIFIER(Protocol)
|
||||||
IDENTIFIER(rawValue)
|
IDENTIFIER(rawValue)
|
||||||
IDENTIFIER(RawValue)
|
IDENTIFIER(RawValue)
|
||||||
|
IDENTIFIER(Selector)
|
||||||
IDENTIFIER(self)
|
IDENTIFIER(self)
|
||||||
IDENTIFIER(Self)
|
IDENTIFIER(Self)
|
||||||
IDENTIFIER(setObject)
|
IDENTIFIER(setObject)
|
||||||
|
|||||||
@@ -1097,6 +1097,7 @@ public:
|
|||||||
bool isExprBasic);
|
bool isExprBasic);
|
||||||
ParserResult<Expr> parseExprPostfix(Diag<> ID, bool isExprBasic);
|
ParserResult<Expr> parseExprPostfix(Diag<> ID, bool isExprBasic);
|
||||||
ParserResult<Expr> parseExprUnary(Diag<> ID, bool isExprBasic);
|
ParserResult<Expr> parseExprUnary(Diag<> ID, bool isExprBasic);
|
||||||
|
ParserResult<Expr> parseExprSelector();
|
||||||
ParserResult<Expr> parseExprSuper();
|
ParserResult<Expr> parseExprSuper();
|
||||||
ParserResult<Expr> parseExprConfiguration();
|
ParserResult<Expr> parseExprConfiguration();
|
||||||
Expr *parseExprStringLiteral();
|
Expr *parseExprStringLiteral();
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ enum class tok {
|
|||||||
pound_endif,
|
pound_endif,
|
||||||
pound_line,
|
pound_line,
|
||||||
pound_available,
|
pound_available,
|
||||||
|
pound_selector,
|
||||||
comment,
|
comment,
|
||||||
|
|
||||||
#define KEYWORD(X) kw_ ## X,
|
#define KEYWORD(X) kw_ ## X,
|
||||||
|
|||||||
@@ -2170,6 +2170,16 @@ public:
|
|||||||
}
|
}
|
||||||
OS << ')';
|
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.
|
} // end anonymous namespace.
|
||||||
|
|||||||
@@ -803,6 +803,14 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
|
|||||||
return E;
|
return E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expr *visitObjCSelectorExpr(ObjCSelectorExpr *E) {
|
||||||
|
Expr *sub = doIt(E->getSubExpr());
|
||||||
|
if (!sub) return nullptr;
|
||||||
|
|
||||||
|
E->setSubExpr(sub);
|
||||||
|
return E;
|
||||||
|
}
|
||||||
|
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
// Everything Else
|
// Everything Else
|
||||||
//===--------------------------------------------------------------------===//
|
//===--------------------------------------------------------------------===//
|
||||||
|
|||||||
@@ -314,6 +314,7 @@ void Expr::propagateLValueAccessKind(AccessKind accessKind,
|
|||||||
NON_LVALUE_EXPR(Assign)
|
NON_LVALUE_EXPR(Assign)
|
||||||
NON_LVALUE_EXPR(DefaultValue)
|
NON_LVALUE_EXPR(DefaultValue)
|
||||||
NON_LVALUE_EXPR(CodeCompletion)
|
NON_LVALUE_EXPR(CodeCompletion)
|
||||||
|
NON_LVALUE_EXPR(ObjCSelector)
|
||||||
|
|
||||||
#define UNCHECKED_EXPR(KIND, BASE) \
|
#define UNCHECKED_EXPR(KIND, BASE) \
|
||||||
NON_LVALUE_EXPR(KIND)
|
NON_LVALUE_EXPR(KIND)
|
||||||
@@ -487,6 +488,7 @@ bool Expr::canAppendCallParentheses() const {
|
|||||||
case ExprKind::StringLiteral:
|
case ExprKind::StringLiteral:
|
||||||
case ExprKind::InterpolatedStringLiteral:
|
case ExprKind::InterpolatedStringLiteral:
|
||||||
case ExprKind::MagicIdentifierLiteral:
|
case ExprKind::MagicIdentifierLiteral:
|
||||||
|
case ExprKind::ObjCSelector:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ExprKind::ObjectLiteral:
|
case ExprKind::ObjectLiteral:
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ SyntaxModelContext::SyntaxModelContext(SourceFile &SrcFile)
|
|||||||
#define KEYWORD(X) case tok::kw_##X: Kind = SyntaxNodeKind::Keyword; break;
|
#define KEYWORD(X) case tok::kw_##X: Kind = SyntaxNodeKind::Keyword; break;
|
||||||
#include "swift/Parse/Tokens.def"
|
#include "swift/Parse/Tokens.def"
|
||||||
#undef KEYWORD
|
#undef KEYWORD
|
||||||
|
case tok::pound_selector: Kind = SyntaxNodeKind::Keyword; break;
|
||||||
case tok::pound_line:
|
case tok::pound_line:
|
||||||
case tok::pound_available: Kind =
|
case tok::pound_available: Kind =
|
||||||
SyntaxNodeKind::BuildConfigKeyword; break;
|
SyntaxNodeKind::BuildConfigKeyword; break;
|
||||||
|
|||||||
@@ -1619,6 +1619,11 @@ Restart:
|
|||||||
return formToken(tok::pound_available, TokStart);
|
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.
|
// Allow a hashbang #! line at the beginning of the file.
|
||||||
if (CurPtr - 1 == BufferStart && *CurPtr == '!') {
|
if (CurPtr - 1 == BufferStart && *CurPtr == '!') {
|
||||||
CurPtr--;
|
CurPtr--;
|
||||||
|
|||||||
@@ -434,6 +434,7 @@ ParserResult<Expr> Parser::parseExprSequenceElement(Diag<> message,
|
|||||||
/// expr-postfix(Mode)
|
/// expr-postfix(Mode)
|
||||||
/// operator-prefix expr-unary(Mode)
|
/// operator-prefix expr-unary(Mode)
|
||||||
/// '&' expr-unary(Mode)
|
/// '&' expr-unary(Mode)
|
||||||
|
/// expr-selector
|
||||||
///
|
///
|
||||||
ParserResult<Expr> Parser::parseExprUnary(Diag<> Message, bool isExprBasic) {
|
ParserResult<Expr> Parser::parseExprUnary(Diag<> Message, bool isExprBasic) {
|
||||||
UnresolvedDeclRefExpr *Operator;
|
UnresolvedDeclRefExpr *Operator;
|
||||||
@@ -454,6 +455,9 @@ ParserResult<Expr> Parser::parseExprUnary(Diag<> Message, bool isExprBasic) {
|
|||||||
new (Context) InOutExpr(Loc, SubExpr.get(), Type()));
|
new (Context) InOutExpr(Loc, SubExpr.get(), Type()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case tok::pound_selector:
|
||||||
|
return parseExprSelector();
|
||||||
|
|
||||||
case tok::oper_postfix:
|
case tok::oper_postfix:
|
||||||
// Postfix operators cannot start a subexpression, but can happen
|
// Postfix operators cannot start a subexpression, but can happen
|
||||||
// syntactically because the operator may just follow whatever precedes this
|
// 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()));
|
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) {
|
static DeclRefKind getDeclRefKindForOperator(tok kind) {
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case tok::oper_binary_spaced:
|
case tok::oper_binary_spaced:
|
||||||
|
|||||||
@@ -197,6 +197,7 @@ namespace {
|
|||||||
SGFContext C);
|
SGFContext C);
|
||||||
RValue visitObjectLiteralExpr(ObjectLiteralExpr *E, SGFContext C);
|
RValue visitObjectLiteralExpr(ObjectLiteralExpr *E, SGFContext C);
|
||||||
RValue visitEditorPlaceholderExpr(EditorPlaceholderExpr *E, SGFContext C);
|
RValue visitEditorPlaceholderExpr(EditorPlaceholderExpr *E, SGFContext C);
|
||||||
|
RValue visitObjCSelectorExpr(ObjCSelectorExpr *E, SGFContext C);
|
||||||
RValue visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E,
|
RValue visitMagicIdentifierLiteralExpr(MagicIdentifierLiteralExpr *E,
|
||||||
SGFContext C);
|
SGFContext C);
|
||||||
RValue visitCollectionExpr(CollectionExpr *E, SGFContext C);
|
RValue visitCollectionExpr(CollectionExpr *E, SGFContext C);
|
||||||
@@ -1942,6 +1943,13 @@ visitEditorPlaceholderExpr(EditorPlaceholderExpr *E, SGFContext C) {
|
|||||||
return visit(E->getSemanticExpr(), 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
|
static StringRef
|
||||||
getMagicFunctionString(SILGenFunction &gen) {
|
getMagicFunctionString(SILGenFunction &gen) {
|
||||||
assert(gen.MagicFunctionName
|
assert(gen.MagicFunctionName
|
||||||
|
|||||||
@@ -3242,6 +3242,151 @@ namespace {
|
|||||||
return E;
|
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
|
/// Interface for ExprWalker
|
||||||
void walkToExprPre(Expr *expr) {
|
void walkToExprPre(Expr *expr) {
|
||||||
ExprStack.push_back(expr);
|
ExprStack.push_back(expr);
|
||||||
|
|||||||
@@ -2738,6 +2738,26 @@ namespace {
|
|||||||
// case we return the null type.
|
// case we return the null type.
|
||||||
return E->getType();
|
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
|
/// \brief AST walker that "sanitizes" an expression for the
|
||||||
|
|||||||
@@ -111,11 +111,11 @@ Type TypeChecker::getExceptionType(DeclContext *dc, SourceLoc loc) {
|
|||||||
return Type();
|
return Type();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Type getObjectiveCClassType(TypeChecker &TC,
|
static Type getObjectiveCNominalType(TypeChecker &TC,
|
||||||
Type &cache,
|
Type &cache,
|
||||||
Identifier ModuleName,
|
Identifier ModuleName,
|
||||||
Identifier TypeName,
|
Identifier TypeName,
|
||||||
DeclContext *dc) {
|
DeclContext *dc) {
|
||||||
if (cache)
|
if (cache)
|
||||||
return cache;
|
return cache;
|
||||||
|
|
||||||
@@ -142,17 +142,24 @@ static Type getObjectiveCClassType(TypeChecker &TC,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Type TypeChecker::getNSObjectType(DeclContext *dc) {
|
Type TypeChecker::getNSObjectType(DeclContext *dc) {
|
||||||
return getObjectiveCClassType(*this, NSObjectType, Context.Id_ObjectiveC,
|
return getObjectiveCNominalType(*this, NSObjectType, Context.Id_ObjectiveC,
|
||||||
Context.getSwiftId(
|
Context.getSwiftId(
|
||||||
KnownFoundationEntity::NSObject),
|
KnownFoundationEntity::NSObject),
|
||||||
dc);
|
dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type TypeChecker::getNSErrorType(DeclContext *dc) {
|
Type TypeChecker::getNSErrorType(DeclContext *dc) {
|
||||||
return getObjectiveCClassType(*this, NSObjectType, Context.Id_Foundation,
|
return getObjectiveCNominalType(*this, NSObjectType, Context.Id_Foundation,
|
||||||
Context.getSwiftId(
|
Context.getSwiftId(
|
||||||
KnownFoundationEntity::NSError),
|
KnownFoundationEntity::NSError),
|
||||||
dc);
|
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) {
|
Type TypeChecker::getBridgedToObjC(const DeclContext *dc, Type type) {
|
||||||
|
|||||||
@@ -515,6 +515,7 @@ private:
|
|||||||
Type UInt8Type;
|
Type UInt8Type;
|
||||||
Type NSObjectType;
|
Type NSObjectType;
|
||||||
Type NSErrorType;
|
Type NSErrorType;
|
||||||
|
Type ObjCSelectorType;
|
||||||
Type ExceptionType;
|
Type ExceptionType;
|
||||||
|
|
||||||
/// The \c Swift.UnsafeMutablePointer<T> declaration.
|
/// The \c Swift.UnsafeMutablePointer<T> declaration.
|
||||||
@@ -589,6 +590,7 @@ public:
|
|||||||
Type getUInt8Type(DeclContext *dc);
|
Type getUInt8Type(DeclContext *dc);
|
||||||
Type getNSObjectType(DeclContext *dc);
|
Type getNSObjectType(DeclContext *dc);
|
||||||
Type getNSErrorType(DeclContext *dc);
|
Type getNSErrorType(DeclContext *dc);
|
||||||
|
Type getObjCSelectorType(DeclContext *dc);
|
||||||
Type getExceptionType(DeclContext *dc, SourceLoc loc);
|
Type getExceptionType(DeclContext *dc, SourceLoc loc);
|
||||||
|
|
||||||
/// \brief Try to resolve an IdentTypeRepr, returning either the referenced
|
/// \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