Skip to content

Commit 76f0d4d

Browse files
committed
[ASTGen] ObjC improvements
* Generate `#selector(...)` expression * Generate `#keyPath(...)` expression * Implicit `@objc` attribute for `@_objcImplementation` attribute
1 parent dc41b21 commit 76f0d4d

File tree

7 files changed

+187
-24
lines changed

7 files changed

+187
-24
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2057,6 +2057,13 @@ BridgedKeyPathExpr BridgedKeyPathExpr_createParsed(
20572057
BridgedNullableExpr cParsedRoot, BridgedNullableExpr cParsedPath,
20582058
bool hasLeadingDot);
20592059

2060+
SWIFT_NAME("BridgedKeyPathExpr.createParsedPoundKeyPath(_:poundLoc:lParenLoc:"
2061+
"names:nameLocs:rParenLoc:)")
2062+
BridgedKeyPathExpr BridgedKeyPathExpr_createParsedPoundKeyPath(
2063+
BridgedASTContext cContext, BridgedSourceLoc cPoundLoc,
2064+
BridgedSourceLoc cLParenLoc, BridgedArrayRef cNames,
2065+
BridgedArrayRef cNameLocs, BridgedSourceLoc cRParenLoc);
2066+
20602067
SWIFT_NAME("BridgedMacroExpansionExpr.createParsed(_:poundLoc:macroNameRef:"
20612068
"macroNameLoc:leftAngleLoc:genericArgs:rightAngleLoc:args:)")
20622069
BridgedMacroExpansionExpr BridgedMacroExpansionExpr_createParsed(
@@ -2087,6 +2094,20 @@ BridgedNilLiteralExpr
20872094
BridgedNilLiteralExpr_createParsed(BridgedASTContext cContext,
20882095
BridgedSourceLoc cNilKeywordLoc);
20892096

2097+
enum ENUM_EXTENSIBILITY_ATTR(open) BridgedObjCSelectorKind {
2098+
BridgedObjCSelectorKindMethod,
2099+
BridgedObjCSelectorKindGetter,
2100+
BridgedObjCSelectorKindSetter,
2101+
};
2102+
2103+
SWIFT_NAME("BridgedObjCSelectorExpr.createParsed(_:kind:keywordLoc:lParenLoc:"
2104+
"modifierLoc:subExpr:rParenLoc:)")
2105+
BridgedObjCSelectorExpr BridgedObjCSelectorExpr_createParsed(
2106+
BridgedASTContext cContext, BridgedObjCSelectorKind cKind,
2107+
BridgedSourceLoc cKeywordLoc, BridgedSourceLoc cLParenLoc,
2108+
BridgedSourceLoc cModifierLoc, BridgedExpr cSubExpr,
2109+
BridgedSourceLoc cRParenLoc);
2110+
20902111
enum ENUM_EXTENSIBILITY_ATTR(open) BridgedObjectLiteralKind : size_t {
20912112
#define POUND_OBJECT_LITERAL(Name, Desc, Proto) BridgedObjectLiteralKind_##Name,
20922113
#include "swift/AST/TokenKinds.def"

lib/AST/Bridging/ExprBridging.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,26 @@ BridgedKeyPathExpr BridgedKeyPathExpr_createParsed(
356356
cParsedPath.unbridged(), hasLeadingDot);
357357
}
358358

359+
BridgedKeyPathExpr BridgedKeyPathExpr_createParsedPoundKeyPath(
360+
BridgedASTContext cContext, BridgedSourceLoc cPoundLoc,
361+
BridgedSourceLoc cLParenLoc, BridgedArrayRef cNames,
362+
BridgedArrayRef cNameLocs, BridgedSourceLoc cRParenLoc) {
363+
364+
SmallVector<KeyPathExpr::Component> components;
365+
auto cNameArr = cNames.unbridged<BridgedDeclNameRef>();
366+
auto cNameLocArr = cNameLocs.unbridged<BridgedDeclNameLoc>();
367+
for (size_t i = 0, e = cNameArr.size(); i != e; ++i) {
368+
auto name = cNameArr[i].unbridged();
369+
auto loc = cNameLocArr[i].unbridged().getBaseNameLoc();
370+
components.push_back(
371+
KeyPathExpr::Component::forUnresolvedProperty(name, loc));
372+
}
373+
374+
return KeyPathExpr::createParsedPoundKeyPath(
375+
cContext.unbridged(), cPoundLoc.unbridged(), cLParenLoc.unbridged(),
376+
components, cRParenLoc.unbridged());
377+
}
378+
359379
BridgedSuperRefExpr
360380
BridgedSuperRefExpr_createParsed(BridgedASTContext cContext,
361381
BridgedSourceLoc cSuperLoc) {
@@ -445,6 +465,28 @@ BridgedNilLiteralExpr_createParsed(BridgedASTContext cContext,
445465
return new (cContext.unbridged()) NilLiteralExpr(cNilKeywordLoc.unbridged());
446466
}
447467

468+
BridgedObjCSelectorExpr BridgedObjCSelectorExpr_createParsed(
469+
BridgedASTContext cContext, BridgedObjCSelectorKind cKind,
470+
BridgedSourceLoc cKeywordLoc, BridgedSourceLoc cLParenLoc,
471+
BridgedSourceLoc cModifierLoc, BridgedExpr cSubExpr,
472+
BridgedSourceLoc cRParenLoc) {
473+
ObjCSelectorExpr::ObjCSelectorKind kind;
474+
switch (cKind) {
475+
case BridgedObjCSelectorKindMethod:
476+
kind = ObjCSelectorExpr::Method;
477+
break;
478+
case BridgedObjCSelectorKindGetter:
479+
kind = ObjCSelectorExpr::Getter;
480+
break;
481+
case BridgedObjCSelectorKindSetter:
482+
kind = ObjCSelectorExpr::Setter;
483+
break;
484+
}
485+
return new (cContext.unbridged()) ObjCSelectorExpr(
486+
kind, cKeywordLoc.unbridged(), cLParenLoc.unbridged(),
487+
cModifierLoc.unbridged(), cSubExpr.unbridged(), cRParenLoc.unbridged());
488+
}
489+
448490
SWIFT_NAME("BridgedObjectLiteralKind.init(from:)")
449491
BridgedObjectLiteralKind
450492
BridgedObjectLiteralKind_fromString(BridgedStringRef cStr) {

lib/AST/Decl.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,19 @@ void Decl::attachParsedAttrs(DeclAttributes attrs) {
427427
for (auto attr : attrs.getAttributes<ABIAttr, /*AllowInvalid=*/true>())
428428
recordABIAttr(attr);
429429

430+
// @implementation requires an explicit @objc attribute, but
431+
// @_objcImplementation didn't. Insert one if necessary.
432+
auto implAttr = attrs.getAttribute<ObjCImplementationAttr>();
433+
if (implAttr && isa<ExtensionDecl>(this) && implAttr->isEarlyAdopter() &&
434+
!attrs.hasAttribute<ObjCAttr>()) {
435+
ObjCAttr *objcAttr =
436+
implAttr->CategoryName.empty()
437+
? ObjCAttr::createUnnamedImplicit(getASTContext())
438+
: ObjCAttr::createNullary(getASTContext(), implAttr->CategoryName,
439+
/*isNameImplicit=*/false);
440+
attrs.add(objcAttr);
441+
}
442+
430443
getAttrs() = attrs;
431444
}
432445

lib/ASTGen/Sources/ASTGen/BuiltinPound.swift

Lines changed: 93 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,11 @@ extension ASTGenVisitor {
7070
switch keyword {
7171
case .selector:
7272
let selectorExpr = self.generateObjCSelectorExpr(freestandingMacroExpansion: node)
73-
return .generated(.expr(selectorExpr.asExpr))
73+
return .generated(.expr(selectorExpr))
7474

7575
case .keyPath:
7676
let keypathExpr = self.generateObjCKeyPathExpr(freestandingMacroExpansion: node)
77-
return .generated(.expr(keypathExpr.asExpr))
77+
return .generated(.expr(keypathExpr))
7878

7979
case .assert where ctx.langOptsHasFeature(.StaticAssert):
8080
let assertStmtOpt = self.generatePoundAssertStmt(freestandingMacroExpansion: node)
@@ -194,11 +194,98 @@ extension ASTGenVisitor {
194194
)
195195
}
196196

197-
func generateObjCSelectorExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedObjCSelectorExpr {
198-
fatalError("unimplemented (objc selector)")
197+
func generateObjCSelectorExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedExpr {
198+
var args = node.arguments[...]
199+
guard let arg = args.popFirst() else {
200+
// TODO: Diagnose
201+
fatalError("expected an argument for #selector")
202+
// return ErrorExpr
203+
}
204+
let kind: BridgedObjCSelectorKind
205+
switch arg.label?.rawText {
206+
case nil: kind = .method
207+
case "getter": kind = .getter
208+
case "setter": kind = .setter
209+
case _?:
210+
// TODO: Diagnose
211+
fatalError("unexpected argument label in #selector")
212+
// return ErrorExpr
213+
}
214+
let expr = self.generate(expr: arg.expression)
215+
guard args.isEmpty else {
216+
// TODO: Diagnose
217+
fatalError("unexpected argument in #selector")
218+
// return ErrorExpr
219+
}
220+
return BridgedObjCSelectorExpr.createParsed(
221+
self.ctx,
222+
kind: kind,
223+
keywordLoc: self.generateSourceLoc(node.pound),
224+
lParenLoc: self.generateSourceLoc(node.leftParen),
225+
modifierLoc: self.generateSourceLoc(arg.label),
226+
subExpr: expr,
227+
rParenLoc: self.generateSourceLoc(node.rightParen)
228+
).asExpr
199229
}
200230

201-
func generateObjCKeyPathExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedKeyPathExpr {
202-
fatalError("unimplemented (objc keypath)")
231+
func generateObjCKeyPathExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedExpr {
232+
233+
var names: [BridgedDeclNameRef] = []
234+
var nameLocs: [BridgedDeclNameLoc] = []
235+
236+
func collectNames(expr node: ExprSyntax) -> Bool {
237+
if let declRefExpr = node.as(DeclReferenceExprSyntax.self) {
238+
let nameAndLoc = self.generateDeclNameRef(declReferenceExpr: declRefExpr)
239+
names.append(nameAndLoc.name)
240+
nameLocs.append(nameAndLoc.loc)
241+
return false
242+
}
243+
if let memberExpr = node.as(MemberAccessExprSyntax.self) {
244+
guard let base = memberExpr.base else {
245+
// TODO: Diagnose
246+
fatalError("unexpected expression in #keyPath")
247+
}
248+
if collectNames(expr: base) {
249+
return true
250+
}
251+
let nameAndLoc = self.generateDeclNameRef(declReferenceExpr: memberExpr.declName)
252+
names.append(nameAndLoc.name)
253+
nameLocs.append(nameAndLoc.loc)
254+
return false
255+
}
256+
// TODO: Diagnose
257+
fatalError("unexpected expression in #keyPath")
258+
// return true
259+
}
260+
261+
var args = node.arguments[...]
262+
guard let arg = args.popFirst() else {
263+
// TODO: Diagnose
264+
fatalError("expected an argument for #keyPath")
265+
// return ErrorExpr
266+
}
267+
guard arg.label == nil else {
268+
// TODO: Diagnose
269+
fatalError("unexpected argument label #keyPath")
270+
271+
}
272+
if /*hadError=*/collectNames(expr: arg.expression) {
273+
return BridgedErrorExpr.create(self.ctx, loc: self.generateSourceRange(node)).asExpr;
274+
}
275+
276+
guard args.isEmpty else {
277+
// TODO: Diagnose
278+
fatalError("unexpected argument in #keyPath")
279+
// return ErrorExpr
280+
}
281+
282+
return BridgedKeyPathExpr.createParsedPoundKeyPath(
283+
self.ctx,
284+
poundLoc: self.generateSourceLoc(node.pound),
285+
lParenLoc: self.generateSourceLoc(node.leftParen),
286+
names: names.lazy.bridgedArray(in: self),
287+
nameLocs: nameLocs.lazy.bridgedArray(in: self),
288+
rParenLoc: self.generateSourceLoc(node.rightParen)
289+
).asExpr
203290
}
204291
}

lib/Parse/ParseDecl.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7070,20 +7070,6 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) {
70707070
status |= whereStatus;
70717071
}
70727072

7073-
// @implementation requires an explicit @objc attribute, but
7074-
// @_objcImplementation didn't. Insert one if necessary.
7075-
auto implAttr = Attributes.getAttribute<ObjCImplementationAttr>();
7076-
if (implAttr && implAttr->isEarlyAdopter()
7077-
&& !Attributes.hasAttribute<ObjCAttr>()) {
7078-
ObjCAttr *objcAttr;
7079-
if (implAttr->CategoryName.empty())
7080-
objcAttr = ObjCAttr::createUnnamedImplicit(Context);
7081-
else
7082-
objcAttr = ObjCAttr::createNullary(Context, implAttr->CategoryName,
7083-
/*isNameImplicit=*/false);
7084-
Attributes.add(objcAttr);
7085-
}
7086-
70877073
ExtensionDecl *ext = ExtensionDecl::create(Context, ExtensionLoc,
70887074
extendedType.getPtrOrNull(),
70897075
Context.AllocateCopy(Inherited),

test/ASTGen/Inputs/objc_decls.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
@import Foundation;
22

33
@interface ObjCClass: NSObject
4+
@property NSString *theValue;
5+
-(void)methodWithX:(NSInteger)x Y:(NSInteger)y;
46
@end
7+
58
@interface ObjCClass(Category1)
69
@end
710
@interface ObjCClass(Category2)

test/ASTGen/attrs_objc.swift

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,25 @@
1717
@objc(barWithX:Y:) func foo(x: Int, y: Int) {}
1818
}
1919

20-
@objc @implementation extension ObjCClass {}
20+
@objc @implementation extension ObjCClass {
21+
var theValue: String? {
22+
get { "" }
23+
set {}
24+
}
25+
@objc(methodWithX:Y:)
26+
func methodWith(x: Int, y: Int) {}
27+
}
2128
@objc @implementation(Category1) extension ObjCClass {} // expected-error {{Objective-C category should be specified on '@objc', not '@implementation'}}
2229
@objc(Category2) @implementation extension ObjCClass {}
2330

24-
// FIXME: @_objcImplementation inserts implicit @objc attribute in C++ parser.
25-
//@_objcImplementation extension ObjCClass2 {} // xpected-error {{cannot find type 'ObjCClass2' in scope}}
26-
//@_objcImplementation(Category) extension ObjCClass2 {} // xpected-error {{cannot find type 'ObjCClass2' in scope}}
31+
@_objcImplementation extension ObjCClass2 {} // expected-warning {{'@_objcImplementation' is deprecated; use '@implementation' instead}}
2732

2833
@_objcRuntimeName(RenamedClass) class ThisWillBeRenamed {}
2934

3035
@_swift_native_objc_runtime_base(NSMagicBase) class TestNativeObjCRuntimeBase {}
36+
37+
func testPoundObjC() {
38+
let _: String = #keyPath(ObjCClass.theValue)
39+
let _: Selector = #selector(getter:ObjCClass.theValue)
40+
let _: Selector = #selector(ObjCClass.methodWith(x:y:))
41+
}

0 commit comments

Comments
 (0)