Skip to content

Commit fcd6985

Browse files
authored
Merge pull request #77463 from slavapestov/fix-rdar139089004
AST: Add workaround for incorrect mangling of conditional conformances with pack requirements
2 parents 75f0de0 + 69e3aaf commit fcd6985

File tree

5 files changed

+147
-13
lines changed

5 files changed

+147
-13
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,9 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
400400
/// checking against global state, if any/all of the types in the requirement
401401
/// are concrete, not type parameters.
402402
bool isRequirementSatisfied(
403-
Requirement requirement, bool allowMissing = false) const;
403+
Requirement requirement,
404+
bool allowMissing = false,
405+
bool brokenPackBehavior = false) const;
404406

405407
bool isReducedType(Type type) const;
406408

lib/AST/ASTMangler.cpp

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1909,19 +1909,32 @@ static bool forEachConditionalConformance(const ProtocolConformance *conformance
19091909
auto *rootConformance = conformance->getRootConformance();
19101910

19111911
auto subMap = conformance->getSubstitutionMap();
1912-
for (auto requirement : rootConformance->getConditionalRequirements()) {
1913-
if (requirement.getKind() != RequirementKind::Conformance)
1912+
1913+
auto ext = dyn_cast<ExtensionDecl>(rootConformance->getDeclContext());
1914+
if (!ext)
1915+
return false;
1916+
1917+
auto typeSig = ext->getExtendedNominal()->getGenericSignature();
1918+
auto extensionSig = rootConformance->getGenericSignature();
1919+
1920+
for (const auto &req : extensionSig.getRequirements()) {
1921+
// We set brokenPackBehavior to true here to maintain compatibility with
1922+
// the mangling produced by an old compiler. We could incorrectly return
1923+
// false from isRequirementSatisfied() here even if the requirement was
1924+
// satisfied, and then it would show up as a conditional requirement
1925+
// even though it was already part of the nominal type's generic signature.
1926+
if (typeSig->isRequirementSatisfied(req,
1927+
/*allowMissing=*/false,
1928+
/*brokenPackBehavior=*/true))
19141929
continue;
1915-
ProtocolDecl *proto = requirement.getProtocolDecl();
1916-
auto conformance = subMap.lookupConformance(
1917-
requirement.getFirstType()->getCanonicalType(), proto);
1918-
if (conformance.isInvalid()) {
1919-
// This should only happen when mangling invalid ASTs, but that happens
1920-
// for indexing purposes.
1930+
1931+
if (req.getKind() != RequirementKind::Conformance)
19211932
continue;
1922-
}
19231933

1924-
if (fn(requirement.getFirstType().subst(subMap), conformance))
1934+
ProtocolDecl *proto = req.getProtocolDecl();
1935+
auto conformance = subMap.lookupConformance(
1936+
req.getFirstType()->getCanonicalType(), proto);
1937+
if (fn(req.getFirstType().subst(subMap), conformance))
19251938
return true;
19261939
}
19271940

@@ -3473,7 +3486,14 @@ void ASTMangler::gatherGenericSignatureParts(GenericSignature sig,
34733486
genericParams = canSig.getGenericParams();
34743487
} else {
34753488
llvm::erase_if(reqs, [&](Requirement req) {
3476-
return contextSig->isRequirementSatisfied(req);
3489+
// We set brokenPackBehavior to true here to maintain compatibility with
3490+
// the mangling produced by an old compiler. We could incorrectly return
3491+
// false from isRequirementSatisfied() here even if the requirement was
3492+
// satisfied, and then it would show up as a conditional requirement
3493+
// even though it was already part of the nominal type's generic signature.
3494+
return contextSig->isRequirementSatisfied(req,
3495+
/*allowMissing=*/false,
3496+
/*brokenPackBehavior=*/true);
34773497
});
34783498
}
34793499
}

lib/AST/GenericSignature.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,10 +406,26 @@ bool GenericSignatureImpl::areReducedTypeParametersEqual(Type type1,
406406
}
407407

408408
bool GenericSignatureImpl::isRequirementSatisfied(
409-
Requirement requirement, bool allowMissing) const {
409+
Requirement requirement,
410+
bool allowMissing,
411+
bool brokenPackBehavior) const {
410412
if (requirement.getFirstType()->hasTypeParameter()) {
411413
auto *genericEnv = getGenericEnvironment();
412414

415+
if (brokenPackBehavior) {
416+
// Swift 5.9 shipped with a bug here where this method would return
417+
// incorrect results. Maintain the old behavior specifically for two
418+
// call sites in the ASTMangler.
419+
if ((requirement.getKind() == RequirementKind::SameType ||
420+
requirement.getKind() == RequirementKind::Superclass) &&
421+
!requirement.getSecondType()->isTypeParameter() &&
422+
requirement.getSecondType().findIf([&](Type t) -> bool {
423+
return t->is<PackExpansionType>();
424+
})) {
425+
return false;
426+
}
427+
}
428+
413429
requirement = requirement.subst(
414430
QueryInterfaceTypeSubstitutions{genericEnv},
415431
LookUpConformanceInModule(),
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: %target-swift-frontend -emit-ir %s -target %target-swift-5.9-abi-triple | %FileCheck %s
2+
3+
public protocol P {
4+
associatedtype A
5+
}
6+
7+
public protocol Q {}
8+
9+
public class C<each T> {}
10+
11+
public struct GG1<A: P, each B: P> where A.A == C<repeat (each B).A> {}
12+
13+
extension GG1: Q where A: Q, repeat each B: Q {}
14+
15+
// This mangling is incorrect; the correct mangling is "$s29conditional_pack_requirements3GG1Vyxq_q_Qp_QPGAA1QA2aERzAaER_rlMc"
16+
// However, we retain the incorrect behavior for ABI compatibility.
17+
//
18+
// CHECK-LABEL: @"$s29conditional_pack_requirements3GG1Vyxq_q_Qp_QPGAA1QA2aERzAaER_AA1CCy1AAA1PPQy_q_Qp_QPGAhJRtzrlMc" =
19+
20+
21+
public struct GG2<each A: P> {
22+
public struct Nested<each B: P> where repeat (each A).A == (each B).A {}
23+
}
24+
25+
extension GG2.Nested: Q where repeat each A: Q, repeat each B: Q {}
26+
27+
// This mangling is correct.
28+
// CHECK-LABEL: @"$s29conditional_pack_requirements3GG2V6NestedVyxxQp_QP_qd__qd__Qp_QPGAA1QA2aGRzAaGRd__rlMc" =
29+
30+
31+
public struct GG3<A: P, each B: P> where A.A : C<repeat (each B).A> {}
32+
33+
extension GG3: Q where A: Q, repeat each B: Q {}
34+
35+
// This mangling is incorrect; the correct mangling is "$s29conditional_pack_requirements3GG3Vyxq_q_Qp_QPGAA1QA2aERzAaER_rlMc"
36+
// However, we retain the incorrect behavior for ABI compatibility.
37+
//
38+
// CHECK-LABEL: @"$s29conditional_pack_requirements3GG3Vyxq_q_Qp_QPGAA1QA2aERzAaER_AA1CCy1AAA1PPQy_q_Qp_QPGAhJRczrlMc" =
39+
40+
41+
public struct GG4<each A: P> {
42+
public struct Nested<each B: P> where repeat (each A).A : C<(each B).A> {}
43+
}
44+
45+
extension GG4.Nested: Q where repeat each A: Q, repeat each B: Q {}
46+
47+
// This mangling is correct.
48+
// CHECK-LABEL: @"$s29conditional_pack_requirements3GG4V6NestedVyxxQp_QP_qd__qd__Qp_QPGAA1QA2aGRzAaGRd__rlMc" =
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-emit-module-interface(%t/conditional_pack_requirements.swiftinterface) %s -target %target-swift-5.9-abi-triple
3+
// RUN: %FileCheck %s < %t/conditional_pack_requirements.swiftinterface
4+
5+
public protocol P {
6+
associatedtype A
7+
}
8+
9+
public protocol Q {}
10+
11+
public class C<each T> {}
12+
13+
public struct GG1<A: P, each B: P> where A.A == C<repeat (each B).A> {}
14+
15+
extension GG1: Q where A: Q, repeat each B: Q {}
16+
17+
// CHECK-LABEL: public struct GG1<A, each B> where A : conditional_pack_requirements.P, repeat each B : conditional_pack_requirements.P, A.A == conditional_pack_requirements.C<repeat (each B).A> {
18+
// CHECK-LABEL: extension conditional_pack_requirements.GG1 : conditional_pack_requirements.Q where A : conditional_pack_requirements.Q, repeat each B : conditional_pack_requirements.Q {
19+
20+
21+
public struct GG2<each A: P> {
22+
public struct Nested<each B: P> where repeat (each A).A == (each B).A {}
23+
}
24+
25+
extension GG2.Nested: Q where repeat each A: Q, repeat each B: Q {}
26+
27+
// CHECK-LABEL: public struct GG2<each A> where repeat each A : conditional_pack_requirements.P {
28+
// CHECK-LABEL: public struct Nested<each B> where repeat each B : conditional_pack_requirements.P, repeat (each A).A == (each B).A {
29+
// CHECK-LABEL: extension conditional_pack_requirements.GG2.Nested : conditional_pack_requirements.Q where repeat each A : conditional_pack_requirements.Q, repeat each B : conditional_pack_requirements.Q {
30+
31+
32+
public struct GG3<A: P, each B: P> where A.A : C<repeat (each B).A> {}
33+
34+
extension GG3: Q where A: Q, repeat each B: Q {}
35+
36+
// CHECK-LABEL: public struct GG3<A, each B> where A : conditional_pack_requirements.P, repeat each B : conditional_pack_requirements.P, A.A : conditional_pack_requirements.C<repeat (each B).A> {
37+
// CHECK-LABEL: extension conditional_pack_requirements.GG3 : conditional_pack_requirements.Q where A : conditional_pack_requirements.Q, repeat each B : conditional_pack_requirements.Q {
38+
39+
40+
public struct GG4<each A: P> {
41+
public struct Nested<each B: P> where repeat (each A).A : C<(each B).A> {}
42+
}
43+
44+
extension GG4.Nested: Q where repeat each A: Q, repeat each B: Q {}
45+
46+
// CHECK-LABEL: public struct GG4<each A> where repeat each A : conditional_pack_requirements.P {
47+
// CHECK-LABEL: public struct Nested<each B> where repeat each B : conditional_pack_requirements.P, repeat (each A).A : conditional_pack_requirements.C<(each B).A> {
48+
// CHECK-LABEL: extension conditional_pack_requirements.GG4.Nested : conditional_pack_requirements.Q where repeat each A : conditional_pack_requirements.Q, repeat each B : conditional_pack_requirements.Q {

0 commit comments

Comments
 (0)