@@ -745,51 +745,58 @@ static Expr* integerLiteralExpr(ASTContext &C, int64_t value) {
745
745
return integerExpr;
746
746
}
747
747
748
- // / Returns a new expression that mixes the hash value of an expression into a
749
- // / variable (as a mutating assignment) .
748
+ // / Returns a new assignment expression that mixes the hash value of an
749
+ // / expression into a variable .
750
750
// / \p C The AST context.
751
751
// / \p resultVar The variable into which the hash value will be mixed.
752
752
// / \p exprToHash The expression whose hash value should be mixed in.
753
753
// / \return The expression that mixes the hash value into the result variable.
754
754
static Expr* mixInHashExpr_hashValue (ASTContext &C,
755
755
VarDecl* resultVar,
756
756
Expr *exprToHash) {
757
- auto intType = C.getIntDecl ()->getDeclaredType ();
758
- auto xorFuncInputType =
759
- TupleType::get ({
760
- TupleTypeElt (intType, Identifier (), ParameterTypeFlags ().withInOut (true )),
761
- TupleTypeElt (intType) }, C);
762
-
763
757
// <exprToHash>.hashValue
764
758
auto hashValueExpr = new (C) UnresolvedDotExpr (exprToHash, SourceLoc (),
765
759
C.Id_hashValue , DeclNameLoc (),
766
760
/* implicit*/ true );
767
761
768
- // _mixInt( <exprToHash>.hashValue)
769
- auto mixinFunc = C.getMixIntDecl ();
762
+ // _mixForSynthesizedHashValue(result, <exprToHash>.hashValue)
763
+ auto mixinFunc = C.getMixForSynthesizedHashValueDecl ();
770
764
auto mixinFuncExpr = new (C) DeclRefExpr (mixinFunc, DeclNameLoc (),
771
765
/* implicit*/ true );
772
- auto mixinResultExpr = CallExpr::createImplicit (C, mixinFuncExpr,
773
- { hashValueExpr }, {});
774
-
775
- // result ^= _mixInt(<exprToHash>.hashValue)
776
- auto resultExpr = new (C) DeclRefExpr (resultVar, DeclNameLoc (),
777
- /* implicit*/ true );
778
- auto resultInoutExpr = new (C) InOutExpr (SourceLoc (), resultExpr,
779
- intType, /* implicit*/ true );
766
+ auto rhsResultExpr = new (C) DeclRefExpr (resultVar, DeclNameLoc (),
767
+ /* implicit*/ true );
768
+ auto mixinResultExpr = CallExpr::createImplicit (
769
+ C, mixinFuncExpr, { rhsResultExpr, hashValueExpr }, {});
780
770
781
- auto xorFunc = C.getMutatingXorIntDecl ();
782
- auto xorFuncExpr = new (C) DeclRefExpr (xorFunc, DeclNameLoc (),
783
- /* implicit*/ true );
771
+ // result = _mixForSynthesizedHashValue(result, <exprToHash>.hashValue)
772
+ auto lhsResultExpr = new (C) DeclRefExpr (resultVar, DeclNameLoc (),
773
+ /* implicit*/ true );
774
+ auto assignExpr = new (C) AssignExpr (lhsResultExpr, SourceLoc (),
775
+ mixinResultExpr, /* implicit*/ true );
776
+ return assignExpr;
777
+ }
784
778
785
- TupleExpr *xorArgTuple = TupleExpr::create (C, SourceLoc (),
786
- { resultInoutExpr,
787
- mixinResultExpr },
788
- { }, { }, SourceLoc (),
789
- /* HasTrailingClosure*/ false ,
790
- /* Implicit*/ true ,
791
- xorFuncInputType);
792
- return new (C) BinaryExpr (xorFuncExpr, xorArgTuple, /* implicit*/ true );
779
+ // / Returns a new assignment expression that invokes _mixInt on a variable and
780
+ // / assigns the result back to the same variable.
781
+ // / \p C The AST context.
782
+ // / \p resultVar The integer variable to be mixed.
783
+ // / \return The expression that mixes the integer value.
784
+ static Expr* mixIntAssignmentExpr (ASTContext &C, VarDecl* resultVar) {
785
+ auto mixinFunc = C.getMixIntDecl ();
786
+ auto mixinFuncExpr = new (C) DeclRefExpr (mixinFunc, DeclNameLoc (),
787
+ /* implicit*/ true );
788
+ auto rhsResultRef = new (C) DeclRefExpr (resultVar, DeclNameLoc (),
789
+ /* implicit*/ true );
790
+ // _mixInt(result)
791
+ auto mixedResultExpr = CallExpr::createImplicit (C, mixinFuncExpr,
792
+ { rhsResultRef }, {});
793
+
794
+ // result = _mixInt(result)
795
+ auto lhsResultRef = new (C) DeclRefExpr (resultVar, DeclNameLoc (),
796
+ /* implicit*/ true );
797
+ auto assignExpr = new (C) AssignExpr (lhsResultRef, SourceLoc (),
798
+ mixedResultExpr, /* implicit*/ true );
799
+ return assignExpr;
793
800
}
794
801
795
802
static void
@@ -844,45 +851,39 @@ deriveBodyHashable_enum_hashValue(AbstractFunctionDecl *hashValueDecl) {
844
851
auto labelItem = CaseLabelItem (/* IsDefault*/ false , pat, SourceLoc (),
845
852
nullptr );
846
853
847
- auto hasBoundDecls = !payloadVars.empty ();
854
+ // If the enum has no associated values, we use the ordinal alone as the
855
+ // hash value, because that is sufficient for a good distribution. If any
856
+ // case do have associated values, then the ordinal is used as the first
857
+ // term mixed into _mixForSynthesizedHashValue, and the final result after
858
+ // mixing in the payload is passed to _mixInt to improve the distribution.
848
859
849
- // If the enum has no cases with associated values, we use the ordinal
850
- // directly as the hash value. If any of the cases have associated values,
851
- // then we mix the ordinal instead to better distribute it among the hash
852
- // values of its payload.
853
- if (hasNoAssociatedValues) {
854
- // result = <ordinal>
860
+ // result = <ordinal>
861
+ {
855
862
auto ordinalExpr = integerLiteralExpr (C, index++);
856
863
auto resultRef = new (C) DeclRefExpr (resultVar, DeclNameLoc (),
857
864
/* implicit*/ true );
858
865
auto assignExpr = new (C) AssignExpr (resultRef, SourceLoc (),
859
866
ordinalExpr, /* implicit*/ true );
860
867
mixExpressions.emplace_back (ASTNode (assignExpr));
861
- } else {
862
- // result = _mixInt(<ordinal>)
863
- auto mixinFunc = C.getMixIntDecl ();
864
- auto mixinFuncExpr = new (C) DeclRefExpr (mixinFunc, DeclNameLoc (),
865
- /* implicit*/ true );
866
- auto ordinalExpr = integerLiteralExpr (C, index++);
867
- auto mixedOrdinalExpr = CallExpr::createImplicit (C, mixinFuncExpr,
868
- { ordinalExpr }, {});
869
- auto resultRef = new (C) DeclRefExpr (resultVar, DeclNameLoc (),
870
- /* implicit*/ true );
871
- auto assignExpr = new (C) AssignExpr (resultRef, SourceLoc (),
872
- mixedOrdinalExpr, /* implicit*/ true );
873
- mixExpressions.emplace_back (ASTNode (assignExpr));
868
+ }
874
869
870
+ if (!hasNoAssociatedValues) {
875
871
// Generate a sequence of expressions that mix the payload's hash values
876
872
// into result.
877
873
for (auto payloadVar : payloadVars) {
878
874
auto payloadVarRef = new (C) DeclRefExpr (payloadVar, DeclNameLoc (),
879
875
/* implicit*/ true );
880
- // result ^= <payloadVar>.hashValue
876
+ // result = _mixForSynthesizedHashValue(result, <payloadVar>.hashValue)
881
877
auto mixExpr = mixInHashExpr_hashValue (C, resultVar, payloadVarRef);
882
878
mixExpressions.emplace_back (ASTNode (mixExpr));
883
879
}
880
+
881
+ // result = _mixInt(result)
882
+ auto assignExpr = mixIntAssignmentExpr (C, resultVar);
883
+ mixExpressions.emplace_back (ASTNode (assignExpr));
884
884
}
885
885
886
+ auto hasBoundDecls = !payloadVars.empty ();
886
887
auto body = BraceStmt::create (C, SourceLoc (), mixExpressions, SourceLoc ());
887
888
cases.push_back (CaseStmt::create (C, SourceLoc (), labelItem, hasBoundDecls,
888
889
SourceLoc (), body));
@@ -961,13 +962,17 @@ deriveBodyHashable_struct_hashValue(AbstractFunctionDecl *hashValueDecl) {
961
962
/* implicit*/ true );
962
963
auto selfPropertyExpr = new (C) DotSyntaxCallExpr (propertyRef, SourceLoc (),
963
964
selfRef);
964
- // result ^= <property>.hashValue
965
+ // result = _mixForSynthesizedHashValue(result, <property>.hashValue)
965
966
auto mixExpr = mixInHashExpr_hashValue (C, resultVar, selfPropertyExpr);
966
967
statements.emplace_back (ASTNode (mixExpr));
967
968
}
968
969
969
- // return result
970
970
{
971
+ // result = _mixInt(result)
972
+ auto assignExpr = mixIntAssignmentExpr (C, resultVar);
973
+ statements.push_back (assignExpr);
974
+
975
+ // return result
971
976
auto resultRef = new (C) DeclRefExpr (resultVar, DeclNameLoc (),
972
977
/* implicit*/ true ,
973
978
AccessSemantics::Ordinary, intType);
@@ -987,16 +992,16 @@ deriveHashable_hashValue(TypeChecker &tc, Decl *parentDecl,
987
992
// enum SomeEnum {
988
993
// case A, B, C
989
994
// @derived var hashValue: Int {
990
- // var index : Int
995
+ // var result : Int
991
996
// switch self {
992
997
// case A:
993
- // index = 0
998
+ // result = 0
994
999
// case B:
995
- // index = 1
1000
+ // result = 1
996
1001
// case C:
997
- // index = 2
1002
+ // result = 2
998
1003
// }
999
- // return index.hashValue
1004
+ // return result
1000
1005
// }
1001
1006
// }
1002
1007
//
@@ -1006,15 +1011,16 @@ deriveHashable_hashValue(TypeChecker &tc, Decl *parentDecl,
1006
1011
// var result: Int
1007
1012
// switch self {
1008
1013
// case A:
1009
- // result = _mixInt(0)
1014
+ // result = 0
1010
1015
// case B(let a0):
1011
- // result = _mixInt( 1)
1012
- // result ^= _mixInt( a0.hashValue)
1016
+ // result = _mixForSynthesizedHashValue(result, 1)
1017
+ // result = _mixForSynthesizedHashValue(result, a0.hashValue)
1013
1018
// case C(let a0, let a1):
1014
- // result = _mixInt( 2)
1015
- // result ^= _mixInt( a0.hashValue)
1016
- // result ^= _mixInt( a1.hashValue)
1019
+ // result = _mixForSynthesizedHashValue(result, 2)
1020
+ // result = _mixForSynthesizedHashValue(result, a0.hashValue)
1021
+ // result = _mixForSynthesizedHashValue(result, a1.hashValue)
1017
1022
// }
1023
+ // result = _mixInt(result)
1018
1024
// return result
1019
1025
// }
1020
1026
// }
@@ -1024,8 +1030,9 @@ deriveHashable_hashValue(TypeChecker &tc, Decl *parentDecl,
1024
1030
// var y: String
1025
1031
// @derived var hashValue: Int {
1026
1032
// var result: Int = 0
1027
- // result ^= _mixInt(x.hashValue)
1028
- // result ^= _mixInt(y.hashValue)
1033
+ // result = _mixForSynthesizedHashValue(result, x.hashValue)
1034
+ // result = _mixForSynthesizedHashValue(result, y.hashValue)
1035
+ // result = _mixInt(result)
1029
1036
// return result
1030
1037
// }
1031
1038
// }
0 commit comments