|
18 | 18 | #include "swift/AST/ASTContext.h"
|
19 | 19 | #include "swift/AST/GenericSignatureBuilder.h"
|
20 | 20 | #include "swift/AST/ProtocolConformance.h"
|
| 21 | +#include "swift/Basic/Defer.h" |
21 | 22 | #include "GenericSignatureBuilderImpl.h"
|
22 | 23 |
|
23 | 24 | using namespace swift;
|
@@ -117,6 +118,128 @@ Type TypeBase::mapTypeOutOfContext() {
|
117 | 118 | SubstFlags::AllowLoweredTypes);
|
118 | 119 | }
|
119 | 120 |
|
| 121 | +Type |
| 122 | +GenericSignatureBuilder::EquivalenceClass::getTypeInContext( |
| 123 | + GenericSignatureBuilder &builder, GenericEnvironment *genericEnv) { |
| 124 | + auto genericParams = genericEnv->getGenericParams(); |
| 125 | + |
| 126 | + // The anchor descr |
| 127 | + Type anchor = getAnchor(builder, genericParams); |
| 128 | + |
| 129 | + // If this equivalence class is mapped to a concrete type, produce that |
| 130 | + // type. |
| 131 | + if (concreteType) { |
| 132 | + if (recursiveConcreteType) |
| 133 | + return ErrorType::get(anchor); |
| 134 | + |
| 135 | + // Prevent recursive substitution. |
| 136 | + this->recursiveConcreteType = true; |
| 137 | + SWIFT_DEFER { |
| 138 | + this->recursiveConcreteType = false; |
| 139 | + }; |
| 140 | + |
| 141 | + return genericEnv->mapTypeIntoContext(concreteType, |
| 142 | + builder.getLookupConformanceFn()); |
| 143 | + } |
| 144 | + |
| 145 | + // Local function to check whether we have a generic parameter that has |
| 146 | + // already been recorded |
| 147 | + auto getAlreadyRecoveredGenericParam = [&]() -> Type { |
| 148 | + auto genericParam = anchor->getAs<GenericTypeParamType>(); |
| 149 | + if (!genericParam) return Type(); |
| 150 | + |
| 151 | + auto type = genericEnv->getMappingIfPresent(genericParam); |
| 152 | + if (!type) return Type(); |
| 153 | + |
| 154 | + // We already have a mapping for this generic parameter in the generic |
| 155 | + // environment. Return it. |
| 156 | + return *type; |
| 157 | + }; |
| 158 | + |
| 159 | + AssociatedTypeDecl *assocType = nullptr; |
| 160 | + ArchetypeType *parentArchetype = nullptr; |
| 161 | + if (auto depMemTy = anchor->getAs<DependentMemberType>()) { |
| 162 | + // Resolve the equivalence class of the parent. |
| 163 | + auto parentEquivClass = |
| 164 | + builder.resolveEquivalenceClass( |
| 165 | + depMemTy->getBase(), |
| 166 | + ArchetypeResolutionKind::CompleteWellFormed); |
| 167 | + if (!parentEquivClass) |
| 168 | + return ErrorType::get(anchor); |
| 169 | + |
| 170 | + // Map the parent type into this context. |
| 171 | + parentArchetype = |
| 172 | + parentEquivClass->getTypeInContext(builder, genericEnv) |
| 173 | + ->castTo<ArchetypeType>(); |
| 174 | + |
| 175 | + // If we already have a nested type with this name, return it. |
| 176 | + assocType = depMemTy->getAssocType(); |
| 177 | + if (auto nested = |
| 178 | + parentArchetype->getNestedTypeIfKnown(assocType->getName())) { |
| 179 | + return *nested; |
| 180 | + } |
| 181 | + |
| 182 | + // We will build the archetype below. |
| 183 | + } else if (auto result = getAlreadyRecoveredGenericParam()) { |
| 184 | + // Return already-contextualized generic type parameter. |
| 185 | + return result; |
| 186 | + } |
| 187 | + |
| 188 | + // Substitute into the superclass. |
| 189 | + Type superclass = this->recursiveSuperclassType ? Type() : this->superclass; |
| 190 | + if (superclass && superclass->hasTypeParameter()) { |
| 191 | + // Prevent recursive substitution. |
| 192 | + this->recursiveSuperclassType = true; |
| 193 | + SWIFT_DEFER { |
| 194 | + this->recursiveSuperclassType = false; |
| 195 | + }; |
| 196 | + |
| 197 | + superclass = genericEnv->mapTypeIntoContext( |
| 198 | + superclass, |
| 199 | + builder.getLookupConformanceFn()); |
| 200 | + if (superclass->is<ErrorType>()) |
| 201 | + superclass = Type(); |
| 202 | + |
| 203 | + // We might have recursively recorded the archetype; if so, return early. |
| 204 | + // FIXME: This should be detectable before we end up building archetypes. |
| 205 | + if (auto result = getAlreadyRecoveredGenericParam()) |
| 206 | + return result; |
| 207 | + } |
| 208 | + |
| 209 | + // Build a new archetype. |
| 210 | + |
| 211 | + // Collect the protocol conformances for the archetype. |
| 212 | + SmallVector<ProtocolDecl *, 4> protos; |
| 213 | + for (const auto &conforms : conformsTo) { |
| 214 | + auto proto = conforms.first; |
| 215 | + |
| 216 | + if (!isConformanceSatisfiedBySuperclass(proto)) |
| 217 | + protos.push_back(proto); |
| 218 | + } |
| 219 | + |
| 220 | + ArchetypeType *archetype; |
| 221 | + ASTContext &ctx = builder.getASTContext(); |
| 222 | + if (parentArchetype) { |
| 223 | + // Create a nested archetype. |
| 224 | + auto *depMemTy = anchor->castTo<DependentMemberType>(); |
| 225 | + archetype = NestedArchetypeType::getNew(ctx, parentArchetype, depMemTy, |
| 226 | + protos, superclass, layout); |
| 227 | + |
| 228 | + // Register this archetype with its parent. |
| 229 | + parentArchetype->registerNestedType(assocType->getName(), archetype); |
| 230 | + } else { |
| 231 | + // Create a top-level archetype. |
| 232 | + auto genericParam = anchor->castTo<GenericTypeParamType>(); |
| 233 | + archetype = PrimaryArchetypeType::getNew(ctx, genericEnv, genericParam, |
| 234 | + protos, superclass, layout); |
| 235 | + |
| 236 | + // Register the archetype with the generic environment. |
| 237 | + genericEnv->addMapping(genericParam, archetype); |
| 238 | + } |
| 239 | + |
| 240 | + return archetype; |
| 241 | +} |
| 242 | + |
120 | 243 | void ArchetypeType::resolveNestedType(
|
121 | 244 | std::pair<Identifier, Type> &nested) const {
|
122 | 245 | auto genericEnv = getGenericEnvironment();
|
|
0 commit comments