@@ -1262,17 +1262,39 @@ bool swift::canBeRepresentedInObjC(const ValueDecl *decl) {
1262
1262
1263
1263
#pragma mark "@objc declaration handling"
1264
1264
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) {
1267
1276
auto ext = dyn_cast<ExtensionDecl>(VD->getDeclContext ());
1268
- if (!ext) return false ;
1277
+ if (!ext || !ext->getSelfClassDecl ())
1278
+ return ObjCExtensionKind::None;
1269
1279
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
+ }
1272
1296
1273
- static bool isMemberOfObjCImplementationExtension (const ValueDecl *VD) {
1274
- return isMemberOfObjCClassExtension (VD) &&
1275
- cast<ExtensionDecl>(VD->getDeclContext ())->isObjCImplementation ();
1297
+ return ObjCExtensionKind::NormalExtension;
1276
1298
}
1277
1299
1278
1300
// / Whether this declaration is a member of a class with the `@objcMembers`
@@ -1509,18 +1531,28 @@ shouldMarkAsObjC(const ValueDecl *VD, bool allowImplicit,
1509
1531
.hasAttribute <NonObjCAttr>()))
1510
1532
return std::nullopt;
1511
1533
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:
1513
1542
// A non-`final` member of an @objc @implementation extension is @objc
1514
1543
// with a special reason.
1515
1544
if (!VD->isFinal () && canInferImplicitObjC (/* allowAnyAccess*/ true )) {
1516
1545
if (!isImplEarlyAdopter)
1517
1546
return ObjCReason (ObjCReason::MemberOfObjCImplementationExtension,
1518
1547
implAttr);
1519
1548
}
1549
+ break ;
1550
+
1551
+ case ObjCExtensionKind::NormalExtension:
1552
+ if (canInferImplicitObjC (/* allowAnyAccess*/ true ))
1553
+ return ObjCReason (ObjCReason::MemberOfObjCExtension);
1554
+ break ;
1520
1555
}
1521
- else if (isMemberOfObjCClassExtension (VD) &&
1522
- canInferImplicitObjC (/* allowAnyAccess*/ true ))
1523
- return ObjCReason (ObjCReason::MemberOfObjCExtension);
1524
1556
1525
1557
if (isMemberOfObjCMembersClass (VD) &&
1526
1558
canInferImplicitObjC (/* allowAnyAccess*/ false ))
0 commit comments