@@ -5878,6 +5878,8 @@ GenericSignatureBuilder::isValidRequirementDerivationPath(
5878
5878
const RequirementSource *otherSource,
5879
5879
RequirementRHS otherRHS,
5880
5880
const ProtocolDecl *requirementSignatureSelfProto) {
5881
+ if (auto *Stats = Context.Stats )
5882
+ ++Stats->getFrontendCounters ().NumRedundantRequirementSteps ;
5881
5883
5882
5884
SmallVector<ExplicitRequirement, 2 > result;
5883
5885
getBaseRequirements (
@@ -5893,18 +5895,116 @@ GenericSignatureBuilder::isValidRequirementDerivationPath(
5893
5895
if (visited.count (otherReq))
5894
5896
return None;
5895
5897
5896
- // Don't consider paths based on requirements that are already
5897
- // known to be redundant either, since those paths become
5898
- // invalid once redundant requirements are dropped.
5899
- if (isRedundantExplicitRequirement (otherReq))
5900
- return None;
5901
-
5902
5898
SWIFT_DEFER {
5903
5899
visited.erase (otherReq);
5904
5900
};
5905
5901
visited.insert (otherReq);
5906
5902
5907
5903
auto otherSubjectType = otherReq.getSubjectType ();
5904
+
5905
+ // If our requirement is based on a path involving some other
5906
+ // redundant requirement, see if we can derive the redundant
5907
+ // requirement using requirements we haven't visited yet.
5908
+ // If not, we go ahead and drop it from consideration.
5909
+ //
5910
+ // We need to do this because sometimes, we don't record all possible
5911
+ // requirement sources that derive a given requirement.
5912
+ //
5913
+ // For example, when a nested type of a type parameter is concretized by
5914
+ // adding a superclass requirement, we only record the requirement source
5915
+ // for the concrete conformance the first time. A subsequently-added
5916
+ // superclass requirement on the same parent type does not record a
5917
+ // redundant concrete conformance for the child type.
5918
+ if (isRedundantExplicitRequirement (otherReq)) {
5919
+ // If we have a redundant explicit requirement source, it really is
5920
+ // redundant; there's no other derivation that would not be redundant.
5921
+ if (!otherSource->isDerivedNonRootRequirement ())
5922
+ return None;
5923
+
5924
+ auto *equivClass = resolveEquivalenceClass (otherSubjectType,
5925
+ ArchetypeResolutionKind::AlreadyKnown);
5926
+ assert (equivClass &&
5927
+ " Explicit requirement names an unknown equivalence class?" );
5928
+
5929
+ switch (otherReq.getKind ()) {
5930
+ case RequirementKind::Conformance: {
5931
+ auto *proto = otherReq.getRHS ().get <ProtocolDecl *>();
5932
+
5933
+ auto found = equivClass->conformsTo .find (proto);
5934
+ assert (found != equivClass->conformsTo .end ());
5935
+
5936
+ bool foundValidDerivation = false ;
5937
+ for (const auto &constraint : found->second ) {
5938
+ if (isValidRequirementDerivationPath (
5939
+ visited, otherReq.getKind (),
5940
+ constraint.source , proto,
5941
+ requirementSignatureSelfProto)) {
5942
+ foundValidDerivation = true ;
5943
+ break ;
5944
+ }
5945
+ }
5946
+
5947
+ if (!foundValidDerivation)
5948
+ return None;
5949
+
5950
+ break ;
5951
+ }
5952
+
5953
+ case RequirementKind::Superclass: {
5954
+ auto superclass = getCanonicalTypeInContext (
5955
+ otherReq.getRHS ().get <Type>(), { });
5956
+
5957
+ for (const auto &constraint : equivClass->superclassConstraints ) {
5958
+ auto otherSuperclass = getCanonicalTypeInContext (
5959
+ constraint.value , { });
5960
+
5961
+ if (superclass->isExactSuperclassOf (otherSuperclass)) {
5962
+ bool foundValidDerivation = false ;
5963
+ if (isValidRequirementDerivationPath (
5964
+ visited, otherReq.getKind (),
5965
+ constraint.source , otherSuperclass,
5966
+ requirementSignatureSelfProto)) {
5967
+ foundValidDerivation = true ;
5968
+ break ;
5969
+ }
5970
+
5971
+ if (!foundValidDerivation)
5972
+ return None;
5973
+ }
5974
+ }
5975
+
5976
+ break ;
5977
+ }
5978
+
5979
+ case RequirementKind::Layout: {
5980
+ auto layout = otherReq.getRHS ().get <LayoutConstraint>();
5981
+
5982
+ for (const auto &constraint : equivClass->layoutConstraints ) {
5983
+ auto otherLayout = constraint.value ;
5984
+
5985
+ if (layout == otherLayout) {
5986
+ bool foundValidDerivation = false ;
5987
+ if (isValidRequirementDerivationPath (
5988
+ visited, otherReq.getKind (),
5989
+ constraint.source , otherLayout,
5990
+ requirementSignatureSelfProto)) {
5991
+ foundValidDerivation = true ;
5992
+ break ;
5993
+ }
5994
+
5995
+ if (!foundValidDerivation)
5996
+ return None;
5997
+ }
5998
+ }
5999
+
6000
+ break ;
6001
+ }
6002
+
6003
+ case RequirementKind::SameType:
6004
+ llvm_unreachable (" Should not see same type requirements here" );
6005
+ }
6006
+ }
6007
+
5908
6008
if (auto *depMemType = otherSubjectType->getAs <DependentMemberType>()) {
5909
6009
// If 'req' is based on some other conformance requirement
5910
6010
// `T.[P.]A : Q', we want to make sure that we have a
@@ -5975,6 +6075,9 @@ void GenericSignatureBuilder::computeRedundantRequirements(
5975
6075
Impl->computedRedundantRequirements = true ;
5976
6076
#endif
5977
6077
6078
+ FrontendStatsTracer tracer (Context.Stats ,
6079
+ " compute-redundant-requirements" );
6080
+
5978
6081
// This sort preserves iteration order with the legacy algorithm.
5979
6082
SmallVector<ExplicitRequirement, 2 > requirements (
5980
6083
Impl->ExplicitRequirements .begin (),
0 commit comments