|
40 | 40 | #include "swift/AST/PropertyWrappers.h"
|
41 | 41 | #include "swift/AST/ProtocolConformance.h"
|
42 | 42 | #include "swift/AST/SourceFile.h"
|
| 43 | +#include "swift/AST/TypeMatcher.h" |
43 | 44 | #include "swift/AST/TypeWalker.h"
|
44 | 45 | #include "swift/Basic/Statistic.h"
|
45 | 46 | #include "swift/Parse/Lexer.h"
|
@@ -869,6 +870,258 @@ IsDynamicRequest::evaluate(Evaluator &evaluator, ValueDecl *decl) const {
|
869 | 870 | return false;
|
870 | 871 | }
|
871 | 872 |
|
| 873 | +static void addTypeRequirement(Type subjectType, Type constraintType, |
| 874 | + SourceLoc loc, bool wasInferred, |
| 875 | + SmallVectorImpl<StructuralRequirement> &result) { |
| 876 | + // Check whether we have a reasonable constraint type at all. |
| 877 | + if (!constraintType->isExistentialType() && |
| 878 | + !constraintType->getClassOrBoundGenericClass()) { |
| 879 | + // FIXME: Diagnose |
| 880 | + return; |
| 881 | + } |
| 882 | + |
| 883 | + // Protocol requirements. |
| 884 | + if (constraintType->isExistentialType()) { |
| 885 | + auto layout = constraintType->getExistentialLayout(); |
| 886 | + |
| 887 | + if (auto layoutConstraint = layout.getLayoutConstraint()) { |
| 888 | + result.push_back({ |
| 889 | + Requirement(RequirementKind::Layout, subjectType, layoutConstraint), |
| 890 | + loc, wasInferred}); |
| 891 | + } |
| 892 | + |
| 893 | + if (auto superclass = layout.explicitSuperclass) { |
| 894 | + result.push_back({ |
| 895 | + Requirement(RequirementKind::Superclass, subjectType, superclass), |
| 896 | + loc, wasInferred}); |
| 897 | + } |
| 898 | + |
| 899 | + for (auto *proto : layout.getProtocols()) { |
| 900 | + result.push_back({ |
| 901 | + Requirement(RequirementKind::Conformance, subjectType, proto), |
| 902 | + loc, wasInferred}); |
| 903 | + } |
| 904 | + |
| 905 | + return; |
| 906 | + } |
| 907 | + |
| 908 | + // Superclass constraint. |
| 909 | + result.push_back({ |
| 910 | + Requirement(RequirementKind::Superclass, subjectType, constraintType), |
| 911 | + loc, wasInferred}); |
| 912 | +} |
| 913 | + |
| 914 | +static void addSameTypeRequirement(Type lhs, Type rhs, |
| 915 | + SourceLoc loc, bool wasInferred, |
| 916 | + SmallVectorImpl<StructuralRequirement> &result) { |
| 917 | + class Matcher : public TypeMatcher<Matcher> { |
| 918 | + SourceLoc loc; |
| 919 | + bool wasInferred; |
| 920 | + SmallVectorImpl<StructuralRequirement> &result; |
| 921 | + |
| 922 | + public: |
| 923 | + Matcher(SourceLoc loc, bool wasInferred, |
| 924 | + SmallVectorImpl<StructuralRequirement> &result) |
| 925 | + : loc(loc), wasInferred(wasInferred), result(result) {} |
| 926 | + |
| 927 | + bool mismatch(TypeBase *firstType, TypeBase *secondType, |
| 928 | + Type sugaredFirstType) { |
| 929 | + if (firstType->isTypeParameter() && secondType->isTypeParameter()) { |
| 930 | + result.push_back({Requirement(RequirementKind::SameType, |
| 931 | + firstType, secondType), |
| 932 | + loc, wasInferred}); |
| 933 | + return true; |
| 934 | + } |
| 935 | + |
| 936 | + if (firstType->isTypeParameter()) { |
| 937 | + result.push_back({Requirement(RequirementKind::SameType, |
| 938 | + firstType, secondType), |
| 939 | + loc, wasInferred}); |
| 940 | + return true; |
| 941 | + } |
| 942 | + |
| 943 | + if (secondType->isTypeParameter()) { |
| 944 | + result.push_back({Requirement(RequirementKind::SameType, |
| 945 | + secondType, firstType), |
| 946 | + loc, wasInferred}); |
| 947 | + return true; |
| 948 | + } |
| 949 | + |
| 950 | + // FIXME: Diagnose concrete type conflict |
| 951 | + return true; |
| 952 | + } |
| 953 | + } matcher(loc, wasInferred, result); |
| 954 | + |
| 955 | + // FIXME: If both sides concrete and was not inferred, diagnose redundancy |
| 956 | + // FIXME: If both sides are equal as type parameters and not inferred, |
| 957 | + // diagnose redundancy |
| 958 | + (void) matcher.match(lhs, rhs); |
| 959 | +} |
| 960 | + |
| 961 | +static void inferRequirements(Type type, SourceLoc loc, |
| 962 | + SmallVectorImpl<StructuralRequirement> &result) { |
| 963 | + |
| 964 | +} |
| 965 | + |
| 966 | +static void addRequirement(Requirement req, RequirementRepr *reqRepr, bool infer, |
| 967 | + SmallVectorImpl<StructuralRequirement> &result) { |
| 968 | + auto firstType = req.getFirstType(); |
| 969 | + if (infer) { |
| 970 | + auto firstLoc = (reqRepr ? reqRepr->getFirstTypeRepr()->getStartLoc() |
| 971 | + : SourceLoc()); |
| 972 | + inferRequirements(firstType, firstLoc, result); |
| 973 | + } |
| 974 | + |
| 975 | + auto loc = (reqRepr ? reqRepr->getSeparatorLoc() : SourceLoc()); |
| 976 | + |
| 977 | + switch (req.getKind()) { |
| 978 | + case RequirementKind::Superclass: |
| 979 | + case RequirementKind::Conformance: { |
| 980 | + if (!firstType->isTypeParameter()) { |
| 981 | + // FIXME: Warn about redundancy if not inferred, diagnose conflicts |
| 982 | + break; |
| 983 | + } |
| 984 | + |
| 985 | + auto secondType = req.getSecondType(); |
| 986 | + if (infer) { |
| 987 | + auto secondLoc = (reqRepr ? reqRepr->getSecondTypeRepr()->getStartLoc() |
| 988 | + : SourceLoc()); |
| 989 | + inferRequirements(secondType, secondLoc, result); |
| 990 | + } |
| 991 | + |
| 992 | + addTypeRequirement(firstType, secondType, loc, /*wasInferred=*/false, |
| 993 | + result); |
| 994 | + break; |
| 995 | + } |
| 996 | + |
| 997 | + case RequirementKind::Layout: |
| 998 | + if (!firstType->isTypeParameter()) { |
| 999 | + // FIXME: Warn about redundancy if not inferred, diagnose conflicts |
| 1000 | + break; |
| 1001 | + } |
| 1002 | + |
| 1003 | + result.push_back({req, loc, /*wasInferred=*/false}); |
| 1004 | + break; |
| 1005 | + |
| 1006 | + case RequirementKind::SameType: { |
| 1007 | + auto secondType = req.getSecondType(); |
| 1008 | + if (infer) { |
| 1009 | + auto secondLoc = (reqRepr ? reqRepr->getSecondTypeRepr()->getStartLoc() |
| 1010 | + : SourceLoc()); |
| 1011 | + inferRequirements(secondType, secondLoc, result); |
| 1012 | + } |
| 1013 | + |
| 1014 | + addSameTypeRequirement(firstType, secondType, loc, /*wasInferred=*/false, |
| 1015 | + result); |
| 1016 | + break; |
| 1017 | + } |
| 1018 | + } |
| 1019 | +} |
| 1020 | + |
| 1021 | +static void addInheritedRequirements(TypeDecl *decl, Type type, bool infer, |
| 1022 | + SmallVectorImpl<StructuralRequirement> &result) { |
| 1023 | + auto &ctx = decl->getASTContext(); |
| 1024 | + auto inheritedTypes = decl->getInherited(); |
| 1025 | + |
| 1026 | + for (unsigned index : indices(inheritedTypes)) { |
| 1027 | + Type inheritedType |
| 1028 | + = evaluateOrDefault(ctx.evaluator, |
| 1029 | + InheritedTypeRequest{decl, index, |
| 1030 | + TypeResolutionStage::Structural}, |
| 1031 | + Type()); |
| 1032 | + if (!inheritedType) continue; |
| 1033 | + |
| 1034 | + auto *typeRepr = inheritedTypes[index].getTypeRepr(); |
| 1035 | + SourceLoc loc = (typeRepr ? typeRepr->getStartLoc() : SourceLoc()); |
| 1036 | + if (infer) { |
| 1037 | + inferRequirements(inheritedType, loc, result); |
| 1038 | + } |
| 1039 | + |
| 1040 | + addTypeRequirement(type, inheritedType, loc, /*wasInferred=*/false, |
| 1041 | + result); |
| 1042 | + } |
| 1043 | +} |
| 1044 | + |
| 1045 | +ArrayRef<StructuralRequirement> |
| 1046 | +StructuralRequirementsRequest::evaluate(Evaluator &evaluator, |
| 1047 | + ProtocolDecl *proto) const { |
| 1048 | + assert(!proto->hasLazyRequirementSignature()); |
| 1049 | + |
| 1050 | + SmallVector<StructuralRequirement, 4> result; |
| 1051 | + |
| 1052 | + auto &ctx = proto->getASTContext(); |
| 1053 | + |
| 1054 | + auto selfTy = proto->getSelfInterfaceType(); |
| 1055 | + |
| 1056 | + addInheritedRequirements(proto, selfTy, |
| 1057 | + /*infer=*/false, result); |
| 1058 | + |
| 1059 | + // Add requirements from the protocol's own 'where' clause. |
| 1060 | + WhereClauseOwner(proto).visitRequirements(TypeResolutionStage::Structural, |
| 1061 | + [&](const Requirement &req, RequirementRepr *reqRepr) { |
| 1062 | + addRequirement(req, reqRepr, /*infer=*/false, result); |
| 1063 | + return false; |
| 1064 | + }); |
| 1065 | + |
| 1066 | + if (proto->isObjC()) { |
| 1067 | + // @objc protocols have an implicit AnyObject requirement on Self. |
| 1068 | + auto layout = LayoutConstraint::getLayoutConstraint( |
| 1069 | + LayoutConstraintKind::Class, ctx); |
| 1070 | + result.push_back({Requirement(RequirementKind::Layout, selfTy, layout), |
| 1071 | + proto->getLoc(), /*inferred=*/true}); |
| 1072 | + |
| 1073 | + // Remaining logic is not relevant to @objc protocols. |
| 1074 | + return ctx.AllocateCopy(result); |
| 1075 | + } |
| 1076 | + |
| 1077 | + // Add requirements for each of the associated types. |
| 1078 | + for (auto assocTypeDecl : proto->getAssociatedTypeMembers()) { |
| 1079 | + // Add requirements placed directly on this associated type. |
| 1080 | + auto assocType = assocTypeDecl->getDeclaredInterfaceType(); |
| 1081 | + addInheritedRequirements(assocTypeDecl, assocType, /*infer=*/false, |
| 1082 | + result); |
| 1083 | + |
| 1084 | + // Add requirements from this associated type's where clause. |
| 1085 | + WhereClauseOwner(assocTypeDecl).visitRequirements( |
| 1086 | + TypeResolutionStage::Structural, |
| 1087 | + [&](const Requirement &req, RequirementRepr *reqRepr) { |
| 1088 | + addRequirement(req, reqRepr, /*infer=*/false, result); |
| 1089 | + return false; |
| 1090 | + }); |
| 1091 | + } |
| 1092 | + |
| 1093 | + return ctx.AllocateCopy(result); |
| 1094 | +} |
| 1095 | + |
| 1096 | +ArrayRef<ProtocolDecl *> |
| 1097 | +ProtocolDependenciesRequest::evaluate(Evaluator &evaluator, |
| 1098 | + ProtocolDecl *proto) const { |
| 1099 | + auto &ctx = proto->getASTContext(); |
| 1100 | + SmallVector<ProtocolDecl *, 4> result; |
| 1101 | + |
| 1102 | + // If we have a serialized requirement signature, deserialize it and |
| 1103 | + // look at conformance requirements. |
| 1104 | + if (proto->hasLazyRequirementSignature()) { |
| 1105 | + for (auto req : proto->getRequirementSignature()) { |
| 1106 | + if (req.getKind() == RequirementKind::Conformance) { |
| 1107 | + result.push_back(req.getProtocolDecl()); |
| 1108 | + } |
| 1109 | + } |
| 1110 | + |
| 1111 | + return ctx.AllocateCopy(result); |
| 1112 | + } |
| 1113 | + |
| 1114 | + // Otherwise, we can't ask for the requirement signature, because |
| 1115 | + // this request is used as part of *building* the requirement |
| 1116 | + // signature. Look at the structural requirements instead. |
| 1117 | + for (auto req : proto->getStructuralRequirements()) { |
| 1118 | + if (req.req.getKind() == RequirementKind::Conformance) |
| 1119 | + result.push_back(req.req.getProtocolDecl()); |
| 1120 | + } |
| 1121 | + |
| 1122 | + return ctx.AllocateCopy(result); |
| 1123 | +} |
| 1124 | + |
872 | 1125 | ArrayRef<Requirement>
|
873 | 1126 | RequirementSignatureRequest::evaluate(Evaluator &evaluator,
|
874 | 1127 | ProtocolDecl *proto) const {
|
|
0 commit comments