@@ -38,8 +38,9 @@ using namespace DerivedConformance;
38
38
// / \p theEnum The enum whose elements and associated values should be checked.
39
39
// / \p protocol The protocol being requested.
40
40
// / \return True if all associated values of all elements of the enum conform.
41
- bool allAssociatedValuesConformToProtocol (TypeChecker &tc, EnumDecl *theEnum,
42
- ProtocolDecl *protocol) {
41
+ static bool allAssociatedValuesConformToProtocol (TypeChecker &tc,
42
+ EnumDecl *theEnum,
43
+ ProtocolDecl *protocol) {
43
44
auto declContext = theEnum->getDeclContext ();
44
45
45
46
for (auto elt : theEnum->getAllElements ()) {
@@ -76,9 +77,9 @@ bool allAssociatedValuesConformToProtocol(TypeChecker &tc, EnumDecl *theEnum,
76
77
// / \p theStruct The struct whose stored properties should be checked.
77
78
// / \p protocol The protocol being requested.
78
79
// / \return True if all stored properties of the struct conform.
79
- bool allStoredPropertiesConformToProtocol (TypeChecker &tc,
80
- StructDecl *theStruct,
81
- ProtocolDecl *protocol) {
80
+ static bool allStoredPropertiesConformToProtocol (TypeChecker &tc,
81
+ StructDecl *theStruct,
82
+ ProtocolDecl *protocol) {
82
83
auto declContext = theStruct->getDeclContext ();
83
84
84
85
auto storedProperties =
@@ -747,71 +748,83 @@ static Expr *integerLiteralExpr(ASTContext &C, int64_t value) {
747
748
748
749
// / Returns a new \c CallExpr representing
749
750
// /
750
- // / hasher.appending (hashable)
751
+ // / hasher.append (hashable)
751
752
// /
752
753
// / \param C The AST context to create the expression in.
753
754
// /
754
- // / \param hasher The base expression to make the call on.
755
+ // / \param hasher The parameter decl to make the call on.
755
756
// /
756
757
// / \param hashable The parameter to the call.
757
- static CallExpr *createHasherAppendingCall (ASTContext &C,
758
- Expr *hasher,
759
- Expr *hashable) {
760
- // hasher.appending(_:)
761
- DeclName name (C, C.Id_appending , {Identifier ()});
762
- auto *appendingCall = new (C) UnresolvedDotExpr (hasher, SourceLoc (),
763
- name, DeclNameLoc (),
764
- /* implicit*/ true );
758
+ static CallExpr *createHasherAppendCall (ASTContext &C,
759
+ ParamDecl *hasher,
760
+ Expr *hashable) {
761
+ Expr *hasherExpr = new (C) DeclRefExpr (ConcreteDeclRef (hasher),
762
+ DeclNameLoc (), /* implicit*/ true );
763
+ DeclName name (C, C.Id_append , {Identifier ()});
764
+ // hasher.append(_:)
765
+ auto *appendCall = new (C) UnresolvedDotExpr (hasherExpr, SourceLoc (),
766
+ name, DeclNameLoc (),
767
+ /* implicit*/ true );
765
768
766
- // hasher.appending (hashable)
767
- return CallExpr::createImplicit (C, appendingCall , {hashable}, {Identifier ()});
769
+ // hasher.append (hashable)
770
+ return CallExpr::createImplicit (C, appendCall , {hashable}, {Identifier ()});
768
771
}
769
772
770
773
static FuncDecl *
771
774
deriveHashable_hashInto (TypeChecker &tc, Decl *parentDecl,
772
775
NominalTypeDecl *typeDecl,
773
776
void (*bodySynthesizer)(AbstractFunctionDecl *)) {
774
- // @derived func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher
777
+ // @derived func _hash(into hasher: inout _Hasher)
775
778
776
779
ASTContext &C = tc.Context ;
777
780
auto parentDC = cast<DeclContext>(parentDecl);
778
781
779
- // Expected type: (Self) -> (into: _UnsafeHasher ) -> _UnsafeHasher
782
+ // Expected type: (Self) -> (into: inout _Hasher ) -> ()
780
783
// Constructed as:
781
784
// func type(input: Self,
782
- // output: func type(input: _UnsafeHasher,
783
- // output: _UnsafeHasher ))
785
+ // output: func type(input: inout _UnsafeHasher,
786
+ // output: () ))
784
787
// Created from the inside out:
785
788
786
- Type hasherType = C.getUnsafeHasherDecl ()->getDeclaredType ();
789
+ auto hasherDecl = C.getHasherDecl ();
790
+ if (!hasherDecl) {
791
+ auto hashableProto = tc.Context .getProtocol (KnownProtocolKind::Hashable);
792
+ tc.diagnose (hashableProto->getLoc (), diag::broken_hashable_no_hasher);
793
+ return nullptr ;
794
+ }
795
+ Type hasherType = hasherDecl->getDeclaredType ();
787
796
788
797
// Params: self (implicit), hasher
789
798
auto *selfDecl = ParamDecl::createSelf (SourceLoc (), parentDC);
790
- auto *hasherParam = new (C) ParamDecl (VarDecl::Specifier::Owned, SourceLoc (),
791
- SourceLoc (), C.Id_into , SourceLoc (),
792
- C.Id_hasher , hasherType, parentDC);
793
- hasherParam->setInterfaceType (hasherType);
799
+ auto *hasherParamDecl = new (C) ParamDecl (VarDecl::Specifier::InOut,
800
+ SourceLoc (),
801
+ SourceLoc (), C.Id_into , SourceLoc (),
802
+ C.Id_hasher , hasherType, parentDC);
803
+ hasherParamDecl->setInterfaceType (hasherType);
794
804
795
805
ParameterList *params[] = {ParameterList::createWithoutLoc (selfDecl),
796
- ParameterList::createWithoutLoc (hasherParam)};
806
+ ParameterList::createWithoutLoc (hasherParamDecl)};
807
+
808
+ // Return type: ()
809
+ auto returnType = TupleType::getEmpty (C);
797
810
798
- // Func name: _hash(into: _UnsafeHasher )
811
+ // Func name: _hash(into: inout _Hasher) -> ( )
799
812
DeclName name (C, C.Id_hash , params[1 ]);
800
813
auto *hashDecl = FuncDecl::create (C,
801
814
SourceLoc (), StaticSpellingKind::None,
802
815
SourceLoc (), name, SourceLoc (),
803
816
/* Throws=*/ false , SourceLoc (),
804
817
nullptr , params,
805
- TypeLoc::withoutLoc (hasherType ),
818
+ TypeLoc::withoutLoc (returnType ),
806
819
parentDC);
807
820
hashDecl->setImplicit ();
808
821
hashDecl->setBodySynthesizer (bodySynthesizer);
809
822
810
- // Evaluate type of Self in (Self) -> (into: _UnsafeHasher ) -> _UnsafeHasher
823
+ // Evaluate type of Self in (Self) -> (into: inout _Hasher ) -> ()
811
824
auto selfParam = computeSelfParam (hashDecl);
812
- auto inputTypeElt = TupleTypeElt (hasherType, C. Id_into );
813
- auto inputType = TupleType::get ({inputTypeElt} , C);
814
- auto innerType = FunctionType::get (inputType, hasherType ,
825
+ auto inoutFlag = ParameterTypeFlags (). withInOut ( true );
826
+ auto hasherParam = AnyFunctionType::Param (hasherType , C. Id_into , inoutFlag );
827
+ auto innerType = FunctionType::get ({hasherParam}, returnType ,
815
828
FunctionType::ExtInfo ());
816
829
817
830
Type interfaceType;
@@ -820,7 +833,7 @@ deriveHashable_hashInto(TypeChecker &tc, Decl *parentDecl,
820
833
interfaceType = GenericFunctionType::get (sig, {selfParam}, innerType,
821
834
FunctionType::ExtInfo ());
822
835
} else {
823
- // (Self) -> innerType == (_UnsafeHasher ) -> _UnsafeHasher
836
+ // (Self) -> innerType == (inout _Hasher ) -> ()
824
837
interfaceType = FunctionType::get ({selfParam}, innerType,
825
838
FunctionType::ExtInfo ());
826
839
}
@@ -865,28 +878,31 @@ static void
865
878
deriveBodyHashable_enum_hashInto (AbstractFunctionDecl *hashIntoDecl) {
866
879
// enum SomeEnum {
867
880
// case A, B, C
868
- // @derived func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher {
881
+ // @derived func _hash(into hasher: inout _Hasher) {
869
882
// switch self {
870
883
// case A:
871
- // return hasher.appending (0)
884
+ // hasher.append (0)
872
885
// case B:
873
- // return hasher.appending (1)
886
+ // hasher.append (1)
874
887
// case C:
875
- // return hasher.appending (2)
888
+ // hasher.append (2)
876
889
// }
877
890
// }
878
891
// }
879
892
//
880
893
// enum SomeEnumWithAssociatedValues {
881
894
// case A, B(Int), C(String, Int)
882
- // @derived func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher {
895
+ // @derived func _hash(into hasher: inout _Hasher) {
883
896
// switch self {
884
897
// case A:
885
- // return hasher.appending (0)
898
+ // hasher.append (0)
886
899
// case B(let a0):
887
- // return hasher.appending(1).appending(a0)
900
+ // hasher.append(1)
901
+ // hasher.append(a0)
888
902
// case C(let a0, let a1):
889
- // return hasher.appending(2).appending(a0).appending(a1)
903
+ // hasher.append(2)
904
+ // hasher.append(a0)
905
+ // hasher.append(a1)
890
906
// }
891
907
// }
892
908
// }
@@ -904,20 +920,12 @@ deriveBodyHashable_enum_hashInto(AbstractFunctionDecl *hashIntoDecl) {
904
920
unsigned index = 0 ;
905
921
SmallVector<ASTNode, 4 > cases;
906
922
907
- auto hasNoAssociatedValues = enumDecl->hasOnlyCasesWithoutAssociatedValues ();
908
-
909
923
// For each enum element, generate a case statement that binds the associated
910
924
// values so that they can be fed to the hasher.
911
925
for (auto elt : enumDecl->getAllElements ()) {
912
926
// case .<elt>(let a0, let a1, ...):
913
927
SmallVector<VarDecl*, 3 > payloadVars;
914
-
915
- // hasherExpr will hold the returned expression. It starts by the hasher
916
- // parameter, but we will add one or more chained method calls to it below.
917
- //
918
- // <hasherExpr> := hasher
919
- Expr* hasherExpr = new (C) DeclRefExpr (ConcreteDeclRef (hasherParam),
920
- DeclNameLoc (), /* implicit*/ true );
928
+ SmallVector<ASTNode, 3 > statements;
921
929
922
930
auto payloadPattern = enumElementPayloadSubpattern (elt, ' a' , hashIntoDecl,
923
931
payloadVars);
@@ -929,32 +937,29 @@ deriveBodyHashable_enum_hashInto(AbstractFunctionDecl *hashIntoDecl) {
929
937
auto labelItem = CaseLabelItem (/* IsDefault*/ false , pat, SourceLoc (),
930
938
nullptr );
931
939
932
- // If the enum has no associated values, we use the ordinal alone as the
933
- // hash value , because that is sufficient for a good distribution. If any
934
- // case does have associated values, then the ordinal is used as the first
935
- // term fed into the hasher.
940
+ // If the enum has no associated values, we use the ordinal as the single
941
+ // hash component , because that is sufficient for a good distribution. If
942
+ // any case does have associated values, then the ordinal is used as the
943
+ // first term fed into the hasher.
936
944
937
- // <hasherExpr> := <hasherExpr>.appending(<ordinal>)
938
945
{
946
+ // Generate: hasher.append(<ordinal>)
939
947
auto ordinalExpr = integerLiteralExpr (C, index++);
940
- hasherExpr = createHasherAppendingCall (C, hasherExpr, ordinalExpr);
948
+ auto appendExpr = createHasherAppendCall (C, hasherParam, ordinalExpr);
949
+ statements.emplace_back (ASTNode (appendExpr));
941
950
}
942
951
943
- if (!hasNoAssociatedValues) {
944
- // Generate a sequence of expressions that combine the payload's hash
945
- // values into result.
946
- for (auto payloadVar : payloadVars) {
947
- auto payloadVarRef = new (C) DeclRefExpr (payloadVar, DeclNameLoc (),
948
- /* implicit*/ true );
949
- // <hasherExpr> := <hasherExpr>.appending(<payloadVar>)
950
- hasherExpr = createHasherAppendingCall (C, hasherExpr, payloadVarRef);
951
- }
952
+ // Generate a sequence of statements that feed the payloads into hasher.
953
+ for (auto payloadVar : payloadVars) {
954
+ auto payloadVarRef = new (C) DeclRefExpr (payloadVar, DeclNameLoc (),
955
+ /* implicit*/ true );
956
+ // Generate: hasher.append(<payloadVar>)
957
+ auto appendExpr = createHasherAppendCall (C, hasherParam, payloadVarRef);
958
+ statements.emplace_back (ASTNode (appendExpr));
952
959
}
953
960
954
- auto returnStmt = new (C) ReturnStmt (SourceLoc (), hasherExpr);
955
961
auto hasBoundDecls = !payloadVars.empty ();
956
- auto body = BraceStmt::create (C, SourceLoc (),
957
- {ASTNode (returnStmt)}, SourceLoc ());
962
+ auto body = BraceStmt::create (C, SourceLoc (), statements, SourceLoc ());
958
963
cases.push_back (CaseStmt::create (C, SourceLoc (), labelItem, hasBoundDecls,
959
964
SourceLoc (), body));
960
965
}
@@ -965,7 +970,8 @@ deriveBodyHashable_enum_hashInto(AbstractFunctionDecl *hashIntoDecl) {
965
970
auto switchStmt = SwitchStmt::create (LabeledStmtInfo (), SourceLoc (), enumRef,
966
971
SourceLoc (), cases, SourceLoc (), C);
967
972
968
- auto body = BraceStmt::create (C, SourceLoc (), {ASTNode (switchStmt)}, SourceLoc ());
973
+ auto body = BraceStmt::create (C, SourceLoc (), {ASTNode (switchStmt)},
974
+ SourceLoc ());
969
975
hashIntoDecl->setBody (body);
970
976
}
971
977
@@ -975,26 +981,21 @@ deriveBodyHashable_struct_hashInto(AbstractFunctionDecl *hashIntoDecl) {
975
981
// struct SomeStruct {
976
982
// var x: Int
977
983
// var y: String
978
- // @derived func _hash(into hasher: _UnsafeHasher) -> _UnsafeHasher {
979
- // return hasher.appending(x).appending(y)
984
+ // @derived func _hash(into hasher: inout _Hasher) {
985
+ // hasher.append(x)
986
+ // hasher.append(y)
980
987
// }
981
988
// }
982
989
auto parentDC = hashIntoDecl->getDeclContext ();
983
990
ASTContext &C = parentDC->getASTContext ();
984
991
985
992
auto structDecl = parentDC->getAsStructOrStructExtensionContext ();
993
+ SmallVector<ASTNode, 6 > statements;
986
994
auto selfDecl = hashIntoDecl->getImplicitSelfDecl ();
987
995
988
996
// Extract the decl for the hasher parameter.
989
997
auto hasherParam = hashIntoDecl->getParameterList (1 )->get (0 );
990
998
991
- // hasherExpr will hold the returned expression. It starts by the hasher
992
- // parameter, but we will add one or more chained method calls to it below.
993
- //
994
- // <hasherExpr> := hasher
995
- Expr* hasherExpr = new (C) DeclRefExpr (hasherParam, DeclNameLoc (),
996
- /* implicit*/ true );
997
-
998
999
auto storedProperties =
999
1000
structDecl->getStoredProperties (/* skipInaccessible=*/ true );
1000
1001
@@ -1006,12 +1007,12 @@ deriveBodyHashable_struct_hashInto(AbstractFunctionDecl *hashIntoDecl) {
1006
1007
/* implicit*/ true );
1007
1008
auto selfPropertyExpr = new (C) DotSyntaxCallExpr (propertyRef, SourceLoc (),
1008
1009
selfRef);
1009
- // <hasherExpr> := <hasherExpr>.appending(self.<property>)
1010
- hasherExpr = createHasherAppendingCall (C, hasherExpr, selfPropertyExpr);
1010
+ // Generate: hasher.append(self.<property>)
1011
+ auto appendExpr = createHasherAppendCall (C, hasherParam, selfPropertyExpr);
1012
+ statements.emplace_back (ASTNode (appendExpr));
1011
1013
}
1012
1014
1013
- auto returnStmt = new (C) ReturnStmt (SourceLoc (), hasherExpr);
1014
- auto body = BraceStmt::create (C, SourceLoc (), {ASTNode (returnStmt)},
1015
+ auto body = BraceStmt::create (C, SourceLoc (), statements,
1015
1016
SourceLoc (), /* implicit*/ true );
1016
1017
hashIntoDecl->setBody (body);
1017
1018
}
@@ -1223,7 +1224,6 @@ ValueDecl *DerivedConformance::deriveHashable(TypeChecker &tc,
1223
1224
return hashValueDecl;
1224
1225
}
1225
1226
1226
- tc.diagnose (requirement->getLoc (),
1227
- diag::broken_hashable_requirement);
1227
+ tc.diagnose (requirement->getLoc (), diag::broken_hashable_requirement);
1228
1228
return nullptr ;
1229
1229
}
0 commit comments