@@ -1262,17 +1262,39 @@ bool swift::canBeRepresentedInObjC(const ValueDecl *decl) {
12621262
12631263#pragma mark "@objc declaration handling"
12641264
1265- // / Whether this declaration is a member of a class extension marked @objc.
1266- static bool isMemberOfObjCClassExtension (const ValueDecl *VD) {
1265+ enum class ObjCExtensionKind : uint8_t {
1266+ // / Not an @objc extension of any kind.
1267+ None,
1268+ // / This should be treated as an @objc @implementation extension.
1269+ ImplementationExtension,
1270+ // / This should be treated as an ordinary @objc extension.
1271+ NormalExtension,
1272+ };
1273+
1274+ static ObjCExtensionKind
1275+ classifyObjCExtensionContext (const ValueDecl *VD, bool isEarlyAdopter) {
12671276 auto ext = dyn_cast<ExtensionDecl>(VD->getDeclContext ());
1268- if (!ext) return false ;
1277+ if (!ext || !ext->getSelfClassDecl ())
1278+ return ObjCExtensionKind::None;
12691279
1270- return ext->getSelfClassDecl () && ext->getAttrs ().hasAttribute <ObjCAttr>();
1271- }
1280+ auto objCAttr = ext->getAttrs ().getAttribute <ObjCAttr>();
1281+ if (!objCAttr)
1282+ return ObjCExtensionKind::None;
1283+
1284+ if (ext->isObjCImplementation ()) {
1285+ // Only apply objcImpl-specific logic at this point in the algorithm if the
1286+ // user wrote the new syntax.
1287+ if (!isEarlyAdopter)
1288+ return ObjCExtensionKind::ImplementationExtension;
1289+
1290+ // Here's the tricky case: If the `@objc` attribute is implicit, then it was
1291+ // added by the parser when it saw the early adopter syntax, so we should
1292+ // pretend it isn't there!
1293+ if (objCAttr->isImplicit ())
1294+ return ObjCExtensionKind::None;
1295+ }
12721296
1273- static bool isMemberOfObjCImplementationExtension (const ValueDecl *VD) {
1274- return isMemberOfObjCClassExtension (VD) &&
1275- cast<ExtensionDecl>(VD->getDeclContext ())->isObjCImplementation ();
1297+ return ObjCExtensionKind::NormalExtension;
12761298}
12771299
12781300// / Whether this declaration is a member of a class with the `@objcMembers`
@@ -1509,18 +1531,28 @@ shouldMarkAsObjC(const ValueDecl *VD, bool allowImplicit,
15091531 .hasAttribute <NonObjCAttr>()))
15101532 return std::nullopt ;
15111533
1512- if (isMemberOfObjCImplementationExtension (VD)) {
1534+ // Handle @objc extensions of various sorts.
1535+ // The `ImplementationExtension` case is only taken if we are *not* an early
1536+ // adopter, though which of the other two it will take instead is complicated.
1537+ switch (classifyObjCExtensionContext (VD, isImplEarlyAdopter)) {
1538+ case ObjCExtensionKind::None:
1539+ break ;
1540+
1541+ case ObjCExtensionKind::ImplementationExtension:
15131542 // A non-`final` member of an @objc @implementation extension is @objc
15141543 // with a special reason.
15151544 if (!VD->isFinal () && canInferImplicitObjC (/* allowAnyAccess*/ true )) {
15161545 if (!isImplEarlyAdopter)
15171546 return ObjCReason (ObjCReason::MemberOfObjCImplementationExtension,
15181547 implAttr);
15191548 }
1549+ break ;
1550+
1551+ case ObjCExtensionKind::NormalExtension:
1552+ if (canInferImplicitObjC (/* allowAnyAccess*/ true ))
1553+ return ObjCReason (ObjCReason::MemberOfObjCExtension);
1554+ break ;
15201555 }
1521- else if (isMemberOfObjCClassExtension (VD) &&
1522- canInferImplicitObjC (/* allowAnyAccess*/ true ))
1523- return ObjCReason (ObjCReason::MemberOfObjCExtension);
15241556
15251557 if (isMemberOfObjCMembersClass (VD) &&
15261558 canInferImplicitObjC (/* allowAnyAccess*/ false ))
0 commit comments