Skip to content

Commit ec3534b

Browse files
committed
[Sema] RuntimeMetadata: Make reflection metadata attribute a conformance requirement
If conforming type doesn't declare required set of reflection metadata attributes (based on the protocol declaration) fail conformance via extension.
1 parent ffd5d96 commit ec3534b

File tree

5 files changed

+70
-1
lines changed

5 files changed

+70
-1
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6945,6 +6945,10 @@ ERROR(cannot_use_attr_with_custom_arguments_on_protocol,none,
69456945
" explicitly written on the conforming type",
69466946
())
69476947

6948+
NOTE(missing_reflection_metadata_attribute_on_type,none,
6949+
"protocol %0 requires reflection metadata attribute @%1",
6950+
(DeclName, StringRef))
6951+
69486952
#define UNDEFINE_DIAGNOSTIC_MACROS
69496953
#include "DefineDiagnosticMacros.h"
69506954

lib/Sema/TypeCheckAttr.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7541,3 +7541,29 @@ GetRuntimeDiscoverableAttributes::evaluate(Evaluator &evaluator,
75417541

75427542
return copyAttrs(attrs);
75437543
}
7544+
7545+
void TypeChecker::checkReflectionMetadataAttributes(ExtensionDecl *ED) {
7546+
auto *extendedType = ED->getExtendedNominal();
7547+
7548+
for (auto *protocol : ED->getLocalProtocols()) {
7549+
forEachCustomAttribute<RuntimeMetadataAttr>(
7550+
protocol, [&](CustomAttr *attr, NominalTypeDecl *attrType) {
7551+
if (llvm::none_of(
7552+
extendedType->getRuntimeDiscoverableAttrs(),
7553+
[&](CustomAttr *typeAttr) {
7554+
return extendedType->getRuntimeDiscoverableAttrTypeDecl(
7555+
typeAttr) == attrType;
7556+
})) {
7557+
auto &ctx = protocol->getASTContext();
7558+
ctx.Diags.diagnose(ED->getLoc(), diag::type_does_not_conform,
7559+
ED->getExtendedType(),
7560+
protocol->getDeclaredInterfaceType());
7561+
7562+
ctx.Diags.diagnose(
7563+
ED->getLoc(),
7564+
diag::missing_reflection_metadata_attribute_on_type,
7565+
protocol->getName(), attrType->getNameStr());
7566+
}
7567+
});
7568+
}
7569+
}

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.

test/type/runtime_discoverable_attrs.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ struct TestNoAmbiguity {
133133
@Flag
134134
protocol Flagged {}
135135

136+
@Flag
137+
protocol OtherFlagged {}
138+
136139
@Flag("flag from protocol") // expected-error {{reflection metadata attributes applied to protocols cannot have additional attribute arguments}}
137140
protocol InvalidFlagged {}
138141

@@ -249,6 +252,9 @@ enum EnumFlag<B, V> {
249252
case function(() -> V)
250253
}
251254

255+
@EnumFlag
256+
protocol EnumFlagged {}
257+
252258
extension EnumFlag {
253259
init(attachedTo: KeyPath<B, V>) { self = .property(attachedTo) }
254260
init(attachedTo: @escaping (B) -> V) { self = .method(attachedTo) }
@@ -280,9 +286,35 @@ extension EnumFlag where B == Void {
280286
}
281287

282288
@available(*, unavailable)
283-
@EnumFlag extension EnumTypeTest { // expected-error {{@EnumFlag is already applied to type 'EnumTypeTest'; did you want to remove it?}} {{269:1-11=}}
289+
@EnumFlag extension EnumTypeTest { // expected-error {{@EnumFlag is already applied to type 'EnumTypeTest'; did you want to remove it?}} {{275:1-11=}}
284290
}
285291

286292
@available(*, unavailable)
287293
@Flag extension CrossModuleTest { // expected-error {{@Flag can only be applied to unavailable extensions in the same module as 'CrossModuleTest'}}
288294
}
295+
296+
struct InvalidConformanceTest1 {}
297+
struct InvalidConformanceTest2 {}
298+
299+
extension InvalidConformanceTest1 : Flagged {} // expected-error {{type 'InvalidConformanceTest1' does not conform to protocol 'Flagged'}}
300+
// expected-note@-1 {{protocol 'Flagged' requires reflection metadata attribute @Flag}}
301+
302+
extension InvalidConformanceTest2 : Flagged & EnumFlagged {}
303+
// expected-error@-1 {{type 'InvalidConformanceTest2' does not conform to protocol 'Flagged'}}
304+
// expected-error@-2 {{type 'InvalidConformanceTest2' does not conform to protocol 'EnumFlagged'}}
305+
// expected-note@-3 {{protocol 'Flagged' requires reflection metadata attribute @Flag}}
306+
// expected-note@-4 {{protocol 'EnumFlagged' requires reflection metadata attribute @EnumFlag}}
307+
308+
@Flag
309+
struct ValidConformance1 {}
310+
extension ValidConformance1 : Flagged {} // Ok
311+
312+
struct ValidConformance2 : Flagged {}
313+
extension ValidConformance2 : OtherFlagged {} // Ok (@Flag is inferred from Flagged protocol conformance)
314+
315+
@EnumFlag @Flag
316+
class MultiAttrTest {
317+
init() {}
318+
}
319+
320+
extension MultiAttrTest : Flagged & EnumFlagged {} // Ok

0 commit comments

Comments
 (0)