Skip to content

Commit a02d9e9

Browse files
author
Karl Wagner
committed
Allow protocols to be nested in non-generic nominal types and functions
1 parent 4640f07 commit a02d9e9

File tree

9 files changed

+43
-14
lines changed

9 files changed

+43
-14
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2061,6 +2061,12 @@ ERROR(unsupported_type_nested_in_protocol_extension,none,
20612061
ERROR(unsupported_nested_protocol,none,
20622062
"protocol %0 cannot be nested inside another declaration",
20632063
(Identifier))
2064+
ERROR(unsupported_nested_protocol_in_generic_context,none,
2065+
"protocol %0 cannot be nested inside a generic context",
2066+
(Identifier))
2067+
ERROR(unsupported_nested_protocol_in_protocol,none,
2068+
"protocol %0 cannot be nested inside another protocol",
2069+
(Identifier))
20642070
ERROR(where_nongeneric_ctx,none,
20652071
"'where' clause on non-generic member declaration requires a "
20662072
"generic context", ())

include/swift/AST/TypeMemberVisitor.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ class TypeMemberVisitor : public DeclVisitor<ImplClass, RetTy> {
3737
}
3838
BAD_MEMBER(Extension)
3939
BAD_MEMBER(Import)
40-
BAD_MEMBER(Protocol)
4140
BAD_MEMBER(TopLevelCode)
4241
BAD_MEMBER(Operator)
4342
BAD_MEMBER(PrecedenceGroup)

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,9 @@ EXPERIMENTAL_FEATURE(ReferenceBindings, false)
208208
/// Enable the explicit 'import Builtin' and allow Builtin usage.
209209
EXPERIMENTAL_FEATURE(BuiltinModule, true)
210210

211+
/// Enable protocols to be nested in non-generic contexts.
212+
EXPERIMENTAL_FEATURE(NestedProtocols, false)
213+
211214
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
212215
#undef EXPERIMENTAL_FEATURE
213216
#undef UPCOMING_FEATURE

lib/AST/ASTPrinter.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3425,6 +3425,14 @@ static bool usesFeatureParameterPacks(Decl *decl) {
34253425
return false;
34263426
}
34273427

3428+
static bool usesFeatureNestedProtocols(Decl *decl) {
3429+
// TODO: How do I test this?
3430+
if (auto *protocolDecl = dyn_cast<ProtocolDecl>(decl)) {
3431+
return decl->getDeclContext()->getParent()->isTypeContext();
3432+
}
3433+
return false;
3434+
}
3435+
34283436
/// Suppress the printing of a particular feature.
34293437
static void suppressingFeature(PrintOptions &options, Feature feature,
34303438
llvm::function_ref<void()> action) {

lib/AST/Decl.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4765,11 +4765,8 @@ static Type computeNominalType(NominalTypeDecl *decl, DeclTypeKind kind) {
47654765
// If `decl` is a nested type, find the parent type.
47664766
Type ParentTy;
47674767
DeclContext *dc = decl->getDeclContext();
4768-
bool isObjCProtocol = isa<ProtocolDecl>(decl) && decl->hasClangNode();
47694768

4770-
// Objective-C protocols, unlike Swift protocols, could be nested
4771-
// in other types.
4772-
if ((isObjCProtocol || !isa<ProtocolDecl>(decl)) && dc->isTypeContext()) {
4769+
if (dc->isTypeContext()) {
47734770
switch (kind) {
47744771
case DeclTypeKind::DeclaredType: {
47754772
if (auto *nominal = dc->getSelfNominalTypeDecl())

lib/IRGen/GenDecl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5589,7 +5589,6 @@ void IRGenModule::emitNestedTypeDecls(DeclRange members) {
55895589
switch (member->getKind()) {
55905590
case DeclKind::Import:
55915591
case DeclKind::TopLevelCode:
5592-
case DeclKind::Protocol:
55935592
case DeclKind::Extension:
55945593
case DeclKind::InfixOperator:
55955594
case DeclKind::PrefixOperator:
@@ -5645,6 +5644,9 @@ void IRGenModule::emitNestedTypeDecls(DeclRange members) {
56455644
case DeclKind::Class:
56465645
emitClassDecl(cast<ClassDecl>(member));
56475646
continue;
5647+
case DeclKind::Protocol:
5648+
emitProtocolDecl(cast<ProtocolDecl>(member));
5649+
continue;
56485650
case DeclKind::MacroExpansion:
56495651
// Expansion already visited as auxiliary decls.
56505652
continue;

lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8961,7 +8961,7 @@ parseDeclProtocol(ParseDeclOptions Flags, DeclAttributes &Attributes) {
89618961
ProtocolDecl(CurDeclContext, ProtocolLoc, NameLoc, ProtocolName,
89628962
Context.AllocateCopy(PrimaryAssociatedTypeNames),
89638963
Context.AllocateCopy(InheritedProtocols), TrailingWhere);
8964-
// No need to setLocalDiscriminator: protocols can't appear in local contexts.
8964+
recordLocalType(Proto);
89658965

89668966
Proto->getAttrs() = Attributes;
89678967
if (whereClauseHadCodeCompletion && CodeCompletionCallbacks)

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2519,12 +2519,26 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
25192519
kind.getSelector());
25202520
}
25212521

2522-
// We don't support protocols outside the top level of a file.
2523-
if (isa<ProtocolDecl>(NTD) &&
2524-
!NTD->getParent()->isModuleScopeContext()) {
2525-
NTD->diagnose(diag::unsupported_nested_protocol, NTD->getName());
2526-
NTD->setInvalid();
2527-
return;
2522+
if (isa<ProtocolDecl>(NTD)) {
2523+
if (NTD->getASTContext().LangOpts.hasFeature(Feature::NestedProtocols)) {
2524+
// Protocols may only be nested in non-generic contexts.
2525+
if (NTD->getParent()->isGenericContext()) {
2526+
if (isa<ProtocolDecl>(NTD->getParent())) {
2527+
NTD->diagnose(diag::unsupported_nested_protocol_in_protocol, NTD->getName());
2528+
} else {
2529+
NTD->diagnose(diag::unsupported_nested_protocol_in_generic_context, NTD->getName());
2530+
}
2531+
NTD->setInvalid();
2532+
return;
2533+
}
2534+
} else {
2535+
// We don't support protocols outside the top level of a file.
2536+
if (!NTD->getParent()->isModuleScopeContext()) {
2537+
NTD->diagnose(diag::unsupported_nested_protocol, NTD->getName());
2538+
NTD->setInvalid();
2539+
return;
2540+
}
2541+
}
25282542
}
25292543

25302544
// We don't support nested types in protocols.

test/decl/nested/protocol.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ protocol OuterProtocol {
3131
struct ConformsToOuterProtocol : OuterProtocol {
3232
typealias Hen = Int
3333

34-
func f() { let _ = InnerProtocol.self } // expected-error {{use of protocol 'InnerProtocol' as a type must be written 'any InnerProtocol'}}
34+
func f() { let _ = InnerProtocol.self } // expected-error {{use of protocol 'OuterProtocol.InnerProtocol' as a type must be written 'any OuterProtocol.InnerProtocol'}}
3535
}
3636

3737
protocol Racoon {

0 commit comments

Comments
 (0)