Skip to content

Commit a98a35e

Browse files
committed
[Sema] RuntimeMetadata: Verify that runtime attribute has a valid initializer
1 parent 5a1f197 commit a98a35e

File tree

3 files changed

+107
-8
lines changed

3 files changed

+107
-8
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6810,6 +6810,21 @@ ERROR(invalid_decl_for_runtime_discoverable_attr,none,
68106810
ERROR(duplicate_runtime_discoverable_attr,none,
68116811
"duplicate runtime discoverable attribute", ())
68126812

6813+
ERROR(runtime_attribute_requires_init,none,
6814+
"runtime attribute type %0 does not contain a required initializer"
6815+
" - init(attachedTo:)",
6816+
(DeclName))
6817+
6818+
ERROR(runtime_attribute_type_failable_init,none,
6819+
"runtime attribute type initializer %0 cannot be failable", (DeclName))
6820+
6821+
ERROR(runtime_attribute_type_requirement_not_accessible,none,
6822+
"%select{private|fileprivate|internal|public|open}0 %1 %2 cannot have "
6823+
"more restrictive access than its enclosing runtime attribute type %3 "
6824+
"(which is %select{private|fileprivate|internal|public|open}4)",
6825+
(AccessLevel, DescriptiveDeclKind, DeclName, Type, AccessLevel))
6826+
6827+
68136828
#define UNDEFINE_DIAGNOSTIC_MACROS
68146829
#include "DefineDiagnosticMacros.h"
68156830

lib/Sema/TypeCheckAttr.cpp

Lines changed: 75 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3806,6 +3806,11 @@ void AttributeChecker::visitCustomAttr(CustomAttr *attr) {
38063806
attr->setInvalid();
38073807
}
38083808

3809+
static bool isMemberLessAccessibleThanType(NominalTypeDecl *typeDecl,
3810+
ValueDecl *member) {
3811+
return member->getFormalAccess() <
3812+
std::min(typeDecl->getFormalAccess(), AccessLevel::Public);
3813+
}
38093814

38103815
void AttributeChecker::visitPropertyWrapperAttr(PropertyWrapperAttr *attr) {
38113816
auto nominal = dyn_cast<NominalTypeDecl>(D);
@@ -3829,11 +3834,6 @@ void AttributeChecker::visitTypeWrapperAttr(TypeWrapperAttr *attr) {
38293834

38303835
auto &ctx = D->getASTContext();
38313836

3832-
auto isLessAccessibleThanType = [&](ValueDecl *decl) {
3833-
return decl->getFormalAccess() <
3834-
std::min(nominal->getFormalAccess(), AccessLevel::Public);
3835-
};
3836-
38373837
enum class UnviabilityReason {
38383838
Failable,
38393839
InvalidWrappedSelfType,
@@ -3891,7 +3891,7 @@ void AttributeChecker::visitTypeWrapperAttr(TypeWrapperAttr *attr) {
38913891
if (init->isFailable())
38923892
nonViableInits[init].push_back(UnviabilityReason::Failable);
38933893

3894-
if (isLessAccessibleThanType(init))
3894+
if (isMemberLessAccessibleThanType(nominal, init))
38953895
nonViableInits[init].push_back(UnviabilityReason::Inaccessible);
38963896
}
38973897

@@ -4112,7 +4112,7 @@ void AttributeChecker::visitTypeWrapperAttr(TypeWrapperAttr *attr) {
41124112
UnviabilityReason::InvalidStorageType);
41134113
}
41144114

4115-
if (isLessAccessibleThanType(subscript))
4115+
if (isMemberLessAccessibleThanType(nominal, subscript))
41164116
nonViableSubscripts[subscript].push_back(
41174117
UnviabilityReason::Inaccessible);
41184118
}
@@ -4198,7 +4198,7 @@ void AttributeChecker::visitTypeWrapperAttr(TypeWrapperAttr *attr) {
41984198
if (!hasKeyPathType(storageKeyPathParam))
41994199
diagnoseSubscript(subscript, UnviabilityReason::InvalidStorageType);
42004200

4201-
if (isLessAccessibleThanType(subscript))
4201+
if (isMemberLessAccessibleThanType(nominal, subscript))
42024202
diagnoseSubscript(subscript, UnviabilityReason::Inaccessible);
42034203
}
42044204
}
@@ -7028,6 +7028,73 @@ void AttributeChecker::visitRuntimeMetadataAttr(RuntimeMetadataAttr *attr) {
70287028
attr->setInvalid();
70297029
return;
70307030
}
7031+
7032+
auto nominal = dyn_cast<NominalTypeDecl>(D);
7033+
if (!nominal)
7034+
return;
7035+
7036+
enum class UnviabilityReason { Failable, Inaccessible };
7037+
7038+
llvm::SmallVector<ConstructorDecl *, 2> matchingInits;
7039+
llvm::SmallDenseMap<ConstructorDecl *, SmallVector<UnviabilityReason, 2>, 2>
7040+
nonViableInits;
7041+
7042+
// Check whether type marked as runtime attribute capable has an initializer
7043+
// with first parameter labeled as `attachedTo:`.
7044+
for (auto *member : nominal->getMembers()) {
7045+
auto *init = dyn_cast<ConstructorDecl>(member);
7046+
if (!init)
7047+
continue;
7048+
7049+
auto *params = init->getParameters();
7050+
if (!params || params->size() == 0)
7051+
continue;
7052+
7053+
if (params->get(0)->getArgumentName() != Ctx.Id_attachedTo)
7054+
continue;
7055+
7056+
matchingInits.push_back(init);
7057+
7058+
if (init->isFailable())
7059+
nonViableInits[init].push_back(UnviabilityReason::Failable);
7060+
7061+
if (isMemberLessAccessibleThanType(nominal, init))
7062+
nonViableInits[init].push_back(UnviabilityReason::Inaccessible);
7063+
}
7064+
7065+
// If there are no matching initializers, let's complain.
7066+
if (matchingInits.empty()) {
7067+
diagnose(nominal->getLoc(), diag::runtime_attribute_requires_init,
7068+
nominal->getName());
7069+
attr->setInvalid();
7070+
return;
7071+
}
7072+
7073+
// If there are matching initializers but none of them are viable.
7074+
if (matchingInits.size() - nonViableInits.size() == 0) {
7075+
for (const auto &entry : nonViableInits) {
7076+
auto *init = entry.first;
7077+
7078+
for (auto reason : entry.second) {
7079+
switch (reason) {
7080+
case UnviabilityReason::Failable:
7081+
diagnose(init, diag::runtime_attribute_type_failable_init,
7082+
init->getName());
7083+
break;
7084+
7085+
case UnviabilityReason::Inaccessible:
7086+
diagnose(init,
7087+
diag::runtime_attribute_type_requirement_not_accessible,
7088+
init->getFormalAccess(), init->getDescriptiveKind(),
7089+
init->getName(), nominal->getDeclaredType(),
7090+
nominal->getFormalAccess());
7091+
break;
7092+
}
7093+
}
7094+
}
7095+
7096+
attr->setInvalid();
7097+
}
70317098
}
70327099

