Skip to content

Commit f8fdcbb

Browse files
authored
Merge pull request #40256 from slavapestov/fix-gsb-conditional-requirement-inference-again
GSB: Tweak condition under which we perform conditional requirement inference
2 parents 5f3b7bb + 0ff17e3 commit f8fdcbb

File tree

4 files changed

+77
-21
lines changed

4 files changed

+77
-21
lines changed

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1916,10 +1916,12 @@ bool EquivalenceClass::recordConformanceConstraint(
19161916

19171917
// If there is a concrete type that resolves this conformance requirement,
19181918
// record the conformance.
1919-
if (!builder.resolveConcreteConformance(type, proto)) {
1919+
bool explicitConformance = !source->isDerivedRequirement();
1920+
1921+
if (!builder.resolveConcreteConformance(type, proto, explicitConformance)) {
19201922
// Otherwise, determine whether there is a superclass constraint where the
19211923
// superclass conforms to this protocol.
1922-
(void)builder.resolveSuperConformance(type, proto);
1924+
(void)builder.resolveSuperConformance(type, proto, explicitConformance);
19231925
}
19241926
}
19251927

@@ -2324,7 +2326,8 @@ void GenericSignatureBuilder::addConditionalRequirements(
23242326

23252327
const RequirementSource *
23262328
GenericSignatureBuilder::resolveConcreteConformance(ResolvedType type,
2327-
ProtocolDecl *proto) {
2329+
ProtocolDecl *proto,
2330+
bool explicitConformance) {
23282331
auto equivClass = type.getEquivalenceClass(*this);
23292332
auto concrete = equivClass->concreteType;
23302333
if (!concrete) return nullptr;
@@ -2378,21 +2381,22 @@ GenericSignatureBuilder::resolveConcreteConformance(ResolvedType type,
23782381
equivClass->recordConformanceConstraint(*this, type, proto, concreteSource);
23792382

23802383
// Only infer conditional requirements from explicit sources.
2381-
bool hasExplicitSource = llvm::any_of(
2384+
bool explicitConcreteType = llvm::any_of(
23822385
equivClass->concreteTypeConstraints,
23832386
[](const ConcreteConstraint &constraint) {
23842387
return !constraint.source->isDerivedRequirement();
23852388
});
23862389

2387-
if (hasExplicitSource) {
2390+
if (explicitConformance || explicitConcreteType) {
23882391
addConditionalRequirements(conformance, /*inferForModule=*/nullptr);
23892392
}
23902393

23912394
return concreteSource;
23922395
}
2393-
const RequirementSource *GenericSignatureBuilder::resolveSuperConformance(
2394-
ResolvedType type,
2395-
ProtocolDecl *proto) {
2396+
const RequirementSource *
2397+
GenericSignatureBuilder::resolveSuperConformance(ResolvedType type,
2398+
ProtocolDecl *proto,
2399+
bool explicitConformance) {
23962400
// Get the superclass constraint.
23972401
auto equivClass = type.getEquivalenceClass(*this);
23982402
Type superclass = equivClass->superclass;
@@ -2418,14 +2422,13 @@ const RequirementSource *GenericSignatureBuilder::resolveSuperConformance(
24182422
equivClass->recordConformanceConstraint(*this, type, proto, superclassSource);
24192423

24202424
// Only infer conditional requirements from explicit sources.
2421-
bool hasExplicitSource = llvm::any_of(
2422-
equivClass->superclassConstraints,
2423-
[](const ConcreteConstraint &constraint) {
2424-
return (!constraint.source->isDerivedRequirement() &&
2425-
constraint.source->getLoc().isValid());
2426-
});
2425+
bool explicitSuperclass = llvm::any_of(
2426+
equivClass->superclassConstraints,
2427+
[](const ConcreteConstraint &constraint) {
2428+
return !constraint.source->isDerivedRequirement();
2429+
});
24272430

2428-
if (hasExplicitSource) {
2431+
if (explicitConformance || explicitSuperclass) {
24292432
addConditionalRequirements(conformance, /*inferForModule=*/nullptr);
24302433
}
24312434

@@ -4410,7 +4413,13 @@ bool GenericSignatureBuilder::updateSuperclass(
44104413
// when the superclass constraint changes.
44114414
auto updateSuperclassConformances = [&] {
44124415
for (const auto &conforms : equivClass->conformsTo) {
4413-
(void)resolveSuperConformance(type, conforms.first);
4416+
bool explicitConformance = std::find_if(
4417+
conforms.second.begin(),
4418+
conforms.second.end(),
4419+
[](const Constraint<ProtocolDecl *> &constraint) {
4420+
return !constraint.source->isDerivedRequirement();
4421+
}) != conforms.second.end();
4422+
(void)resolveSuperConformance(type, conforms.first, explicitConformance);
44144423
}
44154424

44164425
// Eagerly resolve any existing nested types to their concrete forms (others
@@ -4809,8 +4818,15 @@ GenericSignatureBuilder::addSameTypeRequirementBetweenTypeParameters(
48094818
equivClass2->concreteTypeConstraints.begin(),
48104819
equivClass2->concreteTypeConstraints.end());
48114820

4812-
for (const auto &conforms : equivClass->conformsTo)
4813-
(void)resolveConcreteConformance(T1, conforms.first);
4821+
for (const auto &conforms : equivClass->conformsTo) {
4822+
bool explicitConformance = std::find_if(
4823+
conforms.second.begin(),
4824+
conforms.second.end(),
4825+
[](const Constraint<ProtocolDecl *> &constraint) {
4826+
return !constraint.source->isDerivedRequirement();
4827+
}) != conforms.second.end();
4828+
(void)resolveConcreteConformance(T1, conforms.first, explicitConformance);
4829+
}
48144830
}
48154831

48164832
// Make T1 the representative of T2, merging the equivalence classes.
@@ -4946,7 +4962,13 @@ ConstraintResult GenericSignatureBuilder::addSameTypeRequirementToConcrete(
49464962
// Make sure the concrete type fulfills the conformance requirements of
49474963
// this equivalence class.
49484964
for (const auto &conforms : equivClass->conformsTo) {
4949-
if (!resolveConcreteConformance(type, conforms.first))
4965+
bool explicitConformance = std::find_if(
4966+
conforms.second.begin(),
4967+
conforms.second.end(),
4968+
[](const Constraint<ProtocolDecl *> &constraint) {
4969+
return !constraint.source->isDerivedRequirement();
4970+
}) != conforms.second.end();
4971+
if (!resolveConcreteConformance(type, conforms.first, explicitConformance))
49504972
return ConstraintResult::Conflicting;
49514973
}
49524974

lib/AST/GenericSignatureBuilder.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,8 @@ class GenericSignatureBuilder {
338338
/// \returns the requirement source for the resolved conformance, or nullptr
339339
/// if the conformance could not be resolved.
340340
const RequirementSource *resolveConcreteConformance(ResolvedType type,
341-
ProtocolDecl *proto);
341+
ProtocolDecl *proto,
342+
bool explicitConformance);
342343

343344
/// Retrieve the constraint source conformance for the superclass constraint
344345
/// of the given potential archetype (if present) to the given protocol.
@@ -347,7 +348,8 @@ class GenericSignatureBuilder {
347348
///
348349
/// \param proto The protocol to which we are establishing conformance.
349350
const RequirementSource *resolveSuperConformance(ResolvedType type,
350-
ProtocolDecl *proto);
351+
ProtocolDecl *proto,
352+
bool explicitConformance);
351353

352354
public:
353355
/// Add a new conformance requirement specifying that the given

test/Generics/conditional_requirement_inference.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ struct EquatableBox<T : Equatable> {
88
func withArray<U>(_: U) where T == Array<U> {}
99
}
1010

11+
struct EquatableSequenceBox<T : Sequence> where T.Element : Equatable {
12+
// CHECK: Generic signature: <T, U where T == Array<Array<U>>, U : Equatable>
13+
func withArrayArray<U>(_: U) where T == Array<Array<U>> {}
14+
}
15+
1116

1217
// A very elaborate invalid example (see comment in mergeP1AndP2())
1318
struct G<T> {}

test/SILGen/type_lowering_subst_function_type_conditional_conformance.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,30 @@ struct S4<Base> where Base : P1, Base.Element: P1 {
6767
_ = index.map({ _ = $0 })
6868
}
6969
}
70+
71+
struct T0<X> {}
72+
73+
extension T0: P1 where X: P1 {
74+
typealias Element = X.Element
75+
typealias Index = T0<X.Index>
76+
}
77+
78+
struct T1<X, Y>: P1 where X: P1 {
79+
typealias Element = Y
80+
typealias Index = X.Index
81+
}
82+
83+
struct T2<X> where X: P1, X.Element: P1 {
84+
let field: X.Element.Index
85+
}
86+
87+
struct T3<X> where X: P1 {
88+
func callee(_: T2<T1<X, T0<X>>>) {}
89+
90+
// CHECK-LABEL: {{^}}sil {{.*}}2T3{{.*}}6caller{{.*}}F :
91+
// CHECK: @callee_guaranteed @substituted <τ_0_0, τ_0_1, τ_0_2, τ_0_3, τ_0_4, τ_0_5 where τ_0_0 == T1<τ_0_1, T0<τ_0_4>>, τ_0_1 : P1, τ_0_1 == τ_0_3, τ_0_2 == T0<τ_0_4>, τ_0_4 : P1, τ_0_4 == τ_0_5> (T2<T1<τ_0_1, T0<τ_0_4>>>) -> () for <T1<X, T0<X>>, X, T0<X>, X, X, X>
92+
func caller() {
93+
_ = { (x: T2<T1<X, T0<X>>>) in callee(x) }
94+
}
95+
}
96+

0 commit comments

Comments
 (0)