Skip to content

Commit 0ff17e3

Browse files
committed
GSB: Tweak condition under which we perform conditional requirement inference
For SIL substituted generic signature construction to work, we must perform this step if either the conformance requirement or the concrete type requirement is explicit. Previously, we only did it if the concrete type requirement was explicit. This is still somewhat unprincipled and I need to think about it some more before porting it over to the requirement machine. Fixes https://bugs.swift.org/browse/SR-15254 / rdar://problem/84827656.
1 parent 05fa143 commit 0ff17e3

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)