Skip to content

GSB: Record the original type for self-derived conformances #36209

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions include/swift/AST/GenericSignatureBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1118,18 +1118,24 @@ class GenericSignatureBuilder::RequirementSource final
WrittenRequirementLoc writtenLoc =
WrittenRequirementLoc()) const;
public:
/// A requirement source that describes that a requirement that is resolved
/// A requirement source that describes a conformance requirement resolved
/// via a superclass requirement.
const RequirementSource *viaSuperclass(
GenericSignatureBuilder &builder,
ProtocolConformanceRef conformance) const;

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

/// A requirement source that describes that a requirement that is resolved
/// via a concrete type requirement with an existential self-conforming type.
const RequirementSource *viaConcrete(
GenericSignatureBuilder &builder,
Type existentialType) const;

/// A constraint source that describes a layout constraint that was implied
/// by a superclass requirement.
const RequirementSource *viaLayout(GenericSignatureBuilder &builder,
Expand Down
64 changes: 51 additions & 13 deletions lib/AST/GenericSignatureBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -591,10 +591,10 @@ bool RequirementSource::isAcceptableStorageKind(Kind kind,
case Superclass:
case Concrete:
switch (storageKind) {
case StorageKind::StoredType:
case StorageKind::ProtocolConformance:
return true;

case StorageKind::StoredType:
case StorageKind::AssociatedTypeDecl:
case StorageKind::None:
return false;
Expand Down Expand Up @@ -1043,6 +1043,17 @@ const RequirementSource *RequirementSource::viaConcrete(
0, WrittenRequirementLoc());
}

const RequirementSource *RequirementSource::viaConcrete(
GenericSignatureBuilder &builder,
Type existentialType) const {
assert(existentialType->isExistentialType());
REQUIREMENT_SOURCE_FACTORY_BODY(
(nodeID, Concrete, this, existentialType.getPointer(),
nullptr, nullptr),
(Concrete, this, existentialType),
0, WrittenRequirementLoc());
}

const RequirementSource *RequirementSource::viaParent(
GenericSignatureBuilder &builder,
AssociatedTypeDecl *assocType) const {
Expand Down Expand Up @@ -1115,8 +1126,14 @@ const RequirementSource *RequirementSource::withoutRedundantSubpath(
getWrittenRequirementLoc());

case Concrete:
return parent->withoutRedundantSubpath(builder, start, end)
->viaConcrete(builder, getProtocolConformance());
if (auto existentialType = getStoredType()) {
assert(existentialType->isExistentialType());
return parent->withoutRedundantSubpath(builder, start, end)
->viaConcrete(builder, existentialType);
} else {
return parent->withoutRedundantSubpath(builder, start, end)
->viaConcrete(builder, getProtocolConformance());
}

case Layout:
return parent->withoutRedundantSubpath(builder, start, end)
Expand Down Expand Up @@ -2307,11 +2324,30 @@ GenericSignatureBuilder::resolveConcreteConformance(ResolvedType type,
return nullptr;
}

concreteSource = concreteSource->viaConcrete(*this, conformance);
equivClass->recordConformanceConstraint(*this, type, proto, concreteSource);
if (addConditionalRequirements(conformance, /*inferForModule=*/nullptr,
concreteSource->getLoc()))
return nullptr;
if (concrete->isExistentialType()) {
// If we have an existential type, record the original type, and
// not the conformance.
//
// The conformance must be a self-conformance, and self-conformances
// do not record the original type in the case where a derived
// protocol self-conforms to a base protocol; for example:
//
// @objc protocol Base {}
//
// @objc protocol Derived {}
//
// struct S<T : Base> {}
//
// extension S where T == Derived {}
assert(isa<SelfProtocolConformance>(conformance.getConcrete()));
concreteSource = concreteSource->viaConcrete(*this, concrete);
} else {
concreteSource = concreteSource->viaConcrete(*this, conformance);
equivClass->recordConformanceConstraint(*this, type, proto, concreteSource);
if (addConditionalRequirements(conformance, /*inferForModule=*/nullptr,
concreteSource->getLoc()))
return nullptr;
}

return concreteSource;
}
Expand All @@ -2329,6 +2365,8 @@ const RequirementSource *GenericSignatureBuilder::resolveSuperConformance(
if (conformance.isInvalid())
return nullptr;

assert(!conformance.isAbstract());

// Conformance to this protocol is redundant; update the requirement source
// appropriately.
const RequirementSource *superclassSource;
Expand Down Expand Up @@ -2526,10 +2564,11 @@ static void concretizeNestedTypeFromConcreteParent(
conformance.getConcrete()->getTypeWitness(assocType);
if (!witnessType)
return; // FIXME: should we delay here?
} else if (auto archetype = concreteParent->getAs<ArchetypeType>()) {
witnessType = archetype->getNestedType(assocType->getName());
} else {
witnessType = DependentMemberType::get(concreteParent, assocType);
// Otherwise we have an abstract conformance to an opaque result type.
assert(conformance.isAbstract());
auto archetype = concreteParent->castTo<ArchetypeType>();
witnessType = archetype->getNestedType(assocType->getName());
}

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

Identifier name = assocType->getName();

// Look for either an unresolved potential archetype (which we can resolve
// now) or a potential archetype with the appropriate associated type.
// Look for a potential archetype with the appropriate associated type.
PotentialArchetype *resultPA = nullptr;
auto knownNestedTypes = NestedTypes.find(name);
bool shouldUpdatePA = false;
Expand Down