Skip to content

Commit 031e70f

Browse files
committed
Reimplement NormalProtocolConformance::getAssocated{Type|Conformance}.
Reimplement these methods, making use of Type::subst() for the former and the stored protocol conformances that correspond to the protocol's requirement signature for the latter. This is enough to emit witness tables with indirect conformance requirements in them.
1 parent 730ecfe commit 031e70f

File tree

2 files changed

+76
-68
lines changed

2 files changed

+76
-68
lines changed

lib/AST/ProtocolConformance.cpp

Lines changed: 26 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -336,50 +336,35 @@ void NormalProtocolConformance::setTypeWitness(
336336
TypeWitnesses[assocType] = std::make_pair(substitution, typeDecl);
337337
}
338338

339-
/// TypeWitnesses is keyed by the protocol's own declarations, but
340-
/// DependentMemberTypes will sometimes store a base protocol's declaration.
341-
/// Map to the derived declaration if possible.
342-
static AssociatedTypeDecl *getOwnAssociatedTypeDecl(ProtocolDecl *protocol,
343-
AssociatedTypeDecl *assoc) {
344-
// Fast path.
345-
if (assoc->getProtocol() == protocol) return assoc;
346-
347-
// Search the protocol.
348-
for (auto member : protocol->getMembers()) {
349-
if (auto memberAssoc = dyn_cast<AssociatedTypeDecl>(member)) {
350-
if (memberAssoc->getName() == assoc->getName()) {
351-
return memberAssoc;
352-
}
353-
}
354-
}
355-
356-
// Just assume this is fine.
357-
return assoc;
358-
}
359-
360339
Type NormalProtocolConformance::getAssociatedType(Type assocType,
361340
LazyResolver *resolver) const {
362341
assert(assocType->isTypeParameter() &&
363342
"associated type must be a type parameter");
364343

365-
// Fast path.
366344
auto type = assocType->getCanonicalType();
345+
auto proto = getProtocol();
346+
347+
#if false
348+
// Fast path for generic parameters.
367349
if (isa<GenericTypeParamType>(type)) {
368-
assert(type->isEqual(getProtocol()->getSelfInterfaceType()) &&
350+
assert(type->isEqual(proto->getSelfInterfaceType()) &&
369351
"type parameter in protocol was not Self");
370352
return getType();
371353
}
372354

355+
// Fast path for dependent member types on 'Self' of our associated types.
373356
auto memberType = cast<DependentMemberType>(type);
357+
if (memberType.getBase()->isEqual(proto->getProtocolSelfType()) &&
358+
memberType->getAssocType()->getProtocol() == proto)
359+
return getTypeWitness(memberType->getAssocType(), nullptr).getReplacement();
360+
#endif
374361

375-
// TODO: make this handle multiple levels of dependent member type.
376-
assert(memberType.getBase()->isEqual(getProtocol()->getSelfInterfaceType()) &&
377-
"dependent member in protocol was not rooted in Self");
378-
379-
auto assocTypeDecl =
380-
getOwnAssociatedTypeDecl(getProtocol(), memberType->getAssocType());
381-
auto &subst = getTypeWitnessSubstAndDecl(assocTypeDecl, resolver).first;
382-
return subst.getReplacement();
362+
// General case: consult the substitution map.
363+
auto self = const_cast<NormalProtocolConformance *>(this);
364+
auto substMap =
365+
SubstitutionMap::getProtocolSubstitutions(proto, getType(),
366+
ProtocolConformanceRef(self));
367+
return type.subst(substMap);
383368
}
384369

385370
ProtocolConformanceRef
@@ -389,48 +374,21 @@ NormalProtocolConformance::getAssociatedConformance(Type assocType,
389374
assert(assocType->isTypeParameter() &&
390375
"associated type must be a type parameter");
391376

392-
#ifndef NDEBUG
393-
bool foundInRequirements = false;
377+
unsigned conformanceIndex = 0;
394378
for (auto &reqt :
395379
getProtocol()->getRequirementSignature()->getRequirements()) {
396-
if (reqt.getKind() == RequirementKind::Conformance &&
397-
reqt.getFirstType()->isEqual(assocType) &&
398-
reqt.getSecondType()->castTo<ProtocolType>()->getDecl() == protocol) {
399-
foundInRequirements = true;
400-
break;
401-
}
402-
}
403-
assert(foundInRequirements &&
404-
"requested conformance was not a direct requirement of the protocol");
405-
#endif
406-
407-
auto type = assocType->getCanonicalType();
380+
if (reqt.getKind() == RequirementKind::Conformance) {
381+
// Is this the conformance we're looking for?
382+
if (reqt.getFirstType()->isEqual(assocType) &&
383+
reqt.getSecondType()->castTo<ProtocolType>()->getDecl() == protocol)
384+
return getSignatureConformances()[conformanceIndex];
408385

409-
if (isa<GenericTypeParamType>(type)) {
410-
assert(type->isEqual(getProtocol()->getSelfInterfaceType()) &&
411-
"type parameter in protocol was not Self");
412-
auto conf = getInheritedConformance(protocol);
413-
assert(conf && "inherited conformances cannot be abstract");
414-
return ProtocolConformanceRef(conf);
386+
++conformanceIndex;
387+
}
415388
}
416389

417-
auto memberType = cast<DependentMemberType>(type);
418-
419-
// For now, NormalProtocolConformance does not store indirect associations.
420-
assert(memberType.getBase()->isEqual(getProtocol()->getSelfInterfaceType()) &&
421-
"dependent member in protocol was not rooted in Self");
422-
423-
auto assocTypeDecl =
424-
getOwnAssociatedTypeDecl(getProtocol(), memberType->getAssocType());
425-
auto &subst = getTypeWitnessSubstAndDecl(assocTypeDecl, resolver).first;
426-
427-
// Scan the conformances for the exact conformance.
428-
// TODO: should we allow indirect conformances for convenience of use?
429-
for (auto &conf : subst.getConformances()) {
430-
if (conf.getRequirement() == protocol)
431-
return conf;
432-
}
433-
llvm_unreachable("missing conformance to protocol");
390+
llvm_unreachable(
391+
"requested conformance was not a direct requirement of the protocol");
434392
}
435393

436394
/// Retrieve the value witness corresponding to the given requirement.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// RUN: %target-swift-frontend -Xllvm -new-mangling-for-tests -assume-parsing-unqualified-ownership-sil -primary-file %s -emit-ir -disable-objc-attr-requires-foundation-module -swift-version 4 | %FileCheck %s
2+
3+
protocol P1 {
4+
associatedtype AssocP1
5+
}
6+
7+
protocol P2 {
8+
associatedtype AssocP2: P1
9+
10+
func getAssocP2() -> AssocP2
11+
}
12+
13+
protocol P3 {
14+
associatedtype AssocP3: P2 where AssocP3.AssocP2: Q
15+
16+
func getAssocP3() -> AssocP3
17+
}
18+
19+
protocol Q { }
20+
21+
struct X { }
22+
23+
struct Y: P1, Q {
24+
typealias AssocP1 = X
25+
}
26+
27+
struct Z: P2 {
28+
typealias AssocP2 = Y
29+
30+
func getAssocP2() -> Y { return Y() }
31+
}
32+
33+
// CHECK: @_T035witness_table_indirect_conformances1WVAA2P3AAWP = hidden constant [4 x i8*] [i8* bitcast (%swift.type* ()* @_T035witness_table_indirect_conformances1ZVMa to i8*), i8* bitcast (i8** ()* @_T035witness_table_indirect_conformances1ZVAA2P2AAWa to i8*), i8* bitcast (i8** ()* @_T035witness_table_indirect_conformances1YVAA1QAAWa to i8*), i8* bitcast (void (%T35witness_table_indirect_conformances1ZV*, %T35witness_table_indirect_conformances1WV*, %swift.type*, i8**)* @_T035witness_table_indirect_conformances1WVAA2P3A2aDP08getAssocE00gE0QzyFTW to i8*)]
34+
struct W: P3 {
35+
typealias AssocP3 = Z
36+
37+
func getAssocP3() -> Z { return Z() }
38+
}
39+
40+
// CHECK-LABEL: define hidden i8** @_T035witness_table_indirect_conformances1YVAA1QAAWa()
41+
// CHECK-NEXT: entry:
42+
// CHECK-NEXT: ret i8** getelementptr inbounds ([0 x i8*], [0 x i8*]* @_T035witness_table_indirect_conformances1YVAA1QAAWP, i32 0, i32 0)
43+
44+
// CHECK-LABEL: define hidden i8** @_T035witness_table_indirect_conformances1ZVAA2P2AAWa()
45+
// CHECK-NEXT: entry:
46+
// CHECK: ret i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @_T035witness_table_indirect_conformances1ZVAA2P2AAWP, i32 0, i32 0)
47+
48+
// CHECK-LABEL: define hidden %swift.type* @_T035witness_table_indirect_conformances1ZVMa()
49+
// CHECK-NEXT: entry:
50+
// CHECK-NEXT: ret %swift.type* bitcast {{.*}} @_T035witness_table_indirect_conformances1ZVMf, i32 0, i32 1) to %swift.type*

0 commit comments

Comments
 (0)