Skip to content

Commit d311549

Browse files
committed
GSB: Rebuild requirement signatures after dropping redundant conformance requirements
This fixes a regression from the new redundant requirements algorithm and paves the way for removing the notion of 'derived via concrete' requirements.
1 parent a49b93c commit d311549

File tree

3 files changed

+98
-9
lines changed

3 files changed

+98
-9
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8293,7 +8293,31 @@ GenericSignature GenericSignatureBuilder::rebuildSignatureWithoutRedundantRequir
82938293
for (auto param : getGenericParams())
82948294
newBuilder.addGenericParameter(param);
82958295

8296-
auto newSource = FloatingRequirementSource::forAbstract();
8296+
const RequirementSource *requirementSignatureSource = nullptr;
8297+
if (auto *proto = const_cast<ProtocolDecl *>(requirementSignatureSelfProto)) {
8298+
auto selfType = proto->getSelfInterfaceType();
8299+
requirementSignatureSource =
8300+
RequirementSource::forRequirementSignature(newBuilder, selfType, proto);
8301+
8302+
// Add the conformance requirement 'Self : Proto' directly without going
8303+
// through addConformanceRequirement(), since the latter calls
8304+
// expandConformanceRequirement(), which we want to skip since we're
8305+
// re-adding the requirements directly below.
8306+
auto resolvedType = ResolvedType(newBuilder.Impl->PotentialArchetypes[0]);
8307+
auto equivClass = resolvedType.getEquivalenceClass(newBuilder);
8308+
8309+
(void) equivClass->recordConformanceConstraint(newBuilder, resolvedType, proto,
8310+
requirementSignatureSource);
8311+
}
8312+
8313+
auto newSource = [&]() {
8314+
if (auto *proto = const_cast<ProtocolDecl *>(requirementSignatureSelfProto)) {
8315+
return FloatingRequirementSource::viaProtocolRequirement(
8316+
requirementSignatureSource, proto, /*inferred=*/false);
8317+
}
8318+
8319+
return FloatingRequirementSource::forAbstract();
8320+
}();
82978321

