Skip to content

Commit 891e053

Browse files
authored
Merge pull request #36454 from slavapestov/rebuild-signature-without-redundant-conformances
GSB: Formalize the old hack where we rebuild a signature that had redundant conformance requirements
2 parents 72eb0d3 + 504d4f5 commit 891e053

File tree

8 files changed

+291
-45
lines changed

8 files changed

+291
-45
lines changed

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,8 @@ class GenericSignatureBuilder {
620620
/// generic signature builder no longer has valid state.
621621
GenericSignature computeGenericSignature(
622622
bool allowConcreteGenericParams = false,
623-
bool allowBuilderToMove = true) &&;
623+
bool buildingRequirementSignature = false,
624+
bool rebuildingWithoutRedundantConformances = false) &&;
624625

625626
/// Compute the requirement signature for the given protocol.
626627
static GenericSignature computeRequirementSignature(ProtocolDecl *proto);
@@ -645,6 +646,8 @@ class GenericSignatureBuilder {
645646
private:
646647
void computeRedundantRequirements();
647648

649+
bool hasExplicitConformancesImpliedByConcrete() const;
650+
648651
/// Describes the relationship between a given constraint and
649652
/// the canonical constraint of the equivalence class.
650653
enum class ConstraintRelation {
@@ -1434,9 +1437,8 @@ class GenericSignatureBuilder::FloatingRequirementSource {
14341437
/// inferred.
14351438
FloatingRequirementSource asInferred(const TypeRepr *typeRepr) const;
14361439

1437-
/// Whether this requirement source is recursive when composed with
1438-
/// the given type.
1439-
bool isRecursive(Type rootType, GenericSignatureBuilder &builder) const;
1440+
/// Whether this requirement source is recursive.
1441+
bool isRecursive(GenericSignatureBuilder &builder) const;
14401442
};
14411443

14421444
/// Describes a specific constraint on a particular type.

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 196 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ STATISTIC(NumRewriteRhsSimplifiedToLhs,
124124
"# of rewrite rule right-hand sides simplified to lhs (and removed)");
125125
STATISTIC(NumRewriteRulesRedundant,
126126
"# of rewrite rules that are redundant (and removed)");
127+
STATISTIC(NumSignaturesRebuiltWithoutRedundantRequirements,
128+
"# of generic signatures which had a concretized conformance requirement");
127129

128130
namespace {
129131

@@ -616,6 +618,11 @@ class GenericSignatureBuilder::ExplicitRequirement {
616618

617619
return true;
618620
}
621+
622+
friend bool operator!=(const ExplicitRequirement &lhs,
623+
const ExplicitRequirement &rhs) {
624+
return !(lhs == rhs);
625+
}
619626
};
620627

621628
namespace llvm {
@@ -690,8 +697,13 @@ struct GenericSignatureBuilder::Implementation {
690697
/// Whether there were any errors.
691698
bool HadAnyError = false;
692699

693-
/// The set of computed redundant explicit requirements.
694-
llvm::DenseSet<ExplicitRequirement> RedundantRequirements;
700+
/// A mapping of redundant explicit requirements to the best root requirement
701+
/// that implies them.
702+
using RedundantRequirementMap =
703+
llvm::DenseMap<ExplicitRequirement,
704+
llvm::SmallDenseSet<ExplicitRequirement, 2>>;
705+
706+
RedundantRequirementMap RedundantRequirements;
695707

696708
#ifndef NDEBUG
697709
/// Whether we've already computed redundant requiremnts.
@@ -1865,7 +1877,6 @@ FloatingRequirementSource FloatingRequirementSource::asInferred(
18651877
}
18661878

18671879
bool FloatingRequirementSource::isRecursive(
1868-
Type rootType,
18691880
GenericSignatureBuilder &builder) const {
18701881
llvm::SmallSet<std::pair<CanType, ProtocolDecl *>, 32> visitedAssocReqs;
18711882
for (auto storedSource = storage.dyn_cast<const RequirementSource *>();
@@ -3983,12 +3994,12 @@ auto GenericSignatureBuilder::resolve(UnresolvedType paOrT,
39833994
return ResolvedType(pa);
39843995

39853996
// Determine what kind of resolution we want.
3986-
Type type = paOrT.get<Type>();
39873997
ArchetypeResolutionKind resolutionKind =
39883998
ArchetypeResolutionKind::WellFormed;
3989-
if (!source.isExplicit() && source.isRecursive(type, *this))
3999+
if (!source.isExplicit() && source.isRecursive(*this))
39904000
resolutionKind = ArchetypeResolutionKind::AlreadyKnown;
39914001

4002+
Type type = paOrT.get<Type>();
39924003
return maybeResolveEquivalenceClass(type, resolutionKind,
39934004
/*wantExactPotentialArchetype=*/true);
39944005
}
@@ -4636,7 +4647,7 @@ ConstraintResult GenericSignatureBuilder::addTypeRequirement(
46364647
unresolvedHandling);
46374648
}
46384649

4639-
// If the resolved subject is a type, there may be things we can infer (if it
4650+
// If the resolved subject is concrete, there may be things we can infer (if it
46404651
// conditionally conforms to the protocol), and we can probably perform
46414652
// diagnostics here.
46424653
if (auto subjectType = resolvedSubject.getAsConcreteType()) {
@@ -5625,8 +5636,8 @@ class RedundantRequirementGraph {
56255636

56265637
SmallVector<Vertex, 2> vertices;
56275638

5628-
ComponentID nextComponent = 0;
5629-
VertexID nextIndex = 0;
5639+
ComponentID componentCount = 0;
5640+
VertexID vertexCount = 0;
56305641

56315642
SmallVector<VertexID, 2> stack;
56325643

@@ -5785,11 +5796,11 @@ class RedundantRequirementGraph {
57855796
void strongConnect(VertexID v) {
57865797
// Set the depth index for v to the smallest unused index.
57875798
assert(vertices[v].index == Vertex::UndefinedIndex);
5788-
vertices[v].index = nextIndex;
5799+
vertices[v].index = vertexCount;
57895800
assert(vertices[v].lowLink == Vertex::UndefinedIndex);
5790-
vertices[v].lowLink = nextIndex;
5801+
vertices[v].lowLink = vertexCount;
57915802

5792-
nextIndex++;
5803+
vertexCount++;
57935804

57945805
stack.push_back(v);
57955806
assert(!vertices[v].onStack);
@@ -5827,40 +5838,60 @@ class RedundantRequirementGraph {
58275838
vertices[w].onStack = false;
58285839
assert(vertices[w].component == Vertex::UndefinedComponent);
58295840

5830-
vertices[w].component = nextComponent;
5841+
vertices[w].component = componentCount;
58315842
} while (v != w);
58325843

5833-
nextComponent++;
5844+
componentCount++;
58345845
}
58355846
}
58365847

58375848
public:
5849+
using RedundantRequirementMap =
5850+
llvm::DenseMap<ExplicitRequirement,
5851+
llvm::SmallDenseSet<ExplicitRequirement, 2>>;
5852+
58385853
void computeRedundantRequirements(SourceManager &SM,
5839-
llvm::DenseSet<ExplicitRequirement> &redundant) {
5854+
RedundantRequirementMap &redundant) {
58405855
// First, compute SCCs.
58415856
computeSCCs();
58425857

5843-
// The number of edges from other connected components to this one.
5844-
SmallVector<unsigned, 2> inboundComponentEdges;
5845-
inboundComponentEdges.resize(nextComponent);
5858+
// The set of edges pointing to each connected component.
5859+
SmallVector<SmallVector<ComponentID, 2>, 2> inboundComponentEdges;
5860+
inboundComponentEdges.resize(componentCount);
5861+
5862+
// The set of edges originating from this connected component.
5863+
SmallVector<SmallVector<ComponentID, 2>, 2> outboundComponentEdges;
5864+
outboundComponentEdges.resize(componentCount);
58465865

5847-
// Visit all vertices and count inter-component edges.
5866+
// Visit all vertices and build the adjacency sets for the connected
5867+
// component graph.
58485868
for (const auto &vertex : vertices) {
58495869
assert(vertex.component != Vertex::UndefinedComponent);
58505870
for (auto successor : vertex.successors) {
58515871
ComponentID otherComponent = vertices[successor].component;
5852-
if (vertex.component != otherComponent)
5853-
++inboundComponentEdges[otherComponent];
5872+
if (vertex.component != otherComponent) {
5873+
inboundComponentEdges[otherComponent].push_back(vertex.component);
5874+
outboundComponentEdges[vertex.component].push_back(otherComponent);
5875+
}
58545876
}
58555877
}
58565878

5857-
// The best explicit requirement for each root SCC.
5879+
auto isRootComponent = [&](ComponentID component) -> bool {
5880+
return inboundComponentEdges[component].empty();
5881+
};
5882+
5883+
// The set of root components.
5884+
llvm::SmallDenseSet<ComponentID, 2> rootComponents;
5885+
5886+
// The best explicit requirement for each root component.
58585887
SmallVector<Optional<ExplicitRequirement>, 2> bestExplicitReq;
5859-
bestExplicitReq.resize(nextComponent);
5888+
bestExplicitReq.resize(componentCount);
58605889

5861-
// Visit all vertices and find the best requirement for each root SCC.
5890+
// Visit all vertices and find the best requirement for each root component.
58625891
for (const auto &vertex : vertices) {
5863-
if (inboundComponentEdges[vertex.component] == 0) {
5892+
if (isRootComponent(vertex.component)) {
5893+
rootComponents.insert(vertex.component);
5894+
58645895
// If this vertex is part of a root SCC, see if the requirement is
58655896
// better than the one we have so far.
58665897
auto &best = bestExplicitReq[vertex.component];
@@ -5869,26 +5900,61 @@ class RedundantRequirementGraph {
58695900
}
58705901
}
58715902

5872-
// Compute the set of redundant requirements.
5873-
for (const auto &vertex : vertices) {
5874-
if (inboundComponentEdges[vertex.component] == 0) {
5875-
// We have a root SCC. This requirement is redundant unless
5876-
// it is the best requirement for this SCC.
5877-
auto best = bestExplicitReq[vertex.component];
5878-
assert(best.hasValue() &&
5879-
"Did not record best requirement for root SCC?");
5903+
// The set of root components that each component is reachable from.
5904+
SmallVector<llvm::SmallDenseSet<ComponentID, 2>, 2> reachableFromRoot;
5905+
reachableFromRoot.resize(componentCount);
58805906

5881-
if (vertex.req == *best)
5882-
continue;
5907+
// Traverse the graph of connected components starting from the roots.
5908+
for (auto rootComponent : rootComponents) {
5909+
SmallVector<ComponentID, 2> worklist;
5910+
5911+
auto addToWorklist = [&](ComponentID nextComponent) {
5912+
if (!reachableFromRoot[nextComponent].count(rootComponent))
5913+
worklist.push_back(nextComponent);
5914+
};
5915+
5916+
addToWorklist(rootComponent);
5917+
5918+
while (!worklist.empty()) {
5919+
auto component = worklist.back();
5920+
worklist.pop_back();
5921+
5922+
reachableFromRoot[component].insert(rootComponent);
5923+
5924+
for (auto nextComponent : outboundComponentEdges[component])
5925+
addToWorklist(nextComponent);
5926+
}
5927+
}
5928+
5929+
// Compute the mapping of redundant requirements to the best root
5930+
// requirement that implies them.
5931+
for (const auto &vertex : vertices) {
5932+
if (isRootComponent(vertex.component)) {
5933+
// A root component is reachable from itself, and itself only.
5934+
assert(reachableFromRoot[vertex.component].size() == 1);
5935+
assert(reachableFromRoot[vertex.component].count(vertex.component) == 1);
58835936
} else {
5884-
// We have a non-root SCC. This requirement is always
5885-
// redundant.
58865937
assert(!bestExplicitReq[vertex.component].hasValue() &&
58875938
"Recorded best requirement for non-root SCC?");
58885939
}
58895940

5890-
auto inserted = redundant.insert(vertex.req);
5891-
assert(inserted.second && "Saw the same vertex twice?");
5941+
// We have a non-root component. This requirement is always
5942+
// redundant.
5943+
auto reachableFromRootSet = reachableFromRoot[vertex.component];
5944+
assert(reachableFromRootSet.size() > 0);
5945+
5946+
for (auto rootComponent : reachableFromRootSet) {
5947+
assert(isRootComponent(rootComponent));
5948+
5949+
auto best = bestExplicitReq[rootComponent];
5950+
assert(best.hasValue() &&
5951+
"Did not record best requirement for root SCC?");
5952+
5953+
assert(vertex.req != *best || vertex.component == rootComponent);
5954+
if (vertex.req != *best) {
5955+
redundant[vertex.req].insert(*best);
5956+
}
5957+
}
58925958
}
58935959
}
58945960

@@ -8108,9 +8174,60 @@ static void checkGenericSignature(CanGenericSignature canSig,
81088174
}
81098175
#endif
81108176

8177+
bool GenericSignatureBuilder::hasExplicitConformancesImpliedByConcrete() const {
8178+
for (auto pair : Impl->RedundantRequirements) {
8179+
if (pair.first.getKind() != RequirementKind::Conformance)
8180+
continue;
8181+
8182+
for (auto impliedByReq : pair.second) {
8183+
if (impliedByReq.getKind() == RequirementKind::Superclass)
8184+
return true;
8185+
8186+
if (impliedByReq.getKind() == RequirementKind::SameType)
8187+
return true;
8188+
}
8189+
}
8190+
8191+
return false;
8192+
}
8193+
8194+
static Type stripBoundDependentMemberTypes(Type t) {
8195+
if (auto *depMemTy = t->getAs<DependentMemberType>()) {
8196+
return DependentMemberType::get(
8197+
stripBoundDependentMemberTypes(depMemTy->getBase()),
8198+
depMemTy->getName());
8199+
}
8200+
8201+
return t;
8202+
}
8203+
8204+
static Requirement stripBoundDependentMemberTypes(Requirement req) {
8205+
auto subjectType = stripBoundDependentMemberTypes(req.getFirstType());
8206+
8207+
switch (req.getKind()) {
8208+
case RequirementKind::Conformance:
8209+
return Requirement(RequirementKind::Conformance, subjectType,
8210+
req.getSecondType());
8211+
8212+
case RequirementKind::Superclass:
8213+
case RequirementKind::SameType:
8214+
return Requirement(req.getKind(), subjectType,
8215+
req.getSecondType().transform([](Type t) {
8216+
return stripBoundDependentMemberTypes(t);
8217+
}));
8218+
8219+
case RequirementKind::Layout:
8220+
return Requirement(RequirementKind::Conformance, subjectType,
8221+
req.getLayoutConstraint());
8222+
}
8223+
8224+
llvm_unreachable("Bad requirement kind");
8225+
}
8226+
81118227
GenericSignature GenericSignatureBuilder::computeGenericSignature(
81128228
bool allowConcreteGenericParams,
8113-
bool allowBuilderToMove) && {
8229+
bool buildingRequirementSignature,
8230+
bool rebuildingWithoutRedundantConformances) && {
81148231
// Finalize the builder, producing any necessary diagnostics.
81158232
finalize(getGenericParams(), allowConcreteGenericParams);
81168233

@@ -8121,6 +8238,43 @@ GenericSignature GenericSignatureBuilder::computeGenericSignature(
81218238
// Form the generic signature.
81228239
auto sig = GenericSignature::get(getGenericParams(), requirements);
81238240

8241+
// If any of our explicit conformance requirements were implied by
8242+
// superclass or concrete same-type requirements, we have to build the
8243+
// signature again, since dropping the redundant conformance requirements
8244+
// changes the canonical type computation.
8245+
//
8246+
// However, if we already diagnosed an error, don't do this, because
8247+
// we might end up emitting duplicate diagnostics.
8248+
//
8249+
// Also, don't do this when building a requirement signature.
8250+
if (!buildingRequirementSignature &&
8251+
!Impl->HadAnyError &&
8252+
hasExplicitConformancesImpliedByConcrete()) {
8253+
NumSignaturesRebuiltWithoutRedundantRequirements++;
8254+
8255+
if (rebuildingWithoutRedundantConformances) {
8256+
llvm::errs() << "Rebuilt signature still has "
8257+
<< "redundant conformance requirements: ";
8258+
llvm::errs() << sig << "\n";
8259+
abort();
8260+
}
8261+
8262+
GenericSignatureBuilder newBuilder(Context);
8263+
8264+
for (auto param : sig->getGenericParams())
8265+
newBuilder.addGenericParameter(param);
8266+
8267+
for (auto &req : sig->getRequirements()) {
8268+
newBuilder.addRequirement(stripBoundDependentMemberTypes(req),
8269+
FloatingRequirementSource::forAbstract(), nullptr);
8270+
}
8271+
8272+
return std::move(newBuilder).computeGenericSignature(
8273+
allowConcreteGenericParams,
8274+
buildingRequirementSignature,
8275+
/*rebuildingWithoutRedundantConformances=*/true);
8276+
}
8277+
81248278
#ifndef NDEBUG
81258279
if (!Impl->HadAnyError) {
81268280
checkGenericSignature(sig.getCanonicalSignature(), *this);
@@ -8132,7 +8286,9 @@ GenericSignature GenericSignatureBuilder::computeGenericSignature(
81328286
// will produce the same thing.
81338287
//
81348288
// We cannot do this when there were errors.
8135-
if (allowBuilderToMove && !Impl->HadAnyError) {
8289+
//
8290+
// Also, we cannot do this when building a requirement signature.
8291+
if (!buildingRequirementSignature && !Impl->HadAnyError) {
81368292
// Register this generic signature builder as the canonical builder for the
81378293
// given signature.
81388294
Context.registerGenericSignatureBuilder(sig, std::move(*this));

0 commit comments

Comments
 (0)