@@ -3689,6 +3689,10 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
3689
3689
case DeclKind::Protocol: {
3690
3690
// Allow on protocols because they are sources
3691
3691
// of inference.
3692
+ if (attr->hasArgs ()) {
3693
+ diagnoseAndRemoveAttr (
3694
+ attr, diag::cannot_use_attr_with_custom_arguments_on_protocol);
3695
+ }
3692
3696
return ;
3693
3697
}
3694
3698
@@ -3715,6 +3719,40 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
3715
3719
return ;
3716
3720
}
3717
3721
3722
+ case DeclKind::Extension: {
3723
+ auto *ext = cast<ExtensionDecl>(D);
3724
+
3725
+ // Only allowed on unavailable extensions in the same module as type
3726
+ // as a way to opt-out from use of the attribute.
3727
+ if (AvailableAttr::isUnavailable (ext)) {
3728
+ auto *extendedType = ext->getExtendedNominal ();
3729
+
3730
+ // If there is no type, fallback to default diagnostic.
3731
+ if (!extendedType)
3732
+ break ;
3733
+
3734
+ if (extendedType->getParentModule () == ext->getParentModule ()) {
3735
+ for (auto directAttr : extendedType->getRuntimeDiscoverableAttrs ()) {
3736
+ auto directAttrDecl =
3737
+ extendedType->getRuntimeDiscoverableAttrTypeDecl (directAttr);
3738
+ if (directAttrDecl == nominal) {
3739
+ diagnose (attr->getLocation (),
3740
+ diag::invalid_attr_redeclaration_in_extension,
3741
+ nominal->getNameStr (), extendedType->getName ())
3742
+ .fixItRemove (directAttr->getRangeWithAt ());
3743
+ }
3744
+ }
3745
+
3746
+ return ;
3747
+ }
3748
+ }
3749
+
3750
+ diagnoseAndRemoveAttr (
3751
+ attr, diag::invalid_decl_for_runtime_discoverable_attr_in_extension,
3752
+ nominal->getNameStr (), ext->getExtendedNominal ()->getName ());
3753
+ return ;
3754
+ }
3755
+
3718
3756
default :
3719
3757
// All other kinds of declarations i.e. subscripts, constructors etc.
3720
3758
// are unsupported.
@@ -7111,7 +7149,16 @@ void AttributeChecker::visitCompilerInitializedAttr(
7111
7149
}
7112
7150
7113
7151
void AttributeChecker::visitRuntimeMetadataAttr (RuntimeMetadataAttr *attr) {
7114
- if (!Ctx.LangOpts .hasFeature (Feature::RuntimeDiscoverableAttrs)) {
7152
+ auto isEnabled = [&]() {
7153
+ if (Ctx.LangOpts .hasFeature (Feature::RuntimeDiscoverableAttrs))
7154
+ return true ;
7155
+
7156
+ // Accept attributes that come from swiftinterface files.
7157
+ auto *parentSF = D->getDeclContext ()->getParentSourceFile ();
7158
+ return parentSF && parentSF->Kind == SourceFileKind::Interface;
7159
+ };
7160
+
7161
+ if (!isEnabled ()) {
7115
7162
diagnose (attr->getLocation (),
7116
7163
diag::runtime_discoverable_attrs_are_experimental);
7117
7164
attr->setInvalid ();
@@ -7415,7 +7462,7 @@ ValueDecl *RenamedDeclRequest::evaluate(Evaluator &evaluator,
7415
7462
7416
7463
template <typename ATTR>
7417
7464
static void forEachCustomAttribute (
7418
- ValueDecl *decl,
7465
+ Decl *decl,
7419
7466
llvm::function_ref<void (CustomAttr *attr, NominalTypeDecl *)> fn) {
7420
7467
auto &ctx = decl->getASTContext ();
7421
7468
@@ -7425,7 +7472,6 @@ static void forEachCustomAttribute(
7425
7472
auto *nominal = evaluateOrDefault (
7426
7473
ctx.evaluator ,
7427
7474
CustomAttrNominalRequest{mutableAttr, decl->getDeclContext ()}, nullptr );
7428
-
7429
7475
if (!nominal)
7430
7476
continue ;
7431
7477
@@ -7436,15 +7482,15 @@ static void forEachCustomAttribute(
7436
7482
7437
7483
ArrayRef<CustomAttr *>
7438
7484
GetRuntimeDiscoverableAttributes::evaluate (Evaluator &evaluator,
7439
- ValueDecl *decl) const {
7485
+ Decl *decl) const {
7440
7486
auto &ctx = decl->getASTContext ();
7441
7487
7442
7488
llvm::SmallMapVector<NominalTypeDecl *, CustomAttr *, 4 > attrs;
7443
7489
7444
7490
enum class GatheringMode { Direct, Inference };
7445
7491
7446
7492
auto gatherRuntimeAttrsOnDecl =
7447
- [&](ValueDecl *decl,
7493
+ [&](Decl *decl,
7448
7494
llvm::SmallMapVector<NominalTypeDecl *, CustomAttr *, 4 > &attrs,
7449
7495
GatheringMode mode) {
7450
7496
forEachCustomAttribute<RuntimeMetadataAttr>(
@@ -7476,14 +7522,86 @@ GetRuntimeDiscoverableAttributes::evaluate(Evaluator &evaluator,
7476
7522
return copy;
7477
7523
};
7478
7524
7525
+ // Verify that a subclass or a protocol has all of the reflection
7526
+ // metadata attributes expected by the superclass.
7527
+ auto verifySuperclassAttrRequirements = [&](NominalTypeDecl *typeDecl,
7528
+ ClassDecl *superclass) {
7529
+ auto attrRequirements = superclass->getRuntimeDiscoverableAttrs ();
7530
+ if (attrRequirements.empty ())
7531
+ return ;
7532
+
7533
+ // All of the reflection metadata attributes declared in
7534
+ // unavailable extensions of this type in the same module.
7535
+ llvm::SmallPtrSet<NominalTypeDecl *, 4 > unavailableAttrs;
7536
+ for (auto *extension : typeDecl->getExtensions ()) {
7537
+ if (extension->isConstrainedExtension () ||
7538
+ extension->getParentModule () != typeDecl->getParentModule ())
7539
+ continue ;
7540
+
7541
+ forEachCustomAttribute<RuntimeMetadataAttr>(
7542
+ extension, [&](CustomAttr *attr, NominalTypeDecl *attrDecl) {
7543
+ unavailableAttrs.insert (attrDecl);
7544
+ });
7545
+ }
7546
+
7547
+ for (auto *attr : attrRequirements) {
7548
+ auto *attrDecl = superclass->getRuntimeDiscoverableAttrTypeDecl (attr);
7549
+ if (attrs.count (attrDecl) || unavailableAttrs.count (attrDecl))
7550
+ continue ;
7551
+
7552
+ std::string attrName = attrDecl->getNameStr ().str ();
7553
+ std::string subclassName = typeDecl->getNameStr ().str ();
7554
+
7555
+ ctx.Diags .diagnose (
7556
+ typeDecl, diag::missing_reflection_metadata_attribute_on_subclass,
7557
+ superclass->getName (), attrName);
7558
+
7559
+ ctx.Diags
7560
+ .diagnose (typeDecl, diag::add_missing_reflection_metadata_attr,
7561
+ attrName)
7562
+ .fixItInsert (
7563
+ typeDecl->getAttributeInsertionLoc (/* forModifier=*/ false ),
7564
+ " @" + attrName + " " );
7565
+
7566
+ ctx.Diags
7567
+ .diagnose (typeDecl,
7568
+ diag::opt_out_from_missing_reflection_metadata_attr,
7569
+ attrName)
7570
+ .fixItInsertAfter (typeDecl->getEndLoc (),
7571
+ " \n\n @available(*, unavailable)\n @" + attrName +
7572
+ " extension " + subclassName + " {}\n " );
7573
+ }
7574
+ };
7575
+
7576
+ // Gather reflection metadata attributes only if this extension is:
7577
+ // - unavailable;
7578
+ // - unconstrained;
7579
+ // - declared in the same module as the extended type.
7580
+ if (auto *ED = dyn_cast<ExtensionDecl>(decl)) {
7581
+ if (!AvailableAttr::isUnavailable (ED))
7582
+ return copyAttrs (attrs);
7583
+
7584
+ if (ED->isConstrainedExtension () ||
7585
+ ED->getParentModule () != decl->getDeclContext ()->getParentModule ())
7586
+ return copyAttrs (attrs);
7587
+ }
7588
+
7479
7589
// First, gather all of the runtime attributes directly on the decl.
7480
7590
gatherRuntimeAttrsOnDecl (decl, attrs, GatheringMode::Direct);
7481
7591
7482
7592
auto *NTD = dyn_cast<NominalTypeDecl>(decl);
7483
- // Attribute inference is only possible from protocol conformances.
7484
- if (!NTD || isa<ProtocolDecl>(NTD) || NTD->getDeclContext ()->isLocalContext ())
7593
+ if (!NTD || NTD->getDeclContext ()->isLocalContext ())
7485
7594
return copyAttrs (attrs);
7486
7595
7596
+ // If this is a protocol, let's check whether superclass
7597
+ // has any reflection metadata attribute requirements.
7598
+ if (auto *protocol = dyn_cast<ProtocolDecl>(NTD)) {
7599
+ if (auto *superclass = protocol->getSuperclassDecl ())
7600
+ verifySuperclassAttrRequirements (NTD, superclass);
7601
+
7602
+ return copyAttrs (attrs);
7603
+ }
7604
+
7487
7605
// Gather any attributes inferred from (explicit) protocol conformances
7488
7606
// associated with the declaration of the type.
7489
7607
for (unsigned i : indices (NTD->getInherited ())) {
@@ -7501,5 +7619,47 @@ GetRuntimeDiscoverableAttributes::evaluate(Evaluator &evaluator,
7501
7619
gatherRuntimeAttrsOnDecl (protocol, attrs, GatheringMode::Inference);
7502
7620
}
7503
7621
7622
+ // Check superclass attribute requirements after inference.
7623
+ if (auto *classDecl = dyn_cast<ClassDecl>(NTD)) {
7624
+ if (auto *superclass = classDecl->getSuperclassDecl ())
7625
+ verifySuperclassAttrRequirements (NTD, superclass);
7626
+ }
7627
+
7504
7628
return copyAttrs (attrs);
7505
7629
}
7630
+
7631
+ void TypeChecker::checkReflectionMetadataAttributes (ExtensionDecl *ED) {
7632
+ auto &ctx = ED->getASTContext ();
7633
+ auto *extendedType = ED->getExtendedNominal ();
7634
+
7635
+ // If extension has any reflection metadata attributes, trigger the
7636
+ // request to set their types.
7637
+ for (auto *attr : ED->getRuntimeDiscoverableAttrs ()) {
7638
+ (void )evaluateOrDefault (
7639
+ ctx.evaluator ,
7640
+ CustomAttrTypeRequest{attr, ED->getDeclContext (),
7641
+ CustomAttrTypeKind::RuntimeMetadata},
7642
+ nullptr );
7643
+ }
7644
+
7645
+ for (auto *protocol : ED->getLocalProtocols ()) {
7646
+ forEachCustomAttribute<RuntimeMetadataAttr>(
7647
+ protocol, [&](CustomAttr *attr, NominalTypeDecl *attrType) {
7648
+ if (llvm::none_of (
7649
+ extendedType->getRuntimeDiscoverableAttrs (),
7650
+ [&](CustomAttr *typeAttr) {
7651
+ return extendedType->getRuntimeDiscoverableAttrTypeDecl (
7652
+ typeAttr) == attrType;
7653
+ })) {
7654
+ ctx.Diags .diagnose (ED->getLoc (), diag::type_does_not_conform,
7655
+ ED->getExtendedType (),
7656
+ protocol->getDeclaredInterfaceType ());
7657
+
7658
+ ctx.Diags .diagnose (
7659
+ ED->getLoc (),
7660
+ diag::missing_reflection_metadata_attribute_on_type,
7661
+ protocol->getName (), attrType->getNameStr ());
7662
+ }
7663
+ });
7664
+ }
7665
+ }
0 commit comments