|
20 | 20 | #include "swift/AST/Availability.h" |
21 | 21 | #include "swift/AST/ConformanceLookup.h" |
22 | 22 | #include "swift/AST/Decl.h" |
| 23 | +#include "swift/AST/GenericEnvironment.h" |
23 | 24 | #include "swift/AST/InFlightSubstitution.h" |
24 | 25 | #include "swift/AST/Module.h" |
25 | 26 | #include "swift/AST/PackConformance.h" |
@@ -163,8 +164,7 @@ ProtocolConformanceRef::getTypeWitnessByName(Type type, Identifier name) const { |
163 | 164 | if (!assocType) |
164 | 165 | return ErrorType::get(proto->getASTContext()); |
165 | 166 |
|
166 | | - return assocType->getDeclaredInterfaceType().subst( |
167 | | - SubstitutionMap::getProtocolSubstitutions(proto, type, *this)); |
| 167 | + return getTypeWitness(type, assocType); |
168 | 168 | } |
169 | 169 |
|
170 | 170 | ConcreteDeclRef |
@@ -194,78 +194,115 @@ ProtocolConformanceRef::getConditionalRequirements() const { |
194 | 194 | return {}; |
195 | 195 | } |
196 | 196 |
|
197 | | -Type ProtocolConformanceRef::getAssociatedType(Type conformingType, |
198 | | - Type assocType) const { |
| 197 | +Type ProtocolConformanceRef::getTypeWitness(Type conformingType, |
| 198 | + AssociatedTypeDecl *assocType, |
| 199 | + SubstOptions options) const { |
199 | 200 | if (isPack()) { |
200 | 201 | auto *pack = getPack(); |
201 | 202 | ASSERT(conformingType->isEqual(pack->getType())); |
202 | | - return pack->getAssociatedType(assocType); |
| 203 | + return pack->getTypeWitness(assocType); |
203 | 204 | } |
204 | 205 |
|
205 | | - auto type = assocType->getCanonicalType(); |
206 | | - |
207 | | - // Fast path for generic parameters. |
208 | | - if (auto paramTy = dyn_cast<GenericTypeParamType>(type)) { |
209 | | - ASSERT(paramTy->getDepth() == 0 && paramTy->getIndex() == 0 && |
210 | | - "type parameter in protocol was not Self"); |
211 | | - return conformingType; |
212 | | - } |
| 206 | + auto failed = [&]() { |
| 207 | + return DependentMemberType::get(ErrorType::get(conformingType), |
| 208 | + assocType); |
| 209 | + }; |
213 | 210 |
|
214 | 211 | if (isInvalid()) |
215 | | - return ErrorType::get(assocType->getASTContext()); |
| 212 | + return failed(); |
216 | 213 |
|
217 | 214 | auto proto = getRequirement(); |
| 215 | + ASSERT(assocType->getProtocol() == proto); |
218 | 216 |
|
219 | 217 | if (isConcrete()) { |
220 | | - if (auto selfType = conformingType->getAs<DynamicSelfType>()) |
221 | | - conformingType = selfType->getSelfType(); |
222 | | - ASSERT(getConcrete()->getType()->isEqual(conformingType)); |
223 | | - |
224 | | - // Fast path for dependent member types on 'Self' of our associated types. |
225 | | - auto memberType = cast<DependentMemberType>(type); |
226 | | - if (memberType.getBase()->isEqual(proto->getSelfInterfaceType()) && |
227 | | - memberType->getAssocType()->getProtocol() == proto) { |
228 | | - auto witnessType = getConcrete()->getTypeWitness( |
229 | | - memberType->getAssocType()); |
230 | | - if (!witnessType) |
231 | | - return ErrorType::get(assocType->getASTContext()); |
232 | | - return witnessType; |
233 | | - } |
| 218 | + auto witnessType = getConcrete()->getTypeWitness(assocType, options); |
| 219 | + if (!witnessType || witnessType->is<ErrorType>()) |
| 220 | + return failed(); |
| 221 | + return witnessType; |
234 | 222 | } |
235 | 223 |
|
236 | | - // General case: consult the substitution map. |
| 224 | + ASSERT(isAbstract()); |
| 225 | + |
| 226 | + if (auto *archetypeType = conformingType->getAs<ArchetypeType>()) { |
| 227 | + return archetypeType->getNestedType(assocType); |
| 228 | + } |
| 229 | + |
| 230 | + CONDITIONAL_ASSERT(conformingType->isTypeParameter() || |
| 231 | + conformingType->isTypeVariableOrMember() || |
| 232 | + conformingType->is<UnresolvedType>() || |
| 233 | + conformingType->is<PlaceholderType>()); |
| 234 | + |
| 235 | + return DependentMemberType::get(conformingType, assocType); |
| 236 | +} |
| 237 | + |
| 238 | +Type ProtocolConformanceRef::getAssociatedType(Type conformingType, |
| 239 | + Type assocType) const { |
| 240 | + if (isInvalid()) |
| 241 | + return ErrorType::get(assocType->getASTContext()); |
| 242 | + |
| 243 | + auto proto = getRequirement(); |
| 244 | + |
237 | 245 | auto substMap = |
238 | 246 | SubstitutionMap::getProtocolSubstitutions(proto, conformingType, *this); |
239 | | - return type.subst(substMap); |
| 247 | + return assocType.subst(substMap); |
240 | 248 | } |
241 | 249 |
|
242 | 250 | ProtocolConformanceRef |
243 | 251 | ProtocolConformanceRef::getAssociatedConformance(Type conformingType, |
244 | 252 | Type assocType, |
245 | 253 | ProtocolDecl *protocol) const { |
246 | | - // If this is a pack conformance, project the associated conformances. |
| 254 | + // If this is a pack conformance, project the associated conformances from |
| 255 | + // each pack element. |
247 | 256 | if (isPack()) { |
248 | 257 | auto *pack = getPack(); |
249 | 258 | assert(conformingType->isEqual(pack->getType())); |
250 | 259 | return ProtocolConformanceRef( |
251 | 260 | pack->getAssociatedConformance(assocType, protocol)); |
252 | 261 | } |
253 | 262 |
|
254 | | - // If this is a concrete conformance, look up the associated conformance. |
| 263 | + // If this is a concrete conformance, project the associated conformance. |
255 | 264 | if (isConcrete()) { |
256 | 265 | auto conformance = getConcrete(); |
257 | 266 | assert(conformance->getType()->isEqual(conformingType)); |
258 | 267 | return conformance->getAssociatedConformance(assocType, protocol); |
259 | 268 | } |
260 | 269 |
|
261 | | - // Otherwise, apply the substitution {self -> conformingType} |
262 | | - // to the abstract conformance requirement laid upon the dependent type |
263 | | - // by the protocol. |
264 | | - auto subMap = |
265 | | - SubstitutionMap::getProtocolSubstitutions(getRequirement(), |
266 | | - conformingType, *this); |
267 | | - auto abstractConf = ProtocolConformanceRef(protocol); |
268 | | - return abstractConf.subst(assocType, subMap); |
| 270 | + // An associated conformance of an archetype might be known to be |
| 271 | + // a concrete conformance, if the subject type is fixed to a concrete |
| 272 | + // type in the archetype's generic signature. We don't actually have |
| 273 | + // any way to recover the conformance in this case, except via global |
| 274 | + // conformance lookup. |
| 275 | + // |
| 276 | + // However, if we move to a first-class representation of abstract |
| 277 | + // conformances where they store their subject types, we can also |
| 278 | + // cache the lookups inside the abstract conformance instance too. |
| 279 | + if (auto archetypeType = conformingType->getAs<ArchetypeType>()) { |
| 280 | + conformingType = archetypeType->getInterfaceType(); |
| 281 | + auto *genericEnv = archetypeType->getGenericEnvironment(); |
| 282 | + |
| 283 | + auto subjectType = assocType.transformRec( |
| 284 | + [&](TypeBase *t) -> std::optional<Type> { |
| 285 | + if (isa<GenericTypeParamType>(t)) |
| 286 | + return conformingType; |
| 287 | + return std::nullopt; |
| 288 | + }); |
| 289 | + |
| 290 | + return lookupConformance( |
| 291 | + genericEnv->mapTypeIntoContext(subjectType), |
| 292 | + protocol); |
| 293 | + } |
| 294 | + |
| 295 | + // Associated conformances of type parameters and type variables |
| 296 | + // are always abstract, because we don't know the output generic |
| 297 | + // signature of the substitution (or in the case of type variables, |
| 298 | + // we have no visibility into constraints). See the parallel hack |
| 299 | + // to handle this in SubstitutionMap::lookupConformance(). |
| 300 | + CONDITIONAL_ASSERT(conformingType->isTypeParameter() || |
| 301 | + conformingType->isTypeVariableOrMember() || |
| 302 | + conformingType->is<UnresolvedType>() || |
| 303 | + conformingType->is<PlaceholderType>()); |
| 304 | + |
| 305 | + return ProtocolConformanceRef(protocol); |
269 | 306 | } |
270 | 307 |
|
271 | 308 | /// Check of all types used by the conformance are canonical. |
|
0 commit comments