70337100
namespace {

test/type/runtime_discoverable_attrs.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,23 @@ struct OnlyPropsTest<B, V> {
1414
init(attachedTo: KeyPath<B, V>) {}
1515
}
1616

17+
@runtimeMetadata
18+
struct NoInitAttr { // expected-error {{runtime attribute type 'NoInitAttr' does not contain a required initializer - init(attachedTo:)}}
19+
}
20+
21+
@runtimeMetadata
22+
struct FailiableInit {
23+
init?(attachedTo: Any) {} // expected-error {{runtime attribute type initializer 'init(attachedTo:)' cannot be failable}}
24+
}
25+
26+
@runtimeMetadata
27+
public struct AccessMismatchInAttr {
28+
private init(attachedTo: Any) {}
29+
// expected-error@-1 {{private initializer 'init(attachedTo:)' cannot have more restrictive access than its enclosing runtime attribute type 'AccessMismatchInAttr' (which is public)}}
30+
internal init<T>(attachedTo: T.Type, other: Int) {}
31+
// expected-error@-1 {{internal initializer 'init(attachedTo:other:)' cannot have more restrictive access than its enclosing runtime attribute type 'AccessMismatchInAttr' (which is public)}}
32+
}
33+
1734
@Flag("global") func gloabalFn() {}
1835

1936
@runtimeMetadata

0 commit comments

Comments
 (0)