Skip to content

Commit 91e07e9

Browse files
authored
Merge pull request #16439 from huonw/same-file-extension-restructure-4.2
[4.2] Allow synthesis of conformances in same-file extensions.
2 parents 71bee0e + 817a7d5 commit 91e07e9

34 files changed

+1696
-765
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2162,8 +2162,17 @@ NOTE(construct_raw_representable_from_unwrapped_value,none,
21622162
"construct %0 from unwrapped %1 value", (Type, Type))
21632163

21642164
// Derived conformances
2165-
ERROR(cannot_synthesize_in_extension,none,
2166-
"implementation of %0 cannot be automatically synthesized in an extension", (Type))
2165+
ERROR(swift3_cannot_synthesize_in_extension,none,
2166+
"implementation of %0 cannot be automatically synthesized in an extension "
2167+
"in Swift 3", (Type))
2168+
ERROR(cannot_synthesize_init_in_extension_of_nonfinal,none,
2169+
"implementation of %0 for non-final class cannot be automatically "
2170+
"synthesized in extension because initializer requirement %1 can only be "
2171+
"be satisfied by a 'required' initializer in the class definition",
2172+
(Type, DeclName))
2173+
ERROR(cannot_synthesize_in_crossfile_extension,none,
2174+
"implementation of %0 cannot be automatically synthesized in an extension "
2175+
"in a different file to the type", (Type))
21672176

21682177
ERROR(broken_case_iterable_requirement,none,
21692178
"CaseIterable protocol is broken: unexpected requirement", ())

lib/Sema/DerivedConformanceCaseIterable.cpp

Lines changed: 22 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
#include "DerivedConformances.h"
2323

2424
using namespace swift;
25-
using namespace DerivedConformance;
2625

