|
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