@@ -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);
@@ -304,6 +300,34 @@ static GuardStmt *returnIfNotEqualGuard(ASTContext &C,
304
300
return new (C) GuardStmt (SourceLoc (), C.AllocateCopy (conditions), body);
305
301
}
306
302
303
+ static void
304
+ deriveBodyEquatable_enum_uninhabited_eq (AbstractFunctionDecl *eqDecl) {
305
+ auto parentDC = eqDecl->getDeclContext ();
306
+ ASTContext &C = parentDC->getASTContext ();
307
+
308
+ auto args = eqDecl->getParameterLists ().back ();
309
+ auto aParam = args->get (0 );
310
+ auto bParam = args->get (1 );
311
+
312
+ assert (!cast<EnumDecl>(aParam->getType ()->getAnyNominal ())->hasCases ());
313
+
314
+ SmallVector<ASTNode, 1 > statements;
315
+ SmallVector<ASTNode, 0 > cases;
316
+
317
+ // switch (a, b) { }
318
+ auto aRef = new (C) DeclRefExpr (aParam, DeclNameLoc (), /* implicit*/ true );
319
+ auto bRef = new (C) DeclRefExpr (bParam, DeclNameLoc (), /* implicit*/ true );
320
+ auto abExpr = TupleExpr::create (C, SourceLoc (), {aRef, bRef}, {}, {},
321
+ SourceLoc (), /* HasTrailingClosure*/ false ,
322
+ /* implicit*/ true );
323
+ auto switchStmt = SwitchStmt::create (LabeledStmtInfo (), SourceLoc (), abExpr,
324
+ SourceLoc (), cases, SourceLoc (), C);
325
+ statements.push_back (switchStmt);
326
+
327
+ auto body = BraceStmt::create (C, SourceLoc (), statements, SourceLoc ());
328
+ eqDecl->setBody (body);
329
+ }
330
+
307
331
// / Derive the body for an '==' operator for an enum that has no associated
308
332
// / values. This generates code that converts each value to its integer ordinal
309
333
// / and compares them, which produces an optimal single icmp instruction.
@@ -673,11 +697,13 @@ ValueDecl *DerivedConformance::deriveEquatable(ValueDecl *requirement) {
673
697
674
698
// Build the necessary decl.
675
699
if (requirement->getBaseName () == " ==" ) {
676
- if (auto ED = dyn_cast<EnumDecl>(Nominal)) {
700
+ if (auto ed = dyn_cast<EnumDecl>(Nominal)) {
677
701
auto bodySynthesizer =
678
- ED->hasOnlyCasesWithoutAssociatedValues ()
679
- ? &deriveBodyEquatable_enum_noAssociatedValues_eq
680
- : &deriveBodyEquatable_enum_hasAssociatedValues_eq;
702
+ !ed->hasCases ()
703
+ ? &deriveBodyEquatable_enum_uninhabited_eq
704
+ : ed->hasOnlyCasesWithoutAssociatedValues ()
705
+ ? &deriveBodyEquatable_enum_noAssociatedValues_eq
706
+ : &deriveBodyEquatable_enum_hasAssociatedValues_eq;
681
707
return deriveEquatable_eq (*this , TC.Context .Id_derived_enum_equals ,
682
708
bodySynthesizer);
683
709
} else if (isa<StructDecl>(Nominal))
0 commit comments