Skip to content

Commit 063e755

Browse files
committed
Merge pull request #2456 from jckarter/sr1323
AST: More robust rewrite of ProtocolConformance::getInheritedConformance.
2 parents 2210eff + 01f98fa commit 063e755

File tree

3 files changed

+61
-47
lines changed

3 files changed

+61
-47
lines changed

lib/AST/ProtocolConformance.cpp

Lines changed: 42 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -468,69 +468,65 @@ ProtocolConformance *ProtocolConformance::subst(Module *module,
468468

469469
ProtocolConformance *
470470
ProtocolConformance::getInheritedConformance(ProtocolDecl *protocol) const {
471-
// Preserve specialization through this operation by peeling off the
472-
// substitutions from a specialized conformance so we can apply them later.
473-
const ProtocolConformance *unspecialized;
474-
SubstitutionIterator subs;
471+
auto &C = getProtocol()->getASTContext();
472+
// Preserve specialization and class inheritance through this operation by
473+
// reapplying them to the conformance we find.
475474
switch (getKind()) {
476475
case ProtocolConformanceKind::Specialized: {
477476
auto spec = cast<SpecializedProtocolConformance>(this);
478-
unspecialized = spec->getGenericConformance();
479-
subs = spec->getGenericSubstitutionIterator();
480-
break;
477+
auto inherited = spec->getGenericConformance()
478+
->getInheritedConformance(protocol);
479+
assert(inherited->getType()->isEqual(spec->getGenericConformance()->getType())
480+
&& "inherited conformance doesn't match type?!");
481+
482+
TypeSubstitutionMap subMap;
483+
ArchetypeConformanceMap conformanceMap;
484+
485+
// Fill in the substitution and conformance maps.
486+
for (auto archAndSub : spec->getGenericSubstitutionIterator()) {
487+
auto arch = archAndSub.first;
488+
auto sub = archAndSub.second;
489+
conformanceMap[arch] = sub.getConformances();
490+
if (arch->isPrimary())
491+
subMap[arch] = sub.getReplacement();
492+
}
493+
auto r = inherited->subst(getDeclContext()->getParentModule(),
494+
getType(), spec->getGenericSubstitutions(),
495+
subMap, conformanceMap);
496+
assert(getType()->isEqual(r->getType())
497+
&& "substitution didn't produce conformance for same type?!");
498+
return r;
481499
}
482500

501+
case ProtocolConformanceKind::Inherited: {
502+
auto classInherited = cast<InheritedProtocolConformance>(this);
503+
auto protoInherited = classInherited->getInheritedConformance()
504+
->getInheritedConformance(protocol);
505+
assert(protoInherited->getType()->isEqual(
506+
classInherited->getInheritedConformance()->getType())
507+
&& "inherited conformance doesn't match type?!");
508+
return C.getInheritedConformance(classInherited->getType(),
509+
protoInherited);
510+
}
511+
483512
case ProtocolConformanceKind::Normal:
484-
case ProtocolConformanceKind::Inherited:
485-
unspecialized = this;
513+
// For a normal conformance, do the inheritance lookup.
486514
break;
487515
}
488516

489-
490-
ProtocolConformance *foundInherited;
491-
492517
// Search for the inherited conformance among our immediate parents.
493-
auto &inherited = unspecialized->getInheritedConformances();
518+
auto &inherited = getInheritedConformances();
494519
auto known = inherited.find(protocol);
495-
if (known != inherited.end()) {
496-
foundInherited = known->second;
497-
goto found_inherited;
498-
}
520+
if (known != inherited.end())
521+
return known->second;
499522

500523
// If not there, the inherited conformance must be available through one of
501524
// our parents.
502525
for (auto &inheritedMapping : inherited)
503-
if (inheritedMapping.first->inheritsFrom(protocol)) {
504-
foundInherited = inheritedMapping.second->
505-
getInheritedConformance(protocol);
506-
goto found_inherited;
507-
}
526+
if (inheritedMapping.first->inheritsFrom(protocol))
527+
return inheritedMapping.second->getInheritedConformance(protocol);
508528

509529
llvm_unreachable("Can't find the inherited conformance.");
510-
511-
found_inherited:
512-
513-
// Specialize the inherited conformance, if necessary.
514-
if (!subs.empty()) {
515-
TypeSubstitutionMap subMap;
516-
ArchetypeConformanceMap conformanceMap;
517-
518-
// Fill in the substitution and conformance maps.
519-
for (auto archAndSub : subs) {
520-
auto arch = archAndSub.first;
521-
auto sub = archAndSub.second;
522-
conformanceMap[arch] = sub.getConformances();
523-
if (arch->isPrimary())
524-
subMap[arch] = sub.getReplacement();
525-
}
526-
return foundInherited->subst(getDeclContext()->getParentModule(),
527-
getType(), subs.getSubstitutions(),
528-
subMap, conformanceMap);
529-
}
530-
assert((getType()->isEqual(foundInherited->getType()) ||
531-
foundInherited->getType()->isExactSuperclassOf(getType(), nullptr))
532-
&& "inherited conformance does not match type");
533-
return foundInherited;
534530
}
535531

536532
#pragma mark Protocol conformance lookup
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %target-swift-frontend -emit-sil -O %s | FileCheck %s
2+
3+
protocol P { func p() -> Any.Type }
4+
protocol Q: P { }
5+
6+
@inline(never) func sink<T>(_ x: T) {}
7+
8+
func p<T: Q>(_ x: T) { sink(x.p()) }
9+
10+
class Foo<T>: Q { func p() -> Any.Type { return T.self } }
11+
class Bar<T>: Foo<T> {}
12+
13+
// CHECK-LABEL: sil @_TF48specialize_class_inherits_base_inherits_protocol3fooFT_T_
14+
public func foo() {
15+
// CHECK: function_ref @_TTSf4d___TTSg5PMP____TF48specialize_class_inherits_base_inherits_protocol4sinkurFxT_
16+
p(Bar<Int>())
17+
}
18+

test/SILOptimizer/specialize_inherited.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ bb0(%0 : $Int, %1 : $Int):
3939

4040
// CHECK-LABEL: @_TTSg5C7inherit8MMStringCS_8MMObjects8HashableS__GSQCS_6MMFont___callee : $@convention(method) (@owned MMString, Int, @owned MMStorage<MMString, ImplicitlyUnwrappedOptional<MMFont>>) -> Bool {
4141
// CHECK: [[META:%[0-9]+]] = metatype $@thick MMString.Type
42-
// CHECK: [[ID3:%[0-9]+]] = witness_method $MMObject, #Equatable."=="!1 :
42+
// CHECK: [[ID3:%[0-9]+]] = witness_method $MMString, #Equatable."=="!1 :
4343
// CHECK: [[STACK2:%[0-9]+]] = alloc_stack $MMString
4444
// CHECK: [[STACK3:%[0-9]+]] = alloc_stack $MMString
4545
// CHECK: apply [[ID3]]<MMString>([[STACK2]], [[STACK3]], [[META]]) : $@convention(witness_method) <τ_0_0 where τ_0_0 : Equatable> (@in τ_0_0, @in τ_0_0, @thick τ_0_0.Type) -> Bool

0 commit comments

Comments
 (0)