2726
/// Common preconditions for CaseIterable.
2827
static bool canDeriveConformance(NominalTypeDecl *type) {
@@ -43,7 +42,7 @@ static bool canDeriveConformance(NominalTypeDecl *type) {
4342
void deriveCaseIterable_enum_getter(AbstractFunctionDecl *funcDecl) {
4443
auto *parentDC = funcDecl->getDeclContext();
4544
auto *parentEnum = parentDC->getAsEnumOrEnumExtensionContext();
46-
auto enumTy = parentEnum->getDeclaredTypeInContext();
45+
auto enumTy = parentDC->getDeclaredTypeInContext();
4746
auto &C = parentDC->getASTContext();
4847

4948
SmallVector<Expr *, 8> elExprs;
@@ -69,96 +68,69 @@ static ArraySliceType *computeAllCasesType(NominalTypeDecl *enumType) {
6968
return ArraySliceType::get(metaTy->getRValueInstanceType());
7069
}
7170

72-
static Type deriveCaseIterable_AllCases(TypeChecker &tc, Decl *parentDecl,
73-
EnumDecl *enumDecl) {
71+
static Type deriveCaseIterable_AllCases(DerivedConformance &derived) {
7472
// enum SomeEnum : CaseIterable {
7573
// @derived
7674
// typealias AllCases = [SomeEnum]
7775
// }
78-
auto *rawInterfaceType = computeAllCasesType(enumDecl);
79-
return cast<DeclContext>(parentDecl)->mapTypeIntoContext(rawInterfaceType);
76+
auto *rawInterfaceType = computeAllCasesType(cast<EnumDecl>(derived.Nominal));
77+
return derived.getConformanceContext()->mapTypeIntoContext(rawInterfaceType);
8078
}
8179

82-
ValueDecl *DerivedConformance::deriveCaseIterable(TypeChecker &tc,
83-
Decl *parentDecl,
84-
NominalTypeDecl *targetDecl,
85-
ValueDecl *requirement) {
80+
ValueDecl *DerivedConformance::deriveCaseIterable(ValueDecl *requirement) {
8681
// Conformance can't be synthesized in an extension.
87-
auto caseIterableProto
88-
= tc.Context.getProtocol(KnownProtocolKind::CaseIterable);
89-
auto caseIterableType = caseIterableProto->getDeclaredType();
90-
if (targetDecl != parentDecl) {
91-
tc.diagnose(parentDecl->getLoc(), diag::cannot_synthesize_in_extension,
92-
caseIterableType);
82+
if (checkAndDiagnoseDisallowedContext(requirement))
9383
return nullptr;
94-
}
9584

9685
// Check that we can actually derive CaseIterable for this type.
97-
if (!canDeriveConformance(targetDecl))
86+
if (!canDeriveConformance(Nominal))
9887
return nullptr;
9988

10089
// Build the necessary decl.
101-
if (requirement->getBaseName() != tc.Context.Id_allCases) {
102-
tc.diagnose(requirement->getLoc(),
103-
diag::broken_case_iterable_requirement);
90+
if (requirement->getBaseName() != TC.Context.Id_allCases) {
91+
TC.diagnose(requirement->getLoc(), diag::broken_case_iterable_requirement);
10492
return nullptr;
10593
}
10694

107-
auto enumDecl = cast<EnumDecl>(targetDecl);
108-
ASTContext &C = tc.Context;
109-
95+
ASTContext &C = TC.Context;
11096

11197
// Define the property.
112-
auto *returnTy = computeAllCasesType(targetDecl);
98+
auto *returnTy = computeAllCasesType(Nominal);
11399

114100
VarDecl *propDecl;
115101
PatternBindingDecl *pbDecl;
116-
std::tie(propDecl, pbDecl)
117-
= declareDerivedProperty(tc, parentDecl, enumDecl, C.Id_allCases,
118-
returnTy, returnTy,
102+
std::tie(propDecl, pbDecl) =
103+
declareDerivedProperty(C.Id_allCases, returnTy, returnTy,
119104
/*isStatic=*/true, /*isFinal=*/true);
120105

121106
// Define the getter.
122-
auto *getterDecl = addGetterToReadOnlyDerivedProperty(tc, propDecl, returnTy);
107+
auto *getterDecl = addGetterToReadOnlyDerivedProperty(TC, propDecl, returnTy);
123108

124109
getterDecl->setBodySynthesizer(&deriveCaseIterable_enum_getter);
125110

126-
auto dc = cast<IterableDeclContext>(parentDecl);
127-
dc->addMember(getterDecl);
128-
dc->addMember(propDecl);
129-
dc->addMember(pbDecl);
111+
addMembersToConformanceContext({getterDecl, propDecl, pbDecl});
130112

131113
return propDecl;
132114
}
133115

134-
Type DerivedConformance::deriveCaseIterable(TypeChecker &tc, Decl *parentDecl,
135-
NominalTypeDecl *targetDecl,
136-
AssociatedTypeDecl *assocType) {
137-
// Conformance can't be synthesized in an extension.
138-
auto caseIterableProto
139-
= tc.Context.getProtocol(KnownProtocolKind::CaseIterable);
140-
auto caseIterableType = caseIterableProto->getDeclaredType();
141-
if (targetDecl != parentDecl) {
142-
tc.diagnose(parentDecl->getLoc(), diag::cannot_synthesize_in_extension,
143-
caseIterableType);
116+
Type DerivedConformance::deriveCaseIterable(AssociatedTypeDecl *assocType) {
117+
if (checkAndDiagnoseDisallowedContext(assocType))
144118
return nullptr;
145-
}
146119

147120
// We can only synthesize CaseIterable for enums.
148-
auto enumDecl = dyn_cast<EnumDecl>(targetDecl);
121+
auto enumDecl = dyn_cast<EnumDecl>(Nominal);
149122
if (!enumDecl)
150123
return nullptr;
151124

152125
// Check that we can actually derive CaseIterable for this type.
153-
if (!canDeriveConformance(targetDecl))
126+
if (!canDeriveConformance(Nominal))
154127
return nullptr;
155128

156-
if (assocType->getName() == tc.Context.Id_AllCases) {
157-
return deriveCaseIterable_AllCases(tc, parentDecl, enumDecl);
129+
if (assocType->getName() == TC.Context.Id_AllCases) {
130+
return deriveCaseIterable_AllCases(*this);
158131
}
159132

160-
tc.diagnose(assocType->getLoc(),
161-
diag::broken_case_iterable_requirement);
133+
TC.diagnose(assocType->getLoc(), diag::broken_case_iterable_requirement);
162134
return nullptr;
163135
}
164136

0 commit comments

Comments
 (0)