@@ -92,10 +92,6 @@ static bool canDeriveConformance(TypeChecker &tc, DeclContext *DC,
92
92
ProtocolDecl *protocol) {
93
93
// The type must be an enum or a struct.
94
94
if (auto enumDecl = dyn_cast<EnumDecl>(target)) {
95
- // The enum must have cases.
96
- if (!enumDecl->hasCases ())
97
- return false ;
98
-
99
95
// The cases must not have associated values, or all associated values must
100
96
// conform to the protocol.
101
97
return allAssociatedValuesConformToProtocol (tc, DC, enumDecl, protocol);
@@ -320,6 +316,34 @@ static GuardStmt *returnIfNotEqualGuard(ASTContext &C,
320
316
return new (C) GuardStmt (SourceLoc (), C.AllocateCopy (conditions), body);
321
317
}
322
318
319
+ static void
320
+ deriveBodyEquatable_enum_uninhabited_eq (AbstractFunctionDecl *eqDecl) {
321
+ auto parentDC = eqDecl->getDeclContext ();
322
+ ASTContext &C = parentDC->getASTContext ();
323
+
324
+ auto args = eqDecl->getParameterLists ().back ();
325
+ auto aParam = args->get (0 );
326
+ auto bParam = args->get (1 );
327
+
328
+ assert (!cast<EnumDecl>(aParam->getType ()->getAnyNominal ())->hasCases ());
329
+
330
+ SmallVector<ASTNode, 1 > statements;
331
+ SmallVector<ASTNode, 0 > cases;
332
+
333
+ // switch (a, b) { }
334
+ auto aRef = new (C) DeclRefExpr (aParam, DeclNameLoc (), /* implicit*/ true );
335
+ auto bRef = new (C) DeclRefExpr (bParam, DeclNameLoc (), /* implicit*/ true );
336
+ auto abExpr = TupleExpr::create (C, SourceLoc (), {aRef, bRef}, {}, {},
337
+ SourceLoc (), /* HasTrailingClosure*/ false ,
338
+ /* implicit*/ true );
339
+ auto switchStmt = SwitchStmt::create (LabeledStmtInfo (), SourceLoc (), abExpr,
340
+ SourceLoc (), cases, SourceLoc (), C);
341
+ statements.push_back (switchStmt);
342
+
343
+ auto body = BraceStmt::create (C, SourceLoc (), statements, SourceLoc ());
344
+ eqDecl->setBody (body);
345
+ }
346
+
323
347
// / Derive the body for an '==' operator for an enum that has no associated
324
348
// / values. This generates code that converts each value to its integer ordinal
325
349
// / and compares them, which produces an optimal single icmp instruction.
@@ -689,11 +713,13 @@ ValueDecl *DerivedConformance::deriveEquatable(ValueDecl *requirement) {
689
713
690
714
// Build the necessary decl.
691
715
if (requirement->getBaseName () == " ==" ) {
692
- if (auto ED = dyn_cast<EnumDecl>(Nominal)) {
716
+ if (auto ed = dyn_cast<EnumDecl>(Nominal)) {
693
717
auto bodySynthesizer =
694
- ED->hasOnlyCasesWithoutAssociatedValues ()
695
- ? &deriveBodyEquatable_enum_noAssociatedValues_eq
696
- : &deriveBodyEquatable_enum_hasAssociatedValues_eq;
718
+ !ed->hasCases ()
719
+ ? &deriveBodyEquatable_enum_uninhabited_eq
720
+ : ed->hasOnlyCasesWithoutAssociatedValues ()
721
+ ? &deriveBodyEquatable_enum_noAssociatedValues_eq
722
+ : &deriveBodyEquatable_enum_hasAssociatedValues_eq;
697
723
return deriveEquatable_eq (*this , TC.Context .Id_derived_enum_equals ,
698
724
bodySynthesizer);
699
725
} else if (isa<StructDecl>(Nominal))
0 commit comments