|
25 | 25 | #include "RequirementLowering.h"
|
26 | 26 | #include "swift/AST/ASTContext.h"
|
27 | 27 | #include "swift/AST/Decl.h"
|
| 28 | +#include "swift/AST/ExistentialLayout.h" |
28 | 29 | #include "swift/AST/Requirement.h"
|
| 30 | +#include "swift/AST/TypeCheckRequests.h" |
| 31 | +#include "swift/AST/TypeMatcher.h" |
| 32 | +#include "swift/AST/TypeRepr.h" |
29 | 33 | #include "llvm/ADT/SmallVector.h"
|
30 | 34 | #include "RewriteContext.h"
|
31 | 35 | #include "RewriteSystem.h"
|
|
35 | 39 | using namespace swift;
|
36 | 40 | using namespace rewriting;
|
37 | 41 |
|
| 42 | +/// Desugar a protocol conformance requirement by splitting up protocol |
| 43 | +/// compositions on the right hand side until conformance and superclass |
| 44 | +/// requirements. |
| 45 | +static void addTypeRequirement(Type subjectType, Type constraintType, |
| 46 | + SourceLoc loc, bool wasInferred, |
| 47 | + SmallVectorImpl<StructuralRequirement> &result) { |
| 48 | + // Check whether we have a reasonable constraint type at all. |
| 49 | + if (!constraintType->isExistentialType() && |
| 50 | + !constraintType->getClassOrBoundGenericClass()) { |
| 51 | + // FIXME: Diagnose |
| 52 | + return; |
| 53 | + } |
| 54 | + |
| 55 | + // Protocol requirements. |
| 56 | + if (constraintType->isExistentialType()) { |
| 57 | + auto layout = constraintType->getExistentialLayout(); |
| 58 | + |
| 59 | + if (auto layoutConstraint = layout.getLayoutConstraint()) { |
| 60 | + result.push_back({ |
| 61 | + Requirement(RequirementKind::Layout, subjectType, layoutConstraint), |
| 62 | + loc, wasInferred}); |
| 63 | + } |
| 64 | + |
| 65 | + if (auto superclass = layout.explicitSuperclass) { |
| 66 | + result.push_back({ |
| 67 | + Requirement(RequirementKind::Superclass, subjectType, superclass), |
| 68 | + loc, wasInferred}); |
| 69 | + } |
| 70 | + |
| 71 | + for (auto *proto : layout.getProtocols()) { |
| 72 | + result.push_back({ |
| 73 | + Requirement(RequirementKind::Conformance, subjectType, proto), |
| 74 | + loc, wasInferred}); |
| 75 | + } |
| 76 | + |
| 77 | + return; |
| 78 | + } |
| 79 | + |
| 80 | + // Superclass constraint. |
| 81 | + result.push_back({ |
| 82 | + Requirement(RequirementKind::Superclass, subjectType, constraintType), |
| 83 | + loc, wasInferred}); |
| 84 | +} |
| 85 | + |
| 86 | +/// Desugar a same-type requirement that possibly has concrete types on either |
| 87 | +/// side into a series of same-type and concrete-type requirements where the |
| 88 | +/// left hand side is always a type parameter. |
| 89 | +static void addSameTypeRequirement(Type lhs, Type rhs, |
| 90 | + SourceLoc loc, bool wasInferred, |
| 91 | + SmallVectorImpl<StructuralRequirement> &result) { |
| 92 | + class Matcher : public TypeMatcher<Matcher> { |
| 93 | + SourceLoc loc; |
| 94 | + bool wasInferred; |
| 95 | + SmallVectorImpl<StructuralRequirement> &result; |
| 96 | + |
| 97 | + public: |
| 98 | + Matcher(SourceLoc loc, bool wasInferred, |
| 99 | + SmallVectorImpl<StructuralRequirement> &result) |
| 100 | + : loc(loc), wasInferred(wasInferred), result(result) {} |
| 101 | + |
| 102 | + bool mismatch(TypeBase *firstType, TypeBase *secondType, |
| 103 | + Type sugaredFirstType) { |
| 104 | + if (firstType->isTypeParameter() && secondType->isTypeParameter()) { |
| 105 | + result.push_back({Requirement(RequirementKind::SameType, |
| 106 | + firstType, secondType), |
| 107 | + loc, wasInferred}); |
| 108 | + return true; |
| 109 | + } |
| 110 | + |
| 111 | + if (firstType->isTypeParameter()) { |
| 112 | + result.push_back({Requirement(RequirementKind::SameType, |
| 113 | + firstType, secondType), |
| 114 | + loc, wasInferred}); |
| 115 | + return true; |
| 116 | + } |
| 117 | + |
| 118 | + if (secondType->isTypeParameter()) { |
| 119 | + result.push_back({Requirement(RequirementKind::SameType, |
| 120 | + secondType, firstType), |
| 121 | + loc, wasInferred}); |
| 122 | + return true; |
| 123 | + } |
| 124 | + |
| 125 | + // FIXME: Diagnose concrete type conflict |
| 126 | + return true; |
| 127 | + } |
| 128 | + } matcher(loc, wasInferred, result); |
| 129 | + |
| 130 | + // FIXME: If both sides concrete and was not inferred, diagnose redundancy |
| 131 | + // FIXME: If both sides are equal as type parameters and not inferred, |
| 132 | + // diagnose redundancy |
| 133 | + (void) matcher.match(lhs, rhs); |
| 134 | +} |
| 135 | + |
| 136 | +static void inferRequirements(Type type, SourceLoc loc, |
| 137 | + SmallVectorImpl<StructuralRequirement> &result) { |
| 138 | + // FIXME: Implement |
| 139 | +} |
| 140 | + |
| 141 | +static void addRequirement(Requirement req, RequirementRepr *reqRepr, bool infer, |
| 142 | + SmallVectorImpl<StructuralRequirement> &result) { |
| 143 | + auto firstType = req.getFirstType(); |
| 144 | + if (infer) { |
| 145 | + auto firstLoc = (reqRepr ? reqRepr->getFirstTypeRepr()->getStartLoc() |
| 146 | + : SourceLoc()); |
| 147 | + inferRequirements(firstType, firstLoc, result); |
| 148 | + } |
| 149 | + |
| 150 | + auto loc = (reqRepr ? reqRepr->getSeparatorLoc() : SourceLoc()); |
| 151 | + |
| 152 | + switch (req.getKind()) { |
| 153 | + case RequirementKind::Superclass: |
| 154 | + case RequirementKind::Conformance: { |
| 155 | + if (!firstType->isTypeParameter()) { |
| 156 | + // FIXME: Warn about redundancy if not inferred, diagnose conflicts |
| 157 | + break; |
| 158 | + } |
| 159 | + |
| 160 | + auto secondType = req.getSecondType(); |
| 161 | + if (infer) { |
| 162 | + auto secondLoc = (reqRepr ? reqRepr->getSecondTypeRepr()->getStartLoc() |
| 163 | + : SourceLoc()); |
| 164 | + inferRequirements(secondType, secondLoc, result); |
| 165 | + } |
| 166 | + |
| 167 | + addTypeRequirement(firstType, secondType, loc, /*wasInferred=*/false, |
| 168 | + result); |
| 169 | + break; |
| 170 | + } |
| 171 | + |
| 172 | + case RequirementKind::Layout: |
| 173 | + if (!firstType->isTypeParameter()) { |
| 174 | + // FIXME: Warn about redundancy if not inferred, diagnose conflicts |
| 175 | + break; |
| 176 | + } |
| 177 | + |
| 178 | + result.push_back({req, loc, /*wasInferred=*/false}); |
| 179 | + break; |
| 180 | + |
| 181 | + case RequirementKind::SameType: { |
| 182 | + auto secondType = req.getSecondType(); |
| 183 | + if (infer) { |
| 184 | + auto secondLoc = (reqRepr ? reqRepr->getSecondTypeRepr()->getStartLoc() |
| 185 | + : SourceLoc()); |
| 186 | + inferRequirements(secondType, secondLoc, result); |
| 187 | + } |
| 188 | + |
| 189 | + addSameTypeRequirement(firstType, secondType, loc, /*wasInferred=*/false, |
| 190 | + result); |
| 191 | + break; |
| 192 | + } |
| 193 | + } |
| 194 | +} |
| 195 | + |
| 196 | +static void addInheritedRequirements(TypeDecl *decl, Type type, bool infer, |
| 197 | + SmallVectorImpl<StructuralRequirement> &result) { |
| 198 | + auto &ctx = decl->getASTContext(); |
| 199 | + auto inheritedTypes = decl->getInherited(); |
| 200 | + |
| 201 | + for (unsigned index : indices(inheritedTypes)) { |
| 202 | + Type inheritedType |
| 203 | + = evaluateOrDefault(ctx.evaluator, |
| 204 | + InheritedTypeRequest{decl, index, |
| 205 | + TypeResolutionStage::Structural}, |
| 206 | + Type()); |
| 207 | + if (!inheritedType) continue; |
| 208 | + |
| 209 | + auto *typeRepr = inheritedTypes[index].getTypeRepr(); |
| 210 | + SourceLoc loc = (typeRepr ? typeRepr->getStartLoc() : SourceLoc()); |
| 211 | + if (infer) { |
| 212 | + inferRequirements(inheritedType, loc, result); |
| 213 | + } |
| 214 | + |
| 215 | + addTypeRequirement(type, inheritedType, loc, /*wasInferred=*/false, |
| 216 | + result); |
| 217 | + } |
| 218 | +} |
| 219 | + |
| 220 | +ArrayRef<StructuralRequirement> |
| 221 | +StructuralRequirementsRequest::evaluate(Evaluator &evaluator, |
| 222 | + ProtocolDecl *proto) const { |
| 223 | + assert(!proto->hasLazyRequirementSignature()); |
| 224 | + |
| 225 | + SmallVector<StructuralRequirement, 4> result; |
| 226 | + |
| 227 | + auto &ctx = proto->getASTContext(); |
| 228 | + |
| 229 | + auto selfTy = proto->getSelfInterfaceType(); |
| 230 | + |
| 231 | + addInheritedRequirements(proto, selfTy, |
| 232 | + /*infer=*/false, result); |
| 233 | + |
| 234 | + // Add requirements from the protocol's own 'where' clause. |
| 235 | + WhereClauseOwner(proto).visitRequirements(TypeResolutionStage::Structural, |
| 236 | + [&](const Requirement &req, RequirementRepr *reqRepr) { |
| 237 | + addRequirement(req, reqRepr, /*infer=*/false, result); |
| 238 | + return false; |
| 239 | + }); |
| 240 | + |
| 241 | + if (proto->isObjC()) { |
| 242 | + // @objc protocols have an implicit AnyObject requirement on Self. |
| 243 | + auto layout = LayoutConstraint::getLayoutConstraint( |
| 244 | + LayoutConstraintKind::Class, ctx); |
| 245 | + result.push_back({Requirement(RequirementKind::Layout, selfTy, layout), |
| 246 | + proto->getLoc(), /*inferred=*/true}); |
| 247 | + |
| 248 | + // Remaining logic is not relevant to @objc protocols. |
| 249 | + return ctx.AllocateCopy(result); |
| 250 | + } |
| 251 | + |
| 252 | + // Add requirements for each of the associated types. |
| 253 | + for (auto assocTypeDecl : proto->getAssociatedTypeMembers()) { |
| 254 | + // Add requirements placed directly on this associated type. |
| 255 | + auto assocType = assocTypeDecl->getDeclaredInterfaceType(); |
| 256 | + addInheritedRequirements(assocTypeDecl, assocType, /*infer=*/false, |
| 257 | + result); |
| 258 | + |
| 259 | + // Add requirements from this associated type's where clause. |
| 260 | + WhereClauseOwner(assocTypeDecl).visitRequirements( |
| 261 | + TypeResolutionStage::Structural, |
| 262 | + [&](const Requirement &req, RequirementRepr *reqRepr) { |
| 263 | + addRequirement(req, reqRepr, /*infer=*/false, result); |
| 264 | + return false; |
| 265 | + }); |
| 266 | + } |
| 267 | + |
| 268 | + return ctx.AllocateCopy(result); |
| 269 | +} |
| 270 | + |
| 271 | +ArrayRef<ProtocolDecl *> |
| 272 | +ProtocolDependenciesRequest::evaluate(Evaluator &evaluator, |
| 273 | + ProtocolDecl *proto) const { |
| 274 | + auto &ctx = proto->getASTContext(); |
| 275 | + SmallVector<ProtocolDecl *, 4> result; |
| 276 | + |
| 277 | + // If we have a serialized requirement signature, deserialize it and |
| 278 | + // look at conformance requirements. |
| 279 | + // |
| 280 | + // FIXME: For now we just fall back to the GSB for all protocols |
| 281 | + // unless -requirement-machine-protocol-signatures=on is passed. |
| 282 | + if (proto->hasLazyRequirementSignature() || |
| 283 | + (ctx.LangOpts.RequirementMachineProtocolSignatures |
| 284 | + == RequirementMachineMode::Disabled)) { |
| 285 | + for (auto req : proto->getRequirementSignature()) { |
| 286 | + if (req.getKind() == RequirementKind::Conformance) { |
| 287 | + result.push_back(req.getProtocolDecl()); |
| 288 | + } |
| 289 | + } |
| 290 | + |
| 291 | + return ctx.AllocateCopy(result); |
| 292 | + } |
| 293 | + |
| 294 | + // Otherwise, we can't ask for the requirement signature, because |
| 295 | + // this request is used as part of *building* the requirement |
| 296 | + // signature. Look at the structural requirements instead. |
| 297 | + for (auto req : proto->getStructuralRequirements()) { |
| 298 | + if (req.req.getKind() == RequirementKind::Conformance) |
| 299 | + result.push_back(req.req.getProtocolDecl()); |
| 300 | + } |
| 301 | + |
| 302 | + return ctx.AllocateCopy(result); |
| 303 | +} |
| 304 | + |
38 | 305 | /// Given a concrete type that may contain type parameters in structural positions,
|
39 | 306 | /// collect all the structural type parameter components, and replace them all with
|
40 | 307 | /// fresh generic parameters. The fresh generic parameters all have a depth of 0,
|
|
0 commit comments