Skip to content

Commit 2d77260

Browse files
committed
GSB: Clean up and comment redundant requirement algorithm some more
1 parent aa865a2 commit 2d77260

File tree

2 files changed

+85
-50
lines changed

2 files changed

+85
-50
lines changed

include/swift/AST/GenericSignatureBuilder.h

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "swift/AST/TypeRepr.h"
3232
#include "swift/Basic/Debug.h"
3333
#include "swift/Basic/LLVM.h"
34+
#include "llvm/ADT/DenseSet.h"
3435
#include "llvm/ADT/FoldingSet.h"
3536
#include "llvm/ADT/ilist.h"
3637
#include "llvm/ADT/PointerUnion.h"
@@ -659,10 +660,27 @@ class GenericSignatureBuilder {
659660
GetKindAndRHS getKindAndRHS,
660661
const RequirementSource *source,
661662
const ProtocolDecl *requirementSignatureSelfProto,
662-
ASTContext &ctx, SmallVectorImpl<ExplicitRequirement> &result);
663-
663+
SmallVectorImpl<ExplicitRequirement> &result);
664+
665+
/// Determine if an explicit requirement can be derived from the
666+
/// requirement given by \p otherSource and \p otherRHS, using the
667+
/// knowledge of any existing redundant requirements discovered so far.
668+
Optional<ExplicitRequirement>
669+
isValidRequirementDerivationPath(
670+
llvm::SmallDenseSet<ExplicitRequirement, 4> &visited,
671+
RequirementKind otherKind,
672+
const RequirementSource *otherSource,
673+
RequirementRHS otherRHS,
674+
const ProtocolDecl *requirementSignatureSelfProto);
675+
676+
/// Determine if the explicit requirement \p req can be derived from any
677+
/// of the constraints in \p constraints, using the knowledge of any
678+
/// existing redundant requirements discovered so far.
679+
///
680+
/// Use \p filter to screen out less-specific and conflicting constraints
681+
/// if the requirement is a superclass, concrete type or layout requirement.
664682
template<typename T, typename Filter>
665-
void checkRequirementRedundancy(
683+
void checkIfRequirementCanBeDerived(
666684
const ExplicitRequirement &req,
667685
const std::vector<Constraint<T>> &constraints,
668686
const ProtocolDecl *requirementSignatureSelfProto,

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 64 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5875,7 +5875,7 @@ void GenericSignatureBuilder::getBaseRequirements(
58755875
GenericSignatureBuilder::GetKindAndRHS getKindAndRHS,
58765876
const RequirementSource *source,
58775877
const ProtocolDecl *requirementSignatureSelfProto,
5878-
ASTContext &ctx, SmallVectorImpl<ExplicitRequirement> &result) {
5878+
SmallVectorImpl<ExplicitRequirement> &result) {
58795879
// If we're building a generic signature, the base requirement is
58805880
// built from the root of the path.
58815881
if (source->parent == nullptr) {
@@ -5900,14 +5900,44 @@ void GenericSignatureBuilder::getBaseRequirements(
59005900
}
59015901

59025902
getBaseRequirements(
5903-
[&]() {
5904-
return ExplicitRequirement::getKindAndRHS(source, ctx);
5905-
},
5906-
source->parent, requirementSignatureSelfProto, ctx, result);
5903+
[&]() { return ExplicitRequirement::getKindAndRHS(source, Context); },
5904+
source->parent, requirementSignatureSelfProto, result);
5905+
}
5906+
5907+
Optional<ExplicitRequirement>
5908+
GenericSignatureBuilder::isValidRequirementDerivationPath(
5909+
llvm::SmallDenseSet<ExplicitRequirement, 4> &visited,
5910+
RequirementKind otherKind,
5911+
const RequirementSource *otherSource,
5912+
RequirementRHS otherRHS,
5913+
const ProtocolDecl *requirementSignatureSelfProto) {
5914+
5915+
SmallVector<ExplicitRequirement, 2> result;
5916+
getBaseRequirements(
5917+
[&]() { return std::make_pair(otherKind, otherRHS); },
5918+
otherSource, requirementSignatureSelfProto, result);
5919+
assert(result.size() > 0);
5920+
5921+
for (const auto &otherReq : result) {
5922+
// Don't consider paths that are based on the requirement
5923+
// itself; such a path doesn't "prove" this requirement,
5924+
// since if we drop the requirement the path is no longer
5925+
// valid.
5926+
if (visited.count(otherReq))
5927+
return None;
5928+
5929+
// Don't consider paths based on requirements that are already
5930+
// known to be redundant either, since those paths become
5931+
// invalid once redundant requirements are dropped.
5932+
if (isRedundantExplicitRequirement(otherReq))
5933+
return None;
5934+
}
5935+
5936+
return result.front();
59075937
}
59085938

59095939
template<typename T, typename Filter>
5910-
void GenericSignatureBuilder::checkRequirementRedundancy(
5940+
void GenericSignatureBuilder::checkIfRequirementCanBeDerived(
59115941
const ExplicitRequirement &req,
59125942
const std::vector<Constraint<T>> &constraints,
59135943
const ProtocolDecl *requirementSignatureSelfProto,
@@ -5918,34 +5948,18 @@ void GenericSignatureBuilder::checkRequirementRedundancy(
59185948
if (filter(constraint))
59195949
continue;
59205950

5921-
SmallVector<ExplicitRequirement, 2> result;
5922-
getBaseRequirements(
5923-
[&]() {
5924-
return std::make_pair(req.getKind(), constraint.value);
5925-
},
5926-
constraint.source, requirementSignatureSelfProto, Context, result);
5927-
assert(result.size() > 0);
5928-
5929-
bool anyWereRedundant =
5930-
llvm::any_of(result, [&](const ExplicitRequirement &otherReq) {
5931-
// Don't consider paths that are based on the requirement
5932-
// itself; such a path doesn't "prove" this requirement,
5933-
// since if we drop the requirement the path is no longer
5934-
// valid.
5935-
if (req == otherReq)
5936-
return true;
5937-
5938-
// Don't consider paths based on requirements that are already
5939-
// known to be redundant either, since those paths become
5940-
// invalid once redundant requirements are dropped.
5941-
return isRedundantExplicitRequirement(otherReq);
5942-
});
5943-
59445951
// If this requirement can be derived from a set of
59455952
// non-redundant base requirements, then this requirement
59465953
// is redundant.
5947-
if (!anyWereRedundant) {
5948-
Impl->RedundantRequirements[req].insert(result.front());
5954+
llvm::SmallDenseSet<ExplicitRequirement, 4> visited;
5955+
visited.insert(req);
5956+
5957+
if (auto representative = isValidRequirementDerivationPath(
5958+
visited, req.getKind(),
5959+
constraint.source,
5960+
constraint.value,
5961+
requirementSignatureSelfProto)) {
5962+
Impl->RedundantRequirements[req].insert(*representative);
59495963
}
59505964
}
59515965
}
@@ -6006,7 +6020,7 @@ void GenericSignatureBuilder::computeRedundantRequirements(
60066020
auto found = equivClass->conformsTo.find(proto);
60076021
assert(found != equivClass->conformsTo.end());
60086022

6009-
checkRequirementRedundancy(
6023+
checkIfRequirementCanBeDerived(
60106024
req, found->second,
60116025
requirementSignatureSelfProto,
60126026
[&](const Constraint<ProtocolDecl *> &constraint) {
@@ -6041,7 +6055,7 @@ void GenericSignatureBuilder::computeRedundantRequirements(
60416055
// requirement that implies 'T : D'.
60426056
Impl->ConflictingRequirements[req] = resolvedSuperclass;
60436057

6044-
checkRequirementRedundancy(
6058+
checkIfRequirementCanBeDerived(
60456059
req, equivClass->superclassConstraints,
60466060
requirementSignatureSelfProto,
60476061
[&](const Constraint<Type> &constraint) {
@@ -6062,7 +6076,7 @@ void GenericSignatureBuilder::computeRedundantRequirements(
60626076
// This means that 'T : C' is made redundant by any
60636077
// requirement that implies 'T : B', such that 'C' is a
60646078
// superclass of 'B'.
6065-
checkRequirementRedundancy(
6079+
checkIfRequirementCanBeDerived(
60666080
req, equivClass->superclassConstraints,
60676081
requirementSignatureSelfProto,
60686082
[&](const Constraint<Type> &constraint) {
@@ -6081,7 +6095,7 @@ void GenericSignatureBuilder::computeRedundantRequirements(
60816095
// requirement 'T == D'.
60826096
if (resolvedSuperclass->isExactSuperclassOf(resolvedConcreteType)) {
60836097
// 'C' is a superclass of 'D', so 'T : C' is redundant.
6084-
checkRequirementRedundancy(
6098+
checkIfRequirementCanBeDerived(
60856099
req, equivClass->concreteTypeConstraints,
60866100
requirementSignatureSelfProto,
60876101
[&](const Constraint<Type> &constraint) {
@@ -6119,7 +6133,7 @@ void GenericSignatureBuilder::computeRedundantRequirements(
61196133
// requirement that implies 'T : L2'.
61206134
Impl->ConflictingRequirements[req] = equivClass->layout;
61216135

6122-
checkRequirementRedundancy(
6136+
checkIfRequirementCanBeDerived(
61236137
req, equivClass->layoutConstraints,
61246138
requirementSignatureSelfProto,
61256139
[&](const Constraint<LayoutConstraint> &constraint) {
@@ -6137,7 +6151,7 @@ void GenericSignatureBuilder::computeRedundantRequirements(
61376151
//
61386152
// This means that 'T : L1' is made redundant by any
61396153
// requirement that implies 'T : L1'.
6140-
checkRequirementRedundancy(
6154+
checkIfRequirementCanBeDerived(
61416155
req, equivClass->layoutConstraints,
61426156
requirementSignatureSelfProto,
61436157
[&](const Constraint<LayoutConstraint> &constraint) {
@@ -6156,7 +6170,7 @@ void GenericSignatureBuilder::computeRedundantRequirements(
61566170
layout)) {
61576171
Impl->ExplicitConformancesImpliedByConcrete.insert(req);
61586172

6159-
checkRequirementRedundancy(
6173+
checkIfRequirementCanBeDerived(
61606174
req, equivClass->concreteTypeConstraints,
61616175
requirementSignatureSelfProto,
61626176
[&](const Constraint<Type> &constraint) {
@@ -6185,7 +6199,7 @@ void GenericSignatureBuilder::computeRedundantRequirements(
61856199
// This means that 'T : L1' is made redundant by any
61866200
// requirement that implies 'T : L3', where L3 is
61876201
// mergeable with L1.
6188-
checkRequirementRedundancy(
6202+
checkIfRequirementCanBeDerived(
61896203
req, equivClass->layoutConstraints,
61906204
requirementSignatureSelfProto,
61916205
[&](const Constraint<LayoutConstraint> &constraint) {
@@ -6204,7 +6218,7 @@ void GenericSignatureBuilder::computeRedundantRequirements(
62046218
if (typeImpliesLayoutConstraint(resolvedConcreteType, layout)) {
62056219
Impl->ExplicitConformancesImpliedByConcrete.insert(req);
62066220

6207-
checkRequirementRedundancy(
6221+
checkIfRequirementCanBeDerived(
62086222
req, equivClass->concreteTypeConstraints,
62096223
requirementSignatureSelfProto,
62106224
[&](const Constraint<Type> &constraint) {
@@ -6993,15 +7007,18 @@ void GenericSignatureBuilder::diagnoseConflictingConcreteTypeRequirements(
69937007
SmallVector<ExplicitRequirement, 2> result;
69947008
getBaseRequirements(
69957009
[&]() {
6996-
return std::make_pair(RequirementKind::SameType, constraint.value);
7010+
return std::make_pair(RequirementKind::SameType,
7011+
constraint.value);
69977012
},
6998-
constraint.source, requirementSignatureSelfProto, Context, result);
7013+
constraint.source, requirementSignatureSelfProto, result);
69997014

7000-
return
7001-
!llvm::any_of(result, [&](const ExplicitRequirement &otherReq) {
7002-
return isRedundantExplicitRequirement(otherReq);
7003-
});
7004-
});
7015+
for (const auto &otherReq : result) {
7016+
if (isRedundantExplicitRequirement(otherReq))
7017+
return false;
7018+
}
7019+
7020+
return true;
7021+
});
70057022

70067023
assert(foundConcreteRequirement != equivClass->concreteTypeConstraints.end());
70077024

0 commit comments

Comments
 (0)