Skip to content

Commit 63504e4

Browse files
committed
[GSB] Recognize self-derived protocol requirements within a protocol.
When computing the requirement signature of a protocol, eliminate requirement sources that are self-derived by virtual of using a given requirement of that protocol to prove that same constraint.
1 parent da22d25 commit 63504e4

File tree

2 files changed

+68
-12
lines changed

2 files changed

+68
-12
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,32 @@ static PotentialArchetype *replaceSelfWithPotentialArchetype(
579579
return selfPA;
580580
}
581581

582+
/// Determine whether the given protocol requirement is self-derived when it
583+
/// occurs within the requirement signature of its own protocol.
584+
static bool isSelfDerivedProtocolRequirementInProtocol(
585+
const RequirementSource *source,
586+
ProtocolDecl *selfProto,
587+
GenericSignatureBuilder &builder) {
588+
assert(source->isProtocolRequirement());
589+
590+
// This can only happen if the requirement points comes from the protocol
591+
// itself.
592+
if (source->getProtocolDecl() != selfProto) return false;
593+
594+
// This only applies if the parent is not the anchor for computing the
595+
// requirement signature. Anywhere else, we can use the protocol requirement.
596+
if (source->parent->kind == RequirementSource::RequirementSignatureSelf)
597+
return false;
598+
599+
// If the relative type of the protocol requirement itself is in the
600+
// same equivalence class as what we've proven with this requirement,
601+
// it's a self-derived requirement.
602+
return
603+
source->getAffectedPotentialArchetype()->getEquivalenceClassIfPresent() ==
604+
builder.resolveEquivalenceClass(source->getStoredType(),
605+
ArchetypeResolutionKind::AlreadyKnown);
606+
}
607+
582608
const RequirementSource *RequirementSource::getMinimalConformanceSource(
583609
PotentialArchetype *currentPA,
584610
ProtocolDecl *proto,
@@ -607,6 +633,7 @@ const RequirementSource *RequirementSource::getMinimalConformanceSource(
607633
};
608634

609635
bool sawProtocolRequirement = false;
636+
ProtocolDecl *requirementSignatureSelfProto = nullptr;
610637

611638
PotentialArchetype *rootPA = nullptr;
612639
Optional<std::pair<const RequirementSource *, const RequirementSource *>>
@@ -625,14 +652,25 @@ const RequirementSource *RequirementSource::getMinimalConformanceSource(
625652

626653
// The parent potential archetype must conform to the protocol in which
627654
// this requirement resides. Add this constraint.
628-
auto startOfPath =
629-
addConstraint(parentPA, source->getProtocolDecl(), source->parent);
630-
if (!startOfPath) return false;
655+
if (auto startOfPath =
656+
addConstraint(parentPA, source->getProtocolDecl(),
657+
source->parent)) {
658+
// We found a redundant subpath; record it and stop the algorithm.
659+
assert(startOfPath != source->parent);
660+
redundantSubpath = { startOfPath, source->parent };
661+
return true;
662+
}
631663

632-
// We found a redundant subpath; record it and stop the algorithm.
633-
assert(startOfPath != source->parent);
634-
redundantSubpath = { startOfPath, source->parent };
635-
return true;
664+
// If this is a self-derived protocol requirement, fail.
665+
if (requirementSignatureSelfProto &&
666+
isSelfDerivedProtocolRequirementInProtocol(
667+
source,
668+
requirementSignatureSelfProto,
669+
*currentPA->getBuilder()))
670+
return true;
671+
672+
// No redundancy thus far.
673+
return false;
636674
}
637675

638676
case Parent:
@@ -645,12 +683,17 @@ const RequirementSource *RequirementSource::getMinimalConformanceSource(
645683
case EquivalentType:
646684
return false;
647685

686+
case RequirementSignatureSelf:
687+
// Note the protocol whose requirement signature the requirement is
688+
// based on.
689+
requirementSignatureSelfProto = source->getProtocolDecl();
690+
LLVM_FALLTHROUGH;
691+
648692
case Explicit:
649693
case Inferred:
650694
case QuietlyInferred:
651695
case NestedTypeNameMatch:
652696
case ConcreteTypeBinding:
653-
case RequirementSignatureSelf:
654697
rootPA = parentPA;
655698
return false;
656699
}
@@ -4712,7 +4755,8 @@ namespace {
47124755
template<typename T>
47134756
bool removeSelfDerived(std::vector<Constraint<T>> &constraints,
47144757
ProtocolDecl *proto,
4715-
bool dropDerivedViaConcrete = true) {
4758+
bool dropDerivedViaConcrete = true,
4759+
bool allCanBeSelfDerived = false) {
47164760
bool anyDerivedViaConcrete = false;
47174761
Optional<Constraint<T>> remainingConcrete;
47184762
SmallVector<Constraint<T>, 4> minimalSources;
@@ -4780,7 +4824,8 @@ namespace {
47804824
if (constraints.empty() && remainingConcrete)
47814825
constraints.push_back(*remainingConcrete);
47824826

4783-
assert(!constraints.empty() && "All constraints were self-derived!");
4827+
assert((!constraints.empty() || allCanBeSelfDerived) &&
4828+
"All constraints were self-derived!");
47844829
return anyDerivedViaConcrete;
47854830
}
47864831
} // end anonymous namespace
@@ -5536,7 +5581,8 @@ void GenericSignatureBuilder::checkSameTypeConstraints(
55365581

55375582
// Remove self-derived constraints.
55385583
if (removeSelfDerived(constraints, /*proto=*/nullptr,
5539-
/*dropDerivedViaConcrete=*/false))
5584+
/*dropDerivedViaConcrete=*/false,
5585+
/*allCanBeSelfDerived=*/true))
55405586
anyDerivedViaConcrete = true;
55415587

55425588
// Sort the constraints, so we get a deterministic ordering of diagnostics.
@@ -5633,7 +5679,9 @@ void GenericSignatureBuilder::checkSameTypeConstraints(
56335679
auto &constraints = entry.second;
56345680

56355681
// Remove derived-via-concrete constraints.
5636-
(void)removeSelfDerived(constraints, /*proto=*/nullptr);
5682+
(void)removeSelfDerived(constraints, /*proto=*/nullptr,
5683+
/*dropDerivedViaConcrete=*/true,
5684+
/*allCanBeSelfDerived=*/true);
56375685
}
56385686
}
56395687

test/decl/protocol/recursive_requirement_ok.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,11 @@ protocol P11 {
8484
// CHECK: Generic signature: <Self, T where Self : P11, T : P11, Self.Q == T.Q>
8585
func map<T>(_: T.Type) where T : P11, Q == T.Q
8686
}
87+
88+
// Redundances within a requirement signature.
89+
protocol P12 { }
90+
91+
protocol P13 {
92+
associatedtype AT1 : P12
93+
associatedtype AT2: P13 where AT2.AT1 == AT1
94+
}

0 commit comments

Comments
 (0)