Skip to content

Commit 5790c70

Browse files
committed
Sema: Add recursion guard to AssociatedTypeInference::computeFixedTypeWitness()
1 parent 9fac25d commit 5790c70

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

lib/Sema/TypeCheckProtocolInference.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -809,8 +809,6 @@ AssociatedTypeDecl *AssociatedTypeInference::findDefaultedAssociatedType(
809809
Type AssociatedTypeInference::computeFixedTypeWitness(
810810
AssociatedTypeDecl *assocType) {
811811
Type resultType;
812-
auto *const structuralTy = DependentMemberType::get(
813-
proto->getSelfInterfaceType(), assocType->getName());
814812

815813
// Look at all of the inherited protocols to determine whether they
816814
// require a fixed type for this associated type.
@@ -823,17 +821,23 @@ Type AssociatedTypeInference::computeFixedTypeWitness(
823821

824822
// FIXME: The RequirementMachine will assert on re-entrant construction.
825823
// We should find a more principled way of breaking this cycle.
826-
if (ctx.isRecursivelyConstructingRequirementMachine(sig.getCanonicalSignature()))
824+
if (ctx.isRecursivelyConstructingRequirementMachine(sig.getCanonicalSignature()) ||
825+
conformedProto->isComputingRequirementSignature())
827826
continue;
828827

828+
auto selfTy = conformedProto->getSelfInterfaceType();
829+
if (!sig->requiresProtocol(selfTy, assocType->getProtocol()))
830+
continue;
831+
832+
auto structuralTy = DependentMemberType::get(selfTy, assocType->getName());
829833
const auto ty = sig->getCanonicalTypeInContext(structuralTy);
830834

831835
// A dependent member type with an identical base and name indicates that
832836
// the protocol does not same-type constrain it in any way; move on to
833837
// the next protocol.
834838
if (auto *const memberTy = ty->getAs<DependentMemberType>()) {
835-
if (memberTy->getBase()->isEqual(structuralTy->getBase()) &&
836-
memberTy->getName() == structuralTy->getName())
839+
if (memberTy->getBase()->isEqual(selfTy) &&
840+
memberTy->getName() == assocType->getName())
837841
continue;
838842
}
839843

test/decl/protocol/req/associated_type_inference.swift

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -658,19 +658,27 @@ struct S39<B>: P39 {}
658658

659659
// Test that we can handle an analogous complex case involving all kinds of
660660
// type witness resolution.
661+
//
662+
// FIXME: Except there's too much circularity here, and this really can't
663+
// work. The problem is that S40 conforms to P40c, and we can't check the
664+
// conformance without computing the requirement signature of P40c, but the
665+
// requirement signature computation depends on the conformance, via the
666+
// 'D == S40<Never>' requirement.
661667
protocol P40a {
662668
associatedtype A
663669
associatedtype B: P40a
664670

665671
func foo(arg: A)
666672
}
667673
protocol P40b: P40a {
668-
associatedtype C = (A, B.A, D.D, E) -> Self
669-
associatedtype D: P40b
670-
associatedtype E: Equatable
674+
associatedtype C = (A, B.A, D.D, E) -> Self // expected-note {{protocol requires nested type 'C'; do you want to add it?}}
675+
associatedtype D: P40b // expected-note {{protocol requires nested type 'D'; do you want to add it?}}
676+
associatedtype E: Equatable // expected-note {{protocol requires nested type 'E'; do you want to add it?}}
671677
}
672678
protocol P40c: P40b where D == S40<Never> {}
673679
struct S40<E: Equatable>: P40c {
680+
// expected-error@-1 {{type 'S40<E>' does not conform to protocol 'P40b'}}
681+
// expected-error@-2 {{type 'S40<E>' does not conform to protocol 'P40c'}}
674682
func foo(arg: Never) {}
675683

676684
typealias B = Self

0 commit comments

Comments
 (0)