Skip to content

Commit 7a81eb3

Browse files
authored
Merge pull request #63274 from xedin/runtime-metadata-impl-alignment
[AST/Sema] RuntimeMetadata: Align implementation with proposal
2 parents e41cdfb + a6a726e commit 7a81eb3

14 files changed

+345
-23
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,10 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
859859
return Attrs;
860860
}
861861

862+
/// Retrieve runtime discoverable attributes (if any) associated
863+
/// with this declaration.
864+
ArrayRef<CustomAttr *> getRuntimeDiscoverableAttrs() const;
865+
862866
/// Returns the semantic attributes attached to this declaration,
863867
/// including attributes that are generated as the result of member
864868
/// attribute macro expansion.
@@ -2851,9 +2855,6 @@ class ValueDecl : public Decl {
28512855
GenericParameterReferenceInfo findExistentialSelfReferences(
28522856
Type baseTy, bool treatNonResultCovariantSelfAsInvariant) const;
28532857

2854-
/// Retrieve runtime discoverable attributes (if any) associated
2855-
/// with this declaration.
2856-
ArrayRef<CustomAttr *> getRuntimeDiscoverableAttrs() const;
28572858
/// Retrieve a nominal type declaration backing given runtime discoverable
28582859
/// attribute.
28592860
///

include/swift/AST/DiagnosticsSema.def

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6917,6 +6917,14 @@ ERROR(invalid_decl_for_runtime_discoverable_attr,none,
69176917
"@%0 can only be applied to non-generic types, methods, "
69186918
"instance properties, and global functions", (StringRef))
69196919

6920+
ERROR(invalid_decl_for_runtime_discoverable_attr_in_extension,none,
6921+
"@%0 can only be applied to unavailable extensions in the same module"
6922+
" as %1", (StringRef, DeclName))
6923+
6924+
ERROR(invalid_attr_redeclaration_in_extension,none,
6925+
"@%0 is already applied to type %1; did you want to remove it?",
6926+
(StringRef, DeclName))
6927+
69206928
ERROR(duplicate_runtime_discoverable_attr,none,
69216929
"duplicate runtime discoverable attribute", ())
69226930

@@ -6934,6 +6942,26 @@ ERROR(runtime_attribute_type_requirement_not_accessible,none,
69346942
"(which is %select{private|fileprivate|internal|package|public|open}4)",
69356943
(AccessLevel, DescriptiveDeclKind, DeclName, Type, AccessLevel))
69366944

6945+
ERROR(cannot_use_attr_with_custom_arguments_on_protocol,none,
6946+
"reflection metadata attributes applied to protocols cannot have"
6947+
" additional attribute arguments; attribute arguments must be"
6948+
" explicitly written on the conforming type",
6949+
())
6950+
6951+
NOTE(missing_reflection_metadata_attribute_on_type,none,
6952+
"protocol %0 requires reflection metadata attribute @%1",
6953+
(DeclName, StringRef))
6954+
6955+
ERROR(missing_reflection_metadata_attribute_on_subclass,none,
6956+
"superclass %0 requires reflection metadata attribute @%1",
6957+
(DeclName, StringRef))
6958+
NOTE(add_missing_reflection_metadata_attr,none,
6959+
"add missing reflection metadata attribute @%0", (StringRef))
6960+
NOTE(opt_out_from_missing_reflection_metadata_attr,none,
6961+
"opt-out of reflection metadata attribute @%0 using"
6962+
" unavailable extension",
6963+
(StringRef))
6964+
69376965

69386966
#define UNDEFINE_DIAGNOSTIC_MACROS
69396967
#include "DefineDiagnosticMacros.h"

include/swift/AST/TypeCheckRequests.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3927,15 +3927,15 @@ class ExternalMacroDefinitionRequest
39273927

39283928
class GetRuntimeDiscoverableAttributes
39293929
: public SimpleRequest<GetRuntimeDiscoverableAttributes,
3930-
ArrayRef<CustomAttr *>(ValueDecl *),
3930+
ArrayRef<CustomAttr *>(Decl *),
39313931
RequestFlags::Cached> {
39323932
public:
39333933
using SimpleRequest::SimpleRequest;
39343934

39353935
private:
39363936
friend SimpleRequest;
39373937

3938-
ArrayRef<CustomAttr *> evaluate(Evaluator &evaluator, ValueDecl *decl) const;
3938+
ArrayRef<CustomAttr *> evaluate(Evaluator &evaluator, Decl *decl) const;
39393939

39403940
public:
39413941
bool isCached() const { return true; }

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ SWIFT_REQUEST(TypeChecker, SynthesizeRuntimeMetadataAttrGeneratorBody,
468468
BraceStmt *(CustomAttr *, ValueDecl *),
469469
Cached, NoLocationInfo)
470470
SWIFT_REQUEST(TypeChecker, GetRuntimeDiscoverableAttributes,
471-
ArrayRef<CustomAttr *>(ValueDecl *),
471+
ArrayRef<CustomAttr *>(Decl *),
472472
Cached, NoLocationInfo)
473473
SWIFT_REQUEST(TypeChecker, LocalDiscriminatorsRequest,
474474
unsigned(DeclContext *),

lib/AST/ASTPrinter.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1884,6 +1884,11 @@ bool isNonSendableExtension(const Decl *D) {
18841884
bool ShouldPrintChecker::shouldPrint(const Decl *D,
18851885
const PrintOptions &Options) {
18861886
if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
1887+
// Always print unavilable extensions that carry reflection
1888+
// metadata attributes.
1889+
if (!ED->getRuntimeDiscoverableAttrs().empty())
1890+
return true;
1891+
18871892
if (Options.printExtensionContentAsMembers(ED))
18881893
return false;
18891894
}
@@ -2975,12 +2980,6 @@ static bool usesFeatureTypeWrappers(Decl *decl) {
29752980
}
29762981

29772982
static bool usesFeatureRuntimeDiscoverableAttrs(Decl *decl) {
2978-
if (decl->getAttrs().hasAttribute<RuntimeMetadataAttr>())
2979-
return true;
2980-
2981-
if (auto *VD = dyn_cast<ValueDecl>(decl))
2982-
return !VD->getRuntimeDiscoverableAttrs().empty();
2983-
29842983
return false;
29852984
}
29862985

lib/AST/Decl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9888,8 +9888,8 @@ ValueDecl::getRuntimeDiscoverableAttrTypeDecl(CustomAttr *attr) const {
98889888
return nominal;
98899889
}
98909890

9891-
ArrayRef<CustomAttr *> ValueDecl::getRuntimeDiscoverableAttrs() const {
9892-
auto *mutableSelf = const_cast<ValueDecl *>(this);
9891+
ArrayRef<CustomAttr *> Decl::getRuntimeDiscoverableAttrs() const {
9892+
auto *mutableSelf = const_cast<Decl *>(this);
98939893
return evaluateOrDefault(getASTContext().evaluator,
98949894
GetRuntimeDiscoverableAttributes{mutableSelf},
98959895
nullptr);

lib/Sema/TypeCheckAttr.cpp

Lines changed: 167 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3689,6 +3689,10 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
36893689
case DeclKind::Protocol: {
36903690
// Allow on protocols because they are sources
36913691
// of inference.
3692+
if (attr->hasArgs()) {
3693+
diagnoseAndRemoveAttr(
3694+
attr, diag::cannot_use_attr_with_custom_arguments_on_protocol);
3695+
}
36923696
return;
36933697
}
36943698

@@ -3715,6 +3719,40 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
37153719
return;
37163720
}
37173721

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+
37183756
default:
37193757
// All other kinds of declarations i.e. subscripts, constructors etc.
37203758
// are unsupported.
@@ -7111,7 +7149,16 @@ void AttributeChecker::visitCompilerInitializedAttr(
71117149
}
71127150

71137151
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()) {
71157162
diagnose(attr->getLocation(),
71167163
diag::runtime_discoverable_attrs_are_experimental);
71177164
attr->setInvalid();
@@ -7415,7 +7462,7 @@ ValueDecl *RenamedDeclRequest::evaluate(Evaluator &evaluator,
74157462

74167463
template <typename ATTR>
74177464
static void forEachCustomAttribute(
7418-
ValueDecl *decl,
7465+
Decl *decl,
74197466
llvm::function_ref<void(CustomAttr *attr, NominalTypeDecl *)> fn) {
74207467
auto &ctx = decl->getASTContext();
74217468

@@ -7425,7 +7472,6 @@ static void forEachCustomAttribute(
74257472
auto *nominal = evaluateOrDefault(
74267473
ctx.evaluator,
74277474
CustomAttrNominalRequest{mutableAttr, decl->getDeclContext()}, nullptr);
7428-
74297475
if (!nominal)
74307476
continue;
74317477

@@ -7436,15 +7482,15 @@ static void forEachCustomAttribute(
74367482

74377483
ArrayRef<CustomAttr *>
74387484
GetRuntimeDiscoverableAttributes::evaluate(Evaluator &evaluator,
7439-
ValueDecl *decl) const {
7485+
Decl *decl) const {
74407486
auto &ctx = decl->getASTContext();
74417487

74427488
llvm::SmallMapVector<NominalTypeDecl *, CustomAttr *, 4> attrs;
74437489

74447490
enum class GatheringMode { Direct, Inference };
74457491

74467492
auto gatherRuntimeAttrsOnDecl =
7447-
[&](ValueDecl *decl,
7493+
[&](Decl *decl,
74487494
llvm::SmallMapVector<NominalTypeDecl *, CustomAttr *, 4> &attrs,
74497495
GatheringMode mode) {
74507496
forEachCustomAttribute<RuntimeMetadataAttr>(
@@ -7476,14 +7522,86 @@ GetRuntimeDiscoverableAttributes::evaluate(Evaluator &evaluator,
74767522
return copy;
74777523
};
74787524

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+
74797589
// First, gather all of the runtime attributes directly on the decl.
74807590
gatherRuntimeAttrsOnDecl(decl, attrs, GatheringMode::Direct);
74817591

74827592
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())
74857594
return copyAttrs(attrs);
74867595

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+
74877605
// Gather any attributes inferred from (explicit) protocol conformances
74887606
// associated with the declaration of the type.
74897607
for (unsigned i : indices(NTD->getInherited())) {
@@ -7501,5 +7619,47 @@ GetRuntimeDiscoverableAttributes::evaluate(Evaluator &evaluator,
75017619
gatherRuntimeAttrsOnDecl(protocol, attrs, GatheringMode::Inference);
75027620
}
75037621

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+
75047628
return copyAttrs(attrs);
75057629
}
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+
}

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3360,6 +3360,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
33603360
ED->diagnose(diag::moveonly_cannot_conform_to_protocol,
33613361
nominal->getDescriptiveKind(), nominal->getBaseName());
33623362
}
3363+
3364+
TypeChecker::checkReflectionMetadataAttributes(ED);
33633365
}
33643366

33653367
void visitTopLevelCodeDecl(TopLevelCodeDecl *TLCD) {

lib/Sema/TypeChecker.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,11 @@ bool diagnoseInvalidFunctionType(FunctionType *fnTy, SourceLoc loc,
12961296
/// type repr. \param inferredType The type inferred by the type checker.
12971297
void notePlaceholderReplacementTypes(Type writtenType, Type inferredType);
12981298

1299+
/// Check whether the given extension introduces a conformance
1300+
/// to a protocol annotated with reflection metadata attribute(s).
1301+
/// If that's the case, conforming type supposed to match attribute
1302+
/// requirements.
1303+
void checkReflectionMetadataAttributes(ExtensionDecl *extension);
12991304
} // namespace TypeChecker
13001305

13011306
/// Returns the protocol requirement kind of the given declaration.

0 commit comments

Comments
 (0)