diff --git a/include/swift/AST/ASTBridging.h b/include/swift/AST/ASTBridging.h index 5580270f8bf50..3a31cee12ab29 100644 --- a/include/swift/AST/ASTBridging.h +++ b/include/swift/AST/ASTBridging.h @@ -2057,6 +2057,13 @@ BridgedKeyPathExpr BridgedKeyPathExpr_createParsed( BridgedNullableExpr cParsedRoot, BridgedNullableExpr cParsedPath, bool hasLeadingDot); +SWIFT_NAME("BridgedKeyPathExpr.createParsedPoundKeyPath(_:poundLoc:lParenLoc:" + "names:nameLocs:rParenLoc:)") +BridgedKeyPathExpr BridgedKeyPathExpr_createParsedPoundKeyPath( + BridgedASTContext cContext, BridgedSourceLoc cPoundLoc, + BridgedSourceLoc cLParenLoc, BridgedArrayRef cNames, + BridgedArrayRef cNameLocs, BridgedSourceLoc cRParenLoc); + SWIFT_NAME("BridgedMacroExpansionExpr.createParsed(_:poundLoc:macroNameRef:" "macroNameLoc:leftAngleLoc:genericArgs:rightAngleLoc:args:)") BridgedMacroExpansionExpr BridgedMacroExpansionExpr_createParsed( @@ -2087,6 +2094,20 @@ BridgedNilLiteralExpr BridgedNilLiteralExpr_createParsed(BridgedASTContext cContext, BridgedSourceLoc cNilKeywordLoc); +enum ENUM_EXTENSIBILITY_ATTR(open) BridgedObjCSelectorKind { + BridgedObjCSelectorKindMethod, + BridgedObjCSelectorKindGetter, + BridgedObjCSelectorKindSetter, +}; + +SWIFT_NAME("BridgedObjCSelectorExpr.createParsed(_:kind:keywordLoc:lParenLoc:" + "modifierLoc:subExpr:rParenLoc:)") +BridgedObjCSelectorExpr BridgedObjCSelectorExpr_createParsed( + BridgedASTContext cContext, BridgedObjCSelectorKind cKind, + BridgedSourceLoc cKeywordLoc, BridgedSourceLoc cLParenLoc, + BridgedSourceLoc cModifierLoc, BridgedExpr cSubExpr, + BridgedSourceLoc cRParenLoc); + enum ENUM_EXTENSIBILITY_ATTR(open) BridgedObjectLiteralKind : size_t { #define POUND_OBJECT_LITERAL(Name, Desc, Proto) BridgedObjectLiteralKind_##Name, #include "swift/AST/TokenKinds.def" diff --git a/lib/AST/Bridging/ExprBridging.cpp b/lib/AST/Bridging/ExprBridging.cpp index 55d18bb121410..520076f9bee99 100644 --- a/lib/AST/Bridging/ExprBridging.cpp +++ b/lib/AST/Bridging/ExprBridging.cpp @@ -356,6 +356,26 @@ BridgedKeyPathExpr BridgedKeyPathExpr_createParsed( cParsedPath.unbridged(), hasLeadingDot); } +BridgedKeyPathExpr BridgedKeyPathExpr_createParsedPoundKeyPath( + BridgedASTContext cContext, BridgedSourceLoc cPoundLoc, + BridgedSourceLoc cLParenLoc, BridgedArrayRef cNames, + BridgedArrayRef cNameLocs, BridgedSourceLoc cRParenLoc) { + + SmallVector components; + auto cNameArr = cNames.unbridged(); + auto cNameLocArr = cNameLocs.unbridged(); + for (size_t i = 0, e = cNameArr.size(); i != e; ++i) { + auto name = cNameArr[i].unbridged(); + auto loc = cNameLocArr[i].unbridged().getBaseNameLoc(); + components.push_back(KeyPathExpr::Component::forUnresolvedMember( + name, FunctionRefInfo::unappliedBaseName(), loc)); + } + + return KeyPathExpr::createParsedPoundKeyPath( + cContext.unbridged(), cPoundLoc.unbridged(), cLParenLoc.unbridged(), + components, cRParenLoc.unbridged()); +} + BridgedSuperRefExpr BridgedSuperRefExpr_createParsed(BridgedASTContext cContext, BridgedSourceLoc cSuperLoc) { @@ -445,6 +465,28 @@ BridgedNilLiteralExpr_createParsed(BridgedASTContext cContext, return new (cContext.unbridged()) NilLiteralExpr(cNilKeywordLoc.unbridged()); } +BridgedObjCSelectorExpr BridgedObjCSelectorExpr_createParsed( + BridgedASTContext cContext, BridgedObjCSelectorKind cKind, + BridgedSourceLoc cKeywordLoc, BridgedSourceLoc cLParenLoc, + BridgedSourceLoc cModifierLoc, BridgedExpr cSubExpr, + BridgedSourceLoc cRParenLoc) { + ObjCSelectorExpr::ObjCSelectorKind kind; + switch (cKind) { + case BridgedObjCSelectorKindMethod: + kind = ObjCSelectorExpr::Method; + break; + case BridgedObjCSelectorKindGetter: + kind = ObjCSelectorExpr::Getter; + break; + case BridgedObjCSelectorKindSetter: + kind = ObjCSelectorExpr::Setter; + break; + } + return new (cContext.unbridged()) ObjCSelectorExpr( + kind, cKeywordLoc.unbridged(), cLParenLoc.unbridged(), + cModifierLoc.unbridged(), cSubExpr.unbridged(), cRParenLoc.unbridged()); +} + SWIFT_NAME("BridgedObjectLiteralKind.init(from:)") BridgedObjectLiteralKind BridgedObjectLiteralKind_fromString(BridgedStringRef cStr) { diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 3ae901ab97f3a..7699b842c40ef 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -427,6 +427,19 @@ void Decl::attachParsedAttrs(DeclAttributes attrs) { for (auto attr : attrs.getAttributes()) recordABIAttr(attr); + // @implementation requires an explicit @objc attribute, but + // @_objcImplementation didn't. Insert one if necessary. + auto implAttr = attrs.getAttribute(); + if (implAttr && isa(this) && implAttr->isEarlyAdopter() && + !attrs.hasAttribute()) { + ObjCAttr *objcAttr = + implAttr->CategoryName.empty() + ? ObjCAttr::createUnnamedImplicit(getASTContext()) + : ObjCAttr::createNullary(getASTContext(), implAttr->CategoryName, + /*isNameImplicit=*/false); + attrs.add(objcAttr); + } + getAttrs() = attrs; } diff --git a/lib/ASTGen/Sources/ASTGen/BuiltinPound.swift b/lib/ASTGen/Sources/ASTGen/BuiltinPound.swift index 61a0ea9ded2af..8dbe88d23359b 100644 --- a/lib/ASTGen/Sources/ASTGen/BuiltinPound.swift +++ b/lib/ASTGen/Sources/ASTGen/BuiltinPound.swift @@ -70,11 +70,11 @@ extension ASTGenVisitor { switch keyword { case .selector: let selectorExpr = self.generateObjCSelectorExpr(freestandingMacroExpansion: node) - return .generated(.expr(selectorExpr.asExpr)) + return .generated(.expr(selectorExpr)) case .keyPath: let keypathExpr = self.generateObjCKeyPathExpr(freestandingMacroExpansion: node) - return .generated(.expr(keypathExpr.asExpr)) + return .generated(.expr(keypathExpr)) case .assert where ctx.langOptsHasFeature(.StaticAssert): let assertStmtOpt = self.generatePoundAssertStmt(freestandingMacroExpansion: node) @@ -119,6 +119,15 @@ extension ASTGenVisitor { // return } + guard + node.genericArgumentClause == nil, + node.trailingClosure == nil, + node.additionalTrailingClosures.isEmpty + else { + // TODO: Diagnose. + fatalError("#error/#warning with generic specialization") + } + guard node.arguments.count == 1, let arg = node.arguments.first, arg.label == nil, @@ -194,11 +203,115 @@ extension ASTGenVisitor { ) } - func generateObjCSelectorExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedObjCSelectorExpr { - fatalError("unimplemented (objc selector)") + func generateObjCSelectorExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedExpr { + guard + node.genericArgumentClause == nil, + node.trailingClosure == nil, + node.additionalTrailingClosures.isEmpty + else { + // TODO: Diagnose. + fatalError("#selector with generic specialization") + } + + var args = node.arguments[...] + guard let arg = args.popFirst() else { + // TODO: Diagnose + fatalError("expected an argument for #selector") + // return ErrorExpr + } + let kind: BridgedObjCSelectorKind + switch arg.label?.rawText { + case nil: kind = .method + case "getter": kind = .getter + case "setter": kind = .setter + case _?: + // TODO: Diagnose + fatalError("unexpected argument label in #selector") + // return ErrorExpr + } + let expr = self.generate(expr: arg.expression) + guard args.isEmpty else { + // TODO: Diagnose + fatalError("unexpected argument in #selector") + // return ErrorExpr + } + return BridgedObjCSelectorExpr.createParsed( + self.ctx, + kind: kind, + keywordLoc: self.generateSourceLoc(node.pound), + lParenLoc: self.generateSourceLoc(node.leftParen), + modifierLoc: self.generateSourceLoc(arg.label), + subExpr: expr, + rParenLoc: self.generateSourceLoc(node.rightParen) + ).asExpr } - func generateObjCKeyPathExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedKeyPathExpr { - fatalError("unimplemented (objc keypath)") + func generateObjCKeyPathExpr(freestandingMacroExpansion node: some FreestandingMacroExpansionSyntax) -> BridgedExpr { + guard + node.genericArgumentClause == nil, + node.trailingClosure == nil, + node.additionalTrailingClosures.isEmpty + else { + // TODO: Diagnose. + fatalError("#keyPath with generic specialization") + } + + var names: [BridgedDeclNameRef] = [] + var nameLocs: [BridgedDeclNameLoc] = [] + + func collectNames(expr node: ExprSyntax) -> Bool { + if let declRefExpr = node.as(DeclReferenceExprSyntax.self) { + let nameAndLoc = self.generateDeclNameRef(declReferenceExpr: declRefExpr) + names.append(nameAndLoc.name) + nameLocs.append(nameAndLoc.loc) + return false + } + if let memberExpr = node.as(MemberAccessExprSyntax.self) { + guard let base = memberExpr.base else { + // TODO: Diagnose + fatalError("unexpected expression in #keyPath") + } + if collectNames(expr: base) { + return true + } + let nameAndLoc = self.generateDeclNameRef(declReferenceExpr: memberExpr.declName) + names.append(nameAndLoc.name) + nameLocs.append(nameAndLoc.loc) + return false + } + // TODO: Diagnose + fatalError("unexpected expression in #keyPath") + // return true + } + + var args = node.arguments[...] + guard let arg = args.popFirst() else { + // TODO: Diagnose + fatalError("expected an argument for #keyPath") + // return ErrorExpr + } + guard arg.label == nil else { + // TODO: Diagnose + fatalError("unexpected argument label #keyPath") + + } + if /*hadError=*/collectNames(expr: arg.expression) { + return BridgedErrorExpr.create(self.ctx, loc: self.generateSourceRange(node)).asExpr; + } + + guard args.isEmpty else { + // TODO: Diagnose + fatalError("unexpected argument in #keyPath") + // return ErrorExpr + } + + return BridgedKeyPathExpr.createParsedPoundKeyPath( + self.ctx, + poundLoc: self.generateSourceLoc(node.pound), + lParenLoc: self.generateSourceLoc(node.leftParen), + names: names.lazy.bridgedArray(in: self), + nameLocs: nameLocs.lazy.bridgedArray(in: self), + rParenLoc: self.generateSourceLoc(node.rightParen) + ).asExpr } } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index d4b02bf876b7e..f2f378f6c7e9a 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -7070,20 +7070,6 @@ Parser::parseDeclExtension(ParseDeclOptions Flags, DeclAttributes &Attributes) { status |= whereStatus; } - // @implementation requires an explicit @objc attribute, but - // @_objcImplementation didn't. Insert one if necessary. - auto implAttr = Attributes.getAttribute(); - if (implAttr && implAttr->isEarlyAdopter() - && !Attributes.hasAttribute()) { - ObjCAttr *objcAttr; - if (implAttr->CategoryName.empty()) - objcAttr = ObjCAttr::createUnnamedImplicit(Context); - else - objcAttr = ObjCAttr::createNullary(Context, implAttr->CategoryName, - /*isNameImplicit=*/false); - Attributes.add(objcAttr); - } - ExtensionDecl *ext = ExtensionDecl::create(Context, ExtensionLoc, extendedType.getPtrOrNull(), Context.AllocateCopy(Inherited), diff --git a/test/ASTGen/Inputs/objc_decls.h b/test/ASTGen/Inputs/objc_decls.h index 79822e39d86fc..66333a051e495 100644 --- a/test/ASTGen/Inputs/objc_decls.h +++ b/test/ASTGen/Inputs/objc_decls.h @@ -1,7 +1,10 @@ @import Foundation; @interface ObjCClass: NSObject +@property NSString *theValue; +-(void)methodWithX:(NSInteger)x Y:(NSInteger)y; @end + @interface ObjCClass(Category1) @end @interface ObjCClass(Category2) diff --git a/test/ASTGen/attrs_objc.swift b/test/ASTGen/attrs_objc.swift index a9c70373e45b7..64f7e44e39142 100644 --- a/test/ASTGen/attrs_objc.swift +++ b/test/ASTGen/attrs_objc.swift @@ -17,14 +17,25 @@ @objc(barWithX:Y:) func foo(x: Int, y: Int) {} } -@objc @implementation extension ObjCClass {} +@objc @implementation extension ObjCClass { + var theValue: String? { + get { "" } + set {} + } + @objc(methodWithX:Y:) + func methodWith(x: Int, y: Int) {} +} @objc @implementation(Category1) extension ObjCClass {} // expected-error {{Objective-C category should be specified on '@objc', not '@implementation'}} @objc(Category2) @implementation extension ObjCClass {} -// FIXME: @_objcImplementation inserts implicit @objc attribute in C++ parser. -//@_objcImplementation extension ObjCClass2 {} // xpected-error {{cannot find type 'ObjCClass2' in scope}} -//@_objcImplementation(Category) extension ObjCClass2 {} // xpected-error {{cannot find type 'ObjCClass2' in scope}} +@_objcImplementation extension ObjCClass2 {} // expected-warning {{'@_objcImplementation' is deprecated; use '@implementation' instead}} @_objcRuntimeName(RenamedClass) class ThisWillBeRenamed {} @_swift_native_objc_runtime_base(NSMagicBase) class TestNativeObjCRuntimeBase {} + +func testPoundObjC() { + let _: String = #keyPath(ObjCClass.theValue) + let _: Selector = #selector(getter:ObjCClass.theValue) + let _: Selector = #selector(ObjCClass.methodWith(x:y:)) +}