@@ -193,6 +193,20 @@ enumElementPayloadSubpattern(EnumElementDecl *enumElementDecl,
193
193
return pat;
194
194
}
195
195
196
+ // / Returns a new integer literal expression with the given value.
197
+ // / \p C The AST context.
198
+ // / \p value The integer value.
199
+ // / \return The integer literal expression.
200
+ static Expr *integerLiteralExpr (ASTContext &C, int64_t value) {
201
+ llvm::SmallString<8 > integerVal;
202
+ APInt (32 , value).toString (integerVal, 10 , /* signed*/ false );
203
+ auto integerStr = C.AllocateCopy (integerVal);
204
+ auto integerExpr = new (C) IntegerLiteralExpr (
205
+ StringRef (integerStr.data (), integerStr.size ()), SourceLoc (),
206
+ /* implicit*/ true );
207
+ return integerExpr;
208
+ }
209
+
196
210
// / Create AST statements which convert from an enum to an Int with a switch.
197
211
// / \p stmts The generated statements are appended to this vector.
198
212
// / \p parentDC Either an extension or the enum itself.
@@ -240,13 +254,7 @@ static DeclRefExpr *convertEnumToIndex(SmallVectorImpl<ASTNode> &stmts,
240
254
auto labelItem = CaseLabelItem (pat);
241
255
242
256
// generate: indexVar = <index>
243
- llvm::SmallString<8 > indexVal;
244
- APInt (32 , index ++).toString (indexVal, 10 , /* signed*/ false );
245
- auto indexStr = C.AllocateCopy (indexVal);
246
-
247
- auto indexExpr = new (C) IntegerLiteralExpr (StringRef (indexStr.data (),
248
- indexStr.size ()), SourceLoc (),
249
- /* implicit*/ true );
257
+ auto indexExpr = integerLiteralExpr (C, index ++);
250
258
auto indexRef = new (C) DeclRefExpr (indexVar, DeclNameLoc (),
251
259
/* implicit*/ true );
252
260
auto assignExpr = new (C) AssignExpr (indexRef, SourceLoc (),
@@ -714,20 +722,6 @@ ValueDecl *DerivedConformance::deriveEquatable(TypeChecker &tc,
714
722
return nullptr ;
715
723
}
716
724
717
- // / Returns a new integer literal expression with the given value.
718
- // / \p C The AST context.
719
- // / \p value The integer value.
720
- // / \return The integer literal expression.
721
- static Expr *integerLiteralExpr (ASTContext &C, int64_t value) {
722
- llvm::SmallString<8 > integerVal;
723
- APInt (32 , value).toString (integerVal, 10 , /* signed*/ false );
724
- auto integerStr = C.AllocateCopy (integerVal);
725
- auto integerExpr = new (C) IntegerLiteralExpr (
726
- StringRef (integerStr.data (), integerStr.size ()), SourceLoc (),
727
- /* implicit*/ true );
728
- return integerExpr;
729
- }
730
-
731
725
// / Returns a new \c CallExpr representing
732
726
// /
733
727
// / hasher.combine(hashable)
@@ -853,23 +847,54 @@ deriveBodyHashable_compat_hashInto(AbstractFunctionDecl *hashIntoDecl) {
853
847
hashIntoDecl->setBody (body);
854
848
}
855
849
856
- // / Derive the body for the 'hash(into:)' method for an enum.
850
+ // / Derive the body for the 'hash(into:)' method for an enum without associated
851
+ // / values.
857
852
static void
858
- deriveBodyHashable_enum_hashInto (AbstractFunctionDecl *hashIntoDecl) {
853
+ deriveBodyHashable_enum_noAssociatedValues_hashInto (
854
+ AbstractFunctionDecl *hashIntoDecl
855
+ ) {
859
856
// enum SomeEnum {
860
857
// case A, B, C
861
858
// @derived func hash(into hasher: inout Hasher) {
859
+ // let discriminator: Int
862
860
// switch self {
863
861
// case A:
864
- // hasher.combine(0)
862
+ // discriminator = 0
865
863
// case B:
866
- // hasher.combine(1)
864
+ // discriminator = 1
867
865
// case C:
868
- // hasher.combine(2)
866
+ // discriminator = 2
869
867
// }
868
+ // hasher.combine(discriminator)
870
869
// }
871
870
// }
872
- //
871
+ auto parentDC = hashIntoDecl->getDeclContext ();
872
+ ASTContext &C = parentDC->getASTContext ();
873
+
874
+ auto enumDecl = parentDC->getAsEnumOrEnumExtensionContext ();
875
+ auto selfDecl = hashIntoDecl->getImplicitSelfDecl ();
876
+
877
+ // generate: switch self {...}
878
+ SmallVector<ASTNode, 3 > stmts;
879
+ auto discriminatorExpr = convertEnumToIndex (stmts, parentDC, enumDecl,
880
+ selfDecl, hashIntoDecl,
881
+ " discriminator" );
882
+ // generate: hasher.combine(discriminator)
883
+ auto hasherParam = hashIntoDecl->getParameterList (1 )->get (0 );
884
+ auto combineStmt = createHasherCombineCall (C, hasherParam, discriminatorExpr);
885
+ stmts.push_back (combineStmt);
886
+
887
+ auto body = BraceStmt::create (C, SourceLoc (), stmts, SourceLoc (),
888
+ /* implicit*/ true );
889
+ hashIntoDecl->setBody (body);
890
+ }
891
+
892
+ // / Derive the body for the 'hash(into:)' method for an enum with associated
893
+ // / values.
894
+ static void
895
+ deriveBodyHashable_enum_hasAssociatedValues_hashInto (
896
+ AbstractFunctionDecl *hashIntoDecl
897
+ ) {
873
898
// enum SomeEnumWithAssociatedValues {
874
899
// case A, B(Int), C(String, Int)
875
900
// @derived func hash(into hasher: inout Hasher) {
@@ -940,7 +965,8 @@ deriveBodyHashable_enum_hashInto(AbstractFunctionDecl *hashIntoDecl) {
940
965
auto hasBoundDecls = !payloadVars.empty ();
941
966
auto body = BraceStmt::create (C, SourceLoc (), statements, SourceLoc ());
942
967
cases.push_back (CaseStmt::create (C, SourceLoc (), labelItem, hasBoundDecls,
943
- SourceLoc (), SourceLoc (), body));
968
+ SourceLoc (), SourceLoc (), body,
969
+ /* implicit*/ true ));
944
970
}
945
971
946
972
// generate: switch enumVar { }
@@ -1195,16 +1221,20 @@ ValueDecl *DerivedConformance::deriveHashable(TypeChecker &tc,
1195
1221
// special case for enums with no associated values to preserve source
1196
1222
// compatibility.
1197
1223
auto theEnum = dyn_cast<EnumDecl>(type);
1198
- if (!(theEnum && theEnum->hasOnlyCasesWithoutAssociatedValues ()) &&
1199
- type != parentDecl) {
1224
+ auto hasAssociatedValues =
1225
+ theEnum && !theEnum->hasOnlyCasesWithoutAssociatedValues ();
1226
+ if ((!theEnum || hasAssociatedValues) && type != parentDecl) {
1200
1227
tc.diagnose (parentDecl->getLoc (), diag::cannot_synthesize_in_extension,
1201
1228
hashableProto->getDeclaredType ());
1202
1229
return nullptr ;
1203
1230
}
1204
- if (theEnum)
1231
+ if (theEnum) {
1232
+ auto bodySynthesizer = hasAssociatedValues
1233
+ ? &deriveBodyHashable_enum_hasAssociatedValues_hashInto
1234
+ : &deriveBodyHashable_enum_noAssociatedValues_hashInto;
1205
1235
return deriveHashable_hashInto (tc, parentDecl, theEnum,
1206
- &deriveBodyHashable_enum_hashInto );
1207
- else if (auto theStruct = dyn_cast<StructDecl>(type))
1236
+ bodySynthesizer );
1237
+ } else if (auto theStruct = dyn_cast<StructDecl>(type))
1208
1238
return deriveHashable_hashInto (tc, parentDecl, theStruct,
1209
1239
&deriveBodyHashable_struct_hashInto);
1210
1240
else // This should've been caught by canDeriveHashable above.
0 commit comments