Skip to content

Commit ce8549b

Browse files
committed
GSB: Record the original type for self-derived conformances
RequirementSources with Superclass and Concrete kind would reference a protocol conformance. However in the case where the concrete type was an existential conforming to itself, the SelfProtocolConformance does not store the original type. Since self-conforming existentials don't have any nested types, we don't really need to store this conformance at all. Instead of storing a protocol conformance in the case where the original type is an existential, just the original type itself. This allows us to recover the requirement from the RequirementSource, which is important for the new implementation of computing redundant requirements.
1 parent dcd3c6f commit ce8549b

File tree

2 files changed

+60
-16
lines changed

2 files changed

+60
-16
lines changed

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,18 +1118,24 @@ class GenericSignatureBuilder::RequirementSource final
11181118
WrittenRequirementLoc writtenLoc =
11191119
WrittenRequirementLoc()) const;
11201120
public:
1121-
/// A requirement source that describes that a requirement that is resolved
1121+
/// A requirement source that describes a conformance requirement resolved
11221122
/// via a superclass requirement.
11231123
const RequirementSource *viaSuperclass(
11241124
GenericSignatureBuilder &builder,
11251125
ProtocolConformanceRef conformance) const;
11261126

1127-
/// A requirement source that describes that a requirement that is resolved
1128-
/// via a same-type-to-concrete requirement.
1127+
/// A requirement source that describes a conformance requirement resolved
1128+
/// via a concrete type requirement with a conforming nominal type.
11291129
const RequirementSource *viaConcrete(
11301130
GenericSignatureBuilder &builder,
11311131
ProtocolConformanceRef conformance) const;
11321132

1133+
/// A requirement source that describes that a requirement that is resolved
1134+
/// via a concrete type requirement with an existential self-conforming type.
1135+
const RequirementSource *viaConcrete(
1136+
GenericSignatureBuilder &builder,
1137+
Type existentialType) const;
1138+
11331139
/// A constraint source that describes a layout constraint that was implied
11341140
/// by a superclass requirement.
11351141
const RequirementSource *viaLayout(GenericSignatureBuilder &builder,

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -591,10 +591,10 @@ bool RequirementSource::isAcceptableStorageKind(Kind kind,
591591
case Superclass:
592592
case Concrete:
593593
switch (storageKind) {
594+
case StorageKind::StoredType:
594595
case StorageKind::ProtocolConformance:
595596
return true;
596597

597-
case StorageKind::StoredType:
598598
case StorageKind::AssociatedTypeDecl:
599599
case StorageKind::None:
600600
return false;
@@ -1043,6 +1043,17 @@ const RequirementSource *RequirementSource::viaConcrete(
10431043
0, WrittenRequirementLoc());
10441044
}
10451045

1046+
const RequirementSource *RequirementSource::viaConcrete(
1047+
GenericSignatureBuilder &builder,
1048+
Type existentialType) const {
1049+
assert(existentialType->isExistentialType());
1050+
REQUIREMENT_SOURCE_FACTORY_BODY(
1051+
(nodeID, Concrete, this, existentialType.getPointer(),
1052+
nullptr, nullptr),
1053+
(Concrete, this, existentialType),
1054+
0, WrittenRequirementLoc());
1055+
}
1056+
10461057
const RequirementSource *RequirementSource::viaParent(
10471058
GenericSignatureBuilder &builder,
10481059
AssociatedTypeDecl *assocType) const {
@@ -1115,8 +1126,14 @@ const RequirementSource *RequirementSource::withoutRedundantSubpath(
11151126
getWrittenRequirementLoc());
11161127

11171128
case Concrete:
1118-
return parent->withoutRedundantSubpath(builder, start, end)
1119-
->viaConcrete(builder, getProtocolConformance());
1129+
if (auto existentialType = getStoredType()) {
1130+
assert(existentialType->isExistentialType());
1131+
return parent->withoutRedundantSubpath(builder, start, end)
1132+
->viaConcrete(builder, existentialType);
1133+
} else {
1134+
return parent->withoutRedundantSubpath(builder, start, end)
1135+
->viaConcrete(builder, getProtocolConformance());
1136+
}
11201137

11211138
case Layout:
11221139
return parent->withoutRedundantSubpath(builder, start, end)
@@ -2307,11 +2324,30 @@ GenericSignatureBuilder::resolveConcreteConformance(ResolvedType type,
23072324
return nullptr;
23082325
}
23092326

2310-
concreteSource = concreteSource->viaConcrete(*this, conformance);
2311-
equivClass->recordConformanceConstraint(*this, type, proto, concreteSource);
2312-
if (addConditionalRequirements(conformance, /*inferForModule=*/nullptr,
2313-
concreteSource->getLoc()))
2314-
return nullptr;
2327+
if (concrete->isExistentialType()) {
2328+
// If we have an existential type, record the original type, and
2329+
// not the conformance.
2330+
//
2331+
// The conformance must be a self-conformance, and self-conformances
2332+
// do not record the original type in the case where a derived
2333+
// protocol self-conforms to a base protocol; for example:
2334+
//
2335+
// @objc protocol Base {}
2336+
//
2337+
// @objc protocol Derived {}
2338+
//
2339+
// struct S<T : Base> {}
2340+
//
2341+
// extension S where T == Derived {}
2342+
assert(isa<SelfProtocolConformance>(conformance.getConcrete()));
2343+
concreteSource = concreteSource->viaConcrete(*this, concrete);
2344+
} else {
2345+
concreteSource = concreteSource->viaConcrete(*this, conformance);
2346+
equivClass->recordConformanceConstraint(*this, type, proto, concreteSource);
2347+
if (addConditionalRequirements(conformance, /*inferForModule=*/nullptr,
2348+
concreteSource->getLoc()))
2349+
return nullptr;
2350+
}
23152351

23162352
return concreteSource;
23172353
}
@@ -2329,6 +2365,8 @@ const RequirementSource *GenericSignatureBuilder::resolveSuperConformance(
23292365
if (conformance.isInvalid())
23302366
return nullptr;
23312367

2368+
assert(!conformance.isAbstract());
2369+
23322370
// Conformance to this protocol is redundant; update the requirement source
23332371
// appropriately.
23342372
const RequirementSource *superclassSource;
@@ -2526,10 +2564,11 @@ static void concretizeNestedTypeFromConcreteParent(
25262564
conformance.getConcrete()->getTypeWitness(assocType);
25272565
if (!witnessType)
25282566
return; // FIXME: should we delay here?
2529-
} else if (auto archetype = concreteParent->getAs<ArchetypeType>()) {
2530-
witnessType = archetype->getNestedType(assocType->getName());
25312567
} else {
2532-
witnessType = DependentMemberType::get(concreteParent, assocType);
2568+
// Otherwise we have an abstract conformance to an opaque result type.
2569+
assert(conformance.isAbstract());
2570+
auto archetype = concreteParent->castTo<ArchetypeType>();
2571+
witnessType = archetype->getNestedType(assocType->getName());
25332572
}
25342573

25352574
builder.addSameTypeRequirement(
@@ -2549,8 +2588,7 @@ PotentialArchetype *PotentialArchetype::updateNestedTypeForConformance(
25492588

25502589
Identifier name = assocType->getName();
25512590

2552-
// Look for either an unresolved potential archetype (which we can resolve
2553-
// now) or a potential archetype with the appropriate associated type.
2591+
// Look for a potential archetype with the appropriate associated type.
25542592
PotentialArchetype *resultPA = nullptr;
25552593
auto knownNestedTypes = NestedTypes.find(name);
25562594
bool shouldUpdatePA = false;

0 commit comments

Comments
 (0)