82988322
for (const auto &req : Impl->ExplicitRequirements) {
82998323
assert(req.getKind() != RequirementKind::SameType &&
@@ -8382,9 +8406,6 @@ GenericSignature GenericSignatureBuilder::computeGenericSignature(
83828406
requirementSignatureSelfProto);
83838407

83848408
if (rebuildingWithoutRedundantConformances) {
8385-
assert(requirementSignatureSelfProto == nullptr &&
8386-
"Rebuilding a requirement signature?");
8387-
83888409
assert(!Impl->HadAnyError &&
83898410
"Rebuilt signature had errors");
83908411

@@ -8406,7 +8427,6 @@ GenericSignature GenericSignatureBuilder::computeGenericSignature(
84068427
//
84078428
// Also, don't do this when building a requirement signature.
84088429
if (!rebuildingWithoutRedundantConformances &&
8409-
requirementSignatureSelfProto == nullptr &&
84108430
!Impl->HadAnyError &&
84118431
!Impl->ExplicitConformancesImpliedByConcrete.empty()) {
84128432
return std::move(*this).rebuildSignatureWithoutRedundantRequirements(
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// RUN: %target-typecheck-verify-swift
2+
// RUN: %target-swift-frontend -debug-generic-signatures -typecheck %s 2>&1 | %FileCheck %s
3+
4+
protocol P {}
5+
class C {}
6+
7+
class X<T : P> : U {}
8+
class Y<T : C> : V {}
9+
class Z<T : AnyObject> : W {}
10+
11+
protocol U {
12+
associatedtype T : P
13+
}
14+
15+
protocol V {
16+
associatedtype T : C
17+
}
18+
19+
protocol W {
20+
associatedtype T : AnyObject
21+
}
22+
23+
// CHECK: Generic signature: <A, B where A : X<B>, B : P>
24+
func derivedViaConcreteX1<A, B>(_: A, _: B)
25+
where A : U, A : X<B> {}
26+
// expected-warning@-1 {{redundant conformance constraint 'A' : 'U'}}
27+
// expected-note@-2 {{conformance constraint 'A' : 'U' implied here}}
28+
29+
// FIXME: We should not diagnose 'B : P' as redundant, even though it
30+
// really is, because it was made redundant by an inferred requirement.
31+
32+
// CHECK: Generic signature: <A, B where A : X<B>, B : P>
33+
func derivedViaConcreteX2<A, B>(_: A, _: B)
34+
where A : U, B : P, A : X<B> {}
35+
// expected-warning@-1 {{redundant conformance constraint 'A' : 'U'}}
36+
// expected-note@-2 {{conformance constraint 'A' : 'U' implied here}}
37+
// expected-warning@-3 {{redundant conformance constraint 'B' : 'P'}}
38+
// expected-note@-4 {{conformance constraint 'B' : 'P' implied here}}
39+
40+
// CHECK: Generic signature: <A, B where A : Y<B>, B : C>
41+
func derivedViaConcreteY1<A, B>(_: A, _: B)
42+
where A : V, A : Y<B> {}
43+
// expected-warning@-1 {{redundant conformance constraint 'A' : 'V'}}
44+
// expected-note@-2 {{conformance constraint 'A' : 'V' implied here}}
45+
46+
// FIXME: We should not diagnose 'B : C' as redundant, even though it
47+
// really is, because it was made redundant by an inferred requirement.
48+
49+
// CHECK: Generic signature: <A, B where A : Y<B>, B : C>
50+
func derivedViaConcreteY2<A, B>(_: A, _: B)
51+
where A : V, B : C, A : Y<B> {}
52+
// expected-warning@-1 {{redundant conformance constraint 'A' : 'V'}}
53+
// expected-note@-2 {{conformance constraint 'A' : 'V' implied here}}
54+
// expected-warning@-3 {{redundant superclass constraint 'B' : 'C'}}
55+
// expected-note@-4 {{superclass constraint 'B' : 'C' implied here}}
56+
57+
// CHECK: Generic signature: <A, B where A : Z<B>, B : AnyObject>
58+
func derivedViaConcreteZ1<A, B>(_: A, _: B)
59+
where A : W, A : Z<B> {}
60+
// expected-warning@-1 {{redundant conformance constraint 'A' : 'W'}}
61+
// expected-note@-2 {{conformance constraint 'A' : 'W' implied here}}
62+
63+
// CHECK: Generic signature: <A, B where A : Z<B>, B : AnyObject>
64+
func derivedViaConcreteZ2<A, B>(_: A, _: B)
65+
where A : W, B : AnyObject, A : Z<B> {}
66+
// expected-warning@-1 {{redundant conformance constraint 'A' : 'W'}}
67+
// expected-note@-2 {{conformance constraint 'A' : 'W' implied here}}

test/Generics/requirement_inference.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -354,20 +354,22 @@ protocol P26 {
354354
associatedtype C: X3
355355
}
356356

357-
struct X26<T: X3> : P26 { // expected-note {{requirement specified as 'T' : 'X3' [with T = Self.B]}}
357+
struct X26<T: X3> : P26 {
358358
typealias C = T
359359
}
360360

361361
// CHECK-LABEL: .P27a@
362-
// CHECK-NEXT: Requirement signature: <Self where Self.A == X26<Self.B>>
363-
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0.A == X26<τ_0_0.B>>
362+
// CHECK-NEXT: Requirement signature: <Self where Self.A == X26<Self.B>, Self.B : X3>
363+
// CHECK-NEXT: Canonical requirement signature: <τ_0_0 where τ_0_0.A == X26<τ_0_0.B>, τ_0_0.B : X3>
364364
protocol P27a {
365365
associatedtype A: P26 // expected-warning{{redundant conformance constraint 'Self.A' : 'P26'}}
366366
// expected-note@-1 {{superclass constraint 'Self.B' : 'X3' implied here}}
367367

368368
associatedtype B: X3 where A == X26<B> // expected-note{{conformance constraint 'Self.A' : 'P26' implied here}}
369369
// expected-warning@-1 {{redundant superclass constraint 'Self.B' : 'X3'}}
370-
// expected-error@-2 {{'X26' requires that 'Self.B' inherit from 'X3'}}
370+
371+
// FIXME: The above warning should not be emitted -- while the requirement
372+
// really is redundant, it is made redundant by an inferred requirement.
371373
}
372374

373375
// CHECK-LABEL: .P27b@

0 commit comments

Comments
 (0)