Skip to content

Commit c9c5438

Browse files
authored
Merge pull request #38553 from slavapestov/gsb-canonicalize-requirements-when-rebuilding
GSB: Fix some bugs in generic signature rebuilding
2 parents 813a721 + e4115a2 commit c9c5438

File tree

3 files changed

+114
-23
lines changed

3 files changed

+114
-23
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5701,6 +5701,11 @@ GenericSignatureBuilder::isValidRequirementDerivationPath(
57015701

57025702
auto otherSubjectType = otherReq.getSubjectType();
57035703

5704+
auto *equivClass = resolveEquivalenceClass(otherSubjectType,
5705+
ArchetypeResolutionKind::AlreadyKnown);
5706+
assert(equivClass &&
5707+
"Explicit requirement names an unknown equivalence class?");
5708+
57045709
// If our requirement is based on a path involving some other
57055710
// redundant requirement, see if we can derive the redundant
57065711
// requirement using requirements we haven't visited yet.
@@ -5720,11 +5725,6 @@ GenericSignatureBuilder::isValidRequirementDerivationPath(
57205725
if (!otherSource->isDerivedNonRootRequirement())
57215726
return None;
57225727

5723-
auto *equivClass = resolveEquivalenceClass(otherSubjectType,
5724-
ArchetypeResolutionKind::AlreadyKnown);
5725-
assert(equivClass &&
5726-
"Explicit requirement names an unknown equivalence class?");
5727-
57285728
switch (otherReq.getKind()) {
57295729
case RequirementKind::Conformance: {
57305730
auto *proto = otherReq.getRHS().get<ProtocolDecl *>();
@@ -5804,20 +5804,22 @@ GenericSignatureBuilder::isValidRequirementDerivationPath(
58045804
}
58055805
}
58065806

5807-
if (auto *depMemType = otherSubjectType->getAs<DependentMemberType>()) {
5807+
auto anchor = equivClass->getAnchor(*this, { });
5808+
5809+
if (auto *depMemType = anchor->getAs<DependentMemberType>()) {
58085810
// If 'req' is based on some other conformance requirement
58095811
// `T.[P.]A : Q', we want to make sure that we have a
58105812
// non-redundant derivation for 'T : P'.
58115813
auto baseType = depMemType->getBase();
58125814
auto *proto = depMemType->getAssocType()->getProtocol();
58135815

5814-
auto *equivClass = resolveEquivalenceClass(baseType,
5816+
auto *baseEquivClass = resolveEquivalenceClass(baseType,
58155817
ArchetypeResolutionKind::AlreadyKnown);
5816-
assert(equivClass &&
5818+
assert(baseEquivClass &&
58175819
"Explicit requirement names an unknown equivalence class?");
58185820

5819-
auto found = equivClass->conformsTo.find(proto);
5820-
assert(found != equivClass->conformsTo.end());
5821+
auto found = baseEquivClass->conformsTo.find(proto);
5822+
assert(found != baseEquivClass->conformsTo.end());
58215823

58225824
bool foundValidDerivation = false;
58235825
for (const auto &constraint : found->second) {
@@ -8279,24 +8281,42 @@ GenericSignature GenericSignatureBuilder::rebuildSignatureWithoutRedundantRequir
82798281
}
82808282

82818283
auto subjectType = req.getSubjectType();
8282-
subjectType = stripBoundDependentMemberTypes(subjectType);
8283-
auto resolvedSubjectType =
8284-
resolveDependentMemberTypes(*this, subjectType,
8285-
ArchetypeResolutionKind::WellFormed);
8284+
auto resolvedSubject =
8285+
maybeResolveEquivalenceClass(subjectType,
8286+
ArchetypeResolutionKind::WellFormed,
8287+
/*wantExactPotentialArchetype=*/false);
8288+
8289+
auto *resolvedEquivClass = resolvedSubject.getEquivalenceClass(*this);
8290+
Type resolvedSubjectType;
8291+
if (resolvedEquivClass != nullptr)
8292+
resolvedSubjectType = resolvedEquivClass->getAnchor(*this, { });
82868293

82878294
// This can occur if the combination of a superclass requirement and
82888295
// protocol conformance requirement force a type to become concrete.
82898296
//
82908297
// FIXME: Is there a more principled formulation of this?
8291-
if (req.getKind() == RequirementKind::Superclass &&
8292-
!resolvedSubjectType->isTypeParameter()) {
8293-
newBuilder.addRequirement(Requirement(RequirementKind::SameType,
8294-
subjectType, resolvedSubjectType),
8295-
getRebuiltSource(req.getSource()), nullptr);
8296-
continue;
8298+
if (req.getKind() == RequirementKind::Superclass) {
8299+
if (resolvedSubject.getAsConcreteType()) {
8300+
auto unresolvedSubjectType = stripBoundDependentMemberTypes(subjectType);
8301+
newBuilder.addRequirement(Requirement(RequirementKind::SameType,
8302+
unresolvedSubjectType,
8303+
resolvedSubject.getAsConcreteType()),
8304+
getRebuiltSource(req.getSource()), nullptr);
8305+
continue;
8306+
}
8307+
8308+
if (resolvedEquivClass->concreteType) {
8309+
auto unresolvedSubjectType = stripBoundDependentMemberTypes(
8310+
resolvedSubjectType);
8311+
newBuilder.addRequirement(Requirement(RequirementKind::SameType,
8312+
unresolvedSubjectType,
8313+
resolvedEquivClass->concreteType),
8314+
getRebuiltSource(req.getSource()), nullptr);
8315+
continue;
8316+
}
82978317
}
82988318

8299-
assert(resolvedSubjectType->isTypeParameter());
8319+
assert(resolvedSubjectType && resolvedSubjectType->isTypeParameter());
83008320

83018321
if (auto optReq = createRequirement(req.getKind(), resolvedSubjectType,
83028322
req.getRHS(), getGenericParams())) {
@@ -8335,6 +8355,40 @@ GenericSignature GenericSignatureBuilder::rebuildSignatureWithoutRedundantRequir
83358355
}
83368356
};
83378357

8358+
// If we have a same-type requirement where the right hand side is concrete,
8359+
// canonicalize the left hand side, in case dropping some redundant
8360+
// conformance requirement turns the original left hand side into an
8361+
// unresolvable type.
8362+
if (!req.getRHS().get<Type>()->isTypeParameter()) {
8363+
auto resolvedSubject =
8364+
maybeResolveEquivalenceClass(req.getSubjectType(),
8365+
ArchetypeResolutionKind::WellFormed,
8366+
/*wantExactPotentialArchetype=*/false);
8367+
8368+
auto *resolvedEquivClass = resolvedSubject.getEquivalenceClass(*this);
8369+
auto resolvedSubjectType = resolvedEquivClass->getAnchor(*this, { });
8370+
8371+
auto constraintType = resolveType(req.getRHS().get<Type>());
8372+
8373+
auto newReq = stripBoundDependentMemberTypes(
8374+
Requirement(RequirementKind::SameType,
8375+
resolvedSubjectType, constraintType));
8376+
8377+
if (Impl->DebugRedundantRequirements) {
8378+
llvm::dbgs() << "=> ";
8379+
newReq.dump(llvm::dbgs());
8380+
llvm::dbgs() << "\n";
8381+
}
8382+
newBuilder.addRequirement(newReq, getRebuiltSource(req.getSource()),
8383+
nullptr);
8384+
8385+
continue;
8386+
}
8387+
8388+
// Otherwise, we can't canonicalize the two sides of the requirement, since
8389+
// doing so will produce a trivial same-type requirement T == T. Instead,
8390+
// apply some ad-hoc rules to improve the odds that the requirement will
8391+
// resolve in the rebuilt GSB.
83388392
auto subjectType = resolveType(req.getSubjectType());
83398393
auto constraintType = resolveType(req.getRHS().get<Type>());
83408394

test/Generics/rdar75656022.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ struct OriginalExampleWithWarning<A, B> where A : P2, B : P2, A.T == B.T {
4848
init<C, D, E>(_: C)
4949
where C : P1,
5050
D : P1, // expected-warning {{redundant conformance constraint 'D' : 'P1'}}
51-
// expected-note@-1 {{conformance constraint 'C.T' : 'P1' implied here}}
52-
C.T : P1, // expected-warning {{redundant conformance constraint 'C.T' : 'P1'}}
51+
C.T : P1, // expected-warning {{redundant conformance constraint 'D' : 'P1'}}
52+
// expected-note@-1 {{conformance constraint 'D' : 'P1' implied here}}
5353
A == S1<C, C.T.T, S2<C.T>>,
5454
C.T == D,
5555
E == D.T { }

test/Generics/rdar80503090.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// RUN: %target-typecheck-verify-swift
2+
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures %s 2>&1 | %FileCheck %s
3+
4+
protocol P {
5+
associatedtype T where T == Self
6+
}
7+
8+
protocol Q : P {}
9+
10+
extension P {
11+
func missing() {}
12+
}
13+
14+
extension P where T : Q {
15+
// CHECK-LABEL: Generic signature: <Self where Self : Q>
16+
func test() {
17+
missing()
18+
}
19+
}
20+
21+
class C : P {}
22+
23+
extension P where T : C {
24+
// CHECK-LABEL: Generic signature: <Self where Self == C>
25+
func test() {
26+
missing()
27+
}
28+
}
29+
30+
struct S : P {}
31+
32+
extension P where T == S {
33+
// CHECK-LABEL: Generic signature: <Self where Self == S>
34+
func test() {
35+
missing()
36+
}
37+
}

0 commit comments

Comments
 (0)